pi-harness-runtime 1.1.439 → 1.1.441

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 (359) hide show
  1. package/harness/e2e/auto-test-loop.ts +8 -2
  2. package/harness/e2e/browser-scrapers/base-browser-scraper.ts +2 -0
  3. package/harness/e2e/browser-scrapers/chrome-profile-manager.ts +2 -0
  4. package/harness/e2e/browser-scrapers/codex-browser-scraper.ts +2 -0
  5. package/harness/e2e/tools-detector.ts +2 -0
  6. package/harness/index.ts +2 -1
  7. package/harness/key-loader.ts +2 -0
  8. package/harness/langchain/checkpointer.ts +2 -0
  9. package/harness/langchain/cron-cli.ts +2 -0
  10. package/harness/langchain/graph.ts +2 -0
  11. package/harness/master-planner.ts +1 -1
  12. package/harness/notification-center.ts +2 -0
  13. package/harness/output-limit-handler.ts +1 -1
  14. package/harness/project-detector/detector.ts +2 -4
  15. package/harness/secret-provider.ts +2 -0
  16. package/harness/task-graph.ts +460 -113
  17. package/index.ts +16 -7
  18. package/package.json +7 -1
  19. package/packages/a2a-adapter/package.json +1 -1
  20. package/packages/agent-policy/dist/extension.d.ts.map +1 -1
  21. package/packages/agent-policy/dist/extension.js +2 -0
  22. package/packages/agent-policy/dist/extension.js.map +1 -1
  23. package/packages/agent-policy/package.json +1 -1
  24. package/packages/agent-policy/src/extension.ts +2 -0
  25. package/packages/architecture-generator/package.json +1 -1
  26. package/packages/auth/dist/minimax-browser-auth.d.ts.map +1 -1
  27. package/packages/auth/dist/minimax-browser-auth.js +23 -1
  28. package/packages/auth/dist/minimax-browser-auth.js.map +1 -1
  29. package/packages/auth/package.json +1 -1
  30. package/packages/auth/src/minimax-browser-auth.ts +30 -5
  31. package/packages/autonomous-refactor/package.json +1 -1
  32. package/packages/autonomous-runtime/dist/inbox.d.ts.map +1 -1
  33. package/packages/autonomous-runtime/dist/inbox.js +2 -0
  34. package/packages/autonomous-runtime/dist/inbox.js.map +1 -1
  35. package/packages/autonomous-runtime/package.json +1 -1
  36. package/packages/autonomous-runtime/src/inbox.ts +2 -0
  37. package/packages/cache-strategy/package.json +1 -1
  38. package/packages/capability-registry/package.json +1 -1
  39. package/packages/checkpoint/package.json +1 -1
  40. package/packages/cli-plugin-sdk/package.json +1 -1
  41. package/packages/clipboard/dist/src/clipboard.d.ts.map +1 -1
  42. package/packages/clipboard/dist/src/clipboard.js +2 -0
  43. package/packages/clipboard/dist/src/clipboard.js.map +1 -1
  44. package/packages/clipboard/dist/src/copy-sync.d.ts.map +1 -1
  45. package/packages/clipboard/dist/src/copy-sync.js +2 -0
  46. package/packages/clipboard/dist/src/copy-sync.js.map +1 -1
  47. package/packages/clipboard/dist/src/gist-relay.d.ts.map +1 -1
  48. package/packages/clipboard/dist/src/gist-relay.js +2 -0
  49. package/packages/clipboard/dist/src/gist-relay.js.map +1 -1
  50. package/packages/clipboard/package.json +1 -1
  51. package/packages/clipboard/src/clipboard.ts +2 -0
  52. package/packages/clipboard/src/copy-sync.ts +2 -0
  53. package/packages/clipboard/src/gist-relay.ts +2 -0
  54. package/packages/clipboard-plugin/dist/types.d.ts +9 -2
  55. package/packages/clipboard-plugin/dist/types.d.ts.map +1 -1
  56. package/packages/clipboard-plugin/package.json +1 -1
  57. package/packages/clipboard-plugin/src/types.ts +9 -2
  58. package/packages/code-generation/package.json +1 -1
  59. package/packages/code-review/package.json +1 -1
  60. package/packages/codex-adapter/package.json +1 -1
  61. package/packages/codex-watcher/package.json +1 -1
  62. package/packages/config-capture/package.json +1 -1
  63. package/packages/connection-runtime/package.json +1 -1
  64. package/packages/context-compiler/package.json +1 -1
  65. package/packages/context-discovery/package.json +1 -1
  66. package/packages/context-manager/package.json +1 -1
  67. package/packages/contracts/dist/delegation-store.js +1 -4
  68. package/packages/contracts/dist/workspace-env.js +28 -1
  69. package/packages/contracts/package.json +1 -1
  70. package/packages/contracts/src/delegation-store.ts +9 -4
  71. package/packages/contracts/src/workspace-env.ts +29 -4
  72. package/packages/cookie-sanitizer/package.json +1 -1
  73. package/packages/cost-optimizer/package.json +1 -1
  74. package/packages/dependency-analyzer/package.json +1 -1
  75. package/packages/django-plugin/package.json +1 -1
  76. package/packages/doc-generator/package.json +1 -1
  77. package/packages/durable-review/package.json +1 -1
  78. package/packages/e2e-tester/package.json +1 -1
  79. package/packages/evaluation-engine/package.json +1 -1
  80. package/packages/evaluation-runner/package.json +1 -1
  81. package/packages/event-bus/package.json +1 -1
  82. package/packages/event-sink/package.json +1 -1
  83. package/packages/event-store/dist/src/store.d.ts.map +1 -1
  84. package/packages/event-store/dist/src/store.js +2 -0
  85. package/packages/event-store/dist/src/store.js.map +1 -1
  86. package/packages/event-store/package.json +1 -1
  87. package/packages/event-store/src/store.ts +3 -0
  88. package/packages/experience-replay/package.json +1 -1
  89. package/packages/feedback-collector/package.json +1 -1
  90. package/packages/file-copy-helper/package.json +1 -1
  91. package/packages/framework-detector/package.json +1 -1
  92. package/packages/framework-plugin-sdk/package.json +1 -1
  93. package/packages/frappe-plugin/package.json +1 -1
  94. package/packages/generic-web-plugin/dist/analyzer.d.ts.map +1 -1
  95. package/packages/generic-web-plugin/dist/analyzer.js +2 -0
  96. package/packages/generic-web-plugin/dist/analyzer.js.map +1 -1
  97. package/packages/generic-web-plugin/package.json +1 -1
  98. package/packages/generic-web-plugin/src/analyzer.ts +3 -0
  99. package/packages/health-monitor/package.json +1 -1
  100. package/packages/intent-analyzer/package.json +1 -1
  101. package/packages/jev-judge/package.json +1 -1
  102. package/packages/knowledge-graph/package.json +1 -1
  103. package/packages/knowledge-retrieval/dist/mcp-client.d.ts.map +1 -1
  104. package/packages/knowledge-retrieval/dist/mcp-client.js +0 -1
  105. package/packages/knowledge-retrieval/dist/mcp-client.js.map +1 -1
  106. package/packages/knowledge-retrieval/package.json +1 -4
  107. package/packages/knowledge-retrieval/src/mcp-client.ts +0 -1
  108. package/packages/laravel-plugin/package.json +1 -1
  109. package/packages/learning-engine/package.json +1 -1
  110. package/packages/logging/package.json +1 -1
  111. package/packages/mcp-adapter/dist/server.d.ts.map +1 -1
  112. package/packages/mcp-adapter/dist/server.js +2 -0
  113. package/packages/mcp-adapter/dist/server.js.map +1 -1
  114. package/packages/mcp-adapter/package.json +1 -1
  115. package/packages/mcp-adapter/src/server.ts +3 -0
  116. package/packages/memory-engine/package.json +1 -1
  117. package/packages/milestone-manager/package.json +1 -1
  118. package/packages/model-registry/package.json +1 -1
  119. package/packages/nextjs-plugin/package.json +1 -1
  120. package/packages/notification/package.json +1 -1
  121. package/packages/observability/package.json +1 -1
  122. package/packages/okf-indexer/package.json +1 -1
  123. package/packages/paperclip-integration/dist/index.d.ts.map +1 -1
  124. package/packages/paperclip-integration/dist/index.js +2 -0
  125. package/packages/paperclip-integration/dist/index.js.map +1 -1
  126. package/packages/paperclip-integration/package.json +1 -1
  127. package/packages/paperclip-integration/src/index.ts +2 -0
  128. package/packages/performance-optimizer/package.json +1 -1
  129. package/packages/permission-mode/package.json +1 -1
  130. package/packages/privilege-broker/dist/audit.d.ts.map +1 -1
  131. package/packages/privilege-broker/dist/audit.js +2 -0
  132. package/packages/privilege-broker/dist/audit.js.map +1 -1
  133. package/packages/privilege-broker/package.json +1 -1
  134. package/packages/privilege-broker/src/audit.ts +2 -0
  135. package/packages/project-analyzer/package.json +1 -1
  136. package/packages/project-bootstrap/package.json +1 -1
  137. package/packages/projection-engine/package.json +1 -1
  138. package/packages/prompt-compiler/dist/compiler.d.ts.map +1 -1
  139. package/packages/prompt-compiler/dist/compiler.js +2 -0
  140. package/packages/prompt-compiler/dist/compiler.js.map +1 -1
  141. package/packages/prompt-compiler/package.json +1 -1
  142. package/packages/prompt-compiler/src/compiler.ts +2 -0
  143. package/packages/prompt-versioning/package.json +1 -1
  144. package/packages/provider-adapter-sdk/package.json +1 -1
  145. package/packages/provider-router/package.json +1 -1
  146. package/packages/provider-selector/package.json +1 -1
  147. package/packages/providers/package.json +1 -1
  148. package/packages/qdrant-skills/package.json +1 -1
  149. package/packages/quota-manager/package.json +1 -1
  150. package/packages/rate-limiter/package.json +1 -1
  151. package/packages/react-vite-plugin/package.json +1 -1
  152. package/packages/relay/package.json +1 -1
  153. package/packages/release-manager/package.json +1 -1
  154. package/packages/requirement-compiler/package.json +1 -1
  155. package/packages/runtime/package.json +1 -1
  156. package/packages/scheduler/package.json +1 -1
  157. package/packages/scheduler-adapter/package.json +1 -1
  158. package/packages/session/package.json +1 -1
  159. package/packages/session-api/package.json +1 -1
  160. package/packages/session-export/package.json +1 -1
  161. package/packages/shared-context/package.json +1 -1
  162. package/packages/skill-mcp-client/dist/client.d.ts.map +1 -1
  163. package/packages/skill-mcp-client/dist/client.js +0 -1
  164. package/packages/skill-mcp-client/dist/client.js.map +1 -1
  165. package/packages/skill-mcp-client/package.json +1 -4
  166. package/packages/skill-mcp-client/src/client.ts +0 -1
  167. package/packages/skill-registry/package.json +1 -1
  168. package/packages/skills/dist/parser.d.ts.map +1 -1
  169. package/packages/skills/dist/parser.js +2 -0
  170. package/packages/skills/dist/parser.js.map +1 -1
  171. package/packages/skills/dist/skill-versioning.d.ts.map +1 -1
  172. package/packages/skills/dist/skill-versioning.js +2 -0
  173. package/packages/skills/dist/skill-versioning.js.map +1 -1
  174. package/packages/skills/package.json +1 -1
  175. package/packages/skills/src/parser.ts +3 -0
  176. package/packages/skills/src/skill-versioning.ts +2 -0
  177. package/packages/sprint-planner/package.json +1 -1
  178. package/packages/subscription-engine/package.json +1 -1
  179. package/packages/task-compiler/package.json +1 -1
  180. package/packages/tencentdb-memory/package.json +1 -1
  181. package/packages/tencentdb-sync/package.json +1 -1
  182. package/packages/test-data-generator/package.json +1 -1
  183. package/packages/test-generator/package.json +1 -1
  184. package/packages/todo-bd-sync/package.json +1 -1
  185. package/packages/token-estimation/package.json +1 -1
  186. package/packages/token-optimizer/package.json +1 -1
  187. package/packages/tooling-preference/package.json +1 -1
  188. package/packages/trajectory/package.json +1 -1
  189. package/packages/tui/package.json +1 -1
  190. package/packages/two-phase-review/package.json +1 -1
  191. package/packages/types/package.json +1 -1
  192. package/packages/voice-api/package.json +1 -1
  193. package/packages/webmcp-tester/dist/index.js +0 -2
  194. package/packages/webmcp-tester/package.json +1 -1
  195. package/packages/webmcp-tester/src/index.ts +0 -3
  196. package/packages/wiki/package.json +1 -1
  197. package/packages/workflow-events/package.json +1 -1
  198. package/packages/workspace-scanner/package.json +1 -1
  199. package/packages/worktree/package.json +1 -1
  200. package/packages/write-review/dist/trigger.d.ts.map +1 -1
  201. package/packages/write-review/dist/trigger.js +1 -2
  202. package/packages/write-review/dist/trigger.js.map +1 -1
  203. package/packages/write-review/package.json +1 -1
  204. package/packages/write-review/src/trigger.ts +1 -2
  205. package/scripts/lib/runtime-imports.ts +189 -3
  206. package/scripts/release-all.ts +5 -3
  207. package/scripts/telegram-webhook-server.ts +2 -0
  208. package/scripts/typecheck-packages.mjs +7 -4
  209. package/scripts/verify-package-contents.ts +161 -2
  210. package/harness/e2e/tools-detector.test.ts +0 -156
  211. package/harness/glm-quota-countdown.test.ts +0 -323
  212. package/harness/langchain/agents.test.ts +0 -39
  213. package/harness/langchain/checkpointer.test.ts +0 -243
  214. package/harness/langchain/daemon.test.ts +0 -459
  215. package/harness/langchain/model-router.test.ts +0 -191
  216. package/harness/langchain/ping-pong-middleware.test.ts +0 -69
  217. package/harness/langchain/scoreboard.test.ts +0 -245
  218. package/harness/langchain/status-line.test.ts +0 -106
  219. package/harness/langchain/surge.test.ts +0 -467
  220. package/harness/langchain/widget.test.ts +0 -251
  221. package/harness/skill-sync.test.ts +0 -57
  222. package/harness/ssh-detach-interceptor.test.ts +0 -263
  223. package/harness/ssh-hang-recovery.test.ts +0 -86
  224. package/packages/a2a-adapter/test/a2a.test.ts +0 -151
  225. package/packages/agent-policy/test/interlock.test.ts +0 -101
  226. package/packages/agent-policy/test/policy-retention.test.ts +0 -380
  227. package/packages/agent-policy/test/policy.test.ts +0 -387
  228. package/packages/auth/test/auth.test.ts +0 -238
  229. package/packages/autonomous-refactor/test/refactor.test.ts +0 -202
  230. package/packages/autonomous-runtime/test/types.test.ts +0 -95
  231. package/packages/cache-strategy/test/cache.test.ts +0 -137
  232. package/packages/capability-registry/test/registry.test.ts +0 -204
  233. package/packages/checkpoint/test/engine.test.ts +0 -265
  234. package/packages/cli-plugin-sdk/test/cli.test.ts +0 -45
  235. package/packages/code-generation/test/generator.test.ts +0 -238
  236. package/packages/code-review/test/engine.test.ts +0 -302
  237. package/packages/codex-adapter/test/provider.test.ts +0 -142
  238. package/packages/codex-watcher/test/watch.test.ts +0 -453
  239. package/packages/context-compiler/test/context-compiler.test.ts +0 -746
  240. package/packages/context-manager/test/context.test.ts +0 -198
  241. package/packages/contracts/test/delegation.test.ts +0 -350
  242. package/packages/contracts/test/workspace-env.test.ts +0 -802
  243. package/packages/cookie-sanitizer/test/infer.test.ts +0 -110
  244. package/packages/cookie-sanitizer/test/normalize.test.ts +0 -113
  245. package/packages/cookie-sanitizer/test/parse.test.ts +0 -204
  246. package/packages/cookie-sanitizer/test/sync.test.ts +0 -237
  247. package/packages/cookie-sanitizer/test/watcher.test.ts +0 -27
  248. package/packages/cost-optimizer/test/cost-optimizer.test.ts +0 -438
  249. package/packages/dependency-analyzer/test/analyzer.test.ts +0 -49
  250. package/packages/django-plugin/test/analyzer.test.ts +0 -195
  251. package/packages/doc-generator/test/docs.test.ts +0 -168
  252. package/packages/durable-review/test/acceptance.test.ts +0 -357
  253. package/packages/durable-review/test/smoke.test.ts +0 -107
  254. package/packages/evaluation-engine/test/engine.test.ts +0 -277
  255. package/packages/evaluation-runner/test/runner.test.ts +0 -168
  256. package/packages/event-bus/test/bus.test.ts +0 -100
  257. package/packages/event-store/test/store.test.ts +0 -115
  258. package/packages/experience-replay/test/replay.test.ts +0 -267
  259. package/packages/feedback-collector/test/collector.test.ts +0 -142
  260. package/packages/framework-detector/test/detector.test.ts +0 -75
  261. package/packages/framework-plugin-sdk/test/manager.test.ts +0 -320
  262. package/packages/frappe-plugin/test/analyzer.test.ts +0 -250
  263. package/packages/generic-web-plugin/test/analyzer.test.ts +0 -134
  264. package/packages/health-monitor/test/health.test.ts +0 -231
  265. package/packages/intent-analyzer/test/analyzer.test.ts +0 -72
  266. package/packages/intent-analyzer/test/ping-pong.test.ts +0 -96
  267. package/packages/jev-judge/tests/auto-continue-context.test.ts +0 -280
  268. package/packages/jev-judge/tests/continuation-controller.test.ts +0 -1396
  269. package/packages/jev-judge/tests/jev-provider-chain.test.ts +0 -536
  270. package/packages/jev-judge/tests/outcome-application.test.ts +0 -132
  271. package/packages/jev-judge/tests/question-risk.test.ts +0 -129
  272. package/packages/jev-judge/tests/typesafe-provider.test.ts +0 -640
  273. package/packages/jev-judge/tests/validation-ledger.test.ts +0 -181
  274. package/packages/jev-judge/tests/validation-plan.test.ts +0 -170
  275. package/packages/jev-judge/tests/validation-tie-breaker.test.ts +0 -88
  276. package/packages/laravel-plugin/test/analyzer.test.ts +0 -220
  277. package/packages/learning-engine/test/engine.test.ts +0 -331
  278. package/packages/logging/test/buffer.test.ts +0 -44
  279. package/packages/logging/test/classification.test.ts +0 -137
  280. package/packages/logging/test/config.test.ts +0 -97
  281. package/packages/logging/test/fanout.test.ts +0 -186
  282. package/packages/logging/test/identity-transport.test.ts +0 -197
  283. package/packages/logging/test/incidents.test.ts +0 -404
  284. package/packages/logging/test/ingest-schema.test.ts +0 -184
  285. package/packages/logging/test/integration.test.ts +0 -140
  286. package/packages/logging/test/log-http.test.ts +0 -246
  287. package/packages/logging/test/redact.test.ts +0 -109
  288. package/packages/logging/test/sampler.test.ts +0 -57
  289. package/packages/logging/test/server.test.ts +0 -444
  290. package/packages/logging/test/shipper.test.ts +0 -152
  291. package/packages/logging/test/spool.test.ts +0 -96
  292. package/packages/mcp-adapter/test/server.test.ts +0 -91
  293. package/packages/memory-engine/test/engine.test.ts +0 -456
  294. package/packages/model-registry/test/registry.test.ts +0 -342
  295. package/packages/nextjs-plugin/test/analyzer.test.ts +0 -149
  296. package/packages/notification/test/approval-payload.test.ts +0 -269
  297. package/packages/notification/test/detail-format.test.ts +0 -106
  298. package/packages/notification/test/notification.test.ts +0 -375
  299. package/packages/notification/test/pending-question-lifecycle.test.ts +0 -195
  300. package/packages/notification/test/pending-question.test.ts +0 -331
  301. package/packages/notification/test/tooling-proposal-payload.test.ts +0 -212
  302. package/packages/observability/test/observability.test.ts +0 -1350
  303. package/packages/performance-optimizer/test/optimizer.test.ts +0 -267
  304. package/packages/project-analyzer/test/index.test.ts +0 -1719
  305. package/packages/prompt-compiler/test/prompt-compiler.test.ts +0 -813
  306. package/packages/prompt-versioning/test/versioning.test.ts +0 -112
  307. package/packages/provider-adapter-sdk/test/sdk.test.ts +0 -220
  308. package/packages/provider-router/test/provider-router.test.ts +0 -405
  309. package/packages/provider-selector/test/selector.test.ts +0 -192
  310. package/packages/providers/test/providers.test.ts +0 -225
  311. package/packages/qdrant-skills/test/collection-info.test.ts +0 -165
  312. package/packages/qdrant-skills/test/embedder-batch.test.ts +0 -184
  313. package/packages/qdrant-skills/test/embedder.test.ts +0 -97
  314. package/packages/quota-manager/test/quota.test.ts +0 -432
  315. package/packages/rate-limiter/test/limiter.test.ts +0 -128
  316. package/packages/react-vite-plugin/test/analyzer.test.ts +0 -139
  317. package/packages/relay/test/client.test.ts +0 -446
  318. package/packages/relay/test/relay-e2e.test.ts +0 -299
  319. package/packages/relay/test/relay-endpoint.test.ts +0 -278
  320. package/packages/release-manager/test/release.test.ts +0 -215
  321. package/packages/requirement-compiler/test/requirement-compiler.test.ts +0 -743
  322. package/packages/runtime/test/runtime-api.test.ts +0 -169
  323. package/packages/runtime/test/runtime.test.ts +0 -297
  324. package/packages/scheduler/test/scheduler.test.ts +0 -125
  325. package/packages/session/test/manager.test.ts +0 -233
  326. package/packages/shared-context/test/shared-context.test.ts +0 -114
  327. package/packages/skill-registry/test/registry.test.ts +0 -508
  328. package/packages/skills/test/init-skills.test.ts +0 -114
  329. package/packages/skills/test/remote-skills.test.ts +0 -360
  330. package/packages/skills/test/remote-source.test.ts +0 -248
  331. package/packages/skills/test/sanitize.test.ts +0 -250
  332. package/packages/skills/test/vector-indexing.test.ts +0 -205
  333. package/packages/skills/test/vector-schema.test.ts +0 -180
  334. package/packages/skills/test/vector-threshold.test.ts +0 -108
  335. package/packages/sprint-planner/test/planner.test.ts +0 -187
  336. package/packages/task-compiler/test/task-compiler.test.ts +0 -628
  337. package/packages/test-data-generator/test/generator.test.ts +0 -265
  338. package/packages/test-generator/test/generator.test.ts +0 -156
  339. package/packages/token-estimation/test/token-estimation.test.ts +0 -207
  340. package/packages/token-optimizer/test/optimizer.test.ts +0 -141
  341. package/packages/tooling-preference/tests/changed-files.test.ts +0 -124
  342. package/packages/tooling-preference/tests/detect.test.ts +0 -188
  343. package/packages/tooling-preference/tests/proposal.test.ts +0 -107
  344. package/packages/tooling-preference/tests/quality-check.test.ts +0 -272
  345. package/packages/tooling-preference/tests/registry.test.ts +0 -51
  346. package/packages/tooling-preference/tests/store.test.ts +0 -99
  347. package/packages/trajectory/test/store.test.ts +0 -250
  348. package/packages/tui/test/harness-footer.test.ts +0 -559
  349. package/packages/tui/test/harness-header.test.ts +0 -590
  350. package/packages/two-phase-review/test/classify.test.ts +0 -102
  351. package/packages/two-phase-review/test/helpers.ts +0 -72
  352. package/packages/two-phase-review/test/rules.test.ts +0 -150
  353. package/packages/two-phase-review/test/runtime.test.ts +0 -362
  354. package/packages/two-phase-review/test/scope.test.ts +0 -186
  355. package/packages/two-phase-review/test/signals.test.ts +0 -183
  356. package/packages/two-phase-review/test/state.test.ts +0 -201
  357. package/packages/wiki/test/basic.test.ts +0 -242
  358. package/packages/workspace-scanner/test/scanner.test.ts +0 -43
  359. package/packages/worktree/test/worktree.test.ts +0 -163
