@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.
- package/README.md +2 -2
- package/dist/index.js +1 -7
- package/dist/packages/telegram-notify/client.js +2 -75
- package/dist/src/ambient-cli.js +7 -253
- package/dist/src/ambient-deps.js +1 -55
- package/dist/src/ambient-hooks.js +5 -278
- package/dist/src/ambient-ledger.js +6 -95
- package/dist/src/ambient-memory.js +1 -67
- package/dist/src/ambient-recall.js +1 -221
- package/dist/src/aussetzer.js +1 -225
- package/dist/src/auth.js +9 -140
- package/dist/src/autor-abzeichen.js +1 -56
- package/dist/src/autor.js +1 -136
- package/dist/src/bauabdruck.js +1 -93
- package/dist/src/bedeutung.js +2 -323
- package/dist/src/bench/cachly-bench.js +4 -249
- package/dist/src/bench/external-corpus.js +4 -135
- package/dist/src/bench/fixtures.js +1 -225
- package/dist/src/brain-export.js +16 -119
- package/dist/src/brain-watch-hook.js +8 -86
- package/dist/src/cachly-url.js +1 -21
- package/dist/src/ckg.js +1 -108
- package/dist/src/cls-hook.js +8 -94
- package/dist/src/confidence.js +1 -50
- package/dist/src/credentials.js +1 -85
- package/dist/src/deutsch.js +1 -223
- package/dist/src/doctor.js +2 -248
- package/dist/src/editor.js +1 -63
- package/dist/src/eingaenge-nachruesten.js +1 -290
- package/dist/src/eingaenge.js +2 -260
- package/dist/src/embeddings.js +13 -223
- package/dist/src/feldreparatur.js +3 -113
- package/dist/src/first-contact.js +4 -108
- package/dist/src/first-recall-proof.js +4 -41
- package/dist/src/funnel-milestones.js +2 -48
- package/dist/src/geliefert.js +1 -114
- package/dist/src/handlers/advanced.js +38 -537
- package/dist/src/handlers/brain.js +69 -4397
- package/dist/src/handlers/cache.js +59 -638
- package/dist/src/handlers/context.js +17 -182
- package/dist/src/handlers/fedbrain.js +40 -1436
- package/dist/src/handlers/instances.js +16 -201
- package/dist/src/handlers/roadmap.js +13 -175
- package/dist/src/handlers/share.js +19 -530
- package/dist/src/handlers/syndicate.js +38 -904
- package/dist/src/handlers/team.js +89 -1865
- package/dist/src/handlers/viz.js +3 -148
- package/dist/src/index.js +321 -4281
- package/dist/src/interferenz.js +1 -141
- package/dist/src/kostprobe.js +7 -125
- package/dist/src/lesson-preview.js +2 -133
- package/dist/src/namespace.js +1 -128
- package/dist/src/notifier.js +1 -6
- package/dist/src/rangfolge-stellschrauben.js +1 -0
- package/dist/src/rangfolge.js +1 -249
- package/dist/src/raumkorrektur.js +1 -197
- package/dist/src/recall-tiefe.js +1 -42
- package/dist/src/rerank.js +1 -154
- package/dist/src/resonanz.js +1 -140
- package/dist/src/search.js +1 -2104
- package/dist/src/seltenheitsbestand.js +1 -92
- package/dist/src/speicherlage.js +1 -84
- package/dist/src/spuren.js +1 -150
- package/dist/src/starter-corpus.js +1 -165
- package/dist/src/telemetry-types.js +0 -13
- package/dist/src/tools.js +10 -2465
- package/dist/src/toolspecs.js +1 -121
- package/dist/src/upgrade-nudge.js +1 -29
- package/dist/src/utils.js +1 -89
- package/dist/src/versuch.js +1 -264
- package/dist/src/vorspann.js +1 -146
- package/dist/src/wartung/vektoren-verdichten.js +1 -200
- package/dist/src/werkzeug-nutzung.js +1 -72
- package/dist/src/wertbeitrag.js +1 -203
- package/dist/src/wirkungsspur.js +1 -0
- package/glama.json +1 -1
- package/package.json +8 -7
- package/server.json +3 -3
- package/dist/index.d.ts +0 -1
- package/dist/index.js.map +0 -1
- package/dist/packages/telegram-notify/client.d.ts +0 -19
- package/dist/packages/telegram-notify/client.js.map +0 -1
- package/dist/src/ambient-cli.d.ts +0 -101
- package/dist/src/ambient-cli.js.map +0 -1
- package/dist/src/ambient-deps.d.ts +0 -26
- package/dist/src/ambient-deps.js.map +0 -1
- package/dist/src/ambient-hooks.d.ts +0 -137
- package/dist/src/ambient-hooks.js.map +0 -1
- package/dist/src/ambient-ledger.d.ts +0 -19
- package/dist/src/ambient-ledger.js.map +0 -1
- package/dist/src/ambient-memory.d.ts +0 -12
- package/dist/src/ambient-memory.js.map +0 -1
- package/dist/src/ambient-recall.d.ts +0 -127
- package/dist/src/ambient-recall.js.map +0 -1
- package/dist/src/aussetzer.d.ts +0 -156
- package/dist/src/aussetzer.js.map +0 -1
- package/dist/src/auth.d.ts +0 -43
- package/dist/src/auth.js.map +0 -1
- package/dist/src/autor-abzeichen.d.ts +0 -41
- package/dist/src/autor-abzeichen.js.map +0 -1
- package/dist/src/autor.d.ts +0 -101
- package/dist/src/autor.js.map +0 -1
- package/dist/src/bauabdruck-daten.generiert.json +0 -5
- package/dist/src/bauabdruck.d.ts +0 -38
- package/dist/src/bauabdruck.js.map +0 -1
- package/dist/src/bedeutung.d.ts +0 -168
- package/dist/src/bedeutung.js.map +0 -1
- package/dist/src/bench/cachly-bench.d.ts +0 -61
- package/dist/src/bench/cachly-bench.js.map +0 -1
- package/dist/src/bench/external-corpus.d.ts +0 -44
- package/dist/src/bench/external-corpus.js.map +0 -1
- package/dist/src/bench/fixtures.d.ts +0 -37
- package/dist/src/bench/fixtures.js.map +0 -1
- package/dist/src/brain-export.d.ts +0 -64
- package/dist/src/brain-export.js.map +0 -1
- package/dist/src/brain-watch-hook.d.ts +0 -21
- package/dist/src/brain-watch-hook.js.map +0 -1
- package/dist/src/cachly-url.d.ts +0 -68
- package/dist/src/cachly-url.js.map +0 -1
- package/dist/src/ckg.d.ts +0 -54
- package/dist/src/ckg.js.map +0 -1
- package/dist/src/cls-hook.d.ts +0 -15
- package/dist/src/cls-hook.js.map +0 -1
- package/dist/src/confidence.d.ts +0 -19
- package/dist/src/confidence.js.map +0 -1
- package/dist/src/credentials.d.ts +0 -37
- package/dist/src/credentials.js.map +0 -1
- package/dist/src/deutsch.d.ts +0 -98
- package/dist/src/deutsch.js.map +0 -1
- package/dist/src/doctor.d.ts +0 -47
- package/dist/src/doctor.js.map +0 -1
- package/dist/src/editor.d.ts +0 -9
- package/dist/src/editor.js.map +0 -1
- package/dist/src/eingaenge-nachruesten.d.ts +0 -41
- package/dist/src/eingaenge-nachruesten.js.map +0 -1
- package/dist/src/eingaenge.d.ts +0 -159
- package/dist/src/eingaenge.js.map +0 -1
- package/dist/src/embeddings.d.ts +0 -48
- package/dist/src/embeddings.js.map +0 -1
- package/dist/src/feldreparatur.d.ts +0 -58
- package/dist/src/feldreparatur.js.map +0 -1
- package/dist/src/first-contact.d.ts +0 -56
- package/dist/src/first-contact.js.map +0 -1
- package/dist/src/first-recall-proof.d.ts +0 -19
- package/dist/src/first-recall-proof.js.map +0 -1
- package/dist/src/funnel-milestones.d.ts +0 -5
- package/dist/src/funnel-milestones.js.map +0 -1
- package/dist/src/geliefert.d.ts +0 -63
- package/dist/src/geliefert.js.map +0 -1
- package/dist/src/handlers/advanced.d.ts +0 -6
- package/dist/src/handlers/advanced.js.map +0 -1
- package/dist/src/handlers/brain.d.ts +0 -41
- package/dist/src/handlers/brain.js.map +0 -1
- package/dist/src/handlers/cache.d.ts +0 -6
- package/dist/src/handlers/cache.js.map +0 -1
- package/dist/src/handlers/context.d.ts +0 -6
- package/dist/src/handlers/context.js.map +0 -1
- package/dist/src/handlers/fedbrain.d.ts +0 -18
- package/dist/src/handlers/fedbrain.js.map +0 -1
- package/dist/src/handlers/instances.d.ts +0 -33
- package/dist/src/handlers/instances.js.map +0 -1
- package/dist/src/handlers/roadmap.d.ts +0 -6
- package/dist/src/handlers/roadmap.js.map +0 -1
- package/dist/src/handlers/share.d.ts +0 -8
- package/dist/src/handlers/share.js.map +0 -1
- package/dist/src/handlers/syndicate.d.ts +0 -6
- package/dist/src/handlers/syndicate.js.map +0 -1
- package/dist/src/handlers/team.d.ts +0 -45
- package/dist/src/handlers/team.js.map +0 -1
- package/dist/src/handlers/viz.d.ts +0 -6
- package/dist/src/handlers/viz.js.map +0 -1
- package/dist/src/index.d.ts +0 -93
- package/dist/src/index.js.map +0 -1
- package/dist/src/interferenz.d.ts +0 -111
- package/dist/src/interferenz.js.map +0 -1
- package/dist/src/kostprobe.d.ts +0 -25
- package/dist/src/kostprobe.js.map +0 -1
- package/dist/src/lesson-preview.d.ts +0 -81
- package/dist/src/lesson-preview.js.map +0 -1
- package/dist/src/namespace.d.ts +0 -20
- package/dist/src/namespace.js.map +0 -1
- package/dist/src/notifier.d.ts +0 -5
- package/dist/src/notifier.js.map +0 -1
- package/dist/src/rangfolge.d.ts +0 -205
- package/dist/src/rangfolge.js.map +0 -1
- package/dist/src/raumkorrektur.d.ts +0 -100
- package/dist/src/raumkorrektur.js.map +0 -1
- package/dist/src/recall-tiefe.d.ts +0 -48
- package/dist/src/recall-tiefe.js.map +0 -1
- package/dist/src/rerank.d.ts +0 -48
- package/dist/src/rerank.js.map +0 -1
- package/dist/src/resonanz.d.ts +0 -85
- package/dist/src/resonanz.js.map +0 -1
- package/dist/src/search.d.ts +0 -153
- package/dist/src/search.js.map +0 -1
- package/dist/src/seltenheitsbestand.d.ts +0 -53
- package/dist/src/seltenheitsbestand.js.map +0 -1
- package/dist/src/speicherlage.d.ts +0 -51
- package/dist/src/speicherlage.js.map +0 -1
- package/dist/src/spuren.d.ts +0 -97
- package/dist/src/spuren.js.map +0 -1
- package/dist/src/starter-corpus.d.ts +0 -28
- package/dist/src/starter-corpus.js.map +0 -1
- package/dist/src/telemetry-types.d.ts +0 -87
- package/dist/src/telemetry-types.js.map +0 -1
- package/dist/src/tools.d.ts +0 -2933
- package/dist/src/tools.js.map +0 -1
- package/dist/src/toolspecs.d.ts +0 -43
- package/dist/src/toolspecs.js.map +0 -1
- package/dist/src/upgrade-nudge.d.ts +0 -15
- package/dist/src/upgrade-nudge.js.map +0 -1
- package/dist/src/utils.d.ts +0 -34
- package/dist/src/utils.js.map +0 -1
- package/dist/src/versuch.d.ts +0 -187
- package/dist/src/versuch.js.map +0 -1
- package/dist/src/vorspann.d.ts +0 -73
- package/dist/src/vorspann.js.map +0 -1
- package/dist/src/wartung/vektoren-verdichten.d.ts +0 -50
- package/dist/src/wartung/vektoren-verdichten.js.map +0 -1
- package/dist/src/werkzeug-nutzung.d.ts +0 -62
- package/dist/src/werkzeug-nutzung.js.map +0 -1
- package/dist/src/wertbeitrag.d.ts +0 -148
- package/dist/src/wertbeitrag.js.map +0 -1
|
@@ -1,201 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
]
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
]);
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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};
|