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.
Files changed (269) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/LICENSE +15 -0
  3. package/README.md +489 -0
  4. package/dist/artifacts/artifacts.d.ts +28 -0
  5. package/dist/artifacts/artifacts.js +46 -0
  6. package/dist/benchmark/benchmark.d.ts +23 -0
  7. package/dist/benchmark/benchmark.js +40 -0
  8. package/dist/cli/cli.d.ts +6 -0
  9. package/dist/cli/cli.js +161 -0
  10. package/dist/cli/commands/cleanup.d.ts +47 -0
  11. package/dist/cli/commands/cleanup.js +96 -0
  12. package/dist/cli/commands/config.d.ts +8 -0
  13. package/dist/cli/commands/config.js +28 -0
  14. package/dist/cli/commands/doctor.d.ts +57 -0
  15. package/dist/cli/commands/doctor.js +86 -0
  16. package/dist/cli/commands/executions.d.ts +9 -0
  17. package/dist/cli/commands/executions.js +25 -0
  18. package/dist/cli/commands/info.d.ts +43 -0
  19. package/dist/cli/commands/info.js +53 -0
  20. package/dist/cli/commands/init.d.ts +5 -0
  21. package/dist/cli/commands/init.js +75 -0
  22. package/dist/cli/commands/inspect.d.ts +16 -0
  23. package/dist/cli/commands/inspect.js +60 -0
  24. package/dist/cli/commands/phase2.d.ts +22 -0
  25. package/dist/cli/commands/phase2.js +83 -0
  26. package/dist/cli/commands/route.d.ts +14 -0
  27. package/dist/cli/commands/route.js +49 -0
  28. package/dist/cli/commands/run.d.ts +11 -0
  29. package/dist/cli/commands/run.js +37 -0
  30. package/dist/cli/commands/setup.d.ts +34 -0
  31. package/dist/cli/commands/setup.js +104 -0
  32. package/dist/cli/commands/skills.d.ts +28 -0
  33. package/dist/cli/commands/skills.js +48 -0
  34. package/dist/cli/commands/test.d.ts +7 -0
  35. package/dist/cli/commands/test.js +29 -0
  36. package/dist/cli/context.d.ts +12 -0
  37. package/dist/cli/context.js +16 -0
  38. package/dist/cli/interactive/repl.d.ts +6 -0
  39. package/dist/cli/interactive/repl.js +45 -0
  40. package/dist/cli/interactive/session.d.ts +36 -0
  41. package/dist/cli/interactive/session.js +356 -0
  42. package/dist/cli/prompt.d.ts +6 -0
  43. package/dist/cli/prompt.js +18 -0
  44. package/dist/cli/render.d.ts +7 -0
  45. package/dist/cli/render.js +14 -0
  46. package/dist/comparison/analysis.d.ts +46 -0
  47. package/dist/comparison/analysis.js +177 -0
  48. package/dist/comparison/comparator.d.ts +46 -0
  49. package/dist/comparison/comparator.js +270 -0
  50. package/dist/comparison/comparison.d.ts +140 -0
  51. package/dist/comparison/comparison.js +9 -0
  52. package/dist/comparison/render.d.ts +7 -0
  53. package/dist/comparison/render.js +66 -0
  54. package/dist/config/defaults.d.ts +52 -0
  55. package/dist/config/defaults.js +56 -0
  56. package/dist/config/load.d.ts +17 -0
  57. package/dist/config/load.js +50 -0
  58. package/dist/config/providerDefaults.d.ts +17 -0
  59. package/dist/config/providerDefaults.js +61 -0
  60. package/dist/config/schema.d.ts +9 -0
  61. package/dist/config/schema.js +78 -0
  62. package/dist/context/budget.d.ts +13 -0
  63. package/dist/context/budget.js +17 -0
  64. package/dist/context/compiler.d.ts +61 -0
  65. package/dist/context/compiler.js +125 -0
  66. package/dist/context/tokens.d.ts +19 -0
  67. package/dist/context/tokens.js +38 -0
  68. package/dist/conversations/conversations.d.ts +38 -0
  69. package/dist/conversations/conversations.js +64 -0
  70. package/dist/core/capabilities/evidence.d.ts +40 -0
  71. package/dist/core/capabilities/evidence.js +102 -0
  72. package/dist/core/capabilities/overlay.d.ts +15 -0
  73. package/dist/core/capabilities/overlay.js +0 -0
  74. package/dist/core/capabilities/taxonomy.d.ts +19 -0
  75. package/dist/core/capabilities/taxonomy.js +25 -0
  76. package/dist/core/fallback/errors.d.ts +30 -0
  77. package/dist/core/fallback/errors.js +80 -0
  78. package/dist/core/fallback/fallback.d.ts +40 -0
  79. package/dist/core/fallback/fallback.js +82 -0
  80. package/dist/core/fallback/retryPolicy.d.ts +11 -0
  81. package/dist/core/fallback/retryPolicy.js +14 -0
  82. package/dist/core/health/health.d.ts +3 -0
  83. package/dist/core/health/health.js +5 -0
  84. package/dist/core/health/monitor.d.ts +23 -0
  85. package/dist/core/health/monitor.js +82 -0
  86. package/dist/core/policies/budget.d.ts +19 -0
  87. package/dist/core/policies/budget.js +37 -0
  88. package/dist/core/registry/builtinTasks.d.ts +8 -0
  89. package/dist/core/registry/builtinTasks.js +54 -0
  90. package/dist/core/registry/registry.d.ts +18 -0
  91. package/dist/core/registry/registry.js +33 -0
  92. package/dist/core/registry/taskRegistry.d.ts +15 -0
  93. package/dist/core/registry/taskRegistry.js +30 -0
  94. package/dist/core/router/confidence.d.ts +7 -0
  95. package/dist/core/router/confidence.js +20 -0
  96. package/dist/core/router/dimensions.d.ts +16 -0
  97. package/dist/core/router/dimensions.js +60 -0
  98. package/dist/core/router/executor.d.ts +16 -0
  99. package/dist/core/router/executor.js +25 -0
  100. package/dist/core/router/filter.d.ts +34 -0
  101. package/dist/core/router/filter.js +113 -0
  102. package/dist/core/router/normalize.d.ts +30 -0
  103. package/dist/core/router/normalize.js +119 -0
  104. package/dist/core/router/request.d.ts +4 -0
  105. package/dist/core/router/request.js +21 -0
  106. package/dist/core/router/router.d.ts +32 -0
  107. package/dist/core/router/router.js +195 -0
  108. package/dist/core/router/routingPrefs.d.ts +11 -0
  109. package/dist/core/router/routingPrefs.js +30 -0
  110. package/dist/core/router/scorer.d.ts +19 -0
  111. package/dist/core/router/scorer.js +50 -0
  112. package/dist/core/router/weights.d.ts +9 -0
  113. package/dist/core/router/weights.js +31 -0
  114. package/dist/core/validation/validator.d.ts +16 -0
  115. package/dist/core/validation/validator.js +33 -0
  116. package/dist/discovery/modelCatalog.d.ts +28 -0
  117. package/dist/discovery/modelCatalog.js +105 -0
  118. package/dist/discovery/openapi.d.ts +25 -0
  119. package/dist/discovery/openapi.js +76 -0
  120. package/dist/executions/checkpoint.d.ts +26 -0
  121. package/dist/executions/checkpoint.js +114 -0
  122. package/dist/executions/execution.d.ts +51 -0
  123. package/dist/executions/execution.js +8 -0
  124. package/dist/executions/store.d.ts +52 -0
  125. package/dist/executions/store.js +124 -0
  126. package/dist/generation/generateAdapter.d.ts +17 -0
  127. package/dist/generation/generateAdapter.js +30 -0
  128. package/dist/index.d.ts +147 -0
  129. package/dist/index.js +107 -0
  130. package/dist/learning/feedback.d.ts +9 -0
  131. package/dist/learning/feedback.js +18 -0
  132. package/dist/learning/learningStore.d.ts +68 -0
  133. package/dist/learning/learningStore.js +138 -0
  134. package/dist/learning/performanceStore.d.ts +27 -0
  135. package/dist/learning/performanceStore.js +0 -0
  136. package/dist/marketplace/presets.d.ts +24 -0
  137. package/dist/marketplace/presets.js +52 -0
  138. package/dist/mcp/mcp.d.ts +31 -0
  139. package/dist/mcp/mcp.js +54 -0
  140. package/dist/memory/bm25.d.ts +16 -0
  141. package/dist/memory/bm25.js +56 -0
  142. package/dist/memory/classifier.d.ts +14 -0
  143. package/dist/memory/classifier.js +17 -0
  144. package/dist/memory/memory.d.ts +80 -0
  145. package/dist/memory/memory.js +191 -0
  146. package/dist/orchestration/executor.d.ts +35 -0
  147. package/dist/orchestration/executor.js +65 -0
  148. package/dist/orchestration/orchestrator.d.ts +42 -0
  149. package/dist/orchestration/orchestrator.js +63 -0
  150. package/dist/orchestration/plan.d.ts +37 -0
  151. package/dist/orchestration/plan.js +70 -0
  152. package/dist/orchestration/planner.d.ts +29 -0
  153. package/dist/orchestration/planner.js +69 -0
  154. package/dist/plugin/ai.d.ts +82 -0
  155. package/dist/plugin/ai.js +167 -0
  156. package/dist/probing/probe.d.ts +25 -0
  157. package/dist/probing/probe.js +63 -0
  158. package/dist/providers/factory.d.ts +18 -0
  159. package/dist/providers/factory.js +54 -0
  160. package/dist/providers/httpClient.d.ts +34 -0
  161. package/dist/providers/httpClient.js +80 -0
  162. package/dist/providers/httpProvider.d.ts +49 -0
  163. package/dist/providers/httpProvider.js +135 -0
  164. package/dist/providers/mock/demo.d.ts +13 -0
  165. package/dist/providers/mock/demo.js +58 -0
  166. package/dist/providers/mock/mockProvider.d.ts +35 -0
  167. package/dist/providers/mock/mockProvider.js +121 -0
  168. package/dist/providers/mock/scenarios.d.ts +44 -0
  169. package/dist/providers/mock/scenarios.js +30 -0
  170. package/dist/providers/provider.d.ts +26 -0
  171. package/dist/providers/provider.js +11 -0
  172. package/dist/providers/wire/anthropicWire.d.ts +6 -0
  173. package/dist/providers/wire/anthropicWire.js +83 -0
  174. package/dist/providers/wire/openaiWire.d.ts +7 -0
  175. package/dist/providers/wire/openaiWire.js +81 -0
  176. package/dist/providers/wire/registry.d.ts +8 -0
  177. package/dist/providers/wire/registry.js +20 -0
  178. package/dist/providers/wire/types.d.ts +39 -0
  179. package/dist/providers/wire/types.js +24 -0
  180. package/dist/runtime/config.d.ts +31 -0
  181. package/dist/runtime/config.js +121 -0
  182. package/dist/runtime/context.d.ts +34 -0
  183. package/dist/runtime/context.js +11 -0
  184. package/dist/runtime/events.d.ts +99 -0
  185. package/dist/runtime/events.js +82 -0
  186. package/dist/runtime/host.d.ts +27 -0
  187. package/dist/runtime/host.js +7 -0
  188. package/dist/runtime/intent/classifier.d.ts +30 -0
  189. package/dist/runtime/intent/classifier.js +60 -0
  190. package/dist/runtime/intent/signals.d.ts +19 -0
  191. package/dist/runtime/intent/signals.js +46 -0
  192. package/dist/runtime/modes/availability.d.ts +11 -0
  193. package/dist/runtime/modes/availability.js +17 -0
  194. package/dist/runtime/modes/chat.d.ts +18 -0
  195. package/dist/runtime/modes/chat.js +67 -0
  196. package/dist/runtime/modes/modeResolver.d.ts +43 -0
  197. package/dist/runtime/modes/modeResolver.js +78 -0
  198. package/dist/runtime/policy.d.ts +72 -0
  199. package/dist/runtime/policy.js +59 -0
  200. package/dist/runtime/providerView.d.ts +62 -0
  201. package/dist/runtime/providerView.js +105 -0
  202. package/dist/runtime/routing.d.ts +26 -0
  203. package/dist/runtime/routing.js +65 -0
  204. package/dist/runtime/runtime.d.ts +191 -0
  205. package/dist/runtime/runtime.js +718 -0
  206. package/dist/runtime/types.d.ts +153 -0
  207. package/dist/runtime/types.js +9 -0
  208. package/dist/runtime/workspace/detectors.d.ts +15 -0
  209. package/dist/runtime/workspace/detectors.js +57 -0
  210. package/dist/runtime/workspace/workspace.d.ts +29 -0
  211. package/dist/runtime/workspace/workspace.js +116 -0
  212. package/dist/security/credentials.d.ts +26 -0
  213. package/dist/security/credentials.js +34 -0
  214. package/dist/security/redact.d.ts +16 -0
  215. package/dist/security/redact.js +57 -0
  216. package/dist/skills/builtins/fileAnalyzer.d.ts +7 -0
  217. package/dist/skills/builtins/fileAnalyzer.js +47 -0
  218. package/dist/skills/builtins/repositoryAnalyzer.d.ts +6 -0
  219. package/dist/skills/builtins/repositoryAnalyzer.js +47 -0
  220. package/dist/skills/discovery.d.ts +61 -0
  221. package/dist/skills/discovery.js +211 -0
  222. package/dist/skills/manifest.d.ts +30 -0
  223. package/dist/skills/manifest.js +75 -0
  224. package/dist/skills/registry.d.ts +15 -0
  225. package/dist/skills/registry.js +22 -0
  226. package/dist/skills/skill.d.ts +64 -0
  227. package/dist/skills/skill.js +8 -0
  228. package/dist/store/area.d.ts +54 -0
  229. package/dist/store/area.js +164 -0
  230. package/dist/store/paths.d.ts +15 -0
  231. package/dist/store/paths.js +48 -0
  232. package/dist/store/store.d.ts +59 -0
  233. package/dist/store/store.js +140 -0
  234. package/dist/telemetry/sinks/file.d.ts +12 -0
  235. package/dist/telemetry/sinks/file.js +28 -0
  236. package/dist/telemetry/telemetry.d.ts +36 -0
  237. package/dist/telemetry/telemetry.js +63 -0
  238. package/dist/tools/builtins/filesystem.d.ts +7 -0
  239. package/dist/tools/builtins/filesystem.js +53 -0
  240. package/dist/tools/builtins/git.d.ts +10 -0
  241. package/dist/tools/builtins/git.js +66 -0
  242. package/dist/tools/builtins/shell.d.ts +17 -0
  243. package/dist/tools/builtins/shell.js +91 -0
  244. package/dist/tools/jail.d.ts +12 -0
  245. package/dist/tools/jail.js +98 -0
  246. package/dist/tools/permissions.d.ts +25 -0
  247. package/dist/tools/permissions.js +24 -0
  248. package/dist/tools/registry.d.ts +10 -0
  249. package/dist/tools/registry.js +20 -0
  250. package/dist/tools/runner.d.ts +23 -0
  251. package/dist/tools/runner.js +64 -0
  252. package/dist/tools/tool.d.ts +53 -0
  253. package/dist/tools/tool.js +24 -0
  254. package/dist/tools/untrusted.d.ts +13 -0
  255. package/dist/tools/untrusted.js +30 -0
  256. package/dist/types.d.ts +460 -0
  257. package/dist/types.js +12 -0
  258. package/dist/util/clock.d.ts +6 -0
  259. package/dist/util/clock.js +4 -0
  260. package/dist/util/extractJson.d.ts +8 -0
  261. package/dist/util/extractJson.js +54 -0
  262. package/dist/verification/verify.d.ts +26 -0
  263. package/dist/verification/verify.js +67 -0
  264. package/docs/GUIDE.md +358 -0
  265. package/docs/README.md +21 -0
  266. package/docs/architecture.md +78 -0
  267. package/docs/router.md +376 -0
  268. package/docs/security.md +55 -0
  269. package/package.json +67 -0
