@stravica-ai/digital-operator-pa 0.1.0
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/LICENSE +21 -0
- package/README.md +170 -0
- package/bin/desk +9 -0
- package/bin/distill +2 -0
- package/bin/estate-sync +2 -0
- package/bin/launch +2 -0
- package/bin/memory-sync +2 -0
- package/bin/migrate-inspect +2 -0
- package/bin/pa +2 -0
- package/bin/pa-coordinator-hook +2 -0
- package/bin/pa-init +2 -0
- package/bin/research +2 -0
- package/bin/scheduler +2 -0
- package/bin/secrets +2 -0
- package/bin/slice +2 -0
- package/bin/smoke +9 -0
- package/bin/sync +2 -0
- package/dist/engineering-pa-cli/README.md +205 -0
- package/dist/engineering-pa-cli/bin/estate-sync +2 -0
- package/dist/engineering-pa-cli/bin/launch +2 -0
- package/dist/engineering-pa-cli/bin/pa +2 -0
- package/dist/engineering-pa-cli/bin/pa-coordinator-hook +12 -0
- package/dist/engineering-pa-cli/bin/research +2 -0
- package/dist/engineering-pa-cli/bin/scheduler +2 -0
- package/dist/engineering-pa-cli/bin/secrets +2 -0
- package/dist/engineering-pa-cli/bin/smoke +9 -0
- package/dist/engineering-pa-cli/bin/sync +2 -0
- package/dist/engineering-pa-cli/config/coordinator-allowlist.json +118 -0
- package/dist/engineering-pa-cli/docs/coordinator-hook.md +211 -0
- package/dist/engineering-pa-cli/docs/estate-sync.md +412 -0
- package/dist/engineering-pa-cli/docs/gsc.md +175 -0
- package/dist/engineering-pa-cli/docs/lint-linkedin.md +139 -0
- package/dist/engineering-pa-cli/docs/secrets.md +221 -0
- package/dist/engineering-pa-cli/docs/smoke.md +113 -0
- package/dist/engineering-pa-cli/docs/staging-alias.md +114 -0
- package/dist/engineering-pa-cli/index.mjs +17 -0
- package/dist/engineering-pa-cli/package.json +37 -0
- package/dist/engineering-pa-cli/src/autonomy/cli.mjs +329 -0
- package/dist/engineering-pa-cli/src/autonomy/envelope.mjs +301 -0
- package/dist/engineering-pa-cli/src/coordinator-hook/cli.mjs +140 -0
- package/dist/engineering-pa-cli/src/coordinator-hook/config.mjs +134 -0
- package/dist/engineering-pa-cli/src/coordinator-hook/message.mjs +47 -0
- package/dist/engineering-pa-cli/src/coordinator-hook/policy.mjs +211 -0
- package/dist/engineering-pa-cli/src/coordinator-hook/repo-root.mjs +44 -0
- package/dist/engineering-pa-cli/src/coordinator-hook/self.mjs +30 -0
- package/dist/engineering-pa-cli/src/environment/cli.mjs +287 -0
- package/dist/engineering-pa-cli/src/environment/probes.mjs +302 -0
- package/dist/engineering-pa-cli/src/gsc/auth.mjs +148 -0
- package/dist/engineering-pa-cli/src/gsc/cli.mjs +93 -0
- package/dist/engineering-pa-cli/src/gsc/cloudflare.mjs +318 -0
- package/dist/engineering-pa-cli/src/gsc/commands/add-property.mjs +70 -0
- package/dist/engineering-pa-cli/src/gsc/commands/list-properties.mjs +33 -0
- package/dist/engineering-pa-cli/src/gsc/commands/pull-analytics.mjs +130 -0
- package/dist/engineering-pa-cli/src/gsc/commands/submit-sitemap.mjs +41 -0
- package/dist/engineering-pa-cli/src/gsc/commands/verify-via-cf-dns.mjs +189 -0
- package/dist/engineering-pa-cli/src/knowledge/call-log.mjs +59 -0
- package/dist/engineering-pa-cli/src/knowledge/cli.mjs +242 -0
- package/dist/engineering-pa-cli/src/knowledge/eval.mjs +446 -0
- package/dist/engineering-pa-cli/src/knowledge/formatters.mjs +331 -0
- package/dist/engineering-pa-cli/src/knowledge/graph.mjs +710 -0
- package/dist/engineering-pa-cli/src/launch/README.md +214 -0
- package/dist/engineering-pa-cli/src/launch/cli.mjs +51 -0
- package/dist/engineering-pa-cli/src/launch/commands/launch.mjs +106 -0
- package/dist/engineering-pa-cli/src/launch/identity.mjs +43 -0
- package/dist/engineering-pa-cli/src/launch/planner.mjs +44 -0
- package/dist/engineering-pa-cli/src/launch/repo-root.mjs +53 -0
- package/dist/engineering-pa-cli/src/launch/runner.mjs +147 -0
- package/dist/engineering-pa-cli/src/launch/task-loader.mjs +85 -0
- package/dist/engineering-pa-cli/src/lint/cli.mjs +61 -0
- package/dist/engineering-pa-cli/src/lint/commands/linkedin.mjs +133 -0
- package/dist/engineering-pa-cli/src/lint/detectors.mjs +90 -0
- package/dist/engineering-pa-cli/src/lint/linter.mjs +69 -0
- package/dist/engineering-pa-cli/src/lint/reporter.mjs +32 -0
- package/dist/engineering-pa-cli/src/lint/rules.mjs +132 -0
- package/dist/engineering-pa-cli/src/pa/cli.mjs +369 -0
- package/dist/engineering-pa-cli/src/pa/doc-groups.mjs +164 -0
- package/dist/engineering-pa-cli/src/pa/io.mjs +80 -0
- package/dist/engineering-pa-cli/src/pa/project-cli.mjs +385 -0
- package/dist/engineering-pa-cli/src/pa/projects.mjs +352 -0
- package/dist/engineering-pa-cli/src/pa/repo-root.mjs +64 -0
- package/dist/engineering-pa-cli/src/pa/session.mjs +254 -0
- package/dist/engineering-pa-cli/src/pa/work-cli.mjs +164 -0
- package/dist/engineering-pa-cli/src/pa/work.mjs +196 -0
- package/dist/engineering-pa-cli/src/pa/workstreams.mjs +201 -0
- package/dist/engineering-pa-cli/src/research/README.md +360 -0
- package/dist/engineering-pa-cli/src/research/briefs/extractor.md +103 -0
- package/dist/engineering-pa-cli/src/research/briefs/searcher.md +113 -0
- package/dist/engineering-pa-cli/src/research/briefs/synthesizer.md +124 -0
- package/dist/engineering-pa-cli/src/research/briefs/verifier.md +86 -0
- package/dist/engineering-pa-cli/src/research/cli.mjs +141 -0
- package/dist/engineering-pa-cli/src/research/commands/gates.mjs +176 -0
- package/dist/engineering-pa-cli/src/research/commands/list.mjs +56 -0
- package/dist/engineering-pa-cli/src/research/commands/mark.mjs +97 -0
- package/dist/engineering-pa-cli/src/research/commands/paths.mjs +69 -0
- package/dist/engineering-pa-cli/src/research/commands/prune.mjs +86 -0
- package/dist/engineering-pa-cli/src/research/commands/run.mjs +94 -0
- package/dist/engineering-pa-cli/src/research/commands/show.mjs +43 -0
- package/dist/engineering-pa-cli/src/research/docs/operator-present-flow.md +120 -0
- package/dist/engineering-pa-cli/src/research/format.mjs +59 -0
- package/dist/engineering-pa-cli/src/research/promote.mjs +260 -0
- package/dist/engineering-pa-cli/src/research/schema/finding.schema.json +55 -0
- package/dist/engineering-pa-cli/src/research/schema/gates.schema.json +34 -0
- package/dist/engineering-pa-cli/src/research/schema/manifest.schema.json +59 -0
- package/dist/engineering-pa-cli/src/research/schema/plan.schema.json +41 -0
- package/dist/engineering-pa-cli/src/research/schema/sources.schema.json +31 -0
- package/dist/engineering-pa-cli/src/research/store/findings.mjs +61 -0
- package/dist/engineering-pa-cli/src/research/store/gates.mjs +73 -0
- package/dist/engineering-pa-cli/src/research/store/index.mjs +312 -0
- package/dist/engineering-pa-cli/src/research/store/manifest.mjs +56 -0
- package/dist/engineering-pa-cli/src/research/store/plan.mjs +59 -0
- package/dist/engineering-pa-cli/src/research/store/sources.mjs +44 -0
- package/dist/engineering-pa-cli/src/research/store/validate.mjs +92 -0
- package/dist/engineering-pa-cli/src/research/workflows/research-normal.js +573 -0
- package/dist/engineering-pa-cli/src/scheduler/cli.mjs +197 -0
- package/dist/engineering-pa-cli/src/secrets/cli.mjs +254 -0
- package/dist/engineering-pa-cli/src/secrets/commands/backup-template.mjs +67 -0
- package/dist/engineering-pa-cli/src/secrets/commands/backup.mjs +85 -0
- package/dist/engineering-pa-cli/src/secrets/commands/delete.mjs +58 -0
- package/dist/engineering-pa-cli/src/secrets/commands/find.mjs +36 -0
- package/dist/engineering-pa-cli/src/secrets/commands/get.mjs +49 -0
- package/dist/engineering-pa-cli/src/secrets/commands/init.mjs +69 -0
- package/dist/engineering-pa-cli/src/secrets/commands/list.mjs +37 -0
- package/dist/engineering-pa-cli/src/secrets/commands/rotate.mjs +46 -0
- package/dist/engineering-pa-cli/src/secrets/commands/set.mjs +123 -0
- package/dist/engineering-pa-cli/src/secrets/commands/status.mjs +146 -0
- package/dist/engineering-pa-cli/src/secrets/commands/vaults.mjs +57 -0
- package/dist/engineering-pa-cli/src/secrets/commands/verify.mjs +143 -0
- package/dist/engineering-pa-cli/src/secrets/vault.mjs +766 -0
- package/dist/engineering-pa-cli/src/smoke/checks.mjs +199 -0
- package/dist/engineering-pa-cli/src/smoke/cli.mjs +108 -0
- package/dist/engineering-pa-cli/src/smoke/commands/run.mjs +237 -0
- package/dist/engineering-pa-cli/src/smoke/runner.mjs +191 -0
- package/dist/engineering-pa-cli/src/staging-alias/cli.mjs +91 -0
- package/dist/engineering-pa-cli/src/staging-alias/cloudflare.mjs +380 -0
- package/dist/engineering-pa-cli/src/staging-alias/commands/list.mjs +36 -0
- package/dist/engineering-pa-cli/src/staging-alias/commands/set.mjs +188 -0
- package/dist/engineering-pa-cli/src/staging-alias/commands/status.mjs +113 -0
- package/dist/engineering-pa-cli/src/staging-alias/commands/unset.mjs +95 -0
- package/dist/engineering-pa-cli/src/staging-alias/sites.mjs +105 -0
- package/dist/engineering-pa-cli/src/sync/cli.mjs +151 -0
- package/dist/engineering-pa-cli/src/sync/git.mjs +149 -0
- package/dist/engineering-pa-cli/src/sync/lock.mjs +30 -0
- package/dist/engineering-pa-cli/src/sync/regenerated-artifacts.mjs +114 -0
- package/dist/engineering-pa-cli/src/sync/registry-scope.mjs +260 -0
- package/dist/engineering-pa-cli/src/sync/run.mjs +531 -0
- package/dist/engineering-pa-cli/src/sync/runner.mjs +62 -0
- package/dist/engineering-pa-cli/src/sync/runs-digest.mjs +138 -0
- package/dist/engineering-pa-core/README.md +60 -0
- package/dist/engineering-pa-core/bin/desk +9 -0
- package/dist/engineering-pa-core/bin/distill +2 -0
- package/dist/engineering-pa-core/bin/memory-sync +2 -0
- package/dist/engineering-pa-core/bin/slice +2 -0
- package/dist/engineering-pa-core/docs/autonomy-envelope-tracker.md +111 -0
- package/dist/engineering-pa-core/docs/blueprints/README.md +45 -0
- package/dist/engineering-pa-core/docs/blueprints/docker-services/blueprint.md +168 -0
- package/dist/engineering-pa-core/docs/blueprints/git-identity/blueprint.md +116 -0
- package/dist/engineering-pa-core/docs/blueprints/ideas/custom-workspace-views.md +9 -0
- package/dist/engineering-pa-core/docs/blueprints/ideas/knowledge-domain-patterns.md +15 -0
- package/dist/engineering-pa-core/docs/blueprints/ideas/office-integration.md +11 -0
- package/dist/engineering-pa-core/docs/blueprints/ideas/team-scaling.md +9 -0
- package/dist/engineering-pa-core/docs/blueprints/ideas/work-personal-separation.md +9 -0
- package/dist/engineering-pa-core/docs/blueprints/scheduled-distillation/blueprint.md +129 -0
- package/dist/engineering-pa-core/docs/blueprints/tool-integration/blueprint.md +110 -0
- package/dist/engineering-pa-core/docs/commands/init.md +159 -0
- package/dist/engineering-pa-core/docs/commands/schedule.md +98 -0
- package/dist/engineering-pa-core/docs/commands/upgrade.md +67 -0
- package/dist/engineering-pa-core/docs/entity-location-map.md +93 -0
- package/dist/engineering-pa-core/docs/knowledge-scaffold.md +121 -0
- package/dist/engineering-pa-core/docs/lock.md +155 -0
- package/dist/engineering-pa-core/docs/memory-sync.md +28 -0
- package/dist/engineering-pa-core/docs/pa-operating-model.md +457 -0
- package/dist/engineering-pa-core/docs/scheduling.md +35 -0
- package/dist/engineering-pa-core/docs/standards/README.md +24 -0
- package/dist/engineering-pa-core/docs/standards/briefing-contract.md +161 -0
- package/dist/engineering-pa-core/docs/standards/tooling.md +240 -0
- package/dist/engineering-pa-core/docs/tools/distill.md +230 -0
- package/dist/engineering-pa-core/docs/tools/memory-sync.md +98 -0
- package/dist/engineering-pa-core/docs/tools/scheduler.md +243 -0
- package/dist/engineering-pa-core/docs/tools/slice.md +150 -0
- package/dist/engineering-pa-core/docs/upstream-issue-filing.md +88 -0
- package/dist/engineering-pa-core/docs/working-directory.md +29 -0
- package/dist/engineering-pa-core/docs/workspace-operations.md +46 -0
- package/dist/engineering-pa-core/index.mjs +21 -0
- package/dist/engineering-pa-core/knowledge/README.md +53 -0
- package/dist/engineering-pa-core/knowledge/canonical/.gitkeep +0 -0
- package/dist/engineering-pa-core/knowledge/content-voice/README.md +64 -0
- package/dist/engineering-pa-core/knowledge/content-voice/banned-ai-tells-baseline.md +133 -0
- package/dist/engineering-pa-core/knowledge/content-voice/banned-ai-tells-shape.md +58 -0
- package/dist/engineering-pa-core/knowledge/content-voice/banned-ai-tells-taxonomy.md +33 -0
- package/dist/engineering-pa-core/knowledge/content-voice/content-pipeline-routing.md +58 -0
- package/dist/engineering-pa-core/knowledge/content-voice/new-tell-capture-procedure.md +40 -0
- package/dist/engineering-pa-core/knowledge/content-voice/voice-guide-shape.md +43 -0
- package/dist/engineering-pa-core/knowledge/delegation-dispatch/README.md +34 -0
- package/dist/engineering-pa-core/knowledge/delegation-dispatch/briefing-contract.md +77 -0
- package/dist/engineering-pa-core/knowledge/delegation-dispatch/delegation-modes.md +84 -0
- package/dist/engineering-pa-core/knowledge/delegation-dispatch/dispatch-envelope.md +238 -0
- package/dist/engineering-pa-core/knowledge/delegation-dispatch/task-groups-and-orchestrators.md +62 -0
- package/dist/engineering-pa-core/knowledge/delegation-dispatch/team-improvement-loop.md +48 -0
- package/dist/engineering-pa-core/knowledge/delegation-dispatch/tool-development-policy.md +48 -0
- package/dist/engineering-pa-core/knowledge/engineering-discipline/README.md +33 -0
- package/dist/engineering-pa-core/knowledge/engineering-discipline/blast-radius-and-safety.md +50 -0
- package/dist/engineering-pa-core/knowledge/engineering-discipline/investigate-root-causes.md +48 -0
- package/dist/engineering-pa-core/knowledge/engineering-discipline/role-ladder.md +57 -0
- package/dist/engineering-pa-core/knowledge/engineering-discipline/verify-runtime-behaviour.md +53 -0
- package/dist/engineering-pa-core/knowledge/engineering-discipline/worktree-isolation.md +50 -0
- package/dist/engineering-pa-core/knowledge/knowledge-memory/README.md +33 -0
- package/dist/engineering-pa-core/knowledge/knowledge-memory/claude-md-hygiene.md +47 -0
- package/dist/engineering-pa-core/knowledge/knowledge-memory/journal-and-self-improvement.md +53 -0
- package/dist/engineering-pa-core/knowledge/knowledge-memory/knowledge-retrieval-discipline.md +62 -0
- package/dist/engineering-pa-core/knowledge/knowledge-memory/librarian-synthesis-mandate.md +56 -0
- package/dist/engineering-pa-core/knowledge/knowledge-memory/staging-and-observations.md +58 -0
- package/dist/engineering-pa-core/knowledge/operator-interface/README.md +32 -0
- package/dist/engineering-pa-core/knowledge/operator-interface/communication-style.md +33 -0
- package/dist/engineering-pa-core/knowledge/operator-interface/escalation-and-correction.md +45 -0
- package/dist/engineering-pa-core/knowledge/operator-interface/push-back-discipline.md +42 -0
- package/dist/engineering-pa-core/knowledge/operator-interface/session-boot-and-end.md +56 -0
- package/dist/engineering-pa-core/knowledge/platform-tooling/README.md +37 -0
- package/dist/engineering-pa-core/knowledge/platform-tooling/desk-cli-reference.md +52 -0
- package/dist/engineering-pa-core/knowledge/platform-tooling/environment-awareness.md +91 -0
- package/dist/engineering-pa-core/knowledge/platform-tooling/mcp-servers-catalogue.md +52 -0
- package/dist/engineering-pa-core/knowledge/platform-tooling/pa-cli-reference.md +55 -0
- package/dist/engineering-pa-core/knowledge/platform-tooling/scheduling-and-launchd.md +56 -0
- package/dist/engineering-pa-core/knowledge/platform-tooling/tool-discovery-discipline.md +49 -0
- package/dist/engineering-pa-core/knowledge/platform-tooling/working-directory-vs-project-root.md +43 -0
- package/dist/engineering-pa-core/knowledge/platform-tooling/workspace-server.md +51 -0
- package/dist/engineering-pa-core/knowledge/raw/.gitkeep +0 -0
- package/dist/engineering-pa-core/knowledge/scaffold/domains.json +5 -0
- package/dist/engineering-pa-core/knowledge/schema/.gitkeep +0 -0
- package/dist/engineering-pa-core/knowledge/work-management/README.md +33 -0
- package/dist/engineering-pa-core/knowledge/work-management/desk-cli.md +84 -0
- package/dist/engineering-pa-core/knowledge/work-management/progress-md.md +48 -0
- package/dist/engineering-pa-core/knowledge/work-management/projects.md +64 -0
- package/dist/engineering-pa-core/knowledge/work-management/spawn-log.md +48 -0
- package/dist/engineering-pa-core/knowledge/work-management/work-items.md +67 -0
- package/dist/engineering-pa-core/package.json +26 -0
- package/dist/engineering-pa-core/roles/agent-ops/definition.md +79 -0
- package/dist/engineering-pa-core/roles/dispatch-briefer/definition.md +195 -0
- package/dist/engineering-pa-core/roles/librarian/definition.md +176 -0
- package/dist/engineering-pa-core/roles/pa/definition.md +93 -0
- package/dist/engineering-pa-core/roles/system-admin/definition.md +106 -0
- package/dist/engineering-pa-core/roles/tool-developer/definition.md +116 -0
- package/dist/engineering-pa-core/roles/writer/definition.md +130 -0
- package/dist/engineering-pa-core/schema/autonomy-envelope.schema.json +61 -0
- package/dist/engineering-pa-core/schema/project.json +114 -0
- package/dist/engineering-pa-core/schema/schedule.json +63 -0
- package/dist/engineering-pa-core/schema/work-item.json +92 -0
- package/dist/engineering-pa-core/src/config/pa-package-name.mjs +30 -0
- package/dist/engineering-pa-core/src/desk/cli.mjs +95 -0
- package/dist/engineering-pa-core/src/desk/commands.mjs +398 -0
- package/dist/engineering-pa-core/src/desk/format.mjs +84 -0
- package/dist/engineering-pa-core/src/desk/repo.mjs +172 -0
- package/dist/engineering-pa-core/src/desk/team-scope.mjs +142 -0
- package/dist/engineering-pa-core/src/distill/cli.mjs +112 -0
- package/dist/engineering-pa-core/src/distill/prereqs.mjs +171 -0
- package/dist/engineering-pa-core/src/distill/prompt.mjs +74 -0
- package/dist/engineering-pa-core/src/distill/run.mjs +230 -0
- package/dist/engineering-pa-core/src/distill/runner.mjs +86 -0
- package/dist/engineering-pa-core/src/distill/staging.mjs +59 -0
- package/dist/engineering-pa-core/src/knowledge/retrieval/backlink-indexer.mjs +154 -0
- package/dist/engineering-pa-core/src/knowledge/retrieval/graph-builder.mjs +186 -0
- package/dist/engineering-pa-core/src/knowledge/retrieval/index-builder.mjs +225 -0
- package/dist/engineering-pa-core/src/knowledge/retrieval/query.mjs +263 -0
- package/dist/engineering-pa-core/src/lock/lock.mjs +202 -0
- package/dist/engineering-pa-core/src/memory-sync/cli-support.mjs +12 -0
- package/dist/engineering-pa-core/src/memory-sync/cli.mjs +56 -0
- package/dist/engineering-pa-core/src/memory-sync/commands/pull.mjs +44 -0
- package/dist/engineering-pa-core/src/memory-sync/commands/push.mjs +46 -0
- package/dist/engineering-pa-core/src/memory-sync/mirror.mjs +114 -0
- package/dist/engineering-pa-core/src/memory-sync/repo.mjs +65 -0
- package/dist/engineering-pa-core/src/scheduler/detect.mjs +111 -0
- package/dist/engineering-pa-core/src/scheduler/host.mjs +38 -0
- package/dist/engineering-pa-core/src/scheduler/index.mjs +13 -0
- package/dist/engineering-pa-core/src/scheduler/install.mjs +854 -0
- package/dist/engineering-pa-core/src/scheduler/list.mjs +168 -0
- package/dist/engineering-pa-core/src/scheduler/remove.mjs +176 -0
- package/dist/engineering-pa-core/src/scheduler/verify.mjs +435 -0
- package/dist/engineering-pa-core/src/session-boot/autonomy-injection.mjs +84 -0
- package/dist/engineering-pa-core/src/slice/cli.mjs +139 -0
- package/dist/engineering-pa-core/src/slice/inputs.mjs +174 -0
- package/dist/engineering-pa-core/src/slice/prompt.mjs +94 -0
- package/dist/engineering-pa-core/src/slice/prompts/dave-boot.md +91 -0
- package/dist/engineering-pa-core/src/slice/run.mjs +334 -0
- package/dist/engineering-pa-core-extensions-atlassian/README.md +31 -0
- package/dist/engineering-pa-core-extensions-atlassian/index.mjs +9 -0
- package/dist/engineering-pa-core-extensions-atlassian/package.json +19 -0
- package/dist/engineering-pa-core-extensions-n8n/README.md +29 -0
- package/dist/engineering-pa-core-extensions-n8n/index.mjs +8 -0
- package/dist/engineering-pa-core-extensions-n8n/package.json +19 -0
- package/dist/engineering-pa-librarian/README.md +38 -0
- package/dist/engineering-pa-librarian/index.mjs +12 -0
- package/dist/engineering-pa-librarian/package.json +19 -0
- package/dist/engineering-pa-migrate-inspect/README.md +131 -0
- package/dist/engineering-pa-migrate-inspect/bin/migrate-inspect +2 -0
- package/dist/engineering-pa-migrate-inspect/package.json +21 -0
- package/dist/engineering-pa-migrate-inspect/src/age-key-migrate.mjs +83 -0
- package/dist/engineering-pa-migrate-inspect/src/cli.mjs +97 -0
- package/dist/engineering-pa-migrate-inspect/src/inspector.mjs +237 -0
- package/dist/engineering-pa-migrate-inspect/src/platforms/linux.mjs +87 -0
- package/dist/engineering-pa-migrate-inspect/src/platforms/macos.mjs +105 -0
- package/dist/engineering-pa-migrate-inspect/src/runner.mjs +87 -0
- package/dist/engineering-pa-runbook/README.md +103 -0
- package/dist/engineering-pa-runbook/package.json +18 -0
- package/dist/engineering-pa-runbook/reference/dex-template.runbook.json +66 -0
- package/dist/engineering-pa-runbook/reference/hq-dave.runbook.json +69 -0
- package/dist/engineering-pa-runbook/reference/smarthome01.runbook.json +92 -0
- package/dist/engineering-pa-runbook/schema/inspection.schema.json +113 -0
- package/dist/engineering-pa-runbook/schema/runbook.schema.json +67 -0
- package/dist/engineering-pa-runbook/src/validator.mjs +167 -0
- package/dist/engineering-pa-scaffold/README.md +164 -0
- package/dist/engineering-pa-scaffold/bin/pa-init +2 -0
- package/dist/engineering-pa-scaffold/index.mjs +42 -0
- package/dist/engineering-pa-scaffold/package.json +22 -0
- package/dist/engineering-pa-scaffold/src/cli.mjs +115 -0
- package/dist/engineering-pa-scaffold/src/commands/init.mjs +169 -0
- package/dist/engineering-pa-scaffold/src/generator.mjs +354 -0
- package/dist/engineering-pa-scaffold/src/prompts.mjs +125 -0
- package/dist/engineering-pa-scaffold/src/runner.mjs +142 -0
- package/dist/engineering-pa-scaffold/templates/CLAUDE.md.template +196 -0
- package/dist/engineering-pa-scaffold/templates/operator-README.md.template +44 -0
- package/dist/engineering-pa-types-engineering/README.md +35 -0
- package/dist/engineering-pa-types-engineering/docs/commands/product-build.md +120 -0
- package/dist/engineering-pa-types-engineering/index.mjs +9 -0
- package/dist/engineering-pa-types-engineering/package.json +19 -0
- package/dist/engineering-pa-types-engineering/roles/product-engineer/definition.md +650 -0
- package/dist/engineering-pa-types-engineering/roles/product-engineer/templates/build-spec.md +82 -0
- package/dist/engineering-pa-types-engineering/roles/product-engineer/templates/preflight-checklist.md +158 -0
- package/dist/engineering-pa-types-engineering/roles/product-engineer/templates/worker-brief.md +130 -0
- package/dist/engineering-pa-workspace/README.md +197 -0
- package/dist/engineering-pa-workspace/app/assets/md.js +187 -0
- package/dist/engineering-pa-workspace/app/assets/modal.js +120 -0
- package/dist/engineering-pa-workspace/app/assets/theme.css +132 -0
- package/dist/engineering-pa-workspace/app/assets/theme.js +159 -0
- package/dist/engineering-pa-workspace/app/banner.js +320 -0
- package/dist/engineering-pa-workspace/app/delegations.html +345 -0
- package/dist/engineering-pa-workspace/app/home.html +1060 -0
- package/dist/engineering-pa-workspace/app/index.html +361 -0
- package/dist/engineering-pa-workspace/app/knowledge-map.html +163 -0
- package/dist/engineering-pa-workspace/app/knowledge.html +304 -0
- package/dist/engineering-pa-workspace/app/nav.json +75 -0
- package/dist/engineering-pa-workspace/app/notes.html +199 -0
- package/dist/engineering-pa-workspace/app/onboarding.html +592 -0
- package/dist/engineering-pa-workspace/app/profile.html +243 -0
- package/dist/engineering-pa-workspace/app/project-detail.html +432 -0
- package/dist/engineering-pa-workspace/app/projects.html +297 -0
- package/dist/engineering-pa-workspace/app/repos.html +598 -0
- package/dist/engineering-pa-workspace/app/schedules.html +486 -0
- package/dist/engineering-pa-workspace/app/secrets.html +164 -0
- package/dist/engineering-pa-workspace/app/staging.html +319 -0
- package/dist/engineering-pa-workspace/app/tasks.html +465 -0
- package/dist/engineering-pa-workspace/app/vendor/chart.umd.min.js +21 -0
- package/dist/engineering-pa-workspace/app/viewer.html +116 -0
- package/dist/engineering-pa-workspace/docs/DAEMON.md +104 -0
- package/dist/engineering-pa-workspace/docs/page-blueprint.md +286 -0
- package/dist/engineering-pa-workspace/docs/status-mon.md +168 -0
- package/dist/engineering-pa-workspace/index.mjs +12 -0
- package/dist/engineering-pa-workspace/nav.json.example +8 -0
- package/dist/engineering-pa-workspace/package.json +27 -0
- package/dist/engineering-pa-workspace/src/api.mjs +2086 -0
- package/dist/engineering-pa-workspace/src/install-daemon.mjs +573 -0
- package/dist/engineering-pa-workspace/src/nav.mjs +190 -0
- package/dist/engineering-pa-workspace/src/secrets-api.mjs +175 -0
- package/dist/engineering-pa-workspace/src/server.mjs +516 -0
- package/dist/engineering-pa-workspace/src/status-mon/poll.mjs +220 -0
- package/dist/engineering-pa-workspace/src/status-mon/poller.mjs +113 -0
- package/dist/engineering-pa-workspace/src/status-mon/run.mjs +133 -0
- package/dist/engineering-pa-workspace/src/supervisor.mjs +264 -0
- package/dist/engineering-pa-workspace/src/ws.mjs +633 -0
- package/index.mjs +60 -0
- package/package.json +58 -0
- package/templates/banned-ai-tells.md +102 -0
- package/templates/purpose.md +105 -0
- package/templates/voice-guide.md +98 -0
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
// Session store — the WRITE CHOKEPOINT (tooling standard §7).
|
|
2
|
+
//
|
|
3
|
+
// Every filesystem mutation for session state (mkdir, writeFile, rm) lives in
|
|
4
|
+
// this module and nowhere else. Validators are pure; commands read via the
|
|
5
|
+
// helpers here but never call fs.writeFile directly. There is deliberately no
|
|
6
|
+
// "write arbitrary path" API — callers write whole, validated session artifacts.
|
|
7
|
+
//
|
|
8
|
+
// Reads MAY fan out (tooling standard §7: "Reads may be scattered; writes may
|
|
9
|
+
// not"), but for convenience the common reads live here too since path
|
|
10
|
+
// resolution does.
|
|
11
|
+
//
|
|
12
|
+
// Error → exit-code mapping (translated to process.exit only in cli.mjs):
|
|
13
|
+
// session/file not found → 2 (operational)
|
|
14
|
+
// malformed JSON / failed schema → 2 (from the validators)
|
|
15
|
+
// disk read/write/mkdir/rm error → 3 (transport/IO)
|
|
16
|
+
|
|
17
|
+
import { mkdir, writeFile, readFile, readdir, rm } from 'node:fs/promises';
|
|
18
|
+
import { existsSync } from 'node:fs';
|
|
19
|
+
import { join } from 'node:path';
|
|
20
|
+
import { randomBytes } from 'node:crypto';
|
|
21
|
+
|
|
22
|
+
import { getRepoRoot } from '../../pa/repo-root.mjs';
|
|
23
|
+
import { validateManifest, loadManifest } from './manifest.mjs';
|
|
24
|
+
import { validatePlan, loadPlan } from './plan.mjs';
|
|
25
|
+
import { validateSources, loadSources } from './sources.mjs';
|
|
26
|
+
import { validateGates, loadGates } from './gates.mjs';
|
|
27
|
+
import { validateFinding, loadFinding } from './findings.mjs';
|
|
28
|
+
|
|
29
|
+
// Where session directories live inside the operator repo. Historical shape:
|
|
30
|
+
// when the tool sat at `operator/extensions/tools/research/`, sessions were
|
|
31
|
+
// `<that dir>/sessions/`. After promotion into `@stravica-ai/digital-operator-pa`, the
|
|
32
|
+
// package can no longer host runtime state — sessions must land in the
|
|
33
|
+
// operator repo. `.cache/research/sessions/` matches the operational-artefact
|
|
34
|
+
// convention (`.cache/distill/`, `.cache/estate-sync/`); already gitignore-friendly.
|
|
35
|
+
export const SESSIONS_SUBPATH = '.cache/research/sessions';
|
|
36
|
+
|
|
37
|
+
// Resolve the default sessions dir from the operator repo root. Async because
|
|
38
|
+
// getRepoRoot walks upward for `.git` (or reads $DAVE_REPO_ROOT / $PA_REPO_ROOT).
|
|
39
|
+
// Callers that already know the sessions dir (tests, alternative operators)
|
|
40
|
+
// pass it into `makeStore(dir)` directly and never hit this.
|
|
41
|
+
export async function defaultSessionsDir() {
|
|
42
|
+
return join(await getRepoRoot(), SESSIONS_SUBPATH);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Statuses a session cannot leave — `done`/`aborted` are one-way ends.
|
|
46
|
+
const TERMINAL_STATUSES = new Set(['done', 'aborted']);
|
|
47
|
+
|
|
48
|
+
// ── id generation ─────────────────────────────────────────────────────────────
|
|
49
|
+
// ULID-like: 26-char Crockford base32 = 10-char millisecond timestamp (48 bits,
|
|
50
|
+
// lexicographically sortable by creation time) + 16-char entropy (80 bits from
|
|
51
|
+
// crypto.randomBytes → collision-safe). Uppercase, excludes I L O U to stay
|
|
52
|
+
// unambiguous. node:crypto is stdlib, so this stays zero-dependency.
|
|
53
|
+
const CROCKFORD = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
|
|
54
|
+
const SESSION_ID_RE = /^[0-9A-HJKMNP-TV-Z]{26}$/;
|
|
55
|
+
|
|
56
|
+
function encodeTime(ms) {
|
|
57
|
+
let n = ms;
|
|
58
|
+
let out = '';
|
|
59
|
+
for (let i = 0; i < 10; i++) {
|
|
60
|
+
const mod = n % 32;
|
|
61
|
+
out = CROCKFORD[mod] + out;
|
|
62
|
+
n = (n - mod) / 32;
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function encodeEntropy() {
|
|
68
|
+
const bytes = randomBytes(16); // 256 is a multiple of 32 → low 5 bits are unbiased
|
|
69
|
+
let out = '';
|
|
70
|
+
for (let i = 0; i < 16; i++) out += CROCKFORD[bytes[i] & 0x1f];
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function newSessionId(now = Date.now()) {
|
|
75
|
+
return encodeTime(now) + encodeEntropy();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function isValidSessionId(id) {
|
|
79
|
+
return typeof id === 'string' && SESSION_ID_RE.test(id);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// ── error helpers ─────────────────────────────────────────────────────────────
|
|
83
|
+
function notFound(msg) {
|
|
84
|
+
return Object.assign(new Error(msg), { exitCode: 2 });
|
|
85
|
+
}
|
|
86
|
+
function ioFail(msg, cause) {
|
|
87
|
+
return Object.assign(new Error(`${msg}: ${cause && cause.message ? cause.message : cause}`), { exitCode: 3 });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ── store factory ─────────────────────────────────────────────────────────────
|
|
91
|
+
// makeStore(dir) binds all paths + IO to `dir`. Tests pass a temp dir. Commands
|
|
92
|
+
// that don't know the dir up-front go through `getDefaultStore()` (below), which
|
|
93
|
+
// resolves via getRepoRoot() and caches — same lazy pattern `pa knowledge` uses.
|
|
94
|
+
export function makeStore(sessionsDir) {
|
|
95
|
+
if (!sessionsDir) {
|
|
96
|
+
throw new Error('makeStore(sessionsDir) requires an explicit sessions dir; use getDefaultStore() for the operator-repo default');
|
|
97
|
+
}
|
|
98
|
+
function sessionDir(id) { return join(sessionsDir, id); }
|
|
99
|
+
function paths(id) {
|
|
100
|
+
const dir = sessionDir(id);
|
|
101
|
+
return {
|
|
102
|
+
dir,
|
|
103
|
+
manifest: join(dir, 'manifest.json'),
|
|
104
|
+
plan: join(dir, 'plan.json'),
|
|
105
|
+
sources: join(dir, 'sources.json'),
|
|
106
|
+
gates: join(dir, 'gates.json'),
|
|
107
|
+
answer: join(dir, 'answer.md'),
|
|
108
|
+
findingsDir: join(dir, 'findings'),
|
|
109
|
+
gatedDir: join(dir, 'gated'),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function exists(id) { return existsSync(join(sessionsDir, id, 'manifest.json')); }
|
|
114
|
+
|
|
115
|
+
// Sole low-level write. Serialises pretty JSON with a trailing newline.
|
|
116
|
+
async function writeJson(path, obj) {
|
|
117
|
+
try {
|
|
118
|
+
await writeFile(path, JSON.stringify(obj, null, 2) + '\n', 'utf8');
|
|
119
|
+
} catch (e) {
|
|
120
|
+
throw ioFail(`failed to write ${path}`, e);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async function ensureDir(dir) {
|
|
125
|
+
try {
|
|
126
|
+
await mkdir(dir, { recursive: true });
|
|
127
|
+
} catch (e) {
|
|
128
|
+
throw ioFail(`failed to create ${dir}`, e);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async function readText(path, whatMissing) {
|
|
133
|
+
try {
|
|
134
|
+
return await readFile(path, 'utf8');
|
|
135
|
+
} catch (e) {
|
|
136
|
+
if (e.code === 'ENOENT') throw notFound(whatMissing);
|
|
137
|
+
throw ioFail(`failed to read ${path}`, e);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Create a fresh session directory with its four store files. `plan`,
|
|
142
|
+
// `sources`, `gates` are optional; manifest is mandatory. Validates every
|
|
143
|
+
// artifact before it touches disk.
|
|
144
|
+
async function createSession({ manifest, plan, sources, gates }) {
|
|
145
|
+
validateManifest(manifest);
|
|
146
|
+
const p = paths(manifest.sessionId);
|
|
147
|
+
await ensureDir(p.dir);
|
|
148
|
+
await writeJson(p.manifest, manifest);
|
|
149
|
+
if (plan !== undefined) { validatePlan(plan); await writeJson(p.plan, plan); }
|
|
150
|
+
if (sources !== undefined) { validateSources(sources); await writeJson(p.sources, sources); }
|
|
151
|
+
if (gates !== undefined) { validateGates(gates); await writeJson(p.gates, gates); }
|
|
152
|
+
return manifest.sessionId;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async function writeManifest(id, manifest) {
|
|
156
|
+
validateManifest(manifest);
|
|
157
|
+
await writeJson(paths(id).manifest, manifest);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Atomic status transition through the chokepoint: read → guard → validate →
|
|
161
|
+
// write. Refuses to move a session out of a TERMINAL status (done/aborted) —
|
|
162
|
+
// finalising is one-way, so this is an operational failure (exit 2), matching
|
|
163
|
+
// the "explicit filter matched nothing" posture in prune. `nowIso` is injected
|
|
164
|
+
// (the store stays clock-agnostic; the command binds the clock).
|
|
165
|
+
async function updateManifestStatus(id, nextStatus, nowIso) {
|
|
166
|
+
const manifest = await readManifest(id); // exit 2 if missing / malformed
|
|
167
|
+
if (TERMINAL_STATUSES.has(manifest.status)) {
|
|
168
|
+
throw notFound(`session ${id} is already ${manifest.status}; cannot mark ${nextStatus}`);
|
|
169
|
+
}
|
|
170
|
+
const updated = { ...manifest, status: nextStatus, updatedAt: nowIso };
|
|
171
|
+
await writeManifest(id, updated); // validates before persist
|
|
172
|
+
return updated;
|
|
173
|
+
}
|
|
174
|
+
async function writePlan(id, plan) {
|
|
175
|
+
validatePlan(plan);
|
|
176
|
+
await writeJson(paths(id).plan, plan);
|
|
177
|
+
}
|
|
178
|
+
async function writeSources(id, sources) {
|
|
179
|
+
validateSources(sources);
|
|
180
|
+
await writeJson(paths(id).sources, sources);
|
|
181
|
+
}
|
|
182
|
+
async function writeGates(id, gates) {
|
|
183
|
+
validateGates(gates);
|
|
184
|
+
await writeJson(paths(id).gates, gates);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async function deleteSession(id) {
|
|
188
|
+
try {
|
|
189
|
+
await rm(sessionDir(id), { recursive: true, force: true });
|
|
190
|
+
} catch (e) {
|
|
191
|
+
throw ioFail(`failed to delete session ${id}`, e);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// ── reads ───────────────────────────────────────────────────────────────────
|
|
196
|
+
async function readManifest(id) {
|
|
197
|
+
const text = await readText(paths(id).manifest, `session ${id} not found`);
|
|
198
|
+
return loadManifest(text, `session ${id} manifest`);
|
|
199
|
+
}
|
|
200
|
+
async function readPlan(id) {
|
|
201
|
+
const text = await readText(paths(id).plan, `session ${id} has no plan.json`);
|
|
202
|
+
return loadPlan(text, `session ${id} plan`);
|
|
203
|
+
}
|
|
204
|
+
async function readSources(id) {
|
|
205
|
+
if (!existsSync(paths(id).sources)) return { items: [] };
|
|
206
|
+
const text = await readText(paths(id).sources, `session ${id} has no sources.json`);
|
|
207
|
+
return loadSources(text, `session ${id} sources`);
|
|
208
|
+
}
|
|
209
|
+
async function readGates(id) {
|
|
210
|
+
if (!existsSync(paths(id).gates)) return { queue: [] };
|
|
211
|
+
const text = await readText(paths(id).gates, `session ${id} has no gates.json`);
|
|
212
|
+
return loadGates(text, `session ${id} gates`);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// The session answer is worker-written (Finalise phase), free-form Markdown —
|
|
216
|
+
// no schema. Returns the raw text, or null when the session was never
|
|
217
|
+
// finalised (answer.md absent). Promotion reads it verbatim; a missing answer
|
|
218
|
+
// is a soft skip, not an error, so we don't throw here.
|
|
219
|
+
async function readAnswer(id) {
|
|
220
|
+
const p = paths(id).answer;
|
|
221
|
+
if (!existsSync(p)) return null;
|
|
222
|
+
try {
|
|
223
|
+
return await readFile(p, 'utf8');
|
|
224
|
+
} catch (e) {
|
|
225
|
+
throw ioFail(`failed to read answer for ${id}`, e);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Findings are worker-written at findings/sq-<id>.json. Read + validate all.
|
|
230
|
+
async function listFindings(id) {
|
|
231
|
+
const dir = paths(id).findingsDir;
|
|
232
|
+
let entries;
|
|
233
|
+
try {
|
|
234
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
235
|
+
} catch (e) {
|
|
236
|
+
if (e.code === 'ENOENT') return [];
|
|
237
|
+
throw ioFail(`failed to read findings for ${id}`, e);
|
|
238
|
+
}
|
|
239
|
+
const files = entries
|
|
240
|
+
.filter((e) => e.isFile() && e.name.endsWith('.json'))
|
|
241
|
+
.map((e) => e.name)
|
|
242
|
+
.sort();
|
|
243
|
+
const out = [];
|
|
244
|
+
for (const name of files) {
|
|
245
|
+
const text = await readText(join(dir, name), `finding ${name} vanished`);
|
|
246
|
+
out.push(loadFinding(text, `session ${id} finding ${name}`));
|
|
247
|
+
}
|
|
248
|
+
return out;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// List every session, newest first (sessionId sorts by creation time).
|
|
252
|
+
// Malformed sessions are surfaced with an error marker rather than silently
|
|
253
|
+
// dropped — `show` can then diagnose them.
|
|
254
|
+
async function listSessions() {
|
|
255
|
+
let entries;
|
|
256
|
+
try {
|
|
257
|
+
entries = await readdir(sessionsDir, { withFileTypes: true });
|
|
258
|
+
} catch (e) {
|
|
259
|
+
if (e.code === 'ENOENT') return [];
|
|
260
|
+
throw ioFail(`failed to read sessions dir`, e);
|
|
261
|
+
}
|
|
262
|
+
const ids = entries.filter((e) => e.isDirectory()).map((e) => e.name).sort().reverse();
|
|
263
|
+
const out = [];
|
|
264
|
+
for (const id of ids) {
|
|
265
|
+
try {
|
|
266
|
+
const manifest = await readManifest(id);
|
|
267
|
+
out.push({ id, manifest, error: null });
|
|
268
|
+
} catch (e) {
|
|
269
|
+
out.push({ id, manifest: null, error: e.message });
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return out;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return {
|
|
276
|
+
sessionsDir,
|
|
277
|
+
newSessionId,
|
|
278
|
+
isValidSessionId,
|
|
279
|
+
sessionDir,
|
|
280
|
+
paths,
|
|
281
|
+
exists,
|
|
282
|
+
createSession,
|
|
283
|
+
writeManifest,
|
|
284
|
+
updateManifestStatus,
|
|
285
|
+
writePlan,
|
|
286
|
+
writeSources,
|
|
287
|
+
writeGates,
|
|
288
|
+
deleteSession,
|
|
289
|
+
readManifest,
|
|
290
|
+
readPlan,
|
|
291
|
+
readSources,
|
|
292
|
+
readGates,
|
|
293
|
+
readAnswer,
|
|
294
|
+
listFindings,
|
|
295
|
+
listSessions,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Cached default store, resolved lazily via getRepoRoot(). Commands call this
|
|
300
|
+
// when the caller didn't inject a store; tests inject via makeStore(tmpDir).
|
|
301
|
+
let _defaultStore = null;
|
|
302
|
+
export async function getDefaultStore() {
|
|
303
|
+
if (_defaultStore) return _defaultStore;
|
|
304
|
+
const dir = await defaultSessionsDir();
|
|
305
|
+
_defaultStore = makeStore(dir);
|
|
306
|
+
return _defaultStore;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Test seam: drop the cached default so a fresh env/cwd is picked up.
|
|
310
|
+
export function _resetDefaultStore() {
|
|
311
|
+
_defaultStore = null;
|
|
312
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// manifest.json schema + validator (build-spec §3–§6). Zero-dep, hand-rolled.
|
|
2
|
+
// Schema doc: src/schema/manifest.schema.json.
|
|
3
|
+
import {
|
|
4
|
+
parseJson, requireObject, requireFields, noExtraFields,
|
|
5
|
+
requireString, optionalString, requireEnum, requireArray, requireInteger, fail,
|
|
6
|
+
} from './validate.mjs';
|
|
7
|
+
|
|
8
|
+
export const MODES = ['light', 'normal', 'deep'];
|
|
9
|
+
export const GATE_POLICIES = ['operatorPresent', 'background', 'worker'];
|
|
10
|
+
export const STATUSES = ['draft', 'in-progress', 'done', 'aborted'];
|
|
11
|
+
export const OUTPUT_MODES = ['shortAnswer', 'article', 'structured'];
|
|
12
|
+
|
|
13
|
+
const TOP = [
|
|
14
|
+
'sessionId', 'mode', 'question', 'intent', 'gatePolicy', 'status',
|
|
15
|
+
'outputMode', 'budget', 'assumptions', 'createdAt', 'updatedAt',
|
|
16
|
+
];
|
|
17
|
+
const REQUIRED = [
|
|
18
|
+
'sessionId', 'mode', 'question', 'gatePolicy', 'status',
|
|
19
|
+
'outputMode', 'budget', 'assumptions', 'createdAt', 'updatedAt',
|
|
20
|
+
];
|
|
21
|
+
const SESSION_ID_RE = /^[0-9A-HJKMNP-TV-Z]{26}$/;
|
|
22
|
+
const BUDGET_FIELDS = ['maxSubQuestions', 'maxDeepeningRounds', 'wallClockMinutes'];
|
|
23
|
+
|
|
24
|
+
export function loadManifest(text, where = 'manifest') {
|
|
25
|
+
return validateManifest(parseJson(text, where), where);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function validateManifest(m, where = 'manifest') {
|
|
29
|
+
requireObject(m, where);
|
|
30
|
+
requireFields(m, REQUIRED, where);
|
|
31
|
+
noExtraFields(m, TOP, where);
|
|
32
|
+
|
|
33
|
+
const sessionId = requireString(m, 'sessionId', where);
|
|
34
|
+
if (!SESSION_ID_RE.test(sessionId)) fail('sessionId is not a valid ULID-like id', where);
|
|
35
|
+
|
|
36
|
+
requireEnum(m, 'mode', MODES, where);
|
|
37
|
+
requireString(m, 'question', where);
|
|
38
|
+
optionalString(m, 'intent', where);
|
|
39
|
+
requireEnum(m, 'gatePolicy', GATE_POLICIES, where);
|
|
40
|
+
requireEnum(m, 'status', STATUSES, where);
|
|
41
|
+
requireEnum(m, 'outputMode', OUTPUT_MODES, where);
|
|
42
|
+
|
|
43
|
+
requireObject(m.budget, `${where}.budget`);
|
|
44
|
+
requireFields(m.budget, BUDGET_FIELDS, `${where}.budget`);
|
|
45
|
+
noExtraFields(m.budget, BUDGET_FIELDS, `${where}.budget`);
|
|
46
|
+
for (const f of BUDGET_FIELDS) requireInteger(m.budget, f, `${where}.budget`, { min: 0 });
|
|
47
|
+
|
|
48
|
+
const assumptions = requireArray(m, 'assumptions', where);
|
|
49
|
+
assumptions.forEach((a, i) => {
|
|
50
|
+
if (typeof a !== 'string') fail(`assumptions[${i}] must be a string`, where);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
requireString(m, 'createdAt', where);
|
|
54
|
+
requireString(m, 'updatedAt', where);
|
|
55
|
+
return m;
|
|
56
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// plan.json schema + validator (build-spec §4/§5). Zero-dep, hand-rolled.
|
|
2
|
+
// Schema doc: src/schema/plan.schema.json.
|
|
3
|
+
import {
|
|
4
|
+
parseJson, requireObject, requireFields, noExtraFields,
|
|
5
|
+
requireString, requireEnum, requireArray, requireInteger, fail,
|
|
6
|
+
} from './validate.mjs';
|
|
7
|
+
|
|
8
|
+
export const SQ_KINDS = ['independent', 'dependent'];
|
|
9
|
+
export const VERIFICATION_TIERS = ['none', 'central-3vote', 'diverse-lens-3vote'];
|
|
10
|
+
|
|
11
|
+
const TOP = ['subQuestions', 'deepeningRounds', 'verificationTier'];
|
|
12
|
+
const SQ_FIELDS = ['id', 'text', 'kind', 'dependsOn'];
|
|
13
|
+
|
|
14
|
+
// Mode-derived plan defaults. `run` writes the skeleton; the workflow (w-017)
|
|
15
|
+
// fills subQuestions. Single source of truth for the light/normal/deep mapping.
|
|
16
|
+
export const PLAN_DEFAULTS = {
|
|
17
|
+
light: { deepeningRounds: 0, verificationTier: 'none' },
|
|
18
|
+
normal: { deepeningRounds: 1, verificationTier: 'central-3vote' },
|
|
19
|
+
deep: { deepeningRounds: 3, verificationTier: 'diverse-lens-3vote' },
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// Build the skeleton plan for a mode (used by `run`).
|
|
23
|
+
export function skeletonPlan(mode) {
|
|
24
|
+
const d = PLAN_DEFAULTS[mode];
|
|
25
|
+
if (!d) throw Object.assign(new Error(`unknown mode "${mode}"`), { exitCode: 1 });
|
|
26
|
+
return { subQuestions: [], deepeningRounds: d.deepeningRounds, verificationTier: d.verificationTier };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function loadPlan(text, where = 'plan') {
|
|
30
|
+
return validatePlan(parseJson(text, where), where);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function validatePlan(p, where = 'plan') {
|
|
34
|
+
requireObject(p, where);
|
|
35
|
+
requireFields(p, TOP, where);
|
|
36
|
+
noExtraFields(p, TOP, where);
|
|
37
|
+
|
|
38
|
+
const sqs = requireArray(p, 'subQuestions', where);
|
|
39
|
+
const seen = new Set();
|
|
40
|
+
sqs.forEach((sq, i) => {
|
|
41
|
+
const w = `${where}.subQuestions[${i}]`;
|
|
42
|
+
requireObject(sq, w);
|
|
43
|
+
requireFields(sq, SQ_FIELDS, w);
|
|
44
|
+
noExtraFields(sq, SQ_FIELDS, w);
|
|
45
|
+
const id = requireString(sq, 'id', w);
|
|
46
|
+
if (seen.has(id)) fail(`duplicate sub-question id "${id}"`, w);
|
|
47
|
+
seen.add(id);
|
|
48
|
+
requireString(sq, 'text', w);
|
|
49
|
+
requireEnum(sq, 'kind', SQ_KINDS, w);
|
|
50
|
+
const deps = requireArray(sq, 'dependsOn', w);
|
|
51
|
+
deps.forEach((d, j) => {
|
|
52
|
+
if (typeof d !== 'string') fail(`dependsOn[${j}] must be a string`, w);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
requireInteger(p, 'deepeningRounds', where, { min: 0, max: 3 });
|
|
57
|
+
requireEnum(p, 'verificationTier', VERIFICATION_TIERS, where);
|
|
58
|
+
return p;
|
|
59
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// sources.json schema + validator (build-spec §2/§3). Zero-dep, hand-rolled.
|
|
2
|
+
// Schema doc: src/schema/sources.schema.json.
|
|
3
|
+
import {
|
|
4
|
+
parseJson, requireObject, requireFields, noExtraFields,
|
|
5
|
+
requireString, optionalString, requireEnum, requireArray, fail,
|
|
6
|
+
} from './validate.mjs';
|
|
7
|
+
|
|
8
|
+
export const SOURCE_KINDS = ['web', 'playwright', 'kb', 'codebase', 'prior-session'];
|
|
9
|
+
|
|
10
|
+
const TOP = ['items'];
|
|
11
|
+
const ITEM_FIELDS = ['id', 'kind', 'url', 'title', 'fetchedAt', 'checksum'];
|
|
12
|
+
const ITEM_REQUIRED = ['id', 'kind'];
|
|
13
|
+
|
|
14
|
+
export function emptySources() {
|
|
15
|
+
return { items: [] };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function loadSources(text, where = 'sources') {
|
|
19
|
+
return validateSources(parseJson(text, where), where);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function validateSources(s, where = 'sources') {
|
|
23
|
+
requireObject(s, where);
|
|
24
|
+
requireFields(s, TOP, where);
|
|
25
|
+
noExtraFields(s, TOP, where);
|
|
26
|
+
|
|
27
|
+
const items = requireArray(s, 'items', where);
|
|
28
|
+
const seen = new Set();
|
|
29
|
+
items.forEach((it, i) => {
|
|
30
|
+
const w = `${where}.items[${i}]`;
|
|
31
|
+
requireObject(it, w);
|
|
32
|
+
requireFields(it, ITEM_REQUIRED, w);
|
|
33
|
+
noExtraFields(it, ITEM_FIELDS, w);
|
|
34
|
+
const id = requireString(it, 'id', w);
|
|
35
|
+
if (seen.has(id)) fail(`duplicate source id "${id}"`, w);
|
|
36
|
+
seen.add(id);
|
|
37
|
+
requireEnum(it, 'kind', SOURCE_KINDS, w);
|
|
38
|
+
optionalString(it, 'url', w);
|
|
39
|
+
optionalString(it, 'title', w);
|
|
40
|
+
optionalString(it, 'fetchedAt', w);
|
|
41
|
+
optionalString(it, 'checksum', w);
|
|
42
|
+
});
|
|
43
|
+
return s;
|
|
44
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// Shared hand-rolled validation helpers for the research session schemas.
|
|
2
|
+
//
|
|
3
|
+
// Zero-dep. No schema library (tooling standard §3). These are the primitives
|
|
4
|
+
// the per-schema validators in this directory are built from.
|
|
5
|
+
//
|
|
6
|
+
// A validation failure means "a session file on disk is malformed" — that is an
|
|
7
|
+
// operational failure, exit code 2 (tooling standard §6). Callers that validate
|
|
8
|
+
// *user input* (e.g. run's CLI flags) do that in cli.mjs and map to exit 1 there;
|
|
9
|
+
// by the time a manifest object reaches these validators it is expected to be valid,
|
|
10
|
+
// so a failure here is a genuine data-integrity problem.
|
|
11
|
+
|
|
12
|
+
// Throw a validation error carrying exit code 2 and a located message.
|
|
13
|
+
export function fail(msg, where) {
|
|
14
|
+
const err = new Error(`${where ? where + ': ' : ''}${msg}`);
|
|
15
|
+
err.exitCode = 2;
|
|
16
|
+
err.validation = true;
|
|
17
|
+
throw err;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function isObject(v) {
|
|
21
|
+
return v !== null && typeof v === 'object' && !Array.isArray(v);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function requireObject(v, where) {
|
|
25
|
+
if (!isObject(v)) fail('must be a JSON object', where);
|
|
26
|
+
return v;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function requireFields(obj, fields, where) {
|
|
30
|
+
for (const f of fields) {
|
|
31
|
+
if (!(f in obj)) fail(`missing required field "${f}"`, where);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function noExtraFields(obj, allowed, where) {
|
|
36
|
+
const set = new Set(allowed);
|
|
37
|
+
for (const k of Object.keys(obj)) {
|
|
38
|
+
if (!set.has(k)) fail(`unexpected field "${k}"`, where);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function requireString(obj, key, where, { nonEmpty = true } = {}) {
|
|
43
|
+
const v = obj[key];
|
|
44
|
+
if (typeof v !== 'string') fail(`"${key}" must be a string`, where);
|
|
45
|
+
if (nonEmpty && v.length === 0) fail(`"${key}" must be non-empty`, where);
|
|
46
|
+
return v;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function optionalString(obj, key, where) {
|
|
50
|
+
if (!(key in obj) || obj[key] == null) return undefined;
|
|
51
|
+
if (typeof obj[key] !== 'string') fail(`"${key}" must be a string if present`, where);
|
|
52
|
+
return obj[key];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function requireEnum(obj, key, allowed, where) {
|
|
56
|
+
const v = obj[key];
|
|
57
|
+
if (!allowed.includes(v)) fail(`"${key}" must be one of ${allowed.join(' | ')} (got ${JSON.stringify(v)})`, where);
|
|
58
|
+
return v;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function optionalEnum(obj, key, allowed, where) {
|
|
62
|
+
if (!(key in obj) || obj[key] == null) return undefined;
|
|
63
|
+
return requireEnum(obj, key, allowed, where);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function requireArray(obj, key, where) {
|
|
67
|
+
const v = obj[key];
|
|
68
|
+
if (!Array.isArray(v)) fail(`"${key}" must be an array`, where);
|
|
69
|
+
return v;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function requireBoolean(obj, key, where) {
|
|
73
|
+
if (typeof obj[key] !== 'boolean') fail(`"${key}" must be a boolean`, where);
|
|
74
|
+
return obj[key];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function requireInteger(obj, key, where, { min, max } = {}) {
|
|
78
|
+
const v = obj[key];
|
|
79
|
+
if (typeof v !== 'number' || !Number.isInteger(v)) fail(`"${key}" must be an integer`, where);
|
|
80
|
+
if (min != null && v < min) fail(`"${key}" must be >= ${min}`, where);
|
|
81
|
+
if (max != null && v > max) fail(`"${key}" must be <= ${max}`, where);
|
|
82
|
+
return v;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Parse JSON text, failing with exit code 2 on malformed JSON.
|
|
86
|
+
export function parseJson(text, where) {
|
|
87
|
+
try {
|
|
88
|
+
return JSON.parse(text);
|
|
89
|
+
} catch (e) {
|
|
90
|
+
fail(`not valid JSON: ${e.message}`, where);
|
|
91
|
+
}
|
|
92
|
+
}
|