@iowarp/clio-coder 0.4.5 → 0.4.6
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.
- package/CHANGELOG.md +24 -0
- package/CONTRIBUTING.md +14 -9
- package/NOTICE +16 -0
- package/README.md +312 -685
- package/dist/{acp-H3CU2HBQ.js → acp-UVEVWSDL.js} +6 -6
- package/dist/{agents-IXQQZ7BD.js → agents-VWY37DTK.js} +31 -30
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-R7KYF7N3.js → auth-PCV2XQDV.js} +6 -6
- package/dist/{builtins-CRFDQUVP.js → builtins-PD652MTK.js} +3 -3
- package/dist/{chunk-SDWNDICN.js → chunk-24T2YZ7A.js} +58 -56
- package/dist/{chunk-FSTIBAGM.js → chunk-2AKYFREM.js} +7 -7
- package/dist/{chunk-SE4ZKILO.js → chunk-3BJGMT2D.js} +30 -9
- package/dist/{chunk-GVYWZNRK.js → chunk-3HQVBIKD.js} +2 -2
- package/dist/{chunk-EWD5P3GK.js → chunk-3JLFK5MW.js} +4 -4
- package/dist/{chunk-O2RQ7LCK.js → chunk-3O2ZAUGQ.js} +2 -2
- package/dist/{chunk-GXCCHKN6.js → chunk-3QKXHCGS.js} +4 -4
- package/dist/{chunk-YEJIG7LN.js → chunk-3WBALRQH.js} +7 -7
- package/dist/{chunk-I7VLWRK2.js → chunk-4DU2TVI4.js} +5 -5
- package/dist/{chunk-TEG3RYVZ.js → chunk-4U4TKZFR.js} +3 -3
- package/dist/{chunk-EHCPSZJF.js → chunk-4VMV6OS6.js} +2 -2
- package/dist/{chunk-T7FDXNRU.js → chunk-536HXRFE.js} +4 -4
- package/dist/{chunk-ZMZQEBKI.js → chunk-5QRX7SLS.js} +8 -8
- package/dist/{chunk-RXIOCVBZ.js → chunk-6HAO6X5B.js} +4 -4
- package/dist/{chunk-HGSLRG33.js → chunk-6OII3LOK.js} +2 -2
- package/dist/{chunk-U2JOLB7O.js → chunk-6RYDAVQT.js} +32 -32
- package/dist/{chunk-T53XI6I7.js → chunk-6VRRJT7L.js} +2 -2
- package/dist/{chunk-RLTT5GVY.js → chunk-7JSSKXG2.js} +4 -4
- package/dist/{chunk-633EXGZA.js → chunk-ACCKVSHU.js} +3 -3
- package/dist/{chunk-6SYEGZI3.js → chunk-B3MOMLJ4.js} +2 -2
- package/dist/{chunk-UXAC2FX4.js → chunk-BLTEAUCB.js} +3 -3
- package/dist/{chunk-DRD2A54W.js → chunk-BT7HGDOX.js} +15 -15
- package/dist/{chunk-F34AR6O3.js → chunk-DXLUVUD4.js} +5 -5
- package/dist/{chunk-HR3HPQ76.js → chunk-E7RF4KBO.js} +2 -2
- package/dist/chunk-EM2WNQS2.js +93 -0
- package/dist/{chunk-KYKNBD4Y.js → chunk-F5Z7EWMN.js} +953 -233
- package/dist/{chunk-VLPTKCKT.js → chunk-GLYBJ4RQ.js} +3 -3
- package/dist/{chunk-KDWLXVMN.js → chunk-HPTJF6DG.js} +16 -39
- package/dist/{chunk-6CDNRHWH.js → chunk-HZ2T2YED.js} +2 -2
- package/dist/{chunk-UTUNT5QL.js → chunk-HZFBVU5X.js} +7 -7
- package/dist/{chunk-KF6GFW6O.js → chunk-I2K2NCZQ.js} +7 -7
- package/dist/{chunk-5DDOTTG4.js → chunk-IGLVVNEG.js} +2 -2
- package/dist/{chunk-4SVIVOMC.js → chunk-IKRWLEDA.js} +5 -5
- package/dist/{chunk-R6MAYTMS.js → chunk-JMPL7NUB.js} +3 -3
- package/dist/{chunk-5ZMXGW7P.js → chunk-KAFMW7WM.js} +4 -85
- package/dist/{chunk-R6MICQYU.js → chunk-LIN2K3EL.js} +4 -4
- package/dist/{chunk-QEQISF75.js → chunk-LK2FN5JY.js} +1 -1
- package/dist/{chunk-YYB3MC65.js → chunk-N2OKBREN.js} +2 -2
- package/dist/{chunk-XXBQKW32.js → chunk-NNWJYUNO.js} +4 -4
- package/dist/{chunk-TZ7MFRG4.js → chunk-P5JMBPDJ.js} +22 -20
- package/dist/{chunk-WFKDPU7U.js → chunk-P6M7RKMI.js} +2 -2
- package/dist/{chunk-MDU3C27C.js → chunk-PZN2LQY6.js} +5 -5
- package/dist/{chunk-S32UQ5GL.js → chunk-Q7NNUHQV.js} +15 -15
- package/dist/{chunk-U7VQ4NI4.js → chunk-QCOV5DFY.js} +5 -5
- package/dist/{chunk-MC3JSVR6.js → chunk-QJMRYTCX.js} +7 -7
- package/dist/{chunk-DIMRLNIC.js → chunk-QNWRHOMF.js} +3 -3
- package/dist/{chunk-ILJ7DWGE.js → chunk-QXFBABFJ.js} +4 -4
- package/dist/chunk-R2CT5YDO.js +66 -0
- package/dist/{chunk-E3BQTQUP.js → chunk-RGZNQ5CT.js} +3 -3
- package/dist/{chunk-SBZX6ARC.js → chunk-SXQKNKRA.js} +7 -7
- package/dist/{chunk-WLMSOT73.js → chunk-TJFDL26W.js} +3 -3
- package/dist/{chunk-EQEJJ53P.js → chunk-VAHLPXPY.js} +2 -2
- package/dist/{chunk-7TKWWPD7.js → chunk-VANN3GDP.js} +3 -23
- package/dist/{chunk-GNQRWTMY.js → chunk-VHMX7SXF.js} +2 -2
- package/dist/{chunk-UL36QJX6.js → chunk-WKUYQBCG.js} +6 -6
- package/dist/{chunk-FKIOX6DS.js → chunk-WNGF5AJX.js} +9 -4
- package/dist/{chunk-ICO4TQ2F.js → chunk-WV6TDAPN.js} +36 -20
- package/dist/{chunk-K6RDB7IA.js → chunk-X3BI7HTV.js} +9 -9
- package/dist/{chunk-NY6IWDVU.js → chunk-XWMSPJYN.js} +2 -2
- package/dist/{chunk-7HBHHVCK.js → chunk-YPRSNUTC.js} +2 -2
- package/dist/{chunk-ONRTXOZY.js → chunk-ZS43Y2FT.js} +2 -2
- package/dist/cli/index.js +27 -27
- package/dist/{clio-5I2IBFYL.js → clio-QQCMTUZE.js} +6 -6
- package/dist/{code-nav-YXIAEZVS.js → code-nav-GUPM6766.js} +8 -8
- package/dist/{config-Y2JDJ3JJ.js → config-IIM7YOD3.js} +42 -41
- package/dist/{configure-SML6UBZ5.js → configure-4ZM5HWJX.js} +28 -10
- package/dist/{context-S2EEC3EJ.js → context-44BZLJ3J.js} +12 -12
- package/dist/{context-P5YSEO55.js → context-AIDVQKMW.js} +34 -33
- package/dist/{context-QQ53HSGJ.js → context-OL5P3HEP.js} +25 -24
- package/dist/{context-clear-TMEQCOTH.js → context-clear-OQV76MYP.js} +34 -33
- package/dist/{context-working-set-CNLSQN5K.js → context-working-set-ZUW3EGLS.js} +10 -9
- package/dist/{detail-5572VLBO.js → detail-UXPWRANG.js} +35 -34
- package/dist/{dispatch-runner-FRHD6P2O.js → dispatch-runner-P3ZW6G77.js} +38 -37
- package/dist/{doctor-N3LCM2LG.js → doctor-JJVGPZWT.js} +18 -17
- package/dist/{eval-BUU3ZOUZ.js → eval-V2RTN3UH.js} +26 -25
- package/dist/{evidence-DTGEN456.js → evidence-35PYWGSO.js} +34 -33
- package/dist/{evidence-SQ5DNFEN.js → evidence-CIGGKI6J.js} +36 -35
- package/dist/{evolve-IJNUFZDS.js → evolve-33SM3NJP.js} +34 -33
- package/dist/{fleet-ZNNVSYFO.js → fleet-LFO7SIPC.js} +62 -61
- package/dist/{fleet-commands-5YE7NPJL.js → fleet-commands-RLK72GU3.js} +9 -9
- package/dist/fleet-decisions-3SBSCTCW.js +1 -1
- package/dist/{fleet-graph-6HHPWF5T.js → fleet-graph-JZIBCGMW.js} +11 -11
- package/dist/{fleet-inspect-JEYMGCGC.js → fleet-inspect-2L5YGGZJ.js} +35 -34
- package/dist/{fleet-validate-4PM4GDDL.js → fleet-validate-LIAVKDUU.js} +12 -12
- package/dist/{fleet-verify-NJDTHTO3.js → fleet-verify-JIK3OQZR.js} +34 -33
- package/dist/{fleet-view-UP2BWQQY.js → fleet-view-IWHYGQKK.js} +35 -34
- package/dist/{init-S3GZQ5ZF.js → init-NJEDOTQW.js} +46 -45
- package/dist/{interop-YOTGXFJM.js → interop-RVCAYECG.js} +4 -4
- package/dist/{inventory-K2OZ36YJ.js → inventory-74UL7UHU.js} +35 -34
- package/dist/{library-GJI6W6OK.js → library-CTKZA7K3.js} +10 -10
- package/dist/{memory-OQOXQGYD.js → memory-I76I5VUH.js} +34 -33
- package/dist/{models-3IK2Y5WE.js → models-D4YDIQZQ.js} +19 -18
- package/dist/{monitor-FTJLTKCQ.js → monitor-NKVD55HX.js} +40 -39
- package/dist/{orchestrator-N47O7SFD.js → orchestrator-I6OATVPK.js} +658 -1092
- package/dist/{preload-65U34NG6.js → preload-EJAWJEIO.js} +34 -33
- package/dist/{reset-MUVQDLNL.js → reset-4XMQKDNZ.js} +5 -3
- package/dist/{resources-LM76COAO.js → resources-TVYVXK3Q.js} +10 -10
- package/dist/{run-3VFZQ33N.js → run-OWQNNSJU.js} +61 -60
- package/dist/{share-4JUB4BL7.js → share-NPZZMUXG.js} +11 -11
- package/dist/{skills-S36AAJHU.js → skills-OXFEAWMT.js} +12 -12
- package/dist/{skills-eval-G6T57L7M.js → skills-eval-J5TCKSJA.js} +38 -37
- package/dist/{skills-inventory-WLM46PJH.js → skills-inventory-7II4DM57.js} +10 -10
- package/dist/{slash-commands-GBARG3Y7.js → slash-commands-MDSDSWYF.js} +26 -25
- package/dist/{targets-N5REUETU.js → targets-KILZEOCE.js} +36 -20
- package/dist/{tasks-6BVY5YZF.js → tasks-R6P6OV22.js} +7 -7
- package/dist/{terminal-lease-57UEOJKS.js → terminal-lease-LZCG2KN3.js} +2 -2
- package/dist/{upgrade-4HD5HAIV.js → upgrade-D2OZH6IQ.js} +9 -9
- package/dist/{usage-4GWM2WWP.js → usage-PIASNUS4.js} +40 -39
- package/dist/{verifiers-GSKWKWVG.js → verifiers-LTHUY2PX.js} +9 -9
- package/dist/{verify-3AS3ULCY.js → verify-HYF7KBVE.js} +7 -7
- package/dist/{wiki-generate-7BV7XWIY.js → wiki-generate-RK7JQ5NP.js} +51 -50
- package/dist/worker/entry.js +41 -39
- package/docs/architecture/context-engine.md +1 -1
- package/docs/architecture/tui-design.md +45 -30
- package/docs/guide/commands-and-modes.md +26 -25
- package/docs/guide/configuration-and-targets.md +122 -27
- package/docs/guide/configuration-reference.md +9 -4
- package/docs/guide/fleet-dispatch.md +1 -6
- package/docs/guide/glossary.md +1 -1
- package/docs/guide/installation-and-lifecycle.md +44 -11
- package/docs/process/development-pipeline.md +1 -1
- package/docs/process/documentation-coverage.md +1 -1
- package/docs/process/release-cut-checklist.md +18 -6
- package/package.json +1 -1
- package/src/cli/ask.ts +10 -10
- package/src/cli/configure-editor.ts +51 -0
- package/src/cli/configure-interop.ts +1 -1
- package/src/cli/configure-oauth.ts +1 -1
- package/src/cli/configure-onboarding.ts +232 -96
- package/src/cli/configure-prompts.ts +76 -0
- package/src/cli/configure-quick.ts +274 -0
- package/src/cli/configure-target.ts +14 -2
- package/src/cli/configure.ts +413 -174
- package/src/cli/oauth-manual-input.ts +1 -1
- package/src/cli/reset.ts +2 -0
- package/src/cli/select.ts +35 -4
- package/src/cli/upgrade.ts +2 -2
- package/src/core/config.ts +6 -1
- package/src/core/defaults.ts +33 -11
- package/src/{interactive → core}/external-editor.ts +4 -4
- package/src/domains/config/classify.ts +1 -1
- package/src/domains/config/keybindings.ts +3 -31
- package/src/domains/providers/probe/fingerprint.ts +13 -6
- package/src/domains/providers/probe/reasoning.ts +2 -0
- package/src/domains/providers/runtimes/common/probe-helpers.ts +23 -7
- package/src/domains/providers/runtimes/protocol/anthropic-compat.ts +7 -2
- package/src/domains/providers/runtimes/protocol/openai-compat.ts +10 -4
- package/src/interactive/application-controller.ts +1 -31
- package/src/interactive/chat-panel.ts +163 -637
- package/src/interactive/chat-renderer.ts +13 -30
- package/src/interactive/dispatch-board.ts +1 -3
- package/src/interactive/editor-submit.ts +8 -31
- package/src/interactive/footer/dashboard.ts +8 -3
- package/src/interactive/footer/widgets.ts +50 -91
- package/src/interactive/interactive-application.ts +16 -42
- package/src/interactive/interactive-event-projection.ts +2 -44
- package/src/interactive/interactive-input-runtime.ts +3 -28
- package/src/interactive/interactive-presentation.ts +30 -9
- package/src/interactive/interactive-slash-runtime.ts +3 -40
- package/src/interactive/layout.ts +29 -4
- package/src/interactive/overlay-general-openers.ts +2 -0
- package/src/interactive/overlay-lifecycle.ts +1 -0
- package/src/interactive/overlay-session-lifecycle.ts +1 -1
- package/src/interactive/overlays/settings.ts +9 -8
- package/src/interactive/renderers/preview.ts +16 -0
- package/src/interactive/renderers/tool-execution.ts +67 -160
- package/src/interactive/renderers/worker-entry.ts +57 -41
- package/src/interactive/slash-autocomplete.ts +1 -6
- package/src/interactive/slash-commands.ts +7 -39
- package/src/interactive/status/controller.ts +0 -5
- package/src/interactive/status/state-machine.ts +44 -26
- package/src/interactive/status/types.ts +3 -0
- package/src/interactive/status/verbs.ts +13 -12
- package/src/interactive/transcript-detail.ts +50 -112
- package/src/interactive/view/artifacts.ts +4 -0
- package/src/interactive/view/view-overlay.ts +44 -34
- package/src/tools/presentation.ts +1 -1
- package/src/tools/registry.ts +1 -1
- package/src/tools/verify/numeric.ts +4 -4
package/src/cli/reset.ts
CHANGED
|
@@ -372,6 +372,8 @@ export async function runResetCommand(argv: ReadonlyArray<string>): Promise<numb
|
|
|
372
372
|
presenter.finish();
|
|
373
373
|
return 1;
|
|
374
374
|
}
|
|
375
|
+
if (args.config || args.all) presenter.commandAdvice("Set up a model again:", "clio-coder configure");
|
|
376
|
+
else if (args.auth) presenter.commandAdvice("Reconnect your providers:", "clio-coder configure --section targets");
|
|
375
377
|
|
|
376
378
|
presenter.done("Done");
|
|
377
379
|
return 0;
|
package/src/cli/select.ts
CHANGED
|
@@ -48,6 +48,8 @@ export interface SelectOptions<T> {
|
|
|
48
48
|
backLabel?: string;
|
|
49
49
|
/** Rows to show at once. Defaults to what the terminal has room for. */
|
|
50
50
|
maxVisible?: number;
|
|
51
|
+
/** Filter a long list by typing; q/j/k are text in this mode. */
|
|
52
|
+
searchable?: boolean;
|
|
51
53
|
/**
|
|
52
54
|
* Erase the menu once it is answered, leaving the caller's transcript to say
|
|
53
55
|
* what was chosen. A wizard that redraws its own answer rows needs this; a
|
|
@@ -243,7 +245,7 @@ function viewportFor(output: NodeJS.WriteStream, overhead: number, total: number
|
|
|
243
245
|
export async function promptSelect<T>(options: SelectOptions<T>): Promise<SelectResult<T>> {
|
|
244
246
|
const input = options.input ?? process.stdin;
|
|
245
247
|
const output = options.output ?? process.stdout;
|
|
246
|
-
|
|
248
|
+
let choices = options.choices;
|
|
247
249
|
if (choices.length === 0) return { kind: "back" };
|
|
248
250
|
|
|
249
251
|
const rail = options.railPrefix ?? "";
|
|
@@ -255,15 +257,25 @@ export async function promptSelect<T>(options: SelectOptions<T>): Promise<Select
|
|
|
255
257
|
|
|
256
258
|
let index = Math.min(Math.max(options.initialIndex ?? 0, 0), choices.length - 1);
|
|
257
259
|
let windowStart = 0;
|
|
260
|
+
let query = "";
|
|
261
|
+
const filter = () => {
|
|
262
|
+
choices = options.choices.filter((choice) => choice.label.toLowerCase().includes(query.toLowerCase()));
|
|
263
|
+
index = 0;
|
|
264
|
+
windowStart = 0;
|
|
265
|
+
render();
|
|
266
|
+
};
|
|
258
267
|
|
|
259
268
|
const render = (): void => {
|
|
260
|
-
const viewport = viewportFor(output, head.length + 5, choices.length, options.maxVisible);
|
|
269
|
+
const viewport = viewportFor(output, head.length + (options.searchable ? 6 : 5), choices.length, options.maxVisible);
|
|
261
270
|
if (index < windowStart) windowStart = index;
|
|
262
271
|
else if (index >= windowStart + viewport) windowStart = index - viewport + 1;
|
|
263
272
|
windowStart = Math.max(0, Math.min(windowStart, choices.length - viewport));
|
|
264
273
|
const lines: string[] = [];
|
|
265
274
|
for (const line of head) lines.push(`${rail}${line}`.trimEnd());
|
|
266
275
|
if (head.length > 0) lines.push(rail.trimEnd());
|
|
276
|
+
if (options.searchable)
|
|
277
|
+
lines.push(`${rail}${truncate(`Filter: ${query || "(type to search)"}`, terminalColumns(output) - railWidth)}`);
|
|
278
|
+
if (choices.length === 0) lines.push(`${rail}No matching models`);
|
|
267
279
|
lines.push(
|
|
268
280
|
...choiceRows(
|
|
269
281
|
{
|
|
@@ -284,7 +296,8 @@ export async function promptSelect<T>(options: SelectOptions<T>): Promise<Select
|
|
|
284
296
|
// "quit" reads as two different exits.
|
|
285
297
|
const legend = ["↑/↓ move", "enter select"];
|
|
286
298
|
if (options.backLabel !== undefined && options.backLabel !== "quit") legend.push(`esc ${options.backLabel}`);
|
|
287
|
-
legend.push(
|
|
299
|
+
if (options.searchable) legend.push("type to filter", "ctrl-u clear", "ctrl-c quit");
|
|
300
|
+
else legend.push(options.backLabel === "quit" ? "esc or q quit" : "q quit");
|
|
288
301
|
lines.push(`${rail}${chalk.dim(legend.join(" · "))}`);
|
|
289
302
|
frame.draw(lines);
|
|
290
303
|
};
|
|
@@ -294,11 +307,29 @@ export async function promptSelect<T>(options: SelectOptions<T>): Promise<Select
|
|
|
294
307
|
output,
|
|
295
308
|
true,
|
|
296
309
|
render,
|
|
297
|
-
(
|
|
310
|
+
(str, key, finish) => {
|
|
298
311
|
if (key.ctrl && (key.name === "c" || key.name === "d")) {
|
|
299
312
|
finish({ kind: "quit" });
|
|
300
313
|
return;
|
|
301
314
|
}
|
|
315
|
+
if (options.searchable) {
|
|
316
|
+
if (key.ctrl && key.name === "u") {
|
|
317
|
+
query = "";
|
|
318
|
+
filter();
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
if (key.name === "backspace") {
|
|
322
|
+
query = query.slice(0, -1);
|
|
323
|
+
filter();
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (!key.ctrl && !key.meta && str?.length === 1 && str >= " " && str !== "\x7f") {
|
|
327
|
+
query += str;
|
|
328
|
+
filter();
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
if (choices.length === 0 && !["escape", "left"].includes(key.name ?? "")) return;
|
|
332
|
+
}
|
|
302
333
|
switch (key.name) {
|
|
303
334
|
case "up":
|
|
304
335
|
case "k":
|
package/src/cli/upgrade.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { initializeClioHome } from "../core/init.js";
|
|
3
|
-
import {
|
|
3
|
+
import { resolveClioDirs } from "../core/xdg.js";
|
|
4
4
|
import { detectInstallMethod } from "../domains/lifecycle/install-method.js";
|
|
5
5
|
import { listMigrations, readMigrationManifest, runPending } from "../domains/lifecycle/migrations/index.js";
|
|
6
6
|
import { readStateInfo } from "../domains/lifecycle/state.js";
|
|
@@ -185,7 +185,7 @@ export async function runUpgradeCommand(argv: ReadonlyArray<string>): Promise<nu
|
|
|
185
185
|
presenter.header("Upgrade", "upgrade");
|
|
186
186
|
|
|
187
187
|
const before = getVersionInfo().clio;
|
|
188
|
-
const stateDir =
|
|
188
|
+
const stateDir = resolveClioDirs().state;
|
|
189
189
|
const method = detectInstallMethod();
|
|
190
190
|
const methodLabel = method === "source" ? "source checkout" : opts.postInstall ? "package install" : "npm global";
|
|
191
191
|
presenter.setMethod(methodLabel);
|
package/src/core/config.ts
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
ACTIVE_ROUTING_ROLES,
|
|
22
22
|
COUNCIL_MEMBER_LABEL_PATTERN,
|
|
23
23
|
DEFAULT_SETTINGS,
|
|
24
|
+
normalizeOutputStyle,
|
|
24
25
|
THEME_NAMED_COLORS,
|
|
25
26
|
THINKING_LEVELS,
|
|
26
27
|
type ThinkingLevel,
|
|
@@ -1745,8 +1746,12 @@ export function validateSettings(raw: unknown): SettingsValidationResult {
|
|
|
1745
1746
|
const parsed = expectBoolean(issues, `interface.${key}`, ui[key]);
|
|
1746
1747
|
if (parsed !== undefined) (settings.interface as unknown as Record<string, unknown>)[key] = parsed;
|
|
1747
1748
|
}
|
|
1749
|
+
if ("outputDetail" in ui) {
|
|
1750
|
+
const style = normalizeOutputStyle(ui.outputDetail);
|
|
1751
|
+
if (style) settings.interface.outputDetail = style;
|
|
1752
|
+
else issues.add("interface.outputDetail", "expected compact, standard, or detailed");
|
|
1753
|
+
}
|
|
1748
1754
|
for (const [key, allowed] of [
|
|
1749
|
-
["outputDetail", ["minimal", "default", "verbose"]],
|
|
1750
1755
|
["smoothStreaming", ["off", "auto", "on"]],
|
|
1751
1756
|
["mode", ["regular", "fullscreen"]],
|
|
1752
1757
|
["fullscreenScrollbar", ["hidden", "auto", "always"]],
|
package/src/core/defaults.ts
CHANGED
|
@@ -219,15 +219,37 @@ export interface RetrySettings {
|
|
|
219
219
|
streamStallMs: number;
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
-
export
|
|
222
|
+
export const OUTPUT_STYLES = ["compact", "standard", "detailed"] as const;
|
|
223
|
+
export type OutputStyle = (typeof OUTPUT_STYLES)[number];
|
|
224
|
+
|
|
225
|
+
/** Read older preferences without rewriting a user's settings on startup. */
|
|
226
|
+
export function normalizeOutputStyle(value: unknown): OutputStyle | undefined {
|
|
227
|
+
switch (value) {
|
|
228
|
+
case "minimal":
|
|
229
|
+
case "compact":
|
|
230
|
+
return "compact";
|
|
231
|
+
case "default":
|
|
232
|
+
case "standard":
|
|
233
|
+
return "standard";
|
|
234
|
+
case "verbose":
|
|
235
|
+
case "detailed":
|
|
236
|
+
return "detailed";
|
|
237
|
+
default:
|
|
238
|
+
return undefined;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export function nextOutputStyle(style: OutputStyle): OutputStyle {
|
|
243
|
+
return OUTPUT_STYLES[(OUTPUT_STYLES.indexOf(style) + 1) % OUTPUT_STYLES.length] ?? "standard";
|
|
244
|
+
}
|
|
223
245
|
export type TuiMode = "regular" | "fullscreen";
|
|
224
246
|
export type FullscreenScrollbar = "hidden" | "auto" | "always";
|
|
225
247
|
export type SmoothStreaming = "off" | "auto" | "on";
|
|
226
248
|
|
|
227
249
|
export interface InterfaceSettings {
|
|
228
250
|
terminalProgress: boolean;
|
|
229
|
-
/**
|
|
230
|
-
outputDetail:
|
|
251
|
+
/** Output style: Compact, Standard, or Detailed bounded previews. */
|
|
252
|
+
outputDetail: OutputStyle;
|
|
231
253
|
/** Regular scrollback-preserving renderer or alternate-screen sticky layout. */
|
|
232
254
|
mode: TuiMode;
|
|
233
255
|
/** Fullscreen transcript scrollbar visibility. */
|
|
@@ -456,7 +478,7 @@ export const DEFAULT_SETTINGS = {
|
|
|
456
478
|
recentLimit: 12,
|
|
457
479
|
} as ModelSelectorSettings,
|
|
458
480
|
maxOutputTokens: 0,
|
|
459
|
-
prewarm:
|
|
481
|
+
prewarm: false,
|
|
460
482
|
retry: {
|
|
461
483
|
enabled: true,
|
|
462
484
|
maxRetries: 3,
|
|
@@ -484,7 +506,7 @@ export const DEFAULT_SETTINGS = {
|
|
|
484
506
|
mode: "deny" as WorkerPermissionMode,
|
|
485
507
|
escalation: { timeoutMs: 120000, fallback: "deny" } as WorkerEscalationSettings,
|
|
486
508
|
},
|
|
487
|
-
concurrency:
|
|
509
|
+
concurrency: 1 as "auto" | number,
|
|
488
510
|
retry: { maxRetries: 2, routeCooldownMs: 15000 },
|
|
489
511
|
limits: {
|
|
490
512
|
toolCallsPerRun: GUARDRAIL_DEFAULTS.workerToolCallCap,
|
|
@@ -521,10 +543,10 @@ export const DEFAULT_SETTINGS = {
|
|
|
521
543
|
} as SafetySettings,
|
|
522
544
|
interface: {
|
|
523
545
|
terminalProgress: false,
|
|
524
|
-
outputDetail: "
|
|
546
|
+
outputDetail: "standard",
|
|
525
547
|
mode: "regular",
|
|
526
548
|
fullscreenScrollbar: "auto",
|
|
527
|
-
smoothStreaming: "
|
|
549
|
+
smoothStreaming: "auto",
|
|
528
550
|
desktopNotifications: false,
|
|
529
551
|
panes: {
|
|
530
552
|
enabled: "off",
|
|
@@ -591,7 +613,7 @@ chat:
|
|
|
591
613
|
favorites: []
|
|
592
614
|
recentLimit: 12
|
|
593
615
|
maxOutputTokens: 0
|
|
594
|
-
prewarm:
|
|
616
|
+
prewarm: false
|
|
595
617
|
retry:
|
|
596
618
|
enabled: true
|
|
597
619
|
maxRetries: 3
|
|
@@ -617,7 +639,7 @@ fleet:
|
|
|
617
639
|
escalation:
|
|
618
640
|
timeoutMs: 120000
|
|
619
641
|
fallback: deny
|
|
620
|
-
concurrency:
|
|
642
|
+
concurrency: 1
|
|
621
643
|
retry:
|
|
622
644
|
maxRetries: 2
|
|
623
645
|
routeCooldownMs: 15000
|
|
@@ -659,8 +681,8 @@ safety:
|
|
|
659
681
|
enabled: false
|
|
660
682
|
|
|
661
683
|
interface:
|
|
662
|
-
outputDetail:
|
|
663
|
-
smoothStreaming:
|
|
684
|
+
outputDetail: standard
|
|
685
|
+
smoothStreaming: auto
|
|
664
686
|
mode: regular
|
|
665
687
|
fullscreenScrollbar: auto
|
|
666
688
|
terminalProgress: false
|
|
@@ -3,7 +3,7 @@ import { randomUUID } from "node:crypto";
|
|
|
3
3
|
import { readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
5
5
|
import { join } from "node:path";
|
|
6
|
-
import { shellQuote } from "
|
|
6
|
+
import { shellQuote } from "./shell-quote.js";
|
|
7
7
|
|
|
8
8
|
export type ExternalEditorProbe = (candidates: ReadonlyArray<string>) => string | null;
|
|
9
9
|
|
|
@@ -48,11 +48,11 @@ export function resolveExternalEditor(
|
|
|
48
48
|
return probe(["nano", "vi"]);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
export function editTextExternally(initialText: string, command: string | null): ExternalEditResult {
|
|
51
|
+
export function editTextExternally(initialText: string, command: string | null, extension = ".md"): ExternalEditResult {
|
|
52
52
|
if (!command) return { ok: false, error: "no external editor configured; set VISUAL or EDITOR" };
|
|
53
|
-
const tmpFile = join(tmpdir(), `clio-coder-editor-${process.pid}-${randomUUID()}
|
|
53
|
+
const tmpFile = join(tmpdir(), `clio-coder-editor-${process.pid}-${randomUUID()}${extension}`);
|
|
54
54
|
try {
|
|
55
|
-
writeFileSync(tmpFile, initialText, "utf8");
|
|
55
|
+
writeFileSync(tmpFile, initialText, { encoding: "utf8", mode: 0o600, flag: "wx" });
|
|
56
56
|
const result = runEditor(command, tmpFile);
|
|
57
57
|
if (result.error) return { ok: false, error: result.error.message };
|
|
58
58
|
if (result.status !== 0) return { ok: false, error: `external editor exited with code ${result.status ?? "?"}` };
|
|
@@ -22,6 +22,7 @@ const HOT_RELOAD_FIELDS = new Set<string>([
|
|
|
22
22
|
"interface.keybindings",
|
|
23
23
|
"safety.autonomy",
|
|
24
24
|
"chat.modelPicker",
|
|
25
|
+
"interface.outputDetail",
|
|
25
26
|
"interface.smoothStreaming",
|
|
26
27
|
"interface.panes.notifications",
|
|
27
28
|
"integrations.git.commitAttribution",
|
|
@@ -49,7 +50,6 @@ const NEXT_TURN_FIELDS = new Set<string>([
|
|
|
49
50
|
"fleet.history",
|
|
50
51
|
"context",
|
|
51
52
|
"safety.limits",
|
|
52
|
-
"interface.outputDetail",
|
|
53
53
|
"interface.terminalProgress",
|
|
54
54
|
"interface.desktopNotifications",
|
|
55
55
|
"integrations.projectResources",
|
|
@@ -19,6 +19,7 @@ import { TUI_KEYBINDINGS } from "../../engine/tui.js";
|
|
|
19
19
|
* live in `resolveCtrlCAction` and are not a simple keybinding.
|
|
20
20
|
*/
|
|
21
21
|
export interface ClioAppKeybindings {
|
|
22
|
+
"clio-coder.output.cycle": true;
|
|
22
23
|
"clio-coder.thinking.cycle": true;
|
|
23
24
|
"clio-coder.exit": true;
|
|
24
25
|
"clio-coder.status.toggle": true;
|
|
@@ -31,11 +32,6 @@ export interface ClioAppKeybindings {
|
|
|
31
32
|
"clio-coder.model.select": true;
|
|
32
33
|
"clio-coder.model.cycleForward": true;
|
|
33
34
|
"clio-coder.model.cycleBackward": true;
|
|
34
|
-
"clio-coder.tool.expand": true;
|
|
35
|
-
"clio-coder.tool.expandAll": true;
|
|
36
|
-
"clio-coder.tool.liveOutput": true;
|
|
37
|
-
"clio-coder.thinking.expand": true;
|
|
38
|
-
"clio-coder.thinking.expandAll": true;
|
|
39
35
|
"clio-coder.editor.external": true;
|
|
40
36
|
"clio-coder.message.followUp": true;
|
|
41
37
|
"clio-coder.message.interrupt": true;
|
|
@@ -128,33 +124,9 @@ export const CLIO_APP_KEYBINDINGS = {
|
|
|
128
124
|
defaultKeys: "alt+k",
|
|
129
125
|
description: "Cycle to previous scoped model",
|
|
130
126
|
},
|
|
131
|
-
"clio-coder.
|
|
127
|
+
"clio-coder.output.cycle": {
|
|
132
128
|
defaultKeys: "alt+o",
|
|
133
|
-
description:
|
|
134
|
-
"Fold or unfold the newest tool call or worker block between its one-line summary and full details, overriding the /output level for that block",
|
|
135
|
-
},
|
|
136
|
-
"clio-coder.tool.expandAll": {
|
|
137
|
-
// Alt+Shift+letter is commonly consumed by OS keyboard-layout switching.
|
|
138
|
-
// Keep it discoverable, but pair it with the legacy-safe Ctrl+Alt form.
|
|
139
|
-
defaultKeys: ["ctrl+alt+o", "alt+shift+o"],
|
|
140
|
-
description:
|
|
141
|
-
"Fold or unfold every tool call and worker block at once, overriding the /output level; changing /output clears the overrides",
|
|
142
|
-
},
|
|
143
|
-
"clio-coder.tool.liveOutput": {
|
|
144
|
-
defaultKeys: "alt+p",
|
|
145
|
-
description: "Toggle streaming partial tool output in expanded tool bodies",
|
|
146
|
-
},
|
|
147
|
-
"clio-coder.thinking.expand": {
|
|
148
|
-
defaultKeys: "alt+r",
|
|
149
|
-
description:
|
|
150
|
-
"Toggle the latest thinking block between hidden marker and full body (no effect while /output verbose pins it open)",
|
|
151
|
-
},
|
|
152
|
-
"clio-coder.thinking.expandAll": {
|
|
153
|
-
// Ctrl+Alt+R is the fallback for terminals/OSes that do not forward
|
|
154
|
-
// Alt+Shift+R as a distinct key event.
|
|
155
|
-
defaultKeys: ["ctrl+alt+r", "alt+shift+r"],
|
|
156
|
-
description:
|
|
157
|
-
"Toggle all thinking blocks between hidden markers and full bodies, overriding the /output level; changing /output clears the overrides",
|
|
129
|
+
description: "Cycle output style: Compact, Standard, Detailed",
|
|
158
130
|
},
|
|
159
131
|
"clio-coder.editor.external": {
|
|
160
132
|
defaultKeys: "alt+g",
|
|
@@ -3,11 +3,15 @@ export interface NativeRuntimeFingerprint {
|
|
|
3
3
|
displayName: string;
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
-
async function fetchWithTimeout(
|
|
6
|
+
async function fetchWithTimeout(
|
|
7
|
+
url: string,
|
|
8
|
+
timeoutMs: number,
|
|
9
|
+
headers: Record<string, string>,
|
|
10
|
+
): Promise<Response | null> {
|
|
7
11
|
const controller = new AbortController();
|
|
8
12
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
9
13
|
try {
|
|
10
|
-
return await fetch(url, { signal: controller.signal });
|
|
14
|
+
return await fetch(url, { signal: controller.signal, headers });
|
|
11
15
|
} catch {
|
|
12
16
|
return null;
|
|
13
17
|
} finally {
|
|
@@ -22,10 +26,13 @@ async function fetchWithTimeout(url: string, timeoutMs: number): Promise<Respons
|
|
|
22
26
|
* by doctor + configure wizard to steer users onto native runtimes for
|
|
23
27
|
* resident-model lifecycle.
|
|
24
28
|
*/
|
|
25
|
-
export async function fingerprintNativeRuntime(
|
|
29
|
+
export async function fingerprintNativeRuntime(
|
|
30
|
+
baseUrl: string,
|
|
31
|
+
headers: Record<string, string> = {},
|
|
32
|
+
): Promise<NativeRuntimeFingerprint | null> {
|
|
26
33
|
const normalized = baseUrl.replace(/^ws:/u, "http:").replace(/^wss:/u, "https:");
|
|
27
34
|
const trimmed = normalized.endsWith("/") ? normalized.slice(0, -1) : normalized;
|
|
28
|
-
const greeting = await fetchWithTimeout(`${trimmed}/lmstudio-greeting`, 750);
|
|
35
|
+
const greeting = await fetchWithTimeout(`${trimmed}/lmstudio-greeting`, 750, headers);
|
|
29
36
|
if (greeting?.ok) {
|
|
30
37
|
try {
|
|
31
38
|
const data = (await greeting.json()) as { lmstudio?: unknown };
|
|
@@ -34,7 +41,7 @@ export async function fingerprintNativeRuntime(baseUrl: string): Promise<NativeR
|
|
|
34
41
|
// The exact JSON body is the fingerprint.
|
|
35
42
|
}
|
|
36
43
|
}
|
|
37
|
-
const lmStudioV0 = await fetchWithTimeout(`${trimmed}/api/v0/models`, 750);
|
|
44
|
+
const lmStudioV0 = await fetchWithTimeout(`${trimmed}/api/v0/models`, 750, headers);
|
|
38
45
|
if (lmStudioV0?.ok) {
|
|
39
46
|
try {
|
|
40
47
|
const data = (await lmStudioV0.json()) as { data?: unknown };
|
|
@@ -48,7 +55,7 @@ export async function fingerprintNativeRuntime(baseUrl: string): Promise<NativeR
|
|
|
48
55
|
// A malformed v0 body is not an LM Studio fingerprint.
|
|
49
56
|
}
|
|
50
57
|
}
|
|
51
|
-
const ollama = await fetchWithTimeout(`${trimmed}/api/version`, 750);
|
|
58
|
+
const ollama = await fetchWithTimeout(`${trimmed}/api/version`, 750, headers);
|
|
52
59
|
if (ollama?.ok) {
|
|
53
60
|
try {
|
|
54
61
|
const data = (await ollama.json()) as { version?: unknown };
|
|
@@ -19,6 +19,7 @@ export interface ProbeReasoningOptions {
|
|
|
19
19
|
modelId: string;
|
|
20
20
|
timeoutMs: number;
|
|
21
21
|
apiKey?: string;
|
|
22
|
+
headers?: Record<string, string>;
|
|
22
23
|
signal?: AbortSignal;
|
|
23
24
|
}
|
|
24
25
|
|
|
@@ -72,6 +73,7 @@ export async function probeOpenAICompatReasoning(opts: ProbeReasoningOptions): P
|
|
|
72
73
|
|
|
73
74
|
const headers: Record<string, string> = { "content-type": "application/json" };
|
|
74
75
|
if (opts.apiKey && opts.apiKey.length > 0) headers.authorization = `Bearer ${opts.apiKey}`;
|
|
76
|
+
Object.assign(headers, opts.headers);
|
|
75
77
|
|
|
76
78
|
const body = JSON.stringify({
|
|
77
79
|
model: opts.modelId,
|
|
@@ -8,13 +8,27 @@ export interface OpenAIModelsResponse {
|
|
|
8
8
|
data?: Array<Record<string, unknown> & { id?: unknown; status?: unknown }>;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
function bearerHeaders(ctx: ProbeContext): Record<string, string> {
|
|
12
|
+
return ctx.authToken ? { Authorization: `Bearer ${ctx.authToken}` } : {};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function probeUrl(
|
|
16
|
+
url: string,
|
|
17
|
+
ctx: ProbeContext,
|
|
18
|
+
method: "GET" | "HEAD" = "GET",
|
|
19
|
+
headers: Record<string, string> = bearerHeaders(ctx),
|
|
20
|
+
): Promise<ProbeResult> {
|
|
21
|
+
const base = { url, timeoutMs: ctx.httpTimeoutMs, method, headers } as const;
|
|
13
22
|
return ctx.signal ? probeHttp({ ...base, signal: ctx.signal }) : probeHttp(base);
|
|
14
23
|
}
|
|
15
24
|
|
|
16
|
-
export async function probeOpenAIModels(
|
|
17
|
-
|
|
25
|
+
export async function probeOpenAIModels(
|
|
26
|
+
base: string,
|
|
27
|
+
ctx: ProbeContext,
|
|
28
|
+
modelsPath = "/v1/models",
|
|
29
|
+
headers: Record<string, string> = bearerHeaders(ctx),
|
|
30
|
+
): Promise<string[]> {
|
|
31
|
+
return (await probeOpenAIModelCatalog(base, ctx, modelsPath, headers)).models;
|
|
18
32
|
}
|
|
19
33
|
|
|
20
34
|
export interface OpenAIModelCatalogProbe {
|
|
@@ -38,11 +52,12 @@ async function probeModelDetailRows(
|
|
|
38
52
|
base: string,
|
|
39
53
|
ctx: ProbeContext,
|
|
40
54
|
modelsPath: string,
|
|
55
|
+
headers: Record<string, string>,
|
|
41
56
|
): Promise<Map<string, Record<string, unknown>>> {
|
|
42
57
|
const rows = new Map<string, Record<string, unknown>>();
|
|
43
58
|
for (const detailPath of OPENAI_COMPAT_DETAIL_PATHS) {
|
|
44
59
|
if (detailPath === modelsPath) continue;
|
|
45
|
-
const opts = { url: `${base}${detailPath}`, timeoutMs: ctx.httpTimeoutMs } as const;
|
|
60
|
+
const opts = { url: `${base}${detailPath}`, timeoutMs: ctx.httpTimeoutMs, headers } as const;
|
|
46
61
|
const result = await (ctx.signal
|
|
47
62
|
? probeJson<OpenAIModelsResponse>({ ...opts, signal: ctx.signal })
|
|
48
63
|
: probeJson<OpenAIModelsResponse>(opts));
|
|
@@ -60,13 +75,14 @@ export async function probeOpenAIModelCatalog(
|
|
|
60
75
|
base: string,
|
|
61
76
|
ctx: ProbeContext,
|
|
62
77
|
modelsPath = "/v1/models",
|
|
78
|
+
headers: Record<string, string> = bearerHeaders(ctx),
|
|
63
79
|
): Promise<OpenAIModelCatalogProbe> {
|
|
64
|
-
const opts = { url: `${base}${modelsPath}`, timeoutMs: ctx.httpTimeoutMs } as const;
|
|
80
|
+
const opts = { url: `${base}${modelsPath}`, timeoutMs: ctx.httpTimeoutMs, headers } as const;
|
|
65
81
|
const result = await (ctx.signal
|
|
66
82
|
? probeJson<OpenAIModelsResponse>({ ...opts, signal: ctx.signal })
|
|
67
83
|
: probeJson<OpenAIModelsResponse>(opts));
|
|
68
84
|
if (!result.ok || !result.data?.data) return { models: [], modelCapabilities: {}, modelStates: {} };
|
|
69
|
-
const detail = await probeModelDetailRows(base, ctx, modelsPath);
|
|
85
|
+
const detail = await probeModelDetailRows(base, ctx, modelsPath, headers);
|
|
70
86
|
const models: string[] = [];
|
|
71
87
|
const modelCapabilities: Record<string, Partial<CapabilityFlags>> = {};
|
|
72
88
|
const modelStates: Record<string, ProbeModelStatus> = {};
|
|
@@ -49,6 +49,11 @@ function synthesizeAnthropicCompatModel(input: AnthropicCompatSynthesisInput): M
|
|
|
49
49
|
export function makeAnthropicCompatRuntime(spec: AnthropicCompatSpec): RuntimeDescriptor {
|
|
50
50
|
const messagesPath = spec.messagesPath ?? "/v1/messages";
|
|
51
51
|
const modelsPath = spec.modelsPath ?? "/v1/models";
|
|
52
|
+
const headers = (target: TargetDescriptor, ctx: ProbeContext): Record<string, string> => ({
|
|
53
|
+
"anthropic-version": "2023-06-01",
|
|
54
|
+
...(ctx.authToken ? { "x-api-key": ctx.authToken } : {}),
|
|
55
|
+
...target.auth?.headers,
|
|
56
|
+
});
|
|
52
57
|
return {
|
|
53
58
|
id: spec.id,
|
|
54
59
|
displayName: spec.displayName,
|
|
@@ -61,12 +66,12 @@ export function makeAnthropicCompatRuntime(spec: AnthropicCompatSpec): RuntimeDe
|
|
|
61
66
|
async probe(target: TargetDescriptor, ctx: ProbeContext): Promise<ProbeResult> {
|
|
62
67
|
const base = targetBaseUrl(target);
|
|
63
68
|
if (!base) return { ok: false, error: "target has no url" };
|
|
64
|
-
return probeUrl(`${base}${messagesPath}`, ctx, "HEAD");
|
|
69
|
+
return probeUrl(`${base}${messagesPath}`, ctx, "HEAD", headers(target, ctx));
|
|
65
70
|
},
|
|
66
71
|
async probeModels(target: TargetDescriptor, ctx: ProbeContext): Promise<string[]> {
|
|
67
72
|
const base = targetBaseUrl(target);
|
|
68
73
|
if (!base) return [];
|
|
69
|
-
return probeOpenAIModels(base, ctx, modelsPath);
|
|
74
|
+
return probeOpenAIModels(base, ctx, modelsPath, headers(target, ctx));
|
|
70
75
|
},
|
|
71
76
|
synthesizeModel(target: TargetDescriptor, wireModelId: string, kb: KnowledgeBaseHit | null): Model<Api> {
|
|
72
77
|
return synthesizeAnthropicCompatModel({
|
|
@@ -61,6 +61,10 @@ export function makeOpenAICompatRuntime(spec: OpenAICompatSpec): RuntimeDescript
|
|
|
61
61
|
// root and a target naming the `/v1` mount point has to be reduced to it. An
|
|
62
62
|
// `asIs` spec sends the URL verbatim, so it keeps whatever the user typed.
|
|
63
63
|
const probeBase = asIs ? targetBaseUrl : targetRootUrl;
|
|
64
|
+
const headers = (target: TargetDescriptor, ctx: ProbeContext): Record<string, string> => ({
|
|
65
|
+
...(ctx.authToken ? { Authorization: `Bearer ${ctx.authToken}` } : {}),
|
|
66
|
+
...target.auth?.headers,
|
|
67
|
+
});
|
|
64
68
|
return {
|
|
65
69
|
id: spec.id,
|
|
66
70
|
displayName: spec.displayName,
|
|
@@ -72,9 +76,9 @@ export function makeOpenAICompatRuntime(spec: OpenAICompatSpec): RuntimeDescript
|
|
|
72
76
|
async probe(target: TargetDescriptor, ctx: ProbeContext): Promise<ProbeResult> {
|
|
73
77
|
const base = probeBase(target);
|
|
74
78
|
if (!base) return { ok: false, error: "target has no url" };
|
|
75
|
-
const health = await probeUrl(`${base}${healthPath}`, ctx);
|
|
79
|
+
const health = await probeUrl(`${base}${healthPath}`, ctx, "GET", headers(target, ctx));
|
|
76
80
|
if (!health.ok) return health;
|
|
77
|
-
const catalog = await probeOpenAIModelCatalog(base, ctx, modelsPath);
|
|
81
|
+
const catalog = await probeOpenAIModelCatalog(base, ctx, modelsPath, headers(target, ctx));
|
|
78
82
|
const result: ProbeResult = { ...health };
|
|
79
83
|
if (catalog.models.length > 0) result.models = catalog.models;
|
|
80
84
|
if (Object.keys(catalog.modelStates).length > 0) result.modelStates = catalog.modelStates;
|
|
@@ -92,19 +96,21 @@ export function makeOpenAICompatRuntime(spec: OpenAICompatSpec): RuntimeDescript
|
|
|
92
96
|
async probeModels(target: TargetDescriptor, ctx: ProbeContext): Promise<string[]> {
|
|
93
97
|
const base = probeBase(target);
|
|
94
98
|
if (!base) return [];
|
|
95
|
-
return probeOpenAIModels(base, ctx, modelsPath);
|
|
99
|
+
return probeOpenAIModels(base, ctx, modelsPath, headers(target, ctx));
|
|
96
100
|
},
|
|
97
101
|
async probeReasoning(target: TargetDescriptor, modelId: string, ctx: ProbeContext): Promise<ReasoningProbeResult> {
|
|
98
102
|
const base = probeBase(target);
|
|
99
103
|
if (!base) return { reasoning: false, latencyMs: 0, error: "target has no url" };
|
|
100
104
|
const apiKeyEnv = target.auth?.apiKeyEnvVar;
|
|
101
|
-
const apiKey =
|
|
105
|
+
const apiKey =
|
|
106
|
+
ctx.authToken ?? (apiKeyEnv && ctx.credentialsPresent.has(apiKeyEnv) ? process.env[apiKeyEnv] : undefined);
|
|
102
107
|
const probeOpts: Parameters<typeof probeOpenAICompatReasoning>[0] = {
|
|
103
108
|
baseUrl: base,
|
|
104
109
|
modelId,
|
|
105
110
|
timeoutMs: Math.max(ctx.httpTimeoutMs, 8000),
|
|
106
111
|
};
|
|
107
112
|
if (apiKey) probeOpts.apiKey = apiKey;
|
|
113
|
+
if (target.auth?.headers) probeOpts.headers = target.auth.headers;
|
|
108
114
|
if (ctx.signal) probeOpts.signal = ctx.signal;
|
|
109
115
|
return probeOpenAICompatReasoning(probeOpts);
|
|
110
116
|
},
|
|
@@ -6,16 +6,12 @@ import { isEscapeKey, type OverlayState, overlayOwnsInput } from "./overlay-life
|
|
|
6
6
|
export const APPLICATION_DOUBLE_TAP_MS = 500;
|
|
7
7
|
|
|
8
8
|
const CLOSED_ACTION_ORDER = [
|
|
9
|
+
"clio-coder.output.cycle",
|
|
9
10
|
"clio-coder.notifications.dismiss",
|
|
10
|
-
"clio-coder.tool.expand",
|
|
11
|
-
"clio-coder.tool.expandAll",
|
|
12
|
-
"clio-coder.tool.liveOutput",
|
|
13
11
|
"clio-coder.editor.external",
|
|
14
12
|
"clio-coder.message.followUp",
|
|
15
13
|
"clio-coder.message.interrupt",
|
|
16
14
|
"clio-coder.message.dequeue",
|
|
17
|
-
"clio-coder.thinking.expand",
|
|
18
|
-
"clio-coder.thinking.expandAll",
|
|
19
15
|
] as const satisfies ReadonlyArray<ClioKeybinding>;
|
|
20
16
|
|
|
21
17
|
export const GLOBAL_ACTION_ORDER = [
|
|
@@ -108,10 +104,6 @@ export interface ApplicationControllerDeps {
|
|
|
108
104
|
listNotifications: () => ReadonlyArray<{ id: string }>;
|
|
109
105
|
dismissNotification: (id: string) => void;
|
|
110
106
|
dismissAllNotifications: () => void;
|
|
111
|
-
toggleLastToolExpanded: () => boolean;
|
|
112
|
-
toggleAllToolsExpanded: () => boolean;
|
|
113
|
-
toggleLastThinking: () => boolean;
|
|
114
|
-
toggleAllThinking: () => boolean;
|
|
115
107
|
shutdownDisposers: ReadonlyArray<() => void>;
|
|
116
108
|
/** Settle the last presentation mutation into an accepted/drained frame. */
|
|
117
109
|
beforeStopUi?: () => Promise<void>;
|
|
@@ -145,8 +137,6 @@ export interface ApplicationController {
|
|
|
145
137
|
handleInput(data: string): ApplicationInputResult;
|
|
146
138
|
handleCtrlC(): void;
|
|
147
139
|
dismissNotifications(): void;
|
|
148
|
-
toggleToolExpansion(): void;
|
|
149
|
-
toggleThinkingExpansion(): void;
|
|
150
140
|
shutdown(): Promise<void>;
|
|
151
141
|
}
|
|
152
142
|
|
|
@@ -163,8 +153,6 @@ export function createApplicationController(deps: ApplicationControllerDeps): Ap
|
|
|
163
153
|
let shuttingDown = false;
|
|
164
154
|
let lastCtrlCAt = 0;
|
|
165
155
|
let lastNotificationDismissAt = 0;
|
|
166
|
-
let lastToolExpandAt = 0;
|
|
167
|
-
let lastThinkingExpandAt = 0;
|
|
168
156
|
|
|
169
157
|
const isDoubleTap = (lastAt: number, now: number): boolean => lastAt > 0 && now - lastAt <= APPLICATION_DOUBLE_TAP_MS;
|
|
170
158
|
|
|
@@ -346,22 +334,6 @@ export function createApplicationController(deps: ApplicationControllerDeps): Ap
|
|
|
346
334
|
if (first) deps.dismissNotification(first.id);
|
|
347
335
|
};
|
|
348
336
|
|
|
349
|
-
const toggleToolExpansion = (): void => {
|
|
350
|
-
const now = deps.clock.now();
|
|
351
|
-
const doubleTap = isDoubleTap(lastToolExpandAt, now);
|
|
352
|
-
lastToolExpandAt = now;
|
|
353
|
-
const changed = doubleTap ? deps.toggleAllToolsExpanded() : deps.toggleLastToolExpanded();
|
|
354
|
-
if (changed) deps.requestRender();
|
|
355
|
-
};
|
|
356
|
-
|
|
357
|
-
const toggleThinkingExpansion = (): void => {
|
|
358
|
-
const now = deps.clock.now();
|
|
359
|
-
const doubleTap = isDoubleTap(lastThinkingExpandAt, now);
|
|
360
|
-
lastThinkingExpandAt = now;
|
|
361
|
-
const changed = doubleTap ? deps.toggleAllThinking() : deps.toggleLastThinking();
|
|
362
|
-
if (changed) deps.requestRender();
|
|
363
|
-
};
|
|
364
|
-
|
|
365
337
|
const handleInput = (data: string): ApplicationInputResult => {
|
|
366
338
|
const initialOverlayState = deps.getOverlayState();
|
|
367
339
|
if (overlayOwnsInput(initialOverlayState) && deps.leaderKeys.isPending()) deps.leaderKeys.reset();
|
|
@@ -427,8 +399,6 @@ export function createApplicationController(deps: ApplicationControllerDeps): Ap
|
|
|
427
399
|
handleInput,
|
|
428
400
|
handleCtrlC,
|
|
429
401
|
dismissNotifications,
|
|
430
|
-
toggleToolExpansion,
|
|
431
|
-
toggleThinkingExpansion,
|
|
432
402
|
shutdown,
|
|
433
403
|
};
|
|
434
404
|
}
|