@fenglimg/fabric-cli 2.0.0 → 2.0.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/LICENSE +21 -0
- package/README.md +6 -5
- package/dist/chunk-BATF4PEJ.js +361 -0
- package/dist/{chunk-OBQU6NHO.js → chunk-COI5VDFU.js} +0 -18
- package/dist/chunk-D25XJ4BC.js +880 -0
- package/dist/chunk-MF3OTILQ.js +544 -0
- package/dist/chunk-PWLW3B57.js +18 -0
- package/dist/config-XJIPZNUP.js +13 -0
- package/dist/doctor-EJDSEJSS.js +810 -0
- package/dist/index.js +15 -8
- package/dist/{init-BIRSIOXO.js → install-EKWMFLUU.js} +622 -711
- package/dist/metrics-ACEQFPDU.js +122 -0
- package/dist/onboard-coverage-MFCAEBDO.js +220 -0
- package/dist/{plan-context-hint-QMUPAXIB.js → plan-context-hint-FC6P3WFE.js} +34 -28
- package/dist/uninstall-MH7ZIB6M.js +1064 -0
- package/package.json +30 -5
- package/templates/hooks/cite-policy-evict.cjs +231 -0
- package/templates/hooks/configs/README.md +29 -6
- package/templates/hooks/configs/claude-code.json +14 -3
- package/templates/hooks/configs/codex-hooks.json +6 -3
- package/templates/hooks/configs/cursor-hooks.json +8 -10
- package/templates/hooks/fabric-hint.cjs +833 -105
- package/templates/hooks/knowledge-hint-broad.cjs +509 -135
- package/templates/hooks/knowledge-hint-narrow.cjs +791 -26
- package/templates/hooks/lib/banner-i18n.cjs +309 -0
- package/templates/hooks/lib/cite-contract-reminder.cjs +173 -0
- package/templates/hooks/lib/cite-line-parser.cjs +158 -0
- 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/hooks/lib/summary-fallback.cjs +210 -0
- package/templates/skills/fabric-archive/SKILL.md +93 -419
- package/templates/skills/fabric-archive/ref/dry-run-scope.md +16 -0
- package/templates/skills/fabric-archive/ref/e5-cron-recap.md +58 -0
- package/templates/skills/fabric-archive/ref/i18n-policy.md +86 -0
- package/templates/skills/fabric-archive/ref/phase-0-range-resolution.md +156 -0
- package/templates/skills/fabric-archive/ref/phase-1-5-onboard.md +218 -0
- package/templates/skills/fabric-archive/ref/phase-1-cross-session.md +62 -0
- package/templates/skills/fabric-archive/ref/phase-2-5-viability.md +68 -0
- package/templates/skills/fabric-archive/ref/phase-3-5-scope.md +108 -0
- package/templates/skills/fabric-archive/ref/phase-3-classify.md +63 -0
- package/templates/skills/fabric-archive/ref/phase-4-5-emit.md +78 -0
- package/templates/skills/fabric-archive/ref/phase-4-mcp-persist.md +89 -0
- package/templates/skills/fabric-archive/ref/rc-history.md +38 -0
- package/templates/skills/fabric-archive/ref/worked-examples.md +78 -0
- package/templates/skills/fabric-import/SKILL.md +75 -516
- package/templates/skills/fabric-import/ref/checkpoint-state.md +85 -0
- package/templates/skills/fabric-import/ref/i18n-policy.md +79 -0
- package/templates/skills/fabric-import/ref/output-contract.md +61 -0
- package/templates/skills/fabric-import/ref/phase-2-mining.md +213 -0
- package/templates/skills/fabric-import/ref/phase-3-dedup.md +75 -0
- package/templates/skills/fabric-import/ref/state-recovery.md +57 -0
- package/templates/skills/fabric-import/ref/worked-examples.md +127 -0
- package/templates/skills/fabric-review/SKILL.md +86 -284
- package/templates/skills/fabric-review/ref/askuserquestion-policy.md +66 -0
- package/templates/skills/fabric-review/ref/i18n-policy.md +111 -0
- package/templates/skills/fabric-review/ref/modify-flow.md +103 -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/templates/skills/fabric-review/ref/worked-examples.md +95 -0
- package/templates/skills/lib/shared-policy.md +69 -0
- package/dist/chunk-6ICJICVU.js +0 -10
- package/dist/chunk-74SZWYPH.js +0 -658
- package/dist/chunk-EYIDD2YS.js +0 -1000
- package/dist/doctor-T7JWODKG.js +0 -282
- package/dist/hooks-Y74Y5LQS.js +0 -12
- package/dist/scan-LMK3UCWL.js +0 -22
- package/dist/serve-H554BHLG.js +0 -124
- package/templates/agents-md/AGENTS.md.template +0 -59
- package/templates/bootstrap/CLAUDE.md +0 -8
- package/templates/bootstrap/codex-AGENTS-header.md +0 -6
- package/templates/bootstrap/cursor-fabric-bootstrap.mdc +0 -10
package/dist/doctor-T7JWODKG.js
DELETED
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
paint,
|
|
4
|
-
symbol
|
|
5
|
-
} from "./chunk-WWNXR34K.js";
|
|
6
|
-
import {
|
|
7
|
-
t
|
|
8
|
-
} from "./chunk-6ICJICVU.js";
|
|
9
|
-
import {
|
|
10
|
-
resolveDevMode
|
|
11
|
-
} from "./chunk-OBQU6NHO.js";
|
|
12
|
-
|
|
13
|
-
// src/commands/doctor.ts
|
|
14
|
-
import { confirm, isCancel } from "@clack/prompts";
|
|
15
|
-
import { defineCommand } from "citty";
|
|
16
|
-
import {
|
|
17
|
-
appendEventLedgerEvent,
|
|
18
|
-
checkLockOrThrow,
|
|
19
|
-
runDoctorApplyLint,
|
|
20
|
-
runDoctorFix,
|
|
21
|
-
runDoctorReport
|
|
22
|
-
} from "@fenglimg/fabric-server";
|
|
23
|
-
var APPLY_LINT_CODE_LABELS = {
|
|
24
|
-
knowledge_orphan_demote_required: "demote (maturity)",
|
|
25
|
-
knowledge_stale_archive_required: "archive (git mv)",
|
|
26
|
-
knowledge_pending_auto_archive: "archive (git mv, pending)",
|
|
27
|
-
knowledge_index_drift: "counter bump (agents.meta)",
|
|
28
|
-
knowledge_session_hints_stale: "cache delete"
|
|
29
|
-
};
|
|
30
|
-
var PLAN_PREVIEW_LIMIT = 12;
|
|
31
|
-
var doctorCommand = defineCommand({
|
|
32
|
-
meta: {
|
|
33
|
-
name: "doctor",
|
|
34
|
-
description: t("cli.doctor.description")
|
|
35
|
-
},
|
|
36
|
-
args: {
|
|
37
|
-
target: {
|
|
38
|
-
type: "string",
|
|
39
|
-
description: t("cli.doctor.args.target.description")
|
|
40
|
-
},
|
|
41
|
-
fix: {
|
|
42
|
-
type: "boolean",
|
|
43
|
-
description: t("cli.doctor.args.fix.description"),
|
|
44
|
-
default: false
|
|
45
|
-
},
|
|
46
|
-
json: {
|
|
47
|
-
type: "boolean",
|
|
48
|
-
description: t("cli.doctor.args.json.description"),
|
|
49
|
-
default: false
|
|
50
|
-
},
|
|
51
|
-
strict: {
|
|
52
|
-
type: "boolean",
|
|
53
|
-
description: t("cli.doctor.args.strict.description"),
|
|
54
|
-
default: false
|
|
55
|
-
},
|
|
56
|
-
force: {
|
|
57
|
-
type: "boolean",
|
|
58
|
-
description: t("cli.doctor.args.force.description"),
|
|
59
|
-
default: false
|
|
60
|
-
},
|
|
61
|
-
"apply-lint": {
|
|
62
|
-
type: "boolean",
|
|
63
|
-
description: t("cli.doctor.args.apply-lint.description"),
|
|
64
|
-
default: false
|
|
65
|
-
},
|
|
66
|
-
// rc.7 T11: skip the safety confirm before mutations. Required for any
|
|
67
|
-
// non-tty invocation that wants to run --apply-lint without setting
|
|
68
|
-
// FABRIC_NONINTERACTIVE=1 in the environment.
|
|
69
|
-
yes: {
|
|
70
|
-
type: "boolean",
|
|
71
|
-
description: t("cli.doctor.args.yes.description"),
|
|
72
|
-
default: false
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
async run({ args }) {
|
|
76
|
-
const workspaceRoot = process.cwd();
|
|
77
|
-
const resolution = resolveDevMode(args.target, workspaceRoot);
|
|
78
|
-
checkLockOrThrow(resolution.target, { force: args.force });
|
|
79
|
-
const applyLint = args["apply-lint"] === true;
|
|
80
|
-
const fix = args.fix === true;
|
|
81
|
-
if (applyLint && fix) {
|
|
82
|
-
writeStderr(t("cli.doctor.errors.apply-lint-fix-mutually-exclusive"));
|
|
83
|
-
process.exitCode = 1;
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
let applyLintReport = null;
|
|
87
|
-
let fixReport = null;
|
|
88
|
-
let report;
|
|
89
|
-
if (applyLint) {
|
|
90
|
-
const preReport = await runDoctorReport(resolution.target);
|
|
91
|
-
const plan = computeApplyLintPlan(preReport);
|
|
92
|
-
const yesFlag = args.yes === true;
|
|
93
|
-
const envBypass = process.env.FABRIC_NONINTERACTIVE === "1";
|
|
94
|
-
if (plan.totalCount === 0) {
|
|
95
|
-
} else {
|
|
96
|
-
renderApplyLintPlan(plan);
|
|
97
|
-
const decision = await resolveApplyLintConsent({
|
|
98
|
-
yesFlag,
|
|
99
|
-
envBypass,
|
|
100
|
-
plan
|
|
101
|
-
});
|
|
102
|
-
if (decision === "abort") {
|
|
103
|
-
process.exitCode = 1;
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
applyLintReport = await runDoctorApplyLint(resolution.target);
|
|
108
|
-
report = applyLintReport.report;
|
|
109
|
-
} else if (fix) {
|
|
110
|
-
fixReport = await runDoctorFix(resolution.target);
|
|
111
|
-
report = fixReport.report;
|
|
112
|
-
} else {
|
|
113
|
-
report = await runDoctorReport(resolution.target);
|
|
114
|
-
}
|
|
115
|
-
if (args.json === true) {
|
|
116
|
-
writeStdout(JSON.stringify(applyLintReport ?? fixReport ?? report, null, 2));
|
|
117
|
-
} else {
|
|
118
|
-
if (applyLintReport !== null) {
|
|
119
|
-
writeStdout(applyLintReport.message);
|
|
120
|
-
if (applyLintReport.aborted && applyLintReport.abort_reason !== void 0) {
|
|
121
|
-
writeStderr(applyLintReport.abort_reason);
|
|
122
|
-
}
|
|
123
|
-
renderApplyLintMutations(applyLintReport);
|
|
124
|
-
} else if (fixReport !== null) {
|
|
125
|
-
writeStdout(fixReport.message);
|
|
126
|
-
}
|
|
127
|
-
renderHumanReport(report);
|
|
128
|
-
}
|
|
129
|
-
await emitDoctorRunEventBestEffort(resolution.target, {
|
|
130
|
-
mode: applyLint ? "apply-lint" : "lint",
|
|
131
|
-
issues: report.fixable_errors.length + report.manual_errors.length + report.warnings.length,
|
|
132
|
-
mutations: applyLintReport !== null ? applyLintReport.mutations.filter((m) => m.applied).length : void 0
|
|
133
|
-
});
|
|
134
|
-
if (applyLintReport !== null) {
|
|
135
|
-
if (applyLintReport.aborted) {
|
|
136
|
-
process.exitCode = 1;
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
if (applyLintReport.mutations.some((m) => !m.applied)) {
|
|
140
|
-
process.exitCode = 1;
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
if (report.status === "error" || args.strict === true && (report.status === "warn" || report.warnings.length > 0)) {
|
|
145
|
-
process.exitCode = 1;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
var doctor_default = doctorCommand;
|
|
150
|
-
function renderHumanReport(report) {
|
|
151
|
-
writeStdout(`${renderStatus(report.status)} ${paint.ai("fabric doctor")} ${paint.human(report.summary.target)}`);
|
|
152
|
-
for (const check of report.checks) {
|
|
153
|
-
writeStdout(`${renderStatus(check.status)} ${check.name}: ${check.message}`);
|
|
154
|
-
}
|
|
155
|
-
writeIssueSection(t("doctor.section.fixable"), report.fixable_errors);
|
|
156
|
-
writeIssueSection(t("doctor.section.manual"), report.manual_errors);
|
|
157
|
-
writeIssueSection(t("doctor.section.warnings"), report.warnings);
|
|
158
|
-
}
|
|
159
|
-
function renderApplyLintMutations(applyLintReport) {
|
|
160
|
-
if (applyLintReport.mutations.length === 0) {
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
writeStdout("");
|
|
164
|
-
writeStdout(t("doctor.section.apply-lint-mutations"));
|
|
165
|
-
for (const mutation of applyLintReport.mutations) {
|
|
166
|
-
const marker = mutation.applied ? symbol.ok : symbol.error;
|
|
167
|
-
const errSuffix = mutation.applied || mutation.error === void 0 ? "" : ` (${mutation.error})`;
|
|
168
|
-
writeStdout(`${marker} ${mutation.kind}: ${mutation.path} [${mutation.detail}]${errSuffix}`);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
function writeIssueSection(title, issues) {
|
|
172
|
-
if (issues.length === 0) {
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
writeStdout("");
|
|
176
|
-
writeStdout(title);
|
|
177
|
-
for (const issue of issues) {
|
|
178
|
-
writeStdout(`- ${issue.code}: ${issue.message}`);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
function renderStatus(status) {
|
|
182
|
-
if (status === "ok") {
|
|
183
|
-
return symbol.ok;
|
|
184
|
-
}
|
|
185
|
-
if (status === "warn") {
|
|
186
|
-
return symbol.warn;
|
|
187
|
-
}
|
|
188
|
-
return symbol.error;
|
|
189
|
-
}
|
|
190
|
-
function writeStdout(message) {
|
|
191
|
-
process.stdout.write(`${message}
|
|
192
|
-
`);
|
|
193
|
-
}
|
|
194
|
-
async function emitDoctorRunEventBestEffort(projectRoot, payload) {
|
|
195
|
-
try {
|
|
196
|
-
await appendEventLedgerEvent(projectRoot, {
|
|
197
|
-
event_type: "doctor_run",
|
|
198
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
199
|
-
mode: payload.mode,
|
|
200
|
-
issues: payload.issues,
|
|
201
|
-
...payload.mutations !== void 0 ? { mutations: payload.mutations } : {}
|
|
202
|
-
});
|
|
203
|
-
} catch {
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
function writeStderr(message) {
|
|
207
|
-
process.stderr.write(`${message}
|
|
208
|
-
`);
|
|
209
|
-
}
|
|
210
|
-
function computeApplyLintPlan(report) {
|
|
211
|
-
const buckets = {};
|
|
212
|
-
const sources = [
|
|
213
|
-
...report.fixable_errors,
|
|
214
|
-
...report.warnings
|
|
215
|
-
];
|
|
216
|
-
for (const issue of sources) {
|
|
217
|
-
if (APPLY_LINT_CODE_LABELS[issue.code] === void 0) continue;
|
|
218
|
-
if (!Array.isArray(buckets[issue.code])) {
|
|
219
|
-
buckets[issue.code] = [];
|
|
220
|
-
}
|
|
221
|
-
buckets[issue.code].push(issue);
|
|
222
|
-
}
|
|
223
|
-
const codes = Object.keys(buckets).sort(
|
|
224
|
-
(a, b) => APPLY_LINT_CODE_LABELS[a].localeCompare(APPLY_LINT_CODE_LABELS[b])
|
|
225
|
-
);
|
|
226
|
-
const perCodeLines = [];
|
|
227
|
-
let totalCount = 0;
|
|
228
|
-
for (const code of codes) {
|
|
229
|
-
const items = buckets[code];
|
|
230
|
-
totalCount += items.length;
|
|
231
|
-
perCodeLines.push(` - ${APPLY_LINT_CODE_LABELS[code]}: ${items.length}`);
|
|
232
|
-
}
|
|
233
|
-
const previewLines = [];
|
|
234
|
-
const flattened = codes.flatMap((c) => buckets[c]);
|
|
235
|
-
for (const item of flattened.slice(0, PLAN_PREVIEW_LIMIT)) {
|
|
236
|
-
const where = item.path !== void 0 && item.path.length > 0 ? `${item.path}` : "(no path)";
|
|
237
|
-
previewLines.push(` \u2022 ${where} \u2014 ${item.message}`);
|
|
238
|
-
}
|
|
239
|
-
if (flattened.length > PLAN_PREVIEW_LIMIT) {
|
|
240
|
-
previewLines.push(` \u2022 ... and ${flattened.length - PLAN_PREVIEW_LIMIT} more`);
|
|
241
|
-
}
|
|
242
|
-
return { totalCount, perCodeLines, previewLines };
|
|
243
|
-
}
|
|
244
|
-
function renderApplyLintPlan(plan) {
|
|
245
|
-
writeStdout("");
|
|
246
|
-
writeStdout(`${paint.warn("apply-lint mutation plan")} (${plan.totalCount} total)`);
|
|
247
|
-
for (const line of plan.perCodeLines) {
|
|
248
|
-
writeStdout(line);
|
|
249
|
-
}
|
|
250
|
-
if (plan.previewLines.length > 0) {
|
|
251
|
-
writeStdout("");
|
|
252
|
-
writeStdout(" preview:");
|
|
253
|
-
for (const line of plan.previewLines) {
|
|
254
|
-
writeStdout(line);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
async function resolveApplyLintConsent(options) {
|
|
259
|
-
if (options.yesFlag || options.envBypass) {
|
|
260
|
-
return "proceed";
|
|
261
|
-
}
|
|
262
|
-
if (process.stdin.isTTY !== true) {
|
|
263
|
-
writeStderr(
|
|
264
|
-
"doctor --apply-lint: stdin is not a TTY and neither --yes nor FABRIC_NONINTERACTIVE=1 is set. Refusing to mutate."
|
|
265
|
-
);
|
|
266
|
-
return "abort";
|
|
267
|
-
}
|
|
268
|
-
const message = `About to apply ${options.plan.totalCount} mutation(s) to knowledge entries (frontmatter writes + git mv + cache deletes). Proceed?`;
|
|
269
|
-
const answer = await confirm({
|
|
270
|
-
message,
|
|
271
|
-
initialValue: false
|
|
272
|
-
});
|
|
273
|
-
if (isCancel(answer) || answer !== true) {
|
|
274
|
-
writeStderr("doctor --apply-lint: aborted by user.");
|
|
275
|
-
return "abort";
|
|
276
|
-
}
|
|
277
|
-
return "proceed";
|
|
278
|
-
}
|
|
279
|
-
export {
|
|
280
|
-
doctor_default as default,
|
|
281
|
-
doctorCommand
|
|
282
|
-
};
|
package/dist/hooks-Y74Y5LQS.js
DELETED
package/dist/scan-LMK3UCWL.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
__testing__,
|
|
4
|
-
createScanReport,
|
|
5
|
-
deriveTagsFromForensic,
|
|
6
|
-
formatKnowledgeId,
|
|
7
|
-
runInitScan,
|
|
8
|
-
scanCommand,
|
|
9
|
-
scan_default
|
|
10
|
-
} from "./chunk-EYIDD2YS.js";
|
|
11
|
-
import "./chunk-WWNXR34K.js";
|
|
12
|
-
import "./chunk-6ICJICVU.js";
|
|
13
|
-
import "./chunk-OBQU6NHO.js";
|
|
14
|
-
export {
|
|
15
|
-
__testing__,
|
|
16
|
-
createScanReport,
|
|
17
|
-
scan_default as default,
|
|
18
|
-
deriveTagsFromForensic,
|
|
19
|
-
formatKnowledgeId,
|
|
20
|
-
runInitScan,
|
|
21
|
-
scanCommand
|
|
22
|
-
};
|
package/dist/serve-H554BHLG.js
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
paint,
|
|
4
|
-
symbol
|
|
5
|
-
} from "./chunk-WWNXR34K.js";
|
|
6
|
-
import {
|
|
7
|
-
t
|
|
8
|
-
} from "./chunk-6ICJICVU.js";
|
|
9
|
-
import {
|
|
10
|
-
createDebugLogger,
|
|
11
|
-
resolveDevMode
|
|
12
|
-
} from "./chunk-OBQU6NHO.js";
|
|
13
|
-
|
|
14
|
-
// src/commands/serve.ts
|
|
15
|
-
import { defineCommand } from "citty";
|
|
16
|
-
import { acquireLock, releaseLock, startHttpServer } from "@fenglimg/fabric-server";
|
|
17
|
-
var DEFAULT_PORT = 7373;
|
|
18
|
-
var serveCommand = defineCommand({
|
|
19
|
-
meta: {
|
|
20
|
-
name: "serve",
|
|
21
|
-
description: t("cli.serve.description")
|
|
22
|
-
},
|
|
23
|
-
args: {
|
|
24
|
-
port: {
|
|
25
|
-
type: "string",
|
|
26
|
-
description: t("cli.serve.args.port.description"),
|
|
27
|
-
default: String(DEFAULT_PORT)
|
|
28
|
-
},
|
|
29
|
-
host: {
|
|
30
|
-
type: "string",
|
|
31
|
-
description: t("cli.serve.args.host.description"),
|
|
32
|
-
default: "127.0.0.1"
|
|
33
|
-
},
|
|
34
|
-
target: {
|
|
35
|
-
type: "string",
|
|
36
|
-
description: t("cli.serve.args.target.description")
|
|
37
|
-
},
|
|
38
|
-
debug: {
|
|
39
|
-
type: "boolean",
|
|
40
|
-
description: t("cli.serve.args.debug.description"),
|
|
41
|
-
default: false
|
|
42
|
-
},
|
|
43
|
-
force: {
|
|
44
|
-
type: "boolean",
|
|
45
|
-
description: t("cli.serve.args.force.description"),
|
|
46
|
-
default: false
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
async run({ args }) {
|
|
50
|
-
const workspaceRoot = process.cwd();
|
|
51
|
-
const logger = createDebugLogger(args.debug);
|
|
52
|
-
const resolution = resolveDevMode(args.target, workspaceRoot);
|
|
53
|
-
const port = parsePort(args.port);
|
|
54
|
-
const requestedHost = parseHost(args.host);
|
|
55
|
-
const authToken = readAuthTokenFromEnv();
|
|
56
|
-
const host = validateHost(requestedHost, authToken);
|
|
57
|
-
const projectRoot = resolution.target;
|
|
58
|
-
acquireLock(projectRoot, { force: args.force });
|
|
59
|
-
process.on("exit", () => {
|
|
60
|
-
releaseLock(projectRoot);
|
|
61
|
-
});
|
|
62
|
-
logger(`serve target source: ${resolution.source}`);
|
|
63
|
-
for (const step of resolution.chain) {
|
|
64
|
-
logger(step);
|
|
65
|
-
}
|
|
66
|
-
try {
|
|
67
|
-
await startHttpServer({
|
|
68
|
-
port,
|
|
69
|
-
projectRoot,
|
|
70
|
-
host,
|
|
71
|
-
authToken
|
|
72
|
-
});
|
|
73
|
-
} catch (error) {
|
|
74
|
-
if (isNodeError(error) && error.code === "EADDRINUSE") {
|
|
75
|
-
releaseLock(projectRoot);
|
|
76
|
-
throw new Error(t("cli.serve.error.port-in-use", { port: String(port), nextPort: String(port + 1) }));
|
|
77
|
-
}
|
|
78
|
-
releaseLock(projectRoot);
|
|
79
|
-
throw error;
|
|
80
|
-
}
|
|
81
|
-
console.log(`${symbol.ok} ${paint.ai(t("cli.serve.ready.title"))} ${paint.human(`http://${host}:${port}`)}`);
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
var serve_default = serveCommand;
|
|
85
|
-
function parsePort(value) {
|
|
86
|
-
const port = Number.parseInt(value ?? String(DEFAULT_PORT), 10);
|
|
87
|
-
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
88
|
-
throw new Error(t("cli.shared.invalid-port", { value: value ?? "<unset>" }));
|
|
89
|
-
}
|
|
90
|
-
return port;
|
|
91
|
-
}
|
|
92
|
-
function parseHost(value) {
|
|
93
|
-
const host = value?.trim() ?? "127.0.0.1";
|
|
94
|
-
if (host.length === 0) {
|
|
95
|
-
throw new Error(t("cli.shared.invalid-host-empty"));
|
|
96
|
-
}
|
|
97
|
-
return host;
|
|
98
|
-
}
|
|
99
|
-
function readAuthTokenFromEnv() {
|
|
100
|
-
const token = process.env.FABRIC_AUTH_TOKEN;
|
|
101
|
-
return token === void 0 || token.length === 0 ? void 0 : token;
|
|
102
|
-
}
|
|
103
|
-
function validateHost(host, authToken) {
|
|
104
|
-
if (authToken !== void 0) {
|
|
105
|
-
return host;
|
|
106
|
-
}
|
|
107
|
-
if (!isLoopbackHost(host)) {
|
|
108
|
-
console.error(
|
|
109
|
-
`${symbol.warn} ${paint.warn(t("cli.serve.warning.host-fallback", { host }))}`
|
|
110
|
-
);
|
|
111
|
-
return "127.0.0.1";
|
|
112
|
-
}
|
|
113
|
-
return host;
|
|
114
|
-
}
|
|
115
|
-
function isLoopbackHost(host) {
|
|
116
|
-
return host === "127.0.0.1" || host === "localhost" || host === "::1";
|
|
117
|
-
}
|
|
118
|
-
function isNodeError(error) {
|
|
119
|
-
return error instanceof Error;
|
|
120
|
-
}
|
|
121
|
-
export {
|
|
122
|
-
serve_default as default,
|
|
123
|
-
serveCommand
|
|
124
|
-
};
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# { projectName } — Fabric Bootstrap Protocol
|
|
2
|
-
|
|
3
|
-
## CORE RULES (DO NOT TRANSLATE)
|
|
4
|
-
|
|
5
|
-
MUST: Treat this file as the Fabric Protocol bootstrap for this repository.
|
|
6
|
-
MUST: Treat `.fabric/knowledge/` as the source of truth for all Fabric knowledge entries.
|
|
7
|
-
MUST: Before ANY code reading, architecture planning, or logic modification, call `fab_plan_context(paths=[<target file>])`, then call `fab_get_knowledge_sections`.
|
|
8
|
-
MUST: When creating or changing a knowledge entry, keep `.fabric/agents.meta.json` synchronized through Fabric tooling (never hand-edit).
|
|
9
|
-
MUST: Preserve protected tokens exactly: `AGENTS.md`, `.fabric/knowledge/`, `.fabric/agents.meta.json`, `fab_plan_context`, `fab_get_knowledge_sections`, `knowledge sources`, `MUST`, `NEVER`.
|
|
10
|
-
NEVER: Add import-style directive lines to this bootstrap file.
|
|
11
|
-
NEVER: Put domain knowledge bodies, framework rules, or repository specifics in this file.
|
|
12
|
-
NEVER: Create colocated `AGENTS.md` knowledge files under source directories.
|
|
13
|
-
NEVER: Hand-edit anything under `.fabric/knowledge/pending/` outside of the proposal/review workflow.
|
|
14
|
-
|
|
15
|
-
## 使用说明 / Explanation
|
|
16
|
-
|
|
17
|
-
- 本文件只负责启动 Fabric Bootstrap Protocol,不承载项目业务知识。
|
|
18
|
-
- 详细 bootstrap 说明位于 `.fabric/bootstrap/README.md`。
|
|
19
|
-
- Detected framework kind: `{ frameworkKind }`.
|
|
20
|
-
- This repository uses `knowledge mirroring`: source directories contain ZERO knowledge files, while `.fabric/knowledge/` holds all AI-facing constraints, organized by knowledge type.
|
|
21
|
-
- 跨领域、根级知识应放在对应的 `.fabric/knowledge/{type}/` 子目录下。
|
|
22
|
-
- If `.fabric/knowledge/` is empty after init, continue with the Fabric initialization flow before normal coding.
|
|
23
|
-
|
|
24
|
-
## Knowledge layer (v2)
|
|
25
|
-
|
|
26
|
-
Fabric v2 organises every AI-facing knowledge entry along three orthogonal axes: **type**, **maturity**, and **layer**. All entries live as flat markdown files with YAML frontmatter — no nesting, no implicit hierarchies.
|
|
27
|
-
|
|
28
|
-
### 5 knowledge types
|
|
29
|
-
|
|
30
|
-
Each entry lives in exactly one of these subdirectories of `.fabric/knowledge/`:
|
|
31
|
-
|
|
32
|
-
- `decisions/` — architectural / design decisions (the "why" behind a choice, with rejected alternatives)
|
|
33
|
-
- `pitfalls/` — known traps, footguns, and "do-not-do-X" lessons learned the hard way
|
|
34
|
-
- `guidelines/` — actionable rules and conventions the AI should follow when generating or modifying code
|
|
35
|
-
- `models/` — domain models, data shapes, and conceptual abstractions (entities, invariants)
|
|
36
|
-
- `processes/` — multi-step workflows, runbooks, and operational sequences
|
|
37
|
-
|
|
38
|
-
### 3 maturity levels
|
|
39
|
-
|
|
40
|
-
The `maturity` frontmatter field expresses how trusted an entry is:
|
|
41
|
-
|
|
42
|
-
- `draft` — newly captured, not yet reviewed; the AI may consult it but should treat it as provisional
|
|
43
|
-
- `verified` — reviewed and confirmed correct in the current codebase; safe to rely on
|
|
44
|
-
- `proven` — verified and battle-tested across multiple changes; treat as authoritative
|
|
45
|
-
|
|
46
|
-
Promotion is one-way (`draft` → `verified` → `proven`); demotion happens only via the review workflow.
|
|
47
|
-
|
|
48
|
-
### 2 layers (dual-root)
|
|
49
|
-
|
|
50
|
-
Knowledge lives in two physical roots that share the same schema:
|
|
51
|
-
|
|
52
|
-
- `~/.fabric/knowledge/` — **personal layer** (per-user, NOT committed). Entries here use the `KP-` stable_id prefix. Use this layer for individual preferences, scratch notes, and cross-project habits.
|
|
53
|
-
- `<repo>/.fabric/knowledge/` — **team layer** (committed to the repo). Entries here use the `KT-` stable_id prefix. Use this layer for anything every contributor (human or AI) should respect.
|
|
54
|
-
|
|
55
|
-
A given entry belongs to exactly one layer; layer-flip (KP ↔ KT) is the only legal mutation of stable_id.
|
|
56
|
-
|
|
57
|
-
### Proposal staging: `pending/`
|
|
58
|
-
|
|
59
|
-
`.fabric/knowledge/pending/` is the staging area for proposed entries awaiting review. The async-review workflow (`fabric-review` skill, rc.3) promotes pending entries into one of the 5 type subdirectories once accepted, or archives them on rejection. **Never** hand-edit files under `pending/` directly — use the proposal tooling.
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
# Fabric Bootstrap
|
|
2
|
-
- 主说明文档已收敛到 `.fabric/bootstrap/README.md`。
|
|
3
|
-
- 项目级 bootstrap 入口仍然是 `AGENTS.md`。
|
|
4
|
-
- 修改任何文件前必须调用 `fab_plan_context(paths=[<被改文件>])`,再调用 `fab_get_knowledge_sections` 获取规则段落。
|
|
5
|
-
MCP 和 doctor 会写入 `.fabric/events.jsonl`。
|
|
6
|
-
- 规则 baseline 变更通过 `fabric doctor --fix` 接受。
|
|
7
|
-
|
|
8
|
-
@AGENTS.md
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
# Fabric Bootstrap
|
|
2
|
-
- 主说明文档已收敛到 `.fabric/bootstrap/README.md`。
|
|
3
|
-
- 此 header 仅用于把 Codex 引导到 Fabric 项目级规则入口。
|
|
4
|
-
- 修改任何文件前必须调用 `fab_plan_context(paths=[<被改文件>])`,再调用 `fab_get_knowledge_sections` 获取规则段落。
|
|
5
|
-
MCP 和 doctor 会写入 `.fabric/events.jsonl`。
|
|
6
|
-
- 规则 baseline 变更通过 `fabric doctor --fix` 接受。
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
alwaysApply: true
|
|
3
|
-
description: Fabric Protocol bootstrap rules
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Fabric Bootstrap
|
|
7
|
-
- 本项目使用 Fabric Protocol 管理规则。
|
|
8
|
-
- **任何文件修改前**,必须先调 MCP tool `fab_plan_context(paths=[<被改文件>])`,再调 `fab_get_knowledge_sections` 获取规则段落。
|
|
9
|
-
- 新建或调整 L1/L2 节点时,修改规则源文件后运行 `fabric doctor --fix` 接受 baseline,**严禁**直接编辑 `.fabric/agents.meta.json`。
|
|
10
|
-
Fabric 会把 MCP 和 doctor 行为写入 `.fabric/events.jsonl`。
|