@fenglimg/fabric-cli 2.2.0-rc.9 → 2.3.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.
Files changed (76) hide show
  1. package/README.md +2 -2
  2. package/dist/audit-PURSJJFH.js +734 -0
  3. package/dist/{chunk-YM4XATJF.js → chunk-722JU5BP.js} +2 -0
  4. package/dist/{chunk-QPAW6IYT.js → chunk-7V4XMLQ2.js} +3 -3
  5. package/dist/{chunk-7ZDXBOOU.js → chunk-ACSMNX3V.js} +44 -128
  6. package/dist/{chunk-PTGQAZEW.js → chunk-GGDVZCD6.js} +2 -4
  7. package/dist/{chunk-EOT63RDH.js → chunk-I5F5BHWI.js} +9 -0
  8. package/dist/chunk-PP7QVRXH.js +565 -0
  9. package/dist/chunk-SL77FXX7.js +54 -0
  10. package/dist/{chunk-3D7B2UAZ.js → chunk-VQKXTMWH.js} +44 -4
  11. package/dist/doctor-S6KPGS35.js +27 -0
  12. package/dist/index.js +91 -81
  13. package/dist/{info-7FKBTMVO.js → info-NJEY26H6.js} +91 -46
  14. package/dist/{context-7NUKXDB6.js → inspect-5YZMJPFM.js} +11 -11
  15. package/dist/{install-v2-I6PJ6IFT.js → install-v2-KGIDII4H.js} +163 -364
  16. package/dist/{plan-context-hint-G75R4P4J.js → plan-context-hint-5TNGH3R4.js} +1 -1
  17. package/dist/{store-HOCORVL3.js → store-GF4SFBMJ.js} +155 -57
  18. package/dist/{sync-DT5UJMMR.js → sync-3XCIRDPK.js} +3 -4
  19. package/dist/{uninstall-IFN2KYBK.js → uninstall-BG4ML4FC.js} +39 -10
  20. package/package.json +3 -7
  21. package/templates/hooks/cite-policy-evict.cjs +1 -1
  22. package/templates/hooks/configs/claude-code.json +1 -5
  23. package/templates/hooks/configs/codex-hooks.json +1 -5
  24. package/templates/hooks/fabric-hint.cjs +346 -138
  25. package/templates/hooks/knowledge-hint-broad.cjs +265 -75
  26. package/templates/hooks/knowledge-hint-narrow.cjs +3 -3
  27. package/templates/hooks/knowledge-pretooluse.cjs +111 -0
  28. package/templates/hooks/lib/banner-i18n.cjs +31 -12
  29. package/templates/hooks/lib/bindings-snapshot-reader.cjs +1 -1
  30. package/templates/hooks/lib/event-writer.cjs +79 -0
  31. package/templates/hooks/lib/nudge-policy.cjs +11 -0
  32. package/templates/hooks/lib/theme.cjs +62 -0
  33. package/templates/hooks/post-tooluse-mutation.cjs +28 -39
  34. package/templates/skills/fabric-archive/SKILL.md +43 -12
  35. package/templates/skills/fabric-archive/ref/dry-run-scope.md +1 -1
  36. package/templates/skills/fabric-archive/ref/i18n-policy.md +1 -1
  37. package/templates/skills/fabric-archive/ref/phase-1-5-onboard.md +5 -5
  38. package/templates/skills/fabric-archive/ref/phase-1-cross-session.md +2 -2
  39. package/templates/skills/fabric-archive/ref/phase-2-5-viability.md +1 -1
  40. package/templates/skills/fabric-archive/ref/phase-3-5-scope.md +1 -1
  41. package/templates/skills/fabric-archive/ref/phase-3-6-related-edges.md +1 -1
  42. package/templates/skills/fabric-archive/ref/phase-3-classify.md +1 -1
  43. package/templates/skills/fabric-archive/ref/phase-4-5-emit.md +1 -1
  44. package/templates/skills/fabric-archive/ref/phase-4-mcp-persist.md +6 -5
  45. package/templates/skills/{fabric-import/ref/checkpoint-state.md → fabric-archive/ref/source-checkpoint.md} +3 -3
  46. package/templates/skills/{fabric-import/ref/phase-3-dedup.md → fabric-archive/ref/source-dedup.md} +4 -4
  47. package/templates/skills/{fabric-import/ref/phase-2-mining.md → fabric-archive/ref/source-mining.md} +20 -20
  48. package/templates/skills/{fabric-import/ref/output-contract.md → fabric-archive/ref/source-output-contract.md} +3 -3
  49. package/templates/skills/{fabric-import/ref/state-recovery.md → fabric-archive/ref/source-state-recovery.md} +2 -2
  50. package/templates/skills/{fabric-import/ref/worked-examples.md → fabric-archive/ref/source-worked-examples.md} +10 -10
  51. package/templates/skills/fabric-archive/ref/worked-examples.md +3 -3
  52. package/templates/skills/fabric-review/SKILL.md +28 -15
  53. package/templates/skills/fabric-review/ref/cite-contract.md +2 -2
  54. package/templates/skills/fabric-review/ref/modify-flow.md +13 -1
  55. package/templates/skills/fabric-review/ref/per-mode-flows.md +5 -5
  56. package/templates/skills/fabric-review/ref/relate-mode.md +33 -0
  57. package/templates/skills/fabric-review/ref/retire-mode.md +47 -0
  58. package/templates/skills/fabric-review/ref/semantic-check.md +1 -1
  59. package/templates/skills/fabric-review/ref/worked-examples.md +5 -5
  60. package/templates/skills/fabric-store/SKILL.md +12 -27
  61. package/templates/skills/fabric-sync/SKILL.md +16 -35
  62. package/templates/skills/lib/shared-policy.md +6 -4
  63. package/dist/chunk-27HK6H5Y.js +0 -69
  64. package/dist/chunk-E7HJUU34.js +0 -1096
  65. package/dist/chunk-NLNH64A3.js +0 -43
  66. package/dist/chunk-QFIVFZRH.js +0 -13
  67. package/dist/doctor-MDTZWKBK.js +0 -24
  68. package/dist/metrics-HMFH4YHK.js +0 -135
  69. package/dist/scope-explain-HLJZ2M33.js +0 -48
  70. package/dist/status-4R3TM4FJ.js +0 -37
  71. package/dist/whoami-ITGEFWH4.js +0 -49
  72. package/templates/skills/fabric/SKILL.md +0 -100
  73. package/templates/skills/fabric-audit/SKILL.md +0 -63
  74. package/templates/skills/fabric-connect/SKILL.md +0 -48
  75. package/templates/skills/fabric-import/SKILL.md +0 -151
  76. package/templates/skills/fabric-import/ref/i18n-policy.md +0 -78
