@pimmesz/afterburner 1.0.1
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/.env.example +16 -0
- package/LICENSE +201 -0
- package/README.md +294 -0
- package/afterburner.config.example.ts +94 -0
- package/assets/afterburner-logo.png +0 -0
- package/dist/chunk-2NSOEZWY.js +11 -0
- package/dist/chunk-OZAFLQDP.js +1098 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +1524 -0
- package/dist/core/index.d.ts +781 -0
- package/dist/core/index.js +96 -0
- package/dist/mcp/server.d.ts +13 -0
- package/dist/mcp/server.js +8 -0
- package/package.json +75 -0
- package/skill/SKILL.md +38 -0
|
@@ -0,0 +1,781 @@
|
|
|
1
|
+
import { z, ZodError } from 'zod';
|
|
2
|
+
|
|
3
|
+
declare const configDir: string;
|
|
4
|
+
declare const dataDir: string;
|
|
5
|
+
declare function defaultRunStorePath(): string;
|
|
6
|
+
/**
|
|
7
|
+
* Claude Code's config directory. CLAUDE_CONFIG_DIR relocates the whole tree
|
|
8
|
+
* (settings.json, skills/, projects/), so everything that reads or writes
|
|
9
|
+
* under ~/.claude must honor it or it targets a directory Claude Code ignores.
|
|
10
|
+
*/
|
|
11
|
+
declare function claudeConfigDir(): string;
|
|
12
|
+
|
|
13
|
+
declare const TASK_CATEGORIES: readonly ["security", "tests", "types-lint", "dead-code", "perf", "infra", "docs"];
|
|
14
|
+
type TaskCategory = (typeof TASK_CATEGORIES)[number];
|
|
15
|
+
interface TaskCategoryInfo {
|
|
16
|
+
description: string;
|
|
17
|
+
/** How a human reviewer confirms the task is actually done. */
|
|
18
|
+
verifiabilityCheck: string;
|
|
19
|
+
}
|
|
20
|
+
declare const TASK_TAXONOMY: Record<TaskCategory, TaskCategoryInfo>;
|
|
21
|
+
|
|
22
|
+
declare const DEFAULT_MODEL_BY_CATEGORY: Record<TaskCategory, string>;
|
|
23
|
+
declare const repoConfigSchema: z.ZodObject<{
|
|
24
|
+
url: z.ZodString;
|
|
25
|
+
defaultBranch: z.ZodDefault<z.ZodString>;
|
|
26
|
+
branchPrefix: z.ZodDefault<z.ZodString>;
|
|
27
|
+
enabledTaskCategories: z.ZodArray<z.ZodEnum<{
|
|
28
|
+
security: "security";
|
|
29
|
+
tests: "tests";
|
|
30
|
+
"types-lint": "types-lint";
|
|
31
|
+
"dead-code": "dead-code";
|
|
32
|
+
perf: "perf";
|
|
33
|
+
infra: "infra";
|
|
34
|
+
docs: "docs";
|
|
35
|
+
}>>;
|
|
36
|
+
}, z.core.$strip>;
|
|
37
|
+
declare const budgetConfigSchema: z.ZodPrefault<z.ZodObject<{
|
|
38
|
+
provider: z.ZodDefault<z.ZodEnum<{
|
|
39
|
+
manual: "manual";
|
|
40
|
+
"claude-code-transcripts": "claude-code-transcripts";
|
|
41
|
+
"claude-usage": "claude-usage";
|
|
42
|
+
}>>;
|
|
43
|
+
weeklyAllowanceSonnetTokens: z.ZodDefault<z.ZodNumber>;
|
|
44
|
+
usageCacheMaxAgeHours: z.ZodDefault<z.ZodNumber>;
|
|
45
|
+
minWeeklyHeadroomPct: z.ZodDefault<z.ZodNumber>;
|
|
46
|
+
safetyMarginTokens: z.ZodDefault<z.ZodNumber>;
|
|
47
|
+
requireSessionAvailable: z.ZodDefault<z.ZodBoolean>;
|
|
48
|
+
manual: z.ZodDefault<z.ZodObject<{
|
|
49
|
+
sessionAvailable: z.ZodDefault<z.ZodBoolean>;
|
|
50
|
+
weeklyRemainingPct: z.ZodDefault<z.ZodNumber>;
|
|
51
|
+
weeklyRemainingTokensEst: z.ZodDefault<z.ZodNumber>;
|
|
52
|
+
}, z.core.$strip>>;
|
|
53
|
+
}, z.core.$strip>>;
|
|
54
|
+
declare const agentConfigSchema: z.ZodPrefault<z.ZodObject<{
|
|
55
|
+
backend: z.ZodDefault<z.ZodEnum<{
|
|
56
|
+
"dry-run": "dry-run";
|
|
57
|
+
"claude-code": "claude-code";
|
|
58
|
+
"api-key": "api-key";
|
|
59
|
+
}>>;
|
|
60
|
+
modelByCategory: z.ZodPipe<z.ZodDefault<z.ZodRecord<z.ZodEnum<{
|
|
61
|
+
security: "security";
|
|
62
|
+
tests: "tests";
|
|
63
|
+
"types-lint": "types-lint";
|
|
64
|
+
"dead-code": "dead-code";
|
|
65
|
+
perf: "perf";
|
|
66
|
+
infra: "infra";
|
|
67
|
+
docs: "docs";
|
|
68
|
+
}> & z.core.$partial, z.ZodString>>, z.ZodTransform<{
|
|
69
|
+
security: string;
|
|
70
|
+
tests: string;
|
|
71
|
+
"types-lint": string;
|
|
72
|
+
"dead-code": string;
|
|
73
|
+
perf: string;
|
|
74
|
+
infra: string;
|
|
75
|
+
docs: string;
|
|
76
|
+
}, Partial<Record<"security" | "tests" | "types-lint" | "dead-code" | "perf" | "infra" | "docs", string>>>>;
|
|
77
|
+
maxTaskTokens: z.ZodDefault<z.ZodNumber>;
|
|
78
|
+
allowFable: z.ZodDefault<z.ZodBoolean>;
|
|
79
|
+
}, z.core.$strip>>;
|
|
80
|
+
declare const configSchema: z.ZodObject<{
|
|
81
|
+
repos: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
82
|
+
url: z.ZodString;
|
|
83
|
+
defaultBranch: z.ZodDefault<z.ZodString>;
|
|
84
|
+
branchPrefix: z.ZodDefault<z.ZodString>;
|
|
85
|
+
enabledTaskCategories: z.ZodArray<z.ZodEnum<{
|
|
86
|
+
security: "security";
|
|
87
|
+
tests: "tests";
|
|
88
|
+
"types-lint": "types-lint";
|
|
89
|
+
"dead-code": "dead-code";
|
|
90
|
+
perf: "perf";
|
|
91
|
+
infra: "infra";
|
|
92
|
+
docs: "docs";
|
|
93
|
+
}>>;
|
|
94
|
+
}, z.core.$strip>>>;
|
|
95
|
+
budget: z.ZodPrefault<z.ZodObject<{
|
|
96
|
+
provider: z.ZodDefault<z.ZodEnum<{
|
|
97
|
+
manual: "manual";
|
|
98
|
+
"claude-code-transcripts": "claude-code-transcripts";
|
|
99
|
+
"claude-usage": "claude-usage";
|
|
100
|
+
}>>;
|
|
101
|
+
weeklyAllowanceSonnetTokens: z.ZodDefault<z.ZodNumber>;
|
|
102
|
+
usageCacheMaxAgeHours: z.ZodDefault<z.ZodNumber>;
|
|
103
|
+
minWeeklyHeadroomPct: z.ZodDefault<z.ZodNumber>;
|
|
104
|
+
safetyMarginTokens: z.ZodDefault<z.ZodNumber>;
|
|
105
|
+
requireSessionAvailable: z.ZodDefault<z.ZodBoolean>;
|
|
106
|
+
manual: z.ZodDefault<z.ZodObject<{
|
|
107
|
+
sessionAvailable: z.ZodDefault<z.ZodBoolean>;
|
|
108
|
+
weeklyRemainingPct: z.ZodDefault<z.ZodNumber>;
|
|
109
|
+
weeklyRemainingTokensEst: z.ZodDefault<z.ZodNumber>;
|
|
110
|
+
}, z.core.$strip>>;
|
|
111
|
+
}, z.core.$strip>>;
|
|
112
|
+
schedule: z.ZodPrefault<z.ZodObject<{
|
|
113
|
+
cron: z.ZodDefault<z.ZodString>;
|
|
114
|
+
timezone: z.ZodDefault<z.ZodString>;
|
|
115
|
+
}, z.core.$strip>>;
|
|
116
|
+
agent: z.ZodPrefault<z.ZodObject<{
|
|
117
|
+
backend: z.ZodDefault<z.ZodEnum<{
|
|
118
|
+
"dry-run": "dry-run";
|
|
119
|
+
"claude-code": "claude-code";
|
|
120
|
+
"api-key": "api-key";
|
|
121
|
+
}>>;
|
|
122
|
+
modelByCategory: z.ZodPipe<z.ZodDefault<z.ZodRecord<z.ZodEnum<{
|
|
123
|
+
security: "security";
|
|
124
|
+
tests: "tests";
|
|
125
|
+
"types-lint": "types-lint";
|
|
126
|
+
"dead-code": "dead-code";
|
|
127
|
+
perf: "perf";
|
|
128
|
+
infra: "infra";
|
|
129
|
+
docs: "docs";
|
|
130
|
+
}> & z.core.$partial, z.ZodString>>, z.ZodTransform<{
|
|
131
|
+
security: string;
|
|
132
|
+
tests: string;
|
|
133
|
+
"types-lint": string;
|
|
134
|
+
"dead-code": string;
|
|
135
|
+
perf: string;
|
|
136
|
+
infra: string;
|
|
137
|
+
docs: string;
|
|
138
|
+
}, Partial<Record<"security" | "tests" | "types-lint" | "dead-code" | "perf" | "infra" | "docs", string>>>>;
|
|
139
|
+
maxTaskTokens: z.ZodDefault<z.ZodNumber>;
|
|
140
|
+
allowFable: z.ZodDefault<z.ZodBoolean>;
|
|
141
|
+
}, z.core.$strip>>;
|
|
142
|
+
taskCategories: z.ZodPipe<z.ZodDefault<z.ZodRecord<z.ZodEnum<{
|
|
143
|
+
security: "security";
|
|
144
|
+
tests: "tests";
|
|
145
|
+
"types-lint": "types-lint";
|
|
146
|
+
"dead-code": "dead-code";
|
|
147
|
+
perf: "perf";
|
|
148
|
+
infra: "infra";
|
|
149
|
+
docs: "docs";
|
|
150
|
+
}> & z.core.$partial, z.ZodObject<{
|
|
151
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
152
|
+
weight: z.ZodDefault<z.ZodNumber>;
|
|
153
|
+
}, z.core.$strip>>>, z.ZodTransform<{
|
|
154
|
+
security: {
|
|
155
|
+
enabled: boolean;
|
|
156
|
+
weight: number;
|
|
157
|
+
};
|
|
158
|
+
tests: {
|
|
159
|
+
enabled: boolean;
|
|
160
|
+
weight: number;
|
|
161
|
+
};
|
|
162
|
+
"types-lint": {
|
|
163
|
+
enabled: boolean;
|
|
164
|
+
weight: number;
|
|
165
|
+
};
|
|
166
|
+
"dead-code": {
|
|
167
|
+
enabled: boolean;
|
|
168
|
+
weight: number;
|
|
169
|
+
};
|
|
170
|
+
perf: {
|
|
171
|
+
enabled: boolean;
|
|
172
|
+
weight: number;
|
|
173
|
+
};
|
|
174
|
+
infra: {
|
|
175
|
+
enabled: boolean;
|
|
176
|
+
weight: number;
|
|
177
|
+
};
|
|
178
|
+
docs: {
|
|
179
|
+
enabled: boolean;
|
|
180
|
+
weight: number;
|
|
181
|
+
};
|
|
182
|
+
}, Partial<Record<"security" | "tests" | "types-lint" | "dead-code" | "perf" | "infra" | "docs", {
|
|
183
|
+
enabled: boolean;
|
|
184
|
+
weight: number;
|
|
185
|
+
}>>>>;
|
|
186
|
+
}, z.core.$strip>;
|
|
187
|
+
type AfterburnerConfig = z.output<typeof configSchema>;
|
|
188
|
+
type AfterburnerUserConfig = z.input<typeof configSchema>;
|
|
189
|
+
type RepoConfig = z.output<typeof repoConfigSchema>;
|
|
190
|
+
type BudgetConfig = z.output<typeof budgetConfigSchema>;
|
|
191
|
+
type AgentConfig = z.output<typeof agentConfigSchema>;
|
|
192
|
+
/** Identity helper so user configs get full type checking and completion. */
|
|
193
|
+
declare function defineConfig(config: AfterburnerUserConfig): AfterburnerUserConfig;
|
|
194
|
+
|
|
195
|
+
interface LoadedConfig {
|
|
196
|
+
config: AfterburnerConfig;
|
|
197
|
+
filepath: string;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Loads config via cosmiconfig: explicit path > search from cwd > the global
|
|
201
|
+
* config dir (env-paths). cosmiconfig v9 loads .ts configs natively, but only
|
|
202
|
+
* when the `typescript` package is importable at runtime, true in a project
|
|
203
|
+
* that has typescript installed, false after a bare global CLI install. We
|
|
204
|
+
* keep the defaults and rewrite that failure into an actionable error instead
|
|
205
|
+
* of adding a runtime TypeScript dependency.
|
|
206
|
+
*/
|
|
207
|
+
declare function loadConfig(explicitPath?: string): Promise<LoadedConfig>;
|
|
208
|
+
/** Exported for unit tests: rewrites known loader failures into actionable errors. */
|
|
209
|
+
declare function mapConfigLoadError(error: unknown): Error;
|
|
210
|
+
declare function formatConfigError(error: ZodError, filepath: string): string;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* The single source of truth for budget math. ALL budget quantities in
|
|
214
|
+
* Afterburner are expressed in Sonnet-equivalent tokens, normalized through
|
|
215
|
+
* this table. Nothing outside this module may hardcode a model rate.
|
|
216
|
+
*
|
|
217
|
+
* Weights are relative cost factors with Sonnet = 1.0, derived from the
|
|
218
|
+
* published per-MTok API prices (verified 2026-06-11 at
|
|
219
|
+
* https://platform.claude.com/docs/en/about-claude/pricing):
|
|
220
|
+
* Haiku $1/$5, Sonnet $3/$15, Opus $5/$25, Fable $10/$50, input and output
|
|
221
|
+
* ratios are identical, so a single factor per model family suffices. The 1M
|
|
222
|
+
* context window is included at standard pricing, so there is no separate
|
|
223
|
+
* long-context weight. Anthropic publishes no numeric subscription-limit
|
|
224
|
+
* weighting between models (the docs are qualitative only), so these
|
|
225
|
+
* price-derived factors are the best documented proxy.
|
|
226
|
+
*/
|
|
227
|
+
interface ModelCostTable {
|
|
228
|
+
/** Relative cost weight for a model id (longest-prefix match). Throws on unknown models. */
|
|
229
|
+
weightFor(modelId: string): number;
|
|
230
|
+
/** Convert raw tokens spent on `modelId` into Sonnet-equivalent tokens. */
|
|
231
|
+
toSonnetTokens(tokens: number, modelId: string): number;
|
|
232
|
+
}
|
|
233
|
+
type ModelWeightEntry = readonly [prefix: string, weight: number];
|
|
234
|
+
declare function createModelCostTable(weights?: readonly ModelWeightEntry[]): ModelCostTable;
|
|
235
|
+
declare const defaultCostTable: ModelCostTable;
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Premium-model gate (still named the "Fable gate" / `allowFable` for the
|
|
239
|
+
* config key). Matches by model-family prefix (not exact id) so new releases in
|
|
240
|
+
* a gated family stay gated without a code change. It covers every top-tier,
|
|
241
|
+
* real-money family the cost table prices at ~2x Opus, currently Fable and
|
|
242
|
+
* Mythos, by reading PREMIUM_MODEL_PREFIXES from the cost table, so the gate
|
|
243
|
+
* and the cost weights can never drift apart. An autonomous run must never
|
|
244
|
+
* reach one of these models without the explicit `agent.allowFable` opt-in,
|
|
245
|
+
* since outside promotional windows they bill usage credits at API rates and
|
|
246
|
+
* would let an unattended scheduler silently spend real money.
|
|
247
|
+
*/
|
|
248
|
+
declare function isFableModel(modelId: string): boolean;
|
|
249
|
+
declare function assertModelAllowed(modelId: string, allowFable: boolean): void;
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Budget snapshot of the user's Claude subscription headroom.
|
|
253
|
+
*
|
|
254
|
+
* There is no official API that exposes remaining subscription quota, so every
|
|
255
|
+
* provider is estimate-driven. The fields model the two caps a subscription
|
|
256
|
+
* has: the rolling 5-hour session cap and the weekly cap (what `/usage` shows
|
|
257
|
+
* inside Claude Code). Token amounts are Sonnet-equivalent (see ModelCostTable).
|
|
258
|
+
*
|
|
259
|
+
* Billing nuance (verified 2026-06-11): from June 15, 2026 headless
|
|
260
|
+
* `claude -p` / Agent SDK usage on subscription plans draws from a separate
|
|
261
|
+
* monthly "Agent SDK credit" rather than the interactive weekly limits.
|
|
262
|
+
* Afterburner still models the interactive limits the user actually watches;
|
|
263
|
+
* see README "The economics" for what that means per backend.
|
|
264
|
+
*/
|
|
265
|
+
interface Budget {
|
|
266
|
+
/** Is a 5-hour session window currently available? */
|
|
267
|
+
sessionAvailable: boolean;
|
|
268
|
+
/** Remaining share of the weekly cap, 0–100. */
|
|
269
|
+
weeklyRemainingPct: number;
|
|
270
|
+
/** Estimated remaining weekly budget in Sonnet-equivalent tokens. */
|
|
271
|
+
weeklyRemainingTokensEst: number;
|
|
272
|
+
}
|
|
273
|
+
interface BudgetProvider {
|
|
274
|
+
getBudget(): Promise<Budget>;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Budget values supplied by the user (config `budget.manual` or CLI flags).
|
|
279
|
+
* The reference provider for testing and the default until a reliable
|
|
280
|
+
* automated source for subscription usage exists.
|
|
281
|
+
*/
|
|
282
|
+
declare class ManualBudgetProvider implements BudgetProvider {
|
|
283
|
+
private readonly budget;
|
|
284
|
+
constructor(budget: Budget);
|
|
285
|
+
getBudget(): Promise<Budget>;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Automatic budget provider: derives weekly SPENT tokens from the local
|
|
290
|
+
* Claude Code session transcripts (~/.claude/projects/<project>/<session>.jsonl)
|
|
291
|
+
* and subtracts them from a configured weekly allowance.
|
|
292
|
+
*
|
|
293
|
+
* Why transcripts: there is no documented headless command that exposes the
|
|
294
|
+
* `/usage` panel data, and ~/.claude/stats-cache.json can be months stale.
|
|
295
|
+
* Transcripts are written live by every Claude Code session, so they are the
|
|
296
|
+
* one local source that is always current. The same approach is used by
|
|
297
|
+
* community tools like ccusage.
|
|
298
|
+
*
|
|
299
|
+
* TODO(unverified): the transcript JSONL format is undocumented. Verified
|
|
300
|
+
* empirically against Claude Code 2.1.173 (2026-06-11): assistant entries
|
|
301
|
+
* carry `timestamp` (ISO 8601), `message.model`, `message.id`, and
|
|
302
|
+
* `message.usage` with `input_tokens` / `output_tokens` /
|
|
303
|
+
* `cache_creation_input_tokens` / `cache_read_input_tokens`. Parsing is
|
|
304
|
+
* defensive, unknown shapes are skipped, never fatal.
|
|
305
|
+
*
|
|
306
|
+
* Counting convention: input_tokens + output_tokens per assistant message
|
|
307
|
+
* (cache reads/writes excluded). This matches Claude Code's own
|
|
308
|
+
* stats aggregation and avoids cache traffic dwarfing the numbers. The weekly
|
|
309
|
+
* cap itself is not exposed anywhere locally, so `weeklyAllowanceSonnetTokens`
|
|
310
|
+
* stays a one-time calibration against what /usage shows for your plan.
|
|
311
|
+
*/
|
|
312
|
+
interface TranscriptUsageSummary {
|
|
313
|
+
/** Sonnet-equivalent tokens spent inside the window. */
|
|
314
|
+
spentSonnetTokens: number;
|
|
315
|
+
/** Raw tokens per model id, for diagnostics. */
|
|
316
|
+
tokensByModel: Record<string, number>;
|
|
317
|
+
/** Number of assistant messages counted (after dedup). */
|
|
318
|
+
messagesCounted: number;
|
|
319
|
+
}
|
|
320
|
+
declare function defaultClaudeProjectsDir(): string;
|
|
321
|
+
interface ClaudeCodeTranscriptsOptions {
|
|
322
|
+
/** Estimated total weekly capacity in Sonnet-equivalent tokens (calibrate against /usage). */
|
|
323
|
+
weeklyAllowanceSonnetTokens: number;
|
|
324
|
+
costTable: ModelCostTable;
|
|
325
|
+
/**
|
|
326
|
+
* The 5-hour session cap cannot be derived from local data (the limit value
|
|
327
|
+
* is not exposed), so session availability stays a manual input.
|
|
328
|
+
*/
|
|
329
|
+
sessionAvailable: boolean;
|
|
330
|
+
/** Rolling window; the weekly reset anchor is unknown, so 7 rolling days is the conservative read. */
|
|
331
|
+
windowDays?: number;
|
|
332
|
+
projectsDir?: string;
|
|
333
|
+
}
|
|
334
|
+
declare class ClaudeCodeTranscriptsBudgetProvider implements BudgetProvider {
|
|
335
|
+
private readonly opts;
|
|
336
|
+
constructor(opts: ClaudeCodeTranscriptsOptions);
|
|
337
|
+
getBudget(): Promise<Budget>;
|
|
338
|
+
}
|
|
339
|
+
/** Exported separately so the scan/dedup/conversion logic is unit-testable. */
|
|
340
|
+
declare function summarizeTranscriptUsage(projectsDir: string, since: Date, costTable: ModelCostTable): Promise<TranscriptUsageSummary>;
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Local mirror of the `rate_limits` object Claude Code pipes to a statusLine
|
|
344
|
+
* command on stdin (verified against the Claude Code statusline docs,
|
|
345
|
+
* 2026-06-11): each window is optional and present only for Pro/Max
|
|
346
|
+
* subscribers after the first API response in a session.
|
|
347
|
+
* rate_limits.five_hour.used_percentage (0–100)
|
|
348
|
+
* rate_limits.five_hour.resets_at (unix epoch SECONDS)
|
|
349
|
+
* rate_limits.seven_day.{used_percentage,resets_at}
|
|
350
|
+
*/
|
|
351
|
+
interface RateLimitWindow {
|
|
352
|
+
used_percentage?: number;
|
|
353
|
+
resets_at?: number;
|
|
354
|
+
}
|
|
355
|
+
interface RateLimits {
|
|
356
|
+
five_hour?: RateLimitWindow;
|
|
357
|
+
seven_day?: RateLimitWindow;
|
|
358
|
+
}
|
|
359
|
+
interface UsageCache {
|
|
360
|
+
/** ISO 8601 timestamp of when the statusLine hook captured this. */
|
|
361
|
+
capturedAt: string;
|
|
362
|
+
rateLimits: RateLimits;
|
|
363
|
+
/** model.display_name at capture time, for diagnostics. */
|
|
364
|
+
model?: string;
|
|
365
|
+
}
|
|
366
|
+
declare function defaultUsageCachePath(): string;
|
|
367
|
+
declare function readUsageCache(path?: string): Promise<UsageCache | null>;
|
|
368
|
+
declare function writeUsageCache(path: string, cache: UsageCache): Promise<void>;
|
|
369
|
+
interface UsageCacheBudgetOptions {
|
|
370
|
+
/** Total weekly capacity in Sonnet-equivalent tokens, maps the authoritative % to a token figure. */
|
|
371
|
+
weeklyAllowanceSonnetTokens: number;
|
|
372
|
+
/** Cache older than this is treated as unusable (fall back). */
|
|
373
|
+
maxAgeMs: number;
|
|
374
|
+
}
|
|
375
|
+
interface UsageCacheBudgetResult {
|
|
376
|
+
budget?: Budget;
|
|
377
|
+
/** Present when the cache can't yield a usable budget and the caller should fall back. */
|
|
378
|
+
fallbackReason?: string;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Maps a usage cache to a Budget, using the `resets_at` timestamps to reason
|
|
382
|
+
* about staleness so an old cache is self-correcting:
|
|
383
|
+
*
|
|
384
|
+
* - Weekly cap gates spend, so be conservative: if the cache is older than
|
|
385
|
+
* maxAge, or its weekly window has already reset since capture (so the
|
|
386
|
+
* cached % no longer reflects the current window), fall back to the
|
|
387
|
+
* transcript estimate rather than trust a possibly-optimistic number.
|
|
388
|
+
* - The 5-hour session cap is a boolean: if its window has reset
|
|
389
|
+
* (now ≥ resets_at) the session is available again regardless of the old %;
|
|
390
|
+
* otherwise it's available unless that window is maxed.
|
|
391
|
+
*
|
|
392
|
+
* Pure and deterministic (nowMs injected) so the freshness logic is testable.
|
|
393
|
+
*/
|
|
394
|
+
declare function budgetFromUsageCache(cache: UsageCache, opts: UsageCacheBudgetOptions, nowMs: number): UsageCacheBudgetResult;
|
|
395
|
+
|
|
396
|
+
interface ClaudeUsageBudgetOptions {
|
|
397
|
+
weeklyAllowanceSonnetTokens: number;
|
|
398
|
+
maxAgeMs: number;
|
|
399
|
+
/** Used when the usage cache is missing, stale, or incomplete. */
|
|
400
|
+
fallback: BudgetProvider;
|
|
401
|
+
cachePath?: string;
|
|
402
|
+
/** Called with a human-readable reason whenever it falls back. */
|
|
403
|
+
onFallback?: (reason: string) => void;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Reads the authoritative subscription usage figures (5h/7d % + reset times)
|
|
407
|
+
* that Claude Code captures into the usage cache via the statusLine hook
|
|
408
|
+
* (`afterburner statusline install`). Falls back to the supplied provider
|
|
409
|
+
* (normally the transcript estimate) whenever the cache can't be used, so an
|
|
410
|
+
* autonomous run never blocks on a missing or stale cache.
|
|
411
|
+
*/
|
|
412
|
+
declare class ClaudeUsageBudgetProvider implements BudgetProvider {
|
|
413
|
+
private readonly opts;
|
|
414
|
+
private readonly cachePath;
|
|
415
|
+
constructor(opts: ClaudeUsageBudgetOptions);
|
|
416
|
+
getBudget(): Promise<Budget>;
|
|
417
|
+
private fallBack;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
interface BudgetProviderOptions {
|
|
421
|
+
/** Optional sink for diagnostic notes (e.g. "usage cache stale; falling back"). */
|
|
422
|
+
onNote?: (message: string) => void;
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Picks the budget source from config:
|
|
426
|
+
* - 'manual': the values in budget.manual (and/or run-once flags).
|
|
427
|
+
* - 'claude-code-transcripts': spend computed from local Claude Code transcripts.
|
|
428
|
+
* - 'claude-usage': the authoritative subscription limits Claude Code captures
|
|
429
|
+
* via the statusLine hook, with the transcript estimate as fallback.
|
|
430
|
+
* Session availability is a manual input for the non-statusLine providers (the
|
|
431
|
+
* 5-hour cap can't be derived from local data).
|
|
432
|
+
*/
|
|
433
|
+
declare function createBudgetProvider(config: AfterburnerConfig, opts?: BudgetProviderOptions): {
|
|
434
|
+
provider: BudgetProvider;
|
|
435
|
+
source: string;
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
interface TaskIdentity {
|
|
439
|
+
repoUrl: string;
|
|
440
|
+
category: TaskCategory;
|
|
441
|
+
/** Target path or finding identifier, whatever makes the task unique. */
|
|
442
|
+
target: string;
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Deterministic task identity: a stable hash of (repo, category, target).
|
|
446
|
+
* Branch names and PR titles derive from it, the run store records it, and
|
|
447
|
+
* idempotency is enforced by refusing to re-run a fingerprint that already
|
|
448
|
+
* has an open or merged PR. The repo url is normalized first so the identity
|
|
449
|
+
* survives a config rewrite from a relative path to the absolute one (and two
|
|
450
|
+
* different repos reached via the same relative url can't collide).
|
|
451
|
+
*/
|
|
452
|
+
declare function taskFingerprint(id: TaskIdentity): string;
|
|
453
|
+
declare function deriveBranchName(task: {
|
|
454
|
+
category: TaskCategory;
|
|
455
|
+
fingerprint: string;
|
|
456
|
+
}, branchPrefix: string): string;
|
|
457
|
+
declare function derivePrTitle(task: {
|
|
458
|
+
title: string;
|
|
459
|
+
fingerprint: string;
|
|
460
|
+
}): string;
|
|
461
|
+
|
|
462
|
+
interface CandidateTask {
|
|
463
|
+
repoUrl: string;
|
|
464
|
+
category: TaskCategory;
|
|
465
|
+
title: string;
|
|
466
|
+
/** Target path or finding identifier, the unique subject of the task. */
|
|
467
|
+
target: string;
|
|
468
|
+
/** Estimated cost in Sonnet-equivalent tokens (via ModelCostTable). */
|
|
469
|
+
estCostSonnetTokens: number;
|
|
470
|
+
fingerprint: string;
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* The replacement seam for a future Claude-powered ranker: exactly what the
|
|
474
|
+
* orchestrator consumes. (DeterministicTaskSelector also exposes a public
|
|
475
|
+
* rank() for inspection and tests, but implementations only owe select().)
|
|
476
|
+
*/
|
|
477
|
+
interface TaskSelector {
|
|
478
|
+
/** Highest-value candidate that fits within the budget minus the safety margin. */
|
|
479
|
+
select(repo: RepoConfig, budget: Budget): Promise<CandidateTask | null>;
|
|
480
|
+
}
|
|
481
|
+
interface DeterministicSelectorOptions {
|
|
482
|
+
costTable: ModelCostTable;
|
|
483
|
+
modelByCategory: Record<TaskCategory, string>;
|
|
484
|
+
taskCategories: Record<TaskCategory, {
|
|
485
|
+
enabled: boolean;
|
|
486
|
+
weight: number;
|
|
487
|
+
}>;
|
|
488
|
+
safetyMarginTokens: number;
|
|
489
|
+
maxTaskTokens: number;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Rough per-task spend in the routed model's own tokens; converted to
|
|
493
|
+
* Sonnet-equivalent through the ModelCostTable at estimation time. These are
|
|
494
|
+
* deliberately coarse, the selector's judgment is the part designed to be
|
|
495
|
+
* replaced by a Claude-powered ranker later.
|
|
496
|
+
*/
|
|
497
|
+
declare const BASE_TASK_TOKENS: Record<TaskCategory, number>;
|
|
498
|
+
/**
|
|
499
|
+
* The one way run-once, watch, and tests derive selector options from config,
|
|
500
|
+
* so they can never drift (mirrors createBudgetProvider / createRunner).
|
|
501
|
+
*/
|
|
502
|
+
declare function createSelector(config: {
|
|
503
|
+
agent: {
|
|
504
|
+
modelByCategory: Record<TaskCategory, string>;
|
|
505
|
+
maxTaskTokens: number;
|
|
506
|
+
};
|
|
507
|
+
budget: {
|
|
508
|
+
safetyMarginTokens: number;
|
|
509
|
+
};
|
|
510
|
+
taskCategories: Record<TaskCategory, {
|
|
511
|
+
enabled: boolean;
|
|
512
|
+
weight: number;
|
|
513
|
+
}>;
|
|
514
|
+
}): DeterministicTaskSelector;
|
|
515
|
+
/**
|
|
516
|
+
* Deterministic, no-LLM selector: cheap static heuristics over a local
|
|
517
|
+
* checkout. Designed so a Claude-powered ranker can drop in behind the same
|
|
518
|
+
* TaskSelector interface later.
|
|
519
|
+
*/
|
|
520
|
+
declare class DeterministicTaskSelector implements TaskSelector {
|
|
521
|
+
private readonly opts;
|
|
522
|
+
constructor(opts: DeterministicSelectorOptions);
|
|
523
|
+
rank(repo: RepoConfig, _budget: Budget): Promise<CandidateTask[]>;
|
|
524
|
+
select(repo: RepoConfig, budget: Budget): Promise<CandidateTask | null>;
|
|
525
|
+
private isCategoryEnabled;
|
|
526
|
+
/** Estimate flows through the ModelCostTable using the category's ROUTED model. */
|
|
527
|
+
private estimate;
|
|
528
|
+
private makeTask;
|
|
529
|
+
private docsCandidates;
|
|
530
|
+
private testGapCandidates;
|
|
531
|
+
private deadCodeCandidates;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
type RunnerBackend = 'dry-run' | 'claude-code' | 'api-key';
|
|
535
|
+
type RunOutcome = 'dry-run' | 'pr-opened' | 'abandoned' | 'failed';
|
|
536
|
+
interface RunResult {
|
|
537
|
+
outcome: RunOutcome;
|
|
538
|
+
/** Always claude/-prefixed; never the default branch. */
|
|
539
|
+
branch: string;
|
|
540
|
+
prTitle: string;
|
|
541
|
+
prUrl?: string;
|
|
542
|
+
summary: string;
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* Executes ONE bounded task against a repo. Live backends commit only to a
|
|
546
|
+
* claude/-prefixed branch and open a PR, never push to the default branch,
|
|
547
|
+
* never merge. A killed run must leave a resumable claude/ branch, never a
|
|
548
|
+
* broken state.
|
|
549
|
+
*/
|
|
550
|
+
interface AgentRunner {
|
|
551
|
+
readonly backend: RunnerBackend;
|
|
552
|
+
run(task: CandidateTask, repo: RepoConfig): Promise<RunResult>;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/** The default backend: reports exactly what a live run WOULD do. No side effects. */
|
|
556
|
+
declare class DryRunRunner implements AgentRunner {
|
|
557
|
+
readonly backend: "dry-run";
|
|
558
|
+
run(task: CandidateTask, repo: RepoConfig): Promise<RunResult>;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Recommended live backend (stub): wraps Claude Code headless using the
|
|
563
|
+
* user's locally authenticated subscription, preserving the leftover-quota
|
|
564
|
+
* economics.
|
|
565
|
+
*
|
|
566
|
+
* Verified invocation surface (https://code.claude.com/docs/en/headless.md and
|
|
567
|
+
* /en/cli-reference.md, 2026-06-11):
|
|
568
|
+
* claude -p --output-format json --permission-mode acceptEdits \
|
|
569
|
+
* --allowedTools "…" --max-turns N --model <routed-model>
|
|
570
|
+
* - JSON output carries `result`, `session_id`, and `total_cost_usd`.
|
|
571
|
+
* - Subscription OAuth credentials (from `claude /login`, or a
|
|
572
|
+
* `claude setup-token` → CLAUDE_CODE_OAUTH_TOKEN in CI) are the default
|
|
573
|
+
* auth for `-p`.
|
|
574
|
+
* - NEVER pass --bare: it skips OAuth/keychain reads, breaking subscription
|
|
575
|
+
* auth. Docs say --bare will become the `-p` default in a future release,
|
|
576
|
+
* revisit this invocation when that lands.
|
|
577
|
+
*
|
|
578
|
+
* TODO(unverified): exact prompt template, tool allowlist, and the PR-creation
|
|
579
|
+
* step (gh/glab vs API) are not implemented yet, live execution is out of
|
|
580
|
+
* scope for the scaffold.
|
|
581
|
+
*/
|
|
582
|
+
declare class ClaudeCodeRunner implements AgentRunner {
|
|
583
|
+
readonly backend: "claude-code";
|
|
584
|
+
run(_task: CandidateTask, _repo: RepoConfig): Promise<RunResult>;
|
|
585
|
+
}
|
|
586
|
+
interface ClaudeCodeInvocation {
|
|
587
|
+
command: 'claude';
|
|
588
|
+
/** Fixed flags only, untrusted text never lands in argv. */
|
|
589
|
+
args: string[];
|
|
590
|
+
/** Sanitized child environment. */
|
|
591
|
+
env: Record<string, string | undefined>;
|
|
592
|
+
/** The task prompt, delivered via stdin. */
|
|
593
|
+
stdinPrompt: string;
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* Pure builder for the headless invocation, kept separate from the stub so the
|
|
597
|
+
* injection-safety properties are unit-testable today.
|
|
598
|
+
*
|
|
599
|
+
* Injection class defended against: repo contents, issue titles, PR bodies and
|
|
600
|
+
* comments are UNTRUSTED input. Interpolating them into a shell command string
|
|
601
|
+
* (or a CI `run:` block) lets `$(…)`, backticks or quote-breaking text execute
|
|
602
|
+
* arbitrary commands. Defense: spawn with an argv array (no shell), keep argv
|
|
603
|
+
* limited to fixed flags, and deliver all untrusted text via stdin and
|
|
604
|
+
* environment variables that the child reads through process.env.
|
|
605
|
+
*/
|
|
606
|
+
declare function buildClaudeCodeInvocation(task: CandidateTask, repo: RepoConfig, opts: {
|
|
607
|
+
model: string;
|
|
608
|
+
maxTurns: number;
|
|
609
|
+
allowedTools: readonly string[];
|
|
610
|
+
}): ClaudeCodeInvocation;
|
|
611
|
+
/**
|
|
612
|
+
* Strip API-key auth from the child environment. Verified behavior
|
|
613
|
+
* (code.claude.com/docs/en/authentication.md, 2026-06-11): in `-p` mode a
|
|
614
|
+
* present ANTHROPIC_API_KEY is ALWAYS used and outranks the subscription
|
|
615
|
+
* login, a leftover exported key would silently bill the API instead of
|
|
616
|
+
* spending subscription quota. CLAUDE_CODE_OAUTH_TOKEN is kept: it IS
|
|
617
|
+
* subscription auth (the documented CI path).
|
|
618
|
+
*/
|
|
619
|
+
declare function sanitizeSpawnEnv(env: Record<string, string | undefined>): Record<string, string | undefined>;
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* Universal fallback backend (interface stub only): drives the task through
|
|
623
|
+
* the Anthropic API with an API key. Unlike the claude-code backend this is
|
|
624
|
+
* BILLED PER TOKEN at API rates, every run costs real money instead of
|
|
625
|
+
* spending subscription quota you already paid for.
|
|
626
|
+
*
|
|
627
|
+
* TODO(unverified): implementation is out of scope for the scaffold.
|
|
628
|
+
*/
|
|
629
|
+
declare class ApiKeyRunner implements AgentRunner {
|
|
630
|
+
readonly backend: "api-key";
|
|
631
|
+
run(_task: CandidateTask, _repo: RepoConfig): Promise<RunResult>;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Dry-run is the DEFAULT. Live execution requires BOTH opt-ins:
|
|
636
|
+
* 1. the --live flag on the invocation, AND
|
|
637
|
+
* 2. a live backend in the config (agent.backend !== 'dry-run').
|
|
638
|
+
* Either one missing → dry-run. This is a non-negotiable safety rule; do not
|
|
639
|
+
* collapse it into a single switch.
|
|
640
|
+
*/
|
|
641
|
+
declare function createRunner(config: AfterburnerConfig, liveFlag: boolean): AgentRunner;
|
|
642
|
+
|
|
643
|
+
interface RunRecord {
|
|
644
|
+
timestamp: string;
|
|
645
|
+
repoUrl: string;
|
|
646
|
+
fingerprint: string;
|
|
647
|
+
category: TaskCategory;
|
|
648
|
+
title: string;
|
|
649
|
+
estCostSonnetTokens: number;
|
|
650
|
+
branch: string;
|
|
651
|
+
prUrl?: string;
|
|
652
|
+
outcome: RunOutcome;
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Append-only run records, the canonical "what happened" surface (exposed via
|
|
656
|
+
* `afterburner log`) and the source for idempotency checks.
|
|
657
|
+
*/
|
|
658
|
+
interface RunStore {
|
|
659
|
+
append(record: RunRecord): Promise<void>;
|
|
660
|
+
list(): Promise<RunRecord[]>;
|
|
661
|
+
/** Duplicate-PR guard: has this fingerprint already produced an open or merged PR? */
|
|
662
|
+
hasOpenOrMergedPr(fingerprint: string): Promise<boolean>;
|
|
663
|
+
}
|
|
664
|
+
declare class JsonlRunStore implements RunStore {
|
|
665
|
+
private readonly filePath;
|
|
666
|
+
constructor(filePath?: string);
|
|
667
|
+
append(record: RunRecord): Promise<void>;
|
|
668
|
+
list(): Promise<RunRecord[]>;
|
|
669
|
+
hasOpenOrMergedPr(fingerprint: string): Promise<boolean>;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
/**
|
|
673
|
+
* Notification seam. Core ships ONLY ConsoleNotifier: the pull request is the
|
|
674
|
+
* real notification and the run store is the audit trail. This interface is
|
|
675
|
+
* the documented extension point for a future opt-in generic webhook, vendor
|
|
676
|
+
* SDKs are never bundled into core.
|
|
677
|
+
*/
|
|
678
|
+
interface Notifier {
|
|
679
|
+
notify(record: RunRecord): Promise<void>;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
declare class ConsoleNotifier implements Notifier {
|
|
683
|
+
notify(record: RunRecord): Promise<void>;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
interface GateConfig {
|
|
687
|
+
minWeeklyHeadroomPct: number;
|
|
688
|
+
safetyMarginTokens: number;
|
|
689
|
+
requireSessionAvailable: boolean;
|
|
690
|
+
}
|
|
691
|
+
interface GateDecision {
|
|
692
|
+
go: boolean;
|
|
693
|
+
reason: string;
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Both-caps gate, a non-negotiable rule encoded as a pure function: only fire
|
|
697
|
+
* when a session window is available AND the estimated cost plus the safety
|
|
698
|
+
* margin fits inside the remaining weekly budget (with the configured
|
|
699
|
+
* headroom). Reasons are returned, not just booleans, so every skipped run is
|
|
700
|
+
* explainable in the log.
|
|
701
|
+
*/
|
|
702
|
+
declare function shouldIgnite(budget: Budget, estCostSonnetTokens: number, config: GateConfig): GateDecision;
|
|
703
|
+
|
|
704
|
+
interface WatchHandle {
|
|
705
|
+
stop(): void;
|
|
706
|
+
}
|
|
707
|
+
/**
|
|
708
|
+
* Foreground scheduler daemon (`afterburner watch`). Useful for development,
|
|
709
|
+
* temporary runs, and cron expressions native schedulers cannot express. For
|
|
710
|
+
* normal unattended use, prefer `afterburner schedule install`.
|
|
711
|
+
*/
|
|
712
|
+
declare function startWatch(opts: {
|
|
713
|
+
cron: string;
|
|
714
|
+
timezone: string;
|
|
715
|
+
onTick: () => Promise<void>;
|
|
716
|
+
onError?: (error: unknown) => void;
|
|
717
|
+
}): WatchHandle;
|
|
718
|
+
|
|
719
|
+
type SupportedPlatform = 'darwin' | 'linux' | 'win32';
|
|
720
|
+
interface ScheduleArtifacts {
|
|
721
|
+
kind: 'launchd' | 'systemd-user' | 'schtasks';
|
|
722
|
+
/** Files to write (empty for schtasks, which is command-driven). */
|
|
723
|
+
files: Array<{
|
|
724
|
+
path: string;
|
|
725
|
+
content: string;
|
|
726
|
+
}>;
|
|
727
|
+
/** Commands the user runs to activate the schedule. */
|
|
728
|
+
activationHint: string;
|
|
729
|
+
/** Commands/steps to undo the installation. */
|
|
730
|
+
removalHint: string;
|
|
731
|
+
}
|
|
732
|
+
interface SimpleCronSchedule {
|
|
733
|
+
minute: number;
|
|
734
|
+
/** Explicit list of hours the job fires at. */
|
|
735
|
+
hours: number[];
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* Native schedulers don't speak cron uniformly (launchd wants calendar
|
|
739
|
+
* intervals, schtasks wants /SC switches), so we support the simple cron
|
|
740
|
+
* shapes Afterburner actually defaults to and fail loudly on anything fancier;
|
|
741
|
+
* `afterburner watch` handles full cron expressions.
|
|
742
|
+
*
|
|
743
|
+
* Supported: hourly ("M * * * *"), daily ("M H * * *"), every N hours
|
|
744
|
+
* (step syntax on the hour field), and specific hours ("M H1,H2 * * *").
|
|
745
|
+
*/
|
|
746
|
+
declare function parseSimpleCron(cron: string): SimpleCronSchedule;
|
|
747
|
+
interface NativeScheduleOptions {
|
|
748
|
+
cron: string;
|
|
749
|
+
timezone: string;
|
|
750
|
+
/** Absolute path to the node binary. */
|
|
751
|
+
nodePath: string;
|
|
752
|
+
/** Absolute path to the afterburner CLI entry script. */
|
|
753
|
+
cliPath: string;
|
|
754
|
+
configPath?: string;
|
|
755
|
+
}
|
|
756
|
+
declare function generateScheduleArtifacts(platform: SupportedPlatform, opts: NativeScheduleOptions): ScheduleArtifacts;
|
|
757
|
+
|
|
758
|
+
interface RunOnceDeps {
|
|
759
|
+
config: AfterburnerConfig;
|
|
760
|
+
budgetProvider: BudgetProvider;
|
|
761
|
+
selector: TaskSelector;
|
|
762
|
+
runner: AgentRunner;
|
|
763
|
+
store: RunStore;
|
|
764
|
+
notifier: Notifier;
|
|
765
|
+
}
|
|
766
|
+
interface RepoRunOutcome {
|
|
767
|
+
repoUrl: string;
|
|
768
|
+
status: 'completed' | 'skipped';
|
|
769
|
+
reason: string;
|
|
770
|
+
task?: CandidateTask;
|
|
771
|
+
result?: RunResult;
|
|
772
|
+
record?: RunRecord;
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* One ignition cycle: budget → selection → gates → run → record. Encodes the
|
|
776
|
+
* non-negotiables, one bounded task per run, both-caps gating, fingerprint
|
|
777
|
+
* idempotency, and the Fable gate re-checked at run time.
|
|
778
|
+
*/
|
|
779
|
+
declare function runOnce(deps: RunOnceDeps): Promise<RepoRunOutcome[]>;
|
|
780
|
+
|
|
781
|
+
export { type AfterburnerConfig, type AfterburnerUserConfig, type AgentConfig, type AgentRunner, ApiKeyRunner, BASE_TASK_TOKENS, type Budget, type BudgetConfig, type BudgetProvider, type BudgetProviderOptions, type CandidateTask, type ClaudeCodeInvocation, ClaudeCodeRunner, ClaudeCodeTranscriptsBudgetProvider, type ClaudeCodeTranscriptsOptions, type ClaudeUsageBudgetOptions, ClaudeUsageBudgetProvider, ConsoleNotifier, DEFAULT_MODEL_BY_CATEGORY, type DeterministicSelectorOptions, DeterministicTaskSelector, DryRunRunner, type GateConfig, type GateDecision, JsonlRunStore, type LoadedConfig, ManualBudgetProvider, type ModelCostTable, type ModelWeightEntry, type NativeScheduleOptions, type Notifier, type RateLimitWindow, type RateLimits, type RepoConfig, type RepoRunOutcome, type RunOnceDeps, type RunOutcome, type RunRecord, type RunResult, type RunStore, type RunnerBackend, type ScheduleArtifacts, type SupportedPlatform, TASK_CATEGORIES, TASK_TAXONOMY, type TaskCategory, type TaskCategoryInfo, type TaskIdentity, type TaskSelector, type TranscriptUsageSummary, type UsageCache, type UsageCacheBudgetOptions, type UsageCacheBudgetResult, type WatchHandle, assertModelAllowed, budgetFromUsageCache, buildClaudeCodeInvocation, claudeConfigDir, configDir, configSchema, createBudgetProvider, createModelCostTable, createRunner, createSelector, dataDir, defaultClaudeProjectsDir, defaultCostTable, defaultRunStorePath, defaultUsageCachePath, defineConfig, deriveBranchName, derivePrTitle, formatConfigError, generateScheduleArtifacts, isFableModel, loadConfig, mapConfigLoadError, parseSimpleCron, readUsageCache, repoConfigSchema, runOnce, sanitizeSpawnEnv, shouldIgnite, startWatch, summarizeTranscriptUsage, taskFingerprint, writeUsageCache };
|