agentenkit 0.3.0 → 0.5.0

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 (295) hide show
  1. package/README.md +82 -15
  2. package/dist/adapters/brave.d.ts +21 -0
  3. package/dist/adapters/brave.d.ts.map +1 -0
  4. package/dist/adapters/brave.js +52 -0
  5. package/dist/adapters/brave.js.map +1 -0
  6. package/dist/adapters/computesdk.d.ts +71 -0
  7. package/dist/adapters/computesdk.d.ts.map +1 -0
  8. package/dist/adapters/computesdk.js +163 -0
  9. package/dist/adapters/computesdk.js.map +1 -0
  10. package/dist/adapters/docker.d.ts +35 -0
  11. package/dist/adapters/docker.d.ts.map +1 -0
  12. package/dist/adapters/docker.js +246 -0
  13. package/dist/adapters/docker.js.map +1 -0
  14. package/dist/adapters/e2b.d.ts +44 -0
  15. package/dist/adapters/e2b.d.ts.map +1 -0
  16. package/dist/adapters/e2b.js +349 -0
  17. package/dist/adapters/e2b.js.map +1 -0
  18. package/dist/adapters/inline.d.ts +19 -5
  19. package/dist/adapters/inline.d.ts.map +1 -1
  20. package/dist/adapters/inline.js +87 -14
  21. package/dist/adapters/inline.js.map +1 -1
  22. package/dist/adapters/jina.d.ts +34 -0
  23. package/dist/adapters/jina.d.ts.map +1 -0
  24. package/dist/adapters/jina.js +99 -0
  25. package/dist/adapters/jina.js.map +1 -0
  26. package/dist/adapters/local-sandbox.d.ts +32 -0
  27. package/dist/adapters/local-sandbox.d.ts.map +1 -0
  28. package/dist/adapters/local-sandbox.js +257 -0
  29. package/dist/adapters/local-sandbox.js.map +1 -0
  30. package/dist/adapters/memory.d.ts +146 -3
  31. package/dist/adapters/memory.d.ts.map +1 -1
  32. package/dist/adapters/memory.js +474 -3
  33. package/dist/adapters/memory.js.map +1 -1
  34. package/dist/adapters/page-reader.d.ts +39 -0
  35. package/dist/adapters/page-reader.d.ts.map +1 -0
  36. package/dist/adapters/page-reader.js +165 -0
  37. package/dist/adapters/page-reader.js.map +1 -0
  38. package/dist/adapters/prisma.d.ts +125 -18
  39. package/dist/adapters/prisma.d.ts.map +1 -1
  40. package/dist/adapters/prisma.js +308 -67
  41. package/dist/adapters/prisma.js.map +1 -1
  42. package/dist/adapters/qstash.d.ts +15 -2
  43. package/dist/adapters/qstash.d.ts.map +1 -1
  44. package/dist/adapters/qstash.js +31 -14
  45. package/dist/adapters/qstash.js.map +1 -1
  46. package/dist/adapters/redis.d.ts +40 -4
  47. package/dist/adapters/redis.d.ts.map +1 -1
  48. package/dist/adapters/redis.js +265 -20
  49. package/dist/adapters/redis.js.map +1 -1
  50. package/dist/adapters/sandbox-shell.d.ts +60 -0
  51. package/dist/adapters/sandbox-shell.d.ts.map +1 -0
  52. package/dist/adapters/sandbox-shell.js +129 -0
  53. package/dist/adapters/sandbox-shell.js.map +1 -0
  54. package/dist/adapters/sqlite.d.ts +88 -2
  55. package/dist/adapters/sqlite.d.ts.map +1 -1
  56. package/dist/adapters/sqlite.js +443 -37
  57. package/dist/adapters/sqlite.js.map +1 -1
  58. package/dist/adapters/stream-scripts.d.ts +49 -0
  59. package/dist/adapters/stream-scripts.d.ts.map +1 -0
  60. package/dist/adapters/stream-scripts.js +150 -0
  61. package/dist/adapters/stream-scripts.js.map +1 -0
  62. package/dist/adapters/upstash.d.ts +20 -0
  63. package/dist/adapters/upstash.d.ts.map +1 -1
  64. package/dist/adapters/upstash.js +29 -0
  65. package/dist/adapters/upstash.js.map +1 -1
  66. package/dist/adapters/web-search-shared.d.ts +11 -0
  67. package/dist/adapters/web-search-shared.d.ts.map +1 -0
  68. package/dist/adapters/web-search-shared.js +40 -0
  69. package/dist/adapters/web-search-shared.js.map +1 -0
  70. package/dist/admin/memory.d.ts +11 -1
  71. package/dist/admin/memory.d.ts.map +1 -1
  72. package/dist/admin/memory.js +83 -14
  73. package/dist/admin/memory.js.map +1 -1
  74. package/dist/admin/migrations/postgres/0002-run-settled-at.d.ts +5 -0
  75. package/dist/admin/migrations/postgres/0002-run-settled-at.d.ts.map +1 -0
  76. package/dist/admin/migrations/postgres/0002-run-settled-at.js +11 -0
  77. package/dist/admin/migrations/postgres/0002-run-settled-at.js.map +1 -0
  78. package/dist/admin/migrations/postgres/0003-run-enqueued-at.d.ts +5 -0
  79. package/dist/admin/migrations/postgres/0003-run-enqueued-at.d.ts.map +1 -0
  80. package/dist/admin/migrations/postgres/0003-run-enqueued-at.js +15 -0
  81. package/dist/admin/migrations/postgres/0003-run-enqueued-at.js.map +1 -0
  82. package/dist/admin/migrations/postgres/0004-run-settle-claim.d.ts +5 -0
  83. package/dist/admin/migrations/postgres/0004-run-settle-claim.d.ts.map +1 -0
  84. package/dist/admin/migrations/postgres/0004-run-settle-claim.js +15 -0
  85. package/dist/admin/migrations/postgres/0004-run-settle-claim.js.map +1 -0
  86. package/dist/admin/migrations/postgres/0005-bigint-counters.d.ts +5 -0
  87. package/dist/admin/migrations/postgres/0005-bigint-counters.d.ts.map +1 -0
  88. package/dist/admin/migrations/postgres/0005-bigint-counters.js +12 -0
  89. package/dist/admin/migrations/postgres/0005-bigint-counters.js.map +1 -0
  90. package/dist/admin/migrations/postgres/index.d.ts.map +1 -1
  91. package/dist/admin/migrations/postgres/index.js +16 -1
  92. package/dist/admin/migrations/postgres/index.js.map +1 -1
  93. package/dist/admin/migrations/runner.d.ts +21 -1
  94. package/dist/admin/migrations/runner.d.ts.map +1 -1
  95. package/dist/admin/migrations/runner.js +41 -4
  96. package/dist/admin/migrations/runner.js.map +1 -1
  97. package/dist/admin/migrations/sqlite/0002-run-settled-at.d.ts +5 -0
  98. package/dist/admin/migrations/sqlite/0002-run-settled-at.d.ts.map +1 -0
  99. package/dist/admin/migrations/sqlite/0002-run-settled-at.js +11 -0
  100. package/dist/admin/migrations/sqlite/0002-run-settled-at.js.map +1 -0
  101. package/dist/admin/migrations/sqlite/0003-run-enqueued-at.d.ts +5 -0
  102. package/dist/admin/migrations/sqlite/0003-run-enqueued-at.d.ts.map +1 -0
  103. package/dist/admin/migrations/sqlite/0003-run-enqueued-at.js +15 -0
  104. package/dist/admin/migrations/sqlite/0003-run-enqueued-at.js.map +1 -0
  105. package/dist/admin/migrations/sqlite/0004-run-settle-claim.d.ts +5 -0
  106. package/dist/admin/migrations/sqlite/0004-run-settle-claim.d.ts.map +1 -0
  107. package/dist/admin/migrations/sqlite/0004-run-settle-claim.js +15 -0
  108. package/dist/admin/migrations/sqlite/0004-run-settle-claim.js.map +1 -0
  109. package/dist/admin/migrations/sqlite/index.d.ts +2 -2
  110. package/dist/admin/migrations/sqlite/index.d.ts.map +1 -1
  111. package/dist/admin/migrations/sqlite/index.js +17 -3
  112. package/dist/admin/migrations/sqlite/index.js.map +1 -1
  113. package/dist/admin/postgres.d.ts +14 -4
  114. package/dist/admin/postgres.d.ts.map +1 -1
  115. package/dist/admin/postgres.js +131 -36
  116. package/dist/admin/postgres.js.map +1 -1
  117. package/dist/admin/shared.d.ts +19 -0
  118. package/dist/admin/shared.d.ts.map +1 -0
  119. package/dist/admin/shared.js +28 -0
  120. package/dist/admin/shared.js.map +1 -0
  121. package/dist/admin/sqlite.d.ts +9 -1
  122. package/dist/admin/sqlite.d.ts.map +1 -1
  123. package/dist/admin/sqlite.js +112 -29
  124. package/dist/admin/sqlite.js.map +1 -1
  125. package/dist/core/admin.d.ts +28 -6
  126. package/dist/core/admin.d.ts.map +1 -1
  127. package/dist/core/admin.js +92 -23
  128. package/dist/core/admin.js.map +1 -1
  129. package/dist/core/agent.d.ts +7 -4
  130. package/dist/core/agent.d.ts.map +1 -1
  131. package/dist/core/agent.js +15 -11
  132. package/dist/core/agent.js.map +1 -1
  133. package/dist/core/agui.d.ts +17 -0
  134. package/dist/core/agui.d.ts.map +1 -0
  135. package/dist/core/agui.js +69 -0
  136. package/dist/core/agui.js.map +1 -0
  137. package/dist/core/builtin/definitions.d.ts +12 -0
  138. package/dist/core/builtin/definitions.d.ts.map +1 -0
  139. package/dist/core/builtin/definitions.js +149 -0
  140. package/dist/core/builtin/definitions.js.map +1 -0
  141. package/dist/core/builtin/html.d.ts +13 -0
  142. package/dist/core/builtin/html.d.ts.map +1 -0
  143. package/dist/core/builtin/html.js +96 -0
  144. package/dist/core/builtin/html.js.map +1 -0
  145. package/dist/core/builtin/index.d.ts +21 -0
  146. package/dist/core/builtin/index.d.ts.map +1 -0
  147. package/dist/core/builtin/index.js +55 -0
  148. package/dist/core/builtin/index.js.map +1 -0
  149. package/dist/core/builtin/run.d.ts +37 -0
  150. package/dist/core/builtin/run.d.ts.map +1 -0
  151. package/dist/core/builtin/run.js +55 -0
  152. package/dist/core/builtin/run.js.map +1 -0
  153. package/dist/core/builtin/sandbox-tools.d.ts +69 -0
  154. package/dist/core/builtin/sandbox-tools.d.ts.map +1 -0
  155. package/dist/core/builtin/sandbox-tools.js +389 -0
  156. package/dist/core/builtin/sandbox-tools.js.map +1 -0
  157. package/dist/core/builtin/sandbox.d.ts +52 -0
  158. package/dist/core/builtin/sandbox.d.ts.map +1 -0
  159. package/dist/core/builtin/sandbox.js +174 -0
  160. package/dist/core/builtin/sandbox.js.map +1 -0
  161. package/dist/core/builtin/web.d.ts +54 -0
  162. package/dist/core/builtin/web.d.ts.map +1 -0
  163. package/dist/core/builtin/web.js +167 -0
  164. package/dist/core/builtin/web.js.map +1 -0
  165. package/dist/core/context.d.ts +13 -1
  166. package/dist/core/context.d.ts.map +1 -1
  167. package/dist/core/context.js +70 -19
  168. package/dist/core/context.js.map +1 -1
  169. package/dist/core/deleteThread.d.ts.map +1 -1
  170. package/dist/core/deleteThread.js +36 -4
  171. package/dist/core/deleteThread.js.map +1 -1
  172. package/dist/core/engine.d.ts +41 -11
  173. package/dist/core/engine.d.ts.map +1 -1
  174. package/dist/core/engine.js +880 -353
  175. package/dist/core/engine.js.map +1 -1
  176. package/dist/core/follow.d.ts +63 -1
  177. package/dist/core/follow.d.ts.map +1 -1
  178. package/dist/core/follow.js +293 -16
  179. package/dist/core/follow.js.map +1 -1
  180. package/dist/core/hitl.d.ts +43 -0
  181. package/dist/core/hitl.d.ts.map +1 -1
  182. package/dist/core/hitl.js +163 -35
  183. package/dist/core/hitl.js.map +1 -1
  184. package/dist/core/keys.d.ts +22 -4
  185. package/dist/core/keys.d.ts.map +1 -1
  186. package/dist/core/keys.js +23 -5
  187. package/dist/core/keys.js.map +1 -1
  188. package/dist/core/lease.d.ts +46 -0
  189. package/dist/core/lease.d.ts.map +1 -0
  190. package/dist/core/lease.js +142 -0
  191. package/dist/core/lease.js.map +1 -0
  192. package/dist/core/loop.d.ts +27 -7
  193. package/dist/core/loop.d.ts.map +1 -1
  194. package/dist/core/loop.js +140 -55
  195. package/dist/core/loop.js.map +1 -1
  196. package/dist/core/messages.d.ts +21 -2
  197. package/dist/core/messages.d.ts.map +1 -1
  198. package/dist/core/messages.js +61 -2
  199. package/dist/core/messages.js.map +1 -1
  200. package/dist/core/permanent.d.ts +11 -0
  201. package/dist/core/permanent.d.ts.map +1 -0
  202. package/dist/core/permanent.js +37 -0
  203. package/dist/core/permanent.js.map +1 -0
  204. package/dist/core/prune.d.ts +24 -0
  205. package/dist/core/prune.d.ts.map +1 -0
  206. package/dist/core/prune.js +43 -0
  207. package/dist/core/prune.js.map +1 -0
  208. package/dist/core/publish.d.ts +38 -10
  209. package/dist/core/publish.d.ts.map +1 -1
  210. package/dist/core/publish.js +126 -12
  211. package/dist/core/publish.js.map +1 -1
  212. package/dist/core/reclaim.d.ts +8 -1
  213. package/dist/core/reclaim.d.ts.map +1 -1
  214. package/dist/core/reclaim.js +149 -18
  215. package/dist/core/reclaim.js.map +1 -1
  216. package/dist/core/run.d.ts +7 -3
  217. package/dist/core/run.d.ts.map +1 -1
  218. package/dist/core/run.js +95 -35
  219. package/dist/core/run.js.map +1 -1
  220. package/dist/core/segment.d.ts +62 -0
  221. package/dist/core/segment.d.ts.map +1 -0
  222. package/dist/core/segment.js +318 -0
  223. package/dist/core/segment.js.map +1 -0
  224. package/dist/core/settle.d.ts +57 -0
  225. package/dist/core/settle.d.ts.map +1 -0
  226. package/dist/core/settle.js +181 -0
  227. package/dist/core/settle.js.map +1 -0
  228. package/dist/core/snapshot.d.ts +36 -0
  229. package/dist/core/snapshot.d.ts.map +1 -0
  230. package/dist/core/snapshot.js +87 -0
  231. package/dist/core/snapshot.js.map +1 -0
  232. package/dist/core/stop.d.ts +16 -1
  233. package/dist/core/stop.d.ts.map +1 -1
  234. package/dist/core/stop.js +69 -15
  235. package/dist/core/stop.js.map +1 -1
  236. package/dist/core/stream-events.d.ts +184 -0
  237. package/dist/core/stream-events.d.ts.map +1 -0
  238. package/dist/core/stream-events.js +26 -0
  239. package/dist/core/stream-events.js.map +1 -0
  240. package/dist/core/stream.d.ts +29 -0
  241. package/dist/core/stream.d.ts.map +1 -1
  242. package/dist/core/stream.js +79 -0
  243. package/dist/core/stream.js.map +1 -1
  244. package/dist/core/subagent.d.ts +36 -5
  245. package/dist/core/subagent.d.ts.map +1 -1
  246. package/dist/core/subagent.js +130 -25
  247. package/dist/core/subagent.js.map +1 -1
  248. package/dist/core/tools.d.ts +9 -3
  249. package/dist/core/tools.d.ts.map +1 -1
  250. package/dist/core/tools.js.map +1 -1
  251. package/dist/core/types.d.ts +212 -13
  252. package/dist/core/types.d.ts.map +1 -1
  253. package/dist/core/types.js +29 -1
  254. package/dist/core/types.js.map +1 -1
  255. package/dist/core/usage.d.ts +53 -5
  256. package/dist/core/usage.d.ts.map +1 -1
  257. package/dist/core/usage.js +170 -47
  258. package/dist/core/usage.js.map +1 -1
  259. package/dist/index.d.ts +29 -12
  260. package/dist/index.d.ts.map +1 -1
  261. package/dist/index.js +23 -7
  262. package/dist/index.js.map +1 -1
  263. package/dist/ports/admin.d.ts +59 -0
  264. package/dist/ports/admin.d.ts.map +1 -1
  265. package/dist/ports/kv.d.ts +17 -0
  266. package/dist/ports/kv.d.ts.map +1 -1
  267. package/dist/ports/queue.d.ts +87 -7
  268. package/dist/ports/queue.d.ts.map +1 -1
  269. package/dist/ports/queue.js +36 -1
  270. package/dist/ports/queue.js.map +1 -1
  271. package/dist/ports/runtime.d.ts +188 -20
  272. package/dist/ports/runtime.d.ts.map +1 -1
  273. package/dist/ports/sandbox.d.ts +159 -0
  274. package/dist/ports/sandbox.d.ts.map +1 -0
  275. package/dist/ports/sandbox.js +44 -0
  276. package/dist/ports/sandbox.js.map +1 -0
  277. package/dist/ports/storage.d.ts +26 -5
  278. package/dist/ports/storage.d.ts.map +1 -1
  279. package/dist/ports/streams.d.ts +60 -0
  280. package/dist/ports/streams.d.ts.map +1 -0
  281. package/dist/ports/streams.js +20 -0
  282. package/dist/ports/streams.js.map +1 -0
  283. package/dist/ports/tools.d.ts +60 -0
  284. package/dist/ports/tools.d.ts.map +1 -0
  285. package/dist/ports/tools.js +5 -0
  286. package/dist/ports/tools.js.map +1 -0
  287. package/dist/pricing.d.ts +29 -0
  288. package/dist/pricing.d.ts.map +1 -1
  289. package/dist/pricing.js +64 -10
  290. package/dist/pricing.js.map +1 -1
  291. package/dist/runtime.d.ts +6 -0
  292. package/dist/runtime.d.ts.map +1 -1
  293. package/dist/runtime.js +147 -46
  294. package/dist/runtime.js.map +1 -1
  295. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  import type { AgentEvent } from '../core/types.js';
