@fenglimg/fabric-cli 2.2.0-rc.9 → 2.3.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +2 -2
  2. package/dist/audit-PURSJJFH.js +734 -0
  3. package/dist/{chunk-YM4XATJF.js → chunk-722JU5BP.js} +2 -0
  4. package/dist/{chunk-QPAW6IYT.js → chunk-7V4XMLQ2.js} +3 -3
  5. package/dist/{chunk-7ZDXBOOU.js → chunk-ACSMNX3V.js} +44 -128
  6. package/dist/{chunk-PTGQAZEW.js → chunk-GGDVZCD6.js} +2 -4
  7. package/dist/{chunk-EOT63RDH.js → chunk-I5F5BHWI.js} +9 -0
  8. package/dist/chunk-PP7QVRXH.js +565 -0
  9. package/dist/chunk-SL77FXX7.js +54 -0
  10. package/dist/{chunk-3D7B2UAZ.js → chunk-VQKXTMWH.js} +44 -4
  11. package/dist/doctor-S6KPGS35.js +27 -0
  12. package/dist/index.js +91 -81
  13. package/dist/{info-7FKBTMVO.js → info-NJEY26H6.js} +91 -46
  14. package/dist/{context-7NUKXDB6.js → inspect-5YZMJPFM.js} +11 -11
  15. package/dist/{install-v2-I6PJ6IFT.js → install-v2-KGIDII4H.js} +163 -364
  16. package/dist/{plan-context-hint-G75R4P4J.js → plan-context-hint-5TNGH3R4.js} +1 -1
  17. package/dist/{store-HOCORVL3.js → store-GF4SFBMJ.js} +155 -57
  18. package/dist/{sync-DT5UJMMR.js → sync-3XCIRDPK.js} +3 -4
  19. package/dist/{uninstall-IFN2KYBK.js → uninstall-BG4ML4FC.js} +39 -10
  20. package/package.json +3 -7
  21. package/templates/hooks/cite-policy-evict.cjs +1 -1
  22. package/templates/hooks/configs/claude-code.json +1 -5
  23. package/templates/hooks/configs/codex-hooks.json +1 -5
  24. package/templates/hooks/fabric-hint.cjs +346 -138
  25. package/templates/hooks/knowledge-hint-broad.cjs +265 -75
  26. package/templates/hooks/knowledge-hint-narrow.cjs +3 -3
  27. package/templates/hooks/knowledge-pretooluse.cjs +111 -0
  28. package/templates/hooks/lib/banner-i18n.cjs +31 -12
  29. package/templates/hooks/lib/bindings-snapshot-reader.cjs +1 -1
  30. package/templates/hooks/lib/event-writer.cjs +79 -0
  31. package/templates/hooks/lib/nudge-policy.cjs +11 -0
  32. package/templates/hooks/lib/theme.cjs +62 -0
  33. package/templates/hooks/post-tooluse-mutation.cjs +28 -39
  34. package/templates/skills/fabric-archive/SKILL.md +43 -12
  35. package/templates/skills/fabric-archive/ref/dry-run-scope.md +1 -1
  36. package/templates/skills/fabric-archive/ref/i18n-policy.md +1 -1
  37. package/templates/skills/fabric-archive/ref/phase-1-5-onboard.md +5 -5
  38. package/templates/skills/fabric-archive/ref/phase-1-cross-session.md +2 -2
  39. package/templates/skills/fabric-archive/ref/phase-2-5-viability.md +1 -1
  40. package/templates/skills/fabric-archive/ref/phase-3-5-scope.md +1 -1
  41. package/templates/skills/fabric-archive/ref/phase-3-6-related-edges.md +1 -1
  42. package/templates/skills/fabric-archive/ref/phase-3-classify.md +1 -1
  43. package/templates/skills/fabric-archive/ref/phase-4-5-emit.md +1 -1
  44. package/templates/skills/fabric-archive/ref/phase-4-mcp-persist.md +6 -5
  45. package/templates/skills/{fabric-import/ref/checkpoint-state.md → fabric-archive/ref/source-checkpoint.md} +3 -3
  46. package/templates/skills/{fabric-import/ref/phase-3-dedup.md → fabric-archive/ref/source-dedup.md} +4 -4
  47. package/templates/skills/{fabric-import/ref/phase-2-mining.md → fabric-archive/ref/source-mining.md} +20 -20
  48. package/templates/skills/{fabric-import/ref/output-contract.md → fabric-archive/ref/source-output-contract.md} +3 -3
  49. package/templates/skills/{fabric-import/ref/state-recovery.md → fabric-archive/ref/source-state-recovery.md} +2 -2
  50. package/templates/skills/{fabric-import/ref/worked-examples.md → fabric-archive/ref/source-worked-examples.md} +10 -10
  51. package/templates/skills/fabric-archive/ref/worked-examples.md +3 -3
  52. package/templates/skills/fabric-review/SKILL.md +28 -15
  53. package/templates/skills/fabric-review/ref/cite-contract.md +2 -2
  54. package/templates/skills/fabric-review/ref/modify-flow.md +13 -1
  55. package/templates/skills/fabric-review/ref/per-mode-flows.md +5 -5
  56. package/templates/skills/fabric-review/ref/relate-mode.md +33 -0
  57. package/templates/skills/fabric-review/ref/retire-mode.md +47 -0
  58. package/templates/skills/fabric-review/ref/semantic-check.md +1 -1
  59. package/templates/skills/fabric-review/ref/worked-examples.md +5 -5
  60. package/templates/skills/fabric-store/SKILL.md +12 -27
  61. package/templates/skills/fabric-sync/SKILL.md +16 -35
  62. package/templates/skills/lib/shared-policy.md +6 -4
  63. package/dist/chunk-27HK6H5Y.js +0 -69
  64. package/dist/chunk-E7HJUU34.js +0 -1096
  65. package/dist/chunk-NLNH64A3.js +0 -43
  66. package/dist/chunk-QFIVFZRH.js +0 -13
  67. package/dist/doctor-MDTZWKBK.js +0 -24
  68. package/dist/metrics-HMFH4YHK.js +0 -135
  69. package/dist/scope-explain-HLJZ2M33.js +0 -48
  70. package/dist/status-4R3TM4FJ.js +0 -37
  71. package/dist/whoami-ITGEFWH4.js +0 -49
  72. package/templates/skills/fabric/SKILL.md +0 -100
  73. package/templates/skills/fabric-audit/SKILL.md +0 -63
  74. package/templates/skills/fabric-connect/SKILL.md +0 -48
  75. package/templates/skills/fabric-import/SKILL.md +0 -151
  76. package/templates/skills/fabric-import/ref/i18n-policy.md +0 -78
