@fenglimg/fabric-cli 2.1.0-rc.2 → 2.2.0-rc.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -5
- package/dist/chunk-27HK6H5Y.js +69 -0
- package/dist/{chunk-BATF4PEJ.js → chunk-2KBCTMID.js} +31 -8
- package/dist/chunk-3D7B2UAZ.js +149 -0
- package/dist/{chunk-MF3OTILQ.js → chunk-3IOLS5EK.js} +48 -42
- package/dist/{plan-context-hint-FC6P3WFE.js → chunk-722JU5BP.js} +52 -12
- package/dist/{chunk-F46ORPOA.js → chunk-7ZDXBOOU.js} +271 -166
- package/dist/{doctor-QVNPHLJK.js → chunk-E7HJUU34.js} +248 -72
- package/dist/chunk-EOT63RDH.js +36 -0
- package/dist/chunk-FNHDQTPC.js +16 -0
- package/dist/chunk-HORSMSZL.js +26 -0
- package/dist/chunk-NLNH64A3.js +43 -0
- package/dist/{chunk-WU6GAPKH.js → chunk-PTGQAZEW.js} +12 -4
- package/dist/chunk-QFIVFZRH.js +13 -0
- package/dist/chunk-QPAW6IYT.js +387 -0
- package/dist/{chunk-COI5VDFU.js → chunk-WA3DYGSY.js} +1 -2
- package/dist/{config-XJIPZNUP.js → config-A3LTECAY.js} +4 -3
- package/dist/context-UJCGYOT6.js +117 -0
- package/dist/doctor-MDTZWKBK.js +24 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +167 -16
- package/dist/info-7FKBTMVO.js +139 -0
- package/dist/install-v2-RINEA24K.js +3279 -0
- package/dist/{metrics-ACEQFPDU.js → metrics-HMFH4YHK.js} +22 -9
- package/dist/{onboard-coverage-MFCAEBDO.js → onboard-coverage-XSG77LL3.js} +48 -27
- package/dist/plan-context-hint-5TNGH3R4.js +12 -0
- package/dist/scope-explain-HLJZ2M33.js +48 -0
- package/dist/status-4R3TM4FJ.js +37 -0
- package/dist/store-HOCORVL3.js +563 -0
- package/dist/sync-DT5UJMMR.js +418 -0
- package/dist/{uninstall-TAXSUSKH.js → uninstall-IFN2KYBK.js} +128 -140
- package/dist/whoami-ITGEFWH4.js +49 -0
- package/package.json +7 -5
- package/templates/hooks/cite-policy-evict.cjs +412 -160
- package/templates/hooks/configs/README.md +14 -27
- package/templates/hooks/configs/claude-code.json +17 -2
- package/templates/hooks/configs/codex-hooks.json +15 -3
- package/templates/hooks/fabric-hint.cjs +573 -180
- package/templates/hooks/knowledge-hint-broad.cjs +648 -190
- package/templates/hooks/knowledge-hint-narrow.cjs +123 -77
- package/templates/hooks/lib/banner-i18n.cjs +31 -0
- package/templates/hooks/lib/bindings-snapshot-reader.cjs +118 -7
- package/templates/hooks/lib/cite-line-parser.cjs +12 -20
- package/templates/hooks/lib/client-adapter.cjs +66 -7
- package/templates/hooks/lib/injection-log.cjs +91 -0
- package/templates/hooks/lib/nudge-policy.cjs +117 -0
- package/templates/hooks/lib/state-store.cjs +90 -11
- package/templates/hooks/post-tooluse-mutation.cjs +386 -0
- package/templates/hooks/session-end-marker.cjs +140 -0
- package/templates/skills/fabric/SKILL.md +100 -0
- package/templates/skills/fabric-archive/SKILL.md +35 -24
- package/templates/skills/fabric-archive/ref/dry-run-scope.md +1 -1
- package/templates/skills/fabric-archive/ref/i18n-policy.md +2 -3
- package/templates/skills/fabric-archive/ref/phase-1-5-onboard.md +2 -3
- package/templates/skills/fabric-archive/ref/phase-1-cross-session.md +1 -1
- package/templates/skills/fabric-archive/ref/phase-2-5-viability.md +1 -1
- package/templates/skills/fabric-archive/ref/phase-3-6-related-edges.md +18 -0
- package/templates/skills/fabric-archive/ref/phase-3-7-semantic-scope.md +47 -0
- package/templates/skills/fabric-audit/SKILL.md +63 -0
- package/templates/skills/fabric-connect/SKILL.md +48 -0
- package/templates/skills/fabric-import/SKILL.md +7 -7
- package/templates/skills/fabric-import/ref/i18n-policy.md +2 -3
- package/templates/skills/fabric-import/ref/state-recovery.md +1 -2
- package/templates/skills/fabric-review/SKILL.md +16 -5
- package/templates/skills/fabric-review/ref/cite-contract.md +56 -0
- package/templates/skills/fabric-review/ref/i18n-policy.md +2 -3
- package/templates/skills/fabric-review/ref/output-contract.md +1 -1
- package/templates/skills/fabric-review/ref/per-mode-flows.md +2 -2
- package/templates/skills/fabric-review/ref/worked-examples.md +1 -1
- package/templates/skills/fabric-store/SKILL.md +44 -0
- package/templates/skills/fabric-sync/SKILL.md +1 -1
- package/templates/skills/lib/shared-policy.md +2 -2
- package/dist/chunk-HFQVXY6P.js +0 -86
- package/dist/chunk-L4Q55UC4.js +0 -52
- package/dist/chunk-LFIKMVY7.js +0 -27
- package/dist/chunk-PWLW3B57.js +0 -18
- package/dist/chunk-RYAFBNES.js +0 -33
- package/dist/chunk-T5RPGCCM.js +0 -40
- package/dist/chunk-WWNXR34K.js +0 -49
- package/dist/install-2HDO5FTQ.js +0 -2683
- package/dist/scope-explain-2F2R5URO.js +0 -33
- package/dist/status-GLQWLWH6.js +0 -23
- package/dist/store-XTSE5TY6.js +0 -105
- package/dist/sync-BJCWDPNC.js +0 -245
- package/dist/whoami-B6AEMSEV.js +0 -31
- package/templates/hooks/configs/cursor-hooks.json +0 -18
- package/templates/hooks/lib/cite-contract-reminder.cjs +0 -179
- package/templates/hooks/lib/summary-fallback.cjs +0 -210
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* rc.35 TASK-06 (P0-10.b) — summary-fallback library.
|
|
3
|
-
*
|
|
4
|
-
* Resolves opaque hint entries (where `entry.summary === entry.id` so the
|
|
5
|
-
* AI sees no information beyond the id) by reading the entry's markdown
|
|
6
|
-
* file at `.fabric/knowledge/<type>/<id>--<slug>.md`, extracting the first
|
|
7
|
-
* paragraph under `## Summary`, and substituting that text into the entry
|
|
8
|
-
* before the hook renders it.
|
|
9
|
-
*
|
|
10
|
-
* Caching: results are stored in `.fabric/.cache/summary-fallback.json`
|
|
11
|
-
* keyed by the current `revision_hash` returned by plan-context-hint. The
|
|
12
|
-
* cache is wiped wholesale when the revision changes (cheap invariant —
|
|
13
|
-
* any meta rev bump implies entry text MAY have moved). Per-process call
|
|
14
|
-
* also benefits from in-memory dedup since the same opaque id may appear
|
|
15
|
-
* across narrow + broad paths.
|
|
16
|
-
*
|
|
17
|
-
* Design contract:
|
|
18
|
-
* - Never throw. ANY failure (cache read, fs scan, file read) degrades
|
|
19
|
-
* to a no-op — the original opaque summary is left untouched. Hooks
|
|
20
|
-
* must remain best-effort.
|
|
21
|
-
* - Idempotent over identical inputs. Two calls in succession with the
|
|
22
|
-
* same revision_hash + entries set produce zero disk reads on the
|
|
23
|
-
* second call.
|
|
24
|
-
*
|
|
25
|
-
* Public API (module.exports):
|
|
26
|
-
* resolveOpaqueSummaries(entries, projectRoot, revisionHash) — returns
|
|
27
|
-
* a NEW array of entries with `summary` substituted for opaque cases.
|
|
28
|
-
* Original `entry.id` is preserved verbatim.
|
|
29
|
-
*
|
|
30
|
-
* _extractFirstSummaryParagraph(md) — pure helper, exposed for testing.
|
|
31
|
-
*
|
|
32
|
-
* _readCache / _writeCache — exposed for testing.
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
|
-
const { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } = require("node:fs");
|
|
36
|
-
const { join } = require("node:path");
|
|
37
|
-
|
|
38
|
-
const CACHE_DIR_REL = ".fabric/.cache";
|
|
39
|
-
const CACHE_FILE_REL = ".fabric/.cache/summary-fallback.json";
|
|
40
|
-
const KNOWLEDGE_DIR_REL = ".fabric/knowledge";
|
|
41
|
-
const SUMMARY_MAX_LEN = 80;
|
|
42
|
-
const KNOWLEDGE_TYPE_DIRS = ["decisions", "pitfalls", "guidelines", "models", "processes"];
|
|
43
|
-
|
|
44
|
-
function _isOpaque(entry) {
|
|
45
|
-
if (!entry || typeof entry.id !== "string" || typeof entry.summary !== "string") {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
return entry.summary.trim() === entry.id.trim();
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Pure helper: extract the first paragraph under a `## Summary` heading.
|
|
53
|
-
*
|
|
54
|
-
* - `## Summary` is case-insensitive but level-sensitive (only H2).
|
|
55
|
-
* - First paragraph = lines until blank line or next heading.
|
|
56
|
-
* - Collapses whitespace + trims; returns `""` if no summary section or
|
|
57
|
-
* the section is empty.
|
|
58
|
-
*/
|
|
59
|
-
function _extractFirstSummaryParagraph(md) {
|
|
60
|
-
if (typeof md !== "string" || md.length === 0) return "";
|
|
61
|
-
const lines = md.split(/\r?\n/);
|
|
62
|
-
let i = 0;
|
|
63
|
-
while (i < lines.length) {
|
|
64
|
-
if (/^##\s+summary\s*$/i.test(lines[i].trim())) {
|
|
65
|
-
i += 1;
|
|
66
|
-
break;
|
|
67
|
-
}
|
|
68
|
-
i += 1;
|
|
69
|
-
}
|
|
70
|
-
if (i >= lines.length) return "";
|
|
71
|
-
// Skip blank lines after the heading
|
|
72
|
-
while (i < lines.length && lines[i].trim().length === 0) i += 1;
|
|
73
|
-
// Collect until the next blank line or next heading
|
|
74
|
-
const buf = [];
|
|
75
|
-
while (i < lines.length) {
|
|
76
|
-
const line = lines[i];
|
|
77
|
-
if (line.trim().length === 0) break;
|
|
78
|
-
if (/^#{1,6}\s/.test(line.trim())) break;
|
|
79
|
-
buf.push(line.trim());
|
|
80
|
-
i += 1;
|
|
81
|
-
}
|
|
82
|
-
const flat = buf.join(" ").replace(/\s+/g, " ").trim();
|
|
83
|
-
if (flat.length === 0) return "";
|
|
84
|
-
if (flat.length <= SUMMARY_MAX_LEN) return flat;
|
|
85
|
-
return `${flat.slice(0, SUMMARY_MAX_LEN - 1)}…`;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function _readCache(projectRoot) {
|
|
89
|
-
const cachePath = join(projectRoot, CACHE_FILE_REL);
|
|
90
|
-
if (!existsSync(cachePath)) return null;
|
|
91
|
-
try {
|
|
92
|
-
const raw = readFileSync(cachePath, "utf8");
|
|
93
|
-
const parsed = JSON.parse(raw);
|
|
94
|
-
if (parsed && typeof parsed === "object" && typeof parsed.revision === "string" && parsed.summaries && typeof parsed.summaries === "object") {
|
|
95
|
-
return parsed;
|
|
96
|
-
}
|
|
97
|
-
} catch {
|
|
98
|
-
// ignore — caller treats null as no-cache
|
|
99
|
-
}
|
|
100
|
-
return null;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function _writeCache(projectRoot, payload) {
|
|
104
|
-
try {
|
|
105
|
-
const cacheDir = join(projectRoot, CACHE_DIR_REL);
|
|
106
|
-
if (!existsSync(cacheDir)) mkdirSync(cacheDir, { recursive: true });
|
|
107
|
-
const cachePath = join(projectRoot, CACHE_FILE_REL);
|
|
108
|
-
writeFileSync(cachePath, JSON.stringify(payload), "utf8");
|
|
109
|
-
} catch {
|
|
110
|
-
// Best-effort — failing to persist cache is not an error
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Scan `.fabric/knowledge/<type>/` for the canonical `<id>--<slug>.md`
|
|
116
|
-
* matching `stableId`. Tries the most likely type-dir first based on the
|
|
117
|
-
* entry's `type` hint, then falls back to scanning all canonical type
|
|
118
|
-
* directories. Returns the absolute path or null.
|
|
119
|
-
*
|
|
120
|
-
* The id→file mapping is unique by construction (stable_id is allocated
|
|
121
|
-
* once per file), so the first match wins.
|
|
122
|
-
*/
|
|
123
|
-
function _findEntryFile(projectRoot, stableId, typeHint) {
|
|
124
|
-
const baseDir = join(projectRoot, KNOWLEDGE_DIR_REL);
|
|
125
|
-
if (!existsSync(baseDir)) return null;
|
|
126
|
-
const tryOrder = [];
|
|
127
|
-
if (typeof typeHint === "string" && typeHint.length > 0) {
|
|
128
|
-
// Accept both singular and plural hints — find the plural form.
|
|
129
|
-
const lower = typeHint.toLowerCase();
|
|
130
|
-
const plural = KNOWLEDGE_TYPE_DIRS.find((d) => d === lower || d.startsWith(lower));
|
|
131
|
-
if (plural) tryOrder.push(plural);
|
|
132
|
-
}
|
|
133
|
-
for (const t of KNOWLEDGE_TYPE_DIRS) {
|
|
134
|
-
if (!tryOrder.includes(t)) tryOrder.push(t);
|
|
135
|
-
}
|
|
136
|
-
const prefix = `${stableId}--`;
|
|
137
|
-
for (const t of tryOrder) {
|
|
138
|
-
const typeDir = join(baseDir, t);
|
|
139
|
-
if (!existsSync(typeDir)) continue;
|
|
140
|
-
let files;
|
|
141
|
-
try {
|
|
142
|
-
files = readdirSync(typeDir);
|
|
143
|
-
} catch {
|
|
144
|
-
continue;
|
|
145
|
-
}
|
|
146
|
-
for (const f of files) {
|
|
147
|
-
if (f.startsWith(prefix) && f.endsWith(".md")) {
|
|
148
|
-
return join(typeDir, f);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
return null;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function _resolveOne(projectRoot, entry) {
|
|
156
|
-
const filePath = _findEntryFile(projectRoot, entry.id, entry.type);
|
|
157
|
-
if (filePath === null) return "";
|
|
158
|
-
let md;
|
|
159
|
-
try {
|
|
160
|
-
md = readFileSync(filePath, "utf8");
|
|
161
|
-
} catch {
|
|
162
|
-
return "";
|
|
163
|
-
}
|
|
164
|
-
return _extractFirstSummaryParagraph(md);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Main API. Returns a new array of entries with `summary` swapped for
|
|
169
|
-
* the extracted fallback wherever the original summary was opaque AND
|
|
170
|
-
* the fallback extraction yielded a non-empty string. Non-opaque entries
|
|
171
|
-
* pass through unchanged.
|
|
172
|
-
*/
|
|
173
|
-
function resolveOpaqueSummaries(entries, projectRoot, revisionHash) {
|
|
174
|
-
if (!Array.isArray(entries) || entries.length === 0) return entries;
|
|
175
|
-
const cache = _readCache(projectRoot);
|
|
176
|
-
const cachedSummaries = cache && cache.revision === revisionHash && cache.summaries ? cache.summaries : {};
|
|
177
|
-
const nextCacheSummaries = { ...cachedSummaries };
|
|
178
|
-
let cacheChanged = cache === null || cache.revision !== revisionHash;
|
|
179
|
-
const result = entries.map((entry) => {
|
|
180
|
-
if (!_isOpaque(entry)) return entry;
|
|
181
|
-
const id = entry.id;
|
|
182
|
-
let fallback;
|
|
183
|
-
if (Object.prototype.hasOwnProperty.call(cachedSummaries, id)) {
|
|
184
|
-
fallback = cachedSummaries[id];
|
|
185
|
-
} else {
|
|
186
|
-
fallback = _resolveOne(projectRoot, entry);
|
|
187
|
-
nextCacheSummaries[id] = fallback;
|
|
188
|
-
cacheChanged = true;
|
|
189
|
-
}
|
|
190
|
-
if (typeof fallback === "string" && fallback.length > 0) {
|
|
191
|
-
return { ...entry, summary: fallback };
|
|
192
|
-
}
|
|
193
|
-
return entry;
|
|
194
|
-
});
|
|
195
|
-
if (cacheChanged) {
|
|
196
|
-
_writeCache(projectRoot, { revision: revisionHash, summaries: nextCacheSummaries });
|
|
197
|
-
}
|
|
198
|
-
return result;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
module.exports = {
|
|
202
|
-
resolveOpaqueSummaries,
|
|
203
|
-
_extractFirstSummaryParagraph,
|
|
204
|
-
_readCache,
|
|
205
|
-
_writeCache,
|
|
206
|
-
_findEntryFile,
|
|
207
|
-
_isOpaque,
|
|
208
|
-
SUMMARY_MAX_LEN,
|
|
209
|
-
KNOWLEDGE_TYPE_DIRS,
|
|
210
|
-
};
|