@fenglimg/fabric-cli 1.7.0 → 1.8.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{doctor-XP4OQOTX.js → doctor-F52XWWZC.js} +11 -5
- package/dist/index.js +4 -4
- package/dist/{init-WMB3WLXM.js → init-CAZN4S4T.js} +154 -178
- package/dist/{serve-7AXYKBIT.js → serve-466QXQ5Q.js} +14 -2
- package/package.json +5 -7
- package/templates/claude-hooks/{agents-md-init-reminder.cjs → fabric-init-reminder.cjs} +1 -1
- package/templates/claude-skills/fabric-init/SKILL.md +163 -0
- package/templates/codex-skills/fabric-init/SKILL.md +153 -18
- package/templates/skill-source/fabric-init/SOURCE.md +157 -0
- package/templates/skill-source/fabric-init/clients.json +17 -0
- package/templates/claude-skills/agents-md-init/SKILL.md +0 -86
|
@@ -14,18 +14,21 @@ import {
|
|
|
14
14
|
} from "./chunk-QPCRBQ5Y.js";
|
|
15
15
|
|
|
16
16
|
// src/commands/init.ts
|
|
17
|
-
import { createHash } from "crypto";
|
|
17
|
+
import { createHash, randomUUID } from "crypto";
|
|
18
18
|
import * as childProcess from "child_process";
|
|
19
|
-
import { chmodSync as chmodSync2, copyFileSync, existsSync as existsSync9, mkdirSync as mkdirSync3, readFileSync as readFileSync4,
|
|
19
|
+
import { appendFileSync, chmodSync as chmodSync2, copyFileSync, existsSync as existsSync9, mkdirSync as mkdirSync3, readdirSync as readdirSync2, readFileSync as readFileSync4, rmSync, statSync as statSync3, writeFileSync } from "fs";
|
|
20
20
|
import { dirname as dirname5, isAbsolute as isAbsolute4, join as join8, parse as parse3, resolve as resolve9 } from "path";
|
|
21
21
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
22
22
|
import { cancel, confirm, group, intro, isCancel, log, note, outro, select } from "@clack/prompts";
|
|
23
|
+
import { atomicWriteJson as atomicWriteJson3, atomicWriteText as atomicWriteText4 } from "@fenglimg/fabric-shared/node/atomic-write";
|
|
23
24
|
import { defineCommand as defineCommand4 } from "citty";
|
|
25
|
+
import { checkLockOrThrow } from "@fenglimg/fabric-server";
|
|
24
26
|
|
|
25
27
|
// src/bootstrap-guide.ts
|
|
26
|
-
import { existsSync, mkdirSync, readFileSync
|
|
28
|
+
import { existsSync, mkdirSync, readFileSync } from "fs";
|
|
27
29
|
import { dirname, isAbsolute, join, parse, resolve } from "path";
|
|
28
30
|
import { fileURLToPath } from "url";
|
|
31
|
+
import { atomicWriteText } from "@fenglimg/fabric-shared/node/atomic-write";
|
|
29
32
|
var AGENTS_TEMPLATE_BY_FRAMEWORK = {
|
|
30
33
|
"cocos-creator": "templates/agents-md/variants/cocos.md",
|
|
31
34
|
vite: "templates/agents-md/variants/vite.md",
|
|
@@ -47,7 +50,7 @@ async function ensureFabricBootstrapGuide(workspaceRoot, force) {
|
|
|
47
50
|
return;
|
|
48
51
|
}
|
|
49
52
|
mkdirSync(dirname(guidePath), { recursive: true });
|
|
50
|
-
|
|
53
|
+
await atomicWriteText(guidePath, await buildFabricBootstrapGuide(workspaceRoot));
|
|
51
54
|
}
|
|
52
55
|
function findBootstrapTemplatePath(frameworkKind) {
|
|
53
56
|
const relativePath = AGENTS_TEMPLATE_BY_FRAMEWORK[frameworkKind] ?? "templates/agents-md/AGENTS.md.template";
|
|
@@ -115,9 +118,10 @@ import { homedir as homedir2, platform } from "os";
|
|
|
115
118
|
|
|
116
119
|
// src/config/json.ts
|
|
117
120
|
import { existsSync as existsSync2 } from "fs";
|
|
118
|
-
import { mkdir, readFile
|
|
121
|
+
import { mkdir, readFile } from "fs/promises";
|
|
119
122
|
import { dirname as dirname2, join as join2, resolve as resolve2 } from "path";
|
|
120
123
|
import { homedir } from "os";
|
|
124
|
+
import { atomicWriteJson } from "@fenglimg/fabric-shared/node/atomic-write";
|
|
121
125
|
|
|
122
126
|
// src/config/writer.ts
|
|
123
127
|
function createServerEntry(serverPath) {
|
|
@@ -128,6 +132,19 @@ function createServerEntry(serverPath) {
|
|
|
128
132
|
}
|
|
129
133
|
|
|
130
134
|
// src/config/json.ts
|
|
135
|
+
function deepMerge(target, source) {
|
|
136
|
+
if (target === null || typeof target !== "object" || Array.isArray(target) || source === null || typeof source !== "object" || Array.isArray(source)) {
|
|
137
|
+
return source;
|
|
138
|
+
}
|
|
139
|
+
const out = { ...target };
|
|
140
|
+
for (const key of Object.keys(source)) {
|
|
141
|
+
out[key] = deepMerge(
|
|
142
|
+
target[key],
|
|
143
|
+
source[key]
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
131
148
|
function expandHome(filePath) {
|
|
132
149
|
if (filePath === "~") {
|
|
133
150
|
return homedir();
|
|
@@ -159,12 +176,10 @@ async function readJsonConfig(configPath) {
|
|
|
159
176
|
}
|
|
160
177
|
}
|
|
161
178
|
async function writeJsonClientConfig(configPath, serverEntry) {
|
|
162
|
-
const
|
|
163
|
-
const
|
|
164
|
-
config.mcpServers = existingServers !== null && typeof existingServers === "object" && !Array.isArray(existingServers) ? { ...existingServers, fabric: serverEntry } : { fabric: serverEntry };
|
|
179
|
+
const existing = await readJsonConfig(configPath);
|
|
180
|
+
const merged = deepMerge(existing, { mcpServers: { fabric: serverEntry } });
|
|
165
181
|
await mkdir(dirname2(configPath), { recursive: true });
|
|
166
|
-
await
|
|
167
|
-
`, "utf8");
|
|
182
|
+
await atomicWriteJson(configPath, merged, { indent: 2 });
|
|
168
183
|
}
|
|
169
184
|
var JsonClientConfigWriter = class {
|
|
170
185
|
configuredPath;
|
|
@@ -189,18 +204,21 @@ var JsonClientConfigWriter = class {
|
|
|
189
204
|
};
|
|
190
205
|
var ClaudeCodeCLIWriter = class extends JsonClientConfigWriter {
|
|
191
206
|
clientKind = "ClaudeCodeCLI";
|
|
192
|
-
|
|
207
|
+
scope;
|
|
208
|
+
constructor(configuredPath, scope = "project") {
|
|
193
209
|
super(configuredPath);
|
|
210
|
+
this.scope = scope;
|
|
194
211
|
}
|
|
195
|
-
// Writes to project-level .
|
|
196
|
-
//
|
|
212
|
+
// Writes to project-level .mcp.json (per Claude Code MCP spec) by default,
|
|
213
|
+
// or ~/.claude.json for user scope.
|
|
214
|
+
// Detection still checks ~/.claude to confirm Claude Code is installed.
|
|
197
215
|
defaultPath(workspaceRoot) {
|
|
198
216
|
const globalClaudeDir = join2(homedir(), ".claude");
|
|
199
217
|
const projectClaudeDir = join2(workspaceRoot, ".claude");
|
|
200
218
|
if (!existsSync2(globalClaudeDir) && !existsSync2(projectClaudeDir)) {
|
|
201
219
|
return null;
|
|
202
220
|
}
|
|
203
|
-
return join2(
|
|
221
|
+
return this.scope === "user" ? join2(homedir(), ".claude.json") : join2(workspaceRoot, ".mcp.json");
|
|
204
222
|
}
|
|
205
223
|
};
|
|
206
224
|
var CursorWriter = class extends JsonClientConfigWriter {
|
|
@@ -213,36 +231,6 @@ var CursorWriter = class extends JsonClientConfigWriter {
|
|
|
213
231
|
return existsSync2(cursorDir) ? join2(cursorDir, "mcp.json") : null;
|
|
214
232
|
}
|
|
215
233
|
};
|
|
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
234
|
|
|
247
235
|
// src/config/claude-code.ts
|
|
248
236
|
function getClaudeDesktopConfigPath() {
|
|
@@ -279,9 +267,10 @@ var ClaudeCodeDesktopWriter = class {
|
|
|
279
267
|
|
|
280
268
|
// src/config/toml.ts
|
|
281
269
|
import { existsSync as existsSync4 } from "fs";
|
|
282
|
-
import { mkdir as mkdir2, readFile as readFile2
|
|
270
|
+
import { mkdir as mkdir2, readFile as readFile2 } from "fs/promises";
|
|
283
271
|
import { dirname as dirname3, join as join4, resolve as resolve4 } from "path";
|
|
284
272
|
import { homedir as homedir3 } from "os";
|
|
273
|
+
import { atomicWriteText as atomicWriteText2 } from "@fenglimg/fabric-shared/node/atomic-write";
|
|
285
274
|
function expandHome2(filePath) {
|
|
286
275
|
if (filePath === "~") {
|
|
287
276
|
return homedir3();
|
|
@@ -366,7 +355,7 @@ var CodexTOMLConfigWriter = class {
|
|
|
366
355
|
const rawConfig = await readTomlConfigText(configPath);
|
|
367
356
|
const nextConfig = upsertCodexServerBlock(rawConfig, "fabric", createServerEntry(serverPath));
|
|
368
357
|
await mkdir2(dirname3(configPath), { recursive: true });
|
|
369
|
-
await
|
|
358
|
+
await atomicWriteText2(configPath, nextConfig);
|
|
370
359
|
}
|
|
371
360
|
};
|
|
372
361
|
|
|
@@ -380,13 +369,14 @@ function addIfDetected(writers, detected, createWriter, configuredPath) {
|
|
|
380
369
|
writers.push(createWriter(configuredPath));
|
|
381
370
|
}
|
|
382
371
|
}
|
|
383
|
-
function resolveClients(workspaceRoot, fabricConfig = {}) {
|
|
372
|
+
function resolveClients(workspaceRoot, fabricConfig = {}, opts = {}) {
|
|
384
373
|
const clientPaths = fabricConfig.clientPaths;
|
|
385
374
|
const writers = [];
|
|
375
|
+
const claudeMcpScope = opts.claudeMcpScope ?? "project";
|
|
386
376
|
addIfDetected(
|
|
387
377
|
writers,
|
|
388
378
|
existsSync5(join5(homedir4(), ".claude")) || existsSync5(join5(workspaceRoot, ".claude")),
|
|
389
|
-
(configuredPath) => new ClaudeCodeCLIWriter(configuredPath),
|
|
379
|
+
(configuredPath) => new ClaudeCodeCLIWriter(configuredPath, claudeMcpScope),
|
|
390
380
|
hasExplicitPath(clientPaths, "claudeCodeCLI") ? clientPaths.claudeCodeCLI : void 0
|
|
391
381
|
);
|
|
392
382
|
addIfDetected(
|
|
@@ -401,24 +391,6 @@ function resolveClients(workspaceRoot, fabricConfig = {}) {
|
|
|
401
391
|
(configuredPath) => new CursorWriter(configuredPath),
|
|
402
392
|
hasExplicitPath(clientPaths, "cursor") ? clientPaths.cursor : void 0
|
|
403
393
|
);
|
|
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
394
|
addIfDetected(
|
|
423
395
|
writers,
|
|
424
396
|
existsSync5(join5(homedir4(), ".codex")),
|
|
@@ -432,9 +404,6 @@ function detectClientSupports(workspaceRoot, fabricConfig = {}) {
|
|
|
432
404
|
const claudeDetected = existsSync5(join5(homedir4(), ".claude")) || existsSync5(join5(workspaceRoot, ".claude"));
|
|
433
405
|
const claudeDesktopDetected = existsSync5(getClaudeDesktopConfigPath());
|
|
434
406
|
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
407
|
const codexDetected = existsSync5(join5(homedir4(), ".codex"));
|
|
439
408
|
return [
|
|
440
409
|
{
|
|
@@ -480,45 +449,6 @@ function detectClientSupports(workspaceRoot, fabricConfig = {}) {
|
|
|
480
449
|
skill: false
|
|
481
450
|
}
|
|
482
451
|
},
|
|
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
452
|
{
|
|
523
453
|
clientKind: "CodexCLI",
|
|
524
454
|
label: "Codex CLI",
|
|
@@ -549,13 +479,6 @@ var CLIENT_ALIASES = {
|
|
|
549
479
|
claudedesktop: "claude",
|
|
550
480
|
claudecodedesktop: "claude",
|
|
551
481
|
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
482
|
codex: "codex",
|
|
560
483
|
"codex-cli": "codex",
|
|
561
484
|
codexcli: "codex"
|
|
@@ -662,12 +585,6 @@ function mapClientKind(clientKind) {
|
|
|
662
585
|
return "claude";
|
|
663
586
|
case "Cursor":
|
|
664
587
|
return "cursor";
|
|
665
|
-
case "Windsurf":
|
|
666
|
-
return "windsurf";
|
|
667
|
-
case "RooCode":
|
|
668
|
-
return "roo";
|
|
669
|
-
case "GeminiCLI":
|
|
670
|
-
return "gemini";
|
|
671
588
|
case "CodexCLI":
|
|
672
589
|
return "codex";
|
|
673
590
|
default:
|
|
@@ -680,12 +597,6 @@ function mapBootstrapClientToClientKind(client) {
|
|
|
680
597
|
return "ClaudeCodeCLI";
|
|
681
598
|
case "cursor":
|
|
682
599
|
return "Cursor";
|
|
683
|
-
case "windsurf":
|
|
684
|
-
return "Windsurf";
|
|
685
|
-
case "roo":
|
|
686
|
-
return "RooCode";
|
|
687
|
-
case "gemini":
|
|
688
|
-
return "GeminiCLI";
|
|
689
600
|
case "codex":
|
|
690
601
|
return "CodexCLI";
|
|
691
602
|
}
|
|
@@ -699,10 +610,11 @@ import { fileURLToPath as fileURLToPath3 } from "url";
|
|
|
699
610
|
import { defineCommand as defineCommand3 } from "citty";
|
|
700
611
|
|
|
701
612
|
// src/commands/hooks.ts
|
|
702
|
-
import { chmodSync, existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync2, statSync
|
|
613
|
+
import { chmodSync, existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync2, statSync } from "fs";
|
|
703
614
|
import { dirname as dirname4, isAbsolute as isAbsolute2, join as join6, parse as parse2, resolve as resolve6 } from "path";
|
|
704
615
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
705
616
|
import { defineCommand as defineCommand2 } from "citty";
|
|
617
|
+
import { atomicWriteJson as atomicWriteJson2, atomicWriteText as atomicWriteText3 } from "@fenglimg/fabric-shared/node/atomic-write";
|
|
706
618
|
var hooksCommand = defineCommand2({
|
|
707
619
|
meta: {
|
|
708
620
|
name: "hooks",
|
|
@@ -750,7 +662,7 @@ async function installHooks(target, options = {}) {
|
|
|
750
662
|
}
|
|
751
663
|
mkdirSync2(huskyDir, { recursive: true });
|
|
752
664
|
const templateContent = readFileSync2(findTemplatePath2("templates/husky/pre-commit"), "utf8");
|
|
753
|
-
const hookAction = installHookFile(hookPath, templateContent, options.force);
|
|
665
|
+
const hookAction = await installHookFile(hookPath, templateContent, options.force);
|
|
754
666
|
chmodSync(hookPath, 493);
|
|
755
667
|
const packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf8"));
|
|
756
668
|
const scripts = packageJson.scripts && typeof packageJson.scripts === "object" && !Array.isArray(packageJson.scripts) ? packageJson.scripts : {};
|
|
@@ -759,8 +671,7 @@ async function installHooks(target, options = {}) {
|
|
|
759
671
|
if (!hadPrepare) {
|
|
760
672
|
scripts.prepare = "husky install";
|
|
761
673
|
packageJson.scripts = scripts;
|
|
762
|
-
|
|
763
|
-
`, "utf8");
|
|
674
|
+
await atomicWriteJson2(packageJsonPath, packageJson);
|
|
764
675
|
prepareAction = "added";
|
|
765
676
|
}
|
|
766
677
|
const installed = [];
|
|
@@ -792,10 +703,10 @@ function assertExistingDirectory(target) {
|
|
|
792
703
|
throw new Error(t("cli.shared.target-invalid", { target }));
|
|
793
704
|
}
|
|
794
705
|
}
|
|
795
|
-
function installHookFile(hookPath, templateContent, force) {
|
|
706
|
+
async function installHookFile(hookPath, templateContent, force) {
|
|
796
707
|
if (existsSync6(hookPath)) {
|
|
797
708
|
if (force) {
|
|
798
|
-
|
|
709
|
+
await atomicWriteText3(hookPath, templateContent);
|
|
799
710
|
return "overwritten";
|
|
800
711
|
}
|
|
801
712
|
const existing = readFileSync2(hookPath, "utf8");
|
|
@@ -804,11 +715,11 @@ function installHookFile(hookPath, templateContent, force) {
|
|
|
804
715
|
}
|
|
805
716
|
const fabricBlock = templateContent.replace(/^#!\/bin\/sh\n/, "");
|
|
806
717
|
const separator = existing.endsWith("\n") ? "\n" : "\n\n";
|
|
807
|
-
|
|
808
|
-
${fabricBlock}
|
|
718
|
+
await atomicWriteText3(hookPath, `${existing}${separator}# --- Fabric ---
|
|
719
|
+
${fabricBlock}`);
|
|
809
720
|
return "appended";
|
|
810
721
|
}
|
|
811
|
-
|
|
722
|
+
await atomicWriteText3(hookPath, templateContent);
|
|
812
723
|
return "created";
|
|
813
724
|
}
|
|
814
725
|
function findTemplatePath2(relativePath) {
|
|
@@ -852,13 +763,6 @@ var CLIENT_ALIASES2 = {
|
|
|
852
763
|
"claude-code-desktop": "ClaudeCodeDesktop",
|
|
853
764
|
claudedesktop: "ClaudeCodeDesktop",
|
|
854
765
|
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
766
|
codexcli: "CodexCLI",
|
|
863
767
|
"codex-cli": "CodexCLI",
|
|
864
768
|
codex: "CodexCLI"
|
|
@@ -953,7 +857,7 @@ async function installMcpClients(target, options = {}) {
|
|
|
953
857
|
const fabricConfig = await loadFabricConfig(workspaceRoot);
|
|
954
858
|
const selectedClients = options.clients === void 0 ? null : new Set(options.clients);
|
|
955
859
|
const serverPath = resolveServerPath(options.localServerPath);
|
|
956
|
-
const writers = resolveClients(workspaceRoot, fabricConfig).filter(
|
|
860
|
+
const writers = resolveClients(workspaceRoot, fabricConfig, { claudeMcpScope: options.claudeMcpScope }).filter(
|
|
957
861
|
(writer) => selectedClients === null ? true : selectedClients.has(writer.clientKind)
|
|
958
862
|
);
|
|
959
863
|
const installed = [];
|
|
@@ -2088,7 +1992,7 @@ function readProjectName(target) {
|
|
|
2088
1992
|
return basename(target);
|
|
2089
1993
|
}
|
|
2090
1994
|
function getCliVersion() {
|
|
2091
|
-
return true ? "1.
|
|
1995
|
+
return true ? "1.8.0-rc.2" : "unknown";
|
|
2092
1996
|
}
|
|
2093
1997
|
function sortRecord(record) {
|
|
2094
1998
|
return Object.fromEntries(Object.entries(record).sort(([left], [right]) => left.localeCompare(right)));
|
|
@@ -2098,9 +2002,9 @@ function toPosixPath(path) {
|
|
|
2098
2002
|
}
|
|
2099
2003
|
|
|
2100
2004
|
// src/commands/init.ts
|
|
2101
|
-
var CLAUDE_INIT_SKILL_TEMPLATE = "templates/claude-skills/
|
|
2102
|
-
var CLAUDE_INIT_REMINDER_HOOK_TEMPLATE = "templates/claude-hooks/
|
|
2103
|
-
var CLAUDE_INIT_REMINDER_COMMAND = ".claude/hooks/
|
|
2005
|
+
var CLAUDE_INIT_SKILL_TEMPLATE = "templates/claude-skills/fabric-init/SKILL.md";
|
|
2006
|
+
var CLAUDE_INIT_REMINDER_HOOK_TEMPLATE = "templates/claude-hooks/fabric-init-reminder.cjs";
|
|
2007
|
+
var CLAUDE_INIT_REMINDER_COMMAND = ".claude/hooks/fabric-init-reminder.cjs";
|
|
2104
2008
|
var CODEX_INIT_SKILL_TEMPLATE = "templates/codex-skills/fabric-init/SKILL.md";
|
|
2105
2009
|
var CODEX_SESSION_START_HOOK_TEMPLATE = "templates/codex-hooks/fabric-session-start.cjs";
|
|
2106
2010
|
var CODEX_STOP_HOOK_TEMPLATE = "templates/codex-hooks/fabric-stop-reminder.cjs";
|
|
@@ -2168,6 +2072,10 @@ var initCommand = defineCommand4({
|
|
|
2168
2072
|
type: "string",
|
|
2169
2073
|
default: "global",
|
|
2170
2074
|
description: t("cli.init.mcp.install.prompt")
|
|
2075
|
+
},
|
|
2076
|
+
scope: {
|
|
2077
|
+
type: "string",
|
|
2078
|
+
description: t("cli.init.mcp.scope.description")
|
|
2171
2079
|
}
|
|
2172
2080
|
},
|
|
2173
2081
|
async run({ args }) {
|
|
@@ -2179,6 +2087,9 @@ async function runInitCommand(args) {
|
|
|
2179
2087
|
const logger = createDebugLogger(args.debug);
|
|
2180
2088
|
const resolution = resolveDevMode(args.target, process.cwd());
|
|
2181
2089
|
const intent = resolveInitCliIntent(args, resolution.target);
|
|
2090
|
+
if (args.reapply === true) {
|
|
2091
|
+
checkLockOrThrow(intent.target, { force: args.force });
|
|
2092
|
+
}
|
|
2182
2093
|
logger(`init target source: ${resolution.source}`);
|
|
2183
2094
|
for (const step of resolution.chain) {
|
|
2184
2095
|
logger(step);
|
|
@@ -2197,19 +2108,21 @@ async function runInitCommand(args) {
|
|
|
2197
2108
|
target: intent.target,
|
|
2198
2109
|
options: intent.options,
|
|
2199
2110
|
mcpInstallMode: intent.mcpInstallMode,
|
|
2111
|
+
claudeMcpScope: intent.claudeMcpScope,
|
|
2200
2112
|
interactive: intent.interactiveSummary && !intent.wizardEnabled,
|
|
2201
2113
|
supports
|
|
2202
2114
|
});
|
|
2203
2115
|
const plan = intent.wizardEnabled ? await resolveInitExecutionPlanWithWizard(basePlan, args, createDefaultInitWizardAdapter()) : basePlan;
|
|
2204
2116
|
if (plan === null) {
|
|
2205
|
-
|
|
2206
|
-
|
|
2117
|
+
process.exitCode = 130;
|
|
2118
|
+
return;
|
|
2207
2119
|
}
|
|
2208
2120
|
return executeInitExecutionPlan(plan);
|
|
2209
2121
|
}
|
|
2210
2122
|
function resolveInitCliIntent(args, targetInput) {
|
|
2211
2123
|
const target = normalizeTarget4(targetInput);
|
|
2212
2124
|
const mcpInstallMode = resolveMcpInstallMode(args["mcp-install"]);
|
|
2125
|
+
const claudeMcpScope = resolveClaudeMcpScope(args.scope);
|
|
2213
2126
|
const terminalInteractive = isInteractiveInit();
|
|
2214
2127
|
const planOnly = args.plan === true;
|
|
2215
2128
|
const reapply = args.reapply === true;
|
|
@@ -2225,21 +2138,34 @@ function resolveInitCliIntent(args, targetInput) {
|
|
|
2225
2138
|
target,
|
|
2226
2139
|
options,
|
|
2227
2140
|
mcpInstallMode,
|
|
2141
|
+
claudeMcpScope,
|
|
2228
2142
|
interactiveSummary: args.interactive !== false && terminalInteractive,
|
|
2229
2143
|
wizardEnabled: shouldUseInitWizard(args, terminalInteractive) && !planOnly
|
|
2230
2144
|
};
|
|
2231
2145
|
}
|
|
2146
|
+
function resolveClaudeMcpScope(raw) {
|
|
2147
|
+
if (raw === void 0 || raw === "project") {
|
|
2148
|
+
return "project";
|
|
2149
|
+
}
|
|
2150
|
+
if (raw === "user") {
|
|
2151
|
+
return "user";
|
|
2152
|
+
}
|
|
2153
|
+
writeStderr3(t("cli.init.mcp.scope.invalid", { value: raw }));
|
|
2154
|
+
return "project";
|
|
2155
|
+
}
|
|
2232
2156
|
async function buildInitExecutionPlan(input) {
|
|
2233
2157
|
const options = input.options ?? {};
|
|
2234
2158
|
const scaffold = await buildInitFabricPlan(input.target, options);
|
|
2235
2159
|
const supports = input.supports ?? detectClientSupports(input.target);
|
|
2236
2160
|
const mcpInstallMode = input.mcpInstallMode ?? "global";
|
|
2161
|
+
const claudeMcpScope = input.claudeMcpScope ?? "project";
|
|
2237
2162
|
const stages = [
|
|
2238
2163
|
{ name: "bootstrap", skipped: Boolean(options.skipBootstrap) },
|
|
2239
2164
|
{
|
|
2240
2165
|
name: "mcp",
|
|
2241
2166
|
skipped: Boolean(options.skipMcp),
|
|
2242
2167
|
installMode: mcpInstallMode,
|
|
2168
|
+
claudeMcpScope,
|
|
2243
2169
|
localServerPath: mcpInstallMode === "local" ? LOCAL_FABRIC_SERVER_PATH : void 0,
|
|
2244
2170
|
packageManager: mcpInstallMode === "local" ? detectPackageManager(input.target) : void 0
|
|
2245
2171
|
},
|
|
@@ -2249,6 +2175,7 @@ async function buildInitExecutionPlan(input) {
|
|
|
2249
2175
|
target: input.target,
|
|
2250
2176
|
options,
|
|
2251
2177
|
mcpInstallMode,
|
|
2178
|
+
claudeMcpScope,
|
|
2252
2179
|
interactive: input.interactive ?? false,
|
|
2253
2180
|
supports,
|
|
2254
2181
|
scaffold,
|
|
@@ -2288,7 +2215,7 @@ async function executeInitExecutionPlan(plan) {
|
|
|
2288
2215
|
case "preflight":
|
|
2289
2216
|
break;
|
|
2290
2217
|
case "scaffold":
|
|
2291
|
-
created = executeInitFabricPlan(plan.scaffold);
|
|
2218
|
+
created = await executeInitFabricPlan(plan.scaffold);
|
|
2292
2219
|
printInitScaffoldResult(created);
|
|
2293
2220
|
break;
|
|
2294
2221
|
case "bootstrap":
|
|
@@ -2319,12 +2246,12 @@ async function buildInitFabricPlan(target, options) {
|
|
|
2319
2246
|
const taxonomyPath = join8(fabricDir, "INITIAL_TAXONOMY.md");
|
|
2320
2247
|
const rulesDir = join8(fabricDir, "rules");
|
|
2321
2248
|
const eventsPath = join8(fabricDir, "events.jsonl");
|
|
2322
|
-
const claudeSkillPath = join8(target, ".claude", "skills", "
|
|
2249
|
+
const claudeSkillPath = join8(target, ".claude", "skills", "fabric-init", "SKILL.md");
|
|
2323
2250
|
const codexSkillPath = join8(target, ".agents", "skills", "fabric-init", "SKILL.md");
|
|
2324
2251
|
const codexSessionStartHookPath = join8(target, ".codex", "hooks", "fabric-session-start.cjs");
|
|
2325
2252
|
const codexStopHookPath = join8(target, ".codex", "hooks", "fabric-stop-reminder.cjs");
|
|
2326
2253
|
const codexHooksConfigPath = join8(target, ".codex", "hooks.json");
|
|
2327
|
-
const claudeHookPath = join8(target, ".claude", "hooks", "
|
|
2254
|
+
const claudeHookPath = join8(target, ".claude", "hooks", "fabric-init-reminder.cjs");
|
|
2328
2255
|
const claudeSettingsPath = join8(target, ".claude", "settings.json");
|
|
2329
2256
|
const metaPath = join8(fabricDir, "agents.meta.json");
|
|
2330
2257
|
const replaceFabricDir = shouldReplaceWritableDirectory(fabricDir, options);
|
|
@@ -2382,32 +2309,49 @@ async function buildInitFabricPlan(target, options) {
|
|
|
2382
2309
|
claudeSettings: buildClaudeSettingsWritePlan(claudeSettingsPath, options)
|
|
2383
2310
|
};
|
|
2384
2311
|
}
|
|
2385
|
-
function executeInitFabricPlan(plan) {
|
|
2312
|
+
async function executeInitFabricPlan(plan) {
|
|
2313
|
+
const isReapply = plan.options?.reapply === true;
|
|
2314
|
+
const existingRules = isReapply && existsSync9(plan.rulesDir) ? readdirSync2(plan.rulesDir).filter((f) => f.endsWith(".md")) : [];
|
|
2315
|
+
const preserveMeta = isReapply && existingRules.length > 0;
|
|
2386
2316
|
if (plan.replaceFabricDir) {
|
|
2387
2317
|
rmSync(plan.fabricDir, { force: true });
|
|
2388
2318
|
}
|
|
2389
2319
|
mkdirSync3(plan.fabricDir, { recursive: true });
|
|
2390
2320
|
mkdirSync3(dirname5(plan.bootstrapPath), { recursive: true });
|
|
2391
2321
|
preparePlannedPath(plan.bootstrapPath, plan.bootstrapAction);
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2322
|
+
await atomicWriteText4(plan.bootstrapPath, plan.bootstrapContent);
|
|
2323
|
+
if (!preserveMeta) {
|
|
2324
|
+
preparePlannedPath(plan.metaPath, plan.metaAction);
|
|
2325
|
+
await atomicWriteJson3(plan.metaPath, plan.meta);
|
|
2326
|
+
}
|
|
2396
2327
|
preparePlannedPath(plan.taxonomyPath, plan.taxonomyAction);
|
|
2397
|
-
|
|
2328
|
+
await atomicWriteText4(plan.taxonomyPath, ensureTrailingNewline2(plan.taxonomyContent));
|
|
2398
2329
|
mkdirSync3(plan.rulesDir, { recursive: true });
|
|
2399
|
-
|
|
2400
|
-
|
|
2330
|
+
if (isReapply) {
|
|
2331
|
+
if (!existsSync9(plan.eventsPath)) {
|
|
2332
|
+
mkdirSync3(dirname5(plan.eventsPath), { recursive: true });
|
|
2333
|
+
writeFileSync(plan.eventsPath, "", "utf8");
|
|
2334
|
+
}
|
|
2335
|
+
} else {
|
|
2336
|
+
preparePlannedPath(plan.eventsPath, plan.eventsAction);
|
|
2337
|
+
writeFileSync(plan.eventsPath, "", "utf8");
|
|
2338
|
+
}
|
|
2401
2339
|
preparePlannedPath(plan.forensicPath, plan.forensicAction);
|
|
2402
|
-
|
|
2403
|
-
`, "utf8");
|
|
2340
|
+
await atomicWriteJson3(plan.forensicPath, plan.forensicReport);
|
|
2404
2341
|
applyOptionalTemplateWritePlan(plan.claudeSkill);
|
|
2405
2342
|
applyOptionalTemplateWritePlan(plan.codexSkill);
|
|
2406
2343
|
applyOptionalTemplateWritePlan(plan.codexSessionStartHook);
|
|
2407
2344
|
applyOptionalTemplateWritePlan(plan.codexStopHook);
|
|
2408
|
-
applyJsonWritePlan(plan.codexHooksConfig);
|
|
2345
|
+
await applyJsonWritePlan(plan.codexHooksConfig);
|
|
2409
2346
|
applyOptionalTemplateWritePlan(plan.claudeHook);
|
|
2410
|
-
applyClaudeSettingsWritePlan(plan.claudeSettings);
|
|
2347
|
+
await applyClaudeSettingsWritePlan(plan.claudeSettings);
|
|
2348
|
+
if (isReapply) {
|
|
2349
|
+
appendReapplyLedgerEvent(plan.eventsPath, {
|
|
2350
|
+
preserved_ledger: true,
|
|
2351
|
+
preserved_meta: preserveMeta,
|
|
2352
|
+
rules_count: existingRules.length
|
|
2353
|
+
});
|
|
2354
|
+
}
|
|
2411
2355
|
return {
|
|
2412
2356
|
bootstrapPath: plan.bootstrapPath,
|
|
2413
2357
|
bootstrapAction: plan.bootstrapAction,
|
|
@@ -2436,7 +2380,7 @@ function executeInitFabricPlan(plan) {
|
|
|
2436
2380
|
};
|
|
2437
2381
|
}
|
|
2438
2382
|
async function initFabric(target, options) {
|
|
2439
|
-
return executeInitFabricPlan(await buildInitFabricPlan(target, options));
|
|
2383
|
+
return await executeInitFabricPlan(await buildInitFabricPlan(target, options));
|
|
2440
2384
|
}
|
|
2441
2385
|
function shouldUseInitWizard(args, terminalInteractive = isInteractiveInit()) {
|
|
2442
2386
|
return terminalInteractive && args.interactive !== false && args.yes !== true;
|
|
@@ -2447,6 +2391,7 @@ async function resolveInitExecutionPlanWithWizard(basePlan, args, wizardAdapter)
|
|
|
2447
2391
|
options: basePlan.options,
|
|
2448
2392
|
supports: basePlan.supports,
|
|
2449
2393
|
mcpInstallMode: basePlan.mcpInstallMode,
|
|
2394
|
+
claudeMcpScope: basePlan.claudeMcpScope,
|
|
2450
2395
|
lockedStages: collectLockedWizardStages(args)
|
|
2451
2396
|
});
|
|
2452
2397
|
if (selection === null) {
|
|
@@ -2461,6 +2406,7 @@ async function resolveInitExecutionPlanWithWizard(basePlan, args, wizardAdapter)
|
|
|
2461
2406
|
skipHooks: !selection.hooks
|
|
2462
2407
|
},
|
|
2463
2408
|
mcpInstallMode: selection.mcp ? selection.mcpInstallMode : basePlan.mcpInstallMode,
|
|
2409
|
+
claudeMcpScope: selection.claudeMcpScope,
|
|
2464
2410
|
interactive: false,
|
|
2465
2411
|
supports: basePlan.supports
|
|
2466
2412
|
});
|
|
@@ -2584,7 +2530,8 @@ async function executeInitStagePlan(plan, stageName) {
|
|
|
2584
2530
|
}
|
|
2585
2531
|
const result = await installMcpClients(plan.target, {
|
|
2586
2532
|
force: plan.options.force,
|
|
2587
|
-
localServerPath: stage.localServerPath
|
|
2533
|
+
localServerPath: stage.localServerPath,
|
|
2534
|
+
claudeMcpScope: stage.claudeMcpScope
|
|
2588
2535
|
});
|
|
2589
2536
|
if (result.details.length === 0) {
|
|
2590
2537
|
console.log(formatInitStageResult("mcp", "skipped", 0, 0, t("cli.config.install.no-configs")));
|
|
@@ -2681,12 +2628,12 @@ function buildCodexHooksConfigPlan(configPath, options) {
|
|
|
2681
2628
|
value: buildCodexHooksConfigValue()
|
|
2682
2629
|
};
|
|
2683
2630
|
}
|
|
2684
|
-
function applyJsonWritePlan(plan) {
|
|
2631
|
+
async function applyJsonWritePlan(plan) {
|
|
2685
2632
|
if (plan.action === "skipped") {
|
|
2686
2633
|
return;
|
|
2687
2634
|
}
|
|
2688
2635
|
mkdirSync3(dirname5(plan.path), { recursive: true });
|
|
2689
|
-
|
|
2636
|
+
await atomicWriteJson3(plan.path, plan.value);
|
|
2690
2637
|
}
|
|
2691
2638
|
function buildClaudeSettingsWritePlan(settingsPath, options) {
|
|
2692
2639
|
let settings;
|
|
@@ -2746,12 +2693,12 @@ function buildClaudeSettingsWritePlan(settingsPath, options) {
|
|
|
2746
2693
|
value: nextSettings
|
|
2747
2694
|
};
|
|
2748
2695
|
}
|
|
2749
|
-
function applyClaudeSettingsWritePlan(plan) {
|
|
2696
|
+
async function applyClaudeSettingsWritePlan(plan) {
|
|
2750
2697
|
if (plan.value === null) {
|
|
2751
2698
|
return;
|
|
2752
2699
|
}
|
|
2753
2700
|
mkdirSync3(dirname5(plan.path), { recursive: true });
|
|
2754
|
-
|
|
2701
|
+
await atomicWriteJson3(plan.path, plan.value);
|
|
2755
2702
|
}
|
|
2756
2703
|
function createDefaultInitWizardAdapter() {
|
|
2757
2704
|
return {
|
|
@@ -2799,6 +2746,14 @@ function createDefaultInitWizardAdapter() {
|
|
|
2799
2746
|
{ value: "local", label: "local", hint: t("cli.init.mcp.install.local") }
|
|
2800
2747
|
]
|
|
2801
2748
|
}) : context.mcpInstallMode,
|
|
2749
|
+
claudeMcpScope: async ({ results }) => results.mcp ? selectClaudeMcpScopeInGroup({
|
|
2750
|
+
message: t("cli.init.wizard.mcp-scope", { defaultValue: context.claudeMcpScope }),
|
|
2751
|
+
initialValue: context.claudeMcpScope,
|
|
2752
|
+
options: [
|
|
2753
|
+
{ value: "project", label: "project", hint: t("cli.init.mcp.scope.project") },
|
|
2754
|
+
{ value: "user", label: "user", hint: t("cli.init.mcp.scope.user") }
|
|
2755
|
+
]
|
|
2756
|
+
}) : context.claudeMcpScope,
|
|
2802
2757
|
hooks: async () => context.lockedStages.includes("hooks") ? false : confirmInGroup({
|
|
2803
2758
|
message: t("cli.init.wizard.stage.hooks", {
|
|
2804
2759
|
defaultValue: formatPromptDefault(!context.options.skipHooks)
|
|
@@ -2865,6 +2820,17 @@ async function selectMcpInstallModeInGroup(options) {
|
|
|
2865
2820
|
}
|
|
2866
2821
|
return result;
|
|
2867
2822
|
}
|
|
2823
|
+
async function selectClaudeMcpScopeInGroup(options) {
|
|
2824
|
+
const result = await select({
|
|
2825
|
+
message: options.message,
|
|
2826
|
+
initialValue: options.initialValue,
|
|
2827
|
+
options: options.options
|
|
2828
|
+
});
|
|
2829
|
+
if (isCancel(result)) {
|
|
2830
|
+
throw INIT_WIZARD_GROUP_CANCELLED;
|
|
2831
|
+
}
|
|
2832
|
+
return result;
|
|
2833
|
+
}
|
|
2868
2834
|
function collectLockedWizardStages(args) {
|
|
2869
2835
|
const lockedStages = [];
|
|
2870
2836
|
if (args.bootstrap === false) {
|
|
@@ -2957,6 +2923,21 @@ function createInitialMeta(agentsHash) {
|
|
|
2957
2923
|
}
|
|
2958
2924
|
};
|
|
2959
2925
|
}
|
|
2926
|
+
function appendReapplyLedgerEvent(eventsPath, payload) {
|
|
2927
|
+
const event = {
|
|
2928
|
+
kind: "fabric-event",
|
|
2929
|
+
id: `event:${randomUUID()}`,
|
|
2930
|
+
ts: Date.now(),
|
|
2931
|
+
schema_version: 1,
|
|
2932
|
+
event_type: "reapply_completed",
|
|
2933
|
+
preserved_ledger: payload.preserved_ledger,
|
|
2934
|
+
preserved_meta: payload.preserved_meta,
|
|
2935
|
+
rules_count: payload.rules_count
|
|
2936
|
+
};
|
|
2937
|
+
const line = `${JSON.stringify(event)}
|
|
2938
|
+
`;
|
|
2939
|
+
appendFileSync(eventsPath, line, "utf8");
|
|
2940
|
+
}
|
|
2960
2941
|
function buildInitialTaxonomyMarkdown(forensicReport) {
|
|
2961
2942
|
const frameworkInfo = forensicReport.framework;
|
|
2962
2943
|
const framework = [frameworkInfo?.kind ?? "unknown", frameworkInfo?.subkind ?? ""].filter((value) => value.trim() !== "").join(" / ") || "unknown";
|
|
@@ -3048,15 +3029,9 @@ function isClaudeInitReminderStopEntry(entry) {
|
|
|
3048
3029
|
return false;
|
|
3049
3030
|
}
|
|
3050
3031
|
return entry.hooks.some(
|
|
3051
|
-
(hook) => isRecord(hook) && hook.type === "command" && typeof hook.command === "string" && hook.command.includes("agents-md-init-reminder.cjs")
|
|
3032
|
+
(hook) => isRecord(hook) && hook.type === "command" && typeof hook.command === "string" && (hook.command.includes("fabric-init-reminder.cjs") || hook.command.includes("agents-md-init-reminder.cjs"))
|
|
3052
3033
|
);
|
|
3053
3034
|
}
|
|
3054
|
-
function writeJsonAtomically(path, value) {
|
|
3055
|
-
const tempPath = `${path}.${process.pid}.tmp`;
|
|
3056
|
-
writeFileSync3(tempPath, `${JSON.stringify(value, null, 2)}
|
|
3057
|
-
`, "utf8");
|
|
3058
|
-
renameSync(tempPath, path);
|
|
3059
|
-
}
|
|
3060
3035
|
function isRecord(value) {
|
|
3061
3036
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3062
3037
|
}
|
|
@@ -3311,5 +3286,6 @@ export {
|
|
|
3311
3286
|
initCommand,
|
|
3312
3287
|
initFabric,
|
|
3313
3288
|
resolveInitExecutionPlanWithWizard,
|
|
3289
|
+
runInitCommand,
|
|
3314
3290
|
shouldUseInitWizard
|
|
3315
3291
|
};
|