@hasna/todos 0.11.43 → 0.11.45

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/README.md +573 -11
  2. package/dist/cli/commands/agent-reliability-commands.d.ts +3 -0
  3. package/dist/cli/commands/agent-reliability-commands.d.ts.map +1 -0
  4. package/dist/cli/commands/audit-ledger-commands.d.ts +3 -0
  5. package/dist/cli/commands/audit-ledger-commands.d.ts.map +1 -0
  6. package/dist/cli/commands/capacity-commands.d.ts +3 -0
  7. package/dist/cli/commands/capacity-commands.d.ts.map +1 -0
  8. package/dist/cli/commands/config-serve-commands.d.ts.map +1 -1
  9. package/dist/cli/commands/environment-snapshots.d.ts +3 -0
  10. package/dist/cli/commands/environment-snapshots.d.ts.map +1 -0
  11. package/dist/cli/commands/knowledge-commands.d.ts +3 -0
  12. package/dist/cli/commands/knowledge-commands.d.ts.map +1 -0
  13. package/dist/cli/commands/local-snapshot-commands.d.ts +3 -0
  14. package/dist/cli/commands/local-snapshot-commands.d.ts.map +1 -0
  15. package/dist/cli/commands/machines.d.ts.map +1 -1
  16. package/dist/cli/commands/mcp-hooks-commands.d.ts.map +1 -1
  17. package/dist/cli/commands/onboarding-commands.d.ts +3 -0
  18. package/dist/cli/commands/onboarding-commands.d.ts.map +1 -0
  19. package/dist/cli/commands/project-commands.d.ts.map +1 -1
  20. package/dist/cli/commands/query-commands.d.ts.map +1 -1
  21. package/dist/cli/commands/release-compatibility-commands.d.ts +3 -0
  22. package/dist/cli/commands/release-compatibility-commands.d.ts.map +1 -0
  23. package/dist/cli/commands/retrospective-commands.d.ts +3 -0
  24. package/dist/cli/commands/retrospective-commands.d.ts.map +1 -0
  25. package/dist/cli/commands/review-queue-commands.d.ts +3 -0
  26. package/dist/cli/commands/review-queue-commands.d.ts.map +1 -0
  27. package/dist/cli/commands/risk-commands.d.ts +3 -0
  28. package/dist/cli/commands/risk-commands.d.ts.map +1 -0
  29. package/dist/cli/commands/roadmap-commands.d.ts +3 -0
  30. package/dist/cli/commands/roadmap-commands.d.ts.map +1 -0
  31. package/dist/cli/commands/sdk-fixture-commands.d.ts +3 -0
  32. package/dist/cli/commands/sdk-fixture-commands.d.ts.map +1 -0
  33. package/dist/cli/commands/task-commands.d.ts.map +1 -1
  34. package/dist/cli/index.js +26227 -9412
  35. package/dist/cli-mcp-parity.d.ts +1 -1
  36. package/dist/cli-mcp-parity.d.ts.map +1 -1
  37. package/dist/contracts.d.ts +19 -0
  38. package/dist/contracts.d.ts.map +1 -1
  39. package/dist/contracts.js +10174 -679
  40. package/dist/db/agent-metrics.d.ts +101 -0
  41. package/dist/db/agent-metrics.d.ts.map +1 -1
  42. package/dist/db/boards.d.ts +56 -0
  43. package/dist/db/boards.d.ts.map +1 -0
  44. package/dist/db/calendar.d.ts +52 -0
  45. package/dist/db/calendar.d.ts.map +1 -0
  46. package/dist/db/comments.d.ts.map +1 -1
  47. package/dist/db/handoffs.d.ts +25 -0
  48. package/dist/db/handoffs.d.ts.map +1 -1
  49. package/dist/db/machines.d.ts +19 -6
  50. package/dist/db/machines.d.ts.map +1 -1
  51. package/dist/db/migrations.d.ts.map +1 -1
  52. package/dist/db/project-knowledge.d.ts +88 -0
  53. package/dist/db/project-knowledge.d.ts.map +1 -0
  54. package/dist/db/project-risks.d.ts +139 -0
  55. package/dist/db/project-risks.d.ts.map +1 -0
  56. package/dist/db/retrospectives.d.ts +98 -0
  57. package/dist/db/retrospectives.d.ts.map +1 -0
  58. package/dist/db/schema.d.ts.map +1 -1
  59. package/dist/db/task-crud.d.ts.map +1 -1
  60. package/dist/db/task-relations.d.ts +69 -9
  61. package/dist/db/task-relations.d.ts.map +1 -1
  62. package/dist/db/tasks.d.ts +6 -2
  63. package/dist/db/tasks.d.ts.map +1 -1
  64. package/dist/index.d.ts +62 -11
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js +19485 -8856
  67. package/dist/json-contracts.d.ts.map +1 -1
  68. package/dist/lib/agent-replay-simulator.d.ts +66 -0
  69. package/dist/lib/agent-replay-simulator.d.ts.map +1 -0
  70. package/dist/lib/audit-ledger.d.ts +59 -0
  71. package/dist/lib/audit-ledger.d.ts.map +1 -0
  72. package/dist/lib/branch-work-plans.d.ts +46 -0
  73. package/dist/lib/branch-work-plans.d.ts.map +1 -0
  74. package/dist/lib/capacity-forecasts.d.ts +70 -0
  75. package/dist/lib/capacity-forecasts.d.ts.map +1 -0
  76. package/dist/lib/config.d.ts +179 -0
  77. package/dist/lib/config.d.ts.map +1 -1
  78. package/dist/lib/context-packs.d.ts +26 -3
  79. package/dist/lib/context-packs.d.ts.map +1 -1
  80. package/dist/lib/environment-snapshots.d.ts +111 -0
  81. package/dist/lib/environment-snapshots.d.ts.map +1 -0
  82. package/dist/lib/event-hooks.d.ts +1 -1
  83. package/dist/lib/event-hooks.d.ts.map +1 -1
  84. package/dist/lib/external-issue-importers.d.ts +60 -0
  85. package/dist/lib/external-issue-importers.d.ts.map +1 -0
  86. package/dist/lib/extract.d.ts +57 -0
  87. package/dist/lib/extract.d.ts.map +1 -1
  88. package/dist/lib/local-bridge.d.ts +3 -1
  89. package/dist/lib/local-bridge.d.ts.map +1 -1
  90. package/dist/lib/local-extensions.d.ts +75 -0
  91. package/dist/lib/local-extensions.d.ts.map +1 -0
  92. package/dist/lib/local-notifications.d.ts +55 -0
  93. package/dist/lib/local-notifications.d.ts.map +1 -0
  94. package/dist/lib/local-snapshots.d.ts +66 -0
  95. package/dist/lib/local-snapshots.d.ts.map +1 -0
  96. package/dist/lib/mention-resolver.d.ts +43 -0
  97. package/dist/lib/mention-resolver.d.ts.map +1 -0
  98. package/dist/lib/natural-language-intake.d.ts +56 -0
  99. package/dist/lib/natural-language-intake.d.ts.map +1 -0
  100. package/dist/lib/onboarding-fixtures.d.ts +31 -0
  101. package/dist/lib/onboarding-fixtures.d.ts.map +1 -0
  102. package/dist/lib/public-release-gate.d.ts +7 -0
  103. package/dist/lib/public-release-gate.d.ts.map +1 -1
  104. package/dist/lib/redaction.d.ts +9 -0
  105. package/dist/lib/redaction.d.ts.map +1 -1
  106. package/dist/lib/release-compatibility.d.ts +59 -0
  107. package/dist/lib/release-compatibility.d.ts.map +1 -0
  108. package/dist/lib/release-notes.d.ts +81 -0
  109. package/dist/lib/release-notes.d.ts.map +1 -0
  110. package/dist/lib/retention-cleanup.d.ts +63 -0
  111. package/dist/lib/retention-cleanup.d.ts.map +1 -0
  112. package/dist/lib/review-queues.d.ts +98 -0
  113. package/dist/lib/review-queues.d.ts.map +1 -0
  114. package/dist/lib/roadmaps.d.ts +133 -0
  115. package/dist/lib/roadmaps.d.ts.map +1 -0
  116. package/dist/lib/sdk-integration-fixtures.d.ts +65 -0
  117. package/dist/lib/sdk-integration-fixtures.d.ts.map +1 -0
  118. package/dist/lib/terminal-notifications.d.ts +53 -0
  119. package/dist/lib/terminal-notifications.d.ts.map +1 -0
  120. package/dist/lib/todos-md.d.ts.map +1 -1
  121. package/dist/lib/workflow-prompts.d.ts +38 -0
  122. package/dist/lib/workflow-prompts.d.ts.map +1 -0
  123. package/dist/mcp/index.d.ts.map +1 -1
  124. package/dist/mcp/index.js +20925 -9542
  125. package/dist/mcp/token-utils.d.ts.map +1 -1
  126. package/dist/mcp/tools/code-tools.d.ts.map +1 -1
  127. package/dist/mcp/tools/environment-snapshots.d.ts +8 -0
  128. package/dist/mcp/tools/environment-snapshots.d.ts.map +1 -0
  129. package/dist/mcp/tools/machines.d.ts.map +1 -1
  130. package/dist/mcp/tools/task-adv-tools.d.ts.map +1 -1
  131. package/dist/mcp/tools/task-auto-tools.d.ts.map +1 -1
  132. package/dist/mcp/tools/task-crud.d.ts.map +1 -1
  133. package/dist/mcp/tools/task-meta-tools.d.ts.map +1 -1
  134. package/dist/mcp/tools/task-project-tools.d.ts.map +1 -1
  135. package/dist/mcp/tools/task-rel-tools.d.ts.map +1 -1
  136. package/dist/mcp/tools/task-resources.d.ts.map +1 -1
  137. package/dist/mcp/tools/workflow-prompts.d.ts +3 -0
  138. package/dist/mcp/tools/workflow-prompts.d.ts.map +1 -0
  139. package/dist/mcp.js +97 -2
  140. package/dist/registry.js +14462 -5998
  141. package/dist/release-provenance.json +3 -3
  142. package/dist/server/index.js +493 -123
  143. package/dist/storage.js +2353 -139
  144. package/dist/types/index.d.ts +214 -0
  145. package/dist/types/index.d.ts.map +1 -1
  146. package/package.json +1 -1
