@fenglimg/fabric-cli 2.0.0-rc.36 → 2.0.0-rc.37

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 (36) hide show
  1. package/LICENSE +21 -0
  2. package/dist/{chunk-XVS4F3P6.js → chunk-D25XJ4BC.js} +49 -5
  3. package/dist/{chunk-G2CIOLD4.js → chunk-WWNXR34K.js} +1 -16
  4. package/dist/{doctor-2FCRAWDZ.js → doctor-764NFF3X.js} +112 -16
  5. package/dist/index.js +7 -6
  6. package/dist/{install-XSUIX6AD.js → install-U7MGIJ2L.js} +50 -22
  7. package/dist/metrics-ACEQFPDU.js +122 -0
  8. package/dist/{uninstall-BIJ5GLEU.js → uninstall-MH7ZIB6M.js} +6 -18
  9. package/package.json +30 -4
  10. package/templates/hooks/cite-policy-evict.cjs +80 -91
  11. package/templates/hooks/configs/README.md +19 -0
  12. package/templates/hooks/configs/codex-hooks.json +3 -0
  13. package/templates/hooks/configs/cursor-hooks.json +2 -1
  14. package/templates/hooks/fabric-hint.cjs +146 -8
  15. package/templates/hooks/knowledge-hint-broad.cjs +65 -104
  16. package/templates/hooks/knowledge-hint-narrow.cjs +122 -5
  17. package/templates/hooks/lib/cite-line-parser.cjs +7 -1
  18. package/templates/hooks/lib/client-adapter.cjs +106 -0
  19. package/templates/hooks/lib/config-cache.cjs +107 -0
  20. package/templates/hooks/lib/state-store.cjs +84 -0
  21. package/templates/skills/fabric-archive/SKILL.md +29 -7
  22. package/templates/skills/fabric-archive/ref/dry-run-scope.md +1 -1
  23. package/templates/skills/fabric-archive/ref/i18n-policy.md +6 -0
  24. package/templates/skills/fabric-archive/ref/phase-1-5-onboard.md +1 -1
  25. package/templates/skills/fabric-archive/ref/phase-1-cross-session.md +2 -0
  26. package/templates/skills/fabric-archive/ref/phase-2-5-viability.md +25 -11
  27. package/templates/skills/fabric-archive/ref/phase-3-5-scope.md +43 -15
  28. package/templates/skills/fabric-import/SKILL.md +3 -3
  29. package/templates/skills/fabric-import/ref/i18n-policy.md +6 -0
  30. package/templates/skills/fabric-import/ref/phase-2-mining.md +2 -2
  31. package/templates/skills/fabric-review/SKILL.md +31 -25
  32. package/templates/skills/fabric-review/ref/i18n-policy.md +6 -0
  33. package/templates/skills/fabric-review/ref/modify-flow.md +9 -1
  34. package/templates/skills/fabric-review/ref/per-mode-flows.md +1 -1
  35. package/templates/skills/lib/shared-policy.md +69 -0
  36. package/dist/serve-43JTEM3U.js +0 -142