@@ -0,0 +1,27 @@
1
+ /**
2
+ * RuntimeHost — the generic host-integration contract. A host (CLI, IDE, web app, CI, automation)
3
+ * supplies a workspace, an event sink, and optional credential/approval providers; the Runtime returns
4
+ * results and streams events. The Runtime never depends on any UI. In Phase 2 `workspace`, `eventSink`,
5
+ * and `credentialResolver` are wired; `approval` is part of the contract but consumed in Phase 5.
6
+ */
7
+ import type { CredentialResolver } from '../security/credentials.js';
8
+ import type { RuntimeEventSink } from './events.js';
9
+ /** Requested by the Runtime before a dangerous action; a host decides yes/no. Consumed in Phase 5. */
10
+ export interface ApprovalRequest {
11
+ action: string;
12
+ reason?: string;
13
+ risk?: 'low' | 'medium' | 'high';
14
+ }
15
+ export interface ApprovalProvider {
16
+ requestApproval(request: ApprovalRequest): Promise<boolean>;
17
+ }
18
+ export interface RuntimeHost {
19
+ /** Workspace root the Runtime should operate in. */
20
+ workspace?: string;
21
+ /** Receives redacted runtime lifecycle events. */
22
+ eventSink?: RuntimeEventSink;
23
+ /** Resolves an env-var NAME to a secret value (e.g. an OS keychain). Env still wins when present. */
24
+ credentialResolver?: CredentialResolver;
25
+ /** Approves dangerous actions. Wired in Phase 5. */
26
+ approval?: ApprovalProvider;
27
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * RuntimeHost — the generic host-integration contract. A host (CLI, IDE, web app, CI, automation)
3
+ * supplies a workspace, an event sink, and optional credential/approval providers; the Runtime returns
4
+ * results and streams events. The Runtime never depends on any UI. In Phase 2 `workspace`, `eventSink`,
5
+ * and `credentialResolver` are wired; `approval` is part of the contract but consumed in Phase 5.
6
+ */
7
+ export {};
@@ -0,0 +1,30 @@
1
+ /**
2
+ * IntentClassifier — the seam. HeuristicIntentClassifier is a deterministic, offline, pure classifier
3
+ * (no clock/env/fs). `classify` may return a Promise, so a future AI-assisted classifier drops in via
4
+ * RuntimeOptions.classifier with no API change. Ambiguity (low confidence + competing modes) is
5
+ * flagged, never guessed away.
6
+ */
7
+ import type { ExecutableMode } from '../types.js';
8
+ import type { WorkspaceInfo } from '../workspace/workspace.js';
9
+ export interface IntentInput {
10
+ text: string;
11
+ hasParts?: boolean;
12
+ workspace?: WorkspaceInfo;
13
+ }
14
+ export interface IntentClassification {
15
+ mode: ExecutableMode;
16
+ confidence: number;
17
+ reason: string;
18
+ /** True when confidence is low and ≥2 modes compete — the caller may ask for clarification. */
19
+ ambiguous: boolean;
20
+ /** Full per-mode score breakdown (for debugging/tests). */
21
+ scores: Partial<Record<ExecutableMode, number>>;
22
+ }
23
+ export interface IntentClassifier {
24
+ classify(input: IntentInput): IntentClassification | Promise<IntentClassification>;
25
+ }
26
+ /** Below this confidence with ≥2 competing modes, the result is flagged ambiguous. */
27
+ export declare const AMBIGUITY_CONFIDENCE = 0.55;
28
+ export declare class HeuristicIntentClassifier implements IntentClassifier {
29
+ classify(input: IntentInput): IntentClassification;
30
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * IntentClassifier — the seam. HeuristicIntentClassifier is a deterministic, offline, pure classifier
3
+ * (no clock/env/fs). `classify` may return a Promise, so a future AI-assisted classifier drops in via
4
+ * RuntimeOptions.classifier with no API change. Ambiguity (low confidence + competing modes) is
5
+ * flagged, never guessed away.
6
+ */
7
+ import { SIGNALS, MODEL_TOKENS, CHAT_BASELINE, TIE_BREAK_PRIORITY } from './signals.js';
8
+ /** Below this confidence with ≥2 competing modes, the result is flagged ambiguous. */
9
+ export const AMBIGUITY_CONFIDENCE = 0.55;
10
+ export class HeuristicIntentClassifier {
11
+ classify(input) {
12
+ const text = input.text ?? '';
13
+ const scores = new Map();
14
+ const matched = [];
15
+ const add = (mode, weight, label) => {
16
+ scores.set(mode, (scores.get(mode) ?? 0) + weight);
17
+ matched.push(`${mode}("${label}")`);
18
+ };
19
+ // chat baseline so it wins when nothing else fires.
20
+ scores.set('chat', CHAT_BASELINE);
21
+ // Lexical signals.
22
+ for (const s of SIGNALS) {
23
+ if (s.pattern.test(text))
24
+ add(s.mode, s.weight, s.label);
25
+ }
26
+ // Structural cues.
27
+ if (/```|(^|\n)\s*(Error|Exception|Traceback)\b|\bat .+:\d+:\d+/.test(text))
28
+ add('debug', 3, 'stacktrace/code');
29
+ const steps = (text.match(/(^|\n)\s*(?:\d+[.)]|[-*])\s+/g) ?? []).length;
30
+ if (steps >= 3) {
31
+ add('orchestrate', 2, 'numbered-steps');
32
+ add('plan', 1, 'numbered-steps');
33
+ }
34
+ if (/\?\s*$/.test(text.trim()))
35
+ add('chat', 1, 'question-mark');
36
+ if (text.trim().length > 0 && text.trim().length < 20)
37
+ add('chat', 1, 'short-input');
38
+ const modelHits = MODEL_TOKENS.filter((re) => re.test(text)).length;
39
+ if (modelHits >= 2)
40
+ add('compare', 2, 'model-pair');
41
+ // Rank.
42
+ const ranked = [...scores.entries()].sort((a, b) => {
43
+ if (b[1] !== a[1])
44
+ return b[1] - a[1];
45
+ return TIE_BREAK_PRIORITY.indexOf(b[0]) - TIE_BREAK_PRIORITY.indexOf(a[0]);
46
+ });
47
+ const [topMode, topScore] = ranked[0] ?? ['chat', CHAT_BASELINE];
48
+ const runnerUp = ranked[1]?.[1] ?? 0;
49
+ const confidence = Math.min(0.95, Math.max(0.4, topScore / (topScore + runnerUp || 1)));
50
+ const competing = ranked.filter(([, v]) => v > 0).length;
51
+ const ambiguous = confidence < AMBIGUITY_CONFIDENCE && competing >= 2;
52
+ const scoreObj = {};
53
+ for (const [m, v] of scores)
54
+ scoreObj[m] = v;
55
+ const reason = matched.length > 0
56
+ ? `matched ${matched.slice(0, 4).join(', ')}${matched.length > 4 ? ', …' : ''}`
57
+ : 'no strong mode signals; defaulting to chat';
58
+ return { mode: topMode, confidence, reason, ambiguous, scores: scoreObj };
59
+ }
60
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Deterministic intent signals — the data behind the heuristic classifier. Each rule contributes its
3
+ * weight to a mode when its pattern matches. Structural cues (code fences, numbered steps, model-name
4
+ * pairs) are applied separately in classifier.ts. Everything here is pure data.
5
+ */
6
+ import type { ExecutableMode } from '../types.js';
7
+ export interface Signal {
8
+ mode: ExecutableMode;
9
+ pattern: RegExp;
10
+ weight: number;
11
+ label: string;
12
+ }
13
+ /** Baseline score chat always carries so it wins when nothing else fires. */
14
+ export declare const CHAT_BASELINE = 0.5;
15
+ /** Deterministic tie-break order (higher index = wins ties). Declared, so it is testable. */
16
+ export declare const TIE_BREAK_PRIORITY: ExecutableMode[];
17
+ export declare const SIGNALS: Signal[];
18
+ /** Known model/provider tokens; ≥2 distinct in one input is a strong compare signal. */
19
+ export declare const MODEL_TOKENS: RegExp[];
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Deterministic intent signals — the data behind the heuristic classifier. Each rule contributes its
3
+ * weight to a mode when its pattern matches. Structural cues (code fences, numbered steps, model-name
4
+ * pairs) are applied separately in classifier.ts. Everything here is pure data.
5
+ */
6
+ /** Baseline score chat always carries so it wins when nothing else fires. */
7
+ export const CHAT_BASELINE = 0.5;
8
+ /** Deterministic tie-break order (higher index = wins ties). Declared, so it is testable. */
9
+ export const TIE_BREAK_PRIORITY = ['chat', 'execute', 'plan', 'agent', 'orchestrate', 'compare', 'debug'];
10
+ export const SIGNALS = [
11
+ // plan
12
+ { mode: 'plan', pattern: /\b(plan|roadmap|strateg(y|ies)|outline|break (this|it) down|steps to|approach for|how should (i|we))\b/i, weight: 3, label: 'plan' },
13
+ // execute
14
+ { mode: 'execute', pattern: /\b(run|execute|apply|perform|carry out|implement|make (the|this) change)\b/i, weight: 2, label: 'execute' },
15
+ // orchestrate
16
+ { mode: 'orchestrate', pattern: /\b(orchestrate|pipeline|workflow|coordinate|end[- ]to[- ]end)\b/i, weight: 3, label: 'orchestrate' },
17
+ { mode: 'orchestrate', pattern: /\bfix\b.*\b(tests?|failures?|build|suite|errors?)\b/i, weight: 2, label: 'fix-task' },
18
+ // agent
19
+ { mode: 'agent', pattern: /\b(autonomously|on my behalf|agentic|multi[- ]step)\b/i, weight: 3, label: 'agent' },
20
+ { mode: 'agent', pattern: /\bkeep (going|iterating|fixing|trying)\b|\buntil\b.*\b(pass|passes|green|done|works?)\b/i, weight: 3, label: 'until-done' },
21
+ // compare
22
+ { mode: 'compare', pattern: /\b(compare|versus|vs\.?|side[- ]by[- ]side|benchmark)\b/i, weight: 3, label: 'compare' },
23
+ { mode: 'compare', pattern: /\bwhich (model|provider|one|approach)\b|\btry (both|all)\b/i, weight: 2, label: 'which' },
24
+ // debug
25
+ { mode: 'debug', pattern: /\b(debug|diagnose|root cause|troubleshoot)\b/i, weight: 3, label: 'debug' },
26
+ { mode: 'debug', pattern: /\bwhy (is|does|did|are|am|won'?t|can'?t)\b.*\b(fail|failing|error|crash|broken|not work)\b/i, weight: 3, label: 'why-failing' },
27
+ { mode: 'debug', pattern: /\b(not working|isn'?t working|stack ?trace|traceback)\b/i, weight: 2, label: 'broken' },
28
+ // chat
29
+ { mode: 'chat', pattern: /^\s*(what|who|why|how|when|where|explain|tell me|describe|define)\b/i, weight: 1, label: 'question' },
30
+ { mode: 'chat', pattern: /^\s*(hi|hello|hey|thanks|thank you)\b/i, weight: 1, label: 'greeting' },
31
+ ];
32
+ /** Known model/provider tokens; ≥2 distinct in one input is a strong compare signal. */
33
+ export const MODEL_TOKENS = [
34
+ /\bgpt-?\d/i,
35
+ /\bo\d(-mini|-preview)?\b/i,
36
+ /\bclaude\b/i,
37
+ /\bsonnet\b/i,
38
+ /\bopus\b/i,
39
+ /\bhaiku\b/i,
40
+ /\bgemini\b/i,
41
+ /\bgroq\b/i,
42
+ /\bllama\b/i,
43
+ /\bmistral\b/i,
44
+ /\bollama\b/i,
45
+ /\bdeepseek\b/i,
46
+ ];
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Which executable modes are actually implemented, and the phase that will implement the rest. An
3
+ * unimplemented mode degrades to chat with a clear notice (never a hard error for a valid mode name).
4
+ */
5
+ import type { ExecutableMode } from '../types.js';
6
+ export declare const MODE_AVAILABILITY: Record<ExecutableMode, {
7
+ implemented: boolean;
8
+ plannedPhase?: number;
9
+ }>;
10
+ export declare const IMPLEMENTED_MODES: ReadonlySet<ExecutableMode>;
11
+ export declare function isModeImplemented(mode: ExecutableMode): boolean;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Which executable modes are actually implemented, and the phase that will implement the rest. An
3
+ * unimplemented mode degrades to chat with a clear notice (never a hard error for a valid mode name).
4
+ */
5
+ export const MODE_AVAILABILITY = {
6
+ chat: { implemented: true },
7
+ plan: { implemented: true },
8
+ execute: { implemented: true },
9
+ orchestrate: { implemented: true },
10
+ debug: { implemented: true },
11
+ agent: { implemented: true },
12
+ compare: { implemented: true },
13
+ };
14
+ export const IMPLEMENTED_MODES = new Set(Object.keys(MODE_AVAILABILITY).filter((m) => MODE_AVAILABILITY[m].implemented));
15
+ export function isModeImplemented(mode) {
16
+ return MODE_AVAILABILITY[mode].implemented;
17
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The generic `chat` task + the mapping between RuntimeRunInput/RunResult and the router. QA-neutral by
3
+ * construction: capability keys come straight from the shared taxonomy, no context floor, so tiny
4
+ * local models qualify. The chat task is registered on the Runtime's AI instance only-if-absent.
5
+ */
6
+ import type { RoutingPreferences, RunRequest, RunResult, TaskDefinition } from '../../types.js';
7
+ import type { ModeResolution, RuntimeResult, RuntimeRunInput, Clarification } from '../types.js';
8
+ import type { Strategy } from '../../types.js';
9
+ export declare const CHAT_TASK: TaskDefinition;
10
+ /** Extract plain text from a RuntimeRunInput for intent classification. */
11
+ export declare function inputText(input: RuntimeRunInput['input']): string;
12
+ /**
13
+ * Build the router RunRequest for a chat run. The system prompt is precompiled by the ContextCompiler
14
+ * (workspace summary + memory facts + user system, under a token budget) — never raw repo contents.
15
+ */
16
+ export declare function buildChatRequest(input: RuntimeRunInput, strategy?: Strategy, system?: string, routing?: RoutingPreferences): RunRequest;
17
+ /** Map a router RunResult into a RuntimeResult. Routing passes through verbatim; errors keep their category. */
18
+ export declare function toRuntimeResult(run: RunResult, mode: ModeResolution, runId: string, clarification?: Clarification): RuntimeResult;
@@ -0,0 +1,67 @@
1
+ /**
2
+ * The generic `chat` task + the mapping between RuntimeRunInput/RunResult and the router. QA-neutral by
3
+ * construction: capability keys come straight from the shared taxonomy, no context floor, so tiny
4
+ * local models qualify. The chat task is registered on the Runtime's AI instance only-if-absent.
5
+ */
6
+ import { mergeRouting } from '../routing.js';
7
+ export const CHAT_TASK = {
8
+ id: 'chat',
9
+ aliases: ['conversation', 'general-chat'],
10
+ description: 'General conversational response over text input.',
11
+ required: [
12
+ { group: 'intelligence', key: 'reasoning' },
13
+ { group: 'output', key: 'text' },
14
+ ],
15
+ preferred: [{ group: 'intelligence', key: 'summarization' }],
16
+ output: { format: 'text' },
17
+ defaultStrategy: 'best',
18
+ };
19
+ function normalizeInput(input) {
20
+ return typeof input === 'string' ? { text: input } : input;
21
+ }
22
+ /** Extract plain text from a RuntimeRunInput for intent classification. */
23
+ export function inputText(input) {
24
+ if (typeof input === 'string')
25
+ return input;
26
+ if (input.text)
27
+ return input.text;
28
+ return (input.parts ?? []).filter((p) => p.kind === 'text').map((p) => p.text).join('\n');
29
+ }
30
+ /**
31
+ * Build the router RunRequest for a chat run. The system prompt is precompiled by the ContextCompiler
32
+ * (workspace summary + memory facts + user system, under a token budget) — never raw repo contents.
33
+ */
34
+ export function buildChatRequest(input, strategy, system, routing) {
35
+ const req = {
36
+ task: 'chat',
37
+ input: normalizeInput(input.input),
38
+ ...(system ? { system } : {}),
39
+ ...(strategy ? { strategy } : {}),
40
+ ...(input.sensitivity ? { sensitivity: input.sensitivity } : {}),
41
+ ...(input.output ? { output: input.output } : {}),
42
+ ...(input.request ?? {}), // escape hatch: may add preferences, but must NOT drop a resolved exclusion
43
+ };
44
+ // Resolved routing is a FLOOR for exclusions — union it over any escape-hatch request.routing so a
45
+ // caller can add prefer but can never silently re-admit an env/config exclusion.
46
+ const merged = mergeRouting(routing, req.routing);
47
+ if (merged)
48
+ req.routing = merged;
49
+ else
50
+ delete req.routing;
51
+ return req;
52
+ }
53
+ /** Map a router RunResult into a RuntimeResult. Routing passes through verbatim; errors keep their category. */
54
+ export function toRuntimeResult(run, mode, runId, clarification) {
55
+ const response = run.response ? { ...(run.response.text !== undefined ? { text: run.response.text } : {}), ...(run.response.json !== undefined ? { json: run.response.json } : {}) } : undefined;
56
+ return {
57
+ ok: run.ok,
58
+ runId,
59
+ mode,
60
+ status: clarification ? 'waiting_for_clarification' : 'completed',
61
+ ...(response ? { response } : {}),
62
+ ...(clarification ? { clarification } : {}),
63
+ routing: run.routing,
64
+ ...(run.error ? { error: run.error } : {}),
65
+ artifacts: [],
66
+ };
67
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Mode + strategy precedence. Explicit per-run > project config > env > automatic detection. An
3
+ * explicit mode is NEVER overridden by detection. Invalid env values are silently ignored (env must
4
+ * never break a run). Unimplemented modes degrade to chat with a notice.
5
+ */
6
+ import type { ExecutableMode, ModeResolution, RuntimeMode } from '../types.js';
7
+ import type { Strategy } from '../../types.js';
8
+ import type { IntentClassification, IntentClassifier, IntentInput } from '../intent/classifier.js';
9
+ export interface ResolveModeInput {
10
+ /** RuntimeRunInput.mode (may be undefined or 'auto'). */
11
+ explicit?: RuntimeMode;
12
+ /** RuntimeSettings.defaultMode (may be undefined or 'auto'). */
13
+ configDefault?: RuntimeMode;
14
+ /** Raw AI_DEFAULT_MODE value from the injected env (validated; invalid ignored). */
15
+ envDefault?: string;
16
+ intent: IntentInput;
17
+ classifier: IntentClassifier;
18
+ /** Override mode availability (defaults to MODE_AVAILABILITY). Lets the degrade path stay testable. */
19
+ availability?: Partial<Record<ExecutableMode, {
20
+ implemented: boolean;
21
+ plannedPhase?: number;
22
+ }>>;
23
+ }
24
+ export interface ModeResolutionResult {
25
+ resolution: ModeResolution;
26
+ /** Present only when the mode came from auto detection — lets the caller act on ambiguity. */
27
+ classification?: IntentClassification;
28
+ }
29
+ /**
30
+ * Resolve the mode for a run. Throws AIError(CONFIG) only for an INVALID mode string passed
31
+ * programmatically (a valid-but-unimplemented mode degrades, it does not throw).
32
+ */
33
+ export declare function resolveMode(input: ResolveModeInput): Promise<ModeResolutionResult>;
34
+ export interface ResolveStrategyInput {
35
+ explicit?: Strategy;
36
+ configDefault?: Strategy;
37
+ envDefault?: string;
38
+ }
39
+ /**
40
+ * Resolve the strategy to pass through. Precedence: per-run > config > env. Returns undefined when
41
+ * nothing is set, so the router's own chain (task default → router config → 'best') stays intact.
42
+ */
43
+ export declare function resolveStrategy(input: ResolveStrategyInput): Strategy | undefined;
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Mode + strategy precedence. Explicit per-run > project config > env > automatic detection. An
3
+ * explicit mode is NEVER overridden by detection. Invalid env values are silently ignored (env must
4
+ * never break a run). Unimplemented modes degrade to chat with a notice.
5
+ */
6
+ import { AIError } from '../../core/fallback/errors.js';
7
+ import { RUNTIME_MODES } from '../types.js';
8
+ import { STRATEGIES } from '../../config/schema.js';
9
+ import { MODE_AVAILABILITY } from './availability.js';
10
+ function isRuntimeMode(v) {
11
+ return typeof v === 'string' && RUNTIME_MODES.includes(v);
12
+ }
13
+ function isStrategy(v) {
14
+ return typeof v === 'string' && STRATEGIES.includes(v);
15
+ }
16
+ /**
17
+ * Resolve the mode for a run. Throws AIError(CONFIG) only for an INVALID mode string passed
18
+ * programmatically (a valid-but-unimplemented mode degrades, it does not throw).
19
+ */
20
+ export async function resolveMode(input) {
21
+ // An explicit but invalid mode string (reachable only from JS callers) is a config error.
22
+ if (input.explicit !== undefined && !isRuntimeMode(input.explicit)) {
23
+ throw new AIError(`invalid mode '${String(input.explicit)}'; valid modes: ${RUNTIME_MODES.join(', ')}`, { category: 'CONFIG' });
24
+ }
25
+ const requested = input.explicit ?? 'auto';
26
+ let selected;
27
+ let source;
28
+ let confidence;
29
+ let reason;
30
+ let classification;
31
+ if (input.explicit !== undefined && input.explicit !== 'auto') {
32
+ selected = input.explicit;
33
+ source = 'explicit';
34
+ confidence = 1;
35
+ reason = 'mode explicitly requested';
36
+ }
37
+ else if (input.configDefault !== undefined && input.configDefault !== 'auto') {
38
+ selected = input.configDefault;
39
+ source = 'config';
40
+ confidence = 1;
41
+ reason = 'project default mode';
42
+ }
43
+ else if (isRuntimeMode(input.envDefault) && input.envDefault !== 'auto') {
44
+ selected = input.envDefault;
45
+ source = 'env';
46
+ confidence = 1;
47
+ reason = 'AI_DEFAULT_MODE';
48
+ }
49
+ else {
50
+ classification = await input.classifier.classify(input.intent);
51
+ selected = classification.mode;
52
+ source = 'auto';
53
+ confidence = classification.confidence;
54
+ reason = classification.ambiguous ? `${classification.reason} (ambiguous)` : classification.reason;
55
+ }
56
+ // Availability: degrade unimplemented modes to chat with a notice.
57
+ const availability = { ...MODE_AVAILABILITY, ...input.availability };
58
+ let executed = selected;
59
+ if (!availability[selected].implemented) {
60
+ const phase = availability[selected].plannedPhase;
61
+ executed = 'chat';
62
+ reason = `${reason}; '${selected}' is not yet implemented${phase ? ` (planned for Phase ${phase})` : ''} — executed as chat`;
63
+ }
64
+ return { resolution: { requested, selected, executed, confidence, reason, source }, ...(classification ? { classification } : {}) };
65
+ }
66
+ /**
67
+ * Resolve the strategy to pass through. Precedence: per-run > config > env. Returns undefined when
68
+ * nothing is set, so the router's own chain (task default → router config → 'best') stays intact.
69
+ */
70
+ export function resolveStrategy(input) {
71
+ if (input.explicit !== undefined)
72
+ return input.explicit;
73
+ if (input.configDefault !== undefined)
74
+ return input.configDefault;
75
+ if (isStrategy(input.envDefault))
76
+ return input.envDefault;
77
+ return undefined;
78
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * ExecutionPolicy — the SINGLE authority for autonomy, approval, dry-run, execution limits, and
3
+ * permissions. Every later layer (planner, orchestrator, executor, agent, tools, approval system,
4
+ * dry-run, budgets) READS the resolved policy; none re-derives it. In Phase 1 only the shape and
5
+ * resolution exist — enforcement is trivial (chat only) — but there is exactly one definition.
6
+ */
7
+ import type { ExecutableMode, RuntimeSettings } from './types.js';
8
+ /** How much independent action is permitted. Distinct from mode (what kind of work). */
9
+ export type Autonomy = 'chat' | 'assisted' | 'autonomous';
10
+ /** When human approval is required. */
11
+ export type ApprovalLevel = 'none' | 'before-plan' | 'before-execution' | 'per-dangerous-action';
12
+ /**
13
+ * Permission posture (config-facing; all optional, deny-by-default for write/exec). The concrete,
14
+ * fully-defaulted form tools consume is `ResolvedPermissions` (src/tools/permissions.ts). Phase 1
15
+ * shipped the flat `fsWrite`/`shell`/`gitWrite` fields; Phase 5 adds the structured allowlist model.
16
+ * Both are honored by `resolvePermissions` (structured fields win when set).
17
+ */
18
+ export interface PermissionPolicy {
19
+ /** Allow filesystem reads within the workspace. Default true (reads are jailed to the workspace). */
20
+ fsRead?: boolean;
21
+ /** Allow filesystem writes within the workspace. Default false. */
22
+ fsWrite?: boolean;
23
+ /** Allow shell execution. Default false. */
24
+ shell?: boolean;
25
+ /** Allowlist of shell commands (argv[0]); empty means nothing is pre-approved. */
26
+ shellAllowedCommands?: string[];
27
+ /** Umbrella for git commit+push (Phase 1 field). `gitCommit`/`gitPush` override it when set. */
28
+ gitWrite?: boolean;
29
+ gitCommit?: boolean;
30
+ gitPush?: boolean;
31
+ /** Allow tool network access. Default false. */
32
+ network?: boolean;
33
+ }
34
+ export interface ExecutionPolicy {
35
+ autonomy: Autonomy;
36
+ approval: ApprovalLevel;
37
+ dryRun: boolean;
38
+ maxIterations?: number;
39
+ maxCalls?: number;
40
+ maxCostUsd?: number;
41
+ maxParallelSteps?: number;
42
+ permissions: PermissionPolicy;
43
+ }
44
+ /** Per-run overrides a caller may pass (all optional; highest precedence). */
45
+ export interface PolicyOverrides {
46
+ autonomy?: Autonomy;
47
+ approval?: ApprovalLevel;
48
+ dryRun?: boolean;
49
+ maxIterations?: number;
50
+ maxCalls?: number;
51
+ maxCostUsd?: number;
52
+ maxParallelSteps?: number;
53
+ permissions?: PermissionPolicy;
54
+ }
55
+ /** Autonomy implied by a mode when nothing more specific is set. */
56
+ export declare function defaultAutonomyForMode(mode: ExecutableMode): Autonomy;
57
+ export interface ResolvePolicyInput {
58
+ mode: ExecutableMode;
59
+ overrides?: PolicyOverrides;
60
+ settings?: RuntimeSettings;
61
+ /** Raw env values (injected for testability), e.g. AI_MAX_COST_USD / AI_MAX_CALLS. */
62
+ env?: {
63
+ maxCostUsd?: number;
64
+ maxCalls?: number;
65
+ };
66
+ }
67
+ /**
68
+ * Resolve the one policy for a run. Precedence: per-run overrides > env > mode-derived defaults.
69
+ * (Project-config policy fields are folded in through `settings`/`overrides` by the caller as those
70
+ * config keys land; Phase 1 wires the mode-derived + env + per-run rungs.)
71
+ */
72
+ export declare function resolvePolicy(input: ResolvePolicyInput): ExecutionPolicy;
@@ -0,0 +1,59 @@
1
+ /**
2
+ * ExecutionPolicy — the SINGLE authority for autonomy, approval, dry-run, execution limits, and
3
+ * permissions. Every later layer (planner, orchestrator, executor, agent, tools, approval system,
4
+ * dry-run, budgets) READS the resolved policy; none re-derives it. In Phase 1 only the shape and
5
+ * resolution exist — enforcement is trivial (chat only) — but there is exactly one definition.
6
+ */
7
+ /** Autonomy implied by a mode when nothing more specific is set. */
8
+ export function defaultAutonomyForMode(mode) {
9
+ switch (mode) {
10
+ case 'chat':
11
+ case 'plan':
12
+ return 'chat';
13
+ case 'agent':
14
+ return 'autonomous';
15
+ case 'execute':
16
+ case 'orchestrate':
17
+ case 'compare':
18
+ case 'debug':
19
+ return 'assisted';
20
+ }
21
+ }
22
+ /** Approval implied by an autonomy level. */
23
+ function defaultApprovalForAutonomy(autonomy) {
24
+ switch (autonomy) {
25
+ case 'chat':
26
+ return 'none';
27
+ case 'assisted':
28
+ return 'before-execution';
29
+ case 'autonomous':
30
+ return 'per-dangerous-action';
31
+ }
32
+ }
33
+ /**
34
+ * Resolve the one policy for a run. Precedence: per-run overrides > env > mode-derived defaults.
35
+ * (Project-config policy fields are folded in through `settings`/`overrides` by the caller as those
36
+ * config keys land; Phase 1 wires the mode-derived + env + per-run rungs.)
37
+ */
38
+ export function resolvePolicy(input) {
39
+ const o = input.overrides ?? {};
40
+ const autonomy = o.autonomy ?? defaultAutonomyForMode(input.mode);
41
+ const approval = o.approval ?? defaultApprovalForAutonomy(autonomy);
42
+ const policy = {
43
+ autonomy,
44
+ approval,
45
+ dryRun: o.dryRun ?? false,
46
+ permissions: o.permissions ?? {},
47
+ };
48
+ const maxCostUsd = o.maxCostUsd ?? input.env?.maxCostUsd;
49
+ const maxCalls = o.maxCalls ?? input.env?.maxCalls;
50
+ if (maxCostUsd !== undefined)
51
+ policy.maxCostUsd = maxCostUsd;
52
+ if (maxCalls !== undefined)
53
+ policy.maxCalls = maxCalls;
54
+ if (o.maxIterations !== undefined)
55
+ policy.maxIterations = o.maxIterations;
56
+ if (o.maxParallelSteps !== undefined)
57
+ policy.maxParallelSteps = o.maxParallelSteps;
58
+ return policy;
59
+ }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Provider/model inspection views for the interactive surfaces. Distinguishes cataloged (documented)
3
+ * vs accessible (health-derived) vs capability-verified (probed) state, and derives a display-only
4
+ * `AccessState` from the FROZEN `HealthState` enum (the enum is never modified). A freshness cache keeps
5
+ * a chatty REPL from re-hitting providers on every command; stale records display as ACCESS_UNKNOWN and
6
+ * never count as proof of usability.
7
+ */
8
+ import type { Clock } from '../util/clock.js';
9
+ import type { Evidence, HealthState, HealthStatus, ProviderMetadata } from '../types.js';
10
+ import type { ProviderInfo } from '../plugin/ai.js';
11
+ /** Display-only access state, derived from HealthState + discovery freshness. Not a router concept. */
12
+ export type AccessState = 'NOT_CONFIGURED' | 'CONFIGURED' | 'AUTHENTICATED' | 'AUTH_FAILED' | 'ACCESS_UNKNOWN' | 'AVAILABLE' | 'DEGRADED' | 'RATE_LIMITED' | 'QUOTA_EXCEEDED' | 'MODEL_UNAVAILABLE';
13
+ /** Map a HealthState to an AccessState. Exhaustive over the 12 frozen states (compile-checked). */
14
+ export declare function deriveAccessState(state: HealthState): AccessState;
15
+ export interface ModelView {
16
+ id: string;
17
+ /** In the model catalog or operator-declared (source !== 'unknown'). */
18
+ cataloged: boolean;
19
+ /** At least one capability has been verified by a probe. */
20
+ verified: boolean;
21
+ contextWindow?: number;
22
+ quality?: string;
23
+ source: Evidence;
24
+ }
25
+ export interface ProviderView {
26
+ id: string;
27
+ name: string;
28
+ kind: string;
29
+ enabled: boolean;
30
+ accessState: AccessState;
31
+ healthState: HealthState;
32
+ checkedAt?: number;
33
+ ageMs?: number;
34
+ /** True when the health record is older than the freshness ttl. */
35
+ stale: boolean;
36
+ models: ModelView[];
37
+ }
38
+ /** The subset of the AI facade a provider view needs — so views are testable with a stub. */
39
+ export interface ProviderViewSource {
40
+ providers(): ProviderInfo[];
41
+ checkHealth(): Promise<HealthStatus[]>;
42
+ discover(): Promise<ProviderMetadata[]>;
43
+ }
44
+ export interface BuildViewOptions {
45
+ now: number;
46
+ /** Freshness ttl in ms; a health record older than this displays as ACCESS_UNKNOWN. Default 60s. */
47
+ ttlMs?: number;
48
+ }
49
+ /** Build a joined provider/model view. Live: calls checkHealth() + discover(). */
50
+ export declare function buildProviderViews(source: ProviderViewSource, opts: BuildViewOptions): Promise<ProviderView[]>;
51
+ /** Memoizes provider views for a ttl so a long-lived REPL doesn't re-hit providers on every command. */
52
+ export declare class ProviderViewCache {
53
+ private readonly source;
54
+ private readonly clock;
55
+ private readonly ttlMs;
56
+ private last?;
57
+ constructor(source: ProviderViewSource, options?: {
58
+ clock?: Clock;
59
+ ttlMs?: number;
60
+ });
61
+ get(force?: boolean): Promise<ProviderView[]>;
62
+ }