@gajae-code/coding-agent 0.10.2 → 0.11.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/CHANGELOG.md +58 -2
- package/dist/types/append-only-mode.d.ts +1 -1
- package/dist/types/async/job-manager.d.ts +46 -7
- package/dist/types/cli/args.d.ts +4 -5
- package/dist/types/cli/daemon-cli.d.ts +12 -1
- package/dist/types/cli/notify-cli.d.ts +21 -1
- package/dist/types/cli.d.ts +3 -0
- package/dist/types/commands/daemon.d.ts +39 -0
- package/dist/types/commands/launch.d.ts +3 -0
- package/dist/types/commands/notify.d.ts +28 -1
- package/dist/types/commands/sdk.d.ts +33 -0
- package/dist/types/config/atomic-yaml-patch.d.ts +85 -0
- package/dist/types/config/model-profile-activation.d.ts +35 -15
- package/dist/types/config/model-profiles.d.ts +11 -5
- package/dist/types/config/model-registry.d.ts +3 -3
- package/dist/types/config/model-resolver.d.ts +39 -6
- package/dist/types/config/model-selector-value.d.ts +17 -0
- package/dist/types/config/models-config-schema.d.ts +10 -6
- package/dist/types/config/settings-schema.d.ts +133 -6
- package/dist/types/config/settings.d.ts +63 -35
- package/dist/types/coordinator-mcp/model-preset.d.ts +7 -6
- package/dist/types/coordinator-mcp/server.d.ts +6 -49
- package/dist/types/daemon/builtin.d.ts +6 -5
- package/dist/types/daemon/control-types.d.ts +1 -1
- package/dist/types/discovery/mcp-json.d.ts +12 -1
- package/dist/types/extensibility/custom-tools/types.d.ts +1 -1
- package/dist/types/extensibility/extensions/compact-handler.d.ts +4 -2
- package/dist/types/extensibility/extensions/get-commands-handler.d.ts +2 -2
- package/dist/types/extensibility/extensions/loader.d.ts +10 -1
- package/dist/types/extensibility/extensions/runner.d.ts +3 -3
- package/dist/types/extensibility/extensions/types.d.ts +141 -16
- package/dist/types/extensibility/hooks/types.d.ts +1 -1
- package/dist/types/gjc-runtime/launch-tmux.d.ts +3 -2
- package/dist/types/gjc-runtime/psmux-detect.d.ts +3 -0
- package/dist/types/gjc-runtime/session-state-sidecar.d.ts +3 -0
- package/dist/types/gjc-runtime/team-runtime.d.ts +3 -4
- package/dist/types/gjc-runtime/tmux-owner-isolation-cli.d.ts +13 -0
- package/dist/types/gjc-runtime/tmux-sessions.d.ts +4 -1
- package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +11 -0
- package/dist/types/gjc-runtime/windows-powershell-command.d.ts +9 -0
- package/dist/types/harness-control-plane/operate.d.ts +5 -5
- package/dist/types/harness-control-plane/owner.d.ts +18 -4
- package/dist/types/harness-control-plane/receipts.d.ts +0 -1
- package/dist/types/harness-control-plane/sdk-transport.d.ts +43 -0
- package/dist/types/harness-control-plane/session-transport.d.ts +48 -0
- package/dist/types/harness-control-plane/types.d.ts +3 -4
- package/dist/types/lsp/index.d.ts +1 -1
- package/dist/types/main.d.ts +32 -38
- package/dist/types/modes/acp/acp-agent.d.ts +224 -53
- package/dist/types/modes/acp/acp-client-bridge.d.ts +1 -0
- package/dist/types/modes/acp/acp-mode.d.ts +6 -15
- package/dist/types/modes/acp/permission-mode.d.ts +4 -0
- package/dist/types/modes/acp/startup-options.d.ts +6 -0
- package/dist/types/modes/components/agent-dashboard.d.ts +3 -0
- package/dist/types/modes/components/model-selector.d.ts +1 -0
- package/dist/types/modes/components/notifications-settings-editor.d.ts +135 -0
- package/dist/types/modes/components/settings-selector.d.ts +6 -4
- package/dist/types/modes/components/welcome.d.ts +1 -1
- package/dist/types/modes/controllers/command-controller.d.ts +2 -2
- package/dist/types/modes/controllers/extension-ui-controller.d.ts +1 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +35 -1
- package/dist/types/modes/index.d.ts +0 -4
- package/dist/types/modes/interactive-mode.d.ts +5 -2
- package/dist/types/modes/runtime-init.d.ts +2 -2
- package/dist/types/modes/shared/agent-wire/approval-gate.d.ts +6 -9
- package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +4 -6
- package/dist/types/modes/shared/agent-wire/event-contract.d.ts +6 -6
- package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +4 -9
- package/dist/types/modes/shared/agent-wire/event-observation.d.ts +1 -1
- package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +170 -30
- package/dist/types/modes/shared/agent-wire/workflow-gate-schema.d.ts +7 -7
- package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +105 -0
- package/dist/types/modes/types.d.ts +7 -2
- package/dist/types/runtime-mcp/client.d.ts +2 -0
- package/dist/types/runtime-mcp/config.d.ts +5 -1
- package/dist/types/runtime-mcp/manager.d.ts +8 -1
- package/dist/types/runtime-mcp/types.d.ts +4 -0
- package/dist/types/sdk/acp/adapter.d.ts +67 -0
- package/dist/types/sdk/acp/index.d.ts +2 -0
- package/dist/types/sdk/broker/broker.d.ts +53 -0
- package/dist/types/sdk/broker/discovery.d.ts +30 -0
- package/dist/types/sdk/broker/ensure.d.ts +42 -0
- package/dist/types/sdk/broker/identity.d.ts +3 -0
- package/dist/types/sdk/broker/index.d.ts +8 -0
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +95 -0
- package/dist/types/sdk/broker/lifecycle.d.ts +85 -0
- package/dist/types/sdk/broker/process-incarnation.d.ts +14 -0
- package/dist/types/sdk/broker/runtime.d.ts +33 -0
- package/dist/types/sdk/broker/session-index.d.ts +57 -0
- package/dist/types/sdk/broker/state-version.d.ts +8 -0
- package/dist/types/sdk/broker/transport.d.ts +9 -0
- package/dist/types/sdk/bus/chat-command-policy.d.ts +49 -0
- package/dist/types/sdk/bus/chat-daemon-cli.d.ts +21 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +111 -0
- package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +77 -0
- package/dist/types/sdk/bus/chat-effect-journal.d.ts +84 -0
- package/dist/types/{notifications → sdk/bus}/config-commands.d.ts +7 -2
- package/dist/types/sdk/bus/config.d.ts +274 -0
- package/dist/types/sdk/bus/conversation-store.d.ts +72 -0
- package/dist/types/sdk/bus/discord-conversation.d.ts +58 -0
- package/dist/types/sdk/bus/discord-daemon.d.ts +50 -0
- package/dist/types/sdk/bus/discord-live-provider.d.ts +70 -0
- package/dist/types/sdk/bus/discord-provider.d.ts +85 -0
- package/dist/types/{notifications → sdk/bus}/html-format.d.ts +2 -2
- package/dist/types/{notifications → sdk/bus}/index.d.ts +113 -13
- package/dist/types/{notifications → sdk/bus}/lifecycle-control-runtime.d.ts +4 -2
- package/dist/types/{notifications → sdk/bus}/lifecycle-orchestrator.d.ts +18 -21
- package/dist/types/{notifications → sdk/bus}/managed-daemon.d.ts +1 -1
- package/dist/types/sdk/bus/native-runtime-compatibility.d.ts +13 -0
- package/dist/types/sdk/bus/notification-orchestration.d.ts +170 -0
- package/dist/types/{notifications → sdk/bus}/notification-service.d.ts +7 -1
- package/dist/types/sdk/bus/session-control.d.ts +83 -0
- package/dist/types/sdk/bus/slack-conversation.d.ts +56 -0
- package/dist/types/sdk/bus/slack-daemon.d.ts +60 -0
- package/dist/types/sdk/bus/slack-live-provider.d.ts +59 -0
- package/dist/types/sdk/bus/slack-provider.d.ts +55 -0
- package/dist/types/{notifications → sdk/bus}/telegram-cli.d.ts +4 -4
- package/dist/types/{notifications → sdk/bus}/telegram-daemon-cli.d.ts +14 -5
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +12 -0
- package/dist/types/{notifications → sdk/bus}/telegram-daemon-control.d.ts +2 -2
- package/dist/types/{notifications → sdk/bus}/telegram-daemon.d.ts +78 -17
- package/dist/types/{notifications → sdk/bus}/telegram-reference.d.ts +2 -2
- package/dist/types/sdk/bus/telegram-setup.d.ts +128 -0
- package/dist/types/{notifications → sdk/bus}/topic-registry.d.ts +11 -0
- package/dist/types/sdk/cli/index.d.ts +1 -0
- package/dist/types/sdk/cli/session-cli.d.ts +19 -0
- package/dist/types/sdk/client/client.d.ts +1 -0
- package/dist/types/sdk/client/discovery.d.ts +27 -0
- package/dist/types/sdk/client/index.d.ts +2 -0
- package/dist/types/sdk/host/control/dispatch.d.ts +34 -0
- package/dist/types/sdk/host/control/index.d.ts +2 -0
- package/dist/types/sdk/host/control/operations.d.ts +65 -0
- package/dist/types/sdk/host/events.d.ts +35 -0
- package/dist/types/sdk/host/host.d.ts +35 -0
- package/dist/types/sdk/host/index.d.ts +4 -0
- package/dist/types/sdk/host/query/cursor.d.ts +62 -0
- package/dist/types/sdk/host/query/handlers.d.ts +70 -0
- package/dist/types/sdk/host/query/index.d.ts +3 -0
- package/dist/types/sdk/host/query/revision-store.d.ts +60 -0
- package/dist/types/sdk/host/reverse-leases.d.ts +45 -0
- package/dist/types/sdk/host/types.d.ts +32 -0
- package/dist/types/sdk/index.d.ts +6 -0
- package/dist/types/sdk/lifecycle-session.d.ts +14 -0
- package/dist/types/sdk/mcp/index.d.ts +1 -0
- package/dist/types/sdk/mcp/server.d.ts +37 -0
- package/dist/types/sdk/models.d.ts +44 -0
- package/dist/types/sdk/protocol/adapter-validation.d.ts +14 -0
- package/dist/types/sdk/protocol/operation-registry.d.ts +24 -0
- package/dist/types/{sdk.d.ts → sdk/session.d.ts} +44 -38
- package/dist/types/sdk/startup-capability.d.ts +50 -0
- package/dist/types/session/agent-session.d.ts +114 -21
- package/dist/types/session/default-model-selection.d.ts +25 -0
- package/dist/types/session/fallback-chain-controller.d.ts +52 -0
- package/dist/types/session/session-manager.d.ts +58 -1
- package/dist/types/setup/credential-auto-import.d.ts +36 -6
- package/dist/types/tools/ask-answer-registry.d.ts +1 -1
- package/dist/types/tools/browser/benchmark/detector-report.d.ts +63 -0
- package/dist/types/tools/browser/benchmark/run-suite.d.ts +18 -0
- package/dist/types/tools/browser/launch.d.ts +22 -0
- package/dist/types/tools/browser/profile-discovery.d.ts +31 -0
- package/dist/types/tools/browser/profile-posture.d.ts +37 -0
- package/dist/types/tools/browser/profile-reuse.d.ts +39 -0
- package/dist/types/tools/browser/profile-warmup.d.ts +39 -0
- package/dist/types/tools/browser/registry.d.ts +19 -0
- package/dist/types/tools/browser/tab-protocol.d.ts +4 -0
- package/dist/types/tools/index.d.ts +8 -8
- package/dist/types/tools/subagent-render.d.ts +1 -0
- package/dist/types/tools/subagent.d.ts +6 -1
- package/package.json +34 -13
- package/scripts/build-sdk-package-smoke.ts +99 -0
- package/scripts/capture-notifications-settings-showcase.ts +435 -0
- package/scripts/compile-args.ts +4 -2
- package/scripts/g005-daemon-smoke.ts +4 -5
- package/scripts/g011-daemon-path-smoke.ts +5 -5
- package/scripts/generate-sdk-adapter-parity-manifest.ts +163 -0
- package/scripts/generate-sdk-operation-inventory.ts +867 -0
- package/scripts/generate-telegram-baseline-manifest.ts +128 -0
- package/scripts/manifest-schema.ts +124 -0
- package/scripts/run-test-manifest.ts +153 -0
- package/scripts/run-threat-model-check.ts +157 -0
- package/scripts/verify-gjc-sdk-canonicalization.ts +3467 -0
- package/scripts/verify-gjc-sdk-rename.ts +90 -0
- package/src/append-only-mode.ts +1 -1
- package/src/async/job-manager.ts +406 -63
- package/src/cli/args.ts +43 -12
- package/src/cli/auth-gateway-cli.ts +2 -2
- package/src/cli/config-cli.ts +2 -1
- package/src/cli/daemon-cli.ts +63 -14
- package/src/cli/list-models.ts +1 -1
- package/src/cli/notify-cli.ts +288 -286
- package/src/cli.ts +21 -2
- package/src/commands/daemon.ts +50 -6
- package/src/commands/harness.ts +93 -36
- package/src/commands/launch.ts +5 -2
- package/src/commands/mcp-serve.ts +19 -12
- package/src/commands/notify.ts +36 -3
- package/src/commands/sdk.ts +426 -0
- package/src/commit/agentic/agent.ts +1 -0
- package/src/config/atomic-yaml-patch.ts +423 -0
- package/src/config/model-profile-activation.ts +240 -89
- package/src/config/model-profiles.ts +18 -15
- package/src/config/model-registry.ts +51 -26
- package/src/config/model-resolver.ts +138 -51
- package/src/config/model-selector-value.ts +50 -0
- package/src/config/models-config-schema.ts +14 -21
- package/src/config/settings-schema.ts +128 -10
- package/src/config/settings.ts +1120 -158
- package/src/coordinator-mcp/model-preset.ts +74 -20
- package/src/coordinator-mcp/server.ts +1597 -3052
- package/src/daemon/builtin.ts +8 -5
- package/src/daemon/control-types.ts +1 -1
- package/src/defaults/gjc/skills/team/SKILL.md +4 -4
- package/src/discovery/mcp-json.ts +327 -20
- package/src/extensibility/custom-tools/types.ts +1 -1
- package/src/extensibility/extensions/compact-handler.ts +3 -3
- package/src/extensibility/extensions/get-commands-handler.ts +2 -2
- package/src/extensibility/extensions/loader.ts +69 -5
- package/src/extensibility/extensions/runner.ts +112 -4
- package/src/extensibility/extensions/types.ts +176 -17
- package/src/extensibility/hooks/types.ts +1 -1
- package/src/gjc-runtime/launch-tmux.ts +170 -86
- package/src/gjc-runtime/psmux-detect.ts +82 -4
- package/src/gjc-runtime/session-state-sidecar.ts +41 -31
- package/src/gjc-runtime/team-runtime.ts +54 -35
- package/src/gjc-runtime/tmux-owner-isolation-cli.ts +53 -17
- package/src/gjc-runtime/tmux-owner-isolation.ts +1 -1
- package/src/gjc-runtime/tmux-sessions.ts +19 -13
- package/src/gjc-runtime/ultragoal-guard.ts +108 -14
- package/src/gjc-runtime/ultragoal-receipt-freshness.ts +102 -1
- package/src/gjc-runtime/ultragoal-runtime.ts +227 -11
- package/src/gjc-runtime/windows-powershell-command.ts +58 -0
- package/src/harness-control-plane/operate.ts +9 -9
- package/src/harness-control-plane/owner.ts +283 -39
- package/src/harness-control-plane/receipts.ts +0 -1
- package/src/harness-control-plane/sdk-transport.ts +395 -0
- package/src/harness-control-plane/session-transport.ts +94 -0
- package/src/harness-control-plane/types.ts +1 -1
- package/src/internal-urls/docs-index.generated.ts +34 -35
- package/src/lsp/client.ts +42 -6
- package/src/lsp/index.ts +2 -2
- package/src/main.ts +299 -204
- package/src/modes/DESIGN.md +258 -0
- package/src/modes/acp/acp-agent.ts +1228 -2612
- package/src/modes/acp/acp-client-bridge.ts +2 -20
- package/src/modes/acp/acp-event-mapper.ts +18 -2
- package/src/modes/acp/acp-mode.ts +8 -36
- package/src/modes/acp/permission-mode.ts +25 -0
- package/src/modes/acp/startup-options.ts +6 -0
- package/src/modes/components/agent-dashboard.ts +37 -17
- package/src/modes/components/model-selector.ts +93 -35
- package/src/modes/components/notifications-settings-editor.ts +1379 -0
- package/src/modes/components/settings-selector.ts +60 -11
- package/src/modes/components/welcome.ts +4 -4
- package/src/modes/controllers/command-controller.ts +10 -17
- package/src/modes/controllers/event-controller.ts +11 -16
- package/src/modes/controllers/extension-ui-controller.ts +396 -28
- package/src/modes/controllers/selector-controller.ts +674 -36
- package/src/modes/index.ts +0 -22
- package/src/modes/interactive-mode.ts +87 -36
- package/src/modes/runtime-init.ts +298 -6
- package/src/modes/shared/agent-wire/approval-gate.ts +9 -11
- package/src/modes/shared/agent-wire/deep-interview-gate.ts +10 -11
- package/src/modes/shared/agent-wire/event-contract.ts +7 -8
- package/src/modes/shared/agent-wire/event-envelope.ts +9 -17
- package/src/modes/shared/agent-wire/event-observation.ts +16 -7
- package/src/modes/shared/agent-wire/workflow-gate-broker.ts +1258 -87
- package/src/modes/shared/agent-wire/workflow-gate-schema.ts +15 -15
- package/src/modes/shared/agent-wire/workflow-gate-types.ts +113 -0
- package/src/modes/types.ts +7 -2
- package/src/runtime-mcp/client.ts +94 -19
- package/src/runtime-mcp/config.ts +27 -15
- package/src/runtime-mcp/manager.ts +343 -105
- package/src/runtime-mcp/oauth-flow.ts +42 -12
- package/src/runtime-mcp/transports/http.ts +49 -19
- package/src/runtime-mcp/transports/stdio.ts +47 -28
- package/src/runtime-mcp/types.ts +10 -0
- package/src/sdk/acp/adapter.ts +418 -0
- package/src/sdk/acp/index.ts +2 -0
- package/src/sdk/broker/broker.ts +642 -0
- package/src/sdk/broker/discovery.ts +113 -0
- package/src/sdk/broker/ensure.ts +307 -0
- package/src/sdk/broker/identity.ts +42 -0
- package/src/sdk/broker/index.ts +8 -0
- package/src/sdk/broker/internal-source-marker-2178.txt +1 -0
- package/src/sdk/broker/internal-source.bunfig.toml +1 -0
- package/src/sdk/broker/lifecycle-ledger.ts +286 -0
- package/src/sdk/broker/lifecycle.ts +2157 -0
- package/src/sdk/broker/process-incarnation.ts +159 -0
- package/src/sdk/broker/runtime.ts +164 -0
- package/src/sdk/broker/session-index.ts +318 -0
- package/src/sdk/broker/state-version.ts +23 -0
- package/src/sdk/broker/transport.ts +125 -0
- package/src/sdk/bus/chat-command-policy.ts +107 -0
- package/src/sdk/bus/chat-daemon-cli.ts +214 -0
- package/src/sdk/bus/chat-daemon-control.ts +713 -0
- package/src/sdk/bus/chat-daemon-runtime.ts +526 -0
- package/src/sdk/bus/chat-effect-journal.ts +355 -0
- package/src/{notifications → sdk/bus}/config-commands.ts +39 -10
- package/src/sdk/bus/config.ts +433 -0
- package/src/sdk/bus/conversation-store.ts +391 -0
- package/src/sdk/bus/discord-conversation.ts +85 -0
- package/src/sdk/bus/discord-daemon.ts +2292 -0
- package/src/sdk/bus/discord-live-provider.ts +521 -0
- package/src/sdk/bus/discord-provider.ts +56 -0
- package/src/{notifications → sdk/bus}/html-format.ts +2 -2
- package/src/sdk/bus/index.ts +3979 -0
- package/src/{notifications → sdk/bus}/lifecycle-commands.ts +2 -0
- package/src/{notifications → sdk/bus}/lifecycle-control-runtime.ts +225 -196
- package/src/{notifications → sdk/bus}/lifecycle-orchestrator.ts +161 -74
- package/src/{notifications → sdk/bus}/managed-daemon.ts +2 -2
- package/src/sdk/bus/native-runtime-compatibility.ts +42 -0
- package/src/sdk/bus/natives-augment.d.ts +38 -0
- package/src/sdk/bus/notification-orchestration.ts +535 -0
- package/src/{notifications → sdk/bus}/notification-service.ts +106 -12
- package/src/sdk/bus/session-control.ts +333 -0
- package/src/sdk/bus/slack-conversation.ts +74 -0
- package/src/sdk/bus/slack-daemon.ts +2144 -0
- package/src/sdk/bus/slack-live-provider.ts +380 -0
- package/src/sdk/bus/slack-provider.ts +76 -0
- package/src/{notifications → sdk/bus}/telegram-cli.ts +8 -8
- package/src/sdk/bus/telegram-daemon-cli.ts +330 -0
- package/src/sdk/bus/telegram-daemon-contract.ts +14 -0
- package/src/{notifications → sdk/bus}/telegram-daemon-control.ts +4 -4
- package/src/{notifications → sdk/bus}/telegram-daemon.ts +603 -63
- package/src/{notifications → sdk/bus}/telegram-reference.ts +2 -2
- package/src/sdk/bus/telegram-setup.ts +663 -0
- package/src/{notifications → sdk/bus}/topic-registry.ts +32 -0
- package/src/sdk/cli/index.ts +1 -0
- package/src/sdk/cli/session-cli.ts +275 -0
- package/src/sdk/client/client.ts +1 -0
- package/src/sdk/client/discovery.ts +108 -0
- package/src/sdk/client/index.ts +2 -0
- package/src/sdk/host/control/dispatch.ts +367 -0
- package/src/sdk/host/control/index.ts +10 -0
- package/src/sdk/host/control/operations.ts +63 -0
- package/src/sdk/host/events.ts +91 -0
- package/src/sdk/host/host.ts +296 -0
- package/src/sdk/host/index.ts +4 -0
- package/src/sdk/host/query/cursor.ts +189 -0
- package/src/sdk/host/query/handlers.ts +533 -0
- package/src/sdk/host/query/index.ts +3 -0
- package/src/sdk/host/query/revision-store.ts +1126 -0
- package/src/sdk/host/reverse-leases.ts +325 -0
- package/src/sdk/host/types.ts +29 -0
- package/src/sdk/index.ts +13 -0
- package/src/sdk/lifecycle-session.ts +39 -0
- package/src/sdk/mcp/index.ts +1 -0
- package/src/sdk/mcp/server.ts +332 -0
- package/src/sdk/models.ts +168 -0
- package/src/sdk/protocol/adapter-validation.ts +48 -0
- package/src/sdk/protocol/operation-inventory.generated.json +5654 -0
- package/src/sdk/protocol/operation-registry.ts +312 -0
- package/src/{sdk.ts → sdk/session.ts} +339 -212
- package/src/sdk/startup-capability.ts +189 -0
- package/src/session/agent-session.ts +2650 -944
- package/src/session/default-model-selection.ts +93 -0
- package/src/session/fallback-chain-controller.ts +136 -0
- package/src/session/session-manager.ts +438 -11
- package/src/session/session-storage.ts +8 -1
- package/src/setup/credential-auto-import.ts +290 -35
- package/src/setup/hermes/templates/operator-instructions.v1.md +3 -5
- package/src/slash-commands/builtin-registry.ts +2 -1
- package/src/task/executor.ts +62 -13
- package/src/task/index.ts +26 -16
- package/src/tools/ask-answer-registry.ts +1 -1
- package/src/tools/ask.ts +13 -8
- package/src/tools/browser/STEALTH-THIRD-PARTY-NOTICES.md +26 -0
- package/src/tools/browser/benchmark/detector-report.ts +157 -0
- package/src/tools/browser/benchmark/run-suite.ts +39 -0
- package/src/tools/browser/launch.ts +124 -19
- package/src/tools/browser/profile-discovery.ts +63 -0
- package/src/tools/browser/profile-posture.ts +59 -0
- package/src/tools/browser/profile-reuse.ts +102 -0
- package/src/tools/browser/profile-warmup.ts +109 -0
- package/src/tools/browser/registry.ts +87 -11
- package/src/tools/browser/tab-protocol.ts +1 -0
- package/src/tools/browser/tab-supervisor.ts +1 -0
- package/src/tools/browser/tab-worker.ts +1 -1
- package/src/tools/browser.ts +6 -0
- package/src/tools/index.ts +8 -8
- package/src/tools/puppeteer/14_stealth_permissions.txt +57 -0
- package/src/tools/puppeteer/15_stealth_webrtc.txt +60 -0
- package/src/tools/subagent-render.ts +19 -8
- package/src/tools/subagent.ts +84 -32
- package/src/tools/telegram-send.ts +2 -2
- package/vendor/insane-search/MANIFEST.json +2 -1
- package/vendor/insane-search/engine/bias_check.py +4 -1
- package/vendor/insane-search/engine/phase0.py +26 -1
- package/dist/types/harness-control-plane/rpc-adapter.d.ts +0 -69
- package/dist/types/modes/bridge/auth.d.ts +0 -12
- package/dist/types/modes/bridge/bridge-client-bridge.d.ts +0 -9
- package/dist/types/modes/bridge/bridge-mode.d.ts +0 -47
- package/dist/types/modes/bridge/bridge-ui-context.d.ts +0 -88
- package/dist/types/modes/bridge/event-stream.d.ts +0 -8
- package/dist/types/modes/rpc/host-tools.d.ts +0 -1
- package/dist/types/modes/rpc/host-uris.d.ts +0 -1
- package/dist/types/modes/rpc/rpc-client.d.ts +0 -299
- package/dist/types/modes/rpc/rpc-mode.d.ts +0 -86
- package/dist/types/modes/rpc/rpc-socket-security.d.ts +0 -10
- package/dist/types/modes/rpc/rpc-types.d.ts +0 -810
- package/dist/types/modes/shared/agent-wire/command-contract.d.ts +0 -18
- package/dist/types/modes/shared/agent-wire/command-dispatch.d.ts +0 -37
- package/dist/types/modes/shared/agent-wire/command-validation.d.ts +0 -2
- package/dist/types/modes/shared/agent-wire/handshake.d.ts +0 -56
- package/dist/types/modes/shared/agent-wire/host-tool-bridge.d.ts +0 -16
- package/dist/types/modes/shared/agent-wire/host-uri-bridge.d.ts +0 -17
- package/dist/types/modes/shared/agent-wire/protocol.d.ts +0 -25
- package/dist/types/modes/shared/agent-wire/responses.d.ts +0 -4
- package/dist/types/modes/shared/agent-wire/scopes.d.ts +0 -18
- package/dist/types/modes/shared/agent-wire/session-registry.d.ts +0 -25
- package/dist/types/modes/shared/agent-wire/ui-request-broker.d.ts +0 -42
- package/dist/types/modes/shared/agent-wire/ui-result.d.ts +0 -27
- package/dist/types/modes/shared/agent-wire/unattended-action-policy.d.ts +0 -29
- package/dist/types/modes/shared/agent-wire/unattended-audit.d.ts +0 -68
- package/dist/types/modes/shared/agent-wire/unattended-run-controller.d.ts +0 -166
- package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +0 -127
- package/dist/types/notifications/config.d.ts +0 -132
- package/src/harness-control-plane/rpc-adapter.ts +0 -290
- package/src/modes/bridge/auth.ts +0 -41
- package/src/modes/bridge/bridge-client-bridge.ts +0 -47
- package/src/modes/bridge/bridge-mode.ts +0 -675
- package/src/modes/bridge/bridge-ui-context.ts +0 -200
- package/src/modes/bridge/event-stream.ts +0 -70
- package/src/modes/rpc/host-tools.ts +0 -1
- package/src/modes/rpc/host-uris.ts +0 -1
- package/src/modes/rpc/rpc-client.ts +0 -1166
- package/src/modes/rpc/rpc-mode.ts +0 -1029
- package/src/modes/rpc/rpc-socket-security.ts +0 -115
- package/src/modes/rpc/rpc-types.ts +0 -637
- package/src/modes/shared/agent-wire/command-contract.ts +0 -18
- package/src/modes/shared/agent-wire/command-dispatch.ts +0 -498
- package/src/modes/shared/agent-wire/command-validation.ts +0 -181
- package/src/modes/shared/agent-wire/handshake.ts +0 -157
- package/src/modes/shared/agent-wire/host-tool-bridge.ts +0 -197
- package/src/modes/shared/agent-wire/host-uri-bridge.ts +0 -236
- package/src/modes/shared/agent-wire/protocol.ts +0 -46
- package/src/modes/shared/agent-wire/responses.ts +0 -17
- package/src/modes/shared/agent-wire/scopes.ts +0 -94
- package/src/modes/shared/agent-wire/session-registry.ts +0 -109
- package/src/modes/shared/agent-wire/ui-request-broker.ts +0 -150
- package/src/modes/shared/agent-wire/ui-result.ts +0 -48
- package/src/modes/shared/agent-wire/unattended-action-policy.ts +0 -365
- package/src/modes/shared/agent-wire/unattended-audit.ts +0 -176
- package/src/modes/shared/agent-wire/unattended-run-controller.ts +0 -426
- package/src/modes/shared/agent-wire/unattended-session.ts +0 -528
- package/src/notifications/config.ts +0 -219
- package/src/notifications/index.ts +0 -1835
- package/src/notifications/telegram-daemon-cli.ts +0 -243
- package/src/tools/puppeteer/09_stealth_locale.txt +0 -46
- /package/dist/types/{notifications → sdk/bus}/attachment-registry.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/chat-adapters.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/daemon-paths.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/engine.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/helpers.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/lifecycle-commands.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/operator-runtime.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/rate-limit-pool.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/recent-activity.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/reply-sent-store.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/rich-draft.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/rich-render.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/threaded-inbound.d.ts +0 -0
- /package/dist/types/{notifications → sdk/bus}/threaded-render.d.ts +0 -0
- /package/src/{notifications → sdk/bus}/attachment-registry.ts +0 -0
- /package/src/{notifications → sdk/bus}/chat-adapters.ts +0 -0
- /package/src/{notifications → sdk/bus}/daemon-paths.ts +0 -0
- /package/src/{notifications → sdk/bus}/engine.ts +0 -0
- /package/src/{notifications → sdk/bus}/helpers.ts +0 -0
- /package/src/{notifications → sdk/bus}/operator-runtime.ts +0 -0
- /package/src/{notifications → sdk/bus}/rate-limit-pool.ts +0 -0
- /package/src/{notifications → sdk/bus}/recent-activity.ts +0 -0
- /package/src/{notifications → sdk/bus}/reply-sent-store.ts +0 -0
- /package/src/{notifications → sdk/bus}/rich-draft.ts +0 -0
- /package/src/{notifications → sdk/bus}/rich-render.ts +0 -0
- /package/src/{notifications → sdk/bus}/threaded-inbound.ts +0 -0
- /package/src/{notifications → sdk/bus}/threaded-render.ts +0 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { Glob } from "bun";
|
|
5
|
+
import { type Manifest, validateManifest } from "./manifest-schema";
|
|
6
|
+
|
|
7
|
+
const repoRoot = path.resolve(import.meta.dir, "..", "..", "..");
|
|
8
|
+
const testDirectory = process.env.GJC_TELEGRAM_BASELINE_TEST_DIR
|
|
9
|
+
? path.resolve(process.env.GJC_TELEGRAM_BASELINE_TEST_DIR)
|
|
10
|
+
: path.join(repoRoot, "packages", "coding-agent", "test");
|
|
11
|
+
const manifestPath = process.env.GJC_TELEGRAM_BASELINE_MANIFEST
|
|
12
|
+
? path.resolve(process.env.GJC_TELEGRAM_BASELINE_MANIFEST)
|
|
13
|
+
: path.join(testDirectory, "manifests", "telegram-baseline-v1.json");
|
|
14
|
+
const reviewedExclusions: Manifest["excluded"] = [];
|
|
15
|
+
|
|
16
|
+
const explicitTests = [
|
|
17
|
+
"daemon-control.test.ts",
|
|
18
|
+
"telegram-send-tool.test.ts",
|
|
19
|
+
"telegram-onboarding-docs.test.ts",
|
|
20
|
+
"lifecycle-notification-docs.test.ts",
|
|
21
|
+
];
|
|
22
|
+
const requiredTests = [
|
|
23
|
+
"packages/coding-agent/test/daemon-control.test.ts",
|
|
24
|
+
"packages/coding-agent/test/notifications-chat-adapters.test.ts",
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
function toRepoPath(relativeTestPath: string): string {
|
|
28
|
+
return path.posix.join("packages/coding-agent/test", relativeTestPath.split(path.sep).join("/"));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function discoverTests(): Promise<string[]> {
|
|
32
|
+
const tests = new Set<string>();
|
|
33
|
+
for (const pattern of ["notifications-*.test.ts", "telegram-*.test.ts"]) {
|
|
34
|
+
for await (const relativePath of new Glob(pattern).scan(testDirectory)) {
|
|
35
|
+
tests.add(toRepoPath(relativePath));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
for (const filename of explicitTests) {
|
|
40
|
+
const filePath = path.join(testDirectory, filename);
|
|
41
|
+
if (await Bun.file(filePath).exists()) {
|
|
42
|
+
tests.add(toRepoPath(filename));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return [...tests].sort();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function generateManifest(tests: string[]): Manifest {
|
|
50
|
+
const excludedFiles = new Set(reviewedExclusions.map(exclusion => exclusion.file));
|
|
51
|
+
return {
|
|
52
|
+
version: 1,
|
|
53
|
+
commands: tests.filter(test => !excludedFiles.has(test)).map(file => ({ argv: ["bun", "test", file] })),
|
|
54
|
+
excluded: [...reviewedExclusions],
|
|
55
|
+
required: requiredTests,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function normalizedManifest(manifest: Manifest): Manifest {
|
|
60
|
+
return {
|
|
61
|
+
version: manifest.version,
|
|
62
|
+
commands: manifest.commands
|
|
63
|
+
.map(command => ({ argv: [...command.argv] }))
|
|
64
|
+
.sort((left, right) => left.argv.join("\0").localeCompare(right.argv.join("\0"))),
|
|
65
|
+
excluded: manifest.excluded
|
|
66
|
+
.map(exclusion => ({ ...exclusion }))
|
|
67
|
+
.sort((left, right) => left.file.localeCompare(right.file) || left.reason.localeCompare(right.reason)),
|
|
68
|
+
required: [...(manifest.required ?? [])].sort(),
|
|
69
|
+
rows: (manifest.rows ?? [])
|
|
70
|
+
.map(row => ({ ...row, argv: [...row.argv] }))
|
|
71
|
+
.sort((left, right) => JSON.stringify(left).localeCompare(JSON.stringify(right))),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function describeMismatch(expected: Manifest, actual: Manifest): string {
|
|
76
|
+
const expectedCommands = new Set(expected.commands.map(command => command.argv.join("\0")));
|
|
77
|
+
const actualCommands = new Set(actual.commands.map(command => command.argv.join("\0")));
|
|
78
|
+
const expectedExclusions = new Set(expected.excluded.map(exclusion => `${exclusion.file}\0${exclusion.reason}`));
|
|
79
|
+
const actualExclusions = new Set(actual.excluded.map(exclusion => `${exclusion.file}\0${exclusion.reason}`));
|
|
80
|
+
const differences = [
|
|
81
|
+
...actual.commands
|
|
82
|
+
.filter(command => !expectedCommands.has(command.argv.join("\0")))
|
|
83
|
+
.map(command => `- stale command: ${command.argv.join(" ")}`),
|
|
84
|
+
...expected.commands
|
|
85
|
+
.filter(command => !actualCommands.has(command.argv.join("\0")))
|
|
86
|
+
.map(command => `- missing command: ${command.argv.join(" ")}`),
|
|
87
|
+
...actual.excluded
|
|
88
|
+
.filter(exclusion => !expectedExclusions.has(`${exclusion.file}\0${exclusion.reason}`))
|
|
89
|
+
.map(exclusion => `- unapproved exclusion: ${exclusion.file} (${exclusion.reason})`),
|
|
90
|
+
...expected.excluded
|
|
91
|
+
.filter(exclusion => !actualExclusions.has(`${exclusion.file}\0${exclusion.reason}`))
|
|
92
|
+
.map(exclusion => `- missing reviewed exclusion: ${exclusion.file} (${exclusion.reason})`),
|
|
93
|
+
];
|
|
94
|
+
return differences.length > 0 ? differences.join("\n") : "- manifest fields differ";
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function checkManifest(expected: Manifest): Promise<void> {
|
|
98
|
+
let manifest: Manifest;
|
|
99
|
+
try {
|
|
100
|
+
manifest = validateManifest(await Bun.file(manifestPath).json());
|
|
101
|
+
} catch (error) {
|
|
102
|
+
throw new Error(
|
|
103
|
+
`Unable to read ${path.relative(repoRoot, manifestPath)}: ${error instanceof Error ? error.message : String(error)}`,
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const normalizedExpected = normalizedManifest(expected);
|
|
108
|
+
const normalizedManifestFile = normalizedManifest(manifest);
|
|
109
|
+
if (JSON.stringify(normalizedManifestFile) !== JSON.stringify(normalizedExpected)) {
|
|
110
|
+
throw new Error(
|
|
111
|
+
`Telegram baseline manifest does not exactly match the generated baseline:\n${describeMismatch(normalizedExpected, normalizedManifestFile)}`,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const tests = await discoverTests();
|
|
117
|
+
const generatedManifest = validateManifest(generateManifest(tests));
|
|
118
|
+
if (process.argv.slice(2).includes("--check")) {
|
|
119
|
+
try {
|
|
120
|
+
await checkManifest(generatedManifest);
|
|
121
|
+
} catch (error) {
|
|
122
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
await Bun.write(manifestPath, `${JSON.stringify(generatedManifest, null, "\t")}\n`);
|
|
127
|
+
process.stderr.write(`Generated ${path.relative(repoRoot, manifestPath)} (${tests.length} commands)\n`);
|
|
128
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
export type ManifestCommand = {
|
|
2
|
+
argv: string[];
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
export type ManifestExclusion = {
|
|
6
|
+
file: string;
|
|
7
|
+
reason: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type ManifestAdapterRow = {
|
|
11
|
+
adapterTestId: string;
|
|
12
|
+
sdkId: string;
|
|
13
|
+
adapter: "telegram" | "discord" | "slack" | "mcp" | "acp" | "daemonCli";
|
|
14
|
+
disposition: "native_alias" | "generic_safe" | "machine_only" | "provider_only" | "prohibited";
|
|
15
|
+
testFile: string;
|
|
16
|
+
testNamePattern: string;
|
|
17
|
+
expected: "forwarded" | "rejected_before_send" | "internal_only";
|
|
18
|
+
argv: string[];
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type Manifest = {
|
|
22
|
+
version: 1;
|
|
23
|
+
commands: ManifestCommand[];
|
|
24
|
+
excluded: ManifestExclusion[];
|
|
25
|
+
required?: string[];
|
|
26
|
+
rows?: ManifestAdapterRow[];
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export function validateManifest(value: unknown): Manifest {
|
|
30
|
+
if (typeof value !== "object" || value === null) throw new Error("Manifest must be an object.");
|
|
31
|
+
if (!("version" in value) || value.version !== 1) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
`Manifest version must be 1; received ${"version" in value ? JSON.stringify(value.version) : "missing"}.`,
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
if (!("commands" in value) || !Array.isArray(value.commands)) throw new Error("Manifest commands must be an array.");
|
|
37
|
+
if (!("excluded" in value) || !Array.isArray(value.excluded)) throw new Error("Manifest excluded must be an array.");
|
|
38
|
+
if ("required" in value && !Array.isArray(value.required)) throw new Error("Manifest required must be an array.");
|
|
39
|
+
if ("rows" in value && !Array.isArray(value.rows)) throw new Error("Manifest rows must be an array.");
|
|
40
|
+
|
|
41
|
+
if (value.commands.length === 0) throw new Error("Manifest must contain at least one command.");
|
|
42
|
+
|
|
43
|
+
for (const [index, command] of value.commands.entries()) {
|
|
44
|
+
if (
|
|
45
|
+
typeof command !== "object" ||
|
|
46
|
+
command === null ||
|
|
47
|
+
!("argv" in command) ||
|
|
48
|
+
!Array.isArray(command.argv) ||
|
|
49
|
+
command.argv.length === 0 ||
|
|
50
|
+
!command.argv.every((argument: unknown) => typeof argument === "string")
|
|
51
|
+
) {
|
|
52
|
+
throw new Error(`Manifest command ${index} must contain a non-empty string argv array.`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
for (const [index, exclusion] of value.excluded.entries()) {
|
|
57
|
+
if (
|
|
58
|
+
typeof exclusion !== "object" ||
|
|
59
|
+
exclusion === null ||
|
|
60
|
+
!("file" in exclusion) ||
|
|
61
|
+
typeof exclusion.file !== "string" ||
|
|
62
|
+
exclusion.file.length === 0 ||
|
|
63
|
+
!("reason" in exclusion) ||
|
|
64
|
+
typeof exclusion.reason !== "string" ||
|
|
65
|
+
exclusion.reason.trim().length === 0
|
|
66
|
+
) {
|
|
67
|
+
throw new Error(`Manifest excluded entry ${index} must contain non-empty string file and reason fields.`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const required: unknown[] = "required" in value && Array.isArray(value.required) ? value.required : [];
|
|
72
|
+
for (const [index, file] of required.entries()) {
|
|
73
|
+
if (typeof file !== "string" || file.length === 0) {
|
|
74
|
+
throw new Error(`Manifest required entry ${index} must be a non-empty string.`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const rows: unknown[] = "rows" in value && Array.isArray(value.rows) ? value.rows : [];
|
|
79
|
+
const adapters = new Set(["telegram", "discord", "slack", "mcp", "acp", "daemonCli"]);
|
|
80
|
+
const dispositions = new Set(["native_alias", "generic_safe", "machine_only", "provider_only", "prohibited"]);
|
|
81
|
+
const expected = new Set(["forwarded", "rejected_before_send", "internal_only"]);
|
|
82
|
+
for (const [index, row] of rows.entries()) {
|
|
83
|
+
if (
|
|
84
|
+
typeof row !== "object" ||
|
|
85
|
+
row === null ||
|
|
86
|
+
!("adapterTestId" in row) ||
|
|
87
|
+
typeof row.adapterTestId !== "string" ||
|
|
88
|
+
!row.adapterTestId ||
|
|
89
|
+
!("sdkId" in row) ||
|
|
90
|
+
typeof row.sdkId !== "string" ||
|
|
91
|
+
!row.sdkId ||
|
|
92
|
+
!("adapter" in row) ||
|
|
93
|
+
typeof row.adapter !== "string" ||
|
|
94
|
+
!adapters.has(row.adapter) ||
|
|
95
|
+
!("disposition" in row) ||
|
|
96
|
+
typeof row.disposition !== "string" ||
|
|
97
|
+
!dispositions.has(row.disposition) ||
|
|
98
|
+
!("testFile" in row) ||
|
|
99
|
+
typeof row.testFile !== "string" ||
|
|
100
|
+
!row.testFile ||
|
|
101
|
+
!("testNamePattern" in row) ||
|
|
102
|
+
typeof row.testNamePattern !== "string" ||
|
|
103
|
+
!row.testNamePattern.trim() ||
|
|
104
|
+
!("argv" in row) ||
|
|
105
|
+
!Array.isArray(row.argv) ||
|
|
106
|
+
!row.argv.every(argument => typeof argument === "string") ||
|
|
107
|
+
!("expected" in row) ||
|
|
108
|
+
typeof row.expected !== "string" ||
|
|
109
|
+
!expected.has(row.expected)
|
|
110
|
+
)
|
|
111
|
+
throw new Error(`Manifest row ${index} must contain valid adapter coverage fields.`);
|
|
112
|
+
if (
|
|
113
|
+
row.argv.length !== 5 ||
|
|
114
|
+
row.argv[0] !== "bun" ||
|
|
115
|
+
row.argv[1] !== "test" ||
|
|
116
|
+
row.argv[2] !== row.testFile ||
|
|
117
|
+
row.argv[3] !== "--test-name-pattern" ||
|
|
118
|
+
row.argv[4].trim().length === 0
|
|
119
|
+
)
|
|
120
|
+
throw new Error(`Manifest row ${index} must contain an exact bun test receipt argv.`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return value as Manifest;
|
|
124
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { CHAT_OPERATION_POLICY } from "../src/sdk/bus/chat-command-policy";
|
|
5
|
+
import { ADAPTERS, OPERATIONS } from "../src/sdk/protocol/operation-registry";
|
|
6
|
+
import { type Manifest, type ManifestAdapterRow, validateManifest } from "./manifest-schema";
|
|
7
|
+
|
|
8
|
+
const repoRoot = path.resolve(import.meta.dir, "..", "..", "..");
|
|
9
|
+
|
|
10
|
+
function usage(): never {
|
|
11
|
+
process.stderr.write(
|
|
12
|
+
"Usage: bun run packages/coding-agent/scripts/run-test-manifest.ts <manifest.json> [--check]\n",
|
|
13
|
+
);
|
|
14
|
+
process.exit(2);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function testCount(output: string): number | undefined {
|
|
18
|
+
const ran = output.match(/Ran\s+(\d+)\s+tests?\s+across\b/);
|
|
19
|
+
if (ran) return Number(ran[1]);
|
|
20
|
+
const summary = output.match(/^(\d+) pass(?:\s*,?\s*\d+ fail)?$/m);
|
|
21
|
+
return summary ? Number(summary[1]) : undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const [manifestArgument, ...flags] = process.argv.slice(2);
|
|
25
|
+
if (manifestArgument === undefined || flags.some(flag => flag !== "--check")) usage();
|
|
26
|
+
const checkOnly = flags.includes("--check");
|
|
27
|
+
const manifestPath = path.resolve(manifestArgument);
|
|
28
|
+
let manifest: Manifest;
|
|
29
|
+
try {
|
|
30
|
+
manifest = validateManifest(await Bun.file(manifestPath).json());
|
|
31
|
+
} catch (error) {
|
|
32
|
+
process.stderr.write(`Unable to read ${manifestPath}: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
33
|
+
process.exit(2);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function validateRowReceipts(rows: ManifestAdapterRow[]): void {
|
|
37
|
+
const ids = new Set<string>();
|
|
38
|
+
const counts = new Map<string, number>();
|
|
39
|
+
for (const row of rows) {
|
|
40
|
+
if (ids.has(row.adapterTestId)) throw new Error(`Duplicate adapter test ID: ${row.adapterTestId}`);
|
|
41
|
+
ids.add(row.adapterTestId);
|
|
42
|
+
if (/placeholder|todo|tbd|example/i.test(row.testNamePattern))
|
|
43
|
+
throw new Error(`${row.adapterTestId} has a placeholder test pattern.`);
|
|
44
|
+
if (row.argv[4] === undefined || !row.argv[4].includes(row.adapterTestId))
|
|
45
|
+
throw new Error(`${row.adapterTestId} receipt does not select its exact test.`);
|
|
46
|
+
|
|
47
|
+
const [, , operationId] = row.adapterTestId.split("-");
|
|
48
|
+
const operation = OPERATIONS.find(candidate => candidate.id === operationId && candidate.sdkId === row.sdkId);
|
|
49
|
+
if (!operation) throw new Error(`${row.adapterTestId} does not identify a registry operation.`);
|
|
50
|
+
if (row.disposition !== operation.adapterDispositions[row.adapter])
|
|
51
|
+
throw new Error(`${row.adapterTestId} disposition diverges from the operation registry.`);
|
|
52
|
+
if (row.adapter === "telegram" || row.adapter === "discord" || row.adapter === "slack") {
|
|
53
|
+
const policyExpected = row.adapterTestId.endsWith("-secret")
|
|
54
|
+
? "rejected_before_send"
|
|
55
|
+
: CHAT_OPERATION_POLICY[row.adapter][operation.id] === "allowed"
|
|
56
|
+
? "forwarded"
|
|
57
|
+
: "rejected_before_send";
|
|
58
|
+
if (row.expected !== policyExpected)
|
|
59
|
+
throw new Error(`${row.adapterTestId} expected outcome diverges from chat command policy.`);
|
|
60
|
+
}
|
|
61
|
+
counts.set(row.adapter, (counts.get(row.adapter) ?? 0) + 1);
|
|
62
|
+
}
|
|
63
|
+
if (rows.length !== ADAPTERS.length * 91)
|
|
64
|
+
throw new Error(`Expected ${ADAPTERS.length * 91} adapter rows; received ${rows.length}.`);
|
|
65
|
+
for (const adapter of ADAPTERS) {
|
|
66
|
+
if (counts.get(adapter) !== 91)
|
|
67
|
+
throw new Error(`Expected 91 ${adapter} rows; received ${counts.get(adapter) ?? 0}.`);
|
|
68
|
+
}
|
|
69
|
+
process.stdout.write(
|
|
70
|
+
`manifest check: ${rows.length} row receipts (${[...counts].map(([adapter, count]) => `${adapter}=${count}`).join(", ")})\n`,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Required files must be either exact `bun test <file>` commands or fail-closed
|
|
75
|
+
// anchored partitions that collectively match every declared row for that file.
|
|
76
|
+
const rows = manifest.rows ?? [];
|
|
77
|
+
const exactExecutableFiles = new Set(
|
|
78
|
+
manifest.commands
|
|
79
|
+
.filter(command => command.argv.length === 3 && command.argv[0] === "bun" && command.argv[1] === "test")
|
|
80
|
+
.map(command => command.argv[2]),
|
|
81
|
+
);
|
|
82
|
+
for (const file of manifest.required ?? []) {
|
|
83
|
+
if (exactExecutableFiles.has(file)) continue;
|
|
84
|
+
const fileRows = rows.filter(row => row.testFile === file);
|
|
85
|
+
const partitions = manifest.commands
|
|
86
|
+
.filter(
|
|
87
|
+
command =>
|
|
88
|
+
command.argv.length === 5 &&
|
|
89
|
+
command.argv[0] === "bun" &&
|
|
90
|
+
command.argv[1] === "test" &&
|
|
91
|
+
command.argv[2] === file &&
|
|
92
|
+
command.argv[3] === "--test-name-pattern" &&
|
|
93
|
+
command.argv[4]?.startsWith("^"),
|
|
94
|
+
)
|
|
95
|
+
.map(command => new RegExp(command.argv[4]!));
|
|
96
|
+
if (
|
|
97
|
+
fileRows.length === 0 ||
|
|
98
|
+
partitions.length === 0 ||
|
|
99
|
+
fileRows.some(row => !partitions.some(pattern => pattern.test(row.testNamePattern)))
|
|
100
|
+
) {
|
|
101
|
+
process.stderr.write(`Manifest required file is not covered by executable commands: ${file}\n`);
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (rows.length > 0) {
|
|
106
|
+
try {
|
|
107
|
+
validateRowReceipts(rows);
|
|
108
|
+
} catch (error) {
|
|
109
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (checkOnly) process.exit(0);
|
|
114
|
+
|
|
115
|
+
const startedAt = performance.now();
|
|
116
|
+
let commandReceipts = 0;
|
|
117
|
+
let rowReceipts = 0;
|
|
118
|
+
const perAdapter = new Map<string, number>();
|
|
119
|
+
|
|
120
|
+
async function executeReceipt(argv: string[]): Promise<void> {
|
|
121
|
+
const child = Bun.spawn(argv, { cwd: repoRoot, stdout: "pipe", stderr: "pipe" });
|
|
122
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
123
|
+
new Response(child.stdout).text(),
|
|
124
|
+
new Response(child.stderr).text(),
|
|
125
|
+
child.exited,
|
|
126
|
+
]);
|
|
127
|
+
process.stdout.write(stdout);
|
|
128
|
+
process.stderr.write(stderr);
|
|
129
|
+
const tests = testCount(`${stdout}\n${stderr}`);
|
|
130
|
+
process.stdout.write(`receipt: ${argv.join(" ")} exit=${exitCode} tests=${tests ?? "unknown"}\n`);
|
|
131
|
+
if (exitCode === 0 && tests !== undefined && tests >= 1) return;
|
|
132
|
+
const reason = exitCode !== 0 ? `exit ${exitCode}` : "did not report at least one test";
|
|
133
|
+
process.stderr.write(`Manifest receipt failed: ${argv.join(" ")} (${reason})\n`);
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
for (const command of manifest.commands) {
|
|
138
|
+
await executeReceipt(command.argv);
|
|
139
|
+
commandReceipts++;
|
|
140
|
+
}
|
|
141
|
+
process.stdout.write(`manifest command receipts complete: ${commandReceipts}\n`);
|
|
142
|
+
|
|
143
|
+
for (const row of rows) {
|
|
144
|
+
await executeReceipt(row.argv);
|
|
145
|
+
rowReceipts++;
|
|
146
|
+
perAdapter.set(row.adapter, (perAdapter.get(row.adapter) ?? 0) + 1);
|
|
147
|
+
}
|
|
148
|
+
if (rows.length > 0) {
|
|
149
|
+
process.stdout.write(
|
|
150
|
+
`manifest row receipts complete: ${rowReceipts} (${[...perAdapter].map(([adapter, count]) => `${adapter}=${count}`).join(", ")})\n`,
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
process.stdout.write(`manifest receipts runtime=${Math.round(performance.now() - startedAt)}ms\n`);
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import * as fs from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { NotificationServer } from "../../natives/native/index.js";
|
|
6
|
+
import { Broker } from "../src/sdk/broker/broker";
|
|
7
|
+
import { brokerDiscoveryPath } from "../src/sdk/broker/discovery";
|
|
8
|
+
import { brokerIdentityPath, getBrokerIdentityKey } from "../src/sdk/broker/identity";
|
|
9
|
+
|
|
10
|
+
type Check = { id: string; description: string; kind: "assertion" | "negative-test"; command?: string };
|
|
11
|
+
type Manifest = { version: 1; checks: Check[] };
|
|
12
|
+
|
|
13
|
+
function assert(condition: unknown, message: string): asserts condition {
|
|
14
|
+
if (!condition) throw new Error(message);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function rejectedWebSocket(url: string): Promise<void> {
|
|
18
|
+
const ws = new WebSocket(url);
|
|
19
|
+
await new Promise<void>((resolve, reject) => {
|
|
20
|
+
const timeout = setTimeout(() => reject(new Error("unauthorized WebSocket was not rejected")), 2_000);
|
|
21
|
+
ws.addEventListener(
|
|
22
|
+
"close",
|
|
23
|
+
() => {
|
|
24
|
+
clearTimeout(timeout);
|
|
25
|
+
resolve();
|
|
26
|
+
},
|
|
27
|
+
{ once: true },
|
|
28
|
+
);
|
|
29
|
+
ws.addEventListener(
|
|
30
|
+
"open",
|
|
31
|
+
() => {
|
|
32
|
+
clearTimeout(timeout);
|
|
33
|
+
ws.close();
|
|
34
|
+
reject(new Error("unauthorized WebSocket connected"));
|
|
35
|
+
},
|
|
36
|
+
{ once: true },
|
|
37
|
+
);
|
|
38
|
+
ws.addEventListener(
|
|
39
|
+
"error",
|
|
40
|
+
() => {
|
|
41
|
+
clearTimeout(timeout);
|
|
42
|
+
resolve();
|
|
43
|
+
},
|
|
44
|
+
{ once: true },
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function mode(file: string): Promise<number> {
|
|
50
|
+
return (await fs.stat(file)).mode & 0o777;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function main(): Promise<void> {
|
|
54
|
+
const manifestPath = process.argv[2];
|
|
55
|
+
if (!manifestPath) throw new Error("Usage: bun scripts/run-threat-model-check.ts <manifest.json>");
|
|
56
|
+
const manifest = JSON.parse(await fs.readFile(manifestPath, "utf8")) as Manifest;
|
|
57
|
+
assert(manifest.version === 1 && Array.isArray(manifest.checks), "Invalid threat-model manifest");
|
|
58
|
+
const ids = new Set<string>();
|
|
59
|
+
for (const check of manifest.checks) {
|
|
60
|
+
assert(
|
|
61
|
+
typeof check.id === "string" && check.id.length > 0 && !ids.has(check.id),
|
|
62
|
+
"Invalid or duplicate check id",
|
|
63
|
+
);
|
|
64
|
+
assert(
|
|
65
|
+
typeof check.description === "string" && (check.kind === "assertion" || check.kind === "negative-test"),
|
|
66
|
+
`Invalid check ${check.id}`,
|
|
67
|
+
);
|
|
68
|
+
ids.add(check.id);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const agentDir = await fs.mkdtemp(path.join(process.env.TMPDIR ?? "/tmp", "gjc-broker-threat-model-"));
|
|
72
|
+
const broker = new Broker({ agentDir, packageGeneration: "threat-model" });
|
|
73
|
+
const failures: string[] = [];
|
|
74
|
+
try {
|
|
75
|
+
const discovery = await broker.start();
|
|
76
|
+
await getBrokerIdentityKey(agentDir);
|
|
77
|
+
const statusOutput = JSON.stringify(broker.status());
|
|
78
|
+
const checks: Record<string, () => Promise<void>> = {
|
|
79
|
+
"broker-token-agent-global-blast-radius": async () => {
|
|
80
|
+
assert(discovery.token.length === 64, "broker token is not a 256-bit value");
|
|
81
|
+
},
|
|
82
|
+
"broker-discovery-file-permissions": async () => {
|
|
83
|
+
if (process.platform !== "win32") {
|
|
84
|
+
assert((await mode(brokerDiscoveryPath(agentDir))) === 0o600, "broker.json is not mode 0600");
|
|
85
|
+
assert((await mode(path.join(agentDir, "sdk"))) === 0o700, "sdk directory is not mode 0700");
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"broker-identity-file-permissions": async () => {
|
|
89
|
+
if (process.platform !== "win32")
|
|
90
|
+
assert((await mode(brokerIdentityPath(agentDir))) === 0o600, "broker.identity is not mode 0600");
|
|
91
|
+
},
|
|
92
|
+
"broker-loopback-only": async () => {
|
|
93
|
+
assert(discovery.host === "127.0.0.1", "broker advertised a non-loopback host");
|
|
94
|
+
assert(discovery.url === `ws://127.0.0.1:${discovery.port}`, "broker advertised a non-loopback URL");
|
|
95
|
+
},
|
|
96
|
+
"broker-token-rotation-on-stale-takeover": async () => {
|
|
97
|
+
const takeoverDir = await fs.mkdtemp(path.join(process.env.TMPDIR ?? "/tmp", "gjc-broker-takeover-"));
|
|
98
|
+
const first = new Broker({ agentDir: takeoverDir, packageGeneration: "threat-model" });
|
|
99
|
+
try {
|
|
100
|
+
const previous = await first.start();
|
|
101
|
+
await first.stop();
|
|
102
|
+
const replacement = new Broker({ agentDir: takeoverDir, packageGeneration: "threat-model" });
|
|
103
|
+
try {
|
|
104
|
+
const next = await replacement.start();
|
|
105
|
+
assert(next.token !== previous.token, "broker token did not rotate on takeover");
|
|
106
|
+
} finally {
|
|
107
|
+
await replacement.stop();
|
|
108
|
+
}
|
|
109
|
+
} finally {
|
|
110
|
+
await first.stop();
|
|
111
|
+
await fs.rm(takeoverDir, { recursive: true, force: true });
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
"broker-per-session-token-separation": async () => {
|
|
115
|
+
const sessionRoot = await fs.mkdtemp(path.join(process.env.TMPDIR ?? "/tmp", "gjc-broker-session-token-"));
|
|
116
|
+
const sessionToken = "session-token-that-must-not-authorize-broker";
|
|
117
|
+
const sessionServer = new NotificationServer("threat-model", sessionToken, sessionRoot, true);
|
|
118
|
+
try {
|
|
119
|
+
const endpoint = await sessionServer.start();
|
|
120
|
+
assert(endpoint.url.startsWith("ws://127.0.0.1:"), "per-session endpoint did not start on loopback");
|
|
121
|
+
await rejectedWebSocket(`${discovery.url}/?token=${encodeURIComponent(sessionToken)}`);
|
|
122
|
+
} finally {
|
|
123
|
+
sessionServer.stop();
|
|
124
|
+
await fs.rm(sessionRoot, { recursive: true, force: true });
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
"broker-status-token-redaction": async () => {
|
|
128
|
+
assert(!statusOutput.includes(discovery.token), "broker token appeared in production status output");
|
|
129
|
+
assert(statusOutput.includes("[redacted]"), "production status output did not redact broker token");
|
|
130
|
+
},
|
|
131
|
+
"broker-non-loopback-negative-test": async () => {
|
|
132
|
+
assert(!discovery.url.includes("0.0.0.0"), "non-loopback broker URL exists");
|
|
133
|
+
await rejectedWebSocket(`${discovery.url}/?token=wrong-token`);
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
for (const check of manifest.checks) {
|
|
137
|
+
try {
|
|
138
|
+
const run = checks[check.id];
|
|
139
|
+
assert(run, `No implementation for check ${check.id}`);
|
|
140
|
+
await run();
|
|
141
|
+
console.log(`PASS ${check.id}`);
|
|
142
|
+
} catch (error) {
|
|
143
|
+
failures.push(check.id);
|
|
144
|
+
console.error(`FAIL ${check.id}: ${error instanceof Error ? error.message : String(error)}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
} finally {
|
|
148
|
+
await broker.stop();
|
|
149
|
+
await fs.rm(agentDir, { recursive: true, force: true });
|
|
150
|
+
}
|
|
151
|
+
if (failures.length) {
|
|
152
|
+
process.stderr.write(`Failed threat-model checks: ${failures.join(", ")}\n`);
|
|
153
|
+
process.exitCode = 1;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
await main();
|