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,55 @@
1
+ /**
2
+ * Auth composable + token accessor. ❌ FROZEN SEAM.
3
+ *
4
+ * The Bearer token is entered once in the UI and kept in localStorage (the
5
+ * dashboard-proven pattern). In preview mode auth is a NO-OP: the mock adapter
6
+ * ignores the token, so `isAuthed()` is always true and every screen renders.
7
+ */
8
+
9
+ import { ref } from "../vendor/vue.esm-browser.js";
10
+ import { MODE } from "../config.js";
11
+
12
+ const KEY = "BOARD_API_TOKEN";
13
+
14
+ function read() {
15
+ try {
16
+ return localStorage.getItem(KEY) || "";
17
+ } catch {
18
+ return "";
19
+ }
20
+ }
21
+
22
+ /** Reactive token — a single shared ref across the app. */
23
+ const token = ref(read());
24
+
25
+ /** Plain accessor for the production fetch adapter (avoids importing Vue there). */
26
+ export function getToken() {
27
+ return token.value;
28
+ }
29
+
30
+ export function setToken(value) {
31
+ const v = value || "";
32
+ token.value = v;
33
+ try {
34
+ if (v) localStorage.setItem(KEY, v);
35
+ else localStorage.removeItem(KEY);
36
+ } catch {
37
+ /* storage unavailable in sandbox — the ref still drives the UI this session */
38
+ }
39
+ }
40
+
41
+ export function clearToken() {
42
+ setToken("");
43
+ }
44
+
45
+ export function useAuth() {
46
+ return {
47
+ token,
48
+ mode: MODE,
49
+ isPreview: MODE === "preview",
50
+ /** True when the app may talk to the API — always true in preview. */
51
+ isAuthed: () => MODE === "preview" || !!token.value,
52
+ setToken,
53
+ clearToken,
54
+ };
55
+ }
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Board store — cards + lanes polling and operator actions. ❌ FROZEN SEAM.
3
+ *
4
+ * Frozen return surface (the seam the UI is built against):
5
+ * { cards, lanes, loading, error, laneFilter, includeArchived,
6
+ * byStatus, statuses, laneName, start, stop, actions }
7
+ *
8
+ * A single shared instance (module singleton) so the board view and any header
9
+ * share one poll loop.
10
+ *
11
+ * @typedef {import('../api/contract.js').BoardCard} BoardCard
12
+ */
13
+
14
+ import { ref, computed } from "../vendor/vue.esm-browser.js";
15
+ import { api } from "../api/api.js";
16
+ import { POLL_INTERVAL_MS, CARD_STATUSES } from "../config.js";
17
+
18
+ let singleton = null;
19
+
20
+ export function useBoard() {
21
+ if (singleton) return singleton;
22
+
23
+ const cards = ref([]);
24
+ const lanes = ref([]);
25
+ const loading = ref(false);
26
+ const error = ref(null);
27
+ const laneFilter = ref(null); // null = all lanes
28
+ const includeArchived = ref(false);
29
+ let timer = null;
30
+
31
+ async function refresh() {
32
+ try {
33
+ error.value = null;
34
+ const [c, l] = await Promise.all([
35
+ api.listCards({
36
+ includeArchived: includeArchived.value,
37
+ ...(laneFilter.value != null ? { lane: laneFilter.value } : {}),
38
+ }),
39
+ api.listLanes(),
40
+ ]);
41
+ cards.value = c;
42
+ lanes.value = l;
43
+ } catch (e) {
44
+ error.value = (e && e.message) || String(e);
45
+ } finally {
46
+ loading.value = false;
47
+ }
48
+ }
49
+
50
+ async function load() {
51
+ loading.value = true;
52
+ await refresh();
53
+ }
54
+
55
+ function start() {
56
+ stop();
57
+ load();
58
+ timer = setInterval(() => {
59
+ if (typeof document === "undefined" || document.visibilityState === "visible") refresh();
60
+ }, POLL_INTERVAL_MS);
61
+ }
62
+
63
+ function stop() {
64
+ if (timer) {
65
+ clearInterval(timer);
66
+ timer = null;
67
+ }
68
+ }
69
+
70
+ /** Cards grouped by status, each group priority-desc then oldest-first. */
71
+ const byStatus = computed(() => {
72
+ const groups = {};
73
+ for (const s of CARD_STATUSES) groups[s] = [];
74
+ for (const card of cards.value) (groups[card.status] ||= []).push(card);
75
+ for (const s of Object.keys(groups)) {
76
+ groups[s].sort((a, b) => b.priority - a.priority || (a.createdAt < b.createdAt ? -1 : 1));
77
+ }
78
+ return groups;
79
+ });
80
+
81
+ const laneName = (threadId) =>
82
+ lanes.value.find((l) => l.threadId === threadId)?.name ?? `Thread ${threadId}`;
83
+
84
+ const actions = {
85
+ setLaneFilter: (v) => {
86
+ laneFilter.value = v;
87
+ return refresh();
88
+ },
89
+ setIncludeArchived: (v) => {
90
+ includeArchived.value = v;
91
+ return refresh();
92
+ },
93
+ create: async (card) => {
94
+ const c = await api.createCard(card);
95
+ await refresh();
96
+ return c;
97
+ },
98
+ move: async (id, status) => {
99
+ const c = await api.updateCard(id, { status });
100
+ await refresh();
101
+ return c;
102
+ },
103
+ stop: async (id) => {
104
+ const c = await api.stopCard(id);
105
+ await refresh();
106
+ return c;
107
+ },
108
+ archive: async (id) => {
109
+ const c = await api.updateCard(id, { archivedAt: new Date().toISOString() });
110
+ await refresh();
111
+ return c;
112
+ },
113
+ remove: async (id) => {
114
+ await api.deleteCard(id);
115
+ await refresh();
116
+ },
117
+ addLane: async (name) => {
118
+ const l = await api.createLane(name);
119
+ await refresh();
120
+ return l;
121
+ },
122
+ renameLane: async (id, name) => {
123
+ const l = await api.updateLane(id, { name });
124
+ await refresh();
125
+ return l;
126
+ },
127
+ removeLane: async (id) => {
128
+ await api.deleteLane(id);
129
+ await refresh();
130
+ },
131
+ refresh,
132
+ };
133
+
134
+ singleton = {
135
+ cards,
136
+ lanes,
137
+ loading,
138
+ error,
139
+ laneFilter,
140
+ includeArchived,
141
+ byStatus,
142
+ statuses: CARD_STATUSES,
143
+ laneName,
144
+ start,
145
+ stop,
146
+ actions,
147
+ };
148
+ return singleton;
149
+ }
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Card-builder draft store. ❌ FROZEN SEAM.
3
+ *
4
+ * P0 is the placeholder builder SHELL: the WHAT fields (title / description /
5
+ * acceptance) plus type / lane / priority, submitted via the create endpoint.
6
+ * The schema-driven HOW builder + compiled preview arrive in P1 — this surface
7
+ * stays stable so the UI is not rewired then. It is extended ADDITIVELY here
8
+ * with { policySchema, presets } (the How-step field schema + presets, sourced
9
+ * from the editable schema/policy.js via the data seam); the original returns
10
+ * ({ draft, lanes, profiles, types, submitting, error, load, reset, submit }) are
11
+ * unchanged.
12
+ */
13
+
14
+ import { reactive, ref } from "../vendor/vue.esm-browser.js";
15
+ import { api } from "../api/api.js";
16
+
17
+ export function useBuilder() {
18
+ const draft = reactive({
19
+ title: "",
20
+ description: "",
21
+ acceptance: "",
22
+ type: "chore",
23
+ laneThreadId: null,
24
+ priority: 0,
25
+ });
26
+
27
+ const lanes = ref([]);
28
+ const profiles = ref({});
29
+ const types = ref([]);
30
+ const submitting = ref(false);
31
+ const error = ref(null);
32
+ // How-step schema + presets (additive; from schema/policy.js via the seam).
33
+ const policySchema = ref([]);
34
+ const presets = ref([]);
35
+
36
+ async function load() {
37
+ try {
38
+ const [l, p] = await Promise.all([api.listLanes(), api.getProfiles()]);
39
+ lanes.value = l;
40
+ profiles.value = p;
41
+ types.value = Object.keys(p);
42
+ if (draft.laneThreadId == null && l.length) draft.laneThreadId = l[0].threadId;
43
+ } catch (e) {
44
+ error.value = (e && e.message) || String(e);
45
+ }
46
+ // Additive, non-fatal: the schema-driven How controls. In production the real
47
+ // API may not implement these yet (P1 TODO in api/client.js) — degrade to a
48
+ // schema-less builder rather than failing the whole load.
49
+ try {
50
+ const [schema, ps] = await Promise.all([api.getPolicySchema(), api.getPresets()]);
51
+ policySchema.value = schema;
52
+ presets.value = ps;
53
+ } catch {
54
+ /* schema/presets unavailable — builder still renders the WHAT step */
55
+ }
56
+ }
57
+
58
+ function reset() {
59
+ Object.assign(draft, {
60
+ title: "",
61
+ description: "",
62
+ acceptance: "",
63
+ type: "chore",
64
+ priority: 0,
65
+ });
66
+ }
67
+
68
+ /** @returns {Promise<import('../api/contract.js').BoardCard|null>} */
69
+ async function submit() {
70
+ error.value = null;
71
+ if (!draft.title.trim()) {
72
+ error.value = "Title is required";
73
+ return null;
74
+ }
75
+ if (draft.laneThreadId == null) {
76
+ error.value = "A lane is required";
77
+ return null;
78
+ }
79
+ submitting.value = true;
80
+ try {
81
+ return await api.createCard({
82
+ title: draft.title.trim(),
83
+ description: draft.description,
84
+ acceptance: draft.acceptance,
85
+ type: draft.type,
86
+ laneThreadId: Number(draft.laneThreadId),
87
+ priority: Number(draft.priority) || 0,
88
+ });
89
+ } catch (e) {
90
+ error.value = (e && e.message) || String(e);
91
+ return null;
92
+ } finally {
93
+ submitting.value = false;
94
+ }
95
+ }
96
+
97
+ return { draft, lanes, profiles, types, policySchema, presets, submitting, error, load, reset, submit };
98
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Single-card store — card + comments + worker health, plus operator actions.
3
+ * ❌ FROZEN SEAM.
4
+ *
5
+ * Frozen return surface: { card, comments, running, loading, error, load, actions }.
6
+ * `running` is null unless the card is in_progress (P3 adds richer health/logs).
7
+ */
8
+
9
+ import { ref } from "../vendor/vue.esm-browser.js";
10
+ import { api } from "../api/api.js";
11
+
12
+ export function useCard(cardId) {
13
+ const id = Number(cardId);
14
+ const card = ref(null);
15
+ const comments = ref([]);
16
+ const running = ref(null);
17
+ const loading = ref(false);
18
+ const error = ref(null);
19
+
20
+ async function load() {
21
+ loading.value = true;
22
+ error.value = null;
23
+ try {
24
+ const detail = await api.getCard(id);
25
+ card.value = detail.card;
26
+ comments.value = detail.comments;
27
+ if (detail.card.status === "in_progress" && detail.card.workerThreadId != null) {
28
+ running.value = await api.threadRunning(detail.card.workerThreadId).catch(() => null);
29
+ } else {
30
+ running.value = null;
31
+ }
32
+ } catch (e) {
33
+ error.value = (e && e.message) || String(e);
34
+ } finally {
35
+ loading.value = false;
36
+ }
37
+ }
38
+
39
+ const actions = {
40
+ reload: load,
41
+ comment: async (content) => {
42
+ await api.addComment(id, content);
43
+ await load();
44
+ },
45
+ move: async (status) => {
46
+ await api.updateCard(id, { status });
47
+ await load();
48
+ },
49
+ stop: async () => {
50
+ await api.stopCard(id);
51
+ await load();
52
+ },
53
+ archive: async () => {
54
+ await api.updateCard(id, { archivedAt: new Date().toISOString() });
55
+ await load();
56
+ },
57
+ remove: async () => {
58
+ await api.deleteCard(id);
59
+ },
60
+ save: async (patch) => {
61
+ await api.updateCard(id, patch);
62
+ await load();
63
+ },
64
+ };
65
+
66
+ return { card, comments, running, loading, error, load, actions };
67
+ }