maxsimcli 2.5.5 → 3.0.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/README.md +4 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/adapters/base.d.ts +34 -0
- package/dist/adapters/base.d.ts.map +1 -0
- package/dist/adapters/base.js +116 -0
- package/dist/adapters/base.js.map +1 -0
- package/dist/adapters/claude.d.ts +21 -0
- package/dist/adapters/claude.d.ts.map +1 -0
- package/dist/adapters/claude.js +104 -0
- package/dist/adapters/claude.js.map +1 -0
- package/dist/adapters/codex.d.ts +19 -0
- package/dist/adapters/codex.d.ts.map +1 -0
- package/dist/adapters/codex.js +94 -0
- package/dist/adapters/codex.js.map +1 -0
- package/dist/adapters/gemini.d.ts +19 -0
- package/dist/adapters/gemini.d.ts.map +1 -0
- package/dist/adapters/gemini.js +96 -0
- package/dist/adapters/gemini.js.map +1 -0
- package/dist/adapters/index.d.ts +20 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +56 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/opencode.d.ts +17 -0
- package/dist/adapters/opencode.d.ts.map +1 -0
- package/dist/adapters/opencode.js +111 -0
- package/dist/adapters/opencode.js.map +1 -0
- package/dist/adapters/transforms/content.d.ts +39 -0
- package/dist/adapters/transforms/content.d.ts.map +1 -0
- package/dist/adapters/transforms/content.js +125 -0
- package/dist/adapters/transforms/content.js.map +1 -0
- package/dist/adapters/transforms/frontmatter.d.ts +42 -0
- package/dist/adapters/transforms/frontmatter.d.ts.map +1 -0
- package/dist/adapters/transforms/frontmatter.js +204 -0
- package/dist/adapters/transforms/frontmatter.js.map +1 -0
- package/dist/adapters/transforms/tool-maps.d.ts +20 -0
- package/dist/adapters/transforms/tool-maps.d.ts.map +1 -0
- package/dist/adapters/transforms/tool-maps.js +64 -0
- package/dist/adapters/transforms/tool-maps.js.map +1 -0
- package/dist/adapters/types.d.ts +10 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +6 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/assets/CHANGELOG.md +26 -0
- package/dist/assets/dashboard/server.js +27731 -12035
- package/dist/assets/hooks/maxsim-check-update.cjs +2 -2
- package/dist/assets/hooks/maxsim-check-update.cjs.map +1 -0
- package/dist/assets/hooks/maxsim-context-monitor.cjs +2 -2
- package/dist/assets/hooks/maxsim-context-monitor.cjs.map +1 -0
- package/dist/assets/hooks/maxsim-statusline.cjs +2 -2
- package/dist/assets/hooks/maxsim-statusline.cjs.map +1 -0
- package/dist/cli.cjs +15316 -5348
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.d.ts +0 -6
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +282 -443
- package/dist/cli.js.map +1 -1
- package/dist/core/commands.d.ts +19 -0
- package/dist/core/commands.d.ts.map +1 -0
- package/dist/core/commands.js +560 -0
- package/dist/core/commands.js.map +1 -0
- package/dist/core/config.d.ts +9 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +147 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/core.d.ts +39 -0
- package/dist/core/core.d.ts.map +1 -0
- package/dist/core/core.js +411 -0
- package/dist/core/core.js.map +1 -0
- package/dist/core/frontmatter.d.ts +33 -0
- package/dist/core/frontmatter.d.ts.map +1 -0
- package/dist/core/frontmatter.js +192 -0
- package/dist/core/frontmatter.js.map +1 -0
- package/dist/core/index.d.ts +20 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +126 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/init.d.ts +252 -0
- package/dist/core/init.d.ts.map +1 -0
- package/dist/core/init.js +578 -0
- package/dist/core/init.js.map +1 -0
- package/dist/core/milestone.d.ts +9 -0
- package/dist/core/milestone.d.ts.map +1 -0
- package/dist/core/milestone.js +191 -0
- package/dist/core/milestone.js.map +1 -0
- package/dist/core/phase.d.ts +17 -0
- package/dist/core/phase.d.ts.map +1 -0
- package/dist/core/phase.js +610 -0
- package/dist/core/phase.js.map +1 -0
- package/dist/core/roadmap.d.ts +9 -0
- package/dist/core/roadmap.d.ts.map +1 -0
- package/dist/core/roadmap.js +228 -0
- package/dist/core/roadmap.js.map +1 -0
- package/dist/core/state.d.ts +21 -0
- package/dist/core/state.d.ts.map +1 -0
- package/dist/core/state.js +507 -0
- package/dist/core/state.js.map +1 -0
- package/dist/core/template.d.ts +30 -0
- package/dist/core/template.d.ts.map +1 -0
- package/dist/core/template.js +225 -0
- package/dist/core/template.js.map +1 -0
- package/dist/core/types.d.ts +374 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +53 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/verify.d.ts +127 -0
- package/dist/core/verify.d.ts.map +1 -0
- package/dist/core/verify.js +783 -0
- package/dist/core/verify.js.map +1 -0
- package/dist/hooks/index.d.ts +11 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +18 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/maxsim-check-update.d.ts +17 -0
- package/dist/hooks/maxsim-check-update.d.ts.map +1 -0
- package/dist/hooks/maxsim-check-update.js +101 -0
- package/dist/hooks/maxsim-check-update.js.map +1 -0
- package/dist/hooks/maxsim-context-monitor.d.ts +21 -0
- package/dist/hooks/maxsim-context-monitor.d.ts.map +1 -0
- package/dist/hooks/maxsim-context-monitor.js +131 -0
- package/dist/hooks/maxsim-context-monitor.js.map +1 -0
- package/dist/hooks/maxsim-statusline.d.ts +19 -0
- package/dist/hooks/maxsim-statusline.d.ts.map +1 -0
- package/dist/hooks/maxsim-statusline.js +146 -0
- package/dist/hooks/maxsim-statusline.js.map +1 -0
- package/dist/hooks/shared.d.ts +11 -0
- package/dist/hooks/shared.d.ts.map +1 -0
- package/dist/hooks/shared.js +29 -0
- package/dist/hooks/shared.js.map +1 -0
- package/dist/install.cjs +2807 -1211
- package/dist/install.cjs.map +1 -1
- package/dist/install.js +34 -85
- package/dist/install.js.map +1 -1
- package/package.json +10 -7
- package/dist/assets/hooks/index.cjs +0 -239
- package/dist/assets/templates/CLAUDE.md +0 -22
- package/dist/assets/templates/package.json +0 -5
- package/dist/assets/templates/project.json +0 -5
|
@@ -0,0 +1,610 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Phase — Phase CRUD, query, and lifecycle operations
|
|
4
|
+
*
|
|
5
|
+
* Ported from maxsim/bin/lib/phase.cjs
|
|
6
|
+
*/
|
|
7
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
9
|
+
};
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.cmdPhasesList = cmdPhasesList;
|
|
12
|
+
exports.cmdPhaseNextDecimal = cmdPhaseNextDecimal;
|
|
13
|
+
exports.cmdFindPhase = cmdFindPhase;
|
|
14
|
+
exports.cmdPhasePlanIndex = cmdPhasePlanIndex;
|
|
15
|
+
exports.cmdPhaseAdd = cmdPhaseAdd;
|
|
16
|
+
exports.cmdPhaseInsert = cmdPhaseInsert;
|
|
17
|
+
exports.cmdPhaseRemove = cmdPhaseRemove;
|
|
18
|
+
exports.cmdPhaseComplete = cmdPhaseComplete;
|
|
19
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
20
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
21
|
+
const core_js_1 = require("./core.js");
|
|
22
|
+
const frontmatter_js_1 = require("./frontmatter.js");
|
|
23
|
+
// ─── Phase list ─────────────────────────────────────────────────────────────
|
|
24
|
+
function cmdPhasesList(cwd, options, raw) {
|
|
25
|
+
const phasesDir = node_path_1.default.join(cwd, '.planning', 'phases');
|
|
26
|
+
const { type, phase, includeArchived } = options;
|
|
27
|
+
if (!node_fs_1.default.existsSync(phasesDir)) {
|
|
28
|
+
if (type) {
|
|
29
|
+
(0, core_js_1.output)({ files: [], count: 0 }, raw, '');
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
(0, core_js_1.output)({ directories: [], count: 0 }, raw, '');
|
|
33
|
+
}
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const entries = node_fs_1.default.readdirSync(phasesDir, { withFileTypes: true });
|
|
38
|
+
let dirs = entries.filter(e => e.isDirectory()).map(e => e.name);
|
|
39
|
+
if (includeArchived) {
|
|
40
|
+
const archived = (0, core_js_1.getArchivedPhaseDirs)(cwd);
|
|
41
|
+
for (const a of archived) {
|
|
42
|
+
dirs.push(`${a.name} [${a.milestone}]`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
dirs.sort((a, b) => (0, core_js_1.comparePhaseNum)(a, b));
|
|
46
|
+
if (phase) {
|
|
47
|
+
const normalized = (0, core_js_1.normalizePhaseName)(phase);
|
|
48
|
+
const match = dirs.find(d => d.startsWith(normalized));
|
|
49
|
+
if (!match) {
|
|
50
|
+
(0, core_js_1.output)({ files: [], count: 0, phase_dir: null, error: 'Phase not found' }, raw, '');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
dirs = [match];
|
|
54
|
+
}
|
|
55
|
+
if (type) {
|
|
56
|
+
const files = [];
|
|
57
|
+
for (const dir of dirs) {
|
|
58
|
+
const dirPath = node_path_1.default.join(phasesDir, dir);
|
|
59
|
+
const dirFiles = node_fs_1.default.readdirSync(dirPath);
|
|
60
|
+
let filtered;
|
|
61
|
+
if (type === 'plans') {
|
|
62
|
+
filtered = dirFiles.filter(f => f.endsWith('-PLAN.md') || f === 'PLAN.md');
|
|
63
|
+
}
|
|
64
|
+
else if (type === 'summaries') {
|
|
65
|
+
filtered = dirFiles.filter(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md');
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
filtered = dirFiles;
|
|
69
|
+
}
|
|
70
|
+
files.push(...filtered.sort());
|
|
71
|
+
}
|
|
72
|
+
const result = {
|
|
73
|
+
files,
|
|
74
|
+
count: files.length,
|
|
75
|
+
phase_dir: phase ? dirs[0].replace(/^\d+(?:\.\d+)?-?/, '') : null,
|
|
76
|
+
};
|
|
77
|
+
(0, core_js_1.output)(result, raw, files.join('\n'));
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
(0, core_js_1.output)({ directories: dirs, count: dirs.length }, raw, dirs.join('\n'));
|
|
81
|
+
}
|
|
82
|
+
catch (e) {
|
|
83
|
+
(0, core_js_1.error)('Failed to list phases: ' + e.message);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// ─── Next decimal ───────────────────────────────────────────────────────────
|
|
87
|
+
function cmdPhaseNextDecimal(cwd, basePhase, raw) {
|
|
88
|
+
const phasesDir = node_path_1.default.join(cwd, '.planning', 'phases');
|
|
89
|
+
const normalized = (0, core_js_1.normalizePhaseName)(basePhase);
|
|
90
|
+
if (!node_fs_1.default.existsSync(phasesDir)) {
|
|
91
|
+
(0, core_js_1.output)({ found: false, base_phase: normalized, next: `${normalized}.1`, existing: [] }, raw, `${normalized}.1`);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
const entries = node_fs_1.default.readdirSync(phasesDir, { withFileTypes: true });
|
|
96
|
+
const dirs = entries.filter(e => e.isDirectory()).map(e => e.name);
|
|
97
|
+
const baseExists = dirs.some(d => d.startsWith(normalized + '-') || d === normalized);
|
|
98
|
+
const decimalPattern = new RegExp(`^${normalized}\\.(\\d+)`);
|
|
99
|
+
const existingDecimals = [];
|
|
100
|
+
for (const dir of dirs) {
|
|
101
|
+
const match = dir.match(decimalPattern);
|
|
102
|
+
if (match) {
|
|
103
|
+
existingDecimals.push(`${normalized}.${match[1]}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
existingDecimals.sort((a, b) => {
|
|
107
|
+
const aNum = parseFloat(a);
|
|
108
|
+
const bNum = parseFloat(b);
|
|
109
|
+
return aNum - bNum;
|
|
110
|
+
});
|
|
111
|
+
let nextDecimal;
|
|
112
|
+
if (existingDecimals.length === 0) {
|
|
113
|
+
nextDecimal = `${normalized}.1`;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
const lastDecimal = existingDecimals[existingDecimals.length - 1];
|
|
117
|
+
const lastNum = parseInt(lastDecimal.split('.')[1], 10);
|
|
118
|
+
nextDecimal = `${normalized}.${lastNum + 1}`;
|
|
119
|
+
}
|
|
120
|
+
(0, core_js_1.output)({ found: baseExists, base_phase: normalized, next: nextDecimal, existing: existingDecimals }, raw, nextDecimal);
|
|
121
|
+
}
|
|
122
|
+
catch (e) {
|
|
123
|
+
(0, core_js_1.error)('Failed to calculate next decimal phase: ' + e.message);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// ─── Find phase ─────────────────────────────────────────────────────────────
|
|
127
|
+
function cmdFindPhase(cwd, phase, raw) {
|
|
128
|
+
if (!phase) {
|
|
129
|
+
(0, core_js_1.error)('phase identifier required');
|
|
130
|
+
}
|
|
131
|
+
const phasesDir = node_path_1.default.join(cwd, '.planning', 'phases');
|
|
132
|
+
const normalized = (0, core_js_1.normalizePhaseName)(phase);
|
|
133
|
+
const notFound = { found: false, directory: null, phase_number: null, phase_name: null, plans: [], summaries: [] };
|
|
134
|
+
try {
|
|
135
|
+
const entries = node_fs_1.default.readdirSync(phasesDir, { withFileTypes: true });
|
|
136
|
+
const dirs = entries.filter(e => e.isDirectory()).map(e => e.name).sort((a, b) => (0, core_js_1.comparePhaseNum)(a, b));
|
|
137
|
+
const match = dirs.find(d => d.startsWith(normalized));
|
|
138
|
+
if (!match) {
|
|
139
|
+
(0, core_js_1.output)(notFound, raw, '');
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const dirMatch = match.match(/^(\d+[A-Z]?(?:\.\d+)?)-?(.*)/i);
|
|
143
|
+
const phaseNumber = dirMatch ? dirMatch[1] : normalized;
|
|
144
|
+
const phaseName = dirMatch && dirMatch[2] ? dirMatch[2] : null;
|
|
145
|
+
const phaseDir = node_path_1.default.join(phasesDir, match);
|
|
146
|
+
const phaseFiles = node_fs_1.default.readdirSync(phaseDir);
|
|
147
|
+
const plans = phaseFiles.filter(f => f.endsWith('-PLAN.md') || f === 'PLAN.md').sort();
|
|
148
|
+
const summaries = phaseFiles.filter(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md').sort();
|
|
149
|
+
const result = {
|
|
150
|
+
found: true,
|
|
151
|
+
directory: node_path_1.default.join('.planning', 'phases', match),
|
|
152
|
+
phase_number: phaseNumber,
|
|
153
|
+
phase_name: phaseName,
|
|
154
|
+
plans,
|
|
155
|
+
summaries,
|
|
156
|
+
};
|
|
157
|
+
(0, core_js_1.output)(result, raw, result.directory);
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
(0, core_js_1.output)(notFound, raw, '');
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// ─── Phase plan index ───────────────────────────────────────────────────────
|
|
164
|
+
function cmdPhasePlanIndex(cwd, phase, raw) {
|
|
165
|
+
if (!phase) {
|
|
166
|
+
(0, core_js_1.error)('phase required for phase-plan-index');
|
|
167
|
+
}
|
|
168
|
+
const phasesDir = node_path_1.default.join(cwd, '.planning', 'phases');
|
|
169
|
+
const normalized = (0, core_js_1.normalizePhaseName)(phase);
|
|
170
|
+
let phaseDir = null;
|
|
171
|
+
let phaseDirName = null;
|
|
172
|
+
try {
|
|
173
|
+
const entries = node_fs_1.default.readdirSync(phasesDir, { withFileTypes: true });
|
|
174
|
+
const dirs = entries.filter(e => e.isDirectory()).map(e => e.name).sort((a, b) => (0, core_js_1.comparePhaseNum)(a, b));
|
|
175
|
+
const match = dirs.find(d => d.startsWith(normalized));
|
|
176
|
+
if (match) {
|
|
177
|
+
phaseDir = node_path_1.default.join(phasesDir, match);
|
|
178
|
+
phaseDirName = match;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
catch (e) {
|
|
182
|
+
/* optional op, ignore */
|
|
183
|
+
if (process.env.MAXSIM_DEBUG)
|
|
184
|
+
console.error(e);
|
|
185
|
+
}
|
|
186
|
+
if (!phaseDir) {
|
|
187
|
+
(0, core_js_1.output)({ phase: normalized, error: 'Phase not found', plans: [], waves: {}, incomplete: [], has_checkpoints: false }, raw);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const phaseFiles = node_fs_1.default.readdirSync(phaseDir);
|
|
191
|
+
const planFiles = phaseFiles.filter(f => f.endsWith('-PLAN.md') || f === 'PLAN.md').sort();
|
|
192
|
+
const summaryFiles = phaseFiles.filter(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md');
|
|
193
|
+
const completedPlanIds = new Set(summaryFiles.map(s => s.replace('-SUMMARY.md', '').replace('SUMMARY.md', '')));
|
|
194
|
+
const plans = [];
|
|
195
|
+
const waves = {};
|
|
196
|
+
const incomplete = [];
|
|
197
|
+
let hasCheckpoints = false;
|
|
198
|
+
for (const planFile of planFiles) {
|
|
199
|
+
const planId = planFile.replace('-PLAN.md', '').replace('PLAN.md', '');
|
|
200
|
+
const planPath = node_path_1.default.join(phaseDir, planFile);
|
|
201
|
+
const content = node_fs_1.default.readFileSync(planPath, 'utf-8');
|
|
202
|
+
const fm = (0, frontmatter_js_1.extractFrontmatter)(content);
|
|
203
|
+
const taskMatches = content.match(/##\s*Task\s*\d+/gi) || [];
|
|
204
|
+
const taskCount = taskMatches.length;
|
|
205
|
+
const wave = parseInt(fm.wave, 10) || 1;
|
|
206
|
+
let autonomous = true;
|
|
207
|
+
if (fm.autonomous !== undefined) {
|
|
208
|
+
autonomous = fm.autonomous === 'true' || fm.autonomous === true;
|
|
209
|
+
}
|
|
210
|
+
if (!autonomous) {
|
|
211
|
+
hasCheckpoints = true;
|
|
212
|
+
}
|
|
213
|
+
let filesModified = [];
|
|
214
|
+
if (fm['files-modified']) {
|
|
215
|
+
filesModified = Array.isArray(fm['files-modified']) ? fm['files-modified'] : [fm['files-modified']];
|
|
216
|
+
}
|
|
217
|
+
const hasSummary = completedPlanIds.has(planId);
|
|
218
|
+
if (!hasSummary) {
|
|
219
|
+
incomplete.push(planId);
|
|
220
|
+
}
|
|
221
|
+
const plan = {
|
|
222
|
+
id: planId,
|
|
223
|
+
wave,
|
|
224
|
+
autonomous,
|
|
225
|
+
objective: fm.objective || null,
|
|
226
|
+
files_modified: filesModified,
|
|
227
|
+
task_count: taskCount,
|
|
228
|
+
has_summary: hasSummary,
|
|
229
|
+
};
|
|
230
|
+
plans.push(plan);
|
|
231
|
+
const waveKey = String(wave);
|
|
232
|
+
if (!waves[waveKey]) {
|
|
233
|
+
waves[waveKey] = [];
|
|
234
|
+
}
|
|
235
|
+
waves[waveKey].push(planId);
|
|
236
|
+
}
|
|
237
|
+
(0, core_js_1.output)({ phase: normalized, plans, waves, incomplete, has_checkpoints: hasCheckpoints }, raw);
|
|
238
|
+
}
|
|
239
|
+
// ─── Phase add ──────────────────────────────────────────────────────────────
|
|
240
|
+
function cmdPhaseAdd(cwd, description, raw) {
|
|
241
|
+
if (!description) {
|
|
242
|
+
(0, core_js_1.error)('description required for phase add');
|
|
243
|
+
}
|
|
244
|
+
const roadmapPath = node_path_1.default.join(cwd, '.planning', 'ROADMAP.md');
|
|
245
|
+
if (!node_fs_1.default.existsSync(roadmapPath)) {
|
|
246
|
+
(0, core_js_1.error)('ROADMAP.md not found');
|
|
247
|
+
}
|
|
248
|
+
const content = node_fs_1.default.readFileSync(roadmapPath, 'utf-8');
|
|
249
|
+
const slug = (0, core_js_1.generateSlugInternal)(description);
|
|
250
|
+
const phasePattern = (0, core_js_1.getPhasePattern)();
|
|
251
|
+
let maxPhase = 0;
|
|
252
|
+
let m;
|
|
253
|
+
while ((m = phasePattern.exec(content)) !== null) {
|
|
254
|
+
const num = parseInt(m[1], 10);
|
|
255
|
+
if (num > maxPhase)
|
|
256
|
+
maxPhase = num;
|
|
257
|
+
}
|
|
258
|
+
const newPhaseNum = maxPhase + 1;
|
|
259
|
+
const paddedNum = String(newPhaseNum).padStart(2, '0');
|
|
260
|
+
const dirName = `${paddedNum}-${slug}`;
|
|
261
|
+
const dirPath = node_path_1.default.join(cwd, '.planning', 'phases', dirName);
|
|
262
|
+
node_fs_1.default.mkdirSync(dirPath, { recursive: true });
|
|
263
|
+
node_fs_1.default.writeFileSync(node_path_1.default.join(dirPath, '.gitkeep'), '');
|
|
264
|
+
const phaseEntry = `\n### Phase ${newPhaseNum}: ${description}\n\n**Goal:** [To be planned]\n**Requirements**: TBD\n**Depends on:** Phase ${maxPhase}\n**Plans:** 0 plans\n\nPlans:\n- [ ] TBD (run /maxsim:plan-phase ${newPhaseNum} to break down)\n`;
|
|
265
|
+
let updatedContent;
|
|
266
|
+
const lastSeparator = content.lastIndexOf('\n---');
|
|
267
|
+
if (lastSeparator > 0) {
|
|
268
|
+
updatedContent = content.slice(0, lastSeparator) + phaseEntry + content.slice(lastSeparator);
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
updatedContent = content + phaseEntry;
|
|
272
|
+
}
|
|
273
|
+
node_fs_1.default.writeFileSync(roadmapPath, updatedContent, 'utf-8');
|
|
274
|
+
(0, core_js_1.output)({ phase_number: newPhaseNum, padded: paddedNum, name: description, slug, directory: `.planning/phases/${dirName}` }, raw, paddedNum);
|
|
275
|
+
}
|
|
276
|
+
// ─── Phase insert ───────────────────────────────────────────────────────────
|
|
277
|
+
function cmdPhaseInsert(cwd, afterPhase, description, raw) {
|
|
278
|
+
if (!afterPhase || !description) {
|
|
279
|
+
(0, core_js_1.error)('after-phase and description required for phase insert');
|
|
280
|
+
}
|
|
281
|
+
const roadmapPath = node_path_1.default.join(cwd, '.planning', 'ROADMAP.md');
|
|
282
|
+
if (!node_fs_1.default.existsSync(roadmapPath)) {
|
|
283
|
+
(0, core_js_1.error)('ROADMAP.md not found');
|
|
284
|
+
}
|
|
285
|
+
const content = node_fs_1.default.readFileSync(roadmapPath, 'utf-8');
|
|
286
|
+
const slug = (0, core_js_1.generateSlugInternal)(description);
|
|
287
|
+
const normalizedAfter = (0, core_js_1.normalizePhaseName)(afterPhase);
|
|
288
|
+
const unpadded = normalizedAfter.replace(/^0+/, '');
|
|
289
|
+
const afterPhaseEscaped = '0*' + unpadded.replace(/\./g, '\\.');
|
|
290
|
+
const targetPattern = (0, core_js_1.getPhasePattern)(afterPhaseEscaped, 'i');
|
|
291
|
+
if (!targetPattern.test(content)) {
|
|
292
|
+
(0, core_js_1.error)(`Phase ${afterPhase} not found in ROADMAP.md`);
|
|
293
|
+
}
|
|
294
|
+
const phasesDir = node_path_1.default.join(cwd, '.planning', 'phases');
|
|
295
|
+
const normalizedBase = (0, core_js_1.normalizePhaseName)(afterPhase);
|
|
296
|
+
const existingDecimals = [];
|
|
297
|
+
try {
|
|
298
|
+
const entries = node_fs_1.default.readdirSync(phasesDir, { withFileTypes: true });
|
|
299
|
+
const dirs = entries.filter(e => e.isDirectory()).map(e => e.name);
|
|
300
|
+
const decimalPattern = new RegExp(`^${normalizedBase}\\.(\\d+)`);
|
|
301
|
+
for (const dir of dirs) {
|
|
302
|
+
const dm = dir.match(decimalPattern);
|
|
303
|
+
if (dm)
|
|
304
|
+
existingDecimals.push(parseInt(dm[1], 10));
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
catch (e) {
|
|
308
|
+
/* optional op, ignore */
|
|
309
|
+
if (process.env.MAXSIM_DEBUG)
|
|
310
|
+
console.error(e);
|
|
311
|
+
}
|
|
312
|
+
const nextDecimal = existingDecimals.length === 0 ? 1 : Math.max(...existingDecimals) + 1;
|
|
313
|
+
const decimalPhase = `${normalizedBase}.${nextDecimal}`;
|
|
314
|
+
const dirName = `${decimalPhase}-${slug}`;
|
|
315
|
+
const dirPath = node_path_1.default.join(cwd, '.planning', 'phases', dirName);
|
|
316
|
+
node_fs_1.default.mkdirSync(dirPath, { recursive: true });
|
|
317
|
+
node_fs_1.default.writeFileSync(node_path_1.default.join(dirPath, '.gitkeep'), '');
|
|
318
|
+
const phaseEntry = `\n### Phase ${decimalPhase}: ${description} (INSERTED)\n\n**Goal:** [Urgent work - to be planned]\n**Requirements**: TBD\n**Depends on:** Phase ${afterPhase}\n**Plans:** 0 plans\n\nPlans:\n- [ ] TBD (run /maxsim:plan-phase ${decimalPhase} to break down)\n`;
|
|
319
|
+
const headerPattern = new RegExp(`(#{2,4}\\s*Phase\\s+0*${afterPhaseEscaped}:[^\\n]*\\n)`, 'i');
|
|
320
|
+
const headerMatch = content.match(headerPattern);
|
|
321
|
+
if (!headerMatch) {
|
|
322
|
+
(0, core_js_1.error)(`Could not find Phase ${afterPhase} header`);
|
|
323
|
+
}
|
|
324
|
+
const headerIdx = content.indexOf(headerMatch[0]);
|
|
325
|
+
const afterHeader = content.slice(headerIdx + headerMatch[0].length);
|
|
326
|
+
const nextPhaseMatch = afterHeader.match(/\n#{2,4}\s+Phase\s+\d/i);
|
|
327
|
+
let insertIdx;
|
|
328
|
+
if (nextPhaseMatch) {
|
|
329
|
+
insertIdx = headerIdx + headerMatch[0].length + nextPhaseMatch.index;
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
insertIdx = content.length;
|
|
333
|
+
}
|
|
334
|
+
const updatedContent = content.slice(0, insertIdx) + phaseEntry + content.slice(insertIdx);
|
|
335
|
+
node_fs_1.default.writeFileSync(roadmapPath, updatedContent, 'utf-8');
|
|
336
|
+
(0, core_js_1.output)({ phase_number: decimalPhase, after_phase: afterPhase, name: description, slug, directory: `.planning/phases/${dirName}` }, raw, decimalPhase);
|
|
337
|
+
}
|
|
338
|
+
// ─── Phase remove ───────────────────────────────────────────────────────────
|
|
339
|
+
function cmdPhaseRemove(cwd, targetPhase, options, raw) {
|
|
340
|
+
if (!targetPhase) {
|
|
341
|
+
(0, core_js_1.error)('phase number required for phase remove');
|
|
342
|
+
}
|
|
343
|
+
const roadmapPath = node_path_1.default.join(cwd, '.planning', 'ROADMAP.md');
|
|
344
|
+
const phasesDir = node_path_1.default.join(cwd, '.planning', 'phases');
|
|
345
|
+
const force = options.force || false;
|
|
346
|
+
if (!node_fs_1.default.existsSync(roadmapPath)) {
|
|
347
|
+
(0, core_js_1.error)('ROADMAP.md not found');
|
|
348
|
+
}
|
|
349
|
+
const normalized = (0, core_js_1.normalizePhaseName)(targetPhase);
|
|
350
|
+
const isDecimal = targetPhase.includes('.');
|
|
351
|
+
let targetDir = null;
|
|
352
|
+
try {
|
|
353
|
+
const entries = node_fs_1.default.readdirSync(phasesDir, { withFileTypes: true });
|
|
354
|
+
const dirs = entries.filter(e => e.isDirectory()).map(e => e.name).sort((a, b) => (0, core_js_1.comparePhaseNum)(a, b));
|
|
355
|
+
targetDir = dirs.find(d => d.startsWith(normalized + '-') || d === normalized) || null;
|
|
356
|
+
}
|
|
357
|
+
catch (e) {
|
|
358
|
+
/* optional op, ignore */
|
|
359
|
+
if (process.env.MAXSIM_DEBUG)
|
|
360
|
+
console.error(e);
|
|
361
|
+
}
|
|
362
|
+
if (targetDir && !force) {
|
|
363
|
+
const targetPath = node_path_1.default.join(phasesDir, targetDir);
|
|
364
|
+
const files = node_fs_1.default.readdirSync(targetPath);
|
|
365
|
+
const summaries = files.filter(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md');
|
|
366
|
+
if (summaries.length > 0) {
|
|
367
|
+
(0, core_js_1.error)(`Phase ${targetPhase} has ${summaries.length} executed plan(s). Use --force to remove anyway.`);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
if (targetDir) {
|
|
371
|
+
node_fs_1.default.rmSync(node_path_1.default.join(phasesDir, targetDir), { recursive: true, force: true });
|
|
372
|
+
}
|
|
373
|
+
const renamedDirs = [];
|
|
374
|
+
const renamedFiles = [];
|
|
375
|
+
if (isDecimal) {
|
|
376
|
+
const baseParts = normalized.split('.');
|
|
377
|
+
const baseInt = baseParts[0];
|
|
378
|
+
const removedDecimal = parseInt(baseParts[1], 10);
|
|
379
|
+
try {
|
|
380
|
+
const entries = node_fs_1.default.readdirSync(phasesDir, { withFileTypes: true });
|
|
381
|
+
const dirs = entries.filter(e => e.isDirectory()).map(e => e.name).sort((a, b) => (0, core_js_1.comparePhaseNum)(a, b));
|
|
382
|
+
const decPattern = new RegExp(`^${baseInt}\\.(\\d+)-(.+)$`);
|
|
383
|
+
const toRename = [];
|
|
384
|
+
for (const dir of dirs) {
|
|
385
|
+
const dm = dir.match(decPattern);
|
|
386
|
+
if (dm && parseInt(dm[1], 10) > removedDecimal) {
|
|
387
|
+
toRename.push({ dir, oldDecimal: parseInt(dm[1], 10), slug: dm[2] });
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
toRename.sort((a, b) => b.oldDecimal - a.oldDecimal);
|
|
391
|
+
for (const item of toRename) {
|
|
392
|
+
const newDecimal = item.oldDecimal - 1;
|
|
393
|
+
const oldPhaseId = `${baseInt}.${item.oldDecimal}`;
|
|
394
|
+
const newPhaseId = `${baseInt}.${newDecimal}`;
|
|
395
|
+
const newDirName = `${baseInt}.${newDecimal}-${item.slug}`;
|
|
396
|
+
node_fs_1.default.renameSync(node_path_1.default.join(phasesDir, item.dir), node_path_1.default.join(phasesDir, newDirName));
|
|
397
|
+
renamedDirs.push({ from: item.dir, to: newDirName });
|
|
398
|
+
const dirFiles = node_fs_1.default.readdirSync(node_path_1.default.join(phasesDir, newDirName));
|
|
399
|
+
for (const f of dirFiles) {
|
|
400
|
+
if (f.includes(oldPhaseId)) {
|
|
401
|
+
const newFileName = f.replace(oldPhaseId, newPhaseId);
|
|
402
|
+
node_fs_1.default.renameSync(node_path_1.default.join(phasesDir, newDirName, f), node_path_1.default.join(phasesDir, newDirName, newFileName));
|
|
403
|
+
renamedFiles.push({ from: f, to: newFileName });
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
catch (e) {
|
|
409
|
+
/* optional op, ignore */
|
|
410
|
+
if (process.env.MAXSIM_DEBUG)
|
|
411
|
+
console.error(e);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
const removedInt = parseInt(normalized, 10);
|
|
416
|
+
try {
|
|
417
|
+
const entries = node_fs_1.default.readdirSync(phasesDir, { withFileTypes: true });
|
|
418
|
+
const dirs = entries.filter(e => e.isDirectory()).map(e => e.name).sort((a, b) => (0, core_js_1.comparePhaseNum)(a, b));
|
|
419
|
+
const toRename = [];
|
|
420
|
+
for (const dir of dirs) {
|
|
421
|
+
const dm = dir.match(/^(\d+)([A-Z])?(?:\.(\d+))?-(.+)$/i);
|
|
422
|
+
if (!dm)
|
|
423
|
+
continue;
|
|
424
|
+
const dirInt = parseInt(dm[1], 10);
|
|
425
|
+
if (dirInt > removedInt) {
|
|
426
|
+
toRename.push({
|
|
427
|
+
dir,
|
|
428
|
+
oldInt: dirInt,
|
|
429
|
+
letter: dm[2] ? dm[2].toUpperCase() : '',
|
|
430
|
+
decimal: dm[3] ? parseInt(dm[3], 10) : null,
|
|
431
|
+
slug: dm[4],
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
toRename.sort((a, b) => {
|
|
436
|
+
if (a.oldInt !== b.oldInt)
|
|
437
|
+
return b.oldInt - a.oldInt;
|
|
438
|
+
return (b.decimal || 0) - (a.decimal || 0);
|
|
439
|
+
});
|
|
440
|
+
for (const item of toRename) {
|
|
441
|
+
const newInt = item.oldInt - 1;
|
|
442
|
+
const newPadded = String(newInt).padStart(2, '0');
|
|
443
|
+
const oldPadded = String(item.oldInt).padStart(2, '0');
|
|
444
|
+
const letterSuffix = item.letter || '';
|
|
445
|
+
const decimalSuffix = item.decimal !== null ? `.${item.decimal}` : '';
|
|
446
|
+
const oldPrefix = `${oldPadded}${letterSuffix}${decimalSuffix}`;
|
|
447
|
+
const newPrefix = `${newPadded}${letterSuffix}${decimalSuffix}`;
|
|
448
|
+
const newDirName = `${newPrefix}-${item.slug}`;
|
|
449
|
+
node_fs_1.default.renameSync(node_path_1.default.join(phasesDir, item.dir), node_path_1.default.join(phasesDir, newDirName));
|
|
450
|
+
renamedDirs.push({ from: item.dir, to: newDirName });
|
|
451
|
+
const dirFiles = node_fs_1.default.readdirSync(node_path_1.default.join(phasesDir, newDirName));
|
|
452
|
+
for (const f of dirFiles) {
|
|
453
|
+
if (f.startsWith(oldPrefix)) {
|
|
454
|
+
const newFileName = newPrefix + f.slice(oldPrefix.length);
|
|
455
|
+
node_fs_1.default.renameSync(node_path_1.default.join(phasesDir, newDirName, f), node_path_1.default.join(phasesDir, newDirName, newFileName));
|
|
456
|
+
renamedFiles.push({ from: f, to: newFileName });
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
catch (e) {
|
|
462
|
+
/* optional op, ignore */
|
|
463
|
+
if (process.env.MAXSIM_DEBUG)
|
|
464
|
+
console.error(e);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
// Update ROADMAP.md
|
|
468
|
+
let roadmapContent = node_fs_1.default.readFileSync(roadmapPath, 'utf-8');
|
|
469
|
+
const targetEscaped = targetPhase.replace(/\./g, '\\.');
|
|
470
|
+
const sectionPattern = new RegExp(`\\n?#{2,4}\\s*Phase\\s+${targetEscaped}\\s*:[\\s\\S]*?(?=\\n#{2,4}\\s+Phase\\s+\\d|$)`, 'i');
|
|
471
|
+
roadmapContent = roadmapContent.replace(sectionPattern, '');
|
|
472
|
+
const checkboxPattern = new RegExp(`\\n?-\\s*\\[[ x]\\]\\s*.*Phase\\s+${targetEscaped}[:\\s][^\\n]*`, 'gi');
|
|
473
|
+
roadmapContent = roadmapContent.replace(checkboxPattern, '');
|
|
474
|
+
const tableRowPattern = new RegExp(`\\n?\\|\\s*${targetEscaped}\\.?\\s[^|]*\\|[^\\n]*`, 'gi');
|
|
475
|
+
roadmapContent = roadmapContent.replace(tableRowPattern, '');
|
|
476
|
+
if (!isDecimal) {
|
|
477
|
+
const removedInt = parseInt(normalized, 10);
|
|
478
|
+
const maxPhase = 99;
|
|
479
|
+
for (let oldNum = maxPhase; oldNum > removedInt; oldNum--) {
|
|
480
|
+
const newNum = oldNum - 1;
|
|
481
|
+
const oldStr = String(oldNum);
|
|
482
|
+
const newStr = String(newNum);
|
|
483
|
+
const oldPad = oldStr.padStart(2, '0');
|
|
484
|
+
const newPad = newStr.padStart(2, '0');
|
|
485
|
+
roadmapContent = roadmapContent.replace(new RegExp(`(#{2,4}\\s*Phase\\s+)${oldStr}(\\s*:)`, 'gi'), `$1${newStr}$2`);
|
|
486
|
+
roadmapContent = roadmapContent.replace(new RegExp(`(Phase\\s+)${oldStr}([:\\s])`, 'g'), `$1${newStr}$2`);
|
|
487
|
+
roadmapContent = roadmapContent.replace(new RegExp(`${oldPad}-(\\d{2})`, 'g'), `${newPad}-$1`);
|
|
488
|
+
roadmapContent = roadmapContent.replace(new RegExp(`(\\|\\s*)${oldStr}\\.\\s`, 'g'), `$1${newStr}. `);
|
|
489
|
+
roadmapContent = roadmapContent.replace(new RegExp(`(Depends on:\\*\\*\\s*Phase\\s+)${oldStr}\\b`, 'gi'), `$1${newStr}`);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
node_fs_1.default.writeFileSync(roadmapPath, roadmapContent, 'utf-8');
|
|
493
|
+
// Update STATE.md phase count
|
|
494
|
+
const statePath = node_path_1.default.join(cwd, '.planning', 'STATE.md');
|
|
495
|
+
if (node_fs_1.default.existsSync(statePath)) {
|
|
496
|
+
let stateContent = node_fs_1.default.readFileSync(statePath, 'utf-8');
|
|
497
|
+
const totalPattern = /(\*\*Total Phases:\*\*\s*)(\d+)/;
|
|
498
|
+
const totalMatch = stateContent.match(totalPattern);
|
|
499
|
+
if (totalMatch) {
|
|
500
|
+
const oldTotal = parseInt(totalMatch[2], 10);
|
|
501
|
+
stateContent = stateContent.replace(totalPattern, `$1${oldTotal - 1}`);
|
|
502
|
+
}
|
|
503
|
+
const ofPattern = /(\bof\s+)(\d+)(\s*(?:\(|phases?))/i;
|
|
504
|
+
const ofMatch = stateContent.match(ofPattern);
|
|
505
|
+
if (ofMatch) {
|
|
506
|
+
const oldTotal = parseInt(ofMatch[2], 10);
|
|
507
|
+
stateContent = stateContent.replace(ofPattern, `$1${oldTotal - 1}$3`);
|
|
508
|
+
}
|
|
509
|
+
node_fs_1.default.writeFileSync(statePath, stateContent, 'utf-8');
|
|
510
|
+
}
|
|
511
|
+
(0, core_js_1.output)({
|
|
512
|
+
removed: targetPhase,
|
|
513
|
+
directory_deleted: targetDir || null,
|
|
514
|
+
renamed_directories: renamedDirs,
|
|
515
|
+
renamed_files: renamedFiles,
|
|
516
|
+
roadmap_updated: true,
|
|
517
|
+
state_updated: node_fs_1.default.existsSync(statePath),
|
|
518
|
+
}, raw);
|
|
519
|
+
}
|
|
520
|
+
// ─── Phase complete ─────────────────────────────────────────────────────────
|
|
521
|
+
function cmdPhaseComplete(cwd, phaseNum, raw) {
|
|
522
|
+
if (!phaseNum) {
|
|
523
|
+
(0, core_js_1.error)('phase number required for phase complete');
|
|
524
|
+
}
|
|
525
|
+
const roadmapPath = node_path_1.default.join(cwd, '.planning', 'ROADMAP.md');
|
|
526
|
+
const statePath = node_path_1.default.join(cwd, '.planning', 'STATE.md');
|
|
527
|
+
const phasesDir = node_path_1.default.join(cwd, '.planning', 'phases');
|
|
528
|
+
const normalized = (0, core_js_1.normalizePhaseName)(phaseNum);
|
|
529
|
+
const today = new Date().toISOString().split('T')[0];
|
|
530
|
+
const phaseInfo = (0, core_js_1.findPhaseInternal)(cwd, phaseNum);
|
|
531
|
+
if (!phaseInfo) {
|
|
532
|
+
(0, core_js_1.error)(`Phase ${phaseNum} not found`);
|
|
533
|
+
}
|
|
534
|
+
const planCount = phaseInfo.plans.length;
|
|
535
|
+
const summaryCount = phaseInfo.summaries.length;
|
|
536
|
+
if (node_fs_1.default.existsSync(roadmapPath)) {
|
|
537
|
+
let roadmapContent = node_fs_1.default.readFileSync(roadmapPath, 'utf-8');
|
|
538
|
+
const checkboxPattern = new RegExp(`(-\\s*\\[)[ ](\\]\\s*.*Phase\\s+${phaseNum.replace('.', '\\.')}[:\\s][^\\n]*)`, 'i');
|
|
539
|
+
roadmapContent = roadmapContent.replace(checkboxPattern, `$1x$2 (completed ${today})`);
|
|
540
|
+
const phaseEscaped = phaseNum.replace('.', '\\.');
|
|
541
|
+
const tablePattern = new RegExp(`(\\|\\s*${phaseEscaped}\\.?\\s[^|]*\\|[^|]*\\|)\\s*[^|]*(\\|)\\s*[^|]*(\\|)`, 'i');
|
|
542
|
+
roadmapContent = roadmapContent.replace(tablePattern, `$1 Complete $2 ${today} $3`);
|
|
543
|
+
const planCountPattern = new RegExp(`(#{2,4}\\s*Phase\\s+${phaseEscaped}[\\s\\S]*?\\*\\*Plans:\\*\\*\\s*)[^\\n]+`, 'i');
|
|
544
|
+
roadmapContent = roadmapContent.replace(planCountPattern, `$1${summaryCount}/${planCount} plans complete`);
|
|
545
|
+
node_fs_1.default.writeFileSync(roadmapPath, roadmapContent, 'utf-8');
|
|
546
|
+
// Update REQUIREMENTS.md
|
|
547
|
+
const reqPath = node_path_1.default.join(cwd, '.planning', 'REQUIREMENTS.md');
|
|
548
|
+
if (node_fs_1.default.existsSync(reqPath)) {
|
|
549
|
+
const reqMatch = roadmapContent.match(new RegExp(`Phase\\s+${phaseNum.replace('.', '\\.')}[\\s\\S]*?\\*\\*Requirements:\\*\\*\\s*([^\\n]+)`, 'i'));
|
|
550
|
+
if (reqMatch) {
|
|
551
|
+
const reqIds = reqMatch[1].replace(/[\[\]]/g, '').split(/[,\s]+/).map(r => r.trim()).filter(Boolean);
|
|
552
|
+
let reqContent = node_fs_1.default.readFileSync(reqPath, 'utf-8');
|
|
553
|
+
for (const reqId of reqIds) {
|
|
554
|
+
reqContent = reqContent.replace(new RegExp(`(-\\s*\\[)[ ](\\]\\s*\\*\\*${reqId}\\*\\*)`, 'gi'), '$1x$2');
|
|
555
|
+
reqContent = reqContent.replace(new RegExp(`(\\|\\s*${reqId}\\s*\\|[^|]+\\|)\\s*Pending\\s*(\\|)`, 'gi'), '$1 Complete $2');
|
|
556
|
+
}
|
|
557
|
+
node_fs_1.default.writeFileSync(reqPath, reqContent, 'utf-8');
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
// Find next phase
|
|
562
|
+
let nextPhaseNum = null;
|
|
563
|
+
let nextPhaseName = null;
|
|
564
|
+
let isLastPhase = true;
|
|
565
|
+
try {
|
|
566
|
+
const entries = node_fs_1.default.readdirSync(phasesDir, { withFileTypes: true });
|
|
567
|
+
const dirs = entries.filter(e => e.isDirectory()).map(e => e.name).sort((a, b) => (0, core_js_1.comparePhaseNum)(a, b));
|
|
568
|
+
for (const dir of dirs) {
|
|
569
|
+
const dm = dir.match(/^(\d+[A-Z]?(?:\.\d+)?)-?(.*)/i);
|
|
570
|
+
if (dm) {
|
|
571
|
+
if ((0, core_js_1.comparePhaseNum)(dm[1], phaseNum) > 0) {
|
|
572
|
+
nextPhaseNum = dm[1];
|
|
573
|
+
nextPhaseName = dm[2] || null;
|
|
574
|
+
isLastPhase = false;
|
|
575
|
+
break;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
catch (e) {
|
|
581
|
+
/* optional op, ignore */
|
|
582
|
+
if (process.env.MAXSIM_DEBUG)
|
|
583
|
+
console.error(e);
|
|
584
|
+
}
|
|
585
|
+
// Update STATE.md
|
|
586
|
+
if (node_fs_1.default.existsSync(statePath)) {
|
|
587
|
+
let stateContent = node_fs_1.default.readFileSync(statePath, 'utf-8');
|
|
588
|
+
stateContent = stateContent.replace(/(\*\*Current Phase:\*\*\s*).*/, `$1${nextPhaseNum || phaseNum}`);
|
|
589
|
+
if (nextPhaseName) {
|
|
590
|
+
stateContent = stateContent.replace(/(\*\*Current Phase Name:\*\*\s*).*/, `$1${nextPhaseName.replace(/-/g, ' ')}`);
|
|
591
|
+
}
|
|
592
|
+
stateContent = stateContent.replace(/(\*\*Status:\*\*\s*).*/, `$1${isLastPhase ? 'Milestone complete' : 'Ready to plan'}`);
|
|
593
|
+
stateContent = stateContent.replace(/(\*\*Current Plan:\*\*\s*).*/, `$1Not started`);
|
|
594
|
+
stateContent = stateContent.replace(/(\*\*Last Activity:\*\*\s*).*/, `$1${today}`);
|
|
595
|
+
stateContent = stateContent.replace(/(\*\*Last Activity Description:\*\*\s*).*/, `$1Phase ${phaseNum} complete${nextPhaseNum ? `, transitioned to Phase ${nextPhaseNum}` : ''}`);
|
|
596
|
+
node_fs_1.default.writeFileSync(statePath, stateContent, 'utf-8');
|
|
597
|
+
}
|
|
598
|
+
(0, core_js_1.output)({
|
|
599
|
+
completed_phase: phaseNum,
|
|
600
|
+
phase_name: phaseInfo.phase_name,
|
|
601
|
+
plans_executed: `${summaryCount}/${planCount}`,
|
|
602
|
+
next_phase: nextPhaseNum,
|
|
603
|
+
next_phase_name: nextPhaseName,
|
|
604
|
+
is_last_phase: isLastPhase,
|
|
605
|
+
date: today,
|
|
606
|
+
roadmap_updated: node_fs_1.default.existsSync(roadmapPath),
|
|
607
|
+
state_updated: node_fs_1.default.existsSync(statePath),
|
|
608
|
+
}, raw);
|
|
609
|
+
}
|
|
610
|
+
//# sourceMappingURL=phase.js.map
|