@fenglimg/fabric-shared 2.0.1 → 2.2.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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,5 +1,6 @@
1
1
  // src/node/atomic-write.ts
2
- import { appendFile, open, rename, unlink, writeFile } from "fs/promises";
2
+ import { appendFile, mkdir, open, rename, stat, unlink, writeFile } from "fs/promises";
3
+ import { dirname } from "path";
3
4
  function makeTmpSuffix() {
4
5
  const rand = Math.floor(Math.random() * 65535).toString(16).padStart(4, "0");
5
6
  return `.${process.pid}.${Date.now()}.${rand}.tmp`;
@@ -32,6 +33,47 @@ async function atomicWriteJson(path, value, opts) {
32
33
  const content = JSON.stringify(value, null, indent) + "\n";
33
34
  await atomicWriteText(path, content, { fsync: opts?.fsync });
34
35
  }
36
+ function isErrnoException(err) {
37
+ return err instanceof Error && typeof err.code === "string";
38
+ }
39
+ function sleep(ms) {
40
+ return new Promise((resolve) => setTimeout(resolve, ms));
41
+ }
42
+ async function withFileLock(lockPath, fn, opts = {}) {
43
+ const staleMs = opts.staleMs ?? 1e4;
44
+ const retryDelayMs = opts.retryDelayMs ?? 20;
45
+ const maxWaitMs = opts.maxWaitMs ?? 1e4;
46
+ await mkdir(dirname(lockPath), { recursive: true });
47
+ const start = Date.now();
48
+ for (; ; ) {
49
+ let handle;
50
+ try {
51
+ handle = await open(lockPath, "wx");
52
+ } catch (err) {
53
+ if (!isErrnoException(err) || err.code !== "EEXIST") throw err;
54
+ try {
55
+ const st = await stat(lockPath);
56
+ if (Date.now() - st.mtimeMs > staleMs) {
57
+ await unlink(lockPath).catch(() => void 0);
58
+ continue;
59
+ }
60
+ } catch {
61
+ continue;
62
+ }
63
+ if (Date.now() - start > maxWaitMs) {
64
+ throw new Error(`withFileLock: timed out acquiring ${lockPath} after ${maxWaitMs}ms`);
65
+ }
66
+ await sleep(retryDelayMs);
67
+ continue;
68
+ }
69
+ try {
70
+ await handle.close();
71
+ return await fn();
72
+ } finally {
73
+ await unlink(lockPath).catch(() => void 0);
74
+ }
75
+ }
76
+ }
35
77
  function createLedgerWriteQueue() {
36
78
  const chains = /* @__PURE__ */ new Map();
37
79
  async function doAppend(path, line) {
@@ -65,5 +107,6 @@ function createLedgerWriteQueue() {
65
107
  export {
66
108
  atomicWriteJson,
67
109
  atomicWriteText,
68
- createLedgerWriteQueue
110
+ createLedgerWriteQueue,
111
+ withFileLock
69
112
  };
@@ -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 };
@@ -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
  };
@@ -104,38 +104,41 @@ declare const planContextOutputSchema: z.ZodObject<{
104
104
  tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
105
105
  relevance_scope: z.ZodOptional<z.ZodEnum<["narrow", "broad"]>>;
106
106
  relevance_paths: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
107
+ related: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
107
108
  }, "strip", z.ZodTypeAny, {
108
109
  summary: string;
109
110
  intent_clues: string[];
110
111
  tech_stack: string[];
111
112
  impact: string[];
112
113
  must_read_if: string;
114
+ created_at?: string | undefined;
115
+ id?: string | undefined;
113
116
  relevance_scope?: "narrow" | "broad" | undefined;
114
117
  relevance_paths?: string[] | undefined;
115
118
  entities?: string[] | undefined;
116
- id?: string | undefined;
117
119
  knowledge_type?: "models" | "decisions" | "guidelines" | "pitfalls" | "processes" | undefined;
118
120
  maturity?: "draft" | "verified" | "proven" | undefined;
119
121
  knowledge_layer?: "personal" | "team" | undefined;
120
122
  layer_reason?: string | undefined;
121
- created_at?: string | undefined;
122
123
  tags?: string[] | undefined;
124
+ related?: string[] | undefined;
123
125
  }, {
124
126
  summary: string;
125
127
  intent_clues: string[];
126
128
  tech_stack: string[];
127
129
  impact: string[];
128
130
  must_read_if: string;
131
+ created_at?: string | undefined;
132
+ id?: string | undefined;
129
133
  relevance_scope?: "narrow" | "broad" | undefined;
130
134
  relevance_paths?: string[] | undefined;
131
135
  entities?: string[] | undefined;
132
- id?: string | undefined;
133
136
  knowledge_type?: "models" | "decisions" | "guidelines" | "pitfalls" | "processes" | undefined;
134
137
  maturity?: "draft" | "verified" | "proven" | undefined;
135
138
  knowledge_layer?: "personal" | "team" | undefined;
136
139
  layer_reason?: string | undefined;
137
- created_at?: string | undefined;
138
140
  tags?: string[] | undefined;
141
+ related?: string[] | undefined;
139
142
  }>;
140
143
  }, "strip", z.ZodTypeAny, {
141
144
  description: {
@@ -144,16 +147,17 @@ declare const planContextOutputSchema: z.ZodObject<{
144
147
  tech_stack: string[];
145
148
  impact: string[];
146
149
  must_read_if: string;
150
+ created_at?: string | undefined;
151
+ id?: string | undefined;
147
152
  relevance_scope?: "narrow" | "broad" | undefined;
148
153
  relevance_paths?: string[] | undefined;
149
154
  entities?: string[] | undefined;
150
- id?: string | undefined;
151
155
  knowledge_type?: "models" | "decisions" | "guidelines" | "pitfalls" | "processes" | undefined;
152
156
  maturity?: "draft" | "verified" | "proven" | undefined;
153
157
  knowledge_layer?: "personal" | "team" | undefined;
154
158
  layer_reason?: string | undefined;
155
- created_at?: string | undefined;
156
159
  tags?: string[] | undefined;
160
+ related?: string[] | undefined;
157
161
  };
158
162
  stable_id: string;
159
163
  }, {
@@ -163,19 +167,21 @@ declare const planContextOutputSchema: z.ZodObject<{
163
167
  tech_stack: string[];
164
168
  impact: string[];
165
169
  must_read_if: string;
170
+ created_at?: string | undefined;
171
+ id?: string | undefined;
166
172
  relevance_scope?: "narrow" | "broad" | undefined;
167
173
  relevance_paths?: string[] | undefined;
168
174
  entities?: string[] | undefined;
169
- id?: string | undefined;
170
175
  knowledge_type?: "models" | "decisions" | "guidelines" | "pitfalls" | "processes" | undefined;
171
176
  maturity?: "draft" | "verified" | "proven" | undefined;
172
177
  knowledge_layer?: "personal" | "team" | undefined;
173
178
  layer_reason?: string | undefined;
174
- created_at?: string | undefined;
175
179
  tags?: string[] | undefined;
180
+ related?: string[] | undefined;
176
181
  };
177
182
  stable_id: string;
178
183
  }>, "many">;
184
+ omitted_candidate_count: z.ZodOptional<z.ZodNumber>;
179
185
  preflight_diagnostics: z.ZodArray<z.ZodObject<{
180
186
  code: z.ZodEnum<["missing_description", "empty_shell_suppressed"]>;
181
187
  severity: z.ZodLiteral<"warn">;
@@ -234,16 +240,17 @@ declare const planContextOutputSchema: z.ZodObject<{
234
240
  tech_stack: string[];
235
241
  impact: string[];
236
242
  must_read_if: string;
243
+ created_at?: string | undefined;
244
+ id?: string | undefined;
237
245
  relevance_scope?: "narrow" | "broad" | undefined;
238
246
  relevance_paths?: string[] | undefined;
239
247
  entities?: string[] | undefined;
240
- id?: string | undefined;
241
248
  knowledge_type?: "models" | "decisions" | "guidelines" | "pitfalls" | "processes" | undefined;
242
249
  maturity?: "draft" | "verified" | "proven" | undefined;
243
250
  knowledge_layer?: "personal" | "team" | undefined;
244
251
  layer_reason?: string | undefined;
245
- created_at?: string | undefined;
246
252
  tags?: string[] | undefined;
253
+ related?: string[] | undefined;
247
254
  };
248
255
  stable_id: string;
249
256
  }[];
@@ -254,6 +261,7 @@ declare const planContextOutputSchema: z.ZodObject<{
254
261
  path?: string | undefined;
255
262
  stable_ids?: string[] | undefined;
256
263
  }[];
264
+ omitted_candidate_count?: number | undefined;
257
265
  warnings?: {
258
266
  code: string;
259
267
  file: string;
@@ -283,16 +291,17 @@ declare const planContextOutputSchema: z.ZodObject<{
283
291
  tech_stack: string[];
284
292
  impact: string[];
285
293
  must_read_if: string;
294
+ created_at?: string | undefined;
295
+ id?: string | undefined;
286
296
  relevance_scope?: "narrow" | "broad" | undefined;
287
297
  relevance_paths?: string[] | undefined;
288
298
  entities?: string[] | undefined;
289
- id?: string | undefined;
290
299
  knowledge_type?: "models" | "decisions" | "guidelines" | "pitfalls" | "processes" | undefined;
291
300
  maturity?: "draft" | "verified" | "proven" | undefined;
292
301
  knowledge_layer?: "personal" | "team" | undefined;
293
302
  layer_reason?: string | undefined;
294
- created_at?: string | undefined;
295
303
  tags?: string[] | undefined;
304
+ related?: string[] | undefined;
296
305
  };
297
306
  stable_id: string;
298
307
  }[];
@@ -303,6 +312,7 @@ declare const planContextOutputSchema: z.ZodObject<{
303
312
  path?: string | undefined;
304
313
  stable_ids?: string[] | undefined;
305
314
  }[];
315
+ omitted_candidate_count?: number | undefined;
306
316
  warnings?: {
307
317
  code: string;
308
318
  file: string;
@@ -327,13 +337,13 @@ declare const planContextHintNarrowEntrySchema: z.ZodObject<{
327
337
  summary: z.ZodString;
328
338
  }, "strip", z.ZodTypeAny, {
329
339
  type: string;
330
- summary: string;
331
340
  id: string;
341
+ summary: string;
332
342
  maturity: string;
333
343
  }, {
334
344
  type: string;
335
- summary: string;
336
345
  id: string;
346
+ summary: string;
337
347
  maturity: string;
338
348
  }>;
339
349
  declare const planContextHintOutputSchema: z.ZodObject<{
@@ -347,21 +357,21 @@ declare const planContextHintOutputSchema: z.ZodObject<{
347
357
  summary: z.ZodString;
348
358
  }, "strip", z.ZodTypeAny, {
349
359
  type: string;
350
- summary: string;
351
360
  id: string;
361
+ summary: string;
352
362
  maturity: string;
353
363
  }, {
354
364
  type: string;
355
- summary: string;
356
365
  id: string;
366
+ summary: string;
357
367
  maturity: string;
358
368
  }>, "many">;
359
369
  broad_count: z.ZodNumber;
360
370
  }, "strip", z.ZodTypeAny, {
361
371
  narrow: {
362
372
  type: string;
363
- summary: string;
364
373
  id: string;
374
+ summary: string;
365
375
  maturity: string;
366
376
  }[];
367
377
  target_paths: string[];
@@ -371,8 +381,8 @@ declare const planContextHintOutputSchema: z.ZodObject<{
371
381
  }, {
372
382
  narrow: {
373
383
  type: string;
374
- summary: string;
375
384
  id: string;
385
+ summary: string;
376
386
  maturity: string;
377
387
  }[];
378
388
  target_paths: string[];
@@ -527,6 +537,7 @@ declare const recallInputSchema: z.ZodObject<{
527
537
  layer_filter: z.ZodOptional<z.ZodEnum<["team", "personal", "both"]>>;
528
538
  target_paths: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
529
539
  ids: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
540
+ include_related: z.ZodOptional<z.ZodBoolean>;
530
541
  }, "strip", z.ZodTypeAny, {
531
542
  paths: string[];
532
543
  known_tech?: string[] | undefined;
@@ -538,6 +549,7 @@ declare const recallInputSchema: z.ZodObject<{
538
549
  layer_filter?: "personal" | "team" | "both" | undefined;
539
550
  target_paths?: string[] | undefined;
540
551
  ids?: string[] | undefined;
552
+ include_related?: boolean | undefined;
541
553
  }, {
542
554
  paths: string[];
543
555
  known_tech?: string[] | undefined;
@@ -549,6 +561,7 @@ declare const recallInputSchema: z.ZodObject<{
549
561
  layer_filter?: "personal" | "team" | "both" | undefined;
550
562
  target_paths?: string[] | undefined;
551
563
  ids?: string[] | undefined;
564
+ include_related?: boolean | undefined;
552
565
  }>;
553
566
  declare const recallOutputSchema: z.ZodObject<{
554
567
  revision_hash: z.ZodString;
@@ -607,38 +620,41 @@ declare const recallOutputSchema: z.ZodObject<{
607
620
  tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
608
621
  relevance_scope: z.ZodOptional<z.ZodEnum<["narrow", "broad"]>>;
609
622
  relevance_paths: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
623
+ related: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
610
624
  }, "strip", z.ZodTypeAny, {
611
625
  summary: string;
612
626
  intent_clues: string[];
613
627
  tech_stack: string[];
614
628
  impact: string[];
615
629
  must_read_if: string;
630
+ created_at?: string | undefined;
631
+ id?: string | undefined;
616
632
  relevance_scope?: "narrow" | "broad" | undefined;
617
633
  relevance_paths?: string[] | undefined;
618
634
  entities?: string[] | undefined;
619
- id?: string | undefined;
620
635
  knowledge_type?: "models" | "decisions" | "guidelines" | "pitfalls" | "processes" | undefined;
621
636
  maturity?: "draft" | "verified" | "proven" | undefined;
622
637
  knowledge_layer?: "personal" | "team" | undefined;
623
638
  layer_reason?: string | undefined;
624
- created_at?: string | undefined;
625
639
  tags?: string[] | undefined;
640
+ related?: string[] | undefined;
626
641
  }, {
627
642
  summary: string;
628
643
  intent_clues: string[];
629
644
  tech_stack: string[];
630
645
  impact: string[];
631
646
  must_read_if: string;
647
+ created_at?: string | undefined;
648
+ id?: string | undefined;
632
649
  relevance_scope?: "narrow" | "broad" | undefined;
633
650
  relevance_paths?: string[] | undefined;
634
651
  entities?: string[] | undefined;
635
- id?: string | undefined;
636
652
  knowledge_type?: "models" | "decisions" | "guidelines" | "pitfalls" | "processes" | undefined;
637
653
  maturity?: "draft" | "verified" | "proven" | undefined;
638
654
  knowledge_layer?: "personal" | "team" | undefined;
639
655
  layer_reason?: string | undefined;
640
- created_at?: string | undefined;
641
656
  tags?: string[] | undefined;
657
+ related?: string[] | undefined;
642
658
  }>;
643
659
  }, "strip", z.ZodTypeAny, {
644
660
  description: {
@@ -647,16 +663,17 @@ declare const recallOutputSchema: z.ZodObject<{
647
663
  tech_stack: string[];
648
664
  impact: string[];
649
665
  must_read_if: string;
666
+ created_at?: string | undefined;
667
+ id?: string | undefined;
650
668
  relevance_scope?: "narrow" | "broad" | undefined;
651
669
  relevance_paths?: string[] | undefined;
652
670
  entities?: string[] | undefined;
653
- id?: string | undefined;
654
671
  knowledge_type?: "models" | "decisions" | "guidelines" | "pitfalls" | "processes" | undefined;
655
672
  maturity?: "draft" | "verified" | "proven" | undefined;
656
673
  knowledge_layer?: "personal" | "team" | undefined;
657
674
  layer_reason?: string | undefined;
658
- created_at?: string | undefined;
659
675
  tags?: string[] | undefined;
676
+ related?: string[] | undefined;
660
677
  };
661
678
  stable_id: string;
662
679
  }, {
@@ -666,19 +683,21 @@ declare const recallOutputSchema: z.ZodObject<{
666
683
  tech_stack: string[];
667
684
  impact: string[];
668
685
  must_read_if: string;
686
+ created_at?: string | undefined;
687
+ id?: string | undefined;
669
688
  relevance_scope?: "narrow" | "broad" | undefined;
670
689
  relevance_paths?: string[] | undefined;
671
690
  entities?: string[] | undefined;
672
- id?: string | undefined;
673
691
  knowledge_type?: "models" | "decisions" | "guidelines" | "pitfalls" | "processes" | undefined;
674
692
  maturity?: "draft" | "verified" | "proven" | undefined;
675
693
  knowledge_layer?: "personal" | "team" | undefined;
676
694
  layer_reason?: string | undefined;
677
- created_at?: string | undefined;
678
695
  tags?: string[] | undefined;
696
+ related?: string[] | undefined;
679
697
  };
680
698
  stable_id: string;
681
699
  }>, "many">;
700
+ omitted_candidate_count: z.ZodOptional<z.ZodNumber>;
682
701
  preflight_diagnostics: z.ZodArray<z.ZodObject<{
683
702
  code: z.ZodEnum<["missing_description", "empty_shell_suppressed"]>;
684
703
  severity: z.ZodLiteral<"warn">;
@@ -750,6 +769,18 @@ declare const recallOutputSchema: z.ZodObject<{
750
769
  auto_healed: z.ZodOptional<z.ZodBoolean>;
751
770
  previous_revision_hash: z.ZodOptional<z.ZodString>;
752
771
  redirects: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
772
+ directive: z.ZodString;
773
+ next_steps: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
774
+ truncation: z.ZodOptional<z.ZodObject<{
775
+ omitted_candidate_count: z.ZodNumber;
776
+ returned_candidate_count: z.ZodNumber;
777
+ }, "strip", z.ZodTypeAny, {
778
+ omitted_candidate_count: number;
779
+ returned_candidate_count: number;
780
+ }, {
781
+ omitted_candidate_count: number;
782
+ returned_candidate_count: number;
783
+ }>>;
753
784
  }, "strip", z.ZodTypeAny, {
754
785
  entries: {
755
786
  path: string;
@@ -770,16 +801,17 @@ declare const recallOutputSchema: z.ZodObject<{
770
801
  tech_stack: string[];
771
802
  impact: string[];
772
803
  must_read_if: string;
804
+ created_at?: string | undefined;
805
+ id?: string | undefined;
773
806
  relevance_scope?: "narrow" | "broad" | undefined;
774
807
  relevance_paths?: string[] | undefined;
775
808
  entities?: string[] | undefined;
776
- id?: string | undefined;
777
809
  knowledge_type?: "models" | "decisions" | "guidelines" | "pitfalls" | "processes" | undefined;
778
810
  maturity?: "draft" | "verified" | "proven" | undefined;
779
811
  knowledge_layer?: "personal" | "team" | undefined;
780
812
  layer_reason?: string | undefined;
781
- created_at?: string | undefined;
782
813
  tags?: string[] | undefined;
814
+ related?: string[] | undefined;
783
815
  };
784
816
  stable_id: string;
785
817
  }[];
@@ -803,6 +835,8 @@ declare const recallOutputSchema: z.ZodObject<{
803
835
  stable_id: string;
804
836
  severity: "warn";
805
837
  }[];
838
+ directive: string;
839
+ omitted_candidate_count?: number | undefined;
806
840
  warnings?: {
807
841
  code: string;
808
842
  file: string;
@@ -812,6 +846,11 @@ declare const recallOutputSchema: z.ZodObject<{
812
846
  auto_healed?: boolean | undefined;
813
847
  previous_revision_hash?: string | undefined;
814
848
  redirects?: Record<string, string> | undefined;
849
+ next_steps?: string[] | undefined;
850
+ truncation?: {
851
+ omitted_candidate_count: number;
852
+ returned_candidate_count: number;
853
+ } | undefined;
815
854
  }, {
816
855
  entries: {
817
856
  path: string;
@@ -832,16 +871,17 @@ declare const recallOutputSchema: z.ZodObject<{
832
871
  tech_stack: string[];
833
872
  impact: string[];
834
873
  must_read_if: string;
874
+ created_at?: string | undefined;
875
+ id?: string | undefined;
835
876
  relevance_scope?: "narrow" | "broad" | undefined;
836
877
  relevance_paths?: string[] | undefined;
837
878
  entities?: string[] | undefined;
838
- id?: string | undefined;
839
879
  knowledge_type?: "models" | "decisions" | "guidelines" | "pitfalls" | "processes" | undefined;
840
880
  maturity?: "draft" | "verified" | "proven" | undefined;
841
881
  knowledge_layer?: "personal" | "team" | undefined;
842
882
  layer_reason?: string | undefined;
843
- created_at?: string | undefined;
844
883
  tags?: string[] | undefined;
884
+ related?: string[] | undefined;
845
885
  };
846
886
  stable_id: string;
847
887
  }[];
@@ -865,6 +905,8 @@ declare const recallOutputSchema: z.ZodObject<{
865
905
  stable_id: string;
866
906
  severity: "warn";
867
907
  }[];
908
+ directive: string;
909
+ omitted_candidate_count?: number | undefined;
868
910
  warnings?: {
869
911
  code: string;
870
912
  file: string;
@@ -874,6 +916,11 @@ declare const recallOutputSchema: z.ZodObject<{
874
916
  auto_healed?: boolean | undefined;
875
917
  previous_revision_hash?: string | undefined;
876
918
  redirects?: Record<string, string> | undefined;
919
+ next_steps?: string[] | undefined;
920
+ truncation?: {
921
+ omitted_candidate_count: number;
922
+ returned_candidate_count: number;
923
+ } | undefined;
877
924
  }>;
878
925
  declare const recallAnnotations: {
879
926
  readonly readOnlyHint: true;
@@ -2305,18 +2352,18 @@ declare const KnowledgeEntryFrontmatterSchema: z.ZodObject<{
2305
2352
  layer_reason: z.ZodOptional<z.ZodString>;
2306
2353
  created_at: z.ZodString;
2307
2354
  }, "strip", z.ZodTypeAny, {
2355
+ created_at: string;
2308
2356
  type: "models" | "decisions" | "guidelines" | "pitfalls" | "processes";
2309
- layer: "personal" | "team";
2310
2357
  id: string;
2358
+ layer: "personal" | "team";
2311
2359
  maturity: "draft" | "verified" | "proven";
2312
- created_at: string;
2313
2360
  layer_reason?: string | undefined;
2314
2361
  }, {
2362
+ created_at: string;
2315
2363
  type: "models" | "decisions" | "guidelines" | "pitfalls" | "processes";
2316
- layer: "personal" | "team";
2317
2364
  id: string;
2365
+ layer: "personal" | "team";
2318
2366
  maturity: "draft" | "verified" | "proven";
2319
- created_at: string;
2320
2367
  layer_reason?: string | undefined;
2321
2368
  }>;
2322
2369
  type KnowledgeEntryFrontmatter = z.infer<typeof KnowledgeEntryFrontmatterSchema>;
@@ -42,7 +42,7 @@ import {
42
42
  recallInputSchema,
43
43
  recallOutputSchema,
44
44
  structuredWarningSchema
45
- } from "../chunk-WVPDH4BF.js";
45
+ } from "../chunk-JEXTOQVV.js";
46
46
  export {
47
47
  FabExtractKnowledgeInputSchema,
48
48
  FabExtractKnowledgeInputShape,
@@ -51,6 +51,6 @@ declare const LEGACY_KB_REGEX: RegExp;
51
51
  *
52
52
  * Length guarantee: ≥ 800 bytes (rc.24: grew from ≥400 with cite-contract syntax).
53
53
  */
54
- declare const BOOTSTRAP_CANONICAL = "# Fabric Bootstrap\n\n\u672C\u9879\u76EE\u4F7F\u7528 Fabric \u7BA1\u7406\u8DE8\u5BA2\u6237\u7AEF AI \u77E5\u8BC6\u4E0E\u884C\u4E3A\u89C4\u5219\u3002\u672C\u6587\u4EF6\u7531 `fabric install` \u540C\u6B65\u5230\u4E09\u7AEF managed block,**\u4E0D\u8981\u624B\u52A8\u7F16\u8F91\u4E09\u7AEF\u7684 block**,\u53EA\u6539\u8FD9\u91CC + \u91CD\u8DD1 `fabric install`\u3002\n\n## For Developers\n\n\u8FD9\u4E2A\u6587\u4EF6\u662F **AI \u5BA2\u6237\u7AEF\u7684\u7B56\u7565\u4E0E\u89C4\u7EA6\u914D\u7F6E**,\u4E0D\u662F dev onboarding\u3002\u4F60\u4E0D\u9700\u8981\u8BFB Self-archive / Cite / Phase 0.4 \u7B49\u7EC6\u8282\u3002\n\u4F5C\u4E3A dev \u4F60\u53EA\u9700\u8981:\u5728\u6BCF\u4E2A repo \u8DD1\u4E00\u6B21 `fabric install`,\u51FA\u95EE\u9898\u8DD1 `fabric doctor`,\u5728 `.fabric/knowledge/<type>/` \u4E0B\u5199 markdown\u3002\n**\u4E25\u7981\u624B\u52A8\u7F16\u8F91 `.fabric/agents.meta.json`** \u2014 \u6D3E\u751F\u72B6\u6001\u7531 engine \u91CD\u5EFA\u3002\n\n## 5 \u5206\u949F\u4E0A\u624B (Dev Quickstart)\n\n**Fabric \u662F\u4EC0\u4E48**:\u8DE8\u5BA2\u6237\u7AEF(Claude Code / Codex CLI / Cursor)\u7684 AI \u77E5\u8BC6\u5C42\u3002\u628A\u56E2\u961F/\u9879\u76EE\u7684 **decisions / pitfalls / guidelines / models / processes** \u5B58\u4E3A markdown,hook \u81EA\u52A8 surface \u7ED9 AI,\u8BA9 AI \u4E0D\u7528\u6BCF\u6B21\u91CD\u5B66\u3002\n\n**\u4F60\u8981\u505A\u7684 (DO)** vs **engine \u81EA\u52A8\u7684 (DON'T \u624B\u52A8)**:\n\n| \u4F60 DO | \u4F60 DON'T |\n| --- | --- |\n| \u6BCF\u4E2A repo \u8DD1\u4E00\u6B21 `fabric install` | \u624B\u7F16 `.fabric/agents.meta.json` |\n| \u5F02\u5E38\u65F6\u8DD1 `fabric doctor` (--fix \u81EA\u6108) | \u624B\u7F16 `.claude/hooks/` \u4E0B `.cjs` |\n| \u5728 `.fabric/knowledge/<type>/` \u4E0B\u5199 markdown | \u64CD\u5FC3 Phase 0.4 / E3 / cite policy |\n| `npm install -g @fenglimg/fabric-cli@latest` \u5347\u7EA7 | \u80CC 35 \u6761 doctor lint \u4EE3\u7801 |\n\n**4 \u6B65\u5FAA\u73AF**: `fabric install` (\u4E00\u6B21) \u2192 AI \u6B63\u5E38\u5DE5\u4F5C (hook on session start + edit) \u2192 AI \u63D0\u8BAE\u6761\u76EE\u5165 `.fabric/knowledge/pending/` \u2192 \u7528 `fabric-review` skill \u6216 `fabric doctor --fix` \u5BA1\u6838\u5F52\u6863\u3002\n\n**\u771F\u4F8B**:\u67D0 sprite \u9ED1\u8FB9 root cause \u662F `atlas.premultiplyAlpha` flag \u53CD\u5411 \u2014 \u5199\u8FDB `.fabric/knowledge/pitfalls/` \u540E,\u4E0B\u6B21\u540C\u7C7B\u95EE\u9898 AI \u81EA\u52A8 reference\u3002\n\n\u5B8C\u6574 maintainer \u7248\u89C1 `docs/USER-QUICKSTART.md`\u3002\n\n## \u884C\u4E3A\u89C4\u5219\n- **\u4FEE\u6539\u4EFB\u4F55\u6587\u4EF6\u524D**:\u4F18\u5148\u5355\u6B65 `fab_recall(paths=[<\u88AB\u6539\u6587\u4EF6>])` \u2014\u2014 \u4E00\u6B21\u8C03\u7528\u76F4\u63A5\u62FF\u56DE\u6240\u6709\u76F8\u5173 KB \u6B63\u6587(rc.37+ \u9ED8\u8BA4\u8DEF\u5F84,\u7701\u6389\u624B\u52A8\u6311 id \u7684\u73AF\u8282)\u3002**\u4EC5\u5F53\u5355\u6B65\u62C9\u56DE\u7684\u6B63\u6587\u8FC7\u591A\u3001\u5BFC\u81F4\u4E0A\u4E0B\u6587\u8FC7\u8F7D\u9700\u7CBE\u786E\u88C1\u526A\u566A\u97F3\u65F6**\u624D\u8D70\u4E24\u6B65:\u5148 `fab_plan_context(paths=[...])` \u62FF `selection_token` + \u9876\u5C42 `candidates[]`(\u4ECE `candidates[].stable_id` \u6311),\u518D `fab_get_knowledge_sections({ selection_token, ai_selected_stable_ids: [<id>...] })` \u53D6\u6B63\u6587\u3002\n- **`.fabric/agents.meta.json` \u4E25\u7981\u624B\u52A8\u7F16\u8F91**;engine \u4F1A\u81EA\u52A8\u540C\u6B65\u6D3E\u751F\u72B6\u6001,\u663E\u5F0F reconcile \u8DD1 `fabric doctor --fix`\u3002\n\n## \u77E5\u8BC6\u5E93(KB)\n- **Discovery**:SessionStart hook \u5217 broad-scoped \u6761\u76EE(\u542B personal layer `KP-*` \u6761\u76EE,\u5F15\u7528\u65B9\u5F0F\u76F8\u540C);edit \u6587\u4EF6\u65F6 PreToolUse hook \u53EF\u80FD\u89E6\u53D1 narrow hint\u3002\n- **Usage**:\u5E38\u6001\u8D70\u5355\u6B65 `fab_recall(paths=[...])` \u4E00\u6B21\u62FF\u56DE\u76F8\u5173 KB \u6B63\u6587\u3002\u4EC5\u5F53\u5355\u6B65\u6B63\u6587\u8FC7\u591A\u81F4\u4E0A\u4E0B\u6587\u8FC7\u8F7D\u3001\u9700\u7CBE\u786E\u88C1\u526A\u566A\u97F3\u65F6\u624D\u4E24\u6B65:`fab_plan_context(paths=[...])` \u8FD4\u56DE `selection_token` + \u9876\u5C42 `candidates[]`,\u518D `fab_get_knowledge_sections({ selection_token, ai_selected_stable_ids: [<\u4ECE candidates[].stable_id \u6311>...] })` \u62C9\u5168\u6587;`selection_token` \u5FC5\u987B\u6765\u81EA\u6700\u8FD1\u4E00\u6B21 `fab_plan_context`,\u4E0D\u53EF\u51ED\u7A7A\u7F16\u9020\u3002\n- **session_id**: \u8C03\u7528 `fab_recall` / `fab_plan_context` \u65F6, \u52A1\u5FC5\u628A\u5F53\u524D client session id \u4F5C\u4E3A `session_id` \u53C2\u6570\u4F20\u5165(Claude Code \u7684 session id \u5728 stdin payload \u4E2D, Codex \u7684\u5BF9\u5E94 identifier \u540C\u7406)\u3002\u8FD9\u80FD\u8BA9 `fabric doctor --archive-history` \u4E0E archive-hint hook \u51C6\u786E\u8BC6\u522B\u8DE8\u4F1A\u8BDD debt \u72B6\u6001\u3002\n- **Write flows**:`fabric-archive` / `fabric-review` / `fabric-import` \u4E09\u4E2A Skills\u3002\n- **Language**:\u6E32\u67D3\u6309 `.fabric/fabric-config.json` \u7684 `fabric_language` \u5B57\u6BB5\u3002\n- **Archive cadence nudge** (rc.36): \u6BCF\u5B8C\u6210 5+ \u6B21 Edit / \u663E\u8457 decision \u540E,\u5728\u5408\u9002\u56DE\u5408\u4E3B\u52A8 propose \u8C03 `fabric-archive` skill \u2014 archive \u6CA1\u5EFA\u7ACB\u9891\u7387\u4F1A\u8BA9 KB \u6162\u901F\u6B7B\u6389\u3002\n- **Review backlog nudge** (rc.36): `.fabric/knowledge/pending/` \u7D2F\u79EF >10 \u6761\u65F6,\u5728\u5408\u9002\u56DE\u5408\u4E3B\u52A8 propose \u8C03 `fabric-review` skill \u6279\u91CF\u5BA1,\u907F\u514D draft \u5361\u6B7B\u3002\n\n## Self-archive policy (v2.0.0-rc.37 NEW-2: \u7B80\u5316 4 \u4FE1\u53F7 \u2192 2 \u5927\u7C7B)\n\n- **\u89E6\u53D1** (\u672C\u4F1A\u8BDD\u51FA\u73B0\u4EE5\u4E0B\u4EFB\u4E00\u4FE1\u53F7, \u5728\u8BE5 turn \u56DE\u590D\u672B\u5C3E\u81EA\u4E3B\u8C03\u7528 `fabric-archive` skill, \u8D70 AI \u81EA\u89E6\u53D1\u5165\u53E3 E3_ai_self_trigger):\n 1. **User-driven normative** \u2014 \u7528\u6237\u6D88\u606F\u4E2D\u663E\u5F0F\u8868\u8FBE normative \u610F\u56FE: `\u4EE5\u540E` / `always` / `never` / `from now on` / `\u4E0B\u6B21\u6CE8\u610F` / `\u8BB0\u4E00\u4E0B` / `\u6C38\u8FDC\u4E0D\u8981`, OR \u7528\u6237\u5728 \u22652 \u5019\u9009\u95F4\u6743\u8861\u540E\u7ED9\u51FA rationale \u9501\u5B9A\u65B9\u5411, OR \u7528\u6237\u62D2\u4E86\u67D0\u5EFA\u8BAE**\u5E76**\u8BF4\u4E86\u539F\u56E0 (\u62D2\u7EDD\u7406\u7531\u672C\u8EAB\u662F\u77E5\u8BC6)\n 2. **Wrong-turn-and-revert** \u2014 AI \u5C1D\u8BD5 path X, \u53CD\u601D\u540E\u6539\u8D70 path Y (\u5C24\u5176\u5F53 path X \u662F\u975E\u663E\u7136\u8E29\u5751); \u6DB5\u76D6\u6280\u672F\u51B3\u7B56\u53CD\u8F6C + \u5DE5\u5177/\u8303\u5F0F\u5207\u6362 + \u5931\u8D25\u91CD\u8BD5\u3002Anchor: \u4E00\u5B9A\u6709\"\u5426\u5B9A+\u66FF\u4EE3\"\u7684\u4E24\u6B65\u7ED3\u6784, \u4E0D\u662F\u5355\u7EAF\u63A2\u7D22\u5931\u8D25\n\n \u8001 4-state (Normative / Decision-confirmation / Explicit-dismissal / Wrong-turn) \u73B0\u5408\u5E76: \u524D 3 \u4E2A\u5168\u662F\"\u7528\u6237\u6D88\u606F\u4E2D\u663E\u5F0F\u8868\u8FBE\"\u6027\u8D28, \u6298\u6210 1 \u7C7B; \u7B2C 4 \u662F\"AI \u81EA\u5DF1\u7684\u53CD\u601D\u8DEF\u5F84\", \u72EC\u7ACB 1 \u7C7B\u3002\u4E24\u7C7B\u5404\u81EA\u7684\u672C\u8D28\u5224\u522B\u4E0D\u53D8, \u89E6\u53D1\u9762\u6CA1\u53D8\u7A84\u3002\n\n- **Anti-trigger** (\u660E\u786E\u4E0D\u89E6\u53D1):\n - \u7528\u6237\u7EAF\u8BE2\u95EE (\u65E0 normative \u8868\u8FBE)\n - \u7B80\u5355 refactor / typo fix\n - AI \u81EA\u5DF1\u4EA7\u751F\u7684'\u6D1E\u5BDF' (\u5FC5\u987B\u7531\u7528\u6237\u6D88\u606F\u4E2D\u4FE1\u53F7\u6216 AI \u81EA\u5DF1\u7684 wrong-turn \u89E6\u53D1, \u4E0D\u662F\u51ED\u7A7A\"\u6211\u5B66\u5230\u4E86\"\u6027\u8D28)\n\n- **Anti-loop \u4E09\u6761\u9632\u62A4**:\n - \u540C turn \u6700\u591A\u81EA\u8C03 1 \u6B21\n - \u540C session \u540C outcome \u4E0D\u91CD\u590D (\u82E5 user_dismissed, \u672C\u4F1A\u8BDD\u4E0D\u518D\u81EA\u8C03\u76F8\u540C\u4E3B\u9898)\n - Phase 2.5 viability gate \u515C\u5E95 (skill \u5185\u90E8\u4ECD\u8DD1 gate, AI \u5224\u9519\u4E0D\u4F1A\u4E71\u5199 pending)\n\n- **\u5448\u73B0\u6A21\u677F** (turn \u672B\u5C3E\u63D2\u5165, \u4E24\u884C: \u5148 marker \u884C\u4F9B Phase 1.5 \u68C0\u6D4B, \u518D user-facing \u63D0\u793A):\n ```\n self-archive policy triggered by signal: <User-driven normative|Wrong-turn-and-revert>\n \u987A\u624B\u5F52\u6863: \u6CE8\u610F\u5230\u4F60\u8BF4 `<\u89E6\u53D1\u77ED\u8BED>`, \u5DF2\u8C03\u7528 fabric-archive \u6293 N \u6761\u5019\u9009 \u2192 .fabric/knowledge/pending/...\n \u82E5\u4E0D\u8BE5\u8BB0, \u7B54 '\u64A4\u9500' \u6211\u4F1A\u8C03 fab_review reject\u3002\n ```\n \u7B2C\u4E00\u884C\u662F Phase 1.5 Trigger Gate \u8BC6\u522B E3 \u5165\u53E3\u7684 structured marker (verbatim \u5B57\u7B26\u4E32 `self-archive policy triggered by signal`, \u540E\u63A5\u5192\u53F7 + \u89E6\u53D1\u4FE1\u53F7\u540D)\u3002\u7B2C\u4E8C\u884C\u8D77\u662F\u7ED9\u7528\u6237\u770B\u7684\u4E2D\u6587\u63D0\u793A\u3002\u4E24\u884C\u90FD\u5FC5\u987B\u51FA\u73B0; \u7F3A marker \u884C Phase 1.5 \u65E0\u6CD5\u8DEF\u7531\u5230 E3_ai_self_trigger\u3002\n\n Backward compat: Phase 1.5 entry-point regex \u540C\u65F6\u8BC6\u522B\u8001 4 \u4E2A\u4FE1\u53F7\u540D (Normative / Wrong-turn-and-revert / Decision confirmation / Explicit dismissal) \u4E0E\u65B0 2 \u5927\u7C7B\u540D, \u65E7 session marker \u4ECD\u80FD\u6B63\u786E\u8DEF\u7531\u3002\n\n## Cite policy (v2.0.0-rc.37 NEW-1: \u7B80\u5316 4-state \u2192 2-state)\n\n- **\u89E6\u53D1**: \u505A edit / decide / propose plan \u4E4B\u524D,**\u56DE\u590D\u9996\u884C**\u5FC5\u987B\u5199 `KB: <id> (<\u22648\u5B57 \u7528\u6CD5>) [applied|dismissed:<reason>]` \u6216 `KB: none [<reason>]`\u3002\n- **`[applied]` \u9A8C\u8BC1\u4E49\u52A1**: \u5F15\u7528\u4EFB\u4F55 id \u524D\u5FC5\u987B\u5148\u7528 fab_recall (\u6216\u4E24\u6B65 fab_plan_context \u2192 fab_get_knowledge_sections) \u5B9E\u9645\u6293 KB body, \u9632\u6B62\u7F16\u9020 id\u3002\u9A8C\u8BC1\u4E0D\u901A\u8FC7 = \u4E0D\u80FD cite\u3002\n- **contract \u8BED\u6CD5**: decisions/pitfalls \u7C7B `[applied]` cite \u5C3E\u6BB5\u52A0 contract: `\u2192 <operator> [<operator> ...]`,operator \u2208 {`edit:<glob>` `!edit:<glob>` `require:<symbol>` `forbid:<symbol>` `skip:<reason>`}\u3002\u4F8B:`KB: K-001 (auth) [applied] \u2192 edit:src/auth/**/*.ts !edit:src/legacy/**`\u3002\n- **skip reason \u8BCD\u5178**: `sequencing | conditional | semantic | aesthetic | architectural | other:<text>`\u3002\n- **type \u8DEF\u7531**: models \u7C7B\u5F15\u7528\u4E3A reference cite,\u4E0D\u9700\u8981 contract;guidelines/processes \u7C7B\u6682\u4E0D\u5F3A\u5236,\u63A8\u540E LLM-judge\u3002\n- **\u7528\u6237\u53E3\u5934\u63D0\u89C4\u5219\u6CA1\u7ED9 id**: \u5148\u8C03 `fab_recall(paths)` \u6216 `fab_extract_knowledge` \u53CD\u67E5\u3002\n- **dismissed reason**: \u679A\u4E3E `scope-mismatch | outdated | not-applicable | other:<text>`\u3002\n- **`KB: none` sentinel**: \u679A\u4E3E\u4E24\u79CD\u5408\u89C4\u7406\u7531\u2014\u2014`[no-relevant]` \u5DF2\u8C03 `fab_recall` / `fab_plan_context`(\u6216 hook \u8F93\u51FA\u53EF\u89C1)\u4F46\u65E0\u53EF\u7528\u6761\u76EE;`[not-applicable]` \u5F53\u524D\u52A8\u4F5C\u4E0D\u5728 cite \u8303\u56F4(\u7EAF\u63A2\u7D22 / Bash \u53EA\u8BFB / \u7528\u6237\u95EE\u7B54)\u3002\u88F8 `KB: none`(\u65E0\u540E\u7F00)\u4ECD\u7136 valid,\u5F52\u7C7B\u4E3A `[unspecified]`(legacy \u517C\u5BB9,\u9F13\u52B1\u540E\u7EED\u8865\u6CE8)\u3002\n- **\u7A3D\u6838**: `fabric doctor --cite-coverage [--since=7d] [--client=cc|codex|all]` \u8F93\u51FA cite \u8986\u76D6\u7387,\u542B `KB: none` sentinel \u62C6\u5206\u3002\u672C\u89C4\u5219\u4E0D\u963B\u65AD\u4F60\u5DE5\u4F5C,\u53EA\u8BB0\u5F55\u3002\n- **Backward compat**: \u89E3\u6790\u5668\u540C\u65F6\u63A5\u53D7\u8001 4-state tags (`planned` / `recalled` / `chained-from <id>`) \u2014 \u90FD\u6620\u5C04\u5230 `[applied]` \u8BED\u4E49,gradually \u8FC1\u5230\u65B0\u7B80\u5316\u5F62\u6001\u5373\u53EF,\u65E7 session \u7559\u4E0B\u7684 cite \u4ECD\u7136\u8BA1\u5165 cite-coverage\u3002\n";
54
+ declare const BOOTSTRAP_CANONICAL = "# Fabric Bootstrap\n\n\u672C\u9879\u76EE\u4F7F\u7528 Fabric \u7BA1\u7406\u8DE8\u5BA2\u6237\u7AEF AI \u77E5\u8BC6\u4E0E\u884C\u4E3A\u89C4\u5219\u3002\u672C\u6587\u4EF6\u7531 `fabric install` \u540C\u6B65\u5230\u4E09\u7AEF managed block,**\u4E0D\u8981\u624B\u52A8\u7F16\u8F91\u4E09\u7AEF\u7684 block**,\u53EA\u6539\u8FD9\u91CC + \u91CD\u8DD1 `fabric install`\u3002\n\n## For Developers\n\n\u8FD9\u4E2A\u6587\u4EF6\u662F **AI \u5BA2\u6237\u7AEF\u7684\u7B56\u7565\u4E0E\u89C4\u7EA6\u914D\u7F6E**,\u4E0D\u662F dev onboarding\u3002\u4F60\u4E0D\u9700\u8981\u8BFB Self-archive / Cite / Phase 0.4 \u7B49\u7EC6\u8282\u3002\n\u4F5C\u4E3A dev \u4F60\u53EA\u9700\u8981:\u5728\u6BCF\u4E2A repo \u8DD1\u4E00\u6B21 `fabric install`,\u51FA\u95EE\u9898\u8DD1 `fabric doctor`,\u5728 `.fabric/knowledge/<type>/` \u4E0B\u5199 markdown\u3002\n**\u4E25\u7981\u624B\u52A8\u7F16\u8F91 `.fabric/agents.meta.json`** \u2014 \u6D3E\u751F\u72B6\u6001\u7531 engine \u91CD\u5EFA\u3002\n\n## 5 \u5206\u949F\u4E0A\u624B (Dev Quickstart)\n\n**Fabric \u662F\u4EC0\u4E48**:\u8DE8\u5BA2\u6237\u7AEF(Claude Code / Codex CLI / Cursor)\u7684 AI \u77E5\u8BC6\u5C42\u3002\u628A\u56E2\u961F/\u9879\u76EE\u7684 **decisions / pitfalls / guidelines / models / processes** \u5B58\u4E3A markdown,hook \u81EA\u52A8 surface \u7ED9 AI,\u8BA9 AI \u4E0D\u7528\u6BCF\u6B21\u91CD\u5B66\u3002\n\n**\u4F60\u8981\u505A\u7684 (DO)** vs **engine \u81EA\u52A8\u7684 (DON'T \u624B\u52A8)**:\n\n| \u4F60 DO | \u4F60 DON'T |\n| --- | --- |\n| \u6BCF\u4E2A repo \u8DD1\u4E00\u6B21 `fabric install` | \u624B\u7F16 `.fabric/agents.meta.json` |\n| \u5F02\u5E38\u65F6\u8DD1 `fabric doctor` (--fix \u81EA\u6108) | \u624B\u7F16 `.claude/hooks/` \u4E0B `.cjs` |\n| \u5728 `.fabric/knowledge/<type>/` \u4E0B\u5199 markdown | \u64CD\u5FC3 Phase 0.4 / E3 / cite policy |\n| `npm install -g @fenglimg/fabric-cli@latest` \u5347\u7EA7 | \u80CC 35 \u6761 doctor lint \u4EE3\u7801 |\n\n**4 \u6B65\u5FAA\u73AF**: `fabric install` (\u4E00\u6B21) \u2192 AI \u6B63\u5E38\u5DE5\u4F5C (hook on session start + edit) \u2192 AI \u63D0\u8BAE\u6761\u76EE\u5165 `.fabric/knowledge/pending/` \u2192 \u7528 `fabric-review` skill \u6216 `fabric doctor --fix` \u5BA1\u6838\u5F52\u6863\u3002\n\n**\u771F\u4F8B**:\u67D0 sprite \u9ED1\u8FB9 root cause \u662F `atlas.premultiplyAlpha` flag \u53CD\u5411 \u2014 \u5199\u8FDB `.fabric/knowledge/pitfalls/` \u540E,\u4E0B\u6B21\u540C\u7C7B\u95EE\u9898 AI \u81EA\u52A8 reference\u3002\n\n\u5B8C\u6574 maintainer \u7248\u89C1 `docs/USER-QUICKSTART.md`\u3002\n\n## \u884C\u4E3A\u89C4\u5219\n- **\u4FEE\u6539\u4EFB\u4F55\u6587\u4EF6\u524D**:\u4F18\u5148\u5355\u6B65 `fab_recall(paths=[<\u88AB\u6539\u6587\u4EF6>])` \u2014\u2014 \u4E00\u6B21\u8C03\u7528\u76F4\u63A5\u62FF\u56DE\u6240\u6709\u76F8\u5173 KB \u6B63\u6587(rc.37+ \u9ED8\u8BA4\u8DEF\u5F84,\u7701\u6389\u624B\u52A8\u6311 id \u7684\u73AF\u8282)\u3002**\u4EC5\u5F53\u5355\u6B65\u62C9\u56DE\u7684\u6B63\u6587\u8FC7\u591A\u3001\u5BFC\u81F4\u4E0A\u4E0B\u6587\u8FC7\u8F7D\u9700\u7CBE\u786E\u88C1\u526A\u566A\u97F3\u65F6**\u624D\u8D70\u4E24\u6B65:\u5148 `fab_plan_context(paths=[...])` \u62FF `selection_token` + \u9876\u5C42 `candidates[]`(\u4ECE `candidates[].stable_id` \u6311),\u518D `fab_get_knowledge_sections({ selection_token, ai_selected_stable_ids: [<id>...] })` \u53D6\u6B63\u6587\u3002\n- **`.fabric/agents.meta.json` \u4E25\u7981\u624B\u52A8\u7F16\u8F91**;engine \u4F1A\u81EA\u52A8\u540C\u6B65\u6D3E\u751F\u72B6\u6001,\u663E\u5F0F reconcile \u8DD1 `fabric doctor --fix`\u3002\n\n## \u77E5\u8BC6\u5E93(KB)\n- **Discovery**:SessionStart hook \u5217 broad-scoped \u6761\u76EE(\u542B personal layer `KP-*` \u6761\u76EE,\u5F15\u7528\u65B9\u5F0F\u76F8\u540C);edit \u6587\u4EF6\u65F6 PreToolUse hook \u53EF\u80FD\u89E6\u53D1 narrow hint\u3002\n- **Usage**:\u5E38\u6001\u8D70\u5355\u6B65 `fab_recall(paths=[...])` \u4E00\u6B21\u62FF\u56DE\u76F8\u5173 KB \u6B63\u6587\u3002\u4EC5\u5F53\u5355\u6B65\u6B63\u6587\u8FC7\u591A\u81F4\u4E0A\u4E0B\u6587\u8FC7\u8F7D\u3001\u9700\u7CBE\u786E\u88C1\u526A\u566A\u97F3\u65F6\u624D\u4E24\u6B65:`fab_plan_context(paths=[...])` \u8FD4\u56DE `selection_token` + \u9876\u5C42 `candidates[]`,\u518D `fab_get_knowledge_sections({ selection_token, ai_selected_stable_ids: [<\u4ECE candidates[].stable_id \u6311>...] })` \u62C9\u5168\u6587;`selection_token` \u5FC5\u987B\u6765\u81EA\u6700\u8FD1\u4E00\u6B21 `fab_plan_context`,\u4E0D\u53EF\u51ED\u7A7A\u7F16\u9020\u3002\n- **session_id**: \u8C03\u7528 `fab_recall` / `fab_plan_context` \u65F6, \u52A1\u5FC5\u628A\u5F53\u524D client session id \u4F5C\u4E3A `session_id` \u53C2\u6570\u4F20\u5165(Claude Code \u7684 session id \u5728 stdin payload \u4E2D, Codex \u7684\u5BF9\u5E94 identifier \u540C\u7406)\u3002\u8FD9\u80FD\u8BA9 `fabric doctor --archive-history` \u4E0E archive-hint hook \u51C6\u786E\u8BC6\u522B\u8DE8\u4F1A\u8BDD debt \u72B6\u6001\u3002\n- **Write flows**:`fabric-archive` / `fabric-review` / `fabric-import` \u4E09\u4E2A Skills\u3002\n- **Language**:\u6E32\u67D3\u6309 `.fabric/fabric-config.json` \u7684 `fabric_language` \u5B57\u6BB5\u3002\n- **Archive cadence nudge** (rc.36): \u6BCF\u5B8C\u6210 5+ \u6B21 Edit / \u663E\u8457 decision \u540E,\u5728\u5408\u9002\u56DE\u5408\u4E3B\u52A8 propose \u8C03 `fabric-archive` skill \u2014 archive \u6CA1\u5EFA\u7ACB\u9891\u7387\u4F1A\u8BA9 KB \u6162\u901F\u6B7B\u6389\u3002\n- **Review backlog nudge** (rc.36): `.fabric/knowledge/pending/` \u7D2F\u79EF >10 \u6761\u65F6,\u5728\u5408\u9002\u56DE\u5408\u4E3B\u52A8 propose \u8C03 `fabric-review` skill \u6279\u91CF\u5BA1,\u907F\u514D draft \u5361\u6B7B\u3002\n\n## Self-archive policy (v2.0.0-rc.37 NEW-2: \u7B80\u5316 4 \u4FE1\u53F7 \u2192 2 \u5927\u7C7B)\n\n- **\u89E6\u53D1** (\u672C\u4F1A\u8BDD\u51FA\u73B0\u4EE5\u4E0B\u4EFB\u4E00\u4FE1\u53F7, \u5728\u8BE5 turn \u56DE\u590D\u672B\u5C3E\u81EA\u4E3B\u8C03\u7528 `fabric-archive` skill, \u8D70 AI \u81EA\u89E6\u53D1\u5165\u53E3 E3_ai_self_trigger):\n 1. **User-driven normative** \u2014 \u7528\u6237\u6D88\u606F\u4E2D\u663E\u5F0F\u8868\u8FBE normative \u610F\u56FE: `\u4EE5\u540E` / `always` / `never` / `from now on` / `\u4E0B\u6B21\u6CE8\u610F` / `\u8BB0\u4E00\u4E0B` / `\u6C38\u8FDC\u4E0D\u8981`, OR \u7528\u6237\u5728 \u22652 \u5019\u9009\u95F4\u6743\u8861\u540E\u7ED9\u51FA rationale \u9501\u5B9A\u65B9\u5411, OR \u7528\u6237\u62D2\u4E86\u67D0\u5EFA\u8BAE**\u5E76**\u8BF4\u4E86\u539F\u56E0 (\u62D2\u7EDD\u7406\u7531\u672C\u8EAB\u662F\u77E5\u8BC6)\n 2. **Wrong-turn-and-revert** \u2014 AI \u5C1D\u8BD5 path X, \u53CD\u601D\u540E\u6539\u8D70 path Y (\u5C24\u5176\u5F53 path X \u662F\u975E\u663E\u7136\u8E29\u5751); \u6DB5\u76D6\u6280\u672F\u51B3\u7B56\u53CD\u8F6C + \u5DE5\u5177/\u8303\u5F0F\u5207\u6362 + \u5931\u8D25\u91CD\u8BD5\u3002Anchor: \u4E00\u5B9A\u6709\"\u5426\u5B9A+\u66FF\u4EE3\"\u7684\u4E24\u6B65\u7ED3\u6784, \u4E0D\u662F\u5355\u7EAF\u63A2\u7D22\u5931\u8D25\n\n \u8001 4-state (Normative / Decision-confirmation / Explicit-dismissal / Wrong-turn) \u73B0\u5408\u5E76: \u524D 3 \u4E2A\u5168\u662F\"\u7528\u6237\u6D88\u606F\u4E2D\u663E\u5F0F\u8868\u8FBE\"\u6027\u8D28, \u6298\u6210 1 \u7C7B; \u7B2C 4 \u662F\"AI \u81EA\u5DF1\u7684\u53CD\u601D\u8DEF\u5F84\", \u72EC\u7ACB 1 \u7C7B\u3002\u4E24\u7C7B\u5404\u81EA\u7684\u672C\u8D28\u5224\u522B\u4E0D\u53D8, \u89E6\u53D1\u9762\u6CA1\u53D8\u7A84\u3002\n\n- **Anti-trigger** (\u660E\u786E\u4E0D\u89E6\u53D1):\n - \u7528\u6237\u7EAF\u8BE2\u95EE (\u65E0 normative \u8868\u8FBE)\n - \u7B80\u5355 refactor / typo fix\n - AI \u81EA\u5DF1\u4EA7\u751F\u7684'\u6D1E\u5BDF' (\u5FC5\u987B\u7531\u7528\u6237\u6D88\u606F\u4E2D\u4FE1\u53F7\u6216 AI \u81EA\u5DF1\u7684 wrong-turn \u89E6\u53D1, \u4E0D\u662F\u51ED\u7A7A\"\u6211\u5B66\u5230\u4E86\"\u6027\u8D28)\n\n- **Anti-loop \u4E09\u6761\u9632\u62A4**:\n - \u540C turn \u6700\u591A\u81EA\u8C03 1 \u6B21\n - \u540C session \u540C outcome \u4E0D\u91CD\u590D (\u82E5 user_dismissed, \u672C\u4F1A\u8BDD\u4E0D\u518D\u81EA\u8C03\u76F8\u540C\u4E3B\u9898)\n - Phase 2.5 viability gate \u515C\u5E95 (skill \u5185\u90E8\u4ECD\u8DD1 gate, AI \u5224\u9519\u4E0D\u4F1A\u4E71\u5199 pending)\n\n- **\u5448\u73B0\u6A21\u677F** (turn \u672B\u5C3E\u63D2\u5165, \u4E24\u884C: \u5148 marker \u884C\u4F9B Phase 1.5 \u68C0\u6D4B, \u518D user-facing \u63D0\u793A):\n ```\n self-archive policy triggered by signal: <User-driven normative|Wrong-turn-and-revert>\n \u987A\u624B\u5F52\u6863: \u6CE8\u610F\u5230\u4F60\u8BF4 `<\u89E6\u53D1\u77ED\u8BED>`, \u5DF2\u8C03\u7528 fabric-archive \u6293 N \u6761\u5019\u9009 \u2192 .fabric/knowledge/pending/...\n \u82E5\u4E0D\u8BE5\u8BB0, \u7B54 '\u64A4\u9500' \u6211\u4F1A\u8C03 fab_review reject\u3002\n ```\n \u7B2C\u4E00\u884C\u662F Phase 1.5 Trigger Gate \u8BC6\u522B E3 \u5165\u53E3\u7684 structured marker (verbatim \u5B57\u7B26\u4E32 `self-archive policy triggered by signal`, \u540E\u63A5\u5192\u53F7 + \u89E6\u53D1\u4FE1\u53F7\u540D)\u3002\u7B2C\u4E8C\u884C\u8D77\u662F\u7ED9\u7528\u6237\u770B\u7684\u4E2D\u6587\u63D0\u793A\u3002\u4E24\u884C\u90FD\u5FC5\u987B\u51FA\u73B0; \u7F3A marker \u884C Phase 1.5 \u65E0\u6CD5\u8DEF\u7531\u5230 E3_ai_self_trigger\u3002\n\n Backward compat: Phase 1.5 entry-point regex \u540C\u65F6\u8BC6\u522B\u8001 4 \u4E2A\u4FE1\u53F7\u540D (Normative / Wrong-turn-and-revert / Decision confirmation / Explicit dismissal) \u4E0E\u65B0 2 \u5927\u7C7B\u540D, \u65E7 session marker \u4ECD\u80FD\u6B63\u786E\u8DEF\u7531\u3002\n\n## Cite policy (v2.0.0-rc.37 NEW-1: \u7B80\u5316 4-state \u2192 2-state)\n\n- **\u89E6\u53D1**: \u505A edit / decide / propose plan \u4E4B\u524D,**\u56DE\u590D\u9996\u884C**\u5FC5\u987B\u5199 `KB: <id> (<\u22648\u5B57 \u7528\u6CD5>) [applied|dismissed:<reason>]` \u6216 `KB: none [<reason>]`\u3002\n- **`[applied]` \u9A8C\u8BC1\u4E49\u52A1**: \u5F15\u7528\u4EFB\u4F55 id \u524D\u5FC5\u987B\u5148\u7528 fab_recall (\u6216\u4E24\u6B65 fab_plan_context \u2192 fab_get_knowledge_sections) \u5B9E\u9645\u6293 KB body, \u9632\u6B62\u7F16\u9020 id\u3002\u9A8C\u8BC1\u4E0D\u901A\u8FC7 = \u4E0D\u80FD cite\u3002\n- **store \u524D\u7F00 (v2.1, \u591A store)**: \u5F53 read-set \u542B\u591A\u4E2A store \u4E14\u540C\u4E00 local id \u5728\u591A store \u95F4 shadow \u65F6,cite \u5FC5\u987B store-qualified: `KB: <store-alias>:<id> ...`(\u5982 `KB: team:KT-DEC-0001 (auth) [applied]`);alias \u7528\u6237\u81EA\u5B9A/canonical,\u5E95\u5C42 UUID\u3002\u5355 store \u6216\u65E0\u6B67\u4E49\u65F6\u88F8 `KB: <id>` \u4ECD valid\u3002personal-only \u6761\u76EE cite \u8FDB\u56E2\u961F\u4EA7\u7269=\u5F3A warning(\u63A5 P2 \u5199\u8DEF\u5F84\u9632\u6CC4\u6F0F R5#3)\u3002\n- **contract \u8BED\u6CD5**: decisions/pitfalls \u7C7B `[applied]` cite \u5C3E\u6BB5\u52A0 contract: `\u2192 <operator> [<operator> ...]`,operator \u2208 {`edit:<glob>` `!edit:<glob>` `require:<symbol>` `forbid:<symbol>` `skip:<reason>`}\u3002\u4F8B:`KB: K-001 (auth) [applied] \u2192 edit:src/auth/**/*.ts !edit:src/legacy/**`\u3002\n- **skip reason \u8BCD\u5178**: `sequencing | conditional | semantic | aesthetic | architectural | other:<text>`\u3002\n- **type \u8DEF\u7531**: models \u7C7B\u5F15\u7528\u4E3A reference cite,\u4E0D\u9700\u8981 contract;guidelines/processes \u7C7B\u6682\u4E0D\u5F3A\u5236,\u63A8\u540E LLM-judge\u3002\n- **\u7528\u6237\u53E3\u5934\u63D0\u89C4\u5219\u6CA1\u7ED9 id**: \u5148\u8C03 `fab_recall(paths)` \u6216 `fab_extract_knowledge` \u53CD\u67E5\u3002\n- **dismissed reason**: \u679A\u4E3E `scope-mismatch | outdated | not-applicable | other:<text>`\u3002\n- **`KB: none` sentinel**: \u679A\u4E3E\u4E24\u79CD\u5408\u89C4\u7406\u7531\u2014\u2014`[no-relevant]` \u5DF2\u8C03 `fab_recall` / `fab_plan_context`(\u6216 hook \u8F93\u51FA\u53EF\u89C1)\u4F46\u65E0\u53EF\u7528\u6761\u76EE;`[not-applicable]` \u5F53\u524D\u52A8\u4F5C\u4E0D\u5728 cite \u8303\u56F4(\u7EAF\u63A2\u7D22 / Bash \u53EA\u8BFB / \u7528\u6237\u95EE\u7B54)\u3002\u88F8 `KB: none`(\u65E0\u540E\u7F00)\u4ECD\u7136 valid,\u5F52\u7C7B\u4E3A `[unspecified]`(legacy \u517C\u5BB9,\u9F13\u52B1\u540E\u7EED\u8865\u6CE8)\u3002\n- **\u7A3D\u6838**: `fabric doctor --cite-coverage [--since=7d] [--client=cc|codex|all]` \u8F93\u51FA cite \u8986\u76D6\u7387,\u542B `KB: none` sentinel \u62C6\u5206\u3002\u672C\u89C4\u5219\u4E0D\u963B\u65AD\u4F60\u5DE5\u4F5C,\u53EA\u8BB0\u5F55\u3002\n- **Backward compat**: \u89E3\u6790\u5668\u540C\u65F6\u63A5\u53D7\u8001 4-state tags (`planned` / `recalled` / `chained-from <id>`) \u2014 \u90FD\u6620\u5C04\u5230 `[applied]` \u8BED\u4E49,gradually \u8FC1\u5230\u65B0\u7B80\u5316\u5F62\u6001\u5373\u53EF,\u65E7 session \u7559\u4E0B\u7684 cite \u4ECD\u7136\u8BA1\u5165 cite-coverage\u3002\n- **\u5B8C\u6574\u53C2\u8003\u4E0B\u6C89** (v2.2 SK5): contract operator / skip\u00B7dismissed \u8BCD\u5178 / \u7C7B\u578B\u8DEF\u7531 / \u7A3D\u6838\u53E3\u5F84 / **\u88C1\u51B3\u9636\u68AF** (AI\u81EA\u51B3 \u2192 \u591A-LLM \u542B\u96F6\u4E0A\u4E0B\u6587\u51B7\u8BC4 \u2192 \u975E\u963B\u585E\u961F\u5217) \u7684\u6743\u5A01\u8BE6\u53C2\u5728 `fabric-review` skill \u7684 `ref/cite-contract.md` \u2014\u2014 bootstrap \u53EA\u7559\u53EF\u6267\u884C core,\u6CBB\u7406\u7EC6\u8282\u5F52 ref \u4E0D\u518D\u6491\u5927 bootstrap\u3002\n";
55
55
 
56
56
  export { BOOTSTRAP_CANONICAL, BOOTSTRAP_MARKER_BEGIN, BOOTSTRAP_MARKER_END, BOOTSTRAP_REGEX, LEGACY_KB_MARKER_BEGIN, LEGACY_KB_MARKER_END, LEGACY_KB_REGEX };