@@ -994,6 +994,152 @@ var init_migrations = __esm(() => {
994
994
  );
995
995
  CREATE INDEX IF NOT EXISTS idx_saved_search_views_scope ON saved_search_views(scope);
996
996
  INSERT OR IGNORE INTO _migrations (id) VALUES (55);
997
+ `,
998
+ `
999
+ ALTER TABLE task_time_logs ADD COLUMN run_id TEXT;
1000
+ ALTER TABLE task_time_logs ADD COLUMN focus_session_id TEXT;
1001
+ CREATE INDEX IF NOT EXISTS idx_task_time_logs_run ON task_time_logs(run_id);
1002
+ CREATE INDEX IF NOT EXISTS idx_task_time_logs_focus_session ON task_time_logs(focus_session_id);
1003
+ CREATE TABLE IF NOT EXISTS focus_sessions (
1004
+ id TEXT PRIMARY KEY,
1005
+ task_id TEXT REFERENCES tasks(id) ON DELETE SET NULL,
1006
+ plan_id TEXT REFERENCES plans(id) ON DELETE SET NULL,
1007
+ run_id TEXT,
1008
+ agent_id TEXT,
1009
+ title TEXT,
1010
+ status TEXT NOT NULL DEFAULT 'active' CHECK(status IN ('active', 'paused', 'completed', 'cancelled')),
1011
+ started_at TEXT NOT NULL,
1012
+ last_resumed_at TEXT,
1013
+ paused_at TEXT,
1014
+ ended_at TEXT,
1015
+ actual_minutes INTEGER NOT NULL DEFAULT 0,
1016
+ idle_after_minutes INTEGER,
1017
+ notes TEXT,
1018
+ metadata TEXT DEFAULT '{}',
1019
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
1020
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
1021
+ );
1022
+ CREATE INDEX IF NOT EXISTS idx_focus_sessions_task ON focus_sessions(task_id);
1023
+ CREATE INDEX IF NOT EXISTS idx_focus_sessions_plan ON focus_sessions(plan_id);
1024
+ CREATE INDEX IF NOT EXISTS idx_focus_sessions_run ON focus_sessions(run_id);
1025
+ CREATE INDEX IF NOT EXISTS idx_focus_sessions_agent ON focus_sessions(agent_id);
1026
+ CREATE INDEX IF NOT EXISTS idx_focus_sessions_status ON focus_sessions(status);
1027
+ INSERT OR IGNORE INTO _migrations (id) VALUES (56);
1028
+ `,
1029
+ `
1030
+ CREATE TABLE IF NOT EXISTS task_boards (
1031
+ id TEXT PRIMARY KEY,
1032
+ name TEXT NOT NULL UNIQUE,
1033
+ scope TEXT NOT NULL DEFAULT 'tasks' CHECK(scope IN ('tasks', 'plans')),
1034
+ project_id TEXT REFERENCES projects(id) ON DELETE SET NULL,
1035
+ task_list_id TEXT REFERENCES task_lists(id) ON DELETE SET NULL,
1036
+ plan_id TEXT REFERENCES plans(id) ON DELETE SET NULL,
1037
+ agent_id TEXT,
1038
+ lanes TEXT NOT NULL DEFAULT '[]',
1039
+ filters TEXT NOT NULL DEFAULT '{}',
1040
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
1041
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
1042
+ );
1043
+ CREATE INDEX IF NOT EXISTS idx_task_boards_scope ON task_boards(scope);
1044
+ CREATE INDEX IF NOT EXISTS idx_task_boards_project ON task_boards(project_id);
1045
+ CREATE INDEX IF NOT EXISTS idx_task_boards_plan ON task_boards(plan_id);
1046
+ INSERT OR IGNORE INTO _migrations (id) VALUES (57);
1047
+ `,
1048
+ `
1049
+ CREATE TABLE IF NOT EXISTS local_calendar_items (
1050
+ id TEXT PRIMARY KEY,
1051
+ kind TEXT NOT NULL CHECK(kind IN ('task_due', 'task_sla', 'task_reminder', 'milestone', 'work_block', 'run', 'imported')),
1052
+ title TEXT NOT NULL,
1053
+ description TEXT,
1054
+ starts_at TEXT NOT NULL,
1055
+ ends_at TEXT,
1056
+ timezone TEXT,
1057
+ project_id TEXT REFERENCES projects(id) ON DELETE SET NULL,
1058
+ task_id TEXT REFERENCES tasks(id) ON DELETE SET NULL,
1059
+ plan_id TEXT REFERENCES plans(id) ON DELETE SET NULL,
1060
+ run_id TEXT,
1061
+ recurrence_rule TEXT,
1062
+ metadata TEXT DEFAULT '{}',
1063
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
1064
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
1065
+ );
1066
+ CREATE INDEX IF NOT EXISTS idx_local_calendar_items_time ON local_calendar_items(starts_at, ends_at);
1067
+ CREATE INDEX IF NOT EXISTS idx_local_calendar_items_task ON local_calendar_items(task_id);
1068
+ CREATE INDEX IF NOT EXISTS idx_local_calendar_items_project ON local_calendar_items(project_id);
1069
+ CREATE INDEX IF NOT EXISTS idx_local_calendar_items_kind ON local_calendar_items(kind);
1070
+ INSERT OR IGNORE INTO _migrations (id) VALUES (58);
1071
+ `,
1072
+ `
1073
+ CREATE TABLE IF NOT EXISTS project_knowledge_records (
1074
+ id TEXT PRIMARY KEY,
1075
+ record_type TEXT NOT NULL CHECK(record_type IN ('decision','architecture_note','tradeoff','context_snapshot')),
1076
+ title TEXT NOT NULL,
1077
+ content TEXT,
1078
+ decision TEXT,
1079
+ rationale TEXT,
1080
+ alternatives TEXT DEFAULT '[]',
1081
+ task_id TEXT REFERENCES tasks(id) ON DELETE SET NULL,
1082
+ project_id TEXT REFERENCES projects(id) ON DELETE SET NULL,
1083
+ plan_id TEXT REFERENCES plans(id) ON DELETE SET NULL,
1084
+ agent_id TEXT,
1085
+ snapshot_id TEXT REFERENCES context_snapshots(id) ON DELETE SET NULL,
1086
+ tags TEXT DEFAULT '[]',
1087
+ metadata TEXT DEFAULT '{}',
1088
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
1089
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
1090
+ );
1091
+ CREATE INDEX IF NOT EXISTS idx_project_knowledge_type ON project_knowledge_records(record_type);
1092
+ CREATE INDEX IF NOT EXISTS idx_project_knowledge_project ON project_knowledge_records(project_id);
1093
+ CREATE INDEX IF NOT EXISTS idx_project_knowledge_task ON project_knowledge_records(task_id);
1094
+ CREATE INDEX IF NOT EXISTS idx_project_knowledge_plan ON project_knowledge_records(plan_id);
1095
+ CREATE INDEX IF NOT EXISTS idx_project_knowledge_agent ON project_knowledge_records(agent_id);
1096
+ CREATE INDEX IF NOT EXISTS idx_project_knowledge_snapshot ON project_knowledge_records(snapshot_id);
1097
+ INSERT OR IGNORE INTO _migrations (id) VALUES (59);
1098
+ `,
1099
+ `
1100
+ CREATE TABLE IF NOT EXISTS project_risks (
1101
+ id TEXT PRIMARY KEY,
1102
+ title TEXT NOT NULL,
1103
+ description TEXT,
1104
+ status TEXT NOT NULL DEFAULT 'open' CHECK(status IN ('open','mitigating','resolved','accepted')),
1105
+ severity TEXT NOT NULL DEFAULT 'medium' CHECK(severity IN ('low','medium','high','critical')),
1106
+ probability TEXT NOT NULL DEFAULT 'medium' CHECK(probability IN ('low','medium','high')),
1107
+ owner TEXT,
1108
+ mitigation TEXT,
1109
+ due_at TEXT,
1110
+ project_id TEXT REFERENCES projects(id) ON DELETE SET NULL,
1111
+ plan_id TEXT REFERENCES plans(id) ON DELETE SET NULL,
1112
+ task_id TEXT REFERENCES tasks(id) ON DELETE SET NULL,
1113
+ tags TEXT DEFAULT '[]',
1114
+ metadata TEXT DEFAULT '{}',
1115
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
1116
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
1117
+ closed_at TEXT
1118
+ );
1119
+ CREATE INDEX IF NOT EXISTS idx_project_risks_status ON project_risks(status);
1120
+ CREATE INDEX IF NOT EXISTS idx_project_risks_severity ON project_risks(severity);
1121
+ CREATE INDEX IF NOT EXISTS idx_project_risks_project ON project_risks(project_id);
1122
+ CREATE INDEX IF NOT EXISTS idx_project_risks_plan ON project_risks(plan_id);
1123
+ CREATE INDEX IF NOT EXISTS idx_project_risks_task ON project_risks(task_id);
1124
+ CREATE INDEX IF NOT EXISTS idx_project_risks_due ON project_risks(due_at);
1125
+ INSERT OR IGNORE INTO _migrations (id) VALUES (60);
1126
+ `,
1127
+ `
1128
+ CREATE TABLE IF NOT EXISTS local_retrospectives (
1129
+ id TEXT PRIMARY KEY,
1130
+ title TEXT NOT NULL,
1131
+ scope TEXT NOT NULL CHECK(scope IN ('project','plan')),
1132
+ project_id TEXT REFERENCES projects(id) ON DELETE SET NULL,
1133
+ plan_id TEXT REFERENCES plans(id) ON DELETE SET NULL,
1134
+ agent_id TEXT,
1135
+ report_json TEXT NOT NULL,
1136
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
1137
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
1138
+ );
1139
+ CREATE INDEX IF NOT EXISTS idx_local_retrospectives_project ON local_retrospectives(project_id);
1140
+ CREATE INDEX IF NOT EXISTS idx_local_retrospectives_plan ON local_retrospectives(plan_id);
1141
+ CREATE INDEX IF NOT EXISTS idx_local_retrospectives_agent ON local_retrospectives(agent_id);
1142
+ INSERT OR IGNORE INTO _migrations (id) VALUES (61);
997
1143
  `
998
1144
  ];
999
1145
  });
@@ -1181,6 +1327,89 @@ function ensureSchema(db) {
1181
1327
  updated_at TEXT NOT NULL DEFAULT (datetime('now'))
1182
1328
  )`);
