kiokuko-dsh 0.2.2 → 0.2.4

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 (147) hide show
  1. package/README.ja.md +4 -5
  2. package/README.md +5 -5
  3. package/dist/client.cjs +225 -159
  4. package/dist/context/continuity-view.d.ts +1 -1
  5. package/dist/dsh/coding-workflow/contracts.d.ts +120 -0
  6. package/dist/dsh/coding-workflow/contracts.d.ts.map +1 -0
  7. package/dist/dsh/coding-workflow/contracts.js +77 -0
  8. package/dist/dsh/coding-workflow/contracts.js.map +1 -0
  9. package/dist/dsh/coding-workflow/host.d.ts +41 -0
  10. package/dist/dsh/coding-workflow/host.d.ts.map +1 -0
  11. package/dist/dsh/coding-workflow/host.js +235 -0
  12. package/dist/dsh/coding-workflow/host.js.map +1 -0
  13. package/dist/dsh/coding-workflow/intent.d.ts +15 -0
  14. package/dist/dsh/coding-workflow/intent.d.ts.map +1 -0
  15. package/dist/dsh/coding-workflow/intent.js +86 -0
  16. package/dist/dsh/coding-workflow/intent.js.map +1 -0
  17. package/dist/dsh/coding-workflow/service.d.ts +155 -0
  18. package/dist/dsh/coding-workflow/service.d.ts.map +1 -0
  19. package/dist/dsh/coding-workflow/service.js +282 -0
  20. package/dist/dsh/coding-workflow/service.js.map +1 -0
  21. package/dist/dsh/coding-workflow/store.d.ts +17 -0
  22. package/dist/dsh/coding-workflow/store.d.ts.map +1 -0
  23. package/dist/dsh/coding-workflow/store.js +77 -0
  24. package/dist/dsh/coding-workflow/store.js.map +1 -0
  25. package/dist/dsh/completion-verifiers.d.ts +14 -1
  26. package/dist/dsh/completion-verifiers.d.ts.map +1 -1
  27. package/dist/dsh/completion-verifiers.js.map +1 -1
  28. package/dist/dsh/core/host.d.ts.map +1 -1
  29. package/dist/dsh/core/host.js +48 -7
  30. package/dist/dsh/core/host.js.map +1 -1
  31. package/dist/dsh/core/index.js +2 -2
  32. package/dist/dsh/core/index.js.map +1 -1
  33. package/dist/dsh/core/tasks.d.ts +2 -0
  34. package/dist/dsh/core/tasks.d.ts.map +1 -1
  35. package/dist/dsh/core/tasks.js +37 -2
  36. package/dist/dsh/core/tasks.js.map +1 -1
  37. package/dist/dsh/execution-selection.d.ts +1 -1
  38. package/dist/dsh/host-adapter/admission.d.ts.map +1 -1
  39. package/dist/dsh/host-adapter/admission.js +13 -22
  40. package/dist/dsh/host-adapter/admission.js.map +1 -1
  41. package/dist/dsh/host-adapter/boundaries.d.ts.map +1 -1
  42. package/dist/dsh/host-adapter/boundaries.js +2 -0
  43. package/dist/dsh/host-adapter/boundaries.js.map +1 -1
  44. package/dist/dsh/host-adapter/context.d.ts.map +1 -1
  45. package/dist/dsh/host-adapter/context.js +18 -13
  46. package/dist/dsh/host-adapter/context.js.map +1 -1
  47. package/dist/dsh/host-adapter/lifecycle.d.ts.map +1 -1
  48. package/dist/dsh/host-adapter/lifecycle.js +12 -0
  49. package/dist/dsh/host-adapter/lifecycle.js.map +1 -1
  50. package/dist/dsh/host-adapter/routing.js +1 -1
  51. package/dist/dsh/host-adapter/routing.js.map +1 -1
  52. package/dist/dsh/host-adapter.d.ts.map +1 -1
  53. package/dist/dsh/host-adapter.js +36 -6
  54. package/dist/dsh/host-adapter.js.map +1 -1
  55. package/dist/dsh/lisp/candidate.d.ts +2 -2
  56. package/dist/dsh/lisp/code-intelligence-contracts.d.ts +1 -1
  57. package/dist/dsh/lisp/coding-choice.d.ts +3 -1
  58. package/dist/dsh/lisp/coding-choice.d.ts.map +1 -1
  59. package/dist/dsh/lisp/coding-choice.js +17 -12
  60. package/dist/dsh/lisp/coding-choice.js.map +1 -1
  61. package/dist/dsh/lisp/manager.d.ts +1 -0
  62. package/dist/dsh/lisp/manager.d.ts.map +1 -1
  63. package/dist/dsh/lisp/manager.js +13 -0
  64. package/dist/dsh/lisp/manager.js.map +1 -1
  65. package/dist/dsh/lisp/request-surface.d.ts +12 -2
  66. package/dist/dsh/lisp/request-surface.d.ts.map +1 -1
  67. package/dist/dsh/lisp/request-surface.js +1 -1
  68. package/dist/dsh/lisp/request-surface.js.map +1 -1
  69. package/dist/dsh/lisp/surface.d.ts.map +1 -1
  70. package/dist/dsh/lisp/surface.js +46 -5
  71. package/dist/dsh/lisp/surface.js.map +1 -1
  72. package/dist/dsh/lisp-service-key.d.ts +9 -0
  73. package/dist/dsh/lisp-service-key.d.ts.map +1 -1
  74. package/dist/dsh/lisp-service-key.js +11 -0
  75. package/dist/dsh/lisp-service-key.js.map +1 -1
  76. package/dist/dsh/models/profiles.d.ts +2 -0
  77. package/dist/dsh/models/profiles.d.ts.map +1 -1
  78. package/dist/dsh/models/profiles.js +9 -5
  79. package/dist/dsh/models/profiles.js.map +1 -1
  80. package/dist/dsh/models/service.d.ts +24 -1
  81. package/dist/dsh/models/service.d.ts.map +1 -1
  82. package/dist/dsh/models/service.js +85 -42
  83. package/dist/dsh/models/service.js.map +1 -1
  84. package/dist/dsh/modules/lisp.d.ts.map +1 -1
  85. package/dist/dsh/modules/lisp.js +1 -12
  86. package/dist/dsh/modules/lisp.js.map +1 -1
  87. package/dist/dsh/modules/resources.d.ts +3 -1
  88. package/dist/dsh/modules/resources.d.ts.map +1 -1
  89. package/dist/dsh/modules/resources.js +4 -0
  90. package/dist/dsh/modules/resources.js.map +1 -1
  91. package/dist/dsh/node-tap-summary.d.ts +2 -0
  92. package/dist/dsh/node-tap-summary.d.ts.map +1 -1
  93. package/dist/dsh/node-tap-summary.js +6 -1
  94. package/dist/dsh/node-tap-summary.js.map +1 -1
  95. package/dist/dsh/on-demand-intake.d.ts.map +1 -1
  96. package/dist/dsh/on-demand-intake.js +13 -4
  97. package/dist/dsh/on-demand-intake.js.map +1 -1
  98. package/dist/dsh/owned-evidence.d.ts.map +1 -1
  99. package/dist/dsh/owned-evidence.js +2 -2
  100. package/dist/dsh/owned-evidence.js.map +1 -1
  101. package/dist/dsh/owned-execution.d.ts +1 -0
  102. package/dist/dsh/owned-execution.d.ts.map +1 -1
  103. package/dist/dsh/owned-execution.js +37 -2
  104. package/dist/dsh/owned-execution.js.map +1 -1
  105. package/dist/dsh/skill-prompts.json +1 -1
  106. package/dist/dsh/task-completion-host.js +3 -3
  107. package/dist/dsh/task-completion-host.js.map +1 -1
  108. package/dist/dsh/task-completion.d.ts +16 -0
  109. package/dist/dsh/task-completion.d.ts.map +1 -1
  110. package/dist/dsh/task-completion.js +130 -24
  111. package/dist/dsh/task-completion.js.map +1 -1
  112. package/dist/dsh/task-intake.d.ts.map +1 -1
  113. package/dist/dsh/task-intake.js +7 -0
  114. package/dist/dsh/task-intake.js.map +1 -1
  115. package/dist/enno-oduno/coding-workflow.d.ts +39 -0
  116. package/dist/enno-oduno/coding-workflow.d.ts.map +1 -0
  117. package/dist/enno-oduno/coding-workflow.js +33 -0
  118. package/dist/enno-oduno/coding-workflow.js.map +1 -0
  119. package/dist/enno-oduno/schemas.d.ts +2 -2
  120. package/dist/enno-oduno/store.d.ts.map +1 -1
  121. package/dist/enno-oduno/store.js +46 -3
  122. package/dist/enno-oduno/store.js.map +1 -1
  123. package/dist/enno-oduno/types.d.ts +1 -0
  124. package/dist/enno-oduno/types.d.ts.map +1 -1
  125. package/dist/enno-oduno/verifier.d.ts.map +1 -1
  126. package/dist/enno-oduno/verifier.js +4 -1
  127. package/dist/enno-oduno/verifier.js.map +1 -1
  128. package/dist/locale/en.json +1 -1
  129. package/dist/locale/ja.json +1 -1
  130. package/dist/locale/ko.json +1 -1
  131. package/dist/locale/zh-CN.json +1 -1
  132. package/dist/model-tools/contracts.d.ts +2 -2
  133. package/dist/models-client.cjs +223 -157
  134. package/dist/models-client.d.ts.map +1 -1
  135. package/dist/models-client.js +261 -166
  136. package/dist/models-client.js.map +1 -1
  137. package/docs/coding-workflow.md +45 -0
  138. package/docs/execution-support.md +4 -0
  139. package/docs/kiokuko-models.md +25 -13
  140. package/docs/lisp-hot-tools.md +2 -2
  141. package/docs/lisp.md +7 -9
  142. package/migrations/036_coding_workflow.sql +26 -0
  143. package/package.json +2 -2
  144. package/skills/coding-ideal-routine-skill/SKILL.md +6 -0
  145. package/skills/kiokuko-lisp/SKILL.md +5 -1
  146. package/skills/kiokuko-soul/SKILL.md +2 -2
  147. package/skills/one-shot-software-completion/SKILL.md +5 -6
