@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
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { createRequire as __clioCreateRequire } from "node:module"; const require = __clioCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
editTextExternally,
|
|
4
|
+
resolveExternalEditor
|
|
5
|
+
} from "./chunk-R2CT5YDO.js";
|
|
2
6
|
import {
|
|
3
7
|
createDelayedManualCodeInput,
|
|
4
8
|
promptOAuthSelection
|
|
5
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-LK2FN5JY.js";
|
|
6
10
|
import {
|
|
7
11
|
createLifecyclePresenter,
|
|
8
12
|
shortenPath
|
|
9
13
|
} from "./chunk-6YA46L5A.js";
|
|
10
14
|
import {
|
|
11
15
|
fingerprintNativeRuntime
|
|
12
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-QJMRYTCX.js";
|
|
13
17
|
import {
|
|
14
18
|
INHERITED_PROJECT_CONTEXT,
|
|
15
19
|
acceptInteropAgents,
|
|
@@ -18,10 +22,10 @@ import {
|
|
|
18
22
|
interopProposals,
|
|
19
23
|
renderProposalEntry,
|
|
20
24
|
resolveOnPath
|
|
21
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-B3MOMLJ4.js";
|
|
22
26
|
import {
|
|
23
27
|
initializeClioHome
|
|
24
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-6VRRJT7L.js";
|
|
25
29
|
import {
|
|
26
30
|
column,
|
|
27
31
|
terminalColumns,
|
|
@@ -43,17 +47,24 @@ import {
|
|
|
43
47
|
probeCapabilitiesForModel,
|
|
44
48
|
readTargetModelSnapshot,
|
|
45
49
|
recordTargetModelSnapshot
|
|
46
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-4U4TKZFR.js";
|
|
47
51
|
import {
|
|
48
52
|
credentialsPresent
|
|
49
53
|
} from "./chunk-J2FYEQ5L.js";
|
|
50
54
|
import {
|
|
55
|
+
AUTONOMY_LEVELS
|
|
56
|
+
} from "./chunk-EM2WNQS2.js";
|
|
57
|
+
import {
|
|
58
|
+
SettingsValidationError,
|
|
51
59
|
bindAgentProfileInSettings,
|
|
52
60
|
readSettings,
|
|
53
61
|
removeTargetFromSettings,
|
|
54
62
|
settingsPath,
|
|
55
|
-
|
|
56
|
-
|
|
63
|
+
updateSavedSettingsDocument,
|
|
64
|
+
updateSettings,
|
|
65
|
+
validateSettings,
|
|
66
|
+
withSettingsLock
|
|
67
|
+
} from "./chunk-WNGF5AJX.js";
|
|
57
68
|
import {
|
|
58
69
|
warnLegacyNaming
|
|
59
70
|
} from "./chunk-DVNAPPXU.js";
|
|
@@ -62,11 +73,14 @@ import {
|
|
|
62
73
|
} from "./chunk-GD55RTIW.js";
|
|
63
74
|
import {
|
|
64
75
|
greetLmStudio,
|
|
65
|
-
|
|
66
|
-
|
|
76
|
+
probeJson,
|
|
77
|
+
registerBuiltinRuntimes,
|
|
78
|
+
targetRootUrl
|
|
79
|
+
} from "./chunk-WV6TDAPN.js";
|
|
67
80
|
import {
|
|
81
|
+
DEFAULT_SETTINGS_YAML,
|
|
68
82
|
THINKING_LEVELS
|
|
69
|
-
} from "./chunk-
|
|
83
|
+
} from "./chunk-3BJGMT2D.js";
|
|
70
84
|
import {
|
|
71
85
|
buildProviderSupportEntry,
|
|
72
86
|
configuredTargetsForRuntime,
|
|
@@ -83,6 +97,12 @@ import {
|
|
|
83
97
|
resolveRuntimeAuthTarget,
|
|
84
98
|
targetRequiresAuth
|
|
85
99
|
} from "./chunk-HXHFDHB6.js";
|
|
100
|
+
import {
|
|
101
|
+
require_dist
|
|
102
|
+
} from "./chunk-B5GGDIHT.js";
|
|
103
|
+
import {
|
|
104
|
+
safeResourceWrite
|
|
105
|
+
} from "./chunk-ZZFWWYLX.js";
|
|
86
106
|
import {
|
|
87
107
|
getRuntimeRegistry
|
|
88
108
|
} from "./chunk-SRCEQKQS.js";
|
|
@@ -93,18 +113,19 @@ import {
|
|
|
93
113
|
resolveClioDirs
|
|
94
114
|
} from "./chunk-CTTI7G3T.js";
|
|
95
115
|
import {
|
|
116
|
+
__toESM,
|
|
96
117
|
init_esm_shims
|
|
97
118
|
} from "./chunk-ECBHH7LU.js";
|
|
98
119
|
|
|
99
120
|
// src/cli/configure.ts
|
|
100
121
|
init_esm_shims();
|
|
101
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
122
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
102
123
|
import { stdin as input, stdout as output2 } from "node:process";
|
|
103
|
-
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
104
124
|
|
|
105
125
|
// src/cli/ask.ts
|
|
106
126
|
init_esm_shims();
|
|
107
127
|
async function ask(rl, label, defaultValue) {
|
|
128
|
+
if (rl.text) return rl.text(label, defaultValue);
|
|
108
129
|
const suffix = defaultValue && defaultValue.length > 0 ? ` [${defaultValue}]` : "";
|
|
109
130
|
try {
|
|
110
131
|
const answer = (await rl.question(`${label}${suffix}: `)).trim();
|
|
@@ -116,6 +137,7 @@ async function ask(rl, label, defaultValue) {
|
|
|
116
137
|
}
|
|
117
138
|
}
|
|
118
139
|
async function askYesNo(rl, label, defaultValue) {
|
|
140
|
+
if (rl.choose && rl.interactive) return await rl.choose(label, ["yes", "no"], defaultValue ? "yes" : "no") === "yes";
|
|
119
141
|
const marker = defaultValue ? "Y/n" : "y/N";
|
|
120
142
|
for (; ; ) {
|
|
121
143
|
const answer = await ask(rl, `${label} [${marker}]`);
|
|
@@ -129,6 +151,53 @@ async function askYesNo(rl, label, defaultValue) {
|
|
|
129
151
|
}
|
|
130
152
|
}
|
|
131
153
|
|
|
154
|
+
// src/cli/configure-editor.ts
|
|
155
|
+
init_esm_shims();
|
|
156
|
+
var import_yaml = __toESM(require_dist(), 1);
|
|
157
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
158
|
+
async function editSettings(prompts) {
|
|
159
|
+
const file = settingsPath();
|
|
160
|
+
const original = existsSync(file) ? readFileSync(file, "utf8") : null;
|
|
161
|
+
let draft = original ?? DEFAULT_SETTINGS_YAML;
|
|
162
|
+
const editor = resolveExternalEditor();
|
|
163
|
+
for (; ; ) {
|
|
164
|
+
const result = editTextExternally(draft, editor, ".yaml");
|
|
165
|
+
if (!result.ok || result.text === void 0) throw new Error(result.error ?? "Editor did not return a draft");
|
|
166
|
+
draft = `${result.text}
|
|
167
|
+
`;
|
|
168
|
+
if (draft === original) {
|
|
169
|
+
prompts.output.write("Settings unchanged.\n");
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
try {
|
|
173
|
+
const validated = validateSettings((0, import_yaml.parse)(draft));
|
|
174
|
+
if (validated.issues.length) throw new SettingsValidationError(validated.issues);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
prompts.output.write(`${error instanceof Error ? error.message : String(error)}
|
|
177
|
+
`);
|
|
178
|
+
if (await prompts.choose("Invalid draft", ["Return to editor", "Discard draft"], "Return to editor") === "Return to editor")
|
|
179
|
+
continue;
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
const choice = await prompts.choose(
|
|
183
|
+
"Save validated settings?",
|
|
184
|
+
["Save", "Return to editor", "Discard draft"],
|
|
185
|
+
"Save"
|
|
186
|
+
);
|
|
187
|
+
if (choice === "Return to editor") continue;
|
|
188
|
+
if (choice !== "Save") return false;
|
|
189
|
+
withSettingsLock(() => {
|
|
190
|
+
const current = existsSync(file) ? readFileSync(file, "utf8") : null;
|
|
191
|
+
if (current !== original)
|
|
192
|
+
throw new Error("Settings changed while the editor was open. Reopen the editor to keep those changes.");
|
|
193
|
+
safeResourceWrite(file, draft, { encoding: "utf8", mode: 420, backup: original !== null });
|
|
194
|
+
});
|
|
195
|
+
prompts.output.write(`Settings saved to ${file}${original === null ? "" : `; previous file: ${file}.bak`}
|
|
196
|
+
`);
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
132
201
|
// src/cli/configure-interop.ts
|
|
133
202
|
init_esm_shims();
|
|
134
203
|
import { stdout as output } from "node:process";
|
|
@@ -226,6 +295,13 @@ function deriveTargetId(runtimeId, existing) {
|
|
|
226
295
|
}
|
|
227
296
|
return `${base}-${Date.now()}`;
|
|
228
297
|
}
|
|
298
|
+
function targetApiKeyRef(targetId, targets) {
|
|
299
|
+
const taken = new Set(targets.filter((target) => target.id !== targetId).map((target) => target.auth?.apiKeyRef));
|
|
300
|
+
const base = `target:${targetId}`;
|
|
301
|
+
let ref = base;
|
|
302
|
+
for (let suffix = 2; taken.has(ref); suffix += 1) ref = `${base}-${suffix}`;
|
|
303
|
+
return ref;
|
|
304
|
+
}
|
|
229
305
|
async function buildProbeContext(runtime, target) {
|
|
230
306
|
const probeCtx = {
|
|
231
307
|
credentialsPresent: credentialsPresent(),
|
|
@@ -459,8 +535,11 @@ function buildDescriptor(runtime, id, parts) {
|
|
|
459
535
|
if (parts.litellm) descriptor.litellm = parts.litellm;
|
|
460
536
|
return descriptor;
|
|
461
537
|
}
|
|
462
|
-
function describeAuthStatus(runtime) {
|
|
463
|
-
const status = openAuthStorage().statusForTarget(
|
|
538
|
+
function describeAuthStatus(runtime, target) {
|
|
539
|
+
const status = openAuthStorage().statusForTarget(
|
|
540
|
+
target ? resolveAuthTarget(target, runtime) : resolveRuntimeAuthTarget(runtime),
|
|
541
|
+
{ includeFallback: false }
|
|
542
|
+
);
|
|
464
543
|
if (!status.available) return "none stored";
|
|
465
544
|
if (status.source === "environment") return `environment${status.detail ? ` (${status.detail})` : ""}`;
|
|
466
545
|
if (status.source === "stored-api-key") return "stored api key";
|
|
@@ -647,7 +726,7 @@ function viewportFor(output3, overhead, total, requested) {
|
|
|
647
726
|
async function promptSelect(options) {
|
|
648
727
|
const input2 = options.input ?? process.stdin;
|
|
649
728
|
const output3 = options.output ?? process.stdout;
|
|
650
|
-
|
|
729
|
+
let choices = options.choices;
|
|
651
730
|
if (choices.length === 0) return { kind: "back" };
|
|
652
731
|
const rail = options.railPrefix ?? "";
|
|
653
732
|
const railWidth = 3;
|
|
@@ -655,14 +734,24 @@ async function promptSelect(options) {
|
|
|
655
734
|
const frame = makeFrame(output3);
|
|
656
735
|
let index = Math.min(Math.max(options.initialIndex ?? 0, 0), choices.length - 1);
|
|
657
736
|
let windowStart = 0;
|
|
737
|
+
let query = "";
|
|
738
|
+
const filter = () => {
|
|
739
|
+
choices = options.choices.filter((choice) => choice.label.toLowerCase().includes(query.toLowerCase()));
|
|
740
|
+
index = 0;
|
|
741
|
+
windowStart = 0;
|
|
742
|
+
render();
|
|
743
|
+
};
|
|
658
744
|
const render = () => {
|
|
659
|
-
const viewport = viewportFor(output3, head.length + 5, choices.length, options.maxVisible);
|
|
745
|
+
const viewport = viewportFor(output3, head.length + (options.searchable ? 6 : 5), choices.length, options.maxVisible);
|
|
660
746
|
if (index < windowStart) windowStart = index;
|
|
661
747
|
else if (index >= windowStart + viewport) windowStart = index - viewport + 1;
|
|
662
748
|
windowStart = Math.max(0, Math.min(windowStart, choices.length - viewport));
|
|
663
749
|
const lines = [];
|
|
664
750
|
for (const line of head) lines.push(`${rail}${line}`.trimEnd());
|
|
665
751
|
if (head.length > 0) lines.push(rail.trimEnd());
|
|
752
|
+
if (options.searchable)
|
|
753
|
+
lines.push(`${rail}${truncate(`Filter: ${query || "(type to search)"}`, terminalColumns(output3) - railWidth)}`);
|
|
754
|
+
if (choices.length === 0) lines.push(`${rail}No matching models`);
|
|
666
755
|
lines.push(
|
|
667
756
|
...choiceRows(
|
|
668
757
|
{
|
|
@@ -681,7 +770,8 @@ async function promptSelect(options) {
|
|
|
681
770
|
lines.push(rail.trimEnd());
|
|
682
771
|
const legend = ["\u2191/\u2193 move", "enter select"];
|
|
683
772
|
if (options.backLabel !== void 0 && options.backLabel !== "quit") legend.push(`esc ${options.backLabel}`);
|
|
684
|
-
legend.push(
|
|
773
|
+
if (options.searchable) legend.push("type to filter", "ctrl-u clear", "ctrl-c quit");
|
|
774
|
+
else legend.push(options.backLabel === "quit" ? "esc or q quit" : "q quit");
|
|
685
775
|
lines.push(`${rail}${source_default.dim(legend.join(" \xB7 "))}`);
|
|
686
776
|
frame.draw(lines);
|
|
687
777
|
};
|
|
@@ -690,11 +780,29 @@ async function promptSelect(options) {
|
|
|
690
780
|
output3,
|
|
691
781
|
true,
|
|
692
782
|
render,
|
|
693
|
-
(
|
|
783
|
+
(str, key, finish2) => {
|
|
694
784
|
if (key.ctrl && (key.name === "c" || key.name === "d")) {
|
|
695
785
|
finish2({ kind: "quit" });
|
|
696
786
|
return;
|
|
697
787
|
}
|
|
788
|
+
if (options.searchable) {
|
|
789
|
+
if (key.ctrl && key.name === "u") {
|
|
790
|
+
query = "";
|
|
791
|
+
filter();
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
794
|
+
if (key.name === "backspace") {
|
|
795
|
+
query = query.slice(0, -1);
|
|
796
|
+
filter();
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
if (!key.ctrl && !key.meta && str?.length === 1 && str >= " " && str !== "\x7F") {
|
|
800
|
+
query += str;
|
|
801
|
+
filter();
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
if (choices.length === 0 && !["escape", "left"].includes(key.name ?? "")) return;
|
|
805
|
+
}
|
|
698
806
|
switch (key.name) {
|
|
699
807
|
case "up":
|
|
700
808
|
case "k":
|
|
@@ -1315,18 +1423,29 @@ function allEntries() {
|
|
|
1315
1423
|
return listProviderSupportEntries(getRuntimeRegistry().list());
|
|
1316
1424
|
}
|
|
1317
1425
|
function draftDescriptor(answers, runtime, withModel) {
|
|
1318
|
-
const apiKeyRef = answers.credential === "stored"
|
|
1319
|
-
|
|
1426
|
+
const apiKeyRef = answers.credential === "stored" ? targetApiKeyRef(answers.targetId ?? runtime.id, readSettings().targets) : answers.credential === "keep" ? answers.existing?.auth?.apiKeyRef ?? runtime.id : void 0;
|
|
1427
|
+
const configured = buildDescriptor(runtime, answers.targetId ?? runtime.id, {
|
|
1320
1428
|
...answers.url !== void 0 ? { url: answers.url } : {},
|
|
1321
1429
|
...withModel && answers.model !== void 0 ? { model: answers.model } : {},
|
|
1322
1430
|
...answers.apiKeyEnv !== void 0 ? { apiKeyEnv: answers.apiKeyEnv } : {},
|
|
1323
1431
|
...apiKeyRef !== void 0 ? { apiKeyRef } : {},
|
|
1324
|
-
...runtime.auth === "oauth" ? { oauthProfile: runtime.oauthProviderId ?? runtime.id } : {}
|
|
1432
|
+
...runtime.auth === "oauth" ? { oauthProfile: answers.existing?.auth?.oauthProfile ?? runtime.oauthProviderId ?? runtime.id } : {}
|
|
1325
1433
|
});
|
|
1434
|
+
const descriptor = { ...answers.existing, ...configured };
|
|
1435
|
+
if (!withModel) delete descriptor.defaultModel;
|
|
1436
|
+
if (answers.existing?.auth || configured.auth) {
|
|
1437
|
+
descriptor.auth = { ...answers.existing?.auth, ...configured.auth };
|
|
1438
|
+
if (runtime.auth === "api-key") {
|
|
1439
|
+
if (answers.credential !== "env") delete descriptor.auth.apiKeyEnvVar;
|
|
1440
|
+
if (answers.credential !== "stored" && answers.credential !== "keep") delete descriptor.auth.apiKeyRef;
|
|
1441
|
+
}
|
|
1442
|
+
if (Object.keys(descriptor.auth).length === 0) delete descriptor.auth;
|
|
1443
|
+
}
|
|
1444
|
+
return descriptor;
|
|
1326
1445
|
}
|
|
1327
1446
|
var CATEGORY_STEP = {
|
|
1328
1447
|
id: "category",
|
|
1329
|
-
applies: () =>
|
|
1448
|
+
applies: (answers) => answers.mode !== "edit" && !answers.fixedRuntime,
|
|
1330
1449
|
run: async (wizard, answers) => {
|
|
1331
1450
|
const current = CONFIGURE_CATEGORY_CHOICES.findIndex((choice2) => choice2.category === answers.category);
|
|
1332
1451
|
const result = await promptSelect({
|
|
@@ -1357,12 +1476,12 @@ var CATEGORY_STEP = {
|
|
|
1357
1476
|
};
|
|
1358
1477
|
var RUNTIME_STEP = {
|
|
1359
1478
|
id: "runtime",
|
|
1360
|
-
applies: () =>
|
|
1479
|
+
applies: (answers) => answers.mode !== "edit" && !answers.fixedRuntime,
|
|
1361
1480
|
run: async (wizard, answers) => {
|
|
1362
1481
|
const registry = getRuntimeRegistry();
|
|
1363
1482
|
const chatEntries = allEntries().filter((entry) => {
|
|
1364
1483
|
const runtime2 = registry.get(entry.runtimeId);
|
|
1365
|
-
return runtime2 !== null && isOrchestratorEligibleRuntime(runtime2);
|
|
1484
|
+
return runtime2 !== null && (answers.mode !== "first" || isOrchestratorEligibleRuntime(runtime2));
|
|
1366
1485
|
});
|
|
1367
1486
|
const entries = answers.category ? runtimesForCategory(chatEntries, answers.category) : chatEntries;
|
|
1368
1487
|
const usable = entries.length > 0 ? entries : chatEntries;
|
|
@@ -1390,6 +1509,9 @@ var RUNTIME_STEP = {
|
|
|
1390
1509
|
answers.apiKeyEnv = void 0;
|
|
1391
1510
|
answers.apiKeyLiteral = void 0;
|
|
1392
1511
|
answers.model = void 0;
|
|
1512
|
+
answers.thinking = void 0;
|
|
1513
|
+
answers.contextWindow = void 0;
|
|
1514
|
+
answers.probe = void 0;
|
|
1393
1515
|
answers.inventory = void 0;
|
|
1394
1516
|
answers.inventoryKey = void 0;
|
|
1395
1517
|
}
|
|
@@ -1400,7 +1522,7 @@ var RUNTIME_STEP = {
|
|
|
1400
1522
|
};
|
|
1401
1523
|
var TARGET_ID_STEP = {
|
|
1402
1524
|
id: "target-id",
|
|
1403
|
-
applies: () =>
|
|
1525
|
+
applies: (answers) => answers.mode !== "edit",
|
|
1404
1526
|
run: async (wizard, answers) => {
|
|
1405
1527
|
const runtime = answers.runtime;
|
|
1406
1528
|
if (!runtime) return "back";
|
|
@@ -1414,6 +1536,8 @@ var TARGET_ID_STEP = {
|
|
|
1414
1536
|
validate: (value) => {
|
|
1415
1537
|
if (value.length === 0) return "a target id is required";
|
|
1416
1538
|
if (/\s/u.test(value)) return "a target id cannot contain spaces";
|
|
1539
|
+
if (readSettings().targets.some((target) => target.id === value))
|
|
1540
|
+
return "that target id already exists; choose another or use Edit a target";
|
|
1417
1541
|
return null;
|
|
1418
1542
|
},
|
|
1419
1543
|
input: wizard.input,
|
|
@@ -1484,7 +1608,7 @@ async function reportReachability(wizard, answers, runtime, url) {
|
|
|
1484
1608
|
}
|
|
1485
1609
|
var DETECTED_RUNTIME_STEP = {
|
|
1486
1610
|
id: "detected-runtime",
|
|
1487
|
-
applies: (answers) => answers.detected !== void 0 && answers.runtime !== void 0,
|
|
1611
|
+
applies: (answers) => answers.mode !== "edit" && answers.detected !== void 0 && answers.runtime !== void 0,
|
|
1488
1612
|
run: async (wizard, answers) => {
|
|
1489
1613
|
const detected = answers.detected;
|
|
1490
1614
|
const runtime = answers.runtime;
|
|
@@ -1540,10 +1664,15 @@ var CREDENTIAL_STEP = {
|
|
|
1540
1664
|
run: async (wizard, answers) => {
|
|
1541
1665
|
const runtime = answers.runtime;
|
|
1542
1666
|
if (!runtime) return "back";
|
|
1543
|
-
const stored = describeAuthStatus(runtime);
|
|
1667
|
+
const stored = describeAuthStatus(runtime, answers.existing);
|
|
1544
1668
|
if (runtime.auth === "oauth") {
|
|
1545
1669
|
const result2 = await promptSelect({
|
|
1546
|
-
heading: [
|
|
1670
|
+
heading: [
|
|
1671
|
+
"",
|
|
1672
|
+
source_default.bold(`Sign in to ${runtime.displayName}`),
|
|
1673
|
+
source_default.dim(`credential: ${stored}`),
|
|
1674
|
+
"Sign-in stores credentials immediately; target settings wait for Save."
|
|
1675
|
+
],
|
|
1547
1676
|
choices: [
|
|
1548
1677
|
{ value: "oauth-connect", label: "Connect now", hint: "opens your browser and waits for the callback" },
|
|
1549
1678
|
{
|
|
@@ -1575,7 +1704,7 @@ var CREDENTIAL_STEP = {
|
|
|
1575
1704
|
wizard.answer("Credential", "not connected yet");
|
|
1576
1705
|
return "next";
|
|
1577
1706
|
}
|
|
1578
|
-
const hasStored = stored !== "none stored";
|
|
1707
|
+
const hasStored = answers.existing?.auth?.apiKeyRef !== void 0 || stored !== "none stored";
|
|
1579
1708
|
const choices = [
|
|
1580
1709
|
{
|
|
1581
1710
|
value: "env",
|
|
@@ -1609,6 +1738,7 @@ var CREDENTIAL_STEP = {
|
|
|
1609
1738
|
if (result.kind === "back") return "back";
|
|
1610
1739
|
answers.credential = result.value;
|
|
1611
1740
|
if (result.value !== "env") answers.apiKeyEnv = void 0;
|
|
1741
|
+
answers.inventoryKey = void 0;
|
|
1612
1742
|
if (result.value !== "stored") answers.apiKeyLiteral = void 0;
|
|
1613
1743
|
if (result.value === "keep") wizard.answer("Credential", stored);
|
|
1614
1744
|
if (result.value === "skip") wizard.answer("Credential", "none");
|
|
@@ -1627,6 +1757,7 @@ var CREDENTIAL_VALUE_STEP = {
|
|
|
1627
1757
|
initial: wantsEnv ? answers.apiKeyEnv ?? runtime.credentialsEnvVar ?? "" : "",
|
|
1628
1758
|
hint: wantsEnv ? "Clio reads it every time it calls the provider, so the key never lands on disk" : `stored at ${shortenPath(authStoragePath())}`,
|
|
1629
1759
|
...wantsEnv ? {} : { mask: true },
|
|
1760
|
+
validate: (value) => value.length > 0 ? null : `Enter ${wantsEnv ? "an environment variable" : "a key"}, or press Escape to choose No key.`,
|
|
1630
1761
|
railPrefix: wizard.rail,
|
|
1631
1762
|
backLabel: "back",
|
|
1632
1763
|
clearOnExit: true,
|
|
@@ -1742,7 +1873,7 @@ var MODEL_STEP = {
|
|
|
1742
1873
|
};
|
|
1743
1874
|
async function readModelCapabilities(answers, runtime) {
|
|
1744
1875
|
const descriptor = draftDescriptor(answers, runtime, true);
|
|
1745
|
-
const probe = await runtimeProbe(runtime, descriptor);
|
|
1876
|
+
const probe = await runtimeProbe(runtime, descriptor, answers.apiKeyLiteral);
|
|
1746
1877
|
answers.probe = probe;
|
|
1747
1878
|
if (probe?.ok && probe.models) {
|
|
1748
1879
|
recordTargetModelSnapshot(descriptor, probe.models, probe.modelLabels ? { modelLabels: probe.modelLabels } : {});
|
|
@@ -1760,6 +1891,7 @@ var THINKING_HINTS = {
|
|
|
1760
1891
|
var THINKING_STEP = {
|
|
1761
1892
|
id: "thinking",
|
|
1762
1893
|
applies: (answers) => {
|
|
1894
|
+
if (answers.mode !== "first" && !PROTOCOL_COMPAT_RUNTIME_IDS.has(answers.runtime?.id ?? "")) return false;
|
|
1763
1895
|
const runtime = answers.runtime;
|
|
1764
1896
|
if (!runtime || answers.model === void 0) return false;
|
|
1765
1897
|
if (PROTOCOL_COMPAT_RUNTIME_IDS.has(runtime.id)) return true;
|
|
@@ -1768,7 +1900,13 @@ var THINKING_STEP = {
|
|
|
1768
1900
|
run: async (wizard, answers) => {
|
|
1769
1901
|
const current = THINKING_LEVELS.indexOf(answers.thinking ?? "low");
|
|
1770
1902
|
const result = await promptSelect({
|
|
1771
|
-
heading: [
|
|
1903
|
+
heading: [
|
|
1904
|
+
"",
|
|
1905
|
+
source_default.bold("How hard should it think?"),
|
|
1906
|
+
source_default.dim(
|
|
1907
|
+
answers.mode === "first" ? "changeable any time in `clio-coder configure`" : "off disables reasoning for this target; chat and fleet thinking defaults stay unchanged"
|
|
1908
|
+
)
|
|
1909
|
+
],
|
|
1772
1910
|
choices: THINKING_LEVELS.map((level) => ({ value: level, label: level, hint: THINKING_HINTS[level] })),
|
|
1773
1911
|
initialIndex: current >= 0 ? current : 0,
|
|
1774
1912
|
railPrefix: wizard.rail,
|
|
@@ -1786,7 +1924,7 @@ var THINKING_STEP = {
|
|
|
1786
1924
|
};
|
|
1787
1925
|
var ANTIGRAVITY_COLLEAGUE_STEP = {
|
|
1788
1926
|
id: "antigravity-colleague",
|
|
1789
|
-
applies: (answers) => answers.runtime !== void 0 && isOrchestratorEligibleRuntime(answers.runtime) && resolveOnPath(["agy"]).presence === "present" && !readSettings().targets.some((target) => target.runtime === "antigravity-code"),
|
|
1927
|
+
applies: (answers) => answers.mode === "first" && answers.runtime !== void 0 && isOrchestratorEligibleRuntime(answers.runtime) && resolveOnPath(["agy"]).presence === "present" && !readSettings().targets.some((target) => target.runtime === "antigravity-code"),
|
|
1790
1928
|
run: async (wizard, answers) => {
|
|
1791
1929
|
const runtime = getRuntimeRegistry().get("antigravity-code");
|
|
1792
1930
|
if (!runtime) return "next";
|
|
@@ -1845,22 +1983,54 @@ var ANTIGRAVITY_COLLEAGUE_STEP = {
|
|
|
1845
1983
|
return "next";
|
|
1846
1984
|
}
|
|
1847
1985
|
};
|
|
1848
|
-
var
|
|
1849
|
-
id: "
|
|
1850
|
-
applies: () =>
|
|
1986
|
+
var CONTEXT_STEP = {
|
|
1987
|
+
id: "context-window",
|
|
1988
|
+
applies: (answers) => PROTOCOL_COMPAT_RUNTIME_IDS.has(answers.runtime?.id ?? "") || answers.mode === "edit",
|
|
1851
1989
|
run: async (wizard, answers) => {
|
|
1852
|
-
const
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1990
|
+
const result = await promptText({
|
|
1991
|
+
heading: ["", source_default.bold("Context window in tokens")],
|
|
1992
|
+
initial: answers.contextWindow === void 0 ? "" : String(answers.contextWindow),
|
|
1993
|
+
hint: "optional override; blank uses detected capabilities or the runtime default",
|
|
1994
|
+
validate: (value) => value === "" || Number.isSafeInteger(Number(value)) && Number(value) > 0 ? null : "enter a positive whole number, or leave blank",
|
|
1995
|
+
railPrefix: wizard.rail,
|
|
1996
|
+
backLabel: "back",
|
|
1997
|
+
clearOnExit: true,
|
|
1998
|
+
input: wizard.input,
|
|
1999
|
+
output: wizard.output
|
|
1858
2000
|
});
|
|
1859
|
-
if (
|
|
1860
|
-
answers.
|
|
2001
|
+
if (result.kind !== "value") return result.kind;
|
|
2002
|
+
answers.contextWindow = result.value ? Number(result.value) : void 0;
|
|
2003
|
+
wizard.answer("Context", result.value || "detected / runtime default");
|
|
1861
2004
|
return "next";
|
|
1862
2005
|
}
|
|
1863
2006
|
};
|
|
2007
|
+
var REVIEW_STEP = {
|
|
2008
|
+
id: "review",
|
|
2009
|
+
applies: () => true,
|
|
2010
|
+
run: async (wizard, answers) => {
|
|
2011
|
+
const result = await promptSelect({
|
|
2012
|
+
heading: [
|
|
2013
|
+
"",
|
|
2014
|
+
source_default.bold("Review target"),
|
|
2015
|
+
`${answers.targetId} \xB7 ${answers.runtime?.id} \xB7 ${answers.model}`,
|
|
2016
|
+
answers.mode === "first" ? "Use for chat and fleet." : "Existing chat, fleet, memory, and profile defaults stay in place.",
|
|
2017
|
+
"Escape returns to the previous step; settings are saved only when you choose Save."
|
|
2018
|
+
],
|
|
2019
|
+
choices: [
|
|
2020
|
+
{ value: "save", label: "Save target" },
|
|
2021
|
+
{ value: "back", label: "Back" },
|
|
2022
|
+
{ value: "cancel", label: "Cancel setup" }
|
|
2023
|
+
],
|
|
2024
|
+
railPrefix: wizard.rail,
|
|
2025
|
+
backLabel: "back",
|
|
2026
|
+
clearOnExit: true,
|
|
2027
|
+
input: wizard.input,
|
|
2028
|
+
output: wizard.output
|
|
2029
|
+
});
|
|
2030
|
+
if (result.kind !== "selected") return result.kind;
|
|
2031
|
+
return result.value === "save" ? "next" : result.value === "back" ? "back" : "cancel";
|
|
2032
|
+
}
|
|
2033
|
+
};
|
|
1864
2034
|
var STEPS = [
|
|
1865
2035
|
CATEGORY_STEP,
|
|
1866
2036
|
RUNTIME_STEP,
|
|
@@ -1871,31 +2041,37 @@ var STEPS = [
|
|
|
1871
2041
|
DETECTED_RUNTIME_STEP,
|
|
1872
2042
|
MODEL_STEP,
|
|
1873
2043
|
THINKING_STEP,
|
|
2044
|
+
CONTEXT_STEP,
|
|
1874
2045
|
ANTIGRAVITY_COLLEAGUE_STEP,
|
|
1875
|
-
|
|
2046
|
+
REVIEW_STEP
|
|
1876
2047
|
];
|
|
1877
|
-
function
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
if (
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
}
|
|
1896
|
-
|
|
2048
|
+
function applyAnswers(settings, answers, descriptor, chatEligible) {
|
|
2049
|
+
const current = settings.targets.find((target) => target.id === descriptor.id);
|
|
2050
|
+
if (answers.mode === "edit") {
|
|
2051
|
+
if (JSON.stringify(current) !== JSON.stringify(answers.existing))
|
|
2052
|
+
throw new Error("This target changed during setup; reopen Edit to keep those changes.");
|
|
2053
|
+
} else if (current) throw new Error(`Target '${descriptor.id}' already exists; use Edit a target.`);
|
|
2054
|
+
applyTarget(settings, descriptor);
|
|
2055
|
+
if (answers.mode === "first" && chatEligible) setOrchestratorPointer(settings, descriptor, answers.model ?? null);
|
|
2056
|
+
if (answers.mode === "first") setWorkerDefaultPointer(settings, descriptor, answers.model ?? null);
|
|
2057
|
+
if (answers.mode === "first" && answers.thinking !== void 0) {
|
|
2058
|
+
settings.chat.thinkingLevel = answers.thinking;
|
|
2059
|
+
settings.fleet.default.thinkingLevel = answers.thinking;
|
|
2060
|
+
}
|
|
2061
|
+
if (answers.antigravity !== void 0) {
|
|
2062
|
+
const antigravityRuntime = getRuntimeRegistry().get("antigravity-code");
|
|
2063
|
+
if (!antigravityRuntime) throw new Error("Antigravity runtime disappeared before settings were written");
|
|
2064
|
+
const external = buildDescriptor(antigravityRuntime, answers.antigravity.targetId, {
|
|
2065
|
+
model: answers.antigravity.model
|
|
2066
|
+
});
|
|
2067
|
+
applyTarget(settings, external);
|
|
2068
|
+
setWorkerProfilePointer(settings, "world-knowledge-external", external, answers.antigravity.model);
|
|
2069
|
+
bindAgentProfileInSettings(settings, "world-knowledge", "world-knowledge-external");
|
|
2070
|
+
}
|
|
1897
2071
|
}
|
|
1898
|
-
async function runOnboardingWizard(streams
|
|
2072
|
+
async function runOnboardingWizard(streams, options = {
|
|
2073
|
+
mode: "first"
|
|
2074
|
+
}) {
|
|
1899
2075
|
const writer = railWriter(streams.out);
|
|
1900
2076
|
const presenter = createLifecyclePresenter({ stream: writer.stream });
|
|
1901
2077
|
const rail = railPrefix(presenter.isPlain());
|
|
@@ -1910,10 +2086,30 @@ async function runOnboardingWizard(streams) {
|
|
|
1910
2086
|
presenter.fields([[label.padEnd(LABEL_WIDTH), truncate(value, Math.max(12, columns - LABEL_WIDTH - 6))]]);
|
|
1911
2087
|
}
|
|
1912
2088
|
};
|
|
1913
|
-
presenter.header(
|
|
1914
|
-
|
|
2089
|
+
presenter.header(
|
|
2090
|
+
options.mode === "edit" ? `Edit target: ${options.target.id}` : options.mode === "first" ? "Welcome to Clio Coder" : "Add a target",
|
|
2091
|
+
"configure"
|
|
2092
|
+
);
|
|
2093
|
+
presenter.note("Pick a model; escape goes back. Review and save when ready.");
|
|
1915
2094
|
presenter.note(`Result: ${shortenPath(settingsPath())}`);
|
|
1916
|
-
const
|
|
2095
|
+
const existing = options.mode === "edit" ? options.target : void 0;
|
|
2096
|
+
const answers = {
|
|
2097
|
+
mode: options.mode,
|
|
2098
|
+
existing,
|
|
2099
|
+
runtime: existing ? getRuntimeRegistry().get(existing.runtime) ?? void 0 : options.mode !== "edit" ? options.runtime : void 0,
|
|
2100
|
+
fixedRuntime: options.mode !== "edit" && options.runtime !== void 0,
|
|
2101
|
+
targetId: existing?.id,
|
|
2102
|
+
url: existing?.url,
|
|
2103
|
+
model: existing?.defaultModel,
|
|
2104
|
+
credential: existing?.auth?.apiKeyEnvVar ? "env" : existing?.auth?.apiKeyRef ? "keep" : void 0,
|
|
2105
|
+
apiKeyEnv: existing?.auth?.apiKeyEnvVar,
|
|
2106
|
+
contextWindow: existing?.capabilities?.contextWindow,
|
|
2107
|
+
thinking: existing?.capabilities?.reasoning === false ? "off" : void 0
|
|
2108
|
+
};
|
|
2109
|
+
if (existing && !answers.runtime) {
|
|
2110
|
+
presenter.fail(`Unknown runtime: ${existing.runtime}`);
|
|
2111
|
+
return 2;
|
|
2112
|
+
}
|
|
1917
2113
|
const marks = new Array(STEPS.length).fill(writer.mark());
|
|
1918
2114
|
let cursor = 0;
|
|
1919
2115
|
let direction = 1;
|
|
@@ -1922,70 +2118,76 @@ async function runOnboardingWizard(streams) {
|
|
|
1922
2118
|
if (step === void 0) break;
|
|
1923
2119
|
if (!step.applies(answers)) {
|
|
1924
2120
|
cursor += direction;
|
|
1925
|
-
if (cursor < 0) return cancel(presenter);
|
|
2121
|
+
if (cursor < 0) return cancel(presenter, answers);
|
|
1926
2122
|
continue;
|
|
1927
2123
|
}
|
|
1928
2124
|
marks[cursor] = writer.mark();
|
|
1929
2125
|
const outcome = await step.run(wizard, answers);
|
|
1930
|
-
if (outcome === "quit") return cancel(presenter);
|
|
2126
|
+
if (outcome === "quit" || outcome === "cancel") return cancel(presenter, answers, outcome === "quit");
|
|
1931
2127
|
if (outcome === "back") {
|
|
1932
2128
|
direction = -1;
|
|
1933
2129
|
cursor -= 1;
|
|
1934
2130
|
while (cursor >= 0 && !(STEPS[cursor]?.applies(answers) ?? false)) cursor -= 1;
|
|
1935
|
-
if (cursor < 0) return cancel(presenter);
|
|
2131
|
+
if (cursor < 0) return cancel(presenter, answers);
|
|
1936
2132
|
writer.rewindTo(marks[cursor] ?? writer.mark());
|
|
1937
2133
|
continue;
|
|
1938
2134
|
}
|
|
1939
2135
|
direction = 1;
|
|
1940
2136
|
cursor += 1;
|
|
1941
2137
|
}
|
|
1942
|
-
|
|
2138
|
+
const code = finish(wizard, answers);
|
|
2139
|
+
if (code === 0 && answers.mode === "first") {
|
|
2140
|
+
await reviewInteropAgents({ rl: null, streams, presenter, rail, quiet: true });
|
|
2141
|
+
}
|
|
2142
|
+
return code;
|
|
1943
2143
|
}
|
|
1944
|
-
function cancel(presenter) {
|
|
1945
|
-
presenter.done("Cancelled
|
|
1946
|
-
printError("configuration cancelled");
|
|
1947
|
-
return 130;
|
|
2144
|
+
function cancel(presenter, answers, quit = false) {
|
|
2145
|
+
presenter.done("Cancelled; target settings not saved");
|
|
2146
|
+
if (answers.mode === "first") printError("configuration cancelled");
|
|
2147
|
+
return answers.mode === "first" || quit ? 130 : 0;
|
|
1948
2148
|
}
|
|
1949
2149
|
function finish(wizard, answers) {
|
|
1950
2150
|
const runtime = answers.runtime;
|
|
1951
2151
|
const targetId = answers.targetId;
|
|
1952
|
-
if (!runtime || targetId === void 0) return cancel(wizard.presenter);
|
|
2152
|
+
if (!runtime || targetId === void 0) return cancel(wizard.presenter, answers);
|
|
1953
2153
|
const presenter = wizard.presenter;
|
|
1954
|
-
if (answers.apiKeyLiteral !== void 0) {
|
|
1955
|
-
const auth = openAuthStorage();
|
|
1956
|
-
auth.setApiKey(runtime.id, answers.apiKeyLiteral);
|
|
1957
|
-
if (credentialWriteFailed(auth, `credential for ${runtime.id} was not stored; target '${targetId}' not saved`)) {
|
|
1958
|
-
presenter.done("Nothing written");
|
|
1959
|
-
return 1;
|
|
1960
|
-
}
|
|
1961
|
-
printPlaintextCredentialWarning();
|
|
1962
|
-
}
|
|
1963
2154
|
const reasoning = PROTOCOL_COMPAT_RUNTIME_IDS.has(runtime.id) && answers.thinking !== void 0 ? answers.thinking !== "off" : void 0;
|
|
1964
|
-
const descriptor =
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
...runtime.auth === "oauth" ? { oauthProfile: runtime.oauthProviderId ?? runtime.id } : {},
|
|
1970
|
-
...reasoning === void 0 ? {} : { reasoning }
|
|
1971
|
-
});
|
|
2155
|
+
const descriptor = draftDescriptor(answers, runtime, true);
|
|
2156
|
+
descriptor.capabilities = { ...descriptor.capabilities };
|
|
2157
|
+
if (reasoning !== void 0) descriptor.capabilities.reasoning = reasoning;
|
|
2158
|
+
if (answers.contextWindow === void 0) delete descriptor.capabilities.contextWindow;
|
|
2159
|
+
else descriptor.capabilities.contextWindow = answers.contextWindow;
|
|
1972
2160
|
const chatEligible = isOrchestratorEligibleRuntime(runtime);
|
|
1973
2161
|
try {
|
|
1974
|
-
|
|
2162
|
+
const preview = readSettings();
|
|
2163
|
+
applyAnswers(preview, answers, descriptor, chatEligible);
|
|
2164
|
+
const validated = validateSettings(preview);
|
|
2165
|
+
if (validated.issues.length) throw new SettingsValidationError(validated.issues);
|
|
2166
|
+
initializeClioHome();
|
|
2167
|
+
if (answers.apiKeyLiteral !== void 0 && descriptor.auth?.apiKeyRef) {
|
|
2168
|
+
const auth = openAuthStorage();
|
|
2169
|
+
auth.setApiKey(descriptor.auth.apiKeyRef, answers.apiKeyLiteral);
|
|
2170
|
+
if (credentialWriteFailed(auth, `credential for ${runtime.id} was not stored; target '${targetId}' not saved`)) {
|
|
2171
|
+
presenter.done("Nothing written");
|
|
2172
|
+
return 1;
|
|
2173
|
+
}
|
|
2174
|
+
printPlaintextCredentialWarning();
|
|
2175
|
+
}
|
|
2176
|
+
updateSettings((settings) => applyAnswers(settings, answers, descriptor, chatEligible));
|
|
1975
2177
|
} catch (error) {
|
|
1976
2178
|
presenter.fail("settings were not written", error instanceof Error ? error.message : String(error));
|
|
1977
|
-
presenter.done("
|
|
2179
|
+
presenter.done("Target settings not saved");
|
|
1978
2180
|
return 1;
|
|
1979
2181
|
}
|
|
1980
2182
|
presenter.completedStep(`target ${targetId} saved, runtime ${runtime.id}`);
|
|
1981
|
-
if (chatEligible)
|
|
2183
|
+
if (answers.mode === "first" && chatEligible)
|
|
1982
2184
|
presenter.completedStep(`chat runs on ${targetId}${answers.model ? `, model ${answers.model}` : ""}`);
|
|
1983
|
-
else
|
|
1984
|
-
|
|
1985
|
-
if (answers.
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
2185
|
+
else if (!chatEligible)
|
|
2186
|
+
presenter.completedStep(`${runtime.id} cannot answer chat; ${targetId} is registered for dispatch only`);
|
|
2187
|
+
if (answers.mode === "first") presenter.completedStep(`fleet default is ${targetId}`);
|
|
2188
|
+
else presenter.note("Use Targets & Auth to change chat, fleet, or background defaults.");
|
|
2189
|
+
if (answers.mode === "first" && answers.thinking !== void 0)
|
|
2190
|
+
presenter.completedStep(`thinking level ${answers.thinking}`);
|
|
1989
2191
|
if (answers.antigravity !== void 0) {
|
|
1990
2192
|
presenter.completedStep(
|
|
1991
2193
|
`world-knowledge bound read-only to ${answers.antigravity.targetId}/${answers.antigravity.model}`
|
|
@@ -2003,19 +2205,318 @@ function finish(wizard, answers) {
|
|
|
2003
2205
|
return 0;
|
|
2004
2206
|
}
|
|
2005
2207
|
|
|
2208
|
+
// src/cli/configure-prompts.ts
|
|
2209
|
+
init_esm_shims();
|
|
2210
|
+
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
2211
|
+
var ConfigureNavigation = class extends Error {
|
|
2212
|
+
constructor(kind) {
|
|
2213
|
+
super(kind);
|
|
2214
|
+
this.kind = kind;
|
|
2215
|
+
}
|
|
2216
|
+
kind;
|
|
2217
|
+
};
|
|
2218
|
+
var ConfigurePrompts = class {
|
|
2219
|
+
constructor(input2, output3) {
|
|
2220
|
+
this.input = input2;
|
|
2221
|
+
this.output = output3;
|
|
2222
|
+
}
|
|
2223
|
+
input;
|
|
2224
|
+
output;
|
|
2225
|
+
get interactive() {
|
|
2226
|
+
return canSelect(this.input, this.output);
|
|
2227
|
+
}
|
|
2228
|
+
clearScreen() {
|
|
2229
|
+
if (this.interactive) this.output.write("\x1B[H\x1B[2J");
|
|
2230
|
+
}
|
|
2231
|
+
async question(query, options) {
|
|
2232
|
+
const rl = createInterface2({ input: this.input, output: this.output });
|
|
2233
|
+
try {
|
|
2234
|
+
return await new Promise((resolve, reject) => {
|
|
2235
|
+
rl.once("close", () => reject(new ConfigureNavigation("quit")));
|
|
2236
|
+
rl.once("SIGINT", () => reject(new ConfigureNavigation("quit")));
|
|
2237
|
+
rl.question(query, options ?? {}).then(resolve, reject);
|
|
2238
|
+
});
|
|
2239
|
+
} finally {
|
|
2240
|
+
rl.close();
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
async text(label, initial = "", mask = false) {
|
|
2244
|
+
if (!this.interactive) {
|
|
2245
|
+
const value = (await this.question(`${label}${initial ? ` [${initial}]` : ""}: `)).trim();
|
|
2246
|
+
if (/^(q|quit)$/iu.test(value)) throw new ConfigureNavigation("quit");
|
|
2247
|
+
return value || initial;
|
|
2248
|
+
}
|
|
2249
|
+
const result = await promptText({
|
|
2250
|
+
heading: ["", label],
|
|
2251
|
+
railPrefix: railPrefix(createLifecyclePresenter({ stream: this.output }).isPlain()),
|
|
2252
|
+
initial,
|
|
2253
|
+
mask,
|
|
2254
|
+
backLabel: "back",
|
|
2255
|
+
clearOnExit: true,
|
|
2256
|
+
input: this.input,
|
|
2257
|
+
output: this.output
|
|
2258
|
+
});
|
|
2259
|
+
if (result.kind !== "value") throw new ConfigureNavigation(result.kind);
|
|
2260
|
+
return result.value;
|
|
2261
|
+
}
|
|
2262
|
+
async choose(label, choices, current, searchable = false) {
|
|
2263
|
+
if (!this.interactive) return this.text(`${label} [${choices.join("|")}]`, current);
|
|
2264
|
+
const result = await promptSelect({
|
|
2265
|
+
heading: ["", label],
|
|
2266
|
+
railPrefix: railPrefix(createLifecyclePresenter({ stream: this.output }).isPlain()),
|
|
2267
|
+
choices: choices.map((value) => ({ value, label: value })),
|
|
2268
|
+
initialIndex: Math.max(0, choices.indexOf(current)),
|
|
2269
|
+
...searchable ? { searchable: true, maxVisible: 8 } : {},
|
|
2270
|
+
backLabel: "back",
|
|
2271
|
+
clearOnExit: true,
|
|
2272
|
+
input: this.input,
|
|
2273
|
+
output: this.output
|
|
2274
|
+
});
|
|
2275
|
+
if (result.kind !== "selected") throw new ConfigureNavigation(result.kind);
|
|
2276
|
+
return result.value;
|
|
2277
|
+
}
|
|
2278
|
+
};
|
|
2279
|
+
|
|
2280
|
+
// src/cli/configure-quick.ts
|
|
2281
|
+
init_esm_shims();
|
|
2282
|
+
function endpointUrl(value) {
|
|
2283
|
+
const url = new URL(value.includes("://") ? value : `http://${value}`);
|
|
2284
|
+
if (!["http:", "https:"].includes(url.protocol) || !url.hostname)
|
|
2285
|
+
throw new Error("Use an http:// or https:// endpoint URL.");
|
|
2286
|
+
if (url.username || url.password)
|
|
2287
|
+
throw new Error("Enter the endpoint without credentials; Clio asks for a key when needed.");
|
|
2288
|
+
return url.toString().replace(/\/$/u, "");
|
|
2289
|
+
}
|
|
2290
|
+
async function connect(url, key) {
|
|
2291
|
+
const settings = readSettings();
|
|
2292
|
+
const registry = getRuntimeRegistry();
|
|
2293
|
+
const matches = settings.targets.filter((target2) => {
|
|
2294
|
+
const runtime2 = registry.get(target2.runtime);
|
|
2295
|
+
if (!target2.url || !runtime2 || !isOrchestratorEligibleRuntime(runtime2)) return false;
|
|
2296
|
+
try {
|
|
2297
|
+
return endpointUrl(target2.url) === url;
|
|
2298
|
+
} catch {
|
|
2299
|
+
return false;
|
|
2300
|
+
}
|
|
2301
|
+
});
|
|
2302
|
+
const existing = matches.find((target2) => target2.id === settings.chat.target) ?? matches[0];
|
|
2303
|
+
let runtime = existing ? registry.get(existing.runtime) : null;
|
|
2304
|
+
let token = key;
|
|
2305
|
+
if (existing && runtime && token === void 0) {
|
|
2306
|
+
const auth = await openAuthStorage().resolveForTarget(resolveAuthTarget(existing, runtime), {
|
|
2307
|
+
includeFallback: false
|
|
2308
|
+
});
|
|
2309
|
+
token = auth.apiKey;
|
|
2310
|
+
}
|
|
2311
|
+
const ctx = { credentialsPresent: /* @__PURE__ */ new Set(), httpTimeoutMs: 5e3, authToken: token ?? "" };
|
|
2312
|
+
if (!runtime) {
|
|
2313
|
+
const root = targetRootUrl({ id: "quick", runtime: "openai-compat", url }) ?? url;
|
|
2314
|
+
const headers = token ? { Authorization: `Bearer ${token}` } : {};
|
|
2315
|
+
const native = await fingerprintNativeRuntime(root, headers);
|
|
2316
|
+
let id = native?.runtimeId ?? "openai-compat";
|
|
2317
|
+
if (!native) {
|
|
2318
|
+
const info = await probeJson({
|
|
2319
|
+
url: `${root}/v1/model/info`,
|
|
2320
|
+
headers,
|
|
2321
|
+
timeoutMs: 1e3
|
|
2322
|
+
});
|
|
2323
|
+
if (info.ok && info.data?.data?.some((row) => typeof row.model_name === "string" && row.model_info !== void 0))
|
|
2324
|
+
id = "litellm";
|
|
2325
|
+
}
|
|
2326
|
+
runtime = registry.get(id);
|
|
2327
|
+
}
|
|
2328
|
+
if (!runtime) throw new Error("No compatible runtime is available. Open Settings \u2192 Targets & Auth.");
|
|
2329
|
+
const target = existing ? structuredClone(existing) : {
|
|
2330
|
+
id: deriveTargetId(runtime.id, settings.targets),
|
|
2331
|
+
runtime: runtime.id,
|
|
2332
|
+
url
|
|
2333
|
+
};
|
|
2334
|
+
let probe = await runtime.probe?.(target, ctx) ?? {
|
|
2335
|
+
ok: false,
|
|
2336
|
+
error: "This connection does not support endpoint checks."
|
|
2337
|
+
};
|
|
2338
|
+
let models = probe.ok ? probe.models ?? await runtime.probeModels?.(target, ctx) ?? [] : [];
|
|
2339
|
+
if (!existing && runtime.id === "openai-compat" && !probe.ok && /HTTP (401|403|404)/u.test(probe.error ?? "")) {
|
|
2340
|
+
const anthropic = registry.get("anthropic-compat");
|
|
2341
|
+
if (anthropic) {
|
|
2342
|
+
const candidate = { ...target, runtime: anthropic.id };
|
|
2343
|
+
const catalog = await anthropic.probeModels?.(candidate, ctx) ?? [];
|
|
2344
|
+
if (catalog.length > 0) {
|
|
2345
|
+
runtime = anthropic;
|
|
2346
|
+
target.runtime = anthropic.id;
|
|
2347
|
+
target.id = deriveTargetId(anthropic.id, settings.targets);
|
|
2348
|
+
models = catalog;
|
|
2349
|
+
probe = { ok: true, models };
|
|
2350
|
+
}
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2353
|
+
models = [...new Set(models)].filter((id) => probe.modelCapabilities?.[id]?.chat !== false);
|
|
2354
|
+
return { runtime, target, existing, probe, models };
|
|
2355
|
+
}
|
|
2356
|
+
async function runQuickConnect(prompts) {
|
|
2357
|
+
const initial = readSettings();
|
|
2358
|
+
const first = initial.targets.length === 0;
|
|
2359
|
+
const current = initial.targets.find((target) => target.id === initial.chat.target);
|
|
2360
|
+
let url = current?.url ?? "";
|
|
2361
|
+
let key;
|
|
2362
|
+
let connection;
|
|
2363
|
+
let model = "";
|
|
2364
|
+
let step = "url";
|
|
2365
|
+
let askedKey = false;
|
|
2366
|
+
let optionalKey = false;
|
|
2367
|
+
let notice = "";
|
|
2368
|
+
const presenter = createLifecyclePresenter({ stream: prompts.output });
|
|
2369
|
+
for (; ; ) {
|
|
2370
|
+
prompts.clearScreen();
|
|
2371
|
+
presenter.header("Quick Connect", "configure");
|
|
2372
|
+
presenter.note("Connect one model to power Clio. Change other settings whenever you need them.");
|
|
2373
|
+
if (notice) {
|
|
2374
|
+
presenter.warn(notice);
|
|
2375
|
+
notice = "";
|
|
2376
|
+
}
|
|
2377
|
+
try {
|
|
2378
|
+
if (step === "url") {
|
|
2379
|
+
presenter.note("LM Studio: localhost:1234 \xB7 Ollama: localhost:11434");
|
|
2380
|
+
const answer = await prompts.text("Endpoint URL", url);
|
|
2381
|
+
if (!answer) {
|
|
2382
|
+
notice = "Enter the endpoint URL shown by your model server or API provider.";
|
|
2383
|
+
continue;
|
|
2384
|
+
}
|
|
2385
|
+
try {
|
|
2386
|
+
url = endpointUrl(answer);
|
|
2387
|
+
} catch (error) {
|
|
2388
|
+
notice = error instanceof Error ? error.message : String(error);
|
|
2389
|
+
continue;
|
|
2390
|
+
}
|
|
2391
|
+
key = void 0;
|
|
2392
|
+
askedKey = false;
|
|
2393
|
+
connection = void 0;
|
|
2394
|
+
} else if (step === "key") {
|
|
2395
|
+
presenter.note(`Endpoint: ${url}`);
|
|
2396
|
+
if (optionalKey)
|
|
2397
|
+
presenter.note("Some APIs publish models publicly but require a key for chat. Leave blank for a keyless server.");
|
|
2398
|
+
key = await prompts.text("API key (saved locally when you choose Connect)", "", true) || void 0;
|
|
2399
|
+
if (!key && !optionalKey) {
|
|
2400
|
+
notice = "Enter a key, or press Escape to change the endpoint.";
|
|
2401
|
+
continue;
|
|
2402
|
+
}
|
|
2403
|
+
askedKey = true;
|
|
2404
|
+
}
|
|
2405
|
+
if (step === "url" || step === "key") {
|
|
2406
|
+
presenter.note("Checking the endpoint and reading its model list\u2026");
|
|
2407
|
+
connection = await connect(url, key);
|
|
2408
|
+
if (!connection.probe.ok) {
|
|
2409
|
+
if (connection.probe.authFailed || /HTTP (401|403)/u.test(connection.probe.error ?? "")) {
|
|
2410
|
+
optionalKey = false;
|
|
2411
|
+
notice = key ? "The endpoint rejected that key. Try again, or Escape to go back." : "This endpoint needs an API key.";
|
|
2412
|
+
step = "key";
|
|
2413
|
+
} else {
|
|
2414
|
+
notice = `Could not connect: ${connection.probe.error ?? "no reply"}. Check the URL and that the server is running.`;
|
|
2415
|
+
step = "url";
|
|
2416
|
+
}
|
|
2417
|
+
continue;
|
|
2418
|
+
}
|
|
2419
|
+
if (!connection.existing && !askedKey && connection.runtime.auth === "api-key" && connection.runtime.tier !== "local-native") {
|
|
2420
|
+
optionalKey = true;
|
|
2421
|
+
step = "key";
|
|
2422
|
+
continue;
|
|
2423
|
+
}
|
|
2424
|
+
if (connection.models.length === 0) {
|
|
2425
|
+
notice = "The endpoint offered no chat models. Load a model and retry. Servers without model discovery can use Settings \u2192 Targets & Auth.";
|
|
2426
|
+
step = "url";
|
|
2427
|
+
continue;
|
|
2428
|
+
}
|
|
2429
|
+
const preferred = connection.existing?.id === initial.chat.target ? initial.chat.model : connection.target.defaultModel;
|
|
2430
|
+
model = preferred && connection.models.includes(preferred) ? preferred : connection.models[0] ?? "";
|
|
2431
|
+
step = connection.models.length === 1 ? "save" : "model";
|
|
2432
|
+
continue;
|
|
2433
|
+
}
|
|
2434
|
+
if (!connection) {
|
|
2435
|
+
step = "url";
|
|
2436
|
+
continue;
|
|
2437
|
+
}
|
|
2438
|
+
if (step === "model") {
|
|
2439
|
+
presenter.note(`Connected: ${url} (${connection.runtime.displayName})`);
|
|
2440
|
+
model = await prompts.choose("Choose the model for Clio", connection.models, model, true);
|
|
2441
|
+
if (!connection.models.includes(model)) {
|
|
2442
|
+
notice = "Choose a model from the endpoint's live list.";
|
|
2443
|
+
continue;
|
|
2444
|
+
}
|
|
2445
|
+
step = "save";
|
|
2446
|
+
continue;
|
|
2447
|
+
}
|
|
2448
|
+
presenter.fields([
|
|
2449
|
+
["Endpoint", url],
|
|
2450
|
+
["Model", model],
|
|
2451
|
+
["Connection", "live model discovery passed"]
|
|
2452
|
+
]);
|
|
2453
|
+
presenter.note(
|
|
2454
|
+
first ? "Ready with recommended defaults: workspace edits, approval for unrecognized commands, one worker, $5 tracked session budget." : "Use this model for chat. Your other settings and role assignments stay in place."
|
|
2455
|
+
);
|
|
2456
|
+
const choice = await prompts.choose("Ready to connect", ["Connect", "Back"], "Connect");
|
|
2457
|
+
if (choice !== "Connect") throw new ConfigureNavigation("back");
|
|
2458
|
+
const descriptor = structuredClone(connection.target);
|
|
2459
|
+
if (!connection.existing) descriptor.defaultModel = model;
|
|
2460
|
+
if (key) {
|
|
2461
|
+
descriptor.auth = { ...descriptor.auth, apiKeyRef: targetApiKeyRef(descriptor.id, readSettings().targets) };
|
|
2462
|
+
delete descriptor.auth.apiKeyEnvVar;
|
|
2463
|
+
}
|
|
2464
|
+
const apply = (settings) => {
|
|
2465
|
+
const target = settings.targets.find((entry) => entry.id === descriptor.id);
|
|
2466
|
+
if (JSON.stringify(target) !== JSON.stringify(connection?.existing))
|
|
2467
|
+
throw new Error("This target changed during setup. Reopen Quick Connect to keep those changes.");
|
|
2468
|
+
applyTarget(settings, descriptor);
|
|
2469
|
+
setOrchestratorPointer(settings, descriptor, model);
|
|
2470
|
+
if (first && !settings.fleet.default.target) setWorkerDefaultPointer(settings, descriptor, model);
|
|
2471
|
+
};
|
|
2472
|
+
const preview = readSettings();
|
|
2473
|
+
apply(preview);
|
|
2474
|
+
const validated = validateSettings(preview);
|
|
2475
|
+
if (validated.issues.length) throw new SettingsValidationError(validated.issues);
|
|
2476
|
+
initializeClioHome();
|
|
2477
|
+
if (key && descriptor.auth?.apiKeyRef) {
|
|
2478
|
+
const auth = openAuthStorage();
|
|
2479
|
+
auth.setApiKey(descriptor.auth.apiKeyRef, key);
|
|
2480
|
+
if (credentialWriteFailed(auth, "The key was not saved; connection settings were not changed."))
|
|
2481
|
+
throw new Error("The key could not be saved. Check permissions on the credentials file and retry.");
|
|
2482
|
+
printPlaintextCredentialWarning();
|
|
2483
|
+
}
|
|
2484
|
+
updateSettings(apply);
|
|
2485
|
+
presenter.done(`Connected: ${descriptor.id} / ${model}`);
|
|
2486
|
+
presenter.commandAdvice("Start Clio:", "clio-coder");
|
|
2487
|
+
return "connected";
|
|
2488
|
+
} catch (error) {
|
|
2489
|
+
if (!(error instanceof ConfigureNavigation)) {
|
|
2490
|
+
notice = error instanceof Error ? error.message : String(error);
|
|
2491
|
+
step = "url";
|
|
2492
|
+
continue;
|
|
2493
|
+
}
|
|
2494
|
+
if (error.kind === "quit" || step === "url") {
|
|
2495
|
+
presenter.done("Quick Connect cancelled; connection settings not saved.");
|
|
2496
|
+
return error.kind;
|
|
2497
|
+
}
|
|
2498
|
+
step = step === "save" && (connection?.models.length ?? 0) > 1 ? "model" : step === "model" || step === "save" ? askedKey ? "key" : "url" : "url";
|
|
2499
|
+
}
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
2502
|
+
|
|
2006
2503
|
// src/cli/configure.ts
|
|
2007
2504
|
var HELP = `clio-coder configure
|
|
2008
2505
|
|
|
2009
2506
|
Configure model targets and runtime settings for chat and fleet dispatch.
|
|
2010
2507
|
|
|
2011
2508
|
Usage:
|
|
2012
|
-
clio-coder configure
|
|
2509
|
+
clio-coder configure Quick Connect, Settings, or Diagnostics
|
|
2510
|
+
clio-coder configure --quick connect an endpoint with recommended defaults
|
|
2511
|
+
clio-coder configure --settings open the complete settings menu
|
|
2013
2512
|
clio-coder configure --section <name> open one section directly:
|
|
2014
2513
|
targets, models, chat, fleet,
|
|
2015
|
-
permissions, panes, skills, diagnostics
|
|
2514
|
+
permissions, panes, skills, diagnostics, advanced
|
|
2016
2515
|
Without a terminal this prints the
|
|
2017
2516
|
section's values and exits.
|
|
2018
2517
|
clio-coder configure --json emit the effective settings as JSON
|
|
2518
|
+
clio-coder configure --edit edit all user settings in VISUAL/EDITOR;
|
|
2519
|
+
validate and review before saving
|
|
2019
2520
|
clio-coder configure --interop review detected coding agents as delegation peers
|
|
2020
2521
|
clio-coder configure --list list target runtimes (user-facing only)
|
|
2021
2522
|
clio-coder configure --list --all list every registered runtime including aliases
|
|
@@ -2060,6 +2561,9 @@ function parseSetupArgs(argv) {
|
|
|
2060
2561
|
all: false,
|
|
2061
2562
|
interop: false,
|
|
2062
2563
|
json: false,
|
|
2564
|
+
edit: false,
|
|
2565
|
+
quick: false,
|
|
2566
|
+
settings: false,
|
|
2063
2567
|
force: false,
|
|
2064
2568
|
gateway: false,
|
|
2065
2569
|
setOrchestrator: false,
|
|
@@ -2082,6 +2586,15 @@ function parseSetupArgs(argv) {
|
|
|
2082
2586
|
case "--json":
|
|
2083
2587
|
out.json = true;
|
|
2084
2588
|
break;
|
|
2589
|
+
case "--edit":
|
|
2590
|
+
out.edit = true;
|
|
2591
|
+
break;
|
|
2592
|
+
case "--quick":
|
|
2593
|
+
out.quick = true;
|
|
2594
|
+
break;
|
|
2595
|
+
case "--settings":
|
|
2596
|
+
out.settings = true;
|
|
2597
|
+
break;
|
|
2085
2598
|
case "--section":
|
|
2086
2599
|
out.section = need();
|
|
2087
2600
|
break;
|
|
@@ -2197,7 +2710,9 @@ function printRuntimeList(includeHidden) {
|
|
|
2197
2710
|
const rows = [];
|
|
2198
2711
|
for (const entry of listProviderSupportEntries(getRuntimeRegistry().list(), { includeHidden })) {
|
|
2199
2712
|
const runtime = getRuntimeRegistry().get(entry.runtimeId);
|
|
2200
|
-
const status = runtime && entry.connectable ? auth.statusForTarget(resolveRuntimeAuthTarget(runtime), {
|
|
2713
|
+
const status = runtime && entry.connectable ? auth.statusForTarget(resolveRuntimeAuthTarget(runtime), {
|
|
2714
|
+
includeFallback: false
|
|
2715
|
+
}) : null;
|
|
2201
2716
|
const authLabel = runtime?.auth === "oauth" ? status?.available ? "connected" : "login" : runtime?.auth === "api-key" ? status?.available ? "credential" : targetRequiresAuth({ id: entry.runtimeId, runtime: entry.runtimeId }, runtime) ? "needs-key" : "key-optional" : runtime?.auth ?? "none";
|
|
2202
2717
|
rows.push({
|
|
2203
2718
|
group: supportGroupLabel(entry.group),
|
|
@@ -2292,6 +2807,7 @@ async function runNonInteractive(runtime, args) {
|
|
|
2292
2807
|
);
|
|
2293
2808
|
return 2;
|
|
2294
2809
|
}
|
|
2810
|
+
initializeClioHome();
|
|
2295
2811
|
const settings = readSettings();
|
|
2296
2812
|
const auth = openAuthStorage();
|
|
2297
2813
|
const support = buildProviderSupportEntry(runtime);
|
|
@@ -2323,24 +2839,32 @@ async function runNonInteractive(runtime, args) {
|
|
|
2323
2839
|
);
|
|
2324
2840
|
}
|
|
2325
2841
|
}
|
|
2326
|
-
const authStatus = auth.statusForTarget(
|
|
2842
|
+
const authStatus = auth.statusForTarget(
|
|
2843
|
+
existing ? resolveAuthTarget(existing, runtime) : resolveRuntimeAuthTarget(runtime),
|
|
2844
|
+
{ includeFallback: false }
|
|
2845
|
+
);
|
|
2327
2846
|
const apiKeyEnv = args.apiKeyEnv ?? existing?.auth?.apiKeyEnvVar;
|
|
2328
|
-
const apiKeyRef = runtime.auth === "api-key" && (args.apiKey || existing?.auth?.apiKeyRef || authStatus.source === "stored-api-key") ? runtime.id : void 0;
|
|
2847
|
+
const apiKeyRef = runtime.auth === "api-key" && (args.apiKey || existing?.auth?.apiKeyRef || authStatus.source === "stored-api-key") ? args.apiKey ? targetApiKeyRef(args.id, settings.targets) : existing?.auth?.apiKeyRef ?? runtime.id : void 0;
|
|
2329
2848
|
const oauthProfile = runtime.auth === "oauth" ? existing?.auth?.oauthProfile ?? runtime.oauthProviderId ?? runtime.id : void 0;
|
|
2330
|
-
const seed =
|
|
2331
|
-
...
|
|
2332
|
-
...
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2849
|
+
const seed = {
|
|
2850
|
+
...existing,
|
|
2851
|
+
...buildDescriptor(runtime, args.id, {
|
|
2852
|
+
...url !== void 0 ? { url } : {},
|
|
2853
|
+
...args.model !== void 0 ? { model: args.model } : existing?.defaultModel ? { model: existing.defaultModel } : support.defaultModel ? { model: support.defaultModel } : {},
|
|
2854
|
+
...apiKeyEnv !== void 0 ? { apiKeyEnv } : {},
|
|
2855
|
+
...apiKeyRef !== void 0 ? { apiKeyRef } : {},
|
|
2856
|
+
...oauthProfile !== void 0 ? { oauthProfile } : {},
|
|
2857
|
+
gateway: args.gateway || existing?.gateway === true,
|
|
2858
|
+
...args.lifecycle !== void 0 ? { lifecycle: args.lifecycle } : existing?.lifecycle !== void 0 ? { lifecycle: existing.lifecycle } : {},
|
|
2859
|
+
...args.contextWindow !== void 0 ? { contextWindow: args.contextWindow } : {},
|
|
2860
|
+
...args.maxTokens !== void 0 ? { maxTokens: args.maxTokens } : {},
|
|
2861
|
+
...args.reasoning !== void 0 ? { reasoning: args.reasoning } : {},
|
|
2862
|
+
...existing?.lmstudio ? { lmstudio: existing.lmstudio } : {},
|
|
2863
|
+
...existing?.litellm ? { litellm: existing.litellm } : {}
|
|
2864
|
+
})
|
|
2865
|
+
};
|
|
2866
|
+
seed.capabilities = { ...existing?.capabilities, ...seed.capabilities };
|
|
2867
|
+
if (seed.auth) seed.auth = { ...existing?.auth, ...seed.auth };
|
|
2344
2868
|
const inventory = await resolveSupportedWireModels(runtime, seed, existing, args.apiKey);
|
|
2345
2869
|
const wireModels = inventory.models;
|
|
2346
2870
|
const model = args.model ?? existing?.defaultModel ?? (inventory.source === "probe" ? wireModels[0] : support.defaultModel) ?? (support.modelSource === "catalog" ? void 0 : wireModels[0]);
|
|
@@ -2350,20 +2874,25 @@ async function runNonInteractive(runtime, args) {
|
|
|
2350
2874
|
}
|
|
2351
2875
|
if (!validateResolvedModel(runtime, seed, model, args.force, inventory)) return 2;
|
|
2352
2876
|
if (!validateContextWindowOverride(runtime, model, args.contextWindow, args.force)) return 2;
|
|
2353
|
-
const descriptor =
|
|
2354
|
-
...
|
|
2355
|
-
...
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2877
|
+
const descriptor = {
|
|
2878
|
+
...existing,
|
|
2879
|
+
...buildDescriptor(runtime, args.id, {
|
|
2880
|
+
...url !== void 0 ? { url } : {},
|
|
2881
|
+
...model ? { model } : {},
|
|
2882
|
+
...apiKeyEnv !== void 0 ? { apiKeyEnv } : {},
|
|
2883
|
+
...apiKeyRef !== void 0 ? { apiKeyRef } : {},
|
|
2884
|
+
...oauthProfile !== void 0 ? { oauthProfile } : {},
|
|
2885
|
+
gateway: args.gateway || existing?.gateway === true,
|
|
2886
|
+
...args.lifecycle !== void 0 ? { lifecycle: args.lifecycle } : existing?.lifecycle !== void 0 ? { lifecycle: existing.lifecycle } : {},
|
|
2887
|
+
...args.contextWindow !== void 0 ? { contextWindow: args.contextWindow } : {},
|
|
2888
|
+
...args.maxTokens !== void 0 ? { maxTokens: args.maxTokens } : {},
|
|
2889
|
+
...args.reasoning !== void 0 ? { reasoning: args.reasoning } : {},
|
|
2890
|
+
...existing?.lmstudio ? { lmstudio: existing.lmstudio } : {},
|
|
2891
|
+
...existing?.litellm ? { litellm: existing.litellm } : {}
|
|
2892
|
+
})
|
|
2893
|
+
};
|
|
2894
|
+
descriptor.capabilities = { ...existing?.capabilities, ...descriptor.capabilities };
|
|
2895
|
+
if (descriptor.auth) descriptor.auth = { ...existing?.auth, ...descriptor.auth };
|
|
2367
2896
|
const setOrchestrator = args.setOrchestrator || args.orchestratorModel !== void 0;
|
|
2368
2897
|
const setBackground = args.setBackground || args.backgroundModel !== void 0;
|
|
2369
2898
|
if ((setOrchestrator || setBackground) && !isOrchestratorEligibleRuntime(runtime)) {
|
|
@@ -2378,8 +2907,8 @@ async function runNonInteractive(runtime, args) {
|
|
|
2378
2907
|
printError(error instanceof Error ? error.message : String(error));
|
|
2379
2908
|
return 1;
|
|
2380
2909
|
}
|
|
2381
|
-
if (args.apiKey) {
|
|
2382
|
-
auth.setApiKey(
|
|
2910
|
+
if (args.apiKey && apiKeyRef) {
|
|
2911
|
+
auth.setApiKey(apiKeyRef, args.apiKey);
|
|
2383
2912
|
if (credentialWriteFailed(auth, `credential for ${runtime.id} was not stored; target '${descriptor.id}' not saved`))
|
|
2384
2913
|
return 1;
|
|
2385
2914
|
printPlaintextCredentialWarning();
|
|
@@ -2404,12 +2933,14 @@ async function runNonInteractive(runtime, args) {
|
|
|
2404
2933
|
};
|
|
2405
2934
|
applyConfiguration(settings);
|
|
2406
2935
|
updateSettings(applyConfiguration);
|
|
2407
|
-
const probe = await runtimeProbe(runtime, descriptor);
|
|
2936
|
+
const probe = await runtimeProbe(runtime, descriptor, args.apiKey);
|
|
2408
2937
|
if (probe?.ok && probe.models) {
|
|
2409
2938
|
recordTargetModelSnapshot(descriptor, probe.models, probe.modelLabels ? { modelLabels: probe.modelLabels } : {});
|
|
2410
2939
|
}
|
|
2411
2940
|
printSummary(settings, descriptor, probe);
|
|
2412
|
-
if (runtime.auth === "oauth" && !auth.statusForTarget(
|
|
2941
|
+
if (runtime.auth === "oauth" && !auth.statusForTarget(existing ? resolveAuthTarget(existing, runtime) : resolveRuntimeAuthTarget(runtime), {
|
|
2942
|
+
includeFallback: false
|
|
2943
|
+
}).available) {
|
|
2413
2944
|
process.stdout.write(
|
|
2414
2945
|
`note: authenticate ${runtime.id} with \`clio-coder auth login ${runtime.id}\` before using this target
|
|
2415
2946
|
`
|
|
@@ -2541,7 +3072,7 @@ async function runTargetSetupInteractive(rl, runtime, defaults) {
|
|
|
2541
3072
|
let support = buildProviderSupportEntry(runtime);
|
|
2542
3073
|
const initialRuntimeId = runtime.id;
|
|
2543
3074
|
const existingForRuntime = configuredTargetsForRuntime(settings, initialRuntimeId);
|
|
2544
|
-
const existing =
|
|
3075
|
+
const existing = defaults.id ? settings.targets.find((entry) => entry.id === defaults.id && entry.runtime === initialRuntimeId) ?? null : null;
|
|
2545
3076
|
if (existingForRuntime.length > 0) {
|
|
2546
3077
|
process.stdout.write(`
|
|
2547
3078
|
Existing targets for ${runtime.id}:
|
|
@@ -2554,7 +3085,7 @@ Existing targets for ${runtime.id}:
|
|
|
2554
3085
|
process.stdout.write(`
|
|
2555
3086
|
Selected runtime: ${runtime.id} (${support.summary})
|
|
2556
3087
|
`);
|
|
2557
|
-
process.stdout.write(`Credentials: ${describeAuthStatus(runtime)}
|
|
3088
|
+
process.stdout.write(`Credentials: ${describeAuthStatus(runtime, existing ?? void 0)}
|
|
2558
3089
|
`);
|
|
2559
3090
|
if (support.modelHints.length > 0) {
|
|
2560
3091
|
process.stdout.write(`Known models: ${describeRuntimeModels(support, 4)}
|
|
@@ -2601,10 +3132,13 @@ Selected runtime: ${runtime.id} (${support.summary})
|
|
|
2601
3132
|
let apiKeyLiteral;
|
|
2602
3133
|
let apiKeyRef = existing?.auth?.apiKeyRef;
|
|
2603
3134
|
let oauthProfile = runtime.auth === "oauth" ? existing?.auth?.oauthProfile ?? runtime.oauthProviderId ?? runtime.id : void 0;
|
|
2604
|
-
const authStatus = auth.statusForTarget(
|
|
3135
|
+
const authStatus = auth.statusForTarget(
|
|
3136
|
+
existing ? resolveAuthTarget(existing, runtime) : resolveRuntimeAuthTarget(runtime),
|
|
3137
|
+
{ includeFallback: false }
|
|
3138
|
+
);
|
|
2605
3139
|
if (runtime.auth === "api-key") {
|
|
2606
3140
|
const needsCredential = targetRequiresAuth({ id: targetId, runtime: runtime.id }, runtime);
|
|
2607
|
-
const defaultSource = authStatus.source === "stored-api-key" ? "keep" : authStatus.source === "environment" || existing?.auth?.apiKeyEnvVar || needsCredential ? "env" : "skip";
|
|
3141
|
+
const defaultSource = existing?.auth?.apiKeyRef || authStatus.source === "stored-api-key" ? "keep" : authStatus.source === "environment" || existing?.auth?.apiKeyEnvVar || needsCredential ? "env" : "skip";
|
|
2608
3142
|
process.stdout.write(
|
|
2609
3143
|
"\nCredential source: env reads a key from an environment variable, stored writes one to\ncredentials.yaml, keep leaves the current one alone, skip uses no key at all.\n"
|
|
2610
3144
|
);
|
|
@@ -2612,10 +3146,10 @@ Selected runtime: ${runtime.id} (${support.summary})
|
|
|
2612
3146
|
if (choice === null) return 0;
|
|
2613
3147
|
const normalized = choice.trim().toLowerCase();
|
|
2614
3148
|
if (normalized === "stored") {
|
|
2615
|
-
const literal = await
|
|
3149
|
+
const literal = await rl.text("API key literal (stored in credentials.yaml, mode 0600)", "", true);
|
|
2616
3150
|
if (literal !== null && literal.length > 0) {
|
|
2617
3151
|
apiKeyLiteral = literal;
|
|
2618
|
-
apiKeyRef =
|
|
3152
|
+
apiKeyRef = targetApiKeyRef(targetId, settings.targets);
|
|
2619
3153
|
}
|
|
2620
3154
|
} else if (normalized === "env") {
|
|
2621
3155
|
const envDefault = defaults.apiKeyEnv ?? existing?.auth?.apiKeyEnvVar ?? runtime.credentialsEnvVar ?? "";
|
|
@@ -2637,7 +3171,7 @@ Selected runtime: ${runtime.id} (${support.summary})
|
|
|
2637
3171
|
const connected = await loginOAuthRuntime(rl, runtime);
|
|
2638
3172
|
if (!connected) return 1;
|
|
2639
3173
|
}
|
|
2640
|
-
oauthProfile = runtime.oauthProviderId ?? runtime.id;
|
|
3174
|
+
oauthProfile = existing?.auth?.oauthProfile ?? runtime.oauthProviderId ?? runtime.id;
|
|
2641
3175
|
}
|
|
2642
3176
|
let model = defaults.model;
|
|
2643
3177
|
let inventory = { models: [], source: "none" };
|
|
@@ -2654,8 +3188,9 @@ Selected runtime: ${runtime.id} (${support.summary})
|
|
|
2654
3188
|
...existing?.lmstudio ? { lmstudio: existing.lmstudio } : {},
|
|
2655
3189
|
...existing?.litellm ? { litellm: existing.litellm } : {}
|
|
2656
3190
|
});
|
|
3191
|
+
if (existing?.auth?.headers) tentative.auth = { ...tentative.auth, headers: existing.auth.headers };
|
|
2657
3192
|
if (runtime.kind === "http" || runtime.externalAgentLoop?.modelCatalog === "live-authoritative") {
|
|
2658
|
-
inventory = await resolveSupportedWireModels(runtime, tentative, existing ?? void 0);
|
|
3193
|
+
inventory = await resolveSupportedWireModels(runtime, tentative, existing ?? void 0, apiKeyLiteral);
|
|
2659
3194
|
}
|
|
2660
3195
|
const wireModels = inventory.models;
|
|
2661
3196
|
const catalogOrdered = support.modelSource === "catalog";
|
|
@@ -2721,7 +3256,7 @@ Selected runtime: ${runtime.id} (${support.summary})
|
|
|
2721
3256
|
if (!validateContextWindowOverride(runtime, model, contextWindowChoice, defaults.force)) return 2;
|
|
2722
3257
|
const gatewayDefault = defaults.gateway || existing?.gateway === true;
|
|
2723
3258
|
const gatewayAnswer = gatewayDefault ? true : await askYesNo(rl, "Mark as gateway?", false);
|
|
2724
|
-
const
|
|
3259
|
+
const configured = buildDescriptor(runtime, targetId, {
|
|
2725
3260
|
...url !== void 0 ? { url } : {},
|
|
2726
3261
|
...model !== void 0 ? { model } : {},
|
|
2727
3262
|
...apiKeyEnv !== void 0 ? { apiKeyEnv } : {},
|
|
@@ -2735,19 +3270,20 @@ Selected runtime: ${runtime.id} (${support.summary})
|
|
|
2735
3270
|
...existing?.lmstudio ? { lmstudio: existing.lmstudio } : {},
|
|
2736
3271
|
...existing?.litellm ? { litellm: existing.litellm } : {}
|
|
2737
3272
|
});
|
|
3273
|
+
const descriptor = {
|
|
3274
|
+
...existing,
|
|
3275
|
+
...configured,
|
|
3276
|
+
capabilities: { ...existing?.capabilities, ...configured.capabilities }
|
|
3277
|
+
};
|
|
3278
|
+
if (existing?.auth?.headers) descriptor.auth = { ...configured.auth, headers: existing.auth.headers };
|
|
3279
|
+
else if (!configured.auth) delete descriptor.auth;
|
|
2738
3280
|
try {
|
|
2739
3281
|
assertOrchestratorReplacementEligible(settings, descriptor);
|
|
2740
3282
|
} catch (error) {
|
|
2741
3283
|
printError(error instanceof Error ? error.message : String(error));
|
|
2742
3284
|
return 1;
|
|
2743
3285
|
}
|
|
2744
|
-
|
|
2745
|
-
auth.setApiKey(runtime.id, apiKeyLiteral);
|
|
2746
|
-
if (credentialWriteFailed(auth, `credential for ${runtime.id} was not stored; target '${descriptor.id}' not saved`))
|
|
2747
|
-
return 1;
|
|
2748
|
-
printPlaintextCredentialWarning();
|
|
2749
|
-
}
|
|
2750
|
-
const probe = await runtimeProbe(runtime, descriptor);
|
|
3286
|
+
const probe = await runtimeProbe(runtime, descriptor, apiKeyLiteral);
|
|
2751
3287
|
if (probe?.ok && probe.models) recordTargetModelSnapshot(descriptor, probe.models);
|
|
2752
3288
|
if (probe) {
|
|
2753
3289
|
process.stdout.write("\n");
|
|
@@ -2785,6 +3321,12 @@ Selected runtime: ${runtime.id} (${support.summary})
|
|
|
2785
3321
|
settings.context.memory.target === targetId ? settings.context.memory.model ?? model : model
|
|
2786
3322
|
) : void 0;
|
|
2787
3323
|
if (backgroundModel === null) return 0;
|
|
3324
|
+
if (apiKeyLiteral && apiKeyRef) {
|
|
3325
|
+
auth.setApiKey(apiKeyRef, apiKeyLiteral);
|
|
3326
|
+
if (credentialWriteFailed(auth, `credential for ${runtime.id} was not stored; target '${descriptor.id}' not saved`))
|
|
3327
|
+
return 1;
|
|
3328
|
+
printPlaintextCredentialWarning();
|
|
3329
|
+
}
|
|
2788
3330
|
const applyWizardChoice = (target) => {
|
|
2789
3331
|
applyTarget(target, descriptor);
|
|
2790
3332
|
if (setOrchestrator) setOrchestratorPointer(target, descriptor, orchestratorModel);
|
|
@@ -2833,11 +3375,16 @@ function runTargetRename(oldId, newId) {
|
|
|
2833
3375
|
for (const profile of Object.values(settings.fleet.profiles)) {
|
|
2834
3376
|
if (profile.target === oldId) profile.target = newId;
|
|
2835
3377
|
}
|
|
2836
|
-
|
|
3378
|
+
for (const roster of Object.values(settings.fleet.rosters)) {
|
|
3379
|
+
for (const member of roster.members) if (member.target === oldId) member.target = newId;
|
|
3380
|
+
}
|
|
3381
|
+
const renameRef = (entry) => {
|
|
2837
3382
|
const [head, ...rest] = entry.split("/");
|
|
2838
3383
|
if (head !== oldId) return entry;
|
|
2839
3384
|
return rest.length === 0 ? newId : `${newId}/${rest.join("/")}`;
|
|
2840
|
-
}
|
|
3385
|
+
};
|
|
3386
|
+
settings.chat.modelPicker.cycleSet = settings.chat.modelPicker.cycleSet.map(renameRef);
|
|
3387
|
+
settings.chat.modelPicker.favorites = settings.chat.modelPicker.favorites.map(renameRef);
|
|
2841
3388
|
});
|
|
2842
3389
|
printOk(`renamed ${oldId} to ${newId}`);
|
|
2843
3390
|
return 0;
|
|
@@ -2849,27 +3396,42 @@ async function askInteger(io, label, current, apply, min = 0) {
|
|
|
2849
3396
|
const answer = await ask(io.rl, label, String(current));
|
|
2850
3397
|
if (answer === null) return;
|
|
2851
3398
|
const parsed = Number(answer);
|
|
2852
|
-
if (!Number.
|
|
2853
|
-
io.
|
|
3399
|
+
if (!Number.isSafeInteger(parsed) || parsed < min) {
|
|
3400
|
+
io.warn(`${label} must be a whole number of at least ${min}; left at ${current}
|
|
2854
3401
|
`);
|
|
2855
3402
|
return;
|
|
2856
3403
|
}
|
|
2857
|
-
const value =
|
|
3404
|
+
const value = parsed;
|
|
2858
3405
|
apply(value);
|
|
2859
3406
|
io.ok(`${label} set to ${value}`);
|
|
2860
3407
|
}
|
|
2861
3408
|
async function askChoice(io, label, allowed, current, apply) {
|
|
2862
|
-
const answer = await
|
|
3409
|
+
const answer = await io.rl.choose(label, allowed, current);
|
|
2863
3410
|
if (answer === null) return;
|
|
2864
3411
|
const value = answer.trim().toLowerCase();
|
|
2865
3412
|
if (!allowed.includes(value)) {
|
|
2866
|
-
io.
|
|
3413
|
+
io.warn(`${label} must be one of ${allowed.join(", ")}; left at ${current}
|
|
2867
3414
|
`);
|
|
2868
3415
|
return;
|
|
2869
3416
|
}
|
|
2870
3417
|
apply(value);
|
|
2871
3418
|
io.ok(`${label} set to ${value}`);
|
|
2872
3419
|
}
|
|
3420
|
+
async function runTargetWizard(io, options) {
|
|
3421
|
+
const before = readSettings().targets;
|
|
3422
|
+
io.rl.clearScreen();
|
|
3423
|
+
const code = await runOnboardingWizard(io.streams, options);
|
|
3424
|
+
if (code === 130) throw new ConfigureNavigation("quit");
|
|
3425
|
+
if (code !== 0) {
|
|
3426
|
+
await io.rl.text("Press Enter to return");
|
|
3427
|
+
io.warn("Target settings were not saved.");
|
|
3428
|
+
return;
|
|
3429
|
+
}
|
|
3430
|
+
const changed = readSettings().targets.find(
|
|
3431
|
+
(target) => JSON.stringify(target) !== JSON.stringify(before.find((entry) => entry.id === target.id))
|
|
3432
|
+
);
|
|
3433
|
+
if (changed) io.ok(`Target ${changed.id} saved`);
|
|
3434
|
+
}
|
|
2873
3435
|
var SECTIONS = [
|
|
2874
3436
|
{
|
|
2875
3437
|
id: "targets",
|
|
@@ -2900,6 +3462,10 @@ var SECTIONS = [
|
|
|
2900
3462
|
label: "Add a target",
|
|
2901
3463
|
hint: "register a provider endpoint",
|
|
2902
3464
|
run: async (io) => {
|
|
3465
|
+
if (canRunOnboarding(io.streams)) {
|
|
3466
|
+
await runTargetWizard(io, { mode: readSettings().targets.length === 0 ? "first" : "add" });
|
|
3467
|
+
return;
|
|
3468
|
+
}
|
|
2903
3469
|
const runtime = await pickRuntimeViaCategory(io.rl);
|
|
2904
3470
|
if (runtime) await runTargetSetupInteractive(io.rl, runtime, emptyArgs());
|
|
2905
3471
|
}
|
|
@@ -2924,17 +3490,59 @@ var SECTIONS = [
|
|
|
2924
3490
|
const settings = readSettings();
|
|
2925
3491
|
const ids = settings.targets.map((target) => target.id);
|
|
2926
3492
|
if (ids.length === 0) {
|
|
2927
|
-
io.
|
|
3493
|
+
io.warn("No targets to remove.");
|
|
2928
3494
|
return;
|
|
2929
3495
|
}
|
|
2930
3496
|
io.out.write(` Registered: ${ids.join(", ")}
|
|
2931
3497
|
`);
|
|
2932
|
-
const chosen = await
|
|
3498
|
+
const chosen = await io.rl.choose("Target to remove", ids, ids[0] ?? "");
|
|
2933
3499
|
if (chosen === null || !ids.includes(chosen)) return;
|
|
2934
3500
|
if (await askYesNo(io.rl, `Remove target '${chosen}'?`, false)) {
|
|
2935
|
-
runTargetRemove(chosen);
|
|
3501
|
+
if (runTargetRemove(chosen) === 0) io.ok(`Removed target ${chosen}`);
|
|
3502
|
+
else io.warn(`Could not remove target ${chosen}`);
|
|
3503
|
+
}
|
|
3504
|
+
}
|
|
3505
|
+
},
|
|
3506
|
+
{
|
|
3507
|
+
label: "Edit a target",
|
|
3508
|
+
hint: "endpoint, credentials, model, capabilities",
|
|
3509
|
+
run: async (io) => {
|
|
3510
|
+
const targets = readSettings().targets;
|
|
3511
|
+
if (targets.length === 0) return;
|
|
3512
|
+
const id = await io.rl.choose(
|
|
3513
|
+
"Target to edit",
|
|
3514
|
+
targets.map((target2) => target2.id),
|
|
3515
|
+
targets[0]?.id ?? ""
|
|
3516
|
+
);
|
|
3517
|
+
const target = targets.find((entry) => entry.id === id);
|
|
3518
|
+
if (!target) return;
|
|
3519
|
+
if (canRunOnboarding(io.streams)) {
|
|
3520
|
+
await runTargetWizard(io, { mode: "edit", target });
|
|
3521
|
+
} else {
|
|
3522
|
+
const runtime = getRuntimeRegistry().get(target.runtime);
|
|
3523
|
+
if (runtime) await runTargetSetupInteractive(io.rl, runtime, { ...emptyArgs(), id });
|
|
3524
|
+
}
|
|
3525
|
+
}
|
|
3526
|
+
},
|
|
3527
|
+
{
|
|
3528
|
+
label: "Rename a target",
|
|
3529
|
+
run: async (io) => {
|
|
3530
|
+
const ids = readSettings().targets.map((target) => target.id);
|
|
3531
|
+
if (ids.length === 0) return;
|
|
3532
|
+
const id = await io.rl.choose("Target to rename", ids, ids[0] ?? "");
|
|
3533
|
+
const name = await ask(io.rl, "New target id", id);
|
|
3534
|
+
if (!name || name === id) return;
|
|
3535
|
+
if (ids.includes(name)) {
|
|
3536
|
+
io.warn(`Target id already exists: ${name}`);
|
|
3537
|
+
return;
|
|
2936
3538
|
}
|
|
3539
|
+
if (runTargetRename(id, name) === 0) io.ok(`Renamed ${id} to ${name}`);
|
|
3540
|
+
else io.warn(`Could not rename target ${id}`);
|
|
2937
3541
|
}
|
|
3542
|
+
},
|
|
3543
|
+
{
|
|
3544
|
+
label: "Set the background memory target",
|
|
3545
|
+
run: async (io) => assignTarget(io, "memory")
|
|
2938
3546
|
}
|
|
2939
3547
|
]
|
|
2940
3548
|
},
|
|
@@ -2992,8 +3600,10 @@ var SECTIONS = [
|
|
|
2992
3600
|
readSettings().chat.model ?? ""
|
|
2993
3601
|
);
|
|
2994
3602
|
if (model === null) return;
|
|
2995
|
-
|
|
2996
|
-
|
|
3603
|
+
updateSavedSettingsDocument((saved) => {
|
|
3604
|
+
const document = saved;
|
|
3605
|
+
document.chat = { ...document.chat, model: model.length > 0 ? model : null };
|
|
3606
|
+
return document;
|
|
2997
3607
|
});
|
|
2998
3608
|
io.ok(model.length > 0 ? `Chat default model set to ${model}` : "Chat default model cleared");
|
|
2999
3609
|
}
|
|
@@ -3149,7 +3759,7 @@ var SECTIONS = [
|
|
|
3149
3759
|
}
|
|
3150
3760
|
const parsed = Number(answer);
|
|
3151
3761
|
if (!Number.isFinite(parsed) || parsed < 1) {
|
|
3152
|
-
io.
|
|
3762
|
+
io.warn(`Concurrency limit must be auto or at least 1; left at ${current}
|
|
3153
3763
|
`);
|
|
3154
3764
|
return;
|
|
3155
3765
|
}
|
|
@@ -3194,7 +3804,7 @@ var SECTIONS = [
|
|
|
3194
3804
|
if (answer === null) return;
|
|
3195
3805
|
const parsed = Number(answer);
|
|
3196
3806
|
if (!Number.isFinite(parsed) || parsed < 1) {
|
|
3197
|
-
io.
|
|
3807
|
+
io.warn(`Run timeout must be at least 1 second; left at ${current}s
|
|
3198
3808
|
`);
|
|
3199
3809
|
return;
|
|
3200
3810
|
}
|
|
@@ -3224,22 +3834,16 @@ var SECTIONS = [
|
|
|
3224
3834
|
actions: [
|
|
3225
3835
|
{
|
|
3226
3836
|
label: "Autonomy level",
|
|
3227
|
-
hint: "
|
|
3837
|
+
hint: AUTONOMY_LEVELS.join(" | "),
|
|
3228
3838
|
run: async (io) => {
|
|
3229
3839
|
io.out.write(
|
|
3230
|
-
"
|
|
3231
|
-
);
|
|
3232
|
-
await askChoice(
|
|
3233
|
-
io,
|
|
3234
|
-
"Autonomy level",
|
|
3235
|
-
["interactive", "assisted", "auto-edit", "full"],
|
|
3236
|
-
readSettings().safety.autonomy,
|
|
3237
|
-
(value) => {
|
|
3238
|
-
updateSettings((draft) => {
|
|
3239
|
-
draft.safety.autonomy = value;
|
|
3240
|
-
});
|
|
3241
|
-
}
|
|
3840
|
+
" read-only inspects; suggest asks before changes; auto-edit permits workspace\n edits; full-auto skips autonomy prompts. Safety rules still apply at every level.\n"
|
|
3242
3841
|
);
|
|
3842
|
+
await askChoice(io, "Autonomy level", AUTONOMY_LEVELS, readSettings().safety.autonomy, (value) => {
|
|
3843
|
+
updateSettings((draft) => {
|
|
3844
|
+
draft.safety.autonomy = value;
|
|
3845
|
+
});
|
|
3846
|
+
});
|
|
3243
3847
|
}
|
|
3244
3848
|
},
|
|
3245
3849
|
{
|
|
@@ -3268,7 +3872,7 @@ var SECTIONS = [
|
|
|
3268
3872
|
if (answer === null) return;
|
|
3269
3873
|
const parsed = Number(answer);
|
|
3270
3874
|
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
3271
|
-
io.
|
|
3875
|
+
io.warn(`Session cost limit must be greater than 0; left at $${current}
|
|
3272
3876
|
`);
|
|
3273
3877
|
return;
|
|
3274
3878
|
}
|
|
@@ -3319,7 +3923,7 @@ var SECTIONS = [
|
|
|
3319
3923
|
["Panes capability", settings.interface.panes.enabled],
|
|
3320
3924
|
["Startup layout", settings.interface.panes.layout],
|
|
3321
3925
|
["TUI mode", settings.interface.mode],
|
|
3322
|
-
["Output
|
|
3926
|
+
["Output style", settings.interface.outputDetail],
|
|
3323
3927
|
["Desktop notifications", onOff(settings.interface.desktopNotifications)],
|
|
3324
3928
|
["Git commit attribution", onOff(settings.integrations.git.commitAttribution)]
|
|
3325
3929
|
];
|
|
@@ -3371,13 +3975,13 @@ var SECTIONS = [
|
|
|
3371
3975
|
}
|
|
3372
3976
|
},
|
|
3373
3977
|
{
|
|
3374
|
-
label: "Output
|
|
3375
|
-
hint: "
|
|
3978
|
+
label: "Output style",
|
|
3979
|
+
hint: "compact | standard | detailed",
|
|
3376
3980
|
run: async (io) => {
|
|
3377
3981
|
await askChoice(
|
|
3378
3982
|
io,
|
|
3379
|
-
"Output
|
|
3380
|
-
["
|
|
3983
|
+
"Output style",
|
|
3984
|
+
["compact", "standard", "detailed"],
|
|
3381
3985
|
readSettings().interface.outputDetail,
|
|
3382
3986
|
(value) => {
|
|
3383
3987
|
updateSettings((draft) => {
|
|
@@ -3489,23 +4093,44 @@ var SECTIONS = [
|
|
|
3489
4093
|
{
|
|
3490
4094
|
label: "Run doctor",
|
|
3491
4095
|
hint: "read-only health check",
|
|
3492
|
-
run: async () => {
|
|
3493
|
-
const { runDoctorCommand } = await import("./doctor-
|
|
4096
|
+
run: async (io) => {
|
|
4097
|
+
const { runDoctorCommand } = await import("./doctor-JJVGPZWT.js");
|
|
3494
4098
|
await runDoctorCommand([]);
|
|
4099
|
+
await io.rl.text("Press Enter to return");
|
|
3495
4100
|
}
|
|
3496
4101
|
},
|
|
3497
4102
|
{
|
|
3498
4103
|
label: "Show raw settings.yaml",
|
|
3499
4104
|
run: async (io) => {
|
|
3500
4105
|
const file = settingsPath();
|
|
3501
|
-
if (!
|
|
4106
|
+
if (!existsSync2(file)) {
|
|
3502
4107
|
io.out.write(" settings.yaml does not exist yet.\n");
|
|
3503
4108
|
return;
|
|
3504
4109
|
}
|
|
3505
4110
|
io.out.write(`
|
|
3506
4111
|
--- ${shortenPath(file)} ---
|
|
3507
|
-
${
|
|
4112
|
+
${readFileSync2(file, "utf8")}--- end ---
|
|
3508
4113
|
`);
|
|
4114
|
+
await io.rl.text("Press Enter to return");
|
|
4115
|
+
}
|
|
4116
|
+
}
|
|
4117
|
+
]
|
|
4118
|
+
},
|
|
4119
|
+
{
|
|
4120
|
+
id: "advanced",
|
|
4121
|
+
title: "All Settings",
|
|
4122
|
+
summary: "validated editor for every setting",
|
|
4123
|
+
aliases: ["all", "settings"],
|
|
4124
|
+
fields: () => [
|
|
4125
|
+
["Settings file", shortenPath(settingsPath())],
|
|
4126
|
+
["Reference", "clio-coder docs configuration-reference"]
|
|
4127
|
+
],
|
|
4128
|
+
actions: [
|
|
4129
|
+
{
|
|
4130
|
+
label: "Edit all settings",
|
|
4131
|
+
hint: "VISUAL / EDITOR; validate before saving",
|
|
4132
|
+
run: async (io) => {
|
|
4133
|
+
if (await editSettings(io.rl)) io.ok("Settings saved; previous file kept at settings.yaml.bak");
|
|
3509
4134
|
}
|
|
3510
4135
|
}
|
|
3511
4136
|
]
|
|
@@ -3519,6 +4144,9 @@ function emptyArgs() {
|
|
|
3519
4144
|
all: false,
|
|
3520
4145
|
interop: false,
|
|
3521
4146
|
json: false,
|
|
4147
|
+
edit: false,
|
|
4148
|
+
quick: false,
|
|
4149
|
+
settings: false,
|
|
3522
4150
|
force: false,
|
|
3523
4151
|
gateway: false,
|
|
3524
4152
|
setOrchestrator: false,
|
|
@@ -3535,39 +4163,47 @@ async function askList(io, label, current, apply) {
|
|
|
3535
4163
|
}
|
|
3536
4164
|
async function assignTarget(io, role) {
|
|
3537
4165
|
const settings = readSettings();
|
|
3538
|
-
const ids = settings.targets.
|
|
4166
|
+
const ids = settings.targets.filter((target2) => {
|
|
4167
|
+
const runtime = getRuntimeRegistry().get(target2.runtime);
|
|
4168
|
+
return role === "fleet" || runtime !== null && isOrchestratorEligibleRuntime(runtime);
|
|
4169
|
+
}).map((target2) => target2.id);
|
|
3539
4170
|
if (ids.length === 0) {
|
|
3540
|
-
io.
|
|
4171
|
+
io.warn("No eligible targets registered yet. Add one first.");
|
|
3541
4172
|
return;
|
|
3542
4173
|
}
|
|
3543
4174
|
io.out.write(` Registered: ${ids.join(", ")}
|
|
3544
4175
|
`);
|
|
3545
|
-
const currentTarget = role === "chat" ? settings.chat.target : settings.fleet.default.target;
|
|
3546
|
-
const
|
|
4176
|
+
const currentTarget = role === "chat" ? settings.chat.target : role === "fleet" ? settings.fleet.default.target : settings.context.memory.target;
|
|
4177
|
+
const label = role === "chat" ? "Chat" : role === "fleet" ? "Fleet" : "Background memory";
|
|
4178
|
+
const chosen = await io.rl.choose(`${label} target`, ids, currentTarget ?? ids[0] ?? "");
|
|
3547
4179
|
if (chosen === null) return;
|
|
3548
4180
|
if (!ids.includes(chosen)) {
|
|
3549
|
-
io.
|
|
3550
|
-
`);
|
|
4181
|
+
io.warn(`${chosen} is not a registered target; nothing changed.`);
|
|
3551
4182
|
return;
|
|
3552
4183
|
}
|
|
3553
4184
|
const target = settings.targets.find((entry) => entry.id === chosen);
|
|
3554
|
-
const model = await ask(io.rl,
|
|
4185
|
+
const model = await ask(io.rl, `Model override (blank uses ${target?.defaultModel ?? "the target default"})`, "");
|
|
3555
4186
|
if (model === null) return;
|
|
3556
4187
|
updateSettings((draft) => {
|
|
3557
4188
|
if (role === "chat") {
|
|
3558
4189
|
draft.chat.target = chosen;
|
|
3559
4190
|
draft.chat.model = model.length > 0 ? model : null;
|
|
3560
|
-
} else {
|
|
4191
|
+
} else if (role === "fleet") {
|
|
3561
4192
|
draft.fleet.default.target = chosen;
|
|
3562
4193
|
draft.fleet.default.model = model.length > 0 ? model : null;
|
|
4194
|
+
} else {
|
|
4195
|
+
draft.context.memory.target = chosen;
|
|
4196
|
+
draft.context.memory.model = model.length > 0 ? model : null;
|
|
3563
4197
|
}
|
|
3564
4198
|
});
|
|
3565
|
-
io.ok(`${
|
|
4199
|
+
io.ok(`${label} target set to ${chosen}`);
|
|
3566
4200
|
}
|
|
3567
|
-
async function pickEntry(rl, io, entries, backLabel, plain) {
|
|
4201
|
+
async function pickEntry(rl, io, entries, backLabel, plain, initialIndex = 0) {
|
|
3568
4202
|
const out = io.out;
|
|
3569
4203
|
if (canSelect(io.in, out)) {
|
|
3570
4204
|
const result = await promptSelect({
|
|
4205
|
+
initialIndex,
|
|
4206
|
+
clearOnExit: true,
|
|
3571
4207
|
choices: entries.map((entry, index2) => ({
|
|
3572
4208
|
value: index2,
|
|
3573
4209
|
label: entry.label,
|
|
@@ -3608,40 +4244,98 @@ function renderSection(spec, out) {
|
|
|
3608
4244
|
return presenter;
|
|
3609
4245
|
}
|
|
3610
4246
|
async function runSection(rl, streams, spec, backLabel) {
|
|
4247
|
+
let selected = 0;
|
|
4248
|
+
let notice;
|
|
3611
4249
|
for (; ; ) {
|
|
4250
|
+
rl.clearScreen();
|
|
3612
4251
|
const presenter = renderSection(spec, streams.out);
|
|
4252
|
+
if (notice) {
|
|
4253
|
+
if (notice.warning) presenter.warn(notice.text);
|
|
4254
|
+
else presenter.completedStep(notice.text);
|
|
4255
|
+
notice = void 0;
|
|
4256
|
+
}
|
|
3613
4257
|
const io = {
|
|
3614
4258
|
rl,
|
|
3615
4259
|
out: streams.out,
|
|
3616
4260
|
streams,
|
|
3617
4261
|
ok: (text) => {
|
|
3618
|
-
|
|
4262
|
+
notice = { text, warning: false };
|
|
4263
|
+
},
|
|
4264
|
+
warn: (text) => {
|
|
4265
|
+
notice = { text: text.trim(), warning: true };
|
|
3619
4266
|
}
|
|
3620
4267
|
};
|
|
3621
4268
|
presenter.blank();
|
|
3622
|
-
const choice = await pickEntry(rl, streams, spec.actions, backLabel, presenter.isPlain());
|
|
4269
|
+
const choice = await pickEntry(rl, streams, spec.actions, backLabel, presenter.isPlain(), selected);
|
|
3623
4270
|
if (choice.kind !== "index") return choice.kind;
|
|
3624
|
-
|
|
3625
|
-
|
|
4271
|
+
selected = choice.index;
|
|
4272
|
+
const action = spec.actions[selected];
|
|
4273
|
+
try {
|
|
4274
|
+
if (action !== void 0) await action.run(io);
|
|
4275
|
+
} catch (error) {
|
|
4276
|
+
if (error instanceof ConfigureNavigation) {
|
|
4277
|
+
if (error.kind === "quit") return "quit";
|
|
4278
|
+
} else
|
|
4279
|
+
notice = { text: `Change not saved: ${error instanceof Error ? error.message : String(error)}`, warning: true };
|
|
4280
|
+
}
|
|
3626
4281
|
}
|
|
3627
4282
|
}
|
|
3628
|
-
async function runConfigSectionsMenu(rl, streams) {
|
|
4283
|
+
async function runConfigSectionsMenu(rl, streams, backLabel = "quit") {
|
|
4284
|
+
let selected = 0;
|
|
3629
4285
|
for (; ; ) {
|
|
4286
|
+
rl.clearScreen();
|
|
3630
4287
|
const presenter = createLifecyclePresenter({ stream: streams.out });
|
|
3631
|
-
presenter.header("Clio Coder
|
|
4288
|
+
presenter.header("Clio Coder Settings", "configure");
|
|
3632
4289
|
presenter.note(`Source: ${shortenPath(settingsPath())}`);
|
|
3633
4290
|
presenter.blank();
|
|
3634
4291
|
const choice = await pickEntry(
|
|
3635
4292
|
rl,
|
|
3636
4293
|
streams,
|
|
3637
4294
|
SECTIONS.map((section) => ({ label: section.title, hint: section.summary })),
|
|
3638
|
-
|
|
3639
|
-
presenter.isPlain()
|
|
4295
|
+
backLabel,
|
|
4296
|
+
presenter.isPlain(),
|
|
4297
|
+
selected
|
|
3640
4298
|
);
|
|
3641
|
-
if (choice.kind !== "index") return
|
|
3642
|
-
|
|
4299
|
+
if (choice.kind !== "index") return choice.kind;
|
|
4300
|
+
selected = choice.index;
|
|
4301
|
+
const spec = SECTIONS[selected];
|
|
3643
4302
|
if (spec === void 0) continue;
|
|
3644
|
-
if (await runSection(rl, streams, spec, "back") === "quit") return
|
|
4303
|
+
if (await runSection(rl, streams, spec, "back") === "quit") return "quit";
|
|
4304
|
+
}
|
|
4305
|
+
}
|
|
4306
|
+
async function runConfigLauncher(rl, streams) {
|
|
4307
|
+
let selected = 0;
|
|
4308
|
+
const exitCode = () => readSettings().chat.target ? 0 : 130;
|
|
4309
|
+
for (; ; ) {
|
|
4310
|
+
rl.clearScreen();
|
|
4311
|
+
const presenter = createLifecyclePresenter({ stream: streams.out });
|
|
4312
|
+
presenter.header("Clio Coder", "configure");
|
|
4313
|
+
presenter.note("Connect a model and start coding. Everything else is optional.");
|
|
4314
|
+
presenter.blank();
|
|
4315
|
+
const choice = await pickEntry(
|
|
4316
|
+
rl,
|
|
4317
|
+
streams,
|
|
4318
|
+
[
|
|
4319
|
+
{ label: "Quick Connect", hint: "endpoint \u2192 model \u2192 ready" },
|
|
4320
|
+
{ label: "Settings", hint: "all configuration options" },
|
|
4321
|
+
{ label: "Diagnostics", hint: "check an existing installation" }
|
|
4322
|
+
],
|
|
4323
|
+
"quit",
|
|
4324
|
+
presenter.isPlain(),
|
|
4325
|
+
selected
|
|
4326
|
+
);
|
|
4327
|
+
if (choice.kind !== "index") return exitCode();
|
|
4328
|
+
selected = choice.index;
|
|
4329
|
+
if (selected === 0) {
|
|
4330
|
+
const result = await runQuickConnect(rl);
|
|
4331
|
+
if (result === "connected") return 0;
|
|
4332
|
+
if (result === "quit") return exitCode();
|
|
4333
|
+
} else if (selected === 1) {
|
|
4334
|
+
if (await runConfigSectionsMenu(rl, streams, "back") === "quit") return exitCode();
|
|
4335
|
+
} else {
|
|
4336
|
+
const section = findSection("diagnostics");
|
|
4337
|
+
if (section && await runSection(rl, streams, section, "back") === "quit") return exitCode();
|
|
4338
|
+
}
|
|
3645
4339
|
}
|
|
3646
4340
|
}
|
|
3647
4341
|
function findSection(name) {
|
|
@@ -3650,7 +4344,23 @@ function findSection(name) {
|
|
|
3650
4344
|
}
|
|
3651
4345
|
var SECTION_IDS = SECTIONS.map((section) => section.id);
|
|
3652
4346
|
async function runInteractive(rl, preselectedRuntime, defaults, streams) {
|
|
4347
|
+
if (defaults.quick) {
|
|
4348
|
+
if (!canRunOnboarding(streams)) {
|
|
4349
|
+
printError("--quick needs a terminal; use --id and --runtime for unattended setup");
|
|
4350
|
+
return 2;
|
|
4351
|
+
}
|
|
4352
|
+
return await runQuickConnect(rl) === "connected" ? 0 : 130;
|
|
4353
|
+
}
|
|
4354
|
+
if (defaults.settings) {
|
|
4355
|
+
await runConfigSectionsMenu(rl, streams);
|
|
4356
|
+
return 0;
|
|
4357
|
+
}
|
|
3653
4358
|
if (preselectedRuntime) {
|
|
4359
|
+
if (canRunOnboarding(streams))
|
|
4360
|
+
return runOnboardingWizard(streams, {
|
|
4361
|
+
mode: readSettings().targets.length === 0 ? "first" : "add",
|
|
4362
|
+
runtime: preselectedRuntime
|
|
4363
|
+
});
|
|
3654
4364
|
return await runTargetSetupInteractive(rl, preselectedRuntime, defaults);
|
|
3655
4365
|
}
|
|
3656
4366
|
if (defaults.section !== void 0) {
|
|
@@ -3666,11 +4376,8 @@ async function runInteractive(rl, preselectedRuntime, defaults, streams) {
|
|
|
3666
4376
|
await runSection(rl, streams, spec, "quit");
|
|
3667
4377
|
return 0;
|
|
3668
4378
|
}
|
|
4379
|
+
if (canRunOnboarding(streams)) return runConfigLauncher(rl, streams);
|
|
3669
4380
|
if (readSettings().targets.length === 0) {
|
|
3670
|
-
if (canRunOnboarding(streams)) {
|
|
3671
|
-
rl.close();
|
|
3672
|
-
return await runOnboardingWizard(streams);
|
|
3673
|
-
}
|
|
3674
4381
|
const runtime = await pickRuntimeViaCategory(rl);
|
|
3675
4382
|
if (!runtime) {
|
|
3676
4383
|
printError("configuration cancelled");
|
|
@@ -3678,7 +4385,8 @@ async function runInteractive(rl, preselectedRuntime, defaults, streams) {
|
|
|
3678
4385
|
}
|
|
3679
4386
|
return await runTargetSetupInteractive(rl, runtime, defaults);
|
|
3680
4387
|
}
|
|
3681
|
-
|
|
4388
|
+
await runConfigSectionsMenu(rl, streams);
|
|
4389
|
+
return 0;
|
|
3682
4390
|
}
|
|
3683
4391
|
async function runConfigureCommand(argv, inStream = input, outStream = output2) {
|
|
3684
4392
|
let args;
|
|
@@ -3693,8 +4401,21 @@ async function runConfigureCommand(argv, inStream = input, outStream = output2)
|
|
|
3693
4401
|
process.stdout.write(HELP);
|
|
3694
4402
|
return 0;
|
|
3695
4403
|
}
|
|
3696
|
-
initializeClioHome();
|
|
3697
4404
|
ensureRegistryPopulated();
|
|
4405
|
+
if (args.edit) {
|
|
4406
|
+
if (!inStream.isTTY || !outStream.isTTY) {
|
|
4407
|
+
printError("--edit needs a terminal; use configure --json to inspect settings without one");
|
|
4408
|
+
return 2;
|
|
4409
|
+
}
|
|
4410
|
+
try {
|
|
4411
|
+
await editSettings(new ConfigurePrompts(inStream, outStream));
|
|
4412
|
+
return 0;
|
|
4413
|
+
} catch (error) {
|
|
4414
|
+
if (error instanceof ConfigureNavigation) return 0;
|
|
4415
|
+
printError(error instanceof Error ? error.message : String(error));
|
|
4416
|
+
return 1;
|
|
4417
|
+
}
|
|
4418
|
+
}
|
|
3698
4419
|
if (args.json) {
|
|
3699
4420
|
const settings = readSettings();
|
|
3700
4421
|
outStream.write(`${JSON.stringify(settings, null, 2)}
|
|
@@ -3706,13 +4427,9 @@ async function runConfigureCommand(argv, inStream = input, outStream = output2)
|
|
|
3706
4427
|
return 0;
|
|
3707
4428
|
}
|
|
3708
4429
|
if (args.interop) {
|
|
3709
|
-
if (!
|
|
3710
|
-
const rl2 =
|
|
3711
|
-
|
|
3712
|
-
return await runInteropReview({ rl: rl2, streams: { in: input, out: output2 } });
|
|
3713
|
-
} finally {
|
|
3714
|
-
rl2.close();
|
|
3715
|
-
}
|
|
4430
|
+
if (!inStream.isTTY) return runInteropReview({ rl: null });
|
|
4431
|
+
const rl2 = new ConfigurePrompts(inStream, outStream);
|
|
4432
|
+
return runInteropReview({ rl: rl2, streams: { in: inStream, out: outStream } });
|
|
3716
4433
|
}
|
|
3717
4434
|
if (args.remove) return runTargetRemove(args.remove);
|
|
3718
4435
|
if (args.renameOld && args.renameNew) return runTargetRename(args.renameOld, args.renameNew);
|
|
@@ -3735,23 +4452,26 @@ async function runConfigureCommand(argv, inStream = input, outStream = output2)
|
|
|
3735
4452
|
warnLegacyNaming(runtimeId, runtime.id);
|
|
3736
4453
|
}
|
|
3737
4454
|
}
|
|
3738
|
-
const hasTargetSetupFlag = args.id !== void 0 || args.url !== void 0 || args.model !== void 0 || args.workerProfile !== void 0 || args.workerProfileModel !== void 0 || args.apiKey !== void 0 || args.apiKeyEnv !== void 0 || args.gateway || args.lifecycle !== void 0 || args.setOrchestrator || args.setWorkerDefault || args.contextWindow !== void 0 || args.maxTokens !== void 0 || args.reasoning !== void 0;
|
|
4455
|
+
const hasTargetSetupFlag = args.id !== void 0 || args.url !== void 0 || args.model !== void 0 || args.workerProfile !== void 0 || args.workerProfileModel !== void 0 || args.apiKey !== void 0 || args.apiKeyEnv !== void 0 || args.gateway || args.lifecycle !== void 0 || args.setOrchestrator || args.setBackground || args.backgroundModel !== void 0 || args.orchestratorModel !== void 0 || args.workerModel !== void 0 || args.bindAgent !== void 0 || args.setWorkerDefault || args.contextWindow !== void 0 || args.maxTokens !== void 0 || args.reasoning !== void 0;
|
|
3739
4456
|
const nonInteractive = runtime !== null && hasTargetSetupFlag;
|
|
3740
4457
|
if (nonInteractive && runtime) return runNonInteractive(runtime, args);
|
|
3741
|
-
if ((runtimeId !== void 0 || hasTargetSetupFlag) && !
|
|
4458
|
+
if ((runtimeId !== void 0 || hasTargetSetupFlag) && !inStream.isTTY) {
|
|
3742
4459
|
printError(
|
|
3743
4460
|
runtime === null ? "--runtime is required when configuring a target non-interactively" : "--id is required when passing flags non-interactively"
|
|
3744
4461
|
);
|
|
3745
4462
|
return 2;
|
|
3746
4463
|
}
|
|
3747
|
-
const rl =
|
|
4464
|
+
const rl = new ConfigurePrompts(inStream, outStream);
|
|
3748
4465
|
try {
|
|
3749
4466
|
return await runInteractive(rl, runtime, args, { in: inStream, out: outStream });
|
|
3750
4467
|
} catch (err) {
|
|
4468
|
+
if (err instanceof ConfigureNavigation) {
|
|
4469
|
+
if (readSettings().targets.length > 0) return 0;
|
|
4470
|
+
printError("configuration cancelled");
|
|
4471
|
+
return 130;
|
|
4472
|
+
}
|
|
3751
4473
|
printError(err instanceof Error ? err.message : String(err));
|
|
3752
4474
|
return 1;
|
|
3753
|
-
} finally {
|
|
3754
|
-
rl.close();
|
|
3755
4475
|
}
|
|
3756
4476
|
}
|
|
3757
4477
|
|
|
@@ -3761,4 +4481,4 @@ export {
|
|
|
3761
4481
|
runTargetRename,
|
|
3762
4482
|
runConfigureCommand
|
|
3763
4483
|
};
|
|
3764
|
-
//# sourceMappingURL=chunk-
|
|
4484
|
+
//# sourceMappingURL=chunk-F5Z7EWMN.js.map
|