1183
1329
  ensureIndex("CREATE INDEX IF NOT EXISTS idx_saved_search_views_scope ON saved_search_views(scope)");
1330
+ ensureTable("context_snapshots", `
1331
+ CREATE TABLE context_snapshots (
1332
+ id TEXT PRIMARY KEY,
1333
+ agent_id TEXT,
1334
+ task_id TEXT REFERENCES tasks(id) ON DELETE SET NULL,
1335
+ project_id TEXT REFERENCES projects(id) ON DELETE SET NULL,
1336
+ snapshot_type TEXT NOT NULL CHECK(snapshot_type IN ('interrupt','complete','handoff','checkpoint')),
1337
+ plan_summary TEXT,
1338
+ files_open TEXT DEFAULT '[]',
1339
+ attempts TEXT DEFAULT '[]',
1340
+ blockers TEXT DEFAULT '[]',
1341
+ next_steps TEXT,
1342
+ metadata TEXT DEFAULT '{}',
1343
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
1344
+ )`);
1345
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_snapshots_agent ON context_snapshots(agent_id)");
1346
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_snapshots_task ON context_snapshots(task_id)");
1347
+ ensureTable("project_knowledge_records", `
1348
+ CREATE TABLE project_knowledge_records (
1349
+ id TEXT PRIMARY KEY,
1350
+ record_type TEXT NOT NULL CHECK(record_type IN ('decision','architecture_note','tradeoff','context_snapshot')),
1351
+ title TEXT NOT NULL,
1352
+ content TEXT,
1353
+ decision TEXT,
1354
+ rationale TEXT,
1355
+ alternatives TEXT DEFAULT '[]',
1356
+ task_id TEXT REFERENCES tasks(id) ON DELETE SET NULL,
1357
+ project_id TEXT REFERENCES projects(id) ON DELETE SET NULL,
1358
+ plan_id TEXT REFERENCES plans(id) ON DELETE SET NULL,
1359
+ agent_id TEXT,
1360
+ snapshot_id TEXT REFERENCES context_snapshots(id) ON DELETE SET NULL,
1361
+ tags TEXT DEFAULT '[]',
1362
+ metadata TEXT DEFAULT '{}',
1363
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
1364
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
1365
+ )`);
1366
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_project_knowledge_type ON project_knowledge_records(record_type)");
1367
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_project_knowledge_project ON project_knowledge_records(project_id)");
1368
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_project_knowledge_task ON project_knowledge_records(task_id)");
1369
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_project_knowledge_plan ON project_knowledge_records(plan_id)");
1370
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_project_knowledge_agent ON project_knowledge_records(agent_id)");
1371
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_project_knowledge_snapshot ON project_knowledge_records(snapshot_id)");
1372
+ ensureTable("project_risks", `
1373
+ CREATE TABLE project_risks (
1374
+ id TEXT PRIMARY KEY,
1375
+ title TEXT NOT NULL,
1376
+ description TEXT,
1377
+ status TEXT NOT NULL DEFAULT 'open' CHECK(status IN ('open','mitigating','resolved','accepted')),
1378
+ severity TEXT NOT NULL DEFAULT 'medium' CHECK(severity IN ('low','medium','high','critical')),
1379
+ probability TEXT NOT NULL DEFAULT 'medium' CHECK(probability IN ('low','medium','high')),
1380
+ owner TEXT,
1381
+ mitigation TEXT,
1382
+ due_at TEXT,
1383
+ project_id TEXT REFERENCES projects(id) ON DELETE SET NULL,
1384
+ plan_id TEXT REFERENCES plans(id) ON DELETE SET NULL,
1385
+ task_id TEXT REFERENCES tasks(id) ON DELETE SET NULL,
1386
+ tags TEXT DEFAULT '[]',
1387
+ metadata TEXT DEFAULT '{}',
1388
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
1389
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
1390
+ closed_at TEXT
1391
+ )`);
1392
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_project_risks_status ON project_risks(status)");
1393
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_project_risks_severity ON project_risks(severity)");
1394
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_project_risks_project ON project_risks(project_id)");
1395
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_project_risks_plan ON project_risks(plan_id)");
1396
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_project_risks_task ON project_risks(task_id)");
1397
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_project_risks_due ON project_risks(due_at)");
1398
+ ensureTable("local_retrospectives", `
1399
+ CREATE TABLE local_retrospectives (
1400
+ id TEXT PRIMARY KEY,
1401
+ title TEXT NOT NULL,
1402
+ scope TEXT NOT NULL CHECK(scope IN ('project','plan')),
1403
+ project_id TEXT REFERENCES projects(id) ON DELETE SET NULL,
1404
+ plan_id TEXT REFERENCES plans(id) ON DELETE SET NULL,
1405
+ agent_id TEXT,
1406
+ report_json TEXT NOT NULL,
1407
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
1408
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
1409
+ )`);
1410
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_local_retrospectives_project ON local_retrospectives(project_id)");
1411
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_local_retrospectives_plan ON local_retrospectives(plan_id)");
1412
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_local_retrospectives_agent ON local_retrospectives(agent_id)");
1184
1413
  ensureTable("task_relationships", `
1185
1414
  CREATE TABLE task_relationships (
1186
1415
  id TEXT PRIMARY KEY,
@@ -1517,6 +1746,8 @@ function ensureSchema(db) {
1517
1746
  CREATE TABLE task_time_logs (
1518
1747
  id TEXT PRIMARY KEY,
1519
1748
  task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
1749
+ run_id TEXT,
1750
+ focus_session_id TEXT,
1520
1751
  agent_id TEXT,
1521
1752
  started_at TEXT,
1522
1753
  ended_at TEXT,
@@ -1524,9 +1755,77 @@ function ensureSchema(db) {
1524
1755
  notes TEXT,
1525
1756
  created_at TEXT NOT NULL DEFAULT (datetime('now'))
1526
1757
  )`);
