@fenglimg/fabric-cli 1.2.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -22
- package/dist/{bootstrap-IUL4SAAK.js → bootstrap-3PUKUYTY.js} +4 -2
- package/dist/{chunk-N4DCTOXW.js → chunk-AZRKMFRY.js} +6 -6
- package/dist/{chunk-F2BXHPM5.js → chunk-N7EZORJZ.js} +9 -1
- package/dist/{chunk-6UUPKSDE.js → chunk-Q4LOVXML.js} +13 -8
- package/dist/{chunk-RUQCZA2Q.js → chunk-TKTWHAKV.js} +92 -115
- package/dist/{chunk-VMYPJPKV.js → chunk-VOQKQ6W2.js} +153 -21
- package/dist/{chunk-MDI7523D.js → chunk-XFSQM3LJ.js} +5 -1
- package/dist/{config-3JBB77TX.js → config-GINBGANU.js} +3 -2
- package/dist/index.js +11 -22
- package/dist/{init-3FPLOABB.js → init-T3LGMGAO.js} +170 -54
- package/dist/{ledger-append-XZ5SX4O5.js → ledger-append-DULKJ6Q2.js} +1 -1
- package/dist/pre-commit-IK6SJOPT.js +97 -0
- package/dist/{scan-WKDSKEBB.js → scan-43R3IBLR.js} +2 -2
- package/dist/{sync-meta-THZSEM7Y.js → sync-meta-LKVSO6TS.js} +1 -1
- package/dist/update-AN3FYF2O.js +116 -0
- package/package.json +4 -3
- package/templates/agents-md/AGENTS.md.template +14 -13
- package/templates/agents-md/variants/cocos.md +20 -20
- package/templates/agents-md/variants/next.md +20 -20
- package/templates/agents-md/variants/vite.md +20 -20
- package/templates/bootstrap/CLAUDE.md +3 -5
- package/templates/bootstrap/GEMINI.md +3 -5
- package/templates/bootstrap/codex-AGENTS-header.md +3 -5
- package/templates/bootstrap/cursor-fabric-bootstrap.mdc +11 -11
- package/templates/bootstrap/roo-fabric.md +6 -6
- package/templates/bootstrap/windsurf-fabric.md +6 -6
- package/templates/claude-hooks/agents-md-init-reminder.cjs +18 -18
- package/templates/claude-skills/agents-md-init/SKILL.md +86 -86
- package/templates/fabric/human-lock.json +12 -12
- package/templates/husky/pre-commit +24 -24
- package/dist/pre-commit-CJ7EDKJK.js +0 -59
- package/dist/{doctor-5KJGOV2P.js → doctor-QTSG2RWF.js} +3 -3
- package/dist/{serve-MMN4GYLM.js → serve-4J2CQY25.js} +4 -4
package/dist/index.js
CHANGED
|
@@ -8,28 +8,17 @@ import { defineCommand, runMain } from "citty";
|
|
|
8
8
|
|
|
9
9
|
// src/commands/index.ts
|
|
10
10
|
var allCommands = {
|
|
11
|
-
init: () => import("./init-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
init: () => import("./init-T3LGMGAO.js").then((module) => module.default),
|
|
12
|
+
update: () => import("./update-AN3FYF2O.js").then((module) => module.default),
|
|
13
|
+
scan: () => import("./scan-43R3IBLR.js").then((module) => module.default),
|
|
14
|
+
serve: () => import("./serve-4J2CQY25.js").then((module) => module.default),
|
|
15
|
+
doctor: () => import("./doctor-QTSG2RWF.js").then((module) => module.default),
|
|
16
|
+
"sync-meta": () => import("./sync-meta-LKVSO6TS.js").then((module) => module.default),
|
|
16
17
|
"human-lint": () => import("./human-lint-YSFOZHZ7.js").then((module) => module.default),
|
|
17
|
-
"ledger-append": () => import("./ledger-append-
|
|
18
|
-
"pre-commit": () => import("./pre-commit-
|
|
19
|
-
bootstrap: () => import("./bootstrap-
|
|
20
|
-
|
|
21
|
-
meta: {
|
|
22
|
-
...module.default.meta,
|
|
23
|
-
hidden: true
|
|
24
|
-
}
|
|
25
|
-
})),
|
|
26
|
-
config: () => import("./config-3JBB77TX.js").then((module) => ({
|
|
27
|
-
...module.configCmd,
|
|
28
|
-
meta: {
|
|
29
|
-
...module.configCmd.meta,
|
|
30
|
-
hidden: true
|
|
31
|
-
}
|
|
32
|
-
})),
|
|
18
|
+
"ledger-append": () => import("./ledger-append-DULKJ6Q2.js").then((module) => module.default),
|
|
19
|
+
"pre-commit": () => import("./pre-commit-IK6SJOPT.js").then((module) => module.default),
|
|
20
|
+
bootstrap: () => import("./bootstrap-3PUKUYTY.js").then((module) => module.default),
|
|
21
|
+
config: () => import("./config-GINBGANU.js").then((module) => module.configCmd),
|
|
33
22
|
hooks: () => import("./hooks-ZSWVH2JD.js").then((module) => ({
|
|
34
23
|
...module.default,
|
|
35
24
|
meta: {
|
|
@@ -43,7 +32,7 @@ var allCommands = {
|
|
|
43
32
|
var main = defineCommand({
|
|
44
33
|
meta: {
|
|
45
34
|
name: "fabric",
|
|
46
|
-
version: "1.
|
|
35
|
+
version: "1.3.1",
|
|
47
36
|
description: 'Initialize and manage Fabric projects. Use "fabric init" for one-shot setup.'
|
|
48
37
|
},
|
|
49
38
|
subCommands: allCommands
|
|
@@ -1,25 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
buildFabricBootstrapGuide,
|
|
3
4
|
installBootstrap
|
|
4
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-TKTWHAKV.js";
|
|
6
|
+
import {
|
|
7
|
+
detectFramework
|
|
8
|
+
} from "./chunk-AZRKMFRY.js";
|
|
5
9
|
import {
|
|
6
10
|
installMcpClients
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import
|
|
11
|
+
} from "./chunk-XFSQM3LJ.js";
|
|
12
|
+
import {
|
|
13
|
+
detectClientSupports
|
|
14
|
+
} from "./chunk-VOQKQ6W2.js";
|
|
9
15
|
import {
|
|
10
16
|
installHooks
|
|
11
17
|
} from "./chunk-YDZJRLHL.js";
|
|
12
|
-
import {
|
|
13
|
-
createScanReport,
|
|
14
|
-
detectFramework
|
|
15
|
-
} from "./chunk-N4DCTOXW.js";
|
|
16
|
-
import {
|
|
17
|
-
paint
|
|
18
|
-
} from "./chunk-WWNXR34K.js";
|
|
19
18
|
import {
|
|
20
19
|
createDebugLogger,
|
|
21
20
|
resolveDevMode
|
|
22
21
|
} from "./chunk-AEOYCVBG.js";
|
|
22
|
+
import {
|
|
23
|
+
displayWidth,
|
|
24
|
+
padEnd,
|
|
25
|
+
paint
|
|
26
|
+
} from "./chunk-WWNXR34K.js";
|
|
23
27
|
import {
|
|
24
28
|
t
|
|
25
29
|
} from "./chunk-6ICJICVU.js";
|
|
@@ -852,7 +856,7 @@ function readProjectName(target) {
|
|
|
852
856
|
return basename(target);
|
|
853
857
|
}
|
|
854
858
|
function getCliVersion() {
|
|
855
|
-
return true ? "1.
|
|
859
|
+
return true ? "1.3.1" : "unknown";
|
|
856
860
|
}
|
|
857
861
|
function sortRecord(record) {
|
|
858
862
|
return Object.fromEntries(Object.entries(record).sort(([left], [right]) => left.localeCompare(right)));
|
|
@@ -862,11 +866,6 @@ function toPosixPath(path) {
|
|
|
862
866
|
}
|
|
863
867
|
|
|
864
868
|
// src/commands/init.ts
|
|
865
|
-
var AGENTS_TEMPLATE_BY_FRAMEWORK = {
|
|
866
|
-
"cocos-creator": "templates/agents-md/variants/cocos.md",
|
|
867
|
-
vite: "templates/agents-md/variants/vite.md",
|
|
868
|
-
next: "templates/agents-md/variants/next.md"
|
|
869
|
-
};
|
|
870
869
|
var CLAUDE_INIT_SKILL_TEMPLATE = "templates/claude-skills/agents-md-init/SKILL.md";
|
|
871
870
|
var CLAUDE_INIT_REMINDER_HOOK_TEMPLATE = "templates/claude-hooks/agents-md-init-reminder.cjs";
|
|
872
871
|
var CLAUDE_INIT_REMINDER_COMMAND = ".claude/hooks/agents-md-init-reminder.cjs";
|
|
@@ -907,6 +906,11 @@ var initCommand = defineCommand({
|
|
|
907
906
|
default: true,
|
|
908
907
|
negativeDescription: t("cli.init.args.no-hooks.description")
|
|
909
908
|
},
|
|
909
|
+
interactive: {
|
|
910
|
+
type: "boolean",
|
|
911
|
+
description: t("cli.init.args.interactive.description"),
|
|
912
|
+
default: true
|
|
913
|
+
},
|
|
910
914
|
"mcp-install": {
|
|
911
915
|
type: "string",
|
|
912
916
|
default: "global",
|
|
@@ -928,11 +932,16 @@ var initCommand = defineCommand({
|
|
|
928
932
|
for (const step of resolution.chain) {
|
|
929
933
|
logger(step);
|
|
930
934
|
}
|
|
935
|
+
const supports = detectClientSupports(target);
|
|
936
|
+
const interactive = args.interactive !== false && isInteractiveInit();
|
|
931
937
|
if (options.force) {
|
|
932
938
|
writeStderr(t("cli.init.force.warning", { path: target }));
|
|
933
939
|
}
|
|
940
|
+
if (interactive) {
|
|
941
|
+
printInitPlanSummary(target, options, mcpInstallMode, supports);
|
|
942
|
+
}
|
|
934
943
|
const created = initFabric(target, options);
|
|
935
|
-
console.log(formatInitPathAction(created.
|
|
944
|
+
console.log(formatInitPathAction(created.bootstrapPath, created.bootstrapAction));
|
|
936
945
|
console.log(formatInitPathAction(created.metaPath, created.metaAction));
|
|
937
946
|
console.log(formatInitPathAction(created.humanLockPath, created.humanLockAction));
|
|
938
947
|
console.log(formatInitPathAction(created.forensicPath, created.forensicAction));
|
|
@@ -1020,37 +1029,37 @@ var initCommand = defineCommand({
|
|
|
1020
1029
|
console.log(
|
|
1021
1030
|
t("cli.init.reason-message", {
|
|
1022
1031
|
label: reasonLabel(),
|
|
1023
|
-
message: paint.muted(
|
|
1032
|
+
message: paint.muted(formatInitReasonMessage(supports))
|
|
1024
1033
|
})
|
|
1025
1034
|
);
|
|
1026
1035
|
printInitStageSummary(stageResults);
|
|
1036
|
+
printInitCapabilitySummary(supports, stageResults, options);
|
|
1027
1037
|
}
|
|
1028
1038
|
});
|
|
1029
1039
|
var init_default = initCommand;
|
|
1030
1040
|
function initFabric(target, options) {
|
|
1031
1041
|
assertExistingDirectory2(target);
|
|
1032
|
-
const agentsPath = join2(target, "AGENTS.md");
|
|
1033
1042
|
const fabricDir = join2(target, ".fabric");
|
|
1043
|
+
const bootstrapPath = join2(fabricDir, "bootstrap", "README.md");
|
|
1034
1044
|
const forensicPath = join2(fabricDir, "forensic.json");
|
|
1035
1045
|
const claudeSkillPath = join2(target, ".claude", "skills", "agents-md-init", "SKILL.md");
|
|
1036
1046
|
const claudeHookPath = join2(target, ".claude", "hooks", "agents-md-init-reminder.cjs");
|
|
1037
1047
|
const claudeSettingsPath = join2(target, ".claude", "settings.json");
|
|
1038
|
-
const forensicGuardAction = prepareFreshPath(forensicPath, options);
|
|
1039
|
-
const agentsAction = prepareFreshPath(agentsPath, options);
|
|
1040
|
-
const fabricDirAction = prepareFreshPath(fabricDir, options);
|
|
1041
|
-
const forensicAction = forensicGuardAction === "overwritten" || fabricDirAction === "overwritten" ? "overwritten" : "created";
|
|
1042
|
-
const scanReport = createScanReport(target);
|
|
1043
|
-
const forensicReport = buildForensicReport(target);
|
|
1044
|
-
const template = readFileSync2(findAgentsTemplatePath(scanReport.framework.kind), "utf8");
|
|
1045
|
-
const humanLockTemplate = readFileSync2(findTemplatePath("templates/fabric/human-lock.json"), "utf8");
|
|
1046
|
-
const packageName = readPackageName(target) ?? parse(target).base;
|
|
1047
|
-
const agentsContent = template.replaceAll("{ projectName }", packageName).replaceAll("{ frameworkKind }", scanReport.framework.kind);
|
|
1048
|
-
const agentsHash = sha256(agentsContent);
|
|
1049
|
-
const meta = createInitialMeta(agentsHash);
|
|
1050
1048
|
const metaPath = join2(fabricDir, "agents.meta.json");
|
|
1051
1049
|
const humanLockPath = join2(fabricDir, "human-lock.json");
|
|
1052
|
-
|
|
1053
|
-
|
|
1050
|
+
prepareWritableDirectory(fabricDir, options);
|
|
1051
|
+
const bootstrapAction = prepareFreshPath(bootstrapPath, options);
|
|
1052
|
+
const metaAction = prepareFreshPath(metaPath, options);
|
|
1053
|
+
const humanLockAction = prepareFreshPath(humanLockPath, options);
|
|
1054
|
+
const forensicAction = prepareFreshPath(forensicPath, options);
|
|
1055
|
+
const forensicReport = buildForensicReport(target);
|
|
1056
|
+
const humanLockTemplate = readFileSync2(findTemplatePath("templates/fabric/human-lock.json"), "utf8");
|
|
1057
|
+
const bootstrapContent = buildFabricBootstrapGuide(target);
|
|
1058
|
+
const bootstrapHash = sha256(bootstrapContent);
|
|
1059
|
+
const meta = createInitialMeta(bootstrapHash);
|
|
1060
|
+
mkdirSync(fabricDir, { recursive: true });
|
|
1061
|
+
mkdirSync(dirname(bootstrapPath), { recursive: true });
|
|
1062
|
+
writeNewFile(bootstrapPath, bootstrapContent, options);
|
|
1054
1063
|
writeNewFile(metaPath, `${JSON.stringify(meta, null, 2)}
|
|
1055
1064
|
`, options);
|
|
1056
1065
|
writeNewFile(humanLockPath, humanLockTemplate.endsWith("\n") ? humanLockTemplate : `${humanLockTemplate}
|
|
@@ -1065,12 +1074,12 @@ function initFabric(target, options) {
|
|
|
1065
1074
|
);
|
|
1066
1075
|
const claudeSettingsAction = mergeClaudeStopHook(claudeSettingsPath, options);
|
|
1067
1076
|
return {
|
|
1068
|
-
|
|
1069
|
-
|
|
1077
|
+
bootstrapPath,
|
|
1078
|
+
bootstrapAction,
|
|
1070
1079
|
metaPath,
|
|
1071
|
-
metaAction
|
|
1080
|
+
metaAction,
|
|
1072
1081
|
humanLockPath,
|
|
1073
|
-
humanLockAction
|
|
1082
|
+
humanLockAction,
|
|
1074
1083
|
forensicPath,
|
|
1075
1084
|
forensicAction,
|
|
1076
1085
|
claudeSkillPath,
|
|
@@ -1081,10 +1090,6 @@ function initFabric(target, options) {
|
|
|
1081
1090
|
claudeSettingsAction
|
|
1082
1091
|
};
|
|
1083
1092
|
}
|
|
1084
|
-
function findAgentsTemplatePath(frameworkKind) {
|
|
1085
|
-
const relativePath = AGENTS_TEMPLATE_BY_FRAMEWORK[frameworkKind] ?? "templates/agents-md/AGENTS.md.template";
|
|
1086
|
-
return findTemplatePath(relativePath);
|
|
1087
|
-
}
|
|
1088
1093
|
function normalizeTarget2(targetInput) {
|
|
1089
1094
|
return isAbsolute2(targetInput) ? targetInput : resolve2(process.cwd(), targetInput);
|
|
1090
1095
|
}
|
|
@@ -1126,7 +1131,7 @@ function createInitialMeta(agentsHash) {
|
|
|
1126
1131
|
revision: sha256(agentsHash),
|
|
1127
1132
|
nodes: {
|
|
1128
1133
|
L0: {
|
|
1129
|
-
file: "
|
|
1134
|
+
file: ".fabric/bootstrap/README.md",
|
|
1130
1135
|
scope_glob: "**",
|
|
1131
1136
|
deps: [],
|
|
1132
1137
|
priority: "high",
|
|
@@ -1137,18 +1142,6 @@ function createInitialMeta(agentsHash) {
|
|
|
1137
1142
|
}
|
|
1138
1143
|
};
|
|
1139
1144
|
}
|
|
1140
|
-
function readPackageName(target) {
|
|
1141
|
-
const packageJsonPath = join2(target, "package.json");
|
|
1142
|
-
if (!existsSync2(packageJsonPath)) {
|
|
1143
|
-
return void 0;
|
|
1144
|
-
}
|
|
1145
|
-
try {
|
|
1146
|
-
const packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf8"));
|
|
1147
|
-
return packageJson.name;
|
|
1148
|
-
} catch {
|
|
1149
|
-
return void 0;
|
|
1150
|
-
}
|
|
1151
|
-
}
|
|
1152
1145
|
function findTemplatePath(relativePath) {
|
|
1153
1146
|
const currentModuleDir = dirname(fileURLToPath(import.meta.url));
|
|
1154
1147
|
const candidates = [
|
|
@@ -1185,6 +1178,15 @@ function prepareFreshPath(path, options) {
|
|
|
1185
1178
|
rmSync(path, { recursive: true, force: true });
|
|
1186
1179
|
return "overwritten";
|
|
1187
1180
|
}
|
|
1181
|
+
function prepareWritableDirectory(path, options) {
|
|
1182
|
+
if (!existsSync2(path) || statSync2(path).isDirectory()) {
|
|
1183
|
+
return;
|
|
1184
|
+
}
|
|
1185
|
+
if (!options?.force) {
|
|
1186
|
+
throw new Error(t("cli.init.errors.abort-existing", { path }));
|
|
1187
|
+
}
|
|
1188
|
+
rmSync(path, { force: true });
|
|
1189
|
+
}
|
|
1188
1190
|
function writeNewFile(path, content, options) {
|
|
1189
1191
|
const existed = existsSync2(path);
|
|
1190
1192
|
if (existed && !options?.force) {
|
|
@@ -1329,6 +1331,120 @@ function collectInitStageNames(stageResults, disposition) {
|
|
|
1329
1331
|
function shouldPrintHooksNextStep(options, stageResults) {
|
|
1330
1332
|
return Boolean(options.skipHooks) || stageResults.some((stage) => stage.name === "hooks" && stage.disposition === "failed");
|
|
1331
1333
|
}
|
|
1334
|
+
function isInteractiveInit() {
|
|
1335
|
+
return Boolean(process.stdout.isTTY) && Boolean(process.stderr.isTTY);
|
|
1336
|
+
}
|
|
1337
|
+
function printInitPlanSummary(target, options, mcpInstallMode, supports) {
|
|
1338
|
+
console.log(t("cli.init.plan.title"));
|
|
1339
|
+
console.log(t("cli.init.plan.target", { target }));
|
|
1340
|
+
console.log(
|
|
1341
|
+
t("cli.init.plan.actions", {
|
|
1342
|
+
bootstrap: yesNoLabel(!options.skipBootstrap),
|
|
1343
|
+
mcp: yesNoLabel(!options.skipMcp),
|
|
1344
|
+
hooks: yesNoLabel(!options.skipHooks),
|
|
1345
|
+
mcpInstall: mcpInstallMode
|
|
1346
|
+
})
|
|
1347
|
+
);
|
|
1348
|
+
const detected = supports.filter((support) => support.detected);
|
|
1349
|
+
console.log(
|
|
1350
|
+
t("cli.init.plan.detected", {
|
|
1351
|
+
clients: detected.length > 0 ? detected.map((support) => support.label).join(", ") : t("cli.shared.none")
|
|
1352
|
+
})
|
|
1353
|
+
);
|
|
1354
|
+
console.log(t("cli.init.plan.writes"));
|
|
1355
|
+
console.log(` - ${target}/.fabric/bootstrap/README.md`);
|
|
1356
|
+
console.log(` - ${target}/.fabric/agents.meta.json`);
|
|
1357
|
+
console.log(` - ${target}/.fabric/human-lock.json`);
|
|
1358
|
+
console.log(` - ${target}/.fabric/forensic.json`);
|
|
1359
|
+
}
|
|
1360
|
+
function printInitCapabilitySummary(supports, stageResults, options) {
|
|
1361
|
+
const detected = supports.filter((support) => support.detected);
|
|
1362
|
+
if (detected.length === 0) {
|
|
1363
|
+
console.log(t("cli.init.capabilities.none"));
|
|
1364
|
+
return;
|
|
1365
|
+
}
|
|
1366
|
+
console.log(t("cli.init.capabilities.title"));
|
|
1367
|
+
const rows = detected.map((support) => toCapabilityRow(support, stageResults, options));
|
|
1368
|
+
const headers = {
|
|
1369
|
+
client: t("cli.init.capabilities.header.client"),
|
|
1370
|
+
bootstrap: t("cli.init.capabilities.header.bootstrap"),
|
|
1371
|
+
mcp: t("cli.init.capabilities.header.mcp"),
|
|
1372
|
+
hook: t("cli.init.capabilities.header.hook"),
|
|
1373
|
+
skill: t("cli.init.capabilities.header.skill"),
|
|
1374
|
+
followUp: t("cli.init.capabilities.header.follow-up")
|
|
1375
|
+
};
|
|
1376
|
+
const widths = {
|
|
1377
|
+
client: Math.max(displayWidth(headers.client), ...rows.map((row) => displayWidth(row.client))),
|
|
1378
|
+
bootstrap: Math.max(displayWidth(headers.bootstrap), ...rows.map((row) => displayWidth(row.bootstrap))),
|
|
1379
|
+
mcp: Math.max(displayWidth(headers.mcp), ...rows.map((row) => displayWidth(row.mcp))),
|
|
1380
|
+
hook: Math.max(displayWidth(headers.hook), ...rows.map((row) => displayWidth(row.hook))),
|
|
1381
|
+
skill: Math.max(displayWidth(headers.skill), ...rows.map((row) => displayWidth(row.skill))),
|
|
1382
|
+
followUp: Math.max(displayWidth(headers.followUp), ...rows.map((row) => displayWidth(row.followUp)))
|
|
1383
|
+
};
|
|
1384
|
+
console.log(formatCapabilityTableRow(headers, widths));
|
|
1385
|
+
console.log(formatCapabilityDivider(widths));
|
|
1386
|
+
for (const row of rows) {
|
|
1387
|
+
console.log(formatCapabilityTableRow(row, widths));
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
function toCapabilityRow(support, stageResults, options) {
|
|
1391
|
+
const stage = (name) => stageResults.find((entry) => entry.name === name)?.disposition ?? null;
|
|
1392
|
+
const bootstrap = support.capabilities.bootstrap ? capabilityStatus(options.skipBootstrap ? "skipped" : stage("bootstrap")) : t("cli.init.capabilities.status.na");
|
|
1393
|
+
const mcp = support.capabilities.mcp ? capabilityStatus(options.skipMcp ? "skipped" : stage("mcp")) : t("cli.init.capabilities.status.na");
|
|
1394
|
+
const hook = support.capabilities.hook ? capabilityStatus("ran") : t("cli.init.capabilities.status.na");
|
|
1395
|
+
const skill = support.capabilities.skill ? t("cli.init.capabilities.status.installed") : t("cli.init.capabilities.status.manual");
|
|
1396
|
+
return {
|
|
1397
|
+
client: support.label,
|
|
1398
|
+
bootstrap,
|
|
1399
|
+
mcp,
|
|
1400
|
+
hook,
|
|
1401
|
+
skill,
|
|
1402
|
+
followUp: support.capabilities.skill ? t("cli.init.capabilities.follow-up.ready") : t("cli.init.capabilities.follow-up.manual")
|
|
1403
|
+
};
|
|
1404
|
+
}
|
|
1405
|
+
function capabilityStatus(disposition) {
|
|
1406
|
+
switch (disposition) {
|
|
1407
|
+
case "ran":
|
|
1408
|
+
return t("cli.init.capabilities.status.ready");
|
|
1409
|
+
case "skipped":
|
|
1410
|
+
return t("cli.init.capabilities.status.skipped");
|
|
1411
|
+
case "failed":
|
|
1412
|
+
return t("cli.init.capabilities.status.failed");
|
|
1413
|
+
case null:
|
|
1414
|
+
return t("cli.init.capabilities.status.na");
|
|
1415
|
+
default:
|
|
1416
|
+
return t("cli.init.capabilities.status.ready");
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
function formatCapabilityTableRow(row, widths) {
|
|
1420
|
+
return [
|
|
1421
|
+
padEnd(row.client, widths.client),
|
|
1422
|
+
padEnd(row.bootstrap, widths.bootstrap),
|
|
1423
|
+
padEnd(row.mcp, widths.mcp),
|
|
1424
|
+
padEnd(row.hook, widths.hook),
|
|
1425
|
+
padEnd(row.skill, widths.skill),
|
|
1426
|
+
padEnd(row.followUp, widths.followUp)
|
|
1427
|
+
].join(" ");
|
|
1428
|
+
}
|
|
1429
|
+
function formatCapabilityDivider(widths) {
|
|
1430
|
+
return [
|
|
1431
|
+
"".padEnd(widths.client, "-"),
|
|
1432
|
+
"".padEnd(widths.bootstrap, "-"),
|
|
1433
|
+
"".padEnd(widths.mcp, "-"),
|
|
1434
|
+
"".padEnd(widths.hook, "-"),
|
|
1435
|
+
"".padEnd(widths.skill, "-"),
|
|
1436
|
+
"".padEnd(widths.followUp, "-")
|
|
1437
|
+
].join(" ");
|
|
1438
|
+
}
|
|
1439
|
+
function formatInitReasonMessage(supports) {
|
|
1440
|
+
if (supports.some((support) => support.detected && support.capabilities.skill)) {
|
|
1441
|
+
return t("cli.init.reason-message.body");
|
|
1442
|
+
}
|
|
1443
|
+
return t("cli.init.reason-message.manual-body");
|
|
1444
|
+
}
|
|
1445
|
+
function yesNoLabel(value) {
|
|
1446
|
+
return value ? t("cli.shared.yes") : t("cli.shared.no");
|
|
1447
|
+
}
|
|
1332
1448
|
function formatInitPathAction(path, action) {
|
|
1333
1449
|
return t("cli.init.created-path", { label: labelForInitWriteAction(action), path });
|
|
1334
1450
|
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
sync_meta_default
|
|
4
|
+
} from "./chunk-Q4LOVXML.js";
|
|
5
|
+
import {
|
|
6
|
+
human_lint_default
|
|
7
|
+
} from "./chunk-L43IGJ6X.js";
|
|
8
|
+
import {
|
|
9
|
+
ledger_append_default
|
|
10
|
+
} from "./chunk-N7EZORJZ.js";
|
|
11
|
+
import {
|
|
12
|
+
resolveDevModeTarget
|
|
13
|
+
} from "./chunk-AEOYCVBG.js";
|
|
14
|
+
import "./chunk-WWNXR34K.js";
|
|
15
|
+
import {
|
|
16
|
+
t
|
|
17
|
+
} from "./chunk-6ICJICVU.js";
|
|
18
|
+
|
|
19
|
+
// src/commands/pre-commit.ts
|
|
20
|
+
import { execSync } from "child_process";
|
|
21
|
+
import { readFileSync } from "fs";
|
|
22
|
+
import { join } from "path";
|
|
23
|
+
import process from "process";
|
|
24
|
+
import { agentsMetaSchema } from "@fenglimg/fabric-shared";
|
|
25
|
+
import { defineCommand } from "citty";
|
|
26
|
+
import { minimatch } from "minimatch";
|
|
27
|
+
async function runOrFail(name, cmd, args) {
|
|
28
|
+
try {
|
|
29
|
+
await cmd.run?.({ args });
|
|
30
|
+
} catch (err) {
|
|
31
|
+
process.stderr.write(
|
|
32
|
+
`${t("cli.pre-commit.run-failed", { name, message: err.message })}
|
|
33
|
+
`
|
|
34
|
+
);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function getStagedFiles(target) {
|
|
39
|
+
try {
|
|
40
|
+
const output = execSync("git diff --cached --name-only --no-renames", {
|
|
41
|
+
cwd: target,
|
|
42
|
+
encoding: "utf8",
|
|
43
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
44
|
+
});
|
|
45
|
+
return output.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
46
|
+
} catch {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function tryReadAgentsMeta(target) {
|
|
51
|
+
const metaPath = join(target, ".fabric", "agents.meta.json");
|
|
52
|
+
try {
|
|
53
|
+
const raw = readFileSync(metaPath, "utf8");
|
|
54
|
+
return agentsMetaSchema.parse(JSON.parse(raw));
|
|
55
|
+
} catch {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function matchesFabricScope(stagedFiles, meta) {
|
|
60
|
+
const scopeGlobs = Object.values(meta.nodes).filter((node) => node.file !== ".fabric/bootstrap/README.md" && node.file !== "AGENTS.md").map((node) => node.scope_glob);
|
|
61
|
+
return stagedFiles.some(
|
|
62
|
+
(file) => file === ".fabric/bootstrap/README.md" || file === "AGENTS.md" || file === ".fabric/agents.meta.json" || file === ".fabric/human-lock.json" || file === ".intent-ledger.jsonl" || scopeGlobs.some((pattern) => minimatch(file, pattern, { dot: true }))
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
var pre_commit_default = defineCommand({
|
|
66
|
+
meta: {
|
|
67
|
+
name: "pre-commit",
|
|
68
|
+
description: t("cli.pre-commit.description")
|
|
69
|
+
},
|
|
70
|
+
args: {
|
|
71
|
+
target: {
|
|
72
|
+
type: "string",
|
|
73
|
+
description: t("cli.pre-commit.args.target.description")
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
async run({ args }) {
|
|
77
|
+
const target = resolveDevModeTarget(args.target);
|
|
78
|
+
const stagedFiles = getStagedFiles(target);
|
|
79
|
+
const meta = tryReadAgentsMeta(target);
|
|
80
|
+
if (stagedFiles.length > 0 && meta !== null && !matchesFabricScope(stagedFiles, meta)) {
|
|
81
|
+
process.stderr.write("No fabric-managed files staged, skipping checks\n");
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
await runOrFail("sync-meta --check-only", sync_meta_default, {
|
|
85
|
+
target,
|
|
86
|
+
"check-only": true
|
|
87
|
+
});
|
|
88
|
+
await runOrFail("human-lint", human_lint_default, { target });
|
|
89
|
+
await runOrFail("ledger-append --staged", ledger_append_default, {
|
|
90
|
+
target,
|
|
91
|
+
staged: true
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
export {
|
|
96
|
+
pre_commit_default as default
|
|
97
|
+
};
|
|
@@ -3,9 +3,9 @@ import {
|
|
|
3
3
|
createScanReport,
|
|
4
4
|
scanCommand,
|
|
5
5
|
scan_default
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-WWNXR34K.js";
|
|
6
|
+
} from "./chunk-AZRKMFRY.js";
|
|
8
7
|
import "./chunk-AEOYCVBG.js";
|
|
8
|
+
import "./chunk-WWNXR34K.js";
|
|
9
9
|
import "./chunk-6ICJICVU.js";
|
|
10
10
|
export {
|
|
11
11
|
createScanReport,
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
installMcpClients
|
|
4
|
+
} from "./chunk-XFSQM3LJ.js";
|
|
5
|
+
import "./chunk-VOQKQ6W2.js";
|
|
6
|
+
import {
|
|
7
|
+
installHooks
|
|
8
|
+
} from "./chunk-YDZJRLHL.js";
|
|
9
|
+
import {
|
|
10
|
+
resolveDevModeTarget
|
|
11
|
+
} from "./chunk-AEOYCVBG.js";
|
|
12
|
+
import {
|
|
13
|
+
paint
|
|
14
|
+
} from "./chunk-WWNXR34K.js";
|
|
15
|
+
import {
|
|
16
|
+
t
|
|
17
|
+
} from "./chunk-6ICJICVU.js";
|
|
18
|
+
|
|
19
|
+
// src/commands/update.ts
|
|
20
|
+
import { defineCommand } from "citty";
|
|
21
|
+
function writeStderr(message) {
|
|
22
|
+
process.stderr.write(`${message}
|
|
23
|
+
`);
|
|
24
|
+
}
|
|
25
|
+
function completedLabel() {
|
|
26
|
+
return paint.success(t("cli.init.stages.completed"));
|
|
27
|
+
}
|
|
28
|
+
function skippedLabel() {
|
|
29
|
+
return paint.muted(t("cli.init.stages.skipped"));
|
|
30
|
+
}
|
|
31
|
+
function failedLabel() {
|
|
32
|
+
return paint.error(t("cli.init.stages.failed"));
|
|
33
|
+
}
|
|
34
|
+
function formatStageResult(stage, status, installedCount, skippedCount, note) {
|
|
35
|
+
const label = status === "completed" ? completedLabel() : skippedLabel();
|
|
36
|
+
const counts = `installed=${installedCount} skipped=${skippedCount}`;
|
|
37
|
+
const suffix = note ? ` ${paint.muted(`(${note})`)}` : "";
|
|
38
|
+
return `${label} ${stage}: ${counts}${suffix}`;
|
|
39
|
+
}
|
|
40
|
+
function formatStageFailure(stage, error) {
|
|
41
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
42
|
+
return `${failedLabel()} ${stage}: ${message}`;
|
|
43
|
+
}
|
|
44
|
+
function printStageSummary(stageResults) {
|
|
45
|
+
const ran = stageResults.filter((s) => s.disposition === "ran").map((s) => s.name);
|
|
46
|
+
const skipped = stageResults.filter((s) => s.disposition === "skipped").map((s) => s.name);
|
|
47
|
+
const failed = stageResults.filter((s) => s.disposition === "failed").map((s) => s.name);
|
|
48
|
+
console.log(`${paint.success(t("cli.init.stages.summary.ran"))}: ${ran.length > 0 ? ran.join(", ") : t("cli.shared.none")}`);
|
|
49
|
+
console.log(`${paint.muted(t("cli.init.stages.summary.skipped"))}: ${skipped.length > 0 ? skipped.join(", ") : t("cli.shared.none")}`);
|
|
50
|
+
console.log(`${paint.error(t("cli.init.stages.summary.failed"))}: ${failed.length > 0 ? failed.join(", ") : t("cli.shared.none")}`);
|
|
51
|
+
}
|
|
52
|
+
var updateCommand = defineCommand({
|
|
53
|
+
meta: {
|
|
54
|
+
name: "update",
|
|
55
|
+
description: t("cli.update.description")
|
|
56
|
+
},
|
|
57
|
+
args: {
|
|
58
|
+
target: {
|
|
59
|
+
type: "string",
|
|
60
|
+
description: t("cli.update.args.target.description")
|
|
61
|
+
},
|
|
62
|
+
mcp: {
|
|
63
|
+
type: "boolean",
|
|
64
|
+
default: true,
|
|
65
|
+
negativeDescription: t("cli.update.args.no-mcp.description")
|
|
66
|
+
},
|
|
67
|
+
hooks: {
|
|
68
|
+
type: "boolean",
|
|
69
|
+
default: true,
|
|
70
|
+
negativeDescription: t("cli.update.args.no-hooks.description")
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
async run({ args }) {
|
|
74
|
+
const target = resolveDevModeTarget(args.target);
|
|
75
|
+
const skipMcp = args.mcp === false;
|
|
76
|
+
const skipHooks = args.hooks === false;
|
|
77
|
+
const stageResults = [];
|
|
78
|
+
if (skipMcp) {
|
|
79
|
+
stageResults.push({ name: "mcp", disposition: "skipped" });
|
|
80
|
+
} else {
|
|
81
|
+
console.log(`${paint.ai(t("cli.shared.next"))} ${paint.muted(t("cli.init.stages.mcp"))}`);
|
|
82
|
+
try {
|
|
83
|
+
const result = await installMcpClients(target);
|
|
84
|
+
if (result.details.length === 0) {
|
|
85
|
+
console.log(formatStageResult("mcp", "skipped", 0, 0, t("cli.config.install.no-configs")));
|
|
86
|
+
stageResults.push({ name: "mcp", disposition: "skipped" });
|
|
87
|
+
} else {
|
|
88
|
+
console.log(formatStageResult("mcp", "completed", result.installed.length, result.skipped.length));
|
|
89
|
+
stageResults.push({ name: "mcp", disposition: "ran" });
|
|
90
|
+
}
|
|
91
|
+
} catch (error) {
|
|
92
|
+
writeStderr(formatStageFailure("mcp", error));
|
|
93
|
+
stageResults.push({ name: "mcp", disposition: "failed" });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (skipHooks) {
|
|
97
|
+
stageResults.push({ name: "hooks", disposition: "skipped" });
|
|
98
|
+
} else {
|
|
99
|
+
console.log(`${paint.ai(t("cli.shared.next"))} ${paint.muted(t("cli.init.stages.hooks"))}`);
|
|
100
|
+
try {
|
|
101
|
+
const result = await installHooks(target);
|
|
102
|
+
console.log(formatStageResult("hooks", "completed", result.installed.length, result.skipped.length));
|
|
103
|
+
stageResults.push({ name: "hooks", disposition: "ran" });
|
|
104
|
+
} catch (error) {
|
|
105
|
+
writeStderr(formatStageFailure("hooks", error));
|
|
106
|
+
stageResults.push({ name: "hooks", disposition: "failed" });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
printStageSummary(stageResults);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
var update_default = updateCommand;
|
|
113
|
+
export {
|
|
114
|
+
update_default as default,
|
|
115
|
+
updateCommand
|
|
116
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fenglimg/fabric-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"fab": "dist/index.js",
|
|
@@ -15,10 +15,11 @@
|
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@iarna/toml": "^2.2.5",
|
|
17
17
|
"citty": "^0.2.2",
|
|
18
|
+
"minimatch": "^10.0.1",
|
|
18
19
|
"picocolors": "^1.1.1",
|
|
19
20
|
"string-width": "^7.2.0",
|
|
20
|
-
"@fenglimg/fabric-shared": "1.
|
|
21
|
-
"@fenglimg/fabric-server": "1.
|
|
21
|
+
"@fenglimg/fabric-shared": "1.3.1",
|
|
22
|
+
"@fenglimg/fabric-server": "1.3.1"
|
|
22
23
|
},
|
|
23
24
|
"devDependencies": {
|
|
24
25
|
"@types/iarna__toml": "^2.0.5",
|