@fenglimg/fabric-cli 1.6.0 → 1.7.0

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.
Files changed (42) hide show
  1. package/README.md +8 -14
  2. package/dist/{chunk-QSAEGVKE.js → chunk-NMMUETVK.js} +4 -8
  3. package/dist/{chunk-AEOYCVBG.js → chunk-QPCRBQ5Y.js} +52 -5
  4. package/dist/doctor-XP4OQOTX.js +92 -0
  5. package/dist/index.js +5 -20
  6. package/dist/{init-LBVOI2QI.js → init-WMB3WLXM.js} +1089 -147
  7. package/dist/{scan-QH76LC7Z.js → scan-NNBNGIZG.js} +2 -4
  8. package/dist/{serve-4J2CQY25.js → serve-7AXYKBIT.js} +3 -7
  9. package/package.json +3 -3
  10. package/templates/agents-md/AGENTS.md.template +7 -7
  11. package/templates/agents-md/variants/cocos.md +7 -7
  12. package/templates/agents-md/variants/next.md +7 -7
  13. package/templates/agents-md/variants/vite.md +7 -7
  14. package/templates/bootstrap/CLAUDE.md +3 -1
  15. package/templates/bootstrap/GEMINI.md +3 -1
  16. package/templates/bootstrap/codex-AGENTS-header.md +3 -1
  17. package/templates/bootstrap/cursor-fabric-bootstrap.mdc +5 -6
  18. package/templates/bootstrap/roo-fabric.md +5 -6
  19. package/templates/bootstrap/windsurf-fabric.md +5 -6
  20. package/templates/claude-skills/agents-md-init/SKILL.md +1 -1
  21. package/templates/codex-skills/fabric-init/SKILL.md +1 -1
  22. package/templates/husky/pre-commit +9 -24
  23. package/dist/approve-YT4DEABS.js +0 -138
  24. package/dist/bootstrap-VGL3AR26.js +0 -16
  25. package/dist/chunk-2YW5CJ32.js +0 -147
  26. package/dist/chunk-6ICJICVU.js +0 -10
  27. package/dist/chunk-BEKSXO5N.js +0 -442
  28. package/dist/chunk-BVTMVW5M.js +0 -159
  29. package/dist/chunk-KOAEIH72.js +0 -270
  30. package/dist/chunk-L43IGJ6X.js +0 -106
  31. package/dist/chunk-T2WJF5I3.js +0 -254
  32. package/dist/chunk-WWNXR34K.js +0 -49
  33. package/dist/chunk-YDZJRLHL.js +0 -155
  34. package/dist/config-EC5L2QNI.js +0 -16
  35. package/dist/doctor-4BPYHV7V.js +0 -134
  36. package/dist/hooks-ZSWVH2JD.js +0 -12
  37. package/dist/human-lint-YSFOZHZ7.js +0 -13
  38. package/dist/ledger-append-3MDNR3GU.js +0 -10
  39. package/dist/pre-commit-53ENJDRZ.js +0 -98
  40. package/dist/sync-meta-IZR2WLIL.js +0 -16
  41. package/dist/update-M5M5PYKE.js +0 -116
  42. package/templates/fabric/human-lock.json +0 -12
@@ -1,47 +1,988 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- buildFabricBootstrapGuide,
4
- installBootstrap
5
- } from "./chunk-T2WJF5I3.js";
6
- import {
3
+ createScanReport,
7
4
  detectFramework
8
- } from "./chunk-QSAEGVKE.js";
5
+ } from "./chunk-NMMUETVK.js";
9
6
  import {
10
7
  createDebugLogger,
11
- resolveDevMode
12
- } from "./chunk-AEOYCVBG.js";
13
- import {
14
8
  displayWidth,
15
9
  padEnd,
16
- paint
17
- } from "./chunk-WWNXR34K.js";
18
- import {
19
- installMcpClients
20
- } from "./chunk-BVTMVW5M.js";
21
- import {
22
- detectClientSupports
23
- } from "./chunk-BEKSXO5N.js";
24
- import {
25
- installHooks
26
- } from "./chunk-YDZJRLHL.js";
27
- import {
10
+ paint,
11
+ readFabricConfig,
12
+ resolveDevMode,
28
13
  t
29
- } from "./chunk-6ICJICVU.js";
14
+ } from "./chunk-QPCRBQ5Y.js";
30
15
 
31
16
  // src/commands/init.ts
32
17
  import { createHash } from "crypto";
33
18
  import * as childProcess from "child_process";
34
- import { chmodSync, copyFileSync, existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, renameSync, rmSync, statSync as statSync2, writeFileSync } from "fs";
35
- import { dirname, isAbsolute as isAbsolute2, join as join2, parse, resolve as resolve2 } from "path";
36
- import { fileURLToPath } from "url";
19
+ import { chmodSync as chmodSync2, copyFileSync, existsSync as existsSync9, mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync, rmSync, statSync as statSync3, writeFileSync as writeFileSync3 } from "fs";
20
+ import { dirname as dirname5, isAbsolute as isAbsolute4, join as join8, parse as parse3, resolve as resolve9 } from "path";
21
+ import { fileURLToPath as fileURLToPath4 } from "url";
37
22
  import { cancel, confirm, group, intro, isCancel, log, note, outro, select } from "@clack/prompts";
23
+ import { defineCommand as defineCommand4 } from "citty";
24
+
25
+ // src/bootstrap-guide.ts
26
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
27
+ import { dirname, isAbsolute, join, parse, resolve } from "path";
28
+ import { fileURLToPath } from "url";
29
+ var AGENTS_TEMPLATE_BY_FRAMEWORK = {
30
+ "cocos-creator": "templates/agents-md/variants/cocos.md",
31
+ vite: "templates/agents-md/variants/vite.md",
32
+ next: "templates/agents-md/variants/next.md"
33
+ };
34
+ var FABRIC_GUIDE_PATH = ".fabric/bootstrap/README.md";
35
+ async function buildFabricBootstrapGuide(target) {
36
+ const workspaceRoot = normalizeTarget(target);
37
+ const scanReport = await createScanReport(workspaceRoot);
38
+ const template = readFileSync(findBootstrapTemplatePath(scanReport.framework.kind), "utf8");
39
+ const packageName = readPackageName(workspaceRoot) ?? parse(workspaceRoot).base;
40
+ return ensureTrailingNewline(
41
+ template.replaceAll("{ projectName }", packageName).replaceAll("{ frameworkKind }", scanReport.framework.kind)
42
+ );
43
+ }
44
+ async function ensureFabricBootstrapGuide(workspaceRoot, force) {
45
+ const guidePath = resolve(workspaceRoot, FABRIC_GUIDE_PATH);
46
+ if (existsSync(guidePath) && !force) {
47
+ return;
48
+ }
49
+ mkdirSync(dirname(guidePath), { recursive: true });
50
+ writeFileSync(guidePath, await buildFabricBootstrapGuide(workspaceRoot), "utf8");
51
+ }
52
+ function findBootstrapTemplatePath(frameworkKind) {
53
+ const relativePath = AGENTS_TEMPLATE_BY_FRAMEWORK[frameworkKind] ?? "templates/agents-md/AGENTS.md.template";
54
+ return findTemplatePath(relativePath);
55
+ }
56
+ function readPackageName(target) {
57
+ const packageJsonPath = join(target, "package.json");
58
+ if (!existsSync(packageJsonPath)) {
59
+ return void 0;
60
+ }
61
+ try {
62
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
63
+ return packageJson.name;
64
+ } catch {
65
+ return void 0;
66
+ }
67
+ }
68
+ function findTemplatePath(relativePath) {
69
+ const currentModuleDir = dirname(fileURLToPath(import.meta.url));
70
+ const candidates = [
71
+ ...templateCandidatesFrom(process.cwd(), relativePath),
72
+ ...templateCandidatesFrom(currentModuleDir, relativePath)
73
+ ];
74
+ for (const candidate of candidates) {
75
+ if (existsSync(candidate)) {
76
+ return candidate;
77
+ }
78
+ }
79
+ throw new Error(t("cli.shared.template-not-found", { path: relativePath }));
80
+ }
81
+ function templateCandidatesFrom(start, relativePath) {
82
+ const candidates = [];
83
+ let current = resolve(start);
84
+ while (true) {
85
+ candidates.push(join(current, ...relativePath.split("/")));
86
+ const parent = dirname(current);
87
+ if (parent === current || parse(current).root === current) {
88
+ break;
89
+ }
90
+ current = parent;
91
+ }
92
+ return candidates.reverse();
93
+ }
94
+ function ensureTrailingNewline(content) {
95
+ return content.endsWith("\n") ? content : `${content}
96
+ `;
97
+ }
98
+ function normalizeTarget(targetInput) {
99
+ return isAbsolute(targetInput) ? targetInput : resolve(process.cwd(), targetInput);
100
+ }
101
+
102
+ // src/commands/bootstrap.ts
103
+ import { resolve as resolve5 } from "path";
38
104
  import { defineCommand } from "citty";
39
105
 
