@pythonluvr/openwar 0.4.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 (298) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +297 -0
  3. package/bin/openwar +45 -0
  4. package/dist/adapters/anthropic.d.ts +15 -0
  5. package/dist/adapters/anthropic.d.ts.map +1 -0
  6. package/dist/adapters/anthropic.js +179 -0
  7. package/dist/adapters/anthropic.js.map +1 -0
  8. package/dist/adapters/gemini.d.ts +15 -0
  9. package/dist/adapters/gemini.d.ts.map +1 -0
  10. package/dist/adapters/gemini.js +141 -0
  11. package/dist/adapters/gemini.js.map +1 -0
  12. package/dist/adapters/grok.d.ts +6 -0
  13. package/dist/adapters/grok.d.ts.map +1 -0
  14. package/dist/adapters/grok.js +15 -0
  15. package/dist/adapters/grok.js.map +1 -0
  16. package/dist/adapters/index.d.ts +16 -0
  17. package/dist/adapters/index.d.ts.map +1 -0
  18. package/dist/adapters/index.js +35 -0
  19. package/dist/adapters/index.js.map +1 -0
  20. package/dist/adapters/mock.d.ts +17 -0
  21. package/dist/adapters/mock.d.ts.map +1 -0
  22. package/dist/adapters/mock.js +33 -0
  23. package/dist/adapters/mock.js.map +1 -0
  24. package/dist/adapters/openai-compat.d.ts +6 -0
  25. package/dist/adapters/openai-compat.d.ts.map +1 -0
  26. package/dist/adapters/openai-compat.js +19 -0
  27. package/dist/adapters/openai-compat.js.map +1 -0
  28. package/dist/adapters/openai.d.ts +23 -0
  29. package/dist/adapters/openai.d.ts.map +1 -0
  30. package/dist/adapters/openai.js +176 -0
  31. package/dist/adapters/openai.js.map +1 -0
  32. package/dist/adapters/sse.d.ts +6 -0
  33. package/dist/adapters/sse.d.ts.map +1 -0
  34. package/dist/adapters/sse.js +45 -0
  35. package/dist/adapters/sse.js.map +1 -0
  36. package/dist/adapters/types.d.ts +7 -0
  37. package/dist/adapters/types.d.ts.map +1 -0
  38. package/dist/adapters/types.js +2 -0
  39. package/dist/adapters/types.js.map +1 -0
  40. package/dist/auth/categories.d.ts +13 -0
  41. package/dist/auth/categories.d.ts.map +1 -0
  42. package/dist/auth/categories.js +47 -0
  43. package/dist/auth/categories.js.map +1 -0
  44. package/dist/auth/check.d.ts +31 -0
  45. package/dist/auth/check.d.ts.map +1 -0
  46. package/dist/auth/check.js +59 -0
  47. package/dist/auth/check.js.map +1 -0
  48. package/dist/auth/role-scope.d.ts +18 -0
  49. package/dist/auth/role-scope.d.ts.map +1 -0
  50. package/dist/auth/role-scope.js +62 -0
  51. package/dist/auth/role-scope.js.map +1 -0
  52. package/dist/auth/wildcards.d.ts +5 -0
  53. package/dist/auth/wildcards.d.ts.map +1 -0
  54. package/dist/auth/wildcards.js +36 -0
  55. package/dist/auth/wildcards.js.map +1 -0
  56. package/dist/brief.d.ts +9 -0
  57. package/dist/brief.d.ts.map +1 -0
  58. package/dist/brief.js +514 -0
  59. package/dist/brief.js.map +1 -0
  60. package/dist/cli.d.ts +2 -0
  61. package/dist/cli.d.ts.map +1 -0
  62. package/dist/cli.js +585 -0
  63. package/dist/cli.js.map +1 -0
  64. package/dist/coordinator/cost-tracker.d.ts +14 -0
  65. package/dist/coordinator/cost-tracker.d.ts.map +1 -0
  66. package/dist/coordinator/cost-tracker.js +63 -0
  67. package/dist/coordinator/cost-tracker.js.map +1 -0
  68. package/dist/coordinator/driver.d.ts +37 -0
  69. package/dist/coordinator/driver.d.ts.map +1 -0
  70. package/dist/coordinator/driver.js +644 -0
  71. package/dist/coordinator/driver.js.map +1 -0
  72. package/dist/coordinator/index.d.ts +14 -0
  73. package/dist/coordinator/index.d.ts.map +1 -0
  74. package/dist/coordinator/index.js +8 -0
  75. package/dist/coordinator/index.js.map +1 -0
  76. package/dist/coordinator/plan-parser.d.ts +17 -0
  77. package/dist/coordinator/plan-parser.d.ts.map +1 -0
  78. package/dist/coordinator/plan-parser.js +44 -0
  79. package/dist/coordinator/plan-parser.js.map +1 -0
  80. package/dist/coordinator/result-aggregator.d.ts +21 -0
  81. package/dist/coordinator/result-aggregator.d.ts.map +1 -0
  82. package/dist/coordinator/result-aggregator.js +58 -0
  83. package/dist/coordinator/result-aggregator.js.map +1 -0
  84. package/dist/coordinator/retry-policy.d.ts +7 -0
  85. package/dist/coordinator/retry-policy.d.ts.map +1 -0
  86. package/dist/coordinator/retry-policy.js +17 -0
  87. package/dist/coordinator/retry-policy.js.map +1 -0
  88. package/dist/coordinator/state-machine.d.ts +63 -0
  89. package/dist/coordinator/state-machine.d.ts.map +1 -0
  90. package/dist/coordinator/state-machine.js +242 -0
  91. package/dist/coordinator/state-machine.js.map +1 -0
  92. package/dist/coordinator/types.d.ts +3 -0
  93. package/dist/coordinator/types.d.ts.map +1 -0
  94. package/dist/coordinator/types.js +5 -0
  95. package/dist/coordinator/types.js.map +1 -0
  96. package/dist/detectors/banned-phrases.d.ts +3 -0
  97. package/dist/detectors/banned-phrases.d.ts.map +1 -0
  98. package/dist/detectors/banned-phrases.js +33 -0
  99. package/dist/detectors/banned-phrases.js.map +1 -0
  100. package/dist/detectors/blocker.d.ts +3 -0
  101. package/dist/detectors/blocker.d.ts.map +1 -0
  102. package/dist/detectors/blocker.js +62 -0
  103. package/dist/detectors/blocker.js.map +1 -0
  104. package/dist/detectors/completion.d.ts +3 -0
  105. package/dist/detectors/completion.d.ts.map +1 -0
  106. package/dist/detectors/completion.js +17 -0
  107. package/dist/detectors/completion.js.map +1 -0
  108. package/dist/detectors/confirmation-summary.d.ts +3 -0
  109. package/dist/detectors/confirmation-summary.d.ts.map +1 -0
  110. package/dist/detectors/confirmation-summary.js +76 -0
  111. package/dist/detectors/confirmation-summary.js.map +1 -0
  112. package/dist/detectors/destructive.d.ts +3 -0
  113. package/dist/detectors/destructive.d.ts.map +1 -0
  114. package/dist/detectors/destructive.js +96 -0
  115. package/dist/detectors/destructive.js.map +1 -0
  116. package/dist/detectors/index.d.ts +12 -0
  117. package/dist/detectors/index.d.ts.map +1 -0
  118. package/dist/detectors/index.js +19 -0
  119. package/dist/detectors/index.js.map +1 -0
  120. package/dist/detectors/phase-marker.d.ts +3 -0
  121. package/dist/detectors/phase-marker.d.ts.map +1 -0
  122. package/dist/detectors/phase-marker.js +25 -0
  123. package/dist/detectors/phase-marker.js.map +1 -0
  124. package/dist/framework.d.ts +2 -0
  125. package/dist/framework.d.ts.map +1 -0
  126. package/dist/framework.js +34 -0
  127. package/dist/framework.js.map +1 -0
  128. package/dist/index.d.ts +10 -0
  129. package/dist/index.d.ts.map +1 -0
  130. package/dist/index.js +10 -0
  131. package/dist/index.js.map +1 -0
  132. package/dist/io.d.ts +25 -0
  133. package/dist/io.d.ts.map +1 -0
  134. package/dist/io.js +83 -0
  135. package/dist/io.js.map +1 -0
  136. package/dist/mcp/client.d.ts +22 -0
  137. package/dist/mcp/client.d.ts.map +1 -0
  138. package/dist/mcp/client.js +44 -0
  139. package/dist/mcp/client.js.map +1 -0
  140. package/dist/mcp/index.d.ts +5 -0
  141. package/dist/mcp/index.d.ts.map +1 -0
  142. package/dist/mcp/index.js +6 -0
  143. package/dist/mcp/index.js.map +1 -0
  144. package/dist/mcp/registry.d.ts +16 -0
  145. package/dist/mcp/registry.d.ts.map +1 -0
  146. package/dist/mcp/registry.js +53 -0
  147. package/dist/mcp/registry.js.map +1 -0
  148. package/dist/mcp/transport-stdio.d.ts +26 -0
  149. package/dist/mcp/transport-stdio.d.ts.map +1 -0
  150. package/dist/mcp/transport-stdio.js +138 -0
  151. package/dist/mcp/transport-stdio.js.map +1 -0
  152. package/dist/mcp/types.d.ts +90 -0
  153. package/dist/mcp/types.d.ts.map +1 -0
  154. package/dist/mcp/types.js +23 -0
  155. package/dist/mcp/types.js.map +1 -0
  156. package/dist/orchestration/handoff.d.ts +27 -0
  157. package/dist/orchestration/handoff.d.ts.map +1 -0
  158. package/dist/orchestration/handoff.js +322 -0
  159. package/dist/orchestration/handoff.js.map +1 -0
  160. package/dist/phases/blocker.d.ts +8 -0
  161. package/dist/phases/blocker.d.ts.map +1 -0
  162. package/dist/phases/blocker.js +11 -0
  163. package/dist/phases/blocker.js.map +1 -0
  164. package/dist/phases/completion.d.ts +10 -0
  165. package/dist/phases/completion.d.ts.map +1 -0
  166. package/dist/phases/completion.js +47 -0
  167. package/dist/phases/completion.js.map +1 -0
  168. package/dist/phases/destructive.d.ts +10 -0
  169. package/dist/phases/destructive.d.ts.map +1 -0
  170. package/dist/phases/destructive.js +31 -0
  171. package/dist/phases/destructive.js.map +1 -0
  172. package/dist/phases/execute.d.ts +30 -0
  173. package/dist/phases/execute.d.ts.map +1 -0
  174. package/dist/phases/execute.js +222 -0
  175. package/dist/phases/execute.js.map +1 -0
  176. package/dist/phases/intake.d.ts +16 -0
  177. package/dist/phases/intake.d.ts.map +1 -0
  178. package/dist/phases/intake.js +105 -0
  179. package/dist/phases/intake.js.map +1 -0
  180. package/dist/roles/critic.d.ts +3 -0
  181. package/dist/roles/critic.d.ts.map +1 -0
  182. package/dist/roles/critic.js +35 -0
  183. package/dist/roles/critic.js.map +1 -0
  184. package/dist/roles/executor.d.ts +3 -0
  185. package/dist/roles/executor.d.ts.map +1 -0
  186. package/dist/roles/executor.js +46 -0
  187. package/dist/roles/executor.js.map +1 -0
  188. package/dist/roles/index.d.ts +8 -0
  189. package/dist/roles/index.d.ts.map +1 -0
  190. package/dist/roles/index.js +8 -0
  191. package/dist/roles/index.js.map +1 -0
  192. package/dist/roles/planner.d.ts +3 -0
  193. package/dist/roles/planner.d.ts.map +1 -0
  194. package/dist/roles/planner.js +50 -0
  195. package/dist/roles/planner.js.map +1 -0
  196. package/dist/roles/prompt-overlay.d.ts +9 -0
  197. package/dist/roles/prompt-overlay.d.ts.map +1 -0
  198. package/dist/roles/prompt-overlay.js +25 -0
  199. package/dist/roles/prompt-overlay.js.map +1 -0
  200. package/dist/roles/registry.d.ts +8 -0
  201. package/dist/roles/registry.d.ts.map +1 -0
  202. package/dist/roles/registry.js +45 -0
  203. package/dist/roles/registry.js.map +1 -0
  204. package/dist/roles/reviewer.d.ts +3 -0
  205. package/dist/roles/reviewer.d.ts.map +1 -0
  206. package/dist/roles/reviewer.js +46 -0
  207. package/dist/roles/reviewer.js.map +1 -0
  208. package/dist/roles/types.d.ts +2 -0
  209. package/dist/roles/types.d.ts.map +1 -0
  210. package/dist/roles/types.js +4 -0
  211. package/dist/roles/types.js.map +1 -0
  212. package/dist/runner.d.ts +3 -0
  213. package/dist/runner.d.ts.map +1 -0
  214. package/dist/runner.js +473 -0
  215. package/dist/runner.js.map +1 -0
  216. package/dist/sandbox/host-allowlist.d.ts +13 -0
  217. package/dist/sandbox/host-allowlist.d.ts.map +1 -0
  218. package/dist/sandbox/host-allowlist.js +85 -0
  219. package/dist/sandbox/host-allowlist.js.map +1 -0
  220. package/dist/sandbox/output-cap.d.ts +9 -0
  221. package/dist/sandbox/output-cap.d.ts.map +1 -0
  222. package/dist/sandbox/output-cap.js +66 -0
  223. package/dist/sandbox/output-cap.js.map +1 -0
  224. package/dist/sandbox/timeout.d.ts +7 -0
  225. package/dist/sandbox/timeout.d.ts.map +1 -0
  226. package/dist/sandbox/timeout.js +52 -0
  227. package/dist/sandbox/timeout.js.map +1 -0
  228. package/dist/sandbox/types.d.ts +18 -0
  229. package/dist/sandbox/types.d.ts.map +1 -0
  230. package/dist/sandbox/types.js +27 -0
  231. package/dist/sandbox/types.js.map +1 -0
  232. package/dist/sandbox/workdir.d.ts +9 -0
  233. package/dist/sandbox/workdir.d.ts.map +1 -0
  234. package/dist/sandbox/workdir.js +83 -0
  235. package/dist/sandbox/workdir.js.map +1 -0
  236. package/dist/state/index.d.ts +4 -0
  237. package/dist/state/index.d.ts.map +1 -0
  238. package/dist/state/index.js +4 -0
  239. package/dist/state/index.js.map +1 -0
  240. package/dist/state/paths.d.ts +5 -0
  241. package/dist/state/paths.d.ts.map +1 -0
  242. package/dist/state/paths.js +18 -0
  243. package/dist/state/paths.js.map +1 -0
  244. package/dist/state/persist.d.ts +14 -0
  245. package/dist/state/persist.d.ts.map +1 -0
  246. package/dist/state/persist.js +146 -0
  247. package/dist/state/persist.js.map +1 -0
  248. package/dist/state/transcript.d.ts +9 -0
  249. package/dist/state/transcript.d.ts.map +1 -0
  250. package/dist/state/transcript.js +34 -0
  251. package/dist/state/transcript.js.map +1 -0
  252. package/dist/tools/native/apply_patch.d.ts +18 -0
  253. package/dist/tools/native/apply_patch.d.ts.map +1 -0
  254. package/dist/tools/native/apply_patch.js +245 -0
  255. package/dist/tools/native/apply_patch.js.map +1 -0
  256. package/dist/tools/native/http_fetch.d.ts +6 -0
  257. package/dist/tools/native/http_fetch.d.ts.map +1 -0
  258. package/dist/tools/native/http_fetch.js +168 -0
  259. package/dist/tools/native/http_fetch.js.map +1 -0
  260. package/dist/tools/native/index.d.ts +9 -0
  261. package/dist/tools/native/index.d.ts.map +1 -0
  262. package/dist/tools/native/index.js +22 -0
  263. package/dist/tools/native/index.js.map +1 -0
  264. package/dist/tools/native/list_dir.d.ts +4 -0
  265. package/dist/tools/native/list_dir.d.ts.map +1 -0
  266. package/dist/tools/native/list_dir.js +175 -0
  267. package/dist/tools/native/list_dir.js.map +1 -0
  268. package/dist/tools/native/read_file.d.ts +4 -0
  269. package/dist/tools/native/read_file.d.ts.map +1 -0
  270. package/dist/tools/native/read_file.js +91 -0
  271. package/dist/tools/native/read_file.js.map +1 -0
  272. package/dist/tools/native/shell_exec.d.ts +4 -0
  273. package/dist/tools/native/shell_exec.d.ts.map +1 -0
  274. package/dist/tools/native/shell_exec.js +180 -0
  275. package/dist/tools/native/shell_exec.js.map +1 -0
  276. package/dist/tools/native/write_file.d.ts +4 -0
  277. package/dist/tools/native/write_file.d.ts.map +1 -0
  278. package/dist/tools/native/write_file.js +101 -0
  279. package/dist/tools/native/write_file.js.map +1 -0
  280. package/dist/tools/types.d.ts +48 -0
  281. package/dist/tools/types.d.ts.map +1 -0
  282. package/dist/tools/types.js +10 -0
  283. package/dist/tools/types.js.map +1 -0
  284. package/dist/types.d.ts +385 -0
  285. package/dist/types.d.ts.map +1 -0
  286. package/dist/types.js +9 -0
  287. package/dist/types.js.map +1 -0
  288. package/examples/README.md +73 -0
  289. package/examples/creative-brief.md +34 -0
  290. package/examples/critic-disagreement-brief.md +42 -0
  291. package/examples/engineering-brief.md +35 -0
  292. package/examples/file-editing-brief.md +33 -0
  293. package/examples/mcp-brief.md +34 -0
  294. package/examples/multi-agent-brief.md +43 -0
  295. package/examples/research-brief.md +35 -0
  296. package/openwar.md +248 -0
  297. package/package.json +76 -0
  298. package/templates/brief.md +62 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 OpenWar contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,297 @@
