sortie-dogs 0.4.0 → 0.4.1

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
@@ -20,7 +20,7 @@ Requirements: Node.js 22.6 or newer, npm, and OpenCode.
20
20
 
21
21
  Guides: [日本語](docs/guide-ja.md) · [简体中文](docs/guide-zh-CN.md) · [CLI testing](docs/cli-testing.md)
22
22
 
23
- Release: [v0.4.0](https://github.com/zufall-upon/Sortie-dogs/releases/tag/v0.4.0)
23
+ Release: [v0.4.1](https://github.com/zufall-upon/Sortie-dogs/releases/tag/v0.4.1)
24
24
 
25
25
  ## Quick start
26
26
 
@@ -1355,6 +1355,47 @@ export const SortieDogsPlugin = async (input, options) => {
1355
1355
  return undefined;
1356
1356
  }
1357
1357
  }
1358
+ async function hostSessionUserTurn(sessionID) {
1359
+ const messages = input.client?.session?.messages;
1360
+ if (messages === undefined)
1361
+ return undefined;
1362
+ try {
1363
+ const response = await messages.call(input.client.session, { path: { id: sessionID } });
1364
+ const payload = isRecord(response) && "data" in response ? response.data : response;
1365
+ if (!Array.isArray(payload))
1366
+ return undefined;
1367
+ for (let index = payload.length - 1; index >= 0; index -= 1) {
1368
+ const message = payload[index];
1369
+ if ((message.info?.role ?? message.role) !== "user")
1370
+ continue;
1371
+ const agent = message.info?.agent ?? message.agent;
1372
+ if (typeof agent !== "string")
1373
+ return undefined;
1374
+ return {
1375
+ agent,
1376
+ synthetic: (message.parts ?? []).some((part) => part.synthetic === true),
1377
+ };
1378
+ }
1379
+ return undefined;
1380
+ }
1381
+ catch {
1382
+ return undefined;
1383
+ }
1384
+ }
1385
+ async function recoverCoordinatorRoot(sessionID) {
1386
+ if (isCoordinatorSession(sessionID))
1387
+ return true;
1388
+ const identity = await hostSessionIdentity(sessionID);
1389
+ if (identity === undefined || identity.parentPresent)
1390
+ return false;
1391
+ const persistedTurn = await hostSessionUserTurn(sessionID);
1392
+ if (persistedTurn?.agent !== COORDINATOR_AGENT)
1393
+ return false;
1394
+ await rememberCoordinatorRoot(sessionID);
1395
+ releaseSessionEnforcement(sessionID);
1396
+ fastLane.beginTurn(sessionID, persistedTurn?.synthetic ?? false);
1397
+ return true;
1398
+ }
1358
1399
  function consultationRetryKey(parentID, role) {
1359
1400
  return `${parentID}\u0000${role}`;
1360
1401
  }
@@ -1387,10 +1428,8 @@ export const SortieDogsPlugin = async (input, options) => {
1387
1428
  const child = await hostSessionIdentity(sessionID);
1388
1429
  if (child?.parentID === undefined)
1389
1430
  return undefined;
1390
- const parent = await hostSessionIdentity(child.parentID);
1391
- if (parent?.agent !== COORDINATOR_AGENT || parent.parentPresent)
1431
+ if (!await recoverCoordinatorRoot(child.parentID))
1392
1432
  return undefined;
1393
- await rememberCoordinatorRoot(child.parentID);
1394
1433
  rememberParent(sessionID, child.parentID);
1395
1434
  return child.parentID;
1396
1435
  }
@@ -1713,7 +1752,10 @@ export const SortieDogsPlugin = async (input, options) => {
1713
1752
  }
1714
1753
  },
1715
1754
  "tool.execute.before": async (toolInput, output) => {
1716
- if (isCoordinatorSession(toolInput.sessionID)) {
1755
+ const coordinatorCapability = toolInput.tool === "task" ||
1756
+ toolInput.tool === CONTINUATION_CAPABILITY || toolInput.tool === BACKLOG_DRAIN_CAPABILITY;
1757
+ if (isCoordinatorSession(toolInput.sessionID) ||
1758
+ (coordinatorCapability && await recoverCoordinatorRoot(toolInput.sessionID))) {
1717
1759
  if (continuation.blocksTool(toolInput.sessionID)) {
1718
1760
  throw new Error("SORTIE_ROLLOVER_PENDING: stop this turn and wait for compaction");
1719
1761
  }
@@ -27,8 +27,10 @@ export interface SessionMessagePart {
27
27
  export interface SessionMessage {
28
28
  readonly info?: {
29
29
  readonly role?: unknown;
30
+ readonly agent?: unknown;
30
31
  } | undefined;
31
32
  readonly role?: unknown;
33
+ readonly agent?: unknown;
32
34
  readonly parts?: readonly SessionMessagePart[] | undefined;
33
35
  }
34
36
  /** The subset of the OpenCode SDK client this repair depends on. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sortie-dogs",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Bounded, validated orchestration loop plugin for OpenCode",
5
5
  "keywords": [
6
6
  "opencode",