@code-yeongyu/senpi 2026.8.30 → 2026.8.31
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 +142 -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 +18 -0
- package/dist/core/extensions/builtin/compaction/context-pipeline.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/context-pipeline.js +32 -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 +148 -150
- 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/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/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.map +1 -1
- package/dist/main.js +17 -5
- package/dist/main.js.map +1 -1
- package/dist/modes/app-server/daemon.js +3 -3
- 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.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +24 -0
- package/dist/modes/interactive/interactive-mode.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 +173 -23
- package/dist/modes/rpc/connection-handler.js.map +1 -1
- package/dist/modes/rpc/custom-capability.d.ts +1 -0
- package/dist/modes/rpc/custom-capability.d.ts.map +1 -1
- package/dist/modes/rpc/custom-capability.js +1 -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 +67 -16
- package/dist/modes/rpc/host-ensure.js.map +1 -1
- package/dist/modes/rpc/host-lifecycle.d.ts +39 -0
- package/dist/modes/rpc/host-lifecycle.d.ts.map +1 -1
- package/dist/modes/rpc/host-lifecycle.js +80 -15
- package/dist/modes/rpc/host-lifecycle.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 +55 -5
- 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 +38 -11
- 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 +174 -2
- 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/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 +4 -4
- 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 +78 -5
- package/docs/sdk.md +1 -1
- 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 +40 -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/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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host-ensure.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/host-ensure.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"host-ensure.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/host-ensure.ts"],"names":[],"mappings":"AAmBA,OAAO,EAEN,KAAK,aAAa,EAClB,KAAK,wBAAwB,EAE7B,MAAM,qBAAqB,CAAC;AAG7B,YAAY,EAAE,aAAa,EAAE,wBAAwB,EAAE,CAAC;AAExD,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,sFAAsF;IACtF,QAAQ,CAAC,MAAM,CAAC,EAAE,wBAAwB,CAAC;IAC3C,QAAQ,CAAC,KAAK,CAAC,EAAE;QAChB,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;QACrC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAChC,QAAQ,CAAC,KAAK,CAAC,EAAE;YAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;SAAE,CAAC;QAChF,wFAAwF;QACxF,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QAChD,2EAA2E;QAC3E,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QACtC,oFAAoF;QACpF,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;KACjD,CAAC;CACF;AAED,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CACzB;AASD;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,qDAAwE,CAAC;AAErH,wBAAgB,qBAAqB,CAAC,QAAQ,SAAgB,GAAG,eAAe,CAS/E;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAgBjF;AAqPD;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAChC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,QAAQ,GAAE,OAAqB,GAC7B;IACF,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CACf,CAWA"}
|
|
@@ -5,12 +5,12 @@ import { createConnection } from "node:net";
|
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
6
|
import { dirname, join, resolve } from "node:path";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
|
-
import
|
|
9
|
-
import { ENV_AGENT_DIR, getAgentDir, VERSION } from "../../config.js";
|
|
8
|
+
import { ENV_AGENT_DIR, getAgentDir, isBunBinary, VERSION } from "../../config.js";
|
|
10
9
|
import { parseDaemonPidFile, processMatchesPidFile, waitForStartTime, } from "../app-server/daemon/process.js";
|
|
11
10
|
import { CUSTOM_UNSUPPORTED_CAPABILITY, EXTENSION_EVENTS_CAPABILITY, RPC_CLIENT_CAPABILITIES_ENV, } from "./custom-capability.js";
|
|
12
|
-
import { DEFAULT_HOST_IDLE_EXIT_MS } from "./host-lifecycle.js";
|
|
13
|
-
|
|
11
|
+
import { DEFAULT_HOST_IDLE_EXIT_MS, INTERNAL_SUPERVISOR_FLAG, } from "./host-lifecycle.js";
|
|
12
|
+
import { acquireOwnershipSafeLock } from "./ownership-safe-lock.js";
|
|
13
|
+
const lockOptions = { retries: { retries: 100, minTimeout: 20, maxTimeout: 100 } };
|
|
14
14
|
const REQUIRED_CAPABILITIES = ["multi_session", EXTENSION_EVENTS_CAPABILITY];
|
|
15
15
|
/**
|
|
16
16
|
* Every ensured host starts with this installation-wide profile, independent of
|
|
@@ -37,7 +37,7 @@ export async function ensureHost(options) {
|
|
|
37
37
|
const lockTarget = join(tmpdir(), "senpi-rpc-host-locks", createSocketLockName(socket));
|
|
38
38
|
await mkdir(dirname(lockTarget), { recursive: true });
|
|
39
39
|
await writeFile(lockTarget, "", { flag: "a", mode: 0o600 });
|
|
40
|
-
const release = await
|
|
40
|
+
const release = await acquireOwnershipSafeLock(`${lockTarget}.lock`, lockOptions);
|
|
41
41
|
try {
|
|
42
42
|
await options._test?.afterLockAcquired?.();
|
|
43
43
|
return await ensureHostLocked(paths, socket, options.agentDir ?? getAgentDir(), options.policy, options._test);
|
|
@@ -75,9 +75,12 @@ async function startHost(paths, socket, agentDir, policy, testOptions) {
|
|
|
75
75
|
})}\n`, { mode: 0o600 });
|
|
76
76
|
const stderr = await open(paths.stderrLog, "w", 0o600);
|
|
77
77
|
let pidFile;
|
|
78
|
+
let child;
|
|
79
|
+
let exitedEarly;
|
|
80
|
+
let childExit;
|
|
78
81
|
try {
|
|
79
82
|
const launch = testOptions?.spawn ?? defaultHostLaunch(socket, testOptions?.hostArgs ?? []);
|
|
80
|
-
|
|
83
|
+
child = spawn(launch.command, [...launch.args], {
|
|
81
84
|
detached: true,
|
|
82
85
|
env: {
|
|
83
86
|
...process.env,
|
|
@@ -87,21 +90,45 @@ async function startHost(paths, socket, agentDir, policy, testOptions) {
|
|
|
87
90
|
},
|
|
88
91
|
stdio: ["ignore", "ignore", stderr.fd],
|
|
89
92
|
});
|
|
93
|
+
childExit = new Promise((resolveExit) => {
|
|
94
|
+
child.once("exit", (code, signal) => {
|
|
95
|
+
exitedEarly = { code, signal };
|
|
96
|
+
resolveExit(exitedEarly);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
90
99
|
child.unref();
|
|
91
100
|
if (child.pid === undefined)
|
|
92
101
|
throw new Error("failed to spawn RPC socket host");
|
|
93
|
-
|
|
102
|
+
const processStartTime = await Promise.race([
|
|
103
|
+
waitForStartTime(child.pid, 2_000),
|
|
104
|
+
childExit.then(() => {
|
|
105
|
+
throw new Error("RPC socket host exited before its start time could be read");
|
|
106
|
+
}),
|
|
107
|
+
]);
|
|
108
|
+
pidFile = { pid: child.pid, processStartTime };
|
|
94
109
|
await writeFile(paths.pidFile, `${JSON.stringify(pidFile)}\n`, { mode: 0o600 });
|
|
95
110
|
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
if (!exitedEarly)
|
|
113
|
+
throw error;
|
|
114
|
+
const diagnostic = await appendStderr(paths, `RPC socket host exited with code ${exitedEarly.code ?? "null"}${exitedEarly.signal ? ` (${exitedEarly.signal})` : ""} before answering get_protocol_info`);
|
|
115
|
+
await cleanupState(paths);
|
|
116
|
+
throw new Error(diagnostic);
|
|
117
|
+
}
|
|
96
118
|
finally {
|
|
97
119
|
await stderr.close();
|
|
98
120
|
}
|
|
99
121
|
const readinessTimeoutMs = testOptions?.readinessTimeoutMs ?? 10_000;
|
|
100
|
-
const
|
|
101
|
-
if (isCompatible(protocol))
|
|
122
|
+
const result = await pollProtocolInfo(socket, readinessTimeoutMs, childExit);
|
|
123
|
+
if (isCompatible(result.protocol))
|
|
102
124
|
return { pid: pidFile.pid, socket, reused: false };
|
|
103
125
|
await stopManagedHost(pidFile, testOptions?.stopTimeoutMs ?? 10_000);
|
|
104
|
-
const
|
|
126
|
+
const message = result.protocol
|
|
127
|
+
? `RPC socket host answered get_protocol_info with serverVersion ${result.protocol.serverVersion} and capabilities ${JSON.stringify(result.protocol.capabilities)}, but is incompatible with serverVersion ${VERSION} and required capabilities ${JSON.stringify(REQUIRED_CAPABILITIES)}`
|
|
128
|
+
: result.exited
|
|
129
|
+
? `RPC socket host exited with code ${result.exited.code ?? "null"}${result.exited.signal ? ` (${result.exited.signal})` : ""} before answering get_protocol_info`
|
|
130
|
+
: `spawned RPC socket host did not answer get_protocol_info within ${readinessTimeoutMs}ms`;
|
|
131
|
+
const diagnostic = await appendStderr(paths, message);
|
|
105
132
|
await cleanupState(paths);
|
|
106
133
|
// The supervisor may have failed before binding, or another owner may have
|
|
107
134
|
// appeared while readiness was being checked. Never unlink an endpoint we
|
|
@@ -137,15 +164,25 @@ async function waitForGone(pidFile, timeoutMs) {
|
|
|
137
164
|
}
|
|
138
165
|
return false;
|
|
139
166
|
}
|
|
140
|
-
async function pollProtocolInfo(socket, timeoutMs) {
|
|
167
|
+
async function pollProtocolInfo(socket, timeoutMs, childExit) {
|
|
141
168
|
const deadline = Date.now() + timeoutMs;
|
|
169
|
+
let lastProtocol;
|
|
142
170
|
while (Date.now() <= deadline) {
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
171
|
+
const probe = probeProtocolInfo(socket, Math.min(500, Math.max(1, deadline - Date.now())));
|
|
172
|
+
const info = childExit ? await Promise.race([probe, childExit]) : await probe;
|
|
173
|
+
if (isChildExit(info))
|
|
174
|
+
return { protocol: lastProtocol, exited: info };
|
|
175
|
+
if (info) {
|
|
176
|
+
lastProtocol = info;
|
|
177
|
+
if (isCompatible(info))
|
|
178
|
+
return { protocol: info };
|
|
179
|
+
}
|
|
146
180
|
await delay(50);
|
|
147
181
|
}
|
|
148
|
-
return
|
|
182
|
+
return { protocol: lastProtocol };
|
|
183
|
+
}
|
|
184
|
+
function isChildExit(value) {
|
|
185
|
+
return !!value && "code" in value && "signal" in value;
|
|
149
186
|
}
|
|
150
187
|
function probeProtocolInfo(socketPath, timeoutMs) {
|
|
151
188
|
return new Promise((resolveProbe) => {
|
|
@@ -234,8 +271,22 @@ function normalizeSocketPath(value) {
|
|
|
234
271
|
* Default launch: the host-lifecycle supervisor owns the public socket and the
|
|
235
272
|
* idle-exit policy; it spawns the committed RPC socket host itself. Any extra
|
|
236
273
|
* hostArgs are forwarded verbatim to the host CLI (e.g. provider pinning).
|
|
274
|
+
*
|
|
275
|
+
* A compiled standalone binary cannot re-enter itself through a script path:
|
|
276
|
+
* bun executables always boot their embedded entrypoint and parse the whole
|
|
277
|
+
* argv as CLI arguments, so `host-lifecycle.ts --socket <path>` dies with
|
|
278
|
+
* "Unknown option: --socket" before the host ever answers get_protocol_info.
|
|
279
|
+
* Compiled binaries therefore re-enter through the hidden
|
|
280
|
+
* `--internal-rpc-host-supervisor` route that main() dispatches before
|
|
281
|
+
* argument parsing. Exported for tests.
|
|
237
282
|
*/
|
|
238
|
-
function defaultHostLaunch(socket, hostArgs) {
|
|
283
|
+
export function defaultHostLaunch(socket, hostArgs, compiled = isBunBinary) {
|
|
284
|
+
if (compiled) {
|
|
285
|
+
return {
|
|
286
|
+
command: process.execPath,
|
|
287
|
+
args: [INTERNAL_SUPERVISOR_FLAG, "--socket", socket, ...hostArgs],
|
|
288
|
+
};
|
|
289
|
+
}
|
|
239
290
|
return {
|
|
240
291
|
command: process.execPath,
|
|
241
292
|
args: [...process.execArgv, resolveHostLifecycleEntryPath(), "--socket", socket, ...hostArgs],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host-ensure.js","sourceRoot":"","sources":["../../../src/modes/rpc/host-ensure.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { mkdir, open, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { createConnection } from \"node:net\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as properLockfile from \"proper-lockfile\";\nimport { ENV_AGENT_DIR, getAgentDir, VERSION } from \"../../config.ts\";\nimport {\n\ttype DaemonPidFile,\n\tparseDaemonPidFile,\n\tprocessMatchesPidFile,\n\twaitForStartTime,\n} from \"../app-server/daemon/process.ts\";\nimport {\n\tCUSTOM_UNSUPPORTED_CAPABILITY,\n\tEXTENSION_EVENTS_CAPABILITY,\n\tRPC_CLIENT_CAPABILITIES_ENV,\n} from \"./custom-capability.ts\";\nimport { DEFAULT_HOST_IDLE_EXIT_MS, type HostColdStart, type HostLifecyclePolicyInput } from \"./host-lifecycle.ts\";\n\nexport type { HostColdStart, HostLifecyclePolicyInput };\n\nexport interface HostDaemonPaths {\n\treadonly dir: string;\n\treadonly pidFile: string;\n\treadonly lockFile: string;\n\treadonly settingsFile: string;\n\treadonly stderrLog: string;\n}\n\nexport interface EnsureHostOptions {\n\treadonly socket: string;\n\treadonly agentDir?: string;\n\t/** Host lifecycle policy recorded in settings.json (env overrides win at runtime). */\n\treadonly policy?: HostLifecyclePolicyInput;\n\treadonly _test?: {\n\t\treadonly readinessTimeoutMs?: number;\n\t\treadonly stopTimeoutMs?: number;\n\t\treadonly spawn?: { readonly command: string; readonly args: readonly string[] };\n\t\t/** Extra env merged over process.env for the spawned host (hermetic test/QA wiring). */\n\t\treadonly env?: Readonly<Record<string, string>>;\n\t\t/** Extra CLI args forwarded through the supervisor to the host process. */\n\t\treadonly hostArgs?: readonly string[];\n\t\t/** Runs after endpoint ownership is locked; deterministic concurrency-test gate. */\n\t\treadonly afterLockAcquired?: () => Promise<void>;\n\t};\n}\n\nexport interface EnsuredHost {\n\treadonly pid: number;\n\treadonly socket: string;\n\treadonly reused: boolean;\n}\n\ntype ProtocolInfo = {\n\treadonly serverVersion: string;\n\treadonly capabilities: readonly string[];\n};\n\nconst lockOptions = { stale: 60_000, retries: { retries: 100, minTimeout: 20, maxTimeout: 100 } } as const;\nconst REQUIRED_CAPABILITIES = [\"multi_session\", EXTENSION_EVENTS_CAPABILITY] as const;\n/**\n * Every ensured host starts with this installation-wide profile, independent of\n * the first caller. In particular, extension_events must remain available when\n * a terminal client starts the shared host before the desktop connects.\n */\nexport const PINNED_HOST_CLIENT_CAPABILITIES = [EXTENSION_EVENTS_CAPABILITY, CUSTOM_UNSUPPORTED_CAPABILITY] as const;\n\nexport function createHostDaemonPaths(agentDir = getAgentDir()): HostDaemonPaths {\n\tconst dir = join(agentDir, \"rpc-host-daemon\");\n\treturn {\n\t\tdir,\n\t\tpidFile: join(dir, \"host.pid\"),\n\t\tlockFile: join(dir, \"daemon.lock\"),\n\t\tsettingsFile: join(dir, \"settings.json\"),\n\t\tstderrLog: join(dir, \"stderr.log\"),\n\t};\n}\n\nexport async function ensureHost(options: EnsureHostOptions): Promise<EnsuredHost> {\n\tconst socket = normalizeSocketPath(options.socket);\n\tconst paths = createHostDaemonPaths(options.agentDir);\n\tawait mkdir(paths.dir, { recursive: true });\n\t// The public socket is the shared resource; agent directories are not a\n\t// sufficient lock scope when two installations target the same endpoint.\n\tconst lockTarget = join(tmpdir(), \"senpi-rpc-host-locks\", createSocketLockName(socket));\n\tawait mkdir(dirname(lockTarget), { recursive: true });\n\tawait writeFile(lockTarget, \"\", { flag: \"a\", mode: 0o600 });\n\tconst release = await properLockfile.lock(lockTarget, { ...lockOptions, lockfilePath: `${lockTarget}.lock` });\n\ttry {\n\t\tawait options._test?.afterLockAcquired?.();\n\t\treturn await ensureHostLocked(paths, socket, options.agentDir ?? getAgentDir(), options.policy, options._test);\n\t} finally {\n\t\tawait release();\n\t}\n}\n\nasync function ensureHostLocked(\n\tpaths: HostDaemonPaths,\n\tsocket: string,\n\tagentDir: string,\n\tpolicy: HostLifecyclePolicyInput | undefined,\n\ttestOptions: EnsureHostOptions[\"_test\"],\n): Promise<EnsuredHost> {\n\tconst pidFile = await readPidFile(paths);\n\tconst protocol = await probeProtocolInfo(socket, 1_000);\n\tconst pidMatches = pidFile ? await processMatchesPidFile(pidFile) : false;\n\tif (isCompatible(protocol)) {\n\t\t// A compatible socket is attachable even when another client surface\n\t\t// started it. Only hosts we spawned are eligible for lifecycle management.\n\t\treturn { pid: pidFile?.pid ?? 0, socket, reused: true };\n\t}\n\tif (protocol && !pidMatches) {\n\t\tthrow new Error(`RPC socket ${socket} is owned by an unmanaged host`);\n\t}\n\tif (pidFile && pidMatches) {\n\t\tawait stopManagedHost(pidFile, testOptions?.stopTimeoutMs ?? 10_000);\n\t}\n\tawait cleanupState(paths);\n\treturn startHost(paths, socket, agentDir, policy, testOptions);\n}\n\nasync function startHost(\n\tpaths: HostDaemonPaths,\n\tsocket: string,\n\tagentDir: string,\n\tpolicy: HostLifecyclePolicyInput | undefined,\n\ttestOptions: EnsureHostOptions[\"_test\"],\n): Promise<EnsuredHost> {\n\t// The settings file must exist before the supervisor reads it at boot, so it\n\t// records the policy before the spawn instead of beside the pidfile.\n\tawait writeFile(\n\t\tpaths.settingsFile,\n\t\t`${JSON.stringify({\n\t\t\tsocket,\n\t\t\tcapabilities: PINNED_HOST_CLIENT_CAPABILITIES,\n\t\t\tcoldStart: policy?.coldStart ?? \"transient\",\n\t\t\tidleExitMs: policy?.idleExitMs ?? DEFAULT_HOST_IDLE_EXIT_MS,\n\t\t})}\\n`,\n\t\t{ mode: 0o600 },\n\t);\n\tconst stderr = await open(paths.stderrLog, \"w\", 0o600);\n\tlet pidFile: DaemonPidFile | undefined;\n\ttry {\n\t\tconst launch = testOptions?.spawn ?? defaultHostLaunch(socket, testOptions?.hostArgs ?? []);\n\t\tconst child = spawn(launch.command, [...launch.args], {\n\t\t\tdetached: true,\n\t\t\tenv: {\n\t\t\t\t...process.env,\n\t\t\t\t...(testOptions?.env ?? {}),\n\t\t\t\t[ENV_AGENT_DIR]: agentDir,\n\t\t\t\t[RPC_CLIENT_CAPABILITIES_ENV]: PINNED_HOST_CLIENT_CAPABILITIES.join(\",\"),\n\t\t\t},\n\t\t\tstdio: [\"ignore\", \"ignore\", stderr.fd],\n\t\t});\n\t\tchild.unref();\n\t\tif (child.pid === undefined) throw new Error(\"failed to spawn RPC socket host\");\n\t\tpidFile = { pid: child.pid, processStartTime: await waitForStartTime(child.pid, 2_000) };\n\t\tawait writeFile(paths.pidFile, `${JSON.stringify(pidFile)}\\n`, { mode: 0o600 });\n\t} finally {\n\t\tawait stderr.close();\n\t}\n\tconst readinessTimeoutMs = testOptions?.readinessTimeoutMs ?? 10_000;\n\tconst protocol = await pollProtocolInfo(socket, readinessTimeoutMs);\n\tif (isCompatible(protocol)) return { pid: pidFile.pid, socket, reused: false };\n\tawait stopManagedHost(pidFile, testOptions?.stopTimeoutMs ?? 10_000);\n\tconst diagnostic = await appendStderr(\n\t\tpaths,\n\t\t`spawned RPC socket host did not answer get_protocol_info within ${readinessTimeoutMs}ms`,\n\t);\n\tawait cleanupState(paths);\n\t// The supervisor may have failed before binding, or another owner may have\n\t// appeared while readiness was being checked. Never unlink an endpoint we\n\t// cannot prove this start owned.\n\tthrow new Error(diagnostic);\n}\n\nasync function stopManagedHost(pidFile: DaemonPidFile, termTimeoutMs: number): Promise<void> {\n\tawait signalValidated(pidFile, \"SIGTERM\");\n\tif (await waitForGone(pidFile, termTimeoutMs)) return;\n\tawait signalValidated(pidFile, \"SIGKILL\");\n\tif (!(await waitForGone(pidFile, 2_000))) {\n\t\tthrow new Error(`RPC socket host pid ${pidFile.pid} remained alive after SIGKILL`);\n\t}\n}\n\nasync function signalValidated(pidFile: DaemonPidFile, signal: NodeJS.Signals): Promise<void> {\n\tif (!(await processMatchesPidFile(pidFile))) return;\n\ttry {\n\t\tprocess.kill(pidFile.pid, signal);\n\t} catch (error: unknown) {\n\t\tif (!isNodeErrorCode(error, \"ESRCH\")) throw error;\n\t}\n}\n\nasync function waitForGone(pidFile: DaemonPidFile, timeoutMs: number): Promise<boolean> {\n\tconst deadline = Date.now() + timeoutMs;\n\twhile (Date.now() <= deadline) {\n\t\tif (!(await processMatchesPidFile(pidFile))) return true;\n\t\tawait delay(50);\n\t}\n\treturn false;\n}\n\nasync function pollProtocolInfo(socket: string, timeoutMs: number): Promise<ProtocolInfo | undefined> {\n\tconst deadline = Date.now() + timeoutMs;\n\twhile (Date.now() <= deadline) {\n\t\tconst info = await probeProtocolInfo(socket, Math.min(500, Math.max(1, deadline - Date.now())));\n\t\tif (info) return info;\n\t\tawait delay(50);\n\t}\n\treturn undefined;\n}\n\nfunction probeProtocolInfo(socketPath: string, timeoutMs: number): Promise<ProtocolInfo | undefined> {\n\treturn new Promise((resolveProbe) => {\n\t\tconst socket = createConnection(socketPath);\n\t\tlet buffer = \"\";\n\t\tlet settled = false;\n\t\tconst finish = (value?: ProtocolInfo): void => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tclearTimeout(timeout);\n\t\t\tsocket.destroy();\n\t\t\tresolveProbe(value);\n\t\t};\n\t\tconst timeout = setTimeout(() => finish(), timeoutMs);\n\t\tsocket.once(\"connect\", () => {\n\t\t\tsocket.write('{\"id\":\"ensure-host-probe\",\"type\":\"get_protocol_info\"}\\n');\n\t\t});\n\t\tsocket.on(\"data\", (chunk) => {\n\t\t\tbuffer += chunk.toString(\"utf8\");\n\t\t\tconst newline = buffer.indexOf(\"\\n\");\n\t\t\tif (newline === -1) return;\n\t\t\tfinish(readProtocolInfo(buffer.slice(0, newline)));\n\t\t});\n\t\tsocket.once(\"error\", () => finish());\n\t\tsocket.once(\"close\", () => finish());\n\t});\n}\n\nfunction readProtocolInfo(text: string): ProtocolInfo | undefined {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(text);\n\t} catch {\n\t\treturn undefined;\n\t}\n\tif (!isRecord(parsed) || parsed.id !== \"ensure-host-probe\" || parsed.success !== true || !isRecord(parsed.data)) {\n\t\treturn undefined;\n\t}\n\tconst { serverVersion, capabilities } = parsed.data;\n\tif (typeof serverVersion !== \"string\" || !Array.isArray(capabilities)) return undefined;\n\tif (!capabilities.every((capability) => typeof capability === \"string\")) return undefined;\n\treturn { serverVersion, capabilities };\n}\n\nfunction isCompatible(protocol: ProtocolInfo | undefined): boolean {\n\treturn (\n\t\tprotocol?.serverVersion === VERSION &&\n\t\tREQUIRED_CAPABILITIES.every((capability) => protocol.capabilities.includes(capability))\n\t);\n}\n\nasync function readPidFile(paths: HostDaemonPaths): Promise<DaemonPidFile | undefined> {\n\ttry {\n\t\treturn parseDaemonPidFile(await readFile(paths.pidFile, \"utf8\"));\n\t} catch (error: unknown) {\n\t\tif (isNodeErrorCode(error, \"ENOENT\")) return undefined;\n\t\tthrow error;\n\t}\n}\n\nasync function cleanupState(paths: HostDaemonPaths): Promise<void> {\n\tawait rm(paths.pidFile, { force: true });\n\tawait rm(paths.settingsFile, { force: true });\n}\n\nasync function appendStderr(paths: HostDaemonPaths, message: string): Promise<string> {\n\ttry {\n\t\tconst stderr = (await readFile(paths.stderrLog, \"utf8\")).trim();\n\t\treturn stderr ? `${message}\\n${stderr}` : message;\n\t} catch (error: unknown) {\n\t\tif (isNodeErrorCode(error, \"ENOENT\")) return message;\n\t\tthrow error;\n\t}\n}\n\nfunction createSocketLockName(socket: string): string {\n\treturn createHash(\"sha256\").update(socket).digest(\"hex\").slice(0, 32);\n}\n\nfunction normalizeSocketPath(value: string): string {\n\tif (value.startsWith(\"unix://\")) return value.slice(\"unix://\".length);\n\treturn value;\n}\n\n/**\n * Default launch: the host-lifecycle supervisor owns the public socket and the\n * idle-exit policy; it spawns the committed RPC socket host itself. Any extra\n * hostArgs are forwarded verbatim to the host CLI (e.g. provider pinning).\n */\nfunction defaultHostLaunch(\n\tsocket: string,\n\thostArgs: readonly string[],\n): {\n\tcommand: string;\n\targs: string[];\n} {\n\treturn {\n\t\tcommand: process.execPath,\n\t\targs: [...process.execArgv, resolveHostLifecycleEntryPath(), \"--socket\", socket, ...hostArgs],\n\t};\n}\n\nfunction resolveHostLifecycleEntryPath(): string {\n\tconst modulePath = fileURLToPath(import.meta.url);\n\tconst extension = modulePath.endsWith(\".ts\") ? \".ts\" : \".js\";\n\treturn resolve(dirname(modulePath), `host-lifecycle${extension}`);\n}\n\nfunction delay(ms: number): Promise<void> {\n\treturn new Promise((resolveDelay) => setTimeout(resolveDelay, ms));\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 isNodeErrorCode(error: unknown, code: string): boolean {\n\treturn error instanceof Error && \"code\" in error && error.code === code;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"host-ensure.js","sourceRoot":"","sources":["../../../src/modes/rpc/host-ensure.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { mkdir, open, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { createConnection } from \"node:net\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { ENV_AGENT_DIR, getAgentDir, isBunBinary, VERSION } from \"../../config.ts\";\nimport {\n\ttype DaemonPidFile,\n\tparseDaemonPidFile,\n\tprocessMatchesPidFile,\n\twaitForStartTime,\n} from \"../app-server/daemon/process.ts\";\nimport {\n\tCUSTOM_UNSUPPORTED_CAPABILITY,\n\tEXTENSION_EVENTS_CAPABILITY,\n\tRPC_CLIENT_CAPABILITIES_ENV,\n} from \"./custom-capability.ts\";\nimport {\n\tDEFAULT_HOST_IDLE_EXIT_MS,\n\ttype HostColdStart,\n\ttype HostLifecyclePolicyInput,\n\tINTERNAL_SUPERVISOR_FLAG,\n} from \"./host-lifecycle.ts\";\nimport { acquireOwnershipSafeLock } from \"./ownership-safe-lock.ts\";\n\nexport type { HostColdStart, HostLifecyclePolicyInput };\n\nexport interface HostDaemonPaths {\n\treadonly dir: string;\n\treadonly pidFile: string;\n\treadonly lockFile: string;\n\treadonly settingsFile: string;\n\treadonly stderrLog: string;\n}\n\nexport interface EnsureHostOptions {\n\treadonly socket: string;\n\treadonly agentDir?: string;\n\t/** Host lifecycle policy recorded in settings.json (env overrides win at runtime). */\n\treadonly policy?: HostLifecyclePolicyInput;\n\treadonly _test?: {\n\t\treadonly readinessTimeoutMs?: number;\n\t\treadonly stopTimeoutMs?: number;\n\t\treadonly spawn?: { readonly command: string; readonly args: readonly string[] };\n\t\t/** Extra env merged over process.env for the spawned host (hermetic test/QA wiring). */\n\t\treadonly env?: Readonly<Record<string, string>>;\n\t\t/** Extra CLI args forwarded through the supervisor to the host process. */\n\t\treadonly hostArgs?: readonly string[];\n\t\t/** Runs after endpoint ownership is locked; deterministic concurrency-test gate. */\n\t\treadonly afterLockAcquired?: () => Promise<void>;\n\t};\n}\n\nexport interface EnsuredHost {\n\treadonly pid: number;\n\treadonly socket: string;\n\treadonly reused: boolean;\n}\n\ntype ProtocolInfo = {\n\treadonly serverVersion: string;\n\treadonly capabilities: readonly string[];\n};\n\nconst lockOptions = { retries: { retries: 100, minTimeout: 20, maxTimeout: 100 } } as const;\nconst REQUIRED_CAPABILITIES = [\"multi_session\", EXTENSION_EVENTS_CAPABILITY] as const;\n/**\n * Every ensured host starts with this installation-wide profile, independent of\n * the first caller. In particular, extension_events must remain available when\n * a terminal client starts the shared host before the desktop connects.\n */\nexport const PINNED_HOST_CLIENT_CAPABILITIES = [EXTENSION_EVENTS_CAPABILITY, CUSTOM_UNSUPPORTED_CAPABILITY] as const;\n\nexport function createHostDaemonPaths(agentDir = getAgentDir()): HostDaemonPaths {\n\tconst dir = join(agentDir, \"rpc-host-daemon\");\n\treturn {\n\t\tdir,\n\t\tpidFile: join(dir, \"host.pid\"),\n\t\tlockFile: join(dir, \"daemon.lock\"),\n\t\tsettingsFile: join(dir, \"settings.json\"),\n\t\tstderrLog: join(dir, \"stderr.log\"),\n\t};\n}\n\nexport async function ensureHost(options: EnsureHostOptions): Promise<EnsuredHost> {\n\tconst socket = normalizeSocketPath(options.socket);\n\tconst paths = createHostDaemonPaths(options.agentDir);\n\tawait mkdir(paths.dir, { recursive: true });\n\t// The public socket is the shared resource; agent directories are not a\n\t// sufficient lock scope when two installations target the same endpoint.\n\tconst lockTarget = join(tmpdir(), \"senpi-rpc-host-locks\", createSocketLockName(socket));\n\tawait mkdir(dirname(lockTarget), { recursive: true });\n\tawait writeFile(lockTarget, \"\", { flag: \"a\", mode: 0o600 });\n\tconst release = await acquireOwnershipSafeLock(`${lockTarget}.lock`, lockOptions);\n\ttry {\n\t\tawait options._test?.afterLockAcquired?.();\n\t\treturn await ensureHostLocked(paths, socket, options.agentDir ?? getAgentDir(), options.policy, options._test);\n\t} finally {\n\t\tawait release();\n\t}\n}\n\nasync function ensureHostLocked(\n\tpaths: HostDaemonPaths,\n\tsocket: string,\n\tagentDir: string,\n\tpolicy: HostLifecyclePolicyInput | undefined,\n\ttestOptions: EnsureHostOptions[\"_test\"],\n): Promise<EnsuredHost> {\n\tconst pidFile = await readPidFile(paths);\n\tconst protocol = await probeProtocolInfo(socket, 1_000);\n\tconst pidMatches = pidFile ? await processMatchesPidFile(pidFile) : false;\n\tif (isCompatible(protocol)) {\n\t\t// A compatible socket is attachable even when another client surface\n\t\t// started it. Only hosts we spawned are eligible for lifecycle management.\n\t\treturn { pid: pidFile?.pid ?? 0, socket, reused: true };\n\t}\n\tif (protocol && !pidMatches) {\n\t\tthrow new Error(`RPC socket ${socket} is owned by an unmanaged host`);\n\t}\n\tif (pidFile && pidMatches) {\n\t\tawait stopManagedHost(pidFile, testOptions?.stopTimeoutMs ?? 10_000);\n\t}\n\tawait cleanupState(paths);\n\treturn startHost(paths, socket, agentDir, policy, testOptions);\n}\n\nasync function startHost(\n\tpaths: HostDaemonPaths,\n\tsocket: string,\n\tagentDir: string,\n\tpolicy: HostLifecyclePolicyInput | undefined,\n\ttestOptions: EnsureHostOptions[\"_test\"],\n): Promise<EnsuredHost> {\n\t// The settings file must exist before the supervisor reads it at boot, so it\n\t// records the policy before the spawn instead of beside the pidfile.\n\tawait writeFile(\n\t\tpaths.settingsFile,\n\t\t`${JSON.stringify({\n\t\t\tsocket,\n\t\t\tcapabilities: PINNED_HOST_CLIENT_CAPABILITIES,\n\t\t\tcoldStart: policy?.coldStart ?? \"transient\",\n\t\t\tidleExitMs: policy?.idleExitMs ?? DEFAULT_HOST_IDLE_EXIT_MS,\n\t\t})}\\n`,\n\t\t{ mode: 0o600 },\n\t);\n\tconst stderr = await open(paths.stderrLog, \"w\", 0o600);\n\tlet pidFile: DaemonPidFile | undefined;\n\tlet child: ReturnType<typeof spawn> | undefined;\n\tlet exitedEarly: ChildExit | undefined;\n\tlet childExit: Promise<ChildExit> | undefined;\n\ttry {\n\t\tconst launch = testOptions?.spawn ?? defaultHostLaunch(socket, testOptions?.hostArgs ?? []);\n\t\tchild = spawn(launch.command, [...launch.args], {\n\t\t\tdetached: true,\n\t\t\tenv: {\n\t\t\t\t...process.env,\n\t\t\t\t...(testOptions?.env ?? {}),\n\t\t\t\t[ENV_AGENT_DIR]: agentDir,\n\t\t\t\t[RPC_CLIENT_CAPABILITIES_ENV]: PINNED_HOST_CLIENT_CAPABILITIES.join(\",\"),\n\t\t\t},\n\t\t\tstdio: [\"ignore\", \"ignore\", stderr.fd],\n\t\t});\n\t\tchildExit = new Promise((resolveExit) => {\n\t\t\tchild!.once(\"exit\", (code, signal) => {\n\t\t\t\texitedEarly = { code, signal };\n\t\t\t\tresolveExit(exitedEarly);\n\t\t\t});\n\t\t});\n\t\tchild.unref();\n\t\tif (child.pid === undefined) throw new Error(\"failed to spawn RPC socket host\");\n\t\tconst processStartTime = await Promise.race([\n\t\t\twaitForStartTime(child.pid, 2_000),\n\t\t\tchildExit.then(() => {\n\t\t\t\tthrow new Error(\"RPC socket host exited before its start time could be read\");\n\t\t\t}),\n\t\t]);\n\t\tpidFile = { pid: child.pid, processStartTime };\n\t\tawait writeFile(paths.pidFile, `${JSON.stringify(pidFile)}\\n`, { mode: 0o600 });\n\t} catch (error: unknown) {\n\t\tif (!exitedEarly) throw error;\n\t\tconst diagnostic = await appendStderr(\n\t\t\tpaths,\n\t\t\t`RPC socket host exited with code ${exitedEarly.code ?? \"null\"}${exitedEarly.signal ? ` (${exitedEarly.signal})` : \"\"} before answering get_protocol_info`,\n\t\t);\n\t\tawait cleanupState(paths);\n\t\tthrow new Error(diagnostic);\n\t} finally {\n\t\tawait stderr.close();\n\t}\n\tconst readinessTimeoutMs = testOptions?.readinessTimeoutMs ?? 10_000;\n\tconst result = await pollProtocolInfo(socket, readinessTimeoutMs, childExit);\n\tif (isCompatible(result.protocol)) return { pid: pidFile.pid, socket, reused: false };\n\tawait stopManagedHost(pidFile, testOptions?.stopTimeoutMs ?? 10_000);\n\tconst message = result.protocol\n\t\t? `RPC socket host answered get_protocol_info with serverVersion ${result.protocol.serverVersion} and capabilities ${JSON.stringify(result.protocol.capabilities)}, but is incompatible with serverVersion ${VERSION} and required capabilities ${JSON.stringify(REQUIRED_CAPABILITIES)}`\n\t\t: result.exited\n\t\t\t? `RPC socket host exited with code ${result.exited.code ?? \"null\"}${result.exited.signal ? ` (${result.exited.signal})` : \"\"} before answering get_protocol_info`\n\t\t\t: `spawned RPC socket host did not answer get_protocol_info within ${readinessTimeoutMs}ms`;\n\tconst diagnostic = await appendStderr(paths, message);\n\tawait cleanupState(paths);\n\t// The supervisor may have failed before binding, or another owner may have\n\t// appeared while readiness was being checked. Never unlink an endpoint we\n\t// cannot prove this start owned.\n\tthrow new Error(diagnostic);\n}\n\nasync function stopManagedHost(pidFile: DaemonPidFile, termTimeoutMs: number): Promise<void> {\n\tawait signalValidated(pidFile, \"SIGTERM\");\n\tif (await waitForGone(pidFile, termTimeoutMs)) return;\n\tawait signalValidated(pidFile, \"SIGKILL\");\n\tif (!(await waitForGone(pidFile, 2_000))) {\n\t\tthrow new Error(`RPC socket host pid ${pidFile.pid} remained alive after SIGKILL`);\n\t}\n}\n\nasync function signalValidated(pidFile: DaemonPidFile, signal: NodeJS.Signals): Promise<void> {\n\tif (!(await processMatchesPidFile(pidFile))) return;\n\ttry {\n\t\tprocess.kill(pidFile.pid, signal);\n\t} catch (error: unknown) {\n\t\tif (!isNodeErrorCode(error, \"ESRCH\")) throw error;\n\t}\n}\n\nasync function waitForGone(pidFile: DaemonPidFile, timeoutMs: number): Promise<boolean> {\n\tconst deadline = Date.now() + timeoutMs;\n\twhile (Date.now() <= deadline) {\n\t\tif (!(await processMatchesPidFile(pidFile))) return true;\n\t\tawait delay(50);\n\t}\n\treturn false;\n}\n\ntype ChildExit = { readonly code: number | null; readonly signal: NodeJS.Signals | null };\n\ntype ProtocolPollResult = { readonly protocol?: ProtocolInfo; readonly exited?: ChildExit };\n\nasync function pollProtocolInfo(\n\tsocket: string,\n\ttimeoutMs: number,\n\tchildExit?: Promise<ChildExit>,\n): Promise<ProtocolPollResult> {\n\tconst deadline = Date.now() + timeoutMs;\n\tlet lastProtocol: ProtocolInfo | undefined;\n\twhile (Date.now() <= deadline) {\n\t\tconst probe = probeProtocolInfo(socket, Math.min(500, Math.max(1, deadline - Date.now())));\n\t\tconst info = childExit ? await Promise.race([probe, childExit]) : await probe;\n\t\tif (isChildExit(info)) return { protocol: lastProtocol, exited: info };\n\t\tif (info) {\n\t\t\tlastProtocol = info;\n\t\t\tif (isCompatible(info)) return { protocol: info };\n\t\t}\n\t\tawait delay(50);\n\t}\n\treturn { protocol: lastProtocol };\n}\n\nfunction isChildExit(value: ProtocolInfo | ChildExit | undefined): value is ChildExit {\n\treturn !!value && \"code\" in value && \"signal\" in value;\n}\n\nfunction probeProtocolInfo(socketPath: string, timeoutMs: number): Promise<ProtocolInfo | undefined> {\n\treturn new Promise((resolveProbe) => {\n\t\tconst socket = createConnection(socketPath);\n\t\tlet buffer = \"\";\n\t\tlet settled = false;\n\t\tconst finish = (value?: ProtocolInfo): void => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tclearTimeout(timeout);\n\t\t\tsocket.destroy();\n\t\t\tresolveProbe(value);\n\t\t};\n\t\tconst timeout = setTimeout(() => finish(), timeoutMs);\n\t\tsocket.once(\"connect\", () => {\n\t\t\tsocket.write('{\"id\":\"ensure-host-probe\",\"type\":\"get_protocol_info\"}\\n');\n\t\t});\n\t\tsocket.on(\"data\", (chunk) => {\n\t\t\tbuffer += chunk.toString(\"utf8\");\n\t\t\tconst newline = buffer.indexOf(\"\\n\");\n\t\t\tif (newline === -1) return;\n\t\t\tfinish(readProtocolInfo(buffer.slice(0, newline)));\n\t\t});\n\t\tsocket.once(\"error\", () => finish());\n\t\tsocket.once(\"close\", () => finish());\n\t});\n}\n\nfunction readProtocolInfo(text: string): ProtocolInfo | undefined {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(text);\n\t} catch {\n\t\treturn undefined;\n\t}\n\tif (!isRecord(parsed) || parsed.id !== \"ensure-host-probe\" || parsed.success !== true || !isRecord(parsed.data)) {\n\t\treturn undefined;\n\t}\n\tconst { serverVersion, capabilities } = parsed.data;\n\tif (typeof serverVersion !== \"string\" || !Array.isArray(capabilities)) return undefined;\n\tif (!capabilities.every((capability) => typeof capability === \"string\")) return undefined;\n\treturn { serverVersion, capabilities };\n}\n\nfunction isCompatible(protocol: ProtocolInfo | undefined): boolean {\n\treturn (\n\t\tprotocol?.serverVersion === VERSION &&\n\t\tREQUIRED_CAPABILITIES.every((capability) => protocol.capabilities.includes(capability))\n\t);\n}\n\nasync function readPidFile(paths: HostDaemonPaths): Promise<DaemonPidFile | undefined> {\n\ttry {\n\t\treturn parseDaemonPidFile(await readFile(paths.pidFile, \"utf8\"));\n\t} catch (error: unknown) {\n\t\tif (isNodeErrorCode(error, \"ENOENT\")) return undefined;\n\t\tthrow error;\n\t}\n}\n\nasync function cleanupState(paths: HostDaemonPaths): Promise<void> {\n\tawait rm(paths.pidFile, { force: true });\n\tawait rm(paths.settingsFile, { force: true });\n}\n\nasync function appendStderr(paths: HostDaemonPaths, message: string): Promise<string> {\n\ttry {\n\t\tconst stderr = (await readFile(paths.stderrLog, \"utf8\")).trim();\n\t\treturn stderr ? `${message}\\n${stderr}` : message;\n\t} catch (error: unknown) {\n\t\tif (isNodeErrorCode(error, \"ENOENT\")) return message;\n\t\tthrow error;\n\t}\n}\n\nfunction createSocketLockName(socket: string): string {\n\treturn createHash(\"sha256\").update(socket).digest(\"hex\").slice(0, 32);\n}\n\nfunction normalizeSocketPath(value: string): string {\n\tif (value.startsWith(\"unix://\")) return value.slice(\"unix://\".length);\n\treturn value;\n}\n\n/**\n * Default launch: the host-lifecycle supervisor owns the public socket and the\n * idle-exit policy; it spawns the committed RPC socket host itself. Any extra\n * hostArgs are forwarded verbatim to the host CLI (e.g. provider pinning).\n *\n * A compiled standalone binary cannot re-enter itself through a script path:\n * bun executables always boot their embedded entrypoint and parse the whole\n * argv as CLI arguments, so `host-lifecycle.ts --socket <path>` dies with\n * \"Unknown option: --socket\" before the host ever answers get_protocol_info.\n * Compiled binaries therefore re-enter through the hidden\n * `--internal-rpc-host-supervisor` route that main() dispatches before\n * argument parsing. Exported for tests.\n */\nexport function defaultHostLaunch(\n\tsocket: string,\n\thostArgs: readonly string[],\n\tcompiled: boolean = isBunBinary,\n): {\n\tcommand: string;\n\targs: string[];\n} {\n\tif (compiled) {\n\t\treturn {\n\t\t\tcommand: process.execPath,\n\t\t\targs: [INTERNAL_SUPERVISOR_FLAG, \"--socket\", socket, ...hostArgs],\n\t\t};\n\t}\n\treturn {\n\t\tcommand: process.execPath,\n\t\targs: [...process.execArgv, resolveHostLifecycleEntryPath(), \"--socket\", socket, ...hostArgs],\n\t};\n}\n\nfunction resolveHostLifecycleEntryPath(): string {\n\tconst modulePath = fileURLToPath(import.meta.url);\n\tconst extension = modulePath.endsWith(\".ts\") ? \".ts\" : \".js\";\n\treturn resolve(dirname(modulePath), `host-lifecycle${extension}`);\n}\n\nfunction delay(ms: number): Promise<void> {\n\treturn new Promise((resolveDelay) => setTimeout(resolveDelay, ms));\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 isNodeErrorCode(error: unknown, code: string): boolean {\n\treturn error instanceof Error && \"code\" in error && error.code === code;\n}\n"]}
|
|
@@ -27,6 +27,16 @@ export interface HostActivity {
|
|
|
27
27
|
readonly connections: number;
|
|
28
28
|
readonly activeTurns: number;
|
|
29
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* How the supervisor reads its child's exit. The RPC host exits 0 only through
|
|
32
|
+
* its own clean shutdown path - including its idle/empty-host policy - so that
|
|
33
|
+
* is an intentional stop, not a crash: the supervisor mirrors its own idle exit
|
|
34
|
+
* instead of reporting failure. Any non-zero code or signal stays a crash.
|
|
35
|
+
*/
|
|
36
|
+
export declare function classifyChildExit(code: number | null, signal: NodeJS.Signals | null): {
|
|
37
|
+
reason: string;
|
|
38
|
+
exitCode: number;
|
|
39
|
+
};
|
|
30
40
|
export type IdleExitDecision = "active" | "idle" | "exit";
|
|
31
41
|
/**
|
|
32
42
|
* Pure idle-window decision core. `update()` must be called with the CURRENT
|
|
@@ -49,9 +59,38 @@ export interface SupervisorLaunch {
|
|
|
49
59
|
/** Explicit ownership directory for callers whose environment is not yet branded. */
|
|
50
60
|
readonly agentDir?: string;
|
|
51
61
|
}
|
|
62
|
+
/** Hidden internal launch route: wire-invisible, never advertised by the public CLI surface. */
|
|
63
|
+
export declare const INTERNAL_SUPERVISOR_FLAG = "--internal-rpc-host-supervisor";
|
|
64
|
+
/**
|
|
65
|
+
* Returns the internal supervisor payload when argv selects that route.
|
|
66
|
+
*
|
|
67
|
+
* The route dispatches when the sentinel is argv[0] OR is preceded only by
|
|
68
|
+
* known injectable prefix flags and their values - the one perturbation
|
|
69
|
+
* wrappers legitimately perform. Everything else disqualifies it: a positional
|
|
70
|
+
* operand, `--`, or an unknown flag before the sentinel all return undefined,
|
|
71
|
+
* so a user-supplied value that happens to equal the sentinel can never reach
|
|
72
|
+
* the supervisor.
|
|
73
|
+
*
|
|
74
|
+
* The skipped prefix is deliberately NOT forwarded to the host: a wrapper
|
|
75
|
+
* re-injects its own prefix on every re-entry, so the host child receives it
|
|
76
|
+
* from the wrapper rather than twice from here.
|
|
77
|
+
*/
|
|
78
|
+
export declare function findInternalSupervisorArgs(argv: readonly string[]): readonly string[] | undefined;
|
|
52
79
|
/** `--socket <path>` selects the public socket; every other argument is forwarded to the host CLI. */
|
|
53
80
|
export declare function parseSupervisorArgs(argv: readonly string[]): SupervisorLaunch | undefined;
|
|
54
81
|
/** Resolves the committed CLI entry this supervisor wraps (source tree or built dist). */
|
|
55
82
|
export declare function resolveCliMainPath(): string;
|
|
83
|
+
/**
|
|
84
|
+
* Resolves the host child spawn. Explicit child commands (desktop launchers)
|
|
85
|
+
* are forwarded untouched. The default re-enters the committed CLI entry
|
|
86
|
+
* through the runtime, except in compiled standalone binaries, which always
|
|
87
|
+
* boot their embedded entrypoint and would parse a script path as CLI
|
|
88
|
+
* arguments - there the executable itself is the CLI, so the mode flags are
|
|
89
|
+
* passed directly. Exported for tests.
|
|
90
|
+
*/
|
|
91
|
+
export declare function resolveHostChildLaunch(launch: SupervisorLaunch, internalSocket: string, compiled?: boolean): {
|
|
92
|
+
command: string;
|
|
93
|
+
args: string[];
|
|
94
|
+
};
|
|
56
95
|
export declare function runHostSupervisor(launch: SupervisorLaunch): Promise<void>;
|
|
57
96
|
//# sourceMappingURL=host-lifecycle.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host-lifecycle.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/host-lifecycle.ts"],"names":[],"mappings":";AAyDA,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;AAErD,+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;AAuBD,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;gBAEhB,UAAU,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,MAAiB;IAK5D,MAAM,CAAC,QAAQ,EAAE,YAAY,GAAG,gBAAgB;CAchD;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;CAC3B;AAED,sGAAsG;AACtG,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,gBAAgB,GAAG,SAAS,CAgCzF;AAED,0FAA0F;AAC1F,wBAAgB,kBAAkB,IAAI,MAAM,CAI3C;AAED,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"host-lifecycle.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/host-lifecycle.ts"],"names":[],"mappings":"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"}
|
|
@@ -45,7 +45,7 @@ import { createConnection, createServer } from "node:net";
|
|
|
45
45
|
import { tmpdir } from "node:os";
|
|
46
46
|
import { dirname, 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
49
|
import { createHostDaemonPaths } from "./host-ensure.js";
|
|
50
50
|
import { HOST_CLEANUP_PATHS_ENV, HOST_SCRATCH_DIR_ENV, HOST_WATCH_FD_ENV, HOST_WATCH_PPID_ENV, } from "./host-watchdog.js";
|
|
51
51
|
import { attachJsonlLineReader, MAX_RPC_LINE_CHARACTERS } from "./jsonl.js";
|
|
@@ -95,6 +95,17 @@ export function resolveHostPolicy(settings, env) {
|
|
|
95
95
|
DEFAULT_HOST_IDLE_EXIT_MS;
|
|
96
96
|
return { coldStart, idleExitMs };
|
|
97
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* How the supervisor reads its child's exit. The RPC host exits 0 only through
|
|
100
|
+
* its own clean shutdown path - including its idle/empty-host policy - so that
|
|
101
|
+
* is an intentional stop, not a crash: the supervisor mirrors its own idle exit
|
|
102
|
+
* instead of reporting failure. Any non-zero code or signal stays a crash.
|
|
103
|
+
*/
|
|
104
|
+
export function classifyChildExit(code, signal) {
|
|
105
|
+
if (code === 0 && signal === null)
|
|
106
|
+
return { reason: "rpc host exited on its own idle policy", exitCode: 0 };
|
|
107
|
+
return { reason: `rpc host process exited unexpectedly (${code ?? signal})`, exitCode: 1 };
|
|
108
|
+
}
|
|
98
109
|
/**
|
|
99
110
|
* Pure idle-window decision core. `update()` must be called with the CURRENT
|
|
100
111
|
* activity state; the window only counts continuously idle time and any
|
|
@@ -121,6 +132,40 @@ export class IdleExitDecider {
|
|
|
121
132
|
return this.now() - this.idleSince >= this.idleExitMs ? "exit" : "idle";
|
|
122
133
|
}
|
|
123
134
|
}
|
|
135
|
+
/** Hidden internal launch route: wire-invisible, never advertised by the public CLI surface. */
|
|
136
|
+
export const INTERNAL_SUPERVISOR_FLAG = "--internal-rpc-host-supervisor";
|
|
137
|
+
/**
|
|
138
|
+
* Engine-global flags a rebranded wrapper may legitimately prepend when it
|
|
139
|
+
* re-dispatches this binary. `packages/omo-native` injects `--extension <dir>`
|
|
140
|
+
* for every non-early command, which pushed the sentinel off argv[0].
|
|
141
|
+
*/
|
|
142
|
+
const INJECTABLE_PREFIX_FLAGS = new Set(["--extension"]);
|
|
143
|
+
/**
|
|
144
|
+
* Returns the internal supervisor payload when argv selects that route.
|
|
145
|
+
*
|
|
146
|
+
* The route dispatches when the sentinel is argv[0] OR is preceded only by
|
|
147
|
+
* known injectable prefix flags and their values - the one perturbation
|
|
148
|
+
* wrappers legitimately perform. Everything else disqualifies it: a positional
|
|
149
|
+
* operand, `--`, or an unknown flag before the sentinel all return undefined,
|
|
150
|
+
* so a user-supplied value that happens to equal the sentinel can never reach
|
|
151
|
+
* the supervisor.
|
|
152
|
+
*
|
|
153
|
+
* The skipped prefix is deliberately NOT forwarded to the host: a wrapper
|
|
154
|
+
* re-injects its own prefix on every re-entry, so the host child receives it
|
|
155
|
+
* from the wrapper rather than twice from here.
|
|
156
|
+
*/
|
|
157
|
+
export function findInternalSupervisorArgs(argv) {
|
|
158
|
+
for (let index = 0; index < argv.length; index++) {
|
|
159
|
+
const arg = argv[index];
|
|
160
|
+
if (arg === INTERNAL_SUPERVISOR_FLAG)
|
|
161
|
+
return argv.slice(index + 1);
|
|
162
|
+
// A prefix flag only counts when its value is actually present.
|
|
163
|
+
if (!INJECTABLE_PREFIX_FLAGS.has(arg) || index + 1 >= argv.length)
|
|
164
|
+
return undefined;
|
|
165
|
+
index++;
|
|
166
|
+
}
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
124
169
|
/** `--socket <path>` selects the public socket; every other argument is forwarded to the host CLI. */
|
|
125
170
|
export function parseSupervisorArgs(argv) {
|
|
126
171
|
const hostArgs = [];
|
|
@@ -163,6 +208,34 @@ export function resolveCliMainPath() {
|
|
|
163
208
|
const extension = modulePath.endsWith(".ts") ? ".ts" : ".js";
|
|
164
209
|
return resolve(dirname(modulePath), "..", "..", `cli-main${extension}`);
|
|
165
210
|
}
|
|
211
|
+
/**
|
|
212
|
+
* Resolves the host child spawn. Explicit child commands (desktop launchers)
|
|
213
|
+
* are forwarded untouched. The default re-enters the committed CLI entry
|
|
214
|
+
* through the runtime, except in compiled standalone binaries, which always
|
|
215
|
+
* boot their embedded entrypoint and would parse a script path as CLI
|
|
216
|
+
* arguments - there the executable itself is the CLI, so the mode flags are
|
|
217
|
+
* passed directly. Exported for tests.
|
|
218
|
+
*/
|
|
219
|
+
export function resolveHostChildLaunch(launch, internalSocket, compiled = isBunBinary) {
|
|
220
|
+
if (launch.childCommand) {
|
|
221
|
+
return {
|
|
222
|
+
command: launch.childCommand,
|
|
223
|
+
args: [...(launch.childArgs ?? []), "--listen", `unix://${internalSocket}`],
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
return {
|
|
227
|
+
command: process.execPath,
|
|
228
|
+
args: [
|
|
229
|
+
...(compiled ? [] : [...process.execArgv, resolveCliMainPath()]),
|
|
230
|
+
"--mode",
|
|
231
|
+
"rpc",
|
|
232
|
+
"--multi-session",
|
|
233
|
+
"--listen",
|
|
234
|
+
`unix://${internalSocket}`,
|
|
235
|
+
...launch.hostArgs,
|
|
236
|
+
],
|
|
237
|
+
};
|
|
238
|
+
}
|
|
166
239
|
export async function runHostSupervisor(launch) {
|
|
167
240
|
const paths = createHostDaemonPaths(launch.agentDir ?? getAgentDir());
|
|
168
241
|
const policy = resolveHostPolicy(await readSettingsFile(paths.settingsFile), process.env);
|
|
@@ -175,18 +248,8 @@ export async function runHostSupervisor(launch) {
|
|
|
175
248
|
let observerReconnectTimer;
|
|
176
249
|
let shuttingDown = false;
|
|
177
250
|
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
|
-
], {
|
|
251
|
+
const childLaunch = resolveHostChildLaunch(launch, internalSocket);
|
|
252
|
+
const child = spawn(childLaunch.command, childLaunch.args, {
|
|
190
253
|
env: {
|
|
191
254
|
...process.env,
|
|
192
255
|
...(launch.agentDir ? { SENPI_CODING_AGENT_DIR: launch.agentDir } : {}),
|
|
@@ -203,8 +266,10 @@ export async function runHostSupervisor(launch) {
|
|
|
203
266
|
// death notification. Errors on it must not crash the supervisor.
|
|
204
267
|
child.stdio[CHILD_WATCH_FD]?.on("error", () => { });
|
|
205
268
|
child.once("exit", (code, signal) => {
|
|
206
|
-
if (
|
|
207
|
-
|
|
269
|
+
if (shuttingDown)
|
|
270
|
+
return;
|
|
271
|
+
const { reason, exitCode } = classifyChildExit(code, signal);
|
|
272
|
+
void shutdown(reason, exitCode);
|
|
208
273
|
});
|
|
209
274
|
const server = createServer((client) => {
|
|
210
275
|
if (shuttingDown) {
|