1
+ <p align="center">
2
+ <img src="openwar-logo.png" alt="OpenWar" width="160" height="160" />
3
+ </p>
4
+
5
+ <h1 align="center">OpenWar</h1>
6
+
7
+ <p align="center"><strong>A framework and a runtime for agent behavior that doesn't go off the rails.</strong></p>
8
+
9
+ <p align="center">
10
+ <a href="https://github.com/pythonluvr/openwar/releases"><img src="https://img.shields.io/github/v/release/pythonluvr/openwar?display_name=tag&sort=semver" alt="Latest release"></a>
11
+ <a href="https://github.com/pythonluvr/openwar/actions"><img src="https://img.shields.io/github/actions/workflow/status/pythonluvr/openwar/test.yml?branch=main" alt="Tests"></a>
12
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT"></a>
13
+ </p>
14
+
15
+ OpenWar replaces eager-customer-service-rep defaults with the behavior of a senior peer. It confirms briefs before acting, breaks work into phases, asks before doing anything destructive, and writes like an adult who's busy.
16
+
17
+ This is WarBit. He runs OpenWar. He does not "happily help you with that."
18
+
19
+ <p align="center">
20
+ <img src="branding/warbit-story/warbit-04-chaos.png" alt="WarBit buried in TODOs and merge conflicts" width="280" />
21
+ <br />
22
+ <em>Default agent behavior. Sycophantic, eager, drowning in half-finished context.</em>
23
+ </p>
24
+
25
+ You can use OpenWar two ways:
26
+
27
+ 1. **As a runtime** (new in v0.2, expanded in v0.3 with tool calling). Install the package, point it at a brief, watch the phase machine enforce the framework against any BYOK LLM. The runtime is opinionated: no flag to disable Phase 3, no way to skip the Confirmation Summary.
28
+ 2. **As a system prompt** (v0.1, still supported). Paste [`openwar.md`](./openwar.md) into Claude Code's CLAUDE.md, Cursor's rules, Hermes, OpenClaw, or anywhere else. The agent's behavior changes; nothing else does.
29
+
30
+ The framework doc and the runtime are the same source of truth. The doc tells the model what to do. The runtime makes sure it actually does it.
31
+
32
+ <p align="center">
33
+ <img src="branding/warbit-story/warbit-02-daily-intel.png" alt="WarBit at a 'Daily Intel' bulletin board" width="280" />
34
+ <br />
35
+ <em>Phase 0 in one image. What are you shipping today, ops?</em>
36
+ </p>
37
+
38
+ ## Quick start (runtime)
39
+
40
+ ```bash
41
+ npx @pythonluvr/openwar run examples/creative-brief.md --adapter anthropic
42
+ ```
43
+
44
+ Or install:
45
+
46
+ ```bash
47
+ npm install -g @pythonluvr/openwar
48
+ export ANTHROPIC_API_KEY=...
49
+ openwar run examples/engineering-brief.md
50
+ ```
51
+
52
+ Provide an API key for whichever adapter you pick:
53
+
54
+ | Adapter | Env var | Default model |
55
+ |-----------------|--------------------------|-----------------------|
56
+ | `anthropic` | `ANTHROPIC_API_KEY` | `claude-sonnet-4-6` |
57
+ | `openai` | `OPENAI_API_KEY` | `gpt-4o` |
58
+ | `gemini` | `GEMINI_API_KEY` | `gemini-2.0-flash` |
59
+ | `grok` | `XAI_API_KEY` | `grok-2-latest` |
60
+ | `openai-compat` | `OPENAI_COMPAT_API_KEY` | (specify with `--base-url`) |
61
+
62
+ `openai-compat` covers OpenRouter, Groq, Together, Ollama, vLLM, llama.cpp, and anything else speaking OpenAI's chat-completions protocol.
63
+
64
+ ## What the runtime enforces
65
+
66
+ <p align="center">
67
+ <img src="branding/warbit-story/warbit-05-cockpit.png" alt="WarBit watching a wall of monitors" width="280" />
68
+ <br />
69
+ <em>Every turn passes through deterministic detectors. No second LLM, no judging.</em>
70
+ </p>
71
+
72
+ | Phase | What happens | What blocks |
73
+ |---------|--------------------------------------------------------------------------------------------------|-------------|
74
+ | Phase 0 | Agent must produce a Confirmation Summary with Objective / Deliverables / Constraints / Tools / Unknowns. | No execution until the operator accepts. |
75
+ | Phase 1 | Agent executes step by step. Gated mode pauses between steps; auto-pilot runs through clean ones. | Banned phrases warn. |
76
+ | Phase 2 | If the agent declares it's blocked, the runtime halts the session and persists state. | Resume with `openwar resume <brief_id>`. |
77
+ | Phase 3 | If the agent announces intent to do something destructive or out-of-directive, the runtime stops and asks for explicit yes. | Authorization can be pre-approved per category in the brief's `authorized_costs`. |
78
+ | Phase 4 | Agent produces a concise completion report. | None. |
79
+
80
+ If the agent skips the Confirmation Summary, the runtime asks it to restate before letting execution start.
81
+
82
+ ## Tools (new in v0.3)
83
+
84
+ <p align="center">
85
+ <img src="branding/warbit-story/warbit-06-new-tools.png" alt="WarBit opening a glowing 'New Tools' chest" width="280" />
86
+ <br />
87
+ <em>v0.3 turned OpenWar from "constrained chat wrapper" into "real agent." The runtime now calls tools.</em>
88
+ </p>
89
+
90
+ The runtime ships six native tools plus a hand-rolled MCP client. Every tool call goes through:
91
+
92
+ 1. Schema translation in the adapter to the provider's native function-calling format.
93
+ 2. Authorization check against the brief's `authorized_costs` and any session-approved categories.
94
+ 3. Sandbox execution: workdir-bounded paths, timeout enforcement, output caps, HTTP host allowlist.
95
+ 4. Result fed back to the LLM for the next round.
96
+
97
+ If a tool requires an unauthorized category, the runtime halts into Phase 3 and prompts for `y` / `Y` / `n` (one-shot, session-wide, deny).
98
+
99
+ ### Native tools
100
+
101
+ | Name | Categories required | Notes |
102
+ |---------------|---------------------|-------|
103
+ | `read_file` | `filesystem_read` | Default-allowed. Caps at `max_bytes` (1 MB default). |
104
+ | `write_file` | `filesystem_write` | Atomic via tmp+rename. Creates parent dirs. |
105
+ | `list_dir` | `filesystem_read` | Skips `.git`, `node_modules`, etc. Honors `.openwarignore`. |
106
+ | `shell_exec` | `shell_exec` | SIGTERM then SIGKILL on timeout. `--no-shell` disables entirely. |
107
+ | `http_fetch` | `http_fetch` | HTTPS only by default. Optional `~/.openwar/http-allow.json` host allowlist. |
108
+ | `apply_patch` | `filesystem_write` | Unified-diff applier. Rolls back on hunk failure. |
109
+
110
+ List them with `openwar tools`.
111
+
112
+ ### MCP servers
113
+
114
+ Configure once with `openwar mcp add <name> <command...>` (writes to `~/.openwar/mcp.json`) or per-brief:
115
+
116
+ ```yaml
117
+ mcp_servers:
118
+ - filesystem=npx -y @modelcontextprotocol/server-filesystem /allowed/dir
119
+ ```
120
+
121
+ Each MCP server's tools auto-register under `<name>:<tool>` and require `mcp_tool:<name>:<tool>` to call. Use `mcp_tool:<name>:*` in `authorized_costs` to pre-approve everything a server exposes.
122
+
123
+ Test a server before relying on it:
124
+
125
+ ```bash
126
+ openwar mcp test filesystem
127
+ ```
128
+
129
+ ## Multi-agent orchestration (new in v0.4)
130
+
131
+ When a brief opts into multi-agent by setting `roles:` in its frontmatter, the runtime stops running one agent against the whole brief and instead drives a small team:
132
+
133
+ - **planner** decomposes the brief into linear sub-tasks with acceptance criteria.
134
+ - **executor** runs each sub-task with the full v0.3 tool layer, gated by the brief's `authorized_costs`.
135
+ - **reviewer** evaluates the executor's output against the sub-task's acceptance criteria. Read-only file access for verification.
136
+ - **critic** (optional fourth role) gives an independent second-opinion review. Disagreement with the reviewer halts the run for an operator decision.
137
+
138
+ The framework applies recursively. Every role's output passes through the same detectors as a single-agent run. Every sub-task gets its own Phase 0. Phase 2 / Phase 3 fire inside the role that triggered them.
139
+
140
+ Try it without spending execution tokens first:
141
+
142
+ ```bash
143
+ openwar plan examples/multi-agent-brief.md --adapter anthropic
144
+ ```
145
+
146
+ Full run:
147
+
148
+ ```bash
149
+ openwar run examples/multi-agent-brief.md --adapter anthropic
150
+ ```
151
+
152
+ Single-agent mode (omitting `roles:` or passing `--single`) keeps the v0.3 behavior. Sessions from v0.3 resume cleanly under v0.4; the schema migration is automatic.
153
+
154
+ ### Budgets
155
+
156
+ Briefs may declare cost ceilings in `budgets:`. Hitting any ceiling halts the coordinator cleanly with state persisted; the operator can extend and resume.
157
+
158
+ ```yaml
159
+ budgets:
160
+ max_tokens: 80000
161
+ max_wall_clock_minutes: 25
162
+ max_tool_calls_per_subtask: 12
163
+ max_retries_per_subtask: 3
164
+ ```
165
+
166
+ Defaults if omitted: 50k tokens, 20 minutes, 15 tool calls per sub-task, 3 retries per sub-task.
167
+
168
+ ## CLI
169
+
170
+ ```text
171
+ openwar run <brief.md> [--adapter <id>] [--model <name>] [--mode gated|auto]
172
+ [--workdir <path>] [--no-shell]
173
+ [--mcp-server name=command] [--resume] [--ephemeral]
174
+ [--roles planner,executor,reviewer[,critic]]
175
+ [--max-tokens N] [--max-minutes N] [--single]
176
+ openwar plan <brief.md> # planner dry-run; no execution
177
+ openwar resume <brief_id> # auto-detects single-agent vs multi-agent
178
+ openwar list
179
+ openwar inspect <brief_id> [--transcript]
180
+ openwar validate <brief.md>
181
+ openwar roles # list registered roles
182
+ openwar adapters
183
+ openwar tools
184
+ openwar mcp list | add <name> <cmd...> | remove <name> | test <name>
185
+ openwar version
186
+ ```
187
+
188
+ Sessions persist to `~/.openwar/sessions/` as JSON + JSONL transcript. Resume with `openwar resume <brief_id>`. `--ephemeral` skips persistence (used by tests and integrators).
189
+
190
+ ## Use as a library
191
+
192
+ ```ts
193
+ import { run, MockAdapter, AnthropicAdapter } from "openwar";
194
+
195
+ const adapter = new AnthropicAdapter({ id: "anthropic", model: "claude-sonnet-4-6" });
196
+ const result = await run({ briefPath: "./brief.md", adapter });
197
+
198
+ if (!result.completed) {
199
+ console.error(`Halted at ${result.final_phase}: ${result.halt_reason}`);
200
+ }
201
+ ```
202
+
203
+ War Room and other integrators consume OpenWar this way; the runtime is the framework's enforcement surface.
204
+
205
+ ## Brief format
206
+
207
+ Briefs are markdown with required frontmatter. A reference template ships at [`templates/brief.md`](./templates/brief.md).
208
+
209
+ ```yaml
210
+ ---
211
+ project: <slug> # required, kebab-case
212
+ brief_id: YYYY-MM-DD-NNN # optional; auto-generated if absent
213
+ deadline: YYYY-MM-DD # optional
214
+ scope_locked: true|false # if true, refuse out-of-scope additions
215
+ mode: gated|auto # optional override of per-step-vs-auto
216
+ workdir: ./relative-or-absolute # optional. All filesystem tools sandboxed here.
217
+ authorized_costs: # pre-approves these destructive categories
218
+ - filesystem_write
219
+ - shell_exec
220
+ - http_fetch
221
+ - mcp_tool:filesystem
222
+ mcp_servers: # optional. name=command, one per entry.
223
+ - filesystem=npx -y @modelcontextprotocol/server-filesystem /allowed/dir
224
+ ---
225
+ ```
226
+
227
+ Recognized `authorized_costs` categories: `filesystem_read` (default-allowed), `filesystem_write`, `filesystem_delete`, `shell_exec`, `http_fetch`, `paid_api_call`, `git_write`, `git_push`, `deploy`, `external_message`, plus `mcp_tool:<server>` and `mcp_tool:<server>:<tool>`. Wildcards: `*` matches every category, `mcp_tool:*` matches any MCP tool, `mcp_tool:server:*` matches any tool from a server. `*` triggers a brief-lint warning; almost always you want specific entries.
228
+
229
+ Body sections: **Objective**, **Deliverables**, **Constraints**, **Tools required**, **Notes / unknowns**.
230
+
231
+ Validate a brief without running it:
232
+
233
+ ```bash
234
+ openwar validate brief.md
235
+ ```
236
+
237
+ ## Still want just the system prompt?
238
+
239
+ Paste [`openwar.md`](./openwar.md) into your agent's system prompt. The framework remains a single markdown file. You lose enforcement (the model is on the honor system), but you keep the behavior overlay.
240
+
241
+ ### Claude Code
242
+
243
+ ```bash
244
+ mkdir -p ~/.claude
245
+ curl -fsSL https://raw.githubusercontent.com/pythonluvr/openwar/main/openwar.md >> ~/.claude/CLAUDE.md
246
+ ```
247
+
248
+ ### Cursor
249
+
250
+ Settings → Rules for AI → paste the contents of `openwar.md`.
251
+
252
+ ### War Room
253
+
254
+ War Room ships OpenWar as its default framework. v0.7+ adopts the runtime; earlier versions used the system prompt only.
255
+
256
+ ## Why both
257
+
258
+ Behavioral overlays are easy to ignore. A model that's been told "always produce a Confirmation Summary" will sometimes skip it under context pressure or specific phrasing. The runtime catches the skip and asks the model to restate.
259
+
260
+ System prompts cost nothing to install and work with any runtime. The runtime is heavier, but it actually enforces the rules.
261
+
262
+ <p align="center">
263
+ <img src="branding/warbit-story/warbit-03-success.png" alt="WarBit celebrating in front of a 'SUCCESS' screen" width="280" />
264
+ <br />
265
+ <em>Phase 4 completion. WarBit ships.</em>
266
+ </p>
267
+
268
+ ## Versioning
269
+
270
+ Current: **v0.4.0**.
271
+
272
+ - v0.1: framework doc only (single markdown file).
273
+ - v0.2: runtime, CLI, BYOK adapters for Anthropic, OpenAI, Gemini, Grok, OpenAI-compat.
274
+ - v0.3: six native tools (read_file, write_file, list_dir, shell_exec, http_fetch, apply_patch), hand-rolled MCP client, per-adapter tool-call translation, Phase 3 destructive flag for unauthorized tool calls.
275
+ - v0.4: multi-agent orchestration. Coordinator FSM, planner / executor / reviewer / critic roles, typed handoffs, per-role tool scoping, budgets, schema v3 with v2 migration, `openwar plan` and `openwar roles` subcommands.
276
+ - v0.5: persistent project memory across briefs.
277
+ - v0.6: observability dashboards / tracing UI.
278
+
279
+ Framework doc is versioned with the package. Drop-in upgrades preserve compatibility within a major version; major bumps may rename phases or change the brief format.
280
+
281
+ ## Community
282
+
283
+ Questions, bug reports, framework discussion: [Discord](https://discord.gg/ku6GJS92V2). Issues and PRs welcome on this repo too.
284
+
285
+ ## License
286
+
287
+ [MIT](./LICENSE). Use it, modify it, fork it, ship your own variants, paste it into commercial products. No obligations beyond keeping the copyright notice.
288
+
289
+ ## Authorship
290
+
291
+ OpenWar is the framework that ships inside [War Room](https://github.com/pythonluvr/war-room), authored across many iterations of running real agent work. This standalone repo exists so people who don't use War Room can still adopt the framework.
292
+
293
+ <p align="center">
294
+ <img src="branding/warbit-story/warbit-01-sunset.png" alt="WarBit sitting in front of a sunset over the city" width="280" />
295
+ <br />
296
+ <em>Issues and PRs welcome. WarBit will read them in the morning.</em>
297
+ </p>
package/bin/openwar ADDED
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+ // Resolves whether to run compiled dist (preferred) or tsx-compile src on the
3
+ // fly (for development inside the repo before `npm run build` has run).
4
+
5
+ import { existsSync } from "node:fs";
6
+ import { fileURLToPath, pathToFileURL } from "node:url";
7
+ import { dirname, join, resolve } from "node:path";
8
+
9
+ const here = dirname(fileURLToPath(import.meta.url));
10
+ const repoRoot = resolve(here, "..");
11
+ const dist = join(repoRoot, "dist", "cli.js");
12
+ const srcCli = join(repoRoot, "src", "cli.ts");
13
+
14
+ async function loadCli() {
15
+ if (existsSync(dist)) {
16
+ return await import(pathToFileURL(dist).href);
17
+ }
18
+ if (existsSync(srcCli)) {
19
+ try {
20
+ const tsx = await import("tsx/esm/api");
21
+ tsx.register();
22
+ return await import(pathToFileURL(srcCli).href);
23
+ } catch {
24
+ process.stderr.write(
25
+ "openwar: dist/cli.js not found and tsx is not installed. Run `npm install` and `npm run build`.\n",
26
+ );
27
+ process.exit(1);
28
+ }
29
+ }
30
+ process.stderr.write("openwar: cannot locate cli (no dist/cli.js or src/cli.ts).\n");
31
+ process.exit(1);
32
+ }
33
+
34
+ const mod = await loadCli();
35
+ if (typeof mod.main !== "function") {
36
+ process.stderr.write("openwar: cli module did not export main().\n");
37
+ process.exit(1);
38
+ }
39
+ try {
40
+ const code = await mod.main(process.argv.slice(2));
41
+ process.exit(code ?? 0);
42
+ } catch (err) {
43
+ process.stderr.write(`openwar: ${(err && err.message) || err}\n`);
44
+ process.exit(1);
45
+ }
@@ -0,0 +1,15 @@
1
+ import type { AgentAdapter, SendMessageOptions, StreamEvent, AdapterConfig, ToolDefinition, ToolResultForRound } from "../types.js";
2
+ export declare function formatToolsForAnthropic(tools: ToolDefinition[]): unknown[];
3
+ export declare function formatMessagesForAnthropic(opts: SendMessageOptions): unknown[];
4
+ export declare function formatToolResultForAnthropicMessage(r: ToolResultForRound): unknown;
5
+ export declare class AnthropicAdapter implements AgentAdapter {
6
+ readonly id = "anthropic";
7
+ readonly name = "Anthropic (Claude)";
8
+ readonly model: string;
9
+ private readonly apiKey;
10
+ private readonly baseUrl;
11
+ constructor(config?: AdapterConfig);
12
+ isConfigured(): boolean;
13
+ sendMessage(opts: SendMessageOptions): AsyncIterable<StreamEvent>;
14
+ }
15
+ //# sourceMappingURL=anthropic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/adapters/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,cAAc,EAEd,kBAAkB,EACnB,MAAM,aAAa,CAAC;AASrB,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,OAAO,EAAE,CAM1E;AAGD,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,EAAE,CAyB9E;AAED,wBAAgB,mCAAmC,CAAC,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAOlF;AASD,qBAAa,gBAAiB,YAAW,YAAY;IACnD,QAAQ,CAAC,EAAE,eAAe;IAC1B,QAAQ,CAAC,IAAI,wBAAwB;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,MAAM,GAAE,aAAmC;IAMvD,YAAY,IAAI,OAAO;IAIhB,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,aAAa,CAAC,WAAW,CAAC;CAqHzE"}
@@ -0,0 +1,179 @@
1
+ import { parseSseStream } from "./sse.js";
2
+ const DEFAULT_MODEL = "claude-sonnet-4-6";
3
+ const DEFAULT_BASE_URL = "https://api.anthropic.com";
4
+ const ANTHROPIC_VERSION = "2023-06-01";
5
+ // Translate OpenWar ToolDefinition[] into Anthropic's "tools" request shape.
6
+ // https://docs.anthropic.com/claude/docs/tool-use
7
+ export function formatToolsForAnthropic(tools) {
8
+ return tools.map(t => ({
9
+ name: t.name,
10
+ description: t.description,
11
+ input_schema: t.input_schema,
12
+ }));
13
+ }
14
+ // Build the messages array including prior tool_use / tool_result blocks.
15
+ export function formatMessagesForAnthropic(opts) {
16
+ const out = [];
17
+ for (const m of opts.messages) {
18
+ if (m.role === "system")
19
+ continue;
20
+ out.push({ role: m.role, content: m.content });
21
+ }
22
+ if (opts.prior_tool_calls && opts.prior_tool_calls.length > 0) {
23
+ const blocks = opts.prior_tool_calls.map(c => ({
24
+ type: "tool_use",
25
+ id: c.id,
26
+ name: c.name,
27
+ input: c.arguments ?? {},
28
+ }));
29
+ out.push({ role: "assistant", content: blocks });
30
+ }
31
+ if (opts.prior_tool_results && opts.prior_tool_results.length > 0) {
32
+ const blocks = opts.prior_tool_results.map(r => ({
33
+ type: "tool_result",
34
+ tool_use_id: r.call_id,
35
+ content: r.content,
36
+ ...(r.is_error && { is_error: true }),
37
+ }));
38
+ out.push({ role: "user", content: blocks });
39
+ }
40
+ return out;
41
+ }
42
+ export function formatToolResultForAnthropicMessage(r) {
43
+ return {
44
+ type: "tool_result",
45
+ tool_use_id: r.call_id,
46
+ content: r.content,
47
+ ...(r.is_error && { is_error: true }),
48
+ };
49
+ }
50
+ export class AnthropicAdapter {
51
+ id = "anthropic";
52
+ name = "Anthropic (Claude)";
53
+ model;
54
+ apiKey;
55
+ baseUrl;
56
+ constructor(config = { id: "anthropic" }) {
57
+ this.model = config.model ?? DEFAULT_MODEL;
58
+ this.apiKey = config.apiKey ?? process.env.ANTHROPIC_API_KEY;
59
+ this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
60
+ }
61
+ isConfigured() {
62
+ return Boolean(this.apiKey);
63
+ }
64
+ async *sendMessage(opts) {
65
+ if (!this.apiKey) {
66
+ yield { type: "error", error: new Error("ANTHROPIC_API_KEY not set") };
67
+ return;
68
+ }
69
+ const body = {
70
+ model: this.model,
71
+ max_tokens: 4096,
72
+ system: opts.system,
73
+ stream: true,
74
+ messages: formatMessagesForAnthropic(opts),
75
+ };
76
+ if (opts.tools && opts.tools.length > 0) {
77
+ body.tools = formatToolsForAnthropic(opts.tools);
78
+ }
79
+ let res;
80
+ try {
81
+ res = await fetch(`${this.baseUrl}/v1/messages`, {
82
+ method: "POST",
83
+ headers: {
84
+ "content-type": "application/json",
85
+ "anthropic-version": ANTHROPIC_VERSION,
86
+ "x-api-key": this.apiKey,
87
+ },
88
+ body: JSON.stringify(body),
89
+ signal: opts.signal,
90
+ });
91
+ }
92
+ catch (err) {
93
+ yield { type: "error", error: err instanceof Error ? err : new Error(String(err)) };
94
+ return;
95
+ }
96
+ if (!res.ok || !res.body) {
97
+ const txt = await res.text().catch(() => "");
98
+ yield {
99
+ type: "error",
100
+ error: new Error(`Anthropic ${res.status}: ${txt.slice(0, 500)}`),
101
+ };
102
+ return;
103
+ }
104
+ let assembled = "";
105
+ const toolCallsByIndex = new Map();
106
+ const completedCalls = [];
107
+ try {
108
+ for await (const ev of parseSseStream(res.body)) {
109
+ if (!ev.data || ev.data === "[DONE]")
110
+ continue;
111
+ let parsed;
112
+ try {
113
+ parsed = JSON.parse(ev.data);
114
+ }
115
+ catch {
116
+ continue;
117
+ }
118
+ if (parsed.type === "content_block_start" && parsed.content_block?.type === "tool_use") {
119
+ const idx = parsed.index ?? 0;
120
+ toolCallsByIndex.set(idx, {
121
+ index: idx,
122
+ id: parsed.content_block.id ?? `call_${idx}`,
123
+ name: parsed.content_block.name ?? "",
124
+ argsJson: "",
125
+ });
126
+ }
127
+ else if (parsed.type === "content_block_delta" &&
128
+ parsed.delta?.type === "input_json_delta") {
129
+ const idx = parsed.index ?? 0;
130
+ const slot = toolCallsByIndex.get(idx);
131
+ if (slot) {
132
+ const fragment = parsed.delta.partial_json ?? "";
133
+ slot.argsJson += fragment;
134
+ yield {
135
+ type: "tool_call_arg_delta",
136
+ tool_call_id: slot.id,
137
+ name: slot.name,
138
+ arg_delta: fragment,
139
+ };
140
+ }
141
+ }
142
+ else if (parsed.type === "content_block_delta" &&
143
+ parsed.delta?.type === "text_delta") {
144
+ const delta = parsed.delta.text ?? "";
145
+ if (delta) {
146
+ assembled += delta;
147
+ yield { type: "text_delta", delta };
148
+ }
149
+ }
150
+ else if (parsed.type === "content_block_stop") {
151
+ const idx = parsed.index ?? 0;
152
+ const slot = toolCallsByIndex.get(idx);
153
+ if (slot) {
154
+ let args = {};
155
+ try {
156
+ args = slot.argsJson.length > 0 ? JSON.parse(slot.argsJson) : {};
157
+ }
158
+ catch {
159
+ args = { __parse_error: slot.argsJson };
160
+ }
161
+ const call = { id: slot.id, name: slot.name, arguments: args };
162
+ completedCalls.push(call);
163
+ yield { type: "tool_call_complete", call };
164
+ toolCallsByIndex.delete(idx);
165
+ }
166
+ }
167
+ else if (parsed.type === "message_stop") {
168
+ yield { type: "done", message: assembled, tool_calls: completedCalls };
169
+ return;
170
+ }
171
+ }
172
+ yield { type: "done", message: assembled, tool_calls: completedCalls };
173
+ }
174
+ catch (err) {
175
+ yield { type: "error", error: err instanceof Error ? err : new Error(String(err)) };
176
+ }
177
+ }
178
+ }
179
+ //# sourceMappingURL=anthropic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/adapters/anthropic.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { AgentAdapter, SendMessageOptions, StreamEvent, AdapterConfig, ToolDefinition, ToolResultForRound } from "../types.js";
2
+ export declare function formatToolsForGemini(tools: ToolDefinition[]): unknown;
3
+ export declare function formatMessagesForGemini(opts: SendMessageOptions): unknown[];
4
+ export declare function formatToolResultForGeminiMessage(r: ToolResultForRound): unknown;
5
+ export declare class GeminiAdapter implements AgentAdapter {
6
+ readonly id = "gemini";
7
+ readonly name = "Google Gemini";
8
+ readonly model: string;
9
+ private readonly apiKey;
10
+ private readonly baseUrl;
11
+ constructor(config?: AdapterConfig);
12
+ isConfigured(): boolean;
13
+ sendMessage(opts: SendMessageOptions): AsyncIterable<StreamEvent>;
14
+ }
15
+ //# sourceMappingURL=gemini.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini.d.ts","sourceRoot":"","sources":["../../src/adapters/gemini.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,cAAc,EAEd,kBAAkB,EACnB,MAAM,aAAa,CAAC;AAOrB,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,OAAO,CAUrE;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,EAAE,CA6B3E;AAED,wBAAgB,gCAAgC,CAAC,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAO/E;AAED,qBAAa,aAAc,YAAW,YAAY;IAChD,QAAQ,CAAC,EAAE,YAAY;IACvB,QAAQ,CAAC,IAAI,mBAAmB;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,MAAM,GAAE,aAAgC;IAMpD,YAAY,IAAI,OAAO;IAIhB,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,aAAa,CAAC,WAAW,CAAC;CA6EzE"}