@adhdev/mesh-shared 1.0.82-rc.2 → 1.0.82-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.
@@ -0,0 +1,194 @@
1
+ /** Daemon-local launch intent and command wire contract. P2P/local only;
2
+ * never include this document or its history in cloud status_report.
3
+ * Publication through mesh-shared's barrel is a later integration step. */
4
+ export declare const LAUNCH_DEFAULT_ROLES: readonly ["assistant", "coordinator"];
5
+ export type LaunchDefaultRole = typeof LAUNCH_DEFAULT_ROLES[number];
6
+ export declare const LAUNCH_DEFAULT_SOURCES: readonly ["user", "stored_default", "project_default", "provider_default"];
7
+ export type LaunchDefaultSource = typeof LAUNCH_DEFAULT_SOURCES[number];
8
+ export declare const LAUNCH_DEFAULTS_NEXT_LAUNCH_NOTE = "Applies to the next launch; running sessions are unchanged.";
9
+ export declare function isLaunchDefaultRole(value: unknown): value is LaunchDefaultRole;
10
+ export declare function isLaunchDefaultSource(value: unknown): value is LaunchDefaultSource;
11
+ export interface LaunchDefaultSelection {
12
+ provider: string;
13
+ /** Omission means pass no model/thinking argument, not inherit another provider. */
14
+ model?: string;
15
+ thinkingLevel?: string;
16
+ }
17
+ export type LaunchDefaultToolRestriction = 'enforced' | 'prompt_only';
18
+ export type LaunchDefaultOrigin = 'owner' | 'human' | 'relay' | 'review' | 'review_tainted';
19
+ export interface LaunchDefaultEntry extends LaunchDefaultSelection {
20
+ revision: number;
21
+ setBy: 'owner' | 'assistant';
22
+ setAt: number;
23
+ }
24
+ export interface LaunchDefaultChange {
25
+ at: number;
26
+ role: LaunchDefaultRole;
27
+ by: 'owner' | 'assistant';
28
+ origin: LaunchDefaultOrigin;
29
+ from: LaunchDefaultEntry | null;
30
+ to: LaunchDefaultEntry | null;
31
+ }
32
+ export interface LaunchDefaultsDocument {
33
+ version: 1;
34
+ /** Global document token, including clears; distinct from entry revisions. */
35
+ revision: number;
36
+ assistant?: LaunchDefaultEntry;
37
+ coordinator?: LaunchDefaultEntry;
38
+ history: LaunchDefaultChange[];
39
+ }
40
+ export interface LaunchDefaultRef {
41
+ role: LaunchDefaultRole;
42
+ scope: 'global' | 'project';
43
+ /** Entry revision for global defaults; host project token for project defaults. */
44
+ revision: number;
45
+ projectId?: string;
46
+ }
47
+ export type LaunchDefaultField = keyof LaunchDefaultSelection;
48
+ export interface LaunchDefaultAxis {
49
+ value: string | null;
50
+ source: LaunchDefaultSource;
51
+ defaultRef?: LaunchDefaultRef;
52
+ }
53
+ export type LaunchDefaultWarning = 'catalog_unverified' | 'manual_mcp_setup_required';
54
+ export type LaunchDefaultValidationReason = 'invalid_schema' | 'provider_unknown' | 'provider_not_cli' | 'provider_disabled' | 'provider_not_detected' | 'provider_not_eligible' | 'model_unsupported' | 'model_provider_mismatch' | 'model_not_offered' | 'thinking_unsupported' | 'thinking_not_offered' | 'catalog_unavailable';
55
+ export type LaunchDefaultResolution = {
56
+ ok: true;
57
+ selection: LaunchDefaultSelection;
58
+ applied: Record<LaunchDefaultField, LaunchDefaultAxis>;
59
+ defaultRef?: LaunchDefaultRef;
60
+ documentRevision: number;
61
+ warnings: LaunchDefaultWarning[];
62
+ toolRestriction: LaunchDefaultToolRestriction;
63
+ } | {
64
+ ok: false;
65
+ code: 'launch_default_required' | 'launch_default_unavailable' | 'launch_selection_invalid';
66
+ role: LaunchDefaultRole;
67
+ field: LaunchDefaultField;
68
+ reason: string;
69
+ source?: LaunchDefaultSource;
70
+ value?: string | null;
71
+ defaultRef?: LaunchDefaultRef;
72
+ candidates?: readonly string[];
73
+ hint: string;
74
+ };
75
+ export interface LaunchDefaultsRoleView {
76
+ stored: LaunchDefaultEntry | null;
77
+ /** The existing daemon resolver's result, including loud failures. */
78
+ effective: LaunchDefaultResolution;
79
+ }
80
+ type Target = {
81
+ role: 'assistant';
82
+ project?: never;
83
+ } | {
84
+ role: 'coordinator';
85
+ project?: string;
86
+ };
87
+ export type LaunchDefaultsReadRequest = ({
88
+ action?: 'get';
89
+ } & (Target | {
90
+ role?: never;
91
+ project?: never;
92
+ })) | ({
93
+ action: 'check';
94
+ } & Target & LaunchDefaultSelection);
95
+ /** Mandatory CAS: global document token, or host project token for project writes.
96
+ * 0 is explicit first setup; clears advance the token and never restore fallback. */
97
+ export type LaunchDefaultsSetRequest = Target & {
98
+ expectedRevision: number;
99
+ } & (({
100
+ action: 'set';
101
+ } & LaunchDefaultSelection) | {
102
+ action: 'clear';
103
+ provider?: never;
104
+ model?: never;
105
+ thinkingLevel?: never;
106
+ });
107
+ /** Existing assistant routing envelope; session identity never supplies origin. */
108
+ export type AssistantLaunchDefaultsReadRequest = LaunchDefaultsReadRequest & {
109
+ assistantSessionId?: string;
110
+ };
111
+ export type AssistantLaunchDefaultsSetRequest = LaunchDefaultsSetRequest & {
112
+ assistantSessionId?: string;
113
+ };
114
+ export declare const LAUNCH_DEFAULT_ERROR_CODES: readonly ["invalid_args", "launch_default_required", "launch_default_unavailable", "launch_selection_invalid", "launch_default_invalid", "revision_conflict", "store_unavailable", "store_busy", "persistence_failed", "project_not_found", "project_ambiguous", "project_not_hosted", "project_storage_unavailable", "staging_unavailable", "staging_failed", "review_turn_tool_denied"];
115
+ export type LaunchDefaultsErrorCode = typeof LAUNCH_DEFAULT_ERROR_CODES[number];
116
+ export interface LaunchDefaultsError {
117
+ success: false;
118
+ code: LaunchDefaultsErrorCode;
119
+ error: string;
120
+ reason?: string;
121
+ role?: LaunchDefaultRole;
122
+ field?: LaunchDefaultField;
123
+ source?: LaunchDefaultSource;
124
+ value?: string | null;
125
+ defaultRef?: LaunchDefaultRef;
126
+ candidates?: readonly string[];
127
+ actualRevision?: number;
128
+ /** 0 for an absent global document; absent when it cannot be read. */
129
+ documentRevision?: number;
130
+ /** A persistence failure can replace intent without confirming durability.
131
+ * Re-read before retrying; never report applied on committed:true alone. */
132
+ committed?: boolean;
133
+ }
134
+ export interface LaunchDefaultsReadSuccess {
135
+ success: true;
136
+ result: 'get';
137
+ documentRevision: number;
138
+ roles: Partial<Record<LaunchDefaultRole, LaunchDefaultsRoleView>>;
139
+ project?: {
140
+ projectId: string;
141
+ revision: number;
142
+ entry: LaunchDefaultEntry | null;
143
+ };
144
+ }
145
+ export interface LaunchDefaultsCheckSuccess {
146
+ success: true;
147
+ result: 'check';
148
+ role: LaunchDefaultRole;
149
+ selection: LaunchDefaultSelection;
150
+ warnings: LaunchDefaultWarning[];
151
+ toolRestriction: LaunchDefaultToolRestriction;
152
+ lowersToolLock: boolean;
153
+ }
154
+ export interface LaunchDefaultsApplied {
155
+ success: true;
156
+ result: 'applied';
157
+ role: LaunchDefaultRole;
158
+ scope: 'global' | 'project';
159
+ projectId?: string;
160
+ entry: LaunchDefaultEntry | null;
161
+ previous: LaunchDefaultEntry | null;
162
+ /** CAS token returned by the authority that performed the write. */
163
+ revision: number;
164
+ warnings: LaunchDefaultWarning[];
165
+ durable: true;
166
+ note: string;
167
+ }
168
+ export interface LaunchDefaultsStaged {
169
+ success: true;
170
+ result: 'staged';
171
+ role: LaunchDefaultRole;
172
+ stagedId: string;
173
+ previous: LaunchDefaultEntry | null;
174
+ selection: LaunchDefaultSelection | null;
175
+ expectedRevision: number;
176
+ warnings: LaunchDefaultWarning[];
177
+ note: string;
178
+ }
179
+ /** Existing owner Inbox adapter stores this proposal; it is not another default.
180
+ * Applying it must revalidate on the host and CAS via the same set handler. */
181
+ export interface LaunchDefaultsProposal {
182
+ kind: 'launch_defaults';
183
+ role: LaunchDefaultRole;
184
+ project?: string;
185
+ selection: LaunchDefaultSelection | null;
186
+ previous: LaunchDefaultEntry | null;
187
+ expectedRevision: number;
188
+ origin: LaunchDefaultOrigin;
189
+ callerSessionId?: string;
190
+ }
191
+ export type LaunchDefaultsReadResponse = LaunchDefaultsReadSuccess | LaunchDefaultsCheckSuccess | LaunchDefaultsError;
192
+ export type LaunchDefaultsSetResponse = LaunchDefaultsApplied | LaunchDefaultsStaged | LaunchDefaultsError;
193
+ export type LaunchDefaultsResponse = LaunchDefaultsReadResponse | LaunchDefaultsSetResponse;
194
+ export {};
@@ -18,10 +18,10 @@
18
18
  * Order mirrors mcp-server `ALL_MESH_TOOLS` for easy visual diffing, but the consistency
