@code-yeongyu/senpi 2026.8.28 → 2026.8.30-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 +196 -0
- package/dist/cli/args.d.ts +2 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +4 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +2 -0
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +50 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +330 -29
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +1 -0
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +3 -0
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +155 -37
- package/dist/core/bash-executor.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/credential-accounts.d.ts.map +1 -1
- package/dist/core/credential-accounts.js +45 -21
- package/dist/core/credential-accounts.js.map +1 -1
- package/dist/core/credential-pool/classify.d.ts +6 -1
- package/dist/core/credential-pool/classify.d.ts.map +1 -1
- package/dist/core/credential-pool/classify.js +22 -5
- package/dist/core/credential-pool/classify.js.map +1 -1
- package/dist/core/credential-pool/env-slots.d.ts.map +1 -1
- package/dist/core/credential-pool/env-slots.js +2 -0
- package/dist/core/credential-pool/env-slots.js.map +1 -1
- package/dist/core/credential-pool/failover.d.ts +8 -0
- package/dist/core/credential-pool/failover.d.ts.map +1 -1
- package/dist/core/credential-pool/failover.js +24 -6
- package/dist/core/credential-pool/failover.js.map +1 -1
- package/dist/core/credential-pool/rotation-stream.d.ts +13 -2
- package/dist/core/credential-pool/rotation-stream.d.ts.map +1 -1
- package/dist/core/credential-pool/rotation-stream.js +97 -10
- package/dist/core/credential-pool/rotation-stream.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/context-pipeline.d.ts +17 -0
- package/dist/core/extensions/builtin/compaction/context-pipeline.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/context-pipeline.js +28 -0
- package/dist/core/extensions/builtin/compaction/context-pipeline.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.d.ts +8 -2
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.js +163 -48
- 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.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 +121 -147
- 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/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 +56 -0
- package/dist/core/extensions/builtin/compaction/orchestration.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/orchestration.js +136 -0
- package/dist/core/extensions/builtin/compaction/orchestration.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/policy.d.ts +5 -2
- package/dist/core/extensions/builtin/compaction/policy.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/policy.js +43 -26
- package/dist/core/extensions/builtin/compaction/policy.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/retained-message-safety.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/retained-message-safety.js +31 -8
- package/dist/core/extensions/builtin/compaction/retained-message-safety.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 +22 -0
- package/dist/core/extensions/builtin/compaction/speculative-summary.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/speculative-summary.js +131 -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 +7 -196
- package/dist/core/extensions/builtin/compaction/speculative.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/token-budget-reminder.d.ts +18 -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 +18 -0
- package/dist/core/extensions/builtin/compaction/token-budget-reminder.js.map +1 -0
- package/dist/core/extensions/builtin/compaction/tool-admission.d.ts +36 -0
- package/dist/core/extensions/builtin/compaction/tool-admission.d.ts.map +1 -0
- package/dist/core/extensions/builtin/compaction/tool-admission.js +92 -0
- package/dist/core/extensions/builtin/compaction/tool-admission.js.map +1 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/stream.d.ts.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/stream.js +8 -28
- package/dist/core/extensions/builtin/cursor-cli-oauth/stream.js.map +1 -1
- package/dist/core/extensions/builtin/goal/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/goal/index.js +7 -0
- package/dist/core/extensions/builtin/goal/index.js.map +1 -1
- package/dist/core/extensions/builtin/permission-system/external-dir.d.ts.map +1 -1
- package/dist/core/extensions/builtin/permission-system/external-dir.js +15 -5
- package/dist/core/extensions/builtin/permission-system/external-dir.js.map +1 -1
- package/dist/core/extensions/builtin/permission-system/parsers.d.ts.map +1 -1
- package/dist/core/extensions/builtin/permission-system/parsers.js +16 -1
- package/dist/core/extensions/builtin/permission-system/parsers.js.map +1 -1
- package/dist/core/extensions/builtin/service-tier.d.ts.map +1 -1
- package/dist/core/extensions/builtin/service-tier.js +13 -0
- package/dist/core/extensions/builtin/service-tier.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/extension.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/extension.js +4 -2
- package/dist/core/extensions/builtin/terminal/extension.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/manager.d.ts +5 -0
- package/dist/core/extensions/builtin/terminal/manager.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/manager.js +31 -3
- package/dist/core/extensions/builtin/terminal/manager.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/monitor-permission.d.ts +8 -0
- package/dist/core/extensions/builtin/terminal/monitor-permission.d.ts.map +1 -0
- package/dist/core/extensions/builtin/terminal/monitor-permission.js +16 -0
- package/dist/core/extensions/builtin/terminal/monitor-permission.js.map +1 -0
- package/dist/core/extensions/builtin/terminal/monitor-registry.d.ts +13 -0
- package/dist/core/extensions/builtin/terminal/monitor-registry.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/monitor-registry.js +403 -3
- package/dist/core/extensions/builtin/terminal/monitor-registry.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/session-bundle.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/session-bundle.js +1 -0
- package/dist/core/extensions/builtin/terminal/session-bundle.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/tools/kill-bash.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/tools/kill-bash.js +5 -2
- package/dist/core/extensions/builtin/terminal/tools/kill-bash.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/tools/monitor.d.ts +4 -0
- package/dist/core/extensions/builtin/terminal/tools/monitor.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/tools/monitor.js +40 -2
- package/dist/core/extensions/builtin/terminal/tools/monitor.js.map +1 -1
- package/dist/core/model-config-schema.d.ts +4 -4
- package/dist/core/model-resolver.js +2 -2
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/model-runtime.d.ts +2 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +74 -37
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/retry-fallback/chains.d.ts +23 -1
- package/dist/core/retry-fallback/chains.d.ts.map +1 -1
- package/dist/core/retry-fallback/chains.js +59 -3
- package/dist/core/retry-fallback/chains.js.map +1 -1
- package/dist/core/retry-fallback/controller.d.ts.map +1 -1
- package/dist/core/retry-fallback/controller.js +9 -2
- package/dist/core/retry-fallback/controller.js.map +1 -1
- package/dist/core/retry-fallback/settings.d.ts.map +1 -1
- package/dist/core/retry-fallback/settings.js +9 -0
- package/dist/core/retry-fallback/settings.js.map +1 -1
- package/dist/core/retry-fallback/validate.js +1 -1
- package/dist/core/retry-fallback/validate.js.map +1 -1
- package/dist/core/sdk.js +1 -1
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +9 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +40 -0
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +15 -85
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +15 -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/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +97 -15
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/index.d.ts +1 -0
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +8 -0
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/output-accumulator.d.ts +1 -1
- package/dist/core/tools/output-accumulator.d.ts.map +1 -1
- package/dist/core/tools/output-accumulator.js +76 -34
- package/dist/core/tools/output-accumulator.js.map +1 -1
- package/dist/main.d.ts +7 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +27 -6
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/favorite-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/favorite-models-selector.js +2 -2
- package/dist/modes/interactive/components/favorite-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +7 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +34 -8
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/grok/chrome.d.ts +2 -0
- package/dist/modes/interactive/grok/chrome.d.ts.map +1 -1
- package/dist/modes/interactive/grok/chrome.js.map +1 -1
- package/dist/modes/interactive/interactive-host-runtime.d.ts +121 -1
- package/dist/modes/interactive/interactive-host-runtime.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-host-runtime.js +606 -45
- package/dist/modes/interactive/interactive-host-runtime.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +7 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +390 -239
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/connection-handler.d.ts +8 -1
- package/dist/modes/rpc/connection-handler.d.ts.map +1 -1
- package/dist/modes/rpc/connection-handler.js +268 -63
- package/dist/modes/rpc/connection-handler.js.map +1 -1
- package/dist/modes/rpc/host-ensure.d.ts +19 -0
- package/dist/modes/rpc/host-ensure.d.ts.map +1 -1
- package/dist/modes/rpc/host-ensure.js +79 -15
- package/dist/modes/rpc/host-ensure.js.map +1 -1
- package/dist/modes/rpc/host-lifecycle.d.ts +29 -0
- package/dist/modes/rpc/host-lifecycle.d.ts.map +1 -1
- package/dist/modes/rpc/host-lifecycle.js +96 -25
- package/dist/modes/rpc/host-lifecycle.js.map +1 -1
- package/dist/modes/rpc/host-watchdog.d.ts +2 -0
- package/dist/modes/rpc/host-watchdog.d.ts.map +1 -1
- package/dist/modes/rpc/host-watchdog.js +23 -12
- package/dist/modes/rpc/host-watchdog.js.map +1 -1
- package/dist/modes/rpc/multi-session-host.js +20 -8
- package/dist/modes/rpc/multi-session-host.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +91 -16
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +131 -37
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-input-validation.d.ts +1 -0
- package/dist/modes/rpc/rpc-input-validation.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-input-validation.js +66 -0
- package/dist/modes/rpc/rpc-input-validation.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts +3 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +3 -1
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +248 -3
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/modes/rpc/session-binding.d.ts +1 -0
- package/dist/modes/rpc/session-binding.d.ts.map +1 -1
- package/dist/modes/rpc/session-binding.js +21 -1
- package/dist/modes/rpc/session-binding.js.map +1 -1
- package/dist/modes/rpc/session-command-router.d.ts +22 -0
- package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
- package/dist/modes/rpc/session-command-router.js +148 -16
- package/dist/modes/rpc/session-command-router.js.map +1 -1
- package/dist/modes/rpc/session-event-writer.d.ts +4 -0
- package/dist/modes/rpc/session-event-writer.d.ts.map +1 -1
- package/dist/modes/rpc/session-event-writer.js +58 -7
- package/dist/modes/rpc/session-event-writer.js.map +1 -1
- package/dist/modes/rpc/session-extension-ui-requests.d.ts +1 -0
- package/dist/modes/rpc/session-extension-ui-requests.d.ts.map +1 -1
- package/dist/modes/rpc/session-extension-ui-requests.js +5 -0
- package/dist/modes/rpc/session-extension-ui-requests.js.map +1 -1
- package/dist/modes/rpc/session-registry.d.ts +17 -2
- package/dist/modes/rpc/session-registry.d.ts.map +1 -1
- package/dist/modes/rpc/session-registry.js +67 -4
- package/dist/modes/rpc/session-registry.js.map +1 -1
- package/dist/modes/rpc/socket-event-fanout.d.ts +22 -0
- package/dist/modes/rpc/socket-event-fanout.d.ts.map +1 -0
- package/dist/modes/rpc/socket-event-fanout.js +84 -0
- package/dist/modes/rpc/socket-event-fanout.js.map +1 -0
- package/docs/rpc.md +55 -2
- package/docs/settings.md +34 -0
- package/docs/windows.md +2 -0
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +74 -0
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-indirect-eval.js +139 -90
- package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt.ts +4 -4
- package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js +6 -3
- package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/env/nodejs.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/env/nodejs.js +40 -20
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/env/nodejs.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts +3 -3
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/shell-output.d.ts +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/shell-output.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/shell-output.js +28 -9
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/shell-output.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -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 +67 -38
- 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/measure.d.ts +20 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/measure.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/measure.js +443 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/measure.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.d.ts +2 -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 +2 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/index.js +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/index.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/baseten.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-ai-gateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-workers-ai.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/huggingface.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/opencode-go.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode.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/together.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/dist/providers/data/zai-coding-cn.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/zai.json +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts +7 -0
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +5 -0
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/mux.d.ts +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/mux.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/mux.js +2 -2
- package/node_modules/@earendil-works/pi-tui/dist/mux.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts +1 -0
- package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal.js +19 -0
- package/node_modules/@earendil-works/pi-tui/dist/terminal.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +7 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/manager.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,eAAe,EACf,4BAA4B,GAG5B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAA+B,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEnD,OAAO,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AAYtE;;;;;GAKG;AACH,MAAM,OAAO,eAAe;
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/manager.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tSessionRegistry,\n\tSessionRegistryCapacityError,\n\ttype TerminalSession,\n\ttype TerminalSessionOptions,\n} from \"@earendil-works/pi-pty\";\nimport { type TerminalRuntimeOptions, TerminalRuntimeSession } from \"./runtime-session.ts\";\nimport { DEFAULT_MAX_SESSIONS } from \"./shared.ts\";\n\nexport { SessionRegistryCapacityError } from \"@earendil-works/pi-pty\";\n\nexport interface TerminalManagerOptions {\n\treadonly maxSessions?: number;\n\treadonly scrollback?: number;\n}\n\nexport interface CreatedTerminalSession {\n\treadonly id: string;\n\treadonly runtime: TerminalRuntimeSession;\n}\n\n/**\n * Owns the live terminal sessions for one agent session. Delegates id allocation,\n * capacity caps, LRU-exited pruning, and tree-kill teardown to the pi-pty\n * {@link SessionRegistry}, while keeping the richer {@link TerminalRuntimeSession}\n * wrappers (screen model + output buffer) in lock-step.\n */\nexport class TerminalManager {\n\tprivate readonly registry: SessionRegistry<TerminalSession>;\n\tprivate readonly runtimes = new Map<string, TerminalRuntimeSession>();\n\tprivate readonly scrollback?: number;\n\tprivate readonly maxSessions: number;\n\tprivate readonly exited = new Set<string>();\n\tprivate reservations = 0;\n\n\tconstructor(options: TerminalManagerOptions = {}) {\n\t\tthis.maxSessions = options.maxSessions ?? DEFAULT_MAX_SESSIONS;\n\t\tthis.registry = new SessionRegistry<TerminalSession>({ maxSessions: this.maxSessions });\n\t\tthis.scrollback = options.scrollback;\n\t}\n\n\tget size(): number {\n\t\treturn this.runtimes.size;\n\t}\n\n\tget activeSize(): number {\n\t\tthis.reconcileRuntimes();\n\t\treturn this.runtimes.size - this.exited.size + this.reservations;\n\t}\n\n\treserve(): (() => void) | null {\n\t\tthis.reconcileRuntimes();\n\t\tif (this.runtimes.size - this.exited.size + this.reservations >= this.maxSessions) return null;\n\t\tthis.reservations += 1;\n\t\tlet released = false;\n\t\treturn () => {\n\t\t\tif (released) return;\n\t\t\treleased = true;\n\t\t\tthis.reservations -= 1;\n\t\t};\n\t}\n\n\t/** Spawn a new terminal session and register it under an allocated `bash_N` id. */\n\tasync create(command: string, options: TerminalSessionOptions): Promise<CreatedTerminalSession> {\n\t\tconst release = this.reserve();\n\t\tif (!release) throw new SessionRegistryCapacityError(this.maxSessions);\n\t\tconst runtimeOptions: TerminalRuntimeOptions = { ...options, scrollback: this.scrollback };\n\t\tconst runtime = new TerminalRuntimeSession(command, runtimeOptions);\n\t\tlet entry: { id: string };\n\t\ttry {\n\t\t\tentry = await this.registry.create({ command, session: runtime.session });\n\t\t} catch (error) {\n\t\t\trelease();\n\t\t\truntime.dispose();\n\t\t\truntime.session.kill();\n\t\t\tthrow error;\n\t\t}\n\t\tthis.runtimes.set(entry.id, runtime);\n\t\truntime.session.onExit(() => {\n\t\t\tthis.exited.add(entry.id);\n\t\t});\n\t\trelease();\n\t\tthis.reconcileRuntimes();\n\t\treturn { id: entry.id, runtime };\n\t}\n\n\t/** Look up a live-or-exited session, refreshing its LRU timestamp. */\n\tget(id: string): TerminalRuntimeSession | null {\n\t\tconst entry = this.registry.get(id);\n\t\tif (!entry) return null;\n\t\treturn this.runtimes.get(id) ?? null;\n\t}\n\n\tlist(): { id: string; runtime: TerminalRuntimeSession }[] {\n\t\tconst result: { id: string; runtime: TerminalRuntimeSession }[] = [];\n\t\tfor (const entry of this.registry.list()) {\n\t\t\tconst runtime = this.runtimes.get(entry.id);\n\t\t\tif (runtime) result.push({ id: entry.id, runtime });\n\t\t}\n\t\treturn result;\n\t}\n\n\t/** Tree-kill one session; the exited entry is kept for a final output read until swept. */\n\tasync stop(id: string): Promise<boolean> {\n\t\tconst stopped = await this.registry.stop(id);\n\t\tthis.reconcileRuntimes();\n\t\treturn stopped;\n\t}\n\n\t/** Tree-kill every session and dispose all runtime wrappers. */\n\tasync teardown(): Promise<void> {\n\t\tawait this.registry.teardown();\n\t\tfor (const runtime of this.runtimes.values()) runtime.dispose();\n\t\tthis.runtimes.clear();\n\t\tthis.exited.clear();\n\t}\n\n\t/** Dispose runtime wrappers whose registry entry was pruned (capacity/LRU eviction). */\n\tprivate reconcileRuntimes(): void {\n\t\tconst liveIds = new Set(this.registry.list().map((entry) => entry.id));\n\t\tfor (const [id, runtime] of this.runtimes) {\n\t\t\tif (liveIds.has(id)) continue;\n\t\t\truntime.dispose();\n\t\t\tthis.runtimes.delete(id);\n\t\t\tthis.exited.delete(id);\n\t\t}\n\t}\n}\n\nexport function isCapacityError(error: unknown): error is SessionRegistryCapacityError {\n\treturn error instanceof SessionRegistryCapacityError;\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const APPROVED_MONITOR_PARENT: unique symbol;
|
|
2
|
+
export type MonitorPermissionInput = Record<string, unknown> & {
|
|
3
|
+
[APPROVED_MONITOR_PARENT]?: string;
|
|
4
|
+
};
|
|
5
|
+
export declare function setApprovedMonitorParent(input: Record<string, unknown>, parent: string): void;
|
|
6
|
+
export declare function getApprovedMonitorParent(input: Record<string, unknown>): string | undefined;
|
|
7
|
+
export declare function monitorParent(path: string): string;
|
|
8
|
+
//# sourceMappingURL=monitor-permission.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"monitor-permission.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/monitor-permission.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,uBAAuB,eAAoC,CAAC;AAEzE,MAAM,MAAM,sBAAsB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAC9D,CAAC,uBAAuB,CAAC,CAAC,EAAE,MAAM,CAAC;CACnC,CAAC;AAEF,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAM7F;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,SAAS,CAE3F;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { dirname } from "node:path";
|
|
2
|
+
export const APPROVED_MONITOR_PARENT = Symbol("approved-monitor-parent");
|
|
3
|
+
export function setApprovedMonitorParent(input, parent) {
|
|
4
|
+
Object.defineProperty(input, APPROVED_MONITOR_PARENT, {
|
|
5
|
+
configurable: true,
|
|
6
|
+
value: parent,
|
|
7
|
+
writable: false,
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
export function getApprovedMonitorParent(input) {
|
|
11
|
+
return input[APPROVED_MONITOR_PARENT];
|
|
12
|
+
}
|
|
13
|
+
export function monitorParent(path) {
|
|
14
|
+
return dirname(path);
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=monitor-permission.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"monitor-permission.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/monitor-permission.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAC,yBAAyB,CAAC,CAAC;AAMzE,MAAM,UAAU,wBAAwB,CAAC,KAA8B,EAAE,MAAc;IACtF,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,uBAAuB,EAAE;QACrD,YAAY,EAAE,IAAI;QAClB,KAAK,EAAE,MAAM;QACb,QAAQ,EAAE,KAAK;KACf,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,KAA8B;IACtE,OAAQ,KAAgC,CAAC,uBAAuB,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACzC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;AACtB,CAAC","sourcesContent":["import { dirname } from \"node:path\";\n\nexport const APPROVED_MONITOR_PARENT = Symbol(\"approved-monitor-parent\");\n\nexport type MonitorPermissionInput = Record<string, unknown> & {\n\t[APPROVED_MONITOR_PARENT]?: string;\n};\n\nexport function setApprovedMonitorParent(input: Record<string, unknown>, parent: string): void {\n\tObject.defineProperty(input, APPROVED_MONITOR_PARENT, {\n\t\tconfigurable: true,\n\t\tvalue: parent,\n\t\twritable: false,\n\t});\n}\n\nexport function getApprovedMonitorParent(input: Record<string, unknown>): string | undefined {\n\treturn (input as MonitorPermissionInput)[APPROVED_MONITOR_PARENT];\n}\n\nexport function monitorParent(path: string): string {\n\treturn dirname(path);\n}\n"]}
|
|
@@ -23,6 +23,16 @@ export interface MonitorSnapshotEntry {
|
|
|
23
23
|
export interface MonitorRegistryOptions {
|
|
24
24
|
/** Observes every registry transition (register/pause/rearm/settle/dispose) with the live snapshot. */
|
|
25
25
|
readonly onChange?: (snapshot: readonly MonitorSnapshotEntry[]) => void;
|
|
26
|
+
/** Reserves one shared terminal capacity slot for a native watch. */
|
|
27
|
+
readonly reserve?: () => (() => void) | null;
|
|
28
|
+
}
|
|
29
|
+
export interface RegisterFileMonitorOptions {
|
|
30
|
+
readonly description: string;
|
|
31
|
+
readonly path: string;
|
|
32
|
+
readonly event: "create" | "modify";
|
|
33
|
+
readonly timeoutMs: number;
|
|
34
|
+
readonly cwd: string;
|
|
35
|
+
readonly approvedParent?: string;
|
|
26
36
|
}
|
|
27
37
|
export interface RegisterMonitorOptions {
|
|
28
38
|
readonly id: string;
|
|
@@ -39,6 +49,9 @@ export declare class MonitorRegistry {
|
|
|
39
49
|
#private;
|
|
40
50
|
constructor(emit: (event: MonitorEvent) => void, options?: MonitorRegistryOptions);
|
|
41
51
|
snapshot(): readonly MonitorSnapshotEntry[];
|
|
52
|
+
registerFile(options: RegisterFileMonitorOptions): Promise<string>;
|
|
53
|
+
stopFile(id: string): Promise<boolean>;
|
|
54
|
+
stopAllFiles(): Promise<number>;
|
|
42
55
|
register(options: RegisterMonitorOptions): void;
|
|
43
56
|
pauseAll(): string[];
|
|
44
57
|
rearm(id: string): MonitorRearmResult;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"monitor-registry.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/monitor-registry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"monitor-registry.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/monitor-registry.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAGnE,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,YAAY,GAAG,gBAAgB,GAAG,mBAAmB,CAAC;AAElE,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,YAAY,GAAG,WAAW,CAAC;AAExE,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,2FAA2F;IAC3F,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,sBAAsB;IACtC,uGAAuG;IACvG,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,SAAS,oBAAoB,EAAE,KAAK,IAAI,CAAC;IACxE,qEAAqE;IACrE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC;CAC7C;AAED,MAAM,WAAW,0BAA0B;IAC1C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACzB;AAiDD;;;;GAIG;AACH,qBAAa,eAAe;;gBAYf,IAAI,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,EAAE,OAAO,CAAC,EAAE,sBAAsB;IAMjF,QAAQ,IAAI,SAAS,oBAAoB,EAAE;IASrC,YAAY,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,MAAM,CAAC;IA+KlE,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAOtC,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IA2HrC,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI;IAwB/C,QAAQ,IAAI,MAAM,EAAE;IAWpB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,kBAAkB;IAUrC,OAAO,IAAI,IAAI;CAyHf"}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { watch } from "node:fs";
|
|
3
|
+
import { access, lstat, open, realpath, stat } from "node:fs/promises";
|
|
4
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
1
5
|
import { describeExit } from "./tools/spawn.js";
|
|
2
6
|
/**
|
|
3
7
|
* Tracks active monitor sessions alongside the terminal manager's existing bash-id registry.
|
|
@@ -8,18 +12,351 @@ export class MonitorRegistry {
|
|
|
8
12
|
#records = new Map();
|
|
9
13
|
#emit;
|
|
10
14
|
#onChange;
|
|
15
|
+
#reserve;
|
|
16
|
+
#files = new Map();
|
|
17
|
+
#nextFileId = 1;
|
|
18
|
+
#disposed = false;
|
|
19
|
+
#pendingRegistrations = 0;
|
|
20
|
+
#pending = new Set();
|
|
21
|
+
#lifecycle = 0;
|
|
11
22
|
constructor(emit, options) {
|
|
12
23
|
this.#emit = emit;
|
|
13
24
|
this.#onChange = options?.onChange;
|
|
25
|
+
this.#reserve = options?.reserve;
|
|
14
26
|
}
|
|
15
27
|
snapshot() {
|
|
16
|
-
return [...this.#records.values()].map((record) => ({
|
|
28
|
+
return [...this.#records.values(), ...this.#files.values()].map((record) => ({
|
|
17
29
|
id: record.id,
|
|
18
30
|
description: record.description,
|
|
19
31
|
paused: record.paused,
|
|
20
32
|
startedAtMs: record.startedAtMs,
|
|
21
33
|
}));
|
|
22
34
|
}
|
|
35
|
+
async registerFile(options) {
|
|
36
|
+
if (this.#disposed)
|
|
37
|
+
throw new Error("Cannot create file monitor: monitor registry is disposed.");
|
|
38
|
+
this.#pendingRegistrations += 1;
|
|
39
|
+
const lifecycle = this.#lifecycle;
|
|
40
|
+
const release = this.#reserve?.();
|
|
41
|
+
if (this.#reserve && !release) {
|
|
42
|
+
this.#pendingRegistrations -= 1;
|
|
43
|
+
throw new Error("Cannot create file monitor: terminal capacity is already in use.");
|
|
44
|
+
}
|
|
45
|
+
const pending = {
|
|
46
|
+
release: release ?? undefined,
|
|
47
|
+
abort: new AbortController(),
|
|
48
|
+
deadline: setTimeout(() => pending.abort.abort(), options.timeoutMs),
|
|
49
|
+
settled: false,
|
|
50
|
+
};
|
|
51
|
+
this.#pending.add(pending);
|
|
52
|
+
const path = resolve(options.cwd, options.path);
|
|
53
|
+
const parent = dirname(path);
|
|
54
|
+
let approvedParent;
|
|
55
|
+
try {
|
|
56
|
+
await this.#registrationAwait(pending, access(parent));
|
|
57
|
+
approvedParent = await this.#registrationAwait(pending, realpath(parent));
|
|
58
|
+
const approvedParentAtPermission = options.approvedParent;
|
|
59
|
+
if (approvedParentAtPermission !== undefined && approvedParent !== approvedParentAtPermission) {
|
|
60
|
+
throw new Error(`Cannot watch file: parent directory changed during permission approval: ${parent}`);
|
|
61
|
+
}
|
|
62
|
+
if (this.#disposed)
|
|
63
|
+
throw new Error("Cannot create file monitor: monitor registry is disposed.");
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
this.#finishPending(pending);
|
|
67
|
+
this.#pendingRegistrations -= 1;
|
|
68
|
+
if (error instanceof Error && error.message.includes("disposed"))
|
|
69
|
+
throw error;
|
|
70
|
+
if (error?.code !== "ENOENT") {
|
|
71
|
+
throw new Error(`Cannot access parent directory ${parent}: ${error instanceof Error ? error.message : String(error)}`);
|
|
72
|
+
}
|
|
73
|
+
throw new Error(`Cannot watch file: parent directory does not exist: ${parent}`);
|
|
74
|
+
}
|
|
75
|
+
let initial = null;
|
|
76
|
+
let initialHandle;
|
|
77
|
+
try {
|
|
78
|
+
const target = await this.#registrationAwait(pending, lstat(path));
|
|
79
|
+
if (target.isSymbolicLink())
|
|
80
|
+
throw new Error(`Cannot watch file: target is a symbolic link: ${path}`);
|
|
81
|
+
initialHandle = await this.#registrationAwait(pending, open(path, "r"), async (handle) => {
|
|
82
|
+
await handle.close();
|
|
83
|
+
});
|
|
84
|
+
initial = await this.#registrationAwait(pending, initialHandle.stat());
|
|
85
|
+
if (!initial.isFile())
|
|
86
|
+
throw new Error(`Cannot watch file: target is not a regular file: ${path}`);
|
|
87
|
+
const resolvedTarget = await this.#registrationAwait(pending, realpath(path));
|
|
88
|
+
if (resolvedTarget !== join(approvedParent, basename(path)))
|
|
89
|
+
throw new Error(`Cannot watch file: target identity changed: ${path}`);
|
|
90
|
+
const rebound = await this.#registrationAwait(pending, lstat(path));
|
|
91
|
+
if (rebound.isSymbolicLink())
|
|
92
|
+
throw new Error(`Cannot watch file: target identity changed: ${path}`);
|
|
93
|
+
const reboundStat = await this.#registrationAwait(pending, stat(path));
|
|
94
|
+
if (!reboundStat.isFile() || reboundStat.dev !== initial.dev || reboundStat.ino !== initial.ino)
|
|
95
|
+
throw new Error(`Cannot watch file: target identity changed: ${path}`);
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
await initialHandle?.close();
|
|
99
|
+
initialHandle = undefined;
|
|
100
|
+
if (error?.code !== "ENOENT") {
|
|
101
|
+
this.#finishPending(pending);
|
|
102
|
+
this.#pendingRegistrations -= 1;
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (this.#disposed || lifecycle !== this.#lifecycle || this.#pendingRegistrations < 1) {
|
|
107
|
+
this.#finishPending(pending);
|
|
108
|
+
this.#pendingRegistrations -= 1;
|
|
109
|
+
throw new Error("Cannot create file monitor: monitor registry is disposed.");
|
|
110
|
+
}
|
|
111
|
+
const id = `watch_${this.#nextFileId++}`;
|
|
112
|
+
let watcher;
|
|
113
|
+
try {
|
|
114
|
+
const activationParent = await this.#registrationAwait(pending, realpath(parent));
|
|
115
|
+
if (activationParent !== approvedParent) {
|
|
116
|
+
throw new Error(`Cannot watch file: parent directory changed during registration: ${parent}`);
|
|
117
|
+
}
|
|
118
|
+
watcher = watch(activationParent, (_kind, name) => {
|
|
119
|
+
if (!name || basename(String(name)) === basename(path))
|
|
120
|
+
void this.#checkFile(id);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
this.#finishPending(pending);
|
|
125
|
+
this.#pendingRegistrations -= 1;
|
|
126
|
+
throw new Error(`Cannot watch file ${path}: ${error instanceof Error ? error.message : String(error)}`);
|
|
127
|
+
}
|
|
128
|
+
let registrationError;
|
|
129
|
+
watcher.on("error", (error) => {
|
|
130
|
+
registrationError = `watcher error: ${error instanceof Error ? error.message : String(error)}`;
|
|
131
|
+
const record = this.#files.get(id);
|
|
132
|
+
if (record)
|
|
133
|
+
this.#settleFile(record, registrationError);
|
|
134
|
+
});
|
|
135
|
+
let registrationCleaned = false;
|
|
136
|
+
const finishRegistration = () => {
|
|
137
|
+
if (registrationCleaned)
|
|
138
|
+
return;
|
|
139
|
+
registrationCleaned = true;
|
|
140
|
+
this.#pendingRegistrations -= 1;
|
|
141
|
+
};
|
|
142
|
+
const cleanupRegistration = () => {
|
|
143
|
+
if (registrationCleaned)
|
|
144
|
+
return;
|
|
145
|
+
watcher.close();
|
|
146
|
+
finishRegistration();
|
|
147
|
+
this.#finishPending(pending);
|
|
148
|
+
};
|
|
149
|
+
if (this.#disposed || lifecycle !== this.#lifecycle) {
|
|
150
|
+
cleanupRegistration();
|
|
151
|
+
throw new Error("Cannot create file monitor: monitor registry is disposed.");
|
|
152
|
+
}
|
|
153
|
+
const canonicalPath = join(approvedParent, basename(path));
|
|
154
|
+
let digest;
|
|
155
|
+
try {
|
|
156
|
+
digest =
|
|
157
|
+
initial && initialHandle
|
|
158
|
+
? await this.#registrationAwait(pending, this.#digestHandle(initialHandle, pending.abort.signal))
|
|
159
|
+
: "";
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
cleanupRegistration();
|
|
163
|
+
await initialHandle?.close();
|
|
164
|
+
initialHandle = undefined;
|
|
165
|
+
if (registrationError) {
|
|
166
|
+
this.#emit({ type: "summary", id, description: options.description, summary: registrationError });
|
|
167
|
+
throw new Error(registrationError);
|
|
168
|
+
}
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
await initialHandle?.close();
|
|
172
|
+
initialHandle = undefined;
|
|
173
|
+
if (registrationError) {
|
|
174
|
+
cleanupRegistration();
|
|
175
|
+
this.#emit({ type: "summary", id, description: options.description, summary: registrationError });
|
|
176
|
+
throw new Error(registrationError);
|
|
177
|
+
}
|
|
178
|
+
if (this.#disposed || lifecycle !== this.#lifecycle) {
|
|
179
|
+
cleanupRegistration();
|
|
180
|
+
throw new Error("Cannot create file monitor: monitor registry is disposed.");
|
|
181
|
+
}
|
|
182
|
+
const record = {
|
|
183
|
+
id,
|
|
184
|
+
description: options.description,
|
|
185
|
+
startedAtMs: Date.now(),
|
|
186
|
+
path,
|
|
187
|
+
canonicalPath,
|
|
188
|
+
canonicalParent: approvedParent,
|
|
189
|
+
event: options.event,
|
|
190
|
+
watcher,
|
|
191
|
+
release: release ?? (() => { }),
|
|
192
|
+
poll: setInterval(() => void this.#checkFile(id), 250),
|
|
193
|
+
paused: false,
|
|
194
|
+
settled: false,
|
|
195
|
+
present: initial !== null,
|
|
196
|
+
mtimeMs: initial?.mtimeMs ?? 0,
|
|
197
|
+
size: initial?.size ?? 0,
|
|
198
|
+
digest,
|
|
199
|
+
device: initial?.dev ?? 0,
|
|
200
|
+
inode: initial?.ino ?? 0,
|
|
201
|
+
pendingChange: false,
|
|
202
|
+
dirty: false,
|
|
203
|
+
dirtyPasses: 0,
|
|
204
|
+
dirtyWindowStartedAt: 0,
|
|
205
|
+
checking: undefined,
|
|
206
|
+
deadline: setTimeout(() => {
|
|
207
|
+
const current = this.#files.get(id);
|
|
208
|
+
if (current)
|
|
209
|
+
this.#settleFile(current, "watcher timed_out");
|
|
210
|
+
}, options.timeoutMs),
|
|
211
|
+
};
|
|
212
|
+
this.#files.set(id, record);
|
|
213
|
+
finishRegistration();
|
|
214
|
+
this.#finishPending(pending, true);
|
|
215
|
+
if (registrationError || this.#disposed || lifecycle !== this.#lifecycle) {
|
|
216
|
+
this.#settleFile(record, registrationError ?? "watcher killed");
|
|
217
|
+
throw new Error(registrationError ?? "Cannot create file monitor: monitor registry is disposed.");
|
|
218
|
+
}
|
|
219
|
+
this.#notifyChange();
|
|
220
|
+
return id;
|
|
221
|
+
}
|
|
222
|
+
async stopFile(id) {
|
|
223
|
+
const record = this.#files.get(id);
|
|
224
|
+
if (!record)
|
|
225
|
+
return false;
|
|
226
|
+
this.#settleFile(record, "watcher killed");
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
async stopAllFiles() {
|
|
230
|
+
this.#lifecycle += 1;
|
|
231
|
+
const records = [...this.#files.values()];
|
|
232
|
+
for (const record of records)
|
|
233
|
+
this.#settleFile(record, "watcher killed");
|
|
234
|
+
for (const pending of [...this.#pending])
|
|
235
|
+
this.#finishPending(pending);
|
|
236
|
+
return records.length;
|
|
237
|
+
}
|
|
238
|
+
#settleFile(record, summary) {
|
|
239
|
+
if (record.settled)
|
|
240
|
+
return;
|
|
241
|
+
record.settled = true;
|
|
242
|
+
clearInterval(record.poll);
|
|
243
|
+
clearTimeout(record.deadline);
|
|
244
|
+
record.watcher.close();
|
|
245
|
+
record.release();
|
|
246
|
+
this.#files.delete(record.id);
|
|
247
|
+
this.#notifyChange();
|
|
248
|
+
this.#emit({ type: "summary", id: record.id, description: record.description, summary });
|
|
249
|
+
}
|
|
250
|
+
async #checkFile(id) {
|
|
251
|
+
const record = this.#files.get(id);
|
|
252
|
+
if (!record || record.settled)
|
|
253
|
+
return;
|
|
254
|
+
if (record.checking) {
|
|
255
|
+
record.dirty = true;
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
record.checking = this.#checkFileImpl(record)
|
|
259
|
+
.catch((error) => {
|
|
260
|
+
if (!record.settled)
|
|
261
|
+
this.#settleFile(record, `watcher error: ${error instanceof Error ? error.message : String(error)}`);
|
|
262
|
+
})
|
|
263
|
+
.finally(() => {
|
|
264
|
+
record.checking = undefined;
|
|
265
|
+
const now = Date.now();
|
|
266
|
+
if (now - record.dirtyWindowStartedAt >= 1_000) {
|
|
267
|
+
record.dirtyWindowStartedAt = now;
|
|
268
|
+
record.dirtyPasses = 0;
|
|
269
|
+
}
|
|
270
|
+
if (record.dirty && !record.settled && record.dirtyPasses < 1) {
|
|
271
|
+
record.dirty = false;
|
|
272
|
+
record.dirtyPasses += 1;
|
|
273
|
+
void this.#checkFile(id);
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
record.dirty = false;
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
return record.checking;
|
|
280
|
+
}
|
|
281
|
+
async #checkFileImpl(record) {
|
|
282
|
+
if (record.settled)
|
|
283
|
+
return;
|
|
284
|
+
let current = null;
|
|
285
|
+
let handle;
|
|
286
|
+
try {
|
|
287
|
+
const currentParent = await realpath(dirname(record.path));
|
|
288
|
+
if (currentParent !== record.canonicalParent) {
|
|
289
|
+
this.#settleFile(record, `watcher error: monitored parent changed: ${dirname(record.path)}`);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
const target = await lstat(record.canonicalPath);
|
|
293
|
+
if (target.isSymbolicLink())
|
|
294
|
+
throw new Error(`Cannot watch file: target identity changed: ${record.path}`);
|
|
295
|
+
const resolvedTarget = await realpath(record.canonicalPath);
|
|
296
|
+
if (resolvedTarget !== record.canonicalPath)
|
|
297
|
+
throw new Error(`Cannot watch file: target identity changed: ${record.path}`);
|
|
298
|
+
handle = await open(record.canonicalPath, "r");
|
|
299
|
+
const opened = await handle.stat();
|
|
300
|
+
if (!opened.isFile())
|
|
301
|
+
throw new Error(`Cannot watch file: target is not a regular file: ${record.path}`);
|
|
302
|
+
if ((opened.dev !== record.device || opened.ino !== record.inode) && opened.nlink > 1)
|
|
303
|
+
throw new Error(`Cannot watch file: target identity changed: ${record.path}`);
|
|
304
|
+
current = opened;
|
|
305
|
+
const rebound = await lstat(record.canonicalPath);
|
|
306
|
+
if (rebound.isSymbolicLink())
|
|
307
|
+
throw new Error(`Cannot watch file: target identity changed: ${record.path}`);
|
|
308
|
+
const reboundPath = await stat(record.canonicalPath);
|
|
309
|
+
if (!reboundPath.isFile() || reboundPath.dev !== opened.dev || reboundPath.ino !== opened.ino)
|
|
310
|
+
throw new Error(`Cannot watch file: target identity changed: ${record.path}`);
|
|
311
|
+
}
|
|
312
|
+
catch (error) {
|
|
313
|
+
await handle?.close();
|
|
314
|
+
if (error?.code !== "ENOENT") {
|
|
315
|
+
this.#settleFile(record, `watcher error: ${error instanceof Error ? error.message : String(error)}`);
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
const present = current !== null;
|
|
320
|
+
let digest = "";
|
|
321
|
+
try {
|
|
322
|
+
digest = present && handle ? await this.#digestHandle(handle) : "";
|
|
323
|
+
if (present && handle) {
|
|
324
|
+
const afterDigest = await stat(record.canonicalPath);
|
|
325
|
+
const opened = await handle.stat();
|
|
326
|
+
if (afterDigest.dev !== opened.dev || afterDigest.ino !== opened.ino)
|
|
327
|
+
throw new Error(`Cannot watch file: target identity changed: ${record.path}`);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
finally {
|
|
331
|
+
await handle?.close();
|
|
332
|
+
}
|
|
333
|
+
const changed = record.event === "create"
|
|
334
|
+
? !record.present && present
|
|
335
|
+
: record.present &&
|
|
336
|
+
present &&
|
|
337
|
+
(current.mtimeMs !== record.mtimeMs || current.size !== record.size || digest !== record.digest);
|
|
338
|
+
record.pendingChange ||= changed;
|
|
339
|
+
if (!record.present && current) {
|
|
340
|
+
record.device = current.dev;
|
|
341
|
+
record.inode = current.ino;
|
|
342
|
+
}
|
|
343
|
+
record.present = present;
|
|
344
|
+
record.mtimeMs = current?.mtimeMs ?? 0;
|
|
345
|
+
record.size = current?.size ?? 0;
|
|
346
|
+
record.digest = digest;
|
|
347
|
+
if (!record.pendingChange || record.paused || record.settled)
|
|
348
|
+
return;
|
|
349
|
+
record.pendingChange = false;
|
|
350
|
+
if (record.settled)
|
|
351
|
+
return;
|
|
352
|
+
this.#emit({
|
|
353
|
+
type: "line",
|
|
354
|
+
id: record.id,
|
|
355
|
+
description: record.description,
|
|
356
|
+
line: `${record.event} ${record.path}`,
|
|
357
|
+
});
|
|
358
|
+
this.#settleFile(record, "watcher completed");
|
|
359
|
+
}
|
|
23
360
|
register(options) {
|
|
24
361
|
const record = {
|
|
25
362
|
id: options.id,
|
|
@@ -45,7 +382,7 @@ export class MonitorRegistry {
|
|
|
45
382
|
}
|
|
46
383
|
pauseAll() {
|
|
47
384
|
const paused = [];
|
|
48
|
-
for (const record of this.#records.values()) {
|
|
385
|
+
for (const record of [...this.#records.values(), ...this.#files.values()]) {
|
|
49
386
|
if (record.paused)
|
|
50
387
|
continue;
|
|
51
388
|
record.paused = true;
|
|
@@ -56,21 +393,84 @@ export class MonitorRegistry {
|
|
|
56
393
|
return paused;
|
|
57
394
|
}
|
|
58
395
|
rearm(id) {
|
|
59
|
-
const record = this.#records.get(id);
|
|
396
|
+
const record = this.#records.get(id) ?? this.#files.get(id);
|
|
60
397
|
if (!record)
|
|
61
398
|
return "not_found";
|
|
62
399
|
if (!record.paused)
|
|
63
400
|
return "not_paused";
|
|
64
401
|
record.paused = false;
|
|
65
402
|
this.#notifyChange();
|
|
403
|
+
if ("pendingChange" in record && record.pendingChange)
|
|
404
|
+
void this.#checkFile(record.id);
|
|
66
405
|
return "rearmed";
|
|
67
406
|
}
|
|
68
407
|
dispose() {
|
|
408
|
+
this.#disposed = true;
|
|
409
|
+
this.#lifecycle += 1;
|
|
69
410
|
for (const record of this.#records.values())
|
|
70
411
|
this.#disposeRecord(record);
|
|
412
|
+
for (const record of this.#files.values())
|
|
413
|
+
this.#settleFile(record, "watcher disposed");
|
|
414
|
+
for (const pending of this.#pending)
|
|
415
|
+
this.#finishPending(pending);
|
|
71
416
|
this.#records.clear();
|
|
72
417
|
this.#notifyChange();
|
|
73
418
|
}
|
|
419
|
+
#finishPending(pending, transfer = false) {
|
|
420
|
+
if (pending.settled)
|
|
421
|
+
return;
|
|
422
|
+
pending.settled = true;
|
|
423
|
+
clearTimeout(pending.deadline);
|
|
424
|
+
this.#pending.delete(pending);
|
|
425
|
+
if (transfer)
|
|
426
|
+
pending.release = undefined;
|
|
427
|
+
else {
|
|
428
|
+
pending.abort.abort();
|
|
429
|
+
pending.release?.();
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
async #registrationAwait(pending, operation, lateCleanup) {
|
|
433
|
+
if (pending.abort.signal.aborted) {
|
|
434
|
+
void operation.then((value) => lateCleanup?.(value), () => undefined);
|
|
435
|
+
throw new Error("Cannot create file monitor: registration timed out or was disposed.");
|
|
436
|
+
}
|
|
437
|
+
let aborted = false;
|
|
438
|
+
const abort = new Promise((_, reject) => pending.abort.signal.addEventListener("abort", () => {
|
|
439
|
+
aborted = true;
|
|
440
|
+
reject(new Error("Cannot create file monitor: registration timed out or was disposed."));
|
|
441
|
+
}, { once: true }));
|
|
442
|
+
const guarded = operation.then((value) => {
|
|
443
|
+
if (aborted)
|
|
444
|
+
void lateCleanup?.(value);
|
|
445
|
+
return value;
|
|
446
|
+
}, (error) => {
|
|
447
|
+
if (aborted)
|
|
448
|
+
return undefined;
|
|
449
|
+
throw error;
|
|
450
|
+
});
|
|
451
|
+
return Promise.race([guarded, abort]);
|
|
452
|
+
}
|
|
453
|
+
async #digestHandle(handle, signal) {
|
|
454
|
+
const SAMPLE_SIZE = 64 * 1024;
|
|
455
|
+
if (signal?.aborted)
|
|
456
|
+
throw new Error("file monitor registration cancelled");
|
|
457
|
+
const metadata = await handle.stat();
|
|
458
|
+
const hash = createHash("sha256");
|
|
459
|
+
const first = Buffer.alloc(Math.min(SAMPLE_SIZE, metadata.size));
|
|
460
|
+
if (first.length > 0) {
|
|
461
|
+
await handle.read(first, 0, first.length, 0);
|
|
462
|
+
hash.update(first);
|
|
463
|
+
}
|
|
464
|
+
if (metadata.size > SAMPLE_SIZE) {
|
|
465
|
+
const middle = Buffer.alloc(SAMPLE_SIZE);
|
|
466
|
+
await handle.read(middle, 0, middle.length, Math.floor((metadata.size - middle.length) / 2));
|
|
467
|
+
hash.update(middle);
|
|
468
|
+
const last = Buffer.alloc(SAMPLE_SIZE);
|
|
469
|
+
await handle.read(last, 0, last.length, metadata.size - last.length);
|
|
470
|
+
hash.update(last);
|
|
471
|
+
}
|
|
472
|
+
return `${metadata.size}:${hash.digest("hex")}`;
|
|
473
|
+
}
|
|
74
474
|
#notifyChange() {
|
|
75
475
|
this.#onChange?.(this.snapshot());
|
|
76
476
|
}
|