klyro 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/dist/agent/anthropic-adapter.d.ts +49 -5
  2. package/dist/agent/anthropic-adapter.js +86 -17
  3. package/dist/agent/capabilities.d.ts +23 -0
  4. package/dist/agent/capabilities.js +53 -6
  5. package/dist/agent/child-worker.d.ts +104 -0
  6. package/dist/agent/child-worker.js +250 -0
  7. package/dist/agent/orchestrator.d.ts +124 -6
  8. package/dist/agent/orchestrator.js +425 -58
  9. package/dist/agent/provider-adapter.d.ts +8 -0
  10. package/dist/agent/provider-adapter.js +12 -3
  11. package/dist/agent/retry.d.ts +1 -1
  12. package/dist/agent/retry.js +54 -12
  13. package/dist/agent/runtime.d.ts +84 -8
  14. package/dist/agent/runtime.js +352 -39
  15. package/dist/agent/stream-budget.d.ts +36 -0
  16. package/dist/agent/stream-budget.js +121 -0
  17. package/dist/agent/worktree-manager.d.ts +74 -0
  18. package/dist/agent/worktree-manager.js +189 -0
  19. package/dist/checkpoints/store.d.ts +9 -0
  20. package/dist/checkpoints/store.js +56 -5
  21. package/dist/cli/auth.js +16 -1
  22. package/dist/cli/commit.d.ts +31 -0
  23. package/dist/cli/commit.js +142 -0
  24. package/dist/cli/config.d.ts +54 -3
  25. package/dist/cli/config.js +146 -3
  26. package/dist/cli/doctor.d.ts +1 -0
  27. package/dist/cli/doctor.js +71 -6
  28. package/dist/cli/eval.d.ts +6 -1
  29. package/dist/cli/eval.js +9 -0
  30. package/dist/cli/hooks.d.ts +47 -0
  31. package/dist/cli/hooks.js +181 -0
  32. package/dist/cli/repl.js +196 -29
  33. package/dist/cli/run.d.ts +13 -11
  34. package/dist/cli/run.js +144 -20
  35. package/dist/cli/update.d.ts +5 -0
  36. package/dist/cli/update.js +62 -10
  37. package/dist/context/import-graph.d.ts +2 -0
  38. package/dist/context/import-graph.js +31 -3
  39. package/dist/context/klyro-md.js +4 -1
  40. package/dist/context/memory.d.ts +8 -0
  41. package/dist/context/memory.js +50 -2
  42. package/dist/context/project-map.d.ts +6 -0
  43. package/dist/context/project-map.js +50 -2
  44. package/dist/context/repo-map.d.ts +2 -0
  45. package/dist/context/repo-map.js +31 -1
  46. package/dist/events/catalog.d.ts +37 -0
  47. package/dist/events/catalog.js +9 -0
  48. package/dist/index.js +177 -8
  49. package/dist/mcp/client.d.ts +6 -4
  50. package/dist/mcp/client.js +83 -14
  51. package/dist/mcp/config.d.ts +10 -0
  52. package/dist/mcp/config.js +18 -1
  53. package/dist/mcp/registry.d.ts +23 -19
  54. package/dist/mcp/registry.js +127 -8
  55. package/dist/mcp/schema.d.ts +11 -4
  56. package/dist/mcp/schema.js +27 -16
  57. package/dist/mcp/trust.d.ts +20 -0
  58. package/dist/mcp/trust.js +74 -0
  59. package/dist/persistence/audit.d.ts +28 -0
  60. package/dist/persistence/audit.js +101 -1
  61. package/dist/persistence/store.d.ts +26 -2
  62. package/dist/persistence/store.js +140 -13
  63. package/dist/policy/approval.d.ts +14 -0
  64. package/dist/policy/approval.js +44 -2
  65. package/dist/policy/engine.d.ts +17 -0
  66. package/dist/policy/engine.js +162 -9
  67. package/dist/policy/path-guard.d.ts +24 -0
  68. package/dist/policy/path-guard.js +46 -0
  69. package/dist/policy/secret-redactor.js +4 -0
  70. package/dist/providers/model-info.d.ts +23 -0
  71. package/dist/providers/model-info.js +43 -2
  72. package/dist/repl.d.ts +6 -0
  73. package/dist/repl.js +12 -7
  74. package/dist/tools/agent/spawn-agent.js +5 -5
  75. package/dist/tools/agent/task-apply.d.ts +4 -0
  76. package/dist/tools/agent/task-apply.js +44 -0
  77. package/dist/tools/agent/task-stop.d.ts +6 -0
  78. package/dist/tools/agent/task-stop.js +39 -0
  79. package/dist/tools/agent/task-wait.d.ts +17 -0
  80. package/dist/tools/agent/task-wait.js +79 -0
  81. package/dist/tools/fs/apply-patch.js +77 -1
  82. package/dist/tools/fs/edit-file.js +69 -1
  83. package/dist/tools/fs/multi-edit.d.ts +4 -0
  84. package/dist/tools/fs/multi-edit.js +70 -1
  85. package/dist/tools/fs/write-file.js +83 -6
  86. package/dist/tools/plan/todo-write.js +1 -1
  87. package/dist/tools/registry.js +6 -0
  88. package/dist/tools/shell/background.js +6 -3
  89. package/dist/tools/shell/sandbox.d.ts +51 -0
  90. package/dist/tools/shell/sandbox.js +143 -0
  91. package/dist/tools/shell/shell-exec.d.ts +29 -0
  92. package/dist/tools/shell/shell-exec.js +170 -12
  93. package/dist/tools/shell/worker-entry.d.ts +12 -0
  94. package/dist/tools/shell/worker-entry.js +43 -0
  95. package/dist/tools/types.d.ts +6 -0
  96. package/dist/tools/verify/run-verify.js +3 -1
  97. package/dist/trace/writer.d.ts +20 -0
  98. package/dist/trace/writer.js +62 -4
  99. package/dist/tui/app.js +1 -1
  100. package/dist/tui/approval.js +20 -21
  101. package/dist/util.d.ts +1 -0
  102. package/dist/util.js +1 -0
  103. package/dist/verification/baseline.js +17 -3
  104. package/dist/verification/classify.js +27 -15
  105. package/dist/verification/engine.d.ts +8 -0
  106. package/dist/verification/engine.js +28 -1
  107. package/dist/verification/registry.d.ts +2 -0
  108. package/dist/verification/registry.js +44 -0
  109. package/dist/verification/scoped.js +64 -11
  110. package/package.json +1 -1