19
19
  * checks are set-based (order-insensitive).
20
20
  */
21
- export declare const CANONICAL_MESH_TOOL_NAMES: readonly ["mesh_status", "mesh_route_preview", "mesh_list_nodes", "mesh_enqueue_batch", "mesh_enqueue_task", "mesh_view_queue", "mesh_queue_cancel", "mesh_queue_requeue", "mesh_send_task", "mesh_read_chat", "mesh_read_debug", "mesh_read_terminal", "mesh_send_keys", "mesh_launch_session", "mesh_git_status", "mesh_read_node_logs", "mesh_fast_forward_node", "mesh_restart_daemon", "mesh_checkpoint", "mesh_approve", "mesh_answer_question", "mesh_list_pending_approvals", "mesh_create", "mesh_add_node", "mesh_clone_node", "mesh_remove_node", "mesh_cleanup_worktree_nodes", "mesh_refine_node", "mesh_refine_batch", "mesh_config", "mesh_init", "mesh_cleanup_sessions", "mesh_task_history", "mesh_ledger_query", "mesh_note", "mesh_reconcile_ledger", "mesh_mission_upsert", "mesh_mission_list", "mesh_review_inbox", "mesh_node_slots"];
21
+ export declare const CANONICAL_MESH_TOOL_NAMES: readonly ["mesh_status", "mesh_route_preview", "mesh_list_nodes", "mesh_enqueue_batch", "mesh_enqueue_task", "mesh_view_queue", "mesh_queue_cancel", "mesh_queue_requeue", "mesh_send_task", "mesh_read_chat", "mesh_read_debug", "mesh_read_terminal", "mesh_send_keys", "mesh_launch_session", "mesh_git_status", "mesh_read_node_logs", "mesh_fast_forward_node", "mesh_restart_daemon", "mesh_checkpoint", "mesh_approve", "mesh_answer_question", "mesh_list_pending_approvals", "mesh_create", "mesh_add_node", "mesh_attach_remote", "mesh_clone_node", "mesh_remove_node", "mesh_cleanup_worktree_nodes", "mesh_refine_node", "mesh_refine_batch", "mesh_config", "mesh_init", "mesh_cleanup_sessions", "mesh_task_history", "mesh_ledger_query", "mesh_note", "mesh_reconcile_ledger", "mesh_mission_upsert", "mesh_mission_list", "mesh_review_inbox", "mesh_node_slots"];
22
22
  export type CanonicalMeshToolName = typeof CANONICAL_MESH_TOOL_NAMES[number];
