@fenglimg/fabric-cli 2.0.0-rc.36 → 2.0.0-rc.38
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/LICENSE +21 -0
- package/dist/{chunk-XVS4F3P6.js → chunk-D25XJ4BC.js} +49 -5
- package/dist/{chunk-G2CIOLD4.js → chunk-WWNXR34K.js} +1 -16
- package/dist/{doctor-2FCRAWDZ.js → doctor-EJDSEJSS.js} +119 -16
- package/dist/index.js +8 -7
- package/dist/{install-XSUIX6AD.js → install-E6OEB3V2.js} +53 -22
- package/dist/metrics-ACEQFPDU.js +122 -0
- package/dist/{plan-context-hint-UQLRKGBZ.js → plan-context-hint-FC6P3WFE.js} +7 -28
- package/dist/{uninstall-BIJ5GLEU.js → uninstall-MH7ZIB6M.js} +6 -18
- package/package.json +30 -4
- package/templates/hooks/cite-policy-evict.cjs +80 -91
- package/templates/hooks/configs/README.md +19 -0
- package/templates/hooks/configs/codex-hooks.json +3 -0
- package/templates/hooks/configs/cursor-hooks.json +2 -1
- package/templates/hooks/fabric-hint.cjs +146 -8
- package/templates/hooks/knowledge-hint-broad.cjs +65 -104
- package/templates/hooks/knowledge-hint-narrow.cjs +140 -7
- package/templates/hooks/lib/cite-line-parser.cjs +7 -1
- package/templates/hooks/lib/client-adapter.cjs +106 -0
- package/templates/hooks/lib/config-cache.cjs +107 -0
- package/templates/hooks/lib/state-store.cjs +84 -0
- package/templates/skills/fabric-archive/SKILL.md +29 -7
- package/templates/skills/fabric-archive/ref/dry-run-scope.md +1 -1
- package/templates/skills/fabric-archive/ref/i18n-policy.md +6 -0
- package/templates/skills/fabric-archive/ref/phase-1-5-onboard.md +1 -1
- package/templates/skills/fabric-archive/ref/phase-1-cross-session.md +2 -0
- package/templates/skills/fabric-archive/ref/phase-2-5-viability.md +25 -11
- package/templates/skills/fabric-archive/ref/phase-3-5-scope.md +43 -15
- package/templates/skills/fabric-import/SKILL.md +3 -3
- package/templates/skills/fabric-import/ref/i18n-policy.md +6 -0
- package/templates/skills/fabric-import/ref/phase-2-mining.md +2 -2
- package/templates/skills/fabric-review/SKILL.md +31 -25
- package/templates/skills/fabric-review/ref/i18n-policy.md +6 -0
- package/templates/skills/fabric-review/ref/modify-flow.md +9 -1
- package/templates/skills/fabric-review/ref/per-mode-flows.md +1 -1
- package/templates/skills/lib/shared-policy.md +69 -0
- package/dist/serve-43JTEM3U.js +0 -142
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# UX i18n Policy — fabric-review full reference
|
|
2
2
|
|
|
3
|
+
> **Shared core (rc.37 NEW-13):** the cross-skill invariants — protected-token
|
|
4
|
+
> NEVER-translate list, AskUserQuestion routing-key rule, layer heuristic, and
|
|
5
|
+
> events-emit convention — live once in `../../lib/shared-policy.md`. This file
|
|
6
|
+
> keeps only the fabric-review-specific 5-class examples. Read the shared lib
|
|
7
|
+
> for the common rules; do not fork them here.
|
|
8
|
+
|
|
3
9
|
> **Loaded on demand.** Only consult when you need to disambiguate which of the 5 classes a given string belongs to. SKILL.md gives the operative rule.
|
|
4
10
|
|
|
5
11
|
## UX i18n Policy (5-class bilingualization)
|
|
@@ -2,7 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## Modify Sub-Flow
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The modify family is the only action group that mutates frontmatter or stable_id. It accepts `changes` of shape `{title?, summary?, layer?, maturity?, tags?, relevance_scope?, relevance_paths?}`.
|
|
6
|
+
|
|
7
|
+
**v2.0.0-rc.37 NEW-12 — explicit split.** Prefer the dedicated action over the legacy combined `modify`:
|
|
8
|
+
|
|
9
|
+
- `action="modify-content"` — scalar edits (title/summary/tags/maturity/relevance_*); stable_id PRESERVED; the server STRIPS any `changes.layer` so this path can never flip layer. Emits `knowledge_slug_renamed` only when slug derives from title.
|
|
10
|
+
- `action="modify-layer"` — the dedicated layer-flip path; `changes.layer` is REQUIRED. The ONLY legal stable_id mutation in the system (see Layer-Flip Rules below).
|
|
11
|
+
- `action="modify"` (legacy alias) — still accepted; routes to content-edit OR layer-flip by whether `changes.layer` is present. New call sites should use the explicit pair.
|
|
12
|
+
|
|
13
|
+
Server semantics (identical regardless of which action selected the path):
|
|
6
14
|
|
|
7
15
|
- **title / summary / tags / maturity changes** → in-place rewrite; stable_id PRESERVED; emits `knowledge_slug_renamed` only when slug derives from title.
|
|
8
16
|
- **layer change** → the ONLY legal stable_id mutation in the system.
|
|
@@ -152,4 +152,4 @@ Full bilingual rendering blocks + step-by-step procedures for the four modes ref
|
|
|
152
152
|
|
|
153
153
|
### Anti-Pattern (Hard Rule restatement)
|
|
154
154
|
|
|
155
|
-
NEVER emit an `AskUserQuestion` whose options include {pending, topic, health, revisit}. The user does not pick the mode. If inference is genuinely ambiguous after
|
|
155
|
+
NEVER emit an `AskUserQuestion` whose options include {pending, maintain} (or the legacy {topic, health, revisit} aliases). The user does not pick the mode. If inference is genuinely ambiguous after both steps, default to `pending` and proceed; the user can always cancel and redirect. (rc.37 NEW-12 collapsed the 4 legacy modes to 2: `pending` + `maintain`.)
|
|
@@ -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`.
|
package/dist/serve-43JTEM3U.js
DELETED
|
@@ -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
|
-
};
|