Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions .trajectories/completed/2026-01/traj_id0xcg5k8b4g.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"id": "traj_id0xcg5k8b4g",
"version": 1,
"task": {
"title": "Fix relay-pty binary not found on global npm install"
},
"status": "completed",
"startedAt": "2026-01-25T11:28:03.677Z",
"agents": [
{
"name": "default",
"role": "lead",
"joinedAt": "2026-01-25T11:28:09.866Z"
}
],
"chapters": [
{
"id": "chap_xwiuvceylv2a",
"title": "Work",
"agentName": "default",
"startedAt": "2026-01-25T11:28:09.866Z",
"events": [
{
"ts": 1769340489867,
"type": "decision",
"content": "Root cause: wrapper's findRelayPtyBinary() wasn't updated with global npm install fixes from spawner.ts: Root cause: wrapper's findRelayPtyBinary() wasn't updated with global npm install fixes from spawner.ts",
"raw": {
"question": "Root cause: wrapper's findRelayPtyBinary() wasn't updated with global npm install fixes from spawner.ts",
"chosen": "Root cause: wrapper's findRelayPtyBinary() wasn't updated with global npm install fixes from spawner.ts",
"alternatives": [],
"reasoning": "The spawner.ts had comprehensive path resolution but wrapper had outdated 3-levels-up calculation that breaks for nested @agent-relay/* packages"
},
"significance": "high"
},
{
"ts": 1769340495601,
"type": "decision",
"content": "Extract to shared utility instead of duplicating fix: Extract to shared utility instead of duplicating fix",
"raw": {
"question": "Extract to shared utility instead of duplicating fix",
"chosen": "Extract to shared utility instead of duplicating fix",
"alternatives": [],
"reasoning": "User requested reuse over duplication. Created @agent-relay/utils/relay-pty-path so both spawner.ts and wrapper use same logic"
},
"significance": "high"
}
],
"endedAt": "2026-01-25T11:28:20.769Z"
}
],
"commits": [],
"filesChanged": [],
"projectId": "/Users/khaliqgant/Projects/agent-workforce/relay",
"tags": [],
"completedAt": "2026-01-25T11:28:20.769Z",
"retrospective": {
"summary": "Fixed relay-pty binary resolution for global npm installs by extracting shared utility. Binary search now handles nested @agent-relay/* packages correctly using non-greedy regex to find root node_modules.",
"approach": "Standard approach",
"confidence": 0.9
}
}
36 changes: 36 additions & 0 deletions .trajectories/completed/2026-01/traj_id0xcg5k8b4g.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Trajectory: Fix relay-pty binary not found on global npm install

> **Status:** ✅ Completed
> **Confidence:** 90%
> **Started:** January 25, 2026 at 12:28 PM
> **Completed:** January 25, 2026 at 12:28 PM

---

## Summary

