@jakkrichm/create-nexus-devflow 2.0.25 → 2.1.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.
Files changed (147) hide show
  1. package/README.md +30 -8
  2. package/dist/bin/create-nexus-devflow.d.ts +22 -1
  3. package/dist/bin/create-nexus-devflow.js +658 -11
  4. package/dist/bin/create-nexus-devflow.js.map +1 -1
  5. package/dist/lib/branch-context.d.ts +39 -0
  6. package/dist/lib/branch-context.js +196 -0
  7. package/dist/lib/branch-context.js.map +1 -0
  8. package/dist/lib/code-graph.d.ts +30 -0
  9. package/dist/lib/code-graph.js +209 -0
  10. package/dist/lib/code-graph.js.map +1 -0
  11. package/dist/lib/command-catalog.d.ts +11 -0
  12. package/dist/lib/command-catalog.js +63 -0
  13. package/dist/lib/command-catalog.js.map +1 -0
  14. package/dist/lib/context-slicer.d.ts +31 -0
  15. package/dist/lib/context-slicer.js +234 -0
  16. package/dist/lib/context-slicer.js.map +1 -0
  17. package/dist/lib/current-work.js +97 -49
  18. package/dist/lib/current-work.js.map +1 -1
  19. package/dist/lib/dashboard-page.d.ts +2 -0
  20. package/dist/lib/dashboard-page.js +285 -0
  21. package/dist/lib/dashboard-page.js.map +1 -0
  22. package/dist/lib/dashboard-snapshot.d.ts +62 -0
  23. package/dist/lib/dashboard-snapshot.js +114 -0
  24. package/dist/lib/dashboard-snapshot.js.map +1 -0
  25. package/dist/lib/dashboard.d.ts +2 -0
  26. package/dist/lib/dashboard.js +398 -8
  27. package/dist/lib/dashboard.js.map +1 -1
  28. package/dist/lib/discoveries.d.ts +19 -0
  29. package/dist/lib/discoveries.js +81 -0
  30. package/dist/lib/discoveries.js.map +1 -0
  31. package/dist/lib/doctor.d.ts +26 -0
  32. package/dist/lib/doctor.js +474 -0
  33. package/dist/lib/doctor.js.map +1 -0
  34. package/dist/lib/drift-reconciler.d.ts +38 -0
  35. package/dist/lib/drift-reconciler.js +155 -0
  36. package/dist/lib/drift-reconciler.js.map +1 -0
  37. package/dist/lib/findings.d.ts +26 -2
  38. package/dist/lib/findings.js +165 -1
  39. package/dist/lib/findings.js.map +1 -1
  40. package/dist/lib/gatekeeper.d.ts +20 -0
  41. package/dist/lib/gatekeeper.js +106 -0
  42. package/dist/lib/gatekeeper.js.map +1 -0
  43. package/dist/lib/git-hooks.d.ts +16 -0
  44. package/dist/lib/git-hooks.js +103 -0
  45. package/dist/lib/git-hooks.js.map +1 -0
  46. package/dist/lib/history.d.ts +6 -1
  47. package/dist/lib/history.js +98 -11
  48. package/dist/lib/history.js.map +1 -1
  49. package/dist/lib/ide-extension.d.ts +38 -0
  50. package/dist/lib/ide-extension.js +61 -0
  51. package/dist/lib/ide-extension.js.map +1 -0
  52. package/dist/lib/ideas.d.ts +26 -0
  53. package/dist/lib/ideas.js +179 -0
  54. package/dist/lib/ideas.js.map +1 -0
  55. package/dist/lib/mcp.d.ts +36 -0
  56. package/dist/lib/mcp.js +653 -0
  57. package/dist/lib/mcp.js.map +1 -0
  58. package/dist/lib/status.d.ts +3 -1
  59. package/dist/lib/status.js +60 -6
  60. package/dist/lib/status.js.map +1 -1
  61. package/dist/lib/swarm-orchestrator.d.ts +31 -0
  62. package/dist/lib/swarm-orchestrator.js +134 -0
  63. package/dist/lib/swarm-orchestrator.js.map +1 -0
  64. package/dist/lib/update.js +2 -2
  65. package/dist/lib/update.js.map +1 -1
  66. package/dist/lib/version-check.d.ts +22 -0
  67. package/dist/lib/version-check.js +59 -0
  68. package/dist/lib/version-check.js.map +1 -0
  69. package/dist/lib/webview-studio.d.ts +8 -0
  70. package/dist/lib/webview-studio.js +463 -0
  71. package/dist/lib/webview-studio.js.map +1 -0
  72. package/dist/lib/workflow-state.d.ts +23 -0
  73. package/dist/lib/workflow-state.js +128 -0
  74. package/dist/lib/workflow-state.js.map +1 -0
  75. package/dist/scripts/prepare-template.js +3 -3
  76. package/package.json +1 -1
  77. package/template/{.claude/skills/00-discover → .agents/skills/00-explore}/SKILL.md +10 -10
  78. package/template/.agents/skills/10-define/SKILL.md +4 -4
  79. package/template/.agents/skills/20-spec/SKILL.md +2 -3
  80. package/template/.agents/skills/30-plan/SKILL.md +2 -3
  81. package/template/.agents/skills/40-execute/SKILL.md +2 -2
  82. package/template/.agents/skills/50-verify/SKILL.md +2 -2
  83. package/template/.agents/skills/60-report/SKILL.md +3 -3
  84. package/template/{.claude/skills/70-release → .agents/skills/70-deliver}/SKILL.md +7 -13
  85. package/template/.agents/skills/adopt/SKILL.md +136 -73
  86. package/template/.agents/skills/audit/SKILL.md +275 -0
  87. package/template/.agents/skills/autopilot/SKILL.md +228 -147
  88. package/template/.agents/skills/brainstorm/SKILL.md +3 -3
  89. package/template/.agents/skills/brief/SKILL.md +74 -51
  90. package/template/.agents/skills/check/SKILL.md +96 -76
  91. package/template/.agents/skills/ci/SKILL.md +140 -61
  92. package/template/.agents/skills/complete/SKILL.md +156 -101
  93. package/template/.agents/skills/convert-any-to-md/SKILL.md +2 -2
  94. package/template/.agents/skills/debug/SKILL.md +124 -49
  95. package/template/.agents/skills/devflow/SKILL.md +16 -10
  96. package/template/.agents/skills/discovery/SKILL.md +166 -0
  97. package/template/.agents/skills/doctor/SKILL.md +188 -72
  98. package/template/.agents/skills/feature/SKILL.md +195 -102
  99. package/template/.agents/skills/fix/SKILL.md +41 -90
  100. package/template/.agents/skills/idea/SKILL.md +3 -3
  101. package/template/.agents/skills/implement/SKILL.md +189 -46
  102. package/template/.agents/skills/onboard/SKILL.md +215 -85
  103. package/template/.agents/skills/overview/SKILL.md +51 -85
  104. package/template/.agents/skills/prototype/SKILL.md +82 -27
  105. package/template/.agents/skills/release/SKILL.md +160 -0
  106. package/template/.agents/skills/report-html/SKILL.md +2 -2
  107. package/template/.agents/skills/rollback/SKILL.md +123 -77
  108. package/template/.agents/skills/status/SKILL.md +109 -0
  109. package/template/.agents/skills/test/SKILL.md +2 -2
  110. package/template/.agents/skills/tests/SKILL.md +126 -0
  111. package/template/.agents/skills/try/SKILL.md +77 -65
  112. package/template/{.agents/skills/00-discover → .claude/skills/00-explore}/SKILL.md +9 -9
  113. package/template/.claude/skills/10-define/SKILL.md +2 -2
  114. package/template/.claude/skills/20-spec/SKILL.md +1 -1
  115. package/template/.claude/skills/30-plan/SKILL.md +1 -1
  116. package/template/.claude/skills/60-report/SKILL.md +1 -1
  117. package/template/{.agents/skills/70-release → .claude/skills/70-deliver}/SKILL.md +6 -12
  118. package/template/.claude/skills/adopt/SKILL.md +2 -2
  119. package/template/.claude/skills/audit/SKILL.md +141 -0
  120. package/template/.claude/skills/autopilot/SKILL.md +74 -52
  121. package/template/.claude/skills/brief/SKILL.md +67 -45
  122. package/template/.claude/skills/ci/SKILL.md +1 -1
  123. package/template/.claude/skills/complete/SKILL.md +1 -1
  124. package/template/.claude/skills/debug/SKILL.md +1 -1
  125. package/template/.claude/skills/devflow/SKILL.md +7 -7
  126. package/template/.claude/skills/discovery/SKILL.md +145 -0
  127. package/template/.claude/skills/doctor/SKILL.md +1 -1
  128. package/template/.claude/skills/feature/SKILL.md +67 -18
  129. package/template/.claude/skills/fix/SKILL.md +1 -1
  130. package/template/.claude/skills/idea/SKILL.md +2 -2
  131. package/template/.claude/skills/onboard/SKILL.md +3 -3
  132. package/template/.claude/skills/overview/SKILL.md +39 -88
  133. package/template/.claude/skills/prototype/SKILL.md +1 -1
  134. package/template/.claude/skills/release/SKILL.md +171 -0
  135. package/template/.claude/skills/rollback/SKILL.md +2 -2
  136. package/template/AGENTS.md +5 -5
  137. package/template/devflow/build-plan.md +62 -0
  138. package/template/devflow/context/ai-interaction.md +4 -4
  139. package/template/devflow/context/coding-standards.md +3 -3
  140. package/template/devflow/context/current-stage.md +1 -1
  141. package/template/devflow/context/findings.md +1 -1
  142. package/template/devflow/history/HISTORY.md +2 -2
  143. package/template/devflow/project-plan.md +79 -0
  144. package/template/devflow/reference/mockup.html +476 -0
  145. package/template/devflow/reference/project-overview-template.md +39 -0
  146. package/template/devflow/reference/running-id-contract.md +24 -2
  147. package/template/devflow/reference/studio.html +504 -0
