@code-yeongyu/senpi 2026.9.27-4 → 2026.9.28-2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +50 -0
- package/dist/bundle/chunks/{app-server-command-3GVJZFFH.js → app-server-command-H6LFICZ2.js} +1 -1
- package/dist/bundle/chunks/{azure-openai-responses-4SUOOZZ4.js → azure-openai-responses-FCZNBRWE.js} +1 -1
- package/dist/bundle/chunks/bedrock-converse-stream.js +1 -1
- package/dist/bundle/chunks/{chunk-PSCNHY7D.js → chunk-3GMFUEU7.js} +1 -1
- package/dist/bundle/chunks/{chunk-HBG6SQU5.js → chunk-62XHQXCZ.js} +1 -1
- package/dist/bundle/chunks/{chunk-EJKCBRYK.js → chunk-6BWCPOCV.js} +4 -4
- package/dist/bundle/chunks/{chunk-SLL375O7.js → chunk-6VD3EBQE.js} +1 -1
- package/dist/bundle/chunks/chunk-7YUGCTEV.js +15 -0
- package/dist/bundle/chunks/{chunk-FWBSGMAE.js → chunk-A4UMPXQF.js} +1 -1
- package/dist/bundle/chunks/chunk-BBK6SSYT.js +2 -0
- package/dist/bundle/chunks/{chunk-C2425O2Q.js → chunk-CNQ4JB45.js} +1 -1
- package/dist/bundle/chunks/{chunk-27IFXX3B.js → chunk-DRN4FQCE.js} +1 -1
- package/dist/bundle/chunks/{chunk-22MGY5JQ.js → chunk-EHSZ7UCW.js} +1 -1
- package/dist/bundle/chunks/chunk-FHJYIU3U.js +5 -0
- package/dist/bundle/chunks/chunk-GJUCSTAG.js +19 -0
- package/dist/bundle/chunks/chunk-KOPTADA3.js +8 -0
- package/dist/bundle/chunks/{chunk-VMKAYXHL.js → chunk-LSW7QSLV.js} +31 -26
- package/dist/bundle/chunks/{chunk-2BMD37YV.js → chunk-LUPPSEQW.js} +1 -1
- package/dist/bundle/chunks/{chunk-NRGMT74E.js → chunk-QOVUQZO4.js} +1 -1
- package/dist/bundle/chunks/{chunk-IKXPBYSO.js → chunk-SICBVLRH.js} +1 -1
- package/dist/bundle/chunks/chunk-SN4ZHPMN.js +135 -0
- package/dist/bundle/chunks/{chunk-MUTD2NOH.js → chunk-TFA3YAJK.js} +1 -1
- package/dist/bundle/chunks/{chunk-4T4GFAGK.js → chunk-VFSXUT7K.js} +1 -1
- package/dist/bundle/chunks/{cli-main-66NFBKVH.js → cli-main-GYRTYPMG.js} +1 -1
- package/dist/bundle/chunks/{google-generative-ai-ZTGKZTGU.js → google-generative-ai-LFCBHG3Y.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-CCZ376YK.js → google-vertex-C474FXU7.js} +1 -1
- package/dist/bundle/chunks/{help-fast-path-NZ3I2UEN.js → help-fast-path-3U3YDEZ6.js} +1 -1
- package/dist/bundle/chunks/{host-command-RORPAC5X.js → host-command-6CJ7YM6W.js} +1 -1
- package/dist/bundle/chunks/{host-lifecycle-UDMJGLOR.js → host-lifecycle-RZIMOFDM.js} +1 -1
- package/dist/bundle/chunks/host-lifecycle.js +6 -6
- package/dist/bundle/chunks/interactive-host-runtime-A3GEIFTU.js +4 -0
- package/dist/bundle/chunks/{interactive-mode-LOAADKLH.js → interactive-mode-LX665HTP.js} +1 -1
- package/dist/bundle/chunks/{list-tips-S5CANO5W.js → list-tips-S4U7TKER.js} +1 -1
- package/dist/bundle/chunks/multi-session-host-MFTUM6XQ.js +21 -0
- package/dist/bundle/chunks/{openai-codex-responses-YSGZZDD5.js → openai-codex-responses-2LDIFL6Z.js} +1 -1
- package/dist/bundle/chunks/{openai-completions-KWHRWCBN.js → openai-completions-7KZLPKYP.js} +1 -1
- package/dist/bundle/chunks/{openai-images-6U5FCN5S.js → openai-images-I7DR7ERP.js} +1 -1
- package/dist/bundle/chunks/{openai-responses-7PWMBGYX.js → openai-responses-LCHS3AF3.js} +1 -1
- package/dist/bundle/chunks/{openrouter-images-QIKWQZUD.js → openrouter-images-IPNDRK6C.js} +1 -1
- package/dist/bundle/chunks/{package-manager-cli-5EEDA35I.js → package-manager-cli-6IAE5WG3.js} +1 -1
- package/dist/bundle/chunks/{rotation-stream-KZG4OVR7.js → rotation-stream-ZVJEGA2G.js} +1 -1
- package/dist/bundle/chunks/{rpc-mode-HOEA5NGQ.js → rpc-mode-XN3HNZMH.js} +1 -1
- package/dist/bundle/chunks/session-picker-FPKB4DAC.js +2 -0
- package/dist/bundle/chunks/session-worker.js +318 -309
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/cli/args.js +1 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/host-command.d.ts +8 -1
- package/dist/cli/host-command.d.ts.map +1 -1
- package/dist/cli/host-command.js +66 -14
- package/dist/cli/host-command.js.map +1 -1
- package/dist/core/agent-session.d.ts +18 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +119 -3
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.d.ts +2 -2
- package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.d.ts.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.js +13 -5
- package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.js.map +1 -1
- package/dist/core/extensions/builtin/tool-search/native-search.d.ts.map +1 -1
- package/dist/core/extensions/builtin/tool-search/native-search.js +13 -1
- package/dist/core/extensions/builtin/tool-search/native-search.js.map +1 -1
- package/dist/core/retry-fallback/candidates.d.ts +26 -0
- package/dist/core/retry-fallback/candidates.d.ts.map +1 -0
- package/dist/core/retry-fallback/candidates.js +41 -0
- package/dist/core/retry-fallback/candidates.js.map +1 -0
- package/dist/core/retry-fallback/circuit-probes.d.ts +30 -0
- package/dist/core/retry-fallback/circuit-probes.d.ts.map +1 -0
- package/dist/core/retry-fallback/circuit-probes.js +60 -0
- package/dist/core/retry-fallback/circuit-probes.js.map +1 -0
- package/dist/core/retry-fallback/circuit.d.ts +101 -0
- package/dist/core/retry-fallback/circuit.d.ts.map +1 -0
- package/dist/core/retry-fallback/circuit.js +175 -0
- package/dist/core/retry-fallback/circuit.js.map +1 -0
- package/dist/core/retry-fallback/controller-types.d.ts +58 -0
- package/dist/core/retry-fallback/controller-types.d.ts.map +1 -0
- package/dist/core/retry-fallback/controller-types.js +2 -0
- package/dist/core/retry-fallback/controller-types.js.map +1 -0
- package/dist/core/retry-fallback/controller.d.ts +21 -49
- package/dist/core/retry-fallback/controller.d.ts.map +1 -1
- package/dist/core/retry-fallback/controller.js +88 -42
- package/dist/core/retry-fallback/controller.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +25 -17
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-failure-report.d.ts +33 -0
- package/dist/core/session-failure-report.d.ts.map +1 -0
- package/dist/core/session-failure-report.js +62 -0
- package/dist/core/session-failure-report.js.map +1 -0
- package/dist/core/settings-manager.d.ts +3 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +4 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modes/index.d.ts +1 -0
- package/dist/modes/index.d.ts.map +1 -1
- package/dist/modes/index.js +2 -0
- package/dist/modes/index.js.map +1 -1
- package/dist/modes/interactive/help-content.d.ts.map +1 -1
- package/dist/modes/interactive/help-content.js +3 -0
- package/dist/modes/interactive/help-content.js.map +1 -1
- package/dist/modes/interactive/interactive-host-attach.d.ts +10 -0
- package/dist/modes/interactive/interactive-host-attach.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-host-attach.js +14 -0
- package/dist/modes/interactive/interactive-host-attach.js.map +1 -0
- package/dist/modes/interactive/interactive-host-runtime.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-host-runtime.js +3 -6
- package/dist/modes/interactive/interactive-host-runtime.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +12 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +95 -1
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/session-failure-info.d.ts +3 -0
- package/dist/modes/interactive/session-failure-info.d.ts.map +1 -0
- package/dist/modes/interactive/session-failure-info.js +21 -0
- package/dist/modes/interactive/session-failure-info.js.map +1 -0
- package/dist/modes/interactive/tips/catalog/model-tips.d.ts +7 -7
- package/dist/modes/interactive/tips/catalog/model-tips.d.ts.map +1 -1
- package/dist/modes/interactive/tips/catalog/model-tips.js +7 -1
- package/dist/modes/interactive/tips/catalog/model-tips.js.map +1 -1
- package/dist/modes/interactive/tips/catalog/session-tips.d.ts.map +1 -1
- package/dist/modes/interactive/tips/catalog/session-tips.js +1 -1
- package/dist/modes/interactive/tips/catalog/session-tips.js.map +1 -1
- package/dist/modes/rpc/host-attach-hold.d.ts +16 -0
- package/dist/modes/rpc/host-attach-hold.d.ts.map +1 -0
- package/dist/modes/rpc/host-attach-hold.js +9 -0
- package/dist/modes/rpc/host-attach-hold.js.map +1 -0
- package/dist/modes/rpc/host-cleanup-paths.d.ts +20 -0
- package/dist/modes/rpc/host-cleanup-paths.d.ts.map +1 -0
- package/dist/modes/rpc/host-cleanup-paths.js +13 -0
- package/dist/modes/rpc/host-cleanup-paths.js.map +1 -0
- package/dist/modes/rpc/host-client-occupancy.d.ts +24 -0
- package/dist/modes/rpc/host-client-occupancy.d.ts.map +1 -0
- package/dist/modes/rpc/host-client-occupancy.js +53 -0
- package/dist/modes/rpc/host-client-occupancy.js.map +1 -0
- package/dist/modes/rpc/host-daemon-paths.d.ts +61 -8
- package/dist/modes/rpc/host-daemon-paths.d.ts.map +1 -1
- package/dist/modes/rpc/host-daemon-paths.js +128 -11
- package/dist/modes/rpc/host-daemon-paths.js.map +1 -1
- package/dist/modes/rpc/host-daemon-registration.d.ts +11 -1
- package/dist/modes/rpc/host-daemon-registration.d.ts.map +1 -1
- package/dist/modes/rpc/host-daemon-registration.js +28 -15
- package/dist/modes/rpc/host-daemon-registration.js.map +1 -1
- package/dist/modes/rpc/host-endpoints.d.ts +12 -0
- package/dist/modes/rpc/host-endpoints.d.ts.map +1 -0
- package/dist/modes/rpc/host-endpoints.js +59 -0
- package/dist/modes/rpc/host-endpoints.js.map +1 -0
- package/dist/modes/rpc/host-ensure-lock.d.ts +11 -0
- package/dist/modes/rpc/host-ensure-lock.d.ts.map +1 -0
- package/dist/modes/rpc/host-ensure-lock.js +49 -0
- package/dist/modes/rpc/host-ensure-lock.js.map +1 -0
- package/dist/modes/rpc/host-ensure.d.ts +7 -0
- package/dist/modes/rpc/host-ensure.d.ts.map +1 -1
- package/dist/modes/rpc/host-ensure.js +42 -65
- package/dist/modes/rpc/host-ensure.js.map +1 -1
- package/dist/modes/rpc/host-gc-evidence.d.ts +18 -0
- package/dist/modes/rpc/host-gc-evidence.d.ts.map +1 -0
- package/dist/modes/rpc/host-gc-evidence.js +128 -0
- package/dist/modes/rpc/host-gc-evidence.js.map +1 -0
- package/dist/modes/rpc/host-gc.d.ts +28 -0
- package/dist/modes/rpc/host-gc.d.ts.map +1 -0
- package/dist/modes/rpc/host-gc.js +110 -0
- package/dist/modes/rpc/host-gc.js.map +1 -0
- package/dist/modes/rpc/host-generations.d.ts +10 -2
- package/dist/modes/rpc/host-generations.d.ts.map +1 -1
- package/dist/modes/rpc/host-generations.js +12 -7
- package/dist/modes/rpc/host-generations.js.map +1 -1
- package/dist/modes/rpc/host-handoff.d.ts +6 -0
- package/dist/modes/rpc/host-handoff.d.ts.map +1 -1
- package/dist/modes/rpc/host-handoff.js +31 -4
- package/dist/modes/rpc/host-handoff.js.map +1 -1
- package/dist/modes/rpc/host-lifecycle-policy.d.ts +53 -0
- package/dist/modes/rpc/host-lifecycle-policy.d.ts.map +1 -0
- package/dist/modes/rpc/host-lifecycle-policy.js +64 -0
- package/dist/modes/rpc/host-lifecycle-policy.js.map +1 -0
- package/dist/modes/rpc/host-lifecycle.d.ts +1 -44
- package/dist/modes/rpc/host-lifecycle.d.ts.map +1 -1
- package/dist/modes/rpc/host-lifecycle.js +23 -85
- package/dist/modes/rpc/host-lifecycle.js.map +1 -1
- package/dist/modes/rpc/host-observe-request.d.ts +17 -0
- package/dist/modes/rpc/host-observe-request.d.ts.map +1 -0
- package/dist/modes/rpc/host-observe-request.js +30 -0
- package/dist/modes/rpc/host-observe-request.js.map +1 -0
- package/dist/modes/rpc/host-probe.d.ts +12 -0
- package/dist/modes/rpc/host-probe.d.ts.map +1 -1
- package/dist/modes/rpc/host-probe.js +28 -1
- package/dist/modes/rpc/host-probe.js.map +1 -1
- package/dist/modes/rpc/host-protocol-info.d.ts +2 -0
- package/dist/modes/rpc/host-protocol-info.d.ts.map +1 -1
- package/dist/modes/rpc/host-protocol-info.js +1 -0
- package/dist/modes/rpc/host-protocol-info.js.map +1 -1
- package/dist/modes/rpc/host-readiness.d.ts +22 -0
- package/dist/modes/rpc/host-readiness.d.ts.map +1 -0
- package/dist/modes/rpc/host-readiness.js +44 -0
- package/dist/modes/rpc/host-readiness.js.map +1 -0
- package/dist/modes/rpc/host-runner.d.ts +13 -0
- package/dist/modes/rpc/host-runner.d.ts.map +1 -1
- package/dist/modes/rpc/host-runner.js +23 -4
- package/dist/modes/rpc/host-runner.js.map +1 -1
- package/dist/modes/rpc/host-status-all.d.ts +31 -0
- package/dist/modes/rpc/host-status-all.d.ts.map +1 -0
- package/dist/modes/rpc/host-status-all.js +78 -0
- package/dist/modes/rpc/host-status-all.js.map +1 -0
- package/dist/modes/rpc/host-status-rows.d.ts +35 -0
- package/dist/modes/rpc/host-status-rows.d.ts.map +1 -0
- package/dist/modes/rpc/host-status-rows.js +42 -0
- package/dist/modes/rpc/host-status-rows.js.map +1 -0
- package/dist/modes/rpc/host-status.d.ts +32 -1
- package/dist/modes/rpc/host-status.d.ts.map +1 -1
- package/dist/modes/rpc/host-status.js +33 -27
- package/dist/modes/rpc/host-status.js.map +1 -1
- package/dist/modes/rpc/host-successor.d.ts +3 -1
- package/dist/modes/rpc/host-successor.d.ts.map +1 -1
- package/dist/modes/rpc/host-successor.js +105 -42
- package/dist/modes/rpc/host-successor.js.map +1 -1
- package/dist/modes/rpc/host-watchdog.d.ts +6 -0
- package/dist/modes/rpc/host-watchdog.d.ts.map +1 -1
- package/dist/modes/rpc/host-watchdog.js +12 -13
- package/dist/modes/rpc/host-watchdog.js.map +1 -1
- package/dist/modes/rpc/loop-lag-watchdog.d.ts +16 -0
- package/dist/modes/rpc/loop-lag-watchdog.d.ts.map +1 -1
- package/dist/modes/rpc/loop-lag-watchdog.js +34 -2
- package/dist/modes/rpc/loop-lag-watchdog.js.map +1 -1
- package/dist/modes/rpc/multi-session-host.d.ts +2 -1
- package/dist/modes/rpc/multi-session-host.d.ts.map +1 -1
- package/dist/modes/rpc/multi-session-host.js +33 -6
- package/dist/modes/rpc/multi-session-host.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts +2 -2
- package/dist/modes/rpc/rpc-mode.js +2 -2
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +16 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/modes/rpc/session-command-router.d.ts +9 -1
- package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
- package/dist/modes/rpc/session-command-router.js +4 -1
- package/dist/modes/rpc/session-command-router.js.map +1 -1
- package/dist/modes/rpc/session-path-key.d.ts +3 -1
- package/dist/modes/rpc/session-path-key.d.ts.map +1 -1
- package/dist/modes/rpc/session-path-key.js +3 -1
- package/dist/modes/rpc/session-path-key.js.map +1 -1
- package/docs/rpc.md +186 -19
- package/docs/settings.md +25 -1
- package/docs/usage.md +5 -2
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +24 -0
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/error-body.d.ts +6 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/error-body.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/error-body.js +36 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/error-body.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +14 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/autocomplete.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/autocomplete.js +6 -4
- package/node_modules/@earendil-works/pi-tui/dist/autocomplete.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts +3 -0
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +20 -0
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/editor-component.d.ts +2 -0
- package/node_modules/@earendil-works/pi-tui/dist/editor-component.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/editor-component.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/slash-command-autocomplete.d.ts +5 -0
- package/node_modules/@earendil-works/pi-tui/dist/slash-command-autocomplete.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/slash-command-autocomplete.js +7 -0
- package/node_modules/@earendil-works/pi-tui/dist/slash-command-autocomplete.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +7 -7
- package/dist/bundle/chunks/chunk-3DEXCYNN.js +0 -135
- package/dist/bundle/chunks/chunk-5X4KSPK5.js +0 -12
- package/dist/bundle/chunks/chunk-KMD5ZONU.js +0 -5
- package/dist/bundle/chunks/chunk-PEHZYGYA.js +0 -8
- package/dist/bundle/chunks/chunk-PRC5XIIH.js +0 -2
- package/dist/bundle/chunks/chunk-QKY33652.js +0 -18
- package/dist/bundle/chunks/interactive-host-runtime-TIFT2SKR.js +0 -4
- package/dist/bundle/chunks/multi-session-host-GRHKB7Q2.js +0 -21
- package/dist/bundle/chunks/session-picker-FTFCQYHH.js +0 -2
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The lifecycle supervisor's policy half: which cold-start mode and idle-exit window apply
|
|
3
|
+
* (`resolveHostPolicy`, environment over settings.json over the defaults), and the pure decision
|
|
4
|
+
* core that turns the current activity snapshot into active / idle / exit (`IdleExitDecider`).
|
|
5
|
+
*
|
|
6
|
+
* Nothing here touches a socket, a process or the filesystem; `host-lifecycle.ts` owns all of that
|
|
7
|
+
* and re-exports these names so every existing importer keeps resolving them at their original home.
|
|
8
|
+
*/
|
|
9
|
+
export type HostColdStart = "transient" | "persistent";
|
|
10
|
+
/** Environment override for the cold-start policy: `transient` or `persistent`. */
|
|
11
|
+
export declare const HOST_COLD_START_ENV = "SENPI_RPC_HOST_COLD_START";
|
|
12
|
+
/** Environment override for the idle-exit window in milliseconds. */
|
|
13
|
+
export declare const HOST_IDLE_EXIT_MS_ENV = "SENPI_RPC_HOST_IDLE_EXIT_MS";
|
|
14
|
+
/** Default idle-exit window: 15 minutes of continuous no-connection, no-turn idle. */
|
|
15
|
+
export declare const DEFAULT_HOST_IDLE_EXIT_MS: number;
|
|
16
|
+
/** Soft handoff deadline: rescan and report, never interrupt turns or in-flight requests. */
|
|
17
|
+
export declare const HANDOFF_GRACE_MS_ENV = "SENPI_RPC_HANDOFF_GRACE_MS";
|
|
18
|
+
export declare const DEFAULT_HANDOFF_GRACE_MS: number;
|
|
19
|
+
/** The policy fields ensureHost() records in rpc-host-daemon/settings.json. */
|
|
20
|
+
export interface HostLifecyclePolicyInput {
|
|
21
|
+
readonly coldStart?: HostColdStart;
|
|
22
|
+
readonly idleExitMs?: number;
|
|
23
|
+
}
|
|
24
|
+
export interface HostLifecyclePolicy {
|
|
25
|
+
readonly coldStart: HostColdStart;
|
|
26
|
+
readonly idleExitMs: number;
|
|
27
|
+
}
|
|
28
|
+
export declare function parseColdStart(value: string | undefined): HostColdStart | undefined;
|
|
29
|
+
export declare function parseIdleExitMs(value: string | undefined): number | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Resolves the effective host policy. Precedence: environment overrides beat
|
|
32
|
+
* settings.json, which beats the documented defaults (transient, 15 minutes).
|
|
33
|
+
* Invalid values at either source fall through to the next source.
|
|
34
|
+
*/
|
|
35
|
+
export declare function resolveHostPolicy(settings: unknown, env: Readonly<Record<string, string | undefined>>): HostLifecyclePolicy;
|
|
36
|
+
export interface HostActivity {
|
|
37
|
+
readonly connections: number;
|
|
38
|
+
readonly activeTurns: number;
|
|
39
|
+
}
|
|
40
|
+
export type IdleExitDecision = "active" | "idle" | "exit";
|
|
41
|
+
/**
|
|
42
|
+
* Pure idle-window decision core. `update()` must be called with the CURRENT
|
|
43
|
+
* activity state; the window only counts continuously idle time and any
|
|
44
|
+
* activity resets it, so a busy host can never cross the threshold.
|
|
45
|
+
*/
|
|
46
|
+
export declare class IdleExitDecider {
|
|
47
|
+
private idleSince;
|
|
48
|
+
private readonly now;
|
|
49
|
+
readonly idleExitMs: number;
|
|
50
|
+
constructor(idleExitMs: number, now?: () => number);
|
|
51
|
+
update(activity: HostActivity): IdleExitDecision;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=host-lifecycle-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-lifecycle-policy.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/host-lifecycle-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,YAAY,CAAC;AAEvD,mFAAmF;AACnF,eAAO,MAAM,mBAAmB,8BAA8B,CAAC;AAC/D,qEAAqE;AACrE,eAAO,MAAM,qBAAqB,gCAAgC,CAAC;AACnE,sFAAsF;AACtF,eAAO,MAAM,yBAAyB,QAAc,CAAC;AACrD,6FAA6F;AAC7F,eAAO,MAAM,oBAAoB,+BAA+B,CAAC;AACjE,eAAO,MAAM,wBAAwB,QAAc,CAAC;AAEpD,+EAA+E;AAC/E,MAAM,WAAW,wBAAwB;IACxC,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC;IACnC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC5B;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,GAAG,SAAS,CAEnF;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAI7E;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAChC,QAAQ,EAAE,OAAO,EACjB,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,GAC/C,mBAAmB,CASrB;AAED,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;AAE1D;;;;GAIG;AACH,qBAAa,eAAe;IAC3B,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAE5B,YAAY,UAAU,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,MAAiB,EAG3D;IAED,MAAM,CAAC,QAAQ,EAAE,YAAY,GAAG,gBAAgB,CAa/C;CACD"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/** Environment override for the cold-start policy: `transient` or `persistent`. */
|
|
2
|
+
export const HOST_COLD_START_ENV = "SENPI_RPC_HOST_COLD_START";
|
|
3
|
+
/** Environment override for the idle-exit window in milliseconds. */
|
|
4
|
+
export const HOST_IDLE_EXIT_MS_ENV = "SENPI_RPC_HOST_IDLE_EXIT_MS";
|
|
5
|
+
/** Default idle-exit window: 15 minutes of continuous no-connection, no-turn idle. */
|
|
6
|
+
export const DEFAULT_HOST_IDLE_EXIT_MS = 15 * 60_000;
|
|
7
|
+
/** Soft handoff deadline: rescan and report, never interrupt turns or in-flight requests. */
|
|
8
|
+
export const HANDOFF_GRACE_MS_ENV = "SENPI_RPC_HANDOFF_GRACE_MS";
|
|
9
|
+
export const DEFAULT_HANDOFF_GRACE_MS = 10 * 60_000;
|
|
10
|
+
export function parseColdStart(value) {
|
|
11
|
+
return value === "transient" || value === "persistent" ? value : undefined;
|
|
12
|
+
}
|
|
13
|
+
export function parseIdleExitMs(value) {
|
|
14
|
+
if (value === undefined || !/^\d+$/.test(value.trim()))
|
|
15
|
+
return undefined;
|
|
16
|
+
const parsed = Number(value.trim());
|
|
17
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Resolves the effective host policy. Precedence: environment overrides beat
|
|
21
|
+
* settings.json, which beats the documented defaults (transient, 15 minutes).
|
|
22
|
+
* Invalid values at either source fall through to the next source.
|
|
23
|
+
*/
|
|
24
|
+
export function resolveHostPolicy(settings, env) {
|
|
25
|
+
const record = isRecord(settings) ? settings : {};
|
|
26
|
+
const coldStart = parseColdStart(env[HOST_COLD_START_ENV]) ?? parseColdStart(asOptionalString(record.coldStart)) ?? "transient";
|
|
27
|
+
const idleExitMs = parseIdleExitMs(env[HOST_IDLE_EXIT_MS_ENV]) ??
|
|
28
|
+
parseIdleExitMs(asOptionalString(record.idleExitMs)) ??
|
|
29
|
+
DEFAULT_HOST_IDLE_EXIT_MS;
|
|
30
|
+
return { coldStart, idleExitMs };
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Pure idle-window decision core. `update()` must be called with the CURRENT
|
|
34
|
+
* activity state; the window only counts continuously idle time and any
|
|
35
|
+
* activity resets it, so a busy host can never cross the threshold.
|
|
36
|
+
*/
|
|
37
|
+
export class IdleExitDecider {
|
|
38
|
+
constructor(idleExitMs, now = Date.now) {
|
|
39
|
+
this.idleExitMs = idleExitMs;
|
|
40
|
+
this.now = now;
|
|
41
|
+
}
|
|
42
|
+
update(activity) {
|
|
43
|
+
// Any attachment or active turn both holds the host open and resets the
|
|
44
|
+
// window, so only CONTINUOUS idle can ever cross the threshold.
|
|
45
|
+
if (activity.connections > 0 || activity.activeTurns > 0) {
|
|
46
|
+
this.idleSince = undefined;
|
|
47
|
+
return "active";
|
|
48
|
+
}
|
|
49
|
+
if (this.idleExitMs === Number.POSITIVE_INFINITY)
|
|
50
|
+
return "idle";
|
|
51
|
+
if (this.idleSince === undefined) {
|
|
52
|
+
this.idleSince = this.now();
|
|
53
|
+
return "idle";
|
|
54
|
+
}
|
|
55
|
+
return this.now() - this.idleSince >= this.idleExitMs ? "exit" : "idle";
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function isRecord(value) {
|
|
59
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
60
|
+
}
|
|
61
|
+
function asOptionalString(value) {
|
|
62
|
+
return typeof value === "string" ? value : typeof value === "number" ? String(value) : undefined;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=host-lifecycle-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-lifecycle-policy.js","sourceRoot":"","sources":["../../../src/modes/rpc/host-lifecycle-policy.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The lifecycle supervisor's policy half: which cold-start mode and idle-exit window apply\n * (`resolveHostPolicy`, environment over settings.json over the defaults), and the pure decision\n * core that turns the current activity snapshot into active / idle / exit (`IdleExitDecider`).\n *\n * Nothing here touches a socket, a process or the filesystem; `host-lifecycle.ts` owns all of that\n * and re-exports these names so every existing importer keeps resolving them at their original home.\n */\nexport type HostColdStart = \"transient\" | \"persistent\";\n\n/** Environment override for the cold-start policy: `transient` or `persistent`. */\nexport const HOST_COLD_START_ENV = \"SENPI_RPC_HOST_COLD_START\";\n/** Environment override for the idle-exit window in milliseconds. */\nexport const HOST_IDLE_EXIT_MS_ENV = \"SENPI_RPC_HOST_IDLE_EXIT_MS\";\n/** Default idle-exit window: 15 minutes of continuous no-connection, no-turn idle. */\nexport const DEFAULT_HOST_IDLE_EXIT_MS = 15 * 60_000;\n/** Soft handoff deadline: rescan and report, never interrupt turns or in-flight requests. */\nexport const HANDOFF_GRACE_MS_ENV = \"SENPI_RPC_HANDOFF_GRACE_MS\";\nexport const DEFAULT_HANDOFF_GRACE_MS = 10 * 60_000;\n\n/** The policy fields ensureHost() records in rpc-host-daemon/settings.json. */\nexport interface HostLifecyclePolicyInput {\n\treadonly coldStart?: HostColdStart;\n\treadonly idleExitMs?: number;\n}\n\nexport interface HostLifecyclePolicy {\n\treadonly coldStart: HostColdStart;\n\treadonly idleExitMs: number;\n}\n\nexport function parseColdStart(value: string | undefined): HostColdStart | undefined {\n\treturn value === \"transient\" || value === \"persistent\" ? value : undefined;\n}\n\nexport function parseIdleExitMs(value: string | undefined): number | undefined {\n\tif (value === undefined || !/^\\d+$/.test(value.trim())) return undefined;\n\tconst parsed = Number(value.trim());\n\treturn Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;\n}\n\n/**\n * Resolves the effective host policy. Precedence: environment overrides beat\n * settings.json, which beats the documented defaults (transient, 15 minutes).\n * Invalid values at either source fall through to the next source.\n */\nexport function resolveHostPolicy(\n\tsettings: unknown,\n\tenv: Readonly<Record<string, string | undefined>>,\n): HostLifecyclePolicy {\n\tconst record = isRecord(settings) ? settings : {};\n\tconst coldStart =\n\t\tparseColdStart(env[HOST_COLD_START_ENV]) ?? parseColdStart(asOptionalString(record.coldStart)) ?? \"transient\";\n\tconst idleExitMs =\n\t\tparseIdleExitMs(env[HOST_IDLE_EXIT_MS_ENV]) ??\n\t\tparseIdleExitMs(asOptionalString(record.idleExitMs)) ??\n\t\tDEFAULT_HOST_IDLE_EXIT_MS;\n\treturn { coldStart, idleExitMs };\n}\n\nexport interface HostActivity {\n\treadonly connections: number;\n\treadonly activeTurns: number;\n}\n\nexport type IdleExitDecision = \"active\" | \"idle\" | \"exit\";\n\n/**\n * Pure idle-window decision core. `update()` must be called with the CURRENT\n * activity state; the window only counts continuously idle time and any\n * activity resets it, so a busy host can never cross the threshold.\n */\nexport class IdleExitDecider {\n\tprivate idleSince: number | undefined;\n\tprivate readonly now: () => number;\n\treadonly idleExitMs: number;\n\n\tconstructor(idleExitMs: number, now: () => number = Date.now) {\n\t\tthis.idleExitMs = idleExitMs;\n\t\tthis.now = now;\n\t}\n\n\tupdate(activity: HostActivity): IdleExitDecision {\n\t\t// Any attachment or active turn both holds the host open and resets the\n\t\t// window, so only CONTINUOUS idle can ever cross the threshold.\n\t\tif (activity.connections > 0 || activity.activeTurns > 0) {\n\t\t\tthis.idleSince = undefined;\n\t\t\treturn \"active\";\n\t\t}\n\t\tif (this.idleExitMs === Number.POSITIVE_INFINITY) return \"idle\";\n\t\tif (this.idleSince === undefined) {\n\t\t\tthis.idleSince = this.now();\n\t\t\treturn \"idle\";\n\t\t}\n\t\treturn this.now() - this.idleSince >= this.idleExitMs ? \"exit\" : \"idle\";\n\t}\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction asOptionalString(value: unknown): string | undefined {\n\treturn typeof value === \"string\" ? value : typeof value === \"number\" ? String(value) : undefined;\n}\n"]}
|
|
@@ -1,25 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
export { classifyChildExit } from "./host-child-exit.ts";
|
|
3
|
+
export { DEFAULT_HANDOFF_GRACE_MS, DEFAULT_HOST_IDLE_EXIT_MS, HANDOFF_GRACE_MS_ENV, HOST_COLD_START_ENV, HOST_IDLE_EXIT_MS_ENV, type HostActivity, type HostColdStart, type HostLifecyclePolicy, type HostLifecyclePolicyInput, IdleExitDecider, type IdleExitDecision, parseColdStart, parseIdleExitMs, resolveHostPolicy, } from "./host-lifecycle-policy.ts";
|
|
3
4
|
import { type SocketFileIdentity } from "./socket-ownership.ts";
|
|
4
|
-
export type HostColdStart = "transient" | "persistent";
|
|
5
|
-
/** Environment override for the cold-start policy: `transient` or `persistent`. */
|
|
6
|
-
export declare const HOST_COLD_START_ENV = "SENPI_RPC_HOST_COLD_START";
|
|
7
|
-
/** Environment override for the idle-exit window in milliseconds. */
|
|
8
|
-
export declare const HOST_IDLE_EXIT_MS_ENV = "SENPI_RPC_HOST_IDLE_EXIT_MS";
|
|
9
|
-
/** Default idle-exit window: 15 minutes of continuous no-connection, no-turn idle. */
|
|
10
|
-
export declare const DEFAULT_HOST_IDLE_EXIT_MS: number;
|
|
11
|
-
/** Soft handoff deadline: rescan and report, never interrupt turns or in-flight requests. */
|
|
12
|
-
export declare const HANDOFF_GRACE_MS_ENV = "SENPI_RPC_HANDOFF_GRACE_MS";
|
|
13
|
-
export declare const DEFAULT_HANDOFF_GRACE_MS: number;
|
|
14
|
-
/** The policy fields ensureHost() records in rpc-host-daemon/settings.json. */
|
|
15
|
-
export interface HostLifecyclePolicyInput {
|
|
16
|
-
readonly coldStart?: HostColdStart;
|
|
17
|
-
readonly idleExitMs?: number;
|
|
18
|
-
}
|
|
19
|
-
export interface HostLifecyclePolicy {
|
|
20
|
-
readonly coldStart: HostColdStart;
|
|
21
|
-
readonly idleExitMs: number;
|
|
22
|
-
}
|
|
23
5
|
/**
|
|
24
6
|
* The internal hop must stay short enough for sun_path (104 bytes on macOS)
|
|
25
7
|
* regardless of where the public socket lives, and private against other local
|
|
@@ -34,31 +16,6 @@ export declare function createInternalSocketPath(baseDir?: string, platform?: No
|
|
|
34
16
|
dir?: string;
|
|
35
17
|
secretPath?: string;
|
|
36
18
|
}>;
|
|
37
|
-
export declare function parseColdStart(value: string | undefined): HostColdStart | undefined;
|
|
38
|
-
export declare function parseIdleExitMs(value: string | undefined): number | undefined;
|
|
39
|
-
/**
|
|
40
|
-
* Resolves the effective host policy. Precedence: environment overrides beat
|
|
41
|
-
* settings.json, which beats the documented defaults (transient, 15 minutes).
|
|
42
|
-
* Invalid values at either source fall through to the next source.
|
|
43
|
-
*/
|
|
44
|
-
export declare function resolveHostPolicy(settings: unknown, env: Readonly<Record<string, string | undefined>>): HostLifecyclePolicy;
|
|
45
|
-
export interface HostActivity {
|
|
46
|
-
readonly connections: number;
|
|
47
|
-
readonly activeTurns: number;
|
|
48
|
-
}
|
|
49
|
-
export type IdleExitDecision = "active" | "idle" | "exit";
|
|
50
|
-
/**
|
|
51
|
-
* Pure idle-window decision core. `update()` must be called with the CURRENT
|
|
52
|
-
* activity state; the window only counts continuously idle time and any
|
|
53
|
-
* activity resets it, so a busy host can never cross the threshold.
|
|
54
|
-
*/
|
|
55
|
-
export declare class IdleExitDecider {
|
|
56
|
-
private idleSince;
|
|
57
|
-
private readonly now;
|
|
58
|
-
readonly idleExitMs: number;
|
|
59
|
-
constructor(idleExitMs: number, now?: () => number);
|
|
60
|
-
update(activity: HostActivity): IdleExitDecision;
|
|
61
|
-
}
|
|
62
19
|
export interface SupervisorLaunch {
|
|
63
20
|
readonly socket: string;
|
|
64
21
|
readonly hostArgs: readonly string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host-lifecycle.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/host-lifecycle.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"host-lifecycle.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/host-lifecycle.ts"],"names":[],"mappings":";AAgEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAIzD,OAAO,EACN,wBAAwB,EACxB,yBAAyB,EACzB,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,eAAe,EACf,KAAK,gBAAgB,EACrB,cAAc,EACd,eAAe,EACf,iBAAiB,GACjB,MAAM,4BAA4B,CAAC;AAgBpC,OAAO,EAGN,KAAK,kBAAkB,EAKvB,MAAM,uBAAuB,CAAC;AAuB/B;;;;;;;;GAQG;AACH,wBAAsB,wBAAwB,CAC7C,OAAO,SAAW,EAClB,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC1C,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAsBhE;AAED,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,kEAAkE;IAClE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,qFAAqF;IACrF,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,kBAAkB,CAAC;CAC9C;AAED,gGAAgG;AAChG,eAAO,MAAM,wBAAwB,mCAAmC,CAAC;AASzE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS,CASjG;AAED,sGAAsG;AACtG,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,gBAAgB,GAAG,SAAS,CA4CzF;AAQD,0FAA0F;AAC1F,wBAAgB,kBAAkB,IAAI,MAAM,CAW3C;AA4BD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACrC,MAAM,EAAE,gBAAgB,EACxB,cAAc,EAAE,MAAM,EACtB,QAAQ,GAAE,OAAqB,GAC7B;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAmBrC;AAWD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CACnC,MAAM,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,EAC3C,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC1C;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAUrD;AAED,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CA4W/E"}
|
|
@@ -50,9 +50,15 @@ import { fileURLToPath } from "node:url";
|
|
|
50
50
|
import { getAgentDir, isBunBinary, isBundledNode } from "../../config.js";
|
|
51
51
|
import { processIsLive, readProcessStartTime } from "../app-server/daemon/process.js";
|
|
52
52
|
import { classifyChildExit, noteChildExit } from "./host-child-exit.js";
|
|
53
|
+
import { ClientOccupancy } from "./host-client-occupancy.js";
|
|
54
|
+
import { DEFAULT_HANDOFF_GRACE_MS, HANDOFF_GRACE_MS_ENV, IdleExitDecider, parseIdleExitMs, resolveHostPolicy, } from "./host-lifecycle-policy.js";
|
|
53
55
|
// The exit verdict moved to ./host-child-exit.ts with the crash recording it now feeds; it stays
|
|
54
56
|
// exported from here so every existing importer keeps resolving it at its original home.
|
|
55
57
|
export { classifyChildExit } from "./host-child-exit.js";
|
|
58
|
+
// The cold-start/idle-exit policy and its decision core live in ./host-lifecycle-policy.ts; they stay
|
|
59
|
+
// exported from here so every existing importer keeps resolving them at their original home.
|
|
60
|
+
export { DEFAULT_HANDOFF_GRACE_MS, DEFAULT_HOST_IDLE_EXIT_MS, HANDOFF_GRACE_MS_ENV, HOST_COLD_START_ENV, HOST_IDLE_EXIT_MS_ENV, IdleExitDecider, parseColdStart, parseIdleExitMs, resolveHostPolicy, } from "./host-lifecycle-policy.js";
|
|
61
|
+
import { hostCrashCleanupPaths } from "./host-cleanup-paths.js";
|
|
56
62
|
import { createHostDaemonPaths, generationPaths, HOST_DAEMON_DIR_ENV } from "./host-daemon-paths.js";
|
|
57
63
|
import { releaseGeneration } from "./host-daemon-registration.js";
|
|
58
64
|
import { watchForSupersession } from "./host-supersession.js";
|
|
@@ -62,15 +68,6 @@ import { activeTurnsForIdleDecision, createObserverLink } from "./observer-link.
|
|
|
62
68
|
import { HOST_INSTANCE_ID_ENV } from "./protocol-identity.js";
|
|
63
69
|
import { MAX_SOCKET_PATH_BYTES, PUBLIC_SOCKET_IDENTITY_FILE, shieldSocketDuringClose, statSocketIdentity, unlinkOwnedSocket, writeSocketIdentityFile, } from "./socket-ownership.js";
|
|
64
70
|
import { authenticateSocket, createSocketSecret, ensureSocketSecret, resolveSocketTransportAddress, SOCKET_SECRET_FILE_ENV, sendSocketHandshake, socketSecretPath, } from "./socket-transport.js";
|
|
65
|
-
/** Environment override for the cold-start policy: `transient` or `persistent`. */
|
|
66
|
-
export const HOST_COLD_START_ENV = "SENPI_RPC_HOST_COLD_START";
|
|
67
|
-
/** Environment override for the idle-exit window in milliseconds. */
|
|
68
|
-
export const HOST_IDLE_EXIT_MS_ENV = "SENPI_RPC_HOST_IDLE_EXIT_MS";
|
|
69
|
-
/** Default idle-exit window: 15 minutes of continuous no-connection, no-turn idle. */
|
|
70
|
-
export const DEFAULT_HOST_IDLE_EXIT_MS = 15 * 60_000;
|
|
71
|
-
/** Soft handoff deadline: rescan and report, never interrupt turns or in-flight requests. */
|
|
72
|
-
export const HANDOFF_GRACE_MS_ENV = "SENPI_RPC_HANDOFF_GRACE_MS";
|
|
73
|
-
export const DEFAULT_HANDOFF_GRACE_MS = 10 * 60_000;
|
|
74
71
|
const CHILD_STOP_TIMEOUT_MS = 5_000;
|
|
75
72
|
/** Win32 named-pipe shutdown can leave supervisor handles live after close starts. */
|
|
76
73
|
const WINDOWS_SUPERVISOR_SHUTDOWN_HARD_EXIT_MS = 2_000;
|
|
@@ -109,54 +106,6 @@ export async function createInternalSocketPath(baseDir = tmpdir(), platform = pr
|
|
|
109
106
|
}), { mode: 0o600 });
|
|
110
107
|
return { socket: join(dir, "host.sock"), dir, secretPath: join(dir, ".secret") };
|
|
111
108
|
}
|
|
112
|
-
export function parseColdStart(value) {
|
|
113
|
-
return value === "transient" || value === "persistent" ? value : undefined;
|
|
114
|
-
}
|
|
115
|
-
export function parseIdleExitMs(value) {
|
|
116
|
-
if (value === undefined || !/^\d+$/.test(value.trim()))
|
|
117
|
-
return undefined;
|
|
118
|
-
const parsed = Number(value.trim());
|
|
119
|
-
return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Resolves the effective host policy. Precedence: environment overrides beat
|
|
123
|
-
* settings.json, which beats the documented defaults (transient, 15 minutes).
|
|
124
|
-
* Invalid values at either source fall through to the next source.
|
|
125
|
-
*/
|
|
126
|
-
export function resolveHostPolicy(settings, env) {
|
|
127
|
-
const record = isRecord(settings) ? settings : {};
|
|
128
|
-
const coldStart = parseColdStart(env[HOST_COLD_START_ENV]) ?? parseColdStart(asOptionalString(record.coldStart)) ?? "transient";
|
|
129
|
-
const idleExitMs = parseIdleExitMs(env[HOST_IDLE_EXIT_MS_ENV]) ??
|
|
130
|
-
parseIdleExitMs(asOptionalString(record.idleExitMs)) ??
|
|
131
|
-
DEFAULT_HOST_IDLE_EXIT_MS;
|
|
132
|
-
return { coldStart, idleExitMs };
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Pure idle-window decision core. `update()` must be called with the CURRENT
|
|
136
|
-
* activity state; the window only counts continuously idle time and any
|
|
137
|
-
* activity resets it, so a busy host can never cross the threshold.
|
|
138
|
-
*/
|
|
139
|
-
export class IdleExitDecider {
|
|
140
|
-
constructor(idleExitMs, now = Date.now) {
|
|
141
|
-
this.idleExitMs = idleExitMs;
|
|
142
|
-
this.now = now;
|
|
143
|
-
}
|
|
144
|
-
update(activity) {
|
|
145
|
-
// Any attachment or active turn both holds the host open and resets the
|
|
146
|
-
// window, so only CONTINUOUS idle can ever cross the threshold.
|
|
147
|
-
if (activity.connections > 0 || activity.activeTurns > 0) {
|
|
148
|
-
this.idleSince = undefined;
|
|
149
|
-
return "active";
|
|
150
|
-
}
|
|
151
|
-
if (this.idleExitMs === Number.POSITIVE_INFINITY)
|
|
152
|
-
return "idle";
|
|
153
|
-
if (this.idleSince === undefined) {
|
|
154
|
-
this.idleSince = this.now();
|
|
155
|
-
return "idle";
|
|
156
|
-
}
|
|
157
|
-
return this.now() - this.idleSince >= this.idleExitMs ? "exit" : "idle";
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
109
|
/** Hidden internal launch route: wire-invisible, never advertised by the public CLI surface. */
|
|
161
110
|
export const INTERNAL_SUPERVISOR_FLAG = "--internal-rpc-host-supervisor";
|
|
162
111
|
/**
|
|
@@ -362,7 +311,7 @@ export async function runHostSupervisor(launch) {
|
|
|
362
311
|
const internalSocket = internal.socket;
|
|
363
312
|
const internalSecretPath = internal.secretPath ?? socketSecretPath(internalSocket);
|
|
364
313
|
const internalSecret = process.platform === "win32" ? await createSocketSecret(internalSecretPath) : undefined;
|
|
365
|
-
const
|
|
314
|
+
const clients = new ClientOccupancy(() => decider.update(currentActivity()));
|
|
366
315
|
const busySessions = new Map();
|
|
367
316
|
// Declared before anything that can reach `currentActivity()`. A client accepted during startup
|
|
368
317
|
// asks for the activity snapshot, and a `const` read before its initializer runs is a
|
|
@@ -413,18 +362,14 @@ export async function runHostSupervisor(launch) {
|
|
|
413
362
|
[HOST_WATCH_PPID_ENV]: String(process.pid),
|
|
414
363
|
...(internal.dir ? { [HOST_SCRATCH_DIR_ENV]: internal.dir } : {}),
|
|
415
364
|
...(internalSecret ? { [SOCKET_SECRET_FILE_ENV]: internalSecretPath } : {}),
|
|
416
|
-
[HOST_CLEANUP_PATHS_ENV]:
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
// Windows named pipes have no filesystem entry to own, so they stay
|
|
425
|
-
// listed for the crash-path cleanup.
|
|
426
|
-
...(process.platform === "win32" ? [publicSocket] : []),
|
|
427
|
-
].join("\n"),
|
|
365
|
+
[HOST_CLEANUP_PATHS_ENV]: hostCrashCleanupPaths({
|
|
366
|
+
pointerFile: paths.pointerFile,
|
|
367
|
+
generationPidFile: generation.pidFile,
|
|
368
|
+
settingsFile: paths.settingsFile,
|
|
369
|
+
publicSocket,
|
|
370
|
+
successor: Boolean(successor),
|
|
371
|
+
platform: process.platform,
|
|
372
|
+
}).join("\n"),
|
|
428
373
|
...(process.platform === "win32" ? {} : { [HOST_PUBLIC_SOCKET_ENV]: publicSocket }),
|
|
429
374
|
},
|
|
430
375
|
// Slot 3 is the lifetime pipe: "pipe" gives the child a read end it can
|
|
@@ -462,12 +407,12 @@ export async function runHostSupervisor(launch) {
|
|
|
462
407
|
const internal = createConnection(resolveSocketTransportAddress(internalSocket, process.platform, internalSecret));
|
|
463
408
|
if (internalSecret)
|
|
464
409
|
sendSocketHandshake(internal, internalSecret);
|
|
465
|
-
|
|
466
|
-
//
|
|
467
|
-
//
|
|
468
|
-
|
|
410
|
+
// A readiness exchange can begin and end between ticks: the client is recorded the
|
|
411
|
+
// moment its first request line arrives, before a later tick can reuse the preceding
|
|
412
|
+
// idle window. An observing read (`status`) is never recorded (host-client-occupancy.ts).
|
|
413
|
+
clients.admit(client);
|
|
469
414
|
const detach = () => {
|
|
470
|
-
|
|
415
|
+
clients.release(client);
|
|
471
416
|
decider.update(currentActivity());
|
|
472
417
|
internal.destroy();
|
|
473
418
|
client.destroy();
|
|
@@ -496,12 +441,12 @@ export async function runHostSupervisor(launch) {
|
|
|
496
441
|
const decider = new IdleExitDecider(policy.coldStart === "persistent" ? Number.POSITIVE_INFINITY : policy.idleExitMs);
|
|
497
442
|
const tickIntervalMs = Math.max(20, Math.min(1_000, policy.idleExitMs / 4));
|
|
498
443
|
const ticker = setInterval(() => {
|
|
499
|
-
if (!draining && decider.update(currentActivity()) === "exit")
|
|
444
|
+
if (!draining && decider.update(currentActivity()) === "exit" && clients.unclassifiedCount === 0)
|
|
500
445
|
void shutdown("idle", 0);
|
|
501
446
|
}, tickIntervalMs);
|
|
502
447
|
function currentActivity() {
|
|
503
448
|
return {
|
|
504
|
-
connections:
|
|
449
|
+
connections: clients.attachedCount,
|
|
505
450
|
activeTurns: activeTurnsForIdleDecision({
|
|
506
451
|
healthy: observerLink.healthy(),
|
|
507
452
|
unhealthySince: observerLink.unhealthySince(),
|
|
@@ -561,8 +506,7 @@ export async function runHostSupervisor(launch) {
|
|
|
561
506
|
: undefined;
|
|
562
507
|
try {
|
|
563
508
|
writeStderrLine(`senpi rpc host supervisor: ${reason} shutdown`);
|
|
564
|
-
|
|
565
|
-
client.destroy();
|
|
509
|
+
clients.destroyAll();
|
|
566
510
|
// libuv unlinks the bound NAME when the listening handle closes - which
|
|
567
511
|
// would delete a newer host's entry renamed over this path. Shield the
|
|
568
512
|
// current entry for the close, then let the ownership check decide. A drained
|
|
@@ -913,12 +857,6 @@ function errorMessage(cause) {
|
|
|
913
857
|
function isNodeErrorCode(cause, code) {
|
|
914
858
|
return cause instanceof Error && "code" in cause && cause.code === code;
|
|
915
859
|
}
|
|
916
|
-
function isRecord(value) {
|
|
917
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
918
|
-
}
|
|
919
|
-
function asOptionalString(value) {
|
|
920
|
-
return typeof value === "string" ? value : typeof value === "number" ? String(value) : undefined;
|
|
921
|
-
}
|
|
922
860
|
function isEntryScript() {
|
|
923
861
|
const entry = process.argv[1];
|
|
924
862
|
if (!entry)
|