sortie-dogs 0.8.0 → 0.8.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
@@ -24,7 +24,7 @@ Requirements: Node.js 22.6 or newer, npm, and OpenCode.
24
24
 
25
25
  Guides: [日本語](docs/guide-ja.md) · [简体中文](docs/guide-zh-CN.md) · [CLI testing](docs/cli-testing.md)
26
26
 
27
- Release: [v0.8.0](https://github.com/zufall-upon/Sortie-dogs/releases/tag/v0.8.0)
27
+ Release: [v0.8.1](https://github.com/zufall-upon/Sortie-dogs/releases/tag/v0.8.1)
28
28
 
29
29
  ## Quick start
30
30
 
@@ -405,10 +405,13 @@ user-facing worker.
405
405
  After replacing the dependency with a newer release asset, run:
406
406
 
407
407
  ```sh
408
- npx sortie-dogs init .
409
- ```
410
-
411
- `init` is idempotent. It updates files owned by Sortie-dogs, migrates recognized
408
+ npx sortie-dogs init .
409
+ ```
410
+
411
+ After initialization, fully restart the OpenCode host before resuming a coordinator or opening a
412
+ fresh session. Plugin modules are process-scoped, so a new session alone cannot load the update.
413
+
414
+ `init` is idempotent. It updates files owned by Sortie-dogs, migrates recognized
412
415
  older runtime files, and records the installed version in
413
416
  `.opencode/sortie-dogs.version`. Conflicting or unrecognized files remain
414
417
  untouched and initialization stops safely. User-owned configuration—including
@@ -192,7 +192,7 @@ export interface ContinuationHooks {
192
192
  toolStarted(sessionID: string, tool: string): void;
193
193
  blocksTool(sessionID: string): boolean;
194
194
  sessionIdle(sessionID: string): Promise<void>;
195
- stopAutomaticRecovery(sessionID: string): Promise<void>;
195
+ stopAutomaticRecovery(sessionID: string, abortSession?: boolean): Promise<void>;
196
196
  recoverStalledTask(sessionID: string, callIDs: readonly string[]): Promise<"recovered" | "identity-rejected" | "capability-unavailable" | "request-rejected">;
197
197
  forgetSession(sessionID: string): void;
198
198
  }
@@ -795,7 +795,7 @@ export function createContinuationHooks(client, directory, policySource, timings
795
795
  sessions.delete(sessionID);
796
796
  stoppedSessions.delete(sessionID);
797
797
  }
798
- async function stopAutomaticRecovery(sessionID) {
798
+ async function stopAutomaticRecovery(sessionID, abortSession = true) {
799
799
  const state = sessions.get(sessionID);
800
800
  if (state !== undefined) {
801
801
  clearTimer(state.cooldownTimer);
@@ -816,7 +816,7 @@ export function createContinuationHooks(client, directory, policySource, timings
816
816
  while (stoppedSessions.size > MAX_TRACKED_SESSIONS) {
817
817
  stoppedSessions.delete(stoppedSessions.values().next().value);
818
818
  }
819
- const abort = client?.session?.abort;
819
+ const abort = abortSession ? client?.session?.abort : undefined;
820
820
  if (abort !== undefined) {
821
821
  await abort.call(client.session, {
822
822
  path: { id: sessionID },
@@ -85,7 +85,7 @@ export interface OpenCodeHooks {
85
85
  export type OpenCodePlugin = (input: OpenCodePluginInput, options?: SortieDogsPluginOptions | Record<string, unknown>) => Promise<OpenCodeHooks>;
86
86
  export type HandoffDenialReason = "configuration-unavailable" | "path-invalid" | "input-unavailable" | "schema-invalid" | "contract-invalid";
87
87
  export type FreshSessionReason = "child-lineage" | "asset-contract-skew";
88
- export type FreshSessionAction = "open-fresh-root" | "install-assets-then-open-fresh-root";
88
+ export type FreshSessionAction = "open-fresh-root" | "install-assets-then-open-fresh-root" | "restart-host-after-install";
89
89
  export type FreshSessionResult = Readonly<{
90
90
  status: "redispatched";
91
91
  reason: FreshSessionReason;
@@ -1136,7 +1136,7 @@ export const SortieDogsPlugin = async (input, options) => {
1136
1136
  project ??= await createProjectPaths(resolveProjectRoot(input));
1137
1137
  if (await currentAssetVersionStatus(project) !== "current") {
1138
1138
  await deleteFreshSession(targetSessionID);
1139
- return freshSessionFallback(reason, "install-assets-then-open-fresh-root");
1139
+ return freshSessionFallback(reason, "restart-host-after-install");
1140
1140
  }
1141
1141
  }
1142
1142
  const sent = await send.call(input.client.session, {
@@ -1169,7 +1169,7 @@ export const SortieDogsPlugin = async (input, options) => {
1169
1169
  void operation.then((result) => {
1170
1170
  entry.settled = true;
1171
1171
  if (result.status === "user-action-required" &&
1172
- result.action === "install-assets-then-open-fresh-root" &&
1172
+ (result.action === "install-assets-then-open-fresh-root" || result.action === "restart-host-after-install") &&
1173
1173
  freshSessionRedispatches.get(key) === entry) {
1174
1174
  freshSessionRedispatches.delete(key);
1175
1175
  }
@@ -1237,7 +1237,7 @@ export const SortieDogsPlugin = async (input, options) => {
1237
1237
  /**
1238
1238
  * Installed agents and this plugin implement two halves of one contract. A project that installed
1239
1239
  * a different asset version is sticky for this plugin instance. Reinstalling files cannot update an
1240
- * already-running coordinator prompt, so worker dispatch remains blocked until a fresh session loads.
1240
+ * already-loaded plugin, so worker dispatch remains blocked until the host restarts.
1241
1241
  */
1242
1242
  async function readAssetVersionMarker(path) {
1243
1243
  try {
@@ -1281,7 +1281,7 @@ export const SortieDogsPlugin = async (input, options) => {
1281
1281
  }
1282
1282
  if (status === "mismatch") {
1283
1283
  console.warn(`Sortie-dogs: installed agent assets do not match ${RUNTIME_ASSET_VERSION}. ` +
1284
- "Repair the marker, then start a fresh coordinator session.");
1284
+ "Repair the installed assets, then restart the OpenCode host.");
1285
1285
  }
1286
1286
  return status;
1287
1287
  }
@@ -4150,11 +4150,11 @@ export const SortieDogsPlugin = async (input, options) => {
4150
4150
  await ensureLoaded();
4151
4151
  const assetVersionStatus = await pinAssetVersion(toolInput.sessionID);
4152
4152
  if (assetVersionStatus === "mismatch") {
4153
- await continuation.stopAutomaticRecovery(toolInput.sessionID);
4153
+ await continuation.stopAutomaticRecovery(toolInput.sessionID, false);
4154
4154
  const liveStatus = project === undefined ? "mismatch" : await currentAssetVersionStatus(project);
4155
4155
  const result = liveStatus === "current"
4156
4156
  ? await redispatchFreshCoordinator(toolInput.sessionID, "asset-contract-skew", coordinatorPrompts.get(toolInput.sessionID), "open-fresh-root")
4157
- : freshSessionFallback("asset-contract-skew", "install-assets-then-open-fresh-root");
4157
+ : freshSessionFallback("asset-contract-skew", "restart-host-after-install");
4158
4158
  throw new FreshSessionRequiredError(result);
4159
4159
  }
4160
4160
  let prompt = typeof output.args.prompt === "string" ? output.args.prompt : "";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sortie-dogs",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "Bounded agent harness and validated orchestration loop plugin for OpenCode",
5
5
  "keywords": [
6
6
  "opencode",