@mono-agent/agent-app 0.4.0 → 0.5.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 (173) hide show
  1. package/README.md +15 -5
  2. package/dist/adapter-send-tools-main.js +2 -2
  3. package/dist/adapter-send-tools-main.js.map +1 -1
  4. package/dist/adapter-send-tools.d.ts +72 -6
  5. package/dist/adapter-send-tools.d.ts.map +1 -1
  6. package/dist/adapter-send-tools.js +413 -38
  7. package/dist/adapter-send-tools.js.map +1 -1
  8. package/dist/app-config.d.ts +48 -11
  9. package/dist/app-config.d.ts.map +1 -1
  10. package/dist/app-config.js +98 -24
  11. package/dist/app-config.js.map +1 -1
  12. package/dist/app.d.ts +10 -0
  13. package/dist/app.d.ts.map +1 -1
  14. package/dist/app.js +659 -48
  15. package/dist/app.js.map +1 -1
  16. package/dist/artifact-retention.d.ts +32 -0
  17. package/dist/artifact-retention.d.ts.map +1 -0
  18. package/dist/artifact-retention.js +111 -0
  19. package/dist/artifact-retention.js.map +1 -0
  20. package/dist/audit-runs.d.ts +12 -0
  21. package/dist/audit-runs.d.ts.map +1 -0
  22. package/dist/audit-runs.js +68 -0
  23. package/dist/audit-runs.js.map +1 -0
  24. package/dist/backfill.d.ts +3 -7
  25. package/dist/backfill.d.ts.map +1 -1
  26. package/dist/backfill.js +115 -11
  27. package/dist/backfill.js.map +1 -1
  28. package/dist/background.d.ts +8 -1
  29. package/dist/background.d.ts.map +1 -1
  30. package/dist/background.js +202 -4
  31. package/dist/background.js.map +1 -1
  32. package/dist/broadcast-recorder.d.ts +27 -0
  33. package/dist/broadcast-recorder.d.ts.map +1 -0
  34. package/dist/broadcast-recorder.js +82 -0
  35. package/dist/broadcast-recorder.js.map +1 -0
  36. package/dist/channel-config-view.d.ts +28 -0
  37. package/dist/channel-config-view.d.ts.map +1 -0
  38. package/dist/channel-config-view.js +79 -0
  39. package/dist/channel-config-view.js.map +1 -0
  40. package/dist/channel-gate.d.ts +22 -0
  41. package/dist/channel-gate.d.ts.map +1 -0
  42. package/dist/channel-gate.js +35 -0
  43. package/dist/channel-gate.js.map +1 -0
  44. package/dist/channel-plugins.d.ts +39 -0
  45. package/dist/channel-plugins.d.ts.map +1 -0
  46. package/dist/channel-plugins.js +372 -0
  47. package/dist/channel-plugins.js.map +1 -0
  48. package/dist/channels.d.ts +62 -73
  49. package/dist/channels.d.ts.map +1 -1
  50. package/dist/channels.js +833 -126
  51. package/dist/channels.js.map +1 -1
  52. package/dist/cli.d.ts +65 -3
  53. package/dist/cli.d.ts.map +1 -1
  54. package/dist/cli.js +755 -30
  55. package/dist/cli.js.map +1 -1
  56. package/dist/config-reference.d.ts +24 -0
  57. package/dist/config-reference.d.ts.map +1 -0
  58. package/dist/config-reference.js +580 -0
  59. package/dist/config-reference.js.map +1 -0
  60. package/dist/configured-agent.d.ts +104 -0
  61. package/dist/configured-agent.d.ts.map +1 -0
  62. package/dist/configured-agent.js +578 -0
  63. package/dist/configured-agent.js.map +1 -0
  64. package/dist/consumer-contract.d.ts +36 -0
  65. package/dist/consumer-contract.d.ts.map +1 -0
  66. package/dist/consumer-contract.js +290 -0
  67. package/dist/consumer-contract.js.map +1 -0
  68. package/dist/doctor.d.ts +9 -0
  69. package/dist/doctor.d.ts.map +1 -1
  70. package/dist/doctor.js +352 -55
  71. package/dist/doctor.js.map +1 -1
  72. package/dist/index.d.ts +9 -3
  73. package/dist/index.d.ts.map +1 -1
  74. package/dist/index.js +5 -2
  75. package/dist/index.js.map +1 -1
  76. package/dist/init.d.ts +23 -7
  77. package/dist/init.d.ts.map +1 -1
  78. package/dist/init.js +91 -26
  79. package/dist/init.js.map +1 -1
  80. package/dist/install-skill.d.ts +1 -1
  81. package/dist/install-skill.js +2 -2
  82. package/dist/install-skill.js.map +1 -1
  83. package/dist/interaction-bridge.d.ts +72 -0
  84. package/dist/interaction-bridge.d.ts.map +1 -0
  85. package/dist/interaction-bridge.js +354 -0
  86. package/dist/interaction-bridge.js.map +1 -0
  87. package/dist/memory-command.d.ts +10 -0
  88. package/dist/memory-command.d.ts.map +1 -0
  89. package/dist/memory-command.js +649 -0
  90. package/dist/memory-command.js.map +1 -0
  91. package/dist/memory-recall-main.js +1 -1
  92. package/dist/memory-recall-main.js.map +1 -1
  93. package/dist/memory-recall.d.ts +41 -5
  94. package/dist/memory-recall.d.ts.map +1 -1
  95. package/dist/memory-recall.js +75 -5
  96. package/dist/memory-recall.js.map +1 -1
  97. package/dist/memory-rituals.d.ts +8 -11
  98. package/dist/memory-rituals.d.ts.map +1 -1
  99. package/dist/memory-rituals.js +26 -25
  100. package/dist/memory-rituals.js.map +1 -1
  101. package/dist/metrics.d.ts +13 -0
  102. package/dist/metrics.d.ts.map +1 -0
  103. package/dist/metrics.js +105 -0
  104. package/dist/metrics.js.map +1 -0
  105. package/dist/notify-destinations.d.ts +23 -0
  106. package/dist/notify-destinations.d.ts.map +1 -0
  107. package/dist/notify-destinations.js +79 -0
  108. package/dist/notify-destinations.js.map +1 -0
  109. package/dist/posted-message-index.d.ts +61 -0
  110. package/dist/posted-message-index.d.ts.map +1 -0
  111. package/dist/posted-message-index.js +178 -0
  112. package/dist/posted-message-index.js.map +1 -0
  113. package/dist/proactive-notify.d.ts +32 -0
  114. package/dist/proactive-notify.d.ts.map +1 -0
  115. package/dist/proactive-notify.js +62 -0
  116. package/dist/proactive-notify.js.map +1 -0
  117. package/dist/recipes/base.d.ts +15 -0
  118. package/dist/recipes/base.d.ts.map +1 -0
  119. package/dist/recipes/base.js +51 -0
  120. package/dist/recipes/base.js.map +1 -0
  121. package/dist/recipes/catalog.d.ts +4 -0
  122. package/dist/recipes/catalog.d.ts.map +1 -0
  123. package/dist/recipes/catalog.js +525 -0
  124. package/dist/recipes/catalog.js.map +1 -0
  125. package/dist/recipes/index.d.ts +11 -0
  126. package/dist/recipes/index.d.ts.map +1 -0
  127. package/dist/recipes/index.js +14 -0
  128. package/dist/recipes/index.js.map +1 -0
  129. package/dist/recipes/types.d.ts +70 -0
  130. package/dist/recipes/types.d.ts.map +1 -0
  131. package/dist/recipes/types.js +15 -0
  132. package/dist/recipes/types.js.map +1 -0
  133. package/dist/request-model-override.d.ts +67 -0
  134. package/dist/request-model-override.d.ts.map +1 -0
  135. package/dist/request-model-override.js +96 -0
  136. package/dist/request-model-override.js.map +1 -0
  137. package/dist/runs-health.d.ts +22 -0
  138. package/dist/runs-health.d.ts.map +1 -0
  139. package/dist/runs-health.js +144 -0
  140. package/dist/runs-health.js.map +1 -0
  141. package/dist/seen-conversations.d.ts +22 -0
  142. package/dist/seen-conversations.d.ts.map +1 -0
  143. package/dist/seen-conversations.js +120 -0
  144. package/dist/seen-conversations.js.map +1 -0
  145. package/dist/setup.d.ts +29 -0
  146. package/dist/setup.d.ts.map +1 -0
  147. package/dist/setup.js +97 -0
  148. package/dist/setup.js.map +1 -0
  149. package/dist/trigger-overrides.d.ts +17 -0
  150. package/dist/trigger-overrides.d.ts.map +1 -0
  151. package/dist/trigger-overrides.js +30 -0
  152. package/dist/trigger-overrides.js.map +1 -0
  153. package/dist/tui-command.d.ts +56 -0
  154. package/dist/tui-command.d.ts.map +1 -0
  155. package/dist/tui-command.js +160 -0
  156. package/dist/tui-command.js.map +1 -0
  157. package/dist/ui.d.ts.map +1 -1
  158. package/dist/ui.js +4 -0
  159. package/dist/ui.js.map +1 -1
  160. package/dist/web-command.d.ts +45 -0
  161. package/dist/web-command.d.ts.map +1 -0
  162. package/dist/web-command.js +152 -0
  163. package/dist/web-command.js.map +1 -0
  164. package/package.json +19 -18
  165. package/schema/mono-agent.config.schema.json +1686 -0
  166. package/skills/mono-agent-composer/SKILL.md +34 -9
  167. package/skills/mono-agent-composer/agents/openai.yaml +4 -0
  168. package/skills/mono-agent-composer/references/config-blueprint.md +92 -49
  169. package/skills/mono-agent-composer/references/discovery-questions.md +15 -17
  170. package/skills/mono-agent-composer/references/feature-coverage.md +22 -17
  171. package/skills/mono-agent-composer/references/package-map.md +19 -21
  172. package/skills/mono-agent-composer/references/playbooks.md +267 -0
  173. package/skills/mono-agent-composer/references/validation.md +9 -1
