@cortexkit/opencode-openai-auth 0.11.0 → 1.0.0

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 (204) hide show
  1. package/README.md +15 -26
  2. package/dist/index-766sfrh5.js +1 -0
  3. package/dist/index-8kj7sa1p.js +12 -0
  4. package/dist/index-8rqfbhfw.js +221 -0
  5. package/dist/index-b3q3j39x.js +2 -0
  6. package/dist/index-bmd7x5aq.js +2 -0
  7. package/dist/index-eqh53k8v.js +2 -0
  8. package/dist/{index-sdt2d2ra.js → index-hy9030jh.js} +1 -1
  9. package/dist/index-jyr8y8k4.js +7 -0
  10. package/dist/index-rv08jmd4.js +2 -0
  11. package/dist/index.d.ts +578 -145
  12. package/dist/index.js +1 -110
  13. package/dist/pool-lifecycle-DbDmgabd.d.ts +2430 -0
  14. package/dist/port-file-Do3lQIEk.d.ts +29 -0
  15. package/dist/protocol-BOBdkqqm.d.ts +198 -0
  16. package/dist/rpc/port-file.d.ts +4 -17
  17. package/dist/rpc/port-file.js +1 -1
  18. package/dist/rpc/protocol.d.ts +2 -2
  19. package/dist/rpc/protocol.js +1 -0
  20. package/dist/rpc/rpc-client.d.ts +5 -4
  21. package/dist/rpc/rpc-client.js +1 -1
  22. package/dist/rpc/rpc-dir.d.ts +2 -0
  23. package/dist/rpc/rpc-dir.js +1 -1
  24. package/dist/sidebar-state-D6cUKgkm.d.ts +385 -0
  25. package/dist/sidebar-state.d.ts +2 -2
  26. package/dist/sidebar-state.js +1 -1
  27. package/dist/token-util-wdza526f.js +1 -0
  28. package/dist/{token-9823y0pc.js → token-ypk61xj0.js} +1 -1
  29. package/dist/tui-preferences.js +5 -2
  30. package/dist/tui.d.ts +9 -4
  31. package/dist/v2/server.d.ts +54 -0
  32. package/dist/v2/server.js +4 -0
  33. package/package.json +21 -9
  34. package/src/tui/entry.mjs +26 -25
  35. package/src/tui-compiled/raw/logger.js +24 -0
  36. package/src/tui-compiled/raw/rpc/protocol.js +3 -0
  37. package/src/tui-compiled/raw/rpc/rpc-client.js +7 -0
  38. package/src/tui-compiled/raw/rpc/rpc-dir.js +27 -0
  39. package/src/tui-compiled/raw/selector.js +21 -0
  40. package/src/tui-compiled/raw/shared/0332701351b3eeec-format.js +138 -0
  41. package/src/tui-compiled/raw/shared/04a6357627de5ed0-errors.js +38 -0
  42. package/src/tui-compiled/raw/shared/053cc17b5419261e-codec.js +12 -0
  43. package/src/tui-compiled/raw/shared/0766d78c6f481f18-watcher.js +157 -0
  44. package/src/tui-compiled/raw/shared/08eef45626a94992-reserved.js +13 -0
  45. package/src/tui-compiled/raw/shared/39c3cb05738fcf6d-projection.js +134 -0
  46. package/src/tui-compiled/raw/shared/3c2d4169d00f907e-tui-support.js +5 -0
  47. package/src/tui-compiled/raw/shared/3e7d45a77c6ad4d5-index.js +4 -0
  48. package/src/tui-compiled/raw/shared/415792e85d80819e-capture-sink.js +13 -0
  49. package/src/tui-compiled/raw/shared/42ae93ab554fcec2-open-url.js +28 -0
  50. package/src/tui-compiled/raw/shared/43fc9e6b994519c7-refresh-lock.js +136 -0
  51. package/src/tui-compiled/raw/shared/458b934e92490331-mutate.js +500 -0
  52. package/src/tui-compiled/raw/shared/45bf5343bbbf9add-admission.js +142 -0
  53. package/src/tui-compiled/raw/shared/46f3dff1266160e8-client.js +2 -0
  54. package/src/tui-compiled/raw/shared/4825e03209d6ae3e-with-lock.js +48 -0
  55. package/src/tui-compiled/raw/shared/4f36d333d081d040-merge.js +162 -0
  56. package/src/tui-compiled/raw/shared/54eba94fd64c8c3c-index.js +7 -0
  57. package/src/tui-compiled/raw/shared/7211cfec06a298bc-atomic-write.js +80 -0
  58. package/src/tui-compiled/raw/shared/754d6017f8e419cf-builtins.js +534 -0
  59. package/src/tui-compiled/raw/shared/75bd8c3bd63b315f-identity.js +79 -0
  60. package/src/tui-compiled/raw/shared/7a91bb630e6f4804-index.js +1 -0
  61. package/src/tui-compiled/raw/shared/826342a4b6a8b89b-model.js +16 -0
  62. package/src/tui-compiled/raw/shared/83068c0dbe8a6f13-publication.js +304 -0
  63. package/src/tui-compiled/raw/shared/836fc615de6afbd9-settings.js +120 -0
  64. package/src/tui-compiled/raw/shared/83bc3ba9d0fe2761-runtime.js +68 -0
  65. package/src/tui-compiled/raw/shared/8a18abe4fa2977c8-menu.js +300 -0
  66. package/src/tui-compiled/raw/shared/901e149c5a0dbbff-sticky.js +339 -0
  67. package/src/tui-compiled/raw/shared/9020c407ce64f672-ordered.js +58 -0
  68. package/src/tui-compiled/raw/shared/905bffc0220f43d0-map.js +105 -0
  69. package/src/tui-compiled/raw/shared/94820e324f2b4c09-seam.js +301 -0
  70. package/src/tui-compiled/raw/shared/97484d9bb98c705b-provider-state.js +226 -0
  71. package/src/tui-compiled/raw/shared/9968e3cade6969a1-index.js +2 -0
  72. package/src/tui-compiled/raw/shared/9b4da614c45f9cd0-lock-constants.js +14 -0
  73. package/src/tui-compiled/raw/shared/9d3fc9e37456504e-refresh.js +225 -0
  74. package/src/tui-compiled/raw/shared/9deae3c4da4fd63b-hooks.js +34 -0
  75. package/src/tui-compiled/raw/shared/a09b6a533c11858f-tui-preferences.js +77 -0
  76. package/src/tui-compiled/raw/shared/a62a27a204266acd-attribution.js +60 -0
  77. package/src/tui-compiled/raw/shared/a910277ac43a8626-pull.js +143 -0
  78. package/src/tui-compiled/raw/shared/b85c5301fddcb98a-paths.js +5 -0
  79. package/src/tui-compiled/raw/shared/c14988621dc60a75-port-file.js +217 -0
  80. package/src/tui-compiled/raw/shared/c64d7afbc14ca125-sidebar-file.js +157 -0
  81. package/src/tui-compiled/raw/shared/c6b176708c446d6d-pins.js +34 -0
  82. package/src/tui-compiled/raw/shared/c7d252bedee01600-pi.js +206 -0
  83. package/src/tui-compiled/raw/shared/c852a15cfe489d12-pool.js +120 -0
  84. package/src/tui-compiled/raw/shared/cc9e0702a752cea7-index.js +3 -0
  85. package/src/tui-compiled/raw/shared/cd94316a888b0a8e-schema.js +754 -0
  86. package/src/tui-compiled/raw/shared/d319517e3ea6ad70-redact.js +83 -0
  87. package/src/tui-compiled/raw/shared/d5a8f1061ee2f114-index.js +5 -0
  88. package/src/tui-compiled/raw/shared/d669d72c40e9e116-logger.js +19 -0
  89. package/src/tui-compiled/raw/shared/d7dcba96fea1685c-engine.js +246 -0
  90. package/src/tui-compiled/raw/shared/dbef697d1df1cd84-index.js +5 -0
  91. package/src/tui-compiled/raw/shared/e4acc4cb713f300c-protocol.js +3 -0
  92. package/src/tui-compiled/raw/shared/e8cd4929507508d8-refresh-file-lock.js +501 -0
  93. package/src/tui-compiled/raw/shared/ec971142548df90e-index.js +6 -0
  94. package/src/tui-compiled/raw/shared/f37fcefc7aedbf25-error.js +11 -0
  95. package/src/tui-compiled/raw/shared/fbcdcd0f925e74c0-rpc-client.js +253 -0
  96. package/src/tui-compiled/raw/shared/fd45e82f2f9c0a0d-torn.js +294 -0
  97. package/src/tui-compiled/raw/shared/fe02abeadc535f77-rows.js +1258 -0
  98. package/src/tui-compiled/raw/sidebar-state.js +960 -0
  99. package/src/tui-compiled/raw/tui/command-dialogs.tsx +424 -0
  100. package/src/tui-compiled/raw/tui-preferences.js +135 -0
  101. package/src/tui-compiled/raw/tui.tsx +135 -143
  102. package/src/tui-compiled/runtime/logger.js +24 -0
  103. package/src/tui-compiled/runtime/rpc/protocol.js +3 -0
  104. package/src/tui-compiled/runtime/rpc/rpc-client.js +7 -0
  105. package/src/tui-compiled/runtime/rpc/rpc-dir.js +27 -0
  106. package/src/tui-compiled/runtime/selector.js +21 -0
  107. package/src/tui-compiled/runtime/shared/0332701351b3eeec-format.js +138 -0
  108. package/src/tui-compiled/runtime/shared/04a6357627de5ed0-errors.js +38 -0
  109. package/src/tui-compiled/runtime/shared/053cc17b5419261e-codec.js +12 -0
  110. package/src/tui-compiled/runtime/shared/0766d78c6f481f18-watcher.js +157 -0
  111. package/src/tui-compiled/runtime/shared/08eef45626a94992-reserved.js +13 -0
  112. package/src/tui-compiled/runtime/shared/39c3cb05738fcf6d-projection.js +134 -0
  113. package/src/tui-compiled/runtime/shared/3c2d4169d00f907e-tui-support.js +5 -0
  114. package/src/tui-compiled/runtime/shared/3e7d45a77c6ad4d5-index.js +4 -0
  115. package/src/tui-compiled/runtime/shared/415792e85d80819e-capture-sink.js +13 -0
  116. package/src/tui-compiled/runtime/shared/42ae93ab554fcec2-open-url.js +28 -0
  117. package/src/tui-compiled/runtime/shared/43fc9e6b994519c7-refresh-lock.js +136 -0
  118. package/src/tui-compiled/runtime/shared/458b934e92490331-mutate.js +500 -0
  119. package/src/tui-compiled/runtime/shared/45bf5343bbbf9add-admission.js +142 -0
  120. package/src/tui-compiled/runtime/shared/46f3dff1266160e8-client.js +2 -0
  121. package/src/tui-compiled/runtime/shared/4825e03209d6ae3e-with-lock.js +48 -0
  122. package/src/tui-compiled/runtime/shared/4f36d333d081d040-merge.js +162 -0
  123. package/src/tui-compiled/runtime/shared/54eba94fd64c8c3c-index.js +7 -0
  124. package/src/tui-compiled/runtime/shared/7211cfec06a298bc-atomic-write.js +80 -0
  125. package/src/tui-compiled/runtime/shared/754d6017f8e419cf-builtins.js +534 -0
  126. package/src/tui-compiled/runtime/shared/75bd8c3bd63b315f-identity.js +79 -0
  127. package/src/tui-compiled/runtime/shared/7a91bb630e6f4804-index.js +1 -0
  128. package/src/tui-compiled/runtime/shared/826342a4b6a8b89b-model.js +16 -0
  129. package/src/tui-compiled/runtime/shared/83068c0dbe8a6f13-publication.js +304 -0
  130. package/src/tui-compiled/runtime/shared/836fc615de6afbd9-settings.js +120 -0
  131. package/src/tui-compiled/runtime/shared/83bc3ba9d0fe2761-runtime.js +68 -0
  132. package/src/tui-compiled/runtime/shared/8a18abe4fa2977c8-menu.js +300 -0
  133. package/src/tui-compiled/runtime/shared/901e149c5a0dbbff-sticky.js +339 -0
  134. package/src/tui-compiled/runtime/shared/9020c407ce64f672-ordered.js +58 -0
  135. package/src/tui-compiled/runtime/shared/905bffc0220f43d0-map.js +105 -0
  136. package/src/tui-compiled/runtime/shared/94820e324f2b4c09-seam.js +301 -0
  137. package/src/tui-compiled/runtime/shared/97484d9bb98c705b-provider-state.js +226 -0
  138. package/src/tui-compiled/runtime/shared/9968e3cade6969a1-index.js +2 -0
  139. package/src/tui-compiled/runtime/shared/9b4da614c45f9cd0-lock-constants.js +14 -0
  140. package/src/tui-compiled/runtime/shared/9d3fc9e37456504e-refresh.js +225 -0
  141. package/src/tui-compiled/runtime/shared/9deae3c4da4fd63b-hooks.js +34 -0
  142. package/src/tui-compiled/runtime/shared/a09b6a533c11858f-tui-preferences.js +77 -0
  143. package/src/tui-compiled/runtime/shared/a62a27a204266acd-attribution.js +60 -0
  144. package/src/tui-compiled/runtime/shared/a910277ac43a8626-pull.js +143 -0
  145. package/src/tui-compiled/runtime/shared/b85c5301fddcb98a-paths.js +5 -0
  146. package/src/tui-compiled/runtime/shared/c14988621dc60a75-port-file.js +217 -0
  147. package/src/tui-compiled/runtime/shared/c64d7afbc14ca125-sidebar-file.js +157 -0
  148. package/src/tui-compiled/runtime/shared/c6b176708c446d6d-pins.js +34 -0
  149. package/src/tui-compiled/runtime/shared/c7d252bedee01600-pi.js +206 -0
  150. package/src/tui-compiled/runtime/shared/c852a15cfe489d12-pool.js +120 -0
  151. package/src/tui-compiled/runtime/shared/cc9e0702a752cea7-index.js +3 -0
  152. package/src/tui-compiled/runtime/shared/cd94316a888b0a8e-schema.js +754 -0
  153. package/src/tui-compiled/runtime/shared/d319517e3ea6ad70-redact.js +83 -0
  154. package/src/tui-compiled/runtime/shared/d5a8f1061ee2f114-index.js +5 -0
  155. package/src/tui-compiled/runtime/shared/d669d72c40e9e116-logger.js +19 -0
  156. package/src/tui-compiled/runtime/shared/d7dcba96fea1685c-engine.js +246 -0
  157. package/src/tui-compiled/runtime/shared/dbef697d1df1cd84-index.js +5 -0
  158. package/src/tui-compiled/runtime/shared/e4acc4cb713f300c-protocol.js +3 -0
  159. package/src/tui-compiled/runtime/shared/e8cd4929507508d8-refresh-file-lock.js +501 -0
  160. package/src/tui-compiled/runtime/shared/ec971142548df90e-index.js +6 -0
  161. package/src/tui-compiled/runtime/shared/f37fcefc7aedbf25-error.js +11 -0
  162. package/src/tui-compiled/runtime/shared/fbcdcd0f925e74c0-rpc-client.js +253 -0
  163. package/src/tui-compiled/runtime/shared/fd45e82f2f9c0a0d-torn.js +294 -0
  164. package/src/tui-compiled/runtime/shared/fe02abeadc535f77-rows.js +1258 -0
  165. package/src/tui-compiled/runtime/sidebar-state.js +960 -0
  166. package/src/tui-compiled/runtime/tui/command-dialogs.js +378 -0
  167. package/src/tui-compiled/runtime/tui-preferences.js +135 -0
  168. package/src/tui-compiled/runtime/{tui.tsx → tui.js} +288 -316
  169. package/dist/index-4effjmr6.js +0 -2
  170. package/dist/index-9ehhb051.js +0 -2
  171. package/dist/index-g3hsdjh4.js +0 -2
  172. package/dist/index-hh52v8sb.js +0 -2
  173. package/dist/index-jwn4r3sw.js +0 -1
  174. package/dist/index-sq36b120.js +0 -211
  175. package/dist/internal-BTndPmW2.d.ts +0 -914
  176. package/dist/quota-normalize-08hpp51v.js +0 -1
  177. package/dist/sidebar-state-CoKYKcLn.d.ts +0 -220
  178. package/dist/token-util-ypgz7rge.js +0 -1
  179. package/src/tui-compiled/raw/core-account-paths.ts +0 -114
  180. package/src/tui-compiled/raw/core-custody-state.ts +0 -243
  181. package/src/tui-compiled/raw/logger.ts +0 -53
  182. package/src/tui-compiled/raw/rpc-port-file.ts +0 -177
  183. package/src/tui-compiled/raw/rpc-protocol.ts +0 -12
  184. package/src/tui-compiled/raw/rpc-rpc-client.ts +0 -82
  185. package/src/tui-compiled/raw/rpc-rpc-dir.ts +0 -46
  186. package/src/tui-compiled/raw/sidebar-state.ts +0 -1659
  187. package/src/tui-compiled/raw/tui-command-dialogs.tsx +0 -1096
  188. package/src/tui-compiled/raw/tui-preferences.ts +0 -328
  189. package/src/tui-compiled/runtime/core-account-paths.ts +0 -114
  190. package/src/tui-compiled/runtime/core-custody-state.ts +0 -243
  191. package/src/tui-compiled/runtime/logger.ts +0 -53
  192. package/src/tui-compiled/runtime/rpc-port-file.ts +0 -177
  193. package/src/tui-compiled/runtime/rpc-protocol.ts +0 -12
  194. package/src/tui-compiled/runtime/rpc-rpc-client.ts +0 -82
  195. package/src/tui-compiled/runtime/rpc-rpc-dir.ts +0 -46
  196. package/src/tui-compiled/runtime/sidebar-state.ts +0 -1659
  197. package/src/tui-compiled/runtime/tui-command-dialogs.tsx +0 -855
  198. package/src/tui-compiled/runtime/tui-preferences.ts +0 -328
  199. package/src/tui-compiled/shared/internal.ts +0 -6
  200. package/src/tui-compiled/shared/logger.ts +0 -264
  201. package/src/tui-compiled/shared/paths.ts +0 -33
  202. package/src/tui-compiled/shared/refresh-file-lock.ts +0 -384
  203. package/src/tui-compiled/shared/util/error.ts +0 -9
  204. package/src/tui-compiled/shared/util/open-url.ts +0 -30
