@pareto4/pp-core 1.11.0 → 1.12.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 +1 -1
- package/README.md +31 -0
- package/agents/pp-code-fixer.md +1 -1
- package/agents/pp-debug-session-manager.md +1 -1
- package/agents/pp-debugger.md +1 -1
- package/agents/pp-executor.md +20 -10
- package/agents/pp-intel-updater.md +1 -1
- package/agents/pp-phase-researcher.md +1 -1
- package/agents/pp-plan-checker.md +5 -5
- package/agents/pp-planner.md +10 -24
- package/agents/pp-project-researcher.md +1 -1
- package/agents/pp-research-synthesizer.md +1 -1
- package/agents/pp-ui-researcher.md +1 -1
- package/agents/pp-verifier.md +8 -4
- package/bin/install.js +429 -82
- package/commands/pp-autonomous.md +8 -6
- package/commands/pp-discovery-to-build.md +1 -1
- package/commands/pp-discovery.md +3 -2
- package/commands/pp-discuss-phase.md +2 -2
- package/commands/pp-execute-phase.md +3 -1
- package/commands/pp-graphify.md +5 -5
- package/commands/pp-import.md +1 -1
- package/commands/pp-map-codebase.md +1 -1
- package/commands/pp-ns-project.md +2 -3
- package/commands/pp-ns-workflow.md +1 -1
- package/commands/pp-plan-phase.md +2 -1
- package/commands/pp-verify-work.md +2 -1
- package/gemini-extension.json +1 -1
- package/hooks/dist/pp-cursor-session-start.js +2 -2
- package/hooks/dist/pp-session-state.sh +1 -1
- package/hooks/dist/pp-statusline.js +21 -2
- package/hooks/pp-cursor-session-start.js +2 -2
- package/hooks/pp-session-state.sh +1 -1
- package/hooks/pp-statusline.js +21 -2
- package/package.json +18 -5
- package/pareto-skills/pp-project-setup/SKILL.md +5 -63
- package/pp-core/bin/detect-build-commands.sh +182 -0
- package/pp-core/bin/lib/capability-registry.cjs +65 -7
- package/pp-core/bin/lib/check-command-router.cjs +79 -38
- package/pp-core/bin/lib/clusters.cjs +2 -3
- package/pp-core/bin/lib/command-aliases.cjs +36 -0
- package/pp-core/bin/lib/command-arg-projection.cjs +99 -1
- package/pp-core/bin/lib/commands.cjs +21 -6
- package/pp-core/bin/lib/compose-bindings.cjs +128 -15
- package/pp-core/bin/lib/config-schema.cjs +16 -0
- package/pp-core/bin/lib/config.cjs +142 -27
- package/pp-core/bin/lib/core-utils.cjs +43 -7
- package/pp-core/bin/lib/discovery-input-check.cjs +218 -0
- package/pp-core/bin/lib/discovery-rebaseline.cjs +1372 -0
- package/pp-core/bin/lib/discovery-research-track.cjs +979 -0
- package/pp-core/bin/lib/discovery-rollup.cjs +476 -0
- package/pp-core/bin/lib/discovery-screens.cjs +1995 -0
- package/pp-core/bin/lib/discovery-sweep.cjs +390 -0
- package/pp-core/bin/lib/discovery-table.cjs +98 -0
- package/pp-core/bin/lib/dispatch-plan.cjs +472 -0
- package/pp-core/bin/lib/frontmatter.cjs +17 -2
- package/pp-core/bin/lib/init-command-router.cjs +8 -5
- package/pp-core/bin/lib/init-contract.cjs +213 -33
- package/pp-core/bin/lib/init-interactive.cjs +20 -1
- package/pp-core/bin/lib/init.cjs +124 -134
- package/pp-core/bin/lib/install-profiles.cjs +5 -0
- package/pp-core/bin/lib/install-run.cjs +536 -0
- package/pp-core/bin/lib/io.cjs +15 -0
- package/pp-core/bin/lib/loop-resolver.cjs +24 -0
- package/pp-core/bin/lib/milestone.cjs +345 -48
- package/pp-core/bin/lib/phase-command-router.cjs +23 -1
- package/pp-core/bin/lib/phase-locator.cjs +15 -6
- package/pp-core/bin/lib/phase-scope.cjs +91 -0
- package/pp-core/bin/lib/phase-tier.cjs +467 -0
- package/pp-core/bin/lib/phase.cjs +247 -21
- package/pp-core/bin/lib/phases-command-router.cjs +2 -0
- package/pp-core/bin/lib/plan-graph.cjs +368 -0
- package/pp-core/bin/lib/planning-workspace.cjs +53 -0
- package/pp-core/bin/lib/platform-bindings.cjs +32 -2
- package/pp-core/bin/lib/profile-output.cjs +11 -3
- package/pp-core/bin/lib/prohibition-enforcement.cjs +112 -0
- package/pp-core/bin/lib/roadmap-parser.cjs +366 -99
- package/pp-core/bin/lib/roadmap.cjs +141 -39
- package/pp-core/bin/lib/runtime-hooks-surface.cjs +1 -1
- package/pp-core/bin/lib/shell-command-projection.cjs +24 -0
- package/pp-core/bin/lib/state-command-router.cjs +82 -13
- package/pp-core/bin/lib/state-document.cjs +124 -7
- package/pp-core/bin/lib/state.cjs +784 -257
- package/pp-core/bin/lib/template.cjs +22 -6
- package/pp-core/bin/lib/vault-command-router.cjs +57 -6
- package/pp-core/bin/lib/vault-practices.cjs +6 -36
- package/pp-core/bin/lib/vault-write-back.cjs +20 -4
- package/pp-core/bin/lib/vault.cjs +555 -23
- package/pp-core/bin/lib/verify.cjs +53 -31
- package/pp-core/bin/lib/workstream.cjs +1 -1
- package/pp-core/bin/lib/worktree-safety.cjs +26 -15
- package/pp-core/bin/portable-timeout.sh +89 -0
- package/pp-core/bin/pp-tools.cjs +158 -8
- package/pp-core/bin/shared/config-defaults.manifest.json +7 -0
- package/pp-core/bin/shared/config-schema.manifest.json +3 -0
- package/pp-core/references/autonomous-best-effort.md +461 -0
- package/pp-core/references/autonomous-lifecycle.md +146 -0
- package/pp-core/references/autonomous-smart-discuss.md +16 -12
- package/pp-core/references/checkpoints.md +1 -1
- package/pp-core/references/discovery-id-conventions.md +202 -0
- package/pp-core/references/discovery-rebaseline.md +254 -0
- package/pp-core/references/discovery-research-track.md +283 -0
- package/pp-core/references/discovery-traceability.md +400 -0
- package/pp-core/references/loop-hook-dispatch.md +7 -0
- package/pp-core/references/mandatory-initial-read.md +1 -1
- package/pp-core/references/planner-gap-closure.md +1 -0
- package/pp-core/references/planner-human-verify-mode.md +1 -1
- package/pp-core/references/planner-load-graph-context.md +1 -1
- package/pp-core/references/planner-plan-graph.md +66 -0
- package/pp-core/references/planner-tdd.md +1 -0
- package/pp-core/references/planning-config.md +8 -0
- package/pp-core/references/sketch-tooling.md +4 -0
- package/pp-core/references/tdd.md +1 -0
- package/pp-core/templates/claude-md.md +1 -1
- package/pp-core/templates/phase-prompt.md +6 -2
- package/pp-core/templates/prototype-review/review.js +303 -0
- package/pp-core/templates/state.md +6 -0
- package/pp-core/workflows/_runtime-launcher.snippet.sh +1 -1
- package/pp-core/workflows/add-backlog.md +1 -1
- package/pp-core/workflows/add-phase.md +1 -1
- package/pp-core/workflows/add-tests.md +1 -1
- package/pp-core/workflows/add-todo.md +1 -1
- package/pp-core/workflows/ai-integration-phase.md +2 -2
- package/pp-core/workflows/audit-fix.md +12 -16
- package/pp-core/workflows/audit-milestone.md +1 -1
- package/pp-core/workflows/audit-uat.md +1 -1
- package/pp-core/workflows/autonomous.md +68 -306
- package/pp-core/workflows/check-todos.md +1 -1
- package/pp-core/workflows/cleanup.md +1 -1
- package/pp-core/workflows/code-review-fix.md +1 -1
- package/pp-core/workflows/code-review.md +19 -7
- package/pp-core/workflows/complete-milestone.md +41 -60
- package/pp-core/workflows/debug.md +1 -1
- package/pp-core/workflows/diagnose-issues.md +1 -1
- package/pp-core/workflows/discovery-sprint/gap-analysis.md +140 -0
- package/pp-core/workflows/discovery-sprint/input-package.md +140 -0
- package/pp-core/workflows/discovery-sprint/prefill.md +92 -0
- package/pp-core/workflows/discovery-sprint/prototype.md +257 -0
- package/pp-core/workflows/discovery-sprint/rebaseline.md +276 -0
- package/pp-core/workflows/discovery-sprint/session-13-gates.md +24 -0
- package/pp-core/workflows/discovery-sprint/sessions/01-kick-off.md +92 -0
- package/pp-core/workflows/discovery-sprint/sessions/02-as-is.md +98 -0
- package/pp-core/workflows/discovery-sprint/sessions/03-to-be.md +215 -0
- package/pp-core/workflows/discovery-sprint/sessions/04-ux-design.md +146 -0
- package/pp-core/workflows/discovery-sprint/sessions/05-architecture.md +98 -0
- package/pp-core/workflows/discovery-sprint/sessions/06-security.md +107 -0
- package/pp-core/workflows/discovery-sprint/sessions/07-identity.md +98 -0
- package/pp-core/workflows/discovery-sprint/sessions/08-integration.md +85 -0
- package/pp-core/workflows/discovery-sprint/sessions/09-qa.md +109 -0
- package/pp-core/workflows/discovery-sprint/sessions/10-infrastructure.md +119 -0
- package/pp-core/workflows/discovery-sprint/sessions/11-roadmap.md +92 -0
- package/pp-core/workflows/discovery-sprint/sessions/12-delivery-model.md +98 -0
- package/pp-core/workflows/discovery-sprint/sessions/13-wrap-up.md +205 -0
- package/pp-core/workflows/discovery-sprint/templates/context-template.md +266 -0
- package/pp-core/workflows/discovery-sprint.md +79 -1714
- package/pp-core/workflows/discovery-to-build/steps/architecture-deliverables.md +5 -5
- package/pp-core/workflows/discovery-to-build/steps/screen-inventory-gate.md +70 -0
- package/pp-core/workflows/discovery-to-build/templates/discovery-references.md +54 -0
- package/pp-core/workflows/discovery-to-build/templates/pp-handoff.md +184 -0
- package/pp-core/workflows/discovery-to-build.md +21 -238
- package/pp-core/workflows/discuss-phase/modes/advisor.md +1 -1
- package/pp-core/workflows/discuss-phase/modes/auto.md +1 -1
- package/pp-core/workflows/discuss-phase/modes/chain.md +1 -1
- package/pp-core/workflows/discuss-phase-assumptions.md +1 -1
- package/pp-core/workflows/discuss-phase.md +9 -2
- package/pp-core/workflows/do.md +4 -4
- package/pp-core/workflows/docs-update.md +1 -1
- package/pp-core/workflows/edit-phase.md +1 -1
- package/pp-core/workflows/eval-review.md +1 -1
- package/pp-core/workflows/execute-phase/steps/checkpoint-handling.md +45 -0
- package/pp-core/workflows/execute-phase/steps/client-context-gate.md +1 -1
- package/pp-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
- package/pp-core/workflows/execute-phase/steps/cross-ai-delegation.md +90 -0
- package/pp-core/workflows/execute-phase/steps/install-run.md +29 -0
- package/pp-core/workflows/execute-phase/steps/phase-close-rebaseline.md +23 -0
- package/pp-core/workflows/execute-phase/steps/post-merge-gate.md +76 -77
- package/pp-core/workflows/execute-phase/steps/serial-group-dispatch.md +72 -0
- package/pp-core/workflows/execute-phase/steps/vault-fetch.md +5 -5
- package/pp-core/workflows/execute-phase/steps/vault-load-gate.md +19 -112
- package/pp-core/workflows/execute-phase.md +102 -216
- package/pp-core/workflows/execute-plan.md +6 -2
- package/pp-core/workflows/explore.md +1 -1
- package/pp-core/workflows/extract-learnings.md +1 -1
- package/pp-core/workflows/forensics.md +4 -4
- package/pp-core/workflows/graduation.md +1 -1
- package/pp-core/workflows/health.md +1 -1
- package/pp-core/workflows/help/modes/brief.md +1 -0
- package/pp-core/workflows/help/modes/default.md +2 -1
- package/pp-core/workflows/help/modes/full.md +12 -5
- package/pp-core/workflows/import.md +1 -1
- package/pp-core/workflows/ingest-docs.md +1 -1
- package/pp-core/workflows/init.md +18 -2
- package/pp-core/workflows/insert-phase.md +1 -1
- package/pp-core/workflows/list-workspaces.md +1 -1
- package/pp-core/workflows/manager.md +3 -3
- package/pp-core/workflows/map-codebase.md +2 -2
- package/pp-core/workflows/milestone-summary.md +4 -4
- package/pp-core/workflows/mvp-phase.md +1 -1
- package/pp-core/workflows/new-milestone.md +7 -8
- package/pp-core/workflows/new-project.md +6 -1
- package/pp-core/workflows/new-workspace.md +1 -1
- package/pp-core/workflows/next.md +2 -2
- package/pp-core/workflows/note.md +2 -2
- package/pp-core/workflows/pause-work.md +1 -1
- package/pp-core/workflows/plan-milestone-gaps.md +1 -1
- package/pp-core/workflows/plan-phase/steps/chunked-planning.md +111 -0
- package/pp-core/workflows/plan-phase/steps/phase-tier.md +34 -0
- package/pp-core/workflows/plan-phase.md +43 -167
- package/pp-core/workflows/plan-review-convergence.md +2 -2
- package/pp-core/workflows/plant-seed.md +1 -1
- package/pp-core/workflows/pr-branch.md +1 -1
- package/pp-core/workflows/profile-user.md +1 -1
- package/pp-core/workflows/progress.md +3 -3
- package/pp-core/workflows/quick.md +3 -1
- package/pp-core/workflows/remove-phase.md +1 -1
- package/pp-core/workflows/remove-workspace.md +1 -1
- package/pp-core/workflows/resume-project.md +6 -12
- package/pp-core/workflows/review.md +1 -1
- package/pp-core/workflows/scan.md +1 -1
- package/pp-core/workflows/secure-phase.md +1 -1
- package/pp-core/workflows/settings-advanced.md +1 -1
- package/pp-core/workflows/settings-integrations.md +1 -1
- package/pp-core/workflows/settings.md +1 -1
- package/pp-core/workflows/ship.md +25 -8
- package/pp-core/workflows/sketch-wrap-up.md +1 -1
- package/pp-core/workflows/sketch.md +2 -1
- package/pp-core/workflows/spec-phase.md +1 -1
- package/pp-core/workflows/spike-wrap-up.md +1 -1
- package/pp-core/workflows/spike.md +1 -1
- package/pp-core/workflows/stats.md +2 -2
- package/pp-core/workflows/thread.md +1 -1
- package/pp-core/workflows/transition.md +5 -9
- package/pp-core/workflows/ui-phase.md +23 -2
- package/pp-core/workflows/ui-review.md +1 -1
- package/pp-core/workflows/ultraplan-phase.md +2 -2
- package/pp-core/workflows/validate-phase.md +1 -1
- package/pp-core/workflows/vault-write-back.md +1 -1
- package/pp-core/workflows/verify-phase.md +29 -26
- package/pp-core/workflows/verify-work.md +14 -10
- package/scripts/base64-scan.sh +7 -41
- package/scripts/changeset/cli.cjs +25 -5
- package/scripts/dev-env.cjs +462 -0
- package/scripts/lib/allowlist-ratchet.cjs +103 -1
- package/scripts/lib/size-budget.cjs +311 -0
- package/scripts/lint-neutrality-names.cjs +694 -0
- package/scripts/lint-org-coordinates.allowlist.json +35 -0
- package/scripts/lint-org-coordinates.cjs +426 -0
- package/scripts/lint-skill-deps.cjs +48 -9
- package/scripts/lint-test-file-count.cjs +17 -2
- package/scripts/prompt-injection-scan.sh +41 -20
- package/scripts/sync-manifest-versions.cjs +41 -7
- package/scripts/sync-runtime-launcher.cjs +106 -1
- package/scripts/update-size-baseline.cjs +274 -30
- package/scripts/workflow-size.cjs +61 -9
- package/commands/pp-build-handoff.md +0 -46
- package/pp-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +0 -94
|
@@ -35,10 +35,13 @@ const phaseIdMod = require("./phase-id.cjs");
|
|
|
35
35
|
const { escapeRegex, normalizePhaseName, phaseMarkdownRegexSource, comparePhaseNum, phaseTokenMatches } = phaseIdMod;
|
|
36
36
|
// eslint-disable-next-line @typescript-eslint/no-require-imports -- phase-locator.cjs is an export= CommonJS module
|
|
37
37
|
const phaseLocatorMod = require("./phase-locator.cjs");
|
|
38
|
-
const {
|
|
38
|
+
const { getArchivedPhaseDirs } = phaseLocatorMod;
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports -- phase-scope.cjs is an export= CommonJS module
|
|
40
|
+
const phaseScopeMod = require("./phase-scope.cjs");
|
|
41
|
+
const { resolvePhaseForRead } = phaseScopeMod;
|
|
39
42
|
// eslint-disable-next-line @typescript-eslint/no-require-imports -- roadmap-parser.cjs is an export= CommonJS module
|
|
40
43
|
const roadmapParserMod = require("./roadmap-parser.cjs");
|
|
41
|
-
const { stripShippedMilestones, extractCurrentMilestone, getMilestonePhaseFilter } = roadmapParserMod;
|
|
44
|
+
const { stripShippedMilestones, extractCurrentMilestone, getMilestonePhaseFilter, buildPlansSummaryLinePattern } = roadmapParserMod;
|
|
42
45
|
// eslint-disable-next-line @typescript-eslint/no-require-imports -- planning-workspace.cjs is an export= CommonJS module
|
|
43
46
|
const planningWorkspace = require("./planning-workspace.cjs");
|
|
44
47
|
// eslint-disable-next-line @typescript-eslint/no-require-imports -- frontmatter.cjs is an export= CommonJS module
|
|
@@ -48,11 +51,16 @@ const stateMod = require("./state.cjs");
|
|
|
48
51
|
const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
|
|
49
52
|
const runtime_slash_cjs_1 = require("./runtime-slash.cjs");
|
|
50
53
|
const phase_lifecycle_cjs_1 = require("./phase-lifecycle.cjs");
|
|
54
|
+
const state_document_cjs_1 = require("./state-document.cjs");
|
|
51
55
|
const clock_cjs_1 = require("./clock.cjs");
|
|
52
56
|
// eslint-disable-next-line @typescript-eslint/no-require-imports -- uat-predicate.cjs is an export= CommonJS module
|
|
53
57
|
const uatPredicate = require("./uat-predicate.cjs");
|
|
54
58
|
const { evaluateUatPassed } = uatPredicate;
|
|
55
|
-
const
|
|
59
|
+
const plan_graph_cjs_1 = require("./plan-graph.cjs");
|
|
60
|
+
const dispatch_plan_cjs_1 = require("./dispatch-plan.cjs");
|
|
61
|
+
const phase_tier_cjs_1 = require("./phase-tier.cjs");
|
|
62
|
+
const install_run_cjs_1 = require("./install-run.cjs");
|
|
63
|
+
const { planningDir, withPlanningLock, milestonePathsFor } = planningWorkspace;
|
|
56
64
|
const { extractFrontmatter } = frontmatterMod;
|
|
57
65
|
const { readModifyWriteStateMd, stateExtractField, stateReplaceField, stateReplaceFieldWithFallback, syncStateFrontmatter, withStateLock, updatePerformanceMetricsSection, } = stateMod;
|
|
58
66
|
// #2893 — strict canonical filter: `{padded_phase}-{NN}-PLAN.md` or `PLAN.md`.
|
|
@@ -287,7 +295,8 @@ function cmdFindPhase(cwd, phase, raw) {
|
|
|
287
295
|
if (node_fs_1.default.existsSync(flatPhasesDir))
|
|
288
296
|
searchDirs.push(flatPhasesDir);
|
|
289
297
|
try {
|
|
290
|
-
|
|
298
|
+
// CARRY-05: archive location from the owner, not a local join.
|
|
299
|
+
const milestonesDir = milestonePathsFor(planBase).milestonesArchive;
|
|
291
300
|
const entries = node_fs_1.default
|
|
292
301
|
.readdirSync(milestonesDir, { withFileTypes: true })
|
|
293
302
|
.filter((e) => e.isDirectory() && /^v\d+.*-phases$/.test(e.name))
|
|
@@ -399,6 +408,140 @@ function cmdPhasePlanIndex(cwd, phase, raw) {
|
|
|
399
408
|
if (!phase) {
|
|
400
409
|
error('phase required for phase-plan-index');
|
|
401
410
|
}
|
|
411
|
+
const built = buildPhasePlanIndex(cwd, phase);
|
|
412
|
+
if (built.fatal !== undefined) {
|
|
413
|
+
error(built.fatal);
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
output(built.result, raw);
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* `phase.dispatch-plan <phase> [--wave N] [--gaps-only] [--use-worktrees true|false]`:
|
|
420
|
+
* the executor spawns, builds, suite runs and tracking commits for the phase's
|
|
421
|
+
* incomplete plans (computed by src/dispatch-plan.cts from the plan inventory).
|
|
422
|
+
*/
|
|
423
|
+
function cmdPhaseDispatchPlan(cwd, args, raw) {
|
|
424
|
+
const parsed = (0, dispatch_plan_cjs_1.parseDispatchPlanArgs)(args);
|
|
425
|
+
if ('error' in parsed) {
|
|
426
|
+
error(parsed.error);
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
const built = buildPhasePlanIndex(cwd, parsed.phase);
|
|
430
|
+
if (built.fatal !== undefined) {
|
|
431
|
+
error(built.fatal);
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
if (built.phaseDir === null) {
|
|
435
|
+
output({ phase: built.result['phase'], error: 'Phase not found' }, raw);
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
const policy = (0, dispatch_plan_cjs_1.resolveDispatchPolicy)(cwd, parsed);
|
|
439
|
+
const plans = built.result['plans'].map((p) => {
|
|
440
|
+
const extra = built.extras.get(p['id']);
|
|
441
|
+
return {
|
|
442
|
+
id: p['id'],
|
|
443
|
+
title: p['title'] ?? null,
|
|
444
|
+
wave: p['wave'],
|
|
445
|
+
serial_group: p['serial_group'] ?? null,
|
|
446
|
+
files_modified: p['files_modified'],
|
|
447
|
+
autonomous: p['autonomous'],
|
|
448
|
+
has_summary: p['has_summary'],
|
|
449
|
+
requirements: extra?.requirements ?? [],
|
|
450
|
+
gap_closure: extra?.gapClosure ?? false,
|
|
451
|
+
};
|
|
452
|
+
});
|
|
453
|
+
const phaseDirRel = node_path_1.default.relative(cwd, built.phaseDir).split(node_path_1.default.sep).join('/');
|
|
454
|
+
const tier = (0, phase_tier_cjs_1.resolvePhaseTierForProject)(cwd, parsed.phase, parsed.tier);
|
|
455
|
+
output((0, dispatch_plan_cjs_1.computeDispatchPlan)(built.result['phase'], phaseDirRel, plans, policy, tier, { planBounceScript: tier.plan_bounce_script }), raw);
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* `phase.install-run <phase> [--tarball <tgz>] [--package-dir <dir>] [--no-build]`:
|
|
459
|
+
* pack, install into a temp project, init and run the phase's install checks
|
|
460
|
+
* against the installed copy; writes `<NN>-INSTALL-RUN.json` (src/install-run.cts).
|
|
461
|
+
*/
|
|
462
|
+
function cmdPhaseInstallRun(cwd, args, raw) {
|
|
463
|
+
const parsed = (0, install_run_cjs_1.parseInstallRunArgs)(args);
|
|
464
|
+
if ('error' in parsed) {
|
|
465
|
+
error(parsed.error, ERROR_REASON.USAGE);
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
let out;
|
|
469
|
+
try {
|
|
470
|
+
out = (0, install_run_cjs_1.runInstallRun)({ cwd, phase: parsed.phase, tarball: parsed.tarball, packageDir: parsed.packageDir, build: parsed.build });
|
|
471
|
+
}
|
|
472
|
+
catch (e) {
|
|
473
|
+
error(e.message);
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
output(out, raw);
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* `phase.tier <phase> [--tier light|standard|heavy]`: the phase's resolved
|
|
480
|
+
* ceremony tier — tier, source, gate set, suppressed gates (src/phase-tier.cts).
|
|
481
|
+
*/
|
|
482
|
+
function cmdPhaseTier(cwd, args, raw) {
|
|
483
|
+
const usage = 'Usage: phase tier <phase> [--tier light|standard|heavy]';
|
|
484
|
+
const parsed = (0, phase_tier_cjs_1.parseTierFlag)(args.filter((a) => a !== '--raw'));
|
|
485
|
+
if ('error' in parsed) {
|
|
486
|
+
error(`${parsed.error}. ${usage}`, ERROR_REASON.USAGE);
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
if (parsed.rest.length !== 1 || parsed.rest[0].startsWith('--')) {
|
|
490
|
+
error(parsed.rest.length === 0 ? `phase required for phase tier. ${usage}` : `phase tier takes one phase and --tier. ${usage}`, ERROR_REASON.USAGE);
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
const phaseArg = parsed.rest[0];
|
|
494
|
+
output({ phase: phaseArg, ...(0, phase_tier_cjs_1.resolvePhaseTierForProject)(cwd, phaseArg, parsed.tier) }, raw);
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* `phase.tier-propose <phase> [--record] [--tier X]`: propose a tier from the
|
|
498
|
+
* phase's plans (`files_modified`) or, before planning, its requirement tags
|
|
499
|
+
* and ROADMAP text. `--record` writes it to the phase's ROADMAP `**Tier:**`
|
|
500
|
+
* field, marked `(proposed: …)`, unless the operator already chose one;
|
|
501
|
+
* `--record --tier X` records X as the operator's choice.
|
|
502
|
+
*/
|
|
503
|
+
function cmdPhaseTierPropose(cwd, args, raw) {
|
|
504
|
+
const usage = 'Usage: phase tier-propose <phase> [--record] [--tier light|standard|heavy]';
|
|
505
|
+
const parsed = (0, phase_tier_cjs_1.parseTierFlag)(args.filter((a) => a !== '--raw'));
|
|
506
|
+
if ('error' in parsed) {
|
|
507
|
+
error(`${parsed.error}. ${usage}`, ERROR_REASON.USAGE);
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
const doRecord = parsed.rest.includes('--record');
|
|
511
|
+
const positional = parsed.rest.filter((a) => a !== '--record');
|
|
512
|
+
if (positional.length !== 1 || positional[0].startsWith('--')) {
|
|
513
|
+
error(positional.length === 0 ? `phase required for phase tier-propose. ${usage}` : `phase tier-propose does not support ${positional.find((a) => a.startsWith('--')) ?? positional.join(' ')}. ${usage}`, ERROR_REASON.USAGE);
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
const phaseArg = positional[0];
|
|
517
|
+
const record = (0, phase_tier_cjs_1.readPhaseRecord)(cwd, phaseArg);
|
|
518
|
+
if (record.section === null) {
|
|
519
|
+
output({ phase: phaseArg, error: 'Phase not found in ROADMAP.md' }, raw);
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
const built = buildPhasePlanIndex(cwd, phaseArg);
|
|
523
|
+
const planRows = built.fatal === undefined && built.phaseDir !== null
|
|
524
|
+
? built.result['plans'].map((p) => ({ id: p['id'], files_modified: p['files_modified'] ?? [] }))
|
|
525
|
+
: [];
|
|
526
|
+
const reqMatch = record.section.match(/^\*\*Requirements:?\*\*[^\S\n]*:?[^\S\n]*([^\n]*)$/m);
|
|
527
|
+
const requirements = reqMatch ? reqMatch[1].replace(/[[\]]/g, '').split(',').map((s) => s.trim()).filter((s) => s !== '' && s !== 'TBD') : [];
|
|
528
|
+
const proposal = (0, phase_tier_cjs_1.proposePhaseTier)({ plans: planRows, requirements, roadmapText: record.section });
|
|
529
|
+
let recorded = null;
|
|
530
|
+
if (doRecord) {
|
|
531
|
+
recorded = parsed.tier !== null
|
|
532
|
+
? (0, phase_tier_cjs_1.recordPhaseTier)(cwd, phaseArg, parsed.tier, { proposed: false })
|
|
533
|
+
: (0, phase_tier_cjs_1.recordPhaseTier)(cwd, phaseArg, proposal.tier, { proposed: true, reason: proposal.reason });
|
|
534
|
+
}
|
|
535
|
+
const after = (0, phase_tier_cjs_1.resolvePhaseTierForProject)(cwd, phaseArg, parsed.tier);
|
|
536
|
+
output({
|
|
537
|
+
phase: phaseArg,
|
|
538
|
+
proposal,
|
|
539
|
+
phase_record: record.tier !== null ? { tier: record.tier, proposed: record.proposed } : null,
|
|
540
|
+
recorded,
|
|
541
|
+
effective: { tier: after.tier, source: after.source, suppressed: after.suppressed },
|
|
542
|
+
}, raw);
|
|
543
|
+
}
|
|
544
|
+
function buildPhasePlanIndex(cwd, phase) {
|
|
402
545
|
const phasesDir = node_path_1.default.join(planningDir(cwd), 'phases');
|
|
403
546
|
const normalized = normalizePhaseName(phase);
|
|
404
547
|
let phaseDir = null;
|
|
@@ -419,8 +562,11 @@ function cmdPhasePlanIndex(cwd, phase, raw) {
|
|
|
419
562
|
// phases dir doesn't exist
|
|
420
563
|
}
|
|
421
564
|
if (!phaseDir) {
|
|
422
|
-
|
|
423
|
-
|
|
565
|
+
return {
|
|
566
|
+
result: { phase: normalized, error: 'Phase not found', plans: [], waves: {}, incomplete: [], has_checkpoints: false },
|
|
567
|
+
phaseDir: null,
|
|
568
|
+
extras: new Map(),
|
|
569
|
+
};
|
|
424
570
|
}
|
|
425
571
|
void phaseDirName; // used only to set phaseDir above
|
|
426
572
|
const phaseFiles = node_fs_1.default.readdirSync(phaseDir);
|
|
@@ -442,6 +588,13 @@ function cmdPhasePlanIndex(cwd, phase, raw) {
|
|
|
442
588
|
const xmlTasks = content.match(/<task[\s>]/gi) || [];
|
|
443
589
|
const mdTasks = content.match(/##\s*Task\s*\d+/gi) || [];
|
|
444
590
|
const taskCount = xmlTasks.length || mdTasks.length;
|
|
591
|
+
const taskTypes = xmlTasks.length > 0
|
|
592
|
+
? [...content.matchAll(/<task(\s[^>]*)?>/gi)].map((m) => /type=["']?([\w:-]+)/i.exec(m[1] ?? '')?.[1] ?? 'auto')
|
|
593
|
+
: mdTasks.map(() => 'auto');
|
|
594
|
+
const fmString = (key) => {
|
|
595
|
+
const value = fm[key];
|
|
596
|
+
return typeof value === 'string' && value.trim() !== '' ? value.trim() : null;
|
|
597
|
+
};
|
|
445
598
|
const parsedWave = parseInt(fm['wave'], 10);
|
|
446
599
|
const declaredWave = Number.isNaN(parsedWave) ? null : parsedWave;
|
|
447
600
|
let dependsOn = [];
|
|
@@ -464,6 +617,10 @@ function cmdPhasePlanIndex(cwd, phase, raw) {
|
|
|
464
617
|
filesModified = Array.isArray(fmFiles) ? fmFiles.map(String) : [String(fmFiles)];
|
|
465
618
|
}
|
|
466
619
|
const hasSummary = completedPlanIds.has(planId) || completedPlanIds.has(extractCanonicalPlanId(planFile));
|
|
620
|
+
const fmReqs = fm['requirements'];
|
|
621
|
+
const requirements = (Array.isArray(fmReqs) ? fmReqs.map(String) : typeof fmReqs === 'string' && fmReqs.trim() !== '' ? fmReqs.split(/[\s,]+/) : [])
|
|
622
|
+
.map((r) => r.trim())
|
|
623
|
+
.filter((r) => r !== '' && r !== '[]');
|
|
467
624
|
rawPlans.push({
|
|
468
625
|
id: planId,
|
|
469
626
|
declaredWave,
|
|
@@ -473,6 +630,13 @@ function cmdPhasePlanIndex(cwd, phase, raw) {
|
|
|
473
630
|
filesModified,
|
|
474
631
|
taskCount,
|
|
475
632
|
hasSummary,
|
|
633
|
+
title: (0, plan_graph_cjs_1.readPlanTitle)(fm['title']),
|
|
634
|
+
serialGroup: fmString('serial_group'),
|
|
635
|
+
chainReason: fmString('chain_reason'),
|
|
636
|
+
taskTypes,
|
|
637
|
+
requirements,
|
|
638
|
+
// eslint-disable-next-line @typescript-eslint/no-base-to-string -- FrontmatterValue scalar-to-string
|
|
639
|
+
gapClosure: String(fm['gap_closure'] ?? '').trim() === 'true',
|
|
476
640
|
});
|
|
477
641
|
}
|
|
478
642
|
// ── Pass 2: topological level assignment via depends_on DAG ──────────────
|
|
@@ -481,18 +645,31 @@ function cmdPhasePlanIndex(cwd, phase, raw) {
|
|
|
481
645
|
const lower = p.id.toLowerCase();
|
|
482
646
|
const existing = seenLower.get(lower);
|
|
483
647
|
if (existing !== undefined) {
|
|
484
|
-
|
|
485
|
-
|
|
648
|
+
return {
|
|
649
|
+
fatal: `depends_on index collision in phase ${normalized}: plan IDs '${existing}' and '${p.id}' are identical when case-folded. Rename one file to avoid ambiguous dependency resolution.`,
|
|
650
|
+
};
|
|
486
651
|
}
|
|
487
652
|
seenLower.set(lower, p.id);
|
|
488
653
|
}
|
|
489
654
|
const planMap = new Map(rawPlans.map((p) => [p.id.toLowerCase(), p]));
|
|
490
655
|
const canonicalToId = new Map(rawPlans.map((p) => [extractCanonicalPlanId(p.id).toLowerCase(), p.id]));
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
const
|
|
494
|
-
|
|
495
|
-
|
|
656
|
+
// Wave + serial-group assignment and chain metrics: single owner is plan-graph.cts.
|
|
657
|
+
const resolveDep = (dep) => {
|
|
658
|
+
const lower = String(dep).toLowerCase();
|
|
659
|
+
return planMap.has(lower) ? planMap.get(lower).id : canonicalToId.get(lower);
|
|
660
|
+
};
|
|
661
|
+
const graph = (0, plan_graph_cjs_1.computePlanGraph)(rawPlans.map((p) => ({
|
|
662
|
+
id: p.id,
|
|
663
|
+
title: p.title,
|
|
664
|
+
dependsOn: p.dependsOn.map(resolveDep).filter((d) => d !== undefined),
|
|
665
|
+
filesModified: p.filesModified,
|
|
666
|
+
serialGroup: p.serialGroup,
|
|
667
|
+
chainReason: p.chainReason,
|
|
668
|
+
taskTypes: p.taskTypes,
|
|
669
|
+
})));
|
|
670
|
+
if (graph.cycle) {
|
|
671
|
+
const cycleNodes = graph.cycle;
|
|
672
|
+
return { fatal: `depends_on cycle detected in phase ${normalized} — cycle involves: ${cycleNodes.join(', ')}` };
|
|
496
673
|
}
|
|
497
674
|
// ── Pass 3: determine lowest bucket key and build output ─────────────────
|
|
498
675
|
const anyWaveZero = rawPlans.some((p) => p.declaredWave === 0);
|
|
@@ -509,14 +686,16 @@ function cmdPhasePlanIndex(cwd, phase, raw) {
|
|
|
509
686
|
if (!rawPlan.hasSummary) {
|
|
510
687
|
incomplete.push(rawPlan.id);
|
|
511
688
|
}
|
|
512
|
-
const computedWave = (level
|
|
689
|
+
const computedWave = (graph.level[rawPlan.id] ?? 0) + levelOffset;
|
|
513
690
|
const effectiveWave = computedWave;
|
|
514
691
|
if (rawPlan.declaredWave !== null && rawPlan.declaredWave !== computedWave) {
|
|
515
692
|
warnings.push(`Plan ${rawPlan.id}: declared wave: ${rawPlan.declaredWave} but depends_on DAG places it in wave ${computedWave}`);
|
|
516
693
|
}
|
|
517
694
|
const plan = {
|
|
518
695
|
id: rawPlan.id,
|
|
696
|
+
title: rawPlan.title,
|
|
519
697
|
wave: effectiveWave,
|
|
698
|
+
serial_group: graph.serialGroupOf[rawPlan.id] ?? null,
|
|
520
699
|
depends_on: rawPlan.dependsOn.map((dep) => {
|
|
521
700
|
const lower = String(dep).toLowerCase();
|
|
522
701
|
return planMap.has(lower) ? planMap.get(lower).id : dep;
|
|
@@ -538,14 +717,28 @@ function cmdPhasePlanIndex(cwd, phase, raw) {
|
|
|
538
717
|
phase: normalized,
|
|
539
718
|
plans,
|
|
540
719
|
waves,
|
|
720
|
+
serial_groups: Object.fromEntries(graph.serialGroups.map((g) => [g.name, { wave: g.level + levelOffset, plans: g.plans, shared_files: g.shared_files }])),
|
|
721
|
+
graph: {
|
|
722
|
+
plan_count: graph.plan_count,
|
|
723
|
+
wave_count: graph.wave_count,
|
|
724
|
+
longest_chain: graph.longest_chain,
|
|
725
|
+
chain_check: graph.chain_check,
|
|
726
|
+
implicit_edges: graph.implicitEdges,
|
|
727
|
+
merge_candidates: graph.merge_candidates,
|
|
728
|
+
},
|
|
541
729
|
incomplete,
|
|
542
730
|
has_checkpoints: hasCheckpoints,
|
|
543
731
|
};
|
|
732
|
+
warnings.push(...graph.warnings);
|
|
544
733
|
if (planNamingWarning)
|
|
545
734
|
result['warning'] = planNamingWarning;
|
|
546
735
|
if (warnings.length > 0)
|
|
547
736
|
result['warnings'] = warnings;
|
|
548
|
-
|
|
737
|
+
return {
|
|
738
|
+
result,
|
|
739
|
+
phaseDir,
|
|
740
|
+
extras: new Map(rawPlans.map((p) => [p.id, { requirements: p.requirements, gapClosure: p.gapClosure }])),
|
|
741
|
+
};
|
|
549
742
|
}
|
|
550
743
|
function cmdPhaseAdd(cwd, description, raw, customId) {
|
|
551
744
|
if (!description) {
|
|
@@ -986,8 +1179,10 @@ function cmdPhaseRemove(cwd, targetPhase, options, raw) {
|
|
|
986
1179
|
}
|
|
987
1180
|
updateRoadmapAfterPhaseRemoval(roadmapPath, targetPhase, isDecimal, parseInt(normalized, 10), cwd);
|
|
988
1181
|
const statePath = node_path_1.default.join(planningDir(cwd), 'STATE.md');
|
|
1182
|
+
// 261007-ixt D-3: name every frontmatter key the shared writer changed.
|
|
1183
|
+
let stateFrontmatterUpdated = [];
|
|
989
1184
|
if (node_fs_1.default.existsSync(statePath)) {
|
|
990
|
-
readModifyWriteStateMd(statePath, (stateContent) => {
|
|
1185
|
+
stateFrontmatterUpdated = readModifyWriteStateMd(statePath, (stateContent) => {
|
|
991
1186
|
const totalRaw = stateExtractField(stateContent, 'Total Phases');
|
|
992
1187
|
if (totalRaw) {
|
|
993
1188
|
stateContent =
|
|
@@ -999,7 +1194,7 @@ function cmdPhaseRemove(cwd, targetPhase, options, raw) {
|
|
|
999
1194
|
stateContent = stateContent.replace(/(\bof\s+)(\d+)(\s*(?:\(|phases?))/i, `$1${parseInt(ofMatch[2], 10) - 1}$3`);
|
|
1000
1195
|
}
|
|
1001
1196
|
return stateContent;
|
|
1002
|
-
}, cwd);
|
|
1197
|
+
}, cwd).frontmatter_updated;
|
|
1003
1198
|
}
|
|
1004
1199
|
output({
|
|
1005
1200
|
removed: targetPhase,
|
|
@@ -1008,6 +1203,7 @@ function cmdPhaseRemove(cwd, targetPhase, options, raw) {
|
|
|
1008
1203
|
renamed_files: renamedFiles,
|
|
1009
1204
|
roadmap_updated: true,
|
|
1010
1205
|
state_updated: node_fs_1.default.existsSync(statePath),
|
|
1206
|
+
state_frontmatter_updated: stateFrontmatterUpdated,
|
|
1011
1207
|
}, raw);
|
|
1012
1208
|
}
|
|
1013
1209
|
function writePlanningFileSet(writes) {
|
|
@@ -1064,7 +1260,7 @@ function cmdPhaseComplete(cwd, phaseNum, raw) {
|
|
|
1064
1260
|
const statePath = node_path_1.default.join(planningDir(cwd), 'STATE.md');
|
|
1065
1261
|
const phasesDir = node_path_1.default.join(planningDir(cwd), 'phases');
|
|
1066
1262
|
const today = clock_cjs_1.realClock.today();
|
|
1067
|
-
const phaseInfoRaw =
|
|
1263
|
+
const phaseInfoRaw = resolvePhaseForRead(cwd, phaseNum);
|
|
1068
1264
|
if (!phaseInfoRaw) {
|
|
1069
1265
|
error(`Phase ${phaseNum} not found`);
|
|
1070
1266
|
}
|
|
@@ -1113,6 +1309,8 @@ function cmdPhaseComplete(cwd, phaseNum, raw) {
|
|
|
1113
1309
|
let nextPhaseNum = null;
|
|
1114
1310
|
let nextPhaseName = null;
|
|
1115
1311
|
let isLastPhase = true;
|
|
1312
|
+
// 261007-ixt D-3: every STATE.md frontmatter key this transaction changes.
|
|
1313
|
+
let stateFrontmatterUpdated = [];
|
|
1116
1314
|
withPlanningLock(cwd, () => {
|
|
1117
1315
|
const runPhaseCompleteTransaction = () => {
|
|
1118
1316
|
const writes = [];
|
|
@@ -1143,7 +1341,16 @@ function cmdPhaseComplete(cwd, phaseNum, raw) {
|
|
|
1143
1341
|
}
|
|
1144
1342
|
return '|' + cells.join('|') + '|';
|
|
1145
1343
|
});
|
|
1146
|
-
|
|
1344
|
+
// D-08-33: the Plans summary line is resolved through the ONE builder in
|
|
1345
|
+
// src/roadmap-parser.cjs. The inline pattern that stood here knew a
|
|
1346
|
+
// single spelling (`**Plans:**`), had no phase-number boundary and
|
|
1347
|
+
// scanned without a bound — so on a CANONICAL roadmap (`**Plans**:`,
|
|
1348
|
+
// colon outside the bold) it walked out of this phase's section and
|
|
1349
|
+
// wrote `N/N plans complete` into a LATER phase, asserting a build that
|
|
1350
|
+
// had not happened (UAT F2, measured on the live fixture). Only the
|
|
1351
|
+
// pattern moved: the replacement string, the unscoped `.replace` and
|
|
1352
|
+
// this transaction's write set are unchanged (D-08-13/14).
|
|
1353
|
+
const planCountPattern = buildPlansSummaryLinePattern(phaseNum);
|
|
1147
1354
|
roadmapContent = roadmapContent.replace(planCountPattern, `$1${summaryCount}/${planCount} plans complete`);
|
|
1148
1355
|
const phaseInfoSummaries = phaseInfo['summaries'];
|
|
1149
1356
|
for (const summaryFile of phaseInfoSummaries) {
|
|
@@ -1370,7 +1577,21 @@ function cmdPhaseComplete(cwd, phaseNum, raw) {
|
|
|
1370
1577
|
}
|
|
1371
1578
|
}
|
|
1372
1579
|
stateContent = updatePerformanceMetricsSection(stateContent, cwd, phaseNum, planCount, summaryCount);
|
|
1373
|
-
|
|
1580
|
+
// 261007-ixt D-1: completed_phases is capped by the ROADMAP progress table,
|
|
1581
|
+
// and this transaction is flipping this phase's row to Complete in the same
|
|
1582
|
+
// file set — so the writer counts from the roadmap being written, not the
|
|
1583
|
+
// one still on disk.
|
|
1584
|
+
// D-10: this transaction sets Last activity itself; that explicit date flows.
|
|
1585
|
+
const activityFieldSet = (0, state_document_cjs_1.extractPositionalField)(stateContent, 'Last Activity', 'Last activity') !==
|
|
1586
|
+
(0, state_document_cjs_1.extractPositionalField)(originalStateContent, 'Last Activity', 'Last activity');
|
|
1587
|
+
// 261007-rly D-11: phase complete opts OUT of the stopped_at hold and keeps
|
|
1588
|
+
// re-deriving the key from the Session line, as it did before the hold moved
|
|
1589
|
+
// into syncStateFrontmatter: bug #3517's pin (tests/phase.test.cjs) needs a
|
|
1590
|
+
// newer Session line to replace a stale stored value here, the opposite of
|
|
1591
|
+
// the operator-note shape the hold protects. Filed, not decided here:
|
|
1592
|
+
// todos/pending/phase-complete-rederives-stopped-at-from-the-session-line.md.
|
|
1593
|
+
stateContent = syncStateFrontmatter(stateContent, cwd, roadmapContent, activityFieldSet, true);
|
|
1594
|
+
stateFrontmatterUpdated = (0, state_document_cjs_1.diffFrontmatterFields)(extractFrontmatter(originalStateContent), extractFrontmatter(stateContent));
|
|
1374
1595
|
writes.push({ filePath: statePath, before: originalStateContent, after: stateContent });
|
|
1375
1596
|
}
|
|
1376
1597
|
writePlanningFileSet(writes);
|
|
@@ -1410,6 +1631,7 @@ function cmdPhaseComplete(cwd, phaseNum, raw) {
|
|
|
1410
1631
|
date: today,
|
|
1411
1632
|
roadmap_updated: node_fs_1.default.existsSync(roadmapPath),
|
|
1412
1633
|
state_updated: node_fs_1.default.existsSync(statePath),
|
|
1634
|
+
state_frontmatter_updated: stateFrontmatterUpdated,
|
|
1413
1635
|
requirements_updated: requirementsUpdated,
|
|
1414
1636
|
auto_pruned: autoPruned,
|
|
1415
1637
|
warnings,
|
|
@@ -1421,7 +1643,7 @@ function cmdPhaseUatPassed(cwd, phaseNum, raw, opts = {}) {
|
|
|
1421
1643
|
if (!phaseNum) {
|
|
1422
1644
|
error('phase number required for phase uat-passed');
|
|
1423
1645
|
}
|
|
1424
|
-
const phaseInfoRaw =
|
|
1646
|
+
const phaseInfoRaw = resolvePhaseForRead(cwd, phaseNum);
|
|
1425
1647
|
if (!phaseInfoRaw) {
|
|
1426
1648
|
error(`Phase ${phaseNum} not found`);
|
|
1427
1649
|
}
|
|
@@ -1435,6 +1657,10 @@ module.exports = {
|
|
|
1435
1657
|
cmdPhaseNextDecimal,
|
|
1436
1658
|
cmdFindPhase,
|
|
1437
1659
|
cmdPhasePlanIndex,
|
|
1660
|
+
cmdPhaseDispatchPlan,
|
|
1661
|
+
cmdPhaseInstallRun,
|
|
1662
|
+
cmdPhaseTier,
|
|
1663
|
+
cmdPhaseTierPropose,
|
|
1438
1664
|
cmdPhaseAdd,
|
|
1439
1665
|
cmdPhaseAddBatch,
|
|
1440
1666
|
cmdPhaseMvpMode,
|
|
@@ -35,6 +35,8 @@ function routePhasesCommand({ phase, milestone, args, cwd, raw, error }) {
|
|
|
35
35
|
phase.cmdPhasesList(cwd, options, raw);
|
|
36
36
|
},
|
|
37
37
|
clear: () => milestone.cmdPhasesClear(cwd, raw, args.slice(2)),
|
|
38
|
+
// 261007-mmz: the closed-milestone mover new-milestone.md --reset-phase-numbers calls.
|
|
39
|
+
'archive-closed': () => milestone.cmdPhasesArchiveClosed(cwd, raw, args.slice(2)),
|
|
38
40
|
},
|
|
39
41
|
});
|
|
40
42
|
}
|