@cohortapp/agent-sdk 2.16.0 → 2.18.4

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 (529) hide show
  1. package/.claude/settings.json +18 -0
  2. package/.env.example +23 -7
  3. package/README.md +1 -0
  4. package/bin/maestro.mjs +62 -0
  5. package/docs/guides/billing-console-keys.md +60 -0
  6. package/docs/guides/front-door-session.md +54 -9
  7. package/docs/guides/mac-mini.md +20 -25
  8. package/docs/guides/poller-daemon-setup.md +4 -1
  9. package/docs/guides/setup-wizard.md +1 -1
  10. package/docs/runbooks/fleet-rollout.md +156 -0
  11. package/docs/runbooks/mac-mini-bootstrap.md +12 -14
  12. package/lib/action-executor.js +19 -3
  13. package/lib/budget-guard.mjs +279 -3
  14. package/lib/channels/base-adapter.mjs +3 -1
  15. package/lib/channels/contract.mjs +2 -1
  16. package/lib/channels/inbox-item.mjs +8 -0
  17. package/lib/claude-bin.mjs +5 -6
  18. package/lib/cli/doctor-checks.mjs +141 -10
  19. package/lib/cli/global-setup-extras.mjs +5 -1
  20. package/lib/cli/inbox.mjs +100 -15
  21. package/lib/cli/seat-auth.mjs +463 -0
  22. package/lib/cli/session.mjs +80 -12
  23. package/lib/collective/capture.mjs +8 -6
  24. package/lib/collective/global-config.mjs +63 -1
  25. package/lib/collective/presence.mjs +142 -5
  26. package/lib/comms/send-gate.mjs +559 -1
  27. package/lib/context/budget.mjs +327 -0
  28. package/lib/context/history-scope.mjs +138 -0
  29. package/lib/diagnostics/alerts.mjs +49 -0
  30. package/lib/diagnostics/cadence-output-freshness.mjs +288 -0
  31. package/lib/engine/agents/definitions.mjs +343 -0
  32. package/lib/engine/agents/persist.mjs +275 -0
  33. package/lib/engine/agents/runtime.mjs +748 -0
  34. package/lib/engine/agents/usage.mjs +95 -0
  35. package/lib/engine/auth-status.mjs +139 -0
  36. package/lib/engine/budget.mjs +194 -0
  37. package/lib/engine/cli.mjs +1204 -0
  38. package/lib/engine/commands/index.mjs +269 -0
  39. package/lib/engine/context/budget.mjs +219 -0
  40. package/lib/engine/context/cache.mjs +125 -0
  41. package/lib/engine/context/child-env.mjs +215 -0
  42. package/lib/engine/context/compaction.mjs +342 -0
  43. package/lib/engine/context/images.mjs +90 -0
  44. package/lib/engine/context/instructions.mjs +327 -0
  45. package/lib/engine/context/lazy-instructions.mjs +169 -0
  46. package/lib/engine/context/manager.mjs +182 -0
  47. package/lib/engine/context/real-path.mjs +91 -0
  48. package/lib/engine/context/secret-values.mjs +163 -0
  49. package/lib/engine/context/settings.mjs +274 -0
  50. package/lib/engine/context/stream-input.mjs +159 -0
  51. package/lib/engine/guard.mjs +152 -0
  52. package/lib/engine/hooks.mjs +713 -0
  53. package/lib/engine/loop.mjs +560 -0
  54. package/lib/engine/mcp/client.mjs +254 -0
  55. package/lib/engine/mcp/config.mjs +301 -0
  56. package/lib/engine/mcp/http.mjs +201 -0
  57. package/lib/engine/mcp/index.mjs +146 -0
  58. package/lib/engine/mcp/jsonrpc.mjs +147 -0
  59. package/lib/engine/mcp/naming.mjs +66 -0
  60. package/lib/engine/mcp/resources.mjs +89 -0
  61. package/lib/engine/mcp/results.mjs +133 -0
  62. package/lib/engine/mcp/stdio.mjs +137 -0
  63. package/lib/engine/mcp/supervisor.mjs +116 -0
  64. package/lib/engine/messages.mjs +104 -0
  65. package/lib/engine/output/json.mjs +164 -0
  66. package/lib/engine/output/stream-json.mjs +266 -0
  67. package/lib/engine/permissions.mjs +845 -0
  68. package/lib/engine/process-identity.mjs +164 -0
  69. package/lib/engine/process-tree.mjs +551 -0
  70. package/lib/engine/prompt.mjs +60 -0
  71. package/lib/engine/session/store.mjs +299 -0
  72. package/lib/engine/session-runtime/args.mjs +97 -0
  73. package/lib/engine/session-runtime/host.mjs +143 -0
  74. package/lib/engine/session-runtime/inbox.mjs +122 -0
  75. package/lib/engine/session-runtime/notifications.mjs +129 -0
  76. package/lib/engine/session-runtime/registry.mjs +328 -0
  77. package/lib/engine/session-runtime/runner.mjs +344 -0
  78. package/lib/engine/session-runtime/socket.mjs +212 -0
  79. package/lib/engine/session-runtime/wakeup.mjs +115 -0
  80. package/lib/engine/skills/index.mjs +321 -0
  81. package/lib/engine/tools/bash-background.mjs +533 -0
  82. package/lib/engine/tools/bash.mjs +216 -0
  83. package/lib/engine/tools/edit.mjs +97 -0
  84. package/lib/engine/tools/glob.mjs +81 -0
  85. package/lib/engine/tools/grep.mjs +224 -0
  86. package/lib/engine/tools/index.mjs +84 -0
  87. package/lib/engine/tools/list-agents.mjs +32 -0
  88. package/lib/engine/tools/ls.mjs +127 -0
  89. package/lib/engine/tools/monitor.mjs +82 -0
  90. package/lib/engine/tools/notebook-edit.mjs +218 -0
  91. package/lib/engine/tools/read.mjs +103 -0
  92. package/lib/engine/tools/schedule-wakeup.mjs +45 -0
  93. package/lib/engine/tools/schema.mjs +144 -0
  94. package/lib/engine/tools/send-message.mjs +77 -0
  95. package/lib/engine/tools/session.mjs +70 -0
  96. package/lib/engine/tools/todo.mjs +144 -0
  97. package/lib/engine/tools/toolsearch.mjs +217 -0
  98. package/lib/engine/tools/walk.mjs +193 -0
  99. package/lib/engine/tools/web-switch.mjs +31 -0
  100. package/lib/engine/tools/webfetch-html.mjs +387 -0
  101. package/lib/engine/tools/webfetch-net.mjs +340 -0
  102. package/lib/engine/tools/webfetch.mjs +198 -0
  103. package/lib/engine/tools/websearch.mjs +91 -0
  104. package/lib/engine/tools/workflow.mjs +95 -0
  105. package/lib/engine/tools/write.mjs +76 -0
  106. package/lib/engine/tui/line-editor.mjs +137 -0
  107. package/lib/engine/tui/render.mjs +86 -0
  108. package/lib/engine/tui/tui.mjs +274 -0
  109. package/lib/engine/wire/anthropic-messages.mjs +263 -0
  110. package/lib/engine/wire/effort.mjs +36 -0
  111. package/lib/engine/wire/errors.mjs +496 -0
  112. package/lib/engine/wire/http.mjs +441 -0
  113. package/lib/engine/wire/index.mjs +76 -0
  114. package/lib/engine/wire/openai-chat.mjs +332 -0
  115. package/lib/engine/wire/prompt-cache.mjs +79 -0
  116. package/lib/engine/wire/search.mjs +140 -0
  117. package/lib/engine/wire/sse.mjs +114 -0
  118. package/lib/engine/wire/stall.mjs +349 -0
  119. package/lib/engine/wire/token-provider.mjs +175 -0
  120. package/lib/engine/wire/usage.mjs +192 -0
  121. package/lib/engine/workflow/host.mjs +524 -0
  122. package/lib/engine/workflow/journal.mjs +188 -0
  123. package/lib/engine/workflow/json-schema.mjs +171 -0
  124. package/lib/engine/workflow/meta.mjs +329 -0
  125. package/lib/engine/workflow/notifications.mjs +52 -0
  126. package/lib/engine/workflow/runtime.mjs +447 -0
  127. package/lib/engine/workflow/sandbox.mjs +534 -0
  128. package/lib/engine/workflow/worker.mjs +141 -0
  129. package/lib/engine/workflow/worktree.mjs +74 -0
  130. package/lib/execution/disposition.mjs +1 -1
  131. package/lib/execution/intake.mjs +10 -0
  132. package/lib/execution/surface-policy.mjs +15 -0
  133. package/lib/learning/curator.mjs +8 -6
  134. package/lib/learning/reflect.mjs +8 -6
  135. package/lib/model-router/catalog/cohort.yaml +137 -0
  136. package/lib/model-router/catalog.mjs +118 -1
  137. package/lib/model-router/economics.mjs +9 -0
  138. package/lib/model-router/failover.mjs +67 -16
  139. package/lib/model-router/llm-task.mjs +39 -3
  140. package/lib/model-router/resolve.mjs +95 -3
  141. package/lib/model-router/spawn.mjs +46 -47
  142. package/lib/model-router/taxonomy.mjs +126 -4
  143. package/lib/org/cost-sync.mjs +141 -11
  144. package/lib/org/inbound/broadcast.mjs +289 -0
  145. package/lib/org/inbound/collective.mjs +375 -0
  146. package/lib/org/inbound/directedness.mjs +96 -8
  147. package/lib/org/inbound/facts.mjs +82 -4
  148. package/lib/org/inbound/hydrate.mjs +555 -51
  149. package/lib/org/inbound/project.mjs +22 -0
  150. package/lib/org/inbound/surfaces.mjs +14 -0
  151. package/lib/org/llm-token.mjs +879 -0
  152. package/lib/org/mesh.mjs +61 -0
  153. package/lib/org/messaging.mjs +3 -1
  154. package/lib/org/protocol.checksum +1 -1
  155. package/lib/org/protocol.mjs +15 -0
  156. package/lib/org/quota.mjs +520 -0
  157. package/lib/org/tool-surface.mjs +104 -16
  158. package/lib/org/ui-parity.mjs +16 -1
  159. package/lib/org/work-ledger.mjs +37 -6
  160. package/lib/rate-guard.mjs +114 -1
  161. package/lib/resource-governor.mjs +41 -6
  162. package/lib/runtime/adapter.mjs +823 -0
  163. package/lib/runtime/child-env.mjs +191 -0
  164. package/lib/runtime/legacy-shell-guard.mjs +97 -0
  165. package/lib/runtime/seat-engine.mjs +162 -0
  166. package/lib/session/ask-ledger.mjs +271 -0
  167. package/lib/session/current-work.mjs +676 -0
  168. package/lib/session/feed-core.mjs +40 -3
  169. package/lib/session/launch-args.mjs +56 -4
  170. package/lib/session/status-summary.mjs +26 -9
  171. package/lib/session/upgrade-notice.mjs +42 -0
  172. package/lib/setup/claude-probe.mjs +117 -13
  173. package/lib/setup/enrich.mjs +13 -10
  174. package/lib/setup/sections/model.mjs +39 -13
  175. package/lib/telemetry/collect.mjs +208 -9
  176. package/lib/upgrade/ignored-drift.mjs +105 -0
  177. package/lib/voice/post-call-brief.mjs +30 -17
  178. package/package.json +15 -3
  179. package/plugins/maestro-skills/skills/board-work.md +5 -0
  180. package/plugins/maestro-skills/skills/inbound-triage.md +56 -15
  181. package/plugins/maestro-skills/skills/main-session.md +18 -7
  182. package/scripts/ci/check-tarball-fidelity.mjs +126 -2
  183. package/scripts/ci/run-tests.mjs +47 -19
  184. package/scripts/cohort-llm/api-key-helper.mjs +92 -0
  185. package/scripts/collective/hook-runner.mjs +29 -2
  186. package/scripts/continuous-monitor.sh +13 -0
  187. package/scripts/cost/track-claude-usage.mjs +15 -0
  188. package/scripts/daemon/agent-daemon.mjs +408 -20
  189. package/scripts/daemon/assurance.mjs +48 -12
  190. package/scripts/daemon/cadence-consumer.mjs +218 -68
  191. package/scripts/daemon/cadence-handlers.mjs +73 -4
  192. package/scripts/daemon/classifier.mjs +75 -26
  193. package/scripts/daemon/context-compiler.mjs +104 -59
  194. package/scripts/daemon/deliver.mjs +30 -1
  195. package/scripts/daemon/dispatcher.mjs +804 -157
  196. package/scripts/daemon/health.mjs +14 -1
  197. package/scripts/daemon/lib/session-router.mjs +310 -42
  198. package/scripts/daemon/maestro-daemon.mjs +11 -0
  199. package/scripts/daemon/prompt-builder.mjs +121 -12
  200. package/scripts/daemon/responder.mjs +315 -146
  201. package/scripts/daemon/sdk-version.mjs +98 -16
  202. package/scripts/eval/probe-gateway.mjs +635 -0
  203. package/scripts/eval/replay/extract.mjs +270 -0
  204. package/scripts/eval/replay/grade.mjs +260 -0
  205. package/scripts/eval/replay/lib/config.mjs +50 -0
  206. package/scripts/eval/replay/lib/effects.mjs +65 -0
  207. package/scripts/eval/replay/lib/fixture.mjs +188 -0
  208. package/scripts/eval/replay/lib/judge.mjs +72 -0
  209. package/scripts/eval/replay/lib/redact.mjs +136 -0
  210. package/scripts/eval/replay/lib/sandbox.mjs +170 -0
  211. package/scripts/eval/replay/lib/schema-check.mjs +63 -0
  212. package/scripts/eval/replay/lib/transcript.mjs +76 -0
  213. package/scripts/eval/replay/mcp-replay-stub.mjs +101 -0
  214. package/scripts/eval/replay/report.mjs +185 -0
  215. package/scripts/eval/replay/run.mjs +404 -0
  216. package/scripts/fleet/rollout.mjs +1094 -0
  217. package/scripts/hooks/pre-send-audit.sh +36 -245
  218. package/scripts/hooks/pre-write-yaml-validate.mjs +275 -0
  219. package/scripts/hooks/validate-state-yaml.sh +190 -0
  220. package/scripts/huddle/huddle-llm.mjs +361 -0
  221. package/scripts/huddle/huddle-server.mjs +46 -121
  222. package/scripts/local-triggers/autoupdate.sh +448 -78
  223. package/scripts/local-triggers/run-trigger.sh +13 -0
  224. package/scripts/maintenance/pin-integrity.mjs +364 -0
  225. package/scripts/poll-slack-events.sh +41 -9
  226. package/scripts/poller/slack-socket-mode.mjs +28 -3
  227. package/scripts/session/supervisor.mjs +80 -13
  228. package/scripts/spawn-session.sh +13 -0
  229. package/bin/maestro.test.mjs +0 -1574
  230. package/lib/action-executor.test.mjs +0 -871
  231. package/lib/archetype.test.mjs +0 -132
  232. package/lib/assurance/plan-note.test.mjs +0 -234
  233. package/lib/assurance/room-budget.test.mjs +0 -486
  234. package/lib/assurance/tier.test.mjs +0 -174
  235. package/lib/autonomy.test.mjs +0 -66
  236. package/lib/backlog.test.mjs +0 -302
  237. package/lib/backup/policy.test.mjs +0 -305
  238. package/lib/budget-escalate.test.mjs +0 -232
  239. package/lib/budget-guard.envelope.test.mjs +0 -476
  240. package/lib/budget-guard.test.mjs +0 -427
  241. package/lib/cadence-bus-requeue.test.mjs +0 -83
  242. package/lib/cadence-bus-schedule.test.mjs +0 -194
  243. package/lib/cadence-bus.test.mjs +0 -720
  244. package/lib/cadences.test.mjs +0 -230
  245. package/lib/capability/inventory.test.mjs +0 -232
  246. package/lib/capability.test.mjs +0 -78
  247. package/lib/channels/base-adapter.test.mjs +0 -590
  248. package/lib/channels/channels.test.mjs +0 -371
  249. package/lib/channels/contract.test.mjs +0 -162
  250. package/lib/channels/inbox-item.test.mjs +0 -368
  251. package/lib/channels/orgmail/adapter.test.mjs +0 -448
  252. package/lib/channels/pairing.test.mjs +0 -270
  253. package/lib/channels/repeat-suppressor.test.mjs +0 -134
  254. package/lib/channels/slack-adapter.test.mjs +0 -212
  255. package/lib/channels/telegram-adapter.test.mjs +0 -306
  256. package/lib/channels/voice/adapter.test.mjs +0 -278
  257. package/lib/channels/whatsapp/adapter-baileys.test.mjs +0 -359
  258. package/lib/channels/whatsapp/baileys-typing.test.mjs +0 -154
  259. package/lib/charter.test.mjs +0 -89
  260. package/lib/claude-bin.test.mjs +0 -131
  261. package/lib/cli/board.test.mjs +0 -227
  262. package/lib/cli/design.test.mjs +0 -270
  263. package/lib/cli/doctor-checks.test.mjs +0 -336
  264. package/lib/cli/global-setup-extras.test.mjs +0 -462
  265. package/lib/cli/inbox.test.mjs +0 -230
  266. package/lib/cli/session-ack.test.mjs +0 -63
  267. package/lib/cli/session.test.mjs +0 -613
  268. package/lib/collective/capture.test.mjs +0 -121
  269. package/lib/collective/cards.test.mjs +0 -114
  270. package/lib/collective/config.test.mjs +0 -123
  271. package/lib/collective/global-config.test.mjs +0 -220
  272. package/lib/collective/global-skills.test.mjs +0 -126
  273. package/lib/collective/presence.test.mjs +0 -95
  274. package/lib/collective/recall.test.mjs +0 -116
  275. package/lib/collective/vendor-skills.test.mjs +0 -306
  276. package/lib/comms/send-gate.test.mjs +0 -770
  277. package/lib/comms.test.mjs +0 -41
  278. package/lib/cost/ledger-row.test.mjs +0 -183
  279. package/lib/design/design-md.test.mjs +0 -318
  280. package/lib/design/fixtures/DESIGN.golden.md +0 -238
  281. package/lib/design/fixtures/PRODUCT.golden.md +0 -67
  282. package/lib/design/fixtures/foundation.json +0 -133
  283. package/lib/design/refresh-gate.test.mjs +0 -144
  284. package/lib/design/write.test.mjs +0 -241
  285. package/lib/diagnostics/alerts.test.mjs +0 -318
  286. package/lib/diagnostics/backup-freshness.test.mjs +0 -185
  287. package/lib/diagnostics/counters.test.mjs +0 -206
  288. package/lib/diagnostics/events.test.mjs +0 -290
  289. package/lib/diagnostics/otel.test.mjs +0 -196
  290. package/lib/diagnostics/trace.test.mjs +0 -251
  291. package/lib/env-compat.test.mjs +0 -104
  292. package/lib/execution/disposition.test.mjs +0 -553
  293. package/lib/execution/drive.test.mjs +0 -270
  294. package/lib/execution/effects.test.mjs +0 -344
  295. package/lib/execution/intake.test.mjs +0 -389
  296. package/lib/execution/journal.test.mjs +0 -261
  297. package/lib/execution/match.test.mjs +0 -235
  298. package/lib/execution/pipeline.test.mjs +0 -392
  299. package/lib/execution/route.test.mjs +0 -186
  300. package/lib/execution/surface-policy.test.mjs +0 -162
  301. package/lib/fs-atomic.test.mjs +0 -72
  302. package/lib/fs-ownership.test.mjs +0 -158
  303. package/lib/goals/admission.test.mjs +0 -164
  304. package/lib/goals/classify.test.mjs +0 -167
  305. package/lib/goals/collaborate.test.mjs +0 -336
  306. package/lib/goals/gaps.test.mjs +0 -284
  307. package/lib/goals/loop.test.mjs +0 -845
  308. package/lib/hooks/bus.test.mjs +0 -387
  309. package/lib/identity/persona.test.mjs +0 -142
  310. package/lib/kpi-sensors.test.mjs +0 -278
  311. package/lib/kpi.test.mjs +0 -244
  312. package/lib/learning/config.test.mjs +0 -75
  313. package/lib/learning/counters.test.mjs +0 -69
  314. package/lib/learning/curator-consolidate.test.mjs +0 -238
  315. package/lib/learning/curator.test.mjs +0 -106
  316. package/lib/learning/reflect.test.mjs +0 -0
  317. package/lib/learning/session-index.test.mjs +0 -125
  318. package/lib/learning/skill-writer.test.mjs +0 -210
  319. package/lib/mandate/audit.test.mjs +0 -195
  320. package/lib/mandate/contract.test.mjs +0 -185
  321. package/lib/mandate/derive.test.mjs +0 -274
  322. package/lib/mandate/model.test.mjs +0 -164
  323. package/lib/mandate/refresh.test.mjs +0 -389
  324. package/lib/mcp/server.test.mjs +0 -426
  325. package/lib/model-router/auth-profiles.test.mjs +0 -580
  326. package/lib/model-router/catalog.test.mjs +0 -385
  327. package/lib/model-router/economics.test.mjs +0 -438
  328. package/lib/model-router/failover.test.mjs +0 -439
  329. package/lib/model-router/health.test.mjs +0 -338
  330. package/lib/model-router/integration-coverage.test.mjs +0 -831
  331. package/lib/model-router/integration.test.mjs +0 -564
  332. package/lib/model-router/ledger.test.mjs +0 -415
  333. package/lib/model-router/llm-task.test.mjs +0 -392
  334. package/lib/model-router/org-credentials.test.mjs +0 -265
  335. package/lib/model-router/pricing-refresh.test.mjs +0 -286
  336. package/lib/model-router/reconcile.test.mjs +0 -316
  337. package/lib/model-router/repair.test.mjs +0 -180
  338. package/lib/model-router/spawn.test.mjs +0 -446
  339. package/lib/model-router/taxonomy.test.mjs +0 -410
  340. package/lib/model-router.test.mjs +0 -1207
  341. package/lib/org/activity.test.mjs +0 -134
  342. package/lib/org/approvals.test.mjs +0 -216
  343. package/lib/org/awareness.test.mjs +0 -159
  344. package/lib/org/board-mine-cache.test.mjs +0 -53
  345. package/lib/org/board.test.mjs +0 -187
  346. package/lib/org/bootstrap-context.test.mjs +0 -153
  347. package/lib/org/client.test.mjs +0 -1206
  348. package/lib/org/cohort-client.test.mjs +0 -126
  349. package/lib/org/cost-sync.test.mjs +0 -153
  350. package/lib/org/doctor.test.mjs +0 -346
  351. package/lib/org/engagement-ledger.test.mjs +0 -112
  352. package/lib/org/engagement.test.mjs +0 -739
  353. package/lib/org/handoff.test.mjs +0 -269
  354. package/lib/org/inbound/directedness.test.mjs +0 -668
  355. package/lib/org/inbound/facts.test.mjs +0 -471
  356. package/lib/org/inbound/hydrate.test.mjs +0 -453
  357. package/lib/org/inbound/index.test.mjs +0 -429
  358. package/lib/org/inbound/project.test.mjs +0 -287
  359. package/lib/org/integration-tools.test.mjs +0 -160
  360. package/lib/org/keys.test.mjs +0 -92
  361. package/lib/org/knowledge.test.mjs +0 -326
  362. package/lib/org/leases.test.mjs +0 -235
  363. package/lib/org/mesh-directives.test.mjs +0 -110
  364. package/lib/org/mesh-integration.test.mjs +0 -127
  365. package/lib/org/mesh.test.mjs +0 -400
  366. package/lib/org/messaging.test.mjs +0 -471
  367. package/lib/org/param-contract.test.mjs +0 -477
  368. package/lib/org/policy.test.mjs +0 -237
  369. package/lib/org/protocol.checksum.test.mjs +0 -90
  370. package/lib/org/protocol.test.mjs +0 -323
  371. package/lib/org/push.test.mjs +0 -792
  372. package/lib/org/registry.test.mjs +0 -100
  373. package/lib/org/resource-tools.test.mjs +0 -361
  374. package/lib/org/tool-access.test.mjs +0 -144
  375. package/lib/org/tool-surface-integration.test.mjs +0 -120
  376. package/lib/org/tool-surface.test.mjs +0 -1268
  377. package/lib/org/typing.test.mjs +0 -291
  378. package/lib/org/ui-parity.test.mjs +0 -560
  379. package/lib/org/verify.test.mjs +0 -194
  380. package/lib/org/work-ledger.test.mjs +0 -273
  381. package/lib/plan/adoption-e2e.test.mjs +0 -366
  382. package/lib/plan/budget-enforcement.test.mjs +0 -400
  383. package/lib/plan/compile.test.mjs +0 -382
  384. package/lib/plan/emit.test.mjs +0 -269
  385. package/lib/plan/explain.test.mjs +0 -188
  386. package/lib/prompts/parallelism.test.mjs +0 -177
  387. package/lib/rag/rag.test.mjs +0 -505
  388. package/lib/rate-guard.test.mjs +0 -272
  389. package/lib/reactive-gate.test.mjs +0 -57
  390. package/lib/render.test.mjs +0 -68
  391. package/lib/resource-governor.test.mjs +0 -488
  392. package/lib/scheduling/dynamic-jobs.test.mjs +0 -344
  393. package/lib/scheduling/jitter.test.mjs +0 -140
  394. package/lib/secrets/broker.test.mjs +0 -280
  395. package/lib/secrets/providers.test.mjs +0 -274
  396. package/lib/security/audit-engine.test.mjs +0 -424
  397. package/lib/security/coerce-args.test.mjs +0 -281
  398. package/lib/security/dangerous-tools.test.mjs +0 -68
  399. package/lib/security/external-content.test.mjs +0 -84
  400. package/lib/security/redact.test.mjs +0 -441
  401. package/lib/security/secret-equal.test.mjs +0 -55
  402. package/lib/session/config.test.mjs +0 -92
  403. package/lib/session/feed-core.test.mjs +0 -198
  404. package/lib/session/first-run.test.mjs +0 -121
  405. package/lib/session/frontdoor.test.mjs +0 -205
  406. package/lib/session/handoffs.test.mjs +0 -183
  407. package/lib/session/identity.test.mjs +0 -180
  408. package/lib/session/inbox-claims.test.mjs +0 -286
  409. package/lib/session/launch-args.test.mjs +0 -157
  410. package/lib/session/liveness.test.mjs +0 -100
  411. package/lib/session/status-summary.test.mjs +0 -118
  412. package/lib/session-permissions.test.mjs +0 -120
  413. package/lib/setup/claude-probe.test.mjs +0 -187
  414. package/lib/setup/completeness.test.mjs +0 -110
  415. package/lib/setup/context-pack.test.mjs +0 -89
  416. package/lib/setup/enrich.test.mjs +0 -115
  417. package/lib/setup/enroll-from-cohort.test.mjs +0 -300
  418. package/lib/setup/integration.test.mjs +0 -162
  419. package/lib/setup/io.test.mjs +0 -77
  420. package/lib/setup/runner.test.mjs +0 -132
  421. package/lib/setup/sections/identity.test.mjs +0 -234
  422. package/lib/setup/sections/inventory.test.mjs +0 -198
  423. package/lib/setup/sections/learning.test.mjs +0 -81
  424. package/lib/setup/sections/mandate.test.mjs +0 -388
  425. package/lib/setup/sections/messaging.test.mjs +0 -127
  426. package/lib/setup/sections/model.test.mjs +0 -240
  427. package/lib/setup/sections/org.test.mjs +0 -346
  428. package/lib/setup/sections/orgmail.test.mjs +0 -118
  429. package/lib/setup/sections/recovery.test.mjs +0 -98
  430. package/lib/setup/sections/subagents.test.mjs +0 -429
  431. package/lib/setup/sections/verify.test.mjs +0 -175
  432. package/lib/setup/sot.test.mjs +0 -81
  433. package/lib/setup/state.test.mjs +0 -115
  434. package/lib/singleton.test.mjs +0 -151
  435. package/lib/subagents/cli.test.mjs +0 -389
  436. package/lib/subagents/client.test.mjs +0 -309
  437. package/lib/subagents/gap.test.mjs +0 -234
  438. package/lib/subagents/lock.test.mjs +0 -248
  439. package/lib/subagents/manifest.test.mjs +0 -175
  440. package/lib/subagents/refs.test.mjs +0 -204
  441. package/lib/subagents/resolve.test.mjs +0 -422
  442. package/lib/subagents/schema.test.mjs +0 -328
  443. package/lib/telemetry/alerts.test.mjs +0 -109
  444. package/lib/telemetry/collect.test.mjs +0 -1274
  445. package/lib/tool-definitions-integration.test.mjs +0 -83
  446. package/lib/tool-definitions.test.mjs +0 -437
  447. package/lib/upgrade/global-refresh.test.mjs +0 -65
  448. package/lib/upgrade/launchd-reconcile.test.mjs +0 -272
  449. package/lib/upgrade/post-steps.test.mjs +0 -200
  450. package/lib/upgrade/verify.test.mjs +0 -164
  451. package/lib/util/fetch-timeout.test.mjs +0 -202
  452. package/lib/util/reconnect.test.mjs +0 -369
  453. package/lib/util/unhandled.test.mjs +0 -216
  454. package/lib/voice/outbound.test.mjs +0 -69
  455. package/lib/voice/session-rotation.test.mjs +0 -114
  456. package/lib/voice/stt.test.mjs +0 -226
  457. package/lib/voice/voice.test.mjs +0 -990
  458. package/scripts/cadence/enqueue-cadence-tick.test.mjs +0 -187
  459. package/scripts/ci/check-docs-accuracy.test.mjs +0 -409
  460. package/scripts/ci/check-durable-write-seam.test.mjs +0 -90
  461. package/scripts/ci/check-no-build-artifacts.test.mjs +0 -71
  462. package/scripts/ci/check-no-residual-identity.test.mjs +0 -202
  463. package/scripts/ci/check-skill-packs.test.mjs +0 -495
  464. package/scripts/ci/check-subagent-frontmatter.test.mjs +0 -124
  465. package/scripts/ci/check.test.mjs +0 -194
  466. package/scripts/ci/conformance-org-api.test.mjs +0 -425
  467. package/scripts/cloud-relay/voice/relay-identity.test.mjs +0 -96
  468. package/scripts/collective/hook-runner.test.mjs +0 -173
  469. package/scripts/cost/fleet-digest.test.mjs +0 -207
  470. package/scripts/cost/track-claude-usage-pricing.test.mjs +0 -183
  471. package/scripts/cost/track-claude-usage.test.mjs +0 -148
  472. package/scripts/daemon/agent-daemon-board-mine.test.mjs +0 -96
  473. package/scripts/daemon/agent-daemon-design.test.mjs +0 -238
  474. package/scripts/daemon/agent-daemon-frontdoor.test.mjs +0 -60
  475. package/scripts/daemon/agent-daemon.test.mjs +0 -995
  476. package/scripts/daemon/assurance-e2e.test.mjs +0 -613
  477. package/scripts/daemon/assurance.test.mjs +0 -1791
  478. package/scripts/daemon/board-mirror.test.mjs +0 -165
  479. package/scripts/daemon/cadence-consumer-frontdoor.test.mjs +0 -393
  480. package/scripts/daemon/cadence-consumer-governance.test.mjs +0 -276
  481. package/scripts/daemon/cadence-consumer.test.mjs +0 -776
  482. package/scripts/daemon/cadence-handlers.test.mjs +0 -837
  483. package/scripts/daemon/classifier-identity.test.mjs +0 -137
  484. package/scripts/daemon/classifier.test.mjs +0 -266
  485. package/scripts/daemon/classify-kind.test.mjs +0 -40
  486. package/scripts/daemon/context-compiler.test.mjs +0 -300
  487. package/scripts/daemon/deliver.test.mjs +0 -564
  488. package/scripts/daemon/dispatcher-cooldown.test.mjs +0 -122
  489. package/scripts/daemon/dispatcher-governance.test.mjs +0 -1013
  490. package/scripts/daemon/dispatcher-resume.test.mjs +0 -166
  491. package/scripts/daemon/execution-ladder.test.mjs +0 -470
  492. package/scripts/daemon/goal-steward-cadence.test.mjs +0 -312
  493. package/scripts/daemon/inbox-deferral-session.test.mjs +0 -49
  494. package/scripts/daemon/inbox-deferral.test.mjs +0 -336
  495. package/scripts/daemon/inbox-wake.test.mjs +0 -199
  496. package/scripts/daemon/integration.test.mjs +0 -149
  497. package/scripts/daemon/lib/self-echo.test.mjs +0 -153
  498. package/scripts/daemon/lib/session-router.test.mjs +0 -295
  499. package/scripts/daemon/prompt-builder-preamble.test.mjs +0 -210
  500. package/scripts/daemon/prompt-builder.test.mjs +0 -344
  501. package/scripts/daemon/responder-cost.test.mjs +0 -68
  502. package/scripts/daemon/responder-history.test.mjs +0 -185
  503. package/scripts/daemon/sdk-version.test.mjs +0 -31
  504. package/scripts/daemon/session-lock.test.mjs +0 -252
  505. package/scripts/daemon/session-outcomes.test.mjs +0 -533
  506. package/scripts/daemon/typing-registry.test.mjs +0 -102
  507. package/scripts/hooks/pre-send-audit.test.mjs +0 -354
  508. package/scripts/huddle/huddle-prompt.test.mjs +0 -176
  509. package/scripts/local-triggers/autoupdate.test.mjs +0 -518
  510. package/scripts/local-triggers/generate-plists.test.mjs +0 -456
  511. package/scripts/media-generation/brand-clause.test.mjs +0 -135
  512. package/scripts/org/send-orgmail.first-contact.test.mjs +0 -102
  513. package/scripts/poller/inbox-privilege-injection.test.mjs +0 -167
  514. package/scripts/poller/inbox-scan-poller.test.mjs +0 -295
  515. package/scripts/poller/lib/cloud-relay-dedup.test.mjs +0 -133
  516. package/scripts/poller/slack-socket-mode.test.mjs +0 -805
  517. package/scripts/poller-launchd/install.test.mjs +0 -243
  518. package/scripts/restore-from-backup.test.mjs +0 -181
  519. package/scripts/session/feed.test.mjs +0 -196
  520. package/scripts/session/supervisor-sh.test.mjs +0 -218
  521. package/scripts/session/supervisor.test.mjs +0 -482
  522. package/scripts/setup/configure-macos.test.mjs +0 -306
  523. package/scripts/setup/gen-subagent-manifest.test.mjs +0 -124
  524. package/scripts/setup/generate-agent-package-json.test.mjs +0 -143
  525. package/scripts/setup/generate-capability.test.mjs +0 -134
  526. package/scripts/setup/init-agent.test.mjs +0 -370
  527. package/scripts/setup/init-skill-marketplace.test.mjs +0 -193
  528. package/scripts/vendor/sync-skill-packs.test.mjs +0 -103
  529. package/scripts/watchdog/memory-watchdog.test.mjs +0 -64
