@commonlyai/cli 0.1.188 → 0.1.189
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/package.json +1 -1
- package/src/lib/adapters/opencode.js +33 -5
package/package.json
CHANGED
|
@@ -301,12 +301,19 @@ const validateProviderEnvironment = async (environment, workspacePath) => {
|
|
|
301
301
|
return resolveProviderKeyFile(environment.provider, workspacePath);
|
|
302
302
|
};
|
|
303
303
|
|
|
304
|
+
const STALE_SESSION_PATTERN = /session not found/i;
|
|
305
|
+
// Set by runOpenCode only when the rejected run produced no turn output, so a
|
|
306
|
+
// phrase that shows up after the model acted cannot replay the turn.
|
|
307
|
+
const isStaleSessionError = (err) => err?.staleSession === true;
|
|
308
|
+
|
|
304
309
|
const makeEventParser = () => {
|
|
305
310
|
let buffer = '';
|
|
306
311
|
let sessionId = null;
|
|
307
312
|
let text = '';
|
|
308
313
|
let usage = null;
|
|
309
314
|
let errorMessage = null;
|
|
315
|
+
// Any text, tool call or step result means the model acted this run.
|
|
316
|
+
let turnOutput = false;
|
|
310
317
|
// Every tool call that came back as an error, for the public-seat check in
|
|
311
318
|
// spawn (publicToolFailure).
|
|
312
319
|
const toolErrors = [];
|
|
@@ -315,11 +322,15 @@ const makeEventParser = () => {
|
|
|
315
322
|
try {
|
|
316
323
|
const event = JSON.parse(line);
|
|
317
324
|
if (event.sessionID) sessionId = event.sessionID;
|
|
325
|
+
// Any step event means the run started a turn, so it is not safe to replay.
|
|
326
|
+
if (String(event.type || '').startsWith('step_') || event.type === 'tool_use') turnOutput = true;
|
|
318
327
|
if (event.type === 'text' && typeof event.part?.text === 'string') {
|
|
328
|
+
turnOutput = true;
|
|
319
329
|
text += event.part.text;
|
|
320
330
|
} else if (event.type === 'step_finish' && event.part?.tokens) {
|
|
321
331
|
usage = event.part.tokens;
|
|
322
|
-
}
|
|
332
|
+
}
|
|
333
|
+
if (event.type === 'tool_use' && event.part?.state?.status === 'error') {
|
|
323
334
|
const { error } = event.part.state;
|
|
324
335
|
toolErrors.push({
|
|
325
336
|
tool: String(event.part.tool || ''),
|
|
@@ -334,6 +345,7 @@ const makeEventParser = () => {
|
|
|
334
345
|
}
|
|
335
346
|
};
|
|
336
347
|
return {
|
|
348
|
+
get turnOutput() { return turnOutput; },
|
|
337
349
|
consume(chunk) {
|
|
338
350
|
buffer += chunk.toString();
|
|
339
351
|
let newline;
|
|
@@ -428,14 +440,18 @@ const runOpenCode = ({ cmd, args, cwd, env, timeoutMs, credentials, spawnImpl =
|
|
|
428
440
|
events.flush();
|
|
429
441
|
if (timedOut) return reject(new Error(`opencode timed out after ${timeoutMs}ms`));
|
|
430
442
|
if (events.errorMessage) {
|
|
431
|
-
|
|
443
|
+
const err = adapterFailure('opencode turn failed', events.errorMessage, {
|
|
432
444
|
credentials, limit: 2000,
|
|
433
|
-
})
|
|
445
|
+
});
|
|
446
|
+
err.staleSession = !events.turnOutput && STALE_SESSION_PATTERN.test(events.errorMessage);
|
|
447
|
+
return reject(err);
|
|
434
448
|
}
|
|
435
449
|
if (code !== 0) {
|
|
436
|
-
|
|
450
|
+
const err = adapterFailure('opencode', stderr.trim(), {
|
|
437
451
|
credentials, exitCode: code, limit: 500,
|
|
438
|
-
})
|
|
452
|
+
});
|
|
453
|
+
err.staleSession = !events.turnOutput && STALE_SESSION_PATTERN.test(stderr);
|
|
454
|
+
return reject(err);
|
|
439
455
|
}
|
|
440
456
|
resolve({
|
|
441
457
|
sessionId: events.sessionId, text: events.text, usage: events.usage, toolErrors: events.toolErrors,
|
|
@@ -650,6 +666,18 @@ export default {
|
|
|
650
666
|
},
|
|
651
667
|
|
|
652
668
|
async spawn(prompt, rawCtx = {}) {
|
|
669
|
+
try {
|
|
670
|
+
return await this.spawnTurn(prompt, rawCtx);
|
|
671
|
+
} catch (err) {
|
|
672
|
+
if (!rawCtx.sessionId || !isStaleSessionError(err)) throw err;
|
|
673
|
+
// The saved id is one OpenCode does not know: a seat switched from another
|
|
674
|
+
// adapter carries a Claude id, and a pruned session fails the same way. Nothing
|
|
675
|
+
// ran, so one fresh turn is safe (pi #1726 does the same fallback).
|
|
676
|
+
return this.spawnTurn(prompt, { ...rawCtx, sessionId: null });
|
|
677
|
+
}
|
|
678
|
+
},
|
|
679
|
+
|
|
680
|
+
async spawnTurn(prompt, rawCtx = {}) {
|
|
653
681
|
const seatModel = requireSeatModel(rawCtx.environment, 'opencode');
|
|
654
682
|
const sandbox = normalizeSandboxTrust(rawCtx.environment?.sandbox);
|
|
655
683
|
refuseWorkspaceTrust(sandbox, 'opencode');
|