@gajae-code/coding-agent 0.10.2 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +50 -2
- package/dist/types/append-only-mode.d.ts +1 -1
- 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/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/selector-controller.d.ts +35 -1
- package/dist/types/modes/index.d.ts +0 -4
- package/dist/types/modes/interactive-mode.d.ts +3 -0
- 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 +169 -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 +5 -0
- 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 +33 -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 +45 -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 +55 -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/package.json +34 -13
- package/scripts/build-sdk-package-smoke.ts +94 -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/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 +53 -6
- package/src/gjc-runtime/ultragoal-runtime.ts +155 -3
- 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 +1 -2
- package/src/modes/controllers/event-controller.ts +11 -16
- package/src/modes/controllers/extension-ui-controller.ts +348 -4
- package/src/modes/controllers/selector-controller.ts +674 -36
- package/src/modes/index.ts +0 -22
- package/src/modes/interactive-mode.ts +59 -20
- 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 +1254 -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 +5 -0
- 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 +94 -0
- package/src/sdk/broker/ensure.ts +249 -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 +353 -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 +2275 -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 +3943 -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 +502 -54
- 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 +2453 -894
- 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/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/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,535 @@
|
|
|
1
|
+
import type { CasRestoreResult } from "../../config/atomic-yaml-patch";
|
|
2
|
+
import type { RawSettings, SettingsAtomicPatch, SettingsAtomicReceipt } from "../../config/settings";
|
|
3
|
+
import {
|
|
4
|
+
getNotificationConfig,
|
|
5
|
+
hasNonBlankValue,
|
|
6
|
+
type NotificationSettingsReader,
|
|
7
|
+
type NotificationSettingsSnapshot,
|
|
8
|
+
readTelegramActivationMarkers,
|
|
9
|
+
type TelegramActivationMarker,
|
|
10
|
+
type TelegramActivationMarkers,
|
|
11
|
+
type TelegramActivationReason,
|
|
12
|
+
type TelegramActivationState,
|
|
13
|
+
telegramActivationIdentity,
|
|
14
|
+
tokenFingerprint,
|
|
15
|
+
} from "./config";
|
|
16
|
+
import {
|
|
17
|
+
DAEMON_VERSION,
|
|
18
|
+
type EnsureTelegramDaemonDetailedResult,
|
|
19
|
+
readDaemonState,
|
|
20
|
+
type TelegramDaemonFs,
|
|
21
|
+
} from "./telegram-daemon";
|
|
22
|
+
|
|
23
|
+
export type { TelegramActivationMarker, TelegramActivationMarkers, TelegramActivationReason, TelegramActivationState };
|
|
24
|
+
export { telegramActivationIdentity };
|
|
25
|
+
|
|
26
|
+
/** The identity relationship between a proposed Telegram configuration and a live daemon owner. */
|
|
27
|
+
export type ProposedTelegramIdentityStatus = "absent" | "same" | "foreign" | "unknown";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Non-secret metadata about a daemon owner. Token fingerprints and the owner's
|
|
31
|
+
* chat ID intentionally never cross this boundary. `chatDisplay`, when present,
|
|
32
|
+
* is supplied by the caller from an already-approved proposed-chat display.
|
|
33
|
+
*/
|
|
34
|
+
export interface TelegramDaemonOwnerMetadata {
|
|
35
|
+
ownerId: string;
|
|
36
|
+
pid: number;
|
|
37
|
+
generation?: number;
|
|
38
|
+
chatDisplay?: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Secret-safe proposed-identity preflight outcome. */
|
|
42
|
+
export interface ProposedTelegramIdentity {
|
|
43
|
+
status: ProposedTelegramIdentityStatus;
|
|
44
|
+
owner?: TelegramDaemonOwnerMetadata;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface ProposedTelegramIdentityPreflightInput {
|
|
48
|
+
settings: NotificationSettingsReader;
|
|
49
|
+
botToken: string;
|
|
50
|
+
chatId: string;
|
|
51
|
+
/** A UI-approved display value for the proposed chat; never inferred from a foreign daemon state. */
|
|
52
|
+
chatDisplay?: string;
|
|
53
|
+
deps?: {
|
|
54
|
+
fs?: TelegramDaemonFs;
|
|
55
|
+
pidAlive?: (pid: number) => boolean;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function defaultPidAlive(pid: number): boolean {
|
|
60
|
+
try {
|
|
61
|
+
process.kill(pid, 0);
|
|
62
|
+
return true;
|
|
63
|
+
} catch (error) {
|
|
64
|
+
return (error as NodeJS.ErrnoException).code === "EPERM";
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function validPositiveInteger(value: unknown): value is number {
|
|
69
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function validGeneration(value: unknown): value is number | undefined {
|
|
73
|
+
return value === undefined || (typeof value === "number" && Number.isSafeInteger(value) && value >= 0);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Compare a proposed identity with the current daemon owner without exposing a
|
|
78
|
+
* token or token fingerprint. Invalid/unreadable state is deliberately
|
|
79
|
+
* `unknown`, which callers must treat as cancel-by-default.
|
|
80
|
+
*/
|
|
81
|
+
export async function proposedTelegramIdentity(
|
|
82
|
+
input: ProposedTelegramIdentityPreflightInput,
|
|
83
|
+
): Promise<ProposedTelegramIdentity> {
|
|
84
|
+
if (!hasNonBlankValue(input.botToken) || !hasNonBlankValue(input.chatId)) return { status: "unknown" };
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const state = await readDaemonState(input.settings, input.deps?.fs);
|
|
88
|
+
if (!state) return { status: "absent" };
|
|
89
|
+
|
|
90
|
+
const metadata =
|
|
91
|
+
typeof state.ownerId === "string" &&
|
|
92
|
+
state.ownerId.trim().length > 0 &&
|
|
93
|
+
validPositiveInteger(state.pid) &&
|
|
94
|
+
validGeneration(state.generation)
|
|
95
|
+
? {
|
|
96
|
+
ownerId: state.ownerId,
|
|
97
|
+
pid: state.pid,
|
|
98
|
+
...(state.generation === undefined ? {} : { generation: state.generation }),
|
|
99
|
+
}
|
|
100
|
+
: undefined;
|
|
101
|
+
if (
|
|
102
|
+
!metadata ||
|
|
103
|
+
state.version !== DAEMON_VERSION ||
|
|
104
|
+
typeof state.tokenFingerprint !== "string" ||
|
|
105
|
+
typeof state.chatId !== "string"
|
|
106
|
+
) {
|
|
107
|
+
return metadata ? { status: "unknown", owner: metadata } : { status: "unknown" };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const pidAlive = input.deps?.pidAlive ?? defaultPidAlive;
|
|
111
|
+
if (!pidAlive(metadata.pid)) return { status: "absent" };
|
|
112
|
+
|
|
113
|
+
if (state.tokenFingerprint === tokenFingerprint(input.botToken) && state.chatId === input.chatId) {
|
|
114
|
+
return {
|
|
115
|
+
status: "same",
|
|
116
|
+
owner: input.chatDisplay === undefined ? metadata : { ...metadata, chatDisplay: input.chatDisplay },
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
return { status: "foreign", owner: metadata };
|
|
120
|
+
} catch {
|
|
121
|
+
return { status: "unknown" };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export interface NotificationConfigurationWriter extends NotificationSettingsReader {
|
|
126
|
+
commitAtomicBatch(patches: readonly SettingsAtomicPatch[]): Promise<SettingsAtomicReceipt>;
|
|
127
|
+
commitAtomicBatchWithCurrent?(
|
|
128
|
+
buildPatches: (
|
|
129
|
+
current: Readonly<RawSettings>,
|
|
130
|
+
) => Promise<readonly SettingsAtomicPatch[]> | readonly SettingsAtomicPatch[],
|
|
131
|
+
): Promise<SettingsAtomicReceipt>;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function createTelegramActivationMarker(input: {
|
|
135
|
+
botToken: string;
|
|
136
|
+
chatId: string;
|
|
137
|
+
state: TelegramActivationState;
|
|
138
|
+
reason?: TelegramActivationReason;
|
|
139
|
+
now?: Date;
|
|
140
|
+
}): TelegramActivationMarker {
|
|
141
|
+
return {
|
|
142
|
+
identity: telegramActivationIdentity(input.botToken, input.chatId),
|
|
143
|
+
state: input.state,
|
|
144
|
+
updatedAt: (input.now ?? new Date()).toISOString(),
|
|
145
|
+
...(input.reason === undefined ? {} : { reason: input.reason }),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function observedTelegramActivationMarker(
|
|
150
|
+
settings: NotificationSettingsReader,
|
|
151
|
+
botToken: string,
|
|
152
|
+
chatId: string,
|
|
153
|
+
): TelegramActivationMarker | undefined {
|
|
154
|
+
const identity = telegramActivationIdentity(botToken, chatId);
|
|
155
|
+
return readTelegramActivationMarkers(settings.getNotificationSettingsSnapshot().telegram.activation)[identity];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function activationMarkersFromCurrent(current: Readonly<RawSettings>): TelegramActivationMarkers {
|
|
159
|
+
const notifications = current.notifications;
|
|
160
|
+
if (!notifications || typeof notifications !== "object" || Array.isArray(notifications)) return {};
|
|
161
|
+
const telegram = (notifications as Record<string, unknown>).telegram;
|
|
162
|
+
if (!telegram || typeof telegram !== "object" || Array.isArray(telegram)) return {};
|
|
163
|
+
return readTelegramActivationMarkers((telegram as Record<string, unknown>).activation);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function commitNotificationBatchWithCurrent(
|
|
167
|
+
settings: NotificationConfigurationWriter,
|
|
168
|
+
buildPatches: (
|
|
169
|
+
current: Readonly<RawSettings>,
|
|
170
|
+
) => Promise<readonly SettingsAtomicPatch[]> | readonly SettingsAtomicPatch[],
|
|
171
|
+
): Promise<SettingsAtomicReceipt> {
|
|
172
|
+
if (settings.commitAtomicBatchWithCurrent) return settings.commitAtomicBatchWithCurrent(buildPatches);
|
|
173
|
+
const snapshot = settings.getNotificationSettingsSnapshot();
|
|
174
|
+
const current: RawSettings = {
|
|
175
|
+
notifications: {
|
|
176
|
+
telegram: {
|
|
177
|
+
activation: snapshot.telegram.activation,
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
return settings.commitAtomicBatch(await buildPatches(current));
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function sameActivationMarker(left: TelegramActivationMarker, right: TelegramActivationMarker): boolean {
|
|
185
|
+
return (
|
|
186
|
+
left.identity === right.identity &&
|
|
187
|
+
left.state === right.state &&
|
|
188
|
+
left.updatedAt === right.updatedAt &&
|
|
189
|
+
left.reason === right.reason
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** Persist one durable marker without discarding markers for other identities. */
|
|
194
|
+
export async function persistTelegramActivationMarker(
|
|
195
|
+
settings: NotificationConfigurationWriter,
|
|
196
|
+
marker: TelegramActivationMarker,
|
|
197
|
+
): Promise<SettingsAtomicReceipt> {
|
|
198
|
+
return await commitNotificationBatchWithCurrent(settings, current => {
|
|
199
|
+
const markers = activationMarkersFromCurrent(current);
|
|
200
|
+
markers[marker.identity] = { ...marker };
|
|
201
|
+
return [{ path: "notifications.telegram.activation", op: "set", value: markers }];
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** Clear only the exact marker that was safely reconciled. */
|
|
206
|
+
export async function clearTelegramActivationMarker(
|
|
207
|
+
settings: NotificationConfigurationWriter,
|
|
208
|
+
marker: TelegramActivationMarker,
|
|
209
|
+
): Promise<void> {
|
|
210
|
+
const receipt = await commitNotificationBatchWithCurrent(settings, current => {
|
|
211
|
+
const markers = activationMarkersFromCurrent(current);
|
|
212
|
+
const stored = markers[marker.identity];
|
|
213
|
+
if (!stored || !sameActivationMarker(stored, marker)) return [];
|
|
214
|
+
delete markers[marker.identity];
|
|
215
|
+
return Object.keys(markers).length === 0
|
|
216
|
+
? [{ path: "notifications.telegram.activation", op: "unset" }]
|
|
217
|
+
: [{ path: "notifications.telegram.activation", op: "set", value: markers }];
|
|
218
|
+
});
|
|
219
|
+
receipt.discard();
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export type CompleteNonTelegramAdapter = "discord" | "slack";
|
|
223
|
+
|
|
224
|
+
function completeNonTelegramAdapters(snapshot: NotificationSettingsSnapshot): CompleteNonTelegramAdapter[] {
|
|
225
|
+
if (!snapshot.enabled) return [];
|
|
226
|
+
const adapters: CompleteNonTelegramAdapter[] = [];
|
|
227
|
+
if (
|
|
228
|
+
hasNonBlankValue(snapshot.discord.botToken) &&
|
|
229
|
+
hasNonBlankValue(snapshot.discord.applicationId) &&
|
|
230
|
+
hasNonBlankValue(snapshot.discord.guildId) &&
|
|
231
|
+
hasNonBlankValue(snapshot.discord.parentChannelId)
|
|
232
|
+
) {
|
|
233
|
+
adapters.push("discord");
|
|
234
|
+
}
|
|
235
|
+
if (
|
|
236
|
+
hasNonBlankValue(snapshot.slack.botToken) &&
|
|
237
|
+
hasNonBlankValue(snapshot.slack.appToken) &&
|
|
238
|
+
hasNonBlankValue(snapshot.slack.workspaceId) &&
|
|
239
|
+
hasNonBlankValue(snapshot.slack.channelId)
|
|
240
|
+
) {
|
|
241
|
+
adapters.push("slack");
|
|
242
|
+
}
|
|
243
|
+
return adapters;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export type SaveTelegramInactiveAvailability = { available: true };
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Telegram-specific activation markers let Save inactive preserve globally
|
|
250
|
+
* enabled Discord and Slack adapters, so the action is always available.
|
|
251
|
+
*/
|
|
252
|
+
export function getSaveTelegramInactiveAvailability(
|
|
253
|
+
_settings: NotificationSettingsReader,
|
|
254
|
+
): SaveTelegramInactiveAvailability {
|
|
255
|
+
return { available: true };
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export type SaveTelegramInactiveResult = { status: "saved_inactive"; receipt: SettingsAtomicReceipt };
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Atomically persist Telegram credentials with a non-secret inactive marker.
|
|
262
|
+
* Global notifications are disabled only when Telegram is the sole complete adapter.
|
|
263
|
+
*/
|
|
264
|
+
export async function saveTelegramInactive(input: {
|
|
265
|
+
settings: NotificationConfigurationWriter;
|
|
266
|
+
botToken: string;
|
|
267
|
+
chatId: string;
|
|
268
|
+
}): Promise<SaveTelegramInactiveResult> {
|
|
269
|
+
if (!hasNonBlankValue(input.botToken) || !hasNonBlankValue(input.chatId)) {
|
|
270
|
+
throw new TypeError("Saving inactive Telegram configuration requires a non-blank token and chat ID.");
|
|
271
|
+
}
|
|
272
|
+
const snapshot = input.settings.getNotificationSettingsSnapshot();
|
|
273
|
+
const marker = createTelegramActivationMarker({
|
|
274
|
+
botToken: input.botToken,
|
|
275
|
+
chatId: input.chatId,
|
|
276
|
+
state: "inactive",
|
|
277
|
+
reason: "saved_inactive",
|
|
278
|
+
});
|
|
279
|
+
const receipt = await commitNotificationBatchWithCurrent(input.settings, current => {
|
|
280
|
+
const markers = activationMarkersFromCurrent(current);
|
|
281
|
+
markers[marker.identity] = marker;
|
|
282
|
+
const patches: SettingsAtomicPatch[] = [
|
|
283
|
+
{ path: "notifications.telegram.botToken", op: "set", value: input.botToken },
|
|
284
|
+
{ path: "notifications.telegram.chatId", op: "set", value: input.chatId },
|
|
285
|
+
{ path: "notifications.telegram.activation", op: "set", value: markers },
|
|
286
|
+
];
|
|
287
|
+
if (completeNonTelegramAdapters(snapshot).length === 0) {
|
|
288
|
+
patches.push({ path: "notifications.enabled", op: "set", value: false });
|
|
289
|
+
}
|
|
290
|
+
return patches;
|
|
291
|
+
});
|
|
292
|
+
return { status: "saved_inactive", receipt };
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export interface TelegramRemovalRuntime {
|
|
296
|
+
/** Stops the local endpoint, unregisters its root, and stops an unreferenced old daemon. */
|
|
297
|
+
stopAndUnregister(): Promise<void>;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Remove Telegram credentials without disturbing other adapters. Runtime
|
|
302
|
+
* teardown is intentionally first: a failed teardown leaves durable credentials
|
|
303
|
+
* untouched rather than orphaning an old daemon/root behind a successful delete.
|
|
304
|
+
*/
|
|
305
|
+
export async function removeTelegramConfiguration(input: {
|
|
306
|
+
settings: NotificationConfigurationWriter;
|
|
307
|
+
removal: TelegramRemovalRuntime;
|
|
308
|
+
}): Promise<{ receipt: SettingsAtomicReceipt; globallyDisabled: boolean }> {
|
|
309
|
+
const cfg = getNotificationConfig(input.settings);
|
|
310
|
+
const otherAdapterRemains =
|
|
311
|
+
(hasNonBlankValue(cfg.discord.botToken) &&
|
|
312
|
+
hasNonBlankValue(cfg.discord.applicationId) &&
|
|
313
|
+
hasNonBlankValue(cfg.discord.guildId) &&
|
|
314
|
+
hasNonBlankValue(cfg.discord.parentChannelId)) ||
|
|
315
|
+
(hasNonBlankValue(cfg.slack.botToken) &&
|
|
316
|
+
hasNonBlankValue(cfg.slack.appToken) &&
|
|
317
|
+
hasNonBlankValue(cfg.slack.workspaceId) &&
|
|
318
|
+
hasNonBlankValue(cfg.slack.channelId));
|
|
319
|
+
await input.removal.stopAndUnregister();
|
|
320
|
+
const patches: SettingsAtomicPatch[] = [
|
|
321
|
+
{ path: "notifications.telegram.botToken", op: "unset" },
|
|
322
|
+
{ path: "notifications.telegram.chatId", op: "unset" },
|
|
323
|
+
{ path: "notifications.telegram.activation", op: "unset" },
|
|
324
|
+
];
|
|
325
|
+
if (!otherAdapterRemains) patches.push({ path: "notifications.enabled", op: "set", value: false });
|
|
326
|
+
const receipt = await input.settings.commitAtomicBatch(patches);
|
|
327
|
+
return { receipt, globallyDisabled: !otherAdapterRemains };
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/** Detailed outcome of checking or reconnecting the Telegram daemon after a durable commit. */
|
|
331
|
+
export type TelegramDaemonReconnectOutcome = EnsureTelegramDaemonDetailedResult;
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* The session controller must not resolve `enterBlockedRuntime` until its
|
|
335
|
+
* current endpoint has stopped and been removed. This lets callers report a
|
|
336
|
+
* blocked save only after no further frames can reach the foreign owner.
|
|
337
|
+
*/
|
|
338
|
+
export interface NotificationRuntimeController {
|
|
339
|
+
/** Resolves only after the current endpoint is stopped and removed. */
|
|
340
|
+
enterBlockedRuntime(): Promise<unknown>;
|
|
341
|
+
clearBlockedRuntime(): Promise<unknown>;
|
|
342
|
+
reconcileCurrentSession(): Promise<unknown>;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
export interface TelegramPostCommitActivation {
|
|
346
|
+
controller: NotificationRuntimeController;
|
|
347
|
+
reconnect: () => Promise<TelegramDaemonReconnectOutcome>;
|
|
348
|
+
/** Durable Telegram-only marker write after the endpoint has stopped. */
|
|
349
|
+
persistInactive(marker: TelegramActivationMarker): Promise<SettingsAtomicReceipt>;
|
|
350
|
+
/** Remove the exact activation marker only after a safe reconnect. */
|
|
351
|
+
clearInactive(marker: TelegramActivationMarker): Promise<void>;
|
|
352
|
+
marker: TelegramActivationMarker;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
export type PostCommitTelegramActivationResult =
|
|
356
|
+
| { status: "activated"; reconnect: Exclude<TelegramDaemonReconnectOutcome, "blocked_identity"> }
|
|
357
|
+
| {
|
|
358
|
+
status: "blocked_identity";
|
|
359
|
+
message: string;
|
|
360
|
+
restore(): Promise<BlockedTelegramRestoreResult>;
|
|
361
|
+
retainCommitted(): void;
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
export type BlockedTelegramRestoreResult =
|
|
365
|
+
| { status: "restored"; reconnect: TelegramDaemonReconnectOutcome }
|
|
366
|
+
| { status: "conflict"; paths: readonly string[] }
|
|
367
|
+
| { status: "discarded" }
|
|
368
|
+
| { status: "still_blocked" };
|
|
369
|
+
|
|
370
|
+
async function restoreBlockedConfiguration(input: {
|
|
371
|
+
receipt: SettingsAtomicReceipt;
|
|
372
|
+
inactiveReceipt: SettingsAtomicReceipt;
|
|
373
|
+
activation: TelegramPostCommitActivation;
|
|
374
|
+
}): Promise<BlockedTelegramRestoreResult> {
|
|
375
|
+
const retainBlockedMarker = async (): Promise<void> => {
|
|
376
|
+
const receipt = await input.activation.persistInactive(input.activation.marker);
|
|
377
|
+
receipt.discard();
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
let restored: CasRestoreResult;
|
|
381
|
+
try {
|
|
382
|
+
restored = await input.receipt.restore();
|
|
383
|
+
} catch (error) {
|
|
384
|
+
await retainBlockedMarker();
|
|
385
|
+
throw error;
|
|
386
|
+
}
|
|
387
|
+
if (restored.status === "conflict" || restored.status === "discarded") {
|
|
388
|
+
await retainBlockedMarker();
|
|
389
|
+
return restored;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Keep the fail-closed marker durable until the configuration rollback has
|
|
393
|
+
// completed. Removing it first exposes the blocked identity between two CAS
|
|
394
|
+
// operations to other processes.
|
|
395
|
+
let inactiveRestored: CasRestoreResult;
|
|
396
|
+
try {
|
|
397
|
+
inactiveRestored = await input.inactiveReceipt.restore();
|
|
398
|
+
} catch (error) {
|
|
399
|
+
await retainBlockedMarker();
|
|
400
|
+
throw error;
|
|
401
|
+
}
|
|
402
|
+
if (inactiveRestored.status === "conflict" || inactiveRestored.status === "discarded") {
|
|
403
|
+
await retainBlockedMarker();
|
|
404
|
+
await input.activation.controller.enterBlockedRuntime();
|
|
405
|
+
return { status: "still_blocked" };
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const reconnect = await input.activation.reconnect();
|
|
409
|
+
if (reconnect === "blocked_identity") {
|
|
410
|
+
await input.activation.controller.enterBlockedRuntime();
|
|
411
|
+
return { status: "still_blocked" };
|
|
412
|
+
}
|
|
413
|
+
await input.activation.controller.clearBlockedRuntime();
|
|
414
|
+
await input.activation.controller.reconcileCurrentSession();
|
|
415
|
+
return { status: "restored", reconnect };
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Complete a committed Telegram update in the required order: identity
|
|
420
|
+
* reconnect first, normal session reconciliation second. A post-commit foreign
|
|
421
|
+
* owner race stops the endpoint, durably marks only that Telegram identity
|
|
422
|
+
* inactive, then exposes an ordered CAS restore/retain choice.
|
|
423
|
+
*/
|
|
424
|
+
export async function reconcileCommittedTelegramConfiguration(input: {
|
|
425
|
+
receipt: SettingsAtomicReceipt;
|
|
426
|
+
activation: TelegramPostCommitActivation;
|
|
427
|
+
inactiveMarkerToClear?: TelegramActivationMarker;
|
|
428
|
+
}): Promise<PostCommitTelegramActivationResult> {
|
|
429
|
+
const reconnect = await input.activation.reconnect();
|
|
430
|
+
if (reconnect === "blocked_identity") {
|
|
431
|
+
await input.activation.controller.enterBlockedRuntime();
|
|
432
|
+
const inactiveReceipt = await input.activation.persistInactive(input.activation.marker);
|
|
433
|
+
return {
|
|
434
|
+
status: "blocked_identity",
|
|
435
|
+
message:
|
|
436
|
+
"Configuration saved inactive; activation blocked; foreign daemon untouched. Current session stopped because Telegram activation was blocked by a foreign daemon.",
|
|
437
|
+
restore: () => restoreBlockedConfiguration({ ...input, inactiveReceipt }),
|
|
438
|
+
retainCommitted: () => {
|
|
439
|
+
inactiveReceipt.discard();
|
|
440
|
+
input.receipt.discard();
|
|
441
|
+
},
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (input.inactiveMarkerToClear) {
|
|
446
|
+
try {
|
|
447
|
+
await input.activation.clearInactive(input.inactiveMarkerToClear);
|
|
448
|
+
} catch (error) {
|
|
449
|
+
await input.activation.controller.enterBlockedRuntime();
|
|
450
|
+
throw error;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
await input.activation.controller.clearBlockedRuntime();
|
|
454
|
+
await input.activation.controller.reconcileCurrentSession();
|
|
455
|
+
return { status: "activated", reconnect };
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
export type SaveTelegramConfigurationResult =
|
|
459
|
+
| { status: "cancelled"; preflight: ProposedTelegramIdentity; guidance: string }
|
|
460
|
+
| SaveTelegramInactiveResult
|
|
461
|
+
| { status: "saved"; receipt: SettingsAtomicReceipt; preflight: ProposedTelegramIdentity }
|
|
462
|
+
| PostCommitTelegramActivationResult;
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Guard a Telegram setup commit with proposed-identity preflight. Foreign and
|
|
466
|
+
* unreadable ownership are cancel-by-default and make no configuration changes.
|
|
467
|
+
*/
|
|
468
|
+
export async function saveTelegramConfiguration(input: {
|
|
469
|
+
settings: NotificationConfigurationWriter;
|
|
470
|
+
botToken: string;
|
|
471
|
+
chatId: string;
|
|
472
|
+
chatDisplay?: string;
|
|
473
|
+
/** Explicitly persist credentials disabled after a foreign/unknown preflight; otherwise cancel remains the default. */
|
|
474
|
+
saveInactive: boolean;
|
|
475
|
+
preflight?: (input: Omit<ProposedTelegramIdentityPreflightInput, "settings">) => Promise<ProposedTelegramIdentity>;
|
|
476
|
+
activation?: TelegramPostCommitActivation;
|
|
477
|
+
}): Promise<SaveTelegramConfigurationResult> {
|
|
478
|
+
if (!hasNonBlankValue(input.botToken) || !hasNonBlankValue(input.chatId)) {
|
|
479
|
+
throw new TypeError("Saving Telegram configuration requires a non-blank token and chat ID.");
|
|
480
|
+
}
|
|
481
|
+
const runPreflight =
|
|
482
|
+
input.preflight ??
|
|
483
|
+
((next: Omit<ProposedTelegramIdentityPreflightInput, "settings">) =>
|
|
484
|
+
proposedTelegramIdentity({ settings: input.settings, ...next }));
|
|
485
|
+
const preflight = await runPreflight({
|
|
486
|
+
botToken: input.botToken,
|
|
487
|
+
chatId: input.chatId,
|
|
488
|
+
chatDisplay: input.chatDisplay,
|
|
489
|
+
});
|
|
490
|
+
if (preflight.status === "foreign" || preflight.status === "unknown") {
|
|
491
|
+
// Cancel is the default for an untrusted owner. `saveInactive` is an
|
|
492
|
+
// explicit user selection that cannot activate the proposed identity.
|
|
493
|
+
if (input.saveInactive) return await saveTelegramInactive(input);
|
|
494
|
+
return {
|
|
495
|
+
status: "cancelled",
|
|
496
|
+
preflight,
|
|
497
|
+
guidance:
|
|
498
|
+
"Telegram activation was not saved. Cancel or retry after the daemon owner exits or is reconfigured.",
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
if (input.saveInactive) return await saveTelegramInactive(input);
|
|
503
|
+
|
|
504
|
+
const activeIdentity = telegramActivationIdentity(input.botToken, input.chatId);
|
|
505
|
+
const inactiveMarkerToClear = observedTelegramActivationMarker(input.settings, input.botToken, input.chatId);
|
|
506
|
+
const receipt = await commitNotificationBatchWithCurrent(input.settings, current => {
|
|
507
|
+
const patches: SettingsAtomicPatch[] = [
|
|
508
|
+
{ path: "notifications.telegram.botToken", op: "set", value: input.botToken },
|
|
509
|
+
{ path: "notifications.telegram.chatId", op: "set", value: input.chatId },
|
|
510
|
+
{ path: "notifications.enabled", op: "set", value: true },
|
|
511
|
+
];
|
|
512
|
+
// With post-commit activation, the marker has its own receipt so a blocked
|
|
513
|
+
// rollback can restore configuration without self-conflicting on the marker
|
|
514
|
+
// written after this commit. Successful activation clears that marker only
|
|
515
|
+
// after owner readiness is proved.
|
|
516
|
+
if (!input.activation) {
|
|
517
|
+
const markers = activationMarkersFromCurrent(current);
|
|
518
|
+
delete markers[activeIdentity];
|
|
519
|
+
patches.splice(
|
|
520
|
+
2,
|
|
521
|
+
0,
|
|
522
|
+
Object.keys(markers).length === 0
|
|
523
|
+
? { path: "notifications.telegram.activation", op: "unset" }
|
|
524
|
+
: { path: "notifications.telegram.activation", op: "set", value: markers },
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
return patches;
|
|
528
|
+
});
|
|
529
|
+
if (!input.activation) return { status: "saved", receipt, preflight };
|
|
530
|
+
return await reconcileCommittedTelegramConfiguration({
|
|
531
|
+
receipt,
|
|
532
|
+
activation: input.activation,
|
|
533
|
+
inactiveMarkerToClear,
|
|
534
|
+
});
|
|
535
|
+
}
|