@fenglimg/fabric-cli 1.6.0 → 1.8.0-rc.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 +8 -14
- package/dist/{chunk-QSAEGVKE.js → chunk-NMMUETVK.js} +4 -8
- package/dist/{chunk-AEOYCVBG.js → chunk-QPCRBQ5Y.js} +52 -5
- package/dist/doctor-F52XWWZC.js +98 -0
- package/dist/index.js +5 -20
- package/dist/{init-LBVOI2QI.js → init-AEO5JU7R.js} +1084 -167
- package/dist/{scan-QH76LC7Z.js → scan-NNBNGIZG.js} +2 -4
- package/dist/{serve-4J2CQY25.js → serve-466QXQ5Q.js} +17 -9
- package/package.json +5 -7
- package/templates/agents-md/AGENTS.md.template +7 -7
- package/templates/agents-md/variants/cocos.md +7 -7
- package/templates/agents-md/variants/next.md +7 -7
- package/templates/agents-md/variants/vite.md +7 -7
- package/templates/bootstrap/CLAUDE.md +3 -1
- package/templates/bootstrap/GEMINI.md +3 -1
- package/templates/bootstrap/codex-AGENTS-header.md +3 -1
- package/templates/bootstrap/cursor-fabric-bootstrap.mdc +5 -6
- package/templates/bootstrap/roo-fabric.md +5 -6
- package/templates/bootstrap/windsurf-fabric.md +5 -6
- package/templates/claude-skills/fabric-init/SKILL.md +163 -0
- package/templates/codex-skills/fabric-init/SKILL.md +153 -18
- package/templates/husky/pre-commit +9 -24
- package/templates/skill-source/fabric-init/SOURCE.md +157 -0
- package/templates/skill-source/fabric-init/clients.json +17 -0
- package/dist/approve-YT4DEABS.js +0 -138
- package/dist/bootstrap-VGL3AR26.js +0 -16
- package/dist/chunk-2YW5CJ32.js +0 -147
- package/dist/chunk-6ICJICVU.js +0 -10
- package/dist/chunk-BEKSXO5N.js +0 -442
- package/dist/chunk-BVTMVW5M.js +0 -159
- package/dist/chunk-KOAEIH72.js +0 -270
- package/dist/chunk-L43IGJ6X.js +0 -106
- package/dist/chunk-T2WJF5I3.js +0 -254
- package/dist/chunk-WWNXR34K.js +0 -49
- package/dist/chunk-YDZJRLHL.js +0 -155
- package/dist/config-EC5L2QNI.js +0 -16
- package/dist/doctor-4BPYHV7V.js +0 -134
- package/dist/hooks-ZSWVH2JD.js +0 -12
- package/dist/human-lint-YSFOZHZ7.js +0 -13
- package/dist/ledger-append-3MDNR3GU.js +0 -10
- package/dist/pre-commit-53ENJDRZ.js +0 -98
- package/dist/sync-meta-IZR2WLIL.js +0 -16
- package/dist/update-M5M5PYKE.js +0 -116
- package/templates/claude-skills/agents-md-init/SKILL.md +0 -86
- package/templates/fabric/human-lock.json +0 -12
package/dist/chunk-KOAEIH72.js
DELETED
|
@@ -1,270 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
t
|
|
4
|
-
} from "./chunk-6ICJICVU.js";
|
|
5
|
-
|
|
6
|
-
// src/commands/sync-meta.ts
|
|
7
|
-
import { createHash } from "crypto";
|
|
8
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "fs";
|
|
9
|
-
import { isAbsolute, join, relative, resolve, sep } from "path";
|
|
10
|
-
import {
|
|
11
|
-
agentsMetaSchema,
|
|
12
|
-
deriveAgentsMetaLayer,
|
|
13
|
-
deriveAgentsMetaStableId,
|
|
14
|
-
deriveAgentsMetaTopologyType
|
|
15
|
-
} from "@fenglimg/fabric-shared";
|
|
16
|
-
import { defineCommand } from "citty";
|
|
17
|
-
var syncMetaCommand = defineCommand({
|
|
18
|
-
meta: {
|
|
19
|
-
name: "sync-meta",
|
|
20
|
-
description: t("cli.sync-meta.description")
|
|
21
|
-
},
|
|
22
|
-
args: {
|
|
23
|
-
target: {
|
|
24
|
-
type: "string",
|
|
25
|
-
description: t("cli.sync-meta.args.target.description"),
|
|
26
|
-
default: process.cwd()
|
|
27
|
-
},
|
|
28
|
-
"check-only": {
|
|
29
|
-
type: "boolean",
|
|
30
|
-
description: t("cli.sync-meta.args.check-only.description"),
|
|
31
|
-
default: false
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
async run({ args }) {
|
|
35
|
-
const target = normalizeTarget(args.target);
|
|
36
|
-
const metaPath = join(target, ".fabric", "agents.meta.json");
|
|
37
|
-
const computedMeta = computeAgentsMeta(target);
|
|
38
|
-
const existingMeta = readExistingMeta(metaPath);
|
|
39
|
-
if (args["check-only"]) {
|
|
40
|
-
if (!existingMeta || stableStringify(existingMeta) !== stableStringify(computedMeta)) {
|
|
41
|
-
writeStderr(t("cli.sync-meta.drift-detected"));
|
|
42
|
-
process.exitCode = 1;
|
|
43
|
-
}
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
if (existingMeta && stableStringify(existingMeta) === stableStringify(computedMeta)) {
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
mkdirSync(join(target, ".fabric"), { recursive: true });
|
|
50
|
-
writeFileSync(metaPath, `${JSON.stringify(computedMeta, null, 2)}
|
|
51
|
-
`, "utf8");
|
|
52
|
-
writeStderr(t("cli.sync-meta.updated", { label: t("cli.shared.updated"), path: metaPath }));
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
var sync_meta_default = syncMetaCommand;
|
|
56
|
-
function computeAgentsMeta(target) {
|
|
57
|
-
assertExistingDirectory(target);
|
|
58
|
-
const metaPath = join(target, ".fabric", "agents.meta.json");
|
|
59
|
-
const existingMeta = readExistingMeta(metaPath);
|
|
60
|
-
const existingByFile = indexExistingNodesByFile(existingMeta);
|
|
61
|
-
const agentsFiles = findFabricAgentsFiles(target);
|
|
62
|
-
const nodes = {};
|
|
63
|
-
const bootstrapNode = createBootstrapNode(
|
|
64
|
-
target,
|
|
65
|
-
existingByFile.get(".fabric/bootstrap/README.md")?.node ?? existingByFile.get("AGENTS.md")?.node
|
|
66
|
-
);
|
|
67
|
-
if (bootstrapNode !== void 0) {
|
|
68
|
-
nodes.L0 = bootstrapNode;
|
|
69
|
-
}
|
|
70
|
-
for (const file of agentsFiles) {
|
|
71
|
-
const existing = existingByFile.get(file);
|
|
72
|
-
const source = readFileSync(join(target, file), "utf8");
|
|
73
|
-
const id = deriveNodeId(file);
|
|
74
|
-
const hash = sha256(source);
|
|
75
|
-
const defaults = createDefaultNodeMeta(file);
|
|
76
|
-
const identity = deriveRuleIdentity(file, source, existing?.node);
|
|
77
|
-
nodes[id] = {
|
|
78
|
-
...defaults,
|
|
79
|
-
...existing?.node,
|
|
80
|
-
file,
|
|
81
|
-
hash,
|
|
82
|
-
stable_id: identity.stableId,
|
|
83
|
-
identity_source: identity.identitySource
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
return {
|
|
87
|
-
...existingMeta ?? {},
|
|
88
|
-
revision: computeRevision(nodes),
|
|
89
|
-
nodes: sortNodes(nodes)
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
function normalizeTarget(targetInput) {
|
|
93
|
-
return isAbsolute(targetInput) ? targetInput : resolve(process.cwd(), targetInput);
|
|
94
|
-
}
|
|
95
|
-
function assertExistingDirectory(target) {
|
|
96
|
-
if (!existsSync(target) || !statSync(target).isDirectory()) {
|
|
97
|
-
throw new Error(t("cli.shared.target-invalid", { target }));
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
function readExistingMeta(metaPath) {
|
|
101
|
-
if (!existsSync(metaPath)) {
|
|
102
|
-
return void 0;
|
|
103
|
-
}
|
|
104
|
-
try {
|
|
105
|
-
return agentsMetaSchema.parse(JSON.parse(readFileSync(metaPath, "utf8")));
|
|
106
|
-
} catch {
|
|
107
|
-
return void 0;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
function findFabricAgentsFiles(target) {
|
|
111
|
-
const agentsRoot = join(target, ".fabric", "agents");
|
|
112
|
-
if (!existsSync(agentsRoot) || !statSync(agentsRoot).isDirectory()) {
|
|
113
|
-
return [];
|
|
114
|
-
}
|
|
115
|
-
const files = [];
|
|
116
|
-
const stack = [agentsRoot];
|
|
117
|
-
while (stack.length > 0) {
|
|
118
|
-
const current = stack.pop();
|
|
119
|
-
if (current === void 0) {
|
|
120
|
-
continue;
|
|
121
|
-
}
|
|
122
|
-
for (const entry of readdirSync(current, { withFileTypes: true })) {
|
|
123
|
-
const absolutePath = join(current, entry.name);
|
|
124
|
-
const relativePath = toPosixPath(relative(target, absolutePath));
|
|
125
|
-
if (entry.isDirectory()) {
|
|
126
|
-
stack.push(absolutePath);
|
|
127
|
-
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
128
|
-
files.push(relativePath);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
return files.sort();
|
|
133
|
-
}
|
|
134
|
-
function deriveLayer(relativePath) {
|
|
135
|
-
return deriveAgentsMetaLayer(relativePath);
|
|
136
|
-
}
|
|
137
|
-
function deriveTopologyType(relativePath) {
|
|
138
|
-
return deriveAgentsMetaTopologyType(relativePath);
|
|
139
|
-
}
|
|
140
|
-
function indexExistingNodesByFile(existingMeta) {
|
|
141
|
-
const byFile = /* @__PURE__ */ new Map();
|
|
142
|
-
for (const [id, node] of Object.entries(existingMeta?.nodes ?? {})) {
|
|
143
|
-
byFile.set(toPosixPath(node.file), { id, node });
|
|
144
|
-
}
|
|
145
|
-
return byFile;
|
|
146
|
-
}
|
|
147
|
-
function deriveNodeId(file) {
|
|
148
|
-
if (file === ".fabric/bootstrap/README.md") {
|
|
149
|
-
return "L0";
|
|
150
|
-
}
|
|
151
|
-
const layer = deriveLayer(file);
|
|
152
|
-
const relativeStem = getMirrorRelativeStem(file);
|
|
153
|
-
return `${layer}/${relativeStem}`;
|
|
154
|
-
}
|
|
155
|
-
function createDefaultNodeMeta(file) {
|
|
156
|
-
const layer = deriveLayer(file);
|
|
157
|
-
const topologyType = deriveTopologyType(file);
|
|
158
|
-
return {
|
|
159
|
-
file,
|
|
160
|
-
scope_glob: deriveScopeGlob(file),
|
|
161
|
-
deps: layer === "L0" ? [] : ["L0"],
|
|
162
|
-
priority: layer === "L0" ? "high" : "medium",
|
|
163
|
-
layer,
|
|
164
|
-
topology_type: topologyType,
|
|
165
|
-
hash: ""
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
function createBootstrapNode(target, existing) {
|
|
169
|
-
const bootstrapPath = join(target, ".fabric", "bootstrap", "README.md");
|
|
170
|
-
const legacyBootstrapPath = join(target, "AGENTS.md");
|
|
171
|
-
const sourcePath = existsSync(bootstrapPath) ? bootstrapPath : existsSync(legacyBootstrapPath) ? legacyBootstrapPath : void 0;
|
|
172
|
-
if (sourcePath === void 0) {
|
|
173
|
-
return void 0;
|
|
174
|
-
}
|
|
175
|
-
const hash = sha256(readFileSync(sourcePath, "utf8"));
|
|
176
|
-
const identity = {
|
|
177
|
-
stableId: existing?.stable_id ?? deriveAgentsMetaStableId(".fabric/bootstrap/README.md"),
|
|
178
|
-
identitySource: existing?.identity_source ?? "derived"
|
|
179
|
-
};
|
|
180
|
-
return {
|
|
181
|
-
...createDefaultNodeMeta(".fabric/bootstrap/README.md"),
|
|
182
|
-
...existing,
|
|
183
|
-
file: ".fabric/bootstrap/README.md",
|
|
184
|
-
hash,
|
|
185
|
-
stable_id: identity.stableId,
|
|
186
|
-
identity_source: identity.identitySource
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
function deriveScopeGlob(file) {
|
|
190
|
-
if (file === ".fabric/bootstrap/README.md") {
|
|
191
|
-
return "**";
|
|
192
|
-
}
|
|
193
|
-
const stem = getMirrorRelativeStem(file);
|
|
194
|
-
const segments = stem.split("/").filter(Boolean);
|
|
195
|
-
if (segments.length === 0 || stem === "root") {
|
|
196
|
-
return "**";
|
|
197
|
-
}
|
|
198
|
-
if (segments[0] === "_cross") {
|
|
199
|
-
return "**";
|
|
200
|
-
}
|
|
201
|
-
if (segments.at(-1) === "rules") {
|
|
202
|
-
segments.pop();
|
|
203
|
-
}
|
|
204
|
-
const scopePath = segments.join("/");
|
|
205
|
-
return scopePath === "" ? "**" : `${scopePath}/**`;
|
|
206
|
-
}
|
|
207
|
-
function getMirrorRelativeStem(file) {
|
|
208
|
-
return file.replace(/^\.fabric\/agents\//, "").replace(/\.md$/, "");
|
|
209
|
-
}
|
|
210
|
-
function sortNodes(nodes) {
|
|
211
|
-
return Object.fromEntries(Object.entries(nodes).sort(([left], [right]) => left.localeCompare(right)));
|
|
212
|
-
}
|
|
213
|
-
function computeRevision(nodes) {
|
|
214
|
-
const revisionSource = Object.entries(sortNodes(nodes)).map(([id, node]) => [id, node.hash, node.stable_id ?? "", node.identity_source ?? ""].join("|")).join("\n");
|
|
215
|
-
return sha256(revisionSource);
|
|
216
|
-
}
|
|
217
|
-
function writeStderr(message) {
|
|
218
|
-
process.stderr.write(`${message}
|
|
219
|
-
`);
|
|
220
|
-
}
|
|
221
|
-
function stableStringify(value) {
|
|
222
|
-
return JSON.stringify(value, Object.keys(flattenKeys(value)).sort());
|
|
223
|
-
}
|
|
224
|
-
function flattenKeys(value, keys = {}) {
|
|
225
|
-
if (value && typeof value === "object") {
|
|
226
|
-
for (const [key, child] of Object.entries(value)) {
|
|
227
|
-
keys[key] = true;
|
|
228
|
-
flattenKeys(child, keys);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
return keys;
|
|
232
|
-
}
|
|
233
|
-
function toPosixPath(path) {
|
|
234
|
-
return path.split(sep).join("/");
|
|
235
|
-
}
|
|
236
|
-
function sha256(content) {
|
|
237
|
-
return `sha256:${createHash("sha256").update(content).digest("hex")}`;
|
|
238
|
-
}
|
|
239
|
-
function deriveRuleIdentity(file, source, existing) {
|
|
240
|
-
const declaredStableId = extractDeclaredStableId(source);
|
|
241
|
-
const derivedStableId = deriveAgentsMetaStableId(file);
|
|
242
|
-
if (declaredStableId !== void 0) {
|
|
243
|
-
return {
|
|
244
|
-
stableId: declaredStableId,
|
|
245
|
-
identitySource: "declared"
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
if (existing?.identity_source === "declared" && existing.stable_id !== void 0 && existing.stable_id !== derivedStableId) {
|
|
249
|
-
return {
|
|
250
|
-
stableId: existing.stable_id,
|
|
251
|
-
identitySource: "declared"
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
return {
|
|
255
|
-
stableId: derivedStableId,
|
|
256
|
-
identitySource: "derived"
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
function extractDeclaredStableId(source) {
|
|
260
|
-
const match = /^(?:\uFEFF)?<!--\s*fab:rule-id\s+([A-Za-z0-9][A-Za-z0-9/_-]*)\s*-->\s*(?:\r?\n|$)/u.exec(source);
|
|
261
|
-
return match?.[1];
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
export {
|
|
265
|
-
syncMetaCommand,
|
|
266
|
-
sync_meta_default,
|
|
267
|
-
computeAgentsMeta,
|
|
268
|
-
deriveLayer,
|
|
269
|
-
deriveTopologyType
|
|
270
|
-
};
|
package/dist/chunk-L43IGJ6X.js
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
padEnd
|
|
4
|
-
} from "./chunk-WWNXR34K.js";
|
|
5
|
-
import {
|
|
6
|
-
t
|
|
7
|
-
} from "./chunk-6ICJICVU.js";
|
|
8
|
-
|
|
9
|
-
// src/commands/human-lint.ts
|
|
10
|
-
import { createHash } from "crypto";
|
|
11
|
-
import { existsSync } from "fs";
|
|
12
|
-
import { readFile } from "fs/promises";
|
|
13
|
-
import { isAbsolute, join, resolve } from "path";
|
|
14
|
-
import { defineCommand } from "citty";
|
|
15
|
-
import { humanLockEntrySchema } from "@fenglimg/fabric-shared";
|
|
16
|
-
var humanLintCommand = defineCommand({
|
|
17
|
-
meta: {
|
|
18
|
-
name: "human-lint",
|
|
19
|
-
description: t("cli.human-lint.description")
|
|
20
|
-
},
|
|
21
|
-
args: {
|
|
22
|
-
target: {
|
|
23
|
-
type: "string",
|
|
24
|
-
description: t("cli.human-lint.args.target.description"),
|
|
25
|
-
default: process.cwd()
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
async run({ args }) {
|
|
29
|
-
const target = normalizeTarget(args.target);
|
|
30
|
-
const humanLockPath = join(target, ".fabric", "human-lock.json");
|
|
31
|
-
if (!existsSync(humanLockPath)) {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
const parsed = JSON.parse(await readFile(humanLockPath, "utf8"));
|
|
35
|
-
const locked = Array.isArray(parsed.locked) ? parsed.locked : [];
|
|
36
|
-
if (locked.length === 0) {
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
const snapshots = await Promise.all(
|
|
40
|
-
Array.from(new Set(locked.map((entry) => entry.file))).map(async (file) => {
|
|
41
|
-
try {
|
|
42
|
-
return {
|
|
43
|
-
file,
|
|
44
|
-
content: await readFile(join(target, file), "utf8")
|
|
45
|
-
};
|
|
46
|
-
} catch {
|
|
47
|
-
return {
|
|
48
|
-
file,
|
|
49
|
-
content: null
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
})
|
|
53
|
-
);
|
|
54
|
-
const snapshotByFile = new Map(snapshots.map((snapshot) => [snapshot.file, snapshot]));
|
|
55
|
-
const violations = [];
|
|
56
|
-
for (const entry of locked) {
|
|
57
|
-
const snapshot = snapshotByFile.get(entry.file);
|
|
58
|
-
const actual = snapshot?.content === null || snapshot === void 0 ? "missing" : hashLockedContent(snapshot.content, entry);
|
|
59
|
-
if (actual !== entry.hash) {
|
|
60
|
-
violations.push({
|
|
61
|
-
location: `${entry.file}:${entry.start_line}-${entry.end_line}`,
|
|
62
|
-
expected: shortenHash(entry.hash),
|
|
63
|
-
actual: shortenHash(actual)
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
if (violations.length === 0) {
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
writeStderr(t("cli.human-lint.drift-detected"));
|
|
71
|
-
writeStderr(
|
|
72
|
-
`${padEnd(t("cli.human-lint.table.location"), 32)} ${padEnd(t("cli.human-lint.table.expected"), 18)} ${t("cli.human-lint.table.got")}`
|
|
73
|
-
);
|
|
74
|
-
for (const violation of violations) {
|
|
75
|
-
writeStderr(
|
|
76
|
-
`${padEnd(violation.location, 32)} ${padEnd(violation.expected, 18)} ${violation.actual}`
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
process.exitCode = 1;
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
var human_lint_default = humanLintCommand;
|
|
83
|
-
function normalizeTarget(targetInput) {
|
|
84
|
-
return isAbsolute(targetInput) ? targetInput : resolve(process.cwd(), targetInput);
|
|
85
|
-
}
|
|
86
|
-
function hashLockedContent(content, entry) {
|
|
87
|
-
const lines = content.split(/\r?\n/);
|
|
88
|
-
const slice = lines.slice(Math.max(entry.start_line - 1, 0), Math.max(entry.end_line, 0)).join("\n");
|
|
89
|
-
return `sha256:${createHash("sha256").update(slice).digest("hex")}`;
|
|
90
|
-
}
|
|
91
|
-
function shortenHash(value) {
|
|
92
|
-
if (value === "missing") {
|
|
93
|
-
return t("cli.shared.missing");
|
|
94
|
-
}
|
|
95
|
-
return value.slice(0, 15);
|
|
96
|
-
}
|
|
97
|
-
function writeStderr(message) {
|
|
98
|
-
process.stderr.write(`${message}
|
|
99
|
-
`);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export {
|
|
103
|
-
humanLintCommand,
|
|
104
|
-
human_lint_default,
|
|
105
|
-
humanLockEntrySchema
|
|
106
|
-
};
|
package/dist/chunk-T2WJF5I3.js
DELETED
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
createScanReport
|
|
4
|
-
} from "./chunk-QSAEGVKE.js";
|
|
5
|
-
import {
|
|
6
|
-
readFabricConfig
|
|
7
|
-
} from "./chunk-AEOYCVBG.js";
|
|
8
|
-
import {
|
|
9
|
-
resolveClients
|
|
10
|
-
} from "./chunk-BEKSXO5N.js";
|
|
11
|
-
import {
|
|
12
|
-
t
|
|
13
|
-
} from "./chunk-6ICJICVU.js";
|
|
14
|
-
|
|
15
|
-
// src/commands/bootstrap.ts
|
|
16
|
-
import { resolve as resolve2 } from "path";
|
|
17
|
-
import { defineCommand } from "citty";
|
|
18
|
-
|
|
19
|
-
// src/bootstrap-guide.ts
|
|
20
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
21
|
-
import { dirname, isAbsolute, join, parse, resolve } from "path";
|
|
22
|
-
import { fileURLToPath } from "url";
|
|
23
|
-
var AGENTS_TEMPLATE_BY_FRAMEWORK = {
|
|
24
|
-
"cocos-creator": "templates/agents-md/variants/cocos.md",
|
|
25
|
-
vite: "templates/agents-md/variants/vite.md",
|
|
26
|
-
next: "templates/agents-md/variants/next.md"
|
|
27
|
-
};
|
|
28
|
-
var FABRIC_GUIDE_PATH = ".fabric/bootstrap/README.md";
|
|
29
|
-
async function buildFabricBootstrapGuide(target) {
|
|
30
|
-
const workspaceRoot = normalizeTarget(target);
|
|
31
|
-
const scanReport = await createScanReport(workspaceRoot);
|
|
32
|
-
const template = readFileSync(findBootstrapTemplatePath(scanReport.framework.kind), "utf8");
|
|
33
|
-
const packageName = readPackageName(workspaceRoot) ?? parse(workspaceRoot).base;
|
|
34
|
-
return ensureTrailingNewline(
|
|
35
|
-
template.replaceAll("{ projectName }", packageName).replaceAll("{ frameworkKind }", scanReport.framework.kind)
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
async function ensureFabricBootstrapGuide(workspaceRoot, force) {
|
|
39
|
-
const guidePath = resolve(workspaceRoot, FABRIC_GUIDE_PATH);
|
|
40
|
-
if (existsSync(guidePath) && !force) {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
mkdirSync(dirname(guidePath), { recursive: true });
|
|
44
|
-
writeFileSync(guidePath, await buildFabricBootstrapGuide(workspaceRoot), "utf8");
|
|
45
|
-
}
|
|
46
|
-
function findBootstrapTemplatePath(frameworkKind) {
|
|
47
|
-
const relativePath = AGENTS_TEMPLATE_BY_FRAMEWORK[frameworkKind] ?? "templates/agents-md/AGENTS.md.template";
|
|
48
|
-
return findTemplatePath(relativePath);
|
|
49
|
-
}
|
|
50
|
-
function readPackageName(target) {
|
|
51
|
-
const packageJsonPath = join(target, "package.json");
|
|
52
|
-
if (!existsSync(packageJsonPath)) {
|
|
53
|
-
return void 0;
|
|
54
|
-
}
|
|
55
|
-
try {
|
|
56
|
-
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
57
|
-
return packageJson.name;
|
|
58
|
-
} catch {
|
|
59
|
-
return void 0;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
function findTemplatePath(relativePath) {
|
|
63
|
-
const currentModuleDir = dirname(fileURLToPath(import.meta.url));
|
|
64
|
-
const candidates = [
|
|
65
|
-
...templateCandidatesFrom(process.cwd(), relativePath),
|
|
66
|
-
...templateCandidatesFrom(currentModuleDir, relativePath)
|
|
67
|
-
];
|
|
68
|
-
for (const candidate of candidates) {
|
|
69
|
-
if (existsSync(candidate)) {
|
|
70
|
-
return candidate;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
throw new Error(t("cli.shared.template-not-found", { path: relativePath }));
|
|
74
|
-
}
|
|
75
|
-
function templateCandidatesFrom(start, relativePath) {
|
|
76
|
-
const candidates = [];
|
|
77
|
-
let current = resolve(start);
|
|
78
|
-
while (true) {
|
|
79
|
-
candidates.push(join(current, ...relativePath.split("/")));
|
|
80
|
-
const parent = dirname(current);
|
|
81
|
-
if (parent === current || parse(current).root === current) {
|
|
82
|
-
break;
|
|
83
|
-
}
|
|
84
|
-
current = parent;
|
|
85
|
-
}
|
|
86
|
-
return candidates.reverse();
|
|
87
|
-
}
|
|
88
|
-
function ensureTrailingNewline(content) {
|
|
89
|
-
return content.endsWith("\n") ? content : `${content}
|
|
90
|
-
`;
|
|
91
|
-
}
|
|
92
|
-
function normalizeTarget(targetInput) {
|
|
93
|
-
return isAbsolute(targetInput) ? targetInput : resolve(process.cwd(), targetInput);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// src/commands/bootstrap.ts
|
|
97
|
-
var CLIENT_ALIASES = {
|
|
98
|
-
claude: "claude",
|
|
99
|
-
"claude-code": "claude",
|
|
100
|
-
claudecode: "claude",
|
|
101
|
-
claudecli: "claude",
|
|
102
|
-
claudecodecli: "claude",
|
|
103
|
-
claudedesktop: "claude",
|
|
104
|
-
claudecodedesktop: "claude",
|
|
105
|
-
cursor: "cursor",
|
|
106
|
-
windsurf: "windsurf",
|
|
107
|
-
roo: "roo",
|
|
108
|
-
"roo-code": "roo",
|
|
109
|
-
roocode: "roo",
|
|
110
|
-
gemini: "gemini",
|
|
111
|
-
"gemini-cli": "gemini",
|
|
112
|
-
geminicli: "gemini",
|
|
113
|
-
codex: "codex",
|
|
114
|
-
"codex-cli": "codex",
|
|
115
|
-
codexcli: "codex"
|
|
116
|
-
};
|
|
117
|
-
var bootstrapCommand = defineCommand({
|
|
118
|
-
meta: {
|
|
119
|
-
name: "bootstrap",
|
|
120
|
-
description: t("cli.bootstrap.description")
|
|
121
|
-
},
|
|
122
|
-
subCommands: {
|
|
123
|
-
install: defineCommand({
|
|
124
|
-
meta: {
|
|
125
|
-
name: "install",
|
|
126
|
-
description: t("cli.bootstrap.install.description")
|
|
127
|
-
},
|
|
128
|
-
args: {
|
|
129
|
-
clients: {
|
|
130
|
-
type: "string",
|
|
131
|
-
description: t("cli.bootstrap.install.args.clients.description")
|
|
132
|
-
}
|
|
133
|
-
},
|
|
134
|
-
async run({ args }) {
|
|
135
|
-
const workspaceRoot = process.cwd();
|
|
136
|
-
const selectedClients = parseClientFilter(args.clients);
|
|
137
|
-
const result = await installBootstrap(workspaceRoot, {
|
|
138
|
-
clients: selectedClients === null ? void 0 : Array.from(selectedClients, mapBootstrapClientToClientKind)
|
|
139
|
-
});
|
|
140
|
-
if (result.details.length === 0) {
|
|
141
|
-
process.stderr.write(
|
|
142
|
-
`${t("cli.bootstrap.install.no-targets")}
|
|
143
|
-
`
|
|
144
|
-
);
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
for (const detail of result.details) {
|
|
148
|
-
if (detail.action === "skipped") {
|
|
149
|
-
process.stderr.write(`${t("cli.bootstrap.install.skipped-header", { path: detail.path })}
|
|
150
|
-
`);
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
if (detail.action === "prepended") {
|
|
154
|
-
process.stderr.write(`${t("cli.bootstrap.install.prepended", { path: detail.path })}
|
|
155
|
-
`);
|
|
156
|
-
continue;
|
|
157
|
-
}
|
|
158
|
-
process.stderr.write(`${t("cli.bootstrap.install.installed", { path: detail.path })}
|
|
159
|
-
`);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
})
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
var bootstrap_default = bootstrapCommand;
|
|
166
|
-
async function installBootstrap(target, options = {}) {
|
|
167
|
-
const workspaceRoot = resolve2(target);
|
|
168
|
-
const fabricConfig = readFabricConfig(workspaceRoot);
|
|
169
|
-
const targets = resolveBootstrapTargets(workspaceRoot, fabricConfig, options.clients);
|
|
170
|
-
const installed = [];
|
|
171
|
-
const skipped = [];
|
|
172
|
-
const details = [];
|
|
173
|
-
await ensureFabricBootstrapGuide(workspaceRoot, options.force);
|
|
174
|
-
for (const bootstrapTarget of targets) {
|
|
175
|
-
details.push({
|
|
176
|
-
client: bootstrapTarget.client,
|
|
177
|
-
path: resolve2(workspaceRoot, FABRIC_GUIDE_PATH),
|
|
178
|
-
action: "skipped"
|
|
179
|
-
});
|
|
180
|
-
skipped.push(bootstrapTarget.client);
|
|
181
|
-
}
|
|
182
|
-
return { installed, skipped, details };
|
|
183
|
-
}
|
|
184
|
-
function parseClientFilter(value) {
|
|
185
|
-
if (value === void 0 || value.trim().length === 0) {
|
|
186
|
-
return null;
|
|
187
|
-
}
|
|
188
|
-
const clients = /* @__PURE__ */ new Set();
|
|
189
|
-
for (const rawClient of value.split(",")) {
|
|
190
|
-
const alias = rawClient.trim().toLowerCase();
|
|
191
|
-
const client = CLIENT_ALIASES[alias];
|
|
192
|
-
if (client === void 0) {
|
|
193
|
-
throw new Error(t("cli.bootstrap.errors.unknown-client", { client: rawClient }));
|
|
194
|
-
}
|
|
195
|
-
clients.add(client);
|
|
196
|
-
}
|
|
197
|
-
return clients;
|
|
198
|
-
}
|
|
199
|
-
function resolveBootstrapTargets(workspaceRoot, fabricConfig, selectedClients) {
|
|
200
|
-
const targets = [];
|
|
201
|
-
const seenClients = /* @__PURE__ */ new Set();
|
|
202
|
-
const clientKinds = selectedClients ?? resolveClients(workspaceRoot, fabricConfig).map((writer) => writer.clientKind);
|
|
203
|
-
for (const clientKind of clientKinds) {
|
|
204
|
-
const bootstrapClient = mapClientKind(clientKind);
|
|
205
|
-
if (bootstrapClient === null || seenClients.has(bootstrapClient)) {
|
|
206
|
-
continue;
|
|
207
|
-
}
|
|
208
|
-
seenClients.add(bootstrapClient);
|
|
209
|
-
targets.push({ client: clientKind, bootstrapClient });
|
|
210
|
-
}
|
|
211
|
-
return targets;
|
|
212
|
-
}
|
|
213
|
-
function mapClientKind(clientKind) {
|
|
214
|
-
switch (clientKind) {
|
|
215
|
-
case "ClaudeCodeCLI":
|
|
216
|
-
case "ClaudeCodeDesktop":
|
|
217
|
-
return "claude";
|
|
218
|
-
case "Cursor":
|
|
219
|
-
return "cursor";
|
|
220
|
-
case "Windsurf":
|
|
221
|
-
return "windsurf";
|
|
222
|
-
case "RooCode":
|
|
223
|
-
return "roo";
|
|
224
|
-
case "GeminiCLI":
|
|
225
|
-
return "gemini";
|
|
226
|
-
case "CodexCLI":
|
|
227
|
-
return "codex";
|
|
228
|
-
default:
|
|
229
|
-
return null;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
function mapBootstrapClientToClientKind(client) {
|
|
233
|
-
switch (client) {
|
|
234
|
-
case "claude":
|
|
235
|
-
return "ClaudeCodeCLI";
|
|
236
|
-
case "cursor":
|
|
237
|
-
return "Cursor";
|
|
238
|
-
case "windsurf":
|
|
239
|
-
return "Windsurf";
|
|
240
|
-
case "roo":
|
|
241
|
-
return "RooCode";
|
|
242
|
-
case "gemini":
|
|
243
|
-
return "GeminiCLI";
|
|
244
|
-
case "codex":
|
|
245
|
-
return "CodexCLI";
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
export {
|
|
250
|
-
buildFabricBootstrapGuide,
|
|
251
|
-
bootstrapCommand,
|
|
252
|
-
bootstrap_default,
|
|
253
|
-
installBootstrap
|
|
254
|
-
};
|
package/dist/chunk-WWNXR34K.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// src/colors.ts
|
|
4
|
-
import pc from "picocolors";
|
|
5
|
-
import stringWidth from "string-width";
|
|
6
|
-
function isColorEnabled() {
|
|
7
|
-
return !process.env.NO_COLOR && Boolean(process.stdout.isTTY) && Boolean(process.stderr.isTTY);
|
|
8
|
-
}
|
|
9
|
-
function colorize(painter) {
|
|
10
|
-
return (value) => isColorEnabled() ? painter(value) : value;
|
|
11
|
-
}
|
|
12
|
-
var paint = {
|
|
13
|
-
success: colorize(pc.green),
|
|
14
|
-
warn: colorize(pc.yellow),
|
|
15
|
-
error: colorize(pc.red),
|
|
16
|
-
drift: colorize(pc.magenta),
|
|
17
|
-
ai: colorize(pc.blue),
|
|
18
|
-
human: colorize(pc.cyan),
|
|
19
|
-
muted: colorize(pc.dim)
|
|
20
|
-
};
|
|
21
|
-
var symbol = {
|
|
22
|
-
get ok() {
|
|
23
|
-
return isColorEnabled() ? paint.success("\u2713") : "[ok]";
|
|
24
|
-
},
|
|
25
|
-
get warn() {
|
|
26
|
-
return isColorEnabled() ? paint.warn("!") : "[warn]";
|
|
27
|
-
},
|
|
28
|
-
get error() {
|
|
29
|
-
return isColorEnabled() ? paint.error("x") : "[error]";
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
function displayWidth(value) {
|
|
33
|
-
return stringWidth(value);
|
|
34
|
-
}
|
|
35
|
-
function padEnd(value, width, char = " ") {
|
|
36
|
-
const fill = char.length > 0 ? char : " ";
|
|
37
|
-
let result = value;
|
|
38
|
-
while (displayWidth(result) < width) {
|
|
39
|
-
result += fill;
|
|
40
|
-
}
|
|
41
|
-
return result;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export {
|
|
45
|
-
paint,
|
|
46
|
-
symbol,
|
|
47
|
-
displayWidth,
|
|
48
|
-
padEnd
|
|
49
|
-
};
|