@fenglimg/fabric-cli 2.1.0-rc.2 → 2.2.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.
- package/dist/{chunk-PWLW3B57.js → chunk-2CY4BMTH.js} +5 -1
- package/dist/{chunk-F46ORPOA.js → chunk-2R55HNVD.js} +82 -5
- package/dist/{chunk-HFQVXY6P.js → chunk-4R2CYEA4.js} +31 -1
- package/dist/{chunk-BATF4PEJ.js → chunk-AOE6AYI7.js} +2 -2
- package/dist/{chunk-WWNXR34K.js → chunk-BO4XIZWZ.js} +8 -1
- package/dist/{chunk-MF3OTILQ.js → chunk-XC5RUHLK.js} +29 -8
- package/dist/{config-XJIPZNUP.js → config-XYRBZJDU.js} +3 -3
- package/dist/{doctor-QVNPHLJK.js → doctor-YONYXDX6.js} +39 -26
- package/dist/index.js +54 -14
- package/dist/{install-2HDO5FTQ.js → install-74ANPCCP.js} +88 -34
- package/dist/{metrics-ACEQFPDU.js → metrics-RER6NLFC.js} +22 -9
- package/dist/{onboard-coverage-MFCAEBDO.js → onboard-coverage-JWQWDZW7.js} +1 -1
- package/dist/{scope-explain-2F2R5URO.js → scope-explain-CDIZESP5.js} +6 -2
- package/dist/{store-XTSE5TY6.js → store-XB3ADT65.js} +50 -11
- package/dist/{sync-BJCWDPNC.js → sync-UJ4BBCZJ.js} +18 -12
- package/dist/{uninstall-TAXSUSKH.js → uninstall-C3QXKOO6.js} +35 -4
- package/dist/{whoami-B6AEMSEV.js → whoami-2MLO4Y37.js} +10 -5
- package/package.json +3 -3
- package/templates/hooks/fabric-hint.cjs +99 -7
- package/templates/hooks/knowledge-hint-broad.cjs +164 -9
- package/templates/hooks/knowledge-hint-narrow.cjs +10 -4
- package/templates/hooks/lib/injection-log.cjs +91 -0
- package/templates/hooks/lib/state-store.cjs +30 -11
- 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
|
@@ -4,8 +4,11 @@ import {
|
|
|
4
4
|
installArchiveHintHook,
|
|
5
5
|
installCitePolicyEvictHook,
|
|
6
6
|
installFabricArchiveSkill,
|
|
7
|
+
installFabricAuditSkill,
|
|
8
|
+
installFabricConnectSkill,
|
|
7
9
|
installFabricImportSkill,
|
|
8
10
|
installFabricReviewSkill,
|
|
11
|
+
installFabricStoreSkill,
|
|
9
12
|
installFabricSyncSkill,
|
|
10
13
|
installHookLibs,
|
|
11
14
|
installKnowledgeHintBroadHook,
|
|
@@ -19,25 +22,26 @@ import {
|
|
|
19
22
|
writeCodexBootstrapManagedBlock,
|
|
20
23
|
writeCursorBootstrapManagedBlock,
|
|
21
24
|
writeFabricAgentsSnapshot
|
|
22
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-2R55HNVD.js";
|
|
23
26
|
import {
|
|
24
27
|
displayWidth,
|
|
25
28
|
padEnd,
|
|
26
29
|
paint
|
|
27
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-BO4XIZWZ.js";
|
|
28
31
|
import {
|
|
29
32
|
createDebugLogger,
|
|
30
33
|
resolveDevMode
|
|
31
34
|
} from "./chunk-COI5VDFU.js";
|
|
32
35
|
import {
|
|
33
36
|
installMcpClients
|
|
34
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-AOE6AYI7.js";
|
|
35
38
|
import {
|
|
36
39
|
detectClientSupports
|
|
37
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-XC5RUHLK.js";
|
|
38
41
|
import {
|
|
42
|
+
getProjectTranslator,
|
|
39
43
|
t
|
|
40
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-2CY4BMTH.js";
|
|
41
45
|
import {
|
|
42
46
|
globalConfigPath,
|
|
43
47
|
loadGlobalConfig,
|
|
@@ -67,6 +71,9 @@ async function installHooks(target, _options = {}) {
|
|
|
67
71
|
results.push(...await runStep(() => installFabricReviewSkill(normalizedTarget)));
|
|
68
72
|
results.push(...await runStep(() => installFabricImportSkill(normalizedTarget)));
|
|
69
73
|
results.push(...await runStep(() => installFabricSyncSkill(normalizedTarget)));
|
|
74
|
+
results.push(...await runStep(() => installFabricStoreSkill(normalizedTarget)));
|
|
75
|
+
results.push(...await runStep(() => installFabricAuditSkill(normalizedTarget)));
|
|
76
|
+
results.push(...await runStep(() => installFabricConnectSkill(normalizedTarget)));
|
|
70
77
|
results.push(...await runStep(() => installSharedSkillLib(normalizedTarget)));
|
|
71
78
|
results.push(...await runStep(() => installArchiveHintHook(normalizedTarget)));
|
|
72
79
|
results.push(...await runStep(() => installKnowledgeHintBroadHook(normalizedTarget)));
|
|
@@ -197,11 +204,12 @@ import { mkdirSync, mkdtempSync, renameSync } from "fs";
|
|
|
197
204
|
import { tmpdir } from "os";
|
|
198
205
|
import { join as join3 } from "path";
|
|
199
206
|
import { STORES_ROOT_DIR as STORES_ROOT_DIR2, addMountedStore, readStoreIdentity } from "@fenglimg/fabric-shared";
|
|
207
|
+
import { GenericIOError } from "@fenglimg/fabric-shared/errors";
|
|
200
208
|
|
|
201
209
|
// src/store/uid.ts
|
|
202
210
|
import { execFileSync } from "child_process";
|
|
203
211
|
import { createHash } from "crypto";
|
|
204
|
-
function deriveUid() {
|
|
212
|
+
function deriveUid(opts = {}) {
|
|
205
213
|
let email = "";
|
|
206
214
|
try {
|
|
207
215
|
email = execFileSync("git", ["config", "user.email"], {
|
|
@@ -214,7 +222,8 @@ function deriveUid() {
|
|
|
214
222
|
if (email === "") {
|
|
215
223
|
return "u-anon";
|
|
216
224
|
}
|
|
217
|
-
const
|
|
225
|
+
const material = opts.salt !== void 0 && opts.salt.length > 0 ? `${opts.salt}:${email.toLowerCase()}` : email.toLowerCase();
|
|
226
|
+
const hash = createHash("sha256").update(material).digest("hex").slice(0, 12);
|
|
218
227
|
return `u-${hash}`;
|
|
219
228
|
}
|
|
220
229
|
|
|
@@ -319,7 +328,15 @@ async function installGlobalCore(options) {
|
|
|
319
328
|
|
|
320
329
|
// src/install/run-global-install.ts
|
|
321
330
|
function gitClone(url, dest) {
|
|
322
|
-
|
|
331
|
+
console.log(`cloning store from ${url} (this may take a while)\u2026`);
|
|
332
|
+
try {
|
|
333
|
+
execFileSync2("git", ["clone", "--", url, dest], { stdio: ["ignore", "ignore", "inherit"] });
|
|
334
|
+
} catch (error) {
|
|
335
|
+
throw new GenericIOError(`git clone of ${url} failed`, {
|
|
336
|
+
actionHint: "check the url is reachable and points to a Fabric store git repo (the git error above shows the cause), then re-run `fabric install --global <url>`",
|
|
337
|
+
details: error
|
|
338
|
+
});
|
|
339
|
+
}
|
|
323
340
|
}
|
|
324
341
|
function mountStoreFromRemote(url, globalRoot) {
|
|
325
342
|
const storesRoot = join3(globalRoot, STORES_ROOT_DIR2);
|
|
@@ -329,13 +346,17 @@ function mountStoreFromRemote(url, globalRoot) {
|
|
|
329
346
|
gitClone(url, cloneDest);
|
|
330
347
|
const identity = readStoreIdentity(cloneDest);
|
|
331
348
|
if (identity === null) {
|
|
332
|
-
throw new
|
|
349
|
+
throw new GenericIOError(`cloned store at ${url} has no valid store.json (not a Fabric store)`, {
|
|
350
|
+
actionHint: "verify the url points to a repository created by `fabric` (it must contain a store.json at its root); if you meant to mount a different store, re-run with the correct url"
|
|
351
|
+
});
|
|
333
352
|
}
|
|
334
353
|
const finalDir = join3(storesRoot, identity.store_uuid);
|
|
335
354
|
renameSync(cloneDest, finalDir);
|
|
336
355
|
const config = loadGlobalConfig(globalRoot);
|
|
337
356
|
if (config === null) {
|
|
338
|
-
throw new
|
|
357
|
+
throw new GenericIOError("global config missing after install", {
|
|
358
|
+
actionHint: "re-run `fabric install --global` to (re)create the global config, then retry mounting the store; if it persists, inspect ~/.fabric for a partial install"
|
|
359
|
+
});
|
|
339
360
|
}
|
|
340
361
|
const alias = identity.canonical_alias ?? "team";
|
|
341
362
|
saveGlobalConfig(
|
|
@@ -350,7 +371,12 @@ async function runGlobalInstall(options = {}, globalRoot = resolveGlobalRoot())
|
|
|
350
371
|
const now = options.now ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
351
372
|
const result = await installGlobalCore({ globalRoot, uid, personalStoreUuid, now });
|
|
352
373
|
if (!result.receipt.ok) {
|
|
353
|
-
throw new
|
|
374
|
+
throw new GenericIOError(
|
|
375
|
+
`global install failed at step '${result.receipt.failedStep}': ${result.receipt.error}`,
|
|
376
|
+
{
|
|
377
|
+
actionHint: "check write permissions and free space under ~/.fabric, then re-run `fabric install --global` (the install is transactional and rolls back partial state)"
|
|
378
|
+
}
|
|
379
|
+
);
|
|
354
380
|
}
|
|
355
381
|
console.log(
|
|
356
382
|
result.alreadyInstalled ? "global Fabric already installed" : `installed global Fabric (uid ${uid})`
|
|
@@ -419,6 +445,7 @@ import { existsSync as existsSync3, readdirSync as readdirSync2, readFileSync as
|
|
|
419
445
|
import { createRequire } from "module";
|
|
420
446
|
import { basename, extname, isAbsolute as isAbsolute2, join as join5, posix, relative, resolve as resolve2, sep } from "path";
|
|
421
447
|
import {
|
|
448
|
+
buildScanRecommendations,
|
|
422
449
|
forensicReportSchema
|
|
423
450
|
} from "@fenglimg/fabric-shared";
|
|
424
451
|
|
|
@@ -536,7 +563,7 @@ async function buildForensicReport(targetInput) {
|
|
|
536
563
|
candidate_files: candidateFiles,
|
|
537
564
|
sampling_budget: DEFAULT_SAMPLING_BUDGET,
|
|
538
565
|
readme,
|
|
539
|
-
recommendations_for_skill: buildSkillRecommendations(framework.kind, topology, readme)
|
|
566
|
+
recommendations_for_skill: buildSkillRecommendations(framework.kind, topology, readme, target)
|
|
540
567
|
};
|
|
541
568
|
const validation = forensicReportSchema.safeParse(report);
|
|
542
569
|
if (!validation.success) {
|
|
@@ -1491,27 +1518,15 @@ function isDomainFile(relativePath) {
|
|
|
1491
1518
|
}
|
|
1492
1519
|
return !isConfigFile(relativePath) && !isTestFile(relativePath);
|
|
1493
1520
|
}
|
|
1494
|
-
function buildSkillRecommendations(frameworkKind, topology, readme) {
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
recommendations.push("\u5EFA\u8BAE\u786E\u8BA4 app/pages \u8DEF\u7531\u8FB9\u754C\u548C\u670D\u52A1\u7AEF\u7EC4\u4EF6\u7EA6\u675F\u3002");
|
|
1504
|
-
} else if (frameworkKind === "vite") {
|
|
1505
|
-
recommendations.push("\u5EFA\u8BAE\u786E\u8BA4 src/main \u5165\u53E3\u3001\u7EC4\u4EF6\u76EE\u5F55\u548C\u6784\u5EFA\u811A\u672C\u7684\u7EF4\u62A4\u8FB9\u754C\u3002");
|
|
1506
|
-
} else if (frameworkKind === "unknown") {
|
|
1507
|
-
recommendations.push("\u672A\u68C0\u6D4B\u5230\u660E\u786E\u6846\u67B6,\u5EFA\u8BAE\u5148\u8BA9\u7528\u6237\u786E\u8BA4\u6280\u672F\u6808\u548C\u4E3B\u8981\u5165\u53E3\u3002");
|
|
1508
|
-
} else {
|
|
1509
|
-
recommendations.push(`\u5EFA\u8BAE\u56F4\u7ED5 ${frameworkKind} \u7684\u4E3B\u8981\u5165\u53E3\u548C\u751F\u6210\u76EE\u5F55\u786E\u8BA4 AGENTS.md \u5206\u5C42\u8FB9\u754C\u3002`);
|
|
1510
|
-
}
|
|
1511
|
-
if (readme.quality !== "ok") {
|
|
1512
|
-
recommendations.push("README \u4FE1\u606F\u4E0D\u8DB3,\u5EFA\u8BAE\u5728\u521D\u59CB\u5316\u8BBF\u8C08\u4E2D\u8865\u9F50\u9879\u76EE\u76EE\u6807\u3001\u8FD0\u884C\u65B9\u5F0F\u548C\u7981\u6539\u533A\u57DF\u3002");
|
|
1513
|
-
}
|
|
1514
|
-
return recommendations;
|
|
1521
|
+
function buildSkillRecommendations(frameworkKind, topology, readme, projectRoot) {
|
|
1522
|
+
return buildScanRecommendations(
|
|
1523
|
+
{
|
|
1524
|
+
frameworkKind,
|
|
1525
|
+
hasMeta: (topology.by_ext[".meta"] ?? 0) > 0,
|
|
1526
|
+
readmeOk: readme.quality === "ok"
|
|
1527
|
+
},
|
|
1528
|
+
getProjectTranslator(projectRoot)
|
|
1529
|
+
);
|
|
1515
1530
|
}
|
|
1516
1531
|
function readProjectName(target) {
|
|
1517
1532
|
const packageJsonPath = join5(target, "package.json");
|
|
@@ -1528,7 +1543,7 @@ function readProjectName(target) {
|
|
|
1528
1543
|
return basename(target);
|
|
1529
1544
|
}
|
|
1530
1545
|
function getCliVersion() {
|
|
1531
|
-
return true ? "2.
|
|
1546
|
+
return true ? "2.2.0-rc.1" : "unknown";
|
|
1532
1547
|
}
|
|
1533
1548
|
function sortRecord(record) {
|
|
1534
1549
|
return Object.fromEntries(Object.entries(record).sort(([left], [right]) => left.localeCompare(right)));
|
|
@@ -1609,6 +1624,11 @@ ${hint}
|
|
|
1609
1624
|
results.push(...await installFabricArchiveSkill(target));
|
|
1610
1625
|
results.push(...await installFabricReviewSkill(target));
|
|
1611
1626
|
results.push(...await installFabricImportSkill(target));
|
|
1627
|
+
results.push(...await installFabricSyncSkill(target));
|
|
1628
|
+
results.push(...await installFabricStoreSkill(target));
|
|
1629
|
+
results.push(...await installFabricAuditSkill(target));
|
|
1630
|
+
results.push(...await installFabricConnectSkill(target));
|
|
1631
|
+
results.push(...await installSharedSkillLib(target));
|
|
1612
1632
|
let written = 0;
|
|
1613
1633
|
let skipped = 0;
|
|
1614
1634
|
let errors = 0;
|
|
@@ -1706,6 +1726,24 @@ async function runInitCommand(args) {
|
|
|
1706
1726
|
}
|
|
1707
1727
|
return result;
|
|
1708
1728
|
}
|
|
1729
|
+
var FABRIC_GITIGNORE_CONTENT = [
|
|
1730
|
+
"# Fabric per-dev activity ledgers & caches \u2014 auto-generated, not shared.",
|
|
1731
|
+
"# Managed by `fabric install`; edit freely (re-install never overwrites this).",
|
|
1732
|
+
"events.jsonl",
|
|
1733
|
+
"metrics.jsonl",
|
|
1734
|
+
"cite-rollup.jsonl",
|
|
1735
|
+
"injections.jsonl",
|
|
1736
|
+
".cache/",
|
|
1737
|
+
"*.lock",
|
|
1738
|
+
"*.corrupted.*",
|
|
1739
|
+
""
|
|
1740
|
+
].join("\n");
|
|
1741
|
+
function writeDefaultGitignore(fabricDir) {
|
|
1742
|
+
const target = join6(fabricDir, ".gitignore");
|
|
1743
|
+
if (existsSync4(target)) return;
|
|
1744
|
+
mkdirSync2(fabricDir, { recursive: true });
|
|
1745
|
+
writeFileSync(target, FABRIC_GITIGNORE_CONTENT, "utf8");
|
|
1746
|
+
}
|
|
1709
1747
|
function writeDefaultFabricConfig(fabricDir, targetRoot) {
|
|
1710
1748
|
const target = join6(fabricDir, "fabric-config.json");
|
|
1711
1749
|
if (existsSync4(target)) return;
|
|
@@ -1916,7 +1954,16 @@ async function buildInitFabricPlan(target, options) {
|
|
|
1916
1954
|
const metaAction = diffStateToWriteAction(metaClassification.state);
|
|
1917
1955
|
const eventsAction = diffStateToWriteAction(eventsClassification.state);
|
|
1918
1956
|
const forensicAction = diffStateToWriteAction(forensicClassification.state);
|
|
1957
|
+
const showScanProgress = process.stderr.isTTY === true;
|
|
1958
|
+
if (showScanProgress) {
|
|
1959
|
+
process.stderr.write(`${t("cli.install.scanning")}
|
|
1960
|
+
`);
|
|
1961
|
+
}
|
|
1919
1962
|
const forensicReport = await buildForensicReport(target);
|
|
1963
|
+
if (showScanProgress) {
|
|
1964
|
+
process.stderr.write(`${t("cli.install.scan-complete")}
|
|
1965
|
+
`);
|
|
1966
|
+
}
|
|
1920
1967
|
const meta = createInitialMeta();
|
|
1921
1968
|
return {
|
|
1922
1969
|
target,
|
|
@@ -1947,6 +1994,7 @@ async function executeInitFabricPlan(plan) {
|
|
|
1947
1994
|
}
|
|
1948
1995
|
mkdirSync2(plan.fabricDir, { recursive: true });
|
|
1949
1996
|
writeDefaultFabricConfig(plan.fabricDir, plan.target);
|
|
1997
|
+
writeDefaultGitignore(plan.fabricDir);
|
|
1950
1998
|
mkdirSync2(plan.knowledgeDir, { recursive: true });
|
|
1951
1999
|
for (const sub of KNOWLEDGE_SUBDIRS) {
|
|
1952
2000
|
const teamSubDir = join6(plan.knowledgeDir, sub);
|
|
@@ -2126,9 +2174,15 @@ async function executeInitStagePlan(plan, stageName) {
|
|
|
2126
2174
|
installResults.push(...await runBestEffort("skill-install", () => installFabricArchiveSkill(plan.target)));
|
|
2127
2175
|
installResults.push(...await runBestEffort("skill-review-install", () => installFabricReviewSkill(plan.target)));
|
|
2128
2176
|
installResults.push(...await runBestEffort("skill-import-install", () => installFabricImportSkill(plan.target)));
|
|
2177
|
+
installResults.push(...await runBestEffort("skill-sync-install", () => installFabricSyncSkill(plan.target)));
|
|
2178
|
+
installResults.push(...await runBestEffort("skill-store-install", () => installFabricStoreSkill(plan.target)));
|
|
2179
|
+
installResults.push(...await runBestEffort("skill-audit-install", () => installFabricAuditSkill(plan.target)));
|
|
2180
|
+
installResults.push(...await runBestEffort("skill-connect-install", () => installFabricConnectSkill(plan.target)));
|
|
2181
|
+
installResults.push(...await runBestEffort("skill-shared-lib", () => installSharedSkillLib(plan.target)));
|
|
2129
2182
|
installResults.push(...await runBestEffort("hook-script", () => installArchiveHintHook(plan.target)));
|
|
2130
2183
|
installResults.push(...await runBestEffort("hook-broad-script", () => installKnowledgeHintBroadHook(plan.target)));
|
|
2131
2184
|
installResults.push(...await runBestEffort("hook-narrow-script", () => installKnowledgeHintNarrowHook(plan.target)));
|
|
2185
|
+
installResults.push(...await runBestEffort("hook-cite-policy-evict-script", () => installCitePolicyEvictHook(plan.target)));
|
|
2132
2186
|
installResults.push(...await runBestEffort("hook-lib", () => installHookLibs(plan.target)));
|
|
2133
2187
|
installResults.push(await runBestEffortSingle("claude-hook-config", () => mergeClaudeCodeHookConfig(plan.target)));
|
|
2134
2188
|
installResults.push(await runBestEffortSingle("codex-hook-config", () => mergeCodexHookConfig(plan.target)));
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
getProjectTranslator
|
|
4
|
+
} from "./chunk-2CY4BMTH.js";
|
|
2
5
|
|
|
3
6
|
// src/commands/metrics.ts
|
|
4
7
|
import { resolve } from "path";
|
|
5
8
|
import { defineCommand } from "citty";
|
|
6
9
|
import { readMetrics } from "@fenglimg/fabric-server";
|
|
7
|
-
function parseSinceArg(raw) {
|
|
10
|
+
function parseSinceArg(raw, t) {
|
|
8
11
|
if (raw === void 0 || raw.length === 0) return 0;
|
|
9
12
|
const match = /^(\d+)([smhd]?)$/u.exec(raw);
|
|
10
13
|
if (match === null) {
|
|
11
|
-
throw new Error(
|
|
14
|
+
throw new Error(t("cli.metrics.invalid-since", { raw }));
|
|
12
15
|
}
|
|
13
16
|
const n = Number.parseInt(match[1], 10);
|
|
14
17
|
const unit = match[2] ?? "s";
|
|
@@ -36,6 +39,8 @@ function aggregate(rows, sinceMs, now) {
|
|
|
36
39
|
}
|
|
37
40
|
}
|
|
38
41
|
return {
|
|
42
|
+
// Stable token (NOT localized) so the --json contract is locale-independent;
|
|
43
|
+
// renderText localizes "all-time" at presentation time only.
|
|
39
44
|
windowDescription: sinceMs > 0 ? formatDuration(sinceMs) : "all-time",
|
|
40
45
|
rowCount: filtered.length,
|
|
41
46
|
totals,
|
|
@@ -50,17 +55,24 @@ function formatDuration(ms) {
|
|
|
50
55
|
if (ms >= 6e4) return `${Math.round(ms / 6e4)}m`;
|
|
51
56
|
return `${Math.round(ms / 1e3)}s`;
|
|
52
57
|
}
|
|
53
|
-
function renderText(agg) {
|
|
58
|
+
function renderText(agg, t) {
|
|
54
59
|
const lines = [];
|
|
55
|
-
|
|
60
|
+
const windowDisplay = agg.windowDescription === "all-time" ? t("cli.metrics.window-all-time") : agg.windowDescription;
|
|
61
|
+
lines.push(t("cli.metrics.window", { window: windowDisplay }));
|
|
56
62
|
if (agg.rangeStart && agg.rangeEnd) {
|
|
57
|
-
lines.push(
|
|
63
|
+
lines.push(
|
|
64
|
+
t("cli.metrics.rows-range", {
|
|
65
|
+
count: String(agg.rowCount),
|
|
66
|
+
start: agg.rangeStart,
|
|
67
|
+
end: agg.rangeEnd
|
|
68
|
+
})
|
|
69
|
+
);
|
|
58
70
|
} else {
|
|
59
|
-
lines.push(
|
|
71
|
+
lines.push(t("cli.metrics.rows", { count: String(agg.rowCount) }));
|
|
60
72
|
}
|
|
61
73
|
lines.push("");
|
|
62
74
|
if (Object.keys(agg.totals).length === 0) {
|
|
63
|
-
lines.push("
|
|
75
|
+
lines.push(t("cli.metrics.no-activity"));
|
|
64
76
|
return lines.join("\n");
|
|
65
77
|
}
|
|
66
78
|
lines.push(" counter total");
|
|
@@ -103,14 +115,15 @@ var metricsCommand = defineCommand({
|
|
|
103
115
|
},
|
|
104
116
|
async run({ args }) {
|
|
105
117
|
const projectRoot = resolve(args.target ?? process.cwd());
|
|
106
|
-
const
|
|
118
|
+
const t = getProjectTranslator(projectRoot);
|
|
119
|
+
const sinceMs = parseSinceArg(args.since, t);
|
|
107
120
|
const rows = await readMetrics(projectRoot);
|
|
108
121
|
const aggregated = aggregate(rows, sinceMs, /* @__PURE__ */ new Date());
|
|
109
122
|
if (args.json === true) {
|
|
110
123
|
process.stdout.write(`${JSON.stringify(aggregated)}
|
|
111
124
|
`);
|
|
112
125
|
} else {
|
|
113
|
-
process.stdout.write(`${renderText(aggregated)}
|
|
126
|
+
process.stdout.write(`${renderText(aggregated, t)}
|
|
114
127
|
`);
|
|
115
128
|
}
|
|
116
129
|
}
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
import {
|
|
3
3
|
scopeExplain
|
|
4
4
|
} from "./chunk-L4Q55UC4.js";
|
|
5
|
+
import {
|
|
6
|
+
getProjectTranslator
|
|
7
|
+
} from "./chunk-2CY4BMTH.js";
|
|
5
8
|
import "./chunk-LFIKMVY7.js";
|
|
6
9
|
import "./chunk-RYAFBNES.js";
|
|
7
10
|
|
|
@@ -20,9 +23,10 @@ var scope_explain_default = defineCommand({
|
|
|
20
23
|
}
|
|
21
24
|
},
|
|
22
25
|
run({ args }) {
|
|
23
|
-
const
|
|
26
|
+
const projectRoot = process.cwd();
|
|
27
|
+
const result = scopeExplain(projectRoot, args.scope);
|
|
24
28
|
if (result === null) {
|
|
25
|
-
console.log("no
|
|
29
|
+
console.log(getProjectTranslator(projectRoot)("cli.cmd.no-global-config"));
|
|
26
30
|
return;
|
|
27
31
|
}
|
|
28
32
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
assertStoreMountable,
|
|
3
4
|
storeAdd,
|
|
4
5
|
storeBind,
|
|
6
|
+
storeCreate,
|
|
5
7
|
storeExplain,
|
|
6
8
|
storeList,
|
|
7
9
|
storeRemove,
|
|
8
10
|
storeSwitchWrite
|
|
9
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-4R2CYEA4.js";
|
|
10
12
|
import {
|
|
11
13
|
regenerateBindingsSnapshot
|
|
12
14
|
} from "./chunk-WU6GAPKH.js";
|
|
13
15
|
import "./chunk-L4Q55UC4.js";
|
|
16
|
+
import {
|
|
17
|
+
getProjectTranslator
|
|
18
|
+
} from "./chunk-2CY4BMTH.js";
|
|
14
19
|
import "./chunk-LFIKMVY7.js";
|
|
15
20
|
import "./chunk-RYAFBNES.js";
|
|
16
21
|
|
|
@@ -19,13 +24,15 @@ import { defineCommand } from "citty";
|
|
|
19
24
|
var listCommand = defineCommand({
|
|
20
25
|
meta: { name: "list", description: "List mounted knowledge stores" },
|
|
21
26
|
run() {
|
|
27
|
+
const t = getProjectTranslator();
|
|
22
28
|
const stores = storeList();
|
|
23
29
|
if (stores.length === 0) {
|
|
24
|
-
console.log("
|
|
30
|
+
console.log(t("cli.store.none-mounted"));
|
|
25
31
|
return;
|
|
26
32
|
}
|
|
33
|
+
const localOnly = t("cli.shared.local-only");
|
|
27
34
|
for (const store of stores) {
|
|
28
|
-
console.log(`${store.alias} ${store.store_uuid} ${store.remote ??
|
|
35
|
+
console.log(`${store.alias} ${store.store_uuid} ${store.remote ?? localOnly}`);
|
|
29
36
|
}
|
|
30
37
|
}
|
|
31
38
|
});
|
|
@@ -37,9 +44,32 @@ var addCommand = defineCommand({
|
|
|
37
44
|
remote: { type: "string", description: "Git remote locator (omit for local-only)" }
|
|
38
45
|
},
|
|
39
46
|
run({ args }) {
|
|
47
|
+
assertStoreMountable(args.uuid);
|
|
40
48
|
const store = args.remote === void 0 ? { store_uuid: args.uuid, alias: args.alias } : { store_uuid: args.uuid, alias: args.alias, remote: args.remote };
|
|
41
49
|
const next = storeAdd(store);
|
|
42
|
-
console.log(
|
|
50
|
+
console.log(
|
|
51
|
+
getProjectTranslator()("cli.store.mounted", {
|
|
52
|
+
alias: args.alias,
|
|
53
|
+
count: String(next.stores.length)
|
|
54
|
+
})
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
var createCommand = defineCommand({
|
|
59
|
+
meta: { name: "create", description: "Create a brand-new local knowledge store and mount it" },
|
|
60
|
+
args: {
|
|
61
|
+
alias: { type: "string", required: true, description: "Local alias for the new store" },
|
|
62
|
+
remote: { type: "string", description: "Git remote to associate (push target; optional)" }
|
|
63
|
+
},
|
|
64
|
+
run({ args }) {
|
|
65
|
+
const result = storeCreate(args.alias, (/* @__PURE__ */ new Date()).toISOString(), {
|
|
66
|
+
...args.remote === void 0 ? {} : { remote: args.remote }
|
|
67
|
+
});
|
|
68
|
+
const t = getProjectTranslator();
|
|
69
|
+
console.log(
|
|
70
|
+
t("cli.store.created", { alias: args.alias, uuid: result.store_uuid, dir: result.storeDir }) + (args.remote === void 0 ? `
|
|
71
|
+
${t("cli.store.created-local-hint")}` : "")
|
|
72
|
+
);
|
|
43
73
|
}
|
|
44
74
|
});
|
|
45
75
|
var removeCommand = defineCommand({
|
|
@@ -49,8 +79,9 @@ var removeCommand = defineCommand({
|
|
|
49
79
|
},
|
|
50
80
|
run({ args }) {
|
|
51
81
|
const { detached } = storeRemove(args.alias);
|
|
82
|
+
const t = getProjectTranslator();
|
|
52
83
|
console.log(
|
|
53
|
-
detached === null ?
|
|
84
|
+
detached === null ? t("cli.store.no-alias", { alias: args.alias }) : t("cli.store.detached", { alias: args.alias })
|
|
54
85
|
);
|
|
55
86
|
}
|
|
56
87
|
});
|
|
@@ -62,7 +93,7 @@ var explainCommand = defineCommand({
|
|
|
62
93
|
run({ args }) {
|
|
63
94
|
const explanation = storeExplain(args.alias);
|
|
64
95
|
console.log(
|
|
65
|
-
explanation === null ?
|
|
96
|
+
explanation === null ? getProjectTranslator()("cli.store.no-alias", { alias: args.alias }) : JSON.stringify(explanation, null, 2)
|
|
66
97
|
);
|
|
67
98
|
}
|
|
68
99
|
});
|
|
@@ -74,9 +105,15 @@ var bindCommand = defineCommand({
|
|
|
74
105
|
},
|
|
75
106
|
run({ args }) {
|
|
76
107
|
const entry = args.remote === void 0 ? { id: args.id } : { id: args.id, suggested_remote: args.remote };
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
108
|
+
const projectRoot = process.cwd();
|
|
109
|
+
const next = storeBind(projectRoot, entry);
|
|
110
|
+
console.log(
|
|
111
|
+
getProjectTranslator(projectRoot)("cli.store.bound", {
|
|
112
|
+
id: args.id,
|
|
113
|
+
count: String(next.required_stores?.length ?? 0)
|
|
114
|
+
})
|
|
115
|
+
);
|
|
116
|
+
regenerateBindingsSnapshot(projectRoot, { now: (/* @__PURE__ */ new Date()).toISOString() });
|
|
80
117
|
}
|
|
81
118
|
});
|
|
82
119
|
var switchWriteCommand = defineCommand({
|
|
@@ -85,14 +122,16 @@ var switchWriteCommand = defineCommand({
|
|
|
85
122
|
alias: { type: "positional", required: true, description: "Alias of the store to write to" }
|
|
86
123
|
},
|
|
87
124
|
run({ args }) {
|
|
88
|
-
|
|
89
|
-
|
|
125
|
+
const projectRoot = process.cwd();
|
|
126
|
+
storeSwitchWrite(projectRoot, args.alias);
|
|
127
|
+
console.log(getProjectTranslator(projectRoot)("cli.store.switch-write", { alias: args.alias }));
|
|
90
128
|
}
|
|
91
129
|
});
|
|
92
130
|
var store_default = defineCommand({
|
|
93
131
|
meta: { name: "store", description: "Manage mounted Fabric knowledge stores" },
|
|
94
132
|
subCommands: {
|
|
95
133
|
list: listCommand,
|
|
134
|
+
create: createCommand,
|
|
96
135
|
add: addCommand,
|
|
97
136
|
remove: removeCommand,
|
|
98
137
|
explain: explainCommand,
|
|
@@ -3,6 +3,9 @@ import {
|
|
|
3
3
|
regenerateBindingsSnapshot
|
|
4
4
|
} from "./chunk-WU6GAPKH.js";
|
|
5
5
|
import "./chunk-L4Q55UC4.js";
|
|
6
|
+
import {
|
|
7
|
+
getProjectTranslator
|
|
8
|
+
} from "./chunk-2CY4BMTH.js";
|
|
6
9
|
import "./chunk-LFIKMVY7.js";
|
|
7
10
|
import {
|
|
8
11
|
loadGlobalConfig,
|
|
@@ -17,6 +20,7 @@ import { execFileSync } from "child_process";
|
|
|
17
20
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
18
21
|
import { join } from "path";
|
|
19
22
|
import { GLOBAL_STATE_DIR, storeRelativePath } from "@fenglimg/fabric-shared";
|
|
23
|
+
import { GenericIOError } from "@fenglimg/fabric-shared/errors";
|
|
20
24
|
|
|
21
25
|
// src/sync/state-machine.ts
|
|
22
26
|
function syncTransition(state, event) {
|
|
@@ -112,7 +116,11 @@ function defaultPull(storeDir) {
|
|
|
112
116
|
)) {
|
|
113
117
|
return "offline";
|
|
114
118
|
}
|
|
115
|
-
|
|
119
|
+
const gitMessage = detail.trim().length > 0 ? detail.trim() : "unknown git error";
|
|
120
|
+
throw new GenericIOError(`git pull --rebase failed in ${storeDir}: ${gitMessage}`, {
|
|
121
|
+
actionHint: "resolve the git issue above (e.g. authentication, a dirty working tree, or a detached HEAD), then re-run `fabric sync`",
|
|
122
|
+
details: error
|
|
123
|
+
});
|
|
116
124
|
}
|
|
117
125
|
}
|
|
118
126
|
function gitErrText(error, key) {
|
|
@@ -206,19 +214,16 @@ function runAbortSync(options) {
|
|
|
206
214
|
}
|
|
207
215
|
|
|
208
216
|
// src/commands/sync.ts
|
|
209
|
-
function report(result) {
|
|
217
|
+
function report(result, projectRoot) {
|
|
218
|
+
const t = getProjectTranslator(projectRoot);
|
|
210
219
|
for (const store of result.session.stores) {
|
|
211
220
|
console.log(`${store.alias} ${store.state}`);
|
|
212
221
|
}
|
|
213
222
|
if (result.deferred.length > 0) {
|
|
214
|
-
console.log(
|
|
215
|
-
`${result.deferred.length} store(s) offline \u2014 push deferred; re-run \`fabric sync\` when online`
|
|
216
|
-
);
|
|
223
|
+
console.log(t("cli.sync.deferred", { count: String(result.deferred.length) }));
|
|
217
224
|
}
|
|
218
225
|
if (!result.settled) {
|
|
219
|
-
console.log(
|
|
220
|
-
"sync paused on a conflict \u2014 resolve it, then run `fabric sync --continue` (or `--abort`)"
|
|
221
|
-
);
|
|
226
|
+
console.log(t("cli.sync.paused"));
|
|
222
227
|
}
|
|
223
228
|
}
|
|
224
229
|
var sync_default = defineCommand({
|
|
@@ -228,16 +233,17 @@ var sync_default = defineCommand({
|
|
|
228
233
|
abort: { type: "boolean", description: "Abort the conflicted store's rebase" }
|
|
229
234
|
},
|
|
230
235
|
run({ args }) {
|
|
231
|
-
const
|
|
236
|
+
const projectRoot = process.cwd();
|
|
237
|
+
const options = { projectRoot, now: (/* @__PURE__ */ new Date()).toISOString() };
|
|
232
238
|
if (args.continue === true) {
|
|
233
|
-
report(runContinueSync(options));
|
|
239
|
+
report(runContinueSync(options), projectRoot);
|
|
234
240
|
return;
|
|
235
241
|
}
|
|
236
242
|
if (args.abort === true) {
|
|
237
|
-
report(runAbortSync(options));
|
|
243
|
+
report(runAbortSync(options), projectRoot);
|
|
238
244
|
return;
|
|
239
245
|
}
|
|
240
|
-
report(runStartSync(options));
|
|
246
|
+
report(runStartSync(options), projectRoot);
|
|
241
247
|
}
|
|
242
248
|
});
|
|
243
249
|
export {
|
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
HOOK_SCRIPT_DESTINATIONS,
|
|
8
8
|
SKILL_DESTINATIONS,
|
|
9
9
|
fabricAgentsSnapshotPath
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-2R55HNVD.js";
|
|
11
11
|
import {
|
|
12
12
|
paint
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-BO4XIZWZ.js";
|
|
14
14
|
import {
|
|
15
15
|
createDebugLogger,
|
|
16
16
|
resolveDevMode
|
|
@@ -18,10 +18,10 @@ import {
|
|
|
18
18
|
import {
|
|
19
19
|
detectClientSupports,
|
|
20
20
|
resolveClients
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-XC5RUHLK.js";
|
|
22
22
|
import {
|
|
23
23
|
t
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-2CY4BMTH.js";
|
|
25
25
|
|
|
26
26
|
// src/commands/uninstall.ts
|
|
27
27
|
import { existsSync as existsSync2, statSync } from "fs";
|
|
@@ -49,6 +49,12 @@ async function uninstallFabricImportSkill(projectRoot) {
|
|
|
49
49
|
async function uninstallFabricSyncSkill(projectRoot) {
|
|
50
50
|
return removeSkill("skill-sync", SKILL_DESTINATIONS.fabricSync, projectRoot);
|
|
51
51
|
}
|
|
52
|
+
async function uninstallFabricAuditSkill(projectRoot) {
|
|
53
|
+
return removeSkill("skill-audit", SKILL_DESTINATIONS.fabricAudit, projectRoot);
|
|
54
|
+
}
|
|
55
|
+
async function uninstallFabricConnectSkill(projectRoot) {
|
|
56
|
+
return removeSkill("skill-connect", SKILL_DESTINATIONS.fabricConnect, projectRoot);
|
|
57
|
+
}
|
|
52
58
|
async function removeSkill(step, rels, projectRoot) {
|
|
53
59
|
const results = [];
|
|
54
60
|
for (const rel of rels) {
|
|
@@ -75,6 +81,13 @@ async function removeKnowledgeHintNarrowHook(projectRoot) {
|
|
|
75
81
|
projectRoot
|
|
76
82
|
);
|
|
77
83
|
}
|
|
84
|
+
async function removeCitePolicyEvictHook(projectRoot) {
|
|
85
|
+
return removeHookScripts(
|
|
86
|
+
"hook-cite-policy-evict-script",
|
|
87
|
+
HOOK_SCRIPT_DESTINATIONS.citePolicyEvict,
|
|
88
|
+
projectRoot
|
|
89
|
+
);
|
|
90
|
+
}
|
|
78
91
|
async function removeHookScripts(step, rels, projectRoot) {
|
|
79
92
|
const results = [];
|
|
80
93
|
for (const rel of rels) {
|
|
@@ -304,6 +317,24 @@ async function uninstallBootstrapStage(projectRoot, _opts = {}) {
|
|
|
304
317
|
projectRoot,
|
|
305
318
|
() => removeArchiveHintHook(projectRoot)
|
|
306
319
|
);
|
|
320
|
+
await runAndCollect(
|
|
321
|
+
results,
|
|
322
|
+
"hook-cite-policy-evict-script",
|
|
323
|
+
projectRoot,
|
|
324
|
+
() => removeCitePolicyEvictHook(projectRoot)
|
|
325
|
+
);
|
|
326
|
+
await runAndCollect(
|
|
327
|
+
results,
|
|
328
|
+
"skill-connect",
|
|
329
|
+
projectRoot,
|
|
330
|
+
() => uninstallFabricConnectSkill(projectRoot)
|
|
331
|
+
);
|
|
332
|
+
await runAndCollect(
|
|
333
|
+
results,
|
|
334
|
+
"skill-audit",
|
|
335
|
+
projectRoot,
|
|
336
|
+
() => uninstallFabricAuditSkill(projectRoot)
|
|
337
|
+
);
|
|
307
338
|
await runAndCollect(
|
|
308
339
|
results,
|
|
309
340
|
"skill-sync",
|