2
2
  import type { Kv } from '../ports/kv.js';
3
3
  import type { EventBus } from '../ports/bus.js';
4
+ import { ScriptedRunStreams } from './stream-scripts.js';
4
5
  /** Minimal structural type of a node-redis (v4) client — the real client
5
6
  * satisfies it without importing the SDK here. Works against any Redis:
6
7
  * local Docker, self-hosted, or managed. */
@@ -11,6 +12,10 @@ export interface RedisClientLike {
11
12
  del: any;
12
13
  incr: any;
13
14
  publish: any;
15
+ /** node-redis v4: `eval(script, { keys, arguments })`. */
16
+ eval: any;
17
+ /** Any command, raw: `sendCommand(['XREAD', ...])`. */
18
+ sendCommand?: any;
14
19
  duplicate(): any;
15
20
  }
16
21
  /** A dedicated connection for subscriptions (node-redis `client.duplicate()`). */
@@ -32,18 +37,49 @@ export declare class RedisKv implements Kv {
32
37
  }): Promise<boolean>;
33
38
  del(key: string): any;
34
39
  incr(key: string): any;
40
+ setIfValue(key: string, expected: string, value: string, opts?: {
41
+ exSeconds?: number;
42
+ }): Promise<boolean>;
43
+ delIfValue(key: string, expected: string): Promise<boolean>;
44
+ incrWithExpiry(key: string, exSeconds: number): Promise<number>;
35
45
  }