@@ -32,6 +32,8 @@ const MODEL_CONNECTION_DEFAULTS = {
32
32
  ollama: ["Ollama", "http://localhost:11434/v1", "chat-completions"],
33
33
  custom: ["Custom connection", "http://localhost:8080/v1", "chat-completions"],
34
34
  };
35
+ /** Providers whose stored credential can also be an OAuth sign-in. */
36
+ const OAUTH_KINDS = ["codex", "claude", "xai", "openai", "openrouter", "nous"];
35
37
  async function modelsApi(body, query = "") {
36
38
  const response = await fetch("/api/kiokuko.models" + query, {
37
39
  ...(body
@@ -59,6 +61,10 @@ function KiokukoModelsPanel(props) {
59
61
  reasoning: false,
60
62
  image: false,
61
63
  });
64
+ // Both disclosures are state-held: a rerender that shifts the leading
65
+ // status paragraphs remounts the editor, and a DOM-held `open` would snap
66
+ // shut under the user mid-task.
67
+ const [advanced, setAdvanced] = useState(false), [manualOpen, setManualOpen] = useState(false);
62
68
  const operation = useRef(undefined), mounted = useRef(true), working = useRef(false);
63
69
  const sessionId = props.sessionId;
64
70
  const load = async () => {
@@ -102,13 +108,17 @@ function KiokukoModelsPanel(props) {
102
108
  setError("");
103
109
  setModels([]);
104
110
  try {
105
- setModels(await modelsApi(undefined, "?op=models&id=" + encodeURIComponent(c.id)));
111
+ const list = (await modelsApi(undefined, "?op=models&id=" + encodeURIComponent(c.id)));
112
+ setModels(list);
113
+ return list;
106
114
  }
107
115
  catch (e) {
108
116
  setError(messageOf(e));
117
+ return [];
109
118
  }
110
119
  };
111
- const save = async () => {
120
+ /** Store the editor's current fields. Every action below needs this first. */
121
+ const persist = async () => {
112
122
  await modelsApi({
113
123
  op: "save",
114
124
  connection: {
@@ -120,11 +130,43 @@ function KiokukoModelsPanel(props) {
120
130
  serviceTier: connection.serviceTier,
121
131
  models: connection.models,
122
132
  },
123
- revision: state.revision,
133
+ revision: (await load()).revision,
124
134
  });
125
- const next = await load();
126
- await choose(next.connections.find((c) => c.id === connection.id));
127
- setNotice("Connection saved");
135
+ };
136
+ const reopen = async () => {
137
+ const saved = await load();
138
+ return choose(saved.connections.find((c) => c.id === connection.id) ?? connection);
139
+ };
140
+ /**
141
+ * The whole add-a-provider flow in one action: store the connection, store the
142
+ * typed key, then ask the adapter which models it serves. A discovery that
143
+ * fails still leaves the connection and key stored, so the panel reports the
144
+ * cause and keeps the manual registration path instead of discarding work.
145
+ */
146
+ const connect = async () => {
147
+ const draft = { ...connection };
148
+ await persist();
149
+ const typed = key.trim();
150
+ if (typed) {
151
+ await modelsApi({ op: "key", id: draft.id, key: typed });
152
+ setKey("");
153
+ }
154
+ let failure = "";
155
+ try {
156
+ await modelsApi({ op: "refresh", id: draft.id });
157
+ }
158
+ catch (e) {
159
+ failure = messageOf(e);
160
+ }
161
+ const list = await reopen();
162
+ if (failure) {
163
+ setNotice(typed ? "Connection and key saved" : "Connection saved");
164
+ setError(failure + " Register a model manually if this endpoint stays unusable.");
165
+ }
166
+ else
167
+ setNotice(list.length
168
+ ? "Connected · " + list.length + " model(s)"
169
+ : "Connected; no models discovered yet");
128
170
  };
129
171
  const newConnection = (kind) => {
130
172
  const spec = MODEL_CONNECTION_DEFAULTS[kind];
@@ -140,10 +182,11 @@ function KiokukoModelsPanel(props) {
140
182
  setModels([]);
141
183
  setKey("");
142
184
  setError("");
185
+ setNotice("");
143
186
  };
144
187
  const update = (field, value) => setConnection({ ...connection, [field]: value });
145
188
  const startLogin = async () => {
146
- await save();
189
+ await persist();
147
190
  const result = await modelsApi({ op: "login", id: connection.id });
148
191
  operation.current = result.operationId;
149
192
  setAuth({ id: result.operationId, status: "pending", events: [] });
@@ -159,11 +202,10 @@ function KiokukoModelsPanel(props) {
159
202
  setAuth(next);
160
203
  if (next.status !== "pending") {
161
204
  operation.current = undefined;
162
- void load()
163
- .then((value) => {
164
- if (next.status === "success")
165
- return choose(value.connections.find((c) => c.id === connection.id));
166
- setError(next.error ?? "Authentication cancelled");
205
+ void reopen()
206
+ .then(() => {
207
+ if (next.status !== "success")
208
+ setError(next.error ?? "Authentication cancelled");
167
209
  })
168
210
  .catch((e) => setError(messageOf(e)));
169
211
  }
@@ -177,7 +219,7 @@ function KiokukoModelsPanel(props) {
177
219
  clearInterval(timer);
178
220
  };
179
221
  }, [auth?.id, auth?.status]);
180
- const input = (label, value, onChange, type = "text") => jsx("label", {
222
+ const input = (label, value, onChange, type = "text", submit) => jsx("label", {
181
223
  children: jsxs(Fragment, {
182
224
  children: [
183
225
  jsx("span", { children: label }),
@@ -189,6 +231,16 @@ function KiokukoModelsPanel(props) {
189
231
  (label === "Base URL" &&
190
232
  ["codex", "opencode", "opencode-go"].includes(connection?.kind)),
191
233
  onChange: (e) => onChange(e.target.value),
234
+ ...(submit
235
+ ? {
236
+ onKeyDown: (e) => {
237
+ if (e.key !== "Enter")
238
+ return;
239
+ e.preventDefault();
240
+ submit();
241
+ },
242
+ }
243
+ : {}),
192
244
  autoComplete: type === "password" ? "new-password" : "off",
193
245
  }),
194
246
  ],
@@ -209,9 +261,15 @@ function KiokukoModelsPanel(props) {
209
261
  jsx("p", {
210
262
  children: "Connect directly for chat, Enno and Deep. Credentials are shared with dsh-cli. Signing out also signs dsh-cli out.",
211
263
  }),
212
- ...(error ? [jsx("p", { role: "alert", children: error })] : []),
213
- ...(notice ? [jsx("p", { role: "status", children: notice })] : []),
214
- ...(busy ? [jsx("p", { role: "status", children: "Working…" })] : []),
264
+ ...(error
265
+ ? [jsx("p", { role: "alert", children: error }, "error")]
266
+ : []),
267
+ ...(notice
268
+ ? [jsx("p", { role: "status", children: notice }, "notice")]
269
+ : []),
270
+ ...(busy
271
+ ? [jsx("p", { role: "status", children: "Working…" }, "busy")]
272
+ : []),
215
273
  button("Reload", () => void run(load)),
216
274
  jsx("label", {
217
275
  children: jsxs(Fragment, {
@@ -239,112 +297,41 @@ function KiokukoModelsPanel(props) {
239
297
  ? [
240
298
  jsxs("div", {
241
299
  className: "kiokuko-models-editor",
300
+ key: "editor",
242
301
  children: [
243
- input("Connection name", connection.name, (value) => update("name", value)),
244
- input("Base URL", connection.baseURL, (value) => update("baseURL", value)),
245
- jsx("label", {
246
- children: jsxs(Fragment, {
247
- children: [
248
- "Protocol",
249
- jsx("select", {
250
- "aria-label": "Protocol",
251
- value: connection.protocol,
252
- disabled: busy ||
253
- [
254
- "codex",
255
- "infron",
256
- "opencode",
257
- "opencode-go",
258
- ].includes(connection.kind),
259
- onChange: (e) => update("protocol", e.target.value),
260
- children: [
261
- ["chat-completions", "Chat Completions"],
262
- ["responses", "Responses"],
263
- ["messages", "Messages"],
264
- ].map(([id, name]) => jsx("option", { value: id, children: name }, id)),
265
- }),
266
- ],
267
- }),
268
- }),
269
- ...(connection.kind === "infron"
270
- ? [
271
- jsx("label", {
272
- children: jsxs(Fragment, {
273
- children: [
274
- "Service tier",
275
- jsx("select", {
276
- "aria-label": "Service tier",
277
- value: connection.serviceTier,
278
- disabled: busy,
279
- onChange: (e) => update("serviceTier", e.target.value),
280
- children: [
281
- jsx("option", {
282
- value: "standard",
283
- children: "Standard",
284
- }),
285
- jsx("option", {
286
- value: "flex",
287
- children: "Flex",
288
- }),
289
- ],
290
- }),
291
- ],
292
- }),
302
+ jsxs("h3", {
303
+ children: [
304
+ connection.name,
305
+ jsx("span", {
306
+ className: "kiokuko-models-state",
307
+ children: " · " + (connection.authState ?? "not saved yet"),
293
308
  }),
294
- jsx("p", {
295
- children: "Requested tier: " +
296
- connection.serviceTier +
297
- ". Last request: " +
298
- (connection.lastRequestedTier ?? "none") +
299
- ". Actual served tier: " +
300
- (connection.actualTier ?? "unknown") +
301
- ". Infron may serve Standard for a Flex request.",
302
- }),
303
- ]
304
- : []),
305
- button("Save connection", () => void run(save)),
309
+ ],
310
+ }),
306
311
  ...(connection.kind !== "codex" && connection.kind !== "ollama"
307
312
  ? [
308
- input("API key / bearer token", key, setKey, "password"),
309
- button("Save key", () => void run(async () => {
310
- await save();
311
- await modelsApi({
312
- op: "key",
313
- id: connection.id,
314
- key,
315
- });
316
- setKey("");
317
- await load();
318
- await choose(connection);
319
- setNotice("Key saved");
320
- }), !key),
321
- ]
322
- : []),
323
- ...([
324
- "codex",
325
- "claude",
326
- "xai",
327
- "openai",
328
- "openrouter",
329
- "nous",
330
- ].includes(connection.kind)
331
- ? [
332
- button("Log in", () => void run(startLogin), auth?.status === "pending"),
313
+ input("API key / bearer token", key, setKey, "password", () => {
314
+ if (!busy && key.trim())
315
+ void run(connect);
316
+ }),
333
317
  ]
334
318
  : []),
335
- button("Log out (also dsh-cli)", () => void run(async () => {
336
- await modelsApi({ op: "logout", id: connection.id });
337
- setKey("");
338
- setModels([]);
339
- await load();
340
- setNotice("Signed out");
341
- })),
342
- button("Refresh models", () => void run(async () => {
343
- await modelsApi({ op: "refresh", id: connection.id });
344
- const next = await load();
345
- await choose(next.connections.find((c) => c.id === connection.id));
346
- setNotice("Models refreshed");
347
- })),
319
+ jsxs("div", {
320
+ className: "kiokuko-models-actions",
321
+ children: [
322
+ button("Save and connect", () => void run(connect)),
323
+ ...(OAUTH_KINDS.includes(connection.kind)
324
+ ? [
325
+ button("Log in", () => void run(startLogin), auth?.status === "pending"),
326
+ ]
327
+ : []),
328
+ ],
329
+ }),
330
+ jsx("p", {
331
+ children: connection.kind === "ollama"
332
+ ? "Ollama needs no key. Save and connect to list its models."
333
+ : "Paste the API key and press Enter, or use Save and connect. The key is stored with dsh-cli's shared credentials.",
334
+ }),
348
335
  ...(auth?.status === "pending"
349
336
  ? [
350
337
  jsxs("div", {
@@ -445,62 +432,170 @@ function KiokukoModelsPanel(props) {
445
432
  }),
446
433
  ]
447
434
  : []),
448
- ...(!["opencode", "opencode-go"].includes(connection.kind)
449
- ? [
450
- jsx("details", {
435
+ jsxs("details", {
436
+ open: advanced,
437
+ children: [
438
+ jsx("summary", {
439
+ onClick: (e) => {
440
+ e.preventDefault();
441
+ setAdvanced(!advanced);
442
+ },
443
+ children: "Advanced settings",
444
+ }),
445
+ input("Connection name", connection.name, (value) => update("name", value)),
446
+ input("Base URL", connection.baseURL, (value) => update("baseURL", value)),
447
+ jsx("label", {
451
448
  children: jsxs(Fragment, {
452
449
  children: [
453
- jsx("summary", {
454
- children: "Register model manually",
450
+ "Protocol",
451
+ jsx("select", {
452
+ "aria-label": "Protocol",
453
+ value: connection.protocol,
454
+ disabled: busy ||
455
+ [
456
+ "codex",
457
+ "infron",
458
+ "opencode",
459
+ "opencode-go",
460
+ ].includes(connection.kind),
461
+ onChange: (e) => update("protocol", e.target.value),
462
+ children: [
463
+ ["chat-completions", "Chat Completions"],
464
+ ["responses", "Responses"],
465
+ ["messages", "Messages"],
466
+ ].map(([id, name]) => jsx("option", { value: id, children: name }, id)),
455
467
  }),
456
- input("Model ID", manual.id, (value) => setManual({ ...manual, id: value })),
457
- input("Context window", manual.contextWindow, (value) => setManual({
458
- ...manual,
459
- contextWindow: Number(value),
460
- }), "number"),
461
- input("Maximum output tokens", manual.maxTokens, (value) => setManual({
462
- ...manual,
463
- maxTokens: Number(value),
464
- }), "number"),
465
- jsx("label", {
466
- children: jsxs(Fragment, {
467
- children: [
468
- jsx("input", {
469
- type: "checkbox",
470
- checked: manual.reasoning,
471
- onChange: (e) => setManual({
472
- ...manual,
473
- reasoning: e.target.checked,
468
+ ],
469
+ }),
470
+ }),
471
+ ...(connection.kind === "infron"
472
+ ? [
473
+ jsx("label", {
474
+ children: jsxs(Fragment, {
475
+ children: [
476
+ "Service tier",
477
+ jsx("select", {
478
+ "aria-label": "Service tier",
479
+ value: connection.serviceTier,
480
+ disabled: busy,
481
+ onChange: (e) => update("serviceTier", e.target.value),
482
+ children: [
483
+ jsx("option", {
484
+ value: "standard",
485
+ children: "Standard",
474
486
  }),
475
- }),
476
- "Reasoning supported",
477
- ],
478
- }),
479
- }),
480
- jsx("label", {
481
- children: jsxs(Fragment, {
482
- children: [
483
- jsx("input", {
484
- type: "checkbox",
485
- checked: manual.image,
486
- onChange: (e) => setManual({
487
- ...manual,
488
- image: e.target.checked,
487
+ jsx("option", {
488
+ value: "flex",
489
+ children: "Flex",
489
490
  }),
491
+ ],
492
+ }),
493
+ ],
494
+ }),
495
+ }),
496
+ jsx("p", {
497
+ children: "Requested tier: " +
498
+ connection.serviceTier +
499
+ ". Last request: " +
500
+ (connection.lastRequestedTier ?? "none") +
501
+ ". Actual served tier: " +
502
+ (connection.actualTier ?? "unknown") +
503
+ ". Infron may serve Standard for a Flex request.",
504
+ }),
505
+ ]
506
+ : []),
507
+ button("Save connection", () => void run(async () => {
508
+ await persist();
509
+ await reopen();
510
+ setNotice("Connection saved");
511
+ })),
512
+ button("Refresh models", () => void run(async () => {
513
+ await persist();
514
+ await modelsApi({ op: "refresh", id: connection.id });
515
+ const list = await reopen();
516
+ setNotice(list.length
517
+ ? "Models refreshed"
518
+ : "Models refreshed; none discovered");
519
+ })),
520
+ button("Log out (also dsh-cli)", () => void run(async () => {
521
+ await persist();
522
+ await modelsApi({ op: "logout", id: connection.id });
523
+ setKey("");
524
+ setModels([]);
525
+ await load();
526
+ setNotice("Signed out");
527
+ })),
528
+ ...(!["opencode", "opencode-go"].includes(connection.kind)
529
+ ? [
530
+ jsx("details", {
531
+ open: manualOpen,
532
+ children: jsxs(Fragment, {
533
+ children: [
534
+ jsx("summary", {
535
+ onClick: (e) => {
536
+ e.preventDefault();
537
+ setManualOpen(!manualOpen);
538
+ },
539
+ children: "Register model manually",
540
+ }),
541
+ input("Model ID", manual.id, (value) => setManual({ ...manual, id: value })),
542
+ input("Context window", manual.contextWindow, (value) => setManual({
543
+ ...manual,
544
+ contextWindow: Number(value),
545
+ }), "number"),
546
+ input("Maximum output tokens", manual.maxTokens, (value) => setManual({
547
+ ...manual,
548
+ maxTokens: Number(value),
549
+ }), "number"),
550
+ jsx("label", {
551
+ children: jsxs(Fragment, {
552
+ children: [
553
+ jsx("input", {
554
+ type: "checkbox",
555
+ checked: manual.reasoning,
556
+ onChange: (e) => setManual({
557
+ ...manual,
558
+ reasoning: e.target.checked,
559
+ }),
560
+ }),
561
+ "Reasoning supported",
562
+ ],
490
563
  }),
491
- "Image input supported",
492
- ],
493
- }),
564
+ }),
565
+ jsx("label", {
566
+ children: jsxs(Fragment, {
567
+ children: [
568
+ jsx("input", {
569
+ type: "checkbox",
570
+ checked: manual.image,
571
+ onChange: (e) => setManual({
572
+ ...manual,
573
+ image: e.target.checked,
574
+ }),
575
+ }),
576
+ "Image input supported",
577
+ ],
578
+ }),
579
+ }),
580
+ button("Add manual model", () => {
581
+ update("models", [
582
+ ...connection.models.filter((m) => m.id !== manual.id),
583
+ { ...manual, name: manual.id },
584
+ ]);
585
+ setNotice("Model added to draft. Save connection to register it.");
586
+ }, !manual.id),
587
+ ],
494
588
  }),
495
- button("Add manual model", () => {
496
- update("models", [
497
- ...connection.models.filter((m) => m.id !== manual.id),
498
- { ...manual, name: manual.id },
499
- ]);
500
- setNotice("Model added to draft. Save connection to register it.");
501
- }, !manual.id),
502
- ],
503
- }),
589
+ }),
590
+ ]
591
+ : []),
592
+ ],
593
+ }),
594
+ jsx("h4", { children: "Models" }),
595
+ ...(models.length === 0
596
+ ? [
597
+ jsx("p", {
598
+ children: "No models yet. Save and connect to discover them, or register one under Advanced settings.",
504
599
  }),
505
600
  ]
506
601
  : []),
@@ -600,7 +695,7 @@ export function mountModelsClient(ctx) {
600
695
  ctx.effect(() => {
601
696
  const style = document.createElement("style");
602
697
  style.textContent =
603
- ".kiokuko-models-modal{width:min(900px,calc(100vw - 32px))}.kiokuko-models-panel{box-sizing:border-box;width:100%;max-width:900px;padding:16px;overflow:auto;max-height:75vh}.kiokuko-models-panel label{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin:12px 0}.kiokuko-models-panel input,.kiokuko-models-panel select{max-width:100%;box-sizing:border-box;border:1px solid #888;border-radius:6px;padding:8px;color:inherit;background:transparent}.kiokuko-models-panel button{border:1px solid #888;border-radius:6px;padding:8px;margin:4px;color:inherit}.kiokuko-models-panel button:disabled{opacity:.5}.kiokuko-models-panel li{margin:8px 0}.kiokuko-models-panel :focus-visible{outline:2px solid #3286ff;outline-offset:3px}";
698
+ ".kiokuko-models-modal{width:min(900px,calc(100vw - 32px))}.kiokuko-models-panel{box-sizing:border-box;width:100%;max-width:900px;padding:16px;overflow:auto;max-height:75vh}.kiokuko-models-panel label{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin:12px 0}.kiokuko-models-panel input,.kiokuko-models-panel select{max-width:100%;box-sizing:border-box;border:1px solid #888;border-radius:6px;padding:8px;color:inherit;background:transparent}.kiokuko-models-panel button{border:1px solid #888;border-radius:6px;padding:8px;margin:4px;color:inherit}.kiokuko-models-panel button:disabled{opacity:.5}.kiokuko-models-panel li{margin:8px 0}.kiokuko-models-panel :focus-visible{outline:2px solid #3286ff;outline-offset:3px}.kiokuko-models-panel summary{cursor:pointer;margin:12px 0}.kiokuko-models-panel h3,.kiokuko-models-panel h4{margin:12px 0 0}.kiokuko-models-state{font-weight:400;font-size:.85em;opacity:.75}.kiokuko-models-actions{display:flex;gap:8px;align-items:center;flex-wrap:wrap}";
604
699
  document.head.append(style);
605
700
  return () => style.remove();
606
701
  }, "kiokuko models style");