@bridge4dev/runner 0.33.0 → 0.35.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.
- package/dist/adapters/claude.js +30 -2
- package/dist/adapters/codex.js +28 -8
- package/dist/index.js +13 -1
- package/dist/supervisor.d.ts +38 -0
- package/dist/supervisor.js +108 -6
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +9 -9
package/dist/adapters/claude.js
CHANGED
|
@@ -1800,11 +1800,39 @@ class ClaudeSession {
|
|
|
1800
1800
|
break;
|
|
1801
1801
|
}
|
|
1802
1802
|
case 'assistant': {
|
|
1803
|
+
// Ticket #186. A subagent's own prose is NOT this session's answer.
|
|
1804
|
+
//
|
|
1805
|
+
// The SDK's own note — «by default, only tool_use/tool_result blocks
|
|
1806
|
+
// from subagents are emitted» — covers SYNCHRONOUS Task subagents. A
|
|
1807
|
+
// BACKGROUND agent's closing report is delivered regardless, as an
|
|
1808
|
+
// ordinary top-level assistant message that merely carries
|
|
1809
|
+
// `parent_tool_use_id` (probe against 0.3.226, 2026-08-08):
|
|
1810
|
+
//
|
|
1811
|
+
// {type:'assistant', parent_tool_use_id:'toolu_…',
|
|
1812
|
+
// subagent_type:'general-purpose', task_description:'…',
|
|
1813
|
+
// message:{content:[{type:'text', text:'…'}]}}
|
|
1814
|
+
//
|
|
1815
|
+
// Session 50eb77b9 put two of those — 46 655 and 16 368 characters of
|
|
1816
|
+
// internal survey — into the feed four seconds after an
|
|
1817
|
+
// AskUserQuestion card, while the main agent was blocked on the very
|
|
1818
|
+
// tool call that card belongs to and could not have written a word.
|
|
1819
|
+
//
|
|
1820
|
+
// Only text and thinking are dropped. `tool_use` stays, and so does
|
|
1821
|
+
// the paired `tool_result` in `case 'user'` below: the dashboard
|
|
1822
|
+
// resolves a result by toolUseId and falls back to the last unfinished
|
|
1823
|
+
// row, so filtering one arm without the other sticks a subagent's
|
|
1824
|
+
// result onto a stranger's row (that fallback has misfired before).
|
|
1825
|
+
//
|
|
1826
|
+
// The test is «is a string», not «is not null»: an emitter that
|
|
1827
|
+
// omits the field must read as the main loop. Treating a missing
|
|
1828
|
+
// field as a subagent would blank the transcript of every session on
|
|
1829
|
+
// that CLI, which is a far worse failure than one leaked report.
|
|
1830
|
+
const fromSubagent = typeof msg.parent_tool_use_id === 'string';
|
|
1803
1831
|
for (const block of msg.message.content) {
|
|
1804
|
-
if (block.type === 'text' && block.text.trim()) {
|
|
1832
|
+
if (block.type === 'text' && !fromSubagent && block.text.trim()) {
|
|
1805
1833
|
this.emit({ type: 'message', role: 'assistant', text: truncate(block.text) });
|
|
1806
1834
|
}
|
|
1807
|
-
else if (block.type === 'thinking' && block.thinking.trim()) {
|
|
1835
|
+
else if (block.type === 'thinking' && !fromSubagent && block.thinking.trim()) {
|
|
1808
1836
|
this.emit({ type: 'thinking', text: truncate(block.thinking, 8_000) });
|
|
1809
1837
|
}
|
|
1810
1838
|
else if (block.type === 'tool_use') {
|
package/dist/adapters/codex.js
CHANGED
|
@@ -483,21 +483,41 @@ class CodexSession {
|
|
|
483
483
|
// settings/update in this protocol version).
|
|
484
484
|
...(this.effort ? { effort: this.effort } : {}),
|
|
485
485
|
};
|
|
486
|
-
// Collaboration mode is turn-scoped but sticky,
|
|
487
|
-
//
|
|
486
|
+
// Collaboration mode is turn-scoped but sticky, so it is only sent on a real
|
|
487
|
+
// change. What it must NOT carry is our own instructions (ticket #179).
|
|
488
488
|
//
|
|
489
|
-
//
|
|
490
|
-
//
|
|
491
|
-
//
|
|
492
|
-
//
|
|
493
|
-
//
|
|
489
|
+
// The line that used to sit here said `settings` REPLACE the thread's
|
|
490
|
+
// developer instructions, and that passing `null` meant «no developer
|
|
491
|
+
// instructions at all». Both halves are false, and the first one cost the
|
|
492
|
+
// product a duplicated system prompt in every Codex session. Measured on the
|
|
493
|
+
// wire — a fake Responses API behind `codex app-server`, reading the developer
|
|
494
|
+
// message verbatim — on codex-cli 0.135.0 AND 0.147.0, which behave alike:
|
|
495
|
+
//
|
|
496
|
+
// thread developerInstructions + collaborationMode carrying the same text
|
|
497
|
+
// → the text appears TWICE in one developer message: once at the top (on
|
|
498
|
+
// 0.135.0, right after `<permissions instructions>`) and again inside
|
|
499
|
+
// `<collaboration_mode>…</collaboration_mode>`. That is exactly what the
|
|
500
|
+
// ticket's screenshots show, and with a real project prompt it is ~27 KB
|
|
501
|
+
// sent twice on every single request.
|
|
502
|
+
// thread developerInstructions + `developer_instructions: null`
|
|
503
|
+
// → the text appears ONCE, and `<collaboration_mode>` carries Codex's own
|
|
504
|
+
// preset for the mode («# Plan Mode (Conversational)…»).
|
|
505
|
+
//
|
|
506
|
+
// So `null` is not a loss, it is the fix — and it repairs a second, quieter
|
|
507
|
+
// defect at the same time: our text was OVERWRITING Codex's built-in plan
|
|
508
|
+
// instructions, i.e. the one mode a user picks to make the agent think before
|
|
509
|
+
// acting was the one mode that never received the instructions for thinking
|
|
510
|
+
// before acting. The thread-level channel (`threadParams`) stays the single
|
|
511
|
+
// source of DevBridge's rules, exactly like `systemPrompt.append` on Claude.
|
|
494
512
|
if (this.lastCollabMode !== wantCollab) {
|
|
495
513
|
params['collaborationMode'] = {
|
|
496
514
|
mode: wantCollab,
|
|
497
515
|
settings: {
|
|
498
516
|
model: this.model ?? this.threadModel ?? 'gpt-5.5',
|
|
499
517
|
reasoning_effort: null,
|
|
500
|
-
|
|
518
|
+
// «Use the built-in instructions for the selected mode» — the app-server
|
|
519
|
+
// schema's own words. Ours already arrived with the thread.
|
|
520
|
+
developer_instructions: null,
|
|
501
521
|
},
|
|
502
522
|
};
|
|
503
523
|
this.lastCollabMode = wantCollab;
|
package/dist/index.js
CHANGED
|
@@ -35,6 +35,18 @@ const LAST_EXIT = takeLastExit();
|
|
|
35
35
|
function print(line) {
|
|
36
36
|
process.stdout.write(line + '\n');
|
|
37
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Дата для оператора, который читает вывод у себя в консоли.
|
|
40
|
+
*
|
|
41
|
+
* Раньше здесь стояло `iso.slice(0, 10)` — это UTC-день, а не день того, кто
|
|
42
|
+
* смотрит: к востоку от Гринвича поздним вечером он показывает вчерашнее число.
|
|
43
|
+
* Часы машины оператора — единственный разумный ответ: у раннера нет ни
|
|
44
|
+
* человека с настройкой, ни организации.
|
|
45
|
+
*/
|
|
46
|
+
function formatLocalDay(iso) {
|
|
47
|
+
const date = new Date(iso);
|
|
48
|
+
return Number.isNaN(date.getTime()) ? iso.slice(0, 10) : date.toLocaleDateString();
|
|
49
|
+
}
|
|
38
50
|
function fail(message) {
|
|
39
51
|
process.stderr.write(`error: ${message}\n`);
|
|
40
52
|
process.exit(1);
|
|
@@ -908,7 +920,7 @@ async function agentChecks() {
|
|
|
908
920
|
ok: signedIn,
|
|
909
921
|
name: `${agent} login`,
|
|
910
922
|
detail: (info.detail ?? info.status) +
|
|
911
|
-
(info.expiresAt ? ` · until ${info.expiresAt
|
|
923
|
+
(info.expiresAt ? ` · until ${formatLocalDay(info.expiresAt)}` : ''),
|
|
912
924
|
...(signedIn
|
|
913
925
|
? {}
|
|
914
926
|
: {
|
package/dist/supervisor.d.ts
CHANGED
|
@@ -136,6 +136,20 @@ export declare class Supervisor {
|
|
|
136
136
|
* refuse writes to it: in `workMode: DIRECT` the project folder is the
|
|
137
137
|
* agent's own working directory, so without that rule a session could rewrite
|
|
138
138
|
* the prompt it will itself be started with next time (QA-130 MAJOR-3).
|
|
139
|
+
*
|
|
140
|
+
* @param resuming This launch continues an existing agent conversation. It
|
|
141
|
+
* changes only the WORDS, never the behaviour — and the words matter,
|
|
142
|
+
* because a person who has just watched their session crash reads a second
|
|
143
|
+
* «Project prompt loaded» as «my context was thrown away» (ticket #177).
|
|
144
|
+
* Measured, so the line can say it plainly: a system prompt lives in the
|
|
145
|
+
* agent PROCESS, not in the saved conversation. Resuming Claude Code
|
|
146
|
+
* without re-supplying `--append-system-prompt` restores every message and
|
|
147
|
+
* ZERO bytes of the appended prompt; re-supplying it restores the same
|
|
148
|
+
* messages and exactly ONE copy of the prompt, never two. Codex is the same
|
|
149
|
+
* fact by a different route — it rebuilds the developer message from the
|
|
150
|
+
* current parameters on every request. So re-reading the file here is not
|
|
151
|
+
* waste, and skipping it would silently strip the project's rules (and
|
|
152
|
+
* DevBridge's own) from every session that ever resumed.
|
|
139
153
|
*/
|
|
140
154
|
private resolveAgentPrompt;
|
|
141
155
|
/** Warn the user when this share of the budget is gone. */
|
|
@@ -246,6 +260,30 @@ export declare class Supervisor {
|
|
|
246
260
|
* rewound (ticket #126).
|
|
247
261
|
*/
|
|
248
262
|
private park;
|
|
263
|
+
/**
|
|
264
|
+
* The agent is producing output while this runner still says a human is
|
|
265
|
+
* expected — put `lastReported` back to RUNNING (ticket #185).
|
|
266
|
+
*
|
|
267
|
+
* This is not cosmetics on top of the API's own repair. While `lastReported`
|
|
268
|
+
* lies, two things break here and only here:
|
|
269
|
+
*
|
|
270
|
+
* - `isParkable()` reads WAITING_INPUT with no open question as «idle», so
|
|
271
|
+
* `ensureCapacity` may KILL a live agent process to hand its slot to
|
|
272
|
+
* another session;
|
|
273
|
+
* - `isBillable()` counts only RUNNING/STARTING, so `agentActiveMs` stops
|
|
274
|
+
* growing and the time budget never fires for work that is really happening.
|
|
275
|
+
*
|
|
276
|
+
* It happens for real: a background subagent's report wakes a new turn inside
|
|
277
|
+
* the agent process (SDK 0.3.226 emits a second `system:init` and a `result`
|
|
278
|
+
* carrying `origin: {kind:'task-notification'}`), and nothing here reports a
|
|
279
|
+
* turn the runner did not start. Compaction does the same, and so does a
|
|
280
|
+
* question this runner withdraws by itself.
|
|
281
|
+
*
|
|
282
|
+
* An open question is the one thing that must survive: there, WAITING_INPUT
|
|
283
|
+
* means a tool call is parked on a person, and the agent narrating around its
|
|
284
|
+
* own question must not take the card off the screen.
|
|
285
|
+
*/
|
|
286
|
+
private noteAgentIsWorking;
|
|
249
287
|
private forwardEvent;
|
|
250
288
|
/**
|
|
251
289
|
* The dashboard's answer to a parked question (session 12).
|
package/dist/supervisor.js
CHANGED
|
@@ -22,6 +22,12 @@ import { availableModes, MODE_REFUSED_TEXT } from './adapters/types.js';
|
|
|
22
22
|
/** Refusals shared by every checkpoint command (ticket #126). */
|
|
23
23
|
const CHECKPOINTS_OFF = 'Restore points are switched off on this server ([checkpoints] enabled = false)';
|
|
24
24
|
const AGENT_BUSY = 'The agent is still working — stop the turn first';
|
|
25
|
+
/**
|
|
26
|
+
* Adapter events that exist only because the agent is producing output right
|
|
27
|
+
* now (ticket #185). `message` is deliberately absent — a user echo carries the
|
|
28
|
+
* same type and proves nothing about the agent — and is handled at the call site.
|
|
29
|
+
*/
|
|
30
|
+
const AGENT_OUTPUT_EVENTS = new Set(['tool', 'thinking']);
|
|
25
31
|
/**
|
|
26
32
|
* The project's git policy, lifted out of a session descriptor (session 18).
|
|
27
33
|
*
|
|
@@ -352,8 +358,19 @@ export class Supervisor {
|
|
|
352
358
|
if (descriptor.epoch > 0) {
|
|
353
359
|
// The API owns the resume transition; the feed marker has to come from
|
|
354
360
|
// here because the runner is the only writer of the event seq.
|
|
361
|
+
//
|
|
362
|
+
// Ticket #177: which of the two sentences is true depends on whether
|
|
363
|
+
// there is a conversation to go back to. `providerSessionId` is the
|
|
364
|
+
// agent's own name for it, and it is what the next launch hands to
|
|
365
|
+
// `--resume` / `thread/resume`. Without it the next process starts the
|
|
366
|
+
// conversation over — which is a real loss, and promising «continue
|
|
367
|
+
// where the agent left off» there is the one thing the feed must not do.
|
|
368
|
+
// It happens for real: a process that dies before it reports its session
|
|
369
|
+
// id (the SIGABRT this ticket came from) leaves the row with none.
|
|
355
370
|
this.sendEvent(running, 'system_note', {
|
|
356
|
-
text:
|
|
371
|
+
text: descriptor.providerSessionId
|
|
372
|
+
? 'Session resumed — the agent still has this conversation. Send a message to continue where it left off.'
|
|
373
|
+
: 'Session resumed, but the agent never got as far as naming its conversation, so it starts this one over. Your files, your branch and everything above are untouched.',
|
|
357
374
|
});
|
|
358
375
|
}
|
|
359
376
|
running.lastReported = descriptor.status === 'REVIEW' ? 'REVIEW' : 'WAITING_INPUT';
|
|
@@ -438,7 +455,14 @@ export class Supervisor {
|
|
|
438
455
|
// Facts about this session only, plus the one file the project named. The
|
|
439
456
|
// rest of the project's documentation is read by each agent itself — see
|
|
440
457
|
// `composeWorkspaceContext`.
|
|
441
|
-
|
|
458
|
+
// Does this launch CONTINUE the agent's conversation or begin a new one?
|
|
459
|
+
// Read before `rewindAnchor` is consumed below, and without consuming it —
|
|
460
|
+
// the prompt notice says different things about the two cases (#177).
|
|
461
|
+
// A rewind resumes a conversation too, but a CUT one — so it gets neither
|
|
462
|
+
// «loaded» nor «unchanged».
|
|
463
|
+
const rewinding = Boolean(running.rewindAnchor?.agentSession);
|
|
464
|
+
const resuming = rewinding || Boolean(resumeId);
|
|
465
|
+
const agentPrompt = this.resolveAgentPrompt(running, resuming && !rewinding);
|
|
442
466
|
const workspaceContext = composeWorkspaceContext(descriptor, agentPrompt?.text);
|
|
443
467
|
const rewind = running.rewindAnchor;
|
|
444
468
|
delete running.rewindAnchor;
|
|
@@ -509,8 +533,22 @@ export class Supervisor {
|
|
|
509
533
|
* refuse writes to it: in `workMode: DIRECT` the project folder is the
|
|
510
534
|
* agent's own working directory, so without that rule a session could rewrite
|
|
511
535
|
* the prompt it will itself be started with next time (QA-130 MAJOR-3).
|
|
536
|
+
*
|
|
537
|
+
* @param resuming This launch continues an existing agent conversation. It
|
|
538
|
+
* changes only the WORDS, never the behaviour — and the words matter,
|
|
539
|
+
* because a person who has just watched their session crash reads a second
|
|
540
|
+
* «Project prompt loaded» as «my context was thrown away» (ticket #177).
|
|
541
|
+
* Measured, so the line can say it plainly: a system prompt lives in the
|
|
542
|
+
* agent PROCESS, not in the saved conversation. Resuming Claude Code
|
|
543
|
+
* without re-supplying `--append-system-prompt` restores every message and
|
|
544
|
+
* ZERO bytes of the appended prompt; re-supplying it restores the same
|
|
545
|
+
* messages and exactly ONE copy of the prompt, never two. Codex is the same
|
|
546
|
+
* fact by a different route — it rebuilds the developer message from the
|
|
547
|
+
* current parameters on every request. So re-reading the file here is not
|
|
548
|
+
* waste, and skipping it would silently strip the project's rules (and
|
|
549
|
+
* DevBridge's own) from every session that ever resumed.
|
|
512
550
|
*/
|
|
513
|
-
resolveAgentPrompt(running) {
|
|
551
|
+
resolveAgentPrompt(running, resuming = false) {
|
|
514
552
|
const { descriptor } = running;
|
|
515
553
|
const configured = descriptor.workspace.agentPromptPath?.trim();
|
|
516
554
|
if (!configured)
|
|
@@ -551,7 +589,9 @@ export class Supervisor {
|
|
|
551
589
|
// mode.
|
|
552
590
|
this.sendEvent(running, 'notice', {
|
|
553
591
|
level: 'info',
|
|
554
|
-
text:
|
|
592
|
+
text: resuming
|
|
593
|
+
? `Project prompt re-applied from ${quotePath(result.relPath)} — ${agentPromptSizeLabel(result.bytes)}, sha ${result.sha}. A new agent process needs it again; the conversation is unchanged.`
|
|
594
|
+
: `Project prompt loaded from ${quotePath(result.relPath)} — ${agentPromptSizeLabel(result.bytes)}, sha ${result.sha}.`,
|
|
555
595
|
});
|
|
556
596
|
return { text: result.text, absPath: result.absPath };
|
|
557
597
|
}
|
|
@@ -1046,8 +1086,47 @@ export class Supervisor {
|
|
|
1046
1086
|
}
|
|
1047
1087
|
running.session.stop('session_parked');
|
|
1048
1088
|
}
|
|
1089
|
+
/**
|
|
1090
|
+
* The agent is producing output while this runner still says a human is
|
|
1091
|
+
* expected — put `lastReported` back to RUNNING (ticket #185).
|
|
1092
|
+
*
|
|
1093
|
+
* This is not cosmetics on top of the API's own repair. While `lastReported`
|
|
1094
|
+
* lies, two things break here and only here:
|
|
1095
|
+
*
|
|
1096
|
+
* - `isParkable()` reads WAITING_INPUT with no open question as «idle», so
|
|
1097
|
+
* `ensureCapacity` may KILL a live agent process to hand its slot to
|
|
1098
|
+
* another session;
|
|
1099
|
+
* - `isBillable()` counts only RUNNING/STARTING, so `agentActiveMs` stops
|
|
1100
|
+
* growing and the time budget never fires for work that is really happening.
|
|
1101
|
+
*
|
|
1102
|
+
* It happens for real: a background subagent's report wakes a new turn inside
|
|
1103
|
+
* the agent process (SDK 0.3.226 emits a second `system:init` and a `result`
|
|
1104
|
+
* carrying `origin: {kind:'task-notification'}`), and nothing here reports a
|
|
1105
|
+
* turn the runner did not start. Compaction does the same, and so does a
|
|
1106
|
+
* question this runner withdraws by itself.
|
|
1107
|
+
*
|
|
1108
|
+
* An open question is the one thing that must survive: there, WAITING_INPUT
|
|
1109
|
+
* means a tool call is parked on a person, and the agent narrating around its
|
|
1110
|
+
* own question must not take the card off the screen.
|
|
1111
|
+
*/
|
|
1112
|
+
noteAgentIsWorking(running) {
|
|
1113
|
+
if (running.openQuestions.size > 0)
|
|
1114
|
+
return;
|
|
1115
|
+
if (running.stopRequested || running.parkRequested || running.budgetSpent)
|
|
1116
|
+
return;
|
|
1117
|
+
if (running.lastReported !== 'WAITING_INPUT' && running.lastReported !== 'REVIEW')
|
|
1118
|
+
return;
|
|
1119
|
+
running.lastReported = 'RUNNING';
|
|
1120
|
+
this.syncBudgetClock(running);
|
|
1121
|
+
this.reportStatus(running.descriptor.id, 'RUNNING', {});
|
|
1122
|
+
}
|
|
1049
1123
|
forwardEvent(running, event) {
|
|
1050
1124
|
const { descriptor } = running;
|
|
1125
|
+
// Anything below that is the agent talking means the agent is working. Read
|
|
1126
|
+
// before the switch so every such case gets it, including the ones added
|
|
1127
|
+
// after this line was written.
|
|
1128
|
+
if (event.type === 'message' ? event.role === 'assistant' : AGENT_OUTPUT_EVENTS.has(event.type))
|
|
1129
|
+
this.noteAgentIsWorking(running);
|
|
1051
1130
|
switch (event.type) {
|
|
1052
1131
|
case 'provider_session': {
|
|
1053
1132
|
running.descriptor = { ...descriptor, providerSessionId: event.providerSessionId };
|
|
@@ -2050,7 +2129,13 @@ export class Supervisor {
|
|
|
2050
2129
|
*/
|
|
2051
2130
|
const wasMidTurn = descriptor.status === 'RUNNING' || descriptor.status === 'WAITING_PERMISSION';
|
|
2052
2131
|
const resumeId = descriptor.providerSessionId;
|
|
2053
|
-
|
|
2132
|
+
// Ticket #177: `resumeId` is required, not merely nice to have. Without
|
|
2133
|
+
// it the relaunch starts a FRESH conversation, and `AUTO_RESUME_PROMPT`
|
|
2134
|
+
// — "continue from where you stopped, re-check what you were in the
|
|
2135
|
+
// middle of" — would be addressed to an agent that remembers none of
|
|
2136
|
+
// it. A process killed before it reported its session id (the SIGABRT
|
|
2137
|
+
// this ticket came from) leaves the row in exactly that state.
|
|
2138
|
+
const willContinue = wasMidTurn && Boolean(resumeId) && claimAutoResume(descriptor.id);
|
|
2054
2139
|
// The note stays either way (owner's call): an interruption is a fact
|
|
2055
2140
|
// about the session and must not disappear just because we recovered
|
|
2056
2141
|
// from it. Only the instruction at the end changes — telling someone to
|
|
@@ -2058,7 +2143,9 @@ export class Supervisor {
|
|
|
2058
2143
|
this.sendEvent(running, 'system_note', {
|
|
2059
2144
|
text: willContinue
|
|
2060
2145
|
? 'Runner reconnected. The session was resumed — continuing the interrupted turn.'
|
|
2061
|
-
:
|
|
2146
|
+
: resumeId
|
|
2147
|
+
? 'Runner reconnected. The session was resumed — send a message to continue.'
|
|
2148
|
+
: 'Runner reconnected, but the agent never got as far as naming its conversation, so it starts this one over. Your files, your branch and everything above are untouched.',
|
|
2062
2149
|
});
|
|
2063
2150
|
if (willContinue) {
|
|
2064
2151
|
// Resumed through the PROVIDER session, so the agent keeps its whole
|
|
@@ -2431,6 +2518,21 @@ export class Supervisor {
|
|
|
2431
2518
|
error: 'The agent could not compact right now — wait for the current turn to finish',
|
|
2432
2519
|
});
|
|
2433
2520
|
}
|
|
2521
|
+
// Ticket #185. Compaction is a whole agent turn — `/compact` goes in
|
|
2522
|
+
// as an ordinary user message — and until now nobody said so: the
|
|
2523
|
+
// session read «Ваш ход» for the entire squeeze, and the dashboard
|
|
2524
|
+
// papered over it with `compactingSince`, a variable that exists only
|
|
2525
|
+
// in the tab that pressed the button. A second tab, a teammate or a
|
|
2526
|
+
// reload saw a session waiting for a person who had nothing to do.
|
|
2527
|
+
//
|
|
2528
|
+
// It is also not only cosmetic here: a session reading WAITING_INPUT
|
|
2529
|
+
// with no open question is parkable, and parking it would kill the
|
|
2530
|
+
// compaction mid-flight.
|
|
2531
|
+
if (running.lastReported !== 'RUNNING') {
|
|
2532
|
+
running.lastReported = 'RUNNING';
|
|
2533
|
+
this.syncBudgetClock(running);
|
|
2534
|
+
this.reportStatus(running.descriptor.id, 'RUNNING', {});
|
|
2535
|
+
}
|
|
2434
2536
|
return void reply({ ok: true, result: { started: true } });
|
|
2435
2537
|
}
|
|
2436
2538
|
case 'git_status': {
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const RUNNER_VERSION = "0.
|
|
1
|
+
export declare const RUNNER_VERSION = "0.35.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bridge4dev/runner",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.0",
|
|
4
4
|
"description": "DevBridge dev runner — connects a dev server to DevBridge and runs agent sessions (Claude Code / Codex)",
|
|
5
5
|
"homepage": "https://bridge4.dev",
|
|
6
6
|
"license": "MIT",
|
|
@@ -37,16 +37,16 @@
|
|
|
37
37
|
"prepublishOnly": "tsc"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@anthropic-ai/claude-agent-sdk": "^0.3.
|
|
41
|
-
"smol-toml": "^1.7.
|
|
42
|
-
"ws": "^8.21.
|
|
43
|
-
"zod": "^3.
|
|
40
|
+
"@anthropic-ai/claude-agent-sdk": "^0.3.226",
|
|
41
|
+
"smol-toml": "^1.7.1",
|
|
42
|
+
"ws": "^8.21.3",
|
|
43
|
+
"zod": "^3.25.76"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@types/node": "^22.
|
|
46
|
+
"@types/node": "^22.20.1",
|
|
47
47
|
"@types/ws": "^8.18.1",
|
|
48
|
-
"tsx": "^4.
|
|
49
|
-
"typescript": "~5.7.
|
|
50
|
-
"vitest": "^2.
|
|
48
|
+
"tsx": "^4.23.11",
|
|
49
|
+
"typescript": "~5.7.3",
|
|
50
|
+
"vitest": "^3.2.7"
|
|
51
51
|
}
|
|
52
52
|
}
|