@fenglimg/fabric-cli 2.0.0-rc.13 → 2.0.0-rc.21
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 +4 -2
- package/dist/{chunk-X7QPY5KH.js → chunk-4HC5ZK7H.js} +296 -301
- package/dist/{chunk-FDRLV5PL.js → chunk-FNO7CQDG.js} +5 -213
- package/dist/{chunk-WWNXR34K.js → chunk-G2CIOLD4.js} +16 -1
- package/dist/chunk-KZ2YITOS.js +225 -0
- package/dist/{chunk-OHWQNSLH.js → chunk-MF3OTILQ.js} +267 -44
- package/dist/{chunk-OBQU6NHO.js → chunk-ZSESMG6L.js} +0 -6
- package/dist/config-AYP5F72E.js +13 -0
- package/dist/doctor-L6TIXXIX.js +425 -0
- package/dist/index.js +11 -9
- package/dist/{install-SLS5W27W.js → install-DNZXGFHJ.js} +344 -359
- package/dist/{plan-context-hint-QMUPAXIB.js → plan-context-hint-CFDGXHCA.js} +10 -5
- package/dist/{serve-NGLXHDYC.js → serve-6PPQX7AW.js} +16 -11
- package/dist/{uninstall-JHUSFENL.js → uninstall-L2HEEOU3.js} +200 -215
- package/package.json +3 -3
- package/templates/hooks/configs/README.md +9 -5
- package/templates/hooks/configs/cursor-hooks.json +7 -10
- package/templates/hooks/fabric-hint.cjs +350 -21
- package/templates/hooks/knowledge-hint-broad.cjs +39 -14
- package/templates/hooks/knowledge-hint-narrow.cjs +31 -7
- package/templates/hooks/lib/banner-i18n.cjs +252 -0
- package/dist/chunk-Q72D24BG.js +0 -186
- package/dist/doctor-RILCO5OG.js +0 -282
- package/dist/hooks-HIWYI3VG.js +0 -13
- package/dist/scan-VHKZPT2W.js +0 -24
- package/templates/agents-md/AGENTS.md.template +0 -59
- package/templates/bootstrap/CLAUDE.md +0 -8
- package/templates/bootstrap/codex-AGENTS-header.md +0 -6
- package/templates/bootstrap/cursor-fabric-bootstrap.mdc +0 -10
|
@@ -1,31 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
detectClientSupports,
|
|
4
|
-
resolveClients
|
|
5
|
-
} from "./chunk-OHWQNSLH.js";
|
|
6
2
|
import {
|
|
7
3
|
FABRIC_HOOK_COMMAND_PATHS,
|
|
8
|
-
FABRIC_SECTION_REGEX,
|
|
9
4
|
HOOK_CONFIG_ARRAY_PATHS,
|
|
10
5
|
HOOK_CONFIG_TARGETS,
|
|
6
|
+
HOOK_LIB_DESTINATIONS,
|
|
11
7
|
HOOK_SCRIPT_DESTINATIONS,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
} from "./chunk-
|
|
8
|
+
SKILL_DESTINATIONS,
|
|
9
|
+
fabricAgentsSnapshotPath
|
|
10
|
+
} from "./chunk-4HC5ZK7H.js";
|
|
15
11
|
import {
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
detectClientSupports,
|
|
13
|
+
resolveClients
|
|
14
|
+
} from "./chunk-MF3OTILQ.js";
|
|
18
15
|
import {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
hasActionHint,
|
|
17
|
+
paint,
|
|
18
|
+
renderFabricError
|
|
19
|
+
} from "./chunk-G2CIOLD4.js";
|
|
22
20
|
import {
|
|
23
21
|
t
|
|
24
22
|
} from "./chunk-6ICJICVU.js";
|
|
23
|
+
import {
|
|
24
|
+
createDebugLogger,
|
|
25
|
+
resolveDevMode
|
|
26
|
+
} from "./chunk-ZSESMG6L.js";
|
|
25
27
|
|
|
26
28
|
// src/commands/uninstall.ts
|
|
27
29
|
import { existsSync as existsSync2, statSync } from "fs";
|
|
28
|
-
import {
|
|
30
|
+
import { rm as rm2 } from "fs/promises";
|
|
29
31
|
import { homedir } from "os";
|
|
30
32
|
import { isAbsolute, join as join2, relative, resolve, sep } from "path";
|
|
31
33
|
import { cancel, confirm, group, intro, isCancel, log, note, outro } from "@clack/prompts";
|
|
@@ -37,6 +39,7 @@ import { existsSync } from "fs";
|
|
|
37
39
|
import { readdir, readFile, rm, rmdir } from "fs/promises";
|
|
38
40
|
import { dirname, join } from "path";
|
|
39
41
|
import { atomicWriteJson, atomicWriteText } from "@fenglimg/fabric-shared/node/atomic-write";
|
|
42
|
+
import { BOOTSTRAP_REGEX } from "@fenglimg/fabric-shared/templates/bootstrap-canonical";
|
|
40
43
|
async function uninstallFabricArchiveSkill(projectRoot) {
|
|
41
44
|
return removeSkill("skill", SKILL_DESTINATIONS.fabricArchive, projectRoot);
|
|
42
45
|
}
|
|
@@ -80,121 +83,209 @@ async function removeHookScripts(step, rels, projectRoot) {
|
|
|
80
83
|
}
|
|
81
84
|
return results;
|
|
82
85
|
}
|
|
83
|
-
async function
|
|
86
|
+
async function removeHookLibs(projectRoot) {
|
|
87
|
+
const results = [];
|
|
88
|
+
for (const dirRel of HOOK_LIB_DESTINATIONS) {
|
|
89
|
+
const dirAbs = join(projectRoot, dirRel);
|
|
90
|
+
if (!existsSync(dirAbs)) {
|
|
91
|
+
results.push({ step: "hook-lib", path: dirAbs, status: "skipped", message: "absent" });
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
let entries;
|
|
95
|
+
try {
|
|
96
|
+
entries = await readdir(dirAbs);
|
|
97
|
+
} catch (error) {
|
|
98
|
+
results.push({
|
|
99
|
+
step: "hook-lib",
|
|
100
|
+
path: dirAbs,
|
|
101
|
+
status: "error",
|
|
102
|
+
message: error instanceof Error ? error.message : String(error)
|
|
103
|
+
});
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
for (const entry of entries) {
|
|
107
|
+
if (!entry.endsWith(".cjs")) continue;
|
|
108
|
+
results.push(await rmIfExists("hook-lib", join(dirAbs, entry)));
|
|
109
|
+
}
|
|
110
|
+
results.push(await rmDirIfEmpty("hook-lib-dir", dirAbs));
|
|
111
|
+
}
|
|
112
|
+
return results;
|
|
113
|
+
}
|
|
114
|
+
async function unmergeClaudeCodeHookConfig(projectRoot) {
|
|
84
115
|
return unmergeHookConfig({
|
|
85
116
|
step: "claude-hook-config",
|
|
86
117
|
projectRoot,
|
|
87
118
|
configRel: HOOK_CONFIG_TARGETS.claudeCode,
|
|
88
119
|
arrayPaths: [...HOOK_CONFIG_ARRAY_PATHS.claudeCode],
|
|
89
120
|
fabricCommands: Object.values(FABRIC_HOOK_COMMAND_PATHS.claudeCode),
|
|
90
|
-
extractCommands: extractClaudeCommands
|
|
91
|
-
cleanEmpties: opts.cleanEmpties === true
|
|
121
|
+
extractCommands: extractClaudeCommands
|
|
92
122
|
});
|
|
93
123
|
}
|
|
94
|
-
async function unmergeCodexHookConfig(projectRoot
|
|
124
|
+
async function unmergeCodexHookConfig(projectRoot) {
|
|
95
125
|
return unmergeHookConfig({
|
|
96
126
|
step: "codex-hook-config",
|
|
97
127
|
projectRoot,
|
|
98
128
|
configRel: HOOK_CONFIG_TARGETS.codex,
|
|
99
129
|
arrayPaths: [...HOOK_CONFIG_ARRAY_PATHS.codex],
|
|
100
130
|
fabricCommands: Object.values(FABRIC_HOOK_COMMAND_PATHS.codex),
|
|
101
|
-
extractCommands: extractFlatCommands
|
|
102
|
-
cleanEmpties: opts.cleanEmpties === true
|
|
131
|
+
extractCommands: extractFlatCommands
|
|
103
132
|
});
|
|
104
133
|
}
|
|
105
|
-
async function unmergeCursorHookConfig(projectRoot
|
|
134
|
+
async function unmergeCursorHookConfig(projectRoot) {
|
|
106
135
|
return unmergeHookConfig({
|
|
107
136
|
step: "cursor-hook-config",
|
|
108
137
|
projectRoot,
|
|
109
138
|
configRel: HOOK_CONFIG_TARGETS.cursor,
|
|
110
139
|
arrayPaths: [...HOOK_CONFIG_ARRAY_PATHS.cursor],
|
|
111
140
|
fabricCommands: Object.values(FABRIC_HOOK_COMMAND_PATHS.cursor),
|
|
112
|
-
extractCommands: extractFlatCommands
|
|
113
|
-
cleanEmpties: opts.cleanEmpties === true
|
|
141
|
+
extractCommands: extractFlatCommands
|
|
114
142
|
});
|
|
115
143
|
}
|
|
116
|
-
async function
|
|
144
|
+
async function stripFabricBootstrapBlocks(projectRoot) {
|
|
117
145
|
const results = [];
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
146
|
+
results.push(await stripClaudeBootstrapImports(projectRoot));
|
|
147
|
+
results.push(await stripManagedBlock(projectRoot, "AGENTS.md", { deleteWhenEmpty: false }));
|
|
148
|
+
results.push(
|
|
149
|
+
await stripManagedBlock(projectRoot, join(".cursor", "rules", "fabric-bootstrap.mdc"), {
|
|
150
|
+
deleteWhenEmpty: true
|
|
151
|
+
})
|
|
152
|
+
);
|
|
153
|
+
return results;
|
|
154
|
+
}
|
|
155
|
+
async function stripClaudeBootstrapImports(projectRoot) {
|
|
156
|
+
const step = "bootstrap-claude";
|
|
157
|
+
const target = join(projectRoot, "CLAUDE.md");
|
|
158
|
+
if (!existsSync(target)) {
|
|
159
|
+
return { step, path: target, status: "skipped", message: "absent" };
|
|
160
|
+
}
|
|
161
|
+
let existing;
|
|
162
|
+
try {
|
|
163
|
+
existing = await readFile(target, "utf8");
|
|
164
|
+
} catch (error) {
|
|
165
|
+
return {
|
|
166
|
+
step,
|
|
167
|
+
path: target,
|
|
168
|
+
status: "error",
|
|
169
|
+
message: error instanceof Error ? error.message : String(error)
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
const managedLines = /* @__PURE__ */ new Set(["@.fabric/AGENTS.md", "@.fabric/project-rules.md"]);
|
|
173
|
+
const lines = existing.split(/\r?\n/);
|
|
174
|
+
const filtered = lines.filter((l) => !managedLines.has(l.replace(/\s+$/, "")));
|
|
175
|
+
if (filtered.length === lines.length) {
|
|
176
|
+
return { step, path: target, status: "skipped", message: "no-fabric-section" };
|
|
177
|
+
}
|
|
178
|
+
while (filtered.length > 1 && filtered[filtered.length - 1] === "" && filtered[filtered.length - 2] === "") {
|
|
179
|
+
filtered.pop();
|
|
180
|
+
}
|
|
181
|
+
const next = filtered.join("\n");
|
|
182
|
+
if (next === existing) {
|
|
183
|
+
return { step, path: target, status: "skipped", message: "no-fabric-section" };
|
|
184
|
+
}
|
|
185
|
+
try {
|
|
186
|
+
await atomicWriteText(target, next);
|
|
187
|
+
return { step, path: target, status: "removed" };
|
|
188
|
+
} catch (error) {
|
|
189
|
+
return {
|
|
190
|
+
step,
|
|
191
|
+
path: target,
|
|
192
|
+
status: "error",
|
|
193
|
+
message: error instanceof Error ? error.message : String(error)
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
async function stripManagedBlock(projectRoot, relPath, options) {
|
|
198
|
+
const step = relPath.endsWith(".mdc") ? "bootstrap-cursor" : "bootstrap-codex";
|
|
199
|
+
const target = join(projectRoot, relPath);
|
|
200
|
+
if (!existsSync(target)) {
|
|
201
|
+
return { step, path: target, status: "skipped", message: "absent" };
|
|
202
|
+
}
|
|
203
|
+
let existing;
|
|
204
|
+
try {
|
|
205
|
+
existing = await readFile(target, "utf8");
|
|
206
|
+
} catch (error) {
|
|
207
|
+
return {
|
|
208
|
+
step,
|
|
209
|
+
path: target,
|
|
210
|
+
status: "error",
|
|
211
|
+
message: error instanceof Error ? error.message : String(error)
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
const match = existing.match(BOOTSTRAP_REGEX);
|
|
215
|
+
if (match === null) {
|
|
216
|
+
return { step, path: target, status: "skipped", message: "no-fabric-section" };
|
|
217
|
+
}
|
|
218
|
+
const before = existing.slice(0, match.index ?? 0);
|
|
219
|
+
const after = existing.slice((match.index ?? 0) + match[0].length);
|
|
220
|
+
const filtered = `${before}${after.replace(/^\r?\n/, "")}`;
|
|
221
|
+
if (options.deleteWhenEmpty && isFrontMatterOnly(filtered)) {
|
|
158
222
|
try {
|
|
159
|
-
await
|
|
160
|
-
|
|
223
|
+
await rm(target, { force: true });
|
|
224
|
+
return { step, path: target, status: "removed", message: "front-matter-only" };
|
|
161
225
|
} catch (error) {
|
|
162
|
-
|
|
163
|
-
step
|
|
226
|
+
return {
|
|
227
|
+
step,
|
|
164
228
|
path: target,
|
|
165
229
|
status: "error",
|
|
166
230
|
message: error instanceof Error ? error.message : String(error)
|
|
167
|
-
}
|
|
231
|
+
};
|
|
168
232
|
}
|
|
169
233
|
}
|
|
170
|
-
|
|
234
|
+
try {
|
|
235
|
+
await atomicWriteText(target, filtered);
|
|
236
|
+
return { step, path: target, status: "removed" };
|
|
237
|
+
} catch (error) {
|
|
238
|
+
return {
|
|
239
|
+
step,
|
|
240
|
+
path: target,
|
|
241
|
+
status: "error",
|
|
242
|
+
message: error instanceof Error ? error.message : String(error)
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
function isFrontMatterOnly(content) {
|
|
247
|
+
const trimmed = content.replace(/^\s+/, "");
|
|
248
|
+
const match = trimmed.match(/^---\n[\s\S]*?\n---\s*$/);
|
|
249
|
+
if (match === null) return trimmed.length === 0;
|
|
250
|
+
return true;
|
|
171
251
|
}
|
|
172
|
-
async function
|
|
252
|
+
async function deleteFabricAgentsSnapshot(projectRoot) {
|
|
253
|
+
const target = fabricAgentsSnapshotPath(projectRoot);
|
|
254
|
+
return rmIfExists("bootstrap-snapshot", target);
|
|
255
|
+
}
|
|
256
|
+
async function uninstallBootstrapStage(projectRoot, _opts = {}) {
|
|
173
257
|
const results = [];
|
|
174
258
|
await runAndCollect(
|
|
175
259
|
results,
|
|
176
|
-
"
|
|
260
|
+
"bootstrap-blocks",
|
|
177
261
|
projectRoot,
|
|
178
|
-
() =>
|
|
262
|
+
() => stripFabricBootstrapBlocks(projectRoot)
|
|
263
|
+
);
|
|
264
|
+
await runAndCollectOne(
|
|
265
|
+
results,
|
|
266
|
+
"bootstrap-snapshot",
|
|
267
|
+
projectRoot,
|
|
268
|
+
() => deleteFabricAgentsSnapshot(projectRoot)
|
|
179
269
|
);
|
|
180
270
|
await runAndCollectOne(
|
|
181
271
|
results,
|
|
182
272
|
"cursor-hook-config",
|
|
183
273
|
projectRoot,
|
|
184
|
-
() => unmergeCursorHookConfig(projectRoot
|
|
274
|
+
() => unmergeCursorHookConfig(projectRoot)
|
|
185
275
|
);
|
|
186
276
|
await runAndCollectOne(
|
|
187
277
|
results,
|
|
188
278
|
"codex-hook-config",
|
|
189
279
|
projectRoot,
|
|
190
|
-
() => unmergeCodexHookConfig(projectRoot
|
|
280
|
+
() => unmergeCodexHookConfig(projectRoot)
|
|
191
281
|
);
|
|
192
282
|
await runAndCollectOne(
|
|
193
283
|
results,
|
|
194
284
|
"claude-hook-config",
|
|
195
285
|
projectRoot,
|
|
196
|
-
() => unmergeClaudeCodeHookConfig(projectRoot
|
|
286
|
+
() => unmergeClaudeCodeHookConfig(projectRoot)
|
|
197
287
|
);
|
|
288
|
+
await runAndCollect(results, "hook-lib", projectRoot, () => removeHookLibs(projectRoot));
|
|
198
289
|
await runAndCollect(
|
|
199
290
|
results,
|
|
200
291
|
"hook-narrow-script",
|
|
@@ -339,7 +430,7 @@ async function unmergeHookConfig(args) {
|
|
|
339
430
|
}
|
|
340
431
|
const next = JSON.parse(JSON.stringify(parsed));
|
|
341
432
|
for (const dotted of args.arrayPaths) {
|
|
342
|
-
pruneArrayAtPath(next, dotted, args.fabricCommands, args.extractCommands
|
|
433
|
+
pruneArrayAtPath(next, dotted, args.fabricCommands, args.extractCommands);
|
|
343
434
|
}
|
|
344
435
|
if (jsonEqual(parsed, next)) {
|
|
345
436
|
return { step: args.step, path: target, status: "skipped", message: "no-fabric-entries" };
|
|
@@ -356,7 +447,7 @@ async function unmergeHookConfig(args) {
|
|
|
356
447
|
};
|
|
357
448
|
}
|
|
358
449
|
}
|
|
359
|
-
function pruneArrayAtPath(root, path, fabricCommands, extractCommands
|
|
450
|
+
function pruneArrayAtPath(root, path, fabricCommands, extractCommands) {
|
|
360
451
|
const keys = path.split(".");
|
|
361
452
|
const chain = [];
|
|
362
453
|
let cursor = root;
|
|
@@ -384,7 +475,7 @@ function pruneArrayAtPath(root, path, fabricCommands, extractCommands, cleanEmpt
|
|
|
384
475
|
});
|
|
385
476
|
const leaf = chain[chain.length - 1];
|
|
386
477
|
leaf.parent[leaf.key] = filtered;
|
|
387
|
-
if (
|
|
478
|
+
if (filtered.length > 0) {
|
|
388
479
|
return;
|
|
389
480
|
}
|
|
390
481
|
for (let i = chain.length - 1; i >= 0; i--) {
|
|
@@ -446,59 +537,24 @@ var uninstallCommand = defineCommand({
|
|
|
446
537
|
description: t("cli.uninstall.description")
|
|
447
538
|
},
|
|
448
539
|
args: {
|
|
449
|
-
target: {
|
|
450
|
-
type: "string",
|
|
451
|
-
description: t("cli.uninstall.args.target.description")
|
|
452
|
-
},
|
|
453
540
|
debug: {
|
|
454
541
|
type: "boolean",
|
|
455
542
|
description: t("cli.uninstall.args.debug.description"),
|
|
456
543
|
default: false
|
|
457
544
|
},
|
|
458
|
-
|
|
545
|
+
"dry-run": {
|
|
459
546
|
type: "boolean",
|
|
460
|
-
description: t("cli.uninstall.args.
|
|
547
|
+
description: t("cli.uninstall.args.dry-run.description"),
|
|
461
548
|
default: false
|
|
462
549
|
},
|
|
550
|
+
target: {
|
|
551
|
+
type: "string",
|
|
552
|
+
description: t("cli.uninstall.args.target.description")
|
|
553
|
+
},
|
|
463
554
|
yes: {
|
|
464
555
|
type: "boolean",
|
|
465
556
|
description: t("cli.uninstall.args.yes.description"),
|
|
466
557
|
default: false
|
|
467
|
-
},
|
|
468
|
-
plan: {
|
|
469
|
-
type: "boolean",
|
|
470
|
-
description: t("cli.uninstall.args.plan.description"),
|
|
471
|
-
default: false
|
|
472
|
-
},
|
|
473
|
-
bootstrap: {
|
|
474
|
-
type: "boolean",
|
|
475
|
-
default: true,
|
|
476
|
-
negativeDescription: t("cli.uninstall.flags.no-bootstrap")
|
|
477
|
-
},
|
|
478
|
-
mcp: {
|
|
479
|
-
type: "boolean",
|
|
480
|
-
default: true,
|
|
481
|
-
negativeDescription: t("cli.uninstall.flags.no-mcp")
|
|
482
|
-
},
|
|
483
|
-
scaffold: {
|
|
484
|
-
type: "boolean",
|
|
485
|
-
default: true,
|
|
486
|
-
negativeDescription: t("cli.uninstall.flags.no-scaffold")
|
|
487
|
-
},
|
|
488
|
-
interactive: {
|
|
489
|
-
type: "boolean",
|
|
490
|
-
description: t("cli.uninstall.flags.interactive"),
|
|
491
|
-
default: true
|
|
492
|
-
},
|
|
493
|
-
purge: {
|
|
494
|
-
type: "boolean",
|
|
495
|
-
description: t("cli.uninstall.flags.purge"),
|
|
496
|
-
default: false
|
|
497
|
-
},
|
|
498
|
-
"clean-empties": {
|
|
499
|
-
type: "boolean",
|
|
500
|
-
description: t("cli.uninstall.flags.clean-empties"),
|
|
501
|
-
default: false
|
|
502
558
|
}
|
|
503
559
|
},
|
|
504
560
|
async run({ args }) {
|
|
@@ -514,7 +570,15 @@ async function runUninstallCommand(args) {
|
|
|
514
570
|
for (const step of resolution.chain) {
|
|
515
571
|
logger(step);
|
|
516
572
|
}
|
|
517
|
-
|
|
573
|
+
try {
|
|
574
|
+
checkLockOrThrow(intent.target);
|
|
575
|
+
} catch (err) {
|
|
576
|
+
if (hasActionHint(err)) {
|
|
577
|
+
renderFabricError(err);
|
|
578
|
+
process.exit(1);
|
|
579
|
+
}
|
|
580
|
+
throw err;
|
|
581
|
+
}
|
|
518
582
|
const supports = detectClientSupports(intent.target);
|
|
519
583
|
const basePlan = await buildUninstallExecutionPlan(intent.target, {
|
|
520
584
|
...intent.options
|
|
@@ -525,7 +589,7 @@ async function runUninstallCommand(args) {
|
|
|
525
589
|
interactive: intent.interactiveSummary && !intent.wizardEnabled,
|
|
526
590
|
supports
|
|
527
591
|
};
|
|
528
|
-
const finalPlan = intent.wizardEnabled ? await resolveUninstallExecutionPlanWithWizard(planWithSupports,
|
|
592
|
+
const finalPlan = intent.wizardEnabled ? await resolveUninstallExecutionPlanWithWizard(planWithSupports, createDefaultUninstallWizardAdapter()) : planWithSupports;
|
|
529
593
|
if (finalPlan === null) {
|
|
530
594
|
process.exitCode = 130;
|
|
531
595
|
return;
|
|
@@ -541,7 +605,7 @@ async function runUninstallCommand(args) {
|
|
|
541
605
|
}))
|
|
542
606
|
};
|
|
543
607
|
}
|
|
544
|
-
if (intent.interactiveSummary && !intent.wizardEnabled && args.yes !== true
|
|
608
|
+
if (intent.interactiveSummary && !intent.wizardEnabled && args.yes !== true) {
|
|
545
609
|
const proceed = await confirmDestructive(finalPlan);
|
|
546
610
|
if (!proceed) {
|
|
547
611
|
process.exitCode = 130;
|
|
@@ -555,25 +619,19 @@ async function runUninstallCommand(args) {
|
|
|
555
619
|
function resolveUninstallCliIntent(args, targetInput) {
|
|
556
620
|
const target = normalizeTarget(targetInput);
|
|
557
621
|
const terminalInteractive = isInteractiveUninstall();
|
|
558
|
-
const planOnly = args
|
|
622
|
+
const planOnly = args["dry-run"] === true;
|
|
559
623
|
const options = {
|
|
560
|
-
|
|
561
|
-
skipBootstrap: args.bootstrap === false,
|
|
562
|
-
skipMcp: args.mcp === false,
|
|
563
|
-
skipScaffold: args.scaffold === false,
|
|
564
|
-
planOnly,
|
|
565
|
-
purge: args.purge === true,
|
|
566
|
-
cleanEmpties: args["clean-empties"] === true
|
|
624
|
+
planOnly
|
|
567
625
|
};
|
|
568
626
|
return {
|
|
569
627
|
target,
|
|
570
628
|
options,
|
|
571
|
-
interactiveSummary:
|
|
629
|
+
interactiveSummary: terminalInteractive,
|
|
572
630
|
wizardEnabled: shouldUseUninstallWizard(args, terminalInteractive) && !planOnly
|
|
573
631
|
};
|
|
574
632
|
}
|
|
575
633
|
function shouldUseUninstallWizard(args, terminalInteractive = isInteractiveUninstall()) {
|
|
576
|
-
return terminalInteractive && args.
|
|
634
|
+
return terminalInteractive && args.yes !== true;
|
|
577
635
|
}
|
|
578
636
|
async function buildUninstallExecutionPlan(target, options = {}) {
|
|
579
637
|
const scaffold = buildUninstallFabricPlan(target, options);
|
|
@@ -605,13 +663,6 @@ function buildUninstallFabricPlan(target, options = {}) {
|
|
|
605
663
|
const gk = join2(fabricDir, "knowledge", sub, ".gitkeep");
|
|
606
664
|
entries.push({ path: gk, kind: "gitkeep", absent: !existsSync2(gk) });
|
|
607
665
|
}
|
|
608
|
-
if (options.purge === true) {
|
|
609
|
-
for (const sub of KNOWLEDGE_SUBDIRS) {
|
|
610
|
-
const subdir = join2(fabricDir, "knowledge", sub);
|
|
611
|
-
entries.push({ path: subdir, kind: "knowledge-subdir", absent: !existsSync2(subdir) });
|
|
612
|
-
}
|
|
613
|
-
entries.push({ path: fabricDir, kind: "fabric-dir", absent: !existsSync2(fabricDir) });
|
|
614
|
-
}
|
|
615
666
|
const safeEntries = entries.filter((entry) => !isInsidePersonalRoot(entry.path, personalKnowledgeDir));
|
|
616
667
|
return {
|
|
617
668
|
target: absTarget,
|
|
@@ -623,9 +674,7 @@ function buildUninstallFabricPlan(target, options = {}) {
|
|
|
623
674
|
}
|
|
624
675
|
async function executeUninstallFabricPlan(plan) {
|
|
625
676
|
const results = [];
|
|
626
|
-
const
|
|
627
|
-
const otherEntries = plan.entries.filter((entry) => entry.kind !== "fabric-dir");
|
|
628
|
-
for (const entry of otherEntries) {
|
|
677
|
+
for (const entry of plan.entries) {
|
|
629
678
|
if (entry.absent) {
|
|
630
679
|
results.push({
|
|
631
680
|
step: scaffoldStepLabel(entry.kind),
|
|
@@ -636,7 +685,7 @@ async function executeUninstallFabricPlan(plan) {
|
|
|
636
685
|
continue;
|
|
637
686
|
}
|
|
638
687
|
try {
|
|
639
|
-
await rm2(entry.path, {
|
|
688
|
+
await rm2(entry.path, { force: true });
|
|
640
689
|
results.push({ step: scaffoldStepLabel(entry.kind), path: entry.path, status: "removed" });
|
|
641
690
|
} catch (error) {
|
|
642
691
|
results.push({
|
|
@@ -647,39 +696,6 @@ async function executeUninstallFabricPlan(plan) {
|
|
|
647
696
|
});
|
|
648
697
|
}
|
|
649
698
|
}
|
|
650
|
-
if (fabricDirEntry !== void 0) {
|
|
651
|
-
const path = fabricDirEntry.path;
|
|
652
|
-
if (!existsSync2(path)) {
|
|
653
|
-
results.push({
|
|
654
|
-
step: "fabric-dir",
|
|
655
|
-
path,
|
|
656
|
-
status: "skipped",
|
|
657
|
-
message: "absent"
|
|
658
|
-
});
|
|
659
|
-
} else {
|
|
660
|
-
try {
|
|
661
|
-
const entries = await readdir2(path);
|
|
662
|
-
if (entries.length > 0) {
|
|
663
|
-
results.push({
|
|
664
|
-
step: "fabric-dir",
|
|
665
|
-
path,
|
|
666
|
-
status: "skipped",
|
|
667
|
-
message: "not-empty"
|
|
668
|
-
});
|
|
669
|
-
} else {
|
|
670
|
-
await rm2(path, { recursive: true, force: true });
|
|
671
|
-
results.push({ step: "fabric-dir", path, status: "removed" });
|
|
672
|
-
}
|
|
673
|
-
} catch (error) {
|
|
674
|
-
results.push({
|
|
675
|
-
step: "fabric-dir",
|
|
676
|
-
path,
|
|
677
|
-
status: "error",
|
|
678
|
-
message: error instanceof Error ? error.message : String(error)
|
|
679
|
-
});
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
699
|
return results;
|
|
684
700
|
}
|
|
685
701
|
function scaffoldStepLabel(kind) {
|
|
@@ -688,10 +704,6 @@ function scaffoldStepLabel(kind) {
|
|
|
688
704
|
return "scaffold-state";
|
|
689
705
|
case "gitkeep":
|
|
690
706
|
return "scaffold-gitkeep";
|
|
691
|
-
case "knowledge-subdir":
|
|
692
|
-
return "scaffold-knowledge";
|
|
693
|
-
case "fabric-dir":
|
|
694
|
-
return "fabric-dir";
|
|
695
707
|
}
|
|
696
708
|
}
|
|
697
709
|
async function uninstallMcpClients(target, options = {}) {
|
|
@@ -799,7 +811,7 @@ async function executeUninstallStage(plan, stageName) {
|
|
|
799
811
|
case "scaffold":
|
|
800
812
|
return executeUninstallFabricPlan(plan.scaffold);
|
|
801
813
|
case "bootstrap": {
|
|
802
|
-
const opts = {
|
|
814
|
+
const opts = {};
|
|
803
815
|
return uninstallBootstrapStage(plan.target, opts);
|
|
804
816
|
}
|
|
805
817
|
case "mcp": {
|
|
@@ -812,12 +824,12 @@ async function uninstallFabric(target, options = {}) {
|
|
|
812
824
|
const plan = await buildUninstallExecutionPlan(target, options);
|
|
813
825
|
return executeUninstallExecutionPlan(plan);
|
|
814
826
|
}
|
|
815
|
-
async function resolveUninstallExecutionPlanWithWizard(basePlan,
|
|
827
|
+
async function resolveUninstallExecutionPlanWithWizard(basePlan, wizardAdapter) {
|
|
816
828
|
const selection = await wizardAdapter.run({
|
|
817
829
|
target: basePlan.target,
|
|
818
830
|
options: basePlan.options,
|
|
819
831
|
supports: basePlan.supports,
|
|
820
|
-
lockedStages:
|
|
832
|
+
lockedStages: []
|
|
821
833
|
});
|
|
822
834
|
if (selection === null) {
|
|
823
835
|
return null;
|
|
@@ -826,9 +838,7 @@ async function resolveUninstallExecutionPlanWithWizard(basePlan, args, wizardAda
|
|
|
826
838
|
...basePlan.options,
|
|
827
839
|
skipScaffold: !selection.scaffold,
|
|
828
840
|
skipBootstrap: !selection.bootstrap,
|
|
829
|
-
skipMcp: !selection.mcp
|
|
830
|
-
purge: selection.purge,
|
|
831
|
-
cleanEmpties: selection.cleanEmpties
|
|
841
|
+
skipMcp: !selection.mcp
|
|
832
842
|
};
|
|
833
843
|
const rebuilt = await buildUninstallExecutionPlan(basePlan.target, nextOptions);
|
|
834
844
|
return {
|
|
@@ -879,18 +889,6 @@ function createDefaultUninstallWizardAdapter() {
|
|
|
879
889
|
defaultValue: formatPromptDefault(!context.options.skipMcp)
|
|
880
890
|
}),
|
|
881
891
|
initialValue: !context.options.skipMcp
|
|
882
|
-
}),
|
|
883
|
-
purge: async () => confirmInGroup({
|
|
884
|
-
message: t("cli.uninstall.wizard.purge", {
|
|
885
|
-
defaultValue: formatPromptDefault(context.options.purge === true)
|
|
886
|
-
}),
|
|
887
|
-
initialValue: context.options.purge === true
|
|
888
|
-
}),
|
|
889
|
-
cleanEmpties: async () => confirmInGroup({
|
|
890
|
-
message: t("cli.uninstall.wizard.clean-empties", {
|
|
891
|
-
defaultValue: formatPromptDefault(context.options.cleanEmpties === true)
|
|
892
|
-
}),
|
|
893
|
-
initialValue: context.options.cleanEmpties === true
|
|
894
892
|
})
|
|
895
893
|
},
|
|
896
894
|
{
|
|
@@ -910,9 +908,7 @@ function createDefaultUninstallWizardAdapter() {
|
|
|
910
908
|
...context.options,
|
|
911
909
|
skipScaffold: !groupedSelection.scaffold,
|
|
912
910
|
skipBootstrap: !groupedSelection.bootstrap,
|
|
913
|
-
skipMcp: !groupedSelection.mcp
|
|
914
|
-
purge: groupedSelection.purge,
|
|
915
|
-
cleanEmpties: groupedSelection.cleanEmpties
|
|
911
|
+
skipMcp: !groupedSelection.mcp
|
|
916
912
|
};
|
|
917
913
|
log.step(t("cli.uninstall.wizard.step.review"));
|
|
918
914
|
printUninstallPlanSummary(context.target, previewOptions, context.supports);
|
|
@@ -939,13 +935,6 @@ async function confirmInGroup(options) {
|
|
|
939
935
|
}
|
|
940
936
|
return result;
|
|
941
937
|
}
|
|
942
|
-
function collectLockedWizardStages(args) {
|
|
943
|
-
const locked = [];
|
|
944
|
-
if (args.scaffold === false) locked.push("scaffold");
|
|
945
|
-
if (args.bootstrap === false) locked.push("bootstrap");
|
|
946
|
-
if (args.mcp === false) locked.push("mcp");
|
|
947
|
-
return locked;
|
|
948
|
-
}
|
|
949
938
|
async function confirmDestructive(plan) {
|
|
950
939
|
printUninstallPlanSummary(plan.target, plan.options, plan.supports);
|
|
951
940
|
const answer = await confirm({
|
|
@@ -964,9 +953,7 @@ function printUninstallPlanPreview(plan) {
|
|
|
964
953
|
t("cli.uninstall.plan.preview-result", {
|
|
965
954
|
scaffold: yesNoLabel(!plan.options.skipScaffold),
|
|
966
955
|
bootstrap: yesNoLabel(!plan.options.skipBootstrap),
|
|
967
|
-
mcp: yesNoLabel(!plan.options.skipMcp)
|
|
968
|
-
purge: yesNoLabel(plan.options.purge === true),
|
|
969
|
-
cleanEmpties: yesNoLabel(plan.options.cleanEmpties === true)
|
|
956
|
+
mcp: yesNoLabel(!plan.options.skipMcp)
|
|
970
957
|
})
|
|
971
958
|
);
|
|
972
959
|
if (!plan.options.skipScaffold && plan.scaffold.entries.length > 0) {
|
|
@@ -984,9 +971,7 @@ function printUninstallPlanSummary(target, options, supports) {
|
|
|
984
971
|
t("cli.uninstall.plan.actions", {
|
|
985
972
|
scaffold: yesNoLabel(!options.skipScaffold),
|
|
986
973
|
bootstrap: yesNoLabel(!options.skipBootstrap),
|
|
987
|
-
mcp: yesNoLabel(!options.skipMcp)
|
|
988
|
-
purge: yesNoLabel(options.purge === true),
|
|
989
|
-
cleanEmpties: yesNoLabel(options.cleanEmpties === true)
|
|
974
|
+
mcp: yesNoLabel(!options.skipMcp)
|
|
990
975
|
})
|
|
991
976
|
);
|
|
992
977
|
const detected = supports.filter((support) => support.detected);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fenglimg/fabric-cli",
|
|
3
|
-
"version": "2.0.0-rc.
|
|
3
|
+
"version": "2.0.0-rc.21",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"fab": "dist/index.js",
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
"tree-sitter-javascript": "^0.25.0",
|
|
21
21
|
"tree-sitter-typescript": "^0.23.2",
|
|
22
22
|
"web-tree-sitter": "^0.26.8",
|
|
23
|
-
"@fenglimg/fabric-
|
|
24
|
-
"@fenglimg/fabric-
|
|
23
|
+
"@fenglimg/fabric-server": "2.0.0-rc.21",
|
|
24
|
+
"@fenglimg/fabric-shared": "2.0.0-rc.21"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/node": "^22.15.0",
|