infernoflow 0.37.0 → 0.37.3
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/CHANGELOG.md +125 -0
- package/dist/bin/infernoflow.mjs +29 -277
- package/dist/lib/adopters/angular.mjs +1 -128
- package/dist/lib/adopters/css.mjs +1 -111
- package/dist/lib/adopters/react.mjs +1 -104
- package/dist/lib/ai/ideDetection.mjs +1 -31
- package/dist/lib/ai/localProvider.mjs +1 -88
- package/dist/lib/ai/providerRouter.mjs +2 -295
- package/dist/lib/commands/adopt.mjs +20 -869
- package/dist/lib/commands/adoptWizard.mjs +9 -320
- package/dist/lib/commands/agent.mjs +5 -191
- package/dist/lib/commands/ai.mjs +2 -407
- package/dist/lib/commands/ask.mjs +4 -299
- package/dist/lib/commands/audit.mjs +13 -300
- package/dist/lib/commands/changelog.mjs +26 -594
- package/dist/lib/commands/check.mjs +3 -184
- package/dist/lib/commands/ci.mjs +3 -208
- package/dist/lib/commands/claudeMd.mjs +30 -135
- package/dist/lib/commands/cloud.mjs +10 -773
- package/dist/lib/commands/context.mjs +34 -346
- package/dist/lib/commands/coverage.mjs +2 -282
- package/dist/lib/commands/dashboard.mjs +123 -635
- package/dist/lib/commands/demo.mjs +8 -465
- package/dist/lib/commands/diff.mjs +5 -274
- package/dist/lib/commands/docGate.mjs +2 -81
- package/dist/lib/commands/doctor.mjs +3 -321
- package/dist/lib/commands/explain.mjs +8 -438
- package/dist/lib/commands/export.mjs +10 -239
- package/dist/lib/commands/feedback.mjs +12 -216
- package/dist/lib/commands/generateSkills.mjs +38 -163
- package/dist/lib/commands/graph.mjs +11 -378
- package/dist/lib/commands/health.mjs +2 -309
- package/dist/lib/commands/impact.mjs +2 -325
- package/dist/lib/commands/implement.mjs +7 -103
- package/dist/lib/commands/init.mjs +45 -631
- package/dist/lib/commands/installCursorHooks.mjs +1 -36
- package/dist/lib/commands/installVsCodeCopilotHooks.mjs +1 -37
- package/dist/lib/commands/link.mjs +2 -342
- package/dist/lib/commands/log.mjs +18 -248
- package/dist/lib/commands/monorepo.mjs +4 -428
- package/dist/lib/commands/notify.mjs +4 -258
- package/dist/lib/commands/onboard.mjs +4 -296
- package/dist/lib/commands/prComment.mjs +2 -361
- package/dist/lib/commands/prImpact.mjs +2 -157
- package/dist/lib/commands/publish.mjs +15 -316
- package/dist/lib/commands/recap.mjs +6 -380
- package/dist/lib/commands/report.mjs +28 -272
- package/dist/lib/commands/review.mjs +9 -223
- package/dist/lib/commands/run.mjs +8 -336
- package/dist/lib/commands/scaffold.mjs +54 -419
- package/dist/lib/commands/scan.mjs +11 -1118
- package/dist/lib/commands/scout.mjs +2 -291
- package/dist/lib/commands/setup.mjs +5 -310
- package/dist/lib/commands/share.mjs +13 -196
- package/dist/lib/commands/snapshot.mjs +3 -383
- package/dist/lib/commands/stability.mjs +2 -293
- package/dist/lib/commands/stats.mjs +5 -402
- package/dist/lib/commands/status.mjs +4 -172
- package/dist/lib/commands/suggest.mjs +21 -563
- package/dist/lib/commands/switch.mjs +13 -517
- package/dist/lib/commands/syncAuto.mjs +1 -96
- package/dist/lib/commands/synthesize.mjs +10 -228
- package/dist/lib/commands/teamSync.mjs +2 -388
- package/dist/lib/commands/test.mjs +6 -363
- package/dist/lib/commands/theme.mjs +18 -195
- package/dist/lib/commands/uninstall.mjs +13 -406
- package/dist/lib/commands/upgrade.mjs +20 -153
- package/dist/lib/commands/version.mjs +2 -282
- package/dist/lib/commands/vibe.mjs +7 -357
- package/dist/lib/commands/watch.mjs +4 -203
- package/dist/lib/commands/why.mjs +4 -358
- package/dist/lib/cursorHooksInstall.mjs +1 -60
- package/dist/lib/draftToolingInstall.mjs +7 -68
- package/dist/lib/git/detect-drift.mjs +4 -208
- package/dist/lib/learning/adapt.mjs +6 -101
- package/dist/lib/learning/observe.mjs +1 -119
- package/dist/lib/learning/patternDetector.mjs +1 -298
- package/dist/lib/learning/profile.mjs +2 -279
- package/dist/lib/learning/skillSynthesizer.mjs +24 -145
- package/dist/lib/telemetry.mjs +19 -269
- package/dist/lib/templates/index.mjs +1 -131
- package/dist/lib/theme/scanner.mjs +4 -343
- package/dist/lib/ui/errors.mjs +1 -142
- package/dist/lib/ui/output.mjs +6 -95
- package/dist/lib/ui/prompts.mjs +6 -147
- package/dist/lib/vsCodeCopilotHooksInstall.mjs +1 -42
- package/package.json +2 -4
- package/scripts/postinstall.js +2 -2
|
@@ -1,406 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* - .cursor/mcp.json — infernoflow entry (other entries preserved)
|
|
15
|
-
* - inferno-mcp-server.mjs — root-level MCP server copy
|
|
16
|
-
* - ~/.claude.json — infernoflow mcpServers entry (other entries preserved)
|
|
17
|
-
* - .git/hooks/post-commit / pre-push — infernoflow sections (other hooks preserved)
|
|
18
|
-
*
|
|
19
|
-
* Flags:
|
|
20
|
-
* --dry-run Preview what would be removed without touching anything
|
|
21
|
-
* --keep-memory Preserve inferno/sessions.jsonl (your session logs)
|
|
22
|
-
* --keep-inferno Preserve the entire inferno/ folder
|
|
23
|
-
* --yes / -y Skip confirmation prompt
|
|
24
|
-
* --json Machine-readable output
|
|
25
|
-
*
|
|
26
|
-
* Usage:
|
|
27
|
-
* infernoflow uninstall Interactive — shows plan, asks to confirm
|
|
28
|
-
* infernoflow uninstall --dry-run Show what would be removed
|
|
29
|
-
* infernoflow uninstall --yes Remove without prompting
|
|
30
|
-
* infernoflow uninstall --keep-memory Remove setup but keep session logs
|
|
31
|
-
*/
|
|
32
|
-
|
|
33
|
-
import * as fs from "node:fs";
|
|
34
|
-
import * as path from "node:path";
|
|
35
|
-
import * as os from "node:os";
|
|
36
|
-
import * as readline from "node:readline";
|
|
37
|
-
import { bold, cyan, gray, green, yellow, red } from "../ui/output.mjs";
|
|
38
|
-
|
|
39
|
-
const INFERNO_DIR = "inferno";
|
|
40
|
-
const CLAUDE_MD = "CLAUDE.md";
|
|
41
|
-
const CLAUDE_DIR = ".claude";
|
|
42
|
-
const CURSOR_DIR = ".cursor";
|
|
43
|
-
const MCP_SERVER = path.join(CURSOR_DIR, "inferno-mcp-server.mjs");
|
|
44
|
-
const MCP_SERVER_ROOT = "inferno-mcp-server.mjs"; // root-level copy from install-cursor-hooks
|
|
45
|
-
const CURSOR_HOOKS_JSON= path.join(CURSOR_DIR, "hooks.json");
|
|
46
|
-
const CURSOR_HOOK_FILE = path.join(CURSOR_DIR, "hooks", "inferno-session-draft.mjs");
|
|
47
|
-
const CURSOR_MCP = path.join(CURSOR_DIR, "mcp.json");
|
|
48
|
-
const CLAUDE_JSON = path.join(os.homedir(), ".claude.json");
|
|
49
|
-
const GIT_HOOKS = [".git/hooks/post-commit", ".git/hooks/pre-push"];
|
|
50
|
-
const INFERNO_MARKER = "# infernoflow";
|
|
51
|
-
|
|
52
|
-
// ── helpers ──────────────────────────────────────────────────────────────────
|
|
53
|
-
|
|
54
|
-
function exists(p) { return fs.existsSync(p); }
|
|
55
|
-
function readJSON(f) { try { return JSON.parse(fs.readFileSync(f, "utf8")); } catch { return null; } }
|
|
56
|
-
|
|
57
|
-
function readFile(f) {
|
|
58
|
-
try { return fs.readFileSync(f, "utf8"); } catch { return null; }
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function prompt(question) {
|
|
62
|
-
return new Promise(resolve => {
|
|
63
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
64
|
-
rl.question(question, ans => { rl.close(); resolve(ans); });
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// ── planners — compute what would be removed ─────────────────────────────────
|
|
69
|
-
|
|
70
|
-
function planInfernoDir(cwd, keepMemory, keepInferno) {
|
|
71
|
-
const items = [];
|
|
72
|
-
const dir = path.join(cwd, INFERNO_DIR);
|
|
73
|
-
if (!exists(dir)) return items;
|
|
74
|
-
|
|
75
|
-
if (keepInferno) {
|
|
76
|
-
items.push({ type: "skip", path: INFERNO_DIR, reason: "--keep-inferno" });
|
|
77
|
-
return items;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (keepMemory) {
|
|
81
|
-
// Remove everything except sessions.jsonl
|
|
82
|
-
const files = fs.readdirSync(dir);
|
|
83
|
-
for (const f of files) {
|
|
84
|
-
if (f === "sessions.jsonl") {
|
|
85
|
-
items.push({ type: "skip", path: path.join(INFERNO_DIR, f), reason: "--keep-memory" });
|
|
86
|
-
} else {
|
|
87
|
-
const full = path.join(dir, f);
|
|
88
|
-
const stat = fs.statSync(full);
|
|
89
|
-
if (stat.isDirectory()) {
|
|
90
|
-
items.push({ type: "rmdir", path: path.join(INFERNO_DIR, f) });
|
|
91
|
-
} else {
|
|
92
|
-
items.push({ type: "rm", path: path.join(INFERNO_DIR, f) });
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
} else {
|
|
97
|
-
items.push({ type: "rmdir", path: INFERNO_DIR });
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return items;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function planClaudeMd(cwd) {
|
|
104
|
-
const p = path.join(cwd, CLAUDE_MD);
|
|
105
|
-
if (!exists(p)) return [];
|
|
106
|
-
return [{ type: "rm", path: CLAUDE_MD }];
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function planClaudeDir(cwd) {
|
|
110
|
-
const items = [];
|
|
111
|
-
const settingsFile = path.join(cwd, CLAUDE_DIR, "settings.json");
|
|
112
|
-
if (!exists(settingsFile)) return items;
|
|
113
|
-
|
|
114
|
-
const settings = readJSON(settingsFile);
|
|
115
|
-
const hasInfernoTools = settings?.tools?.some?.(t => t.startsWith?.("mcp__infernoflow"));
|
|
116
|
-
const hasOtherContent = settings && Object.keys(settings).some(k => {
|
|
117
|
-
if (k === "tools") {
|
|
118
|
-
return (settings.tools || []).some(t => !t.startsWith("mcp__infernoflow"));
|
|
119
|
-
}
|
|
120
|
-
return k !== "tools";
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
if (hasInfernoTools && !hasOtherContent) {
|
|
124
|
-
items.push({ type: "rm", path: path.join(CLAUDE_DIR, "settings.json"), desc: "auto-approved tools" });
|
|
125
|
-
} else if (hasInfernoTools) {
|
|
126
|
-
items.push({ type: "edit", path: path.join(CLAUDE_DIR, "settings.json"), desc: "remove infernoflow tools (preserve other content)" });
|
|
127
|
-
}
|
|
128
|
-
return items;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function planCursorMcpServer(cwd) {
|
|
132
|
-
const items = [];
|
|
133
|
-
// .cursor/inferno-mcp-server.mjs
|
|
134
|
-
if (exists(path.join(cwd, MCP_SERVER))) items.push({ type: "rm", path: MCP_SERVER });
|
|
135
|
-
// root-level inferno-mcp-server.mjs (written by install-cursor-hooks)
|
|
136
|
-
if (exists(path.join(cwd, MCP_SERVER_ROOT))) items.push({ type: "rm", path: MCP_SERVER_ROOT });
|
|
137
|
-
// .cursor/hooks/inferno-session-draft.mjs
|
|
138
|
-
if (exists(path.join(cwd, CURSOR_HOOK_FILE))) items.push({ type: "rm", path: CURSOR_HOOK_FILE });
|
|
139
|
-
// .cursor/hooks.json — only remove if it only contains the infernoflow hook
|
|
140
|
-
const hooksJsonPath = path.join(cwd, CURSOR_HOOKS_JSON);
|
|
141
|
-
if (exists(hooksJsonPath)) {
|
|
142
|
-
const cfg = readJSON(hooksJsonPath);
|
|
143
|
-
const hooks = cfg?.hooks || [];
|
|
144
|
-
const hasOnlyInferno = hooks.every(h => (h.name || h.command || "").includes("inferno"));
|
|
145
|
-
if (hasOnlyInferno) {
|
|
146
|
-
items.push({ type: "rm", path: CURSOR_HOOKS_JSON, desc: "infernoflow-only hooks config" });
|
|
147
|
-
} else {
|
|
148
|
-
items.push({ type: "edit", path: CURSOR_HOOKS_JSON, desc: "remove infernoflow hook entry (preserve others)" });
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
return items;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
function planCursorMcpJson(cwd) {
|
|
155
|
-
const p = path.join(cwd, CURSOR_MCP);
|
|
156
|
-
if (!exists(p)) return [];
|
|
157
|
-
const cfg = readJSON(p);
|
|
158
|
-
if (!cfg?.mcpServers?.infernoflow) return [];
|
|
159
|
-
const otherKeys = Object.keys(cfg.mcpServers || {}).filter(k => k !== "infernoflow");
|
|
160
|
-
if (otherKeys.length === 0 && Object.keys(cfg).length === 1) {
|
|
161
|
-
return [{ type: "rm", path: CURSOR_MCP, desc: "infernoflow-only file" }];
|
|
162
|
-
}
|
|
163
|
-
return [{ type: "edit", path: CURSOR_MCP, desc: 'remove "infernoflow" key (preserve other servers)' }];
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function planClaudeJson() {
|
|
167
|
-
if (!exists(CLAUDE_JSON)) return [];
|
|
168
|
-
const cfg = readJSON(CLAUDE_JSON);
|
|
169
|
-
if (!cfg?.mcpServers?.infernoflow) return [];
|
|
170
|
-
return [{ type: "edit", path: "~/.claude.json", desc: 'remove "infernoflow" MCP entry (preserve other entries)', _realPath: CLAUDE_JSON }];
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
function planGitHooks(cwd) {
|
|
174
|
-
const items = [];
|
|
175
|
-
for (const hookRel of GIT_HOOKS) {
|
|
176
|
-
const hookPath = path.join(cwd, hookRel);
|
|
177
|
-
if (!exists(hookPath)) continue;
|
|
178
|
-
const content = readFile(hookPath);
|
|
179
|
-
if (!content?.includes(INFERNO_MARKER)) continue;
|
|
180
|
-
|
|
181
|
-
const lines = content.split("\n");
|
|
182
|
-
const markerIdx = lines.findIndex(l => l.includes(INFERNO_MARKER));
|
|
183
|
-
const beforeMarker = lines.slice(0, markerIdx).join("\n").trim();
|
|
184
|
-
|
|
185
|
-
if (!beforeMarker || beforeMarker === "#!/bin/sh" || beforeMarker === "#!/bin/bash") {
|
|
186
|
-
items.push({ type: "rm", path: hookRel, desc: "infernoflow-only hook" });
|
|
187
|
-
} else {
|
|
188
|
-
items.push({ type: "edit", path: hookRel, desc: "remove infernoflow section (preserve existing hooks)" });
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
return items;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// ── executors ─────────────────────────────────────────────────────────────────
|
|
195
|
-
|
|
196
|
-
function removeInfernoDir(cwd, plan, dryRun) {
|
|
197
|
-
for (const item of plan) {
|
|
198
|
-
if (item.type === "skip") continue;
|
|
199
|
-
const full = path.join(cwd, item.path);
|
|
200
|
-
if (dryRun) continue;
|
|
201
|
-
try {
|
|
202
|
-
if (item.type === "rmdir") {
|
|
203
|
-
fs.rmSync(full, { recursive: true, force: true });
|
|
204
|
-
} else {
|
|
205
|
-
fs.unlinkSync(full);
|
|
206
|
-
}
|
|
207
|
-
} catch {}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
function removeClaudeMd(cwd, dryRun) {
|
|
212
|
-
if (dryRun) return;
|
|
213
|
-
try { fs.unlinkSync(path.join(cwd, CLAUDE_MD)); } catch {}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
function removeClaudeDir(cwd, plan, dryRun) {
|
|
217
|
-
const settingsPath = path.join(cwd, CLAUDE_DIR, "settings.json");
|
|
218
|
-
for (const item of plan) {
|
|
219
|
-
if (dryRun) continue;
|
|
220
|
-
if (item.type === "rm") {
|
|
221
|
-
try { fs.unlinkSync(path.join(cwd, item.path)); } catch {}
|
|
222
|
-
} else if (item.type === "edit") {
|
|
223
|
-
try {
|
|
224
|
-
const cfg = readJSON(settingsPath);
|
|
225
|
-
if (cfg?.tools) {
|
|
226
|
-
cfg.tools = cfg.tools.filter(t => !t.startsWith("mcp__infernoflow"));
|
|
227
|
-
}
|
|
228
|
-
fs.writeFileSync(settingsPath, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
229
|
-
} catch {}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
function removeCursorMcpServer(cwd, plan, dryRun) {
|
|
235
|
-
if (dryRun) return;
|
|
236
|
-
for (const item of plan) {
|
|
237
|
-
if (item.type === "rm") {
|
|
238
|
-
try { fs.unlinkSync(path.join(cwd, item.path)); } catch {}
|
|
239
|
-
} else if (item.type === "edit" && item.path === CURSOR_HOOKS_JSON) {
|
|
240
|
-
try {
|
|
241
|
-
const cfg = readJSON(path.join(cwd, CURSOR_HOOKS_JSON));
|
|
242
|
-
if (cfg?.hooks) {
|
|
243
|
-
cfg.hooks = cfg.hooks.filter(h => !(h.name || h.command || "").includes("inferno"));
|
|
244
|
-
}
|
|
245
|
-
fs.writeFileSync(path.join(cwd, CURSOR_HOOKS_JSON), JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
246
|
-
} catch {}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
function removeCursorMcpJson(cwd, plan, dryRun) {
|
|
252
|
-
const mcpPath = path.join(cwd, CURSOR_MCP);
|
|
253
|
-
for (const item of plan) {
|
|
254
|
-
if (dryRun) continue;
|
|
255
|
-
if (item.type === "rm") {
|
|
256
|
-
try { fs.unlinkSync(mcpPath); } catch {}
|
|
257
|
-
} else if (item.type === "edit") {
|
|
258
|
-
try {
|
|
259
|
-
const cfg = readJSON(mcpPath);
|
|
260
|
-
if (cfg?.mcpServers?.infernoflow) delete cfg.mcpServers.infernoflow;
|
|
261
|
-
fs.writeFileSync(mcpPath, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
262
|
-
} catch {}
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
function removeClaudeJson(plan, dryRun) {
|
|
268
|
-
for (const item of plan) {
|
|
269
|
-
if (dryRun) continue;
|
|
270
|
-
const p = item._realPath || CLAUDE_JSON;
|
|
271
|
-
if (item.type === "edit") {
|
|
272
|
-
try {
|
|
273
|
-
const cfg = readJSON(p);
|
|
274
|
-
if (cfg?.mcpServers?.infernoflow) delete cfg.mcpServers.infernoflow;
|
|
275
|
-
fs.writeFileSync(p, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
276
|
-
} catch {}
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
function removeGitHooks(cwd, plan, dryRun) {
|
|
282
|
-
for (const item of plan) {
|
|
283
|
-
const hookPath = path.join(cwd, item.path);
|
|
284
|
-
if (dryRun) continue;
|
|
285
|
-
if (item.type === "rm") {
|
|
286
|
-
try { fs.unlinkSync(hookPath); } catch {}
|
|
287
|
-
} else if (item.type === "edit") {
|
|
288
|
-
try {
|
|
289
|
-
const content = readFile(hookPath);
|
|
290
|
-
const lines = content.split("\n");
|
|
291
|
-
const markerIdx = lines.findIndex(l => l.includes(INFERNO_MARKER));
|
|
292
|
-
const preserved = lines.slice(0, markerIdx).join("\n").trimEnd();
|
|
293
|
-
fs.writeFileSync(hookPath, preserved + "\n", "utf8");
|
|
294
|
-
} catch {}
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// ── entry point ───────────────────────────────────────────────────────────────
|
|
300
|
-
|
|
301
|
-
export async function uninstallCommand(args = []) {
|
|
302
|
-
const has = f => args.includes(f);
|
|
303
|
-
const dryRun = has("--dry-run") || has("--dry");
|
|
304
|
-
const keepMem = has("--keep-memory");
|
|
305
|
-
const keepInf = has("--keep-inferno");
|
|
306
|
-
const skipPrompt= has("--yes") || has("-y");
|
|
307
|
-
const jsonMode = has("--json");
|
|
308
|
-
|
|
309
|
-
const cwd = process.cwd();
|
|
310
|
-
|
|
311
|
-
// ── Build the full removal plan ──────────────────────────────────────────
|
|
312
|
-
const plan = {
|
|
313
|
-
infernoDir: planInfernoDir(cwd, keepMem, keepInf),
|
|
314
|
-
claudeMd: planClaudeMd(cwd),
|
|
315
|
-
claudeDir: planClaudeDir(cwd),
|
|
316
|
-
cursorMcpServer: planCursorMcpServer(cwd),
|
|
317
|
-
cursorMcpJson: planCursorMcpJson(cwd),
|
|
318
|
-
claudeJson: planClaudeJson(),
|
|
319
|
-
gitHooks: planGitHooks(cwd),
|
|
320
|
-
};
|
|
321
|
-
|
|
322
|
-
const allItems = Object.values(plan).flat();
|
|
323
|
-
const actionItems = allItems.filter(i => i.type !== "skip");
|
|
324
|
-
|
|
325
|
-
if (jsonMode) {
|
|
326
|
-
console.log(JSON.stringify({ dryRun, keepMemory: keepMem, keepInferno: keepInf, plan, actionCount: actionItems.length }, null, 2));
|
|
327
|
-
return;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
const SEP = gray(" " + "─".repeat(52));
|
|
331
|
-
|
|
332
|
-
console.log();
|
|
333
|
-
console.log(" " + bold("🔥 infernoflow uninstall"));
|
|
334
|
-
if (dryRun) console.log(yellow(" DRY RUN — nothing will be changed"));
|
|
335
|
-
console.log(SEP);
|
|
336
|
-
|
|
337
|
-
if (actionItems.length === 0) {
|
|
338
|
-
console.log();
|
|
339
|
-
console.log(green(" ✔ Nothing to remove — infernoflow is not installed in this project"));
|
|
340
|
-
console.log();
|
|
341
|
-
return;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
// ── Print the plan ───────────────────────────────────────────────────────
|
|
345
|
-
console.log();
|
|
346
|
-
console.log(" " + bold("Will remove:"));
|
|
347
|
-
console.log();
|
|
348
|
-
|
|
349
|
-
const typeIcon = { rm: red(" ✖"), rmdir: red(" ✖"), edit: yellow(" ~"), skip: gray(" ·") };
|
|
350
|
-
|
|
351
|
-
for (const item of allItems) {
|
|
352
|
-
const icon = typeIcon[item.type] || " ?";
|
|
353
|
-
const label = item.desc ? gray(` (${item.desc})`) : "";
|
|
354
|
-
console.log(`${icon} ${item.path}${label}`);
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
if (keepMem) {
|
|
358
|
-
console.log();
|
|
359
|
-
console.log(gray(" ℹ inferno/sessions.jsonl will be preserved (--keep-memory)"));
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
console.log();
|
|
363
|
-
|
|
364
|
-
// ── Confirm ──────────────────────────────────────────────────────────────
|
|
365
|
-
if (!dryRun && !skipPrompt) {
|
|
366
|
-
const ans = await prompt(" Continue? " + gray("[y/N] ") );
|
|
367
|
-
if (!ans.trim().toLowerCase().startsWith("y")) {
|
|
368
|
-
console.log(gray("\n Aborted — nothing changed.\n"));
|
|
369
|
-
return;
|
|
370
|
-
}
|
|
371
|
-
console.log();
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
if (dryRun) {
|
|
375
|
-
console.log(gray(" ↑ Dry run complete — run without --dry-run to apply\n"));
|
|
376
|
-
return;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
// ── Execute ──────────────────────────────────────────────────────────────
|
|
380
|
-
removeInfernoDir(cwd, plan.infernoDir, false);
|
|
381
|
-
if (plan.claudeMd.length) removeClaudeMd(cwd, false);
|
|
382
|
-
if (plan.claudeDir.length) removeClaudeDir(cwd, plan.claudeDir, false);
|
|
383
|
-
if (plan.cursorMcpServer.length) removeCursorMcpServer(cwd, plan.cursorMcpServer, false);
|
|
384
|
-
if (plan.cursorMcpJson.length) removeCursorMcpJson(cwd, plan.cursorMcpJson, false);
|
|
385
|
-
if (plan.claudeJson.length) removeClaudeJson(plan.claudeJson, false);
|
|
386
|
-
if (plan.gitHooks.length) removeGitHooks(cwd, plan.gitHooks, false);
|
|
387
|
-
|
|
388
|
-
// ── Summary ──────────────────────────────────────────────────────────────
|
|
389
|
-
console.log(SEP);
|
|
390
|
-
console.log();
|
|
391
|
-
console.log(green(" ✔ infernoflow removed from this project"));
|
|
392
|
-
console.log();
|
|
393
|
-
|
|
394
|
-
const edited = actionItems.filter(i => i.type === "edit");
|
|
395
|
-
const removed = actionItems.filter(i => i.type === "rm" || i.type === "rmdir");
|
|
396
|
-
|
|
397
|
-
if (removed.length) console.log(gray(` Deleted: `) + removed.map(i => i.path).join(", "));
|
|
398
|
-
if (edited.length) console.log(gray(` Edited: `) + edited.map(i => i.path).join(", "));
|
|
399
|
-
|
|
400
|
-
if (keepMem) {
|
|
401
|
-
console.log();
|
|
402
|
-
console.log(gray(" Session memory kept → inferno/sessions.jsonl"));
|
|
403
|
-
console.log(gray(" Re-run infernoflow init to restore the rest."));
|
|
404
|
-
}
|
|
405
|
-
console.log();
|
|
406
|
-
}
|
|
1
|
+
import*as u from"node:fs";import*as r from"node:path";import*as A from"node:os";import*as K from"node:readline";import{bold as I,gray as a,green as D,yellow as J,red as N}from"../ui/output.mjs";const y="inferno",O="CLAUDE.md",k=".claude",S=".cursor",E=r.join(S,"inferno-mcp-server.mjs"),P="inferno-mcp-server.mjs",d=r.join(S,"hooks.json"),b=r.join(S,"hooks","inferno-session-draft.mjs"),v=r.join(S,"mcp.json"),w=r.join(A.homedir(),".claude.json"),L=[".git/hooks/post-commit",".git/hooks/pre-push"],C="# infernoflow";function h(n){return u.existsSync(n)}function m(n){try{return JSON.parse(u.readFileSync(n,"utf8"))}catch{return null}}function F(n){try{return u.readFileSync(n,"utf8")}catch{return null}}function W(n){return new Promise(e=>{const s=K.createInterface({input:process.stdin,output:process.stdout});s.question(n,o=>{s.close(),e(o)})})}function $(n,e,s){const o=[],t=r.join(n,y);if(!h(t))return o;if(s)return o.push({type:"skip",path:y,reason:"--keep-inferno"}),o;if(e){const i=u.readdirSync(t);for(const c of i)if(c==="sessions.jsonl")o.push({type:"skip",path:r.join(y,c),reason:"--keep-memory"});else{const l=r.join(t,c);u.statSync(l).isDirectory()?o.push({type:"rmdir",path:r.join(y,c)}):o.push({type:"rm",path:r.join(y,c)})}}else o.push({type:"rmdir",path:y});return o}function G(n){const e=r.join(n,O);return h(e)?[{type:"rm",path:O}]:[]}function T(n){const e=[],s=r.join(n,k,"settings.json");if(!h(s))return e;const o=m(s),t=o?.tools?.some?.(c=>c.startsWith?.("mcp__infernoflow")),i=o&&Object.keys(o).some(c=>c==="tools"?(o.tools||[]).some(l=>!l.startsWith("mcp__infernoflow")):c!=="tools");return t&&!i?e.push({type:"rm",path:r.join(k,"settings.json"),desc:"auto-approved tools"}):t&&e.push({type:"edit",path:r.join(k,"settings.json"),desc:"remove infernoflow tools (preserve other content)"}),e}function V(n){const e=[];h(r.join(n,E))&&e.push({type:"rm",path:E}),h(r.join(n,P))&&e.push({type:"rm",path:P}),h(r.join(n,b))&&e.push({type:"rm",path:b});const s=r.join(n,d);return h(s)&&((m(s)?.hooks||[]).every(c=>(c.name||c.command||"").includes("inferno"))?e.push({type:"rm",path:d,desc:"infernoflow-only hooks config"}):e.push({type:"edit",path:d,desc:"remove infernoflow hook entry (preserve others)"})),e}function q(n){const e=r.join(n,v);if(!h(e))return[];const s=m(e);return s?.mcpServers?.infernoflow?Object.keys(s.mcpServers||{}).filter(t=>t!=="infernoflow").length===0&&Object.keys(s).length===1?[{type:"rm",path:v,desc:"infernoflow-only file"}]:[{type:"edit",path:v,desc:'remove "infernoflow" key (preserve other servers)'}]:[]}function Y(){return h(w)?m(w)?.mcpServers?.infernoflow?[{type:"edit",path:"~/.claude.json",desc:'remove "infernoflow" MCP entry (preserve other entries)',_realPath:w}]:[]:[]}function z(n){const e=[];for(const s of L){const o=r.join(n,s);if(!h(o))continue;const t=F(o);if(!t?.includes(C))continue;const i=t.split(`
|
|
2
|
+
`),c=i.findIndex(f=>f.includes(C)),l=i.slice(0,c).join(`
|
|
3
|
+
`).trim();!l||l==="#!/bin/sh"||l==="#!/bin/bash"?e.push({type:"rm",path:s,desc:"infernoflow-only hook"}):e.push({type:"edit",path:s,desc:"remove infernoflow section (preserve existing hooks)"})}return e}function B(n,e,s){for(const o of e){if(o.type==="skip")continue;const t=r.join(n,o.path);if(!s)try{o.type==="rmdir"?u.rmSync(t,{recursive:!0,force:!0}):u.unlinkSync(t)}catch{}}}function Q(n,e){if(!e)try{u.unlinkSync(r.join(n,O))}catch{}}function X(n,e,s){const o=r.join(n,k,"settings.json");for(const t of e)if(!s){if(t.type==="rm")try{u.unlinkSync(r.join(n,t.path))}catch{}else if(t.type==="edit")try{const i=m(o);i?.tools&&(i.tools=i.tools.filter(c=>!c.startsWith("mcp__infernoflow"))),u.writeFileSync(o,JSON.stringify(i,null,2)+`
|
|
4
|
+
`,"utf8")}catch{}}}function Z(n,e,s){if(!s){for(const o of e)if(o.type==="rm")try{u.unlinkSync(r.join(n,o.path))}catch{}else if(o.type==="edit"&&o.path===d)try{const t=m(r.join(n,d));t?.hooks&&(t.hooks=t.hooks.filter(i=>!(i.name||i.command||"").includes("inferno"))),u.writeFileSync(r.join(n,d),JSON.stringify(t,null,2)+`
|
|
5
|
+
`,"utf8")}catch{}}}function oo(n,e,s){const o=r.join(n,v);for(const t of e)if(!s){if(t.type==="rm")try{u.unlinkSync(o)}catch{}else if(t.type==="edit")try{const i=m(o);i?.mcpServers?.infernoflow&&delete i.mcpServers.infernoflow,u.writeFileSync(o,JSON.stringify(i,null,2)+`
|
|
6
|
+
`,"utf8")}catch{}}}function eo(n,e){for(const s of n){if(e)continue;const o=s._realPath||w;if(s.type==="edit")try{const t=m(o);t?.mcpServers?.infernoflow&&delete t.mcpServers.infernoflow,u.writeFileSync(o,JSON.stringify(t,null,2)+`
|
|
7
|
+
`,"utf8")}catch{}}}function no(n,e,s){for(const o of e){const t=r.join(n,o.path);if(!s){if(o.type==="rm")try{u.unlinkSync(t)}catch{}else if(o.type==="edit")try{const c=F(t).split(`
|
|
8
|
+
`),l=c.findIndex(g=>g.includes(C)),f=c.slice(0,l).join(`
|
|
9
|
+
`).trimEnd();u.writeFileSync(t,f+`
|
|
10
|
+
`,"utf8")}catch{}}}}async function ro(n=[]){const e=p=>n.includes(p),s=e("--dry-run")||e("--dry"),o=e("--keep-memory"),t=e("--keep-inferno"),i=e("--yes")||e("-y"),c=e("--json"),l=process.cwd(),f={infernoDir:$(l,o,t),claudeMd:G(l),claudeDir:T(l),cursorMcpServer:V(l),cursorMcpJson:q(l),claudeJson:Y(),gitHooks:z(l)},g=Object.values(f).flat(),j=g.filter(p=>p.type!=="skip");if(c){console.log(JSON.stringify({dryRun:s,keepMemory:o,keepInferno:t,plan:f,actionCount:j.length},null,2));return}const R=a(" "+"\u2500".repeat(52));if(console.log(),console.log(" "+I("\u{1F525} infernoflow uninstall")),s&&console.log(J(" DRY RUN \u2014 nothing will be changed")),console.log(R),j.length===0){console.log(),console.log(D(" \u2714 Nothing to remove \u2014 infernoflow is not installed in this project")),console.log();return}console.log(),console.log(" "+I("Will remove:")),console.log();const U={rm:N(" \u2716"),rmdir:N(" \u2716"),edit:J(" ~"),skip:a(" \xB7")};for(const p of g){const x=U[p.type]||" ?",H=p.desc?a(` (${p.desc})`):"";console.log(`${x} ${p.path}${H}`)}if(o&&(console.log(),console.log(a(" \u2139 inferno/sessions.jsonl will be preserved (--keep-memory)"))),console.log(),!s&&!i){if(!(await W(" Continue? "+a("[y/N] "))).trim().toLowerCase().startsWith("y")){console.log(a(`
|
|
11
|
+
Aborted \u2014 nothing changed.
|
|
12
|
+
`));return}console.log()}if(s){console.log(a(` \u2191 Dry run complete \u2014 run without --dry-run to apply
|
|
13
|
+
`));return}B(l,f.infernoDir,!1),f.claudeMd.length&&Q(l,!1),f.claudeDir.length&&X(l,f.claudeDir,!1),f.cursorMcpServer.length&&Z(l,f.cursorMcpServer,!1),f.cursorMcpJson.length&&oo(l,f.cursorMcpJson,!1),f.claudeJson.length&&eo(f.claudeJson,!1),f.gitHooks.length&&no(l,f.gitHooks,!1),console.log(R),console.log(),console.log(D(" \u2714 infernoflow removed from this project")),console.log();const M=j.filter(p=>p.type==="edit"),_=j.filter(p=>p.type==="rm"||p.type==="rmdir");_.length&&console.log(a(" Deleted: ")+_.map(p=>p.path).join(", ")),M.length&&console.log(a(" Edited: ")+M.map(p=>p.path).join(", ")),o&&(console.log(),console.log(a(" Session memory kept \u2192 inferno/sessions.jsonl")),console.log(a(" Re-run infernoflow init to restore the rest."))),console.log()}export{ro as uninstallCommand};
|
|
@@ -1,153 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
function readJSON(f) { try { return JSON.parse(fs.readFileSync(f, "utf8")); } catch { return null; } }
|
|
23
|
-
|
|
24
|
-
export async function upgradeCommand(args) {
|
|
25
|
-
const cwd = process.cwd();
|
|
26
|
-
const dryRun = args.includes("--dry-run");
|
|
27
|
-
const yes = args.includes("--yes") || args.includes("-y");
|
|
28
|
-
|
|
29
|
-
console.log("\n " + bold("🔥 infernoflow upgrade"));
|
|
30
|
-
console.log(" " + "─".repeat(50) + "\n");
|
|
31
|
-
|
|
32
|
-
const infernoDir = path.join(cwd, INFERNO_DIR);
|
|
33
|
-
|
|
34
|
-
if (!fs.existsSync(infernoDir)) {
|
|
35
|
-
console.error(red(" ✘ inferno/ not found — run: infernoflow init --lite first\n"));
|
|
36
|
-
process.exit(1);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const liteMark = path.join(infernoDir, ".lite");
|
|
40
|
-
const isLite = fs.existsSync(liteMark);
|
|
41
|
-
const contract = readJSON(path.join(infernoDir, "contract.json"));
|
|
42
|
-
const policyId = contract?.policyId || path.basename(cwd);
|
|
43
|
-
const caps = contract?.capabilities || [];
|
|
44
|
-
|
|
45
|
-
if (!isLite) {
|
|
46
|
-
console.log(yellow(" ⚠ This project is already on the full setup — nothing to upgrade.\n"));
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
console.log(gray(` Project: ${policyId}`));
|
|
51
|
-
console.log(gray(` Capabilities: ${caps.length || 0}`));
|
|
52
|
-
console.log(gray(` Mode: lite → full\n`));
|
|
53
|
-
|
|
54
|
-
const created = [];
|
|
55
|
-
|
|
56
|
-
const write = (relPath, content) => {
|
|
57
|
-
const full = path.join(cwd, relPath);
|
|
58
|
-
if (fs.existsSync(full)) {
|
|
59
|
-
console.log(gray(` skipped (exists): ${relPath}`));
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
if (dryRun) {
|
|
63
|
-
console.log(cyan(` would create: ${relPath}`));
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
fs.mkdirSync(path.dirname(full), { recursive: true });
|
|
67
|
-
fs.writeFileSync(full, content, "utf8");
|
|
68
|
-
console.log(green(` ✔ Created: ${relPath}`));
|
|
69
|
-
created.push(relPath);
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
// ── scenarios/ ──────────────────────────────────────────────────────────────
|
|
73
|
-
if (caps.length) {
|
|
74
|
-
const scenario = {
|
|
75
|
-
scenarioId: "happy_path",
|
|
76
|
-
description: "Basic happy-path covering all capabilities",
|
|
77
|
-
capabilitiesCovered: caps,
|
|
78
|
-
steps: caps.map(c => ({ action: c, expect: `${c} works as expected` })),
|
|
79
|
-
};
|
|
80
|
-
write(
|
|
81
|
-
path.join(INFERNO_DIR, "scenarios", "happy_path.json"),
|
|
82
|
-
JSON.stringify(scenario, null, 2) + "\n"
|
|
83
|
-
);
|
|
84
|
-
} else {
|
|
85
|
-
if (!dryRun) fs.mkdirSync(path.join(infernoDir, "scenarios"), { recursive: true });
|
|
86
|
-
console.log(gray(" created: inferno/scenarios/ (empty — add scenarios as you define capabilities)"));
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// ── CHANGELOG.md ──────────────────────────────────────────────────────────
|
|
90
|
-
write(
|
|
91
|
-
path.join(INFERNO_DIR, "CHANGELOG.md"),
|
|
92
|
-
`# Changelog — ${policyId}\n\n## Unreleased\n\n- Upgraded from lite setup\n\n## 0.1.0 — Initial release\n\n- Project initialized with infernoflow\n`
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
// ── Upgrade contract.json — add rules + remove lite flag ──────────────────
|
|
96
|
-
if (!dryRun && contract) {
|
|
97
|
-
contract.rules = {
|
|
98
|
-
docsRequiredOnCapabilityChange: true,
|
|
99
|
-
requireScenarioForEachCapability: false, // warning only, not error
|
|
100
|
-
requireChangelogOnCapabilityChange: true,
|
|
101
|
-
};
|
|
102
|
-
delete contract.lite;
|
|
103
|
-
fs.writeFileSync(path.join(infernoDir, "contract.json"), JSON.stringify(contract, null, 2) + "\n");
|
|
104
|
-
console.log(green(" ✔ Updated: inferno/contract.json (added rules)"));
|
|
105
|
-
created.push("inferno/contract.json");
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// ── package.json scripts ───────────────────────────────────────────────────
|
|
109
|
-
const pkgPath = path.join(cwd, "package.json");
|
|
110
|
-
if (fs.existsSync(pkgPath) && !dryRun) {
|
|
111
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
112
|
-
pkg.scripts = pkg.scripts || {};
|
|
113
|
-
let changed = false;
|
|
114
|
-
const toAdd = {
|
|
115
|
-
"inferno:check": "infernoflow check",
|
|
116
|
-
"inferno:context": "infernoflow context",
|
|
117
|
-
"inferno:theme": "infernoflow theme",
|
|
118
|
-
};
|
|
119
|
-
for (const [k, v] of Object.entries(toAdd)) {
|
|
120
|
-
if (!pkg.scripts[k]) { pkg.scripts[k] = v; changed = true; }
|
|
121
|
-
}
|
|
122
|
-
if (changed) {
|
|
123
|
-
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
124
|
-
console.log(green(" ✔ Updated: package.json scripts (inferno:check, inferno:context, inferno:theme)"));
|
|
125
|
-
created.push("package.json");
|
|
126
|
-
}
|
|
127
|
-
} else if (dryRun) {
|
|
128
|
-
console.log(cyan(" would update: package.json scripts"));
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// ── Remove .lite marker ────────────────────────────────────────────────────
|
|
132
|
-
if (!dryRun && fs.existsSync(liteMark)) {
|
|
133
|
-
fs.unlinkSync(liteMark);
|
|
134
|
-
console.log(green(" ✔ Removed .lite marker — now on full setup"));
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
console.log();
|
|
138
|
-
|
|
139
|
-
if (dryRun) {
|
|
140
|
-
console.log(yellow(" ⚑ Dry run — nothing written. Remove --dry-run to apply.\n"));
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (!created.length) {
|
|
145
|
-
console.log(gray(" Nothing new to create — already fully set up.\n"));
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
console.log(" " + bold("Upgrade complete!"));
|
|
150
|
-
console.log(" " + cyan("→") + " Run " + cyan("infernoflow check") + " to validate the contract");
|
|
151
|
-
console.log(" " + cyan("→") + " Run " + cyan("infernoflow vibe") + " to start auto-sync mode");
|
|
152
|
-
console.log();
|
|
153
|
-
}
|
|
1
|
+
import*as n from"node:fs";import*as o from"node:path";import{bold as k,cyan as r,gray as c,green as g,yellow as x,red as O}from"../ui/output.mjs";const m="inferno";function N(l){try{return JSON.parse(n.readFileSync(l,"utf8"))}catch{return null}}async function F(l){const f=process.cwd(),i=l.includes("--dry-run"),v=l.includes("--yes")||l.includes("-y");console.log(`
|
|
2
|
+
`+k("\u{1F525} infernoflow upgrade")),console.log(" "+"\u2500".repeat(50)+`
|
|
3
|
+
`);const a=o.join(f,m);n.existsSync(a)||(console.error(O(` \u2718 inferno/ not found \u2014 run: infernoflow init --lite first
|
|
4
|
+
`)),process.exit(1));const y=o.join(a,".lite"),b=n.existsSync(y),s=N(o.join(a,"contract.json")),j=s?.policyId||o.basename(f),d=s?.capabilities||[];if(!b){console.log(x(` \u26A0 This project is already on the full setup \u2014 nothing to upgrade.
|
|
5
|
+
`));return}console.log(c(` Project: ${j}`)),console.log(c(` Capabilities: ${d.length||0}`)),console.log(c(` Mode: lite \u2192 full
|
|
6
|
+
`));const u=[],w=(e,t)=>{const p=o.join(f,e);if(n.existsSync(p)){console.log(c(` skipped (exists): ${e}`));return}if(i){console.log(r(` would create: ${e}`));return}n.mkdirSync(o.dirname(p),{recursive:!0}),n.writeFileSync(p,t,"utf8"),console.log(g(` \u2714 Created: ${e}`)),u.push(e)};if(d.length){const e={scenarioId:"happy_path",description:"Basic happy-path covering all capabilities",capabilitiesCovered:d,steps:d.map(t=>({action:t,expect:`${t} works as expected`}))};w(o.join(m,"scenarios","happy_path.json"),JSON.stringify(e,null,2)+`
|
|
7
|
+
`)}else i||n.mkdirSync(o.join(a,"scenarios"),{recursive:!0}),console.log(c(" created: inferno/scenarios/ (empty \u2014 add scenarios as you define capabilities)"));w(o.join(m,"CHANGELOG.md"),`# Changelog \u2014 ${j}
|
|
8
|
+
|
|
9
|
+
## Unreleased
|
|
10
|
+
|
|
11
|
+
- Upgraded from lite setup
|
|
12
|
+
|
|
13
|
+
## 0.1.0 \u2014 Initial release
|
|
14
|
+
|
|
15
|
+
- Project initialized with infernoflow
|
|
16
|
+
`),!i&&s&&(s.rules={docsRequiredOnCapabilityChange:!0,requireScenarioForEachCapability:!1,requireChangelogOnCapabilityChange:!0},delete s.lite,n.writeFileSync(o.join(a,"contract.json"),JSON.stringify(s,null,2)+`
|
|
17
|
+
`),console.log(g(" \u2714 Updated: inferno/contract.json (added rules)")),u.push("inferno/contract.json"));const h=o.join(f,"package.json");if(n.existsSync(h)&&!i){const e=JSON.parse(n.readFileSync(h,"utf8"));e.scripts=e.scripts||{};let t=!1;const p={"inferno:check":"infernoflow check","inferno:context":"infernoflow context","inferno:theme":"infernoflow theme"};for(const[S,C]of Object.entries(p))e.scripts[S]||(e.scripts[S]=C,t=!0);t&&(n.writeFileSync(h,JSON.stringify(e,null,2)+`
|
|
18
|
+
`),console.log(g(" \u2714 Updated: package.json scripts (inferno:check, inferno:context, inferno:theme)")),u.push("package.json"))}else i&&console.log(r(" would update: package.json scripts"));if(!i&&n.existsSync(y)&&(n.unlinkSync(y),console.log(g(" \u2714 Removed .lite marker \u2014 now on full setup"))),console.log(),i){console.log(x(` \u2691 Dry run \u2014 nothing written. Remove --dry-run to apply.
|
|
19
|
+
`));return}if(!u.length){console.log(c(` Nothing new to create \u2014 already fully set up.
|
|
20
|
+
`));return}console.log(" "+k("Upgrade complete!")),console.log(" "+r("\u2192")+" Run "+r("infernoflow check")+" to validate the contract"),console.log(" "+r("\u2192")+" Run "+r("infernoflow vibe")+" to start auto-sync mode"),console.log()}export{F as upgradeCommand};
|