@pareto4/pp-core 1.5.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/.claude-plugin/plugin.json +23 -0
- package/GEMINI.md +53 -0
- package/LICENSE +22 -0
- package/README.md +100 -0
- package/agents/pp-advisor-researcher.md +108 -0
- package/agents/pp-ai-researcher.md +114 -0
- package/agents/pp-assumptions-analyzer.md +105 -0
- package/agents/pp-code-fixer.md +669 -0
- package/agents/pp-code-reviewer.md +387 -0
- package/agents/pp-codebase-mapper.md +853 -0
- package/agents/pp-debug-session-manager.md +315 -0
- package/agents/pp-debugger.md +1453 -0
- package/agents/pp-doc-classifier.md +168 -0
- package/agents/pp-doc-synthesizer.md +204 -0
- package/agents/pp-doc-verifier.md +217 -0
- package/agents/pp-doc-writer.md +616 -0
- package/agents/pp-domain-researcher.md +147 -0
- package/agents/pp-eval-auditor.md +191 -0
- package/agents/pp-eval-planner.md +154 -0
- package/agents/pp-executor.md +808 -0
- package/agents/pp-framework-selector.md +160 -0
- package/agents/pp-integration-checker.md +470 -0
- package/agents/pp-intel-updater.md +339 -0
- package/agents/pp-mempalace-curator.md +47 -0
- package/agents/pp-nyquist-auditor.md +204 -0
- package/agents/pp-pattern-mapper.md +335 -0
- package/agents/pp-phase-researcher.md +867 -0
- package/agents/pp-plan-checker.md +988 -0
- package/agents/pp-planner.md +1052 -0
- package/agents/pp-project-researcher.md +612 -0
- package/agents/pp-research-synthesizer.md +260 -0
- package/agents/pp-roadmapper.md +741 -0
- package/agents/pp-security-auditor.md +156 -0
- package/agents/pp-ui-auditor.md +495 -0
- package/agents/pp-ui-checker.md +309 -0
- package/agents/pp-ui-researcher.md +375 -0
- package/agents/pp-user-profiler.md +171 -0
- package/agents/pp-verifier.md +967 -0
- package/assets/gsd-logo-2000-transparent.png +0 -0
- package/assets/gsd-logo-2000-transparent.svg +17 -0
- package/assets/gsd-logo-2000.png +0 -0
- package/assets/gsd-logo-2000.svg +21 -0
- package/assets/terminal.svg +68 -0
- package/bin/install.js +12370 -0
- package/bin/lib/ui-safety-gate.cjs +107 -0
- package/commands/pp-add-tests.md +42 -0
- package/commands/pp-ai-integration-phase.md +37 -0
- package/commands/pp-audit-fix.md +34 -0
- package/commands/pp-audit-milestone.md +37 -0
- package/commands/pp-audit-uat.md +24 -0
- package/commands/pp-autonomous.md +51 -0
- package/commands/pp-capture.md +62 -0
- package/commands/pp-cleanup.md +24 -0
- package/commands/pp-code-review.md +59 -0
- package/commands/pp-complete-milestone.md +143 -0
- package/commands/pp-config.md +56 -0
- package/commands/pp-debug.md +52 -0
- package/commands/pp-discovery.md +34 -0
- package/commands/pp-discuss-phase.md +77 -0
- package/commands/pp-docs-update.md +49 -0
- package/commands/pp-eval-review.md +33 -0
- package/commands/pp-execute-phase.md +65 -0
- package/commands/pp-explore.md +27 -0
- package/commands/pp-extract-learnings.md +23 -0
- package/commands/pp-fast.md +31 -0
- package/commands/pp-forensics.md +57 -0
- package/commands/pp-graphify.md +204 -0
- package/commands/pp-health.md +31 -0
- package/commands/pp-help.md +28 -0
- package/commands/pp-import.md +45 -0
- package/commands/pp-inbox.md +39 -0
- package/commands/pp-ingest-docs.md +42 -0
- package/commands/pp-manager.md +45 -0
- package/commands/pp-map-codebase.md +83 -0
- package/commands/pp-mempalace-capture.md +71 -0
- package/commands/pp-mempalace-recall.md +102 -0
- package/commands/pp-milestone-summary.md +51 -0
- package/commands/pp-mvp-phase.md +45 -0
- package/commands/pp-new-milestone.md +45 -0
- package/commands/pp-new-project.md +47 -0
- package/commands/pp-ns-context.md +25 -0
- package/commands/pp-ns-ideate.md +24 -0
- package/commands/pp-ns-manage.md +36 -0
- package/commands/pp-ns-project.md +27 -0
- package/commands/pp-ns-review.md +29 -0
- package/commands/pp-ns-workflow.md +35 -0
- package/commands/pp-pause-work.md +43 -0
- package/commands/pp-phase.md +56 -0
- package/commands/pp-plan-phase.md +63 -0
- package/commands/pp-plan-review-convergence.md +60 -0
- package/commands/pp-pr-branch.md +26 -0
- package/commands/pp-profile-user.md +46 -0
- package/commands/pp-progress.md +49 -0
- package/commands/pp-quick.md +174 -0
- package/commands/pp-resume-work.md +30 -0
- package/commands/pp-review-backlog.md +63 -0
- package/commands/pp-review.md +42 -0
- package/commands/pp-secure-phase.md +36 -0
- package/commands/pp-settings.md +29 -0
- package/commands/pp-ship.md +24 -0
- package/commands/pp-sketch.md +60 -0
- package/commands/pp-spec-phase.md +63 -0
- package/commands/pp-spike.md +57 -0
- package/commands/pp-stats.md +20 -0
- package/commands/pp-surface.md +162 -0
- package/commands/pp-thread.md +24 -0
- package/commands/pp-ui-phase.md +35 -0
- package/commands/pp-ui-review.md +33 -0
- package/commands/pp-ultraplan-phase.md +34 -0
- package/commands/pp-undo.md +35 -0
- package/commands/pp-update.md +49 -0
- package/commands/pp-validate-phase.md +36 -0
- package/commands/pp-verify-work.md +39 -0
- package/commands/pp-workspace.md +52 -0
- package/commands/pp-workstreams.md +70 -0
- package/gemini-extension.json +6 -0
- package/hooks/dist/lib/git-cmd.js +150 -0
- package/hooks/dist/lib/pp-graphify-rebuild.sh +65 -0
- package/hooks/dist/managed-hooks-registry.cjs +39 -0
- package/hooks/dist/pp-check-update-worker.js +108 -0
- package/hooks/dist/pp-check-update.js +66 -0
- package/hooks/dist/pp-config-reload.js +133 -0
- package/hooks/dist/pp-context-monitor.js +196 -0
- package/hooks/dist/pp-cursor-post-tool.js +75 -0
- package/hooks/dist/pp-cursor-session-start.js +52 -0
- package/hooks/dist/pp-ensure-canonical-path.js +305 -0
- package/hooks/dist/pp-graphify-update.sh +158 -0
- package/hooks/dist/pp-phase-boundary.sh +47 -0
- package/hooks/dist/pp-prompt-guard.js +97 -0
- package/hooks/dist/pp-read-guard.js +101 -0
- package/hooks/dist/pp-read-injection-scanner.js +203 -0
- package/hooks/dist/pp-session-state.sh +59 -0
- package/hooks/dist/pp-statusline.js +566 -0
- package/hooks/dist/pp-update-banner.js +138 -0
- package/hooks/dist/pp-validate-commit.sh +57 -0
- package/hooks/dist/pp-workflow-guard.js +167 -0
- package/hooks/dist/pp-worktree-path-guard.js +185 -0
- package/hooks/hooks.json +70 -0
- package/hooks/lib/git-cmd.js +150 -0
- package/hooks/lib/pp-graphify-rebuild.sh +65 -0
- package/hooks/managed-hooks-registry.cjs +39 -0
- package/hooks/pp-check-update-worker.js +108 -0
- package/hooks/pp-check-update.js +66 -0
- package/hooks/pp-config-reload.js +133 -0
- package/hooks/pp-context-monitor.js +196 -0
- package/hooks/pp-cursor-post-tool.js +75 -0
- package/hooks/pp-cursor-session-start.js +52 -0
- package/hooks/pp-ensure-canonical-path.js +305 -0
- package/hooks/pp-graphify-update.sh +158 -0
- package/hooks/pp-phase-boundary.sh +47 -0
- package/hooks/pp-prompt-guard.js +97 -0
- package/hooks/pp-read-guard.js +101 -0
- package/hooks/pp-read-injection-scanner.js +203 -0
- package/hooks/pp-session-state.sh +59 -0
- package/hooks/pp-statusline.js +566 -0
- package/hooks/pp-update-banner.js +138 -0
- package/hooks/pp-validate-commit.sh +57 -0
- package/hooks/pp-workflow-guard.js +167 -0
- package/hooks/pp-worktree-path-guard.js +185 -0
- package/package.json +125 -0
- package/pp-core/bin/check-latest-version.cjs +161 -0
- package/pp-core/bin/lib/active-workstream-store.cjs +297 -0
- package/pp-core/bin/lib/adr-parser.cjs +399 -0
- package/pp-core/bin/lib/agent-command-router.cjs +68 -0
- package/pp-core/bin/lib/agent-install-check.cjs +143 -0
- package/pp-core/bin/lib/artifacts.cjs +51 -0
- package/pp-core/bin/lib/audit-command-router.cjs +61 -0
- package/pp-core/bin/lib/audit.cjs +743 -0
- package/pp-core/bin/lib/capability-activation.cjs +113 -0
- package/pp-core/bin/lib/capability-registry.cjs +3727 -0
- package/pp-core/bin/lib/capability-state.cjs +497 -0
- package/pp-core/bin/lib/capability-writer.cjs +355 -0
- package/pp-core/bin/lib/check-command-router.cjs +800 -0
- package/pp-core/bin/lib/cjs-command-router-adapter.cjs +81 -0
- package/pp-core/bin/lib/cli-exit.cjs +61 -0
- package/pp-core/bin/lib/clock.cjs +95 -0
- package/pp-core/bin/lib/clusters.cjs +131 -0
- package/pp-core/bin/lib/code-review-flags.cjs +59 -0
- package/pp-core/bin/lib/command-aliases.cjs +809 -0
- package/pp-core/bin/lib/command-arg-projection.cjs +55 -0
- package/pp-core/bin/lib/command-roster.cjs +19 -0
- package/pp-core/bin/lib/command-routing-hub.cjs +300 -0
- package/pp-core/bin/lib/commands.cjs +1244 -0
- package/pp-core/bin/lib/config-loader.cjs +714 -0
- package/pp-core/bin/lib/config-schema.cjs +58 -0
- package/pp-core/bin/lib/config-types.cjs +20 -0
- package/pp-core/bin/lib/config.cjs +796 -0
- package/pp-core/bin/lib/configuration.cjs +209 -0
- package/pp-core/bin/lib/context-utilization.cjs +48 -0
- package/pp-core/bin/lib/core-utils.cjs +198 -0
- package/pp-core/bin/lib/decisions.cjs +136 -0
- package/pp-core/bin/lib/docs.cjs +264 -0
- package/pp-core/bin/lib/drift.cjs +364 -0
- package/pp-core/bin/lib/edge-probe.cjs +196 -0
- package/pp-core/bin/lib/fallow-runner.cjs +153 -0
- package/pp-core/bin/lib/federated-config.cjs +182 -0
- package/pp-core/bin/lib/frontmatter.cjs +494 -0
- package/pp-core/bin/lib/gap-checker.cjs +260 -0
- package/pp-core/bin/lib/git-base-branch.cjs +220 -0
- package/pp-core/bin/lib/graphify-command-router.cjs +72 -0
- package/pp-core/bin/lib/graphify.cjs +472 -0
- package/pp-core/bin/lib/gsd2-import.cjs +456 -0
- package/pp-core/bin/lib/init-command-router.cjs +62 -0
- package/pp-core/bin/lib/init.cjs +1912 -0
- package/pp-core/bin/lib/install-profiles.cjs +814 -0
- package/pp-core/bin/lib/installer-migration-authoring.cjs +122 -0
- package/pp-core/bin/lib/installer-migration-report.cjs +351 -0
- package/pp-core/bin/lib/installer-migrations/000-first-time-baseline.cjs +225 -0
- package/pp-core/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +48 -0
- package/pp-core/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +94 -0
- package/pp-core/bin/lib/installer-migrations/003-rename-get-shit-done-to-gsd-core.cjs +108 -0
- package/pp-core/bin/lib/installer-migrations/004-prune-stale-pristine-snapshots.cjs +123 -0
- package/pp-core/bin/lib/installer-migrations/005-rename-gsd-core-to-pp-core.cjs +109 -0
- package/pp-core/bin/lib/installer-migrations/006-rename-gsd-command-namespace.cjs +135 -0
- package/pp-core/bin/lib/installer-migrations.cjs +823 -0
- package/pp-core/bin/lib/intel-command-router.cjs +119 -0
- package/pp-core/bin/lib/intel.cjs +584 -0
- package/pp-core/bin/lib/io.cjs +220 -0
- package/pp-core/bin/lib/learnings.cjs +270 -0
- package/pp-core/bin/lib/legacy-cleanup.cjs +253 -0
- package/pp-core/bin/lib/loop-host-contract.cjs +105 -0
- package/pp-core/bin/lib/loop-resolver.cjs +479 -0
- package/pp-core/bin/lib/milestone.cjs +381 -0
- package/pp-core/bin/lib/model-catalog.cjs +154 -0
- package/pp-core/bin/lib/model-profiles.cjs +24 -0
- package/pp-core/bin/lib/model-resolver.cjs +467 -0
- package/pp-core/bin/lib/observability/event.cjs +51 -0
- package/pp-core/bin/lib/observability/logger.cjs +146 -0
- package/pp-core/bin/lib/observability/redaction.cjs +48 -0
- package/pp-core/bin/lib/package-identity.cjs +35 -0
- package/pp-core/bin/lib/package-legitimacy.cjs +368 -0
- package/pp-core/bin/lib/phase-command-router.cjs +209 -0
- package/pp-core/bin/lib/phase-id.cjs +213 -0
- package/pp-core/bin/lib/phase-lifecycle.cjs +74 -0
- package/pp-core/bin/lib/phase-locator.cjs +145 -0
- package/pp-core/bin/lib/phase.cjs +1446 -0
- package/pp-core/bin/lib/phases-command-router.cjs +43 -0
- package/pp-core/bin/lib/plan-drift-guard.cjs +117 -0
- package/pp-core/bin/lib/plan-scan.cjs +91 -0
- package/pp-core/bin/lib/planning-workspace.cjs +245 -0
- package/pp-core/bin/lib/probe-core.cjs +402 -0
- package/pp-core/bin/lib/profile-output.cjs +1164 -0
- package/pp-core/bin/lib/profile-pipeline-command-router.cjs +138 -0
- package/pp-core/bin/lib/profile-pipeline.cjs +519 -0
- package/pp-core/bin/lib/prohibition-enforcement.cjs +660 -0
- package/pp-core/bin/lib/project-root.cjs +119 -0
- package/pp-core/bin/lib/prompt-budget.cjs +305 -0
- package/pp-core/bin/lib/research-provider.cjs +137 -0
- package/pp-core/bin/lib/research-store.cjs +167 -0
- package/pp-core/bin/lib/review-reviewer-selection.cjs +121 -0
- package/pp-core/bin/lib/roadmap-command-router.cjs +166 -0
- package/pp-core/bin/lib/roadmap-parser.cjs +456 -0
- package/pp-core/bin/lib/roadmap-upgrade.cjs +476 -0
- package/pp-core/bin/lib/roadmap.cjs +738 -0
- package/pp-core/bin/lib/runtime-artifact-conversion.cjs +1966 -0
- package/pp-core/bin/lib/runtime-artifact-layout.cjs +342 -0
- package/pp-core/bin/lib/runtime-config-adapter-registry.cjs +103 -0
- package/pp-core/bin/lib/runtime-homes.cjs +272 -0
- package/pp-core/bin/lib/runtime-hooks-surface.cjs +1460 -0
- package/pp-core/bin/lib/runtime-name-policy.cjs +97 -0
- package/pp-core/bin/lib/runtime-slash.cjs +137 -0
- package/pp-core/bin/lib/schema-detect.cjs +159 -0
- package/pp-core/bin/lib/secrets.cjs +34 -0
- package/pp-core/bin/lib/security.cjs +480 -0
- package/pp-core/bin/lib/semver-compare.cjs +42 -0
- package/pp-core/bin/lib/shell-command-projection.cjs +550 -0
- package/pp-core/bin/lib/state-command-router.cjs +172 -0
- package/pp-core/bin/lib/state-document.cjs +312 -0
- package/pp-core/bin/lib/state.cjs +2587 -0
- package/pp-core/bin/lib/surface.cjs +505 -0
- package/pp-core/bin/lib/task-command-router.cjs +85 -0
- package/pp-core/bin/lib/teams-status.cjs +74 -0
- package/pp-core/bin/lib/template.cjs +246 -0
- package/pp-core/bin/lib/uat-predicate.cjs +329 -0
- package/pp-core/bin/lib/uat.cjs +359 -0
- package/pp-core/bin/lib/ui-safety-gate.cjs +98 -0
- package/pp-core/bin/lib/update-context.cjs +221 -0
- package/pp-core/bin/lib/validate-command-router.cjs +91 -0
- package/pp-core/bin/lib/validate.cjs +122 -0
- package/pp-core/bin/lib/verification-command-router.cjs +31 -0
- package/pp-core/bin/lib/verification.cjs +196 -0
- package/pp-core/bin/lib/verify-command-router.cjs +44 -0
- package/pp-core/bin/lib/verify.cjs +1932 -0
- package/pp-core/bin/lib/workstream-inventory-builder.cjs +81 -0
- package/pp-core/bin/lib/workstream-inventory.cjs +147 -0
- package/pp-core/bin/lib/workstream-name-policy.cjs +91 -0
- package/pp-core/bin/lib/workstream.cjs +386 -0
- package/pp-core/bin/lib/worktree-base-ref.cjs +350 -0
- package/pp-core/bin/lib/worktree-safety.cjs +985 -0
- package/pp-core/bin/pp-tools.cjs +2239 -0
- package/pp-core/bin/pp_run +20 -0
- package/pp-core/bin/shared/config-defaults.manifest.json +97 -0
- package/pp-core/bin/shared/config-schema.manifest.json +176 -0
- package/pp-core/bin/shared/model-catalog.json +160 -0
- package/pp-core/bin/shared/runtime-aliases.manifest.json +79 -0
- package/pp-core/bin/verify-reapply-patches.cjs +400 -0
- package/pp-core/contexts/dev.md +21 -0
- package/pp-core/contexts/research.md +22 -0
- package/pp-core/contexts/review.md +23 -0
- package/pp-core/references/agent-contracts.md +79 -0
- package/pp-core/references/ai-evals.md +156 -0
- package/pp-core/references/ai-frameworks.md +186 -0
- package/pp-core/references/artifact-types.md +131 -0
- package/pp-core/references/autonomous-smart-discuss.md +277 -0
- package/pp-core/references/checkpoints.md +814 -0
- package/pp-core/references/common-bug-patterns.md +114 -0
- package/pp-core/references/context-budget.md +85 -0
- package/pp-core/references/continuation-format.md +253 -0
- package/pp-core/references/debugger-philosophy.md +76 -0
- package/pp-core/references/decimal-phase-calculation.md +64 -0
- package/pp-core/references/doc-conflict-engine.md +91 -0
- package/pp-core/references/domain-probes.md +125 -0
- package/pp-core/references/edge-probe-fixtures/01-round-half-even/expected-coverage.json +7 -0
- package/pp-core/references/edge-probe-fixtures/01-round-half-even/requirements.json +1 -0
- package/pp-core/references/edge-probe-fixtures/02-merge-intervals/expected-coverage.json +8 -0
- package/pp-core/references/edge-probe-fixtures/02-merge-intervals/requirements.json +1 -0
- package/pp-core/references/edge-probe-fixtures/03-truncate-graphemes/expected-coverage.json +7 -0
- package/pp-core/references/edge-probe-fixtures/03-truncate-graphemes/requirements.json +1 -0
- package/pp-core/references/edge-probe-fixtures/04-money-rounding/expected-coverage.json +7 -0
- package/pp-core/references/edge-probe-fixtures/04-money-rounding/requirements.json +1 -0
- package/pp-core/references/edge-probe-fixtures/05-list-dedupe/expected-coverage.json +8 -0
- package/pp-core/references/edge-probe-fixtures/05-list-dedupe/requirements.json +1 -0
- package/pp-core/references/edge-probe-fixtures/06-resolved-mixed/expected-coverage.json +8 -0
- package/pp-core/references/edge-probe-fixtures/06-resolved-mixed/requirements.json +1 -0
- package/pp-core/references/edge-probe-fixtures/06-resolved-mixed/resolutions.json +4 -0
- package/pp-core/references/edge-probe.md +272 -0
- package/pp-core/references/execute-mvp-tdd.md +81 -0
- package/pp-core/references/executor-examples.md +110 -0
- package/pp-core/references/few-shot-examples/plan-checker.md +73 -0
- package/pp-core/references/few-shot-examples/verifier.md +109 -0
- package/pp-core/references/gate-prompts.md +100 -0
- package/pp-core/references/gates.md +70 -0
- package/pp-core/references/git-integration.md +298 -0
- package/pp-core/references/git-planning-commit.md +40 -0
- package/pp-core/references/ios-scaffold.md +123 -0
- package/pp-core/references/loop-hook-dispatch.md +61 -0
- package/pp-core/references/mandatory-initial-read.md +2 -0
- package/pp-core/references/model-profile-resolution.md +38 -0
- package/pp-core/references/model-profiles.md +245 -0
- package/pp-core/references/mvp-concepts.md +49 -0
- package/pp-core/references/phase-argument-parsing.md +61 -0
- package/pp-core/references/planner-antipatterns.md +176 -0
- package/pp-core/references/planner-chunked.md +49 -0
- package/pp-core/references/planner-gap-closure.md +62 -0
- package/pp-core/references/planner-graphify-auto-update.md +67 -0
- package/pp-core/references/planner-guidance.md +186 -0
- package/pp-core/references/planner-human-verify-mode.md +57 -0
- package/pp-core/references/planner-interface-context.md +62 -0
- package/pp-core/references/planner-load-graph-context.md +36 -0
- package/pp-core/references/planner-mvp-mode.md +53 -0
- package/pp-core/references/planner-reviews.md +42 -0
- package/pp-core/references/planner-revision.md +87 -0
- package/pp-core/references/planner-source-audit.md +73 -0
- package/pp-core/references/planning-config.md +477 -0
- package/pp-core/references/prohibition-probe-fixtures/01-streak-reminder/expected.json +14 -0
- package/pp-core/references/prohibition-probe-fixtures/02-clean-utility/expected.json +4 -0
- package/pp-core/references/prohibition-probe-fixtures/03-multi-prohibition/expected.json +32 -0
- package/pp-core/references/prohibition-probe.md +326 -0
- package/pp-core/references/project-skills-discovery.md +19 -0
- package/pp-core/references/questioning.md +162 -0
- package/pp-core/references/research-documentation-lookup.md +29 -0
- package/pp-core/references/research-philosophy.md +29 -0
- package/pp-core/references/research-verification-protocol.md +27 -0
- package/pp-core/references/revision-loop.md +97 -0
- package/pp-core/references/scout-codebase.md +51 -0
- package/pp-core/references/skeleton-template.md +48 -0
- package/pp-core/references/sketch-interactivity.md +41 -0
- package/pp-core/references/sketch-theme-system.md +94 -0
- package/pp-core/references/sketch-tooling.md +45 -0
- package/pp-core/references/sketch-variant-patterns.md +81 -0
- package/pp-core/references/spidr-splitting.md +69 -0
- package/pp-core/references/tdd.md +330 -0
- package/pp-core/references/thinking-models-debug.md +44 -0
- package/pp-core/references/thinking-models-execution.md +50 -0
- package/pp-core/references/thinking-models-planning.md +62 -0
- package/pp-core/references/thinking-models-research.md +50 -0
- package/pp-core/references/thinking-models-verification.md +55 -0
- package/pp-core/references/thinking-partner.md +96 -0
- package/pp-core/references/ui-brand.md +162 -0
- package/pp-core/references/universal-anti-patterns.md +63 -0
- package/pp-core/references/user-profiling.md +681 -0
- package/pp-core/references/user-story-template.md +58 -0
- package/pp-core/references/verification-overrides.md +227 -0
- package/pp-core/references/verification-patterns.md +612 -0
- package/pp-core/references/verify-mvp-mode.md +85 -0
- package/pp-core/references/workstream-flag.md +111 -0
- package/pp-core/references/worktree-branch-check.md +44 -0
- package/pp-core/references/worktree-path-safety.md +67 -0
- package/pp-core/templates/AI-SPEC.md +246 -0
- package/pp-core/templates/DEBUG.md +169 -0
- package/pp-core/templates/README.md +77 -0
- package/pp-core/templates/SECURITY.md +61 -0
- package/pp-core/templates/UAT.md +265 -0
- package/pp-core/templates/UI-SPEC.md +100 -0
- package/pp-core/templates/VALIDATION.md +76 -0
- package/pp-core/templates/claude-md.md +145 -0
- package/pp-core/templates/codebase/architecture.md +255 -0
- package/pp-core/templates/codebase/concerns.md +310 -0
- package/pp-core/templates/codebase/conventions.md +307 -0
- package/pp-core/templates/codebase/integrations.md +280 -0
- package/pp-core/templates/codebase/stack.md +186 -0
- package/pp-core/templates/codebase/structure.md +285 -0
- package/pp-core/templates/codebase/testing.md +480 -0
- package/pp-core/templates/config.json +62 -0
- package/pp-core/templates/context.md +352 -0
- package/pp-core/templates/continue-here.md +78 -0
- package/pp-core/templates/copilot-instructions.md +7 -0
- package/pp-core/templates/debug-subagent-prompt.md +91 -0
- package/pp-core/templates/dev-preferences.md +21 -0
- package/pp-core/templates/discovery.md +146 -0
- package/pp-core/templates/discussion-log.md +63 -0
- package/pp-core/templates/milestone-archive.md +123 -0
- package/pp-core/templates/milestone.md +115 -0
- package/pp-core/templates/phase-prompt.md +610 -0
- package/pp-core/templates/planner-subagent-prompt.md +117 -0
- package/pp-core/templates/project.md +203 -0
- package/pp-core/templates/requirements.md +231 -0
- package/pp-core/templates/research-project/ARCHITECTURE.md +204 -0
- package/pp-core/templates/research-project/FEATURES.md +147 -0
- package/pp-core/templates/research-project/PITFALLS.md +200 -0
- package/pp-core/templates/research-project/STACK.md +120 -0
- package/pp-core/templates/research-project/SUMMARY.md +170 -0
- package/pp-core/templates/research.md +592 -0
- package/pp-core/templates/retrospective.md +54 -0
- package/pp-core/templates/roadmap.md +202 -0
- package/pp-core/templates/spec.md +333 -0
- package/pp-core/templates/state.md +195 -0
- package/pp-core/templates/summary-complex.md +60 -0
- package/pp-core/templates/summary-minimal.md +42 -0
- package/pp-core/templates/summary-standard.md +49 -0
- package/pp-core/templates/summary.md +249 -0
- package/pp-core/templates/user-profile.md +146 -0
- package/pp-core/templates/user-setup.md +311 -0
- package/pp-core/templates/verification-report.md +335 -0
- package/pp-core/workflows/_runtime-launcher.snippet.sh +1 -0
- package/pp-core/workflows/add-backlog.md +91 -0
- package/pp-core/workflows/add-phase.md +113 -0
- package/pp-core/workflows/add-tests.md +355 -0
- package/pp-core/workflows/add-todo.md +161 -0
- package/pp-core/workflows/ai-integration-phase.md +295 -0
- package/pp-core/workflows/analyze-dependencies.md +96 -0
- package/pp-core/workflows/audit-fix.md +178 -0
- package/pp-core/workflows/audit-milestone.md +362 -0
- package/pp-core/workflows/audit-uat.md +110 -0
- package/pp-core/workflows/autonomous.md +886 -0
- package/pp-core/workflows/check-todos.md +180 -0
- package/pp-core/workflows/cleanup.md +195 -0
- package/pp-core/workflows/code-review-fix.md +506 -0
- package/pp-core/workflows/code-review.md +696 -0
- package/pp-core/workflows/complete-milestone.md +857 -0
- package/pp-core/workflows/debug.md +237 -0
- package/pp-core/workflows/diagnose-issues.md +245 -0
- package/pp-core/workflows/discovery-phase.md +291 -0
- package/pp-core/workflows/discovery-sprint.md +1546 -0
- package/pp-core/workflows/discuss-phase/modes/advisor.md +176 -0
- package/pp-core/workflows/discuss-phase/modes/all.md +28 -0
- package/pp-core/workflows/discuss-phase/modes/analyze.md +44 -0
- package/pp-core/workflows/discuss-phase/modes/auto.md +57 -0
- package/pp-core/workflows/discuss-phase/modes/batch.md +52 -0
- package/pp-core/workflows/discuss-phase/modes/chain.md +98 -0
- package/pp-core/workflows/discuss-phase/modes/default.md +141 -0
- package/pp-core/workflows/discuss-phase/modes/power.md +44 -0
- package/pp-core/workflows/discuss-phase/modes/text.md +55 -0
- package/pp-core/workflows/discuss-phase/templates/checkpoint.json +18 -0
- package/pp-core/workflows/discuss-phase/templates/context.md +136 -0
- package/pp-core/workflows/discuss-phase/templates/discussion-log.md +50 -0
- package/pp-core/workflows/discuss-phase-assumptions.md +675 -0
- package/pp-core/workflows/discuss-phase-power.md +291 -0
- package/pp-core/workflows/discuss-phase.md +520 -0
- package/pp-core/workflows/do.md +111 -0
- package/pp-core/workflows/docs-update.md +1168 -0
- package/pp-core/workflows/edit-phase.md +295 -0
- package/pp-core/workflows/eval-review.md +159 -0
- package/pp-core/workflows/execute-phase/steps/codebase-drift-gate.md +95 -0
- package/pp-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +94 -0
- package/pp-core/workflows/execute-phase/steps/post-merge-gate.md +117 -0
- package/pp-core/workflows/execute-phase/steps/worktree-recovery-policy.md +9 -0
- package/pp-core/workflows/execute-phase.md +1707 -0
- package/pp-core/workflows/execute-plan.md +541 -0
- package/pp-core/workflows/explore.md +146 -0
- package/pp-core/workflows/extract-learnings.md +243 -0
- package/pp-core/workflows/fast.md +124 -0
- package/pp-core/workflows/forensics.md +279 -0
- package/pp-core/workflows/graduation.md +196 -0
- package/pp-core/workflows/health.md +224 -0
- package/pp-core/workflows/help/modes/brief.md +22 -0
- package/pp-core/workflows/help/modes/default.md +50 -0
- package/pp-core/workflows/help/modes/full.md +791 -0
- package/pp-core/workflows/help/modes/topic.md +74 -0
- package/pp-core/workflows/help.md +24 -0
- package/pp-core/workflows/import.md +256 -0
- package/pp-core/workflows/inbox.md +387 -0
- package/pp-core/workflows/ingest-docs.md +340 -0
- package/pp-core/workflows/insert-phase.md +152 -0
- package/pp-core/workflows/list-phase-assumptions.md +178 -0
- package/pp-core/workflows/list-workspaces.md +57 -0
- package/pp-core/workflows/manager.md +435 -0
- package/pp-core/workflows/map-codebase.md +444 -0
- package/pp-core/workflows/milestone-summary.md +224 -0
- package/pp-core/workflows/mvp-phase.md +222 -0
- package/pp-core/workflows/new-milestone.md +643 -0
- package/pp-core/workflows/new-project.md +1563 -0
- package/pp-core/workflows/new-workspace.md +240 -0
- package/pp-core/workflows/next.md +347 -0
- package/pp-core/workflows/node-repair.md +92 -0
- package/pp-core/workflows/note.md +158 -0
- package/pp-core/workflows/pause-work.md +250 -0
- package/pp-core/workflows/plan-milestone-gaps.md +281 -0
- package/pp-core/workflows/plan-phase.md +1755 -0
- package/pp-core/workflows/plan-review-convergence.md +369 -0
- package/pp-core/workflows/plant-seed.md +230 -0
- package/pp-core/workflows/pr-branch.md +159 -0
- package/pp-core/workflows/profile-user.md +455 -0
- package/pp-core/workflows/progress.md +756 -0
- package/pp-core/workflows/quick.md +1045 -0
- package/pp-core/workflows/reapply-patches.md +443 -0
- package/pp-core/workflows/remove-phase.md +156 -0
- package/pp-core/workflows/remove-workspace.md +108 -0
- package/pp-core/workflows/resume-project.md +348 -0
- package/pp-core/workflows/review.md +765 -0
- package/pp-core/workflows/scan.md +107 -0
- package/pp-core/workflows/secure-phase.md +184 -0
- package/pp-core/workflows/session-report.md +146 -0
- package/pp-core/workflows/settings-advanced.md +816 -0
- package/pp-core/workflows/settings-integrations.md +312 -0
- package/pp-core/workflows/settings.md +592 -0
- package/pp-core/workflows/ship.md +465 -0
- package/pp-core/workflows/sketch-wrap-up.md +286 -0
- package/pp-core/workflows/sketch.md +361 -0
- package/pp-core/workflows/spec-phase.md +495 -0
- package/pp-core/workflows/spike-wrap-up.md +307 -0
- package/pp-core/workflows/spike.md +453 -0
- package/pp-core/workflows/stats.md +80 -0
- package/pp-core/workflows/sync-skills.md +182 -0
- package/pp-core/workflows/thread.md +222 -0
- package/pp-core/workflows/transition.md +694 -0
- package/pp-core/workflows/ui-phase.md +328 -0
- package/pp-core/workflows/ui-review.md +193 -0
- package/pp-core/workflows/ultraplan-phase.md +199 -0
- package/pp-core/workflows/undo.md +314 -0
- package/pp-core/workflows/update.md +501 -0
- package/pp-core/workflows/validate-phase.md +183 -0
- package/pp-core/workflows/verify-phase.md +569 -0
- package/pp-core/workflows/verify-work.md +804 -0
- package/scripts/affected-tests-lib.cjs +554 -0
- package/scripts/audit-workflow-script-paths.cjs +73 -0
- package/scripts/base64-scan.sh +351 -0
- package/scripts/build-hooks.js +254 -0
- package/scripts/changeset/README.md +129 -0
- package/scripts/changeset/cli.cjs +597 -0
- package/scripts/changeset/github-release-notes.cjs +199 -0
- package/scripts/changeset/lint.cjs +147 -0
- package/scripts/changeset/new.cjs +151 -0
- package/scripts/changeset/parse.cjs +114 -0
- package/scripts/changeset/render.cjs +34 -0
- package/scripts/changeset/serialize.cjs +130 -0
- package/scripts/check-alias-drift.cjs +114 -0
- package/scripts/check-env.cjs +312 -0
- package/scripts/check-npm-integrity.cjs +215 -0
- package/scripts/ci-guard-runner.cjs +22 -0
- package/scripts/ci-prepare-test-scope.cjs +93 -0
- package/scripts/ci-rebase-check.cjs +86 -0
- package/scripts/ci-test-scope.cjs +441 -0
- package/scripts/command-contract-helpers.cjs +64 -0
- package/scripts/diff-touches-shipped-paths.cjs +149 -0
- package/scripts/fix-slash-commands.cjs +161 -0
- package/scripts/gen-capability-registry.cjs +2646 -0
- package/scripts/gen-commands-reference.cjs +139 -0
- package/scripts/gen-inventory-manifest.cjs +114 -0
- package/scripts/gen-loop-host-contract.cjs +526 -0
- package/scripts/gen-research-agents.cjs +276 -0
- package/scripts/generate-package-identity.cjs +134 -0
- package/scripts/issue-dedupe.cjs +278 -0
- package/scripts/issue-version-gate.cjs +140 -0
- package/scripts/lib/allowlist-ratchet.cjs +236 -0
- package/scripts/lib/cli-exit.cjs +56 -0
- package/scripts/lint-allow-test-rule-refs.allowlist.json +328 -0
- package/scripts/lint-allow-test-rule-refs.cjs +162 -0
- package/scripts/lint-command-contract.cjs +118 -0
- package/scripts/lint-descriptions.cjs +87 -0
- package/scripts/lint-docs-required.cjs +222 -0
- package/scripts/lint-legacy-dir-name.cjs +166 -0
- package/scripts/lint-package-identity-drift.cjs +141 -0
- package/scripts/lint-pr-check-project-dir.cjs +99 -0
- package/scripts/lint-regression-test-names.allowlist.json +269 -0
- package/scripts/lint-regression-test-names.cjs +117 -0
- package/scripts/lint-shell-command-projection-drift.cjs +62 -0
- package/scripts/lint-skill-deps.cjs +185 -0
- package/scripts/lint-test-file-count.allowlist.json +181 -0
- package/scripts/lint-test-file-count.cjs +246 -0
- package/scripts/lint-windows-test-portability.cjs +178 -0
- package/scripts/mutation-matrix.cjs +323 -0
- package/scripts/pr-target-policy.cjs +63 -0
- package/scripts/pr-template-policy.cjs +268 -0
- package/scripts/prompt-injection-scan.sh +207 -0
- package/scripts/registry-smoke.cjs +337 -0
- package/scripts/release-notes/discord-release-summary.cjs +373 -0
- package/scripts/release-notes/format-github-release-notes.cjs +261 -0
- package/scripts/release-tarball-smoke.cjs +763 -0
- package/scripts/research-profiles.cjs +149 -0
- package/scripts/run-affected-tests.cjs +7 -0
- package/scripts/run-tests.cjs +589 -0
- package/scripts/secret-scan-lint.sh +231 -0
- package/scripts/secret-scan.sh +358 -0
- package/scripts/setup-branch-protection.sh +234 -0
- package/scripts/strip-prose-atrefs.cjs +106 -0
- package/scripts/sync-manifest-versions.cjs +119 -0
- package/scripts/sync-next-version.cjs +133 -0
- package/scripts/sync-rulesets.sh +34 -0
- package/scripts/sync-runtime-launcher.cjs +425 -0
- package/scripts/test-failure-reasons.cjs +34 -0
- package/scripts/update-size-baseline.cjs +68 -0
- package/scripts/verify-npm-publish.cjs +240 -0
- package/scripts/verify-opengsd-sweep.cjs +288 -0
- package/scripts/verify-phase-02-rename.sh +258 -0
- package/scripts/verify-phase-03-rename.sh +376 -0
- package/scripts/workflow-policy.cjs +483 -0
- package/scripts/workflow-size.cjs +90 -0
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const yaml = require('js-yaml');
|
|
6
|
+
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Policy: native shell per OS
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
const POLICY = Object.freeze({
|
|
11
|
+
'ubuntu-latest': 'bash',
|
|
12
|
+
'ubuntu-22.04': 'bash',
|
|
13
|
+
'ubuntu-24.04': 'bash',
|
|
14
|
+
'macos-latest': 'zsh',
|
|
15
|
+
'macos-13': 'zsh',
|
|
16
|
+
'macos-14': 'zsh',
|
|
17
|
+
'macos-15': 'zsh',
|
|
18
|
+
'windows-latest': 'pwsh',
|
|
19
|
+
'windows-2022': 'pwsh',
|
|
20
|
+
'windows-2025': 'pwsh',
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const VIOLATION = Object.freeze({
|
|
24
|
+
WRONG_SHELL_FOR_OS: 'wrong_shell_for_os',
|
|
25
|
+
MACOS_MISSING_EXPLICIT_ZSH: 'macos_missing_explicit_zsh',
|
|
26
|
+
UNKNOWN_RUNNER: 'unknown_runner',
|
|
27
|
+
UNRESOLVABLE_MATRIX: 'unresolvable_matrix',
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
// Runner default (GitHub Actions documented defaults, not policy)
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
function runnerDefault(runner) {
|
|
34
|
+
if (!runner) return null;
|
|
35
|
+
if (runner.startsWith('windows-')) return 'pwsh';
|
|
36
|
+
return 'bash'; // ubuntu-* and macos-* both default to bash on GHA
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Matrix expansion helpers
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
// Build the GitHub Actions Cartesian product of the given base-list matrix
|
|
44
|
+
// keys. Returns one context object per realized job, each mapping every key
|
|
45
|
+
// to a stringified value. A single key yields one context per value (identical
|
|
46
|
+
// to the legacy base-list expansion); N keys yield the full cross-product.
|
|
47
|
+
// Values are stringified to match runner-label comparison and matrix-expression
|
|
48
|
+
// resolution, which operate on strings.
|
|
49
|
+
function cartesianProduct(keys, matrix) {
|
|
50
|
+
return keys.reduce(
|
|
51
|
+
(contexts, key) =>
|
|
52
|
+
contexts.flatMap((context) =>
|
|
53
|
+
matrix[key].map((value) => ({ ...context, [key]: String(value) })),
|
|
54
|
+
),
|
|
55
|
+
[{}],
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
// Matrix expansion
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Expand a runs-on expression against a job's strategy.matrix.
|
|
65
|
+
* Returns an array of { runner: string, resolvable: boolean, context: object }
|
|
66
|
+
* objects where `context` holds ALL key→value pairs for the realization row
|
|
67
|
+
* (so shell expressions like ${{ matrix.shell }} can be resolved against it).
|
|
68
|
+
* 'resolvable: false' means the expression was an unresolved matrix ref.
|
|
69
|
+
*/
|
|
70
|
+
function expandRunsOn(runsOnRaw, matrix) {
|
|
71
|
+
if (!runsOnRaw) return [];
|
|
72
|
+
|
|
73
|
+
const raw = String(runsOnRaw).trim();
|
|
74
|
+
|
|
75
|
+
// Detect matrix expression: ${{ matrix.X }} or ${{ matrix['X'] }}
|
|
76
|
+
const matrixExprRe = /\$\{\{\s*matrix\.(\w+)\s*\}\}/;
|
|
77
|
+
const match = raw.match(matrixExprRe);
|
|
78
|
+
|
|
79
|
+
if (!match) {
|
|
80
|
+
// Literal runner label
|
|
81
|
+
return [{ runner: raw, resolvable: true, context: {} }];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const key = match[1];
|
|
85
|
+
|
|
86
|
+
if (!matrix) {
|
|
87
|
+
return [{ runner: raw, resolvable: false, context: {} }];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const realizations = [];
|
|
91
|
+
|
|
92
|
+
// matrix.include entries carry complete row context — prefer them as they
|
|
93
|
+
// contain all keys (os, node-version, shell, full_only, etc.).
|
|
94
|
+
// Each include row is a distinct CI realization and must be validated
|
|
95
|
+
// independently — even if two rows share the same runner label, their
|
|
96
|
+
// contexts (and therefore effective shells) may differ.
|
|
97
|
+
if (Array.isArray(matrix.include)) {
|
|
98
|
+
for (const entry of matrix.include) {
|
|
99
|
+
if (entry && entry[key] != null) {
|
|
100
|
+
const runner = String(entry[key]);
|
|
101
|
+
// Clone all keys from include row as the realization context
|
|
102
|
+
const context = {};
|
|
103
|
+
for (const [k, v] of Object.entries(entry)) {
|
|
104
|
+
context[k] = v != null ? String(v) : '';
|
|
105
|
+
}
|
|
106
|
+
realizations.push({ runner, resolvable: true, context });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// GitHub Actions realizes one job per element of the Cartesian product of all
|
|
112
|
+
// base-list matrix keys (every matrix.<k> that is an array, excluding the
|
|
113
|
+
// include/exclude control keys), and each realized job's context carries a
|
|
114
|
+
// value for EVERY matrix key — so ${{ matrix.<key> }} references (e.g. in a
|
|
115
|
+
// shell: field) resolve against any realization, not only the runs-on key.
|
|
116
|
+
// Single-axis matrices yield exactly one realization per value, identical to
|
|
117
|
+
// the prior behavior; only multi-axis matrices change shape.
|
|
118
|
+
// Each realization is pushed unconditionally — deduplicating by runner label
|
|
119
|
+
// would collapse distinct Cartesian rows (e.g. matrix.os: [macos-latest,
|
|
120
|
+
// macos-latest] paired with different shells) and hide policy violations.
|
|
121
|
+
if (Array.isArray(matrix[key])) {
|
|
122
|
+
const baseListKeys = Object.keys(matrix).filter(
|
|
123
|
+
(k) => k !== 'include' && k !== 'exclude' && Array.isArray(matrix[k]),
|
|
124
|
+
);
|
|
125
|
+
for (const context of cartesianProduct(baseListKeys, matrix)) {
|
|
126
|
+
realizations.push({ runner: context[key], resolvable: true, context });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// matrix.exclude: remove matches by runner label (first match only).
|
|
131
|
+
// KNOWN LIMITATION (out of scope for #435, tracked as a follow-up): this
|
|
132
|
+
// matches on the runs-on key's runner label rather than the full exclude
|
|
133
|
+
// tuple, so a multi-axis exclude like { os: macos-latest, shell: bash } can
|
|
134
|
+
// remove the wrong cross-product cell. Full GitHub Actions tuple-match
|
|
135
|
+
// (including the include-rows-are-not-excluded rule) is deferred; #435 scopes
|
|
136
|
+
// only the base-list cross-product expansion above.
|
|
137
|
+
if (Array.isArray(matrix.exclude)) {
|
|
138
|
+
for (const excl of matrix.exclude) {
|
|
139
|
+
if (excl && excl[key] != null) {
|
|
140
|
+
const exclRunner = String(excl[key]);
|
|
141
|
+
const idx = realizations.findIndex(r => r.runner === exclRunner);
|
|
142
|
+
if (idx !== -1) realizations.splice(idx, 1);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (realizations.length === 0) {
|
|
148
|
+
// Could not resolve — no concrete values found
|
|
149
|
+
return [{ runner: raw, resolvable: false, context: {} }];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return realizations;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ---------------------------------------------------------------------------
|
|
156
|
+
// Matrix expression resolution
|
|
157
|
+
// ---------------------------------------------------------------------------
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* If `expr` is a `${{ matrix.<key> }}` expression, look up the value in
|
|
161
|
+
* `realizationContext` (a plain-object snapshot of one matrix.include row).
|
|
162
|
+
* Returns:
|
|
163
|
+
* { resolved: true, value: string } — expression resolved to a concrete value
|
|
164
|
+
* { resolved: false, key: string } — matrix key absent in this realization
|
|
165
|
+
* null — `expr` is not a matrix expression
|
|
166
|
+
*/
|
|
167
|
+
function resolveMatrixExpr(expr, realizationContext) {
|
|
168
|
+
if (!expr || typeof expr !== 'string') return null;
|
|
169
|
+
const m = expr.match(/^\s*\$\{\{\s*matrix\.(\w+)\s*\}\}\s*$/);
|
|
170
|
+
if (!m) return null;
|
|
171
|
+
const key = m[1];
|
|
172
|
+
if (!realizationContext || !(key in realizationContext)) {
|
|
173
|
+
return { resolved: false, key };
|
|
174
|
+
}
|
|
175
|
+
return { resolved: true, value: String(realizationContext[key]) };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ---------------------------------------------------------------------------
|
|
179
|
+
// Effective-shell resolution
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Given a step's shell, job defaults, workflow defaults, runner, and the
|
|
184
|
+
* current matrix realization context, return the effective shell that will
|
|
185
|
+
* actually execute.
|
|
186
|
+
*
|
|
187
|
+
* Matrix expressions (`${{ matrix.shell }}`) in any shell field are resolved
|
|
188
|
+
* against `realizationContext` (a plain object of key→value for the current
|
|
189
|
+
* matrix.include row).
|
|
190
|
+
*
|
|
191
|
+
* Returns:
|
|
192
|
+
* { shell: string, unresolvable: false } — concrete shell value
|
|
193
|
+
* { shell: null, unresolvable: true, key: string } — matrix expr present but key missing
|
|
194
|
+
*/
|
|
195
|
+
function effectiveShell(stepShell, jobDefaultsShell, workflowDefaultsShell, runner, realizationContext) {
|
|
196
|
+
for (const raw of [stepShell, jobDefaultsShell, workflowDefaultsShell]) {
|
|
197
|
+
if (!raw) continue;
|
|
198
|
+
const mx = resolveMatrixExpr(raw, realizationContext);
|
|
199
|
+
if (mx !== null) {
|
|
200
|
+
// It's a matrix expression
|
|
201
|
+
if (!mx.resolved) {
|
|
202
|
+
return { shell: null, unresolvable: true, key: mx.key };
|
|
203
|
+
}
|
|
204
|
+
return { shell: mx.value, unresolvable: false };
|
|
205
|
+
}
|
|
206
|
+
// Literal value
|
|
207
|
+
return { shell: raw, unresolvable: false };
|
|
208
|
+
}
|
|
209
|
+
// Nothing set at any level — use runner default
|
|
210
|
+
return { shell: runnerDefault(runner), unresolvable: false };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// ---------------------------------------------------------------------------
|
|
214
|
+
// Violation detection
|
|
215
|
+
// ---------------------------------------------------------------------------
|
|
216
|
+
/**
|
|
217
|
+
* Determines whether a step/runner combination violates shell policy.
|
|
218
|
+
*
|
|
219
|
+
* `rawStepShell`, `rawJobDefaultsShell`, `rawWorkflowDefaultsShell` are the
|
|
220
|
+
* raw (possibly matrix-expression) values before resolution. They're used
|
|
221
|
+
* only for the MACOS_MISSING_EXPLICIT_ZSH sub-classification: that violation
|
|
222
|
+
* fires only when nothing is set at any level (all three are null/empty AND
|
|
223
|
+
* the runner default is wrong).
|
|
224
|
+
*/
|
|
225
|
+
function detectViolation(runner, resolvedShell, rawStepShell, rawJobDefaultsShell, rawWorkflowDefaultsShell) {
|
|
226
|
+
if (!(runner in POLICY)) {
|
|
227
|
+
return VIOLATION.UNKNOWN_RUNNER;
|
|
228
|
+
}
|
|
229
|
+
const expected = POLICY[runner];
|
|
230
|
+
// GHA accepts custom shells as a format string containing '{0}' (e.g. 'zsh {0}').
|
|
231
|
+
// Per https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions
|
|
232
|
+
// the shell name before the space is the executable; strip the format suffix before
|
|
233
|
+
// comparing against the policy so 'zsh {0}' satisfies the 'zsh' requirement.
|
|
234
|
+
const normalizedShell = resolvedShell ? resolvedShell.replace(/\s+\{0\}$/, '') : resolvedShell;
|
|
235
|
+
if (normalizedShell !== expected) {
|
|
236
|
+
// Specific subtype for macOS missing explicit zsh:
|
|
237
|
+
// fires only when no shell is set at any level (inherited runner default).
|
|
238
|
+
if (runner.startsWith('macos-') && !rawStepShell && !rawJobDefaultsShell && !rawWorkflowDefaultsShell) {
|
|
239
|
+
return VIOLATION.MACOS_MISSING_EXPLICIT_ZSH;
|
|
240
|
+
}
|
|
241
|
+
return VIOLATION.WRONG_SHELL_FOR_OS;
|
|
242
|
+
}
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// ---------------------------------------------------------------------------
|
|
247
|
+
// Source map: find line numbers
|
|
248
|
+
// ---------------------------------------------------------------------------
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Find the line number of a string in YAML text.
|
|
252
|
+
* Returns 1-based line number of the first occurrence at or after startLine.
|
|
253
|
+
*/
|
|
254
|
+
function findLineNumber(yamlText, searchStr, startLine) {
|
|
255
|
+
const lines = yamlText.split('\n');
|
|
256
|
+
const start = Math.max(0, (startLine || 1) - 1);
|
|
257
|
+
for (let i = start; i < lines.length; i++) {
|
|
258
|
+
if (lines[i].includes(searchStr)) {
|
|
259
|
+
return i + 1;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
// Fall back to scanning from beginning
|
|
263
|
+
for (let i = 0; i < lines.length; i++) {
|
|
264
|
+
if (lines[i].includes(searchStr)) {
|
|
265
|
+
return i + 1;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return 1;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// ---------------------------------------------------------------------------
|
|
272
|
+
// Core inspector
|
|
273
|
+
// ---------------------------------------------------------------------------
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* inspectWorkflow(yamlText, { filePath }) → structured inspection result
|
|
277
|
+
*/
|
|
278
|
+
function inspectWorkflow(yamlText, { filePath = '<unknown>' } = {}) {
|
|
279
|
+
let doc;
|
|
280
|
+
try {
|
|
281
|
+
doc = yaml.load(yamlText, { schema: yaml.DEFAULT_SCHEMA });
|
|
282
|
+
} catch (e) {
|
|
283
|
+
return {
|
|
284
|
+
filePath,
|
|
285
|
+
jobs: [],
|
|
286
|
+
workflowDefaultsShell: null,
|
|
287
|
+
parseError: e.message,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (!doc || typeof doc !== 'object') {
|
|
292
|
+
return { filePath, jobs: [], workflowDefaultsShell: null };
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const workflowDefaultsShell =
|
|
296
|
+
doc.defaults?.run?.shell ?? null;
|
|
297
|
+
|
|
298
|
+
const jobs = [];
|
|
299
|
+
|
|
300
|
+
for (const [jobId, jobDef] of Object.entries(doc.jobs || {})) {
|
|
301
|
+
if (!jobDef || typeof jobDef !== 'object') continue;
|
|
302
|
+
|
|
303
|
+
const runsOnRaw = jobDef['runs-on'];
|
|
304
|
+
const matrix = jobDef.strategy?.matrix ?? null;
|
|
305
|
+
const jobDefaultsShell = jobDef.defaults?.run?.shell ?? null;
|
|
306
|
+
|
|
307
|
+
const runsOnStr = runsOnRaw != null ? String(runsOnRaw) : '';
|
|
308
|
+
const runsOnExpressions = [runsOnStr];
|
|
309
|
+
const runnerRealizations = expandRunsOn(runsOnStr, matrix);
|
|
310
|
+
|
|
311
|
+
const steps = [];
|
|
312
|
+
|
|
313
|
+
for (const [stepIndex, step] of (jobDef.steps || []).entries()) {
|
|
314
|
+
if (!step || typeof step !== 'object') continue;
|
|
315
|
+
|
|
316
|
+
// Only check steps that actually run shell scripts (have `run:`)
|
|
317
|
+
if (!step.run) continue;
|
|
318
|
+
|
|
319
|
+
const stepShell = step.shell ?? null;
|
|
320
|
+
const stepName = step.name ?? `step-${stepIndex}`;
|
|
321
|
+
|
|
322
|
+
for (const { runner, resolvable, context: realizationContext } of runnerRealizations) {
|
|
323
|
+
if (!resolvable) {
|
|
324
|
+
// Can't resolve runner — emit UNRESOLVABLE_MATRIX
|
|
325
|
+
const lineNum = findLineNumber(yamlText, stepName !== `step-${stepIndex}` ? stepName : String(step.run).slice(0, 20));
|
|
326
|
+
steps.push({
|
|
327
|
+
index: stepIndex,
|
|
328
|
+
name: stepName,
|
|
329
|
+
stepShell,
|
|
330
|
+
effectiveShell: null,
|
|
331
|
+
runner,
|
|
332
|
+
violation: VIOLATION.UNRESOLVABLE_MATRIX,
|
|
333
|
+
evidence: {
|
|
334
|
+
line: lineNum,
|
|
335
|
+
snippet: `runs-on: ${runsOnStr} (unresolvable matrix expression)`,
|
|
336
|
+
},
|
|
337
|
+
});
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const effResult = effectiveShell(stepShell, jobDefaultsShell, workflowDefaultsShell, runner, realizationContext);
|
|
342
|
+
|
|
343
|
+
// If a matrix expression referenced a key not present in this realization row
|
|
344
|
+
if (effResult.unresolvable) {
|
|
345
|
+
const lineNum = findLineNumber(yamlText, stepName !== `step-${stepIndex}` ? stepName : String(step.run).slice(0, 20));
|
|
346
|
+
steps.push({
|
|
347
|
+
index: stepIndex,
|
|
348
|
+
name: stepName,
|
|
349
|
+
stepShell,
|
|
350
|
+
effectiveShell: null,
|
|
351
|
+
runner,
|
|
352
|
+
violation: VIOLATION.UNRESOLVABLE_MATRIX,
|
|
353
|
+
evidence: {
|
|
354
|
+
line: lineNum,
|
|
355
|
+
snippet: `matrix.${effResult.key} not present in realization for runner=${runner}`,
|
|
356
|
+
},
|
|
357
|
+
});
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const eff = effResult.shell;
|
|
362
|
+
const violation = detectViolation(runner, eff, stepShell, jobDefaultsShell, workflowDefaultsShell);
|
|
363
|
+
|
|
364
|
+
// Find evidence line: prefer step name, then shell:, then run: content
|
|
365
|
+
let evidenceLine = 1;
|
|
366
|
+
let evidenceSnippet = '';
|
|
367
|
+
|
|
368
|
+
if (stepName !== `step-${stepIndex}`) {
|
|
369
|
+
evidenceLine = findLineNumber(yamlText, stepName);
|
|
370
|
+
evidenceSnippet = `name: ${stepName}`;
|
|
371
|
+
} else if (stepShell) {
|
|
372
|
+
evidenceLine = findLineNumber(yamlText, `shell: ${stepShell}`);
|
|
373
|
+
evidenceSnippet = `shell: ${stepShell}`;
|
|
374
|
+
} else {
|
|
375
|
+
const runSnippet = String(step.run).split('\n')[0].slice(0, 40);
|
|
376
|
+
evidenceLine = findLineNumber(yamlText, runSnippet);
|
|
377
|
+
evidenceSnippet = runSnippet;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
steps.push({
|
|
381
|
+
index: stepIndex,
|
|
382
|
+
name: stepName,
|
|
383
|
+
stepShell,
|
|
384
|
+
effectiveShell: eff,
|
|
385
|
+
runner,
|
|
386
|
+
violation: violation ?? null,
|
|
387
|
+
evidence: {
|
|
388
|
+
line: evidenceLine,
|
|
389
|
+
snippet: evidenceSnippet,
|
|
390
|
+
},
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
const resolvedRunners = runnerRealizations
|
|
396
|
+
.filter(r => r.resolvable)
|
|
397
|
+
.map(r => r.runner);
|
|
398
|
+
|
|
399
|
+
jobs.push({
|
|
400
|
+
jobId,
|
|
401
|
+
runsOnExpressions,
|
|
402
|
+
resolvedRunners,
|
|
403
|
+
defaultsShell: jobDefaultsShell,
|
|
404
|
+
steps,
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
return {
|
|
409
|
+
filePath,
|
|
410
|
+
jobs,
|
|
411
|
+
workflowDefaultsShell,
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* inspectWorkflowFile(absPath) — reads file from disk and calls inspectWorkflow.
|
|
417
|
+
*/
|
|
418
|
+
function inspectWorkflowFile(absPath) {
|
|
419
|
+
const text = fs.readFileSync(absPath, 'utf8');
|
|
420
|
+
return inspectWorkflow(text, { filePath: absPath });
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// ---------------------------------------------------------------------------
|
|
424
|
+
// runPolicyLint
|
|
425
|
+
// ---------------------------------------------------------------------------
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* runPolicyLint({ workflowsDir }) → { violations, summary }
|
|
429
|
+
*/
|
|
430
|
+
function runPolicyLint({ workflowsDir }) {
|
|
431
|
+
const absDir = path.resolve(workflowsDir);
|
|
432
|
+
const files = fs.readdirSync(absDir)
|
|
433
|
+
.filter(f => f.endsWith('.yml') || f.endsWith('.yaml'))
|
|
434
|
+
.map(f => path.join(absDir, f))
|
|
435
|
+
.sort();
|
|
436
|
+
|
|
437
|
+
const violations = [];
|
|
438
|
+
|
|
439
|
+
for (const filePath of files) {
|
|
440
|
+
const result = inspectWorkflowFile(filePath);
|
|
441
|
+
for (const job of result.jobs) {
|
|
442
|
+
for (const step of job.steps) {
|
|
443
|
+
if (step.violation) {
|
|
444
|
+
violations.push({
|
|
445
|
+
filePath: result.filePath,
|
|
446
|
+
jobId: job.jobId,
|
|
447
|
+
stepIndex: step.index,
|
|
448
|
+
stepName: step.name,
|
|
449
|
+
runner: step.runner,
|
|
450
|
+
effectiveShell: step.effectiveShell,
|
|
451
|
+
stepShell: step.stepShell,
|
|
452
|
+
violation: step.violation,
|
|
453
|
+
evidence: step.evidence,
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
const perViolationType = {};
|
|
461
|
+
for (const v of violations) {
|
|
462
|
+
perViolationType[v.violation] = (perViolationType[v.violation] || 0) + 1;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
return {
|
|
466
|
+
violations,
|
|
467
|
+
summary: {
|
|
468
|
+
total: violations.length,
|
|
469
|
+
perViolationType,
|
|
470
|
+
},
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// ---------------------------------------------------------------------------
|
|
475
|
+
// Exports
|
|
476
|
+
// ---------------------------------------------------------------------------
|
|
477
|
+
module.exports = {
|
|
478
|
+
POLICY,
|
|
479
|
+
VIOLATION,
|
|
480
|
+
inspectWorkflow,
|
|
481
|
+
inspectWorkflowFile,
|
|
482
|
+
runPolicyLint,
|
|
483
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file workflow-size.cjs
|
|
5
|
+
*
|
|
6
|
+
* Single source of truth for measuring workflow `.md` file sizes in bytes.
|
|
7
|
+
*
|
|
8
|
+
* Shared by `tests/workflow-size-budget.test.cjs` (the CI guard) and
|
|
9
|
+
* `scripts/update-size-baseline.cjs` (the baseline generator) so the two can
|
|
10
|
+
* never disagree on HOW a file is measured. A divergence between the generator
|
|
11
|
+
* and the guard would silently mis-record the baseline (issue #1074).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const path = require('path');
|
|
16
|
+
|
|
17
|
+
const WORKFLOWS_DIR = path.join(__dirname, '..', 'pp-core', 'workflows');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Byte size of a file, counted as on an LF (Unix) checkout.
|
|
21
|
+
*
|
|
22
|
+
* The size budget is calibrated against `wc -c` on a Unix (LF) checkout, but
|
|
23
|
+
* these `.md` files have no `eol=lf` in `.gitattributes`, so Windows checks
|
|
24
|
+
* them out as CRLF. Counting raw on-disk bytes there adds one byte per line,
|
|
25
|
+
* a Windows-only false positive that diverges from the LF calibration basis
|
|
26
|
+
* (issue #683). Stripping CR yields the same LF byte count on every platform.
|
|
27
|
+
* This is still a raw byte count (not a trailing-newline-stripping line count).
|
|
28
|
+
*
|
|
29
|
+
* @param {string} filePath - Absolute or relative path to the file.
|
|
30
|
+
* @returns {number} LF-normalized byte length.
|
|
31
|
+
*/
|
|
32
|
+
function lfByteCount(filePath) {
|
|
33
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
34
|
+
return Buffer.byteLength(content.replace(/\r\n/g, '\n'), 'utf-8');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* List top-level workflow stems (filenames without the `.md` extension), sorted.
|
|
39
|
+
* Non-recursive by design: per-mode bodies under `workflows/<name>/modes/` and
|
|
40
|
+
* templates are NOT measured — only the always-loaded top-level workflows.
|
|
41
|
+
*
|
|
42
|
+
* @param {string} [dir] - Workflows directory (defaults to the canonical one).
|
|
43
|
+
* @returns {string[]} Sorted stems, e.g. `['autonomous', 'plan-phase', ...]`.
|
|
44
|
+
*/
|
|
45
|
+
function listWorkflowStems(dir = WORKFLOWS_DIR) {
|
|
46
|
+
return fs
|
|
47
|
+
.readdirSync(dir)
|
|
48
|
+
.filter((f) => f.endsWith('.md'))
|
|
49
|
+
.map((f) => f.replace(/\.md$/, ''))
|
|
50
|
+
.sort();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Measure every top-level `.md` file in `dir`, keyed by filename, byte sizes.
|
|
55
|
+
* Generic over directory and an optional filename predicate — used for both
|
|
56
|
+
* workflows (`pp-core/workflows/*.md`) and agents (`agents/gsd-*.md`) so the
|
|
57
|
+
* size guards and the baseline generator share one measurement path (#1074).
|
|
58
|
+
* Non-recursive by design.
|
|
59
|
+
*
|
|
60
|
+
* @param {string} dir - Directory to scan.
|
|
61
|
+
* @param {function(string): boolean} [predicate] - Filename filter (default: all `.md`).
|
|
62
|
+
* @returns {Object<string, number>} Map of filename → LF byte size, keys sorted.
|
|
63
|
+
*/
|
|
64
|
+
function measureMdFiles(dir, predicate = () => true) {
|
|
65
|
+
const out = {};
|
|
66
|
+
const names = fs
|
|
67
|
+
.readdirSync(dir)
|
|
68
|
+
.filter((f) => f.endsWith('.md') && predicate(f))
|
|
69
|
+
.sort();
|
|
70
|
+
for (const name of names) out[name] = lfByteCount(path.join(dir, name));
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Measure every top-level workflow file, keyed by filename (`<stem>.md`).
|
|
76
|
+
*
|
|
77
|
+
* @param {string} [dir] - Workflows directory (defaults to the canonical one).
|
|
78
|
+
* @returns {Object<string, number>} Map of `<stem>.md` → LF byte size, sorted.
|
|
79
|
+
*/
|
|
80
|
+
function measureWorkflows(dir = WORKFLOWS_DIR) {
|
|
81
|
+
return measureMdFiles(dir);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
module.exports = {
|
|
85
|
+
WORKFLOWS_DIR,
|
|
86
|
+
lfByteCount,
|
|
87
|
+
listWorkflowStems,
|
|
88
|
+
measureMdFiles,
|
|
89
|
+
measureWorkflows,
|
|
90
|
+
};
|