1758
+ ensureColumn("task_time_logs", "run_id", "TEXT");
1759
+ ensureColumn("task_time_logs", "focus_session_id", "TEXT");
1527
1760
  ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_time_logs_task ON task_time_logs(task_id)");
1528
1761
  ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_time_logs_agent ON task_time_logs(agent_id)");
1762
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_time_logs_run ON task_time_logs(run_id)");
1763
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_time_logs_focus_session ON task_time_logs(focus_session_id)");
1529
1764
  ensureColumn("tasks", "actual_minutes", "INTEGER");
1765
+ ensureTable("focus_sessions", `
1766
+ CREATE TABLE focus_sessions (
1767
+ id TEXT PRIMARY KEY,
1768
+ task_id TEXT REFERENCES tasks(id) ON DELETE SET NULL,
1769
+ plan_id TEXT REFERENCES plans(id) ON DELETE SET NULL,
1770
+ run_id TEXT,
1771
+ agent_id TEXT,
1772
+ title TEXT,
1773
+ status TEXT NOT NULL DEFAULT 'active' CHECK(status IN ('active', 'paused', 'completed', 'cancelled')),
1774
+ started_at TEXT NOT NULL,
1775
+ last_resumed_at TEXT,
1776
+ paused_at TEXT,
1777
+ ended_at TEXT,
1778
+ actual_minutes INTEGER NOT NULL DEFAULT 0,
1779
+ idle_after_minutes INTEGER,
1780
+ notes TEXT,
1781
+ metadata TEXT DEFAULT '{}',
1782
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
1783
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
1784
+ )`);
1785
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_focus_sessions_task ON focus_sessions(task_id)");
1786
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_focus_sessions_plan ON focus_sessions(plan_id)");
1787
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_focus_sessions_run ON focus_sessions(run_id)");
1788
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_focus_sessions_agent ON focus_sessions(agent_id)");
1789
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_focus_sessions_status ON focus_sessions(status)");
1790
+ ensureTable("task_boards", `
1791
+ CREATE TABLE task_boards (
1792
+ id TEXT PRIMARY KEY,
1793
+ name TEXT NOT NULL UNIQUE,
1794
+ scope TEXT NOT NULL DEFAULT 'tasks' CHECK(scope IN ('tasks', 'plans')),
1795
+ project_id TEXT REFERENCES projects(id) ON DELETE SET NULL,
1796
+ task_list_id TEXT REFERENCES task_lists(id) ON DELETE SET NULL,
1797
+ plan_id TEXT REFERENCES plans(id) ON DELETE SET NULL,
1798
+ agent_id TEXT,
1799
+ lanes TEXT NOT NULL DEFAULT '[]',
1800
+ filters TEXT NOT NULL DEFAULT '{}',
1801
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
1802
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
1803
+ )`);
1804
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_boards_scope ON task_boards(scope)");
1805
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_boards_project ON task_boards(project_id)");
1806
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_task_boards_plan ON task_boards(plan_id)");
1807
+ ensureTable("local_calendar_items", `
1808
+ CREATE TABLE local_calendar_items (
1809
+ id TEXT PRIMARY KEY,
1810
+ kind TEXT NOT NULL CHECK(kind IN ('task_due', 'task_sla', 'task_reminder', 'milestone', 'work_block', 'run', 'imported')),
1811
+ title TEXT NOT NULL,
1812
+ description TEXT,
1813
+ starts_at TEXT NOT NULL,
1814
+ ends_at TEXT,
1815
+ timezone TEXT,
1816
+ project_id TEXT REFERENCES projects(id) ON DELETE SET NULL,
1817
+ task_id TEXT REFERENCES tasks(id) ON DELETE SET NULL,
1818
+ plan_id TEXT REFERENCES plans(id) ON DELETE SET NULL,
1819
+ run_id TEXT,
1820
+ recurrence_rule TEXT,
1821
+ metadata TEXT DEFAULT '{}',
1822
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
1823
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
1824
+ )`);
1825
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_local_calendar_items_time ON local_calendar_items(starts_at, ends_at)");
1826
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_local_calendar_items_task ON local_calendar_items(task_id)");
1827
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_local_calendar_items_project ON local_calendar_items(project_id)");
1828
+ ensureIndex("CREATE INDEX IF NOT EXISTS idx_local_calendar_items_kind ON local_calendar_items(kind)");
1530
1829
  ensureTable("task_watchers", `
1531
1830
  CREATE TABLE task_watchers (
1532
1831
  id TEXT PRIMARY KEY,
@@ -1606,12 +1905,22 @@ var init_schema = __esm(() => {
1606
1905
  });
1607
1906
 
1608
1907
  // src/db/machines.ts
1609
- import { hostname as osHostname, platform as osPlatform } from "os";
1908
+ import { hostname as osHostname, platform as osPlatform, arch as osArch } from "os";
1909
+ function parseMetadata(value) {
1910
+ if (!value)
1911
+ return {};
1912
+ try {
1913
+ const parsed = JSON.parse(value);
1914
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
1915
+ } catch {
1916
+ return {};
1917
+ }
1918
+ }
1610
1919
  function rowToMachine(row) {
1611
1920
  return {
1612
1921
  ...row,
1613
1922
  is_primary: !!row.is_primary,
1614
- metadata: row.metadata ? JSON.parse(row.metadata) : {}
1923
+ metadata: parseMetadata(row.metadata)
1615
1924
  };
1616
1925
  }
1617
1926
  function getOrCreateLocalMachine(db) {
@@ -1830,7 +2139,7 @@ var LOCK_EXPIRY_MINUTES = 30, _db = null, ALLOWED_TABLES;
1830
2139
  var init_database = __esm(() => {
1831
2140
  init_schema();
1832
2141
  init_machines();
1833
- ALLOWED_TABLES = new Set(["tasks", "projects", "agents", "plans", "task_lists", "task_templates"]);
2142
+ ALLOWED_TABLES = new Set(["tasks", "projects", "agents", "plans", "task_lists", "task_templates", "project_knowledge_records", "project_risks", "local_retrospectives"]);
1834
2143
  });
1835
2144
 
1836
2145
  // src/lib/recurrence.ts
@@ -2622,8 +2931,45 @@ import { dirname as dirname4, resolve as resolve4 } from "path";
2622
2931
  import { createConnection } from "net";
2623
2932
 
2624
2933
  // src/lib/redaction.ts
2934
+ var DEFAULT_SECRET_PATTERNS = [
2935
+ { name: "aws-access-key", regex: /\b(AKIA|ASIA)[0-9A-Z]{16}\b/g, replacement: "[REDACTED_AWS_KEY]" },
2936
+ { name: "private-key", regex: /-----BEGIN (?:RSA |EC |OPENSSH |)PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |OPENSSH |)PRIVATE KEY-----/g, replacement: "[REDACTED_PRIVATE_KEY]" },
2937
+ { name: "openai-token", regex: /\bsk-[A-Za-z0-9_-]{12,}\b/g, replacement: "[REDACTED_TOKEN]" },
2938
+ { name: "env-secret-assignment", regex: /\b([A-Za-z0-9_]*(?:API_KEY|TOKEN|SECRET|PASSWORD)[A-Za-z0-9_]*)\s*=\s*['"]?[^'"\s]{8,}/gi, replacement: "$1=[REDACTED]" },
2939
+ { name: "bearer-token", regex: /\b(bearer)\s+[A-Za-z0-9._~+/=-]{12,}/gi, replacement: "$1 [REDACTED]" }
2940
+ ];
2941
+ var DEFAULT_SECRET_KEY_PATTERN = /api[_-]?key|token|secret|password/i;
2942
+ function unique(values) {
2943
+ return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
2944
+ }
2945
+ function cloneRegex(regex) {
2946
+ return new RegExp(regex.source, regex.flags.includes("g") ? regex.flags : `${regex.flags}g`);
2947
+ }
2948
+ function customPatterns() {
2949
+ return unique(loadConfig().secret_safety?.redaction_patterns).flatMap((pattern) => {
2950
+ try {
2951
+ return [{ name: `custom:${pattern}`, regex: new RegExp(pattern, "g") }];
2952
+ } catch {
2953
+ return [];
2954
+ }
2955
+ });
2956
+ }
2957
+ function secretPatterns() {
2958
+ return [...customPatterns(), ...DEFAULT_SECRET_PATTERNS];
2959
+ }
2960
+ function isSecretKey(key) {
2961
+ if (DEFAULT_SECRET_KEY_PATTERN.test(key))
2962
+ return true;
2963
+ return unique(loadConfig().secret_safety?.redaction_keys).some((pattern) => key.toLowerCase().includes(pattern.toLowerCase()));
2964
+ }
2625
2965
  function redactEvidenceText(value) {
2626
- return value.replace(/\b(AKIA|ASIA)[0-9A-Z]{16}\b/g, "[REDACTED_AWS_KEY]").replace(/-----BEGIN (?:RSA |EC |OPENSSH |)PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |OPENSSH |)PRIVATE KEY-----/g, "[REDACTED_PRIVATE_KEY]").replace(/\bsk-[A-Za-z0-9_-]{12,}\b/g, "[REDACTED_TOKEN]").replace(/\b([A-Za-z0-9_]*(?:API_KEY|TOKEN|SECRET|PASSWORD)[A-Za-z0-9_]*)\s*=\s*['"]?[^'"\s]{8,}/gi, "$1=[REDACTED]").replace(/\b(bearer)\s+[A-Za-z0-9._~+/=-]{12,}/gi, "$1 [REDACTED]");
2966
+ let redacted = value;
2967
+ for (const pattern of secretPatterns()) {
2968
+ const regex = cloneRegex(pattern.regex);
2969
+ const replacement = pattern.replacement ?? "[REDACTED]";
2970
+ redacted = typeof replacement === "string" ? redacted.replace(regex, replacement) : redacted.replace(regex, replacement);
2971
+ }
2972
+ return redacted;
2627
2973
  }
2628
2974
  function redactValue(value) {
2629
2975
  if (typeof value === "string")
@@ -2633,7 +2979,7 @@ function redactValue(value) {
2633
2979
  if (value && typeof value === "object") {
2634
2980
  const redacted = {};
2635
2981
  for (const [key, child] of Object.entries(value)) {
2636
- if (/api[_-]?key|token|secret|password/i.test(key)) {
2982
+ if (isSecretKey(key)) {
2637
2983
  redacted[key] = "[REDACTED]";
2638
2984
  } else {
2639
2985
  redacted[key] = redactValue(child);
@@ -2696,7 +3042,7 @@ var PRESET_DEFAULTS = {
2696
3042
  function normalizePath(path) {
2697
3043
  return resolve2(path);
2698
3044
  }
2699
- function unique(values) {
3045
+ function unique2(values) {
2700
3046
  return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
2701
3047
  }
2702
3048
  function defaultProfile(root, preset) {
@@ -2749,7 +3095,7 @@ function writeAllowed(profile, root, writePath) {
2749
3095
  function redactedEnvKeys(profile, env) {
2750
3096
  if (!env)
2751
3097
  return [];
2752
- const patterns = unique([...DEFAULT_ENV_REDACTIONS, ...profile.env_redactions]).map((item) => item.toUpperCase());
3098
+ const patterns = unique2([...DEFAULT_ENV_REDACTIONS, ...profile.env_redactions]).map((item) => item.toUpperCase());
2753
3099
  return Object.keys(env).filter((key) => patterns.some((pattern) => key.toUpperCase().includes(pattern)));
2754
3100
  }
2755
3101
  function checkWorkspacePermission(input = {}) {
@@ -2788,7 +3134,7 @@ var DEFAULT_ENV_REDACTIONS2 = ["API_KEY", "TOKEN", "SECRET", "PASSWORD", "AUTH"]
2788
3134
  function normalizePath2(path) {
2789
3135
  return resolve3(path);
2790
3136
  }
2791
- function unique2(values) {
3137
+ function unique3(values) {
2792
3138
  return Array.from(new Set((values || []).map((value) => value.trim()).filter(Boolean)));
2793
3139
  }
2794
3140
  function configuredProfiles2(config = loadConfig()) {
@@ -2844,7 +3190,7 @@ function profileByName(name, path) {
2844
3190
  function redactedEnvKeys2(profile, env) {
2845
3191
  if (!env)
2846
3192
  return [];
2847
- const patterns = unique2([...DEFAULT_ENV_REDACTIONS2, ...profile.env_redactions]).map((item) => item.toUpperCase());
3193
+ const patterns = unique3([...DEFAULT_ENV_REDACTIONS2, ...profile.env_redactions]).map((item) => item.toUpperCase());
2848
3194
  return Object.keys(env).filter((key) => patterns.some((pattern) => key.toUpperCase().includes(pattern)));
2849
3195
  }
2850
3196
  function omittedEnvKeys(profile, env) {
@@ -2896,7 +3242,7 @@ function checkRunnerSandbox(input = {}) {
2896
3242
  const redacted = redactedEnvKeys2(profile, input.env);
2897
3243
  const omitted = omittedEnvKeys(profile, input.env);
2898
3244
  const effective = Object.keys(input.env || {}).filter((key) => !omitted.includes(key));
2899
- const uniqueReasons = unique2(reasons);
3245
+ const uniqueReasons = unique3(reasons);
2900
3246
  const allowed = uniqueReasons.length === 0;
2901
3247
  return {
2902
3248
  allowed,
@@ -3333,8 +3679,8 @@ function createTask(input, db) {
3333
3679
  let id = uuid();
3334
3680
  for (let attempt = 0;attempt < 3; attempt++) {
3335
3681
  try {
3336
- d.run(`INSERT INTO tasks (id, short_id, project_id, parent_id, plan_id, task_list_id, cycle_id, title, description, status, priority, agent_id, assigned_to, session_id, working_dir, tags, metadata, version, created_at, updated_at, due_at, estimated_minutes, confidence, retry_count, max_retries, retry_after, 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)
3337
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
3682
+ d.run(`INSERT INTO tasks (id, short_id, project_id, parent_id, plan_id, task_list_id, cycle_id, title, description, status, priority, agent_id, assigned_to, session_id, working_dir, tags, metadata, version, created_at, updated_at, due_at, estimated_minutes, sla_minutes, confidence, retry_count, max_retries, retry_after, 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)
3683
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
3338
3684
  id,
3339
3685
  null,
3340
3686
  input.project_id || null,
@@ -3356,6 +3702,7 @@ function createTask(input, db) {
3356
3702
  timestamp,
3357
3703
  input.due_at || null,
3358
3704
  input.estimated_minutes || null,
3705
+ input.sla_minutes ?? null,
3359
3706
  input.confidence ?? null,
3360
3707
  input.retry_count ?? 0,
3361
3708
  input.max_retries ?? 3,
@@ -3635,6 +3982,10 @@ function updateTask(id, input, db) {
3635
3982
  sets.push("estimated_minutes = ?");
3636
3983
  params.push(input.estimated_minutes);
3637
3984
  }
3985
+ if (input.sla_minutes !== undefined) {
3986
+ sets.push("sla_minutes = ?");
3987
+ params.push(input.sla_minutes);
3988
+ }
3638
3989
  if (input.actual_minutes !== undefined) {
3639
3990
  sets.push("actual_minutes = ?");
3640
3991
  params.push(input.actual_minutes);
@@ -3716,6 +4067,7 @@ function updateTask(id, input, db) {
3716
4067
  version: task.version + 1,
3717
4068
  updated_at: timestamp,
3718
4069
  completed_at: input.status === "completed" ? completionTimestamp : input.completed_at !== undefined ? input.completed_at : task.completed_at,
4070
+ sla_minutes: input.sla_minutes !== undefined ? input.sla_minutes : task.sla_minutes,
3719
4071
  actual_minutes: input.actual_minutes ?? task.actual_minutes,
3720
4072
  confidence: input.confidence !== undefined ? input.confidence : task.confidence,
3721
4073
  retry_count: input.retry_count ?? task.retry_count,
@@ -3957,7 +4309,7 @@ function completeTask(id, agentId, db, options) {
3957
4309
  emitLocalEventHooksQuiet({ type: "task.completed", payload: { id, agent_id: agentId, title: task.title, completed_at: timestamp } });
3958
4310
  let spawnedTask = null;
3959
4311
  if (task.recurrence_rule && !options?.skip_recurrence) {
3960
- spawnedTask = spawnNextRecurrence(task, d);
4312
+ spawnedTask = spawnNextRecurrence(task, d, timestamp);
3961
4313
  }
3962
4314
  let spawnedFromTemplate = null;
3963
4315
  if (task.spawns_template_id) {
@@ -4176,8 +4528,9 @@ function getStaleTasks(staleQuery = 30, filters, db) {
4176
4528
  const rows = d.query(`SELECT * FROM tasks WHERE ${where} ORDER BY updated_at ASC`).all(...params);
4177
4529
  return rows.map(rowToTask);
4178
4530
  }
4179
- function spawnNextRecurrence(completedTask, db) {
4180
- const dueAt = nextOccurrence(completedTask.recurrence_rule, new Date);
4531
+ function spawnNextRecurrence(completedTask, db, completedAt) {
4532
+ const recurrenceBase = completedTask.due_at ? new Date(completedTask.due_at) : new Date(completedAt);
4533
+ const dueAt = nextOccurrence(completedTask.recurrence_rule, recurrenceBase);
4181
4534
  let title = completedTask.title;
4182
4535
  if (completedTask.short_id && title.startsWith(completedTask.short_id + ": ")) {
4183
4536
  title = title.slice(completedTask.short_id.length + 2);
@@ -4194,6 +4547,7 @@ function spawnNextRecurrence(completedTask, db) {
4194
4547
  tags: completedTask.tags,
4195
4548
  metadata: completedTask.metadata,
4196
4549
  estimated_minutes: completedTask.estimated_minutes ?? undefined,
4550
+ sla_minutes: completedTask.sla_minutes ?? undefined,
4197
4551
  recurrence_rule: completedTask.recurrence_rule,
4198
4552
  recurrence_parent_id: recurrenceParentId,
4199
4553
  due_at: dueAt
@@ -4285,6 +4639,130 @@ function getTaskStats(filters, db) {
4285
4639
  }
4286
4640
  // src/db/task-relations.ts
4287
4641
  init_database();
4642
+ // src/db/boards.ts
4643
+ init_database();
4644
+
4645
+ // src/db/plans.ts
4646
+ init_database();
4647
+ function createPlan(input, db) {
4648
+ const d = db || getDatabase();
4649
+ const id = uuid();
4650
+ const timestamp = now();
4651
+ d.run(`INSERT INTO plans (id, project_id, task_list_id, agent_id, name, description, status, created_at, updated_at)
4652
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
4653
+ id,
4654
+ input.project_id || null,
4655
+ input.task_list_id || null,
4656
+ input.agent_id || null,
4657
+ input.name,
4658
+ input.description || null,
4659
+ input.status || "active",
4660
+ timestamp,
4661
+ timestamp
4662
+ ]);
4663
+ return getPlan(id, d);
4664
+ }
4665
+ function getPlan(id, db) {
4666
+ const d = db || getDatabase();
4667
+ const row = d.query("SELECT * FROM plans WHERE id = ?").get(id);
4668
+ return row;
4669
+ }
4670
+ function listPlans(projectId, db) {
4671
+ const d = db || getDatabase();
4672
+ if (projectId) {
4673
+ return d.query("SELECT * FROM plans WHERE project_id = ? ORDER BY created_at DESC").all(projectId);
4674
+ }
4675
+ return d.query("SELECT * FROM plans ORDER BY created_at DESC").all();
4676
+ }
4677
+ function updatePlan(id, input, db) {
4678
+ const d = db || getDatabase();
4679
+ const plan = getPlan(id, d);
4680
+ if (!plan)
4681
+ throw new PlanNotFoundError(id);
4682
+ const sets = ["updated_at = ?"];
4683
+ const params = [now()];
4684
+ if (input.name !== undefined) {
4685
+ sets.push("name = ?");
4686
+ params.push(input.name);
4687
+ }
4688
+ if (input.description !== undefined) {
4689
+ sets.push("description = ?");
4690
+ params.push(input.description);
4691
+ }
4692
+ if (input.status !== undefined) {
4693
+ sets.push("status = ?");
4694
+ params.push(input.status);
4695
+ }
4696
+ if (input.task_list_id !== undefined) {
4697
+ sets.push("task_list_id = ?");
4698
+ params.push(input.task_list_id);
4699
+ }
4700
+ if (input.agent_id !== undefined) {
4701
+ sets.push("agent_id = ?");
4702
+ params.push(input.agent_id);
4703
+ }
4704
+ params.push(id);
4705
+ d.run(`UPDATE plans SET ${sets.join(", ")} WHERE id = ?`, params);
4706
+ const updated = getPlan(id, d);
4707
+ emitLocalEventHooksQuiet({
4708
+ type: "plan.updated",
4709
+ payload: { id, old_status: plan.status, new_status: updated.status, name: updated.name, project_id: updated.project_id }
4710
+ });
4711
+ return updated;
4712
+ }
4713
+ function deletePlan(id, db) {
4714
+ const d = db || getDatabase();
4715
+ const result = d.run("DELETE FROM plans WHERE id = ?", [id]);
4716
+ return result.changes > 0;
4717
+ }
4718
+ // src/db/calendar.ts
4719
+ init_database();
4720
+
4721
+ // src/lib/artifact-store.ts
4722
+ init_database();
4723
+
4724
+ // src/db/comments.ts
4725
+ init_database();
4726
+ function addComment(input, db) {
4727
+ const d = db || getDatabase();
4728
+ if (!getTask(input.task_id, d)) {
4729
+ throw new TaskNotFoundError(input.task_id);
4730
+ }
4731
+ const id = uuid();
4732
+ const timestamp = now();
4733
+ d.run(`INSERT INTO task_comments (id, task_id, agent_id, session_id, content, type, progress_pct, created_at)
4734
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
4735
+ id,
4736
+ input.task_id,
4737
+ input.agent_id || null,
4738
+ input.session_id || null,
4739
+ redactEvidenceText(input.content),
4740
+ input.type || "comment",
4741
+ input.progress_pct ?? null,
4742
+ timestamp
4743
+ ]);
4744
+ return getComment(id, d);
4745
+ }
4746
+ function logProgress(taskId, message, pct, agentId, db) {
4747
+ return addComment({ task_id: taskId, content: message, type: "progress", progress_pct: pct, agent_id: agentId }, db);
4748
+ }
4749
+ function getComment(id, db) {
4750
+ const d = db || getDatabase();
4751
+ return d.query("SELECT * FROM task_comments WHERE id = ?").get(id);
4752
+ }
4753
+ function listComments(taskId, db) {
4754
+ const d = db || getDatabase();
4755
+ return d.query("SELECT * FROM task_comments WHERE task_id = ? ORDER BY created_at").all(taskId);
4756
+ }
4757
+
4758
+ // src/db/task-runs.ts
4759
+ init_database();
4760
+
4761
+ // src/db/task-files.ts
4762
+ init_database();
4763
+
4764
+ // src/db/task-commits.ts
4765
+ init_database();
4288
4766
  // src/db/agents.ts
4289
4767
  init_database();
4290
4768
 
@@ -4686,80 +5164,6 @@ function getOrgChart(db) {
4686
5164
  return buildTree(null);
4687
5165
  }
4688
5166
 
4689
- // src/db/plans.ts
4690
- init_database();
4691
- function createPlan(input, db) {
4692
- const d = db || getDatabase();
4693
- const id = uuid();
4694
- const timestamp = now();
4695
- d.run(`INSERT INTO plans (id, project_id, task_list_id, agent_id, name, description, status, created_at, updated_at)
4696
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
4697
- id,
4698
- input.project_id || null,
4699
- input.task_list_id || null,
4700
- input.agent_id || null,
4701
- input.name,
4702
- input.description || null,
4703
- input.status || "active",
4704
- timestamp,
4705
- timestamp
4706
- ]);
4707
- return getPlan(id, d);
4708
- }
4709
- function getPlan(id, db) {
4710
- const d = db || getDatabase();
4711
- const row = d.query("SELECT * FROM plans WHERE id = ?").get(id);
4712
- return row;
4713
- }
4714
- function listPlans(projectId, db) {
4715
- const d = db || getDatabase();
4716
- if (projectId) {
4717
- return d.query("SELECT * FROM plans WHERE project_id = ? ORDER BY created_at DESC").all(projectId);
4718
- }
4719
- return d.query("SELECT * FROM plans ORDER BY created_at DESC").all();
4720
- }
4721
- function updatePlan(id, input, db) {
4722
- const d = db || getDatabase();
4723
- const plan = getPlan(id, d);
4724
- if (!plan)
4725
- throw new PlanNotFoundError(id);
4726
- const sets = ["updated_at = ?"];
4727
- const params = [now()];
4728
- if (input.name !== undefined) {
4729
- sets.push("name = ?");
4730
- params.push(input.name);
4731
- }
4732
- if (input.description !== undefined) {
4733
- sets.push("description = ?");
4734
- params.push(input.description);
4735
- }
4736
- if (input.status !== undefined) {
4737
- sets.push("status = ?");
4738
- params.push(input.status);
4739
- }
4740
- if (input.task_list_id !== undefined) {
4741
- sets.push("task_list_id = ?");
4742
- params.push(input.task_list_id);
4743
- }
4744
- if (input.agent_id !== undefined) {
4745
- sets.push("agent_id = ?");
4746
- params.push(input.agent_id);
4747
- }
4748
- params.push(id);
4749
- d.run(`UPDATE plans SET ${sets.join(", ")} WHERE id = ?`, params);
4750
- const updated = getPlan(id, d);
4751
- emitLocalEventHooksQuiet({
4752
- type: "plan.updated",
4753
- payload: { id, old_status: plan.status, new_status: updated.status, name: updated.name, project_id: updated.project_id }
4754
- });
4755
- return updated;
4756
- }
4757
- function deletePlan(id, db) {
4758
- const d = db || getDatabase();
4759
- const result = d.run("DELETE FROM plans WHERE id = ?", [id]);
4760
- return result.changes > 0;
4761
- }
4762
-
4763
5167
  // src/db/orgs.ts
