@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.
Files changed (49) hide show
  1. package/dist/{chunk-PWLW3B57.js → chunk-2CY4BMTH.js} +5 -1
  2. package/dist/chunk-5LQIHYFC.js +64 -0
  3. package/dist/chunk-5ZUMLCD5.js +248 -0
  4. package/dist/{chunk-WWNXR34K.js → chunk-BO4XIZWZ.js} +8 -1
  5. package/dist/chunk-EOT63RDH.js +36 -0
  6. package/dist/{chunk-BATF4PEJ.js → chunk-F6ITRM7T.js} +4 -4
  7. package/dist/{chunk-WU6GAPKH.js → chunk-H3FE6VIK.js} +3 -5
  8. package/dist/{chunk-MF3OTILQ.js → chunk-XC5RUHLK.js} +29 -8
  9. package/dist/chunk-XCBVSGCS.js +25 -0
  10. package/dist/{chunk-F46ORPOA.js → chunk-XHHCRDIR.js} +149 -7
  11. package/dist/{config-XJIPZNUP.js → config-VJMXCLXW.js} +3 -3
  12. package/dist/{doctor-QVNPHLJK.js → doctor-J4O3X54I.js} +154 -30
  13. package/dist/index.js +57 -16
  14. package/dist/{install-2HDO5FTQ.js → install-BULNDUIM.js} +241 -108
  15. package/dist/{metrics-ACEQFPDU.js → metrics-RER6NLFC.js} +22 -9
  16. package/dist/{onboard-coverage-MFCAEBDO.js → onboard-coverage-JWQWDZW7.js} +1 -1
  17. package/dist/{plan-context-hint-FC6P3WFE.js → plan-context-hint-CHVZGOZ5.js} +21 -8
  18. package/dist/{scope-explain-2F2R5URO.js → scope-explain-BWRWBCCP.js} +19 -5
  19. package/dist/{status-GLQWLWH6.js → status-PANEGKU2.js} +17 -6
  20. package/dist/store-66NK2FTQ.js +443 -0
  21. package/dist/sync-EA5HZMXM.js +395 -0
  22. package/dist/{uninstall-TAXSUSKH.js → uninstall-F75MPKQC.js} +61 -4
  23. package/dist/whoami-66YKY5DZ.js +47 -0
  24. package/package.json +3 -3
  25. package/templates/hooks/cite-policy-evict.cjs +412 -160
  26. package/templates/hooks/configs/claude-code.json +17 -2
  27. package/templates/hooks/configs/codex-hooks.json +14 -2
  28. package/templates/hooks/configs/cursor-hooks.json +14 -2
  29. package/templates/hooks/fabric-hint.cjs +247 -19
  30. package/templates/hooks/knowledge-hint-broad.cjs +176 -10
  31. package/templates/hooks/knowledge-hint-narrow.cjs +64 -5
  32. package/templates/hooks/lib/injection-log.cjs +91 -0
  33. package/templates/hooks/lib/state-store.cjs +30 -11
  34. package/templates/hooks/post-tooluse-mutation.cjs +285 -0
  35. package/templates/hooks/session-end-marker.cjs +140 -0
  36. package/templates/skills/fabric-archive/SKILL.md +7 -1
  37. package/templates/skills/fabric-audit/SKILL.md +53 -0
  38. package/templates/skills/fabric-connect/SKILL.md +48 -0
  39. package/templates/skills/fabric-review/SKILL.md +2 -0
  40. package/templates/skills/fabric-review/ref/cite-contract.md +56 -0
  41. package/templates/skills/fabric-store/SKILL.md +44 -0
  42. package/dist/chunk-HFQVXY6P.js +0 -86
  43. package/dist/chunk-L4Q55UC4.js +0 -52
  44. package/dist/chunk-LFIKMVY7.js +0 -27
  45. package/dist/chunk-RYAFBNES.js +0 -33
  46. package/dist/chunk-T5RPGCCM.js +0 -40
  47. package/dist/store-XTSE5TY6.js +0 -105
  48. package/dist/sync-BJCWDPNC.js +0 -245
  49. 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-F46ORPOA.js";
