heyio 1.2.3 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/dist/api/server.js +267 -12
  2. package/dist/config.js +6 -0
  3. package/dist/copilot/agents.js +61 -4
  4. package/dist/copilot/ceremonies.js +12 -2
  5. package/dist/copilot/io-scheduler.js +9 -1
  6. package/dist/copilot/orchestrator.js +2 -0
  7. package/dist/copilot/scheduler.js +4 -0
  8. package/dist/copilot/skills.js +138 -6
  9. package/dist/copilot/system-message.js +12 -0
  10. package/dist/copilot/token-tracker.js +89 -0
  11. package/dist/copilot/tools.js +27 -5
  12. package/dist/paths.js +1 -0
  13. package/dist/store/agent-events.js +19 -0
  14. package/dist/store/audit-log.js +71 -0
  15. package/dist/store/conversations.js +150 -0
  16. package/dist/store/db.js +111 -0
  17. package/dist/store/schedules.js +5 -1
  18. package/dist/store/squad-colors.js +21 -0
  19. package/dist/store/squads.js +6 -1
  20. package/dist/store/tasks.js +43 -0
  21. package/dist/store/token-usage.js +94 -0
  22. package/dist/wiki/backlinks.js +51 -0
  23. package/dist/wiki/fs.js +63 -1
  24. package/package.json +1 -1
  25. package/web-dist/assets/AuditLogView-xgSZ2MOJ.js +6 -0
  26. package/web-dist/assets/ChatView-BU3Jvu5y.js +11 -0
  27. package/web-dist/assets/FeedView-BwkWbe1p.js +6 -0
  28. package/web-dist/assets/HistoryView-Doh9Y3Na.js +1 -0
  29. package/web-dist/assets/LoginView-CoTEOrwE.js +1 -0
  30. package/web-dist/assets/{MarkdownContent.vue_vue_type_script_setup_true_lang-CEo_ckIb.js → MarkdownContent.vue_vue_type_script_setup_true_lang-CObjuCHH.js} +1 -1
  31. package/web-dist/assets/McpView-ByXoAnED.js +1 -0
  32. package/web-dist/assets/SchedulesView-BkUdRYwk.js +1 -0
  33. package/web-dist/assets/SettingsView-_q-IpzFy.js +1 -0
  34. package/web-dist/assets/SkillsView-_FkOdD2U.js +15 -0
  35. package/web-dist/assets/SquadDetailView-CV6_n_If.js +31 -0
  36. package/web-dist/assets/SquadHealthView-DmQqPq7H.js +11 -0
  37. package/web-dist/assets/SquadsView-Dkhtu5MQ.js +6 -0
  38. package/web-dist/assets/UsageView-CCS6pp6n.js +16 -0
  39. package/web-dist/assets/WikiView-CpXzff_L.js +31 -0
  40. package/web-dist/assets/api-CaqVk-rG.js +1 -0
  41. package/web-dist/assets/arrow-left-CkDjCT7Z.js +6 -0
  42. package/web-dist/assets/git-branch-Bu9s__XL.js +6 -0
  43. package/web-dist/assets/index-D3DNfwXI.css +1 -0
  44. package/web-dist/assets/{index-BQdXxKfc.js → index-DfdD_qE4.js} +56 -36
  45. package/web-dist/assets/{plus-Cvp1w2CO.js → plus-GvGwcjX5.js} +1 -1
  46. package/web-dist/assets/{x-O3fBd1Cr.js → save-fQ_rr5hX.js} +2 -7
  47. package/web-dist/assets/search-C3fxUixl.js +6 -0
  48. package/web-dist/assets/squad-colors-B8B_Y-lz.js +1 -0
  49. package/web-dist/assets/{trash-2-Cr3vrmL5.js → trash-2-Ba_1SAua.js} +1 -1
  50. package/web-dist/assets/triangle-alert-BTBlX3kg.js +6 -0
  51. package/web-dist/assets/x-CJifAZQa.js +6 -0
  52. package/web-dist/favicon.svg +9 -3
  53. package/web-dist/index.html +2 -2
  54. package/web-dist/logo.svg +10 -0
  55. package/web-dist/assets/ChatView-mZaaw3pd.js +0 -11
  56. package/web-dist/assets/FeedView-BHacQwXQ.js +0 -6
  57. package/web-dist/assets/LoginView-B6aSD9II.js +0 -1
  58. package/web-dist/assets/McpView-BAVRUHIE.js +0 -1
  59. package/web-dist/assets/SchedulesView-dOd1SQiP.js +0 -1
  60. package/web-dist/assets/SettingsView-CCDeEsVg.js +0 -1
  61. package/web-dist/assets/SkillsView-gCfQ35FQ.js +0 -1
  62. package/web-dist/assets/SquadDetailView-CQhFfZTc.js +0 -21
  63. package/web-dist/assets/SquadsView-CZFxtOao.js +0 -6
  64. package/web-dist/assets/WikiView-B0cuUFfm.js +0 -26
  65. package/web-dist/assets/api-DdW5uOZf.js +0 -1
  66. package/web-dist/assets/index-BbSJ0cfF.css +0 -1
package/dist/store/db.js CHANGED
@@ -2,6 +2,7 @@ import Database from "better-sqlite3";
2
2
  import { existsSync, mkdirSync } from "node:fs";
3
3
  import { dirname } from "node:path";
4
4
  import { PATHS } from "../paths.js";
5
+ import { pickSquadColor } from "./squad-colors.js";
5
6
  let db;
6
7
  export function getDb() {
7
8
  if (db)
@@ -128,6 +129,116 @@ function runMigrations(db) {
128
129
  }
129
130
  setSchemaVersion(db, 2);
130
131
  }
132
+ if (version < 3) {
133
+ db.exec(`
134
+ CREATE TABLE IF NOT EXISTS agent_events (
135
+ id TEXT PRIMARY KEY,
136
+ task_id TEXT NOT NULL,
137
+ type TEXT NOT NULL,
138
+ summary TEXT NOT NULL DEFAULT '',
139
+ payload TEXT NOT NULL DEFAULT '{}',
140
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
141
+ );
142
+
143
+ CREATE INDEX IF NOT EXISTS idx_agent_events_task_id ON agent_events (task_id);
144
+ `);
145
+ setSchemaVersion(db, 3);
146
+ }
147
+ if (version < 4) {
148
+ db.exec(`
149
+ ALTER TABLE squads ADD COLUMN color TEXT;
150
+ `);
151
+ const squads = db
152
+ .prepare("SELECT id FROM squads WHERE color IS NULL ORDER BY created_at")
153
+ .all();
154
+ const update = db.prepare("UPDATE squads SET color = ? WHERE id = ?");
155
+ const usedColors = [];
156
+ for (let i = 0; i < squads.length; i++) {
157
+ const color = pickSquadColor(usedColors);
158
+ usedColors.push(color);
159
+ update.run(color, squads[i].id);
160
+ }
161
+ setSchemaVersion(db, 4);
162
+ }
163
+ if (version < 5) {
164
+ db.exec(`
165
+ CREATE TABLE IF NOT EXISTS conversation_messages (
166
+ id TEXT PRIMARY KEY,
167
+ conversation_id TEXT NOT NULL,
168
+ role TEXT NOT NULL CHECK(role IN ('user', 'assistant')),
169
+ content TEXT NOT NULL,
170
+ source TEXT NOT NULL DEFAULT 'web',
171
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
172
+ );
173
+
174
+ CREATE INDEX IF NOT EXISTS idx_conv_messages_conversation_id
175
+ ON conversation_messages(conversation_id);
176
+
177
+ CREATE INDEX IF NOT EXISTS idx_conv_messages_created_at
178
+ ON conversation_messages(created_at);
179
+
180
+ CREATE VIRTUAL TABLE IF NOT EXISTS conversation_messages_fts
181
+ USING fts5(content, content=conversation_messages, content_rowid=rowid);
182
+
183
+ CREATE TRIGGER IF NOT EXISTS conv_messages_fts_insert
184
+ AFTER INSERT ON conversation_messages BEGIN
185
+ INSERT INTO conversation_messages_fts(rowid, content) VALUES (new.rowid, new.content);
186
+ END;
187
+
188
+ CREATE TRIGGER IF NOT EXISTS conv_messages_fts_update
189
+ AFTER UPDATE ON conversation_messages BEGIN
190
+ INSERT INTO conversation_messages_fts(conversation_messages_fts, rowid, content) VALUES ('delete', old.rowid, old.content);
191
+ INSERT INTO conversation_messages_fts(rowid, content) VALUES (new.rowid, new.content);
192
+ END;
193
+
194
+ CREATE TRIGGER IF NOT EXISTS conv_messages_fts_delete
195
+ AFTER DELETE ON conversation_messages BEGIN
196
+ INSERT INTO conversation_messages_fts(conversation_messages_fts, rowid, content) VALUES ('delete', old.rowid, old.content);
197
+ END;
198
+ `);
199
+ setSchemaVersion(db, 5);
200
+ }
201
+ if (version < 6) {
202
+ db.exec(`
203
+ CREATE TABLE IF NOT EXISTS audit_log (
204
+ id TEXT PRIMARY KEY,
205
+ squad_id TEXT REFERENCES squads(id) ON DELETE SET NULL,
206
+ agent_id TEXT REFERENCES agents(id) ON DELETE SET NULL,
207
+ task_id TEXT,
208
+ action_type TEXT NOT NULL,
209
+ summary TEXT NOT NULL DEFAULT '',
210
+ payload TEXT NOT NULL DEFAULT '{}',
211
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
212
+ );
213
+
214
+ CREATE INDEX IF NOT EXISTS idx_audit_log_squad_id ON audit_log (squad_id);
215
+ CREATE INDEX IF NOT EXISTS idx_audit_log_agent_id ON audit_log (agent_id);
216
+ CREATE INDEX IF NOT EXISTS idx_audit_log_action_type ON audit_log (action_type);
217
+ CREATE INDEX IF NOT EXISTS idx_audit_log_created_at ON audit_log (created_at);
218
+ `);
219
+ setSchemaVersion(db, 6);
220
+ }
221
+ if (version < 7) {
222
+ db.exec(`
223
+ CREATE TABLE IF NOT EXISTS token_usage (
224
+ id TEXT PRIMARY KEY,
225
+ squad_id TEXT REFERENCES squads(id) ON DELETE CASCADE,
226
+ agent_id TEXT REFERENCES agents(id) ON DELETE SET NULL,
227
+ task_id TEXT REFERENCES tasks(id) ON DELETE SET NULL,
228
+ model TEXT NOT NULL,
229
+ input_tokens INTEGER NOT NULL DEFAULT 0,
230
+ output_tokens INTEGER NOT NULL DEFAULT 0,
231
+ cost_usd REAL NOT NULL DEFAULT 0,
232
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
233
+ );
234
+
235
+ CREATE INDEX IF NOT EXISTS idx_token_usage_squad ON token_usage(squad_id);
236
+ CREATE INDEX IF NOT EXISTS idx_token_usage_agent ON token_usage(agent_id);
237
+ CREATE INDEX IF NOT EXISTS idx_token_usage_task ON token_usage(task_id);
238
+ CREATE INDEX IF NOT EXISTS idx_token_usage_created ON token_usage(created_at);
239
+ `);
240
+ setSchemaVersion(db, 7);
241
+ }
131
242
  }
