@bastani/atomic 0.9.2 → 0.9.3-alpha.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 +66 -0
- package/README.md +2 -2
- package/dist/builtin/cursor/CHANGELOG.md +15 -0
- package/dist/builtin/cursor/README.md +2 -1
- package/dist/builtin/cursor/package.json +2 -2
- package/dist/builtin/cursor/src/cursor-models-raw.json +2 -9
- package/dist/builtin/cursor/src/model-mapper.ts +14 -3
- package/dist/builtin/cursor/src/proto/protobuf-codec-base64.ts +22 -0
- package/dist/builtin/cursor/src/proto/protobuf-codec-request.ts +53 -13
- package/dist/builtin/cursor/src/proto/protobuf-codec-wire.ts +24 -7
- package/dist/builtin/cursor/src/proto/protobuf-codec.ts +3 -2
- package/dist/builtin/cursor/src/stream.ts +5 -11
- package/dist/builtin/cursor/src/transport-types.ts +3 -0
- package/dist/builtin/cursor/src/transport.ts +1 -0
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/CHANGELOG.md +6 -0
- package/dist/builtin/mcp/direct-tools.ts +4 -2
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/mcp/proxy-call.ts +3 -1
- package/dist/builtin/mcp/utils.ts +18 -7
- package/dist/builtin/subagents/CHANGELOG.md +20 -0
- package/dist/builtin/subagents/README.md +6 -6
- package/dist/builtin/subagents/agents/code-simplifier.md +7 -6
- package/dist/builtin/subagents/agents/codebase-analyzer.md +5 -4
- package/dist/builtin/subagents/agents/codebase-locator.md +3 -3
- package/dist/builtin/subagents/agents/codebase-online-researcher.md +10 -10
- package/dist/builtin/subagents/agents/codebase-pattern-finder.md +4 -4
- package/dist/builtin/subagents/agents/codebase-research-analyzer.md +3 -3
- package/dist/builtin/subagents/agents/codebase-research-locator.md +4 -4
- package/dist/builtin/subagents/agents/debugger.md +5 -5
- package/dist/builtin/subagents/agents/worker.md +56 -0
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/skills/subagent/SKILL.md +11 -11
- package/dist/builtin/subagents/src/agents/agent-loaders.ts +3 -5
- package/dist/builtin/subagents/src/agents/agent-management-helpers.ts +3 -3
- package/dist/builtin/subagents/src/extension/fanout-child.ts +1 -0
- package/dist/builtin/subagents/src/extension/index.ts +6 -3
- package/dist/builtin/subagents/src/extension/schemas.ts +2 -7
- package/dist/builtin/subagents/src/intercom/result-intercom.ts +4 -3
- package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +1 -4
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +15 -1
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +35 -1
- package/dist/builtin/subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +1 -1
- package/dist/builtin/subagents/src/runs/shared/nested-render.ts +2 -2
- package/dist/builtin/subagents/src/runs/shared/pi-args.ts +2 -1
- package/dist/builtin/subagents/src/runs/shared/subagent-prompt-runtime.ts +4 -2
- package/dist/builtin/subagents/src/shared/types-async.ts +1 -0
- package/dist/builtin/subagents/src/shared/types-depth.ts +5 -5
- package/dist/builtin/subagents/src/shared/types-runtime.ts +2 -1
- package/dist/builtin/subagents/src/slash/prompt-template-bridge.ts +27 -5
- package/dist/builtin/subagents/src/tui/render-event-formatting.ts +2 -2
- package/dist/builtin/subagents/src/tui/render-layout.ts +27 -4
- package/dist/builtin/subagents/src/tui/render-result-animation.ts +22 -31
- package/dist/builtin/subagents/src/tui/render-result-compact.ts +6 -6
- package/dist/builtin/subagents/src/tui/render-result.ts +20 -19
- package/dist/builtin/subagents/src/tui/render-status-progress.ts +3 -3
- package/dist/builtin/subagents/src/tui/render-widget.ts +46 -7
- package/dist/builtin/subagents/src/tui/render.ts +2 -2
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +56 -0
- package/dist/builtin/workflows/README.md +3 -3
- package/dist/builtin/workflows/builtin/goal-artifacts.ts +11 -6
- package/dist/builtin/workflows/builtin/goal-ledger.ts +33 -1
- package/dist/builtin/workflows/builtin/goal-prompts.ts +23 -28
- package/dist/builtin/workflows/builtin/goal-reducer.ts +2 -2
- package/dist/builtin/workflows/builtin/goal-reports.ts +2 -5
- package/dist/builtin/workflows/builtin/goal-review.ts +1 -1
- package/dist/builtin/workflows/builtin/goal-runner.ts +10 -17
- package/dist/builtin/workflows/builtin/open-claude-design-feedback.ts +3 -3
- package/dist/builtin/workflows/builtin/open-claude-design-phases.ts +1 -3
- package/dist/builtin/workflows/builtin/open-claude-design-setup.ts +1 -1
- package/dist/builtin/workflows/builtin/ralph-core.ts +7 -17
- package/dist/builtin/workflows/builtin/ralph-runner.ts +11 -18
- package/dist/builtin/workflows/builtin/shared-prompts.ts +1 -1
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/authoring.d.ts +1 -1
- package/dist/builtin/workflows/src/durable/backend.ts +343 -0
- package/dist/builtin/workflows/src/durable/child-primitive.ts +79 -0
- package/dist/builtin/workflows/src/durable/dbos-backend.ts +421 -0
- package/dist/builtin/workflows/src/durable/dbos-envelope.ts +171 -0
- package/dist/builtin/workflows/src/durable/factory.ts +96 -0
- package/dist/builtin/workflows/src/durable/file-backend.ts +433 -0
- package/dist/builtin/workflows/src/durable/index.ts +73 -0
- package/dist/builtin/workflows/src/durable/resume-catalog.ts +217 -0
- package/dist/builtin/workflows/src/durable/resume-runtime.ts +299 -0
- package/dist/builtin/workflows/src/durable/scoped-backend.ts +171 -0
- package/dist/builtin/workflows/src/durable/stage-primitive.ts +284 -0
- package/dist/builtin/workflows/src/durable/tool-primitive.ts +180 -0
- package/dist/builtin/workflows/src/durable/types.ts +168 -0
- package/dist/builtin/workflows/src/durable/ui-primitive.ts +96 -0
- package/dist/builtin/workflows/src/engine/options.ts +3 -0
- package/dist/builtin/workflows/src/engine/primitives/parallel.ts +2 -2
- package/dist/builtin/workflows/src/engine/primitives/task.ts +4 -4
- package/dist/builtin/workflows/src/engine/primitives/ui.ts +22 -8
- package/dist/builtin/workflows/src/engine/primitives/workflow.ts +8 -0
- package/dist/builtin/workflows/src/engine/run-durable-finalize.ts +69 -0
- package/dist/builtin/workflows/src/engine/run-durable-stage-session.ts +31 -0
- package/dist/builtin/workflows/src/engine/run.ts +148 -6
- package/dist/builtin/workflows/src/engine/runtime.ts +8 -2
- package/dist/builtin/workflows/src/extension/config-loader.ts +35 -15
- package/dist/builtin/workflows/src/extension/discovery.ts +20 -8
- package/dist/builtin/workflows/src/extension/extension-factory.ts +6 -12
- package/dist/builtin/workflows/src/extension/extension-lifecycle.ts +5 -1
- package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +4 -2
- package/dist/builtin/workflows/src/extension/runtime.ts +48 -9
- package/dist/builtin/workflows/src/extension/wiring.ts +1 -1
- package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +143 -4
- package/dist/builtin/workflows/src/runs/background/quit.ts +61 -0
- package/dist/builtin/workflows/src/runs/background/status.ts +1 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +5 -5
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-call.ts +74 -33
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-context.ts +20 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts +8 -7
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-replay.ts +1 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-types.ts +1 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-types.ts +19 -2
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-context.ts +4 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +10 -10
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-options.ts +5 -1
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-send-user-message.ts +25 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-types.ts +3 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +16 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-stage.ts +20 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +23 -1
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.ts +30 -1
- package/dist/builtin/workflows/src/shared/store-public-types.ts +6 -2
- package/dist/builtin/workflows/src/shared/store-run-methods.ts +12 -6
- package/dist/builtin/workflows/src/shared/types.ts +55 -0
- package/dist/builtin/workflows/src/tui/dispatch-confirm.ts +11 -10
- package/dist/builtin/workflows/src/tui/graph-view-constants.ts +1 -1
- package/dist/builtin/workflows/src/tui/graph-view-graph-render.ts +41 -0
- package/dist/builtin/workflows/src/tui/graph-view-input.ts +82 -24
- package/dist/builtin/workflows/src/tui/graph-view-render.ts +7 -0
- package/dist/builtin/workflows/src/tui/graph-view-state.ts +22 -2
- package/dist/builtin/workflows/src/tui/graph-view-types.ts +4 -5
- package/dist/builtin/workflows/src/tui/overlay-adapter.ts +9 -11
- package/dist/builtin/workflows/src/tui/stage-chat-view-footer-status.ts +9 -3
- package/dist/builtin/workflows/src/tui/stage-chat-view-input.ts +11 -2
- package/dist/builtin/workflows/src/tui/stage-chat-view-live-events.ts +35 -0
- package/dist/builtin/workflows/src/tui/stage-chat-view-state.ts +51 -17
- package/dist/builtin/workflows/src/tui/stage-chat-view-status.ts +36 -0
- package/dist/builtin/workflows/src/tui/stage-chat-view-types.ts +5 -1
- package/dist/builtin/workflows/src/tui/stage-chat-view.ts +3 -1
- package/dist/builtin/workflows/src/tui/status-list.ts +14 -2
- package/dist/builtin/workflows/src/tui/widget.ts +23 -8
- package/dist/builtin/workflows/src/tui/workflow-attach-pane-types.ts +5 -4
- package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +8 -8
- package/dist/builtin/workflows/src/tui/workflow-resume-selector.ts +151 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +9 -9
- package/dist/cli/args.js.map +1 -1
- package/dist/config-self-update.d.ts.map +1 -1
- package/dist/config-self-update.js +3 -4
- package/dist/config-self-update.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -5
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-bash.d.ts +1 -0
- package/dist/core/agent-session-bash.d.ts.map +1 -1
- package/dist/core/agent-session-bash.js +1 -0
- package/dist/core/agent-session-bash.js.map +1 -1
- package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
- package/dist/core/agent-session-tool-registry.js +23 -0
- package/dist/core/agent-session-tool-registry.js.map +1 -1
- package/dist/core/bash-executor.d.ts +2 -0
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +1 -0
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +29 -0
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +36 -1
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/context-compaction-metrics.d.ts +14 -2
- package/dist/core/compaction/context-compaction-metrics.d.ts.map +1 -1
- package/dist/core/compaction/context-compaction-metrics.js +50 -1
- package/dist/core/compaction/context-compaction-metrics.js.map +1 -1
- package/dist/core/compaction/context-compaction-prompt.d.ts.map +1 -1
- package/dist/core/compaction/context-compaction-prompt.js +2 -0
- package/dist/core/compaction/context-compaction-prompt.js.map +1 -1
- package/dist/core/compaction/context-compaction-runner.d.ts.map +1 -1
- package/dist/core/compaction/context-compaction-runner.js +1 -1
- package/dist/core/compaction/context-compaction-runner.js.map +1 -1
- package/dist/core/compaction/context-deletion-application.d.ts.map +1 -1
- package/dist/core/compaction/context-deletion-application.js +5 -5
- package/dist/core/compaction/context-deletion-application.js.map +1 -1
- package/dist/core/compaction/context-deletion-targets.d.ts +2 -0
- package/dist/core/compaction/context-deletion-targets.d.ts.map +1 -1
- package/dist/core/compaction/context-deletion-targets.js +23 -3
- package/dist/core/compaction/context-deletion-targets.js.map +1 -1
- package/dist/core/compaction/context-deletion-tool-definitions.d.ts +6 -0
- package/dist/core/compaction/context-deletion-tool-definitions.d.ts.map +1 -1
- package/dist/core/compaction/context-deletion-tool-definitions.js.map +1 -1
- package/dist/core/compaction/context-deletion-tools.d.ts.map +1 -1
- package/dist/core/compaction/context-deletion-tools.js +18 -10
- package/dist/core/compaction/context-deletion-tools.js.map +1 -1
- package/dist/core/compaction/context-transcript-analysis.d.ts.map +1 -1
- package/dist/core/compaction/context-transcript-analysis.js +2 -4
- package/dist/core/compaction/context-transcript-analysis.js.map +1 -1
- package/dist/core/copilot-gemini-tool-arguments.d.ts.map +1 -1
- package/dist/core/copilot-gemini-tool-arguments.js +2 -60
- package/dist/core/copilot-gemini-tool-arguments.js.map +1 -1
- package/dist/core/extensions/context-types.d.ts +2 -0
- package/dist/core/extensions/context-types.d.ts.map +1 -1
- package/dist/core/extensions/context-types.js.map +1 -1
- package/dist/core/extensions/index.d.ts +2 -2
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.js +57 -32
- package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
- package/dist/core/extensions/runner-context.d.ts.map +1 -1
- package/dist/core/extensions/runner-context.js +11 -0
- package/dist/core/extensions/runner-context.js.map +1 -1
- package/dist/core/extensions/tool-events.d.ts +13 -13
- package/dist/core/extensions/tool-events.d.ts.map +1 -1
- package/dist/core/extensions/tool-events.js +3 -3
- package/dist/core/extensions/tool-events.js.map +1 -1
- package/dist/core/extensions/types.d.ts +1 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/flattened-tool-arguments.d.ts +18 -0
- package/dist/core/flattened-tool-arguments.d.ts.map +1 -1
- package/dist/core/flattened-tool-arguments.js +104 -0
- package/dist/core/flattened-tool-arguments.js.map +1 -1
- package/dist/core/messages.d.ts +1 -0
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +46 -1
- package/dist/core/messages.js.map +1 -1
- package/dist/core/sdk-exports.d.ts +1 -1
- package/dist/core/sdk-exports.d.ts.map +1 -1
- package/dist/core/sdk-exports.js +1 -1
- package/dist/core/sdk-exports.js.map +1 -1
- package/dist/core/sdk-types.d.ts +2 -2
- package/dist/core/sdk-types.d.ts.map +1 -1
- package/dist/core/sdk-types.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +12 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager-core.d.ts +15 -7
- package/dist/core/session-manager-core.d.ts.map +1 -1
- package/dist/core/session-manager-core.js +20 -9
- package/dist/core/session-manager-core.js.map +1 -1
- package/dist/core/session-manager-entries.d.ts +2 -2
- package/dist/core/session-manager-entries.d.ts.map +1 -1
- package/dist/core/session-manager-entries.js +9 -3
- package/dist/core/session-manager-entries.js.map +1 -1
- package/dist/core/session-manager-history.d.ts.map +1 -1
- package/dist/core/session-manager-history.js +2 -1
- package/dist/core/session-manager-history.js.map +1 -1
- package/dist/core/session-manager-list.d.ts +3 -3
- package/dist/core/session-manager-list.d.ts.map +1 -1
- package/dist/core/session-manager-list.js +27 -8
- package/dist/core/session-manager-list.js.map +1 -1
- package/dist/core/session-manager-storage.d.ts +3 -1
- package/dist/core/session-manager-storage.d.ts.map +1 -1
- package/dist/core/session-manager-storage.js +55 -12
- package/dist/core/session-manager-storage.js.map +1 -1
- package/dist/core/session-manager-tool-dependencies.d.ts +10 -0
- package/dist/core/session-manager-tool-dependencies.d.ts.map +1 -0
- package/dist/core/session-manager-tool-dependencies.js +133 -0
- package/dist/core/session-manager-tool-dependencies.js.map +1 -0
- package/dist/core/session-manager-types.d.ts +22 -0
- package/dist/core/session-manager-types.d.ts.map +1 -1
- package/dist/core/session-manager-types.js.map +1 -1
- package/dist/core/session-manager.d.ts +2 -2
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +1 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager-basic-accessors.d.ts +4 -0
- package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager-basic-accessors.js +18 -0
- package/dist/core/settings-manager-basic-accessors.js.map +1 -1
- package/dist/core/settings-manager-resource-accessors.d.ts +4 -0
- package/dist/core/settings-manager-resource-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager-resource-accessors.js +15 -0
- package/dist/core/settings-manager-resource-accessors.js.map +1 -1
- package/dist/core/settings-types.d.ts +11 -0
- package/dist/core/settings-types.d.ts.map +1 -1
- package/dist/core/settings-types.js.map +1 -1
- package/dist/core/system-prompt.d.ts +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +3 -2
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/artifact-protocol.d.ts +11 -0
- package/dist/core/tools/artifact-protocol.d.ts.map +1 -0
- package/dist/core/tools/artifact-protocol.js +76 -0
- package/dist/core/tools/artifact-protocol.js.map +1 -0
- package/dist/core/tools/artifacts.d.ts +18 -0
- package/dist/core/tools/artifacts.d.ts.map +1 -0
- package/dist/core/tools/artifacts.js +90 -0
- package/dist/core/tools/artifacts.js.map +1 -0
- package/dist/core/tools/bash-async-jobs.d.ts +20 -0
- package/dist/core/tools/bash-async-jobs.d.ts.map +1 -0
- package/dist/core/tools/bash-async-jobs.js +59 -0
- package/dist/core/tools/bash-async-jobs.js.map +1 -0
- package/dist/core/tools/bash-async-output.d.ts +10 -0
- package/dist/core/tools/bash-async-output.d.ts.map +1 -0
- package/dist/core/tools/bash-async-output.js +80 -0
- package/dist/core/tools/bash-async-output.js.map +1 -0
- package/dist/core/tools/bash-interceptor.d.ts +10 -0
- package/dist/core/tools/bash-interceptor.d.ts.map +1 -0
- package/dist/core/tools/bash-interceptor.js +39 -0
- package/dist/core/tools/bash-interceptor.js.map +1 -0
- package/dist/core/tools/bash-leading-cd.d.ts +7 -0
- package/dist/core/tools/bash-leading-cd.d.ts.map +1 -0
- package/dist/core/tools/bash-leading-cd.js +59 -0
- package/dist/core/tools/bash-leading-cd.js.map +1 -0
- package/dist/core/tools/bash-pty-native.d.ts +14 -0
- package/dist/core/tools/bash-pty-native.d.ts.map +1 -0
- package/dist/core/tools/bash-pty-native.js +71 -0
- package/dist/core/tools/bash-pty-native.js.map +1 -0
- package/dist/core/tools/bash.d.ts +28 -17
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +152 -35
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/block-resolver.d.ts +16 -0
- package/dist/core/tools/block-resolver.d.ts.map +1 -0
- package/dist/core/tools/block-resolver.js +74 -0
- package/dist/core/tools/block-resolver.js.map +1 -0
- package/dist/core/tools/conflict-registry.d.ts +16 -0
- package/dist/core/tools/conflict-registry.d.ts.map +1 -0
- package/dist/core/tools/conflict-registry.js +44 -0
- package/dist/core/tools/conflict-registry.js.map +1 -0
- package/dist/core/tools/directory-tree.d.ts +13 -0
- package/dist/core/tools/directory-tree.d.ts.map +1 -0
- package/dist/core/tools/directory-tree.js +81 -0
- package/dist/core/tools/directory-tree.js.map +1 -0
- package/dist/core/tools/edit.d.ts +4 -29
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +136 -228
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/fetch-url.d.ts +74 -0
- package/dist/core/tools/fetch-url.d.ts.map +1 -0
- package/dist/core/tools/fetch-url.js +518 -0
- package/dist/core/tools/fetch-url.js.map +1 -0
- package/dist/core/tools/find.d.ts +27 -9
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +400 -176
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/glob-path-utils.d.ts +8 -0
- package/dist/core/tools/glob-path-utils.d.ts.map +1 -0
- package/dist/core/tools/glob-path-utils.js +26 -0
- package/dist/core/tools/glob-path-utils.js.map +1 -0
- package/dist/core/tools/grep.d.ts +12 -0
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +141 -17
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/hashline-engine/apply.d.ts +11 -0
- package/dist/core/tools/hashline-engine/apply.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/apply.js +752 -0
- package/dist/core/tools/hashline-engine/apply.js.map +1 -0
- package/dist/core/tools/hashline-engine/block.d.ts +40 -0
- package/dist/core/tools/hashline-engine/block.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/block.js +117 -0
- package/dist/core/tools/hashline-engine/block.js.map +1 -0
- package/dist/core/tools/hashline-engine/diff-preview.d.ts +15 -0
- package/dist/core/tools/hashline-engine/diff-preview.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/diff-preview.js +98 -0
- package/dist/core/tools/hashline-engine/diff-preview.js.map +1 -0
- package/dist/core/tools/hashline-engine/format.d.ts +71 -0
- package/dist/core/tools/hashline-engine/format.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/format.js +178 -0
- package/dist/core/tools/hashline-engine/format.js.map +1 -0
- package/dist/core/tools/hashline-engine/fs.d.ts +81 -0
- package/dist/core/tools/hashline-engine/fs.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/fs.js +143 -0
- package/dist/core/tools/hashline-engine/fs.js.map +1 -0
- package/dist/core/tools/hashline-engine/index.d.ts +18 -0
- package/dist/core/tools/hashline-engine/index.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/index.js +20 -0
- package/dist/core/tools/hashline-engine/index.js.map +1 -0
- package/dist/core/tools/hashline-engine/input.d.ts +101 -0
- package/dist/core/tools/hashline-engine/input.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/input.js +398 -0
- package/dist/core/tools/hashline-engine/input.js.map +1 -0
- package/dist/core/tools/hashline-engine/messages.d.ts +99 -0
- package/dist/core/tools/hashline-engine/messages.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/messages.js +144 -0
- package/dist/core/tools/hashline-engine/messages.js.map +1 -0
- package/dist/core/tools/hashline-engine/mismatch.d.ts +45 -0
- package/dist/core/tools/hashline-engine/mismatch.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/mismatch.js +90 -0
- package/dist/core/tools/hashline-engine/mismatch.js.map +1 -0
- package/dist/core/tools/hashline-engine/normalize.d.ts +21 -0
- package/dist/core/tools/hashline-engine/normalize.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/normalize.js +33 -0
- package/dist/core/tools/hashline-engine/normalize.js.map +1 -0
- package/dist/core/tools/hashline-engine/parser.d.ts +24 -0
- package/dist/core/tools/hashline-engine/parser.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/parser.js +381 -0
- package/dist/core/tools/hashline-engine/parser.js.map +1 -0
- package/dist/core/tools/hashline-engine/patcher.d.ts +118 -0
- package/dist/core/tools/hashline-engine/patcher.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/patcher.js +341 -0
- package/dist/core/tools/hashline-engine/patcher.js.map +1 -0
- package/dist/core/tools/hashline-engine/prefixes.d.ts +43 -0
- package/dist/core/tools/hashline-engine/prefixes.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/prefixes.js +135 -0
- package/dist/core/tools/hashline-engine/prefixes.js.map +1 -0
- package/dist/core/tools/hashline-engine/recovery.d.ts +41 -0
- package/dist/core/tools/hashline-engine/recovery.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/recovery.js +168 -0
- package/dist/core/tools/hashline-engine/recovery.js.map +1 -0
- package/dist/core/tools/hashline-engine/snapshots.d.ts +65 -0
- package/dist/core/tools/hashline-engine/snapshots.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/snapshots.js +108 -0
- package/dist/core/tools/hashline-engine/snapshots.js.map +1 -0
- package/dist/core/tools/hashline-engine/stream.d.ts +3 -0
- package/dist/core/tools/hashline-engine/stream.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/stream.js +111 -0
- package/dist/core/tools/hashline-engine/stream.js.map +1 -0
- package/dist/core/tools/hashline-engine/tokenizer.d.ts +69 -0
- package/dist/core/tools/hashline-engine/tokenizer.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/tokenizer.js +430 -0
- package/dist/core/tools/hashline-engine/tokenizer.js.map +1 -0
- package/dist/core/tools/hashline-engine/types.d.ts +166 -0
- package/dist/core/tools/hashline-engine/types.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/types.js +9 -0
- package/dist/core/tools/hashline-engine/types.js.map +1 -0
- package/dist/core/tools/hashline.d.ts +29 -0
- package/dist/core/tools/hashline.d.ts.map +1 -0
- package/dist/core/tools/hashline.js +110 -0
- package/dist/core/tools/hashline.js.map +1 -0
- package/dist/core/tools/index.d.ts +6 -4
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +52 -35
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/notebook.d.ts +38 -0
- package/dist/core/tools/notebook.d.ts.map +1 -0
- package/dist/core/tools/notebook.js +125 -0
- package/dist/core/tools/notebook.js.map +1 -0
- package/dist/core/tools/read-document-extract.d.ts +9 -0
- package/dist/core/tools/read-document-extract.d.ts.map +1 -0
- package/dist/core/tools/read-document-extract.js +212 -0
- package/dist/core/tools/read-document-extract.js.map +1 -0
- package/dist/core/tools/read-selectors.d.ts +24 -0
- package/dist/core/tools/read-selectors.d.ts.map +1 -0
- package/dist/core/tools/read-selectors.js +277 -0
- package/dist/core/tools/read-selectors.js.map +1 -0
- package/dist/core/tools/read-url.d.ts +37 -0
- package/dist/core/tools/read-url.d.ts.map +1 -0
- package/dist/core/tools/read-url.js +39 -0
- package/dist/core/tools/read-url.js.map +1 -0
- package/dist/core/tools/read.d.ts +11 -11
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +224 -94
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/resource-selectors.d.ts +44 -0
- package/dist/core/tools/resource-selectors.d.ts.map +1 -0
- package/dist/core/tools/resource-selectors.js +808 -0
- package/dist/core/tools/resource-selectors.js.map +1 -0
- package/dist/core/tools/search-details.d.ts +26 -0
- package/dist/core/tools/search-details.d.ts.map +1 -0
- package/dist/core/tools/search-details.js +24 -0
- package/dist/core/tools/search-details.js.map +1 -0
- package/dist/core/tools/search-line-ranges.d.ts +11 -0
- package/dist/core/tools/search-line-ranges.d.ts.map +1 -0
- package/dist/core/tools/search-line-ranges.js +65 -0
- package/dist/core/tools/search-line-ranges.js.map +1 -0
- package/dist/core/tools/search-native.d.ts +97 -0
- package/dist/core/tools/search-native.d.ts.map +1 -0
- package/dist/core/tools/search-native.js +27 -0
- package/dist/core/tools/search-native.js.map +1 -0
- package/dist/core/tools/search.d.ts +24 -0
- package/dist/core/tools/search.d.ts.map +1 -0
- package/dist/core/tools/search.js +573 -0
- package/dist/core/tools/search.js.map +1 -0
- package/dist/core/tools/truncate.d.ts +4 -4
- package/dist/core/tools/truncate.d.ts.map +1 -1
- package/dist/core/tools/truncate.js +3 -3
- package/dist/core/tools/truncate.js.map +1 -1
- package/dist/core/tools/url-ip-guards.d.ts +4 -0
- package/dist/core/tools/url-ip-guards.d.ts.map +1 -0
- package/dist/core/tools/url-ip-guards.js +126 -0
- package/dist/core/tools/url-ip-guards.js.map +1 -0
- package/dist/core/tools/write.d.ts +12 -2
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +166 -14
- package/dist/core/tools/write.js.map +1 -1
- package/dist/core/trust-manager.d.ts.map +1 -1
- package/dist/core/trust-manager.js +2 -3
- package/dist/core/trust-manager.js.map +1 -1
- package/dist/index-extensions.d.ts +2 -2
- package/dist/index-extensions.d.ts.map +1 -1
- package/dist/index-extensions.js +1 -1
- package/dist/index-extensions.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-runtime.d.ts +1 -0
- package/dist/modes/interactive/components/chat-session-host-runtime.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-runtime.js +12 -0
- package/dist/modes/interactive/components/chat-session-host-runtime.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-terminal-cleanup.d.ts +4 -0
- package/dist/modes/interactive/components/chat-session-host-terminal-cleanup.d.ts.map +1 -0
- package/dist/modes/interactive/components/chat-session-host-terminal-cleanup.js +131 -0
- package/dist/modes/interactive/components/chat-session-host-terminal-cleanup.js.map +1 -0
- package/dist/modes/interactive/components/chat-session-host.d.ts +2 -0
- package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.js +7 -1
- package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
- package/dist/modes/interactive/components/chat-transcript.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-transcript.js +15 -4
- package/dist/modes/interactive/components/chat-transcript.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +1 -0
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +9 -2
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector-handlers.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector-handlers.js +3 -0
- package/dist/modes/interactive/components/settings-selector-handlers.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector-items.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector-items.js +7 -0
- package/dist/modes/interactive/components/settings-selector-items.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector-types.d.ts +2 -0
- package/dist/modes/interactive/components/settings-selector-types.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector-types.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +3 -0
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +26 -0
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector-content.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector-content.js +0 -5
- package/dist/modes/interactive/components/tree-selector-content.js.map +1 -1
- package/dist/modes/interactive/interactive-auth-login.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-auth-login.js +1 -0
- package/dist/modes/interactive/interactive-auth-login.js.map +1 -1
- package/dist/modes/interactive/interactive-autocomplete.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-autocomplete.js +80 -2
- package/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
- package/dist/modes/interactive/interactive-hotkeys-debug.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-hotkeys-debug.js +3 -0
- package/dist/modes/interactive/interactive-hotkeys-debug.js.map +1 -1
- package/dist/modes/interactive/interactive-input-handling.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-input-handling.js +51 -0
- package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.d.ts +5 -0
- package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.js +5 -0
- package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-deps.d.ts +1 -1
- package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.d.ts +12 -0
- package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +1 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/interactive-model-routing.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-model-routing.js +4 -1
- package/dist/modes/interactive/interactive-model-routing.js.map +1 -1
- package/dist/modes/interactive/interactive-onboarding.d.ts +11 -0
- package/dist/modes/interactive/interactive-onboarding.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-onboarding.js +220 -0
- package/dist/modes/interactive/interactive-onboarding.js.map +1 -0
- package/dist/modes/interactive/interactive-selectors.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-selectors.js +4 -0
- package/dist/modes/interactive/interactive-selectors.js.map +1 -1
- package/dist/modes/interactive/interactive-session-routing.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-session-routing.js +6 -0
- package/dist/modes/interactive/interactive-session-routing.js.map +1 -1
- package/dist/modes/interactive/interactive-slash-commands.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-slash-commands.js +9 -4
- package/dist/modes/interactive/interactive-slash-commands.js.map +1 -1
- package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-startup.js +28 -0
- package/dist/modes/interactive/interactive-startup.js.map +1 -1
- package/dist/utils/child-process.d.ts.map +1 -1
- package/dist/utils/child-process.js +21 -1
- package/dist/utils/child-process.js.map +1 -1
- package/dist/utils/markit.d.ts +8 -0
- package/dist/utils/markit.d.ts.map +1 -0
- package/dist/utils/markit.js +53 -0
- package/dist/utils/markit.js.map +1 -0
- package/dist/utils/paths.d.ts +2 -1
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +14 -1
- package/dist/utils/paths.js.map +1 -1
- package/docs/compaction.md +18 -1
- package/docs/containerization.md +1 -1
- package/docs/docs.json +1 -0
- package/docs/extensions.md +25 -36
- package/docs/models.md +1 -1
- package/docs/providers.md +2 -1
- package/docs/quickstart.md +11 -6
- package/docs/sdk.md +5 -5
- package/docs/session-format.md +6 -0
- package/docs/sessions.md +6 -0
- package/docs/settings.md +7 -0
- package/docs/subagents.md +3 -2
- package/docs/tools.md +49 -0
- package/docs/usage.md +3 -3
- package/docs/workflows.md +112 -8
- package/examples/extensions/subagent/README.md +5 -5
- package/examples/extensions/subagent/agents/planner.md +1 -1
- package/examples/extensions/subagent/agents/reviewer.md +1 -1
- package/examples/extensions/subagent/agents/scout.md +2 -2
- package/examples/extensions/subagent/display.ts +3 -3
- package/examples/sdk/05-tools.ts +3 -3
- package/examples/sdk/README.md +1 -1
- package/package.json +5 -3
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session artifact storage, mirrored from oh-my-pi's
|
|
3
|
+
* `packages/coding-agent/src/session/artifacts.ts` at 15b5c1397fc.
|
|
4
|
+
*
|
|
5
|
+
* Artifacts are persisted as `<numericId>.<toolType>.log` files inside a
|
|
6
|
+
* session artifacts directory. IDs are sequential and scan-initialized from
|
|
7
|
+
* existing files so a resumed session keeps a contiguous id space. Subagents
|
|
8
|
+
* that share a session dir share the same manager/id space.
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, mkdirSync, readdirSync, writeFileSync } from "node:fs";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
export class ArtifactManager {
|
|
13
|
+
#nextId = 0;
|
|
14
|
+
#dir;
|
|
15
|
+
#initialized = false;
|
|
16
|
+
constructor(dir) {
|
|
17
|
+
this.#dir = dir;
|
|
18
|
+
}
|
|
19
|
+
get dir() {
|
|
20
|
+
return this.#dir;
|
|
21
|
+
}
|
|
22
|
+
#init() {
|
|
23
|
+
if (this.#initialized)
|
|
24
|
+
return;
|
|
25
|
+
this.#initialized = true;
|
|
26
|
+
let max = -1;
|
|
27
|
+
if (existsSync(this.#dir)) {
|
|
28
|
+
for (const name of readdirSync(this.#dir)) {
|
|
29
|
+
const match = name.match(/^(\d+)\..*\.log$/);
|
|
30
|
+
if (match) {
|
|
31
|
+
const id = Number.parseInt(match[1] ?? "0", 10);
|
|
32
|
+
if (id > max)
|
|
33
|
+
max = id;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
this.#nextId = max + 1;
|
|
38
|
+
}
|
|
39
|
+
allocate(toolType) {
|
|
40
|
+
this.#init();
|
|
41
|
+
const id = String(this.#nextId++);
|
|
42
|
+
const path = join(this.#dir, `${id}.${toolType}.log`);
|
|
43
|
+
return { path, id };
|
|
44
|
+
}
|
|
45
|
+
save(content, toolType) {
|
|
46
|
+
this.#init();
|
|
47
|
+
const { path, id } = this.allocate(toolType);
|
|
48
|
+
if (!existsSync(this.#dir))
|
|
49
|
+
mkdirSync(this.#dir, { recursive: true });
|
|
50
|
+
writeFileSync(path, content, "utf8");
|
|
51
|
+
return id;
|
|
52
|
+
}
|
|
53
|
+
/** Resolve a numeric id to its artifact file path, matching by `${id}.` prefix. */
|
|
54
|
+
resolve(id) {
|
|
55
|
+
this.#init();
|
|
56
|
+
if (!existsSync(this.#dir))
|
|
57
|
+
return undefined;
|
|
58
|
+
const prefix = `${id}.`;
|
|
59
|
+
for (const name of readdirSync(this.#dir))
|
|
60
|
+
if (name.startsWith(prefix) && name.endsWith(".log"))
|
|
61
|
+
return join(this.#dir, name);
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
list() {
|
|
65
|
+
this.#init();
|
|
66
|
+
if (!existsSync(this.#dir))
|
|
67
|
+
return [];
|
|
68
|
+
const ids = [];
|
|
69
|
+
for (const name of readdirSync(this.#dir)) {
|
|
70
|
+
const match = name.match(/^(\d+)\..*\.log$/);
|
|
71
|
+
if (match)
|
|
72
|
+
ids.push(Number.parseInt(match[1] ?? "0", 10));
|
|
73
|
+
}
|
|
74
|
+
return ids.sort((a, b) => a - b).map(String);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const managers = new Map();
|
|
78
|
+
/** Returns a shared ArtifactManager for a session artifacts dir (cached per dir). */
|
|
79
|
+
export function getArtifactManager(artifactsDir) {
|
|
80
|
+
let manager = managers.get(artifactsDir);
|
|
81
|
+
if (!manager) {
|
|
82
|
+
manager = new ArtifactManager(artifactsDir);
|
|
83
|
+
managers.set(artifactsDir, manager);
|
|
84
|
+
}
|
|
85
|
+
return manager;
|
|
86
|
+
}
|
|
87
|
+
export function resetArtifactManagerCache() {
|
|
88
|
+
managers.clear();
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=artifacts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../../../src/core/tools/artifacts.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Session artifact storage, mirrored from oh-my-pi's\n * `packages/coding-agent/src/session/artifacts.ts` at 15b5c1397fc.\n *\n * Artifacts are persisted as `<numericId>.<toolType>.log` files inside a\n * session artifacts directory. IDs are sequential and scan-initialized from\n * existing files so a resumed session keeps a contiguous id space. Subagents\n * that share a session dir share the same manager/id space.\n */\nimport { existsSync, mkdirSync, readdirSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport interface AllocatedArtifact {\n\tpath: string;\n\tid: string;\n}\n\nexport class ArtifactManager {\n\t#nextId = 0;\n\treadonly #dir: string;\n\t#initialized = false;\n\n\tconstructor(dir: string) {\n\t\tthis.#dir = dir;\n\t}\n\n\tget dir(): string {\n\t\treturn this.#dir;\n\t}\n\n\t#init(): void {\n\t\tif (this.#initialized) return;\n\t\tthis.#initialized = true;\n\t\tlet max = -1;\n\t\tif (existsSync(this.#dir)) {\n\t\t\tfor (const name of readdirSync(this.#dir)) {\n\t\t\t\tconst match = name.match(/^(\\d+)\\..*\\.log$/);\n\t\t\t\tif (match) {\n\t\t\t\t\tconst id = Number.parseInt(match[1] ?? \"0\", 10);\n\t\t\t\t\tif (id > max) max = id;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.#nextId = max + 1;\n\t}\n\n\tallocate(toolType: string): AllocatedArtifact {\n\t\tthis.#init();\n\t\tconst id = String(this.#nextId++);\n\t\tconst path = join(this.#dir, `${id}.${toolType}.log`);\n\t\treturn { path, id };\n\t}\n\n\tsave(content: string, toolType: string): string {\n\t\tthis.#init();\n\t\tconst { path, id } = this.allocate(toolType);\n\t\tif (!existsSync(this.#dir)) mkdirSync(this.#dir, { recursive: true });\n\t\twriteFileSync(path, content, \"utf8\");\n\t\treturn id;\n\t}\n\n\t/** Resolve a numeric id to its artifact file path, matching by `${id}.` prefix. */\n\tresolve(id: string): string | undefined {\n\t\tthis.#init();\n\t\tif (!existsSync(this.#dir)) return undefined;\n\t\tconst prefix = `${id}.`;\n\t\tfor (const name of readdirSync(this.#dir)) if (name.startsWith(prefix) && name.endsWith(\".log\")) return join(this.#dir, name);\n\t\treturn undefined;\n\t}\n\n\tlist(): string[] {\n\t\tthis.#init();\n\t\tif (!existsSync(this.#dir)) return [];\n\t\tconst ids: number[] = [];\n\t\tfor (const name of readdirSync(this.#dir)) {\n\t\t\tconst match = name.match(/^(\\d+)\\..*\\.log$/);\n\t\t\tif (match) ids.push(Number.parseInt(match[1] ?? \"0\", 10));\n\t\t}\n\t\treturn ids.sort((a, b) => a - b).map(String);\n\t}\n}\n\nconst managers = new Map<string, ArtifactManager>();\n\n/** Returns a shared ArtifactManager for a session artifacts dir (cached per dir). */\nexport function getArtifactManager(artifactsDir: string): ArtifactManager {\n\tlet manager = managers.get(artifactsDir);\n\tif (!manager) {\n\t\tmanager = new ArtifactManager(artifactsDir);\n\t\tmanagers.set(artifactsDir, manager);\n\t}\n\treturn manager;\n}\n\nexport function resetArtifactManagerCache(): void {\n\tmanagers.clear();\n}\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface ManagedBashJob {
|
|
2
|
+
jobId: string;
|
|
3
|
+
command: string;
|
|
4
|
+
cwd: string;
|
|
5
|
+
status: "running" | "completed" | "failed";
|
|
6
|
+
output: string;
|
|
7
|
+
fullOutputPath?: string;
|
|
8
|
+
exitCode?: number | null;
|
|
9
|
+
error?: string;
|
|
10
|
+
startedAt: number;
|
|
11
|
+
endedAt?: number;
|
|
12
|
+
timeoutSeconds?: number;
|
|
13
|
+
requestedTimeoutSeconds?: number;
|
|
14
|
+
abortController?: AbortController;
|
|
15
|
+
}
|
|
16
|
+
export declare function formatAsyncJobError(error: unknown): string;
|
|
17
|
+
export declare function createManagedBashJob(command: string, cwd: string, timeoutSeconds?: number, requestedTimeoutSeconds?: number): ManagedBashJob;
|
|
18
|
+
export declare function getManagedBashJob(jobId: string): ManagedBashJob | undefined;
|
|
19
|
+
export declare function abortManagedBashJob(jobId: string): ManagedBashJob | undefined;
|
|
20
|
+
//# sourceMappingURL=bash-async-jobs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bash-async-jobs.d.ts","sourceRoot":"","sources":["../../../src/core/tools/bash-async-jobs.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,eAAe,CAAC,EAAE,eAAe,CAAC;CAClC;AAKD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAI1D;AAgBD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,EAAE,uBAAuB,CAAC,EAAE,MAAM,GAAG,cAAc,CAO5I;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAM3E;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAK7E","sourcesContent":["import { rmSync } from \"node:fs\";\n\nexport interface ManagedBashJob {\n\tjobId: string;\n\tcommand: string;\n\tcwd: string;\n\tstatus: \"running\" | \"completed\" | \"failed\";\n\toutput: string;\n\tfullOutputPath?: string;\n\texitCode?: number | null;\n\terror?: string;\n\tstartedAt: number;\n\tendedAt?: number;\n\ttimeoutSeconds?: number;\n\trequestedTimeoutSeconds?: number;\n\tabortController?: AbortController;\n}\n\nconst MAX_MANAGED_BASH_JOBS = 100;\nconst COMPLETED_JOB_TTL_MS = 30 * 60 * 1000;\nconst managedBashJobs = new Map<string, ManagedBashJob>();\nexport function formatAsyncJobError(error: unknown): string {\n\tconst message = error instanceof Error ? error.message : String(error);\n\tif (message.startsWith(\"timeout:\")) return `Command timed out after ${message.slice(\"timeout:\".length)} seconds`;\n\treturn message;\n}\nfunction deleteJobOutput(job: ManagedBashJob): void {\n\tif (!job.fullOutputPath) return;\n\ttry { rmSync(job.fullOutputPath, { force: true }); } catch { /* best-effort temp cleanup */ }\n}\n\nfunction cleanupManagedBashJobs(now = Date.now()): void {\n\tfor (const [jobId, job] of managedBashJobs) if (job.status !== \"running\" && job.endedAt !== undefined && now - job.endedAt > COMPLETED_JOB_TTL_MS) { deleteJobOutput(job); managedBashJobs.delete(jobId); }\n\twhile (managedBashJobs.size > MAX_MANAGED_BASH_JOBS) {\n\t\tconst oldest = [...managedBashJobs.values()].sort((a, b) => (a.endedAt ?? a.startedAt) - (b.endedAt ?? b.startedAt))[0];\n\t\tif (!oldest) break;\n\t\tif (oldest.status === \"running\") oldest.abortController?.abort(); else deleteJobOutput(oldest);\n\t\tmanagedBashJobs.delete(oldest.jobId);\n\t}\n}\n\nexport function createManagedBashJob(command: string, cwd: string, timeoutSeconds?: number, requestedTimeoutSeconds?: number): ManagedBashJob {\n\tcleanupManagedBashJobs();\n\tconst jobId = `bash-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n\tconst job: ManagedBashJob = { jobId, command, cwd, status: \"running\", output: \"\", startedAt: Date.now(), timeoutSeconds, requestedTimeoutSeconds, abortController: new AbortController() };\n\tmanagedBashJobs.set(jobId, job);\n\tcleanupManagedBashJobs();\n\treturn job;\n}\n\nexport function getManagedBashJob(jobId: string): ManagedBashJob | undefined {\n\tcleanupManagedBashJobs();\n\tconst job = managedBashJobs.get(jobId);\n\tif (!job) return undefined;\n\tconst { abortController: _abortController, ...snapshot } = job;\n\treturn { ...snapshot };\n}\n\nexport function abortManagedBashJob(jobId: string): ManagedBashJob | undefined {\n\tconst job = managedBashJobs.get(jobId);\n\tif (!job) return undefined;\n\tjob.abortController?.abort();\n\treturn job;\n}\n"]}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { rmSync } from "node:fs";
|
|
2
|
+
const MAX_MANAGED_BASH_JOBS = 100;
|
|
3
|
+
const COMPLETED_JOB_TTL_MS = 30 * 60 * 1000;
|
|
4
|
+
const managedBashJobs = new Map();
|
|
5
|
+
export function formatAsyncJobError(error) {
|
|
6
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7
|
+
if (message.startsWith("timeout:"))
|
|
8
|
+
return `Command timed out after ${message.slice("timeout:".length)} seconds`;
|
|
9
|
+
return message;
|
|
10
|
+
}
|
|
11
|
+
function deleteJobOutput(job) {
|
|
12
|
+
if (!job.fullOutputPath)
|
|
13
|
+
return;
|
|
14
|
+
try {
|
|
15
|
+
rmSync(job.fullOutputPath, { force: true });
|
|
16
|
+
}
|
|
17
|
+
catch { /* best-effort temp cleanup */ }
|
|
18
|
+
}
|
|
19
|
+
function cleanupManagedBashJobs(now = Date.now()) {
|
|
20
|
+
for (const [jobId, job] of managedBashJobs)
|
|
21
|
+
if (job.status !== "running" && job.endedAt !== undefined && now - job.endedAt > COMPLETED_JOB_TTL_MS) {
|
|
22
|
+
deleteJobOutput(job);
|
|
23
|
+
managedBashJobs.delete(jobId);
|
|
24
|
+
}
|
|
25
|
+
while (managedBashJobs.size > MAX_MANAGED_BASH_JOBS) {
|
|
26
|
+
const oldest = [...managedBashJobs.values()].sort((a, b) => (a.endedAt ?? a.startedAt) - (b.endedAt ?? b.startedAt))[0];
|
|
27
|
+
if (!oldest)
|
|
28
|
+
break;
|
|
29
|
+
if (oldest.status === "running")
|
|
30
|
+
oldest.abortController?.abort();
|
|
31
|
+
else
|
|
32
|
+
deleteJobOutput(oldest);
|
|
33
|
+
managedBashJobs.delete(oldest.jobId);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export function createManagedBashJob(command, cwd, timeoutSeconds, requestedTimeoutSeconds) {
|
|
37
|
+
cleanupManagedBashJobs();
|
|
38
|
+
const jobId = `bash-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
39
|
+
const job = { jobId, command, cwd, status: "running", output: "", startedAt: Date.now(), timeoutSeconds, requestedTimeoutSeconds, abortController: new AbortController() };
|
|
40
|
+
managedBashJobs.set(jobId, job);
|
|
41
|
+
cleanupManagedBashJobs();
|
|
42
|
+
return job;
|
|
43
|
+
}
|
|
44
|
+
export function getManagedBashJob(jobId) {
|
|
45
|
+
cleanupManagedBashJobs();
|
|
46
|
+
const job = managedBashJobs.get(jobId);
|
|
47
|
+
if (!job)
|
|
48
|
+
return undefined;
|
|
49
|
+
const { abortController: _abortController, ...snapshot } = job;
|
|
50
|
+
return { ...snapshot };
|
|
51
|
+
}
|
|
52
|
+
export function abortManagedBashJob(jobId) {
|
|
53
|
+
const job = managedBashJobs.get(jobId);
|
|
54
|
+
if (!job)
|
|
55
|
+
return undefined;
|
|
56
|
+
job.abortController?.abort();
|
|
57
|
+
return job;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=bash-async-jobs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bash-async-jobs.js","sourceRoot":"","sources":["../../../src/core/tools/bash-async-jobs.ts"],"names":[],"mappings":"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","sourcesContent":["import { rmSync } from \"node:fs\";\n\nexport interface ManagedBashJob {\n\tjobId: string;\n\tcommand: string;\n\tcwd: string;\n\tstatus: \"running\" | \"completed\" | \"failed\";\n\toutput: string;\n\tfullOutputPath?: string;\n\texitCode?: number | null;\n\terror?: string;\n\tstartedAt: number;\n\tendedAt?: number;\n\ttimeoutSeconds?: number;\n\trequestedTimeoutSeconds?: number;\n\tabortController?: AbortController;\n}\n\nconst MAX_MANAGED_BASH_JOBS = 100;\nconst COMPLETED_JOB_TTL_MS = 30 * 60 * 1000;\nconst managedBashJobs = new Map<string, ManagedBashJob>();\nexport function formatAsyncJobError(error: unknown): string {\n\tconst message = error instanceof Error ? error.message : String(error);\n\tif (message.startsWith(\"timeout:\")) return `Command timed out after ${message.slice(\"timeout:\".length)} seconds`;\n\treturn message;\n}\nfunction deleteJobOutput(job: ManagedBashJob): void {\n\tif (!job.fullOutputPath) return;\n\ttry { rmSync(job.fullOutputPath, { force: true }); } catch { /* best-effort temp cleanup */ }\n}\n\nfunction cleanupManagedBashJobs(now = Date.now()): void {\n\tfor (const [jobId, job] of managedBashJobs) if (job.status !== \"running\" && job.endedAt !== undefined && now - job.endedAt > COMPLETED_JOB_TTL_MS) { deleteJobOutput(job); managedBashJobs.delete(jobId); }\n\twhile (managedBashJobs.size > MAX_MANAGED_BASH_JOBS) {\n\t\tconst oldest = [...managedBashJobs.values()].sort((a, b) => (a.endedAt ?? a.startedAt) - (b.endedAt ?? b.startedAt))[0];\n\t\tif (!oldest) break;\n\t\tif (oldest.status === \"running\") oldest.abortController?.abort(); else deleteJobOutput(oldest);\n\t\tmanagedBashJobs.delete(oldest.jobId);\n\t}\n}\n\nexport function createManagedBashJob(command: string, cwd: string, timeoutSeconds?: number, requestedTimeoutSeconds?: number): ManagedBashJob {\n\tcleanupManagedBashJobs();\n\tconst jobId = `bash-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n\tconst job: ManagedBashJob = { jobId, command, cwd, status: \"running\", output: \"\", startedAt: Date.now(), timeoutSeconds, requestedTimeoutSeconds, abortController: new AbortController() };\n\tmanagedBashJobs.set(jobId, job);\n\tcleanupManagedBashJobs();\n\treturn job;\n}\n\nexport function getManagedBashJob(jobId: string): ManagedBashJob | undefined {\n\tcleanupManagedBashJobs();\n\tconst job = managedBashJobs.get(jobId);\n\tif (!job) return undefined;\n\tconst { abortController: _abortController, ...snapshot } = job;\n\treturn { ...snapshot };\n}\n\nexport function abortManagedBashJob(jobId: string): ManagedBashJob | undefined {\n\tconst job = managedBashJobs.get(jobId);\n\tif (!job) return undefined;\n\tjob.abortController?.abort();\n\treturn job;\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface BashAsyncOutputTarget {
|
|
2
|
+
output: string;
|
|
3
|
+
fullOutputPath?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface BashAsyncOutputAppender {
|
|
6
|
+
append(chunk: Buffer): void;
|
|
7
|
+
close(): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
export declare function createAsyncOutputAppender(job: BashAsyncOutputTarget): BashAsyncOutputAppender;
|
|
10
|
+
//# sourceMappingURL=bash-async-output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bash-async-output.d.ts","sourceRoot":"","sources":["../../../src/core/tools/bash-async-output.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,qBAAqB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,uBAAuB;IACvC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAeD,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,qBAAqB,GAAG,uBAAuB,CAmD7F","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { createWriteStream, type WriteStream } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { APP_NAME } from \"../../config.ts\";\nimport { stripAnsi } from \"../../utils/ansi.ts\";\nimport { sanitizeBinaryOutput } from \"../../utils/shell.ts\";\nimport { DEFAULT_MAX_BYTES, formatSize } from \"./truncate.ts\";\n\nexport interface BashAsyncOutputTarget {\n\toutput: string;\n\tfullOutputPath?: string;\n}\n\nexport interface BashAsyncOutputAppender {\n\tappend(chunk: Buffer): void;\n\tclose(): Promise<void>;\n}\n\nfunction outputPath(): string {\n\treturn join(tmpdir(), `${APP_NAME}-bash-async-${randomBytes(8).toString(\"hex\")}.log`);\n}\n\nfunction byteLength(text: string): number { return Buffer.byteLength(text, \"utf8\"); }\nfunction sanitizeDecodedOutput(text: string): string { return sanitizeBinaryOutput(stripAnsi(text)).replace(/\\r/g, \"\"); }\nfunction utf8Prefix(text: string, maxBytes: number): string {\n\tif (byteLength(text) <= maxBytes) return text;\n\tlet end = text.length;\n\twhile (end > 0 && byteLength(text.slice(0, end)) > maxBytes) end--;\n\treturn text.slice(0, end);\n}\n\nexport function createAsyncOutputAppender(job: BashAsyncOutputTarget): BashAsyncOutputAppender {\n\tlet outputBytes = 0;\n\tlet truncated = false;\n\tlet fullOutputStream: WriteStream | undefined;\n\tlet bufferedChunks: Buffer[] = [];\n\tconst decoder = new TextDecoder();\n\n\tconst ensureFullOutputStream = (): WriteStream => {\n\t\tif (fullOutputStream) return fullOutputStream;\n\t\tjob.fullOutputPath = outputPath();\n\t\tfullOutputStream = createWriteStream(job.fullOutputPath);\n\t\tfor (const chunk of bufferedChunks) fullOutputStream.write(chunk);\n\t\tbufferedChunks = [];\n\t\treturn fullOutputStream;\n\t};\n\tconst appendDecodedText = (decoded: string): void => {\n\t\tif (truncated || decoded.length === 0) return;\n\t\tconst text = sanitizeDecodedOutput(decoded);\n\t\tif (text.length === 0) return;\n\t\tconst bytes = byteLength(text);\n\t\tif (outputBytes + bytes > DEFAULT_MAX_BYTES) {\n\t\t\tensureFullOutputStream();\n\t\t\tconst remaining = Math.max(0, DEFAULT_MAX_BYTES - outputBytes);\n\t\t\tif (remaining > 0) job.output += utf8Prefix(text, remaining);\n\t\t\tjob.output += `\\n[Output truncated at ${formatSize(DEFAULT_MAX_BYTES)} for async job polling. Full output: ${job.fullOutputPath}]`;\n\t\t\toutputBytes += bytes;\n\t\t\ttruncated = true;\n\t\t\treturn;\n\t\t}\n\t\toutputBytes += bytes;\n\t\tjob.output += text;\n\t};\n\n\treturn {\n\t\tappend(chunk) {\n\t\t\tif (fullOutputStream) fullOutputStream.write(chunk);\n\t\t\telse bufferedChunks.push(chunk);\n\t\t\tappendDecodedText(decoder.decode(chunk, { stream: true }));\n\t\t},\n\t\tasync close() {\n\t\t\tappendDecodedText(decoder.decode());\n\t\t\tif (!fullOutputStream) return;\n\t\t\tconst stream = fullOutputStream;\n\t\t\tfullOutputStream = undefined;\n\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\tstream.once(\"error\", reject);\n\t\t\t\tstream.once(\"finish\", resolve);\n\t\t\t\tstream.end();\n\t\t\t});\n\t\t},\n\t};\n}\n"]}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { createWriteStream } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { APP_NAME } from "../../config.js";
|
|
6
|
+
import { stripAnsi } from "../../utils/ansi.js";
|
|
7
|
+
import { sanitizeBinaryOutput } from "../../utils/shell.js";
|
|
8
|
+
import { DEFAULT_MAX_BYTES, formatSize } from "./truncate.js";
|
|
9
|
+
function outputPath() {
|
|
10
|
+
return join(tmpdir(), `${APP_NAME}-bash-async-${randomBytes(8).toString("hex")}.log`);
|
|
11
|
+
}
|
|
12
|
+
function byteLength(text) { return Buffer.byteLength(text, "utf8"); }
|
|
13
|
+
function sanitizeDecodedOutput(text) { return sanitizeBinaryOutput(stripAnsi(text)).replace(/\r/g, ""); }
|
|
14
|
+
function utf8Prefix(text, maxBytes) {
|
|
15
|
+
if (byteLength(text) <= maxBytes)
|
|
16
|
+
return text;
|
|
17
|
+
let end = text.length;
|
|
18
|
+
while (end > 0 && byteLength(text.slice(0, end)) > maxBytes)
|
|
19
|
+
end--;
|
|
20
|
+
return text.slice(0, end);
|
|
21
|
+
}
|
|
22
|
+
export function createAsyncOutputAppender(job) {
|
|
23
|
+
let outputBytes = 0;
|
|
24
|
+
let truncated = false;
|
|
25
|
+
let fullOutputStream;
|
|
26
|
+
let bufferedChunks = [];
|
|
27
|
+
const decoder = new TextDecoder();
|
|
28
|
+
const ensureFullOutputStream = () => {
|
|
29
|
+
if (fullOutputStream)
|
|
30
|
+
return fullOutputStream;
|
|
31
|
+
job.fullOutputPath = outputPath();
|
|
32
|
+
fullOutputStream = createWriteStream(job.fullOutputPath);
|
|
33
|
+
for (const chunk of bufferedChunks)
|
|
34
|
+
fullOutputStream.write(chunk);
|
|
35
|
+
bufferedChunks = [];
|
|
36
|
+
return fullOutputStream;
|
|
37
|
+
};
|
|
38
|
+
const appendDecodedText = (decoded) => {
|
|
39
|
+
if (truncated || decoded.length === 0)
|
|
40
|
+
return;
|
|
41
|
+
const text = sanitizeDecodedOutput(decoded);
|
|
42
|
+
if (text.length === 0)
|
|
43
|
+
return;
|
|
44
|
+
const bytes = byteLength(text);
|
|
45
|
+
if (outputBytes + bytes > DEFAULT_MAX_BYTES) {
|
|
46
|
+
ensureFullOutputStream();
|
|
47
|
+
const remaining = Math.max(0, DEFAULT_MAX_BYTES - outputBytes);
|
|
48
|
+
if (remaining > 0)
|
|
49
|
+
job.output += utf8Prefix(text, remaining);
|
|
50
|
+
job.output += `\n[Output truncated at ${formatSize(DEFAULT_MAX_BYTES)} for async job polling. Full output: ${job.fullOutputPath}]`;
|
|
51
|
+
outputBytes += bytes;
|
|
52
|
+
truncated = true;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
outputBytes += bytes;
|
|
56
|
+
job.output += text;
|
|
57
|
+
};
|
|
58
|
+
return {
|
|
59
|
+
append(chunk) {
|
|
60
|
+
if (fullOutputStream)
|
|
61
|
+
fullOutputStream.write(chunk);
|
|
62
|
+
else
|
|
63
|
+
bufferedChunks.push(chunk);
|
|
64
|
+
appendDecodedText(decoder.decode(chunk, { stream: true }));
|
|
65
|
+
},
|
|
66
|
+
async close() {
|
|
67
|
+
appendDecodedText(decoder.decode());
|
|
68
|
+
if (!fullOutputStream)
|
|
69
|
+
return;
|
|
70
|
+
const stream = fullOutputStream;
|
|
71
|
+
fullOutputStream = undefined;
|
|
72
|
+
await new Promise((resolve, reject) => {
|
|
73
|
+
stream.once("error", reject);
|
|
74
|
+
stream.once("finish", resolve);
|
|
75
|
+
stream.end();
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=bash-async-output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bash-async-output.js","sourceRoot":"","sources":["../../../src/core/tools/bash-async-output.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { createWriteStream, type WriteStream } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { APP_NAME } from \"../../config.ts\";\nimport { stripAnsi } from \"../../utils/ansi.ts\";\nimport { sanitizeBinaryOutput } from \"../../utils/shell.ts\";\nimport { DEFAULT_MAX_BYTES, formatSize } from \"./truncate.ts\";\n\nexport interface BashAsyncOutputTarget {\n\toutput: string;\n\tfullOutputPath?: string;\n}\n\nexport interface BashAsyncOutputAppender {\n\tappend(chunk: Buffer): void;\n\tclose(): Promise<void>;\n}\n\nfunction outputPath(): string {\n\treturn join(tmpdir(), `${APP_NAME}-bash-async-${randomBytes(8).toString(\"hex\")}.log`);\n}\n\nfunction byteLength(text: string): number { return Buffer.byteLength(text, \"utf8\"); }\nfunction sanitizeDecodedOutput(text: string): string { return sanitizeBinaryOutput(stripAnsi(text)).replace(/\\r/g, \"\"); }\nfunction utf8Prefix(text: string, maxBytes: number): string {\n\tif (byteLength(text) <= maxBytes) return text;\n\tlet end = text.length;\n\twhile (end > 0 && byteLength(text.slice(0, end)) > maxBytes) end--;\n\treturn text.slice(0, end);\n}\n\nexport function createAsyncOutputAppender(job: BashAsyncOutputTarget): BashAsyncOutputAppender {\n\tlet outputBytes = 0;\n\tlet truncated = false;\n\tlet fullOutputStream: WriteStream | undefined;\n\tlet bufferedChunks: Buffer[] = [];\n\tconst decoder = new TextDecoder();\n\n\tconst ensureFullOutputStream = (): WriteStream => {\n\t\tif (fullOutputStream) return fullOutputStream;\n\t\tjob.fullOutputPath = outputPath();\n\t\tfullOutputStream = createWriteStream(job.fullOutputPath);\n\t\tfor (const chunk of bufferedChunks) fullOutputStream.write(chunk);\n\t\tbufferedChunks = [];\n\t\treturn fullOutputStream;\n\t};\n\tconst appendDecodedText = (decoded: string): void => {\n\t\tif (truncated || decoded.length === 0) return;\n\t\tconst text = sanitizeDecodedOutput(decoded);\n\t\tif (text.length === 0) return;\n\t\tconst bytes = byteLength(text);\n\t\tif (outputBytes + bytes > DEFAULT_MAX_BYTES) {\n\t\t\tensureFullOutputStream();\n\t\t\tconst remaining = Math.max(0, DEFAULT_MAX_BYTES - outputBytes);\n\t\t\tif (remaining > 0) job.output += utf8Prefix(text, remaining);\n\t\t\tjob.output += `\\n[Output truncated at ${formatSize(DEFAULT_MAX_BYTES)} for async job polling. Full output: ${job.fullOutputPath}]`;\n\t\t\toutputBytes += bytes;\n\t\t\ttruncated = true;\n\t\t\treturn;\n\t\t}\n\t\toutputBytes += bytes;\n\t\tjob.output += text;\n\t};\n\n\treturn {\n\t\tappend(chunk) {\n\t\t\tif (fullOutputStream) fullOutputStream.write(chunk);\n\t\t\telse bufferedChunks.push(chunk);\n\t\t\tappendDecodedText(decoder.decode(chunk, { stream: true }));\n\t\t},\n\t\tasync close() {\n\t\t\tappendDecodedText(decoder.decode());\n\t\t\tif (!fullOutputStream) return;\n\t\t\tconst stream = fullOutputStream;\n\t\t\tfullOutputStream = undefined;\n\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\tstream.once(\"error\", reject);\n\t\t\t\tstream.once(\"finish\", resolve);\n\t\t\t\tstream.end();\n\t\t\t});\n\t\t},\n\t};\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface BashInterceptorRule {
|
|
2
|
+
pattern: string;
|
|
3
|
+
flags?: string;
|
|
4
|
+
tool: string;
|
|
5
|
+
message: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const DEFAULT_BASH_INTERCEPTOR_RULES: BashInterceptorRule[];
|
|
8
|
+
export declare function checkBashInterception(command: string, availableTools: readonly string[], rules?: readonly BashInterceptorRule[]): string | undefined;
|
|
9
|
+
export declare function checkBashInterceptionCandidates(candidates: Array<string | undefined>, availableTools: readonly string[], rules?: readonly BashInterceptorRule[]): void;
|
|
10
|
+
//# sourceMappingURL=bash-interceptor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bash-interceptor.d.ts","sourceRoot":"","sources":["../../../src/core/tools/bash-interceptor.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,8BAA8B,EAAE,mBAAmB,EAQ/D,CAAC;AAEF,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,SAAS,MAAM,EAAE,EACjC,KAAK,GAAE,SAAS,mBAAmB,EAAmC,GACpE,MAAM,GAAG,SAAS,CAWpB;AAED,wBAAgB,+BAA+B,CAC9C,UAAU,EAAE,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC,EACrC,cAAc,EAAE,SAAS,MAAM,EAAE,EACjC,KAAK,GAAE,SAAS,mBAAmB,EAAmC,GACpE,IAAI,CASN","sourcesContent":["export interface BashInterceptorRule {\n\tpattern: string;\n\tflags?: string;\n\ttool: string;\n\tmessage: string;\n}\n\nexport const DEFAULT_BASH_INTERCEPTOR_RULES: BashInterceptorRule[] = [\n\t{ pattern: \"^\\\\s*(cat|head|tail|less|more)\\\\s+\", tool: \"read\", message: \"Use the read tool instead of shell commands to inspect file contents.\" },\n\t{ pattern: \"^\\\\s*(grep|rg|ripgrep|ag|ack)\\\\s+\", tool: \"search\", message: \"Use the search tool instead of shell grep commands.\" },\n\t{ pattern: \"^\\\\s*(find|fd|locate)\\\\s+.*(-name|-iname|-type|--type|-glob)\", tool: \"find\", message: \"Use the find tool instead of shell find/fd/locate commands.\" },\n\t{ pattern: \"^\\\\s*sed\\\\s+(-i|--in-place)\", tool: \"edit\", message: \"Use the edit tool instead of in-place sed.\" },\n\t{ pattern: \"^\\\\s*perl\\\\s+.*-[pn]?i\", tool: \"edit\", message: \"Use the edit tool instead of in-place perl.\" },\n\t{ pattern: \"^\\\\s*awk\\\\s+.*-i\\\\s+inplace\", tool: \"edit\", message: \"Use the edit tool instead of in-place awk.\" },\n\t{ pattern: \"^\\\\s*(echo|printf|cat\\\\s*<<)\\\\s+(?:[^\\\"'>]|\\\"[^\\\"]*\\\"|'[^']*')*(?<!\\\\|)>{1,2}\\\\|?\\\\s*[$\\\\w./~\\\"'-]\", tool: \"write\", message: \"Use the write tool instead of shell redirection to write files.\" },\n];\n\nexport function checkBashInterception(\n\tcommand: string,\n\tavailableTools: readonly string[],\n\trules: readonly BashInterceptorRule[] = DEFAULT_BASH_INTERCEPTOR_RULES,\n): string | undefined {\n\tfor (const rule of rules) {\n\t\tif (!availableTools.includes(rule.tool)) continue;\n\t\tlet matcher: RegExp;\n\t\ttry { matcher = new RegExp(rule.pattern, rule.flags); }\n\t\tcatch (error) { throw new Error(`Invalid bash interceptor rule for ${rule.tool}: ${error instanceof Error ? error.message : String(error)}`); }\n\t\tif (matcher.test(command.trim())) {\n\t\t\treturn `Blocked: ${rule.message}\\n\\nOriginal command: ${command}`;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nexport function checkBashInterceptionCandidates(\n\tcandidates: Array<string | undefined>,\n\tavailableTools: readonly string[],\n\trules: readonly BashInterceptorRule[] = DEFAULT_BASH_INTERCEPTOR_RULES,\n): void {\n\tconst seen = new Set<string>();\n\tfor (const candidate of candidates) {\n\t\tconst command = candidate?.trim();\n\t\tif (!command || seen.has(command)) continue;\n\t\tseen.add(command);\n\t\tconst blocked = checkBashInterception(command, availableTools, rules);\n\t\tif (blocked) throw new Error(blocked);\n\t}\n}\n"]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export const DEFAULT_BASH_INTERCEPTOR_RULES = [
|
|
2
|
+
{ pattern: "^\\s*(cat|head|tail|less|more)\\s+", tool: "read", message: "Use the read tool instead of shell commands to inspect file contents." },
|
|
3
|
+
{ pattern: "^\\s*(grep|rg|ripgrep|ag|ack)\\s+", tool: "search", message: "Use the search tool instead of shell grep commands." },
|
|
4
|
+
{ pattern: "^\\s*(find|fd|locate)\\s+.*(-name|-iname|-type|--type|-glob)", tool: "find", message: "Use the find tool instead of shell find/fd/locate commands." },
|
|
5
|
+
{ pattern: "^\\s*sed\\s+(-i|--in-place)", tool: "edit", message: "Use the edit tool instead of in-place sed." },
|
|
6
|
+
{ pattern: "^\\s*perl\\s+.*-[pn]?i", tool: "edit", message: "Use the edit tool instead of in-place perl." },
|
|
7
|
+
{ pattern: "^\\s*awk\\s+.*-i\\s+inplace", tool: "edit", message: "Use the edit tool instead of in-place awk." },
|
|
8
|
+
{ pattern: "^\\s*(echo|printf|cat\\s*<<)\\s+(?:[^\"'>]|\"[^\"]*\"|'[^']*')*(?<!\\|)>{1,2}\\|?\\s*[$\\w./~\"'-]", tool: "write", message: "Use the write tool instead of shell redirection to write files." },
|
|
9
|
+
];
|
|
10
|
+
export function checkBashInterception(command, availableTools, rules = DEFAULT_BASH_INTERCEPTOR_RULES) {
|
|
11
|
+
for (const rule of rules) {
|
|
12
|
+
if (!availableTools.includes(rule.tool))
|
|
13
|
+
continue;
|
|
14
|
+
let matcher;
|
|
15
|
+
try {
|
|
16
|
+
matcher = new RegExp(rule.pattern, rule.flags);
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
throw new Error(`Invalid bash interceptor rule for ${rule.tool}: ${error instanceof Error ? error.message : String(error)}`);
|
|
20
|
+
}
|
|
21
|
+
if (matcher.test(command.trim())) {
|
|
22
|
+
return `Blocked: ${rule.message}\n\nOriginal command: ${command}`;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
export function checkBashInterceptionCandidates(candidates, availableTools, rules = DEFAULT_BASH_INTERCEPTOR_RULES) {
|
|
28
|
+
const seen = new Set();
|
|
29
|
+
for (const candidate of candidates) {
|
|
30
|
+
const command = candidate?.trim();
|
|
31
|
+
if (!command || seen.has(command))
|
|
32
|
+
continue;
|
|
33
|
+
seen.add(command);
|
|
34
|
+
const blocked = checkBashInterception(command, availableTools, rules);
|
|
35
|
+
if (blocked)
|
|
36
|
+
throw new Error(blocked);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=bash-interceptor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bash-interceptor.js","sourceRoot":"","sources":["../../../src/core/tools/bash-interceptor.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,MAAM,8BAA8B,GAA0B;IACpE,EAAE,OAAO,EAAE,oCAAoC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,uEAAuE,EAAE;IACjJ,EAAE,OAAO,EAAE,mCAAmC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,qDAAqD,EAAE;IAChI,EAAE,OAAO,EAAE,8DAA8D,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,6DAA6D,EAAE;IACjK,EAAE,OAAO,EAAE,6BAA6B,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,4CAA4C,EAAE;IAC/G,EAAE,OAAO,EAAE,wBAAwB,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,6CAA6C,EAAE;IAC3G,EAAE,OAAO,EAAE,6BAA6B,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,4CAA4C,EAAE;IAC/G,EAAE,OAAO,EAAE,oGAAoG,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,iEAAiE,EAAE;CAC5M,CAAC;AAEF,MAAM,UAAU,qBAAqB,CACpC,OAAe,EACf,cAAiC,EACjC,KAAK,GAAmC,8BAA8B;IAEtE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,SAAS;QAClD,IAAI,OAAe,CAAC;QACpB,IAAI,CAAC;YAAC,OAAO,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAAC,CAAC;QACvD,OAAO,KAAK,EAAE,CAAC;YAAC,MAAM,IAAI,KAAK,CAAC,qCAAqC,IAAI,CAAC,IAAI,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAAC,CAAC;QAC/I,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YAClC,OAAO,YAAY,IAAI,CAAC,OAAO,yBAAyB,OAAO,EAAE,CAAC;QACnE,CAAC;IACF,CAAC;IACD,OAAO,SAAS,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,+BAA+B,CAC9C,UAAqC,EACrC,cAAiC,EACjC,KAAK,GAAmC,8BAA8B;IAEtE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,SAAS,EAAE,IAAI,EAAE,CAAC;QAClC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,SAAS;QAC5C,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAClB,MAAM,OAAO,GAAG,qBAAqB,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,CAAC,CAAC;QACtE,IAAI,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IACvC,CAAC;AACF,CAAC","sourcesContent":["export interface BashInterceptorRule {\n\tpattern: string;\n\tflags?: string;\n\ttool: string;\n\tmessage: string;\n}\n\nexport const DEFAULT_BASH_INTERCEPTOR_RULES: BashInterceptorRule[] = [\n\t{ pattern: \"^\\\\s*(cat|head|tail|less|more)\\\\s+\", tool: \"read\", message: \"Use the read tool instead of shell commands to inspect file contents.\" },\n\t{ pattern: \"^\\\\s*(grep|rg|ripgrep|ag|ack)\\\\s+\", tool: \"search\", message: \"Use the search tool instead of shell grep commands.\" },\n\t{ pattern: \"^\\\\s*(find|fd|locate)\\\\s+.*(-name|-iname|-type|--type|-glob)\", tool: \"find\", message: \"Use the find tool instead of shell find/fd/locate commands.\" },\n\t{ pattern: \"^\\\\s*sed\\\\s+(-i|--in-place)\", tool: \"edit\", message: \"Use the edit tool instead of in-place sed.\" },\n\t{ pattern: \"^\\\\s*perl\\\\s+.*-[pn]?i\", tool: \"edit\", message: \"Use the edit tool instead of in-place perl.\" },\n\t{ pattern: \"^\\\\s*awk\\\\s+.*-i\\\\s+inplace\", tool: \"edit\", message: \"Use the edit tool instead of in-place awk.\" },\n\t{ pattern: \"^\\\\s*(echo|printf|cat\\\\s*<<)\\\\s+(?:[^\\\"'>]|\\\"[^\\\"]*\\\"|'[^']*')*(?<!\\\\|)>{1,2}\\\\|?\\\\s*[$\\\\w./~\\\"'-]\", tool: \"write\", message: \"Use the write tool instead of shell redirection to write files.\" },\n];\n\nexport function checkBashInterception(\n\tcommand: string,\n\tavailableTools: readonly string[],\n\trules: readonly BashInterceptorRule[] = DEFAULT_BASH_INTERCEPTOR_RULES,\n): string | undefined {\n\tfor (const rule of rules) {\n\t\tif (!availableTools.includes(rule.tool)) continue;\n\t\tlet matcher: RegExp;\n\t\ttry { matcher = new RegExp(rule.pattern, rule.flags); }\n\t\tcatch (error) { throw new Error(`Invalid bash interceptor rule for ${rule.tool}: ${error instanceof Error ? error.message : String(error)}`); }\n\t\tif (matcher.test(command.trim())) {\n\t\t\treturn `Blocked: ${rule.message}\\n\\nOriginal command: ${command}`;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nexport function checkBashInterceptionCandidates(\n\tcandidates: Array<string | undefined>,\n\tavailableTools: readonly string[],\n\trules: readonly BashInterceptorRule[] = DEFAULT_BASH_INTERCEPTOR_RULES,\n): void {\n\tconst seen = new Set<string>();\n\tfor (const candidate of candidates) {\n\t\tconst command = candidate?.trim();\n\t\tif (!command || seen.has(command)) continue;\n\t\tseen.add(command);\n\t\tconst blocked = checkBashInterception(command, availableTools, rules);\n\t\tif (blocked) throw new Error(blocked);\n\t}\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bash-leading-cd.d.ts","sourceRoot":"","sources":["../../../src/core/tools/bash-leading-cd.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,qBAAqB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;CACvB;AAUD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS,CA+BrG","sourcesContent":["import { homedir } from \"node:os\";\nimport { resolve as resolvePath } from \"node:path\";\nimport { getShellEnv } from \"../../utils/shell.ts\";\n\nexport interface LeadingCdSpawnContext {\n\tcommand: string;\n\tcwd: string;\n\tenv: NodeJS.ProcessEnv;\n}\n\nfunction isShellWhitespace(char: string | undefined): boolean { return char === \" \" || char === \"\\t\" || char === \"\\n\" || char === \"\\r\"; }\nfunction requiresShellExpansion(pathValue: string): boolean { return pathValue.includes(\"$\") || pathValue.includes(\"`\") || pathValue.includes(\"(\"); }\nfunction expandHomePath(pathValue: string): string {\n\tif (pathValue === \"~\") return homedir();\n\tif (pathValue.startsWith(\"~/\")) return resolvePath(homedir(), pathValue.slice(2));\n\treturn pathValue;\n}\n\nexport function stripLeadingCdCommand(command: string, cwd: string): LeadingCdSpawnContext | undefined {\n\tlet index = 0;\n\twhile (isShellWhitespace(command[index])) index++;\n\tif (command.slice(index, index + 2) !== \"cd\" || !isShellWhitespace(command[index + 2])) return undefined;\n\tindex += 2;\n\twhile (isShellWhitespace(command[index])) index++;\n\tlet rawPath = \"\";\n\tconst quote = command[index];\n\tif (quote === \"'\" || quote === '\"') {\n\t\tindex++;\n\t\tconst pathStart = index;\n\t\twhile (index < command.length && command[index] !== quote) index++;\n\t\tif (index >= command.length) return undefined;\n\t\trawPath = command.slice(pathStart, index);\n\t\tindex++;\n\t} else {\n\t\tconst pathStart = index;\n\t\twhile (index < command.length && command[index] !== \"&\" && command[index] !== \";\") index++;\n\t\trawPath = command.slice(pathStart, index).trim();\n\t}\n\tif (!rawPath) return undefined;\n\tif (requiresShellExpansion(rawPath)) return undefined;\n\twhile (isShellWhitespace(command[index])) index++;\n\tlet separatorLength = 0;\n\tif (command[index] === \"&\" && command[index + 1] === \"&\") separatorLength = 2;\n\telse if (command[index] === \";\") separatorLength = 1;\n\telse return undefined;\n\tindex += separatorLength;\n\twhile (isShellWhitespace(command[index])) index++;\n\tconst nextCommand = command.slice(index);\n\treturn nextCommand ? { command: nextCommand, cwd: resolvePath(cwd, expandHomePath(rawPath)), env: { ...getShellEnv() } } : undefined;\n}\n"]}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { resolve as resolvePath } from "node:path";
|
|
3
|
+
import { getShellEnv } from "../../utils/shell.js";
|
|
4
|
+
function isShellWhitespace(char) { return char === " " || char === "\t" || char === "\n" || char === "\r"; }
|
|
5
|
+
function requiresShellExpansion(pathValue) { return pathValue.includes("$") || pathValue.includes("`") || pathValue.includes("("); }
|
|
6
|
+
function expandHomePath(pathValue) {
|
|
7
|
+
if (pathValue === "~")
|
|
8
|
+
return homedir();
|
|
9
|
+
if (pathValue.startsWith("~/"))
|
|
10
|
+
return resolvePath(homedir(), pathValue.slice(2));
|
|
11
|
+
return pathValue;
|
|
12
|
+
}
|
|
13
|
+
export function stripLeadingCdCommand(command, cwd) {
|
|
14
|
+
let index = 0;
|
|
15
|
+
while (isShellWhitespace(command[index]))
|
|
16
|
+
index++;
|
|
17
|
+
if (command.slice(index, index + 2) !== "cd" || !isShellWhitespace(command[index + 2]))
|
|
18
|
+
return undefined;
|
|
19
|
+
index += 2;
|
|
20
|
+
while (isShellWhitespace(command[index]))
|
|
21
|
+
index++;
|
|
22
|
+
let rawPath = "";
|
|
23
|
+
const quote = command[index];
|
|
24
|
+
if (quote === "'" || quote === '"') {
|
|
25
|
+
index++;
|
|
26
|
+
const pathStart = index;
|
|
27
|
+
while (index < command.length && command[index] !== quote)
|
|
28
|
+
index++;
|
|
29
|
+
if (index >= command.length)
|
|
30
|
+
return undefined;
|
|
31
|
+
rawPath = command.slice(pathStart, index);
|
|
32
|
+
index++;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
const pathStart = index;
|
|
36
|
+
while (index < command.length && command[index] !== "&" && command[index] !== ";")
|
|
37
|
+
index++;
|
|
38
|
+
rawPath = command.slice(pathStart, index).trim();
|
|
39
|
+
}
|
|
40
|
+
if (!rawPath)
|
|
41
|
+
return undefined;
|
|
42
|
+
if (requiresShellExpansion(rawPath))
|
|
43
|
+
return undefined;
|
|
44
|
+
while (isShellWhitespace(command[index]))
|
|
45
|
+
index++;
|
|
46
|
+
let separatorLength = 0;
|
|
47
|
+
if (command[index] === "&" && command[index + 1] === "&")
|
|
48
|
+
separatorLength = 2;
|
|
49
|
+
else if (command[index] === ";")
|
|
50
|
+
separatorLength = 1;
|
|
51
|
+
else
|
|
52
|
+
return undefined;
|
|
53
|
+
index += separatorLength;
|
|
54
|
+
while (isShellWhitespace(command[index]))
|
|
55
|
+
index++;
|
|
56
|
+
const nextCommand = command.slice(index);
|
|
57
|
+
return nextCommand ? { command: nextCommand, cwd: resolvePath(cwd, expandHomePath(rawPath)), env: { ...getShellEnv() } } : undefined;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=bash-leading-cd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bash-leading-cd.js","sourceRoot":"","sources":["../../../src/core/tools/bash-leading-cd.ts"],"names":[],"mappings":"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","sourcesContent":["import { homedir } from \"node:os\";\nimport { resolve as resolvePath } from \"node:path\";\nimport { getShellEnv } from \"../../utils/shell.ts\";\n\nexport interface LeadingCdSpawnContext {\n\tcommand: string;\n\tcwd: string;\n\tenv: NodeJS.ProcessEnv;\n}\n\nfunction isShellWhitespace(char: string | undefined): boolean { return char === \" \" || char === \"\\t\" || char === \"\\n\" || char === \"\\r\"; }\nfunction requiresShellExpansion(pathValue: string): boolean { return pathValue.includes(\"$\") || pathValue.includes(\"`\") || pathValue.includes(\"(\"); }\nfunction expandHomePath(pathValue: string): string {\n\tif (pathValue === \"~\") return homedir();\n\tif (pathValue.startsWith(\"~/\")) return resolvePath(homedir(), pathValue.slice(2));\n\treturn pathValue;\n}\n\nexport function stripLeadingCdCommand(command: string, cwd: string): LeadingCdSpawnContext | undefined {\n\tlet index = 0;\n\twhile (isShellWhitespace(command[index])) index++;\n\tif (command.slice(index, index + 2) !== \"cd\" || !isShellWhitespace(command[index + 2])) return undefined;\n\tindex += 2;\n\twhile (isShellWhitespace(command[index])) index++;\n\tlet rawPath = \"\";\n\tconst quote = command[index];\n\tif (quote === \"'\" || quote === '\"') {\n\t\tindex++;\n\t\tconst pathStart = index;\n\t\twhile (index < command.length && command[index] !== quote) index++;\n\t\tif (index >= command.length) return undefined;\n\t\trawPath = command.slice(pathStart, index);\n\t\tindex++;\n\t} else {\n\t\tconst pathStart = index;\n\t\twhile (index < command.length && command[index] !== \"&\" && command[index] !== \";\") index++;\n\t\trawPath = command.slice(pathStart, index).trim();\n\t}\n\tif (!rawPath) return undefined;\n\tif (requiresShellExpansion(rawPath)) return undefined;\n\twhile (isShellWhitespace(command[index])) index++;\n\tlet separatorLength = 0;\n\tif (command[index] === \"&\" && command[index + 1] === \"&\") separatorLength = 2;\n\telse if (command[index] === \";\") separatorLength = 1;\n\telse return undefined;\n\tindex += separatorLength;\n\twhile (isShellWhitespace(command[index])) index++;\n\tconst nextCommand = command.slice(index);\n\treturn nextCommand ? { command: nextCommand, cwd: resolvePath(cwd, expandHomePath(rawPath)), env: { ...getShellEnv() } } : undefined;\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare function resetNativePtyBindingCache(): void;
|
|
2
|
+
export interface NativePtyExecOptions {
|
|
3
|
+
onData: (data: Buffer) => void;
|
|
4
|
+
signal?: AbortSignal;
|
|
5
|
+
timeout?: number;
|
|
6
|
+
env?: NodeJS.ProcessEnv;
|
|
7
|
+
shellPath?: string;
|
|
8
|
+
cols?: number;
|
|
9
|
+
rows?: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function executeNativePty(command: string, cwd: string, options: NativePtyExecOptions): Promise<{
|
|
12
|
+
exitCode: number | null;
|
|
13
|
+
}>;
|
|
14
|
+
//# sourceMappingURL=bash-pty-native.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bash-pty-native.d.ts","sourceRoot":"","sources":["../../../src/core/tools/bash-pty-native.ts"],"names":[],"mappings":"AA4CA,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD;AAqBD,MAAM,WAAW,oBAAoB;IACpC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CA+BxI","sourcesContent":["import { createRequire } from \"node:module\";\nimport { getShellConfig, getShellEnv } from \"../../utils/shell.ts\";\n\nconst NATIVE_PACKAGE = \"@bastani/atomic-natives\";\n\ninterface NativePtyRunResult {\n\texitCode?: number;\n\texit_code?: number;\n\tcancelled?: boolean;\n\ttimedOut?: boolean;\n\ttimed_out?: boolean;\n}\n\ninterface NativePtySession {\n\tstart(\n\t\toptions: {\n\t\t\tcommand: string;\n\t\t\tcwd?: string;\n\t\t\tenv?: Record<string, string>;\n\t\t\ttimeoutMs?: number;\n\t\t\tcols?: number;\n\t\t\trows?: number;\n\t\t\tshell?: string;\n\t\t\tshellArgs?: string[];\n\t\t\tcommandTransport?: \"argv\" | \"stdin\";\n\t\t\tcloseStdinAfterCommand?: boolean;\n\t\t},\n\t\tonChunk?: (error: Error | null, chunk: string) => void,\n\t): Promise<NativePtyRunResult>;\n\twrite(data: string): void;\n\tresize(cols: number, rows: number): void;\n\tkill(): void;\n}\n\ninterface NativePtyBinding {\n\tPtySession: new () => NativePtySession;\n}\n\ntype NativeLoadResult =\n\t| { ok: true; binding: NativePtyBinding }\n\t| { ok: false; error: Error };\n\nlet cachedLoadResult: NativeLoadResult | undefined;\n\nexport function resetNativePtyBindingCache(): void {\n\tcachedLoadResult = undefined;\n}\n\nfunction loadNativePtyBinding(): NativeLoadResult {\n\tif (cachedLoadResult) return cachedLoadResult;\n\ttry {\n\t\tconst loaded = createRequire(import.meta.url)(NATIVE_PACKAGE) as Partial<NativePtyBinding>;\n\t\tif (typeof loaded.PtySession !== \"function\") {\n\t\t\tcachedLoadResult = { ok: false, error: new Error(`Native package ${NATIVE_PACKAGE} is missing PtySession.`) };\n\t\t\treturn cachedLoadResult;\n\t\t}\n\t\tcachedLoadResult = { ok: true, binding: loaded as NativePtyBinding };\n\t\treturn cachedLoadResult;\n\t} catch (error) {\n\t\tcachedLoadResult = {\n\t\t\tok: false,\n\t\t\terror: new Error(`Native PTY package ${NATIVE_PACKAGE} is unavailable for ${process.platform}-${process.arch}: ${error instanceof Error ? error.message : String(error)}`),\n\t\t};\n\t\treturn cachedLoadResult;\n\t}\n}\n\nexport interface NativePtyExecOptions {\n\tonData: (data: Buffer) => void;\n\tsignal?: AbortSignal;\n\ttimeout?: number;\n\tenv?: NodeJS.ProcessEnv;\n\tshellPath?: string;\n\tcols?: number;\n\trows?: number;\n}\n\nexport async function executeNativePty(command: string, cwd: string, options: NativePtyExecOptions): Promise<{ exitCode: number | null }> {\n\tconst loaded = loadNativePtyBinding();\n\tif (!loaded.ok) throw loaded.error;\n\tif (options.signal?.aborted) throw new Error(\"aborted\");\n\tconst shellConfig = getShellConfig(options.shellPath);\n\tconst session = new loaded.binding.PtySession();\n\tconst onAbort = () => {\n\t\ttry { session.kill(); } catch {}\n\t};\n\tif (options.signal) options.signal.addEventListener(\"abort\", onAbort, { once: true });\n\ttry {\n\t\tconst result = await session.start({\n\t\t\tcommand,\n\t\t\tcwd,\n\t\t\tenv: { ...getShellEnv(), ...(options.env ?? {}), TERM: \"xterm-256color\" },\n\t\t\ttimeoutMs: options.timeout !== undefined ? Math.max(1, Math.floor(options.timeout * 1000)) : undefined,\n\t\t\tcols: options.cols ?? 120,\n\t\t\trows: options.rows ?? 40,\n\t\t\tshell: shellConfig.shell,\n\t\t\tshellArgs: shellConfig.args,\n\t\t\tcommandTransport: shellConfig.commandTransport,\n\t\t\tcloseStdinAfterCommand: shellConfig.commandTransport === \"stdin\",\n\t\t}, (_error, chunk) => {\n\t\t\tif (chunk) options.onData(Buffer.from(chunk));\n\t\t});\n\t\tif (options.signal?.aborted || result.cancelled) throw new Error(\"aborted\");\n\t\tif (result.timedOut ?? result.timed_out) throw new Error(`timeout:${options.timeout}`);\n\t\treturn { exitCode: result.exitCode ?? result.exit_code ?? null };\n\t} finally {\n\t\tif (options.signal) options.signal.removeEventListener(\"abort\", onAbort);\n\t}\n}\n"]}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { getShellConfig, getShellEnv } from "../../utils/shell.js";
|
|
3
|
+
const NATIVE_PACKAGE = "@bastani/atomic-natives";
|
|
4
|
+
let cachedLoadResult;
|
|
5
|
+
export function resetNativePtyBindingCache() {
|
|
6
|
+
cachedLoadResult = undefined;
|
|
7
|
+
}
|
|
8
|
+
function loadNativePtyBinding() {
|
|
9
|
+
if (cachedLoadResult)
|
|
10
|
+
return cachedLoadResult;
|
|
11
|
+
try {
|
|
12
|
+
const loaded = createRequire(import.meta.url)(NATIVE_PACKAGE);
|
|
13
|
+
if (typeof loaded.PtySession !== "function") {
|
|
14
|
+
cachedLoadResult = { ok: false, error: new Error(`Native package ${NATIVE_PACKAGE} is missing PtySession.`) };
|
|
15
|
+
return cachedLoadResult;
|
|
16
|
+
}
|
|
17
|
+
cachedLoadResult = { ok: true, binding: loaded };
|
|
18
|
+
return cachedLoadResult;
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
cachedLoadResult = {
|
|
22
|
+
ok: false,
|
|
23
|
+
error: new Error(`Native PTY package ${NATIVE_PACKAGE} is unavailable for ${process.platform}-${process.arch}: ${error instanceof Error ? error.message : String(error)}`),
|
|
24
|
+
};
|
|
25
|
+
return cachedLoadResult;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export async function executeNativePty(command, cwd, options) {
|
|
29
|
+
const loaded = loadNativePtyBinding();
|
|
30
|
+
if (!loaded.ok)
|
|
31
|
+
throw loaded.error;
|
|
32
|
+
if (options.signal?.aborted)
|
|
33
|
+
throw new Error("aborted");
|
|
34
|
+
const shellConfig = getShellConfig(options.shellPath);
|
|
35
|
+
const session = new loaded.binding.PtySession();
|
|
36
|
+
const onAbort = () => {
|
|
37
|
+
try {
|
|
38
|
+
session.kill();
|
|
39
|
+
}
|
|
40
|
+
catch { }
|
|
41
|
+
};
|
|
42
|
+
if (options.signal)
|
|
43
|
+
options.signal.addEventListener("abort", onAbort, { once: true });
|
|
44
|
+
try {
|
|
45
|
+
const result = await session.start({
|
|
46
|
+
command,
|
|
47
|
+
cwd,
|
|
48
|
+
env: { ...getShellEnv(), ...(options.env ?? {}), TERM: "xterm-256color" },
|
|
49
|
+
timeoutMs: options.timeout !== undefined ? Math.max(1, Math.floor(options.timeout * 1000)) : undefined,
|
|
50
|
+
cols: options.cols ?? 120,
|
|
51
|
+
rows: options.rows ?? 40,
|
|
52
|
+
shell: shellConfig.shell,
|
|
53
|
+
shellArgs: shellConfig.args,
|
|
54
|
+
commandTransport: shellConfig.commandTransport,
|
|
55
|
+
closeStdinAfterCommand: shellConfig.commandTransport === "stdin",
|
|
56
|
+
}, (_error, chunk) => {
|
|
57
|
+
if (chunk)
|
|
58
|
+
options.onData(Buffer.from(chunk));
|
|
59
|
+
});
|
|
60
|
+
if (options.signal?.aborted || result.cancelled)
|
|
61
|
+
throw new Error("aborted");
|
|
62
|
+
if (result.timedOut ?? result.timed_out)
|
|
63
|
+
throw new Error(`timeout:${options.timeout}`);
|
|
64
|
+
return { exitCode: result.exitCode ?? result.exit_code ?? null };
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
if (options.signal)
|
|
68
|
+
options.signal.removeEventListener("abort", onAbort);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=bash-pty-native.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bash-pty-native.js","sourceRoot":"","sources":["../../../src/core/tools/bash-pty-native.ts"],"names":[],"mappings":"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","sourcesContent":["import { createRequire } from \"node:module\";\nimport { getShellConfig, getShellEnv } from \"../../utils/shell.ts\";\n\nconst NATIVE_PACKAGE = \"@bastani/atomic-natives\";\n\ninterface NativePtyRunResult {\n\texitCode?: number;\n\texit_code?: number;\n\tcancelled?: boolean;\n\ttimedOut?: boolean;\n\ttimed_out?: boolean;\n}\n\ninterface NativePtySession {\n\tstart(\n\t\toptions: {\n\t\t\tcommand: string;\n\t\t\tcwd?: string;\n\t\t\tenv?: Record<string, string>;\n\t\t\ttimeoutMs?: number;\n\t\t\tcols?: number;\n\t\t\trows?: number;\n\t\t\tshell?: string;\n\t\t\tshellArgs?: string[];\n\t\t\tcommandTransport?: \"argv\" | \"stdin\";\n\t\t\tcloseStdinAfterCommand?: boolean;\n\t\t},\n\t\tonChunk?: (error: Error | null, chunk: string) => void,\n\t): Promise<NativePtyRunResult>;\n\twrite(data: string): void;\n\tresize(cols: number, rows: number): void;\n\tkill(): void;\n}\n\ninterface NativePtyBinding {\n\tPtySession: new () => NativePtySession;\n}\n\ntype NativeLoadResult =\n\t| { ok: true; binding: NativePtyBinding }\n\t| { ok: false; error: Error };\n\nlet cachedLoadResult: NativeLoadResult | undefined;\n\nexport function resetNativePtyBindingCache(): void {\n\tcachedLoadResult = undefined;\n}\n\nfunction loadNativePtyBinding(): NativeLoadResult {\n\tif (cachedLoadResult) return cachedLoadResult;\n\ttry {\n\t\tconst loaded = createRequire(import.meta.url)(NATIVE_PACKAGE) as Partial<NativePtyBinding>;\n\t\tif (typeof loaded.PtySession !== \"function\") {\n\t\t\tcachedLoadResult = { ok: false, error: new Error(`Native package ${NATIVE_PACKAGE} is missing PtySession.`) };\n\t\t\treturn cachedLoadResult;\n\t\t}\n\t\tcachedLoadResult = { ok: true, binding: loaded as NativePtyBinding };\n\t\treturn cachedLoadResult;\n\t} catch (error) {\n\t\tcachedLoadResult = {\n\t\t\tok: false,\n\t\t\terror: new Error(`Native PTY package ${NATIVE_PACKAGE} is unavailable for ${process.platform}-${process.arch}: ${error instanceof Error ? error.message : String(error)}`),\n\t\t};\n\t\treturn cachedLoadResult;\n\t}\n}\n\nexport interface NativePtyExecOptions {\n\tonData: (data: Buffer) => void;\n\tsignal?: AbortSignal;\n\ttimeout?: number;\n\tenv?: NodeJS.ProcessEnv;\n\tshellPath?: string;\n\tcols?: number;\n\trows?: number;\n}\n\nexport async function executeNativePty(command: string, cwd: string, options: NativePtyExecOptions): Promise<{ exitCode: number | null }> {\n\tconst loaded = loadNativePtyBinding();\n\tif (!loaded.ok) throw loaded.error;\n\tif (options.signal?.aborted) throw new Error(\"aborted\");\n\tconst shellConfig = getShellConfig(options.shellPath);\n\tconst session = new loaded.binding.PtySession();\n\tconst onAbort = () => {\n\t\ttry { session.kill(); } catch {}\n\t};\n\tif (options.signal) options.signal.addEventListener(\"abort\", onAbort, { once: true });\n\ttry {\n\t\tconst result = await session.start({\n\t\t\tcommand,\n\t\t\tcwd,\n\t\t\tenv: { ...getShellEnv(), ...(options.env ?? {}), TERM: \"xterm-256color\" },\n\t\t\ttimeoutMs: options.timeout !== undefined ? Math.max(1, Math.floor(options.timeout * 1000)) : undefined,\n\t\t\tcols: options.cols ?? 120,\n\t\t\trows: options.rows ?? 40,\n\t\t\tshell: shellConfig.shell,\n\t\t\tshellArgs: shellConfig.args,\n\t\t\tcommandTransport: shellConfig.commandTransport,\n\t\t\tcloseStdinAfterCommand: shellConfig.commandTransport === \"stdin\",\n\t\t}, (_error, chunk) => {\n\t\t\tif (chunk) options.onData(Buffer.from(chunk));\n\t\t});\n\t\tif (options.signal?.aborted || result.cancelled) throw new Error(\"aborted\");\n\t\tif (result.timedOut ?? result.timed_out) throw new Error(`timeout:${options.timeout}`);\n\t\treturn { exitCode: result.exitCode ?? result.exit_code ?? null };\n\t} finally {\n\t\tif (options.signal) options.signal.removeEventListener(\"abort\", onAbort);\n\t}\n}\n"]}
|