@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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
deepMerge
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-XC5RUHLK.js";
|
|
5
5
|
|
|
6
6
|
// src/install/write-bootstrap-snapshot.ts
|
|
7
7
|
import { existsSync, readFileSync } from "fs";
|
|
@@ -55,10 +55,15 @@ var SKILL_TEMPLATE_REL = "skills/fabric-archive/SKILL.md";
|
|
|
55
55
|
var SKILL_REVIEW_TEMPLATE_REL = "skills/fabric-review/SKILL.md";
|
|
56
56
|
var SKILL_IMPORT_TEMPLATE_REL = "skills/fabric-import/SKILL.md";
|
|
57
57
|
var SKILL_SYNC_TEMPLATE_REL = "skills/fabric-sync/SKILL.md";
|
|
58
|
+
var SKILL_STORE_TEMPLATE_REL = "skills/fabric-store/SKILL.md";
|
|
59
|
+
var SKILL_AUDIT_TEMPLATE_REL = "skills/fabric-audit/SKILL.md";
|
|
60
|
+
var SKILL_CONNECT_TEMPLATE_REL = "skills/fabric-connect/SKILL.md";
|
|
58
61
|
var HOOK_SCRIPT_TEMPLATE_REL = "hooks/fabric-hint.cjs";
|
|
59
62
|
var HOOK_BROAD_SCRIPT_TEMPLATE_REL = "hooks/knowledge-hint-broad.cjs";
|
|
60
63
|
var HOOK_NARROW_SCRIPT_TEMPLATE_REL = "hooks/knowledge-hint-narrow.cjs";
|
|
61
64
|
var HOOK_CITE_EVICT_SCRIPT_TEMPLATE_REL = "hooks/cite-policy-evict.cjs";
|
|
65
|
+
var HOOK_SESSION_END_SCRIPT_TEMPLATE_REL = "hooks/session-end-marker.cjs";
|
|
66
|
+
var HOOK_POST_TOOLUSE_SCRIPT_TEMPLATE_REL = "hooks/post-tooluse-mutation.cjs";
|
|
62
67
|
var HOOK_LIB_TEMPLATE_DIR_REL = "hooks/lib";
|
|
63
68
|
var CLAUDE_HOOK_CONFIG_TEMPLATE_REL = "hooks/configs/claude-code.json";
|
|
64
69
|
var CODEX_HOOK_CONFIG_TEMPLATE_REL = "hooks/configs/codex-hooks.json";
|
|
@@ -81,6 +86,23 @@ var SKILL_DESTINATIONS = {
|
|
|
81
86
|
fabricSync: [
|
|
82
87
|
".claude/skills/fabric-sync/SKILL.md",
|
|
83
88
|
".codex/skills/fabric-sync/SKILL.md"
|
|
89
|
+
],
|
|
90
|
+
// v2.1 ADJ-NEWN-1/#4: fabric-store knowledge-store ops skill, same 2-client
|
|
91
|
+
// coverage as the sibling skills.
|
|
92
|
+
fabricStore: [
|
|
93
|
+
".claude/skills/fabric-store/SKILL.md",
|
|
94
|
+
".codex/skills/fabric-store/SKILL.md"
|
|
95
|
+
],
|
|
96
|
+
// v2.2 SK1-audit (W2-T5): fabric-audit semantic-deprecation skill, same
|
|
97
|
+
// 2-client coverage as the sibling skills.
|
|
98
|
+
fabricAudit: [
|
|
99
|
+
".claude/skills/fabric-audit/SKILL.md",
|
|
100
|
+
".codex/skills/fabric-audit/SKILL.md"
|
|
101
|
+
],
|
|
102
|
+
// v2.2 SK2-connect (W3-T2): fabric-connect knowledge-graph relation skill.
|
|
103
|
+
fabricConnect: [
|
|
104
|
+
".claude/skills/fabric-connect/SKILL.md",
|
|
105
|
+
".codex/skills/fabric-connect/SKILL.md"
|
|
84
106
|
]
|
|
85
107
|
};
|
|
86
108
|
var DEPRECATED_SKILL_DIRS = [
|
|
@@ -115,6 +137,18 @@ var HOOK_SCRIPT_DESTINATIONS = {
|
|
|
115
137
|
".claude/hooks/cite-policy-evict.cjs",
|
|
116
138
|
".codex/hooks/cite-policy-evict.cjs",
|
|
117
139
|
".cursor/hooks/cite-policy-evict.cjs"
|
|
140
|
+
],
|
|
141
|
+
// lifecycle-refactor W2-T2: SessionEnd marker hook — all three clients.
|
|
142
|
+
sessionEndMarker: [
|
|
143
|
+
".claude/hooks/session-end-marker.cjs",
|
|
144
|
+
".codex/hooks/session-end-marker.cjs",
|
|
145
|
+
".cursor/hooks/session-end-marker.cjs"
|
|
146
|
+
],
|
|
147
|
+
// lifecycle-refactor W2-T3: PostToolUse mutation marker hook — all three.
|
|
148
|
+
postTooluseMutation: [
|
|
149
|
+
".claude/hooks/post-tooluse-mutation.cjs",
|
|
150
|
+
".codex/hooks/post-tooluse-mutation.cjs",
|
|
151
|
+
".cursor/hooks/post-tooluse-mutation.cjs"
|
|
118
152
|
]
|
|
119
153
|
};
|
|
120
154
|
var HOOK_LIB_DESTINATIONS = [
|
|
@@ -128,25 +162,51 @@ var HOOK_CONFIG_TARGETS = {
|
|
|
128
162
|
cursor: ".cursor/hooks.json"
|
|
129
163
|
};
|
|
130
164
|
var HOOK_CONFIG_ARRAY_PATHS = {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
165
|
+
// F2: "hooks.UserPromptSubmit" MUST be listed — the Claude Code template
|
|
166
|
+
// ships a UserPromptSubmit cite-policy hook, so without this path deepMerge
|
|
167
|
+
// array-REPLACEs (instead of append-with-dedupe) on re-install, silently
|
|
168
|
+
// clobbering any user-defined UserPromptSubmit hook.
|
|
169
|
+
// lifecycle-refactor W2-T2/T3: PostToolUse + SessionEnd arrays added so
|
|
170
|
+
// deepMerge append-with-dedupes them on re-install (omitting them would
|
|
171
|
+
// array-REPLACE, clobbering any user-defined entries in those slots).
|
|
172
|
+
claudeCode: [
|
|
173
|
+
"hooks.Stop",
|
|
174
|
+
"hooks.SessionStart",
|
|
175
|
+
"hooks.PreToolUse",
|
|
176
|
+
"hooks.UserPromptSubmit",
|
|
177
|
+
"hooks.PostToolUse",
|
|
178
|
+
"hooks.SessionEnd"
|
|
179
|
+
],
|
|
180
|
+
codex: ["events.Stop", "events.SessionStart", "events.PreToolUse", "events.PostToolUse", "events.SessionEnd"],
|
|
181
|
+
cursor: ["hooks.stop", "hooks.sessionStart", "hooks.preToolUse", "hooks.postToolUse", "hooks.sessionEnd"]
|
|
134
182
|
};
|
|
135
183
|
var FABRIC_HOOK_COMMAND_PATHS = {
|
|
136
184
|
claudeCode: {
|
|
137
185
|
fabricHint: "${CLAUDE_PROJECT_DIR}/.claude/hooks/fabric-hint.cjs",
|
|
138
186
|
knowledgeHintBroad: "${CLAUDE_PROJECT_DIR}/.claude/hooks/knowledge-hint-broad.cjs",
|
|
139
|
-
knowledgeHintNarrow: "${CLAUDE_PROJECT_DIR}/.claude/hooks/knowledge-hint-narrow.cjs"
|
|
187
|
+
knowledgeHintNarrow: "${CLAUDE_PROJECT_DIR}/.claude/hooks/knowledge-hint-narrow.cjs",
|
|
188
|
+
// F3: the UserPromptSubmit cite-policy-evict hook must be a known fabric
|
|
189
|
+
// command so uninstall prunes it (matches the literal in claude-code.json).
|
|
190
|
+
citePolicyEvict: "${CLAUDE_PROJECT_DIR}/.claude/hooks/cite-policy-evict.cjs",
|
|
191
|
+
// lifecycle-refactor W2-T2/T3: SessionEnd + PostToolUse marker hooks.
|
|
192
|
+
sessionEndMarker: "${CLAUDE_PROJECT_DIR}/.claude/hooks/session-end-marker.cjs",
|
|
193
|
+
postTooluseMutation: "${CLAUDE_PROJECT_DIR}/.claude/hooks/post-tooluse-mutation.cjs"
|
|
140
194
|
},
|
|
141
195
|
codex: {
|
|
142
196
|
fabricHint: '"$(git rev-parse --show-toplevel)/.codex/hooks/fabric-hint.cjs"',
|
|
143
197
|
knowledgeHintBroad: '"$(git rev-parse --show-toplevel)/.codex/hooks/knowledge-hint-broad.cjs"',
|
|
144
|
-
knowledgeHintNarrow: '"$(git rev-parse --show-toplevel)/.codex/hooks/knowledge-hint-narrow.cjs"'
|
|
198
|
+
knowledgeHintNarrow: '"$(git rev-parse --show-toplevel)/.codex/hooks/knowledge-hint-narrow.cjs"',
|
|
199
|
+
citePolicyEvict: '"$(git rev-parse --show-toplevel)/.codex/hooks/cite-policy-evict.cjs"',
|
|
200
|
+
sessionEndMarker: '"$(git rev-parse --show-toplevel)/.codex/hooks/session-end-marker.cjs"',
|
|
201
|
+
postTooluseMutation: '"$(git rev-parse --show-toplevel)/.codex/hooks/post-tooluse-mutation.cjs"'
|
|
145
202
|
},
|
|
146
203
|
cursor: {
|
|
147
204
|
fabricHint: ".cursor/hooks/fabric-hint.cjs",
|
|
148
205
|
knowledgeHintBroad: ".cursor/hooks/knowledge-hint-broad.cjs",
|
|
149
|
-
knowledgeHintNarrow: ".cursor/hooks/knowledge-hint-narrow.cjs"
|
|
206
|
+
knowledgeHintNarrow: ".cursor/hooks/knowledge-hint-narrow.cjs",
|
|
207
|
+
citePolicyEvict: ".cursor/hooks/cite-policy-evict.cjs",
|
|
208
|
+
sessionEndMarker: ".cursor/hooks/session-end-marker.cjs",
|
|
209
|
+
postTooluseMutation: ".cursor/hooks/post-tooluse-mutation.cjs"
|
|
150
210
|
}
|
|
151
211
|
};
|
|
152
212
|
function readFabricLanguagePreference(projectRoot) {
|
|
@@ -257,6 +317,51 @@ async function installFabricSyncSkill(projectRoot, _options = {}) {
|
|
|
257
317
|
}
|
|
258
318
|
return results;
|
|
259
319
|
}
|
|
320
|
+
async function installFabricStoreSkill(projectRoot, _options = {}) {
|
|
321
|
+
const source = await readTemplate(SKILL_STORE_TEMPLATE_REL);
|
|
322
|
+
validateSkillCanonicalSize(source, "fabric-store");
|
|
323
|
+
const targets = SKILL_DESTINATIONS.fabricStore.map((rel) => join2(projectRoot, rel));
|
|
324
|
+
const results = [];
|
|
325
|
+
for (const target of targets) {
|
|
326
|
+
const staleMsg = inspectStaleInstall(target, source);
|
|
327
|
+
const result = await copyTextIdempotent("skill-store", source, target);
|
|
328
|
+
if (staleMsg && result.status === "written") {
|
|
329
|
+
result.message = result.message ? `${staleMsg}; ${result.message}` : staleMsg;
|
|
330
|
+
}
|
|
331
|
+
results.push(result);
|
|
332
|
+
}
|
|
333
|
+
return results;
|
|
334
|
+
}
|
|
335
|
+
async function installFabricAuditSkill(projectRoot, _options = {}) {
|
|
336
|
+
const source = await readTemplate(SKILL_AUDIT_TEMPLATE_REL);
|
|
337
|
+
validateSkillCanonicalSize(source, "fabric-audit");
|
|
338
|
+
const targets = SKILL_DESTINATIONS.fabricAudit.map((rel) => join2(projectRoot, rel));
|
|
339
|
+
const results = [];
|
|
340
|
+
for (const target of targets) {
|
|
341
|
+
const staleMsg = inspectStaleInstall(target, source);
|
|
342
|
+
const result = await copyTextIdempotent("skill-audit", source, target);
|
|
343
|
+
if (staleMsg && result.status === "written") {
|
|
344
|
+
result.message = result.message ? `${staleMsg}; ${result.message}` : staleMsg;
|
|
345
|
+
}
|
|
346
|
+
results.push(result);
|
|
347
|
+
}
|
|
348
|
+
return results;
|
|
349
|
+
}
|
|
350
|
+
async function installFabricConnectSkill(projectRoot, _options = {}) {
|
|
351
|
+
const source = await readTemplate(SKILL_CONNECT_TEMPLATE_REL);
|
|
352
|
+
validateSkillCanonicalSize(source, "fabric-connect");
|
|
353
|
+
const targets = SKILL_DESTINATIONS.fabricConnect.map((rel) => join2(projectRoot, rel));
|
|
354
|
+
const results = [];
|
|
355
|
+
for (const target of targets) {
|
|
356
|
+
const staleMsg = inspectStaleInstall(target, source);
|
|
357
|
+
const result = await copyTextIdempotent("skill-connect", source, target);
|
|
358
|
+
if (staleMsg && result.status === "written") {
|
|
359
|
+
result.message = result.message ? `${staleMsg}; ${result.message}` : staleMsg;
|
|
360
|
+
}
|
|
361
|
+
results.push(result);
|
|
362
|
+
}
|
|
363
|
+
return results;
|
|
364
|
+
}
|
|
260
365
|
async function cleanupDeprecatedSkills(projectRoot) {
|
|
261
366
|
const results = [];
|
|
262
367
|
for (const rel of DEPRECATED_SKILL_DIRS) {
|
|
@@ -443,6 +548,38 @@ async function installCitePolicyEvictHook(projectRoot, _options = {}) {
|
|
|
443
548
|
}
|
|
444
549
|
return results;
|
|
445
550
|
}
|
|
551
|
+
async function installSessionEndMarkerHook(projectRoot, _options = {}) {
|
|
552
|
+
const source = await readTemplate(HOOK_SESSION_END_SCRIPT_TEMPLATE_REL);
|
|
553
|
+
const targets = HOOK_SCRIPT_DESTINATIONS.sessionEndMarker.map((rel) => join2(projectRoot, rel));
|
|
554
|
+
const results = [];
|
|
555
|
+
for (const target of targets) {
|
|
556
|
+
const result = await copyTextIdempotent("hook-session-end-script", source, target);
|
|
557
|
+
if (result.status === "written" && process.platform !== "win32") {
|
|
558
|
+
try {
|
|
559
|
+
chmodSync(target, 493);
|
|
560
|
+
} catch {
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
results.push(result);
|
|
564
|
+
}
|
|
565
|
+
return results;
|
|
566
|
+
}
|
|
567
|
+
async function installPostTooluseMutationHook(projectRoot, _options = {}) {
|
|
568
|
+
const source = await readTemplate(HOOK_POST_TOOLUSE_SCRIPT_TEMPLATE_REL);
|
|
569
|
+
const targets = HOOK_SCRIPT_DESTINATIONS.postTooluseMutation.map((rel) => join2(projectRoot, rel));
|
|
570
|
+
const results = [];
|
|
571
|
+
for (const target of targets) {
|
|
572
|
+
const result = await copyTextIdempotent("hook-post-tooluse-script", source, target);
|
|
573
|
+
if (result.status === "written" && process.platform !== "win32") {
|
|
574
|
+
try {
|
|
575
|
+
chmodSync(target, 493);
|
|
576
|
+
} catch {
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
results.push(result);
|
|
580
|
+
}
|
|
581
|
+
return results;
|
|
582
|
+
}
|
|
446
583
|
async function installHookLibs(projectRoot, _options = {}) {
|
|
447
584
|
const libTemplateDir = findTemplatePath(HOOK_LIB_TEMPLATE_DIR_REL);
|
|
448
585
|
let libFiles;
|
|
@@ -887,12 +1024,17 @@ export {
|
|
|
887
1024
|
installFabricReviewSkill,
|
|
888
1025
|
installFabricImportSkill,
|
|
889
1026
|
installFabricSyncSkill,
|
|
1027
|
+
installFabricStoreSkill,
|
|
1028
|
+
installFabricAuditSkill,
|
|
1029
|
+
installFabricConnectSkill,
|
|
890
1030
|
cleanupDeprecatedSkills,
|
|
891
1031
|
installSharedSkillLib,
|
|
892
1032
|
installArchiveHintHook,
|
|
893
1033
|
installKnowledgeHintBroadHook,
|
|
894
1034
|
installKnowledgeHintNarrowHook,
|
|
895
1035
|
installCitePolicyEvictHook,
|
|
1036
|
+
installSessionEndMarkerHook,
|
|
1037
|
+
installPostTooluseMutationHook,
|
|
896
1038
|
installHookLibs,
|
|
897
1039
|
mergeClaudeCodeHookConfig,
|
|
898
1040
|
mergeCodexHookConfig,
|
|
@@ -3,9 +3,9 @@ import {
|
|
|
3
3
|
configCmd,
|
|
4
4
|
config_default,
|
|
5
5
|
installMcpClients
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-F6ITRM7T.js";
|
|
7
|
+
import "./chunk-XC5RUHLK.js";
|
|
8
|
+
import "./chunk-2CY4BMTH.js";
|
|
9
9
|
export {
|
|
10
10
|
configCmd,
|
|
11
11
|
config_default as default,
|
|
@@ -2,24 +2,25 @@
|
|
|
2
2
|
import {
|
|
3
3
|
paint,
|
|
4
4
|
symbol
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-BO4XIZWZ.js";
|
|
6
6
|
import {
|
|
7
7
|
resolveDevMode
|
|
8
8
|
} from "./chunk-COI5VDFU.js";
|
|
9
9
|
import {
|
|
10
10
|
getDoctorTranslator,
|
|
11
11
|
t
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-2CY4BMTH.js";
|
|
13
13
|
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
} from "./chunk-
|
|
14
|
+
detectAliasLinkDrift,
|
|
15
|
+
missingRequiredStores,
|
|
16
|
+
syncStoreAliasLinks,
|
|
17
|
+
unboundAvailableStores
|
|
18
|
+
} from "./chunk-5ZUMLCD5.js";
|
|
19
19
|
import {
|
|
20
20
|
loadGlobalConfig,
|
|
21
|
+
loadProjectConfig,
|
|
21
22
|
resolveGlobalRoot
|
|
22
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-XCBVSGCS.js";
|
|
23
24
|
|
|
24
25
|
// src/commands/doctor.ts
|
|
25
26
|
import { confirm, isCancel } from "@clack/prompts";
|
|
@@ -32,7 +33,8 @@ import {
|
|
|
32
33
|
runDoctorCiteCoverage,
|
|
33
34
|
runDoctorFix,
|
|
34
35
|
runDoctorHistoryAll,
|
|
35
|
-
runDoctorReport
|
|
36
|
+
runDoctorReport,
|
|
37
|
+
runDoctorConflictLint
|
|
36
38
|
} from "@fenglimg/fabric-server";
|
|
37
39
|
|
|
38
40
|
// src/store/doctor-checks.ts
|
|
@@ -57,6 +59,23 @@ function storeDoctorChecks(projectRoot, globalRoot = resolveGlobalRoot()) {
|
|
|
57
59
|
message: `required store '${missing.id}' is not mounted; run \`fabric store add\``
|
|
58
60
|
});
|
|
59
61
|
}
|
|
62
|
+
for (const store of unboundAvailableStores(projectRoot, globalRoot)) {
|
|
63
|
+
diagnostics.push({
|
|
64
|
+
code: "unbound_available_store",
|
|
65
|
+
severity: "info",
|
|
66
|
+
ref: store.alias,
|
|
67
|
+
message: `store '${store.alias}' is mounted but not bound to this project; run \`fabric store bind ${store.alias}\` to read its knowledge here (then \`fabric store switch-write ${store.alias}\` to write team knowledge into it)`
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
const aliasDrift = detectAliasLinkDrift(globalRoot);
|
|
71
|
+
if (aliasDrift.length > 0) {
|
|
72
|
+
diagnostics.push({
|
|
73
|
+
code: "store_alias_link_drift",
|
|
74
|
+
severity: "info",
|
|
75
|
+
ref: aliasDrift.join(", "),
|
|
76
|
+
message: `by-alias readability link(s) out of sync for ${aliasDrift.join(", ")}; run \`fabric doctor --fix\` to repair ~/.fabric/stores/by-alias/`
|
|
77
|
+
});
|
|
78
|
+
}
|
|
60
79
|
for (const store of global.stores) {
|
|
61
80
|
if (store.remote === void 0 && store.personal !== true) {
|
|
62
81
|
diagnostics.push({
|
|
@@ -208,6 +227,17 @@ var doctorCommand = defineCommand({
|
|
|
208
227
|
type: "string",
|
|
209
228
|
description: t("cli.doctor.args.history.description"),
|
|
210
229
|
valueHint: "archive|fix|all"
|
|
230
|
+
},
|
|
231
|
+
// v2.1 ④ conflict-detection (P4): knowledge-conflict lint surface.
|
|
232
|
+
"lint-conflicts": {
|
|
233
|
+
type: "boolean",
|
|
234
|
+
description: t("cli.doctor.args.lint-conflicts.description"),
|
|
235
|
+
default: false
|
|
236
|
+
},
|
|
237
|
+
deep: {
|
|
238
|
+
type: "boolean",
|
|
239
|
+
description: t("cli.doctor.args.deep.description"),
|
|
240
|
+
default: false
|
|
211
241
|
}
|
|
212
242
|
},
|
|
213
243
|
async run({ args }) {
|
|
@@ -362,6 +392,22 @@ var doctorCommand = defineCommand({
|
|
|
362
392
|
renderCiteCoverageReport(report2, args.json === true, dt);
|
|
363
393
|
return;
|
|
364
394
|
}
|
|
395
|
+
if (args["lint-conflicts"] === true) {
|
|
396
|
+
if (fix || fixKnowledge || citeCoverage) {
|
|
397
|
+
writeStderr(dt("cli.doctor.errors.lint-conflicts-mutex"));
|
|
398
|
+
process.exitCode = 1;
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
const report2 = await runDoctorConflictLint(resolution.target, {
|
|
402
|
+
deep: args.deep === true
|
|
403
|
+
});
|
|
404
|
+
if (args.json === true) {
|
|
405
|
+
writeStdout(JSON.stringify(report2, null, 2));
|
|
406
|
+
} else {
|
|
407
|
+
renderConflictLintReport(report2, args.deep === true, dt);
|
|
408
|
+
}
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
365
411
|
if (fixKnowledge && fix) {
|
|
366
412
|
writeStderr(dt("cli.doctor.errors.fix-knowledge-fix-mutually-exclusive"));
|
|
367
413
|
process.exitCode = 1;
|
|
@@ -373,29 +419,37 @@ var doctorCommand = defineCommand({
|
|
|
373
419
|
if (fixKnowledge) {
|
|
374
420
|
const preReport = await runDoctorReport(resolution.target);
|
|
375
421
|
const plan = computeFixKnowledgePlan(preReport);
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
422
|
+
if (args["dry-run"] === true) {
|
|
423
|
+
if (plan.totalCount > 0) {
|
|
424
|
+
renderFixKnowledgePlan(plan);
|
|
425
|
+
}
|
|
426
|
+
report = preReport;
|
|
379
427
|
} else {
|
|
380
|
-
|
|
381
|
-
const
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
plan
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
428
|
+
const yesFlag = args.yes === true;
|
|
429
|
+
const envBypass = process.env.FABRIC_NONINTERACTIVE === "1";
|
|
430
|
+
if (plan.totalCount === 0) {
|
|
431
|
+
} else {
|
|
432
|
+
renderFixKnowledgePlan(plan);
|
|
433
|
+
const decision = await resolveFixKnowledgeConsent({
|
|
434
|
+
yesFlag,
|
|
435
|
+
envBypass,
|
|
436
|
+
plan
|
|
437
|
+
});
|
|
438
|
+
if (decision === "abort") {
|
|
439
|
+
process.exitCode = 1;
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
389
442
|
}
|
|
443
|
+
fixKnowledgeReport = await runDoctorFixKnowledge(resolution.target);
|
|
444
|
+
report = fixKnowledgeReport.report;
|
|
390
445
|
}
|
|
391
|
-
fixKnowledgeReport = await runDoctorFixKnowledge(resolution.target);
|
|
392
|
-
report = fixKnowledgeReport.report;
|
|
393
446
|
} else if (fix) {
|
|
394
447
|
if (args["dry-run"] === true) {
|
|
395
448
|
report = await runDoctorReport(resolution.target);
|
|
396
449
|
} else {
|
|
397
450
|
fixReport = await runDoctorFix(resolution.target);
|
|
398
451
|
report = fixReport.report;
|
|
452
|
+
syncStoreAliasLinks();
|
|
399
453
|
}
|
|
400
454
|
} else {
|
|
401
455
|
report = await runDoctorReport(resolution.target);
|
|
@@ -418,7 +472,7 @@ var doctorCommand = defineCommand({
|
|
|
418
472
|
renderFixKnowledgeMutations(fixKnowledgeReport, dt);
|
|
419
473
|
} else if (fixReport !== null) {
|
|
420
474
|
writeStdout(fixReport.message);
|
|
421
|
-
} else if (fix && args["dry-run"] === true) {
|
|
475
|
+
} else if ((fix || fixKnowledge) && args["dry-run"] === true) {
|
|
422
476
|
writeStdout(dt("cli.doctor.fix-dry-run-banner"));
|
|
423
477
|
}
|
|
424
478
|
renderHumanReport(report, dt, args.verbose === true);
|
|
@@ -447,7 +501,7 @@ var doctorCommand = defineCommand({
|
|
|
447
501
|
var doctor_default = doctorCommand;
|
|
448
502
|
function renderHumanReport(report, dt, verbose) {
|
|
449
503
|
writeStdout(`${renderStatus(report.status)} ${paint.ai("fabric doctor")} ${paint.human(report.summary.target)}`);
|
|
450
|
-
renderTldrHeader(report);
|
|
504
|
+
renderTldrHeader(report, dt, verbose);
|
|
451
505
|
for (const check of report.checks) {
|
|
452
506
|
writeStdout(`${renderStatus(check.status)} ${check.name}: ${check.message}`);
|
|
453
507
|
}
|
|
@@ -520,16 +574,16 @@ function writeIssueSection(title, issues, options) {
|
|
|
520
574
|
}
|
|
521
575
|
}
|
|
522
576
|
}
|
|
523
|
-
function renderTldrHeader(report) {
|
|
577
|
+
function renderTldrHeader(report, dt, verbose) {
|
|
524
578
|
const ranked = [];
|
|
525
579
|
for (const issue of report.fixable_errors) {
|
|
526
|
-
ranked.push({ severity: "fixable", code: issue.code, message: issue.message });
|
|
580
|
+
ranked.push({ severity: "fixable", code: issue.code, message: issue.message, actionHint: issue.actionHint, audience: issue.audience });
|
|
527
581
|
}
|
|
528
582
|
for (const issue of report.manual_errors) {
|
|
529
|
-
ranked.push({ severity: "manual", code: issue.code, message: issue.message });
|
|
583
|
+
ranked.push({ severity: "manual", code: issue.code, message: issue.message, actionHint: issue.actionHint, audience: issue.audience });
|
|
530
584
|
}
|
|
531
585
|
for (const issue of report.warnings) {
|
|
532
|
-
ranked.push({ severity: "warn", code: issue.code, message: issue.message });
|
|
586
|
+
ranked.push({ severity: "warn", code: issue.code, message: issue.message, actionHint: issue.actionHint, audience: issue.audience });
|
|
533
587
|
}
|
|
534
588
|
if (ranked.length === 0) {
|
|
535
589
|
writeStdout(`${symbol.ok} TL;DR: all 48 checks green \u2014 nothing to fix.`);
|
|
@@ -543,6 +597,11 @@ function renderTldrHeader(report) {
|
|
|
543
597
|
const marker = item.severity === "fixable" ? symbol.error : item.severity === "manual" ? symbol.error : symbol.warn;
|
|
544
598
|
const truncated = item.message.length > 140 ? `${item.message.slice(0, 137)}...` : item.message;
|
|
545
599
|
writeStdout(` ${marker} ${item.code}: ${truncated}`);
|
|
600
|
+
if (item.actionHint !== void 0 && item.actionHint.length > 0) {
|
|
601
|
+
writeStdout(
|
|
602
|
+
item.audience === "maintainer" && !verbose ? ` \u2192 ${dt("doctor.maintainer-hint-folded")}` : ` \u2192 ${item.actionHint}`
|
|
603
|
+
);
|
|
604
|
+
}
|
|
546
605
|
}
|
|
547
606
|
}
|
|
548
607
|
function renderStatus(status) {
|
|
@@ -689,10 +748,42 @@ function renderCiteCoverageReport(report, jsonMode, dt) {
|
|
|
689
748
|
const complianceRate = report.metrics.cite_compliance_rate;
|
|
690
749
|
const complianceStr = complianceRate === null || complianceRate === void 0 ? dt("doctor.cite.metric.complianceNA") : `${(complianceRate * 100).toFixed(1)}% (${report.metrics.compliant_cites ?? 0}/${(report.metrics.compliant_cites ?? 0) + (report.metrics.noncompliant_cites ?? 0)})`;
|
|
691
750
|
lines.push(` ${dt("doctor.cite.metric.complianceRate")}: ${complianceStr}`);
|
|
751
|
+
const recallRate = report.metrics.recall_coverage_rate;
|
|
752
|
+
const recallStr = recallRate === null || recallRate === void 0 ? dt("doctor.cite.metric.recallCoverageNA") : `${(recallRate * 100).toFixed(1)}% (${report.metrics.recall_backed_edits ?? 0}/${report.metrics.edits_touched})`;
|
|
753
|
+
lines.push(` ${dt("doctor.cite.metric.recallCoverage")}: ${recallStr}`);
|
|
692
754
|
const uncorrelatable = report.metrics.uncorrelatable_edits ?? 0;
|
|
693
755
|
if (uncorrelatable > 0) {
|
|
694
756
|
lines.push(` ${dt("doctor.cite.metric.uncorrelatableEdits")}: ${uncorrelatable}`);
|
|
695
757
|
}
|
|
758
|
+
if (report.metrics.exposed_and_mutated !== void 0) {
|
|
759
|
+
lines.push(
|
|
760
|
+
` ${dt("doctor.cite.metric.exposedAndMutated")}: ${report.metrics.exposed_and_mutated.count}`
|
|
761
|
+
);
|
|
762
|
+
}
|
|
763
|
+
if (report.metrics.mutations_observed !== void 0) {
|
|
764
|
+
lines.push(
|
|
765
|
+
` ${dt("doctor.cite.metric.mutationsObserved")}: ${report.metrics.mutations_observed.count}`
|
|
766
|
+
);
|
|
767
|
+
}
|
|
768
|
+
if (report.metrics.mutation_pool !== void 0) {
|
|
769
|
+
lines.push(
|
|
770
|
+
` ${dt("doctor.cite.metric.mutationPool")}: ${report.metrics.mutation_pool.attributed} / ${report.metrics.mutation_pool.unattributed_workspace_dirty} (attributed / unattributed_workspace_dirty)`
|
|
771
|
+
);
|
|
772
|
+
}
|
|
773
|
+
if (report.metrics.sessions_closed !== void 0) {
|
|
774
|
+
lines.push(
|
|
775
|
+
` ${dt("doctor.cite.metric.sessionsClosed")}: ${report.metrics.sessions_closed.count}`
|
|
776
|
+
);
|
|
777
|
+
}
|
|
778
|
+
if (report.metrics.by_store !== void 0) {
|
|
779
|
+
const storeKeys = Object.keys(report.metrics.by_store).sort();
|
|
780
|
+
if (storeKeys.length > 0) {
|
|
781
|
+
lines.push(` ${dt("doctor.cite.metric.byStore")}:`);
|
|
782
|
+
for (const store of storeKeys) {
|
|
783
|
+
lines.push(` ${store}: ${report.metrics.by_store[store].qualifying_cites}`);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
696
787
|
if (report.per_client !== void 0 && Object.keys(report.per_client).length > 1) {
|
|
697
788
|
lines.push("");
|
|
698
789
|
lines.push(`### ${dt("doctor.cite.section.perClient")}`);
|
|
@@ -794,6 +885,38 @@ function appendContractSection(lines, report, dt) {
|
|
|
794
885
|
);
|
|
795
886
|
}
|
|
796
887
|
}
|
|
888
|
+
function renderConflictLintReport(report, deepRequested, dt) {
|
|
889
|
+
const lines = [];
|
|
890
|
+
lines.push(dt("doctor.conflict.header"));
|
|
891
|
+
lines.push("");
|
|
892
|
+
if (report.candidate_count === 0) {
|
|
893
|
+
lines.push(` ${symbol.ok} ${dt("doctor.conflict.none")}`);
|
|
894
|
+
writeStdout(lines.join("\n"));
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
lines.push(
|
|
898
|
+
` ${dt("doctor.conflict.summary", {
|
|
899
|
+
candidates: String(report.candidate_count),
|
|
900
|
+
conflicts: String(report.conflict_count),
|
|
901
|
+
threshold: report.threshold.toFixed(2)
|
|
902
|
+
})}`
|
|
903
|
+
);
|
|
904
|
+
if (deepRequested && !report.deep) {
|
|
905
|
+
lines.push(` ${symbol.warn} ${dt("doctor.conflict.deep_no_judge")}`);
|
|
906
|
+
}
|
|
907
|
+
lines.push("");
|
|
908
|
+
for (const pair of report.pairs) {
|
|
909
|
+
const sym = pair.verdict === "conflict" ? symbol.error : symbol.warn;
|
|
910
|
+
const verdictLabel = dt(`doctor.conflict.verdict.${pair.verdict}`);
|
|
911
|
+
const pct = `${(pair.similarity * 100).toFixed(0)}%`;
|
|
912
|
+
let line = ` ${sym} [${pair.a} \u2194 ${pair.b}] (${pair.knowledge_type}/${pair.layer}) ${pct} \u2014 ${verdictLabel}`;
|
|
913
|
+
if (pair.rationale !== void 0 && pair.rationale.length > 0) {
|
|
914
|
+
line += `: ${pair.rationale}`;
|
|
915
|
+
}
|
|
916
|
+
lines.push(line);
|
|
917
|
+
}
|
|
918
|
+
writeStdout(lines.join("\n"));
|
|
919
|
+
}
|
|
797
920
|
function renderEnrichDescriptionsReport(report, dt) {
|
|
798
921
|
const header = `${symbol.ok} ${paint.ai("fabric doctor --enrich-descriptions")} mode=${report.mode}${report.dryRun ? " (dry-run)" : ""} scanned=${report.scanned} modified=${report.modified} skipped=${report.skipped}`;
|
|
799
922
|
writeStdout(header);
|
|
@@ -916,5 +1039,6 @@ function formatTimestampForTable(iso) {
|
|
|
916
1039
|
export {
|
|
917
1040
|
doctor_default as default,
|
|
918
1041
|
doctorCommand,
|
|
919
|
-
parseSinceDuration
|
|
1042
|
+
parseSinceDuration,
|
|
1043
|
+
renderTldrHeader
|
|
920
1044
|
};
|
package/dist/index.js
CHANGED
|
@@ -1,47 +1,88 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
t
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-2CY4BMTH.js";
|
|
5
5
|
|
|
6
6
|
// src/index.ts
|
|
7
7
|
import { realpathSync } from "fs";
|
|
8
8
|
import { resolve } from "path";
|
|
9
9
|
import { fileURLToPath } from "url";
|
|
10
|
-
import { defineCommand, runMain } from "citty";
|
|
10
|
+
import { defineCommand, runCommand, runMain } from "citty";
|
|
11
11
|
|
|
12
12
|
// src/commands/index.ts
|
|
13
13
|
var allCommands = {
|
|
14
|
-
install: () => import("./install-
|
|
14
|
+
install: () => import("./install-BULNDUIM.js").then((module) => module.default),
|
|
15
15
|
// v2.1.0-rc.1 P3: multi-store lifecycle command group (list/add/remove/explain).
|
|
16
|
-
store: () => import("./store-
|
|
16
|
+
store: () => import("./store-66NK2FTQ.js").then((module) => module.default),
|
|
17
17
|
// v2.1.0-rc.1 P3 (S9/S17/S37): multi-store pull --rebase + push, conflict resume.
|
|
18
|
-
sync: () => import("./sync-
|
|
18
|
+
sync: () => import("./sync-EA5HZMXM.js").then((module) => module.default),
|
|
19
19
|
// v2.1.0-rc.1 P3 (F5): read-only identity/status info commands.
|
|
20
|
-
whoami: () => import("./whoami-
|
|
21
|
-
status: () => import("./status-
|
|
22
|
-
"scope-explain": () => import("./scope-explain-
|
|
23
|
-
doctor: () => import("./doctor-
|
|
24
|
-
uninstall: () => import("./uninstall-
|
|
25
|
-
config: () => import("./config-
|
|
26
|
-
"plan-context-hint": () => import("./plan-context-hint-
|
|
20
|
+
whoami: () => import("./whoami-66YKY5DZ.js").then((module) => module.default),
|
|
21
|
+
status: () => import("./status-PANEGKU2.js").then((module) => module.default),
|
|
22
|
+
"scope-explain": () => import("./scope-explain-BWRWBCCP.js").then((module) => module.default),
|
|
23
|
+
doctor: () => import("./doctor-J4O3X54I.js").then((module) => module.default),
|
|
24
|
+
uninstall: () => import("./uninstall-F75MPKQC.js").then((module) => module.default),
|
|
25
|
+
config: () => import("./config-VJMXCLXW.js").then((module) => module.default),
|
|
26
|
+
"plan-context-hint": () => import("./plan-context-hint-CHVZGOZ5.js").then((module) => module.default),
|
|
27
27
|
// v2.0.0-rc.23 TASK-014 (F8c): S5 onboard-slot coverage. Used by the
|
|
28
28
|
// fabric-archive Skill's first-run phase to detect unclaimed slots.
|
|
29
|
-
"onboard-coverage": () => import("./onboard-coverage-
|
|
29
|
+
"onboard-coverage": () => import("./onboard-coverage-JWQWDZW7.js").then((module) => module.default),
|
|
30
30
|
// v2.0.0-rc.37 NEW-34: text dashboard over .fabric/metrics.jsonl.
|
|
31
|
-
metrics: () => import("./metrics-
|
|
31
|
+
metrics: () => import("./metrics-RER6NLFC.js").then((module) => module.default)
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
+
// src/lib/error-render.ts
|
|
35
|
+
function hasActionHint(err) {
|
|
36
|
+
if (err === null || typeof err !== "object") return false;
|
|
37
|
+
const candidate = err;
|
|
38
|
+
return typeof candidate.message === "string" && candidate.message.length > 0 && typeof candidate.actionHint === "string" && candidate.actionHint.length > 0;
|
|
39
|
+
}
|
|
40
|
+
function renderFabricError(err, stream = process.stderr) {
|
|
41
|
+
stream.write(`${err.message}
|
|
42
|
+
`);
|
|
43
|
+
stream.write(` -> ${err.actionHint}
|
|
44
|
+
`);
|
|
45
|
+
}
|
|
46
|
+
function renderTopLevelError(err, stream = process.stderr) {
|
|
47
|
+
if (hasActionHint(err)) {
|
|
48
|
+
renderFabricError(err, stream);
|
|
49
|
+
return "fabric-error";
|
|
50
|
+
}
|
|
51
|
+
return "other";
|
|
52
|
+
}
|
|
53
|
+
|
|
34
54
|
// src/index.ts
|
|
35
55
|
var main = defineCommand({
|
|
36
56
|
meta: {
|
|
37
57
|
name: "fabric",
|
|
38
|
-
version: "2.
|
|
58
|
+
version: "2.2.0-rc.3",
|
|
39
59
|
description: t("cli.main.description")
|
|
40
60
|
},
|
|
41
61
|
subCommands: allCommands
|
|
42
62
|
});
|
|
43
63
|
async function run() {
|
|
44
|
-
|
|
64
|
+
const rawArgs = process.argv.slice(2);
|
|
65
|
+
const wantsHelp = rawArgs.some((arg) => arg === "--help" || arg === "-h");
|
|
66
|
+
const wantsVersion = rawArgs.length === 1 && (rawArgs[0] === "--version" || rawArgs[0] === "-v");
|
|
67
|
+
if (wantsHelp || wantsVersion) {
|
|
68
|
+
await runMain(main, { rawArgs });
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
await runCommand(main, { rawArgs });
|
|
73
|
+
} catch (err) {
|
|
74
|
+
if (renderTopLevelError(err) === "fabric-error") {
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
const code = err !== null && typeof err === "object" ? err.code : void 0;
|
|
78
|
+
const isCittyUsageError = err instanceof Error && err.name === "CLIError" || typeof code === "string" && (code.startsWith("E_") || code.startsWith("EARG") || code === "EUSAGE");
|
|
79
|
+
if (isCittyUsageError) {
|
|
80
|
+
await runMain(main, { rawArgs });
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
console.error(err, "\n");
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
45
86
|
}
|
|
46
87
|
var entrypoint = process.argv[1];
|
|
47
88
|
var currentFilePath = fileURLToPath(import.meta.url);
|