@fenglimg/fabric-cli 2.0.0-rc.15 → 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/dist/chunk-4HC5ZK7H.js +598 -0
- package/dist/{chunk-AXIFEVAS.js → chunk-FNO7CQDG.js} +1 -1
- package/dist/chunk-KZ2YITOS.js +225 -0
- package/dist/{chunk-SKSYUHKK.js → chunk-MF3OTILQ.js} +0 -4
- package/dist/{chunk-OBQU6NHO.js → chunk-ZSESMG6L.js} +0 -6
- package/dist/{config-7YD365I3.js → config-AYP5F72E.js} +2 -2
- package/dist/{doctor-6XHLQJXB.js → doctor-L6TIXXIX.js} +129 -3
- package/dist/index.js +11 -8
- package/dist/{install-JLDCHAXV.js → install-DNZXGFHJ.js} +23 -25
- package/dist/{plan-context-hint-73U4FGKO.js → plan-context-hint-CFDGXHCA.js} +4 -4
- package/dist/{serve-L3X5UHG2.js → serve-6PPQX7AW.js} +1 -1
- package/dist/{uninstall-DD6FIFCI.js → uninstall-L2HEEOU3.js} +147 -55
- package/package.json +3 -3
- 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-AIB54QRT.js +0 -82
- package/dist/chunk-UTF4YBDN.js +0 -366
- 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,17 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
FABRIC_HOOK_COMMAND_PATHS,
|
|
4
|
-
FABRIC_SECTION_REGEX,
|
|
5
4
|
HOOK_CONFIG_ARRAY_PATHS,
|
|
6
5
|
HOOK_CONFIG_TARGETS,
|
|
6
|
+
HOOK_LIB_DESTINATIONS,
|
|
7
7
|
HOOK_SCRIPT_DESTINATIONS,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
} from "./chunk-
|
|
8
|
+
SKILL_DESTINATIONS,
|
|
9
|
+
fabricAgentsSnapshotPath
|
|
10
|
+
} from "./chunk-4HC5ZK7H.js";
|
|
11
11
|
import {
|
|
12
12
|
detectClientSupports,
|
|
13
13
|
resolveClients
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-MF3OTILQ.js";
|
|
15
15
|
import {
|
|
16
16
|
hasActionHint,
|
|
17
17
|
paint,
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
import {
|
|
24
24
|
createDebugLogger,
|
|
25
25
|
resolveDevMode
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-ZSESMG6L.js";
|
|
27
27
|
|
|
28
28
|
// src/commands/uninstall.ts
|
|
29
29
|
import { existsSync as existsSync2, statSync } from "fs";
|
|
@@ -39,6 +39,7 @@ import { existsSync } from "fs";
|
|
|
39
39
|
import { readdir, readFile, rm, rmdir } from "fs/promises";
|
|
40
40
|
import { dirname, join } from "path";
|
|
41
41
|
import { atomicWriteJson, atomicWriteText } from "@fenglimg/fabric-shared/node/atomic-write";
|
|
42
|
+
import { BOOTSTRAP_REGEX } from "@fenglimg/fabric-shared/templates/bootstrap-canonical";
|
|
42
43
|
async function uninstallFabricArchiveSkill(projectRoot) {
|
|
43
44
|
return removeSkill("skill", SKILL_DESTINATIONS.fabricArchive, projectRoot);
|
|
44
45
|
}
|
|
@@ -82,6 +83,34 @@ async function removeHookScripts(step, rels, projectRoot) {
|
|
|
82
83
|
}
|
|
83
84
|
return results;
|
|
84
85
|
}
|
|
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
|
+
}
|
|
85
114
|
async function unmergeClaudeCodeHookConfig(projectRoot) {
|
|
86
115
|
return unmergeHookConfig({
|
|
87
116
|
step: "claude-hook-config",
|
|
@@ -112,69 +141,131 @@ async function unmergeCursorHookConfig(projectRoot) {
|
|
|
112
141
|
extractCommands: extractFlatCommands
|
|
113
142
|
});
|
|
114
143
|
}
|
|
115
|
-
async function
|
|
144
|
+
async function stripFabricBootstrapBlocks(projectRoot) {
|
|
116
145
|
const results = [];
|
|
117
|
-
|
|
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
|
-
|
|
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)) {
|
|
157
222
|
try {
|
|
158
|
-
await
|
|
159
|
-
|
|
223
|
+
await rm(target, { force: true });
|
|
224
|
+
return { step, path: target, status: "removed", message: "front-matter-only" };
|
|
160
225
|
} catch (error) {
|
|
161
|
-
|
|
162
|
-
step
|
|
226
|
+
return {
|
|
227
|
+
step,
|
|
163
228
|
path: target,
|
|
164
229
|
status: "error",
|
|
165
230
|
message: error instanceof Error ? error.message : String(error)
|
|
166
|
-
}
|
|
231
|
+
};
|
|
167
232
|
}
|
|
168
233
|
}
|
|
169
|
-
|
|
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;
|
|
251
|
+
}
|
|
252
|
+
async function deleteFabricAgentsSnapshot(projectRoot) {
|
|
253
|
+
const target = fabricAgentsSnapshotPath(projectRoot);
|
|
254
|
+
return rmIfExists("bootstrap-snapshot", target);
|
|
170
255
|
}
|
|
171
256
|
async function uninstallBootstrapStage(projectRoot, _opts = {}) {
|
|
172
257
|
const results = [];
|
|
173
258
|
await runAndCollect(
|
|
174
259
|
results,
|
|
175
|
-
"
|
|
260
|
+
"bootstrap-blocks",
|
|
261
|
+
projectRoot,
|
|
262
|
+
() => stripFabricBootstrapBlocks(projectRoot)
|
|
263
|
+
);
|
|
264
|
+
await runAndCollectOne(
|
|
265
|
+
results,
|
|
266
|
+
"bootstrap-snapshot",
|
|
176
267
|
projectRoot,
|
|
177
|
-
() =>
|
|
268
|
+
() => deleteFabricAgentsSnapshot(projectRoot)
|
|
178
269
|
);
|
|
179
270
|
await runAndCollectOne(
|
|
180
271
|
results,
|
|
@@ -194,6 +285,7 @@ async function uninstallBootstrapStage(projectRoot, _opts = {}) {
|
|
|
194
285
|
projectRoot,
|
|
195
286
|
() => unmergeClaudeCodeHookConfig(projectRoot)
|
|
196
287
|
);
|
|
288
|
+
await runAndCollect(results, "hook-lib", projectRoot, () => removeHookLibs(projectRoot));
|
|
197
289
|
await runAndCollect(
|
|
198
290
|
results,
|
|
199
291
|
"hook-narrow-script",
|
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-server": "2.0.0-rc.
|
|
24
|
-
"@fenglimg/fabric-shared": "2.0.0-rc.
|
|
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",
|