@@ -97,6 +97,8 @@ async function runPlanContextHint(opts) {
97
97
  () => ({
98
98
  by_type: {},
99
99
  by_layer: { team: 0, personal: 0, project: 0 },
100
+ broad_by_type: {},
101
+ narrow_total: 0,
100
102
  dropped_other_project: 0,
101
103
  total: 0
102
104
  })
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  loadProjectConfig,
4
4
  saveProjectConfig
5
- } from "./chunk-QFIVFZRH.js";
5
+ } from "./chunk-I5F5BHWI.js";
6
6
  import {
7
7
  loadGlobalConfig,
8
8
  resolveGlobalRoot,
@@ -233,7 +233,7 @@ function assertStoreMountable(uuid, globalRoot = resolveGlobalRoot(), mountName)
233
233
  const storeDir = candidates.find((dir) => existsSync(join(dir, "store.json"))) ?? candidates[0];
234
234
  if (!existsSync(join(storeDir, "store.json"))) {
235
235
  throw new Error(
236
- `cannot mount store ${uuid}: no store tree at ${storeDir} \u2014 clone it first (\`fabric install --global --url <remote>\`) or create it locally, then re-run \`fabric store add\`. Refusing to register a phantom store.`
236
+ `cannot mount store ${uuid}: no store tree at ${storeDir} \u2014 clone it first (\`fabric install --global --url <remote>\`) or create it locally, then re-run \`fabric store mount\`. Refusing to register a phantom store.`
237
237
  );
238
238
  }
239
239
  }
