@fenglimg/fabric-cli 2.0.0-rc.33 → 2.0.0-rc.35
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 +1 -1
- package/dist/{chunk-SRX7WZUG.js → chunk-BATF4PEJ.js} +2 -2
- package/dist/{chunk-PNRWNUFX.js → chunk-XVS4F3P6.js} +105 -4
- package/dist/{config-5CH4EJQ2.js → config-XJIPZNUP.js} +1 -1
- package/dist/{doctor-E26YO67D.js → doctor-2FCRAWDZ.js} +23 -8
- package/dist/index.js +7 -7
- package/dist/{install-YSFVNY3T.js → install-HOTE5BPA.js} +61 -4
- package/dist/{onboard-coverage-6MN3CYHT.js → onboard-coverage-MFCAEBDO.js} +4 -4
- package/dist/{plan-context-hint-CXTLNVSV.js → plan-context-hint-UQLRKGBZ.js} +2 -2
- package/dist/{uninstall-VLLJG7JT.js → uninstall-BIJ5GLEU.js} +1 -1
- package/package.json +3 -4
- package/templates/hooks/cite-policy-evict.cjs +242 -0
- package/templates/hooks/configs/claude-code.json +11 -0
- package/templates/hooks/fabric-hint.cjs +11 -1
- package/templates/hooks/knowledge-hint-broad.cjs +34 -6
- package/templates/hooks/knowledge-hint-narrow.cjs +106 -1
- package/templates/hooks/lib/summary-fallback.cjs +210 -0
- package/templates/skills/fabric-archive/SKILL.md +38 -255
- package/templates/skills/fabric-archive/ref/dry-run-scope.md +16 -0
- package/templates/skills/fabric-archive/ref/e5-cron-recap.md +1 -1
- package/templates/skills/fabric-archive/ref/i18n-policy.md +1 -1
- package/templates/skills/fabric-archive/ref/phase-1-5-onboard.md +10 -10
- package/templates/skills/fabric-import/ref/i18n-policy.md +1 -1
- package/templates/skills/fabric-review/SKILL.md +55 -413
- package/templates/skills/fabric-review/ref/askuserquestion-policy.md +66 -0
- package/templates/skills/fabric-review/ref/i18n-policy.md +1 -1
- package/templates/skills/fabric-review/ref/modify-flow.md +95 -0
- package/templates/skills/fabric-review/ref/output-contract.md +58 -0
- package/templates/skills/fabric-review/ref/per-mode-flows.md +155 -0
- package/templates/skills/fabric-review/ref/semantic-check.md +26 -0
package/README.md
CHANGED
|
@@ -107,7 +107,7 @@ var dismissSlotCmd = defineCommand({
|
|
|
107
107
|
const next = [...optedOut, slot];
|
|
108
108
|
const merged = { ...config, onboard_slots_opted_out: next };
|
|
109
109
|
await atomicWriteJson(configPath, merged);
|
|
110
|
-
console.log(`Dismissed onboard slot "${slot}". Run \`
|
|
110
|
+
console.log(`Dismissed onboard slot "${slot}". Run \`fabric config onboard-reset ${slot}\` to re-open.`);
|
|
111
111
|
} catch (err) {
|
|
112
112
|
const message = err instanceof Error ? err.message : String(err);
|
|
113
113
|
console.error(`dismiss-slot failed: ${message}`);
|
|
@@ -153,7 +153,7 @@ var onboardResetCmd = defineCommand({
|
|
|
153
153
|
const next = optedOut.filter((s) => s !== slot);
|
|
154
154
|
const merged = { ...config, onboard_slots_opted_out: next };
|
|
155
155
|
await atomicWriteJson(configPath, merged);
|
|
156
|
-
console.log(`Reset onboard slot "${slot}"; it will appear in \`
|
|
156
|
+
console.log(`Reset onboard slot "${slot}"; it will appear in \`fabric onboard-coverage\` as missing again.`);
|
|
157
157
|
} catch (err) {
|
|
158
158
|
const message = err instanceof Error ? err.message : String(err);
|
|
159
159
|
console.error(`onboard-reset failed: ${message}`);
|
|
@@ -57,6 +57,7 @@ var SKILL_IMPORT_TEMPLATE_REL = "skills/fabric-import/SKILL.md";
|
|
|
57
57
|
var HOOK_SCRIPT_TEMPLATE_REL = "hooks/fabric-hint.cjs";
|
|
58
58
|
var HOOK_BROAD_SCRIPT_TEMPLATE_REL = "hooks/knowledge-hint-broad.cjs";
|
|
59
59
|
var HOOK_NARROW_SCRIPT_TEMPLATE_REL = "hooks/knowledge-hint-narrow.cjs";
|
|
60
|
+
var HOOK_CITE_EVICT_SCRIPT_TEMPLATE_REL = "hooks/cite-policy-evict.cjs";
|
|
60
61
|
var HOOK_LIB_TEMPLATE_DIR_REL = "hooks/lib";
|
|
61
62
|
var CLAUDE_HOOK_CONFIG_TEMPLATE_REL = "hooks/configs/claude-code.json";
|
|
62
63
|
var CODEX_HOOK_CONFIG_TEMPLATE_REL = "hooks/configs/codex-hooks.json";
|
|
@@ -75,6 +76,10 @@ var SKILL_DESTINATIONS = {
|
|
|
75
76
|
".codex/skills/fabric-import/SKILL.md"
|
|
76
77
|
]
|
|
77
78
|
};
|
|
79
|
+
var DEPRECATED_SKILL_DIRS = [
|
|
80
|
+
".claude/skills/fabric-init",
|
|
81
|
+
".codex/skills/fabric-init"
|
|
82
|
+
];
|
|
78
83
|
var HOOK_SCRIPT_DESTINATIONS = {
|
|
79
84
|
fabricHint: [
|
|
80
85
|
".claude/hooks/fabric-hint.cjs",
|
|
@@ -90,7 +95,12 @@ var HOOK_SCRIPT_DESTINATIONS = {
|
|
|
90
95
|
".claude/hooks/knowledge-hint-narrow.cjs",
|
|
91
96
|
".codex/hooks/knowledge-hint-narrow.cjs",
|
|
92
97
|
".cursor/hooks/knowledge-hint-narrow.cjs"
|
|
93
|
-
]
|
|
98
|
+
],
|
|
99
|
+
// v2.0.0-rc.34 TASK-06: Claude Code only — UserPromptSubmit cite-policy
|
|
100
|
+
// long-session evict sidecar. Codex / Cursor don't have an equivalent
|
|
101
|
+
// event registration; cite-coverage telemetry there relies on the existing
|
|
102
|
+
// Stop / SessionStart hooks (knowledge-hint-broad rc.33 W2 channel).
|
|
103
|
+
citePolicyEvict: [".claude/hooks/cite-policy-evict.cjs"]
|
|
94
104
|
};
|
|
95
105
|
var HOOK_LIB_DESTINATIONS = [
|
|
96
106
|
".claude/hooks/lib",
|
|
@@ -141,36 +151,109 @@ function readFabricLanguagePreference(projectRoot) {
|
|
|
141
151
|
return "match-existing";
|
|
142
152
|
}
|
|
143
153
|
}
|
|
154
|
+
var SKILL_TOKEN_ERROR_TOKENS = 1e4;
|
|
155
|
+
var STALE_INSTALL_RATIO = 1.5;
|
|
156
|
+
function estimateSkillTokens(text) {
|
|
157
|
+
return Math.ceil(text.length / 3);
|
|
158
|
+
}
|
|
159
|
+
function validateSkillCanonicalSize(source, slug) {
|
|
160
|
+
const tokens = estimateSkillTokens(source);
|
|
161
|
+
if (tokens > SKILL_TOKEN_ERROR_TOKENS) {
|
|
162
|
+
throw new Error(
|
|
163
|
+
`Skill '${slug}' canonical SKILL.md estimates ${tokens} tok (>${SKILL_TOKEN_ERROR_TOKENS} ERROR threshold). Install aborted \u2014 this is a Fabric release bug, not a user-recoverable state. Re-split SKILL.md via progressive disclosure (see fabric-archive/phases/* as canonical example) and rebuild.`
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function inspectStaleInstall(target, source) {
|
|
168
|
+
if (!existsSync2(target)) return null;
|
|
169
|
+
let existing;
|
|
170
|
+
try {
|
|
171
|
+
existing = readFileSync2(target, "utf8");
|
|
172
|
+
} catch {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
const existingTok = estimateSkillTokens(existing);
|
|
176
|
+
const sourceTok = estimateSkillTokens(source);
|
|
177
|
+
if (existingTok > sourceTok * STALE_INSTALL_RATIO) {
|
|
178
|
+
return `stale-replaced (${existingTok} tok \u2192 ${sourceTok} tok canonical)`;
|
|
179
|
+
}
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
144
182
|
async function installFabricArchiveSkill(projectRoot, _options = {}) {
|
|
145
183
|
const source = await readTemplate(SKILL_TEMPLATE_REL);
|
|
184
|
+
validateSkillCanonicalSize(source, "fabric-archive");
|
|
146
185
|
const targets = SKILL_DESTINATIONS.fabricArchive.map((rel) => join2(projectRoot, rel));
|
|
147
186
|
const results = [];
|
|
148
187
|
for (const target of targets) {
|
|
149
|
-
|
|
188
|
+
const staleMsg = inspectStaleInstall(target, source);
|
|
189
|
+
const result = await copyTextIdempotent("skill", source, target);
|
|
190
|
+
if (staleMsg && result.status === "written") {
|
|
191
|
+
result.message = result.message ? `${staleMsg}; ${result.message}` : staleMsg;
|
|
192
|
+
}
|
|
193
|
+
results.push(result);
|
|
150
194
|
}
|
|
151
195
|
results.push(...await installSkillRefFiles(projectRoot, "fabric-archive"));
|
|
152
196
|
return results;
|
|
153
197
|
}
|
|
154
198
|
async function installFabricReviewSkill(projectRoot, _options = {}) {
|
|
155
199
|
const source = await readTemplate(SKILL_REVIEW_TEMPLATE_REL);
|
|
200
|
+
validateSkillCanonicalSize(source, "fabric-review");
|
|
156
201
|
const targets = SKILL_DESTINATIONS.fabricReview.map((rel) => join2(projectRoot, rel));
|
|
157
202
|
const results = [];
|
|
158
203
|
for (const target of targets) {
|
|
159
|
-
|
|
204
|
+
const staleMsg = inspectStaleInstall(target, source);
|
|
205
|
+
const result = await copyTextIdempotent("skill-review", source, target);
|
|
206
|
+
if (staleMsg && result.status === "written") {
|
|
207
|
+
result.message = result.message ? `${staleMsg}; ${result.message}` : staleMsg;
|
|
208
|
+
}
|
|
209
|
+
results.push(result);
|
|
160
210
|
}
|
|
161
211
|
results.push(...await installSkillRefFiles(projectRoot, "fabric-review"));
|
|
162
212
|
return results;
|
|
163
213
|
}
|
|
164
214
|
async function installFabricImportSkill(projectRoot, _options = {}) {
|
|
165
215
|
const source = await readTemplate(SKILL_IMPORT_TEMPLATE_REL);
|
|
216
|
+
validateSkillCanonicalSize(source, "fabric-import");
|
|
166
217
|
const targets = SKILL_DESTINATIONS.fabricImport.map((rel) => join2(projectRoot, rel));
|
|
167
218
|
const results = [];
|
|
168
219
|
for (const target of targets) {
|
|
169
|
-
|
|
220
|
+
const staleMsg = inspectStaleInstall(target, source);
|
|
221
|
+
const result = await copyTextIdempotent("skill-import", source, target);
|
|
222
|
+
if (staleMsg && result.status === "written") {
|
|
223
|
+
result.message = result.message ? `${staleMsg}; ${result.message}` : staleMsg;
|
|
224
|
+
}
|
|
225
|
+
results.push(result);
|
|
170
226
|
}
|
|
171
227
|
results.push(...await installSkillRefFiles(projectRoot, "fabric-import"));
|
|
172
228
|
return results;
|
|
173
229
|
}
|
|
230
|
+
async function cleanupDeprecatedSkills(projectRoot) {
|
|
231
|
+
const results = [];
|
|
232
|
+
for (const rel of DEPRECATED_SKILL_DIRS) {
|
|
233
|
+
const target = join2(projectRoot, rel);
|
|
234
|
+
if (!existsSync2(target)) {
|
|
235
|
+
results.push({ step: "skill-deprecated-cleanup", path: target, status: "skipped", message: "absent" });
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
try {
|
|
239
|
+
await rm(target, { recursive: true, force: true });
|
|
240
|
+
results.push({
|
|
241
|
+
step: "skill-deprecated-cleanup",
|
|
242
|
+
path: target,
|
|
243
|
+
status: "written",
|
|
244
|
+
message: "removed-deprecated"
|
|
245
|
+
});
|
|
246
|
+
} catch (error) {
|
|
247
|
+
results.push({
|
|
248
|
+
step: "skill-deprecated-cleanup",
|
|
249
|
+
path: target,
|
|
250
|
+
status: "error",
|
|
251
|
+
message: error instanceof Error ? error.message : String(error)
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return results;
|
|
256
|
+
}
|
|
174
257
|
async function installSkillRefFiles(projectRoot, skillSlug) {
|
|
175
258
|
let refTemplateDir;
|
|
176
259
|
try {
|
|
@@ -279,6 +362,22 @@ async function installKnowledgeHintNarrowHook(projectRoot, _options = {}) {
|
|
|
279
362
|
}
|
|
280
363
|
return results;
|
|
281
364
|
}
|
|
365
|
+
async function installCitePolicyEvictHook(projectRoot, _options = {}) {
|
|
366
|
+
const source = await readTemplate(HOOK_CITE_EVICT_SCRIPT_TEMPLATE_REL);
|
|
367
|
+
const targets = HOOK_SCRIPT_DESTINATIONS.citePolicyEvict.map((rel) => join2(projectRoot, rel));
|
|
368
|
+
const results = [];
|
|
369
|
+
for (const target of targets) {
|
|
370
|
+
const result = await copyTextIdempotent("hook-cite-evict-script", source, target);
|
|
371
|
+
if (result.status === "written" && process.platform !== "win32") {
|
|
372
|
+
try {
|
|
373
|
+
chmodSync(target, 493);
|
|
374
|
+
} catch {
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
results.push(result);
|
|
378
|
+
}
|
|
379
|
+
return results;
|
|
380
|
+
}
|
|
282
381
|
async function installHookLibs(projectRoot, _options = {}) {
|
|
283
382
|
const libTemplateDir = findTemplatePath(HOOK_LIB_TEMPLATE_DIR_REL);
|
|
284
383
|
let libFiles;
|
|
@@ -722,9 +821,11 @@ export {
|
|
|
722
821
|
installFabricArchiveSkill,
|
|
723
822
|
installFabricReviewSkill,
|
|
724
823
|
installFabricImportSkill,
|
|
824
|
+
cleanupDeprecatedSkills,
|
|
725
825
|
installArchiveHintHook,
|
|
726
826
|
installKnowledgeHintBroadHook,
|
|
727
827
|
installKnowledgeHintNarrowHook,
|
|
828
|
+
installCitePolicyEvictHook,
|
|
728
829
|
installHookLibs,
|
|
729
830
|
mergeClaudeCodeHookConfig,
|
|
730
831
|
mergeCodexHookConfig,
|
|
@@ -72,6 +72,16 @@ var doctorCommand = defineCommand({
|
|
|
72
72
|
description: t("cli.doctor.args.yes.description"),
|
|
73
73
|
default: false
|
|
74
74
|
},
|
|
75
|
+
// rc.35 TASK-12 (P0-11): expose maintainer-audience actionHints. By
|
|
76
|
+
// default the renderer folds remediation strings that target Fabric
|
|
77
|
+
// contributors (edit `packages/cli/templates/...`, interpret G1-G5
|
|
78
|
+
// cite-goodhart codes, etc.) since npm end users have no actionable
|
|
79
|
+
// lever for them. --verbose shows them.
|
|
80
|
+
verbose: {
|
|
81
|
+
type: "boolean",
|
|
82
|
+
description: t("cli.doctor.args.verbose.description"),
|
|
83
|
+
default: false
|
|
84
|
+
},
|
|
75
85
|
// rc.20 TASK-05: cite policy adherence report (read-only). Skips standard
|
|
76
86
|
// inspections entirely — different output surface. Mutually exclusive
|
|
77
87
|
// with --fix / --fix-knowledge (enforced in run()).
|
|
@@ -284,7 +294,7 @@ var doctorCommand = defineCommand({
|
|
|
284
294
|
} else if (fix && args["dry-run"] === true) {
|
|
285
295
|
writeStdout(dt("cli.doctor.fix-dry-run-banner"));
|
|
286
296
|
}
|
|
287
|
-
renderHumanReport(report, dt);
|
|
297
|
+
renderHumanReport(report, dt, args.verbose === true);
|
|
288
298
|
}
|
|
289
299
|
await emitDoctorRunEventBestEffort(resolution.target, {
|
|
290
300
|
mode: fixKnowledge ? "fix-knowledge" : "lint",
|
|
@@ -307,14 +317,15 @@ var doctorCommand = defineCommand({
|
|
|
307
317
|
}
|
|
308
318
|
});
|
|
309
319
|
var doctor_default = doctorCommand;
|
|
310
|
-
function renderHumanReport(report, dt) {
|
|
320
|
+
function renderHumanReport(report, dt, verbose) {
|
|
311
321
|
writeStdout(`${renderStatus(report.status)} ${paint.ai("fabric doctor")} ${paint.human(report.summary.target)}`);
|
|
312
322
|
for (const check of report.checks) {
|
|
313
323
|
writeStdout(`${renderStatus(check.status)} ${check.name}: ${check.message}`);
|
|
314
324
|
}
|
|
315
|
-
|
|
316
|
-
writeIssueSection(dt("doctor.section.
|
|
317
|
-
writeIssueSection(dt("doctor.section.
|
|
325
|
+
const opts = { verbose, dt };
|
|
326
|
+
writeIssueSection(dt("doctor.section.fixable"), report.fixable_errors, opts);
|
|
327
|
+
writeIssueSection(dt("doctor.section.manual"), report.manual_errors, opts);
|
|
328
|
+
writeIssueSection(dt("doctor.section.warnings"), report.warnings, opts);
|
|
318
329
|
renderPayloadLimits(report, dt);
|
|
319
330
|
}
|
|
320
331
|
function renderPayloadLimits(report, dt) {
|
|
@@ -344,7 +355,7 @@ function renderFixKnowledgeMutations(fixKnowledgeReport, dt) {
|
|
|
344
355
|
writeStdout(`${marker} ${mutation.kind}: ${mutation.path} [${mutation.detail}]${errSuffix}`);
|
|
345
356
|
}
|
|
346
357
|
}
|
|
347
|
-
function writeIssueSection(title, issues) {
|
|
358
|
+
function writeIssueSection(title, issues, options) {
|
|
348
359
|
if (issues.length === 0) {
|
|
349
360
|
return;
|
|
350
361
|
}
|
|
@@ -353,7 +364,11 @@ function writeIssueSection(title, issues) {
|
|
|
353
364
|
for (const issue of issues) {
|
|
354
365
|
writeStdout(`- ${issue.code}: ${issue.message}`);
|
|
355
366
|
if (issue.actionHint !== void 0 && issue.actionHint.length > 0) {
|
|
356
|
-
|
|
367
|
+
if (issue.audience === "maintainer" && !options.verbose) {
|
|
368
|
+
writeStdout(` \u2192 ${options.dt("doctor.maintainer-hint-folded")}`);
|
|
369
|
+
} else {
|
|
370
|
+
writeStdout(` \u2192 ${issue.actionHint}`);
|
|
371
|
+
}
|
|
357
372
|
}
|
|
358
373
|
}
|
|
359
374
|
}
|
|
@@ -600,7 +615,7 @@ function appendContractSection(lines, report, dt) {
|
|
|
600
615
|
}
|
|
601
616
|
}
|
|
602
617
|
function renderEnrichDescriptionsReport(report, dt) {
|
|
603
|
-
const header = `${symbol.ok} ${paint.ai("
|
|
618
|
+
const header = `${symbol.ok} ${paint.ai("fabric doctor --enrich-descriptions")} mode=${report.mode}${report.dryRun ? " (dry-run)" : ""} scanned=${report.scanned} modified=${report.modified} skipped=${report.skipped}`;
|
|
604
619
|
writeStdout(header);
|
|
605
620
|
if (report.candidates.length === 0) {
|
|
606
621
|
writeStdout(dt("doctor.enrich.allComplete"));
|
package/dist/index.js
CHANGED
|
@@ -11,22 +11,22 @@ import { defineCommand, runMain } from "citty";
|
|
|
11
11
|
|
|
12
12
|
// src/commands/index.ts
|
|
13
13
|
var allCommands = {
|
|
14
|
-
install: () => import("./install-
|
|
15
|
-
doctor: () => import("./doctor-
|
|
14
|
+
install: () => import("./install-HOTE5BPA.js").then((module) => module.default),
|
|
15
|
+
doctor: () => import("./doctor-2FCRAWDZ.js").then((module) => module.default),
|
|
16
16
|
serve: () => import("./serve-43JTEM3U.js").then((module) => module.default),
|
|
17
|
-
uninstall: () => import("./uninstall-
|
|
18
|
-
config: () => import("./config-
|
|
19
|
-
"plan-context-hint": () => import("./plan-context-hint-
|
|
17
|
+
uninstall: () => import("./uninstall-BIJ5GLEU.js").then((module) => module.default),
|
|
18
|
+
config: () => import("./config-XJIPZNUP.js").then((module) => module.default),
|
|
19
|
+
"plan-context-hint": () => import("./plan-context-hint-UQLRKGBZ.js").then((module) => module.default),
|
|
20
20
|
// v2.0.0-rc.23 TASK-014 (F8c): S5 onboard-slot coverage. Used by the
|
|
21
21
|
// fabric-archive Skill's first-run phase to detect unclaimed slots.
|
|
22
|
-
"onboard-coverage": () => import("./onboard-coverage-
|
|
22
|
+
"onboard-coverage": () => import("./onboard-coverage-MFCAEBDO.js").then((module) => module.default)
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
// src/index.ts
|
|
26
26
|
var main = defineCommand({
|
|
27
27
|
meta: {
|
|
28
28
|
name: "fabric",
|
|
29
|
-
version: "2.0.0-rc.
|
|
29
|
+
version: "2.0.0-rc.35",
|
|
30
30
|
description: t("cli.main.description")
|
|
31
31
|
},
|
|
32
32
|
subCommands: allCommands
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
installMcpClients
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-BATF4PEJ.js";
|
|
5
5
|
import {
|
|
6
|
+
cleanupDeprecatedSkills,
|
|
6
7
|
installArchiveHintHook,
|
|
8
|
+
installCitePolicyEvictHook,
|
|
7
9
|
installFabricArchiveSkill,
|
|
8
10
|
installFabricImportSkill,
|
|
9
11
|
installFabricReviewSkill,
|
|
@@ -18,7 +20,7 @@ import {
|
|
|
18
20
|
writeCodexBootstrapManagedBlock,
|
|
19
21
|
writeCursorBootstrapManagedBlock,
|
|
20
22
|
writeFabricAgentsSnapshot
|
|
21
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-XVS4F3P6.js";
|
|
22
24
|
import {
|
|
23
25
|
detectClientSupports
|
|
24
26
|
} from "./chunk-MF3OTILQ.js";
|
|
@@ -62,6 +64,7 @@ async function installHooks(target, _options = {}) {
|
|
|
62
64
|
results.push(...await runStep(() => installArchiveHintHook(normalizedTarget)));
|
|
63
65
|
results.push(...await runStep(() => installKnowledgeHintBroadHook(normalizedTarget)));
|
|
64
66
|
results.push(...await runStep(() => installKnowledgeHintNarrowHook(normalizedTarget)));
|
|
67
|
+
results.push(...await runStep(() => installCitePolicyEvictHook(normalizedTarget)));
|
|
65
68
|
results.push(...await runStep(() => installHookLibs(normalizedTarget)));
|
|
66
69
|
results.push(await runSingleStep("claude-hook-config", () => mergeClaudeCodeHookConfig(normalizedTarget)));
|
|
67
70
|
results.push(await runSingleStep("codex-hook-config", () => mergeCodexHookConfig(normalizedTarget)));
|
|
@@ -340,7 +343,7 @@ async function buildForensicReport(targetInput) {
|
|
|
340
343
|
const report = {
|
|
341
344
|
version: "1.0",
|
|
342
345
|
generated_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
343
|
-
generated_by: `
|
|
346
|
+
generated_by: `fabric-cli@${getCliVersion()}`,
|
|
344
347
|
target,
|
|
345
348
|
project_name: readProjectName(target),
|
|
346
349
|
framework,
|
|
@@ -1348,7 +1351,7 @@ function readProjectName(target) {
|
|
|
1348
1351
|
return basename(target);
|
|
1349
1352
|
}
|
|
1350
1353
|
function getCliVersion() {
|
|
1351
|
-
return true ? "2.0.0-rc.
|
|
1354
|
+
return true ? "2.0.0-rc.35" : "unknown";
|
|
1352
1355
|
}
|
|
1353
1356
|
function sortRecord(record) {
|
|
1354
1357
|
return Object.fromEntries(Object.entries(record).sort(([left], [right]) => left.localeCompare(right)));
|
|
@@ -1385,6 +1388,11 @@ var installCommand = defineCommand({
|
|
|
1385
1388
|
type: "boolean",
|
|
1386
1389
|
description: t("cli.install.args.yes.description"),
|
|
1387
1390
|
default: false
|
|
1391
|
+
},
|
|
1392
|
+
"force-skills-only": {
|
|
1393
|
+
type: "boolean",
|
|
1394
|
+
description: t("cli.install.args.force-skills-only.description"),
|
|
1395
|
+
default: false
|
|
1388
1396
|
}
|
|
1389
1397
|
},
|
|
1390
1398
|
async run({ args }) {
|
|
@@ -1392,9 +1400,56 @@ var installCommand = defineCommand({
|
|
|
1392
1400
|
}
|
|
1393
1401
|
});
|
|
1394
1402
|
var install_default = installCommand;
|
|
1403
|
+
async function runSkillsOnlyRefresh(targetInput) {
|
|
1404
|
+
const target = normalizeTarget3(targetInput);
|
|
1405
|
+
const metaPath = join4(target, ".fabric", "agents.meta.json");
|
|
1406
|
+
if (!existsSync4(metaPath)) {
|
|
1407
|
+
const message = t("cli.install.force-skills-only.uninitialised.message");
|
|
1408
|
+
const hint = t("cli.install.force-skills-only.uninitialised.hint");
|
|
1409
|
+
process.stderr.write(`${message}
|
|
1410
|
+
${hint}
|
|
1411
|
+
`);
|
|
1412
|
+
process.exitCode = 1;
|
|
1413
|
+
return;
|
|
1414
|
+
}
|
|
1415
|
+
console.log(formatInitStageHeader(t("cli.install.force-skills-only.banner")));
|
|
1416
|
+
const results = [];
|
|
1417
|
+
results.push(...await cleanupDeprecatedSkills(target));
|
|
1418
|
+
results.push(...await installFabricArchiveSkill(target));
|
|
1419
|
+
results.push(...await installFabricReviewSkill(target));
|
|
1420
|
+
results.push(...await installFabricImportSkill(target));
|
|
1421
|
+
let written = 0;
|
|
1422
|
+
let skipped = 0;
|
|
1423
|
+
let errors = 0;
|
|
1424
|
+
for (const r of results) {
|
|
1425
|
+
if (r.status === "written") written += 1;
|
|
1426
|
+
else if (r.status === "skipped") skipped += 1;
|
|
1427
|
+
else if (r.status === "error") errors += 1;
|
|
1428
|
+
}
|
|
1429
|
+
console.log(
|
|
1430
|
+
t("cli.install.force-skills-only.summary", {
|
|
1431
|
+
written: String(written),
|
|
1432
|
+
skipped: String(skipped),
|
|
1433
|
+
errors: String(errors)
|
|
1434
|
+
})
|
|
1435
|
+
);
|
|
1436
|
+
if (errors > 0) {
|
|
1437
|
+
for (const r of results) {
|
|
1438
|
+
if (r.status === "error") {
|
|
1439
|
+
process.stderr.write(` ${r.step} ${r.path}: ${r.message ?? "error"}
|
|
1440
|
+
`);
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
process.exitCode = 1;
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1395
1446
|
async function runInitCommand(args) {
|
|
1396
1447
|
const logger = createDebugLogger(args.debug);
|
|
1397
1448
|
const resolution = resolveDevMode(args.target, process.cwd());
|
|
1449
|
+
if (args["force-skills-only"] === true) {
|
|
1450
|
+
await runSkillsOnlyRefresh(resolution.target);
|
|
1451
|
+
return;
|
|
1452
|
+
}
|
|
1398
1453
|
const intent = resolveInitCliIntent(args, resolution.target);
|
|
1399
1454
|
const fabricInitialized = existsSync4(join4(intent.target, ".fabric", "events.jsonl"));
|
|
1400
1455
|
if (fabricInitialized) {
|
|
@@ -1848,6 +1903,7 @@ async function executeInitStagePlan(plan, stageName) {
|
|
|
1848
1903
|
switch (stage.name) {
|
|
1849
1904
|
case "bootstrap": {
|
|
1850
1905
|
const installResults = [];
|
|
1906
|
+
installResults.push(...await runBestEffort("skill-deprecated-cleanup", () => cleanupDeprecatedSkills(plan.target)));
|
|
1851
1907
|
installResults.push(...await runBestEffort("skill-install", () => installFabricArchiveSkill(plan.target)));
|
|
1852
1908
|
installResults.push(...await runBestEffort("skill-review-install", () => installFabricReviewSkill(plan.target)));
|
|
1853
1909
|
installResults.push(...await runBestEffort("skill-import-install", () => installFabricImportSkill(plan.target)));
|
|
@@ -2400,5 +2456,6 @@ export {
|
|
|
2400
2456
|
installCommand,
|
|
2401
2457
|
resolveInitExecutionPlanWithWizard,
|
|
2402
2458
|
runInitCommand,
|
|
2459
|
+
runSkillsOnlyRefresh,
|
|
2403
2460
|
shouldUseInitWizard
|
|
2404
2461
|
};
|
|
@@ -160,7 +160,7 @@ function renderHumanReadable(report) {
|
|
|
160
160
|
detail = entries.join(", ");
|
|
161
161
|
} else if (report.opted_out.includes(slot)) {
|
|
162
162
|
status = "opted-out";
|
|
163
|
-
detail = "(user-dismissed; run `
|
|
163
|
+
detail = "(user-dismissed; run `fabric config onboard-reset` to re-open)";
|
|
164
164
|
} else {
|
|
165
165
|
status = "missing";
|
|
166
166
|
detail = "(run /fabric-archive to onboard)";
|
|
@@ -174,12 +174,12 @@ var onboardCoverageCommand = defineCommand({
|
|
|
174
174
|
name: "onboard-coverage",
|
|
175
175
|
// v2.0.0-rc.29 TASK-008 (BUG-L2): route description strings through t()
|
|
176
176
|
// (mirrors serve.ts pattern). Previously this command was English-only
|
|
177
|
-
// even when the rest of `
|
|
177
|
+
// even when the rest of `fabric --help` rendered zh-CN, so Chinese-locale
|
|
178
178
|
// users saw an isolated English block under --help.
|
|
179
179
|
description: t("cli.onboard-coverage.description"),
|
|
180
|
-
// Mirrors `plan-context-hint`: hidden from `
|
|
180
|
+
// Mirrors `plan-context-hint`: hidden from `fabric --help` so the top-level
|
|
181
181
|
// banner stays focused on install/doctor/serve/config. The command stays
|
|
182
|
-
// callable directly from Skills via `
|
|
182
|
+
// callable directly from Skills via `fabric onboard-coverage --json`.
|
|
183
183
|
hidden: true
|
|
184
184
|
},
|
|
185
185
|
args: {
|
|
@@ -11,9 +11,9 @@ var planContextHintCommand = defineCommand({
|
|
|
11
11
|
meta: {
|
|
12
12
|
name: "plan-context-hint",
|
|
13
13
|
description: "Emit versioned knowledge hint JSON to stdout. Used by rc.6 hooks and the fabric-import skill.",
|
|
14
|
-
// rc.15 TASK-004 (C8): hidden from `
|
|
14
|
+
// rc.15 TASK-004 (C8): hidden from `fabric --help` listing. The command stays
|
|
15
15
|
// callable so hook scripts and the fabric-import skill can still invoke
|
|
16
|
-
// it via `
|
|
16
|
+
// it via `fabric plan-context-hint ...`; it just no longer appears in the
|
|
17
17
|
// top-level usage banner alongside install/doctor/serve/uninstall/config.
|
|
18
18
|
hidden: true
|
|
19
19
|
},
|
package/package.json
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fenglimg/fabric-cli",
|
|
3
|
-
"version": "2.0.0-rc.
|
|
3
|
+
"version": "2.0.0-rc.35",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
|
-
"fab": "dist/index.js",
|
|
7
6
|
"fabric": "dist/index.js"
|
|
8
7
|
},
|
|
9
8
|
"main": "./dist/index.js",
|
|
@@ -20,8 +19,8 @@
|
|
|
20
19
|
"tree-sitter-javascript": "^0.25.0",
|
|
21
20
|
"tree-sitter-typescript": "^0.23.2",
|
|
22
21
|
"web-tree-sitter": "^0.26.8",
|
|
23
|
-
"@fenglimg/fabric-server": "2.0.0-rc.
|
|
24
|
-
"@fenglimg/fabric-shared": "2.0.0-rc.
|
|
22
|
+
"@fenglimg/fabric-server": "2.0.0-rc.35",
|
|
23
|
+
"@fenglimg/fabric-shared": "2.0.0-rc.35"
|
|
25
24
|
},
|
|
26
25
|
"devDependencies": {
|
|
27
26
|
"@types/node": "^22.15.0",
|