@fenglimg/fabric-server 2.0.0-rc.30 → 2.0.0-rc.33
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.
|
@@ -1691,6 +1691,27 @@ function readSelectionTokenTtlMs(projectRoot) {
|
|
|
1691
1691
|
return void 0;
|
|
1692
1692
|
}
|
|
1693
1693
|
}
|
|
1694
|
+
function readOrphanDemoteThresholdDays(projectRoot) {
|
|
1695
|
+
try {
|
|
1696
|
+
const cfg = readFabricConfig(projectRoot);
|
|
1697
|
+
const out = {};
|
|
1698
|
+
const validate = (v) => {
|
|
1699
|
+
if (typeof v !== "number" || !Number.isFinite(v) || v < 1 || v > 3650 || !Number.isInteger(v)) {
|
|
1700
|
+
return void 0;
|
|
1701
|
+
}
|
|
1702
|
+
return v;
|
|
1703
|
+
};
|
|
1704
|
+
const s = validate(cfg.orphan_demote_stable_days);
|
|
1705
|
+
if (s !== void 0) out.stable = s;
|
|
1706
|
+
const e = validate(cfg.orphan_demote_endorsed_days);
|
|
1707
|
+
if (e !== void 0) out.endorsed = e;
|
|
1708
|
+
const d = validate(cfg.orphan_demote_draft_days);
|
|
1709
|
+
if (d !== void 0) out.draft = d;
|
|
1710
|
+
return out;
|
|
1711
|
+
} catch {
|
|
1712
|
+
return {};
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1694
1715
|
|
|
1695
1716
|
// src/services/doctor.ts
|
|
1696
1717
|
import { atomicWriteJson as atomicWriteJson2, atomicWriteText as atomicWriteText4 } from "@fenglimg/fabric-shared/node/atomic-write";
|
|
@@ -1804,6 +1825,10 @@ async function runDoctorReport(target) {
|
|
|
1804
1825
|
]);
|
|
1805
1826
|
const mcpConfigInWrongFile = inspectMcpConfigInWrongFile(projectRoot);
|
|
1806
1827
|
const skillRefMirror = inspectSkillRefMirror(projectRoot);
|
|
1828
|
+
const skillTokenBudget = inspectSkillTokenBudget(projectRoot);
|
|
1829
|
+
const skillDescription = inspectSkillDescription(projectRoot);
|
|
1830
|
+
const citeGoodhart = await inspectCiteGoodhart(projectRoot);
|
|
1831
|
+
const draftBacklog = inspectDraftBacklog(projectRoot);
|
|
1807
1832
|
const metaManuallyDiverged = await inspectMetaManuallyDiverged(projectRoot);
|
|
1808
1833
|
const knowledgeDirUnindexed = inspectKnowledgeDirUnindexed(projectRoot, meta);
|
|
1809
1834
|
const knowledgeDirMissing = inspectKnowledgeDirMissing(projectRoot);
|
|
@@ -1830,6 +1855,8 @@ async function runDoctorReport(target) {
|
|
|
1830
1855
|
const relevanceFieldsMissing = inspectRelevanceFieldsMissing(projectRoot);
|
|
1831
1856
|
const skillMdYamlInvalid = inspectSkillMdYamlInvalid(projectRoot);
|
|
1832
1857
|
const onboardCoverage = inspectOnboardCoverage(projectRoot);
|
|
1858
|
+
const hooksWired = inspectHooksWired(projectRoot);
|
|
1859
|
+
const promoteLedgerInvariant = eventLedger.exists && eventLedger.writable && eventLedger.parseable ? await inspectPromoteLedgerInvariant(projectRoot) : null;
|
|
1833
1860
|
const checks = [
|
|
1834
1861
|
createBootstrapAnchorCheck(t, bootstrapAnchor),
|
|
1835
1862
|
// v2.0.0-rc.19 TASK-004: bootstrap marker migration check sits adjacent to
|
|
@@ -1871,6 +1898,10 @@ async function runDoctorReport(target) {
|
|
|
1871
1898
|
// contract between .claude/skills/<slug>/ref/ and .codex/skills/<slug>/
|
|
1872
1899
|
// ref/. warning severity — fab install restores parity.
|
|
1873
1900
|
createSkillRefMirrorCheck(t, skillRefMirror),
|
|
1901
|
+
createSkillTokenBudgetCheck(t, skillTokenBudget),
|
|
1902
|
+
createSkillDescriptionCheck(t, skillDescription),
|
|
1903
|
+
createCiteGoodhartCheck(t, citeGoodhart),
|
|
1904
|
+
createDraftBacklogCheck(t, draftBacklog),
|
|
1874
1905
|
createMcpConfigInWrongFileCheck(t, mcpConfigInWrongFile),
|
|
1875
1906
|
createMetaManuallyDivergedCheck(t, metaManuallyDiverged),
|
|
1876
1907
|
createKnowledgeDirUnindexedCheck(t, knowledgeDirUnindexed),
|
|
@@ -1924,6 +1955,12 @@ async function runDoctorReport(target) {
|
|
|
1924
1955
|
// first-run phase. Sits adjacent to Skill markdown YAML — both are
|
|
1925
1956
|
// Skill-adjacent advisories. --fix never mutates onboard state.
|
|
1926
1957
|
createOnboardCoverageCheck(t, onboardCoverage),
|
|
1958
|
+
// rc.31 BUG-M3/NEW-4: hooks_wired observability. Adjacent to onboard /
|
|
1959
|
+
// promote-ledger checks — all three are install/runtime-state advisories.
|
|
1960
|
+
createHooksWiredCheck(t, hooksWired),
|
|
1961
|
+
// rc.31 BUG-G2/G5: promote-ledger invariant. Sits adjacent to onboard
|
|
1962
|
+
// coverage — both are observability advisories built off events.jsonl.
|
|
1963
|
+
...promoteLedgerInvariant === null ? [] : [createPromoteLedgerInvariantCheck(t, promoteLedgerInvariant)],
|
|
1927
1964
|
createPreexistingRootFilesCheck(t, preexistingRootFiles)
|
|
1928
1965
|
// v2.0 / rc.2: `createLegacyClientPathCheck` removed. The schema now
|
|
1929
1966
|
// rejects retired clientPaths keys (windsurf/rooCode/geminiCLI) at Zod
|
|
@@ -2032,13 +2069,14 @@ async function runDoctorFix(target) {
|
|
|
2032
2069
|
const reconcileCodes = [
|
|
2033
2070
|
"agents_meta_missing",
|
|
2034
2071
|
"agents_meta_stale",
|
|
2072
|
+
"agents_meta_invalid",
|
|
2035
2073
|
"knowledge_test_index_missing",
|
|
2036
2074
|
"knowledge_test_index_stale",
|
|
2037
2075
|
"content_ref_missing",
|
|
2038
2076
|
"knowledge_dir_unindexed",
|
|
2039
2077
|
"meta_manually_diverged"
|
|
2040
2078
|
];
|
|
2041
|
-
if (before.fixable_errors.some((issue) => reconcileCodes.includes(issue.code)) || before.warnings.some((issue) => reconcileCodes.includes(issue.code))) {
|
|
2079
|
+
if (before.fixable_errors.some((issue) => reconcileCodes.includes(issue.code)) || before.warnings.some((issue) => reconcileCodes.includes(issue.code)) || before.manual_errors.some((issue) => reconcileCodes.includes(issue.code))) {
|
|
2042
2080
|
await reconcileKnowledge(projectRoot, { trigger: "doctor" });
|
|
2043
2081
|
for (const issue of before.fixable_errors.filter(
|
|
2044
2082
|
(candidate) => reconcileCodes.includes(candidate.code)
|
|
@@ -2050,6 +2088,11 @@ async function runDoctorFix(target) {
|
|
|
2050
2088
|
)) {
|
|
2051
2089
|
fixed.push(issue);
|
|
2052
2090
|
}
|
|
2091
|
+
for (const issue of before.manual_errors.filter(
|
|
2092
|
+
(candidate) => reconcileCodes.includes(candidate.code)
|
|
2093
|
+
)) {
|
|
2094
|
+
fixed.push(issue);
|
|
2095
|
+
}
|
|
2053
2096
|
contextCache.invalidate("meta_write", projectRoot);
|
|
2054
2097
|
await fixCounterDesync(projectRoot);
|
|
2055
2098
|
contextCache.invalidate("meta_write", projectRoot);
|
|
@@ -2735,6 +2778,184 @@ function inspectSkillRefMirror(projectRoot) {
|
|
|
2735
2778
|
if (driftedPaths.length === 0) return { status: "ok" };
|
|
2736
2779
|
return { status: "drift", driftedPaths };
|
|
2737
2780
|
}
|
|
2781
|
+
function inspectSkillTokenBudget(projectRoot) {
|
|
2782
|
+
const skillSlugs = ["fabric-archive", "fabric-review", "fabric-import"];
|
|
2783
|
+
const WARN_TOKENS = 5e3;
|
|
2784
|
+
const ERROR_TOKENS = 1e4;
|
|
2785
|
+
const overSize = [];
|
|
2786
|
+
let highestSeverity = "ok";
|
|
2787
|
+
for (const slug of skillSlugs) {
|
|
2788
|
+
const skillMdPath = join7(projectRoot, ".claude", "skills", slug, "SKILL.md");
|
|
2789
|
+
let body;
|
|
2790
|
+
try {
|
|
2791
|
+
body = readFileSync3(skillMdPath, "utf8");
|
|
2792
|
+
} catch {
|
|
2793
|
+
continue;
|
|
2794
|
+
}
|
|
2795
|
+
const tokens = Math.ceil(body.length / 3);
|
|
2796
|
+
if (tokens > ERROR_TOKENS) {
|
|
2797
|
+
overSize.push({ slug, tokens, severity: "error" });
|
|
2798
|
+
highestSeverity = "error";
|
|
2799
|
+
} else if (tokens > WARN_TOKENS) {
|
|
2800
|
+
overSize.push({ slug, tokens, severity: "warn" });
|
|
2801
|
+
if (highestSeverity !== "error") highestSeverity = "warn";
|
|
2802
|
+
}
|
|
2803
|
+
}
|
|
2804
|
+
return { status: highestSeverity, overSize };
|
|
2805
|
+
}
|
|
2806
|
+
function inspectSkillDescription(projectRoot) {
|
|
2807
|
+
const skillSlugs = ["fabric-archive", "fabric-review", "fabric-import"];
|
|
2808
|
+
const MAX_DESCRIPTION_TOKENS = 60;
|
|
2809
|
+
const issues = [];
|
|
2810
|
+
const CJK_PATTERN = /[㐀-䶿一-鿿]/;
|
|
2811
|
+
const ASCII_PATTERN = /[a-zA-Z]{2,}/;
|
|
2812
|
+
for (const slug of skillSlugs) {
|
|
2813
|
+
const skillMdPath = join7(projectRoot, ".claude", "skills", slug, "SKILL.md");
|
|
2814
|
+
let body;
|
|
2815
|
+
try {
|
|
2816
|
+
body = readFileSync3(skillMdPath, "utf8");
|
|
2817
|
+
} catch {
|
|
2818
|
+
continue;
|
|
2819
|
+
}
|
|
2820
|
+
const fmMatch = body.match(/^---\n([\s\S]*?)\n---/);
|
|
2821
|
+
if (!fmMatch) {
|
|
2822
|
+
issues.push({ slug, problem: "missing", detail: "no YAML frontmatter" });
|
|
2823
|
+
continue;
|
|
2824
|
+
}
|
|
2825
|
+
const descMatch = fmMatch[1].match(/^description:\s*(.+?)\s*$/m);
|
|
2826
|
+
if (!descMatch || descMatch[1].trim().length === 0) {
|
|
2827
|
+
issues.push({ slug, problem: "missing", detail: "description field empty or absent" });
|
|
2828
|
+
continue;
|
|
2829
|
+
}
|
|
2830
|
+
const description = descMatch[1].replace(/^["'](.+)["']$/, "$1");
|
|
2831
|
+
const tokens = Math.ceil(description.length / 3);
|
|
2832
|
+
if (tokens > MAX_DESCRIPTION_TOKENS) {
|
|
2833
|
+
issues.push({ slug, problem: "too_long", detail: `${tokens} tok (max ${MAX_DESCRIPTION_TOKENS})` });
|
|
2834
|
+
}
|
|
2835
|
+
if (!CJK_PATTERN.test(description)) {
|
|
2836
|
+
issues.push({ slug, problem: "no_cjk", detail: "no Chinese trigger phrase" });
|
|
2837
|
+
}
|
|
2838
|
+
if (!ASCII_PATTERN.test(description)) {
|
|
2839
|
+
issues.push({ slug, problem: "no_ascii", detail: "no English trigger phrase" });
|
|
2840
|
+
}
|
|
2841
|
+
}
|
|
2842
|
+
return { status: issues.length === 0 ? "ok" : "warn", issues };
|
|
2843
|
+
}
|
|
2844
|
+
async function inspectCiteGoodhart(projectRoot) {
|
|
2845
|
+
const WINDOW_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
2846
|
+
const RITUAL_REPEAT_THRESHOLD = 5;
|
|
2847
|
+
const DISMISSAL_ABUSE_RATIO = 0.6;
|
|
2848
|
+
const PLACEHOLDER_COUNT_THRESHOLD = 5;
|
|
2849
|
+
const cutoffMs = Date.now() - WINDOW_MS;
|
|
2850
|
+
const fired = [];
|
|
2851
|
+
let events = [];
|
|
2852
|
+
try {
|
|
2853
|
+
const result = await readEventLedger(projectRoot);
|
|
2854
|
+
events = result.events;
|
|
2855
|
+
} catch {
|
|
2856
|
+
return { status: "ok", fired: [] };
|
|
2857
|
+
}
|
|
2858
|
+
const turns = events.filter(
|
|
2859
|
+
(e) => {
|
|
2860
|
+
if (e.event_type !== "assistant_turn_observed") return false;
|
|
2861
|
+
const ts = Date.parse(e.timestamp);
|
|
2862
|
+
return Number.isFinite(ts) && ts >= cutoffMs;
|
|
2863
|
+
}
|
|
2864
|
+
);
|
|
2865
|
+
if (turns.length === 0) {
|
|
2866
|
+
return { status: "ok", fired: [] };
|
|
2867
|
+
}
|
|
2868
|
+
const recalledCount = /* @__PURE__ */ new Map();
|
|
2869
|
+
for (const turn of turns) {
|
|
2870
|
+
for (let i = 0; i < turn.cite_ids.length; i += 1) {
|
|
2871
|
+
if (turn.cite_tags[i] === "recalled") {
|
|
2872
|
+
const key = turn.cite_ids[i];
|
|
2873
|
+
recalledCount.set(key, (recalledCount.get(key) ?? 0) + 1);
|
|
2874
|
+
}
|
|
2875
|
+
}
|
|
2876
|
+
}
|
|
2877
|
+
for (const [id, n] of recalledCount.entries()) {
|
|
2878
|
+
if (n > RITUAL_REPEAT_THRESHOLD) {
|
|
2879
|
+
fired.push({ pattern: "G1", detail: `${id} repeated as [recalled] ${n}x in 7d` });
|
|
2880
|
+
break;
|
|
2881
|
+
}
|
|
2882
|
+
}
|
|
2883
|
+
let recalledTotal = 0;
|
|
2884
|
+
let recalledWithSkip = 0;
|
|
2885
|
+
for (const turn of turns) {
|
|
2886
|
+
for (let i = 0; i < turn.cite_ids.length; i += 1) {
|
|
2887
|
+
if (turn.cite_tags[i] !== "recalled") continue;
|
|
2888
|
+
recalledTotal += 1;
|
|
2889
|
+
const commitment = turn.cite_commitments[i];
|
|
2890
|
+
if (commitment && typeof commitment.skip_reason === "string" && commitment.skip_reason.length > 0) {
|
|
2891
|
+
recalledWithSkip += 1;
|
|
2892
|
+
}
|
|
2893
|
+
}
|
|
2894
|
+
}
|
|
2895
|
+
if (recalledTotal >= 5 && recalledWithSkip / recalledTotal > DISMISSAL_ABUSE_RATIO) {
|
|
2896
|
+
fired.push({
|
|
2897
|
+
pattern: "G2",
|
|
2898
|
+
detail: `${recalledWithSkip}/${recalledTotal} recalled cites used skip:<reason> (> ${Math.round(DISMISSAL_ABUSE_RATIO * 100)}%)`
|
|
2899
|
+
});
|
|
2900
|
+
}
|
|
2901
|
+
let chainedFromMisuse = 0;
|
|
2902
|
+
for (const turn of turns) {
|
|
2903
|
+
for (let i = 0; i < turn.cite_ids.length; i += 1) {
|
|
2904
|
+
if (turn.cite_tags[i] !== "chained-from") continue;
|
|
2905
|
+
const commitment = turn.cite_commitments[i];
|
|
2906
|
+
if (!commitment) {
|
|
2907
|
+
chainedFromMisuse += 1;
|
|
2908
|
+
continue;
|
|
2909
|
+
}
|
|
2910
|
+
const hasOps = Array.isArray(commitment.operators) && commitment.operators.length > 0;
|
|
2911
|
+
const hasSkip = typeof commitment.skip_reason === "string" && commitment.skip_reason.length > 0;
|
|
2912
|
+
if (!hasOps && !hasSkip) chainedFromMisuse += 1;
|
|
2913
|
+
}
|
|
2914
|
+
}
|
|
2915
|
+
if (chainedFromMisuse > RITUAL_REPEAT_THRESHOLD) {
|
|
2916
|
+
fired.push({
|
|
2917
|
+
pattern: "G3",
|
|
2918
|
+
detail: `${chainedFromMisuse} chained-from cites with no commitment (operators=[] + skip_reason=null) in 7d`
|
|
2919
|
+
});
|
|
2920
|
+
}
|
|
2921
|
+
let placeholderCount = 0;
|
|
2922
|
+
for (const turn of turns) {
|
|
2923
|
+
if (turn.cite_tags.length === 0) continue;
|
|
2924
|
+
const allNone = turn.cite_tags.every((t) => t === "none");
|
|
2925
|
+
if (!allNone) continue;
|
|
2926
|
+
const raw = (turn.kb_line_raw ?? "").trim();
|
|
2927
|
+
if (raw === "KB: none" || raw.includes("[unspecified]")) {
|
|
2928
|
+
placeholderCount += 1;
|
|
2929
|
+
}
|
|
2930
|
+
}
|
|
2931
|
+
if (placeholderCount > PLACEHOLDER_COUNT_THRESHOLD) {
|
|
2932
|
+
fired.push({
|
|
2933
|
+
pattern: "G5",
|
|
2934
|
+
detail: `${placeholderCount} placeholder "KB: none" / "[unspecified]" cites in 7d`
|
|
2935
|
+
});
|
|
2936
|
+
}
|
|
2937
|
+
return { status: fired.length === 0 ? "ok" : "warn", fired };
|
|
2938
|
+
}
|
|
2939
|
+
function inspectDraftBacklog(projectRoot) {
|
|
2940
|
+
const DRAFT_BACKLOG_RATIO = 0.5;
|
|
2941
|
+
const MIN_TOTAL_FOR_RATIO = 10;
|
|
2942
|
+
let draftCount = 0;
|
|
2943
|
+
let totalCount = 0;
|
|
2944
|
+
for (const entry of iterateCanonicalEntries(projectRoot, /* @__PURE__ */ new Map())) {
|
|
2945
|
+
totalCount += 1;
|
|
2946
|
+
if (entry.maturity === "draft") draftCount += 1;
|
|
2947
|
+
}
|
|
2948
|
+
if (totalCount < MIN_TOTAL_FOR_RATIO) {
|
|
2949
|
+
return { status: "ok", draftCount, totalCount, ratio: 0 };
|
|
2950
|
+
}
|
|
2951
|
+
const ratio = draftCount / totalCount;
|
|
2952
|
+
return {
|
|
2953
|
+
status: ratio > DRAFT_BACKLOG_RATIO ? "warn" : "ok",
|
|
2954
|
+
draftCount,
|
|
2955
|
+
totalCount,
|
|
2956
|
+
ratio
|
|
2957
|
+
};
|
|
2958
|
+
}
|
|
2738
2959
|
async function inspectKnowledgeTestIndex(projectRoot) {
|
|
2739
2960
|
const path2 = join7(projectRoot, ".fabric", ".cache", "knowledge-test.index.json");
|
|
2740
2961
|
const built = await tryBuildRuleMeta(projectRoot);
|
|
@@ -3330,6 +3551,90 @@ function createSkillRefMirrorCheck(t, inspection) {
|
|
|
3330
3551
|
t("doctor.check.skill_ref_mirror.remediation")
|
|
3331
3552
|
);
|
|
3332
3553
|
}
|
|
3554
|
+
function createSkillTokenBudgetCheck(t, inspection) {
|
|
3555
|
+
if (inspection.status === "ok") {
|
|
3556
|
+
return okCheck(
|
|
3557
|
+
t("doctor.check.skill_token_budget.name"),
|
|
3558
|
+
t("doctor.check.skill_token_budget.ok")
|
|
3559
|
+
);
|
|
3560
|
+
}
|
|
3561
|
+
const list = inspection.overSize.map((s) => `${s.slug}=${s.tokens} tok (${s.severity})`).join(", ");
|
|
3562
|
+
const count = inspection.overSize.length;
|
|
3563
|
+
return issueCheck(
|
|
3564
|
+
t("doctor.check.skill_token_budget.name"),
|
|
3565
|
+
inspection.status,
|
|
3566
|
+
inspection.status === "error" ? "manual_error" : "warning",
|
|
3567
|
+
"skill_token_budget_exceeded",
|
|
3568
|
+
t(`doctor.check.skill_token_budget.message.${count === 1 ? "singular" : "plural"}`, {
|
|
3569
|
+
count: String(count),
|
|
3570
|
+
list
|
|
3571
|
+
}),
|
|
3572
|
+
t("doctor.check.skill_token_budget.remediation")
|
|
3573
|
+
);
|
|
3574
|
+
}
|
|
3575
|
+
function createDraftBacklogCheck(t, inspection) {
|
|
3576
|
+
if (inspection.status === "ok") {
|
|
3577
|
+
return okCheck(
|
|
3578
|
+
t("doctor.check.draft_backlog.name"),
|
|
3579
|
+
t("doctor.check.draft_backlog.ok")
|
|
3580
|
+
);
|
|
3581
|
+
}
|
|
3582
|
+
const pct = Math.round(inspection.ratio * 100);
|
|
3583
|
+
return issueCheck(
|
|
3584
|
+
t("doctor.check.draft_backlog.name"),
|
|
3585
|
+
"warn",
|
|
3586
|
+
"warning",
|
|
3587
|
+
"knowledge_draft_backlog",
|
|
3588
|
+
t("doctor.check.draft_backlog.message", {
|
|
3589
|
+
draftCount: String(inspection.draftCount),
|
|
3590
|
+
totalCount: String(inspection.totalCount),
|
|
3591
|
+
pct: String(pct)
|
|
3592
|
+
}),
|
|
3593
|
+
t("doctor.check.draft_backlog.remediation")
|
|
3594
|
+
);
|
|
3595
|
+
}
|
|
3596
|
+
function createCiteGoodhartCheck(t, inspection) {
|
|
3597
|
+
if (inspection.status === "ok") {
|
|
3598
|
+
return okCheck(
|
|
3599
|
+
t("doctor.check.cite_goodhart.name"),
|
|
3600
|
+
t("doctor.check.cite_goodhart.ok")
|
|
3601
|
+
);
|
|
3602
|
+
}
|
|
3603
|
+
const list = inspection.fired.map((f) => `${f.pattern}: ${f.detail}`).join("; ");
|
|
3604
|
+
const count = inspection.fired.length;
|
|
3605
|
+
return issueCheck(
|
|
3606
|
+
t("doctor.check.cite_goodhart.name"),
|
|
3607
|
+
"warn",
|
|
3608
|
+
"warning",
|
|
3609
|
+
"cite_goodhart_pattern",
|
|
3610
|
+
t(`doctor.check.cite_goodhart.message.${count === 1 ? "singular" : "plural"}`, {
|
|
3611
|
+
count: String(count),
|
|
3612
|
+
list
|
|
3613
|
+
}),
|
|
3614
|
+
t("doctor.check.cite_goodhart.remediation")
|
|
3615
|
+
);
|
|
3616
|
+
}
|
|
3617
|
+
function createSkillDescriptionCheck(t, inspection) {
|
|
3618
|
+
if (inspection.status === "ok") {
|
|
3619
|
+
return okCheck(
|
|
3620
|
+
t("doctor.check.skill_description.name"),
|
|
3621
|
+
t("doctor.check.skill_description.ok")
|
|
3622
|
+
);
|
|
3623
|
+
}
|
|
3624
|
+
const list = inspection.issues.map((i) => `${i.slug}: ${i.problem} (${i.detail})`).join("; ");
|
|
3625
|
+
const count = inspection.issues.length;
|
|
3626
|
+
return issueCheck(
|
|
3627
|
+
t("doctor.check.skill_description.name"),
|
|
3628
|
+
"warn",
|
|
3629
|
+
"warning",
|
|
3630
|
+
"skill_description_quality",
|
|
3631
|
+
t(`doctor.check.skill_description.message.${count === 1 ? "singular" : "plural"}`, {
|
|
3632
|
+
count: String(count),
|
|
3633
|
+
list
|
|
3634
|
+
}),
|
|
3635
|
+
t("doctor.check.skill_description.remediation")
|
|
3636
|
+
);
|
|
3637
|
+
}
|
|
3333
3638
|
function createEventLedgerPartialWriteCheck(t, ledger) {
|
|
3334
3639
|
if (!ledger.exists || !ledger.writable) {
|
|
3335
3640
|
return okCheck(
|
|
@@ -3358,6 +3663,137 @@ function createEventLedgerPartialWriteCheck(t, ledger) {
|
|
|
3358
3663
|
function okCheck(name, message) {
|
|
3359
3664
|
return { name, status: "ok", message };
|
|
3360
3665
|
}
|
|
3666
|
+
function inspectHooksWired(projectRoot) {
|
|
3667
|
+
const claudeDir = join7(projectRoot, ".claude");
|
|
3668
|
+
if (!existsSync5(claudeDir)) {
|
|
3669
|
+
return { status: "skipped", missingHooks: [] };
|
|
3670
|
+
}
|
|
3671
|
+
const settingsPath = join7(projectRoot, ".claude", "settings.json");
|
|
3672
|
+
if (!existsSync5(settingsPath)) {
|
|
3673
|
+
return { status: "missing-settings", missingHooks: [] };
|
|
3674
|
+
}
|
|
3675
|
+
let raw;
|
|
3676
|
+
try {
|
|
3677
|
+
raw = readFileSync3(settingsPath, "utf8");
|
|
3678
|
+
} catch {
|
|
3679
|
+
return { status: "missing-settings", missingHooks: [] };
|
|
3680
|
+
}
|
|
3681
|
+
let parsed;
|
|
3682
|
+
try {
|
|
3683
|
+
parsed = JSON.parse(raw);
|
|
3684
|
+
} catch {
|
|
3685
|
+
return { status: "missing-settings", missingHooks: [] };
|
|
3686
|
+
}
|
|
3687
|
+
const required = [
|
|
3688
|
+
{ event: "Stop", hookFile: "fabric-hint.cjs" },
|
|
3689
|
+
{ event: "SessionStart", hookFile: "knowledge-hint-broad.cjs" },
|
|
3690
|
+
{ event: "PreToolUse", hookFile: "knowledge-hint-narrow.cjs" }
|
|
3691
|
+
];
|
|
3692
|
+
const missing = [];
|
|
3693
|
+
const hooksSection = isRecord(parsed) ? parsed.hooks : void 0;
|
|
3694
|
+
for (const { event, hookFile } of required) {
|
|
3695
|
+
if (!isHookWiredForEvent(hooksSection, event, hookFile)) {
|
|
3696
|
+
missing.push(`${event}:${hookFile}`);
|
|
3697
|
+
}
|
|
3698
|
+
}
|
|
3699
|
+
if (missing.length === 0) {
|
|
3700
|
+
return { status: "ok", missingHooks: [] };
|
|
3701
|
+
}
|
|
3702
|
+
return { status: "incomplete", missingHooks: missing };
|
|
3703
|
+
}
|
|
3704
|
+
function isRecord(value) {
|
|
3705
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3706
|
+
}
|
|
3707
|
+
function isHookWiredForEvent(hooks, event, hookFile) {
|
|
3708
|
+
if (!isRecord(hooks)) return false;
|
|
3709
|
+
const eventEntries = hooks[event];
|
|
3710
|
+
if (!Array.isArray(eventEntries)) return false;
|
|
3711
|
+
for (const matcherBlock of eventEntries) {
|
|
3712
|
+
if (!isRecord(matcherBlock)) continue;
|
|
3713
|
+
const inner = matcherBlock.hooks;
|
|
3714
|
+
if (!Array.isArray(inner)) continue;
|
|
3715
|
+
for (const hookEntry of inner) {
|
|
3716
|
+
if (!isRecord(hookEntry)) continue;
|
|
3717
|
+
const cmd = hookEntry.command;
|
|
3718
|
+
if (typeof cmd === "string" && cmd.includes(hookFile)) {
|
|
3719
|
+
return true;
|
|
3720
|
+
}
|
|
3721
|
+
}
|
|
3722
|
+
}
|
|
3723
|
+
return false;
|
|
3724
|
+
}
|
|
3725
|
+
function createHooksWiredCheck(t, inspection) {
|
|
3726
|
+
if (inspection.status === "skipped") {
|
|
3727
|
+
return okCheck(
|
|
3728
|
+
t("doctor.check.hooks_wired.name"),
|
|
3729
|
+
t("doctor.check.hooks_wired.ok.skipped")
|
|
3730
|
+
);
|
|
3731
|
+
}
|
|
3732
|
+
if (inspection.status === "ok") {
|
|
3733
|
+
return okCheck(
|
|
3734
|
+
t("doctor.check.hooks_wired.name"),
|
|
3735
|
+
t("doctor.check.hooks_wired.ok.wired")
|
|
3736
|
+
);
|
|
3737
|
+
}
|
|
3738
|
+
if (inspection.status === "missing-settings") {
|
|
3739
|
+
return issueCheck(
|
|
3740
|
+
t("doctor.check.hooks_wired.name"),
|
|
3741
|
+
"warn",
|
|
3742
|
+
"warning",
|
|
3743
|
+
"hooks_wired_missing_settings",
|
|
3744
|
+
t("doctor.check.hooks_wired.message.missing_settings"),
|
|
3745
|
+
t("doctor.check.hooks_wired.remediation")
|
|
3746
|
+
);
|
|
3747
|
+
}
|
|
3748
|
+
return issueCheck(
|
|
3749
|
+
t("doctor.check.hooks_wired.name"),
|
|
3750
|
+
"warn",
|
|
3751
|
+
"warning",
|
|
3752
|
+
"hooks_wired_incomplete",
|
|
3753
|
+
t("doctor.check.hooks_wired.message.incomplete", {
|
|
3754
|
+
missing: inspection.missingHooks.join(", ")
|
|
3755
|
+
}),
|
|
3756
|
+
t("doctor.check.hooks_wired.remediation")
|
|
3757
|
+
);
|
|
3758
|
+
}
|
|
3759
|
+
async function inspectPromoteLedgerInvariant(projectRoot) {
|
|
3760
|
+
const [proposed, started, promoted] = await Promise.all([
|
|
3761
|
+
readEventLedger(projectRoot, { event_type: "knowledge_proposed" }),
|
|
3762
|
+
readEventLedger(projectRoot, { event_type: "knowledge_promote_started" }),
|
|
3763
|
+
readEventLedger(projectRoot, { event_type: "knowledge_promoted" })
|
|
3764
|
+
]);
|
|
3765
|
+
const proposedCount = proposed.events.length;
|
|
3766
|
+
const promoteStartedCount = started.events.length;
|
|
3767
|
+
const promotedCount = promoted.events.length;
|
|
3768
|
+
let violation = null;
|
|
3769
|
+
if (proposedCount < promoteStartedCount) {
|
|
3770
|
+
violation = "proposed-lt-started";
|
|
3771
|
+
} else if (promoteStartedCount < promotedCount) {
|
|
3772
|
+
violation = "started-lt-promoted";
|
|
3773
|
+
}
|
|
3774
|
+
return { proposedCount, promoteStartedCount, promotedCount, violation };
|
|
3775
|
+
}
|
|
3776
|
+
function createPromoteLedgerInvariantCheck(t, inspection) {
|
|
3777
|
+
const params = {
|
|
3778
|
+
proposed: String(inspection.proposedCount),
|
|
3779
|
+
started: String(inspection.promoteStartedCount),
|
|
3780
|
+
promoted: String(inspection.promotedCount)
|
|
3781
|
+
};
|
|
3782
|
+
if (inspection.violation === null) {
|
|
3783
|
+
return okCheck(
|
|
3784
|
+
t("doctor.check.promote_ledger_invariant.name"),
|
|
3785
|
+
t("doctor.check.promote_ledger_invariant.ok", params)
|
|
3786
|
+
);
|
|
3787
|
+
}
|
|
3788
|
+
return issueCheck(
|
|
3789
|
+
t("doctor.check.promote_ledger_invariant.name"),
|
|
3790
|
+
"warn",
|
|
3791
|
+
"warning",
|
|
3792
|
+
"promote_ledger_invariant_violated",
|
|
3793
|
+
t(`doctor.check.promote_ledger_invariant.message.${inspection.violation}`, params),
|
|
3794
|
+
t("doctor.check.promote_ledger_invariant.remediation")
|
|
3795
|
+
);
|
|
3796
|
+
}
|
|
3361
3797
|
function issueCheck(name, status, kind, code, message, actionHint) {
|
|
3362
3798
|
return {
|
|
3363
3799
|
name,
|
|
@@ -3804,13 +4240,24 @@ async function buildLastConsumedIndex(projectRoot) {
|
|
|
3804
4240
|
return map;
|
|
3805
4241
|
}
|
|
3806
4242
|
for (const event of events) {
|
|
3807
|
-
if (event.event_type !== "knowledge_consumed" && event.event_type !== "knowledge_demoted" && event.event_type !== "knowledge_archived") {
|
|
3808
|
-
continue;
|
|
3809
|
-
}
|
|
3810
4243
|
const ts = event.ts;
|
|
3811
4244
|
if (typeof ts !== "number" || !Number.isFinite(ts)) {
|
|
3812
4245
|
continue;
|
|
3813
4246
|
}
|
|
4247
|
+
if (event.event_type === "knowledge_sections_fetched") {
|
|
4248
|
+
const ids = Array.isArray(event.final_stable_ids) ? event.final_stable_ids : [];
|
|
4249
|
+
for (const stableId2 of ids) {
|
|
4250
|
+
if (typeof stableId2 !== "string" || stableId2.length === 0) continue;
|
|
4251
|
+
const prev2 = map.get(stableId2);
|
|
4252
|
+
if (prev2 === void 0 || ts > prev2) {
|
|
4253
|
+
map.set(stableId2, ts);
|
|
4254
|
+
}
|
|
4255
|
+
}
|
|
4256
|
+
continue;
|
|
4257
|
+
}
|
|
4258
|
+
if (event.event_type !== "knowledge_consumed" && event.event_type !== "knowledge_demoted" && event.event_type !== "knowledge_archived") {
|
|
4259
|
+
continue;
|
|
4260
|
+
}
|
|
3814
4261
|
const stableId = event.stable_id;
|
|
3815
4262
|
if (typeof stableId !== "string" || stableId.length === 0) {
|
|
3816
4263
|
continue;
|
|
@@ -3882,8 +4329,16 @@ async function buildLastActiveIndex(projectRoot) {
|
|
|
3882
4329
|
}
|
|
3883
4330
|
return map;
|
|
3884
4331
|
}
|
|
3885
|
-
function
|
|
3886
|
-
|
|
4332
|
+
function resolveMaturityThresholds(projectRoot) {
|
|
4333
|
+
const overrides = readOrphanDemoteThresholdDays(projectRoot);
|
|
4334
|
+
return {
|
|
4335
|
+
stable: overrides.stable ?? ORPHAN_DEMOTE_THRESHOLD_DAYS.stable,
|
|
4336
|
+
endorsed: overrides.endorsed ?? ORPHAN_DEMOTE_THRESHOLD_DAYS.endorsed,
|
|
4337
|
+
draft: overrides.draft ?? ORPHAN_DEMOTE_THRESHOLD_DAYS.draft
|
|
4338
|
+
};
|
|
4339
|
+
}
|
|
4340
|
+
function maturityThresholdDays(maturity, thresholds) {
|
|
4341
|
+
return (thresholds ?? ORPHAN_DEMOTE_THRESHOLD_DAYS)[maturity];
|
|
3887
4342
|
}
|
|
3888
4343
|
function nextLowerMaturity(current) {
|
|
3889
4344
|
if (current === "stable") return "endorsed";
|
|
@@ -3969,11 +4424,12 @@ function* iterateCanonicalEntries(projectRoot, lastActiveIndex) {
|
|
|
3969
4424
|
}
|
|
3970
4425
|
async function inspectOrphanDemote(projectRoot, now) {
|
|
3971
4426
|
const lastConsumedIndex = await buildLastConsumedIndex(projectRoot);
|
|
4427
|
+
const thresholds = resolveMaturityThresholds(projectRoot);
|
|
3972
4428
|
const candidates = [];
|
|
3973
4429
|
for (const entry of iterateCanonicalEntries(projectRoot, lastConsumedIndex)) {
|
|
3974
4430
|
const ageMs = entry.lastReferenceMs > 0 ? now - entry.lastReferenceMs : now;
|
|
3975
4431
|
const ageDays = Math.floor(ageMs / MS_PER_DAY);
|
|
3976
|
-
const threshold = maturityThresholdDays(entry.maturity);
|
|
4432
|
+
const threshold = maturityThresholdDays(entry.maturity, thresholds);
|
|
3977
4433
|
if (ageDays <= threshold) {
|
|
3978
4434
|
continue;
|
|
3979
4435
|
}
|
|
@@ -3986,7 +4442,7 @@ async function inspectOrphanDemote(projectRoot, now) {
|
|
|
3986
4442
|
});
|
|
3987
4443
|
}
|
|
3988
4444
|
candidates.sort((a, b) => a.path.localeCompare(b.path));
|
|
3989
|
-
return { candidates };
|
|
4445
|
+
return { candidates, thresholds };
|
|
3990
4446
|
}
|
|
3991
4447
|
async function inspectStaleArchive(projectRoot, now) {
|
|
3992
4448
|
const lastActiveIndex = await buildLastActiveIndex(projectRoot);
|
|
@@ -4307,9 +4763,9 @@ function createOrphanDemoteCheck(t, inspection) {
|
|
|
4307
4763
|
"knowledge_orphan_demote_required",
|
|
4308
4764
|
t(`doctor.check.orphan_demote.message.${count === 1 ? "singular" : "plural"}`, {
|
|
4309
4765
|
count: String(count),
|
|
4310
|
-
stableDays: String(
|
|
4311
|
-
endorsedDays: String(
|
|
4312
|
-
draftDays: String(
|
|
4766
|
+
stableDays: String(inspection.thresholds.stable),
|
|
4767
|
+
endorsedDays: String(inspection.thresholds.endorsed),
|
|
4768
|
+
draftDays: String(inspection.thresholds.draft),
|
|
4313
4769
|
detail
|
|
4314
4770
|
}),
|
|
4315
4771
|
t("doctor.check.orphan_demote.remediation")
|
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-Z23PAA5L.js";
|
|
43
43
|
|
|
44
44
|
// src/index.ts
|
|
45
45
|
import { existsSync as existsSync3 } from "fs";
|
|
@@ -333,6 +333,16 @@ function renderFreshEntry(args) {
|
|
|
333
333
|
`created_at: ${createdAt}`,
|
|
334
334
|
`source_sessions: [${args.sourceSessions.map((s) => JSON.stringify(s)).join(", ")}]`,
|
|
335
335
|
`proposed_reason: ${args.proposedReason}`,
|
|
336
|
+
// rc.31 BUG-2.9/2.1: persist the caller-supplied summary in frontmatter so
|
|
337
|
+
// knowledge-meta-builder.extractDescriptionFromFrontmatter picks it up
|
|
338
|
+
// directly. Without this, the meta-builder fell back to extractRule
|
|
339
|
+
// Description's h1-or-stable-id-or-placeholder synthesis (line ~944),
|
|
340
|
+
// which made user-visible description.summary == stable_id for any
|
|
341
|
+
// pending file whose body started with h2-only sections (`## Summary` is
|
|
342
|
+
// the canonical pending shape). The frontmatter `summary:` line is the
|
|
343
|
+
// canonical source-of-truth: `extractDescriptionFromFrontmatter` reads it
|
|
344
|
+
// before extractRuleDescription's fallback kicks in.
|
|
345
|
+
`summary: ${quoteRelevancePath(args.summary)}`,
|
|
336
346
|
"tags: []"
|
|
337
347
|
];
|
|
338
348
|
if (args.relevanceScope !== void 0) {
|
|
@@ -615,7 +625,11 @@ async function planContext(projectRoot, input) {
|
|
|
615
625
|
}
|
|
616
626
|
const stale = metaResult.degraded === true || input.client_hash !== void 0 && input.client_hash !== meta.revision;
|
|
617
627
|
const uniquePaths = dedupePaths(input.paths);
|
|
618
|
-
const
|
|
628
|
+
const scoringContext = {
|
|
629
|
+
nowMs: Date.now(),
|
|
630
|
+
targetPaths: input.target_paths ?? dedupePaths(input.paths)
|
|
631
|
+
};
|
|
632
|
+
const allDescriptions = buildDescriptionIndex(meta, scoringContext);
|
|
619
633
|
const relevanceTargetPaths = input.target_paths ?? uniquePaths;
|
|
620
634
|
const entries = uniquePaths.map((path) => {
|
|
621
635
|
const profile = buildRequirementProfile(path, input);
|
|
@@ -719,7 +733,7 @@ function buildRequirementProfile(path, input) {
|
|
|
719
733
|
detected_entities: input.detected_entities?.[normalizedPath] ?? input.detected_entities?.[path] ?? []
|
|
720
734
|
};
|
|
721
735
|
}
|
|
722
|
-
function buildDescriptionIndex(meta) {
|
|
736
|
+
function buildDescriptionIndex(meta, scoringContext) {
|
|
723
737
|
return Object.entries(meta.nodes).flatMap(([nodeId, node]) => {
|
|
724
738
|
const level = deriveAgentsMetaLayer(node.file);
|
|
725
739
|
const description = node.description ?? descriptionFromLegacyActivation(node.activation?.description);
|
|
@@ -744,7 +758,7 @@ function buildDescriptionIndex(meta) {
|
|
|
744
758
|
relevance_scope: description.relevance_scope,
|
|
745
759
|
relevance_paths: description.relevance_paths
|
|
746
760
|
}];
|
|
747
|
-
}).sort(compareDescriptionIndexItems);
|
|
761
|
+
}).sort((left, right) => compareDescriptionIndexItems(left, right, scoringContext));
|
|
748
762
|
}
|
|
749
763
|
function matchesAnyPath(globs, targetPaths) {
|
|
750
764
|
if (globs.length === 0) {
|
|
@@ -827,9 +841,68 @@ function dedupeDescriptionIndex(items) {
|
|
|
827
841
|
return true;
|
|
828
842
|
});
|
|
829
843
|
}
|
|
830
|
-
function compareDescriptionIndexItems(left, right) {
|
|
844
|
+
function compareDescriptionIndexItems(left, right, context) {
|
|
845
|
+
if (context !== void 0) {
|
|
846
|
+
const leftScore = scoreDescriptionItem(left, context.nowMs, context.targetPaths);
|
|
847
|
+
const rightScore = scoreDescriptionItem(right, context.nowMs, context.targetPaths);
|
|
848
|
+
if (leftScore !== rightScore) {
|
|
849
|
+
return rightScore - leftScore;
|
|
850
|
+
}
|
|
851
|
+
}
|
|
831
852
|
return left.stable_id.localeCompare(right.stable_id);
|
|
832
853
|
}
|
|
854
|
+
var RECENCY_WINDOW_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
855
|
+
var RECENCY_BOOST = 100;
|
|
856
|
+
var LOCALITY_SAME_FILE = 100;
|
|
857
|
+
var LOCALITY_SAME_DIR = 50;
|
|
858
|
+
var LOCALITY_SAME_PACKAGE = 25;
|
|
859
|
+
function scoreDescriptionItem(item, nowMs, targetPaths) {
|
|
860
|
+
let score = 0;
|
|
861
|
+
const createdAtRaw = item.description?.created_at;
|
|
862
|
+
if (typeof createdAtRaw === "string" && createdAtRaw.length > 0) {
|
|
863
|
+
const createdMs = Date.parse(createdAtRaw);
|
|
864
|
+
if (Number.isFinite(createdMs) && nowMs - createdMs < RECENCY_WINDOW_MS) {
|
|
865
|
+
score += RECENCY_BOOST;
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
if (targetPaths.length > 0) {
|
|
869
|
+
const relevancePaths = item.relevance_paths ?? item.description?.relevance_paths ?? [];
|
|
870
|
+
let best = 0;
|
|
871
|
+
for (const rp of relevancePaths) {
|
|
872
|
+
for (const tp of targetPaths) {
|
|
873
|
+
const tier = localityTier(rp, tp);
|
|
874
|
+
if (tier > best) best = tier;
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
score += best;
|
|
878
|
+
}
|
|
879
|
+
return score;
|
|
880
|
+
}
|
|
881
|
+
function localityTier(relevancePath, targetPath) {
|
|
882
|
+
if (relevancePath === targetPath) return LOCALITY_SAME_FILE;
|
|
883
|
+
const rpDir = dirnameOfPath(relevancePath);
|
|
884
|
+
const tpDir = dirnameOfPath(targetPath);
|
|
885
|
+
if (rpDir.length > 0 && rpDir === tpDir) return LOCALITY_SAME_DIR;
|
|
886
|
+
const rpPkg = packageRootOfPath(relevancePath);
|
|
887
|
+
const tpPkg = packageRootOfPath(targetPath);
|
|
888
|
+
if (rpPkg.length > 0 && rpPkg === tpPkg) return LOCALITY_SAME_PACKAGE;
|
|
889
|
+
return 0;
|
|
890
|
+
}
|
|
891
|
+
function dirnameOfPath(p) {
|
|
892
|
+
const idx = p.search(/[*?[]/);
|
|
893
|
+
if (idx >= 0) {
|
|
894
|
+
return p.slice(0, idx).replace(/\/$/, "");
|
|
895
|
+
}
|
|
896
|
+
const lastSlash = p.lastIndexOf("/");
|
|
897
|
+
return lastSlash >= 0 ? p.slice(0, lastSlash) : "";
|
|
898
|
+
}
|
|
899
|
+
function packageRootOfPath(p) {
|
|
900
|
+
const idx = p.search(/[*?[]/);
|
|
901
|
+
const stem = idx >= 0 ? p.slice(0, idx).replace(/\/$/, "") : p;
|
|
902
|
+
const segments = stem.split("/").filter(Boolean);
|
|
903
|
+
if (segments.length < 2) return "";
|
|
904
|
+
return segments.slice(0, 2).join("/");
|
|
905
|
+
}
|
|
833
906
|
|
|
834
907
|
// src/tools/plan-context.ts
|
|
835
908
|
function registerPlanContext(server, tracker) {
|
|
@@ -1195,6 +1268,11 @@ async function approveOne(projectRoot, pendingPath, allocator) {
|
|
|
1195
1268
|
return null;
|
|
1196
1269
|
}
|
|
1197
1270
|
const slug = basename(pendingPath).replace(/\.md$/u, "");
|
|
1271
|
+
await emitEventBestEffort2(projectRoot, {
|
|
1272
|
+
event_type: "knowledge_proposed",
|
|
1273
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1274
|
+
reason: `approve-synth:${slug}`
|
|
1275
|
+
});
|
|
1198
1276
|
await emitEventBestEffort2(projectRoot, {
|
|
1199
1277
|
event_type: "knowledge_promote_started",
|
|
1200
1278
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -2013,7 +2091,7 @@ function formatPreexistingRootMessage(projectRoot) {
|
|
|
2013
2091
|
function createFabricServer(tracker) {
|
|
2014
2092
|
const server = new McpServer({
|
|
2015
2093
|
name: "fabric-knowledge-server",
|
|
2016
|
-
version: "2.0.0-rc.
|
|
2094
|
+
version: "2.0.0-rc.33"
|
|
2017
2095
|
});
|
|
2018
2096
|
registerPlanContext(server, tracker);
|
|
2019
2097
|
registerKnowledgeSections(server, tracker);
|
|
@@ -2121,7 +2199,7 @@ function createShutdownHandler(deps) {
|
|
|
2121
2199
|
};
|
|
2122
2200
|
}
|
|
2123
2201
|
async function startHttpServer(options) {
|
|
2124
|
-
const { createFabricHttpApp } = await import("./http-
|
|
2202
|
+
const { createFabricHttpApp } = await import("./http-UK7PIXY5.js");
|
|
2125
2203
|
const { port, projectRoot, host = "127.0.0.1", authToken, allowLoopbackNoAuth } = options;
|
|
2126
2204
|
const app = createFabricHttpApp({ projectRoot, host, authToken, allowLoopbackNoAuth });
|
|
2127
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.33",
|
|
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.33"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@types/express": "^5.0.6",
|