@cleocode/core 2026.6.12 → 2026.6.13
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/dist/conduit/local-transport.d.ts +12 -0
- package/dist/conduit/local-transport.d.ts.map +1 -1
- package/dist/conduit/local-transport.js +53 -23
- package/dist/conduit/local-transport.js.map +1 -1
- package/dist/crypto/credentials.d.ts +37 -0
- package/dist/crypto/credentials.d.ts.map +1 -1
- package/dist/crypto/credentials.js +110 -0
- package/dist/crypto/credentials.js.map +1 -1
- package/dist/dispatch/contracts/derive-output-contract.d.ts +86 -0
- package/dist/dispatch/contracts/derive-output-contract.d.ts.map +1 -0
- package/dist/dispatch/contracts/derive-output-contract.js +347 -0
- package/dist/dispatch/contracts/derive-output-contract.js.map +1 -0
- package/dist/dispatch/contracts/ensures-schema.d.ts +77 -0
- package/dist/dispatch/contracts/ensures-schema.d.ts.map +1 -0
- package/dist/dispatch/contracts/ensures-schema.js +91 -0
- package/dist/dispatch/contracts/ensures-schema.js.map +1 -0
- package/dist/dispatch/contracts/output-contracts.d.ts +27 -5
- package/dist/dispatch/contracts/output-contracts.d.ts.map +1 -1
- package/dist/dispatch/contracts/output-contracts.js +29 -6
- package/dist/dispatch/contracts/output-contracts.js.map +1 -1
- package/dist/docs/export-document.js +2294 -1250
- package/dist/docs/export-document.js.map +3 -3
- package/dist/go/driver.d.ts +132 -7
- package/dist/go/driver.d.ts.map +1 -1
- package/dist/go/driver.js +135 -10
- package/dist/go/driver.js.map +1 -1
- package/dist/go/index.d.ts +1 -1
- package/dist/go/index.d.ts.map +1 -1
- package/dist/go/index.js +1 -1
- package/dist/go/index.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +13 -10
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +11 -11
- package/dist/internal.js.map +1 -1
- package/dist/lifecycle/engine-ops.d.ts.map +1 -1
- package/dist/lifecycle/engine-ops.js +7 -4
- package/dist/lifecycle/engine-ops.js.map +1 -1
- package/dist/lifecycle/ivtr-loop.d.ts +108 -183
- package/dist/lifecycle/ivtr-loop.d.ts.map +1 -1
- package/dist/lifecycle/ivtr-loop.js +207 -522
- package/dist/lifecycle/ivtr-loop.js.map +1 -1
- package/dist/llm/auxiliary-fallback.js +1 -1
- package/dist/llm/auxiliary-fallback.js.map +1 -1
- package/dist/llm/cli-ops.d.ts +14 -1
- package/dist/llm/cli-ops.d.ts.map +1 -1
- package/dist/llm/cli-ops.js +41 -12
- package/dist/llm/cli-ops.js.map +1 -1
- package/dist/llm/concrete-session.d.ts.map +1 -1
- package/dist/llm/concrete-session.js +4 -0
- package/dist/llm/concrete-session.js.map +1 -1
- package/dist/llm/credentials.d.ts +35 -0
- package/dist/llm/credentials.d.ts.map +1 -1
- package/dist/llm/credentials.js +49 -0
- package/dist/llm/credentials.js.map +1 -1
- package/dist/llm/index.d.ts +4 -0
- package/dist/llm/index.d.ts.map +1 -1
- package/dist/llm/index.js +4 -0
- package/dist/llm/index.js.map +1 -1
- package/dist/llm/pi/gondolin-loader.d.ts +241 -0
- package/dist/llm/pi/gondolin-loader.d.ts.map +1 -0
- package/dist/llm/pi/gondolin-loader.js +195 -0
- package/dist/llm/pi/gondolin-loader.js.map +1 -0
- package/dist/llm/pi/index.d.ts +28 -0
- package/dist/llm/pi/index.d.ts.map +1 -0
- package/dist/llm/pi/index.js +27 -0
- package/dist/llm/pi/index.js.map +1 -0
- package/dist/llm/pi/pi-agent-adapter.d.ts +135 -0
- package/dist/llm/pi/pi-agent-adapter.d.ts.map +1 -0
- package/dist/llm/pi/pi-agent-adapter.js +329 -0
- package/dist/llm/pi/pi-agent-adapter.js.map +1 -0
- package/dist/llm/pi/pi-errors.d.ts +161 -0
- package/dist/llm/pi/pi-errors.d.ts.map +1 -0
- package/dist/llm/pi/pi-errors.js +296 -0
- package/dist/llm/pi/pi-errors.js.map +1 -0
- package/dist/llm/pi/pi-execution-env.d.ts +286 -0
- package/dist/llm/pi/pi-execution-env.d.ts.map +1 -0
- package/dist/llm/pi/pi-execution-env.js +406 -0
- package/dist/llm/pi/pi-execution-env.js.map +1 -0
- package/dist/llm/pi/pi-gondolin-env.d.ts +227 -0
- package/dist/llm/pi/pi-gondolin-env.d.ts.map +1 -0
- package/dist/llm/pi/pi-gondolin-env.js +541 -0
- package/dist/llm/pi/pi-gondolin-env.js.map +1 -0
- package/dist/llm/pi/pi-session-storage.d.ts +154 -0
- package/dist/llm/pi/pi-session-storage.d.ts.map +1 -0
- package/dist/llm/pi/pi-session-storage.js +314 -0
- package/dist/llm/pi/pi-session-storage.js.map +1 -0
- package/dist/llm/pi/pi-stream-fn.d.ts +124 -0
- package/dist/llm/pi/pi-stream-fn.d.ts.map +1 -0
- package/dist/llm/pi/pi-stream-fn.js +504 -0
- package/dist/llm/pi/pi-stream-fn.js.map +1 -0
- package/dist/llm/pi/pi-tool-bridge.d.ts +99 -0
- package/dist/llm/pi/pi-tool-bridge.d.ts.map +1 -0
- package/dist/llm/pi/pi-tool-bridge.js +117 -0
- package/dist/llm/pi/pi-tool-bridge.js.map +1 -0
- package/dist/llm/pi/pi-types.d.ts +56 -0
- package/dist/llm/pi/pi-types.d.ts.map +1 -0
- package/dist/llm/pi/pi-types.js +16 -0
- package/dist/llm/pi/pi-types.js.map +1 -0
- package/dist/llm/pi/resolve-execution-env.d.ts +194 -0
- package/dist/llm/pi/resolve-execution-env.d.ts.map +1 -0
- package/dist/llm/pi/resolve-execution-env.js +132 -0
- package/dist/llm/pi/resolve-execution-env.js.map +1 -0
- package/dist/llm/plugin-facade.js +2253 -1151
- package/dist/llm/plugin-facade.js.map +3 -3
- package/dist/llm/role-executor.d.ts.map +1 -1
- package/dist/llm/role-executor.js +8 -5
- package/dist/llm/role-executor.js.map +1 -1
- package/dist/llm/role-resolver.d.ts +46 -14
- package/dist/llm/role-resolver.d.ts.map +1 -1
- package/dist/llm/role-resolver.js +178 -20
- package/dist/llm/role-resolver.js.map +1 -1
- package/dist/llm/sealed-credential.d.ts +125 -0
- package/dist/llm/sealed-credential.d.ts.map +1 -0
- package/dist/llm/sealed-credential.js +133 -0
- package/dist/llm/sealed-credential.js.map +1 -0
- package/dist/llm/session-factory.d.ts.map +1 -1
- package/dist/llm/session-factory.js +6 -2
- package/dist/llm/session-factory.js.map +1 -1
- package/dist/llm/system-key.d.ts +67 -0
- package/dist/llm/system-key.d.ts.map +1 -0
- package/dist/llm/system-key.js +87 -0
- package/dist/llm/system-key.js.map +1 -0
- package/dist/llm/system-of-use-registry.d.ts +119 -0
- package/dist/llm/system-of-use-registry.d.ts.map +1 -0
- package/dist/llm/system-of-use-registry.js +200 -0
- package/dist/llm/system-of-use-registry.js.map +1 -0
- package/dist/llm/system-resolver.d.ts +32 -10
- package/dist/llm/system-resolver.d.ts.map +1 -1
- package/dist/llm/system-resolver.js +70 -18
- package/dist/llm/system-resolver.js.map +1 -1
- package/dist/memory/brain-writer-thread.d.ts.map +1 -1
- package/dist/memory/brain-writer-thread.js +116 -11
- package/dist/memory/brain-writer-thread.js.map +1 -1
- package/dist/memory/claude-mem-migration.d.ts.map +1 -1
- package/dist/memory/claude-mem-migration.js +21 -0
- package/dist/memory/claude-mem-migration.js.map +1 -1
- package/dist/memory/graph-memory-bridge.d.ts.map +1 -1
- package/dist/memory/graph-memory-bridge.js +32 -25
- package/dist/memory/graph-memory-bridge.js.map +1 -1
- package/dist/memory/llm-backend-resolver.js +23 -5
- package/dist/memory/llm-backend-resolver.js.map +1 -1
- package/dist/nexus/migrations/M-split-graph.d.ts.map +1 -1
- package/dist/nexus/migrations/M-split-graph.js +60 -53
- package/dist/nexus/migrations/M-split-graph.js.map +1 -1
- package/dist/orchestrate/pivot.d.ts.map +1 -1
- package/dist/orchestrate/pivot.js +20 -2
- package/dist/orchestrate/pivot.js.map +1 -1
- package/dist/release/engine-ops.js +2 -2
- package/dist/release/engine-ops.js.map +1 -1
- package/dist/routing/capability-matrix.d.ts.map +1 -1
- package/dist/routing/capability-matrix.js +0 -57
- package/dist/routing/capability-matrix.js.map +1 -1
- package/dist/selfimprove/budget.d.ts +206 -0
- package/dist/selfimprove/budget.d.ts.map +1 -0
- package/dist/selfimprove/budget.js +203 -0
- package/dist/selfimprove/budget.js.map +1 -0
- package/dist/selfimprove/dhq-adapter.d.ts +105 -0
- package/dist/selfimprove/dhq-adapter.d.ts.map +1 -0
- package/dist/selfimprove/dhq-adapter.js +95 -0
- package/dist/selfimprove/dhq-adapter.js.map +1 -0
- package/dist/selfimprove/draft-pr.d.ts +129 -0
- package/dist/selfimprove/draft-pr.d.ts.map +1 -0
- package/dist/selfimprove/draft-pr.js +158 -0
- package/dist/selfimprove/draft-pr.js.map +1 -0
- package/dist/selfimprove/envelope-diff.d.ts +162 -0
- package/dist/selfimprove/envelope-diff.d.ts.map +1 -0
- package/dist/selfimprove/envelope-diff.js +321 -0
- package/dist/selfimprove/envelope-diff.js.map +1 -0
- package/dist/selfimprove/replay.d.ts +121 -0
- package/dist/selfimprove/replay.d.ts.map +1 -0
- package/dist/selfimprove/replay.js +109 -0
- package/dist/selfimprove/replay.js.map +1 -0
- package/dist/selfimprove/run-loop.d.ts +148 -0
- package/dist/selfimprove/run-loop.d.ts.map +1 -0
- package/dist/selfimprove/run-loop.js +240 -0
- package/dist/selfimprove/run-loop.js.map +1 -0
- package/dist/selfimprove/scenario.d.ts +145 -0
- package/dist/selfimprove/scenario.d.ts.map +1 -0
- package/dist/selfimprove/scenario.js +243 -0
- package/dist/selfimprove/scenario.js.map +1 -0
- package/dist/sentient/daemon-entry.js +5 -0
- package/dist/sentient/daemon-entry.js.map +1 -1
- package/dist/sentient/daemon.d.ts.map +1 -1
- package/dist/sentient/daemon.js +19 -0
- package/dist/sentient/daemon.js.map +1 -1
- package/dist/sentient/hygiene-scan.d.ts.map +1 -1
- package/dist/sentient/hygiene-scan.js +14 -6
- package/dist/sentient/hygiene-scan.js.map +1 -1
- package/dist/sessions/briefing.d.ts.map +1 -1
- package/dist/sessions/briefing.js +13 -9
- package/dist/sessions/briefing.js.map +1 -1
- package/dist/sessions/connection-session-handle.d.ts +161 -0
- package/dist/sessions/connection-session-handle.d.ts.map +1 -0
- package/dist/sessions/connection-session-handle.js +168 -0
- package/dist/sessions/connection-session-handle.js.map +1 -0
- package/dist/sessions/handoff.d.ts.map +1 -1
- package/dist/sessions/handoff.js +9 -0
- package/dist/sessions/handoff.js.map +1 -1
- package/dist/sessions/index.d.ts +4 -1
- package/dist/sessions/index.d.ts.map +1 -1
- package/dist/sessions/index.js +31 -1
- package/dist/sessions/index.js.map +1 -1
- package/dist/sessions/session-id.d.ts +34 -0
- package/dist/sessions/session-id.d.ts.map +1 -1
- package/dist/sessions/session-id.js +37 -0
- package/dist/sessions/session-id.js.map +1 -1
- package/dist/sessions/session-manifest-mirror.d.ts +115 -0
- package/dist/sessions/session-manifest-mirror.d.ts.map +1 -0
- package/dist/sessions/session-manifest-mirror.js +250 -0
- package/dist/sessions/session-manifest-mirror.js.map +1 -0
- package/dist/sessions/session-switch.d.ts.map +1 -1
- package/dist/sessions/session-switch.js +5 -2
- package/dist/sessions/session-switch.js.map +1 -1
- package/dist/store/converters.d.ts.map +1 -1
- package/dist/store/converters.js +2 -0
- package/dist/store/converters.js.map +1 -1
- package/dist/store/db-helpers.d.ts.map +1 -1
- package/dist/store/db-helpers.js +2 -0
- package/dist/store/db-helpers.js.map +1 -1
- package/dist/store/dual-scope-db.d.ts.map +1 -1
- package/dist/store/dual-scope-db.js +87 -47
- package/dist/store/dual-scope-db.js.map +1 -1
- package/dist/store/pi-session-store.d.ts +151 -0
- package/dist/store/pi-session-store.d.ts.map +1 -0
- package/dist/store/pi-session-store.js +166 -0
- package/dist/store/pi-session-store.js.map +1 -0
- package/dist/store/safety-data-accessor.d.ts +1 -0
- package/dist/store/safety-data-accessor.d.ts.map +1 -1
- package/dist/store/safety-data-accessor.js +5 -0
- package/dist/store/safety-data-accessor.js.map +1 -1
- package/dist/store/schema/cleo-global/accounts.d.ts +357 -0
- package/dist/store/schema/cleo-global/accounts.d.ts.map +1 -0
- package/dist/store/schema/cleo-global/accounts.js +136 -0
- package/dist/store/schema/cleo-global/accounts.js.map +1 -0
- package/dist/store/schema/cleo-global/index.d.ts +2 -0
- package/dist/store/schema/cleo-global/index.d.ts.map +1 -1
- package/dist/store/schema/cleo-global/index.js +2 -0
- package/dist/store/schema/cleo-global/index.js.map +1 -1
- package/dist/store/schema/cleo-global/session-manifest.d.ts +217 -0
- package/dist/store/schema/cleo-global/session-manifest.d.ts.map +1 -0
- package/dist/store/schema/cleo-global/session-manifest.js +99 -0
- package/dist/store/schema/cleo-global/session-manifest.js.map +1 -0
- package/dist/store/schema/cleo-project/tasks-core.d.ts +16 -0
- package/dist/store/schema/cleo-project/tasks-core.d.ts.map +1 -1
- package/dist/store/schema/cleo-project/tasks-core.js +14 -0
- package/dist/store/schema/cleo-project/tasks-core.js.map +1 -1
- package/dist/store/schema/tasks.d.ts +16 -0
- package/dist/store/schema/tasks.d.ts.map +1 -1
- package/dist/store/schema/tasks.js +10 -0
- package/dist/store/schema/tasks.js.map +1 -1
- package/dist/store/selfimprove-dhq-schema.d.ts +284 -0
- package/dist/store/selfimprove-dhq-schema.d.ts.map +1 -0
- package/dist/store/selfimprove-dhq-schema.js +128 -0
- package/dist/store/selfimprove-dhq-schema.js.map +1 -0
- package/dist/store/selfimprove-dhq-store.d.ts +175 -0
- package/dist/store/selfimprove-dhq-store.d.ts.map +1 -0
- package/dist/store/selfimprove-dhq-store.js +182 -0
- package/dist/store/selfimprove-dhq-store.js.map +1 -0
- package/dist/store/session-store.d.ts +52 -13
- package/dist/store/session-store.d.ts.map +1 -1
- package/dist/store/session-store.js +71 -13
- package/dist/store/session-store.js.map +1 -1
- package/dist/store/sqlite-data-accessor.d.ts.map +1 -1
- package/dist/store/sqlite-data-accessor.js +7 -0
- package/dist/store/sqlite-data-accessor.js.map +1 -1
- package/dist/store/umbrella-data-accessor.d.ts +1 -0
- package/dist/store/umbrella-data-accessor.d.ts.map +1 -1
- package/dist/store/umbrella-data-accessor.js +5 -0
- package/dist/store/umbrella-data-accessor.js.map +1 -1
- package/dist/store/validation-schemas.d.ts +32 -0
- package/dist/store/validation-schemas.d.ts.map +1 -1
- package/dist/store/writer-lease-schema.d.ts +392 -0
- package/dist/store/writer-lease-schema.d.ts.map +1 -0
- package/dist/store/writer-lease-schema.js +142 -0
- package/dist/store/writer-lease-schema.js.map +1 -0
- package/dist/store/writer-lease.d.ts +368 -0
- package/dist/store/writer-lease.d.ts.map +1 -0
- package/dist/store/writer-lease.js +1002 -0
- package/dist/store/writer-lease.js.map +1 -0
- package/dist/tasks/backfill-child-projections.d.ts.map +1 -1
- package/dist/tasks/backfill-child-projections.js +14 -9
- package/dist/tasks/backfill-child-projections.js.map +1 -1
- package/dist/tasks/complete.d.ts.map +1 -1
- package/dist/tasks/complete.js +7 -10
- package/dist/tasks/complete.js.map +1 -1
- package/dist/tasks/duplicate-detector.d.ts.map +1 -1
- package/dist/tasks/duplicate-detector.js +14 -7
- package/dist/tasks/duplicate-detector.js.map +1 -1
- package/dist/telemetry/index.d.ts.map +1 -1
- package/dist/telemetry/index.js +10 -4
- package/dist/telemetry/index.js.map +1 -1
- package/dist/tools/agent-registry.d.ts +250 -0
- package/dist/tools/agent-registry.d.ts.map +1 -0
- package/dist/tools/agent-registry.js +292 -0
- package/dist/tools/agent-registry.js.map +1 -0
- package/dist/tools/agent-tool-families.d.ts +107 -0
- package/dist/tools/agent-tool-families.d.ts.map +1 -0
- package/dist/tools/agent-tool-families.js +527 -0
- package/dist/tools/agent-tool-families.js.map +1 -0
- package/dist/tools/browser-driver.d.ts +183 -0
- package/dist/tools/browser-driver.d.ts.map +1 -0
- package/dist/tools/browser-driver.js +242 -0
- package/dist/tools/browser-driver.js.map +1 -0
- package/dist/tools/builtin-agent-tools.d.ts +36 -0
- package/dist/tools/builtin-agent-tools.d.ts.map +1 -0
- package/dist/tools/builtin-agent-tools.js +150 -0
- package/dist/tools/builtin-agent-tools.js.map +1 -0
- package/dist/tools/dispatch.d.ts +370 -0
- package/dist/tools/dispatch.d.ts.map +1 -0
- package/dist/tools/dispatch.js +505 -0
- package/dist/tools/dispatch.js.map +1 -0
- package/dist/tools/env-scrub.d.ts +93 -0
- package/dist/tools/env-scrub.d.ts.map +1 -0
- package/dist/tools/env-scrub.js +176 -0
- package/dist/tools/env-scrub.js.map +1 -0
- package/dist/tools/fs.d.ts +30 -0
- package/dist/tools/fs.d.ts.map +1 -1
- package/dist/tools/fs.js +55 -2
- package/dist/tools/fs.js.map +1 -1
- package/dist/tools/guard.d.ts +15 -0
- package/dist/tools/guard.d.ts.map +1 -1
- package/dist/tools/guard.js +49 -12
- package/dist/tools/guard.js.map +1 -1
- package/dist/tools/index.d.ts +10 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +37 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/pty.d.ts +45 -0
- package/dist/tools/pty.d.ts.map +1 -0
- package/dist/tools/pty.js +166 -0
- package/dist/tools/pty.js.map +1 -0
- package/dist/tools/schema-gen.d.ts +57 -0
- package/dist/tools/schema-gen.d.ts.map +1 -0
- package/dist/tools/schema-gen.js +52 -0
- package/dist/tools/schema-gen.js.map +1 -0
- package/dist/tools/shell.d.ts +12 -0
- package/dist/tools/shell.d.ts.map +1 -1
- package/dist/tools/shell.js +14 -1
- package/dist/tools/shell.js.map +1 -1
- package/dist/tools/web-agent-tools.d.ts +72 -0
- package/dist/tools/web-agent-tools.d.ts.map +1 -0
- package/dist/tools/web-agent-tools.js +393 -0
- package/dist/tools/web-agent-tools.js.map +1 -0
- package/dist/tools/web-search-backends.d.ts +156 -0
- package/dist/tools/web-search-backends.d.ts.map +1 -0
- package/dist/tools/web-search-backends.js +290 -0
- package/dist/tools/web-search-backends.js.map +1 -0
- package/dist/validation/ops.d.ts +1 -15
- package/dist/validation/ops.d.ts.map +1 -1
- package/dist/validation/ops.js +0 -20
- package/dist/validation/ops.js.map +1 -1
- package/migrations/drizzle-cleo-global/20260607000000_t11891-writer-leases/migration.sql +55 -0
- package/migrations/drizzle-cleo-global/20260607010000_t11639-session-manifest/migration.sql +43 -0
- package/migrations/drizzle-cleo-global/20260608000000_t11899-pi-session-tree/migration.sql +52 -0
- package/migrations/drizzle-cleo-global/20260608010000_t11709-accounts-credential-pool/migration.sql +72 -0
- package/migrations/drizzle-cleo-global/20260608020000_t11889-selfimprove-dhq/migration.sql +64 -0
- package/migrations/drizzle-cleo-project/20260607000000_t11891-writer-leases/migration.sql +55 -0
- package/migrations/drizzle-cleo-project/20260607010000_t11639-session-parent/migration.sql +22 -0
- package/migrations/drizzle-cleo-project/20260608000000_t11899-pi-session-tree/migration.sql +52 -0
- package/migrations/drizzle-cleo-project/20260608020000_t11889-selfimprove-dhq/migration.sql +64 -0
- package/package.json +15 -13
- package/dist/lifecycle/chain-composition.d.ts +0 -30
- package/dist/lifecycle/chain-composition.d.ts.map +0 -1
- package/dist/lifecycle/chain-composition.js +0 -152
- package/dist/lifecycle/chain-composition.js.map +0 -1
- package/dist/lifecycle/chain-store.d.ts +0 -70
- package/dist/lifecycle/chain-store.d.ts.map +0 -1
- package/dist/lifecycle/chain-store.js +0 -246
- package/dist/lifecycle/chain-store.js.map +0 -1
- package/dist/lifecycle/default-chain.d.ts +0 -39
- package/dist/lifecycle/default-chain.d.ts.map +0 -1
- package/dist/lifecycle/default-chain.js +0 -176
- package/dist/lifecycle/default-chain.js.map +0 -1
- package/dist/lifecycle/tessera-engine.d.ts +0 -48
- package/dist/lifecycle/tessera-engine.d.ts.map +0 -1
- package/dist/lifecycle/tessera-engine.js +0 -249
- package/dist/lifecycle/tessera-engine.js.map +0 -1
- package/dist/validation/chain-validation.d.ts +0 -43
- package/dist/validation/chain-validation.d.ts.map +0 -1
- package/dist/validation/chain-validation.js +0 -146
- package/dist/validation/chain-validation.js.map +0 -1
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subprocess environment scrubbing (T11897 · S1 · security hardening).
|
|
3
|
+
*
|
|
4
|
+
* Building the environment a child process inherits is a SECURITY boundary, not
|
|
5
|
+
* a convenience. Two distinct threats are closed here:
|
|
6
|
+
*
|
|
7
|
+
* 1. **Sandbox escape via Pi-controlled env** — a model-driven loop that can
|
|
8
|
+
* set `LD_PRELOAD`, `NODE_OPTIONS`, `GIT_SSH_COMMAND`, `DYLD_*`, or a custom
|
|
9
|
+
* `PATH` gains arbitrary native code execution outside any command allowlist
|
|
10
|
+
* (the OS loader / Node honour them) and can satisfy a basename denylist with
|
|
11
|
+
* a workspace-resident impostor on a hijacked `PATH`. The scrubber NEVER
|
|
12
|
+
* forwards any of these dangerous variables and PINS `PATH` to a trusted
|
|
13
|
+
* absolute value.
|
|
14
|
+
* 2. **Daemon-secret exfiltration** — the daemon's own `process.env` carries
|
|
15
|
+
* resolved provider credentials (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, …),
|
|
16
|
+
* OAuth headers, and vault material (`CLEO_VAULT_*`). Inheriting the full
|
|
17
|
+
* parent env into a Pi-spawned child means a single `env`/`printenv`/log line
|
|
18
|
+
* exfiltrates them. The scrubber builds a MINIMAL, explicitly-constructed env
|
|
19
|
+
* instead of inheriting `process.env`.
|
|
20
|
+
*
|
|
21
|
+
* The doctrine is **allowlist, not denylist**: the scrubbed env starts EMPTY and
|
|
22
|
+
* only a small set of benign, named variables are copied through from the parent
|
|
23
|
+
* (locale, terminal, home/user, tmp). Everything else — including every secret,
|
|
24
|
+
* every loader hook, and `PATH` itself — is reconstructed from trusted inputs.
|
|
25
|
+
*
|
|
26
|
+
* Pure function of input — no global/session coupling, import-time side-effect
|
|
27
|
+
* free (S1).
|
|
28
|
+
*
|
|
29
|
+
* @epic T10403
|
|
30
|
+
* @task T11761
|
|
31
|
+
* @task T11897
|
|
32
|
+
* @saga T11387
|
|
33
|
+
*/
|
|
34
|
+
import { delimiter } from 'node:path';
|
|
35
|
+
/**
|
|
36
|
+
* The trusted, absolute `PATH` a scrubbed subprocess runs under. A fixed list of
|
|
37
|
+
* standard system binary directories — NEVER the caller's (possibly Pi-poisoned)
|
|
38
|
+
* `PATH`. Pinning this defeats the "workspace-resident impostor on a hijacked
|
|
39
|
+
* PATH satisfies an allowed basename" escape: the workspace is not on it.
|
|
40
|
+
*/
|
|
41
|
+
export const TRUSTED_PATH = [
|
|
42
|
+
'/usr/local/sbin',
|
|
43
|
+
'/usr/local/bin',
|
|
44
|
+
'/usr/sbin',
|
|
45
|
+
'/usr/bin',
|
|
46
|
+
'/sbin',
|
|
47
|
+
'/bin',
|
|
48
|
+
].join(delimiter);
|
|
49
|
+
/**
|
|
50
|
+
* Benign environment variables copied through from the parent when present.
|
|
51
|
+
* These carry NO secrets and NO code-execution surface — locale, terminal type,
|
|
52
|
+
* timezone, home/user identity, and the tmp dir. `PATH` is deliberately ABSENT
|
|
53
|
+
* (it is pinned to {@link TRUSTED_PATH}); every `*_API_KEY`, `*_TOKEN`,
|
|
54
|
+
* `LD_*`, `DYLD_*`, `NODE_OPTIONS`, and `GIT_SSH_COMMAND` is deliberately ABSENT.
|
|
55
|
+
*/
|
|
56
|
+
const PASSTHROUGH_KEYS = [
|
|
57
|
+
'HOME',
|
|
58
|
+
'USER',
|
|
59
|
+
'LOGNAME',
|
|
60
|
+
'LANG',
|
|
61
|
+
'LC_ALL',
|
|
62
|
+
'LC_CTYPE',
|
|
63
|
+
'TZ',
|
|
64
|
+
'TERM',
|
|
65
|
+
'TMPDIR',
|
|
66
|
+
'SHELL',
|
|
67
|
+
];
|
|
68
|
+
/**
|
|
69
|
+
* Variable-name prefixes that are NEVER forwarded into a scrubbed subprocess.
|
|
70
|
+
* These either grant arbitrary code execution to the child (loader/runtime
|
|
71
|
+
* hooks) or carry credentials. Matched case-INsensitively as a prefix so e.g.
|
|
72
|
+
* `LD_PRELOAD`, `LD_LIBRARY_PATH`, `DYLD_INSERT_LIBRARIES`, `ANTHROPIC_API_KEY`,
|
|
73
|
+
* `OPENAI_API_KEY`, `CLEO_VAULT_SECRET`, and `AWS_SECRET_ACCESS_KEY` are all
|
|
74
|
+
* caught. Used to filter the caller-supplied `extra` map.
|
|
75
|
+
*/
|
|
76
|
+
const FORBIDDEN_PREFIXES = [
|
|
77
|
+
'LD_',
|
|
78
|
+
'DYLD_',
|
|
79
|
+
'NODE_OPTIONS',
|
|
80
|
+
'NODE_REPL_EXTERNAL_MODULE',
|
|
81
|
+
'GIT_SSH',
|
|
82
|
+
'GIT_PROXY',
|
|
83
|
+
'BASH_ENV',
|
|
84
|
+
'ENV',
|
|
85
|
+
'CDPATH',
|
|
86
|
+
];
|
|
87
|
+
/**
|
|
88
|
+
* Exact variable names that are NEVER forwarded (in addition to
|
|
89
|
+
* {@link FORBIDDEN_PREFIXES}). `PATH` is pinned separately, so a caller cannot
|
|
90
|
+
* override it via `extra`.
|
|
91
|
+
*/
|
|
92
|
+
const FORBIDDEN_EXACT = new Set(['PATH', 'IFS']);
|
|
93
|
+
/**
|
|
94
|
+
* Substrings whose presence in a variable NAME marks it as a credential that is
|
|
95
|
+
* NEVER forwarded. Matched case-INsensitively. Catches `*_API_KEY`, `*_TOKEN`,
|
|
96
|
+
* `*_SECRET`, `*PASSWORD*`, OAuth material, and the vault namespace.
|
|
97
|
+
*/
|
|
98
|
+
const SECRET_NAME_SUBSTRINGS = [
|
|
99
|
+
'API_KEY',
|
|
100
|
+
'APIKEY',
|
|
101
|
+
'SECRET',
|
|
102
|
+
'TOKEN',
|
|
103
|
+
'PASSWORD',
|
|
104
|
+
'PASSWD',
|
|
105
|
+
'CREDENTIAL',
|
|
106
|
+
'PRIVATE_KEY',
|
|
107
|
+
'ACCESS_KEY',
|
|
108
|
+
'AUTH',
|
|
109
|
+
'VAULT',
|
|
110
|
+
'SESSION_KEY',
|
|
111
|
+
];
|
|
112
|
+
/**
|
|
113
|
+
* Whether a variable NAME is forbidden in a scrubbed subprocess env (a loader
|
|
114
|
+
* hook, `PATH`, or a credential).
|
|
115
|
+
*
|
|
116
|
+
* @param name - The environment variable name.
|
|
117
|
+
* @returns `true` when the variable must NOT be forwarded.
|
|
118
|
+
*/
|
|
119
|
+
export function isForbiddenEnvName(name) {
|
|
120
|
+
const upper = name.toUpperCase();
|
|
121
|
+
if (FORBIDDEN_EXACT.has(upper))
|
|
122
|
+
return true;
|
|
123
|
+
if (FORBIDDEN_PREFIXES.some((p) => upper.startsWith(p)))
|
|
124
|
+
return true;
|
|
125
|
+
if (SECRET_NAME_SUBSTRINGS.some((s) => upper.includes(s)))
|
|
126
|
+
return true;
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Build a MINIMAL, explicitly-constructed subprocess environment.
|
|
131
|
+
*
|
|
132
|
+
* The result starts EMPTY; only the benign {@link PASSTHROUGH_KEYS} present in
|
|
133
|
+
* `parentEnv` are copied, `PATH` is pinned to a trusted absolute value, and any
|
|
134
|
+
* caller-supplied `extra` is merged ON TOP after being filtered through
|
|
135
|
+
* {@link isForbiddenEnvName}. The daemon's secrets and any loader hooks in the
|
|
136
|
+
* parent environment are therefore NEVER visible to the child, and an untrusted
|
|
137
|
+
* caller cannot reintroduce an escape via `extra`.
|
|
138
|
+
*
|
|
139
|
+
* @param options - {@link ScrubEnvOptions}.
|
|
140
|
+
* @returns A fresh `Record<string, string>` safe to hand to `spawn(..., { env })`.
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```ts
|
|
144
|
+
* // A Pi-supplied env that tries to inject a loader hook + hijack PATH:
|
|
145
|
+
* const env = scrubSubprocessEnv({
|
|
146
|
+
* extra: { LD_PRELOAD: '/tmp/evil.so', PATH: '/workspace', SAFE: '1' },
|
|
147
|
+
* });
|
|
148
|
+
* // env has no LD_PRELOAD, PATH is the pinned TRUSTED_PATH, only SAFE survives.
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
export function scrubSubprocessEnv(options = {}) {
|
|
152
|
+
const parentEnv = options.parentEnv ?? process.env;
|
|
153
|
+
const scrubbed = {};
|
|
154
|
+
for (const key of PASSTHROUGH_KEYS) {
|
|
155
|
+
const value = parentEnv[key];
|
|
156
|
+
if (typeof value === 'string' && value.length > 0 && !isForbiddenEnvName(key)) {
|
|
157
|
+
scrubbed[key] = value;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// Pin PATH to a trusted absolute value — never the inbound/parent PATH.
|
|
161
|
+
scrubbed.PATH = options.path ?? TRUSTED_PATH;
|
|
162
|
+
// Merge caller-supplied extras ON TOP, but drop any dangerous key so an
|
|
163
|
+
// untrusted caller (Pi) cannot reintroduce a loader hook, secret, or PATH
|
|
164
|
+
// override through this channel.
|
|
165
|
+
if (options.extra) {
|
|
166
|
+
for (const [key, value] of Object.entries(options.extra)) {
|
|
167
|
+
if (typeof value !== 'string')
|
|
168
|
+
continue;
|
|
169
|
+
if (isForbiddenEnvName(key))
|
|
170
|
+
continue;
|
|
171
|
+
scrubbed[key] = value;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return scrubbed;
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=env-scrub.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-scrub.js","sourceRoot":"","sources":["../../src/tools/env-scrub.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/fs.d.ts
CHANGED
|
@@ -19,6 +19,36 @@
|
|
|
19
19
|
* @saga T11387
|
|
20
20
|
*/
|
|
21
21
|
import type { PathExistsInput, PathExistsResult, ReadFileInput, ReadFileResult, WriteFileInput, WriteFileResult } from '@cleocode/contracts/tools/atomic';
|
|
22
|
+
/**
|
|
23
|
+
* Symlink-resolving canonicalization of a (possibly not-yet-existing) path.
|
|
24
|
+
*
|
|
25
|
+
* A purely LEXICAL path check (`resolve` + `relative`) is symlink-BLIND: a
|
|
26
|
+
* symlink planted inside an allowed root can point anywhere on the host, so the
|
|
27
|
+
* lexical path stays "inside" while the real target is outside. This is the
|
|
28
|
+
* classic symlink/TOCTOU escape. {@link canonicalizePath} resolves the REAL
|
|
29
|
+
* filesystem location so a containment check can be made against it:
|
|
30
|
+
*
|
|
31
|
+
* - If the path EXISTS, its own realpath is returned (every symlink component,
|
|
32
|
+
* including the final one, is followed to its real target).
|
|
33
|
+
* - If the path does NOT exist (a fresh write target), the nearest existing
|
|
34
|
+
* ANCESTOR directory is realpath'd and the not-yet-existing tail segments are
|
|
35
|
+
* re-appended. This prevents a symlinked PARENT directory from redirecting a
|
|
36
|
+
* write outside the boundary while still allowing legitimate new files.
|
|
37
|
+
*
|
|
38
|
+
* The returned path is always absolute. Containment MUST be re-checked against
|
|
39
|
+
* THIS value, not the lexical one.
|
|
40
|
+
*
|
|
41
|
+
* @param path - The path to canonicalize (absolute or relative to `process.cwd()`).
|
|
42
|
+
* @returns The symlink-resolved absolute path.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* // root/innocent.txt -> /tmp/secret ⇒ canonicalizePath('root/innocent.txt')
|
|
47
|
+
* // returns '/tmp/secret', revealing the escape to the containment check.
|
|
48
|
+
* const real = await canonicalizePath(join(root, 'innocent.txt'));
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export declare function canonicalizePath(path: string): Promise<string>;
|
|
22
52
|
/**
|
|
23
53
|
* Read a file as text.
|
|
24
54
|
*
|
package/dist/tools/fs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../src/tools/fs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,cAAc,EACd,eAAe,EAChB,MAAM,kCAAkC,CAAC;AAE1C;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAGhF;AAED;;;;;;;;;GASG;AACH,wBAAsB,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAG1D;AAED;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAUrF;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAQlF"}
|
|
1
|
+
{"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../src/tools/fs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,cAAc,EACd,eAAe,EAChB,MAAM,kCAAkC,CAAC;AAE1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBpE;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAGhF;AAED;;;;;;;;;GASG;AACH,wBAAsB,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAG1D;AAED;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAUrF;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAQlF"}
|
package/dist/tools/fs.js
CHANGED
|
@@ -18,8 +18,61 @@
|
|
|
18
18
|
* @task T11405
|
|
19
19
|
* @saga T11387
|
|
20
20
|
*/
|
|
21
|
-
import { mkdir, readFile, rename, stat, writeFile } from 'node:fs/promises';
|
|
22
|
-
import { dirname, join } from 'node:path';
|
|
21
|
+
import { mkdir, readFile, realpath, rename, stat, writeFile } from 'node:fs/promises';
|
|
22
|
+
import { basename, dirname, isAbsolute, join, resolve as resolvePath } from 'node:path';
|
|
23
|
+
/**
|
|
24
|
+
* Symlink-resolving canonicalization of a (possibly not-yet-existing) path.
|
|
25
|
+
*
|
|
26
|
+
* A purely LEXICAL path check (`resolve` + `relative`) is symlink-BLIND: a
|
|
27
|
+
* symlink planted inside an allowed root can point anywhere on the host, so the
|
|
28
|
+
* lexical path stays "inside" while the real target is outside. This is the
|
|
29
|
+
* classic symlink/TOCTOU escape. {@link canonicalizePath} resolves the REAL
|
|
30
|
+
* filesystem location so a containment check can be made against it:
|
|
31
|
+
*
|
|
32
|
+
* - If the path EXISTS, its own realpath is returned (every symlink component,
|
|
33
|
+
* including the final one, is followed to its real target).
|
|
34
|
+
* - If the path does NOT exist (a fresh write target), the nearest existing
|
|
35
|
+
* ANCESTOR directory is realpath'd and the not-yet-existing tail segments are
|
|
36
|
+
* re-appended. This prevents a symlinked PARENT directory from redirecting a
|
|
37
|
+
* write outside the boundary while still allowing legitimate new files.
|
|
38
|
+
*
|
|
39
|
+
* The returned path is always absolute. Containment MUST be re-checked against
|
|
40
|
+
* THIS value, not the lexical one.
|
|
41
|
+
*
|
|
42
|
+
* @param path - The path to canonicalize (absolute or relative to `process.cwd()`).
|
|
43
|
+
* @returns The symlink-resolved absolute path.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* // root/innocent.txt -> /tmp/secret ⇒ canonicalizePath('root/innocent.txt')
|
|
48
|
+
* // returns '/tmp/secret', revealing the escape to the containment check.
|
|
49
|
+
* const real = await canonicalizePath(join(root, 'innocent.txt'));
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export async function canonicalizePath(path) {
|
|
53
|
+
const abs = isAbsolute(path) ? resolvePath(path) : resolvePath(path);
|
|
54
|
+
// Walk up to the nearest existing ancestor, realpath THAT, then re-attach the
|
|
55
|
+
// non-existing tail. This catches a symlinked parent directory AND a symlinked
|
|
56
|
+
// final component (when it exists, realpath(abs) follows it directly).
|
|
57
|
+
const tail = [];
|
|
58
|
+
let cursor = abs;
|
|
59
|
+
for (;;) {
|
|
60
|
+
try {
|
|
61
|
+
const real = await realpath(cursor);
|
|
62
|
+
return tail.length === 0 ? real : join(real, ...tail);
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
const parent = dirname(cursor);
|
|
66
|
+
if (parent === cursor) {
|
|
67
|
+
// Reached the filesystem root with nothing existing — return the lexical
|
|
68
|
+
// resolution (no symlink could have been involved on a missing chain).
|
|
69
|
+
return abs;
|
|
70
|
+
}
|
|
71
|
+
tail.unshift(basename(cursor));
|
|
72
|
+
cursor = parent;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
23
76
|
/**
|
|
24
77
|
* Read a file as text.
|
|
25
78
|
*
|
package/dist/tools/fs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fs.js","sourceRoot":"","sources":["../../src/tools/fs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"fs.js","sourceRoot":"","sources":["../../src/tools/fs.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/guard.d.ts
CHANGED
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
* @task T11407
|
|
38
38
|
* @saga T11387
|
|
39
39
|
*/
|
|
40
|
+
import type { RunShellInput, RunShellResult } from '@cleocode/contracts/tools/agent-tools';
|
|
40
41
|
import type { ExecuteShellInput, ExecuteShellResult, PathExistsInput, PathExistsResult, ReadFileInput, ReadFileResult, RunGitInput, WriteFileInput, WriteFileResult } from '@cleocode/contracts/tools/atomic';
|
|
41
42
|
import { type ShellExecutor } from './shell.js';
|
|
42
43
|
/** Enforcement posture for a {@link ToolGuard}. */
|
|
@@ -118,11 +119,25 @@ export declare class GuardDeniedError extends Error {
|
|
|
118
119
|
}
|
|
119
120
|
/** The guarded primitive surface returned by {@link createToolGuard}. */
|
|
120
121
|
export interface ToolGuard {
|
|
122
|
+
/**
|
|
123
|
+
* The resolved enforcement posture this guard was constructed with. Exposed so
|
|
124
|
+
* a security-sensitive consumer (e.g. the Pi adapter) can ASSERT it received an
|
|
125
|
+
* `enforce`-mode guard before handing it untrusted work — in `warn` mode the
|
|
126
|
+
* allowlist/denylist are advisory (log-and-proceed) and provide no boundary.
|
|
127
|
+
*/
|
|
128
|
+
readonly mode: GuardMode;
|
|
121
129
|
readFileText(input: ReadFileInput): Promise<ReadFileResult>;
|
|
122
130
|
readJson<T>(path: string): Promise<T>;
|
|
123
131
|
writeFileAtomic(input: WriteFileInput): Promise<WriteFileResult>;
|
|
124
132
|
pathExists(input: PathExistsInput): Promise<PathExistsResult>;
|
|
125
133
|
executeShell(input: ExecuteShellInput, executor?: ShellExecutor): Promise<ExecuteShellResult>;
|
|
134
|
+
/**
|
|
135
|
+
* Run a command under a PTY (or a non-PTY spawn fallback) through the guard.
|
|
136
|
+
* The command basename is checked against the denylist BEFORE any process is
|
|
137
|
+
* spawned and the child env is scrubbed — same policy point as
|
|
138
|
+
* {@link ToolGuard.executeShell}.
|
|
139
|
+
*/
|
|
140
|
+
executePty(input: RunShellInput): Promise<RunShellResult>;
|
|
126
141
|
runGit(input: RunGitInput, executor?: ShellExecutor): Promise<ExecuteShellResult>;
|
|
127
142
|
}
|
|
128
143
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../../src/tools/guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAGH,OAAO,KAAK,EACV,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,WAAW,EACX,cAAc,EACd,eAAe,EAChB,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../../src/tools/guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC3F,OAAO,KAAK,EACV,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,WAAW,EACX,cAAc,EACd,eAAe,EAChB,MAAM,kCAAkC,CAAC;AAK1C,OAAO,EAAwB,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAItE,mDAAmD;AACnD,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;AAE3C;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,sBAAsB,6BAA6B,CAAC;AAEjE;;;;;;;;;GASG;AACH,eAAO,MAAM,0BAA0B,QAAQ,CAAC;AAEhD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,GAAE,IAAiB,GAAG,SAAS,CAGzE;AAED,4CAA4C;AAC5C,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C;;;;OAIG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5C;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;CAC3B;AAED,+EAA+E;AAC/E,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,6BAA6B;IAC7B,QAAQ,CAAC,IAAI,yBAAyB;gBAC1B,OAAO,EAAE,MAAM;CAI5B;AAED,yEAAyE;AACzE,MAAM,WAAW,SAAS;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC5D,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACtC,eAAe,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACjE,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC9D,YAAY,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC9F;;;;;OAKG;IACH,UAAU,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC1D,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACnF;AAoCD;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,MAAM,GAAE,eAAoB,GAAG,SAAS,CAuEvE"}
|
package/dist/tools/guard.js
CHANGED
|
@@ -39,7 +39,9 @@
|
|
|
39
39
|
*/
|
|
40
40
|
import { isAbsolute, resolve as resolvePath } from 'node:path';
|
|
41
41
|
import { getLogger } from '../logger.js';
|
|
42
|
-
import {
|
|
42
|
+
import { scrubSubprocessEnv } from './env-scrub.js';
|
|
43
|
+
import { canonicalizePath, pathExists, readFileText, readJson, writeFileAtomic } from './fs.js';
|
|
44
|
+
import { runPty } from './pty.js';
|
|
43
45
|
import { executeShell, runGit } from './shell.js';
|
|
44
46
|
const log = getLogger('tool-guard');
|
|
45
47
|
/**
|
|
@@ -103,14 +105,32 @@ export class GuardDeniedError extends Error {
|
|
|
103
105
|
this.name = 'GuardDeniedError';
|
|
104
106
|
}
|
|
105
107
|
}
|
|
106
|
-
/** True when `
|
|
107
|
-
function
|
|
108
|
-
const abs = isAbsolute(path) ? path : resolvePath(path);
|
|
108
|
+
/** True when the resolved absolute `abs` is equal to or under one of `roots`. */
|
|
109
|
+
function isUnderRoots(abs, roots) {
|
|
109
110
|
return roots.some((root) => {
|
|
110
111
|
const r = resolvePath(root);
|
|
111
112
|
return abs === r || abs.startsWith(`${r}/`);
|
|
112
113
|
});
|
|
113
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* Whether `path` is allowed under `roots` after SYMLINK RESOLUTION.
|
|
117
|
+
*
|
|
118
|
+
* Both the candidate path AND each allowed root are canonicalized via
|
|
119
|
+
* {@link canonicalizePath} (which follows every symlink component, including a
|
|
120
|
+
* symlinked parent of a not-yet-existing write target) BEFORE the containment
|
|
121
|
+
* comparison. A purely lexical check is symlink-blind — a symlink planted inside
|
|
122
|
+
* an allowed root that points outside it would pass, then the underlying fs
|
|
123
|
+
* primitive would follow it. Resolving first closes that escape.
|
|
124
|
+
*
|
|
125
|
+
* @param path - The candidate path.
|
|
126
|
+
* @param roots - The allowed roots.
|
|
127
|
+
* @returns `true` when the real target is contained.
|
|
128
|
+
*/
|
|
129
|
+
async function isPathAllowed(path, roots) {
|
|
130
|
+
const realAbs = await canonicalizePath(isAbsolute(path) ? path : resolvePath(path));
|
|
131
|
+
const realRoots = await Promise.all(roots.map((r) => canonicalizePath(resolvePath(r))));
|
|
132
|
+
return isUnderRoots(realAbs, realRoots);
|
|
133
|
+
}
|
|
114
134
|
/** The denied command name matched by the policy, or null when allowed. */
|
|
115
135
|
function deniedCommand(command, denied) {
|
|
116
136
|
const base = command.split('/').pop() ?? command;
|
|
@@ -132,12 +152,14 @@ export function createToolGuard(policy = {}) {
|
|
|
132
152
|
// Explicit policy.mode always wins; otherwise the date-gated default applies
|
|
133
153
|
// (held at 'warn' behind the owner-gated flip — T11474 · AC4).
|
|
134
154
|
const mode = policy.mode ?? resolveDefaultGuardMode();
|
|
135
|
-
const denyFs = (op, path) => {
|
|
155
|
+
const denyFs = async (op, path) => {
|
|
136
156
|
if (!policy.allowedRoots || policy.allowedRoots.length === 0)
|
|
137
157
|
return false;
|
|
138
|
-
|
|
158
|
+
// Symlink-resolving containment — a lexically-inside path whose REAL target
|
|
159
|
+
// (via a symlinked component) escapes the roots is rejected here.
|
|
160
|
+
if (await isPathAllowed(path, policy.allowedRoots))
|
|
139
161
|
return false;
|
|
140
|
-
const msg = `tool-guard: fs.${op} path "${path}"
|
|
162
|
+
const msg = `tool-guard: fs.${op} path "${path}" resolves outside the allowed roots`;
|
|
141
163
|
if (mode === 'enforce')
|
|
142
164
|
throw new GuardDeniedError(msg);
|
|
143
165
|
log.warn({ op, path, allowedRoots: policy.allowedRoots }, msg);
|
|
@@ -159,25 +181,40 @@ export function createToolGuard(policy = {}) {
|
|
|
159
181
|
// surfaces as a REJECTED promise (not a synchronous throw) — the API contract
|
|
160
182
|
// is `Promise<…>`, and callers (+ vitest `.rejects`) expect rejection.
|
|
161
183
|
return {
|
|
184
|
+
mode,
|
|
162
185
|
async readFileText(input) {
|
|
163
|
-
denyFs('readFileText', input.path);
|
|
186
|
+
await denyFs('readFileText', input.path);
|
|
164
187
|
return readFileText(input);
|
|
165
188
|
},
|
|
166
189
|
async readJson(path) {
|
|
167
|
-
denyFs('readJson', path);
|
|
190
|
+
await denyFs('readJson', path);
|
|
168
191
|
return readJson(path);
|
|
169
192
|
},
|
|
170
193
|
async writeFileAtomic(input) {
|
|
171
|
-
denyFs('writeFileAtomic', input.path);
|
|
194
|
+
await denyFs('writeFileAtomic', input.path);
|
|
172
195
|
return writeFileAtomic(input);
|
|
173
196
|
},
|
|
174
197
|
async pathExists(input) {
|
|
175
|
-
denyFs('pathExists', input.path);
|
|
198
|
+
await denyFs('pathExists', input.path);
|
|
176
199
|
return pathExists(input);
|
|
177
200
|
},
|
|
178
201
|
async executeShell(input, executor) {
|
|
179
202
|
denyShell('executeShell', input.command);
|
|
180
|
-
|
|
203
|
+
// Scrub the child env at the chokepoint: never inherit the daemon's
|
|
204
|
+
// secrets, never forward a Pi-controlled loader hook / PATH. The
|
|
205
|
+
// caller-supplied `env` is merged ON TOP but itself scrubbed (a forbidden
|
|
206
|
+
// key — loader hook, PATH, secret — is dropped here). `defaultShellExecutor`
|
|
207
|
+
// also scrubs as a redundant net, but the guard is the policy point.
|
|
208
|
+
const env = scrubSubprocessEnv({ extra: input.env });
|
|
209
|
+
return executeShell({ ...input, env }, executor);
|
|
210
|
+
},
|
|
211
|
+
async executePty(input) {
|
|
212
|
+
// Same policy point as executeShell: deny-check the command basename
|
|
213
|
+
// BEFORE spawning any PTY/process. `runPty` re-scrubs the env internally
|
|
214
|
+
// (PTY + spawn paths both use `scrubSubprocessEnv`), so the daemon's
|
|
215
|
+
// secrets and any Pi-controlled loader hook can never reach the child.
|
|
216
|
+
denyShell('executePty', input.command);
|
|
217
|
+
return runPty(input);
|
|
181
218
|
},
|
|
182
219
|
async runGit(input, executor) {
|
|
183
220
|
denyShell('runGit', 'git');
|
package/dist/tools/guard.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guard.js","sourceRoot":"","sources":["../../src/tools/guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,OAAO,EAAE,UAAU,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"guard.js","sourceRoot":"","sources":["../../src/tools/guard.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -42,6 +42,16 @@ export type { ScaffoldProjectOptions, ScaffoldProjectResult, ScaffoldProjectStep
|
|
|
42
42
|
export { scaffoldProject } from '../scaffold/scaffold-project.js';
|
|
43
43
|
export * from '../sdk/index.js';
|
|
44
44
|
export * from '../task-tools/index.js';
|
|
45
|
+
export { AGENT_TOOL_REGISTER_FN, type AgentToolDescriptor, type AgentToolDiscoveryOptions, type AgentToolExecutable, AgentToolRegistry, ALWAYS_AVAILABLE, type AvailabilityCheck, createAgentToolRegistry, type ToolAvailabilityContext, } from './agent-registry.js';
|
|
46
|
+
export { applyFuzzyPatch, type FuzzyPatchOutcome, GIT_LOG_FORMAT, paginateLines, parseGitLog, parseGitStatus, parseRipgrepOutput, registerAgentToolFamilies, } from './agent-tool-families.js';
|
|
47
|
+
export { BrowserSession, isPlaywrightAvailable, PLAYWRIGHT_INSTALL_HINT, type PlaywrightLoader, } from './browser-driver.js';
|
|
48
|
+
export { registerBuiltinAgentTools } from './builtin-agent-tools.js';
|
|
49
|
+
export { flattenZodIssues, formatToolResultForLlm, formatToolValueForLlm, MAX_TOOL_RESULT_CHARS, redactErrorMessage, TOOL_DISPATCH_ERROR_CODE, type ToolArgIssue, type ToolBudgetLimits, type ToolBudgetSnapshot, type ToolCall, ToolCallBudget, ToolDispatchEngine, type ToolDispatchEngineDeps, type ToolDispatchErrorKind, type ToolDispatchFailure, type ToolDispatchResult, type ToolDispatchSuccess, type ToolResultPayload, ToolTimeoutError, } from './dispatch.js';
|
|
50
|
+
export { isForbiddenEnvName, type ScrubEnvOptions, scrubSubprocessEnv, TRUSTED_PATH, } from './env-scrub.js';
|
|
45
51
|
export { createToolGuard, GUARD_ENFORCE_DEADLINE, GUARD_ENFORCE_FLIP_ENABLED, GuardDeniedError, type GuardMode, resolveDefaultGuardMode, type ToolGuard, type ToolGuardPolicy, } from './guard.js';
|
|
52
|
+
export { runPty } from './pty.js';
|
|
53
|
+
export { type ZodSchemaTool, zodSchemaToOpenAITool } from './schema-gen.js';
|
|
46
54
|
export { defaultShellExecutor, type ShellExecutor } from './shell.js';
|
|
55
|
+
export { registerWebAgentTools, type WebAgentToolOptions } from './web-agent-tools.js';
|
|
56
|
+
export { defaultHttpFetch, duckDuckGoBackend, extractTitle, fetchAndExtract, type HttpFetch, htmlToMarkdown, makeSearxngBackend, parseDuckDuckGoHtml, parseSearxngJson, resolveSearchBackends, runSearch, type WebSearchBackend, } from './web-search-backends.js';
|
|
47
57
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAGH,cAAc,yBAAyB,CAAC;AACxC,YAAY,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAE7F,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAE5D,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,yBAAyB,EACzB,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,yBAAyB,EACzB,0BAA0B,EAC1B,0BAA0B,EAC1B,sBAAsB,EACtB,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,2BAA2B,EAC3B,wBAAwB,EACxB,iBAAiB,EACjB,cAAc,EACd,wBAAwB,EACxB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,YAAY,EACV,sBAAsB,EACtB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAElE,cAAc,iBAAiB,CAAC;AAEhC,cAAc,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/index.js
CHANGED
|
@@ -44,10 +44,47 @@ export { scaffoldProject } from '../scaffold/scaffold-project.js';
|
|
|
44
44
|
export * from '../sdk/index.js';
|
|
45
45
|
// TaskTools (Category B) — pure-functional task graph SDK tools (T10068 / T9835)
|
|
46
46
|
export * from '../task-tools/index.js';
|
|
47
|
+
// Agent-facing tool registry (T1739 · E-TOOLS · epic T11456) — the Hermes
|
|
48
|
+
// `tools/registry.py` analogue. Self-discovering, OpenAI-format schema-emitting,
|
|
49
|
+
// toolset-grouped, availability-gated, frozen-after-init registry. Side effects
|
|
50
|
+
// always route through the guarded surface; auto-discovery is an EXPLICIT init()
|
|
51
|
+
// (NOT at module import — AC7).
|
|
52
|
+
export { AGENT_TOOL_REGISTER_FN, AgentToolRegistry, ALWAYS_AVAILABLE, createAgentToolRegistry, } from './agent-registry.js';
|
|
53
|
+
// Agent-facing tool families (T1741 · epic T11456) — terminal `run_shell` (PTY +
|
|
54
|
+
// non-PTY spawn fallback), paginated `read_file_paged`, atomic `write_file_atomic`,
|
|
55
|
+
// fuzzy `apply_patch`, ripgrep `search_files`, and the git family. Pure helpers
|
|
56
|
+
// (pagination, fuzzy patch, rg/git output parsing) are exported for direct unit
|
|
57
|
+
// testing; every executable routes side effects through the guarded surface.
|
|
58
|
+
export { applyFuzzyPatch, GIT_LOG_FORMAT, paginateLines, parseGitLog, parseGitStatus, parseRipgrepOutput, registerAgentToolFamilies, } from './agent-tool-families.js';
|
|
59
|
+
// Web + browser agent tools (T1742 · epic T11456) — the `web` toolset:
|
|
60
|
+
// `web_search` (pluggable keyless backends), `web_extract` (HTML→markdown), and
|
|
61
|
+
// the Playwright-driven `browser_*` family. Playwright is OPTIONAL + lazily
|
|
62
|
+
// loaded; the browser tools register but report unavailable (with an install
|
|
63
|
+
// hint) when it is absent. The `browser_vision` AI call routes through the E9
|
|
64
|
+
// `resolveLLMForSystem` chokepoint + sealed credential — no raw provider call.
|
|
65
|
+
export { BrowserSession, isPlaywrightAvailable, PLAYWRIGHT_INSTALL_HINT, } from './browser-driver.js';
|
|
66
|
+
export { registerBuiltinAgentTools } from './builtin-agent-tools.js';
|
|
67
|
+
// Agent tool-call dispatch engine (T1740 · epic T11456) — the SDK chokepoint that
|
|
68
|
+
// turns a model-emitted tool-call into an executed, LLM-safe result: registry
|
|
69
|
+
// lookup → Zod-validate → availability → run-scoped budget → guarded execution →
|
|
70
|
+
// classified result + LLM-facing formatting. Pure dispatch; defines NO new tool
|
|
71
|
+
// primitive (Gate-11) and makes NO LLM call (Gate-13). The Pi adapter binds the
|
|
72
|
+
// loop's tool execution to this engine (AC6 — see core/src/llm/pi/pi-tool-bridge).
|
|
73
|
+
export { flattenZodIssues, formatToolResultForLlm, formatToolValueForLlm, MAX_TOOL_RESULT_CHARS, redactErrorMessage, TOOL_DISPATCH_ERROR_CODE, ToolCallBudget, ToolDispatchEngine, ToolTimeoutError, } from './dispatch.js';
|
|
74
|
+
// Subprocess env scrubbing (T11897 · security) — the chokepoint builds a minimal,
|
|
75
|
+
// allowlisted child env so daemon secrets never leak and a Pi-controlled loader
|
|
76
|
+
// hook / PATH can never reach a spawned process.
|
|
77
|
+
export { isForbiddenEnvName, scrubSubprocessEnv, TRUSTED_PATH, } from './env-scrub.js';
|
|
47
78
|
// Atomic-tool guard chokepoint (E3 · T11407 · T11474) — the ONLY public route to
|
|
48
79
|
// the fs/shell primitives. Raw primitives are intentionally not re-exported.
|
|
49
80
|
export { createToolGuard, GUARD_ENFORCE_DEADLINE, GUARD_ENFORCE_FLIP_ENABLED, GuardDeniedError, resolveDefaultGuardMode, } from './guard.js';
|
|
81
|
+
// PTY shell runner (T1741) — the terminal toolset's execution backend; lazily +
|
|
82
|
+
// optionally loads `node-pty`, transparently degrading to non-PTY `spawn`.
|
|
83
|
+
export { runPty } from './pty.js';
|
|
84
|
+
export { zodSchemaToOpenAITool } from './schema-gen.js';
|
|
50
85
|
// Injectable shell executor (E3 · T11406) — threaded into the guard's
|
|
51
86
|
// executeShell/runGit; substitutes the subprocess layer in tests/sandboxes.
|
|
52
87
|
export { defaultShellExecutor } from './shell.js';
|
|
88
|
+
export { registerWebAgentTools } from './web-agent-tools.js';
|
|
89
|
+
export { defaultHttpFetch, duckDuckGoBackend, extractTitle, fetchAndExtract, htmlToMarkdown, makeSearxngBackend, parseDuckDuckGoHtml, parseSearxngJson, resolveSearchBackends, runSearch, } from './web-search-backends.js';
|
|
53
90
|
//# sourceMappingURL=index.js.map
|
package/dist/tools/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,uFAAuF;AACvF,cAAc,yBAAyB,CAAC;AAExC,uFAAuF;AACvF,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,uDAAuD;AACvD,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,yBAAyB,EACzB,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,yBAAyB,EACzB,0BAA0B,EAC1B,0BAA0B,EAC1B,sBAAsB,EACtB,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,cAAc,EACd,2BAA2B,EAC3B,wBAAwB,EACxB,iBAAiB,EACjB,cAAc,EACd,wBAAwB,EACxB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAMhE,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,6EAA6E;AAC7E,cAAc,iBAAiB,CAAC;AAChC,iFAAiF;AACjF,cAAc,wBAAwB,CAAC;AACvC,iFAAiF;AACjF,6EAA6E;AAC7E,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,0BAA0B,EAC1B,gBAAgB,EAEhB,uBAAuB,GAGxB,MAAM,YAAY,CAAC;AACpB,sEAAsE;AACtE,4EAA4E;AAC5E,OAAO,EAAE,oBAAoB,EAAsB,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pseudo-terminal (PTY) shell runner (T1741 · epic T11456 · SG-TOOLS).
|
|
3
|
+
*
|
|
4
|
+
* The `terminal` toolset's execution backend. Runs a command under a PTY when
|
|
5
|
+
* the OPTIONAL `node-pty` native dependency is loadable, otherwise transparently
|
|
6
|
+
* degrades to a plain `child_process.spawn` (the {@link defaultShellExecutor}
|
|
7
|
+
* path) so the tool ALWAYS works without a heavy native dep. `node-pty` is
|
|
8
|
+
* loaded lazily via dynamic `import()` inside the runner — NEVER at module
|
|
9
|
+
* import — so this file is import-time side-effect-free (and adds no startup
|
|
10
|
+
* cost / hard dependency).
|
|
11
|
+
*
|
|
12
|
+
* The child runs under the SCRUBBED, explicitly-constructed environment from
|
|
13
|
+
* {@link scrubSubprocessEnv} (same security posture as the non-PTY path): the
|
|
14
|
+
* daemon's secrets are never inherited and a Pi-controlled loader hook / PATH
|
|
15
|
+
* can never reach the spawned process. This runner is invoked ONLY from the
|
|
16
|
+
* guard chokepoint ({@link ./guard.js}), so the command denylist applies before
|
|
17
|
+
* any process is spawned — there is no raw bypass.
|
|
18
|
+
*
|
|
19
|
+
* @epic T11456
|
|
20
|
+
* @task T1741
|
|
21
|
+
* @see ./guard.js — the deny-first chokepoint that wraps this runner
|
|
22
|
+
*/
|
|
23
|
+
import type { RunShellInput, RunShellResult } from '@cleocode/contracts/tools/agent-tools';
|
|
24
|
+
/**
|
|
25
|
+
* Run a command under a PTY when possible, else a non-PTY spawn.
|
|
26
|
+
*
|
|
27
|
+
* - `spawn` mode → always {@link runSpawn}.
|
|
28
|
+
* - `pty` / `auto` mode → attempt {@link loadNodePty}; on success {@link runWithPty},
|
|
29
|
+
* otherwise degrade to {@link runSpawn} with `ptyFellBack: true`.
|
|
30
|
+
*
|
|
31
|
+
* The actual process is always launched under the scrubbed subprocess env. This
|
|
32
|
+
* function performs NO policy decision of its own — it is the executor the guard
|
|
33
|
+
* chokepoint ({@link ./guard.js}) invokes AFTER its denylist check passes.
|
|
34
|
+
*
|
|
35
|
+
* @param input - {@link RunShellInput}.
|
|
36
|
+
* @returns The {@link RunShellResult}.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* const res = await runPty({ command: 'echo', args: ['hi'], mode: 'auto' });
|
|
41
|
+
* // res.mode === 'pty' when node-pty is installed, else 'spawn' (ptyFellBack: true)
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare function runPty(input: RunShellInput): Promise<RunShellResult>;
|
|
45
|
+
//# sourceMappingURL=pty.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pty.d.ts","sourceRoot":"","sources":["../../src/tools/pty.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AA+I3F;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,MAAM,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAU1E"}
|