@gajae-code/coding-agent 0.18.7 → 0.18.9
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 +377 -1
- package/dist/types/async/endpoint-id.d.ts +16 -0
- package/dist/types/async/job-manager.d.ts +1 -1
- package/dist/types/async/support.d.ts +0 -14
- package/dist/types/capability/mcp.d.ts +2 -0
- package/dist/types/capability/skill.d.ts +2 -0
- package/dist/types/capability/types.d.ts +2 -0
- package/dist/types/cli/public-command-errors.d.ts +3 -1
- package/dist/types/cli/setup-cli.d.ts +1 -1
- package/dist/types/commands/deep-interview.d.ts +3 -0
- package/dist/types/commands/mcp-serve.d.ts +4 -0
- package/dist/types/config/autorouting-tier-map.d.ts +348 -9
- package/dist/types/config/file-lock.d.ts +1 -0
- package/dist/types/config/model-bindings-applier.d.ts +2 -0
- package/dist/types/config/model-profile-activation.d.ts +11 -3
- package/dist/types/config/model-registry.d.ts +4 -9
- package/dist/types/config/skill-settings-defaults.d.ts +2 -0
- package/dist/types/cursor-delete-path.d.ts +1 -0
- package/dist/types/cursor-mcp-name.d.ts +8 -0
- package/dist/types/customization/inventory.d.ts +2 -0
- package/dist/types/debug/report-bundle-parent.d.ts +2 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/stream.d.ts +1 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/version-manager.d.ts +31 -0
- package/dist/types/defaults/gjc-skills.generated.d.ts +5 -6
- package/dist/types/discovery/helpers.d.ts +6 -1
- package/dist/types/discovery/mcp-json.d.ts +1 -0
- package/dist/types/eval/py/kernel.d.ts +18 -0
- package/dist/types/export/html/css-color.d.ts +2 -0
- package/dist/types/export/html/html-export-destination.d.ts +2 -0
- package/dist/types/export/html/template.generated.d.ts +1 -1
- package/dist/types/extensibility/extensions/function-hooks-internal.d.ts +5 -0
- package/dist/types/extensibility/extensions/types.d.ts +7 -0
- package/dist/types/extensibility/gjc-plugins/runtime-adapters.d.ts +14 -1
- package/dist/types/extensibility/plugins/marketplace/cache.d.ts +2 -0
- package/dist/types/extensibility/plugins/plugin-link-path.d.ts +2 -0
- package/dist/types/extensibility/runtime-skill-discovery.d.ts +3 -1
- package/dist/types/extensibility/skill-management.d.ts +4 -1
- package/dist/types/extensibility/skills.d.ts +2 -0
- package/dist/types/gjc-runtime/deep-interview-crystallize.d.ts +74 -0
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +11 -0
- package/dist/types/gjc-runtime/gc-runtime.d.ts +5 -0
- package/dist/types/gjc-runtime/psmux-detect.d.ts +3 -3
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +0 -5
- package/dist/types/gjc-runtime/sidecar-bootstrap-env.d.ts +6 -0
- package/dist/types/gjc-runtime/state-argv.d.ts +1 -1
- package/dist/types/gjc-runtime/state-migrations.d.ts +8 -0
- package/dist/types/gjc-runtime/state-runtime.d.ts +95 -0
- package/dist/types/gjc-runtime/state-writer.d.ts +14 -1
- package/dist/types/gjc-runtime/tmux-common.d.ts +8 -5
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +8 -0
- package/dist/types/internal-urls/skill-path.d.ts +1 -0
- package/dist/types/lsp/config.d.ts +8 -5
- package/dist/types/lsp/workspace-path.d.ts +1 -0
- package/dist/types/modes/acp/acp-agent.d.ts +7 -0
- package/dist/types/modes/components/custom-editor.d.ts +6 -0
- package/dist/types/modes/components/customization/customization-dashboard.d.ts +1 -0
- package/dist/types/modes/components/extensions/state-manager.d.ts +4 -3
- package/dist/types/modes/controllers/input-controller.d.ts +9 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/modes/utils/interrupt-ownership.d.ts +3 -0
- package/dist/types/modes/utils/keybinding-matchers.d.ts +1 -0
- package/dist/types/modes/utils/macos-option-forwarding.d.ts +17 -0
- package/dist/types/progress/collect-project-progress.d.ts +38 -0
- package/dist/types/progress/progress-contract.d.ts +154 -0
- package/dist/types/progress/progress-snapshot.d.ts +11 -0
- package/dist/types/progress/project-progress.d.ts +141 -0
- package/dist/types/progress/render-progress.d.ts +28 -0
- package/dist/types/runtime-mcp/manager.d.ts +2 -1
- package/dist/types/runtime-mcp/mcp-redirect.d.ts +9 -0
- package/dist/types/runtime-mcp/oauth-public-url.d.ts +3 -0
- package/dist/types/runtime-mcp/plugin-network-boundary.d.ts +1 -0
- package/dist/types/runtime-mcp/project-host-values.d.ts +27 -0
- package/dist/types/runtime-mcp/smithery-registry.d.ts +24 -0
- package/dist/types/runtime-mcp/types.d.ts +6 -0
- package/dist/types/sdk/acp/adapter.d.ts +1 -1
- package/dist/types/sdk/broker/broker-exit.d.ts +6 -2
- package/dist/types/sdk/broker/broker.d.ts +24 -2
- package/dist/types/sdk/broker/doctor-restart.d.ts +5 -0
- package/dist/types/sdk/broker/ensure.d.ts +14 -1
- package/dist/types/sdk/broker/session-index.d.ts +12 -6
- package/dist/types/sdk/bus/index.d.ts +12 -1
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +6 -1
- package/dist/types/sdk/client/client.d.ts +2 -0
- package/dist/types/sdk/host/query/handlers.d.ts +3 -0
- package/dist/types/sdk/index.d.ts +1 -0
- package/dist/types/sdk/router/session-router.d.ts +2 -0
- package/dist/types/sdk/session-list.d.ts +1 -1
- package/dist/types/sdk/session.d.ts +8 -0
- package/dist/types/session/agent-session.d.ts +38 -9
- package/dist/types/session/artifacts.d.ts +2 -2
- package/dist/types/session/internal/managed-gc-retirement-codec.d.ts +32 -0
- package/dist/types/session/internal/managed-session-scope.d.ts +79 -2
- package/dist/types/session/internal/managed-session-storage.d.ts +26 -1
- package/dist/types/session/internal/managed-task-owner-cleanup.d.ts +62 -0
- package/dist/types/session/internal/task-artifact-owner-access.d.ts +2 -0
- package/dist/types/session/internal/task-artifact-owner-transcript.d.ts +9 -1
- package/dist/types/session/session-manager.d.ts +31 -5
- package/dist/types/session/session-retirement.d.ts +31 -7
- package/dist/types/session/session-storage.d.ts +69 -2
- package/dist/types/session/task-artifact-owner-codec.d.ts +2 -0
- package/dist/types/setup/credential-auto-import.d.ts +1 -1
- package/dist/types/setup/credential-import.d.ts +6 -4
- package/dist/types/skill-state/active-state.d.ts +38 -0
- package/dist/types/skill-state/workflow-mutation-guard.d.ts +3 -0
- package/dist/types/slash-commands/helpers/progress-report.d.ts +8 -0
- package/dist/types/task/executor.d.ts +3 -0
- package/dist/types/task/isolation-dir.d.ts +26 -0
- package/dist/types/tools/ast-edit-write-path.d.ts +13 -0
- package/dist/types/tools/bash-skill-urls.d.ts +1 -1
- package/dist/types/tools/browser/cdp-url.d.ts +2 -0
- package/dist/types/tools/github-side-effect.d.ts +22 -0
- package/dist/types/tools/index.d.ts +3 -0
- package/dist/types/tools/monitor-mutation.d.ts +9 -0
- package/dist/types/tools/python.d.ts +9 -1
- package/dist/types/tools/recipe/recipe-guard.d.ts +7 -0
- package/dist/types/tools/restricted-cwd.d.ts +1 -0
- package/dist/types/tools/todo-write.d.ts +6 -0
- package/dist/types/utils/tools-checksum.d.ts +7 -0
- package/package.json +7 -7
- package/scripts/generate-sdk-operation-inventory.ts +21 -0
- package/scripts/verify-managed-empty-stop.ts +28 -0
- package/src/async/endpoint-id.ts +26 -0
- package/src/async/job-manager.ts +247 -132
- package/src/async/support.ts +0 -25
- package/src/capability/index.ts +15 -0
- package/src/capability/mcp.ts +2 -0
- package/src/capability/skill.ts +2 -0
- package/src/capability/types.ts +2 -0
- package/src/cli/auth-broker-cli.ts +1 -1
- package/src/cli/customize-doctor.ts +15 -2
- package/src/cli/doctor/repairs.ts +4 -1
- package/src/cli/doctor-supervisor.ts +3 -0
- package/src/cli/public-command-errors.ts +21 -1
- package/src/cli/public-command-registry.ts +28 -6
- package/src/cli/setup-cli.ts +4 -4
- package/src/cli/skills-cli.ts +5 -0
- package/src/commands/deep-interview.ts +47 -8
- package/src/commands/mcp-serve.ts +7 -0
- package/src/commands/sdk.ts +455 -397
- package/src/config/autorouting-tier-map.ts +117 -7
- package/src/config/file-lock.ts +316 -79
- package/src/config/mcp-schema.json +4 -0
- package/src/config/model-bindings-applier.ts +20 -0
- package/src/config/model-profile-activation.ts +240 -46
- package/src/config/model-registry.ts +47 -153
- package/src/config/skill-settings-defaults.ts +7 -0
- package/src/coordinator-mcp/policy.ts +3 -2
- package/src/coordinator-mcp/server.ts +2 -0
- package/src/cursor-delete-path.ts +10 -0
- package/src/cursor-mcp-name.ts +15 -0
- package/src/cursor.ts +13 -2
- package/src/customization/inventory.ts +4 -13
- package/src/dap/config.ts +2 -2
- package/src/debug/report-bundle-parent.ts +22 -0
- package/src/debug/report-bundle.ts +3 -0
- package/src/debug/system-info.ts +13 -1
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/register.ts +10 -6
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/stream.ts +67 -4
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/version-manager.ts +80 -0
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +105 -10
- package/src/defaults/gjc/skills/ralplan/SKILL.md +6 -4
- package/src/defaults/gjc-defaults.test.ts +18 -1
- package/src/defaults/gjc-defaults.ts +3 -0
- package/src/defaults/gjc-skills.generated.ts +58 -36
- package/src/discovery/agents.ts +6 -1
- package/src/discovery/builtin.ts +13 -1
- package/src/discovery/helpers.ts +171 -29
- package/src/discovery/mcp-json.ts +26 -12
- package/src/discovery/ssh.ts +1 -1
- package/src/discovery/substitute-plugin-root.ts +3 -1
- package/src/edit/file-read-cache.ts +1 -1
- package/src/eval/py/executor.ts +796 -154
- package/src/eval/py/kernel.ts +79 -13
- package/src/eval/py/tool-bridge.ts +4 -0
- package/src/export/html/css-color.ts +9 -0
- package/src/export/html/html-export-destination.ts +16 -0
- package/src/export/html/index.ts +7 -10
- package/src/export/html/template.generated.ts +1 -1
- package/src/extensibility/extensions/function-hooks-internal.ts +27 -0
- package/src/extensibility/extensions/runner.ts +15 -1
- package/src/extensibility/extensions/types.ts +7 -0
- package/src/extensibility/gjc-plugins/mcp-policy.ts +2 -1
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +85 -8
- package/src/extensibility/plugins/manager.ts +3 -2
- package/src/extensibility/plugins/marketplace/cache.ts +15 -0
- package/src/extensibility/plugins/marketplace/manager.ts +11 -3
- package/src/extensibility/plugins/plugin-link-path.ts +12 -0
- package/src/extensibility/runtime-skill-discovery.ts +20 -2
- package/src/extensibility/skill-management.ts +9 -2
- package/src/extensibility/skills.ts +6 -1
- package/src/gjc-runtime/deep-interview-crystallize.ts +1814 -0
- package/src/gjc-runtime/deep-interview-recorder.ts +20 -2
- package/src/gjc-runtime/deep-interview-runtime.ts +1415 -13
- package/src/gjc-runtime/deep-interview-stage.ts +98 -21
- package/src/gjc-runtime/gc-runtime.ts +206 -9
- package/src/gjc-runtime/launch-worktree.ts +70 -9
- package/src/gjc-runtime/psmux-detect.ts +28 -4
- package/src/gjc-runtime/ralplan-runtime.ts +447 -52
- package/src/gjc-runtime/session-state-sidecar.ts +3 -2
- package/src/gjc-runtime/sidecar-bootstrap-env.ts +19 -0
- package/src/gjc-runtime/state-argv.ts +2 -0
- package/src/gjc-runtime/state-migrations.ts +91 -29
- package/src/gjc-runtime/state-runtime.ts +3716 -135
- package/src/gjc-runtime/state-writer.ts +105 -16
- package/src/gjc-runtime/tmux-common.ts +8 -5
- package/src/gjc-runtime/ultragoal-runtime.ts +16 -4
- package/src/gjc-runtime/workflow-manifest.generated.json +70 -42
- package/src/gjc-runtime/workflow-manifest.ts +54 -21
- package/src/harness-control-plane/operate.ts +12 -4
- package/src/harness-control-plane/owner.ts +5 -1
- package/src/hashline/parser.ts +48 -9
- package/src/hashline/recovery.ts +13 -4
- package/src/internal-urls/docs-index.generated.ts +20 -19
- package/src/internal-urls/skill-path.ts +19 -0
- package/src/internal-urls/skill-protocol.ts +2 -0
- package/src/lsp/config.ts +12 -63
- package/src/lsp/edits.ts +6 -0
- package/src/lsp/workspace-path.ts +51 -0
- package/src/main.ts +195 -31
- package/src/memories/index.ts +88 -7
- package/src/modes/acp/acp-agent.ts +88 -4
- package/src/modes/components/custom-editor.ts +14 -0
- package/src/modes/components/customization/customization-dashboard.ts +12 -0
- package/src/modes/components/extensions/extension-dashboard.ts +2 -2
- package/src/modes/components/extensions/state-manager.ts +15 -5
- package/src/modes/components/hook-editor.ts +1 -1
- package/src/modes/components/hook-selector.ts +1 -1
- package/src/modes/components/model-selector.ts +1 -4
- package/src/modes/components/provider-onboarding-selector.ts +1 -1
- package/src/modes/components/status-line/segments.ts +4 -0
- package/src/modes/controllers/event-controller.ts +11 -4
- package/src/modes/controllers/input-controller.ts +76 -31
- package/src/modes/controllers/runtime-mcp-command-controller.ts +29 -16
- package/src/modes/controllers/selector-controller.ts +24 -15
- package/src/modes/controllers/todo-command-controller.ts +1 -1
- package/src/modes/interactive-mode.ts +5 -1
- package/src/modes/runtime-init.ts +4 -0
- package/src/modes/utils/abort-message.ts +3 -1
- package/src/modes/utils/interrupt-ownership.ts +12 -0
- package/src/modes/utils/keybinding-matchers.ts +4 -0
- package/src/modes/utils/macos-option-forwarding.ts +80 -0
- package/src/progress/collect-project-progress.ts +153 -0
- package/src/progress/progress-contract.ts +172 -0
- package/src/progress/progress-snapshot.ts +140 -0
- package/src/progress/project-progress.ts +446 -0
- package/src/progress/render-progress.ts +209 -0
- package/src/prompts/system/master-mode.md +1 -0
- package/src/prompts/tools/skill-discovery.md +1 -1
- package/src/runtime-mcp/client.ts +4 -2
- package/src/runtime-mcp/config-writer.ts +10 -6
- package/src/runtime-mcp/config.ts +1 -0
- package/src/runtime-mcp/json-rpc.ts +2 -1
- package/src/runtime-mcp/manager.ts +29 -11
- package/src/runtime-mcp/mcp-redirect.ts +73 -0
- package/src/runtime-mcp/oauth-flow.ts +14 -2
- package/src/runtime-mcp/oauth-public-url.ts +14 -0
- package/src/runtime-mcp/plugin-network-boundary.ts +4 -0
- package/src/runtime-mcp/pool.ts +6 -0
- package/src/runtime-mcp/project-host-values.ts +46 -0
- package/src/runtime-mcp/smithery-registry.ts +22 -3
- package/src/runtime-mcp/transports/http.ts +4 -3
- package/src/runtime-mcp/types.ts +6 -0
- package/src/sdk/acp/adapter.ts +95 -8
- package/src/sdk/broker/broker-exit.ts +52 -23
- package/src/sdk/broker/broker.ts +81 -6
- package/src/sdk/broker/doctor-restart.ts +4 -0
- package/src/sdk/broker/ensure.ts +31 -2
- package/src/sdk/broker/lifecycle.ts +711 -66
- package/src/sdk/broker/session-index.ts +191 -81
- package/src/sdk/bus/chat-daemon-cli.ts +38 -1
- package/src/sdk/bus/chat-daemon-control.ts +2 -2
- package/src/sdk/bus/index.ts +238 -43
- package/src/sdk/bus/telegram-daemon-contract.ts +6 -1
- package/src/sdk/cli/session-cli.ts +17 -3
- package/src/sdk/client/client.ts +28 -8
- package/src/sdk/host/query/handlers.ts +9 -1
- package/src/sdk/host/session-runtime.test.ts +2705 -303
- package/src/sdk/host/session-runtime.ts +490 -143
- package/src/sdk/host/surface-policy.ts +1 -0
- package/src/sdk/index.ts +8 -0
- package/src/sdk/lifecycle-session.ts +3 -1
- package/src/sdk/prompt-deadline-manager.ts +15 -0
- package/src/sdk/protocol/operation-inventory.generated.json +146 -0
- package/src/sdk/protocol/operation-registry.ts +9 -2
- package/src/sdk/router/session-router.ts +82 -18
- package/src/sdk/session-list.ts +1 -0
- package/src/sdk/session.ts +69 -45
- package/src/session/agent-session.ts +679 -238
- package/src/session/artifacts.ts +176 -71
- package/src/session/internal/managed-gc-retirement-codec.ts +319 -0
- package/src/session/internal/managed-session-scope.ts +3779 -462
- package/src/session/internal/managed-session-storage.ts +501 -78
- package/src/session/internal/managed-task-owner-cleanup.ts +473 -0
- package/src/session/internal/task-artifact-owner-access.ts +19 -3
- package/src/session/internal/task-artifact-owner-transcript.ts +547 -1
- package/src/session/session-manager.ts +951 -133
- package/src/session/session-retirement.ts +573 -14
- package/src/session/session-storage.ts +447 -15
- package/src/session/task-artifact-owner-codec.ts +71 -8
- package/src/session/task-artifact-owner-retirement.ts +21 -19
- package/src/setup/credential-auto-import.ts +12 -3
- package/src/setup/credential-import.ts +176 -5
- package/src/setup/paseo/announce.ts +6 -1
- package/src/skill-state/active-state.ts +145 -2
- package/src/skill-state/workflow-mutation-guard.ts +102 -10
- package/src/slash-commands/builtin-registry.ts +39 -9
- package/src/slash-commands/helpers/mcp.ts +8 -4
- package/src/slash-commands/helpers/progress-report.ts +23 -0
- package/src/stt/setup.ts +3 -5
- package/src/task/commands.ts +3 -1
- package/src/task/executor.ts +4 -0
- package/src/task/index.ts +6 -0
- package/src/task/isolation-dir.ts +143 -0
- package/src/task/worktree.ts +16 -7
- package/src/tools/ask.ts +205 -6
- package/src/tools/ast-edit-write-path.ts +68 -0
- package/src/tools/ast-edit.ts +10 -1
- package/src/tools/bash-allowed-prefixes.ts +15 -0
- package/src/tools/bash-skill-urls.ts +56 -3
- package/src/tools/bash.ts +48 -79
- package/src/tools/browser/cdp-url.ts +18 -0
- package/src/tools/browser.ts +8 -1
- package/src/tools/descriptors.ts +5 -1
- package/src/tools/eval.ts +56 -36
- package/src/tools/gh.ts +10 -0
- package/src/tools/github-side-effect.ts +112 -0
- package/src/tools/image-gen.ts +1 -1
- package/src/tools/index.ts +3 -0
- package/src/tools/monitor-mutation.ts +27 -0
- package/src/tools/monitor.ts +7 -0
- package/src/tools/python.ts +188 -66
- package/src/tools/recipe/index.ts +9 -0
- package/src/tools/recipe/recipe-guard.ts +19 -0
- package/src/tools/restricted-cwd.ts +10 -0
- package/src/tools/skill-discovery.ts +5 -0
- package/src/tools/skill.ts +28 -1
- package/src/tools/todo-write.ts +10 -1
- package/src/tools/tool-catalog.generated.ts +1 -1
- package/src/tools/write.ts +1 -0
- package/src/utils/external-editor.ts +3 -2
- package/src/utils/tools-checksum.ts +34 -0
- package/src/utils/tools-manager.ts +24 -6
- package/src/web/insane/url-guard.ts +2 -1
- package/src/web/search/providers/codex.ts +3 -2
|
@@ -22,6 +22,7 @@ export type BrokerFenceReason = "suspect-unpublished" | "observation-ambiguous"
|
|
|
22
22
|
export type BrokerExitReason =
|
|
23
23
|
| "ownership-fence-expired"
|
|
24
24
|
| "publication-liveness-timeout"
|
|
25
|
+
| "heartbeat-renewal-blocked"
|
|
25
26
|
| "restart-committed"
|
|
26
27
|
| "shutdown-request"
|
|
27
28
|
| "startup-failure"
|
|
@@ -39,6 +40,8 @@ export interface BrokerExitRecord {
|
|
|
39
40
|
fenceReason: BrokerFenceReason | null;
|
|
40
41
|
fencedForMs: number;
|
|
41
42
|
uptimeMs: number;
|
|
43
|
+
/** For a blocked heartbeat renewal: retained removal transition path. */
|
|
44
|
+
blockingLockPath?: string;
|
|
42
45
|
pid: number;
|
|
43
46
|
signal: "SIGINT" | "SIGTERM" | null;
|
|
44
47
|
writtenAt: number;
|
|
@@ -47,7 +50,7 @@ export interface BrokerExitRecord {
|
|
|
47
50
|
export interface BrokerStartupExitRecord {
|
|
48
51
|
version: 1;
|
|
49
52
|
mode: "startup";
|
|
50
|
-
reason: "startup-deadline" | "startup-signal";
|
|
53
|
+
reason: "startup-deadline" | "startup-signal" | "startup-lock-blocked";
|
|
51
54
|
fenceReason: null;
|
|
52
55
|
fencedForMs: 0;
|
|
53
56
|
uptimeMs: number;
|
|
@@ -56,6 +59,8 @@ export interface BrokerStartupExitRecord {
|
|
|
56
59
|
exitCode: 1 | 130 | 143;
|
|
57
60
|
timeoutMs: number | null;
|
|
58
61
|
writtenAt: number;
|
|
62
|
+
/** For lock-blocked reason: path to the retained removal transition. */
|
|
63
|
+
blockingLockPath?: string;
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
export type BrokerStartupExitWriteStatus =
|
|
@@ -71,6 +76,7 @@ const lastWriteGenerationByPath = new Map<string, number>();
|
|
|
71
76
|
const EXIT_REASONS = new Set<BrokerExitReason>([
|
|
72
77
|
"ownership-fence-expired",
|
|
73
78
|
"publication-liveness-timeout",
|
|
79
|
+
"heartbeat-renewal-blocked",
|
|
74
80
|
"restart-committed",
|
|
75
81
|
"shutdown-request",
|
|
76
82
|
"startup-failure",
|
|
@@ -94,11 +100,20 @@ function isBrokerExitRecord(value: unknown): value is BrokerExitRecord {
|
|
|
94
100
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
95
101
|
const record = value as Partial<BrokerExitRecord>;
|
|
96
102
|
const keys = Object.keys(record).sort();
|
|
103
|
+
const requiredKeys = [
|
|
104
|
+
"fenceReason",
|
|
105
|
+
"fencedForMs",
|
|
106
|
+
"mode",
|
|
107
|
+
"pid",
|
|
108
|
+
"reason",
|
|
109
|
+
"signal",
|
|
110
|
+
"uptimeMs",
|
|
111
|
+
"version",
|
|
112
|
+
"writtenAt",
|
|
113
|
+
];
|
|
97
114
|
return (
|
|
98
|
-
keys.
|
|
99
|
-
|
|
100
|
-
.sort()
|
|
101
|
-
.join(",") &&
|
|
115
|
+
keys.every(key => requiredKeys.includes(key) || key === "blockingLockPath") &&
|
|
116
|
+
requiredKeys.every(key => keys.includes(key)) &&
|
|
102
117
|
record.version === 1 &&
|
|
103
118
|
(record.mode === "owned-root" || record.mode === "lost-root") &&
|
|
104
119
|
typeof record.reason === "string" &&
|
|
@@ -115,6 +130,14 @@ function isBrokerExitRecord(value: unknown): value is BrokerExitRecord {
|
|
|
115
130
|
(record.pid as number) > 0 &&
|
|
116
131
|
(record.signal === null || record.signal === "SIGINT" || record.signal === "SIGTERM") &&
|
|
117
132
|
(record.reason === "signal") === (record.signal !== null) &&
|
|
133
|
+
(record.reason === "heartbeat-renewal-blocked"
|
|
134
|
+
? record.mode === "owned-root" &&
|
|
135
|
+
record.fenceReason === null &&
|
|
136
|
+
record.fencedForMs === 0 &&
|
|
137
|
+
record.signal === null &&
|
|
138
|
+
typeof record.blockingLockPath === "string" &&
|
|
139
|
+
record.blockingLockPath.length > 0
|
|
140
|
+
: record.blockingLockPath === undefined) &&
|
|
118
141
|
Number.isSafeInteger(record.writtenAt) &&
|
|
119
142
|
(record.writtenAt as number) > 0
|
|
120
143
|
);
|
|
@@ -125,26 +148,29 @@ function isBrokerStartupExitRecord(value: unknown): value is BrokerStartupExitRe
|
|
|
125
148
|
const record = value as Partial<BrokerStartupExitRecord>;
|
|
126
149
|
const signalExitCode = record.signal === "SIGINT" ? 130 : record.signal === "SIGTERM" ? 143 : null;
|
|
127
150
|
const keys = Object.keys(record).sort();
|
|
151
|
+
const requiredKeys = [
|
|
152
|
+
"exitCode",
|
|
153
|
+
"fenceReason",
|
|
154
|
+
"fencedForMs",
|
|
155
|
+
"mode",
|
|
156
|
+
"pid",
|
|
157
|
+
"reason",
|
|
158
|
+
"signal",
|
|
159
|
+
"timeoutMs",
|
|
160
|
+
"uptimeMs",
|
|
161
|
+
"version",
|
|
162
|
+
"writtenAt",
|
|
163
|
+
];
|
|
164
|
+
const isValidShape =
|
|
165
|
+
keys.every(k => requiredKeys.includes(k) || k === "blockingLockPath") &&
|
|
166
|
+
requiredKeys.every(k => keys.includes(k));
|
|
128
167
|
return (
|
|
129
|
-
|
|
130
|
-
[
|
|
131
|
-
"exitCode",
|
|
132
|
-
"fenceReason",
|
|
133
|
-
"fencedForMs",
|
|
134
|
-
"mode",
|
|
135
|
-
"pid",
|
|
136
|
-
"reason",
|
|
137
|
-
"signal",
|
|
138
|
-
"timeoutMs",
|
|
139
|
-
"uptimeMs",
|
|
140
|
-
"version",
|
|
141
|
-
"writtenAt",
|
|
142
|
-
]
|
|
143
|
-
.sort()
|
|
144
|
-
.join(",") &&
|
|
168
|
+
isValidShape &&
|
|
145
169
|
record.version === 1 &&
|
|
146
170
|
record.mode === "startup" &&
|
|
147
|
-
(record.reason === "startup-deadline" ||
|
|
171
|
+
(record.reason === "startup-deadline" ||
|
|
172
|
+
record.reason === "startup-signal" ||
|
|
173
|
+
record.reason === "startup-lock-blocked") &&
|
|
148
174
|
record.fenceReason === null &&
|
|
149
175
|
record.fencedForMs === 0 &&
|
|
150
176
|
Number.isSafeInteger(record.uptimeMs) &&
|
|
@@ -154,7 +180,10 @@ function isBrokerStartupExitRecord(value: unknown): value is BrokerStartupExitRe
|
|
|
154
180
|
(record.signal === null || record.signal === "SIGINT" || record.signal === "SIGTERM") &&
|
|
155
181
|
(record.exitCode === 1 || record.exitCode === 130 || record.exitCode === 143) &&
|
|
156
182
|
(record.timeoutMs === null || (Number.isSafeInteger(record.timeoutMs) && (record.timeoutMs as number) > 0)) &&
|
|
157
|
-
(record.reason === "startup-
|
|
183
|
+
(record.reason === "startup-lock-blocked"
|
|
184
|
+
? typeof record.blockingLockPath === "string" && record.blockingLockPath.length > 0
|
|
185
|
+
: record.blockingLockPath === undefined) &&
|
|
186
|
+
(record.reason === "startup-deadline" || record.reason === "startup-lock-blocked"
|
|
158
187
|
? record.exitCode === 1 && record.signal === null && record.timeoutMs !== null
|
|
159
188
|
: record.exitCode === signalExitCode && signalExitCode !== null && record.timeoutMs === null) &&
|
|
160
189
|
Number.isSafeInteger(record.writtenAt) &&
|
package/src/sdk/broker/broker.ts
CHANGED
|
@@ -6,9 +6,14 @@ import path from "node:path";
|
|
|
6
6
|
import type { NativeBrokerRestartIntent, NativeDirectoryTreeSnapshot } from "@gajae-code/natives";
|
|
7
7
|
import { logger, resolveEquivalentPath } from "@gajae-code/utils";
|
|
8
8
|
import packageJson from "../../../package.json" with { type: "json" };
|
|
9
|
+
import { FileLockAcquireError } from "../../config/file-lock";
|
|
9
10
|
import type { ModelProfileErrorDetails } from "../../config/model-profile-contract";
|
|
10
11
|
import { planLaunchWorktree } from "../../gjc-runtime/launch-worktree";
|
|
11
12
|
import { readExistingStateForMutation, withWorkflowStateLock } from "../../gjc-runtime/state-writer";
|
|
13
|
+
import type {
|
|
14
|
+
TaskArtifactOwnerDeletionEvidence,
|
|
15
|
+
TaskArtifactOwnerRetirementContinuation,
|
|
16
|
+
} from "../../session/task-artifact-owner-codec";
|
|
12
17
|
import { SdkClient, SdkClientError } from "../client";
|
|
13
18
|
import {
|
|
14
19
|
BROKER_RUNTIME_ABORT_CAPABILITY_FIELD,
|
|
@@ -127,6 +132,7 @@ import {
|
|
|
127
132
|
type SpawnSubstrateProvider,
|
|
128
133
|
} from "./spawn-authority";
|
|
129
134
|
import { createSpawnSubstrateProvider } from "./spawn-substrate";
|
|
135
|
+
import type { BrokerTaskArtifactOwnerRetirementDisposition } from "./task-artifact-owner-validation";
|
|
130
136
|
import { BrokerTransport } from "./transport";
|
|
131
137
|
|
|
132
138
|
export interface BrokerSettings {
|
|
@@ -158,6 +164,8 @@ export interface BrokerSettings {
|
|
|
158
164
|
restartRequestId?: string;
|
|
159
165
|
/** Cancel bootstrap before retained publication when the owning CLI receives a signal. */
|
|
160
166
|
startupAbortSignal?: AbortSignal;
|
|
167
|
+
/** Monotonic checkpoint deadline, leaving time for retained publication. */
|
|
168
|
+
startupCheckpointDeadline?: number;
|
|
161
169
|
/** Called synchronously when retained publication establishes broker readiness. */
|
|
162
170
|
onStartupReady?: () => void;
|
|
163
171
|
/** Test-only delay after session checkpoint to verify unpublished discovery ownership. */
|
|
@@ -293,6 +301,19 @@ export type BrokerCleanupEvidence = {
|
|
|
293
301
|
retainedTranscriptSuccessorPath?: string;
|
|
294
302
|
retainedTranscriptPlaceholderPath?: string;
|
|
295
303
|
retainedTranscriptUnknownPath?: string;
|
|
304
|
+
/** Immutable task-artifact owner authority captured before the first deletion effect. */
|
|
305
|
+
taskArtifactOwnerDeletionEvidence?: TaskArtifactOwnerDeletionEvidence;
|
|
306
|
+
/** Latest exact native remnant; it never replaces the original deletion evidence. */
|
|
307
|
+
taskArtifactOwnerRetirementContinuation?: TaskArtifactOwnerRetirementContinuation;
|
|
308
|
+
/** Strict owner-only wire disposition, decoded only with its separately stored evidence. */
|
|
309
|
+
taskArtifactOwnerRetirementOutcome?: BrokerTaskArtifactOwnerRetirementDisposition;
|
|
310
|
+
taskArtifactOwnerPayloadRetired?: true;
|
|
311
|
+
taskArtifactOwnerNamespaceRetained?: true;
|
|
312
|
+
taskArtifactOwnerRetired?: true;
|
|
313
|
+
/** Durable fact that transcript retirement completed while the owner namespace remains. */
|
|
314
|
+
taskArtifactOwnerTranscriptDeleted?: true;
|
|
315
|
+
/** Stable artifacts-phase owner refusal diagnostic. */
|
|
316
|
+
taskArtifactOwnerCleanupError?: string;
|
|
296
317
|
/** Durable proof that artifact cleanup completed before transcript mutation. */
|
|
297
318
|
artifactsRemoved?: boolean;
|
|
298
319
|
artifactsAbsentAtAuthorization?: true;
|
|
@@ -756,6 +777,17 @@ function normalizeAliasedString(
|
|
|
756
777
|
return { value: values[0] };
|
|
757
778
|
}
|
|
758
779
|
|
|
780
|
+
const BROKER_TASK_ARTIFACT_OWNER_CLEANUP_FIELDS = [
|
|
781
|
+
"taskArtifactOwnerDeletionEvidence",
|
|
782
|
+
"taskArtifactOwnerRetirementContinuation",
|
|
783
|
+
"taskArtifactOwnerRetirementOutcome",
|
|
784
|
+
"taskArtifactOwnerPayloadRetired",
|
|
785
|
+
"taskArtifactOwnerNamespaceRetained",
|
|
786
|
+
"taskArtifactOwnerRetired",
|
|
787
|
+
"taskArtifactOwnerTranscriptDeleted",
|
|
788
|
+
"taskArtifactOwnerCleanupError",
|
|
789
|
+
] as const;
|
|
790
|
+
|
|
759
791
|
export function normalizeBrokerInput(operation: string, input: Record<string, unknown>): InputNormalization {
|
|
760
792
|
const normalized: Record<string, unknown> = { ...input };
|
|
761
793
|
const session = normalizeAliasedString(input, "sessionId", ["id"]);
|
|
@@ -834,6 +866,18 @@ export function normalizeBrokerInput(operation: string, input: Record<string, un
|
|
|
834
866
|
if (cwd.value !== undefined) normalized.stateRoot = path.join(cwd.value, ".gjc", "state");
|
|
835
867
|
else if (stateRoot.value !== undefined) return error("invalid_input", "stateRoot requires cwd.");
|
|
836
868
|
|
|
869
|
+
if (operation === "session.delete") {
|
|
870
|
+
const hasOwnerField = (value: unknown): boolean =>
|
|
871
|
+
typeof value === "object" &&
|
|
872
|
+
value !== null &&
|
|
873
|
+
!Array.isArray(value) &&
|
|
874
|
+
BROKER_TASK_ARTIFACT_OWNER_CLEANUP_FIELDS.some(key => Object.hasOwn(value, key));
|
|
875
|
+
if (hasOwnerField(input) || hasOwnerField(target) || hasOwnerField(input.cleanup))
|
|
876
|
+
return error(
|
|
877
|
+
"invalid_input",
|
|
878
|
+
"Task-artifact owner cleanup state is broker-managed and cannot be supplied by clients.",
|
|
879
|
+
);
|
|
880
|
+
}
|
|
837
881
|
if (target) {
|
|
838
882
|
const normalizedTarget = { ...target };
|
|
839
883
|
delete normalizedTarget.path;
|
|
@@ -1530,12 +1574,14 @@ export class Broker {
|
|
|
1530
1574
|
#transport: BrokerTransport | null = null;
|
|
1531
1575
|
#heartbeatTimer: NodeJS.Timeout | null = null;
|
|
1532
1576
|
#startupAbortSignal: AbortSignal | undefined;
|
|
1577
|
+
#startupCheckpointDeadline: number | undefined;
|
|
1533
1578
|
#onStartupReady: (() => void) | undefined;
|
|
1534
1579
|
#startupPrePublicationDelayMs: number;
|
|
1535
1580
|
#startupPrePublicationTestHook: (() => Promise<void>) | undefined;
|
|
1536
1581
|
#startupAfterDiscoveryWriteTestHook: (() => Promise<void>) | undefined;
|
|
1537
1582
|
#startupPostPublicationDelayMs: number;
|
|
1538
1583
|
#completionTask: Promise<void> | null = null;
|
|
1584
|
+
#terminalExit: { mode: BrokerExitMode; reason: BrokerExitReason } | null = null;
|
|
1539
1585
|
#completion!: Promise<void>;
|
|
1540
1586
|
#resolveCompletion!: () => void;
|
|
1541
1587
|
#rejectCompletion!: (error: unknown) => void;
|
|
@@ -1569,6 +1615,7 @@ export class Broker {
|
|
|
1569
1615
|
this.#ownsResolveModelPin = settings.resolveModelPin === undefined;
|
|
1570
1616
|
this.#resolveModelPin = settings.resolveModelPin ?? createDefaultSdkHostModelResolver(this.settings.agentDir);
|
|
1571
1617
|
this.#startupAbortSignal = settings.startupAbortSignal;
|
|
1618
|
+
this.#startupCheckpointDeadline = settings.startupCheckpointDeadline;
|
|
1572
1619
|
this.#onStartupReady = settings.onStartupReady;
|
|
1573
1620
|
this.#startupPrePublicationDelayMs =
|
|
1574
1621
|
Number.isSafeInteger(settings.startupPrePublicationDelayMs) &&
|
|
@@ -3898,7 +3945,7 @@ export class Broker {
|
|
|
3898
3945
|
// checkpoint settles. The bootstrap watchdog owns this pre-publication
|
|
3899
3946
|
// interval; publishing first allowed it to kill an endpoint already handed
|
|
3900
3947
|
// to callers when a legitimate index-lock wait outlived the fence.
|
|
3901
|
-
await this.#checkpointSessionHeartbeats();
|
|
3948
|
+
await this.#checkpointSessionHeartbeats(this.#startupAbortSignal, this.#startupCheckpointDeadline);
|
|
3902
3949
|
this.#throwIfStartupAborted();
|
|
3903
3950
|
await this.#startupPrePublicationTestHook?.();
|
|
3904
3951
|
if (this.#startupPrePublicationDelayMs > 0) await Bun.sleep(this.#startupPrePublicationDelayMs);
|
|
@@ -3973,6 +4020,10 @@ export class Broker {
|
|
|
3973
4020
|
get completion(): Promise<void> {
|
|
3974
4021
|
return this.#completion;
|
|
3975
4022
|
}
|
|
4023
|
+
/** Why this broker completed, or null while it is still running. */
|
|
4024
|
+
get terminalExit(): { readonly mode: BrokerExitMode; readonly reason: BrokerExitReason } | null {
|
|
4025
|
+
return this.#terminalExit;
|
|
4026
|
+
}
|
|
3976
4027
|
#restartIdentity(): BrokerRestartOwnerIdentity | undefined {
|
|
3977
4028
|
const d = this.discovery;
|
|
3978
4029
|
if (!d?.incarnation) return undefined;
|
|
@@ -4231,15 +4282,29 @@ export class Broker {
|
|
|
4231
4282
|
if (publication) await this.#writeHeartbeat(publication);
|
|
4232
4283
|
}
|
|
4233
4284
|
/** Re-observes provably live session hosts and checkpoints their liveness. */
|
|
4234
|
-
async heartbeatSessions(now = Date.now()): Promise<number> {
|
|
4235
|
-
return await this.index.checkpointLiveHeartbeats(now);
|
|
4285
|
+
async heartbeatSessions(now = Date.now(), abortSignal?: AbortSignal, deadlineAt?: number): Promise<number> {
|
|
4286
|
+
return await this.index.checkpointLiveHeartbeats(now, abortSignal, deadlineAt);
|
|
4236
4287
|
}
|
|
4237
|
-
async #checkpointSessionHeartbeats(): Promise<void> {
|
|
4288
|
+
async #checkpointSessionHeartbeats(abortSignal?: AbortSignal, startupCheckpointDeadline?: number): Promise<void> {
|
|
4238
4289
|
if (this.#checkpointInFlight || this.#stopping) return;
|
|
4239
4290
|
this.#checkpointInFlight = true;
|
|
4240
4291
|
try {
|
|
4241
|
-
|
|
4292
|
+
// The CLI reserves publication headroom in this startup deadline.
|
|
4293
|
+
// Periodic passes use their own budget, not a retired startup signal.
|
|
4294
|
+
await this.heartbeatSessions(Date.now(), abortSignal, startupCheckpointDeadline);
|
|
4242
4295
|
} catch (error) {
|
|
4296
|
+
if (
|
|
4297
|
+
error instanceof FileLockAcquireError &&
|
|
4298
|
+
error.orphanPath &&
|
|
4299
|
+
this.#publication !== null &&
|
|
4300
|
+
this.#publicationState === "healthy-owned" &&
|
|
4301
|
+
this.#fenceReason === null &&
|
|
4302
|
+
this.#completionTask === null &&
|
|
4303
|
+
this.#provenOwnedRoot()
|
|
4304
|
+
) {
|
|
4305
|
+
await this.#complete("owned-root", "heartbeat-renewal-blocked", null, error.orphanPath);
|
|
4306
|
+
return;
|
|
4307
|
+
}
|
|
4243
4308
|
logger.warn(`sdk broker: session heartbeat checkpoint failed: ${String(error)}`);
|
|
4244
4309
|
} finally {
|
|
4245
4310
|
this.#checkpointInFlight = false;
|
|
@@ -4249,8 +4314,10 @@ export class Broker {
|
|
|
4249
4314
|
mode: BrokerExitMode,
|
|
4250
4315
|
reason: BrokerExitReason,
|
|
4251
4316
|
signal: BrokerExitRecord["signal"] = null,
|
|
4317
|
+
blockingLockPath?: string,
|
|
4252
4318
|
): Promise<void> {
|
|
4253
4319
|
if (this.#completionTask) return this.#completionTask;
|
|
4320
|
+
this.#terminalExit = { mode, reason };
|
|
4254
4321
|
const now = process.hrtime.bigint();
|
|
4255
4322
|
const fenceStartedAt = this.#lossAt ?? this.#ambiguousAt;
|
|
4256
4323
|
const exitRecord: BrokerExitRecord & Record<string, unknown> = {
|
|
@@ -4260,11 +4327,19 @@ export class Broker {
|
|
|
4260
4327
|
fenceReason: this.#fenceReason,
|
|
4261
4328
|
fencedForMs: fenceStartedAt === null ? 0 : Math.max(0, Number((now - fenceStartedAt) / 1_000_000n)),
|
|
4262
4329
|
uptimeMs: this.#startedAt === null ? 0 : Math.max(0, Number((now - this.#startedAt) / 1_000_000n)),
|
|
4330
|
+
...(blockingLockPath === undefined ? {} : { blockingLockPath }),
|
|
4263
4331
|
pid: process.pid,
|
|
4264
4332
|
signal,
|
|
4265
4333
|
writtenAt: Date.now(),
|
|
4266
4334
|
};
|
|
4267
|
-
|
|
4335
|
+
const message =
|
|
4336
|
+
reason === "heartbeat-renewal-blocked" && blockingLockPath
|
|
4337
|
+
? `blocked by retained removal transition ${blockingLockPath}`
|
|
4338
|
+
: undefined;
|
|
4339
|
+
(mode === "lost-root" || message !== undefined ? logger.warn : logger.info)("sdk broker: exiting", {
|
|
4340
|
+
...exitRecord,
|
|
4341
|
+
...(message === undefined ? {} : { message }),
|
|
4342
|
+
});
|
|
4268
4343
|
this.#stopping = true;
|
|
4269
4344
|
this.#checkpointInFlight = false;
|
|
4270
4345
|
this.#publicationState = "stopping";
|
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
} from "./broker";
|
|
10
10
|
import { launchAuthorizedBrokerSuccessor, oldOwnerConfirmedExited } from "./daemon-entry";
|
|
11
11
|
import { type BrokerDiscovery, readBrokerDiscovery } from "./discovery";
|
|
12
|
+
import { isBrokerAttachOnly } from "./ensure";
|
|
12
13
|
|
|
13
14
|
export interface DoctorBrokerRestartOptions {
|
|
14
15
|
agentDir: string;
|
|
@@ -33,6 +34,8 @@ export type DoctorBrokerRestartOutcome =
|
|
|
33
34
|
adopted: boolean;
|
|
34
35
|
}
|
|
35
36
|
| { kind: "owner_unavailable"; reason: "no_discovery" | "owner_not_confirmed_live" }
|
|
37
|
+
/** Attach-only mode: the broker belongs to an external supervisor, so restart through it. */
|
|
38
|
+
| { kind: "attach_only_refused"; reason: "supervisor_owned" }
|
|
36
39
|
| { kind: "prepare_refused"; code: string; message: string }
|
|
37
40
|
| { kind: "commit_refused"; code: string; message: string }
|
|
38
41
|
| { kind: "old_owner_exit_timeout"; requestId: string; oldOwner: BrokerRestartOwnerIdentity }
|
|
@@ -163,6 +166,7 @@ const OLD_OWNER_EXIT_POLL_MS = 50;
|
|
|
163
166
|
* proven it owns the root -- never here, and never before that proof exists.
|
|
164
167
|
*/
|
|
165
168
|
export async function restartBrokerForDoctor(options: DoctorBrokerRestartOptions): Promise<DoctorBrokerRestartOutcome> {
|
|
169
|
+
if (isBrokerAttachOnly()) return { kind: "attach_only_refused", reason: "supervisor_owned" };
|
|
166
170
|
const old = await readBrokerDiscovery(options.agentDir);
|
|
167
171
|
if (!old) return { kind: "owner_unavailable", reason: "no_discovery" };
|
|
168
172
|
const oldOwner = identity(old);
|
package/src/sdk/broker/ensure.ts
CHANGED
|
@@ -6,7 +6,7 @@ import path from "node:path";
|
|
|
6
6
|
import packageJson from "../../../package.json" with { type: "json" };
|
|
7
7
|
import { acquireFileLock, type FileLockOptions, withFileLock } from "../../config/file-lock";
|
|
8
8
|
import { loadInstallationHostId, loadLegacyInstallationHostId } from "../../config/machine-identity";
|
|
9
|
-
import { SdkClient } from "../client/client";
|
|
9
|
+
import { SdkClient, SdkClientError } from "../client/client";
|
|
10
10
|
import { type BrokerStartupExitRecord, clearBrokerStartupExitRecord, readBrokerStartupExitRecord } from "./broker-exit";
|
|
11
11
|
import {
|
|
12
12
|
type BrokerDiscovery,
|
|
@@ -41,6 +41,8 @@ function brokerStartupFailureReason(marker: BrokerStartupFailureMarker | undefin
|
|
|
41
41
|
|
|
42
42
|
function brokerStartupExitReason(record: BrokerStartupExitRecord | undefined): string | undefined {
|
|
43
43
|
if (!record) return undefined;
|
|
44
|
+
if (record.reason === "startup-lock-blocked")
|
|
45
|
+
return `SDK broker startup blocked by retained removal transition ${record.blockingLockPath}.`;
|
|
44
46
|
if (record.reason === "startup-deadline")
|
|
45
47
|
return `SDK broker startup exceeded its ${record.timeoutMs}ms fence deadline.`;
|
|
46
48
|
return `SDK broker startup interrupted by ${record.signal} before readiness.`;
|
|
@@ -1001,9 +1003,36 @@ function startEnsure(settings: EnsureBrokerSettings, initiator: EnsureInitiator)
|
|
|
1001
1003
|
return entry;
|
|
1002
1004
|
}
|
|
1003
1005
|
|
|
1004
|
-
/**
|
|
1006
|
+
/**
|
|
1007
|
+
* Attach-only client mode. When `GJC_SDK_BROKER_AUTOSTART=0`, `ensureBroker`
|
|
1008
|
+
* never spawns, retires or restarts a broker: it returns a live, reusable
|
|
1009
|
+
* discovery or fails with `broker_unavailable`. Hosts that supervise their own
|
|
1010
|
+
* broker (for example a system service) set it for every client they run. The
|
|
1011
|
+
* broker entrypoints never call `ensureBroker`, so they ignore the variable and
|
|
1012
|
+
* their descendants may inherit it.
|
|
1013
|
+
*/
|
|
1014
|
+
export const SDK_BROKER_AUTOSTART_ENV = "GJC_SDK_BROKER_AUTOSTART";
|
|
1015
|
+
|
|
1016
|
+
export function isBrokerAttachOnly(env: NodeJS.ProcessEnv = process.env): boolean {
|
|
1017
|
+
return env[SDK_BROKER_AUTOSTART_ENV] === "0";
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
async function attachExistingBroker(settings: EnsureBrokerSettings): Promise<BrokerDiscovery> {
|
|
1021
|
+
const discovery = await readBrokerDiscovery(settings.agentDir, settings.heartbeatTtlMs);
|
|
1022
|
+
if (discovery && (await isBrokerReusable(discovery))) return discovery;
|
|
1023
|
+
throw new SdkClientError(
|
|
1024
|
+
"broker_unavailable",
|
|
1025
|
+
`SDK broker is not running and ${SDK_BROKER_AUTOSTART_ENV}=0 forbids starting one.`,
|
|
1026
|
+
);
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
/**
|
|
1030
|
+
* Starts the detached broker entrypoint when discovery has no live owner. In
|
|
1031
|
+
* attach-only mode (`SDK_BROKER_AUTOSTART_ENV`) it only attaches.
|
|
1032
|
+
*/
|
|
1005
1033
|
export function ensureBroker(settings: EnsureBrokerSettings): Promise<BrokerDiscovery> {
|
|
1006
1034
|
const resolvedSettings = { ...settings, agentDir: path.resolve(settings.agentDir) };
|
|
1035
|
+
if (isBrokerAttachOnly()) return attachExistingBroker(resolvedSettings);
|
|
1007
1036
|
const inFlight = ensureInFlight.get(resolvedSettings.agentDir) ?? startEnsure(resolvedSettings, "discovery");
|
|
1008
1037
|
return inFlight.discovery;
|
|
1009
1038
|
}
|