maxsimcli 4.6.0 → 4.7.1

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.
Files changed (234) hide show
  1. package/dist/assets/CHANGELOG.md +39 -0
  2. package/dist/cli.cjs +470 -961
  3. package/dist/cli.cjs.map +1 -1
  4. package/dist/{core-RRjCSt0G.cjs → core-D5zUr9cb.cjs} +4 -3
  5. package/dist/core-D5zUr9cb.cjs.map +1 -0
  6. package/dist/install.cjs +3 -195
  7. package/dist/install.cjs.map +1 -1
  8. package/dist/mcp-server.cjs +2853 -217
  9. package/dist/mcp-server.cjs.map +1 -1
  10. package/dist/{skills-MYlMkYNt.cjs → skills-CjFWZIGM.cjs} +6 -6
  11. package/dist/{skills-MYlMkYNt.cjs.map → skills-CjFWZIGM.cjs.map} +1 -1
  12. package/package.json +1 -7
  13. package/dist/.tsbuildinfo +0 -1
  14. package/dist/assets/dashboard/client/assets/index-C199D4Eb.css +0 -32
  15. package/dist/assets/dashboard/client/assets/index-nAXJLp0_.js +0 -233
  16. package/dist/assets/dashboard/client/index.html +0 -19
  17. package/dist/assets/dashboard/server.js +0 -78813
  18. package/dist/backend/index.d.ts +0 -4
  19. package/dist/backend/index.d.ts.map +0 -1
  20. package/dist/backend/index.js +0 -12
  21. package/dist/backend/index.js.map +0 -1
  22. package/dist/backend/lifecycle.d.ts +0 -13
  23. package/dist/backend/lifecycle.d.ts.map +0 -1
  24. package/dist/backend/lifecycle.js +0 -168
  25. package/dist/backend/lifecycle.js.map +0 -1
  26. package/dist/backend/server.d.ts +0 -13
  27. package/dist/backend/server.d.ts.map +0 -1
  28. package/dist/backend/server.js +0 -1013
  29. package/dist/backend/server.js.map +0 -1
  30. package/dist/backend/terminal.d.ts +0 -49
  31. package/dist/backend/terminal.d.ts.map +0 -1
  32. package/dist/backend/terminal.js +0 -209
  33. package/dist/backend/terminal.js.map +0 -1
  34. package/dist/backend/types.d.ts +0 -77
  35. package/dist/backend/types.d.ts.map +0 -1
  36. package/dist/backend/types.js +0 -6
  37. package/dist/backend/types.js.map +0 -1
  38. package/dist/backend-server.cjs +0 -80672
  39. package/dist/backend-server.cjs.map +0 -1
  40. package/dist/backend-server.d.cts +0 -2
  41. package/dist/backend-server.d.ts +0 -11
  42. package/dist/backend-server.d.ts.map +0 -1
  43. package/dist/backend-server.js +0 -43
  44. package/dist/backend-server.js.map +0 -1
  45. package/dist/cli.d.cts +0 -2
  46. package/dist/cli.d.ts +0 -7
  47. package/dist/cli.d.ts.map +0 -1
  48. package/dist/cli.js +0 -510
  49. package/dist/cli.js.map +0 -1
  50. package/dist/core/artefakte.d.ts +0 -12
  51. package/dist/core/artefakte.d.ts.map +0 -1
  52. package/dist/core/artefakte.js +0 -152
  53. package/dist/core/artefakte.js.map +0 -1
  54. package/dist/core/commands.d.ts +0 -26
  55. package/dist/core/commands.d.ts.map +0 -1
  56. package/dist/core/commands.js +0 -550
  57. package/dist/core/commands.js.map +0 -1
  58. package/dist/core/config.d.ts +0 -10
  59. package/dist/core/config.d.ts.map +0 -1
  60. package/dist/core/config.js +0 -143
  61. package/dist/core/config.js.map +0 -1
  62. package/dist/core/context-loader.d.ts +0 -21
  63. package/dist/core/context-loader.d.ts.map +0 -1
  64. package/dist/core/context-loader.js +0 -212
  65. package/dist/core/context-loader.js.map +0 -1
  66. package/dist/core/core.d.ts +0 -91
  67. package/dist/core/core.d.ts.map +0 -1
  68. package/dist/core/core.js +0 -823
  69. package/dist/core/core.js.map +0 -1
  70. package/dist/core/dashboard-launcher.d.ts +0 -56
  71. package/dist/core/dashboard-launcher.d.ts.map +0 -1
  72. package/dist/core/dashboard-launcher.js +0 -246
  73. package/dist/core/dashboard-launcher.js.map +0 -1
  74. package/dist/core/drift.d.ts +0 -37
  75. package/dist/core/drift.d.ts.map +0 -1
  76. package/dist/core/drift.js +0 -213
  77. package/dist/core/drift.js.map +0 -1
  78. package/dist/core/frontmatter.d.ts +0 -33
  79. package/dist/core/frontmatter.d.ts.map +0 -1
  80. package/dist/core/frontmatter.js +0 -193
  81. package/dist/core/frontmatter.js.map +0 -1
  82. package/dist/core/index.d.ts +0 -28
  83. package/dist/core/index.d.ts.map +0 -1
  84. package/dist/core/index.js +0 -189
  85. package/dist/core/index.js.map +0 -1
  86. package/dist/core/init.d.ts +0 -287
  87. package/dist/core/init.d.ts.map +0 -1
  88. package/dist/core/init.js +0 -816
  89. package/dist/core/init.js.map +0 -1
  90. package/dist/core/milestone.d.ts +0 -9
  91. package/dist/core/milestone.d.ts.map +0 -1
  92. package/dist/core/milestone.js +0 -230
  93. package/dist/core/milestone.js.map +0 -1
  94. package/dist/core/phase.d.ts +0 -53
  95. package/dist/core/phase.d.ts.map +0 -1
  96. package/dist/core/phase.js +0 -891
  97. package/dist/core/phase.js.map +0 -1
  98. package/dist/core/roadmap.d.ts +0 -10
  99. package/dist/core/roadmap.d.ts.map +0 -1
  100. package/dist/core/roadmap.js +0 -165
  101. package/dist/core/roadmap.js.map +0 -1
  102. package/dist/core/skills.d.ts +0 -20
  103. package/dist/core/skills.d.ts.map +0 -1
  104. package/dist/core/skills.js +0 -144
  105. package/dist/core/skills.js.map +0 -1
  106. package/dist/core/start.d.ts +0 -15
  107. package/dist/core/start.d.ts.map +0 -1
  108. package/dist/core/start.js +0 -80
  109. package/dist/core/start.js.map +0 -1
  110. package/dist/core/state.d.ts +0 -32
  111. package/dist/core/state.d.ts.map +0 -1
  112. package/dist/core/state.js +0 -582
  113. package/dist/core/state.js.map +0 -1
  114. package/dist/core/template.d.ts +0 -30
  115. package/dist/core/template.d.ts.map +0 -1
  116. package/dist/core/template.js +0 -223
  117. package/dist/core/template.js.map +0 -1
  118. package/dist/core/types.d.ts +0 -519
  119. package/dist/core/types.d.ts.map +0 -1
  120. package/dist/core/types.js +0 -60
  121. package/dist/core/types.js.map +0 -1
  122. package/dist/core/verify.d.ts +0 -128
  123. package/dist/core/verify.d.ts.map +0 -1
  124. package/dist/core/verify.js +0 -754
  125. package/dist/core/verify.js.map +0 -1
  126. package/dist/core-RRjCSt0G.cjs.map +0 -1
  127. package/dist/esm-iIOBzmdz.cjs +0 -1561
  128. package/dist/esm-iIOBzmdz.cjs.map +0 -1
  129. package/dist/hooks/index.d.ts +0 -11
  130. package/dist/hooks/index.d.ts.map +0 -1
  131. package/dist/hooks/index.js +0 -18
  132. package/dist/hooks/index.js.map +0 -1
  133. package/dist/hooks/maxsim-check-update.d.ts +0 -17
  134. package/dist/hooks/maxsim-check-update.d.ts.map +0 -1
  135. package/dist/hooks/maxsim-check-update.js +0 -101
  136. package/dist/hooks/maxsim-check-update.js.map +0 -1
  137. package/dist/hooks/maxsim-context-monitor.d.ts +0 -21
  138. package/dist/hooks/maxsim-context-monitor.d.ts.map +0 -1
  139. package/dist/hooks/maxsim-context-monitor.js +0 -131
  140. package/dist/hooks/maxsim-context-monitor.js.map +0 -1
  141. package/dist/hooks/maxsim-statusline.d.ts +0 -19
  142. package/dist/hooks/maxsim-statusline.d.ts.map +0 -1
  143. package/dist/hooks/maxsim-statusline.js +0 -146
  144. package/dist/hooks/maxsim-statusline.js.map +0 -1
  145. package/dist/hooks/shared.d.ts +0 -11
  146. package/dist/hooks/shared.d.ts.map +0 -1
  147. package/dist/hooks/shared.js +0 -29
  148. package/dist/hooks/shared.js.map +0 -1
  149. package/dist/index.d.ts +0 -2
  150. package/dist/index.d.ts.map +0 -1
  151. package/dist/index.js +0 -3
  152. package/dist/index.js.map +0 -1
  153. package/dist/install/adapters.d.ts +0 -6
  154. package/dist/install/adapters.d.ts.map +0 -1
  155. package/dist/install/adapters.js +0 -65
  156. package/dist/install/adapters.js.map +0 -1
  157. package/dist/install/copy.d.ts +0 -6
  158. package/dist/install/copy.d.ts.map +0 -1
  159. package/dist/install/copy.js +0 -71
  160. package/dist/install/copy.js.map +0 -1
  161. package/dist/install/dashboard.d.ts +0 -16
  162. package/dist/install/dashboard.d.ts.map +0 -1
  163. package/dist/install/dashboard.js +0 -273
  164. package/dist/install/dashboard.js.map +0 -1
  165. package/dist/install/hooks.d.ts +0 -31
  166. package/dist/install/hooks.d.ts.map +0 -1
  167. package/dist/install/hooks.js +0 -260
  168. package/dist/install/hooks.js.map +0 -1
  169. package/dist/install/index.d.ts +0 -2
  170. package/dist/install/index.d.ts.map +0 -1
  171. package/dist/install/index.js +0 -534
  172. package/dist/install/index.js.map +0 -1
  173. package/dist/install/manifest.d.ts +0 -23
  174. package/dist/install/manifest.d.ts.map +0 -1
  175. package/dist/install/manifest.js +0 -133
  176. package/dist/install/manifest.js.map +0 -1
  177. package/dist/install/patches.d.ts +0 -10
  178. package/dist/install/patches.d.ts.map +0 -1
  179. package/dist/install/patches.js +0 -124
  180. package/dist/install/patches.js.map +0 -1
  181. package/dist/install/shared.d.ts +0 -56
  182. package/dist/install/shared.d.ts.map +0 -1
  183. package/dist/install/shared.js +0 -181
  184. package/dist/install/shared.js.map +0 -1
  185. package/dist/install/uninstall.d.ts +0 -5
  186. package/dist/install/uninstall.d.ts.map +0 -1
  187. package/dist/install/uninstall.js +0 -222
  188. package/dist/install/uninstall.js.map +0 -1
  189. package/dist/install/utils.d.ts +0 -27
  190. package/dist/install/utils.d.ts.map +0 -1
  191. package/dist/install/utils.js +0 -99
  192. package/dist/install/utils.js.map +0 -1
  193. package/dist/install.d.cts +0 -2
  194. package/dist/lifecycle-DxCru7rk.cjs +0 -136
  195. package/dist/lifecycle-DxCru7rk.cjs.map +0 -1
  196. package/dist/mcp/config-tools.d.ts +0 -13
  197. package/dist/mcp/config-tools.d.ts.map +0 -1
  198. package/dist/mcp/config-tools.js +0 -66
  199. package/dist/mcp/config-tools.js.map +0 -1
  200. package/dist/mcp/context-tools.d.ts +0 -13
  201. package/dist/mcp/context-tools.d.ts.map +0 -1
  202. package/dist/mcp/context-tools.js +0 -176
  203. package/dist/mcp/context-tools.js.map +0 -1
  204. package/dist/mcp/index.d.ts +0 -11
  205. package/dist/mcp/index.d.ts.map +0 -1
  206. package/dist/mcp/index.js +0 -26
  207. package/dist/mcp/index.js.map +0 -1
  208. package/dist/mcp/phase-tools.d.ts +0 -13
  209. package/dist/mcp/phase-tools.d.ts.map +0 -1
  210. package/dist/mcp/phase-tools.js +0 -177
  211. package/dist/mcp/phase-tools.js.map +0 -1
  212. package/dist/mcp/roadmap-tools.d.ts +0 -13
  213. package/dist/mcp/roadmap-tools.d.ts.map +0 -1
  214. package/dist/mcp/roadmap-tools.js +0 -79
  215. package/dist/mcp/roadmap-tools.js.map +0 -1
  216. package/dist/mcp/state-tools.d.ts +0 -13
  217. package/dist/mcp/state-tools.d.ts.map +0 -1
  218. package/dist/mcp/state-tools.js +0 -185
  219. package/dist/mcp/state-tools.js.map +0 -1
  220. package/dist/mcp/todo-tools.d.ts +0 -13
  221. package/dist/mcp/todo-tools.d.ts.map +0 -1
  222. package/dist/mcp/todo-tools.js +0 -143
  223. package/dist/mcp/todo-tools.js.map +0 -1
  224. package/dist/mcp/utils.d.ts +0 -27
  225. package/dist/mcp/utils.d.ts.map +0 -1
  226. package/dist/mcp/utils.js +0 -82
  227. package/dist/mcp/utils.js.map +0 -1
  228. package/dist/mcp-server.d.cts +0 -2
  229. package/dist/mcp-server.d.ts +0 -12
  230. package/dist/mcp-server.d.ts.map +0 -1
  231. package/dist/mcp-server.js +0 -31
  232. package/dist/mcp-server.js.map +0 -1
  233. package/dist/server-By0TN-nC.cjs +0 -2995
  234. package/dist/server-By0TN-nC.cjs.map +0 -1
