codealmanac 0.2.3 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -6
- package/dist/agents-4Y7X24WW.js +25 -0
- package/dist/chunk-BF2J4XTC.js +766 -0
- package/dist/chunk-BF2J4XTC.js.map +1 -0
- package/dist/{chunk-HNVOYWC2.js → chunk-CW4HRLMS.js} +88 -7
- package/dist/chunk-CW4HRLMS.js.map +1 -0
- package/dist/{chunk-P3LDTCLB.js → chunk-H37GKBWI.js} +13 -1
- package/dist/chunk-H37GKBWI.js.map +1 -0
- package/dist/{chunk-NBVIEZZQ.js → chunk-H6QKCB7M.js} +2 -2
- package/dist/{chunk-QQHIVTXT.js → chunk-MRRX4UQB.js} +4 -4
- package/dist/{chunk-QQHIVTXT.js.map → chunk-MRRX4UQB.js.map} +1 -1
- package/dist/chunk-P5WGG4FJ.js +359 -0
- package/dist/chunk-P5WGG4FJ.js.map +1 -0
- package/dist/{chunk-XNTNXEWY.js → chunk-QRK3JLFX.js} +131 -49
- package/dist/chunk-QRK3JLFX.js.map +1 -0
- package/dist/{chunk-V3QOQSXI.js → chunk-TILAKDN6.js} +14 -8
- package/dist/chunk-TILAKDN6.js.map +1 -0
- package/dist/chunk-TT6ZP4GS.js +282 -0
- package/dist/chunk-TT6ZP4GS.js.map +1 -0
- package/dist/chunk-UU6FBRQO.js +187 -0
- package/dist/chunk-UU6FBRQO.js.map +1 -0
- package/dist/{cli-6BOB6KAN.js → cli-MYMZ66EN.js} +123 -33
- package/dist/cli-MYMZ66EN.js.map +1 -0
- package/dist/codealmanac.js +1 -1
- package/dist/config-ML2RCR7J.js +16 -0
- package/dist/doctor-W5KQQLAX.js +17 -0
- package/dist/{register-commands-IXYE5CNZ.js → register-commands-XTK2G2FB.js} +293 -395
- package/dist/register-commands-XTK2G2FB.js.map +1 -0
- package/dist/uninstall-N7JY7ZV2.js +15 -0
- package/dist/{update-RAF7QRYF.js → update-P2IPG7RO.js} +3 -3
- package/guides/mini.md +1 -1
- package/guides/reference.md +68 -9
- package/package.json +1 -1
- package/dist/agents-RVYQ44DB.js +0 -16
- package/dist/auth-S5DVUIUJ.js +0 -18
- package/dist/chunk-HNVOYWC2.js.map +0 -1
- package/dist/chunk-P3LDTCLB.js.map +0 -1
- package/dist/chunk-PIYJQE4Z.js +0 -102
- package/dist/chunk-PIYJQE4Z.js.map +0 -1
- package/dist/chunk-SSYMRT4I.js +0 -126
- package/dist/chunk-SSYMRT4I.js.map +0 -1
- package/dist/chunk-TWM7I2LU.js +0 -116
- package/dist/chunk-TWM7I2LU.js.map +0 -1
- package/dist/chunk-V3QOQSXI.js.map +0 -1
- package/dist/chunk-WRUSDYYE.js +0 -97
- package/dist/chunk-WRUSDYYE.js.map +0 -1
- package/dist/chunk-XNTNXEWY.js.map +0 -1
- package/dist/cli-6BOB6KAN.js.map +0 -1
- package/dist/doctor-DD7EQGCA.js +0 -18
- package/dist/register-commands-IXYE5CNZ.js.map +0 -1
- package/dist/uninstall-OBV4Z3JE.js +0 -16
- /package/dist/{agents-RVYQ44DB.js.map → agents-4Y7X24WW.js.map} +0 -0
- /package/dist/{chunk-NBVIEZZQ.js.map → chunk-H6QKCB7M.js.map} +0 -0
- /package/dist/{auth-S5DVUIUJ.js.map → config-ML2RCR7J.js.map} +0 -0
- /package/dist/{doctor-DD7EQGCA.js.map → doctor-W5KQQLAX.js.map} +0 -0
- /package/dist/{uninstall-OBV4Z3JE.js.map → uninstall-N7JY7ZV2.js.map} +0 -0
- /package/dist/{update-RAF7QRYF.js.map → update-P2IPG7RO.js.map} +0 -0
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
findNearestAlmanacDir,
|
|
4
|
+
getGlobalAlmanacDir,
|
|
5
|
+
getRepoAlmanacDir
|
|
6
|
+
} from "./chunk-7JUX4ADQ.js";
|
|
7
|
+
|
|
8
|
+
// src/update/config.ts
|
|
9
|
+
import { existsSync } from "fs";
|
|
10
|
+
import { mkdir, readFile, rename, writeFile } from "fs/promises";
|
|
11
|
+
import { dirname, join } from "path";
|
|
12
|
+
var AGENT_PROVIDER_IDS = ["claude", "codex", "cursor"];
|
|
13
|
+
function isAgentProviderId(value) {
|
|
14
|
+
return AGENT_PROVIDER_IDS.includes(value);
|
|
15
|
+
}
|
|
16
|
+
function defaultConfig() {
|
|
17
|
+
return {
|
|
18
|
+
update_notifier: true,
|
|
19
|
+
agent: {
|
|
20
|
+
default: "claude",
|
|
21
|
+
models: {
|
|
22
|
+
claude: null,
|
|
23
|
+
codex: null,
|
|
24
|
+
cursor: null
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function getConfigPath() {
|
|
30
|
+
return join(getGlobalAlmanacDir(), "config.toml");
|
|
31
|
+
}
|
|
32
|
+
function getLegacyConfigPath() {
|
|
33
|
+
return join(getGlobalAlmanacDir(), "config.json");
|
|
34
|
+
}
|
|
35
|
+
function getProjectConfigPath(cwd) {
|
|
36
|
+
const repoRoot = findNearestAlmanacDir(cwd);
|
|
37
|
+
return repoRoot === null ? null : join(getRepoAlmanacDir(repoRoot), "config.toml");
|
|
38
|
+
}
|
|
39
|
+
async function readConfig(input) {
|
|
40
|
+
return (await readConfigWithOrigins(input)).config;
|
|
41
|
+
}
|
|
42
|
+
async function readConfigWithOrigins(input) {
|
|
43
|
+
const opts = normalizeReadOptions(input);
|
|
44
|
+
if (opts.path !== void 0) {
|
|
45
|
+
const raw = await readRawConfigObject(opts.path);
|
|
46
|
+
return {
|
|
47
|
+
config: normalizeRawConfig(raw),
|
|
48
|
+
origins: originsFromRaw(raw, "user"),
|
|
49
|
+
raw
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const file = getConfigPath();
|
|
53
|
+
await migrateLegacyConfigIfNeeded(file);
|
|
54
|
+
const userRaw = await readRawConfigObject(file);
|
|
55
|
+
const mergedRaw = cloneJsonObject(userRaw);
|
|
56
|
+
const origins = originsFromRaw(userRaw, "user");
|
|
57
|
+
const projectPath = opts.cwd !== void 0 ? getProjectConfigPath(opts.cwd) : null;
|
|
58
|
+
if (projectPath !== null) {
|
|
59
|
+
const projectRaw = await readRawConfigObject(projectPath);
|
|
60
|
+
applyProjectConfig(mergedRaw, projectRaw);
|
|
61
|
+
Object.assign(origins, originsFromRaw(projectRaw, "project", true));
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
config: normalizeRawConfig(mergedRaw),
|
|
65
|
+
origins,
|
|
66
|
+
raw: mergedRaw
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function normalizeReadOptions(input) {
|
|
70
|
+
return typeof input === "string" ? { path: input } : input ?? {};
|
|
71
|
+
}
|
|
72
|
+
async function migrateLegacyConfigIfNeeded(file) {
|
|
73
|
+
if (existsSync(file)) return;
|
|
74
|
+
const legacy = getLegacyConfigPath();
|
|
75
|
+
if (!existsSync(legacy)) return;
|
|
76
|
+
const raw = await readRawConfigObject(legacy);
|
|
77
|
+
if (Object.keys(raw).length === 0) return;
|
|
78
|
+
await writeConfig(normalizeRawConfig(raw), file);
|
|
79
|
+
}
|
|
80
|
+
function normalizeRawConfig(raw) {
|
|
81
|
+
const defaults = defaultConfig();
|
|
82
|
+
const rawAgent = raw.agent !== void 0 && raw.agent !== null && typeof raw.agent === "object" && !Array.isArray(raw.agent) ? raw.agent : {};
|
|
83
|
+
const rawDefault = typeof rawAgent.default === "string" && isAgentProviderId(rawAgent.default) ? rawAgent.default : defaults.agent.default;
|
|
84
|
+
const rawModels = rawAgent.models !== void 0 && rawAgent.models !== null && typeof rawAgent.models === "object" && !Array.isArray(rawAgent.models) ? rawAgent.models : {};
|
|
85
|
+
const models = {
|
|
86
|
+
...defaults.agent.models
|
|
87
|
+
};
|
|
88
|
+
for (const id of AGENT_PROVIDER_IDS) {
|
|
89
|
+
const value = rawModels[id];
|
|
90
|
+
if (typeof value === "string" && value.length > 0) {
|
|
91
|
+
models[id] = value === "default" || value === "null" ? null : value;
|
|
92
|
+
} else if (value === null) {
|
|
93
|
+
models[id] = null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
update_notifier: typeof raw.update_notifier === "boolean" ? raw.update_notifier : defaults.update_notifier,
|
|
98
|
+
agent: {
|
|
99
|
+
default: rawDefault,
|
|
100
|
+
models
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function applyProjectConfig(target, projectRaw) {
|
|
105
|
+
const projectAgent = projectRaw.agent !== null && typeof projectRaw.agent === "object" && !Array.isArray(projectRaw.agent) ? projectRaw.agent : {};
|
|
106
|
+
if (Object.keys(projectAgent).length === 0) return;
|
|
107
|
+
const targetAgent = target.agent !== null && typeof target.agent === "object" && !Array.isArray(target.agent) ? target.agent : {};
|
|
108
|
+
target.agent = targetAgent;
|
|
109
|
+
if (typeof projectAgent.default === "string") {
|
|
110
|
+
targetAgent.default = projectAgent.default;
|
|
111
|
+
}
|
|
112
|
+
const projectModels = projectAgent.models !== null && typeof projectAgent.models === "object" && !Array.isArray(projectAgent.models) ? projectAgent.models : {};
|
|
113
|
+
if (Object.keys(projectModels).length === 0) return;
|
|
114
|
+
const targetModels = targetAgent.models !== null && typeof targetAgent.models === "object" && !Array.isArray(targetAgent.models) ? targetAgent.models : {};
|
|
115
|
+
targetAgent.models = targetModels;
|
|
116
|
+
for (const id of AGENT_PROVIDER_IDS) {
|
|
117
|
+
if (Object.prototype.hasOwnProperty.call(projectModels, id)) {
|
|
118
|
+
targetModels[id] = projectModels[id];
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function originsFromRaw(raw, origin, agentOnly = false) {
|
|
123
|
+
const origins = {};
|
|
124
|
+
if (!agentOnly && Object.prototype.hasOwnProperty.call(raw, "update_notifier")) {
|
|
125
|
+
origins.update_notifier = origin;
|
|
126
|
+
}
|
|
127
|
+
const agent = raw.agent !== null && typeof raw.agent === "object" && !Array.isArray(raw.agent) ? raw.agent : {};
|
|
128
|
+
if (Object.prototype.hasOwnProperty.call(agent, "default")) {
|
|
129
|
+
origins["agent.default"] = origin;
|
|
130
|
+
}
|
|
131
|
+
const models = agent.models !== null && typeof agent.models === "object" && !Array.isArray(agent.models) ? agent.models : {};
|
|
132
|
+
for (const id of AGENT_PROVIDER_IDS) {
|
|
133
|
+
if (Object.prototype.hasOwnProperty.call(models, id)) {
|
|
134
|
+
origins[`agent.models.${id}`] = origin;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return origins;
|
|
138
|
+
}
|
|
139
|
+
async function readSingleConfig(file) {
|
|
140
|
+
let raw;
|
|
141
|
+
try {
|
|
142
|
+
raw = await readFile(file, "utf8");
|
|
143
|
+
} catch {
|
|
144
|
+
return defaultConfig();
|
|
145
|
+
}
|
|
146
|
+
const trimmed = raw.trim();
|
|
147
|
+
if (trimmed.length === 0) return defaultConfig();
|
|
148
|
+
try {
|
|
149
|
+
return normalizeRawConfig(parseConfigText(trimmed, file));
|
|
150
|
+
} catch {
|
|
151
|
+
return defaultConfig();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
async function writeConfig(config, path) {
|
|
155
|
+
const file = path ?? getConfigPath();
|
|
156
|
+
await mkdir(dirname(file), { recursive: true });
|
|
157
|
+
const current = await readSingleConfig(file);
|
|
158
|
+
const existingRaw = await readRawConfigObject(file);
|
|
159
|
+
const stored = toStoredConfigPatch(config, current, existingRaw);
|
|
160
|
+
const body = serializeConfig(stored, file);
|
|
161
|
+
const tmp = `${file}.tmp`;
|
|
162
|
+
await writeFile(tmp, body, "utf8");
|
|
163
|
+
await rename(tmp, file);
|
|
164
|
+
}
|
|
165
|
+
function normalizeConfig(config) {
|
|
166
|
+
const defaults = defaultConfig();
|
|
167
|
+
return {
|
|
168
|
+
update_notifier: typeof config.update_notifier === "boolean" ? config.update_notifier : defaults.update_notifier,
|
|
169
|
+
agent: {
|
|
170
|
+
default: config.agent !== void 0 && isAgentProviderId(config.agent.default) ? config.agent.default : defaults.agent.default,
|
|
171
|
+
models: {
|
|
172
|
+
...defaults.agent.models,
|
|
173
|
+
...config.agent?.models ?? {}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
async function readRawConfigObject(path) {
|
|
179
|
+
try {
|
|
180
|
+
return parseConfigText(await readFile(path, "utf8"), path);
|
|
181
|
+
} catch {
|
|
182
|
+
}
|
|
183
|
+
return {};
|
|
184
|
+
}
|
|
185
|
+
function parseConfigText(raw, path = "config.toml") {
|
|
186
|
+
const trimmed = raw.trim();
|
|
187
|
+
if (trimmed.length === 0) return {};
|
|
188
|
+
if (path.endsWith(".json") || trimmed.startsWith("{")) {
|
|
189
|
+
const parsed = JSON.parse(trimmed);
|
|
190
|
+
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
191
|
+
}
|
|
192
|
+
return parseTomlConfig(trimmed);
|
|
193
|
+
}
|
|
194
|
+
function serializeConfig(raw, path = "config.toml") {
|
|
195
|
+
return path.endsWith(".json") ? `${JSON.stringify(raw, null, 2)}
|
|
196
|
+
` : serializeTomlConfig(raw);
|
|
197
|
+
}
|
|
198
|
+
function parseTomlConfig(raw) {
|
|
199
|
+
const result = {};
|
|
200
|
+
let section = [];
|
|
201
|
+
for (const original of raw.split(/\r?\n/)) {
|
|
202
|
+
const line = stripTomlComment(original).trim();
|
|
203
|
+
if (line.length === 0) continue;
|
|
204
|
+
const sectionMatch = line.match(/^\[([A-Za-z0-9_.-]+)\]$/);
|
|
205
|
+
if (sectionMatch !== null) {
|
|
206
|
+
section = sectionMatch[1].split(".");
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
const eq = line.indexOf("=");
|
|
210
|
+
if (eq === -1) continue;
|
|
211
|
+
const key = line.slice(0, eq).trim();
|
|
212
|
+
const value = parseTomlValue(line.slice(eq + 1).trim());
|
|
213
|
+
setObjectPath(result, [...section, key], value);
|
|
214
|
+
}
|
|
215
|
+
return result;
|
|
216
|
+
}
|
|
217
|
+
function serializeTomlConfig(raw) {
|
|
218
|
+
const lines = [];
|
|
219
|
+
if (typeof raw.update_notifier === "boolean") {
|
|
220
|
+
lines.push(`update_notifier = ${raw.update_notifier ? "true" : "false"}`);
|
|
221
|
+
}
|
|
222
|
+
const agent = raw.agent !== null && typeof raw.agent === "object" && !Array.isArray(raw.agent) ? raw.agent : {};
|
|
223
|
+
if (typeof agent.default === "string") {
|
|
224
|
+
if (lines.length > 0) lines.push("");
|
|
225
|
+
lines.push("[agent]");
|
|
226
|
+
lines.push(`default = ${tomlString(agent.default)}`);
|
|
227
|
+
}
|
|
228
|
+
const models = agent.models !== null && typeof agent.models === "object" && !Array.isArray(agent.models) ? agent.models : {};
|
|
229
|
+
const modelLines = [];
|
|
230
|
+
for (const id of AGENT_PROVIDER_IDS) {
|
|
231
|
+
if (!Object.prototype.hasOwnProperty.call(models, id)) continue;
|
|
232
|
+
const value = models[id] === null ? "default" : models[id];
|
|
233
|
+
if (typeof value === "string" && value.length > 0) {
|
|
234
|
+
modelLines.push(`${id} = ${tomlString(value)}`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
if (modelLines.length > 0) {
|
|
238
|
+
if (lines.length > 0) lines.push("");
|
|
239
|
+
lines.push("[agent.models]", ...modelLines);
|
|
240
|
+
}
|
|
241
|
+
return `${lines.join("\n")}
|
|
242
|
+
`;
|
|
243
|
+
}
|
|
244
|
+
function stripTomlComment(line) {
|
|
245
|
+
let inString = false;
|
|
246
|
+
let escaped = false;
|
|
247
|
+
for (let i = 0; i < line.length; i++) {
|
|
248
|
+
const ch = line[i];
|
|
249
|
+
if (escaped) {
|
|
250
|
+
escaped = false;
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
if (ch === "\\") {
|
|
254
|
+
escaped = true;
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
if (ch === '"') inString = !inString;
|
|
258
|
+
if (ch === "#" && !inString) return line.slice(0, i);
|
|
259
|
+
}
|
|
260
|
+
return line;
|
|
261
|
+
}
|
|
262
|
+
function parseTomlValue(raw) {
|
|
263
|
+
if (raw === "true") return true;
|
|
264
|
+
if (raw === "false") return false;
|
|
265
|
+
if (raw.startsWith('"') && raw.endsWith('"')) {
|
|
266
|
+
return JSON.parse(raw);
|
|
267
|
+
}
|
|
268
|
+
return raw;
|
|
269
|
+
}
|
|
270
|
+
function tomlString(value) {
|
|
271
|
+
return JSON.stringify(value);
|
|
272
|
+
}
|
|
273
|
+
function setObjectPath(raw, path, value) {
|
|
274
|
+
let cursor = raw;
|
|
275
|
+
for (const part of path.slice(0, -1)) {
|
|
276
|
+
const next = cursor[part];
|
|
277
|
+
if (next === null || typeof next !== "object" || Array.isArray(next)) {
|
|
278
|
+
cursor[part] = {};
|
|
279
|
+
}
|
|
280
|
+
cursor = cursor[part];
|
|
281
|
+
}
|
|
282
|
+
const leaf = path[path.length - 1];
|
|
283
|
+
if (leaf !== void 0) cursor[leaf] = value;
|
|
284
|
+
}
|
|
285
|
+
function toStoredConfigPatch(config, current, raw) {
|
|
286
|
+
const normalized = normalizeConfig(config);
|
|
287
|
+
const defaults = defaultConfig();
|
|
288
|
+
const stored = cloneJsonObject(raw);
|
|
289
|
+
if (config.update_notifier !== void 0 && normalized.update_notifier !== current.update_notifier) {
|
|
290
|
+
setStoredValue(
|
|
291
|
+
stored,
|
|
292
|
+
["update_notifier"],
|
|
293
|
+
normalized.update_notifier,
|
|
294
|
+
defaults.update_notifier
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
if (config.agent !== void 0) {
|
|
298
|
+
if (config.agent.default !== void 0 && normalized.agent.default !== current.agent.default) {
|
|
299
|
+
setStoredValue(
|
|
300
|
+
stored,
|
|
301
|
+
["agent", "default"],
|
|
302
|
+
normalized.agent.default,
|
|
303
|
+
defaults.agent.default
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
const inputModels = config.agent.models ?? {};
|
|
307
|
+
for (const id of AGENT_PROVIDER_IDS) {
|
|
308
|
+
if (!Object.prototype.hasOwnProperty.call(inputModels, id)) continue;
|
|
309
|
+
const value = normalized.agent.models[id] ?? null;
|
|
310
|
+
const currentValue = current.agent.models[id] ?? null;
|
|
311
|
+
const defaultValue = defaults.agent.models[id] ?? null;
|
|
312
|
+
if (value !== currentValue) {
|
|
313
|
+
setStoredValue(stored, ["agent", "models", id], value, defaultValue);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
pruneEmptyObjects(stored);
|
|
318
|
+
return stored;
|
|
319
|
+
}
|
|
320
|
+
function setStoredValue(raw, path, value, defaultValue) {
|
|
321
|
+
let cursor = raw;
|
|
322
|
+
for (const part of path.slice(0, -1)) {
|
|
323
|
+
const next = cursor[part];
|
|
324
|
+
if (next === null || typeof next !== "object" || Array.isArray(next)) {
|
|
325
|
+
cursor[part] = {};
|
|
326
|
+
}
|
|
327
|
+
cursor = cursor[part];
|
|
328
|
+
}
|
|
329
|
+
const leaf = path[path.length - 1];
|
|
330
|
+
if (leaf === void 0) return;
|
|
331
|
+
cursor[leaf] = value;
|
|
332
|
+
if (value !== defaultValue) return;
|
|
333
|
+
}
|
|
334
|
+
function cloneJsonObject(raw) {
|
|
335
|
+
return JSON.parse(JSON.stringify(raw));
|
|
336
|
+
}
|
|
337
|
+
function pruneEmptyObjects(raw) {
|
|
338
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
339
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
pruneEmptyObjects(value);
|
|
343
|
+
if (Object.keys(value).length === 0) delete raw[key];
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
export {
|
|
348
|
+
AGENT_PROVIDER_IDS,
|
|
349
|
+
isAgentProviderId,
|
|
350
|
+
getConfigPath,
|
|
351
|
+
getLegacyConfigPath,
|
|
352
|
+
getProjectConfigPath,
|
|
353
|
+
readConfig,
|
|
354
|
+
readConfigWithOrigins,
|
|
355
|
+
writeConfig,
|
|
356
|
+
parseConfigText,
|
|
357
|
+
serializeConfig
|
|
358
|
+
};
|
|
359
|
+
//# sourceMappingURL=chunk-P5WGG4FJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/update/config.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { mkdir, readFile, rename, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\nimport {\n findNearestAlmanacDir,\n getGlobalAlmanacDir,\n getRepoAlmanacDir,\n} from \"../paths.js\";\n\nexport const AGENT_PROVIDER_IDS = [\"claude\", \"codex\", \"cursor\"] as const;\nexport type AgentProviderId = (typeof AGENT_PROVIDER_IDS)[number];\n\nexport function isAgentProviderId(value: string): value is AgentProviderId {\n return (AGENT_PROVIDER_IDS as readonly string[]).includes(value);\n}\n\nexport interface AgentConfig {\n /** Default provider for bootstrap/capture. Default: \"claude\". */\n default: AgentProviderId;\n /** Optional per-provider model override. `null` means provider default. */\n models: Partial<Record<AgentProviderId, string | null>>;\n}\n\n/**\n * `~/.almanac/config.toml` — global, cross-wiki configuration. Legacy\n * `config.json` is read and migrated forward on first normal access.\n *\n * Missing or malformed → defaults. Same tolerance as `UpdateState`:\n * the CLI must not be able to fail because this file drifted.\n */\nexport interface GlobalConfig {\n /** When `false`, suppress the pre-command update-nag banner. Default: true. */\n update_notifier: boolean;\n /** Agent-provider settings for bootstrap/capture. */\n agent: AgentConfig;\n}\n\nexport function defaultConfig(): GlobalConfig {\n return {\n update_notifier: true,\n agent: {\n default: \"claude\",\n models: {\n claude: null,\n codex: null,\n cursor: null,\n },\n },\n };\n}\n\nexport function getConfigPath(): string {\n return join(getGlobalAlmanacDir(), \"config.toml\");\n}\n\nexport function getLegacyConfigPath(): string {\n return join(getGlobalAlmanacDir(), \"config.json\");\n}\n\nexport function getProjectConfigPath(cwd: string): string | null {\n const repoRoot = findNearestAlmanacDir(cwd);\n return repoRoot === null ? null : join(getRepoAlmanacDir(repoRoot), \"config.toml\");\n}\n\nexport type ConfigOrigin = \"default\" | \"user\" | \"project\";\n\nexport interface ConfigReadOptions {\n path?: string;\n cwd?: string;\n}\n\nexport interface ConfigReadResult {\n config: GlobalConfig;\n origins: Record<string, ConfigOrigin>;\n raw: Record<string, unknown>;\n}\n\nexport async function readConfig(\n input?: string | ConfigReadOptions,\n): Promise<GlobalConfig> {\n return (await readConfigWithOrigins(input)).config;\n}\n\nexport async function readConfigWithOrigins(\n input?: string | ConfigReadOptions,\n): Promise<ConfigReadResult> {\n const opts = normalizeReadOptions(input);\n if (opts.path !== undefined) {\n const raw = await readRawConfigObject(opts.path);\n return {\n config: normalizeRawConfig(raw),\n origins: originsFromRaw(raw, \"user\"),\n raw,\n };\n }\n\n const file = getConfigPath();\n await migrateLegacyConfigIfNeeded(file);\n const userRaw = await readRawConfigObject(file);\n const mergedRaw = cloneJsonObject(userRaw);\n const origins = originsFromRaw(userRaw, \"user\");\n const projectPath = opts.cwd !== undefined ? getProjectConfigPath(opts.cwd) : null;\n if (projectPath !== null) {\n const projectRaw = await readRawConfigObject(projectPath);\n applyProjectConfig(mergedRaw, projectRaw);\n Object.assign(origins, originsFromRaw(projectRaw, \"project\", true));\n }\n return {\n config: normalizeRawConfig(mergedRaw),\n origins,\n raw: mergedRaw,\n };\n}\n\nfunction normalizeReadOptions(\n input?: string | ConfigReadOptions,\n): ConfigReadOptions {\n return typeof input === \"string\" ? { path: input } : input ?? {};\n}\n\nasync function migrateLegacyConfigIfNeeded(file: string): Promise<void> {\n if (existsSync(file)) return;\n const legacy = getLegacyConfigPath();\n if (!existsSync(legacy)) return;\n const raw = await readRawConfigObject(legacy);\n if (Object.keys(raw).length === 0) return;\n await writeConfig(normalizeRawConfig(raw), file);\n}\n\nfunction normalizeRawConfig(raw: Record<string, unknown>): GlobalConfig {\n const defaults = defaultConfig();\n const rawAgent =\n raw.agent !== undefined &&\n raw.agent !== null &&\n typeof raw.agent === \"object\" &&\n !Array.isArray(raw.agent)\n ? (raw.agent as Partial<AgentConfig>)\n : {};\n const rawDefault =\n typeof rawAgent.default === \"string\" &&\n isAgentProviderId(rawAgent.default)\n ? rawAgent.default\n : defaults.agent.default;\n const rawModels =\n rawAgent.models !== undefined &&\n rawAgent.models !== null &&\n typeof rawAgent.models === \"object\" &&\n !Array.isArray(rawAgent.models)\n ? (rawAgent.models as Record<string, unknown>)\n : {};\n const models: Partial<Record<AgentProviderId, string | null>> = {\n ...defaults.agent.models,\n };\n for (const id of AGENT_PROVIDER_IDS) {\n const value = rawModels[id];\n if (typeof value === \"string\" && value.length > 0) {\n models[id] = value === \"default\" || value === \"null\" ? null : value;\n } else if (value === null) {\n models[id] = null;\n }\n }\n return {\n update_notifier:\n typeof raw.update_notifier === \"boolean\"\n ? raw.update_notifier\n : defaults.update_notifier,\n agent: {\n default: rawDefault,\n models,\n },\n };\n}\n\nfunction applyProjectConfig(\n target: Record<string, unknown>,\n projectRaw: Record<string, unknown>,\n): void {\n const projectAgent =\n projectRaw.agent !== null &&\n typeof projectRaw.agent === \"object\" &&\n !Array.isArray(projectRaw.agent)\n ? projectRaw.agent as Record<string, unknown>\n : {};\n if (Object.keys(projectAgent).length === 0) return;\n const targetAgent =\n target.agent !== null &&\n typeof target.agent === \"object\" &&\n !Array.isArray(target.agent)\n ? target.agent as Record<string, unknown>\n : {};\n target.agent = targetAgent;\n if (typeof projectAgent.default === \"string\") {\n targetAgent.default = projectAgent.default;\n }\n const projectModels =\n projectAgent.models !== null &&\n typeof projectAgent.models === \"object\" &&\n !Array.isArray(projectAgent.models)\n ? projectAgent.models as Record<string, unknown>\n : {};\n if (Object.keys(projectModels).length === 0) return;\n const targetModels =\n targetAgent.models !== null &&\n typeof targetAgent.models === \"object\" &&\n !Array.isArray(targetAgent.models)\n ? targetAgent.models as Record<string, unknown>\n : {};\n targetAgent.models = targetModels;\n for (const id of AGENT_PROVIDER_IDS) {\n if (Object.prototype.hasOwnProperty.call(projectModels, id)) {\n targetModels[id] = projectModels[id];\n }\n }\n}\n\nfunction originsFromRaw(\n raw: Record<string, unknown>,\n origin: ConfigOrigin,\n agentOnly = false,\n): Record<string, ConfigOrigin> {\n const origins: Record<string, ConfigOrigin> = {};\n if (!agentOnly && Object.prototype.hasOwnProperty.call(raw, \"update_notifier\")) {\n origins.update_notifier = origin;\n }\n const agent =\n raw.agent !== null &&\n typeof raw.agent === \"object\" &&\n !Array.isArray(raw.agent)\n ? raw.agent as Record<string, unknown>\n : {};\n if (Object.prototype.hasOwnProperty.call(agent, \"default\")) {\n origins[\"agent.default\"] = origin;\n }\n const models =\n agent.models !== null &&\n typeof agent.models === \"object\" &&\n !Array.isArray(agent.models)\n ? agent.models as Record<string, unknown>\n : {};\n for (const id of AGENT_PROVIDER_IDS) {\n if (Object.prototype.hasOwnProperty.call(models, id)) {\n origins[`agent.models.${id}`] = origin;\n }\n }\n return origins;\n}\n\nasync function readSingleConfig(file: string): Promise<GlobalConfig> {\n let raw: string;\n try {\n raw = await readFile(file, \"utf8\");\n } catch {\n return defaultConfig();\n }\n const trimmed = raw.trim();\n if (trimmed.length === 0) return defaultConfig();\n try {\n return normalizeRawConfig(parseConfigText(trimmed, file));\n } catch {\n return defaultConfig();\n }\n}\n\nexport async function writeConfig(\n config: GlobalConfig | Partial<GlobalConfig>,\n path?: string,\n): Promise<void> {\n const file = path ?? getConfigPath();\n await mkdir(dirname(file), { recursive: true });\n const current = await readSingleConfig(file);\n const existingRaw = await readRawConfigObject(file);\n const stored = toStoredConfigPatch(config, current, existingRaw);\n const body = serializeConfig(stored, file);\n const tmp = `${file}.tmp`;\n await writeFile(tmp, body, \"utf8\");\n await rename(tmp, file);\n}\n\nfunction normalizeConfig(config: GlobalConfig | Partial<GlobalConfig>): GlobalConfig {\n const defaults = defaultConfig();\n return {\n update_notifier:\n typeof config.update_notifier === \"boolean\"\n ? config.update_notifier\n : defaults.update_notifier,\n agent: {\n default:\n config.agent !== undefined && isAgentProviderId(config.agent.default)\n ? config.agent.default\n : defaults.agent.default,\n models: {\n ...defaults.agent.models,\n ...(config.agent?.models ?? {}),\n },\n },\n };\n}\n\nasync function readRawConfigObject(\n path: string,\n): Promise<Record<string, unknown>> {\n try {\n return parseConfigText(await readFile(path, \"utf8\"), path);\n } catch {\n // Fall through to empty.\n }\n return {};\n}\n\nexport function parseConfigText(\n raw: string,\n path = \"config.toml\",\n): Record<string, unknown> {\n const trimmed = raw.trim();\n if (trimmed.length === 0) return {};\n if (path.endsWith(\".json\") || trimmed.startsWith(\"{\")) {\n const parsed = JSON.parse(trimmed) as unknown;\n return parsed !== null && typeof parsed === \"object\" && !Array.isArray(parsed)\n ? parsed as Record<string, unknown>\n : {};\n }\n return parseTomlConfig(trimmed);\n}\n\nexport function serializeConfig(\n raw: Record<string, unknown>,\n path = \"config.toml\",\n): string {\n return path.endsWith(\".json\")\n ? `${JSON.stringify(raw, null, 2)}\\n`\n : serializeTomlConfig(raw);\n}\n\nfunction parseTomlConfig(raw: string): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n let section: string[] = [];\n for (const original of raw.split(/\\r?\\n/)) {\n const line = stripTomlComment(original).trim();\n if (line.length === 0) continue;\n const sectionMatch = line.match(/^\\[([A-Za-z0-9_.-]+)\\]$/);\n if (sectionMatch !== null) {\n section = sectionMatch[1]!.split(\".\");\n continue;\n }\n const eq = line.indexOf(\"=\");\n if (eq === -1) continue;\n const key = line.slice(0, eq).trim();\n const value = parseTomlValue(line.slice(eq + 1).trim());\n setObjectPath(result, [...section, key], value);\n }\n return result;\n}\n\nfunction serializeTomlConfig(raw: Record<string, unknown>): string {\n const lines: string[] = [];\n if (typeof raw.update_notifier === \"boolean\") {\n lines.push(`update_notifier = ${raw.update_notifier ? \"true\" : \"false\"}`);\n }\n const agent =\n raw.agent !== null &&\n typeof raw.agent === \"object\" &&\n !Array.isArray(raw.agent)\n ? raw.agent as Record<string, unknown>\n : {};\n if (typeof agent.default === \"string\") {\n if (lines.length > 0) lines.push(\"\");\n lines.push(\"[agent]\");\n lines.push(`default = ${tomlString(agent.default)}`);\n }\n const models =\n agent.models !== null &&\n typeof agent.models === \"object\" &&\n !Array.isArray(agent.models)\n ? agent.models as Record<string, unknown>\n : {};\n const modelLines: string[] = [];\n for (const id of AGENT_PROVIDER_IDS) {\n if (!Object.prototype.hasOwnProperty.call(models, id)) continue;\n const value = models[id] === null ? \"default\" : models[id];\n if (typeof value === \"string\" && value.length > 0) {\n modelLines.push(`${id} = ${tomlString(value)}`);\n }\n }\n if (modelLines.length > 0) {\n if (lines.length > 0) lines.push(\"\");\n lines.push(\"[agent.models]\", ...modelLines);\n }\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nfunction stripTomlComment(line: string): string {\n let inString = false;\n let escaped = false;\n for (let i = 0; i < line.length; i++) {\n const ch = line[i];\n if (escaped) {\n escaped = false;\n continue;\n }\n if (ch === \"\\\\\") {\n escaped = true;\n continue;\n }\n if (ch === \"\\\"\") inString = !inString;\n if (ch === \"#\" && !inString) return line.slice(0, i);\n }\n return line;\n}\n\nfunction parseTomlValue(raw: string): string | boolean {\n if (raw === \"true\") return true;\n if (raw === \"false\") return false;\n if (raw.startsWith(\"\\\"\") && raw.endsWith(\"\\\"\")) {\n return JSON.parse(raw) as string;\n }\n return raw;\n}\n\nfunction tomlString(value: string): string {\n return JSON.stringify(value);\n}\n\nfunction setObjectPath(\n raw: Record<string, unknown>,\n path: string[],\n value: string | boolean,\n): void {\n let cursor = raw;\n for (const part of path.slice(0, -1)) {\n const next = cursor[part];\n if (next === null || typeof next !== \"object\" || Array.isArray(next)) {\n cursor[part] = {};\n }\n cursor = cursor[part] as Record<string, unknown>;\n }\n const leaf = path[path.length - 1];\n if (leaf !== undefined) cursor[leaf] = value;\n}\n\nfunction toStoredConfigPatch(\n config: GlobalConfig | Partial<GlobalConfig>,\n current: GlobalConfig,\n raw: Record<string, unknown>,\n): Record<string, unknown> {\n const normalized = normalizeConfig(config);\n const defaults = defaultConfig();\n const stored = cloneJsonObject(raw);\n\n if (\n config.update_notifier !== undefined &&\n normalized.update_notifier !== current.update_notifier\n ) {\n setStoredValue(\n stored,\n [\"update_notifier\"],\n normalized.update_notifier,\n defaults.update_notifier,\n );\n }\n\n if (config.agent !== undefined) {\n if (\n config.agent.default !== undefined &&\n normalized.agent.default !== current.agent.default\n ) {\n setStoredValue(\n stored,\n [\"agent\", \"default\"],\n normalized.agent.default,\n defaults.agent.default,\n );\n }\n\n const inputModels = config.agent.models ?? {};\n for (const id of AGENT_PROVIDER_IDS) {\n if (!Object.prototype.hasOwnProperty.call(inputModels, id)) continue;\n const value = normalized.agent.models[id] ?? null;\n const currentValue = current.agent.models[id] ?? null;\n const defaultValue = defaults.agent.models[id] ?? null;\n if (value !== currentValue) {\n setStoredValue(stored, [\"agent\", \"models\", id], value, defaultValue);\n }\n }\n }\n pruneEmptyObjects(stored);\n return stored;\n}\n\nfunction setStoredValue(\n raw: Record<string, unknown>,\n path: string[],\n value: string | boolean | null,\n defaultValue: string | boolean | null,\n): void {\n let cursor = raw;\n for (const part of path.slice(0, -1)) {\n const next = cursor[part];\n if (next === null || typeof next !== \"object\" || Array.isArray(next)) {\n cursor[part] = {};\n }\n cursor = cursor[part] as Record<string, unknown>;\n }\n const leaf = path[path.length - 1];\n if (leaf === undefined) return;\n cursor[leaf] = value;\n if (value !== defaultValue) return;\n // Keep explicit defaults only when the caller changed the value to the\n // default. Unchanged explicit defaults are preserved by cloning `raw`.\n}\n\nfunction cloneJsonObject(raw: Record<string, unknown>): Record<string, unknown> {\n return JSON.parse(JSON.stringify(raw)) as Record<string, unknown>;\n}\n\nfunction pruneEmptyObjects(raw: Record<string, unknown>): void {\n for (const [key, value] of Object.entries(raw)) {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n continue;\n }\n pruneEmptyObjects(value as Record<string, unknown>);\n if (Object.keys(value).length === 0) delete raw[key];\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -2,21 +2,22 @@
|
|
|
2
2
|
import {
|
|
3
3
|
runHookInstall
|
|
4
4
|
} from "./chunk-447U3GQJ.js";
|
|
5
|
-
import {
|
|
6
|
-
listProviderStatuses
|
|
7
|
-
} from "./chunk-TWM7I2LU.js";
|
|
8
5
|
import {
|
|
9
6
|
UNAUTHENTICATED_MESSAGE,
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
buildProviderModelChoices,
|
|
8
|
+
buildProviderSetupView,
|
|
9
|
+
checkClaudeAuth,
|
|
10
|
+
parseAgentSelection
|
|
11
|
+
} from "./chunk-BF2J4XTC.js";
|
|
12
12
|
import {
|
|
13
13
|
isAgentProviderId,
|
|
14
14
|
readConfig,
|
|
15
15
|
writeConfig
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-P5WGG4FJ.js";
|
|
17
17
|
|
|
18
18
|
// src/commands/setup.ts
|
|
19
19
|
import { existsSync as existsSync2 } from "fs";
|
|
20
|
+
import { spawn } from "child_process";
|
|
20
21
|
import {
|
|
21
22
|
copyFile,
|
|
22
23
|
mkdir,
|
|
@@ -231,9 +232,8 @@ async function runSetup(options = {}) {
|
|
|
231
232
|
out,
|
|
232
233
|
interactive,
|
|
233
234
|
requested: options.agent,
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
promptText: options.promptText ?? promptText
|
|
235
|
+
requestedModel: options.model,
|
|
236
|
+
spawnCli: options.spawnCli
|
|
237
237
|
});
|
|
238
238
|
if (!agentChoice.ok) {
|
|
239
239
|
return {
|
|
@@ -243,14 +243,16 @@ async function runSetup(options = {}) {
|
|
|
243
243
|
exitCode: 1
|
|
244
244
|
};
|
|
245
245
|
}
|
|
246
|
-
stepDone(
|
|
246
|
+
stepDone(
|
|
247
|
+
out,
|
|
248
|
+
`Default agent: ${WHITE_BOLD2}${agentChoice.provider}${RST2} (${agentChoice.model ?? "provider default"})`
|
|
249
|
+
);
|
|
247
250
|
out.write(BAR + "\n");
|
|
248
|
-
const confirmPrompt = options.confirm ?? confirm;
|
|
249
251
|
const ephem = options.installPath !== void 0 ? options.installPath !== null ? detectEphemeral(options.installPath) : false : detectEphemeral(detectCurrentInstallPath());
|
|
250
252
|
if (ephem) {
|
|
251
253
|
let globalAction = "install";
|
|
252
254
|
if (interactive) {
|
|
253
|
-
globalAction = await
|
|
255
|
+
globalAction = await confirm(
|
|
254
256
|
out,
|
|
255
257
|
`Running from an ephemeral npx location. Install globally so 'almanac' stays on PATH?`,
|
|
256
258
|
true
|
|
@@ -281,7 +283,7 @@ async function runSetup(options = {}) {
|
|
|
281
283
|
if (options.skipHook === true) {
|
|
282
284
|
hookAction = "skip";
|
|
283
285
|
} else if (interactive) {
|
|
284
|
-
hookAction = await
|
|
286
|
+
hookAction = await confirm(
|
|
285
287
|
out,
|
|
286
288
|
"Install auto-capture hooks for Claude, Codex, and Cursor?",
|
|
287
289
|
true
|
|
@@ -313,7 +315,7 @@ async function runSetup(options = {}) {
|
|
|
313
315
|
if (options.skipGuides === true) {
|
|
314
316
|
guidesAction = "skip";
|
|
315
317
|
} else if (interactive) {
|
|
316
|
-
guidesAction = await
|
|
318
|
+
guidesAction = await confirm(
|
|
317
319
|
out,
|
|
318
320
|
"Install the codealmanac usage guides into ~/.claude/ and import them from CLAUDE.md?",
|
|
319
321
|
true
|
|
@@ -356,55 +358,135 @@ async function safeCheckAuth(spawnCli) {
|
|
|
356
358
|
}
|
|
357
359
|
async function chooseDefaultAgent(args) {
|
|
358
360
|
const config = await readConfig();
|
|
359
|
-
let
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
364
|
-
return { ok: false, error: `failed to check agent providers: ${msg}` };
|
|
361
|
+
let view = null;
|
|
362
|
+
let selected = args.requested ?? config.agent.default;
|
|
363
|
+
if (args.interactive || args.requested !== void 0) {
|
|
364
|
+
view = await buildProviderSetupView({ config, spawnCli: args.spawnCli });
|
|
365
365
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
366
|
+
if (args.interactive && args.requested === void 0 && view !== null) {
|
|
367
|
+
args.out.write(" Choose default agent:\n");
|
|
368
|
+
view.choices.forEach((choice, index) => {
|
|
369
|
+
const tag = choice.recommended ? " recommended" : "";
|
|
370
|
+
const status = choice.ready ? "ready" : "not ready";
|
|
371
|
+
const detail = choice.account ?? choice.fixCommand ?? choice.detail;
|
|
372
|
+
args.out.write(
|
|
373
|
+
` ${index + 1}. ${choice.label.padEnd(6)} ${status.padEnd(9)}${tag} ${detail}
|
|
374
|
+
`
|
|
375
|
+
);
|
|
376
|
+
});
|
|
377
|
+
selected = (await promptText(
|
|
377
378
|
args.out,
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
);
|
|
379
|
+
"Default agent",
|
|
380
|
+
view.recommendedProvider
|
|
381
|
+
)).toLowerCase();
|
|
382
|
+
const number = Number.parseInt(selected, 10);
|
|
383
|
+
if (Number.isInteger(number) && number >= 1 && number <= view.choices.length) {
|
|
384
|
+
selected = view.choices[number - 1]?.id ?? selected;
|
|
385
|
+
}
|
|
381
386
|
}
|
|
382
|
-
|
|
387
|
+
const parsed = parseAgentSelection(selected);
|
|
388
|
+
if (parsed.provider === null || !isAgentProviderId(parsed.provider)) {
|
|
383
389
|
return {
|
|
384
390
|
ok: false,
|
|
385
391
|
error: `unknown agent '${selected}'. Expected one of: claude, codex, cursor.`
|
|
386
392
|
};
|
|
387
393
|
}
|
|
388
|
-
const
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
+
const provider = parsed.provider;
|
|
395
|
+
let selectedChoice = view?.choices.find((choice) => choice.id === provider);
|
|
396
|
+
if (args.interactive && selectedChoice !== void 0 && !selectedChoice.ready && selectedChoice.fixCommand?.startsWith("run: ") === true) {
|
|
397
|
+
const command = selectedChoice.fixCommand.slice("run: ".length);
|
|
398
|
+
const runLogin = await confirm(
|
|
399
|
+
args.out,
|
|
400
|
+
`${selectedChoice.label} is not ready. Run '${command}' now?`,
|
|
401
|
+
true
|
|
402
|
+
);
|
|
403
|
+
if (runLogin === "install") {
|
|
404
|
+
const login = await runLoginCommand(command);
|
|
405
|
+
if (login.ok) {
|
|
406
|
+
view = await buildProviderSetupView({ config, spawnCli: args.spawnCli });
|
|
407
|
+
selectedChoice = view.choices.find((choice) => choice.id === provider);
|
|
408
|
+
} else {
|
|
409
|
+
stepActive(args.out, `${selectedChoice.label} login failed: ${login.error}`);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
394
412
|
}
|
|
413
|
+
const requestedModel = args.requestedModel ?? parsed.model;
|
|
414
|
+
const model = requestedModel ?? await chooseProviderModel({
|
|
415
|
+
out: args.out,
|
|
416
|
+
interactive: args.interactive,
|
|
417
|
+
provider,
|
|
418
|
+
choice: selectedChoice,
|
|
419
|
+
configuredModel: config.agent.models[provider] ?? null
|
|
420
|
+
});
|
|
395
421
|
await writeConfig({
|
|
396
422
|
...config,
|
|
397
423
|
agent: {
|
|
398
424
|
...config.agent,
|
|
399
|
-
default:
|
|
425
|
+
default: provider,
|
|
426
|
+
models: {
|
|
427
|
+
...config.agent.models,
|
|
428
|
+
[provider]: model
|
|
429
|
+
}
|
|
400
430
|
}
|
|
401
431
|
});
|
|
402
|
-
|
|
432
|
+
if (!args.interactive || args.requested !== void 0) {
|
|
433
|
+
const detail = selectedChoice?.ready === true ? "ready" : selectedChoice?.fixCommand ?? selectedChoice?.detail ?? "status unknown";
|
|
434
|
+
stepDone(args.out, `Agent readiness: ${detail}`);
|
|
435
|
+
}
|
|
436
|
+
return { ok: true, provider, model };
|
|
437
|
+
}
|
|
438
|
+
async function chooseProviderModel(args) {
|
|
439
|
+
const choices = args.choice?.modelChoices ?? buildProviderModelChoices(args.provider, args.configuredModel);
|
|
440
|
+
const recommended = choices.find((choice) => choice.recommended) ?? choices.find((choice) => choice.source === "provider-default");
|
|
441
|
+
if (!args.interactive) {
|
|
442
|
+
return args.configuredModel ?? recommended?.value ?? null;
|
|
443
|
+
}
|
|
444
|
+
args.out.write(` Choose ${args.provider} model:
|
|
445
|
+
`);
|
|
446
|
+
choices.forEach((choice, index) => {
|
|
447
|
+
const marker = choice.recommended ? " recommended" : "";
|
|
448
|
+
const current = choice.value === args.configuredModel ? " current" : "";
|
|
449
|
+
args.out.write(
|
|
450
|
+
` ${index + 1}. ${choice.label}${marker}${current}
|
|
451
|
+
`
|
|
452
|
+
);
|
|
453
|
+
});
|
|
454
|
+
const currentIndex = choices.findIndex(
|
|
455
|
+
(choice) => choice.value === args.configuredModel
|
|
456
|
+
);
|
|
457
|
+
const recommendedIndex = choices.findIndex((choice) => choice.recommended);
|
|
458
|
+
const defaultIndex = currentIndex >= 0 ? currentIndex + 1 : recommendedIndex >= 0 ? recommendedIndex + 1 : 1;
|
|
459
|
+
const selected = await promptText(args.out, "Model", String(defaultIndex));
|
|
460
|
+
const number = Number.parseInt(selected, 10);
|
|
461
|
+
let modelChoice;
|
|
462
|
+
if (Number.isInteger(number) && number >= 1 && number <= choices.length) {
|
|
463
|
+
modelChoice = choices[number - 1];
|
|
464
|
+
} else {
|
|
465
|
+
modelChoice = choices.find((choice) => choice.value === selected);
|
|
466
|
+
}
|
|
467
|
+
if (modelChoice?.source === "custom") {
|
|
468
|
+
const custom = await promptText(args.out, "Custom model id", "");
|
|
469
|
+
return custom.length > 0 ? custom : recommended?.value ?? null;
|
|
470
|
+
}
|
|
471
|
+
return modelChoice?.value ?? recommended?.value ?? null;
|
|
403
472
|
}
|
|
404
|
-
function
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
473
|
+
async function runLoginCommand(command) {
|
|
474
|
+
return new Promise((resolve) => {
|
|
475
|
+
const child = spawn(command, {
|
|
476
|
+
shell: true,
|
|
477
|
+
stdio: "inherit"
|
|
478
|
+
});
|
|
479
|
+
child.on("error", (err) => {
|
|
480
|
+
resolve({ ok: false, error: err.message });
|
|
481
|
+
});
|
|
482
|
+
child.on("close", (code) => {
|
|
483
|
+
if (code === 0) {
|
|
484
|
+
resolve({ ok: true });
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
resolve({ ok: false, error: `exited ${code ?? 1}` });
|
|
488
|
+
});
|
|
489
|
+
});
|
|
408
490
|
}
|
|
409
491
|
function reportAuth(out, auth) {
|
|
410
492
|
if (auth.loggedIn) {
|
|
@@ -510,7 +592,7 @@ function promptText(out, question, defaultValue) {
|
|
|
510
592
|
if (nl === -1) return;
|
|
511
593
|
process.stdin.removeListener("data", onData);
|
|
512
594
|
process.stdin.pause();
|
|
513
|
-
const answer = buf.slice(0, nl).trim()
|
|
595
|
+
const answer = buf.slice(0, nl).trim();
|
|
514
596
|
resolve(answer.length === 0 ? defaultValue : answer);
|
|
515
597
|
};
|
|
516
598
|
process.stdin.resume();
|
|
@@ -548,4 +630,4 @@ export {
|
|
|
548
630
|
runSetup,
|
|
549
631
|
IMPORT_LINE
|
|
550
632
|
};
|
|
551
|
-
//# sourceMappingURL=chunk-
|
|
633
|
+
//# sourceMappingURL=chunk-QRK3JLFX.js.map
|