@adhdev/mesh-shared 1.0.82-rc.11 → 1.0.82-rc.13
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/assistant-protocol.d.ts +6 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +115 -11
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +109 -11
- package/dist/index.mjs.map +1 -1
- package/dist/mesh-vocabulary.d.ts +8 -1
- package/dist/node-facts.d.ts +26 -0
- package/dist/provider-approval.d.ts +36 -0
- package/dist/provider-question.d.ts +19 -0
- package/dist/turn-evidence.d.ts +20 -8
- package/dist/types.d.ts +1 -0
- package/package.json +1 -1
- package/src/assistant-protocol.ts +13 -1
- package/src/index.ts +2 -0
- package/src/mesh-vocabulary.ts +8 -0
- package/src/node-facts.ts +21 -0
- package/src/provider-approval.ts +59 -0
- package/src/provider-question.ts +31 -0
- package/src/quota-freshness.ts +7 -2
- package/src/turn-evidence.ts +20 -17
- package/src/types.ts +1 -0
|
@@ -46,10 +46,17 @@ export type MeshSessionCleanupMode = typeof MESH_SESSION_CLEANUP_MODES[number];
|
|
|
46
46
|
/** Outcome a delegated worker may report through `report_completion`. */
|
|
47
47
|
export declare const WORKER_REPORT_OUTCOMES: readonly ["completed", "blocked", "failed"];
|
|
48
48
|
export type WorkerReportOutcome = typeof WORKER_REPORT_OUTCOMES[number];
|
|
49
|
+
/**
|
|
50
|
+
* Hard cap on a `report_completion` summary (characters, after trim). Over-limit
|
|
51
|
+
* summaries are REJECTED, never truncated. Declared once so the daemon validator
|
|
52
|
+
* and the mcp-server's pre-send check (which keeps an over-limit report out of the
|
|
53
|
+
* durable outbox) cannot drift apart.
|
|
54
|
+
*/
|
|
55
|
+
export declare const WORKER_REPORT_SUMMARY_MAX_CHARS = 8000;
|
|
49
56
|
/** Final branch state a worker reports (see coordinator convergence rules). */
|
|
50
57
|
export declare const WORKER_BRANCH_STATES: readonly ["merged_to_main", "pushed_feature_branch_needs_merge", "blocked_review", "cleanup_candidate", "not_mergeable"];
|
|
51
58
|
export type WorkerBranchState = typeof WORKER_BRANCH_STATES[number];
|
|
52
|
-
export declare const isMeshTaskStatus: (value: unknown) => value is "
|
|
59
|
+
export declare const isMeshTaskStatus: (value: unknown) => value is "pending" | "failed" | "assigned" | "completed" | "cancelled";
|
|
53
60
|
export declare const isMeshTerminalTaskStatus: (value: unknown) => value is "failed" | "completed" | "cancelled";
|
|
54
61
|
export declare const isMeshTaskMode: (value: unknown) => value is "code_change" | "validation" | "live_debug_readonly" | "launch_app" | "convergence";
|
|
55
62
|
export declare const isMeshTaskPriority: (value: unknown) => value is "low" | "high" | "normal";
|
package/dist/node-facts.d.ts
CHANGED
|
@@ -123,6 +123,25 @@ export interface MeshNodeFactsProviderQuota {
|
|
|
123
123
|
* predating the field.
|
|
124
124
|
*/
|
|
125
125
|
fetchedAt?: number;
|
|
126
|
+
/**
|
|
127
|
+
* Provenance of the RETAINED reading when `lastGoodWindows` is true —
|
|
128
|
+
* the source/plan/measurement time of the snapshot that produced the
|
|
129
|
+
* carried numbers, as opposed to the top-level `source`/`planType`,
|
|
130
|
+
* which describe the fresh failed attempt. See daemon-core
|
|
131
|
+
* `QuotaMetadata.lastGood`.
|
|
132
|
+
*/
|
|
133
|
+
lastGood?: {
|
|
134
|
+
measuredAt: number;
|
|
135
|
+
source?: string;
|
|
136
|
+
planType?: string | null;
|
|
137
|
+
collectorScope?: string;
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* `'background-collector'` when the snapshot came from a daemon-spawned
|
|
141
|
+
* probe rather than an executing CLI session; a failure with this scope
|
|
142
|
+
* is not evidence about a running session's sign-in.
|
|
143
|
+
*/
|
|
144
|
+
collectorScope?: string;
|
|
126
145
|
[extra: string]: unknown;
|
|
127
146
|
};
|
|
128
147
|
[extra: string]: unknown;
|
|
@@ -146,6 +165,13 @@ export interface MeshNodeFactsProviderEnablement {
|
|
|
146
165
|
}
|
|
147
166
|
export interface MeshNodeFacts {
|
|
148
167
|
schemaVersion: number;
|
|
168
|
+
/** Cached CLI detection only; no paths or account data. */
|
|
169
|
+
providerInventory?: {
|
|
170
|
+
observedAt: number;
|
|
171
|
+
providers: Record<string, {
|
|
172
|
+
installed: boolean;
|
|
173
|
+
}>;
|
|
174
|
+
};
|
|
149
175
|
reportedAt: number;
|
|
150
176
|
daemonBuild?: MeshNodeFactsDaemonBuild;
|
|
151
177
|
providerVersions?: Record<string, string>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** Provider permissions are runtime decisions, never owner write ratification. */
|
|
2
|
+
export interface ProviderApproval {
|
|
3
|
+
source: 'provider_modal' | 'legacy_provider' | 'status_only' | 'ledger_approval';
|
|
4
|
+
/** Exact Inbox actions or the existing session handler; never inferred consent. */
|
|
5
|
+
compatibility?: 'exact' | 'session_only' | 'unknown';
|
|
6
|
+
type: 'tool_permission' | 'provider_setup' | 'unknown';
|
|
7
|
+
evidence: 'live' | 'cached' | 'unavailable';
|
|
8
|
+
lifecycle: 'pending' | 'resolved';
|
|
9
|
+
modalKey: string | null;
|
|
10
|
+
createdAt: number | null;
|
|
11
|
+
resolvedAt: number | null;
|
|
12
|
+
description: string;
|
|
13
|
+
runtimeDirectory?: string;
|
|
14
|
+
displayedDirectory?: string | null;
|
|
15
|
+
buttons: string[];
|
|
16
|
+
actionable: boolean;
|
|
17
|
+
providerType?: string;
|
|
18
|
+
sessionId?: string;
|
|
19
|
+
nodeId?: string | null;
|
|
20
|
+
meshId?: string | null;
|
|
21
|
+
taskId?: string | null;
|
|
22
|
+
attemptId?: string | null;
|
|
23
|
+
generation?: number | null;
|
|
24
|
+
}
|
|
25
|
+
/** Exact resource identity required by the approvals-only action path. */
|
|
26
|
+
export interface ProviderApprovalTarget {
|
|
27
|
+
modalKey: string;
|
|
28
|
+
attemptId: string | null;
|
|
29
|
+
generation: number | null;
|
|
30
|
+
}
|
|
31
|
+
/** Confirmed authority for the new Inbox path. Legacy handlers retain their own checks. */
|
|
32
|
+
export declare function isActionableProviderApproval(approval: ProviderApproval | null | undefined): boolean;
|
|
33
|
+
/** An explicit null suppresses the resource; only missing metadata uses compatibility. */
|
|
34
|
+
export declare function readProviderDecision(approval: ProviderApproval | null | undefined, waiting: boolean, hasModal?: boolean): ProviderApproval | null;
|
|
35
|
+
/** Host metadata is durable: identity and clocks only, never modal text or directories. */
|
|
36
|
+
export declare function providerApprovalSnapshot(approval: ProviderApproval | null | undefined): ProviderApproval | null;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Ephemeral provenance supplied by the owning daemon, never inferred from prompt text. */
|
|
2
|
+
export interface ProviderQuestionBinding {
|
|
3
|
+
transport: 'codex_rpc' | 'codex_async';
|
|
4
|
+
sessionId: string;
|
|
5
|
+
generation: string;
|
|
6
|
+
threadId: string;
|
|
7
|
+
turnId: string;
|
|
8
|
+
itemId: string;
|
|
9
|
+
requestId?: string | number;
|
|
10
|
+
}
|
|
11
|
+
export type ProviderQuestionLifecycle = 'pending' | 'submitted' | 'resolved' | 'completed' | 'cancelled' | 'expired' | 'unknown';
|
|
12
|
+
export interface ProviderQuestionEpisode {
|
|
13
|
+
blocking?: boolean;
|
|
14
|
+
binding?: ProviderQuestionBinding;
|
|
15
|
+
lifecycle?: ProviderQuestionLifecycle;
|
|
16
|
+
/** Async dismiss is product-local; it is not a native tool cancellation. */
|
|
17
|
+
support?: 'request_bound' | 'product_local' | 'uncertain';
|
|
18
|
+
}
|
|
19
|
+
export declare function isProviderQuestionBinding(value: unknown): value is ProviderQuestionBinding;
|
package/dist/turn-evidence.d.ts
CHANGED
|
@@ -58,20 +58,20 @@ export declare const SESSION_REBOUND_REASONS: readonly ["restart", "live_holder"
|
|
|
58
58
|
export type SessionReboundReason = typeof SESSION_REBOUND_REASONS[number];
|
|
59
59
|
export declare const SUSPENSION_MODALS: readonly ["approval", "choice"];
|
|
60
60
|
export type SuspensionModal = typeof SUSPENSION_MODALS[number];
|
|
61
|
-
export declare const SUSPENSION_RESOLUTIONS: readonly ["approved", "rejected", "answered"];
|
|
61
|
+
export declare const SUSPENSION_RESOLUTIONS: readonly ["approved", "rejected", "answered", "dismissed"];
|
|
62
62
|
export type SuspensionResolution = typeof SUSPENSION_RESOLUTIONS[number];
|
|
63
|
-
export declare const SUSPENSION_RESOLUTION_VIAS: readonly ["modal_button", "auto_approve", "prompt_answer"];
|
|
63
|
+
export declare const SUSPENSION_RESOLUTION_VIAS: readonly ["modal_button", "auto_approve", "prompt_answer", "modal_disappeared"];
|
|
64
64
|
export type SuspensionResolutionVia = typeof SUSPENSION_RESOLUTION_VIAS[number];
|
|
65
65
|
export declare const TURN_END_STRENGTHS: readonly ["genuine", "weak"];
|
|
66
66
|
export type TurnEndStrength = typeof TURN_END_STRENGTHS[number];
|
|
67
67
|
/** Why a provider-side weak end was released (was free text `blockReason`). */
|
|
68
68
|
export declare const TURN_END_BLOCK_REASONS: readonly ["missing_final_assistant", "finalization_timeout", "terminal_block_hard_cap", "decoupled_completion"];
|
|
69
69
|
export type TurnEndBlockReason = typeof TURN_END_BLOCK_REASONS[number];
|
|
70
|
-
export declare const NATIVE_TURN_OUTCOMES: readonly ["completed", "aborted"];
|
|
70
|
+
export declare const NATIVE_TURN_OUTCOMES: readonly ["completed", "aborted", "failed"];
|
|
71
71
|
export type NativeTurnOutcome = typeof NATIVE_TURN_OUTCOMES[number];
|
|
72
72
|
export declare const LIVENESS_RESULTS: readonly ["alive", "unknown", "read_failed", "dead"];
|
|
73
73
|
export type LivenessResult = typeof LIVENESS_RESULTS[number];
|
|
74
|
-
export declare const PROVIDER_FAILURES: readonly ["auth_failed", "billing_failed"];
|
|
74
|
+
export declare const PROVIDER_FAILURES: readonly ["auth_failed", "billing_failed", "usage_limit_exceeded", "server_overloaded", "provider_error"];
|
|
75
75
|
export type ProviderFailure = typeof PROVIDER_FAILURES[number];
|
|
76
76
|
/**
|
|
77
77
|
* `daemon_restart` (wiring-unification follow-up, design §5): boot-time
|
|
@@ -99,14 +99,14 @@ export type NoProgressObservedStatus = SessionStatus | 'unknown';
|
|
|
99
99
|
* Reasons a turn hold exists. Holds are attempt-scoped only (C2: delivery-side
|
|
100
100
|
* waits are consumer deferral on the `turn.deliver` cursor, not hold rows).
|
|
101
101
|
*/
|
|
102
|
-
export declare const HOLD_REASONS: readonly ["await_delivery", "await_consume", "await_turn", "liveness", "hard_ceiling", "live_pending", "transcript_quiet", "weak_candidate", "suspension_before_consumed", "await_report", "await_end"];
|
|
102
|
+
export declare const HOLD_REASONS: readonly ["await_delivery", "await_consume", "await_turn", "liveness", "hard_ceiling", "live_pending", "transcript_quiet", "weak_candidate", "suspension_before_consumed", "await_report", "await_end", "report_correction"];
|
|
103
103
|
export type HoldReason = typeof HOLD_REASONS[number];
|
|
104
104
|
export declare const TURN_OUTCOMES: readonly ["completed", "failed", "cancelled"];
|
|
105
105
|
export type TurnOutcome = typeof TURN_OUTCOMES[number];
|
|
106
106
|
export declare const COMMIT_STRENGTHS: readonly ["genuine", "weak", "tool_report", "operator"];
|
|
107
107
|
export type CommitStrength = typeof COMMIT_STRENGTHS[number];
|
|
108
108
|
/** Every terminal or reclaim reason the ledger writes. Closed: no free-text reasons. */
|
|
109
|
-
export declare const TURN_REASONS: readonly ["turn_end", "weak_end_confirmed", "transcript_final", "worker_reported", "finalization_timeout_no_response", "session_error", "provider_auth_failed", "provider_billing_failed", "operator_cancel", "intentional_cleanup", "task_removed", "mission_abandoned", "superseded", "operator_update", "refine_terminal", "validation_terminal", "hard_ceiling", "reclaim_budget_exhausted", "hollow_max_retries", "migration_orphan", "dispatch_refused_session_exited", "dispatch_refused_no_target", "dispatch_refused_unsupported_input", "dispatch_failed", "session_exit", "session_exit_before_turn", "session_dead", "hollow_completion", "assigned_stranded_dispatch_unconfirmed", "delivered_not_consumed_redrive", "delivered_no_turn_deadline"];
|
|
109
|
+
export declare const TURN_REASONS: readonly ["turn_end", "weak_end_confirmed", "transcript_final", "worker_reported", "finalization_timeout_no_response", "weak_end_liveness_unconfirmed", "weak_end_probe_unobserved", "report_correction_expired", "session_error", "provider_auth_failed", "provider_billing_failed", "provider_usage_limit_exceeded", "provider_server_overloaded", "provider_error", "operator_cancel", "intentional_cleanup", "task_removed", "mission_abandoned", "superseded", "operator_update", "refine_terminal", "validation_terminal", "hard_ceiling", "reclaim_budget_exhausted", "hollow_max_retries", "migration_orphan", "dispatch_refused_session_exited", "dispatch_refused_no_target", "dispatch_refused_unsupported_input", "dispatch_failed", "session_exit", "session_exit_before_turn", "session_dead", "hollow_completion", "assigned_stranded_dispatch_unconfirmed", "delivered_not_consumed_redrive", "delivered_no_turn_deadline"];
|
|
110
110
|
export type TurnReason = typeof TURN_REASONS[number];
|
|
111
111
|
/**
|
|
112
112
|
* What a `turn.notify` entry tells a coordinator.
|
|
@@ -149,6 +149,9 @@ export interface EvidenceCoordinatorIdentity {
|
|
|
149
149
|
export interface NativeTurnMarkerRef {
|
|
150
150
|
outcome: NativeTurnOutcome;
|
|
151
151
|
turnId?: string;
|
|
152
|
+
receivedAt?: number;
|
|
153
|
+
startedAt?: number;
|
|
154
|
+
errorAt?: number;
|
|
152
155
|
}
|
|
153
156
|
export interface EvidenceEnvelope {
|
|
154
157
|
/** Stable id of this observation; dedupe key across republish/replication. */
|
|
@@ -220,10 +223,13 @@ export type TurnEvidenceBody = {
|
|
|
220
223
|
kind: 'suspension';
|
|
221
224
|
modal: SuspensionModal;
|
|
222
225
|
modalKey?: string;
|
|
226
|
+
providerSetup?: boolean;
|
|
227
|
+
clockUnknown?: boolean;
|
|
223
228
|
} | {
|
|
224
229
|
kind: 'suspension_resolved';
|
|
225
230
|
resolution: SuspensionResolution;
|
|
226
231
|
via: SuspensionResolutionVia;
|
|
232
|
+
modalKey?: string;
|
|
227
233
|
} | {
|
|
228
234
|
kind: 'turn_end';
|
|
229
235
|
strength: TurnEndStrength;
|
|
@@ -233,6 +239,7 @@ export type TurnEvidenceBody = {
|
|
|
233
239
|
blockReason?: TurnEndBlockReason;
|
|
234
240
|
releasedByHardCap?: boolean;
|
|
235
241
|
nativeOutcome?: NativeTurnOutcome;
|
|
242
|
+
nativeMarker?: NativeTurnMarkerRef;
|
|
236
243
|
live?: LiveTurnPending;
|
|
237
244
|
/**
|
|
238
245
|
* Stamped (true only) by the WORKER's daemon when the session holds a live
|
|
@@ -268,6 +275,7 @@ export type TurnEvidenceBody = {
|
|
|
268
275
|
} | {
|
|
269
276
|
kind: 'liveness';
|
|
270
277
|
result: LivenessResult;
|
|
278
|
+
probeStartedAtMs?: number;
|
|
271
279
|
} | {
|
|
272
280
|
kind: 'process_exit';
|
|
273
281
|
exitCode: number | null;
|
|
@@ -288,6 +296,9 @@ export type TurnEvidenceBody = {
|
|
|
288
296
|
hasHandoffNotes: boolean;
|
|
289
297
|
branchState?: WorkerBranchState;
|
|
290
298
|
touchedFileCount?: number;
|
|
299
|
+
} | {
|
|
300
|
+
kind: 'worker_report_correction_requested';
|
|
301
|
+
deliveryId?: string;
|
|
291
302
|
} | {
|
|
292
303
|
kind: 'worker_progress';
|
|
293
304
|
note?: SummaryRef;
|
|
@@ -371,14 +382,15 @@ export declare const TURN_EVIDENCE_FIELD_SPECS: TurnEvidenceFieldSpecs;
|
|
|
371
382
|
export declare const TURN_EVIDENCE_KINDS: readonly TurnEvidenceKind[];
|
|
372
383
|
/** Evidence kinds that, on their own, can end a turn (the ones R18/R19/R27 reason about). */
|
|
373
384
|
export declare const TERMINAL_CLASS_EVIDENCE_KINDS: readonly ["turn_end", "transcript_final", "no_progress", "worker_report", "session_error", "process_exit", "cancel", "operator_status"];
|
|
374
|
-
export declare const isTurnEvidenceKind: (value: unknown) => value is "no_progress" | "delivered" | "liveness" | "turn_end" | "transcript_final" | "session_error" | "dispatch_failed" | "dispatch_accepted" | "delivery_refused" | "duplicate_dispatch_refusal" | "session_rebound" | "turn_started" | "suspension" | "suspension_resolved" | "transcript_activity" | "process_exit" | "worker_report" | "worker_progress" | "git_side_effect" | "cancel" | "operator_status" | "coordinator_ack" | "hold_expired";
|
|
375
|
-
export declare const isTurnReason: (value: unknown) => value is "intentional_cleanup" | "operator_cancel" | "task_removed" | "mission_abandoned" | "superseded" | "operator_update" | "refine_terminal" | "validation_terminal" | "hard_ceiling" | "turn_end" | "weak_end_confirmed" | "transcript_final" | "worker_reported" | "finalization_timeout_no_response" | "session_error" | "provider_auth_failed" | "provider_billing_failed" | "reclaim_budget_exhausted" | "hollow_max_retries" | "migration_orphan" | "dispatch_refused_session_exited" | "dispatch_refused_no_target" | "dispatch_refused_unsupported_input" | "dispatch_failed" | "session_exit" | "session_exit_before_turn" | "session_dead" | "hollow_completion" | "assigned_stranded_dispatch_unconfirmed" | "delivered_not_consumed_redrive" | "delivered_no_turn_deadline";
|
|
385
|
+
export declare const isTurnEvidenceKind: (value: unknown) => value is "no_progress" | "delivered" | "liveness" | "turn_end" | "transcript_final" | "session_error" | "dispatch_failed" | "dispatch_accepted" | "delivery_refused" | "duplicate_dispatch_refusal" | "session_rebound" | "turn_started" | "suspension" | "suspension_resolved" | "transcript_activity" | "process_exit" | "worker_report" | "worker_report_correction_requested" | "worker_progress" | "git_side_effect" | "cancel" | "operator_status" | "coordinator_ack" | "hold_expired";
|
|
386
|
+
export declare const isTurnReason: (value: unknown) => value is "provider_error" | "intentional_cleanup" | "operator_cancel" | "task_removed" | "mission_abandoned" | "superseded" | "operator_update" | "refine_terminal" | "validation_terminal" | "hard_ceiling" | "turn_end" | "weak_end_confirmed" | "transcript_final" | "worker_reported" | "finalization_timeout_no_response" | "weak_end_liveness_unconfirmed" | "weak_end_probe_unobserved" | "report_correction_expired" | "session_error" | "provider_auth_failed" | "provider_billing_failed" | "provider_usage_limit_exceeded" | "provider_server_overloaded" | "reclaim_budget_exhausted" | "hollow_max_retries" | "migration_orphan" | "dispatch_refused_session_exited" | "dispatch_refused_no_target" | "dispatch_refused_unsupported_input" | "dispatch_failed" | "session_exit" | "session_exit_before_turn" | "session_dead" | "hollow_completion" | "assigned_stranded_dispatch_unconfirmed" | "delivered_not_consumed_redrive" | "delivered_no_turn_deadline";
|
|
376
387
|
export declare const isNotifyKind: (value: unknown) => value is "stopped" | "failed" | "no_progress" | "completed" | "cancelled" | "approval" | "choice" | "approval_resolved" | "candidate" | "progress" | "late_completion" | "mesh_event";
|
|
377
388
|
export declare const isTurnOutcome: (value: unknown) => value is "failed" | "completed" | "cancelled";
|
|
378
389
|
export declare const isCommitStrength: (value: unknown) => value is "operator" | "genuine" | "weak" | "tool_report";
|
|
379
390
|
export declare function isEvidenceIdentifier(value: unknown): value is string;
|
|
380
391
|
export declare function isSummaryRef(value: unknown): value is SummaryRef;
|
|
381
392
|
export declare function isTurnAttemptRef(value: unknown): value is TurnAttemptRef;
|
|
393
|
+
export declare function isNativeMarkerRef(value: unknown): value is NativeTurnMarkerRef;
|
|
382
394
|
/**
|
|
383
395
|
* Strict structural guard: known kind, every declared field of the right class,
|
|
384
396
|
* and NO undeclared field (an unknown key is how free text would sneak in).
|
package/dist/types.d.ts
CHANGED
|
@@ -120,6 +120,7 @@ export interface MeshNodeIdentified {
|
|
|
120
120
|
[key: string]: unknown;
|
|
121
121
|
}
|
|
122
122
|
export interface RepoMeshSessionStatus {
|
|
123
|
+
providerApproval?: import('./provider-approval').ProviderApproval | null;
|
|
123
124
|
sessionId: string;
|
|
124
125
|
providerType?: string;
|
|
125
126
|
state?: string;
|
package/package.json
CHANGED
|
@@ -18,6 +18,9 @@
|
|
|
18
18
|
|
|
19
19
|
export const ASSISTANT_TOOLS = [
|
|
20
20
|
'projects',
|
|
21
|
+
'environment',
|
|
22
|
+
'assistant_action',
|
|
23
|
+
'project_watch',
|
|
21
24
|
'project_status',
|
|
22
25
|
'project_send',
|
|
23
26
|
'project_read',
|
|
@@ -41,6 +44,11 @@ export function isAssistantTool(value: unknown): value is AssistantTool {
|
|
|
41
44
|
export const ASSISTANT_VERB = {
|
|
42
45
|
// tool verbs
|
|
43
46
|
projects: 'assistant_projects',
|
|
47
|
+
environment: 'assistant_environment',
|
|
48
|
+
action: 'assistant_action',
|
|
49
|
+
watch: 'assistant_project_watch',
|
|
50
|
+
executionState: 'assistant_execution_state',
|
|
51
|
+
executionSettings: 'assistant_execution_settings',
|
|
44
52
|
projectStatus: 'assistant_project_status',
|
|
45
53
|
projectSend: 'assistant_project_send',
|
|
46
54
|
projectRead: 'assistant_project_read',
|
|
@@ -64,6 +72,9 @@ export type AssistantVerb = typeof ASSISTANT_VERB[keyof typeof ASSISTANT_VERB]
|
|
|
64
72
|
/** The daemon verb each assistant tool calls. */
|
|
65
73
|
export const ASSISTANT_TOOL_VERBS: Readonly<Record<AssistantTool, AssistantVerb>> = {
|
|
66
74
|
projects: ASSISTANT_VERB.projects,
|
|
75
|
+
environment: ASSISTANT_VERB.environment,
|
|
76
|
+
assistant_action: ASSISTANT_VERB.action,
|
|
77
|
+
project_watch: ASSISTANT_VERB.watch,
|
|
67
78
|
project_status: ASSISTANT_VERB.projectStatus,
|
|
68
79
|
project_send: ASSISTANT_VERB.projectSend,
|
|
69
80
|
project_read: ASSISTANT_VERB.projectRead,
|
|
@@ -81,10 +92,11 @@ export const ASSISTANT_TOOL_VERBS: Readonly<Record<AssistantTool, AssistantVerb>
|
|
|
81
92
|
* because they cause effects (a coordinator message or launch, a new
|
|
82
93
|
* project), and MCP clients use readOnlyHint to skip confirmation.
|
|
83
94
|
*/
|
|
84
|
-
export const ASSISTANT_WRITE_TOOLS: readonly AssistantTool[] = ['memory', 'skill_manage', 'project_note', 'project_send', 'project_add']
|
|
95
|
+
export const ASSISTANT_WRITE_TOOLS: readonly AssistantTool[] = ['project_watch', 'assistant_action', 'memory', 'skill_manage', 'project_note', 'project_send', 'project_add']
|
|
85
96
|
|
|
86
97
|
/** Owner-only verbs: never reachable from the assistant's MCP server (no `ipc`). */
|
|
87
98
|
export const ASSISTANT_OWNER_VERBS: readonly AssistantVerb[] = [
|
|
99
|
+
ASSISTANT_VERB.executionSettings,
|
|
88
100
|
ASSISTANT_VERB.stagedResolve,
|
|
89
101
|
ASSISTANT_VERB.storeAdmin,
|
|
90
102
|
ASSISTANT_VERB.importSkills,
|
package/src/index.ts
CHANGED
package/src/mesh-vocabulary.ts
CHANGED
|
@@ -56,6 +56,14 @@ export type MeshSessionCleanupMode = typeof MESH_SESSION_CLEANUP_MODES[number]
|
|
|
56
56
|
export const WORKER_REPORT_OUTCOMES = ['completed', 'blocked', 'failed'] as const
|
|
57
57
|
export type WorkerReportOutcome = typeof WORKER_REPORT_OUTCOMES[number]
|
|
58
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Hard cap on a `report_completion` summary (characters, after trim). Over-limit
|
|
61
|
+
* summaries are REJECTED, never truncated. Declared once so the daemon validator
|
|
62
|
+
* and the mcp-server's pre-send check (which keeps an over-limit report out of the
|
|
63
|
+
* durable outbox) cannot drift apart.
|
|
64
|
+
*/
|
|
65
|
+
export const WORKER_REPORT_SUMMARY_MAX_CHARS = 8_000
|
|
66
|
+
|
|
59
67
|
/** Final branch state a worker reports (see coordinator convergence rules). */
|
|
60
68
|
export const WORKER_BRANCH_STATES = [
|
|
61
69
|
'merged_to_main',
|
package/src/node-facts.ts
CHANGED
|
@@ -126,6 +126,25 @@ export interface MeshNodeFactsProviderQuota {
|
|
|
126
126
|
* predating the field.
|
|
127
127
|
*/
|
|
128
128
|
fetchedAt?: number
|
|
129
|
+
/**
|
|
130
|
+
* Provenance of the RETAINED reading when `lastGoodWindows` is true —
|
|
131
|
+
* the source/plan/measurement time of the snapshot that produced the
|
|
132
|
+
* carried numbers, as opposed to the top-level `source`/`planType`,
|
|
133
|
+
* which describe the fresh failed attempt. See daemon-core
|
|
134
|
+
* `QuotaMetadata.lastGood`.
|
|
135
|
+
*/
|
|
136
|
+
lastGood?: {
|
|
137
|
+
measuredAt: number
|
|
138
|
+
source?: string
|
|
139
|
+
planType?: string | null
|
|
140
|
+
collectorScope?: string
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* `'background-collector'` when the snapshot came from a daemon-spawned
|
|
144
|
+
* probe rather than an executing CLI session; a failure with this scope
|
|
145
|
+
* is not evidence about a running session's sign-in.
|
|
146
|
+
*/
|
|
147
|
+
collectorScope?: string
|
|
129
148
|
[extra: string]: unknown
|
|
130
149
|
}
|
|
131
150
|
[extra: string]: unknown
|
|
@@ -151,6 +170,8 @@ export interface MeshNodeFactsProviderEnablement {
|
|
|
151
170
|
|
|
152
171
|
export interface MeshNodeFacts {
|
|
153
172
|
schemaVersion: number
|
|
173
|
+
/** Cached CLI detection only; no paths or account data. */
|
|
174
|
+
providerInventory?: { observedAt: number; providers: Record<string, { installed: boolean }> }
|
|
154
175
|
reportedAt: number
|
|
155
176
|
daemonBuild?: MeshNodeFactsDaemonBuild
|
|
156
177
|
providerVersions?: Record<string, string>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** Provider permissions are runtime decisions, never owner write ratification. */
|
|
2
|
+
export interface ProviderApproval {
|
|
3
|
+
source: 'provider_modal' | 'legacy_provider' | 'status_only' | 'ledger_approval';
|
|
4
|
+
/** Exact Inbox actions or the existing session handler; never inferred consent. */
|
|
5
|
+
compatibility?: 'exact' | 'session_only' | 'unknown';
|
|
6
|
+
type: 'tool_permission' | 'provider_setup' | 'unknown';
|
|
7
|
+
evidence: 'live' | 'cached' | 'unavailable';
|
|
8
|
+
lifecycle: 'pending' | 'resolved';
|
|
9
|
+
modalKey: string | null;
|
|
10
|
+
createdAt: number | null;
|
|
11
|
+
resolvedAt: number | null;
|
|
12
|
+
description: string;
|
|
13
|
+
runtimeDirectory?: string;
|
|
14
|
+
displayedDirectory?: string | null;
|
|
15
|
+
buttons: string[];
|
|
16
|
+
actionable: boolean;
|
|
17
|
+
providerType?: string;
|
|
18
|
+
sessionId?: string;
|
|
19
|
+
nodeId?: string | null;
|
|
20
|
+
meshId?: string | null;
|
|
21
|
+
taskId?: string | null;
|
|
22
|
+
attemptId?: string | null;
|
|
23
|
+
generation?: number | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Exact resource identity required by the approvals-only action path. */
|
|
27
|
+
export interface ProviderApprovalTarget {
|
|
28
|
+
modalKey: string;
|
|
29
|
+
attemptId: string | null;
|
|
30
|
+
generation: number | null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Confirmed authority for the new Inbox path. Legacy handlers retain their own checks. */
|
|
34
|
+
export function isActionableProviderApproval(approval: ProviderApproval | null | undefined): boolean {
|
|
35
|
+
return !!approval && approval.source === 'provider_modal' && approval.type === 'tool_permission'
|
|
36
|
+
&& approval.lifecycle === 'pending' && approval.evidence === 'live' && approval.actionable
|
|
37
|
+
&& !!approval.modalKey && Array.isArray(approval.buttons)
|
|
38
|
+
&& approval.buttons.some(button => typeof button === 'string' && !!button.trim());
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** An explicit null suppresses the resource; only missing metadata uses compatibility. */
|
|
42
|
+
export function readProviderDecision(approval: ProviderApproval | null | undefined, waiting: boolean, hasModal = false): ProviderApproval | null {
|
|
43
|
+
if (approval !== undefined) return approval && ['provider_modal', 'legacy_provider', 'status_only', 'ledger_approval'].includes(approval.source) ? approval : null;
|
|
44
|
+
if (!waiting) return null;
|
|
45
|
+
return { source: hasModal ? 'legacy_provider' : 'status_only', type: 'unknown',
|
|
46
|
+
compatibility: hasModal ? 'session_only' : 'unknown', evidence: 'unavailable',
|
|
47
|
+
lifecycle: 'pending', modalKey: null, createdAt: null, resolvedAt: null,
|
|
48
|
+
description: '', buttons: [], actionable: false };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Host metadata is durable: identity and clocks only, never modal text or directories. */
|
|
52
|
+
export function providerApprovalSnapshot(approval: ProviderApproval | null | undefined): ProviderApproval | null {
|
|
53
|
+
if (!approval) return null;
|
|
54
|
+
const { source, type, lifecycle, modalKey, createdAt, resolvedAt, providerType, sessionId,
|
|
55
|
+
nodeId, meshId, taskId, attemptId, generation } = approval;
|
|
56
|
+
return { source, type, lifecycle, modalKey, createdAt, resolvedAt, providerType, sessionId,
|
|
57
|
+
nodeId, meshId, taskId, attemptId, generation, evidence: 'cached', actionable: false,
|
|
58
|
+
description: '', buttons: [] };
|
|
59
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** Ephemeral provenance supplied by the owning daemon, never inferred from prompt text. */
|
|
2
|
+
export interface ProviderQuestionBinding {
|
|
3
|
+
transport: 'codex_rpc' | 'codex_async';
|
|
4
|
+
sessionId: string;
|
|
5
|
+
generation: string;
|
|
6
|
+
threadId: string;
|
|
7
|
+
turnId: string;
|
|
8
|
+
itemId: string;
|
|
9
|
+
requestId?: string | number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type ProviderQuestionLifecycle = 'pending' | 'submitted' | 'resolved' | 'completed' | 'cancelled' | 'expired' | 'unknown';
|
|
13
|
+
|
|
14
|
+
export interface ProviderQuestionEpisode {
|
|
15
|
+
blocking?: boolean;
|
|
16
|
+
binding?: ProviderQuestionBinding;
|
|
17
|
+
lifecycle?: ProviderQuestionLifecycle;
|
|
18
|
+
/** Async dismiss is product-local; it is not a native tool cancellation. */
|
|
19
|
+
support?: 'request_bound' | 'product_local' | 'uncertain';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function isProviderQuestionBinding(value: unknown): value is ProviderQuestionBinding {
|
|
23
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
|
|
24
|
+
const b = value as Record<string, unknown>;
|
|
25
|
+
if (b.transport !== 'codex_rpc' && b.transport !== 'codex_async') return false;
|
|
26
|
+
const keys = ['transport', 'sessionId', 'generation', 'threadId', 'turnId', 'itemId', ...(b.transport === 'codex_rpc' ? ['requestId'] : [])];
|
|
27
|
+
if (Reflect.ownKeys(b).some(key => typeof key !== 'string' || !keys.includes(key))) return false;
|
|
28
|
+
if (['sessionId', 'generation', 'threadId', 'turnId', 'itemId'].some(key => typeof b[key] !== 'string' || !(b[key] as string).trim())) return false;
|
|
29
|
+
return b.transport === 'codex_async' ? b.requestId === undefined
|
|
30
|
+
: (typeof b.requestId === 'string' && !!b.requestId.trim()) || (typeof b.requestId === 'number' && Number.isFinite(b.requestId));
|
|
31
|
+
}
|
package/src/quota-freshness.ts
CHANGED
|
@@ -50,9 +50,14 @@ function hasUsableWindow(window: { usedPercent?: unknown } | null | undefined):
|
|
|
50
50
|
return !!window && typeof window.usedPercent === 'number' && Number.isFinite(window.usedPercent)
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* Does the snapshot carry any renderable number — session/weekly/monthly
|
|
55
|
+
* windows OR per-pool buckets? `monthly` counts on its own: cursor-cli reports
|
|
56
|
+
* ONLY that axis, and leaving it out made a retained cursor reading look
|
|
57
|
+
* numberless. A window without a finite `usedPercent` is unknown, not 0%.
|
|
58
|
+
*/
|
|
54
59
|
function hasReading(quota: MeshNodeFactsProviderQuota): boolean {
|
|
55
|
-
if (hasUsableWindow(quota.session) || hasUsableWindow(quota.weekly)) return true
|
|
60
|
+
if (hasUsableWindow(quota.session) || hasUsableWindow(quota.weekly) || hasUsableWindow(quota.monthly)) return true
|
|
56
61
|
return Array.isArray(quota.buckets) && quota.buckets.some((b) => !!b && typeof b.usedPercent === 'number' && Number.isFinite(b.usedPercent))
|
|
57
62
|
}
|
|
58
63
|
|
package/src/turn-evidence.ts
CHANGED
|
@@ -83,9 +83,9 @@ export type SessionReboundReason = typeof SESSION_REBOUND_REASONS[number]
|
|
|
83
83
|
|
|
84
84
|
export const SUSPENSION_MODALS = ['approval', 'choice'] as const
|
|
85
85
|
export type SuspensionModal = typeof SUSPENSION_MODALS[number]
|
|
86
|
-
export const SUSPENSION_RESOLUTIONS = ['approved', 'rejected', 'answered'] as const
|
|
86
|
+
export const SUSPENSION_RESOLUTIONS = ['approved', 'rejected', 'answered', 'dismissed'] as const
|
|
87
87
|
export type SuspensionResolution = typeof SUSPENSION_RESOLUTIONS[number]
|
|
88
|
-
export const SUSPENSION_RESOLUTION_VIAS = ['modal_button', 'auto_approve', 'prompt_answer'] as const
|
|
88
|
+
export const SUSPENSION_RESOLUTION_VIAS = ['modal_button', 'auto_approve', 'prompt_answer', 'modal_disappeared'] as const
|
|
89
89
|
export type SuspensionResolutionVia = typeof SUSPENSION_RESOLUTION_VIAS[number]
|
|
90
90
|
|
|
91
91
|
export const TURN_END_STRENGTHS = ['genuine', 'weak'] as const
|
|
@@ -97,13 +97,13 @@ export const TURN_END_BLOCK_REASONS = [
|
|
|
97
97
|
] as const
|
|
98
98
|
export type TurnEndBlockReason = typeof TURN_END_BLOCK_REASONS[number]
|
|
99
99
|
|
|
100
|
-
export const NATIVE_TURN_OUTCOMES = ['completed', 'aborted'] as const
|
|
100
|
+
export const NATIVE_TURN_OUTCOMES = ['completed', 'aborted', 'failed'] as const
|
|
101
101
|
export type NativeTurnOutcome = typeof NATIVE_TURN_OUTCOMES[number]
|
|
102
102
|
|
|
103
103
|
export const LIVENESS_RESULTS = ['alive', 'unknown', 'read_failed', 'dead'] as const
|
|
104
104
|
export type LivenessResult = typeof LIVENESS_RESULTS[number]
|
|
105
105
|
|
|
106
|
-
export const PROVIDER_FAILURES = ['auth_failed', 'billing_failed'] as const
|
|
106
|
+
export const PROVIDER_FAILURES = ['auth_failed', 'billing_failed', 'usage_limit_exceeded', 'server_overloaded', 'provider_error'] as const
|
|
107
107
|
export type ProviderFailure = typeof PROVIDER_FAILURES[number]
|
|
108
108
|
|
|
109
109
|
/**
|
|
@@ -150,7 +150,7 @@ export const HOLD_REASONS = [
|
|
|
150
150
|
// — a turn_end commits the report (R9t), expiry commits it anyway (R13t) so
|
|
151
151
|
// a session whose FSM never shows the idle edge again does not wait for
|
|
152
152
|
// liveness / hard_ceiling.
|
|
153
|
-
'await_end',
|
|
153
|
+
'await_end', 'report_correction',
|
|
154
154
|
] as const
|
|
155
155
|
export type HoldReason = typeof HOLD_REASONS[number]
|
|
156
156
|
|
|
@@ -164,7 +164,7 @@ export type CommitStrength = typeof COMMIT_STRENGTHS[number]
|
|
|
164
164
|
export const TURN_REASONS = [
|
|
165
165
|
// commits
|
|
166
166
|
'turn_end', 'weak_end_confirmed', 'transcript_final', 'worker_reported',
|
|
167
|
-
'finalization_timeout_no_response', 'session_error', 'provider_auth_failed', 'provider_billing_failed',
|
|
167
|
+
'finalization_timeout_no_response', 'weak_end_liveness_unconfirmed', 'weak_end_probe_unobserved', 'report_correction_expired', 'session_error', 'provider_auth_failed', 'provider_billing_failed', 'provider_usage_limit_exceeded', 'provider_server_overloaded', 'provider_error',
|
|
168
168
|
'operator_cancel', 'intentional_cleanup', 'task_removed', 'mission_abandoned', 'superseded',
|
|
169
169
|
'operator_update', 'refine_terminal', 'validation_terminal',
|
|
170
170
|
'hard_ceiling', 'reclaim_budget_exhausted', 'hollow_max_retries', 'migration_orphan',
|
|
@@ -207,7 +207,7 @@ export interface LiveTurnPending { modal: boolean; adapterPending: boolean; trai
|
|
|
207
207
|
/** Structural copy of daemon-core's `CoordinatorIdentity` (this package cannot import daemon-core). */
|
|
208
208
|
export interface EvidenceCoordinatorIdentity { daemonId: string; coordinatorRunId: string; sessionId?: string }
|
|
209
209
|
|
|
210
|
-
export interface NativeTurnMarkerRef { outcome: NativeTurnOutcome; turnId?: string }
|
|
210
|
+
export interface NativeTurnMarkerRef { outcome: NativeTurnOutcome; turnId?: string; receivedAt?: number; startedAt?: number; errorAt?: number }
|
|
211
211
|
|
|
212
212
|
export interface EvidenceEnvelope {
|
|
213
213
|
/** Stable id of this observation; dedupe key across republish/replication. */
|
|
@@ -250,10 +250,10 @@ export type TurnEvidenceBody =
|
|
|
250
250
|
| { kind: 'session_rebound'; toSessionId: string; reason: SessionReboundReason }
|
|
251
251
|
// ── worker turn lifecycle ──
|
|
252
252
|
| { kind: 'turn_started'; retro: boolean }
|
|
253
|
-
| { kind: 'suspension'; modal: SuspensionModal; modalKey?: string }
|
|
254
|
-
| { kind: 'suspension_resolved'; resolution: SuspensionResolution; via: SuspensionResolutionVia }
|
|
253
|
+
| { kind: 'suspension'; modal: SuspensionModal; modalKey?: string; providerSetup?: boolean; clockUnknown?: boolean }
|
|
254
|
+
| { kind: 'suspension_resolved'; resolution: SuspensionResolution; via: SuspensionResolutionVia; modalKey?: string }
|
|
255
255
|
| { kind: 'turn_end'; strength: TurnEndStrength; afterFinalizationTimeout?: boolean; hollow?: boolean; summary?: SummaryRef
|
|
256
|
-
blockReason?: TurnEndBlockReason; releasedByHardCap?: boolean; nativeOutcome?: NativeTurnOutcome; live?: LiveTurnPending
|
|
256
|
+
blockReason?: TurnEndBlockReason; releasedByHardCap?: boolean; nativeOutcome?: NativeTurnOutcome; nativeMarker?: NativeTurnMarkerRef; live?: LiveTurnPending
|
|
257
257
|
/**
|
|
258
258
|
* Stamped (true only) by the WORKER's daemon when the session holds a live
|
|
259
259
|
* worker-MCP session bind, i.e. the worker can call report_completion. The
|
|
@@ -273,7 +273,7 @@ export type TurnEvidenceBody =
|
|
|
273
273
|
live: LiveTurnPending; summary?: SummaryRef; messageAt?: number }
|
|
274
274
|
| { kind: 'transcript_activity'; newestActivityAt: number }
|
|
275
275
|
| { kind: 'no_progress'; stalledMs: number; observedStatus: NoProgressObservedStatus; finalAssistantPresent: boolean }
|
|
276
|
-
| { kind: 'liveness'; result: LivenessResult }
|
|
276
|
+
| { kind: 'liveness'; result: LivenessResult; probeStartedAtMs?: number }
|
|
277
277
|
| { kind: 'process_exit'; exitCode: number | null; providerFailure?: ProviderFailure }
|
|
278
278
|
| { kind: 'session_error'; reason: SessionErrorReason }
|
|
279
279
|
// ── worker MCP (F2) ──
|
|
@@ -284,6 +284,7 @@ export type TurnEvidenceBody =
|
|
|
284
284
|
*/
|
|
285
285
|
| { kind: 'worker_report'; outcome: WorkerReportOutcome; summary?: SummaryRef; hasHandoffNotes: boolean
|
|
286
286
|
branchState?: WorkerBranchState; touchedFileCount?: number }
|
|
287
|
+
| { kind: 'worker_report_correction_requested'; deliveryId?: string }
|
|
287
288
|
| { kind: 'worker_progress'; note?: SummaryRef }
|
|
288
289
|
// ── coordinator / operator ──
|
|
289
290
|
| { kind: 'git_side_effect'; dirty: boolean; commitsSinceDispatch: number; attributable: boolean }
|
|
@@ -352,13 +353,13 @@ export const TURN_EVIDENCE_FIELD_SPECS: TurnEvidenceFieldSpecs = {
|
|
|
352
353
|
duplicate_dispatch_refusal: { holderSessionId: id, holderAttemptId: idOpt },
|
|
353
354
|
session_rebound: { toSessionId: id, reason: en(SESSION_REBOUND_REASONS) },
|
|
354
355
|
turn_started: { retro: bool },
|
|
355
|
-
suspension: { modal: en(SUSPENSION_MODALS), modalKey: idOpt },
|
|
356
|
-
suspension_resolved: { resolution: en(SUSPENSION_RESOLUTIONS), via: en(SUSPENSION_RESOLUTION_VIAS) },
|
|
356
|
+
suspension: { modal: en(SUSPENSION_MODALS), modalKey: idOpt, providerSetup: boolOpt, clockUnknown: boolOpt },
|
|
357
|
+
suspension_resolved: { resolution: en(SUSPENSION_RESOLUTIONS), via: en(SUSPENSION_RESOLUTION_VIAS), modalKey: idOpt },
|
|
357
358
|
turn_end: {
|
|
358
359
|
strength: en(TURN_END_STRENGTHS), afterFinalizationTimeout: boolOpt, hollow: boolOpt,
|
|
359
360
|
summary: { t: 'summary_ref', optional: true }, blockReason: enOpt(TURN_END_BLOCK_REASONS),
|
|
360
361
|
releasedByHardCap: boolOpt, nativeOutcome: enOpt(NATIVE_TURN_OUTCOMES), live: { t: 'live', optional: true },
|
|
361
|
-
reportExpected: boolOpt, providerFailure: enOpt(PROVIDER_FAILURES),
|
|
362
|
+
nativeMarker: { t: 'native_marker', optional: true }, reportExpected: boolOpt, providerFailure: enOpt(PROVIDER_FAILURES),
|
|
362
363
|
},
|
|
363
364
|
transcript_final: {
|
|
364
365
|
selfAttributing: bool, nativeRead: bool, nativeMarker: { t: 'native_marker', optional: true },
|
|
@@ -366,13 +367,14 @@ export const TURN_EVIDENCE_FIELD_SPECS: TurnEvidenceFieldSpecs = {
|
|
|
366
367
|
},
|
|
367
368
|
transcript_activity: { newestActivityAt: ms },
|
|
368
369
|
no_progress: { stalledMs: ms, observedStatus: en(NO_PROGRESS_OBSERVED_STATUSES), finalAssistantPresent: bool },
|
|
369
|
-
liveness: { result: en(LIVENESS_RESULTS) },
|
|
370
|
+
liveness: { result: en(LIVENESS_RESULTS), probeStartedAtMs: msOpt },
|
|
370
371
|
process_exit: { exitCode: { t: 'int', nullable: true }, providerFailure: enOpt(PROVIDER_FAILURES) },
|
|
371
372
|
session_error: { reason: en(SESSION_ERROR_REASONS) },
|
|
372
373
|
worker_report: {
|
|
373
374
|
outcome: en(WORKER_REPORT_OUTCOMES), summary: { t: 'summary_ref', optional: true }, hasHandoffNotes: bool,
|
|
374
375
|
branchState: enOpt(WORKER_BRANCH_STATES), touchedFileCount: intOpt,
|
|
375
376
|
},
|
|
377
|
+
worker_report_correction_requested: { deliveryId: { t: 'id', optional: true } },
|
|
376
378
|
worker_progress: { note: { t: 'summary_ref', optional: true } },
|
|
377
379
|
git_side_effect: { dirty: bool, commitsSinceDispatch: { t: 'int' }, attributable: bool },
|
|
378
380
|
cancel: { reason: en(CANCEL_REASONS) },
|
|
@@ -440,11 +442,12 @@ function isLiveTurnPending(value: unknown): value is LiveTurnPending {
|
|
|
440
442
|
&& (value.newestActivityAt === undefined || isFiniteNumber(value.newestActivityAt))
|
|
441
443
|
}
|
|
442
444
|
|
|
443
|
-
function isNativeMarkerRef(value: unknown): value is NativeTurnMarkerRef {
|
|
445
|
+
export function isNativeMarkerRef(value: unknown): value is NativeTurnMarkerRef {
|
|
444
446
|
return isRecord(value)
|
|
445
|
-
&& hasOnlyKeys(value, ['outcome', 'turnId'])
|
|
447
|
+
&& hasOnlyKeys(value, ['outcome', 'turnId', 'receivedAt', 'startedAt', 'errorAt'])
|
|
446
448
|
&& (NATIVE_TURN_OUTCOMES as readonly string[]).includes(value.outcome as string)
|
|
447
449
|
&& (value.turnId === undefined || isEvidenceIdentifier(value.turnId))
|
|
450
|
+
&& ['receivedAt', 'startedAt', 'errorAt'].every((key) => value[key] === undefined || isFiniteNumber(value[key]))
|
|
448
451
|
}
|
|
449
452
|
|
|
450
453
|
function isCoordinatorIdentity(value: unknown): value is EvidenceCoordinatorIdentity {
|
package/src/types.ts
CHANGED