@agentdeck/bridge 1.0.18 → 1.0.20

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.
Files changed (60) hide show
  1. package/dist/adapters/claude-code.d.ts +4 -2
  2. package/dist/adapters/claude-code.d.ts.map +1 -1
  3. package/dist/adapters/claude-code.js +9 -10
  4. package/dist/adapters/claude-code.js.map +1 -1
  5. package/dist/adapters/codex-cli.d.ts +3 -4
  6. package/dist/adapters/codex-cli.d.ts.map +1 -1
  7. package/dist/adapters/codex-cli.js +8 -12
  8. package/dist/adapters/codex-cli.js.map +1 -1
  9. package/dist/adapters/pty-adapter.d.ts +2 -2
  10. package/dist/adapters/pty-adapter.js +2 -2
  11. package/dist/apme/adapters/codex-turn-manager.d.ts +13 -77
  12. package/dist/apme/adapters/codex-turn-manager.d.ts.map +1 -1
  13. package/dist/apme/adapters/codex-turn-manager.js +102 -403
  14. package/dist/apme/adapters/codex-turn-manager.js.map +1 -1
  15. package/dist/apme/claude-transcript-reader.d.ts +22 -0
  16. package/dist/apme/claude-transcript-reader.d.ts.map +1 -1
  17. package/dist/apme/claude-transcript-reader.js +75 -1
  18. package/dist/apme/claude-transcript-reader.js.map +1 -1
  19. package/dist/bridge-core.d.ts.map +1 -1
  20. package/dist/bridge-core.js +6 -1
  21. package/dist/bridge-core.js.map +1 -1
  22. package/dist/check-deps.d.ts.map +1 -1
  23. package/dist/check-deps.js +3 -1
  24. package/dist/check-deps.js.map +1 -1
  25. package/dist/claude-turn-watchdog.d.ts +70 -0
  26. package/dist/claude-turn-watchdog.d.ts.map +1 -0
  27. package/dist/claude-turn-watchdog.js +147 -0
  28. package/dist/claude-turn-watchdog.js.map +1 -0
  29. package/dist/cli.d.ts.map +1 -1
  30. package/dist/cli.js +20 -3
  31. package/dist/cli.js.map +1 -1
  32. package/dist/codex-hook-silence.d.ts +52 -0
  33. package/dist/codex-hook-silence.d.ts.map +1 -0
  34. package/dist/codex-hook-silence.js +80 -0
  35. package/dist/codex-hook-silence.js.map +1 -0
  36. package/dist/codex-rate-limits.d.ts +1 -1
  37. package/dist/codex-rate-limits.d.ts.map +1 -1
  38. package/dist/codex-rate-limits.js +27 -17
  39. package/dist/codex-rate-limits.js.map +1 -1
  40. package/dist/daemon.js +1 -1
  41. package/dist/index.d.ts +3 -0
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +86 -192
  44. package/dist/index.js.map +1 -1
  45. package/dist/state-machine.d.ts +43 -1
  46. package/dist/state-machine.d.ts.map +1 -1
  47. package/dist/state-machine.js +146 -12
  48. package/dist/state-machine.js.map +1 -1
  49. package/dist/types.d.ts +11 -1
  50. package/dist/types.d.ts.map +1 -1
  51. package/dist/types.js.map +1 -1
  52. package/dist/version-check.d.ts +8 -0
  53. package/dist/version-check.d.ts.map +1 -1
  54. package/dist/version-check.js +27 -0
  55. package/dist/version-check.js.map +1 -1
  56. package/package.json +4 -3
  57. package/dist/apme/adapters/claude-pty.d.ts +0 -28
  58. package/dist/apme/adapters/claude-pty.d.ts.map +0 -1
  59. package/dist/apme/adapters/claude-pty.js +0 -88
  60. package/dist/apme/adapters/claude-pty.js.map +0 -1
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Claude turn watchdog — closes a managed turn whose Stop hook was dropped.
3
+ *
4
+ * The Stop hook is the sole authority that closes a Claude turn (state → IDLE,
5
+ * timeline chat_response/chat_end, APME turn response), but its delivery is
6
+ * not guaranteed: the hook curl is fire-and-forget with a tight budget, and
7
+ * historically it has been observed to drop at a meaningful rate. Since the
8
+ * PTY spinner/ring-buffer fallbacks were removed (1.0.19), a dropped Stop left
9
+ * the session stuck PROCESSING for STUCK_TIMEOUT_MS and the timeline/APME turn
10
+ * open until the next prompt.
11
+ *
12
+ * Doctrine: recovery reads the durable log, not the screen. While a turn is
13
+ * open and the hook channel has been quiet, the watchdog probes the
14
+ * transcript JSONL tail (the same authority the Stop branch itself reads).
15
+ * A tail whose last message-bearing record is `assistant` + `end_turn`,
16
+ * stamped after this turn opened, proves the turn finished — the watchdog
17
+ * then injects a synthetic Stop through the normal adapter event pipe so
18
+ * state machine, timeline, and APME all close through their existing paths.
19
+ *
20
+ * False-positive guards:
21
+ * - `stop_reason: "tool_use"` (permission prompt / AskUserQuestion open,
22
+ * tools running) never matches, so a genuine wait is never force-closed.
23
+ * - The end_turn record must be newer than this turn's open time, so the
24
+ * previous turn's end_turn cannot close a freshly opened turn.
25
+ * - A transcript mtime older than the last probe skips the read entirely,
26
+ * so an idle prompt does not re-read 512 KB every poll.
27
+ * - If a real Stop (or SessionEnd) arrives first, the watchdog disarms; a
28
+ * synthetic Stop after a real one is deduped downstream
29
+ * (ccPendingCompletion / transition-table guards).
30
+ */
31
+ import { statSync } from 'fs';
32
+ import { readTurnEndProbe } from './apme/claude-transcript-reader.js';
33
+ import { debug } from './logger.js';
34
+ /** Hook-channel silence required before the transcript is consulted. */
35
+ export const WATCHDOG_QUIET_MS = 10_000;
36
+ /** Poll cadence while a turn is open. */
37
+ export const WATCHDOG_POLL_MS = 5_000;
38
+ /** Clock slack when comparing a record timestamp to the turn-open time. */
39
+ const TURN_OPEN_SLACK_MS = 2_000;
40
+ export class ClaudeTurnWatchdog {
41
+ onMissedStop;
42
+ quietMs;
43
+ pollMs;
44
+ now;
45
+ probe;
46
+ mtimeMs;
47
+ timer = null;
48
+ turnOpenedAt = null;
49
+ lastHookAt = 0;
50
+ transcriptPath = '';
51
+ lastProbedMtimeMs = -1;
52
+ stopped = false;
53
+ constructor(opts) {
54
+ this.onMissedStop = opts.onMissedStop;
55
+ this.quietMs = opts.quietMs ?? WATCHDOG_QUIET_MS;
56
+ this.pollMs = opts.pollMs ?? WATCHDOG_POLL_MS;
57
+ this.now = opts.now ?? Date.now;
58
+ this.probe = opts.probe ?? readTurnEndProbe;
59
+ this.mtimeMs = opts.mtimeMs ?? defaultMtimeMs;
60
+ }
61
+ /** Feed every hook-sourced adapter event through here (synthetic ones too —
62
+ * the synthetic Stop closes the turn like a real one). */
63
+ noteHookEvent(eventName, data) {
64
+ if (this.stopped)
65
+ return;
66
+ this.lastHookAt = this.now();
67
+ const tp = data?.transcript_path;
68
+ if (typeof tp === 'string' && tp)
69
+ this.transcriptPath = tp;
70
+ switch (eventName) {
71
+ case 'UserPromptSubmit':
72
+ this.turnOpenedAt = this.now();
73
+ this.lastProbedMtimeMs = -1;
74
+ this.arm();
75
+ break;
76
+ case 'Stop':
77
+ this.turnOpenedAt = null;
78
+ this.disarm();
79
+ break;
80
+ case 'SessionEnd':
81
+ // Disarm, but do NOT latch `stopped`: Claude Code fires SessionEnd on
82
+ // /clear too (paired with a SessionStart), and the bridge session
83
+ // lives on. A permanent latch here would disable missed-Stop recovery
84
+ // for the rest of the session after the first /clear. Permanent stop
85
+ // is the bridge shutdown path (core.onShutdown → stop()).
86
+ this.turnOpenedAt = null;
87
+ this.disarm();
88
+ break;
89
+ default:
90
+ break;
91
+ }
92
+ }
93
+ stop() {
94
+ this.stopped = true;
95
+ this.turnOpenedAt = null;
96
+ this.disarm();
97
+ }
98
+ arm() {
99
+ if (this.timer)
100
+ return;
101
+ this.timer = setInterval(() => this.check(), this.pollMs);
102
+ // Never hold the process open for the watchdog alone.
103
+ this.timer.unref?.();
104
+ }
105
+ disarm() {
106
+ if (this.timer) {
107
+ clearInterval(this.timer);
108
+ this.timer = null;
109
+ }
110
+ }
111
+ check() {
112
+ if (this.stopped || this.turnOpenedAt == null || !this.transcriptPath)
113
+ return;
114
+ if (this.now() - this.lastHookAt < this.quietMs)
115
+ return;
116
+ // Cheap gate: nothing appended since the last probe means the verdict
117
+ // cannot have changed (a genuinely-awaiting prompt writes nothing).
118
+ const mtime = this.mtimeMs(this.transcriptPath);
119
+ if (mtime != null && mtime === this.lastProbedMtimeMs)
120
+ return;
121
+ if (mtime != null)
122
+ this.lastProbedMtimeMs = mtime;
123
+ const probe = this.probe(this.transcriptPath);
124
+ if (!probe)
125
+ return;
126
+ if (probe.role !== 'assistant' || probe.stopReason !== 'end_turn')
127
+ return;
128
+ if (probe.timestampMs == null)
129
+ return;
130
+ if (probe.timestampMs < this.turnOpenedAt - TURN_OPEN_SLACK_MS)
131
+ return;
132
+ debug('watchdog', `missed Stop recovered from transcript (end_turn @ ${probe.timestampMs})`);
133
+ const transcriptPath = this.transcriptPath;
134
+ this.turnOpenedAt = null;
135
+ this.disarm();
136
+ this.onMissedStop({ transcript_path: transcriptPath });
137
+ }
138
+ }
139
+ function defaultMtimeMs(transcriptPath) {
140
+ try {
141
+ return statSync(transcriptPath).mtimeMs;
142
+ }
143
+ catch {
144
+ return null;
145
+ }
146
+ }
147
+ //# sourceMappingURL=claude-turn-watchdog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-turn-watchdog.js","sourceRoot":"","sources":["../src/claude-turn-watchdog.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAwB,MAAM,WAAW,CAAC;AAyP1D,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAM,CAAC;AAOtF;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAElE;AA+BD,gFAAgF;AAChF,QAAA,MAAM,cAAc,EAAE,MAAM,CAAC,aAAa,GAAG,WAAW,GAAG,UAAU,EAAE,MAAM,CAI5E,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CAsBjE;AAKD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,EAAE,CAyBV;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,OAAO,cAAc,EACtC,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAIR;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,OAAO,cAAc,EACtC,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,OAAO,EACvB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAER;AAID,QAAA,MAAM,OAAO,SAAgB,CAAC;AAs2E9B,wBAAsB,MAAM,CAAC,IAAI,GAAE,MAAM,EAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAMzE;AAED,OAAO,EAAE,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAwB,MAAM,WAAW,CAAC;AAsQ1D,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAM,CAAC;AAOtF;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAElE;AA+BD,gFAAgF;AAChF,QAAA,MAAM,cAAc,EAAE,MAAM,CAAC,aAAa,GAAG,WAAW,GAAG,UAAU,EAAE,MAAM,CAI5E,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CAsBjE;AAKD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,EAAE,CAyBV;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,OAAO,cAAc,EACtC,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAIR;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,OAAO,cAAc,EACtC,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,OAAO,EACvB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAER;AAID,QAAA,MAAM,OAAO,SAAgB,CAAC;AA02E9B,wBAAsB,MAAM,CAAC,IAAI,GAAE,MAAM,EAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAMzE;AAED,OAAO,EAAE,OAAO,EAAE,CAAC"}
package/dist/cli.js CHANGED
@@ -28,6 +28,19 @@ function warnIfDaemonHostIgnored(opts) {
28
28
  function log(msg) {
29
29
  process.stderr.write(msg + '\n');
30
30
  }
31
+ /** `daemon install` is the canonical observation setup entry point. Keep
32
+ * Claude alongside the Codex/OpenCode installers below so normal `claude`
33
+ * sessions never depend on having launched `agentdeck claude` first. */
34
+ async function refreshClaudeHooks() {
35
+ try {
36
+ const { installHooks } = await import('@agentdeck/hooks');
37
+ installHooks();
38
+ log('Claude lifecycle hooks installed/refreshed in ~/.claude/settings.json');
39
+ }
40
+ catch (err) {
41
+ log(`Claude hooks unavailable: ${String(err)}`);
42
+ }
43
+ }
31
44
  /**
32
45
  * Parse a `--weight <n>` value into an integer sort override. Rejects
33
46
  * non-integers so a typo (`--weight foo`) fails loudly instead of silently
@@ -401,7 +414,7 @@ program
401
414
  .option('--local', 'Disable all device modules (WS only)')
402
415
  .option('--no-adb', 'Disable ADB reverse setup')
403
416
  .option('--no-postit', 'Disable terminal tab title updates')
404
- .option('--no-codex-hooks', 'Skip ~/.codex/config.toml hook install')
417
+ .option('--no-codex-hooks', 'Skip ~/.codex/config.toml hook install (terminal UI only; lifecycle monitoring is unavailable)')
405
418
  .option('--remote-daemon', 'Opt in to attaching this session to a daemon on another machine (gates --daemon-host and mDNS discovery)')
406
419
  .option('--daemon-host <host>', 'Explicit remote daemon endpoint (host or host:port); requires --remote-daemon')
407
420
  .option('--daemon-token <token>', 'Pairing token of the remote hub (~/.agentdeck/auth-token there); or set AGENTDECK_DAEMON_TOKEN')
@@ -427,11 +440,11 @@ program
427
440
  }
428
441
  catch (err) {
429
442
  log(`Codex hooks unavailable: ${String(err)}`);
430
- // PTY parser fallback still works without lifecycle hooks.
443
+ log('Codex lifecycle monitoring is unavailable; the managed terminal still works.');
431
444
  }
432
445
  }
433
446
  else {
434
- log('Codex hooks skipped: --no-codex-hooks');
447
+ log('Codex hooks skipped: --no-codex-hooks (terminal UI only; no lifecycle timeline)');
435
448
  }
436
449
  const { startSession } = await import('./index.js');
437
450
  await startSession({
@@ -444,6 +457,7 @@ program
444
457
  daemonHost: opts.daemonHost,
445
458
  daemonToken: opts.daemonToken,
446
459
  weight: opts.weight,
460
+ codexHooksExpected: opts.codexHooks !== false,
447
461
  modules: opts.local ? { mdns: false, adb: false, serial: false, pixoo: false, timebox: false } : {
448
462
  mdns: false, // daemon-only
449
463
  adb: opts.adb !== false ? 'auto' : false,
@@ -805,6 +819,7 @@ daemon
805
819
  catch {
806
820
  log('Task registered; immediate start failed — it will start on next logon.');
807
821
  }
822
+ await refreshClaudeHooks();
808
823
  // Install Codex lifecycle hooks for parity with the macOS install path.
809
824
  try {
810
825
  const { installCodexHooksIfNeeded } = await import('@agentdeck/hooks');
@@ -863,6 +878,7 @@ daemon
863
878
  process.exit(1);
864
879
  }
865
880
  }
881
+ await refreshClaudeHooks();
866
882
  // Install Codex + OpenCode hooks for parity with the macOS/Windows paths.
867
883
  try {
868
884
  const { installCodexHooksIfNeeded } = await import('@agentdeck/hooks');
@@ -903,6 +919,7 @@ daemon
903
919
  catch { }
904
920
  execSync(`launchctl load "${PLIST_PATH}"`);
905
921
  log('LaunchAgent loaded. Daemon will auto-start on login.');
922
+ await refreshClaudeHooks();
906
923
  // Install Codex lifecycle hooks parallel to the LaunchAgent install
907
924
  // so the daemon hub gets codex_* events as soon as Codex CLI runs.
908
925
  try {