@adhdev/daemon-core 1.0.2 → 1.0.3-rc.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.
@@ -63,6 +63,14 @@ export declare class SpecCliAdapter implements CliAdapter {
63
63
  * MCP config), so this routing keeps the dashboard honest until
64
64
  * hermes ships a runtime MCP override. */
65
65
  private spawnedEnv;
66
+ /** Wall clock at the moment an approval modal was last resolved (auto-approve,
67
+ * dashboard, or mesh_approve) via a successful button press. Powers
68
+ * isApprovalRecentlyResolved() — the second suppression signal the mesh event
69
+ * forwarder uses to drop a duplicate agent:waiting_approval re-emitted across
70
+ * the approval↔busy TUI flap window (AUTOAPPROVE-FLAP). Mirrors the
71
+ * cli-state-engine's lastApprovalResolvedAt for the spec-driven adapter path
72
+ * (claude-cli specs/4.0.json), which previously stubbed the method to false. */
73
+ private lastApprovalResolvedAt;
66
74
  constructor(specPath: string, workingDir: string, cliArgs: string[], extraEnv: Record<string, string>, transportFactory?: PtyTransportFactory);
67
75
  spawn(): Promise<void>;
68
76
  sendMessage(text: string): Promise<void>;
@@ -78,6 +86,11 @@ export declare class SpecCliAdapter implements CliAdapter {
78
86
  isAlive(): boolean;
79
87
  private static readonly TERMINAL_SNAPSHOT_DEFAULT_MAX_BYTES;
80
88
  private static readonly TERMINAL_SNAPSHOT_ABSOLUTE_MAX_BYTES;
89
+ /** Window during which isApprovalRecentlyResolved() reports a just-resolved
90
+ * approval. Matches CliProviderInstance.APPROVAL_LOCAL_RESOLUTION_COOLDOWN_MS
91
+ * (8000) — the same auto-approve suppression window signal1 uses — so a modal
92
+ * re-emitted within the approval↔busy flap is suppressed by signal2 too. */
93
+ private static readonly APPROVAL_RESOLVED_COOLDOWN_MS;
81
94
  /**
82
95
  * MESH-READ-TERMINAL (feature 2: RAW terminal read). Least-privilege read
83
96
  * of the CURRENT rendered viewport for mesh_read_terminal on the spec path
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "1.0.2",
3
+ "version": "1.0.3-rc.2",
4
4
  "description": "ADHDev daemon core — CDP, IDE detection, providers, command execution",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -47,8 +47,8 @@
47
47
  "author": "vilmire",
48
48
  "license": "AGPL-3.0-or-later",
49
49
  "dependencies": {
50
- "@adhdev/mesh-shared": "0.9.82-rc.373",
51
- "@adhdev/session-host-core": "*",
50
+ "@adhdev/mesh-shared": "1.0.3-rc.2",
51
+ "@adhdev/session-host-core": "1.0.3-rc.2",
52
52
  "@agentclientprotocol/sdk": "^0.16.1",
53
53
  "ajv": "^8.20.0",
54
54
  "ajv-formats": "^3.0.1",
@@ -157,6 +157,7 @@ export class GhosttyVtTerminalBackend implements TerminalViewportBackend {
157
157
 
158
158
  getCursorPosition(): { col: number; row: number } {
159
159
  if (this.disposed) return { col: 0, row: 0 };
160
+ if (typeof this.terminal.getCursorPosition !== 'function') return { col: 0, row: 0 };
160
161
  return this.terminal.getCursorPosition();
161
162
  }
162
163
 
@@ -53,6 +53,7 @@ export class TerminalScreen {
53
53
  }
54
54
 
55
55
  getCursorPosition(): { col: number; row: number } {
56
+ if (typeof this.terminal.getCursorPosition !== 'function') return { col: 0, row: 0 };
56
57
  return this.terminal.getCursorPosition();
57
58
  }
58
59
 
@@ -127,6 +127,14 @@ export class SpecCliAdapter implements CliAdapter {
127
127
  * MCP config), so this routing keeps the dashboard honest until
128
128
  * hermes ships a runtime MCP override. */
129
129
  private spawnedEnv: Record<string, string> = {};
130
+ /** Wall clock at the moment an approval modal was last resolved (auto-approve,
131
+ * dashboard, or mesh_approve) via a successful button press. Powers
132
+ * isApprovalRecentlyResolved() — the second suppression signal the mesh event
133
+ * forwarder uses to drop a duplicate agent:waiting_approval re-emitted across
134
+ * the approval↔busy TUI flap window (AUTOAPPROVE-FLAP). Mirrors the
135
+ * cli-state-engine's lastApprovalResolvedAt for the spec-driven adapter path
136
+ * (claude-cli specs/4.0.json), which previously stubbed the method to false. */
137
+ private lastApprovalResolvedAt = 0;
130
138
 
131
139
  constructor(
132
140
  specPath: string,
@@ -312,6 +320,11 @@ export class SpecCliAdapter implements CliAdapter {
312
320
  // the char count still looks safe.
313
321
  private static readonly TERMINAL_SNAPSHOT_DEFAULT_MAX_BYTES = 32 * 1024;
314
322
  private static readonly TERMINAL_SNAPSHOT_ABSOLUTE_MAX_BYTES = 64 * 1024;
323
+ /** Window during which isApprovalRecentlyResolved() reports a just-resolved
324
+ * approval. Matches CliProviderInstance.APPROVAL_LOCAL_RESOLUTION_COOLDOWN_MS
325
+ * (8000) — the same auto-approve suppression window signal1 uses — so a modal
326
+ * re-emitted within the approval↔busy flap is suppressed by signal2 too. */
327
+ private static readonly APPROVAL_RESOLVED_COOLDOWN_MS = 8000;
315
328
 
316
329
  /**
317
330
  * MESH-READ-TERMINAL (feature 2: RAW terminal read). Least-privilege read
@@ -455,7 +468,18 @@ export class SpecCliAdapter implements CliAdapter {
455
468
  // clickModalButton returns whether the FSM actually found a button for `target`
456
469
  // and dispatched its confirm keys — surfaced so mesh_approve can distinguish a
457
470
  // real press from a silent miss (the exact false-success the mis-map produced).
458
- return this.driver.clickModalButton(target);
471
+ const pressed = this.driver.clickModalButton(target);
472
+ // AUTOAPPROVE-FLAP (signal2): stamp the resolve time ONLY on a real press of an
473
+ // approval-class modal. This is the resolution path for auto-approve, dashboard,
474
+ // and mesh_approve alike, so isApprovalRecentlyResolved() then suppresses a
475
+ // duplicate agent:waiting_approval re-emitted across the approval↔busy flap.
476
+ // Gate on the authoritative FSM status (approval) — a picker/confirm press must
477
+ // NOT arm the approval cooldown. A silent miss (pressed=false) leaves the modal
478
+ // unresolved, so it must not stamp either.
479
+ if (pressed && this.latestState?.status === 'approval') {
480
+ this.lastApprovalResolvedAt = Date.now();
481
+ }
482
+ return pressed;
459
483
  }
460
484
 
461
485
  async resolveAction(data: unknown): Promise<void> {
@@ -494,7 +518,10 @@ export class SpecCliAdapter implements CliAdapter {
494
518
  this.statusCallback?.();
495
519
  }
496
520
 
497
- isApprovalRecentlyResolved(): boolean { return false; }
521
+ isApprovalRecentlyResolved(): boolean {
522
+ return !!(this.lastApprovalResolvedAt
523
+ && (Date.now() - this.lastApprovalResolvedAt) < SpecCliAdapter.APPROVAL_RESOLVED_COOLDOWN_MS);
524
+ }
498
525
  clearHistory(): void { /* no transcript buffer yet */ }
499
526
  updateRuntimeSettings(): void { /* no runtime settings in spec model yet */ }
500
527
  setServerConn(): void { /* server conn unused by SpecDriver */ }