@rync/moorline-discord-default 0.0.2 → 0.0.4

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.
@@ -4,29 +4,20 @@ import { createRequire as __moorlineCreateRequire } from 'node:module'; const re
4
4
  var manifest_default = {
5
5
  id: "rync/discord-runtime",
6
6
  name: "rync/discord-runtime",
7
- version: "0.0.2",
7
+ version: "0.0.4",
8
8
  type: "plugin",
9
9
  description: "Discord runtime commands and message routing for Moorline.",
10
10
  entrypoint: "index.mjs",
11
11
  priority: 100,
12
12
  capabilities: [
13
- "runtime.control",
14
- "memory.read",
15
13
  "transport.message.send",
16
- "transport.resource.create",
17
- "transport.resource.update",
18
- "transport.resource.delete",
19
- "net.connect",
20
14
  "fs.read",
21
15
  "session.inspect",
22
- "session.create",
23
- "session.archive",
24
- "session.delete"
16
+ "provider.headless.run"
25
17
  ],
26
18
  hooks: [
27
19
  "onAction",
28
- "onDomainEvent",
29
- "onTransportEvent"
20
+ "onTransportIntent"
30
21
  ],
31
22
  defaultEnabled: true,
32
23
  dependencies: [
@@ -39,458 +30,9 @@ var manifest_default = {
39
30
  ]
40
31
  };
41
32
 
42
- // packages/discord-runtime/modules/shared.mjs
43
- function discordAction(id, title, commandName, commandDescription, subcommandName, subcommandDescription, options, policy) {
44
- if (Array.isArray(subcommandName) || subcommandName === void 0 && subcommandDescription && typeof subcommandDescription === "object" && !Array.isArray(subcommandDescription)) {
45
- policy = subcommandDescription;
46
- options = subcommandName;
47
- subcommandDescription = void 0;
48
- subcommandName = void 0;
49
- }
50
- return {
51
- id,
52
- title,
53
- description: subcommandDescription ?? commandDescription,
54
- ...policy ? { policy } : {},
55
- metadata: {
56
- discordCommand: {
57
- commandName,
58
- commandDescription,
59
- ...subcommandName ? { subcommandName } : {},
60
- ...subcommandDescription ? { subcommandDescription } : {},
61
- ...options ? { options } : {}
62
- }
63
- }
64
- };
65
- }
66
- function stringOption(input, key) {
67
- const value = input[key];
68
- return typeof value === "string" ? value.trim() : "";
69
- }
70
- function toRuntimeReply(payload) {
71
- const blocks = (payload.embeds ?? []).map((embed) => ({
72
- kind: "fields",
73
- ...embed.title ? { title: embed.title } : {},
74
- ...embed.description ? { text: embed.description } : {},
75
- ...embed.fields ? {
76
- fields: embed.fields.map((field) => ({
77
- label: field.name,
78
- value: field.value,
79
- ...field.inline !== void 0 ? { inline: field.inline } : {}
80
- }))
81
- } : {}
82
- }));
83
- return {
84
- ...payload.content ? { text: payload.content } : {},
85
- ...blocks.length > 0 ? { blocks } : {}
86
- };
87
- }
88
- async function reply(event, payload) {
89
- const native = event.native?.payload;
90
- if (native && typeof native === "object" && typeof native.reply === "function") {
91
- await native.reply(payload);
92
- return { handled: true };
93
- }
94
- return { handled: true, reply: toRuntimeReply(payload) };
95
- }
96
- async function defer(event, payload) {
97
- const native = event.native?.payload;
98
- if (native && typeof native === "object" && typeof native.defer === "function") {
99
- await native.defer(payload);
100
- }
101
- }
102
- function isMissingPermissions(error) {
103
- return !!error && typeof error === "object" && error.code === 50013;
104
- }
105
- function workspaceDisplay(sessionId) {
106
- return `runtime/workspaces/${sessionId}`;
107
- }
108
-
109
- // packages/discord-runtime/modules/admin-control/index.mjs
110
- function currentThreadIdOrNull(context, transportResourceId) {
111
- return context.getSessionByTransportResourceId(transportResourceId)?.threadId ?? null;
112
- }
113
- var admin_control_default = {
114
- id: manifest_default.id,
115
- manifest: manifest_default,
116
- actions() {
117
- return [
118
- discordAction(
119
- "runtime.admin.status",
120
- "Admin status",
121
- "admin",
122
- "Administrative runtime controls",
123
- "status",
124
- "Show runtime control state",
125
- void 0,
126
- { allowedWhileDraining: true, bypassQueue: true }
127
- ),
128
- discordAction(
129
- "runtime.admin.reload",
130
- "Reload runtime",
131
- "admin",
132
- "Administrative runtime controls",
133
- "reload",
134
- "Reload the runtime worker",
135
- [
136
- {
137
- type: "string",
138
- name: "mode",
139
- description: "Reload mode",
140
- required: true,
141
- choices: [
142
- { name: "graceful", value: "graceful" },
143
- { name: "force", value: "force" }
144
- ]
145
- }
146
- ],
147
- { allowedWhileDraining: true, bypassQueue: true }
148
- ),
149
- discordAction(
150
- "runtime.admin.provider-stop",
151
- "Stop provider sessions",
152
- "admin",
153
- "Administrative runtime controls",
154
- "provider-stop",
155
- "Stop provider sessions",
156
- [
157
- {
158
- type: "string",
159
- name: "scope",
160
- description: "Whether to stop all sessions or only the current session",
161
- required: true,
162
- choices: [
163
- { name: "all", value: "all" },
164
- { name: "current", value: "current" }
165
- ]
166
- }
167
- ],
168
- { allowedWhileDraining: true, bypassQueue: true }
169
- ),
170
- discordAction(
171
- "runtime.admin.provider-start",
172
- "Recover provider sessions",
173
- "admin",
174
- "Administrative runtime controls",
175
- "provider-start",
176
- "Recover provider sessions",
177
- [
178
- {
179
- type: "string",
180
- name: "scope",
181
- description: "Whether to recover all sessions or only the current session",
182
- required: true,
183
- choices: [
184
- { name: "all", value: "all" },
185
- { name: "current", value: "current" }
186
- ]
187
- }
188
- ],
189
- { allowedWhileDraining: true, bypassQueue: true }
190
- ),
191
- discordAction(
192
- "runtime.admin.accepting",
193
- "Toggle accepting work",
194
- "admin",
195
- "Administrative runtime controls",
196
- "accepting",
197
- "Enable or disable acceptance of new work",
198
- [
199
- {
200
- type: "string",
201
- name: "value",
202
- description: "Whether the runtime should accept new work",
203
- required: true,
204
- choices: [
205
- { name: "true", value: "true" },
206
- { name: "false", value: "false" }
207
- ]
208
- }
209
- ],
210
- { allowedWhileDraining: true, bypassQueue: true }
211
- )
212
- ];
213
- },
214
- async onAction(event, context) {
215
- if (!event.actionId.startsWith("runtime.admin.")) {
216
- return { handled: false };
217
- }
218
- const requestedBy = event.actor;
219
- if (!context.isAdminActor(requestedBy)) {
220
- context.appendAuditEvent("runtime.admin.denied", {
221
- actionId: event.actionId,
222
- requestedBy: requestedBy.actorId,
223
- accessGroupIds: requestedBy.accessGroupIds ?? [],
224
- isSurfaceAdmin: requestedBy.isSurfaceAdmin === true
225
- });
226
- return await reply(event, {
227
- content: "This command is restricted to Moorline admins.",
228
- ephemeral: true
229
- });
230
- }
231
- if (event.actionId === "runtime.admin.status") {
232
- const control = context.getRuntimeControlStatus();
233
- const runtime = context.getRuntimeStatus();
234
- return await reply(event, {
235
- content: "Moorline admin status",
236
- embeds: [
237
- {
238
- title: "Runtime Control",
239
- color: 3447003,
240
- fields: [
241
- { name: "Supervised", value: control.supervised ? "yes" : "no", inline: true },
242
- { name: "Accepting Work", value: control.acceptingNewWork ? "yes" : "no", inline: true },
243
- { name: "Running Sessions", value: String(runtime.runningSessions), inline: true },
244
- { name: "Waiting Sessions", value: String(runtime.waitingSessions), inline: true }
245
- ],
246
- timestamp: context.nowIso()
247
- }
248
- ],
249
- ephemeral: true
250
- });
251
- }
252
- if (event.actionId === "runtime.admin.reload") {
253
- const mode = stringOption(event.input, "mode") === "force" ? "force" : "graceful";
254
- const result = await context.requestRuntimeReload({
255
- mode,
256
- reason: `Discord admin request from ${requestedBy.actorId}`,
257
- requestedBy
258
- });
259
- context.appendAuditEvent("runtime.reload.requested.by-admin", {
260
- requestedBy: requestedBy.actorId,
261
- mode
262
- });
263
- return await reply(event, {
264
- content: result.detail,
265
- ephemeral: true
266
- });
267
- }
268
- if (event.actionId === "runtime.admin.provider-stop") {
269
- const threadId = stringOption(event.input, "scope") === "current" && event.transportResourceId ? currentThreadIdOrNull(context, event.transportResourceId) : null;
270
- if (stringOption(event.input, "scope") === "current" && !threadId) {
271
- return await reply(event, {
272
- content: "This resource does not map to an active Moorline session.",
273
- ephemeral: true
274
- });
275
- }
276
- await context.stopProvider({
277
- ...threadId ? { threadId } : {},
278
- reason: `Discord admin request from ${requestedBy.actorId}`,
279
- requestedBy
280
- });
281
- return await reply(event, {
282
- content: threadId ? `Stopped provider session ${threadId}.` : "Stopped all provider sessions.",
283
- ephemeral: true
284
- });
285
- }
286
- if (event.actionId === "runtime.admin.provider-start") {
287
- const threadId = stringOption(event.input, "scope") === "current" && event.transportResourceId ? currentThreadIdOrNull(context, event.transportResourceId) : null;
288
- if (stringOption(event.input, "scope") === "current" && !threadId) {
289
- return await reply(event, {
290
- content: "This resource does not map to an active Moorline session.",
291
- ephemeral: true
292
- });
293
- }
294
- await context.startProvider({
295
- ...threadId ? { threadId } : {},
296
- reason: `Discord admin request from ${requestedBy.actorId}`,
297
- requestedBy
298
- });
299
- return await reply(event, {
300
- content: threadId ? `Recovered provider session ${threadId}.` : "Recovered all provider sessions.",
301
- ephemeral: true
302
- });
303
- }
304
- if (event.actionId === "runtime.admin.accepting") {
305
- const accepting = stringOption(event.input, "value") === "true";
306
- await context.setRuntimeAcceptingNewWork({
307
- accepting,
308
- reason: `Discord admin request from ${requestedBy.actorId}`,
309
- requestedBy
310
- });
311
- return await reply(event, {
312
- content: accepting ? "Runtime is now accepting new work." : "Runtime is no longer accepting new work.",
313
- ephemeral: true
314
- });
315
- }
316
- return await reply(event, {
317
- content: `Unsupported admin action: ${event.actionId}`,
318
- ephemeral: true
319
- });
320
- }
321
- };
322
-
323
- // packages/discord-runtime/modules/channel-lifecycle/index.mjs
324
- function summarizeArchivedTarget(target) {
325
- return {
326
- id: target.session.sessionId,
327
- transportResourceId: target.session.transportResourceId,
328
- workspacePath: target.session.workspacePath
329
- };
330
- }
331
- var channel_lifecycle_default = {
332
- id: manifest_default.id,
333
- manifest: manifest_default,
334
- actions() {
335
- return [
336
- discordAction(
337
- "resource.archive",
338
- "Archive the current Moorline session resource",
339
- "archive",
340
- "Archive the current Moorline session resource",
341
- void 0,
342
- { allowedWhileDraining: true, bypassQueue: true }
343
- ),
344
- discordAction(
345
- "resource.delete",
346
- "Delete the current archived Moorline session resource",
347
- "delete",
348
- "Delete the current archived Moorline session resource",
349
- [
350
- {
351
- type: "string",
352
- name: "confirm",
353
- description: "Type delete to confirm destructive removal",
354
- required: true,
355
- choices: [{ name: "delete", value: "delete" }]
356
- }
357
- ],
358
- { allowedWhileDraining: true, bypassQueue: true }
359
- )
360
- ];
361
- },
362
- async onAction(event, context) {
363
- if (event.actionId === "resource.archive") {
364
- if (!event.transportResourceId) {
365
- return await reply(event, { content: "This action requires a target resource.", ephemeral: true });
366
- }
367
- try {
368
- const archived = await context.archiveTransportResourceTarget({ transportResourceId: event.transportResourceId });
369
- if (!archived) {
370
- return await reply(event, {
371
- content: "This resource is not an archivable Moorline session.",
372
- ephemeral: true
373
- });
374
- }
375
- const target = summarizeArchivedTarget(archived);
376
- await context.sendMessage(target.transportResourceId, {
377
- text: "Session archived. Use `/delete confirm:delete` to remove the local workspace.",
378
- blocks: [
379
- {
380
- kind: "fields",
381
- title: "Session Archived",
382
- tone: "warning",
383
- fields: [
384
- { label: "Session", value: target.id },
385
- { label: "Workspace", value: workspaceDisplay(target.id) }
386
- ]
387
- }
388
- ]
389
- });
390
- await context.sendStatusUpdate({
391
- text: `Archived session ${target.id} from ${target.transportResourceId}.`,
392
- blocks: [
393
- {
394
- kind: "fields",
395
- title: "Session Archived",
396
- tone: "warning",
397
- fields: [
398
- { label: "Session", value: target.id },
399
- { label: "Resource", value: target.transportResourceId }
400
- ]
401
- }
402
- ]
403
- });
404
- context.appendAuditEvent("session.archived", {
405
- sessionId: target.id,
406
- transportResourceId: target.transportResourceId,
407
- pluginId: manifest_default.id
408
- });
409
- return await reply(event, {
410
- content: `Archived session ${target.id}.`,
411
- ephemeral: true
412
- });
413
- } catch (error) {
414
- if (!isMissingPermissions(error)) throw error;
415
- return await reply(event, {
416
- content: "Archive failed: Moorline needs permission to update the current resource and archive area.",
417
- ephemeral: true
418
- });
419
- }
420
- }
421
- if (event.actionId === "resource.delete") {
422
- if (!event.transportResourceId) {
423
- return await reply(event, { content: "This action requires a target resource.", ephemeral: true });
424
- }
425
- if (stringOption(event.input, "confirm") !== "delete") {
426
- return await reply(event, {
427
- content: "Deletion cancelled: pass confirm:delete to remove the archived resource.",
428
- ephemeral: true
429
- });
430
- }
431
- const session = context.getSessionByTransportResourceId(event.transportResourceId);
432
- if (session && session.lifecycleStatus !== "archived") {
433
- return await reply(event, {
434
- content: `Session ${session.sessionId} must be archived before deletion.`,
435
- ephemeral: true
436
- });
437
- }
438
- if (!session) {
439
- return await reply(event, {
440
- content: "This resource is not a deletable Moorline session.",
441
- ephemeral: true
442
- });
443
- }
444
- await defer(event, { ephemeral: true });
445
- try {
446
- const deleted = await context.deleteArchivedTransportResourceTarget({ transportResourceId: event.transportResourceId });
447
- if (!deleted) {
448
- return await reply(event, {
449
- content: "This archived resource could not be deleted.",
450
- ephemeral: true
451
- });
452
- }
453
- const target = summarizeArchivedTarget(deleted);
454
- await context.sendStatusUpdate({
455
- text: `Deleted archived session ${target.id} and removed its local workspace.`,
456
- blocks: [
457
- {
458
- kind: "fields",
459
- title: "Session Deleted",
460
- tone: "danger",
461
- fields: [
462
- { label: "Session", value: target.id },
463
- { label: "Workspace", value: workspaceDisplay(target.id) }
464
- ]
465
- }
466
- ]
467
- });
468
- context.appendAuditEvent("session.deleted", {
469
- sessionId: target.id,
470
- transportResourceId: target.transportResourceId,
471
- workspacePath: target.workspacePath,
472
- pluginId: manifest_default.id
473
- });
474
- return await reply(event, {
475
- content: `Deleted archived session ${target.id} and removed its local workspace (${workspaceDisplay(target.id)}).`,
476
- ephemeral: true
477
- });
478
- } catch (error) {
479
- if (!isMissingPermissions(error)) throw error;
480
- return await reply(event, {
481
- content: "Delete failed: Moorline needs permission to delete the archived resource.",
482
- ephemeral: true
483
- });
484
- }
485
- }
486
- return { handled: false };
487
- }
488
- };
489
-
490
33
  // packages/discord-runtime/modules/routing/index.mjs
491
34
  import { readFile } from "node:fs/promises";
492
35
  var prompts = {
493
- coordination: readFile(new globalThis.URL("./coordination.md", import.meta.url), "utf8").then((value) => value.trim()),
494
36
  session: readFile(new globalThis.URL("./session.md", import.meta.url), "utf8").then((value) => value.trim())
495
37
  };
496
38
  function providerCommandLine(context) {
@@ -513,35 +55,6 @@ async function loadPromptSections(context, surface, dynamicSections = []) {
513
55
  }
514
56
  return sections;
515
57
  }
516
- function mainCoordinationRuntimeMode(context) {
517
- return context.config?.defaults?.runtimeMode === "approval-required" ? "approval-required" : "full-access";
518
- }
519
- async function routeCoordinationMessage(event, context) {
520
- const runtimeMode = mainCoordinationRuntimeMode(context);
521
- const reply2 = await context.runAgent({
522
- surface: "coordination",
523
- transportResourceId: event.transportResourceId,
524
- actorId: event.actor.actorId,
525
- actorLabel: event.actor.displayName ?? event.actor.actorId,
526
- message: event.message.text,
527
- attachments: event.message.attachments,
528
- session: null,
529
- cwd: context.getRuntimeRootPath(),
530
- runtimeMode,
531
- context: {
532
- systemPromptSections: await loadPromptSections(context, "coordination", [
533
- "This coordination surface may use the runtime root for machine-level work, but it is not a durable worker workspace."
534
- ])
535
- }
536
- });
537
- await context.sendMessage(event.transportResourceId, reply2);
538
- context.appendAuditEvent("coordination.replied", {
539
- transportResourceId: event.transportResourceId,
540
- mode: runtimeMode,
541
- pluginId: manifest_default.id
542
- });
543
- return { handled: true };
544
- }
545
58
  async function routeSessionMessage(event, context, session) {
546
59
  const reply2 = await context.runAgent({
547
60
  surface: "session",
@@ -572,325 +85,85 @@ async function routeSessionMessage(event, context, session) {
572
85
  var routing_default = {
573
86
  id: manifest_default.id,
574
87
  manifest: manifest_default,
575
- async onTransportEvent(event, context) {
576
- if (event.type !== "message.received") {
88
+ async onTransportIntent(event, context) {
89
+ if (event.type !== "transport.message.received") {
577
90
  return { handled: false };
578
91
  }
579
- const surface = context.getSurfaceState();
580
- if (event.transportResourceId === surface.coordinationResourceId) {
581
- return await routeCoordinationMessage(event, context);
582
- }
583
92
  const session = context.getSessionByTransportResourceId(event.transportResourceId);
584
- if (!session || session.lifecycleStatus === "archived") {
93
+ if (!session) {
585
94
  return { handled: false };
586
95
  }
587
96
  return await routeSessionMessage(event, context, session);
588
97
  }
589
98
  };
590
99
 
591
- // packages/discord-runtime/modules/session-commands/index.mjs
592
- function summarizeSessions(sessions) {
593
- if (sessions.length === 0) return "No sessions yet.";
594
- return sessions.map(
595
- (session) => `${`- ${session.sessionId} (${session.lifecycleStatus}, ${session.runtimeMode})`}${session.summary ? ` | ${session.summary}` : ""}`
596
- ).join("\n");
597
- }
598
- function buildSessionListEmbed(sessions) {
599
- const openSessions = sessions.filter((session) => session.lifecycleStatus !== "archived");
600
- const coolSessions = sessions.filter((session) => session.lifecycleStatus === "cool");
601
- const archivedSessions = sessions.filter((session) => session.lifecycleStatus === "archived");
100
+ // packages/discord-runtime/modules/shared.mjs
101
+ function discordAction(id, title, commandName, commandDescription, subcommandName, subcommandDescription, options, policy) {
102
+ if (Array.isArray(subcommandName) || subcommandName === void 0 && subcommandDescription && typeof subcommandDescription === "object" && !Array.isArray(subcommandDescription)) {
103
+ policy = subcommandDescription;
104
+ options = subcommandName;
105
+ subcommandDescription = void 0;
106
+ subcommandName = void 0;
107
+ }
602
108
  return {
603
- title: "Moorline Sessions",
604
- color: 3447003,
605
- fields: [
606
- { name: "Open", value: String(openSessions.length), inline: true },
607
- { name: "Cool", value: String(coolSessions.length), inline: true },
608
- { name: "Archived", value: String(archivedSessions.length), inline: true },
609
- { name: "Session Summary", value: summarizeSessions(sessions).slice(0, 1024) || "No sessions yet." }
610
- ],
611
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
109
+ id,
110
+ title,
111
+ description: subcommandDescription ?? commandDescription,
112
+ ...policy ? { policy } : {},
113
+ metadata: {
114
+ discordCommand: {
115
+ commandName,
116
+ commandDescription,
117
+ ...subcommandName ? { subcommandName } : {},
118
+ ...subcommandDescription ? { subcommandDescription } : {},
119
+ ...options ? { options } : {}
120
+ }
121
+ }
612
122
  };
613
123
  }
614
- function sessionOwnerFromEvent(event) {
615
- const actorId = typeof event?.actor?.actorId === "string" ? event.actor.actorId.trim() : "";
616
- if (!actorId) {
617
- return void 0;
618
- }
619
- const actorLabel = typeof event?.actor?.displayName === "string" ? event.actor.displayName.trim() : "";
124
+ function toRuntimeReply(payload) {
125
+ const blocks = (payload.embeds ?? []).map((embed) => ({
126
+ kind: "fields",
127
+ ...embed.title ? { title: embed.title } : {},
128
+ ...embed.description ? { text: embed.description } : {},
129
+ ...embed.fields ? {
130
+ fields: embed.fields.map((field) => ({
131
+ label: field.name,
132
+ value: field.value,
133
+ ...field.inline !== void 0 ? { inline: field.inline } : {}
134
+ }))
135
+ } : {}
136
+ }));
620
137
  return {
621
- kind: "run",
622
- id: actorId,
623
- ...actorLabel ? { label: actorLabel } : {}
138
+ ...payload.content ? { text: payload.content } : {},
139
+ ...blocks.length > 0 ? { blocks } : {}
624
140
  };
625
141
  }
626
- var session_commands_default = {
627
- id: manifest_default.id,
628
- manifest: manifest_default,
629
- actions() {
630
- return [
631
- discordAction(
632
- "session.create",
633
- "Create a new worker session",
634
- "session",
635
- "Manage Moorline worker sessions",
636
- "create",
637
- "Create a new worker session",
638
- [
639
- { type: "string", name: "name", description: "Short session name", required: true },
640
- {
641
- type: "string",
642
- name: "mode",
643
- description: "Runtime mode",
644
- choices: [
645
- { name: "full-access", value: "full-access" },
646
- { name: "approval-required", value: "approval-required" }
647
- ]
648
- }
649
- ]
650
- ),
651
- discordAction(
652
- "session.archive",
653
- "Archive a session",
654
- "session",
655
- "Manage Moorline worker sessions",
656
- "archive",
657
- "Archive a session resource",
658
- [{ type: "string", name: "session_id", description: "Archive a specific session id" }],
659
- { allowedWhileDraining: true, bypassQueue: true }
660
- ),
661
- discordAction(
662
- "session.delete",
663
- "Delete an archived session",
664
- "session",
665
- "Manage Moorline worker sessions",
666
- "delete",
667
- "Delete an archived session and its local workspace",
668
- [
669
- {
670
- type: "string",
671
- name: "confirm",
672
- description: "Type delete to confirm destructive removal",
673
- required: true,
674
- choices: [{ name: "delete", value: "delete" }]
675
- },
676
- { type: "string", name: "session_id", description: "Delete a specific archived session id" }
677
- ],
678
- { allowedWhileDraining: true, bypassQueue: true }
679
- ),
680
- discordAction(
681
- "session.list",
682
- "List sessions",
683
- "session",
684
- "Manage Moorline worker sessions",
685
- "list",
686
- "List active and archived sessions"
687
- )
688
- ];
689
- },
690
- async onAction(event, context) {
691
- if (!event.actionId.startsWith("session.")) {
692
- return { handled: false };
693
- }
694
- if (event.actionId === "session.create") {
695
- const requestedName = stringOption(event.input, "name");
696
- if (!requestedName) {
697
- return await reply(event, { content: "name is required", ephemeral: true });
698
- }
699
- const requestedMode = stringOption(event.input, "mode");
700
- const runtimeMode = requestedMode === "full-access" || requestedMode === "approval-required" ? requestedMode : context.config.defaults.runtimeMode;
701
- const created = await context.createSession({
702
- requestedName,
703
- runtimeMode,
704
- owner: sessionOwnerFromEvent(event)
705
- });
706
- const notificationErrors = [];
707
- try {
708
- await context.sendMessage(created.transportResourceId, {
709
- text: `Session ready: ${created.session.sessionId}. Start by sharing your first task.`
710
- });
711
- } catch (error) {
712
- notificationErrors.push(error instanceof Error ? error.message : String(error));
713
- }
714
- context.appendAuditEvent("session.created", {
715
- sessionId: created.session.sessionId,
716
- transportResourceId: created.transportResourceId,
717
- runtimeMode,
718
- pluginId: manifest_default.id
719
- });
720
- if (notificationErrors.length > 0) {
721
- context.appendAuditEvent("session.created.notification_failed", {
722
- sessionId: created.session.sessionId,
723
- transportResourceId: created.transportResourceId,
724
- runtimeMode,
725
- errors: notificationErrors,
726
- pluginId: manifest_default.id
727
- });
728
- }
729
- return await reply(event, {
730
- content: notificationErrors.length === 0 ? `Created session ${created.session.sessionId} in <#${created.transportResourceId}>.` : `Created session ${created.session.sessionId} in <#${created.transportResourceId}>. Warning: follow-up notifications failed; check runtime status.`,
731
- ephemeral: true
732
- });
733
- }
734
- if (event.actionId === "session.archive") {
735
- if (!event.transportResourceId && !stringOption(event.input, "session_id")) {
736
- return await reply(event, {
737
- content: "Run this in a session resource or pass session_id.",
738
- ephemeral: true
739
- });
740
- }
741
- try {
742
- const session = await context.archiveSession({
743
- transportResourceId: event.transportResourceId ?? "",
744
- ...stringOption(event.input, "session_id") ? { sessionId: stringOption(event.input, "session_id") } : {}
745
- });
746
- if (!session) {
747
- return await reply(event, { content: "No matching session found.", ephemeral: true });
748
- }
749
- context.appendAuditEvent("session.archived", {
750
- sessionId: session.sessionId,
751
- transportResourceId: session.transportResourceId,
752
- pluginId: manifest_default.id
753
- });
754
- return await reply(event, {
755
- content: `Archived session ${session.sessionId}.`,
756
- ephemeral: true
757
- });
758
- } catch (error) {
759
- if (!isMissingPermissions(error)) throw error;
760
- return await reply(event, {
761
- content: "Archive failed: Moorline needs permission to update the session resource and archive area.",
762
- ephemeral: true
763
- });
764
- }
765
- }
766
- if (event.actionId === "session.delete") {
767
- if (!event.transportResourceId && !stringOption(event.input, "session_id")) {
768
- return await reply(event, {
769
- content: "Run this in a session resource or pass session_id.",
770
- ephemeral: true
771
- });
772
- }
773
- const requestedSessionId = stringOption(event.input, "session_id");
774
- const target = (requestedSessionId ? context.getSessionById(requestedSessionId) : null) ?? (event.transportResourceId ? context.getSessionByTransportResourceId(event.transportResourceId) : null);
775
- if (!target) {
776
- return await reply(event, { content: "No matching session found.", ephemeral: true });
777
- }
778
- if (target.lifecycleStatus !== "archived") {
779
- return await reply(event, {
780
- content: `Session ${target.sessionId} must be archived before deletion.`,
781
- ephemeral: true
782
- });
783
- }
784
- if (stringOption(event.input, "confirm") !== "delete") {
785
- return await reply(event, {
786
- content: "Deletion cancelled: pass confirm:delete to remove the archived session.",
787
- ephemeral: true
788
- });
789
- }
790
- if (event.transportResourceId && target.transportResourceId === event.transportResourceId) {
791
- await defer(event, { ephemeral: true });
792
- }
793
- try {
794
- const deleted = await context.deleteArchivedSession({
795
- transportResourceId: event.transportResourceId ?? target.transportResourceId,
796
- ...requestedSessionId ? { sessionId: requestedSessionId } : {}
797
- });
798
- if (!deleted) {
799
- return await reply(event, { content: "No matching session found.", ephemeral: true });
800
- }
801
- context.appendAuditEvent("session.deleted", {
802
- sessionId: deleted.sessionId,
803
- transportResourceId: deleted.transportResourceId,
804
- workspacePath: deleted.workspacePath,
805
- pluginId: manifest_default.id
806
- });
807
- return await reply(event, {
808
- content: `Deleted archived session ${deleted.sessionId} and removed its local workspace (${workspaceDisplay(deleted.sessionId)}).`,
809
- ephemeral: true
810
- });
811
- } catch (error) {
812
- if (!isMissingPermissions(error)) throw error;
813
- return await reply(event, {
814
- content: "Delete failed: Moorline needs permission to delete the archived session resource.",
815
- ephemeral: true
816
- });
817
- }
818
- }
819
- if (event.actionId === "session.list") {
820
- return await reply(event, {
821
- content: "Current Moorline sessions",
822
- embeds: [buildSessionListEmbed(context.listSessions())],
823
- ephemeral: true
824
- });
825
- }
826
- return await reply(event, {
827
- content: `Unsupported session action: ${event.actionId}`,
828
- ephemeral: true
829
- });
142
+ async function reply(event, payload) {
143
+ const native = event.native?.payload;
144
+ if (native && typeof native === "object" && typeof native.reply === "function") {
145
+ await native.reply(payload);
146
+ return { handled: true };
830
147
  }
831
- };
148
+ return { handled: true, reply: toRuntimeReply(payload) };
149
+ }
832
150
 
833
151
  // packages/discord-runtime/modules/status/index.mjs
834
- var MAX_EMBED_FIELD_VALUE = 1024;
835
- function buildHealthEmbed(input) {
152
+ function statusEmbed(input) {
836
153
  return {
837
- title: "Moorline Health",
838
- color: input.dbOk && input.environmentOk ? 3066993 : 15158332,
154
+ title: "Moorline Status",
155
+ color: input.acceptingNewWork ? 3066993 : 15844367,
839
156
  fields: [
840
157
  { name: "Uptime", value: `${input.uptimeSeconds}s`, inline: true },
841
- { name: "Database", value: input.dbDetail ?? (input.dbOk ? "OK" : "Error"), inline: true },
842
- { name: "Environment", value: input.environmentDetail ?? (input.environmentOk ? "OK" : "Error"), inline: true },
843
- { name: "Open Sessions", value: String(input.activeSessions), inline: true },
844
- { name: "Cool Sessions", value: String(input.coolSessions), inline: true },
845
- { name: "Archived Sessions", value: String(input.archivedSessions), inline: true }
158
+ { name: "Accepting Work", value: input.acceptingNewWork ? "Yes" : "No", inline: true },
159
+ { name: "Open Sessions", value: String(input.openSessions), inline: true },
160
+ { name: "Running", value: String(input.runningSessions), inline: true },
161
+ { name: "Waiting", value: String(input.waitingSessions), inline: true },
162
+ { name: "Provider", value: input.providerLabel ?? "unknown", inline: true }
846
163
  ],
847
164
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
848
165
  };
849
166
  }
850
- function parseAnswers(raw) {
851
- try {
852
- const parsed = JSON.parse(raw);
853
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return { answer: raw };
854
- const result = {};
855
- for (const [key, value] of Object.entries(parsed)) {
856
- if (typeof value === "string") result[key] = value;
857
- else if (Array.isArray(value)) {
858
- const normalized = value.filter((entry) => typeof entry === "string");
859
- if (normalized.length > 0) result[key] = normalized;
860
- }
861
- }
862
- return Object.keys(result).length > 0 ? result : { answer: raw };
863
- } catch {
864
- return { answer: raw };
865
- }
866
- }
867
- function toBlock(title, tone, fields) {
868
- return {
869
- kind: "fields",
870
- title,
871
- tone,
872
- fields: fields.map((field) => ({
873
- label: field.name,
874
- value: field.value,
875
- ...field.inline !== void 0 ? { inline: field.inline } : {}
876
- }))
877
- };
878
- }
879
- function truncateEmbedValue(value, maxLength = MAX_EMBED_FIELD_VALUE) {
880
- const normalized = String(value ?? "").trim();
881
- if (!normalized) return "None";
882
- if (normalized.length <= maxLength) return normalized;
883
- return `${normalized.slice(0, Math.max(0, maxLength - 14))}...(truncated)`;
884
- }
885
- function summarizeRuntimeIssue(event) {
886
- if (event.type === "turn.failed") {
887
- return "A turn failed. Check local runtime audit logs for detailed diagnostics.";
888
- }
889
- if (event.type === "provider.closed") {
890
- return "A provider session closed unexpectedly. Check local runtime audit logs for details.";
891
- }
892
- return "A runtime error occurred. Check local runtime audit logs for details.";
893
- }
894
167
  var status_default = {
895
168
  id: manifest_default.id,
896
169
  manifest: manifest_default,
@@ -900,253 +173,32 @@ var status_default = {
900
173
  "runtime.status",
901
174
  "Show runtime status",
902
175
  "status",
903
- "Show Moorline surface and runtime status",
176
+ "Show Moorline runtime status",
904
177
  void 0,
905
178
  void 0,
906
179
  void 0,
907
180
  { allowedWhileDraining: true }
908
- ),
909
- discordAction(
910
- "runtime.turn.stop",
911
- "Stop the active turn",
912
- "turn",
913
- "Control the active provider turn in this session",
914
- "stop",
915
- "Interrupt the active turn for this session",
916
- void 0,
917
- { allowedWhileDraining: true, bypassQueue: true }
918
- ),
919
- discordAction(
920
- "runtime.request.cancel",
921
- "Cancel a pending runtime request",
922
- "request",
923
- "Respond to a pending runtime user-input request",
924
- "cancel",
925
- "Cancel a pending runtime request",
926
- [{ type: "string", name: "request_id", description: "Pending request id", required: true }],
927
- { allowedWhileDraining: true, bypassQueue: true }
928
- ),
929
- discordAction(
930
- "runtime.request.answer",
931
- "Answer a pending runtime request",
932
- "request",
933
- "Respond to a pending runtime user-input request",
934
- "answer",
935
- "Answer a pending runtime user-input request",
936
- [
937
- { type: "string", name: "request_id", description: "Pending request id", required: true },
938
- {
939
- type: "string",
940
- name: "answers",
941
- description: "Plain text answer or JSON object keyed by question id",
942
- required: true
943
- }
944
- ],
945
- { allowedWhileDraining: true, bypassQueue: true }
946
181
  )
947
182
  ];
948
183
  },
949
- async onDomainEvent(event, context) {
950
- if (event.transportResourceId === null) return;
951
- if (event.type === "turn.waiting_for_approval" || event.type === "turn.waiting_for_input") {
952
- await context.sendStatusUpdate({
953
- text: `Session ${event.sessionId ?? event.threadId} is waiting.`,
954
- blocks: [
955
- toBlock("Turn Waiting", "warning", [
956
- { name: "Session", value: event.sessionId ?? event.threadId },
957
- { name: "State", value: event.type.replace("turn.", "").replace(/_/g, " ") }
958
- ])
959
- ]
960
- });
961
- }
962
- if (event.type === "turn.failed" || event.type === "runtime.error" || event.type === "provider.closed") {
963
- const detail = summarizeRuntimeIssue(event);
964
- await context.sendStatusUpdate({
965
- text: `Session ${event.sessionId ?? event.threadId} hit a runtime problem.`,
966
- blocks: [
967
- toBlock("Runtime Issue", "danger", [
968
- { name: "Session", value: event.sessionId ?? event.threadId },
969
- { name: "Detail", value: detail }
970
- ])
971
- ]
972
- });
973
- }
974
- },
975
184
  async onAction(event, context) {
976
- if (event.actionId === "runtime.turn.stop") {
977
- if (!event.transportResourceId) {
978
- return await reply(event, { content: "This action requires a target session resource.", ephemeral: true });
979
- }
980
- const session = context.getSessionByTransportResourceId(event.transportResourceId);
981
- if (!session) {
982
- return await reply(event, {
983
- content: "This resource does not have an active Moorline session.",
984
- ephemeral: true
985
- });
986
- }
987
- await context.interruptTurn({ threadId: session.threadId });
988
- return await reply(event, {
989
- content: `Interrupt sent for ${session.sessionId}.`,
990
- ephemeral: true
991
- });
992
- }
993
- if (event.actionId === "runtime.request.cancel" || event.actionId === "runtime.request.answer") {
994
- if (!event.transportResourceId) {
995
- return await reply(event, { content: "This action requires a target resource.", ephemeral: true });
996
- }
997
- const requestId = stringOption(event.input, "request_id");
998
- if (!requestId) {
999
- return await reply(event, { content: "request_id is required.", ephemeral: true });
1000
- }
1001
- const request = context.listPendingRequests(event.transportResourceId).find((entry) => entry.requestId === requestId);
1002
- if (!request) {
1003
- return await reply(event, {
1004
- content: `No pending request ${requestId} was found in this resource.`,
1005
- ephemeral: true
1006
- });
1007
- }
1008
- if (event.actionId === "runtime.request.cancel") {
1009
- try {
1010
- await context.cancelRuntimeRequest({
1011
- threadId: request.threadId,
1012
- requestId,
1013
- requestType: request.requestType,
1014
- requesterActor: event.actor
1015
- });
1016
- } catch (error) {
1017
- return await reply(event, {
1018
- content: error instanceof Error ? error.message : String(error),
1019
- ephemeral: true
1020
- });
1021
- }
1022
- return await reply(event, {
1023
- content: `Cancelled request ${requestId}.`,
1024
- ephemeral: true
1025
- });
1026
- }
1027
- if (request.requestType !== "tool_user_input") {
1028
- return await reply(event, {
1029
- content: `Request ${requestId} is approval-driven. Use the request actions instead.`,
1030
- ephemeral: true
1031
- });
1032
- }
1033
- try {
1034
- await context.respondToRuntimeUserInput({
1035
- threadId: request.threadId,
1036
- requestId,
1037
- answers: parseAnswers(stringOption(event.input, "answers")),
1038
- requesterActor: event.actor
1039
- });
1040
- } catch (error) {
1041
- return await reply(event, {
1042
- content: error instanceof Error ? error.message : String(error),
1043
- ephemeral: true
1044
- });
1045
- }
1046
- return await reply(event, {
1047
- content: `Answered request ${requestId}.`,
1048
- ephemeral: true
1049
- });
1050
- }
1051
185
  if (event.actionId !== "runtime.status") {
1052
186
  return { handled: false };
1053
187
  }
1054
- const surface = context.getSurfaceState();
1055
188
  const runtimeStatus = context.getRuntimeStatus();
189
+ const controlStatus = context.getRuntimeControlStatus();
1056
190
  const providerDiagnostics = context.getProviderDiagnostics();
1057
- const overview = context.getRuntimeOverview();
1058
- const receipts = overview.receipts;
1059
- const activities = overview.sessions.flatMap((session) => session.recentActivities).slice(-5);
1060
- const projectionStates = overview.projectionStates;
1061
- const projectionFailures = projectionStates.filter((entry) => entry.failure !== null);
1062
- const providerErrorCount = Number(providerDiagnostics.statusCounts.error ?? 0);
1063
- const dbOk = projectionFailures.length === 0;
1064
- const environmentOk = providerErrorCount === 0;
1065
- const dbDetail = projectionFailures.length === 0 ? "OK" : `Error (${projectionFailures.length} projection failure${projectionFailures.length === 1 ? "" : "s"})`;
1066
- const environmentDetail = providerErrorCount === 0 ? "OK" : `Error (${providerErrorCount} provider session${providerErrorCount === 1 ? "" : "s"})`;
1067
191
  return await reply(event, {
1068
192
  content: "Moorline runtime status",
1069
193
  embeds: [
1070
- buildHealthEmbed({
194
+ statusEmbed({
1071
195
  uptimeSeconds: runtimeStatus.uptimeSeconds,
1072
- dbOk,
1073
- environmentOk,
1074
- dbDetail,
1075
- environmentDetail,
1076
- activeSessions: runtimeStatus.openSessions,
1077
- coolSessions: runtimeStatus.coolSessions,
1078
- archivedSessions: runtimeStatus.archivedSessions
1079
- }),
1080
- {
1081
- title: "Runtime Activity",
1082
- color: 1752220,
1083
- fields: [
1084
- { name: "Running Sessions", value: String(runtimeStatus.runningSessions), inline: true },
1085
- { name: "Waiting Sessions", value: String(runtimeStatus.waitingSessions), inline: true },
1086
- {
1087
- name: "Pending Receipts",
1088
- value: truncateEmbedValue(
1089
- receipts.length === 0 ? "None" : receipts.slice(-5).map((receipt) => `${receipt.threadId}: ${receipt.state}`).join("\n")
1090
- )
1091
- },
1092
- {
1093
- name: "Recent Activity",
1094
- value: truncateEmbedValue(
1095
- activities.length === 0 ? "None" : activities.map((activity) => `${activity.title}${activity.detail ? ` - ${activity.detail}` : ""}`).join("\n")
1096
- )
1097
- }
1098
- ],
1099
- timestamp: context.nowIso()
1100
- },
1101
- {
1102
- title: "Provider Diagnostics",
1103
- color: 10181046,
1104
- fields: [
1105
- { name: "Account", value: providerDiagnostics.accountLabel ?? "unknown", inline: true },
1106
- { name: "Default Model", value: context.getDefaultModel(), inline: true },
1107
- { name: "Connected Sessions", value: String(providerDiagnostics.connectedSessions), inline: true },
1108
- {
1109
- name: "Models",
1110
- value: truncateEmbedValue(providerDiagnostics.availableModels.join(", ") || "Unknown"),
1111
- inline: true
1112
- },
1113
- {
1114
- name: "Provider Statuses",
1115
- value: truncateEmbedValue(
1116
- Object.entries(providerDiagnostics.statusCounts).map(([status, count]) => `${status}: ${count}`).join("\n") || "None"
1117
- )
1118
- },
1119
- {
1120
- name: "Capabilities",
1121
- value: truncateEmbedValue(Object.keys(providerDiagnostics.capabilityMetadata).join(", ") || "None")
1122
- }
1123
- ],
1124
- timestamp: context.nowIso()
1125
- },
1126
- {
1127
- title: "Projection Health",
1128
- color: projectionFailures.length === 0 ? 3066993 : 15158332,
1129
- fields: [
1130
- {
1131
- name: "Pipelines",
1132
- value: truncateEmbedValue(
1133
- projectionStates.map((entry) => `${entry.projector}: ${entry.failure ? `failed (${entry.failure})` : "ok"}`).join("\n") || "None"
1134
- )
1135
- }
1136
- ],
1137
- timestamp: context.nowIso()
1138
- },
1139
- {
1140
- title: "Managed Surface",
1141
- color: 3447003,
1142
- fields: [
1143
- { name: "Coordination", value: `<#${surface.coordinationResourceId}>`, inline: true },
1144
- { name: "Status", value: `<#${surface.statusResourceId}>`, inline: true },
1145
- { name: "Sessions", value: surface.sessionsCategoryId, inline: true },
1146
- { name: "Archive", value: surface.archiveCategoryId, inline: true }
1147
- ],
1148
- timestamp: context.nowIso()
1149
- }
196
+ acceptingNewWork: controlStatus.acceptingNewWork,
197
+ openSessions: runtimeStatus.openSessions,
198
+ runningSessions: runtimeStatus.runningSessions,
199
+ waitingSessions: runtimeStatus.waitingSessions,
200
+ providerLabel: providerDiagnostics.accountLabel
201
+ })
1150
202
  ],
1151
203
  ephemeral: true
1152
204
  });
@@ -1155,10 +207,7 @@ var status_default = {
1155
207
 
1156
208
  // packages/discord-runtime/index.mjs
1157
209
  var modules = [
1158
- admin_control_default,
1159
- channel_lifecycle_default,
1160
210
  routing_default,
1161
- session_commands_default,
1162
211
  status_default
1163
212
  ];
1164
213
  async function firstHandled(hook, args) {
@@ -1183,11 +232,8 @@ var index_default = {
1183
232
  async onAction(event, context) {
1184
233
  return await firstHandled("onAction", [event, context]);
1185
234
  },
1186
- async onDomainEvent(event, context) {
1187
- return await firstHandled("onDomainEvent", [event, context]);
1188
- },
1189
- async onTransportEvent(event, context) {
1190
- return await firstHandled("onTransportEvent", [event, context]);
235
+ async onTransportIntent(intent, context) {
236
+ return await firstHandled("onTransportIntent", [intent, context]);
1191
237
  }
1192
238
  };
1193
239
  export {