@hasna/todos 0.11.14 → 0.11.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dashboard/dist/assets/index-B-w1tUlm.js +346 -0
- package/dashboard/dist/assets/index-BXQ39iMX.css +1 -0
- package/dashboard/dist/index.html +13 -0
- package/dashboard/dist/logo.jpg +0 -0
- package/dist/cli/brains.d.ts +3 -0
- package/dist/cli/brains.d.ts.map +1 -0
- package/dist/cli/commands/dispatch.d.ts +3 -0
- package/dist/cli/commands/dispatch.d.ts.map +1 -0
- package/dist/cli/components/App.d.ts +2 -0
- package/dist/cli/components/App.d.ts.map +1 -0
- package/dist/cli/components/Dashboard.d.ts +7 -0
- package/dist/cli/components/Dashboard.d.ts.map +1 -0
- package/dist/cli/components/Header.d.ts +8 -0
- package/dist/cli/components/Header.d.ts.map +1 -0
- package/dist/cli/components/ProjectList.d.ts +8 -0
- package/dist/cli/components/ProjectList.d.ts.map +1 -0
- package/dist/cli/components/SearchView.d.ts +10 -0
- package/dist/cli/components/SearchView.d.ts.map +1 -0
- package/dist/cli/components/TaskDetail.d.ts +7 -0
- package/dist/cli/components/TaskDetail.d.ts.map +1 -0
- package/dist/cli/components/TaskForm.d.ts +15 -0
- package/dist/cli/components/TaskForm.d.ts.map +1 -0
- package/dist/cli/components/TaskList.d.ts +8 -0
- package/dist/cli/components/TaskList.d.ts.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +4975 -4121
- package/dist/db/agent-metrics.d.ts +34 -0
- package/dist/db/agent-metrics.d.ts.map +1 -0
- package/dist/db/agents.d.ts +82 -0
- package/dist/db/agents.d.ts.map +1 -0
- package/dist/db/audit.d.ts +52 -0
- package/dist/db/audit.d.ts.map +1 -0
- package/dist/db/budgets.d.ts +27 -0
- package/dist/db/budgets.d.ts.map +1 -0
- package/dist/db/builtin-templates.d.ts +22 -0
- package/dist/db/builtin-templates.d.ts.map +1 -0
- package/dist/db/checklists.d.ts +13 -0
- package/dist/db/checklists.d.ts.map +1 -0
- package/dist/db/comments.d.ts +8 -0
- package/dist/db/comments.d.ts.map +1 -0
- package/dist/db/database.d.ts +12 -0
- package/dist/db/database.d.ts.map +1 -0
- package/dist/db/dispatches.d.ts +15 -0
- package/dist/db/dispatches.d.ts.map +1 -0
- package/dist/db/file-locks.d.ts +43 -0
- package/dist/db/file-locks.d.ts.map +1 -0
- package/dist/db/handoffs.d.ts +25 -0
- package/dist/db/handoffs.d.ts.map +1 -0
- package/dist/db/kg.d.ts +70 -0
- package/dist/db/kg.d.ts.map +1 -0
- package/dist/db/locks.d.ts +14 -0
- package/dist/db/locks.d.ts.map +1 -0
- package/dist/db/machines.d.ts +17 -0
- package/dist/db/machines.d.ts.map +1 -0
- package/dist/db/orgs.d.ts +13 -0
- package/dist/db/orgs.d.ts.map +1 -0
- package/dist/db/patrol.d.ts +35 -0
- package/dist/db/patrol.d.ts.map +1 -0
- package/dist/db/pg-migrate.d.ts +14 -0
- package/dist/db/pg-migrate.d.ts.map +1 -0
- package/dist/db/pg-migrations.d.ts +8 -0
- package/dist/db/pg-migrations.d.ts.map +1 -0
- package/dist/db/plans.d.ts +8 -0
- package/dist/db/plans.d.ts.map +1 -0
- package/dist/db/project-agent-roles.d.ts +34 -0
- package/dist/db/project-agent-roles.d.ts.map +1 -0
- package/dist/db/projects.d.ts +16 -0
- package/dist/db/projects.d.ts.map +1 -0
- package/dist/db/schema.d.ts +6 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/sessions.d.ts +8 -0
- package/dist/db/sessions.d.ts.map +1 -0
- package/dist/db/snapshots.d.ts +37 -0
- package/dist/db/snapshots.d.ts.map +1 -0
- package/dist/db/task-claim.d.ts +7 -0
- package/dist/db/task-claim.d.ts.map +1 -0
- package/dist/db/task-commits.d.ts +31 -0
- package/dist/db/task-commits.d.ts.map +1 -0
- package/dist/db/task-files.d.ts +74 -0
- package/dist/db/task-files.d.ts.map +1 -0
- package/dist/db/task-lists.d.ts +10 -0
- package/dist/db/task-lists.d.ts.map +1 -0
- package/dist/db/task-relationships.d.ts +36 -0
- package/dist/db/task-relationships.d.ts.map +1 -0
- package/dist/db/task-workflow.d.ts +7 -0
- package/dist/db/task-workflow.d.ts.map +1 -0
- package/dist/db/tasks.d.ts +215 -0
- package/dist/db/tasks.d.ts.map +1 -0
- package/dist/db/templates.d.ts +98 -0
- package/dist/db/templates.d.ts.map +1 -0
- package/dist/db/traces.d.ts +38 -0
- package/dist/db/traces.d.ts.map +1 -0
- package/dist/db/webhooks.d.ts +19 -0
- package/dist/db/webhooks.d.ts.map +1 -0
- package/dist/index.d.ts +72 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +344 -140
- package/dist/lib/agent-tasks.d.ts +11 -0
- package/dist/lib/agent-tasks.d.ts.map +1 -0
- package/dist/lib/auto-assign.d.ts +25 -0
- package/dist/lib/auto-assign.d.ts.map +1 -0
- package/dist/lib/burndown.d.ts +18 -0
- package/dist/lib/burndown.d.ts.map +1 -0
- package/dist/lib/claude-tasks.d.ts +20 -0
- package/dist/lib/claude-tasks.d.ts.map +1 -0
- package/dist/lib/completion-guard.d.ts +17 -0
- package/dist/lib/completion-guard.d.ts.map +1 -0
- package/dist/lib/config.d.ts +44 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/dispatch-formatter.d.ts +21 -0
- package/dist/lib/dispatch-formatter.d.ts.map +1 -0
- package/dist/lib/dispatch.d.ts +28 -0
- package/dist/lib/dispatch.d.ts.map +1 -0
- package/dist/lib/extract.d.ts +51 -0
- package/dist/lib/extract.d.ts.map +1 -0
- package/dist/lib/gatherer.d.ts +16 -0
- package/dist/lib/gatherer.d.ts.map +1 -0
- package/dist/lib/github.d.ts +25 -0
- package/dist/lib/github.d.ts.map +1 -0
- package/dist/lib/model-config.d.ts +14 -0
- package/dist/lib/model-config.d.ts.map +1 -0
- package/dist/lib/recurrence.d.ts +10 -0
- package/dist/lib/recurrence.d.ts.map +1 -0
- package/dist/lib/search.d.ts +17 -0
- package/dist/lib/search.d.ts.map +1 -0
- package/dist/lib/sync-types.d.ts +16 -0
- package/dist/lib/sync-types.d.ts.map +1 -0
- package/dist/lib/sync-utils.d.ts +12 -0
- package/dist/lib/sync-utils.d.ts.map +1 -0
- package/dist/lib/sync.d.ts +9 -0
- package/dist/lib/sync.d.ts.map +1 -0
- package/dist/lib/tmux.d.ts +28 -0
- package/dist/lib/tmux.d.ts.map +1 -0
- package/dist/mcp/index.d.ts +3 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +14175 -13694
- package/dist/mcp/tools/agents.d.ts +16 -0
- package/dist/mcp/tools/agents.d.ts.map +1 -0
- package/dist/mcp/tools/cloud.d.ts +12 -0
- package/dist/mcp/tools/cloud.d.ts.map +1 -0
- package/dist/mcp/tools/dispatch.d.ts +9 -0
- package/dist/mcp/tools/dispatch.d.ts.map +1 -0
- package/dist/mcp/tools/templates.d.ts +9 -0
- package/dist/mcp/tools/templates.d.ts.map +1 -0
- package/dist/mcp/tools/webhooks.d.ts +8 -0
- package/dist/mcp/tools/webhooks.d.ts.map +1 -0
- package/dist/sdk.d.ts +186 -0
- package/dist/sdk.d.ts.map +1 -0
- package/dist/server/index.d.ts +9 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +4933 -0
- package/dist/server/serve.d.ts +10 -0
- package/dist/server/serve.d.ts.map +1 -0
- package/dist/types/index.d.ts +681 -0
- package/dist/types/index.d.ts.map +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15,84 +15,7 @@ var __export = (target, all) => {
|
|
|
15
15
|
};
|
|
16
16
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
17
17
|
|
|
18
|
-
// src/db/
|
|
19
|
-
import { Database } from "bun:sqlite";
|
|
20
|
-
import { existsSync, mkdirSync } from "fs";
|
|
21
|
-
import { dirname, join, resolve } from "path";
|
|
22
|
-
function isInMemoryDb(path) {
|
|
23
|
-
return path === ":memory:" || path.startsWith("file::memory:");
|
|
24
|
-
}
|
|
25
|
-
function findNearestTodosDb(startDir) {
|
|
26
|
-
let dir = resolve(startDir);
|
|
27
|
-
while (true) {
|
|
28
|
-
const candidate = join(dir, ".todos", "todos.db");
|
|
29
|
-
if (existsSync(candidate))
|
|
30
|
-
return candidate;
|
|
31
|
-
const parent = dirname(dir);
|
|
32
|
-
if (parent === dir)
|
|
33
|
-
break;
|
|
34
|
-
dir = parent;
|
|
35
|
-
}
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
function findGitRoot(startDir) {
|
|
39
|
-
let dir = resolve(startDir);
|
|
40
|
-
while (true) {
|
|
41
|
-
if (existsSync(join(dir, ".git")))
|
|
42
|
-
return dir;
|
|
43
|
-
const parent = dirname(dir);
|
|
44
|
-
if (parent === dir)
|
|
45
|
-
break;
|
|
46
|
-
dir = parent;
|
|
47
|
-
}
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
function getDbPath() {
|
|
51
|
-
if (process.env["HASNA_TODOS_DB_PATH"]) {
|
|
52
|
-
return process.env["HASNA_TODOS_DB_PATH"];
|
|
53
|
-
}
|
|
54
|
-
if (process.env["TODOS_DB_PATH"]) {
|
|
55
|
-
return process.env["TODOS_DB_PATH"];
|
|
56
|
-
}
|
|
57
|
-
const cwd = process.cwd();
|
|
58
|
-
const nearest = findNearestTodosDb(cwd);
|
|
59
|
-
if (nearest)
|
|
60
|
-
return nearest;
|
|
61
|
-
if (process.env["TODOS_DB_SCOPE"] === "project") {
|
|
62
|
-
const gitRoot = findGitRoot(cwd);
|
|
63
|
-
if (gitRoot) {
|
|
64
|
-
return join(gitRoot, ".todos", "todos.db");
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
68
|
-
const newPath = join(home, ".hasna", "todos", "todos.db");
|
|
69
|
-
const legacyPath = join(home, ".todos", "todos.db");
|
|
70
|
-
if (!existsSync(newPath) && existsSync(legacyPath)) {
|
|
71
|
-
return legacyPath;
|
|
72
|
-
}
|
|
73
|
-
return newPath;
|
|
74
|
-
}
|
|
75
|
-
function ensureDir(filePath) {
|
|
76
|
-
if (isInMemoryDb(filePath))
|
|
77
|
-
return;
|
|
78
|
-
const dir = dirname(resolve(filePath));
|
|
79
|
-
if (!existsSync(dir)) {
|
|
80
|
-
mkdirSync(dir, { recursive: true });
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
function getDatabase(dbPath) {
|
|
84
|
-
if (_db)
|
|
85
|
-
return _db;
|
|
86
|
-
const path = dbPath || getDbPath();
|
|
87
|
-
ensureDir(path);
|
|
88
|
-
_db = new Database(path);
|
|
89
|
-
_db.run("PRAGMA journal_mode = WAL");
|
|
90
|
-
_db.run("PRAGMA busy_timeout = 5000");
|
|
91
|
-
_db.run("PRAGMA foreign_keys = ON");
|
|
92
|
-
runMigrations(_db);
|
|
93
|
-
backfillTaskTags(_db);
|
|
94
|
-
return _db;
|
|
95
|
-
}
|
|
18
|
+
// src/db/schema.ts
|
|
96
19
|
function runMigrations(db) {
|
|
97
20
|
try {
|
|
98
21
|
const result = db.query("SELECT MAX(id) as max_id FROM _migrations").get();
|
|
@@ -253,6 +176,13 @@ function ensureSchema(db) {
|
|
|
253
176
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
254
177
|
UNIQUE(source_id, source_type, target_id, target_type, relation_type)
|
|
255
178
|
)`);
|
|
179
|
+
ensureTable("machines", `
|
|
180
|
+
CREATE TABLE machines (
|
|
181
|
+
id TEXT PRIMARY KEY, name TEXT NOT NULL UNIQUE, hostname TEXT, platform TEXT,
|
|
182
|
+
last_seen_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
183
|
+
metadata TEXT DEFAULT '{}',
|
|
184
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
185
|
+
)`);
|
|
256
186
|
ensureColumn("projects", "task_list_id", "TEXT");
|
|
257
187
|
ensureColumn("projects", "task_prefix", "TEXT");
|
|
258
188
|
ensureColumn("projects", "task_counter", "INTEGER NOT NULL DEFAULT 0");
|
|
@@ -353,6 +283,38 @@ function ensureSchema(db) {
|
|
|
353
283
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_webhook_deliveries_event ON webhook_deliveries(event)");
|
|
354
284
|
ensureColumn("task_comments", "type", "TEXT DEFAULT 'comment'");
|
|
355
285
|
ensureColumn("task_comments", "progress_pct", "INTEGER");
|
|
286
|
+
ensureColumn("projects", "machine_id", "TEXT");
|
|
287
|
+
ensureColumn("projects", "synced_at", "TEXT");
|
|
288
|
+
ensureColumn("tasks", "machine_id", "TEXT");
|
|
289
|
+
ensureColumn("tasks", "synced_at", "TEXT");
|
|
290
|
+
ensureColumn("agents", "machine_id", "TEXT");
|
|
291
|
+
ensureColumn("agents", "synced_at", "TEXT");
|
|
292
|
+
ensureColumn("task_lists", "machine_id", "TEXT");
|
|
293
|
+
ensureColumn("task_lists", "synced_at", "TEXT");
|
|
294
|
+
ensureColumn("plans", "machine_id", "TEXT");
|
|
295
|
+
ensureColumn("plans", "synced_at", "TEXT");
|
|
296
|
+
ensureColumn("task_comments", "machine_id", "TEXT");
|
|
297
|
+
ensureColumn("task_comments", "synced_at", "TEXT");
|
|
298
|
+
ensureColumn("sessions", "machine_id", "TEXT");
|
|
299
|
+
ensureColumn("sessions", "synced_at", "TEXT");
|
|
300
|
+
ensureColumn("task_history", "machine_id", "TEXT");
|
|
301
|
+
ensureColumn("webhooks", "machine_id", "TEXT");
|
|
302
|
+
ensureColumn("webhooks", "synced_at", "TEXT");
|
|
303
|
+
ensureColumn("task_templates", "machine_id", "TEXT");
|
|
304
|
+
ensureColumn("task_templates", "synced_at", "TEXT");
|
|
305
|
+
ensureColumn("orgs", "machine_id", "TEXT");
|
|
306
|
+
ensureColumn("orgs", "synced_at", "TEXT");
|
|
307
|
+
ensureColumn("handoffs", "machine_id", "TEXT");
|
|
308
|
+
ensureColumn("handoffs", "synced_at", "TEXT");
|
|
309
|
+
ensureColumn("task_checklists", "machine_id", "TEXT");
|
|
310
|
+
ensureColumn("project_sources", "machine_id", "TEXT");
|
|
311
|
+
ensureColumn("project_sources", "synced_at", "TEXT");
|
|
312
|
+
ensureColumn("task_files", "machine_id", "TEXT");
|
|
313
|
+
ensureColumn("task_relationships", "machine_id", "TEXT");
|
|
314
|
+
ensureColumn("kg_edges", "machine_id", "TEXT");
|
|
315
|
+
ensureColumn("project_agent_roles", "machine_id", "TEXT");
|
|
316
|
+
ensureColumn("dispatches", "machine_id", "TEXT");
|
|
317
|
+
ensureColumn("dispatches", "synced_at", "TEXT");
|
|
356
318
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_plan ON tasks(plan_id)");
|
|
357
319
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_task_list ON tasks(task_list_id)");
|
|
358
320
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_due_at ON tasks(due_at)");
|
|
@@ -381,6 +343,10 @@ function ensureSchema(db) {
|
|
|
381
343
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_kg_source ON kg_edges(source_id, source_type)");
|
|
382
344
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_kg_target ON kg_edges(target_id, target_type)");
|
|
383
345
|
ensureIndex("CREATE INDEX IF NOT EXISTS idx_kg_relation ON kg_edges(relation_type)");
|
|
346
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_machine ON tasks(machine_id)");
|
|
347
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_synced ON tasks(synced_at)");
|
|
348
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_projects_machine ON projects(machine_id)");
|
|
349
|
+
ensureIndex("CREATE INDEX IF NOT EXISTS idx_agents_machine ON agents(machine_id)");
|
|
384
350
|
}
|
|
385
351
|
function backfillTaskTags(db) {
|
|
386
352
|
try {
|
|
@@ -411,68 +377,8 @@ function backfillTaskTags(db) {
|
|
|
411
377
|
}
|
|
412
378
|
} catch {}
|
|
413
379
|
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
_db.close();
|
|
417
|
-
_db = null;
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
function resetDatabase() {
|
|
421
|
-
_db = null;
|
|
422
|
-
}
|
|
423
|
-
function now() {
|
|
424
|
-
return new Date().toISOString();
|
|
425
|
-
}
|
|
426
|
-
function uuid() {
|
|
427
|
-
return crypto.randomUUID();
|
|
428
|
-
}
|
|
429
|
-
function isLockExpired(lockedAt) {
|
|
430
|
-
if (!lockedAt)
|
|
431
|
-
return true;
|
|
432
|
-
const lockTime = new Date(lockedAt).getTime();
|
|
433
|
-
const expiryMs = LOCK_EXPIRY_MINUTES * 60 * 1000;
|
|
434
|
-
return Date.now() - lockTime > expiryMs;
|
|
435
|
-
}
|
|
436
|
-
function lockExpiryCutoff(nowMs = Date.now()) {
|
|
437
|
-
const expiryMs = LOCK_EXPIRY_MINUTES * 60 * 1000;
|
|
438
|
-
return new Date(nowMs - expiryMs).toISOString();
|
|
439
|
-
}
|
|
440
|
-
function clearExpiredLocks(db) {
|
|
441
|
-
const cutoff = lockExpiryCutoff();
|
|
442
|
-
db.run("UPDATE tasks SET locked_by = NULL, locked_at = NULL WHERE locked_at IS NOT NULL AND locked_at < ?", [cutoff]);
|
|
443
|
-
}
|
|
444
|
-
function resolvePartialId(db, table, partialId) {
|
|
445
|
-
if (partialId.length >= 36) {
|
|
446
|
-
const row = db.query(`SELECT id FROM ${table} WHERE id = ?`).get(partialId);
|
|
447
|
-
return row?.id ?? null;
|
|
448
|
-
}
|
|
449
|
-
const rows = db.query(`SELECT id FROM ${table} WHERE id LIKE ?`).all(`${partialId}%`);
|
|
450
|
-
if (rows.length === 1) {
|
|
451
|
-
return rows[0].id;
|
|
452
|
-
}
|
|
453
|
-
if (rows.length > 1) {
|
|
454
|
-
return null;
|
|
455
|
-
}
|
|
456
|
-
if (table === "tasks") {
|
|
457
|
-
const shortIdRows = db.query("SELECT id FROM tasks WHERE short_id = ?").all(partialId);
|
|
458
|
-
if (shortIdRows.length === 1) {
|
|
459
|
-
return shortIdRows[0].id;
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
if (table === "task_lists") {
|
|
463
|
-
const slugRow = db.query("SELECT id FROM task_lists WHERE slug = ?").get(partialId);
|
|
464
|
-
if (slugRow)
|
|
465
|
-
return slugRow.id;
|
|
466
|
-
}
|
|
467
|
-
if (table === "projects") {
|
|
468
|
-
const nameRow = db.query("SELECT id FROM projects WHERE lower(name) = ?").get(partialId.toLowerCase());
|
|
469
|
-
if (nameRow)
|
|
470
|
-
return nameRow.id;
|
|
471
|
-
}
|
|
472
|
-
return null;
|
|
473
|
-
}
|
|
474
|
-
var LOCK_EXPIRY_MINUTES = 30, MIGRATIONS, _db = null;
|
|
475
|
-
var init_database = __esm(() => {
|
|
380
|
+
var MIGRATIONS;
|
|
381
|
+
var init_schema = __esm(() => {
|
|
476
382
|
MIGRATIONS = [
|
|
477
383
|
`
|
|
478
384
|
CREATE TABLE IF NOT EXISTS projects (
|
|
@@ -1092,10 +998,297 @@ var init_database = __esm(() => {
|
|
|
1092
998
|
CREATE INDEX IF NOT EXISTS idx_dispatch_logs_dispatch ON dispatch_logs(dispatch_id);
|
|
1093
999
|
|
|
1094
1000
|
INSERT OR IGNORE INTO _migrations (id) VALUES (40);
|
|
1001
|
+
`,
|
|
1002
|
+
`
|
|
1003
|
+
CREATE TABLE IF NOT EXISTS machines (
|
|
1004
|
+
id TEXT PRIMARY KEY,
|
|
1005
|
+
name TEXT NOT NULL UNIQUE,
|
|
1006
|
+
hostname TEXT,
|
|
1007
|
+
platform TEXT,
|
|
1008
|
+
last_seen_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
1009
|
+
metadata TEXT DEFAULT '{}',
|
|
1010
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
1011
|
+
);
|
|
1012
|
+
|
|
1013
|
+
ALTER TABLE projects ADD COLUMN machine_id TEXT;
|
|
1014
|
+
ALTER TABLE projects ADD COLUMN synced_at TEXT;
|
|
1015
|
+
ALTER TABLE tasks ADD COLUMN machine_id TEXT;
|
|
1016
|
+
ALTER TABLE tasks ADD COLUMN synced_at TEXT;
|
|
1017
|
+
ALTER TABLE agents ADD COLUMN machine_id TEXT;
|
|
1018
|
+
ALTER TABLE agents ADD COLUMN synced_at TEXT;
|
|
1019
|
+
ALTER TABLE task_lists ADD COLUMN machine_id TEXT;
|
|
1020
|
+
ALTER TABLE task_lists ADD COLUMN synced_at TEXT;
|
|
1021
|
+
ALTER TABLE plans ADD COLUMN machine_id TEXT;
|
|
1022
|
+
ALTER TABLE plans ADD COLUMN synced_at TEXT;
|
|
1023
|
+
ALTER TABLE task_comments ADD COLUMN machine_id TEXT;
|
|
1024
|
+
ALTER TABLE task_comments ADD COLUMN synced_at TEXT;
|
|
1025
|
+
ALTER TABLE sessions ADD COLUMN machine_id TEXT;
|
|
1026
|
+
ALTER TABLE sessions ADD COLUMN synced_at TEXT;
|
|
1027
|
+
ALTER TABLE task_history ADD COLUMN machine_id TEXT;
|
|
1028
|
+
ALTER TABLE webhooks ADD COLUMN machine_id TEXT;
|
|
1029
|
+
ALTER TABLE webhooks ADD COLUMN synced_at TEXT;
|
|
1030
|
+
ALTER TABLE task_templates ADD COLUMN machine_id TEXT;
|
|
1031
|
+
ALTER TABLE task_templates ADD COLUMN synced_at TEXT;
|
|
1032
|
+
ALTER TABLE orgs ADD COLUMN machine_id TEXT;
|
|
1033
|
+
ALTER TABLE orgs ADD COLUMN synced_at TEXT;
|
|
1034
|
+
ALTER TABLE handoffs ADD COLUMN machine_id TEXT;
|
|
1035
|
+
ALTER TABLE handoffs ADD COLUMN synced_at TEXT;
|
|
1036
|
+
ALTER TABLE task_checklists ADD COLUMN machine_id TEXT;
|
|
1037
|
+
ALTER TABLE project_sources ADD COLUMN machine_id TEXT;
|
|
1038
|
+
ALTER TABLE project_sources ADD COLUMN synced_at TEXT;
|
|
1039
|
+
ALTER TABLE task_files ADD COLUMN machine_id TEXT;
|
|
1040
|
+
ALTER TABLE task_relationships ADD COLUMN machine_id TEXT;
|
|
1041
|
+
ALTER TABLE kg_edges ADD COLUMN machine_id TEXT;
|
|
1042
|
+
ALTER TABLE project_agent_roles ADD COLUMN machine_id TEXT;
|
|
1043
|
+
ALTER TABLE dispatches ADD COLUMN machine_id TEXT;
|
|
1044
|
+
ALTER TABLE dispatches ADD COLUMN synced_at TEXT;
|
|
1045
|
+
|
|
1046
|
+
CREATE INDEX IF NOT EXISTS idx_tasks_machine ON tasks(machine_id);
|
|
1047
|
+
CREATE INDEX IF NOT EXISTS idx_tasks_synced ON tasks(synced_at);
|
|
1048
|
+
CREATE INDEX IF NOT EXISTS idx_projects_machine ON projects(machine_id);
|
|
1049
|
+
CREATE INDEX IF NOT EXISTS idx_agents_machine ON agents(machine_id);
|
|
1050
|
+
|
|
1051
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (41);
|
|
1095
1052
|
`
|
|
1096
1053
|
];
|
|
1097
1054
|
});
|
|
1098
1055
|
|
|
1056
|
+
// src/db/machines.ts
|
|
1057
|
+
import { hostname as osHostname, platform as osPlatform } from "os";
|
|
1058
|
+
function rowToMachine(row) {
|
|
1059
|
+
return {
|
|
1060
|
+
...row,
|
|
1061
|
+
metadata: row.metadata ? JSON.parse(row.metadata) : {}
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1064
|
+
function getOrCreateLocalMachine(db) {
|
|
1065
|
+
const d = db || getDatabase();
|
|
1066
|
+
const name = process.env["TODOS_MACHINE_NAME"] || osHostname();
|
|
1067
|
+
const host = osHostname();
|
|
1068
|
+
const plat = osPlatform();
|
|
1069
|
+
const existing = d.query("SELECT * FROM machines WHERE name = ?").get(name);
|
|
1070
|
+
if (existing) {
|
|
1071
|
+
d.run("UPDATE machines SET hostname = ?, platform = ?, last_seen_at = ? WHERE id = ?", [host, plat, now(), existing.id]);
|
|
1072
|
+
return rowToMachine({ ...existing, hostname: host, platform: plat, last_seen_at: now() });
|
|
1073
|
+
}
|
|
1074
|
+
const id = uuid();
|
|
1075
|
+
const ts = now();
|
|
1076
|
+
d.run("INSERT INTO machines (id, name, hostname, platform, last_seen_at, metadata, created_at) VALUES (?, ?, ?, ?, ?, '{}', ?)", [id, name, host, plat, ts, ts]);
|
|
1077
|
+
return { id, name, hostname: host, platform: plat, last_seen_at: ts, metadata: {}, created_at: ts };
|
|
1078
|
+
}
|
|
1079
|
+
function getMachineId(db) {
|
|
1080
|
+
if (_machineId)
|
|
1081
|
+
return _machineId;
|
|
1082
|
+
const machine = getOrCreateLocalMachine(db);
|
|
1083
|
+
_machineId = machine.id;
|
|
1084
|
+
return _machineId;
|
|
1085
|
+
}
|
|
1086
|
+
function resetMachineId() {
|
|
1087
|
+
_machineId = null;
|
|
1088
|
+
}
|
|
1089
|
+
function getMachine(id, db) {
|
|
1090
|
+
const d = db || getDatabase();
|
|
1091
|
+
const row = d.query("SELECT * FROM machines WHERE id = ?").get(id);
|
|
1092
|
+
return row ? rowToMachine(row) : null;
|
|
1093
|
+
}
|
|
1094
|
+
function getMachineByName(name, db) {
|
|
1095
|
+
const d = db || getDatabase();
|
|
1096
|
+
const row = d.query("SELECT * FROM machines WHERE name = ?").get(name);
|
|
1097
|
+
return row ? rowToMachine(row) : null;
|
|
1098
|
+
}
|
|
1099
|
+
function listMachines(db) {
|
|
1100
|
+
const d = db || getDatabase();
|
|
1101
|
+
const rows = d.query("SELECT * FROM machines ORDER BY last_seen_at DESC").all();
|
|
1102
|
+
return rows.map(rowToMachine);
|
|
1103
|
+
}
|
|
1104
|
+
function deleteMachine(id, db) {
|
|
1105
|
+
const d = db || getDatabase();
|
|
1106
|
+
const result = d.run("DELETE FROM machines WHERE id = ?", [id]);
|
|
1107
|
+
return result.changes > 0;
|
|
1108
|
+
}
|
|
1109
|
+
function backfillMachineId(db, force = false) {
|
|
1110
|
+
if (!force && process.env["TODOS_DB_PATH"] === ":memory:")
|
|
1111
|
+
return;
|
|
1112
|
+
try {
|
|
1113
|
+
const machine = getOrCreateLocalMachine(db);
|
|
1114
|
+
for (const table of TABLES_WITH_MACHINE_ID) {
|
|
1115
|
+
try {
|
|
1116
|
+
db.run(`UPDATE "${table}" SET machine_id = ? WHERE machine_id IS NULL`, [machine.id]);
|
|
1117
|
+
} catch {}
|
|
1118
|
+
}
|
|
1119
|
+
} catch {}
|
|
1120
|
+
}
|
|
1121
|
+
var _machineId = null, TABLES_WITH_MACHINE_ID;
|
|
1122
|
+
var init_machines = __esm(() => {
|
|
1123
|
+
init_database();
|
|
1124
|
+
TABLES_WITH_MACHINE_ID = [
|
|
1125
|
+
"projects",
|
|
1126
|
+
"tasks",
|
|
1127
|
+
"agents",
|
|
1128
|
+
"task_lists",
|
|
1129
|
+
"plans",
|
|
1130
|
+
"task_comments",
|
|
1131
|
+
"sessions",
|
|
1132
|
+
"task_history",
|
|
1133
|
+
"webhooks",
|
|
1134
|
+
"task_templates",
|
|
1135
|
+
"orgs",
|
|
1136
|
+
"handoffs",
|
|
1137
|
+
"task_checklists",
|
|
1138
|
+
"project_sources",
|
|
1139
|
+
"task_files",
|
|
1140
|
+
"task_relationships",
|
|
1141
|
+
"kg_edges",
|
|
1142
|
+
"project_agent_roles",
|
|
1143
|
+
"dispatches"
|
|
1144
|
+
];
|
|
1145
|
+
});
|
|
1146
|
+
|
|
1147
|
+
// src/db/database.ts
|
|
1148
|
+
import { Database } from "bun:sqlite";
|
|
1149
|
+
import { existsSync, mkdirSync } from "fs";
|
|
1150
|
+
import { dirname, join, resolve } from "path";
|
|
1151
|
+
function isInMemoryDb(path) {
|
|
1152
|
+
return path === ":memory:" || path.startsWith("file::memory:");
|
|
1153
|
+
}
|
|
1154
|
+
function findNearestTodosDb(startDir) {
|
|
1155
|
+
let dir = resolve(startDir);
|
|
1156
|
+
while (true) {
|
|
1157
|
+
const candidate = join(dir, ".todos", "todos.db");
|
|
1158
|
+
if (existsSync(candidate))
|
|
1159
|
+
return candidate;
|
|
1160
|
+
const parent = dirname(dir);
|
|
1161
|
+
if (parent === dir)
|
|
1162
|
+
break;
|
|
1163
|
+
dir = parent;
|
|
1164
|
+
}
|
|
1165
|
+
return null;
|
|
1166
|
+
}
|
|
1167
|
+
function findGitRoot(startDir) {
|
|
1168
|
+
let dir = resolve(startDir);
|
|
1169
|
+
while (true) {
|
|
1170
|
+
if (existsSync(join(dir, ".git")))
|
|
1171
|
+
return dir;
|
|
1172
|
+
const parent = dirname(dir);
|
|
1173
|
+
if (parent === dir)
|
|
1174
|
+
break;
|
|
1175
|
+
dir = parent;
|
|
1176
|
+
}
|
|
1177
|
+
return null;
|
|
1178
|
+
}
|
|
1179
|
+
function getDbPath() {
|
|
1180
|
+
if (process.env["HASNA_TODOS_DB_PATH"]) {
|
|
1181
|
+
return process.env["HASNA_TODOS_DB_PATH"];
|
|
1182
|
+
}
|
|
1183
|
+
if (process.env["TODOS_DB_PATH"]) {
|
|
1184
|
+
return process.env["TODOS_DB_PATH"];
|
|
1185
|
+
}
|
|
1186
|
+
const cwd = process.cwd();
|
|
1187
|
+
const nearest = findNearestTodosDb(cwd);
|
|
1188
|
+
if (nearest)
|
|
1189
|
+
return nearest;
|
|
1190
|
+
if (process.env["TODOS_DB_SCOPE"] === "project") {
|
|
1191
|
+
const gitRoot = findGitRoot(cwd);
|
|
1192
|
+
if (gitRoot) {
|
|
1193
|
+
return join(gitRoot, ".todos", "todos.db");
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
1197
|
+
const newPath = join(home, ".hasna", "todos", "todos.db");
|
|
1198
|
+
const legacyPath = join(home, ".todos", "todos.db");
|
|
1199
|
+
if (!existsSync(newPath) && existsSync(legacyPath)) {
|
|
1200
|
+
return legacyPath;
|
|
1201
|
+
}
|
|
1202
|
+
return newPath;
|
|
1203
|
+
}
|
|
1204
|
+
function ensureDir(filePath) {
|
|
1205
|
+
if (isInMemoryDb(filePath))
|
|
1206
|
+
return;
|
|
1207
|
+
const dir = dirname(resolve(filePath));
|
|
1208
|
+
if (!existsSync(dir)) {
|
|
1209
|
+
mkdirSync(dir, { recursive: true });
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
function getDatabase(dbPath) {
|
|
1213
|
+
if (_db)
|
|
1214
|
+
return _db;
|
|
1215
|
+
const path = dbPath || getDbPath();
|
|
1216
|
+
ensureDir(path);
|
|
1217
|
+
_db = new Database(path);
|
|
1218
|
+
_db.run("PRAGMA journal_mode = WAL");
|
|
1219
|
+
_db.run("PRAGMA busy_timeout = 5000");
|
|
1220
|
+
_db.run("PRAGMA foreign_keys = ON");
|
|
1221
|
+
runMigrations(_db);
|
|
1222
|
+
backfillTaskTags(_db);
|
|
1223
|
+
backfillMachineId(_db);
|
|
1224
|
+
return _db;
|
|
1225
|
+
}
|
|
1226
|
+
function closeDatabase() {
|
|
1227
|
+
if (_db) {
|
|
1228
|
+
_db.close();
|
|
1229
|
+
_db = null;
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
function resetDatabase() {
|
|
1233
|
+
_db = null;
|
|
1234
|
+
}
|
|
1235
|
+
function now() {
|
|
1236
|
+
return new Date().toISOString();
|
|
1237
|
+
}
|
|
1238
|
+
function uuid() {
|
|
1239
|
+
return crypto.randomUUID();
|
|
1240
|
+
}
|
|
1241
|
+
function isLockExpired(lockedAt) {
|
|
1242
|
+
if (!lockedAt)
|
|
1243
|
+
return true;
|
|
1244
|
+
const lockTime = new Date(lockedAt).getTime();
|
|
1245
|
+
const expiryMs = LOCK_EXPIRY_MINUTES * 60 * 1000;
|
|
1246
|
+
return Date.now() - lockTime > expiryMs;
|
|
1247
|
+
}
|
|
1248
|
+
function lockExpiryCutoff(nowMs = Date.now()) {
|
|
1249
|
+
const expiryMs = LOCK_EXPIRY_MINUTES * 60 * 1000;
|
|
1250
|
+
return new Date(nowMs - expiryMs).toISOString();
|
|
1251
|
+
}
|
|
1252
|
+
function clearExpiredLocks(db) {
|
|
1253
|
+
const cutoff = lockExpiryCutoff();
|
|
1254
|
+
db.run("UPDATE tasks SET locked_by = NULL, locked_at = NULL WHERE locked_at IS NOT NULL AND locked_at < ?", [cutoff]);
|
|
1255
|
+
}
|
|
1256
|
+
function resolvePartialId(db, table, partialId) {
|
|
1257
|
+
if (partialId.length >= 36) {
|
|
1258
|
+
const row = db.query(`SELECT id FROM ${table} WHERE id = ?`).get(partialId);
|
|
1259
|
+
return row?.id ?? null;
|
|
1260
|
+
}
|
|
1261
|
+
const rows = db.query(`SELECT id FROM ${table} WHERE id LIKE ?`).all(`${partialId}%`);
|
|
1262
|
+
if (rows.length === 1) {
|
|
1263
|
+
return rows[0].id;
|
|
1264
|
+
}
|
|
1265
|
+
if (rows.length > 1) {
|
|
1266
|
+
return null;
|
|
1267
|
+
}
|
|
1268
|
+
if (table === "tasks") {
|
|
1269
|
+
const shortIdRows = db.query("SELECT id FROM tasks WHERE short_id = ?").all(partialId);
|
|
1270
|
+
if (shortIdRows.length === 1) {
|
|
1271
|
+
return shortIdRows[0].id;
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
if (table === "task_lists") {
|
|
1275
|
+
const slugRow = db.query("SELECT id FROM task_lists WHERE slug = ?").get(partialId);
|
|
1276
|
+
if (slugRow)
|
|
1277
|
+
return slugRow.id;
|
|
1278
|
+
}
|
|
1279
|
+
if (table === "projects") {
|
|
1280
|
+
const nameRow = db.query("SELECT id FROM projects WHERE lower(name) = ?").get(partialId.toLowerCase());
|
|
1281
|
+
if (nameRow)
|
|
1282
|
+
return nameRow.id;
|
|
1283
|
+
}
|
|
1284
|
+
return null;
|
|
1285
|
+
}
|
|
1286
|
+
var LOCK_EXPIRY_MINUTES = 30, _db = null;
|
|
1287
|
+
var init_database = __esm(() => {
|
|
1288
|
+
init_schema();
|
|
1289
|
+
init_machines();
|
|
1290
|
+
});
|
|
1291
|
+
|
|
1099
1292
|
// src/types/index.ts
|
|
1100
1293
|
var TASK_STATUSES, TASK_PRIORITIES, PLAN_STATUSES, VersionConflictError, TaskNotFoundError, ProjectNotFoundError, PlanNotFoundError, LockError, AgentNotFoundError, TaskListNotFoundError, DependencyCycleError, CompletionGuardError, DISPATCH_STATUSES, DispatchNotFoundError;
|
|
1101
1294
|
var init_types = __esm(() => {
|
|
@@ -4595,6 +4788,10 @@ function cleanExpiredLocks(db) {
|
|
|
4595
4788
|
const result = d.run("DELETE FROM resource_locks WHERE expires_at < ?", [new Date().toISOString()]);
|
|
4596
4789
|
return result.changes;
|
|
4597
4790
|
}
|
|
4791
|
+
|
|
4792
|
+
// src/index.ts
|
|
4793
|
+
init_machines();
|
|
4794
|
+
|
|
4598
4795
|
// src/db/orgs.ts
|
|
4599
4796
|
init_database();
|
|
4600
4797
|
function rowToOrg(row) {
|
|
@@ -16764,6 +16961,7 @@ export {
|
|
|
16764
16961
|
runDueDispatches,
|
|
16765
16962
|
resolveVariables,
|
|
16766
16963
|
resolvePartialId,
|
|
16964
|
+
resetMachineId,
|
|
16767
16965
|
resetDatabase,
|
|
16768
16966
|
removeTaskRelationshipByPair,
|
|
16769
16967
|
removeTaskRelationship,
|
|
@@ -16804,6 +17002,7 @@ export {
|
|
|
16804
17002
|
listProjectSources,
|
|
16805
17003
|
listPlans,
|
|
16806
17004
|
listOrgs,
|
|
17005
|
+
listMachines,
|
|
16807
17006
|
listHandoffs,
|
|
16808
17007
|
listDispatches,
|
|
16809
17008
|
listDispatchLogs,
|
|
@@ -16850,7 +17049,11 @@ export {
|
|
|
16850
17049
|
getOrgChart,
|
|
16851
17050
|
getOrgByName,
|
|
16852
17051
|
getOrg,
|
|
17052
|
+
getOrCreateLocalMachine,
|
|
16853
17053
|
getNextTask,
|
|
17054
|
+
getMachineId,
|
|
17055
|
+
getMachineByName,
|
|
17056
|
+
getMachine,
|
|
16854
17057
|
getLeaderboard,
|
|
16855
17058
|
getLatestSnapshot,
|
|
16856
17059
|
getLatestHandoff,
|
|
@@ -16899,6 +17102,7 @@ export {
|
|
|
16899
17102
|
deleteProject,
|
|
16900
17103
|
deletePlan,
|
|
16901
17104
|
deleteOrg,
|
|
17105
|
+
deleteMachine,
|
|
16902
17106
|
deleteComment,
|
|
16903
17107
|
deleteAgent,
|
|
16904
17108
|
defaultSyncAgents,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { SyncPrefer, SyncResult } from "./sync-types.js";
|
|
2
|
+
export declare function pushToAgentTaskList(agent: string, taskListId: string, projectId?: string, options?: {
|
|
3
|
+
prefer?: SyncPrefer;
|
|
4
|
+
}): SyncResult;
|
|
5
|
+
export declare function pullFromAgentTaskList(agent: string, taskListId: string, projectId?: string, options?: {
|
|
6
|
+
prefer?: SyncPrefer;
|
|
7
|
+
}): SyncResult;
|
|
8
|
+
export declare function syncAgentTaskList(agent: string, taskListId: string, projectId?: string, options?: {
|
|
9
|
+
prefer?: SyncPrefer;
|
|
10
|
+
}): SyncResult;
|
|
11
|
+
//# sourceMappingURL=agent-tasks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-tasks.d.ts","sourceRoot":"","sources":["../../src/lib/agent-tasks.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AA+D9D,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAO,GACpC,UAAU,CAuFZ;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAO,GACpC,UAAU,CAoFZ;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAO,GACpC,UAAU,CAQZ"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-assign tasks to agents using Cerebras LLM for intelligent routing.
|
|
3
|
+
* Falls back to capability-based matching when the API key is unavailable or the call fails.
|
|
4
|
+
*/
|
|
5
|
+
import type { Database } from "bun:sqlite";
|
|
6
|
+
import type { Task } from "../types/index.js";
|
|
7
|
+
export interface AutoAssignResult {
|
|
8
|
+
task_id: string;
|
|
9
|
+
assigned_to: string | null;
|
|
10
|
+
agent_name: string | null;
|
|
11
|
+
method: "cerebras" | "capability_match" | "no_agents";
|
|
12
|
+
reason?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Find the best agent to assign a task to (legacy simple version, no I/O).
|
|
16
|
+
* Strategy: least-loaded agent with role "agent" (not admin/observer).
|
|
17
|
+
*/
|
|
18
|
+
export declare function findBestAgent(_task: Task, db?: Database): string | null;
|
|
19
|
+
/**
|
|
20
|
+
* Auto-assign a task to the best available agent.
|
|
21
|
+
* Uses Cerebras LLM (llama-3.3-70b) if CEREBRAS_API_KEY is set,
|
|
22
|
+
* otherwise falls back to capability-based matching.
|
|
23
|
+
*/
|
|
24
|
+
export declare function autoAssignTask(taskId: string, db?: Database): Promise<AutoAssignResult>;
|
|
25
|
+
//# sourceMappingURL=auto-assign.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-assign.d.ts","sourceRoot":"","sources":["../../src/lib/auto-assign.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAK9C,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,UAAU,GAAG,kBAAkB,GAAG,WAAW,CAAC;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAsBvE;AA8DD;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA8D7F"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Database } from "bun:sqlite";
|
|
2
|
+
export interface BurndownData {
|
|
3
|
+
total: number;
|
|
4
|
+
completed: number;
|
|
5
|
+
remaining: number;
|
|
6
|
+
days: {
|
|
7
|
+
date: string;
|
|
8
|
+
completed_cumulative: number;
|
|
9
|
+
ideal: number;
|
|
10
|
+
}[];
|
|
11
|
+
chart: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function getBurndown(opts: {
|
|
14
|
+
plan_id?: string;
|
|
15
|
+
project_id?: string;
|
|
16
|
+
task_list_id?: string;
|
|
17
|
+
}, db?: Database): BurndownData;
|
|
18
|
+
//# sourceMappingURL=burndown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"burndown.d.ts","sourceRoot":"","sources":["../../src/lib/burndown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAG3C,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,oBAAoB,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACtE,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,YAAY,CA8C/H"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { SyncPrefer, SyncResult } from "./sync-types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Push all SQLite tasks to a Claude Code task list directory.
|
|
4
|
+
*/
|
|
5
|
+
export declare function pushToClaudeTaskList(taskListId: string, projectId?: string, options?: {
|
|
6
|
+
prefer?: SyncPrefer;
|
|
7
|
+
}): SyncResult;
|
|
8
|
+
/**
|
|
9
|
+
* Pull tasks from a Claude Code task list into SQLite.
|
|
10
|
+
*/
|
|
11
|
+
export declare function pullFromClaudeTaskList(taskListId: string, projectId?: string, options?: {
|
|
12
|
+
prefer?: SyncPrefer;
|
|
13
|
+
}): SyncResult;
|
|
14
|
+
/**
|
|
15
|
+
* Bidirectional sync: pull first, then push.
|
|
16
|
+
*/
|
|
17
|
+
export declare function syncClaudeTaskList(taskListId: string, projectId?: string, options?: {
|
|
18
|
+
prefer?: SyncPrefer;
|
|
19
|
+
}): SyncResult;
|
|
20
|
+
//# sourceMappingURL=claude-tasks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-tasks.d.ts","sourceRoot":"","sources":["../../src/lib/claude-tasks.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAwF9D;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAO,GACpC,UAAU,CA4GZ;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAO,GACpC,UAAU,CAwFZ;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAO,GACpC,UAAU,CAQZ"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Database } from "bun:sqlite";
|
|
2
|
+
import type { Task } from "../types/index.js";
|
|
3
|
+
import { type CompletionGuardConfig } from "./config.js";
|
|
4
|
+
/**
|
|
5
|
+
* Checks completion guards before allowing a task to be marked as completed.
|
|
6
|
+
* Throws CompletionGuardError if any guard condition is violated.
|
|
7
|
+
*
|
|
8
|
+
* Guards:
|
|
9
|
+
* 1. Status check — task must be in_progress
|
|
10
|
+
* 2. Minimum work duration — must have spent enough time since startTask()
|
|
11
|
+
* 3. Rate limit — max completions per agent per time window
|
|
12
|
+
* 4. Cooldown — minimum gap between consecutive completions
|
|
13
|
+
*
|
|
14
|
+
* @param configOverride - Optional config override (used in tests)
|
|
15
|
+
*/
|
|
16
|
+
export declare function checkCompletionGuard(task: Task, agentId: string | null, db: Database, configOverride?: Required<CompletionGuardConfig>): void;
|
|
17
|
+
//# sourceMappingURL=completion-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"completion-guard.d.ts","sourceRoot":"","sources":["../../src/lib/completion-guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAE9C,OAAO,EAA4B,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAGnF;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,EAAE,EAAE,QAAQ,EACZ,cAAc,CAAC,EAAE,QAAQ,CAAC,qBAAqB,CAAC,GAC/C,IAAI,CAyEN"}
|