codealmanac 0.2.5 → 0.2.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/COMMERCIAL.md +9 -0
- package/LICENSE +133 -21
- package/README.md +11 -11
- package/dist/{agents-RVTQYE6A.js → agents-HYRWRHRX.js} +4 -4
- package/dist/{chunk-TT6ZP4GS.js → chunk-2BNDNGUR.js} +8 -4
- package/dist/{chunk-TT6ZP4GS.js.map → chunk-2BNDNGUR.js.map} +1 -1
- package/dist/{chunk-P5WGG4FJ.js → chunk-3E7JNMTZ.js} +28 -3
- package/dist/chunk-3E7JNMTZ.js.map +1 -0
- package/dist/{chunk-SMIK2YLU.js → chunk-DW32TL5W.js} +117 -83
- package/dist/chunk-DW32TL5W.js.map +1 -0
- package/dist/{chunk-6BJUYZ43.js → chunk-GPFVEF6V.js} +28 -18
- package/dist/chunk-GPFVEF6V.js.map +1 -0
- package/dist/{chunk-TILAKDN6.js → chunk-HJ3WREGP.js} +2 -2
- package/dist/{chunk-BGUID5BS.js → chunk-J7DNV2DH.js} +219 -26
- package/dist/chunk-J7DNV2DH.js.map +1 -0
- package/dist/{chunk-DL5BXZCX.js → chunk-K2JBCB7R.js} +40 -54
- package/dist/chunk-K2JBCB7R.js.map +1 -0
- package/dist/{chunk-MRRX4UQB.js → chunk-ODJAAJGZ.js} +2 -2
- package/dist/{chunk-447U3GQJ.js → chunk-PDFS5VFE.js} +17 -5
- package/dist/chunk-PDFS5VFE.js.map +1 -0
- package/dist/{chunk-GFUB57IT.js → chunk-VXDPUOQ5.js} +384 -207
- package/dist/chunk-VXDPUOQ5.js.map +1 -0
- package/dist/{cli-CL4ID7EO.js → cli-MKXCNEMW.js} +14 -14
- package/dist/codealmanac.js +1 -1
- package/dist/{config-ML2RCR7J.js → config-F7FKEQ7F.js} +3 -3
- package/dist/doctor-37UH3HT5.js +17 -0
- package/dist/{hook-2NP3UE7U.js → hook-4SVX446M.js} +4 -2
- package/dist/{register-commands-FBJ6XQ3L.js → register-commands-2F6SXLDI.js} +30 -21
- package/dist/register-commands-2F6SXLDI.js.map +1 -0
- package/dist/uninstall-C62ZOK32.js +17 -0
- package/dist/{update-P2IPG7RO.js → update-2UGOFN5C.js} +3 -3
- package/guides/mini.md +3 -3
- package/guides/reference.md +7 -7
- package/package.json +4 -3
- package/dist/chunk-447U3GQJ.js.map +0 -1
- package/dist/chunk-6BJUYZ43.js.map +0 -1
- package/dist/chunk-BGUID5BS.js.map +0 -1
- package/dist/chunk-DL5BXZCX.js.map +0 -1
- package/dist/chunk-GFUB57IT.js.map +0 -1
- package/dist/chunk-P5WGG4FJ.js.map +0 -1
- package/dist/chunk-SMIK2YLU.js.map +0 -1
- package/dist/doctor-DOLJRGS4.js +0 -17
- package/dist/register-commands-FBJ6XQ3L.js.map +0 -1
- package/dist/uninstall-DX6LFKMX.js +0 -15
- /package/dist/{agents-RVTQYE6A.js.map → agents-HYRWRHRX.js.map} +0 -0
- /package/dist/{chunk-TILAKDN6.js.map → chunk-HJ3WREGP.js.map} +0 -0
- /package/dist/{chunk-MRRX4UQB.js.map → chunk-ODJAAJGZ.js.map} +0 -0
- /package/dist/{cli-CL4ID7EO.js.map → cli-MKXCNEMW.js.map} +0 -0
- /package/dist/{config-ML2RCR7J.js.map → config-F7FKEQ7F.js.map} +0 -0
- /package/dist/{doctor-DOLJRGS4.js.map → doctor-37UH3HT5.js.map} +0 -0
- /package/dist/{hook-2NP3UE7U.js.map → hook-4SVX446M.js.map} +0 -0
- /package/dist/{uninstall-DX6LFKMX.js.map → uninstall-C62ZOK32.js.map} +0 -0
- /package/dist/{update-P2IPG7RO.js.map → update-2UGOFN5C.js.map} +0 -0
|
@@ -1,53 +1,113 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
runHookInstall
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-PDFS5VFE.js";
|
|
5
5
|
import {
|
|
6
6
|
buildProviderModelChoices,
|
|
7
7
|
buildProviderSetupView,
|
|
8
|
-
getProviderLabel,
|
|
9
8
|
parseAgentSelection
|
|
10
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-J7DNV2DH.js";
|
|
11
10
|
import {
|
|
11
|
+
disabledAgentProviderMessage,
|
|
12
|
+
formatEnabledAgentProviderList,
|
|
12
13
|
isAgentProviderId,
|
|
14
|
+
isEnabledAgentProviderId,
|
|
13
15
|
readConfig,
|
|
14
16
|
writeConfig
|
|
15
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-3E7JNMTZ.js";
|
|
18
|
+
|
|
19
|
+
// src/agent/providers/codex-instructions.ts
|
|
20
|
+
import { existsSync } from "fs";
|
|
21
|
+
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
22
|
+
import path from "path";
|
|
23
|
+
var CODEX_INSTRUCTIONS_START = "<!-- codealmanac:start -->";
|
|
24
|
+
var CODEX_INSTRUCTIONS_END = "<!-- codealmanac:end -->";
|
|
25
|
+
var CODEX_INSTRUCTIONS_BODY = `${CODEX_INSTRUCTIONS_START}
|
|
26
|
+
## codealmanac
|
|
27
|
+
|
|
28
|
+
Use codealmanac before answering codebase questions:
|
|
29
|
+
- Search the wiki for relevant context.
|
|
30
|
+
- Read matching pages before making claims about the codebase.
|
|
31
|
+
- Update the wiki when implementation decisions, workflows, invariants, or gotchas change.
|
|
32
|
+
|
|
33
|
+
${CODEX_INSTRUCTIONS_END}`;
|
|
34
|
+
async function ensureCodexInstructions(codexDir) {
|
|
35
|
+
await mkdir(codexDir, { recursive: true });
|
|
36
|
+
const agentsPath = await resolveCodexAgentsPath(codexDir);
|
|
37
|
+
let existing = "";
|
|
38
|
+
if (existsSync(agentsPath)) {
|
|
39
|
+
existing = await readFile(agentsPath, "utf8");
|
|
40
|
+
}
|
|
41
|
+
const next = upsertManagedBlock(
|
|
42
|
+
existing,
|
|
43
|
+
CODEX_INSTRUCTIONS_START,
|
|
44
|
+
CODEX_INSTRUCTIONS_END,
|
|
45
|
+
CODEX_INSTRUCTIONS_BODY
|
|
46
|
+
);
|
|
47
|
+
if (next === existing) return false;
|
|
48
|
+
await writeFile(agentsPath, next, "utf8");
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
async function resolveCodexAgentsPath(codexDir) {
|
|
52
|
+
const overridePath = path.join(codexDir, "AGENTS.override.md");
|
|
53
|
+
if (existsSync(overridePath)) {
|
|
54
|
+
try {
|
|
55
|
+
const body = await readFile(overridePath, "utf8");
|
|
56
|
+
if (body.trim().length > 0) return overridePath;
|
|
57
|
+
} catch {
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return path.join(codexDir, "AGENTS.md");
|
|
61
|
+
}
|
|
62
|
+
function hasCodexInstructions(contents) {
|
|
63
|
+
return contents.includes(CODEX_INSTRUCTIONS_START) && contents.includes(CODEX_INSTRUCTIONS_END);
|
|
64
|
+
}
|
|
65
|
+
function upsertManagedBlock(contents, start, end, block) {
|
|
66
|
+
const startIndex = contents.indexOf(start);
|
|
67
|
+
const endIndex = contents.indexOf(end);
|
|
68
|
+
if (startIndex !== -1 && endIndex !== -1 && endIndex > startIndex) {
|
|
69
|
+
const afterEnd = endIndex + end.length;
|
|
70
|
+
return `${contents.slice(0, startIndex)}${block}${contents.slice(afterEnd)}`;
|
|
71
|
+
}
|
|
72
|
+
const sep = contents.length === 0 ? "" : contents.endsWith("\n") ? "\n" : "\n\n";
|
|
73
|
+
return `${contents}${sep}${block}
|
|
74
|
+
`;
|
|
75
|
+
}
|
|
16
76
|
|
|
17
77
|
// src/commands/setup.ts
|
|
18
|
-
import { existsSync as
|
|
78
|
+
import { existsSync as existsSync3 } from "fs";
|
|
19
79
|
import { spawn } from "child_process";
|
|
20
80
|
import {
|
|
21
81
|
copyFile,
|
|
22
|
-
mkdir,
|
|
23
|
-
readFile,
|
|
24
|
-
writeFile
|
|
82
|
+
mkdir as mkdir2,
|
|
83
|
+
readFile as readFile2,
|
|
84
|
+
writeFile as writeFile2
|
|
25
85
|
} from "fs/promises";
|
|
26
86
|
import { createRequire as createRequire2 } from "module";
|
|
27
87
|
import { homedir as homedir2 } from "os";
|
|
28
|
-
import
|
|
88
|
+
import path4 from "path";
|
|
29
89
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
30
90
|
|
|
31
91
|
// src/commands/setup/install-path.ts
|
|
32
92
|
import { execFile } from "child_process";
|
|
33
93
|
import { createRequire } from "module";
|
|
34
94
|
import { homedir } from "os";
|
|
35
|
-
import
|
|
95
|
+
import path2 from "path";
|
|
36
96
|
import { fileURLToPath } from "url";
|
|
37
97
|
function detectCurrentInstallPath() {
|
|
38
98
|
try {
|
|
39
99
|
const req = createRequire(import.meta.url);
|
|
40
100
|
const here = fileURLToPath(import.meta.url);
|
|
41
|
-
let dir =
|
|
101
|
+
let dir = path2.dirname(here);
|
|
42
102
|
for (let i = 0; i < 6; i++) {
|
|
43
|
-
const pkgPath =
|
|
103
|
+
const pkgPath = path2.join(dir, "package.json");
|
|
44
104
|
try {
|
|
45
105
|
const raw = req("fs").readFileSync(pkgPath, "utf-8");
|
|
46
106
|
const pkg = JSON.parse(raw);
|
|
47
107
|
if (pkg.name === "codealmanac") return dir;
|
|
48
108
|
} catch {
|
|
49
109
|
}
|
|
50
|
-
const parent =
|
|
110
|
+
const parent = path2.dirname(dir);
|
|
51
111
|
if (parent === dir) break;
|
|
52
112
|
dir = parent;
|
|
53
113
|
}
|
|
@@ -58,8 +118,8 @@ function detectCurrentInstallPath() {
|
|
|
58
118
|
function detectEphemeral(installPath) {
|
|
59
119
|
if (installPath.length === 0) return false;
|
|
60
120
|
const home = homedir();
|
|
61
|
-
if (installPath.startsWith(
|
|
62
|
-
if (installPath.startsWith(
|
|
121
|
+
if (installPath.startsWith(path2.join(home, ".npm", "_npx"))) return true;
|
|
122
|
+
if (installPath.startsWith(path2.join(home, ".local", "share", "pnpm", "dlx"))) return true;
|
|
63
123
|
if (installPath.startsWith("/tmp/")) return true;
|
|
64
124
|
if (installPath.startsWith("/var/folders/")) return true;
|
|
65
125
|
return false;
|
|
@@ -86,8 +146,8 @@ function spawnGlobalInstall() {
|
|
|
86
146
|
}
|
|
87
147
|
|
|
88
148
|
// src/commands/setup/next-steps.ts
|
|
89
|
-
import { existsSync, readdirSync } from "fs";
|
|
90
|
-
import
|
|
149
|
+
import { existsSync as existsSync2, readdirSync } from "fs";
|
|
150
|
+
import path3 from "path";
|
|
91
151
|
var RST = "\x1B[0m";
|
|
92
152
|
var BOLD = "\x1B[1m";
|
|
93
153
|
var DIM = "\x1B[2m";
|
|
@@ -142,8 +202,8 @@ function countExistingPages(cwd) {
|
|
|
142
202
|
try {
|
|
143
203
|
let dir = cwd;
|
|
144
204
|
for (let i = 0; i < 10; i++) {
|
|
145
|
-
const pagesDir =
|
|
146
|
-
if (
|
|
205
|
+
const pagesDir = path3.join(dir, ".almanac", "pages");
|
|
206
|
+
if (existsSync2(pagesDir)) {
|
|
147
207
|
try {
|
|
148
208
|
const entries = readdirSync(pagesDir);
|
|
149
209
|
return entries.filter((e) => e.endsWith(".md")).length;
|
|
@@ -151,7 +211,7 @@ function countExistingPages(cwd) {
|
|
|
151
211
|
return 0;
|
|
152
212
|
}
|
|
153
213
|
}
|
|
154
|
-
const parent =
|
|
214
|
+
const parent = path3.dirname(dir);
|
|
155
215
|
if (parent === dir) break;
|
|
156
216
|
dir = parent;
|
|
157
217
|
}
|
|
@@ -191,7 +251,7 @@ function printBanner(out) {
|
|
|
191
251
|
`);
|
|
192
252
|
}
|
|
193
253
|
out.write(`
|
|
194
|
-
${WHITE_BOLD2}
|
|
254
|
+
${WHITE_BOLD2} Set up your automatic codebase wiki${RST2}
|
|
195
255
|
`);
|
|
196
256
|
}
|
|
197
257
|
function printBadge(out) {
|
|
@@ -224,13 +284,25 @@ async function runSetup(options = {}) {
|
|
|
224
284
|
}
|
|
225
285
|
printBanner(out);
|
|
226
286
|
printBadge(out);
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
287
|
+
let agentChoice;
|
|
288
|
+
try {
|
|
289
|
+
agentChoice = await chooseDefaultAgent({
|
|
290
|
+
out,
|
|
291
|
+
interactive,
|
|
292
|
+
requested: options.agent,
|
|
293
|
+
requestedModel: options.model,
|
|
294
|
+
spawnCli: options.spawnCli
|
|
295
|
+
});
|
|
296
|
+
} catch (err) {
|
|
297
|
+
if (isSetupInterrupted(err)) {
|
|
298
|
+
return {
|
|
299
|
+
stdout: "",
|
|
300
|
+
stderr: "almanac: setup cancelled\n",
|
|
301
|
+
exitCode: 130
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
throw err;
|
|
305
|
+
}
|
|
234
306
|
if (!agentChoice.ok) {
|
|
235
307
|
return {
|
|
236
308
|
stdout: "",
|
|
@@ -241,7 +313,7 @@ async function runSetup(options = {}) {
|
|
|
241
313
|
}
|
|
242
314
|
stepDone(
|
|
243
315
|
out,
|
|
244
|
-
`
|
|
316
|
+
`Agent: ${WHITE_BOLD2}${agentChoice.provider}${RST2} (${agentChoice.model ?? "provider default"})`
|
|
245
317
|
);
|
|
246
318
|
out.write(BAR + "\n");
|
|
247
319
|
const ephem = options.installPath !== void 0 ? options.installPath !== null ? detectEphemeral(options.installPath) : false : detectEphemeral(detectCurrentInstallPath());
|
|
@@ -281,7 +353,7 @@ async function runSetup(options = {}) {
|
|
|
281
353
|
} else if (interactive) {
|
|
282
354
|
hookAction = await confirm(
|
|
283
355
|
out,
|
|
284
|
-
"
|
|
356
|
+
"Keep your codebase wiki up to date automatically?",
|
|
285
357
|
true
|
|
286
358
|
);
|
|
287
359
|
}
|
|
@@ -294,27 +366,26 @@ async function runSetup(options = {}) {
|
|
|
294
366
|
stableHooksDir: options.stableHooksDir
|
|
295
367
|
});
|
|
296
368
|
if (res.exitCode !== 0) {
|
|
297
|
-
stepActive(out, `
|
|
369
|
+
stepActive(out, `SessionEnd hook: ${res.stderr.trim()}`);
|
|
298
370
|
return {
|
|
299
371
|
stdout: "",
|
|
300
372
|
stderr: res.stderr,
|
|
301
373
|
exitCode: res.exitCode
|
|
302
374
|
};
|
|
303
375
|
}
|
|
304
|
-
hookResultLine = res.stdout.includes("already installed") ? `Auto-capture hooks ${DIM2}already installed${RST2}` : `Auto-capture
|
|
376
|
+
hookResultLine = res.stdout.includes("already installed") ? `Auto-capture hooks ${DIM2}already installed${RST2}` : `Auto-capture installed`;
|
|
305
377
|
stepDone(out, hookResultLine);
|
|
306
378
|
} else {
|
|
307
|
-
stepSkipped(out, `Auto-capture
|
|
379
|
+
stepSkipped(out, `Auto-capture ${DIM2}skipped${RST2}`);
|
|
308
380
|
}
|
|
309
381
|
out.write(BAR + "\n");
|
|
310
382
|
let guidesAction = "install";
|
|
311
|
-
const providerLabel = getProviderLabel(agentChoice.provider);
|
|
312
383
|
if (options.skipGuides === true) {
|
|
313
384
|
guidesAction = "skip";
|
|
314
385
|
} else if (interactive) {
|
|
315
386
|
guidesAction = await confirm(
|
|
316
387
|
out,
|
|
317
|
-
|
|
388
|
+
"Add codealmanac instructions for your AI agents?",
|
|
318
389
|
true
|
|
319
390
|
);
|
|
320
391
|
}
|
|
@@ -322,12 +393,11 @@ async function runSetup(options = {}) {
|
|
|
322
393
|
if (guidesAction === "install") {
|
|
323
394
|
try {
|
|
324
395
|
const summary = await installGuides({
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
guidesDir: options.guidesDir ?? resolveGuidesDir()
|
|
328
|
-
cwd: process.cwd()
|
|
396
|
+
claudeDir: options.claudeDir ?? path4.join(homedir2(), ".claude"),
|
|
397
|
+
codexDir: options.codexDir ?? path4.join(homedir2(), ".codex"),
|
|
398
|
+
guidesDir: options.guidesDir ?? resolveGuidesDir()
|
|
329
399
|
});
|
|
330
|
-
guidesSummary = summary.anyChanges ? `
|
|
400
|
+
guidesSummary = summary.anyChanges ? `Agent instructions added` : `Agent instructions ${DIM2}already added${RST2}`;
|
|
331
401
|
stepDone(out, guidesSummary);
|
|
332
402
|
} catch (err) {
|
|
333
403
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -339,14 +409,13 @@ async function runSetup(options = {}) {
|
|
|
339
409
|
};
|
|
340
410
|
}
|
|
341
411
|
} else {
|
|
342
|
-
stepSkipped(out, `
|
|
412
|
+
stepSkipped(out, `Agent instructions ${DIM2}skipped${RST2}`);
|
|
343
413
|
}
|
|
344
414
|
out.write(BAR + "\n");
|
|
345
415
|
stepDone(out, `${BLUE2}Setup complete${RST2}`);
|
|
346
416
|
out.write("\n");
|
|
347
417
|
const existingPageCount = countExistingPages(process.cwd());
|
|
348
418
|
printNextSteps(out, existingPageCount);
|
|
349
|
-
printProviderNextSteps(out);
|
|
350
419
|
return { stdout: "", stderr: "", exitCode: 0 };
|
|
351
420
|
}
|
|
352
421
|
async function chooseDefaultAgent(args) {
|
|
@@ -357,34 +426,66 @@ async function chooseDefaultAgent(args) {
|
|
|
357
426
|
view = await buildProviderSetupView({ config, spawnCli: args.spawnCli });
|
|
358
427
|
}
|
|
359
428
|
if (args.interactive && args.requested === void 0 && view !== null) {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
429
|
+
while (true) {
|
|
430
|
+
const choice = await selectChoice({
|
|
431
|
+
out: args.out,
|
|
432
|
+
title: "Choose your agent",
|
|
433
|
+
help: "Choose the AI agent codealmanac should use.",
|
|
434
|
+
choices: view.choices.map((choice2) => ({
|
|
435
|
+
value: choice2,
|
|
436
|
+
line: formatProviderChoice(choice2),
|
|
437
|
+
aliases: [choice2.id, choice2.label.toLowerCase()]
|
|
438
|
+
})),
|
|
439
|
+
defaultIndex: Math.max(
|
|
440
|
+
0,
|
|
441
|
+
view.choices.findIndex(
|
|
442
|
+
(choice2) => choice2.id === view?.recommendedProvider
|
|
443
|
+
)
|
|
444
|
+
)
|
|
445
|
+
});
|
|
446
|
+
if (choice.ready) {
|
|
447
|
+
selected = choice.id;
|
|
448
|
+
break;
|
|
449
|
+
}
|
|
450
|
+
if (choice.readiness === "not-authenticated" && choice.fixCommand !== null) {
|
|
451
|
+
const command = choice.fixCommand.startsWith("run: ") ? choice.fixCommand.slice("run: ".length) : choice.fixCommand;
|
|
452
|
+
const runLogin = await confirm(
|
|
453
|
+
args.out,
|
|
454
|
+
`${choice.label} sign-in is needed. Run '${command}' now?`,
|
|
455
|
+
true
|
|
456
|
+
);
|
|
457
|
+
if (runLogin === "install") {
|
|
458
|
+
const login = await runLoginCommand(command);
|
|
459
|
+
if (!login.ok) {
|
|
460
|
+
stepActive(args.out, `${choice.label} login failed: ${login.error}`);
|
|
461
|
+
}
|
|
462
|
+
view = await buildProviderSetupView({ config, spawnCli: args.spawnCli });
|
|
463
|
+
const refreshed = view.choices.find((next) => next.id === choice.id);
|
|
464
|
+
if (refreshed?.ready === true) {
|
|
465
|
+
selected = refreshed.id;
|
|
466
|
+
break;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
continue;
|
|
470
|
+
}
|
|
471
|
+
showUnavailableProvider(args.out, choice);
|
|
472
|
+
await waitForEnter(args.out, "Press Enter to choose a different agent.");
|
|
378
473
|
}
|
|
379
474
|
}
|
|
380
475
|
const parsed = parseAgentSelection(selected);
|
|
381
476
|
if (parsed.provider === null || !isAgentProviderId(parsed.provider)) {
|
|
382
477
|
return {
|
|
383
478
|
ok: false,
|
|
384
|
-
error: `unknown agent '${selected}'. Expected one of:
|
|
479
|
+
error: `unknown agent '${selected}'. Expected one of: ${formatEnabledAgentProviderList()}.`
|
|
385
480
|
};
|
|
386
481
|
}
|
|
387
482
|
const provider = parsed.provider;
|
|
483
|
+
if (!isEnabledAgentProviderId(provider)) {
|
|
484
|
+
return {
|
|
485
|
+
ok: false,
|
|
486
|
+
error: disabledAgentProviderMessage(provider)
|
|
487
|
+
};
|
|
488
|
+
}
|
|
388
489
|
let selectedChoice = view?.choices.find((choice) => choice.id === provider);
|
|
389
490
|
if (args.interactive && selectedChoice !== void 0 && !selectedChoice.ready && selectedChoice.fixCommand?.startsWith("run: ") === true) {
|
|
390
491
|
const command = selectedChoice.fixCommand.slice("run: ".length);
|
|
@@ -403,6 +504,12 @@ async function chooseDefaultAgent(args) {
|
|
|
403
504
|
}
|
|
404
505
|
}
|
|
405
506
|
}
|
|
507
|
+
if (selectedChoice !== void 0 && !selectedChoice.ready) {
|
|
508
|
+
return {
|
|
509
|
+
ok: false,
|
|
510
|
+
error: `${selectedChoice.label} is not ready: ${selectedChoice.fixCommand ?? selectedChoice.detail}`
|
|
511
|
+
};
|
|
512
|
+
}
|
|
406
513
|
const requestedModel = args.requestedModel ?? parsed.model;
|
|
407
514
|
const model = requestedModel ?? await chooseProviderModel({
|
|
408
515
|
out: args.out,
|
|
@@ -422,47 +529,210 @@ async function chooseDefaultAgent(args) {
|
|
|
422
529
|
}
|
|
423
530
|
}
|
|
424
531
|
});
|
|
425
|
-
if (!args.interactive || args.requested !== void 0) {
|
|
532
|
+
if ((!args.interactive || args.requested !== void 0) && selectedChoice !== void 0) {
|
|
426
533
|
const detail = selectedChoice?.ready === true ? "ready" : selectedChoice?.fixCommand ?? selectedChoice?.detail ?? "status unknown";
|
|
427
534
|
stepDone(args.out, `Agent readiness: ${detail}`);
|
|
428
535
|
}
|
|
429
536
|
return { ok: true, provider, model };
|
|
430
537
|
}
|
|
431
538
|
async function chooseProviderModel(args) {
|
|
432
|
-
const choices = args.choice?.modelChoices ?? buildProviderModelChoices(args.provider, args.configuredModel);
|
|
539
|
+
const choices = args.choice?.modelChoices ?? await buildProviderModelChoices(args.provider, args.configuredModel);
|
|
433
540
|
const recommended = choices.find((choice) => choice.recommended) ?? choices.find((choice) => choice.source === "provider-default");
|
|
434
541
|
if (!args.interactive) {
|
|
435
542
|
return args.configuredModel ?? recommended?.value ?? null;
|
|
436
543
|
}
|
|
437
|
-
args.out.write(` Choose model for ${getProviderLabel(args.provider)}:
|
|
438
|
-
`);
|
|
439
|
-
choices.forEach((choice, index) => {
|
|
440
|
-
const marker = choice.recommended ? " recommended" : "";
|
|
441
|
-
const current = choice.value === args.configuredModel ? " current" : "";
|
|
442
|
-
args.out.write(
|
|
443
|
-
` ${index + 1}. ${choice.label}${marker}${current}
|
|
444
|
-
`
|
|
445
|
-
);
|
|
446
|
-
});
|
|
447
544
|
const currentIndex = choices.findIndex(
|
|
448
545
|
(choice) => choice.value === args.configuredModel
|
|
449
546
|
);
|
|
450
547
|
const recommendedIndex = choices.findIndex((choice) => choice.recommended);
|
|
451
|
-
const defaultIndex =
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
548
|
+
const defaultIndex = Math.max(
|
|
549
|
+
0,
|
|
550
|
+
currentIndex >= 0 ? currentIndex : recommendedIndex >= 0 ? recommendedIndex : 0
|
|
551
|
+
);
|
|
552
|
+
const modelChoice = await selectChoice({
|
|
553
|
+
out: args.out,
|
|
554
|
+
title: `Choose ${providerDisplayName(args.provider)} model`,
|
|
555
|
+
choices: choices.map((choice) => ({
|
|
556
|
+
value: choice,
|
|
557
|
+
line: formatModelChoice(choice, args.configuredModel),
|
|
558
|
+
aliases: choice.value === null ? ["default", "provider default"] : [String(choice.value)]
|
|
559
|
+
})),
|
|
560
|
+
defaultIndex
|
|
561
|
+
});
|
|
460
562
|
if (modelChoice?.source === "custom") {
|
|
461
|
-
const custom = await promptText(args.out, "
|
|
563
|
+
const custom = await promptText(args.out, "Model name", "");
|
|
462
564
|
return custom.length > 0 ? custom : recommended?.value ?? null;
|
|
463
565
|
}
|
|
464
566
|
return modelChoice?.value ?? recommended?.value ?? null;
|
|
465
567
|
}
|
|
568
|
+
async function selectChoice(args) {
|
|
569
|
+
const selected = clampIndex(args.defaultIndex, args.choices.length);
|
|
570
|
+
if (canUseRawSelect()) {
|
|
571
|
+
return await selectChoiceRaw({ ...args, defaultIndex: selected });
|
|
572
|
+
}
|
|
573
|
+
renderSelect(args.out, {
|
|
574
|
+
title: args.title,
|
|
575
|
+
help: args.help,
|
|
576
|
+
choices: args.choices,
|
|
577
|
+
selected,
|
|
578
|
+
raw: false
|
|
579
|
+
});
|
|
580
|
+
const answer = await promptText(args.out, "Select", String(selected + 1));
|
|
581
|
+
const index = Number.parseInt(answer, 10);
|
|
582
|
+
if (Number.isInteger(index) && index >= 1 && index <= args.choices.length) {
|
|
583
|
+
return args.choices[index - 1].value;
|
|
584
|
+
}
|
|
585
|
+
const normalized = answer.trim().toLowerCase();
|
|
586
|
+
const matched = args.choices.find(
|
|
587
|
+
(choice) => choice.aliases?.some((alias) => alias.toLowerCase() === normalized)
|
|
588
|
+
);
|
|
589
|
+
return (matched ?? args.choices[selected]).value;
|
|
590
|
+
}
|
|
591
|
+
async function selectChoiceRaw(args) {
|
|
592
|
+
return new Promise((resolve, reject) => {
|
|
593
|
+
let selected = args.defaultIndex;
|
|
594
|
+
let renderedLines = 0;
|
|
595
|
+
const input = process.stdin;
|
|
596
|
+
const render = () => {
|
|
597
|
+
if (renderedLines > 0) {
|
|
598
|
+
args.out.write(`\x1B[${renderedLines}A\x1B[0J`);
|
|
599
|
+
}
|
|
600
|
+
renderedLines = renderSelect(args.out, {
|
|
601
|
+
title: args.title,
|
|
602
|
+
help: args.help,
|
|
603
|
+
choices: args.choices,
|
|
604
|
+
selected,
|
|
605
|
+
raw: true
|
|
606
|
+
});
|
|
607
|
+
};
|
|
608
|
+
const cleanup = () => {
|
|
609
|
+
input.removeListener("data", onData);
|
|
610
|
+
input.setRawMode?.(false);
|
|
611
|
+
input.pause();
|
|
612
|
+
};
|
|
613
|
+
const onData = (chunk) => {
|
|
614
|
+
const key = chunk.toString("utf8");
|
|
615
|
+
if (key === "") {
|
|
616
|
+
cleanup();
|
|
617
|
+
args.out.write("\n");
|
|
618
|
+
reject(new SetupInterruptedError());
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
if (key === "\r" || key === "\n") {
|
|
622
|
+
cleanup();
|
|
623
|
+
args.out.write("\n");
|
|
624
|
+
resolve(args.choices[selected].value);
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
if (key === "\x1B[A") {
|
|
628
|
+
selected = selected === 0 ? args.choices.length - 1 : selected - 1;
|
|
629
|
+
render();
|
|
630
|
+
} else if (key === "\x1B[B") {
|
|
631
|
+
selected = selected === args.choices.length - 1 ? 0 : selected + 1;
|
|
632
|
+
render();
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
input.setRawMode?.(true);
|
|
636
|
+
input.resume();
|
|
637
|
+
input.on("data", onData);
|
|
638
|
+
render();
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
function renderSelect(out, args) {
|
|
642
|
+
let lines = 0;
|
|
643
|
+
out.write(` ${WHITE_BOLD2}${args.title}${RST2}
|
|
644
|
+
`);
|
|
645
|
+
lines++;
|
|
646
|
+
if (args.help !== void 0) {
|
|
647
|
+
out.write(` ${DIM2}${args.help}${RST2}
|
|
648
|
+
`);
|
|
649
|
+
lines++;
|
|
650
|
+
}
|
|
651
|
+
out.write("\n");
|
|
652
|
+
lines++;
|
|
653
|
+
args.choices.forEach((choice, index) => {
|
|
654
|
+
const pointer = index === args.selected ? `${BLUE2}\u203A${RST2}` : " ";
|
|
655
|
+
out.write(` ${pointer} ${choice.line}
|
|
656
|
+
`);
|
|
657
|
+
lines++;
|
|
658
|
+
});
|
|
659
|
+
const hint = args.raw ? `Use \u2191/\u2193 to move, Enter to select` : `Type a number or name, then press Enter`;
|
|
660
|
+
out.write(`
|
|
661
|
+
${DIM2}${hint}${RST2}
|
|
662
|
+
`);
|
|
663
|
+
lines += 2;
|
|
664
|
+
return lines;
|
|
665
|
+
}
|
|
666
|
+
var SetupInterruptedError = class extends Error {
|
|
667
|
+
constructor() {
|
|
668
|
+
super("setup interrupted");
|
|
669
|
+
}
|
|
670
|
+
};
|
|
671
|
+
function isSetupInterrupted(err) {
|
|
672
|
+
return err instanceof SetupInterruptedError;
|
|
673
|
+
}
|
|
674
|
+
function canUseRawSelect() {
|
|
675
|
+
const input = process.stdin;
|
|
676
|
+
return process.stdin.isTTY === true && typeof input.setRawMode === "function";
|
|
677
|
+
}
|
|
678
|
+
function clampIndex(index, length) {
|
|
679
|
+
if (length <= 0) return 0;
|
|
680
|
+
if (index < 0) return 0;
|
|
681
|
+
if (index >= length) return length - 1;
|
|
682
|
+
return index;
|
|
683
|
+
}
|
|
684
|
+
function formatProviderChoice(choice) {
|
|
685
|
+
const status = providerStatusLabel(choice);
|
|
686
|
+
const detail = providerDetailLabel(choice);
|
|
687
|
+
const tag = choice.recommended ? ` ${DIM2}recommended${RST2}` : "";
|
|
688
|
+
return `${choice.label.padEnd(8)} ${status.padEnd(15)} ${detail}${tag}`;
|
|
689
|
+
}
|
|
690
|
+
function providerStatusLabel(choice) {
|
|
691
|
+
if (choice.ready) {
|
|
692
|
+
return choice.detail === "ANTHROPIC_API_KEY set" ? "API key set" : "signed in";
|
|
693
|
+
}
|
|
694
|
+
return choice.readiness === "missing" ? "not installed" : "sign in needed";
|
|
695
|
+
}
|
|
696
|
+
function providerDetailLabel(choice) {
|
|
697
|
+
if (choice.ready) return choice.account ?? choice.detail;
|
|
698
|
+
if (choice.fixCommand === null) return choice.detail;
|
|
699
|
+
return choice.fixCommand.startsWith("run: ") ? choice.fixCommand.slice("run: ".length) : choice.fixCommand;
|
|
700
|
+
}
|
|
701
|
+
function showUnavailableProvider(out, choice) {
|
|
702
|
+
if (choice.readiness === "missing") {
|
|
703
|
+
out.write(
|
|
704
|
+
`
|
|
705
|
+
${WHITE_BOLD2}${choice.label} is not installed.${RST2}
|
|
706
|
+
${providerDetailLabel(choice)}
|
|
707
|
+
|
|
708
|
+
`
|
|
709
|
+
);
|
|
710
|
+
return;
|
|
711
|
+
}
|
|
712
|
+
out.write(
|
|
713
|
+
`
|
|
714
|
+
${WHITE_BOLD2}${choice.label} is not signed in.${RST2}
|
|
715
|
+
Run: ${providerDetailLabel(choice)}
|
|
716
|
+
|
|
717
|
+
`
|
|
718
|
+
);
|
|
719
|
+
}
|
|
720
|
+
function formatModelChoice(choice, configuredModel) {
|
|
721
|
+
const marker = choice.recommended ? ` ${DIM2}recommended${RST2}` : choice.value === configuredModel ? ` ${DIM2}current${RST2}` : "";
|
|
722
|
+
const label = choice.source === "provider-default" && choice.value !== null ? friendlyModelLabel(choice.value) : choice.label;
|
|
723
|
+
return `${label}${marker}`;
|
|
724
|
+
}
|
|
725
|
+
function friendlyModelLabel(value) {
|
|
726
|
+
if (value === "claude-sonnet-4-6") return "Sonnet 4.6";
|
|
727
|
+
if (value === "claude-opus-4-7") return "Opus 4.7";
|
|
728
|
+
if (value === "claude-haiku-4-5-20251001") return "Haiku 4.5";
|
|
729
|
+
return value;
|
|
730
|
+
}
|
|
731
|
+
function providerDisplayName(provider) {
|
|
732
|
+
if (provider === "claude") return "Claude";
|
|
733
|
+
if (provider === "codex") return "Codex";
|
|
734
|
+
return "Cursor";
|
|
735
|
+
}
|
|
466
736
|
async function runLoginCommand(command) {
|
|
467
737
|
return new Promise((resolve) => {
|
|
468
738
|
const child = spawn(command, {
|
|
@@ -481,83 +751,35 @@ async function runLoginCommand(command) {
|
|
|
481
751
|
});
|
|
482
752
|
});
|
|
483
753
|
}
|
|
484
|
-
var CODEX_BLOCK_START = "<!-- codealmanac:start -->";
|
|
485
|
-
var CODEX_BLOCK_END = "<!-- codealmanac:end -->";
|
|
486
754
|
async function installGuides(options) {
|
|
487
|
-
|
|
488
|
-
const
|
|
489
|
-
|
|
755
|
+
await mkdir2(options.claudeDir, { recursive: true });
|
|
756
|
+
const srcMini = path4.join(options.guidesDir, "mini.md");
|
|
757
|
+
const srcRef = path4.join(options.guidesDir, "reference.md");
|
|
758
|
+
if (!existsSync3(srcMini)) {
|
|
490
759
|
throw new Error(`missing bundled guide: ${srcMini}`);
|
|
491
760
|
}
|
|
492
|
-
if (!
|
|
761
|
+
if (!existsSync3(srcRef)) {
|
|
493
762
|
throw new Error(`missing bundled guide: ${srcRef}`);
|
|
494
763
|
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
return await installClaudeGuides(options, srcMini, srcRef);
|
|
498
|
-
case "codex":
|
|
499
|
-
return await installCodexGuides(srcMini, srcRef);
|
|
500
|
-
case "cursor":
|
|
501
|
-
return await installCursorGuides(options.cwd, srcMini);
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
async function installClaudeGuides(options, srcMini, srcRef) {
|
|
505
|
-
await mkdir(options.claudeDir, { recursive: true });
|
|
506
|
-
const destMini = path3.join(options.claudeDir, "codealmanac.md");
|
|
507
|
-
const destRef = path3.join(options.claudeDir, "codealmanac-reference.md");
|
|
764
|
+
const destMini = path4.join(options.claudeDir, "codealmanac.md");
|
|
765
|
+
const destRef = path4.join(options.claudeDir, "codealmanac-reference.md");
|
|
508
766
|
const miniChanged = await copyIfChanged(srcMini, destMini);
|
|
509
767
|
const refChanged = await copyIfChanged(srcRef, destRef);
|
|
510
|
-
const claudeMd =
|
|
768
|
+
const claudeMd = path4.join(options.claudeDir, "CLAUDE.md");
|
|
511
769
|
const importChanged = await ensureImport(claudeMd);
|
|
770
|
+
const codexChanged = await ensureCodexInstructions(options.codexDir);
|
|
512
771
|
const filesWritten = [];
|
|
513
772
|
if (miniChanged) filesWritten.push("codealmanac.md");
|
|
514
773
|
if (refChanged) filesWritten.push("codealmanac-reference.md");
|
|
515
774
|
if (importChanged) filesWritten.push("CLAUDE.md");
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
anyChanges: filesWritten.length > 0,
|
|
519
|
-
filesWritten
|
|
520
|
-
};
|
|
521
|
-
}
|
|
522
|
-
async function installCodexGuides(srcMini, srcRef) {
|
|
523
|
-
const codexDir = path3.join(homedir2(), ".codex");
|
|
524
|
-
await mkdir(codexDir, { recursive: true });
|
|
525
|
-
const destMini = path3.join(codexDir, "codealmanac.md");
|
|
526
|
-
const destRef = path3.join(codexDir, "codealmanac-reference.md");
|
|
527
|
-
const miniChanged = await copyIfChanged(srcMini, destMini);
|
|
528
|
-
const refChanged = await copyIfChanged(srcRef, destRef);
|
|
529
|
-
const agentsChanged = await ensureManagedBlock(
|
|
530
|
-
path3.join(codexDir, "AGENTS.md"),
|
|
531
|
-
codexGuideBlock()
|
|
532
|
-
);
|
|
533
|
-
const filesWritten = [];
|
|
534
|
-
if (miniChanged) filesWritten.push("codealmanac.md");
|
|
535
|
-
if (refChanged) filesWritten.push("codealmanac-reference.md");
|
|
536
|
-
if (agentsChanged) filesWritten.push("AGENTS.md");
|
|
537
|
-
return {
|
|
538
|
-
providerLabel: "Codex",
|
|
539
|
-
anyChanges: filesWritten.length > 0,
|
|
540
|
-
filesWritten
|
|
541
|
-
};
|
|
542
|
-
}
|
|
543
|
-
async function installCursorGuides(cwd, srcMini) {
|
|
544
|
-
const rulesDir = path3.join(cwd, ".cursor", "rules");
|
|
545
|
-
await mkdir(rulesDir, { recursive: true });
|
|
546
|
-
const mini = await readFile(srcMini, "utf8");
|
|
547
|
-
const dest = path3.join(rulesDir, "codealmanac.mdc");
|
|
548
|
-
const body = "---\ndescription: Use codealmanac wiki context during coding work\nalwaysApply: true\n---\n\n" + mini;
|
|
549
|
-
const changed = await writeIfChanged(dest, body);
|
|
550
|
-
return {
|
|
551
|
-
providerLabel: "Cursor",
|
|
552
|
-
anyChanges: changed,
|
|
553
|
-
filesWritten: changed ? [".cursor/rules/codealmanac.mdc"] : []
|
|
554
|
-
};
|
|
775
|
+
if (codexChanged) filesWritten.push("AGENTS.md");
|
|
776
|
+
return { anyChanges: filesWritten.length > 0, filesWritten };
|
|
555
777
|
}
|
|
556
778
|
async function copyIfChanged(src, dest) {
|
|
557
|
-
const srcBytes = await
|
|
558
|
-
if (
|
|
779
|
+
const srcBytes = await readFile2(src);
|
|
780
|
+
if (existsSync3(dest)) {
|
|
559
781
|
try {
|
|
560
|
-
const destBytes = await
|
|
782
|
+
const destBytes = await readFile2(dest);
|
|
561
783
|
if (srcBytes.equals(destBytes)) return false;
|
|
562
784
|
} catch {
|
|
563
785
|
}
|
|
@@ -565,56 +787,17 @@ async function copyIfChanged(src, dest) {
|
|
|
565
787
|
await copyFile(src, dest);
|
|
566
788
|
return true;
|
|
567
789
|
}
|
|
568
|
-
async function writeIfChanged(dest, body) {
|
|
569
|
-
if (existsSync2(dest)) {
|
|
570
|
-
try {
|
|
571
|
-
if (await readFile(dest, "utf8") === body) return false;
|
|
572
|
-
} catch {
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
await writeFile(dest, body, "utf8");
|
|
576
|
-
return true;
|
|
577
|
-
}
|
|
578
|
-
async function ensureManagedBlock(file, block) {
|
|
579
|
-
let existing = "";
|
|
580
|
-
if (existsSync2(file)) existing = await readFile(file, "utf8");
|
|
581
|
-
const pattern = new RegExp(
|
|
582
|
-
`${escapeRegex(CODEX_BLOCK_START)}[\\s\\S]*?${escapeRegex(CODEX_BLOCK_END)}`
|
|
583
|
-
);
|
|
584
|
-
const next = pattern.test(existing) ? existing.replace(pattern, block.trimEnd()) : `${existing.trimEnd()}${existing.trim().length > 0 ? "\n\n" : ""}${block.trimEnd()}
|
|
585
|
-
`;
|
|
586
|
-
const normalized = next.endsWith("\n") ? next : `${next}
|
|
587
|
-
`;
|
|
588
|
-
if (normalized === existing) return false;
|
|
589
|
-
await writeFile(file, normalized, "utf8");
|
|
590
|
-
return true;
|
|
591
|
-
}
|
|
592
|
-
function codexGuideBlock() {
|
|
593
|
-
return [
|
|
594
|
-
CODEX_BLOCK_START,
|
|
595
|
-
"# codealmanac",
|
|
596
|
-
"",
|
|
597
|
-
"This machine has codealmanac installed: a local wiki for codebases.",
|
|
598
|
-
"Before codealmanac/wiki-related work, read `~/.codex/codealmanac.md`.",
|
|
599
|
-
"For the full command reference, read `~/.codex/codealmanac-reference.md` on demand.",
|
|
600
|
-
CODEX_BLOCK_END,
|
|
601
|
-
""
|
|
602
|
-
].join("\n");
|
|
603
|
-
}
|
|
604
|
-
function escapeRegex(value) {
|
|
605
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
606
|
-
}
|
|
607
790
|
var IMPORT_LINE = "@~/.claude/codealmanac.md";
|
|
608
791
|
async function ensureImport(claudeMdPath) {
|
|
609
792
|
let existing = "";
|
|
610
|
-
if (
|
|
611
|
-
existing = await
|
|
793
|
+
if (existsSync3(claudeMdPath)) {
|
|
794
|
+
existing = await readFile2(claudeMdPath, "utf8");
|
|
612
795
|
}
|
|
613
796
|
if (hasImportLine(existing)) return false;
|
|
614
797
|
const sep = existing.length === 0 ? "" : existing.endsWith("\n") ? "\n" : "\n\n";
|
|
615
798
|
const body = `${existing}${sep}${IMPORT_LINE}
|
|
616
799
|
`;
|
|
617
|
-
await
|
|
800
|
+
await writeFile2(claudeMdPath, body, "utf8");
|
|
618
801
|
return true;
|
|
619
802
|
}
|
|
620
803
|
function hasImportLine(contents) {
|
|
@@ -664,14 +847,17 @@ function promptText(out, question, defaultValue) {
|
|
|
664
847
|
process.stdin.on("data", onData);
|
|
665
848
|
});
|
|
666
849
|
}
|
|
850
|
+
async function waitForEnter(out, message) {
|
|
851
|
+
await promptText(out, message, "");
|
|
852
|
+
}
|
|
667
853
|
function resolveGuidesDir() {
|
|
668
|
-
const here =
|
|
854
|
+
const here = path4.dirname(fileURLToPath2(import.meta.url));
|
|
669
855
|
const candidates = [
|
|
670
|
-
|
|
856
|
+
path4.resolve(here, "..", "guides"),
|
|
671
857
|
// dist layout
|
|
672
|
-
|
|
858
|
+
path4.resolve(here, "..", "..", "guides"),
|
|
673
859
|
// src layout
|
|
674
|
-
|
|
860
|
+
path4.resolve(here, "..", "..", "..", "guides")
|
|
675
861
|
];
|
|
676
862
|
for (const dir of candidates) {
|
|
677
863
|
if (looksLikeGuidesDir(dir)) return dir;
|
|
@@ -679,7 +865,7 @@ function resolveGuidesDir() {
|
|
|
679
865
|
try {
|
|
680
866
|
const require2 = createRequire2(import.meta.url);
|
|
681
867
|
const pkgJson = require2.resolve("codealmanac/package.json");
|
|
682
|
-
const guides =
|
|
868
|
+
const guides = path4.join(path4.dirname(pkgJson), "guides");
|
|
683
869
|
if (looksLikeGuidesDir(guides)) return guides;
|
|
684
870
|
} catch {
|
|
685
871
|
}
|
|
@@ -688,24 +874,15 @@ function resolveGuidesDir() {
|
|
|
688
874
|
);
|
|
689
875
|
}
|
|
690
876
|
function looksLikeGuidesDir(dir) {
|
|
691
|
-
return
|
|
692
|
-
}
|
|
693
|
-
function printProviderNextSteps(out) {
|
|
694
|
-
out.write(` ${DIM2}Change provider/model later:${RST2}
|
|
695
|
-
`);
|
|
696
|
-
out.write(` ${DIM2} almanac agents list${RST2}
|
|
697
|
-
`);
|
|
698
|
-
out.write(` ${DIM2} almanac agents use <claude|codex|cursor>${RST2}
|
|
699
|
-
`);
|
|
700
|
-
out.write(
|
|
701
|
-
` ${DIM2} almanac agents model <provider> <model|--default>${RST2}
|
|
702
|
-
|
|
703
|
-
`
|
|
704
|
-
);
|
|
877
|
+
return existsSync3(path4.join(dir, "mini.md"));
|
|
705
878
|
}
|
|
706
879
|
|
|
707
880
|
export {
|
|
881
|
+
CODEX_INSTRUCTIONS_START,
|
|
882
|
+
CODEX_INSTRUCTIONS_END,
|
|
883
|
+
resolveCodexAgentsPath,
|
|
884
|
+
hasCodexInstructions,
|
|
708
885
|
runSetup,
|
|
709
886
|
IMPORT_LINE
|
|
710
887
|
};
|
|
711
|
-
//# sourceMappingURL=chunk-
|
|
888
|
+
//# sourceMappingURL=chunk-VXDPUOQ5.js.map
|