106
+ // src/config/resolver.ts
107
+ import { existsSync as existsSync5 } from "fs";
108
+ import { join as join5 } from "path";
109
+ import { homedir as homedir4 } from "os";
110
+
111
+ // src/config/claude-code.ts
112
+ import { existsSync as existsSync3 } from "fs";
113
+ import { join as join3, resolve as resolve3 } from "path";
114
+ import { homedir as homedir2, platform } from "os";
115
+
116
+ // src/config/json.ts
117
+ import { existsSync as existsSync2 } from "fs";
118
+ import { mkdir, readFile, writeFile } from "fs/promises";
119
+ import { dirname as dirname2, join as join2, resolve as resolve2 } from "path";
120
+ import { homedir } from "os";
121
+
122
+ // src/config/writer.ts
123
+ function createServerEntry(serverPath) {
124
+ return {
125
+ command: process.execPath,
126
+ args: [serverPath]
127
+ };
128
+ }
129
+
130
+ // src/config/json.ts
131
+ function expandHome(filePath) {
132
+ if (filePath === "~") {
133
+ return homedir();
134
+ }
135
+ if (filePath.startsWith("~/")) {
136
+ return join2(homedir(), filePath.slice(2));
137
+ }
138
+ return filePath;
139
+ }
140
+ function normalizeConfigPath(filePath) {
141
+ return resolve2(expandHome(filePath));
142
+ }
143
+ async function readJsonConfig(configPath) {
144
+ try {
145
+ const raw = await readFile(configPath, "utf8");
146
+ if (raw.trim().length === 0) {
147
+ return {};
148
+ }
149
+ const parsed = JSON.parse(raw);
150
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
151
+ throw new Error(`Expected JSON object in ${configPath}`);
152
+ }
153
+ return parsed;
154
+ } catch (error) {
155
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
156
+ return {};
157
+ }
158
+ throw error;
159
+ }
160
+ }
161
+ async function writeJsonClientConfig(configPath, serverEntry) {
162
+ const config = await readJsonConfig(configPath);
163
+ const existingServers = config.mcpServers;
164
+ config.mcpServers = existingServers !== null && typeof existingServers === "object" && !Array.isArray(existingServers) ? { ...existingServers, fabric: serverEntry } : { fabric: serverEntry };
165
+ await mkdir(dirname2(configPath), { recursive: true });
166
+ await writeFile(configPath, `${JSON.stringify(config, null, 2)}
167
+ `, "utf8");
168
+ }
169
+ var JsonClientConfigWriter = class {
170
+ configuredPath;
171
+ constructor(configuredPath) {
172
+ this.configuredPath = configuredPath;
173
+ }
174
+ async detect(workspaceRoot, overridePath) {
175
+ const explicitPath = overridePath ?? this.configuredPath;
176
+ if (explicitPath !== void 0) {
177
+ return normalizeConfigPath(explicitPath);
178
+ }
179
+ const configPath = this.defaultPath(workspaceRoot);
180
+ return configPath === null ? null : normalizeConfigPath(configPath);
181
+ }
182
+ async write(serverPath, workspaceRoot, overridePath) {
183
+ const configPath = await this.detect(workspaceRoot, overridePath);
184
+ if (configPath === null) {
185
+ return;
186
+ }
187
+ await writeJsonClientConfig(configPath, createServerEntry(serverPath));
188
+ }
189
+ };
190
+ var ClaudeCodeCLIWriter = class extends JsonClientConfigWriter {
191
+ clientKind = "ClaudeCodeCLI";
192
+ constructor(configuredPath) {
193
+ super(configuredPath);
194
+ }
195
+ // Writes to project-level .claude/settings.json so MCP is scoped to the project.
196
+ // Detection in resolver still checks ~/ to confirm Claude Code is installed.
197
+ defaultPath(workspaceRoot) {
198
+ const globalClaudeDir = join2(homedir(), ".claude");
199
+ const projectClaudeDir = join2(workspaceRoot, ".claude");
200
+ if (!existsSync2(globalClaudeDir) && !existsSync2(projectClaudeDir)) {
201
+ return null;
202
+ }
203
+ return join2(projectClaudeDir, "settings.json");
204
+ }
205
+ };
206
+ var CursorWriter = class extends JsonClientConfigWriter {
207
+ clientKind = "Cursor";
208
+ constructor(configuredPath) {
209
+ super(configuredPath);
210
+ }
211
+ defaultPath(workspaceRoot) {
212
+ const cursorDir = join2(workspaceRoot, ".cursor");
213
+ return existsSync2(cursorDir) ? join2(cursorDir, "mcp.json") : null;
214
+ }
215
+ };
216
+ var WindsurfWriter = class extends JsonClientConfigWriter {
217
+ clientKind = "Windsurf";
218
+ constructor(configuredPath) {
219
+ super(configuredPath);
220
+ }
221
+ defaultPath(workspaceRoot) {
222
+ const windsurfDir = join2(workspaceRoot, ".windsurf");
223
+ return existsSync2(windsurfDir) ? join2(windsurfDir, "mcp.json") : null;
224
+ }
225
+ };
226
+ var RooCodeWriter = class extends JsonClientConfigWriter {
227
+ clientKind = "RooCode";
228
+ constructor(configuredPath) {
229
+ super(configuredPath);
230
+ }
231
+ defaultPath(workspaceRoot) {
232
+ const rooDir = join2(workspaceRoot, ".roo");
233
+ return existsSync2(rooDir) ? join2(rooDir, "mcp.json") : null;
234
+ }
235
+ };
236
+ var GeminiCLIWriter = class extends JsonClientConfigWriter {
237
+ clientKind = "GeminiCLI";
238
+ constructor(configuredPath) {
239
+ super(configuredPath);
240
+ }
241
+ defaultPath(workspaceRoot) {
242
+ const geminiDir = join2(homedir(), ".gemini");
243
+ return existsSync2(geminiDir) || existsSync2(join2(workspaceRoot, "GEMINI.md")) ? join2(geminiDir, "settings.json") : null;
244
+ }
245
+ };
246
+
247
+ // src/config/claude-code.ts
248
+ function getClaudeDesktopConfigPath() {
249
+ const os = platform();
250
+ if (os === "darwin") {
251
+ return join3(homedir2(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
252
+ }
253
+ if (os === "win32") {
254
+ return join3(process.env.APPDATA ?? join3(homedir2(), "AppData", "Roaming"), "Claude", "claude_desktop_config.json");
255
+ }
256
+ return join3(homedir2(), ".config", "Claude", "claude_desktop_config.json");
257
+ }
258
+ var ClaudeCodeDesktopWriter = class {
259
+ clientKind = "ClaudeCodeDesktop";
260
+ configuredPath;
261
+ constructor(configuredPath) {
262
+ this.configuredPath = configuredPath;
263
+ }
264
+ async detect(_workspaceRoot, overridePath) {
265
+ const configPath = normalizeConfigPath(overridePath ?? this.configuredPath ?? getClaudeDesktopConfigPath());
266
+ return existsSync3(configPath) || overridePath !== void 0 || this.configuredPath !== void 0 ? configPath : null;
267
+ }
268
+ async write(serverPath, workspaceRoot, overridePath) {
269
+ const configPath = await this.detect(workspaceRoot, overridePath);
270
+ if (configPath === null) {
271
+ return;
272
+ }
273
+ await writeJsonClientConfig(configPath, {
274
+ command: process.execPath,
275
+ args: [serverPath]
276
+ });
277
+ }
278
+ };
279
+
280
+ // src/config/toml.ts
281
+ import { existsSync as existsSync4 } from "fs";
282
+ import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
283
+ import { dirname as dirname3, join as join4, resolve as resolve4 } from "path";
284
+ import { homedir as homedir3 } from "os";
285
+ function expandHome2(filePath) {
286
+ if (filePath === "~") {
287
+ return homedir3();
288
+ }
289
+ if (filePath.startsWith("~/")) {
290
+ return join4(homedir3(), filePath.slice(2));
291
+ }
292
+ return filePath;
293
+ }
294
+ function escapeTomlString(value) {
295
+ return JSON.stringify(value);
296
+ }
297
+ function serializeTomlStringArray(values) {
298
+ return `[${values.map((value) => escapeTomlString(value)).join(", ")}]`;
299
+ }
300
+ function serializeTomlInlineTable(values) {
301
+ const entries = Object.entries(values).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => `${key} = ${escapeTomlString(value)}`);
302
+ return `{ ${entries.join(", ")} }`;
303
+ }
304
+ function serializeCodexServerBlock(serverName, serverEntry) {
305
+ const lines = [
306
+ `[mcp_servers.${serverName}]`,
307
+ `command = ${escapeTomlString(serverEntry.command)}`,
308
+ `args = ${serializeTomlStringArray(serverEntry.args)}`
309
+ ];
310
+ if (serverEntry.env !== void 0 && Object.keys(serverEntry.env).length > 0) {
311
+ lines.push(`env = ${serializeTomlInlineTable(serverEntry.env)}`);
312
+ }
313
+ return `${lines.join("\n")}
314
+ `;
315
+ }
316
+ function trimTrailingBlankLines(value) {
317
+ return value.replace(/\s+$/u, "");
318
+ }
319
+ function upsertCodexServerBlock(rawConfig, serverName, serverEntry) {
320
+ const block = serializeCodexServerBlock(serverName, serverEntry);
321
+ const normalized = rawConfig.replace(/\r\n/g, "\n");
322
+ const legacyPattern = new RegExp(String.raw`\n?\[mcp\.servers\.${serverName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\]\n[\s\S]*?(?=\n\[[^\n]+\]\n|$)`, "g");
323
+ const currentPattern = new RegExp(
324
+ String.raw`\n?\[mcp_servers\.${serverName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\]\n[\s\S]*?(?=\n\[[^\n]+\]\n|$)`,
325
+ "g"
326
+ );
327
+ const withoutLegacy = normalized.replace(legacyPattern, "");
328
+ const withoutExisting = withoutLegacy.replace(currentPattern, "");
329
+ const trimmed = trimTrailingBlankLines(withoutExisting);
330
+ if (trimmed.length === 0) {
331
+ return block;
332
+ }
333
+ return `${trimmed}
334
+
335
+ ${block}`;
336
+ }
337
+ async function readTomlConfigText(configPath) {
338
+ try {
339
+ return await readFile2(configPath, "utf8");
340
+ } catch (error) {
341
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
342
+ return "";
343
+ }
344
+ throw error;
345
+ }
346
+ }
347
+ var CodexTOMLConfigWriter = class {
348
+ clientKind = "CodexCLI";
349
+ configuredPath;
350
+ constructor(configuredPath) {
351
+ this.configuredPath = configuredPath;
352
+ }
353
+ async detect(_workspaceRoot, overridePath) {
354
+ const explicitPath = overridePath ?? this.configuredPath;
355
+ if (explicitPath !== void 0) {
356
+ return resolve4(expandHome2(explicitPath));
357
+ }
358
+ const codexDir = join4(homedir3(), ".codex");
359
+ return existsSync4(codexDir) ? resolve4(join4(codexDir, "config.toml")) : null;
360
+ }
361
+ async write(serverPath, workspaceRoot, overridePath) {
362
+ const configPath = await this.detect(workspaceRoot, overridePath);
363
+ if (configPath === null) {
364
+ return;
365
+ }
366
+ const rawConfig = await readTomlConfigText(configPath);
367
+ const nextConfig = upsertCodexServerBlock(rawConfig, "fabric", createServerEntry(serverPath));
368
+ await mkdir2(dirname3(configPath), { recursive: true });
369
+ await writeFile2(configPath, nextConfig, "utf8");
370
+ }
371
+ };
372
+
373
+ // src/config/resolver.ts
374
+ import { clientPathsSchema, fabricConfigSchema } from "@fenglimg/fabric-shared";
375
+ function hasExplicitPath(clientPaths, key) {
376
+ return typeof clientPaths?.[key] === "string" && clientPaths[key].trim().length > 0;
377
+ }
378
+ function addIfDetected(writers, detected, createWriter, configuredPath) {
379
+ if (configuredPath !== void 0 || detected) {
380
+ writers.push(createWriter(configuredPath));
381
+ }
382
+ }
383
+ function resolveClients(workspaceRoot, fabricConfig = {}) {
384
+ const clientPaths = fabricConfig.clientPaths;
385
+ const writers = [];
386
+ addIfDetected(
387
+ writers,
388
+ existsSync5(join5(homedir4(), ".claude")) || existsSync5(join5(workspaceRoot, ".claude")),
389
+ (configuredPath) => new ClaudeCodeCLIWriter(configuredPath),
390
+ hasExplicitPath(clientPaths, "claudeCodeCLI") ? clientPaths.claudeCodeCLI : void 0
391
+ );
392
+ addIfDetected(
393
+ writers,
394
+ existsSync5(getClaudeDesktopConfigPath()),
395
+ (configuredPath) => new ClaudeCodeDesktopWriter(configuredPath),
396
+ hasExplicitPath(clientPaths, "claudeCodeDesktop") ? clientPaths.claudeCodeDesktop : void 0
397
+ );
398
+ addIfDetected(
399
+ writers,
400
+ existsSync5(join5(workspaceRoot, ".cursor")),
401
+ (configuredPath) => new CursorWriter(configuredPath),
402
+ hasExplicitPath(clientPaths, "cursor") ? clientPaths.cursor : void 0
403
+ );
404
+ addIfDetected(
405
+ writers,
406
+ existsSync5(join5(workspaceRoot, ".windsurf")),
407
+ (configuredPath) => new WindsurfWriter(configuredPath),
408
+ hasExplicitPath(clientPaths, "windsurf") ? clientPaths.windsurf : void 0
409
+ );
410
+ addIfDetected(
411
+ writers,
412
+ existsSync5(join5(workspaceRoot, ".roo")),
413
+ (configuredPath) => new RooCodeWriter(configuredPath),
414
+ hasExplicitPath(clientPaths, "rooCode") ? clientPaths.rooCode : void 0
415
+ );
416
+ addIfDetected(
417
+ writers,
418
+ existsSync5(join5(homedir4(), ".gemini")) || existsSync5(join5(workspaceRoot, "GEMINI.md")),
419
+ (configuredPath) => new GeminiCLIWriter(configuredPath),
420
+ hasExplicitPath(clientPaths, "geminiCLI") ? clientPaths.geminiCLI : void 0
421
+ );
422
+ addIfDetected(
423
+ writers,
424
+ existsSync5(join5(homedir4(), ".codex")),
425
+ (configuredPath) => new CodexTOMLConfigWriter(configuredPath),
426
+ hasExplicitPath(clientPaths, "codexCLI") ? clientPaths.codexCLI : void 0
427
+ );
428
+ return writers;
429
+ }
430
+ function detectClientSupports(workspaceRoot, fabricConfig = {}) {
431
+ const clientPaths = fabricConfig.clientPaths;
432
+ const claudeDetected = existsSync5(join5(homedir4(), ".claude")) || existsSync5(join5(workspaceRoot, ".claude"));
433
+ const claudeDesktopDetected = existsSync5(getClaudeDesktopConfigPath());
434
+ const cursorDetected = existsSync5(join5(workspaceRoot, ".cursor"));
435
+ const windsurfDetected = existsSync5(join5(workspaceRoot, ".windsurf"));
436
+ const rooDetected = existsSync5(join5(workspaceRoot, ".roo"));
437
+ const geminiDetected = existsSync5(join5(homedir4(), ".gemini")) || existsSync5(join5(workspaceRoot, "GEMINI.md"));
438
+ const codexDetected = existsSync5(join5(homedir4(), ".codex"));
439
+ return [
440
+ {
441
+ clientKind: "ClaudeCodeCLI",
442
+ label: "Claude Code CLI",
443
+ detected: claudeDetected || hasExplicitPath(clientPaths, "claudeCodeCLI"),
444
+ bootstrapTargetPath: ".fabric/bootstrap/README.md",
445
+ configPath: "project .claude/settings.json",
446
+ capabilities: {
447
+ bootstrap: true,
448
+ mcp: true,
449
+ hook: true,
450
+ skill: true
451
+ },
452
+ installedCapabilities: {
453
+ hook: true,
454
+ skill: true
455
+ }
456
+ },
457
+ {
458
+ clientKind: "ClaudeCodeDesktop",
459
+ label: "Claude Code Desktop",
460
+ detected: claudeDesktopDetected || hasExplicitPath(clientPaths, "claudeCodeDesktop"),
461
+ bootstrapTargetPath: ".fabric/bootstrap/README.md",
462
+ configPath: "desktop Claude config",
463
+ capabilities: {
464
+ bootstrap: true,
465
+ mcp: true,
466
+ hook: false,
467
+ skill: false
468
+ }
469
+ },
470
+ {
471
+ clientKind: "Cursor",
472
+ label: "Cursor",
473
+ detected: cursorDetected || hasExplicitPath(clientPaths, "cursor"),
474
+ bootstrapTargetPath: ".fabric/bootstrap/README.md",
475
+ configPath: ".cursor/mcp.json",
476
+ capabilities: {
477
+ bootstrap: true,
478
+ mcp: true,
479
+ hook: false,
480
+ skill: false
481
+ }
482
+ },
483
+ {
484
+ clientKind: "Windsurf",
485
+ label: "Windsurf",
486
+ detected: windsurfDetected || hasExplicitPath(clientPaths, "windsurf"),
487
+ bootstrapTargetPath: ".fabric/bootstrap/README.md",
488
+ configPath: ".windsurf/mcp.json",
489
+ capabilities: {
490
+ bootstrap: true,
491
+ mcp: true,
492
+ hook: false,
493
+ skill: false
494
+ }
495
+ },
496
+ {
497
+ clientKind: "RooCode",
498
+ label: "Roo Code",
499
+ detected: rooDetected || hasExplicitPath(clientPaths, "rooCode"),
500
+ bootstrapTargetPath: ".fabric/bootstrap/README.md",
501
+ configPath: ".roo/mcp.json",
502
+ capabilities: {
503
+ bootstrap: true,
504
+ mcp: true,
505
+ hook: false,
506
+ skill: false
507
+ }
508
+ },
509
+ {
510
+ clientKind: "GeminiCLI",
511
+ label: "Gemini CLI",
512
+ detected: geminiDetected || hasExplicitPath(clientPaths, "geminiCLI"),
513
+ bootstrapTargetPath: ".fabric/bootstrap/README.md",
514
+ configPath: "~/.gemini/settings.json",
515
+ capabilities: {
516
+ bootstrap: true,
517
+ mcp: true,
518
+ hook: false,
519
+ skill: false
520
+ }
521
+ },
522
+ {
523
+ clientKind: "CodexCLI",
524
+ label: "Codex CLI",
525
+ detected: codexDetected || hasExplicitPath(clientPaths, "codexCLI"),
526
+ bootstrapTargetPath: ".fabric/bootstrap/README.md",
527
+ configPath: "~/.codex/config.toml",
528
+ capabilities: {
529
+ bootstrap: true,
530
+ mcp: true,
531
+ hook: true,
532
+ skill: true
533
+ },
534
+ installedCapabilities: {
535
+ hook: existsSync5(join5(workspaceRoot, ".codex", "hooks.json")),
536
+ skill: existsSync5(join5(workspaceRoot, ".agents", "skills", "fabric-init", "SKILL.md"))
537
+ }
538
+ }
539
+ ];
540
+ }
541
+
542
+ // src/commands/bootstrap.ts
543
+ var CLIENT_ALIASES = {
544
+ claude: "claude",
545
+ "claude-code": "claude",
546
+ claudecode: "claude",
547
+ claudecli: "claude",
548
+ claudecodecli: "claude",
549
+ claudedesktop: "claude",
550
+ claudecodedesktop: "claude",
551
+ cursor: "cursor",
552
+ windsurf: "windsurf",
553
+ roo: "roo",
554
+ "roo-code": "roo",
555
+ roocode: "roo",
556
+ gemini: "gemini",
557
+ "gemini-cli": "gemini",
558
+ geminicli: "gemini",
559
+ codex: "codex",
560
+ "codex-cli": "codex",
561
+ codexcli: "codex"
562
+ };
563
+ var bootstrapCommand = defineCommand({
564
+ meta: {
565
+ name: "bootstrap",
566
+ description: t("cli.bootstrap.description")
567
+ },
568
+ subCommands: {
569
+ install: defineCommand({
570
+ meta: {
571
+ name: "install",
572
+ description: t("cli.bootstrap.install.description")
573
+ },
574
+ args: {
575
+ clients: {
576
+ type: "string",
577
+ description: t("cli.bootstrap.install.args.clients.description")
578
+ }
579
+ },
580
+ async run({ args }) {
581
+ const workspaceRoot = process.cwd();
582
+ const selectedClients = parseClientFilter(args.clients);
583
+ const result = await installBootstrap(workspaceRoot, {
584
+ clients: selectedClients === null ? void 0 : Array.from(selectedClients, mapBootstrapClientToClientKind)
585
+ });
586
+ if (result.details.length === 0) {
587
+ process.stderr.write(
588
+ `${t("cli.bootstrap.install.no-targets")}
589
+ `
590
+ );
591
+ return;
592
+ }
593
+ for (const detail of result.details) {
594
+ if (detail.action === "skipped") {
595
+ process.stderr.write(`${t("cli.bootstrap.install.skipped-header", { path: detail.path })}
596
+ `);
597
+ continue;
598
+ }
599
+ if (detail.action === "prepended") {
600
+ process.stderr.write(`${t("cli.bootstrap.install.prepended", { path: detail.path })}
601
+ `);
602
+ continue;
603
+ }
604
+ process.stderr.write(`${t("cli.bootstrap.install.installed", { path: detail.path })}
605
+ `);
606
+ }
607
+ }
608
+ })
609
+ }
610
+ });
611
+ async function installBootstrap(target, options = {}) {
612
+ const workspaceRoot = resolve5(target);
613
+ const fabricConfig = readFabricConfig(workspaceRoot);
614
+ const targets = resolveBootstrapTargets(workspaceRoot, fabricConfig, options.clients);
615
+ const installed = [];
616
+ const skipped = [];
617
+ const details = [];
618
+ await ensureFabricBootstrapGuide(workspaceRoot, options.force);
619
+ for (const bootstrapTarget of targets) {
620
+ details.push({
621
+ client: bootstrapTarget.client,
622
+ path: resolve5(workspaceRoot, FABRIC_GUIDE_PATH),
623
+ action: "skipped"
624
+ });
625
+ skipped.push(bootstrapTarget.client);
626
+ }
627
+ return { installed, skipped, details };
628
+ }
629
+ function parseClientFilter(value) {
630
+ if (value === void 0 || value.trim().length === 0) {
631
+ return null;
632
+ }
633
+ const clients = /* @__PURE__ */ new Set();
634
+ for (const rawClient of value.split(",")) {
635
+ const alias = rawClient.trim().toLowerCase();
636
+ const client = CLIENT_ALIASES[alias];
637
+ if (client === void 0) {
638
+ throw new Error(t("cli.bootstrap.errors.unknown-client", { client: rawClient }));
639
+ }
640
+ clients.add(client);
641
+ }
642
+ return clients;
643
+ }
644
+ function resolveBootstrapTargets(workspaceRoot, fabricConfig, selectedClients) {
645
+ const targets = [];
646
+ const seenClients = /* @__PURE__ */ new Set();
647
+ const clientKinds = selectedClients ?? resolveClients(workspaceRoot, fabricConfig).map((writer) => writer.clientKind);
648
+ for (const clientKind of clientKinds) {
649
+ const bootstrapClient = mapClientKind(clientKind);
650
+ if (bootstrapClient === null || seenClients.has(bootstrapClient)) {
651
+ continue;
652
+ }
653
+ seenClients.add(bootstrapClient);
654
+ targets.push({ client: clientKind, bootstrapClient });
655
+ }
656
+ return targets;
657
+ }
658
+ function mapClientKind(clientKind) {
659
+ switch (clientKind) {
660
+ case "ClaudeCodeCLI":
661
+ case "ClaudeCodeDesktop":
662
+ return "claude";
663
+ case "Cursor":
664
+ return "cursor";
665
+ case "Windsurf":
666
+ return "windsurf";
667
+ case "RooCode":
668
+ return "roo";
669
+ case "GeminiCLI":
670
+ return "gemini";
671
+ case "CodexCLI":
672
+ return "codex";
673
+ default:
674
+ return null;
675
+ }
676
+ }
677
+ function mapBootstrapClientToClientKind(client) {
678
+ switch (client) {
679
+ case "claude":
680
+ return "ClaudeCodeCLI";
681
+ case "cursor":
682
+ return "Cursor";
683
+ case "windsurf":
684
+ return "Windsurf";
685
+ case "roo":
686
+ return "RooCode";
687
+ case "gemini":
688
+ return "GeminiCLI";
689
+ case "codex":
690
+ return "CodexCLI";
691
+ }
692
+ }
693
+
694
+ // src/commands/config.ts
695
+ import { existsSync as existsSync7 } from "fs";
696
+ import { readFile as readFile3 } from "fs/promises";
697
+ import { resolve as resolve7 } from "path";
698
+ import { fileURLToPath as fileURLToPath3 } from "url";
699
+ import { defineCommand as defineCommand3 } from "citty";
700
+
701
+ // src/commands/hooks.ts
702
+ import { chmodSync, existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync2, statSync, writeFileSync as writeFileSync2 } from "fs";
703
+ import { dirname as dirname4, isAbsolute as isAbsolute2, join as join6, parse as parse2, resolve as resolve6 } from "path";
704
+ import { fileURLToPath as fileURLToPath2 } from "url";
705
+ import { defineCommand as defineCommand2 } from "citty";
706
+ var hooksCommand = defineCommand2({
707
+ meta: {
708
+ name: "hooks",
709
+ description: t("cli.hooks.description")
710
+ },
711
+ subCommands: {
712
+ install: defineCommand2({
713
+ meta: {
714
+ name: "install",
715
+ description: t("cli.hooks.install.description")
716
+ },
717
+ args: {
718
+ target: {
719
+ type: "string",
720
+ description: t("cli.hooks.install.args.target.description"),
721
+ default: process.cwd()
722
+ }
723
+ },
724
+ async run({ args }) {
725
+ const result = await installHooks(args.target);
726
+ if (result.hookAction === "skipped") {
727
+ writeStderr(t("cli.hooks.install.hook-skipped", { path: result.hookPath }));
728
+ } else if (result.hookAction === "appended") {
729
+ writeStderr(t("cli.hooks.install.hook-appended", { path: result.hookPath }));
730
+ } else {
731
+ writeStderr(t("cli.hooks.install.hook-created", { path: result.hookPath }));
732
+ }
733
+ if (result.prepareAction === "left") {
734
+ writeStderr(t("cli.hooks.install.prepare-left", { path: result.packageJsonPath }));
735
+ } else {
736
+ writeStderr(t("cli.hooks.install.prepare-added", { path: result.packageJsonPath }));
737
+ }
738
+ }
739
+ })
740
+ }
741
+ });
742
+ async function installHooks(target, options = {}) {
743
+ const normalizedTarget = normalizeTarget2(target);
744
+ assertExistingDirectory(normalizedTarget);
745
+ const huskyDir = join6(normalizedTarget, ".husky");
746
+ const hookPath = join6(huskyDir, "pre-commit");
747
+ const packageJsonPath = join6(normalizedTarget, "package.json");
748
+ if (!existsSync6(packageJsonPath)) {
749
+ throw new Error(t("cli.hooks.errors.package-json-required", { path: packageJsonPath }));
750
+ }
751
+ mkdirSync2(huskyDir, { recursive: true });
752
+ const templateContent = readFileSync2(findTemplatePath2("templates/husky/pre-commit"), "utf8");
753
+ const hookAction = installHookFile(hookPath, templateContent, options.force);
754
+ chmodSync(hookPath, 493);
755
+ const packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf8"));
756
+ const scripts = packageJson.scripts && typeof packageJson.scripts === "object" && !Array.isArray(packageJson.scripts) ? packageJson.scripts : {};
757
+ const hadPrepare = typeof scripts.prepare === "string" && scripts.prepare.trim().length > 0;
758
+ let prepareAction = "left";
759
+ if (!hadPrepare) {
760
+ scripts.prepare = "husky install";
761
+ packageJson.scripts = scripts;
762
+ writeFileSync2(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
763
+ `, "utf8");
764
+ prepareAction = "added";
765
+ }
766
+ const installed = [];
767
+ const skipped = [];
768
+ if (hookAction === "skipped") {
769
+ skipped.push(hookPath);
770
+ } else {
771
+ installed.push(hookPath);
772
+ }
773
+ if (prepareAction === "left") {
774
+ skipped.push(packageJsonPath);
775
+ } else {
776
+ installed.push(packageJsonPath);
777
+ }
778
+ return {
779
+ installed,
780
+ skipped,
781
+ hookPath,
782
+ packageJsonPath,
783
+ hookAction,
784
+ prepareAction
785
+ };
786
+ }
787
+ function normalizeTarget2(targetInput) {
788
+ return isAbsolute2(targetInput) ? targetInput : resolve6(process.cwd(), targetInput);
789
+ }
790
+ function assertExistingDirectory(target) {
791
+ if (!existsSync6(target) || !statSync(target).isDirectory()) {
792
+ throw new Error(t("cli.shared.target-invalid", { target }));
793
+ }
794
+ }
795
+ function installHookFile(hookPath, templateContent, force) {
796
+ if (existsSync6(hookPath)) {
797
+ if (force) {
798
+ writeFileSync2(hookPath, templateContent, "utf8");
799
+ return "overwritten";
800
+ }
801
+ const existing = readFileSync2(hookPath, "utf8");
802
+ if (existing.includes("FAB_BIN=")) {
803
+ return "skipped";
804
+ }
805
+ const fabricBlock = templateContent.replace(/^#!\/bin\/sh\n/, "");
806
+ const separator = existing.endsWith("\n") ? "\n" : "\n\n";
807
+ writeFileSync2(hookPath, `${existing}${separator}# --- Fabric ---
808
+ ${fabricBlock}`, "utf8");
809
+ return "appended";
810
+ }
811
+ writeFileSync2(hookPath, templateContent, "utf8");
812
+ return "created";
813
+ }
814
+ function findTemplatePath2(relativePath) {
815
+ const currentModuleDir = dirname4(fileURLToPath2(import.meta.url));
816
+ const candidates = [
817
+ ...templateCandidatesFrom2(process.cwd(), relativePath),
818
+ ...templateCandidatesFrom2(currentModuleDir, relativePath)
819
+ ];
820
+ for (const candidate of candidates) {
821
+ if (existsSync6(candidate)) {
822
+ return candidate;
823
+ }
824
+ }
825
+ throw new Error(t("cli.shared.template-not-found", { path: relativePath }));
826
+ }
827
+ function templateCandidatesFrom2(start, relativePath) {
828
+ const candidates = [];
829
+ let current = resolve6(start);
830
+ while (true) {
831
+ candidates.push(join6(current, ...relativePath.split("/")));
832
+ const parent = dirname4(current);
833
+ if (parent === current || parse2(current).root === current) {
834
+ break;
835
+ }
836
+ current = parent;
837
+ }
838
+ return candidates.reverse();
839
+ }
840
+ function writeStderr(message) {
841
+ process.stderr.write(`${message}
842
+ `);
843
+ }
844
+
845
+ // src/commands/config.ts
846
+ var CLIENT_ALIASES2 = {
847
+ claude: "ClaudeCodeCLI",
848
+ claudecodecli: "ClaudeCodeCLI",
849
+ "claude-code-cli": "ClaudeCodeCLI",
850
+ claudecli: "ClaudeCodeCLI",
851
+ claudecodedesktop: "ClaudeCodeDesktop",
852
+ "claude-code-desktop": "ClaudeCodeDesktop",
853
+ claudedesktop: "ClaudeCodeDesktop",
854
+ cursor: "Cursor",
855
+ windsurf: "Windsurf",
856
+ roocode: "RooCode",
857
+ "roo-code": "RooCode",
858
+ roo: "RooCode",
859
+ geminicli: "GeminiCLI",
860
+ "gemini-cli": "GeminiCLI",
861
+ gemini: "GeminiCLI",
862
+ codexcli: "CodexCLI",
863
+ "codex-cli": "CodexCLI",
864
+ codex: "CodexCLI"
865
+ };
866
+ function parseClientFilter2(value) {
867
+ if (value === void 0 || value.trim().length === 0) {
868
+ return null;
869
+ }
870
+ const clients = /* @__PURE__ */ new Set();
871
+ for (const rawClient of value.split(",")) {
872
+ const alias = rawClient.trim().toLowerCase();
873
+ const clientKind = CLIENT_ALIASES2[alias];
874
+ if (clientKind === void 0) {
875
+ throw new Error(t("cli.config.errors.unknown-client", { client: rawClient }));
876
+ }
877
+ clients.add(clientKind);
878
+ }
879
+ return clients;
880
+ }
881
+ async function loadFabricConfig(workspaceRoot) {
882
+ const configPath = resolve7(workspaceRoot, "fabric.config.json");
883
+ if (!existsSync7(configPath)) {
884
+ return {};
885
+ }
886
+ const parsed = JSON.parse(await readFile3(configPath, "utf8"));
887
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
888
+ throw new Error(t("cli.config.errors.expected-object", { path: configPath }));
889
+ }
890
+ return parsed;
891
+ }
892
+ function resolveServerPath(override) {
893
+ if (override) return override;
894
+ if (process.env.FAB_SERVER_PATH) return resolve7(process.env.FAB_SERVER_PATH);
895
+ return fileURLToPath3(import.meta.resolve("@fenglimg/fabric-server"));
896
+ }
897
+ function writeStderr2(message) {
898
+ process.stderr.write(`${message}
899
+ `);
900
+ }
901
+ var configCmd = defineCommand3({
902
+ meta: {
903
+ name: "config",
904
+ description: t("cli.config.description")
905
+ },
906
+ subCommands: {
907
+ hooks: hooksCommand,
908
+ install: defineCommand3({
909
+ meta: {
910
+ name: "install",
911
+ description: t("cli.config.install.description")
912
+ },
913
+ args: {
914
+ clients: {
915
+ type: "string",
916
+ description: t("cli.config.install.args.clients.description")
917
+ },
918
+ "dry-run": {
919
+ type: "boolean",
920
+ description: t("cli.config.install.args.dry-run.description"),
921
+ default: false
922
+ }
923
+ },
924
+ async run({ args }) {
925
+ const selectedClients = parseClientFilter2(args.clients);
926
+ const result = await installMcpClients(process.cwd(), {
927
+ clients: selectedClients === null ? void 0 : Array.from(selectedClients),
928
+ dryRun: args["dry-run"]
929
+ });
930
+ if (result.details.length === 0) {
931
+ writeStderr2(t("cli.config.install.no-configs"));
932
+ return;
933
+ }
934
+ for (const detail of result.details) {
935
+ if (detail.action === "skipped") {
936
+ writeStderr2(t("cli.config.install.no-config-path", { client: detail.client }));
937
+ continue;
938
+ }
939
+ if (detail.action === "dry-run" && detail.path !== null) {
940
+ writeStderr2(t("cli.config.install.dry-run", { client: detail.client, path: detail.path }));
941
+ continue;
942
+ }
943
+ if (detail.path !== null) {
944
+ writeStderr2(t("cli.config.install.wrote", { client: detail.client, path: detail.path }));
945
+ }
946
+ }
947
+ }
948
+ })
949
+ }
950
+ });
951
+ async function installMcpClients(target, options = {}) {
952
+ const workspaceRoot = resolve7(target);
953
+ const fabricConfig = await loadFabricConfig(workspaceRoot);
954
+ const selectedClients = options.clients === void 0 ? null : new Set(options.clients);
955
+ const serverPath = resolveServerPath(options.localServerPath);
956
+ const writers = resolveClients(workspaceRoot, fabricConfig).filter(
957
+ (writer) => selectedClients === null ? true : selectedClients.has(writer.clientKind)
958
+ );
959
+ const installed = [];
960
+ const skipped = [];
961
+ const details = [];
962
+ for (const writer of writers) {
963
+ const configPath = await writer.detect(workspaceRoot);
964
+ if (configPath === null) {
965
+ skipped.push(writer.clientKind);
966
+ details.push({ client: writer.clientKind, path: null, action: "skipped" });
967
+ continue;
968
+ }
969
+ if (options.dryRun) {
970
+ skipped.push(writer.clientKind);
971
+ details.push({ client: writer.clientKind, path: configPath, action: "dry-run" });
972
+ continue;
973
+ }
974
+ await writer.write(serverPath, workspaceRoot);
975
+ installed.push(writer.clientKind);
976
+ details.push({ client: writer.clientKind, path: configPath, action: "wrote" });
977
+ }
978
+ return { installed, skipped, details };
979
+ }
980
+
40
981
  // src/scanner/forensic.ts
41
982
  import { execFileSync } from "child_process";
42
- import { existsSync, readdirSync, readFileSync, statSync } from "fs";
983
+ import { existsSync as existsSync8, readdirSync, readFileSync as readFileSync3, statSync as statSync2 } from "fs";
43
984
  import { createRequire } from "module";
44
- import { basename, extname, isAbsolute, join, posix, relative, resolve, sep } from "path";
985
+ import { basename, extname, isAbsolute as isAbsolute3, join as join7, posix, relative, resolve as resolve8, sep } from "path";
45
986
  import {
46
987
  forensicReportSchema
47
988
  } from "@fenglimg/fabric-shared";
@@ -127,7 +1068,7 @@ var parserInitPromise = null;
127
1068
  var languagePromiseByKind = {};
128
1069
  var parserBundlePromiseByKind = {};
129
1070
  async function buildForensicReport(targetInput) {
130
- const target = normalizeTarget(targetInput);
1071
+ const target = normalizeTarget3(targetInput);
131
1072
  const framework = detectFramework(target);
132
1073
  const topology = buildTopology(target);
133
1074
  const entryPoints = collectEntryPoints(target, topology.files);
@@ -163,11 +1104,11 @@ async function buildForensicReport(targetInput) {
163
1104
  }
164
1105
  return validation.data;
165
1106
  }
166
- function normalizeTarget(targetInput) {
167
- return isAbsolute(targetInput) ? targetInput : resolve(process.cwd(), targetInput);
1107
+ function normalizeTarget3(targetInput) {
1108
+ return isAbsolute3(targetInput) ? targetInput : resolve8(process.cwd(), targetInput);
168
1109
  }
169
1110
  function buildTopology(root) {
170
- assertExistingDirectory(root);
1111
+ assertExistingDirectory2(root);
171
1112
  const byExt = {};
172
1113
  const keyDirs = /* @__PURE__ */ new Set();
173
1114
  const files = [];
@@ -180,7 +1121,7 @@ function buildTopology(root) {
180
1121
  continue;
181
1122
  }
182
1123
  for (const entry of readdirSync(current, { withFileTypes: true })) {
183
- const absolutePath = join(current, entry.name);
1124
+ const absolutePath = join7(current, entry.name);
184
1125
  const relativePath = toPosixPath(relative(root, absolutePath));
185
1126
  if (relativePath.length === 0) {
186
1127
  continue;
@@ -200,7 +1141,7 @@ function buildTopology(root) {
200
1141
  if (!entry.isFile()) {
201
1142
  continue;
202
1143
  }
203
- const stats = statSync(absolutePath);
1144
+ const stats = statSync2(absolutePath);
204
1145
  const extension = extname(entry.name) || "[none]";
205
1146
  byExt[extension] = (byExt[extension] ?? 0) + 1;
206
1147
  totalFiles += 1;
@@ -218,8 +1159,8 @@ function buildTopology(root) {
218
1159
  files: files.sort((left, right) => left.relativePath.localeCompare(right.relativePath))
219
1160
  };
220
1161
  }
221
- function assertExistingDirectory(target) {
222
- if (!existsSync(target) || !statSync(target).isDirectory()) {
1162
+ function assertExistingDirectory2(target) {
1163
+ if (!existsSync8(target) || !statSync2(target).isDirectory()) {
223
1164
  throw new Error(`Target must be an existing directory: ${target}`);
224
1165
  }
225
1166
  }
@@ -268,7 +1209,7 @@ function getEntryPointReason(relativePath) {
268
1209
  async function buildCodeSamples(target, entryPoints, frameworkKind, topology, packageDependencies) {
269
1210
  const samples = [];
270
1211
  for (const entryPoint of entryPoints.slice(0, SAMPLE_LIMIT)) {
271
- const absolutePath = join(target, ...entryPoint.path.split("/"));
1212
+ const absolutePath = join7(target, ...entryPoint.path.split("/"));
272
1213
  const sample = readFirstLines(absolutePath, SAMPLE_LINE_LIMIT);
273
1214
  const patternAnalysis = await inferPatternHint(entryPoint.path, sample.snippet, {
274
1215
  frameworkKind,
@@ -288,7 +1229,7 @@ async function buildCodeSamples(target, entryPoints, frameworkKind, topology, pa
288
1229
  }
289
1230
  function readFirstLines(path, lineLimit) {
290
1231
  try {
291
- const lines = readFileSync(path, "utf8").split(/\r?\n/);
1232
+ const lines = readFileSync3(path, "utf8").split(/\r?\n/);
292
1233
  if (lines.at(-1) === "") {
293
1234
  lines.pop();
294
1235
  }
@@ -305,12 +1246,12 @@ function readFirstLines(path, lineLimit) {
305
1246
  }
306
1247
  }
307
1248
  function readPackageDependencies(target) {
308
- const packageJsonPath = join(target, "package.json");
309
- if (!existsSync(packageJsonPath)) {
1249
+ const packageJsonPath = join7(target, "package.json");
1250
+ if (!existsSync8(packageJsonPath)) {
310
1251
  return /* @__PURE__ */ new Map();
311
1252
  }
312
1253
  try {
313
- const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
1254
+ const packageJson = JSON.parse(readFileSync3(packageJsonPath, "utf8"));
314
1255
  return new Map([
315
1256
  ...Object.entries(packageJson.dependencies ?? {}),
316
1257
  ...Object.entries(packageJson.devDependencies ?? {}),
@@ -646,16 +1587,16 @@ function scoreFrameworkConfidence(input) {
646
1587
  return input.configCount > 0 || input.packageCount > 0 ? "MEDIUM" : "LOW";
647
1588
  }
648
1589
  function readReadmeInfo(target) {
649
- const readmePath = join(target, "README.md");
650
- const hasContributing = existsSync(join(target, "CONTRIBUTING.md"));
651
- if (!existsSync(readmePath)) {
1590
+ const readmePath = join7(target, "README.md");
1591
+ const hasContributing = existsSync8(join7(target, "CONTRIBUTING.md"));
1592
+ if (!existsSync8(readmePath)) {
652
1593
  return {
653
1594
  quality: "missing",
654
1595
  line_count: 0,
655
1596
  has_contributing: hasContributing
656
1597
  };
657
1598
  }
658
- const readme = readFileSync(readmePath, "utf8");
1599
+ const readme = readFileSync3(readmePath, "utf8");
659
1600
  const wordCount = readme.trim().split(/\s+/).filter(Boolean).length;
660
1601
  return {
661
1602
  quality: wordCount >= 200 ? "ok" : "stub",
@@ -888,7 +1829,7 @@ function buildDomainAssertion(codeSamples) {
888
1829
  namedModules.length >= 2 ? "domain-named-components" : null,
889
1830
  namedSamples.some((sample) => sample.snippet.includes("start():")) ? "lifecycle-hook" : null
890
1831
  ]),
891
- proposedRule: "Preserve domain-specific module names when mirroring structure into AGENTS.md or .fabric/agents/."
1832
+ proposedRule: "Preserve domain-specific module names when mirroring structure into .fabric/rules/."
892
1833
  });
893
1834
  }
894
1835
  function createAssertion(input) {
@@ -1133,10 +2074,10 @@ function buildSkillRecommendations(frameworkKind, topology, readme) {
1133
2074
  return recommendations;
1134
2075
  }
1135
2076
  function readProjectName(target) {
1136
- const packageJsonPath = join(target, "package.json");
1137
- if (existsSync(packageJsonPath)) {
2077
+ const packageJsonPath = join7(target, "package.json");
2078
+ if (existsSync8(packageJsonPath)) {
1138
2079
  try {
1139
- const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
2080
+ const packageJson = JSON.parse(readFileSync3(packageJsonPath, "utf8"));
1140
2081
  if (packageJson.name !== void 0 && packageJson.name.trim().length > 0) {
1141
2082
  return packageJson.name;
1142
2083
  }
@@ -1147,7 +2088,7 @@ function readProjectName(target) {
1147
2088
  return basename(target);
1148
2089
  }
1149
2090
  function getCliVersion() {
1150
- return true ? "1.6.0" : "unknown";
2091
+ return true ? "1.7.0" : "unknown";
1151
2092
  }
1152
2093
  function sortRecord(record) {
1153
2094
  return Object.fromEntries(Object.entries(record).sort(([left], [right]) => left.localeCompare(right)));
@@ -1165,10 +2106,10 @@ var CODEX_SESSION_START_HOOK_TEMPLATE = "templates/codex-hooks/fabric-session-st
1165
2106
  var CODEX_STOP_HOOK_TEMPLATE = "templates/codex-hooks/fabric-stop-reminder.cjs";
1166
2107
  var CODEX_SESSION_START_COMMAND = ".codex/hooks/fabric-session-start.cjs";
1167
2108
  var CODEX_STOP_COMMAND = ".codex/hooks/fabric-stop-reminder.cjs";
1168
- var LOCAL_FABRIC_SERVER_PATH = join2("node_modules", "@fenglimg", "fabric-server", "dist", "index.js");
2109
+ var LOCAL_FABRIC_SERVER_PATH = join8("node_modules", "@fenglimg", "fabric-server", "dist", "index.js");
1169
2110
  var FABRIC_SERVER_PACKAGE = "@fenglimg/fabric-server";
1170
2111
  var INIT_WIZARD_GROUP_CANCELLED = /* @__PURE__ */ Symbol("init-wizard-group-cancelled");
1171
- var initCommand = defineCommand({
2112
+ var initCommand = defineCommand4({
1172
2113
  meta: {
1173
2114
  name: "init",
1174
2115
  description: t("cli.init.description")
@@ -1243,13 +2184,13 @@ async function runInitCommand(args) {
1243
2184
  logger(step);
1244
2185
  }
1245
2186
  if (intent.options.planOnly) {
1246
- writeStderr(t("cli.init.compat.plan"));
2187
+ writeStderr3(t("cli.init.compat.plan"));
1247
2188
  }
1248
2189
  if (args.interactive === false) {
1249
- writeStderr(t("cli.init.compat.interactive"));
2190
+ writeStderr3(t("cli.init.compat.interactive"));
1250
2191
  }
1251
2192
  if (args.bootstrap === false || args.mcp === false || args.hooks === false) {
1252
- writeStderr(t("cli.init.compat.legacy-stage-flags"));
2193
+ writeStderr3(t("cli.init.compat.legacy-stage-flags"));
1253
2194
  }
1254
2195
  const supports = detectClientSupports(intent.target);
1255
2196
  const basePlan = await buildInitExecutionPlan({
@@ -1261,13 +2202,13 @@ async function runInitCommand(args) {
1261
2202
  });
1262
2203
  const plan = intent.wizardEnabled ? await resolveInitExecutionPlanWithWizard(basePlan, args, createDefaultInitWizardAdapter()) : basePlan;
1263
2204
  if (plan === null) {
1264
- writeStderr(t("cli.init.wizard.cancelled"));
2205
+ writeStderr3(t("cli.init.wizard.cancelled"));
1265
2206
  throw new Error(t("cli.init.wizard.cancelled"));
1266
2207
  }
1267
2208
  return executeInitExecutionPlan(plan);
1268
2209
  }
1269
2210
  function resolveInitCliIntent(args, targetInput) {
1270
- const target = normalizeTarget2(targetInput);
2211
+ const target = normalizeTarget4(targetInput);
1271
2212
  const mcpInstallMode = resolveMcpInstallMode(args["mcp-install"]);
1272
2213
  const terminalInteractive = isInteractiveInit();
1273
2214
  const planOnly = args.plan === true;
@@ -1322,10 +2263,10 @@ async function buildInitExecutionPlan(input) {
1322
2263
  }
1323
2264
  async function executeInitExecutionPlan(plan) {
1324
2265
  if (plan.options.force) {
1325
- writeStderr(t("cli.init.force.warning", { path: plan.target }));
2266
+ writeStderr3(t("cli.init.force.warning", { path: plan.target }));
1326
2267
  }
1327
2268
  if (plan.options.reapply && !plan.options.planOnly && !plan.interactive) {
1328
- writeStderr(formatInitModeBanner(plan.options));
2269
+ writeStderr3(formatInitModeBanner(plan.options));
1329
2270
  }
1330
2271
  if (plan.interactive) {
1331
2272
  printInitPlanSummary(plan.target, plan.options, plan.mcpInstallMode, plan.supports);
@@ -1371,28 +2312,28 @@ async function executeInitExecutionPlan(plan) {
1371
2312
  };
1372
2313
  }
1373
2314
  async function buildInitFabricPlan(target, options) {
1374
- assertExistingDirectory2(target);
1375
- const fabricDir = join2(target, ".fabric");
1376
- const bootstrapPath = join2(fabricDir, "bootstrap", "README.md");
1377
- const forensicPath = join2(fabricDir, "forensic.json");
1378
- const taxonomyPath = join2(fabricDir, "INITIAL_TAXONOMY.md");
1379
- const claudeSkillPath = join2(target, ".claude", "skills", "agents-md-init", "SKILL.md");
1380
- const codexSkillPath = join2(target, ".agents", "skills", "fabric-init", "SKILL.md");
1381
- const codexSessionStartHookPath = join2(target, ".codex", "hooks", "fabric-session-start.cjs");
1382
- const codexStopHookPath = join2(target, ".codex", "hooks", "fabric-stop-reminder.cjs");
1383
- const codexHooksConfigPath = join2(target, ".codex", "hooks.json");
1384
- const claudeHookPath = join2(target, ".claude", "hooks", "agents-md-init-reminder.cjs");
1385
- const claudeSettingsPath = join2(target, ".claude", "settings.json");
1386
- const metaPath = join2(fabricDir, "agents.meta.json");
1387
- const humanLockPath = join2(fabricDir, "human-lock.json");
2315
+ assertExistingDirectory3(target);
2316
+ const fabricDir = join8(target, ".fabric");
2317
+ const bootstrapPath = join8(fabricDir, "bootstrap", "README.md");
2318
+ const forensicPath = join8(fabricDir, "forensic.json");
2319
+ const taxonomyPath = join8(fabricDir, "INITIAL_TAXONOMY.md");
2320
+ const rulesDir = join8(fabricDir, "rules");
2321
+ const eventsPath = join8(fabricDir, "events.jsonl");
2322
+ const claudeSkillPath = join8(target, ".claude", "skills", "agents-md-init", "SKILL.md");
2323
+ const codexSkillPath = join8(target, ".agents", "skills", "fabric-init", "SKILL.md");
2324
+ const codexSessionStartHookPath = join8(target, ".codex", "hooks", "fabric-session-start.cjs");
2325
+ const codexStopHookPath = join8(target, ".codex", "hooks", "fabric-stop-reminder.cjs");
2326
+ const codexHooksConfigPath = join8(target, ".codex", "hooks.json");
2327
+ const claudeHookPath = join8(target, ".claude", "hooks", "agents-md-init-reminder.cjs");
2328
+ const claudeSettingsPath = join8(target, ".claude", "settings.json");
2329
+ const metaPath = join8(fabricDir, "agents.meta.json");
1388
2330
  const replaceFabricDir = shouldReplaceWritableDirectory(fabricDir, options);
1389
2331
  const bootstrapAction = planFreshPath(bootstrapPath, options);
1390
2332
  const metaAction = planFreshPath(metaPath, options);
1391
2333
  const taxonomyAction = planFreshPath(taxonomyPath, options);
1392
- const humanLockAction = planFreshPath(humanLockPath, options);
2334
+ const eventsAction = planFreshPath(eventsPath, options);
1393
2335
  const forensicAction = planFreshPath(forensicPath, options);
1394
2336
  const forensicReport = await buildForensicReport(target);
1395
- const humanLockTemplate = readFileSync2(findTemplatePath("templates/fabric/human-lock.json"), "utf8");
1396
2337
  const bootstrapContent = await buildFabricBootstrapGuide(target);
1397
2338
  const taxonomyContent = buildInitialTaxonomyMarkdown(forensicReport);
1398
2339
  const bootstrapHash = sha256(bootstrapContent);
@@ -1411,31 +2352,30 @@ async function buildInitFabricPlan(target, options) {
1411
2352
  taxonomyPath,
1412
2353
  taxonomyAction,
1413
2354
  taxonomyContent,
1414
- humanLockPath,
1415
- humanLockAction,
1416
- humanLockContent: humanLockTemplate.endsWith("\n") ? humanLockTemplate : `${humanLockTemplate}
1417
- `,
2355
+ rulesDir,
2356
+ eventsPath,
2357
+ eventsAction,
1418
2358
  forensicPath,
1419
2359
  forensicAction,
1420
2360
  forensicReport,
1421
- claudeSkill: buildOptionalTemplateWritePlan(claudeSkillPath, findTemplatePath(CLAUDE_INIT_SKILL_TEMPLATE), options),
1422
- codexSkill: buildOptionalTemplateWritePlan(codexSkillPath, findTemplatePath(CODEX_INIT_SKILL_TEMPLATE), options),
2361
+ claudeSkill: buildOptionalTemplateWritePlan(claudeSkillPath, findTemplatePath3(CLAUDE_INIT_SKILL_TEMPLATE), options),
2362
+ codexSkill: buildOptionalTemplateWritePlan(codexSkillPath, findTemplatePath3(CODEX_INIT_SKILL_TEMPLATE), options),
1423
2363
  codexSessionStartHook: buildOptionalTemplateWritePlan(
1424
2364
  codexSessionStartHookPath,
1425
- findTemplatePath(CODEX_SESSION_START_HOOK_TEMPLATE),
2365
+ findTemplatePath3(CODEX_SESSION_START_HOOK_TEMPLATE),
1426
2366
  options,
1427
2367
  true
1428
2368
  ),
1429
2369
  codexStopHook: buildOptionalTemplateWritePlan(
1430
2370
  codexStopHookPath,
1431
- findTemplatePath(CODEX_STOP_HOOK_TEMPLATE),
2371
+ findTemplatePath3(CODEX_STOP_HOOK_TEMPLATE),
1432
2372
  options,
1433
2373
  true
1434
2374
  ),
1435
2375
  codexHooksConfig: buildCodexHooksConfigPlan(codexHooksConfigPath, options),
1436
2376
  claudeHook: buildOptionalTemplateWritePlan(
1437
2377
  claudeHookPath,
1438
- findTemplatePath(CLAUDE_INIT_REMINDER_HOOK_TEMPLATE),
2378
+ findTemplatePath3(CLAUDE_INIT_REMINDER_HOOK_TEMPLATE),
1439
2379
  options,
1440
2380
  true
1441
2381
  ),
@@ -1446,19 +2386,20 @@ function executeInitFabricPlan(plan) {
1446
2386
  if (plan.replaceFabricDir) {
1447
2387
  rmSync(plan.fabricDir, { force: true });
1448
2388
  }
1449
- mkdirSync(plan.fabricDir, { recursive: true });
1450
- mkdirSync(dirname(plan.bootstrapPath), { recursive: true });
2389
+ mkdirSync3(plan.fabricDir, { recursive: true });
2390
+ mkdirSync3(dirname5(plan.bootstrapPath), { recursive: true });
1451
2391
  preparePlannedPath(plan.bootstrapPath, plan.bootstrapAction);
1452
- writeFileSync(plan.bootstrapPath, plan.bootstrapContent, "utf8");
2392
+ writeFileSync3(plan.bootstrapPath, plan.bootstrapContent, "utf8");
1453
2393
  preparePlannedPath(plan.metaPath, plan.metaAction);
1454
- writeFileSync(plan.metaPath, `${JSON.stringify(plan.meta, null, 2)}
2394
+ writeFileSync3(plan.metaPath, `${JSON.stringify(plan.meta, null, 2)}
1455
2395
  `, "utf8");
1456
2396
  preparePlannedPath(plan.taxonomyPath, plan.taxonomyAction);
1457
- writeFileSync(plan.taxonomyPath, ensureTrailingNewline(plan.taxonomyContent), "utf8");
1458
- preparePlannedPath(plan.humanLockPath, plan.humanLockAction);
1459
- writeFileSync(plan.humanLockPath, plan.humanLockContent, "utf8");
2397
+ writeFileSync3(plan.taxonomyPath, ensureTrailingNewline2(plan.taxonomyContent), "utf8");
2398
+ mkdirSync3(plan.rulesDir, { recursive: true });
2399
+ preparePlannedPath(plan.eventsPath, plan.eventsAction);
2400
+ writeFileSync3(plan.eventsPath, "", "utf8");
1460
2401
  preparePlannedPath(plan.forensicPath, plan.forensicAction);
1461
- writeFileSync(plan.forensicPath, `${JSON.stringify(plan.forensicReport, null, 2)}
2402
+ writeFileSync3(plan.forensicPath, `${JSON.stringify(plan.forensicReport, null, 2)}
1462
2403
  `, "utf8");
1463
2404
  applyOptionalTemplateWritePlan(plan.claudeSkill);
1464
2405
  applyOptionalTemplateWritePlan(plan.codexSkill);
@@ -1474,8 +2415,8 @@ function executeInitFabricPlan(plan) {
1474
2415
  metaAction: plan.metaAction,
1475
2416
  taxonomyPath: plan.taxonomyPath,
1476
2417
  taxonomyAction: plan.taxonomyAction,
1477
- humanLockPath: plan.humanLockPath,
1478
- humanLockAction: plan.humanLockAction,
2418
+ eventsPath: plan.eventsPath,
2419
+ eventsAction: plan.eventsAction,
1479
2420
  forensicPath: plan.forensicPath,
1480
2421
  forensicAction: plan.forensicAction,
1481
2422
  claudeSkillPath: plan.claudeSkill.path,
@@ -1537,19 +2478,19 @@ function printInitScaffoldResult(created) {
1537
2478
  console.log(formatInitPathAction(created.bootstrapPath, created.bootstrapAction));
1538
2479
  console.log(formatInitPathAction(created.metaPath, created.metaAction));
1539
2480
  console.log(formatInitPathAction(created.taxonomyPath, created.taxonomyAction));
1540
- console.log(formatInitPathAction(created.humanLockPath, created.humanLockAction));
2481
+ console.log(formatInitPathAction(created.eventsPath, created.eventsAction));
1541
2482
  console.log(formatInitPathAction(created.forensicPath, created.forensicAction));
1542
- writeStderr(formatOptionalInitPathAction(created.claudeSkillPath, created.claudeSkillAction));
1543
- writeStderr(formatOptionalInitPathAction(created.codexSkillPath, created.codexSkillAction));
1544
- writeStderr(
2483
+ writeStderr3(formatOptionalInitPathAction(created.claudeSkillPath, created.claudeSkillAction));
2484
+ writeStderr3(formatOptionalInitPathAction(created.codexSkillPath, created.codexSkillAction));
2485
+ writeStderr3(
1545
2486
  formatOptionalInitPathAction(created.codexSessionStartHookPath, created.codexSessionStartHookAction)
1546
2487
  );
1547
- writeStderr(
2488
+ writeStderr3(
1548
2489
  formatOptionalInitPathAction(created.codexStopHookPath, created.codexStopHookAction)
1549
2490
  );
1550
- writeStderr(formatCodexHooksAction(created.codexHooksConfigPath, created.codexHooksConfigAction));
1551
- writeStderr(formatOptionalInitPathAction(created.claudeHookPath, created.claudeHookAction));
1552
- writeStderr(formatClaudeSettingsAction(created.claudeSettingsPath, created.claudeSettingsAction));
2491
+ writeStderr3(formatCodexHooksAction(created.codexHooksConfigPath, created.codexHooksConfigAction));
2492
+ writeStderr3(formatOptionalInitPathAction(created.claudeHookPath, created.claudeHookAction));
2493
+ writeStderr3(formatClaudeSettingsAction(created.claudeSettingsPath, created.claudeSettingsAction));
1553
2494
  }
1554
2495
  function printInitPostSetup(plan, stageResults, finalSupports) {
1555
2496
  if (shouldPrintHooksNextStep(plan.options, stageResults)) {
@@ -1589,8 +2530,8 @@ function buildPlanOnlyScaffoldResult(plan) {
1589
2530
  metaAction: plan.metaAction,
1590
2531
  taxonomyPath: plan.taxonomyPath,
1591
2532
  taxonomyAction: plan.taxonomyAction,
1592
- humanLockPath: plan.humanLockPath,
1593
- humanLockAction: plan.humanLockAction,
2533
+ eventsPath: plan.eventsPath,
2534
+ eventsAction: plan.eventsAction,
1594
2535
  forensicPath: plan.forensicPath,
1595
2536
  forensicAction: plan.forensicAction,
1596
2537
  claudeSkillPath: plan.claudeSkill.path,
@@ -1634,12 +2575,12 @@ async function executeInitStagePlan(plan, stageName) {
1634
2575
  case "mcp": {
1635
2576
  if (stage.installMode === "local") {
1636
2577
  const manager = stage.packageManager ?? detectPackageManager(plan.target);
1637
- writeStderr(t("cli.init.mcp.install.local"));
1638
- writeStderr(t("cli.init.mcp.local.installing", { manager }));
2578
+ writeStderr3(t("cli.init.mcp.install.local"));
2579
+ writeStderr3(t("cli.init.mcp.local.installing", { manager }));
1639
2580
  installLocalFabricServer(plan.target, manager);
1640
- writeStderr(t("cli.init.mcp.local.installed"));
2581
+ writeStderr3(t("cli.init.mcp.local.installed"));
1641
2582
  } else {
1642
- writeStderr(t("cli.init.mcp.install.global"));
2583
+ writeStderr3(t("cli.init.mcp.install.global"));
1643
2584
  }
1644
2585
  const result = await installMcpClients(plan.target, {
1645
2586
  force: plan.options.force,
@@ -1661,15 +2602,15 @@ async function executeInitStagePlan(plan, stageName) {
1661
2602
  return exhaustiveInitStagePlan(stage);
1662
2603
  }
1663
2604
  } catch (error) {
1664
- writeStderr(formatInitStageFailure(stageName, error));
2605
+ writeStderr3(formatInitStageFailure(stageName, error));
1665
2606
  return { name: stageName, disposition: "failed" };
1666
2607
  }
1667
2608
  }
1668
2609
  function shouldReplaceWritableDirectory(path, options) {
1669
- if (!existsSync2(path)) {
2610
+ if (!existsSync9(path)) {
1670
2611
  return false;
1671
2612
  }
1672
- if (statSync2(path).isDirectory()) {
2613
+ if (statSync3(path).isDirectory()) {
1673
2614
  return false;
1674
2615
  }
1675
2616
  if (!options?.force) {
@@ -1678,7 +2619,7 @@ function shouldReplaceWritableDirectory(path, options) {
1678
2619
  return true;
1679
2620
  }
1680
2621
  function planFreshPath(path, options) {
1681
- if (!existsSync2(path)) {
2622
+ if (!existsSync9(path)) {
1682
2623
  return "created";
1683
2624
  }
1684
2625
  if (!options?.force) {
@@ -1687,13 +2628,13 @@ function planFreshPath(path, options) {
1687
2628
  return "overwritten";
1688
2629
  }
1689
2630
  function preparePlannedPath(path, action) {
1690
- mkdirSync(dirname(path), { recursive: true });
1691
- if (action === "overwritten" && existsSync2(path)) {
2631
+ mkdirSync3(dirname5(path), { recursive: true });
2632
+ if (action === "overwritten" && existsSync9(path)) {
1692
2633
  rmSync(path, { recursive: true, force: true });
1693
2634
  }
1694
2635
  }
1695
2636
  function buildOptionalTemplateWritePlan(path, templatePath, options, executable = false) {
1696
- const existed = existsSync2(path);
2637
+ const existed = existsSync9(path);
1697
2638
  if (existed && !options?.force) {
1698
2639
  return { path, action: "skipped", templatePath, executable };
1699
2640
  }
@@ -1708,10 +2649,10 @@ function applyOptionalTemplateWritePlan(plan) {
1708
2649
  if (plan.action === "skipped") {
1709
2650
  return;
1710
2651
  }
1711
- mkdirSync(dirname(plan.path), { recursive: true });
2652
+ mkdirSync3(dirname5(plan.path), { recursive: true });
1712
2653
  copyFileSync(plan.templatePath, plan.path);
1713
2654
  if (plan.executable) {
1714
- chmodSync(plan.path, 493);
2655
+ chmodSync2(plan.path, 493);
1715
2656
  }
1716
2657
  }
1717
2658
  function buildCodexHooksConfigValue() {
@@ -1733,7 +2674,7 @@ function buildCodexHooksConfigValue() {
1733
2674
  };
1734
2675
  }
1735
2676
  function buildCodexHooksConfigPlan(configPath, options) {
1736
- const action = !existsSync2(configPath) ? "created" : options?.force ? "overwritten" : "skipped";
2677
+ const action = !existsSync9(configPath) ? "created" : options?.force ? "overwritten" : "skipped";
1737
2678
  return {
1738
2679
  path: configPath,
1739
2680
  action,
@@ -1744,37 +2685,37 @@ function applyJsonWritePlan(plan) {
1744
2685
  if (plan.action === "skipped") {
1745
2686
  return;
1746
2687
  }
1747
- mkdirSync(dirname(plan.path), { recursive: true });
2688
+ mkdirSync3(dirname5(plan.path), { recursive: true });
1748
2689
  writeJsonAtomically(plan.path, plan.value);
1749
2690
  }
1750
2691
  function buildClaudeSettingsWritePlan(settingsPath, options) {
1751
2692
  let settings;
1752
2693
  let action = "updated";
1753
- if (!existsSync2(settingsPath)) {
2694
+ if (!existsSync9(settingsPath)) {
1754
2695
  settings = {};
1755
2696
  action = "created";
1756
2697
  } else {
1757
2698
  try {
1758
- const parsed = JSON.parse(readFileSync2(settingsPath, "utf8"));
2699
+ const parsed = JSON.parse(readFileSync4(settingsPath, "utf8"));
1759
2700
  if (!isRecord(parsed)) {
1760
- writeStderr(t("cli.init.claude-settings.invalid-object", { label: skippedLabel(), path: settingsPath }));
2701
+ writeStderr3(t("cli.init.claude-settings.invalid-object", { label: skippedLabel(), path: settingsPath }));
1761
2702
  return { path: settingsPath, action: "skipped-invalid", value: null };
1762
2703
  }
1763
2704
  settings = parsed;
1764
2705
  } catch (error) {
1765
2706
  const reason = error instanceof Error ? error.message : "unknown parse error";
1766
- writeStderr(t("cli.init.claude-settings.invalid-json", { label: skippedLabel(), path: settingsPath, reason }));
2707
+ writeStderr3(t("cli.init.claude-settings.invalid-json", { label: skippedLabel(), path: settingsPath, reason }));
1767
2708
  return { path: settingsPath, action: "skipped-invalid", value: null };
1768
2709
  }
1769
2710
  }
1770
2711
  if (settings.hooks !== void 0 && !isRecord(settings.hooks)) {
1771
- writeStderr(t("cli.init.claude-settings.invalid-hooks", { label: skippedLabel(), path: settingsPath }));
2712
+ writeStderr3(t("cli.init.claude-settings.invalid-hooks", { label: skippedLabel(), path: settingsPath }));
1772
2713
  return { path: settingsPath, action: "skipped-invalid", value: null };
1773
2714
  }
1774
2715
  const hooks = settings.hooks ?? {};
1775
2716
  const stopHooksValue = hooks.Stop;
1776
2717
  if (stopHooksValue !== void 0 && !Array.isArray(stopHooksValue)) {
1777
- writeStderr(t("cli.init.claude-settings.invalid-stop-array", { label: skippedLabel(), path: settingsPath }));
2718
+ writeStderr3(t("cli.init.claude-settings.invalid-stop-array", { label: skippedLabel(), path: settingsPath }));
1778
2719
  return { path: settingsPath, action: "skipped-invalid", value: null };
1779
2720
  }
1780
2721
  const stopHooks = Array.isArray(stopHooksValue) ? stopHooksValue : [];
@@ -1809,7 +2750,7 @@ function applyClaudeSettingsWritePlan(plan) {
1809
2750
  if (plan.value === null) {
1810
2751
  return;
1811
2752
  }
1812
- mkdirSync(dirname(plan.path), { recursive: true });
2753
+ mkdirSync3(dirname5(plan.path), { recursive: true });
1813
2754
  writeJsonAtomically(plan.path, plan.value);
1814
2755
  }
1815
2756
  function createDefaultInitWizardAdapter() {
@@ -1964,23 +2905,23 @@ function formatInitModeBadge(options) {
1964
2905
  }
1965
2906
  return t("cli.init.mode.badge.default");
1966
2907
  }
1967
- function normalizeTarget2(targetInput) {
1968
- return isAbsolute2(targetInput) ? targetInput : resolve2(process.cwd(), targetInput);
2908
+ function normalizeTarget4(targetInput) {
2909
+ return isAbsolute4(targetInput) ? targetInput : resolve9(process.cwd(), targetInput);
1969
2910
  }
1970
- function assertExistingDirectory2(target) {
1971
- if (!existsSync2(target) || !statSync2(target).isDirectory()) {
2911
+ function assertExistingDirectory3(target) {
2912
+ if (!existsSync9(target) || !statSync3(target).isDirectory()) {
1972
2913
  throw new Error(`Target must be an existing directory: ${target}`);
1973
2914
  }
1974
2915
  }
1975
2916
  function detectPackageManager(cwd) {
1976
- const workspaceRoot = resolve2(cwd);
1977
- if (existsSync2(join2(workspaceRoot, "pnpm-lock.yaml"))) {
2917
+ const workspaceRoot = resolve9(cwd);
2918
+ if (existsSync9(join8(workspaceRoot, "pnpm-lock.yaml"))) {
1978
2919
  return "pnpm";
1979
2920
  }
1980
- if (existsSync2(join2(workspaceRoot, "yarn.lock"))) {
2921
+ if (existsSync9(join8(workspaceRoot, "yarn.lock"))) {
1981
2922
  return "yarn";
1982
2923
  }
1983
- if (existsSync2(join2(workspaceRoot, "package-lock.json"))) {
2924
+ if (existsSync9(join8(workspaceRoot, "package-lock.json"))) {
1984
2925
  return "npm";
1985
2926
  }
1986
2927
  return "npm";
@@ -1989,7 +2930,7 @@ function resolveMcpInstallMode(rawMode) {
1989
2930
  if (rawMode === void 0 || rawMode === "global" || rawMode === "local") {
1990
2931
  return rawMode ?? "global";
1991
2932
  }
1992
- writeStderr(t("cli.init.mcp.install.invalid", { value: rawMode }));
2933
+ writeStderr3(t("cli.init.mcp.install.invalid", { value: rawMode }));
1993
2934
  return "global";
1994
2935
  }
1995
2936
  function installLocalFabricServer(target, manager) {
@@ -2066,30 +3007,30 @@ function sanitizeTaxonomyLabel(value) {
2066
3007
  const sanitized = value.replaceAll("\\", "/").split("/").filter(Boolean).join("-").replace(/[^A-Za-z0-9_-]+/gu, "-").replace(/^-+|-+$/gu, "");
2067
3008
  return sanitized === "" ? "General" : sanitized;
2068
3009
  }
2069
- function ensureTrailingNewline(value) {
3010
+ function ensureTrailingNewline2(value) {
2070
3011
  return value.endsWith("\n") ? value : `${value}
2071
3012
  `;
2072
3013
  }
2073
- function findTemplatePath(relativePath) {
2074
- const currentModuleDir = dirname(fileURLToPath(import.meta.url));
3014
+ function findTemplatePath3(relativePath) {
3015
+ const currentModuleDir = dirname5(fileURLToPath4(import.meta.url));
2075
3016
  const candidates = [
2076
- ...templateCandidatesFrom(process.cwd(), relativePath),
2077
- ...templateCandidatesFrom(currentModuleDir, relativePath)
3017
+ ...templateCandidatesFrom3(process.cwd(), relativePath),
3018
+ ...templateCandidatesFrom3(currentModuleDir, relativePath)
2078
3019
  ];
2079
3020
  for (const candidate of candidates) {
2080
- if (existsSync2(candidate)) {
3021
+ if (existsSync9(candidate)) {
2081
3022
  return candidate;
2082
3023
  }
2083
3024
  }
2084
3025
  throw new Error(t("cli.shared.template-not-found", { path: relativePath }));
2085
3026
  }
2086
- function templateCandidatesFrom(start, relativePath) {
3027
+ function templateCandidatesFrom3(start, relativePath) {
2087
3028
  const candidates = [];
2088
- let current = resolve2(start);
3029
+ let current = resolve9(start);
2089
3030
  while (true) {
2090
- candidates.push(join2(current, ...relativePath.split("/")));
2091
- const parent = dirname(current);
2092
- if (parent === current || parse(current).root === current) {
3031
+ candidates.push(join8(current, ...relativePath.split("/")));
3032
+ const parent = dirname5(current);
3033
+ if (parent === current || parse3(current).root === current) {
2093
3034
  break;
2094
3035
  }
2095
3036
  current = parent;
@@ -2112,7 +3053,7 @@ function isClaudeInitReminderStopEntry(entry) {
2112
3053
  }
2113
3054
  function writeJsonAtomically(path, value) {
2114
3055
  const tempPath = `${path}.${process.pid}.tmp`;
2115
- writeFileSync(tempPath, `${JSON.stringify(value, null, 2)}
3056
+ writeFileSync3(tempPath, `${JSON.stringify(value, null, 2)}
2116
3057
  `, "utf8");
2117
3058
  renameSync(tempPath, path);
2118
3059
  }
@@ -2187,7 +3128,8 @@ function printInitPlanSummary(target, options, mcpInstallMode, supports) {
2187
3128
  console.log(t("cli.init.plan.writes"));
2188
3129
  console.log(` - ${target}/.fabric/bootstrap/README.md`);
2189
3130
  console.log(` - ${target}/.fabric/agents.meta.json`);
2190
- console.log(` - ${target}/.fabric/human-lock.json`);
3131
+ console.log(` - ${target}/.fabric/INITIAL_TAXONOMY.md`);
3132
+ console.log(` - ${target}/.fabric/events.jsonl`);
2191
3133
  console.log(` - ${target}/.fabric/forensic.json`);
2192
3134
  }
2193
3135
  function printInitCapabilitySummary(supports, stageResults, options) {
@@ -2351,7 +3293,7 @@ function skippedStageLabel() {
2351
3293
  function failedStageLabel() {
2352
3294
  return paint.error(t("cli.init.stages.failed"));
2353
3295
  }
2354
- function writeStderr(message) {
3296
+ function writeStderr3(message) {
2355
3297
  process.stderr.write(`${message}
2356
3298
  `);
2357
3299
  }