@meetquinn/animactl 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (289) hide show
  1. package/README.md +11 -6
  2. package/dist/server/{runtime/activity-payload.d.ts → activities/format.d.ts} +4 -1
  3. package/dist/server/activities/format.d.ts.map +1 -0
  4. package/dist/server/{runtime/activity-payload.js → activities/format.js} +16 -1
  5. package/dist/server/agents/agent-skills.d.ts +7 -3
  6. package/dist/server/agents/agent-skills.d.ts.map +1 -1
  7. package/dist/server/agents/agent-skills.js +243 -38
  8. package/dist/server/agents/agent-slack.service.d.ts +15 -0
  9. package/dist/server/agents/agent-slack.service.d.ts.map +1 -1
  10. package/dist/server/agents/agent-slack.service.js +43 -6
  11. package/dist/server/agents/default-skills.d.ts +9 -0
  12. package/dist/server/agents/default-skills.d.ts.map +1 -0
  13. package/dist/server/agents/default-skills.js +52 -0
  14. package/dist/server/cli/runtime-cli.d.ts +7 -1
  15. package/dist/server/cli/runtime-cli.d.ts.map +1 -1
  16. package/dist/server/cli/runtime-cli.js +107 -3
  17. package/dist/server/cli/services-cli.d.ts.map +1 -1
  18. package/dist/server/cli/services-cli.js +39 -0
  19. package/dist/server/inbox/slack-subscriber.d.ts +2 -0
  20. package/dist/server/inbox/slack-subscriber.d.ts.map +1 -1
  21. package/dist/server/inbox/slack-subscriber.js +28 -2
  22. package/dist/server/inbox/slack-subscription.service.d.ts.map +1 -1
  23. package/dist/server/inbox/slack-subscription.service.js +13 -1
  24. package/dist/server/inbox/wake-queue.service.d.ts +3 -1
  25. package/dist/server/inbox/wake-queue.service.d.ts.map +1 -1
  26. package/dist/server/inbox/wake-queue.service.js +5 -3
  27. package/dist/server/provider-usage/http.d.ts +1 -0
  28. package/dist/server/provider-usage/http.d.ts.map +1 -1
  29. package/dist/server/provider-usage/http.js +23 -1
  30. package/dist/server/provider-usage/provider-usage.service.d.ts +1 -4
  31. package/dist/server/provider-usage/provider-usage.service.d.ts.map +1 -1
  32. package/dist/server/provider-usage/provider-usage.service.js +1 -18
  33. package/dist/server/provider-usage/providers/claude.d.ts +1 -1
  34. package/dist/server/provider-usage/providers/claude.d.ts.map +1 -1
  35. package/dist/server/provider-usage/providers/claude.js +1 -1
  36. package/dist/server/provider-usage/providers/codex.d.ts +1 -1
  37. package/dist/server/provider-usage/providers/codex.d.ts.map +1 -1
  38. package/dist/server/provider-usage/providers/codex.js +1 -1
  39. package/dist/server/provider-usage/providers/kimi.d.ts +1 -1
  40. package/dist/server/provider-usage/providers/kimi.d.ts.map +1 -1
  41. package/dist/server/provider-usage/providers/kimi.js +4 -4
  42. package/dist/server/provider-usage/result.d.ts +5 -0
  43. package/dist/server/provider-usage/result.d.ts.map +1 -0
  44. package/dist/server/provider-usage/result.js +18 -0
  45. package/dist/server/providers/active-runtime.d.ts +1 -1
  46. package/dist/server/providers/active-runtime.d.ts.map +1 -1
  47. package/dist/server/providers/claude-events.d.ts +1 -1
  48. package/dist/server/providers/claude-events.d.ts.map +1 -1
  49. package/dist/server/providers/claude-events.js +2 -2
  50. package/dist/server/providers/claude.d.ts +1 -1
  51. package/dist/server/providers/claude.d.ts.map +1 -1
  52. package/dist/server/providers/claude.js +2 -2
  53. package/dist/server/providers/codex-app-server.d.ts +1 -1
  54. package/dist/server/providers/codex-app-server.d.ts.map +1 -1
  55. package/dist/server/providers/codex-app-server.js +1 -1
  56. package/dist/server/providers/codex-events.js +1 -1
  57. package/dist/server/providers/codex.d.ts +1 -1
  58. package/dist/server/providers/codex.d.ts.map +1 -1
  59. package/dist/server/providers/codex.js +2 -2
  60. package/dist/server/{runtime/provider-contract.d.ts → providers/contract.d.ts} +1 -1
  61. package/dist/server/providers/contract.d.ts.map +1 -0
  62. package/dist/server/providers/factory.d.ts +1 -1
  63. package/dist/server/providers/factory.d.ts.map +1 -1
  64. package/dist/server/providers/kimi-events.d.ts +1 -1
  65. package/dist/server/providers/kimi-events.d.ts.map +1 -1
  66. package/dist/server/providers/kimi-events.js +1 -1
  67. package/dist/server/providers/kimi.d.ts +1 -1
  68. package/dist/server/providers/kimi.d.ts.map +1 -1
  69. package/dist/server/providers/kimi.js +3 -2
  70. package/dist/server/providers/reasoning-events.js +1 -1
  71. package/dist/server/runtime/active-run-control.d.ts +19 -0
  72. package/dist/server/runtime/active-run-control.d.ts.map +1 -0
  73. package/dist/server/runtime/active-run-control.js +89 -0
  74. package/dist/server/runtime/activity.js +1 -1
  75. package/dist/server/runtime/agent-runner.d.ts +1 -1
  76. package/dist/server/runtime/agent-runner.d.ts.map +1 -1
  77. package/dist/server/runtime/delivery-prompt.d.ts +6 -0
  78. package/dist/server/runtime/delivery-prompt.d.ts.map +1 -1
  79. package/dist/server/runtime/delivery-prompt.js +53 -34
  80. package/dist/server/runtime/followup-appender.d.ts +20 -0
  81. package/dist/server/runtime/followup-appender.d.ts.map +1 -0
  82. package/dist/server/runtime/followup-appender.js +128 -0
  83. package/dist/server/runtime/host.d.ts +2 -0
  84. package/dist/server/runtime/host.d.ts.map +1 -1
  85. package/dist/server/runtime/host.js +8 -0
  86. package/dist/server/runtime/provider-runner.d.ts +16 -0
  87. package/dist/server/runtime/provider-runner.d.ts.map +1 -0
  88. package/dist/server/runtime/provider-runner.js +86 -0
  89. package/dist/server/runtime/runtime-bridge.d.ts +1 -1
  90. package/dist/server/runtime/runtime-bridge.d.ts.map +1 -1
  91. package/dist/server/runtime/runtime-session.service.d.ts +1 -1
  92. package/dist/server/runtime/runtime-session.service.d.ts.map +1 -1
  93. package/dist/server/runtime/runtime-session.service.js +1 -1
  94. package/dist/server/runtime/runtime-worker.d.ts +2 -10
  95. package/dist/server/runtime/runtime-worker.d.ts.map +1 -1
  96. package/dist/server/runtime/runtime-worker.js +60 -286
  97. package/dist/server/runtime-management/managed-runtime.d.ts.map +1 -0
  98. package/dist/server/runtime-management/runtime-release.d.ts.map +1 -0
  99. package/dist/server/{runtime → runtime-management}/runtime-upgrade.d.ts +1 -0
  100. package/dist/server/runtime-management/runtime-upgrade.d.ts.map +1 -0
  101. package/dist/server/{runtime → runtime-management}/runtime-upgrade.js +14 -0
  102. package/dist/server/services/system.service.d.ts +41 -0
  103. package/dist/server/services/system.service.d.ts.map +1 -0
  104. package/dist/server/services/system.service.js +154 -0
  105. package/dist/server/settings/settings.service.d.ts +2 -1
  106. package/dist/server/settings/settings.service.d.ts.map +1 -1
  107. package/dist/server/settings/settings.service.js +9 -1
  108. package/dist/server/slack/shortcuts.d.ts +0 -3
  109. package/dist/server/slack/shortcuts.d.ts.map +1 -1
  110. package/dist/server/slack/shortcuts.js +0 -3
  111. package/dist/server/slack-interactions/shortcut-ids.d.ts +4 -0
  112. package/dist/server/slack-interactions/shortcut-ids.d.ts.map +1 -0
  113. package/dist/server/slack-interactions/shortcut-ids.js +3 -0
  114. package/dist/server/slack-interactions/shortcut-views.d.ts +65 -0
  115. package/dist/server/slack-interactions/shortcut-views.d.ts.map +1 -0
  116. package/dist/server/slack-interactions/shortcut-views.js +211 -0
  117. package/dist/server/{slack → slack-interactions}/shortcut.service.d.ts +2 -47
  118. package/dist/server/slack-interactions/shortcut.service.d.ts.map +1 -0
  119. package/dist/server/slack-interactions/shortcut.service.js +227 -0
  120. package/dist/server/storage/jsonl-log.d.ts +9 -0
  121. package/dist/server/storage/jsonl-log.d.ts.map +1 -1
  122. package/dist/server/storage/jsonl-log.js +36 -1
  123. package/dist/server/storage/schema/server.store.d.ts +5 -0
  124. package/dist/server/storage/schema/server.store.d.ts.map +1 -1
  125. package/dist/server/storage/schema/server.store.js +2 -1
  126. package/dist/server/storage/schema/wake-queue.store.d.ts +15 -1
  127. package/dist/server/storage/schema/wake-queue.store.d.ts.map +1 -1
  128. package/dist/server/storage/schema/wake-queue.store.js +5 -3
  129. package/dist/server/tests/agent-config.test.d.ts +2 -0
  130. package/dist/server/tests/agent-config.test.d.ts.map +1 -0
  131. package/dist/server/tests/agent-config.test.js +229 -0
  132. package/dist/server/tests/agent-runtime.test.d.ts +2 -0
  133. package/dist/server/tests/agent-runtime.test.d.ts.map +1 -0
  134. package/dist/server/tests/agent-runtime.test.js +1110 -0
  135. package/dist/server/tests/agent-seed-memory.test.d.ts +2 -0
  136. package/dist/server/tests/agent-seed-memory.test.d.ts.map +1 -0
  137. package/dist/server/tests/agent-seed-memory.test.js +16 -0
  138. package/dist/server/tests/agent-skills.test.d.ts +2 -0
  139. package/dist/server/tests/agent-skills.test.d.ts.map +1 -0
  140. package/dist/server/tests/agent-skills.test.js +140 -0
  141. package/dist/server/tests/anima-home.d.ts +2 -0
  142. package/dist/server/tests/anima-home.d.ts.map +1 -0
  143. package/dist/server/tests/anima-home.js +4 -0
  144. package/dist/server/tests/cli-file.test.d.ts +2 -0
  145. package/dist/server/tests/cli-file.test.d.ts.map +1 -0
  146. package/dist/server/tests/cli-file.test.js +596 -0
  147. package/dist/server/tests/cli-message.test.d.ts +2 -0
  148. package/dist/server/tests/cli-message.test.d.ts.map +1 -0
  149. package/dist/server/tests/cli-message.test.js +1196 -0
  150. package/dist/server/tests/client-error-routes.test.d.ts +2 -0
  151. package/dist/server/tests/client-error-routes.test.d.ts.map +1 -0
  152. package/dist/server/tests/client-error-routes.test.js +163 -0
  153. package/dist/server/tests/config.test.d.ts +2 -0
  154. package/dist/server/tests/config.test.d.ts.map +1 -0
  155. package/dist/server/tests/config.test.js +497 -0
  156. package/dist/server/tests/default-skills.test.d.ts +2 -0
  157. package/dist/server/tests/default-skills.test.d.ts.map +1 -0
  158. package/dist/server/tests/default-skills.test.js +57 -0
  159. package/dist/server/tests/helpers/inbox.d.ts +10 -0
  160. package/dist/server/tests/helpers/inbox.d.ts.map +1 -0
  161. package/dist/server/tests/helpers/inbox.js +21 -0
  162. package/dist/server/tests/helpers/slack.d.ts +11 -0
  163. package/dist/server/tests/helpers/slack.d.ts.map +1 -0
  164. package/dist/server/tests/helpers/slack.js +17 -0
  165. package/dist/server/tests/helpers/state.d.ts +19 -0
  166. package/dist/server/tests/helpers/state.d.ts.map +1 -0
  167. package/dist/server/tests/helpers/state.js +69 -0
  168. package/dist/server/tests/inbox-slack-events.test.d.ts +2 -0
  169. package/dist/server/tests/inbox-slack-events.test.d.ts.map +1 -0
  170. package/dist/server/tests/inbox-slack-events.test.js +271 -0
  171. package/dist/server/tests/inbox.test.d.ts +2 -0
  172. package/dist/server/tests/inbox.test.d.ts.map +1 -0
  173. package/dist/server/tests/inbox.test.js +144 -0
  174. package/dist/server/tests/interactive-ask.test.d.ts +2 -0
  175. package/dist/server/tests/interactive-ask.test.d.ts.map +1 -0
  176. package/dist/server/tests/interactive-ask.test.js +387 -0
  177. package/dist/server/tests/kb.test.d.ts +2 -0
  178. package/dist/server/tests/kb.test.d.ts.map +1 -0
  179. package/dist/server/tests/kb.test.js +371 -0
  180. package/dist/server/tests/message.service.test.d.ts +2 -0
  181. package/dist/server/tests/message.service.test.d.ts.map +1 -0
  182. package/dist/server/tests/message.service.test.js +151 -0
  183. package/dist/server/tests/messages.test.d.ts +2 -0
  184. package/dist/server/tests/messages.test.d.ts.map +1 -0
  185. package/dist/server/tests/messages.test.js +12 -0
  186. package/dist/server/tests/prompt-attachments.test.d.ts +2 -0
  187. package/dist/server/tests/prompt-attachments.test.d.ts.map +1 -0
  188. package/dist/server/tests/prompt-attachments.test.js +274 -0
  189. package/dist/server/tests/provider-usage.test.d.ts +2 -0
  190. package/dist/server/tests/provider-usage.test.d.ts.map +1 -0
  191. package/dist/server/tests/provider-usage.test.js +97 -0
  192. package/dist/server/tests/reminders.test.d.ts +2 -0
  193. package/dist/server/tests/reminders.test.d.ts.map +1 -0
  194. package/dist/server/tests/reminders.test.js +383 -0
  195. package/dist/server/tests/runtime-cli.test.d.ts +2 -0
  196. package/dist/server/tests/runtime-cli.test.d.ts.map +1 -0
  197. package/dist/server/tests/runtime-cli.test.js +21 -0
  198. package/dist/server/tests/runtime-upgrade.test.d.ts +2 -0
  199. package/dist/server/tests/runtime-upgrade.test.d.ts.map +1 -0
  200. package/dist/server/tests/runtime-upgrade.test.js +307 -0
  201. package/dist/server/tests/runtime-worker.test.d.ts +2 -0
  202. package/dist/server/tests/runtime-worker.test.d.ts.map +1 -0
  203. package/dist/server/tests/runtime-worker.test.js +1021 -0
  204. package/dist/server/tests/runtime.test.d.ts +2 -0
  205. package/dist/server/tests/runtime.test.d.ts.map +1 -0
  206. package/dist/server/tests/runtime.test.js +354 -0
  207. package/dist/server/tests/services.test.d.ts +2 -0
  208. package/dist/server/tests/services.test.d.ts.map +1 -0
  209. package/dist/server/tests/services.test.js +636 -0
  210. package/dist/server/tests/slack-files.test.d.ts +2 -0
  211. package/dist/server/tests/slack-files.test.d.ts.map +1 -0
  212. package/dist/server/tests/slack-files.test.js +118 -0
  213. package/dist/server/tests/slack-shortcuts.test.d.ts +2 -0
  214. package/dist/server/tests/slack-shortcuts.test.d.ts.map +1 -0
  215. package/dist/server/tests/slack-shortcuts.test.js +310 -0
  216. package/dist/server/tests/slack.test.d.ts +2 -0
  217. package/dist/server/tests/slack.test.d.ts.map +1 -0
  218. package/dist/server/tests/slack.test.js +213 -0
  219. package/dist/server/tests/state-cache.test.d.ts +2 -0
  220. package/dist/server/tests/state-cache.test.d.ts.map +1 -0
  221. package/dist/server/tests/state-cache.test.js +184 -0
  222. package/dist/server/tests/subscriptions.test.d.ts +2 -0
  223. package/dist/server/tests/subscriptions.test.d.ts.map +1 -0
  224. package/dist/server/tests/subscriptions.test.js +292 -0
  225. package/dist/server/tests/system-service.test.d.ts +2 -0
  226. package/dist/server/tests/system-service.test.d.ts.map +1 -0
  227. package/dist/server/tests/system-service.test.js +20 -0
  228. package/dist/server/tests/url-routes.test.d.ts +2 -0
  229. package/dist/server/tests/url-routes.test.d.ts.map +1 -0
  230. package/dist/server/tests/url-routes.test.js +217 -0
  231. package/dist/server/tests/web-api.test.d.ts +2 -0
  232. package/dist/server/tests/web-api.test.d.ts.map +1 -0
  233. package/dist/server/tests/web-api.test.js +1759 -0
  234. package/dist/server/web/app.d.ts.map +1 -1
  235. package/dist/server/web/app.js +2 -0
  236. package/dist/server/web/client-error-routes.d.ts +3 -0
  237. package/dist/server/web/client-error-routes.d.ts.map +1 -0
  238. package/dist/server/web/client-error-routes.js +101 -0
  239. package/dist/server/web/system-routes.d.ts.map +1 -1
  240. package/dist/server/web/system-routes.js +21 -131
  241. package/dist/shared/agent-config.d.ts +8 -18
  242. package/dist/shared/agent-config.d.ts.map +1 -1
  243. package/dist/shared/agent-config.js +3 -4
  244. package/dist/shared/inbox.d.ts +27 -0
  245. package/dist/shared/inbox.d.ts.map +1 -1
  246. package/dist/shared/inbox.js +1 -0
  247. package/dist/shared/server-info.d.ts +6 -5
  248. package/dist/shared/server-info.d.ts.map +1 -1
  249. package/dist/shared/server-info.js +3 -1
  250. package/dist/shared/server-settings.d.ts +6 -0
  251. package/dist/shared/server-settings.d.ts.map +1 -1
  252. package/dist/shared/server-settings.js +1 -0
  253. package/dist/shared/skills.d.ts +24 -3
  254. package/dist/shared/skills.d.ts.map +1 -1
  255. package/dist/web/assets/activity-DHjip8tY.js +7 -0
  256. package/dist/web/assets/clipboard-D2NSC52v.js +1 -0
  257. package/dist/web/assets/{external-link-Dt0qTpmV.js → external-link-Bhr1WdRS.js} +1 -1
  258. package/dist/web/assets/{file-text-Dd9ys6py.js → file-text-CYMA_SMA.js} +1 -1
  259. package/dist/web/assets/{index-CzAQnbuO.js → index-CVpew409.js} +5 -5
  260. package/dist/web/assets/index-mh0uJTkY.css +2 -0
  261. package/dist/web/assets/kb-DDVpYkT9.js +35 -0
  262. package/dist/web/assets/profile-CBy6GNzp.js +1 -0
  263. package/dist/web/assets/reminders-Bbwb9QNT.js +1 -0
  264. package/dist/web/favicon.svg +1 -1
  265. package/dist/web/index.html +2 -2
  266. package/package.json +1 -1
  267. package/templates/runtime-standing-prompt.md +16 -2
  268. package/templates/skills/find-skills/SKILL.md +133 -0
  269. package/dist/server/runtime/activity-payload.d.ts.map +0 -1
  270. package/dist/server/runtime/activity-text.d.ts +0 -4
  271. package/dist/server/runtime/activity-text.d.ts.map +0 -1
  272. package/dist/server/runtime/activity-text.js +0 -16
  273. package/dist/server/runtime/managed-runtime.d.ts.map +0 -1
  274. package/dist/server/runtime/provider-contract.d.ts.map +0 -1
  275. package/dist/server/runtime/runtime-release.d.ts.map +0 -1
  276. package/dist/server/runtime/runtime-upgrade.d.ts.map +0 -1
  277. package/dist/server/slack/shortcut.service.d.ts.map +0 -1
  278. package/dist/server/slack/shortcut.service.js +0 -493
  279. package/dist/web/assets/activity-BP0C81IV.js +0 -7
  280. package/dist/web/assets/globe-DmDZSgDP.js +0 -1
  281. package/dist/web/assets/index-DKecrvN0.css +0 -2
  282. package/dist/web/assets/kb-3wFeP2Jt.js +0 -32
  283. package/dist/web/assets/profile-D7wPZXW_.js +0 -1
  284. package/dist/web/assets/reminders-DOhroVwo.js +0 -1
  285. /package/dist/server/{runtime/provider-contract.js → providers/contract.js} +0 -0
  286. /package/dist/server/{runtime → runtime-management}/managed-runtime.d.ts +0 -0
  287. /package/dist/server/{runtime → runtime-management}/managed-runtime.js +0 -0
  288. /package/dist/server/{runtime → runtime-management}/runtime-release.d.ts +0 -0
  289. /package/dist/server/{runtime → runtime-management}/runtime-release.js +0 -0
