verybot 0.1.3

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.

Potentially problematic release.


This version of verybot might be problematic. Click here for more details.

Files changed (244) hide show
  1. package/dist/brain/agent-registry.d.ts +75 -0
  2. package/dist/brain/agent-registry.js +124 -0
  3. package/dist/brain/agent.d.ts +146 -0
  4. package/dist/brain/agent.js +680 -0
  5. package/dist/brain/channel-store.d.ts +27 -0
  6. package/dist/brain/channel-store.js +78 -0
  7. package/dist/brain/compaction.d.ts +37 -0
  8. package/dist/brain/compaction.js +214 -0
  9. package/dist/brain/context.d.ts +33 -0
  10. package/dist/brain/context.js +77 -0
  11. package/dist/brain/delegation-store.d.ts +33 -0
  12. package/dist/brain/delegation-store.js +106 -0
  13. package/dist/brain/loop.d.ts +21 -0
  14. package/dist/brain/loop.js +161 -0
  15. package/dist/brain/mcp-adapter.d.ts +39 -0
  16. package/dist/brain/mcp-adapter.js +227 -0
  17. package/dist/brain/memory-extractor.d.ts +26 -0
  18. package/dist/brain/memory-extractor.js +82 -0
  19. package/dist/brain/providers.d.ts +10 -0
  20. package/dist/brain/providers.js +69 -0
  21. package/dist/brain/queue.d.ts +18 -0
  22. package/dist/brain/queue.js +84 -0
  23. package/dist/brain/run-tools.d.ts +47 -0
  24. package/dist/brain/run-tools.js +84 -0
  25. package/dist/brain/session-key.d.ts +23 -0
  26. package/dist/brain/session-key.js +41 -0
  27. package/dist/brain/session-state.d.ts +36 -0
  28. package/dist/brain/session-state.js +51 -0
  29. package/dist/brain/session-store.d.ts +50 -0
  30. package/dist/brain/session-store.js +207 -0
  31. package/dist/brain/session.d.ts +32 -0
  32. package/dist/brain/session.js +75 -0
  33. package/dist/brain/utils.d.ts +4 -0
  34. package/dist/brain/utils.js +26 -0
  35. package/dist/brain/worker-coordinator.d.ts +25 -0
  36. package/dist/brain/worker-coordinator.js +83 -0
  37. package/dist/channels/commands.d.ts +35 -0
  38. package/dist/channels/commands.js +65 -0
  39. package/dist/channels/discord/channel.d.ts +18 -0
  40. package/dist/channels/discord/channel.js +154 -0
  41. package/dist/channels/discord/markdown.d.ts +19 -0
  42. package/dist/channels/discord/markdown.js +62 -0
  43. package/dist/channels/manager.d.ts +29 -0
  44. package/dist/channels/manager.js +100 -0
  45. package/dist/channels/slack/channel.d.ts +26 -0
  46. package/dist/channels/slack/channel.js +207 -0
  47. package/dist/channels/slack/markdown.d.ts +19 -0
  48. package/dist/channels/slack/markdown.js +62 -0
  49. package/dist/channels/specs.d.ts +21 -0
  50. package/dist/channels/specs.js +96 -0
  51. package/dist/channels/telegram/channel.d.ts +18 -0
  52. package/dist/channels/telegram/channel.js +156 -0
  53. package/dist/channels/telegram/markdown.d.ts +17 -0
  54. package/dist/channels/telegram/markdown.js +66 -0
  55. package/dist/channels/types.d.ts +26 -0
  56. package/dist/channels/types.js +1 -0
  57. package/dist/channels/whatsapp/channel.d.ts +23 -0
  58. package/dist/channels/whatsapp/channel.js +242 -0
  59. package/dist/channels/whatsapp/markdown.d.ts +20 -0
  60. package/dist/channels/whatsapp/markdown.js +51 -0
  61. package/dist/cli/config.d.ts +5 -0
  62. package/dist/cli/config.js +78 -0
  63. package/dist/cli/index.d.ts +5 -0
  64. package/dist/cli/index.js +13 -0
  65. package/dist/computer/browser/actions.d.ts +31 -0
  66. package/dist/computer/browser/actions.js +148 -0
  67. package/dist/computer/browser/manager.d.ts +55 -0
  68. package/dist/computer/browser/manager.js +496 -0
  69. package/dist/computer/browser/profile-badge.d.ts +13 -0
  70. package/dist/computer/browser/profile-badge.js +67 -0
  71. package/dist/computer/browser/screenshot.d.ts +5 -0
  72. package/dist/computer/browser/screenshot.js +21 -0
  73. package/dist/computer/browser/snapshot.d.ts +30 -0
  74. package/dist/computer/browser/snapshot.js +242 -0
  75. package/dist/computer/browser/tools.d.ts +5 -0
  76. package/dist/computer/browser/tools.js +167 -0
  77. package/dist/computer/desktop/adapter.d.ts +25 -0
  78. package/dist/computer/desktop/adapter.js +11 -0
  79. package/dist/computer/desktop/macos.d.ts +24 -0
  80. package/dist/computer/desktop/macos.js +223 -0
  81. package/dist/computer/desktop/tools.d.ts +25 -0
  82. package/dist/computer/desktop/tools.js +114 -0
  83. package/dist/config/agent-config.d.ts +41 -0
  84. package/dist/config/agent-config.js +14 -0
  85. package/dist/config/model-catalog.d.ts +22 -0
  86. package/dist/config/model-catalog.js +99 -0
  87. package/dist/config/store.d.ts +25 -0
  88. package/dist/config/store.js +143 -0
  89. package/dist/config.d.ts +103 -0
  90. package/dist/config.js +224 -0
  91. package/dist/control-ui/assets/index-BANXNUyt.js +143 -0
  92. package/dist/control-ui/assets/index-BSUFrP9R.css +1 -0
  93. package/dist/control-ui/assets/noto-sans-cyrillic-ext-wght-normal-DSNfmdVt.woff2 +0 -0
  94. package/dist/control-ui/assets/noto-sans-cyrillic-wght-normal-B2hlT84T.woff2 +0 -0
  95. package/dist/control-ui/assets/noto-sans-devanagari-wght-normal-Cv-Vwajv.woff2 +0 -0
  96. package/dist/control-ui/assets/noto-sans-greek-ext-wght-normal-12T8GTDR.woff2 +0 -0
  97. package/dist/control-ui/assets/noto-sans-greek-wght-normal-Ymb6dZNd.woff2 +0 -0
  98. package/dist/control-ui/assets/noto-sans-latin-ext-wght-normal-W1qJv59z.woff2 +0 -0
  99. package/dist/control-ui/assets/noto-sans-latin-wght-normal-BYSzYMf3.woff2 +0 -0
  100. package/dist/control-ui/assets/noto-sans-vietnamese-wght-normal-DLTJy58D.woff2 +0 -0
  101. package/dist/control-ui/index.html +14 -0
  102. package/dist/control-ui/vite.svg +1 -0
  103. package/dist/events.d.ts +2 -0
  104. package/dist/events.js +11 -0
  105. package/dist/gateway/broadcast.d.ts +5 -0
  106. package/dist/gateway/broadcast.js +33 -0
  107. package/dist/gateway/methods/chat.d.ts +24 -0
  108. package/dist/gateway/methods/chat.js +19 -0
  109. package/dist/gateway/methods/config.d.ts +13 -0
  110. package/dist/gateway/methods/config.js +14 -0
  111. package/dist/gateway/methods/models.d.ts +10 -0
  112. package/dist/gateway/methods/models.js +14 -0
  113. package/dist/gateway/methods/prompt-templates.d.ts +23 -0
  114. package/dist/gateway/methods/prompt-templates.js +82 -0
  115. package/dist/gateway/methods/scheduler.d.ts +62 -0
  116. package/dist/gateway/methods/scheduler.js +129 -0
  117. package/dist/gateway/methods/sessions.d.ts +26 -0
  118. package/dist/gateway/methods/sessions.js +54 -0
  119. package/dist/gateway/methods/skills.d.ts +35 -0
  120. package/dist/gateway/methods/skills.js +202 -0
  121. package/dist/gateway/methods/system.d.ts +12 -0
  122. package/dist/gateway/methods/system.js +39 -0
  123. package/dist/gateway/methods/tasks.d.ts +21 -0
  124. package/dist/gateway/methods/tasks.js +46 -0
  125. package/dist/gateway/methods/teams.d.ts +70 -0
  126. package/dist/gateway/methods/teams.js +374 -0
  127. package/dist/gateway/methods/tools.d.ts +6 -0
  128. package/dist/gateway/methods/tools.js +7 -0
  129. package/dist/gateway/methods/whatsapp.d.ts +19 -0
  130. package/dist/gateway/methods/whatsapp.js +35 -0
  131. package/dist/gateway/rpc.d.ts +38 -0
  132. package/dist/gateway/rpc.js +75 -0
  133. package/dist/gateway/server.d.ts +4 -0
  134. package/dist/gateway/server.js +133 -0
  135. package/dist/index.d.ts +1 -0
  136. package/dist/index.js +212 -0
  137. package/dist/integrations/github.d.ts +7 -0
  138. package/dist/integrations/github.js +133 -0
  139. package/dist/integrations/mcp.d.ts +7 -0
  140. package/dist/integrations/mcp.js +106 -0
  141. package/dist/integrations/registry.d.ts +43 -0
  142. package/dist/integrations/registry.js +258 -0
  143. package/dist/integrations/scanner.d.ts +10 -0
  144. package/dist/integrations/scanner.js +122 -0
  145. package/dist/integrations/twitter.d.ts +10 -0
  146. package/dist/integrations/twitter.js +120 -0
  147. package/dist/integrations/types.d.ts +72 -0
  148. package/dist/integrations/types.js +1 -0
  149. package/dist/logger.d.ts +16 -0
  150. package/dist/logger.js +104 -0
  151. package/dist/markdown/chunk.d.ts +9 -0
  152. package/dist/markdown/chunk.js +52 -0
  153. package/dist/markdown/ir.d.ts +37 -0
  154. package/dist/markdown/ir.js +529 -0
  155. package/dist/markdown/render.d.ts +22 -0
  156. package/dist/markdown/render.js +148 -0
  157. package/dist/markdown/table-render.d.ts +43 -0
  158. package/dist/markdown/table-render.js +219 -0
  159. package/dist/markdown/tables.d.ts +17 -0
  160. package/dist/markdown/tables.js +27 -0
  161. package/dist/memory/embedding.d.ts +16 -0
  162. package/dist/memory/embedding.js +66 -0
  163. package/dist/memory/extractor.d.ts +6 -0
  164. package/dist/memory/extractor.js +72 -0
  165. package/dist/memory/search.d.ts +15 -0
  166. package/dist/memory/search.js +57 -0
  167. package/dist/memory/store.d.ts +34 -0
  168. package/dist/memory/store.js +328 -0
  169. package/dist/memory/types.d.ts +9 -0
  170. package/dist/memory/types.js +2 -0
  171. package/dist/paths.d.ts +20 -0
  172. package/dist/paths.js +29 -0
  173. package/dist/prompt-templates/builtins.d.ts +2 -0
  174. package/dist/prompt-templates/builtins.js +72 -0
  175. package/dist/prompt-templates/store.d.ts +39 -0
  176. package/dist/prompt-templates/store.js +174 -0
  177. package/dist/prompt-templates/types.d.ts +10 -0
  178. package/dist/prompt-templates/types.js +1 -0
  179. package/dist/scheduler/connected-channels.d.ts +24 -0
  180. package/dist/scheduler/connected-channels.js +57 -0
  181. package/dist/scheduler/scheduler.d.ts +22 -0
  182. package/dist/scheduler/scheduler.js +132 -0
  183. package/dist/scheduler/store.d.ts +27 -0
  184. package/dist/scheduler/store.js +205 -0
  185. package/dist/scheduler/types.d.ts +29 -0
  186. package/dist/scheduler/types.js +1 -0
  187. package/dist/security/command-validator.d.ts +22 -0
  188. package/dist/security/command-validator.js +160 -0
  189. package/dist/security/docker-sandbox.d.ts +48 -0
  190. package/dist/security/docker-sandbox.js +218 -0
  191. package/dist/security/env-filter.d.ts +8 -0
  192. package/dist/security/env-filter.js +41 -0
  193. package/dist/skills/loader.d.ts +33 -0
  194. package/dist/skills/loader.js +132 -0
  195. package/dist/skills/prompt.d.ts +6 -0
  196. package/dist/skills/prompt.js +17 -0
  197. package/dist/skills/read-tool.d.ts +7 -0
  198. package/dist/skills/read-tool.js +24 -0
  199. package/dist/skills/scanner.d.ts +6 -0
  200. package/dist/skills/scanner.js +73 -0
  201. package/dist/skills/types.d.ts +15 -0
  202. package/dist/skills/types.js +1 -0
  203. package/dist/tasks/store.d.ts +47 -0
  204. package/dist/tasks/store.js +193 -0
  205. package/dist/tasks/types.d.ts +75 -0
  206. package/dist/tasks/types.js +32 -0
  207. package/dist/teams/store.d.ts +78 -0
  208. package/dist/teams/store.js +420 -0
  209. package/dist/teams/types.d.ts +23 -0
  210. package/dist/teams/types.js +1 -0
  211. package/dist/tools/bash.d.ts +16 -0
  212. package/dist/tools/bash.js +62 -0
  213. package/dist/tools/channel-history.d.ts +10 -0
  214. package/dist/tools/channel-history.js +43 -0
  215. package/dist/tools/delegate.d.ts +16 -0
  216. package/dist/tools/delegate.js +216 -0
  217. package/dist/tools/fs.d.ts +4 -0
  218. package/dist/tools/fs.js +335 -0
  219. package/dist/tools/integration-toggle.d.ts +14 -0
  220. package/dist/tools/integration-toggle.js +47 -0
  221. package/dist/tools/memory.d.ts +13 -0
  222. package/dist/tools/memory.js +65 -0
  223. package/dist/tools/registry.d.ts +6 -0
  224. package/dist/tools/registry.js +9 -0
  225. package/dist/tools/schedule.d.ts +8 -0
  226. package/dist/tools/schedule.js +219 -0
  227. package/dist/tools/speak.d.ts +10 -0
  228. package/dist/tools/speak.js +56 -0
  229. package/dist/tools/tasks.d.ts +29 -0
  230. package/dist/tools/tasks.js +92 -0
  231. package/dist/tools/teams.d.ts +7 -0
  232. package/dist/tools/teams.js +180 -0
  233. package/dist/tools/web-fetch.d.ts +3 -0
  234. package/dist/tools/web-fetch.js +22 -0
  235. package/dist/tts/edge.d.ts +10 -0
  236. package/dist/tts/edge.js +60 -0
  237. package/dist/tts/speak.d.ts +12 -0
  238. package/dist/tts/speak.js +81 -0
  239. package/dist/tts/transcribe.d.ts +5 -0
  240. package/dist/tts/transcribe.js +40 -0
  241. package/dist/utils.d.ts +5 -0
  242. package/dist/utils.js +22 -0
  243. package/package.json +90 -0
  244. package/verybot.js +2 -0