@@ -15,10 +15,11 @@
15
15
  *
16
16
  * delay = min(maxMs, baseMs * 2^attempt) ± jitter
17
17
  *
18
- * The default policy matches the L6 plan: 3 attempts, 500ms base, 8s cap.
18
+ * The default policy matches the L6 plan: 5 attempts, 500ms base, 8s cap.
19
19
  */
20
+ import { acquireStreamSlot, noteRateLimited } from './stream-budget.js';
20
21
  export const DEFAULT_RETRY = {
21
- maxAttempts: 3,
22
+ maxAttempts: 5,
22
23
  baseMs: 500,
23
24
  maxMs: 8_000,
24
25
  sleep: defaultSleep,
@@ -88,6 +89,28 @@ export function computeBackoff(attempt, baseMs, maxMs) {
88
89
  const jitter = exp * 0.25 * (Math.random() * 2 - 1);
89
90
  return Math.max(0, Math.floor(exp + jitter));
90
91
  }
92
+ /**
93
+ * True when a retryable error event carries a 429 rate-limit signal.
94
+ * Checks the `status` field first, then `code`; accepts numeric values
95
+ * and `'429'` substrings (e.g. `'429'`, `'HTTP_429'`).
96
+ */
97
+ function isRateLimitedError(ev) {
98
+ if (ev.kind !== 'error')
99
+ return false;
100
+ const rec = ev;
101
+ for (const key of ['status', 'code']) {
102
+ const value = rec[key];
103
+ if (typeof value === 'string' && value.includes('429'))
104
+ return true;
105
+ if (typeof value === 'number' && String(value).includes('429'))
106
+ return true;
107
+ }
108
+ return false;
109
+ }
110
+ function rateLimitDelayMs(ev) {
111
+ const raw = ev['retryAfterMs'];
112
+ return typeof raw === 'number' && Number.isFinite(raw) && raw >= 0 ? raw : undefined;
113
+ }
91
114
  export function retryingAdapter(inner, opts = {}) {
92
115
  const cfg = { ...DEFAULT_RETRY, ...opts };
93
116
  const sleep = opts.sleep ?? defaultSleep;
@@ -129,20 +152,39 @@ export function retryingAdapter(inner, opts = {}) {
129
152
  opts.onAttempt?.(attempt);
130
153
  if (effectiveSignal?.aborted)
131
154
  return;
155
+ // Rate-limit scheduler: hold one stream slot for the duration of
156
+ // this attempt's inner.stream consumption. Abort while queued ends
157
+ // the stream promptly with no inner call.
158
+ let release;
132
159
  let sawRetryable = false;
133
160
  let lastError = null;
134
- for await (const ev of streamWithAbort(inner.stream(attemptReq), effectiveSignal)) {
135
- if (effectiveSignal?.aborted)
161
+ try {
162
+ try {
163
+ release = await acquireStreamSlot(effectiveSignal);
164
+ }
165
+ catch {
136
166
  return;
137
- if (ev.kind === 'error' && ev.retryable) {
138
- // Buffer the retryable error; don't yield it yet. We'll either
139
- // re-issue (and the caller will never see the error) or, on
140
- // final attempt, yield it as the terminal error.
141
- sawRetryable = true;
142
- lastError = ev;
143
- break; // stop consuming; the stream is dead on retryable errors.
144
167
  }
145
- yield ev;
168
+ for await (const ev of streamWithAbort(inner.stream(attemptReq), effectiveSignal)) {
169
+ if (effectiveSignal?.aborted)
170
+ return;
171
+ if (ev.kind === 'error' && ev.retryable) {
172
+ // Adaptive throttling: a 429 collapses the global stream cap
173
+ // to 1 for retryAfterMs (or 60s) — see stream-budget.ts.
174
+ if (isRateLimitedError(ev))
175
+ noteRateLimited(rateLimitDelayMs(ev));
176
+ // Buffer the retryable error; don't yield it yet. We'll either
177
+ // re-issue (and the caller will never see the error) or, on
178
+ // final attempt, yield it as the terminal error.
179
+ sawRetryable = true;
180
+ lastError = ev;
181
+ break; // stop consuming; the stream is dead on retryable errors.
182
+ }
183
+ yield ev;
184
+ }
185
+ }
186
+ finally {
187
+ release?.();
146
188
  }
147
189
  if (!sawRetryable)
148
190
  return; // success or non-retryable error — done.
@@ -19,22 +19,58 @@ import type { Message } from './message.js';
19
19
  import type { ToolRegistry } from '../tools/registry.js';
20
20
  import type { PolicyEngine } from '../policy/engine.js';
21
21
  import type { ApprovalPrompt } from '../policy/approval.js';
22
+ /**
23
+ * Verification mode. The canonical definition lives in verification/engine.ts
24
+ * (sibling-owned: `export type VerifyMode = 'strict'|'advisory'|'off'`). It is
25
+ * resolved conditionally here so this file typechecks regardless of sibling
26
+ * landing order — and converges to the sibling type automatically once the
27
+ * sibling export exists.
28
+ */
29
+ export type VerifyMode = typeof import('../verification/engine.js') extends {
30
+ VerifyMode: infer V;
31
+ } ? V : 'strict' | 'advisory' | 'off';
22
32
  export interface RuntimeDeps {
23
33
  adapter: ProviderAdapter;
34
+ /**
35
+ * Ordered failover adapters (L15). When the active adapter ends a step
36
+ * with a terminal provider error, the runtime swaps to the next entry
37
+ * and re-issues the step (bounded by chain length, never loops).
38
+ * Optional — single-adapter callers behave exactly as before.
39
+ */
40
+ failoverAdapters?: ProviderAdapter[];
24
41
  registry: ToolRegistry;
25
42
  policy: PolicyEngine;
26
43
  approval: ApprovalPrompt;
27
44
  /**
28
45
  * Build a system prompt given cwd + the current Level-7 runtime telemetry.
29
- * The telemetry block is a compact, in-memory summary of the run so far
30
- * (step count, last tool calls, recent errors). Injected as part of the
31
- * system prompt so the model can see its own state mid-run.
46
+ *
47
+ * TELEMETRY SPLIT: the fn may return either a plain string (legacy —
48
+ * telemetry already concatenated, cache-unfriendly) or
49
+ * `{system, suffix}` where `suffix` is the volatile telemetry block.
50
+ * The runtime forwards both halves via CallRequest (`system` +
51
+ * `systemSuffix`) so adapters can keep the suffix out of the cacheable
52
+ * prefix (Anthropic array form) or concatenate it (OpenAI — unchanged).
53
+ * Both shapes are accepted so custom fns keep compiling.
32
54
  */
33
- systemPrompt: (ctx: {
34
- cwd: string;
35
- telemetry?: string;
36
- }) => string;
55
+ systemPrompt: SystemPromptFn;
37
56
  }
57
+ /** Split system-prompt result: stable prefix + volatile telemetry suffix. */
58
+ export interface SystemPromptResult {
59
+ system: string;
60
+ suffix?: string;
61
+ }
62
+ export type SystemPromptFn = (ctx: {
63
+ cwd: string;
64
+ telemetry?: string;
65
+ }) => string | SystemPromptResult;
66
+ /** Normalize either systemPrompt shape into {system, suffix}. */
67
+ export declare function resolveSystemPrompt(fn: SystemPromptFn, ctx: {
68
+ cwd: string;
69
+ telemetry?: string;
70
+ }): {
71
+ system: string;
72
+ suffix?: string;
73
+ };
38
74
  export type Phase = 'understanding' | 'exploring' | 'planning' | 'implementing' | 'verifying' | 'done' | 'blocked' | 'limit';
39
75
  export interface RunOptions {
40
76
  task: string;
@@ -77,6 +113,9 @@ export interface RunOptions {
77
113
  maxRepairAttempts?: number;
78
114
  timeoutMs?: number;
79
115
  requireVerify?: boolean;
116
+ /** Verification mode (default 'strict'). 'off' skips the pipeline;
117
+ * 'advisory' runs verify once on completion without repair turns. */
118
+ mode?: VerifyMode;
80
119
  };
81
120
  /**
82
121
  * Level 9 — persistence. When a SessionStore is provided, every message
@@ -99,6 +138,8 @@ export interface RunOptions {
99
138
  depth: number;
100
139
  maxDepth: number;
101
140
  allowedTools?: ReadonlySet<string>;
141
+ /** Path allow-set inherited from the parent (sibling C contract). */
142
+ allowedPaths?: readonly string[];
102
143
  model?: string;
103
144
  };
104
145
  /**
@@ -160,6 +201,8 @@ export type RuntimeEvent = {
160
201
  input: number;
161
202
  output: number;
162
203
  estimated?: boolean;
204
+ cacheRead?: number;
205
+ cacheWrite?: number;
163
206
  } | {
164
207
  kind: 'final_text';
165
208
  text: string;
@@ -190,6 +233,22 @@ export type RuntimeEvent = {
190
233
  } | {
191
234
  kind: 'checkpoint_saved';
192
235
  sessionId: string;
236
+ } | {
237
+ kind: 'status';
238
+ message: string;
239
+ } | {
240
+ kind: 'budget_warning';
241
+ ratio: number;
242
+ threshold: number;
243
+ } | {
244
+ kind: 'provider_failover';
245
+ from: string;
246
+ to: string;
247
+ reason: string;
248
+ } | {
249
+ kind: 'model_override';
250
+ requested: string;
251
+ effective: string;
193
252
  };
194
253
  export interface RunResult {
195
254
  status: 'complete' | 'max_steps' | 'aborted' | 'no_final' | 'verify_failed' | 'limit' | 'blocked' | 'stuck';
@@ -203,6 +262,8 @@ export interface RunResult {
203
262
  input: number;
204
263
  output: number;
205
264
  estimated?: boolean;
265
+ cacheRead?: number;
266
+ cacheWrite?: number;
206
267
  };
207
268
  /** Number of policy-driven user prompts the user accepted. */
208
269
  repairs?: number;
@@ -212,6 +273,10 @@ export interface RunResult {
212
273
  command?: string;
213
274
  attempts: number;
214
275
  failureType?: string;
276
+ repairTokens?: {
277
+ input: number;
278
+ output: number;
279
+ };
215
280
  };
216
281
  /** 5.1 phase */
217
282
  phase?: Phase;
@@ -222,10 +287,21 @@ export declare function toolDefinitions(registry: ToolRegistry): ToolDefinition[
222
287
  export declare function estimateCost(model: string, usage: {
223
288
  input: number;
224
289
  output: number;
290
+ cacheRead?: number;
291
+ cacheWrite?: number;
225
292
  }): number;
293
+ /**
294
+ * Parallel fan-out cap: approved concurrencySafe tool calls execute in
295
+ * sequential chunks of at most this size. Commit order stays identical
296
+ * (commits run sequentially after execution), so the transcript reads as
297
+ * if the calls ran in order.
298
+ */
299
+ export declare const MAX_PARALLEL_TOOLS = 8;
300
+ /** Progressive budget-warning thresholds (fraction of maxCost), fired once each per run. */
301
+ export declare const BUDGET_WARNING_THRESHOLDS: readonly [0.4, 0.7, 0.9];
226
302
  /** Run the autonomous loop. */
227
303
  export declare function run(opts: RunOptions, deps: RuntimeDeps): Promise<RunResult>;
228
304
  export declare function defaultSystemPrompt(ctx: {
229
305
  cwd: string;
230
306
  telemetry?: string;
231
- }): string;
307
+ }): SystemPromptResult;