ai-runtime-engine 1.1.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/CHANGELOG.md +78 -0
- package/LICENSE +15 -0
- package/README.md +489 -0
- package/dist/artifacts/artifacts.d.ts +28 -0
- package/dist/artifacts/artifacts.js +46 -0
- package/dist/benchmark/benchmark.d.ts +23 -0
- package/dist/benchmark/benchmark.js +40 -0
- package/dist/cli/cli.d.ts +6 -0
- package/dist/cli/cli.js +161 -0
- package/dist/cli/commands/cleanup.d.ts +47 -0
- package/dist/cli/commands/cleanup.js +96 -0
- package/dist/cli/commands/config.d.ts +8 -0
- package/dist/cli/commands/config.js +28 -0
- package/dist/cli/commands/doctor.d.ts +57 -0
- package/dist/cli/commands/doctor.js +86 -0
- package/dist/cli/commands/executions.d.ts +9 -0
- package/dist/cli/commands/executions.js +25 -0
- package/dist/cli/commands/info.d.ts +43 -0
- package/dist/cli/commands/info.js +53 -0
- package/dist/cli/commands/init.d.ts +5 -0
- package/dist/cli/commands/init.js +75 -0
- package/dist/cli/commands/inspect.d.ts +16 -0
- package/dist/cli/commands/inspect.js +60 -0
- package/dist/cli/commands/phase2.d.ts +22 -0
- package/dist/cli/commands/phase2.js +83 -0
- package/dist/cli/commands/route.d.ts +14 -0
- package/dist/cli/commands/route.js +49 -0
- package/dist/cli/commands/run.d.ts +11 -0
- package/dist/cli/commands/run.js +37 -0
- package/dist/cli/commands/setup.d.ts +34 -0
- package/dist/cli/commands/setup.js +104 -0
- package/dist/cli/commands/skills.d.ts +28 -0
- package/dist/cli/commands/skills.js +48 -0
- package/dist/cli/commands/test.d.ts +7 -0
- package/dist/cli/commands/test.js +29 -0
- package/dist/cli/context.d.ts +12 -0
- package/dist/cli/context.js +16 -0
- package/dist/cli/interactive/repl.d.ts +6 -0
- package/dist/cli/interactive/repl.js +45 -0
- package/dist/cli/interactive/session.d.ts +36 -0
- package/dist/cli/interactive/session.js +356 -0
- package/dist/cli/prompt.d.ts +6 -0
- package/dist/cli/prompt.js +18 -0
- package/dist/cli/render.d.ts +7 -0
- package/dist/cli/render.js +14 -0
- package/dist/comparison/analysis.d.ts +46 -0
- package/dist/comparison/analysis.js +177 -0
- package/dist/comparison/comparator.d.ts +46 -0
- package/dist/comparison/comparator.js +270 -0
- package/dist/comparison/comparison.d.ts +140 -0
- package/dist/comparison/comparison.js +9 -0
- package/dist/comparison/render.d.ts +7 -0
- package/dist/comparison/render.js +66 -0
- package/dist/config/defaults.d.ts +52 -0
- package/dist/config/defaults.js +56 -0
- package/dist/config/load.d.ts +17 -0
- package/dist/config/load.js +50 -0
- package/dist/config/providerDefaults.d.ts +17 -0
- package/dist/config/providerDefaults.js +61 -0
- package/dist/config/schema.d.ts +9 -0
- package/dist/config/schema.js +78 -0
- package/dist/context/budget.d.ts +13 -0
- package/dist/context/budget.js +17 -0
- package/dist/context/compiler.d.ts +61 -0
- package/dist/context/compiler.js +125 -0
- package/dist/context/tokens.d.ts +19 -0
- package/dist/context/tokens.js +38 -0
- package/dist/conversations/conversations.d.ts +38 -0
- package/dist/conversations/conversations.js +64 -0
- package/dist/core/capabilities/evidence.d.ts +40 -0
- package/dist/core/capabilities/evidence.js +102 -0
- package/dist/core/capabilities/overlay.d.ts +15 -0
- package/dist/core/capabilities/overlay.js +0 -0
- package/dist/core/capabilities/taxonomy.d.ts +19 -0
- package/dist/core/capabilities/taxonomy.js +25 -0
- package/dist/core/fallback/errors.d.ts +30 -0
- package/dist/core/fallback/errors.js +80 -0
- package/dist/core/fallback/fallback.d.ts +40 -0
- package/dist/core/fallback/fallback.js +82 -0
- package/dist/core/fallback/retryPolicy.d.ts +11 -0
- package/dist/core/fallback/retryPolicy.js +14 -0
- package/dist/core/health/health.d.ts +3 -0
- package/dist/core/health/health.js +5 -0
- package/dist/core/health/monitor.d.ts +23 -0
- package/dist/core/health/monitor.js +82 -0
- package/dist/core/policies/budget.d.ts +19 -0
- package/dist/core/policies/budget.js +37 -0
- package/dist/core/registry/builtinTasks.d.ts +8 -0
- package/dist/core/registry/builtinTasks.js +54 -0
- package/dist/core/registry/registry.d.ts +18 -0
- package/dist/core/registry/registry.js +33 -0
- package/dist/core/registry/taskRegistry.d.ts +15 -0
- package/dist/core/registry/taskRegistry.js +30 -0
- package/dist/core/router/confidence.d.ts +7 -0
- package/dist/core/router/confidence.js +20 -0
- package/dist/core/router/dimensions.d.ts +16 -0
- package/dist/core/router/dimensions.js +60 -0
- package/dist/core/router/executor.d.ts +16 -0
- package/dist/core/router/executor.js +25 -0
- package/dist/core/router/filter.d.ts +34 -0
- package/dist/core/router/filter.js +113 -0
- package/dist/core/router/normalize.d.ts +30 -0
- package/dist/core/router/normalize.js +119 -0
- package/dist/core/router/request.d.ts +4 -0
- package/dist/core/router/request.js +21 -0
- package/dist/core/router/router.d.ts +32 -0
- package/dist/core/router/router.js +195 -0
- package/dist/core/router/routingPrefs.d.ts +11 -0
- package/dist/core/router/routingPrefs.js +30 -0
- package/dist/core/router/scorer.d.ts +19 -0
- package/dist/core/router/scorer.js +50 -0
- package/dist/core/router/weights.d.ts +9 -0
- package/dist/core/router/weights.js +31 -0
- package/dist/core/validation/validator.d.ts +16 -0
- package/dist/core/validation/validator.js +33 -0
- package/dist/discovery/modelCatalog.d.ts +28 -0
- package/dist/discovery/modelCatalog.js +105 -0
- package/dist/discovery/openapi.d.ts +25 -0
- package/dist/discovery/openapi.js +76 -0
- package/dist/executions/checkpoint.d.ts +26 -0
- package/dist/executions/checkpoint.js +114 -0
- package/dist/executions/execution.d.ts +51 -0
- package/dist/executions/execution.js +8 -0
- package/dist/executions/store.d.ts +52 -0
- package/dist/executions/store.js +124 -0
- package/dist/generation/generateAdapter.d.ts +17 -0
- package/dist/generation/generateAdapter.js +30 -0
- package/dist/index.d.ts +147 -0
- package/dist/index.js +107 -0
- package/dist/learning/feedback.d.ts +9 -0
- package/dist/learning/feedback.js +18 -0
- package/dist/learning/learningStore.d.ts +68 -0
- package/dist/learning/learningStore.js +138 -0
- package/dist/learning/performanceStore.d.ts +27 -0
- package/dist/learning/performanceStore.js +0 -0
- package/dist/marketplace/presets.d.ts +24 -0
- package/dist/marketplace/presets.js +52 -0
- package/dist/mcp/mcp.d.ts +31 -0
- package/dist/mcp/mcp.js +54 -0
- package/dist/memory/bm25.d.ts +16 -0
- package/dist/memory/bm25.js +56 -0
- package/dist/memory/classifier.d.ts +14 -0
- package/dist/memory/classifier.js +17 -0
- package/dist/memory/memory.d.ts +80 -0
- package/dist/memory/memory.js +191 -0
- package/dist/orchestration/executor.d.ts +35 -0
- package/dist/orchestration/executor.js +65 -0
- package/dist/orchestration/orchestrator.d.ts +42 -0
- package/dist/orchestration/orchestrator.js +63 -0
- package/dist/orchestration/plan.d.ts +37 -0
- package/dist/orchestration/plan.js +70 -0
- package/dist/orchestration/planner.d.ts +29 -0
- package/dist/orchestration/planner.js +69 -0
- package/dist/plugin/ai.d.ts +82 -0
- package/dist/plugin/ai.js +167 -0
- package/dist/probing/probe.d.ts +25 -0
- package/dist/probing/probe.js +63 -0
- package/dist/providers/factory.d.ts +18 -0
- package/dist/providers/factory.js +54 -0
- package/dist/providers/httpClient.d.ts +34 -0
- package/dist/providers/httpClient.js +80 -0
- package/dist/providers/httpProvider.d.ts +49 -0
- package/dist/providers/httpProvider.js +135 -0
- package/dist/providers/mock/demo.d.ts +13 -0
- package/dist/providers/mock/demo.js +58 -0
- package/dist/providers/mock/mockProvider.d.ts +35 -0
- package/dist/providers/mock/mockProvider.js +121 -0
- package/dist/providers/mock/scenarios.d.ts +44 -0
- package/dist/providers/mock/scenarios.js +30 -0
- package/dist/providers/provider.d.ts +26 -0
- package/dist/providers/provider.js +11 -0
- package/dist/providers/wire/anthropicWire.d.ts +6 -0
- package/dist/providers/wire/anthropicWire.js +83 -0
- package/dist/providers/wire/openaiWire.d.ts +7 -0
- package/dist/providers/wire/openaiWire.js +81 -0
- package/dist/providers/wire/registry.d.ts +8 -0
- package/dist/providers/wire/registry.js +20 -0
- package/dist/providers/wire/types.d.ts +39 -0
- package/dist/providers/wire/types.js +24 -0
- package/dist/runtime/config.d.ts +31 -0
- package/dist/runtime/config.js +121 -0
- package/dist/runtime/context.d.ts +34 -0
- package/dist/runtime/context.js +11 -0
- package/dist/runtime/events.d.ts +99 -0
- package/dist/runtime/events.js +82 -0
- package/dist/runtime/host.d.ts +27 -0
- package/dist/runtime/host.js +7 -0
- package/dist/runtime/intent/classifier.d.ts +30 -0
- package/dist/runtime/intent/classifier.js +60 -0
- package/dist/runtime/intent/signals.d.ts +19 -0
- package/dist/runtime/intent/signals.js +46 -0
- package/dist/runtime/modes/availability.d.ts +11 -0
- package/dist/runtime/modes/availability.js +17 -0
- package/dist/runtime/modes/chat.d.ts +18 -0
- package/dist/runtime/modes/chat.js +67 -0
- package/dist/runtime/modes/modeResolver.d.ts +43 -0
- package/dist/runtime/modes/modeResolver.js +78 -0
- package/dist/runtime/policy.d.ts +72 -0
- package/dist/runtime/policy.js +59 -0
- package/dist/runtime/providerView.d.ts +62 -0
- package/dist/runtime/providerView.js +105 -0
- package/dist/runtime/routing.d.ts +26 -0
- package/dist/runtime/routing.js +65 -0
- package/dist/runtime/runtime.d.ts +191 -0
- package/dist/runtime/runtime.js +718 -0
- package/dist/runtime/types.d.ts +153 -0
- package/dist/runtime/types.js +9 -0
- package/dist/runtime/workspace/detectors.d.ts +15 -0
- package/dist/runtime/workspace/detectors.js +57 -0
- package/dist/runtime/workspace/workspace.d.ts +29 -0
- package/dist/runtime/workspace/workspace.js +116 -0
- package/dist/security/credentials.d.ts +26 -0
- package/dist/security/credentials.js +34 -0
- package/dist/security/redact.d.ts +16 -0
- package/dist/security/redact.js +57 -0
- package/dist/skills/builtins/fileAnalyzer.d.ts +7 -0
- package/dist/skills/builtins/fileAnalyzer.js +47 -0
- package/dist/skills/builtins/repositoryAnalyzer.d.ts +6 -0
- package/dist/skills/builtins/repositoryAnalyzer.js +47 -0
- package/dist/skills/discovery.d.ts +61 -0
- package/dist/skills/discovery.js +211 -0
- package/dist/skills/manifest.d.ts +30 -0
- package/dist/skills/manifest.js +75 -0
- package/dist/skills/registry.d.ts +15 -0
- package/dist/skills/registry.js +22 -0
- package/dist/skills/skill.d.ts +64 -0
- package/dist/skills/skill.js +8 -0
- package/dist/store/area.d.ts +54 -0
- package/dist/store/area.js +164 -0
- package/dist/store/paths.d.ts +15 -0
- package/dist/store/paths.js +48 -0
- package/dist/store/store.d.ts +59 -0
- package/dist/store/store.js +140 -0
- package/dist/telemetry/sinks/file.d.ts +12 -0
- package/dist/telemetry/sinks/file.js +28 -0
- package/dist/telemetry/telemetry.d.ts +36 -0
- package/dist/telemetry/telemetry.js +63 -0
- package/dist/tools/builtins/filesystem.d.ts +7 -0
- package/dist/tools/builtins/filesystem.js +53 -0
- package/dist/tools/builtins/git.d.ts +10 -0
- package/dist/tools/builtins/git.js +66 -0
- package/dist/tools/builtins/shell.d.ts +17 -0
- package/dist/tools/builtins/shell.js +91 -0
- package/dist/tools/jail.d.ts +12 -0
- package/dist/tools/jail.js +98 -0
- package/dist/tools/permissions.d.ts +25 -0
- package/dist/tools/permissions.js +24 -0
- package/dist/tools/registry.d.ts +10 -0
- package/dist/tools/registry.js +20 -0
- package/dist/tools/runner.d.ts +23 -0
- package/dist/tools/runner.js +64 -0
- package/dist/tools/tool.d.ts +53 -0
- package/dist/tools/tool.js +24 -0
- package/dist/tools/untrusted.d.ts +13 -0
- package/dist/tools/untrusted.js +30 -0
- package/dist/types.d.ts +460 -0
- package/dist/types.js +12 -0
- package/dist/util/clock.d.ts +6 -0
- package/dist/util/clock.js +4 -0
- package/dist/util/extractJson.d.ts +8 -0
- package/dist/util/extractJson.js +54 -0
- package/dist/verification/verify.d.ts +26 -0
- package/dist/verification/verify.js +67 -0
- package/docs/GUIDE.md +358 -0
- package/docs/README.md +21 -0
- package/docs/architecture.md +78 -0
- package/docs/router.md +376 -0
- package/docs/security.md +55 -0
- package/package.json +67 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Benchmarking. Runs representative tasks against each configured provider and reports
|
|
3
|
+
* success rate, latency, and a cost indicator so a user can compare providers on THEIR tasks. It pins
|
|
4
|
+
* each provider in turn (bypassing selection) so the comparison is apples-to-apples. Makes real calls
|
|
5
|
+
* when keys are present; against MockProvider it is fully offline.
|
|
6
|
+
*/
|
|
7
|
+
import type { AI } from '../plugin/ai.js';
|
|
8
|
+
export interface BenchTaskSpec {
|
|
9
|
+
task: string;
|
|
10
|
+
input: string;
|
|
11
|
+
}
|
|
12
|
+
export interface BenchResult {
|
|
13
|
+
providerId: string;
|
|
14
|
+
model?: string;
|
|
15
|
+
runs: number;
|
|
16
|
+
successRate: number;
|
|
17
|
+
avgLatencyMs: number;
|
|
18
|
+
failures: number;
|
|
19
|
+
}
|
|
20
|
+
export interface BenchmarkOptions {
|
|
21
|
+
samples?: number;
|
|
22
|
+
}
|
|
23
|
+
export declare function benchmark(ai: AI, tasks: BenchTaskSpec[], options?: BenchmarkOptions): Promise<BenchResult[]>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Benchmarking. Runs representative tasks against each configured provider and reports
|
|
3
|
+
* success rate, latency, and a cost indicator so a user can compare providers on THEIR tasks. It pins
|
|
4
|
+
* each provider in turn (bypassing selection) so the comparison is apples-to-apples. Makes real calls
|
|
5
|
+
* when keys are present; against MockProvider it is fully offline.
|
|
6
|
+
*/
|
|
7
|
+
export async function benchmark(ai, tasks, options = {}) {
|
|
8
|
+
const samples = Math.max(1, options.samples ?? 3);
|
|
9
|
+
const results = [];
|
|
10
|
+
for (const provider of ai.providers()) {
|
|
11
|
+
if (!provider.enabled)
|
|
12
|
+
continue;
|
|
13
|
+
let ok = 0;
|
|
14
|
+
let runs = 0;
|
|
15
|
+
let latencyTotal = 0;
|
|
16
|
+
let lastModel;
|
|
17
|
+
for (const spec of tasks) {
|
|
18
|
+
for (let i = 0; i < samples; i += 1) {
|
|
19
|
+
runs += 1;
|
|
20
|
+
const result = await ai.run({ task: spec.task, input: spec.input, provider: provider.id });
|
|
21
|
+
if (result.ok) {
|
|
22
|
+
ok += 1;
|
|
23
|
+
const last = result.routing.attempts[result.routing.attempts.length - 1];
|
|
24
|
+
latencyTotal += last?.latencyMs ?? 0;
|
|
25
|
+
lastModel = result.routing.selected?.model ?? lastModel;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
results.push({
|
|
30
|
+
providerId: provider.id,
|
|
31
|
+
...(lastModel ? { model: lastModel } : {}),
|
|
32
|
+
runs,
|
|
33
|
+
successRate: runs > 0 ? ok / runs : 0,
|
|
34
|
+
avgLatencyMs: ok > 0 ? latencyTotal / ok : 0,
|
|
35
|
+
failures: runs - ok,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
results.sort((a, b) => b.successRate - a.successRate || a.avgLatencyMs - b.avgLatencyMs);
|
|
39
|
+
return results;
|
|
40
|
+
}
|
package/dist/cli/cli.js
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ai-runtime CLI. Bare `ai-runtime` opens the interactive terminal.
|
|
4
|
+
* run <input> | init | providers | models | capabilities | doctor | test | route | config | …
|
|
5
|
+
*/
|
|
6
|
+
import { Command } from 'commander';
|
|
7
|
+
import { routeCommand } from './commands/route.js';
|
|
8
|
+
import { configCommand } from './commands/config.js';
|
|
9
|
+
import { doctorCommand } from './commands/doctor.js';
|
|
10
|
+
import { providersCommand, modelsCommand, capabilitiesCommand } from './commands/inspect.js';
|
|
11
|
+
import { testCommand } from './commands/test.js';
|
|
12
|
+
import { initCommand } from './commands/init.js';
|
|
13
|
+
import { probeCommand, discoverCommand, benchmarkCommand, telemetryCommand, presetsCommand } from './commands/phase2.js';
|
|
14
|
+
import { runCommand } from './commands/run.js';
|
|
15
|
+
import { executionsCommand, resumeExecutionCommand } from './commands/executions.js';
|
|
16
|
+
import { setupCommand } from './commands/setup.js';
|
|
17
|
+
import { infoCommand } from './commands/info.js';
|
|
18
|
+
import { cleanupCommand } from './commands/cleanup.js';
|
|
19
|
+
import { skillsCommand } from './commands/skills.js';
|
|
20
|
+
import { startRepl } from './interactive/repl.js';
|
|
21
|
+
import { printError } from './render.js';
|
|
22
|
+
const program = new Command();
|
|
23
|
+
program.name('ai-runtime').description('Universal, provider-agnostic AI Runtime & Orchestration Platform').version('1.1.0');
|
|
24
|
+
const configOpt = ['-c, --config <path>', 'path to an ai-runtime config file'];
|
|
25
|
+
// Bare `ai-runtime` (no subcommand) opens the interactive terminal. `allowExcessArguments(false)` keeps
|
|
26
|
+
// a mistyped subcommand (e.g. `ai-runtime porviders`) failing fast instead of silently opening the REPL.
|
|
27
|
+
program.allowExcessArguments(false).action(async () => {
|
|
28
|
+
await startRepl();
|
|
29
|
+
});
|
|
30
|
+
program
|
|
31
|
+
.command('run')
|
|
32
|
+
.argument('<input>', 'natural-language request')
|
|
33
|
+
.description('Run one request through the runtime (one-shot; shares the interactive Runtime)')
|
|
34
|
+
.option('-m, --mode <mode>', 'force a mode (auto|chat|plan|execute|orchestrate|agent|compare|debug)')
|
|
35
|
+
.option(...configOpt)
|
|
36
|
+
.option('--json', 'print the full RuntimeResult as JSON')
|
|
37
|
+
.option('--dry-run', 'plan and report what would happen without making any changes')
|
|
38
|
+
.action((input, o) => runCommand(input, o));
|
|
39
|
+
program
|
|
40
|
+
.command('executions')
|
|
41
|
+
.description('List persisted executions')
|
|
42
|
+
.option(...configOpt)
|
|
43
|
+
.option('--json', 'print as JSON')
|
|
44
|
+
.action((o) => executionsCommand(o));
|
|
45
|
+
program
|
|
46
|
+
.command('resume-execution')
|
|
47
|
+
.argument('<id>', 'execution id')
|
|
48
|
+
.description('Resume a persisted execution (reconciles the workspace first)')
|
|
49
|
+
.option(...configOpt)
|
|
50
|
+
.option('--answer <text>', 'answer a pending clarification')
|
|
51
|
+
.action((id, o) => resumeExecutionCommand(id, o));
|
|
52
|
+
program.command('init').description('Scaffold ai-runtime.yaml, .env.example, and .gitignore entries').action(() => initCommand());
|
|
53
|
+
program
|
|
54
|
+
.command('setup')
|
|
55
|
+
.description('Guided bootstrap: detect workspace + provider keys, generate config (asks before each write)')
|
|
56
|
+
.option('-y, --yes', 'accept every write without prompting')
|
|
57
|
+
.action((o) => setupCommand(o));
|
|
58
|
+
program
|
|
59
|
+
.command('skills')
|
|
60
|
+
.description('List available skills; --discover scans the workspace for more (reported, not loaded)')
|
|
61
|
+
.option(...configOpt)
|
|
62
|
+
.option('--discover', 'scan the workspace for skill files elsewhere and report them')
|
|
63
|
+
.option('--json', 'print as JSON')
|
|
64
|
+
.action((o) => skillsCommand(o));
|
|
65
|
+
program
|
|
66
|
+
.command('info')
|
|
67
|
+
.description('Summarize the runtime: workspace, providers, skills, tools, memory, learning, storage')
|
|
68
|
+
.option(...configOpt)
|
|
69
|
+
.option('--json', 'print as JSON')
|
|
70
|
+
.action((o) => infoCommand(o));
|
|
71
|
+
program
|
|
72
|
+
.command('cleanup')
|
|
73
|
+
.description('Enforce retention, drop the cache, and validate the store (confirms before deleting)')
|
|
74
|
+
.option(...configOpt)
|
|
75
|
+
.option('--dry-run', 'report what would be removed without removing anything')
|
|
76
|
+
.option('-y, --yes', 'remove without prompting')
|
|
77
|
+
.option('--json', 'print the cleanup plan as JSON')
|
|
78
|
+
.action((o) => cleanupCommand(o));
|
|
79
|
+
program
|
|
80
|
+
.command('providers')
|
|
81
|
+
.description('List configured providers and their health')
|
|
82
|
+
.option(...configOpt)
|
|
83
|
+
.option('--json', 'print as JSON')
|
|
84
|
+
.action((o) => providersCommand(o));
|
|
85
|
+
program
|
|
86
|
+
.command('models')
|
|
87
|
+
.description('List known models across providers')
|
|
88
|
+
.option(...configOpt)
|
|
89
|
+
.option('--json', 'print as JSON')
|
|
90
|
+
.action((o) => modelsCommand(o));
|
|
91
|
+
program
|
|
92
|
+
.command('capabilities')
|
|
93
|
+
.description('Show the capability matrix by model')
|
|
94
|
+
.option(...configOpt)
|
|
95
|
+
.option('--json', 'print as JSON')
|
|
96
|
+
.action((o) => capabilitiesCommand(o));
|
|
97
|
+
program
|
|
98
|
+
.command('doctor')
|
|
99
|
+
.description('Diagnose the runtime: config, .env, providers, models, store, skills, tools, permissions, git')
|
|
100
|
+
.option(...configOpt)
|
|
101
|
+
.option('--json', 'print the full report as JSON')
|
|
102
|
+
.action((o) => doctorCommand(o));
|
|
103
|
+
program
|
|
104
|
+
.command('test')
|
|
105
|
+
.argument('<provider>', 'provider id to test with one live call')
|
|
106
|
+
.description('Make a minimal live call to a provider (skipped if no key)')
|
|
107
|
+
.option(...configOpt)
|
|
108
|
+
.action((provider, o) => testCommand(provider, o));
|
|
109
|
+
program
|
|
110
|
+
.command('route')
|
|
111
|
+
.argument('<task>', 'task name, e.g. generate-playwright-tests')
|
|
112
|
+
.description('Route a task through the router')
|
|
113
|
+
.option('-i, --input <text>', 'input text for the task')
|
|
114
|
+
.option('-s, --strategy <strategy>', 'routing strategy (best|fastest|cheapest|highest-quality|...)')
|
|
115
|
+
.option('-p, --provider <id>', 'pin a provider')
|
|
116
|
+
.option('-m, --model <id>', 'pin a model')
|
|
117
|
+
.option(...configOpt)
|
|
118
|
+
.option('--json', 'print the full RunResult as JSON')
|
|
119
|
+
.action((task, o) => routeCommand(task, o));
|
|
120
|
+
program
|
|
121
|
+
.command('config')
|
|
122
|
+
.description('Print the resolved configuration')
|
|
123
|
+
.option(...configOpt)
|
|
124
|
+
.option('--json', 'print as JSON')
|
|
125
|
+
.action((o) => configCommand(o));
|
|
126
|
+
// ── Learning, discovery & benchmarking ──
|
|
127
|
+
program
|
|
128
|
+
.command('probe')
|
|
129
|
+
.argument('<provider>', 'provider id')
|
|
130
|
+
.argument('<model>', 'model id')
|
|
131
|
+
.description('Verify a model\'s capabilities with minimal live probes (opt-in, costs tokens)')
|
|
132
|
+
.option(...configOpt)
|
|
133
|
+
.action((provider, model, o) => probeCommand(provider, model, o));
|
|
134
|
+
program
|
|
135
|
+
.command('discover')
|
|
136
|
+
.argument('<spec>', 'path to an OpenAPI 3.x spec (yaml/json)')
|
|
137
|
+
.description('Analyze an OpenAPI spec and suggest a provider config')
|
|
138
|
+
.option('--json', 'print as JSON')
|
|
139
|
+
.action((spec, o) => discoverCommand(spec, o));
|
|
140
|
+
program
|
|
141
|
+
.command('benchmark')
|
|
142
|
+
.description('Compare configured providers on representative tasks')
|
|
143
|
+
.option(...configOpt)
|
|
144
|
+
.option('-n, --samples <n>', 'samples per task per provider', '3')
|
|
145
|
+
.option('--json', 'print as JSON')
|
|
146
|
+
.action((o) => benchmarkCommand(o));
|
|
147
|
+
program
|
|
148
|
+
.command('telemetry')
|
|
149
|
+
.description('Print recent routing telemetry events (metadata only)')
|
|
150
|
+
.option(...configOpt)
|
|
151
|
+
.option('-n, --limit <n>', 'number of recent events', '20')
|
|
152
|
+
.action((o) => telemetryCommand(o));
|
|
153
|
+
program
|
|
154
|
+
.command('presets')
|
|
155
|
+
.description('List provider marketplace presets you can add')
|
|
156
|
+
.option('--json', 'print as JSON')
|
|
157
|
+
.action((o) => presetsCommand(o));
|
|
158
|
+
program.parseAsync(process.argv).catch((err) => {
|
|
159
|
+
printError(`ai-runtime error: ${err instanceof Error ? err.message : String(err)}`);
|
|
160
|
+
process.exitCode = 1;
|
|
161
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ai-runtime cleanup` — enforce retention, drop the disposable cache, and validate the local store.
|
|
3
|
+
* Retention is OPT-IN via `AI_CONVERSATION/EXECUTION/ARTIFACT_RETENTION_DAYS` (unset = keep everything).
|
|
4
|
+
* Nothing is deleted without confirmation unless `--yes`; `--dry-run` only reports the plan. Integrity
|
|
5
|
+
* issues are reported, never auto-"repaired" destructively.
|
|
6
|
+
*/
|
|
7
|
+
import { Runtime } from '../../runtime/runtime.js';
|
|
8
|
+
import type { IntegrityIssue } from '../../store/area.js';
|
|
9
|
+
export interface CleanupPlan {
|
|
10
|
+
retention: {
|
|
11
|
+
conversationDays?: number;
|
|
12
|
+
executionDays?: number;
|
|
13
|
+
artifactDays?: number;
|
|
14
|
+
};
|
|
15
|
+
conversations: {
|
|
16
|
+
total: number;
|
|
17
|
+
expired: string[];
|
|
18
|
+
};
|
|
19
|
+
executions: {
|
|
20
|
+
total: number;
|
|
21
|
+
expired: string[];
|
|
22
|
+
};
|
|
23
|
+
artifacts: {
|
|
24
|
+
total: number;
|
|
25
|
+
expired: string[];
|
|
26
|
+
};
|
|
27
|
+
cache: {
|
|
28
|
+
entries: number;
|
|
29
|
+
};
|
|
30
|
+
integrity: IntegrityIssue[];
|
|
31
|
+
}
|
|
32
|
+
/** Compute what cleanup WOULD remove, given the current time. Pure aside from reading the store. */
|
|
33
|
+
export declare function planCleanup(rt: Runtime, now: number, env?: NodeJS.ProcessEnv): CleanupPlan;
|
|
34
|
+
export interface CleanupResult {
|
|
35
|
+
conversations: number;
|
|
36
|
+
executions: number;
|
|
37
|
+
artifacts: number;
|
|
38
|
+
cache: number;
|
|
39
|
+
}
|
|
40
|
+
/** Apply a cleanup plan: delete expired records and clear the cache. Returns the counts actually removed. */
|
|
41
|
+
export declare function applyCleanup(rt: Runtime, plan: CleanupPlan): CleanupResult;
|
|
42
|
+
export declare function cleanupCommand(opts: {
|
|
43
|
+
config?: string;
|
|
44
|
+
dryRun?: boolean;
|
|
45
|
+
yes?: boolean;
|
|
46
|
+
json?: boolean;
|
|
47
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ai-runtime cleanup` — enforce retention, drop the disposable cache, and validate the local store.
|
|
3
|
+
* Retention is OPT-IN via `AI_CONVERSATION/EXECUTION/ARTIFACT_RETENTION_DAYS` (unset = keep everything).
|
|
4
|
+
* Nothing is deleted without confirmation unless `--yes`; `--dry-run` only reports the plan. Integrity
|
|
5
|
+
* issues are reported, never auto-"repaired" destructively.
|
|
6
|
+
*/
|
|
7
|
+
import { Runtime } from '../../runtime/runtime.js';
|
|
8
|
+
import { TERMINAL } from '../../executions/execution.js';
|
|
9
|
+
import { confirm } from '../prompt.js';
|
|
10
|
+
import { print } from '../render.js';
|
|
11
|
+
const DAY_MS = 86_400_000;
|
|
12
|
+
function numEnv(v) {
|
|
13
|
+
if (v === undefined || v === '')
|
|
14
|
+
return undefined;
|
|
15
|
+
const n = Number(v);
|
|
16
|
+
return Number.isFinite(n) && n >= 0 ? n : undefined;
|
|
17
|
+
}
|
|
18
|
+
/** Parse the creation time base36-encoded in an artifact id ("art_<time36>_<counter>"). */
|
|
19
|
+
function artifactTime(id) {
|
|
20
|
+
const part = id.split('_')[1];
|
|
21
|
+
if (!part)
|
|
22
|
+
return undefined;
|
|
23
|
+
const t = parseInt(part, 36);
|
|
24
|
+
return Number.isFinite(t) ? t : undefined;
|
|
25
|
+
}
|
|
26
|
+
/** Compute what cleanup WOULD remove, given the current time. Pure aside from reading the store. */
|
|
27
|
+
export function planCleanup(rt, now, env = process.env) {
|
|
28
|
+
const convDays = numEnv(env.AI_CONVERSATION_RETENTION_DAYS);
|
|
29
|
+
const execDays = numEnv(env.AI_EXECUTION_RETENTION_DAYS);
|
|
30
|
+
const artDays = numEnv(env.AI_ARTIFACT_RETENTION_DAYS);
|
|
31
|
+
const convs = rt.conversations.enabled ? rt.conversations.list() : [];
|
|
32
|
+
const expiredConvs = convDays !== undefined ? convs.filter((c) => now - c.updatedAt > convDays * DAY_MS).map((c) => c.id) : [];
|
|
33
|
+
const execs = rt.executionStore.enabled ? rt.executions() : [];
|
|
34
|
+
// Only TERMINAL executions are eligible for retention deletion — never a live/waiting one.
|
|
35
|
+
const expiredExecs = execDays !== undefined ? execs.filter((e) => TERMINAL.has(e.status) && now - e.updatedAt > execDays * DAY_MS).map((e) => e.id) : [];
|
|
36
|
+
const artifacts = rt.artifacts.enabled ? rt.artifacts.list() : [];
|
|
37
|
+
const expiredArtifacts = artDays !== undefined ? artifacts.filter((id) => { const t = artifactTime(id); return t !== undefined && now - t > artDays * DAY_MS; }) : [];
|
|
38
|
+
return {
|
|
39
|
+
retention: { ...(convDays !== undefined ? { conversationDays: convDays } : {}), ...(execDays !== undefined ? { executionDays: execDays } : {}), ...(artDays !== undefined ? { artifactDays: artDays } : {}) },
|
|
40
|
+
conversations: { total: convs.length, expired: expiredConvs },
|
|
41
|
+
executions: { total: execs.length, expired: expiredExecs },
|
|
42
|
+
artifacts: { total: artifacts.length, expired: expiredArtifacts },
|
|
43
|
+
cache: { entries: rt.store.cache().listIds().length },
|
|
44
|
+
integrity: rt.store.check(),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** Apply a cleanup plan: delete expired records and clear the cache. Returns the counts actually removed. */
|
|
48
|
+
export function applyCleanup(rt, plan) {
|
|
49
|
+
for (const id of plan.conversations.expired)
|
|
50
|
+
rt.conversations.delete(id);
|
|
51
|
+
for (const id of plan.executions.expired)
|
|
52
|
+
rt.store.executions().remove(id);
|
|
53
|
+
for (const id of plan.artifacts.expired)
|
|
54
|
+
rt.artifacts.delete(id);
|
|
55
|
+
const cacheIds = rt.store.cache().listIds();
|
|
56
|
+
for (const id of cacheIds)
|
|
57
|
+
rt.store.cache().remove(id);
|
|
58
|
+
return { conversations: plan.conversations.expired.length, executions: plan.executions.expired.length, artifacts: plan.artifacts.expired.length, cache: cacheIds.length };
|
|
59
|
+
}
|
|
60
|
+
function toRemove(plan) {
|
|
61
|
+
return plan.conversations.expired.length + plan.executions.expired.length + plan.artifacts.expired.length + plan.cache.entries;
|
|
62
|
+
}
|
|
63
|
+
function renderPlan(plan) {
|
|
64
|
+
const lines = ['ai-runtime cleanup', ''];
|
|
65
|
+
const ret = plan.retention;
|
|
66
|
+
lines.push(`conversations: ${plan.conversations.expired.length} expired of ${plan.conversations.total}${ret.conversationDays === undefined ? ' (retention off)' : ` (> ${ret.conversationDays}d)`}`, `executions: ${plan.executions.expired.length} expired of ${plan.executions.total}${ret.executionDays === undefined ? ' (retention off)' : ` (terminal, > ${ret.executionDays}d)`}`, `artifacts: ${plan.artifacts.expired.length} expired of ${plan.artifacts.total}${ret.artifactDays === undefined ? ' (retention off)' : ` (> ${ret.artifactDays}d)`}`, `cache: ${plan.cache.entries} entr${plan.cache.entries === 1 ? 'y' : 'ies'} to drop (disposable)`, `integrity: ${plan.integrity.length ? `${plan.integrity.length} issue(s) — ${plan.integrity.map((i) => `${i.file} (${i.problem})`).join(', ')}` : 'ok'}`);
|
|
67
|
+
return lines;
|
|
68
|
+
}
|
|
69
|
+
export async function cleanupCommand(opts) {
|
|
70
|
+
const rt = await Runtime.load({ ...(opts.config ? { config: opts.config } : {}) });
|
|
71
|
+
if (!rt.store.enabled) {
|
|
72
|
+
print('storage is disabled (stateless mode) — nothing to clean.');
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const plan = planCleanup(rt, Date.now());
|
|
76
|
+
if (opts.json)
|
|
77
|
+
return print(JSON.stringify(plan, null, 2));
|
|
78
|
+
for (const line of renderPlan(plan))
|
|
79
|
+
print(line);
|
|
80
|
+
const removable = toRemove(plan);
|
|
81
|
+
if (removable === 0) {
|
|
82
|
+
print('\nNothing to remove.');
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (opts.dryRun) {
|
|
86
|
+
print('\n(dry run — nothing was removed)');
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const ok = opts.yes || (await confirm(`\nRemove ${removable} item(s)?`));
|
|
90
|
+
if (!ok) {
|
|
91
|
+
print('cancelled — nothing was removed.');
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const done = applyCleanup(rt, plan);
|
|
95
|
+
print(`\nremoved: ${done.conversations} conversation(s), ${done.executions} execution(s), ${done.artifacts} artifact(s), ${done.cache} cache entr${done.cache === 1 ? 'y' : 'ies'}.`);
|
|
96
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ai-runtime config` — print the resolved configuration (from the config file if present, else
|
|
3
|
+
* defaults). Shows weights, strategy, policy posture, and timeouts. No secrets are read or printed.
|
|
4
|
+
*/
|
|
5
|
+
export declare function configCommand(options: {
|
|
6
|
+
config?: string;
|
|
7
|
+
json?: boolean;
|
|
8
|
+
}): void;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ai-runtime config` — print the resolved configuration (from the config file if present, else
|
|
3
|
+
* defaults). Shows weights, strategy, policy posture, and timeouts. No secrets are read or printed.
|
|
4
|
+
*/
|
|
5
|
+
import { resolveConfig } from '../../config/defaults.js';
|
|
6
|
+
import { loadConfig, findConfigFile } from '../../config/load.js';
|
|
7
|
+
import { print } from '../render.js';
|
|
8
|
+
export function configCommand(options) {
|
|
9
|
+
const file = options.config ?? findConfigFile();
|
|
10
|
+
const resolved = resolveConfig(loadConfig(options.config));
|
|
11
|
+
if (options.json) {
|
|
12
|
+
print(JSON.stringify(resolved, null, 2));
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
print(file ? `Resolved config (${file}):` : 'Resolved defaults (no config file found):');
|
|
16
|
+
print(` providers: ${resolved.providers.length}`);
|
|
17
|
+
print(` strategy: ${resolved.strategy}`);
|
|
18
|
+
print(` timeoutMs: ${resolved.timeoutMs}`);
|
|
19
|
+
print(` maxFallbacks: ${resolved.maxFallbacks}`);
|
|
20
|
+
print(` minEvidence: ${resolved.minEvidence}`);
|
|
21
|
+
print(` minConfidence: ${resolved.minConfidence}`);
|
|
22
|
+
print(' weights:');
|
|
23
|
+
for (const [k, v] of Object.entries(resolved.weights))
|
|
24
|
+
print(` ${k}: ${v}`);
|
|
25
|
+
print(' privacy:');
|
|
26
|
+
for (const [k, v] of Object.entries(resolved.privacy))
|
|
27
|
+
print(` ${k}: ${String(v)}`);
|
|
28
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ai-runtime doctor` — diagnose the whole runtime: config, .env (by env-var NAME only), provider auth +
|
|
3
|
+
* health, accessible models, the local store (integrity + counts), skills, tools, permissions, and git.
|
|
4
|
+
* Never prints a secret VALUE; all output is redacted. `--json` emits the structured report.
|
|
5
|
+
*/
|
|
6
|
+
import { Runtime } from '../../runtime/runtime.js';
|
|
7
|
+
import type { IntegrityIssue } from '../../store/area.js';
|
|
8
|
+
export interface DoctorReport {
|
|
9
|
+
configFile?: string;
|
|
10
|
+
workspace?: {
|
|
11
|
+
name: string;
|
|
12
|
+
branch?: string;
|
|
13
|
+
};
|
|
14
|
+
env: {
|
|
15
|
+
present: string[];
|
|
16
|
+
absent: string[];
|
|
17
|
+
};
|
|
18
|
+
providers: Array<{
|
|
19
|
+
id: string;
|
|
20
|
+
state: string;
|
|
21
|
+
authenticated: boolean;
|
|
22
|
+
models: number;
|
|
23
|
+
}>;
|
|
24
|
+
models: {
|
|
25
|
+
total: number;
|
|
26
|
+
usableProviders: number;
|
|
27
|
+
};
|
|
28
|
+
store: {
|
|
29
|
+
enabled: boolean;
|
|
30
|
+
project: string;
|
|
31
|
+
integrity: IntegrityIssue[];
|
|
32
|
+
conversations: number;
|
|
33
|
+
executions: number;
|
|
34
|
+
memory: number;
|
|
35
|
+
artifacts: number;
|
|
36
|
+
};
|
|
37
|
+
skills: string[];
|
|
38
|
+
tools: string[];
|
|
39
|
+
permissions: {
|
|
40
|
+
fsRead: boolean;
|
|
41
|
+
fsWrite: boolean;
|
|
42
|
+
shell: boolean;
|
|
43
|
+
gitCommit: boolean;
|
|
44
|
+
gitPush: boolean;
|
|
45
|
+
network: boolean;
|
|
46
|
+
};
|
|
47
|
+
git: {
|
|
48
|
+
repo: boolean;
|
|
49
|
+
branch?: string;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export declare function gatherDoctor(rt: Runtime, configFile: string | undefined, env: NodeJS.ProcessEnv): Promise<DoctorReport>;
|
|
53
|
+
export declare function renderDoctor(r: DoctorReport): string[];
|
|
54
|
+
export declare function doctorCommand(opts: {
|
|
55
|
+
config?: string;
|
|
56
|
+
json?: boolean;
|
|
57
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ai-runtime doctor` — diagnose the whole runtime: config, .env (by env-var NAME only), provider auth +
|
|
3
|
+
* health, accessible models, the local store (integrity + counts), skills, tools, permissions, and git.
|
|
4
|
+
* Never prints a secret VALUE; all output is redacted. `--json` emits the structured report.
|
|
5
|
+
*/
|
|
6
|
+
import { Runtime } from '../../runtime/runtime.js';
|
|
7
|
+
import { loadRuntimeConfig } from '../../runtime/config.js';
|
|
8
|
+
import { print } from '../render.js';
|
|
9
|
+
/** The credential env-var NAMES ai-runtime knows about (§16). Presence is reported, never the value. */
|
|
10
|
+
const KNOWN_KEY_ENVS = [
|
|
11
|
+
'GEMINI_API_KEY', 'GROQ_API_KEY', 'ANTHROPIC_API_KEY', 'OPENROUTER_API_KEY', 'MISTRAL_API_KEY',
|
|
12
|
+
'CEREBRAS_API_KEY', 'COHERE_API_KEY', 'HUGGINGFACE_API_KEY', 'CLOUDFLARE_API_TOKEN', 'CUSTOM_AI_API_KEY',
|
|
13
|
+
];
|
|
14
|
+
export async function gatherDoctor(rt, configFile, env) {
|
|
15
|
+
const health = await rt.ai.checkHealth().catch(() => []);
|
|
16
|
+
const metas = await rt.ai.discover().catch(() => []);
|
|
17
|
+
const byId = new Map(metas.map((m) => [m.id, m]));
|
|
18
|
+
let usableProviders = 0;
|
|
19
|
+
const providers = health.map((h) => {
|
|
20
|
+
const authenticated = h.state !== 'NOT_CONFIGURED';
|
|
21
|
+
if (authenticated)
|
|
22
|
+
usableProviders += 1;
|
|
23
|
+
return { id: h.providerId, state: h.state, authenticated, models: byId.get(h.providerId)?.models.length ?? 0 };
|
|
24
|
+
});
|
|
25
|
+
const ws = rt.workspaceInfo();
|
|
26
|
+
const perms = rt.permissions();
|
|
27
|
+
const storeEnabled = rt.store.enabled;
|
|
28
|
+
return {
|
|
29
|
+
...(configFile ? { configFile } : {}),
|
|
30
|
+
...(ws ? { workspace: { name: ws.name ?? ws.root.split(/[\\/]/).pop() ?? 'workspace', ...(ws.git.branch ? { branch: ws.git.branch } : {}) } } : {}),
|
|
31
|
+
env: {
|
|
32
|
+
present: KNOWN_KEY_ENVS.filter((k) => (env[k] ?? '') !== ''),
|
|
33
|
+
absent: KNOWN_KEY_ENVS.filter((k) => (env[k] ?? '') === ''),
|
|
34
|
+
},
|
|
35
|
+
providers,
|
|
36
|
+
models: { total: metas.reduce((n, m) => n + m.models.length, 0), usableProviders },
|
|
37
|
+
store: {
|
|
38
|
+
enabled: storeEnabled,
|
|
39
|
+
project: rt.store.paths().project,
|
|
40
|
+
integrity: storeEnabled ? rt.store.check() : [],
|
|
41
|
+
conversations: rt.conversations.enabled ? rt.conversations.list().length : 0,
|
|
42
|
+
executions: rt.executionStore.enabled ? rt.executions().length : 0,
|
|
43
|
+
memory: rt.memory.enabled ? rt.memory.all().length : 0,
|
|
44
|
+
artifacts: rt.artifacts.enabled ? rt.artifacts.list().length : 0,
|
|
45
|
+
},
|
|
46
|
+
skills: rt.skills().map((s) => `${s.id}@${s.version}`),
|
|
47
|
+
tools: rt.tools().map((t) => t.id),
|
|
48
|
+
permissions: { fsRead: perms.filesystem.read, fsWrite: perms.filesystem.write, shell: perms.shell.enabled, gitCommit: perms.git.commit, gitPush: perms.git.push, network: perms.network.enabled },
|
|
49
|
+
git: { repo: !!ws?.git.isRepo, ...(ws?.git.branch ? { branch: ws.git.branch } : {}) },
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export function renderDoctor(r) {
|
|
53
|
+
const lines = ['ai-runtime Doctor', ''];
|
|
54
|
+
lines.push(`config: ${r.configFile ?? '(none — run `ai-runtime setup`)'}`);
|
|
55
|
+
lines.push(`workspace:${r.workspace ? ` ${r.workspace.name}${r.workspace.branch ? ` @ ${r.workspace.branch}` : ''}` : ' (none)'}`);
|
|
56
|
+
lines.push('', `.env keys present: ${r.env.present.length ? r.env.present.join(', ') : '(none)'}`);
|
|
57
|
+
lines.push(`.env keys absent: ${r.env.absent.join(', ')}`);
|
|
58
|
+
lines.push('', 'Providers:');
|
|
59
|
+
if (!r.providers.length)
|
|
60
|
+
lines.push(' (none configured — run `ai-runtime setup`)');
|
|
61
|
+
for (const p of r.providers)
|
|
62
|
+
lines.push(` ${p.authenticated ? '✓' : '✗'} ${p.id.padEnd(14)} ${p.authenticated ? 'authenticated' : 'not configured'} [${p.state}] ${p.models} models`);
|
|
63
|
+
lines.push(`Models: ${r.models.total} known, ${r.models.usableProviders} provider(s) usable`);
|
|
64
|
+
lines.push('', 'Store:');
|
|
65
|
+
if (!r.store.enabled)
|
|
66
|
+
lines.push(' disabled (stateless mode)');
|
|
67
|
+
else {
|
|
68
|
+
lines.push(` path: ${r.store.project}`);
|
|
69
|
+
lines.push(` ${r.store.conversations} conversation(s), ${r.store.executions} execution(s), ${r.store.memory} memory record(s), ${r.store.artifacts} artifact(s)`);
|
|
70
|
+
lines.push(` integrity: ${r.store.integrity.length ? `${r.store.integrity.length} issue(s) — ${r.store.integrity.map((i) => `${i.file} (${i.problem})`).join(', ')}` : 'ok'}`);
|
|
71
|
+
}
|
|
72
|
+
lines.push('', `Skills: ${r.skills.length ? r.skills.join(', ') : '(none)'}`);
|
|
73
|
+
lines.push(`Tools: ${r.tools.join(', ')}`);
|
|
74
|
+
lines.push(`Perms: fsRead=${r.permissions.fsRead} fsWrite=${r.permissions.fsWrite} shell=${r.permissions.shell} gitCommit=${r.permissions.gitCommit} gitPush=${r.permissions.gitPush} network=${r.permissions.network}`);
|
|
75
|
+
lines.push(`Git: ${r.git.repo ? `repository${r.git.branch ? ` @ ${r.git.branch}` : ''}` : 'not a git repository'}`);
|
|
76
|
+
return lines;
|
|
77
|
+
}
|
|
78
|
+
export async function doctorCommand(opts) {
|
|
79
|
+
const loaded = loadRuntimeConfig({ workspaceRoot: process.cwd(), ...(opts.config ? { explicitPath: opts.config } : {}) });
|
|
80
|
+
const rt = await Runtime.load({ ...(opts.config ? { config: opts.config } : {}) });
|
|
81
|
+
const report = await gatherDoctor(rt, loaded.configFile, process.env);
|
|
82
|
+
if (opts.json)
|
|
83
|
+
return print(JSON.stringify(report, null, 2));
|
|
84
|
+
for (const line of renderDoctor(report))
|
|
85
|
+
print(line);
|
|
86
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** `ai-runtime executions` (list) and `resume-execution <id>` — inspect and resume persisted work. */
|
|
2
|
+
export declare function executionsCommand(options: {
|
|
3
|
+
config?: string;
|
|
4
|
+
json?: boolean;
|
|
5
|
+
}): Promise<void>;
|
|
6
|
+
export declare function resumeExecutionCommand(id: string, options: {
|
|
7
|
+
config?: string;
|
|
8
|
+
answer?: string;
|
|
9
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** `ai-runtime executions` (list) and `resume-execution <id>` — inspect and resume persisted work. */
|
|
2
|
+
import { Runtime } from '../../runtime/runtime.js';
|
|
3
|
+
import { print } from '../render.js';
|
|
4
|
+
export async function executionsCommand(options) {
|
|
5
|
+
const rt = await Runtime.load({ ...(options.config ? { config: options.config } : {}) });
|
|
6
|
+
const list = rt.executions();
|
|
7
|
+
if (options.json)
|
|
8
|
+
return print(JSON.stringify(list, null, 2));
|
|
9
|
+
if (!list.length)
|
|
10
|
+
return print('No executions.');
|
|
11
|
+
print('Executions:');
|
|
12
|
+
for (const e of list)
|
|
13
|
+
print(` ${e.id} [${e.status}] ${e.mode}: ${e.goal.slice(0, 60)}`);
|
|
14
|
+
}
|
|
15
|
+
export async function resumeExecutionCommand(id, options) {
|
|
16
|
+
const rt = await Runtime.load({ ...(options.config ? { config: options.config } : {}) });
|
|
17
|
+
const r = await rt.resumeExecution(id, { ...(options.answer ? { clarificationAnswer: options.answer } : {}) });
|
|
18
|
+
if (r.response?.text)
|
|
19
|
+
print(r.response.text);
|
|
20
|
+
print(`status: ${r.status}`);
|
|
21
|
+
if (r.clarification)
|
|
22
|
+
print(`? ${r.clarification.question}`);
|
|
23
|
+
if (!r.ok)
|
|
24
|
+
process.exitCode = 1;
|
|
25
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ai-runtime info` — a read-only summary of the runtime: workspace, default mode, context budget,
|
|
3
|
+
* providers/models, skills, tools, memory + learning stats, and storage paths. Makes NO live calls and
|
|
4
|
+
* mutates nothing. `--json` prints the structured report.
|
|
5
|
+
*/
|
|
6
|
+
import { Runtime } from '../../runtime/runtime.js';
|
|
7
|
+
export interface InfoReport {
|
|
8
|
+
workspace?: {
|
|
9
|
+
name: string;
|
|
10
|
+
summary: string;
|
|
11
|
+
branch?: string;
|
|
12
|
+
};
|
|
13
|
+
defaultMode: string;
|
|
14
|
+
contextBudgetTokens: number;
|
|
15
|
+
providers: {
|
|
16
|
+
total: number;
|
|
17
|
+
enabled: number;
|
|
18
|
+
};
|
|
19
|
+
models: number;
|
|
20
|
+
skills: string[];
|
|
21
|
+
tools: string[];
|
|
22
|
+
memory: {
|
|
23
|
+
enabled: boolean;
|
|
24
|
+
facts: number;
|
|
25
|
+
};
|
|
26
|
+
learning: {
|
|
27
|
+
enabled: boolean;
|
|
28
|
+
entries: number;
|
|
29
|
+
preferredProviders: string[];
|
|
30
|
+
};
|
|
31
|
+
storage: {
|
|
32
|
+
home: string;
|
|
33
|
+
project: string;
|
|
34
|
+
enabled: boolean;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** Gather the read-only info report from a loaded runtime. Pure aside from reading the local store. */
|
|
38
|
+
export declare function gatherInfo(rt: Runtime): Promise<InfoReport>;
|
|
39
|
+
export declare function renderInfo(r: InfoReport): string[];
|
|
40
|
+
export declare function infoCommand(opts: {
|
|
41
|
+
config?: string;
|
|
42
|
+
json?: boolean;
|
|
43
|
+
}): Promise<void>;
|