pi-ghost-autocomplete 0.3.1 → 0.3.2

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 (155) hide show
  1. package/README.md +101 -6
  2. package/dist/bench-cli.js +81 -5
  3. package/dist/bench-cli.js.map +1 -1
  4. package/dist/bench.d.ts +130 -2
  5. package/dist/bench.d.ts.map +1 -1
  6. package/dist/bench.js +285 -4
  7. package/dist/bench.js.map +1 -1
  8. package/dist/cache.d.ts +124 -0
  9. package/dist/cache.d.ts.map +1 -0
  10. package/dist/cache.js +173 -0
  11. package/dist/cache.js.map +1 -0
  12. package/dist/candidate-rerank.d.ts +57 -0
  13. package/dist/candidate-rerank.d.ts.map +1 -0
  14. package/dist/candidate-rerank.js +78 -0
  15. package/dist/candidate-rerank.js.map +1 -0
  16. package/dist/config.d.ts +43 -0
  17. package/dist/config.d.ts.map +1 -1
  18. package/dist/config.js +148 -18
  19. package/dist/config.js.map +1 -1
  20. package/dist/context-aggregator.d.ts +14 -5
  21. package/dist/context-aggregator.d.ts.map +1 -1
  22. package/dist/context-aggregator.js +38 -9
  23. package/dist/context-aggregator.js.map +1 -1
  24. package/dist/context-selector.d.ts +128 -0
  25. package/dist/context-selector.d.ts.map +1 -0
  26. package/dist/context-selector.js +300 -0
  27. package/dist/context-selector.js.map +1 -0
  28. package/dist/cycle-manager.d.ts +102 -0
  29. package/dist/cycle-manager.d.ts.map +1 -0
  30. package/dist/cycle-manager.js +168 -0
  31. package/dist/cycle-manager.js.map +1 -0
  32. package/dist/edit-history-ring.d.ts +148 -0
  33. package/dist/edit-history-ring.d.ts.map +1 -0
  34. package/dist/edit-history-ring.js +262 -0
  35. package/dist/edit-history-ring.js.map +1 -0
  36. package/dist/entropy-stop.d.ts +102 -0
  37. package/dist/entropy-stop.d.ts.map +1 -0
  38. package/dist/entropy-stop.js +141 -0
  39. package/dist/entropy-stop.js.map +1 -0
  40. package/dist/eval-dataset.d.ts +66 -0
  41. package/dist/eval-dataset.d.ts.map +1 -0
  42. package/dist/eval-dataset.js +127 -0
  43. package/dist/eval-dataset.js.map +1 -0
  44. package/dist/fast-path-engine.d.ts +286 -0
  45. package/dist/fast-path-engine.d.ts.map +1 -0
  46. package/dist/fast-path-engine.js +341 -0
  47. package/dist/fast-path-engine.js.map +1 -0
  48. package/dist/fuzzy-matcher.d.ts +8 -0
  49. package/dist/fuzzy-matcher.d.ts.map +1 -1
  50. package/dist/fuzzy-matcher.js +5 -3
  51. package/dist/fuzzy-matcher.js.map +1 -1
  52. package/dist/ghost-editor.d.ts +321 -4
  53. package/dist/ghost-editor.d.ts.map +1 -1
  54. package/dist/ghost-editor.js +1190 -144
  55. package/dist/ghost-editor.js.map +1 -1
  56. package/dist/index.d.ts +17 -0
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +81 -2
  59. package/dist/index.js.map +1 -1
  60. package/dist/keystroke-timer.d.ts +59 -0
  61. package/dist/keystroke-timer.d.ts.map +1 -0
  62. package/dist/keystroke-timer.js +94 -0
  63. package/dist/keystroke-timer.js.map +1 -0
  64. package/dist/metrics-builder.d.ts +71 -0
  65. package/dist/metrics-builder.d.ts.map +1 -0
  66. package/dist/metrics-builder.js +71 -0
  67. package/dist/metrics-builder.js.map +1 -0
  68. package/dist/metrics.d.ts +99 -2
  69. package/dist/metrics.d.ts.map +1 -1
  70. package/dist/metrics.js +131 -17
  71. package/dist/metrics.js.map +1 -1
  72. package/dist/path-matcher.d.ts +9 -0
  73. package/dist/path-matcher.d.ts.map +1 -1
  74. package/dist/path-matcher.js +5 -2
  75. package/dist/path-matcher.js.map +1 -1
  76. package/dist/profile-store.d.ts +82 -0
  77. package/dist/profile-store.d.ts.map +1 -0
  78. package/dist/profile-store.js +199 -0
  79. package/dist/profile-store.js.map +1 -0
  80. package/dist/profile.d.ts +185 -0
  81. package/dist/profile.d.ts.map +1 -0
  82. package/dist/profile.js +434 -0
  83. package/dist/profile.js.map +1 -0
  84. package/dist/providers/cloud-provider.d.ts +10 -1
  85. package/dist/providers/cloud-provider.d.ts.map +1 -1
  86. package/dist/providers/cloud-provider.js +71 -14
  87. package/dist/providers/cloud-provider.js.map +1 -1
  88. package/dist/providers/local-provider.d.ts +8 -1
  89. package/dist/providers/local-provider.d.ts.map +1 -1
  90. package/dist/providers/local-provider.js +15 -3
  91. package/dist/providers/local-provider.js.map +1 -1
  92. package/dist/providers/openai-compat-provider.d.ts +11 -1
  93. package/dist/providers/openai-compat-provider.d.ts.map +1 -1
  94. package/dist/providers/openai-compat-provider.js +93 -6
  95. package/dist/providers/openai-compat-provider.js.map +1 -1
  96. package/dist/providers/openai-completions-runner.d.ts +25 -1
  97. package/dist/providers/openai-completions-runner.d.ts.map +1 -1
  98. package/dist/providers/openai-completions-runner.js +109 -14
  99. package/dist/providers/openai-completions-runner.js.map +1 -1
  100. package/dist/providers/race.d.ts +58 -1
  101. package/dist/providers/race.d.ts.map +1 -1
  102. package/dist/providers/race.js +317 -4
  103. package/dist/providers/race.js.map +1 -1
  104. package/dist/providers/truncate.d.ts.map +1 -1
  105. package/dist/providers/truncate.js +20 -2
  106. package/dist/providers/truncate.js.map +1 -1
  107. package/dist/providers/types.d.ts +96 -1
  108. package/dist/providers/types.d.ts.map +1 -1
  109. package/dist/providers/types.js +59 -1
  110. package/dist/providers/types.js.map +1 -1
  111. package/dist/provisional-manager.d.ts +93 -0
  112. package/dist/provisional-manager.d.ts.map +1 -0
  113. package/dist/provisional-manager.js +98 -0
  114. package/dist/provisional-manager.js.map +1 -0
  115. package/dist/provisional.d.ts +150 -0
  116. package/dist/provisional.d.ts.map +1 -0
  117. package/dist/provisional.js +238 -0
  118. package/dist/provisional.js.map +1 -0
  119. package/dist/regret-tracker.d.ts +84 -0
  120. package/dist/regret-tracker.d.ts.map +1 -0
  121. package/dist/regret-tracker.js +145 -0
  122. package/dist/regret-tracker.js.map +1 -0
  123. package/dist/replay-cli.d.ts +13 -0
  124. package/dist/replay-cli.d.ts.map +1 -0
  125. package/dist/replay-cli.js +167 -0
  126. package/dist/replay-cli.js.map +1 -0
  127. package/dist/replay.d.ts +107 -0
  128. package/dist/replay.d.ts.map +1 -0
  129. package/dist/replay.js +225 -0
  130. package/dist/replay.js.map +1 -0
  131. package/dist/reranker.d.ts +181 -0
  132. package/dist/reranker.d.ts.map +1 -0
  133. package/dist/reranker.js +324 -0
  134. package/dist/reranker.js.map +1 -0
  135. package/dist/session-trie.d.ts +103 -0
  136. package/dist/session-trie.d.ts.map +1 -0
  137. package/dist/session-trie.js +280 -0
  138. package/dist/session-trie.js.map +1 -0
  139. package/dist/speculative.d.ts +74 -0
  140. package/dist/speculative.d.ts.map +1 -0
  141. package/dist/speculative.js +107 -0
  142. package/dist/speculative.js.map +1 -0
  143. package/dist/tool-summarize.d.ts +40 -0
  144. package/dist/tool-summarize.d.ts.map +1 -0
  145. package/dist/tool-summarize.js +245 -0
  146. package/dist/tool-summarize.js.map +1 -0
  147. package/dist/trie-sanitize.d.ts +22 -0
  148. package/dist/trie-sanitize.d.ts.map +1 -0
  149. package/dist/trie-sanitize.js +142 -0
  150. package/dist/trie-sanitize.js.map +1 -0
  151. package/dist/versions.d.ts +23 -0
  152. package/dist/versions.d.ts.map +1 -0
  153. package/dist/versions.js +31 -0
  154. package/dist/versions.js.map +1 -0
  155. package/package.json +3 -2
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Provisional ghost lifecycle manager. Owns:
3
+ * - the timer that fires `pickProvisional` after `provisionalDelayMs`
4
+ * - the displayed-pick state (text, source, render timestamp)
5
+ * - cancel + reconcile-against-LLM helpers
6
+ *
7
+ * Extracted from `GhostEditor.requestPrediction` as refactor #57 slice 5.
8
+ * The editor supplies callbacks for the editor-state predicates and
9
+ * render side-effect; the manager owns timing + state transitions.
10
+ *
11
+ * Tests cover arm/cancel/clear/reconcile in isolation without spinning
12
+ * up a full editor. Editor wiring is a thin delegation layer.
13
+ */
14
+ import { pickProvisional, provisionalDelayMs, type ProvisionalPick, type PickProvisionalInput, type SwapDecision } from "./provisional.js";
15
+ export interface ArmInput {
16
+ prefix: string;
17
+ picker: () => ProvisionalPick | null;
18
+ delayMs: number;
19
+ /**
20
+ * Predicate run inside the timer callback right before rendering. Must
21
+ * verify all editor-state invariants: not disposed, in-flight request
22
+ * is still ours, no ghost already shown, text + cursor unchanged. The
23
+ * manager calls `picker()` and `onShow` only when this returns true.
24
+ */
25
+ canRender: () => boolean;
26
+ /**
27
+ * Called when a provisional pick is selected and ready to render. The
28
+ * editor wires this to `applyServedGhost(...)`. The manager has already
29
+ * stamped `shown` + `shownAt` by the time this fires.
30
+ */
31
+ onShow: (pick: ProvisionalPick) => void;
32
+ }
33
+ export interface ReconcileInput {
34
+ llm: {
35
+ text: string;
36
+ score: number;
37
+ } | null;
38
+ swapMarginEnvRaw: string | undefined;
39
+ now: number;
40
+ }
41
+ export interface ReconcileResult {
42
+ decision: SwapDecision;
43
+ /** True iff a provisional pick was rendered at reconcile-time. Lets
44
+ * callers distinguish "had-provisional + LLM kept" (discard LLM) from
45
+ * "no-provisional + LLM produced" (normal install path) — both yield
46
+ * `displaced === null`. */
47
+ hadProvisional: boolean;
48
+ /** Non-null iff a provisional was displayed and the LLM is replacing
49
+ * or extending it. Carries the metric fields the editor stamps on
50
+ * the pending metric. Null when keep-decision wins OR no provisional
51
+ * was ever shown. */
52
+ displaced: {
53
+ provisionalSwapMs: number;
54
+ provisionalWasCorrect: boolean;
55
+ swapWasVisualJump: boolean;
56
+ } | null;
57
+ }
58
+ export declare class ProvisionalManager {
59
+ private timer;
60
+ private shown;
61
+ private shownAt;
62
+ /** True iff a provisional is currently rendered. Drives streaming-gate
63
+ * in the editor (no incremental paint over a provisional). */
64
+ get isShown(): boolean;
65
+ get currentPick(): ProvisionalPick | null;
66
+ /**
67
+ * Schedule a provisional pick. Cancels any prior pending timer; does
68
+ * NOT clear an already-displayed pick (callers must `clear()` if they
69
+ * want a fresh slate before re-arming).
70
+ */
71
+ arm(input: ArmInput): void;
72
+ /** Cancel a pending timer without touching the displayed pick. Safe
73
+ * to call when no timer is armed. */
74
+ cancelTimer(): void;
75
+ /** Reset all manager state (timer + displayed pick). Called by the
76
+ * editor's `clearGhost` and on dispose. */
77
+ clear(): void;
78
+ /**
79
+ * Reconcile a freshly-arrived LLM result against the currently-displayed
80
+ * provisional. Returns the swap decision + metric fields for the
81
+ * displaced provisional (null when no provisional was shown).
82
+ *
83
+ * Clears the displayed pick after reconciliation. The caller decides
84
+ * whether to render the resulting text — for `keep`, the editor
85
+ * discards the LLM result entirely and emits `produced` without
86
+ * installing a shownMetric.
87
+ */
88
+ reconcile(input: ReconcileInput): ReconcileResult;
89
+ }
90
+ /** Re-export for editor convenience — keeps the import surface tight. */
91
+ export { pickProvisional, provisionalDelayMs };
92
+ export type { ProvisionalPick, PickProvisionalInput };
93
+ //# sourceMappingURL=provisional-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provisional-manager.d.ts","sourceRoot":"","sources":["../src/provisional-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAGN,eAAe,EACf,kBAAkB,EAClB,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,YAAY,EACjB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,QAAQ;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,eAAe,GAAG,IAAI,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,SAAS,EAAE,MAAM,OAAO,CAAC;IACzB;;;;OAIG;IACH,MAAM,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAC;CACxC;AAED,MAAM,WAAW,cAAc;IAC9B,GAAG,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC5C,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,GAAG,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,eAAe;IAC/B,QAAQ,EAAE,YAAY,CAAC;IACvB;;;gCAG4B;IAC5B,cAAc,EAAE,OAAO,CAAC;IACxB;;;0BAGsB;IACtB,SAAS,EAAE;QACV,iBAAiB,EAAE,MAAM,CAAC;QAC1B,qBAAqB,EAAE,OAAO,CAAC;QAC/B,iBAAiB,EAAE,OAAO,CAAC;KAC3B,GAAG,IAAI,CAAC;CACT;AAED,qBAAa,kBAAkB;IAC9B,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,KAAK,CAAgC;IAC7C,OAAO,CAAC,OAAO,CAAK;IAEpB;mEAC+D;IAC/D,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,WAAW,IAAI,eAAe,GAAG,IAAI,CAExC;IAED;;;;OAIG;IACH,GAAG,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAa1B;0CACsC;IACtC,WAAW,IAAI,IAAI;IAOnB;gDAC4C;IAC5C,KAAK,IAAI,IAAI;IAMb;;;;;;;;;OASG;IACH,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,eAAe;CAwBjD;AAED,yEAAyE;AACzE,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,CAAC;AAC/C,YAAY,EAAE,eAAe,EAAE,oBAAoB,EAAE,CAAC"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Provisional ghost lifecycle manager. Owns:
3
+ * - the timer that fires `pickProvisional` after `provisionalDelayMs`
4
+ * - the displayed-pick state (text, source, render timestamp)
5
+ * - cancel + reconcile-against-LLM helpers
6
+ *
7
+ * Extracted from `GhostEditor.requestPrediction` as refactor #57 slice 5.
8
+ * The editor supplies callbacks for the editor-state predicates and
9
+ * render side-effect; the manager owns timing + state transitions.
10
+ *
11
+ * Tests cover arm/cancel/clear/reconcile in isolation without spinning
12
+ * up a full editor. Editor wiring is a thin delegation layer.
13
+ */
14
+ import { decideSwap, parseProvisionalPreferEnv, pickProvisional, provisionalDelayMs, } from "./provisional.js";
15
+ export class ProvisionalManager {
16
+ timer = null;
17
+ shown = null;
18
+ shownAt = 0;
19
+ /** True iff a provisional is currently rendered. Drives streaming-gate
20
+ * in the editor (no incremental paint over a provisional). */
21
+ get isShown() {
22
+ return this.shown !== null;
23
+ }
24
+ get currentPick() {
25
+ return this.shown;
26
+ }
27
+ /**
28
+ * Schedule a provisional pick. Cancels any prior pending timer; does
29
+ * NOT clear an already-displayed pick (callers must `clear()` if they
30
+ * want a fresh slate before re-arming).
31
+ */
32
+ arm(input) {
33
+ this.cancelTimer();
34
+ this.timer = setTimeout(() => {
35
+ this.timer = null;
36
+ if (!input.canRender())
37
+ return;
38
+ const pick = input.picker();
39
+ if (!pick)
40
+ return;
41
+ this.shown = pick;
42
+ this.shownAt = Date.now();
43
+ input.onShow(pick);
44
+ }, input.delayMs);
45
+ }
46
+ /** Cancel a pending timer without touching the displayed pick. Safe
47
+ * to call when no timer is armed. */
48
+ cancelTimer() {
49
+ if (this.timer) {
50
+ clearTimeout(this.timer);
51
+ this.timer = null;
52
+ }
53
+ }
54
+ /** Reset all manager state (timer + displayed pick). Called by the
55
+ * editor's `clearGhost` and on dispose. */
56
+ clear() {
57
+ this.cancelTimer();
58
+ this.shown = null;
59
+ this.shownAt = 0;
60
+ }
61
+ /**
62
+ * Reconcile a freshly-arrived LLM result against the currently-displayed
63
+ * provisional. Returns the swap decision + metric fields for the
64
+ * displaced provisional (null when no provisional was shown).
65
+ *
66
+ * Clears the displayed pick after reconciliation. The caller decides
67
+ * whether to render the resulting text — for `keep`, the editor
68
+ * discards the LLM result entirely and emits `produced` without
69
+ * installing a shownMetric.
70
+ */
71
+ reconcile(input) {
72
+ this.cancelTimer();
73
+ const hadProvisional = this.shown !== null;
74
+ const decision = decideSwap({
75
+ provisional: this.shown,
76
+ llm: input.llm,
77
+ swapMargin: parseProvisionalPreferEnv(input.swapMarginEnvRaw),
78
+ });
79
+ let displaced = null;
80
+ if (hadProvisional && decision.action !== "keep") {
81
+ displaced = {
82
+ provisionalSwapMs: Math.max(0, input.now - this.shownAt),
83
+ provisionalWasCorrect: decision.action === "extend",
84
+ swapWasVisualJump: decision.action === "swap",
85
+ };
86
+ }
87
+ // `keep` leaves the provisional in place visually; clear the state
88
+ // anyway so a subsequent request starts fresh. The editor's
89
+ // `ghostText` field still carries the rendered provisional text
90
+ // from the original `applyServedGhost` call.
91
+ this.shown = null;
92
+ this.shownAt = 0;
93
+ return { decision, hadProvisional, displaced };
94
+ }
95
+ }
96
+ /** Re-export for editor convenience — keeps the import surface tight. */
97
+ export { pickProvisional, provisionalDelayMs };
98
+ //# sourceMappingURL=provisional-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provisional-manager.js","sourceRoot":"","sources":["../src/provisional-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EACN,UAAU,EACV,yBAAyB,EACzB,eAAe,EACf,kBAAkB,GAIlB,MAAM,kBAAkB,CAAC;AA6C1B,MAAM,OAAO,kBAAkB;IACtB,KAAK,GAA0B,IAAI,CAAC;IACpC,KAAK,GAA2B,IAAI,CAAC;IACrC,OAAO,GAAG,CAAC,CAAC;IAEpB;mEAC+D;IAC/D,IAAI,OAAO;QACV,OAAO,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC;IAC5B,CAAC;IAED,IAAI,WAAW;QACd,OAAO,IAAI,CAAC,KAAK,CAAC;IACnB,CAAC;IAED;;;;OAIG;IACH,GAAG,CAAC,KAAe;QAClB,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;YAClB,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE;gBAAE,OAAO;YAC/B,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YAC5B,IAAI,CAAC,IAAI;gBAAE,OAAO;YAClB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;YAClB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC1B,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACnB,CAAC;IAED;0CACsC;IACtC,WAAW;QACV,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAChB,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACzB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACnB,CAAC;IACF,CAAC;IAED;gDAC4C;IAC5C,KAAK;QACJ,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;IAClB,CAAC;IAED;;;;;;;;;OASG;IACH,SAAS,CAAC,KAAqB;QAC9B,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC;QAC3C,MAAM,QAAQ,GAAG,UAAU,CAAC;YAC3B,WAAW,EAAE,IAAI,CAAC,KAAK;YACvB,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,UAAU,EAAE,yBAAyB,CAAC,KAAK,CAAC,gBAAgB,CAAC;SAC7D,CAAC,CAAC;QACH,IAAI,SAAS,GAAiC,IAAI,CAAC;QACnD,IAAI,cAAc,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAClD,SAAS,GAAG;gBACX,iBAAiB,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC;gBACxD,qBAAqB,EAAE,QAAQ,CAAC,MAAM,KAAK,QAAQ;gBACnD,iBAAiB,EAAE,QAAQ,CAAC,MAAM,KAAK,MAAM;aAC7C,CAAC;QACH,CAAC;QACD,mEAAmE;QACnE,4DAA4D;QAC5D,gEAAgE;QAChE,6CAA6C;QAC7C,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;QACjB,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,SAAS,EAAE,CAAC;IAChD,CAAC;CACD;AAED,yEAAyE;AACzE,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,CAAC"}
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Provisional ghost — fast local guess shown while the LLM is in-flight.
3
+ * PRD §M3.5b.
4
+ *
5
+ * Motivation: when the synchronous fast paths (cache, trie, speculative
6
+ * warm, profile-slash) all miss and the user is waiting on a network
7
+ * round-trip, fill the >150 ms gap with the next-best local guess so the
8
+ * user isn't staring at an empty prompt. Even an imperfect provisional
9
+ * is better than no ghost at all: typing past it dismisses without cost,
10
+ * and an LLM result that matches the provisional prefix collapses to a
11
+ * silent append rather than a visual swap.
12
+ *
13
+ * Pure functions only — no I/O, no editor state, no timers. Callers
14
+ * (the editor) own the timer that gates when this runs.
15
+ *
16
+ * Pipeline:
17
+ * 1. `pickProvisional(...)` — consult trie, profile.acceptByPrefix
18
+ * (M4), and a "common-token" fallback. Score in [0, 1]; null
19
+ * when nothing scores above `MIN_CONFIDENCE`.
20
+ * 2. `decideSwap(provisionalText, llmText)` — given the original
21
+ * provisional and the eventually-arriving LLM result, decide:
22
+ * "keep + extend", "swap", or "discard llm".
23
+ *
24
+ * The two-step shape mirrors the M3c reranker: pickProvisional is the
25
+ * displayed-ghost source; decideSwap is the reconciler when truth
26
+ * (the LLM result) arrives.
27
+ */
28
+ import type { SessionTrie } from "./session-trie.js";
29
+ import type { ProfileStore } from "./profile-store.js";
30
+ import type { LastGhostsRing } from "./speculative.js";
31
+ /** PRD §M3.5b — provisional accepts down to 0.4 (vs M3c.1's 0.55). */
32
+ export declare const MIN_CONFIDENCE = 0.4;
33
+ /** Score margin LLM must exceed provisional to trigger a swap. */
34
+ export declare const SWAP_MARGIN = 0.1;
35
+ /**
36
+ * Anti-flicker swap margin used when `PI_GHOST_PROVISIONAL_PREFER=1` is set.
37
+ * Production autocomplete systems (Cursor, Copilot) bias toward keeping the
38
+ * already-displayed candidate unless the LLM is dramatically better, since
39
+ * any visible swap is a perceived flicker on slow terminals.
40
+ */
41
+ export declare const PREFER_PROVISIONAL_SWAP_MARGIN = 0.3;
42
+ /** Prefix-match ratio above which we extend rather than swap. */
43
+ export declare const KEEP_PREFIX_MATCH = 0.8;
44
+ export type ProvisionalSource = "trie" | "profile-accept" | "session-cache";
45
+ export interface ProvisionalPick {
46
+ text: string;
47
+ score: number;
48
+ source: ProvisionalSource;
49
+ }
50
+ export interface PickProvisionalInput {
51
+ /** Active line text up to the cursor. Trie keys + profile lookups
52
+ * use the last single-line slice. */
53
+ prefix: string;
54
+ /** Session trie — local fast path. */
55
+ trie: SessionTrie | null;
56
+ /** Profile store — cross-session learned signal. */
57
+ profile: ProfileStore | null;
58
+ /** Speculative-warm ring — tertiary source. Same-session LLM ghosts
59
+ * for adjacent prefixes are high-precision provisionals because the
60
+ * provider+context fingerprints already matched at insert-time. */
61
+ lastGhosts?: LastGhostsRing | null;
62
+ }
63
+ /**
64
+ * Walk the local fast paths in priority order and return the first that
65
+ * meets `MIN_CONFIDENCE`. Trie is consulted first (user's own confirmed
66
+ * accepts in this session — highest precision). Profile.acceptByPrefix
67
+ * second (cross-session frequency for the exact-prefix hash). Returns
68
+ * null when nothing qualifies.
69
+ */
70
+ export declare function pickProvisional(input: PickProvisionalInput): ProvisionalPick | null;
71
+ /**
72
+ * Compute the prefix-match ratio between two strings: number of leading
73
+ * characters they share, divided by `max(a.length, b.length)`. Used by
74
+ * `decideSwap` to detect "LLM extends provisional" cases where no
75
+ * visual jump is needed.
76
+ */
77
+ export declare function prefixMatchRatio(a: string, b: string): number;
78
+ export type SwapDecision = {
79
+ action: "extend";
80
+ text: string;
81
+ tail: string;
82
+ } | {
83
+ action: "swap";
84
+ text: string;
85
+ reason: "score-margin" | "no-provisional";
86
+ } | {
87
+ action: "keep";
88
+ text: string;
89
+ reason: "lossy-llm" | "identical";
90
+ };
91
+ export interface DecideSwapInput {
92
+ provisional: ProvisionalPick | null;
93
+ llm: {
94
+ text: string;
95
+ score: number;
96
+ } | null;
97
+ /**
98
+ * Optional override for the LLM-vs-provisional score margin. Defaults
99
+ * to `SWAP_MARGIN`. Callers set this to `PREFER_PROVISIONAL_SWAP_MARGIN`
100
+ * when `PI_GHOST_PROVISIONAL_PREFER=1` is in force.
101
+ */
102
+ swapMargin?: number;
103
+ }
104
+ /**
105
+ * Reconcile the LLM result against the provisional. Returns the action
106
+ * the editor should take + the text to display. PRD §M3.5b decision
107
+ * matrix:
108
+ * - prefix-match ≥ KEEP_PREFIX_MATCH → extend (keep provisional,
109
+ * append LLM tail).
110
+ * - LLM score margin > swapMargin (default SWAP_MARGIN) → swap
111
+ * (visual jump, log `provisionalSwapMs`, `provisionalWasCorrect=false`).
112
+ * - LLM produced nothing → keep provisional (silent).
113
+ * - LLM differs but score not better enough → keep provisional
114
+ * (PRD: "rare; mostly when provisional was a high-quality trie hit").
115
+ */
116
+ export declare function decideSwap(input: DecideSwapInput): SwapDecision;
117
+ /**
118
+ * Convert a `[0, 1]` score (or raw weight) to the LLM-side comparable
119
+ * scale. With M3c rerank scores in `[0, 1]` and confidence-gate default
120
+ * 0.55, this is just an identity pass for clarity at call sites.
121
+ */
122
+ export declare function llmScoreFromRerank(reranked: {
123
+ score: number;
124
+ }): number;
125
+ /** Parse `PI_GHOST_PROVISIONAL`. Returns false when set to "off". */
126
+ export declare function parseProvisionalEnv(raw: string | undefined): boolean;
127
+ /**
128
+ * Parse `PI_GHOST_PROVISIONAL_PREFER`. Returns the swap-margin for
129
+ * {@link decideSwap}. Default is `PREFER_PROVISIONAL_SWAP_MARGIN` (anti-
130
+ * flicker bias) — production autocomplete systems (Cursor, Copilot, Gmail
131
+ * Smart Compose) bias toward keeping the displayed candidate unless the
132
+ * LLM is dramatically better, because any visible swap registers as a
133
+ * perceived flicker. Set to "off" / "0" / "false" / "no" to opt back into
134
+ * the aggressive `SWAP_MARGIN` (0.1) for evaluation builds.
135
+ */
136
+ export declare function parseProvisionalPreferEnv(raw: string | undefined): number;
137
+ /**
138
+ * PRD §M3.5b polish — window after a swap inside which a dismiss/abort is
139
+ * counted as a "flicker" (visual jump that didn't help the user). Bench
140
+ * uses `provisionalSwapFlicker` to track this rate so the
141
+ * `PI_GHOST_PROVISIONAL_PREFER` knob can be evaluated.
142
+ */
143
+ export declare const SWAP_FLICKER_WINDOW_MS = 250;
144
+ /**
145
+ * Default timer budget for the provisional. PRD §M3.5b says
146
+ * `min(150, provider.debounceMs)`; expose as a helper so callers don't
147
+ * duplicate the math.
148
+ */
149
+ export declare function provisionalDelayMs(providerDebounceMs: number): number;
150
+ //# sourceMappingURL=provisional.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provisional.d.ts","sourceRoot":"","sources":["../src/provisional.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD,sEAAsE;AACtE,eAAO,MAAM,cAAc,MAAM,CAAC;AAClC,kEAAkE;AAClE,eAAO,MAAM,WAAW,MAAM,CAAC;AAC/B;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,MAAM,CAAC;AAClD,iEAAiE;AACjE,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAErC,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,gBAAgB,GAAG,eAAe,CAAC;AAE5E,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,iBAAiB,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACpC;0CACsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IACzB,oDAAoD;IACpD,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;IAC7B;;wEAEoE;IACpE,UAAU,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;CACnC;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,eAAe,GAAG,IAAI,CAoEnF;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAO7D;AAED,MAAM,MAAM,YAAY,GACrB;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,cAAc,GAAG,gBAAgB,CAAA;CAAE,GAC3E;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,GAAG,WAAW,CAAA;CAAE,CAAC;AAEvE,MAAM,WAAW,eAAe;IAC/B,WAAW,EAAE,eAAe,GAAG,IAAI,CAAC;IACpC,GAAG,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC5C;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,YAAY,CAiC/D;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAEtE;AASD,qEAAqE;AACrE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAGpE;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAOzE;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,kBAAkB,EAAE,MAAM,GAAG,MAAM,CAIrE"}
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Provisional ghost — fast local guess shown while the LLM is in-flight.
3
+ * PRD §M3.5b.
4
+ *
5
+ * Motivation: when the synchronous fast paths (cache, trie, speculative
6
+ * warm, profile-slash) all miss and the user is waiting on a network
7
+ * round-trip, fill the >150 ms gap with the next-best local guess so the
8
+ * user isn't staring at an empty prompt. Even an imperfect provisional
9
+ * is better than no ghost at all: typing past it dismisses without cost,
10
+ * and an LLM result that matches the provisional prefix collapses to a
11
+ * silent append rather than a visual swap.
12
+ *
13
+ * Pure functions only — no I/O, no editor state, no timers. Callers
14
+ * (the editor) own the timer that gates when this runs.
15
+ *
16
+ * Pipeline:
17
+ * 1. `pickProvisional(...)` — consult trie, profile.acceptByPrefix
18
+ * (M4), and a "common-token" fallback. Score in [0, 1]; null
19
+ * when nothing scores above `MIN_CONFIDENCE`.
20
+ * 2. `decideSwap(provisionalText, llmText)` — given the original
21
+ * provisional and the eventually-arriving LLM result, decide:
22
+ * "keep + extend", "swap", or "discard llm".
23
+ *
24
+ * The two-step shape mirrors the M3c reranker: pickProvisional is the
25
+ * displayed-ghost source; decideSwap is the reconciler when truth
26
+ * (the LLM result) arrives.
27
+ */
28
+ /** PRD §M3.5b — provisional accepts down to 0.4 (vs M3c.1's 0.55). */
29
+ export const MIN_CONFIDENCE = 0.4;
30
+ /** Score margin LLM must exceed provisional to trigger a swap. */
31
+ export const SWAP_MARGIN = 0.1;
32
+ /**
33
+ * Anti-flicker swap margin used when `PI_GHOST_PROVISIONAL_PREFER=1` is set.
34
+ * Production autocomplete systems (Cursor, Copilot) bias toward keeping the
35
+ * already-displayed candidate unless the LLM is dramatically better, since
36
+ * any visible swap is a perceived flicker on slow terminals.
37
+ */
38
+ export const PREFER_PROVISIONAL_SWAP_MARGIN = 0.3;
39
+ /** Prefix-match ratio above which we extend rather than swap. */
40
+ export const KEEP_PREFIX_MATCH = 0.8;
41
+ /**
42
+ * Walk the local fast paths in priority order and return the first that
43
+ * meets `MIN_CONFIDENCE`. Trie is consulted first (user's own confirmed
44
+ * accepts in this session — highest precision). Profile.acceptByPrefix
45
+ * second (cross-session frequency for the exact-prefix hash). Returns
46
+ * null when nothing qualifies.
47
+ */
48
+ export function pickProvisional(input) {
49
+ const { prefix, trie, profile, lastGhosts } = input;
50
+ if (!prefix)
51
+ return null;
52
+ const lastLine = prefix.split("\n").pop() ?? "";
53
+ if (!lastLine)
54
+ return null;
55
+ // Trie: PRD §M2 lookup already returns null below its own internal
56
+ // gates (min-prefix-len, min-weight, min-margin). When it returns a
57
+ // hit we trust it; map its weight to a [0, 1] score via a saturating
58
+ // transform so the swap-decision code can compare across sources.
59
+ if (trie) {
60
+ const hit = trie.lookup(lastLine);
61
+ if (hit) {
62
+ // Weight ≥ 1.5 (trie's own gate). Saturate at weight=6 → score 1.
63
+ // Below 1.5 → 0; saturates above.
64
+ const score = clamp01((hit.weight - 1.5) / 4.5 + 0.6);
65
+ if (score >= MIN_CONFIDENCE) {
66
+ return { text: hit.ghost, score, source: "trie" };
67
+ }
68
+ }
69
+ }
70
+ // Profile.acceptByPrefix: keyed by SHA-256(prefix). Direct hit means
71
+ // the user has accepted *this exact prefix* before. High signal, but
72
+ // the stored `completionTokens` are tokenized, so we render them
73
+ // space-joined as the ghost. Detokenization is lossy — this only
74
+ // fires for plain-word completions, which is fine for fallback.
75
+ if (profile && !profile.disabled) {
76
+ const hit = profile.lookupAcceptByPrefix(lastLine);
77
+ if (hit && hit.completionTokens.length > 0) {
78
+ // Weight ≥ 1 (every accept records weight 3 today). Saturate
79
+ // at weight=9 → score 1. Below 1 → minimum score, gated by
80
+ // MIN_CONFIDENCE.
81
+ const score = clamp01((hit.weight - 1) / 8 + 0.45);
82
+ if (score >= MIN_CONFIDENCE) {
83
+ return {
84
+ text: " " + hit.completionTokens.join(" "),
85
+ source: "profile-accept",
86
+ score,
87
+ };
88
+ }
89
+ }
90
+ }
91
+ // Speculative-warm ring: tertiary source. Ring entries store the FULL
92
+ // multi-line `textBeforeCursor` as their prefix (set by the editor in
93
+ // `requestPrediction`), so we compare against the full `prefix`, not
94
+ // the last-line slice trie/profile use. Score is recency-weighted in
95
+ // `[MIN_CONFIDENCE, 0.7]` — below trie but above the floor.
96
+ //
97
+ // Fingerprints are intentionally NOT checked: trie + profile-accept
98
+ // follow the same precedent (purely text-based, session-wide). A
99
+ // cross-context guess that doesn't match gets dismissed by the user
100
+ // at next keystroke, same as a bad trie hit.
101
+ if (lastGhosts) {
102
+ const entries = lastGhosts.entries();
103
+ for (let i = entries.length - 1; i >= 0; i--) {
104
+ const lg = entries[i];
105
+ if (lg.prefix !== prefix)
106
+ continue;
107
+ if (!lg.ghost)
108
+ continue;
109
+ // Most recent entry gets 0.7, oldest entry gets MIN_CONFIDENCE.
110
+ const recencyFactor = entries.length === 1 ? 1 : i / (entries.length - 1);
111
+ const score = MIN_CONFIDENCE + recencyFactor * (0.7 - MIN_CONFIDENCE);
112
+ return { text: lg.ghost, source: "session-cache", score };
113
+ }
114
+ }
115
+ return null;
116
+ }
117
+ /**
118
+ * Compute the prefix-match ratio between two strings: number of leading
119
+ * characters they share, divided by `max(a.length, b.length)`. Used by
120
+ * `decideSwap` to detect "LLM extends provisional" cases where no
121
+ * visual jump is needed.
122
+ */
123
+ export function prefixMatchRatio(a, b) {
124
+ if (a === b)
125
+ return 1;
126
+ if (a.length === 0 || b.length === 0)
127
+ return 0;
128
+ let i = 0;
129
+ const n = Math.min(a.length, b.length);
130
+ while (i < n && a[i] === b[i])
131
+ i++;
132
+ return i / Math.max(a.length, b.length);
133
+ }
134
+ /**
135
+ * Reconcile the LLM result against the provisional. Returns the action
136
+ * the editor should take + the text to display. PRD §M3.5b decision
137
+ * matrix:
138
+ * - prefix-match ≥ KEEP_PREFIX_MATCH → extend (keep provisional,
139
+ * append LLM tail).
140
+ * - LLM score margin > swapMargin (default SWAP_MARGIN) → swap
141
+ * (visual jump, log `provisionalSwapMs`, `provisionalWasCorrect=false`).
142
+ * - LLM produced nothing → keep provisional (silent).
143
+ * - LLM differs but score not better enough → keep provisional
144
+ * (PRD: "rare; mostly when provisional was a high-quality trie hit").
145
+ */
146
+ export function decideSwap(input) {
147
+ const { provisional, llm } = input;
148
+ const margin = typeof input.swapMargin === "number" && Number.isFinite(input.swapMargin)
149
+ ? input.swapMargin
150
+ : SWAP_MARGIN;
151
+ if (!provisional && !llm) {
152
+ return { action: "keep", text: "", reason: "identical" };
153
+ }
154
+ if (!provisional && llm) {
155
+ return { action: "swap", text: llm.text, reason: "no-provisional" };
156
+ }
157
+ if (provisional && !llm) {
158
+ return { action: "keep", text: provisional.text, reason: "lossy-llm" };
159
+ }
160
+ const p = provisional;
161
+ const l = llm;
162
+ if (p.text === l.text) {
163
+ return { action: "keep", text: p.text, reason: "identical" };
164
+ }
165
+ const pm = prefixMatchRatio(p.text, l.text);
166
+ if (pm >= KEEP_PREFIX_MATCH) {
167
+ // LLM extended (or trimmed) the provisional. Take the longer of
168
+ // the two so the user sees the full LLM output without losing
169
+ // what they already accepted-by-eye.
170
+ const longer = l.text.length >= p.text.length ? l.text : p.text;
171
+ const tail = longer.length > p.text.length ? longer.slice(p.text.length) : "";
172
+ return { action: "extend", text: longer, tail };
173
+ }
174
+ if (l.score > p.score + margin) {
175
+ return { action: "swap", text: l.text, reason: "score-margin" };
176
+ }
177
+ return { action: "keep", text: p.text, reason: "lossy-llm" };
178
+ }
179
+ /**
180
+ * Convert a `[0, 1]` score (or raw weight) to the LLM-side comparable
181
+ * scale. With M3c rerank scores in `[0, 1]` and confidence-gate default
182
+ * 0.55, this is just an identity pass for clarity at call sites.
183
+ */
184
+ export function llmScoreFromRerank(reranked) {
185
+ return clamp01(reranked.score);
186
+ }
187
+ function clamp01(x) {
188
+ if (!Number.isFinite(x))
189
+ return 0;
190
+ if (x < 0)
191
+ return 0;
192
+ if (x > 1)
193
+ return 1;
194
+ return x;
195
+ }
196
+ /** Parse `PI_GHOST_PROVISIONAL`. Returns false when set to "off". */
197
+ export function parseProvisionalEnv(raw) {
198
+ if (raw === undefined)
199
+ return true;
200
+ return raw.toLowerCase() !== "off";
201
+ }
202
+ /**
203
+ * Parse `PI_GHOST_PROVISIONAL_PREFER`. Returns the swap-margin for
204
+ * {@link decideSwap}. Default is `PREFER_PROVISIONAL_SWAP_MARGIN` (anti-
205
+ * flicker bias) — production autocomplete systems (Cursor, Copilot, Gmail
206
+ * Smart Compose) bias toward keeping the displayed candidate unless the
207
+ * LLM is dramatically better, because any visible swap registers as a
208
+ * perceived flicker. Set to "off" / "0" / "false" / "no" to opt back into
209
+ * the aggressive `SWAP_MARGIN` (0.1) for evaluation builds.
210
+ */
211
+ export function parseProvisionalPreferEnv(raw) {
212
+ if (raw === undefined)
213
+ return PREFER_PROVISIONAL_SWAP_MARGIN;
214
+ const norm = raw.toLowerCase();
215
+ if (norm === "0" || norm === "false" || norm === "off" || norm === "no") {
216
+ return SWAP_MARGIN;
217
+ }
218
+ return PREFER_PROVISIONAL_SWAP_MARGIN;
219
+ }
220
+ /**
221
+ * PRD §M3.5b polish — window after a swap inside which a dismiss/abort is
222
+ * counted as a "flicker" (visual jump that didn't help the user). Bench
223
+ * uses `provisionalSwapFlicker` to track this rate so the
224
+ * `PI_GHOST_PROVISIONAL_PREFER` knob can be evaluated.
225
+ */
226
+ export const SWAP_FLICKER_WINDOW_MS = 250;
227
+ /**
228
+ * Default timer budget for the provisional. PRD §M3.5b says
229
+ * `min(150, provider.debounceMs)`; expose as a helper so callers don't
230
+ * duplicate the math.
231
+ */
232
+ export function provisionalDelayMs(providerDebounceMs) {
233
+ const cap = 150;
234
+ if (!Number.isFinite(providerDebounceMs) || providerDebounceMs <= 0)
235
+ return cap;
236
+ return Math.min(cap, providerDebounceMs);
237
+ }
238
+ //# sourceMappingURL=provisional.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provisional.js","sourceRoot":"","sources":["../src/provisional.ts"],"names":[],"mappings":"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"}