@@ -1,43 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/colors.ts
4
- import pc from "picocolors";
5
- import stringWidth from "string-width";
6
- function isColorEnabled() {
7
- if (process.env.NO_COLOR) {
8
- return false;
9
- }
10
- const force = process.env.FORCE_COLOR;
11
- if (force !== void 0) {
12
- return force !== "0" && force.toLowerCase() !== "false";
13
- }
14
- return Boolean(process.stdout.isTTY);
15
- }
16
- function colorize(painter) {
17
- return (value) => isColorEnabled() ? painter(value) : value;
18
- }
19
- var paint = {
20
- success: colorize(pc.green),
21
- warn: colorize(pc.yellow),
22
- error: colorize(pc.red),
23
- drift: colorize(pc.magenta),
24
- ai: colorize(pc.blue),
25
- human: colorize(pc.cyan),
26
- muted: colorize(pc.dim)
27
- };
28
- var symbol = {
29
- get ok() {
30
- return isColorEnabled() ? paint.success("[ok] \u2713") : "[ok]";
31
- },
32
- get warn() {
33
- return isColorEnabled() ? paint.warn("[warn] !") : "[warn]";
34
- },
35
- get error() {
36
- return isColorEnabled() ? paint.error("[error] x") : "[error]";
37
- }
38
- };
39
-
40
- export {
41
- paint,
42
- symbol
43
- };
@@ -1,13 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/store/project-config-io.ts
4
- import {
5
- projectConfigPath,
6
- loadProjectConfig,
7
- saveProjectConfig
8
- } from "@fenglimg/fabric-shared";
9
-
10
- export {
11
- loadProjectConfig,
12
- saveProjectConfig
13
- };
@@ -1,24 +0,0 @@
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
- };
@@ -1,135 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- getProjectTranslator
4
- } from "./chunk-HORSMSZL.js";
5
-
6
- // src/commands/metrics.ts
7
- import { resolve } from "path";
8
- import { defineCommand } from "citty";
9
- import { readMetrics } from "@fenglimg/fabric-server";
10
- function parseSinceArg(raw, t) {
11
- if (raw === void 0 || raw.length === 0) return 0;
12
- const match = /^(\d+)([smhd]?)$/u.exec(raw);
13
- if (match === null) {
14
- throw new Error(t("cli.metrics.invalid-since", { raw }));
15
- }
16
- const n = Number.parseInt(match[1], 10);
17
- const unit = match[2] ?? "s";
18
- const multipliers = { s: 1e3, m: 6e4, h: 36e5, d: 864e5 };
19
- return n * (multipliers[unit] ?? 1e3);
20
- }
21
- function aggregate(rows, sinceMs, now) {
22
- const cutoff = sinceMs > 0 ? now.getTime() - sinceMs : 0;
23
- const filtered = rows.filter((r) => {
24
- if (cutoff === 0) return true;
25
- const ts = Date.parse(r.timestamp);
26
- return Number.isFinite(ts) && ts >= cutoff;
27
- });
28
- const totals = {};
29
- const perEntryConsumed = {};
30
- for (const row of filtered) {
31
- for (const [name, count] of Object.entries(row.counters)) {
32
- if (name.startsWith("knowledge_consumed:")) {
33
- const id = name.slice("knowledge_consumed:".length);
34
- perEntryConsumed[id] = (perEntryConsumed[id] ?? 0) + count;
35
- totals["knowledge_consumed"] = (totals["knowledge_consumed"] ?? 0) + count;
36
- continue;
37
- }
38
- totals[name] = (totals[name] ?? 0) + count;
39
- }
40
- }
41
- return {
42
- // Stable token (NOT localized) so the --json contract is locale-independent;
43
- // renderText localizes "all-time" at presentation time only.
44
- windowDescription: sinceMs > 0 ? formatDuration(sinceMs) : "all-time",
45
- rowCount: filtered.length,
46
- totals,
47
- perEntryConsumed,
48
- rangeStart: filtered[0]?.timestamp ?? null,
49
- rangeEnd: filtered[filtered.length - 1]?.timestamp ?? null
50
- };
51
- }
52
- function formatDuration(ms) {
53
- if (ms >= 864e5) return `${Math.round(ms / 864e5)}d`;
54
- if (ms >= 36e5) return `${Math.round(ms / 36e5)}h`;
55
- if (ms >= 6e4) return `${Math.round(ms / 6e4)}m`;
56
- return `${Math.round(ms / 1e3)}s`;
57
- }
58
- function renderText(agg, t) {
59
- const lines = [];
60
- const windowDisplay = agg.windowDescription === "all-time" ? t("cli.metrics.window-all-time") : agg.windowDescription;
61
- lines.push(t("cli.metrics.window", { window: windowDisplay }));
62
- if (agg.rangeStart && agg.rangeEnd) {
63
- lines.push(
64
- t("cli.metrics.rows-range", {
65
- count: String(agg.rowCount),
66
- start: agg.rangeStart,
67
- end: agg.rangeEnd
68
- })
69
- );
70
- } else {
71
- lines.push(t("cli.metrics.rows", { count: String(agg.rowCount) }));
72
- }
73
- lines.push("");
74
- if (Object.keys(agg.totals).length === 0) {
75
- lines.push(t("cli.metrics.no-activity"));
76
- return lines.join("\n");
77
- }
78
- lines.push(" counter total");
79
- lines.push(" ------------------------------------ ----------");
80
- const sorted = Object.entries(agg.totals).sort((a, b) => b[1] - a[1]);
81
- for (const [name, count] of sorted) {
82
- lines.push(` ${name.padEnd(36)} ${String(count).padStart(10)}`);
83
- }
84
- const perEntrySorted = Object.entries(agg.perEntryConsumed).sort((a, b) => b[1] - a[1]).slice(0, 10);
85
- if (perEntrySorted.length > 0) {
86
- lines.push("");
87
- lines.push(" Top per-entry consumed (knowledge_consumed:<id>)");
88
- lines.push(" ------------------------------------ ----------");
89
- for (const [id, count] of perEntrySorted) {
90
- lines.push(` ${id.padEnd(36)} ${String(count).padStart(10)}`);
91
- }
92
- }
93
- return lines.join("\n");
94
- }
95
- var metricsCommand = defineCommand({
96
- meta: {
97
- name: "metrics",
98
- description: "Print a text dashboard of Fabric counter activity from .fabric/metrics.jsonl",
99
- hidden: true
100
- },
101
- args: {
102
- json: {
103
- type: "boolean",
104
- description: "Emit machine-readable JSON instead of the text table.",
105
- default: false
106
- },
107
- target: {
108
- type: "string",
109
- description: "Project root (defaults to the current working directory)."
110
- },
111
- since: {
112
- type: "string",
113
- description: "Limit to rows within a recent window. Examples: 24h, 7d, 30m, 90s. Omit for all-time."
114
- }
115
- },
116
- async run({ args }) {
117
- const projectRoot = resolve(args.target ?? process.cwd());
118
- const t = getProjectTranslator(projectRoot);
119
- const sinceMs = parseSinceArg(args.since, t);
120
- const rows = await readMetrics(projectRoot);
121
- const aggregated = aggregate(rows, sinceMs, /* @__PURE__ */ new Date());
122
- if (args.json === true) {
123
- process.stdout.write(`${JSON.stringify(aggregated)}
124
- `);
125
- } else {
126
- process.stdout.write(`${renderText(aggregated, t)}
127
- `);
128
- }
129
- }
130
- });
131
- var metrics_default = metricsCommand;
132
- export {
133
- metrics_default as default,
134
- metricsCommand
135
- };
@@ -1,48 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- scopeExplain
4
- } from "./chunk-EOT63RDH.js";
5
- import {
6
- getProjectTranslator
7
- } from "./chunk-HORSMSZL.js";
8
-
9
- // src/commands/scope-explain.ts
10
- import { defineCommand } from "citty";
11
- import { FabricError } from "@fenglimg/fabric-shared/errors";
12
- var scope_explain_default = defineCommand({
13
- meta: {
14
- name: "scope-explain",
15
- description: "[DEPRECATED] Use 'fabric info scope <path>' instead"
16
- },
17
- args: {
18
- scope: {
19
- type: "positional",
20
- required: true,
21
- description: "Scope coordinate (e.g. team, project:x, personal)"
22
- }
23
- },
24
- run({ args }) {
25
- console.error("\u26A0\uFE0F DEPRECATED: 'fabric scope-explain' is deprecated. Use 'fabric info scope <path>' instead.");
26
- const projectRoot = process.cwd();
27
- let result;
28
- try {
29
- result = scopeExplain(projectRoot, args.scope);
30
- } catch (error) {
31
- if (error instanceof FabricError) {
32
- console.error(`${error.message}
33
- \u2192 ${error.actionHint}`);
34
- process.exitCode = 1;
35
- return;
36
- }
37
- throw error;
38
- }
39
- if (result === null) {
40
- console.log(getProjectTranslator(projectRoot)("cli.cmd.no-global-config"));
41
- return;
42
- }
43
- console.log(JSON.stringify(result, null, 2));
44
- }
45
- });
46
- export {
47
- scope_explain_default as default
48
- };
@@ -1,37 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- projectStatus,
4
- warnUnknownFlags
5
- } from "./chunk-27HK6H5Y.js";
6
- import "./chunk-QPAW6IYT.js";
7
- import "./chunk-QFIVFZRH.js";
8
- import "./chunk-FNHDQTPC.js";
9
-
10
- // src/commands/status.ts
11
- import { defineCommand } from "citty";
12
- var status_default = defineCommand({
13
- meta: { name: "status", description: "[DEPRECATED] Use 'fabric info' instead" },
14
- args: {
15
- // F27: `--json` machine-readable output (was silently ignored pre-F27).
16
- json: { type: "boolean", description: "Emit machine-readable JSON instead of text" }
17
- },
18
- run({ args }) {
19
- warnUnknownFlags(["json"]);
20
- console.error("\u26A0\uFE0F DEPRECATED: 'fabric status' is deprecated. Use 'fabric info' instead.");
21
- const status = projectStatus(process.cwd());
22
- if (args.json === true) {
23
- console.log(JSON.stringify(status, null, 2));
24
- return;
25
- }
26
- console.log(`uid: ${status.uid ?? "(no global config)"}`);
27
- const projectIdLabel = status.project_id ?? (status.is_fabric_project ? "(unset)" : "(not a Fabric project)");
28
- console.log(`project_id: ${projectIdLabel}`);
29
- console.log(`mounted stores: ${status.mounted.length > 0 ? status.mounted.join(", ") : "(none)"}`);
30
- console.log(`required: ${status.required.length > 0 ? status.required.join(", ") : "(none)"}`);
31
- console.log(`default write: ${status.default_write_store ?? status.active_write_store ?? "(none \u2014 personal scope only)"}`);
32
- console.log(`write routes: ${status.write_routes.length}`);
33
- }
34
- });
35
- export {
36
- status_default as default
37
- };
@@ -1,49 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- warnUnknownFlags,
4
- whoami
5
- } from "./chunk-27HK6H5Y.js";
6
- import "./chunk-QPAW6IYT.js";
7
- import "./chunk-QFIVFZRH.js";
8
- import "./chunk-FNHDQTPC.js";
9
- import {
10
- getProjectTranslator
11
- } from "./chunk-HORSMSZL.js";
12
-
13
- // src/commands/whoami.ts
14
- import { defineCommand } from "citty";
15
- var whoami_default = defineCommand({
16
- meta: { name: "whoami", description: "[DEPRECATED] Use 'fabric info --global' instead" },
17
- args: {
18
- // F27: `--json` machine-readable output (was silently ignored — the command
19
- // declared no args, so citty swallowed the flag and still printed text).
20
- json: { type: "boolean", description: "Emit machine-readable JSON instead of text" }
21
- },
22
- run({ args }) {
23
- warnUnknownFlags(["json"]);
24
- console.error("\u26A0\uFE0F DEPRECATED: 'fabric whoami' is deprecated. Use 'fabric info --global' instead.");
25
- const info = whoami();
26
- if (args.json === true) {
27
- console.log(JSON.stringify(info, null, 2));
28
- return;
29
- }
30
- const t = getProjectTranslator();
31
- if (info === null) {
32
- console.log(t("cli.cmd.no-global-config"));
33
- return;
34
- }
35
- console.log(t("cli.whoami.uid", { uid: info.uid }));
36
- if (info.stores.length === 0) {
37
- console.log(t("cli.whoami.stores-none"));
38
- return;
39
- }
40
- console.log(t("cli.whoami.stores-label"));
41
- const localOnly = t("cli.shared.local-only");
42
- for (const store of info.stores) {
43
- console.log(` ${store.alias} ${store.store_uuid}${store.local_only ? ` ${localOnly}` : ""}`);
44
- }
45
- }
46
- });
47
- export {
48
- whoami_default as default
49
- };
@@ -1,100 +0,0 @@
1
- ---
2
- name: fabric
3
- description: Fabric 入口层路由 — 参考 maestro 的顺序协调方式,把用户意图分派到 fabric-archive/review/import/store/sync/audit/connect。Triggers fabric/知识库/归档/审批/store/同步/关联/审计.
4
- ---
5
-
6
- # fabric — Fabric Skill Router
7
-
8
- 这是 Fabric 相关 skills 的入口层。它只负责理解用户意图、选择正确的下游 skill、按顺序直接调用;不直接读写 `~/.fabric` store,不自行解析 store 树,也不替代底层 `fabric-*` skills 的安全门。
9
-
10
- ## Routing Contract
11
-
12
- 1. 先判断用户要做的是哪类 Fabric 工作。
13
- 2. 只调用一个最合适的下游 skill;只有用户明确要求一组维护动作时,才按顺序调用多个。
14
- 3. 每一步完成后读取结果,再决定是否继续下一步。不要并发委派,也不要用 CSV/wave worker。
15
- 4. 如果目标涉及写入、审批、退役或关联,必须走对应下游 skill 的既有写路径;本入口 skill 不直接修改 `knowledge/`。
16
- 5. Store 状态只通过 `fabric info`、`fabric store ...`、`fabric sync`、MCP 工具或下游 skill 获取。MUST NOT 直接遍历或执行 `~/.fabric/stores/` 内容;store 是 data-only。
17
-
18
- ## Intent Map
19
-
20
- <!-- fabric:router-intent:begin -->
21
- <!-- 本块由 `fabric install` 从 7 个 leaf skill 的 description Triggers 子句生成。严禁手编;改 leaf description 后重跑 `fabric install`。 -->
22
-
23
- | 用户意图(leaf description Triggers) | 下游 skill |
24
- | --- | --- |
25
- | 以后/always/never/下次/记一下;wrong-turn-revert;decision-confirm;dismissal-reason;/fabric-archive | `fabric-archive` |
26
- | 审批/驳回/复审/重审/approve/reject/review pending | `fabric-review` |
27
- | 导入历史/bootstrap fabric/mine changelog/挖掘 commit | `fabric-import` |
28
- | 同步知识库/sync stores/fabric-sync/解决 store 冲突/rebase 冲突 | `fabric-sync` |
29
- | 创建 store/挂载 store/绑定知识库/store 列表/切换写库/set up knowledge store | `fabric-store` |
30
- | 审计知识库/清理陈旧知识/知识库体检/deprecate 条目/prune stale knowledge/知识库瘦身/淘汰旧决策 | `fabric-audit` |
31
- | 连接知识/找关联条目/建知识图谱/link related entries/补 related 边/知识库连通性 | `fabric-connect` |
32
-
33
- `S_CLASSIFY` 的 `task_type` 枚举:`archive | review | import | sync | store | audit | connect`
34
- <!-- fabric:router-intent:end -->
35
-
36
- ## State Machine
37
-
38
- ### S_CLASSIFY
39
-
40
- 提取:
41
-
42
- ```json
43
- {
44
- "task_type": "<Intent Map task_type 枚举之一>",
45
- "scope": "project|store|entry|paths|null",
46
- "write_intent": true,
47
- "confidence": "high|medium|low"
48
- }
49
- ```
50
-
51
- 低置信度时问 1 个短问题;不要一次性列长菜单。若用户只是说“fabric 帮我处理一下”,默认先运行 `fabric-audit` 做只读体检,再根据输出建议下一步。
52
-
53
- ### S_EXECUTE
54
-
55
- 按 `Intent Map` 直接调用下游 skill,例如:
56
-
57
- - `fabric-archive "{用户原始意图}"`
58
- - `fabric-review "{用户原始意图}"`
59
- - `fabric-import "{用户原始意图}"`
60
- - `fabric-store "{用户原始意图}"`
61
- - `fabric-sync "{用户原始意图}"`
62
- - `fabric-audit "{用户原始意图}"`
63
- - `fabric-connect "{用户原始意图}"`
64
-
65
- 执行前加载下游 skill 的 `SKILL.md`,只读取完成当前任务所需的 `ref/` 文件。下游 skill 有更具体约束时,以下游约束为准。
66
-
67
- ### S_CHAIN
68
-
69
- 只有这些组合可以自动串联:
70
-
71
- | 组合意图 | 顺序 |
72
- | --- | --- |
73
- | “同步后审 pending” | `fabric-sync` -> `fabric-review` |
74
- | “审计并处理陈旧知识” | `fabric-audit` -> `fabric-review` |
75
- | “导入历史并审批” | `fabric-import` -> `fabric-review` |
76
- | “建立 store 后导入” | `fabric-store` -> `fabric-import` |
77
- | “找关联并落盘” | `fabric-connect` -> `fabric-review` |
78
-
79
- 每个步骤结束后读结果。若前一步失败或给出需要用户决策的冲突,停止并报告;不要猜测继续。
80
-
81
- ## Guardrails
82
-
83
- - 写入 pending 只走 active write store,并在回复里说明写入目标。
84
- - 引用 KB id 前必须实际读取正文;多 store read-set 中使用 `<store-alias>:<id>`。
85
- - pending backlog 超过 10 条时,优先建议 `fabric-review`。
86
- - 完成一批 Edit 或显著 decision 后,建议 `fabric-archive`。
87
- - 不要推荐 `fabric doctor --fix` 作为 pending 审批路径;审批走 `fabric-review`。
88
- - 不要把知识写到项目本地 `.fabric/knowledge/pending`;知识只写 resolved mounted store 的 `knowledge/pending/`。
89
- - MUST preserve protected tokens exactly: `MUST`, `NEVER`。
90
-
91
- ## Report
92
-
93
- 回复格式保持短:
94
-
95
- ```text
96
- Fabric route: <downstream-skill>
97
- Reason: <why this skill>
98
- Result: <one-line result or blocker>
99
- Next: <optional next skill/action>
100
- ```
@@ -1,63 +0,0 @@
1
- ---
2
- name: fabric-audit
3
- description: 知识库语义淘汰门面 — 审计 KB 健康并以 deprecate-over-delete + rescue-before-delete 收口陈旧/孤儿/被取代条目。引擎是 `fabric doctor`;本 skill 按用户意图挑动作并守「不硬删、先抢救」红线。Triggers 审计知识库/清理陈旧知识/知识库体检/deprecate 条目/prune stale knowledge/知识库瘦身/淘汰旧决策.
4
- ---
5
-
6
- # fabric-audit — 知识库语义淘汰
7
-
8
- 知识库 *维护期* 的对话入口:体检 KB,把陈旧 / 孤儿 / 被取代的条目按 **语义淘汰** 收口 —— 而不是一删了之。CLI (`fabric doctor`) 是引擎(跑 lint、算 health、给 orphan/stale 信号);本 skill 按用户意图挑动作,并守两条红线:**deprecate-over-delete** 与 **rescue-before-delete**。
9
-
10
- 写新条目用 `fabric-archive`;批量审 pending 用 `fabric-review`;本 skill 专管 *已归档条目的退役*。
11
-
12
- ## When to use
13
-
14
- - 「审计 / 体检知识库」「知识库健康度怎样?」
15
- - 「清理陈旧知识」「这些旧决策还要吗?」「知识库瘦身」
16
- - 发布 / 大重构前想把过时知识收口。
17
- - doctor 报了 orphan / stale / 低 health,想逐条处置。
18
-
19
- ## When NOT to use
20
-
21
- - 写 / 提议新知识条目 → `fabric-archive`。
22
- - 批量审 pending draft → `fabric-review`(内部走 `fab_review action="list"` / `pending_path`)。
23
- - store 运维 / 同步 → `fabric-store` / `fabric-sync`。
24
-
25
- ## 两条红线
26
-
27
- 1. **deprecate-over-delete**:陈旧 ≠ 该删。一条「当时为什么这么决策」的 decision/pitfall 即使方案已换,其 **rationale 仍是知识**。退役 = 降 maturity / 标记 deprecated(保留正文 + 记录被什么取代),而非 `rm`。删除只用于「从未成立 / 纯噪声 / 重复」的条目。
28
- 2. **rescue-before-delete**:任何 *打算删* 的条目,删前必做抢救检查 —— 它是否携带别处没有的独特 rationale / 反例 / 边界?有则先 **merge 进取代它的条目**(或在新条目加 `related` 边指回),再删空壳。抢救检查没做过,不许删。
29
-
30
- ## 意图 → 动作映射
31
-
32
- | 意图 | 动作 |
33
- |---|---|
34
- | 体检 / 健康度 | `fabric doctor`(读 lint + health rollup);零阻断,只报告 |
35
- | 找孤儿 / 陈旧条目 | `fabric doctor`(消费 orphan / stale / orphan-demote 信号) |
36
- | 退役一条陈旧条目 | **不删** → 降 maturity(proven→verified→draft)或在 frontmatter 标 deprecated + 记 superseded-by;经 `fabric-review` 落盘 |
37
- | 删一条「从未成立 / 重复」条目 | 先跑 rescue 检查(独特 rationale?有则 merge/加 related);确认空壳后才删 |
38
- | 被取代但有价值 | rescue:把独特 rationale merge 进取代条目,新条目加 `related` 边指回,再退役旧条目 |
39
-
40
- ## 流程(逐条处置)
41
-
42
- 1. `fabric doctor` 取 KB health + orphan/stale 候选清单(引擎给信号,本 skill 不自算)。
43
- 2. 对每个候选判 **三态**:still-valid(留) / superseded(退役,走 deprecate) / never-valid(删,走 rescue 检查)。
44
- 3. superseded → deprecate:降 maturity 或标 deprecated + `superseded-by`,保留正文 rationale。
45
- 4. never-valid → rescue-before-delete:独特知识?有则 merge + `related`,无则删空壳。
46
- 5. 处置经 `fabric-review` skill 落盘(本 skill 给决策,review 做写入),保持单一写路径。
47
-
48
- ## Scope re-assignment(迁移 / backfill 后纠偏)
49
-
50
- `fabric store backfill-scope` 给老条目补 `semantic_scope`,**默认把所有 team-layer 条目标成 `semantic_scope: team`** —— over-broad 的保守默认,会让项目专属知识错误地暴露给所有项目。审计时按下面的测试纠偏:
51
-
52
- - **team-scope 判定测试**:「换一个**没有本 app 代码**的不同 repo,这条知识还成立吗?」—— 成立才是 `team`。
53
- - app **内部**跨功能 / 跨玩法复用的共享组件(同一 app 多处用)**≠ team** —— 它仍绑这个项目,应是 `project:<id>`。**跨玩法复用 ≠ 跨项目复用**(如语音房 VoiceRoom 被多个玩法共用,仍是 `project:<id>`)。
54
- - **纠偏动作**:把被默认成 team 的项目专属条目降级 ——
55
- `fabric store re-scope <store> --to project:<id> --id <id>`
56
- - 完整判定树 / worked examples 见单一真源:`fabric-archive/ref/phase-3-7-semantic-scope.md`(本 skill 不重述,避免镜像漂移)。
57
-
58
- ## Constraints
59
-
60
- - 本 skill **只读 + 给处置建议**;实际写入(降级 / 标记 / 删)经 `fabric-review` 的写路径,不自行改 store `knowledge/`。
61
- - NEVER 绕过 rescue 检查直接删;删前 MUST 先跑抢救检查。删是最后手段,默认是 deprecate。
62
- - store counters 派生态严禁手改;退役动作改的是 store `knowledge/<type>/` 下 markdown 的 frontmatter(maturity / deprecated / superseded-by),再 `fabric doctor --fix` reconcile。
63
- - health / orphan / stale 一律取自 `fabric doctor` 的 JSON 输出,不在 skill 内重算(单一真源)。
@@ -1,48 +0,0 @@
1
- ---
2
- name: fabric-connect
3
- description: 知识图谱关联门面 — 发现 KB 条目间隐藏关联并回写 H2 `related` 图边。读 fab_recall 看候选, 按语义/共路径/共引提议 related 边, 经 fabric-review 写路径落盘。Triggers 连接知识/找关联条目/建知识图谱/link related entries/补 related 边/知识库连通性.
4
- ---
5
-
6
- # fabric-connect — 知识图谱关联
7
-
8
- 把孤立的 KB 条目连成图:发现彼此**隐藏关联**(同一决策的正反面、pitfall↔规避它的 guideline、被取代↔取代),回写到 frontmatter 的 `related: [<stable_id>...]` 图边(v2.2 H2)。下游 `fab_recall include_related:true` 据此一跳拉回连通知识。
9
-
10
- `related` 是**有向引用**(A.related=[B] 表示「读 A 时也该看 B」),按需补反向边(B.related=[A])。
11
-
12
- ## When to use
13
-
14
- - 「把这些知识连起来」「找出相关条目」「补 related 边」
15
- - 「知识库连通性怎样?」「有哪些孤岛条目?」
16
- - 新增一批条目后想建立彼此引用。
17
-
18
- ## When NOT to use
19
-
20
- - 写新条目 → `fabric-archive`。
21
- - 审 pending / 退役陈旧 → `fabric-review` / `fabric-audit`。
22
- - 检索时临时拉关联 → 直接 `fab_recall include_related:true`(无需建边)。
23
-
24
- ## 关联类型(提议 related 边的判据)
25
-
26
- | 类型 | 例 |
27
- |---|---|
28
- | 互补 | decision「用 JWT」 ↔ pitfall「JWT 过期未刷新踩坑」 |
29
- | 规避 | pitfall「sprite 黑边」 ↔ guideline「premultiplyAlpha 正确设置」 |
30
- | 取代 | 旧 decision ↔ 取代它的新 decision(配合 deprecated/superseded-by) |
31
- | 同域 | 同一子系统 / 共 relevance_paths 的条目 |
32
- | 引用链 | A 的 rationale 依赖 B 的结论 |
33
-
34
- ## 流程
35
-
36
- 1. `fab_recall(paths=[...])` 拿候选 + 现有 `related`(读 description.related 看已连状态)。
37
- 2. 对候选两两/成簇判隐藏关联(用上表判据);只提议**高置信**边,不为「话题相邻」乱连(噪声边稀释图价值)。
38
- 3. 每条提议 = `(源 id, 目标 id, 类型, 一句理由)`;按需提议反向边。
39
- 4. 落盘经 `fabric-review` 写路径:在源条目 frontmatter 的 `related` inline 数组追加目标 stable_id;`fabric doctor --fix` reconcile 进 agents.meta。
40
- 5. 回报新增/反向边数 + 连通性变化(孤岛减少)。
41
-
42
- ## Constraints
43
-
44
- - 本 skill **只提议 + 经 review 写路径落盘**;不自行改 store `knowledge/`,不手改 store counters(派生态)。
45
- - `related` MUST 只填**真实存在的 stable_id**(先 `fab_recall` 验证目标在库);NEVER 编造 / 指向 pending。
46
- - **稀疏优于稠密**:宁缺毋滥。只连高置信关联;低置信「相邻」不连(图的信噪比比覆盖率重要)。
47
- - 反向边按需补,不强制双向(有向语义:A 该带出 B ≠ B 该带出 A)。
48
- - 写 `related` 复用 H2 字段(`fabric-review` 的 modify 路径);schema 已支持,无需迁移。