@atolis-hq/wake 0.2.46 → 0.2.47
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/dist/src/adapters/claude/claude-runner.js +202 -192
- package/dist/src/adapters/codex/codex-runner.js +9 -1
- package/dist/src/adapters/cursor/cursor-runner.js +9 -1
- package/dist/src/adapters/fake/fake-runner.js +25 -1
- package/dist/src/adapters/runner/cli-command.js +17 -3
- package/dist/src/core/live-execution.js +81 -0
- package/dist/src/core/tick-runner.js +114 -11
- package/dist/src/domain/schema.js +4 -0
- package/dist/src/version.js +1 -1
- package/package.json +1 -1
|
@@ -3,6 +3,7 @@ import { runAgentCliCommand } from '../runner/cli-command.js';
|
|
|
3
3
|
import { buildStagePrompt } from '../runner/stage-prompt.js';
|
|
4
4
|
import { emitRuntimeEvent, runnerRuntimeEvent } from '../runner/runtime-events.js';
|
|
5
5
|
import { writeRunnerTranscript } from '../runner/transcripts.js';
|
|
6
|
+
import { createAgentExecution } from '../../core/live-execution.js';
|
|
6
7
|
export { buildStagePrompt } from '../runner/stage-prompt.js';
|
|
7
8
|
function slugify(value, maxLength = 40) {
|
|
8
9
|
return value
|
|
@@ -152,182 +153,109 @@ function readSandboxLogBreadcrumb() {
|
|
|
152
153
|
};
|
|
153
154
|
}
|
|
154
155
|
export function createClaudeRunner(options) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
runId: input.runId,
|
|
230
|
-
projection: input.projection,
|
|
231
|
-
routing: input.routing,
|
|
232
|
-
cli: CLAUDE_CLI_NAME,
|
|
233
|
-
model,
|
|
234
|
-
payload: { pid: identity.pid, processStartedAt: identity.processStartedAt },
|
|
235
|
-
}));
|
|
236
|
-
},
|
|
237
|
-
});
|
|
238
|
-
const responseTranscriptPath = await writeRunnerTranscript({
|
|
239
|
-
config: input.config,
|
|
240
|
-
projection: input.projection,
|
|
241
|
-
runId: input.runId,
|
|
242
|
-
action: input.action,
|
|
243
|
-
cli: CLAUDE_CLI_NAME,
|
|
244
|
-
kind: 'response',
|
|
245
|
-
text: result.stdout,
|
|
246
|
-
});
|
|
247
|
-
if (result.exitCode !== 0 || result.timedOut || result.stdout.trim().length === 0) {
|
|
248
|
-
const sandboxLog = readSandboxLogBreadcrumb();
|
|
249
|
-
const failureClass = classifyClaudeCliFailure({
|
|
250
|
-
stdout: result.stdout,
|
|
251
|
-
stderr: result.stderr,
|
|
252
|
-
timedOut: result.timedOut,
|
|
253
|
-
});
|
|
254
|
-
console.error(formatClaudeRunLogLine({
|
|
255
|
-
phase: 'failure',
|
|
256
|
-
runId: input.runId,
|
|
257
|
-
action: input.action,
|
|
258
|
-
issueNumber: input.projection.issue.number,
|
|
259
|
-
repo: input.projection.issue.repo,
|
|
260
|
-
recentEventIds: input.recentEvents.map((event) => event.eventId),
|
|
261
|
-
model,
|
|
262
|
-
...(input.workspacePath === undefined ? {} : { workspacePath: input.workspacePath }),
|
|
263
|
-
exitCode: result.exitCode,
|
|
264
|
-
}));
|
|
156
|
+
async function executeRun(input) {
|
|
157
|
+
const sessionName = buildWakeSessionName({
|
|
158
|
+
sessionName: options.settings.sessionName,
|
|
159
|
+
issueNumber: input.projection.issue.number,
|
|
160
|
+
title: input.projection.issue.title,
|
|
161
|
+
runId: input.runId,
|
|
162
|
+
});
|
|
163
|
+
// Resume an in-progress session when the projection carries a session ID
|
|
164
|
+
// that was created by this same CLI. This happens when the previous run
|
|
165
|
+
// ended with BLOCKED and the same action is being retried after a human
|
|
166
|
+
// reply. Any forward-stage transition or FAILED run clears the stored
|
|
167
|
+
// session ID so that the next action always starts fresh.
|
|
168
|
+
const priorSessionId = input.projection.wake.sessionId;
|
|
169
|
+
const priorSessionCli = input.projection.wake.sessionCli;
|
|
170
|
+
const isResume = priorSessionId !== undefined && priorSessionCli === CLAUDE_CLI_NAME;
|
|
171
|
+
const stagePrompt = await buildStagePrompt({
|
|
172
|
+
action: input.action,
|
|
173
|
+
projection: input.projection,
|
|
174
|
+
mode: isResume ? 'resume' : 'start',
|
|
175
|
+
config: input.config,
|
|
176
|
+
...(input.promptContextOverrides === undefined
|
|
177
|
+
? {}
|
|
178
|
+
: { contextOverrides: input.promptContextOverrides }),
|
|
179
|
+
...(input.mergeConflictDetected === true ? { mergeConflictDetected: true } : {}),
|
|
180
|
+
...(input.upstreamChanges === undefined ? {} : { upstreamChanges: input.upstreamChanges }),
|
|
181
|
+
});
|
|
182
|
+
const model = resolveModel({
|
|
183
|
+
action: input.action,
|
|
184
|
+
settings: options.settings,
|
|
185
|
+
});
|
|
186
|
+
const args = buildClaudePrintArgs({
|
|
187
|
+
model,
|
|
188
|
+
prompt: stagePrompt.prompt,
|
|
189
|
+
systemPrompt: stagePrompt.harnessPrompt,
|
|
190
|
+
sessionName,
|
|
191
|
+
allowedTools: stagePrompt.allowedTools,
|
|
192
|
+
extraArgs: stagePrompt.extraArgs,
|
|
193
|
+
maxTurns: stagePrompt.maxTurns,
|
|
194
|
+
...(stagePrompt.permissionMode === undefined
|
|
195
|
+
? {}
|
|
196
|
+
: { permissionMode: stagePrompt.permissionMode }),
|
|
197
|
+
...(options.settings.remoteControl.enabled ? { remoteControlName: sessionName } : {}),
|
|
198
|
+
...(options.settings.effort === undefined ? {} : { effort: options.settings.effort }),
|
|
199
|
+
...(isResume ? { resumeSessionId: priorSessionId } : {}),
|
|
200
|
+
});
|
|
201
|
+
const promptTranscriptPath = await writeRunnerTranscript({
|
|
202
|
+
config: input.config,
|
|
203
|
+
projection: input.projection,
|
|
204
|
+
runId: input.runId,
|
|
205
|
+
action: input.action,
|
|
206
|
+
cli: CLAUDE_CLI_NAME,
|
|
207
|
+
kind: 'prompt',
|
|
208
|
+
text: stagePrompt.prompt,
|
|
209
|
+
});
|
|
210
|
+
console.log(formatClaudeRunLogLine({
|
|
211
|
+
phase: 'start',
|
|
212
|
+
runId: input.runId,
|
|
213
|
+
action: input.action,
|
|
214
|
+
issueNumber: input.projection.issue.number,
|
|
215
|
+
repo: input.projection.issue.repo,
|
|
216
|
+
recentEventIds: input.recentEvents.map((event) => event.eventId),
|
|
217
|
+
model,
|
|
218
|
+
...(input.workspacePath === undefined ? {} : { workspacePath: input.workspacePath }),
|
|
219
|
+
}));
|
|
220
|
+
const result = await runClaudeCommand({
|
|
221
|
+
command: options.command,
|
|
222
|
+
args,
|
|
223
|
+
cwd: input.workspacePath ?? options.cwd,
|
|
224
|
+
timeoutMs: options.settings.timeoutMs,
|
|
225
|
+
...(input.cancellationSignal === undefined
|
|
226
|
+
? {}
|
|
227
|
+
: { cancellationSignal: input.cancellationSignal }),
|
|
228
|
+
onProcessStart: async (identity) => {
|
|
229
|
+
await input.onProcessStart?.(identity);
|
|
265
230
|
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
266
|
-
type: 'agent.process.
|
|
231
|
+
type: 'agent.process.started',
|
|
267
232
|
runId: input.runId,
|
|
268
233
|
projection: input.projection,
|
|
269
234
|
routing: input.routing,
|
|
270
235
|
cli: CLAUDE_CLI_NAME,
|
|
271
236
|
model,
|
|
272
|
-
payload: {
|
|
237
|
+
payload: { pid: identity.pid, processStartedAt: identity.processStartedAt },
|
|
273
238
|
}));
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
}
|
|
287
|
-
return {
|
|
288
|
-
result: [
|
|
289
|
-
result.timedOut
|
|
290
|
-
? `Claude runner timed out after ${options.settings.timeoutMs}ms and was killed`
|
|
291
|
-
: trimmedStdout.length === 0
|
|
292
|
-
? 'Claude runner produced no output'
|
|
293
|
-
: parsedReason !== undefined
|
|
294
|
-
? `Claude runner failed: ${parsedReason}`
|
|
295
|
-
: 'Claude runner failed',
|
|
296
|
-
result.stderr,
|
|
297
|
-
stdoutFailureDetail,
|
|
298
|
-
sandboxLog?.text,
|
|
299
|
-
'FAILED',
|
|
300
|
-
]
|
|
301
|
-
.filter((part) => part !== undefined && part.length > 0)
|
|
302
|
-
.join('\n'),
|
|
303
|
-
model,
|
|
304
|
-
cli: CLAUDE_CLI_NAME,
|
|
305
|
-
failureClass,
|
|
306
|
-
metadata: {
|
|
307
|
-
stdout: result.stdout,
|
|
308
|
-
stderr: result.stderr,
|
|
309
|
-
exitCode: result.exitCode,
|
|
310
|
-
failureClass,
|
|
311
|
-
...(promptTranscriptPath === undefined ? {} : { promptTranscriptPath }),
|
|
312
|
-
...(responseTranscriptPath === undefined ? {} : { responseTranscriptPath }),
|
|
313
|
-
...(sandboxLog?.metadata ?? {}),
|
|
314
|
-
},
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
|
-
const parsed = parseClaudePrintOutput(result.stdout);
|
|
239
|
+
},
|
|
240
|
+
});
|
|
241
|
+
const responseTranscriptPath = await writeRunnerTranscript({
|
|
242
|
+
config: input.config,
|
|
243
|
+
projection: input.projection,
|
|
244
|
+
runId: input.runId,
|
|
245
|
+
action: input.action,
|
|
246
|
+
cli: CLAUDE_CLI_NAME,
|
|
247
|
+
kind: 'response',
|
|
248
|
+
text: result.stdout,
|
|
249
|
+
});
|
|
250
|
+
if (result.exitCode !== 0 || result.timedOut || result.stdout.trim().length === 0) {
|
|
318
251
|
const sandboxLog = readSandboxLogBreadcrumb();
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
...(parsed.session_id === undefined ? {} : { sessionId: parsed.session_id }),
|
|
327
|
-
payload: { message: 'Claude print result received', raw: parsed },
|
|
328
|
-
}));
|
|
329
|
-
console.log(formatClaudeRunLogLine({
|
|
330
|
-
phase: 'success',
|
|
252
|
+
const failureClass = classifyClaudeCliFailure({
|
|
253
|
+
stdout: result.stdout,
|
|
254
|
+
stderr: result.stderr,
|
|
255
|
+
timedOut: result.timedOut,
|
|
256
|
+
});
|
|
257
|
+
console.error(formatClaudeRunLogLine({
|
|
258
|
+
phase: 'failure',
|
|
331
259
|
runId: input.runId,
|
|
332
260
|
action: input.action,
|
|
333
261
|
issueNumber: input.projection.issue.number,
|
|
@@ -335,21 +263,8 @@ export function createClaudeRunner(options) {
|
|
|
335
263
|
recentEventIds: input.recentEvents.map((event) => event.eventId),
|
|
336
264
|
model,
|
|
337
265
|
...(input.workspacePath === undefined ? {} : { workspacePath: input.workspacePath }),
|
|
338
|
-
|
|
266
|
+
exitCode: result.exitCode,
|
|
339
267
|
}));
|
|
340
|
-
const tokenUsage = extractTokenUsage(parsed);
|
|
341
|
-
if (tokenUsage !== undefined) {
|
|
342
|
-
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
343
|
-
type: 'agent.usage.updated',
|
|
344
|
-
runId: input.runId,
|
|
345
|
-
projection: input.projection,
|
|
346
|
-
routing: input.routing,
|
|
347
|
-
cli: CLAUDE_CLI_NAME,
|
|
348
|
-
model,
|
|
349
|
-
...(parsed.session_id === undefined ? {} : { sessionId: parsed.session_id }),
|
|
350
|
-
payload: { tokenUsage },
|
|
351
|
-
}));
|
|
352
|
-
}
|
|
353
268
|
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
354
269
|
type: 'agent.process.exited',
|
|
355
270
|
runId: input.runId,
|
|
@@ -357,29 +272,124 @@ export function createClaudeRunner(options) {
|
|
|
357
272
|
routing: input.routing,
|
|
358
273
|
cli: CLAUDE_CLI_NAME,
|
|
359
274
|
model,
|
|
360
|
-
...(parsed.session_id === undefined ? {} : { sessionId: parsed.session_id }),
|
|
361
275
|
payload: { exitCode: result.exitCode, timedOut: result.timedOut },
|
|
362
276
|
}));
|
|
277
|
+
let parsedReason;
|
|
278
|
+
let stdoutFailureDetail;
|
|
279
|
+
const trimmedStdout = result.stdout.trim();
|
|
280
|
+
try {
|
|
281
|
+
if (trimmedStdout.length > 0) {
|
|
282
|
+
parsedReason = parseClaudePrintOutput(result.stdout).result;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
// stdout wasn't valid JSON, so it is likely a CLI-level error
|
|
287
|
+
// message rather than a Claude print result.
|
|
288
|
+
stdoutFailureDetail = trimmedStdout;
|
|
289
|
+
}
|
|
363
290
|
return {
|
|
364
|
-
result:
|
|
291
|
+
result: [
|
|
292
|
+
result.timedOut
|
|
293
|
+
? `Claude runner timed out after ${options.settings.timeoutMs}ms and was killed`
|
|
294
|
+
: trimmedStdout.length === 0
|
|
295
|
+
? 'Claude runner produced no output'
|
|
296
|
+
: parsedReason !== undefined
|
|
297
|
+
? `Claude runner failed: ${parsedReason}`
|
|
298
|
+
: 'Claude runner failed',
|
|
299
|
+
result.stderr,
|
|
300
|
+
stdoutFailureDetail,
|
|
301
|
+
sandboxLog?.text,
|
|
302
|
+
'FAILED',
|
|
303
|
+
]
|
|
304
|
+
.filter((part) => part !== undefined && part.length > 0)
|
|
305
|
+
.join('\n'),
|
|
365
306
|
model,
|
|
366
307
|
cli: CLAUDE_CLI_NAME,
|
|
367
|
-
|
|
368
|
-
? { failureClass: 'task' }
|
|
369
|
-
: {}),
|
|
370
|
-
...(parsed.session_id === undefined ? {} : { session_id: parsed.session_id }),
|
|
371
|
-
...(tokenUsage === undefined ? {} : { tokenUsage }),
|
|
308
|
+
failureClass,
|
|
372
309
|
metadata: {
|
|
373
310
|
stdout: result.stdout,
|
|
374
311
|
stderr: result.stderr,
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
allowAutoApproval: stagePrompt.allowAutoApproval,
|
|
312
|
+
exitCode: result.exitCode,
|
|
313
|
+
failureClass,
|
|
378
314
|
...(promptTranscriptPath === undefined ? {} : { promptTranscriptPath }),
|
|
379
315
|
...(responseTranscriptPath === undefined ? {} : { responseTranscriptPath }),
|
|
380
316
|
...(sandboxLog?.metadata ?? {}),
|
|
381
317
|
},
|
|
382
318
|
};
|
|
319
|
+
}
|
|
320
|
+
const parsed = parseClaudePrintOutput(result.stdout);
|
|
321
|
+
const sandboxLog = readSandboxLogBreadcrumb();
|
|
322
|
+
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
323
|
+
type: 'agent.progress',
|
|
324
|
+
runId: input.runId,
|
|
325
|
+
projection: input.projection,
|
|
326
|
+
routing: input.routing,
|
|
327
|
+
cli: CLAUDE_CLI_NAME,
|
|
328
|
+
model,
|
|
329
|
+
...(parsed.session_id === undefined ? {} : { sessionId: parsed.session_id }),
|
|
330
|
+
payload: { message: 'Claude print result received', raw: parsed },
|
|
331
|
+
}));
|
|
332
|
+
console.log(formatClaudeRunLogLine({
|
|
333
|
+
phase: 'success',
|
|
334
|
+
runId: input.runId,
|
|
335
|
+
action: input.action,
|
|
336
|
+
issueNumber: input.projection.issue.number,
|
|
337
|
+
repo: input.projection.issue.repo,
|
|
338
|
+
recentEventIds: input.recentEvents.map((event) => event.eventId),
|
|
339
|
+
model,
|
|
340
|
+
...(input.workspacePath === undefined ? {} : { workspacePath: input.workspacePath }),
|
|
341
|
+
...(parsed.session_id === undefined ? {} : { sessionId: parsed.session_id }),
|
|
342
|
+
}));
|
|
343
|
+
const tokenUsage = extractTokenUsage(parsed);
|
|
344
|
+
if (tokenUsage !== undefined) {
|
|
345
|
+
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
346
|
+
type: 'agent.usage.updated',
|
|
347
|
+
runId: input.runId,
|
|
348
|
+
projection: input.projection,
|
|
349
|
+
routing: input.routing,
|
|
350
|
+
cli: CLAUDE_CLI_NAME,
|
|
351
|
+
model,
|
|
352
|
+
...(parsed.session_id === undefined ? {} : { sessionId: parsed.session_id }),
|
|
353
|
+
payload: { tokenUsage },
|
|
354
|
+
}));
|
|
355
|
+
}
|
|
356
|
+
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
357
|
+
type: 'agent.process.exited',
|
|
358
|
+
runId: input.runId,
|
|
359
|
+
projection: input.projection,
|
|
360
|
+
routing: input.routing,
|
|
361
|
+
cli: CLAUDE_CLI_NAME,
|
|
362
|
+
model,
|
|
363
|
+
...(parsed.session_id === undefined ? {} : { sessionId: parsed.session_id }),
|
|
364
|
+
payload: { exitCode: result.exitCode, timedOut: result.timedOut },
|
|
365
|
+
}));
|
|
366
|
+
return {
|
|
367
|
+
result: parsed.result,
|
|
368
|
+
model,
|
|
369
|
+
cli: CLAUDE_CLI_NAME,
|
|
370
|
+
...(parseRunnerResult(parsed.result).status === 'FAILED'
|
|
371
|
+
? { failureClass: 'task' }
|
|
372
|
+
: {}),
|
|
373
|
+
...(parsed.session_id === undefined ? {} : { session_id: parsed.session_id }),
|
|
374
|
+
...(tokenUsage === undefined ? {} : { tokenUsage }),
|
|
375
|
+
metadata: {
|
|
376
|
+
stdout: result.stdout,
|
|
377
|
+
stderr: result.stderr,
|
|
378
|
+
raw: parsed,
|
|
379
|
+
skipApproval: stagePrompt.skipApproval,
|
|
380
|
+
allowAutoApproval: stagePrompt.allowAutoApproval,
|
|
381
|
+
...(promptTranscriptPath === undefined ? {} : { promptTranscriptPath }),
|
|
382
|
+
...(responseTranscriptPath === undefined ? {} : { responseTranscriptPath }),
|
|
383
|
+
...(sandboxLog?.metadata ?? {}),
|
|
384
|
+
},
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
return {
|
|
388
|
+
async start(input) {
|
|
389
|
+
return createAgentExecution(input, executeRun);
|
|
390
|
+
},
|
|
391
|
+
async run(input) {
|
|
392
|
+
return (await this.start(input)).result;
|
|
383
393
|
},
|
|
384
394
|
async smoke() {
|
|
385
395
|
const args = buildClaudePrintArgs({
|
|
@@ -2,6 +2,7 @@ import { buildStagePrompt } from '../runner/stage-prompt.js';
|
|
|
2
2
|
import { runAgentCliCommand } from '../runner/cli-command.js';
|
|
3
3
|
import { emitRuntimeEvent, runnerRuntimeEvent } from '../runner/runtime-events.js';
|
|
4
4
|
import { writeRunnerTranscript } from '../runner/transcripts.js';
|
|
5
|
+
import { createAgentExecution } from '../../core/live-execution.js';
|
|
5
6
|
import { parseRunnerResult } from '../../domain/schema.js';
|
|
6
7
|
const CODEX_CLI_NAME = 'Codex';
|
|
7
8
|
export function buildCodexExecArgs(input) {
|
|
@@ -201,7 +202,10 @@ export function buildCodexToolCapabilityNote(input) {
|
|
|
201
202
|
return input.mode === 'resume' ? `Reminder: this is still a planning-only stage. ${note}` : note;
|
|
202
203
|
}
|
|
203
204
|
export function createCodexRunner(options) {
|
|
204
|
-
|
|
205
|
+
const runner = {
|
|
206
|
+
async start(input) {
|
|
207
|
+
return createAgentExecution(input, (liveInput) => runner.run(liveInput));
|
|
208
|
+
},
|
|
205
209
|
async run(input) {
|
|
206
210
|
const runMode = 'start';
|
|
207
211
|
const toolCapabilityNote = buildCodexToolCapabilityNote({
|
|
@@ -269,6 +273,9 @@ export function createCodexRunner(options) {
|
|
|
269
273
|
}),
|
|
270
274
|
cwd,
|
|
271
275
|
timeoutMs: options.settings.timeoutMs,
|
|
276
|
+
...(input.cancellationSignal === undefined
|
|
277
|
+
? {}
|
|
278
|
+
: { cancellationSignal: input.cancellationSignal }),
|
|
272
279
|
onProcessStart: async (identity) => {
|
|
273
280
|
await input.onProcessStart?.(identity);
|
|
274
281
|
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
@@ -474,4 +481,5 @@ export function createCodexRunner(options) {
|
|
|
474
481
|
};
|
|
475
482
|
},
|
|
476
483
|
};
|
|
484
|
+
return runner;
|
|
477
485
|
}
|
|
@@ -3,6 +3,7 @@ import { buildStagePrompt } from '../runner/stage-prompt.js';
|
|
|
3
3
|
import { runAgentCliCommand } from '../runner/cli-command.js';
|
|
4
4
|
import { emitRuntimeEvent, runnerRuntimeEvent } from '../runner/runtime-events.js';
|
|
5
5
|
import { writeRunnerTranscript } from '../runner/transcripts.js';
|
|
6
|
+
import { createAgentExecution } from '../../core/live-execution.js';
|
|
6
7
|
const CURSOR_CLI_NAME = 'Cursor';
|
|
7
8
|
export function buildCursorAgentArgs(input) {
|
|
8
9
|
const fullPrompt = buildCursorPromptText(input);
|
|
@@ -154,7 +155,10 @@ function readSandboxLogBreadcrumb() {
|
|
|
154
155
|
};
|
|
155
156
|
}
|
|
156
157
|
export function createCursorRunner(options) {
|
|
157
|
-
|
|
158
|
+
const runner = {
|
|
159
|
+
async start(input) {
|
|
160
|
+
return createAgentExecution(input, (liveInput) => runner.run(liveInput));
|
|
161
|
+
},
|
|
158
162
|
async run(input) {
|
|
159
163
|
const priorSessionId = input.projection.wake.sessionId;
|
|
160
164
|
const priorSessionCli = input.projection.wake.sessionCli;
|
|
@@ -220,6 +224,9 @@ export function createCursorRunner(options) {
|
|
|
220
224
|
}),
|
|
221
225
|
cwd,
|
|
222
226
|
timeoutMs: options.settings.timeoutMs,
|
|
227
|
+
...(input.cancellationSignal === undefined
|
|
228
|
+
? {}
|
|
229
|
+
: { cancellationSignal: input.cancellationSignal }),
|
|
223
230
|
onProcessStart: async (identity) => {
|
|
224
231
|
await input.onProcessStart?.(identity);
|
|
225
232
|
await emitRuntimeEvent(input.onRuntimeEvent, runnerRuntimeEvent({
|
|
@@ -412,4 +419,5 @@ export function createCursorRunner(options) {
|
|
|
412
419
|
};
|
|
413
420
|
},
|
|
414
421
|
};
|
|
422
|
+
return runner;
|
|
415
423
|
}
|
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
import { emitRuntimeEvent, runnerRuntimeEvent } from '../runner/runtime-events.js';
|
|
2
|
+
import { createAgentExecution } from '../../core/live-execution.js';
|
|
2
3
|
export function createFakeRunner(result, options) {
|
|
3
|
-
|
|
4
|
+
const runner = {
|
|
5
|
+
async start(input) {
|
|
6
|
+
return createAgentExecution(input, (liveInput) => runner.run(liveInput));
|
|
7
|
+
},
|
|
4
8
|
async run(_) {
|
|
5
9
|
const cli = options?.cli ?? 'Fake';
|
|
10
|
+
const isCanceled = () => _.cancellationSignal?.aborted === true;
|
|
11
|
+
if (isCanceled()) {
|
|
12
|
+
return {
|
|
13
|
+
result: 'Fake runner canceled\nFAILED',
|
|
14
|
+
model: 'fake',
|
|
15
|
+
cli,
|
|
16
|
+
failureClass: 'infra',
|
|
17
|
+
metadata: { source: 'fake-runner', canceled: true },
|
|
18
|
+
};
|
|
19
|
+
}
|
|
6
20
|
await emitRuntimeEvent(_.onRuntimeEvent, runnerRuntimeEvent({
|
|
7
21
|
type: 'agent.process.started',
|
|
8
22
|
runId: _.runId,
|
|
@@ -32,6 +46,15 @@ export function createFakeRunner(result, options) {
|
|
|
32
46
|
sessionId: 'fake-session-1',
|
|
33
47
|
payload: { exitCode: 0, synthetic: true },
|
|
34
48
|
}));
|
|
49
|
+
if (isCanceled()) {
|
|
50
|
+
return {
|
|
51
|
+
result: 'Fake runner canceled\nFAILED',
|
|
52
|
+
model: 'fake',
|
|
53
|
+
cli,
|
|
54
|
+
failureClass: 'infra',
|
|
55
|
+
metadata: { source: 'fake-runner', canceled: true },
|
|
56
|
+
};
|
|
57
|
+
}
|
|
35
58
|
return (result ?? {
|
|
36
59
|
result: [
|
|
37
60
|
'Fake runner completed',
|
|
@@ -50,4 +73,5 @@ export function createFakeRunner(result, options) {
|
|
|
50
73
|
});
|
|
51
74
|
},
|
|
52
75
|
};
|
|
76
|
+
return runner;
|
|
53
77
|
}
|
|
@@ -11,6 +11,7 @@ export function runAgentCliCommand(input) {
|
|
|
11
11
|
let stdout = '';
|
|
12
12
|
let stderr = '';
|
|
13
13
|
let timedOut = false;
|
|
14
|
+
let canceled = false;
|
|
14
15
|
let killTimer;
|
|
15
16
|
let startNotification = Promise.resolve();
|
|
16
17
|
let startNotificationError;
|
|
@@ -22,13 +23,24 @@ export function runAgentCliCommand(input) {
|
|
|
22
23
|
});
|
|
23
24
|
}
|
|
24
25
|
}
|
|
26
|
+
const terminate = () => {
|
|
27
|
+
child.kill('SIGTERM');
|
|
28
|
+
killTimer = setTimeout(() => child.kill('SIGKILL'), TIMEOUT_KILL_GRACE_MS);
|
|
29
|
+
};
|
|
25
30
|
const timeoutTimer = input.timeoutMs === undefined
|
|
26
31
|
? undefined
|
|
27
32
|
: setTimeout(() => {
|
|
28
33
|
timedOut = true;
|
|
29
|
-
|
|
30
|
-
killTimer = setTimeout(() => child.kill('SIGKILL'), TIMEOUT_KILL_GRACE_MS);
|
|
34
|
+
terminate();
|
|
31
35
|
}, input.timeoutMs);
|
|
36
|
+
const abortListener = () => {
|
|
37
|
+
canceled = true;
|
|
38
|
+
terminate();
|
|
39
|
+
};
|
|
40
|
+
input.cancellationSignal?.addEventListener('abort', abortListener, { once: true });
|
|
41
|
+
if (input.cancellationSignal?.aborted === true) {
|
|
42
|
+
abortListener();
|
|
43
|
+
}
|
|
32
44
|
child.stdout.on('data', (chunk) => {
|
|
33
45
|
stdout += chunk.toString();
|
|
34
46
|
});
|
|
@@ -38,11 +50,13 @@ export function runAgentCliCommand(input) {
|
|
|
38
50
|
child.on('error', (error) => {
|
|
39
51
|
clearTimeout(timeoutTimer);
|
|
40
52
|
clearTimeout(killTimer);
|
|
53
|
+
input.cancellationSignal?.removeEventListener('abort', abortListener);
|
|
41
54
|
reject(error);
|
|
42
55
|
});
|
|
43
56
|
child.on('close', async (exitCode) => {
|
|
44
57
|
clearTimeout(timeoutTimer);
|
|
45
58
|
clearTimeout(killTimer);
|
|
59
|
+
input.cancellationSignal?.removeEventListener('abort', abortListener);
|
|
46
60
|
await startNotification;
|
|
47
61
|
if (startNotificationError !== undefined) {
|
|
48
62
|
reject(startNotificationError);
|
|
@@ -52,7 +66,7 @@ export function runAgentCliCommand(input) {
|
|
|
52
66
|
stdout,
|
|
53
67
|
stderr,
|
|
54
68
|
exitCode: exitCode ?? 1,
|
|
55
|
-
timedOut,
|
|
69
|
+
timedOut: timedOut || canceled,
|
|
56
70
|
});
|
|
57
71
|
});
|
|
58
72
|
});
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { currentProcessIdentity } from '../lib/process-identity.js';
|
|
2
|
+
function createEventQueue() {
|
|
3
|
+
const queue = [];
|
|
4
|
+
const waiters = [];
|
|
5
|
+
let closed = false;
|
|
6
|
+
function emit(value) {
|
|
7
|
+
const waiter = waiters.shift();
|
|
8
|
+
if (waiter !== undefined) {
|
|
9
|
+
waiter(value);
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
queue.push(value);
|
|
13
|
+
}
|
|
14
|
+
async function nextQueued() {
|
|
15
|
+
const value = queue.shift();
|
|
16
|
+
if (value !== undefined)
|
|
17
|
+
return value;
|
|
18
|
+
if (closed)
|
|
19
|
+
return { kind: 'done' };
|
|
20
|
+
return new Promise((resolve) => waiters.push(resolve));
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
push(event) {
|
|
24
|
+
if (!closed)
|
|
25
|
+
emit({ kind: 'event', event });
|
|
26
|
+
},
|
|
27
|
+
close() {
|
|
28
|
+
if (closed)
|
|
29
|
+
return;
|
|
30
|
+
closed = true;
|
|
31
|
+
emit({ kind: 'done' });
|
|
32
|
+
},
|
|
33
|
+
fail(error) {
|
|
34
|
+
if (closed)
|
|
35
|
+
return;
|
|
36
|
+
closed = true;
|
|
37
|
+
emit({ kind: 'error', error });
|
|
38
|
+
},
|
|
39
|
+
iterable: {
|
|
40
|
+
async *[Symbol.asyncIterator]() {
|
|
41
|
+
while (true) {
|
|
42
|
+
const value = await nextQueued();
|
|
43
|
+
if (value.kind === 'done')
|
|
44
|
+
return;
|
|
45
|
+
if (value.kind === 'error')
|
|
46
|
+
throw value.error;
|
|
47
|
+
yield value.event;
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export function createAgentExecution(input, execute) {
|
|
54
|
+
const controller = new AbortController();
|
|
55
|
+
const events = createEventQueue();
|
|
56
|
+
const result = Promise.resolve()
|
|
57
|
+
.then(() => execute({
|
|
58
|
+
...input,
|
|
59
|
+
cancellationSignal: controller.signal,
|
|
60
|
+
onRuntimeEvent: async (event) => {
|
|
61
|
+
await input.onRuntimeEvent?.(event);
|
|
62
|
+
events.push(event);
|
|
63
|
+
},
|
|
64
|
+
}))
|
|
65
|
+
.then((value) => {
|
|
66
|
+
events.close();
|
|
67
|
+
return value;
|
|
68
|
+
}, (error) => {
|
|
69
|
+
events.fail(error);
|
|
70
|
+
throw error;
|
|
71
|
+
});
|
|
72
|
+
return {
|
|
73
|
+
runId: input.runId,
|
|
74
|
+
processIdentity: currentProcessIdentity(),
|
|
75
|
+
events: events.iterable,
|
|
76
|
+
async cancel(reason) {
|
|
77
|
+
controller.abort(reason);
|
|
78
|
+
},
|
|
79
|
+
result,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
@@ -18,12 +18,14 @@ import { createOutbox } from './outbox.js';
|
|
|
18
18
|
import { createEventResolver } from './event-resolver.js';
|
|
19
19
|
import { createStaleRunReconciler } from './stale-run-reconciler.js';
|
|
20
20
|
import { createWorkspaceCleanup } from './workspace-cleanup.js';
|
|
21
|
+
import { createAgentExecution } from './live-execution.js';
|
|
21
22
|
import { createAutonomousDecisionAuditEvent, workflowRevision as computeWorkflowRevision, } from './audit-events.js';
|
|
22
23
|
import { createRunLease, isRunLeaseExpired, renewRunLease, runLeaseRenewalIntervalMs, } from './run-lease.js';
|
|
23
24
|
import { currentProcessIdentity, processIdentityMatches } from '../lib/process-identity.js';
|
|
24
25
|
import { readJsonFile, writeJsonFile } from '../lib/json-file.js';
|
|
25
26
|
import { isMissingPathError } from '../lib/state-health.js';
|
|
26
27
|
const prReviewApprovalMarker = '<!-- wake:pr-review-approved -->';
|
|
28
|
+
const activeRunSourceRefreshIntervalMs = 1_000;
|
|
27
29
|
function latestHumanCommentId(candidate) {
|
|
28
30
|
const human = candidate.comments.filter((c) => !c.isBotAuthored);
|
|
29
31
|
return human.at(-1)?.id;
|
|
@@ -433,6 +435,21 @@ export function createTickRunner(deps) {
|
|
|
433
435
|
function runnerTimeoutMs() {
|
|
434
436
|
return maxConfiguredRunnerTimeoutMs(deps.config);
|
|
435
437
|
}
|
|
438
|
+
function cancellationReasonForIneligibleProjection(projection) {
|
|
439
|
+
if (projection === null || projection.issue.state !== 'open') {
|
|
440
|
+
return 'CANCELED_BY_SOURCE_CLOSED';
|
|
441
|
+
}
|
|
442
|
+
const requiredAssignees = deps.config.sources.github.policy.requiredAssignees;
|
|
443
|
+
if (requiredAssignees.length > 0 &&
|
|
444
|
+
!requiredAssignees.some((login) => projection.issue.assignees.includes(login))) {
|
|
445
|
+
return 'CANCELED_BY_UNASSIGNMENT';
|
|
446
|
+
}
|
|
447
|
+
const workflow = workflowForProjection(projection, deps.config);
|
|
448
|
+
if (workflow === null || !isKnownWorkflowStage(projection.wake.stage, workflow)) {
|
|
449
|
+
return 'CANCELED_BY_WORKFLOW_CHANGE';
|
|
450
|
+
}
|
|
451
|
+
return 'CANCELED_BY_SUPERSEDING_EVENT';
|
|
452
|
+
}
|
|
436
453
|
async function isRunningRecordActive(record, now) {
|
|
437
454
|
if (record.lease !== undefined && !isRunLeaseExpired(record, now)) {
|
|
438
455
|
return true;
|
|
@@ -1171,6 +1188,12 @@ export function createTickRunner(deps) {
|
|
|
1171
1188
|
});
|
|
1172
1189
|
}, runLeaseRenewalIntervalMs);
|
|
1173
1190
|
}
|
|
1191
|
+
function delayActiveRunRefresh() {
|
|
1192
|
+
return new Promise((resolve) => {
|
|
1193
|
+
const timer = setTimeout(resolve, activeRunSourceRefreshIntervalMs);
|
|
1194
|
+
timer.unref?.();
|
|
1195
|
+
});
|
|
1196
|
+
}
|
|
1174
1197
|
try {
|
|
1175
1198
|
await transitionRunLifecycle('PREPARING');
|
|
1176
1199
|
const prepareResult = workspaceMode === 'branch'
|
|
@@ -1202,17 +1225,20 @@ export function createTickRunner(deps) {
|
|
|
1202
1225
|
const recentEvents = await deps.stateStore.listEventEnvelopesForWorkItem(candidate.workItemKey, 6);
|
|
1203
1226
|
await transitionRunLifecycle('RUNNING');
|
|
1204
1227
|
startLeaseRenewal();
|
|
1228
|
+
const activeCandidate = candidate;
|
|
1205
1229
|
const runnerProjection = watcherRun
|
|
1206
1230
|
? {
|
|
1207
|
-
...
|
|
1231
|
+
...activeCandidate,
|
|
1208
1232
|
wake: {
|
|
1209
|
-
...
|
|
1233
|
+
...activeCandidate.wake,
|
|
1210
1234
|
sessionId: undefined,
|
|
1211
1235
|
sessionCli: undefined,
|
|
1212
1236
|
},
|
|
1213
1237
|
}
|
|
1214
|
-
:
|
|
1215
|
-
|
|
1238
|
+
: activeCandidate;
|
|
1239
|
+
let executionFinished = false;
|
|
1240
|
+
let cancellationReason = null;
|
|
1241
|
+
const runnerInput = {
|
|
1216
1242
|
action,
|
|
1217
1243
|
projection: runnerProjection,
|
|
1218
1244
|
recentEvents,
|
|
@@ -1237,7 +1263,79 @@ export function createTickRunner(deps) {
|
|
|
1237
1263
|
});
|
|
1238
1264
|
},
|
|
1239
1265
|
onRuntimeEvent: appendRuntimeEvent,
|
|
1240
|
-
}
|
|
1266
|
+
};
|
|
1267
|
+
const execution = deps.runner.start === undefined
|
|
1268
|
+
? createAgentExecution(runnerInput, (liveInput) => deps.runner.run(liveInput))
|
|
1269
|
+
: await deps.runner.start(runnerInput);
|
|
1270
|
+
async function persistCancellationRequest(reason) {
|
|
1271
|
+
const requestedAt = deps.clock.now().toISOString();
|
|
1272
|
+
await deps.stateStore.updateRunRecordIf(runId, {
|
|
1273
|
+
expect: (record) => record.status === 'running' &&
|
|
1274
|
+
record.lease?.leaseId === lease.leaseId &&
|
|
1275
|
+
record.lease.ownerInstanceId === ownerInstanceId,
|
|
1276
|
+
update: (record) => ({
|
|
1277
|
+
...record,
|
|
1278
|
+
metadata: {
|
|
1279
|
+
...record.metadata,
|
|
1280
|
+
cancellation: {
|
|
1281
|
+
reason,
|
|
1282
|
+
requestedAt,
|
|
1283
|
+
source: 'active-source-reconciliation',
|
|
1284
|
+
},
|
|
1285
|
+
},
|
|
1286
|
+
}),
|
|
1287
|
+
});
|
|
1288
|
+
}
|
|
1289
|
+
async function superviseActiveSource() {
|
|
1290
|
+
if (deps.workSource.refreshForDispatch === undefined) {
|
|
1291
|
+
return null;
|
|
1292
|
+
}
|
|
1293
|
+
while (!executionFinished) {
|
|
1294
|
+
await delayActiveRunRefresh();
|
|
1295
|
+
if (executionFinished) {
|
|
1296
|
+
return null;
|
|
1297
|
+
}
|
|
1298
|
+
let activeRefresh;
|
|
1299
|
+
try {
|
|
1300
|
+
activeRefresh = await deps.workSource.refreshForDispatch({
|
|
1301
|
+
projection: activeCandidate,
|
|
1302
|
+
});
|
|
1303
|
+
}
|
|
1304
|
+
catch {
|
|
1305
|
+
continue;
|
|
1306
|
+
}
|
|
1307
|
+
if (activeRefresh === null) {
|
|
1308
|
+
continue;
|
|
1309
|
+
}
|
|
1310
|
+
if (activeRefresh.events.length > 0) {
|
|
1311
|
+
await ingestInboundEvents(activeRefresh.events);
|
|
1312
|
+
}
|
|
1313
|
+
const refreshedProjection = (await deps.stateStore.readIssueState(activeCandidate.workItemKey)) ??
|
|
1314
|
+
activeCandidate;
|
|
1315
|
+
const ineligible = activeRefresh.sourceExists === false ||
|
|
1316
|
+
!policy.isEligible(refreshedProjection, deps.config);
|
|
1317
|
+
if (!ineligible) {
|
|
1318
|
+
continue;
|
|
1319
|
+
}
|
|
1320
|
+
const reason = cancellationReasonForIneligibleProjection(activeRefresh.sourceExists === false ? null : refreshedProjection);
|
|
1321
|
+
cancellationReason = reason;
|
|
1322
|
+
await persistCancellationRequest(reason);
|
|
1323
|
+
await execution.cancel(reason);
|
|
1324
|
+
return reason;
|
|
1325
|
+
}
|
|
1326
|
+
return null;
|
|
1327
|
+
}
|
|
1328
|
+
const runnerResult = await Promise.race([
|
|
1329
|
+
execution.result.finally(() => {
|
|
1330
|
+
executionFinished = true;
|
|
1331
|
+
}),
|
|
1332
|
+
superviseActiveSource().then(async (reason) => {
|
|
1333
|
+
if (reason === null) {
|
|
1334
|
+
return execution.result;
|
|
1335
|
+
}
|
|
1336
|
+
return execution.result;
|
|
1337
|
+
}),
|
|
1338
|
+
]);
|
|
1241
1339
|
clearInterval(leaseRenewalTimer);
|
|
1242
1340
|
leaseRenewalTimer = undefined;
|
|
1243
1341
|
const parsedRunnerResult = parseRunnerResult(runnerResult.result);
|
|
@@ -1343,16 +1441,19 @@ export function createTickRunner(deps) {
|
|
|
1343
1441
|
const resultMetadata = {
|
|
1344
1442
|
...runnerResult.metadata,
|
|
1345
1443
|
envelope: parsedRunnerResult.envelope,
|
|
1444
|
+
...(cancellationReason === null ? {} : { cancellationReason }),
|
|
1346
1445
|
...(runnerResult.failureClass === undefined
|
|
1347
1446
|
? {}
|
|
1348
1447
|
: { failureClass: runnerResult.failureClass }),
|
|
1349
1448
|
...(runnerResult.routing === undefined ? {} : { routing: runnerResult.routing }),
|
|
1350
1449
|
};
|
|
1351
|
-
const executionOutcome =
|
|
1352
|
-
?
|
|
1353
|
-
: runnerResult.failureClass === '
|
|
1354
|
-
? '
|
|
1355
|
-
: '
|
|
1450
|
+
const executionOutcome = cancellationReason !== null
|
|
1451
|
+
? cancellationReason
|
|
1452
|
+
: runnerResult.failureClass === 'quota'
|
|
1453
|
+
? 'QUOTA_EXHAUSTED'
|
|
1454
|
+
: runnerResult.failureClass === 'infra'
|
|
1455
|
+
? 'PROCESS_FAILED'
|
|
1456
|
+
: 'COMPLETED';
|
|
1356
1457
|
const workflowOutcome = sentinel === 'DONE'
|
|
1357
1458
|
? 'DONE'
|
|
1358
1459
|
: sentinel === 'BLOCKED'
|
|
@@ -1410,7 +1511,9 @@ export function createTickRunner(deps) {
|
|
|
1410
1511
|
sessionId: runnerResult.session_id,
|
|
1411
1512
|
sessionCli: runnerResult.cli,
|
|
1412
1513
|
workspacePath,
|
|
1413
|
-
reason:
|
|
1514
|
+
reason: cancellationReason === null
|
|
1515
|
+
? `runner:${sentinel.toLowerCase()}`
|
|
1516
|
+
: `runner:${String(cancellationReason).toLowerCase()}`,
|
|
1414
1517
|
...(runnerResult.routing === undefined ? {} : { routing: runnerResult.routing }),
|
|
1415
1518
|
...(runnerResult.failureClass === undefined
|
|
1416
1519
|
? {}
|
|
@@ -24,6 +24,10 @@ export const executionOutcomeValues = [
|
|
|
24
24
|
'TIMED_OUT',
|
|
25
25
|
'STALLED',
|
|
26
26
|
'CANCELED_BY_RECONCILIATION',
|
|
27
|
+
'CANCELED_BY_SOURCE_CLOSED',
|
|
28
|
+
'CANCELED_BY_UNASSIGNMENT',
|
|
29
|
+
'CANCELED_BY_SUPERSEDING_EVENT',
|
|
30
|
+
'CANCELED_BY_WORKFLOW_CHANGE',
|
|
27
31
|
'CANCELED_BY_OPERATOR',
|
|
28
32
|
'QUOTA_EXHAUSTED',
|
|
29
33
|
'MALFORMED_OUTPUT',
|
package/dist/src/version.js
CHANGED