@@ -5,11 +5,25 @@ import readline from "node:readline/promises";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { openDashboard, startDashboardServer } from "../lib/dashboard.js";
7
7
  import { formatHumanStatus, readProjectStatus, shouldUseColor } from "../lib/status.js";
8
+ import { addIdea, formatIdeasHuman, readIdeas } from "../lib/ideas.js";
9
+ import { addFinding, formatFindingsHuman, readFindings, resolveFinding } from "../lib/findings.js";
10
+ import { formatDoctorHuman, runDoctor } from "../lib/doctor.js";
11
+ import { formatHistoryHuman, readHistory } from "../lib/history.js";
12
+ import { evaluateGate, formatGateReport } from "../lib/gatekeeper.js";
13
+ import { sliceContextForStage } from "../lib/context-slicer.js";
14
+ import { detectGitDrift, reconcileState } from "../lib/drift-reconciler.js";
15
+ import { renderStudioHtml } from "../lib/webview-studio.js";
16
+ import { buildCodeGraph, calculateBlastRadius } from "../lib/code-graph.js";
17
+ import { generateSwarmPlan } from "../lib/swarm-orchestrator.js";
18
+ import { startMcpServer } from "../lib/mcp.js";
19
+ import { installGitHook, uninstallGitHooks } from "../lib/git-hooks.js";
8
20
  import { createSpinner, createStyle } from "../lib/ui.js";