@@ -1,238 +0,0 @@
1
- ---
2
- name: "Northwind"
3
- version: "bv_01HQZ"
4
- generatedAt: "2026-09-08T12:00:00.000Z"
5
- source: "cohort · branding.getFoundation"
6
- colors:
7
- ink: "#0d0d0d"
8
- paper: "#ffffff"
9
- primary-moss: "#2d5be3"
10
- muted: "#6b7280"
11
- accent-amber: "#c9851f"
12
- line: "#e7e5e4"
13
- primary: "#2d5be3"
14
- accent: "#c9851f"
15
- success: "#177245"
16
- warning: "#c9851f"
17
- danger: "#a11d1d"
18
- neutral-100: "#f5f5f4"
19
- neutral-500: "#78716c"
20
- neutral-900: "#1c1917"
21
- colorsDark:
22
- ink: "#f5f5f4"
23
- paper: "#0b0b0c"
24
- primary-moss: "#7ea0ff"
25
- line: "#26262a"
26
- primary: "#7ea0ff"
27
- typography:
28
- display: "Outfit"
29
- body: "Inter"
30
- mono: "JetBrains Mono"
31
- heading: "Outfit"
32
- scale:
33
- display: { size: "76px", weight: 600, leading: 1.05, tracking: -0.02 }
34
- heading: { size: "38px", weight: 600, leading: 1.15, tracking: -0.01 }
35
- body: { size: "14px", weight: 400, leading: 1.5 }
36
- small: { size: "11.5px", weight: 500 }
37
- caption: { size: "11px", weight: 500, leading: 1.4, tracking: 0.04 }
38
- rounded:
39
- chip: "8px"
40
- field: "9px"
41
- card: "13px"
42
- modal: "14px"
43
- pill: "999px"
44
- spacing:
45
- xs: "4px"
46
- sm: "8px"
47
- md: "12px"
48
- lg: "16px"
49
- xl: "22px"
50
- shadow:
51
- sm: "0 1px 2px rgba(13,13,13,0.06)"
52
- md: "0 18px 50px rgba(13,13,13,0.13)"
53
- border:
54
- hairline: "1px solid #e7e5e4"
55
- strong: "1px solid #d6d3d1"
56
- components:
57
- button:
58
- background: "{colors.primary}"
59
- foreground: "{colors.paper}"
60
- radius: "{rounded.pill}"
61
- padding: "{spacing.sm} {spacing.lg}"
62
- font: "{typography.body}"
63
- card:
64
- background: "{colors.paper}"
65
- foreground: "{colors.ink}"
66
- border: "{border.hairline}"
67
- radius: "{rounded.card}"
68
- padding: "{spacing.xl}"
69
- shadow: "{shadow.md}"
70
- input:
71
- background: "{colors.paper}"
72
- border: "{border.hairline}"
73
- radius: "{rounded.field}"
74
- padding: "{spacing.sm} {spacing.md}"
75
- font: "{typography.body}"
76
- surface:
77
- background: "{colors.paper}"
78
- foreground: "{colors.ink}"
79
- muted: "{colors.muted}"
80
- radius: "{rounded.modal}"
81
- ---
82
-
83
- # Northwind — design system
84
-
85
- The frontmatter above is the token contract: it is generated from the workspace's
86
- saved brand foundation and is the source of truth for colour, type, radius and
87
- spacing. Read it before you pick a value. Component entries are written as
88
- `{group.key}` refs, so changing a token changes every component that names it.
89
-
90
- This file is GENERATED — edits here are overwritten on the next sync. To change
91
- the foundation itself, propose the change (`design_propose_change`); a human
92
- reviews and applies it, and the next sync brings it back down.
93
-
94
- ## Palette
95
-
96
- - `{colors.ink}` — #0d0d0d (dark #f5f5f4)
97
- - `{colors.paper}` — #ffffff (dark #0b0b0c)
98
- - `{colors.primary-moss}` — #2d5be3 (dark #7ea0ff)
99
- - `{colors.muted}` — #6b7280
100
- - `{colors.accent-amber}` — #c9851f
101
- - `{colors.line}` — #e7e5e4 (dark #26262a)
102
- - `{colors.primary}` — #2d5be3 (dark #7ea0ff)
103
- - `{colors.accent}` — #c9851f
104
- - `{colors.success}` — #177245
105
- - `{colors.warning}` — #c9851f
106
- - `{colors.danger}` — #a11d1d
107
- - `{colors.neutral-100}` — #f5f5f4
108
- - `{colors.neutral-500}` — #78716c
109
- - `{colors.neutral-900}` — #1c1917
110
-
111
- ## Typography
112
-
113
- - **display:** Outfit
114
- - **body:** Inter
115
- - **mono:** JetBrains Mono
116
- - **heading:** Outfit
117
-
118
- - `{typography.scale.display}` — 76px · weight 600 · leading 1.05 · tracking -0.02
119
- - `{typography.scale.heading}` — 38px · weight 600 · leading 1.15 · tracking -0.01
120
- - `{typography.scale.body}` — 14px · weight 400 · leading 1.5
121
- - `{typography.scale.small}` — 11.5px · weight 500
122
- - `{typography.scale.caption}` — 11px · weight 500 · leading 1.4 · tracking 0.04
123
-
124
- ### Type rules
125
-
126
- One geometric face for structure, one humanist face for reading.
127
-
128
- - Display only above 32px.
129
- - Never set body copy below 13px.
130
-
131
- ### Colour rules
132
-
133
- - One primary per view.
134
- - Semantic colour is for state, never decoration.
135
-
136
- ## Visual language
137
-
138
- ### Imagery
139
-
140
- - **Uses imagery:** yes
141
- - **Medium:** photography
142
- - **Secondary media:** diagram
143
- - **Grade:** natural
144
- - **Grain:** fine
145
- - **Crop:** wide
146
- - **Aspect ratios:** 16/9, 1/1
147
- - **Subjects:** hands at work, quiet rooms
148
- - **Mood:** calm, considered
149
- - **Composition:** off-centre, generous negative space
150
- - **Duotone:** shadow #12213f · highlight #f3ede1
151
-
152
- ### Imagery (brand system)
153
-
154
- - **Medium:** documentary photography
155
- - **Style:** unstaged
156
- - **Treatment:** warm highlights, cool shadows
157
- - **Mood:** assured
158
- - **Subjects:** workshops, field crews
159
- - **Avoid:** stock handshakes, isolated laptops
160
-
161
- ### Iconography
162
-
163
- - **Style:** line
164
- - **Weight:** 1.5px
165
- - **Corner:** rounded
166
- - **Grid:** 24
167
-
168
- ### Motion
169
-
170
- - **Character:** settled
171
- - **Easing:** cubic-bezier(0.2, 0, 0, 1)
172
- - **Duration (ms):** 220
173
- - **Principles:** Move once, arrive., Never animate what a person is reading.
174
-
175
- ### Texture
176
-
177
- - **Surfaces:** paper, frosted glass
178
- - **Background:** flat
179
- - **Notes:** No gradients behind text.
180
-
181
- ### Guardrails
182
-
183
- Do:
184
-
185
- - Let type carry the page.
186
- - Use one accent per view.
187
-
188
- Do not:
189
-
190
- - No stock handshakes.
191
- - No drop shadows on text.
192
-
193
- ### Generation seeds
194
-
195
- - **Prompt seed:** quiet rooms, natural light, fine grain
196
- - **Seed locked:** yes
197
- - **Negative seed:** neon, lens flare
198
- - **References:** moodboard/2026-03
199
- - **Source:** generated
200
- - **Schema version:** 2
201
-
202
- ## Layout principles
203
-
204
- - Left-align everything that reads.
205
- - One idea per band.
206
-
207
- ## Marks
208
-
209
- - `brandIcon` — set
210
- - `wordmark` — set
211
-
212
- Fetch the bytes with `design_export_kit`; never inline them here.
213
-
214
- ## Additional tokens
215
-
216
- Keys the renderer does not model yet, carried through verbatim so nothing is
217
- lost between an hq that added a token and an SDK that has not learned it.
218
-
219
- ```json
220
- {
221
- "elevationCurve": {
222
- "0": "none",
223
- "1": "0 1px 2px rgba(0,0,0,0.05)"
224
- },
225
- "examples": {
226
- "hero": "A crew at first light.",
227
- "cta": "Start the walkthrough"
228
- },
229
- "gridUnit": 4
230
- }
231
- ```
232
-
233
- ## Provenance
234
-
235
- - **Version:** V2.7
236
- - **Version id:** bv_01HQZ
237
- - **Synced:** 2026-09-08T12:00:00.000Z
238
- - **Source:** cohort · branding.getFoundation
@@ -1,67 +0,0 @@
1
- ---
2
- name: "Northwind"
3
- version: "bv_01HQZ"
4
- generatedAt: "2026-09-08T12:00:00.000Z"
5
- source: "cohort · branding.getFoundation"
6
- ---
7
-
8
- # Northwind — product voice
9
-
10
- Generated from the workspace's saved brand foundation. It says how this
11
- product sounds; `DESIGN.md` beside it says how it looks. Read both before
12
- writing anything a customer sees. Edits here are overwritten on the next
13
- sync — propose foundation changes with `design_propose_change`.
14
-
15
- ## Positioning
16
-
17
- The operating system for companies that run on agents as well as people.
18
-
19
- ## Taglines
20
-
21
- - Work that runs itself.
22
- - One company, many hands.
23
-
24
- ## Voice
25
-
26
- Concise, specific, accountable. Write like a capable peer — no hype, no emoji, no hedging.
27
-
28
- ## Tone
29
-
30
- - Plain
31
- - Exact
32
- - Unhurried
33
- - Direct
34
-
35
- ## Lexicon
36
-
37
- Say:
38
-
39
- - decide
40
- - ship
41
- - owe
42
-
43
- Avoid:
44
-
45
- - leverage
46
- - synergy
47
- - unlock
48
-
49
- ## In practice
50
-
51
- Two invoices need a decision today. Both are under £5,000.
52
-
53
- ## Motifs
54
-
55
- - A single hairline rule.
56
- - Numbers set in the mono face.
57
-
58
- ## Iconography
59
-
60
- Line icons on a 24px grid, 1.5px stroke.
61
-
62
- ## Provenance
63
-
64
- - **Version:** V2.7
65
- - **Version id:** bv_01HQZ
66
- - **Synced:** 2026-09-08T12:00:00.000Z
67
- - **Source:** cohort · branding.getFoundation
@@ -1,133 +0,0 @@
1
- {
2
- "v": 2,
3
- "colors": [
4
- { "name": "Ink", "value": "#0d0d0d", "dark": "#f5f5f4" },
5
- { "name": "Paper", "value": "#ffffff", "dark": "#0b0b0c" },
6
- { "name": "Primary · Moss", "value": "#2d5be3", "dark": "#7ea0ff" },
7
- { "name": "Muted", "value": "#6b7280" },
8
- { "name": "Accent · Amber", "value": "#c9851f" },
9
- { "name": "Line", "value": "#e7e5e4", "dark": "#26262a" }
10
- ],
11
- "fonts": { "display": "Outfit", "body": "Inter", "mono": "JetBrains Mono" },
12
- "type": [
13
- { "role": "Display", "size": 76, "weight": 600 },
14
- { "role": "Heading", "size": 38, "weight": 600 },
15
- { "role": "Body", "size": 14, "weight": 400 },
16
- { "role": "Small", "size": 11.5, "weight": 500 }
17
- ],
18
- "space": [
19
- { "name": "xs", "value": 4 },
20
- { "name": "sm", "value": 8 },
21
- { "name": "md", "value": 12 },
22
- { "name": "lg", "value": 16 },
23
- { "name": "xl", "value": 22 }
24
- ],
25
- "radii": [
26
- { "name": "chip", "value": 8 },
27
- { "name": "field", "value": 9 },
28
- { "name": "card", "value": 13 },
29
- { "name": "modal", "value": 14 },
30
- { "name": "pill", "value": 999 }
31
- ],
32
- "shadow": [
33
- { "name": "sm", "value": "0 1px 2px rgba(13,13,13,0.06)" },
34
- { "name": "md", "value": "0 18px 50px rgba(13,13,13,0.13)" }
35
- ],
36
- "border": [
37
- { "name": "hairline", "value": "1px solid #e7e5e4" },
38
- { "name": "strong", "value": "1px solid #d6d3d1" }
39
- ],
40
- "voice": "Concise, specific, accountable. Write like a capable peer — no hype, no emoji, no hedging.",
41
- "positioning": "The operating system for companies that run on agents as well as people.",
42
- "taglines": ["Work that runs itself.", "One company, many hands."],
43
- "toneTraits": ["Plain", "Exact", "Unhurried"],
44
- "logos": {
45
- "brandIcon": "https://assets.example.test/icon.png",
46
- "wordmark": "https://assets.example.test/wordmark.svg",
47
- "favicon": null
48
- },
49
- "examples": { "hero": "A crew at first light.", "cta": "Start the walkthrough" },
50
- "visualLanguage": {
51
- "v": 2,
52
- "source": "generated",
53
- "imagery": {
54
- "needsImagery": true,
55
- "medium": "photography",
56
- "secondaryMedia": ["diagram"],
57
- "colorGrade": "natural",
58
- "grain": "fine",
59
- "crop": "wide",
60
- "aspectRatios": ["16/9", "1/1"],
61
- "subjects": ["hands at work", "quiet rooms"],
62
- "mood": ["calm", "considered"],
63
- "composition": "off-centre, generous negative space",
64
- "duotone": { "shadow": "#12213f", "highlight": "#f3ede1" }
65
- },
66
- "iconography": { "style": "line", "weight": "1.5px", "corner": "rounded", "grid": 24 },
67
- "motion": {
68
- "character": "settled",
69
- "easing": "cubic-bezier(0.2, 0, 0, 1)",
70
- "durationMs": 220,
71
- "principles": ["Move once, arrive.", "Never animate what a person is reading."]
72
- },
73
- "texture": { "surfaces": ["paper", "frosted glass"], "background": "flat", "notes": "No gradients behind text." },
74
- "guardrails": {
75
- "dos": ["Let type carry the page.", "Use one accent per view."],
76
- "donts": ["No stock handshakes.", "No drop shadows on text."]
77
- },
78
- "promptSeed": "quiet rooms, natural light, fine grain",
79
- "seedLocked": true,
80
- "negativeSeed": "neon, lens flare",
81
- "references": ["moodboard/2026-03"]
82
- },
83
- "system": {
84
- "typography": {
85
- "families": {
86
- "display": { "family": "Outfit", "category": "sans", "weights": [500, 600] },
87
- "heading": { "family": "Outfit", "category": "sans", "weights": [600] },
88
- "body": { "family": "Inter", "category": "sans", "weights": [400, 500] },
89
- "mono": { "family": "JetBrains Mono", "category": "mono", "weights": [400] }
90
- },
91
- "scale": [
92
- { "role": "Display", "size": 76, "weight": 600, "leading": 1.05, "tracking": -0.02 },
93
- { "role": "Heading", "size": 38, "weight": 600, "leading": 1.15, "tracking": -0.01 },
94
- { "role": "Body", "size": 14, "weight": 400, "leading": 1.5 },
95
- { "role": "Caption", "size": 11, "weight": 500, "leading": 1.4, "tracking": 0.04 }
96
- ],
97
- "pairingRationale": "One geometric face for structure, one humanist face for reading.",
98
- "usageRules": ["Display only above 32px.", "Never set body copy below 13px."]
99
- },
100
- "color": {
101
- "roles": {
102
- "primary": { "name": "Signal Blue", "value": "#2d5be3", "dark": "#7ea0ff" },
103
- "accent": { "name": "Amber", "value": "#c9851f" }
104
- },
105
- "neutralRamp": [
106
- { "step": 100, "value": "#f5f5f4" },
107
- { "step": 500, "value": "#78716c" },
108
- { "step": 900, "value": "#1c1917" }
109
- ],
110
- "semantic": { "success": "#177245", "warning": "#c9851f", "danger": "#a11d1d" },
111
- "usageRules": ["One primary per view.", "Semantic colour is for state, never decoration."]
112
- },
113
- "imagery": {
114
- "medium": "documentary photography",
115
- "style": "unstaged",
116
- "treatment": "warm highlights, cool shadows",
117
- "mood": "assured",
118
- "subjects": ["workshops", "field crews"],
119
- "donts": ["stock handshakes", "isolated laptops"]
120
- },
121
- "motifs": ["A single hairline rule.", "Numbers set in the mono face."],
122
- "iconography": "Line icons on a 24px grid, 1.5px stroke.",
123
- "layoutPrinciples": ["Left-align everything that reads.", "One idea per band."],
124
- "voice": {
125
- "voice": "Concise, specific, accountable.",
126
- "toneTraits": ["Plain", "Direct"],
127
- "lexicon": { "use": ["decide", "ship", "owe"], "avoid": ["leverage", "synergy", "unlock"] },
128
- "exampleCopy": "Two invoices need a decision today. Both are under £5,000."
129
- }
130
- },
131
- "elevationCurve": { "0": "none", "1": "0 1px 2px rgba(0,0,0,0.05)" },
132
- "gridUnit": 4
133
- }
@@ -1,144 +0,0 @@
1
- /**
2
- * refresh-gate.test.mjs — WHEN a seat re-syncs its brand foundation
3
- * (WP-M7 mechanic 4). The gate is pure, so every case here is a table row.
4
- *
5
- * The two rules worth stating in prose because they are the ones a reader
6
- * would get wrong:
7
- *
8
- * · An UNKNOWN current version is not a change. The daemon asks the gate
9
- * twice per tick — before the read (version unknown) and after it — and if
10
- * "unknown" counted as a new version, the pre-read call would say yes on
11
- * every tick and the interval would mean nothing.
12
- * · A `lastAt` in the FUTURE refreshes. A clock that jumped backwards (or a
13
- * state file copied from another box) must not be able to freeze DESIGN.md
14
- * on disk until the wall clock catches up.
15
- */
16
-
17
- import { test } from "node:test";
18
- import assert from "node:assert/strict";
19
-
20
- import {
21
- isUnversionedFoundation,
22
- shouldRefreshDesign,
23
- foundationVersion,
24
- foundationVersionLabel,
25
- DESIGN_REFRESH_INTERVAL_MS,
26
- DESIGN_STATE_REL,
27
- DESIGN_FILES,
28
- } from "./refresh-gate.mjs";
29
-
30
- const NOW = Date.parse("2026-09-08T12:00:00Z");
31
-
32
- test("the interval is 15 minutes and the paths are the ones the CLI and daemon write", () => {
33
- assert.equal(DESIGN_REFRESH_INTERVAL_MS, 15 * 60_000);
34
- assert.equal(DESIGN_STATE_REL, "state/design/foundation.json");
35
- assert.deepEqual(DESIGN_FILES, ["DESIGN.md", "PRODUCT.md"]);
36
- });
37
-
38
- test("never synced → refresh", () => {
39
- assert.deepEqual(shouldRefreshDesign({ now: NOW }), { refresh: true, reason: "never" });
40
- assert.deepEqual(shouldRefreshDesign({ lastAt: null, now: NOW }), { refresh: true, reason: "never" });
41
- assert.deepEqual(shouldRefreshDesign({ lastAt: "not a date", now: NOW }), { refresh: true, reason: "never" });
42
- });
43
-
44
- test("inside the interval with an unchanged version → no refresh", () => {
45
- assert.deepEqual(
46
- shouldRefreshDesign({ lastVersion: "bv_1", currentVersion: "bv_1", lastAt: NOW - 60_000, now: NOW }),
47
- { refresh: false, reason: "fresh" },
48
- );
49
- });
50
-
51
- test("a changed version refreshes immediately, however recent the last sync", () => {
52
- assert.deepEqual(
53
- shouldRefreshDesign({ lastVersion: "bv_1", currentVersion: "bv_2", lastAt: NOW - 1_000, now: NOW }),
54
- { refresh: true, reason: "version-changed" },
55
- );
56
- // First-ever version on a seat that had synced an unversioned org.
57
- assert.deepEqual(
58
- shouldRefreshDesign({ lastVersion: null, currentVersion: "bv_1", lastAt: NOW - 1_000, now: NOW }),
59
- { refresh: true, reason: "version-changed" },
60
- );
61
- });
62
-
63
- test("an UNKNOWN current version is not a change — the pre-read call must not always say yes", () => {
64
- for (const currentVersion of [null, undefined, "", 7, {}]) {
65
- assert.deepEqual(
66
- shouldRefreshDesign({ lastVersion: "bv_1", currentVersion, lastAt: NOW - 60_000, now: NOW }),
67
- { refresh: false, reason: "fresh" },
68
- `currentVersion=${JSON.stringify(currentVersion)}`,
69
- );
70
- }
71
- });
72
-
73
- test("the interval fires at the boundary and after it, not before", () => {
74
- const at = (dt) => shouldRefreshDesign({ lastVersion: "bv_1", currentVersion: "bv_1", lastAt: NOW - dt, now: NOW });
75
- assert.equal(at(DESIGN_REFRESH_INTERVAL_MS - 1).refresh, false);
76
- assert.deepEqual(at(DESIGN_REFRESH_INTERVAL_MS), { refresh: true, reason: "interval" });
77
- assert.deepEqual(at(DESIGN_REFRESH_INTERVAL_MS * 10), { refresh: true, reason: "interval" });
78
- });
79
-
80
- test("a lastAt in the future refreshes rather than freezing the seat", () => {
81
- assert.deepEqual(
82
- shouldRefreshDesign({ lastVersion: "bv_1", currentVersion: "bv_1", lastAt: NOW + 86_400_000, now: NOW }),
83
- { refresh: true, reason: "clock-skew" },
84
- );
85
- });
86
-
87
- test("lastAt is accepted as an ISO string or epoch ms", () => {
88
- const iso = shouldRefreshDesign({ lastVersion: "bv_1", currentVersion: "bv_1", lastAt: "2026-09-08T11:59:00Z", now: NOW });
89
- const ms = shouldRefreshDesign({ lastVersion: "bv_1", currentVersion: "bv_1", lastAt: NOW - 60_000, now: NOW });
90
- assert.deepEqual(iso, ms);
91
- });
92
-
93
- test("a bad or absent intervalMs falls back to the 15-minute default", () => {
94
- for (const intervalMs of [undefined, null, 0, -5, NaN, "soon"]) {
95
- const r = shouldRefreshDesign({ lastVersion: "bv_1", currentVersion: "bv_1", lastAt: NOW - 14 * 60_000, now: NOW, intervalMs });
96
- assert.equal(r.refresh, false, `intervalMs=${String(intervalMs)}`);
97
- }
98
- assert.equal(
99
- shouldRefreshDesign({ lastVersion: "bv_1", currentVersion: "bv_1", lastAt: NOW - 60_000, now: NOW, intervalMs: 30_000 }).reason,
100
- "interval",
101
- "an explicit shorter interval is honoured",
102
- );
103
- });
104
-
105
- test("foundationVersion prefers headVersionId, then version.id, then a stable 'unversioned'", () => {
106
- assert.equal(foundationVersion({ headVersionId: "bv_1", version: { id: "bv_0" }, foundation: {} }), "bv_1");
107
- assert.equal(foundationVersion({ headVersionId: null, version: { id: "bv_0" }, foundation: {} }), "bv_0");
108
- assert.equal(foundationVersion({ headVersionId: null, version: null, foundation: {} }), "unversioned");
109
- assert.equal(foundationVersion({}), null, "a frame with no foundation has no version identity");
110
- assert.equal(foundationVersion(null), null);
111
- assert.equal(foundationVersion("nope"), null);
112
- });
113
-
114
- test("'unversioned' is STABLE, so an org that never saved a foundation does not re-render every poll", () => {
115
- const frame = { headVersionId: null, version: null, foundation: { colors: [] } };
116
- const v = foundationVersion(frame);
117
- assert.equal(shouldRefreshDesign({ lastVersion: v, currentVersion: foundationVersion(frame), lastAt: NOW - 60_000, now: NOW }).refresh, false);
118
- });
119
-
120
- test("foundationVersionLabel reads the label, falls back to V2.<seq>, and never invents", () => {
121
- assert.equal(foundationVersionLabel({ version: { label: "Palette refresh", seq: 7 } }), "Palette refresh");
122
- assert.equal(foundationVersionLabel({ version: { seq: 7 } }), "V2.7");
123
- assert.equal(foundationVersionLabel({ version: { label: " " } }), "");
124
- assert.equal(foundationVersionLabel({ version: null }), "");
125
- assert.equal(foundationVersionLabel(null), "");
126
- });
127
-
128
- test("isUnversionedFoundation catches the frame hq ACTUALLY sends for a workspace with no brand", () => {
129
- // hq's `loadSavedFoundation` falls back to `dsDefaults()`, so the foundation
130
- // is never null. `unversioned` is the only truthful signal, and an older hq
131
- // that omits it is judged by having no version identity at all.
132
- const stock = { foundation: { colors: [] }, version: null, headVersionId: null, unversioned: true };
133
- assert.equal(isUnversionedFoundation(stock), true);
134
- assert.equal(isUnversionedFoundation({ ...stock, unversioned: undefined }), true, "older hq: no version identity of any kind");
135
-
136
- const saved = { foundation: { colors: [] }, version: { id: "bv_1", seq: 3 }, headVersionId: "bv_1", unversioned: false };
137
- assert.equal(isUnversionedFoundation(saved), false);
138
- // hq is trusted when it states the field, even where retention pruned the
139
- // snapshot row and only the etag survives.
140
- assert.equal(isUnversionedFoundation({ foundation: {}, version: null, headVersionId: "bv_9", unversioned: false }), false);
141
-
142
- assert.equal(isUnversionedFoundation(null), false, "an absent frame is a read failure, not an unversioned workspace");
143
- assert.equal(isUnversionedFoundation({}), false);
144
- });