tomo-ai 0.4.1 → 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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.0 (2026-04-26)
4
+
5
+ ### Features
6
+
7
+ - **Proactive messaging via `send_message` MCP tool** (#64). New in-process MCP server (`tomo-internal`) exposes `send_message(target, message, mode)` and `list_sessions()`. Two modes: `delegate` (default) hands the request to the recipient session's Claude as a system message — that Claude composes the actual message in its own voice with full local context (participant names, recent conversation, group tone); fire-and-forget via the existing `handleCronMessage` primitive, the user observes the outcome directly in the recipient channel. `direct` posts verbatim text via `Channel.send()` without triggering a recipient Claude turn — best for factual broadcasts and self-targeted mid-loop progress updates. `list_sessions` returns identities and active groups with `chatTitle` + `participants` metadata, both now persisted on `SessionEntry` in `_sessions.json` (existing group entries populate on next group activity).
8
+ - **Configurable `maxTurns`, default raised to 50** (#64). The Agent SDK `maxTurns` ceiling (one turn ≈ one tool-use round) is now read from `config.maxTurns` instead of being hardcoded to 30. Override via `maxTurns` in `~/.tomo/config.json` or `TOMO_MAX_TURNS` env.
9
+ - **`canUseTool` callback grants writes under `<workspaceDir>/.claude/skills/`** (#64). The SDK's `bypassPermissions` mode does not actually exempt `.claude/` writes despite the docs implying it does, so creating/editing skills via Edit/Write hung on a permission prompt with no UI to approve. A narrow callback now auto-approves writes under the workspace's `.claude/skills/**` (Write/Edit/MultiEdit/NotebookEdit, plus Bash commands targeting that path); everything else that reaches the callback is denied with a descriptive message.
10
+ - **Per-Telegram-group passive listen mode** (#64). New `channels.telegram.passiveGroups: string[]` config field accepts a list of group chatIds. In those groups, Tomo sees every message (no `@mention` required) and decides via `NO_REPLY` whether to respond — same shape as iMessage groups have always behaved. The typing-indicator skip and error-message suppression in `handleMessage` are generalized via a single `isPassiveListenGroup(channel, chatId)` helper. iMessage groups remain implicitly passive (no config needed).
11
+ - **Group context moved into the system prompt** (#64). The "you are in <title>, participants are X, listen mode is passive, NO_REPLY for noise" instructions previously injected as a one-time runtime turn via `updateGroupContext` are now part of the per-session system prompt block (under a new `## Group Chat Context` heading). Survives LCM compaction — earlier the rules could be summarized away, after which Tomo would start replying to passive-group chatter. `updateGroupContext` is now pure persistence (participants + title to `_sessions.json`); no more per-new-participant Claude turn cost. Snapshot of participants in the prompt is from session-creation time; new joiners are still cued by the `<sender>: <text>` message format.
12
+ - **Tool result events logged with originating tool name** (#64). Previously `consumeEvents` handled assistant `tool_use` blocks but silently dropped user `tool_result` blocks, making it impossible to tell from the log whether a failed tool call was harness-rejected vs the model misreading. Adds a `pendingToolNames` map (tool_use_id → name) on `LiveSession` so result lines can be labelled, plus `summarizeToolResult` truncating to a 500-char readable line. `is_error` is surfaced at INFO level so failures stand out.
13
+
14
+ ### Other
15
+
16
+ - **`cli --version` now reads from `package.json` at runtime** (#64). Resolves the long-standing drift risk flagged in `0.4.1`: `src/cli.ts` previously hardcoded the version string and required a parallel update on every release bump. Now derived from `import.meta.url` → `../package.json`, so the package.json bump is the single source of truth.
17
+
18
+ ## 0.4.2 (2026-04-24)
19
+
20
+ ### Bug fixes
21
+
22
+ - **LCM past-day rollups no longer stuck** (#58). `DAILY_FRESH_TAIL = 32` (the guard that preserves warm context when rolling up today) was being applied to past days too — any past day with ≤32 raw events returned "No events found" and never promoted, even as the `RollupRunner` kept nudging every tick. Gate the fresh-tail branch on `resolvedPeriod === today`; past days compact in full. Observed in-session: dailies 04-08 (28), 04-11 (32), 04-15 (10), 04-16 (11), 04-19 (15) all stuck.
23
+ - **LCM nudges past days with leftover raw after a daily block** (#59). `findDuePromotions` previously skipped any past day whose `daily <day>` tag already existed, even when extra raw events sat outside that block. Observed: `daily 2026-04-22` absorbed ~408 events, then 238 more accumulated after and never got swept up. Now flags past days that have raw events regardless of existing block, with a floor of 8 events to suppress small residuals. Rebuild semantics of `tomo lcm daily --date <day>` absorb both the existing block and the leftover raw.
24
+
25
+ ### Documentation
26
+
27
+ - **Realistic LCM summary target lengths for bilingual use** (#60). Original targets (daily 300–1000 tok, weekly 500–1500, monthly 1000–2000, yearly 1500–3000) assumed pure English; in bilingual Chinese/English practice CJK characters tokenize ~3× denser, so real summaries consistently ran 3–6× over target. New ceilings: daily 1,000–2,500, weekly 2,000–4,000, monthly 3,000–6,000, yearly 5,000–10,000 tokens. Hierarchy compression ratios still hold (~3–5× per level). Also removed a stale "hot-tail > 40 events" line in `SKILL.md` that predated the context-% nudging.
28
+
29
+ ### Other
30
+
31
+ - Bump `actions/upload-artifact` 4 → 7 (#54).
32
+ - Bump dev dependencies group: 4 updates (#55).
33
+
3
34
  ## 0.4.1 (2026-04-19)
4
35
 
5
36
  ### Features
package/defaults/AGENT.md CHANGED
@@ -11,3 +11,12 @@ Don't narrate your process. Don't explain what you're "about to do." Just do it
11
11
  ## Mistakes
12
12
 
13
13
  You'll get things wrong. When you do: say so plainly, correct it, move on. Don't over-apologize.
14
+
15
+ ## Reaching Out
16
+
17
+ You have `list_sessions` and `send_message` tools for proactively posting to another conversation — most often a group chat the user is in. Two modes:
18
+
19
+ - **`delegate` (default)**: describe the intent ("follow up with Alice about her recent trip"). The recipient session's Claude composes the actual message in its own voice and context. Use for social or contextual messages.
20
+ - **`direct`**: send verbatim text. Use for factual broadcasts ("meeting moved to 3pm"), pasted content, or self-targeted mid-loop progress updates.
21
+
22
+ Call `list_sessions` first if you're unsure which group to address. For normal in-conversation responses, just reply with text — don't reach for these tools.
@@ -21,7 +21,7 @@ tomo lcm daily --session-id SESSION_ID --summary "<today's summary>"
21
21
 
22
22
  ## Writing
23
23
 
24
- Target length: **300-1000 tokens**. Day summaries are the closest to raw memory in the hierarchy, so they can keep the most texture.
24
+ Target length: **1,000-2,500 tokens** (bilingual Chinese/English; lower for pure English). Day summaries are the closest to raw memory in the hierarchy, so they can keep the most texture — but this is a ceiling, not a target to fill. If nothing happened that day, 300-500 tokens is fine.
25
25
 
26
26
  Structure by phases of the day rather than chronological minute-by-minute:
27
27
 
@@ -20,7 +20,7 @@ tomo lcm monthly --session-id SESSION_ID --summary "<monthly summary>"
20
20
 
21
21
  ## Writing
22
22
 
23
- Target length: **1000-2000 tokens**. Another level of compression — preserve the month's shape, lose week-to-week granularity.
23
+ Target length: **3,000-6,000 tokens** (bilingual CJK ceiling; lower for English). Another level of compression — preserve the month's shape, lose week-to-week granularity.
24
24
 
25
25
  Structure:
26
26
 
@@ -70,7 +70,7 @@ The harness will nudge you via a `System:` message when rollups are due (idempot
70
70
  ## When to act
71
71
 
72
72
  1. **Harness nudge** — always prioritize. The system tells you exactly which rollup to run.
73
- 2. **Hot-tail > 40 events** run `tomo lcm daily` to compress today so far.
73
+ 2. **Context 70%**the harness will nudge you to run `tomo lcm daily`.
74
74
  3. **Heavy tool output** — run `prune-tools` first (cheap, no summary needed).
75
75
  4. **Context > 70% or after big tool-heavy tasks** — use the above as appropriate.
76
76
 
@@ -82,11 +82,13 @@ See the per-level docs for tailored guidance. General rules:
82
82
  - Dates in **YYYY-MM-DD format** (searchable)
83
83
  - Preserve outcomes, decisions, key quotes — drop step-by-step narration
84
84
  - For conversations: one vivid detail beats a paragraph of abstraction
85
- - Target lengths:
86
- - daily: 300-1000 tokens
87
- - weekly: 500-1500 tokens
88
- - monthly: 1000-2000 tokens
89
- - yearly: 1500-3000 tokens
85
+ - Target lengths (assumes bilingual Chinese/English — CJK characters tokenize ~3× denser than English, so byte-budget scales up accordingly):
86
+ - daily: 1,000-2,500 tokens
87
+ - weekly: 2,000-4,000 tokens
88
+ - monthly: 3,000-6,000 tokens
89
+ - yearly: 5,000-10,000 tokens
90
+
91
+ If you're writing pure English, aim for the lower end (or below). These are ceilings for dense CJK content, not targets to fill.
90
92
 
91
93
  ## Archive & recall
92
94
 
@@ -19,7 +19,7 @@ tomo lcm weekly --session-id SESSION_ID --summary "<weekly summary>"
19
19
 
20
20
  ## Writing
21
21
 
22
- Target length: **500-1500 tokens**. One level more compressed than daily.
22
+ Target length: **2,000-4,000 tokens** (bilingual CJK ceiling; lower for English). One level more compressed than daily — should read cleanly without the 7 dailies at hand.
23
23
 
24
24
  Structure around **themes/arcs** of the week, not a day-by-day list:
25
25
 
@@ -19,7 +19,7 @@ tomo lcm yearly --session-id SESSION_ID --summary "<yearly summary>"
19
19
 
20
20
  ## Writing
21
21
 
22
- Target length: **1500-3000 tokens**. This is the most compressed level — it defines what you still remember about the year when everything below has been pruned.
22
+ Target length: **5,000-10,000 tokens** (bilingual CJK ceiling; lower for English). This is the most compressed level — it defines what you still remember about the year when everything below has been pruned.
23
23
 
24
24
  Structure:
25
25
 
@@ -13,7 +13,8 @@ Prefer editing via `tomo config` (interactive TUI). This reference is for readin
13
13
  "channels": {
14
14
  "telegram": {
15
15
  "token": "123456:ABC-DEF1234ghIkl-zyx57W2v...",
16
- "allowlist": ["123456789"]
16
+ "allowlist": ["123456789"],
17
+ "passiveGroups": ["-1001234567"]
17
18
  },
18
19
  "imessage": {
19
20
  "url": "https://your-bluebubbles.example.com",
@@ -34,7 +35,8 @@ Prefer editing via `tomo config` (interactive TUI). This reference is for readin
34
35
  ],
35
36
  "sessionModelOverrides": {
36
37
  "dm:alice": "claude-opus-4-7"
37
- }
38
+ },
39
+ "maxTurns": 50
38
40
  }
39
41
  ```
40
42
 
@@ -48,6 +50,7 @@ Prefer editing via `tomo config` (interactive TUI). This reference is for readin
48
50
  | `groupSecret` | string \| null | Passphrase users send in a group chat to activate Tomo there. `null` disables group chats entirely. |
49
51
  | `channels.telegram.token` | string | BotFather token (`123456:...`). Required to enable the Telegram channel. |
50
52
  | `channels.telegram.allowlist` | string[] | Telegram user IDs (as strings) permitted to DM the bot. Identity-bound chatIds are auto-allowed even if missing here. |
53
+ | `channels.telegram.passiveGroups` | string[] | Telegram group chatIds (negative IDs as strings) where Tomo should listen to every message — no `@mention` required. Tomo decides via `NO_REPLY` whether to respond. iMessage groups are always passive regardless of this list. |
51
54
  | `channels.imessage.url` | string | BlueBubbles server URL. Required to enable the iMessage channel. |
52
55
  | `channels.imessage.password` | string | BlueBubbles server password. |
53
56
  | `channels.imessage.webhookPort` | number | Port Tomo listens on for BlueBubbles webhooks. Default `3100`. |
@@ -56,9 +59,10 @@ Prefer editing via `tomo config` (interactive TUI). This reference is for readin
56
59
  | `identities[].channels` | object | `{ channelName: chatId }` — maps each channel the identity uses to its chatId. |
57
60
  | `identities[].replyPolicy` | string | `"last-active"` (reply on whichever channel the identity last messaged from) or a fixed channel name like `"telegram"` / `"imessage"` (always reply there). |
58
61
  | `sessionModelOverrides` | object | `{ sessionKey: modelId }` — per-session model override, takes precedence over top-level `model`. Keys are session keys (`dm:alice`, `telegram:12345`, etc.). |
62
+ | `maxTurns` | number | Max agent turns per single user message (one turn ≈ one tool-use round). Default `50`. Raise if you see "max turns exceeded" on long tool chains. |
59
63
 
60
64
  ## Requirements and overrides
61
65
 
62
66
  - **At least one channel must be configured** — either `channels.telegram.token` or `channels.imessage.url`. Startup fails otherwise.
63
- - **Env vars override file values** where they exist: `TELEGRAM_BOT_TOKEN`, `IMESSAGE_URL`, `IMESSAGE_PASSWORD`, `IMESSAGE_WEBHOOK_PORT`, `CLAUDE_MODEL`, `TOMO_CITY`, `TOMO_CONTINUITY`, `TOMO_WORKSPACE`, `SESSIONS_DIR`, `HISTORY_LIMIT`.
67
+ - **Env vars override file values** where they exist: `TELEGRAM_BOT_TOKEN`, `IMESSAGE_URL`, `IMESSAGE_PASSWORD`, `IMESSAGE_WEBHOOK_PORT`, `CLAUDE_MODEL`, `TOMO_CITY`, `TOMO_CONTINUITY`, `TOMO_WORKSPACE`, `SESSIONS_DIR`, `HISTORY_LIMIT`, `TOMO_MAX_TURNS`.
64
68
  - `workspaceDir`, `sessionsDir`, `historyLimit` are env-only — they're not read from the JSON file.
@@ -76,6 +76,24 @@ Every message includes a timestamp prefix like `[Mon 04/07 14:30 PDT]` so you al
76
76
  ### System messages
77
77
  Messages prefixed with `System:` are from the harness (cron triggers, group context), not from a human.
78
78
 
79
+ ### Group chats
80
+ Two listen modes per group:
81
+
82
+ - **Mention-required** (default for Telegram): you only receive messages that explicitly tag you. Respond as you would in a DM.
83
+ - **Passive** (default for iMessage; opt-in for Telegram via `channels.telegram.passiveGroups: ["<chatId>"]` in config.json): you see every message in the group without `@mention`. Reply only when genuinely useful — `NO_REPLY` to stay silent on chatter, greetings, or messages not directed at you.
84
+
85
+ The active mode plus group title and known participants are part of your per-session system prompt under `## Group Chat Context` whenever you're in a group session — survives compaction. Each incoming group message is prefixed with the sender name (`Alice: ...`) so you can attribute it.
86
+
87
+ ### Proactive messaging (MCP tools)
88
+ Two in-process MCP tools let you message outside the current conversation:
89
+
90
+ - `mcp__tomo-internal__list_sessions` — discover valid targets. Returns `{identities: [{name}], groups: [{key, title?, participants?}]}`. Group titles and participants populate as messages arrive in the group; an entry without them just hasn't seen activity since the schema landed.
91
+ - `mcp__tomo-internal__send_message(target, message, mode?)` — send to a target. Two modes:
92
+ - `delegate` (default): describe the *intent* (e.g. "follow up with Alice about her recent trip"). The recipient session's Claude composes the actual message in its own voice/context. Best for social or contextual relays. Fire-and-forget.
93
+ - `direct`: send the verbatim text. Recipient is not triggered into a Claude turn. Best for factual broadcasts ("meeting moved to 3pm"), pasted content, or self-targeted mid-loop progress updates.
94
+
95
+ Pass identity name (`"alice"`) or session key (`"telegram:-1001234567"`) as `target`. Call `list_sessions` first if unsure. Tool result lines (with `is_error` flag) appear in `tomo logs` immediately after the corresponding tool call.
96
+
79
97
  ## Skills
80
98
 
81
99
  ### Built-in skills (`tomo-*`)
package/dist/agent.d.ts CHANGED
@@ -1,4 +1,20 @@
1
1
  import type { Channel } from "./channels/types.js";
2
+ export type SendResult = {
3
+ ok: true;
4
+ } | {
5
+ ok: false;
6
+ error: string;
7
+ };
8
+ export interface SessionCatalog {
9
+ identities: Array<{
10
+ name: string;
11
+ }>;
12
+ groups: Array<{
13
+ key: string;
14
+ title?: string;
15
+ participants?: string[];
16
+ }>;
17
+ }
2
18
  export declare class Agent {
3
19
  private channels;
4
20
  private sessions;
@@ -9,9 +25,20 @@ export declare class Agent {
9
25
  private modelOverrides;
10
26
  private lastPromptHash;
11
27
  private contextNudged;
28
+ private pendingNotes;
29
+ private readonly internalMcpServer;
12
30
  constructor();
13
31
  /** Look up a channel by name */
14
32
  private getChannel;
33
+ /**
34
+ * Is this group a "passive listen" group? Tomo sees every message (no
35
+ * @mention required) and decides via NO_REPLY whether to respond.
36
+ * iMessage groups are always passive (the channel can't reliably detect
37
+ * mentions). Telegram (and others) opt in via config.passiveGroups.
38
+ */
39
+ private isPassiveListenGroup;
40
+ /** Snapshot of group metadata for the system prompt — null for non-group sessions. */
41
+ private buildGroupContext;
15
42
  /** Activate a group chat by adding it to the channel's allowlist */
16
43
  private activateGroup;
17
44
  addChannel(channel: Channel): void;
@@ -33,6 +60,11 @@ export declare class Agent {
33
60
  private hashString;
34
61
  private handleMessage;
35
62
  private runWithRetry;
63
+ /** Track participants and chat title for a group session. The actual rules
64
+ * (passive listen, NO_REPLY guidance, participant snapshot) are now part of
65
+ * the system prompt — see SessionContext.group in sdkOptions — so they
66
+ * survive compaction. This stays as pure persistence + in-memory tracking;
67
+ * no LLM injection. */
36
68
  private updateGroupContext;
37
69
  private injectTimestamp;
38
70
  /** Handle a cron-triggered message (queued per session key) */
@@ -45,6 +77,35 @@ export declare class Agent {
45
77
  * Skips group chats (Telegram negative IDs, iMessage group GUIDs). */
46
78
  private parseChannelKey;
47
79
  private findLastChatId;
80
+ /**
81
+ * Direct mode: post a verbatim message to a target session via Channel.send().
82
+ * No Claude query is invoked for the recipient — the message arrives as-is.
83
+ * A pending note is queued so the recipient's next Claude turn knows context.
84
+ */
85
+ sendToSession(target: string, text: string): Promise<SendResult>;
86
+ /**
87
+ * Delegate mode: queue a system request for the target session's Claude to
88
+ * compose and send a message in its own voice/context. Fire-and-forget — the
89
+ * caller's tool result returns as soon as the request is dispatched, not when
90
+ * the recipient's Claude finishes. The user observes the actual outcome in
91
+ * the recipient channel directly (since they're a participant).
92
+ *
93
+ * Note: delegate-to-self isn't blocked here. If it happens, the system
94
+ * request is just queued behind the current turn via enqueueForSession —
95
+ * one extra Claude turn fires, no infinite loop. For mid-loop self-progress
96
+ * updates, prefer direct mode (no extra turn).
97
+ */
98
+ delegateToSession(target: string, request: string): Promise<SendResult>;
99
+ /** Resolve a send_message `target` (identity name or session key) to (sessionKey, replyTarget). */
100
+ private resolveSendTarget;
101
+ /** Parse a "<channel>:<chatId>" key into a ReplyTarget. Group-friendly; for
102
+ * explicit-target paths only. Use parseChannelKey for notification fallbacks. */
103
+ private parseRawChannelKey;
104
+ /** Catalog of valid send_message targets, with friendly metadata for groups. Backs the `list_sessions` tool. */
105
+ listSessionCatalog(): SessionCatalog;
106
+ private queuePendingNote;
107
+ /** Drain notes queued for this session (e.g. by sendToSession) and return them as a prefix. */
108
+ private drainPendingNotes;
48
109
  /** Send a direct notification to the user's DM channel (no agent query) */
49
110
  sendNotification(text: string): Promise<void>;
50
111
  start(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAmB,MAAM,qBAAqB,CAAC;AAsVpE,qBAAa,KAAK;IAChB,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,QAAQ,CAAe;IAC/B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,aAAa,CAAoC;IACzD,OAAO,CAAC,iBAAiB,CAAkC;IAC3D,OAAO,CAAC,cAAc,CAA6B;IACnD,OAAO,CAAC,cAAc,CAAc;IAGpC,OAAO,CAAC,aAAa,CAA8B;;IAYnD,gCAAgC;IAChC,OAAO,CAAC,UAAU;IAIlB,oEAAoE;YACtD,aAAa;IAsB3B,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAMlC,8EAA8E;IAC9E,kBAAkB,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE;IAIxC;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IAWzB,kEAAkE;IAClE,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAMtC;YAEY,aAAa;IAwE3B,OAAO,CAAC,sBAAsB;IA4B9B,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,UAAU;YAQJ,aAAa;YA8Hb,YAAY;YA0EZ,kBAAkB;IA+BhC,OAAO,CAAC,eAAe;IAYvB,+DAA+D;IACzD,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAO7D,kBAAkB;IAwEhC,mFAAmF;IAC7E,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAqBvC,iBAAiB;IAoC/B;2EACuE;IACvE,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,cAAc;IAStB,2EAA2E;IACrE,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA0B7C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAkBtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAM5B"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAmB,MAAM,qBAAqB,CAAC;AAYpE,MAAM,MAAM,UAAU,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAErE,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpC,MAAM,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;CACzE;AAobD,qBAAa,KAAK;IAChB,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,QAAQ,CAAe;IAC/B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,aAAa,CAAoC;IACzD,OAAO,CAAC,iBAAiB,CAAkC;IAC3D,OAAO,CAAC,cAAc,CAA6B;IACnD,OAAO,CAAC,cAAc,CAAc;IAGpC,OAAO,CAAC,aAAa,CAA8B;IAInD,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAiC;;IAanE,gCAAgC;IAChC,OAAO,CAAC,UAAU;IAIlB;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IAK5B,sFAAsF;IACtF,OAAO,CAAC,iBAAiB;IAazB,oEAAoE;YACtD,aAAa;IAsB3B,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAMlC,8EAA8E;IAC9E,kBAAkB,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE;IAIxC;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IAWzB,kEAAkE;IAClE,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAMtC;YAEY,aAAa;IAwE3B,OAAO,CAAC,sBAAsB;IA6B9B,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,UAAU;YAQJ,aAAa;YA+Hb,YAAY;IA0E1B;;;;4BAIwB;IACxB,OAAO,CAAC,kBAAkB;IAW1B,OAAO,CAAC,eAAe;IAYvB,+DAA+D;IACzD,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAO7D,kBAAkB;IAwEhC,mFAAmF;IAC7E,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAqBvC,iBAAiB;IAoC/B;2EACuE;IACvE,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,cAAc;IAStB;;;;OAIG;IACG,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IA2BtE;;;;;;;;;;;OAWG;IACG,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAuB7E,mGAAmG;IACnG,OAAO,CAAC,iBAAiB;IAoBzB;sFACkF;IAClF,OAAO,CAAC,kBAAkB;IAU1B,gHAAgH;IAChH,kBAAkB,IAAI,cAAc;IAepC,OAAO,CAAC,gBAAgB;IAMxB,+FAA+F;IAC/F,OAAO,CAAC,iBAAiB;IAOzB,2EAA2E;IACrE,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA0B7C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAkBtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAM5B"}