package/dist/core/core.js DELETED
@@ -1,823 +0,0 @@
1
- "use strict";
2
- /**
3
- * Core — Shared utilities, constants, and internal helpers
4
- *
5
- * Ported from maxsim/bin/lib/core.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.summaryId = exports.planId = exports.isSummaryFile = exports.isPlanFile = exports.CliError = exports.CliOutput = exports.MODEL_PROFILES = void 0;
12
- exports.output = output;
13
- exports.error = error;
14
- exports.rethrowCliSignals = rethrowCliSignals;
15
- exports.writeOutput = writeOutput;
16
- exports.todayISO = todayISO;
17
- exports.planningPath = planningPath;
18
- exports.statePath = statePath;
19
- exports.roadmapPath = roadmapPath;
20
- exports.configPath = configPath;
21
- exports.phasesPath = phasesPath;
22
- exports.listSubDirs = listSubDirs;
23
- exports.listSubDirsAsync = listSubDirsAsync;
24
- exports.safeReadFileAsync = safeReadFileAsync;
25
- exports.errorMsg = errorMsg;
26
- exports.debugLog = debugLog;
27
- exports.escapePhaseNum = escapePhaseNum;
28
- exports.safeReadFile = safeReadFile;
29
- exports.loadConfig = loadConfig;
30
- exports.isGitIgnored = isGitIgnored;
31
- exports.execGit = execGit;
32
- exports.normalizePhaseName = normalizePhaseName;
33
- exports.comparePhaseNum = comparePhaseNum;
34
- exports.getPhasePattern = getPhasePattern;
35
- exports.findPhaseInternal = findPhaseInternal;
36
- exports.getArchivedPhaseDirs = getArchivedPhaseDirs;
37
- exports.getRoadmapPhaseInternal = getRoadmapPhaseInternal;
38
- exports.resolveModelInternal = resolveModelInternal;
39
- exports.pathExistsInternal = pathExistsInternal;
40
- exports.generateSlugInternal = generateSlugInternal;
41
- exports.getMilestoneInfo = getMilestoneInfo;
42
- exports.pathExistsAsync = pathExistsAsync;
43
- exports.loadConfigAsync = loadConfigAsync;
44
- exports.findPhaseInternalAsync = findPhaseInternalAsync;
45
- exports.getArchivedPhaseDirsAsync = getArchivedPhaseDirsAsync;
46
- exports.getRoadmapPhaseInternalAsync = getRoadmapPhaseInternalAsync;
47
- exports.archivePath = archivePath;
48
- exports.archivePathAsync = archivePathAsync;
49
- exports.getMilestoneInfoAsync = getMilestoneInfoAsync;
50
- const node_fs_1 = __importDefault(require("node:fs"));
51
- const node_fs_2 = require("node:fs");
52
- const node_path_1 = __importDefault(require("node:path"));
53
- const node_os_1 = __importDefault(require("node:os"));
54
- const simple_git_1 = require("simple-git");
55
- const slugify_1 = __importDefault(require("slugify"));
56
- // ─── Model Profile Table ─────────────────────────────────────────────────────
57
- exports.MODEL_PROFILES = {
58
- 'maxsim-planner': { quality: 'opus', balanced: 'opus', budget: 'sonnet', tokenburner: 'opus' },
59
- 'maxsim-roadmapper': { quality: 'opus', balanced: 'sonnet', budget: 'sonnet', tokenburner: 'opus' },
60
- 'maxsim-executor': { quality: 'opus', balanced: 'sonnet', budget: 'sonnet', tokenburner: 'opus' },
61
- 'maxsim-phase-researcher': { quality: 'opus', balanced: 'sonnet', budget: 'haiku', tokenburner: 'opus' },
62
- 'maxsim-project-researcher': { quality: 'opus', balanced: 'sonnet', budget: 'haiku', tokenburner: 'opus' },
63
- 'maxsim-research-synthesizer': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku', tokenburner: 'opus' },
64
- 'maxsim-debugger': { quality: 'opus', balanced: 'sonnet', budget: 'sonnet', tokenburner: 'opus' },
65
- 'maxsim-codebase-mapper': { quality: 'sonnet', balanced: 'haiku', budget: 'haiku', tokenburner: 'opus' },
66
- 'maxsim-verifier': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku', tokenburner: 'opus' },
67
- 'maxsim-plan-checker': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku', tokenburner: 'opus' },
68
- 'maxsim-integration-checker': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku', tokenburner: 'opus' },
69
- 'maxsim-drift-checker': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku', tokenburner: 'opus' },
70
- };
71
- // ─── Output helpers ──────────────────────────────────────────────────────────
72
- // These throw CliOutput / CliError instead of calling process.exit() directly.
73
- // The CLI entry point (cli.ts) catches these and calls process.exit() there.
74
- /** Thrown by output() to signal successful command completion. */
75
- class CliOutput {
76
- result;
77
- raw;
78
- rawValue;
79
- constructor(result, raw, rawValue) {
80
- this.result = result;
81
- this.raw = raw ?? false;
82
- this.rawValue = rawValue;
83
- }
84
- }
85
- exports.CliOutput = CliOutput;
86
- /** Thrown by error() to signal a command error. */
87
- class CliError {
88
- message;
89
- constructor(message) {
90
- this.message = message;
91
- }
92
- }
93
- exports.CliError = CliError;
94
- function output(result, raw, rawValue) {
95
- throw new CliOutput(result, raw, rawValue);
96
- }
97
- function error(message) {
98
- throw new CliError(message);
99
- }
100
- /** Re-throw CliOutput/CliError signals so catch blocks don't intercept them */
101
- function rethrowCliSignals(e) {
102
- if (e instanceof CliOutput || e instanceof CliError)
103
- throw e;
104
- }
105
- /**
106
- * Handle a CliOutput by writing to stdout. Extracted so cli.ts can use it.
107
- */
108
- function writeOutput(out) {
109
- if (out.raw && out.rawValue !== undefined) {
110
- process.stdout.write(String(out.rawValue));
111
- }
112
- else {
113
- const json = JSON.stringify(out.result, null, 2);
114
- if (json.length > 50000) {
115
- const tmpPath = node_path_1.default.join(node_os_1.default.tmpdir(), `maxsim-${Date.now()}.json`);
116
- node_fs_1.default.writeFileSync(tmpPath, json, 'utf-8');
117
- process.stdout.write('@file:' + tmpPath);
118
- }
119
- else {
120
- process.stdout.write(json);
121
- }
122
- }
123
- }
124
- // ─── Shared micro-utilities ─────────────────────────────────────────────────
125
- /** Today's date as YYYY-MM-DD. */
126
- function todayISO() {
127
- return new Date().toISOString().split('T')[0];
128
- }
129
- /** Canonical .planning/ sub-paths. */
130
- function planningPath(cwd, ...segments) {
131
- return node_path_1.default.join(cwd, '.planning', ...segments);
132
- }
133
- function statePath(cwd) { return planningPath(cwd, 'STATE.md'); }
134
- function roadmapPath(cwd) { return planningPath(cwd, 'ROADMAP.md'); }
135
- function configPath(cwd) { return planningPath(cwd, 'config.json'); }
136
- function phasesPath(cwd) { return planningPath(cwd, 'phases'); }
137
- /** Phase-file predicates. */
138
- const isPlanFile = (f) => f.endsWith('-PLAN.md') || f === 'PLAN.md';
139
- exports.isPlanFile = isPlanFile;
140
- const isSummaryFile = (f) => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md';
141
- exports.isSummaryFile = isSummaryFile;
142
- /** Strip suffix to get plan/summary ID. */
143
- const planId = (f) => f.replace('-PLAN.md', '').replace('PLAN.md', '');
144
- exports.planId = planId;
145
- const summaryId = (f) => f.replace('-SUMMARY.md', '').replace('SUMMARY.md', '');
146
- exports.summaryId = summaryId;
147
- /** List subdirectory names, optionally sorted by phase number. */
148
- function listSubDirs(dir, sortByPhase = false) {
149
- const dirs = node_fs_1.default.readdirSync(dir, { withFileTypes: true })
150
- .filter(e => e.isDirectory())
151
- .map(e => e.name);
152
- return sortByPhase ? dirs.sort((a, b) => comparePhaseNum(a, b)) : dirs;
153
- }
154
- /** Async version of listSubDirs using fs.promises. */
155
- async function listSubDirsAsync(dir, sortByPhase = false) {
156
- const entries = await node_fs_2.promises.readdir(dir, { withFileTypes: true });
157
- const dirs = entries.filter(e => e.isDirectory()).map(e => e.name);
158
- return sortByPhase ? dirs.sort((a, b) => comparePhaseNum(a, b)) : dirs;
159
- }
160
- /** Async version of safeReadFile using fs.promises. */
161
- async function safeReadFileAsync(filePath) {
162
- try {
163
- return await node_fs_2.promises.readFile(filePath, 'utf-8');
164
- }
165
- catch {
166
- return null;
167
- }
168
- }
169
- /** Extract a human-readable message from an unknown thrown value. */
170
- function errorMsg(e) {
171
- return e instanceof Error ? e.message : String(e);
172
- }
173
- /** Log only when MAXSIM_DEBUG is set. Accepts an optional context label. */
174
- function debugLog(contextOrError, error) {
175
- if (!process.env.MAXSIM_DEBUG)
176
- return;
177
- if (error !== undefined) {
178
- console.error(`[maxsim:${contextOrError}]`, error);
179
- }
180
- else {
181
- console.error(contextOrError);
182
- }
183
- }
184
- /** Escape a phase number for use in regex. */
185
- function escapePhaseNum(phase) {
186
- return String(phase).replace(/\./g, '\\.');
187
- }
188
- // ─── File & Config utilities ─────────────────────────────────────────────────
189
- function safeReadFile(filePath) {
190
- try {
191
- return node_fs_1.default.readFileSync(filePath, 'utf-8');
192
- }
193
- catch {
194
- return null;
195
- }
196
- }
197
- let _configCache = null;
198
- function loadConfig(cwd) {
199
- if (_configCache && _configCache.cwd === cwd)
200
- return _configCache.config;
201
- const cfgPath = configPath(cwd);
202
- const defaults = {
203
- model_profile: 'balanced',
204
- commit_docs: true,
205
- search_gitignored: false,
206
- branching_strategy: 'none',
207
- phase_branch_template: 'maxsim/phase-{phase}-{slug}',
208
- milestone_branch_template: 'maxsim/{milestone}-{slug}',
209
- research: true,
210
- plan_checker: true,
211
- verifier: true,
212
- parallelization: true,
213
- brave_search: false,
214
- };
215
- try {
216
- const raw = node_fs_1.default.readFileSync(cfgPath, 'utf-8');
217
- const parsed = JSON.parse(raw);
218
- const get = (key, nested) => {
219
- if (parsed[key] !== undefined)
220
- return parsed[key];
221
- if (nested) {
222
- const section = parsed[nested.section];
223
- if (section && typeof section === 'object' && section !== null && nested.field in section) {
224
- return section[nested.field];
225
- }
226
- }
227
- return undefined;
228
- };
229
- const parallelization = (() => {
230
- const val = get('parallelization');
231
- if (typeof val === 'boolean')
232
- return val;
233
- if (typeof val === 'object' && val !== null && 'enabled' in val) {
234
- return val.enabled;
235
- }
236
- return defaults.parallelization;
237
- })();
238
- const result = {
239
- model_profile: get('model_profile') ?? defaults.model_profile,
240
- commit_docs: get('commit_docs', { section: 'planning', field: 'commit_docs' }) ?? defaults.commit_docs,
241
- search_gitignored: get('search_gitignored', { section: 'planning', field: 'search_gitignored' }) ?? defaults.search_gitignored,
242
- branching_strategy: get('branching_strategy', { section: 'git', field: 'branching_strategy' }) ?? defaults.branching_strategy,
243
- phase_branch_template: get('phase_branch_template', { section: 'git', field: 'phase_branch_template' }) ?? defaults.phase_branch_template,
244
- milestone_branch_template: get('milestone_branch_template', { section: 'git', field: 'milestone_branch_template' }) ?? defaults.milestone_branch_template,
245
- research: get('research', { section: 'workflow', field: 'research' }) ?? defaults.research,
246
- plan_checker: (get('plan_checker', { section: 'workflow', field: 'plan_checker' }) ?? get('plan_checker', { section: 'workflow', field: 'plan_check' })) ?? defaults.plan_checker,
247
- verifier: get('verifier', { section: 'workflow', field: 'verifier' }) ?? defaults.verifier,
248
- parallelization,
249
- brave_search: get('brave_search') ?? defaults.brave_search,
250
- model_overrides: parsed['model_overrides'],
251
- };
252
- _configCache = { cwd, config: result };
253
- return result;
254
- }
255
- catch (e) {
256
- // If the file exists but is unparseable, warn the user
257
- if (node_fs_1.default.existsSync(cfgPath)) {
258
- console.warn(`[maxsim] Warning: config.json exists but could not be parsed — using defaults.`);
259
- debugLog('config-load-failed', e);
260
- }
261
- _configCache = { cwd, config: defaults };
262
- return defaults;
263
- }
264
- }
265
- // ─── Git utilities ───────────────────────────────────────────────────────────
266
- async function isGitIgnored(cwd, targetPath) {
267
- try {
268
- const git = (0, simple_git_1.simpleGit)(cwd);
269
- const result = await git.checkIgnore(targetPath);
270
- return result.length > 0;
271
- }
272
- catch {
273
- return false;
274
- }
275
- }
276
- async function execGit(cwd, args) {
277
- try {
278
- const git = (0, simple_git_1.simpleGit)(cwd);
279
- const stdout = await git.raw(args);
280
- return { exitCode: 0, stdout: (stdout ?? '').trim(), stderr: '' };
281
- }
282
- catch (thrown) {
283
- // simple-git throws on non-zero exit — extract what we can
284
- const message = thrown instanceof Error ? thrown.message : String(thrown);
285
- debugLog('exec-git-failed', { args, error: message });
286
- return {
287
- exitCode: 1,
288
- stdout: '',
289
- stderr: message,
290
- };
291
- }
292
- }
293
- // ─── Phase utilities ─────────────────────────────────────────────────────────
294
- function normalizePhaseName(phase) {
295
- const match = phase.match(/^(\d+)([A-Z])?(\.\d+)?/i);
296
- if (!match)
297
- return phase;
298
- const padded = match[1].padStart(2, '0');
299
- const letter = match[2] ? match[2].toUpperCase() : '';
300
- const decimal = match[3] || '';
301
- return padded + letter + decimal;
302
- }
303
- function comparePhaseNum(a, b) {
304
- const pa = String(a).match(/^(\d+)([A-Z])?(\.\d+)?/i);
305
- const pb = String(b).match(/^(\d+)([A-Z])?(\.\d+)?/i);
306
- if (!pa || !pb)
307
- return String(a).localeCompare(String(b));
308
- const intDiff = parseInt(pa[1], 10) - parseInt(pb[1], 10);
309
- if (intDiff !== 0)
310
- return intDiff;
311
- const la = (pa[2] || '').toUpperCase();
312
- const lb = (pb[2] || '').toUpperCase();
313
- if (la !== lb) {
314
- if (!la)
315
- return -1;
316
- if (!lb)
317
- return 1;
318
- return la < lb ? -1 : 1;
319
- }
320
- const da = pa[3] ? parseFloat(pa[3]) : -1;
321
- const db = pb[3] ? parseFloat(pb[3]) : -1;
322
- return da - db;
323
- }
324
- // ─── Phase regex helper ──────────────────────────────────────────────────────
325
- /**
326
- * Returns the canonical regex for matching Phase heading lines in ROADMAP.md.
327
- *
328
- * General form (no escapedPhaseNum):
329
- * Matches: ## Phase 03: Name Here
330
- * Group 1: phase number string (e.g. "03", "3A", "2.1")
331
- * Group 2: phase name string (e.g. "Name Here")
332
- *
333
- * Specific form (with escapedPhaseNum):
334
- * Matches: ## Phase 03: Name Here
335
- * Group 1: phase name string only
336
- *
337
- * @param escapedPhaseNum - regex-escaped phase number string to match a specific phase
338
- * @param flags - regex flags (default: 'gi')
339
- */
340
- function getPhasePattern(escapedPhaseNum, flags = 'gim') {
341
- if (escapedPhaseNum) {
342
- return new RegExp(`^#{2,4}\\s*Phase\\s+${escapedPhaseNum}:\\s*([^\\n]+)`, flags);
343
- }
344
- return new RegExp(`^#{2,4}\\s*Phase\\s+(\\d+[A-Z]?(?:\\.\\d+)?)\\s*:\\s*([^\\n]+)`, flags);
345
- }
346
- function searchPhaseInDir(baseDir, relBase, normalized) {
347
- try {
348
- const dirs = listSubDirs(baseDir, true);
349
- const match = dirs.find(d => d.startsWith(normalized));
350
- if (!match)
351
- return null;
352
- const dirMatch = match.match(/^(\d+[A-Z]?(?:\.\d+)?)-?(.*)/i);
353
- const phaseNumber = dirMatch ? dirMatch[1] : normalized;
354
- const phaseName = dirMatch && dirMatch[2] ? dirMatch[2] : null;
355
- const phaseDir = node_path_1.default.join(baseDir, match);
356
- const phaseFiles = node_fs_1.default.readdirSync(phaseDir);
357
- const plans = phaseFiles.filter(exports.isPlanFile).sort();
358
- const summaries = phaseFiles.filter(exports.isSummaryFile).sort();
359
- const hasResearch = phaseFiles.some(f => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');
360
- const hasContext = phaseFiles.some(f => f.endsWith('-CONTEXT.md') || f === 'CONTEXT.md');
361
- const hasVerification = phaseFiles.some(f => f.endsWith('-VERIFICATION.md') || f === 'VERIFICATION.md');
362
- const completedPlanIds = new Set(summaries.map(exports.summaryId));
363
- const incompletePlans = plans.filter(p => !completedPlanIds.has((0, exports.planId)(p)));
364
- return {
365
- found: true,
366
- directory: node_path_1.default.join(relBase, match),
367
- phase_number: phaseNumber,
368
- phase_name: phaseName,
369
- phase_slug: phaseName ? phaseName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') : null,
370
- plans,
371
- summaries,
372
- incomplete_plans: incompletePlans,
373
- has_research: hasResearch,
374
- has_context: hasContext,
375
- has_verification: hasVerification,
376
- };
377
- }
378
- catch (e) {
379
- debugLog('search-phase-in-dir-failed', { dir: baseDir, phase: normalized, error: errorMsg(e) });
380
- return null;
381
- }
382
- }
383
- function findPhaseInternal(cwd, phase) {
384
- if (!phase)
385
- return null;
386
- const pd = phasesPath(cwd);
387
- const normalized = normalizePhaseName(phase);
388
- const current = searchPhaseInDir(pd, node_path_1.default.join('.planning', 'phases'), normalized);
389
- if (current)
390
- return current;
391
- const milestonesDir = planningPath(cwd, 'milestones');
392
- try {
393
- node_fs_1.default.statSync(milestonesDir);
394
- }
395
- catch {
396
- return null;
397
- }
398
- try {
399
- const milestoneEntries = node_fs_1.default.readdirSync(milestonesDir, { withFileTypes: true });
400
- const archiveDirs = milestoneEntries
401
- .filter(e => e.isDirectory() && /^v[\d.]+-phases$/.test(e.name))
402
- .map(e => e.name)
403
- .sort()
404
- .reverse();
405
- for (const archiveName of archiveDirs) {
406
- const versionMatch = archiveName.match(/^(v[\d.]+)-phases$/);
407
- if (!versionMatch)
408
- continue;
409
- const version = versionMatch[1];
410
- const archivePath = node_path_1.default.join(milestonesDir, archiveName);
411
- const relBase = node_path_1.default.join('.planning', 'milestones', archiveName);
412
- const result = searchPhaseInDir(archivePath, relBase, normalized);
413
- if (result) {
414
- result.archived = version;
415
- return result;
416
- }
417
- }
418
- }
419
- catch (e) {
420
- debugLog('find-phase-milestone-search-failed', e);
421
- }
422
- return null;
423
- }
424
- function getArchivedPhaseDirs(cwd) {
425
- const milestonesDir = planningPath(cwd, 'milestones');
426
- const results = [];
427
- try {
428
- const milestoneEntries = node_fs_1.default.readdirSync(milestonesDir, { withFileTypes: true });
429
- const phaseDirs = milestoneEntries
430
- .filter(e => e.isDirectory() && /^v[\d.]+-phases$/.test(e.name))
431
- .map(e => e.name)
432
- .sort()
433
- .reverse();
434
- for (const archiveName of phaseDirs) {
435
- const versionMatch = archiveName.match(/^(v[\d.]+)-phases$/);
436
- if (!versionMatch)
437
- continue;
438
- const version = versionMatch[1];
439
- const archivePath = node_path_1.default.join(milestonesDir, archiveName);
440
- const dirs = listSubDirs(archivePath, true);
441
- for (const dir of dirs) {
442
- results.push({
443
- name: dir,
444
- milestone: version,
445
- basePath: node_path_1.default.join('.planning', 'milestones', archiveName),
446
- fullPath: node_path_1.default.join(archivePath, dir),
447
- });
448
- }
449
- }
450
- }
451
- catch (e) {
452
- debugLog('get-archived-phase-dirs-failed', e);
453
- }
454
- return results;
455
- }
456
- // ─── Roadmap & model utilities ───────────────────────────────────────────────
457
- function getRoadmapPhaseInternal(cwd, phaseNum) {
458
- if (!phaseNum)
459
- return null;
460
- const rp = roadmapPath(cwd);
461
- try {
462
- const content = node_fs_1.default.readFileSync(rp, 'utf-8');
463
- const escapedPhase = escapePhaseNum(phaseNum);
464
- const phasePattern = getPhasePattern(escapedPhase, 'i');
465
- const headerMatch = content.match(phasePattern);
466
- if (!headerMatch)
467
- return null;
468
- const phaseName = headerMatch[1].trim();
469
- const headerIndex = headerMatch.index;
470
- const restOfContent = content.slice(headerIndex);
471
- const nextHeaderMatch = restOfContent.match(/\n#{2,4}\s+Phase\s+\d/i);
472
- const sectionEnd = nextHeaderMatch ? headerIndex + nextHeaderMatch.index : content.length;
473
- const section = content.slice(headerIndex, sectionEnd).trim();
474
- const goalMatch = section.match(/\*\*Goal(?::\*\*|\*\*:)\s*([^\n]+)/i);
475
- const goal = goalMatch ? goalMatch[1].trim() : null;
476
- return {
477
- found: true,
478
- phase_number: phaseNum.toString(),
479
- phase_name: phaseName,
480
- goal,
481
- section,
482
- };
483
- }
484
- catch (e) {
485
- debugLog('get-roadmap-phase-failed', { phase: phaseNum, error: errorMsg(e) });
486
- return null;
487
- }
488
- }
489
- function resolveModelInternal(cwd, agentType, config) {
490
- config = config ?? loadConfig(cwd);
491
- const override = config.model_overrides?.[agentType];
492
- if (override) {
493
- return override === 'opus' ? 'inherit' : override;
494
- }
495
- const profile = config.model_profile || 'balanced';
496
- const agentModels = exports.MODEL_PROFILES[agentType];
497
- if (!agentModels)
498
- return 'sonnet';
499
- const resolved = agentModels[profile] || agentModels['balanced'] || 'sonnet';
500
- return resolved === 'opus' ? 'inherit' : resolved;
501
- }
502
- // ─── Misc utilities ──────────────────────────────────────────────────────────
503
- function pathExistsInternal(cwd, targetPath) {
504
- const fullPath = node_path_1.default.isAbsolute(targetPath) ? targetPath : node_path_1.default.join(cwd, targetPath);
505
- try {
506
- node_fs_1.default.statSync(fullPath);
507
- return true;
508
- }
509
- catch {
510
- return false;
511
- }
512
- }
513
- function generateSlugInternal(text) {
514
- if (!text)
515
- return null;
516
- return (0, slugify_1.default)(text, { lower: true, strict: true });
517
- }
518
- function getMilestoneInfo(cwd) {
519
- try {
520
- const roadmap = node_fs_1.default.readFileSync(roadmapPath(cwd), 'utf-8');
521
- const versionMatch = roadmap.match(/v(\d+\.\d+)/);
522
- const nameMatch = roadmap.match(/## .*v\d+\.\d+[:\s]+([^\n(]+)/);
523
- return {
524
- version: versionMatch ? versionMatch[0] : 'v1.0',
525
- name: nameMatch ? nameMatch[1].trim() : 'milestone',
526
- };
527
- }
528
- catch {
529
- return { version: 'v1.0', name: 'milestone' };
530
- }
531
- }
532
- // ─── Async versions of internal helpers (Phase 10: Performance) ─────────────
533
- async function pathExistsAsync(p) {
534
- try {
535
- await node_fs_2.promises.access(p);
536
- return true;
537
- }
538
- catch {
539
- return false;
540
- }
541
- }
542
- async function loadConfigAsync(cwd) {
543
- if (_configCache && _configCache.cwd === cwd)
544
- return _configCache.config;
545
- const cfgPath = configPath(cwd);
546
- const defaults = {
547
- model_profile: 'balanced',
548
- commit_docs: true,
549
- search_gitignored: false,
550
- branching_strategy: 'none',
551
- phase_branch_template: 'maxsim/phase-{phase}-{slug}',
552
- milestone_branch_template: 'maxsim/{milestone}-{slug}',
553
- research: true,
554
- plan_checker: true,
555
- verifier: true,
556
- parallelization: true,
557
- brave_search: false,
558
- };
559
- try {
560
- const raw = await node_fs_2.promises.readFile(cfgPath, 'utf-8');
561
- const parsed = JSON.parse(raw);
562
- const get = (key, nested) => {
563
- if (parsed[key] !== undefined)
564
- return parsed[key];
565
- if (nested) {
566
- const section = parsed[nested.section];
567
- if (section && typeof section === 'object' && section !== null && nested.field in section) {
568
- return section[nested.field];
569
- }
570
- }
571
- return undefined;
572
- };
573
- const parallelization = (() => {
574
- const val = get('parallelization');
575
- if (typeof val === 'boolean')
576
- return val;
577
- if (typeof val === 'object' && val !== null && 'enabled' in val) {
578
- return val.enabled;
579
- }
580
- return defaults.parallelization;
581
- })();
582
- const result = {
583
- model_profile: get('model_profile') ?? defaults.model_profile,
584
- commit_docs: get('commit_docs', { section: 'planning', field: 'commit_docs' }) ?? defaults.commit_docs,
585
- search_gitignored: get('search_gitignored', { section: 'planning', field: 'search_gitignored' }) ?? defaults.search_gitignored,
586
- branching_strategy: get('branching_strategy', { section: 'git', field: 'branching_strategy' }) ?? defaults.branching_strategy,
587
- phase_branch_template: get('phase_branch_template', { section: 'git', field: 'phase_branch_template' }) ?? defaults.phase_branch_template,
588
- milestone_branch_template: get('milestone_branch_template', { section: 'git', field: 'milestone_branch_template' }) ?? defaults.milestone_branch_template,
589
- research: get('research', { section: 'workflow', field: 'research' }) ?? defaults.research,
590
- plan_checker: (get('plan_checker', { section: 'workflow', field: 'plan_checker' }) ?? get('plan_checker', { section: 'workflow', field: 'plan_check' })) ?? defaults.plan_checker,
591
- verifier: get('verifier', { section: 'workflow', field: 'verifier' }) ?? defaults.verifier,
592
- parallelization,
593
- brave_search: get('brave_search') ?? defaults.brave_search,
594
- model_overrides: parsed['model_overrides'],
595
- };
596
- _configCache = { cwd, config: result };
597
- return result;
598
- }
599
- catch (e) {
600
- if (await pathExistsAsync(cfgPath)) {
601
- console.warn(`[maxsim] Warning: config.json exists but could not be parsed — using defaults.`);
602
- debugLog('config-load-failed', e);
603
- }
604
- _configCache = { cwd, config: defaults };
605
- return defaults;
606
- }
607
- }
608
- async function searchPhaseInDirAsync(baseDir, relBase, normalized) {
609
- try {
610
- const dirs = await listSubDirsAsync(baseDir, true);
611
- const match = dirs.find(d => d.startsWith(normalized));
612
- if (!match)
613
- return null;
614
- const dirMatch = match.match(/^(\d+[A-Z]?(?:\.\d+)?)-?(.*)/i);
615
- const phaseNumber = dirMatch ? dirMatch[1] : normalized;
616
- const phaseName = dirMatch && dirMatch[2] ? dirMatch[2] : null;
617
- const phaseDir = node_path_1.default.join(baseDir, match);
618
- const phaseFiles = await node_fs_2.promises.readdir(phaseDir);
619
- const plans = phaseFiles.filter(exports.isPlanFile).sort();
620
- const summaries = phaseFiles.filter(exports.isSummaryFile).sort();
621
- const hasResearch = phaseFiles.some(f => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');
622
- const hasContext = phaseFiles.some(f => f.endsWith('-CONTEXT.md') || f === 'CONTEXT.md');
623
- const hasVerification = phaseFiles.some(f => f.endsWith('-VERIFICATION.md') || f === 'VERIFICATION.md');
624
- const completedPlanIds = new Set(summaries.map(exports.summaryId));
625
- const incompletePlans = plans.filter(p => !completedPlanIds.has((0, exports.planId)(p)));
626
- return {
627
- found: true,
628
- directory: node_path_1.default.join(relBase, match),
629
- phase_number: phaseNumber,
630
- phase_name: phaseName,
631
- phase_slug: phaseName ? phaseName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') : null,
632
- plans,
633
- summaries,
634
- incomplete_plans: incompletePlans,
635
- has_research: hasResearch,
636
- has_context: hasContext,
637
- has_verification: hasVerification,
638
- };
639
- }
640
- catch (e) {
641
- debugLog('search-phase-in-dir-async-failed', { dir: baseDir, phase: normalized, error: errorMsg(e) });
642
- return null;
643
- }
644
- }
645
- async function findPhaseInternalAsync(cwd, phase) {
646
- if (!phase)
647
- return null;
648
- const pd = phasesPath(cwd);
649
- const normalized = normalizePhaseName(phase);
650
- const current = await searchPhaseInDirAsync(pd, node_path_1.default.join('.planning', 'phases'), normalized);
651
- if (current)
652
- return current;
653
- // Search new archive location: .planning/archive/<milestone>/
654
- const archiveDir = planningPath(cwd, 'archive');
655
- if (await pathExistsAsync(archiveDir)) {
656
- try {
657
- const archiveEntries = await node_fs_2.promises.readdir(archiveDir, { withFileTypes: true });
658
- const versionDirs = archiveEntries
659
- .filter(e => e.isDirectory())
660
- .map(e => e.name)
661
- .sort()
662
- .reverse();
663
- for (const versionName of versionDirs) {
664
- const versionPath = node_path_1.default.join(archiveDir, versionName);
665
- const relBase = node_path_1.default.join('.planning', 'archive', versionName);
666
- const result = await searchPhaseInDirAsync(versionPath, relBase, normalized);
667
- if (result) {
668
- result.archived = versionName;
669
- return result;
670
- }
671
- }
672
- }
673
- catch (e) {
674
- debugLog('find-phase-async-archive-search-failed', e);
675
- }
676
- }
677
- // Legacy: search .planning/milestones/
678
- const milestonesDir = planningPath(cwd, 'milestones');
679
- if (!(await pathExistsAsync(milestonesDir)))
680
- return null;
681
- try {
682
- const milestoneEntries = await node_fs_2.promises.readdir(milestonesDir, { withFileTypes: true });
683
- const archiveDirs = milestoneEntries
684
- .filter(e => e.isDirectory() && /^v[\d.]+-phases$/.test(e.name))
685
- .map(e => e.name)
686
- .sort()
687
- .reverse();
688
- for (const archiveName of archiveDirs) {
689
- const versionMatch = archiveName.match(/^(v[\d.]+)-phases$/);
690
- if (!versionMatch)
691
- continue;
692
- const version = versionMatch[1];
693
- const archiveMilestonePath = node_path_1.default.join(milestonesDir, archiveName);
694
- const relBase = node_path_1.default.join('.planning', 'milestones', archiveName);
695
- const result = await searchPhaseInDirAsync(archiveMilestonePath, relBase, normalized);
696
- if (result) {
697
- result.archived = version;
698
- return result;
699
- }
700
- }
701
- }
702
- catch (e) {
703
- debugLog('find-phase-async-milestone-search-failed', e);
704
- }
705
- return null;
706
- }
707
- async function getArchivedPhaseDirsAsync(cwd) {
708
- const results = [];
709
- // New archive location: .planning/archive/<milestone>/
710
- const archiveDir = planningPath(cwd, 'archive');
711
- try {
712
- const archiveEntries = await node_fs_2.promises.readdir(archiveDir, { withFileTypes: true });
713
- const versionDirs = archiveEntries
714
- .filter(e => e.isDirectory())
715
- .map(e => e.name)
716
- .sort()
717
- .reverse();
718
- for (const versionName of versionDirs) {
719
- const versionPath = node_path_1.default.join(archiveDir, versionName);
720
- const dirs = await listSubDirsAsync(versionPath, true);
721
- for (const dir of dirs) {
722
- results.push({
723
- name: dir,
724
- milestone: versionName,
725
- basePath: node_path_1.default.join('.planning', 'archive', versionName),
726
- fullPath: node_path_1.default.join(versionPath, dir),
727
- });
728
- }
729
- }
730
- }
731
- catch (e) {
732
- debugLog('get-archived-phase-dirs-async-archive-failed', e);
733
- }
734
- // Legacy: .planning/milestones/
735
- const milestonesDir = planningPath(cwd, 'milestones');
736
- try {
737
- const milestoneEntries = await node_fs_2.promises.readdir(milestonesDir, { withFileTypes: true });
738
- const phaseDirs = milestoneEntries
739
- .filter(e => e.isDirectory() && /^v[\d.]+-phases$/.test(e.name))
740
- .map(e => e.name)
741
- .sort()
742
- .reverse();
743
- for (const archiveName of phaseDirs) {
744
- const versionMatch = archiveName.match(/^(v[\d.]+)-phases$/);
745
- if (!versionMatch)
746
- continue;
747
- const version = versionMatch[1];
748
- const archiveMilestonePath = node_path_1.default.join(milestonesDir, archiveName);
749
- const dirs = await listSubDirsAsync(archiveMilestonePath, true);
750
- for (const dir of dirs) {
751
- results.push({
752
- name: dir,
753
- milestone: version,
754
- basePath: node_path_1.default.join('.planning', 'milestones', archiveName),
755
- fullPath: node_path_1.default.join(archiveMilestonePath, dir),
756
- });
757
- }
758
- }
759
- }
760
- catch (e) {
761
- debugLog('get-archived-phase-dirs-async-failed', e);
762
- }
763
- return results;
764
- }
765
- async function getRoadmapPhaseInternalAsync(cwd, phaseNum) {
766
- if (!phaseNum)
767
- return null;
768
- const rp = roadmapPath(cwd);
769
- try {
770
- const content = await safeReadFileAsync(rp);
771
- if (!content)
772
- return null;
773
- const escapedPhase = escapePhaseNum(phaseNum);
774
- const phasePattern = getPhasePattern(escapedPhase, 'i');
775
- const headerMatch = content.match(phasePattern);
776
- if (!headerMatch)
777
- return null;
778
- const phaseName = headerMatch[1].trim();
779
- const headerIndex = headerMatch.index;
780
- const restOfContent = content.slice(headerIndex);
781
- const nextHeaderMatch = restOfContent.match(/\n#{2,4}\s+Phase\s+\d/i);
782
- const sectionEnd = nextHeaderMatch ? headerIndex + nextHeaderMatch.index : content.length;
783
- const section = content.slice(headerIndex, sectionEnd).trim();
784
- const goalMatch = section.match(/\*\*Goal(?::\*\*|\*\*:)\s*([^\n]+)/i);
785
- const goal = goalMatch ? goalMatch[1].trim() : null;
786
- return {
787
- found: true,
788
- phase_number: phaseNum.toString(),
789
- phase_name: phaseName,
790
- goal,
791
- section,
792
- };
793
- }
794
- catch (e) {
795
- debugLog('get-roadmap-phase-async-failed', { phase: phaseNum, error: errorMsg(e) });
796
- return null;
797
- }
798
- }
799
- function archivePath(cwd, milestone) {
800
- const ms = milestone ?? getMilestoneInfo(cwd).version;
801
- return planningPath(cwd, 'archive', ms);
802
- }
803
- async function archivePathAsync(cwd, milestone) {
804
- const ms = milestone ?? (await getMilestoneInfoAsync(cwd)).version;
805
- return planningPath(cwd, 'archive', ms);
806
- }
807
- async function getMilestoneInfoAsync(cwd) {
808
- try {
809
- const roadmap = await safeReadFileAsync(roadmapPath(cwd));
810
- if (!roadmap)
811
- return { version: 'v1.0', name: 'milestone' };
812
- const versionMatch = roadmap.match(/v(\d+\.\d+)/);
813
- const nameMatch = roadmap.match(/## .*v\d+\.\d+[:\s]+([^\n(]+)/);
814
- return {
815
- version: versionMatch ? versionMatch[0] : 'v1.0',
816
- name: nameMatch ? nameMatch[1].trim() : 'milestone',
817
- };
818
- }
819
- catch {
820
- return { version: 'v1.0', name: 'milestone' };
821
- }
822
- }
823
- //# sourceMappingURL=core.js.map