cool-workflow 0.1.80 → 0.1.81

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 (110) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/README.md +42 -2
  4. package/apps/architecture-review/app.json +1 -1
  5. package/apps/architecture-review-fast/app.json +1 -1
  6. package/apps/end-to-end-golden-path/app.json +1 -1
  7. package/apps/pr-review-fix-ci/app.json +1 -1
  8. package/apps/release-cut/app.json +1 -1
  9. package/apps/research-synthesis/app.json +1 -1
  10. package/dist/agent-config.js +21 -7
  11. package/dist/candidate-scoring.js +42 -22
  12. package/dist/capability-core.js +94 -17
  13. package/dist/capability-registry.js +138 -171
  14. package/dist/cli.js +90 -100
  15. package/dist/collaboration.js +5 -6
  16. package/dist/commit.js +20 -6
  17. package/dist/compare.js +18 -0
  18. package/dist/coordinator/classify.js +45 -0
  19. package/dist/coordinator/paths.js +42 -0
  20. package/dist/coordinator/util.js +129 -0
  21. package/dist/coordinator.js +127 -300
  22. package/dist/dispatch.js +35 -0
  23. package/dist/drive.js +7 -7
  24. package/dist/error-feedback.js +8 -4
  25. package/dist/evidence-reasoning.js +1 -1
  26. package/dist/execution-backend/agent.js +331 -0
  27. package/dist/execution-backend/probes.js +96 -0
  28. package/dist/execution-backend/util.js +47 -0
  29. package/dist/execution-backend.js +67 -420
  30. package/dist/mcp-server.js +34 -173
  31. package/dist/multi-agent/graph.js +84 -0
  32. package/dist/multi-agent/helpers.js +145 -0
  33. package/dist/multi-agent/paths.js +22 -0
  34. package/dist/multi-agent-eval/format.js +194 -0
  35. package/dist/multi-agent-eval/normalize.js +51 -0
  36. package/dist/multi-agent-eval.js +39 -244
  37. package/dist/multi-agent-host.js +0 -19
  38. package/dist/multi-agent.js +125 -314
  39. package/dist/node-snapshot.js +3 -3
  40. package/dist/observability/format.js +61 -0
  41. package/dist/observability/intake.js +98 -0
  42. package/dist/observability.js +14 -160
  43. package/dist/operator-ux/format.js +364 -0
  44. package/dist/operator-ux.js +22 -363
  45. package/dist/orchestrator/report.js +8 -0
  46. package/dist/orchestrator.js +25 -8
  47. package/dist/reclamation.js +26 -21
  48. package/dist/run-export.js +138 -14
  49. package/dist/run-registry/derive.js +172 -0
  50. package/dist/run-registry/format.js +124 -0
  51. package/dist/run-registry/gc.js +251 -0
  52. package/dist/run-registry/policy.js +16 -0
  53. package/dist/run-registry/queue.js +116 -0
  54. package/dist/run-registry.js +78 -593
  55. package/dist/run-state-schema.js +1 -0
  56. package/dist/sandbox-profile.js +43 -2
  57. package/dist/state-explosion/format.js +159 -0
  58. package/dist/state-explosion/helpers.js +82 -0
  59. package/dist/state-explosion.js +65 -283
  60. package/dist/state-node.js +19 -4
  61. package/dist/telemetry-attestation.js +55 -0
  62. package/dist/telemetry-demo.js +15 -3
  63. package/dist/telemetry-ledger.js +60 -15
  64. package/dist/topology.js +25 -8
  65. package/dist/triggers.js +33 -14
  66. package/dist/trust-audit.js +145 -33
  67. package/dist/version.js +1 -1
  68. package/dist/worker-isolation/helpers.js +51 -0
  69. package/dist/worker-isolation/paths.js +46 -0
  70. package/dist/worker-isolation.js +39 -115
  71. package/docs/agent-delegation-drive.7.md +13 -0
  72. package/docs/cli-mcp-parity.7.md +4 -0
  73. package/docs/contract-migration-tooling.7.md +2 -0
  74. package/docs/control-plane-scheduling.7.md +2 -0
  75. package/docs/dogfood/resume-drive-real-agent-2026-06-14.md +40 -0
  76. package/docs/durable-state-and-locking.7.md +4 -0
  77. package/docs/evidence-adoption-reasoning-chain.7.md +2 -0
  78. package/docs/execution-backends.7.md +2 -0
  79. package/docs/index.md +1 -0
  80. package/docs/launch/launch-kit.md +46 -23
  81. package/docs/launch/pre-launch-checklist.md +14 -14
  82. package/docs/multi-agent-cli-mcp-surface.7.md +4 -0
  83. package/docs/multi-agent-eval-replay-harness.7.md +2 -0
  84. package/docs/multi-agent-operator-ux.7.md +2 -0
  85. package/docs/multi-agent-trust-policy-audit.7.md +27 -0
  86. package/docs/node-snapshot-diff-replay.7.md +2 -0
  87. package/docs/observability-cost-accounting.7.md +2 -0
  88. package/docs/project-index.md +18 -5
  89. package/docs/real-execution-backends.7.md +2 -0
  90. package/docs/release-and-migration.7.md +4 -0
  91. package/docs/release-tooling.7.md +2 -0
  92. package/docs/run-registry-control-plane.7.md +54 -8
  93. package/docs/run-retention-reclamation.7.md +4 -0
  94. package/docs/state-explosion-management.7.md +2 -0
  95. package/docs/team-collaboration.7.md +2 -0
  96. package/docs/trust-model.md +267 -0
  97. package/docs/vendor-manifest-loadability.7.md +43 -0
  98. package/docs/web-desktop-workbench.7.md +2 -0
  99. package/manifest/plugin.manifest.json +1 -1
  100. package/package.json +4 -2
  101. package/scripts/agents/builtin-templates.json +7 -0
  102. package/scripts/bump-version.js +5 -11
  103. package/scripts/canonical-apps-list.js +64 -0
  104. package/scripts/canonical-apps.js +19 -4
  105. package/scripts/dogfood-release.js +1 -1
  106. package/scripts/golden-path.js +4 -4
  107. package/scripts/parity-check.js +5 -0
  108. package/scripts/release-check.js +5 -1
  109. package/scripts/version-sync-check.js +5 -8
  110. package/dist/capability-dispatcher.js +0 -86
@@ -17,9 +17,6 @@ exports.listBlackboardMessages = listBlackboardMessages;
17
17
  exports.listBlackboardArtifacts = listBlackboardArtifacts;
18
18
  exports.buildBlackboardGraph = buildBlackboardGraph;
19
19
  exports.persistBlackboardState = persistBlackboardState;
20
- exports.bridgeStateArtifactToBlackboard = bridgeStateArtifactToBlackboard;
21
- exports.evidenceFromArtifactRef = evidenceFromArtifactRef;
22
- const node_crypto_1 = __importDefault(require("node:crypto"));
23
20
  const node_fs_1 = __importDefault(require("node:fs"));
24
21
  const node_path_1 = __importDefault(require("node:path"));
25
22
  const pipeline_contract_1 = require("./pipeline-contract");
@@ -28,9 +25,19 @@ const state_node_1 = require("./state-node");
28
25
  const multi_agent_1 = require("./multi-agent");
29
26
  const trust_audit_1 = require("./trust-audit");
30
27
  const multi_agent_trust_1 = require("./multi-agent-trust");
