dsh-live-teams 0.1.0

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.
Files changed (69) hide show
  1. package/LICENSE +176 -0
  2. package/NOTICE +11 -0
  3. package/README.md +85 -0
  4. package/cordis.patch.yml +25 -0
  5. package/lib/binding.d.ts +18 -0
  6. package/lib/binding.js +42 -0
  7. package/lib/changed-paths.d.ts +26 -0
  8. package/lib/changed-paths.js +69 -0
  9. package/lib/client.js +6753 -0
  10. package/lib/command-queue.d.ts +60 -0
  11. package/lib/command-queue.js +185 -0
  12. package/lib/compatibility.js +109 -0
  13. package/lib/context-provider.d.ts +110 -0
  14. package/lib/context-provider.js +249 -0
  15. package/lib/dispatch.d.ts +174 -0
  16. package/lib/dispatch.js +624 -0
  17. package/lib/errors.d.ts +36 -0
  18. package/lib/errors.js +103 -0
  19. package/lib/git-artifacts.d.ts +50 -0
  20. package/lib/git-artifacts.js +242 -0
  21. package/lib/index.d.ts +14 -0
  22. package/lib/index.js +14 -0
  23. package/lib/mailbox.d.ts +274 -0
  24. package/lib/mailbox.js +721 -0
  25. package/lib/member-tools.d.ts +57 -0
  26. package/lib/member-tools.js +1265 -0
  27. package/lib/migrations.d.ts +17 -0
  28. package/lib/migrations.js +47 -0
  29. package/lib/plugin.d.ts +106 -0
  30. package/lib/plugin.js +1003 -0
  31. package/lib/roles.d.ts +35 -0
  32. package/lib/roles.js +284 -0
  33. package/lib/routes.d.ts +586 -0
  34. package/lib/routes.js +2816 -0
  35. package/lib/scope.d.ts +62 -0
  36. package/lib/scope.js +133 -0
  37. package/lib/session-bridge.d.ts +76 -0
  38. package/lib/session-bridge.js +147 -0
  39. package/lib/session-title.js +35 -0
  40. package/lib/storage.d.ts +9 -0
  41. package/lib/storage.js +65 -0
  42. package/lib/task-store.d.ts +729 -0
  43. package/lib/task-store.js +2205 -0
  44. package/lib/team-store.d.ts +216 -0
  45. package/lib/team-store.js +765 -0
  46. package/lib/tree-snapshot.d.ts +28 -0
  47. package/lib/tree-snapshot.js +80 -0
  48. package/lib/types/client/TeamView.d.ts +26 -0
  49. package/lib/types/client/TeamView.dom.test.d.ts +1 -0
  50. package/lib/types/client/api.d.ts +522 -0
  51. package/lib/types/client/api.test.d.ts +1 -0
  52. package/lib/types/client/attention.d.ts +65 -0
  53. package/lib/types/client/attention.test.d.ts +1 -0
  54. package/lib/types/client/index.d.ts +31 -0
  55. package/lib/types/client/locales.d.ts +577 -0
  56. package/lib/types/client/member-name.d.ts +14 -0
  57. package/lib/types/client/member-name.test.d.ts +1 -0
  58. package/lib/types/client/roster.d.ts +26 -0
  59. package/lib/types/client/roster.test.d.ts +1 -0
  60. package/lib/types/client/styles.d.ts +3 -0
  61. package/package.json +104 -0
  62. package/roles/builder.md +40 -0
  63. package/roles/delegate.md +36 -0
  64. package/roles/lead.md +46 -0
  65. package/roles/oracle.md +36 -0
  66. package/roles/researcher.md +37 -0
  67. package/roles/reviewer.md +45 -0
  68. package/roles/scout.md +36 -0
  69. package/roles/verifier.md +36 -0