36
46
  /** Reference EventBus adapter over plain Redis Pub/Sub (node-redis).
37
47
  *
38
- * While subscribed, emits a bus-only `HEARTBEAT` notice (seq 0, never
39
- * persisted) every heartbeatMs — the §2.5 watchdog pattern: pub/sub is
40
- * at-most-once, so the SSE distributor treats heartbeats as a trigger to
41
- * re-check for orphaned HITL waits. */
48
+ * One subscriber connection per process, shared by every subscription: a
49
+ * channel is subscribed when its first handler arrives and unsubscribed when
50
+ * its last one leaves. A connection per viewer would run a busy deployment
51
+ * into Redis's `maxclients`.
52
+ *
53
+ * While subscribed, a bus-only `HEARTBEAT` notice (seq 0, never persisted)
54
+ * reaches every subscription each `heartbeatMs`, from one timer per process —
55
+ * the §2.5 watchdog pattern: pub/sub is at-most-once, so the SSE distributor
56
+ * treats heartbeats as a trigger to re-check for orphaned HITL waits, and a
57
+ * follower fills any gap from the log. */
42
58
  export declare class RedisBus implements EventBus {
43
59
  private readonly client;
44
60
  private readonly heartbeatMs;
61
+ private sub;
62
+ private readonly handlers;
63
+ private heartbeat?;
45
64
  constructor(client: RedisClientLike, heartbeatMs?: number);
46
65
  publish(threadId: string, event: AgentEvent): Promise<void>;
66
+ /** The shared subscriber connection, opened on first use. */
67
+ private connection;
68
+ private deliver;
47
69
  subscribe(threadId: string, handler: (event: AgentEvent) => void): Promise<() => Promise<void>>;
70
+ private startHeartbeat;
71
+ private stopHeartbeat;
72
+ }
73
+ /** RunStreams over Redis Streams (see stream-scripts.ts for the keys and
74
+ * scripts, the same ones the Go adapter runs). Readers in one process share
75
+ * one blocking connection; `pollMs` is the floor under a missed wake-up. */
76
+ export declare class RedisRunStreams extends ScriptedRunStreams {
77
+ private readonly tail;
78
+ constructor(client: RedisClientLike, opts?: {
79
+ pollMs?: number;
80
+ blockMs?: number;
81
+ });
82
+ /** Closes the shared tail connection. */
83
+ shutdown(): Promise<void>;
48
84
  }
