cli-jaw 2.2.3 → 2.2.4-preview.20260703203439

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 (216) hide show
  1. package/README.ja.md +1 -4
  2. package/README.ko.md +1 -4
  3. package/README.md +4 -7
  4. package/README.zh-CN.md +1 -4
  5. package/dist/bin/commands/bgtask.js +3 -1
  6. package/dist/bin/commands/bgtask.js.map +1 -1
  7. package/dist/bin/commands/chat.js +2 -2
  8. package/dist/bin/commands/chat.js.map +1 -1
  9. package/dist/bin/commands/dispatch.js +10 -3
  10. package/dist/bin/commands/dispatch.js.map +1 -1
  11. package/dist/bin/commands/tui/fullscreen-mode.js +44 -11
  12. package/dist/bin/commands/tui/fullscreen-mode.js.map +1 -1
  13. package/dist/bin/commands/tui/ws-handler.js +15 -1
  14. package/dist/bin/commands/tui/ws-handler.js.map +1 -1
  15. package/dist/scripts/fresh-install-smoke.js +1 -1
  16. package/dist/scripts/fresh-install-smoke.js.map +1 -1
  17. package/dist/server.js +1 -1
  18. package/dist/server.js.map +1 -1
  19. package/dist/src/agent/agy-bootstrap.js +104 -17
  20. package/dist/src/agent/agy-bootstrap.js.map +1 -1
  21. package/dist/src/agent/agy-runtime.js +104 -0
  22. package/dist/src/agent/agy-runtime.js.map +1 -1
  23. package/dist/src/agent/agy-transcript-watcher.js +14 -0
  24. package/dist/src/agent/agy-transcript-watcher.js.map +1 -1
  25. package/dist/src/agent/args.js +16 -83
  26. package/dist/src/agent/args.js.map +1 -1
  27. package/dist/src/agent/error-classifier.js +1 -3
  28. package/dist/src/agent/error-classifier.js.map +1 -1
  29. package/dist/src/agent/events/claude.js +60 -3
  30. package/dist/src/agent/events/claude.js.map +1 -1
  31. package/dist/src/agent/events/helpers.js +1 -1
  32. package/dist/src/agent/events/helpers.js.map +1 -1
  33. package/dist/src/agent/events/index.js +27 -27
  34. package/dist/src/agent/events/index.js.map +1 -1
  35. package/dist/src/agent/events/summary.js +0 -21
  36. package/dist/src/agent/events/summary.js.map +1 -1
  37. package/dist/src/agent/events/tool-labels.js +0 -28
  38. package/dist/src/agent/events/tool-labels.js.map +1 -1
  39. package/dist/src/agent/jwc-event-mapper.js +3 -3
  40. package/dist/src/agent/jwc-event-mapper.js.map +1 -1
  41. package/dist/src/agent/jwc-runtime.js +5 -1
  42. package/dist/src/agent/jwc-runtime.js.map +1 -1
  43. package/dist/src/agent/kiro-runtime.js +40 -14
  44. package/dist/src/agent/kiro-runtime.js.map +1 -1
  45. package/dist/src/agent/lifecycle-handler.js +2 -77
  46. package/dist/src/agent/lifecycle-handler.js.map +1 -1
  47. package/dist/src/agent/prompt-context.js +38 -0
  48. package/dist/src/agent/prompt-context.js.map +1 -0
  49. package/dist/src/agent/resume-classifier.js +0 -4
  50. package/dist/src/agent/resume-classifier.js.map +1 -1
  51. package/dist/src/agent/spawn/resume.js +0 -18
  52. package/dist/src/agent/spawn/resume.js.map +1 -1
  53. package/dist/src/agent/spawn-env.js +0 -28
  54. package/dist/src/agent/spawn-env.js.map +1 -1
  55. package/dist/src/agent/spawn.js +81 -76
  56. package/dist/src/agent/spawn.js.map +1 -1
  57. package/dist/src/bgtask/presets.js +13 -1
  58. package/dist/src/bgtask/presets.js.map +1 -1
  59. package/dist/src/cli/employee-handler.js +10 -10
  60. package/dist/src/cli/employee-handler.js.map +1 -1
  61. package/dist/src/cli/handlers-completions.js +29 -10
  62. package/dist/src/cli/handlers-completions.js.map +1 -1
  63. package/dist/src/cli/handlers-runtime.js +3 -2
  64. package/dist/src/cli/handlers-runtime.js.map +1 -1
  65. package/dist/src/cli/opencodex-models.js +118 -0
  66. package/dist/src/cli/opencodex-models.js.map +1 -0
  67. package/dist/src/cli/readiness.js +2 -8
  68. package/dist/src/cli/readiness.js.map +1 -1
  69. package/dist/src/cli/registry-live.js +21 -1
  70. package/dist/src/cli/registry-live.js.map +1 -1
  71. package/dist/src/cli/registry.js +10 -21
  72. package/dist/src/cli/registry.js.map +1 -1
  73. package/dist/src/cli/tui/jawcode-bridge.js +15 -13
  74. package/dist/src/cli/tui/jawcode-bridge.js.map +1 -1
  75. package/dist/src/cli/tui/jawcode-render.js +26 -0
  76. package/dist/src/cli/tui/jawcode-render.js.map +1 -1
  77. package/dist/src/cli/tui/render/frame.js +158 -16
  78. package/dist/src/cli/tui/render/frame.js.map +1 -1
  79. package/dist/src/cli/tui/transcript.js +79 -3
  80. package/dist/src/cli/tui/transcript.js.map +1 -1
  81. package/dist/src/core/cli-detect.js +1 -1
  82. package/dist/src/core/cli-detect.js.map +1 -1
  83. package/dist/src/core/employees.js +12 -7
  84. package/dist/src/core/employees.js.map +1 -1
  85. package/dist/src/core/event-bus.js +13 -0
  86. package/dist/src/core/event-bus.js.map +1 -1
  87. package/dist/src/goal/heartbeat.js +8 -0
  88. package/dist/src/goal/heartbeat.js.map +1 -1
  89. package/dist/src/manager/load-timing.js +29 -0
  90. package/dist/src/manager/load-timing.js.map +1 -0
  91. package/dist/src/manager/observability.js.map +1 -1
  92. package/dist/src/manager/server.js +67 -6
  93. package/dist/src/manager/server.js.map +1 -1
  94. package/dist/src/memory/bootstrap.js +43 -1
  95. package/dist/src/memory/bootstrap.js.map +1 -1
  96. package/dist/src/orchestrator/distribute.js +5 -1
  97. package/dist/src/orchestrator/distribute.js.map +1 -1
  98. package/dist/src/orchestrator/state-machine.js +20 -0
  99. package/dist/src/orchestrator/state-machine.js.map +1 -1
  100. package/dist/src/orchestrator/worker-registry.js +2 -1
  101. package/dist/src/orchestrator/worker-registry.js.map +1 -1
  102. package/dist/src/prompt/templates/a1-system.md +61 -11
  103. package/dist/src/prompt/templates/employee.md +13 -0
  104. package/dist/src/prompt/templates/orchestration.md +14 -0
  105. package/dist/src/prompt/templates/worker-context.md +4 -4
  106. package/dist/src/routes/employees.js +8 -8
  107. package/dist/src/routes/employees.js.map +1 -1
  108. package/dist/src/routes/events.js +57 -19
  109. package/dist/src/routes/events.js.map +1 -1
  110. package/dist/src/routes/orchestrate.js +42 -17
  111. package/dist/src/routes/orchestrate.js.map +1 -1
  112. package/dist/src/routes/quota-agy-reverse.js +0 -24
  113. package/dist/src/routes/quota-agy-reverse.js.map +1 -1
  114. package/dist/src/routes/quota.js +0 -145
  115. package/dist/src/routes/quota.js.map +1 -1
  116. package/dist/src/routes/settings.js +2 -7
  117. package/dist/src/routes/settings.js.map +1 -1
  118. package/dist/src/shared/tool-log-sanitize.js +6 -0
  119. package/dist/src/shared/tool-log-sanitize.js.map +1 -1
  120. package/dist/src/telegram/forwarder.js +53 -5
  121. package/dist/src/telegram/forwarder.js.map +1 -1
  122. package/dist/src/trace/store.js +82 -0
  123. package/dist/src/trace/store.js.map +1 -1
  124. package/dist/src/types/cli-engine.js +0 -1
  125. package/dist/src/types/cli-engine.js.map +1 -1
  126. package/dist/src/types/cli-events.js +1 -1
  127. package/dist/src/types/cli-events.js.map +1 -1
  128. package/package.json +2 -2
  129. package/public/dist/assets/Agent-CHCXjXSN.js +1 -0
  130. package/public/dist/assets/CodeCanvas-BzhNLZVF.js +3 -0
  131. package/public/dist/assets/DocPanel-6Z_RELzd.js +1 -0
  132. package/public/dist/assets/{DocPanel-D3FYBhMp.css → DocPanel-DZKPTOm8.css} +1 -1
  133. package/public/dist/assets/FolderPanel-DdlzWAuK.js +3 -0
  134. package/public/dist/assets/{Heartbeat-D-Rfp094.js → Heartbeat-BblY8Z4a.js} +1 -1
  135. package/public/dist/assets/MarkdownRenderer-BivJ4hJm.js +1 -0
  136. package/public/dist/assets/MarkdownRenderer-Cl0oEICj.js +15 -0
  137. package/public/dist/assets/{Memory-VH4ZJCMW.js → Memory-BWcfxzCz.js} +1 -1
  138. package/public/dist/assets/ModelProvider-D4LBX7K2.js +1 -0
  139. package/public/dist/assets/agent-meta-FyI15KAa.js +1 -0
  140. package/public/dist/assets/{app-DaORcAyD.js → app-DszWzakT.js} +4 -4
  141. package/public/dist/assets/bgtask-badge-DZEQ5fMl.js +1 -0
  142. package/public/dist/assets/{bgtask-badge-BtUXEe1T.js → bgtask-badge-b7pj_Dbh.js} +1 -1
  143. package/public/dist/assets/constants-EMUBd5RQ.js +1 -0
  144. package/public/dist/assets/{employees-CZSyvJbx.js → employees-DbgFV33i.js} +1 -1
  145. package/public/dist/assets/{manager-DB5qTw1A.js → manager-CdNOlCyS.js} +4 -4
  146. package/public/dist/assets/{manager-D3waO_XX.css → manager-rHNwUB4e.css} +1 -1
  147. package/public/dist/assets/memory-BT-rs3ag.js +1 -0
  148. package/public/dist/assets/{memory-cWI_Htbn.js → memory-QobGT0Kv.js} +1 -1
  149. package/public/dist/assets/message-history-BY1UNJAO.js +1 -0
  150. package/public/dist/assets/message-history-BmP5JKio.js +142 -0
  151. package/public/dist/assets/{render-Bp8eyqCf.js → render-C3r-9_-J.js} +2 -2
  152. package/public/dist/assets/settings-CJm8ZSJs.js +1 -0
  153. package/public/dist/assets/{settings-DLkP7qRV.js → settings-D70uFh8l.js} +1 -1
  154. package/public/dist/assets/{settings-core-B5XRRNcX.js → settings-core-B2lw2bgO.js} +1 -1
  155. package/public/dist/assets/settings-core-gdS0lo1b.js +1 -0
  156. package/public/dist/assets/{sidebar-CsogFOse.js → sidebar-BqWm2XWP.js} +3 -3
  157. package/public/dist/assets/{skills-Dmf4v9rj.js → skills-CdNOfXlk.js} +1 -1
  158. package/public/dist/assets/skills-DG_CbTEf.js +1 -0
  159. package/public/dist/assets/{slash-commands-vcf7FuPD.js → slash-commands-4Ntm5N7h.js} +1 -1
  160. package/public/dist/assets/slash-commands-B9kOEhJ_.js +1 -0
  161. package/public/dist/assets/{trace-drawer-DuQQ0SNq.js → trace-drawer-DqAwwHHQ.js} +1 -1
  162. package/public/dist/assets/ui-Anw2S64o.js +1 -0
  163. package/public/dist/assets/ui-DsK6r0Xv.js +2 -0
  164. package/public/dist/index.html +1 -1
  165. package/public/dist/manager/index.html +2 -2
  166. package/public/js/constants.ts +7 -7
  167. package/public/js/features/employees.ts +0 -3
  168. package/public/js/features/process-block-dom.ts +6 -1
  169. package/public/js/features/process-block.ts +59 -3
  170. package/public/js/render/file-links.ts +1 -1
  171. package/public/js/ui.ts +9 -1
  172. package/public/js/virtual-scroll.ts +23 -0
  173. package/public/js/ws.ts +7 -2
  174. package/public/manager/src/SidebarRailRouter.tsx +15 -10
  175. package/public/manager/src/code/CodeCanvas.tsx +3 -1
  176. package/public/manager/src/code/CodeTranscript.tsx +5 -4
  177. package/public/manager/src/code/CodeWorkbench.tsx +2 -1
  178. package/public/manager/src/doc-panel/DocPanel.tsx +52 -5
  179. package/public/manager/src/doc-panel/doc-panel.css +10 -0
  180. package/public/manager/src/folder-panel/FolderPanel.tsx +14 -16
  181. package/public/manager/src/folder-panel/use-folder-git-status.ts +15 -0
  182. package/public/manager/src/folder-panel/use-folder-preview-sync.ts +37 -0
  183. package/public/manager/src/folder-panel/use-folder-visible-refresh.ts +19 -6
  184. package/public/manager/src/manager-notes.css +23 -0
  185. package/public/manager/src/notes/rendering/MarkdownRenderer.tsx +80 -2
  186. package/public/manager/src/settings/pages/Agent.tsx +30 -8
  187. package/public/manager/src/settings/pages/ModelProvider.tsx +22 -4
  188. package/public/manager/src/settings/pages/components/agent/AgentEmployeesSection.tsx +5 -1
  189. package/public/manager/src/settings/pages/components/agent/FlushAgentSection.tsx +5 -3
  190. package/public/manager/src/settings/pages/components/agent/RuntimeEmployeeRow.tsx +6 -4
  191. package/public/manager/src/settings/pages/components/agent/RuntimeHeader.tsx +4 -2
  192. package/public/manager/src/settings/pages/components/agent/agent-meta.ts +45 -9
  193. package/public/manager/src/settings/pages/components/agent/runtime-employees-helpers.ts +7 -2
  194. package/scripts/capture-agy-quota-fixture.mjs +138 -0
  195. package/scripts/fresh-install-smoke.ts +1 -1
  196. package/dist/src/agent/events/gemini.js +0 -100
  197. package/dist/src/agent/events/gemini.js.map +0 -1
  198. package/public/dist/assets/Agent-Ci12HWhE.js +0 -1
  199. package/public/dist/assets/CodeCanvas-d1gh0-lY.js +0 -3
  200. package/public/dist/assets/DocPanel-C6XQ7W6A.js +0 -1
  201. package/public/dist/assets/FolderPanel-DIFAqajZ.js +0 -3
  202. package/public/dist/assets/MarkdownRenderer-DXKUEE2a.js +0 -1
  203. package/public/dist/assets/MarkdownRenderer-DcIxpNcX.js +0 -15
  204. package/public/dist/assets/ModelProvider-_tUCghOF.js +0 -1
  205. package/public/dist/assets/agent-meta-DqBTGRRQ.js +0 -1
  206. package/public/dist/assets/bgtask-badge-B3HLOZae.js +0 -1
  207. package/public/dist/assets/constants-DkJ3E63Y.js +0 -1
  208. package/public/dist/assets/memory-BEruUlfu.js +0 -1
  209. package/public/dist/assets/message-history-DU1V9ZAW.js +0 -142
  210. package/public/dist/assets/message-history-tjkyOp_K.js +0 -1
  211. package/public/dist/assets/settings-B-GgyJZI.js +0 -1
  212. package/public/dist/assets/settings-core-Cw1av-Ox.js +0 -1
  213. package/public/dist/assets/skills-CLcoop6W.js +0 -1
  214. package/public/dist/assets/slash-commands-DY6-hzq6.js +0 -1
  215. package/public/dist/assets/ui-BKYuBdZE.js +0 -2
  216. package/public/dist/assets/ui-CqlGwgUo.js +0 -1
