@fastagent-sh/fastagent 0.24.4 → 0.25.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 (480) hide show
  1. package/README.md +53 -82
  2. package/dist/agent-api.d.ts +452 -0
  3. package/dist/agent-api.js +201 -0
  4. package/dist/answer-text.d.ts +8 -0
  5. package/dist/answer-text.js +18 -0
  6. package/dist/atomic-write.d.ts +2 -2
  7. package/dist/atomic-write.js +2 -2
  8. package/dist/authoring.d.ts +77 -0
  9. package/dist/authoring.js +238 -0
  10. package/dist/channel.d.ts +29 -15
  11. package/dist/channel.js +4 -1
  12. package/dist/channels/agentcore-protocol.d.ts +36 -50
  13. package/dist/channels/agentcore-protocol.js +3 -3
  14. package/dist/channels/agentcore-service.d.ts +8 -18
  15. package/dist/channels/agentcore-service.js +108 -127
  16. package/dist/channels/agentcore.d.ts +8 -24
  17. package/dist/channels/agentcore.js +32 -65
  18. package/dist/channels/body.d.ts +0 -16
  19. package/dist/channels/body.js +0 -25
  20. package/dist/channels/busy.js +6 -1
  21. package/dist/channels/context.d.ts +4 -0
  22. package/dist/channels/context.js +35 -0
  23. package/dist/channels/discover.d.ts +18 -20
  24. package/dist/channels/discover.js +41 -99
  25. package/dist/channels/feishu/feishu-api.d.ts +54 -4
  26. package/dist/channels/feishu/feishu-api.js +192 -149
  27. package/dist/channels/feishu/feishu.d.ts +3 -0
  28. package/dist/channels/feishu/feishu.js +117 -106
  29. package/dist/channels/feishu/history.d.ts +55 -0
  30. package/dist/channels/feishu/history.js +199 -0
  31. package/dist/channels/feishu/invoke-turn.d.ts +13 -11
  32. package/dist/channels/feishu/invoke-turn.js +9 -10
  33. package/dist/channels/feishu/model.d.ts +2 -1
  34. package/dist/channels/feishu/normalize.js +100 -0
  35. package/dist/channels/feishu/preview.d.ts +2 -2
  36. package/dist/channels/feishu/register-webhook.d.ts +1 -0
  37. package/dist/channels/feishu/register-webhook.js +3 -2
  38. package/dist/channels/feishu/scaffold/channel.ts +65 -46
  39. package/dist/channels/feishu/scaffold/feishu-send.ts +38 -33
  40. package/dist/channels/feishu/scaffold/feishu-threads.ts +25 -0
  41. package/dist/channels/feishu/setup-mode.d.ts +45 -25
  42. package/dist/channels/feishu/setup-mode.js +74 -23
  43. package/dist/channels/feishu/shared-api.d.ts +24 -6
  44. package/dist/channels/feishu/shared-api.js +30 -24
  45. package/dist/channels/kit/context-buffer.d.ts +11 -2
  46. package/dist/channels/kit/context-buffer.js +7 -4
  47. package/dist/channels/kit/delivery.d.ts +19 -3
  48. package/dist/channels/kit/delivery.js +74 -15
  49. package/dist/channels/kit/event-stream.js +2 -1
  50. package/dist/channels/kit/invoke-turn-kit.d.ts +41 -41
  51. package/dist/channels/kit/invoke-turn-kit.js +62 -71
  52. package/dist/channels/kit/place-history.d.ts +107 -0
  53. package/dist/channels/kit/place-history.js +182 -0
  54. package/dist/channels/kit/preview-kit.d.ts +9 -5
  55. package/dist/channels/kit/preview-kit.js +36 -15
  56. package/dist/channels/kit/room-threads.d.ts +46 -0
  57. package/dist/channels/kit/room-threads.js +81 -0
  58. package/dist/channels/kit/seen.js +1 -1
  59. package/dist/channels/kit/stop-command.d.ts +6 -3
  60. package/dist/channels/kit/stop-command.js +20 -18
  61. package/dist/channels/kit/thread-fork.d.ts +17 -0
  62. package/dist/channels/kit/thread-fork.js +43 -0
  63. package/dist/channels/kit/thread-participants.js +1 -1
  64. package/dist/channels/kit/transport.d.ts +5 -0
  65. package/dist/channels/kit/transport.js +5 -0
  66. package/dist/channels/kit/turn-runner.d.ts +10 -9
  67. package/dist/channels/kit/turn-runner.js +17 -19
  68. package/dist/channels/kit/turn-store.d.ts +5 -4
  69. package/dist/channels/kit/turn-store.js +5 -5
  70. package/dist/channels/lark/lark.d.ts +3 -0
  71. package/dist/channels/lark/lark.js +5 -0
  72. package/dist/channels/lark/onboard.d.ts +5 -3
  73. package/dist/channels/lark/onboard.js +14 -14
  74. package/dist/channels/lark/scaffold/channel.ts +67 -44
  75. package/dist/channels/lark/scaffold/lark-send.ts +38 -33
  76. package/dist/channels/lark/scaffold/lark-threads.ts +25 -0
  77. package/dist/channels/respond.d.ts +0 -4
  78. package/dist/channels/respond.js +1 -1
  79. package/dist/channels/router.d.ts +18 -0
  80. package/dist/channels/router.js +68 -0
  81. package/dist/channels/serve.d.ts +5 -70
  82. package/dist/channels/serve.js +105 -287
  83. package/dist/channels/slack/history.d.ts +42 -0
  84. package/dist/channels/slack/history.js +282 -0
  85. package/dist/channels/slack/invoke-turn.d.ts +12 -5
  86. package/dist/channels/slack/invoke-turn.js +7 -5
  87. package/dist/channels/slack/manifest.d.ts +1 -4
  88. package/dist/channels/slack/manifest.js +22 -10
  89. package/dist/channels/slack/model.d.ts +2 -1
  90. package/dist/channels/slack/onboard.d.ts +0 -2
  91. package/dist/channels/slack/onboard.js +2 -4
  92. package/dist/channels/slack/onboarding-state.d.ts +0 -2
  93. package/dist/channels/slack/onboarding-state.js +0 -1
  94. package/dist/channels/slack/parse.d.ts +0 -5
  95. package/dist/channels/slack/parse.js +1 -16
  96. package/dist/channels/slack/preview.d.ts +2 -3
  97. package/dist/channels/slack/preview.js +78 -52
  98. package/dist/channels/slack/register-webhook.d.ts +1 -0
  99. package/dist/channels/slack/register-webhook.js +6 -5
  100. package/dist/channels/slack/scaffold/channel.ts +23 -24
  101. package/dist/channels/slack/scaffold/slack-send.ts +50 -43
  102. package/dist/channels/slack/scaffold/slack-threads.ts +29 -0
  103. package/dist/channels/slack/setup-server.d.ts +19 -0
  104. package/dist/channels/slack/setup-server.js +113 -11
  105. package/dist/channels/slack/shared-api.d.ts +15 -4
  106. package/dist/channels/slack/shared-api.js +19 -14
  107. package/dist/channels/slack/slack-api.d.ts +61 -2
  108. package/dist/channels/slack/slack-api.js +28 -5
  109. package/dist/channels/slack/slack.js +97 -52
  110. package/dist/channels/slack/welcomed.js +1 -1
  111. package/dist/channels/telegram/context-buffer.d.ts +6 -1
  112. package/dist/channels/telegram/context-buffer.js +19 -0
  113. package/dist/channels/telegram/invoke-turn.d.ts +8 -4
  114. package/dist/channels/telegram/invoke-turn.js +7 -7
  115. package/dist/channels/telegram/parse.d.ts +7 -2
  116. package/dist/channels/telegram/parse.js +7 -0
  117. package/dist/channels/telegram/preview.d.ts +2 -2
  118. package/dist/channels/telegram/register-webhook.d.ts +1 -0
  119. package/dist/channels/telegram/register-webhook.js +3 -2
  120. package/dist/channels/telegram/scaffold/channel.ts +27 -28
  121. package/dist/channels/telegram/scaffold/telegram-send.ts +61 -108
  122. package/dist/channels/telegram/shared-api.d.ts +34 -0
  123. package/dist/channels/telegram/shared-api.js +79 -0
  124. package/dist/channels/telegram/telegram-api.d.ts +15 -5
  125. package/dist/channels/telegram/telegram-api.js +10 -6
  126. package/dist/channels/telegram/telegram.js +27 -21
  127. package/dist/channels/telegram/turn-store.js +1 -1
  128. package/dist/channels/{kit/turn-queue.d.ts → turn-queue.d.ts} +2 -2
  129. package/dist/channels/{kit/turn-queue.js → turn-queue.js} +10 -10
  130. package/dist/cli/add-feishu.d.ts +42 -12
  131. package/dist/cli/add-feishu.js +177 -124
  132. package/dist/cli/add-slack.d.ts +8 -3
  133. package/dist/cli/add-slack.js +115 -63
  134. package/dist/cli/auth-view.d.ts +10 -3
  135. package/dist/cli/auth-view.js +8 -6
  136. package/dist/cli/box-login.d.ts +17 -7
  137. package/dist/cli/box-login.js +46 -12
  138. package/dist/cli/commands/add.d.ts +15 -4
  139. package/dist/cli/commands/add.js +252 -143
  140. package/dist/cli/commands/auth.d.ts +6 -0
  141. package/dist/cli/commands/auth.js +50 -0
  142. package/dist/cli/commands/content.d.ts +6 -0
  143. package/dist/cli/commands/content.js +45 -0
  144. package/dist/cli/commands/deploy/agentcore.js +50 -77
  145. package/dist/cli/commands/deploy/docker.js +38 -39
  146. package/dist/cli/commands/deploy/fly.js +21 -18
  147. package/dist/cli/commands/deploy/host-login.d.ts +26 -0
  148. package/dist/cli/commands/deploy/host-login.js +90 -0
  149. package/dist/cli/commands/deploy/railway.js +21 -26
  150. package/dist/cli/commands/deploy/shared.d.ts +45 -17
  151. package/dist/cli/commands/deploy/shared.js +34 -15
  152. package/dist/cli/commands/deploy.d.ts +0 -4
  153. package/dist/cli/commands/deploy.js +237 -50
  154. package/dist/cli/commands/destroy.js +8 -6
  155. package/dist/cli/commands/dev.d.ts +0 -2
  156. package/dist/cli/commands/dev.js +20 -19
  157. package/dist/cli/commands/env.d.ts +12 -0
  158. package/dist/cli/commands/env.js +190 -0
  159. package/dist/cli/commands/info.js +95 -156
  160. package/dist/cli/commands/init.d.ts +2 -2
  161. package/dist/cli/commands/init.js +35 -33
  162. package/dist/cli/commands/invoke.d.ts +6 -0
  163. package/dist/cli/commands/invoke.js +131 -16
  164. package/dist/cli/commands/login.d.ts +31 -2
  165. package/dist/cli/commands/login.js +413 -64
  166. package/dist/cli/commands/logout.d.ts +4 -0
  167. package/dist/cli/commands/logout.js +53 -0
  168. package/dist/cli/commands/logs.js +8 -6
  169. package/dist/cli/commands/models.d.ts +2 -1
  170. package/dist/cli/commands/models.js +39 -37
  171. package/dist/cli/commands/schedules.d.ts +21 -0
  172. package/dist/cli/commands/schedules.js +143 -0
  173. package/dist/cli/commands/start.d.ts +11 -10
  174. package/dist/cli/commands/start.js +35 -62
  175. package/dist/cli/content-view.d.ts +9 -0
  176. package/dist/cli/content-view.js +26 -0
  177. package/dist/cli/fail.d.ts +9 -12
  178. package/dist/cli/fail.js +17 -14
  179. package/dist/cli/invoke-stream.d.ts +12 -3
  180. package/dist/cli/invoke-stream.js +85 -23
  181. package/dist/cli/kernel.d.ts +9 -2
  182. package/dist/cli/kernel.js +15 -6
  183. package/dist/cli/login-relay.d.ts +3 -2
  184. package/dist/cli/login-relay.js +18 -6
  185. package/dist/cli/models-view.d.ts +5 -1
  186. package/dist/cli/models-view.js +1 -1
  187. package/dist/cli/person.d.ts +10 -0
  188. package/dist/cli/person.js +23 -0
  189. package/dist/cli/program.js +421 -203
  190. package/dist/cli/serve.d.ts +13 -63
  191. package/dist/cli/serve.js +31 -121
  192. package/dist/cli/shared.d.ts +21 -48
  193. package/dist/cli/shared.js +68 -89
  194. package/dist/cli/ticket.d.ts +136 -0
  195. package/dist/cli/ticket.js +476 -0
  196. package/dist/client.d.ts +7 -0
  197. package/dist/client.js +2 -0
  198. package/dist/content/declare.d.ts +70 -0
  199. package/dist/content/declare.js +163 -0
  200. package/dist/content/file.d.ts +32 -0
  201. package/dist/content/file.js +119 -0
  202. package/dist/content/git.d.ts +41 -0
  203. package/dist/content/git.js +217 -0
  204. package/dist/content/mount.d.ts +2 -0
  205. package/dist/content/mount.js +15 -0
  206. package/dist/content/resolve.d.ts +52 -0
  207. package/dist/content/resolve.js +151 -0
  208. package/dist/content/source.d.ts +27 -0
  209. package/dist/content/source.js +53 -0
  210. package/dist/conversation-sessions.d.ts +26 -0
  211. package/dist/conversation-sessions.js +99 -0
  212. package/dist/declared-secrets.d.ts +19 -37
  213. package/dist/declared-secrets.js +16 -58
  214. package/dist/deploy/agentcore/destroy.d.ts +3 -3
  215. package/dist/deploy/agentcore/destroy.js +46 -28
  216. package/dist/deploy/agentcore/forwarder.js +105 -22
  217. package/dist/deploy/agentcore/logs.js +1 -1
  218. package/dist/deploy/agentcore/plan.d.ts +10 -24
  219. package/dist/deploy/agentcore/plan.js +31 -135
  220. package/dist/deploy/agentcore/run.d.ts +1 -1
  221. package/dist/deploy/agentcore/run.js +8 -5
  222. package/dist/deploy/agentcore/shell.d.ts +1 -1
  223. package/dist/deploy/agentcore/shell.js +5 -5
  224. package/dist/deploy/api.d.ts +34 -0
  225. package/dist/deploy/api.js +50 -0
  226. package/dist/deploy/box-shell.d.ts +6 -0
  227. package/dist/deploy/box-shell.js +7 -0
  228. package/dist/deploy/build-context.d.ts +7 -5
  229. package/dist/deploy/build-context.js +41 -35
  230. package/dist/deploy/channel-ingress.d.ts +6 -1
  231. package/dist/deploy/channel-ingress.js +18 -5
  232. package/dist/deploy/container.d.ts +22 -9
  233. package/dist/deploy/container.js +96 -55
  234. package/dist/deploy/docker/plan.d.ts +3 -2
  235. package/dist/deploy/docker/plan.js +13 -14
  236. package/dist/deploy/docker/run.d.ts +2 -2
  237. package/dist/deploy/docker/run.js +8 -4
  238. package/dist/deploy/fly/plan.d.ts +1 -1
  239. package/dist/deploy/fly/plan.js +12 -21
  240. package/dist/deploy/fly/run.d.ts +10 -6
  241. package/dist/deploy/fly/run.js +11 -6
  242. package/dist/deploy/hosts.d.ts +2 -1
  243. package/dist/deploy/hosts.js +2 -1
  244. package/dist/deploy/preflight.d.ts +21 -23
  245. package/dist/deploy/preflight.js +222 -201
  246. package/dist/deploy/railway/plan.d.ts +8 -6
  247. package/dist/deploy/railway/plan.js +15 -58
  248. package/dist/deploy/railway/run.d.ts +8 -3
  249. package/dist/deploy/railway/run.js +12 -8
  250. package/dist/deploy/residency.d.ts +5 -11
  251. package/dist/deploy/residency.js +0 -6
  252. package/dist/deploy/runner.d.ts +1 -1
  253. package/dist/deploy/runner.js +1 -1
  254. package/dist/deploy/secrets.d.ts +16 -2
  255. package/dist/deploy/secrets.js +33 -6
  256. package/dist/deploy/workspace.d.ts +11 -6
  257. package/dist/deploy/workspace.js +55 -38
  258. package/dist/dev-supervisor.d.ts +11 -2
  259. package/dist/dev-supervisor.js +51 -26
  260. package/dist/effect-port.d.ts +4 -4
  261. package/dist/effect-port.js +4 -4
  262. package/dist/environment/apt.d.ts +4 -0
  263. package/dist/environment/apt.js +32 -0
  264. package/dist/environment/declare.d.ts +59 -0
  265. package/dist/environment/declare.js +210 -0
  266. package/dist/environment/mise.d.ts +50 -0
  267. package/dist/environment/mise.js +268 -0
  268. package/dist/feishu.d.ts +2 -2
  269. package/dist/feishu.js +2 -2
  270. package/dist/git.d.ts +13 -0
  271. package/dist/git.js +55 -0
  272. package/dist/harnesses/models/catalog.d.ts +20 -0
  273. package/dist/harnesses/models/catalog.js +254 -0
  274. package/dist/{engines/pi/auth.d.ts → harnesses/models/credentials.d.ts} +3 -3
  275. package/dist/{engines/pi/auth.js → harnesses/models/credentials.js} +3 -3
  276. package/dist/harnesses/models/environment.d.ts +43 -0
  277. package/dist/harnesses/models/environment.js +82 -0
  278. package/dist/{engines/pi → harnesses/models}/login.d.ts +57 -26
  279. package/dist/{engines/pi → harnesses/models}/login.js +187 -79
  280. package/dist/harnesses/models/models.d.ts +83 -0
  281. package/dist/harnesses/models/models.js +158 -0
  282. package/dist/harnesses/pi-durable/agent.d.ts +42 -0
  283. package/dist/harnesses/pi-durable/agent.js +579 -0
  284. package/dist/harnesses/pi-durable/defaults.d.ts +28 -0
  285. package/dist/harnesses/pi-durable/defaults.js +26 -0
  286. package/dist/harnesses/pi-durable/define.d.ts +77 -0
  287. package/dist/harnesses/pi-durable/define.js +28 -0
  288. package/dist/harnesses/pi-durable/entries.d.ts +32 -0
  289. package/dist/harnesses/pi-durable/entries.js +126 -0
  290. package/dist/harnesses/pi-durable/events.d.ts +25 -0
  291. package/dist/harnesses/pi-durable/events.js +238 -0
  292. package/dist/harnesses/pi-durable/ids.d.ts +16 -0
  293. package/dist/harnesses/pi-durable/ids.js +55 -0
  294. package/dist/harnesses/pi-durable/messages.d.ts +41 -0
  295. package/dist/harnesses/pi-durable/messages.js +116 -0
  296. package/dist/harnesses/pi-durable/open.d.ts +88 -0
  297. package/dist/harnesses/pi-durable/open.js +329 -0
  298. package/dist/harnesses/pi-durable/reads.d.ts +30 -0
  299. package/dist/harnesses/pi-durable/reads.js +94 -0
  300. package/dist/harnesses/pi-durable/registry.d.ts +18 -0
  301. package/dist/harnesses/pi-durable/registry.js +56 -0
  302. package/dist/harnesses/pi-durable/release.d.ts +13 -0
  303. package/dist/harnesses/pi-durable/release.js +40 -0
  304. package/dist/harnesses/pi-durable/serve.d.ts +80 -0
  305. package/dist/harnesses/pi-durable/serve.js +156 -0
  306. package/dist/harnesses/pi-durable/sessions.d.ts +27 -0
  307. package/dist/harnesses/pi-durable/sessions.js +47 -0
  308. package/dist/harnesses/pi-durable/storage.d.ts +4 -0
  309. package/dist/harnesses/pi-durable/storage.js +49 -0
  310. package/dist/harnesses/pi-durable/stream.d.ts +20 -0
  311. package/dist/harnesses/pi-durable/stream.js +221 -0
  312. package/dist/harnesses/pi-durable/text.d.ts +30 -0
  313. package/dist/harnesses/pi-durable/text.js +292 -0
  314. package/dist/harnesses/pi-durable/wake.d.ts +4 -0
  315. package/dist/harnesses/pi-durable/wake.js +81 -0
  316. package/dist/http/client.d.ts +6 -0
  317. package/dist/http/client.js +256 -0
  318. package/dist/http/contract.d.ts +541 -0
  319. package/dist/http/contract.js +179 -0
  320. package/dist/http/server.d.ts +34 -0
  321. package/dist/http/server.js +194 -0
  322. package/dist/index.d.ts +17 -4
  323. package/dist/index.js +10 -5
  324. package/dist/lark.d.ts +2 -2
  325. package/dist/lark.js +2 -2
  326. package/dist/locked-file.d.ts +17 -0
  327. package/dist/{engines/pi/locked-file.js → locked-file.js} +16 -10
  328. package/dist/once.d.ts +6 -0
  329. package/dist/once.js +23 -0
  330. package/dist/paths.d.ts +36 -52
  331. package/dist/paths.js +66 -182
  332. package/dist/runtime.d.ts +25 -2
  333. package/dist/runtime.js +27 -0
  334. package/dist/scaffold/add-channel.d.ts +14 -27
  335. package/dist/scaffold/add-channel.js +82 -180
  336. package/dist/scaffold/init.d.ts +17 -18
  337. package/dist/scaffold/init.js +87 -99
  338. package/dist/scaffold/templates/SYSTEM.md +12 -0
  339. package/dist/scaffold/templates/env.example +4 -10
  340. package/dist/scaffold/templates/fastagent.config.ts +21 -33
  341. package/dist/scaffold/templates/gitignore +8 -1
  342. package/dist/scaffold/templates/skills/writing-great-skills/SKILL.md +1 -2
  343. package/dist/scaffold/templates.d.ts +9 -4
  344. package/dist/scaffold/templates.js +7 -5
  345. package/dist/scaffold/vendor-skill.d.ts +1 -4
  346. package/dist/scaffold/vendor-skill.js +5 -6
  347. package/dist/schedule/cron.d.ts +13 -0
  348. package/dist/schedule/cron.js +52 -0
  349. package/dist/schedule/eventbridge-cron.d.ts +17 -0
  350. package/dist/schedule/eventbridge-cron.js +88 -0
  351. package/dist/schedule/schedule.d.ts +23 -0
  352. package/dist/schedule/schedule.js +34 -0
  353. package/dist/schedule/scheduler.d.ts +34 -33
  354. package/dist/schedule/scheduler.js +251 -137
  355. package/dist/schedule/state.d.ts +4 -14
  356. package/dist/schedule/state.js +7 -7
  357. package/dist/schedule/wake-alarm.d.ts +22 -2
  358. package/dist/schedule/wake-alarm.js +66 -20
  359. package/dist/schedule/wakeups.d.ts +16 -15
  360. package/dist/schedule/wakeups.js +47 -45
  361. package/dist/service.d.ts +56 -169
  362. package/dist/service.js +91 -187
  363. package/dist/serving-command.d.ts +10 -0
  364. package/dist/serving-command.js +16 -0
  365. package/dist/slack.d.ts +1 -1
  366. package/dist/slack.js +1 -1
  367. package/dist/{channels/kit/state.js → state-file.js} +6 -6
  368. package/dist/telegram.d.ts +1 -0
  369. package/dist/telegram.js +1 -0
  370. package/dist/tunnel.d.ts +3 -0
  371. package/dist/tunnel.js +12 -4
  372. package/dist/value-file.d.ts +21 -0
  373. package/dist/value-file.js +108 -0
  374. package/dist/version.d.ts +5 -0
  375. package/dist/version.js +14 -1
  376. package/package.json +18 -28
  377. package/dist/agent.d.ts +0 -106
  378. package/dist/agent.js +0 -21
  379. package/dist/channels/control.d.ts +0 -31
  380. package/dist/channels/control.js +0 -329
  381. package/dist/channels/define-channel.d.ts +0 -39
  382. package/dist/channels/define-channel.js +0 -9
  383. package/dist/channels/feishu/context-buffer.d.ts +0 -35
  384. package/dist/channels/feishu/context-buffer.js +0 -65
  385. package/dist/channels/feishu/scaffold/channel.websocket.ts +0 -31
  386. package/dist/channels/http.d.ts +0 -23
  387. package/dist/channels/http.js +0 -57
  388. package/dist/channels/lark/scaffold/channel.websocket.ts +0 -31
  389. package/dist/channels/slack/context-buffer.d.ts +0 -23
  390. package/dist/channels/slack/context-buffer.js +0 -37
  391. package/dist/channels/sse.d.ts +0 -4
  392. package/dist/channels/sse.js +0 -66
  393. package/dist/cli/commands/chat.d.ts +0 -3
  394. package/dist/cli/commands/chat.js +0 -14
  395. package/dist/cli/commands/routine-run.d.ts +0 -6
  396. package/dist/cli/commands/routine-run.js +0 -46
  397. package/dist/cli/commands/routine.d.ts +0 -25
  398. package/dist/cli/commands/routine.js +0 -122
  399. package/dist/cli/commands/tool.d.ts +0 -1
  400. package/dist/cli/commands/tool.js +0 -57
  401. package/dist/collect.d.ts +0 -63
  402. package/dist/collect.js +0 -90
  403. package/dist/core.d.ts +0 -13
  404. package/dist/core.js +0 -15
  405. package/dist/engines/pi/agent-models.d.ts +0 -83
  406. package/dist/engines/pi/agent-models.js +0 -120
  407. package/dist/engines/pi/agent-session-factory.d.ts +0 -121
  408. package/dist/engines/pi/agent-session-factory.js +0 -535
  409. package/dist/engines/pi/chat.d.ts +0 -3
  410. package/dist/engines/pi/chat.js +0 -8
  411. package/dist/engines/pi/config.d.ts +0 -71
  412. package/dist/engines/pi/config.js +0 -199
  413. package/dist/engines/pi/create.d.ts +0 -170
  414. package/dist/engines/pi/create.js +0 -343
  415. package/dist/engines/pi/definition.d.ts +0 -74
  416. package/dist/engines/pi/definition.js +0 -236
  417. package/dist/engines/pi/entry-images.d.ts +0 -14
  418. package/dist/engines/pi/entry-images.js +0 -23
  419. package/dist/engines/pi/invoke-session.d.ts +0 -18
  420. package/dist/engines/pi/invoke-session.js +0 -403
  421. package/dist/engines/pi/locked-file.d.ts +0 -9
  422. package/dist/engines/pi/machine.d.ts +0 -53
  423. package/dist/engines/pi/machine.js +0 -137
  424. package/dist/engines/pi/models.d.ts +0 -200
  425. package/dist/engines/pi/models.js +0 -533
  426. package/dist/engines/pi/open.d.ts +0 -180
  427. package/dist/engines/pi/open.js +0 -270
  428. package/dist/engines/pi/openai-account-models.d.ts +0 -35
  429. package/dist/engines/pi/openai-account-models.js +0 -116
  430. package/dist/engines/pi/report.d.ts +0 -18
  431. package/dist/engines/pi/report.js +0 -59
  432. package/dist/engines/pi/retry-event.d.ts +0 -6
  433. package/dist/engines/pi/retry-event.js +0 -15
  434. package/dist/engines/pi/service.d.ts +0 -9
  435. package/dist/engines/pi/service.js +0 -14
  436. package/dist/engines/pi/session-builder.d.ts +0 -13
  437. package/dist/engines/pi/session-builder.js +0 -117
  438. package/dist/engines/pi/session-control.d.ts +0 -77
  439. package/dist/engines/pi/session-control.js +0 -908
  440. package/dist/engines/pi/session-effects.d.ts +0 -14
  441. package/dist/engines/pi/session-effects.js +0 -30
  442. package/dist/engines/pi/session-inheritance.d.ts +0 -21
  443. package/dist/engines/pi/session-inheritance.js +0 -204
  444. package/dist/engines/pi/session-markers.d.ts +0 -49
  445. package/dist/engines/pi/session-markers.js +0 -60
  446. package/dist/engines/pi/session-settings.d.ts +0 -67
  447. package/dist/engines/pi/session-settings.js +0 -119
  448. package/dist/engines/pi/session-store.d.ts +0 -69
  449. package/dist/engines/pi/session-store.js +0 -430
  450. package/dist/engines/pi/tool-context.d.ts +0 -45
  451. package/dist/engines/pi/tool-context.js +0 -31
  452. package/dist/engines/pi/tool.d.ts +0 -99
  453. package/dist/engines/pi/tool.js +0 -118
  454. package/dist/engines/pi/turn-kit.d.ts +0 -92
  455. package/dist/engines/pi/turn-kit.js +0 -288
  456. package/dist/engines/pi/wake-tool.d.ts +0 -9
  457. package/dist/engines/pi/wake-tool.js +0 -92
  458. package/dist/loader.d.ts +0 -41
  459. package/dist/loader.js +0 -116
  460. package/dist/node.d.ts +0 -3
  461. package/dist/node.js +0 -4
  462. package/dist/observe.d.ts +0 -6
  463. package/dist/observe.js +0 -47
  464. package/dist/pi.d.ts +0 -25
  465. package/dist/pi.js +0 -15
  466. package/dist/scaffold/templates/APPEND_SYSTEM.md +0 -12
  467. package/dist/scaffold/templates/tools/fetch-url.ts +0 -25
  468. package/dist/schedule/discover.d.ts +0 -17
  469. package/dist/schedule/discover.js +0 -61
  470. package/dist/schedule/routine.d.ts +0 -43
  471. package/dist/schedule/routine.js +0 -32
  472. package/dist/schedule/run.d.ts +0 -55
  473. package/dist/schedule/run.js +0 -146
  474. package/dist/secrets-gate.d.ts +0 -32
  475. package/dist/secrets-gate.js +0 -33
  476. package/dist/session-remote.d.ts +0 -47
  477. package/dist/session-remote.js +0 -460
  478. package/dist/session.d.ts +0 -466
  479. package/dist/session.js +0 -57
  480. /package/dist/{channels/kit/state.d.ts → state-file.d.ts} +0 -0