23
23
  /** The count the `NN tools` barrel doc comments and consistency test assert against. */
24
- export declare const CANONICAL_MESH_TOOL_COUNT: 40;
24
+ export declare const CANONICAL_MESH_TOOL_COUNT: 41;
25
25
  /**
26
26
  * Tool names retired by the 2026-09-26 tool-surface consolidation (60 → 48).
27
27
  * Every capability behind them is still reachable: each retired name maps to the
@@ -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 "failed" | "pending" | "assigned" | "completed" | "cancelled";
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";
@@ -94,6 +94,20 @@ export interface MeshNodeFactsProviderQuota {
94
94
  * rather than presenting them as a freshly measured value.
95
95
  */
96
96
  lastGoodWindows?: boolean;
97
+ /**
98
+ * Unix ms the reporting node's NEXT scheduled retry of this transient
99
+ * failure is due (HTTP Retry-After wins when later). Re-stamped to the
100
+ * real backoff time on every failure — see daemon-core
101
+ * `updateFailureRetry`. Absent on persistent failures and on daemons
102
+ * predating the stamp.
103
+ */
104
+ retryAtMs?: number;
105
+ /**
106
+ * True once the node has spent its bounded transient-retry budget and
107
+ * stopped retrying; the next look is the hourly backfill. Readers must
108
+ * stop calling retained numbers "refreshing" (`assessQuotaFreshness`).
109
+ */
110
+ retryExhausted?: boolean;
97
111
  /**
98
112
  * Unix ms when the reporting node last ATTEMPTED a refresh of this
99
113
  * provider — deliberately distinct from `updatedAt`, which dates the
@@ -109,6 +123,25 @@ export interface MeshNodeFactsProviderQuota {
109
123
  * predating the field.
110
124
  */
