@fenglimg/fabric-cli 2.2.0-rc.4 → 2.2.0-rc.9
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-5JG4QJLO.js → chunk-27HK6H5Y.js} +10 -5
- package/dist/{chunk-F6ITRM7T.js → chunk-2KBCTMID.js} +29 -6
- package/dist/chunk-3D7B2UAZ.js +149 -0
- package/dist/{chunk-XC5RUHLK.js → chunk-3IOLS5EK.js} +23 -38
- package/dist/{chunk-XHHCRDIR.js → chunk-7ZDXBOOU.js} +174 -211
- package/dist/{doctor-U5W4CX5I.js → chunk-E7HJUU34.js} +103 -51
- package/dist/{chunk-XCBVSGCS.js → chunk-FNHDQTPC.js} +1 -10
- package/dist/{chunk-2CY4BMTH.js → chunk-HORSMSZL.js} +9 -5
- package/dist/{chunk-BO4XIZWZ.js → chunk-NLNH64A3.js} +5 -18
- package/dist/{chunk-H3FE6VIK.js → chunk-PTGQAZEW.js} +13 -3
- package/dist/chunk-QFIVFZRH.js +13 -0
- package/dist/{chunk-5SSNE5GM.js → chunk-QPAW6IYT.js} +125 -39
- package/dist/{chunk-COI5VDFU.js → chunk-WA3DYGSY.js} +1 -2
- package/dist/{plan-context-hint-CHVZGOZ5.js → chunk-YM4XATJF.js} +29 -4
- package/dist/{config-VJMXCLXW.js → config-A3LTECAY.js} +4 -3
- package/dist/context-7NUKXDB6.js +117 -0
- package/dist/doctor-MDTZWKBK.js +24 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +131 -21
- package/dist/info-7FKBTMVO.js +139 -0
- package/dist/install-v2-I6PJ6IFT.js +3279 -0
- package/dist/{metrics-RER6NLFC.js → metrics-HMFH4YHK.js} +1 -1
- package/dist/{onboard-coverage-JWQWDZW7.js → onboard-coverage-XSG77LL3.js} +48 -27
- package/dist/plan-context-hint-G75R4P4J.js +12 -0
- package/dist/{scope-explain-BWRWBCCP.js → scope-explain-HLJZ2M33.js} +3 -2
- package/dist/{status-7UFLWRX7.js → status-4R3TM4FJ.js} +8 -5
- package/dist/{store-ZEZMQVG7.js → store-HOCORVL3.js} +96 -350
- package/dist/{sync-EA5HZMXM.js → sync-DT5UJMMR.js} +36 -13
- package/dist/{uninstall-F75MPKQC.js → uninstall-IFN2KYBK.js} +71 -140
- package/dist/{whoami-3FRWYGML.js → whoami-ITGEFWH4.js} +9 -7
- package/package.json +7 -5
- package/templates/hooks/cite-policy-evict.cjs +5 -5
- package/templates/hooks/configs/README.md +14 -27
- package/templates/hooks/configs/claude-code.json +1 -1
- package/templates/hooks/configs/codex-hooks.json +3 -3
- package/templates/hooks/fabric-hint.cjs +326 -161
- package/templates/hooks/knowledge-hint-broad.cjs +431 -271
- package/templates/hooks/knowledge-hint-narrow.cjs +64 -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/nudge-policy.cjs +117 -0
- package/templates/hooks/lib/state-store.cjs +60 -0
- package/templates/hooks/post-tooluse-mutation.cjs +112 -11
- package/templates/skills/fabric/SKILL.md +100 -0
- package/templates/skills/fabric-archive/SKILL.md +29 -26
- 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 +13 -3
- package/templates/skills/fabric-connect/SKILL.md +3 -3
- 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 +5 -5
- package/templates/skills/fabric-review/ref/cite-contract.md +1 -1
- 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 +1 -1
- package/templates/skills/fabric-sync/SKILL.md +1 -1
- package/templates/skills/lib/shared-policy.md +2 -2
- package/dist/install-7XJ64WSC.js +0 -2743
- package/templates/hooks/configs/cursor-hooks.json +0 -30
- package/templates/hooks/lib/cite-contract-reminder.cjs +0 -179
- package/templates/hooks/lib/summary-fallback.cjs +0 -210
|
@@ -1,28 +1,40 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
loadGlobalConfig,
|
|
4
3
|
loadProjectConfig,
|
|
5
|
-
resolveGlobalRoot,
|
|
6
|
-
saveGlobalConfig,
|
|
7
4
|
saveProjectConfig
|
|
8
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-QFIVFZRH.js";
|
|
6
|
+
import {
|
|
7
|
+
loadGlobalConfig,
|
|
8
|
+
resolveGlobalRoot,
|
|
9
|
+
saveGlobalConfig
|
|
10
|
+
} from "./chunk-FNHDQTPC.js";
|
|
9
11
|
|
|
10
12
|
// src/store/store-ops.ts
|
|
11
13
|
import { execFileSync } from "child_process";
|
|
12
14
|
import { randomUUID } from "crypto";
|
|
13
|
-
import { existsSync, lstatSync, mkdirSync, readdirSync, readlinkSync, rmSync, symlinkSync } from "fs";
|
|
15
|
+
import { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, readlinkSync, rmSync, symlinkSync, writeFileSync } from "fs";
|
|
14
16
|
import { join } from "path";
|
|
15
17
|
import {
|
|
16
18
|
addMountedStore,
|
|
17
19
|
addStoreProject,
|
|
18
20
|
bindRequiredStore,
|
|
21
|
+
deriveMountLabel,
|
|
19
22
|
detachMountedStore,
|
|
20
23
|
explainStore,
|
|
21
24
|
initStore,
|
|
22
|
-
|
|
25
|
+
STORE_GITIGNORE,
|
|
26
|
+
STORE_KNOWLEDGE_TYPE_DIRS,
|
|
27
|
+
STORE_LAYOUT,
|
|
28
|
+
STORE_PENDING_DIR,
|
|
23
29
|
STORES_ROOT_DIR,
|
|
24
30
|
storeHasProject,
|
|
25
|
-
|
|
31
|
+
storeIdentitySchema,
|
|
32
|
+
storeProjectsFileSchema,
|
|
33
|
+
storeMountSubPath,
|
|
34
|
+
storeRelativePath,
|
|
35
|
+
storeRelativePathForMount,
|
|
36
|
+
storeMountNameSchema,
|
|
37
|
+
writeRouteSchema
|
|
26
38
|
} from "@fenglimg/fabric-shared";
|
|
27
39
|
var NO_GLOBAL_CONFIG = "no global Fabric config found \u2014 run `fabric install --global <url>` first";
|
|
28
40
|
function requireConfig(globalRoot) {
|
|
@@ -35,6 +47,18 @@ function requireConfig(globalRoot) {
|
|
|
35
47
|
function storeList(globalRoot = resolveGlobalRoot()) {
|
|
36
48
|
return requireConfig(globalRoot).stores;
|
|
37
49
|
}
|
|
50
|
+
function mountedStoreDir(store, globalRoot) {
|
|
51
|
+
return join(globalRoot, storeRelativePathForMount(store));
|
|
52
|
+
}
|
|
53
|
+
function resolveStoreByAliasOrUuid(aliasOrUuid, globalRoot = resolveGlobalRoot()) {
|
|
54
|
+
const config = loadGlobalConfig(globalRoot);
|
|
55
|
+
if (config === null) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
return config.stores.find(
|
|
59
|
+
(s) => s.alias === aliasOrUuid || s.store_uuid === aliasOrUuid || s.mount_name === aliasOrUuid
|
|
60
|
+
) ?? null;
|
|
61
|
+
}
|
|
38
62
|
var STORE_BY_ALIAS_DIR = "by-alias";
|
|
39
63
|
function syncStoreAliasLinks(globalRoot = resolveGlobalRoot()) {
|
|
40
64
|
const result = { created: [], removed: [], errors: [] };
|
|
@@ -43,7 +67,7 @@ function syncStoreAliasLinks(globalRoot = resolveGlobalRoot()) {
|
|
|
43
67
|
return result;
|
|
44
68
|
}
|
|
45
69
|
const byAliasDir = join(globalRoot, STORES_ROOT_DIR, STORE_BY_ALIAS_DIR);
|
|
46
|
-
const desired = new Map(config.stores.map((s) => [s.alias, s
|
|
70
|
+
const desired = new Map(config.stores.map((s) => [s.alias, storeMountSubPath(s)]));
|
|
47
71
|
try {
|
|
48
72
|
mkdirSync(byAliasDir, { recursive: true });
|
|
49
73
|
} catch {
|
|
@@ -66,9 +90,9 @@ function syncStoreAliasLinks(globalRoot = resolveGlobalRoot()) {
|
|
|
66
90
|
result.errors.push(name);
|
|
67
91
|
}
|
|
68
92
|
}
|
|
69
|
-
for (const [alias,
|
|
93
|
+
for (const [alias, mountName] of desired) {
|
|
70
94
|
const link = join(byAliasDir, alias);
|
|
71
|
-
const target = join("..",
|
|
95
|
+
const target = join("..", mountName);
|
|
72
96
|
try {
|
|
73
97
|
let current = null;
|
|
74
98
|
try {
|
|
@@ -102,7 +126,7 @@ function detectAliasLinkDrift(globalRoot = resolveGlobalRoot()) {
|
|
|
102
126
|
const drifted = [];
|
|
103
127
|
for (const store of config.stores) {
|
|
104
128
|
const link = join(byAliasDir, store.alias);
|
|
105
|
-
const target = join("..", store
|
|
129
|
+
const target = join("..", storeMountSubPath(store));
|
|
106
130
|
try {
|
|
107
131
|
if (!lstatSync(link).isSymbolicLink() || readlinkSync(link) !== target) {
|
|
108
132
|
drifted.push(store.alias);
|
|
@@ -119,25 +143,47 @@ function storeAdd(store, globalRoot = resolveGlobalRoot()) {
|
|
|
119
143
|
syncStoreAliasLinks(globalRoot);
|
|
120
144
|
return next;
|
|
121
145
|
}
|
|
122
|
-
function storeCreate(alias, now, options = {}) {
|
|
146
|
+
async function storeCreate(alias, now, options = {}) {
|
|
123
147
|
const globalRoot = options.globalRoot ?? resolveGlobalRoot();
|
|
124
148
|
const config = requireConfig(globalRoot);
|
|
125
149
|
const uuid = options.uuid ?? randomUUID();
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
150
|
+
const mount_name = options.mountName !== void 0 ? storeMountNameSchema.parse(options.mountName) : deriveMountLabel({ remote: options.remote, alias, store_uuid: uuid });
|
|
151
|
+
const mountedBase = { store_uuid: uuid, alias, mount_name };
|
|
152
|
+
const storeDir = mountedStoreDir(mountedBase, globalRoot);
|
|
153
|
+
const identity = { store_uuid: uuid, created_at: now, canonical_alias: alias };
|
|
154
|
+
if (options.git === false) {
|
|
155
|
+
initStoreSync(storeDir, identity);
|
|
156
|
+
} else {
|
|
157
|
+
await initStore(storeDir, identity, { git: options.git });
|
|
158
|
+
}
|
|
132
159
|
if (options.remote !== void 0 && options.git !== false) {
|
|
133
160
|
gitRemoteAdd(storeDir, options.remote);
|
|
134
161
|
}
|
|
135
|
-
const mounted = options.remote === void 0 ?
|
|
162
|
+
const mounted = options.remote === void 0 ? mountedBase : { ...mountedBase, remote: options.remote };
|
|
136
163
|
const next = addMountedStore(config, mounted);
|
|
137
164
|
saveGlobalConfig(next, globalRoot);
|
|
138
165
|
syncStoreAliasLinks(globalRoot);
|
|
139
166
|
return { config: next, store_uuid: uuid, storeDir };
|
|
140
167
|
}
|
|
168
|
+
function initStoreSync(absDir, identity) {
|
|
169
|
+
const parsed = storeIdentitySchema.parse(identity);
|
|
170
|
+
const identityFile = join(absDir, STORE_LAYOUT.identityFile);
|
|
171
|
+
if (existsSync(identityFile)) {
|
|
172
|
+
throw new Error(`store already initialized at ${absDir} (store.json exists)`);
|
|
173
|
+
}
|
|
174
|
+
for (const type of STORE_KNOWLEDGE_TYPE_DIRS) {
|
|
175
|
+
const typeDir = join(absDir, STORE_LAYOUT.knowledgeDir, type);
|
|
176
|
+
mkdirSync(typeDir, { recursive: true });
|
|
177
|
+
writeFileSync(join(typeDir, ".gitkeep"), "", "utf8");
|
|
178
|
+
}
|
|
179
|
+
mkdirSync(join(absDir, STORE_LAYOUT.knowledgeDir, STORE_PENDING_DIR), { recursive: true });
|
|
180
|
+
mkdirSync(join(absDir, STORE_LAYOUT.bindingsDir), { recursive: true });
|
|
181
|
+
mkdirSync(join(absDir, STORE_LAYOUT.stateDir), { recursive: true });
|
|
182
|
+
writeFileSync(identityFile, `${JSON.stringify(parsed, null, 2)}
|
|
183
|
+
`, "utf8");
|
|
184
|
+
writeFileSync(join(absDir, ".gitignore"), STORE_GITIGNORE, "utf8");
|
|
185
|
+
return parsed;
|
|
186
|
+
}
|
|
141
187
|
function gitRemoteAdd(storeDir, remote) {
|
|
142
188
|
try {
|
|
143
189
|
execFileSync("git", ["remote", "add", "origin", remote], {
|
|
@@ -154,8 +200,8 @@ function gitRemoteAdd(storeDir, remote) {
|
|
|
154
200
|
}
|
|
155
201
|
}
|
|
156
202
|
}
|
|
157
|
-
function storeGitRemote(
|
|
158
|
-
const storeDir = join(globalRoot, storeRelativePath(
|
|
203
|
+
function storeGitRemote(aliasOrUuid, globalRoot = resolveGlobalRoot()) {
|
|
204
|
+
const storeDir = resolveStoreDir(aliasOrUuid, globalRoot) ?? join(globalRoot, storeRelativePath(aliasOrUuid));
|
|
159
205
|
if (!existsSync(storeDir)) {
|
|
160
206
|
return void 0;
|
|
161
207
|
}
|
|
@@ -171,8 +217,20 @@ function storeGitRemote(uuid, globalRoot = resolveGlobalRoot()) {
|
|
|
171
217
|
return void 0;
|
|
172
218
|
}
|
|
173
219
|
}
|
|
174
|
-
function assertStoreMountable(uuid, globalRoot = resolveGlobalRoot()) {
|
|
175
|
-
const
|
|
220
|
+
function assertStoreMountable(uuid, globalRoot = resolveGlobalRoot(), mountName) {
|
|
221
|
+
const registered = resolveStoreByAliasOrUuid(uuid, globalRoot);
|
|
222
|
+
const candidates = mountName === void 0 && registered === null ? [join(globalRoot, storeRelativePath(uuid))] : [
|
|
223
|
+
join(
|
|
224
|
+
globalRoot,
|
|
225
|
+
storeRelativePathForMount({
|
|
226
|
+
store_uuid: uuid,
|
|
227
|
+
mount_name: mountName ?? registered?.mount_name,
|
|
228
|
+
personal: registered?.personal
|
|
229
|
+
})
|
|
230
|
+
),
|
|
231
|
+
join(globalRoot, storeRelativePath(uuid))
|
|
232
|
+
];
|
|
233
|
+
const storeDir = candidates.find((dir) => existsSync(join(dir, "store.json"))) ?? candidates[0];
|
|
176
234
|
if (!existsSync(join(storeDir, "store.json"))) {
|
|
177
235
|
throw new Error(
|
|
178
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.`
|
|
@@ -197,36 +255,40 @@ function requireProjectConfig(projectRoot) {
|
|
|
197
255
|
return config;
|
|
198
256
|
}
|
|
199
257
|
function resolveStoreDir(aliasOrUuid, globalRoot = resolveGlobalRoot()) {
|
|
200
|
-
const
|
|
201
|
-
if (
|
|
258
|
+
const store = resolveStoreByAliasOrUuid(aliasOrUuid, globalRoot);
|
|
259
|
+
if (store === null) {
|
|
202
260
|
return null;
|
|
203
261
|
}
|
|
204
|
-
|
|
205
|
-
(s) => s.alias === aliasOrUuid || s.store_uuid === aliasOrUuid
|
|
206
|
-
);
|
|
207
|
-
if (store === void 0) {
|
|
208
|
-
return null;
|
|
209
|
-
}
|
|
210
|
-
return join(globalRoot, storeRelativePath(store.store_uuid));
|
|
262
|
+
return mountedStoreDir(store, globalRoot);
|
|
211
263
|
}
|
|
212
264
|
function storeProjectList(aliasOrUuid, globalRoot = resolveGlobalRoot()) {
|
|
213
265
|
const storeDir = resolveStoreDir(aliasOrUuid, globalRoot);
|
|
214
266
|
if (storeDir === null) {
|
|
215
267
|
throw new Error(`no mounted store '${aliasOrUuid}' \u2014 run \`fabric store list\` to see mounts`);
|
|
216
268
|
}
|
|
217
|
-
return
|
|
269
|
+
return readStoreProjectsSync(storeDir);
|
|
270
|
+
}
|
|
271
|
+
function readStoreProjectsSync(storeDir) {
|
|
272
|
+
try {
|
|
273
|
+
const parsed = storeProjectsFileSchema.safeParse(
|
|
274
|
+
JSON.parse(readFileSync(join(storeDir, STORE_LAYOUT.projectsFile), "utf8"))
|
|
275
|
+
);
|
|
276
|
+
return parsed.success ? parsed.data.projects : [];
|
|
277
|
+
} catch {
|
|
278
|
+
return [];
|
|
279
|
+
}
|
|
218
280
|
}
|
|
219
|
-
function storeProjectCreate(aliasOrUuid, id, now, options = {}) {
|
|
281
|
+
async function storeProjectCreate(aliasOrUuid, id, now, options = {}) {
|
|
220
282
|
const globalRoot = options.globalRoot ?? resolveGlobalRoot();
|
|
221
283
|
const storeDir = resolveStoreDir(aliasOrUuid, globalRoot);
|
|
222
284
|
if (storeDir === null) {
|
|
223
285
|
throw new Error(`no mounted store '${aliasOrUuid}' \u2014 run \`fabric store list\` to see mounts`);
|
|
224
286
|
}
|
|
225
287
|
const project = options.name === void 0 ? { id, created_at: now } : { id, name: options.name, created_at: now };
|
|
226
|
-
addStoreProject(storeDir, project);
|
|
288
|
+
await addStoreProject(storeDir, project);
|
|
227
289
|
return project;
|
|
228
290
|
}
|
|
229
|
-
function storeBind(projectRoot, entry, options = {}) {
|
|
291
|
+
async function storeBind(projectRoot, entry, options = {}) {
|
|
230
292
|
const config = requireProjectConfig(projectRoot);
|
|
231
293
|
let activeProject = config.active_project;
|
|
232
294
|
if (options.project !== void 0) {
|
|
@@ -237,7 +299,7 @@ function storeBind(projectRoot, entry, options = {}) {
|
|
|
237
299
|
`cannot bind project '${options.project}': store '${entry.id}' is not mounted \u2014 mount it first (\`fabric store add\` / \`fabric install --global --url <remote>\`)`
|
|
238
300
|
);
|
|
239
301
|
}
|
|
240
|
-
if (!storeHasProject(storeDir, options.project)) {
|
|
302
|
+
if (!await storeHasProject(storeDir, options.project)) {
|
|
241
303
|
throw new Error(
|
|
242
304
|
`cannot bind to project '${options.project}': not registered in store '${entry.id}' \u2014 create it first with \`fabric store project create ${entry.id} ${options.project}\``
|
|
243
305
|
);
|
|
@@ -252,9 +314,32 @@ function storeBind(projectRoot, entry, options = {}) {
|
|
|
252
314
|
saveProjectConfig(next, projectRoot);
|
|
253
315
|
return next;
|
|
254
316
|
}
|
|
255
|
-
function storeSwitchWrite(projectRoot, alias) {
|
|
317
|
+
function storeSwitchWrite(projectRoot, alias, options = {}) {
|
|
256
318
|
const config = requireProjectConfig(projectRoot);
|
|
257
|
-
const
|
|
319
|
+
const store = resolveStoreByAliasOrUuid(alias, options.globalRoot ?? resolveGlobalRoot());
|
|
320
|
+
if (store === null || store.personal === true || store.writable === false) {
|
|
321
|
+
throw new Error(`cannot set default write store '${alias}': mount a writable shared store first`);
|
|
322
|
+
}
|
|
323
|
+
const next = {
|
|
324
|
+
...config,
|
|
325
|
+
active_write_store: alias,
|
|
326
|
+
default_write_store: alias
|
|
327
|
+
};
|
|
328
|
+
saveProjectConfig(next, projectRoot);
|
|
329
|
+
return next;
|
|
330
|
+
}
|
|
331
|
+
function storeSetWriteRoute(projectRoot, scope, alias, options = {}) {
|
|
332
|
+
const config = requireProjectConfig(projectRoot);
|
|
333
|
+
const route = writeRouteSchema.parse({ scope, store: alias });
|
|
334
|
+
const store = resolveStoreByAliasOrUuid(alias, options.globalRoot ?? resolveGlobalRoot());
|
|
335
|
+
if (store === null || store.personal === true || store.writable === false) {
|
|
336
|
+
throw new Error(`cannot route scope '${scope}' to '${alias}': mount a writable shared store first`);
|
|
337
|
+
}
|
|
338
|
+
const routes = [
|
|
339
|
+
...(config.write_routes ?? []).filter((existing) => existing.scope !== route.scope),
|
|
340
|
+
route
|
|
341
|
+
];
|
|
342
|
+
const next = { ...config, write_routes: routes };
|
|
258
343
|
saveProjectConfig(next, projectRoot);
|
|
259
344
|
return next;
|
|
260
345
|
}
|
|
@@ -296,6 +381,7 @@ export {
|
|
|
296
381
|
storeProjectCreate,
|
|
297
382
|
storeBind,
|
|
298
383
|
storeSwitchWrite,
|
|
384
|
+
storeSetWriteRoute,
|
|
299
385
|
missingRequiredStores,
|
|
300
386
|
unboundAvailableStores
|
|
301
387
|
};
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/dev-mode.ts
|
|
4
|
-
import {
|
|
5
|
-
import { isAbsolute, join, resolve } from "path";
|
|
4
|
+
import { isAbsolute, resolve } from "path";
|
|
6
5
|
function resolveDevMode(cliTarget, workspaceRoot = process.cwd()) {
|
|
7
6
|
const envTarget = normalizeTarget(process.env.EXTERNAL_FIXTURE_PATH, workspaceRoot);
|
|
8
7
|
const directTarget = normalizeTarget(cliTarget, workspaceRoot);
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
resolveDevMode
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-WA3DYGSY.js";
|
|
5
5
|
|
|
6
6
|
// src/commands/plan-context-hint.ts
|
|
7
7
|
import { defineCommand } from "citty";
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
buildAlwaysActiveBodies,
|
|
10
|
+
buildKnowledgeCensus,
|
|
11
|
+
planContext
|
|
12
|
+
} from "@fenglimg/fabric-server";
|
|
9
13
|
var ALL_PATHS_SENTINEL = "**";
|
|
10
14
|
var planContextHintCommand = defineCommand({
|
|
11
15
|
meta: {
|
|
@@ -74,6 +78,9 @@ async function runPlanContextHint(opts) {
|
|
|
74
78
|
maturity: item.description.maturity ?? "",
|
|
75
79
|
summary: item.description.summary,
|
|
76
80
|
relevance_scope: item.description.relevance_scope ?? "broad",
|
|
81
|
+
// W2-2 (KT-DEC-0027): forward the must_read_if trigger hook for the
|
|
82
|
+
// SessionStart REFERENCE rendering. Omitted when absent/empty.
|
|
83
|
+
...typeof item.description.must_read_if === "string" && item.description.must_read_if.length > 0 ? { must_read_if: item.description.must_read_if } : {},
|
|
77
84
|
// Only set when this entry was pulled in via a graph edge — its presence
|
|
78
85
|
// is the honest signal, never synthesized for ordinarily-ranked entries.
|
|
79
86
|
...typeof relatedTo === "string" ? { related_to: relatedTo } : {}
|
|
@@ -85,6 +92,15 @@ async function runPlanContextHint(opts) {
|
|
|
85
92
|
if (e.relevance_scope === "narrow") narrow_count += 1;
|
|
86
93
|
else broad_only_count += 1;
|
|
87
94
|
}
|
|
95
|
+
const alwaysBodies = await buildAlwaysActiveBodies(resolution.target).catch(() => []);
|
|
96
|
+
const census = await buildKnowledgeCensus(resolution.target).catch(
|
|
97
|
+
() => ({
|
|
98
|
+
by_type: {},
|
|
99
|
+
by_layer: { team: 0, personal: 0, project: 0 },
|
|
100
|
+
dropped_other_project: 0,
|
|
101
|
+
total: 0
|
|
102
|
+
})
|
|
103
|
+
);
|
|
88
104
|
const output = {
|
|
89
105
|
version: 2,
|
|
90
106
|
revision_hash: result.revision_hash,
|
|
@@ -94,7 +110,15 @@ async function runPlanContextHint(opts) {
|
|
|
94
110
|
// semantics unchanged from rc.18 (total candidate count).
|
|
95
111
|
broad_count: candidates.length,
|
|
96
112
|
narrow_count,
|
|
97
|
-
broad_only_count
|
|
113
|
+
broad_only_count,
|
|
114
|
+
always_bodies: alwaysBodies.map((b) => ({
|
|
115
|
+
id: b.stable_id,
|
|
116
|
+
type: b.type,
|
|
117
|
+
layer: b.layer,
|
|
118
|
+
summary: b.summary,
|
|
119
|
+
body: b.body
|
|
120
|
+
})),
|
|
121
|
+
census
|
|
98
122
|
};
|
|
99
123
|
if (result.auto_healed === true) {
|
|
100
124
|
output.auto_healed = true;
|
|
@@ -110,8 +134,9 @@ function parsePathsArg(raw) {
|
|
|
110
134
|
}
|
|
111
135
|
return raw.split(",").map((part) => part.trim()).filter((part) => part.length > 0);
|
|
112
136
|
}
|
|
137
|
+
|
|
113
138
|
export {
|
|
114
|
-
plan_context_hint_default as default,
|
|
115
139
|
planContextHintCommand,
|
|
140
|
+
plan_context_hint_default,
|
|
116
141
|
runPlanContextHint
|
|
117
142
|
};
|
|
@@ -3,9 +3,10 @@ import {
|
|
|
3
3
|
configCmd,
|
|
4
4
|
config_default,
|
|
5
5
|
installMcpClients
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-2KBCTMID.js";
|
|
7
|
+
import "./chunk-3IOLS5EK.js";
|
|
8
|
+
import "./chunk-FNHDQTPC.js";
|
|
9
|
+
import "./chunk-HORSMSZL.js";
|
|
9
10
|
export {
|
|
10
11
|
configCmd,
|
|
11
12
|
config_default as default,
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
runPlanContextHint
|
|
4
|
+
} from "./chunk-YM4XATJF.js";
|
|
5
|
+
import "./chunk-WA3DYGSY.js";
|
|
6
|
+
|
|
7
|
+
// src/commands/context.ts
|
|
8
|
+
import { existsSync } from "fs";
|
|
9
|
+
import { createRequire } from "module";
|
|
10
|
+
import { dirname, join, parse, resolve } from "path";
|
|
11
|
+
import { fileURLToPath } from "url";
|
|
12
|
+
import { defineCommand } from "citty";
|
|
13
|
+
function findTemplatePath(relativePath) {
|
|
14
|
+
const startDir = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
let current = resolve(startDir);
|
|
16
|
+
for (; ; ) {
|
|
17
|
+
const candidate = join(current, "templates", relativePath);
|
|
18
|
+
if (existsSync(candidate)) return candidate;
|
|
19
|
+
const parent = dirname(current);
|
|
20
|
+
if (parent === current || parse(current).root === current) {
|
|
21
|
+
throw new Error(`Template not found: templates/${relativePath} (searched up from ${startDir})`);
|
|
22
|
+
}
|
|
23
|
+
current = parent;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function loadHookRenderer() {
|
|
27
|
+
const require2 = createRequire(import.meta.url);
|
|
28
|
+
return require2(findTemplatePath("hooks/knowledge-hint-broad.cjs"));
|
|
29
|
+
}
|
|
30
|
+
function renderExplain(sinks) {
|
|
31
|
+
const payload = sinks.resolvedPayload;
|
|
32
|
+
const lines = ["", "\u2014 explain (provenance; not injected) \u2014"];
|
|
33
|
+
const bodies = Array.isArray(payload?.always_bodies) ? payload.always_bodies : [];
|
|
34
|
+
if (bodies.length > 0) {
|
|
35
|
+
lines.push("always-active (body injected):");
|
|
36
|
+
for (const b of bodies) {
|
|
37
|
+
lines.push(` [${b.type}] ${b.id} (${b.layer}) \xB7 ${b.summary}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const entries = Array.isArray(payload?.entries) ? payload.entries : [];
|
|
41
|
+
if (entries.length > 0) {
|
|
42
|
+
lines.push("reference / candidates:");
|
|
43
|
+
for (const e of entries) {
|
|
44
|
+
const provenance = typeof e.related_to === "string" ? ` \u2190related-to:${e.related_to}` : "";
|
|
45
|
+
lines.push(
|
|
46
|
+
` [${e.type}] ${e.id} (${e.maturity || "?"}, ${e.relevance_scope})${provenance} \xB7 ${e.summary}`
|
|
47
|
+
);
|
|
48
|
+
if (typeof e.must_read_if === "string" && e.must_read_if.length > 0) {
|
|
49
|
+
lines.push(` must_read_if: ${e.must_read_if}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const census = payload?.census;
|
|
54
|
+
if (census) {
|
|
55
|
+
const layer = census.by_layer ?? { team: 0, personal: 0, project: 0 };
|
|
56
|
+
lines.push(
|
|
57
|
+
`census: total ${census.total} \xB7 [team]${layer.team ?? 0} [project]${layer.project ?? 0} [personal]${layer.personal ?? 0}`
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
return lines.join("\n");
|
|
61
|
+
}
|
|
62
|
+
async function runContext(opts) {
|
|
63
|
+
const cwd = opts.target ? resolve(opts.target) : process.cwd();
|
|
64
|
+
const payload = opts.payload !== void 0 ? opts.payload : await runPlanContextHint({ all: true, target: opts.target });
|
|
65
|
+
const renderer = loadHookRenderer();
|
|
66
|
+
const sinks = renderer.buildSessionStartSinks(cwd, payload, {});
|
|
67
|
+
let base;
|
|
68
|
+
if (opts.render === "ai") {
|
|
69
|
+
base = sinks.ai ?? "";
|
|
70
|
+
} else if (opts.render === "human") {
|
|
71
|
+
base = sinks.human ?? "";
|
|
72
|
+
} else {
|
|
73
|
+
base = [sinks.human, sinks.ai].filter((s) => typeof s === "string" && s.length > 0).join("\n\n");
|
|
74
|
+
}
|
|
75
|
+
if (base.length === 0 && !sinks.hasRenderedContent) return "";
|
|
76
|
+
return opts.explain === true ? base + "\n" + renderExplain(sinks) : base;
|
|
77
|
+
}
|
|
78
|
+
var contextCommand = defineCommand({
|
|
79
|
+
meta: {
|
|
80
|
+
name: "context",
|
|
81
|
+
description: "Show what Fabric injects at SessionStart (the knowledge spine). --explain for per-entry provenance."
|
|
82
|
+
},
|
|
83
|
+
args: {
|
|
84
|
+
render: {
|
|
85
|
+
type: "string",
|
|
86
|
+
description: "Which sink to show: 'human' (systemMessage) or 'ai' (additionalContext). Default: both."
|
|
87
|
+
},
|
|
88
|
+
explain: {
|
|
89
|
+
type: "boolean",
|
|
90
|
+
description: "Append a per-entry provenance section (id \xB7 type \xB7 maturity \xB7 scope \xB7 why-surfaced).",
|
|
91
|
+
default: false
|
|
92
|
+
},
|
|
93
|
+
target: {
|
|
94
|
+
type: "string",
|
|
95
|
+
description: "Override the project root (defaults to cwd / dev-mode resolution)."
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
async run({ args }) {
|
|
99
|
+
try {
|
|
100
|
+
const render = args.render === "human" || args.render === "ai" ? args.render : void 0;
|
|
101
|
+
const out = await runContext({ render, explain: args.explain === true, target: args.target });
|
|
102
|
+
if (out.length > 0) process.stdout.write(`${out}
|
|
103
|
+
`);
|
|
104
|
+
} catch (error) {
|
|
105
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
106
|
+
process.stderr.write(`context failed: ${message}
|
|
107
|
+
`);
|
|
108
|
+
process.exitCode = 1;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
var context_default = contextCommand;
|
|
113
|
+
export {
|
|
114
|
+
contextCommand,
|
|
115
|
+
context_default as default,
|
|
116
|
+
runContext
|
|
117
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
doctorCommand,
|
|
4
|
+
doctor_default,
|
|
5
|
+
parseSinceDuration,
|
|
6
|
+
renderDoctorFilteredHelp,
|
|
7
|
+
renderTldrHeader
|
|
8
|
+
} from "./chunk-E7HJUU34.js";
|
|
9
|
+
import "./chunk-3D7B2UAZ.js";
|
|
10
|
+
import "./chunk-WA3DYGSY.js";
|
|
11
|
+
import "./chunk-NLNH64A3.js";
|
|
12
|
+
import "./chunk-PTGQAZEW.js";
|
|
13
|
+
import "./chunk-EOT63RDH.js";
|
|
14
|
+
import "./chunk-QPAW6IYT.js";
|
|
15
|
+
import "./chunk-QFIVFZRH.js";
|
|
16
|
+
import "./chunk-FNHDQTPC.js";
|
|
17
|
+
import "./chunk-HORSMSZL.js";
|
|
18
|
+
export {
|
|
19
|
+
doctor_default as default,
|
|
20
|
+
doctorCommand,
|
|
21
|
+
parseSinceDuration,
|
|
22
|
+
renderDoctorFilteredHelp,
|
|
23
|
+
renderTldrHeader
|
|
24
|
+
};
|
package/dist/index.d.ts
CHANGED