Fixed relay-pty binary resolution for global npm installs by extracting shared utility. Binary search now handles nested @agent-relay/* packages correctly using non-greedy regex to find root node_modules.

**Approach:** Standard approach

---

## Key Decisions

### Root cause: wrapper's findRelayPtyBinary() wasn't updated with global npm install fixes from spawner.ts
- **Chose:** Root cause: wrapper's findRelayPtyBinary() wasn't updated with global npm install fixes from spawner.ts
- **Reasoning:** The spawner.ts had comprehensive path resolution but wrapper had outdated 3-levels-up calculation that breaks for nested @agent-relay/* packages

### Extract to shared utility instead of duplicating fix
- **Chose:** Extract to shared utility instead of duplicating fix
- **Reasoning:** User requested reuse over duplication. Created @agent-relay/utils/relay-pty-path so both spawner.ts and wrapper use same logic

---

## Chapters

### 1. Work
*Agent: default*

- Root cause: wrapper's findRelayPtyBinary() wasn't updated with global npm install fixes from spawner.ts: Root cause: wrapper's findRelayPtyBinary() wasn't updated with global npm install fixes from spawner.ts
- Extract to shared utility instead of duplicating fix: Extract to shared utility instead of duplicating fix
49 changes: 49 additions & 0 deletions .trajectories/completed/2026-01/traj_ml5tikuiwxpb.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"id": "traj_ml5tikuiwxpb",
"version": 1,
"task": {
"title": "Consolidate all relay-pty binary lookups"
},
"status": "completed",
"startedAt": "2026-01-25T11:30:44.733Z",
"agents": [
{
"name": "default",
"role": "lead",
"joinedAt": "2026-01-25T11:30:44.963Z"
}
],
"chapters": [
{
"id": "chap_1c3w3ievs9ry",
"title": "Work",
"agentName": "default",
"startedAt": "2026-01-25T11:30:44.963Z",
"events": [
{
"ts": 1769340644964,
"type": "decision",
"content": "Updated 4 more files to use shared utility: Updated 4 more files to use shared utility",
"raw": {
"question": "Updated 4 more files to use shared utility",
"chosen": "Updated 4 more files to use shared utility",
"alternatives": [],
"reasoning": "daemon/cli-auth.ts, cloud/cli-pty-runner.ts, and 2 test scripts all had duplicated binary search logic"
},
"significance": "high"
}
],
"endedAt": "2026-01-25T11:30:45.203Z"
}
],
"commits": [],
"filesChanged": [],
"projectId": "/Users/khaliqgant/Projects/agent-workforce/relay",
"tags": [],
"completedAt": "2026-01-25T11:30:45.203Z",
"retrospective": {
"summary": "All 6 locations that find relay-pty binary now use shared utility from @agent-relay/utils/relay-pty-path",
"approach": "Standard approach",
"confidence": 0.95
}
}
31 changes: 31 additions & 0 deletions .trajectories/completed/2026-01/traj_ml5tikuiwxpb.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Trajectory: Consolidate all relay-pty binary lookups

> **Status:** ✅ Completed
> **Confidence:** 95%
> **Started:** January 25, 2026 at 12:30 PM
> **Completed:** January 25, 2026 at 12:30 PM

---

## Summary

All 6 locations that find relay-pty binary now use shared utility from @agent-relay/utils/relay-pty-path

**Approach:** Standard approach

---

## Key Decisions

### Updated 4 more files to use shared utility
- **Chose:** Updated 4 more files to use shared utility
- **Reasoning:** daemon/cli-auth.ts, cloud/cli-pty-runner.ts, and 2 test scripts all had duplicated binary search logic

---

## Chapters

### 1. Work
*Agent: default*

- Updated 4 more files to use shared utility: Updated 4 more files to use shared utility
18 changes: 16 additions & 2 deletions .trajectories/index.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"version": 1,
"lastUpdated": "2026-01-24T08:53:25.073Z",
"lastUpdated": "2026-01-25T11:30:45.234Z",
"trajectories": {
"traj_1b1dj40sl6jl": {
"title": "Revert aggressive retry logic in relay-pty-orchestrator",
Expand Down Expand Up @@ -64,6 +64,20 @@
"startedAt": "2026-01-23T22:56:17.733Z",
"completedAt": "2026-01-23T23:00:29.377Z",
"path": "/Users/khaliqgant/Projects/agent-workforce/relay/.trajectories/completed/2026-01/traj_9eqbfvrxl36g.json"
},
"traj_id0xcg5k8b4g": {
"title": "Fix relay-pty binary not found on global npm install",
"status": "completed",
"startedAt": "2026-01-25T11:28:03.677Z",
"completedAt": "2026-01-25T11:28:20.769Z",
"path": "/Users/khaliqgant/Projects/agent-workforce/relay/.trajectories/completed/2026-01/traj_id0xcg5k8b4g.json"
},
"traj_ml5tikuiwxpb": {
"title": "Consolidate all relay-pty binary lookups",
"status": "completed",
"startedAt": "2026-01-25T11:30:44.733Z",
"completedAt": "2026-01-25T11:30:45.203Z",
"path": "/Users/khaliqgant/Projects/agent-workforce/relay/.trajectories/completed/2026-01/traj_ml5tikuiwxpb.json"
}
}
}
}
78 changes: 3 additions & 75 deletions packages/bridge/src/spawner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { resolveCommand } from '@agent-relay/utils/command-resolver';
import { createTraceableError } from '@agent-relay/utils/error-tracking';
import { createLogger } from '@agent-relay/utils/logger';
import { mapModelToCli } from '@agent-relay/utils/model-mapping';
import { findRelayPtyBinary as findRelayPtyBinaryUtil } from '@agent-relay/utils/relay-pty-path';
import { RelayPtyOrchestrator, type RelayPtyOrchestratorConfig } from '@agent-relay/wrapper';
import type { SummaryEvent, SessionEndEvent } from '@agent-relay/wrapper';
import { selectShadowCli } from './shadow-cli.js';
Expand Down Expand Up @@ -312,83 +313,10 @@ function getRelayInstructions(agentName: string, options: { hasMcp?: boolean; in
/**
* Check if the relay-pty binary is available.
* Returns the path to the binary if found, null otherwise.
*
* Search order:
* 1. bin/relay-pty in package root (installed by postinstall)
* 2. relay-pty/target/release/relay-pty (local Rust build)
* 3. /usr/local/bin/relay-pty (global install)
* 4. In node_modules when installed as dependency
* 5. Global npm installs (nvm) - both scoped and root packages
* Uses shared utility from @agent-relay/utils.
*/
function findRelayPtyBinary(): string | null {
// Determine the agent-relay package root
// This code runs from either:
// - packages/bridge/dist/ (development/workspace)
// - node_modules/@agent-relay/bridge/dist/ (npm install)
//
// We need to find the agent-relay package root where bin/relay-pty lives
let packageRoot: string;

// Check if we're inside node_modules/@agent-relay/bridge/
if (__dirname.includes('node_modules/@agent-relay/bridge')) {
// Go from node_modules/@agent-relay/bridge/dist/ to agent-relay/
// dist/ -> bridge/ -> @agent-relay/ -> node_modules/ -> agent-relay/
packageRoot = path.join(__dirname, '..', '..', '..', '..');
} else if (__dirname.includes('node_modules/agent-relay')) {
// Direct dependency: node_modules/agent-relay/packages/bridge/dist/
// dist/ -> bridge/ -> packages/ -> agent-relay/
packageRoot = path.join(__dirname, '..', '..', '..');
} else {
// Development: packages/bridge/dist/ -> packages/ -> project root
packageRoot = path.join(__dirname, '..', '..', '..');
}

// Find the node_modules root for global installs
// When running from node_modules/@agent-relay/dashboard/node_modules/@agent-relay/bridge/dist/
// we need to look for agent-relay at node_modules/agent-relay
let nodeModulesRoot: string | null = null;
const nodeModulesMatch = __dirname.match(/^(.+?\/node_modules)\/@agent-relay\//);
if (nodeModulesMatch) {
nodeModulesRoot = nodeModulesMatch[1];
}

const candidates = [
// Primary: installed by postinstall from platform-specific binary
path.join(packageRoot, 'bin', 'relay-pty'),
// Development: local Rust build
path.join(packageRoot, 'relay-pty', 'target', 'release', 'relay-pty'),
path.join(packageRoot, 'relay-pty', 'target', 'debug', 'relay-pty'),
// Local build in cwd (for development)
path.join(process.cwd(), 'relay-pty', 'target', 'release', 'relay-pty'),
// Installed globally
'/usr/local/bin/relay-pty',
// In node_modules (when installed as local dependency)
path.join(process.cwd(), 'node_modules', 'agent-relay', 'bin', 'relay-pty'),
// Global npm install (nvm) - root package
path.join(process.env.HOME || '', '.nvm', 'versions', 'node', process.version, 'lib', 'node_modules', 'agent-relay', 'bin', 'relay-pty'),
];

// Add candidate for root agent-relay package when running from scoped @agent-relay/* packages
if (nodeModulesRoot) {
candidates.push(path.join(nodeModulesRoot, 'agent-relay', 'bin', 'relay-pty'));
}

// Try common global npm paths
if (process.env.HOME) {
// Homebrew npm (macOS)
candidates.push(path.join('/usr/local/lib/node_modules', 'agent-relay', 'bin', 'relay-pty'));
candidates.push(path.join('/opt/homebrew/lib/node_modules', 'agent-relay', 'bin', 'relay-pty'));
// pnpm global
candidates.push(path.join(process.env.HOME, '.local', 'share', 'pnpm', 'global', 'node_modules', 'agent-relay', 'bin', 'relay-pty'));
}

for (const candidate of candidates) {
if (fs.existsSync(candidate)) {
return candidate;
}
}

return null;
return findRelayPtyBinaryUtil(__dirname);
}

/** Cached result of relay-pty binary check */
Expand Down
29 changes: 3 additions & 26 deletions packages/cloud/src/api/cli-pty-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
type CLIAuthConfig,
type PromptHandler,
} from '@agent-relay/config/cli-auth-config';
import { findRelayPtyBinary as findRelayPtyBinaryUtil } from '@agent-relay/utils/relay-pty-path';

