@staix/agent-hub 0.7.3 → 0.7.4

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/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.7.4
6
+
7
+ - A Claude session that never persisted a transcript (zero turns) no longer wedges an upgrade at restore: when the original transcript is absent, the coordinator accepts the fresh session the operator attached, because nothing was preserved and nothing is lost. Sessions with a transcript keep the strict identity check; Codex stays strict in all cases (#21).
8
+
5
9
  ## 0.7.3
6
10
 
7
11
  - A peer that detaches mid-upgrade no longer wedges the recovery: readiness ignores a now-offline peer's stale identity (a reattach with a different thread still blocks), an already-exited terminal is closed as a no-op instead of being waited on, and resume can drive the operation to release once the peer returns (#21).
package/README.md CHANGED
@@ -4,7 +4,7 @@ Native multi-agent hub for one developer's machine: Claude Code, Codex, Kimi Cod
4
4
  hub-owned local-LLM worker collaborate as peers in independent project directories, with
5
5
  task-aware model routing (Switchyard) in front of a self-hosted gateway (OmniRoute).
6
6
 
7
- Status: 0.7.3, control protocol 10. Durable delivery records distinguish queued
7
+ Status: 0.7.4, control protocol 10. Durable delivery records distinguish queued
8
8
  work from uncertain execution. The [smoke checklist](docs/smoke.md) records
9
9
  verified paths and remaining prerequisites.
10
10
 
@@ -28,7 +28,7 @@ cd <your project> && ahub init && ahub up && ahub tail
28
28
  Or install the same version from GitHub:
29
29
 
30
30
  ```bash
31
- bun add -g github:STAIxBWLB/agent-hub#v0.7.3 && ahub setup
31
+ bun add -g github:STAIxBWLB/agent-hub#v0.7.4 && ahub setup
32
32
  ```
33
33
 
34
34
  The installed commands remain `ahub` and `agent-hub`.
@@ -1,6 +1,6 @@
1
1
  # Operations guide
2
2
 
3
- This guide describes ahub 0.7.3 and control protocol 10. Live verification
3
+ This guide describes ahub 0.7.4 and control protocol 10. Live verification
4
4
  results and remaining prerequisites are recorded separately in [the smoke ledger](smoke.md).
5
5
 
6
6
  ## Install and start
@@ -182,27 +182,27 @@ For an upgrade from 0.6.4 (protocol 9) or 0.7.0, use the patched coordinator wit
182
182
  replacing the global CLI prematurely. Run from the project directory:
183
183
 
184
184
  ```bash
185
- bunx --package @staix/agent-hub@0.7.3 ahub upgrade --to 0.7.3 --dry-run
186
- bunx --package @staix/agent-hub@0.7.3 ahub upgrade --to 0.7.3 --yes
185
+ bunx --package @staix/agent-hub@0.7.4 ahub upgrade --to 0.7.4 --dry-run
186
+ bunx --package @staix/agent-hub@0.7.4 ahub upgrade --to 0.7.4 --yes
187
187
  ```
188
188
 
189
189
  The coordinator verifies and retains the exact target package, preserves its
190
190
  own source, and promotes the global CLI only after restored projects pass
191
191
  readback. Do not use the old protocol-9 coordinator to target protocol 10.
192
192
 
193
- Once the installed CLI is 0.7.3, review the current project or all registered
193
+ Once the installed CLI is 0.7.4, review the current project or all registered
194
194
  projects first:
195
195
 
196
196
  ```bash
197
197
  ahub restart --dry-run
198
- ahub upgrade --to 0.7.3 --dry-run
198
+ ahub upgrade --to 0.7.4 --dry-run
199
199
  ```
200
200
 
201
201
  Apply only after reviewing the plan:
202
202
 
203
203
  ```bash
204
204
  ahub restart --yes
205
- ahub upgrade --to 0.7.3 --yes
205
+ ahub upgrade --to 0.7.4 --yes
206
206
  ahub recovery status <operation-id>
207
207
  ahub recovery resume <operation-id>
208
208
  ahub recovery abort <operation-id>
@@ -17,7 +17,7 @@ ahub setup # installs the Claude Code channel plu
17
17
  Or use the matching GitHub release:
18
18
 
19
19
  ```bash
20
- bun add -g github:STAIxBWLB/agent-hub#v0.7.3
20
+ bun add -g github:STAIxBWLB/agent-hub#v0.7.4
21
21
  ahub setup
22
22
  ```
23
23
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@staix/agent-hub",
3
- "version": "0.7.3",
3
+ "version": "0.7.4",
4
4
  "description": "Native multi-agent hub: Claude Code, Codex, Kimi Code, Pi and local inference as peers in one project",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-hub",
3
- "version": "0.7.3",
3
+ "version": "0.7.4",
4
4
  "description": "Channel between Claude Code and the agent-hub daemon: peer messages from Codex, Kimi and the local worker arrive as channel events; hub_send replies.",
5
5
  "author": {
6
6
  "name": "Young Joon Lee",
@@ -15727,7 +15727,7 @@ class ControlClient {
15727
15727
  // package.json
15728
15728
  var package_default = {
15729
15729
  name: "@staix/agent-hub",
15730
- version: "0.7.3",
15730
+ version: "0.7.4",
15731
15731
  description: "Native multi-agent hub: Claude Code, Codex, Kimi Code, Pi and local inference as peers in one project",
15732
15732
  license: "MIT",
15733
15733
  type: "module",
@@ -1,4 +1,5 @@
1
1
  import { cpSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync } from "node:fs";
2
+ import { homedir } from "node:os";
2
3
  import { join, resolve } from "node:path";
3
4
  import { randomUUID } from "node:crypto";
4
5
  import { ControlClient, PROTOCOL, RECOVERY_SOURCE_PROTOCOLS, readControl } from "../hub/control-client.ts";
@@ -13,6 +14,17 @@ import { refreshManager } from "../hub/manager.ts";
13
14
  export const PACKAGE_ROOT = resolve(import.meta.dir, "../..");
14
15
  const orcaExecutable = () => process.env.ORCA_CLI_COMMAND || (process.env.ORCA_DEV_REPO_ROOT ? "orca-dev" : process.platform === "linux" && !process.env.ORCA_TERMINAL_HANDLE ? "orca-ide" : "orca");
15
16
 
17
+ /**
18
+ * Claude Code persists a transcript at projects/<slug>/<sessionId>.jsonl under its config
19
+ * dir, creating the project directory only with the first persisted turn; the slug replaces
20
+ * every non-alphanumeric character of the project root with '-'.
21
+ */
22
+ function claudeTranscriptExists(binding: TerminalBinding): boolean {
23
+ const config = binding.launch.env.CLAUDE_CONFIG_DIR ?? join(homedir(), ".claude");
24
+ const slug = binding.projectRoot.replace(/[^a-zA-Z0-9]/g, "-");
25
+ return existsSync(join(config, "projects", slug, `${binding.sessionId}.jsonl`));
26
+ }
27
+
16
28
  function terminalOptions(run: RunCommand = runCommand): TerminalRecoveryOptions {
17
29
  return { orcaExecutable: orcaExecutable(), runner: async (args) => {
18
30
  const result = await run([orcaExecutable(), ...args], { timeoutMs: 610_000 });
@@ -286,10 +298,20 @@ export function makeRecoveryDriver(run: RunCommand = runCommand): RecoveryDriver
286
298
  if (progress.terminals[key] === "pending") {
287
299
  const observed = await inspectRecovery(planned.project);
288
300
  const peer = observed.peers.find((p) => p.id === original.peer);
289
- if ((original.peer === "codex" ? peer?.threadId : peer?.sessionId) !== original.sessionId) {
290
- throw new Error(`${original.peer}: terminal creation outcome is uncertain; attach the original session manually, then resume`);
301
+ const attached = original.peer === "codex" ? peer?.threadId : peer?.sessionId;
302
+ let expected = original;
303
+ if (attached !== original.sessionId) {
304
+ // #21: a Claude session that never got a first turn has no transcript on disk,
305
+ // so `claude --resume S` can never succeed and nothing it stood for is lost by
306
+ // accepting the fresh attach. A session WITH a transcript keeps the strict
307
+ // identity check. Codex stays strict too: its rollout jsonl is written when the
308
+ // thread starts, so an unrestorable thread should not exist.
309
+ if (original.peer !== "claude" || !peer || peer.state === "offline" || !attached || claudeTranscriptExists(original)) {
310
+ throw new Error(`${original.peer}: terminal creation outcome is uncertain; attach the original session manually, then resume`);
311
+ }
312
+ expected = { ...original, sessionId: attached };
291
313
  }
292
- const existing = await revalidateTerminal(planned, progress, original, false);
314
+ const existing = await revalidateTerminal(planned, progress, expected, false);
293
315
  progress.terminals[key] = existing; save(); continue;
294
316
  }
295
317
  const entrypoint = join(op.targetRoot!, "src/cli/main.js");