@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.
- package/dist/cli-adapters/cli-state-engine.d.ts +77 -0
- package/dist/cli-adapters/provider-cli-shared.d.ts +33 -0
- package/dist/cli-adapters/pty-transport.d.ts +2 -1
- package/dist/commands/cli-manager.d.ts +9 -0
- package/dist/commands/process-lifecycle.d.ts +43 -0
- package/dist/commands/upgrade-helper.d.ts +1 -0
- package/dist/commands/windows-atomic-upgrade.d.ts +17 -1
- package/dist/config/mesh-json-config.d.ts +62 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +6674 -4237
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6361 -3927
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/coordinator-prompt.d.ts +76 -0
- package/dist/mesh/mesh-active-work.d.ts +1 -1
- package/dist/mesh/mesh-disk-retention.d.ts +105 -0
- package/dist/mesh/mesh-ledger.d.ts +28 -1
- package/dist/mesh/mesh-node-identity.d.ts +23 -0
- package/dist/mesh/mesh-refine-gates.d.ts +89 -0
- package/dist/mesh/mesh-remote-event-pull.d.ts +3 -0
- package/dist/mesh/mesh-runtime-store.d.ts +11 -0
- package/dist/mesh/mesh-work-queue.d.ts +24 -1
- package/dist/providers/auto-approve-modes.d.ts +14 -0
- package/dist/providers/chat-message-normalization.d.ts +22 -0
- package/dist/providers/cli-provider-instance-types.d.ts +4 -0
- package/dist/providers/cli-provider-instance.d.ts +78 -0
- package/dist/providers/contracts.d.ts +17 -0
- package/dist/providers/provider-schema.d.ts +1 -0
- package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +14 -0
- package/dist/providers/types/interactive-prompt.d.ts +18 -0
- package/dist/repo-mesh-types.d.ts +38 -6
- package/dist/shared-types.d.ts +4 -2
- package/package.json +3 -3
- package/src/boot/daemon-lifecycle.ts +10 -0
- package/src/cli-adapters/cli-state-engine.ts +220 -3
- package/src/cli-adapters/provider-cli-adapter.ts +41 -11
- package/src/cli-adapters/provider-cli-shared.ts +48 -0
- package/src/cli-adapters/pty-transport.d.ts +2 -1
- package/src/cli-adapters/pty-transport.ts +1 -1
- package/src/cli-adapters/session-host-transport.ts +8 -3
- package/src/commands/cli-manager.ts +72 -8
- package/src/commands/high-family/mesh-coordinator-launch.ts +17 -2
- package/src/commands/high-family/mesh-events.ts +13 -2
- package/src/commands/med-family/mesh-crud.ts +155 -0
- package/src/commands/med-family/mesh-queue.ts +74 -1
- package/src/commands/process-lifecycle.ts +248 -0
- package/src/commands/router-refine.ts +71 -4
- package/src/commands/router.ts +8 -0
- package/src/commands/upgrade-helper.ts +106 -82
- package/src/commands/windows-atomic-upgrade.ts +281 -35
- package/src/config/mesh-json-config.ts +111 -0
- package/src/index.ts +21 -1
- package/src/mesh/coordinator-prompt.ts +258 -11
- package/src/mesh/mesh-active-work.ts +11 -1
- package/src/mesh/mesh-completion-synthesis.ts +12 -1
- package/src/mesh/mesh-disk-retention.ts +370 -0
- package/src/mesh/mesh-event-classify.ts +19 -0
- package/src/mesh/mesh-event-forwarding.ts +64 -6
- package/src/mesh/mesh-events-utils.ts +42 -0
- package/src/mesh/mesh-ledger.ts +77 -0
- package/src/mesh/mesh-node-identity.ts +49 -0
- package/src/mesh/mesh-queue-assignment.ts +210 -11
- package/src/mesh/mesh-reconcile-loop.ts +306 -3
- package/src/mesh/mesh-refine-gates.ts +300 -0
- package/src/mesh/mesh-remote-event-pull.ts +68 -47
- package/src/mesh/mesh-runtime-store.ts +21 -0
- package/src/mesh/mesh-work-queue.ts +85 -2
- package/src/providers/auto-approve-modes.ts +103 -0
- package/src/providers/chat-message-normalization.ts +53 -0
- package/src/providers/cli-provider-instance-types.ts +53 -0
- package/src/providers/cli-provider-instance.ts +497 -15
- package/src/providers/contracts.ts +25 -1
- package/src/providers/provider-schema.ts +83 -0
- package/src/providers/sdk/v1/builders/cli/detect-status.ts +23 -0
- package/src/providers/sdk/v1/builders/cli/parse-approval.ts +20 -0
- package/src/providers/sdk/v1/schemas/cli/provider.schema.json +44 -0
- package/src/providers/types/interactive-prompt.ts +77 -0
- package/src/repo-mesh-types.ts +112 -12
- package/src/session-host/managed-host.ts +34 -0
- package/src/shared-types.ts +9 -1
- package/src/status/reporter.ts +1 -0
- 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
|