@@ -13,10 +13,12 @@ import { FlushAgentSection } from './components/agent/FlushAgentSection';
13
13
  import { AgentEmployeesSection } from './components/agent/AgentEmployeesSection';
14
14
  import {
15
15
  metaFor,
16
+ normalizeCliMetaRegistry,
16
17
  optionList,
17
18
  runtimeEffortFor,
18
19
  runtimeModelFor,
19
20
  type ActiveOverride,
21
+ type CliMeta,
20
22
  type PerCliEntry,
21
23
  } from './components/agent/agent-meta';
22
24
  import {
@@ -75,6 +77,19 @@ export default function Agent({ port, client, dirty, registerSave }: SettingsPag
75
77
  const [employeeDraft, setEmployeeDraft] = useState<RuntimeEmployeeRecord[]>([]);
76
78
  const [employeeLoading, setEmployeeLoading] = useState(true);
77
79
  const [employeeError, setEmployeeError] = useState<string | null>(null);
80
+ const [cliMeta, setCliMeta] = useState<Record<string, CliMeta> | null>(null);
81
+
82
+ const loadCliMeta = useCallback(async () => {
83
+ try {
84
+ const response = await client.get<{ data?: unknown } | Record<string, unknown>>('/api/cli-registry');
85
+ const data = response && typeof response === 'object' && 'data' in response
86
+ ? (response as { data?: unknown }).data
87
+ : response;
88
+ setCliMeta(normalizeCliMetaRegistry(data));
89
+ } catch {
90
+ setCliMeta(null);
91
+ }
92
+ }, [client]);
78
93
 
79
94
  const loadFlush = useCallback(async () => {
80
95
  setFlushLoading(true);
@@ -107,24 +122,26 @@ export default function Agent({ port, client, dirty, registerSave }: SettingsPag
107
122
  }, [client]);
108
123
 
109
124
  useEffect(() => {
125
+ void loadCliMeta();
110
126
  void loadFlush();
111
127
  void loadEmployees();
112
- }, [loadEmployees, loadFlush]);
128
+ }, [loadCliMeta, loadEmployees, loadFlush]);
113
129
 
114
130
  useEffect(() => {
115
131
  if (state.kind !== 'ready') return;
116
132
  const cliKeys = Object.keys(state.data.perCli || {});
117
133
  const cli = state.data.cli || cliKeys[0] || '';
118
134
  const permissions = parsePermissionsValue(state.data.permissions);
135
+ const meta = metaFor(cli, cliMeta);
119
136
  setDraft({
120
137
  cli,
121
- provider: state.data.perCli?.[cli]?.provider || metaFor(cli).defaultProvider || '',
138
+ provider: state.data.perCli?.[cli]?.provider || meta.defaultProvider || '',
122
139
  model: runtimeModelFor(cli, state.data.perCli, state.data.activeOverrides),
123
140
  effort: runtimeEffortFor(cli, state.data.perCli, state.data.activeOverrides),
124
141
  workingDir: state.data.workingDir || '',
125
142
  permissions: permissions.mode === 'custom' ? permissions.tokens : 'auto',
126
143
  });
127
- }, [state]);
144
+ }, [cliMeta, state]);
128
145
 
