@gajae-code/coding-agent 0.11.1 → 0.11.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +64 -0
- package/dist/types/cli/config-cli.d.ts +11 -1
- package/dist/types/cli/launch-disposition.d.ts +23 -0
- package/dist/types/cli/notify-cli.d.ts +1 -0
- package/dist/types/cli/session-picker.d.ts +2 -1
- package/dist/types/cli/setup-cli.d.ts +1 -1
- package/dist/types/commands/mcp-serve.d.ts +33 -0
- package/dist/types/commands/mcp.d.ts +1 -1
- package/dist/types/commands/notify.d.ts +0 -2
- package/dist/types/commands/sdk.d.ts +1 -1
- package/dist/types/config/atomic-yaml-patch.d.ts +18 -0
- package/dist/types/config/file-lock.d.ts +14 -4
- package/dist/types/config/keybindings.d.ts +42 -1
- package/dist/types/config/model-auth.d.ts +3 -0
- package/dist/types/config/model-bindings-applier.d.ts +13 -0
- package/dist/types/config/model-discovery-manager.d.ts +49 -0
- package/dist/types/config/model-equivalence.d.ts +20 -0
- package/dist/types/config/model-registry.d.ts +16 -15
- package/dist/types/config/model-resolver.d.ts +28 -18
- package/dist/types/config/models-config-schema.d.ts +11 -0
- package/dist/types/config/settings-schema.d.ts +141 -11
- package/dist/types/config/settings.d.ts +14 -11
- package/dist/types/coordinator-mcp/policy.d.ts +5 -0
- package/dist/types/coordinator-mcp/question-gate-codec.d.ts +129 -0
- package/dist/types/coordinator-mcp/question-state.d.ts +356 -0
- package/dist/types/coordinator-mcp/server.d.ts +4 -0
- package/dist/types/discovery/helpers.d.ts +0 -6
- package/dist/types/edit/index.d.ts +3 -0
- package/dist/types/eval/py/env.d.ts +9 -0
- package/dist/types/extensibility/extensions/loader.d.ts +2 -1
- package/dist/types/extensibility/extensions/runner.d.ts +2 -2
- package/dist/types/extensibility/extensions/types.d.ts +34 -3
- package/dist/types/extensibility/hooks/runner.d.ts +1 -1
- package/dist/types/extensibility/shared-events.d.ts +2 -0
- package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +10 -1
- package/dist/types/gjc-runtime/deep-interview-state.d.ts +44 -0
- package/dist/types/gjc-runtime/goal-mode-request.d.ts +11 -1
- package/dist/types/gjc-runtime/launch-worktree.d.ts +4 -2
- package/dist/types/gjc-runtime/linux-proc.d.ts +29 -0
- package/dist/types/gjc-runtime/session-resolution.d.ts +2 -2
- package/dist/types/gjc-runtime/state-migrations.d.ts +1 -1
- package/dist/types/gjc-runtime/state-writer.d.ts +2 -1
- package/dist/types/gjc-runtime/team-launch.d.ts +59 -0
- package/dist/types/gjc-runtime/team-notify.d.ts +45 -0
- package/dist/types/gjc-runtime/team-runtime.d.ts +29 -121
- package/dist/types/gjc-runtime/team-store.d.ts +160 -0
- package/dist/types/gjc-runtime/team-workers.d.ts +78 -0
- package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +8 -0
- package/dist/types/gjc-runtime/ultragoal-change-set.d.ts +13 -0
- package/dist/types/gjc-runtime/ultragoal-evidence.d.ts +38 -0
- package/dist/types/gjc-runtime/ultragoal-guard.d.ts +7 -0
- package/dist/types/gjc-runtime/ultragoal-pipeline.d.ts +23 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +55 -33
- package/dist/types/gjc-runtime/workflow-cli-common.d.ts +8 -0
- package/dist/types/gjc-runtime/workflow-manifest.d.ts +3 -0
- package/dist/types/goals/continuation-timeout-guard.d.ts +22 -0
- package/dist/types/goals/runtime.d.ts +1 -0
- package/dist/types/goals/state.d.ts +8 -0
- package/dist/types/harness-control-plane/lifecycle-reconciliation.d.ts +17 -0
- package/dist/types/harness-control-plane/phase-rollup.d.ts +4 -7
- package/dist/types/harness-control-plane/receipt-ingest.d.ts +5 -0
- package/dist/types/harness-control-plane/receipt-spool.d.ts +4 -0
- package/dist/types/hindsight/state.d.ts +11 -4
- package/dist/types/lsp/lspmux.d.ts +5 -3
- package/dist/types/lsp/path-trust.d.ts +1 -0
- package/dist/types/main.d.ts +4 -2
- package/dist/types/memories/storage.d.ts +1 -0
- package/dist/types/modes/action-registry.d.ts +29 -0
- package/dist/types/modes/components/chrome.d.ts +14 -0
- package/dist/types/modes/components/command-palette.d.ts +27 -0
- package/dist/types/modes/components/custom-provider-wizard.d.ts +1 -0
- package/dist/types/modes/components/index.d.ts +2 -1
- package/dist/types/modes/components/pet-selector.d.ts +1 -1
- package/dist/types/modes/components/plan-preview-overlay.d.ts +43 -0
- package/dist/types/modes/components/queue-mode-selector.d.ts +1 -1
- package/dist/types/modes/components/queue-pane.d.ts +12 -0
- package/dist/types/modes/components/read-tool-group.d.ts +6 -0
- package/dist/types/modes/components/session-observer-overlay.d.ts +3 -4
- package/dist/types/modes/components/sessions-dashboard.d.ts +32 -0
- package/dist/types/modes/components/settings-selector.d.ts +1 -1
- package/dist/types/modes/components/show-images-selector.d.ts +1 -1
- package/dist/types/modes/components/status-line/types.d.ts +1 -1
- package/dist/types/modes/components/status-line.d.ts +1 -94
- package/dist/types/modes/components/tasks-pane.d.ts +15 -0
- package/dist/types/modes/components/theme-selector.d.ts +1 -1
- package/dist/types/modes/components/tool-execution.d.ts +15 -0
- package/dist/types/modes/components/tool-status-header.d.ts +111 -0
- package/dist/types/modes/components/transcript-viewer-overlay.d.ts +42 -0
- package/dist/types/modes/controllers/goal-mode-controller.d.ts +62 -0
- package/dist/types/modes/controllers/input-controller.d.ts +8 -1
- package/dist/types/modes/controllers/mode-gate.d.ts +8 -0
- package/dist/types/modes/controllers/plan-mode-controller.d.ts +65 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +15 -3
- package/dist/types/modes/controllers/stt-controller.d.ts +26 -0
- package/dist/types/modes/interactive-mode.d.ts +19 -17
- package/dist/types/modes/jobs-observer.d.ts +2 -0
- package/dist/types/modes/prompt-action-autocomplete.d.ts +4 -0
- package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +4 -11
- package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +20 -2
- package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +31 -0
- package/dist/types/modes/tasks-aggregator.d.ts +39 -0
- package/dist/types/modes/transcript-item-registry.d.ts +60 -0
- package/dist/types/modes/types.d.ts +20 -13
- package/dist/types/modes/utils/ui-helpers.d.ts +2 -2
- package/dist/types/runtime-mcp/manager.d.ts +1 -1
- package/dist/types/sdk/broker/broker.d.ts +78 -12
- package/dist/types/sdk/broker/lifecycle-codec.d.ts +4 -0
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +15 -1
- package/dist/types/sdk/broker/lifecycle.d.ts +6 -2
- package/dist/types/sdk/broker/process-incarnation.d.ts +2 -0
- package/dist/types/sdk/broker/session-index.d.ts +0 -1
- package/dist/types/sdk/broker/state-version.d.ts +2 -0
- package/dist/types/sdk/bus/chat-effect-journal.d.ts +1 -0
- package/dist/types/sdk/bus/config-commands.d.ts +1 -1
- package/dist/types/sdk/bus/config.d.ts +11 -0
- package/dist/types/sdk/bus/daemon-paths.d.ts +1 -0
- package/dist/types/sdk/bus/html-format.d.ts +3 -2
- package/dist/types/sdk/bus/index.d.ts +29 -0
- package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +4 -0
- package/dist/types/sdk/bus/notification-service.d.ts +20 -0
- package/dist/types/sdk/bus/rate-limit-pool.d.ts +13 -2
- package/dist/types/sdk/bus/recent-activity.d.ts +21 -12
- package/dist/types/sdk/bus/rich-document.d.ts +7 -0
- package/dist/types/sdk/bus/rich-render.d.ts +18 -41
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +9 -4
- package/dist/types/sdk/bus/telegram-daemon.d.ts +46 -3
- package/dist/types/sdk/bus/threaded-inbound.d.ts +1 -1
- package/dist/types/sdk/bus/threaded-render.d.ts +13 -0
- package/dist/types/sdk/bus/topic-registry.d.ts +24 -2
- package/dist/types/sdk/host/control/operations.d.ts +1 -1
- package/dist/types/sdk/host/host.d.ts +2 -0
- package/dist/types/sdk/index.d.ts +1 -0
- package/dist/types/sdk/session-directory.d.ts +56 -0
- package/dist/types/sdk/session.d.ts +2 -0
- package/dist/types/session/agent-session.d.ts +82 -47
- package/dist/types/session/agent-storage.d.ts +7 -0
- package/dist/types/session/fallback-chain-controller.d.ts +10 -2
- package/dist/types/session/internal/managed-session-scope.d.ts +102 -0
- package/dist/types/session/internal/managed-session-storage.d.ts +38 -0
- package/dist/types/session/messages.d.ts +16 -0
- package/dist/types/session/session-manager-internal.d.ts +14 -0
- package/dist/types/session/session-manager.d.ts +82 -12
- package/dist/types/session/session-storage.d.ts +43 -3
- package/dist/types/session/volatile-context-pruning.d.ts +15 -0
- package/dist/types/skill-state/{deep-interview-mutation-guard.d.ts → workflow-mutation-guard.d.ts} +24 -8
- package/dist/types/skill-state/workflow-state-contract.d.ts +1 -3
- package/dist/types/slash-commands/builtin-registry.d.ts +4 -1
- package/dist/types/system-prompt.d.ts +2 -11
- package/dist/types/task/executor.d.ts +3 -1
- package/dist/types/thinking.d.ts +7 -0
- package/dist/types/tool-discovery/tool-index.d.ts +1 -50
- package/dist/types/tools/ask.d.ts +64 -2
- package/dist/types/tools/bash.d.ts +3 -0
- package/dist/types/tools/browser/dead-tab-recovery.d.ts +24 -0
- package/dist/types/tools/browser/tab-supervisor.d.ts +21 -0
- package/dist/types/tools/cron.d.ts +2 -0
- package/dist/types/tools/fetch.d.ts +1 -0
- package/dist/types/tools/index.d.ts +30 -15
- package/dist/types/tools/output-meta.d.ts +1 -0
- package/dist/types/tools/read.d.ts +5 -0
- package/dist/types/tools/search-tool-bm25.d.ts +3 -4
- package/dist/types/tools/subagent.d.ts +1 -0
- package/dist/types/utils/event-bus.d.ts +1 -1
- package/dist/types/utils/file-mentions.d.ts +3 -3
- package/dist/types/web/search/index.d.ts +3 -1
- package/package.json +21 -9
- package/scripts/build-sdk-package-smoke.ts +34 -1
- package/scripts/generate-hotkeys-docs.ts +74 -0
- package/scripts/generate-sdk-operation-inventory.ts +64 -20
- package/scripts/verify-gjc-sdk-canonicalization.ts +182 -2
- package/src/async/job-manager.ts +49 -6
- package/src/cli/config-cli.ts +75 -2
- package/src/cli/launch-disposition.ts +42 -0
- package/src/cli/notify-cli.ts +92 -26
- package/src/cli/session-picker.ts +20 -3
- package/src/cli/setup-cli.ts +1 -1
- package/src/cli.ts +1 -1
- package/src/commands/config.ts +1 -1
- package/src/commands/harness.ts +34 -106
- package/src/commands/launch.ts +6 -4
- package/src/commands/mcp-serve.ts +85 -8
- package/src/commands/mcp.ts +2 -2
- package/src/commands/notify.ts +8 -4
- package/src/commands/sdk.ts +61 -40
- package/src/commands/ultragoal.ts +4 -1
- package/src/config/atomic-yaml-patch.ts +80 -13
- package/src/config/file-lock.ts +105 -43
- package/src/config/keybindings.ts +64 -20
- package/src/config/model-auth.ts +9 -0
- package/src/config/model-bindings-applier.ts +139 -0
- package/src/config/model-discovery-manager.ts +224 -0
- package/src/config/model-equivalence.ts +66 -0
- package/src/config/model-registry.ts +169 -302
- package/src/config/model-resolver.ts +361 -369
- package/src/config/models-config-schema.ts +5 -4
- package/src/config/settings-schema.ts +214 -12
- package/src/config/settings.ts +458 -482
- package/src/coordinator-mcp/policy.ts +76 -11
- package/src/coordinator-mcp/question-gate-codec.ts +274 -0
- package/src/coordinator-mcp/question-state.ts +778 -0
- package/src/coordinator-mcp/server.ts +1702 -238
- package/src/debug/index.ts +1 -1
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +13 -1
- package/src/defaults/gjc/skills/team/SKILL.md +16 -0
- package/src/discovery/helpers.ts +1 -50
- package/src/edit/index.ts +64 -0
- package/src/eval/py/env.ts +26 -0
- package/src/eval/py/kernel.ts +5 -3
- package/src/extensibility/extensions/loader.ts +9 -1
- package/src/extensibility/extensions/runner.ts +12 -3
- package/src/extensibility/extensions/types.ts +39 -1
- package/src/extensibility/gjc-plugins/installer.ts +16 -16
- package/src/extensibility/hooks/runner.ts +2 -2
- package/src/extensibility/runtime-skill-discovery.ts +33 -13
- package/src/extensibility/shared-events.ts +2 -0
- package/src/gjc-runtime/deep-interview-recorder.ts +63 -3
- package/src/gjc-runtime/deep-interview-runtime.ts +76 -27
- package/src/gjc-runtime/deep-interview-state.ts +317 -5
- package/src/gjc-runtime/goal-mode-request.ts +55 -8
- package/src/gjc-runtime/launch-tmux.ts +2 -5
- package/src/gjc-runtime/launch-worktree.ts +5 -5
- package/src/gjc-runtime/linux-proc.ts +71 -0
- package/src/gjc-runtime/ralplan-runtime.ts +74 -90
- package/src/gjc-runtime/session-resolution.ts +18 -3
- package/src/gjc-runtime/session-state-sidecar.ts +6 -107
- package/src/gjc-runtime/state-migrations.ts +1 -1
- package/src/gjc-runtime/state-runtime.ts +327 -249
- package/src/gjc-runtime/state-writer.ts +36 -40
- package/src/gjc-runtime/team-launch.ts +319 -0
- package/src/gjc-runtime/team-notify.ts +326 -0
- package/src/gjc-runtime/team-runtime.ts +1099 -1482
- package/src/gjc-runtime/team-store.ts +828 -0
- package/src/gjc-runtime/team-workers.ts +962 -0
- package/src/gjc-runtime/tmux-owner-isolation-cli.ts +2 -11
- package/src/gjc-runtime/tmux-owner-isolation.ts +14 -9
- package/src/gjc-runtime/tmux-sessions.ts +4 -21
- package/src/gjc-runtime/ultragoal-change-set.ts +172 -0
- package/src/gjc-runtime/ultragoal-evidence.ts +874 -0
- package/src/gjc-runtime/ultragoal-guard.ts +29 -5
- package/src/gjc-runtime/ultragoal-pipeline.ts +306 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +84 -1311
- package/src/gjc-runtime/workflow-cli-common.ts +30 -0
- package/src/gjc-runtime/workflow-manifest.generated.json +58 -0
- package/src/gjc-runtime/workflow-manifest.ts +18 -0
- package/src/goals/continuation-timeout-guard.ts +79 -0
- package/src/goals/runtime.ts +7 -5
- package/src/goals/state.ts +18 -0
- package/src/harness-control-plane/lifecycle-reconciliation.ts +64 -0
- package/src/harness-control-plane/phase-rollup.ts +4 -7
- package/src/harness-control-plane/receipt-ingest.ts +5 -0
- package/src/harness-control-plane/receipt-spool.ts +51 -7
- package/src/harness-control-plane/session-lease.ts +12 -130
- package/src/hindsight/backend.ts +26 -27
- package/src/hindsight/state.ts +101 -32
- package/src/hooks/skill-state.ts +17 -11
- package/src/internal-urls/docs-index.generated.ts +21 -18
- package/src/lsp/client.ts +1 -1
- package/src/lsp/config.ts +145 -26
- package/src/lsp/index.ts +1 -1
- package/src/lsp/lspmux.ts +39 -10
- package/src/lsp/path-trust.ts +81 -0
- package/src/main.ts +127 -30
- package/src/memories/index.ts +1 -0
- package/src/memories/storage.ts +6 -2
- package/src/modes/action-registry.ts +165 -0
- package/src/modes/components/chrome.ts +40 -0
- package/src/modes/components/command-palette.ts +168 -0
- package/src/modes/components/custom-editor.ts +1 -1
- package/src/modes/components/custom-provider-wizard.ts +51 -14
- package/src/modes/components/index.ts +2 -1
- package/src/modes/components/pet-selector.ts +11 -17
- package/src/modes/components/plan-preview-overlay.ts +295 -0
- package/src/modes/components/queue-mode-selector.ts +10 -27
- package/src/modes/components/queue-pane.ts +79 -0
- package/src/modes/components/read-tool-group.ts +13 -0
- package/src/modes/components/session-observer-overlay.ts +207 -772
- package/src/modes/components/sessions-dashboard.ts +181 -0
- package/src/modes/components/settings-selector.ts +1 -1
- package/src/modes/components/show-images-selector.ts +10 -24
- package/src/modes/components/status-line/types.ts +1 -1
- package/src/modes/components/status-line.ts +1 -969
- package/src/modes/components/tasks-pane.ts +73 -0
- package/src/modes/components/theme-selector.ts +11 -31
- package/src/modes/components/tool-execution.ts +22 -0
- package/src/modes/components/tool-status-header.ts +1056 -0
- package/src/modes/components/transcript-viewer-overlay.ts +384 -0
- package/src/modes/controllers/btw-controller.ts +1 -0
- package/src/modes/controllers/event-controller.ts +3 -2
- package/src/modes/controllers/extension-ui-controller.ts +24 -1
- package/src/modes/controllers/goal-mode-controller.ts +474 -0
- package/src/modes/controllers/input-controller.ts +764 -229
- package/src/modes/controllers/mode-gate.ts +24 -0
- package/src/modes/controllers/plan-mode-controller.ts +517 -0
- package/src/modes/controllers/selector-controller.ts +225 -10
- package/src/modes/controllers/stt-controller.ts +125 -0
- package/src/modes/interactive-mode.ts +289 -1150
- package/src/modes/jobs-observer.ts +3 -0
- package/src/modes/prompt-action-autocomplete.ts +7 -0
- package/src/modes/runtime-init.ts +8 -0
- package/src/modes/shared/agent-wire/deep-interview-gate.ts +31 -106
- package/src/modes/shared/agent-wire/workflow-gate-broker.ts +71 -16
- package/src/modes/shared/agent-wire/workflow-gate-types.ts +177 -0
- package/src/modes/tasks-aggregator.ts +199 -0
- package/src/modes/transcript-item-registry.ts +229 -0
- package/src/modes/types.ts +45 -18
- package/src/modes/utils/ui-helpers.ts +17 -9
- package/src/prompts/agent-fragments/ralplan-persistence.md +6 -0
- package/src/prompts/agent-fragments/restricted-bash.md +1 -0
- package/src/prompts/agents/architect.md +2 -8
- package/src/prompts/agents/critic.md +2 -8
- package/src/prompts/agents/executor.md +3 -0
- package/src/prompts/agents/planner.md +4 -12
- package/src/prompts/system/custom-system-prompt.md +1 -23
- package/src/prompts/system/plan-mode-approved.md +8 -0
- package/src/prompts/system/system-prompt.md +17 -96
- package/src/prompts/tools/bash.md +4 -4
- package/src/prompts/tools/browser.md +15 -52
- package/src/prompts/tools/find.md +2 -2
- package/src/prompts/tools/hashline.md +13 -55
- package/src/prompts/tools/read.md +3 -6
- package/src/prompts/tools/search-tool-bm25.md +0 -2
- package/src/prompts/tools/search.md +2 -4
- package/src/prompts/tools/skill-discovery.md +1 -2
- package/src/prompts/tools/task.md +1 -1
- package/src/runtime-mcp/manager.ts +1 -1
- package/src/sdk/broker/broker.ts +206 -78
- package/src/sdk/broker/discovery.ts +1 -1
- package/src/sdk/broker/ensure.ts +3 -1
- package/src/sdk/broker/lifecycle-codec.ts +11 -0
- package/src/sdk/broker/lifecycle-ledger.ts +371 -74
- package/src/sdk/broker/lifecycle.ts +1399 -142
- package/src/sdk/broker/process-incarnation.ts +5 -13
- package/src/sdk/broker/session-index.ts +145 -56
- package/src/sdk/broker/state-version.ts +21 -0
- package/src/sdk/broker/transport.ts +1 -1
- package/src/sdk/bus/chat-daemon-cli.ts +2 -0
- package/src/sdk/bus/chat-daemon-control.ts +8 -28
- package/src/sdk/bus/chat-effect-journal.ts +10 -2
- package/src/sdk/bus/config-commands.ts +5 -4
- package/src/sdk/bus/config.ts +98 -0
- package/src/sdk/bus/conversation-store.ts +5 -29
- package/src/sdk/bus/daemon-paths.ts +2 -0
- package/src/sdk/bus/html-format.ts +20 -3
- package/src/sdk/bus/index.ts +782 -94
- package/src/sdk/bus/lifecycle-control-runtime.ts +91 -33
- package/src/sdk/bus/natives-augment.d.ts +26 -1
- package/src/sdk/bus/notification-service.ts +168 -20
- package/src/sdk/bus/rate-limit-pool.ts +58 -14
- package/src/sdk/bus/recent-activity.ts +188 -74
- package/src/sdk/bus/rich-document.ts +258 -0
- package/src/sdk/bus/rich-render.ts +62 -70
- package/src/sdk/bus/telegram-daemon-cli.ts +15 -59
- package/src/sdk/bus/telegram-daemon-contract.ts +9 -4
- package/src/sdk/bus/telegram-daemon.ts +1389 -237
- package/src/sdk/bus/threaded-inbound.ts +8 -3
- package/src/sdk/bus/threaded-render.ts +57 -1
- package/src/sdk/bus/topic-registry.ts +120 -13
- package/src/sdk/host/control/dispatch.ts +14 -2
- package/src/sdk/host/control/operations.ts +6 -1
- package/src/sdk/host/host.ts +44 -2
- package/src/sdk/host/query/handlers.ts +20 -22
- package/src/sdk/host/query/revision-store.ts +80 -57
- package/src/sdk/index.ts +1 -0
- package/src/sdk/protocol/operation-inventory.generated.json +943 -1907
- package/src/sdk/session-directory.ts +141 -0
- package/src/sdk/session.ts +462 -480
- package/src/session/agent-session.ts +1700 -583
- package/src/session/agent-storage.ts +18 -0
- package/src/session/cache-economics.ts +25 -8
- package/src/session/fallback-chain-controller.ts +53 -3
- package/src/session/internal/managed-session-scope.ts +2226 -0
- package/src/session/internal/managed-session-storage.ts +453 -0
- package/src/session/messages.ts +91 -2
- package/src/session/session-manager-internal.ts +33 -0
- package/src/session/session-manager.ts +1112 -333
- package/src/session/session-storage.ts +444 -39
- package/src/session/volatile-context-pruning.ts +78 -0
- package/src/setup/credential-auto-import.ts +2 -1
- package/src/setup/hermes/templates/operator-instructions.v1.md +1 -1
- package/src/setup/provider-onboarding.ts +36 -61
- package/src/setup/provider-presets.json +5 -0
- package/src/skill-state/active-state.ts +3 -13
- package/src/skill-state/{deep-interview-mutation-guard.ts → workflow-mutation-guard.ts} +47 -29
- package/src/skill-state/workflow-state-contract.ts +6 -41
- package/src/slash-commands/builtin-registry.ts +46 -11
- package/src/system-prompt.ts +37 -44
- package/src/task/agents.ts +19 -1
- package/src/task/executor.ts +90 -6
- package/src/task/index.ts +36 -21
- package/src/thinking.ts +21 -6
- package/src/tool-discovery/tool-index.ts +2 -134
- package/src/tools/ask.ts +157 -21
- package/src/tools/ast-edit.ts +1 -1
- package/src/tools/bash.ts +38 -0
- package/src/tools/browser/dead-tab-recovery.ts +78 -0
- package/src/tools/browser/tab-supervisor.ts +282 -36
- package/src/tools/computer.ts +10 -3
- package/src/tools/cron.ts +30 -16
- package/src/tools/eval.ts +1 -2
- package/src/tools/fetch.ts +11 -4
- package/src/tools/index.ts +76 -24
- package/src/tools/output-meta.ts +19 -7
- package/src/tools/read.ts +219 -64
- package/src/tools/resource-gc.ts +2 -2
- package/src/tools/search-tool-bm25.ts +11 -74
- package/src/tools/subagent.ts +43 -2
- package/src/utils/event-bus.ts +9 -4
- package/src/utils/file-mentions.ts +4 -4
- package/src/web/search/index.ts +3 -3
- package/dist/types/discovery/plugin-dir-roots.d.ts +0 -15
- package/dist/types/runtime-mcp/discoverable-tool-metadata.d.ts +0 -7
- package/src/discovery/plugin-dir-roots.ts +0 -28
- package/src/runtime-mcp/discoverable-tool-metadata.ts +0 -25
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { Marked, type Token, type Tokens } from "marked";
|
|
2
|
+
|
|
3
|
+
export type RichEligibility = { kind: "eligible" } | { kind: "ineligible" };
|
|
4
|
+
|
|
5
|
+
type MathToken = Token & { type: "btw_math"; expression: string };
|
|
6
|
+
|
|
7
|
+
const MAX_SCALARS = 32_768;
|
|
8
|
+
const MAX_UTF8_BYTES = 131_072;
|
|
9
|
+
const MAX_BLOCKS = 500;
|
|
10
|
+
const MAX_DEPTH = 16;
|
|
11
|
+
const MAX_TABLE_COLUMNS = 20;
|
|
12
|
+
function exceedsScalarLimit(source: string): boolean {
|
|
13
|
+
let count = 0;
|
|
14
|
+
for (const _scalar of source) {
|
|
15
|
+
count++;
|
|
16
|
+
if (count > MAX_SCALARS) return true;
|
|
17
|
+
}
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function isEscaped(source: string, index: number): boolean {
|
|
22
|
+
let escapes = 0;
|
|
23
|
+
for (let cursor = index - 1; cursor >= 0 && source[cursor] === "\\"; cursor--) escapes++;
|
|
24
|
+
return escapes % 2 === 1;
|
|
25
|
+
}
|
|
26
|
+
function isPlainTextSafe(source: string): boolean {
|
|
27
|
+
for (let index = 0; index < source.length; index++) {
|
|
28
|
+
if (
|
|
29
|
+
!isEscaped(source, index) &&
|
|
30
|
+
(source[index] === "*" ||
|
|
31
|
+
source[index] === "_" ||
|
|
32
|
+
source[index] === "~" ||
|
|
33
|
+
source[index] === "`" ||
|
|
34
|
+
source[index] === "[" ||
|
|
35
|
+
source[index] === "]" ||
|
|
36
|
+
source[index] === "<" ||
|
|
37
|
+
source[index] === ">")
|
|
38
|
+
)
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function hasLoneSurrogate(source: string): boolean {
|
|
45
|
+
for (let index = 0; index < source.length; index++) {
|
|
46
|
+
const code = source.charCodeAt(index);
|
|
47
|
+
if (code >= 0xd800 && code <= 0xdbff) {
|
|
48
|
+
if (
|
|
49
|
+
index + 1 >= source.length ||
|
|
50
|
+
source.charCodeAt(index + 1) < 0xdc00 ||
|
|
51
|
+
source.charCodeAt(index + 1) > 0xdfff
|
|
52
|
+
)
|
|
53
|
+
return true;
|
|
54
|
+
index++;
|
|
55
|
+
} else if (code >= 0xdc00 && code <= 0xdfff) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function hasUnescapedDollar(source: string): boolean {
|
|
63
|
+
for (let cursor = 0; cursor < source.length; cursor++) {
|
|
64
|
+
if (source[cursor] === "$" && !isEscaped(source, cursor)) return true;
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function isValidMathExpression(expression: string, multiline: boolean): boolean {
|
|
70
|
+
return (
|
|
71
|
+
expression.trim().length > 0 &&
|
|
72
|
+
(multiline || !expression.includes("\n")) &&
|
|
73
|
+
!expression.startsWith(" ") &&
|
|
74
|
+
!expression.endsWith(" ") &&
|
|
75
|
+
!hasUnescapedDollar(expression) &&
|
|
76
|
+
!expression.includes("\\(") &&
|
|
77
|
+
!expression.includes("\\)") &&
|
|
78
|
+
!expression.includes("\\[") &&
|
|
79
|
+
!expression.includes("\\]")
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function validateInlineMath(source: string): boolean {
|
|
84
|
+
for (let cursor = 0; cursor < source.length; cursor++) {
|
|
85
|
+
if (source[cursor] === "$" && !isEscaped(source, cursor)) {
|
|
86
|
+
if (source[cursor + 1] === "$") return false;
|
|
87
|
+
let closing = cursor + 1;
|
|
88
|
+
while (closing < source.length && (source[closing] !== "$" || isEscaped(source, closing))) closing++;
|
|
89
|
+
if (closing === source.length || !isValidMathExpression(source.slice(cursor + 1, closing), false))
|
|
90
|
+
return false;
|
|
91
|
+
cursor = closing;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (source.startsWith("\\(", cursor) && !isEscaped(source, cursor)) {
|
|
95
|
+
let closing = cursor + 2;
|
|
96
|
+
while (closing < source.length && (!source.startsWith("\\)", closing) || isEscaped(source, closing)))
|
|
97
|
+
closing++;
|
|
98
|
+
if (closing === source.length || !isValidMathExpression(source.slice(cursor + 2, closing), false))
|
|
99
|
+
return false;
|
|
100
|
+
cursor = closing + 1;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (source.startsWith("\\)", cursor) && !isEscaped(source, cursor)) return false;
|
|
104
|
+
if ((source.startsWith("\\[", cursor) || source.startsWith("\\]", cursor)) && !isEscaped(source, cursor))
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function parseDisplayMath(source: string): boolean {
|
|
111
|
+
const block = source.trim();
|
|
112
|
+
const delimiter =
|
|
113
|
+
block.startsWith("$$") && block.endsWith("$$")
|
|
114
|
+
? "$$"
|
|
115
|
+
: block.startsWith("\\[") && block.endsWith("\\]")
|
|
116
|
+
? "\\["
|
|
117
|
+
: undefined;
|
|
118
|
+
if (delimiter === undefined) return false;
|
|
119
|
+
const closing = delimiter === "$$" ? "$$" : "\\]";
|
|
120
|
+
return (
|
|
121
|
+
!isEscaped(block, block.length - closing.length) &&
|
|
122
|
+
isValidMathExpression(block.slice(delimiter.length, -closing.length).trim(), true)
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const marked = new Marked({
|
|
127
|
+
async: false,
|
|
128
|
+
breaks: false,
|
|
129
|
+
gfm: true,
|
|
130
|
+
pedantic: false,
|
|
131
|
+
silent: false,
|
|
132
|
+
extensions: [
|
|
133
|
+
{
|
|
134
|
+
name: "btw_math",
|
|
135
|
+
level: "inline",
|
|
136
|
+
start(src) {
|
|
137
|
+
const dollar = src.indexOf("$");
|
|
138
|
+
const parenthesized = src.indexOf("\\(");
|
|
139
|
+
if (dollar < 0) return parenthesized;
|
|
140
|
+
if (parenthesized < 0) return dollar;
|
|
141
|
+
return Math.min(dollar, parenthesized);
|
|
142
|
+
},
|
|
143
|
+
tokenizer(src) {
|
|
144
|
+
if (src.startsWith("$") && !src.startsWith("$$")) {
|
|
145
|
+
let closing = 1;
|
|
146
|
+
while (closing < src.length && (src[closing] !== "$" || isEscaped(src, closing))) closing++;
|
|
147
|
+
const expression = src.slice(1, closing);
|
|
148
|
+
if (closing < src.length && isValidMathExpression(expression, false))
|
|
149
|
+
return { type: "btw_math", raw: src.slice(0, closing + 1), expression };
|
|
150
|
+
}
|
|
151
|
+
if (src.startsWith("\\(")) {
|
|
152
|
+
let closing = 2;
|
|
153
|
+
while (closing < src.length && (!src.startsWith("\\)", closing) || isEscaped(src, closing))) closing++;
|
|
154
|
+
const expression = src.slice(2, closing);
|
|
155
|
+
if (closing < src.length && isValidMathExpression(expression, false))
|
|
156
|
+
return { type: "btw_math", raw: src.slice(0, closing + 2), expression };
|
|
157
|
+
}
|
|
158
|
+
return undefined;
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
function recognizeText(tokens: Token[], depth: number): boolean {
|
|
165
|
+
if (depth > MAX_DEPTH) return false;
|
|
166
|
+
for (const token of tokens) {
|
|
167
|
+
switch (token.type) {
|
|
168
|
+
case "btw_math":
|
|
169
|
+
if (depth > 2 || !isValidMathExpression((token as MathToken).expression, false)) return false;
|
|
170
|
+
break;
|
|
171
|
+
case "text":
|
|
172
|
+
if (!isPlainTextSafe(token.raw)) return false;
|
|
173
|
+
break;
|
|
174
|
+
case "escape":
|
|
175
|
+
case "br":
|
|
176
|
+
case "codespan":
|
|
177
|
+
break;
|
|
178
|
+
case "strong":
|
|
179
|
+
case "em":
|
|
180
|
+
case "del":
|
|
181
|
+
if (token.tokens === undefined || !recognizeText(token.tokens, depth + 1)) return false;
|
|
182
|
+
break;
|
|
183
|
+
default:
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function recognizeTable(token: Tokens.Table, count: { value: number }): boolean {
|
|
191
|
+
const columns = token.header.length;
|
|
192
|
+
if (
|
|
193
|
+
columns < 1 ||
|
|
194
|
+
columns > MAX_TABLE_COLUMNS ||
|
|
195
|
+
token.align.length !== columns ||
|
|
196
|
+
token.rows.some(row => row.length !== columns) ||
|
|
197
|
+
token.align.some(align => align !== "left" && align !== "center" && align !== "right" && align !== null)
|
|
198
|
+
)
|
|
199
|
+
return false;
|
|
200
|
+
for (const row of [token.header, ...token.rows]) {
|
|
201
|
+
for (const cell of row) {
|
|
202
|
+
if (!validateInlineMath(cell.text) || !recognizeText(cell.tokens, 0)) return false;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
count.value += 1 + token.rows.length + 1;
|
|
206
|
+
return count.value <= MAX_BLOCKS;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/** Conservatively recognize `/btw` Markdown that can be represented as rich content. */
|
|
210
|
+
export function parseRichEligibility(markdown: string): RichEligibility {
|
|
211
|
+
try {
|
|
212
|
+
if (
|
|
213
|
+
hasLoneSurrogate(markdown) ||
|
|
214
|
+
exceedsScalarLimit(markdown) ||
|
|
215
|
+
Buffer.byteLength(markdown, "utf8") > MAX_UTF8_BYTES ||
|
|
216
|
+
markdown.includes("\u0000")
|
|
217
|
+
)
|
|
218
|
+
return { kind: "ineligible" };
|
|
219
|
+
|
|
220
|
+
const tokens = marked.lexer(markdown);
|
|
221
|
+
const count = { value: 0 };
|
|
222
|
+
let structured = false;
|
|
223
|
+
for (const token of tokens) {
|
|
224
|
+
if (token.type === "space") continue;
|
|
225
|
+
if (token.type === "heading") {
|
|
226
|
+
if (
|
|
227
|
+
token.tokens === undefined ||
|
|
228
|
+
token.depth < 1 ||
|
|
229
|
+
token.depth > 6 ||
|
|
230
|
+
!validateInlineMath(token.text) ||
|
|
231
|
+
!recognizeText(token.tokens, 0)
|
|
232
|
+
)
|
|
233
|
+
return { kind: "ineligible" };
|
|
234
|
+
count.value++;
|
|
235
|
+
} else if (token.type === "paragraph" || token.type === "text") {
|
|
236
|
+
if (token.type === "paragraph" && parseDisplayMath(token.text)) {
|
|
237
|
+
structured = true;
|
|
238
|
+
count.value++;
|
|
239
|
+
} else {
|
|
240
|
+
const inline = token.type === "paragraph" ? token.tokens : [token];
|
|
241
|
+
if (inline === undefined || !validateInlineMath(token.text) || !recognizeText(inline, 0))
|
|
242
|
+
return { kind: "ineligible" };
|
|
243
|
+
structured ||= inline.some(part => part.type === "btw_math");
|
|
244
|
+
count.value++;
|
|
245
|
+
}
|
|
246
|
+
} else if (token.type === "table") {
|
|
247
|
+
if (!recognizeTable(token as Tokens.Table, count)) return { kind: "ineligible" };
|
|
248
|
+
structured = true;
|
|
249
|
+
} else {
|
|
250
|
+
return { kind: "ineligible" };
|
|
251
|
+
}
|
|
252
|
+
if (count.value > MAX_BLOCKS) return { kind: "ineligible" };
|
|
253
|
+
}
|
|
254
|
+
return structured ? { kind: "eligible" } : { kind: "ineligible" };
|
|
255
|
+
} catch {
|
|
256
|
+
return { kind: "ineligible" };
|
|
257
|
+
}
|
|
258
|
+
}
|
|
@@ -2,28 +2,20 @@
|
|
|
2
2
|
* Rich-message promotion for stable non-editable Telegram text sends.
|
|
3
3
|
*
|
|
4
4
|
* When enabled, the daemon promotes eligible finalized `sendMessage` payloads
|
|
5
|
-
* carrying raw markdown to
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* carrying raw markdown to Bot API `sendRichMessage`. Only an explicit
|
|
6
|
+
* `{ ok: false }` response selects the unchanged HTML path; ambiguous transport
|
|
7
|
+
* outcomes remain single-attempt and never fall back.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import { parseRichEligibility } from "./rich-document";
|
|
10
11
|
import type { BotApi } from "./telegram-daemon";
|
|
11
12
|
import type { ThreadedSend } from "./threaded-render";
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
|
-
* Telegram's hard per-message character ceiling (4096).
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* Overflow is already safe without it. The production final-answer text is capped
|
|
20
|
-
* at 3500 chars upstream (`summaryFromMessage(..., 3500)`), so a promoted
|
|
21
|
-
* `sendRichMessage` never approaches this ceiling; and if the Bot API ever rejects
|
|
22
|
-
* an oversized rich payload it returns `{ ok: false }`, which
|
|
23
|
-
* `deliverRichWithFallback` (below) turns into the chunked HTML `splitTelegramHtml`
|
|
24
|
-
* fallback (each chunk ≤ TELEGRAM_MESSAGE_LIMIT). This constant only marks where a
|
|
25
|
-
* future rich splitter would read its ceiling; wiring it into a branch would change
|
|
26
|
-
* byte-for-byte behavior and is out of scope.
|
|
15
|
+
* Telegram's hard per-message character ceiling (4096). Final-answer promotion
|
|
16
|
+
* uses this value to keep oversized Markdown on the existing chunked HTML path.
|
|
17
|
+
* `/btw` eligibility has its own 32,768-scalar route guard; only a definite
|
|
18
|
+
* rich rejection may select the correlated HTML path.
|
|
27
19
|
*/
|
|
28
20
|
export const RICH_MESSAGE_LIMIT = 4096;
|
|
29
21
|
|
|
@@ -31,8 +23,16 @@ export const RICH_MESSAGE_LIMIT = 4096;
|
|
|
31
23
|
export function buildRichMessage(
|
|
32
24
|
raw: string,
|
|
33
25
|
extras: { reply_markup?: unknown } = {},
|
|
34
|
-
): { rich_message: { markdown: string }; reply_markup?: unknown } {
|
|
35
|
-
return { rich_message: { markdown: raw }, ...extras };
|
|
26
|
+
): { rich_message: { markdown: string; skip_entity_detection: true }; reply_markup?: unknown } {
|
|
27
|
+
return { rich_message: { markdown: raw, skip_entity_detection: true }, ...extras };
|
|
28
|
+
}
|
|
29
|
+
/** Telegram message identifiers are strictly positive safe integers. */
|
|
30
|
+
function validMessageId(value: unknown): value is number {
|
|
31
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
|
|
32
|
+
}
|
|
33
|
+
/** Whether `/btw` Markdown may use Bot API 10.1 rich delivery. */
|
|
34
|
+
export function isBtwRichEligible(markdown: string): boolean {
|
|
35
|
+
return parseRichEligibility(markdown).kind === "eligible";
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/**
|
|
@@ -56,88 +56,80 @@ export function shouldPromoteRich(input: { enabled?: boolean; send: ThreadedSend
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
/**
|
|
59
|
-
* Deliver the promoted rich message, falling back to `fallbackDeliver`
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* returns `res.json()` for JSON methods, so `ok:false` does not throw). On
|
|
63
|
-
* failure exactly one diagnostic is logged before the fallback runs; on success
|
|
64
|
-
* the fallback never runs.
|
|
65
|
-
*
|
|
66
|
-
* Returns the sent message's `message_id` on success (when the response carries
|
|
67
|
-
* one), otherwise `undefined` — including every failure/fallback path and a
|
|
68
|
-
* success whose response omits `result.message_id`. Callers that ignore the
|
|
69
|
-
* return value are unaffected.
|
|
59
|
+
* Deliver the promoted rich message, falling back to `fallbackDeliver` only
|
|
60
|
+
* after an explicit `{ ok: false }` response. Transport errors and malformed or
|
|
61
|
+
* ambiguous responses are logged but never retried or sent again through HTML.
|
|
70
62
|
*/
|
|
71
63
|
export async function deliverRichWithFallback(
|
|
72
64
|
botApi: BotApi,
|
|
73
65
|
base: { chat_id: string | number; message_thread_id?: number },
|
|
74
66
|
send: ThreadedSend,
|
|
67
|
+
signal: AbortSignal,
|
|
75
68
|
fallbackDeliver: () => Promise<void>,
|
|
76
69
|
log?: { warn(msg: string): void },
|
|
77
70
|
): Promise<number | undefined> {
|
|
78
|
-
let failure: string | undefined;
|
|
79
|
-
let messageId: number | undefined;
|
|
80
71
|
try {
|
|
81
|
-
const res = await botApi.call(
|
|
72
|
+
const res = await botApi.call(
|
|
73
|
+
"sendRichMessage",
|
|
74
|
+
{ ...base, ...buildRichMessage(send.richMarkdown!) },
|
|
75
|
+
{ noRetry: true, signal },
|
|
76
|
+
);
|
|
82
77
|
if (res !== null && typeof res === "object" && (res as { ok?: unknown }).ok === false) {
|
|
83
78
|
const description = (res as { description?: unknown }).description;
|
|
84
|
-
failure = typeof description === "string" && description.length > 0 ? description : "ok:false";
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
79
|
+
const failure = typeof description === "string" && description.length > 0 ? description : "ok:false";
|
|
80
|
+
log?.warn(`notifications: sendRichMessage rejected (${failure}); falling back to HTML`);
|
|
81
|
+
await fallbackDeliver();
|
|
82
|
+
return undefined;
|
|
88
83
|
}
|
|
84
|
+
const candidate = (res as { result?: { message_id?: unknown } } | null)?.result?.message_id;
|
|
85
|
+
if (validMessageId(candidate)) return candidate;
|
|
86
|
+
log?.warn("notifications: sendRichMessage outcome ambiguous; not falling back to HTML");
|
|
89
87
|
} catch (err) {
|
|
90
|
-
failure = err instanceof Error ? err.message : String(err);
|
|
88
|
+
const failure = err instanceof Error ? err.message : String(err);
|
|
89
|
+
log?.warn(`notifications: sendRichMessage failed (${failure}); not falling back to HTML`);
|
|
91
90
|
}
|
|
92
|
-
if (failure === undefined) return messageId;
|
|
93
|
-
log?.warn(`notifications: sendRichMessage failed (${failure}); falling back to HTML`);
|
|
94
|
-
await fallbackDeliver();
|
|
95
91
|
return undefined;
|
|
96
92
|
}
|
|
97
93
|
|
|
98
94
|
/**
|
|
99
95
|
* Deliver an action-needed (ask/idle) message via `sendRichMessage`, falling
|
|
100
|
-
* back to the unchanged HTML chunk loop
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
* `reply_markup` alongside `rich_message`), and surfaces a structured outcome so
|
|
104
|
-
* the daemon can route inbound replies to the resulting message id.
|
|
105
|
-
*
|
|
106
|
-
* On rich success: returns `{ messageId, usedRich: true, usedFallback: false }`
|
|
107
|
-
* where `messageId` is `res.result.message_id` when present. On a `{ ok:false }`
|
|
108
|
-
* response or a thrown transport error: warns exactly once, runs `htmlFallback`,
|
|
109
|
-
* and returns `{ messageId, usedRich: false, usedFallback: true }` where
|
|
110
|
-
* `messageId` is the fallback's return value (the last HTML chunk's id).
|
|
96
|
+
* back to the unchanged HTML chunk loop only after an explicit `{ ok:false }`
|
|
97
|
+
* response. Other outcomes are ambiguous, are logged, and preserve the single
|
|
98
|
+
* physical rich delivery.
|
|
111
99
|
*/
|
|
112
100
|
export async function deliverRichActionWithFallback(
|
|
113
101
|
botApi: BotApi,
|
|
114
102
|
base: { chat_id: string | number; message_thread_id?: number },
|
|
115
|
-
opts: { markdown: string; replyMarkup?: unknown
|
|
103
|
+
opts: { markdown: string; replyMarkup?: unknown },
|
|
104
|
+
signal: AbortSignal,
|
|
116
105
|
htmlFallback: () => Promise<number | undefined>,
|
|
117
106
|
log?: { warn(msg: string): void },
|
|
118
107
|
): Promise<{ messageId?: number; usedRich: boolean; usedFallback: boolean }> {
|
|
119
|
-
let failure: string | undefined;
|
|
120
|
-
let messageId: number | undefined;
|
|
121
108
|
try {
|
|
122
|
-
const res = await botApi.call(
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
109
|
+
const res = await botApi.call(
|
|
110
|
+
"sendRichMessage",
|
|
111
|
+
{
|
|
112
|
+
...base,
|
|
113
|
+
...buildRichMessage(
|
|
114
|
+
opts.markdown,
|
|
115
|
+
opts.replyMarkup === undefined ? {} : { reply_markup: opts.replyMarkup },
|
|
116
|
+
),
|
|
117
|
+
},
|
|
118
|
+
{ noRetry: true, signal },
|
|
119
|
+
);
|
|
126
120
|
if (res !== null && typeof res === "object" && (res as { ok?: unknown }).ok === false) {
|
|
127
121
|
const description = (res as { description?: unknown }).description;
|
|
128
|
-
failure = typeof description === "string" && description.length > 0 ? description : "ok:false";
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
// Ask messages MUST be reply-routable: if a rich success carries no numeric
|
|
133
|
-
// message_id, fall back to HTML so a routable id is guaranteed.
|
|
134
|
-
else if (opts.requireMessageId) failure = "rich response missing message_id";
|
|
122
|
+
const failure = typeof description === "string" && description.length > 0 ? description : "ok:false";
|
|
123
|
+
log?.warn(`notifications: sendRichMessage(action) rejected (${failure}); falling back to HTML`);
|
|
124
|
+
const fallbackId = await htmlFallback();
|
|
125
|
+
return { messageId: fallbackId, usedRich: false, usedFallback: true };
|
|
135
126
|
}
|
|
127
|
+
const candidate = (res as { result?: { message_id?: unknown } } | null)?.result?.message_id;
|
|
128
|
+
if (validMessageId(candidate)) return { messageId: candidate, usedRich: true, usedFallback: false };
|
|
129
|
+
log?.warn("notifications: sendRichMessage(action) outcome ambiguous; not falling back to HTML");
|
|
136
130
|
} catch (err) {
|
|
137
|
-
failure = err instanceof Error ? err.message : String(err);
|
|
131
|
+
const failure = err instanceof Error ? err.message : String(err);
|
|
132
|
+
log?.warn(`notifications: sendRichMessage(action) failed (${failure}); not falling back to HTML`);
|
|
138
133
|
}
|
|
139
|
-
|
|
140
|
-
log?.warn(`notifications: sendRichMessage(action) failed (${failure}); falling back to HTML`);
|
|
141
|
-
const fallbackId = await htmlFallback();
|
|
142
|
-
return { messageId: fallbackId, usedRich: false, usedFallback: true };
|
|
134
|
+
return { messageId: undefined, usedRich: true, usedFallback: false };
|
|
143
135
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
+
import { logger } from "@gajae-code/utils";
|
|
3
4
|
import { YAML } from "bun";
|
|
4
5
|
import { applyAtomicYamlPatches, setByPath } from "../../config/atomic-yaml-patch";
|
|
5
6
|
import type { Settings } from "../../config/settings";
|
|
@@ -7,8 +8,7 @@ import {
|
|
|
7
8
|
getNotificationConfig,
|
|
8
9
|
isTelegramConfigured,
|
|
9
10
|
type NotificationSettingsReader,
|
|
10
|
-
|
|
11
|
-
readTelegramActivationMarkers,
|
|
11
|
+
parseNotificationSettingsSnapshot,
|
|
12
12
|
} from "./config";
|
|
13
13
|
import { daemonPaths, HEARTBEAT_TTL_MS } from "./daemon-paths";
|
|
14
14
|
import {
|
|
@@ -53,68 +53,21 @@ function argValue(argv: string[], name: string): string | undefined {
|
|
|
53
53
|
const i = argv.indexOf(name);
|
|
54
54
|
return i >= 0 ? argv[i + 1] : undefined;
|
|
55
55
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
return current;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function asString(value: unknown): string | undefined {
|
|
67
|
-
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function asBoolean(value: unknown, fallback: boolean): boolean {
|
|
71
|
-
return typeof value === "boolean" ? value : fallback;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function asIdleTimeoutMs(value: unknown): number {
|
|
75
|
-
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 60_000;
|
|
56
|
+
const DAEMON_COMPATIBILITY_DIAGNOSTIC_LIMIT = 1;
|
|
57
|
+
let daemonCompatibilityDiagnosticCount = 0;
|
|
58
|
+
function recordDaemonCompatibilityDiagnostic(message: string): void {
|
|
59
|
+
if (daemonCompatibilityDiagnosticCount >= DAEMON_COMPATIBILITY_DIAGNOSTIC_LIMIT) return;
|
|
60
|
+
daemonCompatibilityDiagnosticCount++;
|
|
61
|
+
logger.warn(message);
|
|
76
62
|
}
|
|
77
63
|
|
|
78
64
|
export function createLightweightDaemonSettings(input: {
|
|
79
65
|
agentDir: string;
|
|
80
66
|
rawConfig?: unknown;
|
|
81
67
|
}): LightweightDaemonSettings {
|
|
82
|
-
const rawConfig = input.rawConfig
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
enabled: asBoolean(getByPath(rawConfig, ["notifications", "enabled"]), false),
|
|
86
|
-
telegram: {
|
|
87
|
-
botToken: asString(getByPath(rawConfig, ["notifications", "telegram", "botToken"])),
|
|
88
|
-
chatId: asString(getByPath(rawConfig, ["notifications", "telegram", "chatId"])),
|
|
89
|
-
...(Object.keys(activation).length === 0 ? {} : { activation }),
|
|
90
|
-
rich: {
|
|
91
|
-
enabled: asBoolean(getByPath(rawConfig, ["notifications", "telegram", "rich", "enabled"]), true),
|
|
92
|
-
},
|
|
93
|
-
richDraft: {
|
|
94
|
-
enabled: asBoolean(getByPath(rawConfig, ["notifications", "telegram", "richDraft", "enabled"]), false),
|
|
95
|
-
},
|
|
96
|
-
topics: {
|
|
97
|
-
nameTemplate: asString(getByPath(rawConfig, ["notifications", "telegram", "topics", "nameTemplate"])),
|
|
98
|
-
},
|
|
99
|
-
},
|
|
100
|
-
discord: {
|
|
101
|
-
botToken: asString(getByPath(rawConfig, ["notifications", "discord", "botToken"])),
|
|
102
|
-
applicationId: asString(getByPath(rawConfig, ["notifications", "discord", "applicationId"])),
|
|
103
|
-
guildId: asString(getByPath(rawConfig, ["notifications", "discord", "guildId"])),
|
|
104
|
-
parentChannelId: asString(getByPath(rawConfig, ["notifications", "discord", "parentChannelId"])),
|
|
105
|
-
},
|
|
106
|
-
slack: {
|
|
107
|
-
botToken: asString(getByPath(rawConfig, ["notifications", "slack", "botToken"])),
|
|
108
|
-
appToken: asString(getByPath(rawConfig, ["notifications", "slack", "appToken"])),
|
|
109
|
-
workspaceId: asString(getByPath(rawConfig, ["notifications", "slack", "workspaceId"])),
|
|
110
|
-
channelId: asString(getByPath(rawConfig, ["notifications", "slack", "channelId"])),
|
|
111
|
-
authorizedUserId: asString(getByPath(rawConfig, ["notifications", "slack", "authorizedUserId"])),
|
|
112
|
-
},
|
|
113
|
-
redact: asBoolean(getByPath(rawConfig, ["notifications", "redact"]), false),
|
|
114
|
-
verbosity: getByPath(rawConfig, ["notifications", "verbosity"]) === "verbose" ? "verbose" : "lean",
|
|
115
|
-
sessionScope: getByPath(rawConfig, ["notifications", "sessionScope"]) === "primary" ? "primary" : "all",
|
|
116
|
-
idleTimeoutMs: asIdleTimeoutMs(getByPath(rawConfig, ["notifications", "daemon", "idleTimeoutMs"])),
|
|
117
|
-
});
|
|
68
|
+
const rawConfig = input.rawConfig === undefined ? {} : input.rawConfig;
|
|
69
|
+
const getNotificationSettingsSnapshot = () => parseNotificationSettingsSnapshot(rawConfig);
|
|
70
|
+
getNotificationSettingsSnapshot();
|
|
118
71
|
|
|
119
72
|
return {
|
|
120
73
|
get(pathName: string): unknown {
|
|
@@ -126,6 +79,8 @@ export function createLightweightDaemonSettings(input: {
|
|
|
126
79
|
return snapshot.telegram.botToken;
|
|
127
80
|
case "notifications.telegram.chatId":
|
|
128
81
|
return snapshot.telegram.chatId;
|
|
82
|
+
case "notifications.telegram.btw.enabled":
|
|
83
|
+
return snapshot.telegram.btw.enabled;
|
|
129
84
|
case "notifications.discord.botToken":
|
|
130
85
|
return snapshot.discord.botToken;
|
|
131
86
|
case "notifications.discord.applicationId":
|
|
@@ -243,7 +198,7 @@ export async function runDaemonInternal(argv: string[], deps: RunDaemonInternalD
|
|
|
243
198
|
const ownerId = argValue(argv, "--owner-id");
|
|
244
199
|
if (!ownerId) throw new Error("missing --owner-id");
|
|
245
200
|
if (!ownerProcessIsAlive(ownerId, deps)) {
|
|
246
|
-
|
|
201
|
+
recordDaemonCompatibilityDiagnostic("GJC notify daemon exiting because its owner is not alive");
|
|
247
202
|
return;
|
|
248
203
|
}
|
|
249
204
|
const resolvedAgentDir = agentDir ?? process.env.GJC_CODING_AGENT_DIR ?? path.join(process.cwd(), ".gjc", "agent");
|
|
@@ -261,6 +216,7 @@ export async function runDaemonInternal(argv: string[], deps: RunDaemonInternalD
|
|
|
261
216
|
rich: cfg.rich,
|
|
262
217
|
richDraft: cfg.richDraft,
|
|
263
218
|
topics: cfg.topics,
|
|
219
|
+
btw: cfg.btw,
|
|
264
220
|
pid: deps.processPid ?? process.pid,
|
|
265
221
|
control: {
|
|
266
222
|
shouldStop: async owner => {
|
|
@@ -7,8 +7,13 @@
|
|
|
7
7
|
export const NOTIFICATION_PROTOCOL_VERSION = 3;
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Operational generation the current daemon build speaks.
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* Operational generation the current daemon build speaks. Decoupled from
|
|
11
|
+
* {@link NOTIFICATION_PROTOCOL_VERSION} (#2304): additive `tool_activity` /
|
|
12
|
+
* `reasoning_summary` frames do not bump the wire protocol version, but a
|
|
13
|
+
* freshly-upgraded host must still recognize an older, still-live daemon that
|
|
14
|
+
* predates capability-gated frame enforcement and trigger a reload. Bump this
|
|
15
|
+
* on every daemon-behavior change independent of the wire version.
|
|
16
|
+
* The current development baseline already includes #2299's generation 4;
|
|
17
|
+
* this behavior change therefore advances the operational generation to 5.
|
|
13
18
|
*/
|
|
14
|
-
export const DAEMON_GENERATION =
|
|
19
|
+
export const DAEMON_GENERATION = 5;
|