27
+ } from "./chunk-XHHCRDIR.js";
23
28
  import {
24
29
  displayWidth,
25
30
  padEnd,
26
31
  paint
27
- } from "./chunk-WWNXR34K.js";
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-BATF4PEJ.js";
39
+ } from "./chunk-F6ITRM7T.js";
35
40
  import {
36
41
  detectClientSupports
37
- } from "./chunk-MF3OTILQ.js";
42
+ } from "./chunk-XC5RUHLK.js";
38
43
  import {
44
+ getProjectTranslator,
39
45
  t
40
- } from "./chunk-PWLW3B57.js";
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-RYAFBNES.js";
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 existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync3, rmSync as rmSync2, statSync as statSync4, writeFileSync } from "fs";
53
- import { dirname, isAbsolute as isAbsolute3, join as join6, resolve as resolve3 } from "path";
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 join3 } from "path";
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 hash = createHash("sha256").update(email.toLowerCase()).digest("hex").slice(0, 12);
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 join2 } from "path";
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 = join2(options.globalRoot, STORES_ROOT_DIR, options.personalStoreUuid);
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
- execFileSync2("git", ["clone", url, dest], { stdio: ["ignore", "ignore", "pipe"] });
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 = join3(globalRoot, STORES_ROOT_DIR2);
391
+ const storesRoot = join4(globalRoot, STORES_ROOT_DIR2);
326
392
  mkdirSync(storesRoot, { recursive: true });
