agent-relay 1.2.3 → 1.3.0
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/T1tgCqVWHFIkV7ClEtzD7/_ssgManifest.js +1 -0
- 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-bb19a9b3d9b39ea6.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/app/onboarding/page-8939b0fc700f7eca.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/app/page-5af1b6b439858aa6.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/connect-repos/page-f45ecbc3e06134fc.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/history/{page-abb9ab2d329f56e9.js → page-8c8bed33beb2bf1c.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/app/layout-2433bb48965f4333.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/login/{page-c22d080201cbd9fb.js → page-16f3b49e55b1e0ed.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/app/metrics/page-ac39dc0cc3c26fa7.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/{page-77e9c65420a06cfb.js → page-4a5938c18a11a654.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/app/pricing/page-982a7000fee44014.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/providers/page-ac3a6ac433fd6001.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/providers/setup/[provider]/page-09f9caae98a18c09.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/signup/{page-68d34f50baa8ab6b.js → page-547dd0ca55ecd0ba.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/{main-ed4e1fb6f29c34cf.js → main-2ee6beb2ae96d210.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/{main-app-6e8e8d3ef4e0192a.js → main-app-5d692157a8eb1fd9.js} +1 -1
- package/dist/dashboard/out/_next/static/css/85d2af9c7ac74d62.css +1 -0
- package/dist/dashboard/out/_next/static/css/fe4b28883eeff359.css +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 +3 -3
- package/dist/dashboard/out/history.html +1 -1
- package/dist/dashboard/out/history.txt +3 -3
- 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 +3 -3
- 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 +3 -3
- 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/onboarding/page-3fdfa60e53f2810d.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/connect-repos/page-3538dfe0ffe984b8.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/layout-c0d118c0f92d969c.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/pricing/page-b08ed1c34d14434a.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 → T1tgCqVWHFIkV7ClEtzD7}/_buildManifest.js +0 -0
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BaseWrapper - Abstract base class for agent wrappers
|
|
3
|
+
*
|
|
4
|
+
* Provides shared functionality between TmuxWrapper and PtyWrapper:
|
|
5
|
+
* - Message queue management and deduplication
|
|
6
|
+
* - Spawn/release command parsing and execution
|
|
7
|
+
* - Continuity integration (agent ID, summary saving)
|
|
8
|
+
* - Relay command handling
|
|
9
|
+
* - Line joining for multi-line commands
|
|
10
|
+
*
|
|
11
|
+
* Subclasses implement:
|
|
12
|
+
* - start() - Initialize and start the agent process
|
|
13
|
+
* - stop() - Stop the agent process
|
|
14
|
+
* - performInjection() - Inject content into the agent
|
|
15
|
+
* - getCleanOutput() - Get cleaned output for parsing
|
|
16
|
+
*/
|
|
17
|
+
import { EventEmitter } from 'node:events';
|
|
18
|
+
import { RelayClient } from './client.js';
|
|
19
|
+
import { isPlaceholderTarget } from './parser.js';
|
|
20
|
+
import { getDefaultRelayPrefix, detectCliType, createInjectionMetrics, } from './shared.js';
|
|
21
|
+
import { getContinuityManager, parseContinuityCommand, hasContinuityCommand, } from '../continuity/index.js';
|
|
22
|
+
/**
|
|
23
|
+
* Abstract base class for agent wrappers
|
|
24
|
+
*/
|
|
25
|
+
export class BaseWrapper extends EventEmitter {
|
|
26
|
+
config;
|
|
27
|
+
client;
|
|
28
|
+
relayPrefix;
|
|
29
|
+
cliType;
|
|
30
|
+
running = false;
|
|
31
|
+
// Message queue state
|
|
32
|
+
messageQueue = [];
|
|
33
|
+
sentMessageHashes = new Set();
|
|
34
|
+
isInjecting = false;
|
|
35
|
+
receivedMessageIds = new Set();
|
|
36
|
+
injectionMetrics = createInjectionMetrics();
|
|
37
|
+
// Spawn/release state
|
|
38
|
+
processedSpawnCommands = new Set();
|
|
39
|
+
processedReleaseCommands = new Set();
|
|
40
|
+
pendingFencedSpawn = null;
|
|
41
|
+
// Continuity state
|
|
42
|
+
continuity;
|
|
43
|
+
agentId;
|
|
44
|
+
processedContinuityCommands = new Set();
|
|
45
|
+
sessionEndProcessed = false;
|
|
46
|
+
sessionEndData;
|
|
47
|
+
lastSummaryRawContent = '';
|
|
48
|
+
constructor(config) {
|
|
49
|
+
super();
|
|
50
|
+
this.config = config;
|
|
51
|
+
this.relayPrefix = config.relayPrefix ?? getDefaultRelayPrefix();
|
|
52
|
+
this.cliType = config.cliType ?? detectCliType(config.command);
|
|
53
|
+
// Initialize relay client with full config
|
|
54
|
+
this.client = new RelayClient({
|
|
55
|
+
agentName: config.name,
|
|
56
|
+
socketPath: config.socketPath,
|
|
57
|
+
cli: this.cliType,
|
|
58
|
+
task: config.task,
|
|
59
|
+
workingDirectory: config.cwd,
|
|
60
|
+
quiet: true,
|
|
61
|
+
});
|
|
62
|
+
// Initialize continuity manager
|
|
63
|
+
this.continuity = getContinuityManager({ defaultCli: this.cliType });
|
|
64
|
+
// Set up message handler
|
|
65
|
+
this.client.onMessage = (from, payload, messageId, meta, originalTo) => {
|
|
66
|
+
this.handleIncomingMessage(from, payload, messageId, meta, originalTo);
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
// =========================================================================
|
|
70
|
+
// Common getters
|
|
71
|
+
// =========================================================================
|
|
72
|
+
get isRunning() {
|
|
73
|
+
return this.running;
|
|
74
|
+
}
|
|
75
|
+
get name() {
|
|
76
|
+
return this.config.name;
|
|
77
|
+
}
|
|
78
|
+
getAgentId() {
|
|
79
|
+
return this.agentId;
|
|
80
|
+
}
|
|
81
|
+
getInjectionMetrics() {
|
|
82
|
+
const total = this.injectionMetrics.total;
|
|
83
|
+
const successes = this.injectionMetrics.successFirstTry + this.injectionMetrics.successWithRetry;
|
|
84
|
+
const successRate = total > 0
|
|
85
|
+
? (successes / total) * 100
|
|
86
|
+
: 100;
|
|
87
|
+
return {
|
|
88
|
+
...this.injectionMetrics,
|
|
89
|
+
successRate,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
get pendingMessageCount() {
|
|
93
|
+
return this.messageQueue.length;
|
|
94
|
+
}
|
|
95
|
+
// =========================================================================
|
|
96
|
+
// Message handling
|
|
97
|
+
// =========================================================================
|
|
98
|
+
/**
|
|
99
|
+
* Handle incoming message from relay
|
|
100
|
+
*/
|
|
101
|
+
handleIncomingMessage(from, payload, messageId, meta, originalTo) {
|
|
102
|
+
// Deduplicate by message ID
|
|
103
|
+
if (this.receivedMessageIds.has(messageId))
|
|
104
|
+
return;
|
|
105
|
+
this.receivedMessageIds.add(messageId);
|
|
106
|
+
// Limit dedup set size
|
|
107
|
+
if (this.receivedMessageIds.size > 1000) {
|
|
108
|
+
const oldest = this.receivedMessageIds.values().next().value;
|
|
109
|
+
if (oldest)
|
|
110
|
+
this.receivedMessageIds.delete(oldest);
|
|
111
|
+
}
|
|
112
|
+
// Queue the message
|
|
113
|
+
const queuedMsg = {
|
|
114
|
+
from,
|
|
115
|
+
body: payload.body,
|
|
116
|
+
messageId,
|
|
117
|
+
thread: payload.thread,
|
|
118
|
+
importance: meta?.importance,
|
|
119
|
+
data: payload.data,
|
|
120
|
+
originalTo,
|
|
121
|
+
};
|
|
122
|
+
this.messageQueue.push(queuedMsg);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Send a relay command via the client
|
|
126
|
+
*/
|
|
127
|
+
sendRelayCommand(cmd) {
|
|
128
|
+
// Validate target
|
|
129
|
+
if (isPlaceholderTarget(cmd.to))
|
|
130
|
+
return;
|
|
131
|
+
// Create hash for deduplication (use first 100 chars of body)
|
|
132
|
+
const hash = `${cmd.to}:${cmd.body.substring(0, 100)}`;
|
|
133
|
+
if (this.sentMessageHashes.has(hash))
|
|
134
|
+
return;
|
|
135
|
+
this.sentMessageHashes.add(hash);
|
|
136
|
+
// Limit hash set size
|
|
137
|
+
if (this.sentMessageHashes.size > 500) {
|
|
138
|
+
const oldest = this.sentMessageHashes.values().next().value;
|
|
139
|
+
if (oldest)
|
|
140
|
+
this.sentMessageHashes.delete(oldest);
|
|
141
|
+
}
|
|
142
|
+
// Only send if client ready
|
|
143
|
+
if (this.client.state !== 'READY')
|
|
144
|
+
return;
|
|
145
|
+
this.client.sendMessage(cmd.to, cmd.body, cmd.kind, cmd.data, cmd.thread);
|
|
146
|
+
}
|
|
147
|
+
// =========================================================================
|
|
148
|
+
// Spawn/release handling
|
|
149
|
+
// =========================================================================
|
|
150
|
+
/**
|
|
151
|
+
* Parse spawn and release commands from output
|
|
152
|
+
*/
|
|
153
|
+
parseSpawnReleaseCommands(content) {
|
|
154
|
+
// Single-line spawn: ->relay:spawn Name cli "task"
|
|
155
|
+
const spawnPattern = new RegExp(`${this.relayPrefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}spawn\\s+(\\w+)\\s+(\\w+)\\s+"([^"]+)"`);
|
|
156
|
+
const spawnMatch = content.match(spawnPattern);
|
|
157
|
+
if (spawnMatch) {
|
|
158
|
+
const [, name, cli, task] = spawnMatch;
|
|
159
|
+
const cmdHash = `spawn:${name}:${cli}:${task}`;
|
|
160
|
+
if (!this.processedSpawnCommands.has(cmdHash)) {
|
|
161
|
+
this.processedSpawnCommands.add(cmdHash);
|
|
162
|
+
this.executeSpawn(name, cli, task);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// Fenced spawn: ->relay:spawn Name cli <<<\ntask\n>>>
|
|
166
|
+
const fencedSpawnPattern = new RegExp(`${this.relayPrefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}spawn\\s+(\\w+)\\s+(\\w+)\\s+<<<\\n?([\\s\\S]*?)>>>`);
|
|
167
|
+
const fencedSpawnMatch = content.match(fencedSpawnPattern);
|
|
168
|
+
if (fencedSpawnMatch) {
|
|
169
|
+
const [, name, cli, task] = fencedSpawnMatch;
|
|
170
|
+
const cmdHash = `spawn:${name}:${cli}:${task.trim()}`;
|
|
171
|
+
if (!this.processedSpawnCommands.has(cmdHash)) {
|
|
172
|
+
this.processedSpawnCommands.add(cmdHash);
|
|
173
|
+
this.executeSpawn(name, cli, task.trim());
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// Release: ->relay:release Name
|
|
177
|
+
const releasePattern = new RegExp(`${this.relayPrefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}release\\s+(\\w+)`);
|
|
178
|
+
const releaseMatch = content.match(releasePattern);
|
|
179
|
+
if (releaseMatch) {
|
|
180
|
+
const name = releaseMatch[1];
|
|
181
|
+
const cmdHash = `release:${name}`;
|
|
182
|
+
if (!this.processedReleaseCommands.has(cmdHash)) {
|
|
183
|
+
this.processedReleaseCommands.add(cmdHash);
|
|
184
|
+
this.executeRelease(name);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Execute a spawn command
|
|
190
|
+
*/
|
|
191
|
+
async executeSpawn(name, cli, task) {
|
|
192
|
+
// Try dashboard API first
|
|
193
|
+
if (this.config.dashboardPort) {
|
|
194
|
+
try {
|
|
195
|
+
const response = await fetch(`http://localhost:${this.config.dashboardPort}/api/agents/spawn`, {
|
|
196
|
+
method: 'POST',
|
|
197
|
+
headers: { 'Content-Type': 'application/json' },
|
|
198
|
+
body: JSON.stringify({ name, cli, task }),
|
|
199
|
+
});
|
|
200
|
+
if (response.ok)
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
// Fall through to callback
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// Use callback
|
|
208
|
+
if (this.config.onSpawn) {
|
|
209
|
+
await this.config.onSpawn(name, cli, task);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Execute a release command
|
|
214
|
+
*/
|
|
215
|
+
async executeRelease(name) {
|
|
216
|
+
// Try dashboard API first
|
|
217
|
+
if (this.config.dashboardPort) {
|
|
218
|
+
try {
|
|
219
|
+
const response = await fetch(`http://localhost:${this.config.dashboardPort}/api/agents/${name}`, { method: 'DELETE' });
|
|
220
|
+
if (response.ok)
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
// Fall through to callback
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// Use callback
|
|
228
|
+
if (this.config.onRelease) {
|
|
229
|
+
await this.config.onRelease(name);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// =========================================================================
|
|
233
|
+
// Continuity handling
|
|
234
|
+
// =========================================================================
|
|
235
|
+
/**
|
|
236
|
+
* Initialize agent ID for continuity/resume
|
|
237
|
+
*/
|
|
238
|
+
async initializeAgentId() {
|
|
239
|
+
if (!this.continuity)
|
|
240
|
+
return;
|
|
241
|
+
try {
|
|
242
|
+
let ledger;
|
|
243
|
+
// If resuming, try to find previous ledger
|
|
244
|
+
if (this.config.resumeAgentId) {
|
|
245
|
+
ledger = await this.continuity.findLedgerByAgentId(this.config.resumeAgentId);
|
|
246
|
+
if (ledger) {
|
|
247
|
+
console.log(`[${this.config.name}] Resuming agent ID: ${ledger.agentId}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
// Otherwise get or create
|
|
251
|
+
if (!ledger) {
|
|
252
|
+
ledger = await this.continuity.getOrCreateLedger(this.config.name, this.cliType);
|
|
253
|
+
console.log(`[${this.config.name}] Agent ID: ${ledger.agentId}`);
|
|
254
|
+
}
|
|
255
|
+
this.agentId = ledger.agentId;
|
|
256
|
+
}
|
|
257
|
+
catch (err) {
|
|
258
|
+
console.error(`[${this.config.name}] Failed to initialize agent ID: ${err.message}`);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Parse continuity commands from output
|
|
263
|
+
*/
|
|
264
|
+
async parseContinuityCommands(content) {
|
|
265
|
+
if (!this.continuity)
|
|
266
|
+
return;
|
|
267
|
+
if (!hasContinuityCommand(content))
|
|
268
|
+
return;
|
|
269
|
+
const command = parseContinuityCommand(content);
|
|
270
|
+
if (!command)
|
|
271
|
+
return;
|
|
272
|
+
// Deduplication
|
|
273
|
+
const cmdHash = `${command.type}:${command.content || command.query || command.item || 'no-content'}`;
|
|
274
|
+
if (command.content && this.processedContinuityCommands.has(cmdHash))
|
|
275
|
+
return;
|
|
276
|
+
this.processedContinuityCommands.add(cmdHash);
|
|
277
|
+
// Limit dedup set size
|
|
278
|
+
if (this.processedContinuityCommands.size > 100) {
|
|
279
|
+
const oldest = this.processedContinuityCommands.values().next().value;
|
|
280
|
+
if (oldest)
|
|
281
|
+
this.processedContinuityCommands.delete(oldest);
|
|
282
|
+
}
|
|
283
|
+
try {
|
|
284
|
+
const response = await this.continuity.handleCommand(this.config.name, command);
|
|
285
|
+
if (response) {
|
|
286
|
+
// Queue response for injection
|
|
287
|
+
this.messageQueue.push({
|
|
288
|
+
from: 'system',
|
|
289
|
+
body: response,
|
|
290
|
+
messageId: `continuity-${Date.now()}`,
|
|
291
|
+
thread: 'continuity-response',
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
catch (err) {
|
|
296
|
+
console.error(`[${this.config.name}] Continuity command error: ${err.message}`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Save a parsed summary to the continuity ledger
|
|
301
|
+
*/
|
|
302
|
+
async saveSummaryToLedger(summary) {
|
|
303
|
+
if (!this.continuity)
|
|
304
|
+
return;
|
|
305
|
+
const updates = {};
|
|
306
|
+
if (summary.currentTask) {
|
|
307
|
+
updates.currentTask = summary.currentTask;
|
|
308
|
+
}
|
|
309
|
+
if (summary.completedTasks && summary.completedTasks.length > 0) {
|
|
310
|
+
updates.completed = summary.completedTasks;
|
|
311
|
+
}
|
|
312
|
+
if (summary.context) {
|
|
313
|
+
updates.inProgress = [summary.context];
|
|
314
|
+
}
|
|
315
|
+
if (summary.files && summary.files.length > 0) {
|
|
316
|
+
updates.fileContext = summary.files.map((f) => ({ path: f }));
|
|
317
|
+
}
|
|
318
|
+
if (Object.keys(updates).length > 0) {
|
|
319
|
+
await this.continuity.saveLedger(this.config.name, updates);
|
|
320
|
+
console.log(`[${this.config.name}] Saved summary to continuity ledger`);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Reset session-specific state for wrapper reuse
|
|
325
|
+
*/
|
|
326
|
+
resetSessionState() {
|
|
327
|
+
this.sessionEndProcessed = false;
|
|
328
|
+
this.lastSummaryRawContent = '';
|
|
329
|
+
this.sessionEndData = undefined;
|
|
330
|
+
}
|
|
331
|
+
// =========================================================================
|
|
332
|
+
// Utility methods
|
|
333
|
+
// =========================================================================
|
|
334
|
+
/**
|
|
335
|
+
* Join continuation lines for multi-line relay/continuity commands.
|
|
336
|
+
* TUIs like Claude Code insert real newlines in output, causing
|
|
337
|
+
* messages to span multiple lines. This joins indented
|
|
338
|
+
* continuation lines back to the command line.
|
|
339
|
+
*/
|
|
340
|
+
joinContinuationLines(content) {
|
|
341
|
+
const lines = content.split('\n');
|
|
342
|
+
const result = [];
|
|
343
|
+
// Pattern to detect relay OR continuity command line (with optional bullet prefix)
|
|
344
|
+
const escapedPrefix = this.relayPrefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
345
|
+
const commandPattern = new RegExp(`^(?:\\s*(?:[>$%#→➜›»●•◦‣⁃\\-*⏺◆◇○□■]\\s*)*)?(?:${escapedPrefix}|->continuity:)`);
|
|
346
|
+
// Pattern to detect a continuation line (starts with spaces, no bullet/command)
|
|
347
|
+
const continuationPattern = /^[ \t]+[^>$%#→➜›»●•◦‣⁃\-*⏺◆◇○□■\s]/;
|
|
348
|
+
// Pattern to detect a new block/bullet (stops continuation)
|
|
349
|
+
const newBlockPattern = /^(?:\s*)?[>$%#→➜›»●•◦‣⁃\-*⏺◆◇○□■]/;
|
|
350
|
+
let i = 0;
|
|
351
|
+
while (i < lines.length) {
|
|
352
|
+
const line = lines[i];
|
|
353
|
+
// Check if this is a command line
|
|
354
|
+
if (commandPattern.test(line)) {
|
|
355
|
+
let joined = line;
|
|
356
|
+
let j = i + 1;
|
|
357
|
+
// Look ahead for continuation lines
|
|
358
|
+
while (j < lines.length) {
|
|
359
|
+
const nextLine = lines[j];
|
|
360
|
+
// Empty line stops continuation
|
|
361
|
+
if (nextLine.trim() === '')
|
|
362
|
+
break;
|
|
363
|
+
// New bullet/block stops continuation
|
|
364
|
+
if (newBlockPattern.test(nextLine))
|
|
365
|
+
break;
|
|
366
|
+
// Check if it looks like a continuation (indented text)
|
|
367
|
+
if (continuationPattern.test(nextLine)) {
|
|
368
|
+
// Join with newline to preserve multi-line message content
|
|
369
|
+
joined += '\n' + nextLine.trim();
|
|
370
|
+
j++;
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
break;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
result.push(joined);
|
|
377
|
+
i = j; // Skip the lines we joined
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
result.push(line);
|
|
381
|
+
i++;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return result.join('\n');
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Clean up resources
|
|
388
|
+
*/
|
|
389
|
+
destroyClient() {
|
|
390
|
+
this.client.destroy();
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
//# sourceMappingURL=base-wrapper.js.map
|
package/dist/wrapper/client.d.ts
CHANGED
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
* Relay Client
|
|
3
3
|
* Connects to the daemon and handles message sending/receiving.
|
|
4
4
|
*/
|
|
5
|
-
import { type SendPayload, type SendMeta, type PayloadKind, type SpeakOnTrigger } from '../protocol/types.js';
|
|
5
|
+
import { type SendPayload, type SendMeta, type PayloadKind, type SpeakOnTrigger, type EntityType } from '../protocol/types.js';
|
|
6
6
|
export type ClientState = 'DISCONNECTED' | 'CONNECTING' | 'HANDSHAKING' | 'READY' | 'BACKOFF';
|
|
7
7
|
export interface ClientConfig {
|
|
8
8
|
socketPath: string;
|
|
9
9
|
agentName: string;
|
|
10
|
+
/** Entity type: 'agent' (default) or 'user' for human users */
|
|
11
|
+
entityType?: EntityType;
|
|
10
12
|
/** Optional CLI identifier to surface to the dashboard */
|
|
11
13
|
cli?: string;
|
|
12
14
|
/** Optional program identifier (e.g., 'claude', 'gpt-4o') */
|
|
@@ -17,6 +19,10 @@ export interface ClientConfig {
|
|
|
17
19
|
task?: string;
|
|
18
20
|
/** Optional working directory to surface in registry/dashboard */
|
|
19
21
|
workingDirectory?: string;
|
|
22
|
+
/** Display name for human users */
|
|
23
|
+
displayName?: string;
|
|
24
|
+
/** Avatar URL for human users */
|
|
25
|
+
avatarUrl?: string;
|
|
20
26
|
/** Suppress client-side console logging */
|
|
21
27
|
quiet?: boolean;
|
|
22
28
|
reconnect: boolean;
|
package/dist/wrapper/client.js
CHANGED
|
@@ -280,11 +280,14 @@ export class RelayClient {
|
|
|
280
280
|
ts: Date.now(),
|
|
281
281
|
payload: {
|
|
282
282
|
agent: this.config.agentName,
|
|
283
|
+
entityType: this.config.entityType,
|
|
283
284
|
cli: this.config.cli,
|
|
284
285
|
program: this.config.program,
|
|
285
286
|
model: this.config.model,
|
|
286
287
|
task: this.config.task,
|
|
287
288
|
workingDirectory: this.config.workingDirectory,
|
|
289
|
+
displayName: this.config.displayName,
|
|
290
|
+
avatarUrl: this.config.avatarUrl,
|
|
288
291
|
capabilities: {
|
|
289
292
|
ack: true,
|
|
290
293
|
resume: true,
|
package/dist/wrapper/index.d.ts
CHANGED
package/dist/wrapper/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from './client.js';
|
|
2
2
|
export * from './parser.js';
|
|
3
|
-
|
|
4
|
-
//
|
|
5
|
-
//
|
|
3
|
+
export * from './base-wrapper.js';
|
|
4
|
+
// Note: tmux-wrapper.ts and pty-wrapper.ts are intentionally not exported here.
|
|
5
|
+
// They're dynamically imported in CLI only, as they have different
|
|
6
|
+
// runtime requirements (tmux/pty must be available).
|
|
6
7
|
//# sourceMappingURL=index.js.map
|