@cachly-dev/mcp-server 0.10.129 โ†’ 0.10.131

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 (223) hide show
  1. package/README.md +2 -2
  2. package/dist/index.js +1 -7
  3. package/dist/packages/telegram-notify/client.js +2 -75
  4. package/dist/src/ambient-cli.js +7 -253
  5. package/dist/src/ambient-deps.js +1 -55
  6. package/dist/src/ambient-hooks.js +5 -278
  7. package/dist/src/ambient-ledger.js +6 -95
  8. package/dist/src/ambient-memory.js +1 -67
  9. package/dist/src/ambient-recall.js +1 -221
  10. package/dist/src/aussetzer.js +1 -225
  11. package/dist/src/auth.js +9 -140
  12. package/dist/src/autor-abzeichen.js +1 -56
  13. package/dist/src/autor.js +1 -136
  14. package/dist/src/bauabdruck.js +1 -93
  15. package/dist/src/bedeutung.js +2 -323
  16. package/dist/src/bench/cachly-bench.js +4 -249
  17. package/dist/src/bench/external-corpus.js +4 -135
  18. package/dist/src/bench/fixtures.js +1 -225
  19. package/dist/src/brain-export.js +16 -119
  20. package/dist/src/brain-watch-hook.js +8 -86
  21. package/dist/src/cachly-url.js +1 -21
  22. package/dist/src/ckg.js +1 -108
  23. package/dist/src/cls-hook.js +8 -94
  24. package/dist/src/confidence.js +1 -50
  25. package/dist/src/credentials.js +1 -85
  26. package/dist/src/deutsch.js +1 -223
  27. package/dist/src/doctor.js +2 -248
  28. package/dist/src/editor.js +1 -63
  29. package/dist/src/eingaenge-nachruesten.js +1 -290
  30. package/dist/src/eingaenge.js +2 -260
  31. package/dist/src/embeddings.js +13 -223
  32. package/dist/src/feldreparatur.js +3 -113
  33. package/dist/src/first-contact.js +4 -108
  34. package/dist/src/first-recall-proof.js +4 -41
  35. package/dist/src/funnel-milestones.js +2 -48
  36. package/dist/src/geliefert.js +1 -114
  37. package/dist/src/handlers/advanced.js +38 -537
  38. package/dist/src/handlers/brain.js +69 -4397
  39. package/dist/src/handlers/cache.js +59 -638
  40. package/dist/src/handlers/context.js +17 -182
  41. package/dist/src/handlers/fedbrain.js +40 -1436
  42. package/dist/src/handlers/instances.js +16 -201
  43. package/dist/src/handlers/roadmap.js +13 -175
  44. package/dist/src/handlers/share.js +19 -530
  45. package/dist/src/handlers/syndicate.js +38 -904
  46. package/dist/src/handlers/team.js +89 -1865
  47. package/dist/src/handlers/viz.js +3 -148
  48. package/dist/src/index.js +321 -4281
  49. package/dist/src/interferenz.js +1 -141
  50. package/dist/src/kostprobe.js +7 -125
  51. package/dist/src/lesson-preview.js +2 -133
  52. package/dist/src/namespace.js +1 -128
  53. package/dist/src/notifier.js +1 -6
  54. package/dist/src/rangfolge-stellschrauben.js +1 -0
  55. package/dist/src/rangfolge.js +1 -249
  56. package/dist/src/raumkorrektur.js +1 -197
  57. package/dist/src/recall-tiefe.js +1 -42
  58. package/dist/src/rerank.js +1 -154
  59. package/dist/src/resonanz.js +1 -140
  60. package/dist/src/search.js +1 -2104
  61. package/dist/src/seltenheitsbestand.js +1 -92
  62. package/dist/src/speicherlage.js +1 -84
  63. package/dist/src/spuren.js +1 -150
  64. package/dist/src/starter-corpus.js +1 -165
  65. package/dist/src/telemetry-types.js +0 -13
  66. package/dist/src/tools.js +10 -2465
  67. package/dist/src/toolspecs.js +1 -121
  68. package/dist/src/upgrade-nudge.js +1 -29
  69. package/dist/src/utils.js +1 -89
  70. package/dist/src/versuch.js +1 -264
  71. package/dist/src/vorspann.js +1 -146
  72. package/dist/src/wartung/vektoren-verdichten.js +1 -200
  73. package/dist/src/werkzeug-nutzung.js +1 -72
  74. package/dist/src/wertbeitrag.js +1 -203
  75. package/dist/src/wirkungsspur.js +1 -0
  76. package/glama.json +1 -1
  77. package/package.json +8 -7
  78. package/server.json +3 -3
  79. package/dist/index.d.ts +0 -1
  80. package/dist/index.js.map +0 -1
  81. package/dist/packages/telegram-notify/client.d.ts +0 -19
  82. package/dist/packages/telegram-notify/client.js.map +0 -1
  83. package/dist/src/ambient-cli.d.ts +0 -101
  84. package/dist/src/ambient-cli.js.map +0 -1
  85. package/dist/src/ambient-deps.d.ts +0 -26
  86. package/dist/src/ambient-deps.js.map +0 -1
  87. package/dist/src/ambient-hooks.d.ts +0 -137
  88. package/dist/src/ambient-hooks.js.map +0 -1
  89. package/dist/src/ambient-ledger.d.ts +0 -19
  90. package/dist/src/ambient-ledger.js.map +0 -1
  91. package/dist/src/ambient-memory.d.ts +0 -12
  92. package/dist/src/ambient-memory.js.map +0 -1
  93. package/dist/src/ambient-recall.d.ts +0 -127
  94. package/dist/src/ambient-recall.js.map +0 -1
  95. package/dist/src/aussetzer.d.ts +0 -156
  96. package/dist/src/aussetzer.js.map +0 -1
  97. package/dist/src/auth.d.ts +0 -43
  98. package/dist/src/auth.js.map +0 -1
  99. package/dist/src/autor-abzeichen.d.ts +0 -41
  100. package/dist/src/autor-abzeichen.js.map +0 -1
  101. package/dist/src/autor.d.ts +0 -101
  102. package/dist/src/autor.js.map +0 -1
  103. package/dist/src/bauabdruck-daten.generiert.json +0 -5
  104. package/dist/src/bauabdruck.d.ts +0 -38
  105. package/dist/src/bauabdruck.js.map +0 -1
  106. package/dist/src/bedeutung.d.ts +0 -168
  107. package/dist/src/bedeutung.js.map +0 -1
  108. package/dist/src/bench/cachly-bench.d.ts +0 -61
  109. package/dist/src/bench/cachly-bench.js.map +0 -1
  110. package/dist/src/bench/external-corpus.d.ts +0 -44
  111. package/dist/src/bench/external-corpus.js.map +0 -1
  112. package/dist/src/bench/fixtures.d.ts +0 -37
  113. package/dist/src/bench/fixtures.js.map +0 -1
  114. package/dist/src/brain-export.d.ts +0 -64
  115. package/dist/src/brain-export.js.map +0 -1
  116. package/dist/src/brain-watch-hook.d.ts +0 -21
  117. package/dist/src/brain-watch-hook.js.map +0 -1
  118. package/dist/src/cachly-url.d.ts +0 -68
  119. package/dist/src/cachly-url.js.map +0 -1
  120. package/dist/src/ckg.d.ts +0 -54
  121. package/dist/src/ckg.js.map +0 -1
  122. package/dist/src/cls-hook.d.ts +0 -15
  123. package/dist/src/cls-hook.js.map +0 -1
  124. package/dist/src/confidence.d.ts +0 -19
  125. package/dist/src/confidence.js.map +0 -1
  126. package/dist/src/credentials.d.ts +0 -37
  127. package/dist/src/credentials.js.map +0 -1
  128. package/dist/src/deutsch.d.ts +0 -98
  129. package/dist/src/deutsch.js.map +0 -1
  130. package/dist/src/doctor.d.ts +0 -47
  131. package/dist/src/doctor.js.map +0 -1
  132. package/dist/src/editor.d.ts +0 -9
  133. package/dist/src/editor.js.map +0 -1
  134. package/dist/src/eingaenge-nachruesten.d.ts +0 -41
  135. package/dist/src/eingaenge-nachruesten.js.map +0 -1
  136. package/dist/src/eingaenge.d.ts +0 -159
  137. package/dist/src/eingaenge.js.map +0 -1
  138. package/dist/src/embeddings.d.ts +0 -48
  139. package/dist/src/embeddings.js.map +0 -1
  140. package/dist/src/feldreparatur.d.ts +0 -58
  141. package/dist/src/feldreparatur.js.map +0 -1
  142. package/dist/src/first-contact.d.ts +0 -56
  143. package/dist/src/first-contact.js.map +0 -1
  144. package/dist/src/first-recall-proof.d.ts +0 -19
  145. package/dist/src/first-recall-proof.js.map +0 -1
  146. package/dist/src/funnel-milestones.d.ts +0 -5
  147. package/dist/src/funnel-milestones.js.map +0 -1
  148. package/dist/src/geliefert.d.ts +0 -63
  149. package/dist/src/geliefert.js.map +0 -1
  150. package/dist/src/handlers/advanced.d.ts +0 -6
  151. package/dist/src/handlers/advanced.js.map +0 -1
  152. package/dist/src/handlers/brain.d.ts +0 -41
  153. package/dist/src/handlers/brain.js.map +0 -1
  154. package/dist/src/handlers/cache.d.ts +0 -6
  155. package/dist/src/handlers/cache.js.map +0 -1
  156. package/dist/src/handlers/context.d.ts +0 -6
  157. package/dist/src/handlers/context.js.map +0 -1
  158. package/dist/src/handlers/fedbrain.d.ts +0 -18
  159. package/dist/src/handlers/fedbrain.js.map +0 -1
  160. package/dist/src/handlers/instances.d.ts +0 -33
  161. package/dist/src/handlers/instances.js.map +0 -1
  162. package/dist/src/handlers/roadmap.d.ts +0 -6
  163. package/dist/src/handlers/roadmap.js.map +0 -1
  164. package/dist/src/handlers/share.d.ts +0 -8
  165. package/dist/src/handlers/share.js.map +0 -1
  166. package/dist/src/handlers/syndicate.d.ts +0 -6
  167. package/dist/src/handlers/syndicate.js.map +0 -1
  168. package/dist/src/handlers/team.d.ts +0 -45
  169. package/dist/src/handlers/team.js.map +0 -1
  170. package/dist/src/handlers/viz.d.ts +0 -6
  171. package/dist/src/handlers/viz.js.map +0 -1
  172. package/dist/src/index.d.ts +0 -93
  173. package/dist/src/index.js.map +0 -1
  174. package/dist/src/interferenz.d.ts +0 -111
  175. package/dist/src/interferenz.js.map +0 -1
  176. package/dist/src/kostprobe.d.ts +0 -25
  177. package/dist/src/kostprobe.js.map +0 -1
  178. package/dist/src/lesson-preview.d.ts +0 -81
  179. package/dist/src/lesson-preview.js.map +0 -1
  180. package/dist/src/namespace.d.ts +0 -20
  181. package/dist/src/namespace.js.map +0 -1
  182. package/dist/src/notifier.d.ts +0 -5
  183. package/dist/src/notifier.js.map +0 -1
  184. package/dist/src/rangfolge.d.ts +0 -205
  185. package/dist/src/rangfolge.js.map +0 -1
  186. package/dist/src/raumkorrektur.d.ts +0 -100
  187. package/dist/src/raumkorrektur.js.map +0 -1
  188. package/dist/src/recall-tiefe.d.ts +0 -48
  189. package/dist/src/recall-tiefe.js.map +0 -1
  190. package/dist/src/rerank.d.ts +0 -48
  191. package/dist/src/rerank.js.map +0 -1
  192. package/dist/src/resonanz.d.ts +0 -85
  193. package/dist/src/resonanz.js.map +0 -1
  194. package/dist/src/search.d.ts +0 -153
  195. package/dist/src/search.js.map +0 -1
  196. package/dist/src/seltenheitsbestand.d.ts +0 -53
  197. package/dist/src/seltenheitsbestand.js.map +0 -1
  198. package/dist/src/speicherlage.d.ts +0 -51
  199. package/dist/src/speicherlage.js.map +0 -1
  200. package/dist/src/spuren.d.ts +0 -97
  201. package/dist/src/spuren.js.map +0 -1
  202. package/dist/src/starter-corpus.d.ts +0 -28
  203. package/dist/src/starter-corpus.js.map +0 -1
  204. package/dist/src/telemetry-types.d.ts +0 -87
  205. package/dist/src/telemetry-types.js.map +0 -1
  206. package/dist/src/tools.d.ts +0 -2933
  207. package/dist/src/tools.js.map +0 -1
  208. package/dist/src/toolspecs.d.ts +0 -43
  209. package/dist/src/toolspecs.js.map +0 -1
  210. package/dist/src/upgrade-nudge.d.ts +0 -15
  211. package/dist/src/upgrade-nudge.js.map +0 -1
  212. package/dist/src/utils.d.ts +0 -34
  213. package/dist/src/utils.js.map +0 -1
  214. package/dist/src/versuch.d.ts +0 -187
  215. package/dist/src/versuch.js.map +0 -1
  216. package/dist/src/vorspann.d.ts +0 -73
  217. package/dist/src/vorspann.js.map +0 -1
  218. package/dist/src/wartung/vektoren-verdichten.d.ts +0 -50
  219. package/dist/src/wartung/vektoren-verdichten.js.map +0 -1
  220. package/dist/src/werkzeug-nutzung.d.ts +0 -62
  221. package/dist/src/werkzeug-nutzung.js.map +0 -1
  222. package/dist/src/wertbeitrag.d.ts +0 -148
  223. package/dist/src/wertbeitrag.js.map +0 -1