111
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;
112
145
  [extra: string]: unknown;
113
146
  };
114
147
  [extra: string]: unknown;
@@ -132,6 +165,13 @@ export interface MeshNodeFactsProviderEnablement {
132
165
  }
133
166
  export interface MeshNodeFacts {
134
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
+ };
135
175
  reportedAt: number;
136
176
  daemonBuild?: MeshNodeFactsDaemonBuild;
137
177
  providerVersions?: Record<string, string>;
@@ -33,7 +33,7 @@
33
33
  */
34
34
  /** One normalized ownership entry: a repo-relative path, optionally a `**` subtree prefix. */
35
35
  export interface OwnedPathEntry {
36
- /** Repo-relative path with forward slashes, no leading `./`, no trailing slash. */
36
+ /** Repo-relative path with forward slashes, no leading `./`, no trailing slash; empty for the whole-repo subtree. */
37
37
  readonly path: string;
38
38
  /** True when this entry was declared as `<path>/**` (owns the whole subtree). */
39
39
  readonly subtree: boolean;
@@ -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;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Quota snapshot freshness — the ONE decision every display surface shares.
3
+ *
4
+ * Why this lives in the leaf package: the dashboard chips (web-core
5
+ * `quotaWindowCue`), the `adhdev quota` CLI (daemon-core `quota/cli.ts`) and the
6
+ * coordinator-facing `mesh_status` fold (mcp-server `summarizeNodeQuota`) each
7
+ * carried a hand-copied version of this rule, and a fix to one left the other
8
+ * two telling a different story about the same snapshot. They all call
9
+ * `assessQuotaFreshness` now; only the WORDING stays per-surface.
10
+ *
11
+ * Pure: plain objects in, plain object out, no clock except the `now` argument.
12
+ */
13
+ import type { MeshNodeFactsProviderQuota } from './node-facts';
14
+ export type QuotaFreshnessCue = 'refreshing' | 'stale';
15
+ export interface QuotaFreshness {
16
+ /** Undefined = nothing to say (a fresh reading, or no retained numbers). */
17
+ cue?: QuotaFreshnessCue;
18
+ /**
19
+ * Only the USER can produce a new reading (aged-out Claude statusline;
20
+ * expired CLI access token — the daemon never redeems it). The surface
21
+ * should say what to run, not promise a self-heal.
22
+ */
23
+ userMustAct: boolean;
24
+ /**
25
+ * Unix ms by which the daemon will have looked again, for a `stale` reading
26
+ * the daemon re-checks on its own. Absent when the user must act, when the
27
+ * reading is `refreshing` (a retry is already scheduled), or when the check
28
+ * is already due.
29
+ */
30
+ nextCheckAt?: number;
31
+ }
32
+ /**
33
+ * How long past `metadata.retryAtMs` a retry still reads as "in flight". The
34
+ * retry timer fires at retryAtMs and the probe itself takes a few seconds; a
35
+ * retryAtMs well in the past with no newer attempt means no retry is coming.
36
+ */
37
+ export declare const QUOTA_RETRY_INFLIGHT_GRACE_MS = 60000;
38
+ /**
39
+ * The daemon's backfill horizon: a snapshot is re-probed once it is this old
40
+ * even on an idle machine. Mirrors daemon-core `QUOTA_ROUTABLE_MAX_AGE_MS`
41
+ * (quota/refresh.ts); daemon-core's quota-freshness test pins the two equal.
42
+ */
43
+ export declare const QUOTA_BACKFILL_HORIZON_MS: number;
44
+ /**
45
+ * Which freshness cue a snapshot's retained numbers should carry.
46
+ *
47
+ * - `stale` + `userMustAct` — nothing will refresh it without the user:
48
+ * · `no-data` on any provider EXCEPT codex (Claude's statusline aged out —
49
+ * a session must run). Codex's `no-data` is the daemon re-reading the
50
+ * rollout files itself (≈60s while a CLI is active, ≤60 min idle), so it
51
+ * is `stale` WITHOUT userMustAct;
52
+ * · `expired-token` on Grok/Kimi/antigravity — only the owning CLI
53
+ * renews it on use. An idle CLI has no background renewal cadence.
54
+ * A scheduled quota retry does not itself renew credentials.
55
+ * - `refreshing` — retained numbers after a transient failure with a retry
56
+ * actually pending. ★Honest about the end of the retry budget: once the
57
+ * daemon has stopped retrying (`metadata.retryExhausted`, or `retryAtMs`
58
+ * long past with no newer attempt) the numbers are `stale` with the next
59
+ * scheduled check, not "refreshing" for the up-to-60 minutes until the
60
+ * hourly backfill. A snapshot with NO retry bookkeeping at all (a daemon
61
+ * predating the stamp) keeps the old `refreshing` reading.
62
+ */
63
+ export declare function assessQuotaFreshness(quota: MeshNodeFactsProviderQuota, now?: number): QuotaFreshness;
64
+ /** Whole minutes (min 1) until `nextCheckAt`, for the "next check ~Nm" wording. */
65
+ export declare function minutesUntilQuotaCheck(nextCheckAt: number, now?: number): number;
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/mesh-shared",
3
- "version": "1.0.82-rc.2",
3
+ "version": "1.0.82-rc.20",
4
4
  "description": "ADHDev mesh-shared — pure mesh/git status normalizers shared by daemon-core and web-core",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -18,15 +18,21 @@
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',
24
27
  'project_add',
28
+ 'project_attach_remote',
25
29
  'discover_repos',
26
30
  'memory',
27
31
  'skill_view',
28
32
  'skill_manage',
29
33
  'project_note',
34
+ 'launch_defaults',
35
+ 'launch_defaults_set',
30
36
  ] as const
