@fenglimg/fabric-shared 2.2.0-rc.1 → 2.2.0-rc.3
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/dist/{chunk-JEXTOQVV.js → chunk-355LUDLW.js} +92 -8
- package/dist/{chunk-TX2XZ7AW.js → chunk-AFT7DB4P.js} +6 -5
- package/dist/{chunk-7TZ2PMVH.js → chunk-QSD4PN4W.js} +67 -3
- package/dist/{chunk-3SZRB42B.js → chunk-VW5QGPIN.js} +4 -0
- package/dist/errors/index.d.ts +4 -1
- package/dist/errors/index.js +5 -3
- package/dist/i18n/index.js +1 -1
- package/dist/{index-J3Xn5h2J.d.ts → index-Dm4IJWwB.d.ts} +24 -3
- package/dist/index.d.ts +263 -4
- package/dist/index.js +205 -14
- package/dist/node/atomic-write.js +17 -2
- package/dist/node/mcp-payload-guard.js +1 -1
- package/dist/schemas/api-contracts.d.ts +140 -18
- package/dist/schemas/api-contracts.js +1 -1
- package/dist/templates/bootstrap-canonical.d.ts +1 -1
- package/dist/templates/bootstrap-canonical.js +1 -1
- package/dist/types/index.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
normalizeLocale,
|
|
9
9
|
resolveFabricLocale,
|
|
10
10
|
zhCNMessages
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-QSD4PN4W.js";
|
|
12
12
|
import {
|
|
13
13
|
FabExtractKnowledgeInputSchema,
|
|
14
14
|
FabExtractKnowledgeInputShape,
|
|
@@ -56,7 +56,7 @@ import {
|
|
|
56
56
|
recallInputSchema,
|
|
57
57
|
recallOutputSchema,
|
|
58
58
|
structuredWarningSchema
|
|
59
|
-
} from "./chunk-
|
|
59
|
+
} from "./chunk-355LUDLW.js";
|
|
60
60
|
import {
|
|
61
61
|
BOOTSTRAP_CANONICAL,
|
|
62
62
|
BOOTSTRAP_MARKER_BEGIN,
|
|
@@ -65,7 +65,7 @@ import {
|
|
|
65
65
|
LEGACY_KB_MARKER_BEGIN,
|
|
66
66
|
LEGACY_KB_MARKER_END,
|
|
67
67
|
LEGACY_KB_REGEX
|
|
68
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-AFT7DB4P.js";
|
|
69
69
|
|
|
70
70
|
// src/schemas/agents-meta.ts
|
|
71
71
|
import { z } from "zod";
|
|
@@ -601,6 +601,30 @@ var fabricConfigSchema = z6.object({
|
|
|
601
601
|
// high-contract-criticality projects. Other strategies (time-based,
|
|
602
602
|
// token-budget) deferred to rc.35 per plan locked-decisions 2026-05-26.
|
|
603
603
|
cite_evict_interval: z6.number().int().min(0).optional().default(0),
|
|
604
|
+
// v2.1 ⑤ cite-redesign (P5): recall-based cite-accounting hook config. The
|
|
605
|
+
// rc.34 cite_evict_interval turn-counter above is superseded by the
|
|
606
|
+
// PreToolUse(Edit/Write) recall-aware nudge in cite-policy-evict.cjs; the old
|
|
607
|
+
// key is retained for back-compat (inert now that the hook moved off
|
|
608
|
+
// UserPromptSubmit). `cite_recall_nudge` is the master switch (default true =
|
|
609
|
+
// ON); set false to silence the "改前先 fab_recall" nudge entirely (mirrors
|
|
610
|
+
// the cite_evict_interval=0 opt-out convention). `cite_recall_window_minutes`
|
|
611
|
+
// bounds how far back an in-session fab_recall counts as "informing" the edit
|
|
612
|
+
// (default 30; 0 = unbounded).
|
|
613
|
+
cite_recall_nudge: z6.boolean().optional().default(true),
|
|
614
|
+
cite_recall_window_minutes: z6.number().int().min(0).optional().default(30),
|
|
615
|
+
// F2: glob exemptions for the cite nudge (cite-policy-evict.cjs). Edit paths
|
|
616
|
+
// matching any glob skip the "改前先 fab_recall" nudge — meta/orchestration
|
|
617
|
+
// files (e.g. `.workflow/` scratchpads) are not source the cite policy
|
|
618
|
+
// governs. MERGED with the hook's built-in [".workflow/**"] default; an
|
|
619
|
+
// omitted/empty value keeps just that default. `*` = within a path segment,
|
|
620
|
+
// `**` = across segments.
|
|
621
|
+
cite_nudge_ignore_globs: z6.array(z6.string()).optional(),
|
|
622
|
+
// v2.1 ④ conflict-detection (P4): bm25 content-similarity threshold (0..1)
|
|
623
|
+
// for the knowledge-conflict lint (`fabric doctor --lint-conflicts`). A
|
|
624
|
+
// same-(type,layer) pair whose normalized bm25 similarity reaches this floor
|
|
625
|
+
// is surfaced as a candidate (possible duplicate OR conflict). Conservative
|
|
626
|
+
// default 0.5 — raise to reduce noise, lower to catch looser pairs.
|
|
627
|
+
conflict_lint_similarity_threshold: z6.number().min(0).max(1).optional().default(0.5),
|
|
604
628
|
// v2.0.0-rc.22 Scope A T3: sliding-window retention (in days) for the
|
|
605
629
|
// event ledger rotation primitive (`rotateEventLedgerIfNeeded`). Lines
|
|
606
630
|
// whose `ts` is older than `now - fabric_event_retention_days * 86_400_000`
|
|
@@ -703,13 +727,25 @@ var fabricConfigSchema = z6.object({
|
|
|
703
727
|
// 0..168 (one week).
|
|
704
728
|
hint_narrow_cooldown_hours: z6.number().int().min(0).max(168).optional().default(0),
|
|
705
729
|
// v2.0.0-rc.33 W4-B3 (T5 P2): per-maturity inactivity thresholds (days)
|
|
706
|
-
// driving orphan_demote. Hardcoded at
|
|
730
|
+
// driving orphan_demote. Hardcoded at proven=90/verified=30/draft=14 in
|
|
707
731
|
// rc.32; chatty workspaces want them tighter, slow ones want them looser.
|
|
708
732
|
// Each field optional; absent → defaults inside doctor.ts apply. Ranges
|
|
709
733
|
// chosen so a typo can't accidentally disable the lint (min 1).
|
|
734
|
+
//
|
|
735
|
+
// v2.2 W3-T5 (F-MATURITY-ENDORSED): the canonical maturity enum is
|
|
736
|
+
// draft/verified/proven (KT-DEC-0005), but these threshold keys historically
|
|
737
|
+
// used the legacy stable/endorsed vocabulary — a config authored with the
|
|
738
|
+
// canonical names could never tune the proven/verified tiers. The canonical
|
|
739
|
+
// keys below are the preferred form; the legacy keys are retained for
|
|
740
|
+
// backward-compat (a config written before this fix keeps working). The
|
|
741
|
+
// loader maps stable→proven / endorsed→verified, canonical taking precedence.
|
|
742
|
+
orphan_demote_proven_days: z6.number().int().min(1).max(3650).optional(),
|
|
743
|
+
orphan_demote_verified_days: z6.number().int().min(1).max(3650).optional(),
|
|
744
|
+
orphan_demote_draft_days: z6.number().int().min(1).max(3650).optional(),
|
|
745
|
+
// Legacy aliases (deprecated; map to proven/verified). Kept so existing
|
|
746
|
+
// configs do not silently lose their tuning.
|
|
710
747
|
orphan_demote_stable_days: z6.number().int().min(1).max(3650).optional(),
|
|
711
748
|
orphan_demote_endorsed_days: z6.number().int().min(1).max(3650).optional(),
|
|
712
|
-
orphan_demote_draft_days: z6.number().int().min(1).max(3650).optional(),
|
|
713
749
|
// v2.0.0-rc.33 W4-A3 (T4 P2): per-entry summary truncation length used by
|
|
714
750
|
// knowledge-hint-{broad,narrow}.cjs. Hard-coded at 80 chars in rc.32 — too
|
|
715
751
|
// short for entries with parameterized summaries (e.g. "Use bcrypt with
|
|
@@ -766,7 +802,25 @@ var fabricConfigSchema = z6.object({
|
|
|
766
802
|
// ENFORCES the "vectors supplement, never override lexical relevance"
|
|
767
803
|
// invariant in the schema rather than leaving it to a comment (W2-REVIEW codex
|
|
768
804
|
// MED-4). Range 0..49; default 30.
|
|
769
|
-
embed_weight: z6.number().int().min(0).max(49).optional().default(30)
|
|
805
|
+
embed_weight: z6.number().int().min(0).max(49).optional().default(30),
|
|
806
|
+
// v2.1 ③ vector-chinese-model (P3): which fastembed model to load. The prior
|
|
807
|
+
// code pinned fastembed's English default (bge-small-en-v1.5) — wrong for the
|
|
808
|
+
// Chinese-heavy zh-CN-hybrid KB. Values are the fastembed@2.x EmbeddingModel
|
|
809
|
+
// enum strings. Default `fast-bge-small-zh-v1.5` (BGESmallZH): light, fast,
|
|
810
|
+
// Chinese-capable (bm25 already covers English/code tokens; the vector term
|
|
811
|
+
// supplements Chinese semantics). `fast-multilingual-e5-large` (MLE5Large) is
|
|
812
|
+
// available for full multilingual recall at a ~1GB download + slower CPU cost.
|
|
813
|
+
// (V1 research: fastembed@2.1.0 has NO multilingual-e5-SMALL — the originally
|
|
814
|
+
// planned pin — so bge-small-zh is the light Chinese choice.)
|
|
815
|
+
embed_model: z6.enum([
|
|
816
|
+
"fast-bge-small-zh-v1.5",
|
|
817
|
+
"fast-multilingual-e5-large",
|
|
818
|
+
"fast-bge-small-en-v1.5",
|
|
819
|
+
"fast-bge-small-en",
|
|
820
|
+
"fast-bge-base-en-v1.5",
|
|
821
|
+
"fast-bge-base-en",
|
|
822
|
+
"fast-all-MiniLM-L6-v2"
|
|
823
|
+
]).optional().default("fast-bge-small-zh-v1.5")
|
|
770
824
|
});
|
|
771
825
|
|
|
772
826
|
// src/schemas/fabric-config-introspect.ts
|
|
@@ -1503,6 +1557,76 @@ function aggregatePendingAcrossStores(stores) {
|
|
|
1503
1557
|
);
|
|
1504
1558
|
}
|
|
1505
1559
|
|
|
1560
|
+
// src/store/global-config-io.ts
|
|
1561
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
1562
|
+
import { homedir } from "os";
|
|
1563
|
+
import { join as join3 } from "path";
|
|
1564
|
+
function resolveGlobalRoot() {
|
|
1565
|
+
return join3(process.env.FABRIC_HOME ?? homedir(), ".fabric");
|
|
1566
|
+
}
|
|
1567
|
+
function globalConfigPath(globalRoot = resolveGlobalRoot()) {
|
|
1568
|
+
return join3(globalRoot, "fabric-global.json");
|
|
1569
|
+
}
|
|
1570
|
+
function loadGlobalConfig(globalRoot = resolveGlobalRoot()) {
|
|
1571
|
+
const path = globalConfigPath(globalRoot);
|
|
1572
|
+
if (!existsSync3(path)) {
|
|
1573
|
+
return null;
|
|
1574
|
+
}
|
|
1575
|
+
return globalConfigSchema.parse(JSON.parse(readFileSync2(path, "utf8")));
|
|
1576
|
+
}
|
|
1577
|
+
function saveGlobalConfig(config, globalRoot = resolveGlobalRoot()) {
|
|
1578
|
+
const validated = globalConfigSchema.parse(config);
|
|
1579
|
+
mkdirSync2(globalRoot, { recursive: true });
|
|
1580
|
+
writeFileSync2(globalConfigPath(globalRoot), `${JSON.stringify(validated, null, 2)}
|
|
1581
|
+
`, "utf8");
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
// src/store/project-config-io.ts
|
|
1585
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
1586
|
+
import { join as join4 } from "path";
|
|
1587
|
+
function projectConfigPath(projectRoot) {
|
|
1588
|
+
return join4(projectRoot, ".fabric", "fabric-config.json");
|
|
1589
|
+
}
|
|
1590
|
+
function loadProjectConfig(projectRoot) {
|
|
1591
|
+
const path = projectConfigPath(projectRoot);
|
|
1592
|
+
if (!existsSync4(path)) {
|
|
1593
|
+
return null;
|
|
1594
|
+
}
|
|
1595
|
+
return fabricConfigSchema.parse(JSON.parse(readFileSync3(path, "utf8")));
|
|
1596
|
+
}
|
|
1597
|
+
function saveProjectConfig(config, projectRoot) {
|
|
1598
|
+
const validated = fabricConfigSchema.parse(config);
|
|
1599
|
+
mkdirSync3(join4(projectRoot, ".fabric"), { recursive: true });
|
|
1600
|
+
writeFileSync3(projectConfigPath(projectRoot), `${JSON.stringify(validated, null, 2)}
|
|
1601
|
+
`, "utf8");
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
// src/store/resolve-input.ts
|
|
1605
|
+
function buildStoreResolveInput(projectRoot, globalRoot = resolveGlobalRoot()) {
|
|
1606
|
+
const global = loadGlobalConfig(globalRoot);
|
|
1607
|
+
if (global === null) {
|
|
1608
|
+
return null;
|
|
1609
|
+
}
|
|
1610
|
+
const project = loadProjectConfig(projectRoot);
|
|
1611
|
+
return {
|
|
1612
|
+
uid: global.uid,
|
|
1613
|
+
mountedStores: global.stores.map((s) => ({
|
|
1614
|
+
store_uuid: s.store_uuid,
|
|
1615
|
+
alias: s.alias,
|
|
1616
|
+
...s.remote === void 0 ? {} : { remote: s.remote },
|
|
1617
|
+
writable: s.writable ?? true,
|
|
1618
|
+
personal: s.personal ?? false
|
|
1619
|
+
})),
|
|
1620
|
+
requiredStores: (project?.required_stores ?? []).map(
|
|
1621
|
+
(r) => ({
|
|
1622
|
+
id: r.id,
|
|
1623
|
+
...r.suggested_remote === void 0 ? {} : { suggested_remote: r.suggested_remote }
|
|
1624
|
+
})
|
|
1625
|
+
),
|
|
1626
|
+
...project?.active_write_store === void 0 ? {} : { activeWriteAlias: project.active_write_store }
|
|
1627
|
+
};
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1506
1630
|
// src/store/secret-scan.ts
|
|
1507
1631
|
var SECRET_RULES = [
|
|
1508
1632
|
{ rule: "aws-access-key-id", re: /\bAKIA[0-9A-Z]{16}\b/ },
|
|
@@ -1540,6 +1664,10 @@ function redactSecrets(content) {
|
|
|
1540
1664
|
return out;
|
|
1541
1665
|
}
|
|
1542
1666
|
function scrubRemoteUrl(remote) {
|
|
1667
|
+
const httpStripped = remote.replace(/^(https?:\/\/)[^/@]+@/i, "$1");
|
|
1668
|
+
if (httpStripped !== remote) {
|
|
1669
|
+
return httpStripped;
|
|
1670
|
+
}
|
|
1543
1671
|
return remote.replace(
|
|
1544
1672
|
/^([a-zA-Z][a-zA-Z0-9+.-]*:\/\/)[^/@]*:[^/@]*@/,
|
|
1545
1673
|
"$1"
|
|
@@ -1719,10 +1847,24 @@ var resolvedBindingsSnapshotSchema = z14.object({
|
|
|
1719
1847
|
}).strict();
|
|
1720
1848
|
|
|
1721
1849
|
// src/store/bindings.ts
|
|
1722
|
-
import { existsSync as
|
|
1723
|
-
import { join as
|
|
1850
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
1851
|
+
import { join as join5, resolve, sep } from "path";
|
|
1852
|
+
var SAFE_PROJECT_ID = /^[A-Za-z0-9._-]+$/;
|
|
1853
|
+
function assertSafeProjectId(projectId) {
|
|
1854
|
+
if (!SAFE_PROJECT_ID.test(projectId) || projectId.includes("..")) {
|
|
1855
|
+
throw new Error(
|
|
1856
|
+
`bindingsSnapshotPath: refusing unsafe project_id ${JSON.stringify(projectId)} (must match ${SAFE_PROJECT_ID} and contain no "..")`
|
|
1857
|
+
);
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1724
1860
|
function bindingsSnapshotPath(globalRoot, projectId) {
|
|
1725
|
-
|
|
1861
|
+
assertSafeProjectId(projectId);
|
|
1862
|
+
const bindingsDir = resolve(join5(globalRoot, GLOBAL_STATE_DIR, GLOBAL_BINDINGS_DIR));
|
|
1863
|
+
const path = resolve(join5(bindingsDir, `${projectId}_resolved.json`));
|
|
1864
|
+
if (path !== bindingsDir && !path.startsWith(bindingsDir + sep)) {
|
|
1865
|
+
throw new Error(`bindingsSnapshotPath: resolved path escapes bindings dir for ${JSON.stringify(projectId)}`);
|
|
1866
|
+
}
|
|
1867
|
+
return path;
|
|
1726
1868
|
}
|
|
1727
1869
|
function writeBindingsSnapshot(options) {
|
|
1728
1870
|
const resolver = createStoreResolver();
|
|
@@ -1736,18 +1878,18 @@ function writeBindingsSnapshot(options) {
|
|
|
1736
1878
|
write_target: target
|
|
1737
1879
|
});
|
|
1738
1880
|
const path = bindingsSnapshotPath(options.globalRoot, options.projectId);
|
|
1739
|
-
|
|
1740
|
-
|
|
1881
|
+
mkdirSync4(join5(path, ".."), { recursive: true });
|
|
1882
|
+
writeFileSync4(path, `${JSON.stringify(snapshot, null, 2)}
|
|
1741
1883
|
`, "utf8");
|
|
1742
1884
|
return snapshot;
|
|
1743
1885
|
}
|
|
1744
1886
|
function readBindingsSnapshot(globalRoot, projectId) {
|
|
1745
1887
|
const path = bindingsSnapshotPath(globalRoot, projectId);
|
|
1746
|
-
if (!
|
|
1888
|
+
if (!existsSync5(path)) {
|
|
1747
1889
|
return null;
|
|
1748
1890
|
}
|
|
1749
1891
|
try {
|
|
1750
|
-
const parsed = resolvedBindingsSnapshotSchema.safeParse(JSON.parse(
|
|
1892
|
+
const parsed = resolvedBindingsSnapshotSchema.safeParse(JSON.parse(readFileSync4(path, "utf8")));
|
|
1751
1893
|
return parsed.success ? parsed.data : null;
|
|
1752
1894
|
} catch {
|
|
1753
1895
|
return null;
|
|
@@ -2438,6 +2580,15 @@ var assistantTurnObservedEventSchema = z18.object({
|
|
|
2438
2580
|
skip_reason: z18.string().nullable()
|
|
2439
2581
|
})
|
|
2440
2582
|
).default([]),
|
|
2583
|
+
// lifecycle-refactor W3-T4 (§2 store 轴 / store-qualified 观测): per-cite store
|
|
2584
|
+
// qualifier, index-aligned with cite_ids. Mirrors the cite-line-parser's
|
|
2585
|
+
// `cite_stores` output (`<alias-or-uuid>:<id>` → the qualifier; a bare id →
|
|
2586
|
+
// null). Persists the store provenance the parser already extracts so
|
|
2587
|
+
// doctor --cite-coverage can break compliance down per store WITHOUT joining
|
|
2588
|
+
// against the store registry. Additive `.optional()` (NOT `.default([])`) so
|
|
2589
|
+
// existing inline event constructors stay valid without supplying it — pre-W3-T4
|
|
2590
|
+
// events parse with the field absent and bucket under the project-local default.
|
|
2591
|
+
cite_stores: z18.array(z18.string().nullable()).optional(),
|
|
2441
2592
|
client: z18.enum(["cc", "codex", "cursor"]).optional(),
|
|
2442
2593
|
turn_id: z18.string(),
|
|
2443
2594
|
envelope_index: z18.number().int().nonnegative().optional(),
|
|
@@ -2580,6 +2731,29 @@ var clientCapabilitySnapshotEventSchema = z18.object({
|
|
|
2580
2731
|
capabilities: z18.array(z18.string()),
|
|
2581
2732
|
version: z18.string()
|
|
2582
2733
|
});
|
|
2734
|
+
var sessionEndedEventSchema = z18.object({
|
|
2735
|
+
...eventLedgerEnvelopeSchema,
|
|
2736
|
+
event_type: z18.literal("session_ended")
|
|
2737
|
+
});
|
|
2738
|
+
var fileMutatedEventSchema = z18.object({
|
|
2739
|
+
...eventLedgerEnvelopeSchema,
|
|
2740
|
+
event_type: z18.literal("file_mutated"),
|
|
2741
|
+
path: z18.string(),
|
|
2742
|
+
tool_call_id: z18.string(),
|
|
2743
|
+
tool_name: z18.string().optional(),
|
|
2744
|
+
source_event_id: z18.string().optional(),
|
|
2745
|
+
store_id: z18.string().optional()
|
|
2746
|
+
});
|
|
2747
|
+
var precompactObservedEventSchema = z18.object({
|
|
2748
|
+
...eventLedgerEnvelopeSchema,
|
|
2749
|
+
event_type: z18.literal("precompact_observed")
|
|
2750
|
+
});
|
|
2751
|
+
var graphEdgeCandidateRequestedEventSchema = z18.object({
|
|
2752
|
+
...eventLedgerEnvelopeSchema,
|
|
2753
|
+
event_type: z18.literal("graph_edge_candidate_requested"),
|
|
2754
|
+
stable_id: z18.string(),
|
|
2755
|
+
store: z18.string().optional()
|
|
2756
|
+
});
|
|
2583
2757
|
var eventLedgerEventSchema = z18.discriminatedUnion("event_type", [
|
|
2584
2758
|
knowledgeContextPlannedEventSchema,
|
|
2585
2759
|
knowledgeSelectionEventSchema,
|
|
@@ -2672,7 +2846,12 @@ var eventLedgerEventSchema = z18.discriminatedUnion("event_type", [
|
|
|
2672
2846
|
skillPhaseTransitionEventSchema,
|
|
2673
2847
|
skillTriggerCandidateEventSchema,
|
|
2674
2848
|
llmJudgeRunEventSchema,
|
|
2675
|
-
clientCapabilitySnapshotEventSchema
|
|
2849
|
+
clientCapabilitySnapshotEventSchema,
|
|
2850
|
+
// lifecycle-refactor Wave 2 — dormant-hook activation markers.
|
|
2851
|
+
sessionEndedEventSchema,
|
|
2852
|
+
fileMutatedEventSchema,
|
|
2853
|
+
precompactObservedEventSchema,
|
|
2854
|
+
graphEdgeCandidateRequestedEventSchema
|
|
2676
2855
|
]);
|
|
2677
2856
|
|
|
2678
2857
|
// src/text-tokenize.ts
|
|
@@ -2813,6 +2992,7 @@ export {
|
|
|
2813
2992
|
buildDebugBundle,
|
|
2814
2993
|
buildFailureTrace,
|
|
2815
2994
|
buildScanRecommendations,
|
|
2995
|
+
buildStoreResolveInput,
|
|
2816
2996
|
candidateFileEntrySchema,
|
|
2817
2997
|
citeContractMetricsSchema,
|
|
2818
2998
|
citeContractPolicyActivatedEventSchema,
|
|
@@ -2850,6 +3030,7 @@ export {
|
|
|
2850
3030
|
fabricConfigSchema,
|
|
2851
3031
|
fabricEventSchema,
|
|
2852
3032
|
fabricLanguageSchema,
|
|
3033
|
+
fileMutatedEventSchema,
|
|
2853
3034
|
findMountedStore,
|
|
2854
3035
|
findStoreExecutableViolations,
|
|
2855
3036
|
forensicAssertionCoverageSchema,
|
|
@@ -2866,8 +3047,10 @@ export {
|
|
|
2866
3047
|
formatKnowledgeId,
|
|
2867
3048
|
getPanelFieldByKey,
|
|
2868
3049
|
getPanelFields,
|
|
3050
|
+
globalConfigPath,
|
|
2869
3051
|
globalConfigSchema,
|
|
2870
3052
|
globalRefSchema,
|
|
3053
|
+
graphEdgeCandidateRequestedEventSchema,
|
|
2871
3054
|
hasSecrets,
|
|
2872
3055
|
historyStateQuerySchema,
|
|
2873
3056
|
hookSignalEmittedEventSchema,
|
|
@@ -2926,6 +3109,8 @@ export {
|
|
|
2926
3109
|
lintCrossStoreReferences,
|
|
2927
3110
|
listStoreKnowledge,
|
|
2928
3111
|
llmJudgeRunEventSchema,
|
|
3112
|
+
loadGlobalConfig,
|
|
3113
|
+
loadProjectConfig,
|
|
2929
3114
|
localKnowledgeIdSchema,
|
|
2930
3115
|
lockApprovedEventSchema,
|
|
2931
3116
|
lockDriftEventSchema,
|
|
@@ -2956,6 +3141,8 @@ export {
|
|
|
2956
3141
|
planContextInputSchema,
|
|
2957
3142
|
planContextOutputSchema,
|
|
2958
3143
|
planContextTopKSchema,
|
|
3144
|
+
precompactObservedEventSchema,
|
|
3145
|
+
projectConfigPath,
|
|
2959
3146
|
projectRootGoldenCaseSchema,
|
|
2960
3147
|
projectRootGoldenFileSchema,
|
|
2961
3148
|
projectRootResolutionSchema,
|
|
@@ -2977,12 +3164,15 @@ export {
|
|
|
2977
3164
|
requiredStoreEntrySchema,
|
|
2978
3165
|
resolveCandidates,
|
|
2979
3166
|
resolveFabricLocale,
|
|
3167
|
+
resolveGlobalRoot,
|
|
2980
3168
|
resolveRetrievalBudget,
|
|
2981
3169
|
resolveStoreQualifiedId,
|
|
2982
3170
|
resolvedBindingsSnapshotSchema,
|
|
2983
3171
|
retrievalBudgetProfile,
|
|
2984
3172
|
ruleDescriptionIndexItemSchema,
|
|
2985
3173
|
ruleDescriptionSchema,
|
|
3174
|
+
saveGlobalConfig,
|
|
3175
|
+
saveProjectConfig,
|
|
2986
3176
|
scanForSecrets,
|
|
2987
3177
|
scopeCoordinateSchema,
|
|
2988
3178
|
scopeRoot,
|
|
@@ -2990,6 +3180,7 @@ export {
|
|
|
2990
3180
|
selectionTokenTtlMsSchema,
|
|
2991
3181
|
serveLockClearedEventSchema,
|
|
2992
3182
|
sessionArchiveAttemptedEventSchema,
|
|
3183
|
+
sessionEndedEventSchema,
|
|
2993
3184
|
skillInvocationCompletedEventSchema,
|
|
2994
3185
|
skillInvocationStartedEventSchema,
|
|
2995
3186
|
skillPhaseTransitionEventSchema,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/node/atomic-write.ts
|
|
2
|
-
import { appendFile, mkdir, open, rename, stat, unlink, writeFile } from "fs/promises";
|
|
2
|
+
import { appendFile, mkdir, open, readFile, rename, stat, unlink, writeFile } from "fs/promises";
|
|
3
3
|
import { dirname } from "path";
|
|
4
|
+
import { randomUUID } from "crypto";
|
|
4
5
|
function makeTmpSuffix() {
|
|
5
6
|
const rand = Math.floor(Math.random() * 65535).toString(16).padStart(4, "0");
|
|
6
7
|
return `.${process.pid}.${Date.now()}.${rand}.tmp`;
|
|
@@ -44,6 +45,7 @@ async function withFileLock(lockPath, fn, opts = {}) {
|
|
|
44
45
|
const retryDelayMs = opts.retryDelayMs ?? 20;
|
|
45
46
|
const maxWaitMs = opts.maxWaitMs ?? 1e4;
|
|
46
47
|
await mkdir(dirname(lockPath), { recursive: true });
|
|
48
|
+
const token = `${process.pid}.${randomUUID()}`;
|
|
47
49
|
const start = Date.now();
|
|
48
50
|
for (; ; ) {
|
|
49
51
|
let handle;
|
|
@@ -54,7 +56,10 @@ async function withFileLock(lockPath, fn, opts = {}) {
|
|
|
54
56
|
try {
|
|
55
57
|
const st = await stat(lockPath);
|
|
56
58
|
if (Date.now() - st.mtimeMs > staleMs) {
|
|
57
|
-
await
|
|
59
|
+
const staleToken = await readFile(lockPath, "utf8").catch(() => null);
|
|
60
|
+
if (staleToken !== null) {
|
|
61
|
+
await unlinkIfToken(lockPath, staleToken);
|
|
62
|
+
}
|
|
58
63
|
continue;
|
|
59
64
|
}
|
|
60
65
|
} catch {
|
|
@@ -67,11 +72,21 @@ async function withFileLock(lockPath, fn, opts = {}) {
|
|
|
67
72
|
continue;
|
|
68
73
|
}
|
|
69
74
|
try {
|
|
75
|
+
await handle.writeFile(token, "utf8");
|
|
70
76
|
await handle.close();
|
|
71
77
|
return await fn();
|
|
72
78
|
} finally {
|
|
79
|
+
await unlinkIfToken(lockPath, token);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async function unlinkIfToken(lockPath, expected) {
|
|
84
|
+
try {
|
|
85
|
+
const current = await readFile(lockPath, "utf8");
|
|
86
|
+
if (current === expected) {
|
|
73
87
|
await unlink(lockPath).catch(() => void 0);
|
|
74
88
|
}
|
|
89
|
+
} catch {
|
|
75
90
|
}
|
|
76
91
|
}
|
|
77
92
|
function createLedgerWriteQueue() {
|