tuff-lil-unit 0.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 (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +84 -0
  3. package/dist/budget.d.ts +14 -0
  4. package/dist/budget.d.ts.map +1 -0
  5. package/dist/budget.js +30 -0
  6. package/dist/budget.js.map +1 -0
  7. package/dist/context.d.ts +76 -0
  8. package/dist/context.d.ts.map +1 -0
  9. package/dist/context.js +236 -0
  10. package/dist/context.js.map +1 -0
  11. package/dist/index.d.ts +13 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +10 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/job.d.ts +8 -0
  16. package/dist/job.d.ts.map +1 -0
  17. package/dist/job.js +195 -0
  18. package/dist/job.js.map +1 -0
  19. package/dist/providers/anthropic.d.ts +3 -0
  20. package/dist/providers/anthropic.d.ts.map +1 -0
  21. package/dist/providers/anthropic.js +6 -0
  22. package/dist/providers/anthropic.js.map +1 -0
  23. package/dist/providers/base.d.ts +21 -0
  24. package/dist/providers/base.d.ts.map +1 -0
  25. package/dist/providers/base.js +89 -0
  26. package/dist/providers/base.js.map +1 -0
  27. package/dist/providers/claude-cli.d.ts +16 -0
  28. package/dist/providers/claude-cli.d.ts.map +1 -0
  29. package/dist/providers/claude-cli.js +194 -0
  30. package/dist/providers/claude-cli.js.map +1 -0
  31. package/dist/providers/openai.d.ts +3 -0
  32. package/dist/providers/openai.d.ts.map +1 -0
  33. package/dist/providers/openai.js +6 -0
  34. package/dist/providers/openai.js.map +1 -0
  35. package/dist/rate-limit.d.ts +8 -0
  36. package/dist/rate-limit.d.ts.map +1 -0
  37. package/dist/rate-limit.js +52 -0
  38. package/dist/rate-limit.js.map +1 -0
  39. package/dist/retry.d.ts +12 -0
  40. package/dist/retry.d.ts.map +1 -0
  41. package/dist/retry.js +59 -0
  42. package/dist/retry.js.map +1 -0
  43. package/dist/schema-sync.d.ts +7 -0
  44. package/dist/schema-sync.d.ts.map +1 -0
  45. package/dist/schema-sync.js +32 -0
  46. package/dist/schema-sync.js.map +1 -0
  47. package/dist/schema.d.ts +24 -0
  48. package/dist/schema.d.ts.map +1 -0
  49. package/dist/schema.js +27 -0
  50. package/dist/schema.js.map +1 -0
  51. package/dist/state.d.ts +28 -0
  52. package/dist/state.d.ts.map +1 -0
  53. package/dist/state.js +86 -0
  54. package/dist/state.js.map +1 -0
  55. package/dist/tuff.d.ts +8 -0
  56. package/dist/tuff.d.ts.map +1 -0
  57. package/dist/tuff.js +73 -0
  58. package/dist/tuff.js.map +1 -0
  59. package/dist/types.d.ts +49 -0
  60. package/dist/types.d.ts.map +1 -0
  61. package/dist/types.js +2 -0
  62. package/dist/types.js.map +1 -0
  63. package/dist/upsert.d.ts +9 -0
  64. package/dist/upsert.d.ts.map +1 -0
  65. package/dist/upsert.js +42 -0
  66. package/dist/upsert.js.map +1 -0
  67. package/dist/workflow.d.ts +12 -0
  68. package/dist/workflow.d.ts.map +1 -0
  69. package/dist/workflow.js +507 -0
  70. package/dist/workflow.js.map +1 -0
  71. package/package.json +62 -0
package/dist/job.js ADDED
@@ -0,0 +1,195 @@
1
+ export function isCustomJob(job) {
2
+ return 'fn' in job;
3
+ }
4
+ export function isProviderJob(job) {
5
+ return 'provider' in job;
6
+ }
7
+ export function isCommandJob(job) {
8
+ return 'command' in job;
9
+ }
10
+ export function isClaudeCodeJob(job) {
11
+ return 'type' in job && job.type === 'claude-code';
12
+ }
13
+ export async function executeJob(job, context, provider) {
14
+ const startTime = Date.now();
15
+ try {
16
+ if (isCustomJob(job)) {
17
+ return await executeCustomJob(job, context, startTime);
18
+ }
19
+ if (isProviderJob(job)) {
20
+ if (!provider) {
21
+ throw new Error(`Provider required for job ${job.id} but none provided`);
22
+ }
23
+ return await executeProviderJob(job, context, provider, startTime);
24
+ }
25
+ if (isCommandJob(job)) {
26
+ return await executeCommandJob(job, context, startTime);
27
+ }
28
+ if (isClaudeCodeJob(job)) {
29
+ return await executeClaudeCodeJob(job, context, startTime);
30
+ }
31
+ const unknownJob = job;
32
+ throw new Error(`Unknown job type: ${JSON.stringify(unknownJob)}`);
33
+ }
34
+ catch (error) {
35
+ return {
36
+ status: 'failed',
37
+ error: error instanceof Error ? error : new Error(String(error)),
38
+ retriable: false,
39
+ };
40
+ }
41
+ }
42
+ async function executeCustomJob(job, context, startTime) {
43
+ const timeoutMs = job.budget?.timeMs;
44
+ if (timeoutMs) {
45
+ const timeoutSignal = AbortSignal.timeout(timeoutMs);
46
+ const combinedSignal = combineSignals([context.signal, timeoutSignal]);
47
+ const result = await Promise.race([
48
+ job.fn({ ...context, signal: combinedSignal }),
49
+ waitForAbort(combinedSignal),
50
+ ]);
51
+ if (result === ABORTED) {
52
+ throw new Error(`Job ${job.id} timed out after ${timeoutMs}ms`);
53
+ }
54
+ return {
55
+ status: 'completed',
56
+ output: result,
57
+ durationMs: Date.now() - startTime,
58
+ };
59
+ }
60
+ const output = await job.fn(context);
61
+ return {
62
+ status: 'completed',
63
+ output,
64
+ durationMs: Date.now() - startTime,
65
+ };
66
+ }
67
+ async function executeProviderJob(job, context, provider, startTime) {
68
+ const prompt = typeof job.prompt === 'function' ? job.prompt(context) : job.prompt;
69
+ const timeoutMs = job.budget?.timeMs;
70
+ const maxTokens = job.budget?.tokens;
71
+ if (timeoutMs) {
72
+ const timeoutSignal = AbortSignal.timeout(timeoutMs);
73
+ const combinedSignal = combineSignals([context.signal, timeoutSignal]);
74
+ const result = await Promise.race([
75
+ provider.execute(prompt, { maxTokens, signal: combinedSignal }),
76
+ waitForAbort(combinedSignal),
77
+ ]);
78
+ if (result === ABORTED) {
79
+ throw new Error(`Job ${job.id} timed out after ${timeoutMs}ms`);
80
+ }
81
+ return {
82
+ status: 'completed',
83
+ output: result.output,
84
+ usage: result.usage,
85
+ durationMs: Date.now() - startTime,
86
+ };
87
+ }
88
+ const result = await provider.execute(prompt, { maxTokens, signal: context.signal });
89
+ return {
90
+ status: 'completed',
91
+ output: result.output,
92
+ usage: result.usage,
93
+ durationMs: Date.now() - startTime,
94
+ };
95
+ }
96
+ const ABORTED = Symbol('aborted');
97
+ function combineSignals(signals) {
98
+ const controller = new AbortController();
99
+ for (const signal of signals) {
100
+ if (signal.aborted) {
101
+ controller.abort(signal.reason);
102
+ break;
103
+ }
104
+ signal.addEventListener('abort', () => {
105
+ controller.abort(signal.reason);
106
+ }, { once: true });
107
+ }
108
+ return controller.signal;
109
+ }
110
+ async function waitForAbort(signal) {
111
+ return new Promise((resolve) => {
112
+ signal.addEventListener('abort', () => resolve(ABORTED), { once: true });
113
+ });
114
+ }
115
+ async function executeCommandJob(job, context, startTime) {
116
+ const { spawn } = await import('node:child_process');
117
+ return new Promise((resolve) => {
118
+ const args = job.args || [];
119
+ const options = {
120
+ cwd: job.cwd,
121
+ env: job.env ? { ...process.env, ...job.env } : process.env,
122
+ shell: job.shell ?? false,
123
+ };
124
+ const proc = spawn(job.command, args, options);
125
+ let stdout = '';
126
+ let stderr = '';
127
+ proc.stdout?.on('data', (chunk) => {
128
+ stdout += chunk.toString();
129
+ });
130
+ proc.stderr?.on('data', (chunk) => {
131
+ stderr += chunk.toString();
132
+ });
133
+ const abortHandler = () => {
134
+ proc.kill('SIGTERM');
135
+ };
136
+ context.signal.addEventListener('abort', abortHandler, { once: true });
137
+ proc.on('exit', (code) => {
138
+ context.signal.removeEventListener('abort', abortHandler);
139
+ if (code === 0) {
140
+ resolve({
141
+ status: 'completed',
142
+ output: { stdout, stderr, exitCode: code },
143
+ durationMs: Date.now() - startTime,
144
+ });
145
+ }
146
+ else {
147
+ resolve({
148
+ status: 'failed',
149
+ error: new Error(`Command exited with code ${code}: ${stderr}`),
150
+ retriable: false,
151
+ });
152
+ }
153
+ });
154
+ proc.on('error', (err) => {
155
+ context.signal.removeEventListener('abort', abortHandler);
156
+ resolve({
157
+ status: 'failed',
158
+ error: err instanceof Error ? err : new Error(String(err)),
159
+ retriable: false,
160
+ });
161
+ });
162
+ });
163
+ }
164
+ async function executeClaudeCodeJob(job, context, startTime) {
165
+ const { ClaudeCLIProvider } = await import('./providers/claude-cli.js');
166
+ const prompt = typeof job.prompt === 'function' ? job.prompt(context) : job.prompt;
167
+ const provider = new ClaudeCLIProvider({ type: 'anthropic', model: job.model }, undefined);
168
+ const timeoutMs = job.budget?.timeMs;
169
+ const maxTokens = job.budget?.tokens;
170
+ if (timeoutMs) {
171
+ const timeoutSignal = AbortSignal.timeout(timeoutMs);
172
+ const combinedSignal = combineSignals([context.signal, timeoutSignal]);
173
+ const result = await Promise.race([
174
+ provider.execute(prompt, { maxTokens, signal: combinedSignal }),
175
+ waitForAbort(combinedSignal),
176
+ ]);
177
+ if (result === ABORTED) {
178
+ throw new Error(`Job ${job.id} timed out after ${timeoutMs}ms`);
179
+ }
180
+ return {
181
+ status: 'completed',
182
+ output: result.output,
183
+ usage: result.usage,
184
+ durationMs: Date.now() - startTime,
185
+ };
186
+ }
187
+ const result = await provider.execute(prompt, { maxTokens, signal: context.signal });
188
+ return {
189
+ status: 'completed',
190
+ output: result.output,
191
+ usage: result.usage,
192
+ durationMs: Date.now() - startTime,
193
+ };
194
+ }
195
+ //# sourceMappingURL=job.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job.js","sourceRoot":"","sources":["../src/job.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type Provider } from './base.js';
2
+ export declare function createAnthropicProvider(): Provider;
3
+ //# sourceMappingURL=anthropic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/providers/anthropic.ts"],"names":[],"mappings":"AACA,OAAO,EAA0B,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAC;AAElE,wBAAgB,uBAAuB,IAAI,QAAQ,CAElD"}
@@ -0,0 +1,6 @@
1
+ import { anthropic } from '@ai-sdk/anthropic';
2
+ import { createVercelAIProvider } from './base.js';
3
+ export function createAnthropicProvider() {
4
+ return createVercelAIProvider(anthropic, { extractCacheTokens: true });
5
+ }
6
+ //# sourceMappingURL=anthropic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/providers/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAiB,MAAM,WAAW,CAAC;AAElE,MAAM,UAAU,uBAAuB;IACrC,OAAO,sBAAsB,CAAC,SAAS,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAAC;AACzE,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { type LanguageModel } from 'ai';
2
+ import type { ProviderResult } from '../types.js';
3
+ export declare class RateLimitError extends Error {
4
+ retryAfterMs?: number | undefined;
5
+ constructor(message: string, retryAfterMs?: number | undefined);
6
+ }
7
+ export declare class BudgetExceededError extends Error {
8
+ constructor(message: string);
9
+ }
10
+ export interface Provider {
11
+ execute(prompt: string, options: {
12
+ model: string;
13
+ maxTokens?: number;
14
+ signal?: AbortSignal;
15
+ } & Record<string, unknown>): Promise<ProviderResult>;
16
+ }
17
+ export declare function extractRetryAfter(headers?: Record<string, string>): number | undefined;
18
+ export declare function createVercelAIProvider(createModel: (id: string) => LanguageModel, options?: {
19
+ extractCacheTokens?: boolean;
20
+ }): Provider;
21
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/providers/base.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,KAAK,aAAa,EAAE,MAAM,IAAI,CAAC;AACtE,OAAO,KAAK,EAAE,cAAc,EAAc,MAAM,aAAa,CAAC;AAE9D,qBAAa,cAAe,SAAQ,KAAK;IAG9B,YAAY,CAAC,EAAE,MAAM;gBAD5B,OAAO,EAAE,MAAM,EACR,YAAY,CAAC,EAAE,MAAM,YAAA;CAK/B;AAED,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,CACL,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7F,OAAO,CAAC,cAAc,CAAC,CAAC;CAC5B;AAED,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,GAAG,SAAS,CAiBtF;AAED,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,aAAa,EAC1C,OAAO,CAAC,EAAE;IAAE,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAAE,GACzC,QAAQ,CAkEV"}
@@ -0,0 +1,89 @@
1
+ import { generateText, generateObject } from 'ai';
2
+ export class RateLimitError extends Error {
3
+ retryAfterMs;
4
+ constructor(message, retryAfterMs) {
5
+ super(message);
6
+ this.retryAfterMs = retryAfterMs;
7
+ this.name = 'RateLimitError';
8
+ }
9
+ }
10
+ export class BudgetExceededError extends Error {
11
+ constructor(message) {
12
+ super(message);
13
+ this.name = 'BudgetExceededError';
14
+ }
15
+ }
16
+ export function extractRetryAfter(headers) {
17
+ if (!headers)
18
+ return undefined;
19
+ const retryAfter = headers['retry-after'] || headers['Retry-After'];
20
+ if (!retryAfter)
21
+ return undefined;
22
+ const seconds = parseInt(retryAfter, 10);
23
+ if (!isNaN(seconds)) {
24
+ return seconds * 1000;
25
+ }
26
+ const date = new Date(retryAfter);
27
+ if (!isNaN(date.getTime())) {
28
+ return Math.max(0, date.getTime() - Date.now());
29
+ }
30
+ return undefined;
31
+ }
32
+ export function createVercelAIProvider(createModel, options) {
33
+ return {
34
+ async execute(prompt, executeOptions) {
35
+ const startTime = Date.now();
36
+ const { model: modelId, maxTokens, signal, schema, ...rest } = executeOptions;
37
+ try {
38
+ let output;
39
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
+ let rawUsage;
41
+ if (schema) {
42
+ const result = await generateObject({
43
+ model: createModel(modelId),
44
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
+ schema: schema,
46
+ prompt,
47
+ maxOutputTokens: maxTokens,
48
+ abortSignal: signal,
49
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
50
+ ...rest,
51
+ });
52
+ output = result.object;
53
+ rawUsage = result.usage;
54
+ }
55
+ else {
56
+ const result = await generateText({
57
+ model: createModel(modelId),
58
+ prompt,
59
+ maxOutputTokens: maxTokens,
60
+ abortSignal: signal,
61
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
62
+ ...rest,
63
+ });
64
+ output = result.text;
65
+ rawUsage = result.usage;
66
+ }
67
+ const usage = {
68
+ inputTokens: rawUsage.inputTokens ?? 0,
69
+ outputTokens: rawUsage.outputTokens ?? 0,
70
+ ...(options?.extractCacheTokens && {
71
+ cacheCreationTokens: rawUsage.inputTokenDetails?.cacheWriteTokens,
72
+ cacheReadTokens: rawUsage.inputTokenDetails?.cacheReadTokens,
73
+ }),
74
+ };
75
+ return { output, usage, durationMs: Date.now() - startTime };
76
+ }
77
+ catch (error) {
78
+ const errorObj = error;
79
+ if (errorObj.status === 429 || errorObj.statusCode === 429) {
80
+ const headers = errorObj.headers || errorObj.response?.headers;
81
+ const retryAfter = extractRetryAfter(headers);
82
+ throw new RateLimitError(errorObj.message || 'Rate limit exceeded', retryAfter);
83
+ }
84
+ throw error;
85
+ }
86
+ },
87
+ };
88
+ }
89
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/providers/base.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { ProviderResult, TokenUsage } from '../types.js';
2
+ import type { Provider } from './base.js';
3
+ import { spawn } from 'node:child_process';
4
+ export declare function parseTranscriptTokens(filePath: string): TokenUsage;
5
+ export declare function createWorkerDir(jobId: string): string;
6
+ export declare function deriveTranscriptDir(workDir: string): string;
7
+ export declare function cleanupWorkerDir(workDir: string): void;
8
+ export declare function monitorBudget(transcriptDir: string, budgetTokens: number, proc: ReturnType<typeof spawn>, signal?: AbortSignal): Promise<TokenUsage>;
9
+ export declare class ClaudeCLIProvider implements Provider {
10
+ execute(prompt: string, options: {
11
+ model: string;
12
+ maxTokens?: number;
13
+ signal?: AbortSignal;
14
+ } & Record<string, unknown>): Promise<ProviderResult>;
15
+ }
16
+ //# sourceMappingURL=claude-cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-cli.d.ts","sourceRoot":"","sources":["../../src/providers/claude-cli.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAY3C,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CA6BlE;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIrD;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAI3D;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAMtD;AAED,wBAAsB,aAAa,CACjC,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,UAAU,CAAC,OAAO,KAAK,CAAC,EAC9B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC,CA8DrB;AAED,qBAAa,iBAAkB,YAAW,QAAQ;IAC1C,OAAO,CACX,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7F,OAAO,CAAC,cAAc,CAAC;CAsG3B"}
@@ -0,0 +1,194 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { mkdirSync, rmSync, realpathSync, readFileSync, existsSync, readdirSync, } from 'node:fs';
3
+ import { homedir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ export function parseTranscriptTokens(filePath) {
6
+ if (!existsSync(filePath)) {
7
+ return { inputTokens: 0, outputTokens: 0, cacheCreationTokens: 0, cacheReadTokens: 0 };
8
+ }
9
+ const content = readFileSync(filePath, 'utf-8');
10
+ const lines = content.trim().split('\n').filter((line) => line.length > 0);
11
+ let inputTokens = 0;
12
+ let outputTokens = 0;
13
+ let cacheCreationTokens = 0;
14
+ let cacheReadTokens = 0;
15
+ for (const line of lines) {
16
+ try {
17
+ const entry = JSON.parse(line);
18
+ if (entry.type === 'assistant' && entry.message?.usage) {
19
+ const usage = entry.message.usage;
20
+ inputTokens += usage.input_tokens || 0;
21
+ outputTokens += usage.output_tokens || 0;
22
+ cacheCreationTokens += usage.cache_creation_input_tokens || 0;
23
+ cacheReadTokens += usage.cache_read_input_tokens || 0;
24
+ }
25
+ }
26
+ catch {
27
+ // Skip malformed lines
28
+ }
29
+ }
30
+ return { inputTokens, outputTokens, cacheCreationTokens, cacheReadTokens };
31
+ }
32
+ export function createWorkerDir(jobId) {
33
+ const workDir = `/tmp/tuff-worker-${jobId}`;
34
+ mkdirSync(workDir, { recursive: true });
35
+ return workDir;
36
+ }
37
+ export function deriveTranscriptDir(workDir) {
38
+ const realPath = realpathSync(workDir);
39
+ const projectDir = realPath.replace(/\//g, '-');
40
+ return join(homedir(), '.claude', 'projects', projectDir);
41
+ }
42
+ export function cleanupWorkerDir(workDir) {
43
+ try {
44
+ rmSync(workDir, { recursive: true, force: true });
45
+ }
46
+ catch {
47
+ // Best-effort cleanup
48
+ }
49
+ }
50
+ export async function monitorBudget(transcriptDir, budgetTokens, proc, signal) {
51
+ const waitStart = Date.now();
52
+ let transcriptPath;
53
+ while (Date.now() - waitStart < 5000) {
54
+ try {
55
+ const files = existsSync(transcriptDir) ? readdirSync(transcriptDir) : [];
56
+ const jsonlFiles = files.filter((f) => f.endsWith('.jsonl') && !f.includes('subagents'));
57
+ if (jsonlFiles.length > 0) {
58
+ transcriptPath = join(transcriptDir, jsonlFiles[0]);
59
+ break;
60
+ }
61
+ }
62
+ catch {
63
+ // Directory may not exist yet
64
+ }
65
+ await new Promise((resolve) => setTimeout(resolve, 100));
66
+ }
67
+ if (!transcriptPath) {
68
+ throw new Error('Transcript not found after 5s');
69
+ }
70
+ let finalUsage = { inputTokens: 0, outputTokens: 0 };
71
+ let intervalId;
72
+ return new Promise((resolve) => {
73
+ intervalId = setInterval(() => {
74
+ if (signal?.aborted) {
75
+ clearInterval(intervalId);
76
+ resolve(finalUsage);
77
+ return;
78
+ }
79
+ try {
80
+ const usage = parseTranscriptTokens(transcriptPath);
81
+ finalUsage = usage;
82
+ const totalTokens = usage.inputTokens + usage.outputTokens + (usage.cacheCreationTokens || 0);
83
+ if (totalTokens > budgetTokens) {
84
+ proc.kill('SIGTERM');
85
+ clearInterval(intervalId);
86
+ }
87
+ }
88
+ catch {
89
+ // Transcript may be partially written
90
+ }
91
+ }, 100);
92
+ proc.on('exit', () => {
93
+ if (intervalId) {
94
+ clearInterval(intervalId);
95
+ }
96
+ try {
97
+ finalUsage = parseTranscriptTokens(transcriptPath);
98
+ }
99
+ catch {
100
+ // Use last known usage
101
+ }
102
+ resolve(finalUsage);
103
+ });
104
+ });
105
+ }
106
+ export class ClaudeCLIProvider {
107
+ async execute(prompt, options) {
108
+ const jobId = `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
109
+ const startTime = Date.now();
110
+ let workDir;
111
+ try {
112
+ workDir = createWorkerDir(jobId);
113
+ const transcriptDir = deriveTranscriptDir(workDir);
114
+ // Strip CLAUDECODE so the CLI's nested-session guard doesn't fire
115
+ const { CLAUDECODE: _cc, ...spawnEnv } = process.env;
116
+ const proc = spawn('claude', ['-p', '--model', options.model], {
117
+ cwd: workDir,
118
+ env: spawnEnv,
119
+ stdio: ['pipe', 'pipe', 'pipe'],
120
+ });
121
+ let stdout = '';
122
+ let stderr = '';
123
+ proc.stdout?.on('data', (chunk) => {
124
+ stdout += chunk.toString();
125
+ });
126
+ proc.stderr?.on('data', (chunk) => {
127
+ stderr += chunk.toString();
128
+ });
129
+ const abortHandler = () => {
130
+ proc.kill('SIGTERM');
131
+ };
132
+ if (options.signal) {
133
+ options.signal.addEventListener('abort', abortHandler);
134
+ }
135
+ proc.stdin?.write(prompt);
136
+ proc.stdin?.end();
137
+ let monitorPromise;
138
+ if (options.maxTokens) {
139
+ monitorPromise = monitorBudget(transcriptDir, options.maxTokens, proc, options.signal);
140
+ }
141
+ const exitCode = await new Promise((resolve, reject) => {
142
+ proc.on('exit', (code) => {
143
+ if (options.signal) {
144
+ options.signal.removeEventListener('abort', abortHandler);
145
+ }
146
+ resolve(code || 0);
147
+ });
148
+ proc.on('error', (err) => {
149
+ if (options.signal) {
150
+ options.signal.removeEventListener('abort', abortHandler);
151
+ }
152
+ reject(err);
153
+ });
154
+ });
155
+ let usage;
156
+ if (monitorPromise) {
157
+ usage = await monitorPromise;
158
+ }
159
+ else {
160
+ const waitStart = Date.now();
161
+ let transcriptPath;
162
+ while (Date.now() - waitStart < 5000) {
163
+ try {
164
+ const files = existsSync(transcriptDir) ? readdirSync(transcriptDir) : [];
165
+ const jsonlFiles = files.filter((f) => f.endsWith('.jsonl') && !f.includes('subagents'));
166
+ if (jsonlFiles.length > 0) {
167
+ transcriptPath = join(transcriptDir, jsonlFiles[0]);
168
+ break;
169
+ }
170
+ }
171
+ catch {
172
+ // Directory may not exist yet
173
+ }
174
+ await new Promise((resolve) => setTimeout(resolve, 100));
175
+ }
176
+ usage = transcriptPath ? parseTranscriptTokens(transcriptPath) : { inputTokens: 0, outputTokens: 0 };
177
+ }
178
+ if (exitCode !== 0) {
179
+ throw new Error(`Claude CLI exited with code ${exitCode}: ${stderr}`);
180
+ }
181
+ return {
182
+ output: stdout,
183
+ usage,
184
+ durationMs: Date.now() - startTime,
185
+ };
186
+ }
187
+ finally {
188
+ if (workDir) {
189
+ cleanupWorkerDir(workDir);
190
+ }
191
+ }
192
+ }
193
+ }
194
+ //# sourceMappingURL=claude-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-cli.js","sourceRoot":"","sources":["../../src/providers/claude-cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type Provider } from './base.js';
2
+ export declare function createOpenAIProvider(): Provider;
3
+ //# sourceMappingURL=openai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/providers/openai.ts"],"names":[],"mappings":"AACA,OAAO,EAA0B,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAC;AAElE,wBAAgB,oBAAoB,IAAI,QAAQ,CAE/C"}
@@ -0,0 +1,6 @@
1
+ import { openai } from '@ai-sdk/openai';
2
+ import { createVercelAIProvider } from './base.js';
3
+ export function createOpenAIProvider() {
4
+ return createVercelAIProvider(openai);
5
+ }
6
+ //# sourceMappingURL=openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/providers/openai.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,sBAAsB,EAAiB,MAAM,WAAW,CAAC;AAElE,MAAM,UAAU,oBAAoB;IAClC,OAAO,sBAAsB,CAAC,MAAM,CAAC,CAAC;AACxC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { RateLimit } from './types.js';
2
+ export declare class RateLimiter {
3
+ #private;
4
+ constructor(config: RateLimit);
5
+ tryAcquire(estimatedTokens?: number): boolean;
6
+ release(actualTokens: number): void;
7
+ }
8
+ //# sourceMappingURL=rate-limit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,qBAAa,WAAW;;gBAOV,MAAM,EAAE,SAAS;IAQ7B,UAAU,CAAC,eAAe,GAAE,MAAU,GAAG,OAAO;IAoBhD,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;CAwBpC"}