agent-relay 1.2.3 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.trajectories/agent-relay-322-324.md +17 -0
- package/.trajectories/completed/2026-01/traj_03zupyv1s7b9.json +49 -0
- package/.trajectories/completed/2026-01/traj_03zupyv1s7b9.md +31 -0
- package/.trajectories/completed/2026-01/traj_0zacdjl1g4ht.json +125 -0
- package/.trajectories/completed/2026-01/traj_0zacdjl1g4ht.md +62 -0
- package/.trajectories/completed/2026-01/traj_33iuy72sezbk.json +49 -0
- package/.trajectories/completed/2026-01/traj_33iuy72sezbk.md +31 -0
- package/.trajectories/completed/2026-01/traj_5ammh5qtvklq.json +77 -0
- package/.trajectories/completed/2026-01/traj_5ammh5qtvklq.md +42 -0
- package/.trajectories/completed/2026-01/traj_6mieijqyvaag.json +77 -0
- package/.trajectories/completed/2026-01/traj_6mieijqyvaag.md +42 -0
- package/.trajectories/completed/2026-01/traj_78ffm31jn3uk.json +77 -0
- package/.trajectories/completed/2026-01/traj_78ffm31jn3uk.md +42 -0
- package/.trajectories/completed/2026-01/traj_94gnp3k30goq.json +66 -0
- package/.trajectories/completed/2026-01/traj_94gnp3k30goq.md +36 -0
- package/.trajectories/completed/2026-01/traj_avqeghu6pz5a.json +40 -0
- package/.trajectories/completed/2026-01/traj_avqeghu6pz5a.md +22 -0
- package/.trajectories/completed/2026-01/traj_dcsp9s8y01ra.json +121 -0
- package/.trajectories/completed/2026-01/traj_dcsp9s8y01ra.md +29 -0
- package/.trajectories/completed/2026-01/traj_fhx9irlckht6.json +53 -0
- package/.trajectories/completed/2026-01/traj_fhx9irlckht6.md +32 -0
- package/.trajectories/completed/2026-01/traj_fqduidx3xbtp.json +101 -0
- package/.trajectories/completed/2026-01/traj_fqduidx3xbtp.md +52 -0
- package/.trajectories/completed/2026-01/traj_hf81ey93uz6t.json +49 -0
- package/.trajectories/completed/2026-01/traj_hf81ey93uz6t.md +31 -0
- package/.trajectories/completed/2026-01/traj_hfmki2jr9d4r.json +65 -0
- package/.trajectories/completed/2026-01/traj_hfmki2jr9d4r.md +37 -0
- package/.trajectories/completed/2026-01/traj_lq450ly148uw.json +49 -0
- package/.trajectories/completed/2026-01/traj_lq450ly148uw.md +31 -0
- package/.trajectories/completed/2026-01/traj_multi_server_arch.md +101 -0
- package/.trajectories/completed/2026-01/traj_psd9ob0j2ru3.json +27 -0
- package/.trajectories/completed/2026-01/traj_psd9ob0j2ru3.md +14 -0
- package/.trajectories/completed/2026-01/traj_ub8csuv3lcv4.json +53 -0
- package/.trajectories/completed/2026-01/traj_ub8csuv3lcv4.md +32 -0
- package/.trajectories/completed/2026-01/traj_uc29tlso8i9s.json +186 -0
- package/.trajectories/completed/2026-01/traj_uc29tlso8i9s.md +86 -0
- package/.trajectories/completed/2026-01/traj_ui9b4tqxoa7j.json +77 -0
- package/.trajectories/completed/2026-01/traj_ui9b4tqxoa7j.md +42 -0
- package/.trajectories/completed/2026-01/traj_v9dkdoxylyid.json +89 -0
- package/.trajectories/completed/2026-01/traj_v9dkdoxylyid.md +47 -0
- package/.trajectories/completed/2026-01/traj_xy9vifpqet80.json +65 -0
- package/.trajectories/completed/2026-01/traj_xy9vifpqet80.md +37 -0
- package/.trajectories/completed/2026-01/traj_y7aiwijyfmmv.json +49 -0
- package/.trajectories/completed/2026-01/traj_y7aiwijyfmmv.md +31 -0
- package/.trajectories/consolidate-settings-panel.md +24 -0
- package/.trajectories/gh-cli-user-token.md +26 -0
- package/.trajectories/index.json +155 -1
- package/deploy/workspace/codex.config.toml +15 -0
- package/deploy/workspace/entrypoint.sh +167 -7
- package/deploy/workspace/git-credential-relay +17 -2
- package/dist/bridge/spawner.d.ts +7 -0
- package/dist/bridge/spawner.js +40 -9
- package/dist/bridge/types.d.ts +2 -0
- package/dist/cli/index.js +210 -168
- package/dist/cloud/api/admin.d.ts +8 -0
- package/dist/cloud/api/admin.js +212 -0
- package/dist/cloud/api/auth.js +8 -0
- package/dist/cloud/api/billing.d.ts +0 -10
- package/dist/cloud/api/billing.js +248 -58
- package/dist/cloud/api/codex-auth-helper.d.ts +10 -4
- package/dist/cloud/api/codex-auth-helper.js +215 -8
- package/dist/cloud/api/coordinators.js +402 -0
- package/dist/cloud/api/daemons.js +15 -11
- package/dist/cloud/api/git.js +104 -17
- package/dist/cloud/api/github-app.js +42 -8
- package/dist/cloud/api/nango-auth.js +297 -16
- package/dist/cloud/api/onboarding.js +97 -33
- package/dist/cloud/api/providers.js +12 -16
- package/dist/cloud/api/repos.js +200 -124
- package/dist/cloud/api/test-helpers.js +40 -0
- package/dist/cloud/api/usage.js +13 -0
- package/dist/cloud/api/webhooks.js +1 -1
- package/dist/cloud/api/workspaces.d.ts +18 -0
- package/dist/cloud/api/workspaces.js +945 -15
- package/dist/cloud/config.d.ts +8 -0
- package/dist/cloud/config.js +15 -0
- package/dist/cloud/db/drizzle.d.ts +5 -2
- package/dist/cloud/db/drizzle.js +27 -20
- package/dist/cloud/db/schema.d.ts +19 -51
- package/dist/cloud/db/schema.js +5 -4
- package/dist/cloud/index.d.ts +0 -1
- package/dist/cloud/index.js +0 -1
- package/dist/cloud/provisioner/index.d.ts +93 -1
- package/dist/cloud/provisioner/index.js +608 -63
- package/dist/cloud/server.js +156 -16
- package/dist/cloud/services/compute-enforcement.d.ts +57 -0
- package/dist/cloud/services/compute-enforcement.js +175 -0
- package/dist/cloud/services/index.d.ts +2 -0
- package/dist/cloud/services/index.js +4 -0
- package/dist/cloud/services/intro-expiration.d.ts +55 -0
- package/dist/cloud/services/intro-expiration.js +211 -0
- package/dist/cloud/services/nango.d.ts +14 -0
- package/dist/cloud/services/nango.js +74 -14
- package/dist/cloud/services/ssh-security.d.ts +31 -0
- package/dist/cloud/services/ssh-security.js +63 -0
- package/dist/continuity/manager.d.ts +5 -0
- package/dist/continuity/manager.js +56 -2
- package/dist/daemon/api.d.ts +2 -0
- package/dist/daemon/api.js +214 -5
- package/dist/daemon/cli-auth.d.ts +13 -1
- package/dist/daemon/cli-auth.js +166 -47
- package/dist/daemon/connection.d.ts +7 -1
- package/dist/daemon/connection.js +15 -0
- package/dist/daemon/orchestrator.d.ts +2 -0
- package/dist/daemon/orchestrator.js +26 -0
- package/dist/daemon/repo-manager.d.ts +116 -0
- package/dist/daemon/repo-manager.js +384 -0
- package/dist/daemon/router.d.ts +60 -1
- package/dist/daemon/router.js +281 -20
- package/dist/daemon/user-directory.d.ts +111 -0
- package/dist/daemon/user-directory.js +233 -0
- package/dist/dashboard/out/404.html +1 -1
- package/dist/dashboard/out/_next/static/chunks/532-bace199897eeab37.js +9 -0
- package/dist/dashboard/out/_next/static/chunks/766-b54f0853794b78c3.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/83-b51836037078006c.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/891-6cd50de1224f70bb.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/899-fc02ed79e3de4302.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/app/onboarding/{page-3fdfa60e53f2810d.js → page-8553743baca53a00.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/app/app/page-c617745b81344f4f.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/metrics/page-f829604fb75a831a.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/{page-77e9c65420a06cfb.js → page-dc786c183425c2ac.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/app/providers/page-84322991d7244499.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/providers/setup/[provider]/page-05606941a8e2be83.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/{main-ed4e1fb6f29c34cf.js → main-2ee6beb2ae96d210.js} +1 -1
- package/dist/dashboard/out/_next/static/css/48a8fbe3e659080e.css +1 -0
- package/dist/dashboard/out/_next/static/css/fe4b28883eeff359.css +1 -0
- package/dist/dashboard/out/_next/static/sDcbGRTYLcpPvyTs_rsNb/_ssgManifest.js +1 -0
- package/dist/dashboard/out/app/onboarding.html +1 -1
- package/dist/dashboard/out/app/onboarding.txt +3 -3
- package/dist/dashboard/out/app.html +1 -1
- package/dist/dashboard/out/app.txt +3 -3
- package/dist/dashboard/out/apple-icon.png +0 -0
- package/dist/dashboard/out/connect-repos.html +1 -1
- package/dist/dashboard/out/connect-repos.txt +2 -2
- package/dist/dashboard/out/history.html +1 -1
- package/dist/dashboard/out/history.txt +2 -2
- package/dist/dashboard/out/index.html +1 -1
- package/dist/dashboard/out/index.txt +3 -3
- package/dist/dashboard/out/login.html +2 -2
- package/dist/dashboard/out/login.txt +2 -2
- package/dist/dashboard/out/metrics.html +1 -1
- package/dist/dashboard/out/metrics.txt +3 -3
- package/dist/dashboard/out/pricing.html +2 -2
- package/dist/dashboard/out/pricing.txt +3 -3
- package/dist/dashboard/out/providers/setup/claude.html +1 -0
- package/dist/dashboard/out/providers/setup/claude.txt +8 -0
- package/dist/dashboard/out/providers/setup/codex.html +1 -0
- package/dist/dashboard/out/providers/setup/codex.txt +8 -0
- package/dist/dashboard/out/providers.html +1 -1
- package/dist/dashboard/out/providers.txt +3 -3
- package/dist/dashboard/out/signup.html +2 -2
- package/dist/dashboard/out/signup.txt +2 -2
- package/dist/dashboard-server/server.js +316 -12
- package/dist/dashboard-server/user-bridge.d.ts +103 -0
- package/dist/dashboard-server/user-bridge.js +189 -0
- package/dist/protocol/channels.d.ts +205 -0
- package/dist/protocol/channels.js +154 -0
- package/dist/protocol/types.d.ts +13 -1
- package/dist/resiliency/provider-context.js +2 -0
- package/dist/shared/cli-auth-config.d.ts +19 -0
- package/dist/shared/cli-auth-config.js +58 -2
- package/dist/utils/agent-config.js +1 -1
- package/dist/wrapper/auth-detection.d.ts +49 -0
- package/dist/wrapper/auth-detection.js +192 -0
- package/dist/wrapper/base-wrapper.d.ts +153 -0
- package/dist/wrapper/base-wrapper.js +393 -0
- package/dist/wrapper/client.d.ts +7 -1
- package/dist/wrapper/client.js +3 -0
- package/dist/wrapper/index.d.ts +1 -0
- package/dist/wrapper/index.js +4 -3
- package/dist/wrapper/pty-wrapper.d.ts +62 -84
- package/dist/wrapper/pty-wrapper.js +154 -180
- package/dist/wrapper/tmux-wrapper.d.ts +41 -66
- package/dist/wrapper/tmux-wrapper.js +90 -134
- package/package.json +4 -2
- package/scripts/postinstall.js +11 -155
- package/scripts/test-interactive-terminal.sh +248 -0
- package/dist/cloud/vault/index.d.ts +0 -76
- package/dist/cloud/vault/index.js +0 -219
- package/dist/dashboard/out/_next/static/chunks/699-3b1cd6618a45d259.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/724-2dae7627550ab88f.js +0 -9
- package/dist/dashboard/out/_next/static/chunks/766-1f2dd8cb7f766b0b.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/app/page-e6381e5a6e1fbcfd.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/metrics/page-67a3e98d9a43a6ed.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/providers/page-e88bc117ef7671c3.js +0 -1
- package/dist/dashboard/out/_next/static/css/29852f26181969a0.css +0 -1
- package/dist/dashboard/out/_next/static/css/7c3ae9e8617d42a5.css +0 -1
- package/dist/dashboard/out/_next/static/wPgKJtcOmTFLpUncDg16A/_ssgManifest.js +0 -1
- /package/dist/dashboard/out/_next/static/{wPgKJtcOmTFLpUncDg16A → sDcbGRTYLcpPvyTs_rsNb}/_buildManifest.js +0 -0
|
@@ -4,55 +4,42 @@
|
|
|
4
4
|
* Unlike TmuxWrapper which provides interactive terminal access,
|
|
5
5
|
* PtyWrapper runs agents headlessly with output capture for logs.
|
|
6
6
|
* Used for spawned workers that don't need direct user interaction.
|
|
7
|
+
*
|
|
8
|
+
* Extends BaseWrapper for shared message handling, spawn/release,
|
|
9
|
+
* and continuity integration.
|
|
7
10
|
*/
|
|
8
11
|
import * as pty from 'node-pty';
|
|
9
12
|
import fs from 'node:fs';
|
|
10
13
|
import path from 'node:path';
|
|
11
|
-
import {
|
|
12
|
-
import { RelayClient } from './client.js';
|
|
14
|
+
import { BaseWrapper } from './base-wrapper.js';
|
|
13
15
|
import { parseSummaryWithDetails, parseSessionEndFromOutput, isPlaceholderTarget } from './parser.js';
|
|
14
16
|
import { getProjectPaths } from '../utils/project-namespace.js';
|
|
15
17
|
import { getTrailEnvVars } from '../trajectory/integration.js';
|
|
16
18
|
import { findAgentConfig } from '../utils/agent-config.js';
|
|
17
19
|
import { HookRegistry, createTrajectoryHooks } from '../hooks/index.js';
|
|
18
|
-
import {
|
|
19
|
-
import { INJECTION_CONSTANTS, stripAnsi, sleep, buildInjectionString, injectWithRetry as sharedInjectWithRetry,
|
|
20
|
+
import { parseContinuityCommand, hasContinuityCommand } from '../continuity/index.js';
|
|
21
|
+
import { INJECTION_CONSTANTS, stripAnsi, sleep, buildInjectionString, injectWithRetry as sharedInjectWithRetry, CLI_QUIRKS, } from './shared.js';
|
|
22
|
+
import { detectProviderAuthRevocation } from './auth-detection.js';
|
|
20
23
|
/** Maximum lines to keep in output buffer */
|
|
21
24
|
const MAX_BUFFER_LINES = 10000;
|
|
22
|
-
export class PtyWrapper extends
|
|
25
|
+
export class PtyWrapper extends BaseWrapper {
|
|
26
|
+
// Override config with PtyWrapper-specific type
|
|
23
27
|
config;
|
|
28
|
+
// PTY-specific state
|
|
24
29
|
ptyProcess;
|
|
25
|
-
client;
|
|
26
|
-
running = false;
|
|
27
30
|
outputBuffer = [];
|
|
28
31
|
rawBuffer = '';
|
|
29
|
-
relayPrefix;
|
|
30
|
-
cliType;
|
|
31
|
-
sentMessageHashes = new Set();
|
|
32
|
-
receivedMessageIds = new Set(); // Dedup incoming messages
|
|
33
|
-
processedSpawnCommands = new Set();
|
|
34
|
-
processedReleaseCommands = new Set();
|
|
35
|
-
pendingFencedSpawn = null;
|
|
36
|
-
messageQueue = [];
|
|
37
|
-
isInjecting = false;
|
|
38
32
|
readyForMessages = false;
|
|
39
33
|
lastOutputTime = 0;
|
|
40
|
-
injectionMetrics = createInjectionMetrics();
|
|
41
34
|
logFilePath;
|
|
42
35
|
logStream;
|
|
43
36
|
acceptedPrompts = new Set(); // Track which prompts have been accepted
|
|
44
37
|
hookRegistry;
|
|
45
38
|
sessionStartTime = Date.now();
|
|
46
|
-
continuity;
|
|
47
|
-
agentId;
|
|
48
|
-
processedContinuityCommands = new Set();
|
|
49
|
-
lastSummaryRawContent = ''; // Dedup summary event emissions
|
|
50
|
-
sessionEndProcessed = false; // Track if we've already emitted session-end
|
|
51
39
|
inThinkingBlock = false; // Track if inside <thinking>...</thinking>
|
|
52
40
|
lastSummaryTime = Date.now(); // Track when last summary was output
|
|
53
41
|
outputsSinceSummary = 0; // Count outputs since last summary
|
|
54
42
|
detectedTask; // Auto-detected task from agent config
|
|
55
|
-
sessionEndData; // Store SESSION_END data for handoff
|
|
56
43
|
instructionsInjected = false; // Track if init instructions have been injected
|
|
57
44
|
continuityInjected = false; // Track if continuity context has been injected
|
|
58
45
|
recentLogChunks = new Map(); // Dedup log streaming (hash -> timestamp)
|
|
@@ -60,12 +47,13 @@ export class PtyWrapper extends EventEmitter {
|
|
|
60
47
|
static LOG_DEDUP_MAX_SIZE = 100; // Max entries in dedup map
|
|
61
48
|
lastParsedLength = 0; // Track last parsed position to avoid re-parsing entire buffer
|
|
62
49
|
lastContinuityParsedLength = 0; // Same for continuity commands
|
|
50
|
+
// Auth revocation detection state
|
|
51
|
+
authRevoked = false;
|
|
52
|
+
lastAuthCheck = 0;
|
|
53
|
+
AUTH_CHECK_INTERVAL = 5000; // Check every 5 seconds max
|
|
63
54
|
constructor(config) {
|
|
64
|
-
super();
|
|
55
|
+
super(config);
|
|
65
56
|
this.config = config;
|
|
66
|
-
this.relayPrefix = config.relayPrefix ?? getDefaultRelayPrefix();
|
|
67
|
-
// Detect CLI type from command for special handling
|
|
68
|
-
this.cliType = config.cliType ?? detectCliType(config.command);
|
|
69
57
|
// Auto-detect agent role from .claude/agents/ or .openagents/ if task not provided
|
|
70
58
|
let detectedTask = config.task;
|
|
71
59
|
if (!detectedTask) {
|
|
@@ -78,15 +66,7 @@ export class PtyWrapper extends EventEmitter {
|
|
|
78
66
|
}
|
|
79
67
|
// Store detected task for use in hook registry
|
|
80
68
|
this.detectedTask = detectedTask;
|
|
81
|
-
|
|
82
|
-
agentName: config.name,
|
|
83
|
-
socketPath: config.socketPath,
|
|
84
|
-
cli: this.cliType,
|
|
85
|
-
task: detectedTask,
|
|
86
|
-
workingDirectory: config.cwd ?? process.cwd(),
|
|
87
|
-
quiet: true,
|
|
88
|
-
});
|
|
89
|
-
// Initialize hook registry
|
|
69
|
+
// Initialize hook registry (PTY-specific)
|
|
90
70
|
const projectPaths = getProjectPaths();
|
|
91
71
|
this.hookRegistry = new HookRegistry({
|
|
92
72
|
agentName: config.name,
|
|
@@ -112,13 +92,29 @@ export class PtyWrapper extends EventEmitter {
|
|
|
112
92
|
if (config.hooks) {
|
|
113
93
|
this.hookRegistry.registerLifecycleHooks(config.hooks);
|
|
114
94
|
}
|
|
115
|
-
// Initialize continuity manager
|
|
116
|
-
this.continuity = getContinuityManager({ defaultCli: 'spawned' });
|
|
117
|
-
// Handle incoming messages
|
|
118
|
-
this.client.onMessage = (from, payload, messageId, meta, originalTo) => {
|
|
119
|
-
this.handleIncomingMessage(from, payload, messageId, meta, originalTo);
|
|
120
|
-
};
|
|
121
95
|
}
|
|
96
|
+
// =========================================================================
|
|
97
|
+
// Abstract method implementations (required by BaseWrapper)
|
|
98
|
+
// =========================================================================
|
|
99
|
+
/**
|
|
100
|
+
* Inject content into the PTY process.
|
|
101
|
+
* Used by BaseWrapper for message injection.
|
|
102
|
+
*/
|
|
103
|
+
async performInjection(content) {
|
|
104
|
+
if (this.ptyProcess && this.running) {
|
|
105
|
+
this.ptyProcess.write(content);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Get cleaned output buffer for command parsing.
|
|
110
|
+
* Strips ANSI codes and returns raw buffer content.
|
|
111
|
+
*/
|
|
112
|
+
getCleanOutput() {
|
|
113
|
+
return stripAnsi(this.rawBuffer);
|
|
114
|
+
}
|
|
115
|
+
// =========================================================================
|
|
116
|
+
// Lifecycle methods
|
|
117
|
+
// =========================================================================
|
|
122
118
|
/**
|
|
123
119
|
* Start the agent process
|
|
124
120
|
*/
|
|
@@ -188,16 +184,19 @@ export class PtyWrapper extends EventEmitter {
|
|
|
188
184
|
}
|
|
189
185
|
this.running = true;
|
|
190
186
|
this.sessionStartTime = Date.now();
|
|
191
|
-
//
|
|
192
|
-
this.
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
.
|
|
199
|
-
|
|
200
|
-
|
|
187
|
+
// Skip hooks and continuity in interactive mode - user handles all prompts directly
|
|
188
|
+
if (!this.config.interactive) {
|
|
189
|
+
// Dispatch session start hook (handles trajectory initialization)
|
|
190
|
+
this.hookRegistry.dispatchSessionStart().catch(err => {
|
|
191
|
+
console.error(`[pty:${this.config.name}] Session start hook error:`, err);
|
|
192
|
+
});
|
|
193
|
+
// Initialize continuity and get agentId, then inject context
|
|
194
|
+
this.initializeAgentId()
|
|
195
|
+
.then(() => this.injectContinuityContext())
|
|
196
|
+
.catch(err => {
|
|
197
|
+
console.error(`[pty:${this.config.name}] Agent ID/continuity initialization error:`, err);
|
|
198
|
+
});
|
|
199
|
+
}
|
|
201
200
|
// Capture output
|
|
202
201
|
this.ptyProcess.onData((data) => {
|
|
203
202
|
this.handleOutput(data);
|
|
@@ -210,48 +209,19 @@ export class PtyWrapper extends EventEmitter {
|
|
|
210
209
|
this.client.destroy();
|
|
211
210
|
});
|
|
212
211
|
// Inject initial instructions after a delay, then mark ready for messages
|
|
212
|
+
// Skip in interactive mode - user handles all prompts directly
|
|
213
213
|
setTimeout(() => {
|
|
214
|
-
this.
|
|
215
|
-
|
|
216
|
-
// Process any messages that arrived while waiting
|
|
217
|
-
this.processMessageQueue();
|
|
218
|
-
}, 2000);
|
|
219
|
-
}
|
|
220
|
-
/**
|
|
221
|
-
* Initialize agent ID for continuity/resume functionality
|
|
222
|
-
*/
|
|
223
|
-
async initializeAgentId() {
|
|
224
|
-
if (!this.continuity)
|
|
225
|
-
return;
|
|
226
|
-
try {
|
|
227
|
-
let ledger;
|
|
228
|
-
// If resuming from a previous agent ID, try to find that ledger
|
|
229
|
-
if (this.config.resumeAgentId) {
|
|
230
|
-
ledger = await this.continuity.findLedgerByAgentId(this.config.resumeAgentId);
|
|
231
|
-
if (ledger) {
|
|
232
|
-
console.log(`[pty:${this.config.name}] Resuming agent ID: ${ledger.agentId} (from previous session)`);
|
|
233
|
-
}
|
|
234
|
-
else {
|
|
235
|
-
console.error(`[pty:${this.config.name}] Resume agent ID ${this.config.resumeAgentId} not found, creating new`);
|
|
236
|
-
}
|
|
214
|
+
if (!this.config.interactive) {
|
|
215
|
+
this.injectInstructions();
|
|
237
216
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
217
|
+
this.readyForMessages = true;
|
|
218
|
+
// Process any messages that arrived while waiting (skip in interactive mode)
|
|
219
|
+
if (!this.config.interactive) {
|
|
220
|
+
this.processMessageQueue();
|
|
242
221
|
}
|
|
243
|
-
|
|
244
|
-
}
|
|
245
|
-
catch (err) {
|
|
246
|
-
console.error(`[pty:${this.config.name}] Failed to initialize agent ID: ${err.message}`);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
/**
|
|
250
|
-
* Get the current agent ID
|
|
251
|
-
*/
|
|
252
|
-
getAgentId() {
|
|
253
|
-
return this.agentId;
|
|
222
|
+
}, 2000);
|
|
254
223
|
}
|
|
224
|
+
// Note: initializeAgentId() and getAgentId() are inherited from BaseWrapper
|
|
255
225
|
/**
|
|
256
226
|
* Inject continuity context from previous session.
|
|
257
227
|
* Called after agent ID initialization to restore state from ledger.
|
|
@@ -310,6 +280,10 @@ export class PtyWrapper extends EventEmitter {
|
|
|
310
280
|
* ->continuity:uncertain "..." - Mark item as uncertain
|
|
311
281
|
* ->continuity:handoff <<<...>>> - Create explicit handoff
|
|
312
282
|
*/
|
|
283
|
+
/**
|
|
284
|
+
* Parse continuity commands from output.
|
|
285
|
+
* Overrides BaseWrapper to use client.sendMessage instead of queuing.
|
|
286
|
+
*/
|
|
313
287
|
async parseContinuityCommands(content) {
|
|
314
288
|
if (!this.continuity)
|
|
315
289
|
return;
|
|
@@ -334,9 +308,7 @@ export class PtyWrapper extends EventEmitter {
|
|
|
334
308
|
const response = await this.continuity.handleCommand(this.config.name, command);
|
|
335
309
|
if (response) {
|
|
336
310
|
// Inject response via relay message to self
|
|
337
|
-
this.client.sendMessage(this.config.name, response, 'message',
|
|
338
|
-
thread: 'continuity-response',
|
|
339
|
-
});
|
|
311
|
+
this.client.sendMessage(this.config.name, response, 'message', undefined, 'continuity-response');
|
|
340
312
|
console.log(`[pty:${this.config.name}] Continuity command handled: ${command.type}`);
|
|
341
313
|
}
|
|
342
314
|
}
|
|
@@ -386,23 +358,31 @@ export class PtyWrapper extends EventEmitter {
|
|
|
386
358
|
// Parse for relay commands
|
|
387
359
|
this.parseRelayCommands();
|
|
388
360
|
// Dispatch output hook (handles phase detection, etc.)
|
|
361
|
+
// Skip in interactive mode - no hooks should inject content
|
|
389
362
|
const cleanData = stripAnsi(data);
|
|
390
|
-
this.
|
|
391
|
-
|
|
392
|
-
|
|
363
|
+
if (!this.config.interactive) {
|
|
364
|
+
this.hookRegistry.dispatchOutput(cleanData, data).catch(err => {
|
|
365
|
+
console.error(`[pty:${this.config.name}] Output hook error:`, err);
|
|
366
|
+
});
|
|
367
|
+
}
|
|
393
368
|
// Check for [[SUMMARY]] and [[SESSION_END]] blocks and emit events
|
|
394
369
|
// This allows cloud services to handle persistence without hardcoding storage
|
|
395
370
|
const cleanContent = stripAnsi(this.rawBuffer);
|
|
396
371
|
this.checkForSummaryAndEmit(cleanContent);
|
|
397
372
|
this.checkForSessionEndAndEmit(cleanContent);
|
|
373
|
+
// Check for auth revocation patterns
|
|
374
|
+
this.checkAuthRevocation(cleanContent);
|
|
398
375
|
// Parse for continuity commands (->continuity:save, ->continuity:load, etc.)
|
|
399
376
|
// Use rawBuffer (accumulated content) not immediate chunk, since multi-line
|
|
400
377
|
// fenced commands like ->continuity:save <<<...>>> span multiple output events
|
|
401
378
|
// Optimization: Only parse new content with lookback for incomplete fenced commands
|
|
402
|
-
|
|
379
|
+
// Skip in interactive mode - no continuity features needed
|
|
380
|
+
if (!this.config.interactive && cleanContent.length > this.lastContinuityParsedLength) {
|
|
403
381
|
const lookbackStart = Math.max(0, this.lastContinuityParsedLength - 500);
|
|
404
382
|
const contentToParse = cleanContent.substring(lookbackStart);
|
|
405
|
-
|
|
383
|
+
// Join continuation lines for multi-line fenced commands
|
|
384
|
+
const joinedContent = this.joinContinuationLines(contentToParse);
|
|
385
|
+
this.parseContinuityCommands(joinedContent).catch(err => {
|
|
406
386
|
console.error(`[pty:${this.config.name}] Continuity command parsing error:`, err);
|
|
407
387
|
});
|
|
408
388
|
this.lastContinuityParsedLength = cleanContent.length;
|
|
@@ -506,6 +486,9 @@ export class PtyWrapper extends EventEmitter {
|
|
|
506
486
|
handleAutoAcceptPrompts(data) {
|
|
507
487
|
if (!this.ptyProcess || !this.running)
|
|
508
488
|
return;
|
|
489
|
+
// Skip auto-accept in interactive mode - user responds to prompts directly
|
|
490
|
+
if (this.config.interactive)
|
|
491
|
+
return;
|
|
509
492
|
const cleanData = stripAnsi(data);
|
|
510
493
|
// Check for the permission acceptance prompt (--dangerously-skip-permissions)
|
|
511
494
|
// Pattern: "2. Yes, I accept" in the output
|
|
@@ -744,23 +727,17 @@ export class PtyWrapper extends EventEmitter {
|
|
|
744
727
|
}
|
|
745
728
|
}
|
|
746
729
|
/**
|
|
747
|
-
* Send relay command to daemon
|
|
730
|
+
* Send relay command to daemon.
|
|
731
|
+
* Extends BaseWrapper to add PTY-specific logging and hook dispatch.
|
|
748
732
|
*/
|
|
749
733
|
sendRelayCommand(cmd) {
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
if
|
|
756
|
-
|
|
757
|
-
return;
|
|
758
|
-
}
|
|
759
|
-
const success = this.client.sendMessage(cmd.to, cmd.body, cmd.kind, cmd.data, cmd.thread);
|
|
760
|
-
console.log(`[pty:${this.config.name}] Sent message to ${cmd.to}: ${success ? 'success' : 'failed'}`);
|
|
761
|
-
if (success) {
|
|
762
|
-
this.sentMessageHashes.add(msgHash);
|
|
763
|
-
// Dispatch message sent hook
|
|
734
|
+
// Check if this message would be sent (before BaseWrapper deduplicates)
|
|
735
|
+
const msgHash = `${cmd.to}:${cmd.body.substring(0, 100)}`;
|
|
736
|
+
const wouldSend = !this.sentMessageHashes.has(msgHash) && this.client.state === 'READY';
|
|
737
|
+
// Call base class to handle deduplication and actual send
|
|
738
|
+
super.sendRelayCommand(cmd);
|
|
739
|
+
// PTY-specific: Dispatch message sent hook if the message was sent
|
|
740
|
+
if (wouldSend && this.sentMessageHashes.has(msgHash)) {
|
|
764
741
|
this.hookRegistry.dispatchMessageSent(cmd.to, cmd.body, cmd.thread).catch(err => {
|
|
765
742
|
console.error(`[pty:${this.config.name}] Message sent hook error:`, err);
|
|
766
743
|
});
|
|
@@ -794,6 +771,8 @@ export class PtyWrapper extends EventEmitter {
|
|
|
794
771
|
* - Command must be at start of line (after whitespace)
|
|
795
772
|
* - Agent name must be PascalCase (e.g., Backend, Frontend, Worker1)
|
|
796
773
|
* - CLI must be a known type (claude, codex, gemini, etc.)
|
|
774
|
+
*
|
|
775
|
+
* Overrides BaseWrapper to add PTY-specific validation and logging.
|
|
797
776
|
*/
|
|
798
777
|
parseSpawnReleaseCommands(content) {
|
|
799
778
|
// Need either API port or callbacks to handle spawn/release
|
|
@@ -968,7 +947,8 @@ export class PtyWrapper extends EventEmitter {
|
|
|
968
947
|
}
|
|
969
948
|
}
|
|
970
949
|
/**
|
|
971
|
-
* Execute spawn via API or callback
|
|
950
|
+
* Execute spawn via API or callback.
|
|
951
|
+
* Overrides BaseWrapper to add PTY-specific logging and API path.
|
|
972
952
|
*/
|
|
973
953
|
async executeSpawn(name, cli, task) {
|
|
974
954
|
console.log(`[pty:${this.config.name}] [SPAWN-DEBUG] executeSpawn called: name=${name}, cli=${cli}, task="${task.substring(0, 50)}..."`);
|
|
@@ -1004,7 +984,8 @@ export class PtyWrapper extends EventEmitter {
|
|
|
1004
984
|
}
|
|
1005
985
|
}
|
|
1006
986
|
/**
|
|
1007
|
-
* Execute release via API or callback
|
|
987
|
+
* Execute release via API or callback.
|
|
988
|
+
* Overrides BaseWrapper to add PTY-specific logging and API path.
|
|
1008
989
|
*/
|
|
1009
990
|
async executeRelease(name) {
|
|
1010
991
|
if (this.config.dashboardPort) {
|
|
@@ -1036,25 +1017,15 @@ export class PtyWrapper extends EventEmitter {
|
|
|
1036
1017
|
}
|
|
1037
1018
|
}
|
|
1038
1019
|
/**
|
|
1039
|
-
* Handle incoming message from relay
|
|
1040
|
-
*
|
|
1020
|
+
* Handle incoming message from relay.
|
|
1021
|
+
* Extends BaseWrapper to add PTY-specific behavior.
|
|
1041
1022
|
*/
|
|
1042
1023
|
handleIncomingMessage(from, payload, messageId, meta, originalTo) {
|
|
1043
|
-
//
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
return;
|
|
1047
|
-
}
|
|
1048
|
-
this.receivedMessageIds.add(messageId);
|
|
1049
|
-
// Limit dedup set size to prevent memory leak
|
|
1050
|
-
if (this.receivedMessageIds.size > 1000) {
|
|
1051
|
-
const oldest = this.receivedMessageIds.values().next().value;
|
|
1052
|
-
if (oldest)
|
|
1053
|
-
this.receivedMessageIds.delete(oldest);
|
|
1054
|
-
}
|
|
1055
|
-
this.messageQueue.push({ from, body: payload.body, messageId, thread: payload.thread, importance: meta?.importance, data: payload.data, originalTo });
|
|
1024
|
+
// Call base class to handle deduplication and queuing
|
|
1025
|
+
super.handleIncomingMessage(from, payload, messageId, meta, originalTo);
|
|
1026
|
+
// PTY-specific: Process the message queue immediately
|
|
1056
1027
|
this.processMessageQueue();
|
|
1057
|
-
// Dispatch message received hook
|
|
1028
|
+
// PTY-specific: Dispatch message received hook
|
|
1058
1029
|
this.hookRegistry.dispatchMessageReceived(from, payload.body, messageId).catch(err => {
|
|
1059
1030
|
console.error(`[pty:${this.config.name}] Message received hook error:`, err);
|
|
1060
1031
|
});
|
|
@@ -1323,12 +1294,6 @@ export class PtyWrapper extends EventEmitter {
|
|
|
1323
1294
|
this.logStream = undefined;
|
|
1324
1295
|
}
|
|
1325
1296
|
}
|
|
1326
|
-
get isRunning() {
|
|
1327
|
-
return this.running;
|
|
1328
|
-
}
|
|
1329
|
-
get name() {
|
|
1330
|
-
return this.config.name;
|
|
1331
|
-
}
|
|
1332
1297
|
get pid() {
|
|
1333
1298
|
return this.ptyProcess?.pid;
|
|
1334
1299
|
}
|
|
@@ -1340,6 +1305,9 @@ export class PtyWrapper extends EventEmitter {
|
|
|
1340
1305
|
* Works with any CLI (Claude, Gemini, Codex, etc.)
|
|
1341
1306
|
*/
|
|
1342
1307
|
trackOutputAndRemind(data) {
|
|
1308
|
+
// Skip in interactive mode - user handles all prompts directly
|
|
1309
|
+
if (this.config.interactive)
|
|
1310
|
+
return;
|
|
1343
1311
|
// Disabled if config.summaryReminder === false or env RELAY_SUMMARY_REMINDER_ENABLED=false
|
|
1344
1312
|
if (this.config.summaryReminder === false)
|
|
1345
1313
|
return;
|
|
@@ -1417,34 +1385,7 @@ export class PtyWrapper extends EventEmitter {
|
|
|
1417
1385
|
summary,
|
|
1418
1386
|
});
|
|
1419
1387
|
}
|
|
1420
|
-
|
|
1421
|
-
* Save a parsed summary to the continuity ledger.
|
|
1422
|
-
* Maps summary fields to ledger fields for session recovery.
|
|
1423
|
-
*/
|
|
1424
|
-
async saveSummaryToLedger(summary) {
|
|
1425
|
-
if (!this.continuity)
|
|
1426
|
-
return;
|
|
1427
|
-
const updates = {};
|
|
1428
|
-
// Map summary fields to ledger fields
|
|
1429
|
-
if (summary.currentTask) {
|
|
1430
|
-
updates.currentTask = summary.currentTask;
|
|
1431
|
-
}
|
|
1432
|
-
if (summary.completedTasks && summary.completedTasks.length > 0) {
|
|
1433
|
-
updates.completed = summary.completedTasks;
|
|
1434
|
-
}
|
|
1435
|
-
if (summary.context) {
|
|
1436
|
-
// Store context in inProgress as "next steps" hint
|
|
1437
|
-
updates.inProgress = [summary.context];
|
|
1438
|
-
}
|
|
1439
|
-
if (summary.files && summary.files.length > 0) {
|
|
1440
|
-
updates.fileContext = summary.files.map((f) => ({ path: f }));
|
|
1441
|
-
}
|
|
1442
|
-
// Only save if we have meaningful updates
|
|
1443
|
-
if (Object.keys(updates).length > 0) {
|
|
1444
|
-
await this.continuity.saveLedger(this.config.name, updates);
|
|
1445
|
-
console.log(`[pty:${this.config.name}] Saved summary to continuity ledger`);
|
|
1446
|
-
}
|
|
1447
|
-
}
|
|
1388
|
+
// Note: saveSummaryToLedger() is inherited from BaseWrapper
|
|
1448
1389
|
/**
|
|
1449
1390
|
* Check for [[SESSION_END]] blocks and emit 'session-end' event.
|
|
1450
1391
|
* Allows cloud services to handle session closure without hardcoding storage.
|
|
@@ -1466,28 +1407,61 @@ export class PtyWrapper extends EventEmitter {
|
|
|
1466
1407
|
});
|
|
1467
1408
|
}
|
|
1468
1409
|
/**
|
|
1469
|
-
*
|
|
1470
|
-
*
|
|
1410
|
+
* Check for auth revocation patterns in output.
|
|
1411
|
+
* Detects when the CLI's OAuth session has been revoked (e.g., user logged in elsewhere).
|
|
1412
|
+
* Emits 'auth_revoked' event and sends notification to relay daemon.
|
|
1471
1413
|
*/
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
this.
|
|
1475
|
-
|
|
1414
|
+
checkAuthRevocation(output) {
|
|
1415
|
+
// Only check once - auth revocation is a terminal state
|
|
1416
|
+
if (this.authRevoked)
|
|
1417
|
+
return;
|
|
1418
|
+
// Throttle checks to avoid performance impact
|
|
1419
|
+
const now = Date.now();
|
|
1420
|
+
if (now - this.lastAuthCheck < this.AUTH_CHECK_INTERVAL)
|
|
1421
|
+
return;
|
|
1422
|
+
this.lastAuthCheck = now;
|
|
1423
|
+
// Determine provider from config
|
|
1424
|
+
const provider = this.config.command || this.cliType || 'claude';
|
|
1425
|
+
// Check for auth revocation patterns
|
|
1426
|
+
const result = detectProviderAuthRevocation(output, provider);
|
|
1427
|
+
if (result.detected && result.confidence !== 'low') {
|
|
1428
|
+
this.authRevoked = true;
|
|
1429
|
+
console.error(`[pty:${this.config.name}] Auth revocation detected: ` +
|
|
1430
|
+
`pattern="${result.pattern}" confidence=${result.confidence} ` +
|
|
1431
|
+
`message="${result.message}"`);
|
|
1432
|
+
// Send notification to relay daemon via system channel
|
|
1433
|
+
if (this.client.state === 'READY') {
|
|
1434
|
+
const authPayload = JSON.stringify({
|
|
1435
|
+
type: 'auth_revoked',
|
|
1436
|
+
agent: this.config.name,
|
|
1437
|
+
provider,
|
|
1438
|
+
message: result.message,
|
|
1439
|
+
confidence: result.confidence,
|
|
1440
|
+
timestamp: new Date().toISOString(),
|
|
1441
|
+
});
|
|
1442
|
+
this.client.sendMessage('#system', authPayload, 'message');
|
|
1443
|
+
}
|
|
1444
|
+
// Emit event for external handlers (cloud services, dashboard)
|
|
1445
|
+
this.emit('auth_revoked', {
|
|
1446
|
+
agentName: this.config.name,
|
|
1447
|
+
provider,
|
|
1448
|
+
message: result.message,
|
|
1449
|
+
confidence: result.confidence,
|
|
1450
|
+
});
|
|
1451
|
+
}
|
|
1476
1452
|
}
|
|
1477
1453
|
/**
|
|
1478
|
-
*
|
|
1454
|
+
* Reset auth state (e.g., after re-authentication)
|
|
1479
1455
|
*/
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
successRate: calculateSuccessRate(this.injectionMetrics),
|
|
1484
|
-
};
|
|
1456
|
+
resetAuthState() {
|
|
1457
|
+
this.authRevoked = false;
|
|
1458
|
+
this.lastAuthCheck = 0;
|
|
1485
1459
|
}
|
|
1486
1460
|
/**
|
|
1487
|
-
*
|
|
1461
|
+
* Check if auth has been revoked
|
|
1488
1462
|
*/
|
|
1489
|
-
|
|
1490
|
-
return this.
|
|
1463
|
+
isAuthRevoked() {
|
|
1464
|
+
return this.authRevoked;
|
|
1491
1465
|
}
|
|
1492
1466
|
}
|
|
1493
1467
|
//# sourceMappingURL=pty-wrapper.js.map
|