@@ -0,0 +1,18 @@
1
+ /** Feed it a message's stream; it answers the text each event adds. */
2
+ export function answerText() {
3
+ let streamed = "";
4
+ return (event) => {
5
+ if (event.type === "delta") {
6
+ if (event.channel !== "text")
7
+ return "";
8
+ streamed += event.text;
9
+ return event.text;
10
+ }
11
+ if (event.type !== "entry" || event.entry.kind !== "assistant")
12
+ return "";
13
+ const text = String(event.entry.data.text ?? "");
14
+ const missing = text.startsWith(streamed) ? text.slice(streamed.length) : "";
15
+ streamed = "";
16
+ return missing;
17
+ };
18
+ }
@@ -11,8 +11,8 @@
11
11
  * redundant with it: `writeFileSync` honours `mode` only when it CREATES the file, so a temp left behind by a crashed
12
12
  * writer would keep its old, possibly looser permissions.
13
13
  *
14
- * `sharedWriters` is for a file SEVERAL processes may write at once (the merged models file, content-addressed, so
15
- * every writer writes the same bytes): each writes its own temp, and the last rename wins. A fixed temp there would
14
+ * `sharedWriters` is for a file SEVERAL processes may write at once (the generated `.fastagent/` files, which every
15
+ * command that reads the definition writes with the same bytes): each writes its own temp, and the last rename wins. A fixed temp there would
16
16
  * let one writer's rename take the other's file and fail it with ENOENT. No test exercises that race: it needs two
