aiden-runtime 4.0.1 → 4.0.2
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/dist/cli/v4/aidenCLI.js +92 -9
- package/dist/cli/v4/chatSession.js +16 -0
- package/dist/cli/v4/commands/index.js +4 -1
- package/dist/cli/v4/commands/setup.js +34 -0
- package/dist/cli/v4/display.js +3 -1
- package/dist/cli/v4/setupWizard.js +466 -232
- package/dist/core/v4/firstRun/providerDetection.js +287 -0
- package/dist/core/version.js +1 -1
- package/dist/providers/v4/nullAdapter.js +58 -0
- package/package.json +1 -1
package/dist/cli/v4/aidenCLI.js
CHANGED
|
@@ -58,6 +58,9 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
58
58
|
return result;
|
|
59
59
|
};
|
|
60
60
|
})();
|
|
61
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
62
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
63
|
+
};
|
|
61
64
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
62
65
|
exports.getEnvSource = exports.loadAidenEnvFile = void 0;
|
|
63
66
|
exports.main = main;
|
|
@@ -71,6 +74,7 @@ exports.runSkillsSubcommand = runSkillsSubcommand;
|
|
|
71
74
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
72
75
|
const commander_1 = require("commander");
|
|
73
76
|
const node_fs_1 = require("node:fs");
|
|
77
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
74
78
|
const chatSession_1 = require("./chatSession");
|
|
75
79
|
const aidenTUI_1 = require("./aidenTUI");
|
|
76
80
|
const display_1 = require("./display");
|
|
@@ -106,6 +110,7 @@ const runtimeResolver_1 = require("../../providers/v4/runtimeResolver");
|
|
|
106
110
|
const chatCompletionsAdapter_1 = require("../../providers/v4/chatCompletionsAdapter");
|
|
107
111
|
const providerFallback_1 = require("../../core/v4/providerFallback");
|
|
108
112
|
const skillBundledRestore_1 = require("../../core/v4/skillBundledRestore");
|
|
113
|
+
const providerDetection_1 = require("../../core/v4/firstRun/providerDetection");
|
|
109
114
|
const aidenLogger_1 = require("../../core/v4/aidenLogger");
|
|
110
115
|
const plugins_1 = require("../../core/v4/plugins");
|
|
111
116
|
const providerAuth_1 = require("../../core/v4/auth/providerAuth");
|
|
@@ -351,9 +356,70 @@ async function buildAgentRuntime(cliOpts, opts) {
|
|
|
351
356
|
}
|
|
352
357
|
const config = new config_1.ConfigManager(paths);
|
|
353
358
|
await config.load();
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
359
|
+
// Phase 30.2 — fresh-user UX. Detection extends the old
|
|
360
|
+
// `isFreshInstall`-only gate so we cover three new failure modes:
|
|
361
|
+
// 1. fresh user with no env / no OAuth / no config → wizard fires
|
|
362
|
+
// (was working under the old gate; still does).
|
|
363
|
+
// 2. user with config.yaml pointing at chatgpt-plus but a stale /
|
|
364
|
+
// missing OAuth token file → wizard fires (was NOT under old
|
|
365
|
+
// code — it saw config.yaml present and proceeded into a
|
|
366
|
+
// broken resolve, which surfaced as a confusing rate-limit
|
|
367
|
+
// error on the user's first chat).
|
|
368
|
+
// 3. user with no config but Ollama running OR an env API key
|
|
369
|
+
// → wizard fires anyway. ConfigManager's DEFAULT_CONFIG points
|
|
370
|
+
// at `anthropic / claude-opus-4-7`, which doesn't match the
|
|
371
|
+
// detected env / Ollama, so skipping the wizard would surface
|
|
372
|
+
// the same confusing "missing ANTHROPIC_API_KEY" error.
|
|
373
|
+
// 4. moat-boot test fixtures that stub `providers.fake.apiKey`
|
|
374
|
+
// inline in config.yaml count as configured — `isFreshInstall`
|
|
375
|
+
// already returns false for them so `wizardNeeded` stays false.
|
|
376
|
+
const detection = await (0, providerDetection_1.detectAvailableProviders)({ paths });
|
|
377
|
+
const configuredProviderBroken = !!detection.configProvider &&
|
|
378
|
+
!detection.configuredProviderHasCredentials;
|
|
379
|
+
const wizardNeeded = !detection.hasAnyProvider ||
|
|
380
|
+
configuredProviderBroken ||
|
|
381
|
+
(await (0, setupWizard_1.isFreshInstall)(paths));
|
|
382
|
+
// Phase 30.2.1: when the wizard returns 'skipped' (explore mode) we
|
|
383
|
+
// boot the REPL with a NullAdapter instead of trying to resolve a
|
|
384
|
+
// real provider. Flagged here, set inside the wizard block, and
|
|
385
|
+
// consumed when building the adapter.
|
|
386
|
+
let exploreMode = false;
|
|
387
|
+
if (wizardNeeded) {
|
|
388
|
+
if (!detection.hasAnyProvider) {
|
|
389
|
+
// Truly empty: no env, no OAuth, no Ollama, no inline config.
|
|
390
|
+
process.stdout.write(`\n${(0, providerDetection_1.summarizeDetection)(detection)}\n`);
|
|
391
|
+
}
|
|
392
|
+
else if (configuredProviderBroken) {
|
|
393
|
+
// Config points at a provider we can't credential-resolve.
|
|
394
|
+
process.stdout.write(`\nConfigured provider '${detection.configProvider}' has no usable credentials ` +
|
|
395
|
+
`at ${node_path_1.default.join(paths.root, 'auth', `${detection.configProvider}.json`)}.\n`);
|
|
396
|
+
}
|
|
397
|
+
else {
|
|
398
|
+
// Detected something (env / oauth / ollama) but config.yaml is
|
|
399
|
+
// missing or empty — DEFAULT_CONFIG would route to anthropic and
|
|
400
|
+
// the resolver would fail. Surface the detection so the user
|
|
401
|
+
// sees what we found, then walk them through proper setup.
|
|
402
|
+
process.stdout.write(`\n${(0, providerDetection_1.summarizeDetection)(detection)}\n`);
|
|
403
|
+
process.stdout.write('config.yaml is empty — let\'s pick a provider that matches.\n');
|
|
404
|
+
}
|
|
405
|
+
process.stdout.write('Launching setup wizard…\n\n');
|
|
406
|
+
const result = await (0, setupWizard_1.runSetupWizard)({ paths });
|
|
407
|
+
// Phase 30.2.1: three exit states.
|
|
408
|
+
if (result.status === 'exited') {
|
|
409
|
+
// Recovery option [5] — clean exit, no REPL.
|
|
410
|
+
process.exit(0);
|
|
411
|
+
}
|
|
412
|
+
if (result.status === 'skipped') {
|
|
413
|
+
// Recovery option [4] "explore mode" OR Ctrl+C cancellation.
|
|
414
|
+
// Boot continues into the REPL with a NullAdapter; chat is
|
|
415
|
+
// intercepted by ChatSession, slash commands work normally.
|
|
416
|
+
// Flagged here and consumed below where the adapter is built.
|
|
417
|
+
exploreMode = true;
|
|
418
|
+
}
|
|
419
|
+
// 'configured' (or 'skipped' — we still want the env/.env reload
|
|
420
|
+
// for slash commands like /providers that read fresh state) →
|
|
421
|
+
// re-load both so the resolver sees what the wizard wrote.
|
|
422
|
+
(0, envSources_1.loadAidenEnvFile)(paths.envFile);
|
|
357
423
|
await config.load();
|
|
358
424
|
}
|
|
359
425
|
const providerId = cliOpts.provider ??
|
|
@@ -385,19 +451,32 @@ async function buildAgentRuntime(cliOpts, opts) {
|
|
|
385
451
|
const credentialResolver = new credentialResolver_1.CredentialResolver(paths.authJson);
|
|
386
452
|
const resolver = new runtimeResolver_1.RuntimeResolver(credentialResolver);
|
|
387
453
|
let adapter;
|
|
388
|
-
|
|
389
|
-
|
|
454
|
+
if (exploreMode) {
|
|
455
|
+
// Phase 30.2.1 — wizard skipped. Use a NullAdapter so AidenAgent
|
|
456
|
+
// construction succeeds; ChatSession will intercept chat attempts
|
|
457
|
+
// BEFORE calling the adapter and surface the friendly message.
|
|
458
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
459
|
+
const { NullAdapter } = require('../../providers/v4/nullAdapter');
|
|
460
|
+
adapter = new NullAdapter();
|
|
390
461
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
462
|
+
else {
|
|
463
|
+
try {
|
|
464
|
+
adapter = await resolver.resolve({ providerId, modelId, config, paths });
|
|
465
|
+
}
|
|
466
|
+
catch (err) {
|
|
467
|
+
display.printError(`Could not resolve provider '${providerId}' / model '${modelId}': ${err.message}`, 'Run `aiden model` to pick a valid provider, or `aiden doctor`.');
|
|
468
|
+
process.exit(1);
|
|
469
|
+
}
|
|
394
470
|
}
|
|
395
471
|
// Phase 16b.1: wrap chat_completions providers in a FallbackAdapter so
|
|
396
472
|
// 429s on Groq slot 1 transparently retry Groq slot 2/3 and Together.
|
|
397
473
|
// Only activates when there's at least one *additional* slot configured
|
|
398
474
|
// beyond the primary — otherwise the wrapper would just rethrow.
|
|
475
|
+
// Phase 30.2.1: skip in explore mode — wrapping a NullAdapter in
|
|
476
|
+
// FallbackAdapter would just defer the friendly error one layer.
|
|
399
477
|
let fallbackAdapter = null;
|
|
400
|
-
if (
|
|
478
|
+
if (!exploreMode &&
|
|
479
|
+
adapter.apiMode === 'chat_completions' &&
|
|
401
480
|
(providerId === 'groq' || providerId === 'together')) {
|
|
402
481
|
const slots = buildAgentFallbackSlots(adapter, providerId, modelId);
|
|
403
482
|
const reachable = slots.filter((s) => s.keyPresent);
|
|
@@ -820,6 +899,7 @@ async function buildAgentRuntime(cliOpts, opts) {
|
|
|
820
899
|
fallbackAdapter,
|
|
821
900
|
personalityManager,
|
|
822
901
|
pluginLoader,
|
|
902
|
+
exploreMode,
|
|
823
903
|
};
|
|
824
904
|
}
|
|
825
905
|
async function runInteractiveChat(cliOpts, opts) {
|
|
@@ -846,6 +926,9 @@ async function runInteractiveChat(cliOpts, opts) {
|
|
|
846
926
|
paths: runtime.paths,
|
|
847
927
|
personalityManager: runtime.personalityManager,
|
|
848
928
|
pluginLoader: runtime.pluginLoader,
|
|
929
|
+
// Phase 30.2.1 — boot card renders "model not configured" and
|
|
930
|
+
// chat attempts get the friendly NotConfiguredError message.
|
|
931
|
+
unconfigured: runtime.exploreMode,
|
|
849
932
|
};
|
|
850
933
|
if (cliOpts.tui) {
|
|
851
934
|
await (0, aidenTUI_1.runTuiMode)({
|
|
@@ -212,6 +212,18 @@ class ChatSession {
|
|
|
212
212
|
}
|
|
213
213
|
// ── Inner: a single agent turn ─────────────────────────────────────
|
|
214
214
|
async runAgentTurn(userInput) {
|
|
215
|
+
// Phase 30.2.1 — explore mode: short-circuit BEFORE building the
|
|
216
|
+
// turn-status spinner / agent call. The wizard skipped, so there's
|
|
217
|
+
// no real provider to talk to. Print a friendly redirect to /setup
|
|
218
|
+
// (or the env-var alternative) and return — REPL stays alive, user
|
|
219
|
+
// can run slash commands or hit /quit.
|
|
220
|
+
if (this.opts.unconfigured) {
|
|
221
|
+
void userInput; // silence unused-arg warning when this branch fires
|
|
222
|
+
this.opts.display.write('\n');
|
|
223
|
+
this.opts.display.printError('No AI provider configured yet.', 'Run /setup to configure a provider, or set an API key environment variable (e.g. GROQ_API_KEY).');
|
|
224
|
+
this.opts.display.write('\n');
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
215
227
|
// Phase 22 Task 4: status bar reflects the live phase. Set on
|
|
216
228
|
// entry, cleared in both success and error paths below.
|
|
217
229
|
this.setStatusState({ kind: 'generating', sinceMs: Date.now() });
|
|
@@ -353,11 +365,15 @@ class ChatSession {
|
|
|
353
365
|
skillsLoaded = 0;
|
|
354
366
|
}
|
|
355
367
|
// PIECE 1 — status pills row.
|
|
368
|
+
// Phase 30.2.1: in explore mode the model pill renders "not
|
|
369
|
+
// configured" instead of the DEFAULT_CONFIG fallback, so a fresh
|
|
370
|
+
// user who skipped the wizard isn't misled by a stale model name.
|
|
356
371
|
display.write(display.statusPillsRow({
|
|
357
372
|
coreOnline: true,
|
|
358
373
|
mode: 'auto',
|
|
359
374
|
model: this.currentModelId,
|
|
360
375
|
memoryActive: true,
|
|
376
|
+
providerOk: !this.opts.unconfigured,
|
|
361
377
|
}) + '\n');
|
|
362
378
|
display.write(` ${display.rule()}\n`);
|
|
363
379
|
display.write('\n');
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* and registers each on the global CommandRegistry at boot.
|
|
13
13
|
*/
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.allCommands = exports.cron = exports.doctor = exports.license = exports.auth = exports.plugins = exports.streaming = exports.debugPrompt = exports.identity = exports.providers = exports.quit = exports.clear = exports.verbose = exports.reasoning = exports.reloadMcp = exports.skills = exports.skin = exports.yolo = exports.usage = exports.compress = exports.title = exports.save = exports.personality = exports.model = exports.tools = exports.help = void 0;
|
|
15
|
+
exports.allCommands = exports.setup = exports.cron = exports.doctor = exports.license = exports.auth = exports.plugins = exports.streaming = exports.debugPrompt = exports.identity = exports.providers = exports.quit = exports.clear = exports.verbose = exports.reasoning = exports.reloadMcp = exports.skills = exports.skin = exports.yolo = exports.usage = exports.compress = exports.title = exports.save = exports.personality = exports.model = exports.tools = exports.help = void 0;
|
|
16
16
|
const help_1 = require("./help");
|
|
17
17
|
Object.defineProperty(exports, "help", { enumerable: true, get: function () { return help_1.help; } });
|
|
18
18
|
const tools_1 = require("./tools");
|
|
@@ -63,6 +63,8 @@ const doctor_1 = require("./doctor");
|
|
|
63
63
|
Object.defineProperty(exports, "doctor", { enumerable: true, get: function () { return doctor_1.doctor; } });
|
|
64
64
|
const cron_1 = require("./cron");
|
|
65
65
|
Object.defineProperty(exports, "cron", { enumerable: true, get: function () { return cron_1.cron; } });
|
|
66
|
+
const setup_1 = require("./setup");
|
|
67
|
+
Object.defineProperty(exports, "setup", { enumerable: true, get: function () { return setup_1.setup; } });
|
|
66
68
|
/** All built-in system commands, in canonical order. */
|
|
67
69
|
exports.allCommands = [
|
|
68
70
|
help_1.help,
|
|
@@ -85,6 +87,7 @@ exports.allCommands = [
|
|
|
85
87
|
license_1.license,
|
|
86
88
|
doctor_1.doctor,
|
|
87
89
|
cron_1.cron,
|
|
90
|
+
setup_1.setup,
|
|
88
91
|
reloadMcp_1.reloadMcp,
|
|
89
92
|
reasoning_1.reasoning,
|
|
90
93
|
verbose_1.verbose,
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setup = void 0;
|
|
4
|
+
const setupWizard_1 = require("../setupWizard");
|
|
5
|
+
exports.setup = {
|
|
6
|
+
name: 'setup',
|
|
7
|
+
description: 'Re-run the setup wizard (configure provider + API key).',
|
|
8
|
+
category: 'system',
|
|
9
|
+
icon: '⚙',
|
|
10
|
+
handler: async (ctx) => {
|
|
11
|
+
if (!ctx.paths) {
|
|
12
|
+
ctx.display.printError('Cannot run wizard from this context — no paths available.', 'This is a wiring bug; please report.');
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const result = await (0, setupWizard_1.runSetupWizard)({
|
|
16
|
+
paths: ctx.paths,
|
|
17
|
+
display: ctx.display,
|
|
18
|
+
force: true,
|
|
19
|
+
});
|
|
20
|
+
if (result.status === 'configured' && result.ran) {
|
|
21
|
+
ctx.display.write('\nProvider configured. ' +
|
|
22
|
+
'Restart Aiden (`/quit` then re-run `aiden`) to pick up the new provider.\n\n');
|
|
23
|
+
}
|
|
24
|
+
else if (result.status === 'skipped') {
|
|
25
|
+
ctx.display.write('\nStill in explore mode. Run /setup again whenever you\'re ready.\n\n');
|
|
26
|
+
}
|
|
27
|
+
else if (result.status === 'exited') {
|
|
28
|
+
// Wizard explicitly chose to exit — but we're inside a REPL,
|
|
29
|
+
// so just report and stay in the session.
|
|
30
|
+
ctx.display.dim('Wizard exited; continuing existing session.');
|
|
31
|
+
}
|
|
32
|
+
return;
|
|
33
|
+
},
|
|
34
|
+
};
|
package/dist/cli/v4/display.js
CHANGED
|
@@ -305,11 +305,13 @@ class Display {
|
|
|
305
305
|
const lab = (s) => sk.applyColors(s, 'muted');
|
|
306
306
|
const val = (s) => sk.applyColors(s, 'agent');
|
|
307
307
|
const pill = (on, label, value) => `${dot(on)} ${lab(label)} ${val(value)}`;
|
|
308
|
+
const providerOk = args.providerOk !== false;
|
|
309
|
+
const modelValue = providerOk ? args.model : 'not configured';
|
|
308
310
|
return (' ' +
|
|
309
311
|
[
|
|
310
312
|
pill(args.coreOnline, 'core', args.coreOnline ? 'online' : 'starting'),
|
|
311
313
|
pill(true, 'mode', args.mode),
|
|
312
|
-
pill(
|
|
314
|
+
pill(providerOk, 'model', modelValue),
|
|
313
315
|
pill(args.memoryActive, 'memory', args.memoryActive ? 'active' : 'off'),
|
|
314
316
|
].join(' '));
|
|
315
317
|
}
|