@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,211 @@
|
|
|
1
|
+
// policy.mjs — the three-tier decision engine.
|
|
2
|
+
//
|
|
3
|
+
// Pure function of (toolName, toolInput, config, context) -> a decision.
|
|
4
|
+
// No I/O here — cli.mjs does the stdin/env/config-loading plumbing and
|
|
5
|
+
// hands this module plain data, so the allowlist-matching logic itself is
|
|
6
|
+
// trivially unit-testable without spawning a process or touching disk.
|
|
7
|
+
//
|
|
8
|
+
// NB: this module only ever runs for tools in the PreToolUse matcher
|
|
9
|
+
// (^(Bash|Read|Write|Edit|NotebookEdit|Grep|Glob|WebFetch|WebSearch)$) —
|
|
10
|
+
// tier1 tools never reach the hook at all, so there is no tier1 branch
|
|
11
|
+
// here; config.tier1 exists purely as documentation (see config file
|
|
12
|
+
// comment).
|
|
13
|
+
|
|
14
|
+
import { relative, resolve } from 'node:path';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {string} toolName
|
|
18
|
+
* @param {object} toolInput
|
|
19
|
+
* @param {object} config effective (core + overlays) merged config
|
|
20
|
+
* @param {object} context
|
|
21
|
+
* @param {string} context.cwd - cwd from the PreToolUse payload
|
|
22
|
+
* @param {string|null} context.repoRoot - resolved repo root, or null
|
|
23
|
+
* @param {string|null} context.selfAgent - resolved paName, or null
|
|
24
|
+
* @returns {{decision: 'allow'|'block', tier: string, reason: string, matched: (string|null)}}
|
|
25
|
+
*/
|
|
26
|
+
export function decide(toolName, toolInput, config, context = {}) {
|
|
27
|
+
if (config.tier3.includes(toolName)) {
|
|
28
|
+
return block('tier3', `${toolName} is always-blocked under coordinator mode`, null);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (toolName === 'Bash') return decideBash(toolInput, config);
|
|
32
|
+
if (toolName === 'Read') return decideReadOrWrite('Read', toolInput, config, context);
|
|
33
|
+
if (toolName === 'Write') return decideReadOrWrite('Write', toolInput, config, context);
|
|
34
|
+
|
|
35
|
+
// Any tool reaching the hook that is neither tier3 nor one of the three
|
|
36
|
+
// argument-gated tier2 tools is unrecognised under this policy — default
|
|
37
|
+
// deny, never default allow. (In practice the matcher regex means this
|
|
38
|
+
// can only happen if the settings.json snippet's matcher is edited to
|
|
39
|
+
// add a tool this policy doesn't know about yet.)
|
|
40
|
+
return block('unrecognised', `${toolName} is not covered by the coordinator policy (matcher/config drift) — defaulting to deny`, null);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function allow(tier, reason, matched) {
|
|
44
|
+
return { decision: 'allow', tier, reason, matched: matched ?? null };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function block(tier, reason, matched) {
|
|
48
|
+
return { decision: 'block', tier, reason, matched: matched ?? null };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function anyPatternMatches(patterns, value) {
|
|
52
|
+
for (const p of patterns ?? []) {
|
|
53
|
+
try {
|
|
54
|
+
if (new RegExp(p).test(value)) return p;
|
|
55
|
+
} catch {
|
|
56
|
+
// A malformed regex in config/overlay never crashes the hook — it
|
|
57
|
+
// just never matches. Fail closed, not open.
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function decideBash(toolInput, config) {
|
|
64
|
+
const command = typeof toolInput?.command === 'string' ? toolInput.command : '';
|
|
65
|
+
const hardDeny = config.hardDeny ?? {};
|
|
66
|
+
const allowPatterns = config.tier2?.Bash?.allowPatterns ?? [];
|
|
67
|
+
|
|
68
|
+
// Belt-and-braces: the chain-guard character class now includes a literal
|
|
69
|
+
// newline alongside the shell-chaining metacharacters, so any multi-line
|
|
70
|
+
// command is blocked outright here, before the per-line pass below even
|
|
71
|
+
// runs. This alone stops every newline-smuggled hard-deny bypass; the
|
|
72
|
+
// per-line pass is kept as a second, independent layer in case the guard
|
|
73
|
+
// pattern is ever narrowed by a future config edit.
|
|
74
|
+
if (hardDeny.bashChainGuardPattern) {
|
|
75
|
+
const chainMatch = anyPatternMatches([hardDeny.bashChainGuardPattern], command);
|
|
76
|
+
if (chainMatch) {
|
|
77
|
+
return block(
|
|
78
|
+
'tier2-hard-deny',
|
|
79
|
+
'command contains a shell-chaining metacharacter (;, &&, ||, |, `, $(...), <, >) or an embedded newline — blocked even though a prefix may match an allow pattern',
|
|
80
|
+
chainMatch,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Hard-deny is evaluated per line, never against the whole (possibly
|
|
86
|
+
// multi-line) command string. `^` in a hardDeny pattern has no `m` flag,
|
|
87
|
+
// so tested against the full string it only ever matches the very start —
|
|
88
|
+
// a hard-denied command hidden behind an embedded newline would sail
|
|
89
|
+
// through. Splitting on \n and testing each line from position 0 makes
|
|
90
|
+
// every hard-deny pattern effectively line-start-anchored without having
|
|
91
|
+
// to touch the patterns themselves. hardDeny.pathPatterns (credential
|
|
92
|
+
// paths) is checked here too, against the Bash command text — not just
|
|
93
|
+
// Read/Write file_path — so a command that references e.g. `.ssh/` via
|
|
94
|
+
// redirection is caught even if it slips past the chain-guard.
|
|
95
|
+
const lines = command.split('\n');
|
|
96
|
+
for (const line of lines) {
|
|
97
|
+
const hardDenyMatch = anyPatternMatches(hardDeny.bashPatterns, line);
|
|
98
|
+
if (hardDenyMatch) {
|
|
99
|
+
return block('tier2-hard-deny', `command matches hard-deny pattern "${hardDenyMatch}" — never allowed, overlays cannot override`, hardDenyMatch);
|
|
100
|
+
}
|
|
101
|
+
const hardDenyPathMatch = anyPatternMatches(hardDeny.pathPatterns, line);
|
|
102
|
+
if (hardDenyPathMatch) {
|
|
103
|
+
return block('tier2-hard-deny', `command references a hard-deny path pattern "${hardDenyPathMatch}" — never allowed, overlays cannot override`, hardDenyPathMatch);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Every line must independently match an allow pattern — an allowlisted
|
|
108
|
+
// first line followed by an unrecognised (or hard-denied) second line is
|
|
109
|
+
// not enough; the whole command has to be clean end to end.
|
|
110
|
+
let matched = null;
|
|
111
|
+
for (const line of lines) {
|
|
112
|
+
const allowMatch = anyPatternMatches(allowPatterns, line);
|
|
113
|
+
if (!allowMatch) {
|
|
114
|
+
return block('tier2', `command does not match any Bash allow pattern (line: "${line}")`, null);
|
|
115
|
+
}
|
|
116
|
+
if (matched === null) matched = allowMatch;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return allow('tier2', `command matches allow pattern "${matched}"`, matched);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function decideReadOrWrite(toolName, toolInput, config, context) {
|
|
123
|
+
const rawFilePath = typeof toolInput?.file_path === 'string' ? toolInput.file_path : '';
|
|
124
|
+
// Normalize absolute paths (collapse `..`/`.`/`//`) before ANY pattern
|
|
125
|
+
// matching happens — hard-deny, absolute-allow, and (via
|
|
126
|
+
// toRepoRelative()) the repo-relative block/allow checks all then operate
|
|
127
|
+
// on the resolved path. Without this, a raw string like
|
|
128
|
+
// `/tmp/../operator/knowledge/foo.md` matches `^/tmp/` on the
|
|
129
|
+
// unresolved text even though it actually points at
|
|
130
|
+
// `/operator/knowledge/foo.md` once traversal is collapsed — the
|
|
131
|
+
// absolute-allow branch was added separately from the repo-relative
|
|
132
|
+
// branch below and never got the same treatment. Relative paths are left
|
|
133
|
+
// untouched here; toRepoRelative() already resolves those correctly
|
|
134
|
+
// against context.cwd.
|
|
135
|
+
const filePath = rawFilePath.startsWith('/') ? resolve(rawFilePath) : rawFilePath;
|
|
136
|
+
const toolConfig = config.tier2?.[toolName] ?? {};
|
|
137
|
+
|
|
138
|
+
// Hard-deny is checked first, against the raw path, and wins over even
|
|
139
|
+
// an absolute allow pattern (scratchpad included) — a determined overlay
|
|
140
|
+
// author extending allowAbsolutePathPatterns must not be able to smuggle
|
|
141
|
+
// a credentials-file read past this.
|
|
142
|
+
const hardDenyPatterns = config.hardDeny?.pathPatterns ?? [];
|
|
143
|
+
const hardDenyMatch = anyPatternMatches(hardDenyPatterns, filePath);
|
|
144
|
+
if (hardDenyMatch) {
|
|
145
|
+
return block('tier2-hard-deny', `path matches hard-deny pattern "${hardDenyMatch}" — never allowed, overlays cannot override`, hardDenyMatch);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Absolute allow patterns (scratchpad etc.) are checked directly against
|
|
149
|
+
// the raw path — they're meaningful with or without a resolvable repo root.
|
|
150
|
+
const absAllow = anyPatternMatches(toolConfig.allowAbsolutePathPatterns, filePath);
|
|
151
|
+
if (absAllow) {
|
|
152
|
+
return allow('tier2', `path matches absolute allow pattern "${absAllow}"`, absAllow);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Everything else is expressed relative to the repo root.
|
|
156
|
+
const relPath = toRepoRelative(filePath, context);
|
|
157
|
+
|
|
158
|
+
if (relPath !== null) {
|
|
159
|
+
const blockMatch = anyPatternMatches(toolConfig.blockPathPatterns, relPath);
|
|
160
|
+
if (blockMatch) {
|
|
161
|
+
return block('tier2-explicit-block', `path matches explicit block pattern "${blockMatch}"`, blockMatch);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const selfAwarePatterns = expandSelfPatterns(toolConfig.allowPathPatterns, context.selfAgent);
|
|
165
|
+
const allowMatch = anyPatternMatches(selfAwarePatterns, relPath);
|
|
166
|
+
if (allowMatch) {
|
|
167
|
+
return allow('tier2', `path matches allow pattern "${allowMatch}"`, allowMatch);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return block('tier2', `path "${relPath}" does not match any ${toolName} allow pattern`, null);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Could not resolve a repo-relative path (no repo root found and the
|
|
174
|
+
// path wasn't under one of the absolute allow patterns) — default deny.
|
|
175
|
+
return block('tier2', `could not resolve "${filePath}" relative to a repo root — defaulting to deny`, null);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Substitutes the literal `<self>` token used in `agents/<self>/…` config
|
|
180
|
+
* patterns. When the calling PA's paName is known, it's substituted
|
|
181
|
+
* verbatim (regex-escaped); when unknown, it's substituted with `[^/]+` —
|
|
182
|
+
* the spec's documented fallback ("if unknown, allow any agents subdirectory").
|
|
183
|
+
* Applies to both core and overlay-supplied patterns, since an overlay
|
|
184
|
+
* author may reasonably write `<self>`-scoped patterns too.
|
|
185
|
+
*/
|
|
186
|
+
function expandSelfPatterns(patterns, selfAgent) {
|
|
187
|
+
if (!patterns) return patterns;
|
|
188
|
+
const replacement = selfAgent ? escapeRegex(selfAgent) : '[^/]+';
|
|
189
|
+
return patterns.map((p) => p.replaceAll('<self>', replacement));
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function escapeRegex(s) {
|
|
193
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Resolve `filePath` to a repo-root-relative, forward-slash path. Returns
|
|
198
|
+
* null when it can't be placed under the repo root at all (no repo root
|
|
199
|
+
* known, or the path lies genuinely outside it).
|
|
200
|
+
*/
|
|
201
|
+
function toRepoRelative(filePath, context) {
|
|
202
|
+
if (!filePath) return null;
|
|
203
|
+
const { repoRoot, cwd } = context;
|
|
204
|
+
const root = repoRoot || null;
|
|
205
|
+
if (!root) return null;
|
|
206
|
+
|
|
207
|
+
const abs = filePath.startsWith('/') ? filePath : resolve(cwd || root, filePath);
|
|
208
|
+
const rel = relative(root, abs);
|
|
209
|
+
if (rel.startsWith('..') || rel === '') return rel === '' ? '.' : null;
|
|
210
|
+
return rel.split('\\').join('/');
|
|
211
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// repo-root.mjs — operator repo root discovery for the coordinator hook.
|
|
2
|
+
//
|
|
3
|
+
// Mirrors packages/cli/src/pa/repo-root.mjs and packages/core/src/desk/repo.mjs.
|
|
4
|
+
// Own copy avoids cross-module coupling for a pure utility (established
|
|
5
|
+
// convention in this monorepo — see the comment in pa/repo-root.mjs).
|
|
6
|
+
//
|
|
7
|
+
// Unlike the CLI-facing copies, this one takes an explicit `startDir` and
|
|
8
|
+
// `env` on every call instead of caching module-global state — the hook is
|
|
9
|
+
// a fresh process per PreToolUse invocation, and it also needs to resolve
|
|
10
|
+
// roots relative to the `cwd` field of the tool-use payload, which is not
|
|
11
|
+
// necessarily `process.cwd()`.
|
|
12
|
+
//
|
|
13
|
+
// Resolution order:
|
|
14
|
+
// 1. DAVE_REPO_ROOT / PA_REPO_ROOT env var (explicit override)
|
|
15
|
+
// 2. Walk upward from startDir looking for a `.git` entry (dir or file —
|
|
16
|
+
// a `.git` file means a worktree checkout)
|
|
17
|
+
// 3. null if nothing found (caller decides the safe-default fallback)
|
|
18
|
+
|
|
19
|
+
import { stat } from 'node:fs/promises';
|
|
20
|
+
import { join, resolve, dirname } from 'node:path';
|
|
21
|
+
|
|
22
|
+
async function pathKind(p) {
|
|
23
|
+
try {
|
|
24
|
+
const s = await stat(p);
|
|
25
|
+
if (s.isDirectory()) return 'dir';
|
|
26
|
+
if (s.isFile()) return 'file';
|
|
27
|
+
return 'other';
|
|
28
|
+
} catch {
|
|
29
|
+
return 'missing';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function resolveRepoRoot(startDir, env = process.env) {
|
|
34
|
+
const envRoot = env.DAVE_REPO_ROOT || env.PA_REPO_ROOT;
|
|
35
|
+
if (envRoot) return resolve(envRoot);
|
|
36
|
+
|
|
37
|
+
let d = resolve(startDir);
|
|
38
|
+
while (d && d !== dirname(d)) {
|
|
39
|
+
const k = await pathKind(join(d, '.git'));
|
|
40
|
+
if (k === 'dir' || k === 'file') return d;
|
|
41
|
+
d = dirname(d);
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// self.mjs — resolve the calling PA's own agent-directory name ("<self>" in
|
|
2
|
+
// the allowlist spec's `agents/<self>/**` patterns).
|
|
3
|
+
//
|
|
4
|
+
// Priority:
|
|
5
|
+
// 1. PA_SELF_AGENT env var (explicit override — useful for tests and for
|
|
6
|
+
// hosts where preferences.json resolution is inconvenient).
|
|
7
|
+
// 2. operator/config/preferences.json → paName, read relative to the
|
|
8
|
+
// resolved repo root.
|
|
9
|
+
// 3. Unknown — caller falls back to the permissive `agents/[^/]+/`
|
|
10
|
+
// pattern, per the spec ("if unknown, allow any agents/*/ path").
|
|
11
|
+
//
|
|
12
|
+
// Returns a string paName, or null when unresolved.
|
|
13
|
+
|
|
14
|
+
import { readFile } from 'node:fs/promises';
|
|
15
|
+
import { join } from 'node:path';
|
|
16
|
+
|
|
17
|
+
export async function resolveSelfAgent(repoRoot, env = process.env) {
|
|
18
|
+
if (env.PA_SELF_AGENT) return env.PA_SELF_AGENT;
|
|
19
|
+
if (!repoRoot) return null;
|
|
20
|
+
try {
|
|
21
|
+
const raw = await readFile(join(repoRoot, 'operator', 'config', 'preferences.json'), 'utf8');
|
|
22
|
+
const config = JSON.parse(raw);
|
|
23
|
+
if (config && typeof config.paName === 'string' && config.paName.trim()) {
|
|
24
|
+
return config.paName.trim();
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
} catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
// cli.mjs — argv router for `pa environment [verb]`.
|
|
2
|
+
//
|
|
3
|
+
// Verbs (three):
|
|
4
|
+
// pa environment Read cache, auto-refresh if stale, print summary
|
|
5
|
+
// pa environment refresh Force rebuild the cache
|
|
6
|
+
// pa environment extended Reserved verb — dispatches to operator overlay
|
|
7
|
+
//
|
|
8
|
+
// Global flags:
|
|
9
|
+
// --format json Machine-readable output to stdout
|
|
10
|
+
// --quiet Suppress human summary; file write is the payload
|
|
11
|
+
// --skip-network Skip network probes (fallback for slow CI or offline dev)
|
|
12
|
+
//
|
|
13
|
+
// Exit codes (tooling standard §6):
|
|
14
|
+
// 0 ok | 1 usage | 2 unresolvable state (extended verb without extension,
|
|
15
|
+
// cache-write failure) | 3 network probe failure (does NOT prevent write —
|
|
16
|
+
// degraded environment is still captured, but the exit code signals it)
|
|
17
|
+
//
|
|
18
|
+
// Performance target: cache-read <2s, refresh <5s. Runs at every session
|
|
19
|
+
// boot; slower and the operator waits.
|
|
20
|
+
|
|
21
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
22
|
+
import { join, dirname } from 'node:path';
|
|
23
|
+
import { pathToFileURL } from 'node:url';
|
|
24
|
+
import { getRepoRoot } from '../pa/repo-root.mjs';
|
|
25
|
+
import {
|
|
26
|
+
probePlatform,
|
|
27
|
+
probeRuntimes,
|
|
28
|
+
probePlatformCli,
|
|
29
|
+
probeCustomTools,
|
|
30
|
+
probeNetwork,
|
|
31
|
+
probeWorkspace,
|
|
32
|
+
probeWorkingDirectory,
|
|
33
|
+
} from './probes.mjs';
|
|
34
|
+
|
|
35
|
+
const CLI_VERSION = '0.2.0';
|
|
36
|
+
const DEFAULT_STALENESS_MINUTES = 60;
|
|
37
|
+
|
|
38
|
+
const USAGE = `pa environment — session-boot environment cache
|
|
39
|
+
|
|
40
|
+
Usage:
|
|
41
|
+
pa environment Read cache; auto-refresh if missing/stale
|
|
42
|
+
pa environment refresh Force rebuild
|
|
43
|
+
pa environment extended (Reserved verb — operator overlay)
|
|
44
|
+
pa environment -h, --help Show this help
|
|
45
|
+
|
|
46
|
+
Global flags:
|
|
47
|
+
--format <human|json> Output format (default: human)
|
|
48
|
+
--quiet Suppress stdout summary
|
|
49
|
+
--skip-network Skip DNS + HTTP probes
|
|
50
|
+
|
|
51
|
+
Cache file: <repo-root>/.session/environment.json.
|
|
52
|
+
Staleness threshold: 60 minutes (override via operator/config/preferences.json:
|
|
53
|
+
environment.cacheStalenessMinutes).
|
|
54
|
+
|
|
55
|
+
Extended verb loader: <repo-root>/operator/extensions/tools/environment-extended/index.mjs.
|
|
56
|
+
|
|
57
|
+
Exit codes (tooling standard §6):
|
|
58
|
+
0 ok | 1 usage | 2 unresolvable state | 3 network probe failure
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
export async function run(argv) {
|
|
62
|
+
const args = argv ?? [];
|
|
63
|
+
if (args.includes('-h') || args.includes('--help')) {
|
|
64
|
+
process.stdout.write(USAGE);
|
|
65
|
+
return 0;
|
|
66
|
+
}
|
|
67
|
+
const { positionals, flags } = parseArgs(args);
|
|
68
|
+
const verb = positionals[0] ?? 'default';
|
|
69
|
+
try {
|
|
70
|
+
switch (verb) {
|
|
71
|
+
case 'default': return await runDefault(flags);
|
|
72
|
+
case 'refresh': return await runRefresh(flags);
|
|
73
|
+
case 'extended': return await runExtended(flags, positionals.slice(1));
|
|
74
|
+
default:
|
|
75
|
+
process.stderr.write(`[pa environment] unknown verb: ${verb}\n`);
|
|
76
|
+
process.stderr.write(USAGE);
|
|
77
|
+
return 1;
|
|
78
|
+
}
|
|
79
|
+
} catch (err) {
|
|
80
|
+
process.stderr.write(`[pa environment] ${err.message || err}\n`);
|
|
81
|
+
return err.exitCode ?? 2;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function parseArgs(argv) {
|
|
86
|
+
const flags = { format: 'human', quiet: false, skipNetwork: false };
|
|
87
|
+
const positionals = [];
|
|
88
|
+
for (let i = 0; i < argv.length; i++) {
|
|
89
|
+
const arg = argv[i];
|
|
90
|
+
if (arg === '--format') { flags.format = argv[++i]; continue; }
|
|
91
|
+
if (arg.startsWith('--format=')) { flags.format = arg.slice('--format='.length); continue; }
|
|
92
|
+
if (arg === '--quiet') { flags.quiet = true; continue; }
|
|
93
|
+
if (arg === '--skip-network') { flags.skipNetwork = true; continue; }
|
|
94
|
+
if (arg.startsWith('--')) {
|
|
95
|
+
const err = new Error(`unknown flag ${arg}`);
|
|
96
|
+
err.exitCode = 1;
|
|
97
|
+
throw err;
|
|
98
|
+
}
|
|
99
|
+
positionals.push(arg);
|
|
100
|
+
}
|
|
101
|
+
return { positionals, flags };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function runDefault(flags) {
|
|
105
|
+
const repoRoot = await getRepoRoot();
|
|
106
|
+
const cachePath = cacheFilePath(repoRoot);
|
|
107
|
+
const staleness = readStalenessMinutes(repoRoot);
|
|
108
|
+
const cached = readCache(cachePath);
|
|
109
|
+
const stale = cached ? isStale(cached, staleness) : true;
|
|
110
|
+
let cache;
|
|
111
|
+
let networkDegraded = false;
|
|
112
|
+
if (!cached || stale) {
|
|
113
|
+
({ cache, networkDegraded } = await buildCache(repoRoot, flags));
|
|
114
|
+
writeCache(cachePath, cache);
|
|
115
|
+
} else {
|
|
116
|
+
cache = cached;
|
|
117
|
+
}
|
|
118
|
+
if (!flags.quiet) {
|
|
119
|
+
if (flags.format === 'json') {
|
|
120
|
+
process.stdout.write(JSON.stringify(cache, null, 2) + '\n');
|
|
121
|
+
} else {
|
|
122
|
+
process.stdout.write(formatSummary(cache) + '\n');
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return networkDegraded ? 3 : 0;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function runRefresh(flags) {
|
|
129
|
+
const repoRoot = await getRepoRoot();
|
|
130
|
+
const cachePath = cacheFilePath(repoRoot);
|
|
131
|
+
const { cache, networkDegraded } = await buildCache(repoRoot, flags);
|
|
132
|
+
writeCache(cachePath, cache);
|
|
133
|
+
if (!flags.quiet) {
|
|
134
|
+
if (flags.format === 'json') {
|
|
135
|
+
process.stdout.write(JSON.stringify(cache, null, 2) + '\n');
|
|
136
|
+
} else {
|
|
137
|
+
process.stdout.write(formatSummary(cache) + '\n');
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return networkDegraded ? 3 : 0;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async function runExtended(flags, extraArgs) {
|
|
144
|
+
const repoRoot = await getRepoRoot();
|
|
145
|
+
const extensionPath = join(repoRoot, 'operator', 'extensions', 'tools', 'environment-extended', 'index.mjs');
|
|
146
|
+
if (!existsSync(extensionPath)) {
|
|
147
|
+
process.stderr.write(
|
|
148
|
+
'[pa environment extended] extended checks require operator extension — ' +
|
|
149
|
+
'see operator/extensions/tools/environment-extended (missing on this repo)\n',
|
|
150
|
+
);
|
|
151
|
+
return 2;
|
|
152
|
+
}
|
|
153
|
+
// Build the core cache first — the extension receives it via context so
|
|
154
|
+
// it can extend rather than duplicate.
|
|
155
|
+
const { cache: coreCache } = await buildCache(repoRoot, flags);
|
|
156
|
+
const cachePath = cacheFilePath(repoRoot);
|
|
157
|
+
let mod;
|
|
158
|
+
try {
|
|
159
|
+
mod = await import(pathToFileURL(extensionPath).href);
|
|
160
|
+
} catch (err) {
|
|
161
|
+
process.stderr.write(`[pa environment extended] failed to load extension: ${err.message}\n`);
|
|
162
|
+
return 2;
|
|
163
|
+
}
|
|
164
|
+
const extendFn = mod.default;
|
|
165
|
+
if (typeof extendFn !== 'function') {
|
|
166
|
+
process.stderr.write(
|
|
167
|
+
'[pa environment extended] extension at operator/extensions/tools/environment-extended/index.mjs ' +
|
|
168
|
+
'must default-export an async function extended({ core, cwd })\n',
|
|
169
|
+
);
|
|
170
|
+
return 2;
|
|
171
|
+
}
|
|
172
|
+
let extended;
|
|
173
|
+
try {
|
|
174
|
+
extended = await extendFn({ core: coreCache, cwd: process.cwd(), extraArgs });
|
|
175
|
+
} catch (err) {
|
|
176
|
+
// Surface the extension's error verbatim — the operator wants to know
|
|
177
|
+
// why the extension failed.
|
|
178
|
+
process.stderr.write(`[pa environment extended] extension threw: ${err.stack || err.message || err}\n`);
|
|
179
|
+
return 2;
|
|
180
|
+
}
|
|
181
|
+
const merged = { ...coreCache, ...(extended ?? {}) };
|
|
182
|
+
writeCache(cachePath, merged);
|
|
183
|
+
if (!flags.quiet) {
|
|
184
|
+
if (flags.format === 'json') {
|
|
185
|
+
process.stdout.write(JSON.stringify(merged, null, 2) + '\n');
|
|
186
|
+
} else {
|
|
187
|
+
process.stdout.write(formatSummary(merged) + '\n');
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return 0;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async function buildCache(repoRoot, flags) {
|
|
194
|
+
const platform = probePlatform();
|
|
195
|
+
const [runtimes, network, workspace] = await Promise.all([
|
|
196
|
+
probeRuntimes(),
|
|
197
|
+
probeNetwork({ skip: flags.skipNetwork }),
|
|
198
|
+
probeWorkspace(repoRoot),
|
|
199
|
+
]);
|
|
200
|
+
const platformCli = probePlatformCli(repoRoot);
|
|
201
|
+
const customTools = probeCustomTools(repoRoot);
|
|
202
|
+
const workingDirectory = probeWorkingDirectory();
|
|
203
|
+
const cache = {
|
|
204
|
+
capturedAt: new Date().toISOString(),
|
|
205
|
+
capturedBy: `pa environment@${CLI_VERSION}`,
|
|
206
|
+
platform,
|
|
207
|
+
runtimes,
|
|
208
|
+
platformCli,
|
|
209
|
+
customTools,
|
|
210
|
+
network,
|
|
211
|
+
workspace,
|
|
212
|
+
workingDirectory,
|
|
213
|
+
};
|
|
214
|
+
const networkDegraded = Boolean(
|
|
215
|
+
!flags.skipNetwork
|
|
216
|
+
&& ((network?.dns?.error) || (network?.http?.error)),
|
|
217
|
+
);
|
|
218
|
+
return { cache, networkDegraded };
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function cacheFilePath(repoRoot) {
|
|
222
|
+
return join(repoRoot, '.session', 'environment.json');
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function readCache(path) {
|
|
226
|
+
if (!existsSync(path)) return null;
|
|
227
|
+
try {
|
|
228
|
+
return JSON.parse(readFileSync(path, 'utf8'));
|
|
229
|
+
} catch {
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function writeCache(path, cache) {
|
|
235
|
+
try {
|
|
236
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
237
|
+
writeFileSync(path, JSON.stringify(cache, null, 2) + '\n');
|
|
238
|
+
} catch (err) {
|
|
239
|
+
const wrapped = new Error(`could not write cache to ${path}: ${err.message}`);
|
|
240
|
+
wrapped.exitCode = 2;
|
|
241
|
+
throw wrapped;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function isStale(cache, stalenessMinutes) {
|
|
246
|
+
if (!cache?.capturedAt) return true;
|
|
247
|
+
const capturedMs = Date.parse(cache.capturedAt);
|
|
248
|
+
if (!Number.isFinite(capturedMs)) return true;
|
|
249
|
+
const ageMs = Date.now() - capturedMs;
|
|
250
|
+
return ageMs > stalenessMinutes * 60 * 1000;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function readStalenessMinutes(repoRoot) {
|
|
254
|
+
try {
|
|
255
|
+
const prefsPath = join(repoRoot, 'operator', 'config', 'preferences.json');
|
|
256
|
+
if (existsSync(prefsPath)) {
|
|
257
|
+
const prefs = JSON.parse(readFileSync(prefsPath, 'utf8'));
|
|
258
|
+
const value = prefs?.environment?.cacheStalenessMinutes;
|
|
259
|
+
if (typeof value === 'number' && value > 0) return value;
|
|
260
|
+
}
|
|
261
|
+
} catch {
|
|
262
|
+
// fall through
|
|
263
|
+
}
|
|
264
|
+
return DEFAULT_STALENESS_MINUTES;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function formatSummary(cache) {
|
|
268
|
+
const parts = [];
|
|
269
|
+
parts.push(`Environment snapshot @ ${cache.capturedAt}`);
|
|
270
|
+
parts.push(`Capturer: ${cache.capturedBy}`);
|
|
271
|
+
parts.push('');
|
|
272
|
+
const p = cache.platform || {};
|
|
273
|
+
parts.push(`Platform: ${p.os}/${p.arch} kernel=${p.kernel} shell=${p.shell ?? '-'}`);
|
|
274
|
+
const r = cache.runtimes || {};
|
|
275
|
+
parts.push(`Runtimes: node=${r.node?.version ?? '-'} pnpm=${r.pnpm?.version ?? '-'} git=${r.git?.version ?? '-'}`);
|
|
276
|
+
const n = cache.network || {};
|
|
277
|
+
const dnsStr = n.dns?.skipped ? 'skipped' : `${n.dns?.resolved?.[0] ?? n.dns?.error ?? '-'} (${n.dns?.elapsedMs ?? '-'}ms)`;
|
|
278
|
+
const httpStr = n.http?.skipped ? 'skipped' : `${n.http?.statusCode ?? n.http?.error ?? '-'} (${n.http?.elapsedMs ?? '-'}ms)`;
|
|
279
|
+
parts.push(`Network: dns(${n.dns?.target ?? '-'})=${dnsStr} http(${n.http?.target ?? '-'})=${httpStr}`);
|
|
280
|
+
const w = cache.workspace || {};
|
|
281
|
+
parts.push(`Workspace: ${w.url ?? '-'} ${w.running ? 'running' : 'not running'}`);
|
|
282
|
+
const wd = cache.workingDirectory || {};
|
|
283
|
+
parts.push(`Working directory: ${wd.cwd ?? '-'} → projectRoot=${wd.projectRoot ?? 'unresolved'} (via ${wd.resolvedVia ?? '-'})`);
|
|
284
|
+
const tools = cache.customTools || [];
|
|
285
|
+
parts.push(`Custom tools: ${tools.length === 0 ? '(none)' : tools.map((t) => t.name).join(', ')}`);
|
|
286
|
+
return parts.join('\n');
|
|
287
|
+
}
|