@@ -0,0 +1,24 @@
1
+ import { tool } from "ai";
2
+ import { z } from "zod";
3
+ /**
4
+ * Create the read_skill tool with the given skill entries baked in.
5
+ * Returns the full SKILL.md content for the requested skill name.
6
+ */
7
+ export function createReadSkillTool(skills) {
8
+ const skillMap = new Map(skills.map((s) => [s.name.toLowerCase(), s]));
9
+ const validNames = skills.map((s) => s.name).join(", ");
10
+ return tool({
11
+ description: `Read the full instructions for a skill. Available: ${validNames}. ` +
12
+ `Call this before applying a skill so you know its full instructions.`,
13
+ inputSchema: z.object({
14
+ name: z.string().describe("The skill name to read"),
15
+ }),
16
+ execute: async ({ name }) => {
17
+ const entry = skillMap.get(name.toLowerCase());
18
+ if (!entry) {
19
+ return `Unknown skill "${name}". Available: ${validNames}`;
20
+ }
21
+ return entry.content;
22
+ },
23
+ });
24
+ }
@@ -0,0 +1,6 @@
1
+ import type { SkillEntry } from "./types.js";
2
+ /**
3
+ * Scan `dir` for subdirectories containing SKILL.md files.
4
+ * Returns metadata for each discovered skill.
5
+ */
6
+ export declare function scanSkills(dir: string): Promise<SkillEntry[]>;
@@ -0,0 +1,73 @@
1
+ import { readdir, readFile, stat } from "fs/promises";
2
+ import { join, basename, resolve } from "path";
3
+ import { logger } from "../logger.js";
4
+ const SKILL_FILENAME = "SKILL.md";
5
+ /** Parse optional YAML frontmatter delimited by --- */
6
+ function parseFrontmatter(raw) {
7
+ const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
8
+ if (!match)
9
+ return { meta: {}, body: raw };
10
+ const meta = {};
11
+ for (const line of match[1].split("\n")) {
12
+ const colon = line.indexOf(":");
13
+ if (colon === -1)
14
+ continue;
15
+ const key = line.slice(0, colon).trim();
16
+ let value = line.slice(colon + 1).trim();
17
+ // Handle inline YAML list: tools: [a, b, c]
18
+ if (typeof value === "string" && value.startsWith("[") && value.endsWith("]")) {
19
+ value = value
20
+ .slice(1, -1)
21
+ .split(",")
22
+ .map((s) => s.trim())
23
+ .filter(Boolean);
24
+ }
25
+ meta[key] = value;
26
+ }
27
+ return { meta, body: match[2] };
28
+ }
29
+ /**
30
+ * Scan `dir` for subdirectories containing SKILL.md files.
31
+ * Returns metadata for each discovered skill.
32
+ */
33
+ export async function scanSkills(dir) {
34
+ const absDir = resolve(dir);
35
+ let entries;
36
+ try {
37
+ entries = await readdir(absDir);
38
+ }
39
+ catch {
40
+ logger.info(`Skills directory not found: ${absDir} (skipping)`);
41
+ return [];
42
+ }
43
+ const skills = [];
44
+ const seenNames = new Set();
45
+ for (const entry of entries) {
46
+ const entryPath = join(absDir, entry);
47
+ const entryStat = await stat(entryPath).catch(() => null);
48
+ if (!entryStat?.isDirectory())
49
+ continue;
50
+ const skillFile = join(entryPath, SKILL_FILENAME);
51
+ let raw;
52
+ try {
53
+ raw = await readFile(skillFile, "utf-8");
54
+ }
55
+ catch {
56
+ continue; // no SKILL.md in this directory
57
+ }
58
+ const { meta, body } = parseFrontmatter(raw);
59
+ const name = meta.name ?? basename(entryPath);
60
+ const description = meta.description ?? "";
61
+ const tools = Array.isArray(meta.tools) ? meta.tools : [];
62
+ const icon = meta.icon ?? undefined;
63
+ const normalizedName = name.toLowerCase();
64
+ if (seenNames.has(normalizedName)) {
65
+ logger.warn(`Duplicate skill name "${name}" at ${skillFile}, skipping`);
66
+ continue;
67
+ }
68
+ seenNames.add(normalizedName);
69
+ skills.push({ name, description, content: body, tools, icon, path: skillFile });
70
+ // logger.info(`Loaded skill: ${name}${description ? ` — ${description}` : ""}`);
71
+ }
72
+ return skills;
73
+ }
@@ -0,0 +1,15 @@
1
+ /** Metadata parsed from a SKILL.md frontmatter during startup scan. */
2
+ export interface SkillEntry {
3
+ /** Skill name (from frontmatter `name` or directory name) */
4
+ name: string;
5
+ /** One-line description (from frontmatter `description`) */
6
+ description: string;
7
+ /** Full raw content of SKILL.md (cached for read_skill tool) */
8
+ content: string;
9
+ /** Optional list of tool names this skill references */
10
+ tools: string[];
11
+ /** Optional Lucide icon name */
12
+ icon?: string;
13
+ /** Absolute path to the SKILL.md file */
14
+ path: string;
15
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,47 @@
1
+ import type { Task, TaskStatus, TaskPriority } from "./types.js";
2
+ export interface CreateTaskInput {
3
+ title: string;
4
+ description?: string;
5
+ teamId?: string;
6
+ assignee?: string;
7
+ priority?: TaskPriority;
8
+ status?: TaskStatus;
9
+ }
10
+ export interface UpdateTaskInput {
11
+ title?: string;
12
+ description?: string | null;
13
+ status?: TaskStatus;
14
+ assignee?: string | null;
15
+ priority?: TaskPriority;
16
+ teamId?: string | null;
17
+ }
18
+ export interface ListTasksFilter {
19
+ teamId?: string;
20
+ status?: TaskStatus;
21
+ assignee?: string;
22
+ includeArchived?: boolean;
23
+ }
24
+ /**
25
+ * SQLite-backed persistence for team tasks.
26
+ * Shares the same DB file as MemoryStore, ScheduleStore, etc.
27
+ */
28
+ export declare class TaskStore {
29
+ private db;
30
+ private constructor();
31
+ static create(dbPath: string): Promise<TaskStore>;
32
+ private createSchema;
33
+ /** Add position column for existing databases that lack it. */
34
+ private migrate;
35
+ /** Get the next position value for a given status (appends to end). */
36
+ private nextPosition;
37
+ create(input: CreateTaskInput): Task;
38
+ update(id: string, input: UpdateTaskInput): Task | null;
39
+ /** Bulk-reorder tasks within a status column. Sets positions 0, 1, 2, ... */
40
+ reorder(status: TaskStatus, orderedIds: string[]): void;
41
+ delete(id: string): boolean;
42
+ getById(id: string): Task | null;
43
+ list(filter?: ListTasksFilter): Task[];
44
+ /** Bulk-archive all done tasks, optionally scoped to a team. */
45
+ archiveDone(teamId?: string): number;
46
+ close(): void;
47
+ }
@@ -0,0 +1,193 @@
1
+ import { mkdirSync } from "fs";
2
+ import { dirname } from "path";
3
+ import { randomUUID } from "crypto";
4
+ import Database from "better-sqlite3";
5
+ import { logger } from "../logger.js";
6
+ import { DEFAULT_TEAM_ID } from "../config/agent-config.js";
7
+ /**
8
+ * SQLite-backed persistence for team tasks.
9
+ * Shares the same DB file as MemoryStore, ScheduleStore, etc.
10
+ */
11
+ export class TaskStore {
12
+ db;
13
+ constructor(db) {
14
+ this.db = db;
15
+ }
16
+ static async create(dbPath) {
17
+ mkdirSync(dirname(dbPath), { recursive: true });
18
+ const db = new Database(dbPath);
19
+ db.pragma("journal_mode = WAL");
20
+ const store = new TaskStore(db);
21
+ store.createSchema();
22
+ store.migrate();
23
+ return store;
24
+ }
25
+ createSchema() {
26
+ this.db.exec(`
27
+ CREATE TABLE IF NOT EXISTS tasks (
28
+ id TEXT PRIMARY KEY,
29
+ team_id TEXT,
30
+ title TEXT NOT NULL,
31
+ description TEXT,
32
+ status TEXT NOT NULL DEFAULT 'todo',
33
+ assignee TEXT,
34
+ priority TEXT NOT NULL DEFAULT 'medium',
35
+ position INTEGER NOT NULL DEFAULT 0,
36
+ created_at INTEGER NOT NULL,
37
+ updated_at INTEGER NOT NULL
38
+ );
39
+ CREATE INDEX IF NOT EXISTS idx_tasks_team ON tasks(team_id);
40
+ CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);
41
+ CREATE INDEX IF NOT EXISTS idx_tasks_assignee ON tasks(assignee);
42
+ `);
43
+ }
44
+ /** Add position column for existing databases that lack it. */
45
+ migrate() {
46
+ const columns = this.db.pragma("table_info(tasks)");
47
+ const hasPosition = columns.some((c) => c.name === "position");
48
+ if (!hasPosition) {
49
+ this.db.exec("ALTER TABLE tasks ADD COLUMN position INTEGER NOT NULL DEFAULT 0");
50
+ // Backfill: assign positions based on created_at DESC per status
51
+ for (const status of ["backlog", "todo", "in_progress", "done", "archived"]) {
52
+ const rows = this.db
53
+ .prepare("SELECT id FROM tasks WHERE status = ? ORDER BY created_at DESC")
54
+ .all(status);
55
+ const stmt = this.db.prepare("UPDATE tasks SET position = ? WHERE id = ?");
56
+ rows.forEach((row, i) => stmt.run(i, row.id));
57
+ }
58
+ logger.info("Migrated tasks table: added position column");
59
+ }
60
+ // Backfill NULL team_id → "default"
61
+ const nullCount = this.db
62
+ .prepare(`SELECT COUNT(*) AS n FROM tasks WHERE team_id IS NULL`)
63
+ .get();
64
+ if (nullCount.n > 0) {
65
+ this.db.prepare(`UPDATE tasks SET team_id = ? WHERE team_id IS NULL`).run(DEFAULT_TEAM_ID);
66
+ logger.info(`Migrated ${nullCount.n} tasks: set NULL team_id to '${DEFAULT_TEAM_ID}'`);
67
+ }
68
+ }
69
+ /** Get the next position value for a given status (appends to end). */
70
+ nextPosition(status) {
71
+ const row = this.db
72
+ .prepare("SELECT COALESCE(MAX(position), -1) + 1 AS next FROM tasks WHERE status = ?")
73
+ .get(status);
74
+ return row.next;
75
+ }
76
+ create(input) {
77
+ const now = Date.now();
78
+ const status = input.status ?? "todo";
79
+ const task = {
80
+ id: randomUUID().slice(0, 8),
81
+ teamId: input.teamId || DEFAULT_TEAM_ID,
82
+ title: input.title,
83
+ description: input.description ?? null,
84
+ status,
85
+ assignee: input.assignee ?? null,
86
+ priority: input.priority ?? "medium",
87
+ position: this.nextPosition(status),
88
+ createdAt: now,
89
+ updatedAt: now,
90
+ };
91
+ this.db
92
+ .prepare(`INSERT INTO tasks (id, team_id, title, description, status, assignee, priority, position, created_at, updated_at)
93
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
94
+ .run(task.id, task.teamId, task.title, task.description, task.status, task.assignee, task.priority, task.position, task.createdAt, task.updatedAt);
95
+ return task;
96
+ }
97
+ update(id, input) {
98
+ const existing = this.getById(id);
99
+ if (!existing)
100
+ return null;
101
+ // When status changes, assign position at end of new column
102
+ const statusChanged = input.status !== undefined && input.status !== existing.status;
103
+ const newPosition = statusChanged ? this.nextPosition(input.status) : existing.position;
104
+ const updated = {
105
+ ...existing,
106
+ ...(input.title !== undefined && { title: input.title }),
107
+ ...(input.description !== undefined && { description: input.description }),
108
+ ...(input.status !== undefined && { status: input.status }),
109
+ ...(input.assignee !== undefined && { assignee: input.assignee }),
110
+ ...(input.priority !== undefined && { priority: input.priority }),
111
+ ...(input.teamId !== undefined && { teamId: input.teamId || DEFAULT_TEAM_ID }),
112
+ position: newPosition,
113
+ updatedAt: Date.now(),
114
+ };
115
+ this.db
116
+ .prepare(`UPDATE tasks SET team_id = ?, title = ?, description = ?, status = ?, assignee = ?, priority = ?, position = ?, updated_at = ?
117
+ WHERE id = ?`)
118
+ .run(updated.teamId, updated.title, updated.description, updated.status, updated.assignee, updated.priority, updated.position, updated.updatedAt, id);
119
+ return updated;
120
+ }
121
+ /** Bulk-reorder tasks within a status column. Sets positions 0, 1, 2, ... */
122
+ reorder(status, orderedIds) {
123
+ const stmt = this.db.prepare("UPDATE tasks SET position = ?, updated_at = ? WHERE id = ? AND status = ?");
124
+ const now = Date.now();
125
+ const tx = this.db.transaction(() => {
126
+ orderedIds.forEach((id, i) => stmt.run(i, now, id, status));
127
+ });
128
+ tx();
129
+ }
130
+ delete(id) {
131
+ const info = this.db.prepare("DELETE FROM tasks WHERE id = ?").run(id);
132
+ return info.changes > 0;
133
+ }
134
+ getById(id) {
135
+ const row = this.db.prepare("SELECT * FROM tasks WHERE id = ?").get(id);
136
+ return row ? toTask(row) : null;
137
+ }
138
+ list(filter = {}) {
139
+ const conditions = [];
140
+ const params = [];
141
+ if (filter.teamId) {
142
+ conditions.push("team_id = ?");
143
+ params.push(filter.teamId);
144
+ }
145
+ if (filter.status) {
146
+ conditions.push("status = ?");
147
+ params.push(filter.status);
148
+ }
149
+ else if (!filter.includeArchived) {
150
+ conditions.push("status != 'archived'");
151
+ }
152
+ if (filter.assignee) {
153
+ conditions.push("assignee = ?");
154
+ params.push(filter.assignee);
155
+ }
156
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
157
+ const rows = this.db
158
+ .prepare(`SELECT * FROM tasks ${where} ORDER BY position ASC`)
159
+ .all(...params);
160
+ return rows.map(toTask);
161
+ }
162
+ /** Bulk-archive all done tasks, optionally scoped to a team. */
163
+ archiveDone(teamId) {
164
+ if (teamId) {
165
+ const info = this.db
166
+ .prepare("UPDATE tasks SET status = 'archived', updated_at = ? WHERE status = 'done' AND team_id = ?")
167
+ .run(Date.now(), teamId);
168
+ return info.changes;
169
+ }
170
+ const info = this.db
171
+ .prepare("UPDATE tasks SET status = 'archived', updated_at = ? WHERE status = 'done'")
172
+ .run(Date.now());
173
+ return info.changes;
174
+ }
175
+ close() {
176
+ this.db.close();
177
+ logger.info("Task store closed");
178
+ }
179
+ }
180
+ function toTask(row) {
181
+ return {
182
+ id: row.id,
183
+ teamId: row.team_id || DEFAULT_TEAM_ID,
184
+ title: row.title,
185
+ description: row.description ?? null,
186
+ status: row.status,
187
+ assignee: row.assignee ?? null,
188
+ priority: row.priority,
189
+ position: row.position ?? 0,
190
+ createdAt: row.created_at,
191
+ updatedAt: row.updated_at,
192
+ };
193
+ }
@@ -0,0 +1,75 @@
1
+ import { z } from "zod";
2
+ export declare const TASK_STATUSES: readonly ["backlog", "todo", "in_progress", "done", "archived"];
3
+ export type TaskStatus = (typeof TASK_STATUSES)[number];
4
+ export declare const TASK_PRIORITIES: readonly ["low", "medium", "high"];
5
+ export type TaskPriority = (typeof TASK_PRIORITIES)[number];
6
+ export interface Task {
7
+ id: string;
8
+ teamId: string;
9
+ title: string;
10
+ description: string | null;
11
+ status: TaskStatus;
12
+ assignee: string | null;
13
+ priority: TaskPriority;
14
+ position: number;
15
+ createdAt: number;
16
+ updatedAt: number;
17
+ }
18
+ export declare const CreateTaskSchema: z.ZodObject<{
19
+ title: z.ZodString;
20
+ description: z.ZodOptional<z.ZodString>;
21
+ teamId: z.ZodOptional<z.ZodString>;
22
+ assignee: z.ZodOptional<z.ZodString>;
23
+ priority: z.ZodDefault<z.ZodEnum<{
24
+ low: "low";
25
+ medium: "medium";
26
+ high: "high";
27
+ }>>;
28
+ status: z.ZodDefault<z.ZodEnum<{
29
+ done: "done";
30
+ backlog: "backlog";
31
+ todo: "todo";
32
+ in_progress: "in_progress";
33
+ }>>;
34
+ }, z.core.$strip>;
35
+ export declare const UpdateTaskSchema: z.ZodObject<{
36
+ id: z.ZodString;
37
+ title: z.ZodOptional<z.ZodString>;
38
+ description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
39
+ status: z.ZodOptional<z.ZodEnum<{
40
+ done: "done";
41
+ backlog: "backlog";
42
+ todo: "todo";
43
+ in_progress: "in_progress";
44
+ archived: "archived";
45
+ }>>;
46
+ assignee: z.ZodOptional<z.ZodNullable<z.ZodString>>;
47
+ priority: z.ZodOptional<z.ZodEnum<{
48
+ low: "low";
49
+ medium: "medium";
50
+ high: "high";
51
+ }>>;
52
+ teamId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
53
+ }, z.core.$strip>;
54
+ export declare const ListTasksSchema: z.ZodObject<{
55
+ teamId: z.ZodOptional<z.ZodString>;
56
+ status: z.ZodOptional<z.ZodEnum<{
57
+ done: "done";
58
+ backlog: "backlog";
59
+ todo: "todo";
60
+ in_progress: "in_progress";
61
+ archived: "archived";
62
+ }>>;
63
+ assignee: z.ZodOptional<z.ZodString>;
64
+ includeArchived: z.ZodOptional<z.ZodBoolean>;
65
+ }, z.core.$strip>;
66
+ export declare const ReorderTasksSchema: z.ZodObject<{
67
+ status: z.ZodEnum<{
68
+ done: "done";
69
+ backlog: "backlog";
70
+ todo: "todo";
71
+ in_progress: "in_progress";
72
+ archived: "archived";
73
+ }>;
74
+ orderedIds: z.ZodArray<z.ZodString>;
75
+ }, z.core.$strip>;
@@ -0,0 +1,32 @@
1
+ import { z } from "zod";
2
+ export const TASK_STATUSES = ["backlog", "todo", "in_progress", "done", "archived"];
3
+ export const TASK_PRIORITIES = ["low", "medium", "high"];
4
+ /** Visible on the kanban board (excludes archived). */
5
+ const BOARD_STATUSES = ["backlog", "todo", "in_progress", "done"];
6
+ export const CreateTaskSchema = z.object({
7
+ title: z.string().min(1),
8
+ description: z.string().optional(),
9
+ teamId: z.string().optional(),
10
+ assignee: z.string().optional(),
11
+ priority: z.enum(TASK_PRIORITIES).default("medium"),
12
+ status: z.enum(BOARD_STATUSES).default("todo"),
13
+ });
14
+ export const UpdateTaskSchema = z.object({
15
+ id: z.string(),
16
+ title: z.string().min(1).optional(),
17
+ description: z.string().nullable().optional(),
18
+ status: z.enum(TASK_STATUSES).optional(),
19
+ assignee: z.string().nullable().optional(),
20
+ priority: z.enum(TASK_PRIORITIES).optional(),
21
+ teamId: z.string().nullable().optional(),
22
+ });
23
+ export const ListTasksSchema = z.object({
24
+ teamId: z.string().optional(),
25
+ status: z.enum(TASK_STATUSES).optional(),
26
+ assignee: z.string().optional(),
27
+ includeArchived: z.boolean().optional(),
28
+ });
29
+ export const ReorderTasksSchema = z.object({
30
+ status: z.enum(TASK_STATUSES),
31
+ orderedIds: z.array(z.string()).min(1),
32
+ });
@@ -0,0 +1,78 @@
1
+ import type { Team, AgentRow } from "./types.js";
2
+ import type { TeamConfig } from "../config/agent-config.js";
3
+ /** Max allowed length for team/agent names. */
4
+ export declare const MAX_NAME_LENGTH = 128;
5
+ /** Max allowed length for agent identity strings. */
6
+ export declare const MAX_IDENTITY_LENGTH = 10000;
7
+ /** Max allowed length for model strings. */
8
+ export declare const MAX_MODEL_LENGTH = 256;
9
+ /** Hex color pattern: #RRGGBB */
10
+ export declare const HEX_COLOR_RE: RegExp;
11
+ export interface CreateTeamInput {
12
+ /** Optional caller-provided id. If omitted, a random UUID is generated. */
13
+ id?: string;
14
+ name: string;
15
+ color?: string;
16
+ workspace?: string;
17
+ variables?: Record<string, string>;
18
+ }
19
+ export interface UpdateTeamInput {
20
+ name?: string;
21
+ color?: string;
22
+ workspace?: string;
23
+ variables?: Record<string, string>;
24
+ }
25
+ export interface CreateAgentInput {
26
+ /** Optional caller-provided id. If omitted, a random UUID is generated. */
27
+ id?: string;
28
+ name: string;
29
+ role: "orchestrator" | "worker";
30
+ model: string;
31
+ contextWindow?: number;
32
+ maxSteps?: number;
33
+ identity?: string;
34
+ tools?: string[];
35
+ timeout?: number;
36
+ templateId?: string | null;
37
+ }
38
+ export interface UpdateAgentInput {
39
+ name?: string;
40
+ role?: "orchestrator" | "worker";
41
+ model?: string;
42
+ contextWindow?: number;
43
+ maxSteps?: number;
44
+ identity?: string;
45
+ tools?: string[];
46
+ timeout?: number;
47
+ templateId?: string | null;
48
+ }
49
+ /**
50
+ * SQLite-backed persistence for teams and agents.
51
+ * Shares the same DB file as MemoryStore, TaskStore, etc.
52
+ */
53
+ export declare class TeamStore {
54
+ private db;
55
+ private constructor();
56
+ static create(dbPath: string): Promise<TeamStore>;
57
+ private createSchema;
58
+ /** Run a function inside a SQLite transaction (all-or-nothing). */
59
+ transaction<T>(fn: () => T): T;
60
+ createTeam(input: CreateTeamInput): Team;
61
+ updateTeam(id: string, input: UpdateTeamInput): Team | null;
62
+ deleteTeam(id: string): boolean;
63
+ getTeamById(id: string): Team | null;
64
+ getTeamByName(name: string): Team | null;
65
+ listTeams(): Team[];
66
+ createAgent(teamId: string, input: CreateAgentInput): AgentRow;
67
+ updateAgent(id: string, input: UpdateAgentInput): AgentRow | null;
68
+ deleteAgent(id: string): boolean;
69
+ getAgentById(id: string): AgentRow | null;
70
+ listAgentsByTeam(teamId: string): AgentRow[];
71
+ getAgentByName(teamId: string, name: string): AgentRow | null;
72
+ /**
73
+ * Convert DB rows to the existing TeamConfig[] format so TeamRegistry
74
+ * constructor is unchanged. Uses a single JOIN query instead of N+1.
75
+ */
76
+ toTeamConfigs(): TeamConfig[];
77
+ close(): void;
78
+ }