// Re-export everything from shared config for backward compatibility
export {
Expand Down Expand Up @@ -80,34 +81,10 @@ export interface PTYAuthOptions {

/**
* Find the relay-pty binary path.
* Returns null if not found.
* Uses shared utility from @agent-relay/utils.
*/
function findRelayPtyBinary(): string | null {
// Get the project root (five levels up from packages/cloud/dist/api/)
// packages/cloud/dist/api/ -> packages/cloud/dist -> packages/cloud -> packages -> project root
const projectRoot = join(__dirname, '..', '..', '..', '..', '..');

const candidates = [
// Primary: installed by postinstall from platform-specific binary
join(projectRoot, 'bin', 'relay-pty'),
// Development: local Rust build
join(projectRoot, 'relay-pty', 'target', 'release', 'relay-pty'),
join(projectRoot, 'relay-pty', 'target', 'debug', 'relay-pty'),
// Local build in cwd (for development)
join(process.cwd(), 'relay-pty', 'target', 'release', 'relay-pty'),
// Installed globally
'/usr/local/bin/relay-pty',
// In node_modules (when installed as dependency)
join(process.cwd(), 'node_modules', 'agent-relay', 'bin', 'relay-pty'),
];

for (const candidate of candidates) {
if (existsSync(candidate)) {
return candidate;
}
}

return null;
return findRelayPtyBinaryUtil(__dirname);
}

/**
Expand Down
Loading
Loading