@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,209 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Configuration Module — legacy-key normalization, defaults merge, and explicit
|
|
4
|
+
* on-disk migration. Pure normalization primitives consumed by config-loader.cjs
|
|
5
|
+
* and config-schema.cjs. `loadConfig` was extracted to config-loader.cjs per
|
|
6
|
+
* ADR-857 phase 2e (#885) and removed from this module per #893.
|
|
7
|
+
*
|
|
8
|
+
* ADR-457 build-at-publish: the hand-written bin/lib/configuration.cjs collapsed
|
|
9
|
+
* to a TypeScript source of truth. Behaviour is preserved byte-for-behaviour
|
|
10
|
+
* from the prior hand-written .cjs; only types are added.
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.DYNAMIC_KEY_PATTERNS = exports.RUNTIME_STATE_KEYS = exports.VALID_CONFIG_KEYS = exports.CONFIG_DEFAULTS = void 0;
|
|
14
|
+
exports.normalizeLegacyKeys = normalizeLegacyKeys;
|
|
15
|
+
exports.mergeDefaults = mergeDefaults;
|
|
16
|
+
exports.migrateOnDisk = migrateOnDisk;
|
|
17
|
+
const node_fs_1 = require("node:fs");
|
|
18
|
+
const node_path_1 = require("node:path");
|
|
19
|
+
// In .cts (CommonJS output) files, `require` is available as a global.
|
|
20
|
+
const _require = require;
|
|
21
|
+
// ─── Manifest requires ───────────────────────────────────────────────────────
|
|
22
|
+
function loadConfigurationManifest(fileName) {
|
|
23
|
+
const candidates = [
|
|
24
|
+
// Installed runtime layout: gsd-core/bin/shared/*.manifest.json
|
|
25
|
+
(0, node_path_1.join)(__dirname, '..', 'shared', fileName),
|
|
26
|
+
];
|
|
27
|
+
let lastErr = null;
|
|
28
|
+
for (const candidate of candidates) {
|
|
29
|
+
try {
|
|
30
|
+
return _require(candidate);
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
const e = err;
|
|
34
|
+
const isMissingCandidate = e && e.code === 'MODULE_NOT_FOUND' && String(e.message || '').includes(candidate);
|
|
35
|
+
if (!isMissingCandidate)
|
|
36
|
+
throw err;
|
|
37
|
+
lastErr = e;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
throw new Error(`${fileName} not found. Tried:\n${candidates.map((p) => ` ${p}`).join('\n')}\nLast error: ${lastErr?.message}`);
|
|
41
|
+
}
|
|
42
|
+
const CONFIG_DEFAULTS = loadConfigurationManifest('config-defaults.manifest.json');
|
|
43
|
+
exports.CONFIG_DEFAULTS = CONFIG_DEFAULTS;
|
|
44
|
+
const SCHEMA_MANIFEST = loadConfigurationManifest('config-schema.manifest.json');
|
|
45
|
+
const VALID_CONFIG_KEYS = new Set(SCHEMA_MANIFEST.validKeys);
|
|
46
|
+
exports.VALID_CONFIG_KEYS = VALID_CONFIG_KEYS;
|
|
47
|
+
const RUNTIME_STATE_KEYS = new Set(SCHEMA_MANIFEST.runtimeStateKeys);
|
|
48
|
+
exports.RUNTIME_STATE_KEYS = RUNTIME_STATE_KEYS;
|
|
49
|
+
const DYNAMIC_KEY_PATTERNS = SCHEMA_MANIFEST.dynamicKeyPatterns.map((p) => {
|
|
50
|
+
const pattern = new RegExp(p.source);
|
|
51
|
+
return {
|
|
52
|
+
...p,
|
|
53
|
+
test: (key) => {
|
|
54
|
+
pattern.lastIndex = 0;
|
|
55
|
+
return pattern.test(key);
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
exports.DYNAMIC_KEY_PATTERNS = DYNAMIC_KEY_PATTERNS;
|
|
60
|
+
// ─── Depth → Granularity mapping ─────────────────────────────────────────────
|
|
61
|
+
const DEPTH_TO_GRANULARITY = {
|
|
62
|
+
quick: 'coarse',
|
|
63
|
+
standard: 'standard',
|
|
64
|
+
comprehensive: 'fine',
|
|
65
|
+
};
|
|
66
|
+
// ─── Internal helpers ─────────────────────────────────────────────────────────
|
|
67
|
+
function planningDir(cwd, workstream) {
|
|
68
|
+
if (!workstream)
|
|
69
|
+
return (0, node_path_1.join)(cwd, '.planning');
|
|
70
|
+
return (0, node_path_1.join)(cwd, '.planning', 'workstreams', workstream);
|
|
71
|
+
}
|
|
72
|
+
function detectSubRepos(cwd) {
|
|
73
|
+
const results = [];
|
|
74
|
+
try {
|
|
75
|
+
const entries = (0, node_fs_1.readdirSync)(cwd, { withFileTypes: true });
|
|
76
|
+
for (const entry of entries) {
|
|
77
|
+
if (!entry.isDirectory())
|
|
78
|
+
continue;
|
|
79
|
+
if (entry.name.startsWith('.') || entry.name === 'node_modules')
|
|
80
|
+
continue;
|
|
81
|
+
const gitPath = (0, node_path_1.join)(cwd, entry.name, '.git');
|
|
82
|
+
try {
|
|
83
|
+
if ((0, node_fs_1.existsSync)(gitPath)) {
|
|
84
|
+
results.push(entry.name);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch { /* ignore */ }
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch { /* ignore */ }
|
|
91
|
+
return results.sort();
|
|
92
|
+
}
|
|
93
|
+
function deepMergeConfig(base, overlay) {
|
|
94
|
+
const result = { ...base };
|
|
95
|
+
for (const key of Object.keys(overlay)) {
|
|
96
|
+
const ov = overlay[key];
|
|
97
|
+
if (ov !== null && ov !== undefined && typeof ov === 'object' && !Array.isArray(ov)) {
|
|
98
|
+
const bv = base[key];
|
|
99
|
+
if (bv !== null && bv !== undefined && typeof bv === 'object' && !Array.isArray(bv)) {
|
|
100
|
+
result[key] = deepMergeConfig(bv, ov);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
result[key] = deepMergeConfig({}, ov);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
result[key] = ov;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
112
|
+
// ─── Exported functions ───────────────────────────────────────────────────────
|
|
113
|
+
function normalizeLegacyKeys(parsed) {
|
|
114
|
+
const result = { ...parsed };
|
|
115
|
+
const normalizations = [];
|
|
116
|
+
// 1. branching_strategy → git.branching_strategy
|
|
117
|
+
if (Object.prototype.hasOwnProperty.call(result, 'branching_strategy')) {
|
|
118
|
+
const value = result['branching_strategy'];
|
|
119
|
+
const git = (result['git'] ?? {});
|
|
120
|
+
if (git['branching_strategy'] === undefined) {
|
|
121
|
+
result['git'] = { ...git, branching_strategy: value };
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
// canonical nested wins — just delete the stale top-level
|
|
125
|
+
result['git'] = { ...git };
|
|
126
|
+
}
|
|
127
|
+
delete result['branching_strategy'];
|
|
128
|
+
normalizations.push({ from: 'branching_strategy', to: 'git.branching_strategy', value });
|
|
129
|
+
}
|
|
130
|
+
// 2. top-level sub_repos → planning.sub_repos
|
|
131
|
+
if (Object.prototype.hasOwnProperty.call(result, 'sub_repos')) {
|
|
132
|
+
const value = result['sub_repos'];
|
|
133
|
+
const planning = (result['planning'] ?? {});
|
|
134
|
+
if (planning['sub_repos'] === undefined) {
|
|
135
|
+
result['planning'] = { ...planning, sub_repos: value };
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
// canonical nested wins — just drop the stale top-level
|
|
139
|
+
result['planning'] = { ...planning };
|
|
140
|
+
}
|
|
141
|
+
delete result['sub_repos'];
|
|
142
|
+
normalizations.push({ from: 'sub_repos', to: 'planning.sub_repos', value });
|
|
143
|
+
}
|
|
144
|
+
// 3. multiRepo: true → marker (filesystem detection deferred to migrateOnDisk / caller)
|
|
145
|
+
if (result['multiRepo'] === true) {
|
|
146
|
+
delete result['multiRepo'];
|
|
147
|
+
normalizations.push({ from: 'multiRepo', to: 'planning.sub_repos', value: true, requiresFilesystem: true });
|
|
148
|
+
}
|
|
149
|
+
// 4. top-level depth → granularity
|
|
150
|
+
if (Object.prototype.hasOwnProperty.call(result, 'depth') && !Object.prototype.hasOwnProperty.call(result, 'granularity')) {
|
|
151
|
+
const rawDepth = result['depth'];
|
|
152
|
+
const mapped = DEPTH_TO_GRANULARITY[rawDepth] ?? rawDepth;
|
|
153
|
+
result['granularity'] = mapped;
|
|
154
|
+
delete result['depth'];
|
|
155
|
+
normalizations.push({ from: 'depth', to: 'granularity', value: mapped });
|
|
156
|
+
}
|
|
157
|
+
return { parsed: result, normalizations };
|
|
158
|
+
}
|
|
159
|
+
function mergeDefaults(parsed) {
|
|
160
|
+
// Start with a deep clone of defaults, then overlay parsed
|
|
161
|
+
const defaults = structuredClone(CONFIG_DEFAULTS);
|
|
162
|
+
return deepMergeConfig(defaults, parsed);
|
|
163
|
+
}
|
|
164
|
+
function migrateOnDisk(cwd, workstream) {
|
|
165
|
+
const configPath = (0, node_path_1.join)(planningDir(cwd, workstream), 'config.json');
|
|
166
|
+
let raw;
|
|
167
|
+
try {
|
|
168
|
+
raw = (0, node_fs_1.readFileSync)(configPath, 'utf-8');
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
// File missing — nothing to migrate
|
|
172
|
+
return { migrated: false, normalizations: [], wrote: null };
|
|
173
|
+
}
|
|
174
|
+
const trimmed = raw.trim();
|
|
175
|
+
if (trimmed === '') {
|
|
176
|
+
return { migrated: false, normalizations: [], wrote: null };
|
|
177
|
+
}
|
|
178
|
+
let parsed;
|
|
179
|
+
try {
|
|
180
|
+
parsed = JSON.parse(trimmed);
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
// Malformed — can't migrate
|
|
184
|
+
return { migrated: false, normalizations: [], wrote: null };
|
|
185
|
+
}
|
|
186
|
+
const { parsed: normalized, normalizations } = normalizeLegacyKeys(parsed);
|
|
187
|
+
if (normalizations.length === 0) {
|
|
188
|
+
return { migrated: false, normalizations: [], wrote: null };
|
|
189
|
+
}
|
|
190
|
+
// Resolve multiRepo filesystem detection
|
|
191
|
+
const result = { ...normalized };
|
|
192
|
+
for (const norm of normalizations) {
|
|
193
|
+
if (norm.requiresFilesystem) {
|
|
194
|
+
const detected = detectSubRepos(cwd);
|
|
195
|
+
if (detected.length > 0) {
|
|
196
|
+
const planning = (result['planning'] ?? {});
|
|
197
|
+
result['planning'] = { ...planning, sub_repos: detected, commit_docs: false };
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
try {
|
|
202
|
+
(0, node_fs_1.writeFileSync)(configPath, JSON.stringify(result, null, 2));
|
|
203
|
+
}
|
|
204
|
+
catch (err) {
|
|
205
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
206
|
+
throw new Error(`Failed to write migrated config at ${configPath}: ${msg}`);
|
|
207
|
+
}
|
|
208
|
+
return { migrated: true, normalizations, wrote: configPath };
|
|
209
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Context-utilization classifier for `gsd-health --context` (ADR-457
|
|
4
|
+
* build-at-publish: the hand-written bin/lib/context-utilization.cjs collapsed
|
|
5
|
+
* to a TypeScript source of truth). Behaviour is preserved byte-for-behaviour
|
|
6
|
+
* from the prior hand-written .cjs; only types are added.
|
|
7
|
+
*
|
|
8
|
+
* Pure function. Callers pass tokensUsed + contextWindow; the
|
|
9
|
+
* classifier returns the percent and one of three states. Recommendation
|
|
10
|
+
* strings are NOT in this module — formatting is the renderer's job
|
|
11
|
+
* (see `validate context` in gsd-tools.cjs). That separation lets the
|
|
12
|
+
* copy change without touching this module's tests.
|
|
13
|
+
*
|
|
14
|
+
* Thresholds:
|
|
15
|
+
* < 60% healthy no action
|
|
16
|
+
* 60–70% warning approaching the fracture zone
|
|
17
|
+
* ≥ 70% critical reasoning quality may degrade
|
|
18
|
+
*
|
|
19
|
+
* State boundaries use the exact ratio. The displayed `percent` is
|
|
20
|
+
* rounded for human reading and may differ from the boundary by ±1 in
|
|
21
|
+
* edge cases (e.g. 59.999% displays as 60 but classifies as healthy).
|
|
22
|
+
*/
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.STATES = void 0;
|
|
25
|
+
exports.classifyContextUtilization = classifyContextUtilization;
|
|
26
|
+
exports.STATES = Object.freeze({
|
|
27
|
+
HEALTHY: 'healthy',
|
|
28
|
+
WARNING: 'warning',
|
|
29
|
+
CRITICAL: 'critical',
|
|
30
|
+
});
|
|
31
|
+
function classifyContextUtilization(tokensUsed, contextWindow) {
|
|
32
|
+
if (!Number.isInteger(tokensUsed) || tokensUsed < 0) {
|
|
33
|
+
throw new TypeError(`tokensUsed must be a non-negative integer, got: ${tokensUsed} (${typeof tokensUsed})`);
|
|
34
|
+
}
|
|
35
|
+
if (!Number.isInteger(contextWindow) || contextWindow <= 0) {
|
|
36
|
+
throw new TypeError(`contextWindow must be a positive integer, got: ${contextWindow} (${typeof contextWindow})`);
|
|
37
|
+
}
|
|
38
|
+
const ratio = Math.min(tokensUsed / contextWindow, 1);
|
|
39
|
+
const percent = Math.min(Math.round(ratio * 100), 100);
|
|
40
|
+
let state;
|
|
41
|
+
if (ratio < 0.60)
|
|
42
|
+
state = exports.STATES.HEALTHY;
|
|
43
|
+
else if (ratio < 0.70)
|
|
44
|
+
state = exports.STATES.WARNING;
|
|
45
|
+
else
|
|
46
|
+
state = exports.STATES.CRITICAL;
|
|
47
|
+
return { percent, state };
|
|
48
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Core Utilities — Shared low-level utility primitives
|
|
4
|
+
*
|
|
5
|
+
* ADR-857 rollout phase 2c: extracted from core.cts (issue #877).
|
|
6
|
+
* Owns POSIX path normalization, sub-repo/subdirectory scanning,
|
|
7
|
+
* phase file stats, slug/one-liner/plan-id helpers, and time-ago.
|
|
8
|
+
* Behaviour is preserved byte-for-behaviour from the prior location;
|
|
9
|
+
* only the module boundary moved. core.cjs re-exports every public symbol
|
|
10
|
+
* here under its own `export =` object so existing consumers are unaffected.
|
|
11
|
+
*
|
|
12
|
+
* New imports should pull core-utils helpers from core-utils.cjs directly.
|
|
13
|
+
*
|
|
14
|
+
* Dependencies (leaf modules only — no core.cjs, no loadConfig):
|
|
15
|
+
* - node:fs / node:path (stdlib)
|
|
16
|
+
* - ./phase-id.cjs (comparePhaseNum, used by readSubdirectories)
|
|
17
|
+
* - ./planning-workspace.cjs (findContextMdIn, used by getPhaseFileStats)
|
|
18
|
+
*/
|
|
19
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
20
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
21
|
+
};
|
|
22
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
23
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
25
|
+
const phaseIdModule = require("./phase-id.cjs");
|
|
26
|
+
const { comparePhaseNum } = phaseIdModule;
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
28
|
+
const planningWorkspace = require("./planning-workspace.cjs");
|
|
29
|
+
const { findContextMdIn } = planningWorkspace;
|
|
30
|
+
// ─── Path helpers ────────────────────────────────────────────────────────────
|
|
31
|
+
/** Normalize a relative path to always use forward slashes (cross-platform). */
|
|
32
|
+
function toPosixPath(p) {
|
|
33
|
+
return p.split(node_path_1.default.sep).join('/');
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Scan immediate child directories for separate git repos.
|
|
37
|
+
* Returns a sorted array of directory names that have their own `.git`.
|
|
38
|
+
* Excludes hidden directories and node_modules.
|
|
39
|
+
*/
|
|
40
|
+
function detectSubRepos(cwd) {
|
|
41
|
+
const results = [];
|
|
42
|
+
try {
|
|
43
|
+
const entries = node_fs_1.default.readdirSync(cwd, { withFileTypes: true });
|
|
44
|
+
for (const entry of entries) {
|
|
45
|
+
if (!entry.isDirectory())
|
|
46
|
+
continue;
|
|
47
|
+
if (entry.name.startsWith('.') || entry.name === 'node_modules')
|
|
48
|
+
continue;
|
|
49
|
+
const gitPath = node_path_1.default.join(cwd, entry.name, '.git');
|
|
50
|
+
try {
|
|
51
|
+
if (node_fs_1.default.existsSync(gitPath)) {
|
|
52
|
+
results.push(entry.name);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch { /* ignore */ }
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch { /* ignore */ }
|
|
59
|
+
return results.sort();
|
|
60
|
+
}
|
|
61
|
+
// ─── Summary body helpers ─────────────────────────────────────────────────
|
|
62
|
+
/**
|
|
63
|
+
* Extract a one-liner from the summary body when it's not in frontmatter.
|
|
64
|
+
*/
|
|
65
|
+
function extractOneLinerFromBody(content) {
|
|
66
|
+
if (!content)
|
|
67
|
+
return null;
|
|
68
|
+
const normalized = content.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
69
|
+
const body = normalized.replace(/^---\n[\s\S]*?\n---\n*/, '');
|
|
70
|
+
const match = body.match(/^#[^\n]*\n+\*\*([^*\n]+)\*\*([^\n]*)/m);
|
|
71
|
+
if (!match)
|
|
72
|
+
return null;
|
|
73
|
+
const boldInner = match[1].trim();
|
|
74
|
+
const afterBold = match[2];
|
|
75
|
+
if (/:\s*$/.test(boldInner)) {
|
|
76
|
+
const prose = afterBold.trim();
|
|
77
|
+
return prose.length > 0 ? prose : null;
|
|
78
|
+
}
|
|
79
|
+
return boldInner.length > 0 ? boldInner : null;
|
|
80
|
+
}
|
|
81
|
+
// ─── Misc utilities ───────────────────────────────────────────────────────────
|
|
82
|
+
function pathExistsInternal(cwd, targetPath) {
|
|
83
|
+
const fullPath = node_path_1.default.isAbsolute(targetPath) ? targetPath : node_path_1.default.join(cwd, targetPath);
|
|
84
|
+
try {
|
|
85
|
+
node_fs_1.default.statSync(fullPath);
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function generateSlugInternal(text) {
|
|
93
|
+
if (!text)
|
|
94
|
+
return null;
|
|
95
|
+
return text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').substring(0, 60);
|
|
96
|
+
}
|
|
97
|
+
// ─── Phase file helpers ──────────────────────────────────────────────────────
|
|
98
|
+
/** Filter a file list to just PLAN.md / *-PLAN.md entries. */
|
|
99
|
+
function filterPlanFiles(files) {
|
|
100
|
+
return files.filter(f => f.endsWith('-PLAN.md') || f === 'PLAN.md');
|
|
101
|
+
}
|
|
102
|
+
/** Filter a file list to just SUMMARY.md / *-SUMMARY.md entries. */
|
|
103
|
+
function filterSummaryFiles(files) {
|
|
104
|
+
return files.filter(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md');
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Read a phase directory and return counts/flags for common file types.
|
|
108
|
+
*/
|
|
109
|
+
function getPhaseFileStats(phaseDir) {
|
|
110
|
+
const files = node_fs_1.default.readdirSync(phaseDir);
|
|
111
|
+
return {
|
|
112
|
+
plans: filterPlanFiles(files),
|
|
113
|
+
summaries: filterSummaryFiles(files),
|
|
114
|
+
hasResearch: files.some(f => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md'),
|
|
115
|
+
hasContext: findContextMdIn(files) !== null,
|
|
116
|
+
hasVerification: files.some(f => f.endsWith('-VERIFICATION.md') || f === 'VERIFICATION.md'),
|
|
117
|
+
hasReviews: files.some(f => f.endsWith('-REVIEWS.md') || f === 'REVIEWS.md'),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Read immediate child directories from a path.
|
|
122
|
+
* Returns [] if the path doesn't exist or can't be read.
|
|
123
|
+
* Pass sort=true to apply comparePhaseNum ordering.
|
|
124
|
+
*/
|
|
125
|
+
function readSubdirectories(dirPath, sort = false) {
|
|
126
|
+
try {
|
|
127
|
+
const entries = node_fs_1.default.readdirSync(dirPath, { withFileTypes: true });
|
|
128
|
+
const dirs = entries.filter(e => e.isDirectory()).map(e => e.name);
|
|
129
|
+
return sort ? dirs.sort((a, b) => comparePhaseNum(a, b)) : dirs;
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return [];
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Format a Date as a fuzzy relative time string (e.g. "5 minutes ago").
|
|
137
|
+
*/
|
|
138
|
+
function timeAgo(date) {
|
|
139
|
+
const seconds = Math.floor((Date.now() - date.getTime()) / 1000);
|
|
140
|
+
if (seconds < 5)
|
|
141
|
+
return 'just now';
|
|
142
|
+
if (seconds < 60)
|
|
143
|
+
return `${seconds} seconds ago`;
|
|
144
|
+
const minutes = Math.floor(seconds / 60);
|
|
145
|
+
if (minutes === 1)
|
|
146
|
+
return '1 minute ago';
|
|
147
|
+
if (minutes < 60)
|
|
148
|
+
return `${minutes} minutes ago`;
|
|
149
|
+
const hours = Math.floor(minutes / 60);
|
|
150
|
+
if (hours === 1)
|
|
151
|
+
return '1 hour ago';
|
|
152
|
+
if (hours < 24)
|
|
153
|
+
return `${hours} hours ago`;
|
|
154
|
+
const days = Math.floor(hours / 24);
|
|
155
|
+
if (days === 1)
|
|
156
|
+
return '1 day ago';
|
|
157
|
+
if (days < 30)
|
|
158
|
+
return `${days} days ago`;
|
|
159
|
+
const months = Math.floor(days / 30);
|
|
160
|
+
if (months === 1)
|
|
161
|
+
return '1 month ago';
|
|
162
|
+
if (months < 12)
|
|
163
|
+
return `${months} months ago`;
|
|
164
|
+
const years = Math.floor(days / 365);
|
|
165
|
+
if (years === 1)
|
|
166
|
+
return '1 year ago';
|
|
167
|
+
return `${years} years ago`;
|
|
168
|
+
}
|
|
169
|
+
// ─── Plan ID helpers ─────────────────────────────────────────────────────────
|
|
170
|
+
/**
|
|
171
|
+
* Extract the canonical plan ID from a filename.
|
|
172
|
+
* Private to the core cluster — exported so core.cjs:searchPhaseInDir can
|
|
173
|
+
* import it from this leaf without circular dependency, but NOT re-exported
|
|
174
|
+
* from core.cjs's public `export =` block.
|
|
175
|
+
*/
|
|
176
|
+
function extractCanonicalPlanId(filename) {
|
|
177
|
+
const base = filename.replace(/-PLAN\.md$/i, '').replace(/-SUMMARY\.md$/i, '').replace(/\.md$/i, '');
|
|
178
|
+
const parts = base.split('-').filter(Boolean);
|
|
179
|
+
const tokenRe = /^\d+[A-Z]?(?:\.\d+)*$/i;
|
|
180
|
+
const phaseIdx = parts.findIndex(p => tokenRe.test(p));
|
|
181
|
+
if (phaseIdx >= 0 && phaseIdx + 1 < parts.length && tokenRe.test(parts[phaseIdx + 1])) {
|
|
182
|
+
return `${parts[phaseIdx]}-${parts[phaseIdx + 1]}`;
|
|
183
|
+
}
|
|
184
|
+
return base;
|
|
185
|
+
}
|
|
186
|
+
module.exports = {
|
|
187
|
+
toPosixPath,
|
|
188
|
+
detectSubRepos,
|
|
189
|
+
extractOneLinerFromBody,
|
|
190
|
+
pathExistsInternal,
|
|
191
|
+
generateSlugInternal,
|
|
192
|
+
filterPlanFiles,
|
|
193
|
+
filterSummaryFiles,
|
|
194
|
+
getPhaseFileStats,
|
|
195
|
+
readSubdirectories,
|
|
196
|
+
timeAgo,
|
|
197
|
+
extractCanonicalPlanId,
|
|
198
|
+
};
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared parser for CONTEXT.md <decisions> blocks (ADR-457 build-at-publish:
|
|
4
|
+
* the hand-written bin/lib/decisions.cjs collapsed to a TypeScript source of
|
|
5
|
+
* truth). Behaviour is preserved byte-for-behaviour from the prior hand-written
|
|
6
|
+
* .cjs; only types are added.
|
|
7
|
+
*
|
|
8
|
+
* Accepts both numeric (D-42) and alphanumeric (D-INFRA-01) IDs.
|
|
9
|
+
* Returns {id, text, category, tags, trackable} per decision.
|
|
10
|
+
* CJS callers that only use {id, text} safely ignore the extra fields.
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.parseDecisions = parseDecisions;
|
|
14
|
+
const DISCRETION_HEADINGS = new Set([
|
|
15
|
+
"claude's discretion",
|
|
16
|
+
'claudes discretion',
|
|
17
|
+
'claude discretion',
|
|
18
|
+
]);
|
|
19
|
+
const NON_TRACKABLE_TAGS = new Set(['informational', 'folded', 'deferred']);
|
|
20
|
+
/**
|
|
21
|
+
* Strip fenced code blocks from `content` so example `<decisions>` snippets
|
|
22
|
+
* inside ```` ``` ```` do not pollute the parser (review F11).
|
|
23
|
+
*/
|
|
24
|
+
function stripFencedCode(content) {
|
|
25
|
+
return content.replace(/```[\s\S]*?```/g, ' ').replace(/~~~[\s\S]*?~~~/g, ' ');
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Extract the inner text of EVERY `<decisions>...</decisions>` block in
|
|
29
|
+
* order, concatenated by `\n\n`. Returns null when no block is present.
|
|
30
|
+
*
|
|
31
|
+
* CONTEXT.md may legitimately contain more than one block (for example, a
|
|
32
|
+
* "current decisions" block plus a "carry-over from prior phase" block);
|
|
33
|
+
* dropping all-but-the-first silently lost the second batch (review F13).
|
|
34
|
+
*/
|
|
35
|
+
function extractDecisionsBlock(content) {
|
|
36
|
+
const cleaned = stripFencedCode(content);
|
|
37
|
+
const matches = [...cleaned.matchAll(/<decisions>([\s\S]*?)<\/decisions>/g)];
|
|
38
|
+
if (matches.length === 0)
|
|
39
|
+
return null;
|
|
40
|
+
return matches.map((m) => m[1]).join('\n\n');
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Parse trackable decisions from CONTEXT.md content.
|
|
44
|
+
*
|
|
45
|
+
* Returns ALL D-NN decisions found inside `<decisions>` (including
|
|
46
|
+
* non-trackable ones, with `trackable: false`). Callers that only want the
|
|
47
|
+
* gate-enforced decisions should filter `.filter(d => d.trackable)`.
|
|
48
|
+
*/
|
|
49
|
+
function parseDecisions(content) {
|
|
50
|
+
if (!content || typeof content !== 'string')
|
|
51
|
+
return [];
|
|
52
|
+
const block = extractDecisionsBlock(content);
|
|
53
|
+
if (block === null)
|
|
54
|
+
return [];
|
|
55
|
+
const lines = block.split(/\r?\n/);
|
|
56
|
+
const out = [];
|
|
57
|
+
let category = '';
|
|
58
|
+
let inDiscretion = false;
|
|
59
|
+
// Bullet line: `- **D-NN[ [tags]]:** text`
|
|
60
|
+
// Phase 6 (#3575): aligned to CJS regex — accepts alphanumeric IDs (D-01, D-INFRA-01, D-FOO_BAR)
|
|
61
|
+
// in addition to numeric-only IDs (D-42). The first character after `D-` must
|
|
62
|
+
// be alphanumeric, so malformed shapes like `D--foo` or `D-_bar` are rejected.
|
|
63
|
+
// CJS callers consume {id, text} and ignore the optional extras.
|
|
64
|
+
// #1343: `[^:*]*` replaces the old `\s*` before `:**` so that a freeform run
|
|
65
|
+
// such as `(parenthetical)`, an em-dash, or other prose between the optional
|
|
66
|
+
// bracket-tag group and the closing `:**` is tolerated rather than silently
|
|
67
|
+
// dropping the whole decision. `[^:*]*` subsumes plain whitespace and stops
|
|
68
|
+
// correctly at `:**`. Capture groups 1 (id), 2 (bracket tags), 3 (text) are
|
|
69
|
+
// unchanged.
|
|
70
|
+
const bulletRe = /^\s*-\s+\*\*D-([A-Za-z0-9][A-Za-z0-9_-]*)(?:\s*\[([^\]]+)\])?[^:*]*:\*\*\s*(.*)$/;
|
|
71
|
+
let current = null;
|
|
72
|
+
const flush = () => {
|
|
73
|
+
if (current) {
|
|
74
|
+
current.text = current.text.trim();
|
|
75
|
+
out.push(current);
|
|
76
|
+
current = null;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
for (const line of lines) {
|
|
80
|
+
const trimmed = line.trim();
|
|
81
|
+
// Track category headings (`### Heading`)
|
|
82
|
+
const headingMatch = trimmed.match(/^###\s+(.+?)\s*$/);
|
|
83
|
+
if (headingMatch) {
|
|
84
|
+
flush();
|
|
85
|
+
category = headingMatch[1];
|
|
86
|
+
// Strip the full unicode-quote family so any rendering of "Claude's
|
|
87
|
+
// Discretion" (ASCII apostrophe, curly U+2019, U+2018, U+201A, U+201B,
|
|
88
|
+
// double-quote variants U+201C/D/E/F, etc.) collapses to the same key
|
|
89
|
+
// (review F20).
|
|
90
|
+
const normalized = category
|
|
91
|
+
.toLowerCase()
|
|
92
|
+
.replace(/[‘’‚‛“”„‟'"`]/g, '')
|
|
93
|
+
.trim();
|
|
94
|
+
inDiscretion = DISCRETION_HEADINGS.has(normalized);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
const bulletMatch = line.match(bulletRe);
|
|
98
|
+
if (bulletMatch) {
|
|
99
|
+
flush();
|
|
100
|
+
const id = `D-${bulletMatch[1]}`;
|
|
101
|
+
const tags = bulletMatch[2]
|
|
102
|
+
? bulletMatch[2]
|
|
103
|
+
.split(',')
|
|
104
|
+
.map((t) => t.trim().toLowerCase())
|
|
105
|
+
.filter(Boolean)
|
|
106
|
+
: [];
|
|
107
|
+
const trackable = !inDiscretion && !tags.some((t) => NON_TRACKABLE_TAGS.has(t));
|
|
108
|
+
current = { id, text: bulletMatch[3], category, tags, trackable };
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
// Parse-miss guard (#1343): a line that looks like a `D-NN` decision bullet
|
|
112
|
+
// but failed `bulletRe` (e.g. a `:` or `*` inside the pre-colon run) must NOT
|
|
113
|
+
// be silently dropped — a narrowed trackable set lets a blocking coverage gate
|
|
114
|
+
// report a false pass. Surface it loudly instead.
|
|
115
|
+
if (/^\s*-\s+\*\*D-/.test(line)) {
|
|
116
|
+
// A malformed D-bullet still starts a (failed) new decision, so it ends the
|
|
117
|
+
// previous one — flush before warning so a following continuation line cannot
|
|
118
|
+
// be mis-appended to the prior valid decision.
|
|
119
|
+
flush();
|
|
120
|
+
console.warn(`parseDecisions: ignored unparseable decision bullet: ${trimmed}`);
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
// Continuation line for current decision (indented with space OR tab,
|
|
124
|
+
// non-bullet, non-empty) — tab indentation must work too (review F12).
|
|
125
|
+
if (current && trimmed !== '' && !trimmed.startsWith('-') && /^[ \t]/.test(line)) {
|
|
126
|
+
current.text += ' ' + trimmed;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
// Blank line or unrelated content terminates the current decision
|
|
130
|
+
if (trimmed === '') {
|
|
131
|
+
flush();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
flush();
|
|
135
|
+
return out;
|
|
136
|
+
}
|