17
17
  * processes renaming within the same moment, which a test cannot arrange without being flaky.
18
18
  */
@@ -15,8 +15,8 @@ import { dirname } from "node:path";
15
15
  * redundant with it: `writeFileSync` honours `mode` only when it CREATES the file, so a temp left behind by a crashed
16
16
  * writer would keep its old, possibly looser permissions.
17
17
  *
18
- * `sharedWriters` is for a file SEVERAL processes may write at once (the merged models file, content-addressed, so
19
- * every writer writes the same bytes): each writes its own temp, and the last rename wins. A fixed temp there would
18
+ * `sharedWriters` is for a file SEVERAL processes may write at once (the generated `.fastagent/` files, which every
19
+ * command that reads the definition writes with the same bytes): each writes its own temp, and the last rename wins. A fixed temp there would
20
20
  * let one writer's rename take the other's file and fail it with ENOENT. No test exercises that race: it needs two
21
21
  * processes renaming within the same moment, which a test cannot arrange without being flaky.
22
22
  */
@@ -0,0 +1,77 @@
1
+ import { type BoundContent } from "./content/declare.ts";
2
+ import type { DeclaredEnvironment } from "./environment/declare.ts";
3
+ import { type ResolvedContent } from "./content/resolve.ts";
4
+ import type { ContentAddition } from "./content/source.ts";
5
+ /**
6
+ * A refusal about a content entry's NAME: one that cannot name an entry, one the agent already has, one it does not
7
+ * have. The caller can fix it by naming another (the CLI exits 2 and asks for `--name`).
8
+ */
9
+ export declare class ContentNameError extends Error {
10
+ name: string;
11
+ }
12
+ export interface CreateAgentOptions {
13
+ /** What the agent works on and knows: repositories into `context.json`, this machine's directories into
14
+ * `context.local.json`. */
15
+ content?: ContentAddition[];
16
+ /**
17
+ * Install the agent's dependencies, after the scaffold and before its first commit, so the lockfile is in that
18
+ * commit; the agent's code imports them. A rejection is a failed create: the scaffold is removed again and the error
19
+ * thrown, as when writing the content fails, so the directory is empty for a retry. One that reports its failure
20
+ * some other way (the CLI's resolves, and says the install failed) leaves the agent created.
21
+ */
22
+ install?: (dir: string) => Promise<void>;
23
+ }
24
+ export interface CreatedAgent {
25
+ /** The agent directory, absolute. */
26
+ dir: string;
27
+ /** The files written, relative to `dir`. */
28
+ created: string[];
29
+ /** The content, resolved for this instance. */
30
+ content: ResolvedContent[];
31
+ /**
32
+ * What became of the agent's git repository, as a sentence to show: created with the scaffold as its first commit,
33
+ * or why not (inside a repository that tracks it, git missing, no commit identity).
34
+ */
35
+ repository: string;
36
+ }
37
+ /**
38
+ * Create an agent in `dir`, which must be new or empty. Every content entry is checked before anything is written, and
39
+ * the scaffold is removed again when writing the content fails. The agent is then a git repository whose first commit
40
+ * is what was written:
41
+ * it changes itself, and version control is how its author goes back to a version that worked.
42
+ */
43
+ export declare function createAgent(dir: string, options?: CreateAgentOptions): Promise<CreatedAgent>;
44
+ /**
45
+ * The agent's content, resolved for this instance (what `fastagent content list` shows), and the directories this
46
+ * machine binds that are not here: the agent is not told of those.
47
+ */
48
+ export declare function listContent(agentDir: string): Promise<{
49
+ content: ResolvedContent[];
50
+ absent: BoundContent[];
51
+ }>;
52
+ /**
53
+ * What an edit leaves: the entry it added or removed, by name, the agent's content after it, and what to tell the
54
+ * user about what was left on this machine.
55
+ */
56
+ export interface ContentEdit {
57
+ name: string;
58
+ content: ResolvedContent[];
59
+ notes: string[];
60
+ }
61
+ /**
62
+ * Add a content entry to the agent in `agentDir`: its repository to `context.json`, its directory on this machine to
63
+ * `context.local.json`, or both. A name that cannot be one, or that the agent already has (ignoring case), is a
64
+ * {@link ContentNameError}.
65
+ */
66
+ export declare function addContent(agentDir: string, addition: ContentAddition): Promise<ContentEdit>;
67
+ /**
68
+ * Remove the agent's content entry named `name` (ignoring case), from `context.json` and from this machine's
69
+ * `context.local.json`. A clone at `content/<name>` is left as it is, and said: it may hold the agent's work, and
70
+ * fastagent never deletes a directory in `content/`. A name the agent does not have is a {@link ContentNameError}.
71
+ */
72
+ export declare function removeContent(agentDir: string, name: string): Promise<ContentEdit>;
73
+ /**
74
+ * Replace the environment `context.json` declares with what `change` makes of it as it is now, under the lock content
75
+ * edits take, keeping the rest of the file as it is; and return what was written.
76
+ */
77
+ export declare function writeEnvironment(agentDir: string, change: (current: DeclaredEnvironment | undefined) => DeclaredEnvironment): Promise<DeclaredEnvironment>;
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Creating an agent and editing its content: `fastagent init` and `fastagent content` are thin wrappers over these (and
3
+ * `fastagent env` writes its declaration through {@link writeEnvironment}), so the rules live here, not in a command.
4
+ * Nothing here prints or exits; every refusal is thrown with the message the CLI shows. Not exported from the package
5
+ * (#847 decides how a client reaches them).
6
+ */
7
+ import { existsSync, lstatSync, readFileSync, statSync } from "node:fs";
8
+ import { rm } from "node:fs/promises";
9
+ import { join, resolve } from "node:path";
10
+ import { writeFileAtomic } from "./atomic-write.js";
11
+ import { GitNotInstalled, gitFor } from "./git.js";
12
+ import { CONTEXT_FILE, LOCAL_CONTEXT_FILE, contentEntryPath, resolveAgentDir } from "./paths.js";
13
+ import { initRepository, scaffoldAgent } from "./scaffold/init.js";
14
+ import { canonicalBinding, canonicalEntry, declareBindings, declareContent, isContentName, } from "./content/declare.js";
15
+ import { contextFileText, loadContent, localContextFileText, parseContextFile, parseLocalContextFile, } from "./content/file.js";
16
+ import { checkBinding, contentAbsentHere, resolveContent } from "./content/resolve.js";
17
+ import { withLockedFile } from "./locked-file.js";
18
+ /** `context.json` is part of the definition, read by whoever reads the agent. */
19
+ const CONTEXT_FILE_MODE = 0o644;
20
+ /**
21
+ * A refusal about a content entry's NAME: one that cannot name an entry, one the agent already has, one it does not
22
+ * have. The caller can fix it by naming another (the CLI exits 2 and asks for `--name`).
23
+ */
24
+ export class ContentNameError extends Error {
25
+ name = "ContentNameError";
26
+ }
27
+ /**
28
+ * Create an agent in `dir`, which must be new or empty. Every content entry is checked before anything is written, and
29
+ * the scaffold is removed again when writing the content fails. The agent is then a git repository whose first commit
30
+ * is what was written:
31
+ * it changes itself, and version control is how its author goes back to a version that worked.
32
+ */
33
+ export async function createAgent(dir, options = {}) {
34
+ const agentDir = resolve(dir);
35
+ const additions = options.content ?? [];
36
+ let maps = { content: {}, bindings: {} };
37
+ for (const addition of additions)
38
+ maps = withAddition(agentDir, maps, addition).maps;
39
+ const { created, undo } = await scaffoldAgent(agentDir);
40
+ const removeAll = async (error) => {
41
+ await rm(join(agentDir, CONTEXT_FILE), { force: true });
42
+ await rm(join(agentDir, LOCAL_CONTEXT_FILE), { force: true });
43
+ await undo();
44
+ throw error;
45
+ };
46
+ // The content was checked above, so a refusal here is one that check could not foresee (the disk changed in
47
+ // between); the scaffold goes with it, or a retry would find "already an agent" declaring no content.
48
+ try {
49
+ if (Object.keys(maps.content).length > 0) {
50
+ writeFileAtomic(join(agentDir, CONTEXT_FILE), contextFileText({ content: maps.content }), CONTEXT_FILE_MODE);
51
+ }
52
+ if (Object.keys(maps.bindings).length > 0) {
53
+ writeFileAtomic(join(agentDir, LOCAL_CONTEXT_FILE), localContextFileText(maps.bindings), CONTEXT_FILE_MODE);
54
+ }
55
+ }
56
+ catch (error) {
57
+ await removeAll(error);
58
+ }
59
+ if (options.install)
60
+ await options.install(agentDir).catch(removeAll);
61
+ const content = resolveContent(agentDir, declarationOf(agentDir, maps));
62
+ return { dir: agentDir, created, content, repository: await initRepository(agentDir) };
63
+ }
64
+ /**
65
+ * The agent's content, resolved for this instance (what `fastagent content list` shows), and the directories this
66
+ * machine binds that are not here: the agent is not told of those.
67
+ */
68
+ export async function listContent(agentDir) {
69
+ const dir = resolveAgentDir(agentDir);
70
+ const declaration = loadContent(dir);
71
+ return { content: resolveContent(dir, declaration), absent: contentAbsentHere(declaration) };
72
+ }
73
+ /**
74
+ * Add a content entry to the agent in `agentDir`: its repository to `context.json`, its directory on this machine to
75
+ * `context.local.json`, or both. A name that cannot be one, or that the agent already has (ignoring case), is a
76
+ * {@link ContentNameError}.
77
+ */
78
+ export async function addContent(agentDir, addition) {
79
+ const dir = resolveAgentDir(agentDir);
80
+ const declaration = await editContext(dir, (shared, local) => {
81
+ const { maps } = withAddition(dir, mapsOf(shared, local), addition);
82
+ return {
83
+ result: declarationOf(dir, maps),
84
+ ...(addition.entry !== undefined ? { shared: contextFileText({ ...shared, content: maps.content }) } : {}),
85
+ ...(addition.binding !== undefined ? { local: localContextFileText(maps.bindings) } : {}),
86
+ };
87
+ });
88
+ const notes = addition.binding !== undefined ? unignoredLocalFile(dir) : [];
89
+ return { name: addition.name, content: resolveContent(dir, declaration), notes };
90
+ }
91
+ /**
92
+ * Remove the agent's content entry named `name` (ignoring case), from `context.json` and from this machine's
93
+ * `context.local.json`. A clone at `content/<name>` is left as it is, and said: it may hold the agent's work, and
94
+ * fastagent never deletes a directory in `content/`. A name the agent does not have is a {@link ContentNameError}.
95
+ */
96
+ export async function removeContent(agentDir, name) {
97
+ const dir = resolveAgentDir(agentDir);
98
+ const { removed, wasDeclared, declaration } = await editContext(dir, (shared, local) => {
99
+ const found = entryNamed(mapsOf(shared, local), name);
100
+ const maps = {
101
+ content: without(shared.content, found.name),
102
+ bindings: without(local.content, found.name),
103
+ };
104
+ const declaration = declarationOf(dir, maps);
105
+ // What is left is resolved before it is written, so an entry that cannot be refuses the edit rather than failing
106
+ // it once it is made. The removed one is not asked: removing a broken entry is how it is mended.
107
+ resolveContent(dir, declaration);
108
+ return {
109
+ result: { removed: found.name, wasDeclared: found.shared, declaration },
110
+ ...(found.shared ? { shared: contextFileText({ ...shared, content: maps.content }) } : {}),
111
+ ...(found.local ? { local: localContextFileText(maps.bindings) } : {}),
112
+ };
113
+ });
114
+ const notes = [];
115
+ if (wasDeclared && lstatSync(contentEntryPath(dir, removed), { throwIfNoEntry: false })) {
116
+ notes.push(`content/${removed} is left as it is: it may hold the agent's work — delete it once nothing in it is needed`);
117
+ }
118
+ return { name: removed, content: resolveContent(dir, declaration), notes };
119
+ }
120
+ /**
121
+ * `maps` with `addition` among them, checked as a whole before anything is written: its name can name an entry and is
122
+ * not taken (ignoring case), the entry is valid, a repository to clone has nothing at `content/<name>` yet, a
123
+ * directory to bind can be bound, and every other entry still resolves (one that does not refuses the edit, not fails
124
+ * it once made).
125
+ */
126
+ function withAddition(agentDir, maps, addition) {
127
+ const { name, entry, binding } = addition;
128
+ if (entry === undefined && binding === undefined)
129
+ throw new Error(`content "${name}": nothing to add`);
130
+ if (!isContentName(name)) {
131
+ throw new ContentNameError(`"${name}" cannot name content (one path segment of letters, digits, "-" and "_")`);
132
+ }
133
+ const taken = [...Object.keys(maps.content), ...Object.keys(maps.bindings)].find((key) => key.toLowerCase() === name.toLowerCase());
134
+ if (taken)
135
+ throw new ContentNameError(`this agent already has content named "${taken}"`);
136
+ const next = {
137
+ content: entry !== undefined ? { ...maps.content, [name]: canonicalEntry(entry) } : maps.content,
138
+ bindings: binding !== undefined ? { ...maps.bindings, [name]: canonicalBinding(binding) } : maps.bindings,
139
+ };
140
+ const declaration = declarationOf(agentDir, next);
141
+ if (binding === undefined) {
142
+ if (lstatSync(contentEntryPath(agentDir, name), { throwIfNoEntry: false })) {
143
+ throw new Error(`content/${name} already exists in ${agentDir}: move it away first`);
144
+ }
145
+ }
146
+ else {
147
+ const bound = declaration.bound.find((b) => b.name === name);
148
+ const repository = declaration.declared.find((d) => d.name === name);
149
+ checkBinding(agentDir, name, bound.path, repository);
150
+ }
151
+ resolveContent(agentDir, declaration);
152
+ return { maps: next };
153
+ }
154
+ /** `maps` declared: what every reader of the files would read from them. */
155
+ function declarationOf(agentDir, maps) {
156
+ const declared = declareContent(maps.content);
157
+ return { declared, bound: declareBindings(maps.bindings, declared, agentDir) };
158
+ }
159
+ function mapsOf(shared, local) {
160
+ return { content: shared.content, bindings: local.content };
161
+ }
162
+ function without(map, name) {
163
+ return Object.fromEntries(Object.entries(map).filter(([key]) => key !== name));
164
+ }
165
+ /**
166
+ * Where the entry `name` matches ignoring case is written: its name, and which of the two files hold it. One the agent
167
+ * does not have is a {@link ContentNameError}.
168
+ */
169
+ function entryNamed(maps, name) {
170
+ const matches = (key) => key.toLowerCase() === name.toLowerCase();
171
+ const shared = Object.keys(maps.content).find(matches);
172
+ const local = Object.keys(maps.bindings).find(matches);
173
+ const found = shared ?? local;
174
+ if (found !== undefined)
175
+ return { name: found, shared: shared !== undefined, local: local !== undefined };
176
+ const names = [...new Set([...Object.keys(maps.content), ...Object.keys(maps.bindings)])];
177
+ throw new ContentNameError(`no content named "${name}" (this agent has: ${names.join(", ") || "none"})`);
178
+ }
179
+ /**
180
+ * Run `edit` over both context files under ONE lock, `context.json`'s, which env edits take too: whether a name is
181
+ * taken is asked of both files, so two edits that write different files must still queue behind each other. The lock
182
+ * creates neither file; what `edit` returns for a file is written under it, `context.local.json` first.
183
+ */
184
+ async function editContext(dir, edit) {
185
+ const sharedPath = join(dir, CONTEXT_FILE);
186
+ const localPath = join(dir, LOCAL_CONTEXT_FILE);
187
+ return withLockedFile(sharedPath, async (sharedText) => {
188
+ const shared = sharedText === undefined ? { content: {}, declared: [] } : parseContextFile(sharedText, sharedPath);
189
+ const localText = textIfExists(localPath);
190
+ const local = localText === undefined
191
+ ? { content: {}, bound: [] }
192
+ : parseLocalContextFile(localText, localPath, shared.declared, dir);
193
+ const out = edit(shared, local);
194
+ if (out.local !== undefined)
195
+ writeFileAtomic(localPath, out.local, fileMode(localPath));
196
+ return { result: out.result, next: out.shared };
197
+ }, { mode: fileMode(sharedPath), create: false });
198
+ }
199
+ function textIfExists(path) {
200
+ return existsSync(path) ? readFileSync(path, "utf8") : undefined;
201
+ }
202
+ /**
203
+ * What to say when git would commit `context.local.json`: it names directories of this machine, so committed it would
204
+ * point every other checkout of the agent at paths it does not have. `init` ignores it; an agent made before that may
205
+ * not. Asked only of an agent in a git repository, and never failing an edit that has already been made.
206
+ */
207
+ function unignoredLocalFile(dir) {
208
+ const git = gitFor("to check that context.local.json stays out of git");
209
+ try {
210
+ if (git.answer(["rev-parse", "--is-inside-work-tree"], dir) !== "true")
211
+ return [];
212
+ if (git.answer(["check-ignore", "-q", LOCAL_CONTEXT_FILE], dir) !== undefined)
213
+ return [];
214
+ }
215
+ catch (error) {
216
+ if (error instanceof GitNotInstalled)
217
+ return [];
218
+ throw error;
219
+ }
220
+ return [`${LOCAL_CONTEXT_FILE} holds directories of this machine and git does not ignore it: add it to .gitignore`];
221
+ }
222
+ /**
223
+ * Replace the environment `context.json` declares with what `change` makes of it as it is now, under the lock content
224
+ * edits take, keeping the rest of the file as it is; and return what was written.
225
+ */
226
+ export async function writeEnvironment(agentDir, change) {
227
+ const path = join(resolveAgentDir(agentDir), CONTEXT_FILE);
228
+ return withLockedFile(path, async (src) => {
229
+ const file = parseContextFile(src ?? "{}", path);
230
+ const environment = change(file.environment);
231
+ return { result: environment, next: contextFileText({ ...file, environment }) };
232
+ }, { mode: fileMode(path) });
233
+ }
234
+ /** The mode a rewrite of `path` keeps: its own, or the definition's default for a new one. */
235
+ function fileMode(path) {
236
+ const stat = statSync(path, { throwIfNoEntry: false });
237
+ return stat === undefined ? CONTEXT_FILE_MODE : stat.mode & 0o777;
238
+ }
package/dist/channel.d.ts CHANGED
@@ -1,27 +1,39 @@
1
1
  /**
2
- * The Channel contract — the trigger side of the product boundary (core.md §1), beside `agent.ts` (what an engine
3
- * implements) and `session.ts` (the serving control plane). Pure types: importing a host, a framework, or an engine
4
- * here is forbidden, as in those two.
2
+ * The Channel contract: how a channel is mounted beside the Agent it talks to (agent-api.ts, SPEC.md §8.1), and
3
+ * `defineChannel`, which types a channel file's export. Importing a host, a framework, or a harness here is forbidden.
5
4
  */
6
- import type { Agent } from "./agent.ts";
7
- import type { SessionControl } from "./session.ts";
5
+ import type { Agent, CreateSessionOptions } from "./agent-api.ts";
8
6
  /** A mounted request handler (a channel's fetch, or a plain route like health). */
9
7
  export type ChannelHandler = (req: Request) => Response | Promise<Response>;
10
8
  /** This deployment's HTTP surface: route key → handler. */
11
9
  export type Routes = Record<string, ChannelHandler>;
12
- /**
13
- * What the framework hands a channel at mount time: the assembled agent plus the resolved state ROOT (absolute;
14
- * `FASTAGENT_STATE_DIR` > `<root>/.state`).
15
- */
10
+ /** The session a new conversation forks from, as `sessions.create` takes it; `undefined` starts it empty. */
11
+ export type ForkSource = CreateSessionOptions["forkFrom"];
12
+ /** What a channel is handed when it is mounted, and all it is handed. */
16
13
  export interface ChannelContext {
14
+ /** The Agent, in process. */
17
15
  agent: Agent;
18
- stateRoot: string;
19
- /** The serving session-control hub: every serve has it, so a stop command reaches the live run through it.
20
- * `config.sessionControl` decides only whether the SAME hub is also published as `/control/*` (and wires its
21
- * write side). Absent only when an embedder mounts a service without one. */
22
- control?: SessionControl;
16
+ /**
17
+ * The session the conversation `key` talks in: the one this channel recorded for it, or a new one created and
18
+ * recorded before it is returned, so a message is sent only into a recorded session. With `forkFrom`, a new one is
19
+ * a fork of what it answers, asked only when `key` has no session yet. Calls for one key are taken one at a time,
20
+ * so two first messages of a new conversation get one session.
21
+ */
22
+ sessionFor(key: string, options?: {
23
+ forkFrom?: () => Promise<ForkSource>;
24
+ }): Promise<string>;
25
+ /** The session recorded for `key`, without creating one: what a stop command asks of a place nothing was said in. */
26
+ recordedSession(key: string): string | undefined;
27
+ /**
28
+ * Run `work` after the route has answered, one at a time per `place` (a chat, a thread) in the order they arrived,
29
+ * counted as work in flight, which `dev`'s restart and AgentCore's `/ping` wait for. It keeps no record: a turn the
30
+ * process stops before it runs is lost unless the platform delivers its event again. A failure goes to the log.
31
+ */
32
+ turn(place: string, work: () => Promise<void>): void;
33
+ /** The channel's own directory, `<state root>/channels/<the channel file's name>`, for the records it must keep. */
34
+ stateDir: string;
23
35
  }
24
- /** A `channels/<name>.ts` route channel: receives mount context and returns its HTTP routes. */
36
+ /** A `channels/<name>.ts` route channel: receives its context and returns its HTTP routes. */
25
37
  export type ChannelModule = (ctx: ChannelContext) => Routes;
26
38
  export interface LongConnection {
27
39
  ready: Promise<void>;
@@ -32,3 +44,5 @@ export interface LongConnectionChannelModule {
32
44
  name: string;
33
45
  connect(ctx: ChannelContext, signal: AbortSignal): LongConnection;
34
46
  }
47
+ /** What a channel file default-exports, typed: its routes for a context, or a long connection. */
48
+ export declare function defineChannel<T extends ChannelModule | LongConnectionChannelModule>(channel: T): T;
package/dist/channel.js CHANGED
@@ -1 +1,4 @@
1
- export {};
1
+ /** What a channel file default-exports, typed: its routes for a context, or a long connection. */
2
+ export function defineChannel(channel) {
3
+ return channel;
4
+ }
@@ -6,7 +6,7 @@ export declare const RESERVED_PATHS: {
6
6
  readonly wakeAlarm: "/__fastagent/wake-alarm";
7
7
  };
8
8
  /** Every kind the container's `POST /invocations` dispatches on. */
9
- export declare const ENVELOPE_KINDS: readonly ["webhook", "routine-fire", "routine-run", "invoke", "wake-poke", "probe"];
9
+ export declare const ENVELOPE_KINDS: readonly ["webhook", "schedule-fire", "wake-poke", "probe"];
10
10
  /**
11
11
  * Did this envelope come from the FORWARDER, rather than from some other principal holding
12
12
  * `bedrock-agentcore:InvokeAgentRuntime`?
@@ -15,8 +15,8 @@ export declare const ENVELOPE_KINDS: readonly ["webhook", "routine-fire", "routi
15
15
  * (`envelope.wake.url`) is where the container later POSTs its wake alarms, carrying `FASTAGENT_WAKE_SECRET` — so a
16
16
  * principal who could set it would redirect that callback and collect the secret along with every pending wake-up.
17
17
  *
18
- * The other thing it gates — the non-`invoke` kinds — is DEPTH, not a boundary. Every one of them is weaker than
19
- * the `invoke` the same caller may already send: `routine-fire` runs a prompt the definition wrote down,
18
+ * The other thing it gates — the kinds other than `api` — is DEPTH, not a boundary. Every one of them is weaker than
19
+ * the `api` the same caller may already send: `schedule-fire` runs a prompt the definition wrote down,
20
20
  * `webhook` reaches only channel routes that verify their own platform's signature, `wake-poke` wakes, `probe`
21
21
  * reports. IAM is what decides who gets to ask at all.
22
22
  *
@@ -26,6 +26,16 @@ export declare const ENVELOPE_KINDS: readonly ["webhook", "routine-fire", "routi
26
26
  export declare function fromForwarder(envelope: {
27
27
  auth?: unknown;
28
28
  } | undefined, expected: string | undefined): boolean;
29
+ /** An HTTP request carried inside an envelope, byte-exact. */
30
+ export interface CarriedRequest {
31
+ method: string;
32
+ path: string;
33
+ /** Raw query string, no leading `?`. */
34
+ query?: string;
35
+ headers?: Record<string, string>;
36
+ /** The body, base64 (byte-exact). */
37
+ bodyB64?: string;
38
+ }
29
39
  /** What the forwarder Lambda / EventBridge deliver in the `/invocations` payload. */
30
40
  export type AgentcoreEnvelope = {
31
41
  /** Shared secret proving this envelope came from the forwarder (FASTAGENT_INGRESS_SECRET). */
@@ -33,22 +43,10 @@ export type AgentcoreEnvelope = {
33
43
  wake?: {
34
44
  url: string;
35
45
  };
36
- } & ({
46
+ } /** A platform's webhook, verbatim: its headers carry the signature material its channel checks. */ & (({
37
47
  kind: "webhook";
38
- /** Original webhook request line, verbatim. */
39
- method: string;
40
- path: string;
41
- /**
42
- * Original raw query string (no leading `?`) — "verbatim" includes it; a channel reading
43
- * `request.url.searchParams` must see what the webhook sender sent.
44
- */
45
- query?: string;
46
- /** Original headers — signature material (secret tokens, Feishu signatures) rides here. */
47
- headers?: Record<string, string>;
48
- /** Original body, base64 (webhook bodies are JSON but the tunnel must be byte-exact). */
49
- bodyB64?: string;
50
- } | {
51
- kind: "routine-fire";
48
+ } & CarriedRequest) | {
49
+ kind: "schedule-fire";
52
50
  name: string;
53
51
  /**
54
52
  * The instant EventBridge scheduled this fire for — the clock's NAME for the occurrence, stable across its
@@ -56,24 +54,6 @@ export type AgentcoreEnvelope = {
56
54
  * never recomputes it.
57
55
  */
58
56
  occurrence: string;
59
- } | {
60
- /**
61
- * Run a declared routine BY NAME — the `POST /run` contract on the host that publishes no routes.
62
- *
63
- * On the IAM door, like `invoke`, and for the same reason: the forwarder never emits this, so it can only
64
- * come from a direct `InvokeAgentRuntime` call, where AWS has already said who the caller is. That makes
65
- * by-name running STRICTER here than on a host with a public URL, where the same route is anonymous.
66
- *
67
- * Separate from `routine-fire` because they are different contracts, not two spellings: a fire names an
68
- * OCCURRENCE our own clock produced and claims it (dedup across redeliveries, a fire history, the overlap
69
- * policy); this names only the work (schedule/run.ts).
70
- */
71
- kind: "routine-run";
72
- name: string;
73
- } | {
74
- kind: "invoke";
75
- session: string;
76
- text: string;
77
57
  }
78
58
  /**
79
59
  * An EventBridge wake-up poke: the invocation ITSELF is the payload — it wakes the container, whose boot drain / 30s
@@ -85,7 +65,7 @@ export type AgentcoreEnvelope = {
85
65
  /**
86
66
  * The deploy driver's post-deploy verification (relayed by the forwarder's reserved probe path, which answers on
87
67
  * EVERY forwarder topology — schedule-only URLs refuse ordinary public traffic). Also accepted from the IAM door,
88
- * where it only opens the workspace (`login --deployment` needs one) and does not construct the channels.
68
+ * where it only opens the deployed definition (`login --deployment` needs one) and does not construct the channels.
89
69
  */
90
70
  | {
91
71
  kind: "probe";
@@ -99,24 +79,30 @@ export interface WebhookReply {
99
79
  headers: Record<string, string>;
100
80
  bodyB64: string;
101
81
  }
102
- /** One desired alarm: mirror of a pending wake-up (id names the EventBridge schedule; at = fireAt). */
82
+ /** One desired one-shot alarm: a pending wake-up's next instant, which pokes the container. */
103
83
  export interface WakeAlarm {
84
+ /** One per INSTANT (`<wake id>@<instant>`), so mirroring again never rewrites a spent alarm. */
104
85
  id: string;
105
86
  at: string;
106
87
  }
107
- /** The wire shape the wake sink POSTs to {@link RESERVED_PATHS.wakeAlarm} (the forwarder validates `secret`). */
108
- export interface WakeAlarmRequest {
109
- secret: string;
110
- alarms: WakeAlarm[];
88
+ /**
89
+ * One desired RECURRING schedule: a `schedules/` file as an EventBridge cron schedule, which EventBridge fires on its
90
+ * own clock. Each fire delivers `{scheduleFire: {name, occurrence: <aws.scheduler.scheduled-time>}}`, the instant it
91
+ * was scheduled for, repeated byte-identical on every redelivery, which is what lets the container claim it once.
92
+ */
93
+ export interface RecurringSchedule {
94
+ name: string;
95
+ /** EventBridge's `cron(...)` (schedule/eventbridge-cron.ts). */
96
+ expression: string;
97
+ /** IANA zone the expression is evaluated in. */
98
+ tz: string;
111
99
  }
112
100
  /**
113
- * What EventBridge hands the forwarder when a cron rule fires: which schedule, and which occurrence of it.
114
- * `occurrence` is `<aws.scheduler.scheduled-time>` — the clock names its own fire, which is the only thing that
115
- * survives a retry (schedule/run.ts).
101
+ * The wire shape the wake sink POSTs to {@link RESERVED_PATHS.wakeAlarm} (the forwarder validates `secret`). The
102
+ * schedules are the WHOLE desired set: the forwarder deletes a recurring schedule it holds that is not in it.
116
103
  */
117
- export interface ScheduleFireEvent {
118
- scheduleFire: {
119
- name: string;
120
- occurrence: string;
121
- };
104
+ export interface WakeAlarmRequest {
105
+ secret: string;
106
+ alarms: WakeAlarm[];
107
+ schedules: RecurringSchedule[];
122
108
  }
@@ -8,7 +8,7 @@ export const RESERVED_PATHS = {
8
8
  wakeAlarm: "/__fastagent/wake-alarm",
9
9
  };
10
10
  /** Every kind the container's `POST /invocations` dispatches on. */
11
- export const ENVELOPE_KINDS = ["webhook", "routine-fire", "routine-run", "invoke", "wake-poke", "probe"];
11
+ export const ENVELOPE_KINDS = ["webhook", "schedule-fire", "wake-poke", "probe"];
12
12
  /**
13
13
  * Did this envelope come from the FORWARDER, rather than from some other principal holding
14
14
  * `bedrock-agentcore:InvokeAgentRuntime`?
@@ -17,8 +17,8 @@ export const ENVELOPE_KINDS = ["webhook", "routine-fire", "routine-run", "invoke
17
17
  * (`envelope.wake.url`) is where the container later POSTs its wake alarms, carrying `FASTAGENT_WAKE_SECRET` — so a
18
18
  * principal who could set it would redirect that callback and collect the secret along with every pending wake-up.
19
19
  *
20
- * The other thing it gates — the non-`invoke` kinds — is DEPTH, not a boundary. Every one of them is weaker than
21
- * the `invoke` the same caller may already send: `routine-fire` runs a prompt the definition wrote down,
20
+ * The other thing it gates — the kinds other than `api` — is DEPTH, not a boundary. Every one of them is weaker than
21
+ * the `api` the same caller may already send: `schedule-fire` runs a prompt the definition wrote down,
22
22
  * `webhook` reaches only channel routes that verify their own platform's signature, `wake-poke` wakes, `probe`
23
23
  * reports. IAM is what decides who gets to ask at all.
24
24
  *
@@ -1,28 +1,18 @@
1
- /** The AgentCore serving assembly — the same product as `mountAgentService`, built differently because the host is. */
2
- import type { Agent } from "../agent.ts";
1
+ /** The AgentCore serving assembly — the same product as `serveAgent`, built differently because the host is. */
2
+ import type { Agent } from "../agent-api.ts";
3
3
  import type { Routes } from "../channel.ts";
4
- import type { LoadedRoutine } from "../schedule/routine.ts";
5
- import { type AgentService, type MountableAgent } from "../service.ts";
4
+ import type { Schedule } from "../schedule/schedule.ts";
5
+ import { type ServableAgent, type ServedAgent, type Service } from "../service.ts";
6
6
  import { type AgentcoreAdapterOptions } from "./agentcore.ts";
7
- import type { ChannelHandler } from "../channel.ts";
8
7
  /**
9
8
  * Runtime filesystems appear on invocation, so even opening the definition must be deferred — in the TWO stages that
10
9
  * differ in what a retry would cost.
11
10
  */
12
11
  export declare function deferAgentcoreService<T>(stages: {
13
12
  prepare: () => Promise<T>;
14
- assemble: (prepared: T) => Promise<AgentService>;
15
- }): {
16
- handler: ChannelHandler;
17
- close: () => Promise<void>;
18
- };
19
- export interface MountAgentcoreServiceOptions {
20
- /** Wrap the opened agent before anything binds to it (the CLI's turn trace). */
21
- wrapAgent?: (agent: Agent) => Agent;
22
- /** The process entry owns the global wake-alarm sink; activation reconciles it once. */
23
- onStateReady?: () => void;
24
- }
25
- export declare function mountAgentcoreService(opened: MountableAgent, options?: MountAgentcoreServiceOptions): Promise<AgentService>;
13
+ assemble: (prepared: T) => Promise<ServedAgent>;
14
+ }): Service;
15
+ export declare function mountAgentcoreService(opened: ServableAgent): Promise<ServedAgent>;
26
16
  /**
27
17
  * Mount the AgentCore Runtime adapter (`POST /invocations` + `GET /ping`) — the deployed container's ONLY reachable
28
18
  * surface (channels/agentcore.ts).
@@ -30,7 +20,7 @@ export declare function mountAgentcoreService(opened: MountableAgent, options?:
30
20
  export declare function mountAgentcore(options: {
31
21
  agent: Agent;
32
22
  stateRoot: string;
33
- routines: readonly LoadedRoutine[];
23
+ schedules: () => readonly Schedule[];
34
24
  onStateReady?: () => void;
35
25
  /** The channel surface, initialized once by the adapter on trusted ingress. */
36
26
  channels: AgentcoreAdapterOptions["channels"];