@code-yeongyu/senpi 2026.8.30 → 2026.9.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 +174 -2
- package/README.md +3 -0
- package/dist/core/agent-session.d.ts +28 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +161 -14
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/compaction-execution.d.ts +14 -0
- package/dist/core/compaction/compaction-execution.d.ts.map +1 -0
- package/dist/core/compaction/compaction-execution.js +121 -0
- package/dist/core/compaction/compaction-execution.js.map +1 -0
- package/dist/core/compaction/compaction-settings.d.ts +17 -0
- package/dist/core/compaction/compaction-settings.d.ts.map +1 -0
- package/dist/core/compaction/compaction-settings.js +17 -0
- package/dist/core/compaction/compaction-settings.js.map +1 -0
- package/dist/core/compaction/compaction.d.ts +13 -26
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +7 -136
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/ideal-compaction-settings.d.ts +9 -0
- package/dist/core/compaction/ideal-compaction-settings.d.ts.map +1 -0
- package/dist/core/compaction/ideal-compaction-settings.js +7 -0
- package/dist/core/compaction/ideal-compaction-settings.js.map +1 -0
- package/dist/core/compaction-settings-access.d.ts +19 -0
- package/dist/core/compaction-settings-access.d.ts.map +1 -0
- package/dist/core/compaction-settings-access.js +10 -0
- package/dist/core/compaction-settings-access.js.map +1 -0
- package/dist/core/compaction-settings-resolver.d.ts +22 -0
- package/dist/core/compaction-settings-resolver.d.ts.map +1 -0
- package/dist/core/compaction-settings-resolver.js +46 -0
- package/dist/core/compaction-settings-resolver.js.map +1 -0
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry.d.ts +9 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry.d.ts.map +1 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry.js +10 -3
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/context-pipeline.d.ts +24 -0
- package/dist/core/extensions/builtin/compaction/context-pipeline.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/context-pipeline.js +43 -0
- package/dist/core/extensions/builtin/compaction/context-pipeline.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.d.ts +1 -1
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.js +8 -2
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/emergency-prune.d.ts +17 -0
- package/dist/core/extensions/builtin/compaction/emergency-prune.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/emergency-prune.js +64 -0
- package/dist/core/extensions/builtin/compaction/emergency-prune.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/extension-wiring.d.ts +27 -0
- package/dist/core/extensions/builtin/compaction/extension-wiring.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/extension-wiring.js +84 -0
- package/dist/core/extensions/builtin/compaction/extension-wiring.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/idle-retry.d.ts +1 -1
- package/dist/core/extensions/builtin/compaction/idle-retry.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/idle-retry.js +1 -1
- package/dist/core/extensions/builtin/compaction/idle-retry.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/idle.d.ts +1 -0
- package/dist/core/extensions/builtin/compaction/idle.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/idle.js +13 -2
- package/dist/core/extensions/builtin/compaction/idle.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/index.d.ts +1 -1
- package/dist/core/extensions/builtin/compaction/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/index.js +152 -154
- package/dist/core/extensions/builtin/compaction/index.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/log.d.ts +1 -1
- package/dist/core/extensions/builtin/compaction/log.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/log.js +2 -0
- package/dist/core/extensions/builtin/compaction/log.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/model-selection.d.ts +14 -0
- package/dist/core/extensions/builtin/compaction/model-selection.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/model-selection.js +37 -0
- package/dist/core/extensions/builtin/compaction/model-selection.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/model-usability-budget.d.ts +30 -0
- package/dist/core/extensions/builtin/compaction/model-usability-budget.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/model-usability-budget.js +74 -0
- package/dist/core/extensions/builtin/compaction/model-usability-budget.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/openai-remote-dependencies.d.ts +9 -0
- package/dist/core/extensions/builtin/compaction/openai-remote-dependencies.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/openai-remote-dependencies.js +2 -0
- package/dist/core/extensions/builtin/compaction/openai-remote-dependencies.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/openai-remote.d.ts +3 -6
- package/dist/core/extensions/builtin/compaction/openai-remote.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/openai-remote.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/orchestration.d.ts +46 -0
- package/dist/core/extensions/builtin/compaction/orchestration.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/orchestration.js +103 -0
- package/dist/core/extensions/builtin/compaction/orchestration.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/policy.d.ts +12 -2
- package/dist/core/extensions/builtin/compaction/policy.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/policy.js +52 -26
- package/dist/core/extensions/builtin/compaction/policy.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/speculation-lead.d.ts +8 -0
- package/dist/core/extensions/builtin/compaction/speculation-lead.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/speculation-lead.js +17 -0
- package/dist/core/extensions/builtin/compaction/speculation-lead.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/speculative-job.d.ts +22 -0
- package/dist/core/extensions/builtin/compaction/speculative-job.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/speculative-job.js +16 -0
- package/dist/core/extensions/builtin/compaction/speculative-job.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/speculative-summary.d.ts +23 -0
- package/dist/core/extensions/builtin/compaction/speculative-summary.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/speculative-summary.js +132 -0
- package/dist/core/extensions/builtin/compaction/speculative-summary.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/speculative.d.ts +8 -13
- package/dist/core/extensions/builtin/compaction/speculative.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/speculative.js +21 -197
- package/dist/core/extensions/builtin/compaction/speculative.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/token-budget-reminder.d.ts +24 -0
- package/dist/core/extensions/builtin/compaction/token-budget-reminder.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/token-budget-reminder.js +25 -0
- package/dist/core/extensions/builtin/compaction/token-budget-reminder.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/tool-admission.d.ts +27 -0
- package/dist/core/extensions/builtin/compaction/tool-admission.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/tool-admission.js +56 -0
- package/dist/core/extensions/builtin/compaction/tool-admission.js.map +1 -0
- package/dist/core/extensions/builtin/hooks/trust-state-json.d.ts +5 -0
- package/dist/core/extensions/builtin/hooks/trust-state-json.d.ts.map +1 -0
- package/dist/core/extensions/builtin/hooks/trust-state-json.js +76 -0
- package/dist/core/extensions/builtin/hooks/trust-state-json.js.map +1 -0
- package/dist/core/extensions/builtin/hooks/trust-storage.d.ts +7 -1
- package/dist/core/extensions/builtin/hooks/trust-storage.d.ts.map +1 -1
- package/dist/core/extensions/builtin/hooks/trust-storage.js +60 -8
- package/dist/core/extensions/builtin/hooks/trust-storage.js.map +1 -1
- package/dist/core/extensions/builtin/hooks/trust.d.ts +1 -2
- package/dist/core/extensions/builtin/hooks/trust.d.ts.map +1 -1
- package/dist/core/extensions/builtin/hooks/trust.js +1 -72
- package/dist/core/extensions/builtin/hooks/trust.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/claude-fable-5-1.d.ts +3 -0
- package/dist/core/extensions/builtin/prompt-preset/claude-fable-5-1.d.ts.map +1 -0
- package/dist/core/extensions/builtin/prompt-preset/claude-fable-5-1.js +108 -0
- package/dist/core/extensions/builtin/prompt-preset/claude-fable-5-1.js.map +1 -0
- package/dist/core/extensions/builtin/prompt-preset/presets.d.ts.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/presets.js +11 -0
- package/dist/core/extensions/builtin/prompt-preset/presets.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/settings.d.ts +1 -1
- package/dist/core/extensions/builtin/prompt-preset/settings.d.ts.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/settings.js +1 -0
- package/dist/core/extensions/builtin/prompt-preset/settings.js.map +1 -1
- package/dist/core/extensions/builtin/recommended-models/index.d.ts +1 -1
- package/dist/core/extensions/builtin/recommended-models/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/recommended-models/index.js +1 -1
- package/dist/core/extensions/builtin/recommended-models/index.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/runtime-session.d.ts +11 -0
- package/dist/core/extensions/builtin/terminal/runtime-session.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/runtime-session.js +18 -2
- package/dist/core/extensions/builtin/terminal/runtime-session.js.map +1 -1
- package/dist/core/extensions/builtin/ttsr/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/ttsr/index.js +4 -0
- package/dist/core/extensions/builtin/ttsr/index.js.map +1 -1
- package/dist/core/extensions/builtin/ttsr/manager.d.ts +2 -0
- package/dist/core/extensions/builtin/ttsr/manager.d.ts.map +1 -1
- package/dist/core/extensions/builtin/ttsr/manager.js +28 -1
- package/dist/core/extensions/builtin/ttsr/manager.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +5 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +7 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/retry-fallback/controller.d.ts +14 -0
- package/dist/core/retry-fallback/controller.d.ts.map +1 -1
- package/dist/core/retry-fallback/controller.js +33 -3
- package/dist/core/retry-fallback/controller.js.map +1 -1
- package/dist/core/retry-fallback/log.js +1 -1
- package/dist/core/retry-fallback/log.js.map +1 -1
- package/dist/core/retry-fallback/settings.d.ts.map +1 -1
- package/dist/core/retry-fallback/settings.js +1 -0
- package/dist/core/retry-fallback/settings.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +5 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-activity.d.ts +47 -0
- package/dist/core/session-activity.d.ts.map +1 -0
- package/dist/core/session-activity.js +58 -0
- package/dist/core/session-activity.js.map +1 -0
- package/dist/core/session-manager.d.ts +8 -12
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +118 -7
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-resident-store.d.ts +8 -1
- package/dist/core/session-resident-store.d.ts.map +1 -1
- package/dist/core/session-resident-store.js +12 -5
- package/dist/core/session-resident-store.js.map +1 -1
- package/dist/core/settings-manager.d.ts +8 -85
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +9 -17
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/settings-public-types.d.ts +11 -0
- package/dist/core/settings-public-types.d.ts.map +1 -0
- package/dist/core/settings-public-types.js +2 -0
- package/dist/core/settings-public-types.js.map +1 -0
- package/dist/core/settings-shapes.d.ts +36 -0
- package/dist/core/settings-shapes.d.ts.map +1 -0
- package/dist/core/settings-shapes.js +2 -0
- package/dist/core/settings-shapes.js.map +1 -0
- package/dist/core/shared-host-policy.d.ts +6 -0
- package/dist/core/shared-host-policy.d.ts.map +1 -0
- package/dist/core/shared-host-policy.js +7 -0
- package/dist/core/shared-host-policy.js.map +1 -0
- package/dist/core/terminal-settings.d.ts +22 -0
- package/dist/core/terminal-settings.d.ts.map +1 -0
- package/dist/core/terminal-settings.js +2 -0
- package/dist/core/terminal-settings.js.map +1 -0
- 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/main.d.ts +4 -4
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +27 -11
- package/dist/main.js.map +1 -1
- package/dist/modes/app-server/daemon/process.d.ts +13 -2
- package/dist/modes/app-server/daemon/process.d.ts.map +1 -1
- package/dist/modes/app-server/daemon/process.js +58 -12
- package/dist/modes/app-server/daemon/process.js.map +1 -1
- package/dist/modes/app-server/daemon.js +65 -7
- package/dist/modes/app-server/daemon.js.map +1 -1
- package/dist/modes/index.d.ts +1 -1
- package/dist/modes/index.d.ts.map +1 -1
- package/dist/modes/index.js +1 -1
- package/dist/modes/index.js.map +1 -1
- package/dist/modes/interactive/interactive-host-runtime.d.ts +84 -1
- package/dist/modes/interactive/interactive-host-runtime.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-host-runtime.js +435 -112
- package/dist/modes/interactive/interactive-host-runtime.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +11 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +59 -6
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/tips/catalog/ethos-tips.js +1 -1
- package/dist/modes/interactive/tips/catalog/ethos-tips.js.map +1 -1
- package/dist/modes/rpc/connection-handler.d.ts +12 -5
- package/dist/modes/rpc/connection-handler.d.ts.map +1 -1
- package/dist/modes/rpc/connection-handler.js +180 -25
- package/dist/modes/rpc/connection-handler.js.map +1 -1
- package/dist/modes/rpc/custom-capability.d.ts +2 -0
- package/dist/modes/rpc/custom-capability.d.ts.map +1 -1
- package/dist/modes/rpc/custom-capability.js +2 -0
- package/dist/modes/rpc/custom-capability.js.map +1 -1
- package/dist/modes/rpc/host-ensure.d.ts +17 -0
- package/dist/modes/rpc/host-ensure.d.ts.map +1 -1
- package/dist/modes/rpc/host-ensure.js +150 -23
- package/dist/modes/rpc/host-ensure.js.map +1 -1
- package/dist/modes/rpc/host-lifecycle.d.ts +54 -0
- package/dist/modes/rpc/host-lifecycle.d.ts.map +1 -1
- package/dist/modes/rpc/host-lifecycle.js +259 -69
- package/dist/modes/rpc/host-lifecycle.js.map +1 -1
- package/dist/modes/rpc/host-watchdog.d.ts +2 -2
- package/dist/modes/rpc/host-watchdog.d.ts.map +1 -1
- package/dist/modes/rpc/host-watchdog.js +89 -21
- package/dist/modes/rpc/host-watchdog.js.map +1 -1
- package/dist/modes/rpc/multi-session-host.d.ts +38 -0
- package/dist/modes/rpc/multi-session-host.d.ts.map +1 -1
- package/dist/modes/rpc/multi-session-host.js +149 -61
- package/dist/modes/rpc/multi-session-host.js.map +1 -1
- package/dist/modes/rpc/ownership-safe-lock.d.ts +14 -0
- package/dist/modes/rpc/ownership-safe-lock.d.ts.map +1 -0
- package/dist/modes/rpc/ownership-safe-lock.js +87 -0
- package/dist/modes/rpc/ownership-safe-lock.js.map +1 -0
- package/dist/modes/rpc/rpc-client.d.ts +13 -2
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +46 -12
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +21 -3
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js +1 -0
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/modes/rpc/session-binding.d.ts +2 -1
- package/dist/modes/rpc/session-binding.d.ts.map +1 -1
- package/dist/modes/rpc/session-binding.js +1 -0
- package/dist/modes/rpc/session-binding.js.map +1 -1
- package/dist/modes/rpc/session-command-router.d.ts +54 -1
- package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
- package/dist/modes/rpc/session-command-router.js +180 -3
- package/dist/modes/rpc/session-command-router.js.map +1 -1
- package/dist/modes/rpc/session-event-writer.d.ts +18 -0
- package/dist/modes/rpc/session-event-writer.d.ts.map +1 -1
- package/dist/modes/rpc/session-event-writer.js +88 -8
- package/dist/modes/rpc/session-event-writer.js.map +1 -1
- package/dist/modes/rpc/session-registry.d.ts +11 -1
- package/dist/modes/rpc/session-registry.d.ts.map +1 -1
- package/dist/modes/rpc/session-registry.js +25 -0
- package/dist/modes/rpc/session-registry.js.map +1 -1
- package/dist/modes/rpc/socket-transport.d.ts +13 -0
- package/dist/modes/rpc/socket-transport.d.ts.map +1 -0
- package/dist/modes/rpc/socket-transport.js +92 -0
- package/dist/modes/rpc/socket-transport.js.map +1 -0
- package/dist/modes/rpc/widget-line-renderer.d.ts +17 -0
- package/dist/modes/rpc/widget-line-renderer.d.ts.map +1 -0
- package/dist/modes/rpc/widget-line-renderer.js +73 -0
- package/dist/modes/rpc/widget-line-renderer.js.map +1 -0
- package/dist/utils/fs-watch.d.ts.map +1 -1
- package/dist/utils/fs-watch.js +11 -2
- package/dist/utils/fs-watch.js.map +1 -1
- package/docs/app-server.md +2 -2
- package/docs/containerization.md +2 -2
- package/docs/development.md +7 -7
- package/docs/extensions.md +5 -5
- package/docs/grok-neo.md +1 -1
- package/docs/index.md +1 -1
- package/docs/packages.md +2 -2
- package/docs/quickstart.md +4 -4
- package/docs/release-guide.md +21 -21
- package/docs/rpc.md +83 -6
- package/docs/sdk.md +1 -1
- package/docs/settings.md +4 -4
- package/docs/skills.md +2 -2
- package/docs/terminal-tools.md +1 -1
- package/docs/termux.md +1 -1
- package/docs/tui.md +1 -1
- package/examples/AGENTS.md +1 -1
- package/examples/sdk/README.md +1 -1
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +52 -0
- package/node_modules/@code-yeongyu/senpi-codemode/README.md +2 -2
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
- package/node_modules/@code-yeongyu/senpi-codemode/src/extension/skill-contribution.ts +71 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/index.ts +3 -1
- package/node_modules/@code-yeongyu/senpi-codemode/src/skill/bun-1-4/SKILL.md +44 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/skill/bun-1-4/references/breaking-changes.md +75 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/skill/bun-1-4/references/build.md +114 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/skill/bun-1-4/references/dev-tooling.md +34 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/skill/bun-1-4/references/http-networking.md +113 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/skill/bun-1-4/references/install.md +93 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/skill/bun-1-4/references/node-compat-platforms.md +36 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/skill/bun-1-4/references/performance.md +33 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/skill/bun-1-4/references/runtime-apis.md +156 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/skill/bun-1-4/references/security.md +52 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/skill/bun-1-4/references/test.md +103 -0
- package/node_modules/@earendil-works/pi-agent-core/README.md +3 -0
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/README.md +6 -3
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js +24 -7
- package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.d.ts +7 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.js +316 -2
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-conversation-rotation.d.ts +4 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-conversation-rotation.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-conversation-rotation.js +23 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-conversation-rotation.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.d.ts +24 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js +20 -2
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/amazon-bedrock.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/anthropic.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/fireworks.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/google.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/groq.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/nvidia.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/opengateway.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/providers/data/vercel-ai-gateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-pty/dist/screen-operations.d.ts +42 -0
- package/node_modules/@earendil-works/pi-pty/dist/screen-operations.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-pty/dist/screen-operations.js +34 -0
- package/node_modules/@earendil-works/pi-pty/dist/screen-operations.js.map +1 -0
- package/node_modules/@earendil-works/pi-pty/dist/screen-text.d.ts +8 -0
- package/node_modules/@earendil-works/pi-pty/dist/screen-text.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-pty/dist/screen-text.js +51 -0
- package/node_modules/@earendil-works/pi-pty/dist/screen-text.js.map +1 -0
- package/node_modules/@earendil-works/pi-pty/dist/screen.d.ts +45 -0
- package/node_modules/@earendil-works/pi-pty/dist/screen.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-pty/dist/screen.js +178 -55
- package/node_modules/@earendil-works/pi-pty/dist/screen.js.map +1 -1
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-telemetry/README.md +6 -3
- package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/README.md +5 -4
- package/node_modules/@earendil-works/pi-tui/native/darwin/README.md +2 -2
- package/node_modules/@earendil-works/pi-tui/native/win32/README.md +2 -2
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +7 -7
|
@@ -40,15 +40,17 @@
|
|
|
40
40
|
import { spawn } from "node:child_process";
|
|
41
41
|
import { randomUUID } from "node:crypto";
|
|
42
42
|
import { realpathSync, writeSync } from "node:fs";
|
|
43
|
-
import { access, chmod, mkdir, readFile, rm, unlink } from "node:fs/promises";
|
|
43
|
+
import { access, chmod, mkdir, readFile, rm, unlink, writeFile } from "node:fs/promises";
|
|
44
44
|
import { createConnection, createServer } from "node:net";
|
|
45
45
|
import { tmpdir } from "node:os";
|
|
46
|
-
import { dirname, join, resolve } from "node:path";
|
|
46
|
+
import { dirname, extname, join, resolve } from "node:path";
|
|
47
47
|
import { fileURLToPath } from "node:url";
|
|
48
|
-
import { getAgentDir } from "../../config.js";
|
|
48
|
+
import { getAgentDir, isBunBinary } from "../../config.js";
|
|
49
|
+
import { readProcessStartTime } from "../app-server/daemon/process.js";
|
|
49
50
|
import { createHostDaemonPaths } from "./host-ensure.js";
|
|
50
51
|
import { HOST_CLEANUP_PATHS_ENV, HOST_SCRATCH_DIR_ENV, HOST_WATCH_FD_ENV, HOST_WATCH_PPID_ENV, } from "./host-watchdog.js";
|
|
51
52
|
import { attachJsonlLineReader, MAX_RPC_LINE_CHARACTERS } from "./jsonl.js";
|
|
53
|
+
import { authenticateSocket, createSocketSecret, readSocketSecret, resolveSocketTransportAddress, SOCKET_SECRET_FILE_ENV, sendSocketHandshake, socketSecretPath, } from "./socket-transport.js";
|
|
52
54
|
/** Environment override for the cold-start policy: `transient` or `persistent`. */
|
|
53
55
|
export const HOST_COLD_START_ENV = "SENPI_RPC_HOST_COLD_START";
|
|
54
56
|
/** Environment override for the idle-exit window in milliseconds. */
|
|
@@ -56,6 +58,8 @@ export const HOST_IDLE_EXIT_MS_ENV = "SENPI_RPC_HOST_IDLE_EXIT_MS";
|
|
|
56
58
|
/** Default idle-exit window: 15 minutes of continuous no-connection, no-turn idle. */
|
|
57
59
|
export const DEFAULT_HOST_IDLE_EXIT_MS = 15 * 60_000;
|
|
58
60
|
const CHILD_STOP_TIMEOUT_MS = 5_000;
|
|
61
|
+
/** Win32 named-pipe shutdown can leave supervisor handles live after close starts. */
|
|
62
|
+
const WINDOWS_SUPERVISOR_SHUTDOWN_HARD_EXIT_MS = 2_000;
|
|
59
63
|
/**
|
|
60
64
|
* Child stdio slot carrying the supervisor-lifetime pipe. The supervisor holds
|
|
61
65
|
* the write end open and never writes; the kernel closes it when the supervisor
|
|
@@ -68,10 +72,24 @@ const CHILD_WATCH_FD = 3;
|
|
|
68
72
|
* regardless of where the public socket lives, and private against other local
|
|
69
73
|
* users, so it gets its own 0700 directory under the OS temp directory.
|
|
70
74
|
*/
|
|
71
|
-
async function createInternalSocketPath() {
|
|
75
|
+
async function createInternalSocketPath(baseDir = tmpdir()) {
|
|
76
|
+
if (process.platform === "win32") {
|
|
77
|
+
const dir = join(baseDir, `internal-${randomUUID()}`);
|
|
78
|
+
await mkdir(dir, { recursive: false, mode: 0o700 });
|
|
79
|
+
return {
|
|
80
|
+
socket: `\\\\.\\pipe\\senpi-rpc-internal-${randomUUID()}`,
|
|
81
|
+
dir,
|
|
82
|
+
secretPath: join(dir, "secret"),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
72
85
|
const dir = join(tmpdir(), `senpi-rpc-host-internal-${randomUUID().slice(0, 8)}`);
|
|
73
86
|
await mkdir(dir, { recursive: false, mode: 0o700 });
|
|
74
|
-
|
|
87
|
+
await writeFile(join(dir, ".owner"), JSON.stringify({
|
|
88
|
+
pid: process.pid,
|
|
89
|
+
processStartTime: await readProcessStartTime(process.pid),
|
|
90
|
+
createdAt: Date.now(),
|
|
91
|
+
}), { mode: 0o600 });
|
|
92
|
+
return { socket: join(dir, "host.sock"), dir, secretPath: join(dir, ".secret") };
|
|
75
93
|
}
|
|
76
94
|
export function parseColdStart(value) {
|
|
77
95
|
return value === "transient" || value === "persistent" ? value : undefined;
|
|
@@ -95,6 +113,17 @@ export function resolveHostPolicy(settings, env) {
|
|
|
95
113
|
DEFAULT_HOST_IDLE_EXIT_MS;
|
|
96
114
|
return { coldStart, idleExitMs };
|
|
97
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* How the supervisor reads its child's exit. The RPC host exits 0 only through
|
|
118
|
+
* its own clean shutdown path - including its idle/empty-host policy - so that
|
|
119
|
+
* is an intentional stop, not a crash: the supervisor mirrors its own idle exit
|
|
120
|
+
* instead of reporting failure. Any non-zero code or signal stays a crash.
|
|
121
|
+
*/
|
|
122
|
+
export function classifyChildExit(code, signal) {
|
|
123
|
+
if (code === 0 && signal === null)
|
|
124
|
+
return { reason: "rpc host exited on its own idle policy", exitCode: 0 };
|
|
125
|
+
return { reason: `rpc host process exited unexpectedly (${code ?? signal})`, exitCode: 1 };
|
|
126
|
+
}
|
|
98
127
|
/**
|
|
99
128
|
* Pure idle-window decision core. `update()` must be called with the CURRENT
|
|
100
129
|
* activity state; the window only counts continuously idle time and any
|
|
@@ -121,6 +150,40 @@ export class IdleExitDecider {
|
|
|
121
150
|
return this.now() - this.idleSince >= this.idleExitMs ? "exit" : "idle";
|
|
122
151
|
}
|
|
123
152
|
}
|
|
153
|
+
/** Hidden internal launch route: wire-invisible, never advertised by the public CLI surface. */
|
|
154
|
+
export const INTERNAL_SUPERVISOR_FLAG = "--internal-rpc-host-supervisor";
|
|
155
|
+
/**
|
|
156
|
+
* Engine-global flags a rebranded wrapper may legitimately prepend when it
|
|
157
|
+
* re-dispatches this binary. `packages/omo-native` injects `--extension <dir>`
|
|
158
|
+
* for every non-early command, which pushed the sentinel off argv[0].
|
|
159
|
+
*/
|
|
160
|
+
const INJECTABLE_PREFIX_FLAGS = new Set(["--extension"]);
|
|
161
|
+
/**
|
|
162
|
+
* Returns the internal supervisor payload when argv selects that route.
|
|
163
|
+
*
|
|
164
|
+
* The route dispatches when the sentinel is argv[0] OR is preceded only by
|
|
165
|
+
* known injectable prefix flags and their values - the one perturbation
|
|
166
|
+
* wrappers legitimately perform. Everything else disqualifies it: a positional
|
|
167
|
+
* operand, `--`, or an unknown flag before the sentinel all return undefined,
|
|
168
|
+
* so a user-supplied value that happens to equal the sentinel can never reach
|
|
169
|
+
* the supervisor.
|
|
170
|
+
*
|
|
171
|
+
* The skipped prefix is deliberately NOT forwarded to the host: a wrapper
|
|
172
|
+
* re-injects its own prefix on every re-entry, so the host child receives it
|
|
173
|
+
* from the wrapper rather than twice from here.
|
|
174
|
+
*/
|
|
175
|
+
export function findInternalSupervisorArgs(argv) {
|
|
176
|
+
for (let index = 0; index < argv.length; index++) {
|
|
177
|
+
const arg = argv[index];
|
|
178
|
+
if (arg === INTERNAL_SUPERVISOR_FLAG)
|
|
179
|
+
return argv.slice(index + 1);
|
|
180
|
+
// A prefix flag only counts when its value is actually present.
|
|
181
|
+
if (!INJECTABLE_PREFIX_FLAGS.has(arg) || index + 1 >= argv.length)
|
|
182
|
+
return undefined;
|
|
183
|
+
index++;
|
|
184
|
+
}
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
124
187
|
/** `--socket <path>` selects the public socket; every other argument is forwarded to the host CLI. */
|
|
125
188
|
export function parseSupervisorArgs(argv) {
|
|
126
189
|
const hostArgs = [];
|
|
@@ -163,67 +226,136 @@ export function resolveCliMainPath() {
|
|
|
163
226
|
const extension = modulePath.endsWith(".ts") ? ".ts" : ".js";
|
|
164
227
|
return resolve(dirname(modulePath), "..", "..", `cli-main${extension}`);
|
|
165
228
|
}
|
|
229
|
+
/**
|
|
230
|
+
* Resolves the host child spawn. Explicit child commands (desktop launchers)
|
|
231
|
+
* are forwarded untouched. The default re-enters the committed CLI entry
|
|
232
|
+
* through the runtime, except in compiled standalone binaries, which always
|
|
233
|
+
* boot their embedded entrypoint and would parse a script path as CLI
|
|
234
|
+
* arguments - there the executable itself is the CLI, so the mode flags are
|
|
235
|
+
* passed directly. Exported for tests.
|
|
236
|
+
*/
|
|
237
|
+
export function resolveHostChildLaunch(launch, internalSocket, compiled = isBunBinary) {
|
|
238
|
+
if (launch.childCommand) {
|
|
239
|
+
return {
|
|
240
|
+
command: launch.childCommand,
|
|
241
|
+
args: [...(launch.childArgs ?? []), "--listen", `unix://${internalSocket}`],
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
return {
|
|
245
|
+
command: process.execPath,
|
|
246
|
+
args: [
|
|
247
|
+
...(compiled ? [] : [...process.execArgv, resolveCliMainPath()]),
|
|
248
|
+
"--mode",
|
|
249
|
+
"rpc",
|
|
250
|
+
"--multi-session",
|
|
251
|
+
"--listen",
|
|
252
|
+
`unix://${internalSocket}`,
|
|
253
|
+
...launch.hostArgs,
|
|
254
|
+
],
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
/** Mirrors cross-spawn: survives cmd.exe parsing and `CommandLineToArgvW`. */
|
|
258
|
+
function quoteWindowsShellArg(value) {
|
|
259
|
+
const escaped = value
|
|
260
|
+
.replace(/(\\*)"/g, '$1$1\\"')
|
|
261
|
+
.replace(/(\\*)$/, "$1$1")
|
|
262
|
+
.replace(/([()%!^"<>&|;,])/g, "^$1");
|
|
263
|
+
return `"${escaped}"`;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Windows refuses to spawn a `.cmd`/`.bat` without a shell, and Node's
|
|
267
|
+
* `shell: true` concatenates argv without escaping it. Escape each original
|
|
268
|
+
* value before adding the surrounding quotes so `.cmd`/`.bat` launchers survive
|
|
269
|
+
* cmd.exe parsing without double-escaping.
|
|
270
|
+
* Exported for tests.
|
|
271
|
+
*/
|
|
272
|
+
export function spawnableChildLaunch(launch, platform = process.platform) {
|
|
273
|
+
const extension = extname(launch.command).toLowerCase();
|
|
274
|
+
if (platform !== "win32" || (extension !== ".cmd" && extension !== ".bat")) {
|
|
275
|
+
return { ...launch, shell: false };
|
|
276
|
+
}
|
|
277
|
+
return {
|
|
278
|
+
command: quoteWindowsShellArg(launch.command),
|
|
279
|
+
args: launch.args.map(quoteWindowsShellArg),
|
|
280
|
+
shell: true,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
166
283
|
export async function runHostSupervisor(launch) {
|
|
167
284
|
const paths = createHostDaemonPaths(launch.agentDir ?? getAgentDir());
|
|
168
285
|
const policy = resolveHostPolicy(await readSettingsFile(paths.settingsFile), process.env);
|
|
169
286
|
const publicSocket = launch.socket;
|
|
170
|
-
const internal = await createInternalSocketPath();
|
|
287
|
+
const internal = await createInternalSocketPath(paths.dir);
|
|
171
288
|
const internalSocket = internal.socket;
|
|
289
|
+
const internalSecretPath = internal.secretPath ?? socketSecretPath(internalSocket);
|
|
290
|
+
const internalSecret = process.platform === "win32" ? await createSocketSecret(internalSecretPath) : undefined;
|
|
291
|
+
const publicSecret = process.platform === "win32" ? await readSocketSecret(socketSecretPath(publicSocket)) : undefined;
|
|
172
292
|
const clientSockets = new Set();
|
|
173
293
|
const busySessions = new Map();
|
|
174
294
|
let observerHealthy = false;
|
|
175
295
|
let observerReconnectTimer;
|
|
296
|
+
let childExitWatchTimer;
|
|
176
297
|
let shuttingDown = false;
|
|
177
298
|
let shutdownPromise;
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
: [
|
|
181
|
-
...process.execArgv,
|
|
182
|
-
resolveCliMainPath(),
|
|
183
|
-
"--mode",
|
|
184
|
-
"rpc",
|
|
185
|
-
"--multi-session",
|
|
186
|
-
"--listen",
|
|
187
|
-
`unix://${internalSocket}`,
|
|
188
|
-
...launch.hostArgs,
|
|
189
|
-
], {
|
|
299
|
+
const childLaunch = spawnableChildLaunch(resolveHostChildLaunch(launch, internalSocket));
|
|
300
|
+
const child = spawn(childLaunch.command, childLaunch.args, {
|
|
190
301
|
env: {
|
|
191
302
|
...process.env,
|
|
192
303
|
...(launch.agentDir ? { SENPI_CODING_AGENT_DIR: launch.agentDir } : {}),
|
|
193
304
|
[HOST_WATCH_FD_ENV]: String(CHILD_WATCH_FD),
|
|
194
305
|
[HOST_WATCH_PPID_ENV]: String(process.pid),
|
|
195
|
-
[HOST_SCRATCH_DIR_ENV]: internal.dir,
|
|
196
|
-
[
|
|
306
|
+
...(internal.dir ? { [HOST_SCRATCH_DIR_ENV]: internal.dir } : {}),
|
|
307
|
+
...(internalSecret ? { [SOCKET_SECRET_FILE_ENV]: internalSecretPath } : {}),
|
|
308
|
+
[HOST_CLEANUP_PATHS_ENV]: [
|
|
309
|
+
paths.pidFile,
|
|
310
|
+
paths.settingsFile,
|
|
311
|
+
...(process.platform === "win32" ? [] : [publicSocket]),
|
|
312
|
+
].join("\n"),
|
|
197
313
|
},
|
|
198
314
|
// Slot 3 is the lifetime pipe: "pipe" gives the child a read end it can
|
|
199
315
|
// wait on and keeps the write end owned by this process alone.
|
|
316
|
+
shell: childLaunch.shell,
|
|
200
317
|
stdio: ["ignore", "ignore", "inherit", "pipe"],
|
|
318
|
+
// The supervisor is spawned detached, so on win32 it owns no console. A
|
|
319
|
+
// console-subsystem child started from it would allocate a fresh one,
|
|
320
|
+
// which Windows Terminal renders as an empty window that takes focus.
|
|
321
|
+
// CREATE_NO_WINDOW gives the child a console with no window instead.
|
|
322
|
+
windowsHide: true,
|
|
201
323
|
});
|
|
202
324
|
// Nothing is ever written; the pipe exists purely so its EOF is a reliable
|
|
203
325
|
// death notification. Errors on it must not crash the supervisor.
|
|
204
326
|
child.stdio[CHILD_WATCH_FD]?.on("error", () => { });
|
|
205
327
|
child.once("exit", (code, signal) => {
|
|
206
|
-
if (
|
|
207
|
-
|
|
328
|
+
if (shuttingDown)
|
|
329
|
+
return;
|
|
330
|
+
const { reason, exitCode } = classifyChildExit(code, signal);
|
|
331
|
+
void shutdown(reason, exitCode);
|
|
208
332
|
});
|
|
209
333
|
const server = createServer((client) => {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
334
|
+
const accept = () => {
|
|
335
|
+
if (shuttingDown) {
|
|
336
|
+
client.destroy();
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
const internal = createConnection(resolveSocketTransportAddress(internalSocket, process.platform, internalSecret));
|
|
340
|
+
if (internalSecret)
|
|
341
|
+
sendSocketHandshake(internal, internalSecret);
|
|
342
|
+
clientSockets.add(client);
|
|
343
|
+
const detach = () => {
|
|
344
|
+
clientSockets.delete(client);
|
|
345
|
+
internal.destroy();
|
|
346
|
+
client.destroy();
|
|
347
|
+
};
|
|
348
|
+
client.pipe(internal);
|
|
349
|
+
internal.pipe(client);
|
|
350
|
+
client.once("close", detach);
|
|
351
|
+
client.once("error", detach);
|
|
352
|
+
internal.once("close", detach);
|
|
353
|
+
internal.once("error", detach);
|
|
220
354
|
};
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
internal.once("close", detach);
|
|
226
|
-
internal.once("error", detach);
|
|
355
|
+
if (publicSecret)
|
|
356
|
+
authenticateSocket(client, publicSecret, accept);
|
|
357
|
+
else
|
|
358
|
+
accept();
|
|
227
359
|
});
|
|
228
360
|
server.once("error", (cause) => {
|
|
229
361
|
if (!shuttingDown)
|
|
@@ -278,25 +410,40 @@ export async function runHostSupervisor(launch) {
|
|
|
278
410
|
process.exit(exitCode);
|
|
279
411
|
shuttingDown = true;
|
|
280
412
|
clearInterval(ticker);
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
413
|
+
if (childExitWatchTimer)
|
|
414
|
+
clearInterval(childExitWatchTimer);
|
|
415
|
+
const hardExit = process.platform === "win32"
|
|
416
|
+
? setTimeout(() => process.exit(exitCode), WINDOWS_SUPERVISOR_SHUTDOWN_HARD_EXIT_MS)
|
|
417
|
+
: undefined;
|
|
418
|
+
try {
|
|
419
|
+
writeStderrLine(`senpi rpc host supervisor: ${reason} shutdown`);
|
|
420
|
+
for (const client of clientSockets)
|
|
421
|
+
client.destroy();
|
|
422
|
+
await closeServer(server);
|
|
423
|
+
// Unlink the private directory BEFORE the child stop, which can take seconds:
|
|
424
|
+
// an external SIGKILL landing during that wait (ensureHost escalates while
|
|
425
|
+
// replacing a host) would otherwise leave the directory behind. The child
|
|
426
|
+
// keeps serving through its already-open socket fd until it exits, and its
|
|
427
|
+
// own watchdog cleanup makes the removal idempotent.
|
|
428
|
+
if (internal.dir)
|
|
429
|
+
await rm(internal.dir, { recursive: true, force: true });
|
|
430
|
+
await stopChild(child);
|
|
431
|
+
observer?.destroy();
|
|
432
|
+
if (publicSocketOwned && process.platform !== "win32")
|
|
433
|
+
await rm(publicSocket, { force: true });
|
|
434
|
+
// Mirror ensureHost's cleanupState: the pidfile and settings describe a
|
|
435
|
+
// live host only; the stderr log stays for diagnostics.
|
|
436
|
+
await rm(paths.pidFile, { force: true });
|
|
437
|
+
await rm(paths.settingsFile, { force: true });
|
|
438
|
+
}
|
|
439
|
+
finally {
|
|
440
|
+
if (hardExit)
|
|
441
|
+
clearTimeout(hardExit);
|
|
442
|
+
// Explicitly terminate after every supervisor shutdown trigger. Windows
|
|
443
|
+
// named-pipe handles can outlive their JavaScript wrappers, so cleanup
|
|
444
|
+
// failure must never leave the supervisor resident or the host orphaned.
|
|
445
|
+
process.exit(exitCode);
|
|
446
|
+
}
|
|
300
447
|
}
|
|
301
448
|
let observer;
|
|
302
449
|
let publicSocketOwned = false;
|
|
@@ -306,17 +453,20 @@ export async function runHostSupervisor(launch) {
|
|
|
306
453
|
// would leave that directory behind.
|
|
307
454
|
registerSupervisorSignals(shutdown);
|
|
308
455
|
try {
|
|
309
|
-
await waitForListener(internalSocket, 30_000);
|
|
456
|
+
await waitForListener(internalSocket, 30_000, internalSecret);
|
|
310
457
|
await connectObserver();
|
|
311
458
|
await prepareSocketPath(publicSocket);
|
|
312
|
-
await listen(server, publicSocket);
|
|
459
|
+
await listen(server, publicSocket, publicSecret);
|
|
313
460
|
publicSocketOwned = true;
|
|
314
461
|
}
|
|
315
462
|
catch (cause) {
|
|
316
463
|
await shutdown(`startup failed: ${errorMessage(cause)}`, 1);
|
|
317
464
|
}
|
|
318
465
|
async function connectObserver() {
|
|
319
|
-
const
|
|
466
|
+
const secret = internalSecret;
|
|
467
|
+
const next = createConnection(resolveSocketTransportAddress(internalSocket, process.platform, secret));
|
|
468
|
+
if (secret)
|
|
469
|
+
sendSocketHandshake(next, secret);
|
|
320
470
|
await waitForConnect(next, 5_000);
|
|
321
471
|
observer = next;
|
|
322
472
|
observerHealthy = true;
|
|
@@ -337,6 +487,33 @@ export async function runHostSupervisor(launch) {
|
|
|
337
487
|
next.once("close", lost);
|
|
338
488
|
next.once("error", lost);
|
|
339
489
|
}
|
|
490
|
+
if (process.platform === "win32" && child.pid !== undefined) {
|
|
491
|
+
const childStartTime = await readProcessStartTime(child.pid, process.platform, 1_000);
|
|
492
|
+
let missingIdentityChecks = 0;
|
|
493
|
+
let checkingChildIdentity = false;
|
|
494
|
+
const checkChildIdentity = () => {
|
|
495
|
+
if (shuttingDown || checkingChildIdentity || child.exitCode !== null || child.signalCode !== null)
|
|
496
|
+
return;
|
|
497
|
+
checkingChildIdentity = true;
|
|
498
|
+
void readProcessStartTime(child.pid, process.platform, 1_000)
|
|
499
|
+
.then((currentStartTime) => {
|
|
500
|
+
if (currentStartTime === undefined)
|
|
501
|
+
missingIdentityChecks++;
|
|
502
|
+
else
|
|
503
|
+
missingIdentityChecks = 0;
|
|
504
|
+
const identityChanged = childStartTime !== undefined && currentStartTime !== undefined && currentStartTime !== childStartTime;
|
|
505
|
+
if (identityChanged || missingIdentityChecks >= 2) {
|
|
506
|
+
void shutdown("rpc host child exit observed by identity watchdog", 0);
|
|
507
|
+
}
|
|
508
|
+
})
|
|
509
|
+
.catch(() => { })
|
|
510
|
+
.finally(() => {
|
|
511
|
+
checkingChildIdentity = false;
|
|
512
|
+
});
|
|
513
|
+
};
|
|
514
|
+
childExitWatchTimer = setInterval(checkChildIdentity, 500);
|
|
515
|
+
childExitWatchTimer.unref?.();
|
|
516
|
+
}
|
|
340
517
|
writeStderrLine(`senpi rpc host ready on unix://${publicSocket} (coldStart=${policy.coldStart}, idleExitMs=${policy.coldStart === "persistent" ? "never" : String(policy.idleExitMs)})`);
|
|
341
518
|
await new Promise(() => { });
|
|
342
519
|
}
|
|
@@ -390,18 +567,20 @@ function waitForChildExit(child, timeoutMs) {
|
|
|
390
567
|
child.once("exit", onExit);
|
|
391
568
|
});
|
|
392
569
|
}
|
|
393
|
-
async function waitForListener(socketPath, timeoutMs) {
|
|
570
|
+
async function waitForListener(socketPath, timeoutMs, secret) {
|
|
394
571
|
const deadline = Date.now() + timeoutMs;
|
|
395
572
|
while (Date.now() <= deadline) {
|
|
396
|
-
if (await canConnect(socketPath))
|
|
573
|
+
if (await canConnect(socketPath, secret))
|
|
397
574
|
return;
|
|
398
575
|
await delay(50);
|
|
399
576
|
}
|
|
400
577
|
throw new Error(`${socketPath}: host did not start listening within ${timeoutMs}ms`);
|
|
401
578
|
}
|
|
402
|
-
function canConnect(socketPath) {
|
|
579
|
+
function canConnect(socketPath, secret) {
|
|
403
580
|
return new Promise((resolve) => {
|
|
404
|
-
const socket = createConnection(socketPath);
|
|
581
|
+
const socket = createConnection(resolveSocketTransportAddress(socketPath, process.platform, secret));
|
|
582
|
+
if (secret)
|
|
583
|
+
sendSocketHandshake(socket, secret);
|
|
405
584
|
const settle = (value) => {
|
|
406
585
|
socket.destroy();
|
|
407
586
|
resolve(value);
|
|
@@ -434,6 +613,8 @@ function waitForConnect(socket, timeoutMs) {
|
|
|
434
613
|
});
|
|
435
614
|
}
|
|
436
615
|
async function prepareSocketPath(socketPath) {
|
|
616
|
+
if (process.platform === "win32")
|
|
617
|
+
return;
|
|
437
618
|
await mkdir(dirname(socketPath), { recursive: true, mode: 0o700 });
|
|
438
619
|
try {
|
|
439
620
|
await access(socketPath);
|
|
@@ -447,14 +628,23 @@ async function prepareSocketPath(socketPath) {
|
|
|
447
628
|
throw new Error(`${socketPath}: address already in use by a live server.`);
|
|
448
629
|
await unlink(socketPath);
|
|
449
630
|
}
|
|
450
|
-
function listen(server, socketPath) {
|
|
631
|
+
function listen(server, socketPath, secret) {
|
|
451
632
|
return new Promise((resolve, reject) => {
|
|
452
633
|
server.once("error", reject);
|
|
453
|
-
server.listen(
|
|
634
|
+
server.listen({
|
|
635
|
+
path: resolveSocketTransportAddress(socketPath, process.platform, secret),
|
|
636
|
+
readableAll: false,
|
|
637
|
+
writableAll: false,
|
|
638
|
+
}, async () => {
|
|
454
639
|
server.off("error", reject);
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
640
|
+
try {
|
|
641
|
+
if (process.platform !== "win32" && !socketPath.startsWith("\0"))
|
|
642
|
+
await chmod(socketPath, 0o600);
|
|
643
|
+
resolve();
|
|
644
|
+
}
|
|
645
|
+
catch (cause) {
|
|
646
|
+
reject(cause);
|
|
647
|
+
}
|
|
458
648
|
});
|
|
459
649
|
});
|
|
460
650
|
}
|