brl-subagent 2.5.1 → 2.5.2

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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > Multi-agent orchestration for [pi](https://github.com/earendil-works/pi) — chain, parallel, and dependency-graph delegation to isolated subagents with per-step model routing, preset-driven tool scoping, thinking-level control, and background execution with live monitoring, real abort, and per-agent timeouts.
4
4
 
5
- **Version:** 2.5.1 · **Author:** Azmeen Afandi / [Beeroo Labs](https://beeroolabs.com) · **License:** MIT
5
+ **Version:** 2.5.2 · **Author:** Azmeen Afandi / [Beeroo Labs](https://beeroolabs.com) · **License:** MIT
6
6
 
7
7
  ---
8
8
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brl-subagent",
3
- "version": "2.5.1",
3
+ "version": "2.5.2",
4
4
  "description": "Subagent delegation for pi — blocking or background runs, chain/parallel/graph modes, presets and task templates, live monitor, and dispatch capability guards.",
5
5
  "keywords": [
6
6
  "pi-package"
@@ -37,10 +37,10 @@
37
37
  "typebox": "*"
38
38
  },
39
39
  "devDependencies": {
40
- "@earendil-works/pi-agent-core": "^1.2.0",
41
- "@earendil-works/pi-ai": "^1.2.0",
42
- "@earendil-works/pi-coding-agent": "^1.2.0",
43
- "@earendil-works/pi-tui": "^1.2.0",
40
+ "@earendil-works/pi-agent-core": "^1.3.0",
41
+ "@earendil-works/pi-ai": "^1.3.0",
42
+ "@earendil-works/pi-coding-agent": "^1.3.0",
43
+ "@earendil-works/pi-tui": "^1.3.0",
44
44
  "jiti": "^2.7.0",
45
45
  "typebox": "1.3.27",
46
46
  "typescript": "7.0.2",
package/src/index.ts CHANGED
@@ -3331,9 +3331,40 @@ export default function (pi: ExtensionAPI) {
3331
3331
  }
3332
3332
  };
3333
3333
 
3334
+ // #340: both pre-start gate rejections below must finalize the
3335
+ // `running` record persisted just above. Without this the session entry
3336
+ // stays non-terminal, the inflight registry row (written by
3337
+ // `persistRun(..., "foreground")`) is never cleared, and the live
3338
+ // registration is never released — a phantom interrupted run at the
3339
+ // next boot (and, on a retry, a dangling twin beside the source).
3340
+ // The fabricated result drives `finalizeRunRecord` to terminal
3341
+ // `failed`; `stopReason: "aborted"` makes `coherentFailureReason` keep
3342
+ // the D1 `aborted` category coherent. The exact gate message the caller
3343
+ // receives is recorded as `errorMessage`; the terminal
3344
+ // `state.persistRun` (no kind) clears the registry row via its
3345
+ // terminal-clear rule. Returned content/isError and the retry-source
3346
+ // retention below are unchanged.
3347
+ const SLOT_CANCEL_MESSAGE = "Subagent cancelled while waiting for concurrency slot.";
3348
+ const finalizePreStartRejection = (errorMessage: string): void => {
3349
+ const rejection: SubagentResult = {
3350
+ messages: [],
3351
+ usage: { ...EMPTY_USAGE },
3352
+ exitCode: 1,
3353
+ stderr: "",
3354
+ stopReason: "aborted",
3355
+ errorMessage,
3356
+ errorCategory: "aborted",
3357
+ };
3358
+ finalizeRunRecord(run, rejection, "", new Date(run.startedAt).getTime());
3359
+ run.originalParams = { ...run.originalParams, errorCategory: rejection.errorCategory };
3360
+ state.persistRun(pi, run);
3361
+ state.finalizeLiveSubagent(run.id);
3362
+ };
3363
+
3334
3364
  // R1: Circuit breaker check — reject if circuit is open
3335
3365
  const circuitCheck = state.checkCircuit();
3336
3366
  if (circuitCheck.isOpen) {
3367
+ finalizePreStartRejection(circuitCheck.message!);
3337
3368
  cleanupGitBranch();
3338
3369
  return {
3339
3370
  content: [{ type: "text" as const, text: circuitCheck.message! }],
@@ -3352,12 +3383,13 @@ export default function (pi: ExtensionAPI) {
3352
3383
  // Acquire concurrency slot
3353
3384
  const acquired = await acquireSlot(state, ctx, signal, singlePriority);
3354
3385
  if (!acquired) {
3386
+ finalizePreStartRejection(SLOT_CANCEL_MESSAGE);
3355
3387
  cleanupGitBranch();
3356
3388
  return {
3357
3389
  content: [
3358
3390
  {
3359
3391
  type: "text" as const,
3360
- text: "Subagent cancelled while waiting for concurrency slot.",
3392
+ text: SLOT_CANCEL_MESSAGE,
3361
3393
  },
3362
3394
  ],
3363
3395
  details: undefined,
@@ -3371,11 +3403,10 @@ export default function (pi: ExtensionAPI) {
3371
3403
  // every pre-spawn gate and is about to start, so the SOURCE interrupted
3372
3404
  // registry entry is superseded — clear it here so the old run is not
3373
3405
  // re-offered at every subsequent boot. A failed pre-start (circuit open,
3374
- // slot cancelled) returns ABOVE this point and leaves the source intact
3375
- // and retryable — but note it is NOT "one row only": the pre-existing
3376
- // pre-start path (`persistRun`, which precedes the circuit/slot gates)
3377
- // still leaves a dangling `running` NEW row behind until the backlogged
3378
- // dangling-row fix. `retrySourceRun` is set only on a `retryRunId` call.
3406
+ // slot cancelled) returns ABOVE this point: the source is left intact
3407
+ // and retryable, while the NEW twin has already been finalized terminal
3408
+ // by the gate (#340) — nothing dangles. `retrySourceRun` is set only on
3409
+ // a `retryRunId` call.
3379
3410
  if (retrySourceRun) clearInflightRun(retrySourceRun.id);
3380
3411
 
3381
3412
  // F7 (issue #65): import BEFORE the try — the crash-path catch calls