@@ -0,0 +1,58 @@
1
+ // `ordered` routing: admitted rows tried in a fixed order, moving to the next
2
+ // row only when a response carries one of the caller's retry statuses.
3
+ import { admit, } from "./45bf5343bbbf9add-admission.js";
4
+ /** The former main row's id when the caller supplies none. */
5
+ export const DEFAULT_FORMER_MAIN_ID = 'main';
6
+ /**
7
+ * Resolves a persisted `routing.mode` value. `main-first` and
8
+ * `fallback-first` are aliases of `ordered` that move the former main row;
9
+ * an absent or unrecognised value is `ordered` in roster order. The
10
+ * persisted value is only read here, never rewritten.
11
+ */
12
+ export function resolveRoutingMode(value) {
13
+ switch (value) {
14
+ case 'sticky-balanced':
15
+ return { mode: 'sticky-balanced', placement: 'roster' };
16
+ case 'main-first':
17
+ return { mode: 'ordered', placement: 'main-first' };
18
+ case 'fallback-first':
19
+ return { mode: 'ordered', placement: 'fallback-first' };
20
+ default:
21
+ return { mode: 'ordered', placement: 'roster' };
22
+ }
23
+ }
24
+ /**
25
+ * Orders `ids` (in roster order) for a placement: `main-first` moves the row
26
+ * named `formerMainId` to the front, `fallback-first` to the back, and
27
+ * `roster` (or a missing former main row) keeps roster order.
28
+ */
29
+ export function orderForPlacement(ids, placement, formerMainId = DEFAULT_FORMER_MAIN_ID) {
30
+ if (placement === 'roster' || !ids.includes(formerMainId))
31
+ return [...ids];
32
+ const rest = ids.filter((id) => id !== formerMainId);
33
+ return placement === 'main-first'
34
+ ? [formerMainId, ...rest]
35
+ : [...rest, formerMainId];
36
+ }
37
+ export function routeOrdered(input) {
38
+ const admission = admit(input);
39
+ const admitted = new Set(admission.admitted.map((row) => row.id));
40
+ const order = orderForPlacement(input.rows.map((row) => row.id), input.placement ?? 'roster', input.formerMainId).filter((id) => admitted.has(id) && input.killswitch?.get(id) !== false);
41
+ return { order, admission };
42
+ }
43
+ /**
44
+ * The next row to try, given the attempts so far: the first row when none
45
+ * has been tried, the next untried row when the last attempt's status is one
46
+ * of `retryStatuses`, and undefined otherwise (the last response stands) or
47
+ * when every row has been tried.
48
+ */
49
+ export function nextOrderedAttempt(order, attempts, retryStatuses) {
50
+ const last = attempts.at(-1);
51
+ if (last !== undefined) {
52
+ if (last.status === undefined || !retryStatuses.includes(last.status)) {
53
+ return undefined;
54
+ }
55
+ }
56
+ const tried = new Set(attempts.map((attempt) => attempt.id));
57
+ return order.find((id) => !tried.has(id));
58
+ }
@@ -0,0 +1,105 @@
1
+ // The per-row quota map: what the pool knows about one row's limits.
2
+ //
3
+ // A row's quota is a set of keyed limits. Each key is a (scope, window label)
4
+ // pair: the scope is `all` for a limit that binds every request, or a model
5
+ // family name for a limit that binds only that family; the label names the
6
+ // window the provider reports (for example `primary` or `secondary`). Each key
7
+ // holds one entry, which is either a reading, a retirement tombstone (the key
8
+ // held a reading until an authoritative observation stopped reporting it), or
9
+ // an absence record (an authoritative observation reported the key as having
10
+ // no limit before any reading was seen). Tombstones and absence records are
11
+ // evidence that the key is known to be unlimited; a missing key is unknown.
12
+ //
13
+ // Beside the limits sits the credit budget, a third pressure axis with its own
14
+ // reset clock. It is a tri-state: absent (never reported), a reading, or
15
+ // cleared (the provider reported that no budget exists).
16
+ //
17
+ // The map is plain JSON so the store can persist it without interpreting it.
18
+ /** The scope of a limit that binds every request regardless of model. */
19
+ export const ALL_SCOPE = 'all';
20
+ /** The window label required when an admission call supplies none. */
21
+ export const DEFAULT_REQUIRED_LABELS = Object.freeze([
22
+ 'primary',
23
+ ]);
24
+ export function emptyQuotaMap() {
25
+ return { limits: [] };
26
+ }
27
+ /** The time an entry speaks for: its reading, retirement or absence time. */
28
+ export function entryTime(entry) {
29
+ return entry.kind === 'retired' ? entry.retiredAt : entry.checkedAt;
30
+ }
31
+ export function limitKey(scope, label) {
32
+ // JSON-encoding the pair keeps keys unambiguous for any scope or label text.
33
+ return JSON.stringify([scope, label]);
34
+ }
35
+ function isRecord(value) {
36
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
37
+ }
38
+ function isFiniteNumber(value) {
39
+ return typeof value === 'number' && Number.isFinite(value);
40
+ }
41
+ function isName(value) {
42
+ return typeof value === 'string' && value.length > 0;
43
+ }
44
+ function optional(record, key, check) {
45
+ return record[key] === undefined || check(record[key]);
46
+ }
47
+ function isPositiveFinite(value) {
48
+ return isFiniteNumber(value) && value > 0;
49
+ }
50
+ function isString(value) {
51
+ return typeof value === 'string';
52
+ }
53
+ function isQuotaEntry(value) {
54
+ if (!isRecord(value) || !isName(value.scope) || !isName(value.label)) {
55
+ return false;
56
+ }
57
+ switch (value.kind) {
58
+ case 'reading':
59
+ return (isFiniteNumber(value.checkedAt) &&
60
+ isFiniteNumber(value.usedPercent) &&
61
+ optional(value, 'resetsAt', isString) &&
62
+ optional(value, 'windowMinutes', isPositiveFinite));
63
+ case 'retired':
64
+ return isFiniteNumber(value.retiredAt);
65
+ case 'absent':
66
+ return isFiniteNumber(value.checkedAt);
67
+ default:
68
+ return false;
69
+ }
70
+ }
71
+ export function isCreditBudgetEntry(value) {
72
+ if (!isRecord(value) || !isFiniteNumber(value.checkedAt))
73
+ return false;
74
+ if (value.kind === 'cleared')
75
+ return true;
76
+ return (value.kind === 'reading' &&
77
+ typeof value.reached === 'boolean' &&
78
+ optional(value, 'remainingPercent', isFiniteNumber) &&
79
+ optional(value, 'usedPercent', isFiniteNumber) &&
80
+ optional(value, 'resetsAt', isString) &&
81
+ optional(value, 'limit', isFiniteNumber) &&
82
+ optional(value, 'used', isFiniteNumber) &&
83
+ optional(value, 'remaining', isFiniteNumber) &&
84
+ optional(value, 'unit', isString));
85
+ }
86
+ /**
87
+ * True when `value` is a well-formed quota map. Unrecognised top-level keys
88
+ * are tolerated (and preserved by merge) so a newer writer's additions
89
+ * survive; a malformed entry, a duplicated (scope, label) key or a malformed
90
+ * budget makes the whole map invalid.
91
+ */
92
+ export function isQuotaMap(value) {
93
+ if (!isRecord(value) || !Array.isArray(value.limits))
94
+ return false;
95
+ const seen = new Set();
96
+ for (const entry of value.limits) {
97
+ if (!isQuotaEntry(entry))
98
+ return false;
99
+ const key = limitKey(entry.scope, entry.label);
100
+ if (seen.has(key))
101
+ return false;
102
+ seen.add(key);
103
+ }
104
+ return optional(value, 'budget', isCreditBudgetEntry);
105
+ }
@@ -0,0 +1,301 @@
1
+ // The one way out of the process for anything the command menu shows. Every
2
+ // payload a renderer receives (the dialog payload and every apply result) is
3
+ // produced here: each part is projected field by field from its definition,
4
+ // so action bodies and stray properties never travel, and the whole payload
5
+ // is then scrubbed as a backstop: credential-shaped property names are
6
+ // dropped and every string value is passed through the redactor. Nothing
7
+ // outside this module can build a payload without passing through
8
+ // `dialogPayload` or `applyResult`. A failed action never shows its raw
9
+ // exception text: `projectFailure` turns it into a stable code and a message
10
+ // the library or the plugin wrote for the user.
11
+ import { createRedactor } from "./cc9e0702a752cea7-index.js";
12
+ import { PoolOperationError } from "./54eba94fd64c8c3c-index.js";
13
+ /**
14
+ * Secret shapes the seam masks on top of the logger's (bearer tokens, `sk-`
15
+ * keys, JWTs, vault host tokens): a value assigned to a secret-named field
16
+ * (`client_secret=…`, `"api_key": "…"`, `Authorization: …`), and a run of 32
17
+ * or more hex digits, the shape of a minted request secret. A plugin adds its
18
+ * provider's key shapes through `RedactionOptions.extraValuePatterns`.
19
+ */
20
+ const SEAM_VALUE_PATTERNS = [
21
+ /\b[\w-]*(?:secret|token|password|passwd|api[_-]?key|authorization|verifier)["']?\s*[:=]\s*["']?(?:(?:Bearer|Basic)\s+)?[^\s"'&,;}]+/gi,
22
+ /\b[0-9a-fA-F]{32,}\b/g,
23
+ ];
24
+ /** The string redactor every value crossing the seam goes through. */
25
+ export function createTextRedactor(options = {}) {
26
+ const { redactStrings } = createRedactor({
27
+ ...options,
28
+ extraValuePatterns: [
29
+ ...SEAM_VALUE_PATTERNS,
30
+ ...(options.extraValuePatterns ?? []),
31
+ ],
32
+ });
33
+ return (text) => redactStrings(text);
34
+ }
35
+ /**
36
+ * A failure whose message was written for the user. An action throws it to
37
+ * show `message` with the stable `code`; any other thrown value is shown only
38
+ * as a generic message, because its text may quote a request, a response or
39
+ * a credential. `code` is lowercase letters, digits and dashes; anything else
40
+ * is reported as `action-failed`.
41
+ */
42
+ export class CommandError extends Error {
43
+ code;
44
+ constructor(code, message, options) {
45
+ super(message, options);
46
+ this.name = 'CommandError';
47
+ this.code = code;
48
+ }
49
+ }
50
+ const CODE_SHAPE = /^[a-z][a-z0-9-]{0,63}$/;
51
+ /** The code and message shown for an exception the seam cannot vouch for. */
52
+ export const ACTION_FAILED = {
53
+ code: 'action-failed',
54
+ text: 'That action failed.',
55
+ };
56
+ /**
57
+ * Store failure kinds whose message the store composes itself from row ids
58
+ * and the plugin's own refusal reasons (`protect`). Other kinds can carry a
59
+ * lock or filesystem error's text, or an arbitrary exception from a hook, so
60
+ * they show a generic message with the kind as the code.
61
+ */
62
+ const STORE_KINDS_WITH_OWN_MESSAGE = new Set([
63
+ 'unknown-row',
64
+ 'invalid-row',
65
+ 'invalid-input',
66
+ 'id-exists',
67
+ 'id-removed',
68
+ 'type-mismatch',
69
+ 'no-credential',
70
+ 'row-disabled',
71
+ 'row-protected',
72
+ 'duplicate-identity',
73
+ 'row-key-changed',
74
+ 'invalid-order',
75
+ 'pending-migration',
76
+ 'provider',
77
+ 'pull',
78
+ 'attribution',
79
+ ]);
80
+ /** The code and display text for a thrown value; never its raw text. */
81
+ export function projectFailure(error) {
82
+ if (error instanceof CommandError)
83
+ return {
84
+ code: CODE_SHAPE.test(error.code) ? error.code : ACTION_FAILED.code,
85
+ text: error.message,
86
+ };
87
+ if (error instanceof PoolOperationError)
88
+ return {
89
+ code: `pool-${error.kind}`,
90
+ text: STORE_KINDS_WITH_OWN_MESSAGE.has(error.kind)
91
+ ? error.message
92
+ : `The account pool could not do that (${error.kind}).`,
93
+ };
94
+ return ACTION_FAILED;
95
+ }
96
+ /** The confirmation shown when an irreversible action names none. */
97
+ export const DEFAULT_IRREVERSIBLE_CONFIRMATION = 'This cannot be undone. Continue?';
98
+ const CREDENTIAL_NAMES = new Set([
99
+ 'access',
100
+ 'refresh',
101
+ 'apikey',
102
+ 'password',
103
+ 'authheader',
104
+ 'credential',
105
+ 'credentials',
106
+ ]);
107
+ /**
108
+ * True for a property name that looks like it holds a secret. Case, `-` and
109
+ * `_` are ignored, so `api_key`, `API-Key` and `apiKey` all match. Any name
110
+ * ending in `token`, `key` or `secret` matches: no menu field is named that
111
+ * way, so a match is a leak whatever the rest of the name says.
112
+ */
113
+ function isCredentialName(name) {
114
+ const normalized = name.toLowerCase().replace(/[-_]/g, '');
115
+ return (CREDENTIAL_NAMES.has(normalized) ||
116
+ normalized.endsWith('token') ||
117
+ normalized.endsWith('key') ||
118
+ normalized.endsWith('secret'));
119
+ }
120
+ function isPlainRecord(value) {
121
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
122
+ }
123
+ /**
124
+ * A copy of `value` without credential-shaped properties and with every
125
+ * string redacted; the paths of both go to `report`.
126
+ */
127
+ function scrub(value, path, report) {
128
+ if (typeof value === 'string') {
129
+ const clean = report.redact(value);
130
+ if (clean !== value)
131
+ report.redacted.push(path);
132
+ return clean;
133
+ }
134
+ if (Array.isArray(value))
135
+ return value.map((entry, index) => scrub(entry, `${path}[${index}]`, report));
136
+ if (!isPlainRecord(value))
137
+ return value;
138
+ const out = {};
139
+ for (const [name, entry] of Object.entries(value)) {
140
+ if (isCredentialName(name)) {
141
+ report.dropped.push(`${path}.${name}`);
142
+ continue;
143
+ }
144
+ Object.defineProperty(out, name, {
145
+ value: scrub(entry, `${path}.${name}`, report),
146
+ enumerable: true,
147
+ writable: true,
148
+ configurable: true,
149
+ });
150
+ }
151
+ return out;
152
+ }
153
+ function sealed(payload, command, seam) {
154
+ const report = {
155
+ redact: seam.redact,
156
+ dropped: [],
157
+ redacted: [],
158
+ };
159
+ const clean = scrub(payload, 'payload', report);
160
+ if (report.dropped.length > 0)
161
+ seam.logger.warn('credential-shaped field dropped from a command payload', {
162
+ command,
163
+ fields: report.dropped,
164
+ });
165
+ if (report.redacted.length > 0)
166
+ seam.logger.warn('secret-shaped text masked in a command payload', {
167
+ command,
168
+ fields: report.redacted,
169
+ });
170
+ return clean;
171
+ }
172
+ function projectChoice(choice) {
173
+ return { value: String(choice.value), label: String(choice.label) };
174
+ }
175
+ function projectKnob(knob) {
176
+ switch (knob.kind) {
177
+ case 'choice':
178
+ return {
179
+ kind: 'choice',
180
+ id: knob.id,
181
+ label: knob.label,
182
+ choices: (knob.choices ?? []).map(projectChoice),
183
+ ...(knob.value !== undefined ? { value: knob.value } : {}),
184
+ };
185
+ case 'toggle':
186
+ return {
187
+ kind: 'toggle',
188
+ id: knob.id,
189
+ label: knob.label,
190
+ value: knob.value === true,
191
+ };
192
+ case 'number':
193
+ return {
194
+ kind: 'number',
195
+ id: knob.id,
196
+ label: knob.label,
197
+ ...(knob.value !== undefined ? { value: knob.value } : {}),
198
+ ...(knob.min !== undefined ? { min: knob.min } : {}),
199
+ ...(knob.max !== undefined ? { max: knob.max } : {}),
200
+ ...(knob.required ? { required: true } : {}),
201
+ };
202
+ case 'text':
203
+ // A masked input holds a secret, so its current value is never shown;
204
+ // the action still receives it when the user leaves the input alone.
205
+ return {
206
+ kind: 'text',
207
+ id: knob.id,
208
+ label: knob.label,
209
+ ...(knob.value !== undefined && !knob.masked
210
+ ? { value: knob.value }
211
+ : {}),
212
+ ...(knob.placeholder !== undefined
213
+ ? { placeholder: knob.placeholder }
214
+ : {}),
215
+ ...(knob.masked ? { masked: true } : {}),
216
+ ...(knob.required ? { required: true } : {}),
217
+ };
218
+ }
219
+ }
220
+ /**
221
+ * The confirmation an action must pass before it runs, or undefined. An
222
+ * irreversible action always has one, even when its definition (built
223
+ * outside the type checker) names none.
224
+ */
225
+ export function confirmationOf(action) {
226
+ if (action.irreversible === true)
227
+ return {
228
+ message: action.confirm || DEFAULT_IRREVERSIBLE_CONFIRMATION,
229
+ irreversible: true,
230
+ };
231
+ if (action.confirm)
232
+ return { message: action.confirm, irreversible: false };
233
+ return undefined;
234
+ }
235
+ function projectAction(action) {
236
+ const confirm = confirmationOf(action);
237
+ return {
238
+ id: action.id,
239
+ label: action.label,
240
+ ...(action.description !== undefined
241
+ ? { description: action.description }
242
+ : {}),
243
+ ...(action.group !== undefined ? { group: String(action.group) } : {}),
244
+ knobs: (action.knobs ?? []).map(projectKnob),
245
+ ...(confirm ? { confirm } : {}),
246
+ };
247
+ }
248
+ /** The account fields a renderer may show; see `MenuAccount`. */
249
+ export function projectAccount(account) {
250
+ return {
251
+ id: account.id,
252
+ ...(account.label !== undefined ? { label: account.label } : {}),
253
+ enabled: account.enabled,
254
+ type: account.type,
255
+ ...(account.identity !== undefined ? { identity: account.identity } : {}),
256
+ };
257
+ }
258
+ function projectItem(item) {
259
+ return {
260
+ id: item.id,
261
+ label: item.label,
262
+ ...(item.detail !== undefined ? { detail: item.detail } : {}),
263
+ ...(item.group !== undefined ? { group: String(item.group) } : {}),
264
+ ...(item.status !== undefined ? { status: String(item.status) } : {}),
265
+ ...(item.account ? { account: projectAccount(item.account) } : {}),
266
+ ...(item.facts !== undefined ? { facts: item.facts } : {}),
267
+ actions: (item.actions ?? []).map(projectAction),
268
+ };
269
+ }
270
+ function projectSection(section) {
271
+ const { content } = section;
272
+ return {
273
+ id: section.id,
274
+ slot: section.slot,
275
+ title: section.title,
276
+ lines: (content.lines ?? []).map(String),
277
+ items: (content.items ?? []).map(projectItem),
278
+ actions: (content.actions ?? []).map(projectAction),
279
+ ...(content.facts !== undefined ? { facts: content.facts } : {}),
280
+ };
281
+ }
282
+ function projectMenu(command, title, sections) {
283
+ return { command, title, sections: sections.map(projectSection) };
284
+ }
285
+ /** The payload a host's TUI receives when the slash command opens. */
286
+ export function dialogPayload(command, title, sections, seam) {
287
+ return sealed({ command, menu: projectMenu(command, title, sections) }, command, seam);
288
+ }
289
+ /** An apply's result: the message and the refreshed menu. */
290
+ export function applyResult(command, title, sections, outcome, seam) {
291
+ return sealed({
292
+ command,
293
+ ok: outcome.ok,
294
+ text: String(outcome.text),
295
+ ...(!outcome.ok && outcome.code !== undefined
296
+ ? { code: CODE_SHAPE.test(outcome.code) ? outcome.code : 'refused' }
297
+ : {}),
298
+ ...(outcome.needsConfirmation ? { needsConfirmation: true } : {}),
299
+ menu: projectMenu(command, title, sections),
300
+ }, command, seam);
301
+ }