132
243
  function getSchemaVersion(db) {
133
244
  const row = db.prepare("SELECT value FROM meta WHERE key = 'schema_version'").get();
@@ -1,10 +1,14 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { getDb } from "./db.js";
3
3
  export function createSchedule(input) {
4
+ const squadId = input.squad_id.trim();
5
+ if (!squadId) {
6
+ throw new Error("squad_id is required");
7
+ }
4
8
  const db = getDb();
5
9
  const id = randomUUID();
6
10
  db.prepare(`INSERT INTO schedules (id, type, squad_id, cron, agenda, prompt)
7
- VALUES (?, ?, ?, ?, ?, ?)`).run(id, input.type, input.squad_id ?? null, input.cron, input.agenda ?? "", input.prompt ?? "");
11
+ VALUES (?, ?, ?, ?, ?, ?)`).run(id, input.type, squadId, input.cron, input.agenda ?? "", input.prompt ?? "");
8
12
  return db.prepare("SELECT * FROM schedules WHERE id = ?").get(id);
9
13
  }
10
14
  export function listSchedules(type) {
@@ -0,0 +1,21 @@
1
+ export const SQUAD_COLOR_PALETTE = [
2
+ "#ef4444",
3
+ "#f97316",
4
+ "#eab308",
5
+ "#22c55e",
6
+ "#06b6d4",
7
+ "#3b82f6",
8
+ "#8b5cf6",
9
+ "#ec4899",
10
+ ];
11
+ const DEFAULT_SQUAD_COLOR = "#3b82f6";
12
+ export function pickSquadColor(usedColors, random = Math.random) {
13
+ const used = new Set(usedColors.filter(Boolean).map((c) => c.toLowerCase()));
14
+ const available = SQUAD_COLOR_PALETTE.filter((c) => !used.has(c.toLowerCase()));
15
+ const source = available.length > 0 ? available : SQUAD_COLOR_PALETTE;
16
+ if (source.length === 0)
17
+ return DEFAULT_SQUAD_COLOR;
18
+ const index = Math.floor(random() * source.length);
19
+ return source[index] ?? DEFAULT_SQUAD_COLOR;
20
+ }
21
+ //# sourceMappingURL=squad-colors.js.map
@@ -1,10 +1,15 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { getDb } from "./db.js";
3
+ import { pickSquadColor } from "./squad-colors.js";
3
4
  export function createSquad(name, universe, repoUrl) {
4
5
  const db = getDb();
5
6
  const id = randomUUID();
6
7
  const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
7
- db.prepare("INSERT INTO squads (id, name, slug, universe, repo_url) VALUES (?, ?, ?, ?, ?)").run(id, name, slug, universe, repoUrl ?? null);
8
+ const usedColors = db
9
+ .prepare("SELECT color FROM squads WHERE color IS NOT NULL")
10
+ .all();
11
+ const color = pickSquadColor(usedColors.map((row) => row.color));
12
+ db.prepare("INSERT INTO squads (id, name, slug, universe, color, repo_url) VALUES (?, ?, ?, ?, ?, ?)").run(id, name, slug, universe, color, repoUrl ?? null);
8
13
  return db.prepare("SELECT * FROM squads WHERE id = ?").get(id);
9
14
  }
10
15
  export function getSquad(id) {
@@ -32,4 +32,47 @@ export function getActiveTasksForInstance(instanceId) {
32
32
  .prepare("SELECT * FROM tasks WHERE instance_id = ? AND status NOT IN ('done', 'failed') ORDER BY created_at")
33
33
  .all(instanceId);
34
34
  }
35
+ /** Squads with active tasks and no update within this window are flagged as stalled. */
36
+ const STALL_THRESHOLD_MS = 60 * 60 * 1000; // 60 minutes
37
+ export function getSquadTaskMetrics(squadId) {
38
+ const db = getDb();
39
+ const row = db
40
+ .prepare(`SELECT
41
+ COUNT(*) AS total,
42
+ SUM(CASE WHEN status = 'done' THEN 1 ELSE 0 END) AS completed,
43
+ SUM(CASE WHEN status = 'done' AND updated_at >= datetime('now', '-7 days') THEN 1 ELSE 0 END) AS completed_recent,
44
+ SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) AS pending,
45
+ SUM(CASE WHEN status = 'in_progress' THEN 1 ELSE 0 END) AS in_progress,
46
+ SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) AS failed,
47
+ AVG(CASE WHEN status = 'done'
48
+ THEN (julianday(updated_at) - julianday(created_at)) * 1440
49
+ ELSE NULL END) AS avg_cycle_minutes,
50
+ MAX(CASE WHEN status IN ('pending', 'in_progress') THEN updated_at ELSE NULL END) AS last_active_update
51
+ FROM tasks WHERE squad_id = ?`)
52
+ .get(squadId);
53
+ // A squad is considered stalled if it has active tasks but none have been
54
+ // updated within STALL_THRESHOLD_MS.
55
+ const hasActiveTasks = row.pending + row.in_progress > 0;
56
+ const isStalled = hasActiveTasks &&
57
+ row.last_active_update !== null &&
58
+ new Date(row.last_active_update + "Z").getTime() <
59
+ Date.now() - STALL_THRESHOLD_MS;
60
+ const recentTasks = db
61
+ .prepare("SELECT * FROM tasks WHERE squad_id = ? ORDER BY updated_at DESC LIMIT 5")
62
+ .all(squadId);
63
+ return {
64
+ squadId,
65
+ tasksTotal: row.total ?? 0,
66
+ tasksCompleted: row.completed ?? 0,
67
+ tasksCompletedRecent: row.completed_recent ?? 0,
68
+ tasksPending: row.pending ?? 0,
69
+ tasksInProgress: row.in_progress ?? 0,
70
+ tasksFailed: row.failed ?? 0,
71
+ avgCycleTimeMinutes: row.avg_cycle_minutes != null
72
+ ? Math.round(row.avg_cycle_minutes * 10) / 10
73
+ : null,
74
+ isStalled,
75
+ recentTasks,
76
+ };
77
+ }
35
78
  //# sourceMappingURL=tasks.js.map
@@ -0,0 +1,94 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { getDb } from "./db.js";
3
+ export function recordTokenUsage(params) {
4
+ const db = getDb();
5
+ const id = randomUUID();
6
+ db.prepare(`INSERT INTO token_usage (id, squad_id, agent_id, task_id, model, input_tokens, output_tokens, cost_usd)
7
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(id, params.squadId ?? null, params.agentId ?? null, params.taskId ?? null, params.model, params.inputTokens, params.outputTokens, params.costUsd);
8
+ return db.prepare("SELECT * FROM token_usage WHERE id = ?").get(id);
9
+ }
10
+ export function getTokenUsageSummary(opts) {
11
+ const db = getDb();
12
+ let sql = `SELECT
13
+ COUNT(*) as total_records,
14
+ COALESCE(SUM(input_tokens), 0) as total_input_tokens,
15
+ COALESCE(SUM(output_tokens), 0) as total_output_tokens,
16
+ COALESCE(SUM(input_tokens + output_tokens), 0) as total_tokens,
17
+ COALESCE(SUM(cost_usd), 0) as total_cost_usd
18
+ FROM token_usage WHERE 1=1`;
19
+ const params = [];
20
+ if (opts?.since) {
21
+ sql += " AND created_at >= ?";
22
+ params.push(opts.since);
23
+ }
24
+ return db.prepare(sql).get(...params);
25
+ }
26
+ export function getTokenUsageBySquad(opts) {
27
+ const db = getDb();
28
+ let sql = `SELECT
29
+ s.id,
30
+ s.name,
31
+ COALESCE(SUM(t.input_tokens), 0) as total_input_tokens,
32
+ COALESCE(SUM(t.output_tokens), 0) as total_output_tokens,
33
+ COALESCE(SUM(t.input_tokens + t.output_tokens), 0) as total_tokens,
34
+ COALESCE(SUM(t.cost_usd), 0) as total_cost_usd,
35
+ COUNT(t.id) as record_count
36
+ FROM squads s
37
+ LEFT JOIN token_usage t ON t.squad_id = s.id`;
38
+ const params = [];
39
+ if (opts?.since) {
40
+ sql += " AND t.created_at >= ?";
41
+ params.push(opts.since);
42
+ }
43
+ sql += " GROUP BY s.id ORDER BY total_tokens DESC";
44
+ return db.prepare(sql).all(...params);
45
+ }
46
+ export function getTokenUsageByAgent(opts) {
47
+ const db = getDb();
48
+ let sql = `SELECT
49
+ a.id,
50
+ a.character_name as name,
51
+ COALESCE(SUM(t.input_tokens), 0) as total_input_tokens,
52
+ COALESCE(SUM(t.output_tokens), 0) as total_output_tokens,
53
+ COALESCE(SUM(t.input_tokens + t.output_tokens), 0) as total_tokens,
54
+ COALESCE(SUM(t.cost_usd), 0) as total_cost_usd,
55
+ COUNT(t.id) as record_count
56
+ FROM agents a
57
+ LEFT JOIN token_usage t ON t.agent_id = a.id`;
58
+ const params = [];
59
+ const conditions = [];
60
+ if (opts?.squadId) {
61
+ conditions.push("a.squad_id = ?");
62
+ params.push(opts.squadId);
63
+ }
64
+ if (opts?.since) {
65
+ conditions.push("(t.created_at >= ? OR t.created_at IS NULL)");
66
+ params.push(opts.since);
67
+ }
68
+ if (conditions.length > 0) {
69
+ sql += " WHERE " + conditions.join(" AND ");
70
+ }
71
+ sql += " GROUP BY a.id ORDER BY total_tokens DESC";
72
+ return db.prepare(sql).all(...params);
73
+ }
74
+ export function getDailyTokenUsage(days = 30) {
75
+ const db = getDb();
76
+ const sql = `SELECT
77
+ date(created_at) as date,
78
+ COALESCE(SUM(input_tokens), 0) as total_input_tokens,
79
+ COALESCE(SUM(output_tokens), 0) as total_output_tokens,
80
+ COALESCE(SUM(input_tokens + output_tokens), 0) as total_tokens,
81
+ COALESCE(SUM(cost_usd), 0) as total_cost_usd
82
+ FROM token_usage
83
+ WHERE created_at >= date('now', '-' || ? || ' days')
84
+ GROUP BY date(created_at)
85
+ ORDER BY date ASC`;
86
+ return db.prepare(sql).all(days);
87
+ }
88
+ export function getTokenUsageForTask(taskId) {
89
+ const db = getDb();
90
+ return db
91
+ .prepare("SELECT * FROM token_usage WHERE task_id = ? ORDER BY created_at ASC")
92
+ .all(taskId);
93
+ }
94
+ //# sourceMappingURL=token-usage.js.map
@@ -0,0 +1,51 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join, dirname, resolve } from "node:path";
3
+ import { PATHS } from "../paths.js";
4
+ import { listPages } from "./fs.js";
5
+ export async function getBacklinks(targetPath) {
6
+ if (!existsSync(PATHS.wikiPages))
7
+ return [];
8
+ const pages = await listPages();
9
+ const backlinks = [];
10
+ // Normalize the target path (ensure .md extension)
11
+ const normalizedTarget = targetPath.endsWith(".md") ? targetPath : `${targetPath}.md`;
12
+ for (const pagePath of pages) {
13
+ if (pagePath === normalizedTarget)
14
+ continue; // Skip self-references
15
+ const fullPath = join(PATHS.wikiPages, pagePath);
16
+ const content = readFileSync(fullPath, "utf-8");
17
+ if (pageLinksTo(content, pagePath, normalizedTarget)) {
18
+ backlinks.push(pagePath);
19
+ }
20
+ }
21
+ return backlinks;
22
+ }
23
+ function pageLinksTo(content, fromPage, targetPage) {
24
+ const fromDir = dirname(fromPage);
25
+ const targetWithoutExt = targetPage.replace(/\.md$/, "");
26
+ // Check standard markdown links: [text](url)
27
+ const markdownLinkRegex = /\[([^\]]*)\]\(([^)]+)\)/g;
28
+ let match;
29
+ while ((match = markdownLinkRegex.exec(content)) !== null) {
30
+ const linkHref = match[2].split("#")[0].trim(); // Strip anchors and whitespace
31
+ if (!linkHref || linkHref.startsWith("http://") || linkHref.startsWith("https://"))
32
+ continue;
33
+ const resolvedLink = resolve("/", fromDir, linkHref).slice(1); // Resolve relative path, strip leading /
34
+ const resolvedWithoutExt = resolvedLink.endsWith(".md") ? resolvedLink.slice(0, -3) : resolvedLink;
35
+ if (resolvedWithoutExt === targetWithoutExt)
36
+ return true;
37
+ }
38
+ // Check wiki-style links: [[page]] or [[page|display text]]
39
+ // Wiki-style links are resolved from the wiki root (absolute), not relative to the current page
40
+ const wikiLinkRegex = /\[\[([^\]]+)\]\]/g;
41
+ while ((match = wikiLinkRegex.exec(content)) !== null) {
42
+ const linkTarget = match[1].split("|")[0].trim(); // Handle [[page|display text]]
43
+ if (!linkTarget)
44
+ continue;
45
+ const resolvedWithoutExt = linkTarget.endsWith(".md") ? linkTarget.slice(0, -3) : linkTarget;
46
+ if (resolvedWithoutExt === targetWithoutExt)
47
+ return true;
48
+ }
49
+ return false;
50
+ }
51
+ //# sourceMappingURL=backlinks.js.map
package/dist/wiki/fs.js CHANGED
@@ -1,7 +1,19 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync, rmSync } from "node:fs";
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, rmSync, cpSync } from "node:fs";
2
2
  import { join, dirname } from "node:path";
