@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,61 @@
|
|
|
1
|
+
// packages/coworker-memory/src/types.ts
|
|
2
|
+
export type Wing = string;
|
|
3
|
+
export type Room = string;
|
|
4
|
+
|
|
5
|
+
export const DRAWER_KINDS = ['turn', 'paste', 'file_load', 'ticket', 'email', 'rca', 'note', 'artifact'] as const;
|
|
6
|
+
export type DrawerKind = typeof DRAWER_KINDS[number];
|
|
7
|
+
|
|
8
|
+
export const LAYER_A_KINDS = ['profile', 'rule', 'lesson'] as const;
|
|
9
|
+
export type LayerAKind = typeof LAYER_A_KINDS[number];
|
|
10
|
+
|
|
11
|
+
export type ScopeMode = 'global' | 'per-project' | 'per-project-tagged';
|
|
12
|
+
|
|
13
|
+
export interface Drawer {
|
|
14
|
+
id: string;
|
|
15
|
+
wing: Wing;
|
|
16
|
+
room: Room;
|
|
17
|
+
kind: DrawerKind;
|
|
18
|
+
content: string;
|
|
19
|
+
metadata: Record<string, unknown>;
|
|
20
|
+
created_at: string;
|
|
21
|
+
parent_id?: string;
|
|
22
|
+
redacted: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface RecallQuery {
|
|
26
|
+
query: string;
|
|
27
|
+
wing?: Wing | Wing[];
|
|
28
|
+
room?: Room;
|
|
29
|
+
kind?: DrawerKind | DrawerKind[];
|
|
30
|
+
days_back?: number;
|
|
31
|
+
max_results?: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface RecallResult {
|
|
35
|
+
drawer: Drawer;
|
|
36
|
+
score: number;
|
|
37
|
+
snippet: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface BackendStatus {
|
|
41
|
+
ready: boolean;
|
|
42
|
+
workspace_wing: Wing;
|
|
43
|
+
drawer_count: number;
|
|
44
|
+
layer_b_db_path: string;
|
|
45
|
+
schema_version: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface LayerAEntry {
|
|
49
|
+
kind: LayerAKind;
|
|
50
|
+
text: string;
|
|
51
|
+
source: 'user' | 'persona-seed';
|
|
52
|
+
ts: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface WorkspaceIdRecord {
|
|
56
|
+
_schema: 1;
|
|
57
|
+
id: string;
|
|
58
|
+
created_at: string;
|
|
59
|
+
memory_seed_applied: boolean;
|
|
60
|
+
memory_seed_persona: string | null;
|
|
61
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// packages/coworker-memory/src/workspace-id.test.ts
|
|
2
|
+
import { describe, it } from 'node:test';
|
|
3
|
+
import assert from 'node:assert/strict';
|
|
4
|
+
import { mkdtempSync, mkdirSync, readFileSync, writeFileSync, existsSync } from 'node:fs';
|
|
5
|
+
import { tmpdir } from 'node:os';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
import { resolveWorkspaceId } from './workspace-id.js';
|
|
8
|
+
|
|
9
|
+
function tmp(): string { return mkdtempSync(join(tmpdir(), 'wsid-')); }
|
|
10
|
+
|
|
11
|
+
describe('resolveWorkspaceId', () => {
|
|
12
|
+
it('creates workspace.json on first call with basename + 6-hex slug', async () => {
|
|
13
|
+
const root = tmp();
|
|
14
|
+
const ws = join(root, 'acme-noc');
|
|
15
|
+
mkdirSync(ws, { recursive: true });
|
|
16
|
+
const rec = await resolveWorkspaceId(ws);
|
|
17
|
+
assert.match(rec.id, /^acme-noc-[0-9a-f]{6}$/);
|
|
18
|
+
assert.equal(rec.memory_seed_applied, false);
|
|
19
|
+
assert.equal(rec.memory_seed_persona, null);
|
|
20
|
+
assert.ok(existsSync(join(ws, '.otto', 'memory', 'workspace.json')));
|
|
21
|
+
});
|
|
22
|
+
it('returns existing id on second call (idempotent)', async () => {
|
|
23
|
+
const root = tmp();
|
|
24
|
+
const ws = join(root, 'acme-noc');
|
|
25
|
+
mkdirSync(ws, { recursive: true });
|
|
26
|
+
const a = await resolveWorkspaceId(ws);
|
|
27
|
+
const b = await resolveWorkspaceId(ws);
|
|
28
|
+
assert.equal(a.id, b.id);
|
|
29
|
+
assert.equal(a.created_at, b.created_at);
|
|
30
|
+
});
|
|
31
|
+
it('falls back to path-hash when workspace.json is corrupted', async () => {
|
|
32
|
+
const root = tmp();
|
|
33
|
+
const ws = join(root, 'broken');
|
|
34
|
+
mkdirSync(join(ws, '.otto', 'memory'), { recursive: true });
|
|
35
|
+
writeFileSync(join(ws, '.otto', 'memory', 'workspace.json'), 'not json');
|
|
36
|
+
const rec = await resolveWorkspaceId(ws);
|
|
37
|
+
assert.match(rec.id, /^broken-[0-9a-f]{6}$/);
|
|
38
|
+
assert.ok(existsSync(join(ws, '.otto', 'memory', 'workspace.json.broken-')) ||
|
|
39
|
+
readFileSync(join(ws, '.otto', 'memory', 'workspace.json'), 'utf8').includes('"_schema"'));
|
|
40
|
+
});
|
|
41
|
+
it('uses workspace fallback when basename is empty', async () => {
|
|
42
|
+
// synthesize via an explicit path with weird basename
|
|
43
|
+
const root = tmp();
|
|
44
|
+
const ws = root; // root-of-tmp has a basename like 'wsid-xxxxxx', fine
|
|
45
|
+
const rec = await resolveWorkspaceId(ws);
|
|
46
|
+
assert.ok(rec.id.length > 0);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// packages/coworker-memory/src/workspace-id.ts
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync, chmodSync } from 'node:fs';
|
|
3
|
+
import { basename, join } from 'node:path';
|
|
4
|
+
import { createHash } from 'node:crypto';
|
|
5
|
+
import type { WorkspaceIdRecord } from './types.js';
|
|
6
|
+
|
|
7
|
+
function pathHash6(absolutePath: string): string {
|
|
8
|
+
return createHash('sha256').update(absolutePath).digest('hex').slice(0, 6);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function deriveSlug(workspaceDir: string): string {
|
|
12
|
+
let base = basename(workspaceDir).replace(/[^a-z0-9-]/gi, '-').replace(/^-+|-+$/g, '').toLowerCase();
|
|
13
|
+
if (!base) base = 'workspace';
|
|
14
|
+
return `${base}-${pathHash6(workspaceDir)}`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function resolveWorkspaceId(workspaceDir: string): Promise<WorkspaceIdRecord> {
|
|
18
|
+
const memDir = join(workspaceDir, '.otto', 'memory');
|
|
19
|
+
const path = join(memDir, 'workspace.json');
|
|
20
|
+
mkdirSync(memDir, { recursive: true, mode: 0o700 });
|
|
21
|
+
|
|
22
|
+
if (existsSync(path)) {
|
|
23
|
+
try {
|
|
24
|
+
const data = JSON.parse(readFileSync(path, 'utf8')) as WorkspaceIdRecord;
|
|
25
|
+
if (data && data._schema === 1 && typeof data.id === 'string' && data.id.length > 0) {
|
|
26
|
+
return data;
|
|
27
|
+
}
|
|
28
|
+
} catch { /* fall through to recreate */ }
|
|
29
|
+
// Move broken aside.
|
|
30
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
31
|
+
try { renameSync(path, `${path}.broken-${stamp}`); } catch { /* best effort */ }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const fresh: WorkspaceIdRecord = {
|
|
35
|
+
_schema: 1,
|
|
36
|
+
id: deriveSlug(workspaceDir),
|
|
37
|
+
created_at: new Date().toISOString(),
|
|
38
|
+
memory_seed_applied: false,
|
|
39
|
+
memory_seed_persona: null,
|
|
40
|
+
};
|
|
41
|
+
const tmp = `${path}.tmp`;
|
|
42
|
+
writeFileSync(tmp, JSON.stringify(fresh, null, 2), { mode: 0o600 });
|
|
43
|
+
chmodSync(tmp, 0o600);
|
|
44
|
+
renameSync(tmp, path);
|
|
45
|
+
return fresh;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function writeWorkspaceId(workspaceDir: string, rec: WorkspaceIdRecord): Promise<void> {
|
|
49
|
+
const memDir = join(workspaceDir, '.otto', 'memory');
|
|
50
|
+
mkdirSync(memDir, { recursive: true, mode: 0o700 });
|
|
51
|
+
const path = join(memDir, 'workspace.json');
|
|
52
|
+
const tmp = `${path}.tmp`;
|
|
53
|
+
writeFileSync(tmp, JSON.stringify(rec, null, 2), { mode: 0o600 });
|
|
54
|
+
chmodSync(tmp, 0o600);
|
|
55
|
+
renameSync(tmp, path);
|
|
56
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"module": "NodeNext",
|
|
4
|
+
"moduleResolution": "NodeNext",
|
|
5
|
+
"target": "ES2022",
|
|
6
|
+
"outDir": "dist",
|
|
7
|
+
"rootDir": "src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true
|
|
12
|
+
},
|
|
13
|
+
"include": ["src"],
|
|
14
|
+
"exclude": ["src/**/*.test.ts"]
|
|
15
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { PersonaRegistry } from './registry.js';
|
|
2
|
+
export declare function handleList(registry: PersonaRegistry, workspaceRoot: string): Promise<string[]>;
|
|
3
|
+
export declare function handleCurrent(registry: PersonaRegistry, workspaceRoot: string): Promise<string[]>;
|
|
4
|
+
export declare function handleSwitch(registry: PersonaRegistry, workspaceRoot: string, name: string): Promise<string[]>;
|
|
5
|
+
export declare function handleReset(registry: PersonaRegistry, workspaceRoot: string): Promise<string[]>;
|
|
6
|
+
export declare function handleInstall(registry: PersonaRegistry, source: string): Promise<string[]>;
|
|
7
|
+
export declare function handleUninstall(registry: PersonaRegistry, name: string, trackedWorkspaces: string[]): Promise<string[]>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export async function handleList(registry, workspaceRoot) {
|
|
2
|
+
const installed = await registry.list();
|
|
3
|
+
const active = await registry.activeInWorkspace(workspaceRoot);
|
|
4
|
+
return installed.map(p => `${p.name === active.name ? '*' : ' '} ${p.name} — ${p.display_name} (v${p.version})`);
|
|
5
|
+
}
|
|
6
|
+
export async function handleCurrent(registry, workspaceRoot) {
|
|
7
|
+
const active = await registry.activeInWorkspace(workspaceRoot);
|
|
8
|
+
return [
|
|
9
|
+
`Active persona: ${active.name}`,
|
|
10
|
+
`Display name: ${active.display_name}`,
|
|
11
|
+
`Version: ${active.version}`,
|
|
12
|
+
`Description: ${active.description}`,
|
|
13
|
+
`Author: ${active.author}`,
|
|
14
|
+
];
|
|
15
|
+
}
|
|
16
|
+
export async function handleSwitch(registry, workspaceRoot, name) {
|
|
17
|
+
const persona = await registry.get(name);
|
|
18
|
+
if (!persona)
|
|
19
|
+
throw new Error(`persona "${name}" is not installed; run /persona list to see installed personas`);
|
|
20
|
+
await registry.activateInWorkspace(workspaceRoot, name);
|
|
21
|
+
return [`Switched to persona: ${name} (${persona.display_name})`];
|
|
22
|
+
}
|
|
23
|
+
export async function handleReset(registry, workspaceRoot) {
|
|
24
|
+
await registry.activateInWorkspace(workspaceRoot, 'default');
|
|
25
|
+
return ['Persona reset to default'];
|
|
26
|
+
}
|
|
27
|
+
export async function handleInstall(registry, source) {
|
|
28
|
+
// For Phase 0 we only support local-path install. Npm + git install come in Phase 6.
|
|
29
|
+
const manifest = await registry.installFromPath(source);
|
|
30
|
+
return [`Installed persona: ${manifest.name} (${manifest.display_name})`];
|
|
31
|
+
}
|
|
32
|
+
export async function handleUninstall(registry, name, trackedWorkspaces) {
|
|
33
|
+
await registry.uninstall(name, { trackedWorkspaces });
|
|
34
|
+
return [`Uninstalled persona: ${name}`];
|
|
35
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
name: default
|
|
2
|
+
display_name: "Default Co-Worker"
|
|
3
|
+
version: 1.0.0
|
|
4
|
+
description: "Generic co-worker with no domain specialization. Auto-activates when no persona is set."
|
|
5
|
+
author: "@cmetech"
|
|
6
|
+
otto_version_required: ">=2.0.0"
|
|
7
|
+
steering:
|
|
8
|
+
- steering/identity.md
|
|
9
|
+
status_line:
|
|
10
|
+
label: "default"
|
|
11
|
+
color: "#6B6B7C"
|
|
12
|
+
icon: "⚙"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface PersonaStatusLine {
|
|
2
|
+
label: string;
|
|
3
|
+
color: string;
|
|
4
|
+
icon: string;
|
|
5
|
+
}
|
|
6
|
+
export interface PersonaMemorySeed {
|
|
7
|
+
apply_on_first_activation: boolean;
|
|
8
|
+
scope?: 'global' | 'per-project' | 'per-project-tagged';
|
|
9
|
+
}
|
|
10
|
+
export interface PersonaManifest {
|
|
11
|
+
name: string;
|
|
12
|
+
display_name: string;
|
|
13
|
+
version: string;
|
|
14
|
+
description: string;
|
|
15
|
+
author: string;
|
|
16
|
+
otto_version_required: string;
|
|
17
|
+
steering: string[];
|
|
18
|
+
memory_seed?: PersonaMemorySeed;
|
|
19
|
+
engines?: string;
|
|
20
|
+
artifact_kinds?: string[];
|
|
21
|
+
skills_path?: string;
|
|
22
|
+
status_line: PersonaStatusLine;
|
|
23
|
+
}
|
|
24
|
+
export declare function parsePersonaManifest(yamlText: string): PersonaManifest;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Persona manifest parser. See spec §2.5.
|
|
2
|
+
import { parse as parseYaml } from 'yaml';
|
|
3
|
+
// Order matters: tests assert the FIRST missing field reported, and the
|
|
4
|
+
// "missing version" case supplies only `name`, so `version` must be checked
|
|
5
|
+
// before `display_name`.
|
|
6
|
+
const REQUIRED = [
|
|
7
|
+
'name', 'version', 'display_name', 'description', 'author',
|
|
8
|
+
'otto_version_required', 'steering', 'status_line',
|
|
9
|
+
];
|
|
10
|
+
export function parsePersonaManifest(yamlText) {
|
|
11
|
+
const raw = parseYaml(yamlText);
|
|
12
|
+
if (!raw || typeof raw !== 'object') {
|
|
13
|
+
throw new Error('persona manifest must be a YAML object');
|
|
14
|
+
}
|
|
15
|
+
for (const field of REQUIRED) {
|
|
16
|
+
if (!(field in raw)) {
|
|
17
|
+
throw new Error(`persona manifest missing required field: ${field}`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return raw;
|
|
21
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type PersonaManifest } from './manifest.js';
|
|
2
|
+
export interface RegistryOptions {
|
|
3
|
+
ottoHome: string;
|
|
4
|
+
}
|
|
5
|
+
export interface ActiveRecord {
|
|
6
|
+
active: string;
|
|
7
|
+
activated_at: string;
|
|
8
|
+
memory_seed_applied: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare class PersonaRegistry {
|
|
11
|
+
#private;
|
|
12
|
+
constructor(opts: RegistryOptions);
|
|
13
|
+
ensureDefaultInstalled(): Promise<void>;
|
|
14
|
+
list(): Promise<PersonaManifest[]>;
|
|
15
|
+
installFromPath(bundlePath: string): Promise<PersonaManifest>;
|
|
16
|
+
activateInWorkspace(workspaceRoot: string, name: string): Promise<void>;
|
|
17
|
+
activeInWorkspace(workspaceRoot: string): Promise<PersonaManifest>;
|
|
18
|
+
get(name: string): Promise<PersonaManifest | null>;
|
|
19
|
+
uninstall(name: string, opts: {
|
|
20
|
+
trackedWorkspaces: string[];
|
|
21
|
+
}): Promise<void>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// PersonaRegistry — install / list / activate / switch. Spec §2.5.
|
|
2
|
+
import * as fs from 'node:fs/promises';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { parsePersonaManifest } from './manifest.js';
|
|
5
|
+
async function dirExists(p) {
|
|
6
|
+
try {
|
|
7
|
+
const s = await fs.stat(p);
|
|
8
|
+
return s.isDirectory();
|
|
9
|
+
}
|
|
10
|
+
catch (err) {
|
|
11
|
+
if (err.code === 'ENOENT')
|
|
12
|
+
return false;
|
|
13
|
+
throw err;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
async function copyDir(src, dst) {
|
|
17
|
+
await fs.mkdir(dst, { recursive: true });
|
|
18
|
+
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
19
|
+
for (const e of entries) {
|
|
20
|
+
const s = path.join(src, e.name);
|
|
21
|
+
const d = path.join(dst, e.name);
|
|
22
|
+
if (e.isDirectory()) {
|
|
23
|
+
await copyDir(s, d);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
await fs.copyFile(s, d);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export class PersonaRegistry {
|
|
31
|
+
#personasDir;
|
|
32
|
+
constructor(opts) {
|
|
33
|
+
this.#personasDir = path.join(opts.ottoHome, 'personas');
|
|
34
|
+
}
|
|
35
|
+
async ensureDefaultInstalled() {
|
|
36
|
+
const target = path.join(this.#personasDir, 'default');
|
|
37
|
+
if (await dirExists(target))
|
|
38
|
+
return;
|
|
39
|
+
// Source: bundled defaults shipped with this package
|
|
40
|
+
const here = path.dirname(new URL(import.meta.url).pathname);
|
|
41
|
+
const source = path.join(here, 'defaults');
|
|
42
|
+
await copyDir(source, target);
|
|
43
|
+
}
|
|
44
|
+
async list() {
|
|
45
|
+
if (!(await dirExists(this.#personasDir)))
|
|
46
|
+
return [];
|
|
47
|
+
const entries = await fs.readdir(this.#personasDir, { withFileTypes: true });
|
|
48
|
+
const out = [];
|
|
49
|
+
for (const e of entries) {
|
|
50
|
+
if (!e.isDirectory())
|
|
51
|
+
continue;
|
|
52
|
+
const manifestPath = path.join(this.#personasDir, e.name, 'manifest.yaml');
|
|
53
|
+
try {
|
|
54
|
+
const raw = await fs.readFile(manifestPath, 'utf8');
|
|
55
|
+
out.push(parsePersonaManifest(raw));
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// skip malformed bundles
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
async installFromPath(bundlePath) {
|
|
64
|
+
const manifestPath = path.join(bundlePath, 'manifest.yaml');
|
|
65
|
+
let raw;
|
|
66
|
+
try {
|
|
67
|
+
raw = await fs.readFile(manifestPath, 'utf8');
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
if (err.code === 'ENOENT') {
|
|
71
|
+
throw new Error(`bundle missing manifest.yaml at ${manifestPath}`);
|
|
72
|
+
}
|
|
73
|
+
throw err;
|
|
74
|
+
}
|
|
75
|
+
const manifest = parsePersonaManifest(raw);
|
|
76
|
+
const target = path.join(this.#personasDir, manifest.name);
|
|
77
|
+
await fs.rm(target, { recursive: true, force: true });
|
|
78
|
+
await copyDir(bundlePath, target);
|
|
79
|
+
return manifest;
|
|
80
|
+
}
|
|
81
|
+
async activateInWorkspace(workspaceRoot, name) {
|
|
82
|
+
const persona = await this.get(name);
|
|
83
|
+
if (!persona)
|
|
84
|
+
throw new Error(`persona not installed: ${name}`);
|
|
85
|
+
const wsOtto = path.join(workspaceRoot, '.otto');
|
|
86
|
+
await fs.mkdir(wsOtto, { recursive: true });
|
|
87
|
+
const record = {
|
|
88
|
+
active: name,
|
|
89
|
+
activated_at: new Date().toISOString(),
|
|
90
|
+
memory_seed_applied: false,
|
|
91
|
+
};
|
|
92
|
+
await fs.writeFile(path.join(wsOtto, 'persona.json'), JSON.stringify(record, null, 2));
|
|
93
|
+
}
|
|
94
|
+
async activeInWorkspace(workspaceRoot) {
|
|
95
|
+
const recordPath = path.join(workspaceRoot, '.otto', 'persona.json');
|
|
96
|
+
try {
|
|
97
|
+
const raw = await fs.readFile(recordPath, 'utf8');
|
|
98
|
+
const record = JSON.parse(raw);
|
|
99
|
+
const m = await this.get(record.active);
|
|
100
|
+
if (m)
|
|
101
|
+
return m;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// fall through to default
|
|
105
|
+
}
|
|
106
|
+
const def = await this.get('default');
|
|
107
|
+
if (!def)
|
|
108
|
+
throw new Error('default persona not installed');
|
|
109
|
+
return def;
|
|
110
|
+
}
|
|
111
|
+
async get(name) {
|
|
112
|
+
const manifestPath = path.join(this.#personasDir, name, 'manifest.yaml');
|
|
113
|
+
try {
|
|
114
|
+
const raw = await fs.readFile(manifestPath, 'utf8');
|
|
115
|
+
return parsePersonaManifest(raw);
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async uninstall(name, opts) {
|
|
122
|
+
if (name === 'default') {
|
|
123
|
+
throw new Error('cannot uninstall the built-in default persona');
|
|
124
|
+
}
|
|
125
|
+
for (const ws of opts.trackedWorkspaces) {
|
|
126
|
+
try {
|
|
127
|
+
const raw = await fs.readFile(path.join(ws, '.otto', 'persona.json'), 'utf8');
|
|
128
|
+
const record = JSON.parse(raw);
|
|
129
|
+
if (record.active === name) {
|
|
130
|
+
throw new Error(`persona ${name} is active in workspace ${ws}; switch first`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
if (err.code === 'ENOENT')
|
|
135
|
+
continue;
|
|
136
|
+
if (err instanceof Error && err.message.startsWith('persona '))
|
|
137
|
+
throw err;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
await fs.rm(path.join(this.#personasDir, name), { recursive: true, force: true });
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@otto/coworker-persona",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Persona registry, manifest parser, and built-in default persona for Otto co-worker",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"otto": {
|
|
7
|
+
"linkable": true,
|
|
8
|
+
"scope": "@otto",
|
|
9
|
+
"name": "coworker-persona"
|
|
10
|
+
},
|
|
11
|
+
"main": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc -p tsconfig.json && node scripts/copy-defaults.cjs",
|
|
21
|
+
"build:publish": "tsc -p tsconfig.publish.json && node scripts/copy-defaults.cjs"
|
|
22
|
+
},
|
|
23
|
+
"files": ["dist"],
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@otto/coworker-utils": "*",
|
|
26
|
+
"yaml": "^2.4.0"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const fs = require('node:fs');
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
|
|
5
|
+
function copyDir(src, dst) {
|
|
6
|
+
fs.mkdirSync(dst, { recursive: true });
|
|
7
|
+
for (const e of fs.readdirSync(src, { withFileTypes: true })) {
|
|
8
|
+
const s = path.join(src, e.name);
|
|
9
|
+
const d = path.join(dst, e.name);
|
|
10
|
+
e.isDirectory() ? copyDir(s, d) : fs.copyFileSync(s, d);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const src = path.resolve(__dirname, '..', 'src', 'defaults');
|
|
15
|
+
const dst = path.resolve(__dirname, '..', 'dist', 'defaults');
|
|
16
|
+
copyDir(src, dst);
|
|
17
|
+
console.log(`Copied persona defaults: ${src} → ${dst}`);
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// /persona slash-command handlers. Spec §2.5 + §5.2.
|
|
2
|
+
// Pure functions over a PersonaRegistry — UI adapters live in otto-cli.
|
|
3
|
+
import { PersonaRegistry } from './registry.js';
|
|
4
|
+
|
|
5
|
+
export async function handleList(registry: PersonaRegistry, workspaceRoot: string): Promise<string[]> {
|
|
6
|
+
const installed = await registry.list();
|
|
7
|
+
const active = await registry.activeInWorkspace(workspaceRoot);
|
|
8
|
+
return installed.map(p => `${p.name === active.name ? '*' : ' '} ${p.name} — ${p.display_name} (v${p.version})`);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function handleCurrent(registry: PersonaRegistry, workspaceRoot: string): Promise<string[]> {
|
|
12
|
+
const active = await registry.activeInWorkspace(workspaceRoot);
|
|
13
|
+
return [
|
|
14
|
+
`Active persona: ${active.name}`,
|
|
15
|
+
`Display name: ${active.display_name}`,
|
|
16
|
+
`Version: ${active.version}`,
|
|
17
|
+
`Description: ${active.description}`,
|
|
18
|
+
`Author: ${active.author}`,
|
|
19
|
+
];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function handleSwitch(registry: PersonaRegistry, workspaceRoot: string, name: string): Promise<string[]> {
|
|
23
|
+
const persona = await registry.get(name);
|
|
24
|
+
if (!persona) throw new Error(`persona "${name}" is not installed; run /persona list to see installed personas`);
|
|
25
|
+
await registry.activateInWorkspace(workspaceRoot, name);
|
|
26
|
+
return [`Switched to persona: ${name} (${persona.display_name})`];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function handleReset(registry: PersonaRegistry, workspaceRoot: string): Promise<string[]> {
|
|
30
|
+
await registry.activateInWorkspace(workspaceRoot, 'default');
|
|
31
|
+
return ['Persona reset to default'];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function handleInstall(registry: PersonaRegistry, source: string): Promise<string[]> {
|
|
35
|
+
// For Phase 0 we only support local-path install. Npm + git install come in Phase 6.
|
|
36
|
+
const manifest = await registry.installFromPath(source);
|
|
37
|
+
return [`Installed persona: ${manifest.name} (${manifest.display_name})`];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function handleUninstall(
|
|
41
|
+
registry: PersonaRegistry,
|
|
42
|
+
name: string,
|
|
43
|
+
trackedWorkspaces: string[],
|
|
44
|
+
): Promise<string[]> {
|
|
45
|
+
await registry.uninstall(name, { trackedWorkspaces });
|
|
46
|
+
return [`Uninstalled persona: ${name}`];
|
|
47
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
name: default
|
|
2
|
+
display_name: "Default Co-Worker"
|
|
3
|
+
version: 1.0.0
|
|
4
|
+
description: "Generic co-worker with no domain specialization. Auto-activates when no persona is set."
|
|
5
|
+
author: "@cmetech"
|
|
6
|
+
otto_version_required: ">=2.0.0"
|
|
7
|
+
steering:
|
|
8
|
+
- steering/identity.md
|
|
9
|
+
status_line:
|
|
10
|
+
label: "default"
|
|
11
|
+
color: "#6B6B7C"
|
|
12
|
+
icon: "⚙"
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { parsePersonaManifest, type PersonaManifest } from './manifest.js';
|
|
4
|
+
|
|
5
|
+
describe('persona manifest', () => {
|
|
6
|
+
it('parses a minimum-valid manifest', () => {
|
|
7
|
+
const yaml = `
|
|
8
|
+
name: noc-ops
|
|
9
|
+
display_name: "NOC / IT Ops Analyst"
|
|
10
|
+
version: 1.0.0
|
|
11
|
+
description: "NOC analyst co-worker"
|
|
12
|
+
author: "@cmetech"
|
|
13
|
+
otto_version_required: ">=2.0.0"
|
|
14
|
+
steering:
|
|
15
|
+
- steering/identity.md
|
|
16
|
+
status_line:
|
|
17
|
+
label: NOC
|
|
18
|
+
color: "#FAD22D"
|
|
19
|
+
icon: "🛡"
|
|
20
|
+
`;
|
|
21
|
+
const m: PersonaManifest = parsePersonaManifest(yaml);
|
|
22
|
+
assert.equal(m.name, 'noc-ops');
|
|
23
|
+
assert.equal(m.steering.length, 1);
|
|
24
|
+
assert.equal(m.status_line.label, 'NOC');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('rejects manifest missing required name', () => {
|
|
28
|
+
const yaml = 'version: 1.0.0';
|
|
29
|
+
assert.throws(() => parsePersonaManifest(yaml), /name/);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('rejects manifest missing version', () => {
|
|
33
|
+
const yaml = 'name: noc-ops';
|
|
34
|
+
assert.throws(() => parsePersonaManifest(yaml), /version/);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('defaults memory_seed.apply_on_first_activation to false when absent', () => {
|
|
38
|
+
const yaml = `
|
|
39
|
+
name: x
|
|
40
|
+
display_name: x
|
|
41
|
+
version: 1.0.0
|
|
42
|
+
description: x
|
|
43
|
+
author: x
|
|
44
|
+
otto_version_required: ">=2.0.0"
|
|
45
|
+
steering: []
|
|
46
|
+
status_line: { label: X, color: "#000000", icon: "x" }
|
|
47
|
+
`;
|
|
48
|
+
const m = parsePersonaManifest(yaml);
|
|
49
|
+
assert.equal(m.memory_seed?.apply_on_first_activation ?? false, false);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('parses artifact_kinds list when provided', () => {
|
|
53
|
+
const yaml = `
|
|
54
|
+
name: x
|
|
55
|
+
display_name: x
|
|
56
|
+
version: 1.0.0
|
|
57
|
+
description: x
|
|
58
|
+
author: x
|
|
59
|
+
otto_version_required: ">=2.0.0"
|
|
60
|
+
steering: []
|
|
61
|
+
status_line: { label: X, color: "#000", icon: "x" }
|
|
62
|
+
artifact_kinds: [report, workbook, inventory_report]
|
|
63
|
+
`;
|
|
64
|
+
const m = parsePersonaManifest(yaml);
|
|
65
|
+
assert.deepEqual(m.artifact_kinds, ['report', 'workbook', 'inventory_report']);
|
|
66
|
+
});
|
|
67
|
+
});
|