@@ -0,0 +1,69 @@
1
+ # Shared skill policy — cross-skill canonical core (rc.37 NEW-13)
2
+
3
+ > **Single source of truth** for the policy invariants that fabric-archive,
4
+ > fabric-review, and fabric-import all depend on. Each skill's `ref/` keeps
5
+ > only its skill-specific examples and points here (`../../lib/shared-policy.md`)
6
+ > for the common rules. Edit invariants HERE — never fork them per skill.
7
+
8
+ ## 1. Protected tokens — NEVER translated
9
+
10
+ When rendering bilingual (zh-CN ↔ en) output, prose is translated but the
11
+ following classes of token appear **verbatim in both variants**:
12
+
13
+ - **MCP tool + field names**: `fab_extract_knowledge`, `fab_review`,
14
+ `fab_recall`, `fab_plan_context`, `fab_get_knowledge_sections`,
15
+ `relevance_scope`, `relevance_paths`, `source_sessions`, `proposed_reason`,
16
+ `session_context`, `intent_clues`, `tech_stack`, `impact`, `must_read_if`,
17
+ `evidence_paths`, `tags`, `pending_path`, `layer`.
18
+ - **Enum / routing values**: `narrow`, `broad`, `team`, `personal`, `draft`,
19
+ `verified`, `proven`, `knowledge_scope_degraded`.
20
+ - **Imperatives + paths**: `MUST`, `NEVER`, `.fabric/knowledge/`, file paths.
21
+
22
+ The authoritative machine-checked list is `PROTECTED_TOKENS` in
23
+ `@fenglimg/fabric-shared` (enforced by `scripts/lint-protected-tokens.ts`).
24
+ Bilingualization scope is **prose ONLY**.
25
+
26
+ ## 2. AskUserQuestion routing-key invariant
27
+
28
+ When any skill issues an `AskUserQuestion`:
29
+
30
+ - `header` + `question` → user-facing prose → **translated** per
31
+ `.fabric/fabric-config.json` → `fabric_language`.
32
+ - `options[]` entries → **routing keys** consumed by the skill's `switch`
33
+ over the returned choice → stay **English** in BOTH variants.
34
+
35
+ Canonical option arrays (English in every locale):
36
+
37
+ - Per-item review action: `["approve", "reject", "modify", "defer", "skip"]`
38
+ - Stale-item action (review health mode): `["defer", "demote", "skip"]`
39
+ - Layer-flip target: `["team", "personal"]`
40
+
41
+ A skill that translates `options[]` MUST then dual-string-match
42
+ (`choice === "approve" || choice === "通过"`); avoid this — keep options
43
+ English so the state machine stays single-string.
44
+
45
+ ## 3. Layer heuristic (team vs personal)
46
+
47
+ Default classification when archiving / proposing knowledge:
48
+
49
+ - **强 team** — cross-cutting decisions, architecture, shared pitfalls,
50
+ conventions the whole repo depends on.
51
+ - **强 personal** — individual workflow preferences, local environment quirks,
52
+ notes scoped to one contributor (`KP-*` ids, in-repo `~/.fabric` root).
53
+ - **默认 team** — when ambiguous, default to `team` (shared visibility is the
54
+ safer default; a mis-scoped personal entry hides knowledge from the team).
55
+
56
+ This block is itself a protected token sequence — render `强 team` /
57
+ `强 personal` / `默认 team` verbatim.
58
+
59
+ ## 4. Events emit convention
60
+
61
+ Skills persist lifecycle via MCP tools (which emit the canonical events) —
62
+ they do NOT hand-write `.fabric/events.jsonl`:
63
+
64
+ - `fab_extract_knowledge` → `knowledge_proposed` (+ archive-attempt events).
65
+ - `fab_review` approve → `knowledge_promote_started` → `knowledge_promoted`.
66
+ - `fab_review` modify-layer → `knowledge_layer_changed` (+ id-redirect).
67
+
68
+ Never instruct the user to delete or hand-edit the event ledger; it is the
69
+ append-only audit trail. Counter rollups live in `.fabric/metrics.jsonl`.
@@ -1,142 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- hasActionHint,
4
- paint,
5
- renderFabricError,
6
- symbol
7
- } from "./chunk-G2CIOLD4.js";
8
- import {
9
- t
10
- } from "./chunk-PWLW3B57.js";
11
- import {
12
- createDebugLogger,
13
- resolveDevMode
14
- } from "./chunk-COI5VDFU.js";
15
-
16
- // src/commands/serve.ts
17
- import { defineCommand } from "citty";
18
- import { acquireLock, releaseLock, startHttpServer } from "@fenglimg/fabric-server";
19
- var DEFAULT_PORT = 7373;
20
- var serveCommand = defineCommand({
21
- meta: {
22
- name: "serve",
23
- description: t("cli.serve.description")
24
- },
25
- args: {
26
- port: {
27
- type: "string",
28
- description: t("cli.serve.args.port.description"),
29
- default: String(DEFAULT_PORT)
30
- },
31
- host: {
32
- type: "string",
33
- description: t("cli.serve.args.host.description"),
34
- default: "127.0.0.1"
35
- },
36
- target: {
37
- type: "string",
38
- description: t("cli.serve.args.target.description")
39
- },
40
- debug: {
41
- type: "boolean",
42
- description: t("cli.serve.args.debug.description"),
43
- default: false
44
- },
45
- // v2.0.0-rc.29 TASK-002 (BUG-K1): default-deny strict-auth.
46
- "allow-loopback-no-auth": {
47
- type: "boolean",
48
- description: t("cli.serve.args.allow-loopback-no-auth.description"),
49
- default: false
50
- }
51
- },
52
- async run({ args }) {
53
- const workspaceRoot = process.cwd();
54
- const logger = createDebugLogger(args.debug);
55
- const resolution = resolveDevMode(args.target, workspaceRoot);
56
- const port = parsePort(args.port);
57
- const requestedHost = parseHost(args.host);
58
- const authToken = readAuthTokenFromEnv();
59
- const allowLoopbackNoAuth = args["allow-loopback-no-auth"] === true;
60
- const host = validateHost(requestedHost, authToken, allowLoopbackNoAuth);
61
- const projectRoot = resolution.target;
62
- try {
63
- acquireLock(projectRoot);
64
- } catch (err) {
65
- if (hasActionHint(err)) {
66
- renderFabricError(err);
67
- process.exit(1);
68
- }
69
- throw err;
70
- }
71
- process.on("exit", () => {
72
- releaseLock(projectRoot);
73
- });
74
- logger(`serve target source: ${resolution.source}`);
75
- for (const step of resolution.chain) {
76
- logger(step);
77
- }
78
- try {
79
- await startHttpServer({
80
- port,
81
- projectRoot,
82
- host,
83
- authToken,
84
- allowLoopbackNoAuth
85
- });
86
- } catch (error) {
87
- if (isNodeError(error) && error.code === "EADDRINUSE") {
88
- releaseLock(projectRoot);
89
- throw new Error(t("cli.serve.error.port-in-use", { port: String(port), nextPort: String(port + 1) }));
90
- }
91
- releaseLock(projectRoot);
92
- throw error;
93
- }
94
- console.log(`${symbol.ok} ${paint.ai(t("cli.serve.ready.title"))} ${paint.human(`http://${host}:${port}`)}`);
95
- }
96
- });
97
- var serve_default = serveCommand;
98
- function parsePort(value) {
99
- const port = Number.parseInt(value ?? String(DEFAULT_PORT), 10);
100
- if (!Number.isInteger(port) || port < 1 || port > 65535) {
101
- throw new Error(t("cli.shared.invalid-port", { value: value ?? "<unset>" }));
102
- }
103
- return port;
104
- }
105
- function parseHost(value) {
106
- const host = value?.trim() ?? "127.0.0.1";
107
- if (host.length === 0) {
108
- throw new Error(t("cli.shared.invalid-host-empty"));
109
- }
110
- return host;
111
- }
112
- function readAuthTokenFromEnv() {
113
- const token = process.env.FABRIC_AUTH_TOKEN;
114
- return token === void 0 || token.length === 0 ? void 0 : token;
115
- }
116
- function validateHost(host, authToken, allowLoopbackNoAuth) {
117
- if (authToken !== void 0) {
118
- return host;
119
- }
120
- if (!isLoopbackHost(host)) {
121
- console.error(
122
- `${symbol.warn} ${paint.warn(t("cli.serve.warning.host-fallback", { host }))}`
123
- );
124
- return "127.0.0.1";
125
- }
126
- if (!allowLoopbackNoAuth) {
127
- console.error(
128
- `${symbol.warn} ${paint.warn(t("cli.serve.warning.loopback-deny-default"))}`
129
- );
130
- }
131
- return host;
132
- }
133
- function isLoopbackHost(host) {
134
- return host === "127.0.0.1" || host === "localhost" || host === "::1";
135
- }
136
- function isNodeError(error) {
137
- return error instanceof Error;
138
- }
139
- export {
140
- serve_default as default,
141
- serveCommand
142
- };