3
3
  import { readdirSync } from "node:fs";
4
4
  import { PATHS } from "../paths.js";
5
+ function safeJoin(base, userPath) {
6
+ // Strip path traversal by removing any '..' and absolute path components
7
+ const sanitized = userPath
8
+ .split(/[/\\]/)
9
+ .filter((segment) => segment !== ".." && segment !== ".")
10
+ .join("/");
11
+ const resolved = join(base, sanitized);
12
+ if (!resolved.startsWith(base)) {
13
+ throw new Error("Invalid path: traversal outside base directory is not allowed");
14
+ }
15
+ return resolved;
16
+ }
5
17
  export async function readPage(path) {
6
18
  const fullPath = join(PATHS.wikiPages, path);
7
19
  if (!existsSync(fullPath)) {
@@ -43,4 +55,54 @@ export async function listPages(dir) {
43
55
  walk(root, "");
44
56
  return results;
45
57
  }
58
+ export async function listTemplates() {
59
+ const root = PATHS.wikiSquadTemplates;
60
+ if (!existsSync(root))
61
+ return [];
62
+ const results = [];
63
+ const walk = (current, prefix) => {
64
+ const entries = readdirSync(current, { withFileTypes: true });
65
+ for (const entry of entries) {
66
+ const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
67
+ if (entry.isDirectory()) {
68
+ walk(join(current, entry.name), rel);
69
+ }
70
+ else {
71
+ results.push(rel);
72
+ }
73
+ }
74
+ };
75
+ walk(root, "");
76
+ return results;
77
+ }
78
+ export async function readTemplate(path) {
79
+ const fullPath = safeJoin(PATHS.wikiSquadTemplates, path);
80
+ if (!existsSync(fullPath)) {
81
+ throw new Error(`Template not found: ${path}`);
82
+ }
83
+ return readFileSync(fullPath, "utf-8");
84
+ }
85
+ export async function writeTemplate(path, content) {
86
+ const fullPath = safeJoin(PATHS.wikiSquadTemplates, path);
87
+ const dir = dirname(fullPath);
88
+ if (!existsSync(dir))
89
+ mkdirSync(dir, { recursive: true });
90
+ writeFileSync(fullPath, content);
91
+ }
92
+ export async function deleteTemplate(path) {
93
+ const fullPath = safeJoin(PATHS.wikiSquadTemplates, path);
94
+ if (!existsSync(fullPath)) {
95
+ throw new Error(`Template not found: ${path}`);
96
+ }
97
+ rmSync(fullPath);
98
+ }
99
+ export async function copySquadTemplates(slug) {
100
+ const templateDir = PATHS.wikiSquadTemplates;
101
+ if (!existsSync(templateDir))
102
+ return;
103
+ const destDir = join(PATHS.wikiPages, "squads", slug);
104
+ if (!existsSync(destDir))
105
+ mkdirSync(destDir, { recursive: true });
106
+ cpSync(templateDir, destDir, { recursive: true, force: false, errorOnExist: false });
107
+ }
46
108
  //# sourceMappingURL=fs.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "heyio",
3
- "version": "1.2.3",
3
+ "version": "1.3.0",
4
4
  "description": "IO — a personal AI assistant daemon built on the GitHub Copilot SDK",
5
5
  "bin": {
6
6
  "io": "dist/index.js"
@@ -0,0 +1,6 @@
1
+ import{h as W,k as X,p as Z,r as a,g as d,d as o,j as P,x as A,a as V,i as S,w as l,N as f,G as T,F as h,t as w,J as F,f as b,s as n,c as _,m as ee}from"./index-DfdD_qE4.js";import{b as L}from"./api-CaqVk-rG.js";/**
2
+ * @license lucide-vue-next v0.474.0 - ISC
3
+ *
4
+ * This source code is licensed under the ISC license.
5
+ * See the LICENSE file in the root directory of this source tree.
6
+ */const te=W("FilterIcon",[["polygon",{points:"22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3",key:"1yg77f"}]]),oe={class:"p-6"},se={class:"flex items-center justify-between mb-6"},ae={class:"text-2xl font-bold flex items-center gap-2"},de={class:"text-sm text-muted-foreground"},le={class:"border border-border rounded-lg p-4 mb-6 space-y-3"},re={class:"flex items-center gap-2 text-sm font-medium text-muted-foreground mb-1"},ne={class:"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-3"},ue=["value"],ie=["value"],ce=["value"],pe={key:0,class:"text-muted-foreground"},ve={key:1,class:"text-center py-12 text-muted-foreground"},me={key:2,class:"space-y-1"},ge=["onClick"],xe={class:"flex-1 min-w-0"},fe={class:"flex flex-wrap items-center gap-2 mb-1"},be={key:0,class:"text-xs bg-secondary text-secondary-foreground px-2 py-0.5 rounded-full"},_e={key:1,class:"text-xs bg-secondary text-secondary-foreground px-2 py-0.5 rounded-full"},ye={class:"text-sm truncate"},ke={class:"text-xs text-muted-foreground mt-0.5"},he={class:"text-xs text-muted-foreground mt-1 shrink-0"},we={key:0,class:"border-t border-border px-4 py-3"},qe={key:0,class:"text-xs text-muted-foreground mb-2"},Ce={class:"font-mono"},Ne={class:"text-xs bg-muted rounded p-3 overflow-x-auto whitespace-pre-wrap break-words"},Pe={key:3,class:"flex items-center justify-between mt-4"},Ae=["disabled"],Se={class:"text-xs text-muted-foreground"},Te=["disabled"],u=50,Ie=X({__name:"AuditLogView",setup(Ve){const q=n([]),c=n(0),C=n(!0),y=n(null),N=n([]),k=n([]),i=n(""),p=n(""),v=n(""),m=n(""),g=n(""),r=n(0),M=["message_received","task_delegated","task_completed","task_failed","shell_command","squad_created","squad_meeting"],I={message_received:"bg-blue-500/20 text-blue-400",task_delegated:"bg-purple-500/20 text-purple-400",task_completed:"bg-green-500/20 text-green-400",task_failed:"bg-red-500/20 text-red-400",shell_command:"bg-yellow-500/20 text-yellow-400",squad_created:"bg-indigo-500/20 text-indigo-400",squad_meeting:"bg-teal-500/20 text-teal-400"};function O(s){return I[s]??"bg-secondary text-secondary-foreground"}async function x(){C.value=!0;try{const s=new URLSearchParams;i.value&&s.set("squad_id",i.value),p.value&&s.set("agent_id",p.value),v.value&&s.set("action_type",v.value),m.value&&s.set("from",m.value),g.value&&s.set("to",g.value),s.set("limit",String(u)),s.set("offset",String(r.value));const t=await L(`/audit-log?${s.toString()}`);q.value=t.entries,c.value=t.total}finally{C.value=!1}}async function U(){const s=await L("/squads");N.value=s.squads,k.value=s.agents}function $(){r.value=0,x()}function D(){i.value="",p.value="",v.value="",m.value="",g.value="",r.value=0,x()}function j(){r.value>0&&(r.value=Math.max(0,r.value-u),x())}function B(){r.value+u<c.value&&(r.value=r.value+u,x())}function E(s){y.value=y.value===s?null:s}function J(s){try{return JSON.stringify(JSON.parse(s.payload),null,2)}catch{return s.payload}}function R(s){var t;return s?((t=N.value.find(e=>e.id===s))==null?void 0:t.name)??s.slice(0,8):""}function G(s){if(!s)return"";const t=k.value.find(e=>e.id===s);return t?`${t.character_name} (${t.role_title})`:s.slice(0,8)}const Y=_(()=>r.value+u<c.value),z=_(()=>r.value>0),H=_(()=>Math.floor(r.value/u)+1),K=_(()=>Math.max(1,Math.ceil(c.value/u))),Q=_(()=>i.value?k.value.filter(s=>s.squad_id===i.value):k.value);return Z(async()=>{await Promise.all([x(),U()])}),(s,t)=>(a(),d("div",oe,[o("div",se,[o("h1",ae,[P(A(V),{class:"w-6 h-6"}),t[6]||(t[6]=S(" Audit Log ",-1))]),o("span",de,l(c.value)+" entries",1)]),o("div",le,[o("div",re,[P(A(te),{class:"w-4 h-4"}),t[7]||(t[7]=S(" Filters ",-1))]),o("div",ne,[f(o("select",{"onUpdate:modelValue":t[0]||(t[0]=e=>i.value=e),class:"px-2 py-1.5 text-sm rounded-md border border-border bg-background",onChange:t[1]||(t[1]=e=>p.value="")},[t[8]||(t[8]=o("option",{value:""},"All squads",-1)),(a(!0),d(h,null,w(N.value,e=>(a(),d("option",{key:e.id,value:e.id},l(e.name),9,ue))),128))],544),[[T,i.value]]),f(o("select",{"onUpdate:modelValue":t[2]||(t[2]=e=>p.value=e),class:"px-2 py-1.5 text-sm rounded-md border border-border bg-background"},[t[9]||(t[9]=o("option",{value:""},"All agents",-1)),(a(!0),d(h,null,w(Q.value,e=>(a(),d("option",{key:e.id,value:e.id},l(e.character_name),9,ie))),128))],512),[[T,p.value]]),f(o("select",{"onUpdate:modelValue":t[3]||(t[3]=e=>v.value=e),class:"px-2 py-1.5 text-sm rounded-md border border-border bg-background"},[t[10]||(t[10]=o("option",{value:""},"All action types",-1)),(a(),d(h,null,w(M,e=>o("option",{key:e,value:e},l(e),9,ce)),64))],512),[[T,v.value]]),f(o("input",{"onUpdate:modelValue":t[4]||(t[4]=e=>m.value=e),type:"datetime-local",placeholder:"From",class:"px-2 py-1.5 text-sm rounded-md border border-border bg-background"},null,512),[[F,m.value]]),f(o("input",{"onUpdate:modelValue":t[5]||(t[5]=e=>g.value=e),type:"datetime-local",placeholder:"To",class:"px-2 py-1.5 text-sm rounded-md border border-border bg-background"},null,512),[[F,g.value]])]),o("div",{class:"flex gap-2"},[o("button",{onClick:$,class:"px-3 py-1.5 text-xs rounded-md bg-primary text-primary-foreground hover:bg-primary/90 transition-colors"}," Apply "),o("button",{onClick:D,class:"px-3 py-1.5 text-xs rounded-md border border-border text-muted-foreground hover:text-foreground transition-colors"}," Reset ")])]),C.value?(a(),d("div",pe,"Loading...")):q.value.length===0?(a(),d("div",ve,[P(A(V),{class:"w-12 h-12 mx-auto mb-3 opacity-50"}),t[11]||(t[11]=o("p",null,"No audit log entries found.",-1))])):(a(),d("div",me,[(a(!0),d(h,null,w(q.value,e=>(a(),d("div",{key:e.id,class:"border border-border rounded-lg overflow-hidden"},[o("div",{onClick:Fe=>E(e.id),class:"flex items-start gap-3 px-4 py-3 cursor-pointer hover:bg-muted/50 transition-colors"},[o("div",xe,[o("div",fe,[o("span",{class:ee(["text-xs px-2 py-0.5 rounded-full font-mono",O(e.action_type)])},l(e.action_type),3),e.squad_id?(a(),d("span",be,l(R(e.squad_id)),1)):b("",!0),e.agent_id?(a(),d("span",_e,l(G(e.agent_id)),1)):b("",!0)]),o("p",ye,l(e.summary),1),o("p",ke,l(e.created_at),1)]),o("span",he,l(y.value===e.id?"▲":"▼"),1)],8,ge),y.value===e.id?(a(),d("div",we,[e.task_id?(a(),d("div",qe,[t[12]||(t[12]=S(" Task ID: ",-1)),o("code",Ce,l(e.task_id),1)])):b("",!0),o("pre",Ne,l(J(e)),1)])):b("",!0)]))),128))])),c.value>u?(a(),d("div",Pe,[o("button",{disabled:!z.value,onClick:j,class:"px-3 py-1.5 text-xs rounded-md border border-border text-muted-foreground disabled:opacity-40 hover:text-foreground transition-colors"}," ← Previous ",8,Ae),o("span",Se," Page "+l(H.value)+" of "+l(K.value),1),o("button",{disabled:!Y.value,onClick:B,class:"px-3 py-1.5 text-xs rounded-md border border-border text-muted-foreground disabled:opacity-40 hover:text-foreground transition-colors"}," Next → ",8,Te)])):b("",!0)]))}});export{Ie as default};
@@ -0,0 +1,11 @@
1
+ import{h as k,l as b,s as u,k as w,K as h,p as S,r,g as c,d as n,x as d,f as x,F as I,t as U,N as M,J as C,e as v,m as y,n as _}from"./index-DfdD_qE4.js";import{c as D}from"./api-CaqVk-rG.js";import{_ as B}from"./MarkdownContent.vue_vue_type_script_setup_true_lang-CObjuCHH.js";/**
2
+ * @license lucide-vue-next v0.474.0 - ISC
3
+ *
4
+ * This source code is licensed under the ISC license.
5
+ * See the LICENSE file in the root directory of this source tree.
6
+ */const j=k("SendIcon",[["path",{d:"M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z",key:"1ffxy3"}],["path",{d:"m21.854 2.147-10.94 10.939",key:"12cjpa"}]]);/**
7
+ * @license lucide-vue-next v0.474.0 - ISC
8
+ *
9
+ * This source code is licensed under the ISC license.
10
+ * See the LICENSE file in the root directory of this source tree.
11
+ */const K=k("SquareIcon",[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}]]),T=b("chat",()=>{const i=u([]),t=u(!1),l=u(null),o=u(crypto.randomUUID());function p(a){const e={id:crypto.randomUUID(),role:"user",content:a,timestamp:new Date};return i.value.push(e),e}async function m(a){p(a),t.value=!0;const e={id:crypto.randomUUID(),role:"assistant",content:"",timestamp:new Date,streaming:!0};i.value.push(e);try{const f=await D("/message",{prompt:a,conversationId:o.value});e.content=f.content,e.streaming=!1,f.conversationId&&(o.value=f.conversationId)}catch(f){e.content=`Error: ${f.message}`,e.streaming=!1}finally{t.value=!1}}function g(a){const e=i.value[i.value.length-1];e!=null&&e.streaming&&(e.content=a)}function s(){i.value=[],o.value=crypto.randomUUID()}return{messages:i,isStreaming:t,eventSource:l,conversationId:o,sendMessage:m,updateStreamingMessage:g,clearMessages:s}}),V={class:"flex flex-col h-full"},z={key:0,class:"flex items-center justify-center h-full"},E={key:1,class:"text-muted-foreground"},N={key:2,class:"inline-block w-2 h-4 bg-current animate-pulse ml-1"},q={class:"border-t border-border p-4"},F={class:"flex gap-2 items-end"},L=["disabled"],O=w({__name:"ChatView",setup(i){const t=T(),l=u(""),o=u();async function p(){const s=l.value.trim();!s||t.isStreaming||(l.value="",await t.sendMessage(s))}function m(){o.value&&(o.value.scrollTop=o.value.scrollHeight)}function g(s){s.key==="Enter"&&!s.shiftKey&&(s.preventDefault(),p())}return h(()=>t.messages.map(s=>s.content),async()=>{await _(),m()},{deep:!0}),h(()=>t.messages.length,async()=>{await _(),m()}),S(()=>m()),(s,a)=>(r(),c("div",V,[n("div",{ref_key:"messagesContainer",ref:o,class:"flex-1 overflow-y-auto p-4 space-y-4"},[d(t).messages.length===0?(r(),c("div",z,[...a[1]||(a[1]=[n("div",{class:"text-center text-muted-foreground"},[n("div",{class:"text-4xl mb-3"},"🤖"),n("p",{class:"text-lg font-medium"},"Welcome to IO"),n("p",{class:"text-sm mt-1"},"Send a message to get started.")],-1)])])):x("",!0),(r(!0),c(I,null,U(d(t).messages,e=>(r(),c("div",{key:e.id,class:y(["flex",e.role==="user"?"justify-end":"justify-start"])},[n("div",{class:y(["max-w-[75%] rounded-lg px-4 py-2 text-sm",e.role==="user"?"bg-blue-600 text-white":"bg-muted text-foreground"])},[e.content?(r(),v(B,{key:0,content:e.content,class:y(e.role==="user"?"prose-invert":"")},null,8,["content","class"])):(r(),c("span",E,"...")),e.streaming?(r(),c("div",N)):x("",!0)],2)],2))),128))],512),n("div",q,[n("div",F,[M(n("textarea",{"onUpdate:modelValue":a[0]||(a[0]=e=>l.value=e),onKeydown:g,placeholder:"Send a message...",rows:"1",class:"flex-1 resize-none rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring min-h-[40px] max-h-[120px]"},null,544),[[C,l.value]]),n("button",{onClick:p,disabled:!l.value.trim()||d(t).isStreaming,class:"rounded-md bg-primary text-primary-foreground p-2 hover:bg-primary/90 disabled:opacity-50 transition-colors"},[d(t).isStreaming?(r(),v(d(K),{key:1,class:"w-4 h-4"})):(r(),v(d(j),{key:0,class:"w-4 h-4"}))],8,L)])])]))}});export{O as default};
@@ -0,0 +1,6 @@
1
+ import{h as M,k as N,p as V,r as o,g as n,d as a,F as y,t as b,j as c,x as i,I as B,s as d,c as D,m as f,w as p,o as j,Q as k,f as C}from"./index-DfdD_qE4.js";import{b as q,c as z,a as P}from"./api-CaqVk-rG.js";import{_ as T}from"./MarkdownContent.vue_vue_type_script_setup_true_lang-CObjuCHH.js";import{g as A}from"./squad-colors-B8B_Y-lz.js";import{T as E}from"./trash-2-Ba_1SAua.js";/**
2
+ * @license lucide-vue-next v0.474.0 - ISC
3
+ *
4
+ * This source code is licensed under the ISC license.
5
+ * See the LICENSE file in the root directory of this source tree.
6
+ */const G=M("CheckIcon",[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]]),Q={class:"p-6"},R={class:"flex items-center justify-between mb-6"},U={class:"flex gap-2"},W=["onClick"],H={key:0,class:"text-muted-foreground"},J={key:1,class:"text-center py-12 text-muted-foreground"},K={key:2,class:"space-y-2"},O=["onClick"],X={class:"flex-1 min-w-0"},Y={class:"flex items-center gap-2"},Z={class:"text-xs text-muted-foreground mt-0.5"},ee={class:"flex gap-1"},te=["onClick"],se=["onClick"],ae={key:0,class:"px-4 pb-3 border-t border-border pt-3"},ce=N({__name:"FeedView",setup(oe){const r=d([]),x=d([]),l=d(0),v=d("all"),m=d(!0),u=d(null);async function g(){m.value=!0;try{const e=await q(`/feed?unread=${v.value==="unread"}`);r.value=e.items,l.value=e.unreadCount}finally{m.value=!1}}async function w(){const e=await q("/squads");x.value=e.squads}async function h(e){await z(`/feed/${e}/read`);const s=r.value.find(t=>t.id===e);s&&(s.read=1,l.value=Math.max(0,l.value-1))}async function $(e){await P(`/feed/${e}`),r.value=r.value.filter(s=>s.id!==e)}function I(e){u.value=u.value===e?null:e,u.value===e&&h(e)}function S(e){if(!e.startsWith("squad-"))return;const s=e.slice(6);return x.value.find(t=>t.id===s)}const F=D(()=>r.value.map(e=>{const s=S(e.source);return{...e,squad:s}}));V(async()=>{await Promise.all([g(),w()])});function L(e){var s;return((s=e.squad)==null?void 0:s.name)??e.source}return(e,s)=>(o(),n("div",Q,[a("div",R,[s[0]||(s[0]=a("h1",{class:"text-2xl font-bold"},"Feed",-1)),a("div",U,[(o(),n(y,null,b(["all","unread"],t=>a("button",{key:t,onClick:_=>{v.value=t,g()},class:f(["px-3 py-1.5 text-xs rounded-md border transition-colors",v.value===t?"bg-primary text-primary-foreground border-primary":"border-border text-muted-foreground hover:text-foreground"])},p(t==="all"?"All":`Unread (${l.value})`),11,W)),64))])]),m.value?(o(),n("div",H,"Loading...")):r.value.length===0?(o(),n("div",J,[c(i(B),{class:"w-12 h-12 mx-auto mb-3 opacity-50"}),s[1]||(s[1]=a("p",null,"No feed items.",-1))])):(o(),n("div",K,[(o(!0),n(y,null,b(F.value,t=>(o(),n("div",{key:t.id,class:f(["border border-border rounded-lg overflow-hidden",{"border-l-2 border-l-primary":!t.read}])},[a("div",{onClick:_=>I(t.id),class:"flex items-center gap-3 px-4 py-3 cursor-pointer hover:bg-muted/50 transition-colors"},[a("div",X,[a("div",Y,[a("span",{class:f(["text-xs px-2 py-0.5 rounded-full",{"bg-secondary text-secondary-foreground":!t.squad}]),style:j(t.squad?i(A)(t.squad.color):{})},p(L(t)),7),a("span",{class:f(["text-sm font-medium truncate",{"font-bold":!t.read}])},p(t.title),3)]),a("p",Z,p(t.created_at),1)]),a("div",ee,[t.read?C("",!0):(o(),n("button",{key:0,onClick:k(_=>h(t.id),["stop"]),class:"p-1.5 rounded hover:bg-accent text-muted-foreground",title:"Mark as read"},[c(i(G),{class:"w-3.5 h-3.5"})],8,te)),a("button",{onClick:k(_=>$(t.id),["stop"]),class:"p-1.5 rounded hover:bg-destructive/10 text-muted-foreground hover:text-destructive",title:"Delete"},[c(i(E),{class:"w-3.5 h-3.5"})],8,se)])],8,O),u.value===t.id?(o(),n("div",ae,[c(T,{content:t.content},null,8,["content"])])):C("",!0)],2))),128))]))]))}});export{ce as default};
@@ -0,0 +1 @@
1
+ import{k as U,K as q,p as P,r,g as n,d as t,j as d,x as c,H as V,N as T,J as L,M as z,f as x,F as $,t as j,m as p,w as g,s as l,c as E,e as G}from"./index-DfdD_qE4.js";import{b as A,a as J}from"./api-CaqVk-rG.js";import{_ as K}from"./MarkdownContent.vue_vue_type_script_setup_true_lang-CObjuCHH.js";import{S as Q}from"./search-C3fxUixl.js";import{A as R}from"./arrow-left-CkDjCT7Z.js";import{T as I}from"./trash-2-Ba_1SAua.js";const O={class:"flex h-full"},W={class:"p-3 border-b border-border space-y-2"},X={class:"flex items-center gap-2"},Y={class:"relative"},Z={class:"flex gap-2"},ee={class:"flex-1"},te={class:"flex-1"},se={class:"flex-1 overflow-y-auto"},oe={key:0,class:"p-4 text-xs text-muted-foreground"},re={key:1,class:"flex flex-col items-center justify-center h-full p-6 text-center text-muted-foreground"},ne=["onClick"],ae={class:"flex-1 min-w-0"},le={class:"text-xs text-foreground line-clamp-2"},ie={class:"flex items-center gap-2 mt-1"},ue={class:"text-xs text-muted-foreground"},de={class:"text-xs text-muted-foreground"},ce=["onClick"],fe={key:2,class:"p-3 text-center"},ve={key:0,class:"flex-1 flex flex-col"},me={class:"flex items-center gap-2 px-4 py-2 border-b border-border"},xe={class:"text-sm font-medium text-muted-foreground"},pe={class:"flex-1 overflow-y-auto p-4 space-y-4"},ge={key:0,class:"text-center text-xs text-muted-foreground py-8"},he={class:"text-xs mt-1 opacity-60"},ye={key:1,class:"hidden md:flex flex-1 items-center justify-center text-muted-foreground"},be={class:"text-center"},_e=50,Me=U({__name:"HistoryView",setup(we){const a=l([]),h=l(0),y=l(!0),f=l(""),v=l(""),m=l(""),u=l(null),b=l([]),_=l(!1),w=l(0);async function k(o=!0){y.value=!0;try{o&&(w.value=0,a.value=[]);const e=new URLSearchParams;f.value&&e.set("q",f.value),v.value&&e.set("from",v.value),m.value&&e.set("to",m.value+"T23:59:59"),e.set("limit",String(_e)),e.set("offset",String(w.value));const i=await A(`/history?${e.toString()}`);a.value=o?i.items:[...a.value,...i.items],h.value=i.total,w.value+=i.items.length}finally{y.value=!1}}async function B(o){u.value=o,_.value=!0;try{b.value=await A(`/history/${o}`)}finally{_.value=!1}}function D(){u.value=null,b.value=[]}async function N(o,e){e.stopPropagation(),confirm("Delete this conversation?")&&(await J(`/history/${o}`),a.value=a.value.filter(i=>i.id!==o),h.value=Math.max(0,h.value-1),u.value===o&&D())}function C(o){return new Date(o).toLocaleString(void 0,{year:"numeric",month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}function F(o,e=100){return o.length>e?o.slice(0,e)+"…":o}const H=E(()=>a.value.length<h.value);let S=null;return q([f,v,m],()=>{S&&clearTimeout(S),S=setTimeout(()=>k(!0),300)}),P(()=>k(!0)),(o,e)=>{var i;return r(),n("div",O,[t("div",{class:p(["flex flex-col border-r border-border",u.value?"hidden md:flex w-80 shrink-0":"flex-1"])},[t("div",W,[t("div",X,[d(c(V),{class:"w-4 h-4 text-muted-foreground"}),e[4]||(e[4]=t("span",{class:"text-sm font-medium"},"Conversation History",-1))]),t("div",Y,[d(c(Q),{class:"absolute left-2.5 top-2.5 w-3.5 h-3.5 text-muted-foreground"}),T(t("input",{"onUpdate:modelValue":e[0]||(e[0]=s=>f.value=s),placeholder:"Search conversations...",class:"w-full rounded-md border border-input bg-background pl-8 pr-3 py-2 text-xs focus:outline-none focus:ring-1 focus:ring-ring"},null,512),[[L,f.value]])]),t("div",Z,[t("div",ee,[e[5]||(e[5]=t("label",{class:"text-xs text-muted-foreground block mb-1"},"From",-1)),T(t("input",{"onUpdate:modelValue":e[1]||(e[1]=s=>v.value=s),type:"date",class:"w-full rounded-md border border-input bg-background px-2 py-1.5 text-xs focus:outline-none focus:ring-1 focus:ring-ring"},null,512),[[L,v.value]])]),t("div",te,[e[6]||(e[6]=t("label",{class:"text-xs text-muted-foreground block mb-1"},"To",-1)),T(t("input",{"onUpdate:modelValue":e[2]||(e[2]=s=>m.value=s),type:"date",class:"w-full rounded-md border border-input bg-background px-2 py-1.5 text-xs focus:outline-none focus:ring-1 focus:ring-ring"},null,512),[[L,m.value]])])])]),t("div",se,[y.value&&a.value.length===0?(r(),n("div",oe," Loading... ")):a.value.length===0?(r(),n("div",re,[d(c(z),{class:"w-10 h-10 mb-3 opacity-40"}),e[7]||(e[7]=t("p",{class:"text-sm"},"No conversations found.",-1)),e[8]||(e[8]=t("p",{class:"text-xs mt-1"},"Start chatting to build up your history.",-1))])):x("",!0),(r(!0),n($,null,j(a.value,s=>(r(),n("div",{key:s.id,class:p(["group flex items-start gap-2 px-3 py-3 border-b border-border cursor-pointer hover:bg-accent/50 transition-colors",u.value===s.id?"bg-accent":""]),onClick:M=>B(s.id)},[t("div",ae,[t("p",le,g(F(s.preview)),1),t("div",ie,[t("span",ue,g(C(s.updatedAt)),1),t("span",de,"· "+g(s.messageCount)+" msgs",1)])]),t("button",{class:"opacity-0 group-hover:opacity-100 p-1 rounded hover:bg-destructive/10 text-muted-foreground hover:text-destructive transition-all",title:"Delete",onClick:M=>N(s.id,M)},[d(c(I),{class:"w-3.5 h-3.5"})],8,ce)],10,ne))),128)),H.value?(r(),n("div",fe,[t("button",{class:"text-xs text-muted-foreground hover:text-foreground underline",onClick:e[3]||(e[3]=s=>k(!1))}," Load more ")])):x("",!0)])],2),u.value?(r(),n("div",ve,[t("div",me,[t("button",{class:"p-1.5 rounded hover:bg-accent text-muted-foreground",title:"Back",onClick:D},[d(c(R),{class:"w-4 h-4"})]),t("span",xe,g(C(((i=a.value.find(s=>s.id===u.value))==null?void 0:i.startedAt)??"")),1)]),t("div",pe,[_.value?(r(),n("div",ge," Loading... ")):x("",!0),(r(!0),n($,null,j(b.value,s=>(r(),n("div",{key:s.id,class:p(["flex",s.role==="user"?"justify-end":"justify-start"])},[t("div",{class:p(["max-w-[75%] rounded-lg px-4 py-2 text-sm",s.role==="user"?"bg-blue-600 text-white":"bg-muted text-foreground"])},[s.content?(r(),G(K,{key:0,content:s.content,class:p(s.role==="user"?"prose-invert":"")},null,8,["content","class"])):x("",!0),t("p",he,g(C(s.createdAt)),1)],2)],2))),128))])])):u.value?x("",!0):(r(),n("div",ye,[t("div",be,[d(c(V),{class:"w-12 h-12 mx-auto mb-3 opacity-50"}),e[9]||(e[9]=t("p",null,"Select a conversation to view",-1))])]))])}}});export{Me as default};
@@ -0,0 +1 @@
1
+ import{k as b,y as v,r as u,g as i,d as t,j as y,Q as w,N as m,J as p,w as f,f as _,x as g,s as d,_ as h,D as S}from"./index-DfdD_qE4.js";const V={class:"min-h-screen flex items-center justify-center bg-background p-4"},k={class:"w-full max-w-sm space-y-8"},D={class:"text-center"},N={key:0,class:"text-sm text-destructive"},A=["disabled"],L=b({__name:"LoginView",setup(B){const o=v(),c=S(),r=d(""),n=d(""),s=d("");async function x(){s.value="";try{await o.login(r.value,n.value),c.push("/")}catch(l){s.value=l.message??"Login failed"}}return(l,e)=>(u(),i("div",V,[t("div",k,[t("div",D,[y(h,{size:56,class:"mx-auto mb-4"}),e[2]||(e[2]=t("h1",{class:"text-2xl font-bold bg-gradient-brand bg-clip-text text-transparent"}," IO ",-1)),e[3]||(e[3]=t("p",{class:"text-sm text-muted-foreground mt-1"},"Sign in to your dashboard",-1))]),t("form",{onSubmit:w(x,["prevent"]),class:"space-y-4 bg-card border border-border rounded-lg p-6"},[t("div",null,[e[4]||(e[4]=t("label",{class:"text-sm font-medium text-muted-foreground",for:"email"},"Email",-1)),m(t("input",{id:"email","onUpdate:modelValue":e[0]||(e[0]=a=>r.value=a),type:"email",required:"",class:"mt-1 w-full rounded-md border border-border bg-input px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring",placeholder:"you@example.com"},null,512),[[p,r.value]])]),t("div",null,[e[5]||(e[5]=t("label",{class:"text-sm font-medium text-muted-foreground",for:"password"},"Password",-1)),m(t("input",{id:"password","onUpdate:modelValue":e[1]||(e[1]=a=>n.value=a),type:"password",required:"",class:"mt-1 w-full rounded-md border border-border bg-input px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring",placeholder:"••••••••"},null,512),[[p,n.value]])]),s.value?(u(),i("div",N,f(s.value),1)):_("",!0),t("button",{type:"submit",disabled:g(o).loading,class:"btn-gradient w-full py-2.5"},f(g(o).loading?"Signing in...":"Sign In"),9,A)],32),e[6]||(e[6]=t("p",{class:"text-center text-xs text-muted-foreground"}," Personal AI Assistant Daemon ",-1))])]))}});export{L as default};
@@ -1,4 +1,4 @@
1
- var me=Object.defineProperty;var we=(n,e,t)=>e in n?me(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var d=(n,e,t)=>we(n,typeof e!="symbol"?e+"":e,t);import{i as ye,m as Re,e as Se,c as $e}from"./index-BQdXxKfc.js";function j(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}var $=j();function ae(n){$=n}var z={exec:()=>null};function u(n,e=""){let t=typeof n=="string"?n:n.source;const r={replace:(s,i)=>{let c=typeof i=="string"?i:i.source;return c=c.replace(b.caret,"$1"),t=t.replace(s,c),r},getRegex:()=>new RegExp(t,e)};return r}var b={codeRemoveIndent:/^(?: {1,4}| {0,3}\t)/gm,outputLinkReplace:/\\([\[\]])/g,indentCodeCompensation:/^(\s+)(?:```)/,beginningSpace:/^\s+/,endingHash:/#$/,startingSpaceChar:/^ /,endingSpaceChar:/ $/,nonSpaceChar:/[^ ]/,newLineCharGlobal:/\n/g,tabCharGlobal:/\t/g,multipleSpaceGlobal:/\s+/g,blankLine:/^[ \t]*$/,doubleBlankLine:/\n[ \t]*\n[ \t]*$/,blockquoteStart:/^ {0,3}>/,blockquoteSetextReplace:/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,blockquoteSetextReplace2:/^ {0,3}>[ \t]?/gm,listReplaceTabs:/^\t+/,listReplaceNesting:/^ {1,4}(?=( {4})*[^ ])/g,listIsTask:/^\[[ xX]\] /,listReplaceTask:/^\[[ xX]\] +/,anyLine:/\n.*\n/,hrefBrackets:/^<(.*)>$/,tableDelimiter:/[:|]/,tableAlignChars:/^\||\| *$/g,tableRowBlankLine:/\n[ \t]*$/,tableAlignRight:/^ *-+: *$/,tableAlignCenter:/^ *:-+: *$/,tableAlignLeft:/^ *:-+ *$/,startATag:/^<a /i,endATag:/^<\/a>/i,startPreScriptTag:/^<(pre|code|kbd|script)(\s|>)/i,endPreScriptTag:/^<\/(pre|code|kbd|script)(\s|>)/i,startAngleBracket:/^</,endAngleBracket:/>$/,pedanticHrefTitle:/^([^'"]*[^\s])\s+(['"])(.*)\2/,unicodeAlphaNumeric:/[\p{L}\p{N}]/u,escapeTest:/[&<>"']/,escapeReplace:/[&<>"']/g,escapeTestNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,escapeReplaceNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g,unescapeTest:/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig,caret:/(^|[^\[])\^/g,percentDecode:/%25/g,findPipe:/\|/g,splitPipe:/ \|/,slashPipe:/\\\|/g,carriageReturn:/\r\n|\r/g,spaceLine:/^ +$/gm,notSpaceStart:/^\S*/,endingNewline:/\n$/,listItemRegex:n=>new RegExp(`^( {0,3}${n})((?:[ ][^\\n]*)?(?:\\n|$))`),nextBulletRegex:n=>new RegExp(`^ {0,${Math.min(3,n-1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`),hrRegex:n=>new RegExp(`^ {0,${Math.min(3,n-1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),fencesBeginRegex:n=>new RegExp(`^ {0,${Math.min(3,n-1)}}(?:\`\`\`|~~~)`),headingBeginRegex:n=>new RegExp(`^ {0,${Math.min(3,n-1)}}#`),htmlBeginRegex:n=>new RegExp(`^ {0,${Math.min(3,n-1)}}<(?:[a-z].*>|!--)`,"i")},ve=/^(?:[ \t]*(?:\n|$))+/,Te=/^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/,_e=/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,A=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,ze=/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,H=/(?:[*+-]|\d{1,9}[.)])/,oe=/^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\n {0,3}(=+|-+) *(?:\n+|$)/,ce=u(oe).replace(/bull/g,H).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/\|table/g,"").getRegex(),Ae=u(oe).replace(/bull/g,H).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/table/g,/ {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex(),Q=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,Le=/^[^\n]+/,F=/(?!\s*\])(?:\\.|[^\[\]\\])+/,Ce=u(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label",F).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),Ie=u(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g,H).getRegex(),E="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",U=/<!--(?:-?>|[\s\S]*?(?:-->|$))/,Pe=u("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|<![A-Z][\\s\\S]*?(?:>\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$))","i").replace("comment",U).replace("tag",E).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),he=u(Q).replace("hr",A).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",E).getRegex(),Be=u(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",he).getRegex(),X={blockquote:Be,code:Te,def:Ce,fences:_e,heading:ze,hr:A,html:Pe,lheading:ce,list:Ie,newline:ve,paragraph:he,table:z,text:Le},ne=u("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr",A).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("blockquote"," {0,3}>").replace("code","(?: {4}| {0,3} )[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",E).getRegex(),Ee={...X,lheading:Ae,table:ne,paragraph:u(Q).replace("hr",A).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("table",ne).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",E).getRegex()},qe={...X,html:u(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:"[^"]*"|'[^']*'|\\s[^'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace("comment",U).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:z,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:u(Q).replace("hr",A).replace("heading",` *#{1,6} *[^
1
+ var me=Object.defineProperty;var we=(n,e,t)=>e in n?me(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var d=(n,e,t)=>we(n,typeof e!="symbol"?e+"":e,t);import{k as ye,r as Re,g as Se,c as $e}from"./index-DfdD_qE4.js";function j(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}var $=j();function ae(n){$=n}var z={exec:()=>null};function u(n,e=""){let t=typeof n=="string"?n:n.source;const r={replace:(s,i)=>{let c=typeof i=="string"?i:i.source;return c=c.replace(b.caret,"$1"),t=t.replace(s,c),r},getRegex:()=>new RegExp(t,e)};return r}var b={codeRemoveIndent:/^(?: {1,4}| {0,3}\t)/gm,outputLinkReplace:/\\([\[\]])/g,indentCodeCompensation:/^(\s+)(?:```)/,beginningSpace:/^\s+/,endingHash:/#$/,startingSpaceChar:/^ /,endingSpaceChar:/ $/,nonSpaceChar:/[^ ]/,newLineCharGlobal:/\n/g,tabCharGlobal:/\t/g,multipleSpaceGlobal:/\s+/g,blankLine:/^[ \t]*$/,doubleBlankLine:/\n[ \t]*\n[ \t]*$/,blockquoteStart:/^ {0,3}>/,blockquoteSetextReplace:/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,blockquoteSetextReplace2:/^ {0,3}>[ \t]?/gm,listReplaceTabs:/^\t+/,listReplaceNesting:/^ {1,4}(?=( {4})*[^ ])/g,listIsTask:/^\[[ xX]\] /,listReplaceTask:/^\[[ xX]\] +/,anyLine:/\n.*\n/,hrefBrackets:/^<(.*)>$/,tableDelimiter:/[:|]/,tableAlignChars:/^\||\| *$/g,tableRowBlankLine:/\n[ \t]*$/,tableAlignRight:/^ *-+: *$/,tableAlignCenter:/^ *:-+: *$/,tableAlignLeft:/^ *:-+ *$/,startATag:/^<a /i,endATag:/^<\/a>/i,startPreScriptTag:/^<(pre|code|kbd|script)(\s|>)/i,endPreScriptTag:/^<\/(pre|code|kbd|script)(\s|>)/i,startAngleBracket:/^</,endAngleBracket:/>$/,pedanticHrefTitle:/^([^'"]*[^\s])\s+(['"])(.*)\2/,unicodeAlphaNumeric:/[\p{L}\p{N}]/u,escapeTest:/[&<>"']/,escapeReplace:/[&<>"']/g,escapeTestNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,escapeReplaceNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g,unescapeTest:/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig,caret:/(^|[^\[])\^/g,percentDecode:/%25/g,findPipe:/\|/g,splitPipe:/ \|/,slashPipe:/\\\|/g,carriageReturn:/\r\n|\r/g,spaceLine:/^ +$/gm,notSpaceStart:/^\S*/,endingNewline:/\n$/,listItemRegex:n=>new RegExp(`^( {0,3}${n})((?:[ ][^\\n]*)?(?:\\n|$))`),nextBulletRegex:n=>new RegExp(`^ {0,${Math.min(3,n-1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`),hrRegex:n=>new RegExp(`^ {0,${Math.min(3,n-1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),fencesBeginRegex:n=>new RegExp(`^ {0,${Math.min(3,n-1)}}(?:\`\`\`|~~~)`),headingBeginRegex:n=>new RegExp(`^ {0,${Math.min(3,n-1)}}#`),htmlBeginRegex:n=>new RegExp(`^ {0,${Math.min(3,n-1)}}<(?:[a-z].*>|!--)`,"i")},ve=/^(?:[ \t]*(?:\n|$))+/,Te=/^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/,_e=/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,A=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,ze=/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,H=/(?:[*+-]|\d{1,9}[.)])/,oe=/^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\n {0,3}(=+|-+) *(?:\n+|$)/,ce=u(oe).replace(/bull/g,H).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/\|table/g,"").getRegex(),Ae=u(oe).replace(/bull/g,H).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/table/g,/ {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex(),Q=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,Le=/^[^\n]+/,F=/(?!\s*\])(?:\\.|[^\[\]\\])+/,Ce=u(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label",F).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),Ie=u(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g,H).getRegex(),E="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",U=/<!--(?:-?>|[\s\S]*?(?:-->|$))/,Pe=u("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|<![A-Z][\\s\\S]*?(?:>\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$))","i").replace("comment",U).replace("tag",E).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),he=u(Q).replace("hr",A).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",E).getRegex(),Be=u(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",he).getRegex(),X={blockquote:Be,code:Te,def:Ce,fences:_e,heading:ze,hr:A,html:Pe,lheading:ce,list:Ie,newline:ve,paragraph:he,table:z,text:Le},ne=u("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr",A).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("blockquote"," {0,3}>").replace("code","(?: {4}| {0,3} )[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",E).getRegex(),Ee={...X,lheading:Ae,table:ne,paragraph:u(Q).replace("hr",A).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("table",ne).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",E).getRegex()},qe={...X,html:u(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:"[^"]*"|'[^']*'|\\s[^'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace("comment",U).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:z,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:u(Q).replace("hr",A).replace("heading",` *#{1,6} *[^
2
2
  ]`).replace("lheading",ce).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},Ze=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,De=/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,pe=/^( {2,}|\\)\n(?!\s*$)/,Me=/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,q=/[\p{P}\p{S}]/u,W=/[\s\p{P}\p{S}]/u,ue=/[^\s\p{P}\p{S}]/u,Ge=u(/^((?![*_])punctSpace)/,"u").replace(/punctSpace/g,W).getRegex(),ge=/(?!~)[\p{P}\p{S}]/u,Oe=/(?!~)[\s\p{P}\p{S}]/u,Ne=/(?:[^\s\p{P}\p{S}]|~)/u,je=/\[[^[\]]*?\]\((?:\\.|[^\\\(\)]|\((?:\\.|[^\\\(\)])*\))*\)|`[^`]*?`|<[^<>]*?>/g,fe=/^(?:\*+(?:((?!\*)punct)|[^\s*]))|^_+(?:((?!_)punct)|([^\s_]))/,He=u(fe,"u").replace(/punct/g,q).getRegex(),Qe=u(fe,"u").replace(/punct/g,ge).getRegex(),de="^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)",Fe=u(de,"gu").replace(/notPunctSpace/g,ue).replace(/punctSpace/g,W).replace(/punct/g,q).getRegex(),Ue=u(de,"gu").replace(/notPunctSpace/g,Ne).replace(/punctSpace/g,Oe).replace(/punct/g,ge).getRegex(),Xe=u("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)","gu").replace(/notPunctSpace/g,ue).replace(/punctSpace/g,W).replace(/punct/g,q).getRegex(),We=u(/\\(punct)/,"gu").replace(/punct/g,q).getRegex(),Je=u(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme",/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email",/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),Ke=u(U).replace("(?:-->|$)","-->").getRegex(),Ve=u("^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>").replace("comment",Ke).replace("attribute",/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),I=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,Ye=u(/^!?\[(label)\]\(\s*(href)(?:(?:[ \t]*(?:\n[ \t]*)?)(title))?\s*\)/).replace("label",I).replace("href",/<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]*/).replace("title",/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),ke=u(/^!?\[(label)\]\[(ref)\]/).replace("label",I).replace("ref",F).getRegex(),xe=u(/^!?\[(ref)\](?:\[\])?/).replace("ref",F).getRegex(),et=u("reflink|nolink(?!\\()","g").replace("reflink",ke).replace("nolink",xe).getRegex(),J={_backpedal:z,anyPunctuation:We,autolink:Je,blockSkip:je,br:pe,code:De,del:z,emStrongLDelim:He,emStrongRDelimAst:Fe,emStrongRDelimUnd:Xe,escape:Ze,link:Ye,nolink:xe,punctuation:Ge,reflink:ke,reflinkSearch:et,tag:Ve,text:Me,url:z},tt={...J,link:u(/^!?\[(label)\]\((.*?)\)/).replace("label",I).getRegex(),reflink:u(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",I).getRegex()},G={...J,emStrongRDelimAst:Ue,emStrongLDelim:Qe,url:u(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,"i").replace("email",/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(),_backpedal:/(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])((?:\\.|[^\\])*?(?:\\.|[^\s~\\]))\1(?=[^~]|$)/,text:/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/},nt={...G,br:u(pe).replace("{2,}","*").getRegex(),text:u(G.text).replace("\\b_","\\b_| {2,}\\n").replace(/\{2,\}/g,"*").getRegex()},L={normal:X,gfm:Ee,pedantic:qe},T={normal:J,gfm:G,breaks:nt,pedantic:tt},rt={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},re=n=>rt[n];function w(n,e){if(e){if(b.escapeTest.test(n))return n.replace(b.escapeReplace,re)}else if(b.escapeTestNoEncode.test(n))return n.replace(b.escapeReplaceNoEncode,re);return n}function se(n){try{n=encodeURI(n).replace(b.percentDecode,"%")}catch{return null}return n}function ie(n,e){var i;const t=n.replace(b.findPipe,(c,l,h)=>{let a=!1,o=l;for(;--o>=0&&h[o]==="\\";)a=!a;return a?"|":" |"}),r=t.split(b.splitPipe);let s=0;if(r[0].trim()||r.shift(),r.length>0&&!((i=r.at(-1))!=null&&i.trim())&&r.pop(),e)if(r.length>e)r.splice(e);else for(;r.length<e;)r.push("");for(;s<r.length;s++)r[s]=r[s].trim().replace(b.slashPipe,"|");return r}function _(n,e,t){const r=n.length;if(r===0)return"";let s=0;for(;s<r&&n.charAt(r-s-1)===e;)s++;return n.slice(0,r-s)}function st(n,e){if(n.indexOf(e[1])===-1)return-1;let t=0;for(let r=0;r<n.length;r++)if(n[r]==="\\")r++;else if(n[r]===e[0])t++;else if(n[r]===e[1]&&(t--,t<0))return r;return t>0?-2:-1}function le(n,e,t,r,s){const i=e.href,c=e.title||null,l=n[1].replace(s.other.outputLinkReplace,"$1");r.state.inLink=!0;const h={type:n[0].charAt(0)==="!"?"image":"link",raw:t,href:i,title:c,text:l,tokens:r.inlineTokens(l)};return r.state.inLink=!1,h}function it(n,e,t){const r=n.match(t.other.indentCodeCompensation);if(r===null)return e;const s=r[1];return e.split(`
3
3
  `).map(i=>{const c=i.match(t.other.beginningSpace);if(c===null)return i;const[l]=c;return l.length>=s.length?i.slice(s.length):i}).join(`
4
4
  `)}var P=class{constructor(n){d(this,"options");d(this,"rules");d(this,"lexer");this.options=n||$}space(n){const e=this.rules.block.newline.exec(n);if(e&&e[0].length>0)return{type:"space",raw:e[0]}}code(n){const e=this.rules.block.code.exec(n);if(e){const t=e[0].replace(this.rules.other.codeRemoveIndent,"");return{type:"code",raw:e[0],codeBlockStyle:"indented",text:this.options.pedantic?t:_(t,`
@@ -0,0 +1 @@
1
+ import{k,p as C,r as a,g as n,d as t,j as m,x as p,i as S,N as u,J as v,G as h,f as _,S as V,F as N,t as M,s as i,w as b,m as y}from"./index-DfdD_qE4.js";import{b as P,c as T,d as U,a as $}from"./api-CaqVk-rG.js";import{P as j}from"./plus-GvGwcjX5.js";import{T as B}from"./trash-2-Ba_1SAua.js";const D={class:"p-6"},L={class:"flex items-center justify-between mb-6"},A={key:0,class:"border border-border rounded-lg p-4 mb-6 space-y-3"},F={class:"grid grid-cols-2 gap-3"},G={key:0},z={key:1},E={key:1,class:"text-muted-foreground"},J={key:2,class:"text-center py-12 text-muted-foreground"},R={key:3,class:"space-y-2"},q={class:"font-medium text-sm"},H={class:"ml-2 text-xs text-muted-foreground bg-secondary px-1.5 py-0.5 rounded"},I={class:"flex items-center gap-3"},K=["onClick"],O=["onClick"],ee=k({__name:"McpView",setup(Q){const d=i([]),c=i(!0),r=i(!1),o=i({name:"",type:"stdio",command:"",url:""});C(async()=>{try{d.value=await P("/mcp")}finally{c.value=!1}});async function f(l){await U(`/mcp/${l.id}`,{enabled:!l.enabled}),l.enabled=!l.enabled}async function x(l){await $(`/mcp/${l}`),d.value=d.value.filter(e=>e.id!==l)}async function g(){const l={name:o.value.name,type:o.value.type};o.value.type==="stdio"?l.command=o.value.command:l.url=o.value.url;const e=await T("/mcp",l);d.value.push(e),r.value=!1,o.value={name:"",type:"stdio",command:"",url:""}}return(l,e)=>(a(),n("div",D,[t("div",L,[e[6]||(e[6]=t("h1",{class:"text-2xl font-bold"},"MCP Servers",-1)),t("button",{onClick:e[0]||(e[0]=s=>r.value=!r.value),class:"inline-flex items-center gap-1 px-3 py-1.5 text-sm rounded-md bg-primary text-primary-foreground hover:bg-primary/90 transition-colors"},[m(p(j),{class:"w-4 h-4"}),e[5]||(e[5]=S(" Add Server ",-1))])]),r.value?(a(),n("div",A,[t("div",F,[t("div",null,[e[7]||(e[7]=t("label",{class:"text-sm font-medium"},"Name",-1)),u(t("input",{"onUpdate:modelValue":e[1]||(e[1]=s=>o.value.name=s),class:"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"},null,512),[[v,o.value.name]])]),t("div",null,[e[9]||(e[9]=t("label",{class:"text-sm font-medium"},"Type",-1)),u(t("select",{"onUpdate:modelValue":e[2]||(e[2]=s=>o.value.type=s),class:"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"},[...e[8]||(e[8]=[t("option",{value:"stdio"},"stdio",-1),t("option",{value:"http"},"http",-1)])],512),[[h,o.value.type]])])]),o.value.type==="stdio"?(a(),n("div",G,[e[10]||(e[10]=t("label",{class:"text-sm font-medium"},"Command",-1)),u(t("input",{"onUpdate:modelValue":e[3]||(e[3]=s=>o.value.command=s),placeholder:"npx @my/mcp-server",class:"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"},null,512),[[v,o.value.command]])])):(a(),n("div",z,[e[11]||(e[11]=t("label",{class:"text-sm font-medium"},"URL",-1)),u(t("input",{"onUpdate:modelValue":e[4]||(e[4]=s=>o.value.url=s),placeholder:"https://...",class:"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"},null,512),[[v,o.value.url]])])),t("button",{onClick:g,class:"px-4 py-2 text-sm rounded-md bg-primary text-primary-foreground hover:bg-primary/90"},"Save")])):_("",!0),c.value?(a(),n("div",E,"Loading...")):d.value.length===0?(a(),n("div",J,[m(p(V),{class:"w-12 h-12 mx-auto mb-3 opacity-50"}),e[12]||(e[12]=t("p",null,"No MCP servers configured.",-1))])):(a(),n("div",R,[(a(!0),n(N,null,M(d.value,s=>(a(),n("div",{key:s.id,class:"flex items-center justify-between border border-border rounded-lg px-4 py-3"},[t("div",null,[t("span",q,b(s.name),1),t("span",H,b(s.type),1)]),t("div",I,[t("button",{onClick:w=>f(s),class:y(["relative w-10 h-5 rounded-full transition-colors",s.enabled?"bg-primary":"bg-muted"])},[t("span",{class:y(["absolute top-0.5 w-4 h-4 rounded-full bg-white transition-transform",s.enabled?"translate-x-5":"translate-x-0.5"])},null,2)],10,K),t("button",{onClick:w=>x(s.id),class:"p-1.5 rounded hover:bg-destructive/10 text-muted-foreground hover:text-destructive"},[m(p(B),{class:"w-4 h-4"})],8,O)])]))),128))]))]))}});export{ee as default};