@mariozechner/pi-coding-agent 0.7.11 → 0.7.12
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 +21 -0
- package/README.md +135 -3
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +207 -60
- package/dist/main.js.map +1 -1
- package/dist/model-config.d.ts +35 -0
- package/dist/model-config.d.ts.map +1 -0
- package/dist/model-config.js +223 -0
- package/dist/model-config.js.map +1 -0
- package/dist/settings-manager.d.ts +7 -0
- package/dist/settings-manager.d.ts.map +1 -1
- package/dist/settings-manager.js +19 -0
- package/dist/settings-manager.js.map +1 -1
- package/dist/tui/footer.d.ts.map +1 -1
- package/dist/tui/footer.js +2 -2
- package/dist/tui/footer.js.map +1 -1
- package/dist/tui/model-selector.d.ts +5 -2
- package/dist/tui/model-selector.d.ts.map +1 -1
- package/dist/tui/model-selector.js +36 -19
- package/dist/tui/model-selector.js.map +1 -1
- package/dist/tui/tui-renderer.d.ts +4 -1
- package/dist/tui/tui-renderer.d.ts.map +1 -1
- package/dist/tui/tui-renderer.js +27 -2
- package/dist/tui/tui-renderer.js.map +1 -1
- package/package.json +3 -3
package/dist/main.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Agent, ProviderTransport } from "@mariozechner/pi-agent";
|
|
2
|
-
import { getModel } from "@mariozechner/pi-ai";
|
|
3
2
|
import { ProcessTerminal, TUI } from "@mariozechner/pi-tui";
|
|
4
3
|
import chalk from "chalk";
|
|
5
4
|
import { existsSync, readFileSync } from "fs";
|
|
@@ -7,6 +6,7 @@ import { homedir } from "os";
|
|
|
7
6
|
import { dirname, join, resolve } from "path";
|
|
8
7
|
import { fileURLToPath } from "url";
|
|
9
8
|
import { getChangelogPath, getNewEntries, parseChangelog } from "./changelog.js";
|
|
9
|
+
import { findModel, getApiKeyForModel, getAvailableModels } from "./model-config.js";
|
|
10
10
|
import { SessionManager } from "./session-manager.js";
|
|
11
11
|
import { SettingsManager } from "./settings-manager.js";
|
|
12
12
|
import { codingTools } from "./tools/index.js";
|
|
@@ -27,6 +27,16 @@ const envApiKeyMap = {
|
|
|
27
27
|
openrouter: ["OPENROUTER_API_KEY"],
|
|
28
28
|
zai: ["ZAI_API_KEY"],
|
|
29
29
|
};
|
|
30
|
+
const defaultModelPerProvider = {
|
|
31
|
+
anthropic: "claude-sonnet-4-5",
|
|
32
|
+
openai: "gpt-5.1-codex",
|
|
33
|
+
google: "gemini-2.5-pro",
|
|
34
|
+
openrouter: "openai/gpt-5.1-codex",
|
|
35
|
+
xai: "grok-4-fast-non-reasoning",
|
|
36
|
+
groq: "openai/gpt-oss-120b",
|
|
37
|
+
cerebras: "zai-glm-4.6",
|
|
38
|
+
zai: "glm-4.6",
|
|
39
|
+
};
|
|
30
40
|
function parseArgs(args) {
|
|
31
41
|
const result = {
|
|
32
42
|
messages: [],
|
|
@@ -169,7 +179,9 @@ function buildSystemPrompt(customPrompt) {
|
|
|
169
179
|
second: "2-digit",
|
|
170
180
|
timeZoneName: "short",
|
|
171
181
|
});
|
|
172
|
-
|
|
182
|
+
// Get absolute path to README.md
|
|
183
|
+
const readmePath = resolve(join(__dirname, "../README.md"));
|
|
184
|
+
let prompt = `You are actually not Claude, you are Pi. You are an expert coding assistant. You help users with coding tasks by reading files, executing commands, editing code, and writing new files.
|
|
173
185
|
|
|
174
186
|
Available tools:
|
|
175
187
|
- read: Read file contents
|
|
@@ -183,7 +195,11 @@ Guidelines:
|
|
|
183
195
|
- Use edit for precise changes (old text must match exactly)
|
|
184
196
|
- Use write only for new files or complete rewrites
|
|
185
197
|
- Be concise in your responses
|
|
186
|
-
- Show file paths clearly when working with files
|
|
198
|
+
- Show file paths clearly when working with files
|
|
199
|
+
|
|
200
|
+
Documentation:
|
|
201
|
+
- Your own documentation (including custom model setup) is at: ${readmePath}
|
|
202
|
+
- Read it when users ask about features, configuration, or setup, and especially if the user asks you to add a custom model or provider.`;
|
|
187
203
|
// Append project context files
|
|
188
204
|
const contextFiles = loadProjectContextFiles();
|
|
189
205
|
if (contextFiles.length > 0) {
|
|
@@ -280,8 +296,8 @@ async function selectSession(sessionManager) {
|
|
|
280
296
|
ui.start();
|
|
281
297
|
});
|
|
282
298
|
}
|
|
283
|
-
async function runInteractiveMode(agent, sessionManager, version, changelogMarkdown = null) {
|
|
284
|
-
const renderer = new TuiRenderer(agent, sessionManager, version, changelogMarkdown);
|
|
299
|
+
async function runInteractiveMode(agent, sessionManager, settingsManager, version, changelogMarkdown = null, modelFallbackMessage = null) {
|
|
300
|
+
const renderer = new TuiRenderer(agent, sessionManager, settingsManager, version, changelogMarkdown);
|
|
285
301
|
// Initialize TUI
|
|
286
302
|
await renderer.init();
|
|
287
303
|
// Set interrupt callback
|
|
@@ -290,6 +306,10 @@ async function runInteractiveMode(agent, sessionManager, version, changelogMarkd
|
|
|
290
306
|
});
|
|
291
307
|
// Render any existing messages (from --continue mode)
|
|
292
308
|
renderer.renderInitialMessages(agent.state);
|
|
309
|
+
// Show model fallback warning at the end of the chat if applicable
|
|
310
|
+
if (modelFallbackMessage) {
|
|
311
|
+
renderer.showWarning(modelFallbackMessage);
|
|
312
|
+
}
|
|
293
313
|
// Subscribe to agent events
|
|
294
314
|
agent.subscribe(async (event) => {
|
|
295
315
|
// Pass all events to the renderer
|
|
@@ -384,85 +404,197 @@ export async function main(args) {
|
|
|
384
404
|
// Set the selected session as the active session
|
|
385
405
|
sessionManager.setSessionFile(selectedSession);
|
|
386
406
|
}
|
|
387
|
-
//
|
|
388
|
-
const
|
|
389
|
-
|
|
390
|
-
//
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
//
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
407
|
+
// Settings manager
|
|
408
|
+
const settingsManager = new SettingsManager();
|
|
409
|
+
// Determine initial model using priority system:
|
|
410
|
+
// 1. CLI args (--provider and --model)
|
|
411
|
+
// 2. Restored from session (if --continue or --resume)
|
|
412
|
+
// 3. Saved default from settings.json
|
|
413
|
+
// 4. First available model with valid API key
|
|
414
|
+
// 5. null (allowed in interactive mode)
|
|
415
|
+
let initialModel = null;
|
|
416
|
+
if (parsed.provider && parsed.model) {
|
|
417
|
+
// 1. CLI args take priority
|
|
418
|
+
const { model, error } = findModel(parsed.provider, parsed.model);
|
|
419
|
+
if (error) {
|
|
420
|
+
console.error(chalk.red(error));
|
|
421
|
+
process.exit(1);
|
|
422
|
+
}
|
|
423
|
+
if (!model) {
|
|
424
|
+
console.error(chalk.red(`Model ${parsed.provider}/${parsed.model} not found`));
|
|
425
|
+
process.exit(1);
|
|
426
|
+
}
|
|
427
|
+
initialModel = model;
|
|
428
|
+
}
|
|
429
|
+
else if (parsed.continue || parsed.resume) {
|
|
430
|
+
// 2. Restore from session (will be handled below after loading session)
|
|
431
|
+
// Leave initialModel as null for now
|
|
432
|
+
}
|
|
433
|
+
if (!initialModel) {
|
|
434
|
+
// 3. Try saved default from settings
|
|
435
|
+
const defaultProvider = settingsManager.getDefaultProvider();
|
|
436
|
+
const defaultModel = settingsManager.getDefaultModel();
|
|
437
|
+
if (defaultProvider && defaultModel) {
|
|
438
|
+
const { model, error } = findModel(defaultProvider, defaultModel);
|
|
439
|
+
if (error) {
|
|
440
|
+
console.error(chalk.red(error));
|
|
441
|
+
process.exit(1);
|
|
402
442
|
}
|
|
443
|
+
initialModel = model;
|
|
403
444
|
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
445
|
+
}
|
|
446
|
+
if (!initialModel) {
|
|
447
|
+
// 4. Try first available model with valid API key
|
|
448
|
+
// Prefer default model for each provider if available
|
|
449
|
+
const { models: availableModels, error } = getAvailableModels();
|
|
450
|
+
if (error) {
|
|
451
|
+
console.error(chalk.red(error));
|
|
452
|
+
process.exit(1);
|
|
453
|
+
}
|
|
454
|
+
if (availableModels.length > 0) {
|
|
455
|
+
// Try to find a default model from known providers
|
|
456
|
+
for (const provider of Object.keys(defaultModelPerProvider)) {
|
|
457
|
+
const defaultModelId = defaultModelPerProvider[provider];
|
|
458
|
+
const match = availableModels.find((m) => m.provider === provider && m.id === defaultModelId);
|
|
459
|
+
if (match) {
|
|
460
|
+
initialModel = match;
|
|
461
|
+
break;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
// If no default found, use first available
|
|
465
|
+
if (!initialModel) {
|
|
466
|
+
initialModel = availableModels[0];
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
// Determine mode early to know if we should print messages and fail early
|
|
471
|
+
const isInteractive = parsed.messages.length === 0 && parsed.mode === undefined;
|
|
472
|
+
const mode = parsed.mode || "text";
|
|
473
|
+
const shouldPrintMessages = isInteractive || mode === "text";
|
|
474
|
+
// Non-interactive mode: fail early if no model available
|
|
475
|
+
if (!isInteractive && !initialModel) {
|
|
476
|
+
console.error(chalk.red("No models available."));
|
|
477
|
+
console.error(chalk.yellow("\nSet an API key environment variable:"));
|
|
478
|
+
console.error(" ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, etc.");
|
|
479
|
+
console.error(chalk.yellow("\nOr create ~/.pi/agent/models.json"));
|
|
413
480
|
process.exit(1);
|
|
414
481
|
}
|
|
415
|
-
//
|
|
416
|
-
|
|
482
|
+
// Non-interactive mode: validate API key exists
|
|
483
|
+
if (!isInteractive && initialModel) {
|
|
484
|
+
const apiKey = parsed.apiKey || getApiKeyForModel(initialModel);
|
|
485
|
+
if (!apiKey) {
|
|
486
|
+
console.error(chalk.red(`No API key found for ${initialModel.provider}`));
|
|
487
|
+
process.exit(1);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
417
490
|
const systemPrompt = buildSystemPrompt(parsed.systemPrompt);
|
|
491
|
+
// Load previous messages if continuing or resuming
|
|
492
|
+
// This may update initialModel if restoring from session
|
|
493
|
+
if (parsed.continue || parsed.resume) {
|
|
494
|
+
const messages = sessionManager.loadMessages();
|
|
495
|
+
if (messages.length > 0 && shouldPrintMessages) {
|
|
496
|
+
console.log(chalk.dim(`Loaded ${messages.length} messages from previous session`));
|
|
497
|
+
}
|
|
498
|
+
// Load and restore model (overrides initialModel if found and has API key)
|
|
499
|
+
const savedModel = sessionManager.loadModel();
|
|
500
|
+
if (savedModel) {
|
|
501
|
+
const { model: restoredModel, error } = findModel(savedModel.provider, savedModel.modelId);
|
|
502
|
+
if (error) {
|
|
503
|
+
console.error(chalk.red(error));
|
|
504
|
+
process.exit(1);
|
|
505
|
+
}
|
|
506
|
+
// Check if restored model exists and has a valid API key
|
|
507
|
+
const hasApiKey = restoredModel ? !!getApiKeyForModel(restoredModel) : false;
|
|
508
|
+
if (restoredModel && hasApiKey) {
|
|
509
|
+
initialModel = restoredModel;
|
|
510
|
+
if (shouldPrintMessages) {
|
|
511
|
+
console.log(chalk.dim(`Restored model: ${savedModel.provider}/${savedModel.modelId}`));
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
else {
|
|
515
|
+
// Model not found or no API key - fall back to default selection
|
|
516
|
+
const reason = !restoredModel ? "model no longer exists" : "no API key available";
|
|
517
|
+
if (shouldPrintMessages) {
|
|
518
|
+
console.error(chalk.yellow(`Warning: Could not restore model ${savedModel.provider}/${savedModel.modelId} (${reason}).`));
|
|
519
|
+
}
|
|
520
|
+
// Ensure we have a valid model - use the same fallback logic
|
|
521
|
+
if (!initialModel) {
|
|
522
|
+
const { models: availableModels, error: availableError } = getAvailableModels();
|
|
523
|
+
if (availableError) {
|
|
524
|
+
console.error(chalk.red(availableError));
|
|
525
|
+
process.exit(1);
|
|
526
|
+
}
|
|
527
|
+
if (availableModels.length > 0) {
|
|
528
|
+
// Try to find a default model from known providers
|
|
529
|
+
for (const provider of Object.keys(defaultModelPerProvider)) {
|
|
530
|
+
const defaultModelId = defaultModelPerProvider[provider];
|
|
531
|
+
const match = availableModels.find((m) => m.provider === provider && m.id === defaultModelId);
|
|
532
|
+
if (match) {
|
|
533
|
+
initialModel = match;
|
|
534
|
+
break;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
// If no default found, use first available
|
|
538
|
+
if (!initialModel) {
|
|
539
|
+
initialModel = availableModels[0];
|
|
540
|
+
}
|
|
541
|
+
if (initialModel && shouldPrintMessages) {
|
|
542
|
+
console.log(chalk.dim(`Falling back to: ${initialModel.provider}/${initialModel.id}`));
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
else {
|
|
546
|
+
// No models available at all
|
|
547
|
+
if (shouldPrintMessages) {
|
|
548
|
+
console.error(chalk.red("\nNo models available."));
|
|
549
|
+
console.error(chalk.yellow("Set an API key environment variable:"));
|
|
550
|
+
console.error(" ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, etc.");
|
|
551
|
+
console.error(chalk.yellow("\nOr create ~/.pi/agent/models.json"));
|
|
552
|
+
}
|
|
553
|
+
process.exit(1);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
else if (shouldPrintMessages) {
|
|
557
|
+
console.log(chalk.dim(`Falling back to: ${initialModel.provider}/${initialModel.id}`));
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
// Create agent (initialModel can be null in interactive mode)
|
|
418
563
|
const agent = new Agent({
|
|
419
564
|
initialState: {
|
|
420
565
|
systemPrompt,
|
|
421
|
-
model,
|
|
566
|
+
model: initialModel, // Can be null
|
|
422
567
|
thinkingLevel: "off",
|
|
423
568
|
tools: codingTools,
|
|
424
569
|
},
|
|
425
570
|
transport: new ProviderTransport({
|
|
426
571
|
// Dynamic API key lookup based on current model's provider
|
|
427
572
|
getApiKey: async () => {
|
|
428
|
-
const
|
|
429
|
-
|
|
573
|
+
const currentModel = agent.state.model;
|
|
574
|
+
if (!currentModel) {
|
|
575
|
+
throw new Error("No model selected");
|
|
576
|
+
}
|
|
577
|
+
// Try CLI override first
|
|
578
|
+
if (parsed.apiKey) {
|
|
579
|
+
return parsed.apiKey;
|
|
580
|
+
}
|
|
581
|
+
// Use model-specific key lookup
|
|
582
|
+
const key = getApiKeyForModel(currentModel);
|
|
430
583
|
if (!key) {
|
|
431
|
-
throw new Error(`No API key found for provider "${
|
|
584
|
+
throw new Error(`No API key found for provider "${currentModel.provider}". Please set the appropriate environment variable or update ~/.pi/agent/models.json`);
|
|
432
585
|
}
|
|
433
586
|
return key;
|
|
434
587
|
},
|
|
435
588
|
}),
|
|
436
589
|
});
|
|
437
|
-
//
|
|
438
|
-
|
|
439
|
-
const mode = parsed.mode || "text";
|
|
440
|
-
const shouldPrintMessages = isInteractive || mode === "text";
|
|
590
|
+
// Track if we had to fall back from saved model (to show in chat later)
|
|
591
|
+
let modelFallbackMessage = null;
|
|
441
592
|
// Load previous messages if continuing or resuming
|
|
442
593
|
if (parsed.continue || parsed.resume) {
|
|
443
594
|
const messages = sessionManager.loadMessages();
|
|
444
595
|
if (messages.length > 0) {
|
|
445
|
-
if (shouldPrintMessages) {
|
|
446
|
-
console.log(chalk.dim(`Loaded ${messages.length} messages from previous session`));
|
|
447
|
-
}
|
|
448
596
|
agent.replaceMessages(messages);
|
|
449
597
|
}
|
|
450
|
-
// Load and restore model
|
|
451
|
-
const savedModel = sessionManager.loadModel();
|
|
452
|
-
if (savedModel) {
|
|
453
|
-
try {
|
|
454
|
-
const restoredModel = getModel(savedModel.provider, savedModel.modelId);
|
|
455
|
-
agent.setModel(restoredModel);
|
|
456
|
-
if (shouldPrintMessages) {
|
|
457
|
-
console.log(chalk.dim(`Restored model: ${savedModel.provider}/${savedModel.modelId}`));
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
catch (error) {
|
|
461
|
-
if (shouldPrintMessages) {
|
|
462
|
-
console.error(chalk.yellow(`Warning: Could not restore model ${savedModel.provider}/${savedModel.modelId}: ${error.message}`));
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
598
|
// Load and restore thinking level
|
|
467
599
|
const thinkingLevel = sessionManager.loadThinkingLevel();
|
|
468
600
|
if (thinkingLevel) {
|
|
@@ -471,6 +603,22 @@ export async function main(args) {
|
|
|
471
603
|
console.log(chalk.dim(`Restored thinking level: ${thinkingLevel}`));
|
|
472
604
|
}
|
|
473
605
|
}
|
|
606
|
+
// Check if we had to fall back from saved model
|
|
607
|
+
const savedModel = sessionManager.loadModel();
|
|
608
|
+
if (savedModel && initialModel) {
|
|
609
|
+
const savedMatches = initialModel.provider === savedModel.provider && initialModel.id === savedModel.modelId;
|
|
610
|
+
if (!savedMatches) {
|
|
611
|
+
const { model: restoredModel, error } = findModel(savedModel.provider, savedModel.modelId);
|
|
612
|
+
if (error) {
|
|
613
|
+
// Config error - already shown above, just use generic message
|
|
614
|
+
modelFallbackMessage = `Could not restore model ${savedModel.provider}/${savedModel.modelId}. Using ${initialModel.provider}/${initialModel.id}.`;
|
|
615
|
+
}
|
|
616
|
+
else {
|
|
617
|
+
const reason = !restoredModel ? "model no longer exists" : "no API key available";
|
|
618
|
+
modelFallbackMessage = `Could not restore model ${savedModel.provider}/${savedModel.modelId} (${reason}). Using ${initialModel.provider}/${initialModel.id}.`;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
474
622
|
}
|
|
475
623
|
// Note: Session will be started lazily after first user+assistant message exchange
|
|
476
624
|
// (unless continuing/resuming, in which case it's already initialized)
|
|
@@ -504,7 +652,6 @@ export async function main(args) {
|
|
|
504
652
|
// Check if we should show changelog (only in interactive mode, only for new sessions)
|
|
505
653
|
let changelogMarkdown = null;
|
|
506
654
|
if (!parsed.continue && !parsed.resume) {
|
|
507
|
-
const settingsManager = new SettingsManager();
|
|
508
655
|
const lastVersion = settingsManager.getLastChangelogVersion();
|
|
509
656
|
// Check if we need to show changelog
|
|
510
657
|
if (!lastVersion) {
|
|
@@ -530,7 +677,7 @@ export async function main(args) {
|
|
|
530
677
|
}
|
|
531
678
|
}
|
|
532
679
|
// No messages and not RPC - use TUI
|
|
533
|
-
await runInteractiveMode(agent, sessionManager, VERSION, changelogMarkdown);
|
|
680
|
+
await runInteractiveMode(agent, sessionManager, settingsManager, VERSION, changelogMarkdown, modelFallbackMessage);
|
|
534
681
|
}
|
|
535
682
|
else {
|
|
536
683
|
// CLI mode with messages
|
package/dist/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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","sourcesContent":["import { Agent, ProviderTransport, type ThinkingLevel } from \"@mariozechner/pi-agent\";\nimport { getModel, type KnownProvider } from \"@mariozechner/pi-ai\";\nimport { ProcessTerminal, TUI } from \"@mariozechner/pi-tui\";\nimport chalk from \"chalk\";\nimport { existsSync, readFileSync } from \"fs\";\nimport { homedir } from \"os\";\nimport { dirname, join, resolve } from \"path\";\nimport { fileURLToPath } from \"url\";\nimport { getChangelogPath, getNewEntries, parseChangelog } from \"./changelog.js\";\nimport { SessionManager } from \"./session-manager.js\";\nimport { SettingsManager } from \"./settings-manager.js\";\nimport { codingTools } from \"./tools/index.js\";\nimport { SessionSelectorComponent } from \"./tui/session-selector.js\";\nimport { TuiRenderer } from \"./tui/tui-renderer.js\";\n\n// Get version from package.json\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst packageJson = JSON.parse(readFileSync(join(__dirname, \"../package.json\"), \"utf-8\"));\nconst VERSION = packageJson.version;\n\nconst envApiKeyMap: Record<KnownProvider, string[]> = {\n\tgoogle: [\"GEMINI_API_KEY\"],\n\topenai: [\"OPENAI_API_KEY\"],\n\tanthropic: [\"ANTHROPIC_OAUTH_TOKEN\", \"ANTHROPIC_API_KEY\"],\n\txai: [\"XAI_API_KEY\"],\n\tgroq: [\"GROQ_API_KEY\"],\n\tcerebras: [\"CEREBRAS_API_KEY\"],\n\topenrouter: [\"OPENROUTER_API_KEY\"],\n\tzai: [\"ZAI_API_KEY\"],\n};\n\ntype Mode = \"text\" | \"json\" | \"rpc\";\n\ninterface Args {\n\tprovider?: string;\n\tmodel?: string;\n\tapiKey?: string;\n\tsystemPrompt?: string;\n\tcontinue?: boolean;\n\tresume?: boolean;\n\thelp?: boolean;\n\tmode?: Mode;\n\tnoSession?: boolean;\n\tsession?: string;\n\tmessages: string[];\n}\n\nfunction parseArgs(args: string[]): Args {\n\tconst result: Args = {\n\t\tmessages: [],\n\t};\n\n\tfor (let i = 0; i < args.length; i++) {\n\t\tconst arg = args[i];\n\n\t\tif (arg === \"--help\" || arg === \"-h\") {\n\t\t\tresult.help = true;\n\t\t} else if (arg === \"--mode\" && i + 1 < args.length) {\n\t\t\tconst mode = args[++i];\n\t\t\tif (mode === \"text\" || mode === \"json\" || mode === \"rpc\") {\n\t\t\t\tresult.mode = mode;\n\t\t\t}\n\t\t} else if (arg === \"--continue\" || arg === \"-c\") {\n\t\t\tresult.continue = true;\n\t\t} else if (arg === \"--resume\" || arg === \"-r\") {\n\t\t\tresult.resume = true;\n\t\t} else if (arg === \"--provider\" && i + 1 < args.length) {\n\t\t\tresult.provider = args[++i];\n\t\t} else if (arg === \"--model\" && i + 1 < args.length) {\n\t\t\tresult.model = args[++i];\n\t\t} else if (arg === \"--api-key\" && i + 1 < args.length) {\n\t\t\tresult.apiKey = args[++i];\n\t\t} else if (arg === \"--system-prompt\" && i + 1 < args.length) {\n\t\t\tresult.systemPrompt = args[++i];\n\t\t} else if (arg === \"--no-session\") {\n\t\t\tresult.noSession = true;\n\t\t} else if (arg === \"--session\" && i + 1 < args.length) {\n\t\t\tresult.session = args[++i];\n\t\t} else if (!arg.startsWith(\"-\")) {\n\t\t\tresult.messages.push(arg);\n\t\t}\n\t}\n\n\treturn result;\n}\n\nfunction printHelp() {\n\tconsole.log(`${chalk.bold(\"coding-agent\")} - AI coding assistant with read, bash, edit, write tools\n\n${chalk.bold(\"Usage:\")}\n coding-agent [options] [messages...]\n\n${chalk.bold(\"Options:\")}\n --provider <name> Provider name (default: google)\n --model <id> Model ID (default: gemini-2.5-flash)\n --api-key <key> API key (defaults to env vars)\n --system-prompt <text> System prompt (default: coding assistant prompt)\n --mode <mode> Output mode: text (default), json, or rpc\n --continue, -c Continue previous session\n --resume, -r Select a session to resume\n --session <path> Use specific session file\n --no-session Don't save session (ephemeral)\n --help, -h Show this help\n\n${chalk.bold(\"Examples:\")}\n # Interactive mode (no messages = interactive TUI)\n coding-agent\n\n # Single message\n coding-agent \"List all .ts files in src/\"\n\n # Multiple messages\n coding-agent \"Read package.json\" \"What dependencies do we have?\"\n\n # Continue previous session\n coding-agent --continue \"What did we discuss?\"\n\n # Use different model\n coding-agent --provider openai --model gpt-4o-mini \"Help me refactor this code\"\n\n${chalk.bold(\"Environment Variables:\")}\n GEMINI_API_KEY - Google Gemini API key\n OPENAI_API_KEY - OpenAI API key\n ANTHROPIC_API_KEY - Anthropic API key\n CODING_AGENT_DIR - Session storage directory (default: ~/.coding-agent)\n\n${chalk.bold(\"Available Tools:\")}\n read - Read file contents\n bash - Execute bash commands\n edit - Edit files with find/replace\n write - Write files (creates/overwrites)\n`);\n}\n\nfunction buildSystemPrompt(customPrompt?: string): string {\n\t// Check if customPrompt is a file path that exists\n\tif (customPrompt && existsSync(customPrompt)) {\n\t\ttry {\n\t\t\tcustomPrompt = readFileSync(customPrompt, \"utf-8\");\n\t\t} catch (error) {\n\t\t\tconsole.error(chalk.yellow(`Warning: Could not read system prompt file ${customPrompt}: ${error}`));\n\t\t\t// Fall through to use as literal string\n\t\t}\n\t}\n\n\tif (customPrompt) {\n\t\t// Use custom prompt as base, then add context/datetime\n\t\tconst now = new Date();\n\t\tconst dateTime = now.toLocaleString(\"en-US\", {\n\t\t\tweekday: \"long\",\n\t\t\tyear: \"numeric\",\n\t\t\tmonth: \"long\",\n\t\t\tday: \"numeric\",\n\t\t\thour: \"2-digit\",\n\t\t\tminute: \"2-digit\",\n\t\t\tsecond: \"2-digit\",\n\t\t\ttimeZoneName: \"short\",\n\t\t});\n\n\t\tlet prompt = customPrompt;\n\n\t\t// Append project context files\n\t\tconst contextFiles = loadProjectContextFiles();\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\t\tprompt += \"The following project context files have been loaded:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t\t}\n\t\t}\n\n\t\t// Add date/time and working directory last\n\t\tprompt += `\\nCurrent date and time: ${dateTime}`;\n\t\tprompt += `\\nCurrent working directory: ${process.cwd()}`;\n\n\t\treturn prompt;\n\t}\n\n\tconst now = new Date();\n\tconst dateTime = now.toLocaleString(\"en-US\", {\n\t\tweekday: \"long\",\n\t\tyear: \"numeric\",\n\t\tmonth: \"long\",\n\t\tday: \"numeric\",\n\t\thour: \"2-digit\",\n\t\tminute: \"2-digit\",\n\t\tsecond: \"2-digit\",\n\t\ttimeZoneName: \"short\",\n\t});\n\n\tlet prompt = `You are an expert coding assistant. You help users with coding tasks by reading files, executing commands, editing code, and writing new files.\n\nAvailable tools:\n- read: Read file contents\n- bash: Execute bash commands (ls, grep, find, etc.)\n- edit: Make surgical edits to files (find exact text and replace)\n- write: Create or overwrite files\n\nGuidelines:\n- Always use bash tool for file operations like ls, grep, find\n- Use read to examine files before editing\n- Use edit for precise changes (old text must match exactly)\n- Use write only for new files or complete rewrites\n- Be concise in your responses\n- Show file paths clearly when working with files`;\n\n\t// Append project context files\n\tconst contextFiles = loadProjectContextFiles();\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\tprompt += \"The following project context files have been loaded:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t}\n\t}\n\n\t// Add date/time and working directory last\n\tprompt += `\\nCurrent date and time: ${dateTime}`;\n\tprompt += `\\nCurrent working directory: ${process.cwd()}`;\n\n\treturn prompt;\n}\n\n/**\n * Look for AGENTS.md or CLAUDE.md in a directory (prefers AGENTS.md)\n */\nfunction loadContextFileFromDir(dir: string): { path: string; content: string } | null {\n\tconst candidates = [\"AGENTS.md\", \"CLAUDE.md\"];\n\tfor (const filename of candidates) {\n\t\tconst filePath = join(dir, filename);\n\t\tif (existsSync(filePath)) {\n\t\t\ttry {\n\t\t\t\treturn {\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\tcontent: readFileSync(filePath, \"utf-8\"),\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(chalk.yellow(`Warning: Could not read ${filePath}: ${error}`));\n\t\t\t}\n\t\t}\n\t}\n\treturn null;\n}\n\n/**\n * Load all project context files in order:\n * 1. Global: ~/.pi/agent/AGENTS.md or CLAUDE.md\n * 2. Parent directories (top-most first) down to cwd\n * Each returns {path, content} for separate messages\n */\nfunction loadProjectContextFiles(): Array<{ path: string; content: string }> {\n\tconst contextFiles: Array<{ path: string; content: string }> = [];\n\n\t// 1. Load global context from ~/.pi/agent/\n\tconst homeDir = homedir();\n\tconst globalContextDir = resolve(process.env.CODING_AGENT_DIR || join(homeDir, \".pi/agent/\"));\n\tconst globalContext = loadContextFileFromDir(globalContextDir);\n\tif (globalContext) {\n\t\tcontextFiles.push(globalContext);\n\t}\n\n\t// 2. Walk up from cwd to root, collecting all context files\n\tconst cwd = process.cwd();\n\tconst ancestorContextFiles: Array<{ path: string; content: string }> = [];\n\n\tlet currentDir = cwd;\n\tconst root = resolve(\"/\");\n\n\twhile (true) {\n\t\tconst contextFile = loadContextFileFromDir(currentDir);\n\t\tif (contextFile) {\n\t\t\t// Add to beginning so we get top-most parent first\n\t\t\tancestorContextFiles.unshift(contextFile);\n\t\t}\n\n\t\t// Stop if we've reached root\n\t\tif (currentDir === root) break;\n\n\t\t// Move up one directory\n\t\tconst parentDir = resolve(currentDir, \"..\");\n\t\tif (parentDir === currentDir) break; // Safety check\n\t\tcurrentDir = parentDir;\n\t}\n\n\t// Add ancestor files in order (top-most → cwd)\n\tcontextFiles.push(...ancestorContextFiles);\n\n\treturn contextFiles;\n}\n\nasync function selectSession(sessionManager: SessionManager): Promise<string | null> {\n\treturn new Promise((resolve) => {\n\t\tconst ui = new TUI(new ProcessTerminal());\n\t\tlet resolved = false;\n\n\t\tconst selector = new SessionSelectorComponent(\n\t\t\tsessionManager,\n\t\t\t(path: string) => {\n\t\t\t\tif (!resolved) {\n\t\t\t\t\tresolved = true;\n\t\t\t\t\tui.stop();\n\t\t\t\t\tresolve(path);\n\t\t\t\t}\n\t\t\t},\n\t\t\t() => {\n\t\t\t\tif (!resolved) {\n\t\t\t\t\tresolved = true;\n\t\t\t\t\tui.stop();\n\t\t\t\t\tresolve(null);\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\n\t\tui.addChild(selector);\n\t\tui.setFocus(selector.getSessionList());\n\t\tui.start();\n\t});\n}\n\nasync function runInteractiveMode(\n\tagent: Agent,\n\tsessionManager: SessionManager,\n\tversion: string,\n\tchangelogMarkdown: string | null = null,\n): Promise<void> {\n\tconst renderer = new TuiRenderer(agent, sessionManager, version, changelogMarkdown);\n\n\t// Initialize TUI\n\tawait renderer.init();\n\n\t// Set interrupt callback\n\trenderer.setInterruptCallback(() => {\n\t\tagent.abort();\n\t});\n\n\t// Render any existing messages (from --continue mode)\n\trenderer.renderInitialMessages(agent.state);\n\n\t// Subscribe to agent events\n\tagent.subscribe(async (event) => {\n\t\t// Pass all events to the renderer\n\t\tawait renderer.handleEvent(event, agent.state);\n\t});\n\n\t// Interactive loop\n\twhile (true) {\n\t\tconst userInput = await renderer.getUserInput();\n\n\t\t// Process the message - agent.prompt will add user message and trigger state updates\n\t\ttry {\n\t\t\tawait agent.prompt(userInput);\n\t\t} catch (error: any) {\n\t\t\t// Display error in the TUI by adding an error message to the chat\n\t\t\trenderer.showError(error.message || \"Unknown error occurred\");\n\t\t}\n\t}\n}\n\nasync function runSingleShotMode(\n\tagent: Agent,\n\t_sessionManager: SessionManager,\n\tmessages: string[],\n\tmode: \"text\" | \"json\",\n): Promise<void> {\n\tif (mode === \"json\") {\n\t\t// Subscribe to all events and output as JSON\n\t\tagent.subscribe((event) => {\n\t\t\t// Output event as JSON (same format as session manager)\n\t\t\tconsole.log(JSON.stringify(event));\n\t\t});\n\t}\n\n\tfor (const message of messages) {\n\t\tawait agent.prompt(message);\n\t}\n\n\t// In text mode, only output the final assistant message\n\tif (mode === \"text\") {\n\t\tconst lastMessage = agent.state.messages[agent.state.messages.length - 1];\n\t\tif (lastMessage.role === \"assistant\") {\n\t\t\tfor (const content of lastMessage.content) {\n\t\t\t\tif (content.type === \"text\") {\n\t\t\t\t\tconsole.log(content.text);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nasync function runRpcMode(agent: Agent, _sessionManager: SessionManager): Promise<void> {\n\t// Subscribe to all events and output as JSON\n\tagent.subscribe((event) => {\n\t\tconsole.log(JSON.stringify(event));\n\t});\n\n\t// Listen for JSON input on stdin\n\tconst readline = await import(\"readline\");\n\tconst rl = readline.createInterface({\n\t\tinput: process.stdin,\n\t\toutput: process.stdout,\n\t\tterminal: false,\n\t});\n\n\trl.on(\"line\", async (line: string) => {\n\t\ttry {\n\t\t\tconst input = JSON.parse(line);\n\n\t\t\t// Handle different RPC commands\n\t\t\tif (input.type === \"prompt\" && input.message) {\n\t\t\t\tawait agent.prompt(input.message);\n\t\t\t} else if (input.type === \"abort\") {\n\t\t\t\tagent.abort();\n\t\t\t}\n\t\t} catch (error: any) {\n\t\t\t// Output error as JSON\n\t\t\tconsole.log(JSON.stringify({ type: \"error\", error: error.message }));\n\t\t}\n\t});\n\n\t// Keep process alive\n\treturn new Promise(() => {});\n}\n\nexport async function main(args: string[]) {\n\tconst parsed = parseArgs(args);\n\n\tif (parsed.help) {\n\t\tprintHelp();\n\t\treturn;\n\t}\n\n\t// Setup session manager\n\tconst sessionManager = new SessionManager(parsed.continue && !parsed.resume, parsed.session);\n\n\t// Disable session saving if --no-session flag is set\n\tif (parsed.noSession) {\n\t\tsessionManager.disable();\n\t}\n\n\t// Handle --resume flag: show session selector\n\tif (parsed.resume) {\n\t\tconst selectedSession = await selectSession(sessionManager);\n\t\tif (!selectedSession) {\n\t\t\tconsole.log(chalk.dim(\"No session selected\"));\n\t\t\treturn;\n\t\t}\n\t\t// Set the selected session as the active session\n\t\tsessionManager.setSessionFile(selectedSession);\n\t}\n\n\t// Determine provider and model\n\tconst provider = (parsed.provider || \"anthropic\") as any;\n\tconst modelId = parsed.model || \"claude-sonnet-4-5\";\n\n\t// Helper function to get API key for a provider\n\tconst getApiKeyForProvider = (providerName: string): string | undefined => {\n\t\t// Check if API key was provided via command line\n\t\tif (parsed.apiKey) {\n\t\t\treturn parsed.apiKey;\n\t\t}\n\n\t\tconst envVars = envApiKeyMap[providerName as KnownProvider];\n\n\t\t// Check each environment variable in priority order\n\t\tfor (const envVar of envVars) {\n\t\t\tconst key = process.env[envVar];\n\t\t\tif (key) {\n\t\t\t\treturn key;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t};\n\n\t// Get initial API key\n\tconst initialApiKey = getApiKeyForProvider(provider);\n\tif (!initialApiKey) {\n\t\tconst envVars = envApiKeyMap[provider as KnownProvider];\n\t\tconst envVarList = envVars.join(\" or \");\n\t\tconsole.error(chalk.red(`Error: No API key found for provider \"${provider}\"`));\n\t\tconsole.error(chalk.dim(`Set ${envVarList} environment variable or use --api-key flag`));\n\t\tprocess.exit(1);\n\t}\n\n\t// Create agent\n\tconst model = getModel(provider, modelId);\n\tconst systemPrompt = buildSystemPrompt(parsed.systemPrompt);\n\n\tconst agent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt,\n\t\t\tmodel,\n\t\t\tthinkingLevel: \"off\",\n\t\t\ttools: codingTools,\n\t\t},\n\t\ttransport: new ProviderTransport({\n\t\t\t// Dynamic API key lookup based on current model's provider\n\t\t\tgetApiKey: async () => {\n\t\t\t\tconst currentProvider = agent.state.model.provider;\n\t\t\t\tconst key = getApiKeyForProvider(currentProvider);\n\t\t\t\tif (!key) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`No API key found for provider \"${currentProvider}\". Please set the appropriate environment variable.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn key;\n\t\t\t},\n\t\t}),\n\t});\n\n\t// Determine mode early to know if we should print messages\n\tconst isInteractive = parsed.messages.length === 0;\n\tconst mode = parsed.mode || \"text\";\n\tconst shouldPrintMessages = isInteractive || mode === \"text\";\n\n\t// Load previous messages if continuing or resuming\n\tif (parsed.continue || parsed.resume) {\n\t\tconst messages = sessionManager.loadMessages();\n\t\tif (messages.length > 0) {\n\t\t\tif (shouldPrintMessages) {\n\t\t\t\tconsole.log(chalk.dim(`Loaded ${messages.length} messages from previous session`));\n\t\t\t}\n\t\t\tagent.replaceMessages(messages);\n\t\t}\n\n\t\t// Load and restore model\n\t\tconst savedModel = sessionManager.loadModel();\n\t\tif (savedModel) {\n\t\t\ttry {\n\t\t\t\tconst restoredModel = getModel(savedModel.provider as any, savedModel.modelId);\n\t\t\t\tagent.setModel(restoredModel);\n\t\t\t\tif (shouldPrintMessages) {\n\t\t\t\t\tconsole.log(chalk.dim(`Restored model: ${savedModel.provider}/${savedModel.modelId}`));\n\t\t\t\t}\n\t\t\t} catch (error: any) {\n\t\t\t\tif (shouldPrintMessages) {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\tchalk.yellow(\n\t\t\t\t\t\t\t`Warning: Could not restore model ${savedModel.provider}/${savedModel.modelId}: ${error.message}`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Load and restore thinking level\n\t\tconst thinkingLevel = sessionManager.loadThinkingLevel() as ThinkingLevel;\n\t\tif (thinkingLevel) {\n\t\t\tagent.setThinkingLevel(thinkingLevel);\n\t\t\tif (shouldPrintMessages) {\n\t\t\t\tconsole.log(chalk.dim(`Restored thinking level: ${thinkingLevel}`));\n\t\t\t}\n\t\t}\n\t}\n\n\t// Note: Session will be started lazily after first user+assistant message exchange\n\t// (unless continuing/resuming, in which case it's already initialized)\n\n\t// Log loaded context files (they're already in the system prompt)\n\tif (shouldPrintMessages && !parsed.continue && !parsed.resume) {\n\t\tconst contextFiles = loadProjectContextFiles();\n\t\tif (contextFiles.length > 0) {\n\t\t\tconsole.log(chalk.dim(\"Loaded project context from:\"));\n\t\t\tfor (const { path: filePath } of contextFiles) {\n\t\t\t\tconsole.log(chalk.dim(` - ${filePath}`));\n\t\t\t}\n\t\t}\n\t}\n\n\t// Subscribe to agent events to save messages\n\tagent.subscribe((event) => {\n\t\t// Save messages on completion\n\t\tif (event.type === \"message_end\") {\n\t\t\tsessionManager.saveMessage(event.message);\n\n\t\t\t// Check if we should initialize session now (after first user+assistant exchange)\n\t\t\tif (sessionManager.shouldInitializeSession(agent.state.messages)) {\n\t\t\t\tsessionManager.startSession(agent.state);\n\t\t\t}\n\t\t}\n\t});\n\n\t// Route to appropriate mode\n\tif (mode === \"rpc\") {\n\t\t// RPC mode - headless operation\n\t\tawait runRpcMode(agent, sessionManager);\n\t} else if (isInteractive) {\n\t\t// Check if we should show changelog (only in interactive mode, only for new sessions)\n\t\tlet changelogMarkdown: string | null = null;\n\t\tif (!parsed.continue && !parsed.resume) {\n\t\t\tconst settingsManager = new SettingsManager();\n\t\t\tconst lastVersion = settingsManager.getLastChangelogVersion();\n\n\t\t\t// Check if we need to show changelog\n\t\t\tif (!lastVersion) {\n\t\t\t\t// First run - show all entries\n\t\t\t\tconst changelogPath = getChangelogPath();\n\t\t\t\tconst entries = parseChangelog(changelogPath);\n\t\t\t\tif (entries.length > 0) {\n\t\t\t\t\tchangelogMarkdown = entries.map((e) => e.content).join(\"\\n\\n\");\n\t\t\t\t\tsettingsManager.setLastChangelogVersion(VERSION);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Parse current and last versions\n\t\t\t\tconst currentParts = VERSION.split(\".\").map(Number);\n\t\t\t\tconst current = { major: currentParts[0] || 0, minor: currentParts[1] || 0, patch: currentParts[2] || 0 };\n\t\t\t\tconst changelogPath = getChangelogPath();\n\t\t\t\tconst entries = parseChangelog(changelogPath);\n\t\t\t\tconst newEntries = getNewEntries(entries, lastVersion);\n\n\t\t\t\tif (newEntries.length > 0) {\n\t\t\t\t\tchangelogMarkdown = newEntries.map((e) => e.content).join(\"\\n\\n\");\n\t\t\t\t\tsettingsManager.setLastChangelogVersion(VERSION);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// No messages and not RPC - use TUI\n\t\tawait runInteractiveMode(agent, sessionManager, VERSION, changelogMarkdown);\n\t} else {\n\t\t// CLI mode with messages\n\t\tawait runSingleShotMode(agent, sessionManager, parsed.messages, mode);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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","sourcesContent":["import { Agent, ProviderTransport, type ThinkingLevel } from \"@mariozechner/pi-agent\";\nimport type { Api, KnownProvider, Model } from \"@mariozechner/pi-ai\";\nimport { ProcessTerminal, TUI } from \"@mariozechner/pi-tui\";\nimport chalk from \"chalk\";\nimport { existsSync, readFileSync } from \"fs\";\nimport { homedir } from \"os\";\nimport { dirname, join, resolve } from \"path\";\nimport { fileURLToPath } from \"url\";\nimport { getChangelogPath, getNewEntries, parseChangelog } from \"./changelog.js\";\nimport { findModel, getApiKeyForModel, getAvailableModels } from \"./model-config.js\";\nimport { SessionManager } from \"./session-manager.js\";\nimport { SettingsManager } from \"./settings-manager.js\";\nimport { codingTools } from \"./tools/index.js\";\nimport { SessionSelectorComponent } from \"./tui/session-selector.js\";\nimport { TuiRenderer } from \"./tui/tui-renderer.js\";\n\n// Get version from package.json\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst packageJson = JSON.parse(readFileSync(join(__dirname, \"../package.json\"), \"utf-8\"));\nconst VERSION = packageJson.version;\n\nconst envApiKeyMap: Record<KnownProvider, string[]> = {\n\tgoogle: [\"GEMINI_API_KEY\"],\n\topenai: [\"OPENAI_API_KEY\"],\n\tanthropic: [\"ANTHROPIC_OAUTH_TOKEN\", \"ANTHROPIC_API_KEY\"],\n\txai: [\"XAI_API_KEY\"],\n\tgroq: [\"GROQ_API_KEY\"],\n\tcerebras: [\"CEREBRAS_API_KEY\"],\n\topenrouter: [\"OPENROUTER_API_KEY\"],\n\tzai: [\"ZAI_API_KEY\"],\n};\n\nconst defaultModelPerProvider: Record<KnownProvider, string> = {\n\tanthropic: \"claude-sonnet-4-5\",\n\topenai: \"gpt-5.1-codex\",\n\tgoogle: \"gemini-2.5-pro\",\n\topenrouter: \"openai/gpt-5.1-codex\",\n\txai: \"grok-4-fast-non-reasoning\",\n\tgroq: \"openai/gpt-oss-120b\",\n\tcerebras: \"zai-glm-4.6\",\n\tzai: \"glm-4.6\",\n};\n\ntype Mode = \"text\" | \"json\" | \"rpc\";\n\ninterface Args {\n\tprovider?: string;\n\tmodel?: string;\n\tapiKey?: string;\n\tsystemPrompt?: string;\n\tcontinue?: boolean;\n\tresume?: boolean;\n\thelp?: boolean;\n\tmode?: Mode;\n\tnoSession?: boolean;\n\tsession?: string;\n\tmessages: string[];\n}\n\nfunction parseArgs(args: string[]): Args {\n\tconst result: Args = {\n\t\tmessages: [],\n\t};\n\n\tfor (let i = 0; i < args.length; i++) {\n\t\tconst arg = args[i];\n\n\t\tif (arg === \"--help\" || arg === \"-h\") {\n\t\t\tresult.help = true;\n\t\t} else if (arg === \"--mode\" && i + 1 < args.length) {\n\t\t\tconst mode = args[++i];\n\t\t\tif (mode === \"text\" || mode === \"json\" || mode === \"rpc\") {\n\t\t\t\tresult.mode = mode;\n\t\t\t}\n\t\t} else if (arg === \"--continue\" || arg === \"-c\") {\n\t\t\tresult.continue = true;\n\t\t} else if (arg === \"--resume\" || arg === \"-r\") {\n\t\t\tresult.resume = true;\n\t\t} else if (arg === \"--provider\" && i + 1 < args.length) {\n\t\t\tresult.provider = args[++i];\n\t\t} else if (arg === \"--model\" && i + 1 < args.length) {\n\t\t\tresult.model = args[++i];\n\t\t} else if (arg === \"--api-key\" && i + 1 < args.length) {\n\t\t\tresult.apiKey = args[++i];\n\t\t} else if (arg === \"--system-prompt\" && i + 1 < args.length) {\n\t\t\tresult.systemPrompt = args[++i];\n\t\t} else if (arg === \"--no-session\") {\n\t\t\tresult.noSession = true;\n\t\t} else if (arg === \"--session\" && i + 1 < args.length) {\n\t\t\tresult.session = args[++i];\n\t\t} else if (!arg.startsWith(\"-\")) {\n\t\t\tresult.messages.push(arg);\n\t\t}\n\t}\n\n\treturn result;\n}\n\nfunction printHelp() {\n\tconsole.log(`${chalk.bold(\"coding-agent\")} - AI coding assistant with read, bash, edit, write tools\n\n${chalk.bold(\"Usage:\")}\n coding-agent [options] [messages...]\n\n${chalk.bold(\"Options:\")}\n --provider <name> Provider name (default: google)\n --model <id> Model ID (default: gemini-2.5-flash)\n --api-key <key> API key (defaults to env vars)\n --system-prompt <text> System prompt (default: coding assistant prompt)\n --mode <mode> Output mode: text (default), json, or rpc\n --continue, -c Continue previous session\n --resume, -r Select a session to resume\n --session <path> Use specific session file\n --no-session Don't save session (ephemeral)\n --help, -h Show this help\n\n${chalk.bold(\"Examples:\")}\n # Interactive mode (no messages = interactive TUI)\n coding-agent\n\n # Single message\n coding-agent \"List all .ts files in src/\"\n\n # Multiple messages\n coding-agent \"Read package.json\" \"What dependencies do we have?\"\n\n # Continue previous session\n coding-agent --continue \"What did we discuss?\"\n\n # Use different model\n coding-agent --provider openai --model gpt-4o-mini \"Help me refactor this code\"\n\n${chalk.bold(\"Environment Variables:\")}\n GEMINI_API_KEY - Google Gemini API key\n OPENAI_API_KEY - OpenAI API key\n ANTHROPIC_API_KEY - Anthropic API key\n CODING_AGENT_DIR - Session storage directory (default: ~/.coding-agent)\n\n${chalk.bold(\"Available Tools:\")}\n read - Read file contents\n bash - Execute bash commands\n edit - Edit files with find/replace\n write - Write files (creates/overwrites)\n`);\n}\n\nfunction buildSystemPrompt(customPrompt?: string): string {\n\t// Check if customPrompt is a file path that exists\n\tif (customPrompt && existsSync(customPrompt)) {\n\t\ttry {\n\t\t\tcustomPrompt = readFileSync(customPrompt, \"utf-8\");\n\t\t} catch (error) {\n\t\t\tconsole.error(chalk.yellow(`Warning: Could not read system prompt file ${customPrompt}: ${error}`));\n\t\t\t// Fall through to use as literal string\n\t\t}\n\t}\n\n\tif (customPrompt) {\n\t\t// Use custom prompt as base, then add context/datetime\n\t\tconst now = new Date();\n\t\tconst dateTime = now.toLocaleString(\"en-US\", {\n\t\t\tweekday: \"long\",\n\t\t\tyear: \"numeric\",\n\t\t\tmonth: \"long\",\n\t\t\tday: \"numeric\",\n\t\t\thour: \"2-digit\",\n\t\t\tminute: \"2-digit\",\n\t\t\tsecond: \"2-digit\",\n\t\t\ttimeZoneName: \"short\",\n\t\t});\n\n\t\tlet prompt = customPrompt;\n\n\t\t// Append project context files\n\t\tconst contextFiles = loadProjectContextFiles();\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\t\tprompt += \"The following project context files have been loaded:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t\t}\n\t\t}\n\n\t\t// Add date/time and working directory last\n\t\tprompt += `\\nCurrent date and time: ${dateTime}`;\n\t\tprompt += `\\nCurrent working directory: ${process.cwd()}`;\n\n\t\treturn prompt;\n\t}\n\n\tconst now = new Date();\n\tconst dateTime = now.toLocaleString(\"en-US\", {\n\t\tweekday: \"long\",\n\t\tyear: \"numeric\",\n\t\tmonth: \"long\",\n\t\tday: \"numeric\",\n\t\thour: \"2-digit\",\n\t\tminute: \"2-digit\",\n\t\tsecond: \"2-digit\",\n\t\ttimeZoneName: \"short\",\n\t});\n\n\t// Get absolute path to README.md\n\tconst readmePath = resolve(join(__dirname, \"../README.md\"));\n\n\tlet prompt = `You are actually not Claude, you are Pi. You are an expert coding assistant. You help users with coding tasks by reading files, executing commands, editing code, and writing new files.\n\nAvailable tools:\n- read: Read file contents\n- bash: Execute bash commands (ls, grep, find, etc.)\n- edit: Make surgical edits to files (find exact text and replace)\n- write: Create or overwrite files\n\nGuidelines:\n- Always use bash tool for file operations like ls, grep, find\n- Use read to examine files before editing\n- Use edit for precise changes (old text must match exactly)\n- Use write only for new files or complete rewrites\n- Be concise in your responses\n- Show file paths clearly when working with files\n\nDocumentation:\n- Your own documentation (including custom model setup) is at: ${readmePath}\n- Read it when users ask about features, configuration, or setup, and especially if the user asks you to add a custom model or provider.`;\n\n\t// Append project context files\n\tconst contextFiles = loadProjectContextFiles();\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\tprompt += \"The following project context files have been loaded:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t}\n\t}\n\n\t// Add date/time and working directory last\n\tprompt += `\\nCurrent date and time: ${dateTime}`;\n\tprompt += `\\nCurrent working directory: ${process.cwd()}`;\n\n\treturn prompt;\n}\n\n/**\n * Look for AGENTS.md or CLAUDE.md in a directory (prefers AGENTS.md)\n */\nfunction loadContextFileFromDir(dir: string): { path: string; content: string } | null {\n\tconst candidates = [\"AGENTS.md\", \"CLAUDE.md\"];\n\tfor (const filename of candidates) {\n\t\tconst filePath = join(dir, filename);\n\t\tif (existsSync(filePath)) {\n\t\t\ttry {\n\t\t\t\treturn {\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\tcontent: readFileSync(filePath, \"utf-8\"),\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(chalk.yellow(`Warning: Could not read ${filePath}: ${error}`));\n\t\t\t}\n\t\t}\n\t}\n\treturn null;\n}\n\n/**\n * Load all project context files in order:\n * 1. Global: ~/.pi/agent/AGENTS.md or CLAUDE.md\n * 2. Parent directories (top-most first) down to cwd\n * Each returns {path, content} for separate messages\n */\nfunction loadProjectContextFiles(): Array<{ path: string; content: string }> {\n\tconst contextFiles: Array<{ path: string; content: string }> = [];\n\n\t// 1. Load global context from ~/.pi/agent/\n\tconst homeDir = homedir();\n\tconst globalContextDir = resolve(process.env.CODING_AGENT_DIR || join(homeDir, \".pi/agent/\"));\n\tconst globalContext = loadContextFileFromDir(globalContextDir);\n\tif (globalContext) {\n\t\tcontextFiles.push(globalContext);\n\t}\n\n\t// 2. Walk up from cwd to root, collecting all context files\n\tconst cwd = process.cwd();\n\tconst ancestorContextFiles: Array<{ path: string; content: string }> = [];\n\n\tlet currentDir = cwd;\n\tconst root = resolve(\"/\");\n\n\twhile (true) {\n\t\tconst contextFile = loadContextFileFromDir(currentDir);\n\t\tif (contextFile) {\n\t\t\t// Add to beginning so we get top-most parent first\n\t\t\tancestorContextFiles.unshift(contextFile);\n\t\t}\n\n\t\t// Stop if we've reached root\n\t\tif (currentDir === root) break;\n\n\t\t// Move up one directory\n\t\tconst parentDir = resolve(currentDir, \"..\");\n\t\tif (parentDir === currentDir) break; // Safety check\n\t\tcurrentDir = parentDir;\n\t}\n\n\t// Add ancestor files in order (top-most → cwd)\n\tcontextFiles.push(...ancestorContextFiles);\n\n\treturn contextFiles;\n}\n\nasync function selectSession(sessionManager: SessionManager): Promise<string | null> {\n\treturn new Promise((resolve) => {\n\t\tconst ui = new TUI(new ProcessTerminal());\n\t\tlet resolved = false;\n\n\t\tconst selector = new SessionSelectorComponent(\n\t\t\tsessionManager,\n\t\t\t(path: string) => {\n\t\t\t\tif (!resolved) {\n\t\t\t\t\tresolved = true;\n\t\t\t\t\tui.stop();\n\t\t\t\t\tresolve(path);\n\t\t\t\t}\n\t\t\t},\n\t\t\t() => {\n\t\t\t\tif (!resolved) {\n\t\t\t\t\tresolved = true;\n\t\t\t\t\tui.stop();\n\t\t\t\t\tresolve(null);\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\n\t\tui.addChild(selector);\n\t\tui.setFocus(selector.getSessionList());\n\t\tui.start();\n\t});\n}\n\nasync function runInteractiveMode(\n\tagent: Agent,\n\tsessionManager: SessionManager,\n\tsettingsManager: SettingsManager,\n\tversion: string,\n\tchangelogMarkdown: string | null = null,\n\tmodelFallbackMessage: string | null = null,\n): Promise<void> {\n\tconst renderer = new TuiRenderer(agent, sessionManager, settingsManager, version, changelogMarkdown);\n\n\t// Initialize TUI\n\tawait renderer.init();\n\n\t// Set interrupt callback\n\trenderer.setInterruptCallback(() => {\n\t\tagent.abort();\n\t});\n\n\t// Render any existing messages (from --continue mode)\n\trenderer.renderInitialMessages(agent.state);\n\n\t// Show model fallback warning at the end of the chat if applicable\n\tif (modelFallbackMessage) {\n\t\trenderer.showWarning(modelFallbackMessage);\n\t}\n\n\t// Subscribe to agent events\n\tagent.subscribe(async (event) => {\n\t\t// Pass all events to the renderer\n\t\tawait renderer.handleEvent(event, agent.state);\n\t});\n\n\t// Interactive loop\n\twhile (true) {\n\t\tconst userInput = await renderer.getUserInput();\n\n\t\t// Process the message - agent.prompt will add user message and trigger state updates\n\t\ttry {\n\t\t\tawait agent.prompt(userInput);\n\t\t} catch (error: any) {\n\t\t\t// Display error in the TUI by adding an error message to the chat\n\t\t\trenderer.showError(error.message || \"Unknown error occurred\");\n\t\t}\n\t}\n}\n\nasync function runSingleShotMode(\n\tagent: Agent,\n\t_sessionManager: SessionManager,\n\tmessages: string[],\n\tmode: \"text\" | \"json\",\n): Promise<void> {\n\tif (mode === \"json\") {\n\t\t// Subscribe to all events and output as JSON\n\t\tagent.subscribe((event) => {\n\t\t\t// Output event as JSON (same format as session manager)\n\t\t\tconsole.log(JSON.stringify(event));\n\t\t});\n\t}\n\n\tfor (const message of messages) {\n\t\tawait agent.prompt(message);\n\t}\n\n\t// In text mode, only output the final assistant message\n\tif (mode === \"text\") {\n\t\tconst lastMessage = agent.state.messages[agent.state.messages.length - 1];\n\t\tif (lastMessage.role === \"assistant\") {\n\t\t\tfor (const content of lastMessage.content) {\n\t\t\t\tif (content.type === \"text\") {\n\t\t\t\t\tconsole.log(content.text);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nasync function runRpcMode(agent: Agent, _sessionManager: SessionManager): Promise<void> {\n\t// Subscribe to all events and output as JSON\n\tagent.subscribe((event) => {\n\t\tconsole.log(JSON.stringify(event));\n\t});\n\n\t// Listen for JSON input on stdin\n\tconst readline = await import(\"readline\");\n\tconst rl = readline.createInterface({\n\t\tinput: process.stdin,\n\t\toutput: process.stdout,\n\t\tterminal: false,\n\t});\n\n\trl.on(\"line\", async (line: string) => {\n\t\ttry {\n\t\t\tconst input = JSON.parse(line);\n\n\t\t\t// Handle different RPC commands\n\t\t\tif (input.type === \"prompt\" && input.message) {\n\t\t\t\tawait agent.prompt(input.message);\n\t\t\t} else if (input.type === \"abort\") {\n\t\t\t\tagent.abort();\n\t\t\t}\n\t\t} catch (error: any) {\n\t\t\t// Output error as JSON\n\t\t\tconsole.log(JSON.stringify({ type: \"error\", error: error.message }));\n\t\t}\n\t});\n\n\t// Keep process alive\n\treturn new Promise(() => {});\n}\n\nexport async function main(args: string[]) {\n\tconst parsed = parseArgs(args);\n\n\tif (parsed.help) {\n\t\tprintHelp();\n\t\treturn;\n\t}\n\n\t// Setup session manager\n\tconst sessionManager = new SessionManager(parsed.continue && !parsed.resume, parsed.session);\n\n\t// Disable session saving if --no-session flag is set\n\tif (parsed.noSession) {\n\t\tsessionManager.disable();\n\t}\n\n\t// Handle --resume flag: show session selector\n\tif (parsed.resume) {\n\t\tconst selectedSession = await selectSession(sessionManager);\n\t\tif (!selectedSession) {\n\t\t\tconsole.log(chalk.dim(\"No session selected\"));\n\t\t\treturn;\n\t\t}\n\t\t// Set the selected session as the active session\n\t\tsessionManager.setSessionFile(selectedSession);\n\t}\n\n\t// Settings manager\n\tconst settingsManager = new SettingsManager();\n\n\t// Determine initial model using priority system:\n\t// 1. CLI args (--provider and --model)\n\t// 2. Restored from session (if --continue or --resume)\n\t// 3. Saved default from settings.json\n\t// 4. First available model with valid API key\n\t// 5. null (allowed in interactive mode)\n\tlet initialModel: Model<Api> | null = null;\n\n\tif (parsed.provider && parsed.model) {\n\t\t// 1. CLI args take priority\n\t\tconst { model, error } = findModel(parsed.provider, parsed.model);\n\t\tif (error) {\n\t\t\tconsole.error(chalk.red(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tif (!model) {\n\t\t\tconsole.error(chalk.red(`Model ${parsed.provider}/${parsed.model} not found`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tinitialModel = model;\n\t} else if (parsed.continue || parsed.resume) {\n\t\t// 2. Restore from session (will be handled below after loading session)\n\t\t// Leave initialModel as null for now\n\t}\n\n\tif (!initialModel) {\n\t\t// 3. Try saved default from settings\n\t\tconst defaultProvider = settingsManager.getDefaultProvider();\n\t\tconst defaultModel = settingsManager.getDefaultModel();\n\t\tif (defaultProvider && defaultModel) {\n\t\t\tconst { model, error } = findModel(defaultProvider, defaultModel);\n\t\t\tif (error) {\n\t\t\t\tconsole.error(chalk.red(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t\tinitialModel = model;\n\t\t}\n\t}\n\n\tif (!initialModel) {\n\t\t// 4. Try first available model with valid API key\n\t\t// Prefer default model for each provider if available\n\t\tconst { models: availableModels, error } = getAvailableModels();\n\n\t\tif (error) {\n\t\t\tconsole.error(chalk.red(error));\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\tif (availableModels.length > 0) {\n\t\t\t// Try to find a default model from known providers\n\t\t\tfor (const provider of Object.keys(defaultModelPerProvider) as KnownProvider[]) {\n\t\t\t\tconst defaultModelId = defaultModelPerProvider[provider];\n\t\t\t\tconst match = availableModels.find((m) => m.provider === provider && m.id === defaultModelId);\n\t\t\t\tif (match) {\n\t\t\t\t\tinitialModel = match;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If no default found, use first available\n\t\t\tif (!initialModel) {\n\t\t\t\tinitialModel = availableModels[0];\n\t\t\t}\n\t\t}\n\t}\n\n\t// Determine mode early to know if we should print messages and fail early\n\tconst isInteractive = parsed.messages.length === 0 && parsed.mode === undefined;\n\tconst mode = parsed.mode || \"text\";\n\tconst shouldPrintMessages = isInteractive || mode === \"text\";\n\n\t// Non-interactive mode: fail early if no model available\n\tif (!isInteractive && !initialModel) {\n\t\tconsole.error(chalk.red(\"No models available.\"));\n\t\tconsole.error(chalk.yellow(\"\\nSet an API key environment variable:\"));\n\t\tconsole.error(\" ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, etc.\");\n\t\tconsole.error(chalk.yellow(\"\\nOr create ~/.pi/agent/models.json\"));\n\t\tprocess.exit(1);\n\t}\n\n\t// Non-interactive mode: validate API key exists\n\tif (!isInteractive && initialModel) {\n\t\tconst apiKey = parsed.apiKey || getApiKeyForModel(initialModel);\n\t\tif (!apiKey) {\n\t\t\tconsole.error(chalk.red(`No API key found for ${initialModel.provider}`));\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\tconst systemPrompt = buildSystemPrompt(parsed.systemPrompt);\n\n\t// Load previous messages if continuing or resuming\n\t// This may update initialModel if restoring from session\n\tif (parsed.continue || parsed.resume) {\n\t\tconst messages = sessionManager.loadMessages();\n\t\tif (messages.length > 0 && shouldPrintMessages) {\n\t\t\tconsole.log(chalk.dim(`Loaded ${messages.length} messages from previous session`));\n\t\t}\n\n\t\t// Load and restore model (overrides initialModel if found and has API key)\n\t\tconst savedModel = sessionManager.loadModel();\n\t\tif (savedModel) {\n\t\t\tconst { model: restoredModel, error } = findModel(savedModel.provider, savedModel.modelId);\n\n\t\t\tif (error) {\n\t\t\t\tconsole.error(chalk.red(error));\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\n\t\t\t// Check if restored model exists and has a valid API key\n\t\t\tconst hasApiKey = restoredModel ? !!getApiKeyForModel(restoredModel) : false;\n\n\t\t\tif (restoredModel && hasApiKey) {\n\t\t\t\tinitialModel = restoredModel;\n\t\t\t\tif (shouldPrintMessages) {\n\t\t\t\t\tconsole.log(chalk.dim(`Restored model: ${savedModel.provider}/${savedModel.modelId}`));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Model not found or no API key - fall back to default selection\n\t\t\t\tconst reason = !restoredModel ? \"model no longer exists\" : \"no API key available\";\n\n\t\t\t\tif (shouldPrintMessages) {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\tchalk.yellow(\n\t\t\t\t\t\t\t`Warning: Could not restore model ${savedModel.provider}/${savedModel.modelId} (${reason}).`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Ensure we have a valid model - use the same fallback logic\n\t\t\t\tif (!initialModel) {\n\t\t\t\t\tconst { models: availableModels, error: availableError } = getAvailableModels();\n\t\t\t\t\tif (availableError) {\n\t\t\t\t\t\tconsole.error(chalk.red(availableError));\n\t\t\t\t\t\tprocess.exit(1);\n\t\t\t\t\t}\n\t\t\t\t\tif (availableModels.length > 0) {\n\t\t\t\t\t\t// Try to find a default model from known providers\n\t\t\t\t\t\tfor (const provider of Object.keys(defaultModelPerProvider) as KnownProvider[]) {\n\t\t\t\t\t\t\tconst defaultModelId = defaultModelPerProvider[provider];\n\t\t\t\t\t\t\tconst match = availableModels.find((m) => m.provider === provider && m.id === defaultModelId);\n\t\t\t\t\t\t\tif (match) {\n\t\t\t\t\t\t\t\tinitialModel = match;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// If no default found, use first available\n\t\t\t\t\t\tif (!initialModel) {\n\t\t\t\t\t\t\tinitialModel = availableModels[0];\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (initialModel && shouldPrintMessages) {\n\t\t\t\t\t\t\tconsole.log(chalk.dim(`Falling back to: ${initialModel.provider}/${initialModel.id}`));\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// No models available at all\n\t\t\t\t\t\tif (shouldPrintMessages) {\n\t\t\t\t\t\t\tconsole.error(chalk.red(\"\\nNo models available.\"));\n\t\t\t\t\t\t\tconsole.error(chalk.yellow(\"Set an API key environment variable:\"));\n\t\t\t\t\t\t\tconsole.error(\" ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, etc.\");\n\t\t\t\t\t\t\tconsole.error(chalk.yellow(\"\\nOr create ~/.pi/agent/models.json\"));\n\t\t\t\t\t\t}\n\t\t\t\t\t\tprocess.exit(1);\n\t\t\t\t\t}\n\t\t\t\t} else if (shouldPrintMessages) {\n\t\t\t\t\tconsole.log(chalk.dim(`Falling back to: ${initialModel.provider}/${initialModel.id}`));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Create agent (initialModel can be null in interactive mode)\n\tconst agent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt,\n\t\t\tmodel: initialModel as any, // Can be null\n\t\t\tthinkingLevel: \"off\",\n\t\t\ttools: codingTools,\n\t\t},\n\t\ttransport: new ProviderTransport({\n\t\t\t// Dynamic API key lookup based on current model's provider\n\t\t\tgetApiKey: async () => {\n\t\t\t\tconst currentModel = agent.state.model;\n\t\t\t\tif (!currentModel) {\n\t\t\t\t\tthrow new Error(\"No model selected\");\n\t\t\t\t}\n\n\t\t\t\t// Try CLI override first\n\t\t\t\tif (parsed.apiKey) {\n\t\t\t\t\treturn parsed.apiKey;\n\t\t\t\t}\n\n\t\t\t\t// Use model-specific key lookup\n\t\t\t\tconst key = getApiKeyForModel(currentModel);\n\t\t\t\tif (!key) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`No API key found for provider \"${currentModel.provider}\". Please set the appropriate environment variable or update ~/.pi/agent/models.json`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn key;\n\t\t\t},\n\t\t}),\n\t});\n\n\t// Track if we had to fall back from saved model (to show in chat later)\n\tlet modelFallbackMessage: string | null = null;\n\n\t// Load previous messages if continuing or resuming\n\tif (parsed.continue || parsed.resume) {\n\t\tconst messages = sessionManager.loadMessages();\n\t\tif (messages.length > 0) {\n\t\t\tagent.replaceMessages(messages);\n\t\t}\n\n\t\t// Load and restore thinking level\n\t\tconst thinkingLevel = sessionManager.loadThinkingLevel() as ThinkingLevel;\n\t\tif (thinkingLevel) {\n\t\t\tagent.setThinkingLevel(thinkingLevel);\n\t\t\tif (shouldPrintMessages) {\n\t\t\t\tconsole.log(chalk.dim(`Restored thinking level: ${thinkingLevel}`));\n\t\t\t}\n\t\t}\n\n\t\t// Check if we had to fall back from saved model\n\t\tconst savedModel = sessionManager.loadModel();\n\t\tif (savedModel && initialModel) {\n\t\t\tconst savedMatches = initialModel.provider === savedModel.provider && initialModel.id === savedModel.modelId;\n\t\t\tif (!savedMatches) {\n\t\t\t\tconst { model: restoredModel, error } = findModel(savedModel.provider, savedModel.modelId);\n\t\t\t\tif (error) {\n\t\t\t\t\t// Config error - already shown above, just use generic message\n\t\t\t\t\tmodelFallbackMessage = `Could not restore model ${savedModel.provider}/${savedModel.modelId}. Using ${initialModel.provider}/${initialModel.id}.`;\n\t\t\t\t} else {\n\t\t\t\t\tconst reason = !restoredModel ? \"model no longer exists\" : \"no API key available\";\n\t\t\t\t\tmodelFallbackMessage = `Could not restore model ${savedModel.provider}/${savedModel.modelId} (${reason}). Using ${initialModel.provider}/${initialModel.id}.`;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Note: Session will be started lazily after first user+assistant message exchange\n\t// (unless continuing/resuming, in which case it's already initialized)\n\n\t// Log loaded context files (they're already in the system prompt)\n\tif (shouldPrintMessages && !parsed.continue && !parsed.resume) {\n\t\tconst contextFiles = loadProjectContextFiles();\n\t\tif (contextFiles.length > 0) {\n\t\t\tconsole.log(chalk.dim(\"Loaded project context from:\"));\n\t\t\tfor (const { path: filePath } of contextFiles) {\n\t\t\t\tconsole.log(chalk.dim(` - ${filePath}`));\n\t\t\t}\n\t\t}\n\t}\n\n\t// Subscribe to agent events to save messages\n\tagent.subscribe((event) => {\n\t\t// Save messages on completion\n\t\tif (event.type === \"message_end\") {\n\t\t\tsessionManager.saveMessage(event.message);\n\n\t\t\t// Check if we should initialize session now (after first user+assistant exchange)\n\t\t\tif (sessionManager.shouldInitializeSession(agent.state.messages)) {\n\t\t\t\tsessionManager.startSession(agent.state);\n\t\t\t}\n\t\t}\n\t});\n\n\t// Route to appropriate mode\n\tif (mode === \"rpc\") {\n\t\t// RPC mode - headless operation\n\t\tawait runRpcMode(agent, sessionManager);\n\t} else if (isInteractive) {\n\t\t// Check if we should show changelog (only in interactive mode, only for new sessions)\n\t\tlet changelogMarkdown: string | null = null;\n\t\tif (!parsed.continue && !parsed.resume) {\n\t\t\tconst lastVersion = settingsManager.getLastChangelogVersion();\n\n\t\t\t// Check if we need to show changelog\n\t\t\tif (!lastVersion) {\n\t\t\t\t// First run - show all entries\n\t\t\t\tconst changelogPath = getChangelogPath();\n\t\t\t\tconst entries = parseChangelog(changelogPath);\n\t\t\t\tif (entries.length > 0) {\n\t\t\t\t\tchangelogMarkdown = entries.map((e) => e.content).join(\"\\n\\n\");\n\t\t\t\t\tsettingsManager.setLastChangelogVersion(VERSION);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Parse current and last versions\n\t\t\t\tconst currentParts = VERSION.split(\".\").map(Number);\n\t\t\t\tconst current = { major: currentParts[0] || 0, minor: currentParts[1] || 0, patch: currentParts[2] || 0 };\n\t\t\t\tconst changelogPath = getChangelogPath();\n\t\t\t\tconst entries = parseChangelog(changelogPath);\n\t\t\t\tconst newEntries = getNewEntries(entries, lastVersion);\n\n\t\t\t\tif (newEntries.length > 0) {\n\t\t\t\t\tchangelogMarkdown = newEntries.map((e) => e.content).join(\"\\n\\n\");\n\t\t\t\t\tsettingsManager.setLastChangelogVersion(VERSION);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// No messages and not RPC - use TUI\n\t\tawait runInteractiveMode(\n\t\t\tagent,\n\t\t\tsessionManager,\n\t\t\tsettingsManager,\n\t\t\tVERSION,\n\t\t\tchangelogMarkdown,\n\t\t\tmodelFallbackMessage,\n\t\t);\n\t} else {\n\t\t// CLI mode with messages\n\t\tawait runSingleShotMode(agent, sessionManager, parsed.messages, mode);\n\t}\n}\n"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type Api, type Model } from "@mariozechner/pi-ai";
|
|
2
|
+
/**
|
|
3
|
+
* Resolve an API key config value to an actual key.
|
|
4
|
+
* First checks if it's an environment variable, then treats as literal.
|
|
5
|
+
*/
|
|
6
|
+
export declare function resolveApiKey(keyConfig: string): string | undefined;
|
|
7
|
+
/**
|
|
8
|
+
* Get all models (built-in + custom), freshly loaded
|
|
9
|
+
* Returns { models, error } - either models array or error message
|
|
10
|
+
*/
|
|
11
|
+
export declare function loadAndMergeModels(): {
|
|
12
|
+
models: Model<Api>[];
|
|
13
|
+
error: string | null;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Get API key for a model (checks custom providers first, then built-in)
|
|
17
|
+
*/
|
|
18
|
+
export declare function getApiKeyForModel(model: Model<Api>): string | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Get only models that have valid API keys available
|
|
21
|
+
* Returns { models, error } - either models array or error message
|
|
22
|
+
*/
|
|
23
|
+
export declare function getAvailableModels(): {
|
|
24
|
+
models: Model<Api>[];
|
|
25
|
+
error: string | null;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Find a specific model by provider and ID
|
|
29
|
+
* Returns { model, error } - either model or error message
|
|
30
|
+
*/
|
|
31
|
+
export declare function findModel(provider: string, modelId: string): {
|
|
32
|
+
model: Model<Api> | null;
|
|
33
|
+
error: string | null;
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=model-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-config.d.ts","sourceRoot":"","sources":["../src/model-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAA0D,KAAK,KAAK,EAAE,MAAM,qBAAqB,CAAC;AA2DnH;;;GAGG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAOnE;AA2HD;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI;IAAE,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAmBnF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,MAAM,GAAG,SAAS,CASvE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI;IAAE,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAanF;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAS/G","sourcesContent":["import { type Api, getApiKey, getModels, getProviders, type KnownProvider, type Model } from \"@mariozechner/pi-ai\";\nimport { type Static, Type } from \"@sinclair/typebox\";\nimport AjvModule from \"ajv\";\nimport { existsSync, readFileSync } from \"fs\";\nimport { homedir } from \"os\";\nimport { join } from \"path\";\n\n// Handle both default and named exports\nconst Ajv = (AjvModule as any).default || AjvModule;\n\n// Schema for custom model definition\nconst ModelDefinitionSchema = Type.Object({\n\tid: Type.String({ minLength: 1 }),\n\tname: Type.String({ minLength: 1 }),\n\tapi: Type.Optional(\n\t\tType.Union([\n\t\t\tType.Literal(\"openai-completions\"),\n\t\t\tType.Literal(\"openai-responses\"),\n\t\t\tType.Literal(\"anthropic-messages\"),\n\t\t\tType.Literal(\"google-generative-ai\"),\n\t\t]),\n\t),\n\treasoning: Type.Boolean(),\n\tinput: Type.Array(Type.Union([Type.Literal(\"text\"), Type.Literal(\"image\")])),\n\tcost: Type.Object({\n\t\tinput: Type.Number(),\n\t\toutput: Type.Number(),\n\t\tcacheRead: Type.Number(),\n\t\tcacheWrite: Type.Number(),\n\t}),\n\tcontextWindow: Type.Number(),\n\tmaxTokens: Type.Number(),\n});\n\nconst ProviderConfigSchema = Type.Object({\n\tbaseUrl: Type.String({ minLength: 1 }),\n\tapiKey: Type.String({ minLength: 1 }),\n\tapi: Type.Optional(\n\t\tType.Union([\n\t\t\tType.Literal(\"openai-completions\"),\n\t\t\tType.Literal(\"openai-responses\"),\n\t\t\tType.Literal(\"anthropic-messages\"),\n\t\t\tType.Literal(\"google-generative-ai\"),\n\t\t]),\n\t),\n\tmodels: Type.Array(ModelDefinitionSchema),\n});\n\nconst ModelsConfigSchema = Type.Object({\n\tproviders: Type.Record(Type.String(), ProviderConfigSchema),\n});\n\ntype ModelsConfig = Static<typeof ModelsConfigSchema>;\ntype ProviderConfig = Static<typeof ProviderConfigSchema>;\ntype ModelDefinition = Static<typeof ModelDefinitionSchema>;\n\n// Custom provider API key mappings (provider name -> apiKey config)\nconst customProviderApiKeys: Map<string, string> = new Map();\n\n/**\n * Resolve an API key config value to an actual key.\n * First checks if it's an environment variable, then treats as literal.\n */\nexport function resolveApiKey(keyConfig: string): string | undefined {\n\t// First check if it's an env var name\n\tconst envValue = process.env[keyConfig];\n\tif (envValue) return envValue;\n\n\t// Otherwise treat as literal API key\n\treturn keyConfig;\n}\n\n/**\n * Load custom models from ~/.pi/agent/models.json\n * Returns { models, error } - either models array or error message\n */\nfunction loadCustomModels(): { models: Model<Api>[]; error: string | null } {\n\tconst configPath = join(homedir(), \".pi\", \"agent\", \"models.json\");\n\tif (!existsSync(configPath)) {\n\t\treturn { models: [], error: null };\n\t}\n\n\ttry {\n\t\tconst content = readFileSync(configPath, \"utf-8\");\n\t\tconst config: ModelsConfig = JSON.parse(content);\n\n\t\t// Validate schema\n\t\tconst ajv = new Ajv();\n\t\tconst validate = ajv.compile(ModelsConfigSchema);\n\t\tif (!validate(config)) {\n\t\t\tconst errors =\n\t\t\t\tvalidate.errors?.map((e: any) => ` - ${e.instancePath || \"root\"}: ${e.message}`).join(\"\\n\") ||\n\t\t\t\t\"Unknown schema error\";\n\t\t\treturn {\n\t\t\t\tmodels: [],\n\t\t\t\terror: `Invalid models.json schema:\\n${errors}\\n\\nFile: ${configPath}`,\n\t\t\t};\n\t\t}\n\n\t\t// Additional validation\n\t\ttry {\n\t\t\tvalidateConfig(config);\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tmodels: [],\n\t\t\t\terror: `Invalid models.json: ${error instanceof Error ? error.message : error}\\n\\nFile: ${configPath}`,\n\t\t\t};\n\t\t}\n\n\t\t// Parse models\n\t\treturn { models: parseModels(config), error: null };\n\t} catch (error) {\n\t\tif (error instanceof SyntaxError) {\n\t\t\treturn {\n\t\t\t\tmodels: [],\n\t\t\t\terror: `Failed to parse models.json: ${error.message}\\n\\nFile: ${configPath}`,\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tmodels: [],\n\t\t\terror: `Failed to load models.json: ${error instanceof Error ? error.message : error}\\n\\nFile: ${configPath}`,\n\t\t};\n\t}\n}\n\n/**\n * Validate config structure and requirements\n */\nfunction validateConfig(config: ModelsConfig): void {\n\tfor (const [providerName, providerConfig] of Object.entries(config.providers)) {\n\t\tconst hasProviderApi = !!providerConfig.api;\n\n\t\tfor (const modelDef of providerConfig.models) {\n\t\t\tconst hasModelApi = !!modelDef.api;\n\n\t\t\tif (!hasProviderApi && !hasModelApi) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Provider ${providerName}, model ${modelDef.id}: no \"api\" specified. ` +\n\t\t\t\t\t\t`Set at provider or model level.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Validate required fields\n\t\t\tif (!modelDef.id) throw new Error(`Provider ${providerName}: model missing \"id\"`);\n\t\t\tif (!modelDef.name) throw new Error(`Provider ${providerName}: model missing \"name\"`);\n\t\t\tif (modelDef.contextWindow <= 0)\n\t\t\t\tthrow new Error(`Provider ${providerName}, model ${modelDef.id}: invalid contextWindow`);\n\t\t\tif (modelDef.maxTokens <= 0)\n\t\t\t\tthrow new Error(`Provider ${providerName}, model ${modelDef.id}: invalid maxTokens`);\n\t\t}\n\t}\n}\n\n/**\n * Parse config into Model objects\n */\nfunction parseModels(config: ModelsConfig): Model<Api>[] {\n\tconst models: Model<Api>[] = [];\n\n\t// Clear and rebuild custom provider API key mappings\n\tcustomProviderApiKeys.clear();\n\n\tfor (const [providerName, providerConfig] of Object.entries(config.providers)) {\n\t\t// Store API key config for this provider\n\t\tcustomProviderApiKeys.set(providerName, providerConfig.apiKey);\n\n\t\tfor (const modelDef of providerConfig.models) {\n\t\t\t// Model-level api overrides provider-level api\n\t\t\tconst api = modelDef.api || providerConfig.api;\n\n\t\t\tif (!api) {\n\t\t\t\t// This should have been caught by validateConfig, but be safe\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tmodels.push({\n\t\t\t\tid: modelDef.id,\n\t\t\t\tname: modelDef.name,\n\t\t\t\tapi: api as Api,\n\t\t\t\tprovider: providerName,\n\t\t\t\tbaseUrl: providerConfig.baseUrl,\n\t\t\t\treasoning: modelDef.reasoning,\n\t\t\t\tinput: modelDef.input as (\"text\" | \"image\")[],\n\t\t\t\tcost: modelDef.cost,\n\t\t\t\tcontextWindow: modelDef.contextWindow,\n\t\t\t\tmaxTokens: modelDef.maxTokens,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn models;\n}\n\n/**\n * Get all models (built-in + custom), freshly loaded\n * Returns { models, error } - either models array or error message\n */\nexport function loadAndMergeModels(): { models: Model<Api>[]; error: string | null } {\n\tconst builtInModels: Model<Api>[] = [];\n\tconst providers = getProviders();\n\n\t// Load all built-in models\n\tfor (const provider of providers) {\n\t\tconst providerModels = getModels(provider as KnownProvider);\n\t\tbuiltInModels.push(...(providerModels as Model<Api>[]));\n\t}\n\n\t// Load custom models\n\tconst { models: customModels, error } = loadCustomModels();\n\n\tif (error) {\n\t\treturn { models: [], error };\n\t}\n\n\t// Merge: custom models come after built-in\n\treturn { models: [...builtInModels, ...customModels], error: null };\n}\n\n/**\n * Get API key for a model (checks custom providers first, then built-in)\n */\nexport function getApiKeyForModel(model: Model<Api>): string | undefined {\n\t// For custom providers, check their apiKey config\n\tconst customKeyConfig = customProviderApiKeys.get(model.provider);\n\tif (customKeyConfig) {\n\t\treturn resolveApiKey(customKeyConfig);\n\t}\n\n\t// For built-in providers, use getApiKey from @mariozechner/pi-ai\n\treturn getApiKey(model.provider as KnownProvider);\n}\n\n/**\n * Get only models that have valid API keys available\n * Returns { models, error } - either models array or error message\n */\nexport function getAvailableModels(): { models: Model<Api>[]; error: string | null } {\n\tconst { models: allModels, error } = loadAndMergeModels();\n\n\tif (error) {\n\t\treturn { models: [], error };\n\t}\n\n\tconst availableModels = allModels.filter((model) => {\n\t\tconst apiKey = getApiKeyForModel(model);\n\t\treturn !!apiKey;\n\t});\n\n\treturn { models: availableModels, error: null };\n}\n\n/**\n * Find a specific model by provider and ID\n * Returns { model, error } - either model or error message\n */\nexport function findModel(provider: string, modelId: string): { model: Model<Api> | null; error: string | null } {\n\tconst { models: allModels, error } = loadAndMergeModels();\n\n\tif (error) {\n\t\treturn { model: null, error };\n\t}\n\n\tconst model = allModels.find((m) => m.provider === provider && m.id === modelId) || null;\n\treturn { model, error: null };\n}\n"]}
|