@adhdev/daemon-core 1.0.18-rc.2 → 1.0.18-rc.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 (82) hide show
  1. package/dist/cli-adapters/cli-state-engine.d.ts +77 -0
  2. package/dist/cli-adapters/provider-cli-shared.d.ts +33 -0
  3. package/dist/cli-adapters/pty-transport.d.ts +2 -1
  4. package/dist/commands/cli-manager.d.ts +9 -0
  5. package/dist/commands/process-lifecycle.d.ts +43 -0
  6. package/dist/commands/upgrade-helper.d.ts +1 -0
  7. package/dist/commands/windows-atomic-upgrade.d.ts +17 -1
  8. package/dist/config/mesh-json-config.d.ts +62 -0
  9. package/dist/index.d.ts +4 -2
  10. package/dist/index.js +6674 -4237
  11. package/dist/index.js.map +1 -1
  12. package/dist/index.mjs +6361 -3927
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/mesh/coordinator-prompt.d.ts +76 -0
  15. package/dist/mesh/mesh-active-work.d.ts +1 -1
  16. package/dist/mesh/mesh-disk-retention.d.ts +105 -0
  17. package/dist/mesh/mesh-ledger.d.ts +28 -1
  18. package/dist/mesh/mesh-node-identity.d.ts +23 -0
  19. package/dist/mesh/mesh-refine-gates.d.ts +89 -0
  20. package/dist/mesh/mesh-remote-event-pull.d.ts +3 -0
  21. package/dist/mesh/mesh-runtime-store.d.ts +11 -0
  22. package/dist/mesh/mesh-work-queue.d.ts +24 -1
  23. package/dist/providers/auto-approve-modes.d.ts +14 -0
  24. package/dist/providers/chat-message-normalization.d.ts +22 -0
  25. package/dist/providers/cli-provider-instance-types.d.ts +4 -0
  26. package/dist/providers/cli-provider-instance.d.ts +78 -0
  27. package/dist/providers/contracts.d.ts +17 -0
  28. package/dist/providers/provider-schema.d.ts +1 -0
  29. package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +14 -0
  30. package/dist/providers/types/interactive-prompt.d.ts +18 -0
  31. package/dist/repo-mesh-types.d.ts +38 -6
  32. package/dist/shared-types.d.ts +4 -2
  33. package/package.json +3 -3
  34. package/src/boot/daemon-lifecycle.ts +10 -0
  35. package/src/cli-adapters/cli-state-engine.ts +220 -3
  36. package/src/cli-adapters/provider-cli-adapter.ts +41 -11
  37. package/src/cli-adapters/provider-cli-shared.ts +48 -0
  38. package/src/cli-adapters/pty-transport.d.ts +2 -1
  39. package/src/cli-adapters/pty-transport.ts +1 -1
  40. package/src/cli-adapters/session-host-transport.ts +8 -3
  41. package/src/commands/cli-manager.ts +72 -8
  42. package/src/commands/high-family/mesh-coordinator-launch.ts +17 -2
  43. package/src/commands/high-family/mesh-events.ts +13 -2
  44. package/src/commands/med-family/mesh-crud.ts +155 -0
  45. package/src/commands/med-family/mesh-queue.ts +74 -1
  46. package/src/commands/process-lifecycle.ts +248 -0
  47. package/src/commands/router-refine.ts +71 -4
  48. package/src/commands/router.ts +8 -0
  49. package/src/commands/upgrade-helper.ts +106 -82
  50. package/src/commands/windows-atomic-upgrade.ts +281 -35
  51. package/src/config/mesh-json-config.ts +111 -0
  52. package/src/index.ts +21 -1
  53. package/src/mesh/coordinator-prompt.ts +258 -11
  54. package/src/mesh/mesh-active-work.ts +11 -1
  55. package/src/mesh/mesh-completion-synthesis.ts +12 -1
  56. package/src/mesh/mesh-disk-retention.ts +370 -0
  57. package/src/mesh/mesh-event-classify.ts +19 -0
  58. package/src/mesh/mesh-event-forwarding.ts +64 -6
  59. package/src/mesh/mesh-events-utils.ts +42 -0
  60. package/src/mesh/mesh-ledger.ts +77 -0
  61. package/src/mesh/mesh-node-identity.ts +49 -0
  62. package/src/mesh/mesh-queue-assignment.ts +210 -11
  63. package/src/mesh/mesh-reconcile-loop.ts +306 -3
  64. package/src/mesh/mesh-refine-gates.ts +300 -0
  65. package/src/mesh/mesh-remote-event-pull.ts +68 -47
  66. package/src/mesh/mesh-runtime-store.ts +21 -0
  67. package/src/mesh/mesh-work-queue.ts +85 -2
  68. package/src/providers/auto-approve-modes.ts +103 -0
  69. package/src/providers/chat-message-normalization.ts +53 -0
  70. package/src/providers/cli-provider-instance-types.ts +53 -0
  71. package/src/providers/cli-provider-instance.ts +497 -15
  72. package/src/providers/contracts.ts +25 -1
  73. package/src/providers/provider-schema.ts +83 -0
  74. package/src/providers/sdk/v1/builders/cli/detect-status.ts +23 -0
  75. package/src/providers/sdk/v1/builders/cli/parse-approval.ts +20 -0
  76. package/src/providers/sdk/v1/schemas/cli/provider.schema.json +44 -0
  77. package/src/providers/types/interactive-prompt.ts +77 -0
  78. package/src/repo-mesh-types.ts +112 -12
  79. package/src/session-host/managed-host.ts +34 -0
  80. package/src/shared-types.ts +9 -1
  81. package/src/status/reporter.ts +1 -0
  82. package/src/status/snapshot.ts +2 -0
