sensorium-mcp 3.1.2-board.1 → 3.1.3

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 (103) hide show
  1. package/dist/dashboard/routes/threads-read.d.ts +7 -3
  2. package/dist/dashboard/routes/threads-read.d.ts.map +1 -1
  3. package/dist/dashboard/routes/threads-read.js +19 -4
  4. package/dist/dashboard/routes/threads-read.js.map +1 -1
  5. package/dist/dashboard/routes/types.d.ts +0 -6
  6. package/dist/dashboard/routes/types.d.ts.map +1 -1
  7. package/dist/dashboard/routes/types.js.map +1 -1
  8. package/dist/dashboard/routes.d.ts.map +1 -1
  9. package/dist/dashboard/routes.js +0 -32
  10. package/dist/dashboard/routes.js.map +1 -1
  11. package/dist/dashboard/spa.html +12 -12
  12. package/dist/data/memory/migration-runner.d.ts.map +1 -1
  13. package/dist/data/memory/migration-runner.js +0 -4
  14. package/dist/data/memory/migration-runner.js.map +1 -1
  15. package/dist/data/memory/schema.d.ts.map +1 -1
  16. package/dist/data/memory/schema.js +0 -4
  17. package/dist/data/memory/schema.js.map +1 -1
  18. package/dist/index.js +2 -39
  19. package/dist/index.js.map +1 -1
  20. package/dist/integrations/openai/speech.d.ts.map +1 -1
  21. package/dist/integrations/openai/speech.js +52 -19
  22. package/dist/integrations/openai/speech.js.map +1 -1
  23. package/dist/lib/utils.d.ts +10 -0
  24. package/dist/lib/utils.d.ts.map +1 -1
  25. package/dist/lib/utils.js +22 -0
  26. package/dist/lib/utils.js.map +1 -1
  27. package/dist/server/http-server.d.ts +1 -3
  28. package/dist/server/http-server.d.ts.map +1 -1
  29. package/dist/server/http-server.js +1 -3
  30. package/dist/server/http-server.js.map +1 -1
  31. package/dist/services/spawn-common.d.ts.map +1 -1
  32. package/dist/services/spawn-common.js +1 -3
  33. package/dist/services/spawn-common.js.map +1 -1
  34. package/dist/services/worker-cleanup.service.d.ts +1 -6
  35. package/dist/services/worker-cleanup.service.d.ts.map +1 -1
  36. package/dist/services/worker-cleanup.service.js +10 -123
  37. package/dist/services/worker-cleanup.service.js.map +1 -1
  38. package/dist/tools/delegate-tool.d.ts.map +1 -1
  39. package/dist/tools/delegate-tool.js +0 -32
  40. package/dist/tools/delegate-tool.js.map +1 -1
  41. package/dist/tools/utility-tools.d.ts.map +1 -1
  42. package/dist/tools/utility-tools.js +7 -3
  43. package/dist/tools/utility-tools.js.map +1 -1
  44. package/dist/tools/wait/message-delivery.d.ts.map +1 -1
  45. package/dist/tools/wait/message-delivery.js +0 -13
  46. package/dist/tools/wait/message-delivery.js.map +1 -1
  47. package/package.json +1 -1
  48. package/dist/dashboard/routes/board.d.ts +0 -67
  49. package/dist/dashboard/routes/board.d.ts.map +0 -1
  50. package/dist/dashboard/routes/board.js +0 -612
  51. package/dist/dashboard/routes/board.js.map +0 -1
  52. package/dist/data/board/board-schema.d.ts +0 -22
  53. package/dist/data/board/board-schema.d.ts.map +0 -1
  54. package/dist/data/board/board-schema.js +0 -103
  55. package/dist/data/board/board-schema.js.map +0 -1
  56. package/dist/data/board/board-types.d.ts +0 -117
  57. package/dist/data/board/board-types.d.ts.map +0 -1
  58. package/dist/data/board/board-types.js +0 -9
  59. package/dist/data/board/board-types.js.map +0 -1
  60. package/dist/data/board/card.repository.d.ts +0 -64
  61. package/dist/data/board/card.repository.d.ts.map +0 -1
  62. package/dist/data/board/card.repository.js +0 -272
  63. package/dist/data/board/card.repository.js.map +0 -1
  64. package/dist/data/board/comment.repository.d.ts +0 -12
  65. package/dist/data/board/comment.repository.d.ts.map +0 -1
  66. package/dist/data/board/comment.repository.js +0 -31
  67. package/dist/data/board/comment.repository.js.map +0 -1
  68. package/dist/data/board/lane.repository.d.ts +0 -18
  69. package/dist/data/board/lane.repository.d.ts.map +0 -1
  70. package/dist/data/board/lane.repository.js +0 -44
  71. package/dist/data/board/lane.repository.js.map +0 -1
  72. package/dist/data/board/profile-defaults.d.ts +0 -19
  73. package/dist/data/board/profile-defaults.d.ts.map +0 -1
  74. package/dist/data/board/profile-defaults.js +0 -118
  75. package/dist/data/board/profile-defaults.js.map +0 -1
  76. package/dist/services/board/board-signals.d.ts +0 -25
  77. package/dist/services/board/board-signals.d.ts.map +0 -1
  78. package/dist/services/board/board-signals.js +0 -83
  79. package/dist/services/board/board-signals.js.map +0 -1
  80. package/dist/services/board/card-briefing.d.ts +0 -17
  81. package/dist/services/board/card-briefing.d.ts.map +0 -1
  82. package/dist/services/board/card-briefing.js +0 -86
  83. package/dist/services/board/card-briefing.js.map +0 -1
  84. package/dist/services/board/orchestrator.service.d.ts +0 -55
  85. package/dist/services/board/orchestrator.service.d.ts.map +0 -1
  86. package/dist/services/board/orchestrator.service.js +0 -198
  87. package/dist/services/board/orchestrator.service.js.map +0 -1
  88. package/dist/services/board/release-worker.d.ts +0 -32
  89. package/dist/services/board/release-worker.d.ts.map +0 -1
  90. package/dist/services/board/release-worker.js +0 -49
  91. package/dist/services/board/release-worker.js.map +0 -1
  92. package/dist/services/board/report-capture.d.ts +0 -48
  93. package/dist/services/board/report-capture.d.ts.map +0 -1
  94. package/dist/services/board/report-capture.js +0 -172
  95. package/dist/services/board/report-capture.js.map +0 -1
  96. package/dist/services/board/worker-spawn.d.ts +0 -30
  97. package/dist/services/board/worker-spawn.d.ts.map +0 -1
  98. package/dist/services/board/worker-spawn.js +0 -90
  99. package/dist/services/board/worker-spawn.js.map +0 -1
  100. package/dist/services/passive-notice.service.d.ts +0 -39
  101. package/dist/services/passive-notice.service.d.ts.map +0 -1
  102. package/dist/services/passive-notice.service.js +0 -274
  103. package/dist/services/passive-notice.service.js.map +0 -1
