pi-smart-compact 9.5.0 → 9.6.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.
Files changed (44) hide show
  1. package/ARCHITECTURE.md +7 -5
  2. package/CHANGELOG.md +40 -0
  3. package/README.md +35 -19
  4. package/dist/app/global-settings-runtime.d.ts +7 -0
  5. package/dist/app/global-settings-runtime.d.ts.map +1 -0
  6. package/dist/app/register-context-tools.d.ts +4 -1
  7. package/dist/app/register-context-tools.d.ts.map +1 -1
  8. package/dist/app/register-smart-compact-command.d.ts +3 -1
  9. package/dist/app/register-smart-compact-command.d.ts.map +1 -1
  10. package/dist/app/run-context.d.ts +3 -3
  11. package/dist/app/run-context.d.ts.map +1 -1
  12. package/dist/app/smart-compact-policy.d.ts +4 -1
  13. package/dist/app/smart-compact-policy.d.ts.map +1 -1
  14. package/dist/app/steps/tier.d.ts +5 -4
  15. package/dist/app/steps/tier.d.ts.map +1 -1
  16. package/dist/constants.d.ts +43 -1
  17. package/dist/constants.d.ts.map +1 -1
  18. package/dist/domain/tool-semantics.d.ts.map +1 -1
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +1830 -560
  21. package/dist/infra/ai-messages.d.ts.map +1 -1
  22. package/dist/infra/fs.d.ts +2 -1
  23. package/dist/infra/fs.d.ts.map +1 -1
  24. package/dist/phases/explore.d.ts.map +1 -1
  25. package/dist/phases/synthesize.d.ts +5 -0
  26. package/dist/phases/synthesize.d.ts.map +1 -1
  27. package/dist/phases/verify.d.ts.map +1 -1
  28. package/dist/provider-eval.js +157 -54
  29. package/dist/provider-scenario-eval.js +162 -57
  30. package/dist/telemetry-report.js +125 -22
  31. package/dist/ui/overlays.d.ts.map +1 -1
  32. package/dist/ui/settings-complex.d.ts +9 -0
  33. package/dist/ui/settings-complex.d.ts.map +1 -0
  34. package/dist/ui/settings-overlay.d.ts +43 -3
  35. package/dist/ui/settings-overlay.d.ts.map +1 -1
  36. package/dist/utils/config.d.ts +14 -1
  37. package/dist/utils/config.d.ts.map +1 -1
  38. package/dist/utils/file-needles.d.ts +24 -0
  39. package/dist/utils/file-needles.d.ts.map +1 -1
  40. package/dist/utils/file-ref-detect.d.ts +6 -1
  41. package/dist/utils/file-ref-detect.d.ts.map +1 -1
  42. package/dist/utils/helpers.d.ts +1 -0
  43. package/dist/utils/helpers.d.ts.map +1 -1
  44. package/package.json +5 -3