@@ -0,0 +1,103 @@
1
+ import type {
2
+ AutoApproveMode,
3
+ AutoApproveModeRisk,
4
+ AutoApproveModeStrategy,
5
+ ProviderModule,
6
+ } from './contracts.js';
7
+
8
+ const KNOWN_DANGEROUS_LAUNCH_ARGS = new Set([
9
+ '--dangerously-skip-permissions',
10
+ '--dangerously-bypass-approvals-and-sandbox',
11
+ 'bypassPermissions',
12
+ 'sandbox_mode=danger-full-access',
13
+ 'approval_policy=never',
14
+ ]);
15
+
16
+ export interface ResolvedAutoApproveMode {
17
+ active: boolean;
18
+ strategy: AutoApproveModeStrategy;
19
+ modeId: string;
20
+ }
21
+
22
+ function isKnownDangerousLaunchArg(arg: string): boolean {
23
+ const normalized = arg.trim();
24
+ if (KNOWN_DANGEROUS_LAUNCH_ARGS.has(normalized)) return true;
25
+ return normalized.startsWith('--dangerously-skip-permissions=')
26
+ || normalized.startsWith('--dangerously-bypass-approvals-and-sandbox=');
27
+ }
28
+
29
+ /** Runtime defense-in-depth for provider definitions that bypass schema validation. */
30
+ export function deriveAutoApproveModeRisk(mode: Pick<AutoApproveMode, 'risk' | 'launchArgs'>): AutoApproveModeRisk {
31
+ return Array.isArray(mode.launchArgs) && mode.launchArgs.some(isKnownDangerousLaunchArg)
32
+ ? 'dangerous'
33
+ : mode.risk;
34
+ }
35
+
36
+ function inactiveMode(modeId = ''): ResolvedAutoApproveMode {
37
+ return { active: false, strategy: 'pty-parse-default', modeId };
38
+ }
39
+
40
+ function resolveConfiguredMode(
41
+ provider: ProviderModule,
42
+ mode: AutoApproveMode,
43
+ settings: Record<string, unknown> | undefined,
44
+ ): ResolvedAutoApproveMode {
45
+ if (mode.strategy === 'post-boot-command') return inactiveMode(mode.id);
46
+ if (settings?.launchedByCoordinator === true
47
+ && settings.delegatedWorkerDangerousModeAllow !== true
48
+ && deriveAutoApproveModeRisk(mode) === 'dangerous') {
49
+ const fallback = provider.autoApproveModes?.modes.find((candidate) =>
50
+ candidate.strategy === 'pty-parse-default'
51
+ && deriveAutoApproveModeRisk(candidate) !== 'dangerous');
52
+ return fallback
53
+ ? { active: true, strategy: fallback.strategy, modeId: fallback.id }
54
+ : inactiveMode(mode.id);
55
+ }
56
+ return { active: true, strategy: mode.strategy, modeId: mode.id };
57
+ }
58
+
59
+ /**
60
+ * Resolve new mode settings before the legacy boolean. A stale/unknown explicit
61
+ * mode id fails closed instead of falling through to an enabled legacy setting.
62
+ */
63
+ export function resolveProviderAutoApproveMode(
64
+ provider: ProviderModule | null | undefined,
65
+ settings: Record<string, unknown> | undefined,
66
+ ): ResolvedAutoApproveMode {
67
+ // No provider (e.g. an instance whose module isn't set when a modal-park /
68
+ // auto-approve classification runs) ⇒ auto-approve is inactive. this.provider is
69
+ // genuinely nullable at runtime (the instance reads this.provider?.nativeHistory
70
+ // elsewhere), and the sibling helper findProviderAutoApproveMode already guards
71
+ // with provider?.autoApproveModes. Guard the entry so every caller is safe.
72
+ if (!provider) return inactiveMode();
73
+ const config = provider.autoApproveModes;
74
+ const explicitModeId = settings?.autoApproveMode;
75
+ if (typeof explicitModeId === 'string') {
76
+ const mode = config?.modes.find((candidate) => candidate.id === explicitModeId);
77
+ if (!mode) return inactiveMode(explicitModeId);
78
+ return resolveConfiguredMode(provider, mode, settings);
79
+ }
80
+
81
+ const explicitLegacy = settings?.autoApprove;
82
+ const providerLegacyDefault = provider.settings?.autoApprove?.default;
83
+ const legacyActive = typeof explicitLegacy === 'boolean'
84
+ ? explicitLegacy
85
+ : typeof providerLegacyDefault === 'boolean'
86
+ ? providerLegacyDefault
87
+ : false;
88
+ if (!legacyActive) return inactiveMode();
89
+
90
+ if (!config) {
91
+ return { active: true, strategy: 'pty-parse-default', modeId: 'legacy' };
92
+ }
93
+ const defaultMode = config.modes.find((mode) => mode.id === config.default);
94
+ if (!defaultMode) return inactiveMode(config.default);
95
+ return resolveConfiguredMode(provider, defaultMode, settings);
96
+ }
97
+
98
+ export function findProviderAutoApproveMode(
99
+ provider: ProviderModule | undefined,
100
+ modeId: string,
101
+ ): AutoApproveMode | undefined {
102
+ return provider?.autoApproveModes?.modes.find((mode) => mode.id === modeId);
103
+ }
@@ -156,6 +156,59 @@ export function selectFinalAssistantTurnEndMessage(
156
156
  return null;
157
157
  }
