@prestyj/cli 4.3.34 → 4.3.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/cli.js +248 -59
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +122 -3
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +2 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auto-update.d.ts +8 -0
- package/dist/core/auto-update.d.ts.map +1 -1
- package/dist/core/auto-update.js +20 -2
- package/dist/core/auto-update.js.map +1 -1
- package/dist/core/compaction/compactor.d.ts.map +1 -1
- package/dist/core/compaction/compactor.js +4 -1
- package/dist/core/compaction/compactor.js.map +1 -1
- package/dist/core/compaction/compactor.test.js +5 -5
- package/dist/core/compaction/compactor.test.js.map +1 -1
- package/dist/core/compaction/token-estimator.d.ts.map +1 -1
- package/dist/core/compaction/token-estimator.js +14 -1
- package/dist/core/compaction/token-estimator.js.map +1 -1
- package/dist/core/logger.d.ts +7 -2
- package/dist/core/logger.d.ts.map +1 -1
- package/dist/core/logger.js +48 -4
- package/dist/core/logger.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +57 -25
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/prompt-commands.d.ts.map +1 -1
- package/dist/core/prompt-commands.js +224 -3
- package/dist/core/prompt-commands.js.map +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +29 -14
- package/dist/core/skills.js.map +1 -1
- package/dist/modes/agent-home-mode.js +6 -6
- package/dist/modes/agent-home-mode.js.map +1 -1
- package/dist/system-prompt.d.ts +5 -1
- package/dist/system-prompt.d.ts.map +1 -1
- package/dist/system-prompt.js +74 -104
- package/dist/system-prompt.js.map +1 -1
- package/dist/tools/edit.d.ts +2 -2
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +16 -3
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/plan-mode.test.js +20 -4
- package/dist/tools/plan-mode.test.js.map +1 -1
- package/dist/tools/prompt-hints.d.ts +10 -0
- package/dist/tools/prompt-hints.d.ts.map +1 -0
- package/dist/tools/prompt-hints.js +45 -0
- package/dist/tools/prompt-hints.js.map +1 -0
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +32 -6
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/read.test.js +23 -4
- package/dist/tools/read.test.js.map +1 -1
- package/dist/tools/write.test.js +13 -1
- package/dist/tools/write.test.js.map +1 -1
- package/dist/ui/App.d.ts +6 -1
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js +95 -24
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/components/EyesOverlay.d.ts +10 -0
- package/dist/ui/components/EyesOverlay.d.ts.map +1 -0
- package/dist/ui/components/EyesOverlay.js +220 -0
- package/dist/ui/components/EyesOverlay.js.map +1 -0
- package/dist/ui/components/Footer.d.ts.map +1 -1
- package/dist/ui/components/Footer.js +6 -5
- package/dist/ui/components/Footer.js.map +1 -1
- package/dist/ui/components/InputArea.d.ts +4 -1
- package/dist/ui/components/InputArea.d.ts.map +1 -1
- package/dist/ui/components/InputArea.js +4 -3
- package/dist/ui/components/InputArea.js.map +1 -1
- package/dist/ui/components/ModelSelector.d.ts.map +1 -1
- package/dist/ui/components/ModelSelector.js +1 -1
- package/dist/ui/components/ModelSelector.js.map +1 -1
- package/dist/ui/components/PlanOverlay.d.ts.map +1 -1
- package/dist/ui/components/PlanOverlay.js +7 -1
- package/dist/ui/components/PlanOverlay.js.map +1 -1
- package/dist/ui/components/SelectList.d.ts +3 -1
- package/dist/ui/components/SelectList.d.ts.map +1 -1
- package/dist/ui/components/SelectList.js +15 -2
- package/dist/ui/components/SelectList.js.map +1 -1
- package/dist/ui/components/SkillsOverlay.d.ts.map +1 -1
- package/dist/ui/components/SkillsOverlay.js +6 -59
- package/dist/ui/components/SkillsOverlay.js.map +1 -1
- package/dist/ui/components/SlashCommandMenu.d.ts.map +1 -1
- package/dist/ui/components/SlashCommandMenu.js +18 -8
- package/dist/ui/components/SlashCommandMenu.js.map +1 -1
- package/dist/ui/login.js +5 -5
- package/dist/ui/login.js.map +1 -1
- package/dist/ui/utils/token-to-ansi.d.ts.map +1 -1
- package/dist/ui/utils/token-to-ansi.js +9 -1
- package/dist/ui/utils/token-to-ansi.js.map +1 -1
- package/dist/utils/image.d.ts +18 -1
- package/dist/utils/image.d.ts.map +1 -1
- package/dist/utils/image.js +80 -31
- package/dist/utils/image.js.map +1 -1
- package/dist/utils/session-title.js +1 -1
- package/package.json +9 -7
package/README.md
CHANGED
|
@@ -75,7 +75,7 @@ Switch mid-conversation with `/model`. Not locked to anyone.
|
|
|
75
75
|
| **Anthropic** | Claude Opus 4.7, Sonnet 4.6, Haiku 4.5 | OAuth |
|
|
76
76
|
| **OpenAI** | GPT-4.1, o3, o4-mini | OAuth |
|
|
77
77
|
| **Z.AI (GLM)** | GLM-5.1, GLM-4.7 | API key |
|
|
78
|
-
| **Moonshot** | Kimi K2.
|
|
78
|
+
| **Moonshot** | Kimi K2.6 | API key |
|
|
79
79
|
|
|
80
80
|
---
|
|
81
81
|
|
|
@@ -85,7 +85,7 @@ Everything runs through slash commands inside the session. Not CLI flags.
|
|
|
85
85
|
|
|
86
86
|
```bash
|
|
87
87
|
/model claude-opus-4-7 # Switch models on the fly
|
|
88
|
-
/model kimi-k2.
|
|
88
|
+
/model kimi-k2.6
|
|
89
89
|
/compact # Compress context when it gets long
|
|
90
90
|
|
|
91
91
|
# Built-in workflows
|
package/dist/cli.js
CHANGED
|
@@ -38,12 +38,13 @@ import { PerformanceObserver, performance } from "node:perf_hooks";
|
|
|
38
38
|
import { parseArgs } from "node:util";
|
|
39
39
|
import fs from "node:fs";
|
|
40
40
|
import readline from "node:readline/promises";
|
|
41
|
-
import { execFile } from "node:child_process";
|
|
41
|
+
import { execFile, spawnSync } from "node:child_process";
|
|
42
42
|
import { createRequire } from "node:module";
|
|
43
43
|
import { renderApp } from "./ui/render.js";
|
|
44
44
|
import { runJsonMode } from "./modes/json-mode.js";
|
|
45
45
|
import { runRpcMode } from "./modes/rpc-mode.js";
|
|
46
46
|
import { runServeMode } from "./modes/serve-mode.js";
|
|
47
|
+
import { runAgentHomeMode } from "./modes/agent-home-mode.js";
|
|
47
48
|
import { renderLoginSelector } from "./ui/login.js";
|
|
48
49
|
import { renderSessionSelector } from "./ui/sessions.js";
|
|
49
50
|
import { formatUserError } from "./utils/error-handler.js";
|
|
@@ -53,10 +54,11 @@ import { ensureAppDirs, getAppPaths, loadSavedSettings } from "./config.js";
|
|
|
53
54
|
import { initLogger, log, closeLogger } from "./core/logger.js";
|
|
54
55
|
import { setStreamDiagnostic } from "@prestyj/agent";
|
|
55
56
|
import { buildSystemPrompt } from "./system-prompt.js";
|
|
57
|
+
import { isEyesActive, journalCount } from "@prestyj/ezcoder-eyes";
|
|
56
58
|
import { createTools } from "./tools/index.js";
|
|
57
59
|
import { shouldCompact, compact } from "./core/compaction/compactor.js";
|
|
58
60
|
import { setEstimatorModel } from "./core/compaction/token-estimator.js";
|
|
59
|
-
import { getContextWindow } from "./core/model-registry.js";
|
|
61
|
+
import { getContextWindow, getDefaultModel } from "./core/model-registry.js";
|
|
60
62
|
import { MCPClientManager, getMCPServers } from "./core/mcp/index.js";
|
|
61
63
|
import { discoverAgents } from "./core/agents.js";
|
|
62
64
|
import { discoverSkills } from "./core/skills.js";
|
|
@@ -144,7 +146,7 @@ function printHelp() {
|
|
|
144
146
|
["-h, --help", "Show this help message"],
|
|
145
147
|
["-v, --version", "Show version number"],
|
|
146
148
|
["--provider <name>", "AI provider (anthropic, xiaomi, openai, glm, moonshot)"],
|
|
147
|
-
["--model <name>", "Model to use (e.g. claude-sonnet-4-6, gpt-
|
|
149
|
+
["--model <name>", "Model to use (e.g. claude-sonnet-4-6, gpt-5.5)"],
|
|
148
150
|
["--max-turns <n>", "Maximum agent turns per prompt"],
|
|
149
151
|
["--system-prompt <text>", "Override the system prompt"],
|
|
150
152
|
["--json", "JSON output mode (for sub-agents)"],
|
|
@@ -187,7 +189,7 @@ function main() {
|
|
|
187
189
|
// Silent auto-update check (throttled, non-blocking on failure)
|
|
188
190
|
const updateMessage = checkAndAutoUpdate(CLI_VERSION);
|
|
189
191
|
if (updateMessage) {
|
|
190
|
-
console.error(chalk.hex("#
|
|
192
|
+
console.error(chalk.bold.hex("#4ade80")(`✨ ${updateMessage}`));
|
|
191
193
|
}
|
|
192
194
|
// Intercept --help / -h before anything else so it works with subcommands
|
|
193
195
|
// (e.g. `ezcoder login --help` or `ezcoder --help`)
|
|
@@ -197,6 +199,24 @@ function main() {
|
|
|
197
199
|
}
|
|
198
200
|
// Handle subcommands before parseArgs
|
|
199
201
|
const subcommand = process.argv[2];
|
|
202
|
+
// Passthrough to @prestyj/ezcoder-eyes CLI. Agents call this from bash as
|
|
203
|
+
// `ezcoder eyes log rough "..."` etc. — `ezcoder` is guaranteed on PATH
|
|
204
|
+
// (user launched it), so this avoids depending on nested bin visibility in
|
|
205
|
+
// global npm/pnpm installs.
|
|
206
|
+
if (subcommand === "eyes") {
|
|
207
|
+
let cliPath;
|
|
208
|
+
try {
|
|
209
|
+
cliPath = _require.resolve("@prestyj/ezcoder-eyes/cli");
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
process.stderr.write("ezcoder-eyes package not installed\n");
|
|
213
|
+
process.exit(1);
|
|
214
|
+
}
|
|
215
|
+
const r = spawnSync(process.execPath, [cliPath, ...process.argv.slice(3)], {
|
|
216
|
+
stdio: "inherit",
|
|
217
|
+
});
|
|
218
|
+
process.exit(r.status ?? 0);
|
|
219
|
+
}
|
|
200
220
|
if (subcommand === "login") {
|
|
201
221
|
runLogin().catch((err) => {
|
|
202
222
|
log("ERROR", "fatal", err instanceof Error ? err.message : String(err));
|
|
@@ -321,11 +341,11 @@ function main() {
|
|
|
321
341
|
const provider = saved.provider ?? "anthropic";
|
|
322
342
|
function getHardcodedDefault(p) {
|
|
323
343
|
if (p === "openai")
|
|
324
|
-
return "gpt-5.
|
|
344
|
+
return "gpt-5.5";
|
|
325
345
|
if (p === "glm")
|
|
326
346
|
return "glm-5.1";
|
|
327
347
|
if (p === "moonshot")
|
|
328
|
-
return "kimi-k2.
|
|
348
|
+
return "kimi-k2.6";
|
|
329
349
|
if (p === "minimax")
|
|
330
350
|
return "MiniMax-M2.7";
|
|
331
351
|
if (p === "openrouter")
|
|
@@ -353,53 +373,42 @@ function main() {
|
|
|
353
373
|
}
|
|
354
374
|
// ── Ink TUI ───────────────────────────────────────────────
|
|
355
375
|
async function runInkTUI(opts) {
|
|
356
|
-
const {
|
|
357
|
-
//
|
|
358
|
-
|
|
359
|
-
//
|
|
376
|
+
const { cwd } = opts;
|
|
377
|
+
// Resolve auth first so we can pick an active provider the user has
|
|
378
|
+
// actually logged in with — we must never default to a provider they
|
|
379
|
+
// haven't authenticated against.
|
|
360
380
|
const paths = await ensureAppDirs();
|
|
361
|
-
initLogger(paths.logFile, {
|
|
362
|
-
version: CLI_VERSION,
|
|
363
|
-
provider,
|
|
364
|
-
model,
|
|
365
|
-
thinking: opts.thinkingLevel,
|
|
366
|
-
});
|
|
367
381
|
// Wire stream stall diagnostics into the debug log
|
|
368
382
|
setStreamDiagnostic((phase, data) => {
|
|
369
383
|
log("INFO", "stream", phase, data);
|
|
370
384
|
});
|
|
371
385
|
const authStorage = new AuthStorage(paths.authFile);
|
|
372
386
|
await authStorage.load();
|
|
373
|
-
const
|
|
374
|
-
//
|
|
375
|
-
const allProviders = [
|
|
376
|
-
"anthropic",
|
|
377
|
-
"xiaomi",
|
|
378
|
-
"openai",
|
|
379
|
-
"glm",
|
|
380
|
-
"moonshot",
|
|
381
|
-
"minimax",
|
|
382
|
-
"openrouter",
|
|
383
|
-
];
|
|
384
|
-
const loggedInProviders = [];
|
|
387
|
+
const { provider, model, loggedInProviders } = await resolveActiveProvider(authStorage, opts.provider, opts.model);
|
|
388
|
+
// Preload every logged-in provider's credentials for the model switcher.
|
|
385
389
|
const credentialsByProvider = {};
|
|
386
|
-
for (const p of
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
}
|
|
398
|
-
catch {
|
|
399
|
-
// Token refresh failed — still mark as logged in
|
|
400
|
-
}
|
|
390
|
+
for (const p of loggedInProviders) {
|
|
391
|
+
try {
|
|
392
|
+
const resolved = await authStorage.resolveCredentials(p);
|
|
393
|
+
credentialsByProvider[p] = {
|
|
394
|
+
accessToken: resolved.accessToken,
|
|
395
|
+
accountId: resolved.accountId,
|
|
396
|
+
baseUrl: resolved.baseUrl,
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
catch {
|
|
400
|
+
// Token refresh failed — still leave them in loggedInProviders
|
|
401
401
|
}
|
|
402
402
|
}
|
|
403
|
+
// Set model for token estimation accuracy (after provider is finalized)
|
|
404
|
+
setEstimatorModel(model);
|
|
405
|
+
initLogger(paths.logFile, {
|
|
406
|
+
version: CLI_VERSION,
|
|
407
|
+
provider,
|
|
408
|
+
model,
|
|
409
|
+
thinking: opts.thinkingLevel,
|
|
410
|
+
});
|
|
411
|
+
const creds = await authStorage.resolveCredentials(provider);
|
|
403
412
|
// Ensure project-local .ezcoder directories exist
|
|
404
413
|
const localEzDir = path.join(cwd, ".ezcoder");
|
|
405
414
|
await fs.promises.mkdir(path.join(localEzDir, "skills"), { recursive: true });
|
|
@@ -505,6 +514,21 @@ async function runInkTUI(opts) {
|
|
|
505
514
|
sessionPath = session.path;
|
|
506
515
|
log("INFO", "session", `New session created`, { path: sessionPath });
|
|
507
516
|
}
|
|
517
|
+
// Eyes startup banner — surface open journal signals from past sessions so the
|
|
518
|
+
// user isn't relying on reading agent prose to know improvements are pending.
|
|
519
|
+
if (isEyesActive(cwd)) {
|
|
520
|
+
const openCount = journalCount({ status: "open" }, cwd);
|
|
521
|
+
if (openCount > 0) {
|
|
522
|
+
const s = openCount === 1 ? "" : "s";
|
|
523
|
+
if (!initialHistory)
|
|
524
|
+
initialHistory = [];
|
|
525
|
+
initialHistory.push({
|
|
526
|
+
kind: "info",
|
|
527
|
+
text: `👁 Eyes: ${openCount} open improvement signal${s} from recent sessions. Run /eyes-improve to triage.`,
|
|
528
|
+
id: "eyes-banner",
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
}
|
|
508
532
|
await renderApp({
|
|
509
533
|
provider,
|
|
510
534
|
model,
|
|
@@ -876,11 +900,11 @@ async function runSessions() {
|
|
|
876
900
|
const provider = saved2.provider ?? "anthropic";
|
|
877
901
|
function getDefault(p) {
|
|
878
902
|
if (p === "openai")
|
|
879
|
-
return "gpt-5.
|
|
903
|
+
return "gpt-5.5";
|
|
880
904
|
if (p === "glm")
|
|
881
905
|
return "glm-5.1";
|
|
882
906
|
if (p === "moonshot")
|
|
883
|
-
return "kimi-k2.
|
|
907
|
+
return "kimi-k2.6";
|
|
884
908
|
if (p === "minimax")
|
|
885
909
|
return "MiniMax-M2.7";
|
|
886
910
|
return "claude-opus-4-7";
|
|
@@ -1064,21 +1088,12 @@ async function runServe() {
|
|
|
1064
1088
|
process.exit(1);
|
|
1065
1089
|
}
|
|
1066
1090
|
const saved3 = loadSavedSettings();
|
|
1067
|
-
const provider = serveValues.provider ?? saved3.provider ?? "anthropic";
|
|
1068
|
-
function getDefault(p) {
|
|
1069
|
-
if (p === "openai")
|
|
1070
|
-
return "gpt-5.4";
|
|
1071
|
-
if (p === "glm")
|
|
1072
|
-
return "glm-5.1";
|
|
1073
|
-
if (p === "moonshot")
|
|
1074
|
-
return "kimi-k2.5";
|
|
1075
|
-
if (p === "minimax")
|
|
1076
|
-
return "MiniMax-M2.7";
|
|
1077
|
-
return "claude-opus-4-7";
|
|
1078
|
-
}
|
|
1079
|
-
const model = serveValues.model ?? saved3.model ?? getDefault(provider);
|
|
1080
1091
|
const thinkingLevel = saved3.thinkingEnabled ? "medium" : undefined;
|
|
1081
1092
|
const paths = await ensureAppDirs();
|
|
1093
|
+
const authStorage = new AuthStorage(paths.authFile);
|
|
1094
|
+
await authStorage.load();
|
|
1095
|
+
const preferredProvider = serveValues.provider ?? saved3.provider ?? "anthropic";
|
|
1096
|
+
const { provider, model } = await resolveActiveProvider(authStorage, preferredProvider, serveValues.model ?? saved3.model);
|
|
1082
1097
|
initLogger(paths.logFile, {
|
|
1083
1098
|
version: CLI_VERSION,
|
|
1084
1099
|
provider,
|
|
@@ -1094,7 +1109,176 @@ async function runServe() {
|
|
|
1094
1109
|
telegram: { botToken, userId },
|
|
1095
1110
|
});
|
|
1096
1111
|
}
|
|
1112
|
+
async function loadAgentHomeConfig() {
|
|
1113
|
+
try {
|
|
1114
|
+
const raw = await fs.promises.readFile(getAppPaths().agentHomeFile, "utf-8");
|
|
1115
|
+
const data = JSON.parse(raw);
|
|
1116
|
+
if (data.token)
|
|
1117
|
+
return data;
|
|
1118
|
+
return null;
|
|
1119
|
+
}
|
|
1120
|
+
catch {
|
|
1121
|
+
return null;
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
async function saveAgentHomeConfig(config) {
|
|
1125
|
+
const paths = await ensureAppDirs();
|
|
1126
|
+
await fs.promises.writeFile(paths.agentHomeFile, JSON.stringify(config, null, 2), {
|
|
1127
|
+
encoding: "utf-8",
|
|
1128
|
+
mode: 0o600,
|
|
1129
|
+
});
|
|
1130
|
+
}
|
|
1131
|
+
async function runAgentHomeLogin() {
|
|
1132
|
+
process.stdout.write("\x1b[2J\x1b[3J\x1b[H");
|
|
1133
|
+
const paths = await ensureAppDirs();
|
|
1134
|
+
initLogger(paths.logFile, { version: CLI_VERSION });
|
|
1135
|
+
log("INFO", "agent-home", "Agent Home login started");
|
|
1136
|
+
const existing = await loadAgentHomeConfig();
|
|
1137
|
+
// Banner
|
|
1138
|
+
const LOGO = [
|
|
1139
|
+
" \u2588\u2580\u2580\u2580 \u2580\u2580\u2580\u2588",
|
|
1140
|
+
" \u2588\u2580\u2580 \u2584\u2580 ",
|
|
1141
|
+
" \u2588\u2584\u2584\u2584 \u2588\u2584\u2584\u2584",
|
|
1142
|
+
];
|
|
1143
|
+
function gradientTextLocal(text) {
|
|
1144
|
+
let colorIdx = 0;
|
|
1145
|
+
return text
|
|
1146
|
+
.split("")
|
|
1147
|
+
.map((ch) => {
|
|
1148
|
+
if (ch === " ")
|
|
1149
|
+
return ch;
|
|
1150
|
+
const color = GRADIENT[colorIdx++ % GRADIENT.length];
|
|
1151
|
+
return chalk.hex(color)(ch);
|
|
1152
|
+
})
|
|
1153
|
+
.join("");
|
|
1154
|
+
}
|
|
1155
|
+
const GAP = " ";
|
|
1156
|
+
console.log();
|
|
1157
|
+
console.log(` ${gradientTextLocal(LOGO[0])}${GAP}` +
|
|
1158
|
+
chalk.hex("#60a5fa").bold("EZ Coder") +
|
|
1159
|
+
chalk.hex("#6b7280")(` v${CLI_VERSION}`) +
|
|
1160
|
+
chalk.hex("#6b7280")(" \u00b7 By ") +
|
|
1161
|
+
chalk.white.bold("Nolan Grout"));
|
|
1162
|
+
console.log(` ${gradientTextLocal(LOGO[1])}${GAP}` + chalk.hex("#a78bfa")("Agent Home Setup"));
|
|
1163
|
+
console.log(` ${gradientTextLocal(LOGO[2])}${GAP}` + chalk.hex("#6b7280")("Remote Control via iOS"));
|
|
1164
|
+
console.log();
|
|
1165
|
+
if (existing) {
|
|
1166
|
+
console.log(chalk.hex("#6b7280")(" Current config:\n") +
|
|
1167
|
+
chalk.hex("#6b7280")(` Token: ${existing.token.slice(0, 8)}...${existing.token.slice(-4)}\n`));
|
|
1168
|
+
}
|
|
1169
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
1170
|
+
try {
|
|
1171
|
+
console.log(chalk.hex("#a78bfa")(" Auth Token\n") +
|
|
1172
|
+
chalk.hex("#6b7280")(" Open Agent Home iOS app \u2192 Settings \u2192 Generate SDK Token\n") +
|
|
1173
|
+
chalk.hex("#6b7280")(" Copy the token\n"));
|
|
1174
|
+
const tokenPrompt = existing
|
|
1175
|
+
? chalk.hex("#60a5fa")(" Auth token (enter to keep current): ")
|
|
1176
|
+
: chalk.hex("#60a5fa")(" Auth token: ");
|
|
1177
|
+
const tokenInput = await rl.question(tokenPrompt);
|
|
1178
|
+
const token = tokenInput.trim() || existing?.token;
|
|
1179
|
+
if (!token) {
|
|
1180
|
+
console.log(chalk.hex("#ef4444")("\n No token provided. Setup cancelled."));
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1183
|
+
// Save config
|
|
1184
|
+
await saveAgentHomeConfig({ token });
|
|
1185
|
+
log("INFO", "agent-home", `Agent Home setup complete`);
|
|
1186
|
+
console.log(chalk.hex("#4ade80")(`\n \u2713 Token saved`) +
|
|
1187
|
+
"\n" +
|
|
1188
|
+
chalk.hex("#4ade80")(` \u2713 Config saved to ${paths.agentHomeFile}`) +
|
|
1189
|
+
"\n\n" +
|
|
1190
|
+
chalk.hex("#60a5fa")(" To start:\n") +
|
|
1191
|
+
chalk.hex("#6b7280")(" cd your-project && ezcoder agent-home\n"));
|
|
1192
|
+
}
|
|
1193
|
+
finally {
|
|
1194
|
+
rl.close();
|
|
1195
|
+
closeLogger();
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
// ── Agent Home (Run) ────────────────────────────────────
|
|
1199
|
+
async function runAgentHome() {
|
|
1200
|
+
const { values: ahValues } = parseArgs({
|
|
1201
|
+
options: {
|
|
1202
|
+
token: { type: "string" },
|
|
1203
|
+
provider: { type: "string" },
|
|
1204
|
+
model: { type: "string" },
|
|
1205
|
+
},
|
|
1206
|
+
strict: true,
|
|
1207
|
+
});
|
|
1208
|
+
// Priority: CLI flags > saved config
|
|
1209
|
+
const saved = await loadAgentHomeConfig();
|
|
1210
|
+
const token = ahValues.token ?? saved?.token;
|
|
1211
|
+
if (!token) {
|
|
1212
|
+
console.error(chalk.hex("#ef4444")("Agent Home not configured.\n\n") +
|
|
1213
|
+
"Run " +
|
|
1214
|
+
chalk.hex("#60a5fa").bold("ezcoder agent-home-login") +
|
|
1215
|
+
" to set up your token.\n\n" +
|
|
1216
|
+
chalk.hex("#6b7280")("Or provide manually:\n") +
|
|
1217
|
+
chalk.hex("#6b7280")(" ezcoder agent-home --token TOKEN"));
|
|
1218
|
+
process.exit(1);
|
|
1219
|
+
}
|
|
1220
|
+
const saved4 = loadSavedSettings();
|
|
1221
|
+
const thinkingLevel = saved4.thinkingEnabled ? "medium" : undefined;
|
|
1222
|
+
const paths = await ensureAppDirs();
|
|
1223
|
+
const authStorage = new AuthStorage(paths.authFile);
|
|
1224
|
+
await authStorage.load();
|
|
1225
|
+
const preferredProvider = ahValues.provider ?? saved4.provider ?? "anthropic";
|
|
1226
|
+
const { provider, model } = await resolveActiveProvider(authStorage, preferredProvider, ahValues.model ?? saved4.model);
|
|
1227
|
+
initLogger(paths.logFile, {
|
|
1228
|
+
version: CLI_VERSION,
|
|
1229
|
+
provider,
|
|
1230
|
+
model,
|
|
1231
|
+
});
|
|
1232
|
+
setEstimatorModel(model);
|
|
1233
|
+
await runAgentHomeMode({
|
|
1234
|
+
provider,
|
|
1235
|
+
model,
|
|
1236
|
+
cwd: process.cwd(),
|
|
1237
|
+
version: CLI_VERSION,
|
|
1238
|
+
thinkingLevel,
|
|
1239
|
+
agentHome: { token },
|
|
1240
|
+
});
|
|
1241
|
+
}
|
|
1097
1242
|
// ── Helpers ────────────────────────────────────────────────
|
|
1243
|
+
/**
|
|
1244
|
+
* Resolve the provider and model to start with. If the preferred provider isn't
|
|
1245
|
+
* one the user is logged into, fall back to the first provider they ARE
|
|
1246
|
+
* logged into (in `allProviders` order). Throws if nothing is logged in.
|
|
1247
|
+
*
|
|
1248
|
+
* This prevents the CLI from crashing with "Not logged in" on startup just
|
|
1249
|
+
* because settings.json remembers a provider the user later logged out of.
|
|
1250
|
+
*/
|
|
1251
|
+
async function resolveActiveProvider(authStorage, preferred, savedModel) {
|
|
1252
|
+
const allProviders = [
|
|
1253
|
+
"anthropic",
|
|
1254
|
+
"xiaomi",
|
|
1255
|
+
"openai",
|
|
1256
|
+
"glm",
|
|
1257
|
+
"moonshot",
|
|
1258
|
+
"minimax",
|
|
1259
|
+
"openrouter",
|
|
1260
|
+
];
|
|
1261
|
+
const loggedInProviders = [];
|
|
1262
|
+
for (const p of allProviders) {
|
|
1263
|
+
if (await authStorage.getCredentials(p))
|
|
1264
|
+
loggedInProviders.push(p);
|
|
1265
|
+
}
|
|
1266
|
+
if (loggedInProviders.length === 0) {
|
|
1267
|
+
throw new Error('Not logged in to any provider. Run "ezcoder login" to authenticate.');
|
|
1268
|
+
}
|
|
1269
|
+
if (loggedInProviders.includes(preferred)) {
|
|
1270
|
+
return {
|
|
1271
|
+
provider: preferred,
|
|
1272
|
+
model: savedModel ?? getDefaultModel(preferred).id,
|
|
1273
|
+
loggedInProviders,
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1276
|
+
// Preferred provider isn't authenticated — fall back to the first one
|
|
1277
|
+
// that is, and use that provider's default model (the saved model
|
|
1278
|
+
// belonged to a provider the user can no longer reach).
|
|
1279
|
+
const provider = loggedInProviders[0];
|
|
1280
|
+
return { provider, model: getDefaultModel(provider).id, loggedInProviders };
|
|
1281
|
+
}
|
|
1098
1282
|
function displayName(provider) {
|
|
1099
1283
|
if (provider === "anthropic")
|
|
1100
1284
|
return "Anthropic";
|
|
@@ -1126,8 +1310,13 @@ function messagesToHistoryItems(msgs) {
|
|
|
1126
1310
|
for (const msg of msgs) {
|
|
1127
1311
|
if (msg.role === "tool") {
|
|
1128
1312
|
for (const tr of msg.content) {
|
|
1313
|
+
const text = typeof tr.content === "string"
|
|
1314
|
+
? tr.content
|
|
1315
|
+
: tr.content
|
|
1316
|
+
.map((b) => (b.type === "text" ? b.text : `[image ${b.mediaType}]`))
|
|
1317
|
+
.join("\n");
|
|
1129
1318
|
toolResults.set(tr.toolCallId, {
|
|
1130
|
-
content:
|
|
1319
|
+
content: text,
|
|
1131
1320
|
isError: tr.isError ?? false,
|
|
1132
1321
|
});
|
|
1133
1322
|
}
|