49
85
  //# sourceMappingURL=redis.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../src/adapters/redis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAGhD;;6CAE6C;AAC7C,MAAM,WAAW,eAAe;IAC9B,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAG5B,GAAG,EAAE,GAAG,CAAC;IACT,GAAG,EAAE,GAAG,CAAC;IACT,GAAG,EAAE,GAAG,CAAC;IACT,IAAI,EAAE,GAAG,CAAC;IACV,OAAO,EAAE,GAAG,CAAC;IACb,SAAS,IAAI,GAAG,CAAC;CAClB;AAED,kFAAkF;AAClF,MAAM,WAAW,mBAAmB;IAClC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5B,SAAS,EAAE,GAAG,CAAC;IACf,WAAW,EAAE,GAAG,CAAC;IACjB,IAAI,EAAE,GAAG,CAAC;IACV,EAAE,EAAE,GAAG,CAAC;CACT;AAED,0DAA0D;AAC1D,qBAAa,OAAQ,YAAW,EAAE;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,eAAe;IAEnD,GAAG,CAAC,GAAG,EAAE,MAAM;IACT,GAAG,CACP,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE,GACvD,OAAO,CAAC,OAAO,CAAC;IAanB,GAAG,CAAC,GAAG,EAAE,MAAM;IACf,IAAI,CAAC,GAAG,EAAE,MAAM;CACjB;AAED;;;;;wCAKwC;AACxC,qBAAa,QAAS,YAAW,QAAQ;IAErC,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,WAAW;gBADX,MAAM,EAAE,eAAe,EACvB,WAAW,SAAS;IAGjC,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU;IAI3C,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI;CAuBvE"}
1
+ {"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../src/adapters/redis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAmB,kBAAkB,EAAS,MAAM,qBAAqB,CAAC;AAGjF;;6CAE6C;AAC7C,MAAM,WAAW,eAAe;IAC9B,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAG5B,GAAG,EAAE,GAAG,CAAC;IACT,GAAG,EAAE,GAAG,CAAC;IACT,GAAG,EAAE,GAAG,CAAC;IACT,IAAI,EAAE,GAAG,CAAC;IACV,OAAO,EAAE,GAAG,CAAC;IACb,0DAA0D;IAC1D,IAAI,EAAE,GAAG,CAAC;IACV,uDAAuD;IACvD,WAAW,CAAC,EAAE,GAAG,CAAC;IAClB,SAAS,IAAI,GAAG,CAAC;CAClB;AAED,kFAAkF;AAClF,MAAM,WAAW,mBAAmB;IAClC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5B,SAAS,EAAE,GAAG,CAAC;IACf,WAAW,EAAE,GAAG,CAAC;IACjB,IAAI,EAAE,GAAG,CAAC;IACV,EAAE,EAAE,GAAG,CAAC;CACT;AAED,0DAA0D;AAC1D,qBAAa,OAAQ,YAAW,EAAE;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,eAAe;IAEnD,GAAG,CAAC,GAAG,EAAE,MAAM;IACT,GAAG,CACP,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE,GACvD,OAAO,CAAC,OAAO,CAAC;IAanB,GAAG,CAAC,GAAG,EAAE,MAAM;IACf,IAAI,CAAC,GAAG,EAAE,MAAM;IACV,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE;IAQtF,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IAIxC,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;CAOpD;AAED;;;;;;;;;;;2CAW2C;AAC3C,qBAAa,QAAS,YAAW,QAAQ;IAMrC,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAN9B,OAAO,CAAC,GAAG,CAA6C;IACxD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuD;IAChF,OAAO,CAAC,SAAS,CAAC,CAAiC;gBAGhC,MAAM,EAAE,eAAe,EACvB,WAAW,SAAS;IAGjC,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU;IAIjD,6DAA6D;IAC7D,OAAO,CAAC,UAAU;IAmBlB,OAAO,CAAC,OAAO;IAUT,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI;IAyCtE,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,aAAa;CAItB;AAmID;;6EAE6E;AAC7E,qBAAa,eAAgB,SAAQ,kBAAkB;IACrD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;gBAEtB,MAAM,EAAE,eAAe,EAAE,IAAI,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO;IAUrF,yCAAyC;IACnC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAGhC"}
@@ -1,4 +1,5 @@
1
- import { THREAD_CHANNEL } from './upstash.js';
1
+ import { compareEntryIds, ScriptedRunStreams, sleep } from './stream-scripts.js';
2
+ import { DEL_IF_VALUE_SCRIPT, INCR_WITH_EXPIRY_SCRIPT, SET_IF_VALUE_SCRIPT, THREAD_CHANNEL } from './upstash.js';
2
3
  /** Reference Kv adapter over plain Redis (node-redis). */