158
158
 
159
+ /**
160
+ * EARLY-IDLE-COMPLETION-FALSE-POSITIVE — trailing tool/terminal activity detector.
161
+ *
162
+ * True when the transcript's LAST non-empty user-facing assistant bubble is followed
163
+ * by one or more TOOL / TERMINAL activity bubbles (a tool_use/command the assistant
164
+ * fired AFTER its text) — i.e. the assistant emitted a preamble ("Let me explore…"),
165
+ * then started running Read/Grep, so the turn is still executing and its answer has
166
+ * not landed. Callers that would otherwise promote that preamble to a turn-end summary
167
+ * off a momentary (startup-grace / inter-tool) idle read use this as a veto.
168
+ *
169
+ * Deliberately NARROW so the pure-PTY completion rescue is preserved:
170
+ * - Only TOOL/TERMINAL activity trailing the assistant vetoes. A trailing THOUGHT or
171
+ * status bubble does NOT (a finished turn can end on an internal thought), matching
172
+ * selectFinalAssistantTurnEndMessage's skip set minus the "still-working" signals.
173
+ * - A genuinely FINISHED worker (final assistant last, no trailing tool activity —
174
+ * the kimi pure-PTY continuous-idle shape) returns false, so its early completion
175
+ * is untouched.
176
+ *
177
+ * Returns false when there is no final assistant bubble at all (the caller's
178
+ * selectFinalAssistantTurnEndMessage already handles that as "not a turn end").
179
+ */
180
+ export function hasTrailingToolActivityAfterFinalAssistant(
181
+ messages: ChatMessage[] | null | undefined,
182
+ ): boolean {
183
+ if (!Array.isArray(messages) || messages.length === 0) return false;
184
+ let sawTrailingToolActivity = false;
185
+ for (let i = messages.length - 1; i >= 0; i--) {
186
+ const msg = messages[i];
187
+ if (!msg) continue;
188
+ const classification = classifyChatMessageVisibility(msg);
189
+ // A trailing user-facing assistant/model bubble with real text ends the scan:
190
+ // whether we saw a tool AFTER it is the verdict.
191
+ if (classification.isUserFacing && (msg.role === 'assistant' || msg.role === 'model')) {
192
+ if (flattenContent(msg.content).trim()) return sawTrailingToolActivity;
193
+ // Empty streaming assistant bubble — keep scanning back past it, same as
194
+ // selectFinalAssistantTurnEndMessage (which returns null here); an empty tail
195
+ // isn't a turn end, so there is nothing to veto.
196
+ return false;
197
+ }
198
+ if (classification.isUserFacing) {
199
+ // A trailing user bubble (freshly dispatched task, no reply) → no assistant
200
+ // turn end below it to veto.
201
+ return false;
202
+ }
203
+ // Non-user-facing activity/internal bubble sitting AFTER the (not-yet-seen)
204
+ // assistant bubble. Only tool/terminal activity signals an in-flight turn.
205
+ if (classification.kind === 'tool' || classification.kind === 'terminal') {
206
+ sawTrailingToolActivity = true;
207
+ }
208
+ }
209
+ return false;
210
+ }
211
+
159
212
  export const BUILTIN_CHAT_MESSAGE_KINDS = ['standard', 'thought', 'tool', 'terminal', 'system'] as const;
