@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,427 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import process from 'node:process';
|
|
3
|
+
import { writeNdjson, readNdjson } from '@otto/coworker-utils';
|
|
4
|
+
import { filterEnv, kernelExecArgv, resolveKernelEntry } from './kernel-spawn.js';
|
|
5
|
+
import { isDataLoadEvent, isProgressEvent, isStartupErrorEvent, isSnapshotResult, isArtifactCreateEvent, isArtifactCreateRequest, isArtifactUpdateRequest, } from './kernel-protocol.js';
|
|
6
|
+
const DEFAULT_CELL_TIMEOUT_MS = 120_000;
|
|
7
|
+
const DEFAULT_INACTIVITY_MS = 30_000;
|
|
8
|
+
const DEFAULT_INACTIVITY_AFTER_PROGRESS_MS = 60_000;
|
|
9
|
+
const DEFAULT_CANCEL_GRACE_MS = 2_000;
|
|
10
|
+
const MAX_RESTARTS_BEFORE_SUCCESS = 1;
|
|
11
|
+
export class ChildProcessRuntime {
|
|
12
|
+
options;
|
|
13
|
+
child = null;
|
|
14
|
+
pending = new Map();
|
|
15
|
+
pendingSnapshots = new Map();
|
|
16
|
+
activeId = null;
|
|
17
|
+
nextId = 1;
|
|
18
|
+
alive = false;
|
|
19
|
+
childReady = false;
|
|
20
|
+
disposed = false;
|
|
21
|
+
restartsSinceSuccess = 0;
|
|
22
|
+
recoveryNotes_ = [];
|
|
23
|
+
resolveReady = () => { };
|
|
24
|
+
rejectReady = () => { };
|
|
25
|
+
ready = Promise.resolve();
|
|
26
|
+
/**
|
|
27
|
+
* Phase 2 Task 13: timestamp of the most recent successful spawn(). Used by
|
|
28
|
+
* higher-level staleness checks (Task 15) to decide whether a warm kernel's
|
|
29
|
+
* env-injected credentials need to be refreshed. Pre-start() value is epoch
|
|
30
|
+
* so callers can distinguish "never spawned" without nullable juggling.
|
|
31
|
+
*/
|
|
32
|
+
spawnTime = new Date(0);
|
|
33
|
+
constructor(options) {
|
|
34
|
+
this.options = options;
|
|
35
|
+
}
|
|
36
|
+
async start() {
|
|
37
|
+
if (this.disposed)
|
|
38
|
+
throw new Error('runtime disposed');
|
|
39
|
+
await this.spawnChild();
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Phase 2 Task 13: env construction split out so the injector hop has a clean
|
|
43
|
+
* seam to extend. Existing semantics unchanged: filterEnv applies the kernel's
|
|
44
|
+
* allowlist/denylist, then (when configured) the injector overlays OTTO_DS_*
|
|
45
|
+
* vars from vault entries. Only the spawned child sees the result; the parent
|
|
46
|
+
* process.env is never mutated.
|
|
47
|
+
*/
|
|
48
|
+
async buildBaseEnv() {
|
|
49
|
+
const base = filterEnv(process.env);
|
|
50
|
+
const { injector, bindings } = this.options;
|
|
51
|
+
if (!injector || !bindings || bindings.length === 0)
|
|
52
|
+
return base;
|
|
53
|
+
return injector.injectEnv(base, bindings, {
|
|
54
|
+
scratchpadName: this.options.scratchpadName ?? '',
|
|
55
|
+
sessionId: this.options.sessionId ?? '',
|
|
56
|
+
pid: process.pid,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
async spawnChild() {
|
|
60
|
+
this.ready = new Promise((resolve, reject) => {
|
|
61
|
+
this.resolveReady = resolve;
|
|
62
|
+
this.rejectReady = reject;
|
|
63
|
+
});
|
|
64
|
+
const entry = this.options.entryPath ?? resolveKernelEntry();
|
|
65
|
+
const args = [...kernelExecArgv(), entry, this.options.workspace];
|
|
66
|
+
if (this.options.scratchpadDir !== undefined)
|
|
67
|
+
args.push(this.options.scratchpadDir);
|
|
68
|
+
const env = await this.buildBaseEnv();
|
|
69
|
+
const child = spawn(process.execPath, args, { stdio: ['pipe', 'pipe', 'inherit'], cwd: process.cwd(), env });
|
|
70
|
+
this.child = child;
|
|
71
|
+
this.alive = true;
|
|
72
|
+
this.childReady = false;
|
|
73
|
+
// Phase 2 Task 13: stamp spawnTime immediately after a successful spawn.
|
|
74
|
+
// Done synchronously so the ready promise (which the caller awaits) reflects
|
|
75
|
+
// a non-epoch spawnTime by the time start() returns.
|
|
76
|
+
this.spawnTime = new Date();
|
|
77
|
+
child.on('exit', (code, signal) => {
|
|
78
|
+
if (this.child !== child)
|
|
79
|
+
return; // superseded by a restart
|
|
80
|
+
this.alive = false;
|
|
81
|
+
this.childReady = false;
|
|
82
|
+
if (this.disposed)
|
|
83
|
+
return;
|
|
84
|
+
const err = new Error(`kernel exited (code=${code ?? 'null'}, signal=${signal ?? 'null'})`);
|
|
85
|
+
this.rejectReady(err); // no-op if ready already resolved
|
|
86
|
+
this.failAllPending(err);
|
|
87
|
+
});
|
|
88
|
+
void this.readLoop(child);
|
|
89
|
+
return this.ready;
|
|
90
|
+
}
|
|
91
|
+
async readLoop(child) {
|
|
92
|
+
try {
|
|
93
|
+
for await (const raw of readNdjson(child.stdout)) {
|
|
94
|
+
if (this.child !== child)
|
|
95
|
+
break; // superseded by a restart
|
|
96
|
+
const frame = raw;
|
|
97
|
+
if (frame.type === 'event') {
|
|
98
|
+
if (frame.event === 'ready') {
|
|
99
|
+
if (frame.recovery_notes)
|
|
100
|
+
this.recoveryNotes_ = [...frame.recovery_notes];
|
|
101
|
+
this.childReady = true;
|
|
102
|
+
this.resolveReady();
|
|
103
|
+
}
|
|
104
|
+
else if (isStartupErrorEvent(frame)) {
|
|
105
|
+
const err = new Error(frame.error.message);
|
|
106
|
+
err.name = `startup_error/${frame.kind}`;
|
|
107
|
+
this.rejectReady(err);
|
|
108
|
+
}
|
|
109
|
+
else if (isDataLoadEvent(frame))
|
|
110
|
+
this.options.onDataLoad?.(frame.drawer);
|
|
111
|
+
else if (isArtifactCreateEvent(frame))
|
|
112
|
+
this.options.onArtifactCreate?.(frame.drawer);
|
|
113
|
+
else if (isProgressEvent(frame))
|
|
114
|
+
this.resetInactivity();
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (isSnapshotResult(frame)) {
|
|
118
|
+
const resolver = this.pendingSnapshots.get(frame.id);
|
|
119
|
+
if (resolver) {
|
|
120
|
+
this.pendingSnapshots.delete(frame.id);
|
|
121
|
+
resolver(frame);
|
|
122
|
+
}
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
// Phase 4 Task 10: artifact RPC requests originate from the kernel and
|
|
126
|
+
// are serviced by the manager via handleArtifactCreate/Update. Handle
|
|
127
|
+
// before the result-fallthrough — these frames carry a string `id`
|
|
128
|
+
// (kernel mints `art-<pid>-<seq>`) and would otherwise be miskeyed
|
|
129
|
+
// against the numeric `pending` map.
|
|
130
|
+
if (isArtifactCreateRequest(frame)) {
|
|
131
|
+
void this.handleArtifactCreateRpc(frame);
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (isArtifactUpdateRequest(frame)) {
|
|
135
|
+
void this.handleArtifactUpdateRpc(frame);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (frame.type !== 'result')
|
|
139
|
+
continue; // defensive: unknown frame shape
|
|
140
|
+
const p = this.pending.get(frame.id);
|
|
141
|
+
if (!p)
|
|
142
|
+
continue;
|
|
143
|
+
clearTimeout(p.totalTimer);
|
|
144
|
+
clearTimeout(p.inactivityTimer);
|
|
145
|
+
this.pending.delete(frame.id);
|
|
146
|
+
if (this.activeId === frame.id)
|
|
147
|
+
this.activeId = null;
|
|
148
|
+
this.restartsSinceSuccess = 0; // a completed cell proves the kernel is healthy
|
|
149
|
+
if (frame.ok) {
|
|
150
|
+
p.resolve({ value: frame.value, stdout: frame.stdout });
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
const err = new Error(frame.error.message);
|
|
154
|
+
err.name = frame.error.name;
|
|
155
|
+
if (frame.error.stack)
|
|
156
|
+
err.stack = frame.error.stack;
|
|
157
|
+
p.reject(err);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
this.failAllPending(err);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
resetInactivity() {
|
|
166
|
+
if (this.activeId === null)
|
|
167
|
+
return;
|
|
168
|
+
const id = this.activeId;
|
|
169
|
+
const p = this.pending.get(id);
|
|
170
|
+
if (!p)
|
|
171
|
+
return;
|
|
172
|
+
p.inactivityWindowMs =
|
|
173
|
+
this.options.inactivityAfterProgressMs ?? DEFAULT_INACTIVITY_AFTER_PROGRESS_MS;
|
|
174
|
+
clearTimeout(p.inactivityTimer);
|
|
175
|
+
p.inactivityTimer = setTimeout(() => this.onInactivityTimeout(id), p.inactivityWindowMs);
|
|
176
|
+
}
|
|
177
|
+
onInactivityTimeout(id) {
|
|
178
|
+
const p = this.pending.get(id);
|
|
179
|
+
if (!p)
|
|
180
|
+
return;
|
|
181
|
+
clearTimeout(p.totalTimer);
|
|
182
|
+
this.pending.delete(id);
|
|
183
|
+
if (this.activeId === id)
|
|
184
|
+
this.activeId = null;
|
|
185
|
+
this.markDead();
|
|
186
|
+
p.reject(new Error(`cell ${id} timed out after ${p.inactivityWindowMs}ms of inactivity`));
|
|
187
|
+
}
|
|
188
|
+
onTotalTimeout(id, totalMs) {
|
|
189
|
+
const p = this.pending.get(id);
|
|
190
|
+
if (!p)
|
|
191
|
+
return;
|
|
192
|
+
clearTimeout(p.inactivityTimer);
|
|
193
|
+
this.pending.delete(id);
|
|
194
|
+
if (this.activeId === id)
|
|
195
|
+
this.activeId = null;
|
|
196
|
+
this.markDead();
|
|
197
|
+
p.reject(new Error(`cell ${id} timed out after ${totalMs}ms (total wall-clock)`));
|
|
198
|
+
}
|
|
199
|
+
async runCell(code) {
|
|
200
|
+
if (this.disposed)
|
|
201
|
+
throw new Error('runtime disposed');
|
|
202
|
+
if (!this.alive) {
|
|
203
|
+
if (this.restartsSinceSuccess >= MAX_RESTARTS_BEFORE_SUCCESS) {
|
|
204
|
+
throw new Error(`kernel repeatedly crashed (${this.restartsSinceSuccess} restart(s) without a successful cell); giving up`);
|
|
205
|
+
}
|
|
206
|
+
this.restartsSinceSuccess++;
|
|
207
|
+
this.spawnChild(); // start a fresh kernel; the write below waits for its ready
|
|
208
|
+
}
|
|
209
|
+
const id = this.nextId++;
|
|
210
|
+
const totalMs = this.options.cellTimeoutMs ?? DEFAULT_CELL_TIMEOUT_MS;
|
|
211
|
+
const inactivityMs = this.options.inactivityTimeoutMs ?? DEFAULT_INACTIVITY_MS;
|
|
212
|
+
const result = new Promise((resolve, reject) => {
|
|
213
|
+
const totalTimer = setTimeout(() => this.onTotalTimeout(id, totalMs), totalMs);
|
|
214
|
+
const inactivityTimer = setTimeout(() => this.onInactivityTimeout(id), inactivityMs);
|
|
215
|
+
this.pending.set(id, { resolve, reject, totalTimer, inactivityTimer, inactivityWindowMs: inactivityMs });
|
|
216
|
+
});
|
|
217
|
+
// Register the active cell synchronously so cancel()/timeouts can act on it even
|
|
218
|
+
// while a restarted kernel is still starting up. Send the code once it's ready.
|
|
219
|
+
this.activeId = id;
|
|
220
|
+
const ready = this.ready;
|
|
221
|
+
void ready
|
|
222
|
+
.then(() => {
|
|
223
|
+
const child = this.child;
|
|
224
|
+
if (child && this.pending.has(id))
|
|
225
|
+
return writeNdjson(child.stdin, { id, type: 'run', code });
|
|
226
|
+
})
|
|
227
|
+
.catch(() => {
|
|
228
|
+
// ready rejected (kernel died during startup); the exit handler/cancel rejects this cell.
|
|
229
|
+
});
|
|
230
|
+
return result;
|
|
231
|
+
}
|
|
232
|
+
async cancel() {
|
|
233
|
+
const child = this.child;
|
|
234
|
+
if (!child || !this.alive)
|
|
235
|
+
return;
|
|
236
|
+
const id = this.activeId;
|
|
237
|
+
if (!this.childReady) {
|
|
238
|
+
// The kernel is still starting (e.g. a fresh restart). SIGINT would race the
|
|
239
|
+
// child's SIG_IGN handler install and could kill it before it's installed, so
|
|
240
|
+
// escalate straight to a hard kill and reject the active cell as cancelled.
|
|
241
|
+
this.rejectActive(id, `cell ${id} cancelled`);
|
|
242
|
+
this.markDead();
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
child.kill('SIGINT'); // child ignores SIGINT between cells; no-op for sync vm code mid-cell
|
|
246
|
+
if (id === null)
|
|
247
|
+
return; // nothing running: the gentle signal is harmless
|
|
248
|
+
await new Promise((r) => setTimeout(r, this.options.cancelGraceMs ?? DEFAULT_CANCEL_GRACE_MS));
|
|
249
|
+
const p = this.pending.get(id);
|
|
250
|
+
if (!p)
|
|
251
|
+
return; // settled within the grace window
|
|
252
|
+
clearTimeout(p.totalTimer);
|
|
253
|
+
clearTimeout(p.inactivityTimer);
|
|
254
|
+
this.pending.delete(id);
|
|
255
|
+
if (this.activeId === id)
|
|
256
|
+
this.activeId = null;
|
|
257
|
+
this.markDead(); // escalate: SIGTERM -> SIGKILL
|
|
258
|
+
p.reject(new Error(`cell ${id} cancelled`));
|
|
259
|
+
}
|
|
260
|
+
async snapshot() {
|
|
261
|
+
if (this.disposed) {
|
|
262
|
+
return { id: 0, type: 'snapshot_result', ok: false, error: { name: 'RuntimeDisposed', message: 'runtime disposed' } };
|
|
263
|
+
}
|
|
264
|
+
if (!this.alive || !this.child) {
|
|
265
|
+
return { id: 0, type: 'snapshot_result', ok: false, error: { name: 'RuntimeDead', message: 'kernel is not alive' } };
|
|
266
|
+
}
|
|
267
|
+
const id = this.nextId++;
|
|
268
|
+
const result = new Promise((resolve) => {
|
|
269
|
+
this.pendingSnapshots.set(id, resolve);
|
|
270
|
+
});
|
|
271
|
+
try {
|
|
272
|
+
await this.ready;
|
|
273
|
+
const child = this.child;
|
|
274
|
+
if (!child) {
|
|
275
|
+
this.pendingSnapshots.delete(id);
|
|
276
|
+
return { id, type: 'snapshot_result', ok: false, error: { name: 'RuntimeDead', message: 'kernel died before snapshot' } };
|
|
277
|
+
}
|
|
278
|
+
await writeNdjson(child.stdin, { id, type: 'snapshot' });
|
|
279
|
+
}
|
|
280
|
+
catch (err) {
|
|
281
|
+
this.pendingSnapshots.delete(id);
|
|
282
|
+
const e = err;
|
|
283
|
+
return { id, type: 'snapshot_result', ok: false, error: { name: e.name, message: e.message } };
|
|
284
|
+
}
|
|
285
|
+
return result;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Phase 4 Task 10: service an `artifact_create` RPC request from the kernel.
|
|
289
|
+
* Calls the manager-supplied handler (if any), serializes the result into a
|
|
290
|
+
* `{type:'response', request:'artifact_create'}` frame, and writes it back
|
|
291
|
+
* to the child's stdin. Errors are surfaced to the kernel as `ok:false`
|
|
292
|
+
* frames so the awaiting cell rejects cleanly rather than hanging.
|
|
293
|
+
*/
|
|
294
|
+
async handleArtifactCreateRpc(req) {
|
|
295
|
+
const child = this.child;
|
|
296
|
+
if (!child)
|
|
297
|
+
return;
|
|
298
|
+
let resp;
|
|
299
|
+
try {
|
|
300
|
+
const handler = this.options.handleArtifactCreate;
|
|
301
|
+
if (!handler)
|
|
302
|
+
throw new Error('artifacts unavailable');
|
|
303
|
+
const result = await handler({ kind: req.kind, name: req.name });
|
|
304
|
+
resp = {
|
|
305
|
+
type: 'response',
|
|
306
|
+
request: 'artifact_create',
|
|
307
|
+
id: req.id,
|
|
308
|
+
ok: true,
|
|
309
|
+
slug: result.slug,
|
|
310
|
+
uri: result.uri,
|
|
311
|
+
primary_path: result.primary_path,
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
catch (err) {
|
|
315
|
+
const e = err;
|
|
316
|
+
resp = {
|
|
317
|
+
type: 'response',
|
|
318
|
+
request: 'artifact_create',
|
|
319
|
+
id: req.id,
|
|
320
|
+
ok: false,
|
|
321
|
+
error: e.message,
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
try {
|
|
325
|
+
await writeNdjson(child.stdin, resp);
|
|
326
|
+
}
|
|
327
|
+
catch {
|
|
328
|
+
// child died between request and response — exit handler fails pending cells.
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Phase 4 Task 10: service an `artifact_update` RPC request. Mirror of
|
|
333
|
+
* handleArtifactCreateRpc for the update path.
|
|
334
|
+
*/
|
|
335
|
+
async handleArtifactUpdateRpc(req) {
|
|
336
|
+
const child = this.child;
|
|
337
|
+
if (!child)
|
|
338
|
+
return;
|
|
339
|
+
let resp;
|
|
340
|
+
try {
|
|
341
|
+
const handler = this.options.handleArtifactUpdate;
|
|
342
|
+
if (!handler)
|
|
343
|
+
throw new Error('artifacts unavailable');
|
|
344
|
+
const result = await handler({ slug: req.slug, files: req.files });
|
|
345
|
+
resp = {
|
|
346
|
+
type: 'response',
|
|
347
|
+
request: 'artifact_update',
|
|
348
|
+
id: req.id,
|
|
349
|
+
ok: true,
|
|
350
|
+
files_touched: result.files_touched,
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
catch (err) {
|
|
354
|
+
const e = err;
|
|
355
|
+
resp = {
|
|
356
|
+
type: 'response',
|
|
357
|
+
request: 'artifact_update',
|
|
358
|
+
id: req.id,
|
|
359
|
+
ok: false,
|
|
360
|
+
error: e.message,
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
try {
|
|
364
|
+
await writeNdjson(child.stdin, resp);
|
|
365
|
+
}
|
|
366
|
+
catch {
|
|
367
|
+
// child died between request and response — exit handler fails pending cells.
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
rejectActive(id, message) {
|
|
371
|
+
if (id === null)
|
|
372
|
+
return;
|
|
373
|
+
const p = this.pending.get(id);
|
|
374
|
+
if (!p)
|
|
375
|
+
return;
|
|
376
|
+
clearTimeout(p.totalTimer);
|
|
377
|
+
clearTimeout(p.inactivityTimer);
|
|
378
|
+
this.pending.delete(id);
|
|
379
|
+
if (this.activeId === id)
|
|
380
|
+
this.activeId = null;
|
|
381
|
+
p.reject(new Error(message));
|
|
382
|
+
}
|
|
383
|
+
failAllPending(err) {
|
|
384
|
+
for (const p of this.pending.values()) {
|
|
385
|
+
clearTimeout(p.totalTimer);
|
|
386
|
+
clearTimeout(p.inactivityTimer);
|
|
387
|
+
p.reject(err);
|
|
388
|
+
}
|
|
389
|
+
this.pending.clear();
|
|
390
|
+
this.activeId = null;
|
|
391
|
+
for (const resolve of this.pendingSnapshots.values()) {
|
|
392
|
+
resolve({ id: 0, type: 'snapshot_result', ok: false, error: { name: err.name, message: err.message } });
|
|
393
|
+
}
|
|
394
|
+
this.pendingSnapshots.clear();
|
|
395
|
+
}
|
|
396
|
+
markDead() {
|
|
397
|
+
const child = this.child;
|
|
398
|
+
if (!child)
|
|
399
|
+
return;
|
|
400
|
+
this.alive = false;
|
|
401
|
+
this.childReady = false;
|
|
402
|
+
child.kill('SIGTERM');
|
|
403
|
+
child.kill('SIGKILL');
|
|
404
|
+
// child stays referenced until its 'exit' fires; identity guards in readLoop/exit
|
|
405
|
+
// ignore the dead child once a restart reassigns this.child.
|
|
406
|
+
}
|
|
407
|
+
get hasActiveCell() {
|
|
408
|
+
return this.activeId !== null;
|
|
409
|
+
}
|
|
410
|
+
get recoveryNotes() {
|
|
411
|
+
return this.recoveryNotes_;
|
|
412
|
+
}
|
|
413
|
+
async dispose() {
|
|
414
|
+
if (this.disposed)
|
|
415
|
+
return;
|
|
416
|
+
this.disposed = true;
|
|
417
|
+
this.alive = false;
|
|
418
|
+
this.childReady = false;
|
|
419
|
+
this.failAllPending(new Error('runtime disposed'));
|
|
420
|
+
const child = this.child;
|
|
421
|
+
this.child = null;
|
|
422
|
+
if (child) {
|
|
423
|
+
child.stdin.end();
|
|
424
|
+
child.kill('SIGTERM');
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Collector, CollectorRegistry, DataSourceRef } from '@otto/coworker-types';
|
|
2
|
+
export declare function uriMatchesPattern(uri: string, pattern: string): boolean;
|
|
3
|
+
export declare class DefaultCollectorRegistry implements CollectorRegistry {
|
|
4
|
+
private readonly collectors;
|
|
5
|
+
register(collector: Collector): void;
|
|
6
|
+
list(): Collector[];
|
|
7
|
+
get(id: string): Collector | null;
|
|
8
|
+
resolve(uri: string): Promise<{
|
|
9
|
+
collector: Collector;
|
|
10
|
+
ref: DataSourceRef;
|
|
11
|
+
} | null>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export function uriMatchesPattern(uri, pattern) {
|
|
2
|
+
if (pattern.endsWith('*'))
|
|
3
|
+
return uri.startsWith(pattern.slice(0, -1));
|
|
4
|
+
return uri === pattern;
|
|
5
|
+
}
|
|
6
|
+
export class DefaultCollectorRegistry {
|
|
7
|
+
collectors = new Map();
|
|
8
|
+
register(collector) {
|
|
9
|
+
this.collectors.set(collector.id, collector);
|
|
10
|
+
}
|
|
11
|
+
list() {
|
|
12
|
+
return [...this.collectors.values()];
|
|
13
|
+
}
|
|
14
|
+
get(id) {
|
|
15
|
+
return this.collectors.get(id) ?? null;
|
|
16
|
+
}
|
|
17
|
+
async resolve(uri) {
|
|
18
|
+
for (const collector of this.collectors.values()) {
|
|
19
|
+
const patterns = collector.describe().supports_uris;
|
|
20
|
+
if (!patterns.some((p) => uriMatchesPattern(uri, p)))
|
|
21
|
+
continue;
|
|
22
|
+
for await (const ref of collector.list()) {
|
|
23
|
+
if (ref.uri === uri)
|
|
24
|
+
return { collector, ref };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const EXT_TO_KIND = {
|
|
2
|
+
'.csv': 'csv',
|
|
3
|
+
'.xlsx': 'xlsx',
|
|
4
|
+
'.json': 'json',
|
|
5
|
+
'.parquet': 'parquet',
|
|
6
|
+
'.txt': 'txt',
|
|
7
|
+
'.md': 'md',
|
|
8
|
+
};
|
|
9
|
+
// The six file kinds FileCollector enumerates. (DataKind also includes
|
|
10
|
+
// rest/mcp-resource/acp-stream, which belong to future non-file collectors.)
|
|
11
|
+
export const FILE_COLLECTOR_KINDS = ['csv', 'xlsx', 'json', 'parquet', 'txt', 'md'];
|
|
12
|
+
export function detectKind(pathOrUri) {
|
|
13
|
+
const clean = pathOrUri.split('?')[0].split('#')[0];
|
|
14
|
+
const dot = clean.lastIndexOf('.');
|
|
15
|
+
if (dot === -1)
|
|
16
|
+
return null;
|
|
17
|
+
const ext = clean.slice(dot).toLowerCase();
|
|
18
|
+
return EXT_TO_KIND[ext] ?? null;
|
|
19
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Collector, CollectorCapabilities, DataSource, DataSourceRef, ListOpts, Unsubscribe } from '@otto/coworker-types';
|
|
2
|
+
export interface FileCollectorOptions {
|
|
3
|
+
/** Absolute path to the workspace root. inputs/ resolves to <workspace>/.otto/inputs. */
|
|
4
|
+
workspace: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class FileCollector implements Collector {
|
|
7
|
+
readonly id = "file";
|
|
8
|
+
readonly kind: "file";
|
|
9
|
+
private readonly inputsDir;
|
|
10
|
+
constructor(opts: FileCollectorOptions);
|
|
11
|
+
describe(): CollectorCapabilities;
|
|
12
|
+
list(opts?: ListOpts): AsyncIterable<DataSourceRef>;
|
|
13
|
+
open(ref: DataSourceRef): Promise<DataSource>;
|
|
14
|
+
watch(ref: DataSourceRef, onChange: (ref: DataSourceRef) => void): Unsubscribe;
|
|
15
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { readdir, readFile, stat } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { pathToFileURL, fileURLToPath } from 'node:url';
|
|
4
|
+
import { watch as chokidarWatch } from 'chokidar';
|
|
5
|
+
import { detectKind, FILE_COLLECTOR_KINDS } from './detect-kind.js';
|
|
6
|
+
const TEXT_KINDS = new Set(['csv', 'txt', 'md']);
|
|
7
|
+
export class FileCollector {
|
|
8
|
+
id = 'file';
|
|
9
|
+
kind = 'file';
|
|
10
|
+
inputsDir;
|
|
11
|
+
constructor(opts) {
|
|
12
|
+
this.inputsDir = join(opts.workspace, '.otto', 'inputs');
|
|
13
|
+
}
|
|
14
|
+
describe() {
|
|
15
|
+
return {
|
|
16
|
+
supports_uris: ['file://*'],
|
|
17
|
+
supports_kinds: [...FILE_COLLECTOR_KINDS],
|
|
18
|
+
supports_streaming: false,
|
|
19
|
+
supports_watching: true,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
async *list(opts) {
|
|
23
|
+
let remaining = opts?.limit ?? Number.POSITIVE_INFINITY;
|
|
24
|
+
if (remaining <= 0)
|
|
25
|
+
return;
|
|
26
|
+
const prefixDir = opts?.prefix ? join(this.inputsDir, opts.prefix) : this.inputsDir;
|
|
27
|
+
for await (const abs of walk(this.inputsDir)) {
|
|
28
|
+
if (opts?.prefix && !abs.startsWith(prefixDir))
|
|
29
|
+
continue;
|
|
30
|
+
const kind = detectKind(abs);
|
|
31
|
+
if (!kind)
|
|
32
|
+
continue;
|
|
33
|
+
const st = await stat(abs);
|
|
34
|
+
yield {
|
|
35
|
+
collector: this.id,
|
|
36
|
+
uri: pathToFileURL(abs).href,
|
|
37
|
+
kind,
|
|
38
|
+
bytes: st.size,
|
|
39
|
+
modified: st.mtime.toISOString(),
|
|
40
|
+
metadata: {},
|
|
41
|
+
};
|
|
42
|
+
remaining -= 1;
|
|
43
|
+
if (remaining <= 0)
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async open(ref) {
|
|
48
|
+
const abs = fileURLToPath(ref.uri);
|
|
49
|
+
const kind = ref.kind;
|
|
50
|
+
return {
|
|
51
|
+
ref,
|
|
52
|
+
async load() {
|
|
53
|
+
if (kind === 'json') {
|
|
54
|
+
return JSON.parse(await readFile(abs, 'utf8'));
|
|
55
|
+
}
|
|
56
|
+
if (TEXT_KINDS.has(kind)) {
|
|
57
|
+
return readFile(abs, 'utf8');
|
|
58
|
+
}
|
|
59
|
+
return readFile(abs); // Buffer for xlsx/parquet
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
watch(ref, onChange) {
|
|
64
|
+
const abs = fileURLToPath(ref.uri);
|
|
65
|
+
const watcher = chokidarWatch(abs, { ignoreInitial: true });
|
|
66
|
+
const handler = async () => {
|
|
67
|
+
try {
|
|
68
|
+
const st = await stat(abs);
|
|
69
|
+
onChange({ ...ref, bytes: st.size, modified: st.mtime.toISOString() });
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
onChange(ref);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
watcher.on('change', () => void handler());
|
|
76
|
+
watcher.on('add', () => void handler());
|
|
77
|
+
return () => {
|
|
78
|
+
void watcher.close();
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async function* walk(dir) {
|
|
83
|
+
let entries;
|
|
84
|
+
try {
|
|
85
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return; // inputs/ may not exist yet — yield nothing
|
|
89
|
+
}
|
|
90
|
+
for (const entry of entries) {
|
|
91
|
+
const full = join(dir, entry.name);
|
|
92
|
+
if (entry.isDirectory()) {
|
|
93
|
+
yield* walk(full);
|
|
94
|
+
}
|
|
95
|
+
else if (entry.isFile()) {
|
|
96
|
+
yield full;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
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 { isDataLoadEvent, isProgressEvent, isStartupErrorEvent, isSnapshotResult, type RunRequest, type SnapshotRequest, type KernelRequest, type ResultOk, type ResultErr, type ResultResponse, type SnapshotResultOk, type SnapshotResultErr, type SnapshotResult, type SkippedKey, type RecoveryNote, type StartupErrorEvent, type DataLoadDrawer, type ArtifactCreateDrawer, type ReadyEvent, type DataLoadEvent, type ProgressEvent, type KernelEvent, type KernelFrame, } from './kernel-protocol.js';
|
|
5
|
+
export { filterEnv, kernelExecArgv, resolveKernelEntry } from './kernel-spawn.js';
|
|
6
|
+
export { ChildProcessRuntime, type CellResult, type ChildProcessRuntimeOptions, } from './child-process-runtime.js';
|
|
7
|
+
export { ScratchpadManager, ForkKernelHangError, type ScratchpadManagerOptions, type AttachOptions, type ScratchpadInfo, } from './scratchpad-manager.js';
|
|
8
|
+
export { acquireLock, releaseLock, readLock, isStaleLock, ScratchpadBusyError, type LockInfo, type AcquireOptions, } from './scratchpad-lock.js';
|
|
9
|
+
export { CellArchive, CELLS_SCHEMA_VERSION, type CellEntry, type AppendInput, } from './cell-archive.js';
|
|
10
|
+
export { buildDataLibBindings } from './kernel-bindings.js';
|
|
11
|
+
export { NAMESPACE_SCHEMA_VERSION, encodeNamespace, decodeNamespace, type NamespaceEnvelope, type EncodeResult, type DecodeResult, } from './namespace-codec.js';
|
|
12
|
+
export { projectTree, findLeaves, validateLeafId, formatTreeText, type TreeNode, type CellTree, } from './cell-tree.js';
|
|
13
|
+
export { StalenessBanner, type StalenessCheck } from './staleness-banner.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { detectKind, FILE_COLLECTOR_KINDS } from './detect-kind.js';
|
|
2
|
+
export { FileCollector } from './file-collector.js';
|
|
3
|
+
export { DefaultCollectorRegistry, uriMatchesPattern } from './collector-registry.js';
|
|
4
|
+
export { isDataLoadEvent, isProgressEvent, isStartupErrorEvent, isSnapshotResult, } from './kernel-protocol.js';
|
|
5
|
+
export { filterEnv, kernelExecArgv, resolveKernelEntry } from './kernel-spawn.js';
|
|
6
|
+
export { ChildProcessRuntime, } from './child-process-runtime.js';
|
|
7
|
+
export { ScratchpadManager, ForkKernelHangError, } from './scratchpad-manager.js';
|
|
8
|
+
export { acquireLock, releaseLock, readLock, isStaleLock, ScratchpadBusyError, } from './scratchpad-lock.js';
|
|
9
|
+
export { CellArchive, CELLS_SCHEMA_VERSION, } from './cell-archive.js';
|
|
10
|
+
export { buildDataLibBindings } from './kernel-bindings.js';
|
|
11
|
+
export { NAMESPACE_SCHEMA_VERSION, encodeNamespace, decodeNamespace, } from './namespace-codec.js';
|
|
12
|
+
export { projectTree, findLeaves, validateLeafId, formatTreeText, } from './cell-tree.js';
|
|
13
|
+
export { StalenessBanner } from './staleness-banner.js';
|