@@ -0,0 +1,1265 @@
1
+ import { resolveLeadMemberId } from "./team-store.js";
2
+ import { messageDeliveryOutcome } from "./mailbox.js";
3
+ import path from "node:path";
4
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
5
+ import { defineTool } from "@deepseek-ai/dsh-tools";
6
+ //#region src/member-tools.ts
7
+ const MEMBER_TOOL_NAMES = Object.freeze([
8
+ "live_team_send",
9
+ "live_team_ack_message",
10
+ "live_team_context",
11
+ "live_team_status",
12
+ "live_team_brief",
13
+ "live_team_member_note",
14
+ "live_team_grant",
15
+ "live_team_dispatch",
16
+ "live_team_create_task",
17
+ "live_team_read_task",
18
+ "live_team_list_tasks",
19
+ "live_team_claim_task",
20
+ "live_team_ack_task",
21
+ "live_team_submit",
22
+ "live_team_review",
23
+ "live_team_update_task",
24
+ "live_team_accept_task",
25
+ "live_team_revise_task",
26
+ "live_team_revoke_task"
27
+ ]);
28
+ /**
29
+ * Which team tools belong to whom.
30
+ *
31
+ * The host registers tools globally and gives a plugin no way to hide one from a Session, so a
32
+ * builder is *offered* the lead's tools and learns by refusal. The membership context is rendered on
33
+ * every turn, so it can say what belongs to the role — and that is what this is for: the context
34
+ * names the member's own tools and the ones addressed to somebody else.
35
+ *
36
+ * One list, not a second copy of the authority rules: `assertToolRolesComplete` (a test) fails if a
37
+ * tool is added without a home here, and the runtime guards in `execute` stay exactly as they are.
38
+ * Visibility is a hint; authority is still decided per call.
39
+ */
40
+ const MEMBER_BASE_TOOLS = [
41
+ "live_team_send",
42
+ "live_team_ack_message",
43
+ "live_team_context",
44
+ "live_team_status",
45
+ "live_team_brief",
46
+ "live_team_read_task",
47
+ "live_team_list_tasks",
48
+ "live_team_claim_task",
49
+ "live_team_ack_task",
50
+ "live_team_submit"
51
+ ];
52
+ const LEAD_TOOLS = [
53
+ "live_team_create_task",
54
+ "live_team_update_task",
55
+ "live_team_revoke_task",
56
+ "live_team_accept_task",
57
+ "live_team_revise_task",
58
+ "live_team_grant",
59
+ "live_team_dispatch",
60
+ "live_team_member_note"
61
+ ];
62
+ const REVIEW_TOOLS = ["live_team_review"];
63
+ /** Reviewer and verifier both judge work; the role files are craft, the capability is this. */
64
+ const REVIEW_ROLES = ["reviewer", "verifier"];
65
+ function toolsForRole(role) {
66
+ const mine = [
67
+ ...MEMBER_BASE_TOOLS,
68
+ ...role === "lead" ? LEAD_TOOLS : [],
69
+ ...REVIEW_ROLES.includes(role) ? REVIEW_TOOLS : []
70
+ ];
71
+ return {
72
+ mine,
73
+ notMine: MEMBER_TOOL_NAMES.filter((name) => !mine.includes(name))
74
+ };
75
+ }
76
+ function sessionIdOf(exec) {
77
+ const value = exec.agent?.session?.id;
78
+ if (typeof value !== "string" || value.length === 0) throw new Error("calling Session has no identity");
79
+ return value;
80
+ }
81
+ function memberName(binding, recipient) {
82
+ if (recipient === "human") return "human";
83
+ return binding.team.members.find((member) => member.memberId === recipient)?.displayName ?? recipient;
84
+ }
85
+ function sendResult(binding, messageId, deliveries) {
86
+ const projected = deliveries.map((delivery) => ({
87
+ recipient: delivery.recipient,
88
+ name: memberName(binding, delivery.recipient),
89
+ state: delivery.state,
90
+ outcome: messageDeliveryOutcome(delivery),
91
+ ...delivery.state === "failed" && delivery.failure !== void 0 ? { failure: delivery.failure } : {}
92
+ }));
93
+ return {
94
+ accepted: true,
95
+ messageId,
96
+ delivered: projected.filter((delivery) => delivery.outcome === "delivered").length,
97
+ inbox: projected.filter((delivery) => delivery.outcome === "inbox").length,
98
+ pending: projected.filter((delivery) => delivery.outcome === "pending").length,
99
+ failed: projected.filter((delivery) => delivery.outcome === "failed").length,
100
+ deliveries: projected
101
+ };
102
+ }
103
+ function memberContext(binding) {
104
+ return {
105
+ teamName: binding.teamName,
106
+ memberName: binding.member.displayName,
107
+ role: binding.member.role,
108
+ availability: binding.member.availability,
109
+ members: binding.team.members.map((member) => ({
110
+ memberId: member.memberId,
111
+ name: member.displayName,
112
+ role: member.role,
113
+ availability: member.availability,
114
+ live: binding.live(member)
115
+ }))
116
+ };
117
+ }
118
+ function memberStatus(binding) {
119
+ return {
120
+ memberId: binding.member.memberId,
121
+ teamId: binding.team.teamId,
122
+ role: binding.member.role,
123
+ availability: binding.member.availability,
124
+ bindingGeneration: binding.member.bindingGeneration,
125
+ contractRevision: binding.member.contractRevision,
126
+ live: binding.live(binding.member)
127
+ };
128
+ }
129
+ function renderOutput(value) {
130
+ return [{
131
+ type: "text",
132
+ text: JSON.stringify(value)
133
+ }];
134
+ }
135
+ function jsonRecord(value) {
136
+ return JSON.parse(JSON.stringify(value));
137
+ }
138
+ function jsonCreateResult(value) {
139
+ const candidate = jsonRecord(value);
140
+ return {
141
+ task: jsonRecord(candidate.task),
142
+ documentPath: String(candidate.documentPath)
143
+ };
144
+ }
145
+ function jsonReadResult(value) {
146
+ const candidate = jsonRecord(value);
147
+ return {
148
+ task: jsonRecord(candidate.task),
149
+ document: String(candidate.document),
150
+ submissions: Array.isArray(candidate.submissions) ? candidate.submissions : [],
151
+ rounds: Array.isArray(candidate.rounds) ? candidate.rounds : []
152
+ };
153
+ }
154
+ function jsonListedTasks(value) {
155
+ return JSON.parse(JSON.stringify(value));
156
+ }
157
+ function normalizeOptions(options, b18, b19, b20) {
158
+ if (typeof options === "object" && options !== null) return {
159
+ includeContext: options.includeContext === true,
160
+ includeContact: options.includeContact === true,
161
+ includeTasks: options.includeTasks === true,
162
+ includeSubmissions: options.includeSubmissions === true,
163
+ includeReview: options.includeReview === true,
164
+ includeAcceptance: options.includeAcceptance === true,
165
+ includeDispatch: options.includeDispatch === true
166
+ };
167
+ return {
168
+ includeContext: options === true,
169
+ includeContact: b18 === true,
170
+ includeTasks: b19 === true,
171
+ includeSubmissions: b20 === true,
172
+ includeReview: false,
173
+ includeAcceptance: false,
174
+ includeDispatch: false
175
+ };
176
+ }
177
+ /** Mount B13 only when the optional tools service is present. */
178
+ function registerMemberToolsIfAvailable(registry, resolve, options = {}, legacyB18 = false, legacyB19 = false, legacyB20 = false) {
179
+ if (registry === void 0) return false;
180
+ registerMemberTools(registry, resolve, typeof options === "boolean" ? {
181
+ includeContext: true,
182
+ includeContact: legacyB18,
183
+ includeTasks: legacyB19,
184
+ includeSubmissions: legacyB20
185
+ } : {
186
+ includeContext: true,
187
+ ...options
188
+ });
189
+ return true;
190
+ }
191
+ /** Register the member-tool surface. Object options prevent positional flag drift as gates grow. */
192
+ function registerMemberTools(registry, resolve, options = false, legacyB18, legacyB19, legacyB20) {
193
+ const flags = normalizeOptions(options, legacyB18, legacyB19, legacyB20);
194
+ const includeContext = flags.includeContext;
195
+ const includeContact = flags.includeContact;
196
+ const includeTasks = flags.includeTasks;
197
+ const includeSubmissions = flags.includeSubmissions;
198
+ const includeReview = flags.includeReview;
199
+ const includeAcceptance = flags.includeAcceptance;
200
+ const includeDispatch = flags.includeDispatch;
201
+ registry.register(defineTool({
202
+ name: "live_team_send",
203
+ description: "Send a message, direction, or comment to a member id or display name, the team, or the human.",
204
+ parameters: {
205
+ to: {
206
+ type: "string",
207
+ required: true,
208
+ description: "A member id, display name, 'team', or 'human'."
209
+ },
210
+ kind: {
211
+ type: "string",
212
+ enum: [
213
+ "message",
214
+ "direction",
215
+ "comment",
216
+ "report"
217
+ ],
218
+ description: "The message kind: `message` (the default), `direction` (the lead directing a member), `comment` (a note on someone else's work). `report` is accepted as a synonym for `message`."
219
+ },
220
+ content: {
221
+ type: "string",
222
+ required: true,
223
+ description: "The message body."
224
+ },
225
+ threadId: {
226
+ type: "string",
227
+ description: "Optional thread to continue."
228
+ }
229
+ },
230
+ output: {
231
+ schema: {
232
+ type: "object",
233
+ additionalProperties: false,
234
+ properties: {
235
+ accepted: {
236
+ type: "boolean",
237
+ required: true
238
+ },
239
+ messageId: {
240
+ type: "string",
241
+ required: true
242
+ },
243
+ delivered: {
244
+ type: "number",
245
+ required: true
246
+ },
247
+ inbox: {
248
+ type: "number",
249
+ required: true
250
+ },
251
+ pending: {
252
+ type: "number",
253
+ required: true
254
+ },
255
+ failed: {
256
+ type: "number",
257
+ required: true
258
+ },
259
+ deliveries: {
260
+ type: "array",
261
+ required: true,
262
+ items: {
263
+ type: "object",
264
+ additionalProperties: false,
265
+ properties: {
266
+ recipient: {
267
+ type: "string",
268
+ required: true
269
+ },
270
+ name: {
271
+ type: "string",
272
+ required: true
273
+ },
274
+ state: {
275
+ type: "string",
276
+ required: true,
277
+ enum: [
278
+ "stored",
279
+ "leased",
280
+ "delivered",
281
+ "acknowledged",
282
+ "failed"
283
+ ]
284
+ },
285
+ outcome: {
286
+ type: "string",
287
+ required: true,
288
+ enum: [
289
+ "delivered",
290
+ "inbox",
291
+ "pending",
292
+ "failed"
293
+ ]
294
+ },
295
+ failure: { type: "string" }
296
+ }
297
+ }
298
+ }
299
+ }
300
+ },
301
+ render: (_args, value) => {
302
+ const result = value;
303
+ const statements = result.deliveries.map((delivery) => {
304
+ if (delivery.outcome === "delivered") return `Delivered to ${delivery.name}.`;
305
+ if (delivery.outcome === "inbox") return delivery.name === "human" ? "Stored in the human inbox (waits for the human)." : `Stored for ${delivery.name}'s context.`;
306
+ if (delivery.outcome === "pending") return `Pending delivery to ${delivery.name}.`;
307
+ return `Failed to deliver to ${delivery.name}: ${delivery.failure ?? "delivery failed"}.`;
308
+ });
309
+ const undelivered = result.deliveries.filter((delivery) => delivery.outcome === "failed" || delivery.outcome === "pending");
310
+ const warning = undelivered.length === 0 ? "" : result.delivered === 0 && result.inbox === 0 ? ` Nothing was delivered to: ${undelivered.map((delivery) => `${delivery.name} (${delivery.outcome}${delivery.failure === void 0 ? "" : `: ${delivery.failure}`})`).join(", ")}.` : ` Not delivered to: ${undelivered.map((delivery) => `${delivery.name} (${delivery.outcome}${delivery.failure === void 0 ? "" : `: ${delivery.failure}`})`).join(", ")}.`;
311
+ return [{
312
+ type: "text",
313
+ text: `Accepted. ${statements.join(" ")}${warning}`
314
+ }];
315
+ }
316
+ },
317
+ execute: async (args, exec) => {
318
+ const sessionId = sessionIdOf(exec);
319
+ const binding = await resolve(sessionId);
320
+ if (binding === void 0) throw new Error("calling Session is not an active member of this team");
321
+ const draft = {
322
+ ...args,
323
+ kind: args.kind === void 0 || args.kind === "report" ? "message" : args.kind
324
+ };
325
+ const result = await binding.mailbox.sendFromSession(sessionId, draft);
326
+ return sendResult(binding, result.message.id, result.deliveries);
327
+ }
328
+ }));
329
+ registry.register(defineTool({
330
+ name: "live_team_ack_message",
331
+ description: "Acknowledge the calling member's own delivery of a team message.",
332
+ parameters: { messageId: {
333
+ type: "string",
334
+ required: true
335
+ } },
336
+ output: {
337
+ schema: {
338
+ type: "object",
339
+ additionalProperties: false,
340
+ properties: {
341
+ acknowledged: {
342
+ type: "boolean",
343
+ required: true
344
+ },
345
+ messageId: {
346
+ type: "string",
347
+ required: true
348
+ }
349
+ }
350
+ },
351
+ render: (_args, value) => renderOutput(value)
352
+ },
353
+ execute: async (args, exec) => {
354
+ const binding = await resolve(sessionIdOf(exec));
355
+ if (binding === void 0) throw new Error("calling Session is not an active member of this team");
356
+ await binding.mailbox.acknowledge(args.messageId, binding.member.memberId);
357
+ return {
358
+ acknowledged: true,
359
+ messageId: args.messageId
360
+ };
361
+ }
362
+ }));
363
+ registry.register(defineTool({
364
+ name: "live_team_context",
365
+ description: "Read the bounded current team context for the calling member.",
366
+ parameters: {},
367
+ output: {
368
+ schema: {
369
+ type: "object",
370
+ additionalProperties: false,
371
+ properties: {
372
+ teamName: {
373
+ type: "string",
374
+ required: true
375
+ },
376
+ memberName: {
377
+ type: "string",
378
+ required: true
379
+ },
380
+ role: {
381
+ type: "string",
382
+ required: true
383
+ },
384
+ availability: {
385
+ type: "string",
386
+ required: true
387
+ },
388
+ members: {
389
+ type: "array",
390
+ required: true,
391
+ items: {
392
+ type: "object",
393
+ additionalProperties: false,
394
+ properties: {
395
+ memberId: {
396
+ type: "string",
397
+ required: true
398
+ },
399
+ name: {
400
+ type: "string",
401
+ required: true
402
+ },
403
+ role: {
404
+ type: "string",
405
+ required: true
406
+ },
407
+ availability: {
408
+ type: "string",
409
+ required: true
410
+ },
411
+ live: {
412
+ type: "boolean",
413
+ required: true
414
+ }
415
+ }
416
+ }
417
+ }
418
+ }
419
+ },
420
+ render: (_args, value) => renderOutput(value)
421
+ },
422
+ execute: async (_args, exec) => {
423
+ const binding = await resolve(sessionIdOf(exec));
424
+ if (binding === void 0) throw new Error("calling Session is not an active member of this team");
425
+ return memberContext(binding);
426
+ }
427
+ }));
428
+ if (includeContact) registry.register(defineTool({
429
+ name: "live_team_grant",
430
+ description: "List your permitted contacts, or ask the lead to grant/revoke a contact.",
431
+ parameters: {
432
+ action: {
433
+ type: "string",
434
+ required: true,
435
+ enum: [
436
+ "list",
437
+ "add",
438
+ "remove"
439
+ ]
440
+ },
441
+ memberId: { type: "string" },
442
+ allow: { type: "string" }
443
+ },
444
+ output: {
445
+ schema: {
446
+ type: "object",
447
+ additionalProperties: false,
448
+ properties: {
449
+ grants: {
450
+ type: "array",
451
+ required: true
452
+ },
453
+ leadMemberId: { type: "string" }
454
+ }
455
+ },
456
+ render: (_args, value) => renderOutput(value)
457
+ },
458
+ execute: async (args, exec) => {
459
+ const binding = await resolve(sessionIdOf(exec));
460
+ if (binding === void 0) throw new Error("calling Session is not an active member of this team");
461
+ const leadId = resolveLeadMemberId(binding.team);
462
+ const ownGrants = (binding.team.contactGrants ?? []).filter((grant) => grant.from === binding.member.memberId);
463
+ if (args.action === "list") return {
464
+ grants: ownGrants,
465
+ ...leadId === void 0 ? {} : { leadMemberId: leadId }
466
+ };
467
+ if (binding.member.memberId !== leadId) throw new Error(`only the lead may change contact grants; ask ${leadId ?? "the lead"}`);
468
+ if (typeof args.memberId !== "string" || args.memberId.length === 0 || typeof args.allow !== "string" || args.allow.length === 0) throw new Error("memberId and allow are required");
469
+ if (binding.updateContactGrant === void 0) throw new Error("contact grants are unavailable");
470
+ return binding.updateContactGrant(args.memberId, args.allow, args.action, binding.member.memberId);
471
+ }
472
+ }));
473
+ if (includeDispatch) registry.register(defineTool({
474
+ name: "live_team_dispatch",
475
+ description: "Pause or resume automatic dispatch for this team. Only the lead may change it. Pausing stops new work from starting: it never revokes a running attempt, never moves ownership, and never drops a message already queued for a member.",
476
+ parameters: {
477
+ mode: {
478
+ type: "string",
479
+ required: true,
480
+ enum: ["auto", "paused"]
481
+ },
482
+ reason: { type: "string" }
483
+ },
484
+ output: {
485
+ schema: {
486
+ type: "object",
487
+ additionalProperties: false,
488
+ properties: {
489
+ from: {
490
+ type: "string",
491
+ required: true
492
+ },
493
+ to: {
494
+ type: "string",
495
+ required: true
496
+ }
497
+ }
498
+ },
499
+ render: (_args, value) => renderOutput(value)
500
+ },
501
+ execute: async (args, exec) => {
502
+ const binding = await resolve(sessionIdOf(exec));
503
+ if (binding === void 0) throw new Error("calling Session is not an active member of this team");
504
+ const leadId = resolveLeadMemberId(binding.team);
505
+ if (binding.member.memberId !== leadId) throw new Error(`only the lead may pause or resume dispatch; ask ${leadId ?? "the lead"}`);
506
+ if (binding.setDispatch === void 0) throw new Error("dispatch is unavailable");
507
+ const result = await binding.setDispatch({
508
+ mode: args.mode,
509
+ actor: binding.member.memberId,
510
+ ...typeof args.reason === "string" && args.reason.trim().length > 0 ? { reason: args.reason.trim() } : {}
511
+ });
512
+ return {
513
+ from: result.from,
514
+ to: result.to
515
+ };
516
+ }
517
+ }));
518
+ if (includeTasks) {
519
+ registry.register(defineTool({
520
+ name: "live_team_create_task",
521
+ description: "Create a durable task. Only the team lead may create tasks.",
522
+ parameters: {
523
+ title: {
524
+ type: "string",
525
+ required: true
526
+ },
527
+ kind: {
528
+ type: "string",
529
+ required: true,
530
+ enum: [
531
+ "work",
532
+ "research",
533
+ "requirements",
534
+ "implementation",
535
+ "verification",
536
+ "review",
537
+ "repair",
538
+ "integration"
539
+ ]
540
+ },
541
+ assignee: { type: "string" },
542
+ route: {
543
+ type: "json",
544
+ description: "Where the finished work goes: {\"type\":\"review\",\"reviewer\":\"<member id>\"} or {\"type\":\"report\",\"to\":\"human\"}."
545
+ },
546
+ humanContact: {
547
+ type: "string",
548
+ enum: [
549
+ "none",
550
+ "expected",
551
+ "required"
552
+ ]
553
+ },
554
+ acceptance: {
555
+ type: "array",
556
+ required: true,
557
+ items: { type: "string" },
558
+ description: "What \"done\" means, each criterion checkable inside this task declared paths (e.g. \"node --test packages/alpha/test\"). A repository-wide criterion needs a declared dependency: a sibling task in flight makes it unsatisfiable."
559
+ },
560
+ checks: {
561
+ type: "array",
562
+ items: { type: "string" }
563
+ },
564
+ why: { type: "string" },
565
+ body: { type: "string" },
566
+ roundLimit: { type: "integer" },
567
+ dependsOn: {
568
+ type: "array",
569
+ items: { type: "string" }
570
+ },
571
+ paths: {
572
+ type: "array",
573
+ items: { type: "string" },
574
+ description: "Workspace-relative globs this task may touch. Two writing tasks with intersecting paths never run at the same time, so declare them for any task that writes code."
575
+ }
576
+ },
577
+ output: {
578
+ schema: {
579
+ type: "object",
580
+ additionalProperties: false,
581
+ properties: {
582
+ task: {
583
+ type: "json",
584
+ required: true
585
+ },
586
+ documentPath: {
587
+ type: "string",
588
+ required: true
589
+ }
590
+ }
591
+ },
592
+ render: (_args, value) => renderOutput(value)
593
+ },
594
+ execute: async (args, exec) => {
595
+ const binding = await resolve(sessionIdOf(exec));
596
+ if (binding === void 0) throw new Error("calling Session is not an active member of this team");
597
+ const leadId = resolveLeadMemberId(binding.team);
598
+ if (binding.member.memberId !== leadId) throw new Error(`only the lead may create tasks; ask ${leadId ?? "the lead"}`);
599
+ if (binding.taskStore === void 0) throw new Error("task store is unavailable");
600
+ return jsonCreateResult(await binding.taskStore.createTask({
601
+ ...args,
602
+ actor: binding.member.memberId
603
+ }));
604
+ }
605
+ }));
606
+ registry.register(defineTool({
607
+ name: "live_team_update_task",
608
+ description: "Edit the contract of a task you created: title, kind, assignee, route, acceptance, checks, why, body, round limit, human contact, dependencies, declared paths. Only the lead may update tasks, and only while nobody has started them (draft or ready). Absent fields are left alone; assignee, route, dependsOn and paths accept null to clear them.",
609
+ parameters: {
610
+ taskId: {
611
+ type: "string",
612
+ required: true
613
+ },
614
+ expectedRevision: { type: "integer" },
615
+ title: { type: "string" },
616
+ kind: {
617
+ type: "string",
618
+ enum: [
619
+ "work",
620
+ "research",
621
+ "requirements",
622
+ "implementation",
623
+ "verification",
624
+ "review",
625
+ "repair",
626
+ "integration"
627
+ ]
628
+ },
629
+ assignee: { type: "string" },
630
+ route: {
631
+ type: "json",
632
+ description: "Where the finished work goes: {\"type\":\"review\",\"reviewer\":\"<member id>\"} or {\"type\":\"report\",\"to\":\"human\"}."
633
+ },
634
+ humanContact: {
635
+ type: "string",
636
+ enum: [
637
+ "none",
638
+ "expected",
639
+ "required"
640
+ ]
641
+ },
642
+ acceptance: {
643
+ type: "array",
644
+ items: { type: "string" },
645
+ description: "What \"done\" means, each criterion checkable inside this task declared paths (e.g. \"node --test packages/alpha/test\"). A repository-wide criterion needs a declared dependency: a sibling task in flight makes it unsatisfiable."
646
+ },
647
+ checks: {
648
+ type: "array",
649
+ items: { type: "string" }
650
+ },
651
+ why: { type: "string" },
652
+ body: { type: "string" },
653
+ roundLimit: { type: "integer" },
654
+ dependsOn: {
655
+ type: "array",
656
+ items: { type: "string" }
657
+ },
658
+ paths: {
659
+ type: "array",
660
+ items: { type: "string" },
661
+ description: "Workspace-relative globs this task may touch; null clears the declaration."
662
+ }
663
+ },
664
+ output: {
665
+ schema: {
666
+ type: "object",
667
+ additionalProperties: false,
668
+ properties: {
669
+ task: {
670
+ type: "json",
671
+ required: true
672
+ },
673
+ document: {
674
+ type: "string",
675
+ required: true
676
+ },
677
+ changed: {
678
+ type: "array",
679
+ required: true,
680
+ items: { type: "string" }
681
+ }
682
+ }
683
+ },
684
+ render: (_args, value) => renderOutput(value)
685
+ },
686
+ execute: async (args, exec) => {
687
+ const binding = await resolve(sessionIdOf(exec));
688
+ if (binding === void 0) throw new Error("calling Session is not an active member of this team");
689
+ if (binding.taskStore === void 0) throw new Error("task store is unavailable");
690
+ const result = await binding.taskStore.updateTask({
691
+ ...args,
692
+ actor: binding.member.memberId
693
+ });
694
+ return {
695
+ task: jsonRecord(result.task),
696
+ document: result.document,
697
+ changed: [...result.changed]
698
+ };
699
+ }
700
+ }));
701
+ registry.register(defineTool({
702
+ name: "live_team_revoke_task",
703
+ description: "Take a task away from the member working on it: invalidate their attempt, stop their Session, and return the task to ready (optionally for a new assignee). Only the lead may revoke. If the Session cannot be observed to have stopped, the task goes to needs_human instead of pretending it was revoked.",
704
+ parameters: {
705
+ taskId: {
706
+ type: "string",
707
+ required: true
708
+ },
709
+ reason: {
710
+ type: "string",
711
+ required: true
712
+ },
713
+ nextAssignee: { type: "string" },
714
+ expectedRevision: { type: "integer" }
715
+ },
716
+ output: {
717
+ schema: {
718
+ type: "object",
719
+ additionalProperties: false,
720
+ properties: {
721
+ task: {
722
+ type: "json",
723
+ required: true
724
+ },
725
+ attempt: {
726
+ type: "json",
727
+ required: true
728
+ },
729
+ quiesced: {
730
+ type: "boolean",
731
+ required: true
732
+ },
733
+ reassigned: {
734
+ type: "boolean",
735
+ required: true
736
+ }
737
+ }
738
+ },
739
+ render: (_args, value) => renderOutput(value)
740
+ },
741
+ execute: async (args, exec) => {
742
+ const binding = await resolve(sessionIdOf(exec));
743
+ if (binding === void 0) throw new Error("calling Session is not an active member of this team");
744
+ if (binding.taskStore === void 0) throw new Error("task store is unavailable");
745
+ const result = await binding.taskStore.revokeTask({
746
+ ...args,
747
+ actor: binding.member.memberId
748
+ });
749
+ return {
750
+ task: jsonRecord(result.task),
751
+ attempt: jsonRecord(result.attempt),
752
+ quiesced: result.quiesced,
753
+ reassigned: result.reassigned
754
+ };
755
+ }
756
+ }));
757
+ registry.register(defineTool({
758
+ name: "live_team_read_task",
759
+ description: "Read a durable task and its authored document.",
760
+ parameters: { taskId: {
761
+ type: "string",
762
+ required: true
763
+ } },
764
+ output: {
765
+ schema: {
766
+ type: "object",
767
+ additionalProperties: false,
768
+ properties: {
769
+ task: {
770
+ type: "json",
771
+ required: true
772
+ },
773
+ document: {
774
+ type: "string",
775
+ required: true
776
+ },
777
+ submissions: {
778
+ type: "array",
779
+ required: true
780
+ },
781
+ rounds: {
782
+ type: "array",
783
+ required: true
784
+ }
785
+ }
786
+ },
787
+ render: (_args, value) => renderOutput(value)
788
+ },
789
+ execute: async (args, exec) => {
790
+ const binding = await resolve(sessionIdOf(exec));
791
+ if (binding === void 0) throw new Error("calling Session is not an active member of this team");
792
+ if (binding.taskStore === void 0) throw new Error("task store is unavailable");
793
+ return jsonReadResult(await binding.taskStore.readTask(args.taskId));
794
+ }
795
+ }));
796
+ registry.register(defineTool({
797
+ name: "live_team_list_tasks",
798
+ description: "List durable tasks for this team, newest first; archived tasks are hidden unless requested.",
799
+ parameters: { includeArchived: { type: "boolean" } },
800
+ output: {
801
+ schema: {
802
+ type: "object",
803
+ additionalProperties: false,
804
+ properties: { tasks: {
805
+ type: "array",
806
+ required: true,
807
+ items: {
808
+ type: "object",
809
+ additionalProperties: true,
810
+ properties: { documentMissing: { type: "boolean" } }
811
+ }
812
+ } }
813
+ },
814
+ render: (_args, value) => renderOutput(value)
815
+ },
816
+ execute: async (args, exec) => {
817
+ const binding = await resolve(sessionIdOf(exec));
818
+ if (binding === void 0) throw new Error("calling Session is not an active member of this team");
819
+ if (binding.taskStore === void 0) throw new Error("task store is unavailable");
820
+ return jsonListedTasks({ tasks: await binding.taskStore.listTasks({ includeArchived: args.includeArchived === true }) });
821
+ }
822
+ }));
823
+ if (includeSubmissions) {
824
+ registry.register(defineTool({
825
+ name: "live_team_claim_task",
826
+ description: "Claim your assigned ready task and create its active attempt.",
827
+ parameters: { taskId: {
828
+ type: "string",
829
+ required: true
830
+ } },
831
+ output: {
832
+ schema: {
833
+ type: "object",
834
+ additionalProperties: false,
835
+ properties: {
836
+ task: {
837
+ type: "json",
838
+ required: true
839
+ },
840
+ attempt: {
841
+ type: "json",
842
+ required: true
843
+ }
844
+ }
845
+ },
846
+ render: (_args, value) => renderOutput(value)
847
+ },
848
+ execute: async (args, exec) => {
849
+ const binding = await resolve(sessionIdOf(exec));
850
+ if (binding === void 0) throw new Error("calling Session is not an active member of this team");
851
+ if (binding.taskStore === void 0) throw new Error("task store is unavailable");
852
+ const result = await binding.taskStore.claimTask({
853
+ taskId: args.taskId,
854
+ memberId: binding.member.memberId,
855
+ sessionId: binding.member.sessionId ?? sessionIdOf(exec),
856
+ bindingGeneration: binding.member.bindingGeneration
857
+ });
858
+ return {
859
+ task: jsonRecord(result.task),
860
+ attempt: jsonRecord(result.attempt)
861
+ };
862
+ }
863
+ }));
864
+ registry.register(defineTool({
865
+ name: "live_team_ack_task",
866
+ description: "Acknowledge your claimed task and move it into progress.",
867
+ parameters: { taskId: {
868
+ type: "string",
869
+ required: true
870
+ } },
871
+ output: {
872
+ schema: {
873
+ type: "object",
874
+ additionalProperties: false,
875
+ properties: { task: {
876
+ type: "json",
877
+ required: true
878
+ } }
879
+ },
880
+ render: (_args, value) => renderOutput(value)
881
+ },
882
+ execute: async (args, exec) => {
883
+ const binding = await resolve(sessionIdOf(exec));
884
+ if (binding === void 0) throw new Error("calling Session is not an active member of this team");
885
+ if (binding.taskStore === void 0) throw new Error("task store is unavailable");
886
+ return { task: jsonRecord((await binding.taskStore.acknowledgeTask({
887
+ taskId: args.taskId,
888
+ memberId: binding.member.memberId,
889
+ sessionId: sessionIdOf(exec),
890
+ bindingGeneration: binding.member.bindingGeneration
891
+ })).task) };
892
+ }
893
+ }));
894
+ }
895
+ }
896
+ if (includeReview) {
897
+ registry.register(defineTool({
898
+ name: "live_team_submit",
899
+ description: "Submit an immutable report or file artifact for the active task attempt. A refusal here changes nothing about the task.",
900
+ parameters: {
901
+ taskId: {
902
+ type: "string",
903
+ required: true
904
+ },
905
+ artifact: {
906
+ type: "json",
907
+ required: true,
908
+ description: "Exactly one of two shapes, with exactly these keys: {\"type\":\"report\",\"bodyRef\":\"<workspace-relative path to the report you wrote>\"} or {\"type\":\"files\",\"paths\":[\"<workspace-relative path>\", \"...\"]}. `type` is required; no other keys are accepted. Write a report body under .dsh-live-teams/reports/<task-id>.md, never in the repository root: the root is the integration tree."
909
+ },
910
+ summary: {
911
+ type: "string",
912
+ required: true,
913
+ description: "One or two sentences: what you changed and what you observed."
914
+ },
915
+ checks: {
916
+ type: "array",
917
+ items: { type: "json" },
918
+ description: "The checks you actually ran: [{\"command\":\"npm test\",\"status\":\"passed\" | \"failed\",\"output\":\"<short tail>\"}]. Each entry needs `command` and `status`."
919
+ }
920
+ },
921
+ output: {
922
+ schema: {
923
+ type: "object",
924
+ additionalProperties: false,
925
+ properties: { submission: {
926
+ type: "json",
927
+ required: true
928
+ } }
929
+ },
930
+ render: (_args, value) => renderOutput(value)
931
+ },
932
+ execute: async (args, exec) => {
933
+ const sessionId = sessionIdOf(exec);
934
+ const binding = await resolve(sessionId);
935
+ if (binding === void 0) throw new Error("calling Session is not an active member of this team");
936
+ if (binding.taskStore === void 0) throw new Error("task store is unavailable");
937
+ const shape = args.artifact === null || typeof args.artifact !== "object" ? String(args.artifact) : Object.keys(args.artifact).join(", ");
938
+ if (args.artifact?.type === "report" && typeof args.artifact.bodyRef !== "string") throw new Error(`artifact {"type":"report"} needs a string "bodyRef"; received keys: ${shape}. Accepted shapes: {"type":"report","bodyRef":"<path>"} or {"type":"files","paths":["<path>", "…"]}`);
939
+ if (args.artifact?.type === "files" && (!Array.isArray(args.artifact.paths) || args.artifact.paths.length === 0 || !args.artifact.paths.every((entry) => typeof entry === "string"))) throw new Error(`artifact {"type":"files"} needs a non-empty "paths" array of strings; received keys: ${shape}. Accepted shapes: {"type":"files","paths":["<path>", "…"]} or {"type":"report","bodyRef":"<path>"}`);
940
+ if (args.artifact?.type !== "report" && args.artifact?.type !== "files") throw new Error(`artifact must declare its shape with "type":"report" or "type":"files"; received keys: ${shape}. Accepted shapes: {"type":"report","bodyRef":"<path>"} or {"type":"files","paths":["<path>", "…"]}`);
941
+ const artifact = args.artifact.type === "report" ? {
942
+ type: "report",
943
+ bodyRef: args.artifact.bodyRef
944
+ } : {
945
+ type: "files",
946
+ paths: args.artifact.paths
947
+ };
948
+ return { submission: jsonRecord((await binding.taskStore.submitTask({
949
+ taskId: args.taskId,
950
+ memberId: binding.member.memberId,
951
+ sessionId,
952
+ bindingGeneration: binding.member.bindingGeneration,
953
+ artifact,
954
+ summary: args.summary,
955
+ checks: args.checks ?? []
956
+ })).submission) };
957
+ }
958
+ }));
959
+ registry.register(defineTool({
960
+ name: "live_team_review",
961
+ description: "Reviewer only. Review the latest immutable task submission with a terminal verdict. A pass must record at least one check — the command you ran and what it printed — because a verdict that names no command cannot be reproduced; an inspection counts, so record what you looked at.",
962
+ parameters: {
963
+ taskId: {
964
+ type: "string",
965
+ required: true
966
+ },
967
+ submissionId: {
968
+ type: "string",
969
+ required: true
970
+ },
971
+ verdict: {
972
+ type: "string",
973
+ required: true,
974
+ enum: [
975
+ "pass",
976
+ "needs_revision",
977
+ "escalate"
978
+ ]
979
+ },
980
+ findings: {
981
+ type: "array",
982
+ items: { type: "json" },
983
+ description: "One entry per problem: [{\"severity\":\"low\" | \"medium\" | \"high\" | \"blocker\",\"problem\":\"…\",\"requiredFix\":\"…\",\"artifactLocation\":\"<optional path>\"}]. Required for a verdict other than pass."
984
+ },
985
+ evidence: {
986
+ type: "array",
987
+ items: { type: "json" },
988
+ description: "What you ran while judging: [{\"command\":\"npm test\",\"status\":\"passed\" | \"failed\",\"output\":\"<short tail>\"}]."
989
+ }
990
+ },
991
+ output: {
992
+ schema: {
993
+ type: "object",
994
+ additionalProperties: false,
995
+ properties: {
996
+ round: {
997
+ type: "json",
998
+ required: true
999
+ },
1000
+ task: {
1001
+ type: "json",
1002
+ required: true
1003
+ }
1004
+ }
1005
+ },
1006
+ render: (_args, value) => renderOutput(value)
1007
+ },
1008
+ execute: async (args, exec) => {
1009
+ const binding = await resolve(sessionIdOf(exec));
1010
+ if (binding === void 0) throw new Error("calling Session is not an active member of this team");
1011
+ if (binding.taskStore === void 0) throw new Error("task store is unavailable");
1012
+ const result = await binding.taskStore.reviewTask({
1013
+ taskId: args.taskId,
1014
+ submissionId: args.submissionId,
1015
+ reviewerMemberId: binding.member.memberId,
1016
+ verdict: args.verdict,
1017
+ findings: args.findings ?? [],
1018
+ evidence: args.evidence ?? []
1019
+ });
1020
+ return {
1021
+ round: jsonRecord(result.round),
1022
+ task: jsonRecord(result.task)
1023
+ };
1024
+ }
1025
+ }));
1026
+ }
1027
+ if (includeAcceptance) {
1028
+ registry.register(defineTool({
1029
+ name: "live_team_accept_task",
1030
+ description: "Accept a waiting task as the team lead and archive its authored document.",
1031
+ parameters: {
1032
+ taskId: {
1033
+ type: "string",
1034
+ required: true
1035
+ },
1036
+ note: { type: "string" }
1037
+ },
1038
+ output: {
1039
+ schema: {
1040
+ type: "object",
1041
+ additionalProperties: false,
1042
+ properties: {
1043
+ task: {
1044
+ type: "json",
1045
+ required: true
1046
+ },
1047
+ archivedPath: {
1048
+ type: "string",
1049
+ required: true
1050
+ }
1051
+ }
1052
+ },
1053
+ render: (_args, value) => renderOutput(value)
1054
+ },
1055
+ execute: async (args, exec) => {
1056
+ const binding = await resolve(sessionIdOf(exec));
1057
+ if (binding === void 0) throw new Error("calling Session is not an active member of this team");
1058
+ if (binding.taskStore === void 0) throw new Error("task store is unavailable");
1059
+ const leadId = resolveLeadMemberId(binding.team);
1060
+ if (binding.member.memberId !== leadId) throw new Error(`only the lead may accept tasks; ask ${leadId ?? "the lead"}`);
1061
+ const result = await binding.taskStore.acceptTask({
1062
+ taskId: args.taskId,
1063
+ actor: binding.member.memberId,
1064
+ ...args.note === void 0 ? {} : { note: args.note }
1065
+ });
1066
+ return {
1067
+ task: jsonRecord(result.task),
1068
+ archivedPath: result.archivedPath
1069
+ };
1070
+ }
1071
+ }));
1072
+ registry.register(defineTool({
1073
+ name: "live_team_revise_task",
1074
+ description: "Return a waiting task to progress with high-priority instructions for its assignee.",
1075
+ parameters: {
1076
+ taskId: {
1077
+ type: "string",
1078
+ required: true
1079
+ },
1080
+ instructions: {
1081
+ type: "string",
1082
+ required: true
1083
+ }
1084
+ },
1085
+ output: {
1086
+ schema: {
1087
+ type: "object",
1088
+ additionalProperties: false,
1089
+ properties: { task: {
1090
+ type: "json",
1091
+ required: true
1092
+ } }
1093
+ },
1094
+ render: (_args, value) => renderOutput(value)
1095
+ },
1096
+ execute: async (args, exec) => {
1097
+ const binding = await resolve(sessionIdOf(exec));
1098
+ if (binding === void 0) throw new Error("calling Session is not an active member of this team");
1099
+ if (binding.taskStore === void 0) throw new Error("task store is unavailable");
1100
+ const leadId = resolveLeadMemberId(binding.team);
1101
+ if (binding.member.memberId !== leadId) throw new Error(`only the lead may revise tasks; ask ${leadId ?? "the lead"}`);
1102
+ return { task: jsonRecord((await binding.taskStore.reviseTask({
1103
+ taskId: args.taskId,
1104
+ actor: binding.member.memberId,
1105
+ instructions: args.instructions
1106
+ })).task) };
1107
+ }
1108
+ }));
1109
+ }
1110
+ if (includeContext) registry.register(defineTool({
1111
+ name: "live_team_brief",
1112
+ description: "Read or update the team briefing. Only the team lead may update it.",
1113
+ parameters: {
1114
+ action: {
1115
+ type: "string",
1116
+ required: true,
1117
+ enum: ["read", "update"]
1118
+ },
1119
+ text: { type: "string" }
1120
+ },
1121
+ output: {
1122
+ schema: {
1123
+ type: "object",
1124
+ additionalProperties: false,
1125
+ properties: {
1126
+ text: { type: "string" },
1127
+ saved: { type: "boolean" },
1128
+ length: { type: "number" }
1129
+ }
1130
+ },
1131
+ render: (_args, value) => renderOutput(value)
1132
+ },
1133
+ execute: async (args, exec) => {
1134
+ const binding = await resolve(sessionIdOf(exec));
1135
+ if (binding === void 0) throw new Error("calling Session is not an active member of this team");
1136
+ const leadId = resolveLeadMemberId(binding.team);
1137
+ if (args.action === "read") {
1138
+ if (binding.workspacePath === void 0) return { text: "" };
1139
+ try {
1140
+ return { text: await readFile(path.join(binding.workspacePath, ".dsh-live-teams", "BRIEF.md"), "utf8") };
1141
+ } catch {
1142
+ return { text: "" };
1143
+ }
1144
+ }
1145
+ if (binding.member.memberId !== leadId) throw new Error("briefing is owned by the lead; ask the lead to update it");
1146
+ if (typeof args.text !== "string") throw new Error("text is required for update");
1147
+ const next = args.text.trim().slice(0, 8e3);
1148
+ if (binding.workspacePath === void 0) throw new Error("team workspace is unavailable");
1149
+ await mkdir(path.join(binding.workspacePath, ".dsh-live-teams"), { recursive: true });
1150
+ const file = path.join(binding.workspacePath, ".dsh-live-teams", "BRIEF.md");
1151
+ if (next.length === 0) await writeFile(file, "", "utf8");
1152
+ else await writeFile(file, next, "utf8");
1153
+ await binding.appendAudit?.({
1154
+ kind: "briefing/updated",
1155
+ actor: binding.member.memberId,
1156
+ length: next.length,
1157
+ at: Date.now()
1158
+ });
1159
+ return {
1160
+ saved: true,
1161
+ length: next.length
1162
+ };
1163
+ }
1164
+ }));
1165
+ if (includeContext) registry.register(defineTool({
1166
+ name: "live_team_member_note",
1167
+ description: "Set a member note. Only the team lead may update notes.",
1168
+ parameters: {
1169
+ memberId: {
1170
+ type: "string",
1171
+ required: true
1172
+ },
1173
+ note: {
1174
+ type: "string",
1175
+ required: true
1176
+ }
1177
+ },
1178
+ output: {
1179
+ schema: {
1180
+ type: "object",
1181
+ additionalProperties: false,
1182
+ properties: {
1183
+ memberId: {
1184
+ type: "string",
1185
+ required: true
1186
+ },
1187
+ note: {
1188
+ type: "string",
1189
+ required: true
1190
+ }
1191
+ }
1192
+ },
1193
+ render: (_args, value) => renderOutput(value)
1194
+ },
1195
+ execute: async (args, exec) => {
1196
+ const binding = await resolve(sessionIdOf(exec));
1197
+ if (binding === void 0) throw new Error("calling Session is not an active member of this team");
1198
+ const leadId = resolveLeadMemberId(binding.team);
1199
+ if (binding.member.memberId !== leadId) throw new Error("briefing is owned by the lead; ask the lead to update the member note");
1200
+ if (binding.team.members.find((entry) => entry.memberId === args.memberId) === void 0) throw new Error("member not found");
1201
+ const note = args.note.trim().slice(0, 200);
1202
+ if (binding.setMemberNote !== void 0) await binding.setMemberNote(args.memberId, note, binding.member.memberId);
1203
+ await binding.appendAudit?.({
1204
+ kind: "member/note",
1205
+ memberId: args.memberId,
1206
+ note,
1207
+ actor: binding.member.memberId,
1208
+ at: Date.now()
1209
+ });
1210
+ return {
1211
+ memberId: args.memberId,
1212
+ note
1213
+ };
1214
+ }
1215
+ }));
1216
+ registry.register(defineTool({
1217
+ name: "live_team_status",
1218
+ description: "Read the calling member current binding and contract status.",
1219
+ parameters: {},
1220
+ output: {
1221
+ schema: {
1222
+ type: "object",
1223
+ additionalProperties: false,
1224
+ properties: {
1225
+ memberId: {
1226
+ type: "string",
1227
+ required: true
1228
+ },
1229
+ teamId: {
1230
+ type: "string",
1231
+ required: true
1232
+ },
1233
+ role: {
1234
+ type: "string",
1235
+ required: true
1236
+ },
1237
+ availability: {
1238
+ type: "string",
1239
+ required: true
1240
+ },
1241
+ bindingGeneration: {
1242
+ type: "number",
1243
+ required: true
1244
+ },
1245
+ contractRevision: {
1246
+ type: "number",
1247
+ required: true
1248
+ },
1249
+ live: {
1250
+ type: "boolean",
1251
+ required: true
1252
+ }
1253
+ }
1254
+ },
1255
+ render: (_args, value) => renderOutput(value)
1256
+ },
1257
+ execute: async (_args, exec) => {
1258
+ const binding = await resolve(sessionIdOf(exec));
1259
+ if (binding === void 0) throw new Error("calling Session is not an active member of this team");
1260
+ return memberStatus(binding);
1261
+ }
1262
+ }));
1263
+ }
1264
+ //#endregion
1265
+ export { MEMBER_TOOL_NAMES, registerMemberTools, registerMemberToolsIfAvailable, toolsForRole };