@adhdev/mesh-shared 1.0.82-rc.35 → 1.0.82-rc.37

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.
@@ -20,6 +20,8 @@ export interface LaunchDefaultEntry extends LaunchDefaultSelection {
20
20
  revision: number;
21
21
  setBy: 'owner' | 'assistant';
22
22
  setAt: number;
23
+ /** Ordered quota-failover alternatives (<= 3, distinct providers). Absent = none. */
24
+ fallback?: LaunchDefaultSelection[];
23
25
  }
24
26
  export interface LaunchDefaultChange {
25
27
  at: number;
@@ -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_queue_revise", "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_reattach_source_parent", "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", "driver_list", "driver_describe", "artifact_list", "artifact_read", "artifact_register"];
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_direct_cancel", "mesh_queue_requeue", "mesh_queue_revise", "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_reattach_source_parent", "mesh_attach_remote", "mesh_clone_node", "mesh_remove_node", "mesh_retry_node_bootstrap", "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_mission_git_eval", "mesh_release_upsert", "mesh_release_scope", "mesh_release_list", "mesh_release_record_deploy", "mesh_release_changelog_draft", "mesh_review_inbox", "mesh_node_slots", "driver_list", "driver_describe", "artifact_list", "artifact_read", "artifact_register"];
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: 48;
24
+ export declare const CANONICAL_MESH_TOOL_COUNT: 56;
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
@@ -0,0 +1,83 @@
1
+ /**
2
+ * mission-git-state — types and the pure aggregation for "did this mission's
3
+ * referenced commits/branches land on the default branch?"
4
+ * (docs/design/2026-11-01-mission-git-refs.md §3).
5
+ *
6
+ * The facts come from the daemon opening git objects itself (never from
7
+ * commit-message text, branch-name similarity or worker prose). `landed` means
8
+ * ONLY "the referenced changes are on the base"; it never implies live
9
+ * acceptance, mission completion or that remaining items are done, and it is
10
+ * never used to change a mission's status.
11
+ *
12
+ * Dependency-free leaf: plain data in, plain data out.
13
+ */
14
+ /** Per-ref verdict. `unknown` is never folded into `not_contained` nor promoted to `contained_*`. */
15
+ export declare const MISSION_REF_GIT_STATUSES: readonly ["contained_ancestor", "contained_patch_equivalent", "not_contained", "unknown"];
16
+ export type MissionRefGitStatus = typeof MISSION_REF_GIT_STATUSES[number];
17
+ /** How a contained verdict was reached. */
18
+ export declare const MISSION_REF_GIT_METHODS: readonly ["ancestry", "cherry", "residual_patch"];
19
+ export type MissionRefGitMethod = typeof MISSION_REF_GIT_METHODS[number];
20
+ /** Mission-level projection. */
21
+ export declare const MISSION_GIT_STATES: readonly ["no_refs", "landed", "partial", "not_landed", "unknown"];
22
+ export type MissionGitStateValue = typeof MISSION_GIT_STATES[number];
23
+ export declare function isMissionRefContained(status: MissionRefGitStatus): boolean;
24
+ /** Why a ref is `unknown` (detail.unknownReason). Free-form strings are tolerated on read. */
25
+ export type MissionRefUnknownReason = 'object_missing' | 'shallow' | 'undeterminable' | 'base_missing' | 'branch_not_found' | 'base_branch_ref' | 'gitlink_undeterminable' | 'merge_tree_failed' | 'node_offline' | 'no_repo' | 'budget' | 'not_a_git_ref';
26
+ export interface MissionRefGitDetail {
27
+ reasonCode?: string;
28
+ unknownReason?: MissionRefUnknownReason | string;
29
+ /** `modified_since_landing_possible`: main later touched the same lines — shown as a hint, not a verdict. */
30
+ note?: string;
31
+ nodeId?: string;
32
+ residualPatchId?: string;
33
+ ahead?: number;
34
+ behind?: number;
35
+ }
36
+ /** One stored per-ref evaluation (a row of `mesh_mission_ref_evals`). */
37
+ export interface MissionRefGitEval {
38
+ itemId: string;
39
+ /** `kind:repo:value` (normalized, lower-case SHA). */
40
+ refKey: string;
41
+ kind: 'commit' | 'branch';
42
+ value: string;
43
+ repo?: string;
44
+ /** Branch refs: the SHA the name resolved to at first evaluation (re-evaluation keeps using it). */
45
+ pinnedSha?: string;
46
+ baseRef: string;
47
+ baseSha?: string;
48
+ status: MissionRefGitStatus;
49
+ method?: MissionRefGitMethod;
50
+ detail?: MissionRefGitDetail;
51
+ evaluatedAt: string;
52
+ }
53
+ export interface MissionGitState {
54
+ missionId: string;
55
+ state: MissionGitStateValue;
56
+ /** `partial` only: some refs were `unknown` (not just `not_contained`). */
57
+ partialUnknown: boolean;
58
+ counts: {
59
+ total: number;
60
+ contained: number;
61
+ notContained: number;
62
+ unknown: number;
63
+ };
64
+ /** Base the newest evaluation compared against. */
65
+ baseRef?: string;
66
+ baseSha?: string;
67
+ /** Oldest `evaluatedAt` among the refs (the freshness floor). */
68
+ evaluatedAt?: string;
69
+ /** True when no row exists yet / the rows are older than the TTL — a refresh was (or can be) triggered. */
70
+ stale: boolean;
71
+ refs: MissionRefGitEval[];
72
+ }
73
+ /**
74
+ * Aggregate per-ref statuses (design §3.3):
75
+ * - none → `no_refs`; all contained → `landed`; some contained → `partial`
76
+ * (`partialUnknown` when any of the rest is `unknown`);
77
+ * - none contained: all `not_contained` → `not_landed`, otherwise `unknown`.
78
+ */
79
+ export declare function aggregateMissionGitState(statuses: readonly MissionRefGitStatus[]): {
80
+ state: MissionGitStateValue;
81
+ partialUnknown: boolean;
82
+ counts: MissionGitState['counts'];
83
+ };
@@ -14,9 +14,9 @@
14
14
  */
15
15
  export declare const MISSION_ITEM_KINDS: readonly ["remaining", "live_check", "decision", "evidence"];
16
16
  export type MissionItemKind = typeof MISSION_ITEM_KINDS[number];
17
- export declare const MISSION_ITEM_STATES: readonly ["open", "done", "dropped", "moved", "answered", "expired", "withdrawn", "superseded"];
17
+ export declare const MISSION_ITEM_STATES: readonly ["open", "done", "failed", "dropped", "moved", "answered", "expired", "withdrawn", "superseded"];
18
18
  export type MissionItemState = typeof MISSION_ITEM_STATES[number];
19
- /** States a coordinator/worker may SET through items_update, per kind. `answered`/`expired` are daemon-owned. */
19
+ /** States a coordinator/worker may SET through items_update, per kind. `answered`/`expired`/`failed` (owner live-check verdict) are daemon-owned. */
20
20
  export declare const COORDINATOR_SETTABLE_ITEM_STATES: Readonly<Record<MissionItemKind, readonly MissionItemState[]>>;
21
21
  export declare const MISSION_OUTCOMES: readonly ["merged", "verified_live", "superseded", "not_needed", "owner_abandoned", "unspecified"];
22
22
  export type MissionOutcome = typeof MISSION_OUTCOMES[number];
@@ -234,6 +234,24 @@ export interface MeshNodeFacts {
234
234
  * Booleans keyed by provider type only — no free text, no credentials.
235
235
  */
236
236
  providerEnablement?: Record<string, MeshNodeFactsProviderEnablement>;
237
+ /**
238
+ * The reporting machine's stored quota RESERVE (daemon-core
239
+ * `ADHDevConfig.quotaReserve`, sparse, ≤ 2 KB, migration audit trail
240
+ * stripped): the "how much quota to leave for the person" bar that the
241
+ * coordinator's launch gate applies to THIS machine's snapshots.
242
+ * ★ABSENT means "this node did not tell us" (older daemon) and resolves to
243
+ * the code defaults — the same fail-open direction as before the field
244
+ * existed. Percentages, durations and hashed account keys only; no free
245
+ * text, no emails. Resolve with daemon-core `resolveQuotaReserve`; never
246
+ * read its fields directly.
247
+ */
248
+ quotaReserve?: {
249
+ version: 1;
250
+ defaults?: Record<string, number>;
251
+ pools?: Record<string, Record<string, number>>;
252
+ accounts?: Record<string, Record<string, Record<string, number>>>;
253
+ updatedAt?: string;
254
+ };
237
255
  /** Future fields ride through opaquely — do not enumerate them in relays. */
238
256
  [extra: string]: unknown;
239
257
  }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * release — types, limits and pure helpers for release objects
3
+ * (docs/design/2026-11-01-release-objects.md).
4
+ *
5
+ * A release is a mesh-scoped entity that groups MISSIONS (explicit membership) and records
6
+ * deploy facts. It is distinct from the vendor release stamp (a build channel stamp) and
7
+ * from `.adhdev/preview-deploy.json` (the per-checkout deploy record it snapshots).
8
+ * Membership is only ever created by an explicit call; git evaluation and deploy heads
9
+ * produce suggestions, never members. Dependency-free leaf.
10
+ */
11
+ export declare const MESH_RELEASE_CHANNELS: readonly ["preview", "stable"];
12
+ export type MeshReleaseChannel = typeof MESH_RELEASE_CHANNELS[number];
13
+ export declare function isMeshReleaseChannel(value: unknown): value is MeshReleaseChannel;
14
+ export declare const MESH_RELEASE_STATUSES: readonly ["planned", "frozen", "deployed", "verified", "superseded", "cancelled"];
15
+ export type ReleaseStatus = typeof MESH_RELEASE_STATUSES[number];
16
+ export declare function isReleaseStatus(value: unknown): value is ReleaseStatus;
17
+ export declare const RELEASE_MEMBER_STATES: readonly ["member", "moved_out", "removed"];
18
+ export type ReleaseMemberState = typeof RELEASE_MEMBER_STATES[number];
19
+ /** Who may write release membership. The daemon never adds a member on its own. */
20
+ export declare const RELEASE_ACTORS: readonly ["coordinator", "owner", "assistant", "script"];
21
+ export type ReleaseActor = typeof RELEASE_ACTORS[number];
22
+ export declare const RELEASE_EVENT_TYPES: readonly ["created", "status_changed", "scope_added", "scope_moved", "scope_removed", "deploy_recorded", "changelog_drafted", "changelog_applied"];
23
+ export type ReleaseEventType = typeof RELEASE_EVENT_TYPES[number];
24
+ /** Mission-side events recorded when membership changes (so the mission history shows it). */
25
+ export declare const MISSION_RELEASE_EVENT_TYPES: readonly ["release_attached", "release_moved", "release_detached"];
26
+ export declare const RELEASE_LIMITS: {
27
+ readonly name: 80;
28
+ readonly note: 500;
29
+ /** `mesh_missions.release_note`: one user/operator-visible sentence. */
30
+ readonly releaseNote: 400;
31
+ readonly missionsPerCall: 100;
32
+ readonly changelogEntries: 300;
33
+ };
34
+ /** Deploy targets snapshot (a copy of `.adhdev/preview-deploy.json` `targets`). */
35
+ export interface ReleaseDeployTarget {
36
+ commit?: string;
37
+ deployedAt?: string;
38
+ previewVersion?: string;
39
+ [key: string]: unknown;
40
+ }
41
+ export type ReleaseTargets = Partial<Record<'npm' | 'server' | 'web', ReleaseDeployTarget>> & Record<string, ReleaseDeployTarget | undefined>;
42
+ export declare const CHANGELOG_SECTIONS: readonly ["Added", "Fixed", "Changed"];
43
+ export type ChangelogSection = typeof CHANGELOG_SECTIONS[number];
44
+ export interface ChangelogDraftEntry {
45
+ missionId: string;
46
+ /** `<!-- m:<id8> -->` — the idempotency marker `--apply` writes after the line. */
47
+ marker: string;
48
+ section: ChangelogSection;
49
+ /** The sentence that would be written to CHANGELOG.md. */
50
+ text: string;
51
+ source: 'release_note' | 'summary';
52
+ /** True when `text` is not user-facing wording yet (carries the needs-wording marker). */
53
+ needsWording?: boolean;
54
+ /** Evidence kept in the draft JSON only; never written to CHANGELOG.md. */
55
+ evidence?: {
56
+ gitState?: string;
57
+ outcome?: string;
58
+ shas?: string[];
59
+ };
60
+ /** Non-blocking lint warnings (internal ids / wave numbers / forbidden phrases). */
61
+ lint?: string[];
62
+ }
63
+ export interface ChangelogDraftExcluded {
64
+ missionId: string;
65
+ reason: string;
66
+ }
67
+ export interface ChangelogDraft {
68
+ generatedAt: string;
69
+ entries: ChangelogDraftEntry[];
70
+ /** Member missions without a `release_note` (target 0 at deploy time). */
71
+ needsNote: string[];
72
+ excluded: ChangelogDraftExcluded[];
73
+ /** Member missions whose refs are not confirmed on the default branch (`not_landed` / `unknown`). */
74
+ warnings: Array<{
75
+ missionId: string;
76
+ gitState: string;
77
+ message: string;
78
+ }>;
79
+ appliedAt?: string;
80
+ }
81
+ export declare const NEEDS_WORDING_MARKER = "[needs user-facing wording]";
82
+ /** Marker that makes `--apply` idempotent: one per mission entry inside CHANGELOG.md. */
83
+ export declare function changelogMissionMarker(missionId: string): string;
84
+ /** Default section for an entry; `[Fixed]`/`[Added]`/`[Changed]` prefixes on the note pin it. */
85
+ export declare function classifyChangelogSection(text: string, hint?: string): {
86
+ section: ChangelogSection;
87
+ text: string;
88
+ };
89
+ /** Phrases that must not reach a public CHANGELOG (internal waves, rc numbering, ids). Warning-only. */
90
+ export declare function lintChangelogText(text: string): string[];
@@ -41,6 +41,13 @@ export interface ModelSelection {
41
41
  /** Last value the provider itself reported (statusline, native history). */
42
42
  observed?: string;
43
43
  observedAt?: number;
44
+ /**
45
+ * The provider SILENTLY substituted another model for the requested one
46
+ * (antigravity: `model X is not recognized … Using "Y" instead`). `observed`
47
+ * then holds the model actually running. P2P/launch-record only — the
48
+ * server path never carries it (see the content boundary above).
49
+ */
50
+ fallback?: boolean;
44
51
  /** Every value change in order. The last entry is the value in force. */
45
52
  history: ModelSelectionHistoryEntry[];
46
53
  }
@@ -39,6 +39,8 @@ export interface MissionUpsertRequest {
39
39
  */
40
40
  structured?: boolean;
41
41
  summary?: string;
42
+ /** One user/operator-visible sentence for the release CHANGELOG draft (design 2026-11-01-release-objects L5). `''` clears. */
43
+ releaseNote?: string;
42
44
  outcome?: string;
43
45
  outcomeReason?: string;
44
46
  /** Mission id open items move to when this call closes the mission (default: the carry-over mission). */
@@ -57,6 +59,7 @@ export interface MeshMissionOpenItemCountsWire {
57
59
  /** Structured-missions fields (only with `structured: true` on the request). */
58
60
  export interface MeshMissionStructuredWire {
59
61
  summary?: string;
62
+ releaseNote?: string;
60
63
  outcome?: string;
61
64
  outcomeReason?: string;
62
65
  version?: number;
@@ -157,6 +160,7 @@ export interface MissionListSummaryVerboseWire {
157
160
  closeCandidateEmittedAt?: string | null;
158
161
  /** Structured lists only. */
159
162
  summary?: string;
163
+ releaseNote?: string;
160
164
  outcome?: string;
161
165
  outcomeReason?: string;
162
166
  version?: number;
@@ -183,6 +187,7 @@ export interface MissionListSummarySlimWire {
183
187
  closeCandidateEmittedAt?: string | null;
184
188
  /** Structured lists only. */
185
189
  summary?: string;
190
+ releaseNote?: string;
186
191
  outcome?: string;
187
192
  outcomeReason?: string;
188
193
  version?: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/mesh-shared",
3
- "version": "1.0.82-rc.35",
3
+ "version": "1.0.82-rc.37",
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",
@@ -27,6 +27,7 @@ export const ASSISTANT_TOOLS = [
27
27
  'project_attach_remote',
28
28
  'discover_repos',
29
29
  'memory',
30
+ 'memory_search',
30
31
  'skill_view',
31
32
  'skill_manage',
32
33
  'project_note',
@@ -38,6 +39,7 @@ export const ASSISTANT_TOOLS = [
38
39
  'artifact_read',
39
40
  'decision_answer',
40
41
  'decision_request',
42
+ 'session_control',
41
43
  ] as const
42
44
 
43
45
  export type AssistantTool = typeof ASSISTANT_TOOLS[number]
@@ -66,6 +68,8 @@ export const ASSISTANT_VERB = {
66
68
  projectAttachRemote: 'assistant_project_attach_remote',
67
69
  discoverRepos: 'assistant_discover_repos',
68
70
  memory: 'assistant_memory',
71
+ /** Pull-only FTS search over the archive tier (memory design 2026-11-01 §3.4). */
72
+ memorySearch: 'assistant_memory_search',
69
73
  skillView: 'assistant_skill_view',
70
74
  skillManage: 'assistant_skill_manage',
71
75
  projectNote: 'assistant_project_note',
@@ -77,6 +81,8 @@ export const ASSISTANT_VERB = {
77
81
  decisionAnswer: 'assistant_decision_answer',
78
82
  /** Register a plain-text question a coordinator put to the owner as a decision item (§5.2). */
79
83
  decisionRequest: 'assistant_decision_request',
84
+ /** Stop / restart / switch the provider of a coordinator, worker or the assistant session (handoff design 2026-11-01 §4). */
85
+ sessionControl: 'assistant_session_control',
80
86
  // assistant-side daemon verbs without a tool of the same name
81
87
  launch: 'launch_assistant',
82
88
  pendingRelays: 'assistant_pending_relays',
@@ -84,6 +90,12 @@ export const ASSISTANT_VERB = {
84
90
  stagedResolve: 'assistant_staged_resolve',
85
91
  storeAdmin: 'assistant_store_admin',
86
92
  importSkills: 'assistant_import_skills',
93
+ /** Owner skill list (attach/view counts, save proposals, recent skill metrics); reads move no counter. */
94
+ skillsList: 'assistant_skills_list',
95
+ /** Owner: what the assistant remembered recently, with undo handles (memory design §3.2). */
96
+ memoryDigest: 'assistant_memory_digest',
97
+ /** Owner: reverse one remembered write or one batch (memory design §3.2). Never an assistant tool. */
98
+ memoryUndo: 'assistant_memory_undo',
87
99
  /** Projects the assistant is following (open relay threads) — list / stop following. */
88
100
  threads: 'assistant_threads',
89
101
  threadClose: 'assistant_thread_close',
@@ -106,6 +118,7 @@ export const ASSISTANT_TOOL_VERBS: Readonly<Record<AssistantTool, AssistantVerb>
106
118
  project_attach_remote: ASSISTANT_VERB.projectAttachRemote,
107
119
  discover_repos: ASSISTANT_VERB.discoverRepos,
108
120
  memory: ASSISTANT_VERB.memory,
121
+ memory_search: ASSISTANT_VERB.memorySearch,
109
122
  skill_view: ASSISTANT_VERB.skillView,
110
123
  skill_manage: ASSISTANT_VERB.skillManage,
111
124
  project_note: ASSISTANT_VERB.projectNote,
@@ -115,6 +128,7 @@ export const ASSISTANT_TOOL_VERBS: Readonly<Record<AssistantTool, AssistantVerb>
115
128
  artifact_read: ASSISTANT_VERB.artifactRead,
116
129
  decision_answer: ASSISTANT_VERB.decisionAnswer,
117
130
  decision_request: ASSISTANT_VERB.decisionRequest,
131
+ session_control: ASSISTANT_VERB.sessionControl,
118
132
  }
119
133
 
120
134
  /**
@@ -123,7 +137,7 @@ export const ASSISTANT_TOOL_VERBS: Readonly<Record<AssistantTool, AssistantVerb>
123
137
  * because they cause effects (a coordinator message or launch, a new
124
138
  * project), and MCP clients use readOnlyHint to skip confirmation.
125
139
  */
126
- 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', 'decision_answer', 'decision_request']
140
+ 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', 'decision_answer', 'decision_request', 'session_control']
127
141
 
128
142
  /** Owner-only verbs: never reachable from the assistant's MCP server (no `ipc`). */
129
143
  export const ASSISTANT_OWNER_VERBS: readonly AssistantVerb[] = [
@@ -131,12 +145,16 @@ export const ASSISTANT_OWNER_VERBS: readonly AssistantVerb[] = [
131
145
  ASSISTANT_VERB.stagedResolve,
132
146
  ASSISTANT_VERB.storeAdmin,
133
147
  ASSISTANT_VERB.importSkills,
148
+ ASSISTANT_VERB.skillsList,
149
+ ASSISTANT_VERB.memoryDigest,
150
+ ASSISTANT_VERB.memoryUndo,
134
151
  ASSISTANT_VERB.threadClose,
135
152
  ]
136
153
 
137
154
  /** The only assistant verbs accepted while an idle review turn is open (§4.10.7). */
138
155
  export const ASSISTANT_REVIEW_TURN_VERBS: readonly AssistantVerb[] = [
139
156
  ASSISTANT_VERB.memory,
157
+ ASSISTANT_VERB.memorySearch,
140
158
  ASSISTANT_VERB.skillView,
141
159
  ASSISTANT_VERB.skillManage,
142
160
  ASSISTANT_VERB.projectNote,
package/src/index.ts CHANGED
@@ -42,6 +42,8 @@ export * from './turn-ipc'
42
42
  export * from './path-ownership'
43
43
  export * from './mission-brief'
44
44
  export * from './mission-items'
45
+ export * from './mission-git-state'
46
+ export * from './release'
45
47
  export * from './decision-push-relay'
46
48
  export * from './keyed-doc-delta'
47
49
  export * from './provider-approval'
@@ -24,6 +24,8 @@ export interface LaunchDefaultEntry extends LaunchDefaultSelection {
24
24
  revision: number;
25
25
  setBy: 'owner' | 'assistant';
26
26
  setAt: number;
27
+ /** Ordered quota-failover alternatives (<= 3, distinct providers). Absent = none. */
28
+ fallback?: LaunchDefaultSelection[];
27
29
  }
28
30
  export interface LaunchDefaultChange {
29
31
  at: number;
@@ -27,6 +27,7 @@ export const CANONICAL_MESH_TOOL_NAMES = [
27
27
  'mesh_enqueue_task',
28
28
  'mesh_view_queue',
29
29
  'mesh_queue_cancel',
30
+ 'mesh_direct_cancel',
30
31
  'mesh_queue_requeue',
31
32
  'mesh_queue_revise',
32
33
  'mesh_send_task',
@@ -49,6 +50,7 @@ export const CANONICAL_MESH_TOOL_NAMES = [
49
50
  'mesh_attach_remote',
50
51
  'mesh_clone_node',
51
52
  'mesh_remove_node',
53
+ 'mesh_retry_node_bootstrap',
52
54
  'mesh_cleanup_worktree_nodes',
53
55
  'mesh_refine_node',
54
56
  'mesh_refine_batch',
@@ -65,6 +67,12 @@ export const CANONICAL_MESH_TOOL_NAMES = [
65
67
  'mesh_reconcile_ledger',
66
68
  'mesh_mission_upsert',
67
69
  'mesh_mission_list',
70
+ 'mesh_mission_git_eval',
71
+ 'mesh_release_upsert',
72
+ 'mesh_release_scope',
73
+ 'mesh_release_list',
74
+ 'mesh_release_record_deploy',
75
+ 'mesh_release_changelog_draft',
68
76
  'mesh_review_inbox',
69
77
  'mesh_node_slots',
70
78
  'driver_list',
@@ -0,0 +1,112 @@
1
+ /**
2
+ * mission-git-state — types and the pure aggregation for "did this mission's
3
+ * referenced commits/branches land on the default branch?"
4
+ * (docs/design/2026-11-01-mission-git-refs.md §3).
5
+ *
6
+ * The facts come from the daemon opening git objects itself (never from
7
+ * commit-message text, branch-name similarity or worker prose). `landed` means
8
+ * ONLY "the referenced changes are on the base"; it never implies live
9
+ * acceptance, mission completion or that remaining items are done, and it is
10
+ * never used to change a mission's status.
11
+ *
12
+ * Dependency-free leaf: plain data in, plain data out.
13
+ */
14
+
15
+ /** Per-ref verdict. `unknown` is never folded into `not_contained` nor promoted to `contained_*`. */
16
+ export const MISSION_REF_GIT_STATUSES = ['contained_ancestor', 'contained_patch_equivalent', 'not_contained', 'unknown'] as const
17
+ export type MissionRefGitStatus = typeof MISSION_REF_GIT_STATUSES[number]
18
+
19
+ /** How a contained verdict was reached. */
20
+ export const MISSION_REF_GIT_METHODS = ['ancestry', 'cherry', 'residual_patch'] as const
21
+ export type MissionRefGitMethod = typeof MISSION_REF_GIT_METHODS[number]
22
+
23
+ /** Mission-level projection. */
24
+ export const MISSION_GIT_STATES = ['no_refs', 'landed', 'partial', 'not_landed', 'unknown'] as const
25
+ export type MissionGitStateValue = typeof MISSION_GIT_STATES[number]
26
+
27
+ export function isMissionRefContained(status: MissionRefGitStatus): boolean {
28
+ return status === 'contained_ancestor' || status === 'contained_patch_equivalent'
29
+ }
30
+
31
+ /** Why a ref is `unknown` (detail.unknownReason). Free-form strings are tolerated on read. */
32
+ export type MissionRefUnknownReason =
33
+ | 'object_missing'
34
+ | 'shallow'
35
+ | 'undeterminable'
36
+ | 'base_missing'
37
+ | 'branch_not_found'
38
+ | 'base_branch_ref'
39
+ | 'gitlink_undeterminable'
40
+ | 'merge_tree_failed'
41
+ | 'node_offline'
42
+ | 'no_repo'
43
+ | 'budget'
44
+ | 'not_a_git_ref'
45
+
46
+ export interface MissionRefGitDetail {
47
+ reasonCode?: string
48
+ unknownReason?: MissionRefUnknownReason | string
49
+ /** `modified_since_landing_possible`: main later touched the same lines — shown as a hint, not a verdict. */
50
+ note?: string
51
+ nodeId?: string
52
+ residualPatchId?: string
53
+ ahead?: number
54
+ behind?: number
55
+ }
56
+
57
+ /** One stored per-ref evaluation (a row of `mesh_mission_ref_evals`). */
58
+ export interface MissionRefGitEval {
59
+ itemId: string
60
+ /** `kind:repo:value` (normalized, lower-case SHA). */
61
+ refKey: string
62
+ kind: 'commit' | 'branch'
63
+ value: string
64
+ repo?: string
65
+ /** Branch refs: the SHA the name resolved to at first evaluation (re-evaluation keeps using it). */
66
+ pinnedSha?: string
67
+ baseRef: string
68
+ baseSha?: string
69
+ status: MissionRefGitStatus
70
+ method?: MissionRefGitMethod
71
+ detail?: MissionRefGitDetail
72
+ evaluatedAt: string
73
+ }
74
+
75
+ export interface MissionGitState {
76
+ missionId: string
77
+ state: MissionGitStateValue
78
+ /** `partial` only: some refs were `unknown` (not just `not_contained`). */
79
+ partialUnknown: boolean
80
+ counts: { total: number; contained: number; notContained: number; unknown: number }
81
+ /** Base the newest evaluation compared against. */
82
+ baseRef?: string
83
+ baseSha?: string
84
+ /** Oldest `evaluatedAt` among the refs (the freshness floor). */
85
+ evaluatedAt?: string
86
+ /** True when no row exists yet / the rows are older than the TTL — a refresh was (or can be) triggered. */
87
+ stale: boolean
88
+ refs: MissionRefGitEval[]
89
+ }
90
+
91
+ /**
92
+ * Aggregate per-ref statuses (design §3.3):
93
+ * - none → `no_refs`; all contained → `landed`; some contained → `partial`
94
+ * (`partialUnknown` when any of the rest is `unknown`);
95
+ * - none contained: all `not_contained` → `not_landed`, otherwise `unknown`.
96
+ */
97
+ export function aggregateMissionGitState(statuses: readonly MissionRefGitStatus[]): {
98
+ state: MissionGitStateValue
99
+ partialUnknown: boolean
100
+ counts: MissionGitState['counts']
101
+ } {
102
+ const total = statuses.length
103
+ const contained = statuses.filter(isMissionRefContained).length
104
+ const notContained = statuses.filter(s => s === 'not_contained').length
105
+ const unknown = statuses.filter(s => s === 'unknown').length
106
+ const counts = { total, contained, notContained, unknown }
107
+ if (total === 0) return { state: 'no_refs', partialUnknown: false, counts }
108
+ if (contained === total) return { state: 'landed', partialUnknown: false, counts }
109
+ if (contained > 0) return { state: 'partial', partialUnknown: unknown > 0, counts }
110
+ if (notContained === total) return { state: 'not_landed', partialUnknown: false, counts }
111
+ return { state: 'unknown', partialUnknown: false, counts }
112
+ }
@@ -16,10 +16,10 @@
16
16
  export const MISSION_ITEM_KINDS = ['remaining', 'live_check', 'decision', 'evidence'] as const
17
17
  export type MissionItemKind = typeof MISSION_ITEM_KINDS[number]
18
18
 
19
- export const MISSION_ITEM_STATES = ['open', 'done', 'dropped', 'moved', 'answered', 'expired', 'withdrawn', 'superseded'] as const
19
+ export const MISSION_ITEM_STATES = ['open', 'done', 'failed', 'dropped', 'moved', 'answered', 'expired', 'withdrawn', 'superseded'] as const
20
20
  export type MissionItemState = typeof MISSION_ITEM_STATES[number]
21
21
 
22
- /** States a coordinator/worker may SET through items_update, per kind. `answered`/`expired` are daemon-owned. */
22
+ /** States a coordinator/worker may SET through items_update, per kind. `answered`/`expired`/`failed` (owner live-check verdict) are daemon-owned. */
23
23
  export const COORDINATOR_SETTABLE_ITEM_STATES: Readonly<Record<MissionItemKind, readonly MissionItemState[]>> = {
24
24
  remaining: ['open', 'done', 'dropped'],
25
25
  live_check: ['open', 'done', 'dropped'],
package/src/node-facts.ts CHANGED
@@ -234,6 +234,24 @@ export interface MeshNodeFacts {
234
234
  * Booleans keyed by provider type only — no free text, no credentials.
235
235
  */
236
236
  providerEnablement?: Record<string, MeshNodeFactsProviderEnablement>
237
+ /**
238
+ * The reporting machine's stored quota RESERVE (daemon-core
239
+ * `ADHDevConfig.quotaReserve`, sparse, ≤ 2 KB, migration audit trail
240
+ * stripped): the "how much quota to leave for the person" bar that the
241
+ * coordinator's launch gate applies to THIS machine's snapshots.
242
+ * ★ABSENT means "this node did not tell us" (older daemon) and resolves to
243
+ * the code defaults — the same fail-open direction as before the field
244
+ * existed. Percentages, durations and hashed account keys only; no free
245
+ * text, no emails. Resolve with daemon-core `resolveQuotaReserve`; never
246
+ * read its fields directly.
247
+ */
248
+ quotaReserve?: {
249
+ version: 1
250
+ defaults?: Record<string, number>
251
+ pools?: Record<string, Record<string, number>>
252
+ accounts?: Record<string, Record<string, Record<string, number>>>
253
+ updatedAt?: string
254
+ }
237
255
  /** Future fields ride through opaquely — do not enumerate them in relays. */
238
256
  [extra: string]: unknown
239
257
  }