@@ -1,201 +1,16 @@
1
- export const INSTANCE_TOOL_NAMES = new Set([
2
- 'list_instances', 'create_instance', 'get_instance', 'get_connection_string', 'delete_instance',
3
- 'list_orgs', 'create_org', 'invite_member', 'get_org_plan',
4
- ]);
5
- function formatInstance(inst) {
6
- const badge = inst.status === 'running' ? '๐ŸŸข' : inst.status === 'provisioning' ? '๐ŸŸก' : '๐Ÿ”ด';
7
- const mb = inst.memory_mb >= 1024 ? `${inst.memory_mb / 1024}GB` : `${inst.memory_mb}MB`;
8
- return `${badge} **${inst.name}** (\`${inst.id}\`) ยท ${inst.tier} ยท ${mb} ยท ${inst.region}`;
9
- }
10
- /**
11
- * Baut eine Adresse aus einem Instanz-Datensatz.
12
- *
13
- * โ”€โ”€ Warum diese Funktion NICHT mehr fuer get_connection_string benutzt wird โ”€โ”€
14
- *
15
- * Am 19.08.2026 gemessen: `get_connection_string` gab
16
- * `redis://49.13.38.27:30114` zurueck โ€” ohne Passwort. Der mitgelieferte
17
- * "Quick test" (`redis-cli -u ... PING`) scheiterte sofort an NOAUTH. Ein
18
- * Werkzeug, das eine Verbindungsadresse verspricht und eine liefert, die nicht
19
- * verbindet.
20
- *
21
- * Die Funktion war nicht falsch. Sie bekam nur nie ein Passwort: sie wurde mit
22
- * dem Datensatz aus /api/v1/instances/:id gefuettert, und der fuehrt kein
23
- * Passwort โ€” voellig richtig, das ist der allgemeine Instanz-Datensatz. Die
24
- * Zugangsdaten stehen unter /api/v1/instances/:id/connection, und dort baut der
25
- * Server die Adresse laengst fertig zusammen.
26
- *
27
- * Also gab es zwei Stellen, die wussten, wie eine Adresse aussieht โ€” und nur
28
- * eine hatte alles, was dazugehoert. Dieselbe Fehlerklasse wie beim Export am
29
- * selben Tag: eine Frage aus einer Quelle bedient, die fuer eine andere gebaut
30
- * wurde.
31
- *
32
- * Sie bleibt fuer die Anzeige in Listen, wo bewusst kein Passwort hingehoert.
33
- */
34
- function buildConnectionString(inst) {
35
- if (!inst.host)
36
- return 'โŒ Instance not ready yet.';
37
- const proto = inst.tls_enabled ? 'rediss' : 'redis';
38
- const auth = inst.password ? `:${inst.password}@` : '';
39
- return `${proto}://${auth}${inst.host}:${inst.port ?? 6379}`;
40
- }
41
- export async function handleInstanceTool(name, args, getConnection, apiFetch) {
42
- switch (name) {
43
- case 'list_instances': {
44
- const res = await apiFetch('/api/v1/instances');
45
- const instances = res.data ?? [];
46
- if (instances.length === 0)
47
- return 'You have no cache instances yet. Use `create_instance` to create one.';
48
- return [`Found ${instances.length} instance(s):\n`, ...instances.map(formatInstance)].join('\n');
49
- }
50
- case 'create_instance': {
51
- const { name: instName, tier } = args;
52
- const res = await apiFetch('/api/v1/instances', {
53
- method: 'POST',
54
- body: JSON.stringify({ name: instName, tier, created_via: 'api' }),
55
- });
56
- if (res.checkout_url) {
57
- return [
58
- `โœ… Instance **${instName}** (${tier}) created! ID: \`${res.instance_id}\``,
59
- ``,
60
- `๐Ÿ’ณ This is a paid tier. Complete payment to activate:`,
61
- ` ${res.checkout_url}`,
62
- ``,
63
- `After payment, provisioning starts automatically (~30 seconds).`,
64
- ].join('\n');
65
- }
66
- return [
67
- `โœ… Instance **${instName}** (${tier}) created and provisioning started!`,
68
- ` ID: \`${res.instance_id}\``,
69
- ` Status: ${res.status}`,
70
- ``,
71
- `Use \`get_instance\` or \`get_connection_string\` to get your connection details.`,
72
- ].join('\n');
73
- }
74
- case 'get_instance': {
75
- const inst = await apiFetch(`/api/v1/instances/${args.instance_id}`);
76
- return formatInstance(inst);
77
- }
78
- case 'get_connection_string': {
79
- const inst = await apiFetch(`/api/v1/instances/${args.instance_id}`);
80
- if (inst.status !== 'running') {
81
- return `Instance is not running yet (status: ${inst.status}). Provisioning takes ~30 seconds after payment.`;
82
- }
83
- // Die Adresse kommt vom Server, nicht von hier. Er hat als einziger das
84
- // Passwort (verschluesselt in der Datenbank, dort entschluesselt) und
85
- // baut die Zeichenkette bereits vollstaendig zusammen.
86
- let conn = {};
87
- let konnteNichtFragen = false;
88
- try {
89
- conn = await apiFetch(`/api/v1/instances/${args.instance_id}/connection`);
90
- }
91
- catch {
92
- // Aeltere oder eingeschraenkte Server. Dann bleibt nur der allgemeine
93
- // Datensatz โ€” der fuehrt kein Passwort. Das ist kein Grund
94
- // abzubrechen, aber ein Grund, es dazuzuschreiben.
95
- konnteNichtFragen = true;
96
- }
97
- const connStr = conn.connection_string || buildConnectionString(inst);
98
- // Eine Adresse ohne Passwort ist gegen ein passwortgeschuetztes Valkey
99
- // nutzlos โ€” sie scheitert mit NOAUTH, und zwar erst beim Nutzer. Deshalb
100
- // steht der Hinweis hier, ueber der Adresse, nicht in einer Fussnote.
101
- const ohnePasswort = !connStr.includes('@');
102
- const warnung = !ohnePasswort ? [] : konnteNichtFragen
103
- ? ['โš ๏ธ Could not read the credentials endpoint โ€” this string has NO password and will fail with NOAUTH if the instance requires one.', '']
104
- : conn.password
105
- ? ['โš ๏ธ The server returned a password but this string carries none โ€” please report this.', '']
106
- : [];
107
- return [
108
- ...warnung,
109
- `**Connection string for ${inst.name}:**`,
110
- `\`\`\``,
111
- connStr,
112
- `\`\`\``,
113
- ``,
114
- `**Environment variable:**`,
115
- `\`\`\`bash`,
116
- `REDIS_URL="${connStr}"`,
117
- `CACHLY_URL="${connStr}"`,
118
- `\`\`\``,
119
- ``,
120
- `**Quick test:**`,
121
- `\`\`\`bash`,
122
- `redis-cli -u "${connStr}" PING`,
123
- `\`\`\``,
124
- ].join('\n');
125
- }
126
- case 'delete_instance': {
127
- const { instance_id, confirm } = args;
128
- if (!confirm)
129
- return 'Deletion cancelled. Set `confirm: true` to proceed.';
130
- // Clean up cached connection (best-effort; connection times out otherwise)
131
- try {
132
- getConnection._pool?.delete?.(instance_id);
133
- }
134
- catch { /* ignore */ }
135
- await apiFetch(`/api/v1/instances/${instance_id}`, { method: 'DELETE' });
136
- return `โœ… Instance \`${instance_id}\` has been deleted and all data removed.`;
137
- }
138
- // โ”€โ”€ Org / Team management โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
139
- case 'list_orgs': {
140
- const res = await apiFetch('/api/v1/orgs');
141
- const orgs = res.orgs ?? [];
142
- if (orgs.length === 0)
143
- return `๐Ÿ“ญ No organizations yet.\n\nCreate one with \`create_org(name="My Team")\`.\nOrg plans: Team โ‚ฌ99/mo (10 seats), Business โ‚ฌ299/mo (50 seats), Enterprise custom.`;
144
- return [
145
- `๐Ÿข **Your organizations (${orgs.length})**\n`,
146
- ...orgs.map(o => `โ€ข **${o.name}** (\`${o.slug}\`) โ€” plan: ${o.plan} ยท seats: ${o.member_count ?? '?'}/${o.max_members}\n ID: \`${o.id}\``),
147
- `\n_Manage: \`get_org_plan\`, \`invite_member\`, dashboard โ†’ /team_`,
148
- ].join('\n');
149
- }
150
- case 'create_org': {
151
- const { name: orgName, slug } = args;
152
- const body = { name: orgName };
153
- if (slug)
154
- body.slug = slug;
155
- const res = await apiFetch('/api/v1/orgs', {
156
- method: 'POST',
157
- body: JSON.stringify(body),
158
- });
159
- return [
160
- `โœ… **Organization created:** ${res.name}`,
161
- ` ID: \`${res.id}\` ยท Slug: \`${res.slug}\` ยท Plan: ${res.plan}`,
162
- ``,
163
- `**Next steps:**`,
164
- `1. Invite team members: \`invite_member(org_id="${res.id}", email="dev@example.com")\``,
165
- `2. Upgrade plan: open billing portal via dashboard โ†’ /team`,
166
- ` Team: โ‚ฌ99/mo (10 seats) ยท Business: โ‚ฌ299/mo (50 seats)`,
167
- ].join('\n');
168
- }
169
- case 'invite_member': {
170
- const { org_id, email, role = 'member' } = args;
171
- await apiFetch(`/api/v1/orgs/${org_id}/members`, {
172
- method: 'POST',
173
- body: JSON.stringify({ email, role }),
174
- });
175
- return `โœ… Invite sent to **${email}** as \`${role}\` in org \`${org_id}\`.\n\nThey will receive an email to join the organization.`;
176
- }
177
- case 'get_org_plan': {
178
- const { org_id } = args;
179
- const org = await apiFetch(`/api/v1/orgs/${org_id}`);
180
- const accepted = (org.members ?? []).filter(m => m.accepted_at).length;
181
- const pending = (org.members ?? []).filter(m => !m.accepted_at).length;
182
- const planPrice = { free: 'โ‚ฌ0', team: 'โ‚ฌ99/mo', business: 'โ‚ฌ299/mo', enterprise: 'custom' };
183
- return [
184
- `๐Ÿข **${org.name}** โ€” Plan: **${org.plan}** (${planPrice[org.plan] ?? org.plan})`,
185
- ` Seats: ${accepted} active + ${pending} pending / ${org.max_members} max`,
186
- ``,
187
- `**Members:**`,
188
- ...(org.members ?? []).map(m => ` โ€ข ${m.invite_email} (${m.role})${m.accepted_at ? '' : ' โ€” pending'}`),
189
- ``,
190
- org.stripe_customer_id
191
- ? `๐Ÿ’ณ Billing: managed via Stripe. Upgrade/cancel: dashboard โ†’ /billing`
192
- : `๐Ÿ’ณ No payment method yet. Upgrade: dashboard โ†’ /billing โ†’ Team Plans`,
193
- ].join('\n');
194
- }
195
- // โ”€โ”€ Live cache operations โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
196
- default:
197
- return null;
198
- }
199
- }
200
- export { formatInstance, buildConnectionString };
201
- //# sourceMappingURL=instances.js.map
1
+ const g=new Set(["list_instances","create_instance","get_instance","get_connection_string","delete_instance","list_orgs","create_org","invite_member","get_org_plan"]);function m(a){const i=a.status==="running"?"\u{1F7E2}":a.status==="provisioning"?"\u{1F7E1}":"\u{1F534}",c=a.memory_mb>=1024?`${a.memory_mb/1024}GB`:`${a.memory_mb}MB`;return`${i} **${a.name}** (\`${a.id}\`) \xB7 ${a.tier} \xB7 ${c} \xB7 ${a.region}`}function d(a){if(!a.host)return"\u274C Instance not ready yet.";const i=a.tls_enabled?"rediss":"redis",c=a.password?`:${a.password}@`:"";return`${i}://${c}${a.host}:${a.port??6379}`}async function u(a,i,c,r){switch(a){case"list_instances":{const e=(await r("/api/v1/instances")).data??[];return e.length===0?"You have no cache instances yet. Use `create_instance` to create one.":[`Found ${e.length} instance(s):
2
+ `,...e.map(m)].join(`
3
+ `)}case"create_instance":{const{name:n,tier:e}=i,t=await r("/api/v1/instances",{method:"POST",body:JSON.stringify({name:n,tier:e,created_via:"api"})});return t.checkout_url?[`\u2705 Instance **${n}** (${e}) created! ID: \`${t.instance_id}\``,"","\u{1F4B3} This is a paid tier. Complete payment to activate:",` ${t.checkout_url}`,"","After payment, provisioning starts automatically (~30 seconds)."].join(`
4
+ `):[`\u2705 Instance **${n}** (${e}) created and provisioning started!`,` ID: \`${t.instance_id}\``,` Status: ${t.status}`,"","Use `get_instance` or `get_connection_string` to get your connection details."].join(`
5
+ `)}case"get_instance":{const n=await r(`/api/v1/instances/${i.instance_id}`);return m(n)}case"get_connection_string":{const n=await r(`/api/v1/instances/${i.instance_id}`);if(n.status!=="running")return`Instance is not running yet (status: ${n.status}). Provisioning takes ~30 seconds after payment.`;let e={},t=!1;try{e=await r(`/api/v1/instances/${i.instance_id}/connection`)}catch{t=!0}const s=e.connection_string||d(n);return[...!s.includes("@")?t?["\u26A0\uFE0F Could not read the credentials endpoint \u2014 this string has NO password and will fail with NOAUTH if the instance requires one.",""]:e.password?["\u26A0\uFE0F The server returned a password but this string carries none \u2014 please report this.",""]:[]:[],`**Connection string for ${n.name}:**`,"```",s,"```","","**Environment variable:**","```bash",`REDIS_URL="${s}"`,`CACHLY_URL="${s}"`,"```","","**Quick test:**","```bash",`redis-cli -u "${s}" PING`,"```"].join(`
6
+ `)}case"delete_instance":{const{instance_id:n,confirm:e}=i;if(!e)return"Deletion cancelled. Set `confirm: true` to proceed.";try{c._pool?.delete?.(n)}catch{}return await r(`/api/v1/instances/${n}`,{method:"DELETE"}),`\u2705 Instance \`${n}\` has been deleted and all data removed.`}case"list_orgs":{const e=(await r("/api/v1/orgs")).orgs??[];return e.length===0?`\u{1F4ED} No organizations yet.
7
+
8
+ Create one with \`create_org(name="My Team")\`.
9
+ Org plans: Team \u20AC99/mo (10 seats), Business \u20AC299/mo (50 seats), Enterprise custom.`:[`\u{1F3E2} **Your organizations (${e.length})**
10
+ `,...e.map(t=>`\u2022 **${t.name}** (\`${t.slug}\`) \u2014 plan: ${t.plan} \xB7 seats: ${t.member_count??"?"}/${t.max_members}
11
+ ID: \`${t.id}\``),"\n_Manage: `get_org_plan`, `invite_member`, dashboard \u2192 /team_"].join(`
12
+ `)}case"create_org":{const{name:n,slug:e}=i,t={name:n};e&&(t.slug=e);const s=await r("/api/v1/orgs",{method:"POST",body:JSON.stringify(t)});return[`\u2705 **Organization created:** ${s.name}`,` ID: \`${s.id}\` \xB7 Slug: \`${s.slug}\` \xB7 Plan: ${s.plan}`,"","**Next steps:**",`1. Invite team members: \`invite_member(org_id="${s.id}", email="dev@example.com")\``,"2. Upgrade plan: open billing portal via dashboard \u2192 /team"," Team: \u20AC99/mo (10 seats) \xB7 Business: \u20AC299/mo (50 seats)"].join(`
13
+ `)}case"invite_member":{const{org_id:n,email:e,role:t="member"}=i;return await r(`/api/v1/orgs/${n}/members`,{method:"POST",body:JSON.stringify({email:e,role:t})}),`\u2705 Invite sent to **${e}** as \`${t}\` in org \`${n}\`.
14
+
15
+ They will receive an email to join the organization.`}case"get_org_plan":{const{org_id:n}=i,e=await r(`/api/v1/orgs/${n}`),t=(e.members??[]).filter(o=>o.accepted_at).length,s=(e.members??[]).filter(o=>!o.accepted_at).length,l={free:"\u20AC0",team:"\u20AC99/mo",business:"\u20AC299/mo",enterprise:"custom"};return[`\u{1F3E2} **${e.name}** \u2014 Plan: **${e.plan}** (${l[e.plan]??e.plan})`,` Seats: ${t} active + ${s} pending / ${e.max_members} max`,"","**Members:**",...(e.members??[]).map(o=>` \u2022 ${o.invite_email} (${o.role})${o.accepted_at?"":" \u2014 pending"}`),"",e.stripe_customer_id?"\u{1F4B3} Billing: managed via Stripe. Upgrade/cancel: dashboard \u2192 /billing":"\u{1F4B3} No payment method yet. Upgrade: dashboard \u2192 /billing \u2192 Team Plans"].join(`
16
+ `)}default:return null}}export{g as INSTANCE_TOOL_NAMES,d as buildConnectionString,m as formatInstance,u as handleInstanceTool};
@@ -1,175 +1,13 @@
1
- import { safeJsonParse } from '../utils.js';
2
- export const ROADMAP_TOOL_NAMES = new Set([
3
- 'roadmap_add', 'roadmap_update', 'roadmap_list', 'roadmap_next',
4
- ]);
5
- export async function handleRoadmapTool(name, args, getConnection, _apiFetch) {
6
- switch (name) {
7
- case 'roadmap_add': {
8
- const { instance_id: rid, title, description: desc = '', priority = 'medium', tags: rtags = [], milestone = '', } = args;
9
- const redis = await getConnection(rid);
10
- const id = `rm_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 6)}`;
11
- const item = {
12
- id, title, description: desc, priority, tags: rtags, milestone,
13
- status: 'planned',
14
- created: new Date().toISOString(),
15
- updated: new Date().toISOString(),
16
- notes: '',
17
- };
18
- await redis.hset(`cachly:roadmap:${rid}`, id, JSON.stringify(item));
19
- const PRIORITY_ICON = { critical: '๐Ÿ”ด', high: '๐ŸŸ ', medium: '๐ŸŸก', low: '๐Ÿ”ต' };
20
- return [
21
- `๐Ÿ“‹ **Roadmap item added**`,
22
- ``,
23
- ` ID: \`${id}\``,
24
- ` Title: ${title}`,
25
- ` Priority: ${PRIORITY_ICON[priority] ?? 'โšช'} ${priority}`,
26
- ` Status: planned`,
27
- milestone ? ` Milestone: ${milestone}` : '',
28
- rtags.length ? ` Tags: ${rtags.join(', ')}` : '',
29
- ``,
30
- `๐Ÿ’ก Use \`roadmap_update(id: "${id}", status: "in-progress")\` when you start working on it.`,
31
- ].filter(Boolean).join('\n');
32
- }
33
- case 'roadmap_update': {
34
- const { instance_id: rid, id: itemId, status: newStatus, priority: newPriority, notes: newNotes, title: newTitle, description: newDesc, } = args;
35
- const redis = await getConnection(rid);
36
- const raw = await redis.hget(`cachly:roadmap:${rid}`, itemId);
37
- if (!raw)
38
- return `โš ๏ธ **roadmap_update** โ€“ Item \`${itemId}\` not found. Use \`roadmap_list\` to see all items.`;
39
- const item = safeJsonParse(raw, null);
40
- if (!item)
41
- return `โš ๏ธ **roadmap_update** โ€“ Item \`${itemId}\` data is corrupted. Re-add with \`roadmap_add\`.`;
42
- const oldStatus = item.status;
43
- if (newStatus)
44
- item.status = newStatus;
45
- if (newPriority)
46
- item.priority = newPriority;
47
- if (newTitle)
48
- item.title = newTitle;
49
- if (newDesc)
50
- item.description = newDesc;
51
- if (newNotes)
52
- item.notes = item.notes ? `${item.notes}\n[${new Date().toISOString().slice(0, 10)}] ${newNotes}` : `[${new Date().toISOString().slice(0, 10)}] ${newNotes}`;
53
- item.updated = new Date().toISOString();
54
- await redis.hset(`cachly:roadmap:${rid}`, itemId, JSON.stringify(item));
55
- const statusEmoji = { planned: '๐Ÿ“‹', 'in-progress': 'โšก', done: 'โœ…', blocked: '๐Ÿšซ', cancelled: '๐Ÿ—‘๏ธ' };
56
- return [
57
- `${statusEmoji[newStatus ?? oldStatus] ?? '๐Ÿ“‹'} **Roadmap updated** \`${itemId}\``,
58
- ``,
59
- ` Title: ${item.title}`,
60
- oldStatus !== newStatus ? ` Status: ${oldStatus} โ†’ ${newStatus}` : ` Status: ${item.status}`,
61
- newNotes ? ` Notes: ${newNotes}` : '',
62
- ].filter(Boolean).join('\n');
63
- }
64
- case 'roadmap_list': {
65
- const { instance_id: rid, status: filterStatus = 'open', tag: filterTag, milestone: filterMilestone, priority: filterPriority, } = args;
66
- const redis = await getConnection(rid);
67
- const all = await redis.hgetall(`cachly:roadmap:${rid}`);
68
- if (!all || Object.keys(all).length === 0) {
69
- return '๐Ÿ“‹ **Roadmap is empty.**\n\nUse `roadmap_add` to create your first item.';
70
- }
71
- const PRIORITY_ORDER = { critical: 0, high: 1, medium: 2, low: 3 };
72
- const PRIORITY_ICON = { critical: '๐Ÿ”ด', high: '๐ŸŸ ', medium: '๐ŸŸก', low: '๐Ÿ”ต' };
73
- const STATUS_ICON = { planned: '๐Ÿ“‹', 'in-progress': 'โšก', done: 'โœ…', blocked: '๐Ÿšซ', cancelled: '๐Ÿ—‘๏ธ' };
74
- const openStatuses = new Set(['planned', 'in-progress', 'blocked']);
75
- let items = Object.values(all).flatMap(v => {
76
- const item = safeJsonParse(v, null);
77
- return item ? [item] : [];
78
- });
79
- // Filter
80
- if (filterStatus === 'open')
81
- items = items.filter(i => openStatuses.has(i.status));
82
- else if (filterStatus)
83
- items = items.filter(i => i.status === filterStatus);
84
- if (filterTag)
85
- items = items.filter(i => i.tags.includes(filterTag));
86
- if (filterMilestone)
87
- items = items.filter(i => i.milestone === filterMilestone);
88
- if (filterPriority)
89
- items = items.filter(i => (PRIORITY_ORDER[i.priority] ?? 99) <= (PRIORITY_ORDER[filterPriority] ?? 99));
90
- // Sort: priority asc, then created asc
91
- items.sort((a, b) => {
92
- const pa = PRIORITY_ORDER[a.priority] ?? 99;
93
- const pb = PRIORITY_ORDER[b.priority] ?? 99;
94
- return pa !== pb ? pa - pb : a.created.localeCompare(b.created);
95
- });
96
- if (items.length === 0)
97
- return `๐Ÿ“‹ **No roadmap items** match the current filter (status: ${filterStatus}).`;
98
- const grouped = {};
99
- for (const it of items) {
100
- const st = it.status;
101
- if (!grouped[st])
102
- grouped[st] = [];
103
- grouped[st].push(it);
104
- }
105
- const lines = [`๐Ÿ“‹ **Roadmap** (${items.length} item${items.length !== 1 ? 's' : ''})`, ''];
106
- for (const [st, grp] of Object.entries(grouped)) {
107
- lines.push(`**${STATUS_ICON[st] ?? 'โ€ข'} ${st.toUpperCase()}** (${grp.length})`);
108
- for (const it of grp) {
109
- const tags = it.tags.length ? ` [${it.tags.join(', ')}]` : '';
110
- const milestone = it.milestone ? ` ยท ${it.milestone}` : '';
111
- lines.push(` ${PRIORITY_ICON[it.priority] ?? 'โšช'} \`${it.id}\` **${it.title}**${tags}${milestone}`);
112
- if (it.description)
113
- lines.push(` ${it.description.slice(0, 120)}`);
114
- if (it.notes)
115
- lines.push(` ๐Ÿ“ ${it.notes.split('\n').pop()?.slice(0, 100)}`);
116
- }
117
- lines.push('');
118
- }
119
- lines.push(`๐Ÿ’ก \`roadmap_update(id, status: "in-progress")\` to start ยท \`roadmap_next\` for top priority item`);
120
- return lines.join('\n');
121
- }
122
- case 'roadmap_next': {
123
- const { instance_id: rid, tag: filterTag } = args;
124
- const redis = await getConnection(rid);
125
- const all = await redis.hgetall(`cachly:roadmap:${rid}`);
126
- if (!all || Object.keys(all).length === 0) {
127
- return '๐Ÿ“‹ **Roadmap is empty.** Use `roadmap_add` to plan your first task.';
128
- }
129
- const PRIORITY_ORDER = { critical: 0, high: 1, medium: 2, low: 3 };
130
- const PRIORITY_ICON = { critical: '๐Ÿ”ด', high: '๐ŸŸ ', medium: '๐ŸŸก', low: '๐Ÿ”ต' };
131
- const items = Object.values(all)
132
- .flatMap(v => {
133
- const item = safeJsonParse(v, null);
134
- return item ? [item] : [];
135
- })
136
- .filter(i => i.status === 'in-progress' || i.status === 'planned')
137
- .filter(i => !filterTag || (Array.isArray(i.tags) ? i.tags : []).includes(filterTag));
138
- if (items.length === 0)
139
- return '๐ŸŽ‰ **No open roadmap items!** All tasks are done (or use `roadmap_list` to check).';
140
- // in-progress first, then by priority
141
- items.sort((a, b) => {
142
- if (a.status === 'in-progress' && b.status !== 'in-progress')
143
- return -1;
144
- if (b.status === 'in-progress' && a.status !== 'in-progress')
145
- return 1;
146
- return (PRIORITY_ORDER[a.priority] ?? 99) - (PRIORITY_ORDER[b.priority] ?? 99);
147
- });
148
- const next = items[0];
149
- const remaining = items.length - 1;
150
- const nextTags = Array.isArray(next.tags) ? next.tags : [];
151
- const tags = nextTags.length ? `\nTags: ${nextTags.join(', ')}` : '';
152
- const milestone = next.milestone ? `\nMilestone: ${next.milestone}` : '';
153
- const notes = next.notes ? `\nNotes: ${next.notes.split('\n').pop()?.slice(0, 120)}` : '';
154
- return [
155
- `${next.status === 'in-progress' ? 'โšก' : '๐Ÿ“‹'} **Next up: ${next.title}**`,
156
- ``,
157
- `ID: \`${next.id}\``,
158
- `Priority: ${PRIORITY_ICON[next.priority] ?? 'โšช'} ${next.priority}`,
159
- `Status: ${next.status}`,
160
- next.description ? `\nWhat to do:\n${next.description}` : '',
161
- tags, milestone, notes,
162
- ``,
163
- remaining > 0 ? `(+${remaining} more open item${remaining !== 1 ? 's' : ''} in roadmap)` : '(last open item)',
164
- ``,
165
- next.status === 'planned'
166
- ? `๐Ÿ’ก Start with: \`roadmap_update(id: "${next.id}", status: "in-progress")\``
167
- : `๐Ÿ’ก Finish with: \`roadmap_update(id: "${next.id}", status: "done", notes: "...")\``,
168
- ].filter(s => s !== undefined).join('\n');
169
- }
170
- // โ”€โ”€ v0.6 Cognitive Cache: memory_consolidate โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
171
- default:
172
- return null;
173
- }
174
- }
175
- //# sourceMappingURL=roadmap.js.map
1
+ import{safeJsonParse as w}from"../utils.js";const T=new Set(["roadmap_add","roadmap_update","roadmap_list","roadmap_next"]);async function j(S,h,y,I){switch(S){case"roadmap_add":{const{instance_id:p,title:o,description:u="",priority:d="medium",tags:n=[],milestone:g=""}=h,l=await y(p),t=`rm_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,6)}`,m={id:t,title:o,description:u,priority:d,tags:n,milestone:g,status:"planned",created:new Date().toISOString(),updated:new Date().toISOString(),notes:""};await l.hset(`cachly:roadmap:${p}`,t,JSON.stringify(m));const i={critical:"\u{1F534}",high:"\u{1F7E0}",medium:"\u{1F7E1}",low:"\u{1F535}"};return["\u{1F4CB} **Roadmap item added**","",` ID: \`${t}\``,` Title: ${o}`,` Priority: ${i[d]??"\u26AA"} ${d}`," Status: planned",g?` Milestone: ${g}`:"",n.length?` Tags: ${n.join(", ")}`:"","",`\u{1F4A1} Use \`roadmap_update(id: "${t}", status: "in-progress")\` when you start working on it.`].filter(Boolean).join(`
2
+ `)}case"roadmap_update":{const{instance_id:p,id:o,status:u,priority:d,notes:n,title:g,description:l}=h,t=await y(p),m=await t.hget(`cachly:roadmap:${p}`,o);if(!m)return`\u26A0\uFE0F **roadmap_update** \u2013 Item \`${o}\` not found. Use \`roadmap_list\` to see all items.`;const i=w(m,null);if(!i)return`\u26A0\uFE0F **roadmap_update** \u2013 Item \`${o}\` data is corrupted. Re-add with \`roadmap_add\`.`;const $=i.status;return u&&(i.status=u),d&&(i.priority=d),g&&(i.title=g),l&&(i.description=l),n&&(i.notes=i.notes?`${i.notes}
3
+ [${new Date().toISOString().slice(0,10)}] ${n}`:`[${new Date().toISOString().slice(0,10)}] ${n}`),i.updated=new Date().toISOString(),await t.hset(`cachly:roadmap:${p}`,o,JSON.stringify(i)),[`${{planned:"\u{1F4CB}","in-progress":"\u26A1",done:"\u2705",blocked:"\u{1F6AB}",cancelled:"\u{1F5D1}\uFE0F"}[u??$]??"\u{1F4CB}"} **Roadmap updated** \`${o}\``,"",` Title: ${i.title}`,$!==u?` Status: ${$} \u2192 ${u}`:` Status: ${i.status}`,n?` Notes: ${n}`:""].filter(Boolean).join(`
4
+ `)}case"roadmap_list":{const{instance_id:p,status:o="open",tag:u,milestone:d,priority:n}=h,l=await(await y(p)).hgetall(`cachly:roadmap:${p}`);if(!l||Object.keys(l).length===0)return"\u{1F4CB} **Roadmap is empty.**\n\nUse `roadmap_add` to create your first item.";const t={critical:0,high:1,medium:2,low:3},m={critical:"\u{1F534}",high:"\u{1F7E0}",medium:"\u{1F7E1}",low:"\u{1F535}"},i={planned:"\u{1F4CB}","in-progress":"\u26A1",done:"\u2705",blocked:"\u{1F6AB}",cancelled:"\u{1F5D1}\uFE0F"},$=new Set(["planned","in-progress","blocked"]);let a=Object.values(l).flatMap(e=>{const c=w(e,null);return c?[c]:[]});if(o==="open"?a=a.filter(e=>$.has(e.status)):o&&(a=a.filter(e=>e.status===o)),u&&(a=a.filter(e=>e.tags.includes(u))),d&&(a=a.filter(e=>e.milestone===d)),n&&(a=a.filter(e=>(t[e.priority]??99)<=(t[n]??99))),a.sort((e,c)=>{const r=t[e.priority]??99,_=t[c.priority]??99;return r!==_?r-_:e.created.localeCompare(c.created)}),a.length===0)return`\u{1F4CB} **No roadmap items** match the current filter (status: ${o}).`;const f={};for(const e of a){const c=e.status;f[c]||(f[c]=[]),f[c].push(e)}const s=[`\u{1F4CB} **Roadmap** (${a.length} item${a.length!==1?"s":""})`,""];for(const[e,c]of Object.entries(f)){s.push(`**${i[e]??"\u2022"} ${e.toUpperCase()}** (${c.length})`);for(const r of c){const _=r.tags.length?` [${r.tags.join(", ")}]`:"",O=r.milestone?` \xB7 ${r.milestone}`:"";s.push(` ${m[r.priority]??"\u26AA"} \`${r.id}\` **${r.title}**${_}${O}`),r.description&&s.push(` ${r.description.slice(0,120)}`),r.notes&&s.push(` \u{1F4DD} ${r.notes.split(`
5
+ `).pop()?.slice(0,100)}`)}s.push("")}return s.push('\u{1F4A1} `roadmap_update(id, status: "in-progress")` to start \xB7 `roadmap_next` for top priority item'),s.join(`
6
+ `)}case"roadmap_next":{const{instance_id:p,tag:o}=h,d=await(await y(p)).hgetall(`cachly:roadmap:${p}`);if(!d||Object.keys(d).length===0)return"\u{1F4CB} **Roadmap is empty.** Use `roadmap_add` to plan your first task.";const n={critical:0,high:1,medium:2,low:3},g={critical:"\u{1F534}",high:"\u{1F7E0}",medium:"\u{1F7E1}",low:"\u{1F535}"},l=Object.values(d).flatMap(s=>{const e=w(s,null);return e?[e]:[]}).filter(s=>s.status==="in-progress"||s.status==="planned").filter(s=>!o||(Array.isArray(s.tags)?s.tags:[]).includes(o));if(l.length===0)return"\u{1F389} **No open roadmap items!** All tasks are done (or use `roadmap_list` to check).";l.sort((s,e)=>s.status==="in-progress"&&e.status!=="in-progress"?-1:e.status==="in-progress"&&s.status!=="in-progress"?1:(n[s.priority]??99)-(n[e.priority]??99));const t=l[0],m=l.length-1,i=Array.isArray(t.tags)?t.tags:[],$=i.length?`
7
+ Tags: ${i.join(", ")}`:"",a=t.milestone?`
8
+ Milestone: ${t.milestone}`:"",f=t.notes?`
9
+ Notes: ${t.notes.split(`
10
+ `).pop()?.slice(0,120)}`:"";return[`${t.status==="in-progress"?"\u26A1":"\u{1F4CB}"} **Next up: ${t.title}**`,"",`ID: \`${t.id}\``,`Priority: ${g[t.priority]??"\u26AA"} ${t.priority}`,`Status: ${t.status}`,t.description?`
11
+ What to do:
12
+ ${t.description}`:"",$,a,f,"",m>0?`(+${m} more open item${m!==1?"s":""} in roadmap)`:"(last open item)","",t.status==="planned"?`\u{1F4A1} Start with: \`roadmap_update(id: "${t.id}", status: "in-progress")\``:`\u{1F4A1} Finish with: \`roadmap_update(id: "${t.id}", status: "done", notes: "...")\``].filter(s=>s!==void 0).join(`
13
+ `)}default:return null}}export{T as ROADMAP_TOOL_NAMES,j as handleRoadmapTool};