@adhdev/mesh-shared 1.0.82-rc.16 → 1.0.82-rc.17

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
@@ -17,7 +17,7 @@ export interface QuotaFreshness {
17
17
  cue?: QuotaFreshnessCue;
18
18
  /**
19
19
  * Only the USER can produce a new reading (aged-out Claude statusline;
20
- * antigravity expired token — the daemon never redeems it). The surface
20
+ * expired CLI access token — the daemon never redeems it). The surface
21
21
  * should say what to run, not promise a self-heal.
22
22
  */
23
23
  userMustAct: boolean;
@@ -49,9 +49,9 @@ export declare const QUOTA_BACKFILL_HORIZON_MS: number;
49
49
  * a session must run). Codex's `no-data` is the daemon re-reading the
50
50
  * rollout files itself (≈60s while a CLI is active, ≤60 min idle), so it
51
51
  * is `stale` WITHOUT userMustAct;
52
- * · antigravity `expired-token` — the daemon deliberately does not redeem
53
- * the refresh token. Kimi's expired-token is NOT here: its CLI refreshes
54
- * the token on its own cadence.
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
55
  * - `refreshing` — retained numbers after a transient failure with a retry
56
56
  * actually pending. ★Honest about the end of the retry budget: once the
57
57
  * daemon has stopped retrying (`metadata.retryExhausted`, or `retryAtMs`
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@adhdev/mesh-shared",
3
- "version": "1.0.82-rc.16",
4
- "description": "ADHDev mesh-shared \u2014 pure mesh/git status normalizers shared by daemon-core and web-core",
3
+ "version": "1.0.82-rc.17",
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",
7
7
  "exports": {
@@ -25,6 +25,7 @@ export const ASSISTANT_TOOLS = [
25
25
  'project_send',
26
26
  'project_read',
27
27
  'project_add',
28
+ 'project_attach_remote',
28
29
  'discover_repos',
29
30
  'memory',
30
31
  'skill_view',
@@ -53,6 +54,7 @@ export const ASSISTANT_VERB = {
53
54
  projectSend: 'assistant_project_send',
54
55
  projectRead: 'assistant_project_read',
55
56
  projectAdd: 'assistant_project_add',
57
+ projectAttachRemote: 'assistant_project_attach_remote',
56
58
  discoverRepos: 'assistant_discover_repos',
57
59
  memory: 'assistant_memory',
58
60
  skillView: 'assistant_skill_view',
@@ -79,6 +81,7 @@ export const ASSISTANT_TOOL_VERBS: Readonly<Record<AssistantTool, AssistantVerb>
79
81
  project_send: ASSISTANT_VERB.projectSend,
80
82
  project_read: ASSISTANT_VERB.projectRead,
81
83
  project_add: ASSISTANT_VERB.projectAdd,
84
+ project_attach_remote: ASSISTANT_VERB.projectAttachRemote,
82
85
  discover_repos: ASSISTANT_VERB.discoverRepos,
83
86
  memory: ASSISTANT_VERB.memory,
84
87
  skill_view: ASSISTANT_VERB.skillView,
@@ -92,7 +95,7 @@ export const ASSISTANT_TOOL_VERBS: Readonly<Record<AssistantTool, AssistantVerb>
92
95
  * because they cause effects (a coordinator message or launch, a new
93
96
  * project), and MCP clients use readOnlyHint to skip confirmation.
94
97
  */
95
- export const ASSISTANT_WRITE_TOOLS: readonly AssistantTool[] = ['project_watch', 'assistant_action', 'memory', 'skill_manage', 'project_note', 'project_send', 'project_add']
98
+ export const ASSISTANT_WRITE_TOOLS: readonly AssistantTool[] = ['project_watch', 'assistant_action', 'memory', 'skill_manage', 'project_note', 'project_send', 'project_add', 'project_attach_remote']
96
99
 
97
100
  /** Owner-only verbs: never reachable from the assistant's MCP server (no `ipc`). */
98
101
  export const ASSISTANT_OWNER_VERBS: readonly AssistantVerb[] = [
package/src/index.ts CHANGED
@@ -44,3 +44,4 @@ export * from './mission-brief'
44
44
  export * from './keyed-doc-delta'
45
45
  export * from './provider-approval'
46
46
  export * from './provider-question'
47
+ export * from './launch-defaults'
@@ -0,0 +1,168 @@
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 const LAUNCH_DEFAULT_ROLES = ['assistant', 'coordinator'] as const;
5
+ export type LaunchDefaultRole = typeof LAUNCH_DEFAULT_ROLES[number];
6
+ export const LAUNCH_DEFAULT_SOURCES = ['user', 'stored_default', 'project_default', 'provider_default'] as const;
7
+ export type LaunchDefaultSource = typeof LAUNCH_DEFAULT_SOURCES[number];
8
+ export const LAUNCH_DEFAULTS_NEXT_LAUNCH_NOTE = 'Applies to the next launch; running sessions are unchanged.';
9
+ export function isLaunchDefaultRole(value: unknown): value is LaunchDefaultRole {
10
+ return typeof value === 'string' && (LAUNCH_DEFAULT_ROLES as readonly string[]).includes(value);
11
+ }
12
+ export function isLaunchDefaultSource(value: unknown): value is LaunchDefaultSource {
13
+ return typeof value === 'string' && (LAUNCH_DEFAULT_SOURCES as readonly string[]).includes(value);
14
+ }
15
+ export interface LaunchDefaultSelection {
16
+ provider: string;
17
+ /** Omission means pass no model/thinking argument, not inherit another provider. */
18
+ model?: string;
19
+ thinkingLevel?: string;
20
+ }
21
+ export type LaunchDefaultToolRestriction = 'enforced' | 'prompt_only';
22
+ export type LaunchDefaultOrigin = 'owner' | 'human' | 'relay' | 'review' | 'review_tainted';
23
+ export interface LaunchDefaultEntry extends LaunchDefaultSelection {
24
+ revision: number;
25
+ setBy: 'owner' | 'assistant';
26
+ setAt: number;
27
+ }
28
+ export interface LaunchDefaultChange {
29
+ at: number;
30
+ role: LaunchDefaultRole;
31
+ by: 'owner' | 'assistant';
32
+ origin: LaunchDefaultOrigin;
33
+ from: LaunchDefaultEntry | null;
34
+ to: LaunchDefaultEntry | null;
35
+ }
36
+ export interface LaunchDefaultsDocument {
37
+ version: 1;
38
+ /** Global document token, including clears; distinct from entry revisions. */
39
+ revision: number;
40
+ assistant?: LaunchDefaultEntry;
41
+ coordinator?: LaunchDefaultEntry;
42
+ history: LaunchDefaultChange[];
43
+ }
44
+ export interface LaunchDefaultRef {
45
+ role: LaunchDefaultRole;
46
+ scope: 'global' | 'project';
47
+ /** Entry revision for global defaults; host project token for project defaults. */
48
+ revision: number;
49
+ projectId?: string;
50
+ }
51
+ export type LaunchDefaultField = keyof LaunchDefaultSelection;
52
+ export interface LaunchDefaultAxis {
53
+ value: string | null;
54
+ source: LaunchDefaultSource;
55
+ defaultRef?: LaunchDefaultRef;
56
+ }
57
+ export type LaunchDefaultWarning = 'catalog_unverified' | 'manual_mcp_setup_required';
58
+ export type LaunchDefaultValidationReason =
59
+ | 'invalid_schema' | 'provider_unknown' | 'provider_not_cli' | 'provider_disabled'
60
+ | 'provider_not_detected' | 'provider_not_eligible' | 'model_unsupported'
61
+ | 'model_provider_mismatch' | 'model_not_offered' | 'thinking_unsupported'
62
+ | 'thinking_not_offered' | 'catalog_unavailable';
63
+ export type LaunchDefaultResolution =
64
+ | { ok: true; selection: LaunchDefaultSelection; applied: Record<LaunchDefaultField, LaunchDefaultAxis>;
65
+ defaultRef?: LaunchDefaultRef; documentRevision: number; warnings: LaunchDefaultWarning[];
66
+ toolRestriction: LaunchDefaultToolRestriction }
67
+ | { ok: false; code: 'launch_default_required' | 'launch_default_unavailable' | 'launch_selection_invalid';
68
+ role: LaunchDefaultRole; field: LaunchDefaultField; reason: string; source?: LaunchDefaultSource;
69
+ value?: string | null; defaultRef?: LaunchDefaultRef; candidates?: readonly string[]; hint: string };
70
+ export interface LaunchDefaultsRoleView {
71
+ stored: LaunchDefaultEntry | null;
72
+ /** The existing daemon resolver's result, including loud failures. */
73
+ effective: LaunchDefaultResolution;
74
+ }
75
+ type Target = { role: 'assistant'; project?: never } | { role: 'coordinator'; project?: string };
76
+ export type LaunchDefaultsReadRequest =
77
+ | ({ action?: 'get' } & (Target | { role?: never; project?: never }))
78
+ | ({ action: 'check' } & Target & LaunchDefaultSelection);
79
+ /** Mandatory CAS: global document token, or host project token for project writes.
80
+ * 0 is explicit first setup; clears advance the token and never restore fallback. */
81
+ export type LaunchDefaultsSetRequest = Target & { expectedRevision: number } & (
82
+ | ({ action: 'set' } & LaunchDefaultSelection)
83
+ | { action: 'clear'; provider?: never; model?: never; thinkingLevel?: never }
84
+ );
85
+ /** Existing assistant routing envelope; session identity never supplies origin. */
86
+ export type AssistantLaunchDefaultsReadRequest = LaunchDefaultsReadRequest & { assistantSessionId?: string };
87
+ export type AssistantLaunchDefaultsSetRequest = LaunchDefaultsSetRequest & { assistantSessionId?: string };
88
+ export const LAUNCH_DEFAULT_ERROR_CODES = [
89
+ 'invalid_args', 'launch_default_required', 'launch_default_unavailable', 'launch_selection_invalid',
90
+ 'launch_default_invalid', 'revision_conflict', 'store_unavailable', 'store_busy', 'persistence_failed',
91
+ 'project_not_found', 'project_ambiguous', 'project_not_hosted', 'project_storage_unavailable',
92
+ 'staging_unavailable', 'staging_failed', 'review_turn_tool_denied',
93
+ ] as const;
94
+ export type LaunchDefaultsErrorCode = typeof LAUNCH_DEFAULT_ERROR_CODES[number];
95
+ export interface LaunchDefaultsError {
96
+ success: false;
97
+ code: LaunchDefaultsErrorCode;
98
+ error: string;
99
+ reason?: string;
100
+ role?: LaunchDefaultRole;
101
+ field?: LaunchDefaultField;
102
+ source?: LaunchDefaultSource;
103
+ value?: string | null;
104
+ defaultRef?: LaunchDefaultRef;
105
+ candidates?: readonly string[];
106
+ actualRevision?: number;
107
+ /** 0 for an absent global document; absent when it cannot be read. */
108
+ documentRevision?: number;
109
+ /** A persistence failure can replace intent without confirming durability.
110
+ * Re-read before retrying; never report applied on committed:true alone. */
111
+ committed?: boolean;
112
+ }
113
+ export interface LaunchDefaultsReadSuccess {
114
+ success: true;
115
+ result: 'get';
116
+ documentRevision: number;
117
+ roles: Partial<Record<LaunchDefaultRole, LaunchDefaultsRoleView>>;
118
+ project?: { projectId: string; revision: number; entry: LaunchDefaultEntry | null };
119
+ }
120
+ export interface LaunchDefaultsCheckSuccess {
121
+ success: true;
122
+ result: 'check';
123
+ role: LaunchDefaultRole;
124
+ selection: LaunchDefaultSelection;
125
+ warnings: LaunchDefaultWarning[];
126
+ toolRestriction: LaunchDefaultToolRestriction;
127
+ lowersToolLock: boolean;
128
+ }
129
+ export interface LaunchDefaultsApplied {
130
+ success: true;
131
+ result: 'applied';
132
+ role: LaunchDefaultRole;
133
+ scope: 'global' | 'project';
134
+ projectId?: string;
135
+ entry: LaunchDefaultEntry | null;
136
+ previous: LaunchDefaultEntry | null;
137
+ /** CAS token returned by the authority that performed the write. */
138
+ revision: number;
139
+ warnings: LaunchDefaultWarning[];
140
+ durable: true;
141
+ note: string;
142
+ }
143
+ export interface LaunchDefaultsStaged {
144
+ success: true;
145
+ result: 'staged';
146
+ role: LaunchDefaultRole;
147
+ stagedId: string;
148
+ previous: LaunchDefaultEntry | null;
149
+ selection: LaunchDefaultSelection | null;
150
+ expectedRevision: number;
151
+ warnings: LaunchDefaultWarning[];
152
+ note: string;
153
+ }
154
+ /** Existing owner Inbox adapter stores this proposal; it is not another default.
155
+ * Applying it must revalidate on the host and CAS via the same set handler. */
156
+ export interface LaunchDefaultsProposal {
157
+ kind: 'launch_defaults';
158
+ role: LaunchDefaultRole;
159
+ project?: string;
160
+ selection: LaunchDefaultSelection | null;
161
+ previous: LaunchDefaultEntry | null;
162
+ expectedRevision: number;
163
+ origin: LaunchDefaultOrigin;
164
+ callerSessionId?: string;
165
+ }
166
+ export type LaunchDefaultsReadResponse = LaunchDefaultsReadSuccess | LaunchDefaultsCheckSuccess | LaunchDefaultsError;
167
+ export type LaunchDefaultsSetResponse = LaunchDefaultsApplied | LaunchDefaultsStaged | LaunchDefaultsError;
168
+ export type LaunchDefaultsResponse = LaunchDefaultsReadResponse | LaunchDefaultsSetResponse;
@@ -44,6 +44,7 @@ export const CANONICAL_MESH_TOOL_NAMES = [
44
44
  'mesh_list_pending_approvals',
45
45
  'mesh_create',
46
46
  'mesh_add_node',
47
+ 'mesh_attach_remote',
47
48
  'mesh_clone_node',
48
49
  'mesh_remove_node',
49
50
  'mesh_cleanup_worktree_nodes',
@@ -19,7 +19,7 @@ export interface QuotaFreshness {
19
19
  cue?: QuotaFreshnessCue
20
20
  /**
21
21
  * Only the USER can produce a new reading (aged-out Claude statusline;
22
- * antigravity expired token — the daemon never redeems it). The surface
22
+ * expired CLI access token — the daemon never redeems it). The surface
23
23
  * should say what to run, not promise a self-heal.
24
24
  */
25
25
  userMustAct: boolean
@@ -88,9 +88,9 @@ function backfillCheckAt(quota: MeshNodeFactsProviderQuota, now: number): number
88
88
  * a session must run). Codex's `no-data` is the daemon re-reading the
89
89
  * rollout files itself (≈60s while a CLI is active, ≤60 min idle), so it
90
90
  * is `stale` WITHOUT userMustAct;
91
- * · antigravity `expired-token` — the daemon deliberately does not redeem
92
- * the refresh token. Kimi's expired-token is NOT here: its CLI refreshes
93
- * the token on its own cadence.
91
+ * · `expired-token` on Grok/Kimi/antigravity — only the owning CLI
92
+ * renews it on use. An idle CLI has no background renewal cadence.
93
+ * A scheduled quota retry does not itself renew credentials.
94
94
  * - `refreshing` — retained numbers after a transient failure with a retry
95
95
  * actually pending. ★Honest about the end of the retry budget: once the
96
96
  * daemon has stopped retrying (`metadata.retryExhausted`, or `retryAtMs`
@@ -103,12 +103,20 @@ export function assessQuotaFreshness(quota: MeshNodeFactsProviderQuota, now: num
103
103
  const meta = quota.metadata
104
104
  const kind = meta?.failureKind
105
105
  const userMustAct = (kind === 'no-data' && quota.provider !== 'codex-cli')
106
- || (kind === 'expired-token' && quota.provider === 'antigravity-cli')
106
+ || (kind === 'expired-token' && ['grok-cli', 'kimi', 'antigravity-cli'].includes(quota.provider))
107
107
  // Order matters: the aged-out Claude shape and the retained antigravity
108
108
  // shape both ALSO mark lastGoodWindows (mesh routing trusts retained numbers
109
109
  // until their reset), so they must be classified before the generic branch.
110
- if (userMustAct && hasReading(quota)) return { cue: 'stale', userMustAct: true }
111
- if (meta?.lastGoodWindows !== true) return { userMustAct }
110
+ if (userMustAct) return hasReading(quota) ? { cue: 'stale', userMustAct: true } : { userMustAct: true }
111
+ if (meta?.lastGoodWindows !== true) {
112
+ // A successful fetch is not a perpetual live reading. Use the DATA
113
+ // clock; a recent failed attempt must never rejuvenate old numbers.
114
+ const measuredAt = finiteMs(quota.updatedAt)
115
+ if (hasReading(quota) && (measuredAt === undefined || now - measuredAt >= QUOTA_BACKFILL_HORIZON_MS)) {
116
+ return { cue: 'stale', userMustAct }
117
+ }
118
+ return { userMustAct }
119
+ }
112
120
 
113
121
  const retryAtMs = finiteMs(meta?.retryAtMs)
114
122
  const retryStopped = meta?.retryExhausted === true