4764
5168
  init_database();
4765
5169
  function rowToOrg(row) {
@@ -4809,40 +5213,6 @@ function deleteOrg(id, db) {
4809
5213
  return d.run("DELETE FROM orgs WHERE id = ?", [id]).changes > 0;
4810
5214
  }
4811
5215
 
4812
- // src/db/comments.ts
4813
- init_database();
4814
- function addComment(input, db) {
4815
- const d = db || getDatabase();
4816
- if (!getTask(input.task_id, d)) {
4817
- throw new TaskNotFoundError(input.task_id);
4818
- }
4819
- const id = uuid();
4820
- const timestamp = now();
4821
- d.run(`INSERT INTO task_comments (id, task_id, agent_id, session_id, content, type, progress_pct, created_at)
4822
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
4823
- id,
4824
- input.task_id,
4825
- input.agent_id || null,
4826
- input.session_id || null,
4827
- input.content,
4828
- input.type || "comment",
4829
- input.progress_pct ?? null,
4830
- timestamp
4831
- ]);
4832
- return getComment(id, d);
4833
- }
4834
- function logProgress(taskId, message, pct, agentId, db) {
4835
- return addComment({ task_id: taskId, content: message, type: "progress", progress_pct: pct, agent_id: agentId }, db);
4836
- }
4837
- function getComment(id, db) {
4838
- const d = db || getDatabase();
4839
- return d.query("SELECT * FROM task_comments WHERE id = ?").get(id);
4840
- }
4841
- function listComments(taskId, db) {
4842
- const d = db || getDatabase();
4843
- return d.query("SELECT * FROM task_comments WHERE task_id = ? ORDER BY created_at").all(taskId);
4844
- }
4845
-
4846
5216
  // src/server/routes.ts
4847
5217
  import { join as join5, resolve as resolve5, sep } from "path";
4848
5218
  function parseFieldsParam(url) {