@pixelbyte-software/pixcode 1.51.2 → 1.51.3
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/CODE_OF_CONDUCT.md +41 -41
- package/CONTRIBUTING.md +155 -155
- package/LICENSE +718 -718
- package/README.de.md +169 -169
- package/README.ja.md +167 -167
- package/README.ko.md +167 -167
- package/README.md +419 -419
- package/README.ru.md +169 -169
- package/README.tr.md +298 -298
- package/README.zh-CN.md +167 -167
- package/SECURITY.md +46 -46
- package/dist/api-automation.html +110 -110
- package/dist/api-docs.html +548 -548
- package/dist/assets/{index-EN9ngyxf.js → index-17CwxHSZ.js} +185 -185
- package/dist/assets/index-B9N-gfOQ.css +32 -0
- package/dist/clear-cache.html +85 -85
- package/dist/convert-icons.md +52 -52
- package/dist/docs.html +308 -308
- package/dist/favicon.svg +8 -8
- package/dist/features.html +133 -133
- package/dist/generate-icons.js +48 -48
- package/dist/humans.txt +15 -15
- 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/landing.html +268 -268
- package/dist/llms-full.txt +119 -119
- package/dist/llms.txt +53 -53
- package/dist/logo.svg +12 -12
- package/dist/manifest.json +60 -60
- package/dist/openapi.yaml +1696 -1696
- package/dist/orchestration.html +125 -125
- package/dist/robots.txt +4 -4
- package/dist/site.css +692 -692
- package/dist/sitemap.xml +51 -51
- package/dist/sw.js +132 -132
- package/dist-server/server/cli.js +96 -96
- package/dist-server/server/daemon/manager.js +33 -33
- package/dist-server/server/daemon-manager.js +64 -64
- package/dist-server/server/index.js +122 -3
- package/dist-server/server/index.js.map +1 -1
- package/dist-server/server/modules/orchestration/a2a/adapters/json-event.adapter.js +84 -0
- package/dist-server/server/modules/orchestration/a2a/adapters/json-event.adapter.js.map +1 -0
- package/dist-server/server/modules/orchestration/a2a/adapters/json-event.adapter.test.js +43 -0
- package/dist-server/server/modules/orchestration/a2a/adapters/json-event.adapter.test.js.map +1 -0
- package/dist-server/server/modules/orchestration/hermes/hermes.routes.js +55 -1
- package/dist-server/server/modules/orchestration/hermes/hermes.routes.js.map +1 -1
- package/dist-server/server/modules/orchestration/index.js +1 -0
- package/dist-server/server/modules/orchestration/index.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/live-view.js +46 -46
- package/dist-server/server/services/hermes-gateway.js +310 -0
- package/dist-server/server/services/hermes-gateway.js.map +1 -1
- package/dist-server/server/services/public-api-manifest.js +59 -51
- package/dist-server/server/services/public-api-manifest.js.map +1 -1
- package/package.json +222 -222
- package/scripts/fix-node-pty.js +67 -67
- package/scripts/github/create-v1.38-issues.mjs +351 -351
- package/scripts/github/create-vscode-workbench-issues.mjs +121 -121
- package/scripts/hermes/configure-pixcode-mcp.mjs +165 -163
- package/scripts/hermes/pixcode-mcp-server.mjs +1009 -958
- package/scripts/smoke/changes-panel-layout.mjs +48 -48
- package/scripts/smoke/chat-composer-fixed-layout.mjs +55 -55
- package/scripts/smoke/chat-message-timeline-order.mjs +41 -41
- package/scripts/smoke/chat-realtime-hydration.mjs +44 -44
- package/scripts/smoke/chat-session-provider-pools.mjs +35 -35
- package/scripts/smoke/chat-session-state.mjs +19 -19
- package/scripts/smoke/code-editor-theme.mjs +55 -55
- package/scripts/smoke/code-editor-vscode-engine.mjs +91 -91
- package/scripts/smoke/command-center-agent-writes.mjs +79 -79
- package/scripts/smoke/command-center-non-git.mjs +46 -46
- package/scripts/smoke/context-packet.mjs +43 -43
- package/scripts/smoke/control-room-ux-redesign.mjs +91 -91
- package/scripts/smoke/daemon-entrypoint.mjs +20 -20
- package/scripts/smoke/default-landing-routing.mjs +33 -33
- package/scripts/smoke/desktop-native-notifications.mjs +30 -30
- package/scripts/smoke/desktop-tray-icon.mjs +33 -33
- package/scripts/smoke/discord-release-workflow.mjs +24 -24
- package/scripts/smoke/git-install-update.mjs +255 -255
- package/scripts/smoke/handoff-artifact-protocol.mjs +50 -50
- package/scripts/smoke/hermes-api-install.mjs +56 -56
- package/scripts/smoke/hermes-gateway-persistence.mjs +104 -104
- package/scripts/smoke/hermes-mcp-pixcode-roundtrip.mjs +426 -367
- package/scripts/smoke/hermes-rest-chat-api.mjs +162 -162
- package/scripts/smoke/hermes-rest-chat-live.mjs +45 -45
- package/scripts/smoke/hermes-rest-codex-launch.mjs +209 -209
- package/scripts/smoke/hermes-rest-gateway.mjs +79 -70
- package/scripts/smoke/hermes-rest-live.mjs +42 -42
- package/scripts/smoke/hermes-roundtrip.mjs +167 -167
- package/scripts/smoke/hermes-settings-commands.mjs +349 -346
- package/scripts/smoke/hermes-smoke-launcher-guard.mjs +34 -34
- package/scripts/smoke/live-view-diagnostics.mjs +53 -53
- package/scripts/smoke/live-view-environment.mjs +92 -92
- package/scripts/smoke/live-view-integration.mjs +450 -450
- package/scripts/smoke/mac-desktop-runtime.mjs +37 -37
- package/scripts/smoke/mobile-tunnel-guidance.mjs +29 -29
- package/scripts/smoke/model-registry.mjs +36 -36
- package/scripts/smoke/multi-project-ui.mjs +45 -45
- package/scripts/smoke/multi-worker-slots.mjs +42 -42
- package/scripts/smoke/notification-center.mjs +87 -87
- package/scripts/smoke/notification-inapp-preference.mjs +23 -23
- package/scripts/smoke/notification-taxonomy.mjs +58 -58
- package/scripts/smoke/orchestration-api.mjs +172 -172
- package/scripts/smoke/orchestration-execution-dashboard.mjs +33 -33
- package/scripts/smoke/orchestration-live-run.mjs +176 -176
- package/scripts/smoke/orchestration-mobile-scroll.mjs +29 -29
- package/scripts/smoke/orchestration-model-sync.mjs +30 -30
- package/scripts/smoke/orchestration-permission-fallback.mjs +34 -34
- package/scripts/smoke/orchestration-runtime-guards.mjs +48 -48
- package/scripts/smoke/orchestration-user-facing-output.mjs +25 -25
- package/scripts/smoke/permission-policy.mjs +50 -50
- package/scripts/smoke/pixcode-workbench-1-48.mjs +167 -167
- package/scripts/smoke/provider-models-opencode-live.mjs +66 -66
- package/scripts/smoke/provider-rest-api.mjs +124 -124
- package/scripts/smoke/provider-selection-status.mjs +52 -52
- package/scripts/smoke/run-state-refresh.mjs +52 -52
- package/scripts/smoke/runtime-manager.mjs +99 -99
- package/scripts/smoke/shell-manual-disconnect.mjs +30 -30
- package/scripts/smoke/side-panel-editor-layout.mjs +34 -34
- package/scripts/smoke/static-root-routing.mjs +21 -21
- package/scripts/smoke/strict-handoff-compact.mjs +60 -60
- package/scripts/smoke/taskmaster-config.mjs +24 -24
- package/scripts/smoke/taskmaster-execution-telegram.mjs +3 -3
- package/scripts/smoke/taskmaster-onboarding.mjs +3 -3
- package/scripts/smoke/taskmaster-run-graph.mjs +3 -3
- package/scripts/smoke/telegram-control.mjs +242 -242
- package/scripts/smoke/tunnel-persistence.mjs +56 -56
- package/scripts/smoke/update-issue-progress.mjs +69 -69
- package/scripts/smoke/update-ux.mjs +55 -55
- package/scripts/smoke/v138-completion.mjs +132 -132
- package/scripts/smoke/v138-desktop-release-hardening.mjs +69 -69
- package/scripts/smoke/v138-diagnostics.mjs +63 -63
- package/scripts/smoke/v138-issue-planner.mjs +33 -33
- package/scripts/smoke/v143-remote-control.mjs +76 -76
- package/scripts/smoke/v144-production-loop.mjs +47 -47
- package/scripts/smoke/v145-platformization.mjs +46 -46
- package/scripts/smoke/v146-control-room-ui.mjs +150 -150
- package/scripts/smoke/version-modal-autoshow.mjs +29 -29
- package/scripts/smoke/vscode-workbench-layout.mjs +63 -63
- package/scripts/smoke/vscode-workbench-polish.mjs +461 -436
- package/scripts/smoke/workflow-fallback-replay.mjs +56 -56
- package/scripts/smoke/workflow-templates.mjs +43 -43
- package/scripts/smoke/workflow-trace-timeline.mjs +46 -46
- package/scripts/update-git-install.mjs +293 -293
- package/server/claude-sdk.js +920 -920
- package/server/cli.js +1039 -1039
- package/server/constants/config.js +4 -4
- package/server/cursor-cli.js +344 -344
- package/server/daemon/manager.js +563 -563
- package/server/daemon-manager.js +964 -964
- package/server/database/db.js +921 -921
- package/server/database/json-store.js +197 -197
- package/server/gemini-cli.js +550 -550
- package/server/gemini-response-handler.js +79 -79
- package/server/index.js +128 -2
- package/server/load-env.js +35 -35
- package/server/middleware/auth.js +175 -175
- package/server/modules/orchestration/a2a/adapter-registry.ts +108 -108
- package/server/modules/orchestration/a2a/adapters/abstract-a2a.adapter.ts +63 -63
- package/server/modules/orchestration/a2a/adapters/claude-code.adapter.ts +286 -286
- package/server/modules/orchestration/a2a/adapters/codex.adapter.ts +244 -244
- package/server/modules/orchestration/a2a/adapters/cursor.adapter.ts +249 -249
- package/server/modules/orchestration/a2a/adapters/gemini.adapter.ts +248 -248
- package/server/modules/orchestration/a2a/adapters/json-event.adapter.test.ts +60 -0
- package/server/modules/orchestration/a2a/adapters/json-event.adapter.ts +101 -0
- package/server/modules/orchestration/a2a/adapters/opencode.adapter.ts +248 -248
- package/server/modules/orchestration/a2a/adapters/qwen.adapter.ts +248 -248
- package/server/modules/orchestration/a2a/agent-card.ts +55 -55
- package/server/modules/orchestration/a2a/routes.ts +590 -590
- package/server/modules/orchestration/a2a/task-store.ts +178 -178
- package/server/modules/orchestration/a2a/types.ts +126 -126
- package/server/modules/orchestration/a2a/validator.ts +113 -113
- package/server/modules/orchestration/hermes/hermes.routes.ts +642 -583
- package/server/modules/orchestration/index.ts +101 -100
- package/server/modules/orchestration/preview/port-watcher.ts +112 -112
- package/server/modules/orchestration/preview/preview-proxy.ts +60 -60
- package/server/modules/orchestration/preview/types.ts +19 -19
- package/server/modules/orchestration/security/permission-policy.ts +401 -401
- package/server/modules/orchestration/tasks/orchestration-task-store.ts +41 -41
- package/server/modules/orchestration/tasks/orchestration-task.routes.ts +64 -64
- package/server/modules/orchestration/tasks/orchestration-task.service.ts +209 -209
- package/server/modules/orchestration/tasks/orchestration-task.types.ts +40 -40
- package/server/modules/orchestration/tasks/task-run-graph.ts +155 -155
- package/server/modules/orchestration/workflows/approval-queue.ts +106 -106
- package/server/modules/orchestration/workflows/built-in-workflows.ts +127 -127
- package/server/modules/orchestration/workflows/context-packet.ts +186 -186
- package/server/modules/orchestration/workflows/handoff-artifact.ts +175 -175
- package/server/modules/orchestration/workflows/workflow-fallback-policy.ts +161 -161
- package/server/modules/orchestration/workflows/workflow-replay.ts +254 -254
- package/server/modules/orchestration/workflows/workflow-runner.ts +2070 -2070
- package/server/modules/orchestration/workflows/workflow-store.ts +97 -97
- package/server/modules/orchestration/workflows/workflow-templates.ts +272 -272
- package/server/modules/orchestration/workflows/workflow-trace.ts +424 -424
- package/server/modules/orchestration/workflows/workflow.routes.ts +586 -586
- package/server/modules/orchestration/workflows/workflow.types.ts +111 -111
- package/server/modules/orchestration/workflows/workspace-target.ts +122 -122
- package/server/modules/orchestration/workspace/docker-workspace.ts +136 -136
- package/server/modules/orchestration/workspace/path-safety.ts +55 -55
- package/server/modules/orchestration/workspace/types.ts +52 -52
- package/server/modules/orchestration/workspace/workspace-manager.ts +102 -102
- package/server/modules/orchestration/workspace/worktree-workspace.ts +126 -126
- package/server/modules/providers/index.ts +2 -2
- package/server/modules/providers/list/claude/claude-auth.provider.ts +146 -146
- 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 +117 -117
- 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 +147 -147
- 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 +173 -173
- 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 +131 -131
- package/server/modules/providers/list/opencode/opencode-mcp.provider.ts +126 -126
- package/server/modules/providers/list/opencode/opencode-sessions.provider.ts +286 -286
- package/server/modules/providers/list/opencode/opencode.provider.ts +29 -29
- package/server/modules/providers/list/qwen/qwen-auth.provider.ts +146 -146
- 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 +944 -944
- 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 -462
- package/server/opencode-cli.js +491 -491
- package/server/opencode-response-handler.js +111 -111
- package/server/projects.js +3008 -3008
- package/server/qwen-code-cli.js +410 -410
- package/server/qwen-response-handler.js +73 -73
- package/server/routes/agent.js +1435 -1435
- package/server/routes/auth.js +159 -159
- package/server/routes/codex.js +20 -20
- package/server/routes/commands.js +570 -570
- package/server/routes/cursor.js +61 -61
- package/server/routes/diagnostics.js +41 -41
- package/server/routes/gemini.js +25 -25
- package/server/routes/git.js +1650 -1650
- package/server/routes/live-view.js +411 -411
- package/server/routes/mcp-utils.js +13 -13
- package/server/routes/messages.js +62 -62
- package/server/routes/network.js +125 -125
- package/server/routes/platformization.js +212 -212
- package/server/routes/plugins.js +320 -320
- package/server/routes/production-agent-loop.js +90 -90
- package/server/routes/projects.js +917 -917
- package/server/routes/public-api.js +34 -34
- package/server/routes/qwen.js +27 -27
- package/server/routes/remote.js +55 -55
- package/server/routes/settings.js +321 -321
- package/server/routes/telegram.js +140 -140
- package/server/routes/user.js +125 -125
- package/server/routes/webhooks.js +63 -63
- package/server/services/control-room.js +102 -102
- package/server/services/diagnostics.js +165 -165
- package/server/services/external-access.js +375 -375
- package/server/services/hermes-gateway.js +1562 -1247
- package/server/services/hermes-install-jobs.js +729 -729
- package/server/services/install-jobs.js +715 -715
- package/server/services/live-view.js +956 -956
- package/server/services/managed-runtimes.js +493 -493
- package/server/services/model-registry.js +144 -144
- package/server/services/notification-orchestrator.js +365 -365
- package/server/services/notification-taxonomy.js +204 -204
- package/server/services/platformization.js +815 -815
- package/server/services/production-agent-loop.js +248 -248
- package/server/services/provider-cli-versions.js +149 -149
- package/server/services/provider-credentials.js +189 -189
- package/server/services/provider-models.js +396 -396
- package/server/services/public-api-manifest.js +190 -182
- package/server/services/remote-connection.js +127 -127
- package/server/services/runtime-manager.js +323 -323
- package/server/services/startup-update.js +234 -234
- package/server/services/telegram/bot.js +331 -331
- package/server/services/telegram/control-center.js +979 -979
- package/server/services/telegram/telegram-http-client.js +151 -151
- package/server/services/telegram/translations.js +340 -340
- package/server/services/vapid-keys.js +36 -36
- package/server/services/webhooks.js +216 -216
- 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 +305 -305
- package/server/utils/frontmatter.js +18 -18
- package/server/utils/gitConfig.js +34 -34
- package/server/utils/plugin-loader.js +457 -457
- package/server/utils/plugin-process-manager.js +185 -185
- package/server/utils/port-access.js +209 -209
- package/server/utils/runtime-paths.js +37 -37
- package/server/utils/url-detection.js +71 -71
- package/server/vite-daemon.js +79 -79
- package/shared/modelConstants.js +161 -161
- package/shared/networkHosts.js +22 -22
- package/dist/assets/index-DMz0zv6T.css +0 -32
|
@@ -1,286 +1,286 @@
|
|
|
1
|
-
// server/modules/orchestration/a2a/adapters/claude-code.adapter.ts
|
|
2
|
-
// Wraps the existing server/claude-sdk.js queryClaudeSDK() function.
|
|
3
|
-
// claude-sdk.js was designed to stream SDK messages over a WebSocket
|
|
4
|
-
// connection, so we feed it a "fake WS" that captures send() calls and
|
|
5
|
-
// emits A2A bus events instead.
|
|
6
|
-
//
|
|
7
|
-
// IMPORTANT: claude-sdk.js calls ws.send(<NormalizedMessage object>) — it
|
|
8
|
-
// does NOT JSON.stringify before send. Our shim therefore receives objects
|
|
9
|
-
// (not strings) and dispatches on `frame.kind` (not `frame.type`). See
|
|
10
|
-
// server/shared/types.ts for the MessageKind enum.
|
|
11
|
-
|
|
12
|
-
import crypto from 'node:crypto';
|
|
13
|
-
|
|
14
|
-
// eslint-disable-next-line boundaries/no-unknown -- claude-sdk.js is a top-level CLI runtime not yet classified by eslint.config.js; cleanup deferred (cascades into a server/services classification gap).
|
|
15
|
-
import { abortClaudeSDKSession, queryClaudeSDK } from '@/claude-sdk.js';
|
|
16
|
-
import { AbstractA2AAdapter } from '@/modules/orchestration/a2a/adapters/abstract-a2a.adapter.js';
|
|
17
|
-
import type {
|
|
18
|
-
AdapterContext,
|
|
19
|
-
TaskHandle,
|
|
20
|
-
} from '@/modules/orchestration/a2a/adapters/abstract-a2a.adapter.js';
|
|
21
|
-
import type { AgentCard, Part, Task } from '@/modules/orchestration/a2a/types.js';
|
|
22
|
-
|
|
23
|
-
interface FakeWS {
|
|
24
|
-
send(data: unknown): void;
|
|
25
|
-
readyState: number;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// WebSocket.OPEN per the ws library — claude-sdk.js gates send() on readyState === 1.
|
|
29
|
-
const WS_OPEN = 1;
|
|
30
|
-
|
|
31
|
-
function joinPartsToPrompt(parts: Part[]): string {
|
|
32
|
-
return parts
|
|
33
|
-
.map((p) => {
|
|
34
|
-
if (p.kind === 'text') return p.text;
|
|
35
|
-
if (p.kind === 'data') return JSON.stringify(p.data);
|
|
36
|
-
// file parts: include name + uri/inline marker
|
|
37
|
-
return `[file:${p.name}${p.uri ? ` uri=${p.uri}` : ''}]`;
|
|
38
|
-
})
|
|
39
|
-
.join('\n');
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function newId(prefix: string): string {
|
|
43
|
-
return `${prefix}_${crypto.randomBytes(8).toString('hex')}`;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export class ClaudeCodeA2AAdapter extends AbstractA2AAdapter {
|
|
47
|
-
readonly id = 'claude-code';
|
|
48
|
-
|
|
49
|
-
readonly agentCard: AgentCard = {
|
|
50
|
-
name: 'pixcode-claude-code',
|
|
51
|
-
description: 'Anthropic Claude Code, accessed via Pixcode',
|
|
52
|
-
url: '/hermes/agents/claude-code',
|
|
53
|
-
version: '1.0.0',
|
|
54
|
-
capabilities: ['streaming', 'fileEdit', 'commandExec', 'mcp'],
|
|
55
|
-
skills: [
|
|
56
|
-
{
|
|
57
|
-
id: 'architectural-review',
|
|
58
|
-
description: 'Review code architecture and propose structural changes',
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
id: 'typescript-edit',
|
|
62
|
-
description: 'Edit TypeScript files with type-aware reasoning',
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
id: 'multi-file-refactor',
|
|
66
|
-
description: 'Coordinated edits across many files',
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
id: 'test-run',
|
|
70
|
-
description: 'Run test suites and react to results',
|
|
71
|
-
},
|
|
72
|
-
],
|
|
73
|
-
authentication: { type: 'bearer' },
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
private readonly active = new Map<string, { sessionId: string | null }>();
|
|
77
|
-
|
|
78
|
-
async submitTask(task: Task, ctx: AdapterContext): Promise<TaskHandle> {
|
|
79
|
-
// Foundation: only the last user message is fed in. Multi-turn resumption
|
|
80
|
-
// (input-required tasks, workflow chaining) needs to pass options.sessionId
|
|
81
|
-
// and append history; deferred to a follow-on plan.
|
|
82
|
-
const promptText = joinPartsToPrompt(
|
|
83
|
-
task.history[task.history.length - 1]?.parts ?? [],
|
|
84
|
-
);
|
|
85
|
-
const session = { sessionId: null as string | null };
|
|
86
|
-
this.active.set(task.id, session);
|
|
87
|
-
|
|
88
|
-
this.emitState(task.id, 'working');
|
|
89
|
-
|
|
90
|
-
const fakeWS: FakeWS = {
|
|
91
|
-
readyState: WS_OPEN,
|
|
92
|
-
send: (data) => this.handleSdkFrame(task.id, data, session),
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
const finished = (async () => {
|
|
96
|
-
try {
|
|
97
|
-
await queryClaudeSDK(
|
|
98
|
-
promptText,
|
|
99
|
-
{
|
|
100
|
-
cwd: ctx.cwd,
|
|
101
|
-
permissionMode: ctx.permissionMode ?? 'default',
|
|
102
|
-
permissionPolicy: ctx.permissionPolicy,
|
|
103
|
-
permissionPolicyContext: ctx.permissionPolicyContext,
|
|
104
|
-
toolsSettings: ctx.toolsSettings,
|
|
105
|
-
},
|
|
106
|
-
fakeWS,
|
|
107
|
-
);
|
|
108
|
-
// If cancelTask removed us from `active` first, suppress the spurious
|
|
109
|
-
// 'completed' that would otherwise race the 'canceled' state.
|
|
110
|
-
if (this.active.has(task.id)) {
|
|
111
|
-
this.emitState(task.id, 'completed');
|
|
112
|
-
}
|
|
113
|
-
} catch (err) {
|
|
114
|
-
if (this.active.has(task.id)) {
|
|
115
|
-
this.emitState(task.id, 'failed', {
|
|
116
|
-
code: 'ADAPTER_RUNTIME_ERROR',
|
|
117
|
-
message: err instanceof Error ? err.message : String(err),
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
} finally {
|
|
121
|
-
this.active.delete(task.id);
|
|
122
|
-
}
|
|
123
|
-
})();
|
|
124
|
-
|
|
125
|
-
return {
|
|
126
|
-
cancel: () => this.cancelTask(task.id),
|
|
127
|
-
finished,
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
async cancelTask(taskId: string): Promise<void> {
|
|
132
|
-
const session = this.active.get(taskId);
|
|
133
|
-
if (!session) {
|
|
134
|
-
this.emitState(taskId, 'canceled');
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
// Delete BEFORE awaiting so submitTask's IIFE guard (this.active.has)
|
|
138
|
-
// suppresses the spurious 'completed' state when queryClaudeSDK's
|
|
139
|
-
// for-await loop unwinds from the abort.
|
|
140
|
-
this.active.delete(taskId);
|
|
141
|
-
if (session.sessionId) {
|
|
142
|
-
try {
|
|
143
|
-
await abortClaudeSDKSession(session.sessionId);
|
|
144
|
-
} catch {
|
|
145
|
-
// swallow — adapter has already cleaned its own state
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
this.emitState(taskId, 'canceled');
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* claude-sdk.js calls `ws.send(<NormalizedMessage>)` with a JS OBJECT
|
|
153
|
-
* (not a JSON string). We translate each frame into A2A bus events.
|
|
154
|
-
* See server/shared/types.ts for the MessageKind union.
|
|
155
|
-
*/
|
|
156
|
-
private handleSdkFrame(
|
|
157
|
-
taskId: string,
|
|
158
|
-
frame: unknown,
|
|
159
|
-
session: { sessionId: string | null },
|
|
160
|
-
): void {
|
|
161
|
-
if (!frame || typeof frame !== 'object') return;
|
|
162
|
-
const f = frame as {
|
|
163
|
-
kind?: string;
|
|
164
|
-
sessionId?: unknown;
|
|
165
|
-
newSessionId?: unknown;
|
|
166
|
-
text?: unknown;
|
|
167
|
-
content?: unknown;
|
|
168
|
-
toolName?: unknown;
|
|
169
|
-
toolInput?: unknown;
|
|
170
|
-
toolResult?: unknown;
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
// session_created carries the new session id in `newSessionId`. Capture
|
|
174
|
-
// it here so cancelTask can call abortClaudeSDKSession with the right id.
|
|
175
|
-
if (
|
|
176
|
-
f.kind === 'session_created' &&
|
|
177
|
-
typeof f.newSessionId === 'string' &&
|
|
178
|
-
!session.sessionId
|
|
179
|
-
) {
|
|
180
|
-
session.sessionId = f.newSessionId;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
switch (f.kind) {
|
|
184
|
-
case 'session_created':
|
|
185
|
-
case 'status':
|
|
186
|
-
case 'stream_delta':
|
|
187
|
-
case 'stream_end':
|
|
188
|
-
// session_created and status are not user-facing.
|
|
189
|
-
// stream_delta and stream_end CARRY user-visible delta text but are
|
|
190
|
-
// not currently emitted by claude-sdk.js (it doesn't pass
|
|
191
|
-
// includePartialMessages: true to query()). If that flag flips on
|
|
192
|
-
// upstream, these cases must be re-routed to emit text Messages.
|
|
193
|
-
return;
|
|
194
|
-
|
|
195
|
-
case 'text':
|
|
196
|
-
case 'thinking': {
|
|
197
|
-
const text =
|
|
198
|
-
typeof f.text === 'string'
|
|
199
|
-
? f.text
|
|
200
|
-
: typeof f.content === 'string'
|
|
201
|
-
? f.content
|
|
202
|
-
: null;
|
|
203
|
-
if (text) {
|
|
204
|
-
this.emitMessage(taskId, {
|
|
205
|
-
messageId: newId('msg'),
|
|
206
|
-
role: 'agent',
|
|
207
|
-
parts: [{ kind: 'text', text }],
|
|
208
|
-
taskId,
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
case 'tool_use': {
|
|
215
|
-
this.emitArtifact(taskId, {
|
|
216
|
-
artifactId: newId('art'),
|
|
217
|
-
type: 'command-output',
|
|
218
|
-
parts: [
|
|
219
|
-
{
|
|
220
|
-
kind: 'data',
|
|
221
|
-
data: { toolName: f.toolName, toolInput: f.toolInput },
|
|
222
|
-
},
|
|
223
|
-
],
|
|
224
|
-
metadata: { source: 'claude-tool-use' },
|
|
225
|
-
});
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
case 'tool_result': {
|
|
230
|
-
this.emitArtifact(taskId, {
|
|
231
|
-
artifactId: newId('art'),
|
|
232
|
-
type: 'command-output',
|
|
233
|
-
parts: [{ kind: 'data', data: { toolResult: f.toolResult } }],
|
|
234
|
-
metadata: { source: 'claude-tool-result' },
|
|
235
|
-
});
|
|
236
|
-
return;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
case 'permission_request':
|
|
240
|
-
case 'permission_cancelled':
|
|
241
|
-
case 'interactive_prompt':
|
|
242
|
-
case 'task_notification':
|
|
243
|
-
// Informational — surface as data artifact for visibility.
|
|
244
|
-
this.emitArtifact(taskId, {
|
|
245
|
-
artifactId: newId('art'),
|
|
246
|
-
type: 'data',
|
|
247
|
-
parts: [{ kind: 'data', data: f as Record<string, unknown> }],
|
|
248
|
-
metadata: { source: `claude-${f.kind}` },
|
|
249
|
-
});
|
|
250
|
-
return;
|
|
251
|
-
|
|
252
|
-
case 'error': {
|
|
253
|
-
// claude-sdk.js catches internally and emits an error frame without
|
|
254
|
-
// rethrowing, so the IIFE await would resolve cleanly. Force the
|
|
255
|
-
// failed state here and remove from active so the IIFE's
|
|
256
|
-
// 'completed' emit is suppressed by its active.has() guard.
|
|
257
|
-
const message =
|
|
258
|
-
typeof f.content === 'string'
|
|
259
|
-
? f.content
|
|
260
|
-
: typeof f.text === 'string'
|
|
261
|
-
? f.text
|
|
262
|
-
: 'Claude Code reported an error';
|
|
263
|
-
this.emitState(taskId, 'failed', {
|
|
264
|
-
code: 'CLAUDE_RUNTIME_ERROR',
|
|
265
|
-
message,
|
|
266
|
-
details: f as Record<string, unknown>,
|
|
267
|
-
});
|
|
268
|
-
this.active.delete(taskId);
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
case 'complete':
|
|
273
|
-
// Lifecycle redundant with the IIFE's 'completed' emit; suppress to
|
|
274
|
-
// avoid double-signaling. The IIFE owns terminal state transitions.
|
|
275
|
-
return;
|
|
276
|
-
|
|
277
|
-
default:
|
|
278
|
-
// Unknown kind — surface for visibility
|
|
279
|
-
this.emitArtifact(taskId, {
|
|
280
|
-
artifactId: newId('art'),
|
|
281
|
-
type: 'data',
|
|
282
|
-
parts: [{ kind: 'data', data: f as Record<string, unknown> }],
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
}
|
|
1
|
+
// server/modules/orchestration/a2a/adapters/claude-code.adapter.ts
|
|
2
|
+
// Wraps the existing server/claude-sdk.js queryClaudeSDK() function.
|
|
3
|
+
// claude-sdk.js was designed to stream SDK messages over a WebSocket
|
|
4
|
+
// connection, so we feed it a "fake WS" that captures send() calls and
|
|
5
|
+
// emits A2A bus events instead.
|
|
6
|
+
//
|
|
7
|
+
// IMPORTANT: claude-sdk.js calls ws.send(<NormalizedMessage object>) — it
|
|
8
|
+
// does NOT JSON.stringify before send. Our shim therefore receives objects
|
|
9
|
+
// (not strings) and dispatches on `frame.kind` (not `frame.type`). See
|
|
10
|
+
// server/shared/types.ts for the MessageKind enum.
|
|
11
|
+
|
|
12
|
+
import crypto from 'node:crypto';
|
|
13
|
+
|
|
14
|
+
// eslint-disable-next-line boundaries/no-unknown -- claude-sdk.js is a top-level CLI runtime not yet classified by eslint.config.js; cleanup deferred (cascades into a server/services classification gap).
|
|
15
|
+
import { abortClaudeSDKSession, queryClaudeSDK } from '@/claude-sdk.js';
|
|
16
|
+
import { AbstractA2AAdapter } from '@/modules/orchestration/a2a/adapters/abstract-a2a.adapter.js';
|
|
17
|
+
import type {
|
|
18
|
+
AdapterContext,
|
|
19
|
+
TaskHandle,
|
|
20
|
+
} from '@/modules/orchestration/a2a/adapters/abstract-a2a.adapter.js';
|
|
21
|
+
import type { AgentCard, Part, Task } from '@/modules/orchestration/a2a/types.js';
|
|
22
|
+
|
|
23
|
+
interface FakeWS {
|
|
24
|
+
send(data: unknown): void;
|
|
25
|
+
readyState: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// WebSocket.OPEN per the ws library — claude-sdk.js gates send() on readyState === 1.
|
|
29
|
+
const WS_OPEN = 1;
|
|
30
|
+
|
|
31
|
+
function joinPartsToPrompt(parts: Part[]): string {
|
|
32
|
+
return parts
|
|
33
|
+
.map((p) => {
|
|
34
|
+
if (p.kind === 'text') return p.text;
|
|
35
|
+
if (p.kind === 'data') return JSON.stringify(p.data);
|
|
36
|
+
// file parts: include name + uri/inline marker
|
|
37
|
+
return `[file:${p.name}${p.uri ? ` uri=${p.uri}` : ''}]`;
|
|
38
|
+
})
|
|
39
|
+
.join('\n');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function newId(prefix: string): string {
|
|
43
|
+
return `${prefix}_${crypto.randomBytes(8).toString('hex')}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export class ClaudeCodeA2AAdapter extends AbstractA2AAdapter {
|
|
47
|
+
readonly id = 'claude-code';
|
|
48
|
+
|
|
49
|
+
readonly agentCard: AgentCard = {
|
|
50
|
+
name: 'pixcode-claude-code',
|
|
51
|
+
description: 'Anthropic Claude Code, accessed via Pixcode',
|
|
52
|
+
url: '/hermes/agents/claude-code',
|
|
53
|
+
version: '1.0.0',
|
|
54
|
+
capabilities: ['streaming', 'fileEdit', 'commandExec', 'mcp'],
|
|
55
|
+
skills: [
|
|
56
|
+
{
|
|
57
|
+
id: 'architectural-review',
|
|
58
|
+
description: 'Review code architecture and propose structural changes',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
id: 'typescript-edit',
|
|
62
|
+
description: 'Edit TypeScript files with type-aware reasoning',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: 'multi-file-refactor',
|
|
66
|
+
description: 'Coordinated edits across many files',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
id: 'test-run',
|
|
70
|
+
description: 'Run test suites and react to results',
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
authentication: { type: 'bearer' },
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
private readonly active = new Map<string, { sessionId: string | null }>();
|
|
77
|
+
|
|
78
|
+
async submitTask(task: Task, ctx: AdapterContext): Promise<TaskHandle> {
|
|
79
|
+
// Foundation: only the last user message is fed in. Multi-turn resumption
|
|
80
|
+
// (input-required tasks, workflow chaining) needs to pass options.sessionId
|
|
81
|
+
// and append history; deferred to a follow-on plan.
|
|
82
|
+
const promptText = joinPartsToPrompt(
|
|
83
|
+
task.history[task.history.length - 1]?.parts ?? [],
|
|
84
|
+
);
|
|
85
|
+
const session = { sessionId: null as string | null };
|
|
86
|
+
this.active.set(task.id, session);
|
|
87
|
+
|
|
88
|
+
this.emitState(task.id, 'working');
|
|
89
|
+
|
|
90
|
+
const fakeWS: FakeWS = {
|
|
91
|
+
readyState: WS_OPEN,
|
|
92
|
+
send: (data) => this.handleSdkFrame(task.id, data, session),
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const finished = (async () => {
|
|
96
|
+
try {
|
|
97
|
+
await queryClaudeSDK(
|
|
98
|
+
promptText,
|
|
99
|
+
{
|
|
100
|
+
cwd: ctx.cwd,
|
|
101
|
+
permissionMode: ctx.permissionMode ?? 'default',
|
|
102
|
+
permissionPolicy: ctx.permissionPolicy,
|
|
103
|
+
permissionPolicyContext: ctx.permissionPolicyContext,
|
|
104
|
+
toolsSettings: ctx.toolsSettings,
|
|
105
|
+
},
|
|
106
|
+
fakeWS,
|
|
107
|
+
);
|
|
108
|
+
// If cancelTask removed us from `active` first, suppress the spurious
|
|
109
|
+
// 'completed' that would otherwise race the 'canceled' state.
|
|
110
|
+
if (this.active.has(task.id)) {
|
|
111
|
+
this.emitState(task.id, 'completed');
|
|
112
|
+
}
|
|
113
|
+
} catch (err) {
|
|
114
|
+
if (this.active.has(task.id)) {
|
|
115
|
+
this.emitState(task.id, 'failed', {
|
|
116
|
+
code: 'ADAPTER_RUNTIME_ERROR',
|
|
117
|
+
message: err instanceof Error ? err.message : String(err),
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
} finally {
|
|
121
|
+
this.active.delete(task.id);
|
|
122
|
+
}
|
|
123
|
+
})();
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
cancel: () => this.cancelTask(task.id),
|
|
127
|
+
finished,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async cancelTask(taskId: string): Promise<void> {
|
|
132
|
+
const session = this.active.get(taskId);
|
|
133
|
+
if (!session) {
|
|
134
|
+
this.emitState(taskId, 'canceled');
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
// Delete BEFORE awaiting so submitTask's IIFE guard (this.active.has)
|
|
138
|
+
// suppresses the spurious 'completed' state when queryClaudeSDK's
|
|
139
|
+
// for-await loop unwinds from the abort.
|
|
140
|
+
this.active.delete(taskId);
|
|
141
|
+
if (session.sessionId) {
|
|
142
|
+
try {
|
|
143
|
+
await abortClaudeSDKSession(session.sessionId);
|
|
144
|
+
} catch {
|
|
145
|
+
// swallow — adapter has already cleaned its own state
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
this.emitState(taskId, 'canceled');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* claude-sdk.js calls `ws.send(<NormalizedMessage>)` with a JS OBJECT
|
|
153
|
+
* (not a JSON string). We translate each frame into A2A bus events.
|
|
154
|
+
* See server/shared/types.ts for the MessageKind union.
|
|
155
|
+
*/
|
|
156
|
+
private handleSdkFrame(
|
|
157
|
+
taskId: string,
|
|
158
|
+
frame: unknown,
|
|
159
|
+
session: { sessionId: string | null },
|
|
160
|
+
): void {
|
|
161
|
+
if (!frame || typeof frame !== 'object') return;
|
|
162
|
+
const f = frame as {
|
|
163
|
+
kind?: string;
|
|
164
|
+
sessionId?: unknown;
|
|
165
|
+
newSessionId?: unknown;
|
|
166
|
+
text?: unknown;
|
|
167
|
+
content?: unknown;
|
|
168
|
+
toolName?: unknown;
|
|
169
|
+
toolInput?: unknown;
|
|
170
|
+
toolResult?: unknown;
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// session_created carries the new session id in `newSessionId`. Capture
|
|
174
|
+
// it here so cancelTask can call abortClaudeSDKSession with the right id.
|
|
175
|
+
if (
|
|
176
|
+
f.kind === 'session_created' &&
|
|
177
|
+
typeof f.newSessionId === 'string' &&
|
|
178
|
+
!session.sessionId
|
|
179
|
+
) {
|
|
180
|
+
session.sessionId = f.newSessionId;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
switch (f.kind) {
|
|
184
|
+
case 'session_created':
|
|
185
|
+
case 'status':
|
|
186
|
+
case 'stream_delta':
|
|
187
|
+
case 'stream_end':
|
|
188
|
+
// session_created and status are not user-facing.
|
|
189
|
+
// stream_delta and stream_end CARRY user-visible delta text but are
|
|
190
|
+
// not currently emitted by claude-sdk.js (it doesn't pass
|
|
191
|
+
// includePartialMessages: true to query()). If that flag flips on
|
|
192
|
+
// upstream, these cases must be re-routed to emit text Messages.
|
|
193
|
+
return;
|
|
194
|
+
|
|
195
|
+
case 'text':
|
|
196
|
+
case 'thinking': {
|
|
197
|
+
const text =
|
|
198
|
+
typeof f.text === 'string'
|
|
199
|
+
? f.text
|
|
200
|
+
: typeof f.content === 'string'
|
|
201
|
+
? f.content
|
|
202
|
+
: null;
|
|
203
|
+
if (text) {
|
|
204
|
+
this.emitMessage(taskId, {
|
|
205
|
+
messageId: newId('msg'),
|
|
206
|
+
role: 'agent',
|
|
207
|
+
parts: [{ kind: 'text', text }],
|
|
208
|
+
taskId,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
case 'tool_use': {
|
|
215
|
+
this.emitArtifact(taskId, {
|
|
216
|
+
artifactId: newId('art'),
|
|
217
|
+
type: 'command-output',
|
|
218
|
+
parts: [
|
|
219
|
+
{
|
|
220
|
+
kind: 'data',
|
|
221
|
+
data: { toolName: f.toolName, toolInput: f.toolInput },
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
metadata: { source: 'claude-tool-use' },
|
|
225
|
+
});
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
case 'tool_result': {
|
|
230
|
+
this.emitArtifact(taskId, {
|
|
231
|
+
artifactId: newId('art'),
|
|
232
|
+
type: 'command-output',
|
|
233
|
+
parts: [{ kind: 'data', data: { toolResult: f.toolResult } }],
|
|
234
|
+
metadata: { source: 'claude-tool-result' },
|
|
235
|
+
});
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
case 'permission_request':
|
|
240
|
+
case 'permission_cancelled':
|
|
241
|
+
case 'interactive_prompt':
|
|
242
|
+
case 'task_notification':
|
|
243
|
+
// Informational — surface as data artifact for visibility.
|
|
244
|
+
this.emitArtifact(taskId, {
|
|
245
|
+
artifactId: newId('art'),
|
|
246
|
+
type: 'data',
|
|
247
|
+
parts: [{ kind: 'data', data: f as Record<string, unknown> }],
|
|
248
|
+
metadata: { source: `claude-${f.kind}` },
|
|
249
|
+
});
|
|
250
|
+
return;
|
|
251
|
+
|
|
252
|
+
case 'error': {
|
|
253
|
+
// claude-sdk.js catches internally and emits an error frame without
|
|
254
|
+
// rethrowing, so the IIFE await would resolve cleanly. Force the
|
|
255
|
+
// failed state here and remove from active so the IIFE's
|
|
256
|
+
// 'completed' emit is suppressed by its active.has() guard.
|
|
257
|
+
const message =
|
|
258
|
+
typeof f.content === 'string'
|
|
259
|
+
? f.content
|
|
260
|
+
: typeof f.text === 'string'
|
|
261
|
+
? f.text
|
|
262
|
+
: 'Claude Code reported an error';
|
|
263
|
+
this.emitState(taskId, 'failed', {
|
|
264
|
+
code: 'CLAUDE_RUNTIME_ERROR',
|
|
265
|
+
message,
|
|
266
|
+
details: f as Record<string, unknown>,
|
|
267
|
+
});
|
|
268
|
+
this.active.delete(taskId);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
case 'complete':
|
|
273
|
+
// Lifecycle redundant with the IIFE's 'completed' emit; suppress to
|
|
274
|
+
// avoid double-signaling. The IIFE owns terminal state transitions.
|
|
275
|
+
return;
|
|
276
|
+
|
|
277
|
+
default:
|
|
278
|
+
// Unknown kind — surface for visibility
|
|
279
|
+
this.emitArtifact(taskId, {
|
|
280
|
+
artifactId: newId('art'),
|
|
281
|
+
type: 'data',
|
|
282
|
+
parts: [{ kind: 'data', data: f as Record<string, unknown> }],
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|