@jakkrichm/create-nexus-devflow 2.0.25 → 2.0.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/bin/create-nexus-devflow.d.ts +18 -1
- package/dist/bin/create-nexus-devflow.js +439 -11
- package/dist/bin/create-nexus-devflow.js.map +1 -1
- package/dist/lib/command-catalog.d.ts +11 -0
- package/dist/lib/command-catalog.js +63 -0
- package/dist/lib/command-catalog.js.map +1 -0
- package/dist/lib/current-work.js +94 -48
- package/dist/lib/current-work.js.map +1 -1
- package/dist/lib/dashboard-page.d.ts +2 -0
- package/dist/lib/dashboard-page.js +201 -0
- package/dist/lib/dashboard-page.js.map +1 -0
- package/dist/lib/dashboard-snapshot.d.ts +49 -0
- package/dist/lib/dashboard-snapshot.js +96 -0
- package/dist/lib/dashboard-snapshot.js.map +1 -0
- package/dist/lib/dashboard.d.ts +2 -0
- package/dist/lib/dashboard.js +360 -8
- package/dist/lib/dashboard.js.map +1 -1
- package/dist/lib/discoveries.d.ts +19 -0
- package/dist/lib/discoveries.js +81 -0
- package/dist/lib/discoveries.js.map +1 -0
- package/dist/lib/doctor.d.ts +26 -0
- package/dist/lib/doctor.js +474 -0
- package/dist/lib/doctor.js.map +1 -0
- package/dist/lib/findings.d.ts +26 -2
- package/dist/lib/findings.js +165 -1
- package/dist/lib/findings.js.map +1 -1
- package/dist/lib/gatekeeper.d.ts +19 -0
- package/dist/lib/gatekeeper.js +77 -0
- package/dist/lib/gatekeeper.js.map +1 -0
- package/dist/lib/git-hooks.d.ts +16 -0
- package/dist/lib/git-hooks.js +78 -0
- package/dist/lib/git-hooks.js.map +1 -0
- package/dist/lib/history.d.ts +6 -1
- package/dist/lib/history.js +98 -11
- package/dist/lib/history.js.map +1 -1
- package/dist/lib/ideas.d.ts +26 -0
- package/dist/lib/ideas.js +179 -0
- package/dist/lib/ideas.js.map +1 -0
- package/dist/lib/status.d.ts +2 -0
- package/dist/lib/status.js +60 -6
- package/dist/lib/status.js.map +1 -1
- package/dist/lib/update.js +2 -2
- package/dist/lib/update.js.map +1 -1
- package/dist/lib/version-check.d.ts +22 -0
- package/dist/lib/version-check.js +59 -0
- package/dist/lib/version-check.js.map +1 -0
- package/dist/lib/workflow-state.d.ts +23 -0
- package/dist/lib/workflow-state.js +112 -0
- package/dist/lib/workflow-state.js.map +1 -0
- package/dist/scripts/prepare-template.js +3 -3
- package/package.json +1 -1
- package/template/{.claude/skills/00-discover → .agents/skills/00-explore}/SKILL.md +10 -10
- package/template/.agents/skills/10-define/SKILL.md +4 -4
- package/template/.agents/skills/20-spec/SKILL.md +2 -3
- package/template/.agents/skills/30-plan/SKILL.md +2 -3
- package/template/.agents/skills/40-execute/SKILL.md +2 -2
- package/template/.agents/skills/50-verify/SKILL.md +2 -2
- package/template/.agents/skills/60-report/SKILL.md +3 -3
- package/template/{.claude/skills/70-release → .agents/skills/70-deliver}/SKILL.md +7 -13
- package/template/.agents/skills/adopt/SKILL.md +136 -73
- package/template/.agents/skills/audit/SKILL.md +275 -0
- package/template/.agents/skills/autopilot/SKILL.md +228 -147
- package/template/.agents/skills/brainstorm/SKILL.md +3 -3
- package/template/.agents/skills/brief/SKILL.md +74 -51
- package/template/.agents/skills/check/SKILL.md +96 -76
- package/template/.agents/skills/ci/SKILL.md +140 -61
- package/template/.agents/skills/complete/SKILL.md +156 -101
- package/template/.agents/skills/convert-any-to-md/SKILL.md +2 -2
- package/template/.agents/skills/debug/SKILL.md +124 -49
- package/template/.agents/skills/devflow/SKILL.md +16 -10
- package/template/.agents/skills/discovery/SKILL.md +166 -0
- package/template/.agents/skills/doctor/SKILL.md +188 -72
- package/template/.agents/skills/feature/SKILL.md +195 -102
- package/template/.agents/skills/fix/SKILL.md +41 -90
- package/template/.agents/skills/idea/SKILL.md +3 -3
- package/template/.agents/skills/implement/SKILL.md +189 -46
- package/template/.agents/skills/onboard/SKILL.md +215 -85
- package/template/.agents/skills/overview/SKILL.md +51 -85
- package/template/.agents/skills/prototype/SKILL.md +82 -27
- package/template/.agents/skills/release/SKILL.md +160 -0
- package/template/.agents/skills/report-html/SKILL.md +2 -2
- package/template/.agents/skills/rollback/SKILL.md +123 -77
- package/template/.agents/skills/status/SKILL.md +109 -0
- package/template/.agents/skills/test/SKILL.md +2 -2
- package/template/.agents/skills/tests/SKILL.md +126 -0
- package/template/.agents/skills/try/SKILL.md +77 -65
- package/template/{.agents/skills/00-discover → .claude/skills/00-explore}/SKILL.md +9 -9
- package/template/.claude/skills/10-define/SKILL.md +2 -2
- package/template/.claude/skills/20-spec/SKILL.md +1 -1
- package/template/.claude/skills/30-plan/SKILL.md +1 -1
- package/template/.claude/skills/60-report/SKILL.md +1 -1
- package/template/{.agents/skills/70-release → .claude/skills/70-deliver}/SKILL.md +6 -12
- package/template/.claude/skills/adopt/SKILL.md +2 -2
- package/template/.claude/skills/audit/SKILL.md +141 -0
- package/template/.claude/skills/autopilot/SKILL.md +74 -52
- package/template/.claude/skills/brief/SKILL.md +67 -45
- package/template/.claude/skills/ci/SKILL.md +1 -1
- package/template/.claude/skills/complete/SKILL.md +1 -1
- package/template/.claude/skills/debug/SKILL.md +1 -1
- package/template/.claude/skills/devflow/SKILL.md +7 -7
- package/template/.claude/skills/discovery/SKILL.md +145 -0
- package/template/.claude/skills/doctor/SKILL.md +1 -1
- package/template/.claude/skills/feature/SKILL.md +67 -18
- package/template/.claude/skills/fix/SKILL.md +1 -1
- package/template/.claude/skills/idea/SKILL.md +2 -2
- package/template/.claude/skills/onboard/SKILL.md +3 -3
- package/template/.claude/skills/overview/SKILL.md +39 -88
- package/template/.claude/skills/prototype/SKILL.md +1 -1
- package/template/.claude/skills/release/SKILL.md +171 -0
- package/template/.claude/skills/rollback/SKILL.md +2 -2
- package/template/AGENTS.md +5 -5
- package/template/devflow/build-plan.md +40 -0
- package/template/devflow/context/ai-interaction.md +4 -4
- package/template/devflow/context/coding-standards.md +3 -3
- package/template/devflow/context/current-stage.md +1 -1
- package/template/devflow/context/findings.md +1 -1
- package/template/devflow/history/HISTORY.md +2 -2
- package/template/devflow/project-plan.md +27 -0
- package/template/devflow/reference/mockup.html +476 -0
- package/template/devflow/reference/project-overview-template.md +39 -0
- package/template/devflow/reference/running-id-contract.md +24 -2
package/README.md
CHANGED
|
@@ -45,7 +45,7 @@ The installer overlays the DevFlow workflow layer into your workspace:
|
|
|
45
45
|
### 2. Deep-Track (Architect Mode — 8 Steps)
|
|
46
46
|
*Recommended for large architectural epics and database migrations:*
|
|
47
47
|
```text
|
|
48
|
-
00-
|
|
48
|
+
00-explore ──▶ 10-define ──▶ 20-spec ──▶ 30-plan ──▶ 40-execute ──▶ 50-verify ──▶ 60-report ──▶ 70-deliver
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
---
|
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { type FindingSeverity, type FindingStatus } from "../lib/findings.js";
|
|
3
|
+
import { type GitHookType } from "../lib/git-hooks.js";
|
|
2
4
|
interface CliOptions {
|
|
3
|
-
command: "install" | "status" | "ui" | "update" | "uninstall" | "eject";
|
|
5
|
+
command: "dashboard" | "install" | "status" | "ui" | "update" | "uninstall" | "eject" | "idea" | "ideas" | "findings" | "doctor" | "archive" | "check-gate" | "hook";
|
|
6
|
+
subcommandAction?: "add" | "list" | "resolve" | "stats" | "install" | "uninstall";
|
|
7
|
+
subcommandArg?: string;
|
|
8
|
+
hookType?: GitHookType;
|
|
9
|
+
ideaTitle?: string;
|
|
10
|
+
findingStatus?: FindingStatus;
|
|
11
|
+
findingSeverity?: FindingSeverity;
|
|
12
|
+
findingId?: string;
|
|
13
|
+
findingLocation?: string;
|
|
14
|
+
findingImpact?: string;
|
|
15
|
+
findingRemediation?: string;
|
|
16
|
+
blockersOnly: boolean;
|
|
17
|
+
fix: boolean;
|
|
18
|
+
statsOnly: boolean;
|
|
19
|
+
strict: boolean;
|
|
20
|
+
deprecatedUi: boolean;
|
|
4
21
|
target: string | null;
|
|
5
22
|
adapter: string;
|
|
6
23
|
force: boolean;
|
|
@@ -5,11 +5,19 @@ 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 { installGitHook, uninstallGitHooks } from "../lib/git-hooks.js";
|
|
8
14
|
import { createSpinner, createStyle } from "../lib/ui.js";
|
|
9
15
|
import { applyPreparedUpdate, prepareUpdate } from "../lib/update.js";
|
|
10
16
|
import { applyUninstall, prepareUninstall } from "../lib/uninstall.js";
|
|
11
17
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
-
const packageRoot = path.
|
|
18
|
+
const packageRoot = fsSync.existsSync(path.join(__dirname, "..", "package.json"))
|
|
19
|
+
? path.resolve(__dirname, "..")
|
|
20
|
+
: path.resolve(__dirname, "..", "..");
|
|
13
21
|
const templateRoot = path.join(packageRoot, "template");
|
|
14
22
|
const adapterChoices = new Set(["codex", "antigravity", "claude", "copilot", "both", "all"]);
|
|
15
23
|
async function main(args = process.argv.slice(2)) {
|
|
@@ -23,6 +31,9 @@ async function main(args = process.argv.slice(2)) {
|
|
|
23
31
|
return;
|
|
24
32
|
}
|
|
25
33
|
const targetDir = path.resolve(process.cwd(), options.target || ".");
|
|
34
|
+
if (options.deprecatedUi) {
|
|
35
|
+
console.warn("Warning: `ui` is deprecated; use `dashboard` instead.");
|
|
36
|
+
}
|
|
26
37
|
if (options.command === "status") {
|
|
27
38
|
const status = await readProjectStatus(targetDir);
|
|
28
39
|
console.log(options.json
|
|
@@ -30,7 +41,163 @@ async function main(args = process.argv.slice(2)) {
|
|
|
30
41
|
: formatHumanStatus(status, { color: shouldUseColor() }));
|
|
31
42
|
return;
|
|
32
43
|
}
|
|
33
|
-
if (options.command === "
|
|
44
|
+
if (options.command === "check-gate") {
|
|
45
|
+
const report = await evaluateGate(targetDir, {
|
|
46
|
+
strict: options.strict,
|
|
47
|
+
color: shouldUseColor()
|
|
48
|
+
});
|
|
49
|
+
if (options.json) {
|
|
50
|
+
console.log(JSON.stringify(report, null, 2));
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
console.log(formatGateReport(report, { color: shouldUseColor() }));
|
|
54
|
+
}
|
|
55
|
+
if (!report.passed) {
|
|
56
|
+
process.exitCode = 1;
|
|
57
|
+
}
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (options.command === "hook") {
|
|
61
|
+
if (options.subcommandAction === "uninstall") {
|
|
62
|
+
const result = await uninstallGitHooks(targetDir);
|
|
63
|
+
if (options.json) {
|
|
64
|
+
console.log(JSON.stringify(result, null, 2));
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
const style = createStyle(shouldUseColor());
|
|
68
|
+
console.log(`\n${style.green("✔")} ${style.bold(result.message)}`);
|
|
69
|
+
}
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
// Default: install
|
|
73
|
+
const hookType = options.hookType || "pre-commit";
|
|
74
|
+
const result = await installGitHook(targetDir, hookType, { strict: options.strict });
|
|
75
|
+
if (options.json) {
|
|
76
|
+
console.log(JSON.stringify(result, null, 2));
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
const style = createStyle(shouldUseColor());
|
|
80
|
+
if (result.success) {
|
|
81
|
+
console.log(`\n${style.green("✔")} ${style.bold(result.message)}`);
|
|
82
|
+
console.log(` ${style.dim("Hook:")} ${style.cyan(result.path)}`);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
console.error(`\n${style.red("✖")} ${style.bold(result.message)}`);
|
|
86
|
+
process.exitCode = 1;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (options.command === "idea" || options.command === "ideas") {
|
|
92
|
+
if (options.subcommandAction === "add") {
|
|
93
|
+
const text = options.subcommandArg || "";
|
|
94
|
+
if (!text.trim()) {
|
|
95
|
+
throw new Error("Idea text is required. Example: nexus-devflow idea add \"My idea\"");
|
|
96
|
+
}
|
|
97
|
+
const created = await addIdea(targetDir, {
|
|
98
|
+
text,
|
|
99
|
+
title: options.ideaTitle
|
|
100
|
+
});
|
|
101
|
+
if (options.json) {
|
|
102
|
+
console.log(JSON.stringify(created, null, 2));
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
const style = createStyle(shouldUseColor());
|
|
106
|
+
console.log(`\n${style.green("✔")} ${style.bold("Idea added successfully!")}`);
|
|
107
|
+
console.log(` ${style.dim("ID :")} ${style.bold(style.cyan(created.id))}`);
|
|
108
|
+
console.log(` ${style.dim("Title:")} ${style.bold(created.title)}`);
|
|
109
|
+
console.log(` ${style.dim("Start:")} ${style.yellow(`/feature ${created.id}`)} or ${style.yellow(`/00-explore ${created.id}`)}`);
|
|
110
|
+
}
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const ideas = await readIdeas(targetDir);
|
|
114
|
+
console.log(options.json
|
|
115
|
+
? JSON.stringify(ideas, null, 2)
|
|
116
|
+
: formatIdeasHuman(ideas, { color: shouldUseColor() }));
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (options.command === "findings") {
|
|
120
|
+
if (options.subcommandAction === "add") {
|
|
121
|
+
const title = options.subcommandArg || "";
|
|
122
|
+
if (!title.trim()) {
|
|
123
|
+
throw new Error('Finding title is required. Example: nexus-devflow findings add "Hardcoded secret" --severity P0');
|
|
124
|
+
}
|
|
125
|
+
const result = await addFinding(targetDir, title, {
|
|
126
|
+
id: options.findingId,
|
|
127
|
+
severity: options.findingSeverity,
|
|
128
|
+
status: options.findingStatus,
|
|
129
|
+
location: options.findingLocation,
|
|
130
|
+
impact: options.findingImpact,
|
|
131
|
+
remediation: options.findingRemediation
|
|
132
|
+
});
|
|
133
|
+
if (options.json) {
|
|
134
|
+
console.log(JSON.stringify(result, null, 2));
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
const style = createStyle(shouldUseColor());
|
|
138
|
+
console.log(`\n${style.green("✔")} ${style.bold("Finding recorded successfully!")}`);
|
|
139
|
+
console.log(` ${style.dim("ID :")} ${style.bold(style.cyan(result.finding?.id || ""))}`);
|
|
140
|
+
const sev = result.finding?.severity || "P2";
|
|
141
|
+
const isBlocker = sev === "P0" || sev === "P1";
|
|
142
|
+
console.log(` ${style.dim("Severity:")} ${style.bold(isBlocker ? style.red(`[${sev}]`) : style.yellow(`[${sev}]`))}`);
|
|
143
|
+
console.log(` ${style.dim("Status :")} ${style.yellow(result.finding?.status || "")}`);
|
|
144
|
+
console.log(` ${style.dim("Title :")} ${style.bold(result.finding?.title || "")}`);
|
|
145
|
+
console.log(` ${style.dim("File :")} ${style.dim(result.filePath)}`);
|
|
146
|
+
}
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (options.subcommandAction === "resolve") {
|
|
150
|
+
const findingId = options.subcommandArg || "";
|
|
151
|
+
if (!findingId.trim()) {
|
|
152
|
+
throw new Error("Finding ID is required. Example: nexus-devflow findings resolve FIND-001");
|
|
153
|
+
}
|
|
154
|
+
const statusToSet = options.findingStatus || "closed";
|
|
155
|
+
const result = await resolveFinding(targetDir, findingId, statusToSet);
|
|
156
|
+
if (options.json) {
|
|
157
|
+
console.log(JSON.stringify(result, null, 2));
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
const style = createStyle(shouldUseColor());
|
|
161
|
+
if (result.success) {
|
|
162
|
+
console.log(`\n${style.green("✔")} ${style.bold(result.message)}`);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
console.error(`\n${style.red("✖")} ${style.bold(result.message)}`);
|
|
166
|
+
process.exitCode = 1;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const findings = await readFindings(targetDir);
|
|
172
|
+
console.log(options.json
|
|
173
|
+
? JSON.stringify(findings, null, 2)
|
|
174
|
+
: formatFindingsHuman(findings, {
|
|
175
|
+
blockersOnly: options.blockersOnly,
|
|
176
|
+
color: shouldUseColor()
|
|
177
|
+
}));
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (options.command === "doctor") {
|
|
181
|
+
const report = await runDoctor(targetDir, {
|
|
182
|
+
fix: options.fix,
|
|
183
|
+
color: shouldUseColor()
|
|
184
|
+
});
|
|
185
|
+
console.log(options.json
|
|
186
|
+
? JSON.stringify(report, null, 2)
|
|
187
|
+
: formatDoctorHuman(report, { color: shouldUseColor() }));
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (options.command === "archive") {
|
|
191
|
+
const history = await readHistory(targetDir);
|
|
192
|
+
console.log(options.json
|
|
193
|
+
? JSON.stringify(history, null, 2)
|
|
194
|
+
: formatHistoryHuman(history, {
|
|
195
|
+
statsOnly: options.statsOnly,
|
|
196
|
+
color: shouldUseColor()
|
|
197
|
+
}));
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (options.command === "dashboard" || options.command === "ui") {
|
|
34
201
|
const server = await startDashboardServer(targetDir);
|
|
35
202
|
const style = createStyle();
|
|
36
203
|
console.log(style.bold(style.cyan(`Nexus-DevFlow Dashboard live at ${server.url}`)));
|
|
@@ -137,6 +304,21 @@ async function main(args = process.argv.slice(2)) {
|
|
|
137
304
|
}
|
|
138
305
|
function parseArgs(args) {
|
|
139
306
|
let command = "install";
|
|
307
|
+
let subcommandAction;
|
|
308
|
+
let subcommandArg;
|
|
309
|
+
let hookType;
|
|
310
|
+
let ideaTitle;
|
|
311
|
+
let findingStatus;
|
|
312
|
+
let findingSeverity;
|
|
313
|
+
let findingId;
|
|
314
|
+
let findingLocation;
|
|
315
|
+
let findingImpact;
|
|
316
|
+
let findingRemediation;
|
|
317
|
+
let blockersOnly = false;
|
|
318
|
+
let fix = false;
|
|
319
|
+
let statsOnly = false;
|
|
320
|
+
let strict = false;
|
|
321
|
+
let deprecatedUi = false;
|
|
140
322
|
let target = null;
|
|
141
323
|
let adapter = "both";
|
|
142
324
|
let force = false;
|
|
@@ -182,6 +364,110 @@ function parseArgs(args) {
|
|
|
182
364
|
keepHistory = true;
|
|
183
365
|
continue;
|
|
184
366
|
}
|
|
367
|
+
if (arg === "--blockers") {
|
|
368
|
+
blockersOnly = true;
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
if (arg === "--fix") {
|
|
372
|
+
fix = true;
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
if (arg === "--stats") {
|
|
376
|
+
statsOnly = true;
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
if (arg === "--strict") {
|
|
380
|
+
strict = true;
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
if (arg === "--title") {
|
|
384
|
+
const next = args[++i];
|
|
385
|
+
if (!next) {
|
|
386
|
+
throw new Error(`${arg} requires a title string`);
|
|
387
|
+
}
|
|
388
|
+
ideaTitle = next;
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
if (arg.startsWith("--title=")) {
|
|
392
|
+
ideaTitle = arg.slice("--title=".length);
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
if (arg === "--status") {
|
|
396
|
+
const next = args[++i];
|
|
397
|
+
if (!next) {
|
|
398
|
+
throw new Error(`${arg} requires a status string (e.g. closed, accepted, invalid)`);
|
|
399
|
+
}
|
|
400
|
+
findingStatus = next.toLowerCase();
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
if (arg.startsWith("--status=")) {
|
|
404
|
+
findingStatus = arg.slice("--status=".length).toLowerCase();
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
if (arg === "--severity" || arg === "-s") {
|
|
408
|
+
const next = args[++i];
|
|
409
|
+
if (!next) {
|
|
410
|
+
throw new Error(`${arg} requires a severity level (P0, P1, P2, P3)`);
|
|
411
|
+
}
|
|
412
|
+
const sev = next.toUpperCase();
|
|
413
|
+
if (sev !== "P0" && sev !== "P1" && sev !== "P2" && sev !== "P3") {
|
|
414
|
+
throw new Error(`Invalid severity "${next}". Expected one of: P0, P1, P2, P3`);
|
|
415
|
+
}
|
|
416
|
+
findingSeverity = sev;
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
if (arg.startsWith("--severity=")) {
|
|
420
|
+
const sev = arg.slice("--severity=".length).toUpperCase();
|
|
421
|
+
if (sev !== "P0" && sev !== "P1" && sev !== "P2" && sev !== "P3") {
|
|
422
|
+
throw new Error(`Invalid severity "${sev}". Expected one of: P0, P1, P2, P3`);
|
|
423
|
+
}
|
|
424
|
+
findingSeverity = sev;
|
|
425
|
+
continue;
|
|
426
|
+
}
|
|
427
|
+
if (arg === "--id") {
|
|
428
|
+
const next = args[++i];
|
|
429
|
+
if (!next)
|
|
430
|
+
throw new Error(`${arg} requires an ID string`);
|
|
431
|
+
findingId = next;
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
434
|
+
if (arg.startsWith("--id=")) {
|
|
435
|
+
findingId = arg.slice("--id=".length);
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
438
|
+
if (arg === "--location") {
|
|
439
|
+
const next = args[++i];
|
|
440
|
+
if (!next)
|
|
441
|
+
throw new Error(`${arg} requires a location string`);
|
|
442
|
+
findingLocation = next;
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
if (arg.startsWith("--location=")) {
|
|
446
|
+
findingLocation = arg.slice("--location=".length);
|
|
447
|
+
continue;
|
|
448
|
+
}
|
|
449
|
+
if (arg === "--impact") {
|
|
450
|
+
const next = args[++i];
|
|
451
|
+
if (!next)
|
|
452
|
+
throw new Error(`${arg} requires an impact string`);
|
|
453
|
+
findingImpact = next;
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
456
|
+
if (arg.startsWith("--impact=")) {
|
|
457
|
+
findingImpact = arg.slice("--impact=".length);
|
|
458
|
+
continue;
|
|
459
|
+
}
|
|
460
|
+
if (arg === "--remediation") {
|
|
461
|
+
const next = args[++i];
|
|
462
|
+
if (!next)
|
|
463
|
+
throw new Error(`${arg} requires a remediation string`);
|
|
464
|
+
findingRemediation = next;
|
|
465
|
+
continue;
|
|
466
|
+
}
|
|
467
|
+
if (arg.startsWith("--remediation=")) {
|
|
468
|
+
findingRemediation = arg.slice("--remediation=".length);
|
|
469
|
+
continue;
|
|
470
|
+
}
|
|
185
471
|
if (arg === "--target" || arg === "-t") {
|
|
186
472
|
const next = args[++i];
|
|
187
473
|
if (!next) {
|
|
@@ -216,27 +502,130 @@ function parseArgs(args) {
|
|
|
216
502
|
positional.push(arg);
|
|
217
503
|
}
|
|
218
504
|
if (positional.length > 0) {
|
|
219
|
-
|
|
505
|
+
const first = positional[0].toLowerCase();
|
|
506
|
+
if (first === "status") {
|
|
220
507
|
command = "status";
|
|
221
508
|
target = positional[1] || target || ".";
|
|
222
509
|
}
|
|
223
|
-
else if (
|
|
224
|
-
command = "
|
|
510
|
+
else if (first === "check-gate") {
|
|
511
|
+
command = "check-gate";
|
|
225
512
|
target = positional[1] || target || ".";
|
|
226
513
|
}
|
|
227
|
-
else if (
|
|
514
|
+
else if (first === "hook" || first === "hooks") {
|
|
515
|
+
command = "hook";
|
|
516
|
+
if (positional[1] === "uninstall") {
|
|
517
|
+
subcommandAction = "uninstall";
|
|
518
|
+
target = positional[2] || target || ".";
|
|
519
|
+
}
|
|
520
|
+
else if (positional[1] === "install") {
|
|
521
|
+
subcommandAction = "install";
|
|
522
|
+
if (positional[2] === "pre-commit" || positional[2] === "pre-push") {
|
|
523
|
+
hookType = positional[2];
|
|
524
|
+
target = positional[3] || target || ".";
|
|
525
|
+
}
|
|
526
|
+
else {
|
|
527
|
+
target = positional[2] || target || ".";
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
else if (positional[1] === "pre-commit" || positional[1] === "pre-push") {
|
|
531
|
+
subcommandAction = "install";
|
|
532
|
+
hookType = positional[1];
|
|
533
|
+
target = positional[2] || target || ".";
|
|
534
|
+
}
|
|
535
|
+
else {
|
|
536
|
+
subcommandAction = "install";
|
|
537
|
+
target = positional[1] || target || ".";
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
else if (first === "dashboard") {
|
|
541
|
+
command = "dashboard";
|
|
542
|
+
target = positional[1] || target || ".";
|
|
543
|
+
}
|
|
544
|
+
else if (first === "ui") {
|
|
545
|
+
command = "dashboard";
|
|
546
|
+
deprecatedUi = true;
|
|
547
|
+
target = positional[1] || target || ".";
|
|
548
|
+
}
|
|
549
|
+
else if (first === "update") {
|
|
228
550
|
command = "update";
|
|
229
551
|
target = positional[1] || target || ".";
|
|
230
552
|
}
|
|
231
|
-
else if (
|
|
553
|
+
else if (first === "uninstall") {
|
|
232
554
|
command = "uninstall";
|
|
233
555
|
target = positional[1] || target || ".";
|
|
234
556
|
}
|
|
235
|
-
else if (
|
|
557
|
+
else if (first === "eject") {
|
|
236
558
|
command = "eject";
|
|
237
559
|
target = positional[1] || target || ".";
|
|
238
560
|
}
|
|
239
|
-
else if (
|
|
561
|
+
else if (first === "idea" || first === "ideas") {
|
|
562
|
+
command = first === "idea" ? "idea" : "ideas";
|
|
563
|
+
if (positional[1] === "add") {
|
|
564
|
+
subcommandAction = "add";
|
|
565
|
+
subcommandArg = positional[2];
|
|
566
|
+
target = positional[3] || target || ".";
|
|
567
|
+
}
|
|
568
|
+
else if (positional[1] === "list") {
|
|
569
|
+
subcommandAction = "list";
|
|
570
|
+
target = positional[2] || target || ".";
|
|
571
|
+
}
|
|
572
|
+
else if (positional[1] && !positional[1].startsWith("-")) {
|
|
573
|
+
subcommandAction = "add";
|
|
574
|
+
subcommandArg = positional[1];
|
|
575
|
+
target = positional[2] || target || ".";
|
|
576
|
+
}
|
|
577
|
+
else {
|
|
578
|
+
subcommandAction = "list";
|
|
579
|
+
target = positional[1] || target || ".";
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
else if (first === "findings") {
|
|
583
|
+
command = "findings";
|
|
584
|
+
if (positional[1] === "add") {
|
|
585
|
+
subcommandAction = "add";
|
|
586
|
+
subcommandArg = positional[2];
|
|
587
|
+
target = positional[3] || target || ".";
|
|
588
|
+
}
|
|
589
|
+
else if (positional[1] === "resolve") {
|
|
590
|
+
subcommandAction = "resolve";
|
|
591
|
+
subcommandArg = positional[2];
|
|
592
|
+
target = positional[3] || target || ".";
|
|
593
|
+
}
|
|
594
|
+
else if (positional[1] === "list") {
|
|
595
|
+
subcommandAction = "list";
|
|
596
|
+
target = positional[2] || target || ".";
|
|
597
|
+
}
|
|
598
|
+
else if (positional[1] && !positional[1].startsWith("-")) {
|
|
599
|
+
subcommandAction = "add";
|
|
600
|
+
subcommandArg = positional[1];
|
|
601
|
+
target = positional[2] || target || ".";
|
|
602
|
+
}
|
|
603
|
+
else {
|
|
604
|
+
subcommandAction = "list";
|
|
605
|
+
target = positional[1] || target || ".";
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
else if (first === "doctor") {
|
|
609
|
+
command = "doctor";
|
|
610
|
+
target = positional[1] || target || ".";
|
|
611
|
+
}
|
|
612
|
+
else if (first === "archive") {
|
|
613
|
+
command = "archive";
|
|
614
|
+
if (positional[1] === "list") {
|
|
615
|
+
subcommandAction = "list";
|
|
616
|
+
target = positional[2] || target || ".";
|
|
617
|
+
}
|
|
618
|
+
else if (positional[1] === "stats") {
|
|
619
|
+
subcommandAction = "stats";
|
|
620
|
+
statsOnly = true;
|
|
621
|
+
target = positional[2] || target || ".";
|
|
622
|
+
}
|
|
623
|
+
else {
|
|
624
|
+
subcommandAction = "list";
|
|
625
|
+
target = positional[1] || target || ".";
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
else if (first === "install") {
|
|
240
629
|
command = "install";
|
|
241
630
|
target = positional[1] || target || ".";
|
|
242
631
|
}
|
|
@@ -246,6 +635,21 @@ function parseArgs(args) {
|
|
|
246
635
|
}
|
|
247
636
|
return {
|
|
248
637
|
command,
|
|
638
|
+
subcommandAction,
|
|
639
|
+
subcommandArg,
|
|
640
|
+
hookType,
|
|
641
|
+
ideaTitle,
|
|
642
|
+
findingStatus,
|
|
643
|
+
findingSeverity,
|
|
644
|
+
findingId,
|
|
645
|
+
findingLocation,
|
|
646
|
+
findingImpact,
|
|
647
|
+
findingRemediation,
|
|
648
|
+
blockersOnly,
|
|
649
|
+
fix,
|
|
650
|
+
statsOnly,
|
|
651
|
+
strict,
|
|
652
|
+
deprecatedUi,
|
|
249
653
|
target,
|
|
250
654
|
adapter,
|
|
251
655
|
force,
|
|
@@ -282,18 +686,42 @@ ${style.bold(style.cyan("Nexus-DevFlow CLI"))} ${style.bold(`v${readPackageVersi
|
|
|
282
686
|
${style.bold("Usage:")}
|
|
283
687
|
${style.cyan("npx @jakkrichm/create-nexus-devflow")} [target-dir] [options]
|
|
284
688
|
${style.cyan("nexus-devflow status")} [target-dir] [options]
|
|
285
|
-
${style.cyan("nexus-devflow
|
|
689
|
+
${style.cyan("nexus-devflow check-gate")} [--strict] [--json]
|
|
690
|
+
${style.cyan("nexus-devflow hook install")} [pre-commit|pre-push]
|
|
691
|
+
${style.cyan("nexus-devflow hook uninstall")}
|
|
692
|
+
${style.cyan("nexus-devflow dashboard")} [target-dir] [options]
|
|
693
|
+
${style.cyan("nexus-devflow idea")} add "<text>" [--title "<title>"]
|
|
694
|
+
${style.cyan("nexus-devflow ideas")} [list] [--json]
|
|
695
|
+
${style.cyan("nexus-devflow findings add")} "<title>" [--severity P0|P1|P2|P3] [--location <loc>]
|
|
696
|
+
${style.cyan("nexus-devflow findings")} [list] [--blockers] [--json]
|
|
697
|
+
${style.cyan("nexus-devflow findings resolve")} <ID> [--status <status>]
|
|
698
|
+
${style.cyan("nexus-devflow doctor")} [--fix] [--json]
|
|
699
|
+
${style.cyan("nexus-devflow archive")} [list|stats] [--json]
|
|
286
700
|
${style.cyan("nexus-devflow update")} [target-dir] [options]
|
|
287
701
|
${style.cyan("nexus-devflow uninstall")} [target-dir] [options]
|
|
288
702
|
${style.cyan("nexus-devflow eject")} [target-dir] [options]
|
|
289
703
|
|
|
290
704
|
${style.bold("Commands:")}
|
|
291
705
|
${style.brightCyan("status")} Show project overview, progress, findings, git status, and next action
|
|
292
|
-
${style.brightCyan("
|
|
706
|
+
${style.brightCyan("check-gate")} CI/CD quality gatekeeper check (returns exit code 0 or 1)
|
|
707
|
+
${style.brightCyan("hook")} Install or remove local Git pre-commit/pre-push gatekeeper hooks
|
|
708
|
+
${style.brightCyan("dashboard")} Run local interactive web dashboard for Nexus-DevFlow (alias: ui)
|
|
709
|
+
${style.brightCyan("idea, ideas")} Manage idea backlog: add new ideas or list pending ideas
|
|
710
|
+
${style.brightCyan("findings")} Inspect findings ledger, record new findings, filter blockers, or resolve
|
|
711
|
+
${style.brightCyan("doctor")} Inspect project workspace health and auto-heal missing files (--fix)
|
|
712
|
+
${style.brightCyan("archive")} Explore delivered runs and release statistics from devflow/history/
|
|
293
713
|
${style.brightCyan("update")} Update existing DevFlow installation without overwriting user changes
|
|
294
714
|
${style.brightCyan("uninstall, eject")} Completely remove DevFlow workflow files and adapters from project
|
|
295
715
|
|
|
296
716
|
${style.bold("Options:")}
|
|
717
|
+
${style.cyan("--strict")} Strict mode for check-gate (blocks unverified runs)
|
|
718
|
+
${style.cyan("--title <text>")} Custom title for idea add
|
|
719
|
+
${style.cyan("--severity, -s")} Finding severity: P0, P1, P2, P3 (default: P2)
|
|
720
|
+
${style.cyan("--status <name>")} Status to set when resolving finding (default: closed)
|
|
721
|
+
${style.cyan("--location <path>")} Finding source code file and line location
|
|
722
|
+
${style.cyan("--blockers")} Filter findings to only active P0/P1 blockers
|
|
723
|
+
${style.cyan("--fix")} Automatically repair/create missing context files in doctor
|
|
724
|
+
${style.cyan("--stats")} Display history summary statistics only
|
|
297
725
|
${style.cyan("--adapter <name>")} Tool adapters to install: codex, antigravity, claude, copilot, both, all
|
|
298
726
|
${style.cyan("--no-open")} Start local dashboard without opening a browser
|
|
299
727
|
${style.cyan("--keep-history")} Keep devflow/history/ directory during uninstall
|