@@ -0,0 +1,307 @@
1
+ import assert from 'node:assert/strict';
2
+ import { createServer } from 'node:http';
3
+ import { chmod, mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
4
+ import { tmpdir } from 'node:os';
5
+ import { join } from 'node:path';
6
+ import test from 'node:test';
7
+ import { withAnimaHome } from './anima-home.js';
8
+ import { defaultServerSettingsService } from '../settings/settings.service.js';
9
+ import { RuntimeUpgradeCheckStore, compareRuntimeVersions, runRuntimeUpgradeWorker, RuntimeUpgradeConflictError, RuntimeUpgradeService, } from '../runtime-management/runtime-upgrade.js';
10
+ test('runtime version compare handles prerelease canaries', () => {
11
+ assert.equal(compareRuntimeVersions('0.1.1-canary.5.1.723b529', '0.1.1-canary.4.1.0688e3f') > 0, true);
12
+ assert.equal(compareRuntimeVersions('0.1.1-canary.4.2.aaaaaaa', '0.1.1-canary.4.1.zzzzzzz') > 0, true);
13
+ assert.equal(compareRuntimeVersions('0.1.1', '0.1.1-canary.99.1.abcdef0') > 0, true);
14
+ assert.equal(compareRuntimeVersions('0.1.1-canary.1', '0.1.1') < 0, true);
15
+ assert.equal(compareRuntimeVersions('0.2.0', '0.1.9-canary.99') > 0, true);
16
+ });
17
+ test('runtime upgrade status is track-scoped and includes idle gate state', async () => {
18
+ const rootDir = await mkdtemp(join(tmpdir(), 'anima-runtime-upgrade-status-'));
19
+ try {
20
+ await withAnimaHome(rootDir, async () => {
21
+ await defaultServerSettingsService.setReleaseTrack('canary');
22
+ const checkStore = new RuntimeUpgradeCheckStore();
23
+ await checkStore.write({
24
+ checkedAt: '2026-05-29T09:00:00.000Z',
25
+ latestOnTrack: '0.1.1-canary.5.1.723b529',
26
+ releaseTrack: 'canary',
27
+ });
28
+ const status = await new RuntimeUpgradeService({
29
+ checkStore,
30
+ distTagLookup: async ({ packageName, tag }) => {
31
+ assert.equal(packageName, '@meetquinn/animactl');
32
+ assert.equal(tag, 'canary');
33
+ return '0.1.1-canary.5.1.723b529';
34
+ },
35
+ now: () => new Date('2026-05-29T09:10:00.000Z'),
36
+ packageVersion: async () => '0.1.1-canary.4.1.0688e3f',
37
+ }).status();
38
+ assert.equal(status.currentVersion, '0.1.1-canary.4.1.0688e3f');
39
+ assert.equal(status.releaseTrack, 'canary');
40
+ assert.equal(status.latestOnTrack, '0.1.1-canary.5.1.723b529');
41
+ assert.equal(status.state, 'available');
42
+ assert.equal(status.updateAvailable, true);
43
+ assert.equal(status.gate.state, 'idle');
44
+ assert.deepEqual(status.gate.blockers, []);
45
+ assert.equal(status.operation.status, 'idle');
46
+ });
47
+ }
48
+ finally {
49
+ await rm(rootDir, { force: true, recursive: true });
50
+ }
51
+ });
52
+ test('runtime upgrade gate reports running blockers and ignores queued items', async () => {
53
+ const rootDir = await mkdtemp(join(tmpdir(), 'anima-runtime-upgrade-running-gate-'));
54
+ try {
55
+ await withAnimaHome(rootDir, async () => {
56
+ await writeAgentQueueFixture(rootDir, 'scout', [
57
+ queueItem('item_queued', 'queued'),
58
+ queueItem('item_running', 'running'),
59
+ ]);
60
+ const status = await new RuntimeUpgradeService({
61
+ checkTtlMs: Number.MAX_SAFE_INTEGER,
62
+ distTagLookup: async () => '0.1.2',
63
+ packageVersion: async () => '0.1.1',
64
+ }).status();
65
+ assert.equal(status.gate.state, 'busy');
66
+ assert.deepEqual(status.gate.blockers.map((blocker) => ({ itemId: blocker.itemId, status: blocker.status })), [{ itemId: 'item_running', status: 'running' }]);
67
+ });
68
+ }
69
+ finally {
70
+ await rm(rootDir, { force: true, recursive: true });
71
+ }
72
+ });
73
+ test('runtime upgrade worker rolls metadata back when target artifact is incomplete before restart', async () => {
74
+ const rootDir = await mkdtemp(join(tmpdir(), 'anima-runtime-upgrade-worker-'));
75
+ const fakeNpm = join(rootDir, 'fake-npm.cjs');
76
+ await writeFakeNpm(fakeNpm);
77
+ const server = createServer((req, res) => {
78
+ if (req.url === '/api/health') {
79
+ res.writeHead(200, { 'content-type': 'application/json' });
80
+ res.end('{"ok":true}');
81
+ return;
82
+ }
83
+ if (req.url === '/api/server-info') {
84
+ res.writeHead(200, { 'content-type': 'application/json' });
85
+ res.end(JSON.stringify({
86
+ animaHome: rootDir,
87
+ dashboardPort: 4174,
88
+ ok: true,
89
+ startedAt: '2026-05-29T08:18:33.000Z',
90
+ track: 'stable',
91
+ uptimeSeconds: 10,
92
+ version: '0.1.1',
93
+ }));
94
+ return;
95
+ }
96
+ res.writeHead(404);
97
+ res.end();
98
+ });
99
+ try {
100
+ await new Promise((resolve, reject) => {
101
+ server.listen(0, '127.0.0.1', resolve);
102
+ server.once('error', reject);
103
+ });
104
+ const address = server.address();
105
+ if (!address || typeof address === 'string')
106
+ throw new Error('Expected TCP address');
107
+ await withAnimaHome(rootDir, async () => {
108
+ await assert.rejects(() => runRuntimeUpgradeWorker({
109
+ dashboardPort: address.port,
110
+ npmCommand: fakeNpm,
111
+ previousVersion: '0.1.1',
112
+ releaseTrack: 'stable',
113
+ targetVersion: '0.1.2',
114
+ verifyTimeoutMs: 50,
115
+ }), /Installed runtime template missing/);
116
+ const operation = JSON.parse(await readFile(join(rootDir, 'runtime', 'upgrade-status.json'), 'utf8'));
117
+ assert.equal(operation.status, 'failed');
118
+ assert.equal(operation.rollback, 'succeeded');
119
+ const installed = JSON.parse(await readFile(join(rootDir, 'runtime', 'current', 'node_modules', '@meetquinn', 'animactl', 'package.json'), 'utf8'));
120
+ assert.equal(installed.version, '0.1.1');
121
+ });
122
+ }
123
+ finally {
124
+ await new Promise((resolve) => server.close(() => resolve()));
125
+ await rm(rootDir, { force: true, recursive: true });
126
+ }
127
+ });
128
+ async function writeFakeNpm(path) {
129
+ await writeFile(path, `#!/usr/bin/env node
130
+ const { mkdirSync, writeFileSync } = require('node:fs');
131
+ const { join } = require('node:path');
132
+ const args = process.argv.slice(2);
133
+ const prefix = args[args.indexOf('--prefix') + 1];
134
+ const spec = args[args.length - 1];
135
+ const version = spec.slice(spec.lastIndexOf('@') + 1);
136
+ const packageDir = join(prefix, 'node_modules', '@meetquinn', 'animactl');
137
+ mkdirSync(join(packageDir, 'dist', 'server', 'cli'), { recursive: true });
138
+ writeFileSync(join(packageDir, 'package.json'), JSON.stringify({ name: '@meetquinn/animactl', version }, null, 2));
139
+ writeFileSync(join(packageDir, 'dist', 'server', 'cli', 'animactl.js'), 'process.exit(0);\\n');
140
+ if (version !== '0.1.2') {
141
+ mkdirSync(join(packageDir, 'templates'), { recursive: true });
142
+ writeFileSync(join(packageDir, 'templates', 'runtime-standing-prompt.md'), 'prompt');
143
+ }
144
+ `, 'utf8');
145
+ await chmod(path, 0o755);
146
+ }
147
+ async function writeAgentQueueFixture(rootDir, agentId, items) {
148
+ const agentDir = join(rootDir, 'agents', agentId);
149
+ await mkdir(agentDir, { recursive: true });
150
+ await writeFile(join(agentDir, 'config.json'), `${JSON.stringify({ id: agentId }, null, 2)}\n`, 'utf8');
151
+ await writeFile(join(agentDir, 'inbox.json'), `${JSON.stringify(Object.fromEntries(items.map((item) => [String(item['id']), item])), null, 2)}\n`, 'utf8');
152
+ }
153
+ function queueItem(id, status) {
154
+ const createdAt = '2026-05-29T08:00:00.000Z';
155
+ const handling = {
156
+ createdAt,
157
+ queuedAt: '2026-05-29T08:00:01.000Z',
158
+ status,
159
+ updatedAt: status === 'running' ? '2026-05-29T08:00:02.000Z' : '2026-05-29T08:00:01.000Z',
160
+ };
161
+ if (status === 'running') {
162
+ handling['startedAt'] = '2026-05-29T08:00:02.000Z';
163
+ handling['workerId'] = 'scout:12345';
164
+ }
165
+ return {
166
+ channelId: 'D1',
167
+ handling,
168
+ id,
169
+ kind: 'slack',
170
+ messageTs: '1780040000.000001',
171
+ receivedAt: createdAt,
172
+ teamId: 'T1',
173
+ text: id,
174
+ };
175
+ }
176
+ test('runtime upgrade status degrades cleanly when npm check fails', async () => {
177
+ const rootDir = await mkdtemp(join(tmpdir(), 'anima-runtime-upgrade-fail-'));
178
+ try {
179
+ await withAnimaHome(rootDir, async () => {
180
+ const checkStore = new RuntimeUpgradeCheckStore();
181
+ await checkStore.write({
182
+ checkedAt: '2026-05-29T09:00:00.000Z',
183
+ checkError: { message: 'Unable to check npm dist-tag: network unavailable', type: 'unknown' },
184
+ releaseTrack: 'stable',
185
+ });
186
+ const status = await new RuntimeUpgradeService({
187
+ checkStore,
188
+ distTagLookup: async () => {
189
+ throw new Error('network unavailable');
190
+ },
191
+ now: () => new Date('2026-05-29T09:10:00.000Z'),
192
+ packageVersion: async () => '0.1.1',
193
+ }).status();
194
+ assert.equal(status.releaseTrack, 'stable');
195
+ assert.equal(status.latestOnTrack, undefined);
196
+ assert.equal(status.state, 'error');
197
+ assert.equal(status.updateAvailable, false);
198
+ assert.equal(status.checkError?.type, 'unknown');
199
+ assert.match(status.checkError?.message ?? '', /network unavailable/);
200
+ });
201
+ }
202
+ finally {
203
+ await rm(rootDir, { force: true, recursive: true });
204
+ }
205
+ });
206
+ test('runtime upgrade status returns cached state immediately and refreshes in background', async () => {
207
+ const rootDir = await mkdtemp(join(tmpdir(), 'anima-runtime-upgrade-cache-'));
208
+ try {
209
+ await withAnimaHome(rootDir, async () => {
210
+ const checkStore = new RuntimeUpgradeCheckStore();
211
+ await checkStore.write({
212
+ checkedAt: '2026-05-29T08:00:00.000Z',
213
+ latestOnTrack: '0.1.2',
214
+ releaseTrack: 'stable',
215
+ });
216
+ let lookupCalls = 0;
217
+ const service = new RuntimeUpgradeService({
218
+ checkStore,
219
+ checkTtlMs: 0,
220
+ distTagLookup: async () => {
221
+ lookupCalls += 1;
222
+ await new Promise((resolve) => setTimeout(resolve, 20));
223
+ return '0.1.3';
224
+ },
225
+ now: () => new Date('2026-05-29T09:00:00.000Z'),
226
+ packageVersion: async () => '0.1.1',
227
+ });
228
+ const status = await service.status();
229
+ assert.equal(status.latestOnTrack, '0.1.2');
230
+ assert.equal(status.state, 'available');
231
+ assert.equal(lookupCalls, 1);
232
+ await waitFor(async () => (await checkStore.read()).latestOnTrack === '0.1.3');
233
+ });
234
+ }
235
+ finally {
236
+ await rm(rootDir, { force: true, recursive: true });
237
+ }
238
+ });
239
+ test('runtime upgrade checkNow refreshes npm dist-tag before returning', async () => {
240
+ const rootDir = await mkdtemp(join(tmpdir(), 'anima-runtime-upgrade-check-now-'));
241
+ try {
242
+ await withAnimaHome(rootDir, async () => {
243
+ await defaultServerSettingsService.setReleaseTrack('canary');
244
+ const checkStore = new RuntimeUpgradeCheckStore();
245
+ await checkStore.write({
246
+ checkedAt: '2026-05-29T08:00:00.000Z',
247
+ latestOnTrack: '0.1.1-canary.21.1.cd63d38',
248
+ releaseTrack: 'canary',
249
+ });
250
+ let lookupCalls = 0;
251
+ const service = new RuntimeUpgradeService({
252
+ checkStore,
253
+ distTagLookup: async ({ packageName, tag }) => {
254
+ lookupCalls += 1;
255
+ assert.equal(packageName, '@meetquinn/animactl');
256
+ assert.equal(tag, 'canary');
257
+ return '0.1.1-canary.22.1.d153e32';
258
+ },
259
+ now: () => new Date('2026-05-29T09:00:00.000Z'),
260
+ packageVersion: async () => '0.1.1-canary.21.1.cd63d38',
261
+ });
262
+ const status = await service.checkNow();
263
+ assert.equal(lookupCalls, 1);
264
+ assert.equal(status.checkedAt, '2026-05-29T09:00:00.000Z');
265
+ assert.equal(status.latestOnTrack, '0.1.1-canary.22.1.d153e32');
266
+ assert.equal(status.state, 'available');
267
+ assert.equal(status.updateAvailable, true);
268
+ assert.equal((await checkStore.read()).latestOnTrack, '0.1.1-canary.22.1.d153e32');
269
+ });
270
+ }
271
+ finally {
272
+ await rm(rootDir, { force: true, recursive: true });
273
+ }
274
+ });
275
+ test('runtime upgrade apply records a scheduled operation and prevents duplicate scheduling', async () => {
276
+ const rootDir = await mkdtemp(join(tmpdir(), 'anima-runtime-upgrade-apply-'));
277
+ try {
278
+ await withAnimaHome(rootDir, async () => {
279
+ const service = new RuntimeUpgradeService({
280
+ distTagLookup: async () => '0.1.2',
281
+ packageVersion: async () => '0.1.1',
282
+ });
283
+ const prepared = await service.prepareApply({
284
+ animactlScript: join(rootDir, 'dist', 'server', 'cli', 'animactl.js'),
285
+ dashboardPort: 4175,
286
+ previousStartedAt: '2026-05-29T08:18:33.000Z',
287
+ });
288
+ assert.equal(prepared.response.currentVersion, '0.1.1');
289
+ assert.equal(prepared.response.latestOnTrack, '0.1.2');
290
+ assert.equal(prepared.response.releaseTrack, 'stable');
291
+ assert.equal(prepared.response.scheduled, true);
292
+ await assert.rejects(() => service.prepareApply({ animactlScript: join(rootDir, 'dist', 'server', 'cli', 'animactl.js') }), RuntimeUpgradeConflictError);
293
+ });
294
+ }
295
+ finally {
296
+ await rm(rootDir, { force: true, recursive: true });
297
+ }
298
+ });
299
+ async function waitFor(predicate) {
300
+ const deadline = Date.now() + 1000;
301
+ while (Date.now() < deadline) {
302
+ if (await predicate())
303
+ return;
304
+ await new Promise((resolve) => setTimeout(resolve, 10));
305
+ }
306
+ assert.fail('condition did not become true before timeout');
307
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=runtime-worker.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-worker.test.d.ts","sourceRoot":"","sources":["../../../server/tests/runtime-worker.test.ts"],"names":[],"mappings":""}