@@ -1,90 +0,0 @@
1
- /**
2
- * Card-worker spawn path (design §3.1) — the board-side equivalent of
3
- * handleStartThread's mode=worker branch (delegate-tool.ts), reusing the same
4
- * primitives in the same order: topic create → agent-type set → pre-queue
5
- * payload → dispatchSpawn(memorySourceThreadId=lane) → registerThread.
6
- * The worker inherits the FULL lane-thread briefing via memorySourceThreadId
7
- * (assembleBootstrap), with the card payload as its pre-queued task on top.
8
- */
9
- import { appendFileSync } from "node:fs";
10
- import { join } from "node:path";
11
- import { getAgentType } from "../../config/index.js";
12
- import { log } from "../../lib/logger.js";
13
- import { errorMessage } from "../../lib/utils.js";
14
- import { getThread } from "../../data/memory/thread-registry.js";
15
- import { dispatchSpawn } from "../agent-spawn.service.js";
16
- import { deletePendingTaskMailbox, ensureDirs, PENDING_TASKS_DIR } from "../process.service.js";
17
- import { createManagedTopic } from "../topic.service.js";
18
- import { setThreadAgentType } from "../thread-config.service.js";
19
- import { renderCardBriefing } from "./card-briefing.js";
20
- /** Windows drive-letter or POSIX absolute path → usable as a working directory. */
21
- const looksLikeLocalPath = (s) => /^([A-Za-z]:[\\/]|\/)/.test(s);
22
- export async function spawnCardWorker(deps, card, comments) {
23
- const { db, telegram, chatId, threadLifecycle } = deps;
24
- const agentType = card.profile.agentType ?? getAgentType();
25
- const shortTitle = card.title.length > 40 ? card.title.slice(0, 37) + "…" : card.title;
26
- const name = `Card #${card.cardId} ${shortTitle}`;
27
- // 1. Fresh Telegram topic — a fresh stateless worker per (re)dispatch, never reused.
28
- let workerThreadId;
29
- try {
30
- workerThreadId = await createManagedTopic(telegram, chatId, `[Worker] ${name}`, [name]);
31
- }
32
- catch (err) {
33
- return { error: `Topic creation failed: ${errorMessage(err)}` };
34
- }
35
- setThreadAgentType(workerThreadId, agentType);
36
- // Every failure after this point must tear the topic + mailbox back down —
37
- // otherwise each failed dispatch leaks one Telegram topic and a pending-task
38
- // file that could feed a future thread reusing the id.
39
- const cleanupAfterFailure = async () => {
40
- deletePendingTaskMailbox(workerThreadId);
41
- try {
42
- await telegram.deleteForumTopic(chatId, workerThreadId);
43
- }
44
- catch (err) {
45
- log.warn(`[board] failed-dispatch topic cleanup for ${workerThreadId}: ${errorMessage(err)}`);
46
- }
47
- };
48
- // 2. Working directory: explicit local repo path on the card wins, else the
49
- // lane thread's own working directory (the worker is branched from it).
50
- const laneThread = getThread(db, card.laneThreadId);
51
- const workingDirectory = card.profile.repository && looksLikeLocalPath(card.profile.repository)
52
- ? card.profile.repository
53
- : (laneThread?.workingDirectory ?? process.cwd());
54
- // 3. Pre-queue the card payload before the process exists (same guarantee as
55
- // start_thread's task param — delivery on the worker's first poll).
56
- try {
57
- ensureDirs();
58
- appendFileSync(join(PENDING_TASKS_DIR, `${workerThreadId}.txt`), renderCardBriefing(card, comments, workerThreadId) + "\n", "utf-8");
59
- }
60
- catch (err) {
61
- await cleanupAfterFailure();
62
- return { error: `Failed to pre-queue card payload: ${errorMessage(err)}` };
63
- }
64
- // 4. Spawn, briefed from the lane thread (full parent briefing + card).
65
- const result = await dispatchSpawn(agentType, name, workerThreadId, threadLifecycle, workingDirectory, card.laneThreadId, "worker");
66
- if ("error" in result) {
67
- await cleanupAfterFailure();
68
- return { error: result.error };
69
- }
70
- // 5. Register in the thread registry (worker hygiene — TTL, cleanup — applies).
71
- try {
72
- threadLifecycle.registerThread(db, {
73
- threadId: workerThreadId,
74
- name,
75
- type: "worker",
76
- rootThreadId: card.laneThreadId,
77
- badge: "board-worker",
78
- client: agentType,
79
- workingDirectory,
80
- chatId,
81
- telegramTopicId: workerThreadId,
82
- });
83
- }
84
- catch (err) {
85
- log.warn(`[board] registerThread failed for card-worker ${workerThreadId}: ${errorMessage(err)}`);
86
- }
87
- log.info(`[board] card ${card.cardId} dispatched → worker thread ${workerThreadId} (PID ${result.pid}, agent ${agentType})`);
88
- return { workerThreadId };
89
- }
90
- //# sourceMappingURL=worker-spawn.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"worker-spawn.js","sourceRoot":"","sources":["../../../src/services/board/worker-spawn.ts"],"names":[],"mappings":"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"}
@@ -1,39 +0,0 @@
1
- /**
2
- * Passive-notice channel — "context, not command" (design §5).
3
- *
4
- * A general capability, independent of the board: notices pushed here are
5
- * DRAINED into the next delivered turn of the target thread as an FYI block
6
- * (message-delivery renders them next to the Persistent Context block). They
7
- * never wake the agent and are never framed as tasks — the agent is aware,
8
- * not commanded. This fixes the notification/command conflation of the
9
- * pending-task inbox for updates that carry no instruction.
10
- *
11
- * Storage: per-thread JSON queue under ~/.remote-copilot-mcp/passive-notices/,
12
- * write-then-rename (same durability pattern as schedules). Bounded to the
13
- * most recent MAX_NOTICES entries.
14
- */
15
- export interface PassiveNotice {
16
- text: string;
17
- createdAt: string;
18
- }
19
- /** Queue an FYI notice for a thread's next delivered turn. Never wakes the agent. */
20
- export declare function pushPassiveNotice(threadId: number, text: string): void;
21
- /**
22
- * Read-and-clear (delivered-once semantics). Returns oldest→newest.
23
- *
24
- * Drain claims the queue file via atomic rename (under the same lock pushes
25
- * take), so a push landing mid-drain writes a FRESH queue file and survives.
26
- * Claims are per-pid; claims left by a crashed process are swept in too
27
- * (redelivery of an FYI beats losing it).
28
- */
29
- export declare function drainPassiveNotices(threadId: number): PassiveNotice[];
30
- /** Non-destructive peek (dashboard/diagnostics). */
31
- export declare function peekPassiveNotices(threadId: number): PassiveNotice[];
32
- /**
33
- * Drain and render the FYI block appended to a delivered turn (next to the
34
- * Persistent Context block in message-delivery). Empty string when quiet.
35
- * The framing does the "aware, not commanded" work: explicit no-action wording
36
- * so a later operator voice about these makes sense without triggering work.
37
- */
38
- export declare function renderPassiveNoticeBlock(threadId: number): string;
39
- //# sourceMappingURL=passive-notice.service.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"passive-notice.service.d.ts","sourceRoot":"","sources":["../../src/services/passive-notice.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAmBH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AA4FD,qFAAqF;AACrF,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAmBtE;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,EAAE,CAgFrE;AAED,oDAAoD;AACpD,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,EAAE,CAEpE;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA6BjE"}
@@ -1,274 +0,0 @@
1
- /**
2
- * Passive-notice channel — "context, not command" (design §5).
3
- *
4
- * A general capability, independent of the board: notices pushed here are
5
- * DRAINED into the next delivered turn of the target thread as an FYI block
6
- * (message-delivery renders them next to the Persistent Context block). They
7
- * never wake the agent and are never framed as tasks — the agent is aware,
8
- * not commanded. This fixes the notification/command conflation of the
9
- * pending-task inbox for updates that carry no instruction.
10
- *
11
- * Storage: per-thread JSON queue under ~/.remote-copilot-mcp/passive-notices/,
12
- * write-then-rename (same durability pattern as schedules). Bounded to the
13
- * most recent MAX_NOTICES entries.
14
- */
15
- import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from "node:fs";
16
- import { homedir } from "node:os";
17
- import { join } from "node:path";
18
- import { log } from "../lib/logger.js";
19
- import { errorMessage } from "../lib/utils.js";
20
- const NOTICES_DIR = join(homedir(), ".remote-copilot-mcp", "passive-notices");
21
- const MAX_NOTICES = 10;
22
- function noticesFilePath(threadId) {
23
- return join(NOTICES_DIR, `${threadId}.json`);
24
- }
25
- // ── Cross-process safety (H4 of the board kernel review) ───────────────────
26
- // Writers live in DIFFERENT OS processes (a worker's own MCP tool call vs the
27
- // server's orchestrator/cleanup loops). The bare read→modify→write→rename pair
28
- // is atomic only in the rename, so concurrent pushes were last-writer-wins and
29
- // a push landing inside drain's read→unlink window was destroyed. Same lock
30
- // pattern as dispatcher/lock.ts (wx-create + dead-pid/stale takeover), scoped
31
- // per thread; drain claims the file by atomic rename so a concurrent push
32
- // simply starts a fresh queue file and survives.
33
- const LOCK_STALE_MS = 10_000;
34
- const LOCK_RETRY_MS = 5;
35
- const LOCK_MAX_ATTEMPTS = 60;
36
- function isPidAlive(pid) {
37
- try {
38
- process.kill(pid, 0);
39
- return true;
40
- }
41
- catch (err) {
42
- return err.code === "EPERM";
43
- }
44
- }
45
- function sleepSync(ms) {
46
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
47
- }
48
- /** Acquire the per-thread mutation lock. Hold time is sub-millisecond (tiny
49
- * file ops), so bounded spinning is fine. Returns false only under pathological
50
- * contention — callers then proceed unlocked (a rare racy write beats losing
51
- * the notice outright). */
52
- function acquireNoticeLock(threadId) {
53
- const lockPath = join(NOTICES_DIR, `${threadId}.lock`);
54
- for (let attempt = 0; attempt < LOCK_MAX_ATTEMPTS; attempt++) {
55
- try {
56
- writeFileSync(lockPath, JSON.stringify({ pid: process.pid, ts: Date.now() }), {
57
- encoding: "utf8",
58
- flag: "wx",
59
- });
60
- return true;
61
- }
62
- catch {
63
- try {
64
- const holder = JSON.parse(readFileSync(lockPath, "utf8"));
65
- if (!isPidAlive(holder.pid) || Date.now() - holder.ts > LOCK_STALE_MS) {
66
- unlinkSync(lockPath); // dead or stale holder — take over next attempt
67
- continue;
68
- }
69
- }
70
- catch {
71
- // Corrupt/vanished lock — remove and retry.
72
- try {
73
- unlinkSync(lockPath);
74
- }
75
- catch {
76
- /* already gone */
77
- }
78
- continue;
79
- }
80
- sleepSync(LOCK_RETRY_MS);
81
- }
82
- }
83
- log.warn(`[passive-notice] lock contention for thread ${threadId} — proceeding unlocked`);
84
- return false;
85
- }
86
- function releaseNoticeLock(threadId) {
87
- const lockPath = join(NOTICES_DIR, `${threadId}.lock`);
88
- try {
89
- const holder = JSON.parse(readFileSync(lockPath, "utf8"));
90
- if (holder.pid === process.pid)
91
- unlinkSync(lockPath);
92
- }
93
- catch {
94
- /* already gone or not ours */
95
- }
96
- }
97
- function readNotices(threadId) {
98
- const file = noticesFilePath(threadId);
99
- try {
100
- if (!existsSync(file))
101
- return [];
102
- const parsed = JSON.parse(readFileSync(file, "utf8"));
103
- return Array.isArray(parsed) ? parsed : [];
104
- }
105
- catch (err) {
106
- log.warn(`[passive-notice] Failed to read notices for thread ${threadId}: ${errorMessage(err)}`);
107
- return [];
108
- }
109
- }
110
- /** Queue an FYI notice for a thread's next delivered turn. Never wakes the agent. */
111
- export function pushPassiveNotice(threadId, text) {
112
- try {
113
- mkdirSync(NOTICES_DIR, { recursive: true });
114
- const locked = acquireNoticeLock(threadId);
115
- try {
116
- const notices = readNotices(threadId);
117
- notices.push({ text, createdAt: new Date().toISOString() });
118
- // Bounded: keep only the freshest MAX_NOTICES — stale FYIs have no value.
119
- const bounded = notices.slice(-MAX_NOTICES);
120
- const file = noticesFilePath(threadId);
121
- const tmp = `${file}.tmp.${process.pid}`;
122
- writeFileSync(tmp, JSON.stringify(bounded, null, 2), "utf8");
123
- renameSync(tmp, file);
124
- }
125
- finally {
126
- if (locked)
127
- releaseNoticeLock(threadId);
128
- }
129
- }
130
- catch (err) {
131
- log.warn(`[passive-notice] Failed to push notice for thread ${threadId}: ${errorMessage(err)}`);
132
- }
133
- }
134
- /**
135
- * Read-and-clear (delivered-once semantics). Returns oldest→newest.
136
- *
137
- * Drain claims the queue file via atomic rename (under the same lock pushes
138
- * take), so a push landing mid-drain writes a FRESH queue file and survives.
139
- * Claims are per-pid; claims left by a crashed process are swept in too
140
- * (redelivery of an FYI beats losing it).
141
- */
142
- export function drainPassiveNotices(threadId) {
143
- const file = noticesFilePath(threadId);
144
- const claimPath = `${file}.claim.${process.pid}`;
145
- const drained = [];
146
- // Sweep litter left by crashed peers: claims orphaned by a dead drainer AND
147
- // `.tmp.<pid>` half-writes left by a push that died between write and rename.
148
- // Both are keyed by the writer's pid; anything owned by a gone pid is dead.
149
- try {
150
- const claimPrefix = `${threadId}.json.claim.`;
151
- const tmpPrefix = `${threadId}.json.tmp.`;
152
- for (const entry of readdirSync(NOTICES_DIR)) {
153
- if (entry.startsWith(claimPrefix)) {
154
- const pid = Number(entry.slice(claimPrefix.length));
155
- if (!Number.isInteger(pid) || pid === process.pid || isPidAlive(pid))
156
- continue;
157
- const orphanPath = join(NOTICES_DIR, entry);
158
- try {
159
- const parsed = JSON.parse(readFileSync(orphanPath, "utf8"));
160
- if (Array.isArray(parsed))
161
- drained.push(...parsed);
162
- }
163
- catch {
164
- /* corrupt orphan — drop it */
165
- }
166
- try {
167
- unlinkSync(orphanPath);
168
- }
169
- catch {
170
- /* already gone */
171
- }
172
- }
173
- else if (entry.startsWith(tmpPrefix)) {
174
- // A crashed push's temp file: its contents never became the live queue
175
- // (the rename never ran), so it may be a partial write — discard rather
176
- // than risk resurrecting corrupt/duplicate notices. Only reap dead pids
177
- // so a concurrent live push's in-flight temp is never deleted.
178
- const pid = Number(entry.slice(tmpPrefix.length));
179
- if (!Number.isInteger(pid) || pid === process.pid || isPidAlive(pid))
180
- continue;
181
- try {
182
- unlinkSync(join(NOTICES_DIR, entry));
183
- }
184
- catch {
185
- /* already gone */
186
- }
187
- }
188
- }
189
- }
190
- catch {
191
- /* dir missing — nothing queued yet */
192
- }
193
- // A same-pid claim left by THIS process's earlier crashed drain (renamed but
194
- // never consumed) would be silently clobbered by the rename below, losing its
195
- // notices. Consume it first so the notices survive.
196
- if (existsSync(claimPath)) {
197
- try {
198
- const parsed = JSON.parse(readFileSync(claimPath, "utf8"));
199
- if (Array.isArray(parsed))
200
- drained.push(...parsed);
201
- unlinkSync(claimPath);
202
- }
203
- catch (err) {
204
- if (err.code !== "ENOENT")
205
- log.warn(`[passive-notice] stale claim recovery failed for thread ${threadId}: ${errorMessage(err)}`);
206
- }
207
- }
208
- if (existsSync(file)) {
209
- const locked = acquireNoticeLock(threadId);
210
- try {
211
- renameSync(file, claimPath);
212
- }
213
- catch (err) {
214
- log.debug(`[passive-notice] drain claim failed for thread ${threadId}: ${errorMessage(err)}`);
215
- }
216
- finally {
217
- if (locked)
218
- releaseNoticeLock(threadId);
219
- }
220
- try {
221
- const parsed = JSON.parse(readFileSync(claimPath, "utf8"));
222
- if (Array.isArray(parsed))
223
- drained.push(...parsed);
224
- unlinkSync(claimPath);
225
- }
226
- catch (err) {
227
- if (err.code !== "ENOENT")
228
- log.warn(`[passive-notice] drain read failed for thread ${threadId}: ${errorMessage(err)}`);
229
- }
230
- }
231
- return drained;
232
- }
233
- /** Non-destructive peek (dashboard/diagnostics). */
234
- export function peekPassiveNotices(threadId) {
235
- return readNotices(threadId);
236
- }
237
- /**
238
- * Drain and render the FYI block appended to a delivered turn (next to the
239
- * Persistent Context block in message-delivery). Empty string when quiet.
240
- * The framing does the "aware, not commanded" work: explicit no-action wording
241
- * so a later operator voice about these makes sense without triggering work.
242
- */
243
- export function renderPassiveNoticeBlock(threadId) {
244
- const notices = drainPassiveNotices(threadId);
245
- if (notices.length === 0)
246
- return "";
247
- // Per-item fault isolation: one malformed record (bad createdAt, non-string
248
- // text) must not throw AFTER the drain already consumed the batch — that
249
- // would lose every notice in the turn. Bad records are skipped, not fatal.
250
- const lines = [];
251
- for (const n of notices) {
252
- try {
253
- const stamp = typeof n.createdAt === "string" ? n.createdAt.slice(0, 16).replace("T", " ") : "?";
254
- if (typeof n.text !== "string" || n.text.length === 0)
255
- continue;
256
- lines.push(`- [${stamp}] ${n.text}`);
257
- }
258
- catch {
259
- /* skip malformed record */
260
- }
261
- }
262
- if (lines.length === 0)
263
- return "";
264
- // Delivery-loss note: drain happens at render time, inside the poll loop's
265
- // transport-liveness guards — the same consumption bar the system applies to
266
- // operator messages themselves. A deeper delivered-ack protocol was reviewed
267
- // and deliberately not built (FYI notices must not carry more delivery
268
- // guarantees than operator messages do).
269
- return (`\n\n## Situational Notices (FYI — context, not command)\n` +
270
- `These are awareness-only updates. Do NOT act on them, reply to them, or treat them as tasks; ` +
271
- `they exist so later operator messages about them make sense.\n` +
272
- lines.join("\n"));
273
- }
274
- //# sourceMappingURL=passive-notice.service.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"passive-notice.service.js","sourceRoot":"","sources":["../../src/services/passive-notice.service.ts"],"names":[],"mappings":"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"}