@@ -1,169 +0,0 @@
1
- /**
2
- * Runtime API tests — the job actions and the states they use.
3
- *
4
- * The API stores the job machine the harness registers and moves the job
5
- * through the state machine. The states are the ones the state machine
6
- * actually has: `paused_quota` is its only paused state, and there is no
7
- * plain `paused` status.
8
- */
9
-
10
- import { describe, it, expect, beforeEach, afterEach } from "bun:test";
11
- import {
12
- RuntimeApi,
13
- type JobStateMachineLike,
14
- type JobTransitionResult,
15
- } from "../src/runtime-api.js";
16
- import type {
17
- JobStatus,
18
- RuntimeCheckpoint,
19
- } from "../../types/dist/runtime-types.js";
20
-
21
- /** The states the fake machine accepts. */
22
- const ACCEPTED: JobStatus[] = ["running", "paused_quota", "cancelled"];
23
-
24
- /** The envelope every API response uses. */
25
- interface ApiResponseBody<T> {
26
- success: boolean;
27
- data?: T;
28
- error?: string;
29
- }
30
-
31
- /** Read the JSON body of a response. */
32
- async function readJson<T>(res: Response): Promise<ApiResponseBody<T>> {
33
- return (await res.json()) as ApiResponseBody<T>;
34
- }
35
-
36
- /** A job machine that records the moves the API asks for. */
37
- class FakeMachine implements JobStateMachineLike {
38
- status: JobStatus = "running";
39
- readonly moves: JobStatus[] = [];
40
-
41
- getStatusSummary() {
42
- return {
43
- status: this.status,
44
- isTerminal: this.status === "cancelled",
45
- canResume: this.status === "paused_quota",
46
- };
47
- }
48
-
49
- getCheckpoint(): RuntimeCheckpoint {
50
- return {
51
- version: 1,
52
- jobId: "job-1",
53
- status: this.status,
54
- requirement: "do the thing",
55
- createdAt: "2026-01-01T00:00:00.000Z",
56
- updatedAt: "2026-01-01T00:00:00.000Z",
57
- };
58
- }
59
-
60
- async resumeJob(): Promise<JobTransitionResult> {
61
- return { success: true };
62
- }
63
-
64
- async transition(to: JobStatus): Promise<JobTransitionResult> {
65
- this.moves.push(to);
66
- if (!ACCEPTED.includes(to)) {
67
- return { success: false, error: `Invalid transition to ${to}` };
68
- }
69
- this.status = to;
70
- return { success: true };
71
- }
72
- }
73
-
74
- describe("RuntimeApi job actions", () => {
75
- let api: RuntimeApi;
76
- let machine: FakeMachine;
77
- let base: string;
78
-
79
- beforeEach(async () => {
80
- api = new RuntimeApi({ port: 0, host: "127.0.0.1" });
81
- machine = new FakeMachine();
82
- api.registerJob("job-1", machine);
83
- await api.start();
84
- base = `http://127.0.0.1:${api.getPort()}`;
85
- });
86
-
87
- afterEach(async () => {
88
- await api.stop();
89
- });
90
-
91
- it("pauses a job into the state the machine has", async () => {
92
- const res = await fetch(`${base}/jobs/job-1?action=pause`, {
93
- method: "POST",
94
- });
95
-
96
- expect(res.status).toBe(200);
97
- expect(machine.moves).toEqual(["paused_quota"]);
98
- expect(machine.status).toBe("paused_quota");
99
- });
100
-
101
- it("resumes a paused job", async () => {
102
- await fetch(`${base}/jobs/job-1?action=pause`, { method: "POST" });
103
- machine.moves.length = 0;
104
-
105
- const res = await fetch(`${base}/jobs/job-1?action=resume`, {
106
- method: "POST",
107
- });
108
-
109
- expect(res.status).toBe(200);
110
- expect(machine.moves).toEqual(["running"]);
111
- expect(machine.status).toBe("running");
112
- });
113
-
114
- it("cancels a job", async () => {
115
- const res = await fetch(`${base}/jobs/job-1?action=cancel`, {
116
- method: "POST",
117
- });
118
-
119
- expect(res.status).toBe(200);
120
- expect(machine.status).toBe("cancelled");
121
- });
122
-
123
- it("reports a refused move instead of a false success", async () => {
124
- const refusing = new FakeMachine();
125
- refusing.transition = async (to: JobStatus) => {
126
- refusing.moves.push(to);
127
- return { success: false, error: "the state machine refused the move" };
128
- };
129
- api.registerJob("job-2", refusing);
130
-
131
- const res = await fetch(`${base}/jobs/job-2?action=pause`, {
132
- method: "POST",
133
- });
134
-
135
- expect(res.status).toBe(409);
136
- const body = await readJson<never>(res);
137
- expect(body.error).toBe("the state machine refused the move");
138
- });
139
-
140
- it("rejects an unknown action", async () => {
141
- const res = await fetch(`${base}/jobs/job-1?action=explode`, {
142
- method: "POST",
143
- });
144
-
145
- expect(res.status).toBe(400);
146
- expect(machine.moves).toEqual([]);
147
- });
148
-
149
- it("counts a paused job as paused", async () => {
150
- await fetch(`${base}/jobs/job-1?action=pause`, { method: "POST" });
151
-
152
- const res = await fetch(`${base}/status`);
153
- const body = await readJson<{
154
- jobs: { total: number; active: number; paused: number; completed: number };
155
- }>(res);
156
-
157
- expect(body.data?.jobs.total).toBe(1);
158
- expect(body.data?.jobs.paused).toBe(1);
159
- expect(body.data?.jobs.active).toBe(0);
160
- });
161
-
162
- it("reports an unknown job", async () => {
163
- const res = await fetch(`${base}/jobs/nope?action=pause`, {
164
- method: "POST",
165
- });
166
-
167
- expect(res.status).toBe(404);
168
- });
169
- });
@@ -1,297 +0,0 @@
1
- /**
2
- * Runtime Tests — Policy Engine & Runtime API
3
- */
4
-
5
- import { describe, it, expect, beforeEach } from "bun:test";
6
- import {
7
- PolicyEngine,
8
- createHarnessPolicyEngine,
9
- type PolicyContext,
10
- } from "../src/policy-engine.js";
11
-
12
- describe("PolicyEngine", () => {
13
- let engine: PolicyEngine;
14
-
15
- beforeEach(() => {
16
- engine = new PolicyEngine();
17
- });
18
-
19
- describe("defaults", () => {
20
- it("denies rm -rf /", () => {
21
- const result = engine.canExecuteCommand("rm -rf /");
22
- expect(result.effect).toBe("deny");
23
- });
24
-
25
- it("allows git commands", () => {
26
- const result = engine.canExecuteCommand("git status");
27
- expect(result.effect).toBe("allow");
28
- });
29
-
30
- it("allows npm/npx commands", () => {
31
- expect(engine.canExecuteCommand("npm install").effect).toBe("allow");
32
- expect(engine.canExecuteCommand("npx test").effect).toBe("allow");
33
- });
34
-
35
- it("allows HTTPS network requests", () => {
36
- const result = engine.canMakeNetworkRequest("https://api.example.com");
37
- expect(result.effect).toBe("allow");
38
- });
39
-
40
- it("denies HTTP network requests by default", () => {
41
- const result = engine.canMakeNetworkRequest(
42
- "http://insecure.example.com",
43
- );
44
- expect(result.effect).toBe("ask"); // Default ask, not explicit deny
45
- });
46
-
47
- it("denies private network access", () => {
48
- const result = engine.canMakeNetworkRequest("10.0.0.1");
49
- expect(result.effect).toBe("deny");
50
- });
51
-
52
- it("denies localhost network access", () => {
53
- const result = engine.canMakeNetworkRequest("localhost");
54
- expect(result.effect).toBe("deny");
55
- });
56
-
57
- it("denies file access outside workspace (.. paths)", () => {
58
- const result = engine.canAccessFile("../secret.txt", "read");
59
- expect(result.effect).toBe("deny");
60
- });
61
-
62
- it("defaults to ask for unknown resources", () => {
63
- const ctx: PolicyContext = {
64
- subject: {},
65
- resource: { type: "command", path: "unknown-cmd" },
66
- };
67
- const result = engine.evaluate(ctx);
68
- expect(result.effect).toBe("ask");
69
- });
70
- });
71
-
72
- describe("addPolicy / removePolicy", () => {
73
- it("adds a custom allow policy", () => {
74
- engine.addPolicy({
75
- id: "allow-my-cmd",
76
- name: "Allow my command",
77
- priority: 5,
78
- effect: "allow",
79
- condition: {
80
- resource: { pathPattern: "^my-script" },
81
- },
82
- });
83
-
84
- const result = engine.canExecuteCommand("my-script.sh");
85
- expect(result.effect).toBe("allow");
86
- });
87
-
88
- it("higher priority policies override lower", () => {
89
- engine.addPolicy({
90
- id: "allow-any",
91
- name: "Allow all",
92
- priority: 1,
93
- effect: "allow",
94
- condition: { resource: { type: "command" } },
95
- });
96
- engine.addPolicy({
97
- id: "deny-specific",
98
- name: "Deny specific",
99
- priority: 50,
100
- effect: "deny",
101
- condition: {
102
- resource: { pathPattern: "git" },
103
- },
104
- });
105
-
106
- const result = engine.canExecuteCommand("git status");
107
- expect(result.effect).toBe("deny");
108
- });
109
-
110
- it("removes policy by id", () => {
111
- engine.addPolicy({
112
- id: "temp-policy",
113
- name: "Temp",
114
- priority: 5,
115
- effect: "allow",
116
- condition: { resource: { type: "command" } },
117
- });
118
- expect(engine.removePolicy("temp-policy")).toBe(true);
119
- expect(engine.removePolicy("nonexistent")).toBe(false);
120
- });
121
-
122
- it("getPolicies returns all policies", () => {
123
- engine.addPolicy({
124
- id: "p1",
125
- name: "Policy 1",
126
- priority: 1,
127
- effect: "allow",
128
- condition: { resource: { type: "command" } },
129
- });
130
- const policies = engine.getPolicies();
131
- expect(policies.some((p) => p.id === "p1")).toBe(true);
132
- });
133
- });
134
-
135
- describe("canExecuteCommand", () => {
136
- it("returns policy name in result", () => {
137
- const result = engine.canExecuteCommand("git status");
138
- expect(result.policy).toBeDefined();
139
- });
140
- });
141
-
142
- describe("canAccessFile", () => {
143
- it("allows reading safe paths", () => {
144
- const result = engine.canAccessFile("/home/project/src/index.ts", "read");
145
- expect(result.effect).not.toBe("deny");
146
- });
147
- });
148
-
149
- describe("canMakeNetworkRequest", () => {
150
- it("allows github HTTPS", () => {
151
- const result = engine.canMakeNetworkRequest("https://github.com/api");
152
- expect(result.effect).toBe("allow");
153
- });
154
- });
155
-
156
- describe("addCommandRule", () => {
157
- it("adds regex-based command rule", () => {
158
- engine.addCommandRule(/^curl\s+/, "allow", "curl allowed");
159
- const result = engine.canExecuteCommand("curl https://example.com");
160
- expect(result.effect).toBe("allow");
161
- expect(result.reason).toBe("curl allowed");
162
- });
163
- });
164
-
165
- describe("addFileRule", () => {
166
- it("adds regex-based file rule", () => {
167
- engine.addFileRule(/\.log$/, "deny", "No log files");
168
- const result = engine.canAccessFile("/tmp/debug.log", "read");
169
- expect(result.effect).toBe("deny");
170
- });
171
- });
172
-
173
- describe("addNetworkRule", () => {
174
- it("adds regex-based network rule", () => {
175
- engine.addNetworkRule(
176
- /internal\.company\.com/,
177
- "deny",
178
- "Internal hosts blocked",
179
- );
180
- const result = engine.canMakeNetworkRequest(
181
- "https://internal.company.com",
182
- );
183
- expect(result.effect).toBe("deny");
184
- });
185
- });
186
-
187
- describe("rate limiting", () => {
188
- it("enforces rate limits via custom policy", () => {
189
- // Add policy with custom rate limit condition
190
- let callCount = 0;
191
- engine.addPolicy({
192
- id: "rate-limit-test",
193
- name: "Rate Limit Test",
194
- priority: 50,
195
- effect: "deny",
196
- condition: {
197
- resource: { type: "command" },
198
- custom: () => {
199
- callCount++;
200
- return callCount > 3;
201
- },
202
- },
203
- reason: "Rate limit exceeded",
204
- });
205
-
206
- // First 3 should be allowed (no policy match)
207
- expect(engine.canExecuteCommand("git status").effect).toBe("allow");
208
- expect(engine.canExecuteCommand("git status").effect).toBe("allow");
209
- expect(engine.canExecuteCommand("git status").effect).toBe("allow");
210
-
211
- // 4th should be denied
212
- const result = engine.canExecuteCommand("git status");
213
- expect(result.effect).toBe("deny");
214
- });
215
-
216
- it("getRateLimit returns configured limit", () => {
217
- engine.setRateLimit("network", { maxRequests: 50, windowMs: 60000 });
218
- const limit = engine.getRateLimit("network");
219
- expect(limit?.maxRequests).toBe(50);
220
- expect(limit?.windowMs).toBe(60000);
221
- });
222
- });
223
-
224
- describe("audit log", () => {
225
- it("logs audited policies", () => {
226
- engine.addPolicy({
227
- id: "audit-test",
228
- name: "Audit Test",
229
- priority: 5,
230
- effect: "allow",
231
- audit: true,
232
- condition: {
233
- resource: { type: "command", pathPattern: "^test-audit" },
234
- },
235
- });
236
-
237
- engine.canExecuteCommand("test-audit");
238
- const log = engine.getAuditLog();
239
- expect(log.length).toBeGreaterThan(0);
240
- });
241
-
242
- it("filters audit log by effect", () => {
243
- engine.clearAuditLog();
244
- const log = engine.getAuditLog({ effect: "deny" });
245
- expect(Array.isArray(log)).toBe(true);
246
- });
247
-
248
- it("clears audit log", () => {
249
- engine.clearAuditLog();
250
- expect(engine.getAuditLog()).toEqual([]);
251
- });
252
- });
253
-
254
- describe("export/import policies", () => {
255
- it("exports policies as JSON", () => {
256
- const json = engine.exportPolicies();
257
- expect(json).toContain("policies");
258
- expect(json).toContain("commandRules");
259
- });
260
-
261
- it("imports policies from JSON", () => {
262
- const original = engine.exportPolicies();
263
- const imported = new PolicyEngine();
264
- expect(imported.importPolicies(original)).toBe(true);
265
-
266
- // After import, should still deny rm -rf
267
- expect(imported.canExecuteCommand("rm -rf /").effect).toBe("deny");
268
- });
269
-
270
- it("returns false for invalid JSON", () => {
271
- expect(engine.importPolicies("not valid json")).toBe(false);
272
- });
273
- });
274
- });
275
-
276
- describe("createHarnessPolicyEngine", () => {
277
- it("creates engine with harness-specific policies", () => {
278
- const engine = createHarnessPolicyEngine();
279
-
280
- // Should still deny dangerous commands
281
- expect(engine.canExecuteCommand("rm -rf /").effect).toBe("deny");
282
-
283
- // Should allow harness internal commands
284
- expect(engine.canExecuteCommand("pi-status").effect).toBe("allow");
285
- expect(engine.canExecuteCommand("harness-status").effect).toBe("allow");
286
-
287
- // Should deny system commands
288
- expect(engine.canExecuteCommand("sudo rm /").effect).toBe("deny");
289
- });
290
-
291
- it("has rate limits configured", () => {
292
- const engine = createHarnessPolicyEngine();
293
- expect(engine.getRateLimit("command")?.maxRequests).toBe(60);
294
- expect(engine.getRateLimit("network")?.maxRequests).toBe(100);
295
- expect(engine.getRateLimit("file")?.maxRequests).toBe(200);
296
- });
297
- });
@@ -1,125 +0,0 @@
1
- /**
2
- * Scheduler Tests
3
- */
4
-
5
- import { describe, it, expect, beforeEach } from "bun:test";
6
- import { mkdirSync, rmSync } from "node:fs";
7
- import { join } from "node:path";
8
- import { JsonRuntimeScheduler } from "../src/scheduler";
9
-
10
- const TMP = join(process.cwd(), ".test-scheduler-tmp");
11
-
12
- function scheduler(): JsonRuntimeScheduler {
13
- return new JsonRuntimeScheduler(TMP);
14
- }
15
-
16
- beforeEach(() => {
17
- rmSync(TMP, { force: true, recursive: true });
18
- mkdirSync(TMP, { recursive: true });
19
- });
20
-
21
- describe("JsonRuntimeScheduler", () => {
22
- describe("scheduleResume", () => {
23
- it("writes a job to schedule.json", async () => {
24
- const s = scheduler();
25
- await s.scheduleResume("job-1", "2025-01-01T12:00:00Z", "test reason");
26
- const jobs = await s.readAll();
27
- expect(jobs).toHaveLength(1);
28
- expect(jobs[0].jobId).toBe("job-1");
29
- expect(jobs[0].status).toBe("scheduled");
30
- expect(jobs[0].reason).toBe("test reason");
31
- });
32
-
33
- it("overwrites existing job with same ID", async () => {
34
- const s = scheduler();
35
- await s.scheduleResume("job-1", "2025-01-01T12:00:00Z", "reason A");
36
- await s.scheduleResume("job-1", "2025-01-02T12:00:00Z", "reason B");
37
- const jobs = await s.readAll();
38
- expect(jobs).toHaveLength(1);
39
- expect(jobs[0].reason).toBe("reason B");
40
- });
41
-
42
- it("keeps separate jobs distinct", async () => {
43
- const s = scheduler();
44
- await s.scheduleResume("job-A", "2025-01-01T12:00:00Z", "reason A");
45
- await s.scheduleResume("job-B", "2025-01-02T12:00:00Z", "reason B");
46
- const jobs = await s.readAll();
47
- expect(jobs).toHaveLength(2);
48
- });
49
- });
50
-
51
- describe("dueJobs", () => {
52
- it("returns empty when nothing is due", async () => {
53
- const s = scheduler();
54
- await s.scheduleResume("job-1", "2099-12-31T23:59:59Z", "far future");
55
- const due = await s.dueJobs(new Date("2025-01-01"));
56
- expect(due).toHaveLength(0);
57
- });
58
-
59
- it("returns job when resumeAt has passed", async () => {
60
- const s = scheduler();
61
- await s.scheduleResume("job-1", "2024-01-01T12:00:00Z", "past");
62
- const due = await s.dueJobs(new Date("2025-01-01"));
63
- expect(due).toEqual(["job-1"]);
64
- });
65
-
66
- it("skips cancelled jobs", async () => {
67
- const s = scheduler();
68
- await s.scheduleResume("job-1", "2024-01-01T12:00:00Z", "cancelled");
69
- await s.cancel("job-1");
70
- const due = await s.dueJobs(new Date("2025-01-01"));
71
- expect(due).toHaveLength(0);
72
- });
73
-
74
- it("returns multiple due jobs", async () => {
75
- const s = scheduler();
76
- await s.scheduleResume("job-A", "2024-01-01T12:00:00Z", "A");
77
- await s.scheduleResume("job-B", "2024-01-02T12:00:00Z", "B");
78
- await s.cancel("job-A");
79
- const due = await s.dueJobs(new Date("2025-01-01"));
80
- expect(due).toEqual(["job-B"]);
81
- });
82
-
83
- it("ignores resumeAt in the future", async () => {
84
- const s = scheduler();
85
- await s.scheduleResume("job-future", "2099-01-01T00:00:00Z", "too late");
86
- const due = await s.dueJobs(new Date("2025-06-15"));
87
- expect(due).toHaveLength(0);
88
- });
89
- });
90
-
91
- describe("cancel", () => {
92
- it("sets status to cancelled", async () => {
93
- const s = scheduler();
94
- await s.scheduleResume("job-1", "2024-01-01T00:00:00Z", "to cancel");
95
- await s.cancel("job-1");
96
- const jobs = await s.readAll();
97
- expect(jobs).toHaveLength(1);
98
- expect(jobs[0].status).toBe("cancelled");
99
- });
100
-
101
- it("no-op for unknown job", async () => {
102
- const s = scheduler();
103
- await s.scheduleResume("job-1", "2024-01-01T00:00:00Z", "exists");
104
- await s.cancel("nonexistent");
105
- const jobs = await s.readAll();
106
- expect(jobs).toHaveLength(1);
107
- });
108
-
109
- it("cancelled job not returned by dueJobs", async () => {
110
- const s = scheduler();
111
- await s.scheduleResume("job-1", "2020-01-01T00:00:00Z", "was due");
112
- await s.cancel("job-1");
113
- const due = await s.dueJobs(new Date("2025-01-01"));
114
- expect(due).toHaveLength(0);
115
- });
116
- });
117
-
118
- describe("readAll", () => {
119
- it("returns empty array for missing file", async () => {
120
- const s = scheduler();
121
- const jobs = await s.readAll();
122
- expect(jobs).toEqual([]);
123
- });
124
- });
125
- });