@fenglimg/fabric-cli 1.0.0 → 1.2.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.
@@ -1,601 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- createScanReport,
4
- detectFramework
5
- } from "./chunk-DKQ3HOTK.js";
6
- import {
7
- createDebugLogger,
8
- resolveDevMode
9
- } from "./chunk-AEOYCVBG.js";
10
- import "./chunk-P4KVFB2T.js";
11
- import {
12
- paint
13
- } from "./chunk-WWNXR34K.js";
14
- import {
15
- t
16
- } from "./chunk-6ICJICVU.js";
17
-
18
- // src/commands/init.ts
19
- import { createHash } from "crypto";
20
- import { chmodSync, copyFileSync, existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, renameSync, statSync as statSync2, writeFileSync } from "fs";
21
- import { dirname, isAbsolute as isAbsolute2, join as join2, parse, resolve as resolve2 } from "path";
22
- import { fileURLToPath } from "url";
23
- import { defineCommand } from "citty";
24
-
25
- // src/scanner/forensic.ts
26
- import { existsSync, readdirSync, readFileSync, statSync } from "fs";
27
- import { basename, extname, isAbsolute, join, posix, relative, resolve, sep } from "path";
28
- import { forensicReportSchema } from "@fenglimg/fabric-shared";
29
- var IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([
30
- ".fabric",
31
- ".git",
32
- ".next",
33
- ".turbo",
34
- "Library",
35
- "Temp",
36
- "build",
37
- "coverage",
38
- "dist",
39
- "node_modules"
40
- ]);
41
- var KEY_DIRECTORY_NAMES = /* @__PURE__ */ new Set([
42
- "app",
43
- "components",
44
- "pages",
45
- "prefabs",
46
- "scenes",
47
- "scripts",
48
- "src"
49
- ]);
50
- var SCRIPT_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".jsx", ".ts", ".tsx"]);
51
- var SAMPLE_LIMIT = 5;
52
- var SAMPLE_LINE_LIMIT = 30;
53
- function buildForensicReport(targetInput) {
54
- const target = normalizeTarget(targetInput);
55
- const framework = detectFramework(target);
56
- const topology = buildTopology(target);
57
- const entryPoints = collectEntryPoints(topology.files);
58
- const readme = readReadmeInfo(target);
59
- const report = {
60
- version: "1.0",
61
- generated_at: (/* @__PURE__ */ new Date()).toISOString(),
62
- generated_by: `fab-cli@${getCliVersion()}`,
63
- target,
64
- project_name: readProjectName(target),
65
- framework,
66
- topology: {
67
- total_files: topology.total_files,
68
- by_ext: topology.by_ext,
69
- key_dirs: topology.key_dirs,
70
- max_depth: topology.max_depth
71
- },
72
- entry_points: entryPoints,
73
- code_samples: buildCodeSamples(target, entryPoints),
74
- readme,
75
- recommendations_for_skill: buildSkillRecommendations(framework.kind, topology, readme)
76
- };
77
- const validation = forensicReportSchema.safeParse(report);
78
- if (!validation.success) {
79
- throw new Error(`ForensicReport schema validation failed: ${validation.error.message}`);
80
- }
81
- return validation.data;
82
- }
83
- function normalizeTarget(targetInput) {
84
- return isAbsolute(targetInput) ? targetInput : resolve(process.cwd(), targetInput);
85
- }
86
- function buildTopology(root) {
87
- assertExistingDirectory(root);
88
- const byExt = {};
89
- const keyDirs = /* @__PURE__ */ new Set();
90
- const files = [];
91
- let totalFiles = 0;
92
- let maxDepth = 0;
93
- const stack = [root];
94
- while (stack.length > 0) {
95
- const current = stack.pop();
96
- if (current === void 0) {
97
- continue;
98
- }
99
- for (const entry of readdirSync(current, { withFileTypes: true })) {
100
- const absolutePath = join(current, entry.name);
101
- const relativePath = toPosixPath(relative(root, absolutePath));
102
- if (relativePath.length === 0) {
103
- continue;
104
- }
105
- const depth = relativePath.split("/").length;
106
- maxDepth = Math.max(maxDepth, depth);
107
- if (entry.isDirectory()) {
108
- if (IGNORED_DIRECTORIES.has(entry.name)) {
109
- continue;
110
- }
111
- if (isKeyDirectory(relativePath)) {
112
- keyDirs.add(relativePath);
113
- }
114
- stack.push(absolutePath);
115
- continue;
116
- }
117
- if (!entry.isFile()) {
118
- continue;
119
- }
120
- const stats = statSync(absolutePath);
121
- const extension = extname(entry.name) || "[none]";
122
- byExt[extension] = (byExt[extension] ?? 0) + 1;
123
- totalFiles += 1;
124
- files.push({
125
- relativePath,
126
- sizeBytes: stats.size
127
- });
128
- }
129
- }
130
- return {
131
- total_files: totalFiles,
132
- by_ext: sortRecord(byExt),
133
- key_dirs: [...keyDirs].sort(),
134
- max_depth: maxDepth,
135
- files: files.sort((left, right) => left.relativePath.localeCompare(right.relativePath))
136
- };
137
- }
138
- function assertExistingDirectory(target) {
139
- if (!existsSync(target) || !statSync(target).isDirectory()) {
140
- throw new Error(`Target must be an existing directory: ${target}`);
141
- }
142
- }
143
- function isKeyDirectory(relativePath) {
144
- const name = basename(relativePath);
145
- return KEY_DIRECTORY_NAMES.has(name);
146
- }
147
- function collectEntryPoints(files) {
148
- const entryPoints = [];
149
- for (const file of files) {
150
- const reason = getEntryPointReason(file.relativePath);
151
- if (reason === null) {
152
- continue;
153
- }
154
- entryPoints.push({
155
- path: file.relativePath,
156
- reason,
157
- size_bytes: file.sizeBytes
158
- });
159
- }
160
- return entryPoints;
161
- }
162
- function getEntryPointReason(relativePath) {
163
- if (!SCRIPT_EXTENSIONS.has(extname(relativePath))) {
164
- return null;
165
- }
166
- const directory = posix.dirname(relativePath);
167
- const fileName = basename(relativePath);
168
- const fileBase = basename(relativePath, extname(relativePath));
169
- if (directory === "assets/scripts" || directory === "scripts") {
170
- return "top-level script";
171
- }
172
- if (directory === "src" && /^(App|app|index|main)$/.test(fileBase)) {
173
- return "application entry";
174
- }
175
- if ((directory === "app" || directory.startsWith("app/")) && /^(layout|page|route)$/.test(fileBase)) {
176
- return "next app route";
177
- }
178
- if ((directory === "pages" || directory.startsWith("pages/")) && fileName !== "_app.d.ts") {
179
- return "next page route";
180
- }
181
- return null;
182
- }
183
- function buildCodeSamples(target, entryPoints) {
184
- return entryPoints.slice(0, SAMPLE_LIMIT).map((entryPoint) => {
185
- const absolutePath = join(target, ...entryPoint.path.split("/"));
186
- const sample = readFirstLines(absolutePath, SAMPLE_LINE_LIMIT);
187
- return {
188
- path: entryPoint.path,
189
- lines: `1-${sample.lineCount}`,
190
- snippet: sample.snippet,
191
- pattern_hint: inferPatternHint(entryPoint.path, sample.snippet)
192
- };
193
- });
194
- }
195
- function readFirstLines(path, lineLimit) {
196
- try {
197
- const lines = readFileSync(path, "utf8").split(/\r?\n/);
198
- if (lines.at(-1) === "") {
199
- lines.pop();
200
- }
201
- const sampledLines = lines.slice(0, lineLimit);
202
- return {
203
- snippet: sampledLines.join("\n"),
204
- lineCount: sampledLines.length
205
- };
206
- } catch {
207
- return {
208
- snippet: "",
209
- lineCount: 0
210
- };
211
- }
212
- }
213
- function inferPatternHint(relativePath, snippet) {
214
- if (snippet.includes("_decorator") || snippet.includes("extends Component")) {
215
- return "cocos-component-class";
216
- }
217
- if (snippet.includes("createRoot(") || snippet.includes("ReactDOM.render(")) {
218
- return "react-root";
219
- }
220
- if (relativePath.startsWith("app/") || relativePath.startsWith("pages/")) {
221
- return "next-route-component";
222
- }
223
- if (relativePath === "src/main.ts" || relativePath === "src/main.js") {
224
- return "vite-main-entry";
225
- }
226
- return "source-entry";
227
- }
228
- function readReadmeInfo(target) {
229
- const readmePath = join(target, "README.md");
230
- const hasContributing = existsSync(join(target, "CONTRIBUTING.md"));
231
- if (!existsSync(readmePath)) {
232
- return {
233
- quality: "missing",
234
- line_count: 0,
235
- has_contributing: hasContributing
236
- };
237
- }
238
- const readme = readFileSync(readmePath, "utf8");
239
- const wordCount = readme.trim().split(/\s+/).filter(Boolean).length;
240
- return {
241
- quality: wordCount >= 200 ? "ok" : "stub",
242
- line_count: readme.length === 0 ? 0 : readme.split(/\r?\n/).length,
243
- has_contributing: hasContributing
244
- };
245
- }
246
- function buildSkillRecommendations(frameworkKind, topology, readme) {
247
- const recommendations = [];
248
- if (frameworkKind === "cocos-creator") {
249
- recommendations.push("\u5EFA\u8BAE\u5411\u7528\u6237\u786E\u8BA4 Cocos Creator Component \u751F\u547D\u5468\u671F(onLoad/onEnable/start)\u987A\u5E8F\u3002");
250
- recommendations.push("\u5EFA\u8BAE\u8BE2\u95EE assets/prefabs \u548C assets/scenes \u662F\u5426\u5C5E\u4E8E @HUMAN \u4FDD\u62A4\u533A\u57DF\u3002");
251
- if ((topology.by_ext[".meta"] ?? 0) > 0) {
252
- recommendations.push("\u68C0\u6D4B\u5230 .meta \u6587\u4EF6,\u5EFA\u8BAE\u5728 @HUMAN \u9501\u5B9A .meta \u4E0D\u88AB AI \u6539\u52A8\u3002");
253
- }
254
- } else if (frameworkKind === "next") {
255
- recommendations.push("\u5EFA\u8BAE\u786E\u8BA4 app/pages \u8DEF\u7531\u8FB9\u754C\u548C\u670D\u52A1\u7AEF\u7EC4\u4EF6\u7EA6\u675F\u3002");
256
- } else if (frameworkKind === "vite") {
257
- recommendations.push("\u5EFA\u8BAE\u786E\u8BA4 src/main \u5165\u53E3\u3001\u7EC4\u4EF6\u76EE\u5F55\u548C\u6784\u5EFA\u811A\u672C\u7684\u7EF4\u62A4\u8FB9\u754C\u3002");
258
- } else if (frameworkKind === "unknown") {
259
- recommendations.push("\u672A\u68C0\u6D4B\u5230\u660E\u786E\u6846\u67B6,\u5EFA\u8BAE\u5148\u8BA9\u7528\u6237\u786E\u8BA4\u6280\u672F\u6808\u548C\u4E3B\u8981\u5165\u53E3\u3002");
260
- } else {
261
- recommendations.push(`\u5EFA\u8BAE\u56F4\u7ED5 ${frameworkKind} \u7684\u4E3B\u8981\u5165\u53E3\u548C\u751F\u6210\u76EE\u5F55\u786E\u8BA4 AGENTS.md \u5206\u5C42\u8FB9\u754C\u3002`);
262
- }
263
- if (readme.quality !== "ok") {
264
- recommendations.push("README \u4FE1\u606F\u4E0D\u8DB3,\u5EFA\u8BAE\u5728\u521D\u59CB\u5316\u8BBF\u8C08\u4E2D\u8865\u9F50\u9879\u76EE\u76EE\u6807\u3001\u8FD0\u884C\u65B9\u5F0F\u548C\u7981\u6539\u533A\u57DF\u3002");
265
- }
266
- return recommendations;
267
- }
268
- function readProjectName(target) {
269
- const packageJsonPath = join(target, "package.json");
270
- if (existsSync(packageJsonPath)) {
271
- try {
272
- const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
273
- if (packageJson.name !== void 0 && packageJson.name.trim().length > 0) {
274
- return packageJson.name;
275
- }
276
- } catch {
277
- return basename(target);
278
- }
279
- }
280
- return basename(target);
281
- }
282
- function getCliVersion() {
283
- return true ? "1.0.0" : "unknown";
284
- }
285
- function sortRecord(record) {
286
- return Object.fromEntries(Object.entries(record).sort(([left], [right]) => left.localeCompare(right)));
287
- }
288
- function toPosixPath(path) {
289
- return path.split(sep).join("/");
290
- }
291
-
292
- // src/commands/init.ts
293
- var AGENTS_TEMPLATE_BY_FRAMEWORK = {
294
- "cocos-creator": "templates/agents-md/variants/cocos.md",
295
- vite: "templates/agents-md/variants/vite.md",
296
- next: "templates/agents-md/variants/next.md"
297
- };
298
- var CLAUDE_INIT_SKILL_TEMPLATE = "templates/claude-skills/agents-md-init/SKILL.md";
299
- var CLAUDE_INIT_REMINDER_HOOK_TEMPLATE = "templates/claude-hooks/agents-md-init-reminder.cjs";
300
- var CLAUDE_INIT_REMINDER_COMMAND = ".claude/hooks/agents-md-init-reminder.cjs";
301
- var initCommand = defineCommand({
302
- meta: {
303
- name: "init",
304
- description: t("cli.init.description")
305
- },
306
- args: {
307
- target: {
308
- type: "string",
309
- description: t("cli.init.args.target.description")
310
- },
311
- debug: {
312
- type: "boolean",
313
- description: t("cli.init.args.debug.description"),
314
- default: false
315
- }
316
- },
317
- async run({ args }) {
318
- const logger = createDebugLogger(args.debug);
319
- const resolution = resolveDevMode(args.target, process.cwd());
320
- const target = normalizeTarget2(resolution.target);
321
- logger(`init target source: ${resolution.source}`);
322
- for (const step of resolution.chain) {
323
- logger(step);
324
- }
325
- const created = initFabric(target);
326
- console.log(t("cli.init.created-path", { label: createdLabel(), path: created.agentsPath }));
327
- console.log(t("cli.init.created-path", { label: createdLabel(), path: created.metaPath }));
328
- console.log(t("cli.init.created-path", { label: createdLabel(), path: created.humanLockPath }));
329
- console.log(t("cli.init.created-path", { label: createdLabel(), path: created.forensicPath }));
330
- writeStderr(
331
- created.claudeSkillAction === "created" ? t("cli.init.created-path", { label: createdLabel(), path: created.claudeSkillPath }) : t("cli.init.skipped-existing-path", { label: skippedLabel(), path: created.claudeSkillPath })
332
- );
333
- writeStderr(
334
- created.claudeHookAction === "created" ? t("cli.init.created-path", { label: createdLabel(), path: created.claudeHookPath }) : t("cli.init.skipped-existing-path", { label: skippedLabel(), path: created.claudeHookPath })
335
- );
336
- writeStderr(formatClaudeSettingsAction(created.claudeSettingsPath, created.claudeSettingsAction));
337
- console.log(
338
- t("cli.init.next-step", {
339
- label: nextLabel(),
340
- message: paint.muted(t("cli.init.next-step.message"))
341
- })
342
- );
343
- console.log(
344
- t("cli.init.reason-message", {
345
- label: reasonLabel(),
346
- message: paint.muted(t("cli.init.reason-message.body"))
347
- })
348
- );
349
- }
350
- });
351
- var init_default = initCommand;
352
- function initFabric(target) {
353
- assertExistingDirectory2(target);
354
- const agentsPath = join2(target, "AGENTS.md");
355
- const fabricDir = join2(target, ".fabric");
356
- const forensicPath = join2(fabricDir, "forensic.json");
357
- const claudeSkillPath = join2(target, ".claude", "skills", "agents-md-init", "SKILL.md");
358
- const claudeHookPath = join2(target, ".claude", "hooks", "agents-md-init-reminder.cjs");
359
- const claudeSettingsPath = join2(target, ".claude", "settings.json");
360
- if (existsSync2(forensicPath)) {
361
- throw new Error(`ABORT: ${forensicPath} already exists. fab init is non-destructive.`);
362
- }
363
- if (existsSync2(agentsPath)) {
364
- throw new Error(`ABORT: ${agentsPath} already exists. fab init is non-destructive.`);
365
- }
366
- if (existsSync2(fabricDir)) {
367
- throw new Error(`ABORT: ${fabricDir} already exists. fab init is non-destructive.`);
368
- }
369
- const scanReport = createScanReport(target);
370
- const forensicReport = buildForensicReport(target);
371
- const template = readFileSync2(findAgentsTemplatePath(scanReport.framework.kind), "utf8");
372
- const humanLockTemplate = readFileSync2(findTemplatePath("templates/fabric/human-lock.json"), "utf8");
373
- const packageName = readPackageName(target) ?? parse(target).base;
374
- const agentsContent = template.replaceAll("{ projectName }", packageName).replaceAll("{ frameworkKind }", scanReport.framework.kind);
375
- const agentsHash = sha256(agentsContent);
376
- const meta = createInitialMeta(agentsHash);
377
- const metaPath = join2(fabricDir, "agents.meta.json");
378
- const humanLockPath = join2(fabricDir, "human-lock.json");
379
- mkdirSync(fabricDir, { recursive: false });
380
- writeNewFile(agentsPath, agentsContent);
381
- writeNewFile(metaPath, `${JSON.stringify(meta, null, 2)}
382
- `);
383
- writeNewFile(humanLockPath, humanLockTemplate.endsWith("\n") ? humanLockTemplate : `${humanLockTemplate}
384
- `);
385
- writeNewFile(forensicPath, `${JSON.stringify(forensicReport, null, 2)}
386
- `);
387
- const claudeSkillAction = copyTemplateIfMissing(findTemplatePath(CLAUDE_INIT_SKILL_TEMPLATE), claudeSkillPath);
388
- const claudeHookAction = copyExecutableTemplateIfMissing(
389
- findTemplatePath(CLAUDE_INIT_REMINDER_HOOK_TEMPLATE),
390
- claudeHookPath
391
- );
392
- const claudeSettingsAction = mergeClaudeStopHook(claudeSettingsPath);
393
- return {
394
- agentsPath,
395
- metaPath,
396
- humanLockPath,
397
- forensicPath,
398
- claudeSkillPath,
399
- claudeSkillAction,
400
- claudeHookPath,
401
- claudeHookAction,
402
- claudeSettingsPath,
403
- claudeSettingsAction
404
- };
405
- }
406
- function findAgentsTemplatePath(frameworkKind) {
407
- const relativePath = AGENTS_TEMPLATE_BY_FRAMEWORK[frameworkKind] ?? "templates/agents-md/AGENTS.md.template";
408
- return findTemplatePath(relativePath);
409
- }
410
- function normalizeTarget2(targetInput) {
411
- return isAbsolute2(targetInput) ? targetInput : resolve2(process.cwd(), targetInput);
412
- }
413
- function assertExistingDirectory2(target) {
414
- if (!existsSync2(target) || !statSync2(target).isDirectory()) {
415
- throw new Error(`Target must be an existing directory: ${target}`);
416
- }
417
- }
418
- function createInitialMeta(agentsHash) {
419
- return {
420
- revision: sha256(agentsHash),
421
- nodes: {
422
- L0: {
423
- file: "AGENTS.md",
424
- scope_glob: "**",
425
- deps: [],
426
- priority: "high",
427
- hash: agentsHash
428
- }
429
- }
430
- };
431
- }
432
- function readPackageName(target) {
433
- const packageJsonPath = join2(target, "package.json");
434
- if (!existsSync2(packageJsonPath)) {
435
- return void 0;
436
- }
437
- try {
438
- const packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf8"));
439
- return packageJson.name;
440
- } catch {
441
- return void 0;
442
- }
443
- }
444
- function findTemplatePath(relativePath) {
445
- const currentModuleDir = dirname(fileURLToPath(import.meta.url));
446
- const candidates = [
447
- ...templateCandidatesFrom(process.cwd(), relativePath),
448
- ...templateCandidatesFrom(currentModuleDir, relativePath)
449
- ];
450
- for (const candidate of candidates) {
451
- if (existsSync2(candidate)) {
452
- return candidate;
453
- }
454
- }
455
- throw new Error(t("cli.shared.template-not-found", { path: relativePath }));
456
- }
457
- function templateCandidatesFrom(start, relativePath) {
458
- const candidates = [];
459
- let current = resolve2(start);
460
- while (true) {
461
- candidates.push(join2(current, ...relativePath.split("/")));
462
- const parent = dirname(current);
463
- if (parent === current || parse(current).root === current) {
464
- break;
465
- }
466
- current = parent;
467
- }
468
- return candidates.reverse();
469
- }
470
- function writeNewFile(path, content) {
471
- if (existsSync2(path)) {
472
- throw new Error(`ABORT: ${path} already exists. fab init is non-destructive.`);
473
- }
474
- writeFileSync(path, content, "utf8");
475
- }
476
- function copyTemplateIfMissing(templatePath, targetPath) {
477
- mkdirSync(dirname(targetPath), { recursive: true });
478
- if (existsSync2(targetPath)) {
479
- return "skipped";
480
- }
481
- copyFileSync(templatePath, targetPath);
482
- return "created";
483
- }
484
- function copyExecutableTemplateIfMissing(templatePath, targetPath) {
485
- const action = copyTemplateIfMissing(templatePath, targetPath);
486
- if (action === "created") {
487
- chmodSync(targetPath, 493);
488
- }
489
- return action;
490
- }
491
- function mergeClaudeStopHook(settingsPath) {
492
- mkdirSync(dirname(settingsPath), { recursive: true });
493
- let settings;
494
- let action = "updated";
495
- if (!existsSync2(settingsPath)) {
496
- settings = {};
497
- action = "created";
498
- } else {
499
- try {
500
- const parsed = JSON.parse(readFileSync2(settingsPath, "utf8"));
501
- if (!isRecord(parsed)) {
502
- writeStderr(t("cli.init.claude-settings.invalid-object", { label: skippedLabel(), path: settingsPath }));
503
- return "skipped-invalid";
504
- }
505
- settings = parsed;
506
- } catch (error) {
507
- const reason = error instanceof Error ? error.message : "unknown parse error";
508
- writeStderr(t("cli.init.claude-settings.invalid-json", { label: skippedLabel(), path: settingsPath, reason }));
509
- return "skipped-invalid";
510
- }
511
- }
512
- if (settings.hooks !== void 0 && !isRecord(settings.hooks)) {
513
- writeStderr(t("cli.init.claude-settings.invalid-hooks", { label: skippedLabel(), path: settingsPath }));
514
- return "skipped-invalid";
515
- }
516
- const hooks = settings.hooks ?? {};
517
- const stopHooksValue = hooks.Stop;
518
- if (stopHooksValue !== void 0 && !Array.isArray(stopHooksValue)) {
519
- writeStderr(t("cli.init.claude-settings.invalid-stop-array", { label: skippedLabel(), path: settingsPath }));
520
- return "skipped-invalid";
521
- }
522
- const stopHooks = Array.isArray(stopHooksValue) ? stopHooksValue : [];
523
- if (hasClaudeInitReminderHook(stopHooks)) {
524
- return "skipped";
525
- }
526
- stopHooks.push({
527
- matcher: "*",
528
- hooks: [
529
- {
530
- type: "command",
531
- command: CLAUDE_INIT_REMINDER_COMMAND
532
- }
533
- ]
534
- });
535
- settings.hooks = {
536
- ...hooks,
537
- Stop: stopHooks
538
- };
539
- writeJsonAtomically(settingsPath, settings);
540
- return action;
541
- }
542
- function hasClaudeInitReminderHook(stopHooks) {
543
- return stopHooks.some((entry) => {
544
- if (!isRecord(entry) || !Array.isArray(entry.hooks)) {
545
- return false;
546
- }
547
- return entry.hooks.some(
548
- (hook) => isRecord(hook) && hook.type === "command" && typeof hook.command === "string" && hook.command.includes("agents-md-init-reminder.cjs")
549
- );
550
- });
551
- }
552
- function writeJsonAtomically(path, value) {
553
- const tempPath = `${path}.${process.pid}.tmp`;
554
- writeFileSync(tempPath, `${JSON.stringify(value, null, 2)}
555
- `, "utf8");
556
- renameSync(tempPath, path);
557
- }
558
- function isRecord(value) {
559
- return typeof value === "object" && value !== null && !Array.isArray(value);
560
- }
561
- function formatClaudeSettingsAction(settingsPath, action) {
562
- switch (action) {
563
- case "created":
564
- return t("cli.init.claude-settings.created", { label: createdLabel(), path: settingsPath });
565
- case "updated":
566
- return t("cli.init.claude-settings.updated", { label: updatedLabel(), path: settingsPath });
567
- case "skipped":
568
- return t("cli.init.claude-settings.skipped", { label: skippedLabel(), path: settingsPath });
569
- case "skipped-invalid":
570
- return t("cli.init.claude-settings.skipped-invalid", { label: skippedLabel(), path: settingsPath });
571
- default:
572
- return t("cli.init.claude-settings.updated", { label: updatedLabel(), path: settingsPath });
573
- }
574
- }
575
- function createdLabel() {
576
- return paint.success(t("cli.shared.created"));
577
- }
578
- function skippedLabel() {
579
- return paint.muted(t("cli.shared.skipped"));
580
- }
581
- function nextLabel() {
582
- return paint.ai(t("cli.shared.next"));
583
- }
584
- function reasonLabel() {
585
- return paint.human(t("cli.shared.reason"));
586
- }
587
- function updatedLabel() {
588
- return paint.success(t("cli.shared.updated"));
589
- }
590
- function writeStderr(message) {
591
- process.stderr.write(`${message}
592
- `);
593
- }
594
- function sha256(content) {
595
- return `sha256:${createHash("sha256").update(content).digest("hex")}`;
596
- }
597
- export {
598
- init_default as default,
599
- initCommand,
600
- initFabric
601
- };
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- createDebugLogger,
4
- resolveDevMode
5
- } from "./chunk-AEOYCVBG.js";
6
2
  import {
7
3
  paint,
8
4
  symbol
9
5
  } from "./chunk-WWNXR34K.js";
6
+ import {
7
+ createDebugLogger,
8
+ resolveDevMode
9
+ } from "./chunk-AEOYCVBG.js";
10
10
  import {
11
11
  t
12
12
  } from "./chunk-6ICJICVU.js";