agent-relay 1.3.0 → 1.3.2
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/active/traj_3yx9dy148mge.json +42 -0
- package/.trajectories/completed/2026-01/traj_1g7yx6qtg4ai.json +49 -0
- package/.trajectories/completed/2026-01/traj_1g7yx6qtg4ai.md +31 -0
- package/.trajectories/completed/2026-01/traj_4qwd4zmhfwp4.json +49 -0
- package/.trajectories/completed/2026-01/traj_4qwd4zmhfwp4.md +31 -0
- package/.trajectories/completed/2026-01/traj_6unwwmgyj5sq.json +109 -0
- package/.trajectories/completed/2026-01/traj_a0tqx8biw9c4.json +49 -0
- package/.trajectories/completed/2026-01/traj_a0tqx8biw9c4.md +31 -0
- package/.trajectories/completed/2026-01/traj_ax8uungxz2qh.json +66 -0
- package/.trajectories/completed/2026-01/traj_ax8uungxz2qh.md +36 -0
- package/.trajectories/completed/2026-01/traj_c9izbh2snpzf.json +49 -0
- package/.trajectories/completed/2026-01/traj_c9izbh2snpzf.md +31 -0
- package/.trajectories/completed/2026-01/traj_cpn70dw066nt.json +65 -0
- package/.trajectories/completed/2026-01/traj_cpn70dw066nt.md +37 -0
- package/.trajectories/completed/2026-01/traj_erglv2f8t9eh.json +36 -0
- package/.trajectories/completed/2026-01/traj_erglv2f8t9eh.md +21 -0
- package/.trajectories/completed/2026-01/traj_he75f24d1xfm.json +101 -0
- package/.trajectories/completed/2026-01/traj_he75f24d1xfm.md +52 -0
- package/.trajectories/completed/2026-01/traj_lgtodco7dp1n.json +61 -0
- package/.trajectories/completed/2026-01/traj_lgtodco7dp1n.md +36 -0
- package/.trajectories/completed/2026-01/traj_oszg9flv74pk.json +73 -0
- package/.trajectories/completed/2026-01/traj_oszg9flv74pk.md +41 -0
- package/.trajectories/completed/2026-01/traj_pulomd3y8cvj.json +77 -0
- package/.trajectories/completed/2026-01/traj_pulomd3y8cvj.md +42 -0
- package/.trajectories/completed/2026-01/traj_rsavt0jipi3c.json +109 -0
- package/.trajectories/completed/2026-01/traj_rsavt0jipi3c.md +56 -0
- package/.trajectories/completed/2026-01/traj_x721m1j9rzup.json +113 -0
- package/.trajectories/completed/2026-01/traj_x721m1j9rzup.md +57 -0
- package/.trajectories/completed/2026-01/traj_xjqvmep5ed3h.json +61 -0
- package/.trajectories/completed/2026-01/traj_xjqvmep5ed3h.md +36 -0
- package/.trajectories/completed/2026-01/traj_y7n6hfbf7dmg.json +49 -0
- package/.trajectories/completed/2026-01/traj_y7n6hfbf7dmg.md +31 -0
- package/.trajectories/completed/2026-01/traj_yvfkwnkdiso2.json +49 -0
- package/.trajectories/completed/2026-01/traj_yvfkwnkdiso2.md +31 -0
- package/.trajectories/index.json +140 -1
- package/TRAIL_GIT_AUTH_FIX.md +113 -0
- package/deploy/workspace/codex.config.toml +1 -1
- package/deploy/workspace/entrypoint.sh +20 -79
- package/deploy/workspace/gh-relay +156 -0
- package/deploy/workspace/git-credential-relay +5 -1
- package/dist/bridge/multi-project-client.js +13 -10
- package/dist/bridge/spawner.d.ts +2 -0
- package/dist/bridge/spawner.js +19 -1
- package/dist/bridge/types.d.ts +2 -0
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +115 -69
- package/dist/cloud/api/admin.js +16 -3
- package/dist/cloud/api/codex-auth-helper.js +28 -8
- package/dist/cloud/api/consensus.d.ts +13 -0
- package/dist/cloud/api/consensus.js +259 -0
- package/dist/cloud/api/daemons.js +205 -1
- package/dist/cloud/api/git.js +37 -7
- package/dist/cloud/api/onboarding.js +4 -1
- package/dist/cloud/api/provider-env.d.ts +5 -0
- package/dist/cloud/api/provider-env.js +27 -0
- package/dist/cloud/api/providers.js +2 -0
- package/dist/cloud/api/test-helpers.js +130 -0
- package/dist/cloud/api/workspaces.js +38 -3
- package/dist/cloud/db/bulk-ingest.d.ts +88 -0
- package/dist/cloud/db/bulk-ingest.js +268 -0
- package/dist/cloud/db/drizzle.d.ts +33 -0
- package/dist/cloud/db/drizzle.js +174 -2
- package/dist/cloud/db/index.d.ts +24 -5
- package/dist/cloud/db/index.js +19 -4
- package/dist/cloud/db/schema.d.ts +397 -3
- package/dist/cloud/db/schema.js +75 -1
- package/dist/cloud/provisioner/index.d.ts +8 -0
- package/dist/cloud/provisioner/index.js +256 -50
- package/dist/cloud/server.js +47 -3
- package/dist/cloud/services/index.d.ts +1 -0
- package/dist/cloud/services/index.js +2 -0
- package/dist/cloud/services/nango.d.ts +3 -4
- package/dist/cloud/services/nango.js +11 -33
- package/dist/cloud/services/workspace-keepalive.d.ts +76 -0
- package/dist/cloud/services/workspace-keepalive.js +234 -0
- package/dist/config/relay-config.d.ts +23 -0
- package/dist/config/relay-config.js +23 -0
- package/dist/daemon/agent-manager.d.ts +20 -1
- package/dist/daemon/agent-manager.js +47 -0
- package/dist/daemon/agent-registry.js +4 -4
- package/dist/daemon/agent-signing.d.ts +158 -0
- package/dist/daemon/agent-signing.js +523 -0
- package/dist/daemon/api.js +18 -1
- package/dist/daemon/cli-auth.d.ts +4 -1
- package/dist/daemon/cli-auth.js +55 -11
- package/dist/daemon/cloud-sync.d.ts +47 -1
- package/dist/daemon/cloud-sync.js +152 -3
- package/dist/daemon/connection.d.ts +28 -0
- package/dist/daemon/connection.js +98 -15
- package/dist/daemon/consensus-integration.d.ts +167 -0
- package/dist/daemon/consensus-integration.js +371 -0
- package/dist/daemon/consensus.d.ts +271 -0
- package/dist/daemon/consensus.js +632 -0
- package/dist/daemon/delivery-tracker.d.ts +34 -0
- package/dist/daemon/delivery-tracker.js +104 -0
- package/dist/daemon/enhanced-features.d.ts +118 -0
- package/dist/daemon/enhanced-features.js +178 -0
- package/dist/daemon/index.d.ts +4 -0
- package/dist/daemon/index.js +5 -0
- package/dist/daemon/rate-limiter.d.ts +68 -0
- package/dist/daemon/rate-limiter.js +130 -0
- package/dist/daemon/router.d.ts +18 -11
- package/dist/daemon/router.js +55 -111
- package/dist/daemon/server.d.ts +13 -1
- package/dist/daemon/server.js +71 -9
- package/dist/daemon/sync-queue.d.ts +116 -0
- package/dist/daemon/sync-queue.js +361 -0
- package/dist/health-worker-manager.d.ts +62 -0
- package/dist/health-worker-manager.js +144 -0
- package/dist/health-worker.d.ts +9 -0
- package/dist/health-worker.js +79 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +5 -1
- package/dist/memory/context-compaction.d.ts +156 -0
- package/dist/memory/context-compaction.js +453 -0
- package/dist/memory/index.d.ts +1 -0
- package/dist/memory/index.js +1 -0
- package/dist/protocol/channels.js +4 -4
- package/dist/protocol/framing.d.ts +72 -10
- package/dist/protocol/framing.js +194 -25
- package/dist/storage/adapter.d.ts +8 -1
- package/dist/storage/adapter.js +11 -0
- package/dist/storage/batched-sqlite-adapter.d.ts +71 -0
- package/dist/storage/batched-sqlite-adapter.js +183 -0
- package/dist/storage/dead-letter-queue.d.ts +196 -0
- package/dist/storage/dead-letter-queue.js +427 -0
- package/dist/storage/dlq-adapter.d.ts +195 -0
- package/dist/storage/dlq-adapter.js +664 -0
- package/dist/trajectory/config.d.ts +32 -14
- package/dist/trajectory/config.js +38 -16
- package/dist/trajectory/integration.js +217 -64
- package/dist/utils/git-remote.d.ts +47 -0
- package/dist/utils/git-remote.js +125 -0
- package/dist/utils/id-generator.d.ts +35 -0
- package/dist/utils/id-generator.js +60 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/precompiled-patterns.d.ts +110 -0
- package/dist/utils/precompiled-patterns.js +322 -0
- package/dist/wrapper/auth-detection.js +1 -1
- package/dist/wrapper/base-wrapper.d.ts +36 -0
- package/dist/wrapper/base-wrapper.js +48 -2
- package/dist/wrapper/client.d.ts +14 -4
- package/dist/wrapper/client.js +84 -31
- package/dist/wrapper/idle-detector.d.ts +102 -0
- package/dist/wrapper/idle-detector.js +279 -0
- package/dist/wrapper/parser.d.ts +4 -0
- package/dist/wrapper/parser.js +19 -1
- package/dist/wrapper/pty-wrapper.d.ts +7 -1
- package/dist/wrapper/pty-wrapper.js +51 -27
- package/dist/wrapper/tmux-wrapper.d.ts +12 -1
- package/dist/wrapper/tmux-wrapper.js +65 -17
- package/package.json +5 -5
- package/scripts/run-migrations.js +43 -0
- package/scripts/verify-schema.js +134 -0
- package/tests/benchmarks/protocol.bench.ts +310 -0
- package/dist/dashboard/out/404.html +0 -1
- package/dist/dashboard/out/_next/static/T1tgCqVWHFIkV7ClEtzD7/_buildManifest.js +0 -1
- package/dist/dashboard/out/_next/static/T1tgCqVWHFIkV7ClEtzD7/_ssgManifest.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/116-2502180def231162.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/117-f7b8ab0809342e77.js +0 -2
- package/dist/dashboard/out/_next/static/chunks/282-980c2eb8fff20123.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/532-bace199897eeab37.js +0 -9
- package/dist/dashboard/out/_next/static/chunks/648-5cc6e1921389a58a.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/766-b54f0853794b78c3.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/83-b51836037078006c.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/891-6cd50de1224f70bb.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/899-bb19a9b3d9b39ea6.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/_not-found/page-53b8a69f76db17d0.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/app/onboarding/page-8939b0fc700f7eca.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/app/page-5af1b6b439858aa6.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/connect-repos/page-f45ecbc3e06134fc.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/history/page-8c8bed33beb2bf1c.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/layout-2433bb48965f4333.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/login/page-16f3b49e55b1e0ed.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/metrics/page-ac39dc0cc3c26fa7.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/page-4a5938c18a11a654.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/pricing/page-982a7000fee44014.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/providers/page-ac3a6ac433fd6001.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/providers/setup/[provider]/page-09f9caae98a18c09.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/signup/page-547dd0ca55ecd0ba.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/e868780c-48e5f147c90a3a41.js +0 -18
- package/dist/dashboard/out/_next/static/chunks/fd9d1056-609918ca7b6280bb.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/framework-f66176bb897dc684.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/main-2ee6beb2ae96d210.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/main-app-5d692157a8eb1fd9.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/pages/_app-72b849fbd24ac258.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/pages/_error-7ba65e1336b92748.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/polyfills-42372ed130431b0a.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/webpack-1cdd8ed57114d5e1.js +0 -1
- package/dist/dashboard/out/_next/static/css/85d2af9c7ac74d62.css +0 -1
- package/dist/dashboard/out/_next/static/css/fe4b28883eeff359.css +0 -1
- package/dist/dashboard/out/alt-logos/agent-relay-logo-128.png +0 -0
- package/dist/dashboard/out/alt-logos/agent-relay-logo-256.png +0 -0
- package/dist/dashboard/out/alt-logos/agent-relay-logo-32.png +0 -0
- package/dist/dashboard/out/alt-logos/agent-relay-logo-512.png +0 -0
- package/dist/dashboard/out/alt-logos/agent-relay-logo-64.png +0 -0
- package/dist/dashboard/out/alt-logos/agent-relay-logo.svg +0 -45
- package/dist/dashboard/out/alt-logos/logo.svg +0 -38
- package/dist/dashboard/out/alt-logos/monogram-logo-128.png +0 -0
- package/dist/dashboard/out/alt-logos/monogram-logo-256.png +0 -0
- package/dist/dashboard/out/alt-logos/monogram-logo-32.png +0 -0
- package/dist/dashboard/out/alt-logos/monogram-logo-512.png +0 -0
- package/dist/dashboard/out/alt-logos/monogram-logo-64.png +0 -0
- package/dist/dashboard/out/alt-logos/monogram-logo.svg +0 -38
- package/dist/dashboard/out/app/onboarding.html +0 -1
- package/dist/dashboard/out/app/onboarding.txt +0 -7
- package/dist/dashboard/out/app.html +0 -1
- package/dist/dashboard/out/app.txt +0 -7
- package/dist/dashboard/out/apple-icon.png +0 -0
- package/dist/dashboard/out/connect-repos.html +0 -1
- package/dist/dashboard/out/connect-repos.txt +0 -7
- package/dist/dashboard/out/history.html +0 -1
- package/dist/dashboard/out/history.txt +0 -7
- package/dist/dashboard/out/index.html +0 -1
- package/dist/dashboard/out/index.txt +0 -7
- package/dist/dashboard/out/login.html +0 -6
- package/dist/dashboard/out/login.txt +0 -7
- package/dist/dashboard/out/metrics.html +0 -1
- package/dist/dashboard/out/metrics.txt +0 -7
- package/dist/dashboard/out/pricing.html +0 -13
- package/dist/dashboard/out/pricing.txt +0 -7
- package/dist/dashboard/out/providers/setup/claude.html +0 -1
- package/dist/dashboard/out/providers/setup/claude.txt +0 -8
- package/dist/dashboard/out/providers/setup/codex.html +0 -1
- package/dist/dashboard/out/providers/setup/codex.txt +0 -8
- package/dist/dashboard/out/providers.html +0 -1
- package/dist/dashboard/out/providers.txt +0 -7
- package/dist/dashboard/out/signup.html +0 -6
- package/dist/dashboard/out/signup.txt +0 -7
- package/dist/dashboard-server/metrics.d.ts +0 -105
- package/dist/dashboard-server/metrics.js +0 -193
- package/dist/dashboard-server/needs-attention.d.ts +0 -24
- package/dist/dashboard-server/needs-attention.js +0 -78
- package/dist/dashboard-server/server.d.ts +0 -15
- package/dist/dashboard-server/server.js +0 -3776
- package/dist/dashboard-server/start.d.ts +0 -6
- package/dist/dashboard-server/start.js +0 -13
- package/dist/dashboard-server/user-bridge.d.ts +0 -103
- package/dist/dashboard-server/user-bridge.js +0 -189
package/dist/bridge/spawner.d.ts
CHANGED
package/dist/bridge/spawner.js
CHANGED
|
@@ -12,6 +12,7 @@ import { PtyWrapper } from '../wrapper/pty-wrapper.js';
|
|
|
12
12
|
import { selectShadowCli } from './shadow-cli.js';
|
|
13
13
|
import { AgentPolicyService } from '../policy/agent-policy.js';
|
|
14
14
|
import { buildClaudeArgs } from '../utils/agent-config.js';
|
|
15
|
+
import { getUserDirectoryService } from '../daemon/user-directory.js';
|
|
15
16
|
/**
|
|
16
17
|
* Get a minimal relay reminder.
|
|
17
18
|
* Agents already have full relay docs via CLAUDE.md - this is just a brief reminder.
|
|
@@ -150,7 +151,7 @@ export class AgentSpawner {
|
|
|
150
151
|
* Spawn a new worker agent using node-pty
|
|
151
152
|
*/
|
|
152
153
|
async spawn(request) {
|
|
153
|
-
const { name, cli, task, team, spawnerName } = request;
|
|
154
|
+
const { name, cli, task, team, spawnerName, userId } = request;
|
|
154
155
|
const debug = process.env.DEBUG_SPAWN === '1';
|
|
155
156
|
// Check if worker already exists
|
|
156
157
|
if (this.activeWorkers.has(name)) {
|
|
@@ -219,6 +220,19 @@ export class AgentSpawner {
|
|
|
219
220
|
const agentCwd = request.cwd || this.projectRoot;
|
|
220
221
|
// Log whether nested spawning will be enabled for this agent
|
|
221
222
|
console.log(`[spawner] Spawning ${name}: dashboardPort=${this.dashboardPort || 'none'} (${this.dashboardPort ? 'nested spawns enabled' : 'nested spawns disabled'})`);
|
|
223
|
+
let userEnv;
|
|
224
|
+
if (userId) {
|
|
225
|
+
try {
|
|
226
|
+
const userDirService = getUserDirectoryService();
|
|
227
|
+
userEnv = userDirService.getUserEnvironment(userId);
|
|
228
|
+
}
|
|
229
|
+
catch (err) {
|
|
230
|
+
console.warn('[spawner] Failed to resolve user environment, using default', {
|
|
231
|
+
userId,
|
|
232
|
+
error: err instanceof Error ? err.message : String(err),
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
}
|
|
222
236
|
const ptyConfig = {
|
|
223
237
|
name,
|
|
224
238
|
command,
|
|
@@ -227,6 +241,7 @@ export class AgentSpawner {
|
|
|
227
241
|
cwd: agentCwd,
|
|
228
242
|
logsDir: this.logsDir,
|
|
229
243
|
dashboardPort: this.dashboardPort,
|
|
244
|
+
env: userEnv,
|
|
230
245
|
// Interactive mode - disables auto-accept for auth setup flows
|
|
231
246
|
interactive: request.interactive,
|
|
232
247
|
// Shadow agent configuration
|
|
@@ -242,6 +257,7 @@ export class AgentSpawner {
|
|
|
242
257
|
cli: workerCli,
|
|
243
258
|
task: workerTask,
|
|
244
259
|
// Nested spawns don't inherit team - they're flat by default
|
|
260
|
+
userId,
|
|
245
261
|
});
|
|
246
262
|
},
|
|
247
263
|
onRelease: this.dashboardPort ? undefined : async (workerName) => {
|
|
@@ -386,6 +402,7 @@ export class AgentSpawner {
|
|
|
386
402
|
cli,
|
|
387
403
|
task,
|
|
388
404
|
team,
|
|
405
|
+
userId,
|
|
389
406
|
spawnedAt: Date.now(),
|
|
390
407
|
pid: pty.pid,
|
|
391
408
|
pty,
|
|
@@ -674,6 +691,7 @@ export class AgentSpawner {
|
|
|
674
691
|
cli: w.cli,
|
|
675
692
|
task: w.task,
|
|
676
693
|
team: w.team,
|
|
694
|
+
userId: w.userId,
|
|
677
695
|
spawnedAt: w.spawnedAt,
|
|
678
696
|
pid: w.pid,
|
|
679
697
|
logFile: w.logFile,
|
package/dist/bridge/types.d.ts
CHANGED
|
@@ -53,6 +53,8 @@ export interface SpawnRequest {
|
|
|
53
53
|
shadowTriggers?: Array<'SESSION_END' | 'CODE_WRITTEN' | 'REVIEW_REQUEST' | 'EXPLICIT_ASK' | 'ALL_MESSAGES'>;
|
|
54
54
|
/** When the shadow should speak (default: ['EXPLICIT_ASK']) */
|
|
55
55
|
shadowSpeakOn?: Array<'SESSION_END' | 'CODE_WRITTEN' | 'REVIEW_REQUEST' | 'EXPLICIT_ASK' | 'ALL_MESSAGES'>;
|
|
56
|
+
/** User ID for per-user credential storage in shared workspaces */
|
|
57
|
+
userId?: string;
|
|
56
58
|
}
|
|
57
59
|
/** Policy decision details */
|
|
58
60
|
export interface PolicyDecision {
|
package/dist/cli/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Commands:
|
|
6
6
|
* relay <cmd> - Wrap agent with real-time messaging (default)
|
|
7
7
|
* relay -n Name cmd - Wrap with specific agent name
|
|
8
|
-
* relay up - Start daemon
|
|
8
|
+
* relay up - Start daemon
|
|
9
9
|
* relay read <id> - Read full message by ID
|
|
10
10
|
* relay agents - List connected agents
|
|
11
11
|
* relay who - Show currently active agents
|
package/dist/cli/index.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Commands:
|
|
6
6
|
* relay <cmd> - Wrap agent with real-time messaging (default)
|
|
7
7
|
* relay -n Name cmd - Wrap with specific agent name
|
|
8
|
-
* relay up - Start daemon
|
|
8
|
+
* relay up - Start daemon
|
|
9
9
|
* relay read <id> - Read full message by ID
|
|
10
10
|
* relay agents - List connected agents
|
|
11
11
|
* relay who - Show currently active agents
|
|
@@ -26,7 +26,6 @@ import { promisify } from 'node:util';
|
|
|
26
26
|
import { exec } from 'node:child_process';
|
|
27
27
|
import { fileURLToPath } from 'node:url';
|
|
28
28
|
dotenvConfig();
|
|
29
|
-
const DEFAULT_DASHBOARD_PORT = process.env.AGENT_RELAY_DASHBOARD_PORT || '3888';
|
|
30
29
|
// Read version from package.json
|
|
31
30
|
const __filename = fileURLToPath(import.meta.url);
|
|
32
31
|
const __dirname = path.dirname(__filename);
|
|
@@ -55,7 +54,6 @@ program
|
|
|
55
54
|
.option('-n, --name <name>', 'Agent name (auto-generated if not set)')
|
|
56
55
|
.option('-q, --quiet', 'Disable debug output', false)
|
|
57
56
|
.option('--prefix <pattern>', 'Relay prefix pattern (default: ->relay:)')
|
|
58
|
-
.option('--dashboard-port <port>', 'Dashboard port for spawn/release API (auto-detected if not set)')
|
|
59
57
|
.option('--shadow <name>', 'Spawn a shadow agent with this name that monitors the primary')
|
|
60
58
|
.option('--shadow-role <role>', 'Shadow role: reviewer, auditor, or triggers (comma-separated: SESSION_END,CODE_WRITTEN,REVIEW_REQUEST,EXPLICIT_ASK,ALL_MESSAGES)')
|
|
61
59
|
.argument('[command...]', 'Command to wrap (e.g., claude)')
|
|
@@ -86,31 +84,8 @@ program
|
|
|
86
84
|
}
|
|
87
85
|
const { TmuxWrapper } = await import('../wrapper/tmux-wrapper.js');
|
|
88
86
|
const { AgentSpawner } = await import('../bridge/spawner.js');
|
|
89
|
-
//
|
|
90
|
-
|
|
91
|
-
let dashboardPort;
|
|
92
|
-
if (options.dashboardPort) {
|
|
93
|
-
dashboardPort = parseInt(options.dashboardPort, 10);
|
|
94
|
-
}
|
|
95
|
-
else {
|
|
96
|
-
// Try to detect if dashboard is running at default port
|
|
97
|
-
const defaultPort = parseInt(DEFAULT_DASHBOARD_PORT, 10);
|
|
98
|
-
try {
|
|
99
|
-
const response = await fetch(`http://localhost:${defaultPort}/api/status`, {
|
|
100
|
-
method: 'GET',
|
|
101
|
-
signal: AbortSignal.timeout(500), // Quick timeout for detection
|
|
102
|
-
});
|
|
103
|
-
if (response.ok) {
|
|
104
|
-
dashboardPort = defaultPort;
|
|
105
|
-
console.error(`Dashboard detected: http://localhost:${dashboardPort}`);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
catch {
|
|
109
|
-
// Dashboard not running - spawn/release will use fallback callbacks
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
// Create spawner as fallback for direct spawn (if dashboard API not available)
|
|
113
|
-
const spawner = new AgentSpawner(paths.projectRoot, undefined, dashboardPort);
|
|
87
|
+
// Create spawner for spawn/release callbacks
|
|
88
|
+
const spawner = new AgentSpawner(paths.projectRoot);
|
|
114
89
|
const wrapper = new TmuxWrapper({
|
|
115
90
|
name: agentName,
|
|
116
91
|
command: mainCommand,
|
|
@@ -120,9 +95,7 @@ program
|
|
|
120
95
|
relayPrefix: options.prefix,
|
|
121
96
|
useInbox: true,
|
|
122
97
|
inboxDir: paths.dataDir, // Use the project-specific data directory for the inbox
|
|
123
|
-
//
|
|
124
|
-
dashboardPort,
|
|
125
|
-
// Wire up spawn/release callbacks as fallback (if no dashboardPort)
|
|
98
|
+
// Wire up spawn/release callbacks
|
|
126
99
|
onSpawn: async (workerName, workerCli, task) => {
|
|
127
100
|
console.error(`[${agentName}] Spawning ${workerName} (${workerCli})...`);
|
|
128
101
|
const result = await spawner.spawn({
|
|
@@ -226,12 +199,10 @@ program
|
|
|
226
199
|
}
|
|
227
200
|
}
|
|
228
201
|
});
|
|
229
|
-
// up - Start daemon
|
|
202
|
+
// up - Start daemon
|
|
230
203
|
program
|
|
231
204
|
.command('up')
|
|
232
|
-
.description('Start daemon
|
|
233
|
-
.option('--no-dashboard', 'Disable web dashboard')
|
|
234
|
-
.option('--port <port>', 'Dashboard port', DEFAULT_DASHBOARD_PORT)
|
|
205
|
+
.description('Start daemon')
|
|
235
206
|
.option('--spawn', 'Force spawn all agents from teams.json')
|
|
236
207
|
.option('--no-spawn', 'Do not auto-spawn agents (just start daemon)')
|
|
237
208
|
.option('--watch', 'Auto-restart daemon on crash (supervisor mode)')
|
|
@@ -248,10 +219,6 @@ program
|
|
|
248
219
|
const startDaemon = () => {
|
|
249
220
|
// Build args without --watch to prevent infinite recursion
|
|
250
221
|
const args = ['up'];
|
|
251
|
-
if (options.dashboard === false)
|
|
252
|
-
args.push('--no-dashboard');
|
|
253
|
-
if (options.port)
|
|
254
|
-
args.push('--port', options.port);
|
|
255
222
|
if (options.spawn === true)
|
|
256
223
|
args.push('--spawn');
|
|
257
224
|
if (options.spawn === false)
|
|
@@ -363,28 +330,6 @@ program
|
|
|
363
330
|
try {
|
|
364
331
|
await daemon.start();
|
|
365
332
|
console.log('Daemon started.');
|
|
366
|
-
let dashboardPort;
|
|
367
|
-
// Dashboard starts by default (use --no-dashboard to disable)
|
|
368
|
-
if (options.dashboard !== false) {
|
|
369
|
-
const port = parseInt(options.port, 10);
|
|
370
|
-
const { startDashboard } = await import('../dashboard-server/server.js');
|
|
371
|
-
dashboardPort = await startDashboard({
|
|
372
|
-
port,
|
|
373
|
-
dataDir: paths.dataDir,
|
|
374
|
-
teamDir: paths.teamDir,
|
|
375
|
-
dbPath,
|
|
376
|
-
enableSpawner: true,
|
|
377
|
-
projectRoot: paths.projectRoot,
|
|
378
|
-
});
|
|
379
|
-
console.log(`Dashboard: http://localhost:${dashboardPort}`);
|
|
380
|
-
// Hook daemon log output to dashboard WebSocket
|
|
381
|
-
daemon.onLogOutput = (agentName, data, _timestamp) => {
|
|
382
|
-
const broadcast = global.__broadcastLogOutput;
|
|
383
|
-
if (broadcast) {
|
|
384
|
-
broadcast(agentName, data);
|
|
385
|
-
}
|
|
386
|
-
};
|
|
387
|
-
}
|
|
388
333
|
// Determine if we should auto-spawn agents
|
|
389
334
|
// --spawn: force spawn
|
|
390
335
|
// --no-spawn: never spawn
|
|
@@ -397,7 +342,7 @@ program
|
|
|
397
342
|
if (shouldSpawn && teamsConfig && teamsConfig.agents.length > 0) {
|
|
398
343
|
console.log('');
|
|
399
344
|
console.log('Auto-spawning agents from teams.json...');
|
|
400
|
-
spawner = new AgentSpawner(paths.projectRoot
|
|
345
|
+
spawner = new AgentSpawner(paths.projectRoot);
|
|
401
346
|
for (const agent of teamsConfig.agents) {
|
|
402
347
|
console.log(` Spawning ${agent.name} (${agent.cli})...`);
|
|
403
348
|
const result = await spawner.spawn({
|
|
@@ -1341,14 +1286,113 @@ program
|
|
|
1341
1286
|
}
|
|
1342
1287
|
}
|
|
1343
1288
|
});
|
|
1289
|
+
// spawn - Spawn an agent via API (works from any context, no tmux required)
|
|
1290
|
+
program
|
|
1291
|
+
.command('spawn', { hidden: true })
|
|
1292
|
+
.description('Spawn an agent via dashboard API (no tmux required, works in containers)')
|
|
1293
|
+
.argument('<name>', 'Agent name')
|
|
1294
|
+
.argument('<cli>', 'CLI to use (claude, codex, gemini, etc.)')
|
|
1295
|
+
.argument('[task]', 'Task description (can also be piped via stdin)')
|
|
1296
|
+
.option('--port <port>', 'Dashboard port', '3888')
|
|
1297
|
+
.option('--team <team>', 'Team name for the agent')
|
|
1298
|
+
.option('--spawner <name>', 'Name of the agent requesting the spawn (for policy enforcement)')
|
|
1299
|
+
.option('--interactive', 'Disable auto-accept of permission prompts (for auth setup flows)')
|
|
1300
|
+
.option('--cwd <path>', 'Working directory for the agent')
|
|
1301
|
+
.option('--shadow-mode <mode>', 'Shadow execution mode: subagent or process')
|
|
1302
|
+
.option('--shadow-of <name>', 'Primary agent to shadow (if this agent is a shadow)')
|
|
1303
|
+
.option('--shadow-agent <profile>', 'Shadow agent profile to use')
|
|
1304
|
+
.option('--shadow-triggers <triggers>', 'When to trigger shadow (comma-separated: SESSION_END,CODE_WRITTEN,REVIEW_REQUEST,EXPLICIT_ASK,ALL_MESSAGES)')
|
|
1305
|
+
.option('--shadow-speak-on <triggers>', 'When shadow should speak (comma-separated, same values as --shadow-triggers)')
|
|
1306
|
+
.action(async (name, cli, task, options) => {
|
|
1307
|
+
const port = options.port || '3888';
|
|
1308
|
+
// Read task from stdin if not provided as argument
|
|
1309
|
+
let finalTask = task;
|
|
1310
|
+
if (!finalTask && !process.stdin.isTTY) {
|
|
1311
|
+
const chunks = [];
|
|
1312
|
+
for await (const chunk of process.stdin) {
|
|
1313
|
+
chunks.push(chunk);
|
|
1314
|
+
}
|
|
1315
|
+
finalTask = Buffer.concat(chunks).toString('utf-8').trim();
|
|
1316
|
+
}
|
|
1317
|
+
if (!finalTask) {
|
|
1318
|
+
console.error('Error: Task description required (as argument or via stdin)');
|
|
1319
|
+
process.exit(1);
|
|
1320
|
+
}
|
|
1321
|
+
// Validate shadow mode if provided
|
|
1322
|
+
if (options.shadowMode && !['subagent', 'process'].includes(options.shadowMode)) {
|
|
1323
|
+
console.error('Error: --shadow-mode must be "subagent" or "process"');
|
|
1324
|
+
process.exit(1);
|
|
1325
|
+
}
|
|
1326
|
+
// Parse comma-separated trigger lists
|
|
1327
|
+
const parseTriggers = (value) => {
|
|
1328
|
+
if (!value)
|
|
1329
|
+
return undefined;
|
|
1330
|
+
const validTriggers = ['SESSION_END', 'CODE_WRITTEN', 'REVIEW_REQUEST', 'EXPLICIT_ASK', 'ALL_MESSAGES'];
|
|
1331
|
+
const triggers = value.split(',').map(t => t.trim().toUpperCase());
|
|
1332
|
+
const invalid = triggers.filter(t => !validTriggers.includes(t));
|
|
1333
|
+
if (invalid.length > 0) {
|
|
1334
|
+
console.error(`Error: Invalid triggers: ${invalid.join(', ')}`);
|
|
1335
|
+
console.error(`Valid triggers: ${validTriggers.join(', ')}`);
|
|
1336
|
+
process.exit(1);
|
|
1337
|
+
}
|
|
1338
|
+
return triggers;
|
|
1339
|
+
};
|
|
1340
|
+
try {
|
|
1341
|
+
// Build spawn request using the SpawnRequest type for consistency
|
|
1342
|
+
const spawnRequest = {
|
|
1343
|
+
name,
|
|
1344
|
+
cli,
|
|
1345
|
+
task: finalTask,
|
|
1346
|
+
team: options.team,
|
|
1347
|
+
spawnerName: options.spawner,
|
|
1348
|
+
interactive: options.interactive,
|
|
1349
|
+
cwd: options.cwd,
|
|
1350
|
+
shadowMode: options.shadowMode,
|
|
1351
|
+
shadowOf: options.shadowOf,
|
|
1352
|
+
shadowAgent: options.shadowAgent,
|
|
1353
|
+
shadowTriggers: parseTriggers(options.shadowTriggers),
|
|
1354
|
+
shadowSpeakOn: parseTriggers(options.shadowSpeakOn),
|
|
1355
|
+
};
|
|
1356
|
+
const response = await fetch(`http://localhost:${port}/api/spawn`, {
|
|
1357
|
+
method: 'POST',
|
|
1358
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1359
|
+
body: JSON.stringify(spawnRequest),
|
|
1360
|
+
});
|
|
1361
|
+
const result = await response.json();
|
|
1362
|
+
if (result.success) {
|
|
1363
|
+
console.log(`Spawned agent: ${name} (pid: ${result.pid})`);
|
|
1364
|
+
process.exit(0);
|
|
1365
|
+
}
|
|
1366
|
+
else {
|
|
1367
|
+
if (result.policyDecision) {
|
|
1368
|
+
console.error(`Policy denied spawn: ${result.policyDecision.reason}`);
|
|
1369
|
+
console.error(`Policy source: ${result.policyDecision.policySource}`);
|
|
1370
|
+
}
|
|
1371
|
+
else {
|
|
1372
|
+
console.error(`Failed to spawn ${name}: ${result.error || 'Unknown error'}`);
|
|
1373
|
+
}
|
|
1374
|
+
process.exit(1);
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
catch (err) {
|
|
1378
|
+
if (err.code === 'ECONNREFUSED') {
|
|
1379
|
+
console.error(`Cannot connect to dashboard at port ${port}. Is the daemon running?`);
|
|
1380
|
+
console.log(`Run 'agent-relay up' to start the daemon.`);
|
|
1381
|
+
}
|
|
1382
|
+
else {
|
|
1383
|
+
console.error(`Failed to spawn ${name}: ${err.message}`);
|
|
1384
|
+
}
|
|
1385
|
+
process.exit(1);
|
|
1386
|
+
}
|
|
1387
|
+
});
|
|
1344
1388
|
// release - Release a spawned agent via API (works from any context, no terminal required)
|
|
1345
1389
|
program
|
|
1346
1390
|
.command('release')
|
|
1347
1391
|
.description('Release a spawned agent via API (no terminal required)')
|
|
1348
1392
|
.argument('<name>', 'Agent name to release')
|
|
1349
|
-
.option('--port <port>', 'Dashboard port',
|
|
1393
|
+
.option('--port <port>', 'Dashboard port', '3888')
|
|
1350
1394
|
.action(async (name, options) => {
|
|
1351
|
-
const port = options.port ||
|
|
1395
|
+
const port = options.port || '3888';
|
|
1352
1396
|
try {
|
|
1353
1397
|
const response = await fetch(`http://localhost:${port}/api/spawned/${encodeURIComponent(name)}`, {
|
|
1354
1398
|
method: 'DELETE',
|
|
@@ -1439,7 +1483,7 @@ cloudCommand
|
|
|
1439
1483
|
.command('link')
|
|
1440
1484
|
.description('Link this machine to your Agent Relay Cloud account')
|
|
1441
1485
|
.option('--name <name>', 'Name for this machine')
|
|
1442
|
-
.option('--cloud-url <url>', 'Cloud API URL', process.env.AGENT_RELAY_CLOUD_URL || 'https://
|
|
1486
|
+
.option('--cloud-url <url>', 'Cloud API URL', process.env.AGENT_RELAY_CLOUD_URL || 'https://agent-relay.com')
|
|
1443
1487
|
.action(async (options) => {
|
|
1444
1488
|
const os = await import('node:os');
|
|
1445
1489
|
const crypto = await import('node:crypto');
|
|
@@ -1720,6 +1764,8 @@ program
|
|
|
1720
1764
|
stdio: 'inherit',
|
|
1721
1765
|
env: {
|
|
1722
1766
|
...process.env,
|
|
1767
|
+
// Trajectory env vars override parent shell settings
|
|
1768
|
+
// This ensures config-based TRAJECTORIES_DATA_DIR takes precedence
|
|
1723
1769
|
TRAJECTORIES_PROJECT: paths.projectId,
|
|
1724
1770
|
TRAJECTORIES_DATA_DIR: trajectoriesDir,
|
|
1725
1771
|
},
|
|
@@ -1914,12 +1960,12 @@ program
|
|
|
1914
1960
|
.command('metrics')
|
|
1915
1961
|
.description('Show agent memory metrics and resource usage')
|
|
1916
1962
|
.option('--agent <name>', 'Show metrics for specific agent')
|
|
1917
|
-
.option('--port <port>', 'Dashboard port',
|
|
1963
|
+
.option('--port <port>', 'Dashboard port', '3888')
|
|
1918
1964
|
.option('--json', 'Output as JSON')
|
|
1919
1965
|
.option('--watch', 'Continuously update metrics')
|
|
1920
1966
|
.option('--interval <ms>', 'Update interval for watch mode', '5000')
|
|
1921
1967
|
.action(async (options) => {
|
|
1922
|
-
const port = options.port ||
|
|
1968
|
+
const port = options.port || '3888';
|
|
1923
1969
|
const fetchMetrics = async () => {
|
|
1924
1970
|
try {
|
|
1925
1971
|
const response = await fetch(`http://localhost:${port}/api/metrics/agents`);
|
|
@@ -2033,12 +2079,12 @@ program
|
|
|
2033
2079
|
program
|
|
2034
2080
|
.command('health')
|
|
2035
2081
|
.description('Show system health, crash insights, and recommendations')
|
|
2036
|
-
.option('--port <port>', 'Dashboard port',
|
|
2082
|
+
.option('--port <port>', 'Dashboard port', '3888')
|
|
2037
2083
|
.option('--json', 'Output as JSON')
|
|
2038
2084
|
.option('--crashes', 'Show recent crash history')
|
|
2039
2085
|
.option('--alerts', 'Show unacknowledged alerts')
|
|
2040
2086
|
.action(async (options) => {
|
|
2041
|
-
const port = options.port ||
|
|
2087
|
+
const port = options.port || '3888';
|
|
2042
2088
|
try {
|
|
2043
2089
|
const response = await fetch(`http://localhost:${port}/api/metrics/health`);
|
|
2044
2090
|
if (!response.ok) {
|
package/dist/cloud/api/admin.js
CHANGED
|
@@ -43,7 +43,7 @@ adminRouter.use(requireAdminAuth);
|
|
|
43
43
|
* - batchSize?: Number of concurrent updates (default: 5)
|
|
44
44
|
*
|
|
45
45
|
* Response:
|
|
46
|
-
* - summary: { total, updated, pendingRestart, skippedActiveAgents, skippedNotRunning, errors }
|
|
46
|
+
* - summary: { total, updated, pendingRestart, skippedActiveAgents, skippedVerificationFailed, skippedNotRunning, errors }
|
|
47
47
|
* - results: Array of per-workspace results
|
|
48
48
|
*/
|
|
49
49
|
adminRouter.post('/workspaces/update-image', async (req, res) => {
|
|
@@ -159,7 +159,9 @@ adminRouter.get('/workspaces/:id/agents', async (req, res) => {
|
|
|
159
159
|
return;
|
|
160
160
|
}
|
|
161
161
|
try {
|
|
162
|
-
|
|
162
|
+
// Use /api/data endpoint which returns { agents: [...], ... }
|
|
163
|
+
// Note: /api/agents doesn't exist on the workspace dashboard-server
|
|
164
|
+
const response = await fetch(`${baseUrl}/api/data`, {
|
|
163
165
|
method: 'GET',
|
|
164
166
|
headers: { 'Accept': 'application/json' },
|
|
165
167
|
signal: AbortSignal.timeout(10_000),
|
|
@@ -170,7 +172,18 @@ adminRouter.get('/workspaces/:id/agents', async (req, res) => {
|
|
|
170
172
|
}
|
|
171
173
|
const data = await response.json();
|
|
172
174
|
const agents = data.agents || [];
|
|
173
|
-
const activeAgents = agents.filter(a =>
|
|
175
|
+
const activeAgents = agents.filter(a => {
|
|
176
|
+
const status = (a.status ?? '').toLowerCase();
|
|
177
|
+
const activityState = (a.activityState ?? '').toLowerCase();
|
|
178
|
+
const isProcessing = a.isProcessing === true;
|
|
179
|
+
if (activityState === 'active' || activityState === 'idle')
|
|
180
|
+
return true;
|
|
181
|
+
if (status && status !== 'disconnected' && status !== 'offline')
|
|
182
|
+
return true;
|
|
183
|
+
if (isProcessing)
|
|
184
|
+
return true;
|
|
185
|
+
return false;
|
|
186
|
+
});
|
|
174
187
|
res.json({
|
|
175
188
|
hasActiveAgents: activeAgents.length > 0,
|
|
176
189
|
agentCount: activeAgents.length,
|
|
@@ -19,6 +19,7 @@ import { requireAuth } from './auth.js';
|
|
|
19
19
|
import { db } from '../db/index.js';
|
|
20
20
|
import { deriveSshPassword } from '../services/ssh-security.js';
|
|
21
21
|
export const codexAuthHelperRouter = Router();
|
|
22
|
+
const WORKSPACE_SSH_PORT = 3022;
|
|
22
23
|
const pendingAuthSessions = new Map();
|
|
23
24
|
const pendingCliTokens = new Map();
|
|
24
25
|
// Clean up old sessions every minute
|
|
@@ -201,18 +202,18 @@ codexAuthHelperRouter.get('/tunnel-info/:workspaceId', async (req, res) => {
|
|
|
201
202
|
const host = url.hostname;
|
|
202
203
|
const apiPort = parseInt(url.port, 10) || 80;
|
|
203
204
|
// SSH connection info varies by environment:
|
|
204
|
-
// - Fly.io: Use public fly.dev hostname with port
|
|
205
|
+
// - Fly.io: Use public fly.dev hostname with port 3022 (exposed via TCP service)
|
|
205
206
|
// - Local Docker: Use localhost with derived SSH port (22000 + apiPort - 3000)
|
|
206
207
|
const isOnFly = !!process.env.FLY_APP_NAME;
|
|
207
208
|
const isLocalDocker = (host === 'localhost' || host === '127.0.0.1') && apiPort >= 3000;
|
|
208
209
|
let sshHost;
|
|
209
210
|
let sshPort;
|
|
210
211
|
if (isOnFly) {
|
|
211
|
-
// Fly.io public hostname - SSH is exposed as a public TCP service on port
|
|
212
|
-
// Users can SSH directly from their machine to {app}.fly.dev:
|
|
212
|
+
// Fly.io public hostname - SSH is exposed as a public TCP service on port 3022
|
|
213
|
+
// Users can SSH directly from their machine to {app}.fly.dev:3022
|
|
213
214
|
const appName = `ar-${workspace.id.substring(0, 8)}`;
|
|
214
215
|
sshHost = `${appName}.fly.dev`;
|
|
215
|
-
sshPort =
|
|
216
|
+
sshPort = WORKSPACE_SSH_PORT;
|
|
216
217
|
}
|
|
217
218
|
else if (isLocalDocker) {
|
|
218
219
|
// Local Docker: SSH port is derived from API port
|
|
@@ -223,7 +224,7 @@ codexAuthHelperRouter.get('/tunnel-info/:workspaceId', async (req, res) => {
|
|
|
223
224
|
else {
|
|
224
225
|
// Default fallback
|
|
225
226
|
sshHost = host;
|
|
226
|
-
sshPort =
|
|
227
|
+
sshPort = WORKSPACE_SSH_PORT;
|
|
227
228
|
}
|
|
228
229
|
// SSH password is derived per-workspace for security
|
|
229
230
|
// Each workspace gets a unique password based on its ID + secret salt
|
|
@@ -288,18 +289,37 @@ codexAuthHelperRouter.get('/auth-status/:workspaceId', async (req, res) => {
|
|
|
288
289
|
if (!workspace.publicUrl) {
|
|
289
290
|
return res.status(400).json({ error: 'Workspace URL not available' });
|
|
290
291
|
}
|
|
291
|
-
// Check with workspace daemon if Codex is authenticated
|
|
292
|
-
|
|
292
|
+
// Check with workspace daemon if Codex is authenticated for this specific user
|
|
293
|
+
// Pass userId to enable per-user credential checking (multiple users can share a workspace)
|
|
294
|
+
const checkUrl = new URL(`${workspace.publicUrl}/auth/cli/openai/check`);
|
|
295
|
+
checkUrl.searchParams.set('userId', userId);
|
|
296
|
+
const response = await fetch(checkUrl.toString(), {
|
|
293
297
|
method: 'GET',
|
|
294
298
|
signal: AbortSignal.timeout(5000),
|
|
295
299
|
});
|
|
296
300
|
if (response.ok) {
|
|
297
301
|
const data = await response.json();
|
|
302
|
+
// When authentication is detected, mark the provider as connected in the database
|
|
303
|
+
// This ensures the dashboard shows correct per-user connection status
|
|
304
|
+
if (data.authenticated && userId) {
|
|
305
|
+
try {
|
|
306
|
+
await db.credentials.upsert({
|
|
307
|
+
userId,
|
|
308
|
+
provider: 'codex', // Codex provider for OpenAI
|
|
309
|
+
scopes: [],
|
|
310
|
+
});
|
|
311
|
+
console.log(`[codex-helper] Marked codex as connected for user ${userId}`);
|
|
312
|
+
}
|
|
313
|
+
catch (dbError) {
|
|
314
|
+
console.error('[codex-helper] Failed to mark provider as connected:', dbError);
|
|
315
|
+
// Don't fail the request if DB update fails
|
|
316
|
+
}
|
|
317
|
+
}
|
|
298
318
|
return res.json({ authenticated: data.authenticated });
|
|
299
319
|
}
|
|
300
320
|
res.json({ authenticated: false });
|
|
301
321
|
}
|
|
302
|
-
catch (
|
|
322
|
+
catch (_error) {
|
|
303
323
|
// Workspace might not be reachable, return false
|
|
304
324
|
res.json({ authenticated: false });
|
|
305
325
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consensus API Routes (Read-Only)
|
|
3
|
+
*
|
|
4
|
+
* Provides API endpoints for observing multi-agent consensus decisions.
|
|
5
|
+
* The dashboard is read-only - agents handle all consensus activity via relay messages.
|
|
6
|
+
*
|
|
7
|
+
* Architecture:
|
|
8
|
+
* - Agents create proposals and vote via ->relay:_consensus messages
|
|
9
|
+
* - The daemon processes these and syncs state to cloud via /sync endpoint
|
|
10
|
+
* - Dashboard reads consensus state for display only
|
|
11
|
+
*/
|
|
12
|
+
export declare const consensusRouter: import("express-serve-static-core").Router;
|
|
13
|
+
//# sourceMappingURL=consensus.d.ts.map
|