@code-yeongyu/senpi 2026.9.15 → 2026.9.16-3
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 +89 -0
- package/README.md +1 -1
- package/dist/cli/help-extension-flags.d.ts +22 -0
- package/dist/cli/help-extension-flags.d.ts.map +1 -0
- package/dist/cli/help-extension-flags.js +30 -0
- package/dist/cli/help-extension-flags.js.map +1 -0
- package/dist/cli/help-fast-path.d.ts +19 -0
- package/dist/cli/help-fast-path.d.ts.map +1 -0
- package/dist/cli/help-fast-path.js +64 -0
- package/dist/cli/help-fast-path.js.map +1 -0
- package/dist/cli/help-flags-cache.d.ts +23 -0
- package/dist/cli/help-flags-cache.d.ts.map +1 -0
- package/dist/cli/help-flags-cache.js +118 -0
- package/dist/cli/help-flags-cache.js.map +1 -0
- package/dist/cli/startup-loading-indicator.d.ts.map +1 -1
- package/dist/cli/startup-loading-indicator.js +10 -4
- package/dist/cli/startup-loading-indicator.js.map +1 -1
- package/dist/cli.js +9 -0
- package/dist/cli.js.map +1 -1
- package/dist/core/agent-session.d.ts +17 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +62 -8
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +4 -2
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/stream-watchdog.d.ts +56 -2
- package/dist/core/compaction/stream-watchdog.d.ts.map +1 -1
- package/dist/core/compaction/stream-watchdog.js +93 -15
- package/dist/core/compaction/stream-watchdog.js.map +1 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-binding.d.ts +6 -0
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-binding.d.ts.map +1 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-binding.js +17 -0
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-binding.js.map +1 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-continuity.d.ts +4 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-continuity.d.ts.map +1 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-continuity.js +31 -0
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-continuity.js.map +1 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.d.ts +2 -0
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.d.ts.map +1 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.js +16 -0
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.js.map +1 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry-wiring.d.ts.map +1 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry-wiring.js +19 -8
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry-wiring.js.map +1 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-stream.d.ts.map +1 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-stream.js +2 -1
- package/dist/core/extensions/builtin/claude-sdk-oauth/session-stream.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.d.ts +13 -1
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.js +66 -2
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/index.js +16 -10
- package/dist/core/extensions/builtin/compaction/index.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/speculative-summary.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/speculative-summary.js +4 -2
- package/dist/core/extensions/builtin/compaction/speculative-summary.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/speculative.d.ts +8 -1
- package/dist/core/extensions/builtin/compaction/speculative.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/speculative.js +31 -7
- package/dist/core/extensions/builtin/compaction/speculative.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/transient-failure.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/transient-failure.js +6 -3
- package/dist/core/extensions/builtin/compaction/transient-failure.js.map +1 -1
- package/dist/core/extensions/builtin/config-reload/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/config-reload/index.js +25 -8
- package/dist/core/extensions/builtin/config-reload/index.js.map +1 -1
- package/dist/core/extensions/builtin/config-reload/watch-engine.d.ts +4 -5
- package/dist/core/extensions/builtin/config-reload/watch-engine.d.ts.map +1 -1
- package/dist/core/extensions/builtin/config-reload/watch-engine.js +14 -18
- package/dist/core/extensions/builtin/config-reload/watch-engine.js.map +1 -1
- package/dist/core/extensions/builtin/config-reload/watch-event-source.d.ts.map +1 -1
- package/dist/core/extensions/builtin/config-reload/watch-event-source.js +32 -9
- package/dist/core/extensions/builtin/config-reload/watch-event-source.js.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/catalog-refresh.d.ts +23 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/catalog-refresh.d.ts.map +1 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/catalog-refresh.js +48 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/catalog-refresh.js.map +1 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/environment.d.ts +13 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/environment.d.ts.map +1 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/environment.js +24 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/environment.js.map +1 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/executable.d.ts +1 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/executable.d.ts.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/executable.js +7 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/executable.js.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/index.d.ts +2 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/index.js +11 -9
- package/dist/core/extensions/builtin/cursor-cli-oauth/index.js.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/models-probe.d.ts +18 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/models-probe.d.ts.map +1 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/models-probe.js +61 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/models-probe.js.map +1 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/models.d.ts +4 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/models.d.ts.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/models.js +1 -44
- package/dist/core/extensions/builtin/cursor-cli-oauth/models.js.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/oauth-login.d.ts +22 -0
- package/dist/core/extensions/builtin/cursor-cli-oauth/oauth-login.d.ts.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/oauth-login.js +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/oauth-login.js.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/transport.d.ts.map +1 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/transport.js +2 -13
- package/dist/core/extensions/builtin/cursor-cli-oauth/transport.js.map +1 -1
- package/dist/core/extensions/builtin/terminal/monitor-file-digest.d.ts +3 -0
- package/dist/core/extensions/builtin/terminal/monitor-file-digest.d.ts.map +1 -0
- package/dist/core/extensions/builtin/terminal/monitor-file-digest.js +25 -0
- package/dist/core/extensions/builtin/terminal/monitor-file-digest.js.map +1 -0
- package/dist/core/extensions/builtin/terminal/monitor-file-watch.d.ts +9 -0
- package/dist/core/extensions/builtin/terminal/monitor-file-watch.d.ts.map +1 -0
- package/dist/core/extensions/builtin/terminal/monitor-file-watch.js +33 -0
- package/dist/core/extensions/builtin/terminal/monitor-file-watch.js.map +1 -0
- package/dist/core/extensions/builtin/terminal/monitor-line-buffer.d.ts +6 -0
- package/dist/core/extensions/builtin/terminal/monitor-line-buffer.d.ts.map +1 -0
- package/dist/core/extensions/builtin/terminal/monitor-line-buffer.js +22 -0
- package/dist/core/extensions/builtin/terminal/monitor-line-buffer.js.map +1 -0
- package/dist/core/extensions/builtin/terminal/monitor-registry.d.ts.map +1 -1
- package/dist/core/extensions/builtin/terminal/monitor-registry.js +14 -35
- package/dist/core/extensions/builtin/terminal/monitor-registry.js.map +1 -1
- package/dist/core/extensions/builtin/ttsr/detectors/collapse-near-duplicates.d.ts +38 -0
- package/dist/core/extensions/builtin/ttsr/detectors/collapse-near-duplicates.d.ts.map +1 -0
- package/dist/core/extensions/builtin/ttsr/detectors/collapse-near-duplicates.js +155 -0
- package/dist/core/extensions/builtin/ttsr/detectors/collapse-near-duplicates.js.map +1 -0
- package/dist/core/extensions/builtin/ttsr/detectors/collapse.d.ts +2 -0
- package/dist/core/extensions/builtin/ttsr/detectors/collapse.d.ts.map +1 -1
- package/dist/core/extensions/builtin/ttsr/detectors/collapse.js +4 -1
- package/dist/core/extensions/builtin/ttsr/detectors/collapse.js.map +1 -1
- package/dist/core/extensions/kernel-tools-context.d.ts +13 -0
- package/dist/core/extensions/kernel-tools-context.d.ts.map +1 -0
- package/dist/core/extensions/kernel-tools-context.js +3 -0
- package/dist/core/extensions/kernel-tools-context.js.map +1 -0
- package/dist/core/extensions/runner.d.ts +19 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +103 -1
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +21 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/keybindings.d.ts +5 -0
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +1 -0
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +9 -17
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/session-manager.d.ts +30 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +92 -5
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-resident-store.d.ts +33 -7
- package/dist/core/session-resident-store.d.ts.map +1 -1
- package/dist/core/session-resident-store.js +163 -14
- package/dist/core/session-resident-store.js.map +1 -1
- package/dist/core/session-write-reservation.d.ts +6 -0
- package/dist/core/session-write-reservation.d.ts.map +1 -1
- package/dist/core/session-write-reservation.js +19 -0
- package/dist/core/session-write-reservation.js.map +1 -1
- package/dist/core/settings-manager.d.ts +23 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +41 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +2 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/tools/index.d.ts +1 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +4 -3
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/read.d.ts +3 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +16 -2
- package/dist/core/tools/read.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +31 -3
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/assistant-render-descriptors.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-render-descriptors.js +12 -5
- package/dist/modes/interactive/components/assistant-render-descriptors.js.map +1 -1
- package/dist/modes/interactive/components/extension-input.d.ts +2 -0
- package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-input.js +5 -0
- package/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +7 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +35 -16
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/tips/catalog/session-tips.js +1 -1
- package/dist/modes/interactive/tips/catalog/session-tips.js.map +1 -1
- package/dist/modes/print-mode.d.ts +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +5 -1
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/host-watchdog.d.ts.map +1 -1
- package/dist/modes/rpc/host-watchdog.js +5 -24
- package/dist/modes/rpc/host-watchdog.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +3 -8
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
- package/dist/modes/rpc/session-command-router.js +3 -0
- package/dist/modes/rpc/session-command-router.js.map +1 -1
- package/dist/modes/rpc/session-worker-client.d.ts +3 -0
- package/dist/modes/rpc/session-worker-client.d.ts.map +1 -1
- package/dist/modes/rpc/session-worker-client.js +17 -6
- package/dist/modes/rpc/session-worker-client.js.map +1 -1
- package/dist/modes/rpc/shutdown.d.ts +3 -0
- package/dist/modes/rpc/shutdown.d.ts.map +1 -0
- package/dist/modes/rpc/shutdown.js +17 -0
- package/dist/modes/rpc/shutdown.js.map +1 -0
- package/dist/senpi +9 -0
- package/docs/extensions.md +5 -2
- package/docs/keybindings.md +1 -0
- package/docs/session-format.md +1 -1
- package/docs/sessions.md +3 -3
- package/docs/settings.md +12 -0
- package/docs/usage.md +1 -1
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +62 -0
- package/node_modules/@code-yeongyu/senpi-codemode/README.md +24 -0
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
- package/node_modules/@code-yeongyu/senpi-codemode/src/bridge/http-server.ts +7 -1
- package/node_modules/@code-yeongyu/senpi-codemode/src/bridge/kernel-tools-protocol.ts +85 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/bridge/protocol.ts +6 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/bridges/agent-bridge.ts +30 -11
- package/node_modules/@code-yeongyu/senpi-codemode/src/extension/session-manager.ts +11 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/index.ts +10 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/jl/prelude.jl +46 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/jl/runner.jl +1 -1
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/context-manager.ts +58 -10
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-contract.ts +12 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-context.d.ts +13 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-context.js +7 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-define.d.ts +10 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-define.js +12 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-errors.js +22 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-errors.ts +26 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-host.ts +134 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-naming.js +28 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-parse.d.ts +5 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-parse.js +255 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-pump.js +105 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-registry.d.ts +27 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-registry.js +127 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-schema.js +69 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-types.ts +42 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/prelude.ts +2 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-core.js +26 -3
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-runtime.js +20 -8
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-slot.ts +6 -1
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-startup.ts +9 -7
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/workpool.js +37 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/kernel-tools-unavailable.ts +5 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/kernel.ts +13 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/prelude.py +57 -3
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/rb/prelude.rb +13 -2
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/rb/workpool.rb +38 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/shared/subprocess-kernel.ts +13 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/shared/subprocess-queue.ts +9 -1
- package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt-template.ts +4 -2
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/cell-handler.ts +31 -3
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-manager.ts +36 -71
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/image-resize.ts +52 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/image.ts +37 -72
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/managed-cell.ts +78 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/render.ts +30 -5
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/run-eval-cell.ts +52 -30
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/terminal-snapshot-store.ts +35 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/tool-result-marshal.ts +23 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/types.ts +2 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/empty-assistant-recovery.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/empty-assistant-recovery.js +51 -12
- package/node_modules/@earendil-works/pi-agent-core/dist/empty-assistant-recovery.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/read.d.ts +3 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/read.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/read.js +18 -3
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/read.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/brace-scanner.d.ts +4 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/brace-scanner.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/brace-scanner.js +268 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/brace-scanner.js.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/header-protection.d.ts +18 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/header-protection.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/header-protection.js +69 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/header-protection.js.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/index.d.ts +27 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/index.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/index.js +118 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/index.js.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-context.d.ts +21 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-context.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-context.js +24 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-context.js.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-spans.d.ts +12 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-spans.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-spans.js +92 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-spans.js.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/types.d.ts +47 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/types.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/types.js +8 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/types.js.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/segmented-read-view.d.ts +52 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/segmented-read-view.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/segmented-read-view.js +155 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/segmented-read-view.js.map +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/index.d.ts +2 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/index.js +2 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- 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/alibaba-token-plan.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/fireworks.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/qwen-token-plan.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/venice.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/utils/empty-response-errors.d.ts +15 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/empty-response-errors.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/empty-response-errors.js +15 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/empty-response-errors.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts +23 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +74 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -12,6 +12,94 @@
|
|
|
12
12
|
|
|
13
13
|
### Removed
|
|
14
14
|
|
|
15
|
+
## [2026.9.16-3] - 2026-09-16
|
|
16
|
+
|
|
17
|
+
### Breaking Changes
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- The stream guard now interrupts a message that keeps restating itself in different words, not only one that repeats a paragraph verbatim. A paragraph counts as an echo when its normalized word set overlaps an earlier paragraph of the same message by half, and the guard acts only once at least 8 of the last 12 paragraphs are echoes, so a repeated sentence, a callback, or a closing summary is left alone while a narration loop is cut within a few thousand characters. Paragraphs inside fenced code blocks are ignored, and the earlier text is kept - only the repeated run is dropped before the retry. Measured against 12,499 real assistant messages, the rule matched nothing except two known runaway generations. ([#1330](https://github.com/code-yeongyu/senpi/issues/1330))
|
|
24
|
+
|
|
25
|
+
- `--help` no longer boots the engine to print a help screen. The usage text and the flags extensions register are answered from a cache of the last launch's flag set (`<agentDir>/cache/help-flags.json`, validated against the engine version and the mtime/size of every extension, settings and trust input, so an upgrade or an edited extension refreshes it); a cache miss loads extensions for their flags only and skips the model runtime, the session and every other resource class. Measured warm on an Apple M4 Pro: 790ms → 28ms on bun and 959ms → 59ms on node for `--help`; a help screen never prompts for project trust and never runs project-local extension code that is not already trusted. ([oh-my-openagent#8371](https://github.com/code-yeongyu/oh-my-openagent/issues/8371))
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- The startup spinner is drawn the moment interactive startup begins instead of after a 120ms grace timer. That timer could not fire while the synchronous extension imports it was meant to cover were running, so on a real terminal the first frame appeared only once the whole load was done (measured: first byte at 2.27s, one frame before the TUI took over) and the load ran on a blank screen. ([oh-my-openagent#8371](https://github.com/code-yeongyu/oh-my-openagent/issues/8371))
|
|
30
|
+
|
|
31
|
+
### Removed
|
|
32
|
+
|
|
33
|
+
## [2026.9.16-2] - 2026-09-16
|
|
34
|
+
|
|
35
|
+
### Breaking Changes
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
|
|
39
|
+
- Added `/rename [name]` to rename the current session from the TUI: with an argument it sets the name immediately, without one it opens an inline editor prefilled with the current name (Enter commits, Esc cancels, empty names are rejected). `/name` remains as an alias, and the new unbound `app.session.renameCurrent` keybinding action opens the same editor. ([#1738](https://github.com/code-yeongyu/senpi/issues/1738))
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
|
|
43
|
+
- Large tool-result strings evicted from the resident store persist to a per-session blob backing and hydrate on read instead of forcing a full session-JSONL reparse. Blob names are the SHA-256 of the text, so a string that is hydrated and externalized again maps to the same file, and two processes sharing a session directory can only ever write identical bytes under one name. Blobs are integrity-checked envelopes: a corrupt file is deleted on read and the entry falls back to JSONL recovery. `--no-session` never writes blobs ([#1746](https://github.com/code-yeongyu/senpi/issues/1746)).
|
|
44
|
+
- Idle sessions release the memoized entry views and tokenize the runtime message state only once the store has evicted something; `session.messages` and the compaction estimators hydrate those tokens before returning, so readers never see resident tokens. The blob directory is removed when the session manager is disposed, when the session is switched or branched, and stale blobs are cleared when a persisted session is reopened ([#1746](https://github.com/code-yeongyu/senpi/issues/1746)).
|
|
45
|
+
- Compaction spills resident strings to the blob backing instead of dropping them, keeping post-compaction reads on the per-string hydration path.
|
|
46
|
+
- Branched sessions materialize entry content before the previous backing is released, so resident tokens can no longer be written into a new branched session file.
|
|
47
|
+
|
|
48
|
+
### Fixed
|
|
49
|
+
|
|
50
|
+
- Moving the model selector off a Claude model and back no longer re-sends the whole conversation. Leaving the `claude-sdk-oauth` provider now closes the live SDK session but keeps its continuity binding - the same thing a thinking-level change already did - so returning to the same Claude model re-attaches to the existing session and sends only the messages added while you were away, instead of paying for the full history again. Switching to a different Claude model, a restart with no usable transcript, a diverged conversation and an unacknowledged session id all still start fresh exactly as before. When a binding really was discarded, the transcript notice now names the recorded cause (`model_selected`, `tainted_compaction`, `branch_diverged`, `extensions_removed`, ...) instead of the generic `registry_miss`, which from now on means only "no record was ever found" ([#1747](https://github.com/code-yeongyu/senpi/issues/1747)).
|
|
51
|
+
|
|
52
|
+
- A provider that accepts a request and never starts streaming no longer ends the turn with the watchdog's own message (`Provider stream start timed out after 180000ms ...`). The stall is still retried on the same model with the configured stream-start bound, and still hands the turn to the next model in a configured `retry.fallbackChains` entry whose answer becomes the turn result. What changed is what you read: the transcript (and `senpi -p`) describes the stall in plain language, and when nothing can take the turn over the final line names the stalled model, the attempts spent and the next step - `/fallback`, resending, or raising `retry.provider.streamStartTimeoutMs` (`0` disables). The wording on the assistant message is unchanged, so retry classification and fallback routing behave exactly as before ([#1740](https://github.com/code-yeongyu/senpi/issues/1740)).
|
|
53
|
+
|
|
54
|
+
- A session no longer dead-ends when the compaction summarizer is killed by a provider or credential failure. Such a stream used to end required compaction with the raw internal `senpi:no-turn-retry:` marker, which also disabled auto-retry and model fallback; because compaction never applied, the context stayed above the threshold and every following prompt failed identically. Those failures now apply the deterministic compaction checkpoint (retained-suffix safety checks unchanged) and the turn continues, with one plain warning saying a provider summary could not be completed, that a checkpoint was applied and older detail was dropped, and that it is safe to continue. Provider refusals, missing credentials and user aborts still surface loudly instead of reducing context. One compaction is also bounded at 15 minutes total across every attempt and retry regardless of input size (an explicit `compaction.summarizationMaxDurationMs` above that still wins), and the summary stream's final settlement now happens inside the watchdog, so a provider whose stream ends without a terminal event can no longer park compaction with no timer armed ([#1741](https://github.com/code-yeongyu/senpi/issues/1741)).
|
|
55
|
+
|
|
56
|
+
### Removed
|
|
57
|
+
|
|
58
|
+
## [2026.9.16] - 2026-09-16
|
|
59
|
+
|
|
60
|
+
### Breaking Changes
|
|
61
|
+
|
|
62
|
+
### Added
|
|
63
|
+
|
|
64
|
+
- Extensions receive a per-handler `signal` on the `session_shutdown` event. The host aborts it when that handler exceeds its budget, so long shutdown work can stop cleanly instead of being left behind ([#1732](https://github.com/code-yeongyu/senpi/issues/1732)).
|
|
65
|
+
|
|
66
|
+
- Added the optional `ExtensionContext.kernelTools` capability with `describe(names)` and `invoke(request, signal?)`. It is present only while a JavaScript eval cell owns the host-tool context, so an extension tool called from inside that cell can reach the functions the cell registered with `tool(fn)`; on older runtimes and outside such a cell it is `undefined`. The package exports `kernelToolsStorage` and the `ExtensionKernelTools` type for hosts that install the capability ([#1647](https://github.com/code-yeongyu/senpi/issues/1647)).
|
|
67
|
+
|
|
68
|
+
### Changed
|
|
69
|
+
|
|
70
|
+
- Default `read` calls on eligible `.json` files now return the agent package's structural view, with the same declaration-safe folding and numeric `offset`/`limit` rereads, so edits after a read still target real lines. TypeScript and JavaScript stay raw because the measured candidate missed their quality thresholds. Prose, explicit ranges and the existing size-limit continuations produce the same output as before. `ReadToolOptions.folder` selects the folder; `createReadToolDefinition`, `createCodingTools` and `createReadOnlyTools` default it to `selectedReadFolder`, and an options object without `folder` keeps reads verbatim. Compiled binaries produce byte-identical read output to the source build, and no parser dependency is added ([#1639](https://github.com/code-yeongyu/senpi/issues/1639)).
|
|
71
|
+
|
|
72
|
+
### Fixed
|
|
73
|
+
|
|
74
|
+
- One extension can no longer hold quit, `/reload`, `/new`, `/resume` or a fork hostage: senpi now bounds every `session_shutdown` handler itself. A handler still running after `sessionShutdownHandlerWarnMs` (default 2000) logs one warning naming the extension, and at `sessionShutdownHandlerTimeoutMs` (default 10000) senpi aborts that handler's `event.signal`, reports an extension error naming it, and continues teardown with the remaining handlers. Set either setting to `0` to disable that half. Handlers that finish under the warning threshold are unaffected, and every other extension event keeps its uncapped wait (ask-user and approval dialogs may legitimately block for minutes) ([#1732](https://github.com/code-yeongyu/senpi/issues/1732)).
|
|
75
|
+
|
|
76
|
+
### Removed
|
|
77
|
+
|
|
78
|
+
## [2026.9.15-2] - 2026-09-15
|
|
79
|
+
|
|
80
|
+
### Breaking Changes
|
|
81
|
+
|
|
82
|
+
### Added
|
|
83
|
+
|
|
84
|
+
### Changed
|
|
85
|
+
|
|
86
|
+
- Standalone binaries load codemode from the staged on-disk package instead of embedding a second copy; the sidecar includes its JS parser dependency and retains the bun-1-4 skill ([#1656](https://github.com/code-yeongyu/senpi/issues/1656)).
|
|
87
|
+
|
|
88
|
+
### Fixed
|
|
89
|
+
|
|
90
|
+
- RPC `close_session` acknowledgements and `session_closed` events, including worker-failure terminals, are published only after the session registry has removed the entry, so an immediate `list_sessions` never returns the closed session. Filesystem watchers are cancelled atomically with shutdown, every disposer is joined before process exit, reentrant RPC shutdown shares that join and keeps a failure exit code, and nonpersistent RPC probes do not start watchers ([#1656](https://github.com/code-yeongyu/senpi/issues/1656)).
|
|
91
|
+
|
|
92
|
+
- The RPC host watchdog's ppid fallback no longer spawns `ps -o lstart=` every 250ms while the supervisor is alive: a dead supervisor is reaped by its own parent and the host is then reparented, so the free `kill(pid, 0)` + ppid comparison observes the loss without any child process. Long-lived shared hosts no longer accumulate thousands of `ps` children (zombies on runtimes that fail to reap them) ([#1507](https://github.com/code-yeongyu/senpi/issues/1507)).
|
|
93
|
+
|
|
94
|
+
- Terminal monitors no longer burn CPU while paused: a paused file watch clears its 250ms poll timer entirely (no stat/SHA-256 digest work) and resume runs one immediate check, so a change made during the pause still fires. Session-output line buffers are now capped at 64KiB, so a newline-less stream can no longer grow a monitor's retained tail without bound ([#1698](https://github.com/code-yeongyu/senpi/issues/1698)).
|
|
95
|
+
|
|
96
|
+
- Long, compaction-trimmed sessions no longer re-parse the entire session file every time the working/retry status animation cadence is decided (which periodically froze the UI on multi-day sessions): the cadence reads an O(1) maintained entry count, `SessionManager#getEntryCount()`; explicit full-history retrieval is unchanged ([#1699](https://github.com/code-yeongyu/senpi/issues/1699)).
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
- The Cursor CLI OAuth lane no longer spawns `cursor-agent models` on every senpi start. The startup catalog probe runs only when the lane is usable (not disabled, `cursor-agent` installed, at least one account bound), inside that account's HOME, and every `cursor-agent` spawn (turn, `models`, `--version`) now receives the same explicit environment allowlist instead of the inherited `process.env`. Hermetic or SSH-launched senpi processes therefore never trigger the CLI's macOS keychain preflight, which used to surface as a blocking "Keychain Not Found" dialog for `cursor-keychain-probe` on the logged-in console ([#1722](https://github.com/code-yeongyu/senpi/issues/1722)).
|
|
100
|
+
|
|
101
|
+
### Removed
|
|
102
|
+
|
|
15
103
|
## [2026.9.15] - 2026-09-15
|
|
16
104
|
|
|
17
105
|
### Breaking Changes
|
|
@@ -40,6 +128,7 @@
|
|
|
40
128
|
|
|
41
129
|
- Compiled Bun binaries load TypeScript extensions through native runtime modules instead of embedding jiti, preserving host-module identity and fresh dependency graphs on reload. Computed imports and requires share their generation, unused graphs can be reclaimed, native data imports keep Bun's loaders, and parser errors retain source locations. Node runtimes retain their existing jiti options and load only their own importer when needed ([#1656](https://github.com/code-yeongyu/senpi/issues/1656)).
|
|
42
130
|
|
|
131
|
+
|
|
43
132
|
### Fixed
|
|
44
133
|
|
|
45
134
|
- Fixed background processes surviving shutdown when the shell that started them exited first: the bash tool now keeps owning a command's process group until its last descendant is gone, so `sleep 30 &` or `nohup server &` is killed by shutdown cleanup instead of being orphaned. Tracked groups that have drained are pruned, and a group whose leader already exited is never re-signalled by bare pid ([#1697](https://github.com/code-yeongyu/senpi/issues/1697)).
|
package/README.md
CHANGED
|
@@ -194,7 +194,7 @@ Type `/` in the editor to trigger commands. [Extensions](#extensions) can regist
|
|
|
194
194
|
| `/settings` | Theme, message delivery, transport, and other preferences |
|
|
195
195
|
| `/resume` | Pick from previous sessions |
|
|
196
196
|
| `/new` | Start a new session |
|
|
197
|
-
| `/
|
|
197
|
+
| `/rename [name]` | Rename the current session (`/name` is an alias) |
|
|
198
198
|
| `/session` | Show session info (file, ID, messages, tokens, cost) |
|
|
199
199
|
| `/tree` | Jump to any point in the session and continue from there |
|
|
200
200
|
| `/trust` | Save project trust decision for future sessions (restart required) |
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ExtensionFlag, InlineExtension } from "../core/extensions/types.ts";
|
|
2
|
+
import type { SettingsManager } from "../core/settings-manager.ts";
|
|
3
|
+
export interface HelpExtensionFlagsResult {
|
|
4
|
+
readonly flags: ExtensionFlag[];
|
|
5
|
+
readonly extensionPaths: string[];
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Load extensions for their CLI flags and nothing else.
|
|
9
|
+
*
|
|
10
|
+
* Help renders flag descriptors, so this deliberately skips every other resource class and the
|
|
11
|
+
* whole model/session stack that `createAgentSessionServices` would build: skills, prompt
|
|
12
|
+
* templates, themes and context files cannot register a flag.
|
|
13
|
+
*/
|
|
14
|
+
export declare function resolveHelpExtensionFlags(options: {
|
|
15
|
+
readonly cwd: string;
|
|
16
|
+
readonly agentDir: string;
|
|
17
|
+
readonly settingsManager: SettingsManager;
|
|
18
|
+
readonly additionalExtensionPaths: readonly string[];
|
|
19
|
+
readonly noExtensions: boolean;
|
|
20
|
+
readonly extensionFactories?: readonly InlineExtension[];
|
|
21
|
+
}): Promise<HelpExtensionFlagsResult>;
|
|
22
|
+
//# sourceMappingURL=help-extension-flags.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help-extension-flags.d.ts","sourceRoot":"","sources":["../../src/cli/help-extension-flags.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAElF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAEnE,MAAM,WAAW,wBAAwB;IACxC,QAAQ,CAAC,KAAK,EAAE,aAAa,EAAE,CAAC;IAChC,QAAQ,CAAC,cAAc,EAAE,MAAM,EAAE,CAAC;CAClC;AAED;;;;;;GAMG;AACH,wBAAsB,yBAAyB,CAAC,OAAO,EAAE;IACxD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,QAAQ,CAAC,wBAAwB,EAAE,SAAS,MAAM,EAAE,CAAC;IACrD,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;CACzD,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAoBpC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { DefaultResourceLoader } from "../core/resource-loader.js";
|
|
2
|
+
/**
|
|
3
|
+
* Load extensions for their CLI flags and nothing else.
|
|
4
|
+
*
|
|
5
|
+
* Help renders flag descriptors, so this deliberately skips every other resource class and the
|
|
6
|
+
* whole model/session stack that `createAgentSessionServices` would build: skills, prompt
|
|
7
|
+
* templates, themes and context files cannot register a flag.
|
|
8
|
+
*/
|
|
9
|
+
export async function resolveHelpExtensionFlags(options) {
|
|
10
|
+
const resourceLoader = new DefaultResourceLoader({
|
|
11
|
+
cwd: options.cwd,
|
|
12
|
+
agentDir: options.agentDir,
|
|
13
|
+
settingsManager: options.settingsManager,
|
|
14
|
+
sharedHostEnabled: false,
|
|
15
|
+
additionalExtensionPaths: [...options.additionalExtensionPaths],
|
|
16
|
+
noExtensions: options.noExtensions,
|
|
17
|
+
noSkills: true,
|
|
18
|
+
noPromptTemplates: true,
|
|
19
|
+
noThemes: true,
|
|
20
|
+
noContextFiles: true,
|
|
21
|
+
...(options.extensionFactories ? { extensionFactories: [...options.extensionFactories] } : {}),
|
|
22
|
+
});
|
|
23
|
+
await resourceLoader.reload();
|
|
24
|
+
const { extensions } = resourceLoader.getExtensions();
|
|
25
|
+
return {
|
|
26
|
+
flags: extensions.flatMap((extension) => [...extension.flags.values()]),
|
|
27
|
+
extensionPaths: extensions.map((extension) => extension.resolvedPath),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=help-extension-flags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help-extension-flags.js","sourceRoot":"","sources":["../../src/cli/help-extension-flags.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAQnE;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,OAO/C;IACA,MAAM,cAAc,GAAG,IAAI,qBAAqB,CAAC;QAChD,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,eAAe,EAAE,OAAO,CAAC,eAAe;QACxC,iBAAiB,EAAE,KAAK;QACxB,wBAAwB,EAAE,CAAC,GAAG,OAAO,CAAC,wBAAwB,CAAC;QAC/D,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,QAAQ,EAAE,IAAI;QACd,iBAAiB,EAAE,IAAI;QACvB,QAAQ,EAAE,IAAI;QACd,cAAc,EAAE,IAAI;QACpB,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,CAAC,GAAG,OAAO,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9F,CAAC,CAAC;IACH,MAAM,cAAc,CAAC,MAAM,EAAE,CAAC;IAC9B,MAAM,EAAE,UAAU,EAAE,GAAG,cAAc,CAAC,aAAa,EAAE,CAAC;IACtD,OAAO;QACN,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QACvE,cAAc,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,YAAY,CAAC;KACrE,CAAC;AACH,CAAC","sourcesContent":["import type { ExtensionFlag, InlineExtension } from \"../core/extensions/types.ts\";\nimport { DefaultResourceLoader } from \"../core/resource-loader.ts\";\nimport type { SettingsManager } from \"../core/settings-manager.ts\";\n\nexport interface HelpExtensionFlagsResult {\n\treadonly flags: ExtensionFlag[];\n\treadonly extensionPaths: string[];\n}\n\n/**\n * Load extensions for their CLI flags and nothing else.\n *\n * Help renders flag descriptors, so this deliberately skips every other resource class and the\n * whole model/session stack that `createAgentSessionServices` would build: skills, prompt\n * templates, themes and context files cannot register a flag.\n */\nexport async function resolveHelpExtensionFlags(options: {\n\treadonly cwd: string;\n\treadonly agentDir: string;\n\treadonly settingsManager: SettingsManager;\n\treadonly additionalExtensionPaths: readonly string[];\n\treadonly noExtensions: boolean;\n\treadonly extensionFactories?: readonly InlineExtension[];\n}): Promise<HelpExtensionFlagsResult> {\n\tconst resourceLoader = new DefaultResourceLoader({\n\t\tcwd: options.cwd,\n\t\tagentDir: options.agentDir,\n\t\tsettingsManager: options.settingsManager,\n\t\tsharedHostEnabled: false,\n\t\tadditionalExtensionPaths: [...options.additionalExtensionPaths],\n\t\tnoExtensions: options.noExtensions,\n\t\tnoSkills: true,\n\t\tnoPromptTemplates: true,\n\t\tnoThemes: true,\n\t\tnoContextFiles: true,\n\t\t...(options.extensionFactories ? { extensionFactories: [...options.extensionFactories] } : {}),\n\t});\n\tawait resourceLoader.reload();\n\tconst { extensions } = resourceLoader.getExtensions();\n\treturn {\n\t\tflags: extensions.flatMap((extension) => [...extension.flags.values()]),\n\t\textensionPaths: extensions.map((extension) => extension.resolvedPath),\n\t};\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type Args } from "./args.ts";
|
|
2
|
+
import { type HelpFlagsScope } from "./help-flags-cache.ts";
|
|
3
|
+
export declare function isPlainHelpRequest(parsed: Args): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* A help screen never prompts for project trust and never runs project-local extension code
|
|
6
|
+
* the user has not already trusted: only a recorded decision, or an explicit override, lets
|
|
7
|
+
* project resources in.
|
|
8
|
+
*/
|
|
9
|
+
export declare function resolveHelpProjectTrust(parsed: Args, cwd: string, agentDir: string): boolean;
|
|
10
|
+
export declare function helpFlagsScope(parsed: Args, cwd: string, agentDir: string, projectTrusted: boolean): HelpFlagsScope;
|
|
11
|
+
/**
|
|
12
|
+
* Answer `--help` before the engine module graph is imported.
|
|
13
|
+
*
|
|
14
|
+
* Returns false for every launch it cannot answer from what is already known - a non-plain help
|
|
15
|
+
* request, or a scope whose cached flags are missing or stale - and the normal startup path then
|
|
16
|
+
* resolves the flags and refills the cache.
|
|
17
|
+
*/
|
|
18
|
+
export declare function tryPrintHelpWithoutEngine(argv: readonly string[]): boolean;
|
|
19
|
+
//# sourceMappingURL=help-fast-path.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help-fast-path.d.ts","sourceRoot":"","sources":["../../src/cli/help-fast-path.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,IAAI,EAAwB,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,KAAK,cAAc,EAAsB,MAAM,uBAAuB,CAAC;AAEhF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,IAAI,GAAG,OAAO,CAExD;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAI5F;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,GAAG,cAAc,CAQnH;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAuB1E"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { getAgentDir } from "../config.js";
|
|
2
|
+
import { hasTrustRequiringProjectResources, ProjectTrustStore } from "../core/trust-manager.js";
|
|
3
|
+
import { parseArgs, printHelp } from "./args.js";
|
|
4
|
+
import { readHelpFlagsCache } from "./help-flags-cache.js";
|
|
5
|
+
export function isPlainHelpRequest(parsed) {
|
|
6
|
+
return parsed.help === true && parsed.print !== true && parsed.mode === undefined;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* A help screen never prompts for project trust and never runs project-local extension code
|
|
10
|
+
* the user has not already trusted: only a recorded decision, or an explicit override, lets
|
|
11
|
+
* project resources in.
|
|
12
|
+
*/
|
|
13
|
+
export function resolveHelpProjectTrust(parsed, cwd, agentDir) {
|
|
14
|
+
if (parsed.projectTrustOverride !== undefined)
|
|
15
|
+
return parsed.projectTrustOverride;
|
|
16
|
+
if (!hasTrustRequiringProjectResources(cwd))
|
|
17
|
+
return true;
|
|
18
|
+
return new ProjectTrustStore(agentDir).get(cwd) === true;
|
|
19
|
+
}
|
|
20
|
+
export function helpFlagsScope(parsed, cwd, agentDir, projectTrusted) {
|
|
21
|
+
return {
|
|
22
|
+
cwd,
|
|
23
|
+
agentDir,
|
|
24
|
+
cliExtensionPaths: [...(parsed.extensions ?? [])],
|
|
25
|
+
noExtensions: parsed.noExtensions === true,
|
|
26
|
+
projectTrusted,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Answer `--help` before the engine module graph is imported.
|
|
31
|
+
*
|
|
32
|
+
* Returns false for every launch it cannot answer from what is already known - a non-plain help
|
|
33
|
+
* request, or a scope whose cached flags are missing or stale - and the normal startup path then
|
|
34
|
+
* resolves the flags and refills the cache.
|
|
35
|
+
*/
|
|
36
|
+
export function tryPrintHelpWithoutEngine(argv) {
|
|
37
|
+
let parsed;
|
|
38
|
+
try {
|
|
39
|
+
parsed = parseArgs([...argv]);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
if (!isPlainHelpRequest(parsed) || parsed.diagnostics.length > 0)
|
|
45
|
+
return false;
|
|
46
|
+
if (parsed.noExtensions === true) {
|
|
47
|
+
printHelp([]);
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
let flags;
|
|
51
|
+
try {
|
|
52
|
+
const cwd = process.cwd();
|
|
53
|
+
const agentDir = getAgentDir();
|
|
54
|
+
flags = readHelpFlagsCache(helpFlagsScope(parsed, cwd, agentDir, resolveHelpProjectTrust(parsed, cwd, agentDir)));
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
if (!flags)
|
|
60
|
+
return false;
|
|
61
|
+
printHelp(flags);
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=help-fast-path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help-fast-path.js","sourceRoot":"","sources":["../../src/cli/help-fast-path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,iCAAiC,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAChG,OAAO,EAAa,SAAS,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAuB,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhF,MAAM,UAAU,kBAAkB,CAAC,MAAY;IAC9C,OAAO,MAAM,CAAC,IAAI,KAAK,IAAI,IAAI,MAAM,CAAC,KAAK,KAAK,IAAI,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC;AACnF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAY,EAAE,GAAW,EAAE,QAAgB;IAClF,IAAI,MAAM,CAAC,oBAAoB,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC,oBAAoB,CAAC;IAClF,IAAI,CAAC,iCAAiC,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACzD,OAAO,IAAI,iBAAiB,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAY,EAAE,GAAW,EAAE,QAAgB,EAAE,cAAuB;IAClG,OAAO;QACN,GAAG;QACH,QAAQ;QACR,iBAAiB,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;QACjD,YAAY,EAAE,MAAM,CAAC,YAAY,KAAK,IAAI;QAC1C,cAAc;KACd,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB,CAAC,IAAuB;IAChE,IAAI,MAAY,CAAC;IACjB,IAAI,CAAC;QACJ,MAAM,GAAG,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAC;IACd,CAAC;IACD,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAC/E,IAAI,MAAM,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;QAClC,SAAS,CAAC,EAAE,CAAC,CAAC;QACd,OAAO,IAAI,CAAC;IACb,CAAC;IACD,IAAI,KAAkC,CAAC;IACvC,IAAI,CAAC;QACJ,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAC1B,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;QAC/B,KAAK,GAAG,kBAAkB,CAAC,cAAc,CAAC,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,uBAAuB,CAAC,MAAM,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IACnH,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAC;IACd,CAAC;IACD,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,SAAS,CAAC,KAAK,CAAC,CAAC;IACjB,OAAO,IAAI,CAAC;AACb,CAAC","sourcesContent":["import { getAgentDir } from \"../config.ts\";\nimport type { ExtensionFlag } from \"../core/extensions/types.ts\";\nimport { hasTrustRequiringProjectResources, ProjectTrustStore } from \"../core/trust-manager.ts\";\nimport { type Args, parseArgs, printHelp } from \"./args.ts\";\nimport { type HelpFlagsScope, readHelpFlagsCache } from \"./help-flags-cache.ts\";\n\nexport function isPlainHelpRequest(parsed: Args): boolean {\n\treturn parsed.help === true && parsed.print !== true && parsed.mode === undefined;\n}\n\n/**\n * A help screen never prompts for project trust and never runs project-local extension code\n * the user has not already trusted: only a recorded decision, or an explicit override, lets\n * project resources in.\n */\nexport function resolveHelpProjectTrust(parsed: Args, cwd: string, agentDir: string): boolean {\n\tif (parsed.projectTrustOverride !== undefined) return parsed.projectTrustOverride;\n\tif (!hasTrustRequiringProjectResources(cwd)) return true;\n\treturn new ProjectTrustStore(agentDir).get(cwd) === true;\n}\n\nexport function helpFlagsScope(parsed: Args, cwd: string, agentDir: string, projectTrusted: boolean): HelpFlagsScope {\n\treturn {\n\t\tcwd,\n\t\tagentDir,\n\t\tcliExtensionPaths: [...(parsed.extensions ?? [])],\n\t\tnoExtensions: parsed.noExtensions === true,\n\t\tprojectTrusted,\n\t};\n}\n\n/**\n * Answer `--help` before the engine module graph is imported.\n *\n * Returns false for every launch it cannot answer from what is already known - a non-plain help\n * request, or a scope whose cached flags are missing or stale - and the normal startup path then\n * resolves the flags and refills the cache.\n */\nexport function tryPrintHelpWithoutEngine(argv: readonly string[]): boolean {\n\tlet parsed: Args;\n\ttry {\n\t\tparsed = parseArgs([...argv]);\n\t} catch {\n\t\treturn false;\n\t}\n\tif (!isPlainHelpRequest(parsed) || parsed.diagnostics.length > 0) return false;\n\tif (parsed.noExtensions === true) {\n\t\tprintHelp([]);\n\t\treturn true;\n\t}\n\tlet flags: ExtensionFlag[] | undefined;\n\ttry {\n\t\tconst cwd = process.cwd();\n\t\tconst agentDir = getAgentDir();\n\t\tflags = readHelpFlagsCache(helpFlagsScope(parsed, cwd, agentDir, resolveHelpProjectTrust(parsed, cwd, agentDir)));\n\t} catch {\n\t\treturn false;\n\t}\n\tif (!flags) return false;\n\tprintHelp(flags);\n\treturn true;\n}\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ExtensionFlag } from "../core/extensions/types.ts";
|
|
2
|
+
export interface HelpFlagsScope {
|
|
3
|
+
readonly cwd: string;
|
|
4
|
+
readonly agentDir: string;
|
|
5
|
+
readonly cliExtensionPaths: readonly string[];
|
|
6
|
+
readonly noExtensions: boolean;
|
|
7
|
+
readonly projectTrusted: boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Flags a previous run resolved for this exact scope, or `undefined` when anything that feeds
|
|
11
|
+
* extension discovery changed. Never throws: a help screen must not depend on its own cache.
|
|
12
|
+
*/
|
|
13
|
+
export declare function readHelpFlagsCache(scope: HelpFlagsScope): ExtensionFlag[] | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Record the flags a full extension load produced. Failure is silent by contract: this runs on
|
|
16
|
+
* the startup path, where a cache write must never be the reason a launch fails.
|
|
17
|
+
*/
|
|
18
|
+
export declare function writeHelpFlagsCache(options: {
|
|
19
|
+
readonly scope: HelpFlagsScope;
|
|
20
|
+
readonly flags: readonly ExtensionFlag[];
|
|
21
|
+
readonly extensionPaths: readonly string[];
|
|
22
|
+
}): void;
|
|
23
|
+
//# sourceMappingURL=help-flags-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help-flags-cache.d.ts","sourceRoot":"","sources":["../../src/cli/help-flags-cache.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAKjE,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9C,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;CACjC;AAgFD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,GAAG,aAAa,EAAE,GAAG,SAAS,CAOrF;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE;IAC5C,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAC;IACzC,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3C,GAAG,IAAI,CA4BP"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { dirname, isAbsolute, join } from "node:path";
|
|
4
|
+
import { CONFIG_DIR_NAME, DISPLAY_VERSION } from "../config.js";
|
|
5
|
+
const CACHE_FILE_VERSION = 1;
|
|
6
|
+
const MAX_CACHED_SCOPES = 8;
|
|
7
|
+
function cachePath(agentDir) {
|
|
8
|
+
return join(agentDir, "cache", "help-flags.json");
|
|
9
|
+
}
|
|
10
|
+
function scopeKey(scope) {
|
|
11
|
+
const material = [
|
|
12
|
+
scope.cwd,
|
|
13
|
+
scope.noExtensions ? "no-extensions" : "extensions",
|
|
14
|
+
scope.projectTrusted ? "trusted" : "untrusted",
|
|
15
|
+
...scope.cliExtensionPaths,
|
|
16
|
+
].join("\u0000");
|
|
17
|
+
return createHash("sha256").update(material).digest("hex").slice(0, 32);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A path's identity for cache validation. Directories carry only their mtime, which is what
|
|
21
|
+
* changes when an extension file is added or removed inside them; files carry mtime and size,
|
|
22
|
+
* so an in-place upgrade of a bundled plugin invalidates the entry it produced.
|
|
23
|
+
*/
|
|
24
|
+
function stamp(path) {
|
|
25
|
+
try {
|
|
26
|
+
const stats = statSync(path);
|
|
27
|
+
if (stats.isDirectory())
|
|
28
|
+
return `d:${stats.mtimeMs}`;
|
|
29
|
+
return `f:${stats.mtimeMs}:${stats.size}`;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return "absent";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function discoveryInputs(scope, extensionPaths) {
|
|
36
|
+
const paths = new Set([
|
|
37
|
+
join(scope.agentDir, "settings.json"),
|
|
38
|
+
join(scope.agentDir, "extensions"),
|
|
39
|
+
join(scope.agentDir, "trust.json"),
|
|
40
|
+
join(scope.cwd, CONFIG_DIR_NAME, "settings.json"),
|
|
41
|
+
join(scope.cwd, CONFIG_DIR_NAME, "extensions"),
|
|
42
|
+
]);
|
|
43
|
+
for (const path of extensionPaths) {
|
|
44
|
+
if (!isAbsolute(path))
|
|
45
|
+
continue;
|
|
46
|
+
paths.add(path);
|
|
47
|
+
paths.add(dirname(path));
|
|
48
|
+
}
|
|
49
|
+
for (const path of scope.cliExtensionPaths) {
|
|
50
|
+
if (!isAbsolute(path))
|
|
51
|
+
continue;
|
|
52
|
+
paths.add(path);
|
|
53
|
+
}
|
|
54
|
+
return [...paths].sort();
|
|
55
|
+
}
|
|
56
|
+
function readCacheFile(agentDir) {
|
|
57
|
+
try {
|
|
58
|
+
const parsed = JSON.parse(readFileSync(cachePath(agentDir), "utf8"));
|
|
59
|
+
if (parsed.version !== CACHE_FILE_VERSION || typeof parsed.scopes !== "object" || parsed.scopes === null) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
return parsed;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Flags a previous run resolved for this exact scope, or `undefined` when anything that feeds
|
|
70
|
+
* extension discovery changed. Never throws: a help screen must not depend on its own cache.
|
|
71
|
+
*/
|
|
72
|
+
export function readHelpFlagsCache(scope) {
|
|
73
|
+
const cached = readCacheFile(scope.agentDir)?.scopes[scopeKey(scope)];
|
|
74
|
+
if (!cached || cached.appVersion !== DISPLAY_VERSION || !Array.isArray(cached.inputs))
|
|
75
|
+
return undefined;
|
|
76
|
+
for (const input of cached.inputs) {
|
|
77
|
+
if (stamp(input.path) !== input.state)
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
return [...cached.flags];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Record the flags a full extension load produced. Failure is silent by contract: this runs on
|
|
84
|
+
* the startup path, where a cache write must never be the reason a launch fails.
|
|
85
|
+
*/
|
|
86
|
+
export function writeHelpFlagsCache(options) {
|
|
87
|
+
const { scope, flags, extensionPaths } = options;
|
|
88
|
+
try {
|
|
89
|
+
const existing = readCacheFile(scope.agentDir);
|
|
90
|
+
const scopes = { ...(existing?.scopes ?? {}) };
|
|
91
|
+
scopes[scopeKey(scope)] = {
|
|
92
|
+
writtenAt: Date.now(),
|
|
93
|
+
appVersion: DISPLAY_VERSION,
|
|
94
|
+
inputs: discoveryInputs(scope, extensionPaths).map((path) => ({ path, state: stamp(path) })),
|
|
95
|
+
flags: [...flags],
|
|
96
|
+
};
|
|
97
|
+
const keptEntries = Object.entries(scopes)
|
|
98
|
+
.sort(([, left], [, right]) => right.writtenAt - left.writtenAt)
|
|
99
|
+
.slice(0, MAX_CACHED_SCOPES);
|
|
100
|
+
const file = { version: CACHE_FILE_VERSION, scopes: Object.fromEntries(keptEntries) };
|
|
101
|
+
const target = cachePath(scope.agentDir);
|
|
102
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
103
|
+
const temporary = `${target}.${process.pid}.tmp`;
|
|
104
|
+
writeFileSync(temporary, JSON.stringify(file), { mode: 0o600 });
|
|
105
|
+
try {
|
|
106
|
+
renameSync(temporary, target);
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
if (existsSync(temporary))
|
|
110
|
+
rmSync(temporary, { force: true });
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=help-flags-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help-flags-cache.js","sourceRoot":"","sources":["../../src/cli/help-flags-cache.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from \"node:fs\";\nimport { dirname, isAbsolute, join } from \"node:path\";\nimport { CONFIG_DIR_NAME, DISPLAY_VERSION } from \"../config.ts\";\nimport type { ExtensionFlag } from \"../core/extensions/types.ts\";\n\nconst CACHE_FILE_VERSION = 1;\nconst MAX_CACHED_SCOPES = 8;\n\nexport interface HelpFlagsScope {\n\treadonly cwd: string;\n\treadonly agentDir: string;\n\treadonly cliExtensionPaths: readonly string[];\n\treadonly noExtensions: boolean;\n\treadonly projectTrusted: boolean;\n}\n\ninterface InputStamp {\n\treadonly path: string;\n\treadonly state: string;\n}\n\ninterface CachedScope {\n\treadonly writtenAt: number;\n\treadonly appVersion: string;\n\treadonly inputs: readonly InputStamp[];\n\treadonly flags: readonly ExtensionFlag[];\n}\n\ninterface CacheFile {\n\treadonly version: number;\n\treadonly scopes: Record<string, CachedScope>;\n}\n\nfunction cachePath(agentDir: string): string {\n\treturn join(agentDir, \"cache\", \"help-flags.json\");\n}\n\nfunction scopeKey(scope: HelpFlagsScope): string {\n\tconst material = [\n\t\tscope.cwd,\n\t\tscope.noExtensions ? \"no-extensions\" : \"extensions\",\n\t\tscope.projectTrusted ? \"trusted\" : \"untrusted\",\n\t\t...scope.cliExtensionPaths,\n\t].join(\"\\u0000\");\n\treturn createHash(\"sha256\").update(material).digest(\"hex\").slice(0, 32);\n}\n\n/**\n * A path's identity for cache validation. Directories carry only their mtime, which is what\n * changes when an extension file is added or removed inside them; files carry mtime and size,\n * so an in-place upgrade of a bundled plugin invalidates the entry it produced.\n */\nfunction stamp(path: string): string {\n\ttry {\n\t\tconst stats = statSync(path);\n\t\tif (stats.isDirectory()) return `d:${stats.mtimeMs}`;\n\t\treturn `f:${stats.mtimeMs}:${stats.size}`;\n\t} catch {\n\t\treturn \"absent\";\n\t}\n}\n\nfunction discoveryInputs(scope: HelpFlagsScope, extensionPaths: readonly string[]): string[] {\n\tconst paths = new Set<string>([\n\t\tjoin(scope.agentDir, \"settings.json\"),\n\t\tjoin(scope.agentDir, \"extensions\"),\n\t\tjoin(scope.agentDir, \"trust.json\"),\n\t\tjoin(scope.cwd, CONFIG_DIR_NAME, \"settings.json\"),\n\t\tjoin(scope.cwd, CONFIG_DIR_NAME, \"extensions\"),\n\t]);\n\tfor (const path of extensionPaths) {\n\t\tif (!isAbsolute(path)) continue;\n\t\tpaths.add(path);\n\t\tpaths.add(dirname(path));\n\t}\n\tfor (const path of scope.cliExtensionPaths) {\n\t\tif (!isAbsolute(path)) continue;\n\t\tpaths.add(path);\n\t}\n\treturn [...paths].sort();\n}\n\nfunction readCacheFile(agentDir: string): CacheFile | undefined {\n\ttry {\n\t\tconst parsed = JSON.parse(readFileSync(cachePath(agentDir), \"utf8\")) as CacheFile;\n\t\tif (parsed.version !== CACHE_FILE_VERSION || typeof parsed.scopes !== \"object\" || parsed.scopes === null) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn parsed;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Flags a previous run resolved for this exact scope, or `undefined` when anything that feeds\n * extension discovery changed. Never throws: a help screen must not depend on its own cache.\n */\nexport function readHelpFlagsCache(scope: HelpFlagsScope): ExtensionFlag[] | undefined {\n\tconst cached = readCacheFile(scope.agentDir)?.scopes[scopeKey(scope)];\n\tif (!cached || cached.appVersion !== DISPLAY_VERSION || !Array.isArray(cached.inputs)) return undefined;\n\tfor (const input of cached.inputs) {\n\t\tif (stamp(input.path) !== input.state) return undefined;\n\t}\n\treturn [...cached.flags];\n}\n\n/**\n * Record the flags a full extension load produced. Failure is silent by contract: this runs on\n * the startup path, where a cache write must never be the reason a launch fails.\n */\nexport function writeHelpFlagsCache(options: {\n\treadonly scope: HelpFlagsScope;\n\treadonly flags: readonly ExtensionFlag[];\n\treadonly extensionPaths: readonly string[];\n}): void {\n\tconst { scope, flags, extensionPaths } = options;\n\ttry {\n\t\tconst existing = readCacheFile(scope.agentDir);\n\t\tconst scopes: Record<string, CachedScope> = { ...(existing?.scopes ?? {}) };\n\t\tscopes[scopeKey(scope)] = {\n\t\t\twrittenAt: Date.now(),\n\t\t\tappVersion: DISPLAY_VERSION,\n\t\t\tinputs: discoveryInputs(scope, extensionPaths).map((path) => ({ path, state: stamp(path) })),\n\t\t\tflags: [...flags],\n\t\t};\n\t\tconst keptEntries = Object.entries(scopes)\n\t\t\t.sort(([, left], [, right]) => right.writtenAt - left.writtenAt)\n\t\t\t.slice(0, MAX_CACHED_SCOPES);\n\t\tconst file: CacheFile = { version: CACHE_FILE_VERSION, scopes: Object.fromEntries(keptEntries) };\n\t\tconst target = cachePath(scope.agentDir);\n\t\tmkdirSync(dirname(target), { recursive: true });\n\t\tconst temporary = `${target}.${process.pid}.tmp`;\n\t\twriteFileSync(temporary, JSON.stringify(file), { mode: 0o600 });\n\t\ttry {\n\t\t\trenameSync(temporary, target);\n\t\t} catch (error) {\n\t\t\tif (existsSync(temporary)) rmSync(temporary, { force: true });\n\t\t\tthrow error;\n\t\t}\n\t} catch {\n\t\treturn;\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"startup-loading-indicator.d.ts","sourceRoot":"","sources":["../../src/cli/startup-loading-indicator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAaxD,MAAM,WAAW,8BAA8B;IAC9C,QAAQ,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,uBAAuB;IACvC,KAAK,IAAI,IAAI,CAAC;IACd,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IAC1C,KAAK,IAAI,IAAI,CAAC;IACd,MAAM,IAAI,IAAI,CAAC;IACf,IAAI,IAAI,IAAI,CAAC;IACb,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC1B;
|
|
1
|
+
{"version":3,"file":"startup-loading-indicator.d.ts","sourceRoot":"","sources":["../../src/cli/startup-loading-indicator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAaxD,MAAM,WAAW,8BAA8B;IAC9C,QAAQ,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,uBAAuB;IACvC,KAAK,IAAI,IAAI,CAAC;IACd,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IAC1C,KAAK,IAAI,IAAI,CAAC;IACd,MAAM,IAAI,IAAI,CAAC;IACf,IAAI,IAAI,IAAI,CAAC;IACb,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC1B;AAmID,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,8BAA8B,GAAG,uBAAuB,CAE9G;AAED,wBAAgB,iCAAiC,CAAC,KAAK,EAAE;IACxD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;CAChC,GAAG,OAAO,CAEV;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAC1C,OAAO,EAAE,mBAAmB,EAC5B,SAAS,EAAE,IAAI,CAAC,uBAAuB,EAAE,OAAO,GAAG,QAAQ,CAAC,GAC1D,mBAAmB,CAsBrB"}
|
|
@@ -10,9 +10,12 @@ const DEFAULT_INTERVAL_MS = 80;
|
|
|
10
10
|
/**
|
|
11
11
|
* Single-line ANSI loading indicator for the pre-TUI startup window, borrowed
|
|
12
12
|
* from codex's UI-first startup design (codex-rs/tui keeps a dim placeholder
|
|
13
|
-
* header until the session is configured). The
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
* header until the session is configured). The first frame is written in
|
|
14
|
+
* start() itself: the work it covers is synchronous module loading, which
|
|
15
|
+
* starves every timer until it is done, so a timer-driven first frame lands
|
|
16
|
+
* only after that work (measured: 2.27s to the first byte on a real pty). The
|
|
17
|
+
* grace delay now gates the animation only; stop() must run before any other
|
|
18
|
+
* stdout writer (TUI, prompts, help) takes over the terminal.
|
|
16
19
|
*/
|
|
17
20
|
class AnsiStartupLoadingIndicator {
|
|
18
21
|
constructor(options) {
|
|
@@ -45,6 +48,7 @@ class AnsiStartupLoadingIndicator {
|
|
|
45
48
|
this.writer(CLEAR_LINE + SHOW_CURSOR);
|
|
46
49
|
};
|
|
47
50
|
process.on("exit", this.exitListener);
|
|
51
|
+
this.draw(true);
|
|
48
52
|
this.startGraceTimer();
|
|
49
53
|
}
|
|
50
54
|
setPhase(phase) {
|
|
@@ -68,6 +72,7 @@ class AnsiStartupLoadingIndicator {
|
|
|
68
72
|
this.beginAnimation();
|
|
69
73
|
}
|
|
70
74
|
else {
|
|
75
|
+
this.draw(true);
|
|
71
76
|
this.startGraceTimer();
|
|
72
77
|
}
|
|
73
78
|
}
|
|
@@ -89,7 +94,8 @@ class AnsiStartupLoadingIndicator {
|
|
|
89
94
|
}, this.graceMs);
|
|
90
95
|
}
|
|
91
96
|
beginAnimation() {
|
|
92
|
-
this.
|
|
97
|
+
if (!this.drawn)
|
|
98
|
+
this.draw(true);
|
|
93
99
|
this.frameTimer = setInterval(() => {
|
|
94
100
|
this.frameIndex = (this.frameIndex + 1) % this.frames.length;
|
|
95
101
|
this.draw(false);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"startup-loading-indicator.js","sourceRoot":"","sources":["../../src/cli/startup-loading-indicator.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ProjectTrustContext } from \"../core/extensions/types.ts\";\nimport type { AppMode } from \"../core/project-trust.ts\";\n\nconst HIDE_CURSOR = \"\\u001b[?25l\";\nconst SHOW_CURSOR = \"\\u001b[?25h\";\nconst CLEAR_LINE = \"\\r\\u001b[2K\";\nconst DIM = \"\\u001b[2m\";\nconst RESET = \"\\u001b[0m\";\n\nconst DEFAULT_FRAMES = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"] as const;\nconst DEFAULT_LABEL = \"Loading\";\nconst DEFAULT_GRACE_MS = 120;\nconst DEFAULT_INTERVAL_MS = 80;\n\nexport interface StartupLoadingIndicatorOptions {\n\treadonly writer: (chunk: string) => void;\n\treadonly isTTY: boolean;\n\treadonly label?: string;\n\treadonly graceMs?: number;\n\treadonly intervalMs?: number;\n\treadonly frames?: readonly string[];\n}\n\nexport interface StartupLoadingIndicator {\n\tstart(): void;\n\tsetPhase(phase: string | undefined): void;\n\tpause(): void;\n\tresume(): void;\n\tstop(): void;\n\treadonly running: boolean;\n}\n\n/**\n * Single-line ANSI loading indicator for the pre-TUI startup window, borrowed\n * from codex's UI-first startup design (codex-rs/tui keeps a dim placeholder\n * header until the session is configured). The grace delay keeps fast startups\n * flash-free; stop() must run before any other stdout writer (TUI, prompts,\n * help) takes over the terminal.\n */\nclass AnsiStartupLoadingIndicator implements StartupLoadingIndicator {\n\tprivate readonly writer: (chunk: string) => void;\n\tprivate readonly isTTY: boolean;\n\tprivate readonly label: string;\n\tprivate readonly graceMs: number;\n\tprivate readonly intervalMs: number;\n\tprivate readonly frames: readonly string[];\n\tprivate phase: string | undefined = undefined;\n\tprivate frameIndex = 0;\n\tprivate drawn = false;\n\tprivate graceElapsed = false;\n\tprivate started = false;\n\tprivate paused = false;\n\tprivate stopped = false;\n\tprivate graceTimer: NodeJS.Timeout | undefined = undefined;\n\tprivate frameTimer: NodeJS.Timeout | undefined = undefined;\n\tprivate exitListener: (() => void) | undefined = undefined;\n\n\tconstructor(options: StartupLoadingIndicatorOptions) {\n\t\tthis.writer = options.writer;\n\t\tthis.isTTY = options.isTTY;\n\t\tthis.label = options.label ?? DEFAULT_LABEL;\n\t\tthis.graceMs = options.graceMs ?? DEFAULT_GRACE_MS;\n\t\tthis.intervalMs = options.intervalMs ?? DEFAULT_INTERVAL_MS;\n\t\tthis.frames = options.frames && options.frames.length > 0 ? options.frames : DEFAULT_FRAMES;\n\t}\n\n\tget running(): boolean {\n\t\treturn this.started && !this.stopped;\n\t}\n\n\tstart(): void {\n\t\tif (!this.isTTY || this.started || this.stopped) return;\n\t\tthis.started = true;\n\t\tthis.exitListener = () => {\n\t\t\tif (this.drawn) this.writer(CLEAR_LINE + SHOW_CURSOR);\n\t\t};\n\t\tprocess.on(\"exit\", this.exitListener);\n\t\tthis.startGraceTimer();\n\t}\n\n\tsetPhase(phase: string | undefined): void {\n\t\tthis.phase = phase;\n\t\tif (this.drawn && !this.paused && !this.stopped) {\n\t\t\tthis.draw(false);\n\t\t}\n\t}\n\n\tpause(): void {\n\t\tif (!this.started || this.stopped || this.paused) return;\n\t\tthis.paused = true;\n\t\tthis.clearTimers();\n\t\tthis.eraseLine();\n\t}\n\n\tresume(): void {\n\t\tif (!this.started || this.stopped || !this.paused) return;\n\t\tthis.paused = false;\n\t\tif (this.graceElapsed) {\n\t\t\tthis.beginAnimation();\n\t\t} else {\n\t\t\tthis.startGraceTimer();\n\t\t}\n\t}\n\n\tstop(): void {\n\t\tif (this.stopped) return;\n\t\tthis.stopped = true;\n\t\tthis.clearTimers();\n\t\tthis.eraseLine();\n\t\tif (this.exitListener) {\n\t\t\tprocess.removeListener(\"exit\", this.exitListener);\n\t\t\tthis.exitListener = undefined;\n\t\t}\n\t}\n\n\tprivate startGraceTimer(): void {\n\t\tthis.graceTimer = setTimeout(() => {\n\t\t\tthis.graceElapsed = true;\n\t\t\tthis.beginAnimation();\n\t\t}, this.graceMs);\n\t}\n\n\tprivate beginAnimation(): void {\n\t\tthis.draw(true);\n\t\tthis.frameTimer = setInterval(() => {\n\t\t\tthis.frameIndex = (this.frameIndex + 1) % this.frames.length;\n\t\t\tthis.draw(false);\n\t\t}, this.intervalMs);\n\t}\n\n\tprivate draw(hideCursor: boolean): void {\n\t\tconst frame = this.frames[this.frameIndex] ?? \"\";\n\t\tconst phaseSuffix = this.phase ? ` ${this.phase}` : \"\";\n\t\tconst line = `${DIM}${frame} ${this.label}…${phaseSuffix}${RESET}`;\n\t\tthis.writer(`${hideCursor ? HIDE_CURSOR : \"\"}${CLEAR_LINE}${line}`);\n\t\tthis.drawn = true;\n\t}\n\n\tprivate eraseLine(): void {\n\t\tif (!this.drawn) return;\n\t\tthis.writer(CLEAR_LINE + SHOW_CURSOR);\n\t\tthis.drawn = false;\n\t}\n\n\tprivate clearTimers(): void {\n\t\tif (this.graceTimer) {\n\t\t\tclearTimeout(this.graceTimer);\n\t\t\tthis.graceTimer = undefined;\n\t\t}\n\t\tif (this.frameTimer) {\n\t\t\tclearInterval(this.frameTimer);\n\t\t\tthis.frameTimer = undefined;\n\t\t}\n\t}\n}\n\nexport function createStartupLoadingIndicator(options: StartupLoadingIndicatorOptions): StartupLoadingIndicator {\n\treturn new AnsiStartupLoadingIndicator(options);\n}\n\nexport function shouldShowStartupLoadingIndicator(input: {\n\treadonly appMode: AppMode;\n\treadonly stdoutIsTTY: boolean;\n\treadonly helpRequested: boolean;\n}): boolean {\n\treturn input.appMode === \"interactive\" && input.stdoutIsTTY && !input.helpRequested;\n}\n\n/**\n * Project-trust prompts open their own startup TUI mid-load; pausing the\n * indicator around each prompt keeps the two from fighting over the terminal.\n */\nexport function pauseIndicatorDuringPrompts(\n\tcontext: ProjectTrustContext,\n\tindicator: Pick<StartupLoadingIndicator, \"pause\" | \"resume\">,\n): ProjectTrustContext {\n\tconst wrapPrompt =\n\t\t<Args extends readonly unknown[], Result>(\n\t\t\tprompt: (...args: Args) => Promise<Result>,\n\t\t): ((...args: Args) => Promise<Result>) =>\n\t\tasync (...args: Args): Promise<Result> => {\n\t\t\tindicator.pause();\n\t\t\ttry {\n\t\t\t\treturn await prompt(...args);\n\t\t\t} finally {\n\t\t\t\tindicator.resume();\n\t\t\t}\n\t\t};\n\treturn {\n\t\t...context,\n\t\tui: {\n\t\t\tselect: wrapPrompt(context.ui.select),\n\t\t\tconfirm: wrapPrompt(context.ui.confirm),\n\t\t\tinput: wrapPrompt(context.ui.input),\n\t\t\tnotify: context.ui.notify,\n\t\t},\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"startup-loading-indicator.js","sourceRoot":"","sources":["../../src/cli/startup-loading-indicator.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ProjectTrustContext } from \"../core/extensions/types.ts\";\nimport type { AppMode } from \"../core/project-trust.ts\";\n\nconst HIDE_CURSOR = \"\\u001b[?25l\";\nconst SHOW_CURSOR = \"\\u001b[?25h\";\nconst CLEAR_LINE = \"\\r\\u001b[2K\";\nconst DIM = \"\\u001b[2m\";\nconst RESET = \"\\u001b[0m\";\n\nconst DEFAULT_FRAMES = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"] as const;\nconst DEFAULT_LABEL = \"Loading\";\nconst DEFAULT_GRACE_MS = 120;\nconst DEFAULT_INTERVAL_MS = 80;\n\nexport interface StartupLoadingIndicatorOptions {\n\treadonly writer: (chunk: string) => void;\n\treadonly isTTY: boolean;\n\treadonly label?: string;\n\treadonly graceMs?: number;\n\treadonly intervalMs?: number;\n\treadonly frames?: readonly string[];\n}\n\nexport interface StartupLoadingIndicator {\n\tstart(): void;\n\tsetPhase(phase: string | undefined): void;\n\tpause(): void;\n\tresume(): void;\n\tstop(): void;\n\treadonly running: boolean;\n}\n\n/**\n * Single-line ANSI loading indicator for the pre-TUI startup window, borrowed\n * from codex's UI-first startup design (codex-rs/tui keeps a dim placeholder\n * header until the session is configured). The first frame is written in\n * start() itself: the work it covers is synchronous module loading, which\n * starves every timer until it is done, so a timer-driven first frame lands\n * only after that work (measured: 2.27s to the first byte on a real pty). The\n * grace delay now gates the animation only; stop() must run before any other\n * stdout writer (TUI, prompts, help) takes over the terminal.\n */\nclass AnsiStartupLoadingIndicator implements StartupLoadingIndicator {\n\tprivate readonly writer: (chunk: string) => void;\n\tprivate readonly isTTY: boolean;\n\tprivate readonly label: string;\n\tprivate readonly graceMs: number;\n\tprivate readonly intervalMs: number;\n\tprivate readonly frames: readonly string[];\n\tprivate phase: string | undefined = undefined;\n\tprivate frameIndex = 0;\n\tprivate drawn = false;\n\tprivate graceElapsed = false;\n\tprivate started = false;\n\tprivate paused = false;\n\tprivate stopped = false;\n\tprivate graceTimer: NodeJS.Timeout | undefined = undefined;\n\tprivate frameTimer: NodeJS.Timeout | undefined = undefined;\n\tprivate exitListener: (() => void) | undefined = undefined;\n\n\tconstructor(options: StartupLoadingIndicatorOptions) {\n\t\tthis.writer = options.writer;\n\t\tthis.isTTY = options.isTTY;\n\t\tthis.label = options.label ?? DEFAULT_LABEL;\n\t\tthis.graceMs = options.graceMs ?? DEFAULT_GRACE_MS;\n\t\tthis.intervalMs = options.intervalMs ?? DEFAULT_INTERVAL_MS;\n\t\tthis.frames = options.frames && options.frames.length > 0 ? options.frames : DEFAULT_FRAMES;\n\t}\n\n\tget running(): boolean {\n\t\treturn this.started && !this.stopped;\n\t}\n\n\tstart(): void {\n\t\tif (!this.isTTY || this.started || this.stopped) return;\n\t\tthis.started = true;\n\t\tthis.exitListener = () => {\n\t\t\tif (this.drawn) this.writer(CLEAR_LINE + SHOW_CURSOR);\n\t\t};\n\t\tprocess.on(\"exit\", this.exitListener);\n\t\tthis.draw(true);\n\t\tthis.startGraceTimer();\n\t}\n\n\tsetPhase(phase: string | undefined): void {\n\t\tthis.phase = phase;\n\t\tif (this.drawn && !this.paused && !this.stopped) {\n\t\t\tthis.draw(false);\n\t\t}\n\t}\n\n\tpause(): void {\n\t\tif (!this.started || this.stopped || this.paused) return;\n\t\tthis.paused = true;\n\t\tthis.clearTimers();\n\t\tthis.eraseLine();\n\t}\n\n\tresume(): void {\n\t\tif (!this.started || this.stopped || !this.paused) return;\n\t\tthis.paused = false;\n\t\tif (this.graceElapsed) {\n\t\t\tthis.beginAnimation();\n\t\t} else {\n\t\t\tthis.draw(true);\n\t\t\tthis.startGraceTimer();\n\t\t}\n\t}\n\n\tstop(): void {\n\t\tif (this.stopped) return;\n\t\tthis.stopped = true;\n\t\tthis.clearTimers();\n\t\tthis.eraseLine();\n\t\tif (this.exitListener) {\n\t\t\tprocess.removeListener(\"exit\", this.exitListener);\n\t\t\tthis.exitListener = undefined;\n\t\t}\n\t}\n\n\tprivate startGraceTimer(): void {\n\t\tthis.graceTimer = setTimeout(() => {\n\t\t\tthis.graceElapsed = true;\n\t\t\tthis.beginAnimation();\n\t\t}, this.graceMs);\n\t}\n\n\tprivate beginAnimation(): void {\n\t\tif (!this.drawn) this.draw(true);\n\t\tthis.frameTimer = setInterval(() => {\n\t\t\tthis.frameIndex = (this.frameIndex + 1) % this.frames.length;\n\t\t\tthis.draw(false);\n\t\t}, this.intervalMs);\n\t}\n\n\tprivate draw(hideCursor: boolean): void {\n\t\tconst frame = this.frames[this.frameIndex] ?? \"\";\n\t\tconst phaseSuffix = this.phase ? ` ${this.phase}` : \"\";\n\t\tconst line = `${DIM}${frame} ${this.label}…${phaseSuffix}${RESET}`;\n\t\tthis.writer(`${hideCursor ? HIDE_CURSOR : \"\"}${CLEAR_LINE}${line}`);\n\t\tthis.drawn = true;\n\t}\n\n\tprivate eraseLine(): void {\n\t\tif (!this.drawn) return;\n\t\tthis.writer(CLEAR_LINE + SHOW_CURSOR);\n\t\tthis.drawn = false;\n\t}\n\n\tprivate clearTimers(): void {\n\t\tif (this.graceTimer) {\n\t\t\tclearTimeout(this.graceTimer);\n\t\t\tthis.graceTimer = undefined;\n\t\t}\n\t\tif (this.frameTimer) {\n\t\t\tclearInterval(this.frameTimer);\n\t\t\tthis.frameTimer = undefined;\n\t\t}\n\t}\n}\n\nexport function createStartupLoadingIndicator(options: StartupLoadingIndicatorOptions): StartupLoadingIndicator {\n\treturn new AnsiStartupLoadingIndicator(options);\n}\n\nexport function shouldShowStartupLoadingIndicator(input: {\n\treadonly appMode: AppMode;\n\treadonly stdoutIsTTY: boolean;\n\treadonly helpRequested: boolean;\n}): boolean {\n\treturn input.appMode === \"interactive\" && input.stdoutIsTTY && !input.helpRequested;\n}\n\n/**\n * Project-trust prompts open their own startup TUI mid-load; pausing the\n * indicator around each prompt keeps the two from fighting over the terminal.\n */\nexport function pauseIndicatorDuringPrompts(\n\tcontext: ProjectTrustContext,\n\tindicator: Pick<StartupLoadingIndicator, \"pause\" | \"resume\">,\n): ProjectTrustContext {\n\tconst wrapPrompt =\n\t\t<Args extends readonly unknown[], Result>(\n\t\t\tprompt: (...args: Args) => Promise<Result>,\n\t\t): ((...args: Args) => Promise<Result>) =>\n\t\tasync (...args: Args): Promise<Result> => {\n\t\t\tindicator.pause();\n\t\t\ttry {\n\t\t\t\treturn await prompt(...args);\n\t\t\t} finally {\n\t\t\t\tindicator.resume();\n\t\t\t}\n\t\t};\n\treturn {\n\t\t...context,\n\t\tui: {\n\t\t\tselect: wrapPrompt(context.ui.select),\n\t\t\tconfirm: wrapPrompt(context.ui.confirm),\n\t\t\tinput: wrapPrompt(context.ui.input),\n\t\t\tnotify: context.ui.notify,\n\t\t},\n\t};\n}\n"]}
|
package/dist/cli.js
CHANGED
|
@@ -120,6 +120,15 @@ if (isRootCommand(args) && (args.includes("--version") || args.includes("-v")))
|
|
|
120
120
|
console.log(DISPLAY_VERSION);
|
|
121
121
|
process.exit();
|
|
122
122
|
}
|
|
123
|
+
// Help is static text plus the flags extensions registered, so a launch that already knows those
|
|
124
|
+
// flags must not import the engine graph to print them. The import stays dynamic for the same
|
|
125
|
+
// reason `cli-main` is: a static one would evaluate that graph before this answer.
|
|
126
|
+
if (isRootCommand(args) && args.some((arg) => arg === "--help" || arg === "-h")) {
|
|
127
|
+
const { tryPrintHelpWithoutEngine } = await import("./cli/help-fast-path.js");
|
|
128
|
+
if (tryPrintHelpWithoutEngine(args)) {
|
|
129
|
+
process.exit();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
123
132
|
if (isMissingBundledWorkspaceDependencies(getPackageDir())) {
|
|
124
133
|
if (await handleBootstrapSelfUpdate(args)) {
|
|
125
134
|
process.exit();
|