pan-wizard 2.8.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 (164) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +772 -0
  3. package/agents/pan-debugger.md +1246 -0
  4. package/agents/pan-document_code.md +965 -0
  5. package/agents/pan-executor.md +469 -0
  6. package/agents/pan-integration-checker.md +443 -0
  7. package/agents/pan-phase-researcher.md +572 -0
  8. package/agents/pan-plan-checker.md +763 -0
  9. package/agents/pan-planner.md +1297 -0
  10. package/agents/pan-project-researcher.md +647 -0
  11. package/agents/pan-research-synthesizer.md +239 -0
  12. package/agents/pan-reviewer.md +112 -0
  13. package/agents/pan-roadmapper.md +642 -0
  14. package/agents/pan-verifier.md +672 -0
  15. package/assets/pan-logo-2000-transparent.svg +30 -0
  16. package/assets/pan-logo-2000.svg +43 -0
  17. package/assets/terminal.svg +119 -0
  18. package/bin/install-lib.cjs +616 -0
  19. package/bin/install.js +1936 -0
  20. package/commands/pan/add-phase.md +44 -0
  21. package/commands/pan/assumptions.md +47 -0
  22. package/commands/pan/audit-deployment.md +378 -0
  23. package/commands/pan/debug.md +168 -0
  24. package/commands/pan/discord.md +19 -0
  25. package/commands/pan/discuss-phase.md +84 -0
  26. package/commands/pan/exec-phase.md +45 -0
  27. package/commands/pan/focus-auto.md +323 -0
  28. package/commands/pan/focus-design.md +816 -0
  29. package/commands/pan/focus-exec.md +316 -0
  30. package/commands/pan/focus-plan.md +101 -0
  31. package/commands/pan/focus-scan.md +272 -0
  32. package/commands/pan/focus-sync.md +104 -0
  33. package/commands/pan/health.md +23 -0
  34. package/commands/pan/help.md +23 -0
  35. package/commands/pan/insert-phase.md +33 -0
  36. package/commands/pan/map-codebase.md +72 -0
  37. package/commands/pan/milestone-audit.md +37 -0
  38. package/commands/pan/milestone-cleanup.md +19 -0
  39. package/commands/pan/milestone-done.md +137 -0
  40. package/commands/pan/milestone-gaps.md +35 -0
  41. package/commands/pan/milestone-new.md +45 -0
  42. package/commands/pan/new-project.md +43 -0
  43. package/commands/pan/patches.md +110 -0
  44. package/commands/pan/pause.md +39 -0
  45. package/commands/pan/phase-budget.md +23 -0
  46. package/commands/pan/phase-tests.md +42 -0
  47. package/commands/pan/plan-phase.md +46 -0
  48. package/commands/pan/profile.md +36 -0
  49. package/commands/pan/progress.md +25 -0
  50. package/commands/pan/quick.md +42 -0
  51. package/commands/pan/remove-phase.md +32 -0
  52. package/commands/pan/research-phase.md +190 -0
  53. package/commands/pan/resume.md +41 -0
  54. package/commands/pan/retro.md +33 -0
  55. package/commands/pan/settings.md +37 -0
  56. package/commands/pan/todo-add.md +48 -0
  57. package/commands/pan/todo-check.md +46 -0
  58. package/commands/pan/update.md +38 -0
  59. package/commands/pan/verify-phase.md +39 -0
  60. package/hooks/dist/pan-check-update.js +62 -0
  61. package/hooks/dist/pan-context-monitor.js +122 -0
  62. package/hooks/dist/pan-statusline.js +108 -0
  63. package/package.json +66 -0
  64. package/pan-wizard-core/bin/lib/codebase.cjs +746 -0
  65. package/pan-wizard-core/bin/lib/commands.cjs +1435 -0
  66. package/pan-wizard-core/bin/lib/config.cjs +611 -0
  67. package/pan-wizard-core/bin/lib/constants.cjs +696 -0
  68. package/pan-wizard-core/bin/lib/context-budget.cjs +150 -0
  69. package/pan-wizard-core/bin/lib/core.cjs +650 -0
  70. package/pan-wizard-core/bin/lib/focus.cjs +900 -0
  71. package/pan-wizard-core/bin/lib/frontmatter.cjs +442 -0
  72. package/pan-wizard-core/bin/lib/init.cjs +881 -0
  73. package/pan-wizard-core/bin/lib/milestone.cjs +276 -0
  74. package/pan-wizard-core/bin/lib/phase.cjs +1212 -0
  75. package/pan-wizard-core/bin/lib/roadmap.cjs +470 -0
  76. package/pan-wizard-core/bin/lib/state.cjs +1029 -0
  77. package/pan-wizard-core/bin/lib/template.cjs +314 -0
  78. package/pan-wizard-core/bin/lib/utils.cjs +171 -0
  79. package/pan-wizard-core/bin/lib/verify.cjs +1808 -0
  80. package/pan-wizard-core/bin/pan-tools.cjs +773 -0
  81. package/pan-wizard-core/references/checkpoints.md +776 -0
  82. package/pan-wizard-core/references/continuation-format.md +249 -0
  83. package/pan-wizard-core/references/decimal-phase-calculation.md +65 -0
  84. package/pan-wizard-core/references/git-integration.md +248 -0
  85. package/pan-wizard-core/references/git-planning-commit.md +38 -0
  86. package/pan-wizard-core/references/model-profile-resolution.md +34 -0
  87. package/pan-wizard-core/references/model-profiles.md +111 -0
  88. package/pan-wizard-core/references/phase-argument-parsing.md +61 -0
  89. package/pan-wizard-core/references/planning-config.md +196 -0
  90. package/pan-wizard-core/references/questioning.md +145 -0
  91. package/pan-wizard-core/references/tdd.md +263 -0
  92. package/pan-wizard-core/references/ui-brand.md +160 -0
  93. package/pan-wizard-core/references/verification-patterns.md +612 -0
  94. package/pan-wizard-core/templates/codebase/architecture.md +283 -0
  95. package/pan-wizard-core/templates/codebase/best-practices.md +133 -0
  96. package/pan-wizard-core/templates/codebase/concerns.md +325 -0
  97. package/pan-wizard-core/templates/codebase/conventions.md +307 -0
  98. package/pan-wizard-core/templates/codebase/integrations.md +305 -0
  99. package/pan-wizard-core/templates/codebase/relationships.md +124 -0
  100. package/pan-wizard-core/templates/codebase/stack.md +199 -0
  101. package/pan-wizard-core/templates/codebase/structure.md +298 -0
  102. package/pan-wizard-core/templates/codebase/testing.md +480 -0
  103. package/pan-wizard-core/templates/config.json +37 -0
  104. package/pan-wizard-core/templates/context.md +283 -0
  105. package/pan-wizard-core/templates/continue-here.md +78 -0
  106. package/pan-wizard-core/templates/debug-subagent-prompt.md +91 -0
  107. package/pan-wizard-core/templates/debug.md +164 -0
  108. package/pan-wizard-core/templates/discovery.md +146 -0
  109. package/pan-wizard-core/templates/milestone-archive.md +123 -0
  110. package/pan-wizard-core/templates/milestone.md +115 -0
  111. package/pan-wizard-core/templates/phase-prompt.md +593 -0
  112. package/pan-wizard-core/templates/planner-subagent-prompt.md +117 -0
  113. package/pan-wizard-core/templates/project.md +184 -0
  114. package/pan-wizard-core/templates/requirements.md +231 -0
  115. package/pan-wizard-core/templates/research-project/architecture.md +204 -0
  116. package/pan-wizard-core/templates/research-project/features.md +147 -0
  117. package/pan-wizard-core/templates/research-project/pitfalls.md +200 -0
  118. package/pan-wizard-core/templates/research-project/stack.md +120 -0
  119. package/pan-wizard-core/templates/research-project/summary.md +170 -0
  120. package/pan-wizard-core/templates/research.md +552 -0
  121. package/pan-wizard-core/templates/retrospective.md +54 -0
  122. package/pan-wizard-core/templates/roadmap.md +202 -0
  123. package/pan-wizard-core/templates/standards.md +24 -0
  124. package/pan-wizard-core/templates/state.md +176 -0
  125. package/pan-wizard-core/templates/summary-complex.md +59 -0
  126. package/pan-wizard-core/templates/summary-minimal.md +41 -0
  127. package/pan-wizard-core/templates/summary-standard.md +49 -0
  128. package/pan-wizard-core/templates/summary.md +249 -0
  129. package/pan-wizard-core/templates/uat.md +247 -0
  130. package/pan-wizard-core/templates/user-setup.md +311 -0
  131. package/pan-wizard-core/templates/validation.md +76 -0
  132. package/pan-wizard-core/templates/verification-report.md +322 -0
  133. package/pan-wizard-core/workflows/add-phase.md +111 -0
  134. package/pan-wizard-core/workflows/assumptions.md +178 -0
  135. package/pan-wizard-core/workflows/diagnose-issues.md +219 -0
  136. package/pan-wizard-core/workflows/discuss-phase.md +542 -0
  137. package/pan-wizard-core/workflows/exec-phase.md +572 -0
  138. package/pan-wizard-core/workflows/execute-plan.md +448 -0
  139. package/pan-wizard-core/workflows/health.md +156 -0
  140. package/pan-wizard-core/workflows/help.md +431 -0
  141. package/pan-wizard-core/workflows/insert-phase.md +129 -0
  142. package/pan-wizard-core/workflows/map-codebase.md +401 -0
  143. package/pan-wizard-core/workflows/milestone-audit.md +297 -0
  144. package/pan-wizard-core/workflows/milestone-cleanup.md +152 -0
  145. package/pan-wizard-core/workflows/milestone-gaps.md +274 -0
  146. package/pan-wizard-core/workflows/milestone-new.md +382 -0
  147. package/pan-wizard-core/workflows/new-project.md +1178 -0
  148. package/pan-wizard-core/workflows/pause.md +122 -0
  149. package/pan-wizard-core/workflows/phase-tests.md +388 -0
  150. package/pan-wizard-core/workflows/plan-phase.md +569 -0
  151. package/pan-wizard-core/workflows/profile.md +115 -0
  152. package/pan-wizard-core/workflows/progress.md +381 -0
  153. package/pan-wizard-core/workflows/quick.md +453 -0
  154. package/pan-wizard-core/workflows/remove-phase.md +154 -0
  155. package/pan-wizard-core/workflows/research-phase.md +73 -0
  156. package/pan-wizard-core/workflows/resume-project.md +306 -0
  157. package/pan-wizard-core/workflows/retro.md +121 -0
  158. package/pan-wizard-core/workflows/settings.md +213 -0
  159. package/pan-wizard-core/workflows/todo-add.md +157 -0
  160. package/pan-wizard-core/workflows/todo-check.md +176 -0
  161. package/pan-wizard-core/workflows/transition.md +544 -0
  162. package/pan-wizard-core/workflows/update.md +219 -0
  163. package/pan-wizard-core/workflows/verify-phase.md +301 -0
  164. package/scripts/build-hooks.js +43 -0
