@adhdev/mesh-shared 1.0.82-rc.34 → 1.0.82-rc.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assistant-protocol.d.ts +7 -2
- package/dist/decision-push-relay.d.ts +20 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +425 -11
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +388 -11
- package/dist/index.mjs.map +1 -1
- package/dist/mission-items.d.ts +202 -0
- package/dist/protocol/daemon-server.d.ts +27 -2
- package/dist/protocol/dashboard-server.d.ts +2 -2
- package/dist/session-launch.d.ts +7 -0
- package/dist/turn-ipc-mission.d.ts +59 -1
- package/dist/worker-protocol.d.ts +1 -1
- package/package.json +1 -1
- package/src/assistant-protocol.ts +29 -2
- package/src/decision-push-relay.ts +23 -0
- package/src/index.ts +2 -0
- package/src/mission-items.ts +421 -0
- package/src/protocol/daemon-server.ts +26 -0
- package/src/session-launch.ts +9 -0
- package/src/turn-ipc-mission.ts +108 -9
- package/src/worker-protocol.ts +4 -0
package/src/turn-ipc-mission.ts
CHANGED
|
@@ -85,9 +85,43 @@ export interface MissionUpsertRequest {
|
|
|
85
85
|
* this wire guard only checks SHAPE, not that decision.
|
|
86
86
|
*/
|
|
87
87
|
brief?: MissionBriefWire | null
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
/**
|
|
89
|
+
* Structured-missions bundle A (design 2026-10-28 §5.1). Every key below is optional
|
|
90
|
+
* and ABSENT on a legacy call. `structured: true` is the caller's capability flag: the
|
|
91
|
+
* daemon only puts the new keys on the response (mission summary/outcome/version,
|
|
92
|
+
* `result`) when it is set, so an older mcp-server that never sends it keeps decoding
|
|
93
|
+
* byte-identical responses (mixed-version fleets, design §13.1).
|
|
94
|
+
*/
|
|
95
|
+
structured?: boolean
|
|
96
|
+
summary?: string
|
|
97
|
+
outcome?: string
|
|
98
|
+
outcomeReason?: string
|
|
99
|
+
/** Mission id open items move to when this call closes the mission (default: the carry-over mission). */
|
|
100
|
+
carryOverTo?: string
|
|
101
|
+
/** Route to the mesh's auto-created carry-over mission instead of `id`/`title` (decision requests without a mission). `title` may then be empty. */
|
|
102
|
+
toCarryOver?: boolean
|
|
103
|
+
itemsAdd?: readonly Record<string, unknown>[]
|
|
104
|
+
itemsUpdate?: readonly Record<string, unknown>[]
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface MeshMissionOpenItemCountsWire {
|
|
108
|
+
remaining: number
|
|
109
|
+
live_check: number
|
|
110
|
+
decision: number
|
|
111
|
+
evidence: number
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Structured-missions fields (only with `structured: true` on the request). */
|
|
115
|
+
export interface MeshMissionStructuredWire {
|
|
116
|
+
summary?: string
|
|
117
|
+
outcome?: string
|
|
118
|
+
outcomeReason?: string
|
|
119
|
+
version?: number
|
|
120
|
+
carryOver?: boolean
|
|
121
|
+
openItems?: MeshMissionOpenItemCountsWire
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface MeshMissionRecordWire extends MeshMissionStructuredWire {
|
|
91
125
|
id: string
|
|
92
126
|
meshId: string
|
|
93
127
|
title: string
|
|
@@ -99,10 +133,30 @@ export interface MeshMissionRecordWire {
|
|
|
99
133
|
|
|
100
134
|
export interface MissionUpsertResponse {
|
|
101
135
|
mission: MeshMissionRecordWire
|
|
136
|
+
/** Structured calls only: per-item results, movedItems/movedTo, restoredItems, ownerConfirmationItemId, warnings. */
|
|
137
|
+
result?: Record<string, unknown>
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const STRUCTURED_MISSION_KEYS = ['summary', 'outcome', 'outcomeReason', 'version', 'carryOver', 'openItems'] as const
|
|
141
|
+
|
|
142
|
+
function isOpenItemCountsWire(value: unknown): value is MeshMissionOpenItemCountsWire {
|
|
143
|
+
if (!isRecord(value) || !hasOnlyKeys(value, ['remaining', 'live_check', 'decision', 'evidence'])) return false
|
|
144
|
+
return (['remaining', 'live_check', 'decision', 'evidence'] as const).every((k) => isNonNegativeInt(value[k]))
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function isStructuredMissionFields(value: Record<string, unknown>): boolean {
|
|
148
|
+
for (const k of ['summary', 'outcome', 'outcomeReason'] as const) {
|
|
149
|
+
if (value[k] !== undefined && typeof value[k] !== 'string') return false
|
|
150
|
+
}
|
|
151
|
+
if (value.version !== undefined && !isNonNegativeInt(value.version)) return false
|
|
152
|
+
if (value.carryOver !== undefined && typeof value.carryOver !== 'boolean') return false
|
|
153
|
+
if (value.openItems !== undefined && !isOpenItemCountsWire(value.openItems)) return false
|
|
154
|
+
return true
|
|
102
155
|
}
|
|
103
156
|
|
|
104
157
|
function isMeshMissionRecordWire(value: unknown): value is MeshMissionRecordWire {
|
|
105
|
-
if (!isRecord(value) || !hasOnlyKeys(value, ['id', 'meshId', 'title', 'goal', 'status', 'brief'])) return false
|
|
158
|
+
if (!isRecord(value) || !hasOnlyKeys(value, ['id', 'meshId', 'title', 'goal', 'status', 'brief', ...STRUCTURED_MISSION_KEYS])) return false
|
|
159
|
+
if (!isStructuredMissionFields(value)) return false
|
|
106
160
|
if (!isEvidenceIdentifier(value.id) || !isEvidenceIdentifier(value.meshId)) return false
|
|
107
161
|
if (typeof value.title !== 'string' || typeof value.goal !== 'string') return false
|
|
108
162
|
if (!isMeshMissionStatusValue(value.status)) return false
|
|
@@ -111,11 +165,24 @@ function isMeshMissionRecordWire(value: unknown): value is MeshMissionRecordWire
|
|
|
111
165
|
}
|
|
112
166
|
|
|
113
167
|
function isMissionUpsertRequest(value: unknown): value is MissionUpsertRequest {
|
|
114
|
-
if (!isRecord(value) || !hasOnlyKeys(value, ['v', 'meshId', 'id', 'title', 'goal', 'status', 'brief'])) return false
|
|
168
|
+
if (!isRecord(value) || !hasOnlyKeys(value, ['v', 'meshId', 'id', 'title', 'goal', 'status', 'brief', 'structured', 'summary', 'outcome', 'outcomeReason', 'carryOverTo', 'toCarryOver', 'itemsAdd', 'itemsUpdate'])) return false
|
|
115
169
|
if (value.v !== TURN_IPC_PROTOCOL_VERSION) return false
|
|
116
170
|
if (!isEvidenceIdentifier(value.meshId)) return false
|
|
117
171
|
if (value.id !== undefined && !isEvidenceIdentifier(value.id)) return false
|
|
118
|
-
if (typeof value.title !== 'string'
|
|
172
|
+
if (typeof value.title !== 'string') return false
|
|
173
|
+
// An empty title is allowed only when the daemon can supply one: an existing mission (id) or the carry-over mission.
|
|
174
|
+
if (value.title.trim().length === 0 && value.toCarryOver !== true && value.id === undefined) return false
|
|
175
|
+
if (value.structured !== undefined && typeof value.structured !== 'boolean') return false
|
|
176
|
+
if (value.toCarryOver !== undefined && typeof value.toCarryOver !== 'boolean') return false
|
|
177
|
+
for (const k of ['summary', 'outcome', 'outcomeReason'] as const) {
|
|
178
|
+
if (value[k] !== undefined && typeof value[k] !== 'string') return false
|
|
179
|
+
}
|
|
180
|
+
if (value.carryOverTo !== undefined && !isEvidenceIdentifier(value.carryOverTo)) return false
|
|
181
|
+
for (const k of ['itemsAdd', 'itemsUpdate'] as const) {
|
|
182
|
+
const list = value[k]
|
|
183
|
+
// Bounded only to keep the IPC message sane; per-entry shape/size is clamped (never rejected) by the daemon.
|
|
184
|
+
if (list !== undefined && (!Array.isArray(list) || list.length > 500 || !list.every(isRecord))) return false
|
|
185
|
+
}
|
|
119
186
|
if (value.goal !== undefined && typeof value.goal !== 'string') return false
|
|
120
187
|
if (value.status !== undefined && !isMeshMissionStatusValue(value.status)) return false
|
|
121
188
|
if (value.brief !== undefined && value.brief !== null && !isMissionBriefWire(value.brief)) return false
|
|
@@ -127,7 +194,8 @@ export function decodeMissionUpsertRequest(value: unknown): MissionUpsertRequest
|
|
|
127
194
|
}
|
|
128
195
|
|
|
129
196
|
export function isMissionUpsertResponse(value: unknown): value is MissionUpsertResponse {
|
|
130
|
-
return isRecord(value) && hasOnlyKeys(value, ['mission']) && isMeshMissionRecordWire(value.mission)
|
|
197
|
+
return isRecord(value) && hasOnlyKeys(value, ['mission', 'result']) && isMeshMissionRecordWire(value.mission)
|
|
198
|
+
&& (value.result === undefined || isRecord(value.result))
|
|
131
199
|
}
|
|
132
200
|
|
|
133
201
|
export function decodeMissionUpsertResponse(value: unknown): MissionUpsertResponse | null {
|
|
@@ -207,6 +275,12 @@ export interface MissionListQueryRequest {
|
|
|
207
275
|
* option except `historyIdLimit` is ignored. An older daemon rejects the key.
|
|
208
276
|
*/
|
|
209
277
|
meshStatusView?: 'compact' | 'verbose'
|
|
278
|
+
/** Structured-missions capability flag (see MissionUpsertRequest.structured): rows then carry summary/outcome/openItems/carryOver/version. */
|
|
279
|
+
structured?: boolean
|
|
280
|
+
/** Structured only: attach each mission's items. */
|
|
281
|
+
items?: boolean
|
|
282
|
+
/** Structured only: attach each mission's change history (bounded tail). */
|
|
283
|
+
history?: boolean
|
|
210
284
|
}
|
|
211
285
|
|
|
212
286
|
export interface MeshMissionTaskAggregateWire {
|
|
@@ -248,6 +322,15 @@ export interface MissionListSummaryVerboseWire {
|
|
|
248
322
|
createdAt?: string
|
|
249
323
|
updatedAt?: string
|
|
250
324
|
closeCandidateEmittedAt?: string | null
|
|
325
|
+
/** Structured lists only. */
|
|
326
|
+
summary?: string
|
|
327
|
+
outcome?: string
|
|
328
|
+
outcomeReason?: string
|
|
329
|
+
version?: number
|
|
330
|
+
carryOver?: boolean
|
|
331
|
+
openItems?: MeshMissionOpenItemCountsWire
|
|
332
|
+
items?: readonly Record<string, unknown>[]
|
|
333
|
+
history?: readonly Record<string, unknown>[]
|
|
251
334
|
}
|
|
252
335
|
|
|
253
336
|
/** Compact (default) mission row. `goalPreview`/`goalTruncated` present, `goal` absent. */
|
|
@@ -266,6 +349,15 @@ export interface MissionListSummarySlimWire {
|
|
|
266
349
|
createdAt?: string
|
|
267
350
|
updatedAt?: string
|
|
268
351
|
closeCandidateEmittedAt?: string | null
|
|
352
|
+
/** Structured lists only. */
|
|
353
|
+
summary?: string
|
|
354
|
+
outcome?: string
|
|
355
|
+
outcomeReason?: string
|
|
356
|
+
version?: number
|
|
357
|
+
carryOver?: boolean
|
|
358
|
+
openItems?: MeshMissionOpenItemCountsWire
|
|
359
|
+
items?: readonly Record<string, unknown>[]
|
|
360
|
+
history?: readonly Record<string, unknown>[]
|
|
269
361
|
}
|
|
270
362
|
|
|
271
363
|
export type MissionListSummaryWire = MissionListSummaryVerboseWire | MissionListSummarySlimWire
|
|
@@ -286,7 +378,10 @@ export interface MissionListQueryResponse {
|
|
|
286
378
|
}
|
|
287
379
|
|
|
288
380
|
function isMissionListQueryRequest(value: unknown): value is MissionListQueryRequest {
|
|
289
|
-
if (!isRecord(value) || !hasOnlyKeys(value, ['v', 'meshId', 'statuses', 'verbose', 'withStats', 'limit', 'historyIdLimit', 'meshStatusView'])) return false
|
|
381
|
+
if (!isRecord(value) || !hasOnlyKeys(value, ['v', 'meshId', 'statuses', 'verbose', 'withStats', 'limit', 'historyIdLimit', 'meshStatusView', 'structured', 'items', 'history'])) return false
|
|
382
|
+
for (const k of ['structured', 'items', 'history'] as const) {
|
|
383
|
+
if (value[k] !== undefined && typeof value[k] !== 'boolean') return false
|
|
384
|
+
}
|
|
290
385
|
if (value.meshStatusView !== undefined && value.meshStatusView !== 'compact' && value.meshStatusView !== 'verbose') return false
|
|
291
386
|
if (value.v !== TURN_IPC_PROTOCOL_VERSION) return false
|
|
292
387
|
if (!isEvidenceIdentifier(value.meshId)) return false
|
|
@@ -332,7 +427,7 @@ function isMissionListSummaryWire(value: unknown): value is MissionListSummaryWi
|
|
|
332
427
|
const hasGoal = 'goal' in value
|
|
333
428
|
const hasPreview = 'goalPreview' in value && 'goalTruncated' in value
|
|
334
429
|
if (hasGoal === hasPreview) return false // exactly one of the two shapes
|
|
335
|
-
const baseKeys = ['id', 'meshId', 'title', 'status', 'tasks', 'stats', 'brief', 'createdAt', 'updatedAt', 'closeCandidateEmittedAt'] as const
|
|
430
|
+
const baseKeys = ['id', 'meshId', 'title', 'status', 'tasks', 'stats', 'brief', 'createdAt', 'updatedAt', 'closeCandidateEmittedAt', ...STRUCTURED_MISSION_KEYS, 'items', 'history'] as const
|
|
336
431
|
const allowed = hasGoal ? [...baseKeys, 'goal'] : [...baseKeys, 'goalPreview', 'goalTruncated']
|
|
337
432
|
if (!hasOnlyKeys(value, allowed)) return false
|
|
338
433
|
if (!isEvidenceIdentifier(value.id) || !isEvidenceIdentifier(value.meshId)) return false
|
|
@@ -346,6 +441,10 @@ function isMissionListSummaryWire(value: unknown): value is MissionListSummaryWi
|
|
|
346
441
|
if (value.createdAt !== undefined && typeof value.createdAt !== 'string') return false
|
|
347
442
|
if (value.updatedAt !== undefined && typeof value.updatedAt !== 'string') return false
|
|
348
443
|
if (value.closeCandidateEmittedAt !== undefined && value.closeCandidateEmittedAt !== null && typeof value.closeCandidateEmittedAt !== 'string') return false
|
|
444
|
+
if (!isStructuredMissionFields(value)) return false
|
|
445
|
+
for (const k of ['items', 'history'] as const) {
|
|
446
|
+
if (value[k] !== undefined && (!Array.isArray(value[k]) || !(value[k] as unknown[]).every(isRecord))) return false
|
|
447
|
+
}
|
|
349
448
|
return true
|
|
350
449
|
}
|
|
351
450
|
|
package/src/worker-protocol.ts
CHANGED