@hasna/todos 0.9.20 → 0.9.21
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.
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>Hasna Todos</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-DVzieYOj.js"></script>
|
|
8
8
|
<link rel="stylesheet" crossorigin href="/assets/index-DWpVlvWb.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
package/dist/cli/index.js
CHANGED
|
@@ -9495,6 +9495,59 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
9495
9495
|
return json({ error: e instanceof Error ? e.message : "Failed" }, 500, port);
|
|
9496
9496
|
}
|
|
9497
9497
|
}
|
|
9498
|
+
if (path === "/api/activity" && method === "GET") {
|
|
9499
|
+
const limit = parseInt(url.searchParams.get("limit") || "50", 10);
|
|
9500
|
+
const { getRecentActivity: getRecentActivity2 } = await Promise.resolve().then(() => (init_audit(), exports_audit));
|
|
9501
|
+
return json(getRecentActivity2(limit), 200, port);
|
|
9502
|
+
}
|
|
9503
|
+
const historyMatch = path.match(/^\/api\/tasks\/([^/]+)\/history$/);
|
|
9504
|
+
if (historyMatch && method === "GET") {
|
|
9505
|
+
const id = historyMatch[1];
|
|
9506
|
+
const { getTaskHistory: getTaskHistory2 } = await Promise.resolve().then(() => (init_audit(), exports_audit));
|
|
9507
|
+
return json(getTaskHistory2(id), 200, port);
|
|
9508
|
+
}
|
|
9509
|
+
if (path === "/api/webhooks" && method === "GET") {
|
|
9510
|
+
const { listWebhooks: listWebhooks2 } = await Promise.resolve().then(() => (init_webhooks(), exports_webhooks));
|
|
9511
|
+
return json(listWebhooks2(), 200, port);
|
|
9512
|
+
}
|
|
9513
|
+
if (path === "/api/webhooks" && method === "POST") {
|
|
9514
|
+
try {
|
|
9515
|
+
const body = await req.json();
|
|
9516
|
+
if (!body.url)
|
|
9517
|
+
return json({ error: "Missing url" }, 400, port);
|
|
9518
|
+
const { createWebhook: createWebhook2 } = await Promise.resolve().then(() => (init_webhooks(), exports_webhooks));
|
|
9519
|
+
return json(createWebhook2(body), 201, port);
|
|
9520
|
+
} catch (e) {
|
|
9521
|
+
return json({ error: e instanceof Error ? e.message : "Failed" }, 500, port);
|
|
9522
|
+
}
|
|
9523
|
+
}
|
|
9524
|
+
const webhookMatch = path.match(/^\/api\/webhooks\/([^/]+)$/);
|
|
9525
|
+
if (webhookMatch && method === "DELETE") {
|
|
9526
|
+
const { deleteWebhook: deleteWebhook2 } = await Promise.resolve().then(() => (init_webhooks(), exports_webhooks));
|
|
9527
|
+
const deleted = deleteWebhook2(webhookMatch[1]);
|
|
9528
|
+
return json(deleted ? { success: true } : { error: "Not found" }, deleted ? 200 : 404, port);
|
|
9529
|
+
}
|
|
9530
|
+
if (path === "/api/templates" && method === "GET") {
|
|
9531
|
+
const { listTemplates: listTemplates2 } = await Promise.resolve().then(() => (init_templates(), exports_templates));
|
|
9532
|
+
return json(listTemplates2(), 200, port);
|
|
9533
|
+
}
|
|
9534
|
+
if (path === "/api/templates" && method === "POST") {
|
|
9535
|
+
try {
|
|
9536
|
+
const body = await req.json();
|
|
9537
|
+
if (!body.name || !body.title_pattern)
|
|
9538
|
+
return json({ error: "Missing name or title_pattern" }, 400, port);
|
|
9539
|
+
const { createTemplate: createTemplate2 } = await Promise.resolve().then(() => (init_templates(), exports_templates));
|
|
9540
|
+
return json(createTemplate2(body), 201, port);
|
|
9541
|
+
} catch (e) {
|
|
9542
|
+
return json({ error: e instanceof Error ? e.message : "Failed" }, 500, port);
|
|
9543
|
+
}
|
|
9544
|
+
}
|
|
9545
|
+
const templateMatch = path.match(/^\/api\/templates\/([^/]+)$/);
|
|
9546
|
+
if (templateMatch && method === "DELETE") {
|
|
9547
|
+
const { deleteTemplate: deleteTemplate2 } = await Promise.resolve().then(() => (init_templates(), exports_templates));
|
|
9548
|
+
const deleted = deleteTemplate2(templateMatch[1]);
|
|
9549
|
+
return json(deleted ? { success: true } : { error: "Not found" }, deleted ? 200 : 404, port);
|
|
9550
|
+
}
|
|
9498
9551
|
if (path === "/api/plans" && method === "GET") {
|
|
9499
9552
|
const projectId = url.searchParams.get("project_id") || undefined;
|
|
9500
9553
|
const plans = listPlans(projectId);
|
package/dist/server/index.js
CHANGED
|
@@ -646,6 +646,33 @@ var init_projects = __esm(() => {
|
|
|
646
646
|
init_database();
|
|
647
647
|
});
|
|
648
648
|
|
|
649
|
+
// src/db/audit.ts
|
|
650
|
+
var exports_audit = {};
|
|
651
|
+
__export(exports_audit, {
|
|
652
|
+
logTaskChange: () => logTaskChange,
|
|
653
|
+
getTaskHistory: () => getTaskHistory,
|
|
654
|
+
getRecentActivity: () => getRecentActivity
|
|
655
|
+
});
|
|
656
|
+
function logTaskChange(taskId, action, field, oldValue, newValue, agentId, db) {
|
|
657
|
+
const d = db || getDatabase();
|
|
658
|
+
const id = uuid();
|
|
659
|
+
const timestamp = now();
|
|
660
|
+
d.run(`INSERT INTO task_history (id, task_id, action, field, old_value, new_value, agent_id, created_at)
|
|
661
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [id, taskId, action, field || null, oldValue ?? null, newValue ?? null, agentId || null, timestamp]);
|
|
662
|
+
return { id, task_id: taskId, action, field: field || null, old_value: oldValue ?? null, new_value: newValue ?? null, agent_id: agentId || null, created_at: timestamp };
|
|
663
|
+
}
|
|
664
|
+
function getTaskHistory(taskId, db) {
|
|
665
|
+
const d = db || getDatabase();
|
|
666
|
+
return d.query("SELECT * FROM task_history WHERE task_id = ? ORDER BY created_at DESC").all(taskId);
|
|
667
|
+
}
|
|
668
|
+
function getRecentActivity(limit = 50, db) {
|
|
669
|
+
const d = db || getDatabase();
|
|
670
|
+
return d.query("SELECT * FROM task_history ORDER BY created_at DESC LIMIT ?").all(limit);
|
|
671
|
+
}
|
|
672
|
+
var init_audit = __esm(() => {
|
|
673
|
+
init_database();
|
|
674
|
+
});
|
|
675
|
+
|
|
649
676
|
// src/db/agents.ts
|
|
650
677
|
var exports_agents = {};
|
|
651
678
|
__export(exports_agents, {
|
|
@@ -746,6 +773,124 @@ var init_agents = __esm(() => {
|
|
|
746
773
|
init_database();
|
|
747
774
|
});
|
|
748
775
|
|
|
776
|
+
// src/db/webhooks.ts
|
|
777
|
+
var exports_webhooks = {};
|
|
778
|
+
__export(exports_webhooks, {
|
|
779
|
+
listWebhooks: () => listWebhooks,
|
|
780
|
+
getWebhook: () => getWebhook,
|
|
781
|
+
dispatchWebhook: () => dispatchWebhook,
|
|
782
|
+
deleteWebhook: () => deleteWebhook,
|
|
783
|
+
createWebhook: () => createWebhook
|
|
784
|
+
});
|
|
785
|
+
function rowToWebhook(row) {
|
|
786
|
+
return { ...row, events: JSON.parse(row.events || "[]"), active: !!row.active };
|
|
787
|
+
}
|
|
788
|
+
function createWebhook(input, db) {
|
|
789
|
+
const d = db || getDatabase();
|
|
790
|
+
const id = uuid();
|
|
791
|
+
d.run(`INSERT INTO webhooks (id, url, events, secret, created_at) VALUES (?, ?, ?, ?, ?)`, [id, input.url, JSON.stringify(input.events || []), input.secret || null, now()]);
|
|
792
|
+
return getWebhook(id, d);
|
|
793
|
+
}
|
|
794
|
+
function getWebhook(id, db) {
|
|
795
|
+
const d = db || getDatabase();
|
|
796
|
+
const row = d.query("SELECT * FROM webhooks WHERE id = ?").get(id);
|
|
797
|
+
return row ? rowToWebhook(row) : null;
|
|
798
|
+
}
|
|
799
|
+
function listWebhooks(db) {
|
|
800
|
+
const d = db || getDatabase();
|
|
801
|
+
return d.query("SELECT * FROM webhooks ORDER BY created_at DESC").all().map(rowToWebhook);
|
|
802
|
+
}
|
|
803
|
+
function deleteWebhook(id, db) {
|
|
804
|
+
const d = db || getDatabase();
|
|
805
|
+
return d.run("DELETE FROM webhooks WHERE id = ?", [id]).changes > 0;
|
|
806
|
+
}
|
|
807
|
+
async function dispatchWebhook(event, payload, db) {
|
|
808
|
+
const webhooks = listWebhooks(db).filter((w) => w.active && (w.events.length === 0 || w.events.includes(event)));
|
|
809
|
+
for (const wh of webhooks) {
|
|
810
|
+
try {
|
|
811
|
+
const body = JSON.stringify({ event, payload, timestamp: now() });
|
|
812
|
+
const headers = { "Content-Type": "application/json" };
|
|
813
|
+
if (wh.secret) {
|
|
814
|
+
const encoder = new TextEncoder;
|
|
815
|
+
const key = await crypto.subtle.importKey("raw", encoder.encode(wh.secret), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
816
|
+
const sig = await crypto.subtle.sign("HMAC", key, encoder.encode(body));
|
|
817
|
+
headers["X-Webhook-Signature"] = Array.from(new Uint8Array(sig)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
818
|
+
}
|
|
819
|
+
fetch(wh.url, { method: "POST", headers, body }).catch(() => {});
|
|
820
|
+
} catch {}
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
var init_webhooks = __esm(() => {
|
|
824
|
+
init_database();
|
|
825
|
+
});
|
|
826
|
+
|
|
827
|
+
// src/db/templates.ts
|
|
828
|
+
var exports_templates = {};
|
|
829
|
+
__export(exports_templates, {
|
|
830
|
+
taskFromTemplate: () => taskFromTemplate,
|
|
831
|
+
listTemplates: () => listTemplates,
|
|
832
|
+
getTemplate: () => getTemplate,
|
|
833
|
+
deleteTemplate: () => deleteTemplate,
|
|
834
|
+
createTemplate: () => createTemplate
|
|
835
|
+
});
|
|
836
|
+
function rowToTemplate(row) {
|
|
837
|
+
return {
|
|
838
|
+
...row,
|
|
839
|
+
tags: JSON.parse(row.tags || "[]"),
|
|
840
|
+
metadata: JSON.parse(row.metadata || "{}"),
|
|
841
|
+
priority: row.priority || "medium"
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
function createTemplate(input, db) {
|
|
845
|
+
const d = db || getDatabase();
|
|
846
|
+
const id = uuid();
|
|
847
|
+
d.run(`INSERT INTO task_templates (id, name, title_pattern, description, priority, tags, project_id, plan_id, metadata, created_at)
|
|
848
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
849
|
+
id,
|
|
850
|
+
input.name,
|
|
851
|
+
input.title_pattern,
|
|
852
|
+
input.description || null,
|
|
853
|
+
input.priority || "medium",
|
|
854
|
+
JSON.stringify(input.tags || []),
|
|
855
|
+
input.project_id || null,
|
|
856
|
+
input.plan_id || null,
|
|
857
|
+
JSON.stringify(input.metadata || {}),
|
|
858
|
+
now()
|
|
859
|
+
]);
|
|
860
|
+
return getTemplate(id, d);
|
|
861
|
+
}
|
|
862
|
+
function getTemplate(id, db) {
|
|
863
|
+
const d = db || getDatabase();
|
|
864
|
+
const row = d.query("SELECT * FROM task_templates WHERE id = ?").get(id);
|
|
865
|
+
return row ? rowToTemplate(row) : null;
|
|
866
|
+
}
|
|
867
|
+
function listTemplates(db) {
|
|
868
|
+
const d = db || getDatabase();
|
|
869
|
+
return d.query("SELECT * FROM task_templates ORDER BY name").all().map(rowToTemplate);
|
|
870
|
+
}
|
|
871
|
+
function deleteTemplate(id, db) {
|
|
872
|
+
const d = db || getDatabase();
|
|
873
|
+
return d.run("DELETE FROM task_templates WHERE id = ?", [id]).changes > 0;
|
|
874
|
+
}
|
|
875
|
+
function taskFromTemplate(templateId, overrides = {}, db) {
|
|
876
|
+
const t = getTemplate(templateId, db);
|
|
877
|
+
if (!t)
|
|
878
|
+
throw new Error(`Template not found: ${templateId}`);
|
|
879
|
+
return {
|
|
880
|
+
title: overrides.title || t.title_pattern,
|
|
881
|
+
description: overrides.description ?? t.description ?? undefined,
|
|
882
|
+
priority: overrides.priority ?? t.priority,
|
|
883
|
+
tags: overrides.tags ?? t.tags,
|
|
884
|
+
project_id: overrides.project_id ?? t.project_id ?? undefined,
|
|
885
|
+
plan_id: overrides.plan_id ?? t.plan_id ?? undefined,
|
|
886
|
+
metadata: overrides.metadata ?? t.metadata,
|
|
887
|
+
...overrides
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
var init_templates = __esm(() => {
|
|
891
|
+
init_database();
|
|
892
|
+
});
|
|
893
|
+
|
|
749
894
|
// src/server/serve.ts
|
|
750
895
|
import { existsSync as existsSync4 } from "fs";
|
|
751
896
|
import { join as join3, dirname as dirname2, extname } from "path";
|
|
@@ -852,18 +997,8 @@ function checkCompletionGuard(task, agentId, db, configOverride) {
|
|
|
852
997
|
}
|
|
853
998
|
}
|
|
854
999
|
|
|
855
|
-
// src/db/audit.ts
|
|
856
|
-
init_database();
|
|
857
|
-
function logTaskChange(taskId, action, field, oldValue, newValue, agentId, db) {
|
|
858
|
-
const d = db || getDatabase();
|
|
859
|
-
const id = uuid();
|
|
860
|
-
const timestamp = now();
|
|
861
|
-
d.run(`INSERT INTO task_history (id, task_id, action, field, old_value, new_value, agent_id, created_at)
|
|
862
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [id, taskId, action, field || null, oldValue ?? null, newValue ?? null, agentId || null, timestamp]);
|
|
863
|
-
return { id, task_id: taskId, action, field: field || null, old_value: oldValue ?? null, new_value: newValue ?? null, agent_id: agentId || null, created_at: timestamp };
|
|
864
|
-
}
|
|
865
|
-
|
|
866
1000
|
// src/db/tasks.ts
|
|
1001
|
+
init_audit();
|
|
867
1002
|
function rowToTask(row) {
|
|
868
1003
|
return {
|
|
869
1004
|
...row,
|
|
@@ -1563,6 +1698,59 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
1563
1698
|
return json({ error: e instanceof Error ? e.message : "Failed" }, 500, port);
|
|
1564
1699
|
}
|
|
1565
1700
|
}
|
|
1701
|
+
if (path === "/api/activity" && method === "GET") {
|
|
1702
|
+
const limit = parseInt(url.searchParams.get("limit") || "50", 10);
|
|
1703
|
+
const { getRecentActivity: getRecentActivity2 } = await Promise.resolve().then(() => (init_audit(), exports_audit));
|
|
1704
|
+
return json(getRecentActivity2(limit), 200, port);
|
|
1705
|
+
}
|
|
1706
|
+
const historyMatch = path.match(/^\/api\/tasks\/([^/]+)\/history$/);
|
|
1707
|
+
if (historyMatch && method === "GET") {
|
|
1708
|
+
const id = historyMatch[1];
|
|
1709
|
+
const { getTaskHistory: getTaskHistory2 } = await Promise.resolve().then(() => (init_audit(), exports_audit));
|
|
1710
|
+
return json(getTaskHistory2(id), 200, port);
|
|
1711
|
+
}
|
|
1712
|
+
if (path === "/api/webhooks" && method === "GET") {
|
|
1713
|
+
const { listWebhooks: listWebhooks2 } = await Promise.resolve().then(() => (init_webhooks(), exports_webhooks));
|
|
1714
|
+
return json(listWebhooks2(), 200, port);
|
|
1715
|
+
}
|
|
1716
|
+
if (path === "/api/webhooks" && method === "POST") {
|
|
1717
|
+
try {
|
|
1718
|
+
const body = await req.json();
|
|
1719
|
+
if (!body.url)
|
|
1720
|
+
return json({ error: "Missing url" }, 400, port);
|
|
1721
|
+
const { createWebhook: createWebhook2 } = await Promise.resolve().then(() => (init_webhooks(), exports_webhooks));
|
|
1722
|
+
return json(createWebhook2(body), 201, port);
|
|
1723
|
+
} catch (e) {
|
|
1724
|
+
return json({ error: e instanceof Error ? e.message : "Failed" }, 500, port);
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
const webhookMatch = path.match(/^\/api\/webhooks\/([^/]+)$/);
|
|
1728
|
+
if (webhookMatch && method === "DELETE") {
|
|
1729
|
+
const { deleteWebhook: deleteWebhook2 } = await Promise.resolve().then(() => (init_webhooks(), exports_webhooks));
|
|
1730
|
+
const deleted = deleteWebhook2(webhookMatch[1]);
|
|
1731
|
+
return json(deleted ? { success: true } : { error: "Not found" }, deleted ? 200 : 404, port);
|
|
1732
|
+
}
|
|
1733
|
+
if (path === "/api/templates" && method === "GET") {
|
|
1734
|
+
const { listTemplates: listTemplates2 } = await Promise.resolve().then(() => (init_templates(), exports_templates));
|
|
1735
|
+
return json(listTemplates2(), 200, port);
|
|
1736
|
+
}
|
|
1737
|
+
if (path === "/api/templates" && method === "POST") {
|
|
1738
|
+
try {
|
|
1739
|
+
const body = await req.json();
|
|
1740
|
+
if (!body.name || !body.title_pattern)
|
|
1741
|
+
return json({ error: "Missing name or title_pattern" }, 400, port);
|
|
1742
|
+
const { createTemplate: createTemplate2 } = await Promise.resolve().then(() => (init_templates(), exports_templates));
|
|
1743
|
+
return json(createTemplate2(body), 201, port);
|
|
1744
|
+
} catch (e) {
|
|
1745
|
+
return json({ error: e instanceof Error ? e.message : "Failed" }, 500, port);
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
const templateMatch = path.match(/^\/api\/templates\/([^/]+)$/);
|
|
1749
|
+
if (templateMatch && method === "DELETE") {
|
|
1750
|
+
const { deleteTemplate: deleteTemplate2 } = await Promise.resolve().then(() => (init_templates(), exports_templates));
|
|
1751
|
+
const deleted = deleteTemplate2(templateMatch[1]);
|
|
1752
|
+
return json(deleted ? { success: true } : { error: "Not found" }, deleted ? 200 : 404, port);
|
|
1753
|
+
}
|
|
1566
1754
|
if (path === "/api/plans" && method === "GET") {
|
|
1567
1755
|
const projectId = url.searchParams.get("project_id") || undefined;
|
|
1568
1756
|
const plans = listPlans(projectId);
|