9
21
  import { applyPreparedUpdate, prepareUpdate } from "../lib/update.js";
10
22
  import { applyUninstall, prepareUninstall } from "../lib/uninstall.js";
11
23
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
- const packageRoot = path.resolve(__dirname, "..", "..");
24
+ const packageRoot = fsSync.existsSync(path.join(__dirname, "..", "package.json"))
25
+ ? path.resolve(__dirname, "..")
26
+ : path.resolve(__dirname, "..", "..");
13
27
  const templateRoot = path.join(packageRoot, "template");
14
28
  const adapterChoices = new Set(["codex", "antigravity", "claude", "copilot", "both", "all"]);
15
29
  async function main(args = process.argv.slice(2)) {
@@ -23,6 +37,146 @@ async function main(args = process.argv.slice(2)) {
23
37
  return;
24
38
  }
25
39
  const targetDir = path.resolve(process.cwd(), options.target || ".");
40
+ if (options.deprecatedUi) {
41
+ console.warn("Warning: `ui` is deprecated; use `dashboard` instead.");
42
+ }
43
+ if (options.command === "mcp") {
44
+ startMcpServer(targetDir);
45
+ return;
46
+ }
47
+ if (options.command === "slice") {
48
+ const stage = options.sliceStage || "implement";
49
+ const sliceResult = await sliceContextForStage(targetDir, stage, { maxTokens: options.maxTokens });
50
+ if (options.json) {
51
+ console.log(JSON.stringify(sliceResult, null, 2));
52
+ }
53
+ else {
54
+ console.log(`[DevFlow JIT Context Slice - Stage: ${sliceResult.stage}]`);
55
+ console.log(`Estimated Tokens: ~${sliceResult.estimatedTokens} (Reduction: ~${sliceResult.reductionPercentage}%)\n`);
56
+ console.log(sliceResult.content);
57
+ }
58
+ return;
59
+ }
60
+ if (options.command === "drift") {
61
+ const drift = await detectGitDrift(targetDir);
62
+ if (options.json) {
63
+ console.log(JSON.stringify(drift, null, 2));
64
+ }
65
+ else {
66
+ const style = createStyle();
67
+ if (!drift.hasDrift && drift.phantomFiles.length === 0) {
68
+ console.log(style.green("✔ No Git drift detected. Living spec is in sync with repository files."));
69
+ }
70
+ else {
71
+ console.log(style.bold(style.yellow("Git Drift Detection Report:")));
72
+ if (drift.undocumentedFiles.length > 0) {
73
+ console.log(style.red(` - Undocumented modified files (${drift.undocumentedFiles.length}):`));
74
+ for (const f of drift.undocumentedFiles) {
75
+ console.log(` ✖ ${f}`);
76
+ }
77
+ }
78
+ if (drift.phantomFiles.length > 0) {
79
+ console.log(style.yellow(` - Phantom spec files (not modified in git) (${drift.phantomFiles.length}):`));
80
+ for (const f of drift.phantomFiles) {
81
+ console.log(` ⚠ ${f}`);
82
+ }
83
+ }
84
+ if (drift.stageDrift.isDrifted) {
85
+ console.log(style.yellow(` - Stage alignment drift: Active branch '${drift.stageDrift.activeBranch}' vs Stage ID '${drift.stageDrift.stageRunningId}'`));
86
+ }
87
+ console.log(`\nRun ${style.cyan("nexus-devflow reconcile --fix")} to auto-heal spec alignment.`);
88
+ }
89
+ }
90
+ return;
91
+ }
92
+ if (options.command === "reconcile") {
93
+ const result = await reconcileState(targetDir, {
94
+ autoAddUndocumented: options.fix,
95
+ healStage: options.fix
96
+ });
97
+ if (options.json) {
98
+ console.log(JSON.stringify(result, null, 2));
99
+ }
100
+ else {
101
+ const style = createStyle();
102
+ if (result.reconciled) {
103
+ console.log(style.green(`✔ ${result.message}`));
104
+ if (result.addedFiles.length > 0) {
105
+ for (const f of result.addedFiles) {
106
+ console.log(style.dim(` + Added to spec: ${f}`));
107
+ }
108
+ }
109
+ }
110
+ else {
111
+ console.log(style.dim(result.message));
112
+ }
113
+ }
114
+ return;
115
+ }
116
+ if (options.command === "studio") {
117
+ const html = await renderStudioHtml(targetDir);
118
+ if (options.json) {
119
+ console.log(JSON.stringify({ html }, null, 2));
120
+ }
121
+ else {
122
+ console.log(html);
123
+ }
124
+ return;
125
+ }
126
+ if (options.command === "swarm") {
127
+ const plan = await generateSwarmPlan(targetDir);
128
+ if (options.json) {
129
+ console.log(JSON.stringify(plan, null, 2));
130
+ }
131
+ else {
132
+ const style = createStyle();
133
+ console.log(style.bold(style.cyan(`[Nexus-DevFlow Multi-Agent Swarm Matrix: ${plan.runId}]`)));
134
+ console.log(`Title: ${plan.title} (Strategy: ${plan.executionStrategy})\n`);
135
+ for (const t of plan.tasks) {
136
+ const roleIcon = t.role === "coder" ? "👨‍💻" : t.role === "qa" ? "🕵️" : t.role === "security" ? "🛡️" : "👑";
137
+ console.log(` ${roleIcon} ${style.bold(t.id)}: ${t.title} [Role: ${t.role.toUpperCase()}]`);
138
+ console.log(style.dim(` Context: ${t.requiredContext.join(", ")}`));
139
+ console.log(style.dim(` Verify : ${t.verificationCriterion}`));
140
+ }
141
+ }
142
+ return;
143
+ }
144
+ if (options.command === "graph") {
145
+ const graph = await buildCodeGraph(targetDir);
146
+ if (options.graphFile) {
147
+ const blast = calculateBlastRadius(graph, options.graphFile);
148
+ if (options.json) {
149
+ console.log(JSON.stringify(blast, null, 2));
150
+ }
151
+ else {
152
+ const style = createStyle();
153
+ console.log(style.bold(style.cyan(`[Code Graph Blast Radius: ${blast.targetFile}]`)));
154
+ console.log(`Impact Score: ${blast.impactScore} | Total Affected: ${blast.totalAffected} files\n`);
155
+ if (blast.directDependents.length > 0) {
156
+ console.log(style.bold("Direct Dependents:"));
157
+ for (const d of blast.directDependents)
158
+ console.log(` - ${d}`);
159
+ }
160
+ if (blast.transitiveDependents.length > 0) {
161
+ console.log(style.bold("Transitive Dependents:"));
162
+ for (const t of blast.transitiveDependents)
163
+ console.log(` ~ ${t}`);
164
+ }
165
+ }
166
+ }
167
+ else {
168
+ if (options.json) {
169
+ console.log(JSON.stringify({ totalFiles: graph.totalFiles, totalEdges: graph.totalEdges, files: Object.keys(graph.nodes) }, null, 2));
170
+ }
171
+ else {
172
+ const style = createStyle();
173
+ console.log(style.bold(style.cyan("[Nexus-DevFlow Semantic Code Graph]")));
174
+ console.log(`Indexed Files: ${graph.totalFiles} | Total Dependency Edges: ${graph.totalEdges}`);
175
+ console.log(`\nRun ${style.yellow("nexus-devflow graph --file <path>")} to calculate Blast Radius.`);
176
+ }
177
+ }
178
+ return;
179
+ }
26
180
  if (options.command === "status") {
27
181
  const status = await readProjectStatus(targetDir);
28
182
  console.log(options.json
@@ -30,7 +184,163 @@ async function main(args = process.argv.slice(2)) {
30
184
  : formatHumanStatus(status, { color: shouldUseColor() }));
31
185
  return;
32
186
  }
33
- if (options.command === "ui") {
187
+ if (options.command === "check-gate") {
188
+ const report = await evaluateGate(targetDir, {
189
+ strict: options.strict,
190
+ color: shouldUseColor()
191
+ });
192
+ if (options.json) {
193
+ console.log(JSON.stringify(report, null, 2));
194
+ }
195
+ else {
196
+ console.log(formatGateReport(report, { color: shouldUseColor() }));
197
+ }
198
+ if (!report.passed) {
199
+ process.exitCode = 1;
200
+ }
201
+ return;
202
+ }
203
+ if (options.command === "hook") {
204
+ if (options.subcommandAction === "uninstall") {
205
+ const result = await uninstallGitHooks(targetDir);
206
+ if (options.json) {
207
+ console.log(JSON.stringify(result, null, 2));
208
+ }
209
+ else {
210
+ const style = createStyle(shouldUseColor());
211
+ console.log(`\n${style.green("✔")} ${style.bold(result.message)}`);
212
+ }
213
+ return;
214
+ }
215
+ // Default: install
216
+ const hookType = options.hookType || "pre-commit";
217
+ const result = await installGitHook(targetDir, hookType, { strict: options.strict });
218
+ if (options.json) {
219
+ console.log(JSON.stringify(result, null, 2));
220
+ }
221
+ else {
222
+ const style = createStyle(shouldUseColor());
223
+ if (result.success) {
224
+ console.log(`\n${style.green("✔")} ${style.bold(result.message)}`);
225
+ console.log(` ${style.dim("Hook:")} ${style.cyan(result.path)}`);
226
+ }
227
+ else {
228
+ console.error(`\n${style.red("✖")} ${style.bold(result.message)}`);
229
+ process.exitCode = 1;
230
+ }
231
+ }
232
+ return;
233
+ }
234
+ if (options.command === "idea" || options.command === "ideas") {
235
+ if (options.subcommandAction === "add") {
236
+ const text = options.subcommandArg || "";
237
+ if (!text.trim()) {
238
+ throw new Error("Idea text is required. Example: nexus-devflow idea add \"My idea\"");
239
+ }
240
+ const created = await addIdea(targetDir, {
241
+ text,
242
+ title: options.ideaTitle
243
+ });
244
+ if (options.json) {
245
+ console.log(JSON.stringify(created, null, 2));
246
+ }
247
+ else {
248
+ const style = createStyle(shouldUseColor());
249
+ console.log(`\n${style.green("✔")} ${style.bold("Idea added successfully!")}`);
250
+ console.log(` ${style.dim("ID :")} ${style.bold(style.cyan(created.id))}`);
251
+ console.log(` ${style.dim("Title:")} ${style.bold(created.title)}`);
252
+ console.log(` ${style.dim("Start:")} ${style.yellow(`/feature ${created.id}`)} or ${style.yellow(`/00-explore ${created.id}`)}`);
253
+ }
254
+ return;
255
+ }
256
+ const ideas = await readIdeas(targetDir);
257
+ console.log(options.json
258
+ ? JSON.stringify(ideas, null, 2)
259
+ : formatIdeasHuman(ideas, { color: shouldUseColor() }));
260
+ return;
261
+ }
262
+ if (options.command === "findings") {
263
+ if (options.subcommandAction === "add") {
264
+ const title = options.subcommandArg || "";
265
+ if (!title.trim()) {
266
+ throw new Error('Finding title is required. Example: nexus-devflow findings add "Hardcoded secret" --severity P0');
267
+ }
268
+ const result = await addFinding(targetDir, title, {
269
+ id: options.findingId,
270
+ severity: options.findingSeverity,
271
+ status: options.findingStatus,
272
+ location: options.findingLocation,
273
+ impact: options.findingImpact,
274
+ remediation: options.findingRemediation
275
+ });
276
+ if (options.json) {
277
+ console.log(JSON.stringify(result, null, 2));
278
+ }
279
+ else {
280
+ const style = createStyle(shouldUseColor());
281
+ console.log(`\n${style.green("✔")} ${style.bold("Finding recorded successfully!")}`);
282
+ console.log(` ${style.dim("ID :")} ${style.bold(style.cyan(result.finding?.id || ""))}`);
283
+ const sev = result.finding?.severity || "P2";
284
+ const isBlocker = sev === "P0" || sev === "P1";
285
+ console.log(` ${style.dim("Severity:")} ${style.bold(isBlocker ? style.red(`[${sev}]`) : style.yellow(`[${sev}]`))}`);
286
+ console.log(` ${style.dim("Status :")} ${style.yellow(result.finding?.status || "")}`);
287
+ console.log(` ${style.dim("Title :")} ${style.bold(result.finding?.title || "")}`);
288
+ console.log(` ${style.dim("File :")} ${style.dim(result.filePath)}`);
289
+ }
290
+ return;
291
+ }
292
+ if (options.subcommandAction === "resolve") {
293
+ const findingId = options.subcommandArg || "";
294
+ if (!findingId.trim()) {
295
+ throw new Error("Finding ID is required. Example: nexus-devflow findings resolve FIND-001");
296
+ }
297
+ const statusToSet = options.findingStatus || "closed";
298
+ const result = await resolveFinding(targetDir, findingId, statusToSet);
299
+ if (options.json) {
300
+ console.log(JSON.stringify(result, null, 2));
301
+ }
302
+ else {
303
+ const style = createStyle(shouldUseColor());
304
+ if (result.success) {
305
+ console.log(`\n${style.green("✔")} ${style.bold(result.message)}`);
306
+ }
307
+ else {
308
+ console.error(`\n${style.red("✖")} ${style.bold(result.message)}`);
309
+ process.exitCode = 1;
310
+ }
311
+ }
312
+ return;
313
+ }
314
+ const findings = await readFindings(targetDir);
315
+ console.log(options.json
316
+ ? JSON.stringify(findings, null, 2)
317
+ : formatFindingsHuman(findings, {
318
+ blockersOnly: options.blockersOnly,
319
+ color: shouldUseColor()
320
+ }));
321
+ return;
322
+ }
323
+ if (options.command === "doctor") {
324
+ const report = await runDoctor(targetDir, {
325
+ fix: options.fix,
326
+ color: shouldUseColor()
327
+ });
328
+ console.log(options.json
329
+ ? JSON.stringify(report, null, 2)
330
+ : formatDoctorHuman(report, { color: shouldUseColor() }));
331
+ return;
332
+ }
333
+ if (options.command === "archive") {
334
+ const history = await readHistory(targetDir);
335
+ console.log(options.json
336
+ ? JSON.stringify(history, null, 2)
337
+ : formatHistoryHuman(history, {
338
+ statsOnly: options.statsOnly,
339
+ color: shouldUseColor()
340
+ }));
341
+ return;
342
+ }
343
+ if (options.command === "dashboard" || options.command === "ui") {
34
344
  const server = await startDashboardServer(targetDir);
35
345
  const style = createStyle();
36
346
  console.log(style.bold(style.cyan(`Nexus-DevFlow Dashboard live at ${server.url}`)));
@@ -137,6 +447,24 @@ async function main(args = process.argv.slice(2)) {
137
447
  }
138
448
  function parseArgs(args) {
139
449
  let command = "install";
450
+ let subcommandAction;
451
+ let subcommandArg;
452
+ let graphFile;
453
+ let sliceStage;
454
+ let maxTokens;
455
+ let hookType;
456
+ let ideaTitle;
457
+ let findingStatus;
458
+ let findingSeverity;
459
+ let findingId;
460
+ let findingLocation;
461
+ let findingImpact;
462
+ let findingRemediation;
463
+ let blockersOnly = false;
464
+ let fix = false;
465
+ let statsOnly = false;
466
+ let strict = false;
467
+ let deprecatedUi = false;
140
468
  let target = null;
141
469
  let adapter = "both";
142
470
  let force = false;
@@ -182,6 +510,137 @@ function parseArgs(args) {
182
510
  keepHistory = true;
183
511
  continue;
184
512
  }
513
+ if (arg === "--blockers") {
514
+ blockersOnly = true;
515
+ continue;
516
+ }
517
+ if (arg === "--file" && args[i + 1] && !args[i + 1].startsWith("-")) {
518
+ graphFile = args[i + 1];
519
+ i++;
520
+ continue;
521
+ }
522
+ if (arg === "--fix") {
523
+ fix = true;
524
+ continue;
525
+ }
526
+ if (arg === "--stats") {
527
+ statsOnly = true;
528
+ continue;
529
+ }
530
+ if (arg === "--strict") {
531
+ strict = true;
532
+ continue;
533
+ }
534
+ if (arg === "--title") {
535
+ const next = args[++i];
536
+ if (!next) {
537
+ throw new Error(`${arg} requires a title string`);
538
+ }
539
+ ideaTitle = next;
540
+ continue;
541
+ }
542
+ if (arg.startsWith("--title=")) {
543
+ ideaTitle = arg.slice("--title=".length);
544
+ continue;
545
+ }
546
+ if (arg === "--status") {
547
+ const next = args[++i];
548
+ if (!next) {
549
+ throw new Error(`${arg} requires a status string (e.g. closed, accepted, invalid)`);
550
+ }
551
+ findingStatus = next.toLowerCase();
552
+ continue;
553
+ }
554
+ if (arg.startsWith("--status=")) {
555
+ findingStatus = arg.slice("--status=".length).toLowerCase();
556
+ continue;
557
+ }
558
+ if (arg === "--severity" || arg === "-s") {
559
+ const next = args[++i];
560
+ if (!next) {
561
+ throw new Error(`${arg} requires a severity level (P0, P1, P2, P3)`);
562
+ }
563
+ const sev = next.toUpperCase();
564
+ if (sev !== "P0" && sev !== "P1" && sev !== "P2" && sev !== "P3") {
565
+ throw new Error(`Invalid severity "${next}". Expected one of: P0, P1, P2, P3`);
566
+ }
567
+ findingSeverity = sev;
568
+ continue;
569
+ }
570
+ if (arg.startsWith("--severity=")) {
571
+ const sev = arg.slice("--severity=".length).toUpperCase();
572
+ if (sev !== "P0" && sev !== "P1" && sev !== "P2" && sev !== "P3") {
573
+ throw new Error(`Invalid severity "${sev}". Expected one of: P0, P1, P2, P3`);
574
+ }
575
+ findingSeverity = sev;
576
+ continue;
577
+ }
578
+ if (arg === "--id") {
579
+ const next = args[++i];
580
+ if (!next)
581
+ throw new Error(`${arg} requires an ID string`);
582
+ findingId = next;
583
+ continue;
584
+ }
585
+ if (arg.startsWith("--id=")) {
586
+ findingId = arg.slice("--id=".length);
587
+ continue;
588
+ }
589
+ if (arg === "--location") {
590
+ const next = args[++i];
591
+ if (!next)
592
+ throw new Error(`${arg} requires a location string`);
593
+ findingLocation = next;
594
+ continue;
595
+ }
596
+ if (arg.startsWith("--location=")) {
597
+ findingLocation = arg.slice("--location=".length);
598
+ continue;
599
+ }
600
+ if (arg === "--impact") {
601
+ const next = args[++i];
602
+ if (!next)
603
+ throw new Error(`${arg} requires an impact string`);
604
+ findingImpact = next;
605
+ continue;
606
+ }
607
+ if (arg.startsWith("--impact=")) {
608
+ findingImpact = arg.slice("--impact=".length);
609
+ continue;
610
+ }
611
+ if (arg === "--remediation") {
612
+ const next = args[++i];
613
+ if (!next)
614
+ throw new Error(`${arg} requires a remediation string`);
615
+ findingRemediation = next;
616
+ continue;
617
+ }
618
+ if (arg.startsWith("--remediation=")) {
619
+ findingRemediation = arg.slice("--remediation=".length);
620
+ continue;
621
+ }
622
+ if (arg === "--stage") {
623
+ const next = args[++i];
624
+ if (!next)
625
+ throw new Error(`${arg} requires a stage name`);
626
+ sliceStage = next.toLowerCase();
627
+ continue;
628
+ }
629
+ if (arg.startsWith("--stage=")) {
630
+ sliceStage = arg.slice("--stage=".length).toLowerCase();
631
+ continue;
632
+ }
633
+ if (arg === "--max-tokens") {
634
+ const next = args[++i];
635
+ if (!next || isNaN(Number(next)))
636
+ throw new Error(`${arg} requires a number`);
637
+ maxTokens = Number(next);
638
+ continue;
639
+ }
640
+ if (arg.startsWith("--max-tokens=")) {
641
+ maxTokens = Number(arg.slice("--max-tokens=".length));
642
+ continue;
643
+ }
185
644
  if (arg === "--target" || arg === "-t") {
186
645
  const next = args[++i];
187
646
  if (!next) {
@@ -216,27 +675,164 @@ function parseArgs(args) {
216
675
  positional.push(arg);
217
676
  }
218
677
  if (positional.length > 0) {
219
- if (positional[0] === "status") {
678
+ const first = positional[0].toLowerCase();
679
+ if (first === "status") {
220
680
  command = "status";
221
681
  target = positional[1] || target || ".";
222
682
  }
223
- else if (positional[0] === "ui") {
224
- command = "ui";
683
+ else if (first === "mcp") {
684
+ command = "mcp";
685
+ target = positional[1] || target || ".";
686
+ }
687
+ else if (first === "slice") {
688
+ command = "slice";
689
+ if (positional[1] && !positional[1].startsWith("-")) {
690
+ sliceStage = positional[1].toLowerCase();
691
+ target = positional[2] || target || ".";
692
+ }
693
+ else {
694
+ target = positional[1] || target || ".";
695
+ }
696
+ }
697
+ else if (first === "drift") {
698
+ command = "drift";
699
+ target = positional[1] || target || ".";
700
+ }
701
+ else if (first === "reconcile") {
702
+ command = "reconcile";
703
+ target = positional[1] || target || ".";
704
+ }
705
+ else if (first === "studio") {
706
+ command = "studio";
707
+ target = positional[1] || target || ".";
708
+ }
709
+ else if (first === "swarm") {
710
+ command = "swarm";
225
711
  target = positional[1] || target || ".";
226
712
  }
227
- else if (positional[0] === "update") {
713
+ else if (first === "graph") {
714
+ command = "graph";
715
+ target = positional[1] || target || ".";
716
+ }
717
+ else if (first === "check-gate") {
718
+ command = "check-gate";
719
+ target = positional[1] || target || ".";
720
+ }
721
+ else if (first === "hook" || first === "hooks") {
722
+ command = "hook";
723
+ if (positional[1] === "uninstall") {
724
+ subcommandAction = "uninstall";
725
+ target = positional[2] || target || ".";
726
+ }
727
+ else if (positional[1] === "install") {
728
+ subcommandAction = "install";
729
+ if (positional[2] === "pre-commit" || positional[2] === "pre-push") {
730
+ hookType = positional[2];
731
+ target = positional[3] || target || ".";
732
+ }
733
+ else {
734
+ target = positional[2] || target || ".";
735
+ }
736
+ }
737
+ else if (positional[1] === "pre-commit" || positional[1] === "pre-push") {
738
+ subcommandAction = "install";
739
+ hookType = positional[1];
740
+ target = positional[2] || target || ".";
741
+ }
742
+ else {
743
+ subcommandAction = "install";
744
+ target = positional[1] || target || ".";
745
+ }
746
+ }
747
+ else if (first === "dashboard") {
748
+ command = "dashboard";
749
+ target = positional[1] || target || ".";
750
+ }
751
+ else if (first === "ui") {
752
+ command = "dashboard";
753
+ deprecatedUi = true;
754
+ target = positional[1] || target || ".";
755
+ }
756
+ else if (first === "update") {
228
757
  command = "update";
229
758
  target = positional[1] || target || ".";
230
759
  }
231
- else if (positional[0] === "uninstall") {
760
+ else if (first === "uninstall") {
232
761
  command = "uninstall";
233
762
  target = positional[1] || target || ".";
234
763
  }
235
- else if (positional[0] === "eject") {
764
+ else if (first === "eject") {
236
765
  command = "eject";
237
766
  target = positional[1] || target || ".";
238
767
  }
239
- else if (positional[0] === "install") {
768
+ else if (first === "idea" || first === "ideas") {
769
+ command = first === "idea" ? "idea" : "ideas";
770
+ if (positional[1] === "add") {
771
+ subcommandAction = "add";
772
+ subcommandArg = positional[2];
773
+ target = positional[3] || target || ".";
774
+ }
775
+ else if (positional[1] === "list") {
776
+ subcommandAction = "list";
777
+ target = positional[2] || target || ".";
778
+ }
779
+ else if (positional[1] && !positional[1].startsWith("-")) {
780
+ subcommandAction = "add";
781
+ subcommandArg = positional[1];
782
+ target = positional[2] || target || ".";
783
+ }
784
+ else {
785
+ subcommandAction = "list";
786
+ target = positional[1] || target || ".";
787
+ }
788
+ }
789
+ else if (first === "findings") {
790
+ command = "findings";
791
+ if (positional[1] === "add") {
792
+ subcommandAction = "add";
793
+ subcommandArg = positional[2];
794
+ target = positional[3] || target || ".";
795
+ }
796
+ else if (positional[1] === "resolve") {
797
+ subcommandAction = "resolve";
798
+ subcommandArg = positional[2];
799
+ target = positional[3] || target || ".";
800
+ }
801
+ else if (positional[1] === "list") {
802
+ subcommandAction = "list";
803
+ target = positional[2] || target || ".";
804
+ }
805
+ else if (positional[1] && !positional[1].startsWith("-")) {
806
+ subcommandAction = "add";
807
+ subcommandArg = positional[1];
808
+ target = positional[2] || target || ".";
809
+ }
810
+ else {
811
+ subcommandAction = "list";
812
+ target = positional[1] || target || ".";
813
+ }
814
+ }
815
+ else if (first === "doctor") {
816
+ command = "doctor";
817
+ target = positional[1] || target || ".";
818
+ }
819
+ else if (first === "archive") {
820
+ command = "archive";
821
+ if (positional[1] === "list") {
822
+ subcommandAction = "list";
823
+ target = positional[2] || target || ".";
824
+ }
825
+ else if (positional[1] === "stats") {
826
+ subcommandAction = "stats";
827
+ statsOnly = true;
828
+ target = positional[2] || target || ".";
829
+ }
830
+ else {
831
+ subcommandAction = "list";
832
+ target = positional[1] || target || ".";
833
+ }
834
+ }
835
+ else if (first === "install") {
240
836
  command = "install";
241
837
  target = positional[1] || target || ".";
242
838
  }
@@ -246,6 +842,24 @@ function parseArgs(args) {
246
842
  }
247
843
  return {
248
844
  command,
845
+ subcommandAction,
846
+ subcommandArg,
847
+ graphFile,
848
+ sliceStage,
849
+ maxTokens,
850
+ hookType,
851
+ ideaTitle,
852
+ findingStatus,
853
+ findingSeverity,
854
+ findingId,
855
+ findingLocation,
856
+ findingImpact,
857
+ findingRemediation,
858
+ blockersOnly,
859
+ fix,
860
+ statsOnly,
861
+ strict,
862
+ deprecatedUi,
249
863
  target,
250
864
  adapter,
251
865
  force,
@@ -282,18 +896,51 @@ ${style.bold(style.cyan("Nexus-DevFlow CLI"))} ${style.bold(`v${readPackageVersi
282
896
  ${style.bold("Usage:")}
283
897
  ${style.cyan("npx @jakkrichm/create-nexus-devflow")} [target-dir] [options]
284
898
  ${style.cyan("nexus-devflow status")} [target-dir] [options]
285
- ${style.cyan("nexus-devflow ui")} [target-dir] [options]
899
+ ${style.cyan("nexus-devflow mcp")} [target-dir]
900
+ ${style.cyan("nexus-devflow slice")} [--stage <stage>] [--max-tokens <num>] [--json]
901
+ ${style.cyan("nexus-devflow drift")} [target-dir] [--json]
902
+ ${style.cyan("nexus-devflow reconcile")} [target-dir] [--fix] [--json]
903
+ ${style.cyan("nexus-devflow studio")} [target-dir] [--json]
904
+ ${style.cyan("nexus-devflow swarm")} [target-dir] [--json]
905
+ ${style.cyan("nexus-devflow graph")} [target-dir] [--file <path>] [--json]
906
+ ${style.cyan("nexus-devflow check-gate")} [--strict] [--json]
907
+ ${style.cyan("nexus-devflow hook install")} [pre-commit|pre-push]
908
+ ${style.cyan("nexus-devflow hook uninstall")}
909
+ ${style.cyan("nexus-devflow dashboard")} [target-dir] [options]
910
+ ${style.cyan("nexus-devflow idea")} add "<text>" [--title "<title>"]
911
+ ${style.cyan("nexus-devflow ideas")} [list] [--json]
912
+ ${style.cyan("nexus-devflow findings add")} "<title>" [--severity P0|P1|P2|P3] [--location <loc>]
913
+ ${style.cyan("nexus-devflow findings")} [list] [--blockers] [--json]
914
+ ${style.cyan("nexus-devflow findings resolve")} <ID> [--status <status>]
915
+ ${style.cyan("nexus-devflow doctor")} [--fix] [--json]
916
+ ${style.cyan("nexus-devflow archive")} [list|stats] [--json]
286
917
  ${style.cyan("nexus-devflow update")} [target-dir] [options]
287
918
  ${style.cyan("nexus-devflow uninstall")} [target-dir] [options]
288
919
  ${style.cyan("nexus-devflow eject")} [target-dir] [options]
289
920
 
290
921
  ${style.bold("Commands:")}
291
922
  ${style.brightCyan("status")} Show project overview, progress, findings, git status, and next action
292
- ${style.brightCyan("ui")} Run local interactive web dashboard for Nexus-DevFlow
923
+ ${style.brightCyan("mcp")} Run Model Context Protocol (MCP) JSON-RPC Stdio Server for AI agents
924
+ ${style.brightCyan("slice")} Generate JIT stage-aware context slice (reduces AI tokens by 60-70%)
925
+ ${style.brightCyan("check-gate")} CI/CD quality gatekeeper check (returns exit code 0 or 1)
926
+ ${style.brightCyan("hook")} Install or remove local Git pre-commit/pre-push gatekeeper hooks
927
+ ${style.brightCyan("dashboard")} Run local interactive web dashboard for Nexus-DevFlow (alias: ui)
928
+ ${style.brightCyan("idea, ideas")} Manage idea backlog: add new ideas or list pending ideas
929
+ ${style.brightCyan("findings")} Inspect findings ledger, record new findings, filter blockers, or resolve
930
+ ${style.brightCyan("doctor")} Inspect project workspace health and auto-heal missing files (--fix)
931
+ ${style.brightCyan("archive")} Explore delivered runs and release statistics from devflow/history/
293
932
  ${style.brightCyan("update")} Update existing DevFlow installation without overwriting user changes
294
933
  ${style.brightCyan("uninstall, eject")} Completely remove DevFlow workflow files and adapters from project
295
934
 
296
935
  ${style.bold("Options:")}
936
+ ${style.cyan("--strict")} Strict mode for check-gate (blocks unverified runs)
937
+ ${style.cyan("--title <text>")} Custom title for idea add
938
+ ${style.cyan("--severity, -s")} Finding severity: P0, P1, P2, P3 (default: P2)
939
+ ${style.cyan("--status <name>")} Status to set when resolving finding (default: closed)
940
+ ${style.cyan("--location <path>")} Finding source code file and line location
941
+ ${style.cyan("--blockers")} Filter findings to only active P0/P1 blockers
942
+ ${style.cyan("--fix")} Automatically repair/create missing context files in doctor
943
+ ${style.cyan("--stats")} Display history summary statistics only
297
944
  ${style.cyan("--adapter <name>")} Tool adapters to install: codex, antigravity, claude, copilot, both, all
298
945
  ${style.cyan("--no-open")} Start local dashboard without opening a browser
299
946
  ${style.cyan("--keep-history")} Keep devflow/history/ directory during uninstall