@@ -1 +1 @@
1
- {"version":3,"file":"ai-messages.d.ts","sourceRoot":"","sources":["../../src/infra/ai-messages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAEzD;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,OAAO,EAAE,CAEpE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,cAAc,GAAG,UAAU,EAAE,CAE3F"}
1
+ {"version":3,"file":"ai-messages.d.ts","sourceRoot":"","sources":["../../src/infra/ai-messages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAEzD;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,OAAO,EAAE,CAIpE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,cAAc,GAAG,UAAU,EAAE,CAE3F"}
@@ -25,7 +25,8 @@
25
25
  * `atomicWriteFile` for new async-friendly callers (background metrics).
26
26
  *
27
27
  * Lock acquisition is fail-closed: callers never continue an append/trim
28
- * without ownership. Locks older than 5s are reclaimed with an atomic rename.
28
+ * without ownership. Locks are never stolen on elapsed time because a live,
29
+ * slow owner must not overlap a successor.
29
30
  */
30
31
  /** Ensure a private directory exists and normalize an existing target. */
31
32
  export declare function ensureDir(dir: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../src/infra/fs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAYH,0EAA0E;AAC1E,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAG3C;AAWD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAYnF;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAW9F;AAmCD,gFAAgF;AAChF,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,IAAI,CAI1D;AAYD,+EAA+E;AAC/E,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CASrE;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAoCtF;AAED,+EAA+E;AAC/E,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwC1G;AAED,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,SAAa,GAAG,CAAC,EAAE,CAoB1F;AAED,oEAAoE;AACpE,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBxF;AAGD,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CASxD;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,UAAQ,GAAG,IAAI,CAElF"}
1
+ {"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../src/infra/fs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAWH,0EAA0E;AAC1E,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAG3C;AAWD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAYnF;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAW9F;AA2CD,gFAAgF;AAChF,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,IAAI,CAI1D;AAYD,+EAA+E;AAC/E,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CASrE;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAoCtF;AAED,+EAA+E;AAC/E,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwC1G;AAED,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,SAAa,GAAG,CAAC,EAAE,CAoB1F;AAED,oEAAoE;AACpE,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBxF;AAGD,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CASxD;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,UAAQ,GAAG,IAAI,CAElF"}
@@ -1 +1 @@
1
- {"version":3,"file":"explore.d.ts","sourceRoot":"","sources":["../../src/phases/explore.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,KAAK,EACL,GAAG,EAKH,eAAe,EAChB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EACV,UAAU,EACV,oBAAoB,EACpB,iBAAiB,EAElB,MAAM,aAAa,CAAC;AAcrB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAIjE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAuBpD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,oBAAoB,GAAG,OAAO,CAqBvE;AAoGD,wBAAgB,sBAAsB,CACpC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EAC1D,WAAW,EAAE,UAAU,EAAE,EACzB,QAAQ,iBAAuB,GAC9B,MAAM,CA6MR;AAED,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,UAAU,EAAE,GACxB,iBAAiB,CAkDnB;AA6DD,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,OAAO,EACf,WAAW,EAAE,UAAU,EAAE,GACxB,iBAAiB,CAgCnB;AAED,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,UAAU,EAAE,GACxB,iBAAiB,CAWnB;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,UAAU,EAAE,EACzB,UAAU,EAAE,oBAAoB,EAChC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,eAAe,CAAA;CAAE,EACnD,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,MAAM,CAAC,EAAE,WAAW,EACpB,SAAS,SAAyB,EAClC,MAAM,CAAC,EAAE,CACP,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,KAC5C,IAAI,EACT,QAAQ,CAAC,EAAE,oBAAoB,GAC9B,OAAO,CAAC;IACT,MAAM,EAAE,iBAAiB,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,OAAO,CAAC;CACxB,CAAC,CAkTD"}
1
+ {"version":3,"file":"explore.d.ts","sourceRoot":"","sources":["../../src/phases/explore.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,KAAK,EACL,GAAG,EAKH,eAAe,EAChB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EACV,UAAU,EACV,oBAAoB,EACpB,iBAAiB,EAElB,MAAM,aAAa,CAAC;AAcrB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAIjE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAuBpD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,oBAAoB,GAAG,OAAO,CAqBvE;AAsHD,wBAAgB,sBAAsB,CACpC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EAC1D,WAAW,EAAE,UAAU,EAAE,EACzB,QAAQ,iBAAuB,GAC9B,MAAM,CA6MR;AAED,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,UAAU,EAAE,GACxB,iBAAiB,CAkDnB;AA6DD,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,OAAO,EACf,WAAW,EAAE,UAAU,EAAE,GACxB,iBAAiB,CAgCnB;AAED,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,UAAU,EAAE,GACxB,iBAAiB,CAWnB;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,UAAU,EAAE,EACzB,UAAU,EAAE,oBAAoB,EAChC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,eAAe,CAAA;CAAE,EACnD,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,MAAM,CAAC,EAAE,WAAW,EACpB,SAAS,SAAyB,EAClC,MAAM,CAAC,EAAE,CACP,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,KAC5C,IAAI,EACT,QAAQ,CAAC,EAAE,oBAAoB,GAC9B,OAAO,CAAC;IACT,MAAM,EAAE,iBAAiB,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,OAAO,CAAC;CACxB,CAAC,CAkTD"}
@@ -5,6 +5,11 @@ import type { Model, Api, ProviderHeaders } from "@earendil-works/pi-ai";
5
5
  import type { LlmMessage, LlmChunk, ChunkSummary, StructuredExtraction, ExplorationReport, ProfileConfig, CompactionState } from "../types.ts";
6
6
  import { type TokenEstimator } from "../utils/tokens.ts";
7
7
  import type { SmartCompactServices } from "../infra/services.ts";
8
+ /** A provider response completed, but did not satisfy the batch-output contract. */
9
+ export declare class BatchSummaryFormatError extends Error {
10
+ readonly name = "BatchSummaryFormatError";
11
+ constructor(reason: string);
12
+ }
8
13
  export declare function chunkLlmMessages(msgs: LlmMessage[], boundaries: import("../types.ts").TopicBoundary[], pc: ProfileConfig, estimator?: TokenEstimator, focus?: string): LlmChunk[];
9
14
  export declare function singlePassCompact(convText: string, extraction: StructuredExtraction, report: ExplorationReport | null, prevContext: string, model: Model<Api>, auth: {
10
15
  apiKey: string;
@@ -1 +1 @@
1
- {"version":3,"file":"synthesize.d.ts","sourceRoot":"","sources":["../../src/phases/synthesize.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,KAAK,EACX,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,oBAAoB,EACpB,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,MAAM,aAAa,CAAC;AAYrB,OAAO,EAGN,KAAK,cAAc,EACnB,MAAM,oBAAoB,CAAC;AAU5B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAsNjE,wBAAgB,gBAAgB,CAC/B,IAAI,EAAE,UAAU,EAAE,EAClB,UAAU,EAAE,OAAO,aAAa,EAAE,aAAa,EAAE,EACjD,EAAE,EAAE,aAAa,EACjB,SAAS,GAAE,cAAqC,EAChD,KAAK,CAAC,EAAE,MAAM,GACZ,QAAQ,EAAE,CAwGZ;AAED,wBAAsB,iBAAiB,CACtC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,oBAAoB,EAChC,MAAM,EAAE,iBAAiB,GAAG,IAAI,EAChC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,eAAe,CAAA;CAAE,EACnD,YAAY,EAAE,MAAM,EACpB,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,oBAAoB,EAC/B,KAAK,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,CAAC,CAAA;CAAE,CAAC,CA2D3C;AAED,wBAAsB,cAAc,CACnC,KAAK,EAAE,QAAQ,EAAE,EACjB,UAAU,EAAE,oBAAoB,EAChC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,eAAe,CAAA;CAAE,EACnD,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,oBAAoB,EAC/B,eAAe,CAAC,EAAE,MAAM,EACxB,UAAU,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,YAAY,EAAE,CAAC,CAgKzB;AA6BD,wBAAsB,WAAW,CAChC,SAAS,EAAE,YAAY,EAAE,EACzB,UAAU,EAAE,oBAAoB,EAChC,MAAM,EAAE,iBAAiB,GAAG,IAAI,EAChC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,eAAe,CAAA;CAAE,EACnD,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,oBAAoB,EAC/B,KAAK,CAAC,EAAE,MAAM,EACd,UAAU,GAAE,eAAe,GAAG,IAAW,GACvC,OAAO,CAAC,MAAM,CAAC,CAmDjB;AAED,wBAAgB,gBAAgB,CAC/B,SAAS,EAAE,YAAY,EAAE,EACzB,UAAU,EAAE,oBAAoB,EAChC,QAAQ,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,EAChD,YAAY,GAAE,MAAc,EAC5B,UAAU,GAAE,eAAe,GAAG,IAAW,GACvC,MAAM,CAwIR;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,QAAQ,GAAG,YAAY,CAiB7D"}
1
+ {"version":3,"file":"synthesize.d.ts","sourceRoot":"","sources":["../../src/phases/synthesize.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,KAAK,EACX,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,oBAAoB,EACpB,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,MAAM,aAAa,CAAC;AAYrB,OAAO,EAGN,KAAK,cAAc,EACnB,MAAM,oBAAoB,CAAC;AAU5B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AA0BjE,oFAAoF;AACpF,qBAAa,uBAAwB,SAAQ,KAAK;IACjD,QAAQ,CAAC,IAAI,6BAA6B;IAE1C,YAAY,MAAM,EAAE,MAAM,EAEzB;CACD;AAoRD,wBAAgB,gBAAgB,CAC/B,IAAI,EAAE,UAAU,EAAE,EAClB,UAAU,EAAE,OAAO,aAAa,EAAE,aAAa,EAAE,EACjD,EAAE,EAAE,aAAa,EACjB,SAAS,GAAE,cAAqC,EAChD,KAAK,CAAC,EAAE,MAAM,GACZ,QAAQ,EAAE,CAwGZ;AAED,wBAAsB,iBAAiB,CACtC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,oBAAoB,EAChC,MAAM,EAAE,iBAAiB,GAAG,IAAI,EAChC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,eAAe,CAAA;CAAE,EACnD,YAAY,EAAE,MAAM,EACpB,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,oBAAoB,EAC/B,KAAK,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,CAAC,CAAA;CAAE,CAAC,CA2D3C;AAED,wBAAsB,cAAc,CACnC,KAAK,EAAE,QAAQ,EAAE,EACjB,UAAU,EAAE,oBAAoB,EAChC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,eAAe,CAAA;CAAE,EACnD,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,oBAAoB,EAC/B,eAAe,CAAC,EAAE,MAAM,EACxB,UAAU,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,YAAY,EAAE,CAAC,CAyKzB;AA6BD,wBAAsB,WAAW,CAChC,SAAS,EAAE,YAAY,EAAE,EACzB,UAAU,EAAE,oBAAoB,EAChC,MAAM,EAAE,iBAAiB,GAAG,IAAI,EAChC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,eAAe,CAAA;CAAE,EACnD,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,oBAAoB,EAC/B,KAAK,CAAC,EAAE,MAAM,EACd,UAAU,GAAE,eAAe,GAAG,IAAW,GACvC,OAAO,CAAC,MAAM,CAAC,CAmDjB;AAED,wBAAgB,gBAAgB,CAC/B,SAAS,EAAE,YAAY,EAAE,EACzB,UAAU,EAAE,oBAAoB,EAChC,QAAQ,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,EAChD,YAAY,GAAE,MAAc,EAC5B,UAAU,GAAE,eAAe,GAAG,IAAW,GACvC,MAAM,CAwIR;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,QAAQ,GAAG,YAAY,CAiB7D"}
@@ -1 +1 @@
1
- {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/phases/verify.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACX,KAAK,EACL,GAAG,EACH,eAAe,EAEf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EACX,eAAe,EACf,oBAAoB,EACpB,eAAe,EACf,qBAAqB,EACrB,kBAAkB,EAClB,UAAU,EACV,MAAM,aAAa,CAAC;AAkCrB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,MAAM,WAAW,oBAAoB;IACpC,cAAc,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IACvC,QAAQ,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC7B;AA8SD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,CAkClE;AAED,wBAAgB,0BAA0B,CACzC,MAAM,EAAE,kBAAkB,GACxB,MAAM,GAAG,IAAI,CAcf;AAED,wFAAwF;AACxF,qBAAa,qBAAsB,SAAQ,KAAK;IAC/C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC;IAC7C,QAAQ,CAAC,KAAK,EAAE,qBAAqB,CAAC;IACtC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,YACC,MAAM,EAAE,kBAAkB,EAC1B,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,qBAAqB,EAW5B;CACD;AAwUD,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAK1E;AAED,qGAAqG;AACrG,wBAAgB,8BAA8B,CAC7C,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,kBAAkB,EAC1B,UAAU,EAAE,oBAAoB,EAChC,UAAU,GAAE,eAAe,GAAG,IAAW,EACzC,QAAQ,GAAE,oBAAyB,EACnC,SAAS,SAAI,GACX;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,kBAAkB,CAAC;IAAC,OAAO,EAAE,eAAe,EAAE,CAAA;CAAE,CAyB7E;AA8XD,wBAAgB,aAAa,CAC5B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,oBAAoB,EAChC,UAAU,GAAE,eAAe,GAAG,IAAW,EACzC,QAAQ,GAAE,oBAAyB,GACjC,kBAAkB,CA2CpB;AAED,iHAAiH;AACjH,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,eAAe,EAAE,EACvB,UAAU,EAAE,oBAAoB,EAChC,UAAU,GAAE,eAAe,GAAG,IAAW,EACzC,QAAQ,GAAE,oBAAyB,GACjC,MAAM,CA4MR;AA2CD,wBAAsB,YAAY,CACjC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,eAAe,EAAE,EACvB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,eAAe,CAAA;CAAE,EACnD,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,MAAM,CAAC,CA2DjB"}
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/phases/verify.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACX,KAAK,EACL,GAAG,EACH,eAAe,EAEf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EACX,eAAe,EACf,oBAAoB,EACpB,eAAe,EACf,qBAAqB,EACrB,kBAAkB,EAClB,UAAU,EACV,MAAM,aAAa,CAAC;AAoCrB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,MAAM,WAAW,oBAAoB;IACpC,cAAc,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IACvC,QAAQ,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC7B;AA8SD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,CAkClE;AAED,wBAAgB,0BAA0B,CACzC,MAAM,EAAE,kBAAkB,GACxB,MAAM,GAAG,IAAI,CAcf;AAED,wFAAwF;AACxF,qBAAa,qBAAsB,SAAQ,KAAK;IAC/C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC;IAC7C,QAAQ,CAAC,KAAK,EAAE,qBAAqB,CAAC;IACtC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,YACC,MAAM,EAAE,kBAAkB,EAC1B,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,qBAAqB,EAW5B;CACD;AAwUD,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAK1E;AAED,qGAAqG;AACrG,wBAAgB,8BAA8B,CAC7C,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,kBAAkB,EAC1B,UAAU,EAAE,oBAAoB,EAChC,UAAU,GAAE,eAAe,GAAG,IAAW,EACzC,QAAQ,GAAE,oBAAyB,EACnC,SAAS,SAAI,GACX;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,kBAAkB,CAAC;IAAC,OAAO,EAAE,eAAe,EAAE,CAAA;CAAE,CAyB7E;AAiYD,wBAAgB,aAAa,CAC5B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,oBAAoB,EAChC,UAAU,GAAE,eAAe,GAAG,IAAW,EACzC,QAAQ,GAAE,oBAAyB,GACjC,kBAAkB,CA2CpB;AAED,iHAAiH;AACjH,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,eAAe,EAAE,EACvB,UAAU,EAAE,oBAAoB,EAChC,UAAU,GAAE,eAAe,GAAG,IAAW,EACzC,QAAQ,GAAE,oBAAyB,GACjC,MAAM,CA4MR;AA2CD,wBAAsB,YAAY,CACjC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,eAAe,EAAE,EACvB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,eAAe,CAAA;CAAE,EACnD,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,MAAM,CAAC,CA2DjB"}
@@ -156,7 +156,7 @@ function formatProviderEvaluation(report) {
156
156
  import fs2 from "fs";
157
157
 
158
158
  // src/constants.ts
159
- var VERSION = "9.5.0";
159
+ var VERSION = "9.6.1";
160
160
  var SETTLED_TRIGGER_COOLDOWN_MS = 10 * 60000;
161
161
  var COMPACT_SYSTEM_PREFIX = "You are an expert conversation summarizer for a coding agent. " + "Produce structured markdown summaries. " + "Follow output format exactly. " + "Use EXACT names \u2014 never paraphrase code identifiers. " + "Trust deterministic extraction data over intuition.";
162
162
  var PROFILES = {
@@ -667,38 +667,117 @@ function buildPathNeedles(filePath) {
667
667
  }
668
668
  return needles;
669
669
  }
670
- function buildUniquePathNeedles(filePath, allPaths) {
671
- const normalized = allPaths.map(normalizePath);
670
+ var MAX_INDEXED_SUFFIX_CHARS = 1024;
671
+ function buildPathNeedleOwnershipIndex(allPaths) {
672
+ const owners = new Map;
673
+ const normalizedPaths = allPaths.map(normalizePath);
674
+ let hasUnindexedSuffixes = false;
675
+ for (const normalized of normalizedPaths) {
676
+ const suffixes = new Set([normalized]);
677
+ for (let index = 0;index < normalized.length; index++) {
678
+ if (normalized[index] !== "/")
679
+ continue;
680
+ if (normalized.length - index - 1 <= MAX_INDEXED_SUFFIX_CHARS) {
681
+ suffixes.add(normalized.slice(index + 1));
682
+ } else {
683
+ hasUnindexedSuffixes = true;
684
+ }
685
+ }
686
+ for (const suffix of suffixes) {
687
+ owners.set(suffix, (owners.get(suffix) ?? 0) + 1);
688
+ }
689
+ }
690
+ return { counts: owners, normalizedPaths, hasUnindexedSuffixes };
691
+ }
692
+ function buildUniquePathNeedlesFromIndex(filePath, owners) {
672
693
  return buildPathNeedles(filePath).filter((needle) => {
673
- let owners = 0;
674
- for (const candidate of normalized) {
694
+ if (!owners.hasUnindexedSuffixes)
695
+ return owners.counts.get(needle) === 1;
696
+ let count = 0;
697
+ for (const candidate of owners.normalizedPaths) {
675
698
  if (candidate === needle || candidate.endsWith("/" + needle))
676
- owners++;
677
- if (owners > 1)
699
+ count++;
700
+ if (count > 1)
678
701
  return false;
679
702
  }
680
- return owners === 1;
703
+ return count === 1;
681
704
  });
682
705
  }
683
- function isKnownPathReference(ref, knownPaths) {
684
- const normalizedRef = normalizePath(ref).replace(/^\/+/, "");
685
- if (!normalizedRef)
686
- return false;
687
- const pathShaped = normalizedRef.includes("/");
688
- return knownPaths.some((path) => {
706
+ var PATH_CANDIDATE_CHAR_RE = /[\w./-]/;
707
+ function buildKnownPathReferenceIndex(knownPaths) {
708
+ const segmentSuffixes = new Set;
709
+ const boundarySuffixes = new Set;
710
+ const normalizedPaths = [];
711
+ let hasUnindexedSuffixes = false;
712
+ for (const path of knownPaths) {
689
713
  const normalizedPath = normalizePath(path).replace(/^\/+/, "");
714
+ if (!normalizedPath)
715
+ continue;
716
+ normalizedPaths.push(normalizedPath);
717
+ segmentSuffixes.add(normalizedPath);
718
+ for (let index = 0;index < normalizedPath.length; index++) {
719
+ if (normalizedPath[index] === "/") {
720
+ if (normalizedPath.length - index - 1 <= MAX_INDEXED_SUFFIX_CHARS) {
721
+ segmentSuffixes.add(normalizedPath.slice(index + 1));
722
+ } else {
723
+ hasUnindexedSuffixes = true;
724
+ }
725
+ }
726
+ if (index > 0 && !PATH_CANDIDATE_CHAR_RE.test(normalizedPath[index - 1])) {
727
+ if (normalizedPath.length - index <= MAX_INDEXED_SUFFIX_CHARS) {
728
+ boundarySuffixes.add(normalizedPath.slice(index));
729
+ } else {
730
+ hasUnindexedSuffixes = true;
731
+ }
732
+ }
733
+ }
734
+ }
735
+ return {
736
+ segmentSuffixes,
737
+ sortedSegmentSuffixes: [...segmentSuffixes].sort(),
738
+ boundarySuffixes,
739
+ normalizedPaths,
740
+ hasUnindexedSuffixes
741
+ };
742
+ }
743
+ function matchesKnownPathReference(normalizedRef, normalizedPaths) {
744
+ const pathShaped = normalizedRef.includes("/");
745
+ return normalizedPaths.some((normalizedPath) => {
690
746
  if (normalizedPath === normalizedRef || normalizedPath.endsWith("/" + normalizedRef))
691
747
  return true;
692
748
  if (normalizedPath.endsWith(normalizedRef)) {
693
749
  const boundary = normalizedPath[normalizedPath.length - normalizedRef.length - 1];
694
- if (boundary && !/[\w./-]/.test(boundary))
750
+ if (boundary && !PATH_CANDIDATE_CHAR_RE.test(boundary))
695
751
  return true;
696
752
  }
697
753
  if (!pathShaped)
698
754
  return false;
699
- return normalizedPath.split("/").some((_, index, parts) => parts.slice(index).join("/").startsWith(normalizedRef + "/"));
755
+ return normalizedPath.startsWith(normalizedRef + "/") || normalizedPath.includes("/" + normalizedRef + "/");
700
756
  });
701
757
  }
758
+ function sortedHasPrefix(values, prefix) {
759
+ let low = 0;
760
+ let high = values.length;
761
+ while (low < high) {
762
+ const middle = low + high >>> 1;
763
+ if (values[middle] < prefix)
764
+ low = middle + 1;
765
+ else
766
+ high = middle;
767
+ }
768
+ return values[low]?.startsWith(prefix) ?? false;
769
+ }
770
+ function isKnownPathReferenceInIndex(ref, index) {
771
+ const normalizedRef = normalizePath(ref).replace(/^\/+/, "");
772
+ if (!normalizedRef)
773
+ return false;
774
+ if (index.segmentSuffixes.has(normalizedRef) || index.boundarySuffixes.has(normalizedRef)) {
775
+ return true;
776
+ }
777
+ if (normalizedRef.includes("/") && sortedHasPrefix(index.sortedSegmentSuffixes, normalizedRef + "/"))
778
+ return true;
779
+ return index.hasUnindexedSuffixes ? matchesKnownPathReference(normalizedRef, index.normalizedPaths) : false;
780
+ }
702
781
 
703
782
  // src/domain/tool-semantics.ts
704
783
  var PATH_KEYS = [
@@ -775,6 +854,38 @@ function warn(msg, err) {
775
854
  console.error(LOG_PREFIX + " " + msg + (detail ? ": " + detail : ""));
776
855
  }
777
856
 
857
+ // src/infra/fs.ts
858
+ import fs from "fs";
859
+ function readJsonlTail(target, limit, maxBytes = 512 * 1024) {
860
+ if (limit <= 0 || !fs.existsSync(target))
861
+ return [];
862
+ const stat = fs.statSync(target);
863
+ const length = Math.min(stat.size, maxBytes);
864
+ const buffer = Buffer.alloc(length);
865
+ const fd = fs.openSync(target, "r");
866
+ try {
867
+ fs.readSync(fd, buffer, 0, length, stat.size - length);
868
+ } finally {
869
+ fs.closeSync(fd);
870
+ }
871
+ let text = buffer.toString("utf8");
872
+ if (stat.size > length) {
873
+ const newline = text.indexOf(`
874
+ `);
875
+ text = newline >= 0 ? text.slice(newline + 1) : "";
876
+ }
877
+ const values = [];
878
+ for (const line of text.split(`
879
+ `)) {
880
+ if (!line)
881
+ continue;
882
+ try {
883
+ values.push(JSON.parse(line));
884
+ } catch {}
885
+ }
886
+ return values.slice(-limit);
887
+ }
888
+
778
889
  // src/infra/paths.ts
779
890
  import path from "path";
780
891
  import os from "os";
@@ -800,7 +911,12 @@ function damageReportsFile() {
800
911
  // src/utils/file-ref-detect.ts
801
912
  var CODE_EXT_RE = /\.(ts|tsx|js|jsx|mjs|cjs|rs|py|go|java|rb|cs|cpp|c|h|hpp|swift|kt|scala|php|css|scss|html|json|yaml|yml|toml|md|mdx|sh|sql|tf|ini|env|lock|gradle|xml)$/i;
802
913
  var VERSION_RE = /^v?\d+(?:\.\d+)+(?:[-+][\w.-]+)?$/i;
803
- var FILE_REF_CANDIDATE_RE = /[\w.\/-]+\.[\w]+/g;
914
+ function isAsciiWordCode(code) {
915
+ return code >= 48 && code <= 57 || code >= 65 && code <= 90 || code === 95 || code >= 97 && code <= 122;
916
+ }
917
+ function isCandidateCode(code) {
918
+ return isAsciiWordCode(code) || code === 45 || code === 46 || code === 47;
919
+ }
804
920
  function isLikelyFileRef(candidate) {
805
921
  if (candidate.startsWith("//") || VERSION_RE.test(candidate))
806
922
  return false;
@@ -811,13 +927,32 @@ function isLikelyFileRef(candidate) {
811
927
  return CODE_EXT_RE.test(candidate);
812
928
  }
813
929
  function extractFileRefs(summary) {
814
- const matcher = new RegExp(FILE_REF_CANDIDATE_RE.source, FILE_REF_CANDIDATE_RE.flags);
815
930
  const refs = [];
816
- for (const match of summary.matchAll(matcher)) {
817
- if (/[\\/]/.test(summary[(match.index ?? 0) + match[0].length] ?? ""))
931
+ let cursor = 0;
932
+ while (cursor < summary.length) {
933
+ while (cursor < summary.length && !isCandidateCode(summary.charCodeAt(cursor)))
934
+ cursor++;
935
+ const runStart = cursor;
936
+ while (cursor < summary.length && isCandidateCode(summary.charCodeAt(cursor)))
937
+ cursor++;
938
+ const runEnd = cursor;
939
+ let extensionDot = -1;
940
+ for (let index = runStart + 1;index + 1 < runEnd; index++) {
941
+ if (summary.charCodeAt(index) === 46 && isAsciiWordCode(summary.charCodeAt(index + 1))) {
942
+ extensionDot = index;
943
+ }
944
+ }
945
+ if (extensionDot < 0)
946
+ continue;
947
+ let matchEnd = extensionDot + 2;
948
+ while (matchEnd < runEnd && isAsciiWordCode(summary.charCodeAt(matchEnd))) {
949
+ matchEnd++;
950
+ }
951
+ const candidate = summary.slice(runStart, matchEnd);
952
+ if (/[\\/]/.test(summary[matchEnd] ?? ""))
818
953
  continue;
819
- if (isLikelyFileRef(match[0]))
820
- refs.push(match[0]);
954
+ if (isLikelyFileRef(candidate))
955
+ refs.push(candidate);
821
956
  }
822
957
  return refs;
823
958
  }
@@ -1083,38 +1218,6 @@ function isDiagnosticConstraintText(text) {
1083
1218
  return /^(?:\[[^\]]+\]\s*)?(?:npm\s+(?:error|warn|notice|audit|verbose|info)\b|(?:rg|grep):|command exited\b)/i.test(candidate);
1084
1219
  }
1085
1220
 
1086
- // src/infra/fs.ts
1087
- import fs from "fs";
1088
- function readJsonlTail(target, limit, maxBytes = 512 * 1024) {
1089
- if (limit <= 0 || !fs.existsSync(target))
1090
- return [];
1091
- const stat = fs.statSync(target);
1092
- const length = Math.min(stat.size, maxBytes);
1093
- const buffer = Buffer.alloc(length);
1094
- const fd = fs.openSync(target, "r");
1095
- try {
1096
- fs.readSync(fd, buffer, 0, length, stat.size - length);
1097
- } finally {
1098
- fs.closeSync(fd);
1099
- }
1100
- let text = buffer.toString("utf8");
1101
- if (stat.size > length) {
1102
- const newline = text.indexOf(`
1103
- `);
1104
- text = newline >= 0 ? text.slice(newline + 1) : "";
1105
- }
1106
- const values = [];
1107
- for (const line of text.split(`
1108
- `)) {
1109
- if (!line)
1110
- continue;
1111
- try {
1112
- values.push(JSON.parse(line));
1113
- } catch {}
1114
- }
1115
- return values.slice(-limit);
1116
- }
1117
-
1118
1221
  // src/infra/clock.ts
1119
1222
  var systemClock = {
1120
1223
  now: () => Date.now()
@@ -5,7 +5,7 @@ var __require = import.meta.require;
5
5
  import { ModelRegistry, ModelRuntime } from "@earendil-works/pi-coding-agent";
6
6
 
7
7
  // src/constants.ts
8
- var VERSION = "9.5.0";
8
+ var VERSION = "9.6.1";
9
9
  var SETTLED_TRIGGER_COOLDOWN_MS = 10 * 60000;
10
10
  var COMPACT_SYSTEM_PREFIX = "You are an expert conversation summarizer for a coding agent. " + "Produce structured markdown summaries. " + "Follow output format exactly. " + "Use EXACT names \u2014 never paraphrase code identifiers. " + "Trust deterministic extraction data over intuition.";
11
11
  var PROFILES = {
@@ -690,38 +690,117 @@ function buildPathNeedles(filePath) {
690
690
  }
691
691
  return needles;
692
692
  }
693
- function buildUniquePathNeedles(filePath, allPaths) {
694
- const normalized = allPaths.map(normalizePath);
693
+ var MAX_INDEXED_SUFFIX_CHARS = 1024;
694
+ function buildPathNeedleOwnershipIndex(allPaths) {
695
+ const owners = new Map;
696
+ const normalizedPaths = allPaths.map(normalizePath);
697
+ let hasUnindexedSuffixes = false;
698
+ for (const normalized of normalizedPaths) {
699
+ const suffixes = new Set([normalized]);
700
+ for (let index = 0;index < normalized.length; index++) {
701
+ if (normalized[index] !== "/")
702
+ continue;
703
+ if (normalized.length - index - 1 <= MAX_INDEXED_SUFFIX_CHARS) {
704
+ suffixes.add(normalized.slice(index + 1));
705
+ } else {
706
+ hasUnindexedSuffixes = true;
707
+ }
708
+ }
709
+ for (const suffix of suffixes) {
710
+ owners.set(suffix, (owners.get(suffix) ?? 0) + 1);
711
+ }
712
+ }
713
+ return { counts: owners, normalizedPaths, hasUnindexedSuffixes };
714
+ }
715
+ function buildUniquePathNeedlesFromIndex(filePath, owners) {
695
716
  return buildPathNeedles(filePath).filter((needle) => {
696
- let owners = 0;
697
- for (const candidate of normalized) {
717
+ if (!owners.hasUnindexedSuffixes)
718
+ return owners.counts.get(needle) === 1;
719
+ let count = 0;
720
+ for (const candidate of owners.normalizedPaths) {
698
721
  if (candidate === needle || candidate.endsWith("/" + needle))
699
- owners++;
700
- if (owners > 1)
722
+ count++;
723
+ if (count > 1)
701
724
  return false;
702
725
  }
703
- return owners === 1;
726
+ return count === 1;
704
727
  });
705
728
  }
706
- function isKnownPathReference(ref, knownPaths) {
707
- const normalizedRef = normalizePath(ref).replace(/^\/+/, "");
708
- if (!normalizedRef)
709
- return false;
710
- const pathShaped = normalizedRef.includes("/");
711
- return knownPaths.some((path) => {
729
+ var PATH_CANDIDATE_CHAR_RE = /[\w./-]/;
730
+ function buildKnownPathReferenceIndex(knownPaths) {
731
+ const segmentSuffixes = new Set;
732
+ const boundarySuffixes = new Set;
733
+ const normalizedPaths = [];
734
+ let hasUnindexedSuffixes = false;
735
+ for (const path of knownPaths) {
712
736
  const normalizedPath = normalizePath(path).replace(/^\/+/, "");
737
+ if (!normalizedPath)
738
+ continue;
739
+ normalizedPaths.push(normalizedPath);
740
+ segmentSuffixes.add(normalizedPath);
741
+ for (let index = 0;index < normalizedPath.length; index++) {
742
+ if (normalizedPath[index] === "/") {
743
+ if (normalizedPath.length - index - 1 <= MAX_INDEXED_SUFFIX_CHARS) {
744
+ segmentSuffixes.add(normalizedPath.slice(index + 1));
745
+ } else {
746
+ hasUnindexedSuffixes = true;
747
+ }
748
+ }
749
+ if (index > 0 && !PATH_CANDIDATE_CHAR_RE.test(normalizedPath[index - 1])) {
750
+ if (normalizedPath.length - index <= MAX_INDEXED_SUFFIX_CHARS) {
751
+ boundarySuffixes.add(normalizedPath.slice(index));
752
+ } else {
753
+ hasUnindexedSuffixes = true;
754
+ }
755
+ }
756
+ }
757
+ }
758
+ return {
759
+ segmentSuffixes,
760
+ sortedSegmentSuffixes: [...segmentSuffixes].sort(),
761
+ boundarySuffixes,
762
+ normalizedPaths,
763
+ hasUnindexedSuffixes
764
+ };
765
+ }
766
+ function matchesKnownPathReference(normalizedRef, normalizedPaths) {
767
+ const pathShaped = normalizedRef.includes("/");
768
+ return normalizedPaths.some((normalizedPath) => {
713
769
  if (normalizedPath === normalizedRef || normalizedPath.endsWith("/" + normalizedRef))
714
770
  return true;
715
771
  if (normalizedPath.endsWith(normalizedRef)) {
716
772
  const boundary = normalizedPath[normalizedPath.length - normalizedRef.length - 1];
717
- if (boundary && !/[\w./-]/.test(boundary))
773
+ if (boundary && !PATH_CANDIDATE_CHAR_RE.test(boundary))
718
774
  return true;
719
775
  }
720
776
  if (!pathShaped)
721
777
  return false;
722
- return normalizedPath.split("/").some((_, index, parts) => parts.slice(index).join("/").startsWith(normalizedRef + "/"));
778
+ return normalizedPath.startsWith(normalizedRef + "/") || normalizedPath.includes("/" + normalizedRef + "/");
723
779
  });
724
780
  }
781
+ function sortedHasPrefix(values, prefix) {
782
+ let low = 0;
783
+ let high = values.length;
784
+ while (low < high) {
785
+ const middle = low + high >>> 1;
786
+ if (values[middle] < prefix)
787
+ low = middle + 1;
788
+ else
789
+ high = middle;
790
+ }
791
+ return values[low]?.startsWith(prefix) ?? false;
792
+ }
793
+ function isKnownPathReferenceInIndex(ref, index) {
794
+ const normalizedRef = normalizePath(ref).replace(/^\/+/, "");
795
+ if (!normalizedRef)
796
+ return false;
797
+ if (index.segmentSuffixes.has(normalizedRef) || index.boundarySuffixes.has(normalizedRef)) {
798
+ return true;
799
+ }
800
+ if (normalizedRef.includes("/") && sortedHasPrefix(index.sortedSegmentSuffixes, normalizedRef + "/"))
801
+ return true;
802
+ return index.hasUnindexedSuffixes ? matchesKnownPathReference(normalizedRef, index.normalizedPaths) : false;
803
+ }
725
804
 
726
805
  // src/domain/tool-semantics.ts
727
806
  var PATH_KEYS = [
@@ -798,6 +877,38 @@ function warn(msg, err) {
798
877
  console.error(LOG_PREFIX + " " + msg + (detail ? ": " + detail : ""));
799
878
  }
800
879
 
880
+ // src/infra/fs.ts
881
+ import fs from "fs";
882
+ function readJsonlTail(target, limit, maxBytes = 512 * 1024) {
883
+ if (limit <= 0 || !fs.existsSync(target))
884
+ return [];
885
+ const stat = fs.statSync(target);
886
+ const length = Math.min(stat.size, maxBytes);
887
+ const buffer = Buffer.alloc(length);
888
+ const fd = fs.openSync(target, "r");
889
+ try {
890
+ fs.readSync(fd, buffer, 0, length, stat.size - length);
891
+ } finally {
892
+ fs.closeSync(fd);
893
+ }
894
+ let text = buffer.toString("utf8");
895
+ if (stat.size > length) {
896
+ const newline = text.indexOf(`
897
+ `);
898
+ text = newline >= 0 ? text.slice(newline + 1) : "";
899
+ }
900
+ const values = [];
901
+ for (const line of text.split(`
902
+ `)) {
903
+ if (!line)
904
+ continue;
905
+ try {
906
+ values.push(JSON.parse(line));
907
+ } catch {}
908
+ }
909
+ return values.slice(-limit);
910
+ }
911
+
801
912
  // src/infra/paths.ts
802
913
  import path from "path";
803
914
  import os from "os";
@@ -823,7 +934,12 @@ function damageReportsFile() {
823
934
  // src/utils/file-ref-detect.ts
824
935
  var CODE_EXT_RE = /\.(ts|tsx|js|jsx|mjs|cjs|rs|py|go|java|rb|cs|cpp|c|h|hpp|swift|kt|scala|php|css|scss|html|json|yaml|yml|toml|md|mdx|sh|sql|tf|ini|env|lock|gradle|xml)$/i;
825
936
  var VERSION_RE = /^v?\d+(?:\.\d+)+(?:[-+][\w.-]+)?$/i;
826
- var FILE_REF_CANDIDATE_RE = /[\w.\/-]+\.[\w]+/g;
937
+ function isAsciiWordCode(code) {
938
+ return code >= 48 && code <= 57 || code >= 65 && code <= 90 || code === 95 || code >= 97 && code <= 122;
939
+ }
940
+ function isCandidateCode(code) {
941
+ return isAsciiWordCode(code) || code === 45 || code === 46 || code === 47;
942
+ }
827
943
  function isLikelyFileRef(candidate) {
828
944
  if (candidate.startsWith("//") || VERSION_RE.test(candidate))
829
945
  return false;
@@ -834,13 +950,32 @@ function isLikelyFileRef(candidate) {
834
950
  return CODE_EXT_RE.test(candidate);
835
951
  }
836
952
  function extractFileRefs(summary) {
837
- const matcher = new RegExp(FILE_REF_CANDIDATE_RE.source, FILE_REF_CANDIDATE_RE.flags);
838
953
  const refs = [];
839
- for (const match of summary.matchAll(matcher)) {
840
- if (/[\\/]/.test(summary[(match.index ?? 0) + match[0].length] ?? ""))
954
+ let cursor = 0;
955
+ while (cursor < summary.length) {
956
+ while (cursor < summary.length && !isCandidateCode(summary.charCodeAt(cursor)))
957
+ cursor++;
958
+ const runStart = cursor;
959
+ while (cursor < summary.length && isCandidateCode(summary.charCodeAt(cursor)))
960
+ cursor++;
961
+ const runEnd = cursor;
962
+ let extensionDot = -1;
963
+ for (let index = runStart + 1;index + 1 < runEnd; index++) {
964
+ if (summary.charCodeAt(index) === 46 && isAsciiWordCode(summary.charCodeAt(index + 1))) {
965
+ extensionDot = index;
966
+ }
967
+ }
968
+ if (extensionDot < 0)
969
+ continue;
970
+ let matchEnd = extensionDot + 2;
971
+ while (matchEnd < runEnd && isAsciiWordCode(summary.charCodeAt(matchEnd))) {
972
+ matchEnd++;
973
+ }
974
+ const candidate = summary.slice(runStart, matchEnd);
975
+ if (/[\\/]/.test(summary[matchEnd] ?? ""))
841
976
  continue;
842
- if (isLikelyFileRef(match[0]))
843
- refs.push(match[0]);
977
+ if (isLikelyFileRef(candidate))
978
+ refs.push(candidate);
844
979
  }
845
980
  return refs;
846
981
  }
@@ -1106,38 +1241,6 @@ function isDiagnosticConstraintText(text) {
1106
1241
  return /^(?:\[[^\]]+\]\s*)?(?:npm\s+(?:error|warn|notice|audit|verbose|info)\b|(?:rg|grep):|command exited\b)/i.test(candidate);
1107
1242
  }
1108
1243
 
1109
- // src/infra/fs.ts
1110
- import fs from "fs";
1111
- function readJsonlTail(target, limit, maxBytes = 512 * 1024) {
1112
- if (limit <= 0 || !fs.existsSync(target))
1113
- return [];
1114
- const stat = fs.statSync(target);
1115
- const length = Math.min(stat.size, maxBytes);
1116
- const buffer = Buffer.alloc(length);
1117
- const fd = fs.openSync(target, "r");
1118
- try {
1119
- fs.readSync(fd, buffer, 0, length, stat.size - length);
1120
- } finally {
1121
- fs.closeSync(fd);
1122
- }
1123
- let text = buffer.toString("utf8");
1124
- if (stat.size > length) {
1125
- const newline = text.indexOf(`
1126
- `);
1127
- text = newline >= 0 ? text.slice(newline + 1) : "";
1128
- }
1129
- const values = [];
1130
- for (const line of text.split(`
1131
- `)) {
1132
- if (!line)
1133
- continue;
1134
- try {
1135
- values.push(JSON.parse(line));
1136
- } catch {}
1137
- }
1138
- return values.slice(-limit);
1139
- }
1140
-
1141
1244
  // src/infra/clock.ts
1142
1245
  var systemClock = {
1143
1246
  now: () => Date.now()
@@ -2220,8 +2323,9 @@ function verifyFileReferences(summary, extraction, continuity, evidence, collect
2220
2323
  ...(continuity?.unresolvedErrors ?? []).flatMap((error) => error.files),
2221
2324
  ...(continuity?.openLoops ?? []).flatMap((loop) => loop.files)
2222
2325
  ]));
2326
+ const knownFileIndex = buildKnownPathReferenceIndex(knownFiles);
2223
2327
  for (const ref of new Set(extractFileRefs(summary))) {
2224
- const grounded = isKnownPathReference(ref, knownFiles) || Boolean(evidence.sourceMessages && sourceSupportsFileReference(ref, evidence.sourceMessages));
2328
+ const grounded = isKnownPathReferenceInIndex(ref, knownFileIndex) || Boolean(evidence.sourceMessages && sourceSupportsFileReference(ref, evidence.sourceMessages));
2225
2329
  if (!grounded)
2226
2330
  addGap(accumulator, { kind: "fabricated-file", ref }, 4);
2227
2331
  }
@@ -2239,9 +2343,10 @@ function verifyProgressConsistency(parsed, extraction, collected, paths, accumul
2239
2343
  }, 12);
2240
2344
  }
2241
2345
  const doneRefs = new Set(extractFileRefs(done).map(normalizePath));
2346
+ const modifiedPathOwners = buildPathNeedleOwnershipIndex(paths.modified);
2242
2347
  for (const file of extraction.modifiedFiles) {
2243
- const needles = buildUniquePathNeedles(file.path, paths.modified);
2244
- if (!needles.some((needle) => doneRefs.has(normalizePath(needle))))
2348
+ const needles = buildUniquePathNeedlesFromIndex(file.path, modifiedPathOwners);
2349
+ if (!needles.some((needle) => doneRefs.has(needle)))
2245
2350
  continue;
2246
2351
  const unresolved = collected.unresolved.find((error) => {
2247
2352
  const firstLine = error.message.split(/\r?\n/, 1)[0] ?? "";