sensorium-mcp 3.1.2 → 3.1.3-board.2

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 (217) hide show
  1. package/Install-Sensorium.ps1 +61 -0
  2. package/dist/board/api/api.js +61 -0
  3. package/dist/board/api/client.js +96 -0
  4. package/dist/board/components/BottomNav.js +32 -0
  5. package/dist/board/components/Card.js +44 -0
  6. package/dist/board/components/CommentComposer.js +26 -0
  7. package/dist/board/components/CommentList.js +39 -0
  8. package/dist/board/components/Dropdown.js +66 -0
  9. package/dist/board/components/Lane.js +40 -0
  10. package/dist/board/components/PriorityChip.js +17 -0
  11. package/dist/board/components/ProfileSummary.js +39 -0
  12. package/dist/board/components/StateBanner.js +22 -0
  13. package/dist/board/components/StatusChip.js +21 -0
  14. package/dist/board/components/TokenEntry.js +42 -0
  15. package/dist/board/config.js +56 -0
  16. package/dist/board/index.html +18 -0
  17. package/dist/board/main.js +37 -0
  18. package/dist/board/mock/api.mock.js +193 -0
  19. package/dist/board/mock/fixtures.js +164 -0
  20. package/dist/board/schema/policy.js +192 -0
  21. package/dist/board/state/auth.js +55 -0
  22. package/dist/board/state/useBoard.js +149 -0
  23. package/dist/board/state/useBuilder.js +98 -0
  24. package/dist/board/state/useCard.js +67 -0
  25. package/dist/board/styles/board.css +1760 -0
  26. package/dist/board/styles/tokens.css +71 -0
  27. package/dist/board/vendor/vue.esm-browser.js +9 -0
  28. package/dist/board/views/App.js +65 -0
  29. package/dist/board/views/BoardView.js +84 -0
  30. package/dist/board/views/BuilderView.js +303 -0
  31. package/dist/board/views/CardView.js +245 -0
  32. package/dist/board/views/SettingsView.js +145 -0
  33. package/dist/config/agent-settings.d.ts +2 -0
  34. package/dist/config/agent-settings.d.ts.map +1 -1
  35. package/dist/config/agent-settings.js +23 -0
  36. package/dist/config/agent-settings.js.map +1 -1
  37. package/dist/config/index.d.ts +1 -0
  38. package/dist/config/index.d.ts.map +1 -1
  39. package/dist/config/index.js +12 -0
  40. package/dist/config/index.js.map +1 -1
  41. package/dist/config/misc-settings.d.ts +14 -0
  42. package/dist/config/misc-settings.d.ts.map +1 -1
  43. package/dist/config/misc-settings.js +53 -0
  44. package/dist/config/misc-settings.js.map +1 -1
  45. package/dist/dashboard/board-static.d.ts +23 -0
  46. package/dist/dashboard/board-static.d.ts.map +1 -0
  47. package/dist/dashboard/board-static.js +131 -0
  48. package/dist/dashboard/board-static.js.map +1 -0
  49. package/dist/dashboard/routes/board.d.ts +73 -0
  50. package/dist/dashboard/routes/board.d.ts.map +1 -0
  51. package/dist/dashboard/routes/board.js +623 -0
  52. package/dist/dashboard/routes/board.js.map +1 -0
  53. package/dist/dashboard/routes/claude.d.ts.map +1 -1
  54. package/dist/dashboard/routes/claude.js +10 -1
  55. package/dist/dashboard/routes/claude.js.map +1 -1
  56. package/dist/dashboard/routes/settings.d.ts +2 -0
  57. package/dist/dashboard/routes/settings.d.ts.map +1 -1
  58. package/dist/dashboard/routes/settings.js +24 -1
  59. package/dist/dashboard/routes/settings.js.map +1 -1
  60. package/dist/dashboard/routes/threads-read.d.ts +7 -3
  61. package/dist/dashboard/routes/threads-read.d.ts.map +1 -1
  62. package/dist/dashboard/routes/threads-read.js +19 -4
  63. package/dist/dashboard/routes/threads-read.js.map +1 -1
  64. package/dist/dashboard/routes/types.d.ts +6 -0
  65. package/dist/dashboard/routes/types.d.ts.map +1 -1
  66. package/dist/dashboard/routes/types.js.map +1 -1
  67. package/dist/dashboard/routes.d.ts.map +1 -1
  68. package/dist/dashboard/routes.js +42 -1
  69. package/dist/dashboard/routes.js.map +1 -1
  70. package/dist/dashboard/spa.html +12 -12
  71. package/dist/data/board/board-schema.d.ts +22 -0
  72. package/dist/data/board/board-schema.d.ts.map +1 -0
  73. package/dist/data/board/board-schema.js +103 -0
  74. package/dist/data/board/board-schema.js.map +1 -0
  75. package/dist/data/board/board-types.d.ts +117 -0
  76. package/dist/data/board/board-types.d.ts.map +1 -0
  77. package/dist/data/board/board-types.js +9 -0
  78. package/dist/data/board/board-types.js.map +1 -0
  79. package/dist/data/board/card.repository.d.ts +64 -0
  80. package/dist/data/board/card.repository.d.ts.map +1 -0
  81. package/dist/data/board/card.repository.js +272 -0
  82. package/dist/data/board/card.repository.js.map +1 -0
  83. package/dist/data/board/comment.repository.d.ts +12 -0
  84. package/dist/data/board/comment.repository.d.ts.map +1 -0
  85. package/dist/data/board/comment.repository.js +31 -0
  86. package/dist/data/board/comment.repository.js.map +1 -0
  87. package/dist/data/board/lane.repository.d.ts +18 -0
  88. package/dist/data/board/lane.repository.d.ts.map +1 -0
  89. package/dist/data/board/lane.repository.js +44 -0
  90. package/dist/data/board/lane.repository.js.map +1 -0
  91. package/dist/data/board/profile-defaults.d.ts +19 -0
  92. package/dist/data/board/profile-defaults.d.ts.map +1 -0
  93. package/dist/data/board/profile-defaults.js +118 -0
  94. package/dist/data/board/profile-defaults.js.map +1 -0
  95. package/dist/data/memory/migration-runner.d.ts.map +1 -1
  96. package/dist/data/memory/migration-runner.js +4 -0
  97. package/dist/data/memory/migration-runner.js.map +1 -1
  98. package/dist/data/memory/narrative-store.d.ts +14 -0
  99. package/dist/data/memory/narrative-store.d.ts.map +1 -1
  100. package/dist/data/memory/narrative-store.js +36 -0
  101. package/dist/data/memory/narrative-store.js.map +1 -1
  102. package/dist/data/memory/narrative.d.ts.map +1 -1
  103. package/dist/data/memory/narrative.js +13 -1
  104. package/dist/data/memory/narrative.js.map +1 -1
  105. package/dist/data/memory/schema.d.ts.map +1 -1
  106. package/dist/data/memory/schema.js +4 -0
  107. package/dist/data/memory/schema.js.map +1 -1
  108. package/dist/index.js +84 -2
  109. package/dist/index.js.map +1 -1
  110. package/dist/integrations/openai/speech.d.ts.map +1 -1
  111. package/dist/integrations/openai/speech.js +52 -19
  112. package/dist/integrations/openai/speech.js.map +1 -1
  113. package/dist/lib/http-retry.d.ts +91 -0
  114. package/dist/lib/http-retry.d.ts.map +1 -0
  115. package/dist/lib/http-retry.js +177 -0
  116. package/dist/lib/http-retry.js.map +1 -0
  117. package/dist/lib/usage-metering/pricing.js +1 -1
  118. package/dist/lib/usage-metering/pricing.js.map +1 -1
  119. package/dist/lib/utils.d.ts +10 -0
  120. package/dist/lib/utils.d.ts.map +1 -1
  121. package/dist/lib/utils.js +22 -0
  122. package/dist/lib/utils.js.map +1 -1
  123. package/dist/server/http-server.d.ts +3 -1
  124. package/dist/server/http-server.d.ts.map +1 -1
  125. package/dist/server/http-server.js +6 -2
  126. package/dist/server/http-server.js.map +1 -1
  127. package/dist/services/board/board-signals.d.ts +25 -0
  128. package/dist/services/board/board-signals.d.ts.map +1 -0
  129. package/dist/services/board/board-signals.js +83 -0
  130. package/dist/services/board/board-signals.js.map +1 -0
  131. package/dist/services/board/card-briefing.d.ts +17 -0
  132. package/dist/services/board/card-briefing.d.ts.map +1 -0
  133. package/dist/services/board/card-briefing.js +86 -0
  134. package/dist/services/board/card-briefing.js.map +1 -0
  135. package/dist/services/board/orchestrator.service.d.ts +55 -0
  136. package/dist/services/board/orchestrator.service.d.ts.map +1 -0
  137. package/dist/services/board/orchestrator.service.js +198 -0
  138. package/dist/services/board/orchestrator.service.js.map +1 -0
  139. package/dist/services/board/release-worker.d.ts +32 -0
  140. package/dist/services/board/release-worker.d.ts.map +1 -0
  141. package/dist/services/board/release-worker.js +49 -0
  142. package/dist/services/board/release-worker.js.map +1 -0
  143. package/dist/services/board/report-capture.d.ts +48 -0
  144. package/dist/services/board/report-capture.d.ts.map +1 -0
  145. package/dist/services/board/report-capture.js +172 -0
  146. package/dist/services/board/report-capture.js.map +1 -0
  147. package/dist/services/board/worker-spawn.d.ts +30 -0
  148. package/dist/services/board/worker-spawn.d.ts.map +1 -0
  149. package/dist/services/board/worker-spawn.js +90 -0
  150. package/dist/services/board/worker-spawn.js.map +1 -0
  151. package/dist/services/broker-client.d.ts +30 -0
  152. package/dist/services/broker-client.d.ts.map +1 -1
  153. package/dist/services/broker-client.js +23 -0
  154. package/dist/services/broker-client.js.map +1 -1
  155. package/dist/services/codex-spawn.service.d.ts +2 -2
  156. package/dist/services/codex-spawn.service.d.ts.map +1 -1
  157. package/dist/services/codex-spawn.service.js +54 -54
  158. package/dist/services/codex-spawn.service.js.map +1 -1
  159. package/dist/services/http-retry.d.ts +1 -90
  160. package/dist/services/http-retry.d.ts.map +1 -1
  161. package/dist/services/http-retry.js +1 -176
  162. package/dist/services/http-retry.js.map +1 -1
  163. package/dist/services/mcp-config.service.d.ts.map +1 -1
  164. package/dist/services/mcp-config.service.js +5 -1
  165. package/dist/services/mcp-config.service.js.map +1 -1
  166. package/dist/services/passive-notice.service.d.ts +39 -0
  167. package/dist/services/passive-notice.service.d.ts.map +1 -0
  168. package/dist/services/passive-notice.service.js +274 -0
  169. package/dist/services/passive-notice.service.js.map +1 -0
  170. package/dist/services/spawn-common.d.ts.map +1 -1
  171. package/dist/services/spawn-common.js +14 -1
  172. package/dist/services/spawn-common.js.map +1 -1
  173. package/dist/services/telegram.d.ts +7 -5
  174. package/dist/services/telegram.d.ts.map +1 -1
  175. package/dist/services/telegram.js +18 -13
  176. package/dist/services/telegram.js.map +1 -1
  177. package/dist/services/usage/usage-inbox-notifier.d.ts +50 -0
  178. package/dist/services/usage/usage-inbox-notifier.d.ts.map +1 -0
  179. package/dist/services/usage/usage-inbox-notifier.js +118 -0
  180. package/dist/services/usage/usage-inbox-notifier.js.map +1 -0
  181. package/dist/services/usage/usage-poller.service.d.ts +41 -0
  182. package/dist/services/usage/usage-poller.service.d.ts.map +1 -0
  183. package/dist/services/usage/usage-poller.service.js +66 -0
  184. package/dist/services/usage/usage-poller.service.js.map +1 -0
  185. package/dist/services/usage/usage-snapshot-provider.d.ts +29 -0
  186. package/dist/services/usage/usage-snapshot-provider.d.ts.map +1 -0
  187. package/dist/services/usage/usage-snapshot-provider.js +59 -0
  188. package/dist/services/usage/usage-snapshot-provider.js.map +1 -0
  189. package/dist/services/usage/usage-types.d.ts +23 -0
  190. package/dist/services/usage/usage-types.d.ts.map +1 -0
  191. package/dist/services/usage/usage-types.js +14 -0
  192. package/dist/services/usage/usage-types.js.map +1 -0
  193. package/dist/services/worker-cleanup.service.d.ts +6 -1
  194. package/dist/services/worker-cleanup.service.d.ts.map +1 -1
  195. package/dist/services/worker-cleanup.service.js +123 -10
  196. package/dist/services/worker-cleanup.service.js.map +1 -1
  197. package/dist/tools/delegate-tool.d.ts.map +1 -1
  198. package/dist/tools/delegate-tool.js +34 -2
  199. package/dist/tools/delegate-tool.js.map +1 -1
  200. package/dist/tools/utility-tools.d.ts.map +1 -1
  201. package/dist/tools/utility-tools.js +7 -3
  202. package/dist/tools/utility-tools.js.map +1 -1
  203. package/dist/tools/wait/consolidation-strategy.d.ts +42 -0
  204. package/dist/tools/wait/consolidation-strategy.d.ts.map +1 -0
  205. package/dist/tools/wait/consolidation-strategy.js +50 -0
  206. package/dist/tools/wait/consolidation-strategy.js.map +1 -0
  207. package/dist/tools/wait/drive-handler.d.ts +5 -7
  208. package/dist/tools/wait/drive-handler.d.ts.map +1 -1
  209. package/dist/tools/wait/drive-handler.js +30 -48
  210. package/dist/tools/wait/drive-handler.js.map +1 -1
  211. package/dist/tools/wait/message-delivery.d.ts.map +1 -1
  212. package/dist/tools/wait/message-delivery.js +13 -0
  213. package/dist/tools/wait/message-delivery.js.map +1 -1
  214. package/package.json +2 -2
  215. package/templates/atomic-build-spec.default.md +57 -0
  216. package/templates/buildless-vue-preview.default.md +47 -0
  217. package/templates/phased-build.default.md +59 -0
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Agent Task Board — SQLite DDL + its OWN schema versioning.
3
+ *
4
+ * The board deliberately does NOT consume a number from the memory system's
5
+ * schema_version sequence (kernel review MED: a feature branch claiming main's
6
+ * next number means whichever line ships second gets silently skipped on DBs
7
+ * that rode the other). Board DDL versions live in board_schema_version and
8
+ * are applied by ensureBoardSchema() after the main migrations run.
9
+ *
10
+ * Design: implementation_plans/2026-08-01_agent-task-board-design.md §2.
11
+ * Single-writer invariant: only dashboard routes and the board orchestrator
12
+ * write these tables — there is no agent-facing (MCP tool) write path.
13
+ */
14
+ import type { Database } from "../memory/db-types.js";
15
+ export declare const BOARD_SCHEMA_SQL = "\nCREATE TABLE IF NOT EXISTS board_cards (\n card_id INTEGER PRIMARY KEY AUTOINCREMENT,\n title TEXT NOT NULL,\n description TEXT NOT NULL DEFAULT '',\n acceptance TEXT NOT NULL DEFAULT '',\n type TEXT NOT NULL DEFAULT 'chore',\n lane_thread_id INTEGER NOT NULL,\n priority INTEGER NOT NULL DEFAULT 0,\n status TEXT NOT NULL DEFAULT 'backlog'\n CHECK(status IN ('backlog','in_progress','blocked','done')),\n profile_json TEXT NOT NULL DEFAULT '{}',\n escalate INTEGER NOT NULL DEFAULT 0,\n recur_delay_min INTEGER,\n recur_group_id INTEGER,\n next_spawn_at TEXT,\n worker_thread_id INTEGER,\n blocked_reason TEXT,\n archived_at TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n started_at TEXT,\n finished_at TEXT\n);\nCREATE INDEX IF NOT EXISTS idx_board_cards_lane_status ON board_cards(lane_thread_id, status);\nCREATE INDEX IF NOT EXISTS idx_board_cards_worker ON board_cards(worker_thread_id)\n WHERE worker_thread_id IS NOT NULL;\nCREATE INDEX IF NOT EXISTS idx_board_cards_recur ON board_cards(recur_group_id)\n WHERE recur_group_id IS NOT NULL;\n\nCREATE TABLE IF NOT EXISTS board_comments (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n card_id INTEGER NOT NULL REFERENCES board_cards(card_id),\n author TEXT NOT NULL CHECK(author IN ('operator','worker','board')),\n content TEXT NOT NULL,\n created_at TEXT NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_board_comments_card ON board_comments(card_id, created_at);\n\nCREATE TABLE IF NOT EXISTS board_lanes (\n thread_id INTEGER PRIMARY KEY,\n connected INTEGER NOT NULL DEFAULT 1,\n max_concurrent INTEGER NOT NULL DEFAULT 1,\n created_at TEXT NOT NULL\n);\n";
16
+ /**
17
+ * Apply board schema migrations (own version table, independent of the memory
18
+ * system's schema_version). Called from initMemoryDb after runMigrations.
19
+ * Same transactional halt-on-failure contract as the main runner.
20
+ */
21
+ export declare function ensureBoardSchema(db: Database): void;
22
+ //# sourceMappingURL=board-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"board-schema.d.ts","sourceRoot":"","sources":["../../../src/data/board/board-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAItD,eAAO,MAAM,gBAAgB,+0DA6C5B,CAAC;AAUF;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CA6BpD"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Agent Task Board — SQLite DDL + its OWN schema versioning.
3
+ *
4
+ * The board deliberately does NOT consume a number from the memory system's
5
+ * schema_version sequence (kernel review MED: a feature branch claiming main's
6
+ * next number means whichever line ships second gets silently skipped on DBs
7
+ * that rode the other). Board DDL versions live in board_schema_version and
8
+ * are applied by ensureBoardSchema() after the main migrations run.
9
+ *
10
+ * Design: implementation_plans/2026-08-01_agent-task-board-design.md §2.
11
+ * Single-writer invariant: only dashboard routes and the board orchestrator
12
+ * write these tables — there is no agent-facing (MCP tool) write path.
13
+ */
14
+ import { log } from "../../lib/logger.js";
15
+ import { errorMessage } from "../../lib/utils.js";
16
+ export const BOARD_SCHEMA_SQL = `
17
+ CREATE TABLE IF NOT EXISTS board_cards (
18
+ card_id INTEGER PRIMARY KEY AUTOINCREMENT,
19
+ title TEXT NOT NULL,
20
+ description TEXT NOT NULL DEFAULT '',
21
+ acceptance TEXT NOT NULL DEFAULT '',
22
+ type TEXT NOT NULL DEFAULT 'chore',
23
+ lane_thread_id INTEGER NOT NULL,
24
+ priority INTEGER NOT NULL DEFAULT 0,
25
+ status TEXT NOT NULL DEFAULT 'backlog'
26
+ CHECK(status IN ('backlog','in_progress','blocked','done')),
27
+ profile_json TEXT NOT NULL DEFAULT '{}',
28
+ escalate INTEGER NOT NULL DEFAULT 0,
29
+ recur_delay_min INTEGER,
30
+ recur_group_id INTEGER,
31
+ next_spawn_at TEXT,
32
+ worker_thread_id INTEGER,
33
+ blocked_reason TEXT,
34
+ archived_at TEXT,
35
+ created_at TEXT NOT NULL,
36
+ updated_at TEXT NOT NULL,
37
+ started_at TEXT,
38
+ finished_at TEXT
39
+ );
40
+ CREATE INDEX IF NOT EXISTS idx_board_cards_lane_status ON board_cards(lane_thread_id, status);
41
+ CREATE INDEX IF NOT EXISTS idx_board_cards_worker ON board_cards(worker_thread_id)
42
+ WHERE worker_thread_id IS NOT NULL;
43
+ CREATE INDEX IF NOT EXISTS idx_board_cards_recur ON board_cards(recur_group_id)
44
+ WHERE recur_group_id IS NOT NULL;
45
+
46
+ CREATE TABLE IF NOT EXISTS board_comments (
47
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
48
+ card_id INTEGER NOT NULL REFERENCES board_cards(card_id),
49
+ author TEXT NOT NULL CHECK(author IN ('operator','worker','board')),
50
+ content TEXT NOT NULL,
51
+ created_at TEXT NOT NULL
52
+ );
53
+ CREATE INDEX IF NOT EXISTS idx_board_comments_card ON board_comments(card_id, created_at);
54
+
55
+ CREATE TABLE IF NOT EXISTS board_lanes (
56
+ thread_id INTEGER PRIMARY KEY,
57
+ connected INTEGER NOT NULL DEFAULT 1,
58
+ max_concurrent INTEGER NOT NULL DEFAULT 1,
59
+ created_at TEXT NOT NULL
60
+ );
61
+ `;
62
+ const BOARD_SCHEMA_VERSION = 1;
63
+ const BOARD_MIGRATIONS = {
64
+ 1: (db) => {
65
+ db.exec(BOARD_SCHEMA_SQL);
66
+ },
67
+ };
68
+ /**
69
+ * Apply board schema migrations (own version table, independent of the memory
70
+ * system's schema_version). Called from initMemoryDb after runMigrations.
71
+ * Same transactional halt-on-failure contract as the main runner.
72
+ */
73
+ export function ensureBoardSchema(db) {
74
+ db.exec(`CREATE TABLE IF NOT EXISTS board_schema_version (
75
+ version INTEGER PRIMARY KEY,
76
+ applied_at TEXT NOT NULL
77
+ );`);
78
+ let current = 0;
79
+ try {
80
+ const row = db.prepare(`SELECT MAX(version) AS v FROM board_schema_version`).get();
81
+ current = row?.v ?? 0;
82
+ }
83
+ catch (err) {
84
+ log.warn(`[board-schema] version read failed (assuming 0): ${errorMessage(err)}`);
85
+ }
86
+ for (let v = current + 1; v <= BOARD_SCHEMA_VERSION; v++) {
87
+ const migration = BOARD_MIGRATIONS[v];
88
+ if (!migration)
89
+ continue;
90
+ try {
91
+ db.transaction(() => {
92
+ migration(db);
93
+ db.prepare(`INSERT OR REPLACE INTO board_schema_version (version, applied_at) VALUES (?, datetime('now'))`).run(v);
94
+ })();
95
+ log.info(`[board-schema] Migrated board schema to version ${v}`);
96
+ }
97
+ catch (err) {
98
+ log.error(`[board-schema] Migration ${v} failed: ${errorMessage(err)} — halting.`);
99
+ break;
100
+ }
101
+ }
102
+ }
103
+ //# sourceMappingURL=board-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"board-schema.js","sourceRoot":"","sources":["../../../src/data/board/board-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,CAAC,MAAM,gBAAgB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6C/B,CAAC;AAEF,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAE/B,MAAM,gBAAgB,GAA2C;IAC/D,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE;QACR,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC5B,CAAC;CACF,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAAY;IAC5C,EAAE,CAAC,IAAI,CAAC;;;KAGL,CAAC,CAAC;IACL,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,oDAAoD,CAAC,CAAC,GAAG,EAC9C,CAAC;QACnC,OAAO,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,IAAI,CAAC,oDAAoD,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACpF,CAAC;IACD,KAAK,IAAI,CAAC,GAAG,OAAO,GAAG,CAAC,EAAE,CAAC,IAAI,oBAAoB,EAAE,CAAC,EAAE,EAAE,CAAC;QACzD,MAAM,SAAS,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC;QACtC,IAAI,CAAC,SAAS;YAAE,SAAS;QACzB,IAAI,CAAC;YACH,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE;gBAClB,SAAS,CAAC,EAAE,CAAC,CAAC;gBACd,EAAE,CAAC,OAAO,CACR,+FAA+F,CAChG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACX,CAAC,CAAC,EAAE,CAAC;YACL,GAAG,CAAC,IAAI,CAAC,mDAAmD,CAAC,EAAE,CAAC,CAAC;QACnE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,4BAA4B,CAAC,YAAY,YAAY,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;YACnF,MAAM;QACR,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Agent Task Board — shared types.
3
+ *
4
+ * The card is the task's whole world: description + acceptance + execution
5
+ * profile + comment history form the complete briefing for a stateless
6
+ * card-worker (design §2, §3.2).
7
+ */
8
+ export type CardStatus = "backlog" | "in_progress" | "blocked" | "done";
9
+ export type CardType = "bug" | "feature" | "tech-debt" | "chore" | "research" | "recurring-ops";
10
+ export type CommentAuthor = "operator" | "worker" | "board";
11
+ /**
12
+ * Execution profile — the operator's standing orders for a task, declared
13
+ * once at card creation so the worker never has a question mid-run (spec §4).
14
+ * Every field optional; the card's type seeds defaults (profile-defaults.ts).
15
+ */
16
+ export interface ExecutionProfile {
17
+ /** Repository to work in (path or URL). Blank → worker's cwd default. */
18
+ repository?: string;
19
+ /** Create a work branch (name auto-derived from the card when true). */
20
+ createBranch?: boolean;
21
+ /** Skills the worker must load via get_skill before starting. */
22
+ skills?: string[];
23
+ /** Operator must review the result before the card may be closed. */
24
+ operatorReview?: boolean;
25
+ /** Open a pull request with the changes. */
26
+ openPr?: boolean;
27
+ /** Spawn an expert code-review worker over the diff. */
28
+ expertReview?: boolean;
29
+ /** Reviewer provider when expertReview is on (operator amendment 2026-08-01:
30
+ * review MAY use fable; the core build never fans out). */
31
+ reviewAgentType?: "claude" | "copilot" | "codex" | "fable";
32
+ /** Single worker or allow splitting into multiple workers. */
33
+ workerSplit?: "single" | "multi";
34
+ /** Provider that runs the card. Fable ONLY by explicit choice, never by size. */
35
+ agentType?: "claude" | "copilot" | "codex" | "fable";
36
+ /** Model bucket within the provider; blank → auto-classifier decides. */
37
+ size?: "operational" | "code";
38
+ runTests?: boolean;
39
+ build?: boolean;
40
+ push?: boolean;
41
+ /** Where to verify CI after pushing. */
42
+ ciCheck?: "none" | "github" | "azure";
43
+ /** RESERVED (v1 unimplemented): run inline in the lane thread instead of a worker. */
44
+ inline?: boolean;
45
+ /** Optional per-card hard TTL override (minutes) for the card-worker. Blank →
46
+ * the WORKER_CARD_TTL_HOURS default; always clamped to WORKER_CARD_TTL_MAX_HOURS.
47
+ * Anchored to created_at like every worker TTL (no idle/activity anchor). */
48
+ ttlMinutes?: number;
49
+ }
50
+ export interface BoardCard {
51
+ cardId: number;
52
+ title: string;
53
+ description: string;
54
+ acceptance: string;
55
+ type: string;
56
+ laneThreadId: number;
57
+ priority: number;
58
+ status: CardStatus;
59
+ profile: ExecutionProfile;
60
+ escalate: boolean;
61
+ recurDelayMin: number | null;
62
+ recurGroupId: number | null;
63
+ nextSpawnAt: string | null;
64
+ workerThreadId: number | null;
65
+ blockedReason: string | null;
66
+ archivedAt: string | null;
67
+ createdAt: string;
68
+ updatedAt: string;
69
+ startedAt: string | null;
70
+ finishedAt: string | null;
71
+ }
72
+ export interface NewCard {
73
+ title: string;
74
+ description?: string;
75
+ acceptance?: string;
76
+ type?: string;
77
+ laneThreadId: number;
78
+ priority?: number;
79
+ profile?: ExecutionProfile;
80
+ escalate?: boolean;
81
+ recurDelayMin?: number;
82
+ /** Set by the recurrence respawner to link fresh copies to the original. */
83
+ recurGroupId?: number;
84
+ }
85
+ export interface CardPatch {
86
+ title?: string;
87
+ description?: string;
88
+ acceptance?: string;
89
+ type?: string;
90
+ laneThreadId?: number;
91
+ priority?: number;
92
+ status?: CardStatus;
93
+ profile?: ExecutionProfile;
94
+ escalate?: boolean;
95
+ recurDelayMin?: number | null;
96
+ recurGroupId?: number | null;
97
+ nextSpawnAt?: string | null;
98
+ workerThreadId?: number | null;
99
+ blockedReason?: string | null;
100
+ archivedAt?: string | null;
101
+ startedAt?: string | null;
102
+ finishedAt?: string | null;
103
+ }
104
+ export interface BoardComment {
105
+ id: number;
106
+ cardId: number;
107
+ author: CommentAuthor;
108
+ content: string;
109
+ createdAt: string;
110
+ }
111
+ export interface BoardLane {
112
+ threadId: number;
113
+ connected: boolean;
114
+ maxConcurrent: number;
115
+ createdAt: string;
116
+ }
117
+ //# sourceMappingURL=board-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"board-types.d.ts","sourceRoot":"","sources":["../../../src/data/board/board-types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Agent Task Board — shared types.
3
+ *
4
+ * The card is the task's whole world: description + acceptance + execution
5
+ * profile + comment history form the complete briefing for a stateless
6
+ * card-worker (design §2, §3.2).
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=board-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"board-types.js","sourceRoot":"","sources":["../../../src/data/board/board-types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Agent Task Board — card CRUD + orchestrator queries.
3
+ *
4
+ * Writers: dashboard routes (operator) and the board orchestrator only.
5
+ * Agents never touch these tables (single-writer invariant, design §2).
6
+ */
7
+ import type { Database } from "../memory/db-types.js";
8
+ import type { BoardCard, CardPatch, CardStatus, NewCard } from "./board-types.js";
9
+ export declare function createCard(db: Database, card: NewCard): BoardCard;
10
+ export declare function getCard(db: Database, cardId: number): BoardCard | undefined;
11
+ export declare function listCards(db: Database, opts?: {
12
+ includeArchived?: boolean;
13
+ laneThreadId?: number;
14
+ status?: CardStatus;
15
+ }): BoardCard[];
16
+ export declare function updateCard(db: Database, cardId: number, patch: CardPatch): BoardCard | undefined;
17
+ export declare function deleteCard(db: Database, cardId: number): boolean;
18
+ /** Top-priority dispatchable Backlog card for a lane (priority DESC, oldest first). */
19
+ export declare function getNextDispatchableCard(db: Database, laneThreadId: number): BoardCard | undefined;
20
+ /**
21
+ * THE one DONE transition (single source — operator "Mark Done", worker
22
+ * STATUS: DONE, and any future path must all build the patch here; three
23
+ * hand-rolled copies had already drifted on blockedReason).
24
+ */
25
+ export declare function buildDonePatch(card: BoardCard): CardPatch;
26
+ /**
27
+ * Atomically claim a Backlog card for dispatch (compare-and-set on status).
28
+ * Returns false when another process/tick already claimed, archived, or moved
29
+ * it — the caller must NOT spawn in that case. This is the in-DB guard against
30
+ * double-dispatch across concurrent orchestrators (self-update overlap) and
31
+ * against operator moves racing an in-flight tick.
32
+ */
33
+ export declare function claimCardForDispatch(db: Database, cardId: number): boolean;
34
+ /** Bind the spawned worker to a card ONLY while it is still in_progress (an
35
+ * operator move/delete during the async spawn must win, not be clobbered). */
36
+ export declare function bindWorkerToCard(db: Database, cardId: number, workerThreadId: number): boolean;
37
+ /**
38
+ * CAS block for a card still bound to a specific worker (exit safety net).
39
+ * Blocks ONLY when the card is in_progress AND its worker is still this exact
40
+ * thread — so two concurrent callers (worker teardown vs a reconcile tick,
41
+ * possibly cross-process) cannot both emit a BLOCKED signal. Returns the
42
+ * updated card when it changed exactly one row, else undefined (another path
43
+ * already handled it → the caller must no-op).
44
+ */
45
+ export declare function blockBoundWorkerCard(db: Database, cardId: number, workerThreadId: number, reason: string): BoardCard | undefined;
46
+ /**
47
+ * CAS block for a claimed-but-unbound card (dispatch died between claim and
48
+ * bind, leaving it in_progress with NO worker). Blocks ONLY while it is still
49
+ * in_progress AND worker_thread_id IS NULL, so a late bind or another reconcile
50
+ * tick cannot double-block. Returns the updated card when it changed exactly
51
+ * one row, else undefined.
52
+ */
53
+ export declare function blockUnboundCard(db: Database, cardId: number, reason: string): BoardCard | undefined;
54
+ export declare function countInProgress(db: Database, laneThreadId?: number): number;
55
+ /** The in_progress card a live card-worker belongs to (report interception key). */
56
+ export declare function findCardByWorkerThread(db: Database, workerThreadId: number): BoardCard | undefined;
57
+ /**
58
+ * Done recurring cards whose respawn delay has elapsed AND whose group has no
59
+ * live instance outside Done (single-live-instance anti-clutter, design §4).
60
+ */
61
+ export declare function listDueRecurrences(db: Database, nowIso: string): BoardCard[];
62
+ /** Auto-archive Done cards older than `days` (hidden, never deleted — design §4). */
63
+ export declare function archiveDoneOlderThan(db: Database, days: number): number;
64
+ //# sourceMappingURL=card.repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card.repository.d.ts","sourceRoot":"","sources":["../../../src/data/board/card.repository.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAItD,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAoB,OAAO,EAAE,MAAM,kBAAkB,CAAC;AA4DpG,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,GAAG,SAAS,CA0CjE;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAI3E;AAED,wBAAgB,SAAS,CACvB,EAAE,EAAE,QAAQ,EACZ,IAAI,GAAE;IAAE,eAAe,CAAC,EAAE,OAAO,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,UAAU,CAAA;CAAO,GACnF,SAAS,EAAE,CAiBb;AAuBD,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAmBhG;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAOhE;AAID,uFAAuF;AACvF,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CASjG;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,CAUzD;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAS1E;AAED;+EAC+E;AAC/E,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAQ9F;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,GACb,SAAS,GAAG,SAAS,CASvB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACb,SAAS,GAAG,SAAS,CASvB;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,QAAQ,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAiB3E;AAED,oFAAoF;AACpF,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,QAAQ,EACZ,cAAc,EAAE,MAAM,GACrB,SAAS,GAAG,SAAS,CAOvB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,CAe5E;AAED,qFAAqF;AACrF,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAUvE"}
@@ -0,0 +1,272 @@
1
+ /**
2
+ * Agent Task Board — card CRUD + orchestrator queries.
3
+ *
4
+ * Writers: dashboard routes (operator) and the board orchestrator only.
5
+ * Agents never touch these tables (single-writer invariant, design §2).
6
+ */
7
+ import { nowISO } from "../memory/utils.js";
8
+ import { log } from "../../lib/logger.js";
9
+ import { errorMessage } from "../../lib/utils.js";
10
+ function parseProfile(json) {
11
+ try {
12
+ const parsed = JSON.parse(json);
13
+ return typeof parsed === "object" && parsed !== null ? parsed : {};
14
+ }
15
+ catch (err) {
16
+ log.warn(`[board] Malformed profile_json — using empty profile: ${errorMessage(err)}`);
17
+ return {};
18
+ }
19
+ }
20
+ function mapRow(row) {
21
+ return {
22
+ cardId: row.card_id,
23
+ title: row.title,
24
+ description: row.description,
25
+ acceptance: row.acceptance,
26
+ type: row.type,
27
+ laneThreadId: row.lane_thread_id,
28
+ priority: row.priority,
29
+ status: row.status,
30
+ profile: parseProfile(row.profile_json),
31
+ escalate: row.escalate === 1,
32
+ recurDelayMin: row.recur_delay_min,
33
+ recurGroupId: row.recur_group_id,
34
+ nextSpawnAt: row.next_spawn_at,
35
+ workerThreadId: row.worker_thread_id,
36
+ blockedReason: row.blocked_reason,
37
+ archivedAt: row.archived_at,
38
+ createdAt: row.created_at,
39
+ updatedAt: row.updated_at,
40
+ startedAt: row.started_at,
41
+ finishedAt: row.finished_at,
42
+ };
43
+ }
44
+ export function createCard(db, card) {
45
+ // Insert + group-anchor update are one atomic unit (a crash between them
46
+ // left a recurring card with no group — invisible to recurrence forever).
47
+ return db.transaction(() => {
48
+ const now = nowISO();
49
+ // Defense-in-depth floor (the API also validates): recurDelayMin < 1 —
50
+ // e.g. an empty input coerced to 0 — would be a tight respawn loop.
51
+ const recurDelayMin = card.recurDelayMin != null ? Math.max(1, Math.trunc(card.recurDelayMin)) : null;
52
+ const result = db
53
+ .prepare(`INSERT INTO board_cards (
54
+ title, description, acceptance, type, lane_thread_id, priority,
55
+ profile_json, escalate, recur_delay_min, recur_group_id, created_at, updated_at
56
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
57
+ .run(card.title, card.description ?? "", card.acceptance ?? "", card.type ?? "chore", card.laneThreadId, card.priority ?? 0, JSON.stringify(card.profile ?? {}), card.escalate ? 1 : 0, recurDelayMin, card.recurGroupId ?? null, now, now);
58
+ const created = getCard(db, Number(result.lastInsertRowid));
59
+ if (!created)
60
+ throw new Error("board_cards insert did not persist");
61
+ // A recurring original anchors its own group so fresh copies can find it.
62
+ if (created.recurDelayMin != null && created.recurGroupId == null) {
63
+ db.prepare(`UPDATE board_cards SET recur_group_id = ? WHERE card_id = ?`).run(created.cardId, created.cardId);
64
+ created.recurGroupId = created.cardId;
65
+ }
66
+ return created;
67
+ })();
68
+ }
69
+ export function getCard(db, cardId) {
70
+ const row = db.prepare(`SELECT * FROM board_cards WHERE card_id = ?`).get(cardId);
71
+ return row ? mapRow(row) : undefined;
72
+ }
73
+ export function listCards(db, opts = {}) {
74
+ const where = [];
75
+ const params = [];
76
+ if (!opts.includeArchived)
77
+ where.push("archived_at IS NULL");
78
+ if (opts.laneThreadId !== undefined) {
79
+ where.push("lane_thread_id = ?");
80
+ params.push(opts.laneThreadId);
81
+ }
82
+ if (opts.status !== undefined) {
83
+ where.push("status = ?");
84
+ params.push(opts.status);
85
+ }
86
+ const sql = `SELECT * FROM board_cards` +
87
+ (where.length > 0 ? ` WHERE ${where.join(" AND ")}` : "") +
88
+ ` ORDER BY priority DESC, created_at ASC`;
89
+ return db.prepare(sql).all(...params).map(mapRow);
90
+ }
91
+ /** Column-name map for the dynamically assembled UPDATE in updateCard. */
92
+ const PATCH_COLUMNS = {
93
+ title: "title",
94
+ description: "description",
95
+ acceptance: "acceptance",
96
+ type: "type",
97
+ laneThreadId: "lane_thread_id",
98
+ priority: "priority",
99
+ status: "status",
100
+ profile: "profile_json",
101
+ escalate: "escalate",
102
+ recurDelayMin: "recur_delay_min",
103
+ recurGroupId: "recur_group_id",
104
+ nextSpawnAt: "next_spawn_at",
105
+ workerThreadId: "worker_thread_id",
106
+ blockedReason: "blocked_reason",
107
+ archivedAt: "archived_at",
108
+ startedAt: "started_at",
109
+ finishedAt: "finished_at",
110
+ };
111
+ export function updateCard(db, cardId, patch) {
112
+ const sets = [];
113
+ const params = [];
114
+ for (const [key, column] of Object.entries(PATCH_COLUMNS)) {
115
+ const value = patch[key];
116
+ // Test the VALUE, not key presence: `{ title: undefined }` must mean
117
+ // "unchanged", not "SET title = NULL" (which throws on NOT NULL columns).
118
+ // Nullable columns are cleared with an explicit null.
119
+ if (value === undefined)
120
+ continue;
121
+ sets.push(`${column} = ?`);
122
+ if (key === "profile")
123
+ params.push(JSON.stringify(value ?? {}));
124
+ else if (key === "escalate")
125
+ params.push(value ? 1 : 0);
126
+ else
127
+ params.push(value ?? null);
128
+ }
129
+ if (sets.length === 0)
130
+ return getCard(db, cardId);
131
+ sets.push("updated_at = ?");
132
+ params.push(nowISO(), cardId);
133
+ db.prepare(`UPDATE board_cards SET ${sets.join(", ")} WHERE card_id = ?`).run(...params);
134
+ return getCard(db, cardId);
135
+ }
136
+ export function deleteCard(db, cardId) {
137
+ // Atomic: never leave orphaned comments when the card delete fails mid-way.
138
+ return db.transaction(() => {
139
+ db.prepare(`DELETE FROM board_comments WHERE card_id = ?`).run(cardId);
140
+ const result = db.prepare(`DELETE FROM board_cards WHERE card_id = ?`).run(cardId);
141
+ return result.changes > 0;
142
+ })();
143
+ }
144
+ // ── Orchestrator queries (design §3) ────────────────────────────────────────
145
+ /** Top-priority dispatchable Backlog card for a lane (priority DESC, oldest first). */
146
+ export function getNextDispatchableCard(db, laneThreadId) {
147
+ const row = db
148
+ .prepare(`SELECT * FROM board_cards
149
+ WHERE lane_thread_id = ? AND status = 'backlog' AND archived_at IS NULL
150
+ ORDER BY priority DESC, created_at ASC LIMIT 1`)
151
+ .get(laneThreadId);
152
+ return row ? mapRow(row) : undefined;
153
+ }
154
+ /**
155
+ * THE one DONE transition (single source — operator "Mark Done", worker
156
+ * STATUS: DONE, and any future path must all build the patch here; three
157
+ * hand-rolled copies had already drifted on blockedReason).
158
+ */
159
+ export function buildDonePatch(card) {
160
+ return {
161
+ status: "done",
162
+ finishedAt: nowISO(),
163
+ workerThreadId: null,
164
+ blockedReason: null,
165
+ ...(card.recurDelayMin != null
166
+ ? { nextSpawnAt: new Date(Date.now() + card.recurDelayMin * 60_000).toISOString() }
167
+ : {}),
168
+ };
169
+ }
170
+ /**
171
+ * Atomically claim a Backlog card for dispatch (compare-and-set on status).
172
+ * Returns false when another process/tick already claimed, archived, or moved
173
+ * it — the caller must NOT spawn in that case. This is the in-DB guard against
174
+ * double-dispatch across concurrent orchestrators (self-update overlap) and
175
+ * against operator moves racing an in-flight tick.
176
+ */
177
+ export function claimCardForDispatch(db, cardId) {
178
+ const result = db
179
+ .prepare(`UPDATE board_cards
180
+ SET status = 'in_progress', started_at = ?, blocked_reason = NULL, updated_at = ?
181
+ WHERE card_id = ? AND status = 'backlog' AND archived_at IS NULL`)
182
+ .run(nowISO(), nowISO(), cardId);
183
+ return result.changes === 1;
184
+ }
185
+ /** Bind the spawned worker to a card ONLY while it is still in_progress (an
186
+ * operator move/delete during the async spawn must win, not be clobbered). */
187
+ export function bindWorkerToCard(db, cardId, workerThreadId) {
188
+ const result = db
189
+ .prepare(`UPDATE board_cards SET worker_thread_id = ?, updated_at = ?
190
+ WHERE card_id = ? AND status = 'in_progress' AND worker_thread_id IS NULL`)
191
+ .run(workerThreadId, nowISO(), cardId);
192
+ return result.changes === 1;
193
+ }
194
+ /**
195
+ * CAS block for a card still bound to a specific worker (exit safety net).
196
+ * Blocks ONLY when the card is in_progress AND its worker is still this exact
197
+ * thread — so two concurrent callers (worker teardown vs a reconcile tick,
198
+ * possibly cross-process) cannot both emit a BLOCKED signal. Returns the
199
+ * updated card when it changed exactly one row, else undefined (another path
200
+ * already handled it → the caller must no-op).
201
+ */
202
+ export function blockBoundWorkerCard(db, cardId, workerThreadId, reason) {
203
+ const result = db
204
+ .prepare(`UPDATE board_cards
205
+ SET status = 'blocked', blocked_reason = ?, worker_thread_id = NULL, updated_at = ?
206
+ WHERE card_id = ? AND status = 'in_progress' AND worker_thread_id = ?`)
207
+ .run(reason, nowISO(), cardId, workerThreadId);
208
+ return result.changes === 1 ? getCard(db, cardId) : undefined;
209
+ }
210
+ /**
211
+ * CAS block for a claimed-but-unbound card (dispatch died between claim and
212
+ * bind, leaving it in_progress with NO worker). Blocks ONLY while it is still
213
+ * in_progress AND worker_thread_id IS NULL, so a late bind or another reconcile
214
+ * tick cannot double-block. Returns the updated card when it changed exactly
215
+ * one row, else undefined.
216
+ */
217
+ export function blockUnboundCard(db, cardId, reason) {
218
+ const result = db
219
+ .prepare(`UPDATE board_cards
220
+ SET status = 'blocked', blocked_reason = ?, updated_at = ?
221
+ WHERE card_id = ? AND status = 'in_progress' AND worker_thread_id IS NULL`)
222
+ .run(reason, nowISO(), cardId);
223
+ return result.changes === 1 ? getCard(db, cardId) : undefined;
224
+ }
225
+ export function countInProgress(db, laneThreadId) {
226
+ const row = (laneThreadId !== undefined
227
+ ? db
228
+ .prepare(`SELECT COUNT(*) AS n FROM board_cards
229
+ WHERE status = 'in_progress' AND archived_at IS NULL AND lane_thread_id = ?`)
230
+ .get(laneThreadId)
231
+ : db
232
+ .prepare(`SELECT COUNT(*) AS n FROM board_cards
233
+ WHERE status = 'in_progress' AND archived_at IS NULL`)
234
+ .get());
235
+ return row.n;
236
+ }
237
+ /** The in_progress card a live card-worker belongs to (report interception key). */
238
+ export function findCardByWorkerThread(db, workerThreadId) {
239
+ const row = db
240
+ .prepare(`SELECT * FROM board_cards WHERE worker_thread_id = ? AND status = 'in_progress' LIMIT 1`)
241
+ .get(workerThreadId);
242
+ return row ? mapRow(row) : undefined;
243
+ }
244
+ /**
245
+ * Done recurring cards whose respawn delay has elapsed AND whose group has no
246
+ * live instance outside Done (single-live-instance anti-clutter, design §4).
247
+ */
248
+ export function listDueRecurrences(db, nowIso) {
249
+ const rows = db
250
+ .prepare(`SELECT * FROM board_cards c
251
+ WHERE c.status = 'done' AND c.recur_group_id IS NOT NULL
252
+ AND c.archived_at IS NULL
253
+ AND c.next_spawn_at IS NOT NULL AND c.next_spawn_at <= ?
254
+ AND NOT EXISTS (
255
+ SELECT 1 FROM board_cards o
256
+ WHERE o.recur_group_id = c.recur_group_id AND o.status != 'done'
257
+ AND o.archived_at IS NULL
258
+ )`)
259
+ .all(nowIso);
260
+ return rows.map(mapRow);
261
+ }
262
+ /** Auto-archive Done cards older than `days` (hidden, never deleted — design §4). */
263
+ export function archiveDoneOlderThan(db, days) {
264
+ const cutoff = new Date(Date.now() - days * 86_400_000).toISOString();
265
+ const result = db
266
+ .prepare(`UPDATE board_cards SET archived_at = ?, updated_at = ?
267
+ WHERE status = 'done' AND archived_at IS NULL AND finished_at IS NOT NULL
268
+ AND finished_at < ? AND next_spawn_at IS NULL`)
269
+ .run(nowISO(), nowISO(), cutoff);
270
+ return result.changes;
271
+ }
272
+ //# sourceMappingURL=card.repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card.repository.js","sourceRoot":"","sources":["../../../src/data/board/card.repository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Agent Task Board — card comments.
3
+ *
4
+ * All task chatter lives on the card (design §2): operator guidance, worker
5
+ * reports (written by the orchestrator from intercepted replies), and board
6
+ * lifecycle events. Comments are append-only.
7
+ */
8
+ import type { Database } from "../memory/db-types.js";
9
+ import type { BoardComment, CommentAuthor } from "./board-types.js";
10
+ export declare function addComment(db: Database, cardId: number, author: CommentAuthor, content: string): BoardComment;
11
+ export declare function listComments(db: Database, cardId: number): BoardComment[];
12
+ //# sourceMappingURL=comment.repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comment.repository.d.ts","sourceRoot":"","sources":["../../../src/data/board/comment.repository.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAoBpE,wBAAgB,UAAU,CACxB,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,MAAM,GACd,YAAY,CAQd;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE,CAKzE"}