@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,109 @@
|
|
|
1
|
+
import { describe, it, beforeEach, afterEach } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { mkdtemp, mkdir, writeFile, rm } from 'node:fs/promises';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { pathToFileURL } from 'node:url';
|
|
7
|
+
import { FileCollector } from './file-collector.js';
|
|
8
|
+
|
|
9
|
+
let workspace: string;
|
|
10
|
+
let inputs: string;
|
|
11
|
+
|
|
12
|
+
async function collectRefs(it: AsyncIterable<{ uri: string; kind: string; bytes?: number; metadata: unknown }>) {
|
|
13
|
+
const out = [];
|
|
14
|
+
for await (const ref of it) out.push(ref);
|
|
15
|
+
return out;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
describe('FileCollector', () => {
|
|
19
|
+
beforeEach(async () => {
|
|
20
|
+
workspace = await mkdtemp(join(tmpdir(), 'fc-ws-'));
|
|
21
|
+
inputs = join(workspace, '.otto', 'inputs');
|
|
22
|
+
await mkdir(inputs, { recursive: true });
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
afterEach(async () => {
|
|
26
|
+
await rm(workspace, { recursive: true, force: true });
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('describe() advertises file:// support, the six kinds, watching, no streaming', () => {
|
|
30
|
+
const fc = new FileCollector({ workspace });
|
|
31
|
+
const cap = fc.describe();
|
|
32
|
+
assert.deepEqual(cap.supports_uris, ['file://*']);
|
|
33
|
+
assert.deepEqual([...cap.supports_kinds].sort(), ['csv', 'json', 'md', 'parquet', 'txt', 'xlsx']);
|
|
34
|
+
assert.equal(cap.supports_streaming, false);
|
|
35
|
+
assert.equal(cap.supports_watching, true);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('list() yields refs only for supported files, recursively, skipping unsupported', async () => {
|
|
39
|
+
await writeFile(join(inputs, 'cmdb.csv'), 'a,b\n1,2\n');
|
|
40
|
+
await writeFile(join(inputs, 'notes.txt'), 'hi');
|
|
41
|
+
await writeFile(join(inputs, 'ignore.pdf'), 'x');
|
|
42
|
+
await mkdir(join(inputs, 'nested'), { recursive: true });
|
|
43
|
+
await writeFile(join(inputs, 'nested', 'data.json'), '{"k":1}');
|
|
44
|
+
|
|
45
|
+
const fc = new FileCollector({ workspace });
|
|
46
|
+
const refs = await collectRefs(fc.list());
|
|
47
|
+
const byKind = Object.fromEntries(refs.map((r) => [r.kind, r]));
|
|
48
|
+
|
|
49
|
+
assert.deepEqual(Object.keys(byKind).sort(), ['csv', 'json', 'txt']);
|
|
50
|
+
assert.equal(byKind.csv.collector, 'file');
|
|
51
|
+
assert.equal(byKind.csv.uri, pathToFileURL(join(inputs, 'cmdb.csv')).href);
|
|
52
|
+
assert.equal(byKind.csv.bytes, 8);
|
|
53
|
+
assert.deepEqual(byKind.csv.metadata, {});
|
|
54
|
+
assert.equal(typeof byKind.csv.modified, 'string');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('list() honors the limit option', async () => {
|
|
58
|
+
await writeFile(join(inputs, 'a.csv'), 'x');
|
|
59
|
+
await writeFile(join(inputs, 'b.csv'), 'x');
|
|
60
|
+
await writeFile(join(inputs, 'c.csv'), 'x');
|
|
61
|
+
const fc = new FileCollector({ workspace });
|
|
62
|
+
const refs = await collectRefs(fc.list({ limit: 2 }));
|
|
63
|
+
assert.equal(refs.length, 2);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('list() yields nothing when the inputs dir does not exist', async () => {
|
|
67
|
+
await rm(inputs, { recursive: true, force: true });
|
|
68
|
+
const fc = new FileCollector({ workspace });
|
|
69
|
+
const refs = await collectRefs(fc.list());
|
|
70
|
+
assert.deepEqual(refs, []);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('open().load() parses JSON, returns text as string, and binary as Buffer', async () => {
|
|
74
|
+
await writeFile(join(inputs, 'd.json'), '{"hello":"world"}');
|
|
75
|
+
await writeFile(join(inputs, 'd.csv'), 'a,b\n1,2\n');
|
|
76
|
+
await writeFile(join(inputs, 'd.parquet'), Buffer.from([0x50, 0x41, 0x52, 0x31]));
|
|
77
|
+
const fc = new FileCollector({ workspace });
|
|
78
|
+
|
|
79
|
+
const byKind = Object.fromEntries((await collectRefs(fc.list())).map((r) => [r.kind, r]));
|
|
80
|
+
|
|
81
|
+
const json = await (await fc.open(byKind.json as never)).load();
|
|
82
|
+
assert.deepEqual(json, { hello: 'world' });
|
|
83
|
+
|
|
84
|
+
const csv = await (await fc.open(byKind.csv as never)).load();
|
|
85
|
+
assert.equal(csv, 'a,b\n1,2\n');
|
|
86
|
+
|
|
87
|
+
const parquet = await (await fc.open(byKind.parquet as never)).load();
|
|
88
|
+
assert.ok(Buffer.isBuffer(parquet));
|
|
89
|
+
assert.deepEqual(parquet, Buffer.from([0x50, 0x41, 0x52, 0x31]));
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('watch() invokes onChange when the file is modified and unsubscribe stops it', async () => {
|
|
93
|
+
const file = join(inputs, 'live.csv');
|
|
94
|
+
await writeFile(file, 'v1');
|
|
95
|
+
const fc = new FileCollector({ workspace });
|
|
96
|
+
const ref = (await collectRefs(fc.list()))[0];
|
|
97
|
+
|
|
98
|
+
const changed = new Promise<void>((resolve) => {
|
|
99
|
+
const unsub = fc.watch(ref as never, () => {
|
|
100
|
+
unsub();
|
|
101
|
+
resolve();
|
|
102
|
+
});
|
|
103
|
+
// Give chokidar a moment to register before mutating.
|
|
104
|
+
setTimeout(() => void writeFile(file, 'v2-longer'), 300);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
await changed; // test times out (and fails) if onChange never fires
|
|
108
|
+
});
|
|
109
|
+
});
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { readdir, readFile, stat } from 'node:fs/promises';
|
|
2
|
+
import type { Dirent } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { pathToFileURL, fileURLToPath } from 'node:url';
|
|
5
|
+
import { watch as chokidarWatch } from 'chokidar';
|
|
6
|
+
import type {
|
|
7
|
+
Collector,
|
|
8
|
+
CollectorCapabilities,
|
|
9
|
+
DataSource,
|
|
10
|
+
DataSourceRef,
|
|
11
|
+
ListOpts,
|
|
12
|
+
Unsubscribe,
|
|
13
|
+
} from '@otto/coworker-types';
|
|
14
|
+
import { detectKind, FILE_COLLECTOR_KINDS } from './detect-kind.js';
|
|
15
|
+
|
|
16
|
+
const TEXT_KINDS = new Set(['csv', 'txt', 'md']);
|
|
17
|
+
|
|
18
|
+
export interface FileCollectorOptions {
|
|
19
|
+
/** Absolute path to the workspace root. inputs/ resolves to <workspace>/.otto/inputs. */
|
|
20
|
+
workspace: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class FileCollector implements Collector {
|
|
24
|
+
readonly id = 'file';
|
|
25
|
+
readonly kind = 'file' as const;
|
|
26
|
+
private readonly inputsDir: string;
|
|
27
|
+
|
|
28
|
+
constructor(opts: FileCollectorOptions) {
|
|
29
|
+
this.inputsDir = join(opts.workspace, '.otto', 'inputs');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
describe(): CollectorCapabilities {
|
|
33
|
+
return {
|
|
34
|
+
supports_uris: ['file://*'],
|
|
35
|
+
supports_kinds: [...FILE_COLLECTOR_KINDS],
|
|
36
|
+
supports_streaming: false,
|
|
37
|
+
supports_watching: true,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async *list(opts?: ListOpts): AsyncIterable<DataSourceRef> {
|
|
42
|
+
let remaining = opts?.limit ?? Number.POSITIVE_INFINITY;
|
|
43
|
+
if (remaining <= 0) return;
|
|
44
|
+
const prefixDir = opts?.prefix ? join(this.inputsDir, opts.prefix) : this.inputsDir;
|
|
45
|
+
for await (const abs of walk(this.inputsDir)) {
|
|
46
|
+
if (opts?.prefix && !abs.startsWith(prefixDir)) continue;
|
|
47
|
+
const kind = detectKind(abs);
|
|
48
|
+
if (!kind) continue;
|
|
49
|
+
const st = await stat(abs);
|
|
50
|
+
yield {
|
|
51
|
+
collector: this.id,
|
|
52
|
+
uri: pathToFileURL(abs).href,
|
|
53
|
+
kind,
|
|
54
|
+
bytes: st.size,
|
|
55
|
+
modified: st.mtime.toISOString(),
|
|
56
|
+
metadata: {},
|
|
57
|
+
};
|
|
58
|
+
remaining -= 1;
|
|
59
|
+
if (remaining <= 0) return;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async open(ref: DataSourceRef): Promise<DataSource> {
|
|
64
|
+
const abs = fileURLToPath(ref.uri);
|
|
65
|
+
const kind = ref.kind;
|
|
66
|
+
return {
|
|
67
|
+
ref,
|
|
68
|
+
async load(): Promise<Buffer | string | object> {
|
|
69
|
+
if (kind === 'json') {
|
|
70
|
+
return JSON.parse(await readFile(abs, 'utf8')) as object;
|
|
71
|
+
}
|
|
72
|
+
if (TEXT_KINDS.has(kind)) {
|
|
73
|
+
return readFile(abs, 'utf8');
|
|
74
|
+
}
|
|
75
|
+
return readFile(abs); // Buffer for xlsx/parquet
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
watch(ref: DataSourceRef, onChange: (ref: DataSourceRef) => void): Unsubscribe {
|
|
81
|
+
const abs = fileURLToPath(ref.uri);
|
|
82
|
+
const watcher = chokidarWatch(abs, { ignoreInitial: true });
|
|
83
|
+
const handler = async (): Promise<void> => {
|
|
84
|
+
try {
|
|
85
|
+
const st = await stat(abs);
|
|
86
|
+
onChange({ ...ref, bytes: st.size, modified: st.mtime.toISOString() });
|
|
87
|
+
} catch {
|
|
88
|
+
onChange(ref);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
watcher.on('change', () => void handler());
|
|
92
|
+
watcher.on('add', () => void handler());
|
|
93
|
+
return () => {
|
|
94
|
+
void watcher.close();
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function* walk(dir: string): AsyncIterable<string> {
|
|
100
|
+
let entries: Dirent[];
|
|
101
|
+
try {
|
|
102
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
103
|
+
} catch {
|
|
104
|
+
return; // inputs/ may not exist yet — yield nothing
|
|
105
|
+
}
|
|
106
|
+
for (const entry of entries) {
|
|
107
|
+
const full = join(dir, entry.name);
|
|
108
|
+
if (entry.isDirectory()) {
|
|
109
|
+
yield* walk(full);
|
|
110
|
+
} else if (entry.isFile()) {
|
|
111
|
+
yield full;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export { detectKind, FILE_COLLECTOR_KINDS } from './detect-kind.js';
|
|
2
|
+
export { FileCollector, type FileCollectorOptions } from './file-collector.js';
|
|
3
|
+
export { DefaultCollectorRegistry, uriMatchesPattern } from './collector-registry.js';
|
|
4
|
+
export {
|
|
5
|
+
isDataLoadEvent,
|
|
6
|
+
isProgressEvent,
|
|
7
|
+
isStartupErrorEvent,
|
|
8
|
+
isSnapshotResult,
|
|
9
|
+
type RunRequest,
|
|
10
|
+
type SnapshotRequest,
|
|
11
|
+
type KernelRequest,
|
|
12
|
+
type ResultOk,
|
|
13
|
+
type ResultErr,
|
|
14
|
+
type ResultResponse,
|
|
15
|
+
type SnapshotResultOk,
|
|
16
|
+
type SnapshotResultErr,
|
|
17
|
+
type SnapshotResult,
|
|
18
|
+
type SkippedKey,
|
|
19
|
+
type RecoveryNote,
|
|
20
|
+
type StartupErrorEvent,
|
|
21
|
+
type DataLoadDrawer,
|
|
22
|
+
type ArtifactCreateDrawer,
|
|
23
|
+
type ReadyEvent,
|
|
24
|
+
type DataLoadEvent,
|
|
25
|
+
type ProgressEvent,
|
|
26
|
+
type KernelEvent,
|
|
27
|
+
type KernelFrame,
|
|
28
|
+
} from './kernel-protocol.js';
|
|
29
|
+
export { filterEnv, kernelExecArgv, resolveKernelEntry } from './kernel-spawn.js';
|
|
30
|
+
export {
|
|
31
|
+
ChildProcessRuntime,
|
|
32
|
+
type CellResult,
|
|
33
|
+
type ChildProcessRuntimeOptions,
|
|
34
|
+
} from './child-process-runtime.js';
|
|
35
|
+
export {
|
|
36
|
+
ScratchpadManager,
|
|
37
|
+
ForkKernelHangError,
|
|
38
|
+
type ScratchpadManagerOptions,
|
|
39
|
+
type AttachOptions,
|
|
40
|
+
type ScratchpadInfo,
|
|
41
|
+
} from './scratchpad-manager.js';
|
|
42
|
+
export {
|
|
43
|
+
acquireLock,
|
|
44
|
+
releaseLock,
|
|
45
|
+
readLock,
|
|
46
|
+
isStaleLock,
|
|
47
|
+
ScratchpadBusyError,
|
|
48
|
+
type LockInfo,
|
|
49
|
+
type AcquireOptions,
|
|
50
|
+
} from './scratchpad-lock.js';
|
|
51
|
+
export {
|
|
52
|
+
CellArchive,
|
|
53
|
+
CELLS_SCHEMA_VERSION,
|
|
54
|
+
type CellEntry,
|
|
55
|
+
type AppendInput,
|
|
56
|
+
} from './cell-archive.js';
|
|
57
|
+
export { buildDataLibBindings } from './kernel-bindings.js';
|
|
58
|
+
export {
|
|
59
|
+
NAMESPACE_SCHEMA_VERSION,
|
|
60
|
+
encodeNamespace,
|
|
61
|
+
decodeNamespace,
|
|
62
|
+
type NamespaceEnvelope,
|
|
63
|
+
type EncodeResult,
|
|
64
|
+
type DecodeResult,
|
|
65
|
+
} from './namespace-codec.js';
|
|
66
|
+
export {
|
|
67
|
+
projectTree,
|
|
68
|
+
findLeaves,
|
|
69
|
+
validateLeafId,
|
|
70
|
+
formatTreeText,
|
|
71
|
+
type TreeNode,
|
|
72
|
+
type CellTree,
|
|
73
|
+
} from './cell-tree.js';
|
|
74
|
+
export { StalenessBanner, type StalenessCheck } from './staleness-banner.js';
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { describe, it, beforeEach, afterEach } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { mkdtemp, mkdir, rm } from 'node:fs/promises';
|
|
4
|
+
import { mkdtempSync } from 'node:fs';
|
|
5
|
+
import { tmpdir } from 'node:os';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
import { AuditLog, type AuditRecord } from '@otto/coworker-utils';
|
|
8
|
+
import { buildDataLibBindings, redactForJournal } from './kernel-bindings.js';
|
|
9
|
+
import { ChildProcessRuntime } from './child-process-runtime.js';
|
|
10
|
+
|
|
11
|
+
describe('kernel-bindings', () => {
|
|
12
|
+
it('exposes all seven pre-bound data libraries', () => {
|
|
13
|
+
const b = buildDataLibBindings();
|
|
14
|
+
for (const key of ['polars', 'DuckDB', 'ExcelJS', 'dateFns', 'lodash', 'zod', 'axios']) {
|
|
15
|
+
assert.ok(key in b, `missing binding: ${key}`);
|
|
16
|
+
assert.notEqual(b[key], undefined, `binding is undefined: ${key}`);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('binds usable shapes (polars.DataFrame, zod.string, dateFns.format)', () => {
|
|
21
|
+
const b = buildDataLibBindings() as Record<string, any>;
|
|
22
|
+
assert.equal(typeof b.polars.DataFrame, 'function');
|
|
23
|
+
assert.equal(typeof b.zod.string, 'function');
|
|
24
|
+
assert.equal(typeof b.dateFns.format, 'function');
|
|
25
|
+
assert.equal(typeof b.lodash.chunk, 'function');
|
|
26
|
+
assert.equal(typeof b.axios.get, 'function');
|
|
27
|
+
assert.equal(typeof b.ExcelJS.Workbook, 'function');
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('otto.duckdb.registerDf (Task F)', () => {
|
|
32
|
+
let ws: string;
|
|
33
|
+
let sp: string;
|
|
34
|
+
let rt: ChildProcessRuntime | undefined;
|
|
35
|
+
|
|
36
|
+
beforeEach(async () => {
|
|
37
|
+
ws = await mkdtemp(join(tmpdir(), 'kb-registerdf-ws-'));
|
|
38
|
+
await mkdir(join(ws, '.otto', 'inputs'), { recursive: true });
|
|
39
|
+
sp = await mkdtemp(join(tmpdir(), 'kb-registerdf-sp-'));
|
|
40
|
+
rt = new ChildProcessRuntime({
|
|
41
|
+
workspace: ws,
|
|
42
|
+
scratchpadDir: sp,
|
|
43
|
+
cellTimeoutMs: 30_000,
|
|
44
|
+
inactivityTimeoutMs: 30_000,
|
|
45
|
+
});
|
|
46
|
+
await rt.start();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
afterEach(async () => {
|
|
50
|
+
await rt?.dispose();
|
|
51
|
+
rt = undefined;
|
|
52
|
+
await rm(ws, { recursive: true, force: true });
|
|
53
|
+
await rm(sp, { recursive: true, force: true });
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const runCell = async (code: string): Promise<unknown> => {
|
|
57
|
+
const { value } = await rt!.runCell(code);
|
|
58
|
+
return value;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
it('round-trips an array of records', async () => {
|
|
62
|
+
const result = (await runCell(`
|
|
63
|
+
await otto.duckdb.registerDf('rec', [{a: 1, b: 'x'}, {a: 2, b: 'y'}]);
|
|
64
|
+
const c = await otto.duckdb.connect();
|
|
65
|
+
return (await c.runAndReadAll('SELECT SUM(a) FROM rec')).getRows();
|
|
66
|
+
`)) as unknown[][];
|
|
67
|
+
assert.equal(Number(result[0]![0]), 3);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('round-trips a polars DataFrame', async () => {
|
|
71
|
+
const result = (await runCell(`
|
|
72
|
+
const df = polars.DataFrame({ a: [1, 2, 3], b: ['x', 'y', 'z'] });
|
|
73
|
+
await otto.duckdb.registerDf('pdf', df);
|
|
74
|
+
const c = await otto.duckdb.connect();
|
|
75
|
+
return (await c.runAndReadAll('SELECT SUM(a) FROM pdf')).getRows();
|
|
76
|
+
`)) as unknown[][];
|
|
77
|
+
assert.equal(Number(result[0]![0]), 6);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('throws TypeError for unsupported input', async () => {
|
|
81
|
+
await assert.rejects(
|
|
82
|
+
runCell(`await otto.duckdb.registerDf('bad', 42);`),
|
|
83
|
+
/must be a polars DataFrame, Arrow Table, or array of records/,
|
|
84
|
+
);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('opts.schema override skips inference and uses provided types', async () => {
|
|
88
|
+
const result = (await runCell(`
|
|
89
|
+
await otto.duckdb.registerDf(
|
|
90
|
+
'sized',
|
|
91
|
+
[{n: 1}, {n: 2}, {n: 3}],
|
|
92
|
+
{ schema: { n: 'BIGINT' } }
|
|
93
|
+
);
|
|
94
|
+
const c = await otto.duckdb.connect();
|
|
95
|
+
const desc = await c.runAndReadAll('DESCRIBE sized');
|
|
96
|
+
return desc.getRows();
|
|
97
|
+
`)) as unknown[][];
|
|
98
|
+
assert.equal(result[0]![0], 'n');
|
|
99
|
+
assert.equal(String(result[0]![1]).toUpperCase(), 'BIGINT');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('null-walk inference picks the first non-null value type', async () => {
|
|
103
|
+
const result = (await runCell(`
|
|
104
|
+
const rows = Array(8).fill({ rev: null }).concat([{ rev: 1200 }, { rev: 980 }]);
|
|
105
|
+
await otto.duckdb.registerDf('rev', rows);
|
|
106
|
+
const c = await otto.duckdb.connect();
|
|
107
|
+
const desc = await c.runAndReadAll('DESCRIBE rev');
|
|
108
|
+
return desc.getRows();
|
|
109
|
+
`)) as unknown[][];
|
|
110
|
+
assert.equal(result[0]![0], 'rev');
|
|
111
|
+
assert.equal(String(result[0]![1]).toUpperCase(), 'DOUBLE');
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('partial-failure leaves no table behind (all-or-nothing) and names failing column', async () => {
|
|
115
|
+
// First call: BIGINT schema with a non-coercible string value in row 11 → append fails mid-batch.
|
|
116
|
+
// The all-or-nothing semantic should DROP the partially-populated table so the
|
|
117
|
+
// retry below with the same name + clean data succeeds without "Table already exists."
|
|
118
|
+
await assert.rejects(
|
|
119
|
+
runCell(`
|
|
120
|
+
const rows = [];
|
|
121
|
+
for (let i = 0; i < 11; i++) rows.push({ n: i });
|
|
122
|
+
rows.push({ n: 'not-a-number' });
|
|
123
|
+
await otto.duckdb.registerDf('aon', rows, { schema: { n: 'BIGINT' } });
|
|
124
|
+
`),
|
|
125
|
+
/registerDf row 11: append failed for column 'n'/,
|
|
126
|
+
);
|
|
127
|
+
const result = (await runCell(`
|
|
128
|
+
await otto.duckdb.registerDf('aon', [{n: 7}, {n: 8}], { schema: { n: 'BIGINT' } });
|
|
129
|
+
const c = await otto.duckdb.connect();
|
|
130
|
+
// Cast to DOUBLE so the value survives JSON serialization across the
|
|
131
|
+
// child-process boundary (BIGINT sums become BigInt and JSON-stringify-throw).
|
|
132
|
+
return (await c.runAndReadAll('SELECT CAST(SUM(n) AS DOUBLE) FROM aon')).getRows();
|
|
133
|
+
`)) as unknown[][];
|
|
134
|
+
// Sum of clean retry batch — proves both that the first-call table was DROPped
|
|
135
|
+
// (otherwise CREATE TABLE here would fail) and that the retry persisted rows.
|
|
136
|
+
assert.equal(Number(result[0]![0]), 15);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
describe('kernel-bindings — secret redaction (Phase 2 Task 14)', () => {
|
|
141
|
+
it('redacts secret patterns in stdout before journaling and emits one audit record per hit', async () => {
|
|
142
|
+
const auditPath = join(mkdtempSync(join(tmpdir(), 'kb-audit-')), 'audit.jsonl');
|
|
143
|
+
const audit = new AuditLog({ path: auditPath });
|
|
144
|
+
// AKIA + 16 [A-Z0-9] chars — matches the aws_access_key_id pattern.
|
|
145
|
+
const raw = 'before AKIAABCDEFGHIJKLMNOP after';
|
|
146
|
+
const result = redactForJournal(raw, {
|
|
147
|
+
audit,
|
|
148
|
+
sessionId: 's',
|
|
149
|
+
scratchpadName: 'sp',
|
|
150
|
+
pid: 1,
|
|
151
|
+
cellId: 'c1',
|
|
152
|
+
});
|
|
153
|
+
assert.equal(result, 'before [REDACTED:aws_access_key_id] after');
|
|
154
|
+
const records: AuditRecord[] = [];
|
|
155
|
+
for await (const r of audit.read({ producer: 'secret-scanner' })) records.push(r);
|
|
156
|
+
assert.equal(records.length, 1);
|
|
157
|
+
const rec = records[0]!;
|
|
158
|
+
assert.equal(rec.action, 'redact');
|
|
159
|
+
assert.equal(rec.severity, 'warn');
|
|
160
|
+
assert.equal(rec.scratchpadName, 'sp');
|
|
161
|
+
assert.equal(rec.sessionId, 's');
|
|
162
|
+
assert.equal(rec.pid, 1);
|
|
163
|
+
// Detail must carry kind/offset/length/cell_id and NOT include the secret value or preview.
|
|
164
|
+
assert.equal(rec.detail.kind, 'aws_access_key_id');
|
|
165
|
+
assert.equal(rec.detail.cell_id, 'c1');
|
|
166
|
+
assert.equal(rec.detail.offset, 'before '.length);
|
|
167
|
+
assert.equal(rec.detail.length, 'AKIAABCDEFGHIJKLMNOP'.length);
|
|
168
|
+
assert.equal('preview' in rec.detail, false);
|
|
169
|
+
// Defense-in-depth: the serialized record must not contain the raw secret substring.
|
|
170
|
+
assert.equal(JSON.stringify(rec).includes('AKIAABCDEFGHIJKLMNOP'), false);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('returns input unchanged when no secrets present and writes no audit record', async () => {
|
|
174
|
+
const auditPath = join(mkdtempSync(join(tmpdir(), 'kb-audit-clean-')), 'audit.jsonl');
|
|
175
|
+
const audit = new AuditLog({ path: auditPath });
|
|
176
|
+
const out = redactForJournal('hello world', {
|
|
177
|
+
audit,
|
|
178
|
+
sessionId: 's',
|
|
179
|
+
scratchpadName: 'sp',
|
|
180
|
+
pid: 1,
|
|
181
|
+
cellId: 'c1',
|
|
182
|
+
});
|
|
183
|
+
assert.equal(out, 'hello world');
|
|
184
|
+
const records: AuditRecord[] = [];
|
|
185
|
+
for await (const r of audit.read({ producer: 'secret-scanner' })) records.push(r);
|
|
186
|
+
assert.equal(records.length, 0);
|
|
187
|
+
});
|
|
188
|
+
});
|