@fenglimg/fabric-cli 2.0.0-rc.11 → 2.0.0-rc.15
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 +6 -4
- package/dist/chunk-AIB54QRT.js +82 -0
- package/dist/{chunk-5MQ52F42.js → chunk-AXIFEVAS.js} +16 -219
- package/dist/{chunk-WWNXR34K.js → chunk-G2CIOLD4.js} +16 -1
- package/dist/{chunk-HQLEHH4O.js → chunk-SKSYUHKK.js} +267 -40
- package/dist/chunk-UTF4YBDN.js +366 -0
- package/dist/config-7YD365I3.js +13 -0
- package/dist/{doctor-RILCO5OG.js → doctor-6XHLQJXB.js} +67 -50
- package/dist/index.js +8 -9
- package/dist/{init-C56PWHID.js → install-JLDCHAXV.js} +409 -416
- package/dist/{plan-context-hint-QMUPAXIB.js → plan-context-hint-73U4FGKO.js} +6 -1
- package/dist/{serve-NGLXHDYC.js → serve-L3X5UHG2.js} +15 -10
- package/dist/{uninstall-DBAR2JBS.js → uninstall-DD6FIFCI.js} +81 -179
- package/package.json +3 -3
- package/templates/hooks/configs/README.md +10 -6
- package/templates/hooks/configs/cursor-hooks.json +7 -10
- package/templates/hooks/knowledge-hint-broad.cjs +28 -107
- package/templates/skills/fabric-archive/SKILL.md +15 -15
- package/templates/skills/fabric-import/SKILL.md +26 -26
- package/templates/skills/fabric-review/SKILL.md +19 -19
- package/dist/chunk-AW3G7ZH5.js +0 -576
- package/dist/chunk-WPTA74BY.js +0 -184
- package/dist/hooks-NX32PPEN.js +0 -13
- package/dist/scan-66EKMNAY.js +0 -24
|
@@ -10,7 +10,12 @@ var ALL_PATHS_SENTINEL = "**";
|
|
|
10
10
|
var planContextHintCommand = defineCommand({
|
|
11
11
|
meta: {
|
|
12
12
|
name: "plan-context-hint",
|
|
13
|
-
description: "Emit versioned knowledge hint JSON to stdout. Used by rc.6 hooks and the fabric-import skill."
|
|
13
|
+
description: "Emit versioned knowledge hint JSON to stdout. Used by rc.6 hooks and the fabric-import skill.",
|
|
14
|
+
// rc.15 TASK-004 (C8): hidden from `fab --help` listing. The command stays
|
|
15
|
+
// callable so hook scripts and the fabric-import skill can still invoke
|
|
16
|
+
// it via `fab plan-context-hint ...`; it just no longer appears in the
|
|
17
|
+
// top-level usage banner alongside install/doctor/serve/uninstall/config.
|
|
18
|
+
hidden: true
|
|
14
19
|
},
|
|
15
20
|
args: {
|
|
16
21
|
paths: {
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
hasActionHint,
|
|
3
4
|
paint,
|
|
5
|
+
renderFabricError,
|
|
4
6
|
symbol
|
|
5
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-G2CIOLD4.js";
|
|
8
|
+
import {
|
|
9
|
+
t
|
|
10
|
+
} from "./chunk-6ICJICVU.js";
|
|
6
11
|
import {
|
|
7
12
|
createDebugLogger,
|
|
8
13
|
resolveDevMode
|
|
9
14
|
} from "./chunk-OBQU6NHO.js";
|
|
10
|
-
import {
|
|
11
|
-
t
|
|
12
|
-
} from "./chunk-6ICJICVU.js";
|
|
13
15
|
|
|
14
16
|
// src/commands/serve.ts
|
|
15
17
|
import { defineCommand } from "citty";
|
|
@@ -39,11 +41,6 @@ var serveCommand = defineCommand({
|
|
|
39
41
|
type: "boolean",
|
|
40
42
|
description: t("cli.serve.args.debug.description"),
|
|
41
43
|
default: false
|
|
42
|
-
},
|
|
43
|
-
force: {
|
|
44
|
-
type: "boolean",
|
|
45
|
-
description: t("cli.serve.args.force.description"),
|
|
46
|
-
default: false
|
|
47
44
|
}
|
|
48
45
|
},
|
|
49
46
|
async run({ args }) {
|
|
@@ -55,7 +52,15 @@ var serveCommand = defineCommand({
|
|
|
55
52
|
const authToken = readAuthTokenFromEnv();
|
|
56
53
|
const host = validateHost(requestedHost, authToken);
|
|
57
54
|
const projectRoot = resolution.target;
|
|
58
|
-
|
|
55
|
+
try {
|
|
56
|
+
acquireLock(projectRoot);
|
|
57
|
+
} catch (err) {
|
|
58
|
+
if (hasActionHint(err)) {
|
|
59
|
+
renderFabricError(err);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
throw err;
|
|
63
|
+
}
|
|
59
64
|
process.on("exit", () => {
|
|
60
65
|
releaseLock(projectRoot);
|
|
61
66
|
});
|
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
detectClientSupports,
|
|
4
|
-
resolveClients
|
|
5
|
-
} from "./chunk-HQLEHH4O.js";
|
|
6
2
|
import {
|
|
7
3
|
FABRIC_HOOK_COMMAND_PATHS,
|
|
4
|
+
FABRIC_SECTION_REGEX,
|
|
8
5
|
HOOK_CONFIG_ARRAY_PATHS,
|
|
9
6
|
HOOK_CONFIG_TARGETS,
|
|
10
7
|
HOOK_SCRIPT_DESTINATIONS,
|
|
11
|
-
|
|
12
|
-
POINTER_LINE,
|
|
13
|
-
POINTER_TARGETS,
|
|
14
|
-
REVIEW_POINTER_LINE,
|
|
8
|
+
SECTION_TARGETS,
|
|
15
9
|
SKILL_DESTINATIONS
|
|
16
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-UTF4YBDN.js";
|
|
17
11
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
detectClientSupports,
|
|
13
|
+
resolveClients
|
|
14
|
+
} from "./chunk-SKSYUHKK.js";
|
|
20
15
|
import {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
hasActionHint,
|
|
17
|
+
paint,
|
|
18
|
+
renderFabricError
|
|
19
|
+
} from "./chunk-G2CIOLD4.js";
|
|
24
20
|
import {
|
|
25
21
|
t
|
|
26
22
|
} from "./chunk-6ICJICVU.js";
|
|
23
|
+
import {
|
|
24
|
+
createDebugLogger,
|
|
25
|
+
resolveDevMode
|
|
26
|
+
} from "./chunk-OBQU6NHO.js";
|
|
27
27
|
|
|
28
28
|
// src/commands/uninstall.ts
|
|
29
29
|
import { existsSync as existsSync2, statSync } from "fs";
|
|
30
|
-
import {
|
|
30
|
+
import { rm as rm2 } from "fs/promises";
|
|
31
31
|
import { homedir } from "os";
|
|
32
32
|
import { isAbsolute, join as join2, relative, resolve, sep } from "path";
|
|
33
33
|
import { cancel, confirm, group, intro, isCancel, log, note, outro } from "@clack/prompts";
|
|
@@ -82,45 +82,42 @@ async function removeHookScripts(step, rels, projectRoot) {
|
|
|
82
82
|
}
|
|
83
83
|
return results;
|
|
84
84
|
}
|
|
85
|
-
async function unmergeClaudeCodeHookConfig(projectRoot
|
|
85
|
+
async function unmergeClaudeCodeHookConfig(projectRoot) {
|
|
86
86
|
return unmergeHookConfig({
|
|
87
87
|
step: "claude-hook-config",
|
|
88
88
|
projectRoot,
|
|
89
89
|
configRel: HOOK_CONFIG_TARGETS.claudeCode,
|
|
90
90
|
arrayPaths: [...HOOK_CONFIG_ARRAY_PATHS.claudeCode],
|
|
91
91
|
fabricCommands: Object.values(FABRIC_HOOK_COMMAND_PATHS.claudeCode),
|
|
92
|
-
extractCommands: extractClaudeCommands
|
|
93
|
-
cleanEmpties: opts.cleanEmpties === true
|
|
92
|
+
extractCommands: extractClaudeCommands
|
|
94
93
|
});
|
|
95
94
|
}
|
|
96
|
-
async function unmergeCodexHookConfig(projectRoot
|
|
95
|
+
async function unmergeCodexHookConfig(projectRoot) {
|
|
97
96
|
return unmergeHookConfig({
|
|
98
97
|
step: "codex-hook-config",
|
|
99
98
|
projectRoot,
|
|
100
99
|
configRel: HOOK_CONFIG_TARGETS.codex,
|
|
101
100
|
arrayPaths: [...HOOK_CONFIG_ARRAY_PATHS.codex],
|
|
102
101
|
fabricCommands: Object.values(FABRIC_HOOK_COMMAND_PATHS.codex),
|
|
103
|
-
extractCommands: extractFlatCommands
|
|
104
|
-
cleanEmpties: opts.cleanEmpties === true
|
|
102
|
+
extractCommands: extractFlatCommands
|
|
105
103
|
});
|
|
106
104
|
}
|
|
107
|
-
async function unmergeCursorHookConfig(projectRoot
|
|
105
|
+
async function unmergeCursorHookConfig(projectRoot) {
|
|
108
106
|
return unmergeHookConfig({
|
|
109
107
|
step: "cursor-hook-config",
|
|
110
108
|
projectRoot,
|
|
111
109
|
configRel: HOOK_CONFIG_TARGETS.cursor,
|
|
112
110
|
arrayPaths: [...HOOK_CONFIG_ARRAY_PATHS.cursor],
|
|
113
111
|
fabricCommands: Object.values(FABRIC_HOOK_COMMAND_PATHS.cursor),
|
|
114
|
-
extractCommands: extractFlatCommands
|
|
115
|
-
cleanEmpties: opts.cleanEmpties === true
|
|
112
|
+
extractCommands: extractFlatCommands
|
|
116
113
|
});
|
|
117
114
|
}
|
|
118
|
-
async function
|
|
115
|
+
async function stripFabricKnowledgeBaseSection(projectRoot) {
|
|
119
116
|
const results = [];
|
|
120
|
-
for (const rel of
|
|
117
|
+
for (const rel of SECTION_TARGETS) {
|
|
121
118
|
const target = join(projectRoot, rel);
|
|
122
119
|
if (!existsSync(target)) {
|
|
123
|
-
results.push({ step: "
|
|
120
|
+
results.push({ step: "section", path: target, status: "skipped", message: "absent" });
|
|
124
121
|
continue;
|
|
125
122
|
}
|
|
126
123
|
let existing;
|
|
@@ -128,30 +125,41 @@ async function stripArchiveSkillPointers(projectRoot) {
|
|
|
128
125
|
existing = await readFile(target, "utf8");
|
|
129
126
|
} catch (error) {
|
|
130
127
|
results.push({
|
|
131
|
-
step: "
|
|
128
|
+
step: "section",
|
|
132
129
|
path: target,
|
|
133
130
|
status: "error",
|
|
134
131
|
message: error instanceof Error ? error.message : String(error)
|
|
135
132
|
});
|
|
136
133
|
continue;
|
|
137
134
|
}
|
|
138
|
-
const
|
|
139
|
-
|
|
135
|
+
const match = existing.match(FABRIC_SECTION_REGEX);
|
|
136
|
+
if (match === null) {
|
|
137
|
+
results.push({
|
|
138
|
+
step: "section",
|
|
139
|
+
path: target,
|
|
140
|
+
status: "skipped",
|
|
141
|
+
message: "no-fabric-section"
|
|
142
|
+
});
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const before = existing.slice(0, match.index ?? 0);
|
|
146
|
+
const after = existing.slice((match.index ?? 0) + match[0].length);
|
|
147
|
+
const filtered = `${before}${after.replace(/^\r?\n/, "")}`;
|
|
140
148
|
if (filtered === existing) {
|
|
141
149
|
results.push({
|
|
142
|
-
step: "
|
|
150
|
+
step: "section",
|
|
143
151
|
path: target,
|
|
144
152
|
status: "skipped",
|
|
145
|
-
message: "no-fabric-
|
|
153
|
+
message: "no-fabric-section"
|
|
146
154
|
});
|
|
147
155
|
continue;
|
|
148
156
|
}
|
|
149
157
|
try {
|
|
150
158
|
await atomicWriteText(target, filtered);
|
|
151
|
-
results.push({ step: "
|
|
159
|
+
results.push({ step: "section", path: target, status: "removed" });
|
|
152
160
|
} catch (error) {
|
|
153
161
|
results.push({
|
|
154
|
-
step: "
|
|
162
|
+
step: "section",
|
|
155
163
|
path: target,
|
|
156
164
|
status: "error",
|
|
157
165
|
message: error instanceof Error ? error.message : String(error)
|
|
@@ -160,31 +168,31 @@ async function stripArchiveSkillPointers(projectRoot) {
|
|
|
160
168
|
}
|
|
161
169
|
return results;
|
|
162
170
|
}
|
|
163
|
-
async function uninstallBootstrapStage(projectRoot,
|
|
171
|
+
async function uninstallBootstrapStage(projectRoot, _opts = {}) {
|
|
164
172
|
const results = [];
|
|
165
173
|
await runAndCollect(
|
|
166
174
|
results,
|
|
167
|
-
"
|
|
175
|
+
"section",
|
|
168
176
|
projectRoot,
|
|
169
|
-
() =>
|
|
177
|
+
() => stripFabricKnowledgeBaseSection(projectRoot)
|
|
170
178
|
);
|
|
171
179
|
await runAndCollectOne(
|
|
172
180
|
results,
|
|
173
181
|
"cursor-hook-config",
|
|
174
182
|
projectRoot,
|
|
175
|
-
() => unmergeCursorHookConfig(projectRoot
|
|
183
|
+
() => unmergeCursorHookConfig(projectRoot)
|
|
176
184
|
);
|
|
177
185
|
await runAndCollectOne(
|
|
178
186
|
results,
|
|
179
187
|
"codex-hook-config",
|
|
180
188
|
projectRoot,
|
|
181
|
-
() => unmergeCodexHookConfig(projectRoot
|
|
189
|
+
() => unmergeCodexHookConfig(projectRoot)
|
|
182
190
|
);
|
|
183
191
|
await runAndCollectOne(
|
|
184
192
|
results,
|
|
185
193
|
"claude-hook-config",
|
|
186
194
|
projectRoot,
|
|
187
|
-
() => unmergeClaudeCodeHookConfig(projectRoot
|
|
195
|
+
() => unmergeClaudeCodeHookConfig(projectRoot)
|
|
188
196
|
);
|
|
189
197
|
await runAndCollect(
|
|
190
198
|
results,
|
|
@@ -330,7 +338,7 @@ async function unmergeHookConfig(args) {
|
|
|
330
338
|
}
|
|
331
339
|
const next = JSON.parse(JSON.stringify(parsed));
|
|
332
340
|
for (const dotted of args.arrayPaths) {
|
|
333
|
-
pruneArrayAtPath(next, dotted, args.fabricCommands, args.extractCommands
|
|
341
|
+
pruneArrayAtPath(next, dotted, args.fabricCommands, args.extractCommands);
|
|
334
342
|
}
|
|
335
343
|
if (jsonEqual(parsed, next)) {
|
|
336
344
|
return { step: args.step, path: target, status: "skipped", message: "no-fabric-entries" };
|
|
@@ -347,7 +355,7 @@ async function unmergeHookConfig(args) {
|
|
|
347
355
|
};
|
|
348
356
|
}
|
|
349
357
|
}
|
|
350
|
-
function pruneArrayAtPath(root, path, fabricCommands, extractCommands
|
|
358
|
+
function pruneArrayAtPath(root, path, fabricCommands, extractCommands) {
|
|
351
359
|
const keys = path.split(".");
|
|
352
360
|
const chain = [];
|
|
353
361
|
let cursor = root;
|
|
@@ -375,7 +383,7 @@ function pruneArrayAtPath(root, path, fabricCommands, extractCommands, cleanEmpt
|
|
|
375
383
|
});
|
|
376
384
|
const leaf = chain[chain.length - 1];
|
|
377
385
|
leaf.parent[leaf.key] = filtered;
|
|
378
|
-
if (
|
|
386
|
+
if (filtered.length > 0) {
|
|
379
387
|
return;
|
|
380
388
|
}
|
|
381
389
|
for (let i = chain.length - 1; i >= 0; i--) {
|
|
@@ -437,59 +445,24 @@ var uninstallCommand = defineCommand({
|
|
|
437
445
|
description: t("cli.uninstall.description")
|
|
438
446
|
},
|
|
439
447
|
args: {
|
|
440
|
-
target: {
|
|
441
|
-
type: "string",
|
|
442
|
-
description: t("cli.uninstall.args.target.description")
|
|
443
|
-
},
|
|
444
448
|
debug: {
|
|
445
449
|
type: "boolean",
|
|
446
450
|
description: t("cli.uninstall.args.debug.description"),
|
|
447
451
|
default: false
|
|
448
452
|
},
|
|
449
|
-
|
|
453
|
+
"dry-run": {
|
|
450
454
|
type: "boolean",
|
|
451
|
-
description: t("cli.uninstall.args.
|
|
455
|
+
description: t("cli.uninstall.args.dry-run.description"),
|
|
452
456
|
default: false
|
|
453
457
|
},
|
|
458
|
+
target: {
|
|
459
|
+
type: "string",
|
|
460
|
+
description: t("cli.uninstall.args.target.description")
|
|
461
|
+
},
|
|
454
462
|
yes: {
|
|
455
463
|
type: "boolean",
|
|
456
464
|
description: t("cli.uninstall.args.yes.description"),
|
|
457
465
|
default: false
|
|
458
|
-
},
|
|
459
|
-
plan: {
|
|
460
|
-
type: "boolean",
|
|
461
|
-
description: t("cli.uninstall.args.plan.description"),
|
|
462
|
-
default: false
|
|
463
|
-
},
|
|
464
|
-
bootstrap: {
|
|
465
|
-
type: "boolean",
|
|
466
|
-
default: true,
|
|
467
|
-
negativeDescription: t("cli.uninstall.flags.no-bootstrap")
|
|
468
|
-
},
|
|
469
|
-
mcp: {
|
|
470
|
-
type: "boolean",
|
|
471
|
-
default: true,
|
|
472
|
-
negativeDescription: t("cli.uninstall.flags.no-mcp")
|
|
473
|
-
},
|
|
474
|
-
scaffold: {
|
|
475
|
-
type: "boolean",
|
|
476
|
-
default: true,
|
|
477
|
-
negativeDescription: t("cli.uninstall.flags.no-scaffold")
|
|
478
|
-
},
|
|
479
|
-
interactive: {
|
|
480
|
-
type: "boolean",
|
|
481
|
-
description: t("cli.uninstall.flags.interactive"),
|
|
482
|
-
default: true
|
|
483
|
-
},
|
|
484
|
-
purge: {
|
|
485
|
-
type: "boolean",
|
|
486
|
-
description: t("cli.uninstall.flags.purge"),
|
|
487
|
-
default: false
|
|
488
|
-
},
|
|
489
|
-
"clean-empties": {
|
|
490
|
-
type: "boolean",
|
|
491
|
-
description: t("cli.uninstall.flags.clean-empties"),
|
|
492
|
-
default: false
|
|
493
466
|
}
|
|
494
467
|
},
|
|
495
468
|
async run({ args }) {
|
|
@@ -505,7 +478,15 @@ async function runUninstallCommand(args) {
|
|
|
505
478
|
for (const step of resolution.chain) {
|
|
506
479
|
logger(step);
|
|
507
480
|
}
|
|
508
|
-
|
|
481
|
+
try {
|
|
482
|
+
checkLockOrThrow(intent.target);
|
|
483
|
+
} catch (err) {
|
|
484
|
+
if (hasActionHint(err)) {
|
|
485
|
+
renderFabricError(err);
|
|
486
|
+
process.exit(1);
|
|
487
|
+
}
|
|
488
|
+
throw err;
|
|
489
|
+
}
|
|
509
490
|
const supports = detectClientSupports(intent.target);
|
|
510
491
|
const basePlan = await buildUninstallExecutionPlan(intent.target, {
|
|
511
492
|
...intent.options
|
|
@@ -516,7 +497,7 @@ async function runUninstallCommand(args) {
|
|
|
516
497
|
interactive: intent.interactiveSummary && !intent.wizardEnabled,
|
|
517
498
|
supports
|
|
518
499
|
};
|
|
519
|
-
const finalPlan = intent.wizardEnabled ? await resolveUninstallExecutionPlanWithWizard(planWithSupports,
|
|
500
|
+
const finalPlan = intent.wizardEnabled ? await resolveUninstallExecutionPlanWithWizard(planWithSupports, createDefaultUninstallWizardAdapter()) : planWithSupports;
|
|
520
501
|
if (finalPlan === null) {
|
|
521
502
|
process.exitCode = 130;
|
|
522
503
|
return;
|
|
@@ -532,7 +513,7 @@ async function runUninstallCommand(args) {
|
|
|
532
513
|
}))
|
|
533
514
|
};
|
|
534
515
|
}
|
|
535
|
-
if (intent.interactiveSummary && !intent.wizardEnabled && args.yes !== true
|
|
516
|
+
if (intent.interactiveSummary && !intent.wizardEnabled && args.yes !== true) {
|
|
536
517
|
const proceed = await confirmDestructive(finalPlan);
|
|
537
518
|
if (!proceed) {
|
|
538
519
|
process.exitCode = 130;
|
|
@@ -546,25 +527,19 @@ async function runUninstallCommand(args) {
|
|
|
546
527
|
function resolveUninstallCliIntent(args, targetInput) {
|
|
547
528
|
const target = normalizeTarget(targetInput);
|
|
548
529
|
const terminalInteractive = isInteractiveUninstall();
|
|
549
|
-
const planOnly = args
|
|
530
|
+
const planOnly = args["dry-run"] === true;
|
|
550
531
|
const options = {
|
|
551
|
-
|
|
552
|
-
skipBootstrap: args.bootstrap === false,
|
|
553
|
-
skipMcp: args.mcp === false,
|
|
554
|
-
skipScaffold: args.scaffold === false,
|
|
555
|
-
planOnly,
|
|
556
|
-
purge: args.purge === true,
|
|
557
|
-
cleanEmpties: args["clean-empties"] === true
|
|
532
|
+
planOnly
|
|
558
533
|
};
|
|
559
534
|
return {
|
|
560
535
|
target,
|
|
561
536
|
options,
|
|
562
|
-
interactiveSummary:
|
|
537
|
+
interactiveSummary: terminalInteractive,
|
|
563
538
|
wizardEnabled: shouldUseUninstallWizard(args, terminalInteractive) && !planOnly
|
|
564
539
|
};
|
|
565
540
|
}
|
|
566
541
|
function shouldUseUninstallWizard(args, terminalInteractive = isInteractiveUninstall()) {
|
|
567
|
-
return terminalInteractive && args.
|
|
542
|
+
return terminalInteractive && args.yes !== true;
|
|
568
543
|
}
|
|
569
544
|
async function buildUninstallExecutionPlan(target, options = {}) {
|
|
570
545
|
const scaffold = buildUninstallFabricPlan(target, options);
|
|
@@ -596,13 +571,6 @@ function buildUninstallFabricPlan(target, options = {}) {
|
|
|
596
571
|
const gk = join2(fabricDir, "knowledge", sub, ".gitkeep");
|
|
597
572
|
entries.push({ path: gk, kind: "gitkeep", absent: !existsSync2(gk) });
|
|
598
573
|
}
|
|
599
|
-
if (options.purge === true) {
|
|
600
|
-
for (const sub of KNOWLEDGE_SUBDIRS) {
|
|
601
|
-
const subdir = join2(fabricDir, "knowledge", sub);
|
|
602
|
-
entries.push({ path: subdir, kind: "knowledge-subdir", absent: !existsSync2(subdir) });
|
|
603
|
-
}
|
|
604
|
-
entries.push({ path: fabricDir, kind: "fabric-dir", absent: !existsSync2(fabricDir) });
|
|
605
|
-
}
|
|
606
574
|
const safeEntries = entries.filter((entry) => !isInsidePersonalRoot(entry.path, personalKnowledgeDir));
|
|
607
575
|
return {
|
|
608
576
|
target: absTarget,
|
|
@@ -614,9 +582,7 @@ function buildUninstallFabricPlan(target, options = {}) {
|
|
|
614
582
|
}
|
|
615
583
|
async function executeUninstallFabricPlan(plan) {
|
|
616
584
|
const results = [];
|
|
617
|
-
const
|
|
618
|
-
const otherEntries = plan.entries.filter((entry) => entry.kind !== "fabric-dir");
|
|
619
|
-
for (const entry of otherEntries) {
|
|
585
|
+
for (const entry of plan.entries) {
|
|
620
586
|
if (entry.absent) {
|
|
621
587
|
results.push({
|
|
622
588
|
step: scaffoldStepLabel(entry.kind),
|
|
@@ -627,7 +593,7 @@ async function executeUninstallFabricPlan(plan) {
|
|
|
627
593
|
continue;
|
|
628
594
|
}
|
|
629
595
|
try {
|
|
630
|
-
await rm2(entry.path, {
|
|
596
|
+
await rm2(entry.path, { force: true });
|
|
631
597
|
results.push({ step: scaffoldStepLabel(entry.kind), path: entry.path, status: "removed" });
|
|
632
598
|
} catch (error) {
|
|
633
599
|
results.push({
|
|
@@ -638,39 +604,6 @@ async function executeUninstallFabricPlan(plan) {
|
|
|
638
604
|
});
|
|
639
605
|
}
|
|
640
606
|
}
|
|
641
|
-
if (fabricDirEntry !== void 0) {
|
|
642
|
-
const path = fabricDirEntry.path;
|
|
643
|
-
if (!existsSync2(path)) {
|
|
644
|
-
results.push({
|
|
645
|
-
step: "fabric-dir",
|
|
646
|
-
path,
|
|
647
|
-
status: "skipped",
|
|
648
|
-
message: "absent"
|
|
649
|
-
});
|
|
650
|
-
} else {
|
|
651
|
-
try {
|
|
652
|
-
const entries = await readdir2(path);
|
|
653
|
-
if (entries.length > 0) {
|
|
654
|
-
results.push({
|
|
655
|
-
step: "fabric-dir",
|
|
656
|
-
path,
|
|
657
|
-
status: "skipped",
|
|
658
|
-
message: "not-empty"
|
|
659
|
-
});
|
|
660
|
-
} else {
|
|
661
|
-
await rm2(path, { recursive: true, force: true });
|
|
662
|
-
results.push({ step: "fabric-dir", path, status: "removed" });
|
|
663
|
-
}
|
|
664
|
-
} catch (error) {
|
|
665
|
-
results.push({
|
|
666
|
-
step: "fabric-dir",
|
|
667
|
-
path,
|
|
668
|
-
status: "error",
|
|
669
|
-
message: error instanceof Error ? error.message : String(error)
|
|
670
|
-
});
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
607
|
return results;
|
|
675
608
|
}
|
|
676
609
|
function scaffoldStepLabel(kind) {
|
|
@@ -679,10 +612,6 @@ function scaffoldStepLabel(kind) {
|
|
|
679
612
|
return "scaffold-state";
|
|
680
613
|
case "gitkeep":
|
|
681
614
|
return "scaffold-gitkeep";
|
|
682
|
-
case "knowledge-subdir":
|
|
683
|
-
return "scaffold-knowledge";
|
|
684
|
-
case "fabric-dir":
|
|
685
|
-
return "fabric-dir";
|
|
686
615
|
}
|
|
687
616
|
}
|
|
688
617
|
async function uninstallMcpClients(target, options = {}) {
|
|
@@ -790,7 +719,7 @@ async function executeUninstallStage(plan, stageName) {
|
|
|
790
719
|
case "scaffold":
|
|
791
720
|
return executeUninstallFabricPlan(plan.scaffold);
|
|
792
721
|
case "bootstrap": {
|
|
793
|
-
const opts = {
|
|
722
|
+
const opts = {};
|
|
794
723
|
return uninstallBootstrapStage(plan.target, opts);
|
|
795
724
|
}
|
|
796
725
|
case "mcp": {
|
|
@@ -803,12 +732,12 @@ async function uninstallFabric(target, options = {}) {
|
|
|
803
732
|
const plan = await buildUninstallExecutionPlan(target, options);
|
|
804
733
|
return executeUninstallExecutionPlan(plan);
|
|
805
734
|
}
|
|
806
|
-
async function resolveUninstallExecutionPlanWithWizard(basePlan,
|
|
735
|
+
async function resolveUninstallExecutionPlanWithWizard(basePlan, wizardAdapter) {
|
|
807
736
|
const selection = await wizardAdapter.run({
|
|
808
737
|
target: basePlan.target,
|
|
809
738
|
options: basePlan.options,
|
|
810
739
|
supports: basePlan.supports,
|
|
811
|
-
lockedStages:
|
|
740
|
+
lockedStages: []
|
|
812
741
|
});
|
|
813
742
|
if (selection === null) {
|
|
814
743
|
return null;
|
|
@@ -817,9 +746,7 @@ async function resolveUninstallExecutionPlanWithWizard(basePlan, args, wizardAda
|
|
|
817
746
|
...basePlan.options,
|
|
818
747
|
skipScaffold: !selection.scaffold,
|
|
819
748
|
skipBootstrap: !selection.bootstrap,
|
|
820
|
-
skipMcp: !selection.mcp
|
|
821
|
-
purge: selection.purge,
|
|
822
|
-
cleanEmpties: selection.cleanEmpties
|
|
749
|
+
skipMcp: !selection.mcp
|
|
823
750
|
};
|
|
824
751
|
const rebuilt = await buildUninstallExecutionPlan(basePlan.target, nextOptions);
|
|
825
752
|
return {
|
|
@@ -870,18 +797,6 @@ function createDefaultUninstallWizardAdapter() {
|
|
|
870
797
|
defaultValue: formatPromptDefault(!context.options.skipMcp)
|
|
871
798
|
}),
|
|
872
799
|
initialValue: !context.options.skipMcp
|
|
873
|
-
}),
|
|
874
|
-
purge: async () => confirmInGroup({
|
|
875
|
-
message: t("cli.uninstall.wizard.purge", {
|
|
876
|
-
defaultValue: formatPromptDefault(context.options.purge === true)
|
|
877
|
-
}),
|
|
878
|
-
initialValue: context.options.purge === true
|
|
879
|
-
}),
|
|
880
|
-
cleanEmpties: async () => confirmInGroup({
|
|
881
|
-
message: t("cli.uninstall.wizard.clean-empties", {
|
|
882
|
-
defaultValue: formatPromptDefault(context.options.cleanEmpties === true)
|
|
883
|
-
}),
|
|
884
|
-
initialValue: context.options.cleanEmpties === true
|
|
885
800
|
})
|
|
886
801
|
},
|
|
887
802
|
{
|
|
@@ -901,9 +816,7 @@ function createDefaultUninstallWizardAdapter() {
|
|
|
901
816
|
...context.options,
|
|
902
817
|
skipScaffold: !groupedSelection.scaffold,
|
|
903
818
|
skipBootstrap: !groupedSelection.bootstrap,
|
|
904
|
-
skipMcp: !groupedSelection.mcp
|
|
905
|
-
purge: groupedSelection.purge,
|
|
906
|
-
cleanEmpties: groupedSelection.cleanEmpties
|
|
819
|
+
skipMcp: !groupedSelection.mcp
|
|
907
820
|
};
|
|
908
821
|
log.step(t("cli.uninstall.wizard.step.review"));
|
|
909
822
|
printUninstallPlanSummary(context.target, previewOptions, context.supports);
|
|
@@ -930,13 +843,6 @@ async function confirmInGroup(options) {
|
|
|
930
843
|
}
|
|
931
844
|
return result;
|
|
932
845
|
}
|
|
933
|
-
function collectLockedWizardStages(args) {
|
|
934
|
-
const locked = [];
|
|
935
|
-
if (args.scaffold === false) locked.push("scaffold");
|
|
936
|
-
if (args.bootstrap === false) locked.push("bootstrap");
|
|
937
|
-
if (args.mcp === false) locked.push("mcp");
|
|
938
|
-
return locked;
|
|
939
|
-
}
|
|
940
846
|
async function confirmDestructive(plan) {
|
|
941
847
|
printUninstallPlanSummary(plan.target, plan.options, plan.supports);
|
|
942
848
|
const answer = await confirm({
|
|
@@ -955,9 +861,7 @@ function printUninstallPlanPreview(plan) {
|
|
|
955
861
|
t("cli.uninstall.plan.preview-result", {
|
|
956
862
|
scaffold: yesNoLabel(!plan.options.skipScaffold),
|
|
957
863
|
bootstrap: yesNoLabel(!plan.options.skipBootstrap),
|
|
958
|
-
mcp: yesNoLabel(!plan.options.skipMcp)
|
|
959
|
-
purge: yesNoLabel(plan.options.purge === true),
|
|
960
|
-
cleanEmpties: yesNoLabel(plan.options.cleanEmpties === true)
|
|
864
|
+
mcp: yesNoLabel(!plan.options.skipMcp)
|
|
961
865
|
})
|
|
962
866
|
);
|
|
963
867
|
if (!plan.options.skipScaffold && plan.scaffold.entries.length > 0) {
|
|
@@ -975,9 +879,7 @@ function printUninstallPlanSummary(target, options, supports) {
|
|
|
975
879
|
t("cli.uninstall.plan.actions", {
|
|
976
880
|
scaffold: yesNoLabel(!options.skipScaffold),
|
|
977
881
|
bootstrap: yesNoLabel(!options.skipBootstrap),
|
|
978
|
-
mcp: yesNoLabel(!options.skipMcp)
|
|
979
|
-
purge: yesNoLabel(options.purge === true),
|
|
980
|
-
cleanEmpties: yesNoLabel(options.cleanEmpties === true)
|
|
882
|
+
mcp: yesNoLabel(!options.skipMcp)
|
|
981
883
|
})
|
|
982
884
|
);
|
|
983
885
|
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.15",
|
|
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-server": "2.0.0-rc.
|
|
24
|
-
"@fenglimg/fabric-shared": "2.0.0-rc.
|
|
23
|
+
"@fenglimg/fabric-server": "2.0.0-rc.15",
|
|
24
|
+
"@fenglimg/fabric-shared": "2.0.0-rc.15"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/node": "^22.15.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Client hook config templates
|
|
2
2
|
|
|
3
|
-
These JSON files are **fragment templates** consumed by `fabric
|
|
3
|
+
These JSON files are **fragment templates** consumed by `fabric install` and
|
|
4
4
|
`fabric hooks install`. They are not standalone client config files.
|
|
5
5
|
|
|
6
6
|
The supported clients are pinned by `packages/shared/src/schemas/fabric-config.ts`
|
|
@@ -27,11 +27,15 @@ config (`~/.codex/config.toml`) is TOML.
|
|
|
27
27
|
|
|
28
28
|
## cursor-hooks.json
|
|
29
29
|
|
|
30
|
-
Written to (or merged into) the user repo's `.cursor/hooks.json`.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
Written to (or merged into) the user repo's `.cursor/hooks.json`. Schema
|
|
31
|
+
authoritative source: https://cursor.com/cn/docs/hooks. Top-level requires
|
|
32
|
+
`version: 1` (number literal, NOT string) and a `hooks` object (NOT `events`)
|
|
33
|
+
keyed by camelCase event names: `stop`, `sessionStart`, `preToolUse`. Per-entry
|
|
34
|
+
shape stays flat (Codex-style): `{command, matcher?, type?, timeout?,
|
|
35
|
+
loop_limit?, failClosed?}`. rc.14 TASK-001 corrected rc.13's wrong top-level
|
|
36
|
+
envelope (was `{events: {Stop, SessionStart, PreToolUse}}` PascalCase, which
|
|
37
|
+
Cursor rejects with "Config version must be a number; Config hooks must be an
|
|
38
|
+
object").
|
|
35
39
|
|
|
36
40
|
## fabric-hint.cjs script paths
|
|
37
41
|
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
2
|
+
"version": 1,
|
|
3
|
+
"hooks": {
|
|
4
|
+
"stop": [
|
|
5
|
+
{ "command": ".cursor/hooks/fabric-hint.cjs" }
|
|
7
6
|
],
|
|
8
|
-
"
|
|
9
|
-
{
|
|
10
|
-
"command": ".cursor/hooks/knowledge-hint-broad.cjs"
|
|
11
|
-
}
|
|
7
|
+
"sessionStart": [
|
|
8
|
+
{ "command": ".cursor/hooks/knowledge-hint-broad.cjs" }
|
|
12
9
|
],
|
|
13
|
-
"
|
|
10
|
+
"preToolUse": [
|
|
14
11
|
{
|
|
15
12
|
"matcher": "Edit|Write|MultiEdit",
|
|
16
13
|
"command": ".cursor/hooks/knowledge-hint-narrow.cjs"
|