@adhdev/mesh-shared 1.0.76-rc.1 → 1.0.76-rc.2
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 +60 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +84 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +75 -14
- package/dist/index.mjs.map +1 -1
- package/dist/node-facts.d.ts +0 -1
- package/dist/outbound-message.d.ts +6 -2
- package/dist/session-launch.d.ts +3 -1
- package/dist/slot-proposal.d.ts +2 -2
- package/dist/turn-evidence.d.ts +7 -5
- package/package.json +1 -1
- package/src/assistant-protocol.ts +109 -0
- package/src/index.ts +1 -0
- package/src/node-facts.ts +0 -1
- package/src/outbound-message.ts +6 -2
- package/src/session-launch.ts +3 -1
- package/src/slot-proposal.ts +3 -15
- package/src/turn-evidence.ts +7 -5
package/dist/node-facts.d.ts
CHANGED
|
@@ -223,7 +223,6 @@ export declare function normalizeMeshNodeFacts(raw: unknown): MeshNodeFacts | un
|
|
|
223
223
|
*
|
|
224
224
|
* Known non-members and why, so this is not re-litigated per surface:
|
|
225
225
|
* - cursor-cli — permanently impossible; no personal usage API exists
|
|
226
|
-
* - hermes-cli — no model-axis quota to report
|
|
227
226
|
*
|
|
228
227
|
* ★grok-cli WAS listed here as impossible and is not: that verdict came from
|
|
229
228
|
* probing `api.x.ai` / `management-api.x.ai` (the team-API billing axis, which
|
|
@@ -93,8 +93,12 @@ export interface InputEnvelopeWire {
|
|
|
93
93
|
* `'mesh'` (flagged as an open question in phase-D-plan.md §7.3 risk 5) —
|
|
94
94
|
* kept here unchanged pending an owner decision; dropping a union member is
|
|
95
95
|
* a decision for whoever lands D-daemon/D2, not this workstream.
|
|
96
|
+
*
|
|
97
|
+
* `'assistant'`: the assistant layer's `project_send` into a project
|
|
98
|
+
* coordinator (docs/design/2026-10-07-assistant-layer.md §4.3 step 4). A label
|
|
99
|
+
* only — it is not an auth signal and selects no policy of its own.
|
|
96
100
|
*/
|
|
97
|
-
export type OutboundMessageOrigin = 'dashboard' | 'mcp' | 'mesh' | 'api' | 'cli';
|
|
101
|
+
export type OutboundMessageOrigin = 'dashboard' | 'mcp' | 'mesh' | 'api' | 'cli' | 'assistant';
|
|
98
102
|
/**
|
|
99
103
|
* How this message should be admitted when the session is not idle.
|
|
100
104
|
* Replaces the loose `sendNow`/`interrupt`/`force`/`forceSend` booleans (and
|
|
@@ -188,7 +192,7 @@ export interface OutboundMessage {
|
|
|
188
192
|
}
|
|
189
193
|
export declare function mintMessageId(now?: number): string;
|
|
190
194
|
export declare function isMessageId(value: unknown): value is string;
|
|
191
|
-
export declare const OUTBOUND_MESSAGE_ORIGINS: readonly ["dashboard", "mcp", "mesh", "api", "cli"];
|
|
195
|
+
export declare const OUTBOUND_MESSAGE_ORIGINS: readonly ["dashboard", "mcp", "mesh", "api", "cli", "assistant"];
|
|
192
196
|
export declare function isOutboundMessageOrigin(value: unknown): value is OutboundMessageOrigin;
|
|
193
197
|
export declare const SEND_POLICY_MODES: readonly ["queue", "send_now", "interrupt"];
|
|
194
198
|
export declare function isSendPolicyMode(value: unknown): value is SendPolicy['mode'];
|
package/dist/session-launch.d.ts
CHANGED
|
@@ -25,8 +25,10 @@ export declare function isModelAxisSource(value: unknown): value is ModelAxisSou
|
|
|
25
25
|
/**
|
|
26
26
|
* Which surface started the session. `restore` means "re-attached to a hosted
|
|
27
27
|
* runtime that outlived a daemon restart" — the axis sources are preserved.
|
|
28
|
+
* `assistant` is the assistant layer's own session (`launch_assistant`,
|
|
29
|
+
* docs/design/2026-10-07-assistant-layer.md §4.5).
|
|
28
30
|
*/
|
|
29
|
-
export declare const SESSION_LAUNCHED_BY: readonly ["dashboard", "mesh", "cli", "api", "restore"];
|
|
31
|
+
export declare const SESSION_LAUNCHED_BY: readonly ["dashboard", "mesh", "cli", "api", "restore", "assistant"];
|
|
30
32
|
export type SessionLaunchedBy = typeof SESSION_LAUNCHED_BY[number];
|
|
31
33
|
export declare function isSessionLaunchedBy(value: unknown): value is SessionLaunchedBy;
|
|
32
34
|
/** How a value entered the axis history. */
|
package/dist/slot-proposal.d.ts
CHANGED
|
@@ -58,8 +58,8 @@ export interface CliSlotRecipe {
|
|
|
58
58
|
* invented heuristic. Replace wholesale once usage data (success rate, cost,
|
|
59
59
|
* turn latency per provider×difficulty) can drive it.
|
|
60
60
|
*
|
|
61
|
-
* Every entry
|
|
62
|
-
*
|
|
61
|
+
* Every entry reflects a real configured slot. A provider absent from the table
|
|
62
|
+
* falls back to {@link UNKNOWN_CLI_SLOT_RECIPE}, the only `provisional` recipe.
|
|
63
63
|
*/
|
|
64
64
|
export declare const CLI_SLOT_RECIPES: Readonly<Record<string, readonly CliSlotRecipe[]>>;
|
|
65
65
|
/**
|
package/dist/turn-evidence.d.ts
CHANGED
|
@@ -74,11 +74,13 @@ export type LivenessResult = typeof LIVENESS_RESULTS[number];
|
|
|
74
74
|
export declare const PROVIDER_FAILURES: readonly ["auth_failed", "billing_failed"];
|
|
75
75
|
export type ProviderFailure = typeof PROVIDER_FAILURES[number];
|
|
76
76
|
/**
|
|
77
|
-
* `daemon_restart` (wiring-unification follow-up, design §5):
|
|
78
|
-
* reconciliation observes this for a plain attempt
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
77
|
+
* `daemon_restart` (wiring-unification follow-up, design §5): boot-time
|
|
78
|
+
* reconciliation observes this for a plain attempt that was open when the
|
|
79
|
+
* daemon restarted — either its session is gone, or the session was restored
|
|
80
|
+
* live but the turn in flight was cut by the restart. The daemon never saw
|
|
81
|
+
* the session's own exit or commit, so it is not `provider_error` /
|
|
82
|
+
* `adapter_error` / etc.; it is the daemon itself closing a turn it can no
|
|
83
|
+
* longer follow.
|
|
82
84
|
*/
|
|
83
85
|
export declare const SESSION_ERROR_REASONS: readonly ["provider_error", "adapter_error", "spawn_failed", "auth_failed", "billing_failed", "unknown", "daemon_restart"];
|
|
84
86
|
export type SessionErrorReason = typeof SESSION_ERROR_REASONS[number];
|
package/package.json
CHANGED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* assistant-protocol — the assistant layer's tool and daemon-verb names
|
|
3
|
+
* (docs/design/2026-10-07-assistant-layer.md §4.4).
|
|
4
|
+
*
|
|
5
|
+
* The single source for both halves of the assistant contract, like
|
|
6
|
+
* `WORKER_TOOLS` is for workers:
|
|
7
|
+
* - `ASSISTANT_TOOLS` — exactly what `adhdev mcp --assistant` will advertise
|
|
8
|
+
* (an mcp-server parity test pins ListTools to this tuple once that mode
|
|
9
|
+
* lands);
|
|
10
|
+
* - `ASSISTANT_TOOL_VERBS` — the daemon command each tool calls;
|
|
11
|
+
* - the daemon-only verbs (launch / MCP-only pull / owner actions) that have
|
|
12
|
+
* no tool.
|
|
13
|
+
*
|
|
14
|
+
* Assistant tools are a separate set from the mesh tools: none of these names
|
|
15
|
+
* belongs in `CANONICAL_MESH_TOOL_NAMES`, and the coordinator/worker MCP modes
|
|
16
|
+
* never publish them.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
export const ASSISTANT_TOOLS = [
|
|
20
|
+
'projects',
|
|
21
|
+
'project_status',
|
|
22
|
+
'project_send',
|
|
23
|
+
'project_read',
|
|
24
|
+
'project_add',
|
|
25
|
+
'discover_repos',
|
|
26
|
+
'memory',
|
|
27
|
+
'skill_view',
|
|
28
|
+
'skill_manage',
|
|
29
|
+
'project_note',
|
|
30
|
+
] as const
|
|
31
|
+
|
|
32
|
+
export type AssistantTool = typeof ASSISTANT_TOOLS[number]
|
|
33
|
+
|
|
34
|
+
const ASSISTANT_TOOL_SET: ReadonlySet<string> = new Set(ASSISTANT_TOOLS)
|
|
35
|
+
|
|
36
|
+
export function isAssistantTool(value: unknown): value is AssistantTool {
|
|
37
|
+
return typeof value === 'string' && ASSISTANT_TOOL_SET.has(value)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Daemon verb names (§4.4 table + the five verbs below it). */
|
|
41
|
+
export const ASSISTANT_VERB = {
|
|
42
|
+
// tool verbs
|
|
43
|
+
projects: 'assistant_projects',
|
|
44
|
+
projectStatus: 'assistant_project_status',
|
|
45
|
+
projectSend: 'assistant_project_send',
|
|
46
|
+
projectRead: 'assistant_project_read',
|
|
47
|
+
projectAdd: 'assistant_project_add',
|
|
48
|
+
discoverRepos: 'assistant_discover_repos',
|
|
49
|
+
memory: 'assistant_memory',
|
|
50
|
+
skillView: 'assistant_skill_view',
|
|
51
|
+
skillManage: 'assistant_skill_manage',
|
|
52
|
+
projectNote: 'assistant_project_note',
|
|
53
|
+
// assistant-side daemon verbs without a tool of the same name
|
|
54
|
+
launch: 'launch_assistant',
|
|
55
|
+
pendingRelays: 'assistant_pending_relays',
|
|
56
|
+
// owner verbs (dashboard only)
|
|
57
|
+
stagedResolve: 'assistant_staged_resolve',
|
|
58
|
+
storeAdmin: 'assistant_store_admin',
|
|
59
|
+
importSkills: 'assistant_import_skills',
|
|
60
|
+
} as const
|
|
61
|
+
|
|
62
|
+
export type AssistantVerb = typeof ASSISTANT_VERB[keyof typeof ASSISTANT_VERB]
|
|
63
|
+
|
|
64
|
+
/** The daemon verb each assistant tool calls. */
|
|
65
|
+
export const ASSISTANT_TOOL_VERBS: Readonly<Record<AssistantTool, AssistantVerb>> = {
|
|
66
|
+
projects: ASSISTANT_VERB.projects,
|
|
67
|
+
project_status: ASSISTANT_VERB.projectStatus,
|
|
68
|
+
project_send: ASSISTANT_VERB.projectSend,
|
|
69
|
+
project_read: ASSISTANT_VERB.projectRead,
|
|
70
|
+
project_add: ASSISTANT_VERB.projectAdd,
|
|
71
|
+
discover_repos: ASSISTANT_VERB.discoverRepos,
|
|
72
|
+
memory: ASSISTANT_VERB.memory,
|
|
73
|
+
skill_view: ASSISTANT_VERB.skillView,
|
|
74
|
+
skill_manage: ASSISTANT_VERB.skillManage,
|
|
75
|
+
project_note: ASSISTANT_VERB.projectNote,
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Tools annotated as writes; every other assistant tool is read-only. §4.4
|
|
80
|
+
* lists the three store writes; project_send and project_add are here too
|
|
81
|
+
* because they cause effects (a coordinator message or launch, a new
|
|
82
|
+
* project), and MCP clients use readOnlyHint to skip confirmation.
|
|
83
|
+
*/
|
|
84
|
+
export const ASSISTANT_WRITE_TOOLS: readonly AssistantTool[] = ['memory', 'skill_manage', 'project_note', 'project_send', 'project_add']
|
|
85
|
+
|
|
86
|
+
/** Owner-only verbs: never reachable from the assistant's MCP server (no `ipc`). */
|
|
87
|
+
export const ASSISTANT_OWNER_VERBS: readonly AssistantVerb[] = [
|
|
88
|
+
ASSISTANT_VERB.stagedResolve,
|
|
89
|
+
ASSISTANT_VERB.storeAdmin,
|
|
90
|
+
ASSISTANT_VERB.importSkills,
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
/** The only assistant verbs accepted while an idle review turn is open (§4.10.7). */
|
|
94
|
+
export const ASSISTANT_REVIEW_TURN_VERBS: readonly AssistantVerb[] = [
|
|
95
|
+
ASSISTANT_VERB.memory,
|
|
96
|
+
ASSISTANT_VERB.skillView,
|
|
97
|
+
ASSISTANT_VERB.skillManage,
|
|
98
|
+
ASSISTANT_VERB.projectNote,
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Env var the daemon sets on the assistant CLI's process (§4.5), read by the
|
|
103
|
+
* assistant MCP server and forwarded on every verb as
|
|
104
|
+
* `ASSISTANT_SESSION_ID_ARG`. Routing / ownership only — never an auth gate.
|
|
105
|
+
*/
|
|
106
|
+
export const ASSISTANT_SESSION_ID_ENV = 'ADHDEV_ASSISTANT_SESSION_ID'
|
|
107
|
+
|
|
108
|
+
/** Request arg carrying the calling assistant session id. */
|
|
109
|
+
export const ASSISTANT_SESSION_ID_ARG = 'assistantSessionId'
|
package/src/index.ts
CHANGED
|
@@ -33,6 +33,7 @@ export * from './session-status'
|
|
|
33
33
|
export * from './mesh-vocabulary'
|
|
34
34
|
export * from './outbound-message'
|
|
35
35
|
export * from './worker-protocol'
|
|
36
|
+
export * from './assistant-protocol'
|
|
36
37
|
export * from './protocol'
|
|
37
38
|
export * from './turn-evidence'
|
|
38
39
|
export * from './session-launch'
|
package/src/node-facts.ts
CHANGED
|
@@ -238,7 +238,6 @@ export function normalizeMeshNodeFacts(raw: unknown): MeshNodeFacts | undefined
|
|
|
238
238
|
*
|
|
239
239
|
* Known non-members and why, so this is not re-litigated per surface:
|
|
240
240
|
* - cursor-cli — permanently impossible; no personal usage API exists
|
|
241
|
-
* - hermes-cli — no model-axis quota to report
|
|
242
241
|
*
|
|
243
242
|
* ★grok-cli WAS listed here as impossible and is not: that verdict came from
|
|
244
243
|
* probing `api.x.ai` / `management-api.x.ai` (the team-API billing axis, which
|
package/src/outbound-message.ts
CHANGED
|
@@ -113,8 +113,12 @@ export interface InputEnvelopeWire {
|
|
|
113
113
|
* `'mesh'` (flagged as an open question in phase-D-plan.md §7.3 risk 5) —
|
|
114
114
|
* kept here unchanged pending an owner decision; dropping a union member is
|
|
115
115
|
* a decision for whoever lands D-daemon/D2, not this workstream.
|
|
116
|
+
*
|
|
117
|
+
* `'assistant'`: the assistant layer's `project_send` into a project
|
|
118
|
+
* coordinator (docs/design/2026-10-07-assistant-layer.md §4.3 step 4). A label
|
|
119
|
+
* only — it is not an auth signal and selects no policy of its own.
|
|
116
120
|
*/
|
|
117
|
-
export type OutboundMessageOrigin = 'dashboard' | 'mcp' | 'mesh' | 'api' | 'cli'
|
|
121
|
+
export type OutboundMessageOrigin = 'dashboard' | 'mcp' | 'mesh' | 'api' | 'cli' | 'assistant'
|
|
118
122
|
|
|
119
123
|
/**
|
|
120
124
|
* How this message should be admitted when the session is not idle.
|
|
@@ -243,7 +247,7 @@ export function isMessageId(value: unknown): value is string {
|
|
|
243
247
|
|
|
244
248
|
// ─── Guards ─────────────────────────────────────────────────────────────────
|
|
245
249
|
|
|
246
|
-
export const OUTBOUND_MESSAGE_ORIGINS = ['dashboard', 'mcp', 'mesh', 'api', 'cli'] as const satisfies readonly OutboundMessageOrigin[]
|
|
250
|
+
export const OUTBOUND_MESSAGE_ORIGINS = ['dashboard', 'mcp', 'mesh', 'api', 'cli', 'assistant'] as const satisfies readonly OutboundMessageOrigin[]
|
|
247
251
|
|
|
248
252
|
export function isOutboundMessageOrigin(value: unknown): value is OutboundMessageOrigin {
|
|
249
253
|
return typeof value === 'string' && (OUTBOUND_MESSAGE_ORIGINS as readonly string[]).includes(value)
|
package/src/session-launch.ts
CHANGED
|
@@ -54,8 +54,10 @@ export function isModelAxisSource(value: unknown): value is ModelAxisSource {
|
|
|
54
54
|
/**
|
|
55
55
|
* Which surface started the session. `restore` means "re-attached to a hosted
|
|
56
56
|
* runtime that outlived a daemon restart" — the axis sources are preserved.
|
|
57
|
+
* `assistant` is the assistant layer's own session (`launch_assistant`,
|
|
58
|
+
* docs/design/2026-10-07-assistant-layer.md §4.5).
|
|
57
59
|
*/
|
|
58
|
-
export const SESSION_LAUNCHED_BY = ['dashboard', 'mesh', 'cli', 'api', 'restore'] as const
|
|
60
|
+
export const SESSION_LAUNCHED_BY = ['dashboard', 'mesh', 'cli', 'api', 'restore', 'assistant'] as const
|
|
59
61
|
|
|
60
62
|
export type SessionLaunchedBy = typeof SESSION_LAUNCHED_BY[number]
|
|
61
63
|
|
package/src/slot-proposal.ts
CHANGED
|
@@ -64,8 +64,8 @@ export interface CliSlotRecipe {
|
|
|
64
64
|
* invented heuristic. Replace wholesale once usage data (success rate, cost,
|
|
65
65
|
* turn latency per provider×difficulty) can drive it.
|
|
66
66
|
*
|
|
67
|
-
* Every entry
|
|
68
|
-
*
|
|
67
|
+
* Every entry reflects a real configured slot. A provider absent from the table
|
|
68
|
+
* falls back to {@link UNKNOWN_CLI_SLOT_RECIPE}, the only `provisional` recipe.
|
|
69
69
|
*/
|
|
70
70
|
export const CLI_SLOT_RECIPES: Readonly<Record<string, readonly CliSlotRecipe[]>> = Object.freeze<Record<string, readonly CliSlotRecipe[]>>({
|
|
71
71
|
'claude-cli': [
|
|
@@ -115,18 +115,6 @@ export const CLI_SLOT_RECIPES: Readonly<Record<string, readonly CliSlotRecipe[]>
|
|
|
115
115
|
rationale: 'Easy tasks only; auto model selection.',
|
|
116
116
|
},
|
|
117
117
|
],
|
|
118
|
-
'hermes-cli': [
|
|
119
|
-
{
|
|
120
|
-
difficulty: ['medium'],
|
|
121
|
-
maxParallel: 2,
|
|
122
|
-
provisional: true,
|
|
123
|
-
// NOTE: ESTIMATE, NOT OBSERVED. hermes-cli is absent from the live
|
|
124
|
-
// slot configuration this table was seeded from, so `medium` is a
|
|
125
|
-
// conservative placement rather than a transcription. Revisit once
|
|
126
|
-
// it has real usage data.
|
|
127
|
-
rationale: 'ESTIMATE — no live slot to transcribe; conservative mid placement. Adjust after real use.',
|
|
128
|
-
},
|
|
129
|
-
],
|
|
130
118
|
})
|
|
131
119
|
|
|
132
120
|
/**
|
|
@@ -193,7 +181,7 @@ function slotKey(slot: NodeCapabilitySlot): string {
|
|
|
193
181
|
[...(slot.difficulty ?? [])].sort().join('|'),
|
|
194
182
|
[...(slot.capability ?? [])].sort().join('|'),
|
|
195
183
|
slot.maxParallel ?? '',
|
|
196
|
-
].join('
|
|
184
|
+
].join('\u0000')
|
|
197
185
|
}
|
|
198
186
|
|
|
199
187
|
/** Dedupe detected providers by type, preserving first-seen order. */
|
package/src/turn-evidence.ts
CHANGED
|
@@ -107,11 +107,13 @@ export const PROVIDER_FAILURES = ['auth_failed', 'billing_failed'] as const
|
|
|
107
107
|
export type ProviderFailure = typeof PROVIDER_FAILURES[number]
|
|
108
108
|
|
|
109
109
|
/**
|
|
110
|
-
* `daemon_restart` (wiring-unification follow-up, design §5):
|
|
111
|
-
* reconciliation observes this for a plain attempt
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
110
|
+
* `daemon_restart` (wiring-unification follow-up, design §5): boot-time
|
|
111
|
+
* reconciliation observes this for a plain attempt that was open when the
|
|
112
|
+
* daemon restarted — either its session is gone, or the session was restored
|
|
113
|
+
* live but the turn in flight was cut by the restart. The daemon never saw
|
|
114
|
+
* the session's own exit or commit, so it is not `provider_error` /
|
|
115
|
+
* `adapter_error` / etc.; it is the daemon itself closing a turn it can no
|
|
116
|
+
* longer follow.
|
|
115
117
|
*/
|
|
116
118
|
export const SESSION_ERROR_REASONS = ['provider_error', 'adapter_error', 'spawn_failed', 'auth_failed', 'billing_failed', 'unknown', 'daemon_restart'] as const
|
|
117
119
|
export type SessionErrorReason = typeof SESSION_ERROR_REASONS[number]
|