327
- const tmp = mkdtempSync(join3(tmpdir(), "fabric-clone-"));
328
- const cloneDest = join3(tmp, "store");
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 Error(`cloned store at ${url} has no valid store.json (not a Fabric store)`);
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 = join3(storesRoot, identity.store_uuid);
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 Error("global config missing after install");
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 Error(`global install failed at step '${result.receipt.failedStep}': ${result.receipt.error}`);
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 existsSync2, readdirSync, readFileSync, statSync as statSync2 } from "fs";
365
- import { join as join4 } from "path";
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 = join4(target, "README.md");
370
- if (existsSync2(readmePath)) {
445
+ const readmePath = join5(target, "README.md");
446
+ if (existsSync3(readmePath)) {
371
447
  try {
372
- samples.push(readFileSync(readmePath, "utf8"));
448
+ samples.push(readFileSync2(readmePath, "utf8"));
373
449
  } catch {
374
450
  }
375
451
  }
376
- const docsDir = join4(target, "docs");
377
- if (existsSync2(docsDir)) {
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(readFileSync(join4(docsDir, entry.name), "utf8"));
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 existsSync3, readdirSync as readdirSync2, readFileSync as readFileSync2, statSync as statSync3 } from "fs";
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 join5, posix, relative, resolve as resolve2, sep } from "path";
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 = join5(current, entry.name);
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 (!existsSync3(target) || !statSync3(target).isDirectory()) {
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 = join5(target, ...entryPoint.path.split("/"));
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 = readFileSync2(path, "utf8").split(/\r?\n/);
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 = join5(target, "package.json");
690
- if (!existsSync3(packageJsonPath)) {
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(readFileSync2(packageJsonPath, "utf8"));
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 = join5(target, "README.md");
1031
- const hasContributing = existsSync3(join5(target, "CONTRIBUTING.md"));
1032
- if (!existsSync3(readmePath)) {
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 = readFileSync2(readmePath, "utf8");
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
- const recommendations = [];
1496
- if (frameworkKind === "cocos-creator") {
1497
- recommendations.push("\u5EFA\u8BAE\u5411\u7528\u6237\u786E\u8BA4 Cocos Creator Component \u751F\u547D\u5468\u671F(onLoad/onEnable/start)\u987A\u5E8F\u3002");
1498
- recommendations.push("\u5EFA\u8BAE\u8BE2\u95EE assets/prefabs \u548C assets/scenes \u662F\u5426\u5C5E\u4E8E @HUMAN \u4FDD\u62A4\u533A\u57DF\u3002");
1499
- if ((topology.by_ext[".meta"] ?? 0) > 0) {
1500
- recommendations.push("\u68C0\u6D4B\u5230 .meta \u6587\u4EF6,\u5EFA\u8BAE\u5728 @HUMAN \u9501\u5B9A .meta \u4E0D\u88AB AI \u6539\u52A8\u3002");
1501
- }
1502
- } else if (frameworkKind === "next") {
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 = join5(target, "package.json");
1518
- if (existsSync3(packageJsonPath)) {
1582
+ const packageJsonPath = join6(target, "package.json");
1583
+ if (existsSync4(packageJsonPath)) {
1519
1584
  try {
1520
- const packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf8"));
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.1.0-rc.2" : "unknown";
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 = join6("node_modules", "@fenglimg", "fabric-server", "dist", "index.js");
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 = join6(target, ".fabric", "agents.meta.json");
1597
- if (!existsSync4(metaPath)) {
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 = join6(target, ".fabric", "agents.meta.json");
1640
- if (!existsSync4(metaPath)) {
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 = join6(fabricDir, "fabric-config.json");
1711
- if (existsSync4(target)) return;
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
- writeFileSync(target, JSON.stringify(FABRIC_CONFIG_DEFAULTS, null, 2) + "\n", "utf8");
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 (existsSync4(plan.scaffold.fabricDir) && !statSync4(plan.scaffold.fabricDir).isDirectory()) {
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 = join6(target, ".fabric");
1904
- const agentsMdPath = join6(target, "AGENTS.md");
1905
- const agentsMdAction = existsSync4(agentsMdPath) ? "preserved" : "created";
1906
- const knowledgeDir = join6(fabricDir, "knowledge");
1907
- const personalKnowledgeDir = join6(resolvePersonalFabricRoot(), ".fabric", "knowledge");
1908
- const forensicPath = join6(fabricDir, "forensic.json");
1909
- const eventsPath = join6(fabricDir, "events.jsonl");
1910
- const metaPath = join6(fabricDir, "agents.meta.json");
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 = existsSync4(knowledgeDir) ? "overwritten" : "created";
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 = join6(plan.knowledgeDir, sub);
2084
+ const teamSubDir = join7(plan.knowledgeDir, sub);
1953
2085
  mkdirSync2(teamSubDir, { recursive: true });
1954
- const teamGitkeep = join6(teamSubDir, ".gitkeep");
1955
- if (!existsSync4(teamGitkeep)) {
1956
- writeFileSync(teamGitkeep, "", "utf8");
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
- writeFileSync(plan.eventsPath, "", "utf8");
2098
+ writeFileSync2(plan.eventsPath, "", "utf8");
1974
2099
  }
1975
2100
  preparePlannedPath(plan.forensicPath, plan.forensicAction);
1976
2101
  await atomicWriteJson(plan.forensicPath, plan.forensicReport);
1977
- if (existsSync4(plan.eventsPath)) {
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 (!existsSync4(path)) {
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 (!existsSync4(path)) {
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 = readFileSync3(path, "utf8");
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" && existsSync4(path)) {
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 (!existsSync4(target) || !statSync4(target).isDirectory()) {
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 (existsSync4(join6(workspaceRoot, "pnpm-lock.yaml"))) {
2538
+ if (existsSync5(join7(workspaceRoot, "pnpm-lock.yaml"))) {
2406
2539
  return "pnpm";
2407
2540
  }
2408
- if (existsSync4(join6(workspaceRoot, "yarn.lock"))) {
2541
+ if (existsSync5(join7(workspaceRoot, "yarn.lock"))) {
2409
2542
  return "yarn";
2410
2543
  }
2411
- if (existsSync4(join6(workspaceRoot, "package-lock.json"))) {
2544
+ if (existsSync5(join7(workspaceRoot, "package-lock.json"))) {
2412
2545
  return "npm";
2413
2546
  }
2414
2547
  return "npm";