28
+ const util_1 = require("./coordinator/util");
29
+ const classify_1 = require("./coordinator/classify");
30
+ const paths_1 = require("./coordinator/paths");
31
+ // NOTE: the symbols imported above from ./coordinator/{util,classify,paths} were
32
+ // PRIVATE helpers inside this module before the carve (no importer reaches them,
33
+ // including the `import * as cb` consumer in orchestrator/multi-agent-operations).
34
+ // They are relocated as pure code movement — zero signature/behavior change — and
35
+ // imported back for internal use only, so this module's PUBLIC surface stays
36
+ // byte-identical (no new exports). The public exported functions below are
37
+ // unchanged.
31
38
  exports.BLACKBOARD_SCHEMA_VERSION = 1;
32
39
  function ensureBlackboardState(run) {
33
- run.paths.blackboardDir = blackboardRoot(run);
40
+ run.paths.blackboardDir = (0, paths_1.blackboardRoot)(run);
34
41
  node_fs_1.default.mkdirSync(run.paths.blackboardDir, { recursive: true });
35
42
  for (const dir of ["topics", "contexts", "artifacts", "snapshots", "decisions"]) {
36
43
  node_fs_1.default.mkdirSync(node_path_1.default.join(run.paths.blackboardDir, dir), { recursive: true });
@@ -57,13 +64,13 @@ function resolveBlackboard(run, input = {}) {
57
64
  : state.boards[0];
58
65
  if (existing) {
59
66
  linkMultiAgent(run, existing.id, existing.topicIds, input);
60
- touch(existing);
67
+ (0, util_1.touch)(existing);
61
68
  persistBlackboardState(run);
62
69
  return existing;
63
70
  }
64
- const id = input.id || createId("bb");
65
- assertUnique(state.boards, id, "Blackboard");
66
- const now = timestamp();
71
+ const id = input.id || (0, util_1.createId)("bb", state.boards.length + 1);
72
+ (0, util_1.assertUnique)(state.boards, id, "Blackboard");
73
+ const now = (0, util_1.timestamp)();
67
74
  const author = normalizeAuthor(input.author, "runtime");
68
75
  const scope = normalizeScope(input.scope, input.multiAgentRunId ? { kind: "multi-agent-run", id: input.multiAgentRunId } : { kind: "run", id: run.id });
69
76
  const board = {
@@ -76,7 +83,7 @@ function resolveBlackboard(run, input = {}) {
76
83
  scope,
77
84
  status: "active",
78
85
  parentIds: [],
79
- tags: sortTags(input.tags),
86
+ tags: (0, util_1.sortTags)(input.tags),
80
87
  title: input.title || id,
81
88
  topicIds: [],
82
89
  messageCount: 0,
@@ -90,8 +97,8 @@ function resolveBlackboard(run, input = {}) {
90
97
  agentRoleId: input.roleId,
91
98
  agentMembershipId: input.membershipId
92
99
  }),
93
- paths: boardPaths(run),
94
- metadata: scrub(input.metadata)
100
+ paths: (0, paths_1.boardPaths)(run),
101
+ metadata: (0, util_1.scrub)(input.metadata)
95
102
  };
96
103
  linkMultiAgent(run, board.id, [], input);
97
104
  state.boards.push(board);
@@ -115,10 +122,10 @@ function resolveBlackboard(run, input = {}) {
115
122
  function createBlackboardTopic(run, input) {
116
123
  const board = resolveBlackboard(run, { id: input.blackboardId });
117
124
  const state = ensureBlackboardState(run);
118
- const id = input.id || createId("topic");
119
- assertUnique(state.topics, id, "BlackboardTopic");
125
+ const id = input.id || (0, util_1.createId)("topic", state.topics.length + 1);
126
+ (0, util_1.assertUnique)(state.topics, id, "BlackboardTopic");
120
127
  const topicLinks = compactLinks(run, { ...board.links, ...roleLinkFromAuthor(input.author), ...input.scope });
121
- const now = timestamp();
128
+ const now = (0, util_1.timestamp)();
122
129
  const topic = {
123
130
  ...base(run, board.id, id, input.author, input.scope, "open", input.tags, input.metadata),
124
131
  createdAt: now,
@@ -131,10 +138,10 @@ function createBlackboardTopic(run, input) {
131
138
  links: topicLinks
132
139
  };
133
140
  state.topics.push(topic);
134
- board.topicIds = unique([...board.topicIds, topic.id]);
135
- touch(board);
141
+ board.topicIds = (0, util_1.unique)([...board.topicIds, topic.id]);
142
+ (0, util_1.touch)(board);
136
143
  linkMultiAgent(run, board.id, [topic.id], board.links);
137
- appendBlackboardNode(run, "blackboard-topic", topic.id, "running", topic.title, recordPath(run, "topics", topic.id), [`${run.id}:blackboard:${board.id}`]);
144
+ appendBlackboardNode(run, "blackboard-topic", topic.id, "running", topic.title, (0, paths_1.recordPath)(run, "topics", topic.id), [`${run.id}:blackboard:${board.id}`]);
138
145
  const audit = (0, trust_audit_1.recordTrustAuditEvent)(run, {
139
146
  kind: "blackboard.topic",
140
147
  decision: "recorded",
@@ -148,7 +155,7 @@ function createBlackboardTopic(run, input) {
148
155
  agentMembershipId: topic.links.agentMembershipId,
149
156
  metadata: { title: topic.title, tags: topic.tags }
150
157
  });
151
- topic.links.auditEventIds = unique([...(topic.links.auditEventIds || []), audit.id]);
158
+ topic.links.auditEventIds = (0, util_1.unique)([...(topic.links.auditEventIds || []), audit.id]);
152
159
  (0, multi_agent_trust_1.recordBlackboardWriteAudit)(run, {
153
160
  operation: "topic",
154
161
  status: topic.status,
@@ -174,8 +181,8 @@ function postBlackboardMessage(run, input) {
174
181
  }
175
182
  if (!input.body.trim())
176
183
  throw new Error("Blackboard message body is required");
177
- const id = input.id || createId("msg");
178
- assertUnique(state.messages, id, "BlackboardMessage");
184
+ const id = input.id || (0, util_1.createId)("msg", state.messages.length + 1);
185
+ (0, util_1.assertUnique)(state.messages, id, "BlackboardMessage");
179
186
  const author = normalizeAuthor(input.author, "operator");
180
187
  const links = compactLinks(run, { ...topic.links, ...roleLinkFromAuthor(author), ...(input.links || {}), evidenceRefs: input.evidenceRefs, auditEventIds: input.auditEventIds });
181
188
  const enforcePolicy = shouldEnforcePolicy(author, links);
@@ -201,10 +208,10 @@ function postBlackboardMessage(run, input) {
201
208
  body: input.body,
202
209
  visibility: input.visibility || "public",
203
210
  replyToId: input.replyToId,
204
- parentIds: unique([...(input.parentIds || []), ...(input.replyToId ? [input.replyToId] : [])]),
205
- linkedEvidenceRefs: unique(input.evidenceRefs || []),
211
+ parentIds: (0, util_1.unique)([...(input.parentIds || []), ...(input.replyToId ? [input.replyToId] : [])]),
212
+ linkedEvidenceRefs: (0, util_1.unique)(input.evidenceRefs || []),
206
213
  linkedArtifactRefIds: requireArtifactRefs(run, input.artifactRefIds || []),
207
- linkedAuditEventIds: unique(input.auditEventIds || []),
214
+ linkedAuditEventIds: (0, util_1.unique)(input.auditEventIds || []),
208
215
  links,
209
216
  provenance: {
210
217
  schemaVersion: 1,
@@ -218,24 +225,24 @@ function postBlackboardMessage(run, input) {
218
225
  agentFaninId: links.agentFaninId,
219
226
  workerId: links.workerId || (author.kind === "worker" ? author.id : undefined),
220
227
  source: (0, multi_agent_trust_1.sourceForActor)(author),
221
- linkedEvidenceRefs: unique(input.evidenceRefs || []),
222
- linkedAuditEventIds: unique(input.auditEventIds || []),
223
- parentMessageIds: unique([...(input.parentIds || []), ...(input.replyToId ? [input.replyToId] : [])]),
228
+ linkedEvidenceRefs: (0, util_1.unique)(input.evidenceRefs || []),
229
+ linkedAuditEventIds: (0, util_1.unique)(input.auditEventIds || []),
230
+ parentMessageIds: (0, util_1.unique)([...(input.parentIds || []), ...(input.replyToId ? [input.replyToId] : [])]),
224
231
  topicScope: topic.id,
225
232
  bodyHash: (0, multi_agent_trust_1.hashText)(input.body),
226
233
  locator: `${board.id}/messages/${id}`
227
234
  }
228
235
  };
229
236
  state.messages.push(message);
230
- topic.messageIds = unique([...topic.messageIds, message.id]);
237
+ topic.messageIds = (0, util_1.unique)([...topic.messageIds, message.id]);
231
238
  board.messageCount = state.messages.filter((entry) => entry.blackboardId === board.id).length;
232
- touch(topic);
233
- touch(board);
234
- appendBlackboardNode(run, "blackboard-message", message.id, "completed", truncate(message.body), messagesPath(run), [`${run.id}:blackboard:topic:${topic.id}`]);
239
+ (0, util_1.touch)(topic);
240
+ (0, util_1.touch)(board);
241
+ appendBlackboardNode(run, "blackboard-message", message.id, "completed", (0, util_1.truncate)(message.body), (0, paths_1.messagesPath)(run), [`${run.id}:blackboard:topic:${topic.id}`]);
235
242
  const audit = (0, trust_audit_1.recordTrustAuditEvent)(run, {
236
243
  kind: "blackboard.message",
237
244
  decision: "recorded",
238
- source: sourceForAuthor(message.author),
245
+ source: (0, classify_1.sourceForAuthor)(message.author),
239
246
  actor: message.author.id,
240
247
  blackboardId: board.id,
241
248
  blackboardTopicId: topic.id,
@@ -264,7 +271,7 @@ function postBlackboardMessage(run, input) {
264
271
  blackboardTopicId: topic.id,
265
272
  blackboardMessageId: message.id,
266
273
  evidenceRefs: message.linkedEvidenceRefs,
267
- parentEventIds: unique([...(permission ? [permission.event.id] : []), audit.id]),
274
+ parentEventIds: (0, util_1.unique)([...(permission ? [permission.event.id] : []), audit.id]),
268
275
  policyRef: permission?.policyRef,
269
276
  metadata: { visibility: message.visibility }
270
277
  });
@@ -300,12 +307,12 @@ function postBlackboardMessage(run, input) {
300
307
  policyRef: permission?.policyRef,
301
308
  parentEventIds: [audit.id, writeAudit.id, provenanceAudit.id]
302
309
  });
303
- message.linkedAuditEventIds = unique([...message.linkedAuditEventIds, rationaleAudit.id]);
310
+ message.linkedAuditEventIds = (0, util_1.unique)([...message.linkedAuditEventIds, rationaleAudit.id]);
304
311
  }
305
- message.linkedAuditEventIds = unique([...message.linkedAuditEventIds, audit.id, writeAudit.id, provenanceAudit.id]);
306
- message.links.auditEventIds = unique([...(message.links.auditEventIds || []), audit.id, writeAudit.id, provenanceAudit.id]);
312
+ message.linkedAuditEventIds = (0, util_1.unique)([...message.linkedAuditEventIds, audit.id, writeAudit.id, provenanceAudit.id]);
313
+ message.links.auditEventIds = (0, util_1.unique)([...(message.links.auditEventIds || []), audit.id, writeAudit.id, provenanceAudit.id]);
307
314
  if (message.provenance) {
308
- message.provenance.linkedAuditEventIds = unique([...message.provenance.linkedAuditEventIds, audit.id, writeAudit.id, provenanceAudit.id]);
315
+ message.provenance.linkedAuditEventIds = (0, util_1.unique)([...message.provenance.linkedAuditEventIds, audit.id, writeAudit.id, provenanceAudit.id]);
309
316
  }
310
317
  persistBlackboardState(run);
311
318
  return message;
@@ -315,8 +322,8 @@ function putBlackboardContext(run, input) {
315
322
  const topic = requireTopic(run, input.topicId);
316
323
  const board = requireBoard(run, input.blackboardId || topic.blackboardId);
317
324
  const key = input.key || input.kind;
318
- const id = input.id || createId("ctx");
319
- assertUnique(state.contexts, id, "BlackboardContext");
325
+ const id = input.id || (0, util_1.createId)("ctx", state.contexts.length + 1);
326
+ (0, util_1.assertUnique)(state.contexts, id, "BlackboardContext");
320
327
  const author = normalizeAuthor(input.author, "operator");
321
328
  const links = compactLinks(run, { ...topic.links, ...roleLinkFromAuthor(author), ...(input.links || {}), evidenceRefs: input.evidenceRefs });
322
329
  const permission = shouldEnforcePolicy(author, links)
@@ -344,7 +351,7 @@ function putBlackboardContext(run, input) {
344
351
  const superseded = requireContext(run, supersededId);
345
352
  superseded.status = "superseded";
346
353
  superseded.supersededByContextId = id;
347
- touch(superseded);
354
+ (0, util_1.touch)(superseded);
348
355
  }
349
356
  const status = conflicts.length ? "conflicting" : input.kind === "question" ? "open" : "active";
350
357
  const context = {
@@ -353,22 +360,22 @@ function putBlackboardContext(run, input) {
353
360
  kind: input.kind,
354
361
  key,
355
362
  value: input.value,
356
- supersedesContextIds: unique(input.supersedesContextIds || []),
363
+ supersedesContextIds: (0, util_1.unique)(input.supersedesContextIds || []),
357
364
  conflictingContextIds: conflicts.map((entry) => entry.id),
358
- evidenceRefs: unique(input.evidenceRefs || []),
365
+ evidenceRefs: (0, util_1.unique)(input.evidenceRefs || []),
359
366
  artifactRefIds: requireArtifactRefs(run, input.artifactRefIds || []),
360
367
  links
361
368
  };
362
369
  for (const conflict of conflicts) {
363
370
  conflict.status = "conflicting";
364
- conflict.conflictingContextIds = unique([...conflict.conflictingContextIds, context.id]);
365
- touch(conflict);
371
+ conflict.conflictingContextIds = (0, util_1.unique)([...conflict.conflictingContextIds, context.id]);
372
+ (0, util_1.touch)(conflict);
366
373
  }
367
374
  state.contexts.push(context);
368
- topic.contextIds = unique([...topic.contextIds, context.id]);
369
- board.contextIds = unique([...board.contextIds, context.id]);
370
- touch(topic);
371
- touch(board);
375
+ topic.contextIds = (0, util_1.unique)([...topic.contextIds, context.id]);
376
+ board.contextIds = (0, util_1.unique)([...board.contextIds, context.id]);
377
+ (0, util_1.touch)(topic);
378
+ (0, util_1.touch)(board);
372
379
  const decision = recordCoordinatorDecision(run, {
373
380
  blackboardId: board.id,
374
381
  topicId: topic.id,
@@ -386,11 +393,11 @@ function putBlackboardContext(run, input) {
386
393
  tags: ["context", input.kind]
387
394
  });
388
395
  context.decisionId = decision.id;
389
- appendBlackboardNode(run, "blackboard-context", context.id, statusToNodeStatus(context.status), `${context.kind}:${context.key}`, recordPath(run, "contexts", context.id), [`${run.id}:blackboard:topic:${topic.id}`]);
396
+ appendBlackboardNode(run, "blackboard-context", context.id, (0, classify_1.statusToNodeStatus)(context.status), `${context.kind}:${context.key}`, (0, paths_1.recordPath)(run, "contexts", context.id), [`${run.id}:blackboard:topic:${topic.id}`]);
390
397
  const audit = (0, trust_audit_1.recordTrustAuditEvent)(run, {
391
398
  kind: "blackboard.context",
392
399
  decision: conflicts.length ? "failed" : "accepted",
393
- source: sourceForAuthor(context.author),
400
+ source: (0, classify_1.sourceForAuthor)(context.author),
394
401
  actor: context.author.id,
395
402
  blackboardId: board.id,
396
403
  blackboardTopicId: topic.id,
@@ -416,12 +423,12 @@ function putBlackboardContext(run, input) {
416
423
  blackboardContextId: context.id,
417
424
  coordinatorDecisionId: decision.id,
418
425
  evidenceRefs: context.evidenceRefs,
419
- parentEventIds: unique([...(permission ? [permission.event.id] : []), audit.id]),
426
+ parentEventIds: (0, util_1.unique)([...(permission ? [permission.event.id] : []), audit.id]),
420
427
  policyRef: permission?.policyRef,
421
428
  metadata: { kind: context.kind, key: context.key, conflicts: context.conflictingContextIds }
422
429
  });
423
- context.links.auditEventIds = unique([...(context.links.auditEventIds || []), audit.id]);
424
- context.links.auditEventIds = unique([...(context.links.auditEventIds || []), writeAudit.id]);
430
+ context.links.auditEventIds = (0, util_1.unique)([...(context.links.auditEventIds || []), audit.id]);
431
+ context.links.auditEventIds = (0, util_1.unique)([...(context.links.auditEventIds || []), writeAudit.id]);
425
432
  persistBlackboardState(run);
426
433
  return context;
427
434
  }
@@ -433,8 +440,8 @@ function addBlackboardArtifact(run, input) {
433
440
  const topic = input.topicId ? requireTopic(run, input.topicId) : undefined;
434
441
  if (topic && topic.blackboardId !== board.id)
435
442
  throw new Error(`Topic ${topic.id} does not belong to blackboard ${board.id}`);
436
- const id = input.id || createId("artifact");
437
- assertUnique(state.artifacts, id, "BlackboardArtifactRef");
443
+ const id = input.id || (0, util_1.createId)("artifact", state.artifacts.length + 1);
444
+ (0, util_1.assertUnique)(state.artifacts, id, "BlackboardArtifactRef");
438
445
  const author = normalizeAuthor(input.author, "operator");
439
446
  const links = compactLinks(run, { ...board.links, ...(topic?.links || {}), ...roleLinkFromAuthor(author), ...(input.links || {}), evidenceRefs: input.evidenceRefs, auditEventIds: input.auditEventIds });
440
447
  const permission = shouldEnforcePolicy(author, links)
@@ -461,17 +468,17 @@ function addBlackboardArtifact(run, input) {
461
468
  owner: normalizeAuthor(input.owner || input.author, "operator"),
462
469
  source: input.source || "operator-recorded",
463
470
  provenance: compactLinks(run, { ...(input.provenance || {}), ...links }),
464
- evidenceRefs: unique(input.evidenceRefs || []),
465
- checksum: absolutePath && node_fs_1.default.existsSync(absolutePath) && node_fs_1.default.statSync(absolutePath).isFile() ? checksumFile(absolutePath) : undefined,
466
- trustAuditEventIds: unique(input.auditEventIds || [])
471
+ evidenceRefs: (0, util_1.unique)(input.evidenceRefs || []),
472
+ checksum: absolutePath && node_fs_1.default.existsSync(absolutePath) && node_fs_1.default.statSync(absolutePath).isFile() ? (0, util_1.checksumFile)(absolutePath) : undefined,
473
+ trustAuditEventIds: (0, util_1.unique)(input.auditEventIds || [])
467
474
  };
468
475
  state.artifacts.push(artifact);
469
- board.artifactRefIds = unique([...board.artifactRefIds, artifact.id]);
476
+ board.artifactRefIds = (0, util_1.unique)([...board.artifactRefIds, artifact.id]);
470
477
  if (topic)
471
- topic.artifactRefIds = unique([...topic.artifactRefIds, artifact.id]);
472
- touch(board);
478
+ topic.artifactRefIds = (0, util_1.unique)([...topic.artifactRefIds, artifact.id]);
479
+ (0, util_1.touch)(board);
473
480
  if (topic)
474
- touch(topic);
481
+ (0, util_1.touch)(topic);
475
482
  const decision = recordCoordinatorDecision(run, {
476
483
  blackboardId: board.id,
477
484
  topicId: topic?.id,
@@ -485,13 +492,13 @@ function addBlackboardArtifact(run, input) {
485
492
  scope: artifact.scope,
486
493
  tags: ["artifact", artifact.kind]
487
494
  });
488
- appendBlackboardNode(run, "blackboard-artifact", artifact.id, "completed", artifact.kind, recordPath(run, "artifacts", artifact.id), [
495
+ appendBlackboardNode(run, "blackboard-artifact", artifact.id, "completed", artifact.kind, (0, paths_1.recordPath)(run, "artifacts", artifact.id), [
489
496
  topic ? `${run.id}:blackboard:topic:${topic.id}` : `${run.id}:blackboard:${board.id}`
490
497
  ]);
491
498
  const audit = (0, trust_audit_1.recordTrustAuditEvent)(run, {
492
499
  kind: "blackboard.artifact",
493
500
  decision: "accepted",
494
- source: sourceForAuthor(artifact.author),
501
+ source: (0, classify_1.sourceForAuthor)(artifact.author),
495
502
  actor: artifact.author.id,
496
503
  blackboardId: board.id,
497
504
  blackboardTopicId: topic?.id,
@@ -519,19 +526,19 @@ function addBlackboardArtifact(run, input) {
519
526
  blackboardArtifactRefId: artifact.id,
520
527
  coordinatorDecisionId: decision.id,
521
528
  evidenceRefs: artifact.evidenceRefs,
522
- parentEventIds: unique([...(permission ? [permission.event.id] : []), audit.id]),
529
+ parentEventIds: (0, util_1.unique)([...(permission ? [permission.event.id] : []), audit.id]),
523
530
  policyRef: permission?.policyRef,
524
531
  metadata: { kind: artifact.kind, locator: artifact.locator, checksum: artifact.checksum }
525
532
  });
526
- artifact.trustAuditEventIds = unique([...artifact.trustAuditEventIds, audit.id, writeAudit.id]);
533
+ artifact.trustAuditEventIds = (0, util_1.unique)([...artifact.trustAuditEventIds, audit.id, writeAudit.id]);
527
534
  persistBlackboardState(run);
528
535
  return artifact;
529
536
  }
530
537
  function createBlackboardSnapshot(run, blackboardId) {
531
538
  const state = ensureBlackboardState(run);
532
539
  const board = resolveBlackboard(run, { id: blackboardId });
533
- const id = createId("snapshot");
534
- const snapshotPath = recordPath(run, "snapshots", id);
540
+ const id = (0, util_1.createId)("snapshot", state.snapshots.length + 1);
541
+ const snapshotPath = (0, paths_1.recordPath)(run, "snapshots", id);
535
542
  const summary = summarizeBlackboard(run, board.id);
536
543
  const snapshot = {
537
544
  ...base(run, board.id, id, { kind: "runtime", id: "cw" }, { kind: "run", id: run.id }, "active", ["snapshot"], undefined),
@@ -546,8 +553,8 @@ function createBlackboardSnapshot(run, blackboardId) {
546
553
  links: compactLinks(run, board.links)
547
554
  };
548
555
  state.snapshots.push(snapshot);
549
- board.snapshotIds = unique([...board.snapshotIds, snapshot.id]);
550
- touch(board);
556
+ board.snapshotIds = (0, util_1.unique)([...board.snapshotIds, snapshot.id]);
557
+ (0, util_1.touch)(board);
551
558
  appendBlackboardNode(run, "blackboard-snapshot", snapshot.id, "completed", snapshot.id, snapshotPath, [`${run.id}:blackboard:${board.id}`]);
552
559
  const audit = (0, trust_audit_1.recordTrustAuditEvent)(run, {
553
560
  kind: "blackboard.snapshot",
@@ -572,36 +579,36 @@ function createBlackboardSnapshot(run, blackboardId) {
572
579
  metadata: { snapshotPath }
573
580
  });
574
581
  snapshot.links.auditEventIds = [audit.id];
575
- snapshot.links.auditEventIds = unique([...snapshot.links.auditEventIds, writeAudit.id]);
582
+ snapshot.links.auditEventIds = (0, util_1.unique)([...snapshot.links.auditEventIds, writeAudit.id]);
576
583
  persistBlackboardState(run);
577
584
  return snapshot;
578
585
  }
579
586
  function recordCoordinatorDecision(run, input) {
580
587
  const state = ensureBlackboardState(run);
581
588
  const board = resolveBlackboard(run, { id: input.blackboardId });
582
- const id = input.id || createId("decision");
583
- assertUnique(state.decisions, id, "CoordinatorDecision");
589
+ const id = input.id || (0, util_1.createId)("decision", state.decisions.length + 1);
590
+ (0, util_1.assertUnique)(state.decisions, id, "CoordinatorDecision");
584
591
  const decision = {
585
- ...base(run, board.id, id, input.author || { kind: "coordinator", id: "cw" }, input.scope, decisionStatus(input.outcome), input.tags, input.metadata),
592
+ ...base(run, board.id, id, input.author || { kind: "coordinator", id: "cw" }, input.scope, (0, classify_1.decisionStatus)(input.outcome), input.tags, input.metadata),
586
593
  kind: input.kind,
587
594
  outcome: input.outcome,
588
- subjectIds: unique(input.subjectIds || []),
595
+ subjectIds: (0, util_1.unique)(input.subjectIds || []),
589
596
  reason: input.reason,
590
- evidenceRefs: unique(input.evidenceRefs || []),
597
+ evidenceRefs: (0, util_1.unique)(input.evidenceRefs || []),
591
598
  artifactRefIds: requireArtifactRefs(run, input.artifactRefIds || []),
592
599
  messageIds: requireMessages(run, input.messageIds || []),
593
600
  links: compactLinks(run, { ...board.links, ...roleLinkFromAuthor(input.author), ...(input.links || {}), evidenceRefs: input.evidenceRefs })
594
601
  };
595
602
  state.decisions.push(decision);
596
- board.decisionIds = unique([...board.decisionIds, decision.id]);
597
- touch(board);
598
- appendBlackboardNode(run, "coordinator-decision", decision.id, statusToNodeStatus(decision.status), `${decision.kind}:${decision.outcome}`, recordPath(run, "decisions", decision.id), [
603
+ board.decisionIds = (0, util_1.unique)([...board.decisionIds, decision.id]);
604
+ (0, util_1.touch)(board);
605
+ appendBlackboardNode(run, "coordinator-decision", decision.id, (0, classify_1.statusToNodeStatus)(decision.status), `${decision.kind}:${decision.outcome}`, (0, paths_1.recordPath)(run, "decisions", decision.id), [
599
606
  `${run.id}:blackboard:${board.id}`,
600
607
  ...(input.topicId ? [`${run.id}:blackboard:topic:${input.topicId}`] : [])
601
608
  ]);
602
609
  const audit = (0, trust_audit_1.recordTrustAuditEvent)(run, {
603
610
  kind: "coordinator.decision",
604
- decision: auditDecision(input.outcome),
611
+ decision: (0, classify_1.auditDecision)(input.outcome),
605
612
  source: "cw-validated",
606
613
  actor: decision.author.id,
607
614
  blackboardId: board.id,
@@ -649,9 +656,9 @@ function recordCoordinatorDecision(run, input) {
649
656
  rationale: decision.reason,
650
657
  parentEventIds: [audit.id, writeAudit.id]
651
658
  });
652
- decision.links.auditEventIds = unique([...(decision.links.auditEventIds || []), panelAudit.id]);
659
+ decision.links.auditEventIds = (0, util_1.unique)([...(decision.links.auditEventIds || []), panelAudit.id]);
653
660
  }
654
- decision.links.auditEventIds = unique([...(decision.links.auditEventIds || []), audit.id, writeAudit.id]);
661
+ decision.links.auditEventIds = (0, util_1.unique)([...(decision.links.auditEventIds || []), audit.id, writeAudit.id]);
655
662
  persistBlackboardState(run);
656
663
  return decision;
657
664
  }
@@ -683,7 +690,7 @@ function summarizeBlackboard(run, blackboardId) {
683
690
  missingEvidence,
684
691
  readyForFanin,
685
692
  latestSnapshotPath: latestSnapshot?.snapshotPath,
686
- indexPath: board?.paths.index || node_path_1.default.join(blackboardRoot(run), "index.json"),
693
+ indexPath: board?.paths.index || node_path_1.default.join((0, paths_1.blackboardRoot)(run), "index.json"),
687
694
  nextAction: nextAction(run, board, openQuestions, conflicts, artifacts)
688
695
  };
689
696
  }
@@ -710,21 +717,21 @@ function buildBlackboardGraph(run) {
710
717
  edges.push({ from: `${run.id}:multi-agent:${board.links.multiAgentRunId}`, to: `${run.id}:blackboard:${board.id}`, label: "coordinates" });
711
718
  }
712
719
  for (const topic of state.topics) {
713
- nodes.push({ id: `${run.id}:blackboard:topic:${topic.id}`, kind: "blackboard-topic", status: topic.status, label: topic.title, path: recordPath(run, "topics", topic.id) });
720
+ nodes.push({ id: `${run.id}:blackboard:topic:${topic.id}`, kind: "blackboard-topic", status: topic.status, label: topic.title, path: (0, paths_1.recordPath)(run, "topics", topic.id) });
714
721
  edges.push({ from: `${run.id}:blackboard:${topic.blackboardId}`, to: `${run.id}:blackboard:topic:${topic.id}` });
715
722
  }
716
723
  for (const context of state.contexts) {
717
- nodes.push({ id: `${run.id}:blackboard:context:${context.id}`, kind: "blackboard-context", status: context.status, label: `${context.kind}:${context.key}`, path: recordPath(run, "contexts", context.id) });
724
+ nodes.push({ id: `${run.id}:blackboard:context:${context.id}`, kind: "blackboard-context", status: context.status, label: `${context.kind}:${context.key}`, path: (0, paths_1.recordPath)(run, "contexts", context.id) });
718
725
  edges.push({ from: `${run.id}:blackboard:topic:${context.topicId}`, to: `${run.id}:blackboard:context:${context.id}` });
719
726
  for (const conflicting of context.conflictingContextIds)
720
727
  edges.push({ from: `${run.id}:blackboard:context:${context.id}`, to: `${run.id}:blackboard:context:${conflicting}`, label: "conflicts" });
721
728
  }
722
729
  for (const artifact of state.artifacts) {
723
- nodes.push({ id: `${run.id}:blackboard:artifact:${artifact.id}`, kind: "blackboard-artifact", status: artifact.status, label: artifact.kind, path: recordPath(run, "artifacts", artifact.id) });
730
+ nodes.push({ id: `${run.id}:blackboard:artifact:${artifact.id}`, kind: "blackboard-artifact", status: artifact.status, label: artifact.kind, path: (0, paths_1.recordPath)(run, "artifacts", artifact.id) });
724
731
  edges.push({ from: artifact.topicId ? `${run.id}:blackboard:topic:${artifact.topicId}` : `${run.id}:blackboard:${artifact.blackboardId}`, to: `${run.id}:blackboard:artifact:${artifact.id}` });
725
732
  }
726
733
  for (const message of state.messages) {
727
- nodes.push({ id: `${run.id}:blackboard:message:${message.id}`, kind: "blackboard-message", status: message.status, label: truncate(message.body), path: messagesPath(run) });
734
+ nodes.push({ id: `${run.id}:blackboard:message:${message.id}`, kind: "blackboard-message", status: message.status, label: (0, util_1.truncate)(message.body), path: (0, paths_1.messagesPath)(run) });
728
735
  edges.push({ from: `${run.id}:blackboard:topic:${message.topicId}`, to: `${run.id}:blackboard:message:${message.id}` });
729
736
  if (message.replyToId)
730
737
  edges.push({ from: `${run.id}:blackboard:message:${message.replyToId}`, to: `${run.id}:blackboard:message:${message.id}`, label: "reply" });
@@ -732,7 +739,7 @@ function buildBlackboardGraph(run) {
732
739
  edges.push({ from: `${run.id}:blackboard:message:${message.id}`, to: `${run.id}:blackboard:artifact:${artifactId}`, label: "cites" });
733
740
  }
734
741
  for (const decision of state.decisions) {
735
- nodes.push({ id: `${run.id}:coordinator:decision:${decision.id}`, kind: "coordinator-decision", status: decision.status, label: `${decision.kind}:${decision.outcome}`, path: recordPath(run, "decisions", decision.id) });
742
+ nodes.push({ id: `${run.id}:coordinator:decision:${decision.id}`, kind: "coordinator-decision", status: decision.status, label: `${decision.kind}:${decision.outcome}`, path: (0, paths_1.recordPath)(run, "decisions", decision.id) });
736
743
  edges.push({ from: `${run.id}:blackboard:${decision.blackboardId}`, to: `${run.id}:coordinator:decision:${decision.id}` });
737
744
  for (const subjectId of decision.subjectIds)
738
745
  edges.push({ from: `${run.id}:coordinator:decision:${decision.id}`, to: graphSubject(run, subjectId), label: "subject" });
@@ -741,20 +748,20 @@ function buildBlackboardGraph(run) {
741
748
  nodes.push({ id: `${run.id}:blackboard:snapshot:${snapshot.id}`, kind: "blackboard-snapshot", status: snapshot.status, label: snapshot.id, path: snapshot.snapshotPath });
742
749
  edges.push({ from: `${run.id}:blackboard:${snapshot.blackboardId}`, to: `${run.id}:blackboard:snapshot:${snapshot.id}` });
743
750
  }
744
- return { nodes, edges: uniqueEdges(edges) };
751
+ return { nodes, edges: (0, util_1.uniqueEdges)(edges) };
745
752
  }
746
753
  function persistBlackboardState(run) {
747
754
  const state = ensureBlackboardState(run);
748
- const root = blackboardRoot(run);
749
- assertNoRecordPathCollisions("BlackboardTopic", state.topics);
750
- assertNoRecordPathCollisions("BlackboardContext", state.contexts);
751
- assertNoRecordPathCollisions("BlackboardArtifactRef", state.artifacts);
752
- assertNoRecordPathCollisions("BlackboardSnapshot", state.snapshots);
753
- assertNoRecordPathCollisions("CoordinatorDecision", state.decisions);
755
+ const root = (0, paths_1.blackboardRoot)(run);
756
+ (0, util_1.assertNoRecordPathCollisions)("BlackboardTopic", state.topics);
757
+ (0, util_1.assertNoRecordPathCollisions)("BlackboardContext", state.contexts);
758
+ (0, util_1.assertNoRecordPathCollisions)("BlackboardArtifactRef", state.artifacts);
759
+ (0, util_1.assertNoRecordPathCollisions)("BlackboardSnapshot", state.snapshots);
760
+ (0, util_1.assertNoRecordPathCollisions)("CoordinatorDecision", state.decisions);
754
761
  const index = {
755
762
  schemaVersion: exports.BLACKBOARD_SCHEMA_VERSION,
756
763
  runId: run.id,
757
- generatedAt: timestamp(),
764
+ generatedAt: (0, util_1.timestamp)(),
758
765
  counts: {
759
766
  boards: state.boards.length,
760
767
  topics: state.topics.length,
@@ -764,12 +771,12 @@ function persistBlackboardState(run) {
764
771
  snapshots: state.snapshots.length,
765
772
  decisions: state.decisions.length
766
773
  },
767
- boards: state.boards.map(indexRow),
768
- topics: state.topics.map(indexRow),
769
- contexts: state.contexts.map(indexRow),
770
- artifacts: state.artifacts.map(indexRow),
771
- snapshots: state.snapshots.map(indexRow),
772
- decisions: state.decisions.map(indexRow),
774
+ boards: state.boards.map(util_1.indexRow),
775
+ topics: state.topics.map(util_1.indexRow),
776
+ contexts: state.contexts.map(util_1.indexRow),
777
+ artifacts: state.artifacts.map(util_1.indexRow),
778
+ snapshots: state.snapshots.map(util_1.indexRow),
779
+ decisions: state.decisions.map(util_1.indexRow),
773
780
  messages: state.messages.map((message) => ({
774
781
  id: message.id,
775
782
  blackboardId: message.blackboardId,
@@ -782,45 +789,17 @@ function persistBlackboardState(run) {
782
789
  }))
783
790
  };
784
791
  (0, state_1.writeJson)(node_path_1.default.join(root, "index.json"), index);
785
- node_fs_1.default.writeFileSync(messagesPath(run), state.messages.sort(compareRecords).map((message) => JSON.stringify(message)).join("\n") + (state.messages.length ? "\n" : ""), "utf8");
792
+ node_fs_1.default.writeFileSync((0, paths_1.messagesPath)(run), state.messages.sort(util_1.compareRecords).map((message) => JSON.stringify(message)).join("\n") + (state.messages.length ? "\n" : ""), "utf8");
786
793
  for (const topic of state.topics)
787
- (0, state_1.writeJson)(recordPath(run, "topics", topic.id), topic);
794
+ (0, state_1.writeJson)((0, paths_1.recordPath)(run, "topics", topic.id), topic);
788
795
  for (const context of state.contexts)
789
- (0, state_1.writeJson)(recordPath(run, "contexts", context.id), context);
796
+ (0, state_1.writeJson)((0, paths_1.recordPath)(run, "contexts", context.id), context);
790
797
  for (const artifact of state.artifacts)
791
- (0, state_1.writeJson)(recordPath(run, "artifacts", artifact.id), artifact);
798
+ (0, state_1.writeJson)((0, paths_1.recordPath)(run, "artifacts", artifact.id), artifact);
792
799
  for (const snapshot of state.snapshots)
793
- (0, state_1.writeJson)(recordPath(run, "snapshots", snapshot.id), snapshot);
800
+ (0, state_1.writeJson)((0, paths_1.recordPath)(run, "snapshots", snapshot.id), snapshot);
794
801
  for (const decision of state.decisions)
795
- (0, state_1.writeJson)(recordPath(run, "decisions", decision.id), decision);
796
- }
797
- function bridgeStateArtifactToBlackboard(run, artifact, input = {}) {
798
- return addBlackboardArtifact(run, {
799
- kind: artifact.kind,
800
- path: artifact.path,
801
- locator: artifact.path,
802
- metadata: { description: artifact.description, stateArtifactId: artifact.id },
803
- ...input
804
- });
805
- }
806
- function evidenceFromArtifactRef(artifact) {
807
- return {
808
- id: artifact.id,
809
- source: "blackboard-artifact",
810
- path: artifact.path,
811
- locator: artifact.locator || artifact.path,
812
- summary: `${artifact.kind} ${artifact.path || artifact.locator || artifact.id}`,
813
- provenance: {
814
- schemaVersion: 1,
815
- runId: artifact.runId,
816
- source: "cw-validated",
817
- workerId: artifact.provenance.workerId,
818
- taskId: artifact.provenance.taskId,
819
- candidateId: artifact.provenance.candidateId,
820
- commitId: artifact.provenance.commitId,
821
- auditEventIds: artifact.trustAuditEventIds
822
- }
823
- };
802
+ (0, state_1.writeJson)((0, paths_1.recordPath)(run, "decisions", decision.id), decision);
824
803
  }
825
804
  function emptyState() {
826
805
  return {
@@ -853,7 +832,7 @@ function shouldEnforcePolicy(author, links) {
853
832
  return Boolean(links.agentRoleId || links.agentGroupId || links.agentMembershipId);
854
833
  }
855
834
  function base(run, blackboardId, id, author, scope, status = "active", tags, metadata) {
856
- const now = timestamp();
835
+ const now = (0, util_1.timestamp)();
857
836
  return {
858
837
  schemaVersion: exports.BLACKBOARD_SCHEMA_VERSION,
859
838
  id,
@@ -865,8 +844,8 @@ function base(run, blackboardId, id, author, scope, status = "active", tags, met
865
844
  scope: normalizeScope(scope, { kind: "run", id: run.id }),
866
845
  status,
867
846
  parentIds: [],
868
- tags: sortTags(tags),
869
- metadata: scrub(metadata)
847
+ tags: (0, util_1.sortTags)(tags),
848
+ metadata: (0, util_1.scrub)(metadata)
870
849
  };
871
850
  }
872
851
  function normalizeAuthor(input, fallbackKind) {
@@ -884,7 +863,7 @@ function normalizeScope(input, fallback) {
884
863
  return { kind, id };
885
864
  }
886
865
  function compactLinks(run, input) {
887
- return compact({
866
+ return (0, util_1.compact)({
888
867
  workflowRunId: run.id,
889
868
  multiAgentRunId: input.multiAgentRunId,
890
869
  agentGroupId: input.agentGroupId,
@@ -897,8 +876,8 @@ function compactLinks(run, input) {
897
876
  candidateId: input.candidateId,
898
877
  verifierNodeId: input.verifierNodeId,
899
878
  commitId: input.commitId,
900
- auditEventIds: unique(input.auditEventIds || []),
901
- evidenceRefs: unique(input.evidenceRefs || [])
879
+ auditEventIds: (0, util_1.unique)(input.auditEventIds || []),
880
+ evidenceRefs: (0, util_1.unique)(input.evidenceRefs || [])
902
881
  });
903
882
  }
904
883
  function linkMultiAgent(run, blackboardId, topicIds, input) {
@@ -909,30 +888,30 @@ function linkMultiAgent(run, blackboardId, topicIds, input) {
909
888
  const record = (0, multi_agent_1.getMultiAgentRun)(run, input.multiAgentRunId);
910
889
  if (record) {
911
890
  record.blackboardId = blackboardId;
912
- record.topicIds = unique([...(record.topicIds || []), ...topicIds]);
891
+ record.topicIds = (0, util_1.unique)([...(record.topicIds || []), ...topicIds]);
913
892
  record.links.blackboardId = blackboardId;
914
- record.links.blackboardTopicIds = unique([...(record.links.blackboardTopicIds || []), ...topicIds]);
893
+ record.links.blackboardTopicIds = (0, util_1.unique)([...(record.links.blackboardTopicIds || []), ...topicIds]);
915
894
  }
916
895
  }
917
896
  if (groupId) {
918
897
  const record = (0, multi_agent_1.getAgentGroup)(run, groupId);
919
898
  if (record) {
920
899
  record.blackboardId = blackboardId;
921
- record.topicIds = unique([...(record.topicIds || []), ...topicIds]);
900
+ record.topicIds = (0, util_1.unique)([...(record.topicIds || []), ...topicIds]);
922
901
  }
923
902
  }
924
903
  if (roleId) {
925
904
  const record = (0, multi_agent_1.getAgentRole)(run, roleId);
926
905
  if (record) {
927
906
  record.blackboardId = blackboardId;
928
- record.topicIds = unique([...(record.topicIds || []), ...topicIds]);
907
+ record.topicIds = (0, util_1.unique)([...(record.topicIds || []), ...topicIds]);
929
908
  }
930
909
  }
931
910
  if (membershipId) {
932
911
  const record = (0, multi_agent_1.getAgentMembership)(run, membershipId);
933
912
  if (record) {
934
913
  record.blackboardId = blackboardId;
935
- record.topicIds = unique([...(record.topicIds || []), ...topicIds]);
914
+ record.topicIds = (0, util_1.unique)([...(record.topicIds || []), ...topicIds]);
936
915
  }
937
916
  }
938
917
  }
@@ -960,7 +939,7 @@ function requireArtifactRefs(run, ids) {
960
939
  if (!state.artifacts.some((artifact) => artifact.id === id))
961
940
  throw new Error(`Unknown BlackboardArtifactRef id: ${id}`);
962
941
  }
963
- return unique(ids);
942
+ return (0, util_1.unique)(ids);
964
943
  }
965
944
  function requireMessages(run, ids) {
966
945
  const state = ensureBlackboardState(run);
@@ -968,7 +947,7 @@ function requireMessages(run, ids) {
968
947
  if (!state.messages.some((message) => message.id === id))
969
948
  throw new Error(`Unknown BlackboardMessage id: ${id}`);
970
949
  }
971
- return unique(ids);
950
+ return (0, util_1.unique)(ids);
972
951
  }
973
952
  function appendBlackboardNode(run, kind, id, status, label, artifactPath, parents = []) {
974
953
  const nodeId = kind === "blackboard"
@@ -988,67 +967,6 @@ function appendBlackboardNode(run, kind, id, status, label, artifactPath, parent
988
967
  metadata: { id, label }
989
968
  }));
990
969
  }
991
- function statusToNodeStatus(status) {
992
- switch (status) {
993
- case "active":
994
- case "open":
995
- return "running";
996
- case "resolved":
997
- case "superseded":
998
- return "completed";
999
- case "conflicting":
1000
- return "blocked";
1001
- case "rejected":
1002
- return "rejected";
1003
- default:
1004
- return "completed";
1005
- }
1006
- }
1007
- function decisionStatus(outcome) {
1008
- if (outcome === "conflicting" || outcome === "blocked")
1009
- return "conflicting";
1010
- if (outcome === "rejected")
1011
- return "rejected";
1012
- if (outcome === "superseded")
1013
- return "superseded";
1014
- return "active";
1015
- }
1016
- function auditDecision(outcome) {
1017
- if (outcome === "rejected")
1018
- return "rejected";
1019
- if (outcome === "blocked" || outcome === "conflicting")
1020
- return "failed";
1021
- return "accepted";
1022
- }
1023
- function sourceForAuthor(author) {
1024
- if (author.kind === "runtime" || author.kind === "coordinator")
1025
- return "runtime-derived";
1026
- if (author.kind === "worker" || author.kind === "verifier")
1027
- return "cw-validated";
1028
- return "operator-recorded";
1029
- }
1030
- function boardPaths(run) {
1031
- const root = blackboardRoot(run);
1032
- return {
1033
- root,
1034
- index: node_path_1.default.join(root, "index.json"),
1035
- messages: messagesPath(run),
1036
- topicsDir: node_path_1.default.join(root, "topics"),
1037
- contextsDir: node_path_1.default.join(root, "contexts"),
1038
- artifactsDir: node_path_1.default.join(root, "artifacts"),
1039
- snapshotsDir: node_path_1.default.join(root, "snapshots"),
1040
- decisionsDir: node_path_1.default.join(root, "decisions")
1041
- };
1042
- }
1043
- function blackboardRoot(run) {
1044
- return run.paths.blackboardDir || node_path_1.default.join(run.paths.runDir, "blackboard");
1045
- }
1046
- function messagesPath(run) {
1047
- return node_path_1.default.join(blackboardRoot(run), "messages.jsonl");
1048
- }
1049
- function recordPath(run, kind, id) {
1050
- return node_path_1.default.join(blackboardRoot(run), kind, `${(0, state_1.safeFileName)(id)}.json`);
1051
- }
1052
970
  function graphSubject(run, id) {
1053
971
  const state = ensureBlackboardState(run);
1054
972
  if (state.contexts.some((entry) => entry.id === id))
@@ -1070,94 +988,3 @@ function nextAction(run, board, openQuestions, conflicts, artifacts) {
1070
988
  return `node scripts/cw.js blackboard artifact add ${run.id} --path <path> --kind <kind>`;
1071
989
  return `node scripts/cw.js blackboard snapshot ${run.id}`;
1072
990
  }
1073
- function checksumFile(file) {
1074
- return `sha256:${node_crypto_1.default.createHash("sha256").update(node_fs_1.default.readFileSync(file)).digest("hex")}`;
1075
- }
1076
- function assertUnique(items, id, label) {
1077
- if (items.some((item) => item.id === id))
1078
- throw new Error(`Duplicate ${label} id: ${id}`);
1079
- }
1080
- function assertNoRecordPathCollisions(label, records) {
1081
- const seen = new Map();
1082
- for (const record of records) {
1083
- const safe = (0, state_1.safeFileName)(record.id);
1084
- const existing = seen.get(safe);
1085
- if (existing && existing !== record.id) {
1086
- throw new Error(`${label} ids ${existing} and ${record.id} collide on safe file name ${safe}`);
1087
- }
1088
- seen.set(safe, record.id);
1089
- }
1090
- }
1091
- function indexRow(record) {
1092
- return { id: record.id, blackboardId: record.blackboardId, topicId: record.topicId, status: record.status, updatedAt: record.updatedAt };
1093
- }
1094
- function compareRecords(left, right) {
1095
- return left.createdAt.localeCompare(right.createdAt) || left.id.localeCompare(right.id);
1096
- }
1097
- function uniqueEdges(edges) {
1098
- const seen = new Set();
1099
- const result = [];
1100
- for (const edge of edges) {
1101
- const key = `${edge.from}\0${edge.to}\0${edge.label || ""}`;
1102
- if (seen.has(key))
1103
- continue;
1104
- seen.add(key);
1105
- result.push(edge);
1106
- }
1107
- return result;
1108
- }
1109
- function createId(prefix) {
1110
- const stamp = new Date().toISOString().replace(/[-:]/g, "").replace(/\..+/, "Z");
1111
- return `${prefix}-${stamp}-${Math.random().toString(36).slice(2, 8)}`;
1112
- }
1113
- function touch(record) {
1114
- record.updatedAt = timestamp();
1115
- return record;
1116
- }
1117
- function timestamp() {
1118
- return new Date().toISOString();
1119
- }
1120
- function unique(values) {
1121
- return Array.from(new Set(values.filter(Boolean))).sort();
1122
- }
1123
- function sortTags(values) {
1124
- return unique(values || []);
1125
- }
1126
- function truncate(value) {
1127
- return value.length > 64 ? `${value.slice(0, 61)}...` : value;
1128
- }
1129
- function compact(value) {
1130
- return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined && (!Array.isArray(entry) || entry.length > 0)));
1131
- }
1132
- // Recursive secret redaction (v0.1.40 self-audit P3): the previous scrub only
1133
- // inspected TOP-LEVEL keys, so a secret nested under an allowed key
1134
- // (e.g. `metadata.config.token`) leaked into the recorded coordinator decision.
1135
- // Now we recurse into nested objects and arrays so a secret-named key at any depth
1136
- // is dropped and an obvious credential value is redacted.
1137
- const SECRET_KEY_RE = /secret|token|password|credential|authorization|api[_-]?key|env/i;
1138
- const SECRET_VALUE_RE = /secret|token|password|credential/i;
1139
- function scrubValue(value) {
1140
- if (Array.isArray(value))
1141
- return value.map(scrubValue);
1142
- if (value && typeof value === "object")
1143
- return scrub(value);
1144
- if (typeof value === "string" && SECRET_VALUE_RE.test(value))
1145
- return "[redacted]";
1146
- return value;
1147
- }
1148
- function scrub(value) {
1149
- if (!value)
1150
- return undefined;
1151
- const result = {};
1152
- for (const [key, entry] of Object.entries(value)) {
1153
- if (entry === undefined)
1154
- continue;
1155
- if (SECRET_KEY_RE.test(key)) {
1156
- result[key] = "[redacted]";
1157
- }
1158
- else {
1159
- result[key] = scrubValue(entry);
1160
- }
1161
- }
1162
- return Object.keys(result).length ? result : undefined;
1163
- }