31
37
 
32
38
  export type AssistantTool = typeof ASSISTANT_TOOLS[number]
@@ -41,15 +47,23 @@ export function isAssistantTool(value: unknown): value is AssistantTool {
41
47
  export const ASSISTANT_VERB = {
42
48
  // tool verbs
43
49
  projects: 'assistant_projects',
50
+ environment: 'assistant_environment',
51
+ action: 'assistant_action',
52
+ watch: 'assistant_project_watch',
53
+ executionState: 'assistant_execution_state',
54
+ executionSettings: 'assistant_execution_settings',
44
55
  projectStatus: 'assistant_project_status',
45
56
  projectSend: 'assistant_project_send',
46
57
  projectRead: 'assistant_project_read',
47
58
  projectAdd: 'assistant_project_add',
59
+ projectAttachRemote: 'assistant_project_attach_remote',
48
60
  discoverRepos: 'assistant_discover_repos',
49
61
  memory: 'assistant_memory',
50
62
  skillView: 'assistant_skill_view',
51
63
  skillManage: 'assistant_skill_manage',
52
64
  projectNote: 'assistant_project_note',
65
+ launchDefaults: 'assistant_launch_defaults',
66
+ launchDefaultsSet: 'assistant_launch_defaults_set',
53
67
  // assistant-side daemon verbs without a tool of the same name
54
68
  launch: 'launch_assistant',
55
69
  pendingRelays: 'assistant_pending_relays',
@@ -64,15 +78,21 @@ export type AssistantVerb = typeof ASSISTANT_VERB[keyof typeof ASSISTANT_VERB]
64
78
  /** The daemon verb each assistant tool calls. */
65
79
  export const ASSISTANT_TOOL_VERBS: Readonly<Record<AssistantTool, AssistantVerb>> = {
66
80
  projects: ASSISTANT_VERB.projects,
81
+ environment: ASSISTANT_VERB.environment,
82
+ assistant_action: ASSISTANT_VERB.action,
83
+ project_watch: ASSISTANT_VERB.watch,
67
84
  project_status: ASSISTANT_VERB.projectStatus,
68
85
  project_send: ASSISTANT_VERB.projectSend,
69
86
  project_read: ASSISTANT_VERB.projectRead,
70
87
  project_add: ASSISTANT_VERB.projectAdd,
88
+ project_attach_remote: ASSISTANT_VERB.projectAttachRemote,
71
89
  discover_repos: ASSISTANT_VERB.discoverRepos,
72
90
  memory: ASSISTANT_VERB.memory,
73
91
  skill_view: ASSISTANT_VERB.skillView,
74
92
  skill_manage: ASSISTANT_VERB.skillManage,
75
93
  project_note: ASSISTANT_VERB.projectNote,
94
+ launch_defaults: ASSISTANT_VERB.launchDefaults,
95
+ launch_defaults_set: ASSISTANT_VERB.launchDefaultsSet,
76
96
  }
77
97
 
78
98
  /**
@@ -81,10 +101,11 @@ export const ASSISTANT_TOOL_VERBS: Readonly<Record<AssistantTool, AssistantVerb>
81
101
  * because they cause effects (a coordinator message or launch, a new
82
102
  * project), and MCP clients use readOnlyHint to skip confirmation.
83
103
  */
84
- export const ASSISTANT_WRITE_TOOLS: readonly AssistantTool[] = ['memory', 'skill_manage', 'project_note', 'project_send', 'project_add']
104
+ export const ASSISTANT_WRITE_TOOLS: readonly AssistantTool[] = ['project_watch', 'assistant_action', 'memory', 'skill_manage', 'project_note', 'project_send', 'project_add', 'project_attach_remote', 'launch_defaults_set']
85
105
 
86
106
  /** Owner-only verbs: never reachable from the assistant's MCP server (no `ipc`). */
87
107
  export const ASSISTANT_OWNER_VERBS: readonly AssistantVerb[] = [
108
+ ASSISTANT_VERB.executionSettings,
88
109
  ASSISTANT_VERB.stagedResolve,
89
110
  ASSISTANT_VERB.storeAdmin,
90
111
  ASSISTANT_VERB.importSkills,