@@ -0,0 +1,105 @@
1
+ import { resolve } from "node:path";
2
+ import process from "node:process";
3
+ import { summarizeRecordedRunMetrics } from "@mono-agent/observability";
4
+ import { resolveAppArtifactDir } from "./app-config.js";
5
+ export async function runMetrics(args) {
6
+ const cwd = process.cwd();
7
+ const input = {
8
+ env: process.env,
9
+ cwd,
10
+ configPath: resolve(cwd, args.configPath ?? "mono-agent.config.json"),
11
+ };
12
+ let report;
13
+ try {
14
+ const artifactDir = args.artifactDir === undefined
15
+ ? await resolveAppArtifactDir(input)
16
+ : resolve(cwd, args.artifactDir);
17
+ report = await summarizeRecordedRunMetrics({
18
+ artifactDir,
19
+ ...(args.since === undefined ? {} : { since: args.since }),
20
+ ...(args.until === undefined ? {} : { until: args.until }),
21
+ ...(args.groupBy === undefined ? {} : { groupBy: args.groupBy }),
22
+ scope: args.includeMemory === true ? "all" : "agent",
23
+ });
24
+ }
25
+ catch (error) {
26
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
27
+ return 1;
28
+ }
29
+ process.stdout.write(args.json === true ? `${JSON.stringify(report, null, 2)}\n` : renderMetricsReport(report));
30
+ return 0;
31
+ }
32
+ export function renderMetricsReport(report) {
33
+ let out = `Artifact metrics: ${report.artifactDir}\n`;
34
+ out += `Summary files: ${report.totalSummaryFiles} (${report.parsedSummaryFiles} parsed, ${report.parseFailureCount} parse failed)\n`;
35
+ if (report.since !== undefined || report.until !== undefined) {
36
+ out += `Window: ${report.since ?? "-inf"} to ${report.until ?? "+inf"}\n`;
37
+ }
38
+ out += renderBucket(report.overall);
39
+ if (report.groups.length > 0 && report.groupBy !== undefined) {
40
+ out += `\nGroups by ${report.groupBy}\n`;
41
+ for (const group of report.groups) {
42
+ out += ` ${group.key}: ${group.totalRuns} run${group.totalRuns === 1 ? "" : "s"}`;
43
+ out += `, failed ${group.statusCounts.failed} (${formatPercent(group.statusRates.failed)})`;
44
+ out += `, p90 ${formatDuration(group.durationMs.p90)}`;
45
+ out += `, cost ${formatUsd(group.cost.totalUsd)}\n`;
46
+ }
47
+ }
48
+ if (report.parseFailures.length > 0) {
49
+ out += "\nParse failures\n";
50
+ for (const issue of report.parseFailures) {
51
+ const value = issue.value === undefined ? "" : ` (${issue.value})`;
52
+ out += ` ${issue.fileName}: ${issue.reason}${value}\n`;
53
+ }
54
+ }
55
+ if (report.warnings.length > 0) {
56
+ out += "\nWarnings\n";
57
+ for (const warning of report.warnings) {
58
+ out += ` ${warning}\n`;
59
+ }
60
+ }
61
+ return out;
62
+ }
63
+ function renderBucket(bucket) {
64
+ let out = `Total runs: ${bucket.totalRuns}\n`;
65
+ out += "\nStatuses\n";
66
+ for (const [status, count] of Object.entries(bucket.statusCounts)) {
67
+ out += ` ${status}: ${count} (${formatPercent(bucket.statusRates[status])})\n`;
68
+ }
69
+ out += "\nDuration\n";
70
+ out += ` samples: ${bucket.durationMs.count}\n`;
71
+ out += ` p50: ${formatDuration(bucket.durationMs.p50)}\n`;
72
+ out += ` p90: ${formatDuration(bucket.durationMs.p90)}\n`;
73
+ out += ` p99: ${formatDuration(bucket.durationMs.p99)}\n`;
74
+ out += ` max: ${formatDuration(bucket.durationMs.max)}\n`;
75
+ out += "\nCost\n";
76
+ out += ` total: ${formatUsd(bucket.cost.totalUsd)}\n`;
77
+ out += ` average/run: ${formatUsd(bucket.cost.averageUsdPerRun)}\n`;
78
+ out += ` runs with cost: ${bucket.cost.runsWithCost}\n`;
79
+ out += "\nFailure kinds\n";
80
+ if (bucket.failureKindRates.length === 0) {
81
+ out += " none\n";
82
+ }
83
+ else {
84
+ for (const failureKind of bucket.failureKindRates) {
85
+ out += ` ${failureKind.failureKind}: ${failureKind.count} (${formatPercent(failureKind.rate)})\n`;
86
+ }
87
+ }
88
+ return out;
89
+ }
90
+ function formatPercent(rate) {
91
+ const fixed = (rate * 100).toFixed(1);
92
+ return `${fixed.replace(/\.0$/u, "")}%`;
93
+ }
94
+ function formatDuration(value) {
95
+ return value === null ? "n/a" : `${formatNumber(value)} ms`;
96
+ }
97
+ function formatUsd(value) {
98
+ return `$${formatNumber(value, 6)}`;
99
+ }
100
+ function formatNumber(value, maxFractionDigits = 3) {
101
+ return new Intl.NumberFormat("en-US", {
102
+ maximumFractionDigits: maxFractionDigits,
103
+ }).format(value);
104
+ }
105
+ //# sourceMappingURL=metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { NotifyDestination } from "@mono-agent/agent-contracts";
2
+ import type { MonoAgentAppConfigInput } from "./app-config.js";
3
+ import type { ChannelId, MonoAgentAppLogger } from "./channels.js";
4
+ export type { NotifyDestination } from "@mono-agent/agent-contracts";
5
+ export interface ResolveNotifyDestinationsInput {
6
+ readonly input: MonoAgentAppConfigInput;
7
+ readonly artifactDir: string;
8
+ /** Whether a given channel is currently running (only running channels can deliver). */
9
+ readonly isRunning: (id: ChannelId) => boolean;
10
+ readonly logger?: MonoAgentAppLogger | undefined;
11
+ }
12
+ /**
13
+ * The conversations a native cron/webhook notification may be delivered to, used by
14
+ * the app to infer a destination when a job/endpoint sets no explicit
15
+ * `notifyConversationId`. Combines two id-free sources so the operator never types a conversationId:
16
+ * - conversations the agent has actually handled (run-artifact summaries), filtered to
17
+ * notify-capable + running channels, newest-first;
18
+ * - the adapter allowlist entries (when not allow-all), surfaced as candidates the agent
19
+ * can reach even before it has conversed there (covers a fresh single-user agent).
20
+ * WhatsApp is excluded (no notify hook yet) so the agent never picks an undeliverable id.
21
+ */
22
+ export declare function resolveNotifyDestinations(opts: ResolveNotifyDestinationsInput): Promise<readonly NotifyDestination[]>;
23
+ //# sourceMappingURL=notify-destinations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notify-destinations.d.ts","sourceRoot":"","sources":["../src/notify-destinations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAErE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAKnE,YAAY,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAiBrE,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,KAAK,EAAE,uBAAuB,CAAC;IACxC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,wFAAwF;IACxF,QAAQ,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,OAAO,CAAC;IAC/C,QAAQ,CAAC,MAAM,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;CAClD;AAED;;;;;;;;;GASG;AACH,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,8BAA8B,GACnC,OAAO,CAAC,SAAS,iBAAiB,EAAE,CAAC,CA6BvC"}
@@ -0,0 +1,79 @@
1
+ import { listSeenNotifyDestinations } from "./seen-conversations.js";
2
+ let slackModule;
3
+ let telegramModule;
4
+ const loadSlackModule = async () => (slackModule ??= await import("@mono-agent/slack-adapter"));
5
+ const loadTelegramModule = async () => (telegramModule ??= await import("@mono-agent/telegram-adapter"));
6
+ /** Channels whose conversations can receive a proactive notification turn. */
7
+ const NOTIFY_CAPABLE = new Set(["telegram", "slack"]);
8
+ /**
9
+ * The conversations a native cron/webhook notification may be delivered to, used by
10
+ * the app to infer a destination when a job/endpoint sets no explicit
11
+ * `notifyConversationId`. Combines two id-free sources so the operator never types a conversationId:
12
+ * - conversations the agent has actually handled (run-artifact summaries), filtered to
13
+ * notify-capable + running channels, newest-first;
14
+ * - the adapter allowlist entries (when not allow-all), surfaced as candidates the agent
15
+ * can reach even before it has conversed there (covers a fresh single-user agent).
16
+ * WhatsApp is excluded (no notify hook yet) so the agent never picks an undeliverable id.
17
+ */
18
+ export async function resolveNotifyDestinations(opts) {
19
+ const out = [];
20
+ const present = new Set();
21
+ const seen = await listSeenNotifyDestinations(opts.artifactDir);
22
+ for (const sighting of seen) {
23
+ if (!NOTIFY_CAPABLE.has(sighting.channelId) || !opts.isRunning(sighting.channelId)) {
24
+ continue;
25
+ }
26
+ out.push({
27
+ conversationId: sighting.conversationId,
28
+ channelId: sighting.channelId,
29
+ ...(sighting.lastSeen === undefined ? {} : { lastSeen: sighting.lastSeen }),
30
+ });
31
+ present.add(sighting.conversationId);
32
+ }
33
+ if (opts.isRunning("telegram")) {
34
+ for (const chatId of await telegramAllowlist(opts)) {
35
+ addAllowlisted(out, present, `telegram:${chatId}`, "telegram");
36
+ }
37
+ }
38
+ if (opts.isRunning("slack")) {
39
+ for (const channelId of await slackAllowlist(opts)) {
40
+ addAllowlisted(out, present, `slack:${channelId}`, "slack");
41
+ }
42
+ }
43
+ return out;
44
+ }
45
+ function addAllowlisted(out, present, conversationId, channelId) {
46
+ if (present.has(conversationId)) {
47
+ return;
48
+ }
49
+ present.add(conversationId);
50
+ out.push({ conversationId, channelId, fromAllowlist: true });
51
+ }
52
+ /** Allowlisted Telegram chat ids (empty when allow-all, disabled, or unavailable — no enumerable candidate). */
53
+ async function telegramAllowlist(opts) {
54
+ try {
55
+ const adapter = await loadTelegramModule();
56
+ const config = await adapter.loadTelegramAdapterConfig({ env: opts.input.env, jsonPath: opts.input.configPath });
57
+ return config.enabled && !config.allowAllChats ? config.allowedChatIds : [];
58
+ }
59
+ catch (error) {
60
+ opts.logger?.warn?.("notify destinations: telegram allowlist unavailable.", { reason: reasonOf(error) });
61
+ return [];
62
+ }
63
+ }
64
+ /** Allowlisted Slack channel ids (empty when allow-all, disabled, or unavailable). */
65
+ async function slackAllowlist(opts) {
66
+ try {
67
+ const adapter = await loadSlackModule();
68
+ const config = await adapter.loadSlackAdapterConfig({ env: opts.input.env, jsonPath: opts.input.configPath });
69
+ return config.enabled && !config.allowAllChannels ? config.allowedChannelIds : [];
70
+ }
71
+ catch (error) {
72
+ opts.logger?.warn?.("notify destinations: slack allowlist unavailable.", { reason: reasonOf(error) });
73
+ return [];
74
+ }
75
+ }
76
+ function reasonOf(error) {
77
+ return error instanceof Error ? error.message : String(error);
78
+ }
79
+ //# sourceMappingURL=notify-destinations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notify-destinations.js","sourceRoot":"","sources":["../src/notify-destinations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Maps a message the agent POSTED (`channelId` + Slack `ts`) back to the
3
+ * conversation that produced it, so a later in-thread reply can be resolved to
4
+ * that conversation and continue its history/session.
5
+ *
6
+ * Why this exists: a scheduled/proactive post (e.g. a daily digest) runs under a
7
+ * synthetic conversationId (e.g. `scheduled-scan`) and posts via
8
+ * `slack_send_message`, which registers no `slack:` conversation. When the user
9
+ * replies, the Slack adapter derives `slack:<channel>:<posted-ts>` — an id with no
10
+ * history. This index closes that gap: the producer records `(channel, ts) →
11
+ * producing conversationId`; the consumer (inbound dispatch) looks it up and
12
+ * aliases the reply onto the producing conversation.
13
+ *
14
+ * Storage is an append-only JSONL file inside the run-artifact dir. Append-only
15
+ * keeps cross-process writes safe: the `slack_send_message` child process and the
16
+ * adapter both only ever append (small `O_APPEND` writes are atomic), and only the
17
+ * single adapter process compacts. A `.jsonl` file is ignored by the
18
+ * `.summary.json` artifact scanners (see `seen-conversations.ts`), so it never
19
+ * collides with run-artifact tooling.
20
+ */
21
+ export declare const POSTED_MESSAGE_INDEX_FILENAME = "posted-message-index.jsonl";
22
+ export interface PostedMessageEntry {
23
+ /** Slack channel/DM id the message was posted to. */
24
+ readonly channelId: string;
25
+ /** Slack message timestamp returned by `chat.postMessage`. */
26
+ readonly ts: string;
27
+ /** Producing conversationId, de-bucketed to its base form. */
28
+ readonly conversationId: string;
29
+ /** ISO timestamp of when the entry was written. */
30
+ readonly writtenAt: string;
31
+ }
32
+ /** The single index-file path both producer and consumer agree on. */
33
+ export declare function resolvePostedMessageIndexPath(artifactDir: string): string;
34
+ /** Strip a trailing daily-rollover bucket so the stored id is the base producing id. */
35
+ export declare function basePostedConversationId(conversationId: string): string;
36
+ /**
37
+ * Record that `conversationId` posted a message at `(channelId, ts)`. Best-effort:
38
+ * a failed index write must never fail the Slack post, so callers should not await
39
+ * this in a way that surfaces its errors — it swallows them. The stored
40
+ * conversationId is de-bucketed so the consumer can let the responder re-bucket to
41
+ * the reply's own day (consistent with daily session rollover).
42
+ */
43
+ export declare function appendPostedMessage(indexPath: string, entry: {
44
+ channelId: string;
45
+ ts: string;
46
+ conversationId: string;
47
+ }, now?: () => Date): Promise<void>;
48
+ /**
49
+ * Resolve the producing conversationId for a posted message, newest write wins.
50
+ * Returns `undefined` when the file is missing or has no matching entry, so the
51
+ * caller falls back to the default (a fresh `slack:` conversation) — no regression.
52
+ */
53
+ export declare function lookupProducingConversation(indexPath: string, channelId: string, ts: string): Promise<string | undefined>;
54
+ /**
55
+ * Bound file growth by rewriting the index with only the newest `maxEntries`
56
+ * (by write time, de-duped to the newest entry per `channel+ts`). Consumer-only —
57
+ * a single process compacts, via temp-file + rename so a concurrent append is
58
+ * never interleaved with a partial rewrite. Best-effort.
59
+ */
60
+ export declare function compactPostedMessageIndex(indexPath: string, maxEntries?: number): Promise<void>;
61
+ //# sourceMappingURL=posted-message-index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"posted-message-index.d.ts","sourceRoot":"","sources":["../src/posted-message-index.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,eAAO,MAAM,6BAA6B,+BAA+B,CAAC;AAO1E,MAAM,WAAW,kBAAkB;IACjC,qDAAqD;IACrD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,8DAA8D;IAC9D,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,mDAAmD;IACnD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,sEAAsE;AACtE,wBAAgB,6BAA6B,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED,wFAAwF;AACxF,wBAAgB,wBAAwB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAEvE;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,EAChE,GAAG,GAAE,MAAM,IAAuB,GACjC,OAAO,CAAC,IAAI,CAAC,CA6Bf;AAED;;;;GAIG;AACH,wBAAsB,2BAA2B,CAC/C,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAgB7B;AAED;;;;;GAKG;AACH,wBAAsB,yBAAyB,CAC7C,SAAS,EAAE,MAAM,EACjB,UAAU,GAAE,MAAoC,GAC/C,OAAO,CAAC,IAAI,CAAC,CAyBf"}
@@ -0,0 +1,178 @@
1
+ import { appendFile, mkdir, readFile, rename, writeFile } from "node:fs/promises";
2
+ import { dirname, join } from "node:path";
3
+ /**
4
+ * Maps a message the agent POSTED (`channelId` + Slack `ts`) back to the
5
+ * conversation that produced it, so a later in-thread reply can be resolved to
6
+ * that conversation and continue its history/session.
7
+ *
8
+ * Why this exists: a scheduled/proactive post (e.g. a daily digest) runs under a
9
+ * synthetic conversationId (e.g. `scheduled-scan`) and posts via
10
+ * `slack_send_message`, which registers no `slack:` conversation. When the user
11
+ * replies, the Slack adapter derives `slack:<channel>:<posted-ts>` — an id with no
12
+ * history. This index closes that gap: the producer records `(channel, ts) →
13
+ * producing conversationId`; the consumer (inbound dispatch) looks it up and
14
+ * aliases the reply onto the producing conversation.
15
+ *
16
+ * Storage is an append-only JSONL file inside the run-artifact dir. Append-only
17
+ * keeps cross-process writes safe: the `slack_send_message` child process and the
18
+ * adapter both only ever append (small `O_APPEND` writes are atomic), and only the
19
+ * single adapter process compacts. A `.jsonl` file is ignored by the
20
+ * `.summary.json` artifact scanners (see `seen-conversations.ts`), so it never
21
+ * collides with run-artifact tooling.
22
+ */
23
+ export const POSTED_MESSAGE_INDEX_FILENAME = "posted-message-index.jsonl";
24
+ /** Daily-rollover bucket suffix the responder appends (`…#2026-06-22`). */
25
+ const ROLLOVER_BUCKET = /#\d{4}-\d{2}-\d{2}$/u;
26
+ const DEFAULT_COMPACT_MAX_ENTRIES = 5000;
27
+ /** The single index-file path both producer and consumer agree on. */
28
+ export function resolvePostedMessageIndexPath(artifactDir) {
29
+ return join(artifactDir, POSTED_MESSAGE_INDEX_FILENAME);
30
+ }
31
+ /** Strip a trailing daily-rollover bucket so the stored id is the base producing id. */
32
+ export function basePostedConversationId(conversationId) {
33
+ return conversationId.replace(ROLLOVER_BUCKET, "");
34
+ }
35
+ /**
36
+ * Record that `conversationId` posted a message at `(channelId, ts)`. Best-effort:
37
+ * a failed index write must never fail the Slack post, so callers should not await
38
+ * this in a way that surfaces its errors — it swallows them. The stored
39
+ * conversationId is de-bucketed so the consumer can let the responder re-bucket to
40
+ * the reply's own day (consistent with daily session rollover).
41
+ */
42
+ export async function appendPostedMessage(indexPath, entry, now = () => new Date()) {
43
+ const channelId = entry.channelId.trim();
44
+ const ts = entry.ts.trim();
45
+ const conversationId = basePostedConversationId(entry.conversationId.trim());
46
+ if (channelId.length === 0 || ts.length === 0 || conversationId.length === 0) {
47
+ return;
48
+ }
49
+ const record = {
50
+ channelId,
51
+ ts,
52
+ conversationId,
53
+ writtenAt: now().toISOString(),
54
+ };
55
+ const line = `${JSON.stringify(record)}\n`;
56
+ try {
57
+ await appendFile(indexPath, line, "utf8");
58
+ }
59
+ catch (error) {
60
+ if (error?.code !== "ENOENT") {
61
+ return; // best-effort
62
+ }
63
+ // Artifact dir not created yet (agent never wrote a summary here). Create it
64
+ // and retry once; still best-effort.
65
+ try {
66
+ await mkdir(dirname(indexPath), { recursive: true });
67
+ await appendFile(indexPath, line, "utf8");
68
+ }
69
+ catch {
70
+ // Give up silently.
71
+ }
72
+ }
73
+ }
74
+ /**
75
+ * Resolve the producing conversationId for a posted message, newest write wins.
76
+ * Returns `undefined` when the file is missing or has no matching entry, so the
77
+ * caller falls back to the default (a fresh `slack:` conversation) — no regression.
78
+ */
79
+ export async function lookupProducingConversation(indexPath, channelId, ts) {
80
+ const wantChannel = channelId.trim();
81
+ const wantTs = ts.trim();
82
+ if (wantChannel.length === 0 || wantTs.length === 0) {
83
+ return undefined;
84
+ }
85
+ let match;
86
+ for (const entry of await readEntries(indexPath)) {
87
+ if (entry.channelId !== wantChannel || entry.ts !== wantTs) {
88
+ continue;
89
+ }
90
+ if (match === undefined || entry.writtenAt >= match.writtenAt) {
91
+ match = entry;
92
+ }
93
+ }
94
+ return match?.conversationId;
95
+ }
96
+ /**
97
+ * Bound file growth by rewriting the index with only the newest `maxEntries`
98
+ * (by write time, de-duped to the newest entry per `channel+ts`). Consumer-only —
99
+ * a single process compacts, via temp-file + rename so a concurrent append is
100
+ * never interleaved with a partial rewrite. Best-effort.
101
+ */
102
+ export async function compactPostedMessageIndex(indexPath, maxEntries = DEFAULT_COMPACT_MAX_ENTRIES) {
103
+ const entries = await readEntries(indexPath);
104
+ if (entries.length <= maxEntries) {
105
+ return;
106
+ }
107
+ // Newest entry per (channel, ts), then newest-first, then cap.
108
+ const latest = new Map();
109
+ for (const entry of entries) {
110
+ const key = `${entry.channelId} ${entry.ts}`;
111
+ const prior = latest.get(key);
112
+ if (prior === undefined || entry.writtenAt >= prior.writtenAt) {
113
+ latest.set(key, entry);
114
+ }
115
+ }
116
+ const kept = [...latest.values()]
117
+ .sort((a, b) => (a.writtenAt < b.writtenAt ? 1 : a.writtenAt > b.writtenAt ? -1 : 0))
118
+ .slice(0, maxEntries);
119
+ const body = kept.map((entry) => JSON.stringify(entry)).join("\n");
120
+ const tmpPath = `${indexPath}.tmp-${String(kept.length)}`;
121
+ try {
122
+ await writeFile(tmpPath, kept.length === 0 ? "" : `${body}\n`, "utf8");
123
+ await rename(tmpPath, indexPath);
124
+ }
125
+ catch {
126
+ // Best-effort; leave the original file in place on failure.
127
+ }
128
+ }
129
+ async function readEntries(indexPath) {
130
+ let raw;
131
+ try {
132
+ raw = await readFile(indexPath, "utf8");
133
+ }
134
+ catch {
135
+ return []; // missing/unreadable → nothing recorded yet
136
+ }
137
+ const out = [];
138
+ for (const line of raw.split("\n")) {
139
+ const trimmed = line.trim();
140
+ if (trimmed.length === 0) {
141
+ continue;
142
+ }
143
+ const parsed = parseEntry(trimmed);
144
+ if (parsed !== undefined) {
145
+ out.push(parsed);
146
+ }
147
+ }
148
+ return out;
149
+ }
150
+ function parseEntry(line) {
151
+ let json;
152
+ try {
153
+ json = JSON.parse(line);
154
+ }
155
+ catch {
156
+ return undefined; // tolerate a torn/partial line
157
+ }
158
+ if (typeof json !== "object" || json === null) {
159
+ return undefined;
160
+ }
161
+ const record = json;
162
+ const channelId = stringField(record.channelId);
163
+ const ts = stringField(record.ts);
164
+ const conversationId = stringField(record.conversationId);
165
+ if (channelId === undefined || ts === undefined || conversationId === undefined) {
166
+ return undefined;
167
+ }
168
+ return {
169
+ channelId,
170
+ ts,
171
+ conversationId,
172
+ writtenAt: stringField(record.writtenAt) ?? "",
173
+ };
174
+ }
175
+ function stringField(value) {
176
+ return typeof value === "string" && value.length > 0 ? value : undefined;
177
+ }
178
+ //# sourceMappingURL=posted-message-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"posted-message-index.js","sourceRoot":"","sources":["../src/posted-message-index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { NotifyDeliveryResult } from "@mono-agent/agent-contracts";
2
+ import type { ChannelId, MonoAgentAppLogger, RunningChannel } from "./channels.js";
3
+ export type { NotifyDeliveryResult } from "@mono-agent/agent-contracts";
4
+ /** The push channel that owns a destination conversationId (requires a `<scheme>:<target>` form), or undefined. */
5
+ export declare function channelIdForConversation(conversationId: string): ChannelId | undefined;
6
+ export interface ProactiveNotifyInput {
7
+ /** Destination conversationId, e.g. `telegram:42` or `slack:C1:171.5`. */
8
+ readonly conversationId: string;
9
+ /** The message to deliver. With `verbatim`, posted as-is; otherwise run as a turn. */
10
+ readonly text: string;
11
+ /**
12
+ * Deliver `text` VERBATIM — post it to the destination unchanged with no model
13
+ * call, then record it to the conversation's history (native cron/webhook
14
+ * notification). Without it, `text` is a prompt run as a turn on the
15
+ * destination's harness (e.g. a Slack interactive trigger).
16
+ */
17
+ readonly verbatim?: boolean;
18
+ /** Currently running channels, keyed by id (the app's live registry). */
19
+ readonly running: ReadonlyMap<ChannelId, Pick<RunningChannel, "notify">>;
20
+ readonly logger?: MonoAgentAppLogger;
21
+ }
22
+ /**
23
+ * Route a proactive notification to the channel that owns its destination
24
+ * conversation, so the message runs as a real turn on that channel's own harness
25
+ * (shared session/history) and is delivered through its normal stream. The owning
26
+ * channel's `notify` hook enforces its adapter allowlist before delivering, so a
27
+ * non-allowlisted (e.g. payload-supplied) destination is rejected here. Returns a
28
+ * structured {@link NotifyDeliveryResult}; never throws (the trigger run already
29
+ * succeeded), so the caller can report the outcome to the model.
30
+ */
31
+ export declare function routeProactiveNotification(input: ProactiveNotifyInput): Promise<NotifyDeliveryResult>;
32
+ //# sourceMappingURL=proactive-notify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proactive-notify.d.ts","sourceRoot":"","sources":["../src/proactive-notify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAExE,OAAO,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAInF,YAAY,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAcxE,mHAAmH;AACnH,wBAAgB,wBAAwB,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAMtF;AAED,MAAM,WAAW,oBAAoB;IACnC,0EAA0E;IAC1E,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,sFAAsF;IACtF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC,CAAC;IACzE,QAAQ,CAAC,MAAM,CAAC,EAAE,kBAAkB,CAAC;CACtC;AAED;;;;;;;;GAQG;AACH,wBAAsB,0BAA0B,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA+B3G"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Push channels a proactive notification can be delivered to. The conversationId
3
+ * scheme (the part before the first `:`) identifies the owning channel; only
4
+ * these channels run a destination harness that can both produce and deliver a
5
+ * turn. cron/webhook/openai-api/a2a are request-driven, not push destinations.
6
+ */
7
+ const PUSH_CHANNEL_BY_SCHEME = {
8
+ telegram: "telegram",
9
+ slack: "slack",
10
+ whatsapp: "whatsapp",
11
+ };
12
+ /** The push channel that owns a destination conversationId (requires a `<scheme>:<target>` form), or undefined. */
13
+ export function channelIdForConversation(conversationId) {
14
+ const colon = conversationId.indexOf(":");
15
+ if (colon <= 0) {
16
+ return undefined;
17
+ }
18
+ return PUSH_CHANNEL_BY_SCHEME[conversationId.slice(0, colon)];
19
+ }
20
+ /**
21
+ * Route a proactive notification to the channel that owns its destination
22
+ * conversation, so the message runs as a real turn on that channel's own harness
23
+ * (shared session/history) and is delivered through its normal stream. The owning
24
+ * channel's `notify` hook enforces its adapter allowlist before delivering, so a
25
+ * non-allowlisted (e.g. payload-supplied) destination is rejected here. Returns a
26
+ * structured {@link NotifyDeliveryResult}; never throws (the trigger run already
27
+ * succeeded), so the caller can report the outcome to the model.
28
+ */
29
+ export async function routeProactiveNotification(input) {
30
+ const channelId = channelIdForConversation(input.conversationId);
31
+ if (channelId === undefined) {
32
+ input.logger?.warn?.("Proactive notification skipped: unrecognized destination.", {
33
+ conversationId: input.conversationId,
34
+ });
35
+ return { delivered: false, reason: "unrecognized destination conversationId" };
36
+ }
37
+ const channel = input.running.get(channelId);
38
+ if (channel?.notify === undefined) {
39
+ input.logger?.warn?.("Proactive notification skipped: destination channel is not running or does not support delivery.", { conversationId: input.conversationId, channelId });
40
+ return { delivered: false, reason: `${channelId} channel is not running or does not support proactive delivery` };
41
+ }
42
+ try {
43
+ return await channel.notify({
44
+ conversationId: input.conversationId,
45
+ text: input.text,
46
+ ...(input.verbatim === undefined ? {} : { verbatim: input.verbatim }),
47
+ });
48
+ }
49
+ catch (error) {
50
+ const reason = reasonOf(error);
51
+ input.logger?.warn?.("Proactive notification failed: destination channel notify threw.", {
52
+ conversationId: input.conversationId,
53
+ channelId,
54
+ reason,
55
+ });
56
+ return { delivered: false, reason };
57
+ }
58
+ }
59
+ function reasonOf(error) {
60
+ return error instanceof Error ? error.message : String(error);
61
+ }
62
+ //# sourceMappingURL=proactive-notify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proactive-notify.js","sourceRoot":"","sources":["../src/proactive-notify.ts"],"names":[],"mappings":"AAQA;;;;;GAKG;AACH,MAAM,sBAAsB,GAAuC;IACjE,QAAQ,EAAE,UAAU;IACpB,KAAK,EAAE,OAAO;IACd,QAAQ,EAAE,UAAU;CACrB,CAAC;AAEF,mHAAmH;AACnH,MAAM,UAAU,wBAAwB,CAAC,cAAsB;IAC7D,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC1C,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QACf,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,sBAAsB,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;AAChE,CAAC;AAmBD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAAC,KAA2B;IAC1E,MAAM,SAAS,GAAG,wBAAwB,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IACjE,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,2DAA2D,EAAE;YAChF,cAAc,EAAE,KAAK,CAAC,cAAc;SACrC,CAAC,CAAC;QACH,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,yCAAyC,EAAE,CAAC;IACjF,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC7C,IAAI,OAAO,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;QAClC,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,CAClB,kGAAkG,EAClG,EAAE,cAAc,EAAE,KAAK,CAAC,cAAc,EAAE,SAAS,EAAE,CACpD,CAAC;QACF,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,gEAAgE,EAAE,CAAC;IACpH,CAAC;IACD,IAAI,CAAC;QACH,OAAO,MAAM,OAAO,CAAC,MAAM,CAAC;YAC1B,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,GAAG,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;SACtE,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC/B,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,kEAAkE,EAAE;YACvF,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,SAAS;YACT,MAAM;SACP,CAAC,CAAC;QACH,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IACtC,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { MonoAgentConfigJson } from "@mono-agent/config";
2
+ import type { RecipeInput, RecipeInputValues } from "./types.js";
3
+ export declare const DEFAULT_MODEL = "claude:claude-sonnet-4-6";
4
+ /** The model input every recipe shares; overridable from `--model`. */
5
+ export declare const MODEL_INPUT: RecipeInput;
6
+ /**
7
+ * The adapter-neutral skeleton every recipe extends: runtime model, identity,
8
+ * empty tool policy, local artifacts, and the trace registry. Recipes spread
9
+ * this and add their channel / memory / sandbox / observability blocks. Mirrors
10
+ * `init.ts`'s scaffold so a recipe-built folder matches a hand-init'd one.
11
+ */
12
+ export declare function baseConfig(input: RecipeInputValues): MonoAgentConfigJson;
13
+ /** A `memory` block for the given tier, rooted at the standard memory path. */
14
+ export declare function memoryBlock(mode: "lite" | "journal" | "bujo"): NonNullable<MonoAgentConfigJson["memory"]>;
15
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/recipes/base.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAG9D,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEjE,eAAO,MAAM,aAAa,6BAA6B,CAAC;AAExD,uEAAuE;AACvE,eAAO,MAAM,WAAW,EAAE,WAKzB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,iBAAiB,GAAG,mBAAmB,CA0BxE;AAED,+EAA+E;AAC/E,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAChC,WAAW,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC,CAM5C"}