@@ -0,0 +1,881 @@
1
+ /**
2
+ * Init — Compound init commands for workflow bootstrapping
3
+ */
4
+
5
+ const fs = require('fs');
6
+ const os = require('os');
7
+ const path = require('path');
8
+ const { loadConfig, resolveModelInternal, findPhaseInternal, getRoadmapPhaseInternal, pathExistsInternal, generateSlugInternal, getMilestoneInfo, normalizePhaseName, toPosix, output, error, scanPendingTodos, isGitRepo, execGit } = require('./core.cjs');
9
+ const { PLANNING_DIR, PHASES_DIR, CODEBASE_DIR, QUICK_DIR, MILESTONES_DIR, STATE_FILE, ROADMAP_FILE, CONFIG_FILE, PROJECT_FILE, REQUIREMENTS_FILE, isPlanFile, isSummaryFile, isResearchFile, isContextFile, isVerificationFile, PLAN_SUFFIX, SUMMARY_SUFFIX, CONTEXT_SUFFIX, RESEARCH_SUFFIX, VERIFICATION_SUFFIX, UAT_SUFFIX, MAX_SLUG_LENGTH } = require('./constants.cjs');
10
+ const { planningPath, phasesPath, filterPlanFiles, filterSummaryFiles, classifyPhaseStatus, hasBraveSearchKey } = require('./utils.cjs');
11
+ const { classifyPlanTier } = require('./phase.cjs');
12
+ const { extractFrontmatter } = require('./frontmatter.cjs');
13
+ const { detectLanguages } = require('./codebase.cjs');
14
+
15
+ // ---- Git helpers ----
16
+
17
+ function ensureGitRepo(cwd) {
18
+ if (isGitRepo(cwd)) return true;
19
+ const result = execGit(cwd, ['init']);
20
+ return result.exitCode === 0;
21
+ }
22
+
23
+ // ---- Shared path builders for JSON output values (forward-slash, not filesystem) ----
24
+
25
+ /** Build a forward-slash relative path under .planning for JSON output */
26
+ function planningRelPath(...segments) {
27
+ return [PLANNING_DIR, ...segments].join('/');
28
+ }
29
+
30
+ /**
31
+ * Extract requirement IDs from a ROADMAP phase section.
32
+ * Looks for a **Requirements**: line, strips brackets, splits by comma,
33
+ * and returns null when absent or set to 'TBD'.
34
+ */
35
+ function extractReqIds(roadmapPhase) {
36
+ const reqMatch = roadmapPhase?.section?.match(/^\*\*Requirements\*\*:[^\S\n]*([^\n]*)$/m);
37
+ const reqExtracted = reqMatch
38
+ ? reqMatch[1].replace(/[\[\]]/g, '').split(',').map(segment => segment.trim()).filter(Boolean).join(', ')
39
+ : null;
40
+ return (reqExtracted && reqExtracted !== 'TBD') ? reqExtracted : null;
41
+ }
42
+
43
+ /**
44
+ * Discover optional artifact files (CONTEXT, RESEARCH, VERIFICATION, UAT)
45
+ * within a phase directory and attach their paths to a result object.
46
+ *
47
+ * Each suffix is checked because phases may contain any combination of these
48
+ * optional artifacts. Files may be named either with a prefix (e.g. "01-context.md")
49
+ * or as bare names (e.g. "context.md").
50
+ */
51
+ function attachPhaseArtifactPaths(result, cwd, phaseDirectory) {
52
+ const phaseDirFull = path.join(cwd, phaseDirectory);
53
+ try {
54
+ const files = fs.readdirSync(phaseDirFull);
55
+ const contextFile = files.find(isContextFile);
56
+ if (contextFile) {
57
+ result.context_path = toPosix(path.join(phaseDirectory, contextFile));
58
+ }
59
+ const researchFile = files.find(isResearchFile);
60
+ if (researchFile) {
61
+ result.research_path = toPosix(path.join(phaseDirectory, researchFile));
62
+ }
63
+ const verificationFile = files.find(isVerificationFile);
64
+ if (verificationFile) {
65
+ result.verification_path = toPosix(path.join(phaseDirectory, verificationFile));
66
+ }
67
+ const uatFile = files.find(filename => filename.endsWith(UAT_SUFFIX) || filename === 'uat.md');
68
+ if (uatFile) {
69
+ result.uat_path = toPosix(path.join(phaseDirectory, uatFile));
70
+ }
71
+ } catch {
72
+ // Phase directory may not exist yet or may be unreadable
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Bootstrap context for phase execution: models, config, phase info, and plan inventory.
78
+ * @param {string} cwd - Working directory path
79
+ * @param {string} phase - Phase number to initialize execution for
80
+ * @param {boolean} raw - If true, output raw value instead of JSON
81
+ * @returns {void}
82
+ */
83
+ /**
84
+ * Map effort string to budget points.
85
+ * @param {string|null} effort
86
+ * @returns {number}
87
+ */
88
+ function effortToPoints(effort) {
89
+ const map = { XS: 1, S: 2, M: 4, L: 10, XL: 20 };
90
+ return map[String(effort).toUpperCase()] || 4; // default to M (4)
91
+ }
92
+
93
+ function cmdInitExecutePhase(cwd, phase, raw, opts) {
94
+ if (!phase) {
95
+ error('phase required for init execute-phase');
96
+ }
97
+
98
+ const dryRun = opts && opts.dry_run === true;
99
+ const budgetArg = opts && opts.budget;
100
+ const config = loadConfig(cwd);
101
+
102
+ // Validate and resolve budget
103
+ let totalBudget = (config.budget && config.budget.default_points) || 50;
104
+ if (budgetArg !== undefined && budgetArg !== null) {
105
+ const parsed = parseInt(budgetArg, 10);
106
+ if (isNaN(parsed)) {
107
+ error('Budget must be a number');
108
+ }
109
+ if (parsed < 1) {
110
+ error('Budget must be >= 1');
111
+ }
112
+ totalBudget = Math.min(parsed, 200);
113
+ }
114
+
115
+ const phaseInfo = findPhaseInternal(cwd, phase);
116
+ const milestone = getMilestoneInfo(cwd);
117
+
118
+ // Extract requirement IDs from the ROADMAP **Requirements** field for this phase
119
+ const roadmapPhase = getRoadmapPhaseInternal(cwd, phase);
120
+ const phaseReqIds = extractReqIds(roadmapPhase);
121
+
122
+ // Classify tiers for each plan and calculate budget
123
+ const plans = phaseInfo?.plans || [];
124
+ const plansTierInfo = { micro: 0, standard: 0, full: 0 };
125
+ let estimatedPoints = 0;
126
+
127
+ for (const planFile of plans) {
128
+ // Read plan frontmatter to classify tier
129
+ const planPath = path.join(cwd, phaseInfo?.directory || '', planFile);
130
+ let fm = {};
131
+ try {
132
+ const content = fs.readFileSync(planPath, 'utf-8');
133
+ fm = extractFrontmatter(content) || {};
134
+ } catch { /* plan file unreadable — use defaults */ }
135
+
136
+ const tier = classifyPlanTier(fm, config);
137
+ plansTierInfo[tier] = (plansTierInfo[tier] || 0) + 1;
138
+ estimatedPoints += effortToPoints(fm.effort);
139
+ }
140
+
141
+ const result = {
142
+ // Models
143
+ executor_model: resolveModelInternal(cwd, 'pan-executor'),
144
+ verifier_model: resolveModelInternal(cwd, 'pan-verifier'),
145
+ reviewer_model: resolveModelInternal(cwd, 'pan-reviewer'),
146
+
147
+ // Config flags
148
+ commit_docs: config.commit_docs,
149
+ parallelization: config.parallelization,
150
+ branching_strategy: config.branching_strategy,
151
+ phase_branch_template: config.phase_branch_template,
152
+ milestone_branch_template: config.milestone_branch_template,
153
+ verifier_enabled: config.verifier,
154
+
155
+ // Phase info
156
+ phase_found: !!phaseInfo,
157
+ phase_dir: phaseInfo?.directory || null,
158
+ phase_number: phaseInfo?.phase_number || null,
159
+ phase_name: phaseInfo?.phase_name || null,
160
+ phase_slug: phaseInfo?.phase_slug || null,
161
+ phase_req_ids: phaseReqIds,
162
+
163
+ // Plan inventory
164
+ plans,
165
+ summaries: phaseInfo?.summaries || [],
166
+ incomplete_plans: phaseInfo?.incomplete_plans || [],
167
+ plan_count: plans.length,
168
+ incomplete_count: phaseInfo?.incomplete_plans?.length || 0,
169
+
170
+ // Branch name (pre-computed from template).
171
+ branch_name: config.branching_strategy === 'phase' && phaseInfo
172
+ ? config.phase_branch_template
173
+ .replace('{phase}', phaseInfo.phase_number)
174
+ .replace('{slug}', phaseInfo.phase_slug || 'phase')
175
+ : config.branching_strategy === 'milestone'
176
+ ? config.milestone_branch_template
177
+ .replace('{milestone}', milestone.version)
178
+ .replace('{slug}', generateSlugInternal(milestone.name) || 'milestone')
179
+ : null,
180
+
181
+ // Milestone info
182
+ milestone_version: milestone.version,
183
+ milestone_name: milestone.name,
184
+ milestone_slug: generateSlugInternal(milestone.name),
185
+
186
+ // File existence
187
+ state_exists: pathExistsInternal(cwd, planningRelPath(STATE_FILE)),
188
+ roadmap_exists: pathExistsInternal(cwd, planningRelPath(ROADMAP_FILE)),
189
+ config_exists: pathExistsInternal(cwd, planningRelPath(CONFIG_FILE)),
190
+ // File paths
191
+ state_path: planningRelPath(STATE_FILE),
192
+ roadmap_path: planningRelPath(ROADMAP_FILE),
193
+ config_path: planningRelPath(CONFIG_FILE),
194
+
195
+ // Execution enhancements
196
+ plans_by_tier: plansTierInfo,
197
+ total_budget_points: totalBudget,
198
+ estimated_points: estimatedPoints,
199
+ budget_exceeded: estimatedPoints > totalBudget,
200
+ execution_mode: (config.execution && config.execution.default_mode) || 'wave_order',
201
+ dry_run: dryRun,
202
+ rollback_tag: null,
203
+ };
204
+
205
+ output(result, raw);
206
+ }
207
+
208
+ /**
209
+ * Bootstrap context for phase planning: models, workflow flags, and existing artifacts.
210
+ * @param {string} cwd - Working directory path
211
+ * @param {string} phase - Phase number to initialize planning for
212
+ * @param {boolean} raw - If true, output raw value instead of JSON
213
+ * @returns {void}
214
+ */
215
+ function cmdInitPlanPhase(cwd, phase, raw) {
216
+ if (!phase) {
217
+ error('phase required for init plan-phase');
218
+ }
219
+
220
+ const config = loadConfig(cwd);
221
+ const phaseInfo = findPhaseInternal(cwd, phase);
222
+
223
+ // Extract requirement IDs from the ROADMAP **Requirements** field for this phase
224
+ const roadmapPhase = getRoadmapPhaseInternal(cwd, phase);
225
+ const phaseReqIds = extractReqIds(roadmapPhase);
226
+
227
+ const result = {
228
+ // Models
229
+ researcher_model: resolveModelInternal(cwd, 'pan-phase-researcher'),
230
+ planner_model: resolveModelInternal(cwd, 'pan-planner'),
231
+ checker_model: resolveModelInternal(cwd, 'pan-plan-checker'),
232
+
233
+ // Workflow flags
234
+ research_enabled: config.research,
235
+ plan_checker_enabled: config.plan_checker,
236
+ nyquist_validation_enabled: config.nyquist_validation,
237
+ commit_docs: config.commit_docs,
238
+
239
+ // Phase info
240
+ phase_found: !!phaseInfo,
241
+ phase_dir: phaseInfo?.directory || null,
242
+ phase_number: phaseInfo?.phase_number || null,
243
+ phase_name: phaseInfo?.phase_name || null,
244
+ phase_slug: phaseInfo?.phase_slug || null,
245
+ padded_phase: phaseInfo?.phase_number?.padStart(2, '0') || null,
246
+ phase_req_ids: phaseReqIds,
247
+
248
+ // Existing artifacts
249
+ has_research: phaseInfo?.has_research || false,
250
+ has_context: phaseInfo?.has_context || false,
251
+ has_plans: (phaseInfo?.plans?.length || 0) > 0,
252
+ plan_count: phaseInfo?.plans?.length || 0,
253
+
254
+ // Environment
255
+ planning_exists: pathExistsInternal(cwd, PLANNING_DIR),
256
+ roadmap_exists: pathExistsInternal(cwd, planningRelPath(ROADMAP_FILE)),
257
+
258
+ // File paths
259
+ state_path: planningRelPath(STATE_FILE),
260
+ roadmap_path: planningRelPath(ROADMAP_FILE),
261
+ requirements_path: planningRelPath(REQUIREMENTS_FILE),
262
+ };
263
+
264
+ if (phaseInfo?.directory) {
265
+ // Discover optional artifact files (CONTEXT, RESEARCH, VERIFICATION, UAT)
266
+ attachPhaseArtifactPaths(result, cwd, phaseInfo.directory);
267
+ }
268
+
269
+ output(result, raw);
270
+ }
271
+
272
+ /**
273
+ * Bootstrap context for new project initialization: models, brownfield detection, git state.
274
+ * @param {string} cwd - Working directory path
275
+ * @param {boolean} raw - If true, output raw value instead of JSON
276
+ * @returns {void}
277
+ */
278
+ function cmdInitNewProject(cwd, raw) {
279
+ const config = loadConfig(cwd);
280
+
281
+ // Detect Brave Search API key availability
282
+ const hasBraveSearch = hasBraveSearchKey();
283
+
284
+ // Detect existing code (cross-platform, no shell dependency)
285
+ let hasCode = false;
286
+ let hasPackageFile = false;
287
+ const CODE_EXTS = new Set(['.ts', '.js', '.py', '.go', '.rs', '.swift', '.java']);
288
+ const SKIP_DIRS = new Set(['node_modules', '.git', '.planning', '.claude', '.opencode', '.gemini', '.codex', '.copilot']);
289
+ try {
290
+ const scanDir = (dir, depth) => {
291
+ if (depth > 3 || hasCode) return;
292
+ let entries;
293
+ try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
294
+ for (const entry of entries) {
295
+ if (hasCode) return;
296
+ if (entry.isDirectory()) {
297
+ if (!SKIP_DIRS.has(entry.name)) scanDir(path.join(dir, entry.name), depth + 1);
298
+ } else if (CODE_EXTS.has(path.extname(entry.name))) {
299
+ hasCode = true;
300
+ }
301
+ }
302
+ };
303
+ scanDir(cwd, 0);
304
+ } catch {
305
+ // Filesystem error — treat as greenfield
306
+ }
307
+
308
+ hasPackageFile = pathExistsInternal(cwd, 'package.json') ||
309
+ pathExistsInternal(cwd, 'requirements.txt') ||
310
+ pathExistsInternal(cwd, 'Cargo.toml') ||
311
+ pathExistsInternal(cwd, 'go.mod') ||
312
+ pathExistsInternal(cwd, 'Package.swift');
313
+
314
+ const result = {
315
+ // Models
316
+ researcher_model: resolveModelInternal(cwd, 'pan-project-researcher'),
317
+ synthesizer_model: resolveModelInternal(cwd, 'pan-research-synthesizer'),
318
+ roadmapper_model: resolveModelInternal(cwd, 'pan-roadmapper'),
319
+
320
+ // Config
321
+ commit_docs: config.commit_docs,
322
+
323
+ // Existing state
324
+ project_exists: pathExistsInternal(cwd, planningRelPath(PROJECT_FILE)),
325
+ has_codebase_map: pathExistsInternal(cwd, planningRelPath(CODEBASE_DIR)),
326
+ planning_exists: pathExistsInternal(cwd, PLANNING_DIR),
327
+
328
+ // Brownfield detection
329
+ has_existing_code: hasCode,
330
+ has_package_file: hasPackageFile,
331
+ is_brownfield: hasCode || hasPackageFile,
332
+ needs_codebase_map: (hasCode || hasPackageFile) && !pathExistsInternal(cwd, planningRelPath(CODEBASE_DIR)),
333
+
334
+ // Git state — auto-init if missing
335
+ has_git: ensureGitRepo(cwd),
336
+
337
+ // Enhanced search
338
+ brave_search_available: hasBraveSearch,
339
+
340
+ // File paths
341
+ project_path: planningRelPath(PROJECT_FILE),
342
+ };
343
+
344
+ output(result, raw);
345
+ }
346
+
347
+ /**
348
+ * Bootstrap context for new milestone creation: models, current milestone info, file existence.
349
+ * @param {string} cwd - Working directory path
350
+ * @param {boolean} raw - If true, output raw value instead of JSON
351
+ * @returns {void}
352
+ */
353
+ function cmdInitNewMilestone(cwd, raw) {
354
+ const config = loadConfig(cwd);
355
+ const milestone = getMilestoneInfo(cwd);
356
+
357
+ const result = {
358
+ // Models
359
+ researcher_model: resolveModelInternal(cwd, 'pan-project-researcher'),
360
+ synthesizer_model: resolveModelInternal(cwd, 'pan-research-synthesizer'),
361
+ roadmapper_model: resolveModelInternal(cwd, 'pan-roadmapper'),
362
+
363
+ // Config
364
+ commit_docs: config.commit_docs,
365
+ research_enabled: config.research,
366
+
367
+ // Current milestone
368
+ current_milestone: milestone.version,
369
+ current_milestone_name: milestone.name,
370
+
371
+ // File existence
372
+ project_exists: pathExistsInternal(cwd, planningRelPath(PROJECT_FILE)),
373
+ roadmap_exists: pathExistsInternal(cwd, planningRelPath(ROADMAP_FILE)),
374
+ state_exists: pathExistsInternal(cwd, planningRelPath(STATE_FILE)),
375
+
376
+ // File paths
377
+ project_path: planningRelPath(PROJECT_FILE),
378
+ roadmap_path: planningRelPath(ROADMAP_FILE),
379
+ state_path: planningRelPath(STATE_FILE),
380
+ };
381
+
382
+ output(result, raw);
383
+ }
384
+
385
+ /**
386
+ * Bootstrap context for a quick task: models, task numbering, and directory paths.
387
+ * @param {string} cwd - Working directory path
388
+ * @param {string} description - Optional task description for slug generation
389
+ * @param {boolean} raw - If true, output raw value instead of JSON
390
+ * @returns {void}
391
+ */
392
+ function cmdInitQuick(cwd, description, raw) {
393
+ const config = loadConfig(cwd);
394
+ const now = new Date();
395
+ const slug = description ? generateSlugInternal(description)?.substring(0, MAX_SLUG_LENGTH) : null;
396
+
397
+ // Find next quick task number by scanning existing numbered directories
398
+ const quickDirPath = path.join(planningPath(cwd), QUICK_DIR);
399
+ let nextNum = 1;
400
+ try {
401
+ const existingNums = fs.readdirSync(quickDirPath)
402
+ .filter(entry => /^\d+-/.test(entry))
403
+ .map(entry => parseInt(entry.split('-')[0], 10))
404
+ .filter(num => !isNaN(num));
405
+ if (existingNums.length > 0) {
406
+ nextNum = Math.max(...existingNums) + 1;
407
+ }
408
+ } catch {
409
+ // Quick directory does not exist yet -- start at 1
410
+ }
411
+
412
+ const quickRelDir = planningRelPath(QUICK_DIR);
413
+
414
+ const result = {
415
+ // Models
416
+ planner_model: resolveModelInternal(cwd, 'pan-planner'),
417
+ executor_model: resolveModelInternal(cwd, 'pan-executor'),
418
+ checker_model: resolveModelInternal(cwd, 'pan-plan-checker'),
419
+ verifier_model: resolveModelInternal(cwd, 'pan-verifier'),
420
+
421
+ // Config
422
+ commit_docs: config.commit_docs,
423
+
424
+ // Quick task info
425
+ next_num: nextNum,
426
+ slug: slug,
427
+ description: description || null,
428
+
429
+ // Timestamps
430
+ date: now.toISOString().split('T')[0],
431
+ timestamp: now.toISOString(),
432
+
433
+ // Paths
434
+ quick_dir: quickRelDir,
435
+ task_dir: slug ? `${quickRelDir}/${nextNum}-${slug}` : null,
436
+
437
+ // File existence
438
+ roadmap_exists: pathExistsInternal(cwd, planningRelPath(ROADMAP_FILE)),
439
+ planning_exists: pathExistsInternal(cwd, PLANNING_DIR),
440
+
441
+ };
442
+
443
+ output(result, raw);
444
+ }
445
+
446
+ /**
447
+ * Bootstrap context for resuming work: file existence, interrupted agent detection.
448
+ * @param {string} cwd - Working directory path
449
+ * @param {boolean} raw - If true, output raw value instead of JSON
450
+ * @returns {void}
451
+ */
452
+ function cmdInitResume(cwd, raw) {
453
+ const config = loadConfig(cwd);
454
+
455
+ // Check for interrupted agent
456
+ let interruptedAgentId = null;
457
+ try {
458
+ interruptedAgentId = fs.readFileSync(path.join(planningPath(cwd), 'current-agent-id.txt'), 'utf-8').trim();
459
+ } catch {
460
+ // No interrupted agent file found -- normal state
461
+ }
462
+
463
+ const result = {
464
+ // File existence
465
+ state_exists: pathExistsInternal(cwd, planningRelPath(STATE_FILE)),
466
+ roadmap_exists: pathExistsInternal(cwd, planningRelPath(ROADMAP_FILE)),
467
+ project_exists: pathExistsInternal(cwd, planningRelPath(PROJECT_FILE)),
468
+ planning_exists: pathExistsInternal(cwd, PLANNING_DIR),
469
+
470
+ // File paths
471
+ state_path: planningRelPath(STATE_FILE),
472
+ roadmap_path: planningRelPath(ROADMAP_FILE),
473
+ project_path: planningRelPath(PROJECT_FILE),
474
+
475
+ // Agent state
476
+ has_interrupted_agent: !!interruptedAgentId,
477
+ interrupted_agent_id: interruptedAgentId,
478
+
479
+ // Config
480
+ commit_docs: config.commit_docs,
481
+ };
482
+
483
+ output(result, raw);
484
+ }
485
+
486
+ /**
487
+ * Bootstrap context for work verification: models, phase info, existing verification artifacts.
488
+ * @param {string} cwd - Working directory path
489
+ * @param {string} phase - Phase number to verify
490
+ * @param {boolean} raw - If true, output raw value instead of JSON
491
+ * @returns {void}
492
+ */
493
+ function cmdInitVerifyWork(cwd, phase, raw) {
494
+ if (!phase) {
495
+ error('phase required for init verify-work');
496
+ }
497
+
498
+ const config = loadConfig(cwd);
499
+ const phaseInfo = findPhaseInternal(cwd, phase);
500
+
501
+ const result = {
502
+ // Models
503
+ planner_model: resolveModelInternal(cwd, 'pan-planner'),
504
+ checker_model: resolveModelInternal(cwd, 'pan-plan-checker'),
505
+
506
+ // Config
507
+ commit_docs: config.commit_docs,
508
+
509
+ // Phase info
510
+ phase_found: !!phaseInfo,
511
+ phase_dir: phaseInfo?.directory || null,
512
+ phase_number: phaseInfo?.phase_number || null,
513
+ phase_name: phaseInfo?.phase_name || null,
514
+
515
+ // Existing artifacts
516
+ has_verification: phaseInfo?.has_verification || false,
517
+ };
518
+
519
+ output(result, raw);
520
+ }
521
+
522
+ /**
523
+ * Bootstrap context for phase operations: config, artifacts, and context/research file paths.
524
+ * @param {string} cwd - Working directory path
525
+ * @param {string} phase - Phase number to operate on
526
+ * @param {boolean} raw - If true, output raw value instead of JSON
527
+ * @returns {void}
528
+ */
529
+ function cmdInitPhaseOp(cwd, phase, raw) {
530
+ const config = loadConfig(cwd);
531
+ let phaseInfo = findPhaseInternal(cwd, phase);
532
+
533
+ // Fallback to roadmap.md if no directory exists (e.g., Plans: TBD)
534
+ if (!phaseInfo) {
535
+ const roadmapPhase = getRoadmapPhaseInternal(cwd, phase);
536
+ if (roadmapPhase?.found) {
537
+ const phaseName = roadmapPhase.phase_name;
538
+ phaseInfo = {
539
+ found: true,
540
+ directory: null,
541
+ phase_number: roadmapPhase.phase_number,
542
+ phase_name: phaseName,
543
+ phase_slug: phaseName ? generateSlugInternal(phaseName) : null,
544
+ plans: [],
545
+ summaries: [],
546
+ incomplete_plans: [],
547
+ has_research: false,
548
+ has_context: false,
549
+ has_verification: false,
550
+ };
551
+ }
552
+ }
553
+
554
+ const result = {
555
+ // Config
556
+ commit_docs: config.commit_docs,
557
+ brave_search: config.brave_search,
558
+
559
+ // Phase info
560
+ phase_found: !!phaseInfo,
561
+ phase_dir: phaseInfo?.directory || null,
562
+ phase_number: phaseInfo?.phase_number || null,
563
+ phase_name: phaseInfo?.phase_name || null,
564
+ phase_slug: phaseInfo?.phase_slug || null,
565
+ padded_phase: phaseInfo?.phase_number?.padStart(2, '0') || null,
566
+
567
+ // Existing artifacts
568
+ has_research: phaseInfo?.has_research || false,
569
+ has_context: phaseInfo?.has_context || false,
570
+ has_plans: (phaseInfo?.plans?.length || 0) > 0,
571
+ has_verification: phaseInfo?.has_verification || false,
572
+ plan_count: phaseInfo?.plans?.length || 0,
573
+
574
+ // File existence
575
+ roadmap_exists: pathExistsInternal(cwd, planningRelPath(ROADMAP_FILE)),
576
+ planning_exists: pathExistsInternal(cwd, PLANNING_DIR),
577
+
578
+ // File paths
579
+ state_path: planningRelPath(STATE_FILE),
580
+ roadmap_path: planningRelPath(ROADMAP_FILE),
581
+ requirements_path: planningRelPath(REQUIREMENTS_FILE),
582
+ };
583
+
584
+ if (phaseInfo?.directory) {
585
+ // Discover optional artifact files (CONTEXT, RESEARCH, VERIFICATION, UAT)
586
+ attachPhaseArtifactPaths(result, cwd, phaseInfo.directory);
587
+ }
588
+
589
+ output(result, raw);
590
+ }
591
+
592
+ /**
593
+ * Bootstrap context for todo management: config, pending todo inventory, and paths.
594
+ * @param {string} cwd - Working directory path
595
+ * @param {string} area - Optional area filter for todos
596
+ * @param {boolean} raw - If true, output raw value instead of JSON
597
+ * @returns {void}
598
+ */
599
+ function cmdInitTodos(cwd, area, raw) {
600
+ const config = loadConfig(cwd);
601
+ const now = new Date();
602
+
603
+ const { count, todos } = scanPendingTodos(cwd, area);
604
+
605
+ const result = {
606
+ commit_docs: config.commit_docs,
607
+ date: now.toISOString().split('T')[0],
608
+ timestamp: now.toISOString(),
609
+ todo_count: count,
610
+ todos,
611
+ area_filter: area || null,
612
+ pending_dir: planningRelPath('todos/pending'),
613
+ completed_dir: planningRelPath('todos/completed'),
614
+ planning_exists: pathExistsInternal(cwd, PLANNING_DIR),
615
+ todos_dir_exists: pathExistsInternal(cwd, planningRelPath('todos')),
616
+ pending_dir_exists: pathExistsInternal(cwd, planningRelPath('todos/pending')),
617
+ };
618
+
619
+ output(result, raw);
620
+ }
621
+
622
+ /**
623
+ * Bootstrap context for milestone operations: phase counts, archive info, file existence.
624
+ * @param {string} cwd - Working directory path
625
+ * @param {boolean} raw - If true, output raw value instead of JSON
626
+ * @returns {void}
627
+ */
628
+ function cmdInitMilestoneOp(cwd, raw) {
629
+ const config = loadConfig(cwd);
630
+ const milestone = getMilestoneInfo(cwd);
631
+
632
+ // Count phases
633
+ let phaseCount = 0;
634
+ let completedPhases = 0;
635
+ const phasesDirPath = phasesPath(cwd);
636
+ try {
637
+ const entries = fs.readdirSync(phasesDirPath, { withFileTypes: true });
638
+ const dirNames = entries.filter(entry => entry.isDirectory()).map(entry => entry.name);
639
+ phaseCount = dirNames.length;
640
+
641
+ // Count phases with summaries (completed)
642
+ for (const dirName of dirNames) {
643
+ try {
644
+ const phaseFiles = fs.readdirSync(path.join(phasesDirPath, dirName));
645
+ const hasSummary = phaseFiles.some(isSummaryFile);
646
+ if (hasSummary) completedPhases++;
647
+ } catch {
648
+ // Phase directory unreadable -- skip
649
+ }
650
+ }
651
+ } catch {
652
+ // Phases directory does not exist yet
653
+ }
654
+
655
+ // Check archive
656
+ const archiveDirPath = path.join(planningPath(cwd), MILESTONES_DIR);
657
+ let archivedMilestones = [];
658
+ try {
659
+ archivedMilestones = fs.readdirSync(archiveDirPath, { withFileTypes: true })
660
+ .filter(entry => entry.isDirectory())
661
+ .map(entry => entry.name);
662
+ } catch {
663
+ // Archive directory does not exist yet
664
+ }
665
+
666
+ const result = {
667
+ // Config
668
+ commit_docs: config.commit_docs,
669
+
670
+ // Current milestone
671
+ milestone_version: milestone.version,
672
+ milestone_name: milestone.name,
673
+ milestone_slug: generateSlugInternal(milestone.name),
674
+
675
+ // Phase counts
676
+ phase_count: phaseCount,
677
+ completed_phases: completedPhases,
678
+ all_phases_complete: phaseCount > 0 && phaseCount === completedPhases,
679
+
680
+ // Archive
681
+ archived_milestones: archivedMilestones,
682
+ archive_count: archivedMilestones.length,
683
+
684
+ // File existence
685
+ project_exists: pathExistsInternal(cwd, planningRelPath(PROJECT_FILE)),
686
+ roadmap_exists: pathExistsInternal(cwd, planningRelPath(ROADMAP_FILE)),
687
+ state_exists: pathExistsInternal(cwd, planningRelPath(STATE_FILE)),
688
+ archive_exists: pathExistsInternal(cwd, planningRelPath(MILESTONES_DIR)),
689
+ phases_dir_exists: pathExistsInternal(cwd, planningRelPath(PHASES_DIR)),
690
+ };
691
+
692
+ output(result, raw);
693
+ }
694
+
695
+ /**
696
+ * Bootstrap context for codebase mapping: mapper model, existing maps, config flags.
697
+ * @param {string} cwd - Working directory path
698
+ * @param {boolean} raw - If true, output raw value instead of JSON
699
+ * @returns {void}
700
+ */
701
+ function cmdInitMapCodebase(cwd, raw) {
702
+ const config = loadConfig(cwd);
703
+
704
+ // Check for existing codebase maps
705
+ const codebaseDirPath = path.join(planningPath(cwd), CODEBASE_DIR);
706
+ let existingMaps = [];
707
+ try {
708
+ existingMaps = fs.readdirSync(codebaseDirPath).filter(filename => filename.endsWith('.md'));
709
+ } catch {
710
+ // Codebase directory does not exist yet
711
+ }
712
+
713
+ const result = {
714
+ // Models
715
+ mapper_model: resolveModelInternal(cwd, 'pan-document_code'),
716
+
717
+ // Config
718
+ commit_docs: config.commit_docs,
719
+ search_gitignored: config.search_gitignored,
720
+ parallelization: config.parallelization,
721
+
722
+ // Paths
723
+ codebase_dir: planningRelPath(CODEBASE_DIR),
724
+
725
+ // Existing maps
726
+ existing_maps: existingMaps,
727
+ has_maps: existingMaps.length > 0,
728
+
729
+ // File existence
730
+ planning_exists: pathExistsInternal(cwd, PLANNING_DIR),
731
+ codebase_dir_exists: pathExistsInternal(cwd, planningRelPath(CODEBASE_DIR)),
732
+
733
+ // Language detection
734
+ ...(() => {
735
+ const langInfo = detectLanguages(cwd);
736
+ return {
737
+ supported_languages: [langInfo.primary, ...langInfo.secondary].filter(Boolean),
738
+ file_count: langInfo.file_count,
739
+ };
740
+ })(),
741
+
742
+ // Focus areas
743
+ focus_areas: ['tech', 'arch', 'quality', 'concerns', 'relationships', 'practices'],
744
+ };
745
+
746
+ output(result, raw);
747
+ }
748
+
749
+ /**
750
+ * Bootstrap context for progress display: phase analysis, current/next phase, paused state.
751
+ * @param {string} cwd - Working directory path
752
+ * @param {boolean} raw - If true, output raw value instead of JSON
753
+ * @returns {void}
754
+ */
755
+ /**
756
+ * Scan all phase directories and return phase info, current phase, and next phase.
757
+ * @param {string} cwd - Working directory path
758
+ * @returns {{ phases: Object[], currentPhase: Object|null, nextPhase: Object|null }}
759
+ */
760
+ function scanAllPhases(cwd) {
761
+ const phasesDirPath = phasesPath(cwd);
762
+ const phases = [];
763
+ let currentPhase = null;
764
+ let nextPhase = null;
765
+
766
+ try {
767
+ const entries = fs.readdirSync(phasesDirPath, { withFileTypes: true });
768
+ const dirNames = entries.filter(entry => entry.isDirectory()).map(entry => entry.name).sort();
769
+
770
+ for (const dirName of dirNames) {
771
+ const dirMatch = dirName.match(/^(\d+(?:\.\d+)*)-?(.*)/);
772
+ const phaseNumber = dirMatch ? dirMatch[1] : dirName;
773
+ const phaseName = dirMatch && dirMatch[2] ? dirMatch[2] : null;
774
+
775
+ const phaseFullPath = path.join(phasesDirPath, dirName);
776
+ let phaseFiles;
777
+ try { phaseFiles = fs.readdirSync(phaseFullPath); } catch { continue; }
778
+
779
+ const plans = phaseFiles.filter(isPlanFile);
780
+ const summaries = phaseFiles.filter(isSummaryFile);
781
+ const hasResearch = phaseFiles.some(isResearchFile);
782
+
783
+ const rawStatus = classifyPhaseStatus(plans.length, summaries.length, { hasResearch });
784
+ const status = rawStatus === 'partial' || rawStatus === 'planned' ? 'in_progress' :
785
+ rawStatus === 'discussed' || rawStatus === 'empty' ? 'pending' :
786
+ rawStatus;
787
+
788
+ const phaseInfo = {
789
+ number: phaseNumber,
790
+ name: phaseName,
791
+ directory: toPosix(path.join(PLANNING_DIR, PHASES_DIR, dirName)),
792
+ status,
793
+ plan_count: plans.length,
794
+ summary_count: summaries.length,
795
+ has_research: hasResearch,
796
+ };
797
+
798
+ phases.push(phaseInfo);
799
+
800
+ if (!currentPhase && (status === 'in_progress' || status === 'researched')) {
801
+ currentPhase = phaseInfo;
802
+ }
803
+ if (!nextPhase && status === 'pending') {
804
+ nextPhase = phaseInfo;
805
+ }
806
+ }
807
+ } catch {
808
+ // Phases directory does not exist yet
809
+ }
810
+
811
+ return { phases, currentPhase, nextPhase };
812
+ }
813
+
814
+ function cmdInitProgress(cwd, raw) {
815
+ const config = loadConfig(cwd);
816
+ const milestone = getMilestoneInfo(cwd);
817
+
818
+ const { phases, currentPhase, nextPhase } = scanAllPhases(cwd);
819
+
820
+ // Check for paused work
821
+ let pausedAt = null;
822
+ try {
823
+ const stateContent = fs.readFileSync(path.join(planningPath(cwd), STATE_FILE), 'utf-8');
824
+ const pauseMatch = stateContent.match(/\*\*Paused At:\*\*\s*(.+)/);
825
+ if (pauseMatch) pausedAt = pauseMatch[1].trim();
826
+ } catch {
827
+ // state.md does not exist yet -- no paused state
828
+ }
829
+
830
+ const result = {
831
+ // Models
832
+ executor_model: resolveModelInternal(cwd, 'pan-executor'),
833
+ planner_model: resolveModelInternal(cwd, 'pan-planner'),
834
+
835
+ // Config
836
+ commit_docs: config.commit_docs,
837
+
838
+ // Milestone
839
+ milestone_version: milestone.version,
840
+ milestone_name: milestone.name,
841
+
842
+ // Phase overview
843
+ phases,
844
+ phase_count: phases.length,
845
+ completed_count: phases.filter(phaseEntry => phaseEntry.status === 'complete').length,
846
+ in_progress_count: phases.filter(phaseEntry => phaseEntry.status === 'in_progress').length,
847
+
848
+ // Current state
849
+ current_phase: currentPhase,
850
+ next_phase: nextPhase,
851
+ paused_at: pausedAt,
852
+ has_work_in_progress: !!currentPhase,
853
+
854
+ // File existence
855
+ project_exists: pathExistsInternal(cwd, planningRelPath(PROJECT_FILE)),
856
+ roadmap_exists: pathExistsInternal(cwd, planningRelPath(ROADMAP_FILE)),
857
+ state_exists: pathExistsInternal(cwd, planningRelPath(STATE_FILE)),
858
+ // File paths
859
+ state_path: planningRelPath(STATE_FILE),
860
+ roadmap_path: planningRelPath(ROADMAP_FILE),
861
+ project_path: planningRelPath(PROJECT_FILE),
862
+ config_path: planningRelPath(CONFIG_FILE),
863
+ };
864
+
865
+ output(result, raw);
866
+ }
867
+
868
+ module.exports = {
869
+ cmdInitExecutePhase,
870
+ cmdInitPlanPhase,
871
+ cmdInitNewProject,
872
+ cmdInitNewMilestone,
873
+ cmdInitQuick,
874
+ cmdInitResume,
875
+ cmdInitVerifyWork,
876
+ cmdInitPhaseOp,
877
+ cmdInitTodos,
878
+ cmdInitMilestoneOp,
879
+ cmdInitMapCodebase,
880
+ cmdInitProgress,
881
+ };