@fenglimg/fabric-shared 2.1.0-rc.2 → 2.2.0-rc.10
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-2GLIAZ5M.js +251 -0
- package/dist/{chunk-WVPDH4BF.js → chunk-5AKCRBKJ.js} +551 -382
- package/dist/{chunk-R2J7DAED.js → chunk-AQMDXC6J.js} +545 -517
- package/dist/chunk-BDJQIOQO.js +206 -0
- package/dist/chunk-C7WZPYZE.js +129 -0
- package/dist/{chunk-3SZRB42B.js → chunk-O6GIHZF3.js} +14 -0
- package/dist/errors/index.d.ts +12 -1
- package/dist/errors/index.js +9 -3
- package/dist/i18n/index.d.ts +29 -23
- package/dist/i18n/index.js +7 -3
- package/dist/{index-GQpaWTm-.d.ts → index-D_gT1CEA.d.ts} +125 -28
- package/dist/index.d.ts +2348 -1187
- package/dist/index.js +1675 -835
- package/dist/node/atomic-write.d.ts +26 -1
- package/dist/node/atomic-write.js +8 -65
- package/dist/node/mcp-payload-guard.d.ts +32 -1
- package/dist/node/mcp-payload-guard.js +16 -2
- package/dist/node.d.ts +10 -1
- package/dist/node.js +32 -1
- package/dist/schemas/api-contracts.d.ts +319 -100
- package/dist/schemas/api-contracts.js +3 -3
- package/dist/templates/bootstrap-canonical.d.ts +50 -23
- package/dist/templates/bootstrap-canonical.js +12 -9
- package/dist/types/index.d.ts +1 -1
- package/dist/types-qg4xXVuT.d.ts +8 -0
- package/package.json +3 -2
- package/dist/chunk-MDWTGOAY.js +0 -101
|
@@ -6,6 +6,31 @@ interface AtomicWriteJsonOptions extends AtomicWriteOptions {
|
|
|
6
6
|
}
|
|
7
7
|
declare function atomicWriteText(path: string, content: string, opts?: AtomicWriteOptions): Promise<void>;
|
|
8
8
|
declare function atomicWriteJson(path: string, value: unknown, opts?: AtomicWriteJsonOptions): Promise<void>;
|
|
9
|
+
interface FileLockOptions {
|
|
10
|
+
/** A held lock older than this (ms, by lock-file mtime) is presumed stale —
|
|
11
|
+
* left by a crashed holder — and reclaimed. Default 10s. */
|
|
12
|
+
staleMs?: number;
|
|
13
|
+
/** Poll interval (ms) between acquire attempts while contended. Default 20ms. */
|
|
14
|
+
retryDelayMs?: number;
|
|
15
|
+
/** Give up acquiring after this long (ms) and throw. Default 10s. */
|
|
16
|
+
maxWaitMs?: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Run `fn` while holding a cross-process advisory lock at `lockPath`.
|
|
20
|
+
*
|
|
21
|
+
* Unlike the hook-side `appendLockedLine` (which DROPS on contention, fine for
|
|
22
|
+
* best-effort telemetry), this WAITS for the lock — the critical section it
|
|
23
|
+
* guards (e.g. a read-modify-write of a shared counter file) must not be
|
|
24
|
+
* skipped. The lock is a `wx` (O_CREAT|O_EXCL) lock file, so acquisition is
|
|
25
|
+
* atomic across processes; a crashed holder leaves the file behind, so any
|
|
26
|
+
* holder older than `staleMs` is reclaimed. The lock is always released in a
|
|
27
|
+
* `finally`, even if `fn` throws.
|
|
28
|
+
*
|
|
29
|
+
* Scope: cross-process AND in-process. Two concurrent callers on the same
|
|
30
|
+
* `lockPath` (same process or not) serialize, because both race the same
|
|
31
|
+
* O_EXCL create.
|
|
32
|
+
*/
|
|
33
|
+
declare function withFileLock<T>(lockPath: string, fn: () => Promise<T>, opts?: FileLockOptions): Promise<T>;
|
|
9
34
|
interface LedgerWriteQueue {
|
|
10
35
|
append(path: string, line: string): Promise<void>;
|
|
11
36
|
/**
|
|
@@ -27,4 +52,4 @@ interface LedgerWriteQueue {
|
|
|
27
52
|
}
|
|
28
53
|
declare function createLedgerWriteQueue(): LedgerWriteQueue;
|
|
29
54
|
|
|
30
|
-
export { type AtomicWriteJsonOptions, type AtomicWriteOptions, type LedgerWriteQueue, atomicWriteJson, atomicWriteText, createLedgerWriteQueue };
|
|
55
|
+
export { type AtomicWriteJsonOptions, type AtomicWriteOptions, type FileLockOptions, type LedgerWriteQueue, atomicWriteJson, atomicWriteText, createLedgerWriteQueue, withFileLock };
|
|
@@ -1,69 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
async function atomicWriteText(path, content, opts) {
|
|
8
|
-
const tmpPath = path + makeTmpSuffix();
|
|
9
|
-
try {
|
|
10
|
-
if (opts?.fsync) {
|
|
11
|
-
const fd = await open(tmpPath, "w");
|
|
12
|
-
try {
|
|
13
|
-
await fd.writeFile(content, "utf8");
|
|
14
|
-
await fd.datasync();
|
|
15
|
-
} finally {
|
|
16
|
-
await fd.close();
|
|
17
|
-
}
|
|
18
|
-
} else {
|
|
19
|
-
await writeFile(tmpPath, content, "utf8");
|
|
20
|
-
}
|
|
21
|
-
await rename(tmpPath, path);
|
|
22
|
-
} catch (err) {
|
|
23
|
-
try {
|
|
24
|
-
await unlink(tmpPath);
|
|
25
|
-
} catch {
|
|
26
|
-
}
|
|
27
|
-
throw err;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
async function atomicWriteJson(path, value, opts) {
|
|
31
|
-
const indent = opts?.indent ?? 2;
|
|
32
|
-
const content = JSON.stringify(value, null, indent) + "\n";
|
|
33
|
-
await atomicWriteText(path, content, { fsync: opts?.fsync });
|
|
34
|
-
}
|
|
35
|
-
function createLedgerWriteQueue() {
|
|
36
|
-
const chains = /* @__PURE__ */ new Map();
|
|
37
|
-
async function doAppend(path, line) {
|
|
38
|
-
const normalized = line.endsWith("\n") ? line : line + "\n";
|
|
39
|
-
await appendFile(path, normalized, "utf8");
|
|
40
|
-
}
|
|
41
|
-
function enqueue(path, work) {
|
|
42
|
-
const prev = chains.get(path) ?? Promise.resolve();
|
|
43
|
-
const result = prev.catch(() => void 0).then(() => work());
|
|
44
|
-
const chainSlot = result.then(
|
|
45
|
-
() => void 0,
|
|
46
|
-
() => void 0
|
|
47
|
-
);
|
|
48
|
-
chains.set(path, chainSlot);
|
|
49
|
-
chainSlot.finally(() => {
|
|
50
|
-
if (chains.get(path) === chainSlot) {
|
|
51
|
-
chains.delete(path);
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
return result;
|
|
55
|
-
}
|
|
56
|
-
return {
|
|
57
|
-
append(path, line) {
|
|
58
|
-
return enqueue(path, () => doAppend(path, line));
|
|
59
|
-
},
|
|
60
|
-
runExclusive(path, fn) {
|
|
61
|
-
return enqueue(path, fn);
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
atomicWriteJson,
|
|
3
|
+
atomicWriteText,
|
|
4
|
+
createLedgerWriteQueue,
|
|
5
|
+
withFileLock
|
|
6
|
+
} from "../chunk-C7WZPYZE.js";
|
|
65
7
|
export {
|
|
66
8
|
atomicWriteJson,
|
|
67
9
|
atomicWriteText,
|
|
68
|
-
createLedgerWriteQueue
|
|
10
|
+
createLedgerWriteQueue,
|
|
11
|
+
withFileLock
|
|
69
12
|
};
|
|
@@ -14,5 +14,36 @@ interface PayloadGuardResult {
|
|
|
14
14
|
declare const PAYLOAD_LIMIT_DEFAULT_WARN_BYTES = 16384;
|
|
15
15
|
declare const PAYLOAD_LIMIT_DEFAULT_HARD_BYTES = 65536;
|
|
16
16
|
declare function enforcePayloadLimit(serializedPayload: string, opts?: PayloadGuardOptions): PayloadGuardResult;
|
|
17
|
+
interface PayloadBudgetTrimResult<T> {
|
|
18
|
+
/** The retained head of `items` (the ranked tail was dropped to fit). */
|
|
19
|
+
items: T[];
|
|
20
|
+
/** How many trailing items were dropped to fit the hard budget. */
|
|
21
|
+
dropped: number;
|
|
22
|
+
/** Serialized byte size of the envelope built from the retained items. */
|
|
23
|
+
bytes: number;
|
|
24
|
+
/**
|
|
25
|
+
* True when even `minKeep` items still overflow the hard budget — the caller
|
|
26
|
+
* must surface this (a single oversized entry) rather than assume it fit.
|
|
27
|
+
*/
|
|
28
|
+
overBudget: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* v2.2 MC4-payload-budget (W1-T4): the byte-budget tail of the unified
|
|
32
|
+
* truncation chain (CJK → BM25 → top_k → payload). Rather than hard-throwing
|
|
33
|
+
* when a response overflows the hard limit, callers trim the LEAST-relevant
|
|
34
|
+
* items off the tail of an already-ranked list until the serialized envelope
|
|
35
|
+
* fits — turning a 413 crash into graceful degradation.
|
|
36
|
+
*
|
|
37
|
+
* `serialize` builds the FULL response envelope from a candidate slice (so the
|
|
38
|
+
* byte count includes warnings / metadata, not just the list). Trimming drops
|
|
39
|
+
* from the END, which is correct ONLY when the list is pre-ranked best-first
|
|
40
|
+
* (plan_context sorts by BM25 before calling this). `minKeep` (default 1)
|
|
41
|
+
* guarantees a non-empty result even under a pathological oversized head; in
|
|
42
|
+
* that case `overBudget` is returned true so the caller can warn instead of
|
|
43
|
+
* silently shipping an over-limit payload.
|
|
44
|
+
*/
|
|
45
|
+
declare function trimToPayloadBudget<T>(items: T[], serialize: (items: T[]) => string, opts?: PayloadGuardOptions & {
|
|
46
|
+
minKeep?: number;
|
|
47
|
+
}): PayloadBudgetTrimResult<T>;
|
|
17
48
|
|
|
18
|
-
export { PAYLOAD_LIMIT_DEFAULT_HARD_BYTES, PAYLOAD_LIMIT_DEFAULT_WARN_BYTES, type PayloadGuardOptions, type PayloadGuardResult, enforcePayloadLimit };
|
|
49
|
+
export { PAYLOAD_LIMIT_DEFAULT_HARD_BYTES, PAYLOAD_LIMIT_DEFAULT_WARN_BYTES, type PayloadBudgetTrimResult, type PayloadGuardOptions, type PayloadGuardResult, enforcePayloadLimit, trimToPayloadBudget };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
MCPError
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-O6GIHZF3.js";
|
|
4
4
|
|
|
5
5
|
// src/node/mcp-payload-guard.ts
|
|
6
6
|
var McpPayloadTooLargeError = class extends MCPError {
|
|
@@ -37,8 +37,22 @@ function enforcePayloadLimit(serializedPayload, opts) {
|
|
|
37
37
|
}
|
|
38
38
|
return { bytes };
|
|
39
39
|
}
|
|
40
|
+
function trimToPayloadBudget(items, serialize, opts) {
|
|
41
|
+
const hardAt = opts?.hardBytes ?? DEFAULT_HARD;
|
|
42
|
+
const minKeep = Math.max(0, opts?.minKeep ?? 1);
|
|
43
|
+
let kept = items;
|
|
44
|
+
let bytes = Buffer.byteLength(serialize(kept), "utf8");
|
|
45
|
+
let dropped = 0;
|
|
46
|
+
while (bytes > hardAt && kept.length > minKeep) {
|
|
47
|
+
kept = kept.slice(0, -1);
|
|
48
|
+
dropped += 1;
|
|
49
|
+
bytes = Buffer.byteLength(serialize(kept), "utf8");
|
|
50
|
+
}
|
|
51
|
+
return { items: kept, dropped, bytes, overBudget: bytes > hardAt };
|
|
52
|
+
}
|
|
40
53
|
export {
|
|
41
54
|
PAYLOAD_LIMIT_DEFAULT_HARD_BYTES,
|
|
42
55
|
PAYLOAD_LIMIT_DEFAULT_WARN_BYTES,
|
|
43
|
-
enforcePayloadLimit
|
|
56
|
+
enforcePayloadLimit,
|
|
57
|
+
trimToPayloadBudget
|
|
44
58
|
};
|
package/dist/node.d.ts
CHANGED
|
@@ -11,4 +11,13 @@ type FrameworkInfo = {
|
|
|
11
11
|
type TechProfile = FrameworkInfo;
|
|
12
12
|
declare function detectFramework(root: string): FrameworkInfo;
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
interface ServeLockState {
|
|
15
|
+
pid: number;
|
|
16
|
+
acquiredAt: number;
|
|
17
|
+
host?: string;
|
|
18
|
+
}
|
|
19
|
+
declare function serveLockPath(projectRoot: string): string;
|
|
20
|
+
declare function isAlive(pid: number): boolean;
|
|
21
|
+
declare function readServeLockState(projectRoot: string): ServeLockState | null;
|
|
22
|
+
|
|
23
|
+
export { type FrameworkInfo, type ServeLockState, type TechProfile, detectFramework, isAlive, readServeLockState, serveLockPath };
|
package/dist/node.js
CHANGED
|
@@ -170,6 +170,37 @@ function collectProjectFileEvidence(root, relativePaths) {
|
|
|
170
170
|
function compactStrings(values) {
|
|
171
171
|
return [...new Set(values.filter((value) => value !== null && value !== void 0 && value.length > 0))];
|
|
172
172
|
}
|
|
173
|
+
|
|
174
|
+
// src/node/serve-lock.ts
|
|
175
|
+
import fs from "fs";
|
|
176
|
+
import path from "path";
|
|
177
|
+
var SERVE_LOCK_FILENAME = ".serve.lock";
|
|
178
|
+
function serveLockPath(projectRoot) {
|
|
179
|
+
return path.join(projectRoot, ".fabric", SERVE_LOCK_FILENAME);
|
|
180
|
+
}
|
|
181
|
+
function isAlive(pid) {
|
|
182
|
+
try {
|
|
183
|
+
process.kill(pid, 0);
|
|
184
|
+
return true;
|
|
185
|
+
} catch (e) {
|
|
186
|
+
const err = e;
|
|
187
|
+
if (err.code === "ESRCH") return false;
|
|
188
|
+
if (err.code === "EPERM") return true;
|
|
189
|
+
throw e;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function readServeLockState(projectRoot) {
|
|
193
|
+
const p = serveLockPath(projectRoot);
|
|
194
|
+
if (!fs.existsSync(p)) return null;
|
|
195
|
+
try {
|
|
196
|
+
return JSON.parse(fs.readFileSync(p, "utf8"));
|
|
197
|
+
} catch {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
173
201
|
export {
|
|
174
|
-
detectFramework
|
|
202
|
+
detectFramework,
|
|
203
|
+
isAlive,
|
|
204
|
+
readServeLockState,
|
|
205
|
+
serveLockPath
|
|
175
206
|
};
|