@fenglimg/fabric-server 2.0.0-rc.34 → 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.
|
@@ -88,7 +88,7 @@ import { agentsMetaSchema as agentsMetaSchema2 } from "@fenglimg/fabric-shared";
|
|
|
88
88
|
var AgentsMetaFileMissingError = class extends IOFabricError {
|
|
89
89
|
constructor(metaPath, opts) {
|
|
90
90
|
super(`Fabric agents metadata file is missing: ${metaPath}`, {
|
|
91
|
-
actionHint: opts?.actionHint ?? "Run `
|
|
91
|
+
actionHint: opts?.actionHint ?? "Run `fabric install` to scaffold the .fabric/agents.meta.json file"
|
|
92
92
|
});
|
|
93
93
|
this.metaPath = metaPath;
|
|
94
94
|
}
|
|
@@ -241,7 +241,7 @@ async function appendEventLedgerEvent(projectRoot, event) {
|
|
|
241
241
|
if (size > EVENT_LEDGER_SIZE_WARN_BYTES) {
|
|
242
242
|
warnedOversize = true;
|
|
243
243
|
process.stderr.write(
|
|
244
|
-
'fabric: events.jsonl > 50MB, run "
|
|
244
|
+
'fabric: events.jsonl > 50MB, run "fabric doctor --fix" to rotate\n'
|
|
245
245
|
);
|
|
246
246
|
}
|
|
247
247
|
} catch {
|
|
@@ -1280,7 +1280,7 @@ function validateFrontmatter(source, filePath, throwOnInvalid) {
|
|
|
1280
1280
|
const msg = `Unterminated YAML frontmatter in ${filePath}`;
|
|
1281
1281
|
if (throwOnInvalid) {
|
|
1282
1282
|
throw new RuleValidationError(msg, {
|
|
1283
|
-
actionHint: "Run `
|
|
1283
|
+
actionHint: "Run `fabric doctor --fix` to repair frontmatter",
|
|
1284
1284
|
fixable: true,
|
|
1285
1285
|
details: { file: filePath }
|
|
1286
1286
|
});
|
|
@@ -1288,7 +1288,7 @@ function validateFrontmatter(source, filePath, throwOnInvalid) {
|
|
|
1288
1288
|
return {
|
|
1289
1289
|
code: "rule_frontmatter_invalid",
|
|
1290
1290
|
file: filePath,
|
|
1291
|
-
action_hint: "Run `
|
|
1291
|
+
action_hint: "Run `fabric doctor --fix` to repair frontmatter"
|
|
1292
1292
|
};
|
|
1293
1293
|
}
|
|
1294
1294
|
const frontmatter = source.slice(3, endIdx).trim();
|
|
@@ -1301,7 +1301,7 @@ function validateFrontmatter(source, filePath, throwOnInvalid) {
|
|
|
1301
1301
|
const msg = `Invalid YAML frontmatter line "${trimmed}" in ${filePath}`;
|
|
1302
1302
|
if (throwOnInvalid) {
|
|
1303
1303
|
throw new RuleValidationError(msg, {
|
|
1304
|
-
actionHint: "Run `
|
|
1304
|
+
actionHint: "Run `fabric doctor --fix` to repair frontmatter",
|
|
1305
1305
|
fixable: true,
|
|
1306
1306
|
details: { file: filePath, line: trimmed }
|
|
1307
1307
|
});
|
|
@@ -1309,7 +1309,7 @@ function validateFrontmatter(source, filePath, throwOnInvalid) {
|
|
|
1309
1309
|
return {
|
|
1310
1310
|
code: "rule_frontmatter_invalid",
|
|
1311
1311
|
file: filePath,
|
|
1312
|
-
action_hint: "Run `
|
|
1312
|
+
action_hint: "Run `fabric doctor --fix` to repair frontmatter"
|
|
1313
1313
|
};
|
|
1314
1314
|
}
|
|
1315
1315
|
}
|
|
@@ -1634,13 +1634,14 @@ function checkLockOrThrow(projectRoot, opts) {
|
|
|
1634
1634
|
}
|
|
1635
1635
|
|
|
1636
1636
|
// src/services/doctor.ts
|
|
1637
|
-
import { execFileSync } from "child_process";
|
|
1637
|
+
import { execFileSync, spawnSync } from "child_process";
|
|
1638
1638
|
import { existsSync as existsSync5, readdirSync, readFileSync as readFileSync3, statSync as statSync4 } from "fs";
|
|
1639
1639
|
import { access, mkdir as mkdir4, readFile as readFile5, rename, unlink, writeFile as writeFile2 } from "fs/promises";
|
|
1640
1640
|
import { constants } from "fs";
|
|
1641
1641
|
import { homedir as homedir3 } from "os";
|
|
1642
1642
|
import { isAbsolute as isAbsolute2, join as join7, posix, relative as nodeRelative, resolve as resolve3, sep as sep3 } from "path";
|
|
1643
1643
|
import { minimatch } from "minimatch";
|
|
1644
|
+
import { ZodError } from "zod";
|
|
1644
1645
|
import {
|
|
1645
1646
|
agentsMetaSchema as agentsMetaSchema4,
|
|
1646
1647
|
AgentsMetaCountersSchema,
|
|
@@ -1857,6 +1858,7 @@ async function runDoctorReport(target) {
|
|
|
1857
1858
|
const onboardCoverage = inspectOnboardCoverage(projectRoot);
|
|
1858
1859
|
const hooksWired = inspectHooksWired(projectRoot);
|
|
1859
1860
|
const promoteLedgerInvariant = eventLedger.exists && eventLedger.writable && eventLedger.parseable ? await inspectPromoteLedgerInvariant(projectRoot) : null;
|
|
1861
|
+
const globalCliVersion = process.env.VITEST === "true" ? { status: "ok", version: "test-skipped" } : inspectGlobalCliVersion();
|
|
1860
1862
|
const checks = [
|
|
1861
1863
|
createBootstrapAnchorCheck(t, bootstrapAnchor),
|
|
1862
1864
|
// v2.0.0-rc.19 TASK-004: bootstrap marker migration check sits adjacent to
|
|
@@ -1880,7 +1882,7 @@ async function runDoctorReport(target) {
|
|
|
1880
1882
|
// The file's absence is a legitimate post-init state when the skill has
|
|
1881
1883
|
// not yet run, so flagging it as a doctor manual_error misrepresents
|
|
1882
1884
|
// ownership.
|
|
1883
|
-
createMetaCheck(t, meta),
|
|
1885
|
+
createMetaCheck(t, meta, globalCliVersion),
|
|
1884
1886
|
createRuleContentRefCheck(t, meta),
|
|
1885
1887
|
// v2.0 / rc.2: `createRuleSectionsCheck` removed — it parsed v1.x
|
|
1886
1888
|
// [MANDATORY_INJECTION] sections out of legacy rule files, a structural
|
|
@@ -1896,7 +1898,7 @@ async function runDoctorReport(target) {
|
|
|
1896
1898
|
// v2.0.0-rc.28 TASK-04 (audit §3.1 follow-up): SKILL ref/ mirror parity.
|
|
1897
1899
|
// Detects hand-edits or partial install that breaks the byte-identical
|
|
1898
1900
|
// contract between .claude/skills/<slug>/ref/ and .codex/skills/<slug>/
|
|
1899
|
-
// ref/. warning severity —
|
|
1901
|
+
// ref/. warning severity — fabric install restores parity.
|
|
1900
1902
|
createSkillRefMirrorCheck(t, skillRefMirror),
|
|
1901
1903
|
createSkillTokenBudgetCheck(t, skillTokenBudget),
|
|
1902
1904
|
createSkillDescriptionCheck(t, skillDescription),
|
|
@@ -1958,6 +1960,15 @@ async function runDoctorReport(target) {
|
|
|
1958
1960
|
// rc.31 BUG-M3/NEW-4: hooks_wired observability. Adjacent to onboard /
|
|
1959
1961
|
// promote-ledger checks — all three are install/runtime-state advisories.
|
|
1960
1962
|
createHooksWiredCheck(t, hooksWired),
|
|
1963
|
+
// rc.35 TASK-04 (P0-9.b): global CLI version probe — surfaces rc.30 PATH
|
|
1964
|
+
// installs against rc.31+ project schemas (the silent-hooks fault mode).
|
|
1965
|
+
// Sits next to hooks_wired since both lints diagnose runtime install state.
|
|
1966
|
+
createGlobalCliVersionCheck(t, globalCliVersion),
|
|
1967
|
+
// rc.35 TASK-05 (P0-10.a): opaque-summary ratio — surfaces the
|
|
1968
|
+
// werewolf-eval failure mode where description.summary == stable_id so
|
|
1969
|
+
// hint output is "KT-PIT-0001 · KT-PIT-0001" (AI skips fetch). Built
|
|
1970
|
+
// from the same MetaInspection so no extra disk reads.
|
|
1971
|
+
createKnowledgeSummaryOpaqueCheck(t, inspectKnowledgeSummaryOpaque(meta)),
|
|
1961
1972
|
// rc.31 BUG-G2/G5: promote-ledger invariant. Sits adjacent to onboard
|
|
1962
1973
|
// coverage — both are observability advisories built off events.jsonl.
|
|
1963
1974
|
...promoteLedgerInvariant === null ? [] : [createPromoteLedgerInvariantCheck(t, promoteLedgerInvariant)],
|
|
@@ -2615,6 +2626,17 @@ async function inspectMeta(projectRoot) {
|
|
|
2615
2626
|
changed: built?.changed ?? true
|
|
2616
2627
|
};
|
|
2617
2628
|
}
|
|
2629
|
+
let readErrorKind = "other";
|
|
2630
|
+
let readErrorZodIssues;
|
|
2631
|
+
if (error instanceof ZodError) {
|
|
2632
|
+
readErrorKind = "zod";
|
|
2633
|
+
readErrorZodIssues = error.issues.slice(0, 3).map((issue) => ({
|
|
2634
|
+
path: issue.path.length > 0 ? issue.path.join(".") : "<root>",
|
|
2635
|
+
message: issue.message
|
|
2636
|
+
}));
|
|
2637
|
+
} else if (error instanceof SyntaxError) {
|
|
2638
|
+
readErrorKind = "json";
|
|
2639
|
+
}
|
|
2618
2640
|
return {
|
|
2619
2641
|
present: true,
|
|
2620
2642
|
valid: false,
|
|
@@ -2622,6 +2644,8 @@ async function inspectMeta(projectRoot) {
|
|
|
2622
2644
|
revision: null,
|
|
2623
2645
|
computedRevision: built?.meta.revision ?? null,
|
|
2624
2646
|
ruleCount: 0,
|
|
2647
|
+
readErrorKind,
|
|
2648
|
+
readErrorZodIssues,
|
|
2625
2649
|
missingContentRefs: [],
|
|
2626
2650
|
invalidContentRefs: [],
|
|
2627
2651
|
stale: true,
|
|
@@ -3325,7 +3349,7 @@ function createForensicCheck(t, forensic, frameworkKind, entryPointCount) {
|
|
|
3325
3349
|
t("doctor.check.forensic.ok", { frameworkKind: forensic.report?.framework.kind ?? "unknown" })
|
|
3326
3350
|
);
|
|
3327
3351
|
}
|
|
3328
|
-
function createMetaCheck(t, meta) {
|
|
3352
|
+
function createMetaCheck(t, meta, globalCli) {
|
|
3329
3353
|
if (!meta.present) {
|
|
3330
3354
|
return issueCheck(
|
|
3331
3355
|
t("doctor.check.agents_meta.name"),
|
|
@@ -3337,6 +3361,30 @@ function createMetaCheck(t, meta) {
|
|
|
3337
3361
|
);
|
|
3338
3362
|
}
|
|
3339
3363
|
if (!meta.valid) {
|
|
3364
|
+
if (globalCli && globalCli.status === "outdated") {
|
|
3365
|
+
return issueCheck(
|
|
3366
|
+
t("doctor.check.agents_meta.name"),
|
|
3367
|
+
"error",
|
|
3368
|
+
"manual_error",
|
|
3369
|
+
"agents_meta_invalid_global_cli_outdated",
|
|
3370
|
+
t("doctor.check.agents_meta.message.invalid-from-old-cli", {
|
|
3371
|
+
version: globalCli.version,
|
|
3372
|
+
minVersion: globalCli.minVersion
|
|
3373
|
+
}),
|
|
3374
|
+
t("doctor.check.global_cli_outdated.remediation")
|
|
3375
|
+
);
|
|
3376
|
+
}
|
|
3377
|
+
if (meta.readErrorKind === "zod" && meta.readErrorZodIssues && meta.readErrorZodIssues.length > 0) {
|
|
3378
|
+
const formatted = meta.readErrorZodIssues.map((issue) => `${issue.path}: ${issue.message}`).join("; ");
|
|
3379
|
+
return issueCheck(
|
|
3380
|
+
t("doctor.check.agents_meta.name"),
|
|
3381
|
+
"error",
|
|
3382
|
+
"manual_error",
|
|
3383
|
+
"agents_meta_invalid",
|
|
3384
|
+
t("doctor.check.agents_meta.message.invalid-zod", { issues: formatted }),
|
|
3385
|
+
t("doctor.check.agents_meta.remediation.invalid")
|
|
3386
|
+
);
|
|
3387
|
+
}
|
|
3340
3388
|
return issueCheck(
|
|
3341
3389
|
t("doctor.check.agents_meta.name"),
|
|
3342
3390
|
"error",
|
|
@@ -3569,7 +3617,11 @@ function createSkillTokenBudgetCheck(t, inspection) {
|
|
|
3569
3617
|
count: String(count),
|
|
3570
3618
|
list
|
|
3571
3619
|
}),
|
|
3572
|
-
t("doctor.check.skill_token_budget.remediation")
|
|
3620
|
+
t("doctor.check.skill_token_budget.remediation"),
|
|
3621
|
+
// rc.35 TASK-12 (P0-11): maintainer audience. Remediation points at
|
|
3622
|
+
// `packages/cli/templates/skills/*` source — only Fabric contributors
|
|
3623
|
+
// can act. CLI renderer folds by default; --verbose unfolds.
|
|
3624
|
+
"maintainer"
|
|
3573
3625
|
);
|
|
3574
3626
|
}
|
|
3575
3627
|
function createDraftBacklogCheck(t, inspection) {
|
|
@@ -3611,7 +3663,11 @@ function createCiteGoodhartCheck(t, inspection) {
|
|
|
3611
3663
|
count: String(count),
|
|
3612
3664
|
list
|
|
3613
3665
|
}),
|
|
3614
|
-
t("doctor.check.cite_goodhart.remediation")
|
|
3666
|
+
t("doctor.check.cite_goodhart.remediation"),
|
|
3667
|
+
// rc.35 TASK-12 (P0-11): maintainer audience. G1/G2/G3/G5 are internal
|
|
3668
|
+
// pattern codes from the cite-policy design memo — npm end users have
|
|
3669
|
+
// no actionable lever for these. Fold by default; --verbose unfolds.
|
|
3670
|
+
"maintainer"
|
|
3615
3671
|
);
|
|
3616
3672
|
}
|
|
3617
3673
|
function createSkillDescriptionCheck(t, inspection) {
|
|
@@ -3632,7 +3688,10 @@ function createSkillDescriptionCheck(t, inspection) {
|
|
|
3632
3688
|
count: String(count),
|
|
3633
3689
|
list
|
|
3634
3690
|
}),
|
|
3635
|
-
t("doctor.check.skill_description.remediation")
|
|
3691
|
+
t("doctor.check.skill_description.remediation"),
|
|
3692
|
+
// rc.35 TASK-12 (P0-11): maintainer audience. Remediation points at
|
|
3693
|
+
// `packages/cli/templates/skills/<slug>/SKILL.md` frontmatter.
|
|
3694
|
+
"maintainer"
|
|
3636
3695
|
);
|
|
3637
3696
|
}
|
|
3638
3697
|
function createEventLedgerPartialWriteCheck(t, ledger) {
|
|
@@ -3794,7 +3853,157 @@ function createPromoteLedgerInvariantCheck(t, inspection) {
|
|
|
3794
3853
|
t("doctor.check.promote_ledger_invariant.remediation")
|
|
3795
3854
|
);
|
|
3796
3855
|
}
|
|
3797
|
-
|
|
3856
|
+
var MIN_SUPPORTED_GLOBAL_CLI_VERSION = "2.0.0-rc.31";
|
|
3857
|
+
var defaultGlobalCliSpawn = () => {
|
|
3858
|
+
const res = spawnSync("fabric", ["-v"], {
|
|
3859
|
+
encoding: "utf8",
|
|
3860
|
+
timeout: 5e3,
|
|
3861
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
3862
|
+
});
|
|
3863
|
+
return { error: res.error ?? null, status: res.status, stdout: res.stdout };
|
|
3864
|
+
};
|
|
3865
|
+
function inspectGlobalCliVersion(spawn = defaultGlobalCliSpawn) {
|
|
3866
|
+
let res;
|
|
3867
|
+
try {
|
|
3868
|
+
res = spawn();
|
|
3869
|
+
} catch (e) {
|
|
3870
|
+
return { status: "unparseable", detail: e instanceof Error ? e.message : String(e) };
|
|
3871
|
+
}
|
|
3872
|
+
if (res.error) {
|
|
3873
|
+
if (res.error.code === "ENOENT") {
|
|
3874
|
+
return { status: "not-found" };
|
|
3875
|
+
}
|
|
3876
|
+
return { status: "unparseable", detail: res.error.message };
|
|
3877
|
+
}
|
|
3878
|
+
if (res.status !== 0) {
|
|
3879
|
+
return { status: "unparseable", detail: `exit ${res.status ?? "?"}` };
|
|
3880
|
+
}
|
|
3881
|
+
const raw = (res.stdout ?? "").trim();
|
|
3882
|
+
const m = /(\d+)\.(\d+)\.(\d+)-rc\.(\d+)/.exec(raw);
|
|
3883
|
+
if (!m) {
|
|
3884
|
+
return { status: "unparseable", detail: raw.slice(0, 80) };
|
|
3885
|
+
}
|
|
3886
|
+
const version = `${m[1]}.${m[2]}.${m[3]}-rc.${m[4]}`;
|
|
3887
|
+
const observedRc = Number(m[4]);
|
|
3888
|
+
const minMatch = /-rc\.(\d+)/.exec(MIN_SUPPORTED_GLOBAL_CLI_VERSION);
|
|
3889
|
+
const minRc = minMatch ? Number(minMatch[1]) : 0;
|
|
3890
|
+
if (observedRc < minRc) {
|
|
3891
|
+
return { status: "outdated", version, minVersion: MIN_SUPPORTED_GLOBAL_CLI_VERSION };
|
|
3892
|
+
}
|
|
3893
|
+
return { status: "ok", version };
|
|
3894
|
+
}
|
|
3895
|
+
function createGlobalCliVersionCheck(t, inspection) {
|
|
3896
|
+
if (inspection.status === "ok") {
|
|
3897
|
+
return okCheck(
|
|
3898
|
+
t("doctor.check.global_cli_outdated.name"),
|
|
3899
|
+
t("doctor.check.global_cli_outdated.ok", { version: inspection.version })
|
|
3900
|
+
);
|
|
3901
|
+
}
|
|
3902
|
+
if (inspection.status === "outdated") {
|
|
3903
|
+
return issueCheck(
|
|
3904
|
+
t("doctor.check.global_cli_outdated.name"),
|
|
3905
|
+
"error",
|
|
3906
|
+
"manual_error",
|
|
3907
|
+
"global_cli_outdated",
|
|
3908
|
+
t("doctor.check.global_cli_outdated.message.outdated", {
|
|
3909
|
+
version: inspection.version,
|
|
3910
|
+
minVersion: inspection.minVersion
|
|
3911
|
+
}),
|
|
3912
|
+
t("doctor.check.global_cli_outdated.remediation")
|
|
3913
|
+
);
|
|
3914
|
+
}
|
|
3915
|
+
if (inspection.status === "not-found") {
|
|
3916
|
+
return issueCheck(
|
|
3917
|
+
t("doctor.check.global_cli_outdated.name"),
|
|
3918
|
+
"warn",
|
|
3919
|
+
"warning",
|
|
3920
|
+
"global_cli_not_found",
|
|
3921
|
+
t("doctor.check.global_cli_outdated.message.not_found"),
|
|
3922
|
+
t("doctor.check.global_cli_outdated.remediation")
|
|
3923
|
+
);
|
|
3924
|
+
}
|
|
3925
|
+
return issueCheck(
|
|
3926
|
+
t("doctor.check.global_cli_outdated.name"),
|
|
3927
|
+
"warn",
|
|
3928
|
+
"warning",
|
|
3929
|
+
"global_cli_unparseable",
|
|
3930
|
+
t("doctor.check.global_cli_outdated.message.unparseable", { detail: inspection.detail }),
|
|
3931
|
+
t("doctor.check.global_cli_outdated.remediation")
|
|
3932
|
+
);
|
|
3933
|
+
}
|
|
3934
|
+
var KNOWLEDGE_SUMMARY_OPAQUE_THRESHOLD = 0.3;
|
|
3935
|
+
function inspectKnowledgeSummaryOpaque(meta) {
|
|
3936
|
+
const baseline = {
|
|
3937
|
+
totalWithDescription: 0,
|
|
3938
|
+
opaqueCount: 0,
|
|
3939
|
+
ratio: 0,
|
|
3940
|
+
threshold: KNOWLEDGE_SUMMARY_OPAQUE_THRESHOLD,
|
|
3941
|
+
opaqueSample: []
|
|
3942
|
+
};
|
|
3943
|
+
if (!meta.valid || meta.meta === null) {
|
|
3944
|
+
return { status: "skipped", ...baseline };
|
|
3945
|
+
}
|
|
3946
|
+
let total = 0;
|
|
3947
|
+
const opaqueIds = [];
|
|
3948
|
+
for (const node of Object.values(meta.meta.nodes)) {
|
|
3949
|
+
const description = node.description;
|
|
3950
|
+
const stableId = node.stable_id;
|
|
3951
|
+
if (!description || typeof stableId !== "string" || stableId.length === 0) {
|
|
3952
|
+
continue;
|
|
3953
|
+
}
|
|
3954
|
+
total += 1;
|
|
3955
|
+
const summary = (description.summary ?? "").trim();
|
|
3956
|
+
if (summary === stableId.trim()) {
|
|
3957
|
+
opaqueIds.push(stableId);
|
|
3958
|
+
}
|
|
3959
|
+
}
|
|
3960
|
+
if (total === 0) {
|
|
3961
|
+
return { status: "ok", ...baseline };
|
|
3962
|
+
}
|
|
3963
|
+
const ratio = opaqueIds.length / total;
|
|
3964
|
+
const status = ratio > KNOWLEDGE_SUMMARY_OPAQUE_THRESHOLD ? "warn" : "ok";
|
|
3965
|
+
return {
|
|
3966
|
+
status,
|
|
3967
|
+
totalWithDescription: total,
|
|
3968
|
+
opaqueCount: opaqueIds.length,
|
|
3969
|
+
ratio,
|
|
3970
|
+
threshold: KNOWLEDGE_SUMMARY_OPAQUE_THRESHOLD,
|
|
3971
|
+
opaqueSample: opaqueIds.slice(0, 5)
|
|
3972
|
+
};
|
|
3973
|
+
}
|
|
3974
|
+
function createKnowledgeSummaryOpaqueCheck(t, inspection) {
|
|
3975
|
+
if (inspection.status === "skipped") {
|
|
3976
|
+
return okCheck(
|
|
3977
|
+
t("doctor.check.knowledge_summary_opaque.name"),
|
|
3978
|
+
t("doctor.check.knowledge_summary_opaque.ok.skipped")
|
|
3979
|
+
);
|
|
3980
|
+
}
|
|
3981
|
+
if (inspection.status === "ok") {
|
|
3982
|
+
return okCheck(
|
|
3983
|
+
t("doctor.check.knowledge_summary_opaque.name"),
|
|
3984
|
+
t("doctor.check.knowledge_summary_opaque.ok", {
|
|
3985
|
+
opaque: String(inspection.opaqueCount),
|
|
3986
|
+
total: String(inspection.totalWithDescription)
|
|
3987
|
+
})
|
|
3988
|
+
);
|
|
3989
|
+
}
|
|
3990
|
+
const pct = Math.round(inspection.ratio * 1e3) / 10;
|
|
3991
|
+
return issueCheck(
|
|
3992
|
+
t("doctor.check.knowledge_summary_opaque.name"),
|
|
3993
|
+
"warn",
|
|
3994
|
+
"warning",
|
|
3995
|
+
"knowledge_summary_opaque",
|
|
3996
|
+
t("doctor.check.knowledge_summary_opaque.message.warn", {
|
|
3997
|
+
opaque: String(inspection.opaqueCount),
|
|
3998
|
+
total: String(inspection.totalWithDescription),
|
|
3999
|
+
pct: String(pct),
|
|
4000
|
+
threshold: String(Math.round(inspection.threshold * 100)),
|
|
4001
|
+
sample: inspection.opaqueSample.join(", ")
|
|
4002
|
+
}),
|
|
4003
|
+
t("doctor.check.knowledge_summary_opaque.remediation")
|
|
4004
|
+
);
|
|
4005
|
+
}
|
|
4006
|
+
function issueCheck(name, status, kind, code, message, actionHint, audience) {
|
|
3798
4007
|
return {
|
|
3799
4008
|
name,
|
|
3800
4009
|
status,
|
|
@@ -3802,7 +4011,8 @@ function issueCheck(name, status, kind, code, message, actionHint) {
|
|
|
3802
4011
|
code,
|
|
3803
4012
|
fixable: kind === "fixable_error",
|
|
3804
4013
|
message,
|
|
3805
|
-
actionHint
|
|
4014
|
+
actionHint,
|
|
4015
|
+
audience
|
|
3806
4016
|
};
|
|
3807
4017
|
}
|
|
3808
4018
|
function collectIssues(checks, kind) {
|
|
@@ -3810,7 +4020,8 @@ function collectIssues(checks, kind) {
|
|
|
3810
4020
|
code: check.code ?? check.name,
|
|
3811
4021
|
name: check.name,
|
|
3812
4022
|
message: check.message,
|
|
3813
|
-
actionHint: check.actionHint
|
|
4023
|
+
actionHint: check.actionHint,
|
|
4024
|
+
audience: check.audience
|
|
3814
4025
|
}));
|
|
3815
4026
|
}
|
|
3816
4027
|
function findIssue(issues, code) {
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
readEventLedger,
|
|
15
15
|
runDoctorReport,
|
|
16
16
|
sha256
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-DRIWYXFP.js";
|
|
18
18
|
|
|
19
19
|
// src/http.ts
|
|
20
20
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
@@ -944,7 +944,7 @@ function toPosixPath(path) {
|
|
|
944
944
|
function buildRecommendations(input) {
|
|
945
945
|
const recommendations = [];
|
|
946
946
|
if (!input.hasExistingFabric) {
|
|
947
|
-
recommendations.push("L0: Run `
|
|
947
|
+
recommendations.push("L0: Run `fabric install` to scaffold the .fabric/ knowledge layout (decisions, pitfalls, guidelines, models, processes).");
|
|
948
948
|
}
|
|
949
949
|
if (input.readmeQuality === "stub") {
|
|
950
950
|
recommendations.push("L0: Expand README.md before promoting project facts into Fabric knowledge entries.");
|
|
@@ -980,7 +980,7 @@ function createLoopbackDenyMiddleware() {
|
|
|
980
980
|
res,
|
|
981
981
|
401,
|
|
982
982
|
"UNAUTHORIZED",
|
|
983
|
-
"FABRIC_AUTH_TOKEN is not set. Either export FABRIC_AUTH_TOKEN=<secret> before running `
|
|
983
|
+
"FABRIC_AUTH_TOKEN is not set. Either export FABRIC_AUTH_TOKEN=<secret> before running `fabric serve`, or pass `--allow-loopback-no-auth` to explicitly opt in to unauthenticated loopback access (security risk)."
|
|
984
984
|
);
|
|
985
985
|
};
|
|
986
986
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -32,6 +32,7 @@ type DoctorCheck = {
|
|
|
32
32
|
code?: string;
|
|
33
33
|
fixable?: boolean;
|
|
34
34
|
actionHint?: string;
|
|
35
|
+
audience?: "user" | "maintainer";
|
|
35
36
|
};
|
|
36
37
|
type DoctorIssue = {
|
|
37
38
|
code: string;
|
|
@@ -39,6 +40,7 @@ type DoctorIssue = {
|
|
|
39
40
|
message: string;
|
|
40
41
|
path?: string;
|
|
41
42
|
actionHint?: string;
|
|
43
|
+
audience?: "user" | "maintainer";
|
|
42
44
|
};
|
|
43
45
|
type DoctorPayloadLimits = {
|
|
44
46
|
warn_bytes: number;
|
package/dist/index.js
CHANGED
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
sha256,
|
|
40
40
|
stableStringify,
|
|
41
41
|
writeKnowledgeMeta
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-DRIWYXFP.js";
|
|
43
43
|
|
|
44
44
|
// src/index.ts
|
|
45
45
|
import { existsSync as existsSync3 } from "fs";
|
|
@@ -59,13 +59,13 @@ function gateWarning(result) {
|
|
|
59
59
|
return {
|
|
60
60
|
code: "meta_stale",
|
|
61
61
|
file: "<response>",
|
|
62
|
-
action_hint: "Initial reconcile still pending; results may use cached meta. Retry shortly or run `
|
|
62
|
+
action_hint: "Initial reconcile still pending; results may use cached meta. Retry shortly or run `fabric doctor --fix`."
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
65
|
return {
|
|
66
66
|
code: "reconcile_failed",
|
|
67
67
|
file: "<response>",
|
|
68
|
-
action_hint: "Reconcile failed at startup; run `
|
|
68
|
+
action_hint: "Reconcile failed at startup; run `fabric doctor --fix` and restart the MCP server."
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
71
|
var state = {
|
|
@@ -297,7 +297,7 @@ async function extractKnowledge(projectRoot, input) {
|
|
|
297
297
|
// v2.0.0-rc.23 TASK-014 (F8c): optional S5 onboard-slot tag. Same emit
|
|
298
298
|
// discipline as the four a-C1 fields — bare YAML line iff caller-supplied,
|
|
299
299
|
// never in the idempotency_key hash. fabric-archive's first-run phase is
|
|
300
|
-
// the only producer; downstream `
|
|
300
|
+
// the only producer; downstream `fabric onboard-coverage` walks frontmatter
|
|
301
301
|
// looking for this exact key.
|
|
302
302
|
onboardSlot: input.onboard_slot
|
|
303
303
|
});
|
|
@@ -2091,7 +2091,7 @@ function formatPreexistingRootMessage(projectRoot) {
|
|
|
2091
2091
|
function createFabricServer(tracker) {
|
|
2092
2092
|
const server = new McpServer({
|
|
2093
2093
|
name: "fabric-knowledge-server",
|
|
2094
|
-
version: "2.0.0-rc.
|
|
2094
|
+
version: "2.0.0-rc.35"
|
|
2095
2095
|
});
|
|
2096
2096
|
registerPlanContext(server, tracker);
|
|
2097
2097
|
registerKnowledgeSections(server, tracker);
|
|
@@ -2199,7 +2199,7 @@ function createShutdownHandler(deps) {
|
|
|
2199
2199
|
};
|
|
2200
2200
|
}
|
|
2201
2201
|
async function startHttpServer(options) {
|
|
2202
|
-
const { createFabricHttpApp } = await import("./http-
|
|
2202
|
+
const { createFabricHttpApp } = await import("./http-OHY2I6ZY.js");
|
|
2203
2203
|
const { port, projectRoot, host = "127.0.0.1", authToken, allowLoopbackNoAuth } = options;
|
|
2204
2204
|
const app = createFabricHttpApp({ projectRoot, host, authToken, allowLoopbackNoAuth });
|
|
2205
2205
|
return await new Promise((resolveServer, rejectServer) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fenglimg/fabric-server",
|
|
3
|
-
"version": "2.0.0-rc.
|
|
3
|
+
"version": "2.0.0-rc.35",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"express": "^5.2.1",
|
|
14
14
|
"minimatch": "^10.0.1",
|
|
15
15
|
"zod": "^3.25.0",
|
|
16
|
-
"@fenglimg/fabric-shared": "2.0.0-rc.
|
|
16
|
+
"@fenglimg/fabric-shared": "2.0.0-rc.35"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@types/express": "^5.0.6",
|