@pixelbyte-software/pixcode 1.34.0 → 1.35.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/LICENSE +718 -718
- package/README.de.md +248 -248
- package/README.ja.md +240 -240
- package/README.ko.md +240 -240
- package/README.md +303 -303
- package/README.ru.md +248 -248
- package/README.tr.md +250 -250
- package/README.zh-CN.md +240 -240
- package/dist/api-docs.html +548 -395
- package/dist/assets/index-B8w57E1r.css +32 -0
- package/dist/assets/index-CBdsvGSR.js +854 -0
- package/dist/clear-cache.html +85 -85
- package/dist/convert-icons.md +52 -52
- package/dist/favicon.svg +8 -8
- package/dist/generate-icons.js +48 -48
- package/dist/icons/codex-white.svg +3 -3
- package/dist/icons/codex.svg +3 -3
- package/dist/icons/cursor-white.svg +11 -11
- package/dist/icons/icon-128x128.svg +9 -9
- package/dist/icons/icon-144x144.svg +9 -9
- package/dist/icons/icon-152x152.svg +9 -9
- package/dist/icons/icon-192x192.svg +9 -9
- package/dist/icons/icon-384x384.svg +9 -9
- package/dist/icons/icon-512x512.svg +9 -9
- package/dist/icons/icon-72x72.svg +9 -9
- package/dist/icons/icon-96x96.svg +9 -9
- package/dist/icons/icon-template.svg +9 -9
- package/dist/icons/qwen-logo.svg +14 -14
- package/dist/index.html +59 -59
- package/dist/logo.svg +12 -12
- package/dist/manifest.json +60 -60
- package/dist/openapi.yaml +1693 -1311
- package/dist/sw.js +124 -124
- package/dist-server/server/claude-sdk.js +38 -7
- package/dist-server/server/claude-sdk.js.map +1 -1
- package/dist-server/server/cli.js +107 -112
- package/dist-server/server/cli.js.map +1 -1
- package/dist-server/server/daemon/manager.js +33 -33
- package/dist-server/server/daemon-manager.js +159 -112
- package/dist-server/server/daemon-manager.js.map +1 -1
- package/dist-server/server/database/json-store.js +8 -5
- package/dist-server/server/database/json-store.js.map +1 -1
- package/dist-server/server/index.js +31 -10
- package/dist-server/server/index.js.map +1 -1
- package/dist-server/server/modules/orchestration/a2a/adapter-registry.js +45 -19
- package/dist-server/server/modules/orchestration/a2a/adapter-registry.js.map +1 -1
- package/dist-server/server/modules/orchestration/a2a/adapters/abstract-a2a.adapter.js.map +1 -1
- package/dist-server/server/modules/orchestration/a2a/adapters/claude-code.adapter.js +1 -0
- package/dist-server/server/modules/orchestration/a2a/adapters/claude-code.adapter.js.map +1 -1
- package/dist-server/server/modules/orchestration/a2a/adapters/codex.adapter.js +202 -0
- package/dist-server/server/modules/orchestration/a2a/adapters/codex.adapter.js.map +1 -0
- package/dist-server/server/modules/orchestration/a2a/adapters/cursor.adapter.js +205 -0
- package/dist-server/server/modules/orchestration/a2a/adapters/cursor.adapter.js.map +1 -0
- package/dist-server/server/modules/orchestration/a2a/adapters/gemini.adapter.js +205 -0
- package/dist-server/server/modules/orchestration/a2a/adapters/gemini.adapter.js.map +1 -0
- package/dist-server/server/modules/orchestration/a2a/adapters/opencode.adapter.js +205 -0
- package/dist-server/server/modules/orchestration/a2a/adapters/opencode.adapter.js.map +1 -0
- package/dist-server/server/modules/orchestration/a2a/adapters/qwen.adapter.js +205 -0
- package/dist-server/server/modules/orchestration/a2a/adapters/qwen.adapter.js.map +1 -0
- package/dist-server/server/modules/orchestration/a2a/routes.js +298 -34
- package/dist-server/server/modules/orchestration/a2a/routes.js.map +1 -1
- package/dist-server/server/modules/orchestration/a2a/task-store.js +144 -0
- package/dist-server/server/modules/orchestration/a2a/task-store.js.map +1 -0
- package/dist-server/server/modules/orchestration/a2a/validator.js +16 -0
- package/dist-server/server/modules/orchestration/a2a/validator.js.map +1 -1
- package/dist-server/server/modules/orchestration/index.js +14 -0
- package/dist-server/server/modules/orchestration/index.js.map +1 -1
- package/dist-server/server/modules/orchestration/preview/port-watcher.js +90 -0
- package/dist-server/server/modules/orchestration/preview/port-watcher.js.map +1 -0
- package/dist-server/server/modules/orchestration/preview/preview-proxy.js +58 -0
- package/dist-server/server/modules/orchestration/preview/preview-proxy.js.map +1 -0
- package/dist-server/server/modules/orchestration/preview/types.js +2 -0
- package/dist-server/server/modules/orchestration/preview/types.js.map +1 -0
- package/dist-server/server/modules/orchestration/tasks/orchestration-task-store.js +37 -0
- package/dist-server/server/modules/orchestration/tasks/orchestration-task-store.js.map +1 -0
- package/dist-server/server/modules/orchestration/tasks/orchestration-task.routes.js +68 -0
- package/dist-server/server/modules/orchestration/tasks/orchestration-task.routes.js.map +1 -0
- package/dist-server/server/modules/orchestration/tasks/orchestration-task.service.js +128 -0
- package/dist-server/server/modules/orchestration/tasks/orchestration-task.service.js.map +1 -0
- package/dist-server/server/modules/orchestration/tasks/orchestration-task.types.js +2 -0
- package/dist-server/server/modules/orchestration/tasks/orchestration-task.types.js.map +1 -0
- package/dist-server/server/modules/orchestration/workflows/built-in-workflows.js +126 -0
- package/dist-server/server/modules/orchestration/workflows/built-in-workflows.js.map +1 -0
- package/dist-server/server/modules/orchestration/workflows/workflow-runner.js +1047 -0
- package/dist-server/server/modules/orchestration/workflows/workflow-runner.js.map +1 -0
- package/dist-server/server/modules/orchestration/workflows/workflow-store.js +76 -0
- package/dist-server/server/modules/orchestration/workflows/workflow-store.js.map +1 -0
- package/dist-server/server/modules/orchestration/workflows/workflow.routes.js +151 -0
- package/dist-server/server/modules/orchestration/workflows/workflow.routes.js.map +1 -0
- package/dist-server/server/modules/orchestration/workflows/workflow.types.js +2 -0
- package/dist-server/server/modules/orchestration/workflows/workflow.types.js.map +1 -0
- package/dist-server/server/modules/orchestration/workflows/workspace-target.js +98 -0
- package/dist-server/server/modules/orchestration/workflows/workspace-target.js.map +1 -0
- package/dist-server/server/modules/orchestration/workspace/docker-workspace.js +122 -0
- package/dist-server/server/modules/orchestration/workspace/docker-workspace.js.map +1 -0
- package/dist-server/server/modules/orchestration/workspace/path-safety.js +48 -0
- package/dist-server/server/modules/orchestration/workspace/path-safety.js.map +1 -0
- package/dist-server/server/modules/orchestration/workspace/types.js +11 -0
- package/dist-server/server/modules/orchestration/workspace/types.js.map +1 -0
- package/dist-server/server/modules/orchestration/workspace/workspace-manager.js +80 -0
- package/dist-server/server/modules/orchestration/workspace/workspace-manager.js.map +1 -0
- package/dist-server/server/modules/orchestration/workspace/worktree-workspace.js +96 -0
- package/dist-server/server/modules/orchestration/workspace/worktree-workspace.js.map +1 -0
- package/dist-server/server/modules/providers/index.js +3 -0
- package/dist-server/server/modules/providers/index.js.map +1 -0
- package/dist-server/server/openai-codex.js +35 -4
- package/dist-server/server/openai-codex.js.map +1 -1
- package/dist-server/server/routes/commands.js +25 -25
- package/dist-server/server/routes/git.js +17 -17
- package/dist-server/server/routes/taskmaster.js +525 -508
- package/dist-server/server/routes/taskmaster.js.map +1 -1
- package/package.json +180 -178
- package/scripts/fix-node-pty.js +67 -67
- package/scripts/smoke/a2a-roundtrip.mjs +86 -17
- package/scripts/smoke/orchestration-api.mjs +172 -0
- package/scripts/smoke/orchestration-live-run.mjs +176 -0
- package/server/claude-sdk.js +898 -857
- package/server/cli.js +935 -940
- package/server/constants/config.js +4 -4
- package/server/cursor-cli.js +342 -342
- package/server/daemon/manager.js +564 -564
- package/server/daemon-manager.js +959 -920
- package/server/database/db.js +794 -794
- package/server/database/json-store.js +197 -194
- package/server/gemini-cli.js +535 -535
- package/server/gemini-response-handler.js +79 -79
- package/server/index.js +3135 -3104
- package/server/load-env.js +34 -34
- package/server/middleware/auth.js +173 -173
- package/server/modules/orchestration/a2a/adapter-registry.ts +72 -22
- package/server/modules/orchestration/a2a/adapters/abstract-a2a.adapter.ts +9 -3
- package/server/modules/orchestration/a2a/adapters/claude-code.adapter.ts +1 -0
- package/server/modules/orchestration/a2a/adapters/codex.adapter.ts +244 -0
- package/server/modules/orchestration/a2a/adapters/cursor.adapter.ts +249 -0
- package/server/modules/orchestration/a2a/adapters/gemini.adapter.ts +248 -0
- package/server/modules/orchestration/a2a/adapters/opencode.adapter.ts +248 -0
- package/server/modules/orchestration/a2a/adapters/qwen.adapter.ts +248 -0
- package/server/modules/orchestration/a2a/routes.ts +349 -36
- package/server/modules/orchestration/a2a/task-store.ts +178 -0
- package/server/modules/orchestration/a2a/types.ts +14 -0
- package/server/modules/orchestration/a2a/validator.ts +25 -2
- package/server/modules/orchestration/index.ts +40 -0
- package/server/modules/orchestration/preview/port-watcher.ts +112 -0
- package/server/modules/orchestration/preview/preview-proxy.ts +60 -0
- package/server/modules/orchestration/preview/types.ts +19 -0
- package/server/modules/orchestration/tasks/orchestration-task-store.ts +45 -0
- package/server/modules/orchestration/tasks/orchestration-task.routes.ts +73 -0
- package/server/modules/orchestration/tasks/orchestration-task.service.ts +145 -0
- package/server/modules/orchestration/tasks/orchestration-task.types.ts +29 -0
- package/server/modules/orchestration/workflows/built-in-workflows.ts +127 -0
- package/server/modules/orchestration/workflows/workflow-runner.ts +1206 -0
- package/server/modules/orchestration/workflows/workflow-store.ts +97 -0
- package/server/modules/orchestration/workflows/workflow.routes.ts +169 -0
- package/server/modules/orchestration/workflows/workflow.types.ts +70 -0
- package/server/modules/orchestration/workflows/workspace-target.ts +120 -0
- package/server/modules/orchestration/workspace/docker-workspace.ts +135 -0
- package/server/modules/orchestration/workspace/path-safety.ts +55 -0
- package/server/modules/orchestration/workspace/types.ts +52 -0
- package/server/modules/orchestration/workspace/workspace-manager.ts +97 -0
- package/server/modules/orchestration/workspace/worktree-workspace.ts +125 -0
- package/server/modules/providers/index.ts +2 -0
- package/server/modules/providers/list/claude/claude-auth.provider.ts +145 -145
- package/server/modules/providers/list/claude/claude-mcp.provider.ts +135 -135
- package/server/modules/providers/list/claude/claude-sessions.provider.ts +306 -306
- package/server/modules/providers/list/claude/claude.provider.ts +15 -15
- package/server/modules/providers/list/codex/codex-auth.provider.ts +115 -115
- package/server/modules/providers/list/codex/codex-mcp.provider.ts +135 -135
- package/server/modules/providers/list/codex/codex-sessions.provider.ts +319 -319
- package/server/modules/providers/list/codex/codex.provider.ts +15 -15
- package/server/modules/providers/list/cursor/cursor-auth.provider.ts +143 -143
- package/server/modules/providers/list/cursor/cursor-mcp.provider.ts +108 -108
- package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +421 -421
- package/server/modules/providers/list/cursor/cursor.provider.ts +15 -15
- package/server/modules/providers/list/gemini/gemini-auth.provider.ts +163 -163
- package/server/modules/providers/list/gemini/gemini-mcp.provider.ts +110 -110
- package/server/modules/providers/list/gemini/gemini-sessions.provider.ts +227 -227
- package/server/modules/providers/list/gemini/gemini.provider.ts +15 -15
- package/server/modules/providers/list/opencode/opencode-auth.provider.ts +130 -130
- package/server/modules/providers/list/opencode/opencode-mcp.provider.ts +126 -126
- package/server/modules/providers/list/opencode/opencode-sessions.provider.ts +232 -232
- package/server/modules/providers/list/opencode/opencode.provider.ts +29 -29
- package/server/modules/providers/list/qwen/qwen-auth.provider.ts +145 -145
- package/server/modules/providers/list/qwen/qwen-mcp.provider.ts +114 -114
- package/server/modules/providers/list/qwen/qwen-sessions.provider.ts +265 -265
- package/server/modules/providers/list/qwen/qwen.provider.ts +21 -21
- package/server/modules/providers/provider.registry.ts +40 -40
- package/server/modules/providers/provider.routes.ts +819 -819
- package/server/modules/providers/services/mcp.service.ts +86 -86
- package/server/modules/providers/services/provider-auth.service.ts +26 -26
- package/server/modules/providers/services/sessions.service.ts +45 -45
- package/server/modules/providers/shared/base/abstract.provider.ts +20 -20
- package/server/modules/providers/shared/mcp/mcp.provider.ts +151 -151
- package/server/modules/providers/shared/provider-configs.ts +142 -142
- package/server/modules/providers/tests/mcp.test.ts +293 -293
- package/server/openai-codex.js +462 -426
- package/server/opencode-cli.js +459 -459
- package/server/opencode-response-handler.js +107 -107
- package/server/projects.js +3105 -3105
- package/server/qwen-code-cli.js +395 -395
- package/server/qwen-response-handler.js +73 -73
- package/server/routes/agent.js +1365 -1365
- package/server/routes/auth.js +138 -138
- package/server/routes/codex.js +19 -19
- package/server/routes/commands.js +554 -554
- package/server/routes/cursor.js +52 -52
- package/server/routes/gemini.js +24 -24
- package/server/routes/git.js +1488 -1488
- package/server/routes/mcp-utils.js +31 -31
- package/server/routes/messages.js +61 -61
- package/server/routes/network.js +120 -120
- package/server/routes/plugins.js +318 -318
- package/server/routes/projects.js +915 -915
- package/server/routes/qwen.js +27 -27
- package/server/routes/settings.js +286 -286
- package/server/routes/taskmaster.js +1496 -1471
- package/server/routes/telegram.js +125 -125
- package/server/routes/user.js +123 -123
- package/server/services/external-access.js +171 -171
- package/server/services/install-jobs.js +571 -571
- package/server/services/notification-orchestrator.js +242 -242
- package/server/services/provider-credentials.js +189 -189
- package/server/services/provider-models.js +381 -381
- package/server/services/telegram/bot.js +279 -279
- package/server/services/telegram/telegram-http-client.js +130 -130
- package/server/services/telegram/translations.js +170 -170
- package/server/services/vapid-keys.js +36 -36
- package/server/sessionManager.js +225 -225
- package/server/shared/interfaces.ts +54 -54
- package/server/shared/types.ts +172 -172
- package/server/shared/utils.ts +193 -193
- package/server/tsconfig.json +36 -36
- package/server/utils/colors.js +21 -21
- package/server/utils/commandParser.js +303 -303
- package/server/utils/frontmatter.js +18 -18
- package/server/utils/gitConfig.js +34 -34
- package/server/utils/mcp-detector.js +147 -147
- package/server/utils/plugin-loader.js +457 -457
- package/server/utils/plugin-process-manager.js +184 -184
- package/server/utils/port-access.js +209 -209
- package/server/utils/runtime-paths.js +37 -37
- package/server/utils/taskmaster-websocket.js +128 -128
- package/server/utils/url-detection.js +71 -71
- package/server/vite-daemon.js +78 -78
- package/shared/modelConstants.js +162 -162
- package/shared/networkHosts.js +22 -22
- package/dist/assets/index-B1ghfb4w.css +0 -32
- package/dist/assets/index-BvClqlMf.js +0 -852
package/scripts/fix-node-pty.js
CHANGED
|
@@ -1,67 +1,67 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Fix node-pty spawn-helper permissions on macOS
|
|
4
|
-
*
|
|
5
|
-
* This script fixes a known issue with node-pty where the spawn-helper
|
|
6
|
-
* binary is shipped without execute permissions, causing "posix_spawnp failed" errors.
|
|
7
|
-
*
|
|
8
|
-
* @see https://github.com/microsoft/node-pty/issues/850
|
|
9
|
-
* @module scripts/fix-node-pty
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { promises as fs } from 'fs';
|
|
13
|
-
import path from 'path';
|
|
14
|
-
import { fileURLToPath } from 'url';
|
|
15
|
-
|
|
16
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
17
|
-
const __dirname = path.dirname(__filename);
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Fixes the spawn-helper binary permissions for node-pty on macOS.
|
|
21
|
-
*
|
|
22
|
-
* The node-pty package ships the spawn-helper binary without execute permissions
|
|
23
|
-
* (644 instead of 755), which causes "posix_spawnp failed" errors when trying
|
|
24
|
-
* to spawn terminal processes.
|
|
25
|
-
*
|
|
26
|
-
* This function:
|
|
27
|
-
* 1. Checks if running on macOS (darwin)
|
|
28
|
-
* 2. Locates spawn-helper binaries for both arm64 and x64 architectures
|
|
29
|
-
* 3. Sets execute permissions (755) on each binary found
|
|
30
|
-
*
|
|
31
|
-
* @async
|
|
32
|
-
* @function fixSpawnHelper
|
|
33
|
-
* @returns {Promise<void>} Resolves when permissions are fixed or skipped
|
|
34
|
-
* @example
|
|
35
|
-
* // Run as postinstall script
|
|
36
|
-
* await fixSpawnHelper();
|
|
37
|
-
*/
|
|
38
|
-
async function fixSpawnHelper() {
|
|
39
|
-
const nodeModulesPath = path.join(__dirname, '..', 'node_modules', 'node-pty', 'prebuilds');
|
|
40
|
-
|
|
41
|
-
// Only run on macOS
|
|
42
|
-
if (process.platform !== 'darwin') {
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const darwinDirs = ['darwin-arm64', 'darwin-x64'];
|
|
47
|
-
|
|
48
|
-
for (const dir of darwinDirs) {
|
|
49
|
-
const spawnHelperPath = path.join(nodeModulesPath, dir, 'spawn-helper');
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
// Check if file exists
|
|
53
|
-
await fs.access(spawnHelperPath);
|
|
54
|
-
|
|
55
|
-
// Make it executable (755)
|
|
56
|
-
await fs.chmod(spawnHelperPath, 0o755);
|
|
57
|
-
console.log(`[postinstall] Fixed permissions for ${spawnHelperPath}`);
|
|
58
|
-
} catch (err) {
|
|
59
|
-
// File doesn't exist or other error - ignore
|
|
60
|
-
if (err.code !== 'ENOENT') {
|
|
61
|
-
console.warn(`[postinstall] Warning: Could not fix ${spawnHelperPath}: ${err.message}`);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
fixSpawnHelper().catch(console.error);
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Fix node-pty spawn-helper permissions on macOS
|
|
4
|
+
*
|
|
5
|
+
* This script fixes a known issue with node-pty where the spawn-helper
|
|
6
|
+
* binary is shipped without execute permissions, causing "posix_spawnp failed" errors.
|
|
7
|
+
*
|
|
8
|
+
* @see https://github.com/microsoft/node-pty/issues/850
|
|
9
|
+
* @module scripts/fix-node-pty
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { promises as fs } from 'fs';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
import { fileURLToPath } from 'url';
|
|
15
|
+
|
|
16
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
17
|
+
const __dirname = path.dirname(__filename);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Fixes the spawn-helper binary permissions for node-pty on macOS.
|
|
21
|
+
*
|
|
22
|
+
* The node-pty package ships the spawn-helper binary without execute permissions
|
|
23
|
+
* (644 instead of 755), which causes "posix_spawnp failed" errors when trying
|
|
24
|
+
* to spawn terminal processes.
|
|
25
|
+
*
|
|
26
|
+
* This function:
|
|
27
|
+
* 1. Checks if running on macOS (darwin)
|
|
28
|
+
* 2. Locates spawn-helper binaries for both arm64 and x64 architectures
|
|
29
|
+
* 3. Sets execute permissions (755) on each binary found
|
|
30
|
+
*
|
|
31
|
+
* @async
|
|
32
|
+
* @function fixSpawnHelper
|
|
33
|
+
* @returns {Promise<void>} Resolves when permissions are fixed or skipped
|
|
34
|
+
* @example
|
|
35
|
+
* // Run as postinstall script
|
|
36
|
+
* await fixSpawnHelper();
|
|
37
|
+
*/
|
|
38
|
+
async function fixSpawnHelper() {
|
|
39
|
+
const nodeModulesPath = path.join(__dirname, '..', 'node_modules', 'node-pty', 'prebuilds');
|
|
40
|
+
|
|
41
|
+
// Only run on macOS
|
|
42
|
+
if (process.platform !== 'darwin') {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const darwinDirs = ['darwin-arm64', 'darwin-x64'];
|
|
47
|
+
|
|
48
|
+
for (const dir of darwinDirs) {
|
|
49
|
+
const spawnHelperPath = path.join(nodeModulesPath, dir, 'spawn-helper');
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
// Check if file exists
|
|
53
|
+
await fs.access(spawnHelperPath);
|
|
54
|
+
|
|
55
|
+
// Make it executable (755)
|
|
56
|
+
await fs.chmod(spawnHelperPath, 0o755);
|
|
57
|
+
console.log(`[postinstall] Fixed permissions for ${spawnHelperPath}`);
|
|
58
|
+
} catch (err) {
|
|
59
|
+
// File doesn't exist or other error - ignore
|
|
60
|
+
if (err.code !== 'ENOENT') {
|
|
61
|
+
console.warn(`[postinstall] Warning: Could not fix ${spawnHelperPath}: ${err.message}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
fixSpawnHelper().catch(console.error);
|
|
@@ -25,6 +25,15 @@ async function jget(path) {
|
|
|
25
25
|
return r.json();
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
async function jpost(path, body) {
|
|
29
|
+
const r = await fetch(`${baseUrl}${path}`, {
|
|
30
|
+
method: 'POST',
|
|
31
|
+
headers: { 'content-type': 'application/json' },
|
|
32
|
+
body: JSON.stringify(body),
|
|
33
|
+
});
|
|
34
|
+
return { status: r.status, json: await r.json() };
|
|
35
|
+
}
|
|
36
|
+
|
|
28
37
|
async function main() {
|
|
29
38
|
console.log('1) /a2a/.well-known/agent-card.json');
|
|
30
39
|
const card = await jget('/a2a/.well-known/agent-card.json');
|
|
@@ -35,28 +44,88 @@ async function main() {
|
|
|
35
44
|
const agents = await jget('/a2a/agents');
|
|
36
45
|
const ids = agents.agents.map((a) => a.name);
|
|
37
46
|
console.log(' registered:', ids.join(', '));
|
|
38
|
-
|
|
39
|
-
|
|
47
|
+
const expectedAgents = [
|
|
48
|
+
'pixcode-claude-code',
|
|
49
|
+
'pixcode-codex',
|
|
50
|
+
'pixcode-cursor',
|
|
51
|
+
'pixcode-gemini',
|
|
52
|
+
'pixcode-qwen',
|
|
53
|
+
'pixcode-opencode',
|
|
54
|
+
];
|
|
55
|
+
for (const expected of expectedAgents) {
|
|
56
|
+
if (!ids.includes(expected)) {
|
|
57
|
+
throw new Error(`${expected} adapter not registered`);
|
|
58
|
+
}
|
|
40
59
|
}
|
|
41
60
|
|
|
42
|
-
console.log('3) POST /a2a/
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
61
|
+
console.log('3) POST /a2a/adapters/resolve');
|
|
62
|
+
const resolveRes = await jpost('/a2a/adapters/resolve', {
|
|
63
|
+
adapterId: 'skill:typescript-edit',
|
|
64
|
+
routing: { preferredAdapterId: 'codex' },
|
|
65
|
+
});
|
|
66
|
+
if (resolveRes.status !== 200) throw new Error(`resolve -> ${resolveRes.status}`);
|
|
67
|
+
console.log(' resolved=', resolveRes.json.resolvedAdapterId);
|
|
68
|
+
if (resolveRes.json.resolvedAdapterId !== 'codex') {
|
|
69
|
+
throw new Error('skill resolution did not honor preferredAdapterId=codex');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
console.log('4) POST /a2a/tasks (invalid adapter)');
|
|
73
|
+
const invalidSubmit = await jpost('/a2a/tasks', {
|
|
74
|
+
adapterId: 'missing-adapter',
|
|
75
|
+
message: {
|
|
76
|
+
messageId: 'm_invalid_adapter',
|
|
77
|
+
role: 'user',
|
|
78
|
+
parts: [{ kind: 'text', text: 'noop' }],
|
|
79
|
+
},
|
|
54
80
|
});
|
|
55
|
-
if (
|
|
56
|
-
|
|
81
|
+
if (invalidSubmit.status !== 404) {
|
|
82
|
+
throw new Error(`invalid submit -> expected 404, got ${invalidSubmit.status}`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
console.log('5) POST /a2a/messages (missing task)');
|
|
86
|
+
const missingTaskMessage = await jpost('/a2a/messages', {
|
|
87
|
+
messageId: 'm_missing_task',
|
|
88
|
+
role: 'user',
|
|
89
|
+
taskId: 'task_missing',
|
|
90
|
+
parts: [{ kind: 'text', text: 'noop' }],
|
|
91
|
+
});
|
|
92
|
+
if (missingTaskMessage.status !== 404) {
|
|
93
|
+
throw new Error(`missing task message -> expected 404, got ${missingTaskMessage.status}`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
console.log('6) POST /a2a/tasks');
|
|
97
|
+
const submitRes = await jpost('/a2a/tasks', {
|
|
98
|
+
adapterId: 'claude-code',
|
|
99
|
+
message: {
|
|
100
|
+
messageId: 'm_smoke_1',
|
|
101
|
+
role: 'user',
|
|
102
|
+
parts: [{ kind: 'text', text: 'Reply with the single word: ok' }],
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
if (submitRes.status !== 202) throw new Error(`submit -> ${submitRes.status}`);
|
|
106
|
+
const task = submitRes.json;
|
|
57
107
|
console.log(' task.id=', task.id, 'state=', task.state);
|
|
108
|
+
if (task.history?.[0]?.taskId !== task.id) {
|
|
109
|
+
throw new Error('task-scoped initial history message is missing taskId');
|
|
110
|
+
}
|
|
111
|
+
if (task.metadata?.adapterId !== 'claude-code') {
|
|
112
|
+
throw new Error('resolved adapterId was not persisted to task metadata');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
console.log('7) GET /a2a/tasks?adapterId=claude-code&limit=5');
|
|
116
|
+
const listedTasks = await jget('/a2a/tasks?adapterId=claude-code&limit=5');
|
|
117
|
+
if (!Array.isArray(listedTasks.tasks) || listedTasks.count < 1) {
|
|
118
|
+
throw new Error('task listing did not return any tasks');
|
|
119
|
+
}
|
|
120
|
+
const listedTask = listedTasks.tasks.find((entry) => entry.id === task.id);
|
|
121
|
+
if (!listedTask) {
|
|
122
|
+
throw new Error('submitted task did not appear in filtered task listing');
|
|
123
|
+
}
|
|
124
|
+
if (listedTask.adapterId !== 'claude-code') {
|
|
125
|
+
throw new Error('task summary adapterId mismatch');
|
|
126
|
+
}
|
|
58
127
|
|
|
59
|
-
console.log('
|
|
128
|
+
console.log('8) GET /a2a/tasks/:id/stream (SSE)');
|
|
60
129
|
const streamRes = await fetch(`${baseUrl}/a2a/tasks/${task.id}/stream`);
|
|
61
130
|
if (!streamRes.ok) throw new Error(`stream -> ${streamRes.status}`);
|
|
62
131
|
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const baseUrl = process.env.PIXCODE_BASE_URL || 'http://127.0.0.1:3001';
|
|
4
|
+
const apiKey = process.env.PIXCODE_API_KEY;
|
|
5
|
+
|
|
6
|
+
if (!apiKey) {
|
|
7
|
+
console.error('PIXCODE_API_KEY is required.');
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async function request(path, options = {}) {
|
|
12
|
+
const response = await fetch(`${baseUrl}${path}`, {
|
|
13
|
+
...options,
|
|
14
|
+
headers: {
|
|
15
|
+
authorization: `Bearer ${apiKey}`,
|
|
16
|
+
'content-type': 'application/json',
|
|
17
|
+
...(options.headers || {}),
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
const text = await response.text();
|
|
21
|
+
const body = text ? JSON.parse(text) : null;
|
|
22
|
+
if (!response.ok) {
|
|
23
|
+
throw new Error(`${options.method || 'GET'} ${path} failed: ${response.status} ${text}`);
|
|
24
|
+
}
|
|
25
|
+
return body;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function assert(condition, message) {
|
|
29
|
+
if (!condition) {
|
|
30
|
+
throw new Error(message);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function nodeById(nodes, id) {
|
|
35
|
+
const node = nodes.find((candidate) => candidate.id === id);
|
|
36
|
+
assert(node, `Missing workflow node: ${id}`);
|
|
37
|
+
return node;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function parseJsonEnv(name, fallback) {
|
|
41
|
+
if (!process.env[name]) return fallback;
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(process.env[name]);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
throw new Error(`${name} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function safeNodeId(adapterId, suffix) {
|
|
50
|
+
return `${adapterId.replace(/[^a-zA-Z0-9_]+/g, '_')}_${suffix}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function safeAgentNodeId(agent, index, suffix) {
|
|
54
|
+
return `agent_${index + 1}_${safeNodeId(agent.adapterId, suffix)}`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const smokeAgents = parseJsonEnv('PIXCODE_SMOKE_AGENTS_JSON', [
|
|
58
|
+
{
|
|
59
|
+
instanceId: 'codex-frontend',
|
|
60
|
+
adapterId: 'codex',
|
|
61
|
+
label: 'Agent #1',
|
|
62
|
+
role: 'frontend',
|
|
63
|
+
enabled: true,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
instanceId: 'codex-backend',
|
|
67
|
+
adapterId: 'codex',
|
|
68
|
+
label: 'Agent #2',
|
|
69
|
+
role: 'backend',
|
|
70
|
+
enabled: true,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
instanceId: 'codex-review',
|
|
74
|
+
adapterId: 'codex',
|
|
75
|
+
label: 'Agent #3',
|
|
76
|
+
role: 'review',
|
|
77
|
+
enabled: true,
|
|
78
|
+
},
|
|
79
|
+
]);
|
|
80
|
+
|
|
81
|
+
const teamMetadata = {
|
|
82
|
+
agents: smokeAgents,
|
|
83
|
+
settings: {
|
|
84
|
+
...parseJsonEnv('PIXCODE_SMOKE_SETTINGS_JSON', {}),
|
|
85
|
+
maxParallelAgents: Number.parseInt(process.env.PIXCODE_SMOKE_MAX_PARALLEL || '3', 10),
|
|
86
|
+
isolation: process.env.PIXCODE_SMOKE_ISOLATION || 'host',
|
|
87
|
+
keepWorkspace: process.env.PIXCODE_SMOKE_KEEP_WORKSPACE !== 'false',
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
async function main() {
|
|
92
|
+
const health = await fetch(`${baseUrl}/health`).then((response) => response.json());
|
|
93
|
+
assert(health.status === 'ok', 'Health check did not return ok.');
|
|
94
|
+
|
|
95
|
+
const workflows = await request('/api/orchestration/workflows');
|
|
96
|
+
assert(Array.isArray(workflows.workflows), 'Workflow list payload is invalid.');
|
|
97
|
+
assert(workflows.workflows.some((workflow) => workflow.id === 'agent_team'), 'agent_team workflow is missing.');
|
|
98
|
+
|
|
99
|
+
const preview = await request('/api/orchestration/workflows/agent_team/preview', {
|
|
100
|
+
method: 'POST',
|
|
101
|
+
body: JSON.stringify({ metadata: teamMetadata }),
|
|
102
|
+
});
|
|
103
|
+
assert(preview.workflow?.id === 'agent_team', 'Preview did not return the agent_team workflow.');
|
|
104
|
+
assert(preview.nodeCount === preview.nodes.length, 'Preview nodeCount does not match nodes length.');
|
|
105
|
+
|
|
106
|
+
const backendIndex = smokeAgents.findIndex((agent) => agent.role === 'backend');
|
|
107
|
+
const frontendIndex = smokeAgents.findIndex((agent) => agent.role === 'frontend');
|
|
108
|
+
const reviewIndex = smokeAgents.findIndex((agent) => agent.role === 'review');
|
|
109
|
+
assert(backendIndex >= 0, 'Smoke agents must include one role=backend agent.');
|
|
110
|
+
assert(frontendIndex >= 0, 'Smoke agents must include one role=frontend agent.');
|
|
111
|
+
assert(reviewIndex >= 0, 'Smoke agents must include one role=review agent.');
|
|
112
|
+
|
|
113
|
+
const backendAgent = smokeAgents[backendIndex];
|
|
114
|
+
const frontendAgent = smokeAgents[frontendIndex];
|
|
115
|
+
const reviewAgent = smokeAgents[reviewIndex];
|
|
116
|
+
const backendHandoffId = safeAgentNodeId(backendAgent, backendIndex, 'handoff');
|
|
117
|
+
const backendWorkId = safeAgentNodeId(backendAgent, backendIndex, 'work');
|
|
118
|
+
const frontendWorkId = safeAgentNodeId(frontendAgent, frontendIndex, 'work');
|
|
119
|
+
const reviewWorkId = safeAgentNodeId(reviewAgent, reviewIndex, 'work');
|
|
120
|
+
|
|
121
|
+
const backendHandoff = nodeById(preview.nodes, backendHandoffId);
|
|
122
|
+
const backendWork = nodeById(preview.nodes, backendWorkId);
|
|
123
|
+
const frontendWork = nodeById(preview.nodes, frontendWorkId);
|
|
124
|
+
const reviewWork = nodeById(preview.nodes, reviewWorkId);
|
|
125
|
+
const finalReport = nodeById(preview.nodes, 'final_report');
|
|
126
|
+
|
|
127
|
+
assert(backendHandoff.timeoutMs === 120000, 'Backend handoff timeout is not set to 120000ms.');
|
|
128
|
+
assert(backendHandoff.inputs.includes('coordinator'), 'Backend handoff must depend on coordinator.');
|
|
129
|
+
assert(backendWork.inputs.includes(backendHandoffId), 'Backend work must depend on backend handoff.');
|
|
130
|
+
assert(frontendWork.inputs.includes(backendHandoffId), 'Frontend work must depend on backend handoff.');
|
|
131
|
+
assert(!frontendWork.inputs.includes(backendWorkId), 'Frontend must not wait for full backend implementation.');
|
|
132
|
+
assert(reviewWork.inputs.includes(frontendWorkId), 'Review must depend on frontend work.');
|
|
133
|
+
assert(reviewWork.inputs.includes(backendWorkId), 'Review must depend on backend work.');
|
|
134
|
+
assert(finalReport.inputs.includes(reviewWorkId), 'Final report must include review output.');
|
|
135
|
+
|
|
136
|
+
const runs = await request('/api/orchestration/workflows/runs?limit=5');
|
|
137
|
+
assert(Array.isArray(runs.runs), 'Runs payload is invalid.');
|
|
138
|
+
|
|
139
|
+
let eventsChecked = false;
|
|
140
|
+
if (runs.runs[0]?.id) {
|
|
141
|
+
const controller = new AbortController();
|
|
142
|
+
const response = await fetch(
|
|
143
|
+
`${baseUrl}/api/orchestration/workflows/runs/${encodeURIComponent(runs.runs[0].id)}/events`,
|
|
144
|
+
{
|
|
145
|
+
headers: { authorization: `Bearer ${apiKey}` },
|
|
146
|
+
signal: controller.signal,
|
|
147
|
+
},
|
|
148
|
+
);
|
|
149
|
+
assert(response.ok, `Run events endpoint returned ${response.status}.`);
|
|
150
|
+
assert(response.body, 'Run events endpoint did not return a readable body.');
|
|
151
|
+
const reader = response.body.getReader();
|
|
152
|
+
const firstChunk = await reader.read();
|
|
153
|
+
controller.abort();
|
|
154
|
+
const eventText = new TextDecoder().decode(firstChunk.value || new Uint8Array());
|
|
155
|
+
assert(eventText.includes('event: snapshot'), 'Run events endpoint did not emit an initial snapshot.');
|
|
156
|
+
eventsChecked = true;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
console.log(JSON.stringify({
|
|
160
|
+
ok: true,
|
|
161
|
+
baseUrl,
|
|
162
|
+
workflowCount: workflows.workflows.length,
|
|
163
|
+
previewNodeIds: preview.nodes.map((node) => node.id),
|
|
164
|
+
recentRunCount: runs.runs.length,
|
|
165
|
+
eventsChecked,
|
|
166
|
+
}, null, 2));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
main().catch((error) => {
|
|
170
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
171
|
+
process.exit(1);
|
|
172
|
+
});
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const baseUrl = process.env.PIXCODE_BASE_URL || 'http://127.0.0.1:3001';
|
|
4
|
+
const apiKey = process.env.PIXCODE_API_KEY;
|
|
5
|
+
const goal = process.env.PIXCODE_LIVE_GOAL;
|
|
6
|
+
const timeoutMs = Number.parseInt(process.env.PIXCODE_LIVE_TIMEOUT_MS || '1200000', 10);
|
|
7
|
+
const minAgentOutputs = Number.parseInt(process.env.PIXCODE_LIVE_MIN_AGENT_OUTPUTS || '2', 10);
|
|
8
|
+
const workflowId = process.env.PIXCODE_LIVE_WORKFLOW_ID || 'agent_team';
|
|
9
|
+
|
|
10
|
+
if (!apiKey) {
|
|
11
|
+
console.error('PIXCODE_API_KEY is required.');
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (!goal) {
|
|
16
|
+
console.error('PIXCODE_LIVE_GOAL is required.');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function parseJsonEnv(name) {
|
|
21
|
+
const raw = process.env[name];
|
|
22
|
+
if (!raw) {
|
|
23
|
+
throw new Error(`${name} is required.`);
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(raw);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
throw new Error(`${name} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function assert(condition, message) {
|
|
33
|
+
if (!condition) throw new Error(message);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function headers(extra = {}) {
|
|
37
|
+
return {
|
|
38
|
+
authorization: `Bearer ${apiKey}`,
|
|
39
|
+
'content-type': 'application/json',
|
|
40
|
+
...extra,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function request(path, options = {}) {
|
|
45
|
+
const response = await fetch(`${baseUrl}${path}`, {
|
|
46
|
+
...options,
|
|
47
|
+
headers: headers(options.headers || {}),
|
|
48
|
+
});
|
|
49
|
+
const text = await response.text();
|
|
50
|
+
const body = text ? JSON.parse(text) : null;
|
|
51
|
+
if (!response.ok) {
|
|
52
|
+
throw new Error(`${options.method || 'GET'} ${path} failed: ${response.status} ${text}`);
|
|
53
|
+
}
|
|
54
|
+
return body;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function terminal(status) {
|
|
58
|
+
return status === 'completed' || status === 'failed' || status === 'canceled';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function agentTextCount(run) {
|
|
62
|
+
return (run.nodeRuns || []).filter((node) =>
|
|
63
|
+
(node.messages || []).some((message) => message.role !== 'user' && message.text?.trim()) ||
|
|
64
|
+
Boolean(node.outputText?.trim()),
|
|
65
|
+
).length;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function compactNodes(run) {
|
|
69
|
+
return (run.nodeRuns || []).map((node) => ({
|
|
70
|
+
nodeId: node.nodeId,
|
|
71
|
+
label: node.agentLabel,
|
|
72
|
+
status: node.status,
|
|
73
|
+
taskId: node.a2aTaskId,
|
|
74
|
+
messageCount: (node.messages || []).filter((message) => message.role !== 'user').length,
|
|
75
|
+
hasOutput: Boolean(node.outputText?.trim()),
|
|
76
|
+
error: node.error,
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function cancelRun(runId) {
|
|
81
|
+
try {
|
|
82
|
+
await request(`/api/orchestration/workflows/runs/${encodeURIComponent(runId)}/cancel`, {
|
|
83
|
+
method: 'POST',
|
|
84
|
+
body: '{}',
|
|
85
|
+
});
|
|
86
|
+
} catch {
|
|
87
|
+
// Best-effort cleanup only.
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function main() {
|
|
92
|
+
const agents = parseJsonEnv('PIXCODE_LIVE_AGENTS_JSON');
|
|
93
|
+
assert(Array.isArray(agents) && agents.length > 0, 'PIXCODE_LIVE_AGENTS_JSON must be a non-empty array.');
|
|
94
|
+
|
|
95
|
+
const settings = process.env.PIXCODE_LIVE_SETTINGS_JSON
|
|
96
|
+
? JSON.parse(process.env.PIXCODE_LIVE_SETTINGS_JSON)
|
|
97
|
+
: {};
|
|
98
|
+
const metadata = {
|
|
99
|
+
agents,
|
|
100
|
+
projectPath: process.env.PIXCODE_LIVE_PROJECT_PATH,
|
|
101
|
+
projectId: process.env.PIXCODE_LIVE_PROJECT_ID,
|
|
102
|
+
settings: {
|
|
103
|
+
maxParallelAgents: Number.parseInt(process.env.PIXCODE_LIVE_MAX_PARALLEL || '3', 10),
|
|
104
|
+
isolation: process.env.PIXCODE_LIVE_ISOLATION || 'host',
|
|
105
|
+
keepWorkspace: process.env.PIXCODE_LIVE_KEEP_WORKSPACE !== 'false',
|
|
106
|
+
...settings,
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const preview = await request(`/api/orchestration/workflows/${encodeURIComponent(workflowId)}/preview`, {
|
|
111
|
+
method: 'POST',
|
|
112
|
+
body: JSON.stringify({ metadata }),
|
|
113
|
+
});
|
|
114
|
+
assert(preview.nodeCount >= agents.length + 1, 'Preview did not expand enough nodes for the requested agents.');
|
|
115
|
+
console.log(JSON.stringify({ event: 'preview', nodeIds: preview.nodes.map((node) => node.id) }));
|
|
116
|
+
|
|
117
|
+
const started = await request(`/api/orchestration/workflows/${encodeURIComponent(workflowId)}/runs`, {
|
|
118
|
+
method: 'POST',
|
|
119
|
+
body: JSON.stringify({ input: goal, metadata }),
|
|
120
|
+
});
|
|
121
|
+
const runId = started.id;
|
|
122
|
+
assert(runId, 'Run id missing from start response.');
|
|
123
|
+
console.log(JSON.stringify({ event: 'started', runId, contextId: started.contextId }));
|
|
124
|
+
|
|
125
|
+
const deadline = Date.now() + timeoutMs;
|
|
126
|
+
let lastSignature = '';
|
|
127
|
+
let latest = started;
|
|
128
|
+
while (!terminal(latest.status) && Date.now() < deadline) {
|
|
129
|
+
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
130
|
+
latest = await request(`/api/orchestration/workflows/runs/${encodeURIComponent(runId)}`);
|
|
131
|
+
const nodes = compactNodes(latest);
|
|
132
|
+
const signature = JSON.stringify(nodes.map((node) => [
|
|
133
|
+
node.nodeId,
|
|
134
|
+
node.status,
|
|
135
|
+
node.messageCount,
|
|
136
|
+
node.hasOutput,
|
|
137
|
+
node.error,
|
|
138
|
+
]));
|
|
139
|
+
if (signature !== lastSignature) {
|
|
140
|
+
lastSignature = signature;
|
|
141
|
+
console.log(JSON.stringify({
|
|
142
|
+
event: 'progress',
|
|
143
|
+
status: latest.status,
|
|
144
|
+
agentOutputs: agentTextCount(latest),
|
|
145
|
+
nodes,
|
|
146
|
+
}));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (!terminal(latest.status)) {
|
|
151
|
+
await cancelRun(runId);
|
|
152
|
+
throw new Error(`Run ${runId} did not finish before ${timeoutMs}ms; canceled.`);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const outputCount = agentTextCount(latest);
|
|
156
|
+
if (outputCount < minAgentOutputs) {
|
|
157
|
+
throw new Error(`Expected at least ${minAgentOutputs} nodes with agent output; got ${outputCount}.`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (latest.status !== 'completed') {
|
|
161
|
+
throw new Error(`Run ended with ${latest.status}: ${JSON.stringify(compactNodes(latest))}`);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
console.log(JSON.stringify({
|
|
165
|
+
event: 'completed',
|
|
166
|
+
runId,
|
|
167
|
+
contextId: latest.contextId,
|
|
168
|
+
outputCount,
|
|
169
|
+
nodes: compactNodes(latest),
|
|
170
|
+
}, null, 2));
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
main().catch((error) => {
|
|
174
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
175
|
+
process.exit(1);
|
|
176
|
+
});
|