@fenglimg/fabric-cli 2.1.0-rc.2 → 2.2.0-rc.3
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/{chunk-PWLW3B57.js → chunk-2CY4BMTH.js} +5 -1
- package/dist/chunk-5LQIHYFC.js +64 -0
- package/dist/chunk-5ZUMLCD5.js +248 -0
- package/dist/{chunk-WWNXR34K.js → chunk-BO4XIZWZ.js} +8 -1
- package/dist/chunk-EOT63RDH.js +36 -0
- package/dist/{chunk-BATF4PEJ.js → chunk-F6ITRM7T.js} +4 -4
- package/dist/{chunk-WU6GAPKH.js → chunk-H3FE6VIK.js} +3 -5
- package/dist/{chunk-MF3OTILQ.js → chunk-XC5RUHLK.js} +29 -8
- package/dist/chunk-XCBVSGCS.js +25 -0
- package/dist/{chunk-F46ORPOA.js → chunk-XHHCRDIR.js} +149 -7
- package/dist/{config-XJIPZNUP.js → config-VJMXCLXW.js} +3 -3
- package/dist/{doctor-QVNPHLJK.js → doctor-J4O3X54I.js} +154 -30
- package/dist/index.js +57 -16
- package/dist/{install-2HDO5FTQ.js → install-BULNDUIM.js} +241 -108
- package/dist/{metrics-ACEQFPDU.js → metrics-RER6NLFC.js} +22 -9
- package/dist/{onboard-coverage-MFCAEBDO.js → onboard-coverage-JWQWDZW7.js} +1 -1
- package/dist/{plan-context-hint-FC6P3WFE.js → plan-context-hint-CHVZGOZ5.js} +21 -8
- package/dist/{scope-explain-2F2R5URO.js → scope-explain-BWRWBCCP.js} +19 -5
- package/dist/{status-GLQWLWH6.js → status-PANEGKU2.js} +17 -6
- package/dist/store-66NK2FTQ.js +443 -0
- package/dist/sync-EA5HZMXM.js +395 -0
- package/dist/{uninstall-TAXSUSKH.js → uninstall-F75MPKQC.js} +61 -4
- package/dist/whoami-66YKY5DZ.js +47 -0
- package/package.json +3 -3
- package/templates/hooks/cite-policy-evict.cjs +412 -160
- package/templates/hooks/configs/claude-code.json +17 -2
- package/templates/hooks/configs/codex-hooks.json +14 -2
- package/templates/hooks/configs/cursor-hooks.json +14 -2
- package/templates/hooks/fabric-hint.cjs +247 -19
- package/templates/hooks/knowledge-hint-broad.cjs +176 -10
- package/templates/hooks/knowledge-hint-narrow.cjs +64 -5
- package/templates/hooks/lib/injection-log.cjs +91 -0
- package/templates/hooks/lib/state-store.cjs +30 -11
- package/templates/hooks/post-tooluse-mutation.cjs +285 -0
- package/templates/hooks/session-end-marker.cjs +140 -0
- package/templates/skills/fabric-archive/SKILL.md +7 -1
- package/templates/skills/fabric-audit/SKILL.md +53 -0
- package/templates/skills/fabric-connect/SKILL.md +48 -0
- package/templates/skills/fabric-review/SKILL.md +2 -0
- package/templates/skills/fabric-review/ref/cite-contract.md +56 -0
- package/templates/skills/fabric-store/SKILL.md +44 -0
- package/dist/chunk-HFQVXY6P.js +0 -86
- package/dist/chunk-L4Q55UC4.js +0 -52
- package/dist/chunk-LFIKMVY7.js +0 -27
- package/dist/chunk-RYAFBNES.js +0 -33
- package/dist/chunk-T5RPGCCM.js +0 -40
- package/dist/store-XTSE5TY6.js +0 -105
- package/dist/sync-BJCWDPNC.js +0 -245
- package/dist/whoami-B6AEMSEV.js +0 -31
|
@@ -4,12 +4,17 @@ import {
|
|
|
4
4
|
installArchiveHintHook,
|
|
5
5
|
installCitePolicyEvictHook,
|
|
6
6
|
installFabricArchiveSkill,
|
|
7
|
+
installFabricAuditSkill,
|
|
8
|
+
installFabricConnectSkill,
|
|
7
9
|
installFabricImportSkill,
|
|
8
10
|
installFabricReviewSkill,
|
|
11
|
+
installFabricStoreSkill,
|
|
9
12
|
installFabricSyncSkill,
|
|
10
13
|
installHookLibs,
|
|
11
14
|
installKnowledgeHintBroadHook,
|
|
12
15
|
installKnowledgeHintNarrowHook,
|
|
16
|
+
installPostTooluseMutationHook,
|
|
17
|
+
installSessionEndMarkerHook,
|
|
13
18
|
installSharedSkillLib,
|
|
14
19
|
mergeClaudeCodeHookConfig,
|
|
15
20
|
mergeCodexHookConfig,
|
|
@@ -19,38 +24,43 @@ import {
|
|
|
19
24
|
writeCodexBootstrapManagedBlock,
|
|
20
25
|
writeCursorBootstrapManagedBlock,
|
|
21
26
|
writeFabricAgentsSnapshot
|
|
22
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-XHHCRDIR.js";
|
|
23
28
|
import {
|
|
24
29
|
displayWidth,
|
|
25
30
|
padEnd,
|
|
26
31
|
paint
|
|
27
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-BO4XIZWZ.js";
|
|
28
33
|
import {
|
|
29
34
|
createDebugLogger,
|
|
30
35
|
resolveDevMode
|
|
31
36
|
} from "./chunk-COI5VDFU.js";
|
|
32
37
|
import {
|
|
33
38
|
installMcpClients
|
|
34
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-F6ITRM7T.js";
|
|
35
40
|
import {
|
|
36
41
|
detectClientSupports
|
|
37
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-XC5RUHLK.js";
|
|
38
43
|
import {
|
|
44
|
+
getProjectTranslator,
|
|
39
45
|
t
|
|
40
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-2CY4BMTH.js";
|
|
47
|
+
import {
|
|
48
|
+
syncStoreAliasLinks,
|
|
49
|
+
unboundAvailableStores
|
|
50
|
+
} from "./chunk-5ZUMLCD5.js";
|
|
41
51
|
import {
|
|
42
52
|
globalConfigPath,
|
|
43
53
|
loadGlobalConfig,
|
|
44
54
|
resolveGlobalRoot,
|
|
45
55
|
saveGlobalConfig
|
|
46
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-XCBVSGCS.js";
|
|
47
57
|
|
|
48
58
|
// src/commands/install.ts
|
|
49
59
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
50
60
|
import { homedir } from "os";
|
|
51
61
|
import * as childProcess from "child_process";
|
|
52
|
-
import { appendFileSync, existsSync as
|
|
53
|
-
import { dirname, isAbsolute as isAbsolute3, join as
|
|
62
|
+
import { appendFileSync, existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync4, rmSync as rmSync2, statSync as statSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
63
|
+
import { dirname, isAbsolute as isAbsolute3, join as join7, resolve as resolve3 } from "path";
|
|
54
64
|
import { cancel, confirm, group, intro, isCancel, log, note, outro, select } from "@clack/prompts";
|
|
55
65
|
import { defaultAgentsMetaCounters } from "@fenglimg/fabric-shared";
|
|
56
66
|
import { atomicWriteJson } from "@fenglimg/fabric-shared/node/atomic-write";
|
|
@@ -67,11 +77,16 @@ async function installHooks(target, _options = {}) {
|
|
|
67
77
|
results.push(...await runStep(() => installFabricReviewSkill(normalizedTarget)));
|
|
68
78
|
results.push(...await runStep(() => installFabricImportSkill(normalizedTarget)));
|
|
69
79
|
results.push(...await runStep(() => installFabricSyncSkill(normalizedTarget)));
|
|
80
|
+
results.push(...await runStep(() => installFabricStoreSkill(normalizedTarget)));
|
|
81
|
+
results.push(...await runStep(() => installFabricAuditSkill(normalizedTarget)));
|
|
82
|
+
results.push(...await runStep(() => installFabricConnectSkill(normalizedTarget)));
|
|
70
83
|
results.push(...await runStep(() => installSharedSkillLib(normalizedTarget)));
|
|
71
84
|
results.push(...await runStep(() => installArchiveHintHook(normalizedTarget)));
|
|
72
85
|
results.push(...await runStep(() => installKnowledgeHintBroadHook(normalizedTarget)));
|
|
73
86
|
results.push(...await runStep(() => installKnowledgeHintNarrowHook(normalizedTarget)));
|
|
74
87
|
results.push(...await runStep(() => installCitePolicyEvictHook(normalizedTarget)));
|
|
88
|
+
results.push(...await runStep(() => installSessionEndMarkerHook(normalizedTarget)));
|
|
89
|
+
results.push(...await runStep(() => installPostTooluseMutationHook(normalizedTarget)));
|
|
75
90
|
results.push(...await runStep(() => installHookLibs(normalizedTarget)));
|
|
76
91
|
results.push(await runSingleStep("claude-hook-config", () => mergeClaudeCodeHookConfig(normalizedTarget)));
|
|
77
92
|
results.push(await runSingleStep("codex-hook-config", () => mergeCodexHookConfig(normalizedTarget)));
|
|
@@ -87,7 +102,10 @@ function validateHookPaths(projectRoot) {
|
|
|
87
102
|
const scripts = [
|
|
88
103
|
{ stepSuffix: "", hookFile: "fabric-hint.cjs" },
|
|
89
104
|
{ stepSuffix: "-broad", hookFile: "knowledge-hint-broad.cjs" },
|
|
90
|
-
{ stepSuffix: "-narrow", hookFile: "knowledge-hint-narrow.cjs" }
|
|
105
|
+
{ stepSuffix: "-narrow", hookFile: "knowledge-hint-narrow.cjs" },
|
|
106
|
+
// lifecycle-refactor W2-T2/T3: SessionEnd + PostToolUse marker hooks.
|
|
107
|
+
{ stepSuffix: "-session-end", hookFile: "session-end-marker.cjs" },
|
|
108
|
+
{ stepSuffix: "-post-tooluse", hookFile: "post-tooluse-mutation.cjs" }
|
|
91
109
|
];
|
|
92
110
|
const clients = [
|
|
93
111
|
{
|
|
@@ -190,18 +208,57 @@ function assertExistingDirectory(target) {
|
|
|
190
208
|
}
|
|
191
209
|
}
|
|
192
210
|
|
|
211
|
+
// src/install/semantic-search.ts
|
|
212
|
+
import { existsSync as existsSync2, readFileSync, writeFileSync } from "fs";
|
|
213
|
+
import { join as join2 } from "path";
|
|
214
|
+
var DEFAULT_EMBED_MODEL_PIN = "fast-bge-small-zh-v1.5";
|
|
215
|
+
function enableSemanticSearch(projectRoot, opts = {}) {
|
|
216
|
+
const model = typeof opts.model === "string" && opts.model.length > 0 ? opts.model : DEFAULT_EMBED_MODEL_PIN;
|
|
217
|
+
const configPath = join2(projectRoot, "fabric.config.json");
|
|
218
|
+
let existing = {};
|
|
219
|
+
if (existsSync2(configPath)) {
|
|
220
|
+
try {
|
|
221
|
+
const parsed = JSON.parse(readFileSync(configPath, "utf8"));
|
|
222
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
223
|
+
existing = parsed;
|
|
224
|
+
}
|
|
225
|
+
} catch {
|
|
226
|
+
existing = {};
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const alreadyEnabled = existing.embed_enabled === true && existing.embed_model === model;
|
|
230
|
+
if (alreadyEnabled) {
|
|
231
|
+
return { configPath, model, alreadyEnabled: true, changed: false };
|
|
232
|
+
}
|
|
233
|
+
const merged = { ...existing, embed_enabled: true, embed_model: model };
|
|
234
|
+
writeFileSync(configPath, JSON.stringify(merged, null, 2) + "\n", "utf8");
|
|
235
|
+
return { configPath, model, alreadyEnabled: false, changed: true };
|
|
236
|
+
}
|
|
237
|
+
function renderSemanticSearchInstructions(model) {
|
|
238
|
+
return [
|
|
239
|
+
"\u8BED\u4E49\u641C\u7D22\u5DF2\u542F\u7528 (embed_enabled=true, embed_model=" + model + ")\u3002\u8FD8\u9700\u4E24\u6B65 (\u4E00\u6B21\u6027):",
|
|
240
|
+
" 1. \u5B89\u88C5\u53EF\u9009 embedder (\u88C5\u5230 MCP server \u89E3\u6790\u6A21\u5757\u7684\u4F4D\u7F6E \u2014 \u5168\u5C40\u5B89\u88C5\u5373\u5168\u5C40):",
|
|
241
|
+
" npm i -g fastembed",
|
|
242
|
+
" 2. \u9884\u70ED\u6A21\u578B\u7F13\u5B58 (\u9996\u8DD1\u4F1A\u8054\u7F51\u4E0B\u8F7D\u6A21\u578B\u6743\u91CD ~\u6570\u5341-\u6570\u767E MB, \u4E0D\u4E0A\u4F20\u4EFB\u4F55 KB \u6570\u636E):",
|
|
243
|
+
" export FABRIC_EMBED_CACHE_DIR=~/.cache/fabric-embed # \u4E25\u683C\u79BB\u7EBF\u8005\u9884\u5148\u653E\u597D\u6743\u91CD",
|
|
244
|
+
" \u6CE8: \u5207\u6362 embed_model \u540E\u5DF2\u6709\u5411\u91CF\u7EF4\u5EA6/\u8BED\u4E49\u53D8\u5316, \u4E0B\u6B21 recall \u4F1A\u6309\u65B0\u6A21\u578B\u91CD\u65B0\u5D4C\u5165 (doc \u5411\u91CF\u6309\u6587\u672C\u7F13\u5B58, \u81EA\u52A8\u5931\u914D\u91CD\u7B97)\u3002",
|
|
245
|
+
" \u5173\u95ED: \u7F16\u8F91 fabric.config.json \u8BBE embed_enabled=false\u3002"
|
|
246
|
+
];
|
|
247
|
+
}
|
|
248
|
+
|
|
193
249
|
// src/install/run-global-install.ts
|
|
194
250
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
195
251
|
import { randomUUID } from "crypto";
|
|
196
252
|
import { mkdirSync, mkdtempSync, renameSync } from "fs";
|
|
197
253
|
import { tmpdir } from "os";
|
|
198
|
-
import { join as
|
|
254
|
+
import { join as join4 } from "path";
|
|
199
255
|
import { STORES_ROOT_DIR as STORES_ROOT_DIR2, addMountedStore, readStoreIdentity } from "@fenglimg/fabric-shared";
|
|
256
|
+
import { GenericIOError } from "@fenglimg/fabric-shared/errors";
|
|
200
257
|
|
|
201
258
|
// src/store/uid.ts
|
|
202
259
|
import { execFileSync } from "child_process";
|
|
203
260
|
import { createHash } from "crypto";
|
|
204
|
-
function deriveUid() {
|
|
261
|
+
function deriveUid(opts = {}) {
|
|
205
262
|
let email = "";
|
|
206
263
|
try {
|
|
207
264
|
email = execFileSync("git", ["config", "user.email"], {
|
|
@@ -214,13 +271,14 @@ function deriveUid() {
|
|
|
214
271
|
if (email === "") {
|
|
215
272
|
return "u-anon";
|
|
216
273
|
}
|
|
217
|
-
const
|
|
274
|
+
const material = opts.salt !== void 0 && opts.salt.length > 0 ? `${opts.salt}:${email.toLowerCase()}` : email.toLowerCase();
|
|
275
|
+
const hash = createHash("sha256").update(material).digest("hex").slice(0, 12);
|
|
218
276
|
return `u-${hash}`;
|
|
219
277
|
}
|
|
220
278
|
|
|
221
279
|
// src/install/install-global.ts
|
|
222
280
|
import { rmSync } from "fs";
|
|
223
|
-
import { join as
|
|
281
|
+
import { join as join3 } from "path";
|
|
224
282
|
import {
|
|
225
283
|
STORES_ROOT_DIR,
|
|
226
284
|
globalConfigSchema,
|
|
@@ -279,7 +337,7 @@ async function installGlobalCore(options) {
|
|
|
279
337
|
};
|
|
280
338
|
}
|
|
281
339
|
const alias = options.personalAlias ?? "personal";
|
|
282
|
-
const personalDir =
|
|
340
|
+
const personalDir = join3(options.globalRoot, STORES_ROOT_DIR, options.personalStoreUuid);
|
|
283
341
|
let config = null;
|
|
284
342
|
const receipt = await runInstallTransaction([
|
|
285
343
|
{
|
|
@@ -319,23 +377,35 @@ async function installGlobalCore(options) {
|
|
|
319
377
|
|
|
320
378
|
// src/install/run-global-install.ts
|
|
321
379
|
function gitClone(url, dest) {
|
|
322
|
-
|
|
380
|
+
console.log(`cloning store from ${url} (this may take a while)\u2026`);
|
|
381
|
+
try {
|
|
382
|
+
execFileSync2("git", ["clone", "--", url, dest], { stdio: ["ignore", "ignore", "inherit"] });
|
|
383
|
+
} catch (error) {
|
|
384
|
+
throw new GenericIOError(`git clone of ${url} failed`, {
|
|
385
|
+
actionHint: "check the url is reachable and points to a Fabric store git repo (the git error above shows the cause), then re-run `fabric install --global <url>`",
|
|
386
|
+
details: error
|
|
387
|
+
});
|
|
388
|
+
}
|
|
323
389
|
}
|
|
324
390
|
function mountStoreFromRemote(url, globalRoot) {
|
|
325
|
-
const storesRoot =
|
|
391
|
+
const storesRoot = join4(globalRoot, STORES_ROOT_DIR2);
|
|
326
392
|
mkdirSync(storesRoot, { recursive: true });
|
|
327
|
-
const tmp = mkdtempSync(
|
|
328
|
-
const cloneDest =
|
|
393
|
+
const tmp = mkdtempSync(join4(tmpdir(), "fabric-clone-"));
|
|
394
|
+
const cloneDest = join4(tmp, "store");
|
|
329
395
|
gitClone(url, cloneDest);
|
|
330
396
|
const identity = readStoreIdentity(cloneDest);
|
|
331
397
|
if (identity === null) {
|
|
332
|
-
throw new
|
|
398
|
+
throw new GenericIOError(`cloned store at ${url} has no valid store.json (not a Fabric store)`, {
|
|
399
|
+
actionHint: "verify the url points to a repository created by `fabric` (it must contain a store.json at its root); if you meant to mount a different store, re-run with the correct url"
|
|
400
|
+
});
|
|
333
401
|
}
|
|
334
|
-
const finalDir =
|
|
402
|
+
const finalDir = join4(storesRoot, identity.store_uuid);
|
|
335
403
|
renameSync(cloneDest, finalDir);
|
|
336
404
|
const config = loadGlobalConfig(globalRoot);
|
|
337
405
|
if (config === null) {
|
|
338
|
-
throw new
|
|
406
|
+
throw new GenericIOError("global config missing after install", {
|
|
407
|
+
actionHint: "re-run `fabric install --global` to (re)create the global config, then retry mounting the store; if it persists, inspect ~/.fabric for a partial install"
|
|
408
|
+
});
|
|
339
409
|
}
|
|
340
410
|
const alias = identity.canonical_alias ?? "team";
|
|
341
411
|
saveGlobalConfig(
|
|
@@ -350,7 +420,12 @@ async function runGlobalInstall(options = {}, globalRoot = resolveGlobalRoot())
|
|
|
350
420
|
const now = options.now ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
351
421
|
const result = await installGlobalCore({ globalRoot, uid, personalStoreUuid, now });
|
|
352
422
|
if (!result.receipt.ok) {
|
|
353
|
-
throw new
|
|
423
|
+
throw new GenericIOError(
|
|
424
|
+
`global install failed at step '${result.receipt.failedStep}': ${result.receipt.error}`,
|
|
425
|
+
{
|
|
426
|
+
actionHint: "check write permissions and free space under ~/.fabric, then re-run `fabric install --global` (the install is transactional and rolls back partial state)"
|
|
427
|
+
}
|
|
428
|
+
);
|
|
354
429
|
}
|
|
355
430
|
console.log(
|
|
356
431
|
result.alreadyInstalled ? "global Fabric already installed" : `installed global Fabric (uid ${uid})`
|
|
@@ -358,23 +433,24 @@ async function runGlobalInstall(options = {}, globalRoot = resolveGlobalRoot())
|
|
|
358
433
|
if (options.url !== void 0) {
|
|
359
434
|
mountStoreFromRemote(options.url, globalRoot);
|
|
360
435
|
}
|
|
436
|
+
syncStoreAliasLinks(globalRoot);
|
|
361
437
|
}
|
|
362
438
|
|
|
363
439
|
// src/lib/detect-language.ts
|
|
364
|
-
import { existsSync as
|
|
365
|
-
import { join as
|
|
440
|
+
import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync2, statSync as statSync2 } from "fs";
|
|
441
|
+
import { join as join5 } from "path";
|
|
366
442
|
function detectExistingLanguage(target) {
|
|
367
443
|
const ZH_CN_RATIO_THRESHOLD = 0.3;
|
|
368
444
|
const samples = [];
|
|
369
|
-
const readmePath =
|
|
370
|
-
if (
|
|
445
|
+
const readmePath = join5(target, "README.md");
|
|
446
|
+
if (existsSync3(readmePath)) {
|
|
371
447
|
try {
|
|
372
|
-
samples.push(
|
|
448
|
+
samples.push(readFileSync2(readmePath, "utf8"));
|
|
373
449
|
} catch {
|
|
374
450
|
}
|
|
375
451
|
}
|
|
376
|
-
const docsDir =
|
|
377
|
-
if (
|
|
452
|
+
const docsDir = join5(target, "docs");
|
|
453
|
+
if (existsSync3(docsDir)) {
|
|
378
454
|
try {
|
|
379
455
|
const stat = statSync2(docsDir);
|
|
380
456
|
if (stat.isDirectory()) {
|
|
@@ -382,7 +458,7 @@ function detectExistingLanguage(target) {
|
|
|
382
458
|
if (!entry.isFile()) continue;
|
|
383
459
|
if (!/\.(md|mdx|txt)$/iu.test(entry.name)) continue;
|
|
384
460
|
try {
|
|
385
|
-
samples.push(
|
|
461
|
+
samples.push(readFileSync2(join5(docsDir, entry.name), "utf8"));
|
|
386
462
|
} catch {
|
|
387
463
|
}
|
|
388
464
|
}
|
|
@@ -415,10 +491,11 @@ function detectExistingLanguage(target) {
|
|
|
415
491
|
|
|
416
492
|
// src/scanner/forensic.ts
|
|
417
493
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
418
|
-
import { existsSync as
|
|
494
|
+
import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as readFileSync3, statSync as statSync3 } from "fs";
|
|
419
495
|
import { createRequire } from "module";
|
|
420
|
-
import { basename, extname, isAbsolute as isAbsolute2, join as
|
|
496
|
+
import { basename, extname, isAbsolute as isAbsolute2, join as join6, posix, relative, resolve as resolve2, sep } from "path";
|
|
421
497
|
import {
|
|
498
|
+
buildScanRecommendations,
|
|
422
499
|
forensicReportSchema
|
|
423
500
|
} from "@fenglimg/fabric-shared";
|
|
424
501
|
|
|
@@ -536,7 +613,7 @@ async function buildForensicReport(targetInput) {
|
|
|
536
613
|
candidate_files: candidateFiles,
|
|
537
614
|
sampling_budget: DEFAULT_SAMPLING_BUDGET,
|
|
538
615
|
readme,
|
|
539
|
-
recommendations_for_skill: buildSkillRecommendations(framework.kind, topology, readme)
|
|
616
|
+
recommendations_for_skill: buildSkillRecommendations(framework.kind, topology, readme, target)
|
|
540
617
|
};
|
|
541
618
|
const validation = forensicReportSchema.safeParse(report);
|
|
542
619
|
if (!validation.success) {
|
|
@@ -561,7 +638,7 @@ function buildTopology(root) {
|
|
|
561
638
|
continue;
|
|
562
639
|
}
|
|
563
640
|
for (const entry of readdirSync2(current, { withFileTypes: true })) {
|
|
564
|
-
const absolutePath =
|
|
641
|
+
const absolutePath = join6(current, entry.name);
|
|
565
642
|
const relativePath = toPosixPath(relative(root, absolutePath));
|
|
566
643
|
if (relativePath.length === 0) {
|
|
567
644
|
continue;
|
|
@@ -600,7 +677,7 @@ function buildTopology(root) {
|
|
|
600
677
|
};
|
|
601
678
|
}
|
|
602
679
|
function assertExistingDirectory2(target) {
|
|
603
|
-
if (!
|
|
680
|
+
if (!existsSync4(target) || !statSync3(target).isDirectory()) {
|
|
604
681
|
throw new Error(`Target must be an existing directory: ${target}`);
|
|
605
682
|
}
|
|
606
683
|
}
|
|
@@ -649,7 +726,7 @@ function getEntryPointReason(relativePath) {
|
|
|
649
726
|
async function buildCodeSamples(target, entryPoints, frameworkKind, topology, packageDependencies) {
|
|
650
727
|
const samples = [];
|
|
651
728
|
for (const entryPoint of entryPoints.slice(0, SAMPLE_LIMIT)) {
|
|
652
|
-
const absolutePath =
|
|
729
|
+
const absolutePath = join6(target, ...entryPoint.path.split("/"));
|
|
653
730
|
const sample = readFirstLines(absolutePath, SAMPLE_LINE_LIMIT);
|
|
654
731
|
const patternAnalysis = await inferPatternHint(entryPoint.path, sample.snippet, {
|
|
655
732
|
frameworkKind,
|
|
@@ -669,7 +746,7 @@ async function buildCodeSamples(target, entryPoints, frameworkKind, topology, pa
|
|
|
669
746
|
}
|
|
670
747
|
function readFirstLines(path, lineLimit) {
|
|
671
748
|
try {
|
|
672
|
-
const lines =
|
|
749
|
+
const lines = readFileSync3(path, "utf8").split(/\r?\n/);
|
|
673
750
|
if (lines.at(-1) === "") {
|
|
674
751
|
lines.pop();
|
|
675
752
|
}
|
|
@@ -686,12 +763,12 @@ function readFirstLines(path, lineLimit) {
|
|
|
686
763
|
}
|
|
687
764
|
}
|
|
688
765
|
function readPackageDependencies(target) {
|
|
689
|
-
const packageJsonPath =
|
|
690
|
-
if (!
|
|
766
|
+
const packageJsonPath = join6(target, "package.json");
|
|
767
|
+
if (!existsSync4(packageJsonPath)) {
|
|
691
768
|
return /* @__PURE__ */ new Map();
|
|
692
769
|
}
|
|
693
770
|
try {
|
|
694
|
-
const packageJson = JSON.parse(
|
|
771
|
+
const packageJson = JSON.parse(readFileSync3(packageJsonPath, "utf8"));
|
|
695
772
|
return new Map([
|
|
696
773
|
...Object.entries(packageJson.dependencies ?? {}),
|
|
697
774
|
...Object.entries(packageJson.devDependencies ?? {}),
|
|
@@ -1027,16 +1104,16 @@ function scoreFrameworkConfidence(input) {
|
|
|
1027
1104
|
return input.configCount > 0 || input.packageCount > 0 ? "MEDIUM" : "LOW";
|
|
1028
1105
|
}
|
|
1029
1106
|
function readReadmeInfo(target) {
|
|
1030
|
-
const readmePath =
|
|
1031
|
-
const hasContributing =
|
|
1032
|
-
if (!
|
|
1107
|
+
const readmePath = join6(target, "README.md");
|
|
1108
|
+
const hasContributing = existsSync4(join6(target, "CONTRIBUTING.md"));
|
|
1109
|
+
if (!existsSync4(readmePath)) {
|
|
1033
1110
|
return {
|
|
1034
1111
|
quality: "missing",
|
|
1035
1112
|
line_count: 0,
|
|
1036
1113
|
has_contributing: hasContributing
|
|
1037
1114
|
};
|
|
1038
1115
|
}
|
|
1039
|
-
const readme =
|
|
1116
|
+
const readme = readFileSync3(readmePath, "utf8");
|
|
1040
1117
|
const wordCount = readme.trim().split(/\s+/).filter(Boolean).length;
|
|
1041
1118
|
return {
|
|
1042
1119
|
quality: wordCount >= 200 ? "ok" : "stub",
|
|
@@ -1491,33 +1568,21 @@ function isDomainFile(relativePath) {
|
|
|
1491
1568
|
}
|
|
1492
1569
|
return !isConfigFile(relativePath) && !isTestFile(relativePath);
|
|
1493
1570
|
}
|
|
1494
|
-
function buildSkillRecommendations(frameworkKind, topology, readme) {
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
recommendations.push("\u5EFA\u8BAE\u786E\u8BA4 app/pages \u8DEF\u7531\u8FB9\u754C\u548C\u670D\u52A1\u7AEF\u7EC4\u4EF6\u7EA6\u675F\u3002");
|
|
1504
|
-
} else if (frameworkKind === "vite") {
|
|
1505
|
-
recommendations.push("\u5EFA\u8BAE\u786E\u8BA4 src/main \u5165\u53E3\u3001\u7EC4\u4EF6\u76EE\u5F55\u548C\u6784\u5EFA\u811A\u672C\u7684\u7EF4\u62A4\u8FB9\u754C\u3002");
|
|
1506
|
-
} else if (frameworkKind === "unknown") {
|
|
1507
|
-
recommendations.push("\u672A\u68C0\u6D4B\u5230\u660E\u786E\u6846\u67B6,\u5EFA\u8BAE\u5148\u8BA9\u7528\u6237\u786E\u8BA4\u6280\u672F\u6808\u548C\u4E3B\u8981\u5165\u53E3\u3002");
|
|
1508
|
-
} else {
|
|
1509
|
-
recommendations.push(`\u5EFA\u8BAE\u56F4\u7ED5 ${frameworkKind} \u7684\u4E3B\u8981\u5165\u53E3\u548C\u751F\u6210\u76EE\u5F55\u786E\u8BA4 AGENTS.md \u5206\u5C42\u8FB9\u754C\u3002`);
|
|
1510
|
-
}
|
|
1511
|
-
if (readme.quality !== "ok") {
|
|
1512
|
-
recommendations.push("README \u4FE1\u606F\u4E0D\u8DB3,\u5EFA\u8BAE\u5728\u521D\u59CB\u5316\u8BBF\u8C08\u4E2D\u8865\u9F50\u9879\u76EE\u76EE\u6807\u3001\u8FD0\u884C\u65B9\u5F0F\u548C\u7981\u6539\u533A\u57DF\u3002");
|
|
1513
|
-
}
|
|
1514
|
-
return recommendations;
|
|
1571
|
+
function buildSkillRecommendations(frameworkKind, topology, readme, projectRoot) {
|
|
1572
|
+
return buildScanRecommendations(
|
|
1573
|
+
{
|
|
1574
|
+
frameworkKind,
|
|
1575
|
+
hasMeta: (topology.by_ext[".meta"] ?? 0) > 0,
|
|
1576
|
+
readmeOk: readme.quality === "ok"
|
|
1577
|
+
},
|
|
1578
|
+
getProjectTranslator(projectRoot)
|
|
1579
|
+
);
|
|
1515
1580
|
}
|
|
1516
1581
|
function readProjectName(target) {
|
|
1517
|
-
const packageJsonPath =
|
|
1518
|
-
if (
|
|
1582
|
+
const packageJsonPath = join6(target, "package.json");
|
|
1583
|
+
if (existsSync4(packageJsonPath)) {
|
|
1519
1584
|
try {
|
|
1520
|
-
const packageJson = JSON.parse(
|
|
1585
|
+
const packageJson = JSON.parse(readFileSync3(packageJsonPath, "utf8"));
|
|
1521
1586
|
if (packageJson.name !== void 0 && packageJson.name.trim().length > 0) {
|
|
1522
1587
|
return packageJson.name;
|
|
1523
1588
|
}
|
|
@@ -1528,7 +1593,7 @@ function readProjectName(target) {
|
|
|
1528
1593
|
return basename(target);
|
|
1529
1594
|
}
|
|
1530
1595
|
function getCliVersion() {
|
|
1531
|
-
return true ? "2.
|
|
1596
|
+
return true ? "2.2.0-rc.3" : "unknown";
|
|
1532
1597
|
}
|
|
1533
1598
|
function sortRecord(record) {
|
|
1534
1599
|
return Object.fromEntries(Object.entries(record).sort(([left], [right]) => left.localeCompare(right)));
|
|
@@ -1538,7 +1603,7 @@ function toPosixPath(path) {
|
|
|
1538
1603
|
}
|
|
1539
1604
|
|
|
1540
1605
|
// src/commands/install.ts
|
|
1541
|
-
var LOCAL_FABRIC_SERVER_PATH =
|
|
1606
|
+
var LOCAL_FABRIC_SERVER_PATH = join7("node_modules", "@fenglimg", "fabric-server", "dist", "index.js");
|
|
1542
1607
|
var FABRIC_SERVER_PACKAGE = "@fenglimg/fabric-server";
|
|
1543
1608
|
var INIT_WIZARD_GROUP_CANCELLED = /* @__PURE__ */ Symbol("init-wizard-group-cancelled");
|
|
1544
1609
|
var installCommand = defineCommand({
|
|
@@ -1584,6 +1649,15 @@ var installCommand = defineCommand({
|
|
|
1584
1649
|
url: {
|
|
1585
1650
|
type: "string",
|
|
1586
1651
|
description: "With --global: clone + mount this shared store remote"
|
|
1652
|
+
},
|
|
1653
|
+
"enable-embed": {
|
|
1654
|
+
type: "boolean",
|
|
1655
|
+
description: t("cli.install.args.enable-embed.description"),
|
|
1656
|
+
default: false
|
|
1657
|
+
},
|
|
1658
|
+
"embed-model": {
|
|
1659
|
+
type: "string",
|
|
1660
|
+
description: t("cli.install.args.embed-model.description")
|
|
1587
1661
|
}
|
|
1588
1662
|
},
|
|
1589
1663
|
async run({ args }) {
|
|
@@ -1593,8 +1667,8 @@ var installCommand = defineCommand({
|
|
|
1593
1667
|
var install_default = installCommand;
|
|
1594
1668
|
async function runSkillsOnlyRefresh(targetInput) {
|
|
1595
1669
|
const target = normalizeTarget3(targetInput);
|
|
1596
|
-
const metaPath =
|
|
1597
|
-
if (!
|
|
1670
|
+
const metaPath = join7(target, ".fabric", "agents.meta.json");
|
|
1671
|
+
if (!existsSync5(metaPath)) {
|
|
1598
1672
|
const message = t("cli.install.force-skills-only.uninitialised.message");
|
|
1599
1673
|
const hint = t("cli.install.force-skills-only.uninitialised.hint");
|
|
1600
1674
|
process.stderr.write(`${message}
|
|
@@ -1609,6 +1683,11 @@ ${hint}
|
|
|
1609
1683
|
results.push(...await installFabricArchiveSkill(target));
|
|
1610
1684
|
results.push(...await installFabricReviewSkill(target));
|
|
1611
1685
|
results.push(...await installFabricImportSkill(target));
|
|
1686
|
+
results.push(...await installFabricSyncSkill(target));
|
|
1687
|
+
results.push(...await installFabricStoreSkill(target));
|
|
1688
|
+
results.push(...await installFabricAuditSkill(target));
|
|
1689
|
+
results.push(...await installFabricConnectSkill(target));
|
|
1690
|
+
results.push(...await installSharedSkillLib(target));
|
|
1612
1691
|
let written = 0;
|
|
1613
1692
|
let skipped = 0;
|
|
1614
1693
|
let errors = 0;
|
|
@@ -1636,8 +1715,8 @@ ${hint}
|
|
|
1636
1715
|
}
|
|
1637
1716
|
async function runHooksOnlyRefresh(targetInput) {
|
|
1638
1717
|
const target = normalizeTarget3(targetInput);
|
|
1639
|
-
const metaPath =
|
|
1640
|
-
if (!
|
|
1718
|
+
const metaPath = join7(target, ".fabric", "agents.meta.json");
|
|
1719
|
+
if (!existsSync5(metaPath)) {
|
|
1641
1720
|
const message = t("cli.install.force-hooks-only.uninitialised.message");
|
|
1642
1721
|
const hint = t("cli.install.force-hooks-only.uninitialised.hint");
|
|
1643
1722
|
process.stderr.write(`${message}
|
|
@@ -1683,6 +1762,10 @@ async function runInitCommand(args) {
|
|
|
1683
1762
|
for (const step of resolution.chain) {
|
|
1684
1763
|
logger(step);
|
|
1685
1764
|
}
|
|
1765
|
+
if (loadGlobalConfig() === null) {
|
|
1766
|
+
logger("no global Fabric config found \u2014 minting ~/.fabric (uid + personal store)");
|
|
1767
|
+
await runGlobalInstall({});
|
|
1768
|
+
}
|
|
1686
1769
|
const supports = detectClientSupports(intent.target);
|
|
1687
1770
|
const basePlan = await buildInitExecutionPlan({
|
|
1688
1771
|
target: intent.target,
|
|
@@ -1703,12 +1786,51 @@ async function runInitCommand(args) {
|
|
|
1703
1786
|
console.log(t("cli.install.next-steps"));
|
|
1704
1787
|
console.log("");
|
|
1705
1788
|
console.log(paint.muted("More: docs/surfaces.md explains when to use CLI vs Skill vs MCP."));
|
|
1789
|
+
const unboundStores = unboundAvailableStores(resolution.target);
|
|
1790
|
+
if (unboundStores.length > 0) {
|
|
1791
|
+
console.log("");
|
|
1792
|
+
console.log(
|
|
1793
|
+
t("cli.install.store-bind-nudge", {
|
|
1794
|
+
aliases: unboundStores.map((s) => `'${s.alias}'`).join(", "),
|
|
1795
|
+
first: unboundStores[0].alias
|
|
1796
|
+
})
|
|
1797
|
+
);
|
|
1798
|
+
}
|
|
1799
|
+
if (args["enable-embed"] === true) {
|
|
1800
|
+
const enabled = enableSemanticSearch(resolution.target, { model: args["embed-model"] });
|
|
1801
|
+
console.log("");
|
|
1802
|
+
if (enabled.alreadyEnabled) {
|
|
1803
|
+
console.log(paint.muted(`\u8BED\u4E49\u641C\u7D22\u5DF2\u662F\u542F\u7528\u72B6\u6001 (embed_model=${enabled.model})\uFF0C\u672A\u6539\u52A8 ${enabled.configPath}\u3002`));
|
|
1804
|
+
} else {
|
|
1805
|
+
for (const line of renderSemanticSearchInstructions(enabled.model)) {
|
|
1806
|
+
console.log(line);
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1706
1810
|
}
|
|
1707
1811
|
return result;
|
|
1708
1812
|
}
|
|
1813
|
+
var FABRIC_GITIGNORE_CONTENT = [
|
|
1814
|
+
"# Fabric per-dev activity ledgers & caches \u2014 auto-generated, not shared.",
|
|
1815
|
+
"# Managed by `fabric install`; edit freely (re-install never overwrites this).",
|
|
1816
|
+
"events.jsonl",
|
|
1817
|
+
"metrics.jsonl",
|
|
1818
|
+
"cite-rollup.jsonl",
|
|
1819
|
+
"injections.jsonl",
|
|
1820
|
+
".cache/",
|
|
1821
|
+
"*.lock",
|
|
1822
|
+
"*.corrupted.*",
|
|
1823
|
+
""
|
|
1824
|
+
].join("\n");
|
|
1825
|
+
function writeDefaultGitignore(fabricDir) {
|
|
1826
|
+
const target = join7(fabricDir, ".gitignore");
|
|
1827
|
+
if (existsSync5(target)) return;
|
|
1828
|
+
mkdirSync2(fabricDir, { recursive: true });
|
|
1829
|
+
writeFileSync2(target, FABRIC_GITIGNORE_CONTENT, "utf8");
|
|
1830
|
+
}
|
|
1709
1831
|
function writeDefaultFabricConfig(fabricDir, targetRoot) {
|
|
1710
|
-
const target =
|
|
1711
|
-
if (
|
|
1832
|
+
const target = join7(fabricDir, "fabric-config.json");
|
|
1833
|
+
if (existsSync5(target)) return;
|
|
1712
1834
|
const detectedLanguage = detectExistingLanguage(targetRoot);
|
|
1713
1835
|
const FABRIC_CONFIG_DEFAULTS = {
|
|
1714
1836
|
// Scan/import language policy. Fixated at init time by probing
|
|
@@ -1770,7 +1892,7 @@ function writeDefaultFabricConfig(fabricDir, targetRoot) {
|
|
|
1770
1892
|
review_stale_pending_days: 14
|
|
1771
1893
|
};
|
|
1772
1894
|
mkdirSync2(fabricDir, { recursive: true });
|
|
1773
|
-
|
|
1895
|
+
writeFileSync2(target, JSON.stringify(FABRIC_CONFIG_DEFAULTS, null, 2) + "\n", "utf8");
|
|
1774
1896
|
log.info(
|
|
1775
1897
|
`Detected and fixated fabric_language = ${detectedLanguage}; edit ${target} to override.`
|
|
1776
1898
|
);
|
|
@@ -1847,7 +1969,7 @@ async function executeInitExecutionPlan(plan) {
|
|
|
1847
1969
|
finalSupports: plan.supports
|
|
1848
1970
|
};
|
|
1849
1971
|
}
|
|
1850
|
-
if (
|
|
1972
|
+
if (existsSync5(plan.scaffold.fabricDir) && !statSync4(plan.scaffold.fabricDir).isDirectory()) {
|
|
1851
1973
|
throw new Error(
|
|
1852
1974
|
t("cli.install.diff.drift-abort", { path: plan.scaffold.fabricDir })
|
|
1853
1975
|
);
|
|
@@ -1900,23 +2022,32 @@ function resolvePersonalFabricRoot() {
|
|
|
1900
2022
|
}
|
|
1901
2023
|
async function buildInitFabricPlan(target, options) {
|
|
1902
2024
|
assertExistingDirectory3(target);
|
|
1903
|
-
const fabricDir =
|
|
1904
|
-
const agentsMdPath =
|
|
1905
|
-
const agentsMdAction =
|
|
1906
|
-
const knowledgeDir =
|
|
1907
|
-
const personalKnowledgeDir =
|
|
1908
|
-
const forensicPath =
|
|
1909
|
-
const eventsPath =
|
|
1910
|
-
const metaPath =
|
|
2025
|
+
const fabricDir = join7(target, ".fabric");
|
|
2026
|
+
const agentsMdPath = join7(target, "AGENTS.md");
|
|
2027
|
+
const agentsMdAction = existsSync5(agentsMdPath) ? "preserved" : "created";
|
|
2028
|
+
const knowledgeDir = join7(fabricDir, "knowledge");
|
|
2029
|
+
const personalKnowledgeDir = join7(resolvePersonalFabricRoot(), ".fabric", "knowledge");
|
|
2030
|
+
const forensicPath = join7(fabricDir, "forensic.json");
|
|
2031
|
+
const eventsPath = join7(fabricDir, "events.jsonl");
|
|
2032
|
+
const metaPath = join7(fabricDir, "agents.meta.json");
|
|
1911
2033
|
const replaceFabricDir = shouldReplaceWritableDirectory(fabricDir, options);
|
|
1912
|
-
const knowledgeDirAction =
|
|
2034
|
+
const knowledgeDirAction = existsSync5(knowledgeDir) ? "overwritten" : "created";
|
|
1913
2035
|
const metaClassification = classifyFreshPath(metaPath, "structural");
|
|
1914
2036
|
const eventsClassification = classifyFreshPath(eventsPath, "presence");
|
|
1915
2037
|
const forensicClassification = classifyFreshPath(forensicPath, "always-rewrite");
|
|
1916
2038
|
const metaAction = diffStateToWriteAction(metaClassification.state);
|
|
1917
2039
|
const eventsAction = diffStateToWriteAction(eventsClassification.state);
|
|
1918
2040
|
const forensicAction = diffStateToWriteAction(forensicClassification.state);
|
|
2041
|
+
const showScanProgress = process.stderr.isTTY === true;
|
|
2042
|
+
if (showScanProgress) {
|
|
2043
|
+
process.stderr.write(`${t("cli.install.scanning")}
|
|
2044
|
+
`);
|
|
2045
|
+
}
|
|
1919
2046
|
const forensicReport = await buildForensicReport(target);
|
|
2047
|
+
if (showScanProgress) {
|
|
2048
|
+
process.stderr.write(`${t("cli.install.scan-complete")}
|
|
2049
|
+
`);
|
|
2050
|
+
}
|
|
1920
2051
|
const meta = createInitialMeta();
|
|
1921
2052
|
return {
|
|
1922
2053
|
target,
|
|
@@ -1947,22 +2078,16 @@ async function executeInitFabricPlan(plan) {
|
|
|
1947
2078
|
}
|
|
1948
2079
|
mkdirSync2(plan.fabricDir, { recursive: true });
|
|
1949
2080
|
writeDefaultFabricConfig(plan.fabricDir, plan.target);
|
|
2081
|
+
writeDefaultGitignore(plan.fabricDir);
|
|
1950
2082
|
mkdirSync2(plan.knowledgeDir, { recursive: true });
|
|
1951
2083
|
for (const sub of KNOWLEDGE_SUBDIRS) {
|
|
1952
|
-
const teamSubDir =
|
|
2084
|
+
const teamSubDir = join7(plan.knowledgeDir, sub);
|
|
1953
2085
|
mkdirSync2(teamSubDir, { recursive: true });
|
|
1954
|
-
const teamGitkeep =
|
|
1955
|
-
if (!
|
|
1956
|
-
|
|
2086
|
+
const teamGitkeep = join7(teamSubDir, ".gitkeep");
|
|
2087
|
+
if (!existsSync5(teamGitkeep)) {
|
|
2088
|
+
writeFileSync2(teamGitkeep, "", "utf8");
|
|
1957
2089
|
}
|
|
1958
2090
|
}
|
|
1959
|
-
try {
|
|
1960
|
-
mkdirSync2(plan.personalKnowledgeDir, { recursive: true });
|
|
1961
|
-
for (const sub of KNOWLEDGE_SUBDIRS) {
|
|
1962
|
-
mkdirSync2(join6(plan.personalKnowledgeDir, sub), { recursive: true });
|
|
1963
|
-
}
|
|
1964
|
-
} catch {
|
|
1965
|
-
}
|
|
1966
2091
|
if (plan.metaState === "missing") {
|
|
1967
2092
|
preparePlannedPath(plan.metaPath, plan.metaAction);
|
|
1968
2093
|
await atomicWriteJson(plan.metaPath, plan.meta);
|
|
@@ -1970,11 +2095,11 @@ async function executeInitFabricPlan(plan) {
|
|
|
1970
2095
|
if (plan.eventsState === "missing") {
|
|
1971
2096
|
preparePlannedPath(plan.eventsPath, plan.eventsAction);
|
|
1972
2097
|
mkdirSync2(dirname(plan.eventsPath), { recursive: true });
|
|
1973
|
-
|
|
2098
|
+
writeFileSync2(plan.eventsPath, "", "utf8");
|
|
1974
2099
|
}
|
|
1975
2100
|
preparePlannedPath(plan.forensicPath, plan.forensicAction);
|
|
1976
2101
|
await atomicWriteJson(plan.forensicPath, plan.forensicReport);
|
|
1977
|
-
if (
|
|
2102
|
+
if (existsSync5(plan.eventsPath)) {
|
|
1978
2103
|
const applied = [];
|
|
1979
2104
|
const canonical = [];
|
|
1980
2105
|
const drifted = [];
|
|
@@ -2126,9 +2251,17 @@ async function executeInitStagePlan(plan, stageName) {
|
|
|
2126
2251
|
installResults.push(...await runBestEffort("skill-install", () => installFabricArchiveSkill(plan.target)));
|
|
2127
2252
|
installResults.push(...await runBestEffort("skill-review-install", () => installFabricReviewSkill(plan.target)));
|
|
2128
2253
|
installResults.push(...await runBestEffort("skill-import-install", () => installFabricImportSkill(plan.target)));
|
|
2254
|
+
installResults.push(...await runBestEffort("skill-sync-install", () => installFabricSyncSkill(plan.target)));
|
|
2255
|
+
installResults.push(...await runBestEffort("skill-store-install", () => installFabricStoreSkill(plan.target)));
|
|
2256
|
+
installResults.push(...await runBestEffort("skill-audit-install", () => installFabricAuditSkill(plan.target)));
|
|
2257
|
+
installResults.push(...await runBestEffort("skill-connect-install", () => installFabricConnectSkill(plan.target)));
|
|
2258
|
+
installResults.push(...await runBestEffort("skill-shared-lib", () => installSharedSkillLib(plan.target)));
|
|
2129
2259
|
installResults.push(...await runBestEffort("hook-script", () => installArchiveHintHook(plan.target)));
|
|
2130
2260
|
installResults.push(...await runBestEffort("hook-broad-script", () => installKnowledgeHintBroadHook(plan.target)));
|
|
2131
2261
|
installResults.push(...await runBestEffort("hook-narrow-script", () => installKnowledgeHintNarrowHook(plan.target)));
|
|
2262
|
+
installResults.push(...await runBestEffort("hook-cite-policy-evict-script", () => installCitePolicyEvictHook(plan.target)));
|
|
2263
|
+
installResults.push(...await runBestEffort("hook-session-end-script", () => installSessionEndMarkerHook(plan.target)));
|
|
2264
|
+
installResults.push(...await runBestEffort("hook-post-tooluse-script", () => installPostTooluseMutationHook(plan.target)));
|
|
2132
2265
|
installResults.push(...await runBestEffort("hook-lib", () => installHookLibs(plan.target)));
|
|
2133
2266
|
installResults.push(await runBestEffortSingle("claude-hook-config", () => mergeClaudeCodeHookConfig(plan.target)));
|
|
2134
2267
|
installResults.push(await runBestEffortSingle("codex-hook-config", () => mergeCodexHookConfig(plan.target)));
|
|
@@ -2184,7 +2317,7 @@ async function executeInitStagePlan(plan, stageName) {
|
|
|
2184
2317
|
}
|
|
2185
2318
|
}
|
|
2186
2319
|
function shouldReplaceWritableDirectory(path, _options) {
|
|
2187
|
-
if (!
|
|
2320
|
+
if (!existsSync5(path)) {
|
|
2188
2321
|
return false;
|
|
2189
2322
|
}
|
|
2190
2323
|
if (statSync4(path).isDirectory()) {
|
|
@@ -2193,7 +2326,7 @@ function shouldReplaceWritableDirectory(path, _options) {
|
|
|
2193
2326
|
return false;
|
|
2194
2327
|
}
|
|
2195
2328
|
function classifyFreshPath(path, strategy) {
|
|
2196
|
-
if (!
|
|
2329
|
+
if (!existsSync5(path)) {
|
|
2197
2330
|
return { path, state: "missing" };
|
|
2198
2331
|
}
|
|
2199
2332
|
let stat;
|
|
@@ -2213,7 +2346,7 @@ function classifyFreshPath(path, strategy) {
|
|
|
2213
2346
|
return { path, state: "present-canonical" };
|
|
2214
2347
|
}
|
|
2215
2348
|
try {
|
|
2216
|
-
const raw =
|
|
2349
|
+
const raw = readFileSync4(path, "utf8");
|
|
2217
2350
|
const parsed = JSON.parse(raw);
|
|
2218
2351
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
2219
2352
|
return { path, state: "user-modified", reason: "not a JSON object" };
|
|
@@ -2242,7 +2375,7 @@ function formatDiffFileState(state) {
|
|
|
2242
2375
|
}
|
|
2243
2376
|
function preparePlannedPath(path, action) {
|
|
2244
2377
|
mkdirSync2(dirname(path), { recursive: true });
|
|
2245
|
-
if (action === "overwritten" &&
|
|
2378
|
+
if (action === "overwritten" && existsSync5(path)) {
|
|
2246
2379
|
rmSync2(path, { recursive: true, force: true });
|
|
2247
2380
|
}
|
|
2248
2381
|
}
|
|
@@ -2396,19 +2529,19 @@ function normalizeTarget3(targetInput) {
|
|
|
2396
2529
|
return isAbsolute3(targetInput) ? targetInput : resolve3(process.cwd(), targetInput);
|
|
2397
2530
|
}
|
|
2398
2531
|
function assertExistingDirectory3(target) {
|
|
2399
|
-
if (!
|
|
2532
|
+
if (!existsSync5(target) || !statSync4(target).isDirectory()) {
|
|
2400
2533
|
throw new Error(`Target must be an existing directory: ${target}`);
|
|
2401
2534
|
}
|
|
2402
2535
|
}
|
|
2403
2536
|
function detectPackageManager(cwd) {
|
|
2404
2537
|
const workspaceRoot = resolve3(cwd);
|
|
2405
|
-
if (
|
|
2538
|
+
if (existsSync5(join7(workspaceRoot, "pnpm-lock.yaml"))) {
|
|
2406
2539
|
return "pnpm";
|
|
2407
2540
|
}
|
|
2408
|
-
if (
|
|
2541
|
+
if (existsSync5(join7(workspaceRoot, "yarn.lock"))) {
|
|
2409
2542
|
return "yarn";
|
|
2410
2543
|
}
|
|
2411
|
-
if (
|
|
2544
|
+
if (existsSync5(join7(workspaceRoot, "package-lock.json"))) {
|
|
2412
2545
|
return "npm";
|
|
2413
2546
|
}
|
|
2414
2547
|
return "npm";
|