infinicode 1.0.0 → 2.0.0
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/.opencode/plugins/home-logo-animation.tsx +120 -0
- package/.opencode/plugins/routing-mode-display.tsx +135 -0
- package/.opencode/themes/infinibot-gold.json +222 -0
- package/.opencode/tui.json +8 -0
- package/README.md +527 -75
- package/dist/ascii-video-animation.d.ts +2 -0
- package/dist/ascii-video-animation.js +243 -0
- package/dist/cli.js +195 -50
- package/dist/commands/console.d.ts +6 -0
- package/dist/commands/console.js +111 -0
- package/dist/commands/kernel-setup.d.ts +3 -0
- package/dist/commands/kernel-setup.js +303 -0
- package/dist/commands/mcp.d.ts +12 -0
- package/dist/commands/mcp.js +96 -0
- package/dist/commands/mission.d.ts +16 -0
- package/dist/commands/mission.js +301 -0
- package/dist/commands/models.d.ts +3 -1
- package/dist/commands/models.js +111 -55
- package/dist/commands/providers.d.ts +6 -0
- package/dist/commands/providers.js +95 -0
- package/dist/commands/run.d.ts +2 -1
- package/dist/commands/run.js +349 -59
- package/dist/commands/serve.d.ts +18 -0
- package/dist/commands/serve.js +127 -0
- package/dist/commands/setup.d.ts +1 -1
- package/dist/commands/setup.js +77 -44
- package/dist/commands/status.d.ts +2 -1
- package/dist/commands/status.js +46 -30
- package/dist/commands/workers.d.ts +5 -0
- package/dist/commands/workers.js +103 -0
- package/dist/kernel/autonomy/goal-loop.d.ts +49 -0
- package/dist/kernel/autonomy/goal-loop.js +113 -0
- package/dist/kernel/autonomy/index.d.ts +8 -0
- package/dist/kernel/autonomy/index.js +7 -0
- package/dist/kernel/browser/browser-controller.d.ts +57 -0
- package/dist/kernel/browser/browser-controller.js +175 -0
- package/dist/kernel/checkpoint-engine.d.ts +17 -0
- package/dist/kernel/checkpoint-engine.js +128 -0
- package/dist/kernel/command-system.d.ts +37 -0
- package/dist/kernel/command-system.js +239 -0
- package/dist/kernel/config-schema.d.ts +53 -0
- package/dist/kernel/config-schema.js +36 -0
- package/dist/kernel/event-bus.d.ts +19 -0
- package/dist/kernel/event-bus.js +65 -0
- package/dist/kernel/federation/auto-update.d.ts +36 -0
- package/dist/kernel/federation/auto-update.js +57 -0
- package/dist/kernel/federation/compute-router.d.ts +27 -0
- package/dist/kernel/federation/compute-router.js +44 -0
- package/dist/kernel/federation/config-sync.d.ts +33 -0
- package/dist/kernel/federation/config-sync.js +37 -0
- package/dist/kernel/federation/discovery.d.ts +11 -0
- package/dist/kernel/federation/discovery.js +44 -0
- package/dist/kernel/federation/event-bridge.d.ts +30 -0
- package/dist/kernel/federation/event-bridge.js +61 -0
- package/dist/kernel/federation/federation-plugin.d.ts +24 -0
- package/dist/kernel/federation/federation-plugin.js +35 -0
- package/dist/kernel/federation/federation.d.ts +126 -0
- package/dist/kernel/federation/federation.js +335 -0
- package/dist/kernel/federation/index.d.ts +31 -0
- package/dist/kernel/federation/index.js +23 -0
- package/dist/kernel/federation/moltfed-adapter.d.ts +30 -0
- package/dist/kernel/federation/moltfed-adapter.js +52 -0
- package/dist/kernel/federation/moltfed-connector.d.ts +98 -0
- package/dist/kernel/federation/moltfed-connector.js +193 -0
- package/dist/kernel/federation/node-identity.d.ts +19 -0
- package/dist/kernel/federation/node-identity.js +86 -0
- package/dist/kernel/federation/peer-mesh.d.ts +46 -0
- package/dist/kernel/federation/peer-mesh.js +117 -0
- package/dist/kernel/federation/protocol.d.ts +20 -0
- package/dist/kernel/federation/protocol.js +61 -0
- package/dist/kernel/federation/role-context.d.ts +5 -0
- package/dist/kernel/federation/role-context.js +45 -0
- package/dist/kernel/federation/telemetry.d.ts +21 -0
- package/dist/kernel/federation/telemetry.js +138 -0
- package/dist/kernel/federation/transport-http.d.ts +44 -0
- package/dist/kernel/federation/transport-http.js +207 -0
- package/dist/kernel/federation/types.d.ts +212 -0
- package/dist/kernel/federation/types.js +3 -0
- package/dist/kernel/free-providers.d.ts +28 -0
- package/dist/kernel/free-providers.js +162 -0
- package/dist/kernel/frontend-scoring.d.ts +21 -0
- package/dist/kernel/frontend-scoring.js +125 -0
- package/dist/kernel/index.d.ts +63 -0
- package/dist/kernel/index.js +45 -0
- package/dist/kernel/kernel.d.ts +75 -0
- package/dist/kernel/kernel.js +223 -0
- package/dist/kernel/logger.d.ts +18 -0
- package/dist/kernel/logger.js +26 -0
- package/dist/kernel/mcp/index.d.ts +9 -0
- package/dist/kernel/mcp/index.js +8 -0
- package/dist/kernel/mcp/mcp-server.d.ts +27 -0
- package/dist/kernel/mcp/mcp-server.js +178 -0
- package/dist/kernel/mission-engine.d.ts +42 -0
- package/dist/kernel/mission-engine.js +160 -0
- package/dist/kernel/orchestrator.d.ts +51 -0
- package/dist/kernel/orchestrator.js +226 -0
- package/dist/kernel/plugin-manager.d.ts +28 -0
- package/dist/kernel/plugin-manager.js +76 -0
- package/dist/kernel/plugins/browser-plugin.d.ts +22 -0
- package/dist/kernel/plugins/browser-plugin.js +34 -0
- package/dist/kernel/plugins/dashboard-plugin.d.ts +17 -0
- package/dist/kernel/plugins/dashboard-plugin.js +72 -0
- package/dist/kernel/plugins/discord-plugin.d.ts +11 -0
- package/dist/kernel/plugins/discord-plugin.js +35 -0
- package/dist/kernel/plugins/metrics-plugin.d.ts +33 -0
- package/dist/kernel/plugins/metrics-plugin.js +86 -0
- package/dist/kernel/plugins/search-plugin.d.ts +17 -0
- package/dist/kernel/plugins/search-plugin.js +20 -0
- package/dist/kernel/plugins/slack-plugin.d.ts +11 -0
- package/dist/kernel/plugins/slack-plugin.js +35 -0
- package/dist/kernel/plugins/telegram-plugin.d.ts +20 -0
- package/dist/kernel/plugins/telegram-plugin.js +122 -0
- package/dist/kernel/policies.d.ts +33 -0
- package/dist/kernel/policies.js +105 -0
- package/dist/kernel/provider-discovery.d.ts +41 -0
- package/dist/kernel/provider-discovery.js +179 -0
- package/dist/kernel/provider-manager.d.ts +38 -0
- package/dist/kernel/provider-manager.js +206 -0
- package/dist/kernel/provider-url.d.ts +18 -0
- package/dist/kernel/provider-url.js +45 -0
- package/dist/kernel/providers/gemini-provider.d.ts +43 -0
- package/dist/kernel/providers/gemini-provider.js +203 -0
- package/dist/kernel/providers/ollama-provider.d.ts +44 -0
- package/dist/kernel/providers/ollama-provider.js +241 -0
- package/dist/kernel/providers/openai-compatible-provider.d.ts +43 -0
- package/dist/kernel/providers/openai-compatible-provider.js +233 -0
- package/dist/kernel/recovery-manager.d.ts +38 -0
- package/dist/kernel/recovery-manager.js +156 -0
- package/dist/kernel/router.d.ts +44 -0
- package/dist/kernel/router.js +222 -0
- package/dist/kernel/sample-missions.d.ts +11 -0
- package/dist/kernel/sample-missions.js +132 -0
- package/dist/kernel/scheduler.d.ts +30 -0
- package/dist/kernel/scheduler.js +147 -0
- package/dist/kernel/sdk/harness-sdk.d.ts +37 -0
- package/dist/kernel/sdk/harness-sdk.js +48 -0
- package/dist/kernel/sdk/plugin-sdk.d.ts +27 -0
- package/dist/kernel/sdk/plugin-sdk.js +40 -0
- package/dist/kernel/search/search-controller.d.ts +32 -0
- package/dist/kernel/search/search-controller.js +141 -0
- package/dist/kernel/setup.d.ts +13 -0
- package/dist/kernel/setup.js +59 -0
- package/dist/kernel/types.d.ts +479 -0
- package/dist/kernel/types.js +7 -0
- package/dist/kernel/verification-engine.d.ts +33 -0
- package/dist/kernel/verification-engine.js +287 -0
- package/dist/kernel/worker-runtime.d.ts +66 -0
- package/dist/kernel/worker-runtime.js +261 -0
- package/dist/kernel/workers/browser-worker.d.ts +6 -0
- package/dist/kernel/workers/browser-worker.js +92 -0
- package/dist/kernel/workers/builtin-workers.d.ts +20 -0
- package/dist/kernel/workers/builtin-workers.js +120 -0
- package/dist/kernel/workers/research-worker.d.ts +5 -0
- package/dist/kernel/workers/research-worker.js +90 -0
- package/dist/prompt-ascii-video-animation.d.ts +2 -0
- package/dist/prompt-ascii-video-animation.js +243 -0
- package/package.json +43 -9
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* infinicode mission command — drives the OpenKernel runtime.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* infinicode mission run --goal "..." [--task "..." --cap coding ...]
|
|
6
|
+
* infinicode mission status <id>
|
|
7
|
+
* infinicode mission list
|
|
8
|
+
* infinicode mission resume <id>
|
|
9
|
+
* infinicode mission cancel <id>
|
|
10
|
+
*/
|
|
11
|
+
import chalk from 'chalk';
|
|
12
|
+
import ora from 'ora';
|
|
13
|
+
import { buildKernelFromConfig } from '../kernel/setup.js';
|
|
14
|
+
import { SAMPLE_MISSIONS } from '../kernel/sample-missions.js';
|
|
15
|
+
function parseCapabilities(raw) {
|
|
16
|
+
if (!raw)
|
|
17
|
+
return ['reasoning'];
|
|
18
|
+
return raw.split(',').map(s => s.trim()).filter(Boolean);
|
|
19
|
+
}
|
|
20
|
+
export async function missionRun(config, opts) {
|
|
21
|
+
const kernel = buildKernelFromConfig(config);
|
|
22
|
+
let input;
|
|
23
|
+
if (opts.sample) {
|
|
24
|
+
const sample = SAMPLE_MISSIONS[opts.sample];
|
|
25
|
+
if (!sample) {
|
|
26
|
+
console.log(chalk.red(`Unknown sample: ${opts.sample}`));
|
|
27
|
+
console.log(chalk.dim(`Available: ${Object.keys(SAMPLE_MISSIONS).join(', ')}`));
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
input = sample;
|
|
31
|
+
console.log(chalk.dim(`Using sample mission: ${chalk.cyan(opts.sample)}`));
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
const tasks = (opts.task ?? []).map((desc, i) => ({
|
|
35
|
+
description: desc,
|
|
36
|
+
capabilities: parseCapabilities(opts.cap?.[i] ?? opts.cap?.[0] ?? 'coding'),
|
|
37
|
+
input: { prompt: desc },
|
|
38
|
+
}));
|
|
39
|
+
if (tasks.length === 0) {
|
|
40
|
+
console.log(chalk.yellow('No --task provided; running a single goal-driven task.'));
|
|
41
|
+
tasks.push({
|
|
42
|
+
description: opts.goal,
|
|
43
|
+
capabilities: ['reasoning', 'coding'],
|
|
44
|
+
input: { prompt: opts.goal },
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
input = {
|
|
48
|
+
name: opts.name,
|
|
49
|
+
description: opts.description ?? opts.goal,
|
|
50
|
+
goal: opts.goal,
|
|
51
|
+
policy: opts.policy,
|
|
52
|
+
tasks,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const spinner = ora('Starting mission...').start();
|
|
56
|
+
// Renders are serialized through a queue so the routing animation for one
|
|
57
|
+
// task never interleaves with another task's spinner (missions run tasks in
|
|
58
|
+
// parallel, but their visualization plays back in event order).
|
|
59
|
+
let chain = Promise.resolve();
|
|
60
|
+
const enqueue = (fn) => {
|
|
61
|
+
chain = chain.then(fn).catch(() => { });
|
|
62
|
+
};
|
|
63
|
+
const line = (s) => {
|
|
64
|
+
if (spinner.isSpinning)
|
|
65
|
+
spinner.stop();
|
|
66
|
+
console.log(s);
|
|
67
|
+
};
|
|
68
|
+
const unsub = kernel.subscribeAll((event) => {
|
|
69
|
+
switch (event.type) {
|
|
70
|
+
case 'MISSION_STARTED':
|
|
71
|
+
enqueue(() => line(`${chalk.green('✔')} Mission started: ${chalk.cyan(String(event.missionId))}`));
|
|
72
|
+
break;
|
|
73
|
+
case 'ROUTING_DECISION':
|
|
74
|
+
enqueue(() => animateRouting(spinner, event.data));
|
|
75
|
+
break;
|
|
76
|
+
case 'TASK_STARTED': {
|
|
77
|
+
const model = event.data && typeof event.data === 'object' && 'modelId' in event.data
|
|
78
|
+
? event.data.modelId : '?';
|
|
79
|
+
enqueue(() => {
|
|
80
|
+
spinner.start(`${chalk.dim('task ' + (event.taskId ?? '?'))} executing on ${chalk.cyan(String(model))}`);
|
|
81
|
+
});
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
case 'TASK_COMPLETED':
|
|
85
|
+
enqueue(() => line(`${chalk.green('✔')} ${chalk.dim('task ' + (event.taskId ?? '?'))} completed`));
|
|
86
|
+
break;
|
|
87
|
+
case 'TASK_FAILED':
|
|
88
|
+
enqueue(() => line(`${chalk.red('✖')} ${chalk.dim('task ' + (event.taskId ?? '?'))} failed: ${String(event.data && typeof event.data === 'object' && 'error' in event.data ? event.data.error : '')}`));
|
|
89
|
+
break;
|
|
90
|
+
case 'MISSION_COMPLETED':
|
|
91
|
+
enqueue(() => line(chalk.green('✔ Mission completed')));
|
|
92
|
+
break;
|
|
93
|
+
case 'MISSION_FAILED':
|
|
94
|
+
enqueue(() => line(chalk.red('✖ Mission failed')));
|
|
95
|
+
break;
|
|
96
|
+
case 'PROVIDER_HEALTH':
|
|
97
|
+
// silent
|
|
98
|
+
break;
|
|
99
|
+
default:
|
|
100
|
+
if (process.env.OPENKERNEL_DEBUG === '1') {
|
|
101
|
+
enqueue(() => line(chalk.dim(`event ${event.type}`)));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
try {
|
|
106
|
+
const mission = await kernel.execute(input);
|
|
107
|
+
await chain;
|
|
108
|
+
if (spinner.isSpinning)
|
|
109
|
+
spinner.stop();
|
|
110
|
+
unsub();
|
|
111
|
+
console.log(chalk.bold('\nMission Result'));
|
|
112
|
+
console.log(chalk.dim('-'.repeat(50)));
|
|
113
|
+
console.log(` ID: ${chalk.cyan(mission.id)}`);
|
|
114
|
+
console.log(` Status: ${formatMissionStatus(mission.status)}`);
|
|
115
|
+
console.log(` Tasks: ${mission.tasks.length}`);
|
|
116
|
+
const completed = mission.tasks.filter(t => t.status === 'COMPLETED').length;
|
|
117
|
+
console.log(` Completed: ${completed}/${mission.tasks.length}`);
|
|
118
|
+
console.log(` Checkpoints: ${mission.checkpoints.length}`);
|
|
119
|
+
for (const task of mission.tasks) {
|
|
120
|
+
console.log(chalk.dim(`\n ── Task ${task.id} ──`));
|
|
121
|
+
console.log(` description: ${task.description}`);
|
|
122
|
+
console.log(` status: ${formatTaskStatus(task.status)}`);
|
|
123
|
+
if (task.providerId && task.modelId) {
|
|
124
|
+
console.log(` model: ${chalk.cyan(task.providerId + '/' + task.modelId)}`);
|
|
125
|
+
}
|
|
126
|
+
if (task.output?.content) {
|
|
127
|
+
const preview = task.output.content.slice(0, 400);
|
|
128
|
+
console.log(chalk.dim(' output:'));
|
|
129
|
+
console.log(chalk.dim(' ─────────────────────────────────────'));
|
|
130
|
+
for (const line of preview.split('\n')) {
|
|
131
|
+
console.log(' ' + line);
|
|
132
|
+
}
|
|
133
|
+
if (task.output.content.length > 400) {
|
|
134
|
+
console.log(chalk.dim(` … (${task.output.content.length - 400} more chars)`));
|
|
135
|
+
}
|
|
136
|
+
console.log(chalk.dim(' ─────────────────────────────────────'));
|
|
137
|
+
}
|
|
138
|
+
if (task.error) {
|
|
139
|
+
console.log(` error: ${chalk.red(task.error)}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
console.log();
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
await chain.catch(() => { });
|
|
146
|
+
unsub();
|
|
147
|
+
if (spinner.isSpinning)
|
|
148
|
+
spinner.stop();
|
|
149
|
+
console.log(chalk.red('✖ Mission execution failed'));
|
|
150
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
finally {
|
|
154
|
+
kernel.destroy();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const GOLD = '#FFD86B';
|
|
158
|
+
function sleep(ms) {
|
|
159
|
+
return new Promise(r => setTimeout(r, ms));
|
|
160
|
+
}
|
|
161
|
+
function candidateLabel(c) {
|
|
162
|
+
return `${c.providerId}/${c.modelId}`;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Animate the orchestrator's routing choice: a short "slot machine" over the
|
|
166
|
+
* ranked candidates, landing on and highlighting the chosen model in gold.
|
|
167
|
+
*/
|
|
168
|
+
async function animateRouting(spinner, data) {
|
|
169
|
+
if (!data || !data.chosen)
|
|
170
|
+
return;
|
|
171
|
+
if (spinner.isSpinning)
|
|
172
|
+
spinner.stop();
|
|
173
|
+
if (data.locked) {
|
|
174
|
+
console.log(' ' + chalk.hex(GOLD)('🔒 ') +
|
|
175
|
+
chalk.dim(`${data.workerType} · ${data.mode} locked → `) +
|
|
176
|
+
chalk.hex(GOLD).bold(candidateLabel(data.chosen)));
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const cands = data.candidates.length ? data.candidates : [data.chosen];
|
|
180
|
+
const interactive = !!process.stdout.isTTY && !process.env.CI;
|
|
181
|
+
if (interactive && cands.length > 1) {
|
|
182
|
+
const ticks = Math.min(16, 6 + cands.length * 2);
|
|
183
|
+
for (let i = 0; i < ticks; i++) {
|
|
184
|
+
const c = cands[i % cands.length];
|
|
185
|
+
process.stdout.write(`\r ${chalk.hex(GOLD)('⚡')} routing ${chalk.dim(data.workerType)} … ${chalk.cyan(candidateLabel(c))}\x1b[K`);
|
|
186
|
+
await sleep(50 + i * 8);
|
|
187
|
+
}
|
|
188
|
+
process.stdout.write('\r\x1b[K');
|
|
189
|
+
}
|
|
190
|
+
console.log(` ${chalk.hex(GOLD)('⚡')} ${chalk.bold('routing')} ${chalk.dim(data.workerType)} ${chalk.dim('· mode=' + data.mode)}`);
|
|
191
|
+
cands.forEach((c, idx) => {
|
|
192
|
+
const stats = `score=${c.score.toFixed(2)} bench=${c.benchmarkScore} ${c.providerType}`;
|
|
193
|
+
if (idx === 0) {
|
|
194
|
+
console.log(' ' + chalk.hex(GOLD).bold(`◆ ${candidateLabel(c)}`) + ' ' + chalk.hex(GOLD)(stats) + chalk.hex(GOLD)(' ◄ chosen'));
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
console.log(' ' + chalk.dim(`${candidateLabel(c)} ${stats}`));
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
export async function missionStatus(config, missionId) {
|
|
202
|
+
// Status reads from checkpoint storage
|
|
203
|
+
const kernel = buildKernelFromConfig(config);
|
|
204
|
+
const mission = kernel.getMission(missionId);
|
|
205
|
+
if (!mission) {
|
|
206
|
+
console.log(chalk.yellow(`Mission ${missionId} not found in this session.`));
|
|
207
|
+
console.log(chalk.dim(' (Missions live in-memory for Phase 1; checkpoints persist to .openkernel/checkpoints)'));
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
console.log(chalk.bold('\nMission Status'));
|
|
211
|
+
console.log(chalk.dim('-'.repeat(40)));
|
|
212
|
+
console.log(` ID: ${chalk.cyan(mission.id)}`);
|
|
213
|
+
console.log(` Name: ${mission.name}`);
|
|
214
|
+
console.log(` Status: ${formatMissionStatus(mission.status)}`);
|
|
215
|
+
console.log(` Goal: ${mission.goal}`);
|
|
216
|
+
console.log(` Tasks: ${mission.tasks.length}`);
|
|
217
|
+
console.log();
|
|
218
|
+
}
|
|
219
|
+
export async function missionList(config) {
|
|
220
|
+
const kernel = buildKernelFromConfig(config);
|
|
221
|
+
const missions = kernel.listMissions();
|
|
222
|
+
if (missions.length === 0) {
|
|
223
|
+
console.log(chalk.yellow('No missions in this session.'));
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
console.log(chalk.bold('\nMissions'));
|
|
227
|
+
console.log(chalk.dim('-'.repeat(60)));
|
|
228
|
+
for (const m of missions) {
|
|
229
|
+
console.log(` ${chalk.cyan(m.id)} ${formatMissionStatus(m.status)} ${m.name}`);
|
|
230
|
+
}
|
|
231
|
+
console.log();
|
|
232
|
+
}
|
|
233
|
+
export async function missionResume(config, missionId) {
|
|
234
|
+
const kernel = buildKernelFromConfig(config);
|
|
235
|
+
const mission = kernel.getMission(missionId);
|
|
236
|
+
if (!mission) {
|
|
237
|
+
console.log(chalk.yellow(`Mission ${missionId} not found in this session.`));
|
|
238
|
+
console.log(chalk.dim(' (Missions are in-memory; only checkpoints persist across restarts.)'));
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
if (mission.status !== 'PAUSED' && mission.status !== 'WAITING') {
|
|
242
|
+
console.log(chalk.yellow(`Mission ${missionId} is ${mission.status}; only PAUSED or WAITING missions can be resumed.`));
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
console.log(chalk.dim(`Resuming mission ${chalk.cyan(missionId)}...`));
|
|
246
|
+
try {
|
|
247
|
+
const resumed = await kernel.resume(missionId);
|
|
248
|
+
console.log(chalk.green(`✓ Mission resumed — status: ${formatMissionStatus(resumed.status)}`));
|
|
249
|
+
for (const task of resumed.tasks) {
|
|
250
|
+
console.log(chalk.dim(` ── Task ${task.id} ── ${formatTaskStatus(task.status)}`));
|
|
251
|
+
if (task.output?.content) {
|
|
252
|
+
const preview = task.output.content.slice(0, 300);
|
|
253
|
+
console.log(chalk.dim(` ${preview}${task.output.content.length > 300 ? '…' : ''}`));
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
catch (err) {
|
|
258
|
+
console.log(chalk.red(`Resume failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
259
|
+
}
|
|
260
|
+
finally {
|
|
261
|
+
kernel.destroy();
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
export async function missionCancel(config, missionId) {
|
|
265
|
+
const kernel = buildKernelFromConfig(config);
|
|
266
|
+
const mission = kernel.getMission(missionId);
|
|
267
|
+
if (!mission) {
|
|
268
|
+
console.log(chalk.yellow(`Mission ${missionId} not found in this session.`));
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
await kernel.cancel(missionId);
|
|
272
|
+
console.log(chalk.green(`✓ Mission ${missionId} cancelled — status: ${formatMissionStatus(kernel.getMission(missionId)?.status ?? 'CANCELLED')}`));
|
|
273
|
+
kernel.destroy();
|
|
274
|
+
}
|
|
275
|
+
function formatMissionStatus(s) {
|
|
276
|
+
const map = {
|
|
277
|
+
NEW: chalk.dim('NEW'),
|
|
278
|
+
PLANNING: chalk.yellow('PLANNING'),
|
|
279
|
+
READY: chalk.blue('READY'),
|
|
280
|
+
RUNNING: chalk.cyan('RUNNING'),
|
|
281
|
+
VERIFYING: chalk.magenta('VERIFYING'),
|
|
282
|
+
WAITING: chalk.yellow('WAITING'),
|
|
283
|
+
PAUSED: chalk.yellow('PAUSED'),
|
|
284
|
+
FAILED: chalk.red('FAILED'),
|
|
285
|
+
COMPLETED: chalk.green('COMPLETED'),
|
|
286
|
+
CANCELLED: chalk.red('CANCELLED'),
|
|
287
|
+
};
|
|
288
|
+
return map[s] ?? s;
|
|
289
|
+
}
|
|
290
|
+
function formatTaskStatus(s) {
|
|
291
|
+
const map = {
|
|
292
|
+
PENDING: chalk.dim('PENDING'),
|
|
293
|
+
QUEUED: chalk.blue('QUEUED'),
|
|
294
|
+
RUNNING: chalk.cyan('RUNNING'),
|
|
295
|
+
VERIFYING: chalk.magenta('VERIFYING'),
|
|
296
|
+
COMPLETED: chalk.green('COMPLETED'),
|
|
297
|
+
FAILED: chalk.red('FAILED'),
|
|
298
|
+
SKIPPED: chalk.yellow('SKIPPED'),
|
|
299
|
+
};
|
|
300
|
+
return map[s] ?? s;
|
|
301
|
+
}
|
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
import type Conf from 'conf';
|
|
2
|
-
|
|
2
|
+
import type { InfinicodeConfig } from '../kernel/config-schema.js';
|
|
3
|
+
export declare function listModels(config: Conf<InfinicodeConfig>): Promise<void>;
|
|
4
|
+
export declare function pullAllModels(config: Conf<InfinicodeConfig>): Promise<void>;
|
package/dist/commands/models.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import ora from 'ora';
|
|
3
|
+
import { buildKernelFromConfig } from '../kernel/setup.js';
|
|
3
4
|
function formatSize(bytes) {
|
|
4
5
|
const gb = bytes / (1024 ** 3);
|
|
5
6
|
if (gb >= 1)
|
|
@@ -7,70 +8,125 @@ function formatSize(bytes) {
|
|
|
7
8
|
const mb = bytes / (1024 ** 2);
|
|
8
9
|
return `${mb.toFixed(0)} MB`;
|
|
9
10
|
}
|
|
11
|
+
function partitionModels(models) {
|
|
12
|
+
const codingModels = [];
|
|
13
|
+
const otherModels = [];
|
|
14
|
+
for (const model of models) {
|
|
15
|
+
const name = model.id.toLowerCase();
|
|
16
|
+
if (name.includes('code') || name.includes('coder') || name.includes('stral')) {
|
|
17
|
+
codingModels.push(model);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
otherModels.push(model);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return { codingModels, otherModels };
|
|
24
|
+
}
|
|
10
25
|
export async function listModels(config) {
|
|
11
|
-
const masterUrl = config.get('masterUrl');
|
|
12
26
|
const defaultModel = config.get('defaultModel');
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
27
|
+
const kernel = buildKernelFromConfig(config);
|
|
28
|
+
const spinner = ora('Discovering models across all providers...').start();
|
|
29
|
+
// Give health checks a moment to populate
|
|
30
|
+
await new Promise(r => setTimeout(r, 1500));
|
|
31
|
+
let models = [];
|
|
17
32
|
try {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
codingModels.push(m);
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
otherModels.push(m);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
// Display coding models first
|
|
33
|
+
models = await kernel.providerManager.getAvailableModels();
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// continue with empty
|
|
37
|
+
}
|
|
38
|
+
if (models.length === 0) {
|
|
39
|
+
spinner.fail('No models available — no healthy providers.');
|
|
40
|
+
console.log(chalk.dim(' Check that Ollama is running or a cloud provider API key is set.'));
|
|
41
|
+
console.log(chalk.dim(' Run: infinicode providers test'));
|
|
42
|
+
kernel.destroy();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
spinner.succeed(`Found ${models.length} models across healthy providers`);
|
|
46
|
+
const byProvider = new Map();
|
|
47
|
+
for (const m of models) {
|
|
48
|
+
const list = byProvider.get(m.providerId) ?? [];
|
|
49
|
+
list.push(m);
|
|
50
|
+
byProvider.set(m.providerId, list);
|
|
51
|
+
}
|
|
52
|
+
console.log(chalk.bold('\nAvailable Models'));
|
|
53
|
+
console.log(chalk.dim('-'.repeat(60)));
|
|
54
|
+
for (const [providerId, providerModels] of byProvider) {
|
|
55
|
+
console.log(chalk.bold(`\n ${chalk.cyan(providerId)} (${providerModels.length})`));
|
|
56
|
+
const { codingModels, otherModels } = partitionModels(providerModels);
|
|
49
57
|
if (codingModels.length > 0) {
|
|
50
|
-
console.log(chalk.
|
|
51
|
-
for (const
|
|
52
|
-
const isDefault =
|
|
53
|
-
const marker = isDefault ? chalk.green('
|
|
54
|
-
const
|
|
55
|
-
|
|
58
|
+
console.log(chalk.dim(' Coding:'));
|
|
59
|
+
for (const model of codingModels.slice(0, 20)) {
|
|
60
|
+
const isDefault = model.id === defaultModel || model.id.startsWith(defaultModel.split(':')[0]);
|
|
61
|
+
const marker = isDefault ? chalk.green('*') : ' ';
|
|
62
|
+
const ctx = model.contextLength >= 1000 ? `${Math.round(model.contextLength / 1000)}k` : `${model.contextLength}`;
|
|
63
|
+
const sizeMeta = model.metadata?.size;
|
|
64
|
+
const sizeStr = sizeMeta ? ` ${chalk.dim(formatSize(sizeMeta))}` : '';
|
|
65
|
+
console.log(` ${marker} ${model.id.padEnd(42)} ${chalk.dim(`ctx=${ctx}`)}${sizeStr}`);
|
|
56
66
|
}
|
|
57
67
|
}
|
|
58
68
|
if (otherModels.length > 0) {
|
|
59
|
-
console.log(chalk.
|
|
60
|
-
for (const
|
|
61
|
-
const isDefault =
|
|
62
|
-
const marker = isDefault ? chalk.green('
|
|
63
|
-
const
|
|
64
|
-
|
|
69
|
+
console.log(chalk.dim(' Other:'));
|
|
70
|
+
for (const model of otherModels.slice(0, 10)) {
|
|
71
|
+
const isDefault = model.id === defaultModel;
|
|
72
|
+
const marker = isDefault ? chalk.green('*') : ' ';
|
|
73
|
+
const ctx = model.contextLength >= 1000 ? `${Math.round(model.contextLength / 1000)}k` : `${model.contextLength}`;
|
|
74
|
+
const sizeMeta = model.metadata?.size;
|
|
75
|
+
const sizeStr = sizeMeta ? ` ${chalk.dim(formatSize(sizeMeta))}` : '';
|
|
76
|
+
console.log(` ${marker} ${model.id.padEnd(42)} ${chalk.dim(`ctx=${ctx}`)}${sizeStr}`);
|
|
77
|
+
}
|
|
78
|
+
if (otherModels.length > 10) {
|
|
79
|
+
console.log(chalk.dim(` ... and ${otherModels.length - 10} more`));
|
|
65
80
|
}
|
|
66
81
|
}
|
|
67
|
-
console.log(chalk.dim(`\n Total: ${models.length} models`));
|
|
68
|
-
console.log(chalk.dim(` ★ = current default\n`));
|
|
69
82
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
83
|
+
console.log(chalk.dim(`\n Total: ${models.length} models from ${byProvider.size} provider(s)`));
|
|
84
|
+
console.log(chalk.dim(' * = current default\n'));
|
|
85
|
+
kernel.destroy();
|
|
86
|
+
}
|
|
87
|
+
export async function pullAllModels(config) {
|
|
88
|
+
const masterUrl = config.get('masterUrl');
|
|
89
|
+
const tailscaleMasterUrl = config.get('tailscaleMasterUrl');
|
|
90
|
+
const candidates = [
|
|
91
|
+
masterUrl,
|
|
92
|
+
...(tailscaleMasterUrl && tailscaleMasterUrl !== masterUrl ? [tailscaleMasterUrl] : []),
|
|
93
|
+
];
|
|
94
|
+
let models = [];
|
|
95
|
+
for (const candidate of candidates) {
|
|
96
|
+
try {
|
|
97
|
+
const response = await fetch(`${candidate}/api/tags`, {
|
|
98
|
+
signal: AbortSignal.timeout(10000),
|
|
99
|
+
});
|
|
100
|
+
if (!response.ok)
|
|
101
|
+
throw new Error(`HTTP ${response.status}`);
|
|
102
|
+
const data = (await response.json());
|
|
103
|
+
models = data.models ?? [];
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// try next
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (models.length === 0) {
|
|
111
|
+
console.log(chalk.red('\nCould not reach any configured Ollama master.'));
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
console.log(chalk.bold('\nPulling Models'));
|
|
115
|
+
console.log(chalk.dim('-'.repeat(50)));
|
|
116
|
+
console.log(chalk.dim(` Count: ${models.length}`));
|
|
117
|
+
console.log();
|
|
118
|
+
const { execa } = await import('execa');
|
|
119
|
+
const pulled = [];
|
|
120
|
+
for (const [index, model] of models.entries()) {
|
|
121
|
+
const spinner = ora(`[${index + 1}/${models.length}] Pulling ${model.name}...`).start();
|
|
122
|
+
try {
|
|
123
|
+
await execa('ollama', ['pull', model.name], { stdio: 'inherit' });
|
|
124
|
+
pulled.push(model.name);
|
|
125
|
+
spinner.succeed(`Pulled ${model.name}`);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
spinner.fail(`Failed to pull ${model.name}`);
|
|
129
|
+
}
|
|
75
130
|
}
|
|
131
|
+
console.log(chalk.green(`\nPulled ${pulled.length}/${models.length} models successfully.`));
|
|
76
132
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type Conf from 'conf';
|
|
2
|
+
import type { InfinicodeConfig } from '../kernel/config-schema.js';
|
|
3
|
+
export declare function providersList(config: Conf<InfinicodeConfig>): Promise<void>;
|
|
4
|
+
export declare function providersAdd(config: Conf<InfinicodeConfig>): Promise<void>;
|
|
5
|
+
export declare function providersRemove(config: Conf<InfinicodeConfig>, id: string): Promise<void>;
|
|
6
|
+
export declare function providersTest(config: Conf<InfinicodeConfig>, id?: string): Promise<void>;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* infinicode providers — view + edit cloud provider credentials.
|
|
3
|
+
*
|
|
4
|
+
* infinicode providers list configured providers
|
|
5
|
+
* infinicode providers add add a new cloud provider (interactive)
|
|
6
|
+
* infinicode providers remove <id> remove a provider
|
|
7
|
+
* infinicode providers test [id] test connection to one or all providers
|
|
8
|
+
*/
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
import inquirer from 'inquirer';
|
|
11
|
+
import { FREE_PROVIDERS, getProviderPreset, toCloudProviderConfig } from '../kernel/free-providers.js';
|
|
12
|
+
import { testOllamaProvider, testCloudProvider, testProviderInteractive } from '../kernel/provider-discovery.js';
|
|
13
|
+
export async function providersList(config) {
|
|
14
|
+
const cloud = config.get('cloudProviders') ?? [];
|
|
15
|
+
console.log(chalk.bold('\nConfigured Providers'));
|
|
16
|
+
console.log(chalk.dim('-'.repeat(60)));
|
|
17
|
+
// Ollama
|
|
18
|
+
const ollamaURL = config.get('masterUrl');
|
|
19
|
+
console.log(` ${chalk.cyan('ollama')} ${ollamaURL}`);
|
|
20
|
+
if (config.get('tailscaleMasterUrl')) {
|
|
21
|
+
console.log(chalk.dim(` tailscale fallback: ${config.get('tailscaleMasterUrl')}`));
|
|
22
|
+
}
|
|
23
|
+
if (cloud.length === 0) {
|
|
24
|
+
console.log(chalk.dim('\n No cloud providers configured.'));
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
console.log();
|
|
28
|
+
for (const p of cloud) {
|
|
29
|
+
const status = p.enabled ? chalk.green('✓') : chalk.yellow('○');
|
|
30
|
+
console.log(` ${status} ${chalk.cyan(p.id.padEnd(12))} ${p.name}`);
|
|
31
|
+
console.log(chalk.dim(` ${p.baseURL}`));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
console.log(chalk.dim(`\n Run ${chalk.cyan('infinicode providers add')} to add a cloud provider.`));
|
|
35
|
+
console.log(chalk.dim(` Run ${chalk.cyan('infinicode providers test')} to test connections.\n`));
|
|
36
|
+
}
|
|
37
|
+
export async function providersAdd(config) {
|
|
38
|
+
const existing = new Set((config.get('cloudProviders') ?? []).map(p => p.id));
|
|
39
|
+
const choices = FREE_PROVIDERS.map(p => ({
|
|
40
|
+
name: `${p.name} — ${p.notes ?? ''}${existing.has(p.id) ? chalk.dim(' (already configured)') : ''}`,
|
|
41
|
+
value: p.id,
|
|
42
|
+
short: p.name,
|
|
43
|
+
}));
|
|
44
|
+
const { presetId } = await inquirer.prompt([
|
|
45
|
+
{
|
|
46
|
+
type: 'list',
|
|
47
|
+
name: 'presetId',
|
|
48
|
+
message: 'Which cloud provider?',
|
|
49
|
+
choices,
|
|
50
|
+
pageSize: 10,
|
|
51
|
+
},
|
|
52
|
+
]);
|
|
53
|
+
const preset = getProviderPreset(presetId);
|
|
54
|
+
if (!preset)
|
|
55
|
+
return;
|
|
56
|
+
console.log(chalk.dim(`\n Get a free API key at: ${chalk.cyan(preset.keyUrl)}`));
|
|
57
|
+
const { apiKey } = await inquirer.prompt([
|
|
58
|
+
{
|
|
59
|
+
type: 'password',
|
|
60
|
+
name: 'apiKey',
|
|
61
|
+
message: `API key for ${preset.name}:`,
|
|
62
|
+
mask: '*',
|
|
63
|
+
},
|
|
64
|
+
]);
|
|
65
|
+
const cfg = toCloudProviderConfig(preset, apiKey);
|
|
66
|
+
const result = await testProviderInteractive(preset.name, () => testCloudProvider(cfg));
|
|
67
|
+
cfg.enabled = result.ok;
|
|
68
|
+
const cloud = config.get('cloudProviders') ?? [];
|
|
69
|
+
const filtered = cloud.filter(p => p.id !== presetId);
|
|
70
|
+
filtered.push(cfg);
|
|
71
|
+
config.set('cloudProviders', filtered);
|
|
72
|
+
console.log(chalk.green(`\n ✓ ${preset.name} ${result.ok ? 'added + enabled' : 'added (disabled — test failed, set API key later with `infinicode providers add`)'}.`));
|
|
73
|
+
}
|
|
74
|
+
export async function providersRemove(config, id) {
|
|
75
|
+
const cloud = config.get('cloudProviders') ?? [];
|
|
76
|
+
const next = cloud.filter(p => p.id !== id);
|
|
77
|
+
if (next.length === cloud.length) {
|
|
78
|
+
console.log(chalk.yellow(`No provider named "${id}" configured.`));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
config.set('cloudProviders', next);
|
|
82
|
+
console.log(chalk.green(`✓ Removed ${id}.`));
|
|
83
|
+
}
|
|
84
|
+
export async function providersTest(config, id) {
|
|
85
|
+
// Test Ollama
|
|
86
|
+
if (!id || id === 'ollama') {
|
|
87
|
+
await testProviderInteractive('Ollama', () => testOllamaProvider(config.get('masterUrl'), config.get('tailscaleMasterUrl')));
|
|
88
|
+
}
|
|
89
|
+
const cloud = config.get('cloudProviders') ?? [];
|
|
90
|
+
for (const p of cloud) {
|
|
91
|
+
if (id && id !== p.id)
|
|
92
|
+
continue;
|
|
93
|
+
await testProviderInteractive(p.name, () => testCloudProvider(p));
|
|
94
|
+
}
|
|
95
|
+
}
|
package/dist/commands/run.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import type Conf from 'conf';
|
|
2
|
-
|
|
2
|
+
import type { InfinicodeConfig } from '../kernel/config-schema.js';
|
|
3
|
+
export declare function runAgent(_masterUrl: string, _model: string, _useTui: boolean, config: Conf<InfinicodeConfig>): Promise<void>;
|