@hasna/todos 0.11.21 → 0.11.23
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/dist/cli/index.js +228 -207
- package/dist/db/pg-migrations.d.ts.map +1 -1
- package/dist/db/projects.d.ts.map +1 -1
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/tasks.d.ts.map +1 -1
- package/dist/index.js +180 -166
- package/dist/mcp/index.js +194 -191
- package/dist/server/index.js +114 -107
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -1168,6 +1168,12 @@ var init_schema = __esm(() => {
|
|
|
1168
1168
|
ALTER TABLE tasks ADD COLUMN archived_at TEXT;
|
|
1169
1169
|
CREATE INDEX IF NOT EXISTS idx_tasks_archived ON tasks(archived_at) WHERE archived_at IS NOT NULL;
|
|
1170
1170
|
INSERT OR IGNORE INTO _migrations (id) VALUES (43);
|
|
1171
|
+
`,
|
|
1172
|
+
`
|
|
1173
|
+
DROP INDEX IF EXISTS idx_tasks_short_id;
|
|
1174
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_tasks_short_id ON tasks(short_id, machine_id) WHERE short_id IS NOT NULL AND machine_id IS NOT NULL;
|
|
1175
|
+
CREATE INDEX IF NOT EXISTS idx_tasks_short_id_lookup ON tasks(short_id) WHERE short_id IS NOT NULL;
|
|
1176
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (44);
|
|
1171
1177
|
`
|
|
1172
1178
|
];
|
|
1173
1179
|
});
|
|
@@ -1376,6 +1382,68 @@ var init_database = __esm(() => {
|
|
|
1376
1382
|
init_machines();
|
|
1377
1383
|
});
|
|
1378
1384
|
|
|
1385
|
+
// src/lib/sync-utils.ts
|
|
1386
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
|
|
1387
|
+
function readJsonFile(path) {
|
|
1388
|
+
try {
|
|
1389
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
1390
|
+
} catch {
|
|
1391
|
+
return null;
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
var HOME;
|
|
1395
|
+
var init_sync_utils = __esm(() => {
|
|
1396
|
+
HOME = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
1397
|
+
});
|
|
1398
|
+
|
|
1399
|
+
// src/lib/config.ts
|
|
1400
|
+
import { existsSync as existsSync3 } from "fs";
|
|
1401
|
+
import { join as join2 } from "path";
|
|
1402
|
+
function getTodosGlobalDir() {
|
|
1403
|
+
const home = process.env["HOME"] || HOME;
|
|
1404
|
+
const newDir = join2(home, ".hasna", "todos");
|
|
1405
|
+
const legacyDir = join2(home, ".todos");
|
|
1406
|
+
if (!existsSync3(newDir) && existsSync3(legacyDir))
|
|
1407
|
+
return legacyDir;
|
|
1408
|
+
return newDir;
|
|
1409
|
+
}
|
|
1410
|
+
function getConfigPath() {
|
|
1411
|
+
return join2(getTodosGlobalDir(), "config.json");
|
|
1412
|
+
}
|
|
1413
|
+
function loadConfig() {
|
|
1414
|
+
if (cached)
|
|
1415
|
+
return cached;
|
|
1416
|
+
if (!existsSync3(getConfigPath())) {
|
|
1417
|
+
cached = {};
|
|
1418
|
+
return cached;
|
|
1419
|
+
}
|
|
1420
|
+
const config = readJsonFile(getConfigPath()) || {};
|
|
1421
|
+
if (typeof config.sync_agents === "string") {
|
|
1422
|
+
config.sync_agents = config.sync_agents.split(",").map((a) => a.trim()).filter(Boolean);
|
|
1423
|
+
}
|
|
1424
|
+
cached = config;
|
|
1425
|
+
return cached;
|
|
1426
|
+
}
|
|
1427
|
+
function getCompletionGuardConfig(projectPath) {
|
|
1428
|
+
const config = loadConfig();
|
|
1429
|
+
const global = { ...GUARD_DEFAULTS, ...config.completion_guard };
|
|
1430
|
+
if (projectPath && config.project_overrides?.[projectPath]?.completion_guard) {
|
|
1431
|
+
return { ...global, ...config.project_overrides[projectPath].completion_guard };
|
|
1432
|
+
}
|
|
1433
|
+
return global;
|
|
1434
|
+
}
|
|
1435
|
+
var cached = null, GUARD_DEFAULTS;
|
|
1436
|
+
var init_config = __esm(() => {
|
|
1437
|
+
init_sync_utils();
|
|
1438
|
+
GUARD_DEFAULTS = {
|
|
1439
|
+
enabled: false,
|
|
1440
|
+
min_work_seconds: 30,
|
|
1441
|
+
max_completions_per_window: 5,
|
|
1442
|
+
window_minutes: 10,
|
|
1443
|
+
cooldown_seconds: 60
|
|
1444
|
+
};
|
|
1445
|
+
});
|
|
1446
|
+
|
|
1379
1447
|
// src/db/projects.ts
|
|
1380
1448
|
var exports_projects = {};
|
|
1381
1449
|
__export(exports_projects, {
|
|
@@ -1557,13 +1625,6 @@ function nextTaskShortId(projectId, db) {
|
|
|
1557
1625
|
const project = getProject(projectId, d);
|
|
1558
1626
|
if (!project || !project.task_prefix)
|
|
1559
1627
|
return null;
|
|
1560
|
-
const prefix = project.task_prefix;
|
|
1561
|
-
const prefixLen = prefix.length + 2;
|
|
1562
|
-
const maxRow = d.query(`SELECT MAX(CAST(SUBSTR(short_id, ?) AS INTEGER)) as max_counter FROM tasks WHERE short_id LIKE ?`).get(prefixLen, `${prefix}-%`);
|
|
1563
|
-
const syncedMax = maxRow?.max_counter ?? 0;
|
|
1564
|
-
if (syncedMax >= (project.task_counter ?? 0)) {
|
|
1565
|
-
d.run("UPDATE projects SET task_counter = ?, updated_at = ? WHERE id = ?", [syncedMax, now(), projectId]);
|
|
1566
|
-
}
|
|
1567
1628
|
d.run("UPDATE projects SET task_counter = task_counter + 1, updated_at = ? WHERE id = ?", [now(), projectId]);
|
|
1568
1629
|
const updated = getProject(projectId, d);
|
|
1569
1630
|
const padded = String(updated.task_counter).padStart(5, "0");
|
|
@@ -1627,68 +1688,6 @@ var init_projects = __esm(() => {
|
|
|
1627
1688
|
init_machines();
|
|
1628
1689
|
});
|
|
1629
1690
|
|
|
1630
|
-
// src/lib/sync-utils.ts
|
|
1631
|
-
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
|
|
1632
|
-
function readJsonFile(path) {
|
|
1633
|
-
try {
|
|
1634
|
-
return JSON.parse(readFileSync(path, "utf-8"));
|
|
1635
|
-
} catch {
|
|
1636
|
-
return null;
|
|
1637
|
-
}
|
|
1638
|
-
}
|
|
1639
|
-
var HOME;
|
|
1640
|
-
var init_sync_utils = __esm(() => {
|
|
1641
|
-
HOME = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
1642
|
-
});
|
|
1643
|
-
|
|
1644
|
-
// src/lib/config.ts
|
|
1645
|
-
import { existsSync as existsSync3 } from "fs";
|
|
1646
|
-
import { join as join2 } from "path";
|
|
1647
|
-
function getTodosGlobalDir() {
|
|
1648
|
-
const home = process.env["HOME"] || HOME;
|
|
1649
|
-
const newDir = join2(home, ".hasna", "todos");
|
|
1650
|
-
const legacyDir = join2(home, ".todos");
|
|
1651
|
-
if (!existsSync3(newDir) && existsSync3(legacyDir))
|
|
1652
|
-
return legacyDir;
|
|
1653
|
-
return newDir;
|
|
1654
|
-
}
|
|
1655
|
-
function getConfigPath() {
|
|
1656
|
-
return join2(getTodosGlobalDir(), "config.json");
|
|
1657
|
-
}
|
|
1658
|
-
function loadConfig() {
|
|
1659
|
-
if (cached)
|
|
1660
|
-
return cached;
|
|
1661
|
-
if (!existsSync3(getConfigPath())) {
|
|
1662
|
-
cached = {};
|
|
1663
|
-
return cached;
|
|
1664
|
-
}
|
|
1665
|
-
const config = readJsonFile(getConfigPath()) || {};
|
|
1666
|
-
if (typeof config.sync_agents === "string") {
|
|
1667
|
-
config.sync_agents = config.sync_agents.split(",").map((a) => a.trim()).filter(Boolean);
|
|
1668
|
-
}
|
|
1669
|
-
cached = config;
|
|
1670
|
-
return cached;
|
|
1671
|
-
}
|
|
1672
|
-
function getCompletionGuardConfig(projectPath) {
|
|
1673
|
-
const config = loadConfig();
|
|
1674
|
-
const global = { ...GUARD_DEFAULTS, ...config.completion_guard };
|
|
1675
|
-
if (projectPath && config.project_overrides?.[projectPath]?.completion_guard) {
|
|
1676
|
-
return { ...global, ...config.project_overrides[projectPath].completion_guard };
|
|
1677
|
-
}
|
|
1678
|
-
return global;
|
|
1679
|
-
}
|
|
1680
|
-
var cached = null, GUARD_DEFAULTS;
|
|
1681
|
-
var init_config = __esm(() => {
|
|
1682
|
-
init_sync_utils();
|
|
1683
|
-
GUARD_DEFAULTS = {
|
|
1684
|
-
enabled: false,
|
|
1685
|
-
min_work_seconds: 30,
|
|
1686
|
-
max_completions_per_window: 5,
|
|
1687
|
-
window_minutes: 10,
|
|
1688
|
-
cooldown_seconds: 60
|
|
1689
|
-
};
|
|
1690
|
-
});
|
|
1691
|
-
|
|
1692
1691
|
// src/lib/completion-guard.ts
|
|
1693
1692
|
function checkCompletionGuard(task, agentId, db, configOverride) {
|
|
1694
1693
|
let config;
|
|
@@ -2534,47 +2533,56 @@ function replaceTaskTags(taskId, tags, db) {
|
|
|
2534
2533
|
}
|
|
2535
2534
|
function createTask(input, db) {
|
|
2536
2535
|
const d = db || getDatabase();
|
|
2537
|
-
const id = uuid();
|
|
2538
2536
|
const timestamp = now();
|
|
2539
2537
|
const tags = input.tags || [];
|
|
2540
|
-
const shortId = input.project_id ? nextTaskShortId(input.project_id, d) : null;
|
|
2541
|
-
const title = shortId ? `${shortId}: ${input.title}` : input.title;
|
|
2542
2538
|
const assignedBy = input.assigned_by || input.agent_id;
|
|
2543
2539
|
const assignedFromProject = input.assigned_from_project || null;
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2540
|
+
let id = uuid();
|
|
2541
|
+
for (let attempt = 0;attempt < 3; attempt++) {
|
|
2542
|
+
try {
|
|
2543
|
+
d.run(`INSERT INTO tasks (id, short_id, project_id, parent_id, plan_id, task_list_id, title, description, status, priority, agent_id, assigned_to, session_id, working_dir, tags, metadata, version, created_at, updated_at, due_at, estimated_minutes, requires_approval, approved_by, approved_at, recurrence_rule, recurrence_parent_id, spawns_template_id, reason, spawned_from_session, assigned_by, assigned_from_project, task_type)
|
|
2544
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
2545
|
+
id,
|
|
2546
|
+
null,
|
|
2547
|
+
input.project_id || null,
|
|
2548
|
+
input.parent_id || null,
|
|
2549
|
+
input.plan_id || null,
|
|
2550
|
+
input.task_list_id || null,
|
|
2551
|
+
input.title,
|
|
2552
|
+
input.description || null,
|
|
2553
|
+
input.status || "pending",
|
|
2554
|
+
input.priority || "medium",
|
|
2555
|
+
input.agent_id || null,
|
|
2556
|
+
input.assigned_to || null,
|
|
2557
|
+
input.session_id || null,
|
|
2558
|
+
input.working_dir || null,
|
|
2559
|
+
JSON.stringify(tags),
|
|
2560
|
+
JSON.stringify(input.metadata || {}),
|
|
2561
|
+
timestamp,
|
|
2562
|
+
timestamp,
|
|
2563
|
+
input.due_at || null,
|
|
2564
|
+
input.estimated_minutes || null,
|
|
2565
|
+
input.requires_approval ? 1 : 0,
|
|
2566
|
+
null,
|
|
2567
|
+
null,
|
|
2568
|
+
input.recurrence_rule || null,
|
|
2569
|
+
input.recurrence_parent_id || null,
|
|
2570
|
+
input.spawns_template_id || null,
|
|
2571
|
+
input.reason || null,
|
|
2572
|
+
input.spawned_from_session || null,
|
|
2573
|
+
assignedBy || null,
|
|
2574
|
+
assignedFromProject || null,
|
|
2575
|
+
input.task_type || null
|
|
2576
|
+
]);
|
|
2577
|
+
break;
|
|
2578
|
+
} catch (e) {
|
|
2579
|
+
if (attempt < 2 && e?.message?.includes("UNIQUE constraint failed: tasks.id")) {
|
|
2580
|
+
id = uuid();
|
|
2581
|
+
continue;
|
|
2582
|
+
}
|
|
2583
|
+
throw e;
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2578
2586
|
if (tags.length > 0) {
|
|
2579
2587
|
insertTaskTags(id, tags, d);
|
|
2580
2588
|
}
|
|
@@ -3660,7 +3668,6 @@ function getOverdueTasks(projectId, db) {
|
|
|
3660
3668
|
var init_tasks = __esm(() => {
|
|
3661
3669
|
init_types();
|
|
3662
3670
|
init_database();
|
|
3663
|
-
init_projects();
|
|
3664
3671
|
init_completion_guard();
|
|
3665
3672
|
init_audit();
|
|
3666
3673
|
init_recurrence();
|