rird 1.0.200

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 (350) hide show
  1. package/AGENTS.md +27 -0
  2. package/Dockerfile +18 -0
  3. package/README.md +15 -0
  4. package/bin/opencode +336 -0
  5. package/bin/pty-wrapper.js +285 -0
  6. package/bunfig.toml +4 -0
  7. package/facebook_ads_library.png +0 -0
  8. package/nul`nif +0 -0
  9. package/package.json +111 -0
  10. package/parsers-config.ts +239 -0
  11. package/rird-1.0.199.tgz +0 -0
  12. package/script/build-windows.ts +54 -0
  13. package/script/build.ts +167 -0
  14. package/script/postinstall.mjs +544 -0
  15. package/script/publish-registries.ts +187 -0
  16. package/script/publish.ts +72 -0
  17. package/script/schema.ts +47 -0
  18. package/src/acp/README.md +164 -0
  19. package/src/acp/agent.ts +1063 -0
  20. package/src/acp/session.ts +101 -0
  21. package/src/acp/types.ts +22 -0
  22. package/src/agent/agent.ts +367 -0
  23. package/src/agent/generate.txt +75 -0
  24. package/src/agent/prompt/compaction.txt +12 -0
  25. package/src/agent/prompt/explore.txt +18 -0
  26. package/src/agent/prompt/summary.txt +10 -0
  27. package/src/agent/prompt/title.txt +36 -0
  28. package/src/auth/index.ts +70 -0
  29. package/src/bun/index.ts +114 -0
  30. package/src/bus/bus-event.ts +43 -0
  31. package/src/bus/global.ts +10 -0
  32. package/src/bus/index.ts +105 -0
  33. package/src/cli/bootstrap.ts +17 -0
  34. package/src/cli/cmd/acp.ts +88 -0
  35. package/src/cli/cmd/agent.ts +256 -0
  36. package/src/cli/cmd/auth.ts +391 -0
  37. package/src/cli/cmd/cmd.ts +7 -0
  38. package/src/cli/cmd/debug/config.ts +15 -0
  39. package/src/cli/cmd/debug/file.ts +91 -0
  40. package/src/cli/cmd/debug/index.ts +43 -0
  41. package/src/cli/cmd/debug/lsp.ts +48 -0
  42. package/src/cli/cmd/debug/ripgrep.ts +83 -0
  43. package/src/cli/cmd/debug/scrap.ts +15 -0
  44. package/src/cli/cmd/debug/skill.ts +15 -0
  45. package/src/cli/cmd/debug/snapshot.ts +48 -0
  46. package/src/cli/cmd/export.ts +88 -0
  47. package/src/cli/cmd/generate.ts +38 -0
  48. package/src/cli/cmd/github.ts +1400 -0
  49. package/src/cli/cmd/import.ts +98 -0
  50. package/src/cli/cmd/mcp.ts +654 -0
  51. package/src/cli/cmd/models.ts +77 -0
  52. package/src/cli/cmd/pr.ts +112 -0
  53. package/src/cli/cmd/run.ts +368 -0
  54. package/src/cli/cmd/serve.ts +31 -0
  55. package/src/cli/cmd/session.ts +106 -0
  56. package/src/cli/cmd/stats.ts +298 -0
  57. package/src/cli/cmd/tui/app.tsx +696 -0
  58. package/src/cli/cmd/tui/attach.ts +30 -0
  59. package/src/cli/cmd/tui/component/border.tsx +21 -0
  60. package/src/cli/cmd/tui/component/dialog-agent.tsx +31 -0
  61. package/src/cli/cmd/tui/component/dialog-command.tsx +124 -0
  62. package/src/cli/cmd/tui/component/dialog-mcp.tsx +86 -0
  63. package/src/cli/cmd/tui/component/dialog-model.tsx +245 -0
  64. package/src/cli/cmd/tui/component/dialog-provider.tsx +224 -0
  65. package/src/cli/cmd/tui/component/dialog-session-list.tsx +102 -0
  66. package/src/cli/cmd/tui/component/dialog-session-rename.tsx +31 -0
  67. package/src/cli/cmd/tui/component/dialog-stash.tsx +86 -0
  68. package/src/cli/cmd/tui/component/dialog-status.tsx +162 -0
  69. package/src/cli/cmd/tui/component/dialog-tag.tsx +44 -0
  70. package/src/cli/cmd/tui/component/dialog-theme-list.tsx +50 -0
  71. package/src/cli/cmd/tui/component/did-you-know.tsx +85 -0
  72. package/src/cli/cmd/tui/component/logo.tsx +35 -0
  73. package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +574 -0
  74. package/src/cli/cmd/tui/component/prompt/history.tsx +108 -0
  75. package/src/cli/cmd/tui/component/prompt/index.tsx +1090 -0
  76. package/src/cli/cmd/tui/component/prompt/stash.tsx +101 -0
  77. package/src/cli/cmd/tui/component/tips.ts +27 -0
  78. package/src/cli/cmd/tui/component/todo-item.tsx +32 -0
  79. package/src/cli/cmd/tui/context/args.tsx +14 -0
  80. package/src/cli/cmd/tui/context/directory.ts +13 -0
  81. package/src/cli/cmd/tui/context/exit.tsx +23 -0
  82. package/src/cli/cmd/tui/context/helper.tsx +25 -0
  83. package/src/cli/cmd/tui/context/keybind.tsx +101 -0
  84. package/src/cli/cmd/tui/context/kv.tsx +49 -0
  85. package/src/cli/cmd/tui/context/local.tsx +354 -0
  86. package/src/cli/cmd/tui/context/prompt.tsx +18 -0
  87. package/src/cli/cmd/tui/context/route.tsx +46 -0
  88. package/src/cli/cmd/tui/context/sdk.tsx +74 -0
  89. package/src/cli/cmd/tui/context/sync.tsx +372 -0
  90. package/src/cli/cmd/tui/context/theme/aura.json +69 -0
  91. package/src/cli/cmd/tui/context/theme/ayu.json +80 -0
  92. package/src/cli/cmd/tui/context/theme/catppuccin-frappe.json +233 -0
  93. package/src/cli/cmd/tui/context/theme/catppuccin-macchiato.json +233 -0
  94. package/src/cli/cmd/tui/context/theme/catppuccin.json +112 -0
  95. package/src/cli/cmd/tui/context/theme/cobalt2.json +228 -0
  96. package/src/cli/cmd/tui/context/theme/cursor.json +249 -0
  97. package/src/cli/cmd/tui/context/theme/dracula.json +219 -0
  98. package/src/cli/cmd/tui/context/theme/everforest.json +241 -0
  99. package/src/cli/cmd/tui/context/theme/flexoki.json +237 -0
  100. package/src/cli/cmd/tui/context/theme/github.json +233 -0
  101. package/src/cli/cmd/tui/context/theme/gruvbox.json +95 -0
  102. package/src/cli/cmd/tui/context/theme/kanagawa.json +77 -0
  103. package/src/cli/cmd/tui/context/theme/lucent-orng.json +227 -0
  104. package/src/cli/cmd/tui/context/theme/material.json +235 -0
  105. package/src/cli/cmd/tui/context/theme/matrix.json +77 -0
  106. package/src/cli/cmd/tui/context/theme/mercury.json +252 -0
  107. package/src/cli/cmd/tui/context/theme/monokai.json +221 -0
  108. package/src/cli/cmd/tui/context/theme/nightowl.json +221 -0
  109. package/src/cli/cmd/tui/context/theme/nord.json +223 -0
  110. package/src/cli/cmd/tui/context/theme/one-dark.json +84 -0
  111. package/src/cli/cmd/tui/context/theme/orng.json +245 -0
  112. package/src/cli/cmd/tui/context/theme/palenight.json +222 -0
  113. package/src/cli/cmd/tui/context/theme/rird.json +245 -0
  114. package/src/cli/cmd/tui/context/theme/rosepine.json +234 -0
  115. package/src/cli/cmd/tui/context/theme/solarized.json +223 -0
  116. package/src/cli/cmd/tui/context/theme/synthwave84.json +226 -0
  117. package/src/cli/cmd/tui/context/theme/tokyonight.json +243 -0
  118. package/src/cli/cmd/tui/context/theme/vercel.json +245 -0
  119. package/src/cli/cmd/tui/context/theme/vesper.json +218 -0
  120. package/src/cli/cmd/tui/context/theme/zenburn.json +223 -0
  121. package/src/cli/cmd/tui/context/theme.tsx +1109 -0
  122. package/src/cli/cmd/tui/event.ts +40 -0
  123. package/src/cli/cmd/tui/routes/home.tsx +138 -0
  124. package/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx +64 -0
  125. package/src/cli/cmd/tui/routes/session/dialog-message.tsx +109 -0
  126. package/src/cli/cmd/tui/routes/session/dialog-subagent.tsx +26 -0
  127. package/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +47 -0
  128. package/src/cli/cmd/tui/routes/session/footer.tsx +88 -0
  129. package/src/cli/cmd/tui/routes/session/header.tsx +125 -0
  130. package/src/cli/cmd/tui/routes/session/index.tsx +1864 -0
  131. package/src/cli/cmd/tui/routes/session/sidebar.tsx +318 -0
  132. package/src/cli/cmd/tui/spawn.ts +60 -0
  133. package/src/cli/cmd/tui/thread.ts +142 -0
  134. package/src/cli/cmd/tui/ui/dialog-alert.tsx +57 -0
  135. package/src/cli/cmd/tui/ui/dialog-confirm.tsx +83 -0
  136. package/src/cli/cmd/tui/ui/dialog-help.tsx +38 -0
  137. package/src/cli/cmd/tui/ui/dialog-prompt.tsx +77 -0
  138. package/src/cli/cmd/tui/ui/dialog-select.tsx +332 -0
  139. package/src/cli/cmd/tui/ui/dialog.tsx +170 -0
  140. package/src/cli/cmd/tui/ui/spinner.ts +368 -0
  141. package/src/cli/cmd/tui/ui/toast.tsx +100 -0
  142. package/src/cli/cmd/tui/util/clipboard.ts +127 -0
  143. package/src/cli/cmd/tui/util/editor.ts +32 -0
  144. package/src/cli/cmd/tui/util/terminal.ts +114 -0
  145. package/src/cli/cmd/tui/worker.ts +63 -0
  146. package/src/cli/cmd/uninstall.ts +344 -0
  147. package/src/cli/cmd/upgrade.ts +100 -0
  148. package/src/cli/cmd/web.ts +84 -0
  149. package/src/cli/error.ts +56 -0
  150. package/src/cli/ui.ts +84 -0
  151. package/src/cli/upgrade.ts +25 -0
  152. package/src/command/index.ts +80 -0
  153. package/src/command/template/initialize.txt +10 -0
  154. package/src/command/template/review.txt +97 -0
  155. package/src/config/config.ts +995 -0
  156. package/src/config/markdown.ts +41 -0
  157. package/src/env/index.ts +26 -0
  158. package/src/file/ignore.ts +83 -0
  159. package/src/file/index.ts +328 -0
  160. package/src/file/ripgrep.ts +393 -0
  161. package/src/file/time.ts +64 -0
  162. package/src/file/watcher.ts +103 -0
  163. package/src/flag/flag.ts +46 -0
  164. package/src/format/formatter.ts +315 -0
  165. package/src/format/index.ts +137 -0
  166. package/src/global/index.ts +52 -0
  167. package/src/id/id.ts +73 -0
  168. package/src/ide/index.ts +76 -0
  169. package/src/index.ts +240 -0
  170. package/src/installation/index.ts +239 -0
  171. package/src/lsp/client.ts +229 -0
  172. package/src/lsp/index.ts +485 -0
  173. package/src/lsp/language.ts +116 -0
  174. package/src/lsp/server.ts +1895 -0
  175. package/src/mcp/auth.ts +135 -0
  176. package/src/mcp/index.ts +690 -0
  177. package/src/mcp/oauth-callback.ts +200 -0
  178. package/src/mcp/oauth-provider.ts +154 -0
  179. package/src/patch/index.ts +622 -0
  180. package/src/permission/index.ts +199 -0
  181. package/src/plugin/index.ts +91 -0
  182. package/src/project/bootstrap.ts +31 -0
  183. package/src/project/instance.ts +78 -0
  184. package/src/project/project.ts +221 -0
  185. package/src/project/state.ts +65 -0
  186. package/src/project/vcs.ts +76 -0
  187. package/src/provider/auth.ts +143 -0
  188. package/src/provider/models-macro.ts +11 -0
  189. package/src/provider/models.ts +106 -0
  190. package/src/provider/provider.ts +1071 -0
  191. package/src/provider/sdk/openai-compatible/src/README.md +5 -0
  192. package/src/provider/sdk/openai-compatible/src/index.ts +2 -0
  193. package/src/provider/sdk/openai-compatible/src/openai-compatible-provider.ts +100 -0
  194. package/src/provider/sdk/openai-compatible/src/responses/convert-to-openai-responses-input.ts +303 -0
  195. package/src/provider/sdk/openai-compatible/src/responses/map-openai-responses-finish-reason.ts +22 -0
  196. package/src/provider/sdk/openai-compatible/src/responses/openai-config.ts +18 -0
  197. package/src/provider/sdk/openai-compatible/src/responses/openai-error.ts +22 -0
  198. package/src/provider/sdk/openai-compatible/src/responses/openai-responses-api-types.ts +207 -0
  199. package/src/provider/sdk/openai-compatible/src/responses/openai-responses-language-model.ts +1713 -0
  200. package/src/provider/sdk/openai-compatible/src/responses/openai-responses-prepare-tools.ts +177 -0
  201. package/src/provider/sdk/openai-compatible/src/responses/openai-responses-settings.ts +1 -0
  202. package/src/provider/sdk/openai-compatible/src/responses/tool/code-interpreter.ts +88 -0
  203. package/src/provider/sdk/openai-compatible/src/responses/tool/file-search.ts +128 -0
  204. package/src/provider/sdk/openai-compatible/src/responses/tool/image-generation.ts +115 -0
  205. package/src/provider/sdk/openai-compatible/src/responses/tool/local-shell.ts +65 -0
  206. package/src/provider/sdk/openai-compatible/src/responses/tool/web-search-preview.ts +104 -0
  207. package/src/provider/sdk/openai-compatible/src/responses/tool/web-search.ts +103 -0
  208. package/src/provider/transform.ts +455 -0
  209. package/src/pty/index.ts +231 -0
  210. package/src/security/guardrails.test.ts +341 -0
  211. package/src/security/guardrails.ts +558 -0
  212. package/src/security/index.ts +19 -0
  213. package/src/server/error.ts +36 -0
  214. package/src/server/project.ts +79 -0
  215. package/src/server/server.ts +2642 -0
  216. package/src/server/tui.ts +71 -0
  217. package/src/session/compaction.ts +223 -0
  218. package/src/session/index.ts +461 -0
  219. package/src/session/llm.ts +201 -0
  220. package/src/session/message-v2.ts +690 -0
  221. package/src/session/message.ts +189 -0
  222. package/src/session/processor.ts +409 -0
  223. package/src/session/prompt/act-switch.txt +5 -0
  224. package/src/session/prompt/anthropic-20250930.txt +166 -0
  225. package/src/session/prompt/anthropic.txt +85 -0
  226. package/src/session/prompt/anthropic_spoof.txt +1 -0
  227. package/src/session/prompt/beast.txt +103 -0
  228. package/src/session/prompt/codex.txt +304 -0
  229. package/src/session/prompt/copilot-gpt-5.txt +138 -0
  230. package/src/session/prompt/gemini.txt +85 -0
  231. package/src/session/prompt/max-steps.txt +16 -0
  232. package/src/session/prompt/plan-reminder-anthropic.txt +35 -0
  233. package/src/session/prompt/plan.txt +24 -0
  234. package/src/session/prompt/polaris.txt +84 -0
  235. package/src/session/prompt/qwen.txt +106 -0
  236. package/src/session/prompt.ts +1509 -0
  237. package/src/session/retry.ts +86 -0
  238. package/src/session/revert.ts +108 -0
  239. package/src/session/sensitive-filter.test.ts +327 -0
  240. package/src/session/sensitive-filter.ts +466 -0
  241. package/src/session/status.ts +76 -0
  242. package/src/session/summary.ts +194 -0
  243. package/src/session/system.ts +120 -0
  244. package/src/session/todo.ts +37 -0
  245. package/src/share/share-next.ts +194 -0
  246. package/src/share/share.ts +87 -0
  247. package/src/shell/shell.ts +67 -0
  248. package/src/skill/index.ts +1 -0
  249. package/src/skill/skill.ts +83 -0
  250. package/src/snapshot/index.ts +197 -0
  251. package/src/storage/storage.ts +226 -0
  252. package/src/tests/agent.test.ts +308 -0
  253. package/src/tests/build-guards.test.ts +267 -0
  254. package/src/tests/config.test.ts +664 -0
  255. package/src/tests/tool-registry.test.ts +589 -0
  256. package/src/tool/bash.ts +317 -0
  257. package/src/tool/bash.txt +158 -0
  258. package/src/tool/batch.ts +175 -0
  259. package/src/tool/batch.txt +24 -0
  260. package/src/tool/codesearch.ts +168 -0
  261. package/src/tool/codesearch.txt +12 -0
  262. package/src/tool/edit.ts +675 -0
  263. package/src/tool/edit.txt +10 -0
  264. package/src/tool/glob.ts +65 -0
  265. package/src/tool/glob.txt +6 -0
  266. package/src/tool/grep.ts +121 -0
  267. package/src/tool/grep.txt +8 -0
  268. package/src/tool/invalid.ts +17 -0
  269. package/src/tool/ls.ts +110 -0
  270. package/src/tool/ls.txt +1 -0
  271. package/src/tool/lsp-diagnostics.ts +26 -0
  272. package/src/tool/lsp-diagnostics.txt +1 -0
  273. package/src/tool/lsp-hover.ts +31 -0
  274. package/src/tool/lsp-hover.txt +1 -0
  275. package/src/tool/lsp.ts +87 -0
  276. package/src/tool/lsp.txt +19 -0
  277. package/src/tool/multiedit.ts +46 -0
  278. package/src/tool/multiedit.txt +41 -0
  279. package/src/tool/patch.ts +233 -0
  280. package/src/tool/patch.txt +1 -0
  281. package/src/tool/read.ts +219 -0
  282. package/src/tool/read.txt +12 -0
  283. package/src/tool/registry.ts +162 -0
  284. package/src/tool/skill.ts +100 -0
  285. package/src/tool/task.ts +136 -0
  286. package/src/tool/task.txt +51 -0
  287. package/src/tool/todo.ts +39 -0
  288. package/src/tool/todoread.txt +14 -0
  289. package/src/tool/todowrite.txt +167 -0
  290. package/src/tool/tool.ts +71 -0
  291. package/src/tool/webfetch.ts +198 -0
  292. package/src/tool/webfetch.txt +13 -0
  293. package/src/tool/websearch.ts +180 -0
  294. package/src/tool/websearch.txt +11 -0
  295. package/src/tool/write.ts +110 -0
  296. package/src/tool/write.txt +8 -0
  297. package/src/util/archive.ts +16 -0
  298. package/src/util/color.ts +19 -0
  299. package/src/util/context.ts +25 -0
  300. package/src/util/defer.ts +12 -0
  301. package/src/util/eventloop.ts +20 -0
  302. package/src/util/filesystem.ts +83 -0
  303. package/src/util/fn.ts +11 -0
  304. package/src/util/iife.ts +3 -0
  305. package/src/util/keybind.ts +102 -0
  306. package/src/util/lazy.ts +11 -0
  307. package/src/util/license.ts +325 -0
  308. package/src/util/locale.ts +81 -0
  309. package/src/util/lock.ts +98 -0
  310. package/src/util/log.ts +180 -0
  311. package/src/util/queue.ts +32 -0
  312. package/src/util/rpc.ts +42 -0
  313. package/src/util/scrap.ts +10 -0
  314. package/src/util/signal.ts +12 -0
  315. package/src/util/timeout.ts +14 -0
  316. package/src/util/token.ts +7 -0
  317. package/src/util/wildcard.ts +54 -0
  318. package/sst-env.d.ts +9 -0
  319. package/test/agent/agent.test.ts +146 -0
  320. package/test/bun.test.ts +53 -0
  321. package/test/cli/github-remote.test.ts +80 -0
  322. package/test/config/agent-color.test.ts +66 -0
  323. package/test/config/config.test.ts +535 -0
  324. package/test/config/markdown.test.ts +89 -0
  325. package/test/file/ignore.test.ts +10 -0
  326. package/test/fixture/fixture.ts +36 -0
  327. package/test/fixture/lsp/fake-lsp-server.js +77 -0
  328. package/test/ide/ide.test.ts +82 -0
  329. package/test/keybind.test.ts +421 -0
  330. package/test/lsp/client.test.ts +95 -0
  331. package/test/mcp/headers.test.ts +153 -0
  332. package/test/patch/patch.test.ts +348 -0
  333. package/test/preload.ts +57 -0
  334. package/test/project/project.test.ts +72 -0
  335. package/test/provider/provider.test.ts +1809 -0
  336. package/test/provider/transform.test.ts +411 -0
  337. package/test/session/retry.test.ts +111 -0
  338. package/test/session/session.test.ts +71 -0
  339. package/test/skill/skill.test.ts +131 -0
  340. package/test/snapshot/snapshot.test.ts +939 -0
  341. package/test/tool/__snapshots__/tool.test.ts.snap +9 -0
  342. package/test/tool/bash.test.ts +434 -0
  343. package/test/tool/grep.test.ts +108 -0
  344. package/test/tool/patch.test.ts +259 -0
  345. package/test/tool/read.test.ts +42 -0
  346. package/test/util/iife.test.ts +36 -0
  347. package/test/util/lazy.test.ts +50 -0
  348. package/test/util/timeout.test.ts +21 -0
  349. package/test/util/wildcard.test.ts +55 -0
  350. package/tsconfig.json +16 -0
@@ -0,0 +1,308 @@
1
+ import { describe, test, expect } from "bun:test"
2
+ import z from "zod"
3
+ import { Agent } from "../agent/agent"
4
+
5
+ describe("Agent.Info schema", () => {
6
+ test("agent info schema has required fields", () => {
7
+ const shape = Agent.Info.shape
8
+
9
+ // Required fields
10
+ expect(shape.name).toBeDefined()
11
+ expect(shape.mode).toBeDefined()
12
+ expect(shape.permission).toBeDefined()
13
+ expect(shape.tools).toBeDefined()
14
+ expect(shape.options).toBeDefined()
15
+ })
16
+
17
+ test("agent mode enum has correct values", () => {
18
+ // Test that valid modes are accepted
19
+ const validModes = ["subagent", "primary", "all"]
20
+
21
+ for (const mode of validModes) {
22
+ const testAgent = {
23
+ name: "test",
24
+ mode,
25
+ permission: { edit: "allow", bash: { "*": "allow" }, skill: { "*": "allow" } },
26
+ tools: {},
27
+ options: {},
28
+ }
29
+ const result = Agent.Info.safeParse(testAgent)
30
+ expect(result.success).toBe(true)
31
+ }
32
+
33
+ // Test that invalid mode is rejected
34
+ const invalidAgent = {
35
+ name: "test",
36
+ mode: "invalid",
37
+ permission: { edit: "allow", bash: { "*": "allow" }, skill: { "*": "allow" } },
38
+ tools: {},
39
+ options: {},
40
+ }
41
+ const result = Agent.Info.safeParse(invalidAgent)
42
+ expect(result.success).toBe(false)
43
+ })
44
+
45
+ test("agent permission structure is valid", () => {
46
+ const permissionSchema = Agent.Info.shape.permission
47
+ const permissionShape = (permissionSchema as z.ZodObject<any>).shape
48
+
49
+ expect(permissionShape.edit).toBeDefined()
50
+ expect(permissionShape.bash).toBeDefined()
51
+ expect(permissionShape.skill).toBeDefined()
52
+ expect(permissionShape.webfetch).toBeDefined()
53
+ expect(permissionShape.doom_loop).toBeDefined()
54
+ expect(permissionShape.external_directory).toBeDefined()
55
+ })
56
+
57
+ test("agent info validates correctly for valid data", () => {
58
+ const validAgent: z.input<typeof Agent.Info> = {
59
+ name: "test-agent",
60
+ mode: "primary",
61
+ permission: {
62
+ edit: "allow",
63
+ bash: { "*": "allow" },
64
+ skill: { "*": "allow" },
65
+ },
66
+ tools: {},
67
+ options: {},
68
+ }
69
+
70
+ const result = Agent.Info.safeParse(validAgent)
71
+ expect(result.success).toBe(true)
72
+ if (result.success) {
73
+ expect(result.data.name).toBe("test-agent")
74
+ expect(result.data.mode).toBe("primary")
75
+ }
76
+ })
77
+
78
+ test("agent info rejects invalid mode", () => {
79
+ const invalidAgent = {
80
+ name: "test-agent",
81
+ mode: "invalid-mode",
82
+ permission: {
83
+ edit: "allow",
84
+ bash: { "*": "allow" },
85
+ skill: { "*": "allow" },
86
+ },
87
+ tools: {},
88
+ options: {},
89
+ }
90
+
91
+ const result = Agent.Info.safeParse(invalidAgent)
92
+ expect(result.success).toBe(false)
93
+ })
94
+
95
+ test("optional fields are optional", () => {
96
+ const minimalAgent: z.input<typeof Agent.Info> = {
97
+ name: "minimal",
98
+ mode: "subagent",
99
+ permission: {
100
+ edit: "deny",
101
+ bash: { "*": "deny" },
102
+ skill: { "*": "deny" },
103
+ },
104
+ tools: {},
105
+ options: {},
106
+ }
107
+
108
+ const result = Agent.Info.safeParse(minimalAgent)
109
+ expect(result.success).toBe(true)
110
+ if (result.success) {
111
+ expect(result.data.description).toBeUndefined()
112
+ expect(result.data.native).toBeUndefined()
113
+ expect(result.data.hidden).toBeUndefined()
114
+ expect(result.data.default).toBeUndefined()
115
+ expect(result.data.topP).toBeUndefined()
116
+ expect(result.data.temperature).toBeUndefined()
117
+ expect(result.data.color).toBeUndefined()
118
+ expect(result.data.model).toBeUndefined()
119
+ expect(result.data.prompt).toBeUndefined()
120
+ expect(result.data.maxSteps).toBeUndefined()
121
+ }
122
+ })
123
+
124
+ test("agent with all optional fields validates", () => {
125
+ const fullAgent: z.input<typeof Agent.Info> = {
126
+ name: "full-agent",
127
+ description: "A test agent",
128
+ mode: "all",
129
+ native: true,
130
+ hidden: false,
131
+ default: true,
132
+ topP: 0.9,
133
+ temperature: 0.7,
134
+ color: "#FF5733",
135
+ permission: {
136
+ edit: "ask",
137
+ bash: { "*": "ask", "echo *": "allow" },
138
+ skill: { "*": "allow" },
139
+ webfetch: "allow",
140
+ doom_loop: "ask",
141
+ external_directory: "deny",
142
+ },
143
+ model: {
144
+ modelID: "claude-3-opus",
145
+ providerID: "anthropic",
146
+ },
147
+ prompt: "You are a helpful assistant",
148
+ tools: { bash: true, read: true },
149
+ options: { customOption: "value" },
150
+ maxSteps: 100,
151
+ }
152
+
153
+ const result = Agent.Info.safeParse(fullAgent)
154
+ expect(result.success).toBe(true)
155
+ if (result.success) {
156
+ expect(result.data.description).toBe("A test agent")
157
+ expect(result.data.temperature).toBe(0.7)
158
+ expect(result.data.topP).toBe(0.9)
159
+ expect(result.data.maxSteps).toBe(100)
160
+ }
161
+ })
162
+
163
+ test("permission values are valid enum values", () => {
164
+ const validPermissions = ["ask", "allow", "deny"]
165
+
166
+ const testAgent: z.input<typeof Agent.Info> = {
167
+ name: "perm-test",
168
+ mode: "primary",
169
+ permission: {
170
+ edit: "ask",
171
+ bash: { "*": "allow" },
172
+ skill: { "*": "deny" },
173
+ webfetch: "allow",
174
+ doom_loop: "ask",
175
+ external_directory: "deny",
176
+ },
177
+ tools: {},
178
+ options: {},
179
+ }
180
+
181
+ const result = Agent.Info.safeParse(testAgent)
182
+ expect(result.success).toBe(true)
183
+ if (result.success) {
184
+ expect(validPermissions).toContain(result.data.permission.edit)
185
+ expect(validPermissions).toContain(result.data.permission.webfetch as string)
186
+ }
187
+ })
188
+
189
+ test("maxSteps must be positive integer", () => {
190
+ const negativeSteps = {
191
+ name: "test",
192
+ mode: "primary",
193
+ permission: { edit: "allow", bash: { "*": "allow" }, skill: { "*": "allow" } },
194
+ tools: {},
195
+ options: {},
196
+ maxSteps: -1,
197
+ }
198
+
199
+ const result = Agent.Info.safeParse(negativeSteps)
200
+ expect(result.success).toBe(false)
201
+ })
202
+
203
+ test("temperature can be decimal number", () => {
204
+ const agent: z.input<typeof Agent.Info> = {
205
+ name: "temp-test",
206
+ mode: "primary",
207
+ permission: { edit: "allow", bash: { "*": "allow" }, skill: { "*": "allow" } },
208
+ tools: {},
209
+ options: {},
210
+ temperature: 0.5,
211
+ }
212
+
213
+ const result = Agent.Info.safeParse(agent)
214
+ expect(result.success).toBe(true)
215
+ if (result.success) {
216
+ expect(result.data.temperature).toBe(0.5)
217
+ }
218
+ })
219
+ })
220
+
221
+ describe("Agent mode definitions", () => {
222
+ test("subagent mode is valid", () => {
223
+ const agent: z.input<typeof Agent.Info> = {
224
+ name: "subagent-test",
225
+ mode: "subagent",
226
+ permission: { edit: "deny", bash: { "*": "deny" }, skill: { "*": "deny" } },
227
+ tools: {},
228
+ options: {},
229
+ }
230
+
231
+ const result = Agent.Info.safeParse(agent)
232
+ expect(result.success).toBe(true)
233
+ if (result.success) {
234
+ expect(result.data.mode).toBe("subagent")
235
+ }
236
+ })
237
+
238
+ test("primary mode is valid", () => {
239
+ const agent: z.input<typeof Agent.Info> = {
240
+ name: "primary-test",
241
+ mode: "primary",
242
+ permission: { edit: "allow", bash: { "*": "allow" }, skill: { "*": "allow" } },
243
+ tools: {},
244
+ options: {},
245
+ }
246
+
247
+ const result = Agent.Info.safeParse(agent)
248
+ expect(result.success).toBe(true)
249
+ if (result.success) {
250
+ expect(result.data.mode).toBe("primary")
251
+ }
252
+ })
253
+
254
+ test("all mode is valid", () => {
255
+ const agent: z.input<typeof Agent.Info> = {
256
+ name: "all-test",
257
+ mode: "all",
258
+ permission: { edit: "ask", bash: { "*": "ask" }, skill: { "*": "ask" } },
259
+ tools: {},
260
+ options: {},
261
+ }
262
+
263
+ const result = Agent.Info.safeParse(agent)
264
+ expect(result.success).toBe(true)
265
+ if (result.success) {
266
+ expect(result.data.mode).toBe("all")
267
+ }
268
+ })
269
+ })
270
+
271
+ describe("Agent model configuration", () => {
272
+ test("model requires both modelID and providerID", () => {
273
+ const agentWithModel: z.input<typeof Agent.Info> = {
274
+ name: "model-test",
275
+ mode: "primary",
276
+ permission: { edit: "allow", bash: { "*": "allow" }, skill: { "*": "allow" } },
277
+ tools: {},
278
+ options: {},
279
+ model: {
280
+ modelID: "gpt-4",
281
+ providerID: "openai",
282
+ },
283
+ }
284
+
285
+ const result = Agent.Info.safeParse(agentWithModel)
286
+ expect(result.success).toBe(true)
287
+ if (result.success) {
288
+ expect(result.data.model?.modelID).toBe("gpt-4")
289
+ expect(result.data.model?.providerID).toBe("openai")
290
+ }
291
+ })
292
+
293
+ test("model with missing providerID fails", () => {
294
+ const agentInvalidModel = {
295
+ name: "model-test",
296
+ mode: "primary",
297
+ permission: { edit: "allow", bash: { "*": "allow" }, skill: { "*": "allow" } },
298
+ tools: {},
299
+ options: {},
300
+ model: {
301
+ modelID: "gpt-4",
302
+ },
303
+ }
304
+
305
+ const result = Agent.Info.safeParse(agentInvalidModel)
306
+ expect(result.success).toBe(false)
307
+ })
308
+ })
@@ -0,0 +1,267 @@
1
+ /**
2
+ * Tier 1 Build & Syntax Guards
3
+ *
4
+ * These tests run on every PR to catch build/syntax issues early.
5
+ * They verify:
6
+ * 1. TypeScript compiles without errors (imports resolve)
7
+ * 2. No circular import issues in key modules
8
+ * 3. Agent modes are properly defined
9
+ * 4. Tool definitions have required fields
10
+ * 5. Prompt template files exist and are non-empty
11
+ *
12
+ * Run with: bun test build-guards.test.ts
13
+ */
14
+
15
+ import { describe, it, expect, test } from "bun:test"
16
+ import * as fs from "fs"
17
+ import * as path from "path"
18
+
19
+ // ------------------------------------------------------------------
20
+ // 1. TypeScript Compilation - Verify key imports resolve
21
+ // ------------------------------------------------------------------
22
+ describe("TypeScript Compilation", () => {
23
+ it("should import Tool namespace without errors", async () => {
24
+ const { Tool } = await import("../tool/tool")
25
+ expect(Tool).toBeDefined()
26
+ expect(Tool.define).toBeInstanceOf(Function)
27
+ })
28
+
29
+ it("should import Agent namespace without errors", async () => {
30
+ const { Agent } = await import("../agent/agent")
31
+ expect(Agent).toBeDefined()
32
+ expect(Agent.Info).toBeDefined()
33
+ })
34
+
35
+ it("should import ToolRegistry without errors", async () => {
36
+ const { ToolRegistry } = await import("../tool/registry")
37
+ expect(ToolRegistry).toBeDefined()
38
+ expect(ToolRegistry.register).toBeInstanceOf(Function)
39
+ })
40
+
41
+ it("should import Config namespace without errors", async () => {
42
+ const { Config } = await import("../config/config")
43
+ expect(Config).toBeDefined()
44
+ })
45
+
46
+ it("should import Provider namespace without errors", async () => {
47
+ const { Provider } = await import("../provider/provider")
48
+ expect(Provider).toBeDefined()
49
+ })
50
+ })
51
+
52
+ // ------------------------------------------------------------------
53
+ // 2. Circular Import Detection - Import key modules together
54
+ // ------------------------------------------------------------------
55
+ describe("Circular Import Detection", () => {
56
+ it("should import tool and agent modules without circular dependency errors", async () => {
57
+ // Import order matters for circular deps - test common patterns
58
+ const [toolModule, agentModule] = await Promise.all([
59
+ import("../tool/tool"),
60
+ import("../agent/agent"),
61
+ ])
62
+ expect(toolModule.Tool).toBeDefined()
63
+ expect(agentModule.Agent).toBeDefined()
64
+ })
65
+
66
+ it("should import registry with all tools without circular dependency errors", async () => {
67
+ const { ToolRegistry } = await import("../tool/registry")
68
+ const { BashTool } = await import("../tool/bash")
69
+ const { ReadTool } = await import("../tool/read")
70
+ const { EditTool } = await import("../tool/edit")
71
+ const { WriteTool } = await import("../tool/write")
72
+ const { GlobTool } = await import("../tool/glob")
73
+ const { GrepTool } = await import("../tool/grep")
74
+
75
+ expect(ToolRegistry).toBeDefined()
76
+ expect(BashTool).toBeDefined()
77
+ expect(ReadTool).toBeDefined()
78
+ expect(EditTool).toBeDefined()
79
+ expect(WriteTool).toBeDefined()
80
+ expect(GlobTool).toBeDefined()
81
+ expect(GrepTool).toBeDefined()
82
+ })
83
+
84
+ it("should import session and provider modules together", async () => {
85
+ const [sessionModule, providerModule] = await Promise.all([
86
+ import("../session"),
87
+ import("../provider/provider"),
88
+ ])
89
+ expect(sessionModule.Session).toBeDefined()
90
+ expect(providerModule.Provider).toBeDefined()
91
+ })
92
+ })
93
+
94
+ // ------------------------------------------------------------------
95
+ // 3. Agent Mode Validation
96
+ // ------------------------------------------------------------------
97
+ describe("Agent Mode Validation", () => {
98
+ it("should have valid mode enum values in Agent.Info schema", async () => {
99
+ const { Agent } = await import("../agent/agent")
100
+ const validModes = ["subagent", "primary", "all"] as const
101
+
102
+ // The Info schema should have mode as an enum
103
+ const modeField = Agent.Info.shape.mode
104
+ expect(modeField).toBeDefined()
105
+
106
+ // Get the enum values from the zod schema
107
+ const enumValues = modeField.options
108
+ expect(enumValues).toBeDefined()
109
+ expect(Array.from(enumValues).sort()).toEqual([...validModes].sort())
110
+ })
111
+
112
+ it("should have required permission fields in Agent.Info schema", async () => {
113
+ const { Agent } = await import("../agent/agent")
114
+
115
+ const permissionShape = Agent.Info.shape.permission.shape
116
+ expect(permissionShape).toBeDefined()
117
+ expect(permissionShape.edit).toBeDefined()
118
+ expect(permissionShape.bash).toBeDefined()
119
+ expect(permissionShape.skill).toBeDefined()
120
+ })
121
+ })
122
+
123
+ // ------------------------------------------------------------------
124
+ // 4. Tool Definition Validation
125
+ // ------------------------------------------------------------------
126
+ describe("Tool Definition Validation", () => {
127
+ const toolFiles = [
128
+ "bash",
129
+ "read",
130
+ "edit",
131
+ "write",
132
+ "glob",
133
+ "grep",
134
+ "task",
135
+ "webfetch",
136
+ "websearch",
137
+ "skill",
138
+ "todo",
139
+ "ls",
140
+ "lsp",
141
+ ]
142
+
143
+ for (const toolName of toolFiles) {
144
+ it(`should have valid Tool.define structure for ${toolName}`, async () => {
145
+ try {
146
+ const toolModule = await import(`../tool/${toolName}`)
147
+
148
+ // Find the exported tool (naming convention: XxxTool)
149
+ const toolExport = Object.values(toolModule).find(
150
+ (exp: any) => exp && typeof exp === "object" && "id" in exp && "init" in exp
151
+ ) as any
152
+
153
+ if (toolExport) {
154
+ expect(toolExport.id).toBeDefined()
155
+ expect(typeof toolExport.id).toBe("string")
156
+ expect(toolExport.init).toBeInstanceOf(Function)
157
+ }
158
+ } catch (err: any) {
159
+ // Some tools may have optional dependencies - that's ok for build check
160
+ if (!err.message.includes("Cannot find module")) {
161
+ throw err
162
+ }
163
+ }
164
+ })
165
+ }
166
+
167
+ it("should have id and init for all core tools", async () => {
168
+ const { BashTool } = await import("../tool/bash")
169
+ const { ReadTool } = await import("../tool/read")
170
+ const { EditTool } = await import("../tool/edit")
171
+ const { WriteTool } = await import("../tool/write")
172
+
173
+ const tools = [BashTool, ReadTool, EditTool, WriteTool]
174
+
175
+ for (const tool of tools) {
176
+ expect(tool.id).toBeDefined()
177
+ expect(typeof tool.id).toBe("string")
178
+ expect(tool.id.length).toBeGreaterThan(0)
179
+ expect(tool.init).toBeInstanceOf(Function)
180
+ }
181
+ })
182
+ })
183
+
184
+ // ------------------------------------------------------------------
185
+ // 5. Prompt Template File Validation
186
+ // ------------------------------------------------------------------
187
+ describe("Prompt Template File Validation", () => {
188
+ const srcDir = path.join(__dirname, "..")
189
+
190
+ const requiredPromptFiles = [
191
+ // Agent prompts
192
+ "agent/generate.txt",
193
+ "agent/prompt/compaction.txt",
194
+ "agent/prompt/summary.txt",
195
+ "agent/prompt/title.txt",
196
+ // Tool prompts (description files)
197
+ "tool/bash.txt",
198
+ "tool/read.txt",
199
+ "tool/edit.txt",
200
+ "tool/write.txt",
201
+ "tool/glob.txt",
202
+ "tool/grep.txt",
203
+ "tool/task.txt",
204
+ ]
205
+
206
+ for (const file of requiredPromptFiles) {
207
+ it(`should have non-empty prompt file: ${file}`, () => {
208
+ const filePath = path.join(srcDir, file)
209
+ expect(fs.existsSync(filePath)).toBe(true)
210
+
211
+ const content = fs.readFileSync(filePath, "utf-8")
212
+ expect(content.length).toBeGreaterThan(0)
213
+ expect(content.trim().length).toBeGreaterThan(0)
214
+ })
215
+ }
216
+ })
217
+
218
+ // ------------------------------------------------------------------
219
+ // 6. Config Schema Validation
220
+ // ------------------------------------------------------------------
221
+ describe("Config Schema Validation", () => {
222
+ it("should have valid Permission enum values", async () => {
223
+ const { Config } = await import("../config/config")
224
+
225
+ // Permission should be a zod enum
226
+ expect(Config.Permission).toBeDefined()
227
+ const permissionValues = Config.Permission.options
228
+ expect(permissionValues).toContain("allow")
229
+ expect(permissionValues).toContain("deny")
230
+ expect(permissionValues).toContain("ask")
231
+ })
232
+
233
+ it("should export core config functions", async () => {
234
+ const { Config } = await import("../config/config")
235
+
236
+ expect(Config.get).toBeInstanceOf(Function)
237
+ expect(Config.directories).toBeInstanceOf(Function)
238
+ })
239
+ })
240
+
241
+ // ------------------------------------------------------------------
242
+ // 7. Export Structure Validation
243
+ // ------------------------------------------------------------------
244
+ describe("Export Structure Validation", () => {
245
+ it("should have Log utility with required methods", async () => {
246
+ const { Log } = await import("../util/log")
247
+
248
+ expect(Log).toBeDefined()
249
+ expect(Log.create).toBeInstanceOf(Function)
250
+ })
251
+
252
+ it("should have Instance with required properties", async () => {
253
+ const { Instance } = await import("../project/instance")
254
+
255
+ expect(Instance).toBeDefined()
256
+ expect(Instance.state).toBeInstanceOf(Function)
257
+ expect(Instance.provide).toBeInstanceOf(Function)
258
+ })
259
+
260
+ it("should have Permission namespace with required exports", async () => {
261
+ const { Permission } = await import("../permission")
262
+
263
+ expect(Permission).toBeDefined()
264
+ expect(Permission.ask).toBeInstanceOf(Function)
265
+ expect(Permission.RejectedError).toBeDefined()
266
+ })
267
+ })