3
4
  export class RedisKv {
4
5
  redis;
@@ -17,16 +18,44 @@ export class RedisKv {
17
18
  }
18
19
  del(key) { return this.redis.del(key).then(() => undefined); }
19
20
  incr(key) { return this.redis.incr(key); }
21
+ async setIfValue(key, expected, value, opts) {
22
+ const ms = Math.round((opts?.exSeconds ?? 0) * 1000);
23
+ const n = await this.redis.eval(SET_IF_VALUE_SCRIPT, {
24
+ keys: [key],
25
+ arguments: [expected, value, String(ms)],
26
+ });
27
+ return Number(n) === 1;
28
+ }
29
+ async delIfValue(key, expected) {
30
+ const n = await this.redis.eval(DEL_IF_VALUE_SCRIPT, { keys: [key], arguments: [expected] });
31
+ return Number(n) === 1;
32
+ }
33
+ async incrWithExpiry(key, exSeconds) {
34
+ const n = await this.redis.eval(INCR_WITH_EXPIRY_SCRIPT, {
35
+ keys: [key],
36
+ arguments: [String(Math.round(exSeconds * 1000))],
37
+ });
38
+ return Number(n);
39
+ }
20
40
  }
21
41
  /** Reference EventBus adapter over plain Redis Pub/Sub (node-redis).
22
42
  *
23
- * While subscribed, emits a bus-only `HEARTBEAT` notice (seq 0, never
24
- * persisted) every heartbeatMs — the §2.5 watchdog pattern: pub/sub is
25
- * at-most-once, so the SSE distributor treats heartbeats as a trigger to
26
- * re-check for orphaned HITL waits. */
43
+ * One subscriber connection per process, shared by every subscription: a
44
+ * channel is subscribed when its first handler arrives and unsubscribed when
45
+ * its last one leaves. A connection per viewer would run a busy deployment
46
+ * into Redis's `maxclients`.
47
+ *
48
+ * While subscribed, a bus-only `HEARTBEAT` notice (seq 0, never persisted)
49
+ * reaches every subscription each `heartbeatMs`, from one timer per process —
50
+ * the §2.5 watchdog pattern: pub/sub is at-most-once, so the SSE distributor
51
+ * treats heartbeats as a trigger to re-check for orphaned HITL waits, and a
52
+ * follower fills any gap from the log. */
27
53
  export class RedisBus {
28
54
  client;
29
55
  heartbeatMs;
56
+ sub = null;
57
+ handlers = new Map();
58
+ heartbeat;
30
59
  constructor(client, heartbeatMs = 60_000) {
31
60
  this.client = client;
32
61
  this.heartbeatMs = heartbeatMs;
@@ -34,27 +63,243 @@ export class RedisBus {
34
63
  async publish(threadId, event) {
35
64
  await this.client.publish(THREAD_CHANNEL(threadId), JSON.stringify(event));
36
65
  }
37
- async subscribe(threadId, handler) {
38
- const sub = this.client.duplicate();
39
- await sub.connect();
40
- await sub.subscribe(THREAD_CHANNEL(threadId), (message) => {
66
+ /** The shared subscriber connection, opened on first use. */
67
+ connection() {
68
+ if (!this.sub) {
69
+ const sub = this.client.duplicate();
70
+ // node-redis emits 'error' on a dropped connection and reconnects by
71
+ // itself. With no listener, the emit throws and ends the process, so one
72
+ // Redis failover would take down every worker and SSE server.
73
+ sub.on('error', (err) => console.error('redis subscriber error', err));
74
+ this.sub = Promise.resolve(sub.connect()).then(() => sub, (err) => {
75
+ this.sub = null; // a later subscribe tries again
76
+ void Promise.resolve(sub.quit()).catch(() => undefined);
77
+ throw err;
78
+ });
79
+ }
80
+ return this.sub;
81
+ }
82
+ deliver(handlers, event) {
83
+ for (const handler of handlers) {
41
84
  try {
42
- handler(JSON.parse(message));
85
+ handler(event);
43
86
  }
44
87
  catch {
45
- // malformed frame — never kill the subscription
88
+ // one throwing handler must not stop the others
46
89
  }
47
- });
48
- const heartbeat = setInterval(() => {
49
- handler({
50
- threadId, seq: 0, type: 'HEARTBEAT', payload: null, createdAt: new Date(),
51
- });
52
- }, this.heartbeatMs);
90
+ }
91
+ }
92
+ async subscribe(threadId, handler) {
93
+ const channel = THREAD_CHANNEL(threadId);
94
+ const sub = await this.connection();
95
+ let set = this.handlers.get(channel);
96
+ if (!set) {
97
+ set = new Set();
98
+ this.handlers.set(channel, set);
99
+ const mine = set;
100
+ try {
101
+ await sub.subscribe(channel, (message) => {
102
+ let event;
103
+ try {
104
+ event = JSON.parse(message);
105
+ event.createdAt = new Date(event.createdAt);
106
+ }
107
+ catch {
108
+ return; // malformed frame — never kill the subscription
109
+ }
110
+ this.deliver([...mine], event);
111
+ });
112
+ }
113
+ catch (err) {
114
+ this.handlers.delete(channel);
115
+ throw err;
116
+ }
117
+ }
118
+ set.add(handler);
119
+ this.startHeartbeat();
120
+ let done = false;
53
121
  return async () => {
54
- clearInterval(heartbeat);
55
- await sub.unsubscribe(THREAD_CHANNEL(threadId)).catch(() => undefined);
56
- await sub.quit().catch(() => undefined);
122
+ if (done)
123
+ return;
124
+ done = true;
125
+ const current = this.handlers.get(channel);
126
+ current?.delete(handler);
127
+ if (current && current.size === 0) {
128
+ this.handlers.delete(channel);
129
+ await sub.unsubscribe(channel).catch(() => undefined);
130
+ }
131
+ if (this.handlers.size === 0)
132
+ this.stopHeartbeat();
57
133
  };
58
134
  }
135
+ startHeartbeat() {
136
+ if (this.heartbeat)
137
+ return;
138
+ this.heartbeat = setInterval(() => {
139
+ for (const [channel, set] of this.handlers) {
140
+ const threadId = channel.slice('thread:'.length, -':events'.length);
141
+ this.deliver([...set], {
142
+ threadId, seq: 0, type: 'HEARTBEAT', payload: null, createdAt: new Date(),
143
+ });
144
+ }
145
+ }, this.heartbeatMs);
146
+ this.heartbeat.unref?.();
147
+ }
148
+ stopHeartbeat() {
149
+ if (this.heartbeat)
150
+ clearInterval(this.heartbeat);
151
+ this.heartbeat = undefined;
152
+ }
153
+ }
154
+ /** How long a stream key with no reader stays watched. */
155
+ const TAIL_IDLE_MS = 10_000;
156
+ /** An XREAD reply as [key, entries] pairs. RESP2 gives an array of pairs;
157
+ * RESP3 clients give a map, as a Map or a plain object. */
158
+ function xreadPairs(reply) {
159
+ if (!reply)
160
+ return [];
161
+ if (Array.isArray(reply))
162
+ return reply;
163
+ if (reply instanceof Map)
164
+ return [...reply.entries()];
165
+ return Object.entries(reply);
166
+ }
167
+ /** One blocking `XREAD` per process, shared by every reader of every stream
168
+ * here: a connection per reader would run a busy deployment into Redis's
169
+ * `maxclients`, like a subscriber per viewer would. A reader registers the
170
+ * stream key and the last id it has; the tail wakes it when an entry past
171
+ * that id lands. When a key it does not watch yet arrives, the tail breaks
172
+ * its own block with `CLIENT UNBLOCK` and starts again with the new key. */
173
+ class StreamTail {
174
+ client;
175
+ blockMs;
176
+ conn = null;
177
+ /** Per key: the newest entry id the tail has seen, who waits, and when a
178
+ * reader last waited. A key stays watched a while after its last reader
179
+ * leaves, so a reader that waits again after each event does not break
180
+ * the block every time. */
181
+ keys = new Map();
182
+ running = false;
183
+ constructor(client, blockMs) {
184
+ this.client = client;
185
+ this.blockMs = blockMs;
186
+ }
187
+ connection() {
188
+ if (!this.conn) {
189
+ const conn = this.client.duplicate();
190
+ conn.on?.('error', (err) => console.error('redis stream tail error', err));
191
+ this.conn = Promise.resolve(conn.connect())
192
+ .then(async () => ({ client: conn, id: String(await conn.sendCommand(['CLIENT', 'ID'])) }))
193
+ .catch((err) => {
194
+ this.conn = null;
195
+ void Promise.resolve(conn.quit?.()).catch(() => undefined);
196
+ throw err;
197
+ });
198
+ }
199
+ return this.conn;
200
+ }
201
+ /** Resolves when `key` may have an entry past `after`. */
202
+ wait(key, after, maxMs, signal) {
203
+ return new Promise((resolve) => {
204
+ let entry = this.keys.get(key);
205
+ // The tail already saw something past this reader: wake at once.
206
+ if (entry && compareEntryIds(entry.seen, after) > 0)
207
+ return resolve();
208
+ let timer;
209
+ const done = () => {
210
+ clearTimeout(timer);
211
+ signal?.removeEventListener('abort', done);
212
+ const e = this.keys.get(key);
213
+ if (e?.waiters.delete(done))
214
+ e.used = Date.now();
215
+ resolve();
216
+ };
217
+ timer = setTimeout(done, maxMs);
218
+ signal?.addEventListener('abort', done, { once: true });
219
+ const fresh = !entry;
220
+ if (!entry) {
221
+ entry = { seen: after, waiters: new Set(), used: Date.now() };
222
+ this.keys.set(key, entry);
223
+ }
224
+ entry.waiters.add(done);
225
+ entry.used = Date.now();
226
+ if (fresh)
227
+ void this.restart();
228
+ });
229
+ }
230
+ /** Runs the loop, or breaks its current block so it takes the new keys. */
231
+ async restart() {
232
+ if (!this.running) {
233
+ this.running = true;
234
+ void this.loop().finally(() => {
235
+ this.running = false;
236
+ // A key that came in while the loop was on its way out.
237
+ if (this.keys.size > 0)
238
+ void this.restart();
239
+ });
240
+ return;
241
+ }
242
+ try {
243
+ const { id } = await this.connection();
244
+ await this.client.sendCommand?.(['CLIENT', 'UNBLOCK', id]);
245
+ }
246
+ catch {
247
+ // The loop's own timeout picks the key up.
248
+ }
249
+ }
250
+ async loop() {
251
+ for (;;) {
252
+ const now = Date.now();
253
+ for (const [key, e] of this.keys) {
254
+ if (e.waiters.size === 0 && now - e.used > TAIL_IDLE_MS)
255
+ this.keys.delete(key);
256
+ }
257
+ if (this.keys.size === 0)
258
+ return;
259
+ const keys = [...this.keys.keys()];
260
+ const ids = keys.map((k) => this.keys.get(k).seen);
261
+ let reply;
262
+ try {
263
+ const { client } = await this.connection();
264
+ reply = await client.sendCommand(['XREAD', 'BLOCK', String(this.blockMs), 'STREAMS', ...keys, ...ids]);
265
+ }
266
+ catch {
267
+ // A dropped connection: readers fall back on their own poll until
268
+ // the next pass reconnects.
269
+ await sleep(200);
270
+ continue;
271
+ }
272
+ for (const [key, entries] of xreadPairs(reply)) {
273
+ const entry = this.keys.get(String(key));
274
+ const last = entries.at(-1)?.[0];
275
+ if (!entry || !last)
276
+ continue;
277
+ entry.seen = String(last);
278
+ for (const wake of [...entry.waiters])
279
+ wake();
280
+ }
281
+ }
282
+ }
283
+ async close() {
284
+ const conn = this.conn;
285
+ this.conn = null;
286
+ if (conn)
287
+ await conn.then(({ client }) => client.quit()).catch(() => undefined);
288
+ }
289
+ }
290
+ /** RunStreams over Redis Streams (see stream-scripts.ts for the keys and
291
+ * scripts, the same ones the Go adapter runs). Readers in one process share
292
+ * one blocking connection; `pollMs` is the floor under a missed wake-up. */
293
+ export class RedisRunStreams extends ScriptedRunStreams {
294
+ tail;
295
+ constructor(client, opts = {}) {
296
+ const tail = new StreamTail(client, opts.blockMs ?? 5_000);
297
+ super((script, keys, args) => client.eval(script, { keys, arguments: args }), (key, after, maxMs, signal) => tail.wait(key, after, maxMs, signal), opts.pollMs ?? 1_000);
298
+ this.tail = tail;
299
+ }
300
+ /** Closes the shared tail connection. */
301
+ async shutdown() {
302
+ await this.tail.close();
303
+ }
59
304
  }
60
305
  //# sourceMappingURL=redis.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"redis.js","sourceRoot":"","sources":["../../src/adapters/redis.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"redis.js","sourceRoot":"","sources":["../../src/adapters/redis.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import { type FileEntry } from '../ports/sandbox.js';
2
+ /** Pieces the sandbox adapters share. The Go adapters use the same scripts
3
+ * (adapters/internal/sandboxsh), so a command behaves the same in both. */
4
+ /** Runs `$1` in bash (sh where there is no bash), under `timeout` for `$2`
5
+ * seconds when that is given and the sandbox has `timeout`. `$3` is `-l`
6
+ * for a login shell. Called as `sh -c RUN_SCRIPT sandbox <command> <secs> <-l>`. */
7
+ export declare const RUN_SCRIPT: string;
8
+ /** The argv that runs `command` through RUN_SCRIPT. */
9
+ export declare function runArgv(command: string, timeoutSeconds?: number, login?: boolean): string[];
10
+ /** Starts `command` apart from the caller and returns at once. */
11
+ export declare function backgroundCommand(command: string): string;
12
+ /** Whole seconds for `timeout(1)`, never less than one. */
13
+ export declare function timeoutSeconds(ms: number): number;
14
+ /** `timeout` stops a command with 124 (TERM) or 137 (KILL after -k). */
15
+ export declare function looksTimedOut(exitCode: number, elapsedMs: number, limitMs: number): boolean;
16
+ export declare function shellQuote(s: string): string;
17
+ /** A relative path is taken from the work folder. */
18
+ export declare function resolveIn(workdir: string, path: string): string;
19
+ /** The exit code the file scripts give for "no such file or folder". */
20
+ export declare const NOT_FOUND_EXIT = 44;
21
+ /** `sh -c <script> sandbox <path>` scripts for adapters that reach files
22
+ * only through commands. Each exits 44 when the path is not there. */
23
+ export declare const FILE_SCRIPTS: {
24
+ readonly read: "[ -f \"$1\" ] || exit 44; cat -- \"$1\"";
25
+ readonly readBase64: "[ -f \"$1\" ] || exit 44; base64 < \"$1\"";
26
+ readonly write: "mkdir -p -- \"$(dirname -- \"$1\")\" && cat > \"$1\"";
27
+ readonly list: string;
28
+ readonly mkdir: "mkdir -p -- \"$1\"";
29
+ readonly exists: "[ -e \"$1\" ] || [ -L \"$1\" ]";
30
+ readonly remove: "rm -rf -- \"$1\"";
31
+ };
32
+ /** Reads what FILE_SCRIPTS.list printed. */
33
+ export declare function parseListing(out: string): FileEntry[];
34
+ export declare function sortEntries(entries: FileEntry[]): FileEntry[];
35
+ /** Collects one output stream: keeps up to MAX_COMMAND_OUTPUT_BYTES, hands
36
+ * each piece on as text as it comes, never splitting a character. */
37
+ export declare class OutputCollector {
38
+ private readonly onText?;
39
+ private readonly decoder;
40
+ private readonly parts;
41
+ private kept;
42
+ truncated: boolean;
43
+ constructor(onText?: ((chunk: string) => void) | undefined);
44
+ push(chunk: Uint8Array): void;
45
+ end(): string;
46
+ private add;
47
+ }
48
+ /** Output from an adapter that hands it over whole, cut to
49
+ * MAX_COMMAND_OUTPUT_BYTES the way OutputCollector cuts a stream. */
50
+ export declare function capOutput(text: string): {
51
+ text: string;
52
+ truncated: boolean;
53
+ };
54
+ /** Random lowercase letters and digits, for sandbox names. */
55
+ export declare function randomId(length?: number): string;
56
+ /** Base64 without the line breaks some `base64` tools add. */
57
+ export declare function decodeBase64(text: string): Uint8Array;
58
+ export declare function encodeBase64(bytes: Uint8Array): string;
59
+ export declare function toBytes(content: string | Uint8Array): Uint8Array;
60
+ //# sourceMappingURL=sandbox-shell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox-shell.d.ts","sourceRoot":"","sources":["../../src/adapters/sandbox-shell.ts"],"names":[],"mappings":"AACA,OAAO,EAA4B,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAE/E;4EAC4E;AAE5E;;qFAEqF;AACrF,eAAO,MAAM,UAAU,QAGC,CAAC;AAEzB,uDAAuD;AACvD,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,EAAE,KAAK,UAAQ,GAAG,MAAM,EAAE,CAEzF;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,2DAA2D;AAC3D,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wEAAwE;AACxE,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAE3F;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED,qDAAqD;AACrD,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,wEAAwE;AACxE,eAAO,MAAM,cAAc,KAAK,CAAC;AAEjC;uEACuE;AACvE,eAAO,MAAM,YAAY;;;;;;;;CAYf,CAAC;AAEX,4CAA4C;AAC5C,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,CASrD;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,CAE7D;AAED;sEACsE;AACtE,qBAAa,eAAe;IAMd,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IALpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IACtC,OAAO,CAAC,IAAI,CAAK;IACjB,SAAS,UAAS;gBAEW,MAAM,CAAC,GAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,aAAA;IAE7D,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAY7B,GAAG,IAAI,MAAM;IAQb,OAAO,CAAC,GAAG;CAIZ;AAED;sEACsE;AACtE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAI5E;AAED,8DAA8D;AAC9D,wBAAgB,QAAQ,CAAC,MAAM,SAAK,GAAG,MAAM,CAM5C;AAED,8DAA8D;AAC9D,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAErD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAEtD;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,CAEhE"}
@@ -0,0 +1,129 @@
1
+ import { posix } from 'node:path';
2
+ import { MAX_COMMAND_OUTPUT_BYTES } from '../ports/sandbox.js';
3
+ /** Pieces the sandbox adapters share. The Go adapters use the same scripts
4
+ * (adapters/internal/sandboxsh), so a command behaves the same in both. */
5
+ /** Runs `$1` in bash (sh where there is no bash), under `timeout` for `$2`
6
+ * seconds when that is given and the sandbox has `timeout`. `$3` is `-l`
7
+ * for a login shell. Called as `sh -c RUN_SCRIPT sandbox <command> <secs> <-l>`. */
8
+ export const RUN_SCRIPT = 'if command -v bash >/dev/null 2>&1; then s=bash; else s=sh; fi; ' +
9
+ 'if [ -n "$2" ] && command -v timeout >/dev/null 2>&1; then exec timeout -k 2 "$2" "$s" $3 -c "$1"; fi; ' +
10
+ 'exec "$s" $3 -c "$1"';
11
+ /** The argv that runs `command` through RUN_SCRIPT. */
12
+ export function runArgv(command, timeoutSeconds, login = false) {
13
+ return ['sh', '-c', RUN_SCRIPT, 'sandbox', command, timeoutSeconds ? String(timeoutSeconds) : '', login ? '-l' : ''];
14
+ }
15
+ /** Starts `command` apart from the caller and returns at once. */
16
+ export function backgroundCommand(command) {
17
+ return `nohup sh -c ${shellQuote(command)} >/dev/null 2>&1 &`;
18
+ }
19
+ /** Whole seconds for `timeout(1)`, never less than one. */
20
+ export function timeoutSeconds(ms) {
21
+ return Math.max(1, Math.ceil(ms / 1000));
22
+ }
23
+ /** `timeout` stops a command with 124 (TERM) or 137 (KILL after -k). */
24
+ export function looksTimedOut(exitCode, elapsedMs, limitMs) {
25
+ return (exitCode === 124 || exitCode === 137) && elapsedMs >= limitMs - 250;
26
+ }
27
+ export function shellQuote(s) {
28
+ return `'${s.replace(/'/g, `'\\''`)}'`;
29
+ }
30
+ /** A relative path is taken from the work folder. */
31
+ export function resolveIn(workdir, path) {
32
+ return path.startsWith('/') ? posix.normalize(path) : posix.join(workdir, path);
33
+ }
34
+ /** The exit code the file scripts give for "no such file or folder". */
35
+ export const NOT_FOUND_EXIT = 44;
36
+ /** `sh -c <script> sandbox <path>` scripts for adapters that reach files
37
+ * only through commands. Each exits 44 when the path is not there. */
38
+ export const FILE_SCRIPTS = {
39
+ read: '[ -f "$1" ] || exit 44; cat -- "$1"',
40
+ readBase64: '[ -f "$1" ] || exit 44; base64 < "$1"',
41
+ write: 'mkdir -p -- "$(dirname -- "$1")" && cat > "$1"',
42
+ list: '[ -d "$1" ] || exit 44; cd -- "$1" || exit 44; ' +
43
+ 'for f in * .[!.]* ..?*; do [ -e "$f" ] || [ -L "$f" ] || continue; ' +
44
+ 'if [ -d "$f" ]; then printf \'d\\t0\\t%s\\n\' "$f"; ' +
45
+ 'else printf \'f\\t%s\\t%s\\n\' "$(wc -c < "$f" | tr -d \' \')" "$f"; fi; done',
46
+ mkdir: 'mkdir -p -- "$1"',
47
+ exists: '[ -e "$1" ] || [ -L "$1" ]',
48
+ remove: 'rm -rf -- "$1"',
49
+ };
50
+ /** Reads what FILE_SCRIPTS.list printed. */
51
+ export function parseListing(out) {
52
+ const entries = [];
53
+ for (const line of out.split('\n')) {
54
+ if (!line)
55
+ continue;
56
+ const [kind, size, ...rest] = line.split('\t');
57
+ const name = rest.join('\t');
58
+ entries.push(kind === 'd' ? { name, type: 'directory' } : { name, type: 'file', size: Number(size) || 0 });
59
+ }
60
+ return sortEntries(entries);
61
+ }
62
+ export function sortEntries(entries) {
63
+ return entries.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
64
+ }
65
+ /** Collects one output stream: keeps up to MAX_COMMAND_OUTPUT_BYTES, hands
66
+ * each piece on as text as it comes, never splitting a character. */
67
+ export class OutputCollector {
68
+ onText;
69
+ decoder = new TextDecoder();
70
+ parts = [];
71
+ kept = 0;
72
+ truncated = false;
73
+ constructor(onText) {
74
+ this.onText = onText;
75
+ }
76
+ push(chunk) {
77
+ let bytes = chunk;
78
+ if (this.kept + bytes.length > MAX_COMMAND_OUTPUT_BYTES) {
79
+ bytes = bytes.subarray(0, Math.max(0, MAX_COMMAND_OUTPUT_BYTES - this.kept));
80
+ this.truncated = true;
81
+ }
82
+ this.kept += bytes.length;
83
+ if (bytes.length === 0)
84
+ return;
85
+ const text = this.decoder.decode(bytes, { stream: true });
86
+ if (text)
87
+ this.add(text);
88
+ }
89
+ end() {
90
+ const rest = this.decoder.decode();
91
+ // Past the cap, a character cut in half is dropped rather than shown
92
+ // as a broken one.
93
+ if (rest && !this.truncated)
94
+ this.add(rest);
95
+ return this.parts.join('');
96
+ }
97
+ add(text) {
98
+ this.parts.push(text);
99
+ this.onText?.(text);
100
+ }
101
+ }
102
+ /** Output from an adapter that hands it over whole, cut to
103
+ * MAX_COMMAND_OUTPUT_BYTES the way OutputCollector cuts a stream. */
104
+ export function capOutput(text) {
105
+ const bytes = new TextEncoder().encode(text);
106
+ if (bytes.length <= MAX_COMMAND_OUTPUT_BYTES)
107
+ return { text, truncated: false };
108
+ return { text: new TextDecoder().decode(bytes.subarray(0, MAX_COMMAND_OUTPUT_BYTES)).replace(/\uFFFD$/, ''), truncated: true };
109
+ }
110
+ /** Random lowercase letters and digits, for sandbox names. */
111
+ export function randomId(length = 12) {
112
+ const alphabet = 'abcdefghijklmnopqrstuvwxyz0123456789';
113
+ const bytes = crypto.getRandomValues(new Uint8Array(length));
114
+ let out = '';
115
+ for (const b of bytes)
116
+ out += alphabet[b % alphabet.length];
117
+ return out;
118
+ }
119
+ /** Base64 without the line breaks some `base64` tools add. */
120
+ export function decodeBase64(text) {
121
+ return Uint8Array.from(Buffer.from(text.replace(/\s+/g, ''), 'base64'));
122
+ }
123
+ export function encodeBase64(bytes) {
124
+ return Buffer.from(bytes).toString('base64');
125
+ }
126
+ export function toBytes(content) {
127
+ return typeof content === 'string' ? new TextEncoder().encode(content) : content;
128
+ }
129
+ //# sourceMappingURL=sandbox-shell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox-shell.js","sourceRoot":"","sources":["../../src/adapters/sandbox-shell.ts"],"names":[],"mappings":"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"}