@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,164 @@
|
|
|
1
|
+
// work-cli.mjs — argv router for `pa work <verb>`.
|
|
2
|
+
//
|
|
3
|
+
// Verbs:
|
|
4
|
+
// pa work create [--project <id>] --title "..." --category <c> [--priority N] [--summary "..."] [--owner ...] [--assignee ...]
|
|
5
|
+
// pa work status <id> <status>
|
|
6
|
+
// pa work list [--project <id>] [--status ...] [--mine] [--theirs] [--all] [--json]
|
|
7
|
+
//
|
|
8
|
+
// PA name (for --mine resolution) is read from
|
|
9
|
+
// operator/config/preferences.json. Falls back to 'pa' if missing.
|
|
10
|
+
|
|
11
|
+
import { readFile } from 'node:fs/promises';
|
|
12
|
+
import { join } from 'node:path';
|
|
13
|
+
|
|
14
|
+
import { createWork, setWorkStatus, listWork } from './work.mjs';
|
|
15
|
+
import { getRepoRoot } from './repo-root.mjs';
|
|
16
|
+
|
|
17
|
+
const USAGE = `pa work — manage operator-repo work items
|
|
18
|
+
|
|
19
|
+
Usage:
|
|
20
|
+
pa work create [--project <id>] --title "..." --category <feature|bug|chore|discussion|research>
|
|
21
|
+
[--priority 0|1|2|3] [--summary "..."] [--owner ...] [--assignee ...]
|
|
22
|
+
pa work status <id> <draft|planned|in-progress|blocked|done|archived>
|
|
23
|
+
pa work list [--project <id>] [--status ...] [--category ...] [--mine] [--theirs] [--all] [--json]
|
|
24
|
+
pa work -h, --help
|
|
25
|
+
|
|
26
|
+
Notes:
|
|
27
|
+
- status=done stamps \`completedAt\` to today (only if not already set).
|
|
28
|
+
- --mine resolves the PA name from operator/config/preferences.json
|
|
29
|
+
(paName / agentName). Default: "pa".
|
|
30
|
+
|
|
31
|
+
Exit codes:
|
|
32
|
+
0 ok | 1 usage/not-found | 2 operational failure
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
export async function run(argv) {
|
|
36
|
+
if (!argv.length || argv[0] === '-h' || argv[0] === '--help') {
|
|
37
|
+
process.stdout.write(USAGE);
|
|
38
|
+
return 0;
|
|
39
|
+
}
|
|
40
|
+
const verb = argv[0];
|
|
41
|
+
const rest = argv.slice(1);
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
switch (verb) {
|
|
45
|
+
case 'create': return await doCreate(rest);
|
|
46
|
+
case 'status': return await doStatus(rest);
|
|
47
|
+
case 'list': return await doList(rest);
|
|
48
|
+
default:
|
|
49
|
+
process.stderr.write(`[pa work] unknown verb: ${verb}\n`);
|
|
50
|
+
process.stderr.write(USAGE);
|
|
51
|
+
return 1;
|
|
52
|
+
}
|
|
53
|
+
} catch (err) {
|
|
54
|
+
process.stderr.write(`[pa work] ${err.message || err}\n`);
|
|
55
|
+
return err.exitCode || 2;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function parseFlags(args) {
|
|
60
|
+
const positional = [];
|
|
61
|
+
const flags = {};
|
|
62
|
+
for (let i = 0; i < args.length; i++) {
|
|
63
|
+
const a = args[i];
|
|
64
|
+
if (a.startsWith('--')) {
|
|
65
|
+
const key = a.slice(2);
|
|
66
|
+
const peek = args[i + 1];
|
|
67
|
+
if (peek == null || peek.startsWith('--')) {
|
|
68
|
+
flags[key] = true;
|
|
69
|
+
} else {
|
|
70
|
+
flags[key] = peek;
|
|
71
|
+
i += 1;
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
positional.push(a);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return { positional, flags };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function getPaName() {
|
|
81
|
+
try {
|
|
82
|
+
const repoRoot = await getRepoRoot();
|
|
83
|
+
const raw = await readFile(
|
|
84
|
+
join(repoRoot, 'operator', 'config', 'preferences.json'),
|
|
85
|
+
'utf8',
|
|
86
|
+
);
|
|
87
|
+
const config = JSON.parse(raw);
|
|
88
|
+
return config.paName || config.agentName || 'pa';
|
|
89
|
+
} catch {
|
|
90
|
+
return 'pa';
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function doCreate(args) {
|
|
95
|
+
const { flags } = parseFlags(args);
|
|
96
|
+
const priority = flags.priority != null && flags.priority !== true
|
|
97
|
+
? Number(flags.priority)
|
|
98
|
+
: null;
|
|
99
|
+
const res = await createWork({
|
|
100
|
+
projectId: typeof flags.project === 'string' ? flags.project : null,
|
|
101
|
+
title: typeof flags.title === 'string' ? flags.title : null,
|
|
102
|
+
category: typeof flags.category === 'string' ? flags.category : null,
|
|
103
|
+
priority,
|
|
104
|
+
summary: typeof flags.summary === 'string' ? flags.summary : null,
|
|
105
|
+
owner: typeof flags.owner === 'string' ? flags.owner : null,
|
|
106
|
+
assignee: typeof flags.assignee === 'string' ? flags.assignee : null,
|
|
107
|
+
});
|
|
108
|
+
process.stdout.write(`created ${res.id}\n`);
|
|
109
|
+
process.stdout.write(` ${res.path}\n`);
|
|
110
|
+
return 0;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function doStatus(args) {
|
|
114
|
+
if (args.length < 2) {
|
|
115
|
+
process.stderr.write('usage: pa work status <id> <status>\n');
|
|
116
|
+
return 1;
|
|
117
|
+
}
|
|
118
|
+
const [id, status] = args;
|
|
119
|
+
const res = await setWorkStatus(id, status);
|
|
120
|
+
process.stdout.write(`work ${res.id} → ${res.status}\n`);
|
|
121
|
+
if (res.completedAt && status === 'done') {
|
|
122
|
+
process.stdout.write(` completedAt: ${res.completedAt}\n`);
|
|
123
|
+
}
|
|
124
|
+
return 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async function doList(args) {
|
|
128
|
+
const { flags } = parseFlags(args);
|
|
129
|
+
const paName = (flags.mine || flags.theirs) ? await getPaName() : null;
|
|
130
|
+
const items = await listWork({
|
|
131
|
+
all: flags.all === true,
|
|
132
|
+
status: typeof flags.status === 'string' ? flags.status : null,
|
|
133
|
+
category: typeof flags.category === 'string' ? flags.category : null,
|
|
134
|
+
project: typeof flags.project === 'string' ? flags.project : null,
|
|
135
|
+
owner: typeof flags.owner === 'string' ? flags.owner : null,
|
|
136
|
+
assignee: typeof flags.assignee === 'string' ? flags.assignee : null,
|
|
137
|
+
mine: flags.mine === true,
|
|
138
|
+
theirs: flags.theirs === true,
|
|
139
|
+
paName,
|
|
140
|
+
});
|
|
141
|
+
if (flags.json) {
|
|
142
|
+
process.stdout.write(JSON.stringify(items, null, 2) + '\n');
|
|
143
|
+
return 0;
|
|
144
|
+
}
|
|
145
|
+
if (!items.length) {
|
|
146
|
+
process.stdout.write('no work items match\n');
|
|
147
|
+
return 0;
|
|
148
|
+
}
|
|
149
|
+
const rows = items.map((w) => ({
|
|
150
|
+
id: w.id,
|
|
151
|
+
status: w.status || 'draft',
|
|
152
|
+
priority: w.priority == null ? '-' : `P${w.priority}`,
|
|
153
|
+
project: w.projectId || '-',
|
|
154
|
+
title: (w.title || '').slice(0, 60),
|
|
155
|
+
}));
|
|
156
|
+
const cols = ['id', 'status', 'priority', 'project', 'title'];
|
|
157
|
+
const widths = {};
|
|
158
|
+
for (const c of cols) widths[c] = Math.max(c.length, ...rows.map((r) => String(r[c]).length));
|
|
159
|
+
const pad = (s, w) => String(s).padEnd(w, ' ');
|
|
160
|
+
process.stdout.write(cols.map((c) => pad(c, widths[c])).join(' ') + '\n');
|
|
161
|
+
process.stdout.write(cols.map((c) => '-'.repeat(widths[c])).join(' ') + '\n');
|
|
162
|
+
for (const r of rows) process.stdout.write(cols.map((c) => pad(r[c], widths[c])).join(' ') + '\n');
|
|
163
|
+
return 0;
|
|
164
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
// work.mjs — write-side commands for `pa work <verb>`.
|
|
2
|
+
//
|
|
3
|
+
// Source of truth is work/w-YYYY-MM-DD-NNN.json. We never cache.
|
|
4
|
+
//
|
|
5
|
+
// What lives here:
|
|
6
|
+
// - create: scaffold a new work item with the next-free NNN for today
|
|
7
|
+
// - status: change status (stamps `completedAt` on done)
|
|
8
|
+
// - list: list work items, optionally filtered
|
|
9
|
+
//
|
|
10
|
+
// ID format and status/category enums match
|
|
11
|
+
// packages/core/schema/work-item.json.
|
|
12
|
+
|
|
13
|
+
import { existsSync } from 'node:fs';
|
|
14
|
+
import { join } from 'node:path';
|
|
15
|
+
|
|
16
|
+
import { getRepoRoot } from './repo-root.mjs';
|
|
17
|
+
import { readJson, writeJson, ensureDir, listJsonFiles, today } from './io.mjs';
|
|
18
|
+
|
|
19
|
+
const STATUSES = new Set(['draft', 'planned', 'in-progress', 'blocked', 'done', 'archived']);
|
|
20
|
+
|
|
21
|
+
const CATEGORIES = new Set(['feature', 'bug', 'chore', 'discussion', 'research']);
|
|
22
|
+
|
|
23
|
+
const ID_RE = /^w-(\d{4}-\d{2}-\d{2})-(\d{3})$/;
|
|
24
|
+
|
|
25
|
+
function validateStatus(status) {
|
|
26
|
+
if (!STATUSES.has(status)) {
|
|
27
|
+
const err = new Error(
|
|
28
|
+
`invalid status: ${status} (expected one of: ${[...STATUSES].join(', ')})`,
|
|
29
|
+
);
|
|
30
|
+
err.exitCode = 1;
|
|
31
|
+
throw err;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function validateCategory(category) {
|
|
36
|
+
if (!category) return;
|
|
37
|
+
if (!CATEGORIES.has(category)) {
|
|
38
|
+
const err = new Error(
|
|
39
|
+
`invalid category: ${category} (expected one of: ${[...CATEGORIES].join(', ')})`,
|
|
40
|
+
);
|
|
41
|
+
err.exitCode = 1;
|
|
42
|
+
throw err;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function validatePriority(priority) {
|
|
47
|
+
if (priority == null) return;
|
|
48
|
+
if (!Number.isInteger(priority) || priority < 0 || priority > 3) {
|
|
49
|
+
const err = new Error(`invalid priority: ${priority} (expected integer 0–3)`);
|
|
50
|
+
err.exitCode = 1;
|
|
51
|
+
throw err;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Scan work/*.json for the highest NNN with today's date. Returns the
|
|
57
|
+
* next free NNN, zero-padded to 3 digits. Result is always "001"–"999".
|
|
58
|
+
*
|
|
59
|
+
* If 999 is already taken, throws — callers should treat as an
|
|
60
|
+
* operational failure and report. In practice this is unreachable.
|
|
61
|
+
*/
|
|
62
|
+
async function nextWorkNumber(repoRoot, dateStr) {
|
|
63
|
+
const dir = join(repoRoot, 'work');
|
|
64
|
+
const files = await listJsonFiles(dir);
|
|
65
|
+
let max = 0;
|
|
66
|
+
const prefix = `w-${dateStr}-`;
|
|
67
|
+
for (const file of files) {
|
|
68
|
+
if (!file.startsWith(prefix)) continue;
|
|
69
|
+
const m = file.match(/^w-\d{4}-\d{2}-\d{2}-(\d{3})\.json$/);
|
|
70
|
+
if (!m) continue;
|
|
71
|
+
const n = parseInt(m[1], 10);
|
|
72
|
+
if (Number.isFinite(n) && n > max) max = n;
|
|
73
|
+
}
|
|
74
|
+
const next = max + 1;
|
|
75
|
+
if (next > 999) {
|
|
76
|
+
const err = new Error(`no free work-item slot for ${dateStr} (NNN exhausted)`);
|
|
77
|
+
err.exitCode = 2;
|
|
78
|
+
throw err;
|
|
79
|
+
}
|
|
80
|
+
return String(next).padStart(3, '0');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Create a new work item. Returns { id, path }.
|
|
85
|
+
*
|
|
86
|
+
* Status defaults to "draft" per the brief. Date and NNN are
|
|
87
|
+
* auto-derived from today; we do not accept overrides.
|
|
88
|
+
*/
|
|
89
|
+
export async function createWork(opts) {
|
|
90
|
+
if (!opts.title) {
|
|
91
|
+
const err = new Error('--title is required');
|
|
92
|
+
err.exitCode = 1;
|
|
93
|
+
throw err;
|
|
94
|
+
}
|
|
95
|
+
validateCategory(opts.category);
|
|
96
|
+
validatePriority(opts.priority);
|
|
97
|
+
|
|
98
|
+
const repoRoot = await getRepoRoot();
|
|
99
|
+
const workDir = join(repoRoot, 'work');
|
|
100
|
+
await ensureDir(workDir);
|
|
101
|
+
|
|
102
|
+
const dateStr = today();
|
|
103
|
+
const nnn = await nextWorkNumber(repoRoot, dateStr);
|
|
104
|
+
const id = `w-${dateStr}-${nnn}`;
|
|
105
|
+
const path = join(workDir, `${id}.json`);
|
|
106
|
+
|
|
107
|
+
const item = {
|
|
108
|
+
id,
|
|
109
|
+
projectId: opts.projectId || null,
|
|
110
|
+
title: opts.title,
|
|
111
|
+
category: opts.category || 'chore',
|
|
112
|
+
status: 'draft',
|
|
113
|
+
priority: opts.priority == null ? 2 : opts.priority,
|
|
114
|
+
owner: opts.owner || 'system-architect',
|
|
115
|
+
assignee: opts.assignee || opts.owner || 'system-architect',
|
|
116
|
+
created: dateStr,
|
|
117
|
+
updated: dateStr,
|
|
118
|
+
completedAt: null,
|
|
119
|
+
summary: opts.summary || '',
|
|
120
|
+
blocked: null,
|
|
121
|
+
links: [],
|
|
122
|
+
};
|
|
123
|
+
await writeJson(path, item);
|
|
124
|
+
return { id, path };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Set work-item status. Stamps `completedAt` to today's date when
|
|
129
|
+
* status=done (only if not already set). Always bumps `updated`.
|
|
130
|
+
*/
|
|
131
|
+
export async function setWorkStatus(id, status) {
|
|
132
|
+
if (!ID_RE.test(id)) {
|
|
133
|
+
const err = new Error(`invalid work id: ${id} (expected w-YYYY-MM-DD-NNN)`);
|
|
134
|
+
err.exitCode = 1;
|
|
135
|
+
throw err;
|
|
136
|
+
}
|
|
137
|
+
validateStatus(status);
|
|
138
|
+
|
|
139
|
+
const repoRoot = await getRepoRoot();
|
|
140
|
+
const path = join(repoRoot, 'work', `${id}.json`);
|
|
141
|
+
if (!existsSync(path)) {
|
|
142
|
+
const err = new Error(`work item not found: ${id}`);
|
|
143
|
+
err.exitCode = 1;
|
|
144
|
+
throw err;
|
|
145
|
+
}
|
|
146
|
+
const item = await readJson(path);
|
|
147
|
+
item.status = status;
|
|
148
|
+
item.updated = today();
|
|
149
|
+
if (status === 'done' && !item.completedAt) {
|
|
150
|
+
item.completedAt = today();
|
|
151
|
+
}
|
|
152
|
+
await writeJson(path, item);
|
|
153
|
+
return { id, status, completedAt: item.completedAt, path };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* List work items. Filters: status, category, project, owner, assignee,
|
|
158
|
+
* mine, theirs, all, paName (used for --mine resolution).
|
|
159
|
+
* By default excludes done + archived (mirrors desk-list semantics).
|
|
160
|
+
*/
|
|
161
|
+
export async function listWork(filters = {}) {
|
|
162
|
+
const repoRoot = await getRepoRoot();
|
|
163
|
+
const dir = join(repoRoot, 'work');
|
|
164
|
+
const files = await listJsonFiles(dir);
|
|
165
|
+
const items = [];
|
|
166
|
+
for (const f of files) {
|
|
167
|
+
try {
|
|
168
|
+
items.push(await readJson(join(dir, f)));
|
|
169
|
+
} catch {
|
|
170
|
+
// Skip unparseable.
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
let filtered = items;
|
|
174
|
+
if (!filters.all) {
|
|
175
|
+
filtered = filtered.filter((w) => !['done', 'archived'].includes(w.status));
|
|
176
|
+
}
|
|
177
|
+
if (filters.status) filtered = filtered.filter((w) => w.status === filters.status);
|
|
178
|
+
if (filters.category) filtered = filtered.filter((w) => w.category === filters.category);
|
|
179
|
+
if (filters.project) filtered = filtered.filter((w) => w.projectId === filters.project);
|
|
180
|
+
if (filters.owner) filtered = filtered.filter((w) => w.owner === filters.owner);
|
|
181
|
+
if (filters.assignee) filtered = filtered.filter((w) => w.assignee === filters.assignee);
|
|
182
|
+
if (filters.mine && filters.paName) filtered = filtered.filter((w) => w.assignee === filters.paName);
|
|
183
|
+
if (filters.theirs) filtered = filtered.filter((w) => w.assignee === 'operator');
|
|
184
|
+
|
|
185
|
+
const STATE_ORDER = ['in-progress', 'blocked', 'planned', 'draft', 'done', 'archived'];
|
|
186
|
+
filtered.sort((a, b) => {
|
|
187
|
+
const sa = STATE_ORDER.indexOf(a.status || 'draft');
|
|
188
|
+
const sb = STATE_ORDER.indexOf(b.status || 'draft');
|
|
189
|
+
if (sa !== sb) return sa - sb;
|
|
190
|
+
const pa = a.priority == null ? 99 : a.priority;
|
|
191
|
+
const pb = b.priority == null ? 99 : b.priority;
|
|
192
|
+
if (pa !== pb) return pa - pb;
|
|
193
|
+
return (a.id || '').localeCompare(b.id || '');
|
|
194
|
+
});
|
|
195
|
+
return filtered;
|
|
196
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
// workstreams.mjs — write-side commands for `pa project workstream <verb>`.
|
|
2
|
+
//
|
|
3
|
+
// A workstream is a named unit of work within a project. Each workstream
|
|
4
|
+
// has its own status, blockedOn signal, next-action text for operator and
|
|
5
|
+
// Dave, and owns a set of documents.
|
|
6
|
+
//
|
|
7
|
+
// Workstream schema:
|
|
8
|
+
// {
|
|
9
|
+
// "id": "content-pipeline", // kebab-case
|
|
10
|
+
// "name": "Content pipeline",
|
|
11
|
+
// "status": "in-progress", // same vocab as project status
|
|
12
|
+
// "blockedOn": "operator", // optional: "operator" | "dave" | free text
|
|
13
|
+
// "nextOperator": "Review week 1 drafts", // optional
|
|
14
|
+
// "nextDave": "Publish after approval",// optional
|
|
15
|
+
// "docs": [{ "label": "...", "path": "...", "status": "review" }]
|
|
16
|
+
// }
|
|
17
|
+
|
|
18
|
+
import { existsSync } from 'node:fs';
|
|
19
|
+
import { join } from 'node:path';
|
|
20
|
+
|
|
21
|
+
import { getRepoRoot } from './repo-root.mjs';
|
|
22
|
+
import { readJson, writeJson, today } from './io.mjs';
|
|
23
|
+
import { VALID_DOC_STATUSES } from './doc-groups.mjs';
|
|
24
|
+
|
|
25
|
+
const STATUSES = new Set(['draft', 'planned', 'in-progress', 'blocked', 'done', 'archived']);
|
|
26
|
+
|
|
27
|
+
function fail(msg, code = 1) {
|
|
28
|
+
const err = new Error(msg);
|
|
29
|
+
err.exitCode = code;
|
|
30
|
+
throw err;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function validateWsId(id) {
|
|
34
|
+
if (!id || typeof id !== 'string') fail('workstream --id is required');
|
|
35
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(id)) {
|
|
36
|
+
fail(`invalid workstream id: ${id} (lowercase letters, digits, and '-' only; must start with a letter or digit)`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function validateStatus(status) {
|
|
41
|
+
if (!STATUSES.has(status)) {
|
|
42
|
+
fail(`invalid status: ${status} (expected one of: ${[...STATUSES].join(', ')})`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function loadProject(projectId) {
|
|
47
|
+
const repoRoot = await getRepoRoot();
|
|
48
|
+
const path = join(repoRoot, 'projects', projectId, 'project.json');
|
|
49
|
+
if (!existsSync(path)) fail(`project not found: ${projectId}`);
|
|
50
|
+
const manifest = await readJson(path);
|
|
51
|
+
return { manifest, path };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function saveProject(path, manifest) {
|
|
55
|
+
manifest.updated = today();
|
|
56
|
+
await writeJson(path, manifest);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function ensureWorkstreams(manifest) {
|
|
60
|
+
if (!Array.isArray(manifest.workstreams)) {
|
|
61
|
+
manifest.workstreams = [];
|
|
62
|
+
}
|
|
63
|
+
return manifest.workstreams;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function findWorkstream(workstreams, wsId) {
|
|
67
|
+
return workstreams.find((ws) => ws.id === wsId);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Add a new workstream to a project.
|
|
72
|
+
*/
|
|
73
|
+
export async function addWorkstream(projectId, { id: wsId, name, status, blockedOn }) {
|
|
74
|
+
validateWsId(wsId);
|
|
75
|
+
if (!name) fail('--name is required');
|
|
76
|
+
if (status) validateStatus(status);
|
|
77
|
+
|
|
78
|
+
const { manifest, path } = await loadProject(projectId);
|
|
79
|
+
const workstreams = ensureWorkstreams(manifest);
|
|
80
|
+
|
|
81
|
+
if (findWorkstream(workstreams, wsId)) {
|
|
82
|
+
fail(`workstream already exists: ${wsId} in project ${projectId}`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const ws = {
|
|
86
|
+
id: wsId,
|
|
87
|
+
name,
|
|
88
|
+
status: status || 'draft',
|
|
89
|
+
docs: [],
|
|
90
|
+
};
|
|
91
|
+
if (blockedOn) ws.blockedOn = blockedOn;
|
|
92
|
+
|
|
93
|
+
workstreams.push(ws);
|
|
94
|
+
await saveProject(path, manifest);
|
|
95
|
+
|
|
96
|
+
return { projectId, workstream: ws, path };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Update a workstream's status and optionally blockedOn.
|
|
101
|
+
*/
|
|
102
|
+
export async function setWorkstreamStatus(projectId, { id: wsId, status, blockedOn }) {
|
|
103
|
+
validateWsId(wsId);
|
|
104
|
+
validateStatus(status);
|
|
105
|
+
|
|
106
|
+
const { manifest, path } = await loadProject(projectId);
|
|
107
|
+
const workstreams = ensureWorkstreams(manifest);
|
|
108
|
+
const ws = findWorkstream(workstreams, wsId);
|
|
109
|
+
if (!ws) fail(`workstream not found: ${wsId} in project ${projectId}`);
|
|
110
|
+
|
|
111
|
+
ws.status = status;
|
|
112
|
+
if (blockedOn !== undefined) {
|
|
113
|
+
if (blockedOn) {
|
|
114
|
+
ws.blockedOn = blockedOn;
|
|
115
|
+
} else {
|
|
116
|
+
delete ws.blockedOn;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
await saveProject(path, manifest);
|
|
121
|
+
return { projectId, workstream: ws, path };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Set the next-action text for operator and/or Dave on a workstream.
|
|
126
|
+
*/
|
|
127
|
+
export async function setWorkstreamNext(projectId, { id: wsId, operator: nextOp, dave: nextDave }) {
|
|
128
|
+
validateWsId(wsId);
|
|
129
|
+
|
|
130
|
+
const { manifest, path } = await loadProject(projectId);
|
|
131
|
+
const workstreams = ensureWorkstreams(manifest);
|
|
132
|
+
const ws = findWorkstream(workstreams, wsId);
|
|
133
|
+
if (!ws) fail(`workstream not found: ${wsId} in project ${projectId}`);
|
|
134
|
+
|
|
135
|
+
if (nextOp !== undefined) {
|
|
136
|
+
if (nextOp) {
|
|
137
|
+
ws.nextOperator = nextOp;
|
|
138
|
+
} else {
|
|
139
|
+
delete ws.nextOperator;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (nextDave !== undefined) {
|
|
143
|
+
if (nextDave) {
|
|
144
|
+
ws.nextDave = nextDave;
|
|
145
|
+
} else {
|
|
146
|
+
delete ws.nextDave;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
await saveProject(path, manifest);
|
|
151
|
+
return { projectId, workstream: ws, path };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Remove a workstream from a project.
|
|
156
|
+
*/
|
|
157
|
+
export async function removeWorkstream(projectId, { id: wsId }) {
|
|
158
|
+
validateWsId(wsId);
|
|
159
|
+
|
|
160
|
+
const { manifest, path } = await loadProject(projectId);
|
|
161
|
+
const workstreams = ensureWorkstreams(manifest);
|
|
162
|
+
const idx = workstreams.findIndex((ws) => ws.id === wsId);
|
|
163
|
+
if (idx === -1) fail(`workstream not found: ${wsId} in project ${projectId}`);
|
|
164
|
+
|
|
165
|
+
workstreams.splice(idx, 1);
|
|
166
|
+
await saveProject(path, manifest);
|
|
167
|
+
|
|
168
|
+
return { projectId, removed: wsId, path };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Add a doc entry to a specific workstream's docs array.
|
|
173
|
+
* Idempotent on {label, path} match within the workstream.
|
|
174
|
+
*/
|
|
175
|
+
export async function addDocToWorkstream(projectId, wsId, { label, path: docPath, status }) {
|
|
176
|
+
validateWsId(wsId);
|
|
177
|
+
if (!label) fail('--label is required');
|
|
178
|
+
if (!docPath) fail('--path is required');
|
|
179
|
+
if (status && !VALID_DOC_STATUSES.has(status)) {
|
|
180
|
+
fail(`invalid doc status: ${status} (expected one of: ${[...VALID_DOC_STATUSES].join(', ')})`);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const { manifest, path } = await loadProject(projectId);
|
|
184
|
+
const workstreams = ensureWorkstreams(manifest);
|
|
185
|
+
const ws = findWorkstream(workstreams, wsId);
|
|
186
|
+
if (!ws) fail(`workstream not found: ${wsId} in project ${projectId}`);
|
|
187
|
+
|
|
188
|
+
if (!Array.isArray(ws.docs)) ws.docs = [];
|
|
189
|
+
|
|
190
|
+
const dup = ws.docs.find((d) => d.path === docPath && d.label === label);
|
|
191
|
+
if (dup) {
|
|
192
|
+
return { projectId, workstream: wsId, label, path: docPath, status: status || null, changed: false, manifestPath: path };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const entry = { label, path: docPath };
|
|
196
|
+
if (status) entry.status = status;
|
|
197
|
+
ws.docs.push(entry);
|
|
198
|
+
|
|
199
|
+
await saveProject(path, manifest);
|
|
200
|
+
return { projectId, workstream: wsId, label, path: docPath, status: status || null, changed: true, manifestPath: path };
|
|
201
|
+
}
|