@@ -296,7 +296,7 @@ async function storeBind(projectRoot, entry, options = {}) {
296
296
  const storeDir = resolveStoreDir(entry.id, globalRoot);
297
297
  if (storeDir === null) {
298
298
  throw new Error(
299
- `cannot bind project '${options.project}': store '${entry.id}' is not mounted \u2014 mount it first (\`fabric store add\` / \`fabric install --global --url <remote>\`)`
299
+ `cannot bind project '${options.project}': store '${entry.id}' is not mounted \u2014 mount it first (\`fabric store mount\` / \`fabric install --global --url <remote>\`)`
300
300
  );
301
301
  }
302
302
  if (!await storeHasProject(storeDir, options.project)) {
@@ -52,21 +52,14 @@ import {
52
52
  BOOTSTRAP_MARKER_END,
53
53
  BOOTSTRAP_REGEX
54
54
  } from "@fenglimg/fabric-shared/templates/bootstrap-canonical";
55
- var SKILL_ROUTER_TEMPLATE_REL = "skills/fabric/SKILL.md";
56
- var ROUTER_INTENT_MARKER_BEGIN = "<!-- fabric:router-intent:begin -->";
57
- var ROUTER_INTENT_MARKER_END = "<!-- fabric:router-intent:end -->";
58
- var ROUTER_INTENT_GENERATED_NOTE = "<!-- \u672C\u5757\u7531 `fabric install` \u4ECE 7 \u4E2A leaf skill \u7684 description Triggers \u5B50\u53E5\u751F\u6210\u3002\u4E25\u7981\u624B\u7F16;\u6539 leaf description \u540E\u91CD\u8DD1 `fabric install`\u3002 -->";
59
- var ROUTER_INTENT_REGEX = /<!-- fabric:router-intent:begin -->[\s\S]*?<!-- fabric:router-intent:end -->/u;
60
55
  var SKILL_TEMPLATE_REL = "skills/fabric-archive/SKILL.md";
61
56
  var SKILL_REVIEW_TEMPLATE_REL = "skills/fabric-review/SKILL.md";
62
- var SKILL_IMPORT_TEMPLATE_REL = "skills/fabric-import/SKILL.md";
63
57
  var SKILL_SYNC_TEMPLATE_REL = "skills/fabric-sync/SKILL.md";
64
58
  var SKILL_STORE_TEMPLATE_REL = "skills/fabric-store/SKILL.md";
65
- var SKILL_AUDIT_TEMPLATE_REL = "skills/fabric-audit/SKILL.md";
66
- var SKILL_CONNECT_TEMPLATE_REL = "skills/fabric-connect/SKILL.md";
67
59
  var HOOK_SCRIPT_TEMPLATE_REL = "hooks/fabric-hint.cjs";
68
60
  var HOOK_BROAD_SCRIPT_TEMPLATE_REL = "hooks/knowledge-hint-broad.cjs";
69
61
  var HOOK_NARROW_SCRIPT_TEMPLATE_REL = "hooks/knowledge-hint-narrow.cjs";
62
+ var HOOK_PRETOOLUSE_SCRIPT_TEMPLATE_REL = "hooks/knowledge-pretooluse.cjs";
70
63
  var HOOK_CITE_EVICT_SCRIPT_TEMPLATE_REL = "hooks/cite-policy-evict.cjs";
71
64
  var HOOK_SESSION_END_SCRIPT_TEMPLATE_REL = "hooks/session-end-marker.cjs";
72
65
  var HOOK_POST_TOOLUSE_SCRIPT_TEMPLATE_REL = "hooks/post-tooluse-mutation.cjs";
@@ -74,12 +67,6 @@ var HOOK_LIB_TEMPLATE_DIR_REL = "hooks/lib";
74
67
  var CLAUDE_HOOK_CONFIG_TEMPLATE_REL = "hooks/configs/claude-code.json";
75
68
  var CODEX_HOOK_CONFIG_TEMPLATE_REL = "hooks/configs/codex-hooks.json";
76
69
  var SKILL_DESTINATIONS = {
77
- // B2 skill-router: the fabric/ router skill — single-file (no ref/), installed
78
- // alongside the 7 leaf skills as the human-facing dispatch entry point.
79
- fabricRouter: [
80
- ".claude/skills/fabric/SKILL.md",
81
- ".codex/skills/fabric/SKILL.md"
82
- ],
83
70
  fabricArchive: [
84
71
  ".claude/skills/fabric-archive/SKILL.md",
85
72
  ".codex/skills/fabric-archive/SKILL.md"
@@ -88,10 +75,6 @@ var SKILL_DESTINATIONS = {
88
75
  ".claude/skills/fabric-review/SKILL.md",
89
76
  ".codex/skills/fabric-review/SKILL.md"
90
77
  ],
91
- fabricImport: [
92
- ".claude/skills/fabric-import/SKILL.md",
93
- ".codex/skills/fabric-import/SKILL.md"
94
- ],
95
78
  // v2.1.0-rc.1 P4 (S46): fabric-sync mirrors the sibling skills' 2-client
96
79
  // coverage (Claude Code + Codex CLI surface a Skills directory).
97
80
  fabricSync: [
@@ -103,26 +86,9 @@ var SKILL_DESTINATIONS = {
103
86
  fabricStore: [
104
87
  ".claude/skills/fabric-store/SKILL.md",
105
88
  ".codex/skills/fabric-store/SKILL.md"
106
- ],
107
- // v2.2 SK1-audit (W2-T5): fabric-audit semantic-deprecation skill, same
108
- // 2-client coverage as the sibling skills.
109
- fabricAudit: [
110
- ".claude/skills/fabric-audit/SKILL.md",
111
- ".codex/skills/fabric-audit/SKILL.md"
112
- ],
113
- // v2.2 SK2-connect (W3-T2): fabric-connect knowledge-graph relation skill.
114
- fabricConnect: [
115
- ".claude/skills/fabric-connect/SKILL.md",
116
- ".codex/skills/fabric-connect/SKILL.md"
117
89
  ]
118
90
  };
119
91
  var FABRIC_SKILL_INSTALL_SPECS = {
120
- fabricRouter: {
121
- slug: "fabric",
122
- templateRel: SKILL_ROUTER_TEMPLATE_REL,
123
- destinations: SKILL_DESTINATIONS.fabricRouter,
124
- step: "skill-router"
125
- },
126
92
  fabricArchive: {
127
93
  slug: "fabric-archive",
128
94
  templateRel: SKILL_TEMPLATE_REL,
@@ -137,13 +103,6 @@ var FABRIC_SKILL_INSTALL_SPECS = {
137
103
  step: "skill-review",
138
104
  includeRefFiles: true
139
105
  },
140
- fabricImport: {
141
- slug: "fabric-import",
142
- templateRel: SKILL_IMPORT_TEMPLATE_REL,
143
- destinations: SKILL_DESTINATIONS.fabricImport,
144
- step: "skill-import",
145
- includeRefFiles: true
146
- },
147
106
  fabricSync: {
148
107
  slug: "fabric-sync",
149
108
  templateRel: SKILL_SYNC_TEMPLATE_REL,
@@ -155,23 +114,22 @@ var FABRIC_SKILL_INSTALL_SPECS = {
155
114
  templateRel: SKILL_STORE_TEMPLATE_REL,
156
115
  destinations: SKILL_DESTINATIONS.fabricStore,
157
116
  step: "skill-store"
158
- },
159
- fabricAudit: {
160
- slug: "fabric-audit",
161
- templateRel: SKILL_AUDIT_TEMPLATE_REL,
162
- destinations: SKILL_DESTINATIONS.fabricAudit,
163
- step: "skill-audit"
164
- },
165
- fabricConnect: {
166
- slug: "fabric-connect",
167
- templateRel: SKILL_CONNECT_TEMPLATE_REL,
168
- destinations: SKILL_DESTINATIONS.fabricConnect,
169
- step: "skill-connect"
170
117
  }
171
118
  };
172
119
  var DEPRECATED_SKILL_DIRS = [
173
120
  ".claude/skills/fabric-init",
174
- ".codex/skills/fabric-init"
121
+ ".codex/skills/fabric-init",
122
+ // W3-C (skill collapse): the router + 3 folded leaves are retired. import→
123
+ // archive source mode, audit→review retire, connect→review relate. Sweep the
124
+ // residual installed copies on the next `fabric install`.
125
+ ".claude/skills/fabric",
126
+ ".codex/skills/fabric",
127
+ ".claude/skills/fabric-import",
128
+ ".codex/skills/fabric-import",
129
+ ".claude/skills/fabric-audit",
130
+ ".codex/skills/fabric-audit",
131
+ ".claude/skills/fabric-connect",
132
+ ".codex/skills/fabric-connect"
175
133
  ];
176
134
  var HOOK_SCRIPT_DESTINATIONS = {
177
135
  fabricHint: [
@@ -186,6 +144,14 @@ var HOOK_SCRIPT_DESTINATIONS = {
186
144
  ".claude/hooks/knowledge-hint-narrow.cjs",
187
145
  ".codex/hooks/knowledge-hint-narrow.cjs"
188
146
  ],
147
+ // ux-w2-6: the single PreToolUse orchestrator. Requires knowledge-hint-narrow
148
+ // + cite-policy-evict as libs (both still copied) and merges their output into
149
+ // one envelope, so the Edit|Write|MultiEdit matcher carries ONE command (was
150
+ // two = 双弹).
151
+ knowledgePretoolUse: [
152
+ ".claude/hooks/knowledge-pretooluse.cjs",
153
+ ".codex/hooks/knowledge-pretooluse.cjs"
154
+ ],
189
155
  // v2.0.0-rc.34 TASK-06: Claude Code — UserPromptSubmit cite-policy long-
190
156
  // session evict sidecar.
191
157
  // v2.0.0-rc.37 NEW-21: extended to Codex SessionStart slot.
@@ -240,6 +206,8 @@ var FABRIC_HOOK_COMMAND_PATHS = {
240
206
  fabricHint: "${CLAUDE_PROJECT_DIR}/.claude/hooks/fabric-hint.cjs",
241
207
  knowledgeHintBroad: "${CLAUDE_PROJECT_DIR}/.claude/hooks/knowledge-hint-broad.cjs",
242
208
  knowledgeHintNarrow: "${CLAUDE_PROJECT_DIR}/.claude/hooks/knowledge-hint-narrow.cjs",
209
+ // ux-w2-6: the single PreToolUse orchestrator command (wired in claude-code.json).
210
+ knowledgePretoolUse: "${CLAUDE_PROJECT_DIR}/.claude/hooks/knowledge-pretooluse.cjs",
243
211
  // F3: the UserPromptSubmit cite-policy-evict hook must be a known fabric
244
212
  // command so uninstall prunes it (matches the literal in claude-code.json).
245
213
  citePolicyEvict: "${CLAUDE_PROJECT_DIR}/.claude/hooks/cite-policy-evict.cjs",
@@ -251,6 +219,7 @@ var FABRIC_HOOK_COMMAND_PATHS = {
251
219
  fabricHint: '"$(git rev-parse --show-toplevel)/.codex/hooks/fabric-hint.cjs"',
252
220
  knowledgeHintBroad: '"$(git rev-parse --show-toplevel)/.codex/hooks/knowledge-hint-broad.cjs"',
253
221
  knowledgeHintNarrow: '"$(git rev-parse --show-toplevel)/.codex/hooks/knowledge-hint-narrow.cjs"',
222
+ knowledgePretoolUse: '"$(git rev-parse --show-toplevel)/.codex/hooks/knowledge-pretooluse.cjs"',
254
223
  citePolicyEvict: '"$(git rev-parse --show-toplevel)/.codex/hooks/cite-policy-evict.cjs"',
255
224
  sessionEndMarker: '"$(git rev-parse --show-toplevel)/.codex/hooks/session-end-marker.cjs"',
256
225
  postTooluseMutation: '"$(git rev-parse --show-toplevel)/.codex/hooks/post-tooluse-mutation.cjs"'
@@ -308,81 +277,12 @@ async function installFabricArchiveSkill(projectRoot, _options = {}) {
308
277
  async function installFabricReviewSkill(projectRoot, _options = {}) {
309
278
  return installFabricSkill(projectRoot, FABRIC_SKILL_INSTALL_SPECS.fabricReview);
310
279
  }
311
- async function installFabricImportSkill(projectRoot, _options = {}) {
312
- return installFabricSkill(projectRoot, FABRIC_SKILL_INSTALL_SPECS.fabricImport);
313
- }
314
280
  async function installFabricSyncSkill(projectRoot, _options = {}) {
315
281
  return installFabricSkill(projectRoot, FABRIC_SKILL_INSTALL_SPECS.fabricSync);
316
282
  }
317
283
  async function installFabricStoreSkill(projectRoot, _options = {}) {
318
284
  return installFabricSkill(projectRoot, FABRIC_SKILL_INSTALL_SPECS.fabricStore);
319
285
  }
320
- async function installFabricAuditSkill(projectRoot, _options = {}) {
321
- return installFabricSkill(projectRoot, FABRIC_SKILL_INSTALL_SPECS.fabricAudit);
322
- }
323
- async function installFabricConnectSkill(projectRoot, _options = {}) {
324
- return installFabricSkill(projectRoot, FABRIC_SKILL_INSTALL_SPECS.fabricConnect);
325
- }
326
- function extractSkillMdDescription(skillMd) {
327
- const fm = skillMd.match(/^---\n([\s\S]*?)\n---/u);
328
- if (!fm) return "";
329
- const desc = fm[1].match(/^description:\s*(.+?)\s*$/mu);
330
- if (!desc) return "";
331
- return desc[1].replace(/^["'](.+)["']$/u, "$1").trim();
332
- }
333
- function extractTriggersClause(description) {
334
- const m = description.match(/Triggers?\s+([\s\S]+)$/u);
335
- if (!m) return "";
336
- return m[1].trim().replace(/[.。]\s*$/u, "").replace(/\|/gu, "\\|");
337
- }
338
- function renderRouterIntentBlock(leaves) {
339
- const rows = leaves.map((l) => `| ${l.triggers} | \`${l.slug}\` |`).join("\n");
340
- const enumVals = leaves.map((l) => l.slug.replace(/^fabric-/u, "")).join(" | ");
341
- return [
342
- ROUTER_INTENT_MARKER_BEGIN,
343
- ROUTER_INTENT_GENERATED_NOTE,
344
- "",
345
- "| \u7528\u6237\u610F\u56FE(leaf description Triggers) | \u4E0B\u6E38 skill |",
346
- "| --- | --- |",
347
- rows,
348
- "",
349
- `\`S_CLASSIFY\` \u7684 \`task_type\` \u679A\u4E3E:\`${enumVals}\``,
350
- ROUTER_INTENT_MARKER_END
351
- ].join("\n");
352
- }
353
- async function buildRouterSkillSource() {
354
- const template = await readTemplate(SKILL_ROUTER_TEMPLATE_REL);
355
- if (!ROUTER_INTENT_REGEX.test(template)) {
356
- throw new Error(
357
- `fabric/SKILL.md is missing the ${ROUTER_INTENT_MARKER_BEGIN} \u2026 ${ROUTER_INTENT_MARKER_END} marker pair \u2014 cannot regenerate the Intent Map. This is a Fabric release bug (router template was hand-edited away from the managed-block contract).`
358
- );
359
- }
360
- const leafSpecs = Object.values(FABRIC_SKILL_INSTALL_SPECS).filter(
361
- (spec) => spec.slug !== "fabric"
362
- );
363
- const leaves = [];
364
- for (const spec of leafSpecs) {
365
- const leafMd = await readTemplate(spec.templateRel);
366
- leaves.push({ slug: spec.slug, triggers: extractTriggersClause(extractSkillMdDescription(leafMd)) });
367
- }
368
- return template.replace(ROUTER_INTENT_REGEX, renderRouterIntentBlock(leaves));
369
- }
370
- async function installFabricRouterSkill(projectRoot, _options = {}) {
371
- const source = await buildRouterSkillSource();
372
- validateSkillCanonicalSize(source, "fabric");
373
- const spec = FABRIC_SKILL_INSTALL_SPECS.fabricRouter;
374
- const targets = spec.destinations.map((rel) => join2(projectRoot, rel));
375
- const results = [];
376
- for (const target of targets) {
377
- const staleMsg = inspectStaleInstall(target, source);
378
- const result = await copyTextIdempotent(spec.step, source, target);
379
- if (staleMsg && result.status === "written") {
380
- result.message = result.message ? `${staleMsg}; ${result.message}` : staleMsg;
381
- }
382
- results.push(result);
383
- }
384
- return results;
385
- }
386
286
  async function cleanupDeprecatedSkills(projectRoot) {
387
287
  const results = [];
388
288
  for (const rel of DEPRECATED_SKILL_DIRS) {
@@ -553,6 +453,22 @@ async function installKnowledgeHintNarrowHook(projectRoot, _options = {}) {
553
453
  }
554
454
  return results;
555
455
  }
456
+ async function installKnowledgePretoolUseHook(projectRoot, _options = {}) {
457
+ const source = await readTemplate(HOOK_PRETOOLUSE_SCRIPT_TEMPLATE_REL);
458
+ const targets = HOOK_SCRIPT_DESTINATIONS.knowledgePretoolUse.map((rel) => join2(projectRoot, rel));
459
+ const results = [];
460
+ for (const target of targets) {
461
+ const result = await copyTextIdempotent("hook-pretooluse-script", source, target);
462
+ if (result.status === "written" && process.platform !== "win32") {
463
+ try {
464
+ chmodSync(target, 493);
465
+ } catch {
466
+ }
467
+ }
468
+ results.push(result);
469
+ }
470
+ return results;
471
+ }
556
472
  async function installCitePolicyEvictHook(projectRoot, _options = {}) {
557
473
  const source = await readTemplate(HOOK_CITE_EVICT_SCRIPT_TEMPLATE_REL);
558
474
  const targets = HOOK_SCRIPT_DESTINATIONS.citePolicyEvict.map((rel) => join2(projectRoot, rel));
@@ -835,6 +751,9 @@ var FABRIC_HOOK_SCRIPT_BASENAMES = /* @__PURE__ */ new Set([
835
751
  "fabric-hint.cjs",
836
752
  "knowledge-hint-broad.cjs",
837
753
  "knowledge-hint-narrow.cjs",
754
+ // ux-w2-6: the single PreToolUse orchestrator — must be in the strip set so a
755
+ // template matcher edit re-syncs on re-install (same reason as the others below).
756
+ "knowledge-pretooluse.cjs",
838
757
  // dual-sink W5-1: the strip set must enumerate the COMPLETE fabric-owned hook
839
758
  // surface — same set as FABRIC_HOOK_COMMAND_PATHS. Otherwise a matcher change
840
759
  // in the template (e.g. adding `apply_patch` to the Codex PreToolUse/PostToolUse
@@ -986,17 +905,14 @@ export {
986
905
  FABRIC_HOOK_COMMAND_PATHS,
987
906
  installFabricArchiveSkill,
988
907
  installFabricReviewSkill,
989
- installFabricImportSkill,
990
908
  installFabricSyncSkill,
991
909
  installFabricStoreSkill,
992
- installFabricAuditSkill,
993
- installFabricConnectSkill,
994
- installFabricRouterSkill,
995
910
  cleanupDeprecatedSkills,
996
911
  installSharedSkillLib,
997
912
  installArchiveHintHook,
998
913
  installKnowledgeHintBroadHook,
999
914
  installKnowledgeHintNarrowHook,
915
+ installKnowledgePretoolUseHook,
1000
916
  installCitePolicyEvictHook,
1001
917
  installSessionEndMarkerHook,
1002
918
  installPostTooluseMutationHook,
@@ -1,10 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- buildResolveInput
4
- } from "./chunk-EOT63RDH.js";
5
- import {
3
+ buildResolveInput,
6
4
  loadProjectConfig
7
- } from "./chunk-QFIVFZRH.js";
5
+ } from "./chunk-I5F5BHWI.js";
8
6
  import {
9
7
  resolveGlobalRoot
10
8
  } from "./chunk-FNHDQTPC.js";
@@ -1,5 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // src/store/project-config-io.ts
4
+ import {
5
+ projectConfigPath,
6
+ loadProjectConfig,
7
+ saveProjectConfig
8
+ } from "@fenglimg/fabric-shared";
9
+
3
10
  // src/store/scope-explain.ts
4
11
  import {
5
12
  SCOPE_COORDINATE_PATTERN,
@@ -31,6 +38,8 @@ function scopeExplain(projectRoot, scope, globalRoot = resolveGlobalRoot()) {
31
38
  }
32
39
 
33
40
  export {
41
+ loadProjectConfig,
42
+ saveProjectConfig,
34
43
  buildResolveInput,
35
44
  scopeExplain
36
45
  };