129
146
  useEffect(() => {
130
147
  return () => {
@@ -153,9 +170,10 @@ export default function Agent({ port, client, dirty, registerSave }: SettingsPag
153
170
  dirty.clear();
154
171
  if (freshSettings) setData(freshSettings as AgentSnapshot);
155
172
  await refresh();
173
+ await loadCliMeta();
156
174
  await loadFlush();
157
175
  await loadEmployees();
158
- }, [client, dirty, employeeDraft, employeeOriginal, loadEmployees, loadFlush, refresh, setData]);
176
+ }, [client, dirty, employeeDraft, employeeOriginal, loadCliMeta, loadEmployees, loadFlush, refresh, setData]);
159
177
 
160
178
  useEffect(() => {
161
179
  if (!registerSave) return;
@@ -167,7 +185,7 @@ export default function Agent({ port, client, dirty, registerSave }: SettingsPag
167
185
  const perCli = settingsData.perCli || {};
168
186
  const activeOverrides = settingsData.activeOverrides || {};
169
187
  const cliOptions = useMemo(() => Object.keys(perCli), [perCli]);
170
- const activeMeta = metaFor(draft.cli);
188
+ const activeMeta = metaFor(draft.cli, cliMeta);
171
189
  const activeProvider = draft.provider || activeMeta.defaultProvider || activeMeta.providers?.[0] || '';
172
190
  const isPiRuntime = draft.cli === 'pi';
173
191
  const hasProviders = !isPiRuntime && (activeMeta.providers?.length ?? 0) > 0;
@@ -212,11 +230,13 @@ export default function Agent({ port, client, dirty, registerSave }: SettingsPag
212
230
  effortOptions={activeEffortOptions}
213
231
  workingDir={draft.workingDir}
214
232
  workingDirError={workingDirError}
233
+ cliMeta={cliMeta}
215
234
  onCliChange={(next) => {
235
+ const nextMeta = metaFor(next, cliMeta);
216
236
  const nextDraft = {
217
237
  ...draft,
218
238
  cli: next,
219
- provider: perCli[next]?.provider || metaFor(next).defaultProvider || '',
239
+ provider: perCli[next]?.provider || nextMeta.defaultProvider || '',
220
240
  model: runtimeModelFor(next, perCli, activeOverrides),
221
241
  effort: runtimeEffortFor(next, perCli, activeOverrides),
222
242
  };
@@ -287,11 +307,12 @@ export default function Agent({ port, client, dirty, registerSave }: SettingsPag
287
307
  flushCli={flushDraft.cli || ''}
288
308
  flushModel={flushDraft.model || ''}
289
309
  cliOptions={cliOptions}
290
- modelOptions={optionList(metaFor(flushDraft.cli || draft.cli).models, flushDraft.model || '')}
310
+ cliMeta={cliMeta}
311
+ modelOptions={optionList(metaFor(flushDraft.cli || draft.cli, cliMeta).models, flushDraft.model || '')}
291
312
  loading={flushLoading}
292
313
  error={flushError}
293
314
  onFlushCliChange={(next) => {
294
- const model = next ? metaFor(next).models[0] || '' : '';
315
+ const model = next ? metaFor(next, cliMeta).models[0] || '' : '';
295
316
  setFlushDraft({ cli: next, model });
296
317
  setEntry('flushCli', { value: next, original: flushOriginal.cli || '', valid: true });
297
318
  setEntry('flushModel', { value: model, original: flushOriginal.model || '', valid: true });
@@ -305,6 +326,7 @@ export default function Agent({ port, client, dirty, registerSave }: SettingsPag
305
326
  roster={employeeDraft}
306
327
  original={employeeOriginal}
307
328
  cliOptions={cliOptions}
329
+ cliMeta={cliMeta}
308
330
  loading={employeeLoading}
309
331
  error={employeeError}
310
332
  onRosterChange={(next) => {
@@ -12,8 +12,8 @@ import {
12
12
  usePageSnapshot,
13
13
  } from './page-shell';
14
14
  import { PerCliRow } from './components/PerCliRow';
15
- import { metaFor } from './components/agent/agent-meta';
16
- import type { PerCliEntry } from './components/agent/agent-meta';
15
+ import { metaFor, normalizeCliMetaRegistry } from './components/agent/agent-meta';
16
+ import type { CliMeta, PerCliEntry } from './components/agent/agent-meta';
17
17
  import type { PiSettingsView } from './components/pi-profile';
18
18
  import { expandPatch } from './path-utils';
19
19
 
@@ -58,6 +58,23 @@ export default function ModelProvider({ port, client, dirty, registerSave }: Set
58
58
  const [codexCtx, setCodexCtx] = useState<{ contextWindowSize?: number; contextWindowCompactLimit?: number }>({});
59
59
  const [resetting, setResetting] = useState(false);
60
60
  const [resetError, setResetError] = useState<string | null>(null);
61
+ const [cliMeta, setCliMeta] = useState<Record<string, CliMeta> | null>(null);
62
+
63
+ const loadCliMeta = useCallback(async () => {
64
+ try {
65
+ const response = await client.get<{ data?: unknown } | Record<string, unknown>>('/api/cli-registry');
66
+ const data = response && typeof response === 'object' && 'data' in response
67
+ ? (response as { data?: unknown }).data
68
+ : response;
69
+ setCliMeta(normalizeCliMetaRegistry(data));
70
+ } catch {
71
+ setCliMeta(null);
72
+ }
73
+ }, [client]);
74
+
75
+ useEffect(() => {
76
+ void loadCliMeta();
77
+ }, [loadCliMeta]);
61
78
 
62
79
  useEffect(() => {
63
80
  if (state.kind !== 'ready') return;
@@ -101,7 +118,8 @@ export default function ModelProvider({ port, client, dirty, registerSave }: Set
101
118
  setPerCliDraft({ ...(fresh.perCli || {}) });
102
119
  setFallback([...(fresh.fallbackOrder || [])]);
103
120
  await refresh();
104
- }, [client, dirty, refresh, setData]);
121
+ await loadCliMeta();
122
+ }, [client, dirty, loadCliMeta, refresh, setData]);
105
123
 
106
124
  useEffect(() => {
107
125
  if (!registerSave) return;
@@ -159,7 +177,7 @@ export default function ModelProvider({ port, client, dirty, registerSave }: Set
159
177
  <PerCliRow
160
178
  key={cli}
161
179
  cli={cli}
162
- meta={metaFor(cli)}
180
+ meta={metaFor(cli, cliMeta)}
163
181
  original={perCliOriginal[cli] || {}}
164
182
  value={perCliDraft[cli] || perCliOriginal[cli] || {}}
165
183
  setValue={(next) => setPerCliDraft({ ...perCliDraft, [cli]: next })}
@@ -1,5 +1,6 @@
1
1
  import { SettingsSection } from '../../page-shell';
2
2
  import { RuntimeEmployeeRow } from './RuntimeEmployeeRow';
3
+ import type { CliMeta } from './agent-meta';
3
4
  import {
4
5
  makeDefaultRuntimeEmployee,
5
6
  runtimeEmployeeChangeSummary,
@@ -11,6 +12,7 @@ type AgentEmployeesSectionProps = {
11
12
  roster: RuntimeEmployeeRecord[];
12
13
  original: RuntimeEmployeeRecord[];
13
14
  cliOptions: ReadonlyArray<string>;
15
+ cliMeta?: Record<string, CliMeta> | null;
14
16
  loading?: boolean;
15
17
  error?: string | null;
16
18
  onRosterChange(next: RuntimeEmployeeRecord[]): void;
@@ -20,6 +22,7 @@ export function AgentEmployeesSection({
20
22
  roster,
21
23
  original,
22
24
  cliOptions,
25
+ cliMeta,
23
26
  loading,
24
27
  error,
25
28
  onRosterChange,
@@ -58,6 +61,7 @@ export function AgentEmployeesSection({
58
61
  employee={employee}
59
62
  index={idx}
60
63
  cliOptions={cliOptions}
64
+ cliMeta={cliMeta ?? null}
61
65
  onChange={(patch) => updateRow(idx, patch)}
62
66
  onRemove={() => removeRow(idx)}
63
67
  />
@@ -68,7 +72,7 @@ export function AgentEmployeesSection({
68
72
  <button
69
73
  type="button"
70
74
  className="settings-action settings-action-discard"
71
- onClick={() => onRosterChange([...roster, makeDefaultRuntimeEmployee(cliOptions)])}
75
+ onClick={() => onRosterChange([...roster, makeDefaultRuntimeEmployee(cliOptions, cliMeta)])}
72
76
  >
73
77
  + Add employee
74
78
  </button>
@@ -1,6 +1,6 @@
1
1
  import { SelectField } from '../../../fields';
2
2
  import { SettingsSection } from '../../page-shell';
3
- import { metaFor } from './agent-meta';
3
+ import { metaFor, type CliMeta } from './agent-meta';
4
4
 
5
5
  type FlushAgentSectionProps = {
6
6
  activeCli: string;
@@ -8,6 +8,7 @@ type FlushAgentSectionProps = {
8
8
  flushModel: string;
9
9
  cliOptions: ReadonlyArray<string>;
10
10
  modelOptions: ReadonlyArray<{ value: string; label: string }>;
11
+ cliMeta?: Record<string, CliMeta> | null;
11
12
  loading?: boolean;
12
13
  error?: string | null;
13
14
  onFlushCliChange(next: string): void;
@@ -20,13 +21,14 @@ export function FlushAgentSection({
20
21
  flushModel,
21
22
  cliOptions,
22
23
  modelOptions,
24
+ cliMeta,
23
25
  loading,
24
26
  error,
25
27
  onFlushCliChange,
26
28
  onFlushModelChange,
27
29
  }: FlushAgentSectionProps) {
28
30
  const effectiveCli = flushCli || activeCli;
29
- const effectiveCliLabel = effectiveCli ? metaFor(effectiveCli).label || effectiveCli : 'active';
31
+ const effectiveCliLabel = effectiveCli ? metaFor(effectiveCli, cliMeta).label || effectiveCli : 'active';
30
32
  return (
31
33
  <SettingsSection
32
34
  title="Flush Agent"
@@ -46,7 +48,7 @@ export function FlushAgentSection({
46
48
  value={flushCli}
47
49
  options={[
48
50
  { value: '', label: '(active CLI)' },
49
- ...cliOptions.map((value) => ({ value, label: metaFor(value).label || value })),
51
+ ...cliOptions.map((value) => ({ value, label: metaFor(value, cliMeta).label || value })),
50
52
  ]}
51
53
  onChange={onFlushCliChange}
52
54
  />
@@ -1,5 +1,5 @@
1
1
  import { SelectField, TextField } from '../../../fields';
2
- import { metaFor, optionList } from './agent-meta';
2
+ import { metaFor, optionList, type CliMeta } from './agent-meta';
3
3
  import {
4
4
  isStaticEmployee,
5
5
  runtimeEmployeeError,
@@ -10,6 +10,7 @@ type RuntimeEmployeeRowProps = {
10
10
  employee: RuntimeEmployeeRecord;
11
11
  index: number;
12
12
  cliOptions: ReadonlyArray<string>;
13
+ cliMeta?: Record<string, CliMeta> | null;
13
14
  onChange(patch: Partial<RuntimeEmployeeRecord>): void;
14
15
  onRemove(): void;
15
16
  };
@@ -18,11 +19,12 @@ export function RuntimeEmployeeRow({
18
19
  employee,
19
20
  index,
20
21
  cliOptions,
22
+ cliMeta,
21
23
  onChange,
22
24
  onRemove,
23
25
  }: RuntimeEmployeeRowProps) {
24
26
  const locked = isStaticEmployee(employee);
25
- const meta = metaFor(employee.cli);
27
+ const meta = metaFor(employee.cli, cliMeta);
26
28
  const modelOptions = optionList(meta.models, employee.model);
27
29
  const error = runtimeEmployeeError(employee);
28
30
  const cliChoices = Array.from(new Set([...cliOptions, employee.cli, 'claude'])).filter(Boolean);
@@ -47,9 +49,9 @@ export function RuntimeEmployeeRow({
47
49
  label="CLI"
48
50
  value={employee.cli}
49
51
  disabled={locked}
50
- options={cliChoices.map((value) => ({ value, label: metaFor(value).label || value }))}
52
+ options={cliChoices.map((value) => ({ value, label: metaFor(value, cliMeta).label || value }))}
51
53
  onChange={(next) => {
52
- const nextModel = metaFor(next).models[0] || 'default';
54
+ const nextModel = metaFor(next, cliMeta).models[0] || 'default';
53
55
  onChange({ cli: next, model: nextModel });
54
56
  }}
55
57
  />
@@ -1,6 +1,6 @@
1
1
  import { SelectField, TextField } from '../../../fields';
2
2
  import { SettingsSection } from '../../page-shell';
3
- import { metaFor, orderRuntimeCliOptions, PRIMARY_CLIS } from './agent-meta';
3
+ import { metaFor, orderRuntimeCliOptions, PRIMARY_CLIS, type CliMeta } from './agent-meta';
4
4
 
5
5
  type RuntimeHeaderProps = {
6
6
  cli: string;
@@ -13,6 +13,7 @@ type RuntimeHeaderProps = {
13
13
  effortOptions: ReadonlyArray<string>;
14
14
  workingDir: string;
15
15
  workingDirError: string | null;
16
+ cliMeta?: Record<string, CliMeta> | null;
16
17
  onCliChange(next: string): void;
17
18
  onProviderChange?(next: string): void;
18
19
  onModelChange(next: string): void;
@@ -31,6 +32,7 @@ export function RuntimeHeader({
31
32
  effortOptions,
32
33
  workingDir,
33
34
  workingDirError,
35
+ cliMeta,
34
36
  onCliChange,
35
37
  onProviderChange,
36
38
  onModelChange,
@@ -50,7 +52,7 @@ export function RuntimeHeader({
50
52
  id="agent-cli"
51
53
  label="Active CLI"
52
54
  value={cli}
53
- options={orderedCliOptions.map((value) => ({ value, label: metaFor(value).label || value }))}
55
+ options={orderedCliOptions.map((value) => ({ value, label: metaFor(value, cliMeta).label || value }))}
54
56
  collapsedAfter={orderedPrimaryCliCount}
55
57
  onChange={onCliChange}
56
58
  />
@@ -26,6 +26,8 @@ export type ActiveOverride = {
26
26
  effort?: string;
27
27
  };
28
28
 
29
+ const CODEX_MODELS: ReadonlyArray<string> = ['gpt-5.5', 'gpt-5.4', 'gpt-5.4-mini', 'gpt-5.3-codex-spark'];
30
+
29
31
  export const PRIMARY_CLIS: ReadonlyArray<string> = ['pi', 'claude', 'claude-e', 'jwc', 'agy', 'codex', 'cursor', 'kiro-code', 'gemini'];
30
32
 
31
33
  export const CLI_META: Record<string, CliMeta> = {
@@ -48,11 +50,11 @@ export const CLI_META: Record<string, CliMeta> = {
48
50
  label: 'AI-E',
49
51
  defaultProvider: 'claude',
50
52
  providers: ['claude', 'codex', 'gemini', 'grok', 'copilot', 'kiro'],
51
- models: ['opus', 'sonnet', 'haiku', 'gpt-5.5', 'gpt-5.4', 'gpt-5.4-mini', 'gemini-3-flash-preview', 'grok-build', 'grok-composer-2.5-fast', 'gpt-5-mini'],
53
+ models: ['opus', 'sonnet', 'haiku', ...CODEX_MODELS, 'gemini-3-flash-preview', 'grok-build', 'grok-composer-2.5-fast', 'gpt-5-mini'],
52
54
  efforts: ['low', 'medium', 'high', 'xhigh', 'max'],
53
55
  modelsByProvider: {
54
56
  claude: ['claude-fable-5', 'claude-opus-4-8', 'opus', 'sonnet', 'haiku'],
55
- codex: ['gpt-5.5', 'gpt-5.4', 'gpt-5.4-mini'],
57
+ codex: CODEX_MODELS,
56
58
  gemini: ['gemini-3-flash-preview'],
57
59
  grok: ['grok-build', 'grok-composer-2.5-fast'],
58
60
  copilot: ['gpt-5-mini'],
@@ -64,7 +66,7 @@ export const CLI_META: Record<string, CliMeta> = {
64
66
  gemini: [],
65
67
  grok: [],
66
68
  copilot: ['low', 'medium', 'high'],
67
- kiro: [],
69
+ kiro: ['low', 'medium', 'high', 'xhigh'],
68
70
  },
69
71
  },
70
72
  claude: {
@@ -126,12 +128,12 @@ export const CLI_META: Record<string, CliMeta> = {
126
128
  },
127
129
  codex: {
128
130
  label: 'Codex',
129
- models: ['gpt-5.5', 'gpt-5.4', 'gpt-5.4-mini', 'gpt-5.3-codex'],
131
+ models: CODEX_MODELS,
130
132
  efforts: ['low', 'medium', 'high', 'xhigh'],
131
133
  },
132
134
  'codex-app': {
133
135
  label: 'Codex App',
134
- models: ['gpt-5.5', 'gpt-5.4', 'gpt-5.4-mini', 'gpt-5.3-codex'],
136
+ models: CODEX_MODELS,
135
137
  efforts: ['low', 'medium', 'high', 'xhigh'],
136
138
  },
137
139
  cursor: {
@@ -171,8 +173,8 @@ export const CLI_META: Record<string, CliMeta> = {
171
173
  'glm-5',
172
174
  'qwen3-coder-next',
173
175
  ],
174
- efforts: [],
175
- effortNote: 'Kiro CLI has no separate effort flag',
176
+ efforts: ['low', 'medium', 'high', 'xhigh'],
177
+ effortNote: 'Kiro CLI forwards --effort; cli-jaw maps xhigh to Kiro max on the wire',
176
178
  },
177
179
  gemini: {
178
180
  label: 'Gemini',
@@ -197,8 +199,42 @@ export const CLI_META: Record<string, CliMeta> = {
197
199
  },
198
200
  };
199
201
 
200
- export function metaFor(cli: string): CliMeta {
201
- return CLI_META[cli] || { label: cli, models: [], efforts: [] };
202
+ function stringArray(value: unknown): string[] {
203
+ return Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === 'string') : [];
204
+ }
205
+
206
+ function stringArrayRecord(value: unknown): Record<string, string[]> | undefined {
207
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined;
208
+ const out: Record<string, string[]> = {};
209
+ for (const [key, raw] of Object.entries(value as Record<string, unknown>)) out[key] = stringArray(raw);
210
+ return out;
211
+ }
212
+
213
+ export function normalizeCliMetaRegistry(raw: unknown): Record<string, CliMeta> {
214
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return {};
215
+ const out: Record<string, CliMeta> = {};
216
+ for (const [key, value] of Object.entries(raw as Record<string, unknown>)) {
217
+ if (!value || typeof value !== 'object' || Array.isArray(value)) continue;
218
+ const record = value as Record<string, unknown>;
219
+ const modelsByProvider = stringArrayRecord(record['modelsByProvider']);
220
+ const effortsByProvider = stringArrayRecord(record['effortsByProvider']);
221
+ out[key] = {
222
+ label: typeof record['label'] === 'string' ? record['label'] : key,
223
+ models: stringArray(record['models']),
224
+ efforts: stringArray(record['efforts']),
225
+ ...(typeof record['defaultProvider'] === 'string' ? { defaultProvider: record['defaultProvider'] } : {}),
226
+ ...(record['providers'] ? { providers: stringArray(record['providers']) } : {}),
227
+ ...(modelsByProvider ? { modelsByProvider } : {}),
228
+ ...(effortsByProvider ? { effortsByProvider } : {}),
229
+ ...(typeof record['effortNote'] === 'string' ? { effortNote: record['effortNote'] } : {}),
230
+ ...(typeof record['modelNote'] === 'string' ? { modelNote: record['modelNote'] } : {}),
231
+ };
232
+ }
233
+ return out;
234
+ }
235
+
236
+ export function metaFor(cli: string, registry?: Record<string, CliMeta> | null): CliMeta {
237
+ return registry?.[cli] || CLI_META[cli] || { label: cli, models: [], efforts: [] };
202
238
  }
203
239
 
204
240
  export function orderRuntimeCliOptions(cliOptions: ReadonlyArray<string>): string[] {
@@ -1,4 +1,5 @@
1
1
  import type { SettingsClient } from '../../../types';
2
+ import type { CliMeta } from './agent-meta';
2
3
 
3
4
  export type RuntimeEmployeeSource = 'static' | 'db';
4
5
 
@@ -37,13 +38,17 @@ export function newRuntimeEmployeeId(): string {
37
38
  return `new:${Date.now().toString(36)}:${Math.random().toString(36).slice(2, 8)}`;
38
39
  }
39
40
 
40
- export function makeDefaultRuntimeEmployee(cliOptions: ReadonlyArray<string>): RuntimeEmployeeRecord {
41
+ export function makeDefaultRuntimeEmployee(
42
+ cliOptions: ReadonlyArray<string>,
43
+ cliMeta?: Record<string, CliMeta> | null,
44
+ ): RuntimeEmployeeRecord {
41
45
  const cli = cliOptions[0] || 'claude';
46
+ const model = cliMeta?.[cli]?.models?.[0] || 'default';
42
47
  return {
43
48
  id: newRuntimeEmployeeId(),
44
49
  name: 'New Agent',
45
50
  cli,
46
- model: 'default',
51
+ model,
47
52
  role: '',
48
53
  status: 'idle',
49
54
  source: 'db',
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env node
2
+ import { execFileSync } from 'node:child_process';
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
8
+ const FIXTURE_DIR = path.join(ROOT, 'tests', 'fixtures', 'agy-quota');
9
+ const EMAIL_PLACEHOLDER = 'redacted@example.invalid';
10
+ const REDACTED = '[REDACTED]';
11
+ const REDACT_KEYS = new Set([
12
+ 'email',
13
+ 'account',
14
+ 'accountid',
15
+ 'user',
16
+ 'id',
17
+ 'requestid',
18
+ 'request_id',
19
+ 'token',
20
+ 'accesstoken',
21
+ 'refreshtoken',
22
+ 'idtoken',
23
+ 'apikey',
24
+ 'secret',
25
+ 'password',
26
+ 'bearer',
27
+ 'cookie',
28
+ 'authorization',
29
+ ]);
30
+
31
+ function usage() {
32
+ console.log(`Usage: node scripts/capture-agy-quota-fixture.mjs [--out <path>]
33
+
34
+ Capture antigravity-usage --json, redact account identifiers, and write an AGY
35
+ quota fixture. Review the output manually before committing.
36
+
37
+ Options:
38
+ --out <path> Write to a custom JSON path.
39
+ -h, --help Show this help.
40
+ `);
41
+ }
42
+
43
+ function parseArgs(argv) {
44
+ const args = { out: '' };
45
+ for (let i = 0; i < argv.length; i += 1) {
46
+ const arg = argv[i];
47
+ if (arg === '-h' || arg === '--help') {
48
+ usage();
49
+ process.exit(0);
50
+ }
51
+ if (arg === '--out') {
52
+ const value = argv[i + 1];
53
+ if (!value) throw new Error('--out requires a path');
54
+ args.out = value;
55
+ i += 1;
56
+ continue;
57
+ }
58
+ throw new Error(`unknown argument: ${arg}`);
59
+ }
60
+ return args;
61
+ }
62
+
63
+ function runJson() {
64
+ const commands = [
65
+ ['antigravity-usage', ['--json']],
66
+ ['npx', ['--yes', 'antigravity-usage', '--json']],
67
+ ];
68
+ const errors = [];
69
+ for (const [binary, args] of commands) {
70
+ try {
71
+ return execFileSync(binary, args, {
72
+ encoding: 'utf8',
73
+ timeout: 15000,
74
+ maxBuffer: 1024 * 1024,
75
+ stdio: ['ignore', 'pipe', 'pipe'],
76
+ });
77
+ } catch (error) {
78
+ errors.push(`${binary}: ${error.message}`);
79
+ }
80
+ }
81
+ throw new Error(`failed to run antigravity-usage JSON capture:\n${errors.join('\n')}`);
82
+ }
83
+
84
+ function redactString(value, forceEmail = false) {
85
+ if (forceEmail) return EMAIL_PLACEHOLDER;
86
+ return value.replace(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi, EMAIL_PLACEHOLDER);
87
+ }
88
+
89
+ function redact(value, key = '') {
90
+ if (Array.isArray(value)) return value.map(item => redact(item));
91
+ if (value && typeof value === 'object') {
92
+ const out = {};
93
+ for (const [rawKey, rawValue] of Object.entries(value)) {
94
+ const normalized = rawKey.toLowerCase().replace(/[-_\s]/g, '');
95
+ if (REDACT_KEYS.has(normalized)) {
96
+ out[rawKey] = normalized === 'email'
97
+ ? EMAIL_PLACEHOLDER
98
+ : typeof rawValue === 'string'
99
+ ? redactString(rawValue) === rawValue ? REDACTED : EMAIL_PLACEHOLDER
100
+ : REDACTED;
101
+ continue;
102
+ }
103
+ out[rawKey] = redact(rawValue, rawKey);
104
+ }
105
+ return out;
106
+ }
107
+ if (typeof value === 'string') {
108
+ return redactString(value, key.toLowerCase() === 'email');
109
+ }
110
+ return value;
111
+ }
112
+
113
+ function defaultOutPath() {
114
+ const day = new Date().toISOString().slice(0, 10);
115
+ return path.join(FIXTURE_DIR, `live-redacted-${day}.json`);
116
+ }
117
+
118
+ function main() {
119
+ const args = parseArgs(process.argv.slice(2));
120
+ const raw = runJson().trim();
121
+ if (!raw.startsWith('{')) throw new Error('antigravity-usage output is not a JSON object');
122
+ const parsed = JSON.parse(raw);
123
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
124
+ throw new Error('antigravity-usage output must be a JSON object');
125
+ }
126
+ const redacted = redact(parsed);
127
+ const outPath = path.resolve(args.out || defaultOutPath());
128
+ fs.mkdirSync(path.dirname(outPath), { recursive: true });
129
+ fs.writeFileSync(outPath, `${JSON.stringify(redacted, null, 2)}\n`);
130
+ console.log(outPath);
131
+ }
132
+
133
+ try {
134
+ main();
135
+ } catch (error) {
136
+ console.error((error instanceof Error ? error.message : String(error)));
137
+ process.exit(1);
138
+ }
@@ -179,7 +179,7 @@ async function main(): Promise<void> {
179
179
  if (!cliRes.ok) throw new Error(`/api/cli-status HTTP ${cliRes.status}`);
180
180
  const cliJson = (await cliRes.json()) as Record<string, unknown> | null;
181
181
  const keys = Object.keys(cliJson ?? {});
182
- const required: string[] = ['ai-e', 'claude', 'claude-e', 'codex', 'codex-app', 'copilot', 'cursor', 'kiro-code', 'gemini', 'grok', 'opencode'];
182
+ const required: string[] = ['ai-e', 'claude', 'claude-e', 'codex', 'codex-app', 'copilot', 'cursor', 'kiro-code', 'grok', 'opencode'];
183
183
  for (const k of required) {
184
184
  if (!keys.includes(k)) throw new Error(`missing cli key in status: ${k}`);
185
185
  }