@cmetech/otto 1.1.0 → 1.2.4
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/coworker/persona-commands.d.ts +1 -0
- package/dist/coworker/persona-commands.js +5 -0
- package/dist/coworker/persona-commands.test.d.ts +1 -0
- package/dist/coworker/persona-commands.test.js +45 -0
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/_coworker-paths.js +8 -0
- package/dist/resources/extensions/coworker-artifacts/artifacts-command.js +31 -0
- package/dist/resources/extensions/coworker-artifacts/artifacts-singleton.js +17 -0
- package/dist/resources/extensions/coworker-artifacts/extension-manifest.json +13 -0
- package/dist/resources/extensions/coworker-artifacts/index.js +125 -0
- package/dist/resources/extensions/coworker-artifacts/list-tool.js +27 -0
- package/dist/resources/extensions/coworker-artifacts/open-tool.js +25 -0
- package/dist/resources/extensions/coworker-memory/extension-manifest.json +13 -0
- package/dist/resources/extensions/coworker-memory/index.js +219 -0
- package/dist/resources/extensions/coworker-memory/memorize-tool.js +10 -0
- package/dist/resources/extensions/coworker-memory/memory-command.js +157 -0
- package/dist/resources/extensions/coworker-memory/memory-singleton.js +55 -0
- package/dist/resources/extensions/coworker-memory/recall-tool.js +18 -0
- package/dist/resources/extensions/coworker-memory/session-hooks.js +45 -0
- package/dist/resources/extensions/coworker-scratchpad/attach-banners.js +53 -0
- package/dist/resources/extensions/coworker-scratchpad/extension-manifest.json +13 -0
- package/dist/resources/extensions/coworker-scratchpad/format-age.js +9 -0
- package/dist/resources/extensions/coworker-scratchpad/helpers.js +38 -0
- package/dist/resources/extensions/coworker-scratchpad/index.js +199 -0
- package/dist/resources/extensions/coworker-scratchpad/mime-bundle.js +20 -0
- package/dist/resources/extensions/coworker-scratchpad/scratchpad-tool.js +118 -0
- package/dist/resources/extensions/coworker-scratchpad/session-sidecar.js +60 -0
- package/dist/resources/extensions/coworker-scratchpad/sp-command.js +597 -0
- package/dist/resources/extensions/coworker-scratchpad/workspace-pointer.js +41 -0
- package/dist/resources/extensions/coworker-scratchpad/workspace-root.js +17 -0
- package/dist/resources/extensions/coworker-vault/audit-command.js +35 -0
- package/dist/resources/extensions/coworker-vault/connect-command.js +42 -0
- package/dist/resources/extensions/coworker-vault/datasource-command.js +50 -0
- package/dist/resources/extensions/coworker-vault/extension-manifest.json +12 -0
- package/dist/resources/extensions/coworker-vault/index.js +171 -0
- package/dist/resources/extensions/coworker-vault/test-helpers.js +86 -0
- package/dist/resources/extensions/coworker-vault/vault-singleton.js +24 -0
- package/dist/resources/extensions/otto/commands/release-notes/_data.js +82 -0
- package/dist/resources/extensions/otto/commands/release-notes/command.js +15 -4
- package/dist/resources/extensions/subagent/index.js +8 -1
- package/dist/resources/extensions/subagent/launch.js +37 -5
- package/dist/resources/extensions/subagent/run-store.js +1 -0
- package/dist/resources/extensions/workflow/bootstrap/register-extension.js +2 -0
- package/dist/resources/extensions/workflow/bootstrap/register-hooks.js +10 -0
- package/dist/resources/extensions/workflow/persona-status.js +87 -0
- package/dist/update-cmd.d.ts +19 -0
- package/dist/update-cmd.js +177 -6
- package/package.json +25 -10
- package/packages/contracts/package.json +1 -1
- package/packages/coworker-artifacts/dist/artifact-store.d.ts +25 -0
- package/packages/coworker-artifacts/dist/artifact-store.js +187 -0
- package/packages/coworker-artifacts/dist/dir-snapshot.d.ts +7 -0
- package/packages/coworker-artifacts/dist/dir-snapshot.js +54 -0
- package/packages/coworker-artifacts/dist/errors.d.ts +18 -0
- package/packages/coworker-artifacts/dist/errors.js +37 -0
- package/packages/coworker-artifacts/dist/index.d.ts +7 -0
- package/packages/coworker-artifacts/dist/index.js +7 -0
- package/packages/coworker-artifacts/dist/readme-renderer.d.ts +5 -0
- package/packages/coworker-artifacts/dist/readme-renderer.js +47 -0
- package/packages/coworker-artifacts/dist/resolve-uri.d.ts +3 -0
- package/packages/coworker-artifacts/dist/resolve-uri.js +29 -0
- package/packages/coworker-artifacts/dist/slug.d.ts +4 -0
- package/packages/coworker-artifacts/dist/slug.js +32 -0
- package/packages/coworker-artifacts/dist/types.d.ts +52 -0
- package/packages/coworker-artifacts/dist/types.js +1 -0
- package/packages/coworker-artifacts/package.json +20 -0
- package/packages/coworker-artifacts/src/artifact-store.test.ts +188 -0
- package/packages/coworker-artifacts/src/artifact-store.ts +206 -0
- package/packages/coworker-artifacts/src/artifacts-integration.test.ts +109 -0
- package/packages/coworker-artifacts/src/dir-snapshot.test.ts +71 -0
- package/packages/coworker-artifacts/src/dir-snapshot.ts +52 -0
- package/packages/coworker-artifacts/src/errors.test.ts +37 -0
- package/packages/coworker-artifacts/src/errors.ts +28 -0
- package/packages/coworker-artifacts/src/index.test.ts +22 -0
- package/packages/coworker-artifacts/src/index.ts +7 -0
- package/packages/coworker-artifacts/src/readme-renderer.test.ts +72 -0
- package/packages/coworker-artifacts/src/readme-renderer.ts +56 -0
- package/packages/coworker-artifacts/src/resolve-uri.test.ts +46 -0
- package/packages/coworker-artifacts/src/resolve-uri.ts +29 -0
- package/packages/coworker-artifacts/src/slug.test.ts +47 -0
- package/packages/coworker-artifacts/src/slug.ts +31 -0
- package/packages/coworker-artifacts/src/types.ts +61 -0
- package/packages/coworker-artifacts/tsconfig.json +15 -0
- package/packages/coworker-artifacts/tsconfig.publish.json +4 -0
- package/packages/coworker-memory/dist/context-injection.d.ts +9 -0
- package/packages/coworker-memory/dist/context-injection.js +41 -0
- package/packages/coworker-memory/dist/errors.d.ts +25 -0
- package/packages/coworker-memory/dist/errors.js +51 -0
- package/packages/coworker-memory/dist/index.d.ts +12 -0
- package/packages/coworker-memory/dist/index.js +12 -0
- package/packages/coworker-memory/dist/layer-a-store.d.ts +16 -0
- package/packages/coworker-memory/dist/layer-a-store.js +78 -0
- package/packages/coworker-memory/dist/local-sqlite-backend.d.ts +28 -0
- package/packages/coworker-memory/dist/local-sqlite-backend.js +167 -0
- package/packages/coworker-memory/dist/memory-backend.d.ts +14 -0
- package/packages/coworker-memory/dist/memory-backend.js +1 -0
- package/packages/coworker-memory/dist/memory-recorder.d.ts +50 -0
- package/packages/coworker-memory/dist/memory-recorder.js +69 -0
- package/packages/coworker-memory/dist/migrations/001-init.sql +38 -0
- package/packages/coworker-memory/dist/migrations/002-artifact-kind.sql +50 -0
- package/packages/coworker-memory/dist/paste-detector.d.ts +5 -0
- package/packages/coworker-memory/dist/paste-detector.js +14 -0
- package/packages/coworker-memory/dist/persona-seed.d.ts +10 -0
- package/packages/coworker-memory/dist/persona-seed.js +38 -0
- package/packages/coworker-memory/dist/recall-formatter.d.ts +2 -0
- package/packages/coworker-memory/dist/recall-formatter.js +14 -0
- package/packages/coworker-memory/dist/scope-resolver.d.ts +9 -0
- package/packages/coworker-memory/dist/scope-resolver.js +10 -0
- package/packages/coworker-memory/dist/types.d.ts +51 -0
- package/packages/coworker-memory/dist/types.js +2 -0
- package/packages/coworker-memory/dist/workspace-id.d.ts +3 -0
- package/packages/coworker-memory/dist/workspace-id.js +54 -0
- package/packages/coworker-memory/package.json +35 -0
- package/packages/coworker-memory/src/activator-integration.test.ts +141 -0
- package/packages/coworker-memory/src/context-injection.test.ts +72 -0
- package/packages/coworker-memory/src/context-injection.ts +57 -0
- package/packages/coworker-memory/src/errors.test.ts +45 -0
- package/packages/coworker-memory/src/errors.ts +42 -0
- package/packages/coworker-memory/src/index.test.ts +21 -0
- package/packages/coworker-memory/src/index.ts +12 -0
- package/packages/coworker-memory/src/layer-a-store.test.ts +85 -0
- package/packages/coworker-memory/src/layer-a-store.ts +88 -0
- package/packages/coworker-memory/src/local-sqlite-backend.test.ts +110 -0
- package/packages/coworker-memory/src/local-sqlite-backend.ts +185 -0
- package/packages/coworker-memory/src/memory-backend.ts +10 -0
- package/packages/coworker-memory/src/memory-integration.test.ts +89 -0
- package/packages/coworker-memory/src/memory-recorder.test.ts +101 -0
- package/packages/coworker-memory/src/memory-recorder.ts +95 -0
- package/packages/coworker-memory/src/migrations/001-init.sql +38 -0
- package/packages/coworker-memory/src/migrations/002-artifact-kind.sql +50 -0
- package/packages/coworker-memory/src/paste-detector.test.ts +23 -0
- package/packages/coworker-memory/src/paste-detector.ts +18 -0
- package/packages/coworker-memory/src/persona-seed.test.ts +57 -0
- package/packages/coworker-memory/src/persona-seed.ts +46 -0
- package/packages/coworker-memory/src/recall-formatter.test.ts +34 -0
- package/packages/coworker-memory/src/recall-formatter.ts +15 -0
- package/packages/coworker-memory/src/scope-resolver.test.ts +23 -0
- package/packages/coworker-memory/src/scope-resolver.ts +18 -0
- package/packages/coworker-memory/src/types.ts +61 -0
- package/packages/coworker-memory/src/workspace-id.test.ts +48 -0
- package/packages/coworker-memory/src/workspace-id.ts +56 -0
- package/packages/coworker-memory/tsconfig.json +15 -0
- package/packages/coworker-memory/tsconfig.publish.json +4 -0
- package/packages/coworker-persona/dist/commands.d.ts +7 -0
- package/packages/coworker-persona/dist/commands.js +35 -0
- package/packages/coworker-persona/dist/defaults/manifest.yaml +12 -0
- package/packages/coworker-persona/dist/defaults/steering/identity.md +3 -0
- package/packages/coworker-persona/dist/index.d.ts +3 -0
- package/packages/coworker-persona/dist/index.js +3 -0
- package/packages/coworker-persona/dist/manifest.d.ts +24 -0
- package/packages/coworker-persona/dist/manifest.js +21 -0
- package/packages/coworker-persona/dist/registry.d.ts +22 -0
- package/packages/coworker-persona/dist/registry.js +142 -0
- package/packages/coworker-persona/package.json +28 -0
- package/packages/coworker-persona/scripts/copy-defaults.cjs +17 -0
- package/packages/coworker-persona/src/commands.ts +47 -0
- package/packages/coworker-persona/src/defaults/manifest.yaml +12 -0
- package/packages/coworker-persona/src/defaults/steering/identity.md +3 -0
- package/packages/coworker-persona/src/index.ts +3 -0
- package/packages/coworker-persona/src/manifest.test.ts +67 -0
- package/packages/coworker-persona/src/manifest.ts +49 -0
- package/packages/coworker-persona/src/registry.test.ts +89 -0
- package/packages/coworker-persona/src/registry.ts +147 -0
- package/packages/coworker-persona/tsconfig.json +15 -0
- package/packages/coworker-persona/tsconfig.publish.json +4 -0
- package/packages/coworker-scratchpad/dist/cell-archive.d.ts +39 -0
- package/packages/coworker-scratchpad/dist/cell-archive.js +77 -0
- package/packages/coworker-scratchpad/dist/cell-tree.d.ts +14 -0
- package/packages/coworker-scratchpad/dist/cell-tree.js +72 -0
- package/packages/coworker-scratchpad/dist/child-process-runtime.d.ts +129 -0
- package/packages/coworker-scratchpad/dist/child-process-runtime.js +427 -0
- package/packages/coworker-scratchpad/dist/collector-registry.d.ts +12 -0
- package/packages/coworker-scratchpad/dist/collector-registry.js +29 -0
- package/packages/coworker-scratchpad/dist/detect-kind.d.ts +3 -0
- package/packages/coworker-scratchpad/dist/detect-kind.js +19 -0
- package/packages/coworker-scratchpad/dist/file-collector.d.ts +15 -0
- package/packages/coworker-scratchpad/dist/file-collector.js +99 -0
- package/packages/coworker-scratchpad/dist/index.d.ts +13 -0
- package/packages/coworker-scratchpad/dist/index.js +13 -0
- package/packages/coworker-scratchpad/dist/kernel-bindings.d.ts +49 -0
- package/packages/coworker-scratchpad/dist/kernel-bindings.js +220 -0
- package/packages/coworker-scratchpad/dist/kernel-entry.d.ts +1 -0
- package/packages/coworker-scratchpad/dist/kernel-entry.js +355 -0
- package/packages/coworker-scratchpad/dist/kernel-protocol.d.ts +171 -0
- package/packages/coworker-scratchpad/dist/kernel-protocol.js +48 -0
- package/packages/coworker-scratchpad/dist/kernel-spawn.d.ts +3 -0
- package/packages/coworker-scratchpad/dist/kernel-spawn.js +54 -0
- package/packages/coworker-scratchpad/dist/namespace-codec.d.ts +22 -0
- package/packages/coworker-scratchpad/dist/namespace-codec.js +61 -0
- package/packages/coworker-scratchpad/dist/scratchpad-lock.d.ts +24 -0
- package/packages/coworker-scratchpad/dist/scratchpad-lock.js +86 -0
- package/packages/coworker-scratchpad/dist/scratchpad-manager.d.ts +193 -0
- package/packages/coworker-scratchpad/dist/scratchpad-manager.js +866 -0
- package/packages/coworker-scratchpad/dist/staleness-banner.d.ts +12 -0
- package/packages/coworker-scratchpad/dist/staleness-banner.js +27 -0
- package/packages/coworker-scratchpad/package.json +31 -0
- package/packages/coworker-scratchpad/src/cell-archive.test.ts +150 -0
- package/packages/coworker-scratchpad/src/cell-archive.ts +97 -0
- package/packages/coworker-scratchpad/src/cell-tree.test.ts +105 -0
- package/packages/coworker-scratchpad/src/cell-tree.ts +90 -0
- package/packages/coworker-scratchpad/src/child-process-runtime.test.ts +413 -0
- package/packages/coworker-scratchpad/src/child-process-runtime.ts +493 -0
- package/packages/coworker-scratchpad/src/collector-registry.test.ts +69 -0
- package/packages/coworker-scratchpad/src/collector-registry.ts +33 -0
- package/packages/coworker-scratchpad/src/detect-kind.test.ts +33 -0
- package/packages/coworker-scratchpad/src/detect-kind.ts +22 -0
- package/packages/coworker-scratchpad/src/file-collector.test.ts +109 -0
- package/packages/coworker-scratchpad/src/file-collector.ts +114 -0
- package/packages/coworker-scratchpad/src/index.ts +74 -0
- package/packages/coworker-scratchpad/src/kernel-bindings.test.ts +188 -0
- package/packages/coworker-scratchpad/src/kernel-bindings.ts +279 -0
- package/packages/coworker-scratchpad/src/kernel-entry.test.ts +123 -0
- package/packages/coworker-scratchpad/src/kernel-entry.ts +390 -0
- package/packages/coworker-scratchpad/src/kernel-protocol.test.ts +105 -0
- package/packages/coworker-scratchpad/src/kernel-protocol.ts +230 -0
- package/packages/coworker-scratchpad/src/kernel-spawn.test.ts +60 -0
- package/packages/coworker-scratchpad/src/kernel-spawn.ts +54 -0
- package/packages/coworker-scratchpad/src/namespace-codec.test.ts +102 -0
- package/packages/coworker-scratchpad/src/namespace-codec.ts +90 -0
- package/packages/coworker-scratchpad/src/scratchpad-lock.test.ts +98 -0
- package/packages/coworker-scratchpad/src/scratchpad-lock.ts +102 -0
- package/packages/coworker-scratchpad/src/scratchpad-manager.test.ts +1343 -0
- package/packages/coworker-scratchpad/src/scratchpad-manager.ts +891 -0
- package/packages/coworker-scratchpad/src/staleness-banner.test.ts +53 -0
- package/packages/coworker-scratchpad/src/staleness-banner.ts +33 -0
- package/packages/coworker-scratchpad/src/vault-integration.test.ts +221 -0
- package/packages/coworker-scratchpad/tsconfig.json +15 -0
- package/packages/coworker-scratchpad/tsconfig.publish.json +4 -0
- package/packages/coworker-types/dist/artifacts.d.ts +31 -0
- package/packages/coworker-types/dist/artifacts.js +2 -0
- package/packages/coworker-types/dist/contracts.d.ts +32 -0
- package/packages/coworker-types/dist/contracts.js +1 -0
- package/packages/coworker-types/dist/index.d.ts +5 -0
- package/packages/coworker-types/dist/index.js +5 -0
- package/packages/coworker-types/dist/memory.d.ts +61 -0
- package/packages/coworker-types/dist/memory.js +3 -0
- package/packages/coworker-types/dist/scratchpad.d.ts +43 -0
- package/packages/coworker-types/dist/scratchpad.js +2 -0
- package/packages/coworker-types/dist/vault.d.ts +34 -0
- package/packages/coworker-types/dist/vault.js +2 -0
- package/packages/coworker-types/package.json +24 -0
- package/packages/coworker-types/src/artifacts.test.ts +52 -0
- package/packages/coworker-types/src/artifacts.ts +35 -0
- package/packages/coworker-types/src/contracts.test.ts +43 -0
- package/packages/coworker-types/src/contracts.ts +36 -0
- package/packages/coworker-types/src/index.ts +5 -0
- package/packages/coworker-types/src/memory.test.ts +50 -0
- package/packages/coworker-types/src/memory.ts +79 -0
- package/packages/coworker-types/src/scratchpad.test.ts +46 -0
- package/packages/coworker-types/src/scratchpad.ts +51 -0
- package/packages/coworker-types/src/smoke.test.ts +34 -0
- package/packages/coworker-types/src/vault.test.ts +49 -0
- package/packages/coworker-types/src/vault.ts +40 -0
- package/packages/coworker-types/tsconfig.json +15 -0
- package/packages/coworker-types/tsconfig.publish.json +4 -0
- package/packages/coworker-utils/dist/audit-log.d.ts +34 -0
- package/packages/coworker-utils/dist/audit-log.js +88 -0
- package/packages/coworker-utils/dist/index.d.ts +6 -0
- package/packages/coworker-utils/dist/index.js +6 -0
- package/packages/coworker-utils/dist/lease.d.ts +7 -0
- package/packages/coworker-utils/dist/lease.js +67 -0
- package/packages/coworker-utils/dist/logger.d.ts +13 -0
- package/packages/coworker-utils/dist/logger.js +26 -0
- package/packages/coworker-utils/dist/migration-runner.d.ts +7 -0
- package/packages/coworker-utils/dist/migration-runner.js +36 -0
- package/packages/coworker-utils/dist/ndjson-channel.d.ts +3 -0
- package/packages/coworker-utils/dist/ndjson-channel.js +38 -0
- package/packages/coworker-utils/dist/secret-scanner.d.ts +10 -0
- package/packages/coworker-utils/dist/secret-scanner.js +42 -0
- package/packages/coworker-utils/package.json +24 -0
- package/packages/coworker-utils/src/audit-log.test.ts +140 -0
- package/packages/coworker-utils/src/audit-log.ts +107 -0
- package/packages/coworker-utils/src/index.ts +6 -0
- package/packages/coworker-utils/src/lease.test.ts +64 -0
- package/packages/coworker-utils/src/lease.ts +76 -0
- package/packages/coworker-utils/src/logger.test.ts +50 -0
- package/packages/coworker-utils/src/logger.ts +45 -0
- package/packages/coworker-utils/src/migration-runner.test.ts +65 -0
- package/packages/coworker-utils/src/migration-runner.ts +50 -0
- package/packages/coworker-utils/src/ndjson-channel.test.ts +76 -0
- package/packages/coworker-utils/src/ndjson-channel.ts +41 -0
- package/packages/coworker-utils/src/secret-scanner.test.ts +61 -0
- package/packages/coworker-utils/src/secret-scanner.ts +56 -0
- package/packages/coworker-utils/tsconfig.json +15 -0
- package/packages/coworker-utils/tsconfig.publish.json +4 -0
- package/packages/coworker-vault/dist/data-vault.d.ts +41 -0
- package/packages/coworker-vault/dist/data-vault.js +223 -0
- package/packages/coworker-vault/dist/engine-registry.d.ts +34 -0
- package/packages/coworker-vault/dist/engine-registry.js +90 -0
- package/packages/coworker-vault/dist/engines/jira.yaml +17 -0
- package/packages/coworker-vault/dist/errors.d.ts +28 -0
- package/packages/coworker-vault/dist/errors.js +57 -0
- package/packages/coworker-vault/dist/index.d.ts +6 -0
- package/packages/coworker-vault/dist/index.js +6 -0
- package/packages/coworker-vault/dist/injector.d.ts +19 -0
- package/packages/coworker-vault/dist/injector.js +77 -0
- package/packages/coworker-vault/dist/types.d.ts +28 -0
- package/packages/coworker-vault/dist/types.js +1 -0
- package/packages/coworker-vault/dist/vault-keep.d.ts +4 -0
- package/packages/coworker-vault/dist/vault-keep.js +21 -0
- package/packages/coworker-vault/package.json +29 -0
- package/packages/coworker-vault/src/data-vault.test.ts +199 -0
- package/packages/coworker-vault/src/data-vault.ts +257 -0
- package/packages/coworker-vault/src/engine-registry.test.ts +120 -0
- package/packages/coworker-vault/src/engine-registry.ts +107 -0
- package/packages/coworker-vault/src/engines/jira.yaml +17 -0
- package/packages/coworker-vault/src/errors.test.ts +58 -0
- package/packages/coworker-vault/src/errors.ts +50 -0
- package/packages/coworker-vault/src/index.test.ts +24 -0
- package/packages/coworker-vault/src/index.ts +6 -0
- package/packages/coworker-vault/src/injector.test.ts +109 -0
- package/packages/coworker-vault/src/injector.ts +98 -0
- package/packages/coworker-vault/src/types.ts +33 -0
- package/packages/coworker-vault/src/vault-keep.test.ts +49 -0
- package/packages/coworker-vault/src/vault-keep.ts +31 -0
- package/packages/coworker-vault/tsconfig.json +15 -0
- package/packages/coworker-vault/tsconfig.publish.json +4 -0
- package/packages/daemon/package.json +3 -3
- package/packages/mcp-server/package.json +3 -3
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +1 -1
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +6 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +22 -3
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +11 -0
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.d.ts +47 -0
- package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.js +107 -0
- package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.regression.test.d.ts +19 -0
- package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.regression.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.regression.test.js +121 -0
- package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.regression.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +17 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +2 -2
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +22 -3
- package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +11 -0
- package/packages/pi-coding-agent/src/modes/rpc/raw-stdout.regression.test.ts +129 -0
- package/packages/pi-coding-agent/src/modes/rpc/raw-stdout.ts +117 -0
- package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +18 -1
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/package.json +2 -2
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
- package/pkg/package.json +1 -1
- package/scripts/install.js +6 -5
- package/src/resources/extensions/_coworker-paths.test.ts +40 -0
- package/src/resources/extensions/_coworker-paths.ts +10 -0
- package/src/resources/extensions/coworker-artifacts/artifacts-command.test.ts +54 -0
- package/src/resources/extensions/coworker-artifacts/artifacts-command.ts +43 -0
- package/src/resources/extensions/coworker-artifacts/artifacts-singleton.test.ts +25 -0
- package/src/resources/extensions/coworker-artifacts/artifacts-singleton.ts +29 -0
- package/src/resources/extensions/coworker-artifacts/extension-manifest.json +13 -0
- package/src/resources/extensions/coworker-artifacts/index.test.ts +46 -0
- package/src/resources/extensions/coworker-artifacts/index.ts +154 -0
- package/src/resources/extensions/coworker-artifacts/list-tool.test.ts +29 -0
- package/src/resources/extensions/coworker-artifacts/list-tool.ts +53 -0
- package/src/resources/extensions/coworker-artifacts/open-tool.test.ts +30 -0
- package/src/resources/extensions/coworker-artifacts/open-tool.ts +43 -0
- package/src/resources/extensions/coworker-memory/extension-manifest.json +13 -0
- package/src/resources/extensions/coworker-memory/index.test.ts +137 -0
- package/src/resources/extensions/coworker-memory/index.ts +257 -0
- package/src/resources/extensions/coworker-memory/memorize-tool.test.ts +41 -0
- package/src/resources/extensions/coworker-memory/memorize-tool.ts +20 -0
- package/src/resources/extensions/coworker-memory/memory-command.test.ts +134 -0
- package/src/resources/extensions/coworker-memory/memory-command.ts +131 -0
- package/src/resources/extensions/coworker-memory/memory-singleton.test.ts +41 -0
- package/src/resources/extensions/coworker-memory/memory-singleton.ts +89 -0
- package/src/resources/extensions/coworker-memory/recall-tool.test.ts +50 -0
- package/src/resources/extensions/coworker-memory/recall-tool.ts +35 -0
- package/src/resources/extensions/coworker-memory/session-hooks.test.ts +77 -0
- package/src/resources/extensions/coworker-memory/session-hooks.ts +61 -0
- package/src/resources/extensions/coworker-scratchpad/attach-banners.test.ts +124 -0
- package/src/resources/extensions/coworker-scratchpad/attach-banners.ts +67 -0
- package/src/resources/extensions/coworker-scratchpad/extension-manifest.json +13 -0
- package/src/resources/extensions/coworker-scratchpad/format-age.test.ts +30 -0
- package/src/resources/extensions/coworker-scratchpad/format-age.ts +6 -0
- package/src/resources/extensions/coworker-scratchpad/helpers.test.ts +93 -0
- package/src/resources/extensions/coworker-scratchpad/helpers.ts +42 -0
- package/src/resources/extensions/coworker-scratchpad/index.test.ts +514 -0
- package/src/resources/extensions/coworker-scratchpad/index.ts +207 -0
- package/src/resources/extensions/coworker-scratchpad/mime-bundle.test.ts +61 -0
- package/src/resources/extensions/coworker-scratchpad/mime-bundle.ts +23 -0
- package/src/resources/extensions/coworker-scratchpad/scratchpad-tool.test.ts +137 -0
- package/src/resources/extensions/coworker-scratchpad/scratchpad-tool.ts +165 -0
- package/src/resources/extensions/coworker-scratchpad/session-sidecar.test.ts +133 -0
- package/src/resources/extensions/coworker-scratchpad/session-sidecar.ts +68 -0
- package/src/resources/extensions/coworker-scratchpad/sp-command.test.ts +836 -0
- package/src/resources/extensions/coworker-scratchpad/sp-command.ts +602 -0
- package/src/resources/extensions/coworker-scratchpad/workspace-pointer.test.ts +74 -0
- package/src/resources/extensions/coworker-scratchpad/workspace-pointer.ts +55 -0
- package/src/resources/extensions/coworker-scratchpad/workspace-root.test.ts +51 -0
- package/src/resources/extensions/coworker-scratchpad/workspace-root.ts +16 -0
- package/src/resources/extensions/coworker-vault/audit-command.test.ts +109 -0
- package/src/resources/extensions/coworker-vault/audit-command.ts +56 -0
- package/src/resources/extensions/coworker-vault/connect-command.test.ts +103 -0
- package/src/resources/extensions/coworker-vault/connect-command.ts +69 -0
- package/src/resources/extensions/coworker-vault/datasource-command.test.ts +80 -0
- package/src/resources/extensions/coworker-vault/datasource-command.ts +81 -0
- package/src/resources/extensions/coworker-vault/extension-manifest.json +12 -0
- package/src/resources/extensions/coworker-vault/index.test.ts +82 -0
- package/src/resources/extensions/coworker-vault/index.ts +181 -0
- package/src/resources/extensions/coworker-vault/test-helpers.ts +120 -0
- package/src/resources/extensions/coworker-vault/vault-singleton.test.ts +27 -0
- package/src/resources/extensions/coworker-vault/vault-singleton.ts +40 -0
- package/src/resources/extensions/otto/commands/release-notes/_data.ts +96 -0
- package/src/resources/extensions/otto/commands/release-notes/command.ts +16 -3
- package/src/resources/extensions/subagent/index.ts +9 -0
- package/src/resources/extensions/subagent/launch.test.ts +97 -0
- package/src/resources/extensions/subagent/launch.ts +42 -5
- package/src/resources/extensions/subagent/run-store.ts +3 -1
- package/src/resources/extensions/workflow/bootstrap/register-extension.ts +2 -0
- package/src/resources/extensions/workflow/bootstrap/register-hooks.ts +10 -0
- package/src/resources/extensions/workflow/persona-status.ts +109 -0
- package/src/resources/extensions/workflow/tests/auto-recovery.test.ts +34 -0
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import pl from 'nodejs-polars';
|
|
2
|
+
import ExcelJS from 'exceljs';
|
|
3
|
+
import lodash from 'lodash';
|
|
4
|
+
import axios from 'axios';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import * as dateFns from 'date-fns';
|
|
7
|
+
import * as DuckDB from '@duckdb/node-api';
|
|
8
|
+
import type { DuckDBInstance, DuckDBConnection } from '@duckdb/node-api';
|
|
9
|
+
import { SecretScanner, type AuditLog, type AuditRecord } from '@otto/coworker-utils';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The data libraries pre-bound into every scratchpad cell's vm sandbox.
|
|
13
|
+
* DuckDB is bound as an in-memory-capable lib here; on-disk kernel.db wiring is 1d2.
|
|
14
|
+
*/
|
|
15
|
+
export function buildDataLibBindings(): Record<string, unknown> {
|
|
16
|
+
return {
|
|
17
|
+
polars: pl,
|
|
18
|
+
DuckDB,
|
|
19
|
+
ExcelJS,
|
|
20
|
+
dateFns,
|
|
21
|
+
lodash,
|
|
22
|
+
zod: z,
|
|
23
|
+
axios,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// Task F: otto.duckdb.registerDf — single-call polars/Arrow/records → DuckDB
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
/** SQL column type string passed straight into CREATE TABLE (e.g. VARCHAR, BIGINT). */
|
|
32
|
+
export type DuckDBColumnType = string;
|
|
33
|
+
|
|
34
|
+
export interface RegisterDfOptions {
|
|
35
|
+
/**
|
|
36
|
+
* Explicit per-column SQL types. When omitted, the schema is inferred from
|
|
37
|
+
* the first non-null value of each column in the first 10 rows.
|
|
38
|
+
*/
|
|
39
|
+
schema?: Record<string, DuckDBColumnType> | Array<[string, DuckDBColumnType]>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface PolarsDataFrameShape {
|
|
43
|
+
toRecords: () => Record<string, unknown>[];
|
|
44
|
+
width: number;
|
|
45
|
+
height: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface ArrowTableShape {
|
|
49
|
+
toArray: () => Record<string, unknown>[];
|
|
50
|
+
numRows: number;
|
|
51
|
+
schema: unknown;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function isPolarsDataFrame(x: unknown): x is PolarsDataFrameShape {
|
|
55
|
+
return (
|
|
56
|
+
!!x &&
|
|
57
|
+
typeof x === 'object' &&
|
|
58
|
+
typeof (x as { toRecords?: unknown }).toRecords === 'function' &&
|
|
59
|
+
typeof (x as { width?: unknown }).width === 'number' &&
|
|
60
|
+
typeof (x as { height?: unknown }).height === 'number'
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function isArrowTable(x: unknown): x is ArrowTableShape {
|
|
65
|
+
return (
|
|
66
|
+
!!x &&
|
|
67
|
+
typeof x === 'object' &&
|
|
68
|
+
typeof (x as { toArray?: unknown }).toArray === 'function' &&
|
|
69
|
+
typeof (x as { numRows?: unknown }).numRows === 'number' &&
|
|
70
|
+
'schema' in (x as object)
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function coerceToRecords(input: unknown): Record<string, unknown>[] {
|
|
75
|
+
if (isPolarsDataFrame(input)) return input.toRecords();
|
|
76
|
+
if (isArrowTable(input)) return input.toArray();
|
|
77
|
+
if (Array.isArray(input)) return input as Record<string, unknown>[];
|
|
78
|
+
throw new TypeError(
|
|
79
|
+
'registerDf: input must be a polars DataFrame, Arrow Table, or array of records',
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function inferSchema(records: Record<string, unknown>[]): Record<string, DuckDBColumnType> {
|
|
84
|
+
if (records.length === 0) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
'registerDf: cannot infer schema from empty input. Provide opts.schema or pass at least one row.',
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
const cols = Object.keys(records[0]!);
|
|
90
|
+
const out: Record<string, DuckDBColumnType> = {};
|
|
91
|
+
for (const col of cols) {
|
|
92
|
+
// Null-walk: scan up to the first 10 rows for the first non-null value of this column.
|
|
93
|
+
// Defaults to VARCHAR for all-null columns (safe — DuckDB will accept NULL into a VARCHAR).
|
|
94
|
+
out[col] = 'VARCHAR';
|
|
95
|
+
const walk = Math.min(10, records.length);
|
|
96
|
+
for (let i = 0; i < walk; i++) {
|
|
97
|
+
const v = records[i]![col];
|
|
98
|
+
if (v === null || v === undefined) continue;
|
|
99
|
+
if (typeof v === 'string') { out[col] = 'VARCHAR'; break; }
|
|
100
|
+
if (typeof v === 'bigint') { out[col] = 'BIGINT'; break; }
|
|
101
|
+
if (typeof v === 'number') { out[col] = 'DOUBLE'; break; }
|
|
102
|
+
if (typeof v === 'boolean') { out[col] = 'BOOLEAN'; break; }
|
|
103
|
+
if (v instanceof Date) { out[col] = 'TIMESTAMP'; break; }
|
|
104
|
+
out[col] = 'VARCHAR'; // unknown object → store as VARCHAR
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return out;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function normalizeSchema(
|
|
112
|
+
schema: Record<string, DuckDBColumnType> | Array<[string, DuckDBColumnType]>,
|
|
113
|
+
): Array<[string, DuckDBColumnType]> {
|
|
114
|
+
if (Array.isArray(schema)) return schema;
|
|
115
|
+
return Object.entries(schema);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function quoteIdent(name: string): string {
|
|
119
|
+
// DuckDB identifier quoting: wrap in double quotes, escape embedded double quotes.
|
|
120
|
+
return `"${name.replace(/"/g, '""')}"`;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function registerViaAppender(
|
|
124
|
+
conn: DuckDBConnection,
|
|
125
|
+
name: string,
|
|
126
|
+
records: Record<string, unknown>[],
|
|
127
|
+
schema: Array<[string, DuckDBColumnType]>,
|
|
128
|
+
sourceHint: 'inferred' | 'explicit',
|
|
129
|
+
): Promise<void> {
|
|
130
|
+
const ddl = `CREATE TABLE ${quoteIdent(name)} (${schema
|
|
131
|
+
.map(([c, t]) => `${quoteIdent(c)} ${t}`)
|
|
132
|
+
.join(', ')})`;
|
|
133
|
+
await conn.run(ddl);
|
|
134
|
+
// All-or-nothing semantic: on any failure we drop the table so the caller
|
|
135
|
+
// can retry the same name without hitting "Table already exists." On the
|
|
136
|
+
// success path we flip this flag and the finally becomes a no-op.
|
|
137
|
+
let createdTable = true;
|
|
138
|
+
const app = await conn.createAppender(name);
|
|
139
|
+
try {
|
|
140
|
+
for (let i = 0; i < records.length; i++) {
|
|
141
|
+
let failingColIdx = -1;
|
|
142
|
+
try {
|
|
143
|
+
for (let colIdx = 0; colIdx < schema.length; colIdx++) {
|
|
144
|
+
failingColIdx = colIdx;
|
|
145
|
+
const col = schema[colIdx]![0];
|
|
146
|
+
const v = records[i]![col];
|
|
147
|
+
if (v === null || v === undefined) {
|
|
148
|
+
app.appendNull();
|
|
149
|
+
} else {
|
|
150
|
+
// appendValue accepts DuckDBValue (null | boolean | number | bigint | string | ...)
|
|
151
|
+
// and lets the engine coerce based on the declared column type.
|
|
152
|
+
app.appendValue(v as never);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// endRow() may itself reject the row on a type mismatch detected at
|
|
156
|
+
// end-of-row; in that case we can't attribute to a single column so
|
|
157
|
+
// we fall back to '<column>' literally rather than blame col 0.
|
|
158
|
+
failingColIdx = -1;
|
|
159
|
+
app.endRow();
|
|
160
|
+
} catch (e) {
|
|
161
|
+
const failingCol =
|
|
162
|
+
failingColIdx >= 0 ? schema[failingColIdx]![0] : '<column>';
|
|
163
|
+
const hint =
|
|
164
|
+
sourceHint === 'inferred'
|
|
165
|
+
? ` Pass an explicit schema via the third argument: registerDf(name, df, { schema: { ${failingCol}: 'VARCHAR' } })`
|
|
166
|
+
: '';
|
|
167
|
+
throw new Error(
|
|
168
|
+
`registerDf row ${i}: append failed for column '${failingCol}' (${(e as Error).message}).${hint}`,
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
// Success path: close the appender to commit the rows, then disarm cleanup.
|
|
173
|
+
app.closeSync();
|
|
174
|
+
createdTable = false;
|
|
175
|
+
} finally {
|
|
176
|
+
if (createdTable) {
|
|
177
|
+
// Failure path: close the appender (may already be closed; best-effort)
|
|
178
|
+
// then drop the partially-populated table.
|
|
179
|
+
try { app.closeSync(); } catch { /* already closed or errored */ }
|
|
180
|
+
try { await conn.run(`DROP TABLE IF EXISTS ${quoteIdent(name)}`); } catch { /* best-effort */ }
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Patches a DuckDBInstance with a `registerDf(name, input, opts?)` method
|
|
187
|
+
* so the LLM can drop a polars DataFrame / Arrow Table / array of records
|
|
188
|
+
* into DuckDB in one call instead of discovering the appender API.
|
|
189
|
+
*
|
|
190
|
+
* The method opens a fresh connection on each call (cheap — DuckDB connections
|
|
191
|
+
* share the underlying instance/db) and CREATE-TABLE-then-appends.
|
|
192
|
+
*/
|
|
193
|
+
export function attachRegisterDf(instance: DuckDBInstance): void {
|
|
194
|
+
const patched = instance as unknown as {
|
|
195
|
+
registerDf: (
|
|
196
|
+
name: string,
|
|
197
|
+
input: unknown,
|
|
198
|
+
opts?: RegisterDfOptions,
|
|
199
|
+
) => Promise<void>;
|
|
200
|
+
};
|
|
201
|
+
patched.registerDf = async function registerDf(
|
|
202
|
+
name: string,
|
|
203
|
+
input: unknown,
|
|
204
|
+
opts: RegisterDfOptions = {},
|
|
205
|
+
): Promise<void> {
|
|
206
|
+
const conn = await instance.connect();
|
|
207
|
+
try {
|
|
208
|
+
const records = coerceToRecords(input);
|
|
209
|
+
const sourceHint: 'inferred' | 'explicit' = opts.schema ? 'explicit' : 'inferred';
|
|
210
|
+
const schemaObj = opts.schema ?? inferSchema(records);
|
|
211
|
+
const schema = normalizeSchema(schemaObj);
|
|
212
|
+
await registerViaAppender(conn, name, records, schema, sourceHint);
|
|
213
|
+
} finally {
|
|
214
|
+
// Release the connection — DuckDBConnection exposes closeSync(): void.
|
|
215
|
+
// Without this, every registerDf call leaks one connection over the
|
|
216
|
+
// lifetime of the scratchpad session.
|
|
217
|
+
conn.closeSync();
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// ---------------------------------------------------------------------------
|
|
223
|
+
// Phase 2 Task 14: SecretScanner gate on cell-output journal writes.
|
|
224
|
+
// Live TUI output is UPSTREAM of the journal write (the runtime returns the
|
|
225
|
+
// raw stdout, then the manager forks: the same string is returned to the tool
|
|
226
|
+
// for live display AND passed through redactForJournal before archive.append).
|
|
227
|
+
// Only the journal copy is redacted; the TUI copy is untouched.
|
|
228
|
+
// ---------------------------------------------------------------------------
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Context passed to `redactForJournal`. The audit instance is the same one
|
|
232
|
+
* held by the CredentialInjector — supplied by the manager so secret-redaction
|
|
233
|
+
* audit records land alongside vault inject/inject-skipped records.
|
|
234
|
+
*/
|
|
235
|
+
export interface RedactionContext {
|
|
236
|
+
audit: AuditLog;
|
|
237
|
+
sessionId: string;
|
|
238
|
+
scratchpadName: string;
|
|
239
|
+
pid: number;
|
|
240
|
+
cellId: string;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const journalScanner = new SecretScanner();
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Scans `raw` for known secret patterns; for each hit, appends a
|
|
247
|
+
* `producer: 'secret-scanner', action: 'redact'` audit record (severity warn)
|
|
248
|
+
* with `detail = { cell_id, kind, offset, length }` — NEVER the secret value
|
|
249
|
+
* or `SecretHit.preview`. Returns the redacted text (`[REDACTED:<kind>]` per
|
|
250
|
+
* hit). If no hits, returns the input verbatim with no audit emission.
|
|
251
|
+
*
|
|
252
|
+
* Backward compatibility: callers that don't have an AuditLog should skip this
|
|
253
|
+
* helper entirely (pass-through). Audit is required here because the redaction
|
|
254
|
+
* MUST be observable.
|
|
255
|
+
*/
|
|
256
|
+
export function redactForJournal(raw: string, ctx: RedactionContext): string {
|
|
257
|
+
const hits = journalScanner.scan(raw);
|
|
258
|
+
if (hits.length === 0) return raw;
|
|
259
|
+
const ts = new Date().toISOString();
|
|
260
|
+
for (const h of hits) {
|
|
261
|
+
ctx.audit.append({
|
|
262
|
+
_schema: 1,
|
|
263
|
+
ts,
|
|
264
|
+
producer: 'secret-scanner',
|
|
265
|
+
action: 'redact',
|
|
266
|
+
severity: 'warn',
|
|
267
|
+
sessionId: ctx.sessionId,
|
|
268
|
+
scratchpadName: ctx.scratchpadName,
|
|
269
|
+
pid: ctx.pid,
|
|
270
|
+
detail: {
|
|
271
|
+
cell_id: ctx.cellId,
|
|
272
|
+
kind: h.kind,
|
|
273
|
+
offset: h.start,
|
|
274
|
+
length: h.end - h.start,
|
|
275
|
+
},
|
|
276
|
+
} satisfies AuditRecord);
|
|
277
|
+
}
|
|
278
|
+
return journalScanner.redact(raw);
|
|
279
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { describe, it, beforeEach, afterEach } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { spawn, type ChildProcessWithoutNullStreams } from 'node:child_process';
|
|
4
|
+
import { existsSync } from 'node:fs';
|
|
5
|
+
import { mkdtemp, mkdir, writeFile, rm } from 'node:fs/promises';
|
|
6
|
+
import { tmpdir } from 'node:os';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { pathToFileURL } from 'node:url';
|
|
9
|
+
import process from 'node:process';
|
|
10
|
+
import { writeNdjson, readNdjson } from '@otto/coworker-utils';
|
|
11
|
+
import { ChildProcessRuntime } from './child-process-runtime.js';
|
|
12
|
+
import { resolveKernelEntry, kernelExecArgv, filterEnv } from './kernel-spawn.js';
|
|
13
|
+
import type { KernelFrame, ProgressEvent, ResultResponse } from './kernel-protocol.js';
|
|
14
|
+
|
|
15
|
+
let workspace: string;
|
|
16
|
+
let inputs: string;
|
|
17
|
+
let child: ChildProcessWithoutNullStreams;
|
|
18
|
+
|
|
19
|
+
function startKernel(ws: string): ChildProcessWithoutNullStreams {
|
|
20
|
+
return spawn(
|
|
21
|
+
process.execPath,
|
|
22
|
+
[...kernelExecArgv(), resolveKernelEntry(), ws],
|
|
23
|
+
{ stdio: ['pipe', 'pipe', 'inherit'], cwd: process.cwd(), env: filterEnv(process.env) },
|
|
24
|
+
) as unknown as ChildProcessWithoutNullStreams;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Drain frames until `count` result frames have arrived; ignore events.
|
|
28
|
+
async function collectResults(c: ChildProcessWithoutNullStreams, count: number): Promise<ResultResponse[]> {
|
|
29
|
+
const results: ResultResponse[] = [];
|
|
30
|
+
for await (const raw of readNdjson(c.stdout)) {
|
|
31
|
+
const frame = raw as KernelFrame;
|
|
32
|
+
if (frame.type === 'result') {
|
|
33
|
+
results.push(frame);
|
|
34
|
+
if (results.length === count) break;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return results;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
describe('kernel-entry (child process)', () => {
|
|
41
|
+
beforeEach(async () => {
|
|
42
|
+
workspace = await mkdtemp(join(tmpdir(), 'ke-ws-'));
|
|
43
|
+
inputs = join(workspace, '.otto', 'inputs');
|
|
44
|
+
await mkdir(inputs, { recursive: true });
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
afterEach(async () => {
|
|
48
|
+
child?.kill('SIGKILL');
|
|
49
|
+
await rm(workspace, { recursive: true, force: true });
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('evaluates a cell and returns its value + captured stdout', async () => {
|
|
53
|
+
child = startKernel(workspace);
|
|
54
|
+
await writeNdjson(child.stdin, { id: 1, type: 'run', code: "console.log('hi'); return 1 + 1;" });
|
|
55
|
+
const [res] = await collectResults(child, 1);
|
|
56
|
+
assert.equal(res.ok, true);
|
|
57
|
+
assert.equal((res as { value: unknown }).value, 2);
|
|
58
|
+
assert.equal((res as { stdout: string }).stdout, 'hi');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('persists globalThis across cells', async () => {
|
|
62
|
+
child = startKernel(workspace);
|
|
63
|
+
await writeNdjson(child.stdin, { id: 1, type: 'run', code: 'globalThis.counter = 41; return globalThis.counter;' });
|
|
64
|
+
await writeNdjson(child.stdin, { id: 2, type: 'run', code: 'return globalThis.counter + 1;' });
|
|
65
|
+
const results = await collectResults(child, 2);
|
|
66
|
+
assert.equal(results[0].ok, true);
|
|
67
|
+
assert.equal((results[0] as { value: unknown }).value, 41);
|
|
68
|
+
assert.equal((results[1] as { value: unknown }).value, 42);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('binds otto.collectors.list() to the workspace inputs dir', async () => {
|
|
72
|
+
await writeFile(join(inputs, 'cmdb.csv'), 'a,b\n1,2\n');
|
|
73
|
+
child = startKernel(workspace);
|
|
74
|
+
await writeNdjson(child.stdin, { id: 1, type: 'run', code: 'return (await otto.collectors.list()).map((r) => r.uri);' });
|
|
75
|
+
const [res] = await collectResults(child, 1);
|
|
76
|
+
assert.equal(res.ok, true);
|
|
77
|
+
assert.deepEqual((res as { value: string[] }).value, [pathToFileURL(join(inputs, 'cmdb.csv')).href]);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('returns ok:false with the error message when a cell throws', async () => {
|
|
81
|
+
child = startKernel(workspace);
|
|
82
|
+
await writeNdjson(child.stdin, { id: 1, type: 'run', code: "throw new Error('boom');" });
|
|
83
|
+
const [res] = await collectResults(child, 1);
|
|
84
|
+
assert.equal(res.ok, false);
|
|
85
|
+
assert.match((res as { error: { message: string } }).error.message, /boom/);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('emits a progress event when a cell calls progress()', async () => {
|
|
89
|
+
child = startKernel(workspace);
|
|
90
|
+
await writeNdjson(child.stdin, { id: 1, type: 'run', code: "progress('halfway'); return 1;" });
|
|
91
|
+
const frames: KernelFrame[] = [];
|
|
92
|
+
for await (const raw of readNdjson(child.stdout)) {
|
|
93
|
+
const f = raw as KernelFrame;
|
|
94
|
+
frames.push(f);
|
|
95
|
+
if (f.type === 'result') break;
|
|
96
|
+
}
|
|
97
|
+
const prog = frames.find((f) => f.type === 'event' && f.event === 'progress');
|
|
98
|
+
assert.ok(prog, 'expected a progress event before the result');
|
|
99
|
+
assert.equal((prog as ProgressEvent).message, 'halfway');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('snapshot writes namespace.json via tmp + rename (no .tmp leak — 1g3)', async () => {
|
|
103
|
+
// Strategy: drive the kernel via ChildProcessRuntime, run a cell, snapshot,
|
|
104
|
+
// confirm namespace.json exists and namespace.json.tmp does NOT.
|
|
105
|
+
// (kernel-entry's snapshot handler is exercised through a real subprocess
|
|
106
|
+
// in the existing tests; this just adds the .tmp absence assertion.)
|
|
107
|
+
const ws = await mkdtemp(join(tmpdir(), 'ke-ws-'));
|
|
108
|
+
const dir = await mkdtemp(join(tmpdir(), 'ke-dir-'));
|
|
109
|
+
try {
|
|
110
|
+
const rt = new ChildProcessRuntime({ workspace: ws, scratchpadDir: dir });
|
|
111
|
+
await rt.start();
|
|
112
|
+
await rt.runCell('globalThis.x = 1;');
|
|
113
|
+
const res = await rt.snapshot();
|
|
114
|
+
assert.equal(res.ok, true, 'snapshot acked');
|
|
115
|
+
assert.ok(existsSync(join(dir, 'namespace.json')), 'namespace.json present');
|
|
116
|
+
assert.equal(existsSync(join(dir, 'namespace.json.tmp')), false, 'no .tmp leak');
|
|
117
|
+
await rt.dispose();
|
|
118
|
+
} finally {
|
|
119
|
+
await rm(ws, { recursive: true, force: true });
|
|
120
|
+
await rm(dir, { recursive: true, force: true });
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
});
|