@cmetech/otto 1.1.1 → 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 +71 -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/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 +85 -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,49 @@
|
|
|
1
|
+
import type { DuckDBInstance } from '@duckdb/node-api';
|
|
2
|
+
import { type AuditLog } from '@otto/coworker-utils';
|
|
3
|
+
/**
|
|
4
|
+
* The data libraries pre-bound into every scratchpad cell's vm sandbox.
|
|
5
|
+
* DuckDB is bound as an in-memory-capable lib here; on-disk kernel.db wiring is 1d2.
|
|
6
|
+
*/
|
|
7
|
+
export declare function buildDataLibBindings(): Record<string, unknown>;
|
|
8
|
+
/** SQL column type string passed straight into CREATE TABLE (e.g. VARCHAR, BIGINT). */
|
|
9
|
+
export type DuckDBColumnType = string;
|
|
10
|
+
export interface RegisterDfOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Explicit per-column SQL types. When omitted, the schema is inferred from
|
|
13
|
+
* the first non-null value of each column in the first 10 rows.
|
|
14
|
+
*/
|
|
15
|
+
schema?: Record<string, DuckDBColumnType> | Array<[string, DuckDBColumnType]>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Patches a DuckDBInstance with a `registerDf(name, input, opts?)` method
|
|
19
|
+
* so the LLM can drop a polars DataFrame / Arrow Table / array of records
|
|
20
|
+
* into DuckDB in one call instead of discovering the appender API.
|
|
21
|
+
*
|
|
22
|
+
* The method opens a fresh connection on each call (cheap — DuckDB connections
|
|
23
|
+
* share the underlying instance/db) and CREATE-TABLE-then-appends.
|
|
24
|
+
*/
|
|
25
|
+
export declare function attachRegisterDf(instance: DuckDBInstance): void;
|
|
26
|
+
/**
|
|
27
|
+
* Context passed to `redactForJournal`. The audit instance is the same one
|
|
28
|
+
* held by the CredentialInjector — supplied by the manager so secret-redaction
|
|
29
|
+
* audit records land alongside vault inject/inject-skipped records.
|
|
30
|
+
*/
|
|
31
|
+
export interface RedactionContext {
|
|
32
|
+
audit: AuditLog;
|
|
33
|
+
sessionId: string;
|
|
34
|
+
scratchpadName: string;
|
|
35
|
+
pid: number;
|
|
36
|
+
cellId: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Scans `raw` for known secret patterns; for each hit, appends a
|
|
40
|
+
* `producer: 'secret-scanner', action: 'redact'` audit record (severity warn)
|
|
41
|
+
* with `detail = { cell_id, kind, offset, length }` — NEVER the secret value
|
|
42
|
+
* or `SecretHit.preview`. Returns the redacted text (`[REDACTED:<kind>]` per
|
|
43
|
+
* hit). If no hits, returns the input verbatim with no audit emission.
|
|
44
|
+
*
|
|
45
|
+
* Backward compatibility: callers that don't have an AuditLog should skip this
|
|
46
|
+
* helper entirely (pass-through). Audit is required here because the redaction
|
|
47
|
+
* MUST be observable.
|
|
48
|
+
*/
|
|
49
|
+
export declare function redactForJournal(raw: string, ctx: RedactionContext): string;
|
|
@@ -0,0 +1,220 @@
|
|
|
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 { SecretScanner } from '@otto/coworker-utils';
|
|
9
|
+
/**
|
|
10
|
+
* The data libraries pre-bound into every scratchpad cell's vm sandbox.
|
|
11
|
+
* DuckDB is bound as an in-memory-capable lib here; on-disk kernel.db wiring is 1d2.
|
|
12
|
+
*/
|
|
13
|
+
export function buildDataLibBindings() {
|
|
14
|
+
return {
|
|
15
|
+
polars: pl,
|
|
16
|
+
DuckDB,
|
|
17
|
+
ExcelJS,
|
|
18
|
+
dateFns,
|
|
19
|
+
lodash,
|
|
20
|
+
zod: z,
|
|
21
|
+
axios,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function isPolarsDataFrame(x) {
|
|
25
|
+
return (!!x &&
|
|
26
|
+
typeof x === 'object' &&
|
|
27
|
+
typeof x.toRecords === 'function' &&
|
|
28
|
+
typeof x.width === 'number' &&
|
|
29
|
+
typeof x.height === 'number');
|
|
30
|
+
}
|
|
31
|
+
function isArrowTable(x) {
|
|
32
|
+
return (!!x &&
|
|
33
|
+
typeof x === 'object' &&
|
|
34
|
+
typeof x.toArray === 'function' &&
|
|
35
|
+
typeof x.numRows === 'number' &&
|
|
36
|
+
'schema' in x);
|
|
37
|
+
}
|
|
38
|
+
function coerceToRecords(input) {
|
|
39
|
+
if (isPolarsDataFrame(input))
|
|
40
|
+
return input.toRecords();
|
|
41
|
+
if (isArrowTable(input))
|
|
42
|
+
return input.toArray();
|
|
43
|
+
if (Array.isArray(input))
|
|
44
|
+
return input;
|
|
45
|
+
throw new TypeError('registerDf: input must be a polars DataFrame, Arrow Table, or array of records');
|
|
46
|
+
}
|
|
47
|
+
function inferSchema(records) {
|
|
48
|
+
if (records.length === 0) {
|
|
49
|
+
throw new Error('registerDf: cannot infer schema from empty input. Provide opts.schema or pass at least one row.');
|
|
50
|
+
}
|
|
51
|
+
const cols = Object.keys(records[0]);
|
|
52
|
+
const out = {};
|
|
53
|
+
for (const col of cols) {
|
|
54
|
+
// Null-walk: scan up to the first 10 rows for the first non-null value of this column.
|
|
55
|
+
// Defaults to VARCHAR for all-null columns (safe — DuckDB will accept NULL into a VARCHAR).
|
|
56
|
+
out[col] = 'VARCHAR';
|
|
57
|
+
const walk = Math.min(10, records.length);
|
|
58
|
+
for (let i = 0; i < walk; i++) {
|
|
59
|
+
const v = records[i][col];
|
|
60
|
+
if (v === null || v === undefined)
|
|
61
|
+
continue;
|
|
62
|
+
if (typeof v === 'string') {
|
|
63
|
+
out[col] = 'VARCHAR';
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
if (typeof v === 'bigint') {
|
|
67
|
+
out[col] = 'BIGINT';
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
if (typeof v === 'number') {
|
|
71
|
+
out[col] = 'DOUBLE';
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
if (typeof v === 'boolean') {
|
|
75
|
+
out[col] = 'BOOLEAN';
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
if (v instanceof Date) {
|
|
79
|
+
out[col] = 'TIMESTAMP';
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
out[col] = 'VARCHAR'; // unknown object → store as VARCHAR
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return out;
|
|
87
|
+
}
|
|
88
|
+
function normalizeSchema(schema) {
|
|
89
|
+
if (Array.isArray(schema))
|
|
90
|
+
return schema;
|
|
91
|
+
return Object.entries(schema);
|
|
92
|
+
}
|
|
93
|
+
function quoteIdent(name) {
|
|
94
|
+
// DuckDB identifier quoting: wrap in double quotes, escape embedded double quotes.
|
|
95
|
+
return `"${name.replace(/"/g, '""')}"`;
|
|
96
|
+
}
|
|
97
|
+
async function registerViaAppender(conn, name, records, schema, sourceHint) {
|
|
98
|
+
const ddl = `CREATE TABLE ${quoteIdent(name)} (${schema
|
|
99
|
+
.map(([c, t]) => `${quoteIdent(c)} ${t}`)
|
|
100
|
+
.join(', ')})`;
|
|
101
|
+
await conn.run(ddl);
|
|
102
|
+
// All-or-nothing semantic: on any failure we drop the table so the caller
|
|
103
|
+
// can retry the same name without hitting "Table already exists." On the
|
|
104
|
+
// success path we flip this flag and the finally becomes a no-op.
|
|
105
|
+
let createdTable = true;
|
|
106
|
+
const app = await conn.createAppender(name);
|
|
107
|
+
try {
|
|
108
|
+
for (let i = 0; i < records.length; i++) {
|
|
109
|
+
let failingColIdx = -1;
|
|
110
|
+
try {
|
|
111
|
+
for (let colIdx = 0; colIdx < schema.length; colIdx++) {
|
|
112
|
+
failingColIdx = colIdx;
|
|
113
|
+
const col = schema[colIdx][0];
|
|
114
|
+
const v = records[i][col];
|
|
115
|
+
if (v === null || v === undefined) {
|
|
116
|
+
app.appendNull();
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
// appendValue accepts DuckDBValue (null | boolean | number | bigint | string | ...)
|
|
120
|
+
// and lets the engine coerce based on the declared column type.
|
|
121
|
+
app.appendValue(v);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// endRow() may itself reject the row on a type mismatch detected at
|
|
125
|
+
// end-of-row; in that case we can't attribute to a single column so
|
|
126
|
+
// we fall back to '<column>' literally rather than blame col 0.
|
|
127
|
+
failingColIdx = -1;
|
|
128
|
+
app.endRow();
|
|
129
|
+
}
|
|
130
|
+
catch (e) {
|
|
131
|
+
const failingCol = failingColIdx >= 0 ? schema[failingColIdx][0] : '<column>';
|
|
132
|
+
const hint = sourceHint === 'inferred'
|
|
133
|
+
? ` Pass an explicit schema via the third argument: registerDf(name, df, { schema: { ${failingCol}: 'VARCHAR' } })`
|
|
134
|
+
: '';
|
|
135
|
+
throw new Error(`registerDf row ${i}: append failed for column '${failingCol}' (${e.message}).${hint}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Success path: close the appender to commit the rows, then disarm cleanup.
|
|
139
|
+
app.closeSync();
|
|
140
|
+
createdTable = false;
|
|
141
|
+
}
|
|
142
|
+
finally {
|
|
143
|
+
if (createdTable) {
|
|
144
|
+
// Failure path: close the appender (may already be closed; best-effort)
|
|
145
|
+
// then drop the partially-populated table.
|
|
146
|
+
try {
|
|
147
|
+
app.closeSync();
|
|
148
|
+
}
|
|
149
|
+
catch { /* already closed or errored */ }
|
|
150
|
+
try {
|
|
151
|
+
await conn.run(`DROP TABLE IF EXISTS ${quoteIdent(name)}`);
|
|
152
|
+
}
|
|
153
|
+
catch { /* best-effort */ }
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Patches a DuckDBInstance with a `registerDf(name, input, opts?)` method
|
|
159
|
+
* so the LLM can drop a polars DataFrame / Arrow Table / array of records
|
|
160
|
+
* into DuckDB in one call instead of discovering the appender API.
|
|
161
|
+
*
|
|
162
|
+
* The method opens a fresh connection on each call (cheap — DuckDB connections
|
|
163
|
+
* share the underlying instance/db) and CREATE-TABLE-then-appends.
|
|
164
|
+
*/
|
|
165
|
+
export function attachRegisterDf(instance) {
|
|
166
|
+
const patched = instance;
|
|
167
|
+
patched.registerDf = async function registerDf(name, input, opts = {}) {
|
|
168
|
+
const conn = await instance.connect();
|
|
169
|
+
try {
|
|
170
|
+
const records = coerceToRecords(input);
|
|
171
|
+
const sourceHint = opts.schema ? 'explicit' : 'inferred';
|
|
172
|
+
const schemaObj = opts.schema ?? inferSchema(records);
|
|
173
|
+
const schema = normalizeSchema(schemaObj);
|
|
174
|
+
await registerViaAppender(conn, name, records, schema, sourceHint);
|
|
175
|
+
}
|
|
176
|
+
finally {
|
|
177
|
+
// Release the connection — DuckDBConnection exposes closeSync(): void.
|
|
178
|
+
// Without this, every registerDf call leaks one connection over the
|
|
179
|
+
// lifetime of the scratchpad session.
|
|
180
|
+
conn.closeSync();
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
const journalScanner = new SecretScanner();
|
|
185
|
+
/**
|
|
186
|
+
* Scans `raw` for known secret patterns; for each hit, appends a
|
|
187
|
+
* `producer: 'secret-scanner', action: 'redact'` audit record (severity warn)
|
|
188
|
+
* with `detail = { cell_id, kind, offset, length }` — NEVER the secret value
|
|
189
|
+
* or `SecretHit.preview`. Returns the redacted text (`[REDACTED:<kind>]` per
|
|
190
|
+
* hit). If no hits, returns the input verbatim with no audit emission.
|
|
191
|
+
*
|
|
192
|
+
* Backward compatibility: callers that don't have an AuditLog should skip this
|
|
193
|
+
* helper entirely (pass-through). Audit is required here because the redaction
|
|
194
|
+
* MUST be observable.
|
|
195
|
+
*/
|
|
196
|
+
export function redactForJournal(raw, ctx) {
|
|
197
|
+
const hits = journalScanner.scan(raw);
|
|
198
|
+
if (hits.length === 0)
|
|
199
|
+
return raw;
|
|
200
|
+
const ts = new Date().toISOString();
|
|
201
|
+
for (const h of hits) {
|
|
202
|
+
ctx.audit.append({
|
|
203
|
+
_schema: 1,
|
|
204
|
+
ts,
|
|
205
|
+
producer: 'secret-scanner',
|
|
206
|
+
action: 'redact',
|
|
207
|
+
severity: 'warn',
|
|
208
|
+
sessionId: ctx.sessionId,
|
|
209
|
+
scratchpadName: ctx.scratchpadName,
|
|
210
|
+
pid: ctx.pid,
|
|
211
|
+
detail: {
|
|
212
|
+
cell_id: ctx.cellId,
|
|
213
|
+
kind: h.kind,
|
|
214
|
+
offset: h.start,
|
|
215
|
+
length: h.end - h.start,
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
return journalScanner.redact(raw);
|
|
220
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
import process, { argv, stdin, stdout } from 'node:process';
|
|
2
|
+
import vm from 'node:vm';
|
|
3
|
+
import { existsSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { DuckDBInstance } from '@duckdb/node-api';
|
|
6
|
+
import { writeNdjson, readNdjson } from '@otto/coworker-utils';
|
|
7
|
+
import { DefaultCollectorRegistry } from './collector-registry.js';
|
|
8
|
+
import { FileCollector } from './file-collector.js';
|
|
9
|
+
import { isKernelRpcResponse } from './kernel-protocol.js';
|
|
10
|
+
import { buildDataLibBindings, attachRegisterDf } from './kernel-bindings.js';
|
|
11
|
+
import { encodeNamespace, decodeNamespace } from './namespace-codec.js';
|
|
12
|
+
const workspace = argv[2] ?? process.cwd();
|
|
13
|
+
const scratchpadDir = argv[3];
|
|
14
|
+
const trace = process.env.OTTO_SCRATCHPAD_IPC_TRACE === '1';
|
|
15
|
+
const KNOWN_BOUND_KEYS = new Set([
|
|
16
|
+
'otto',
|
|
17
|
+
'console',
|
|
18
|
+
'progress',
|
|
19
|
+
'setTimeout',
|
|
20
|
+
'clearTimeout',
|
|
21
|
+
'setInterval',
|
|
22
|
+
'clearInterval',
|
|
23
|
+
'polars',
|
|
24
|
+
'DuckDB',
|
|
25
|
+
'ExcelJS',
|
|
26
|
+
'dateFns',
|
|
27
|
+
'lodash',
|
|
28
|
+
'zod',
|
|
29
|
+
'axios',
|
|
30
|
+
'Date',
|
|
31
|
+
// Phase 2 Task 13: process is bound so cells can read OTTO_DS_* env vars
|
|
32
|
+
// injected by CredentialInjector. Filtered from namespace snapshots.
|
|
33
|
+
'process',
|
|
34
|
+
'Buffer',
|
|
35
|
+
]);
|
|
36
|
+
const registry = new DefaultCollectorRegistry();
|
|
37
|
+
registry.register(new FileCollector({ workspace }));
|
|
38
|
+
process.on('SIGINT', () => {
|
|
39
|
+
// Ignored on purpose. A stray cancel between cells must not tear down a healthy
|
|
40
|
+
// kernel; the parent escalates to SIGTERM/SIGKILL to actually stop a hung kernel.
|
|
41
|
+
});
|
|
42
|
+
function send(frame) {
|
|
43
|
+
if (trace)
|
|
44
|
+
process.stderr.write(`[kernel→] ${JSON.stringify(frame)}\n`);
|
|
45
|
+
void writeNdjson(stdout, frame);
|
|
46
|
+
}
|
|
47
|
+
const pendingRpc = new Map();
|
|
48
|
+
let nextRpcId = 1;
|
|
49
|
+
function newRpcId() {
|
|
50
|
+
return `art-${process.pid}-${nextRpcId++}`;
|
|
51
|
+
}
|
|
52
|
+
function rpcRequest(payload) {
|
|
53
|
+
return new Promise((resolve, reject) => {
|
|
54
|
+
pendingRpc.set(payload.id, {
|
|
55
|
+
resolve: resolve,
|
|
56
|
+
reject,
|
|
57
|
+
});
|
|
58
|
+
send(payload);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
// Returns true when the frame was consumed as an RPC response.
|
|
62
|
+
function tryRouteRpcResponse(frame) {
|
|
63
|
+
if (!isKernelRpcResponse(frame))
|
|
64
|
+
return false;
|
|
65
|
+
const p = pendingRpc.get(frame.id);
|
|
66
|
+
if (!p)
|
|
67
|
+
return true; // unknown id — silently drop; nothing to do
|
|
68
|
+
pendingRpc.delete(frame.id);
|
|
69
|
+
if (frame.ok === false)
|
|
70
|
+
p.reject(new Error(frame.error));
|
|
71
|
+
else
|
|
72
|
+
p.resolve(frame);
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
const ottoCollectors = {
|
|
76
|
+
async list() {
|
|
77
|
+
const refs = [];
|
|
78
|
+
for (const collector of registry.list()) {
|
|
79
|
+
for await (const ref of collector.list())
|
|
80
|
+
refs.push(ref);
|
|
81
|
+
}
|
|
82
|
+
return refs;
|
|
83
|
+
},
|
|
84
|
+
async open(uri) {
|
|
85
|
+
const hit = await registry.resolve(uri);
|
|
86
|
+
if (!hit)
|
|
87
|
+
throw new Error(`no collector resolves uri: ${uri}`);
|
|
88
|
+
const source = await hit.collector.open(hit.ref);
|
|
89
|
+
return {
|
|
90
|
+
ref: source.ref,
|
|
91
|
+
async load() {
|
|
92
|
+
const value = await source.load();
|
|
93
|
+
send({
|
|
94
|
+
type: 'event',
|
|
95
|
+
event: 'data_load',
|
|
96
|
+
drawer: {
|
|
97
|
+
kind: 'data_load',
|
|
98
|
+
collector: source.ref.collector,
|
|
99
|
+
uri: source.ref.uri,
|
|
100
|
+
bytes: source.ref.bytes ?? null,
|
|
101
|
+
rows_loaded: Array.isArray(value) ? value.length : null,
|
|
102
|
+
loaded_at: new Date().toISOString(),
|
|
103
|
+
schema: null,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
return value;
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
function makeArtifactProxy(args) {
|
|
112
|
+
return {
|
|
113
|
+
slug: args.slug,
|
|
114
|
+
uri: args.uri,
|
|
115
|
+
primaryPath: args.primaryPath,
|
|
116
|
+
async update(files) {
|
|
117
|
+
const req = {
|
|
118
|
+
type: 'request',
|
|
119
|
+
request: 'artifact_update',
|
|
120
|
+
id: newRpcId(),
|
|
121
|
+
slug: args.slug,
|
|
122
|
+
files,
|
|
123
|
+
};
|
|
124
|
+
const resp = await rpcRequest(req);
|
|
125
|
+
if (resp.ok === false)
|
|
126
|
+
throw new Error(`artifact_update failed: ${resp.error}`);
|
|
127
|
+
return { files_touched: resp.files_touched };
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
const ottoArtifact = {
|
|
132
|
+
async create(kind, name) {
|
|
133
|
+
if (kind !== 'report') {
|
|
134
|
+
throw new Error(`unsupported artifact kind: ${kind}. v1 ships only 'report'.`);
|
|
135
|
+
}
|
|
136
|
+
const req = {
|
|
137
|
+
type: 'request',
|
|
138
|
+
request: 'artifact_create',
|
|
139
|
+
id: newRpcId(),
|
|
140
|
+
kind,
|
|
141
|
+
name,
|
|
142
|
+
};
|
|
143
|
+
const resp = await rpcRequest(req);
|
|
144
|
+
if (resp.ok === false)
|
|
145
|
+
throw new Error(`artifact_create failed: ${resp.error}`);
|
|
146
|
+
// Broadcast artifact_create event so the manager can call recordArtifact
|
|
147
|
+
// into memory (Phase 4 Task 12 closure: getMemoryRecorder()?.recordArtifact).
|
|
148
|
+
// Without this, Layer B is silent for artifacts.
|
|
149
|
+
send({
|
|
150
|
+
type: 'event',
|
|
151
|
+
event: 'artifact_create',
|
|
152
|
+
drawer: {
|
|
153
|
+
kind: 'artifact',
|
|
154
|
+
slug: resp.slug,
|
|
155
|
+
artifact_kind: kind,
|
|
156
|
+
uri: resp.uri,
|
|
157
|
+
primary_path: resp.primary_path,
|
|
158
|
+
created_at: new Date().toISOString(),
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
return makeArtifactProxy({
|
|
162
|
+
slug: resp.slug,
|
|
163
|
+
uri: resp.uri,
|
|
164
|
+
primaryPath: resp.primary_path,
|
|
165
|
+
});
|
|
166
|
+
},
|
|
167
|
+
async spillIfLarge(value, opts) {
|
|
168
|
+
const threshold = opts?.thresholdBytes ?? 10_240;
|
|
169
|
+
let serialized;
|
|
170
|
+
try {
|
|
171
|
+
serialized = typeof value === 'string' ? value : JSON.stringify(value, null, 2);
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
serialized = String(value);
|
|
175
|
+
}
|
|
176
|
+
if (Buffer.byteLength(serialized, 'utf8') < threshold)
|
|
177
|
+
return null;
|
|
178
|
+
const name = opts?.name ??
|
|
179
|
+
`cell-output-${new Date().toISOString().slice(0, 19).replace(/[T:]/g, '-')}`;
|
|
180
|
+
const handle = await ottoArtifact.create('report', name);
|
|
181
|
+
await handle.update([{ path: 'report.md', content: serialized }]);
|
|
182
|
+
return handle;
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
const otto = { collectors: ottoCollectors, artifact: ottoArtifact };
|
|
186
|
+
const sandbox = {
|
|
187
|
+
otto,
|
|
188
|
+
...buildDataLibBindings(),
|
|
189
|
+
// Timers are not part of a fresh vm context; bind the host ones so async cells
|
|
190
|
+
// (await new Promise((r) => setTimeout(r, ...))) and progress() heartbeats work.
|
|
191
|
+
setTimeout,
|
|
192
|
+
clearTimeout,
|
|
193
|
+
setInterval,
|
|
194
|
+
clearInterval,
|
|
195
|
+
// Bind the host Date so that v8-deserialized Date objects (from namespace restore)
|
|
196
|
+
// pass `instanceof Date` checks inside the vm context (cross-realm fix).
|
|
197
|
+
Date,
|
|
198
|
+
// Phase 2 Task 13: cells need process.env to read OTTO_DS_* vault-injected
|
|
199
|
+
// env vars. Bind the host process directly; vm sandbox isolation otherwise
|
|
200
|
+
// hides Node globals. Buffer is bound alongside since cells frequently
|
|
201
|
+
// base64-encode credentials (e.g. Basic auth from env vars).
|
|
202
|
+
process,
|
|
203
|
+
Buffer,
|
|
204
|
+
};
|
|
205
|
+
const context = vm.createContext(sandbox);
|
|
206
|
+
async function runCell(code) {
|
|
207
|
+
const logs = [];
|
|
208
|
+
sandbox.console = {
|
|
209
|
+
log: (...args) => logs.push(args.map((a) => String(a)).join(' ')),
|
|
210
|
+
error: (...args) => logs.push(args.map((a) => String(a)).join(' ')),
|
|
211
|
+
};
|
|
212
|
+
sandbox.progress = (message) => {
|
|
213
|
+
send({
|
|
214
|
+
type: 'event',
|
|
215
|
+
event: 'progress',
|
|
216
|
+
message: message === undefined ? undefined : String(message),
|
|
217
|
+
});
|
|
218
|
+
};
|
|
219
|
+
const wrapped = `(async () => {\n${code}\n})()`;
|
|
220
|
+
const value = await vm.runInContext(wrapped, context, { filename: 'cell.js' });
|
|
221
|
+
return { value, stdout: logs.join('\n') };
|
|
222
|
+
}
|
|
223
|
+
function toSerializable(value) {
|
|
224
|
+
try {
|
|
225
|
+
return JSON.parse(JSON.stringify(value ?? null));
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
return { valuePreview: String(value) };
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
async function openKernelDb(dir) {
|
|
232
|
+
try {
|
|
233
|
+
const instance = await DuckDBInstance.create(join(dir, 'kernel.db'));
|
|
234
|
+
attachRegisterDf(instance);
|
|
235
|
+
otto.duckdb = instance;
|
|
236
|
+
}
|
|
237
|
+
catch (err) {
|
|
238
|
+
const e = err;
|
|
239
|
+
await writeNdjson(stdout, {
|
|
240
|
+
type: 'event',
|
|
241
|
+
event: 'startup_error',
|
|
242
|
+
kind: 'duckdb_open',
|
|
243
|
+
error: { name: e.name, message: e.message },
|
|
244
|
+
});
|
|
245
|
+
process.exit(1);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
function restoreNamespace(dir) {
|
|
249
|
+
const path = join(dir, 'namespace.json');
|
|
250
|
+
if (!existsSync(path))
|
|
251
|
+
return [{ kind: 'namespace-absent' }];
|
|
252
|
+
let raw;
|
|
253
|
+
try {
|
|
254
|
+
raw = readFileSync(path, 'utf8');
|
|
255
|
+
}
|
|
256
|
+
catch (err) {
|
|
257
|
+
return [{ kind: 'namespace-corrupt', message: err.message }];
|
|
258
|
+
}
|
|
259
|
+
try {
|
|
260
|
+
const { values } = decodeNamespace(raw);
|
|
261
|
+
for (const key of Object.keys(values)) {
|
|
262
|
+
if (KNOWN_BOUND_KEYS.has(key))
|
|
263
|
+
continue; // never let a tampered namespace.json overwrite host bindings
|
|
264
|
+
sandbox[key] = values[key];
|
|
265
|
+
}
|
|
266
|
+
return [];
|
|
267
|
+
}
|
|
268
|
+
catch (err) {
|
|
269
|
+
return [{ kind: 'namespace-corrupt', message: err.message }];
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
function writeNamespaceSnapshot(dir) {
|
|
273
|
+
// Enumerate live globalThis additions, excluding the known-bound surface.
|
|
274
|
+
const live = {};
|
|
275
|
+
for (const key of Object.keys(sandbox)) {
|
|
276
|
+
if (KNOWN_BOUND_KEYS.has(key))
|
|
277
|
+
continue;
|
|
278
|
+
live[key] = sandbox[key];
|
|
279
|
+
}
|
|
280
|
+
const { envelope, skipped } = encodeNamespace(live, () => Date.now());
|
|
281
|
+
const nsPath = join(dir, 'namespace.json');
|
|
282
|
+
const tmp = `${nsPath}.tmp`;
|
|
283
|
+
writeFileSync(tmp, JSON.stringify(envelope));
|
|
284
|
+
renameSync(tmp, nsPath);
|
|
285
|
+
return { skipped, snapshotted_at: envelope.ts };
|
|
286
|
+
}
|
|
287
|
+
async function main() {
|
|
288
|
+
const recoveryNotes = [];
|
|
289
|
+
if (scratchpadDir !== undefined) {
|
|
290
|
+
await openKernelDb(scratchpadDir);
|
|
291
|
+
recoveryNotes.push(...restoreNamespace(scratchpadDir));
|
|
292
|
+
}
|
|
293
|
+
send({ type: 'event', event: 'ready', recovery_notes: recoveryNotes });
|
|
294
|
+
try {
|
|
295
|
+
for await (const raw of readNdjson(stdin)) {
|
|
296
|
+
if (trace)
|
|
297
|
+
process.stderr.write(`[kernel←] ${JSON.stringify(raw)}\n`);
|
|
298
|
+
// Phase 4 Task 9 — route artifact RPC responses to the pending map before
|
|
299
|
+
// falling through to the existing run/snapshot request dispatch.
|
|
300
|
+
if (tryRouteRpcResponse(raw))
|
|
301
|
+
continue;
|
|
302
|
+
const req = raw;
|
|
303
|
+
if (req.type === 'snapshot') {
|
|
304
|
+
if (scratchpadDir === undefined) {
|
|
305
|
+
send({ id: req.id, type: 'snapshot_result', ok: true, skipped: [], snapshotted_at: new Date().toISOString() });
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
try {
|
|
309
|
+
const { skipped, snapshotted_at } = writeNamespaceSnapshot(scratchpadDir);
|
|
310
|
+
send({ id: req.id, type: 'snapshot_result', ok: true, skipped, snapshotted_at });
|
|
311
|
+
}
|
|
312
|
+
catch (err) {
|
|
313
|
+
const e = err;
|
|
314
|
+
send({ id: req.id, type: 'snapshot_result', ok: false, error: { name: e.name, message: e.message } });
|
|
315
|
+
}
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
if (req.type !== 'run')
|
|
319
|
+
continue;
|
|
320
|
+
// Phase 4 Task 10 fix — `runCell` may issue an artifact RPC and await its
|
|
321
|
+
// response. The response arrives over stdin, which means the main loop
|
|
322
|
+
// MUST keep iterating to route it via tryRouteRpcResponse. Awaiting
|
|
323
|
+
// runCell inline would deadlock the kernel against its own RPC. Fire it
|
|
324
|
+
// off; runCell sends its own result frame. The manager already serializes
|
|
325
|
+
// cell submissions, so there's no concurrency to worry about.
|
|
326
|
+
void (async () => {
|
|
327
|
+
let res;
|
|
328
|
+
try {
|
|
329
|
+
const { value, stdout: out } = await runCell(req.code);
|
|
330
|
+
res = { id: req.id, type: 'result', ok: true, value: toSerializable(value), stdout: out };
|
|
331
|
+
}
|
|
332
|
+
catch (err) {
|
|
333
|
+
const e = err;
|
|
334
|
+
res = {
|
|
335
|
+
id: req.id,
|
|
336
|
+
type: 'result',
|
|
337
|
+
ok: false,
|
|
338
|
+
error: { name: e.name, message: e.message, stack: e.stack },
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
send(res);
|
|
342
|
+
})();
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
finally {
|
|
346
|
+
// Phase 4 Task 9 review fix — if stdin closes (manager died / EOF) while
|
|
347
|
+
// RPCs are still in flight, reject them so awaiting cells fail fast
|
|
348
|
+
// instead of hanging until SIGKILL.
|
|
349
|
+
for (const [, p] of pendingRpc) {
|
|
350
|
+
p.reject(new Error('kernel: stdin closed with pending RPC'));
|
|
351
|
+
}
|
|
352
|
+
pendingRpc.clear();
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
void main();
|