160
213
 
161
214
  export type BuiltinChatMessageKind = typeof BUILTIN_CHAT_MESSAGE_KINDS[number];
@@ -66,6 +66,15 @@ export type CompletedFinalizationBlock = {
66
66
  // preamble summary (evidenceLevel=insufficient) into the append-only ledger before the
67
67
  // worker's next approval turn resumes. Independent of valley length.
68
68
  holdForTranscript?: boolean;
69
+ // (CANON-C EARLY-EMIT FLOOR) Set on a missing_final_assistant block whose provider has NO
70
+ // external transcript source to trail — a PTY-parsed provider (codex-cli) or one that merely
71
+ // requires a final assistant before idle. For those the CANON-C decoupled-immediate emit is a
72
+ // pure timing guess (no separate transcript will land to upgrade it), so it must observe the
73
+ // CANON_C_MISSING_ASSISTANT_MIN_ELAPSED_MS floor rather than fire at the ~13s first-poll
74
+ // waitedMs. A native-source block (claude-cli external-native, where the transcript legitimately
75
+ // trails the idle transition by a write) deliberately does NOT set this — its immediate emit is
76
+ // correct and is upgraded by the transcript reconcile.
77
+ noExternalTranscriptSource?: boolean;
69
78
  };
70
79
 
71
80
  export type CompletionFinalAssistantEvidence = {
@@ -87,6 +96,25 @@ export type ExternalTranscriptProbe = {
87
96
 
88
97
  export const COMPLETED_FINALIZATION_RETRY_MS = 1000;
89
98
  export const COMPLETED_FINALIZATION_MAX_WAIT_MS = 30_000;
99
+ // (CANON-C EARLY-EMIT FLOOR) Minimum elapsed time before the CANON-C transcript-evidence
100
+ // gate (allowTimeout blocks) may fire its decoupled-immediate completion for a block that
101
+ // has NO final-assistant evidence (missing_final_assistant, finalAssistantPresent=false).
102
+ //
103
+ // CANON-C deliberately decouples the idle NOTIFICATION from the transcript's final-assistant
104
+ // turn: for a native-source worker whose transcript write merely trails the idle transition,
105
+ // emitting immediately (weak, later upgraded) is correct. But the SAME allowTimeout path also
106
+ // carries codex/antigravity PLAIN terminal blocks whose on-screen "final" assistant never
107
+ // landed — there the immediate emit fires at whatever tiny waitedMs the first completion-gate
108
+ // poll observed (~13s live), stamping evidenceLevel=insufficient and racing the transcript
109
+ // before it can catch up or the 180s mesh-worker stall watchdog can arm. Requiring a minimum
110
+ // dwell gives the transcript a window to land (clearing the block for a GENUINE emit) and lets
111
+ // the stall watchdog own long turns, while still emitting a weak completion promptly once the
112
+ // floor is met so a genuinely-answerless turn is never wedged. A block WITH final-assistant
113
+ // evidence present is unaffected (it takes the normal emit path, not this floor). Scoped (at
114
+ // the call site) to the missing_final_assistant transcript-evidence gate on mesh workers.
115
+ // Sized so a short transcript-write lag resolves under it while staying well below the 30s
116
+ // COMPLETED_FINALIZATION_MAX_WAIT_MS cap that force-releases the weak completion regardless.
117
+ export const CANON_C_MISSING_ASSISTANT_MIN_ELAPSED_MS = 20_000;
90
118
  // (FALSEIDLE-BGCHILD-a) Minimum generating→idle settle window for native-history mesh worker
91
119
  // sessions. Native-history providers (e.g. claude-cli) normally flush the completion with
92
120
  // flushDelay=0 — the transcript is authoritative, so there is no reason to wait. But a worker
@@ -120,6 +148,31 @@ export const NATIVE_HISTORY_MESH_IDLE_SETTLE_MS = 4000;
120
148
  // met. Scoped (at the call site) to autonomous mesh sessions, so interactive sessions are
121
149
  // untouched.
122
150
  export const PTY_PARSED_FINAL_ASSISTANT_QUIET_DWELL_MS = 1200;
151
+ // (ANTIGRAVITY-30S-CAP-PREMATURE) Minimum PTY quiet dwell required before the
152
+ // COMPLETED_FINALIZATION_MAX_WAIT_MS (30s) cap may RELEASE an antigravity `holdForTranscript`
153
+ // block into the forced weak completion. Antigravity is a native-source provider: its
154
+ // idle/generating verdict is PTY-screen-derived, but its assistant answer lands in
155
+ // native-history and can legitimately lag past 30s on a long turn (tool phase + slow reply).
156
+ // The 30s cap releases on ELAPSED TIME, not proof-of-idle — so on a long turn it fired a
157
+ // premature completed/idle to the coordinator while the PTY was still generating (live-repro:
158
+ // a routed RCA task emitted "completed" in 10s with no result). Require instead that the PTY
159
+ // has been quiet (no raw output) for at least this long AND the adapter reports no pending
160
+ // response before the cap may force-emit. A genuinely quiescent tool-only turn (no assistant
161
+ // bubble) has a stable screen well past this bound and still finalizes; a turn whose PTY is
162
+ // still producing output keeps holding past 30s (up to ANTIGRAVITY_HOLD_HARD_CAP_MS). Scoped
163
+ // (at the call site) to antigravity-cli holdForTranscript blocks, so claude-cli/codex-cli
164
+ // completion timing is untouched.
165
+ export const ANTIGRAVITY_HOLD_QUIET_DWELL_MS = 3000;
166
+ // (ANTIGRAVITY-30S-CAP-PREMATURE) Absolute upper bound on how long an antigravity
167
+ // `holdForTranscript` block may be held once the 30s cap is reached but the PTY is still
168
+ // active. The quiet-dwell gate above keeps holding while the PTY keeps emitting output, so a
169
+ // truly runaway turn (PTY never falls quiet) must still eventually release rather than wedge
170
+ // the session in generating forever — strictly worse than the original premature-emit bug.
171
+ // Once a pending completion has been held this long we force-emit regardless of PTY activity.
172
+ // Sized generously (5 min) so realistic long antigravity turns (multi-tool + slow reply)
173
+ // finish and let the transcript land / the PTY fall quiet naturally, while still guaranteeing
174
+ // eventual release. Mirrors BACKGROUND_TASK_HOLD_MAX_MS's escape-hatch rationale.
175
+ export const ANTIGRAVITY_HOLD_HARD_CAP_MS = 5 * 60_000;
123
176
  // (FALSE-IDLE-BACKGROUND-CMD) Hard cap on how long a pending completion may be HELD
124
177
  // solely because the claude-cli transcript still shows an unresolved run_in_background
125
178
  // bash job (backgroundTaskActive). The hold is the correct behaviour while the job is