@openma/common 0.0.0-stage → 0.9.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 (328) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +391 -2
  3. package/dist/acp-artifacts/binary.d.ts +35 -0
  4. package/dist/acp-artifacts/binary.d.ts.map +1 -0
  5. package/dist/acp-artifacts/binary.js +120 -0
  6. package/dist/acp-artifacts/binary.js.map +1 -0
  7. package/dist/acp-artifacts/index.d.ts +7 -0
  8. package/dist/acp-artifacts/index.d.ts.map +1 -0
  9. package/dist/acp-artifacts/index.js +7 -0
  10. package/dist/acp-artifacts/index.js.map +1 -0
  11. package/dist/acp-artifacts/node-abi.d.ts +3 -0
  12. package/dist/acp-artifacts/node-abi.d.ts.map +1 -0
  13. package/dist/acp-artifacts/node-abi.js +17 -0
  14. package/dist/acp-artifacts/node-abi.js.map +1 -0
  15. package/dist/acp-artifacts/npm-cli.d.ts +3 -0
  16. package/dist/acp-artifacts/npm-cli.d.ts.map +1 -0
  17. package/dist/acp-artifacts/npm-cli.js +9 -0
  18. package/dist/acp-artifacts/npm-cli.js.map +1 -0
  19. package/dist/acp-artifacts/npm.d.ts +37 -0
  20. package/dist/acp-artifacts/npm.d.ts.map +1 -0
  21. package/dist/acp-artifacts/npm.js +167 -0
  22. package/dist/acp-artifacts/npm.js.map +1 -0
  23. package/dist/acp-artifacts/registry.d.ts +45 -0
  24. package/dist/acp-artifacts/registry.d.ts.map +1 -0
  25. package/dist/acp-artifacts/registry.js +206 -0
  26. package/dist/acp-artifacts/registry.js.map +1 -0
  27. package/dist/acp-artifacts/shared.d.ts +45 -0
  28. package/dist/acp-artifacts/shared.d.ts.map +1 -0
  29. package/dist/acp-artifacts/shared.js +157 -0
  30. package/dist/acp-artifacts/shared.js.map +1 -0
  31. package/dist/acp-artifacts/uvx.d.ts +32 -0
  32. package/dist/acp-artifacts/uvx.d.ts.map +1 -0
  33. package/dist/acp-artifacts/uvx.js +95 -0
  34. package/dist/acp-artifacts/uvx.js.map +1 -0
  35. package/dist/acp-fork/index.d.ts +51 -0
  36. package/dist/acp-fork/index.d.ts.map +1 -0
  37. package/dist/acp-fork/index.js +116 -0
  38. package/dist/acp-fork/index.js.map +1 -0
  39. package/dist/acp-harnesses/agent-setup.d.ts +118 -0
  40. package/dist/acp-harnesses/agent-setup.d.ts.map +1 -0
  41. package/dist/acp-harnesses/agent-setup.js +717 -0
  42. package/dist/acp-harnesses/agent-setup.js.map +1 -0
  43. package/dist/acp-harnesses/custom-agents.d.ts +81 -0
  44. package/dist/acp-harnesses/custom-agents.d.ts.map +1 -0
  45. package/dist/acp-harnesses/custom-agents.js +361 -0
  46. package/dist/acp-harnesses/custom-agents.js.map +1 -0
  47. package/dist/acp-harnesses/headless-launch.d.ts +34 -0
  48. package/dist/acp-harnesses/headless-launch.d.ts.map +1 -0
  49. package/dist/acp-harnesses/headless-launch.js +67 -0
  50. package/dist/acp-harnesses/headless-launch.js.map +1 -0
  51. package/dist/acp-harnesses/index.d.ts +18 -0
  52. package/dist/acp-harnesses/index.d.ts.map +1 -0
  53. package/dist/acp-harnesses/index.js +58 -0
  54. package/dist/acp-harnesses/index.js.map +1 -0
  55. package/dist/acp-harnesses/install-state.d.ts +86 -0
  56. package/dist/acp-harnesses/install-state.d.ts.map +1 -0
  57. package/dist/acp-harnesses/install-state.js +322 -0
  58. package/dist/acp-harnesses/install-state.js.map +1 -0
  59. package/dist/acp-harnesses/installer.d.ts +145 -0
  60. package/dist/acp-harnesses/installer.d.ts.map +1 -0
  61. package/dist/acp-harnesses/installer.js +716 -0
  62. package/dist/acp-harnesses/installer.js.map +1 -0
  63. package/dist/acp-harnesses/known-agents.d.ts +154 -0
  64. package/dist/acp-harnesses/known-agents.d.ts.map +1 -0
  65. package/dist/acp-harnesses/known-agents.js +240 -0
  66. package/dist/acp-harnesses/known-agents.js.map +1 -0
  67. package/dist/acp-harnesses/launcher.d.ts +27 -0
  68. package/dist/acp-harnesses/launcher.d.ts.map +1 -0
  69. package/dist/acp-harnesses/launcher.js +64 -0
  70. package/dist/acp-harnesses/launcher.js.map +1 -0
  71. package/dist/acp-harnesses/registry-fetch.d.ts +42 -0
  72. package/dist/acp-harnesses/registry-fetch.d.ts.map +1 -0
  73. package/dist/acp-harnesses/registry-fetch.js +132 -0
  74. package/dist/acp-harnesses/registry-fetch.js.map +1 -0
  75. package/dist/acp-harnesses/registry.d.ts +36 -0
  76. package/dist/acp-harnesses/registry.d.ts.map +1 -0
  77. package/dist/acp-harnesses/registry.js +307 -0
  78. package/dist/acp-harnesses/registry.js.map +1 -0
  79. package/dist/acp-runtime/errors.d.ts +7 -0
  80. package/dist/acp-runtime/errors.d.ts.map +1 -0
  81. package/dist/acp-runtime/errors.js +17 -0
  82. package/dist/acp-runtime/errors.js.map +1 -0
  83. package/dist/acp-runtime/fork-support.d.ts +8 -0
  84. package/dist/acp-runtime/fork-support.d.ts.map +1 -0
  85. package/dist/acp-runtime/fork-support.js +20 -0
  86. package/dist/acp-runtime/fork-support.js.map +1 -0
  87. package/dist/acp-runtime/index.d.ts +11 -0
  88. package/dist/acp-runtime/index.d.ts.map +1 -0
  89. package/dist/acp-runtime/index.js +6 -0
  90. package/dist/acp-runtime/index.js.map +1 -0
  91. package/dist/acp-runtime/probe.d.ts +103 -0
  92. package/dist/acp-runtime/probe.d.ts.map +1 -0
  93. package/dist/acp-runtime/probe.js +872 -0
  94. package/dist/acp-runtime/probe.js.map +1 -0
  95. package/dist/acp-runtime/runtime.d.ts +7 -0
  96. package/dist/acp-runtime/runtime.d.ts.map +1 -0
  97. package/dist/acp-runtime/runtime.js +26 -0
  98. package/dist/acp-runtime/runtime.js.map +1 -0
  99. package/dist/acp-runtime/session.d.ts +87 -0
  100. package/dist/acp-runtime/session.d.ts.map +1 -0
  101. package/dist/acp-runtime/session.js +1071 -0
  102. package/dist/acp-runtime/session.js.map +1 -0
  103. package/dist/acp-runtime/spawners/node.d.ts +5 -0
  104. package/dist/acp-runtime/spawners/node.d.ts.map +1 -0
  105. package/dist/acp-runtime/spawners/node.js +244 -0
  106. package/dist/acp-runtime/spawners/node.js.map +1 -0
  107. package/dist/acp-runtime/types.d.ts +180 -0
  108. package/dist/acp-runtime/types.d.ts.map +1 -0
  109. package/dist/acp-runtime/types.js +2 -0
  110. package/dist/acp-runtime/types.js.map +1 -0
  111. package/dist/agent-contract/acp.d.ts +4 -0
  112. package/dist/agent-contract/acp.d.ts.map +1 -0
  113. package/dist/agent-contract/acp.js +273 -0
  114. package/dist/agent-contract/acp.js.map +1 -0
  115. package/dist/agent-contract/index.d.ts +125 -0
  116. package/dist/agent-contract/index.d.ts.map +1 -0
  117. package/dist/agent-contract/index.js +102 -0
  118. package/dist/agent-contract/index.js.map +1 -0
  119. package/dist/agent-contract/managed.d.ts +5 -0
  120. package/dist/agent-contract/managed.d.ts.map +1 -0
  121. package/dist/agent-contract/managed.js +242 -0
  122. package/dist/agent-contract/managed.js.map +1 -0
  123. package/dist/agent-ui/index.d.ts +170 -0
  124. package/dist/agent-ui/index.d.ts.map +1 -0
  125. package/dist/agent-ui/index.js +853 -0
  126. package/dist/agent-ui/index.js.map +1 -0
  127. package/dist/agent-ui/presentation.d.ts +30 -0
  128. package/dist/agent-ui/presentation.d.ts.map +1 -0
  129. package/dist/agent-ui/presentation.js +79 -0
  130. package/dist/agent-ui/presentation.js.map +1 -0
  131. package/dist/agent-ui/react.d.ts +50 -0
  132. package/dist/agent-ui/react.d.ts.map +1 -0
  133. package/dist/agent-ui/react.js +334 -0
  134. package/dist/agent-ui/react.js.map +1 -0
  135. package/dist/brand/index.d.ts +17 -0
  136. package/dist/brand/index.d.ts.map +1 -0
  137. package/dist/brand/index.js +119 -0
  138. package/dist/brand/index.js.map +1 -0
  139. package/dist/brand/openma-logo-mark.svg +7 -0
  140. package/dist/brand/tokens.css +77 -0
  141. package/dist/brand/website.css +67 -0
  142. package/dist/chat-ui/acp.d.ts +26 -0
  143. package/dist/chat-ui/acp.d.ts.map +1 -0
  144. package/dist/chat-ui/acp.js +166 -0
  145. package/dist/chat-ui/acp.js.map +1 -0
  146. package/dist/chat-ui/components.d.ts +230 -0
  147. package/dist/chat-ui/components.d.ts.map +1 -0
  148. package/dist/chat-ui/components.js +561 -0
  149. package/dist/chat-ui/components.js.map +1 -0
  150. package/dist/chat-ui/composer-drafts.d.ts +21 -0
  151. package/dist/chat-ui/composer-drafts.d.ts.map +1 -0
  152. package/dist/chat-ui/composer-drafts.js +58 -0
  153. package/dist/chat-ui/composer-drafts.js.map +1 -0
  154. package/dist/chat-ui/controller.d.ts +61 -0
  155. package/dist/chat-ui/controller.d.ts.map +1 -0
  156. package/dist/chat-ui/controller.js +218 -0
  157. package/dist/chat-ui/controller.js.map +1 -0
  158. package/dist/chat-ui/index.d.ts +8 -0
  159. package/dist/chat-ui/index.d.ts.map +1 -0
  160. package/dist/chat-ui/index.js +8 -0
  161. package/dist/chat-ui/index.js.map +1 -0
  162. package/dist/chat-ui/markdown.d.ts +37 -0
  163. package/dist/chat-ui/markdown.d.ts.map +1 -0
  164. package/dist/chat-ui/markdown.js +33 -0
  165. package/dist/chat-ui/markdown.js.map +1 -0
  166. package/dist/chat-ui/presentation.d.ts +34 -0
  167. package/dist/chat-ui/presentation.d.ts.map +1 -0
  168. package/dist/chat-ui/presentation.js +191 -0
  169. package/dist/chat-ui/presentation.js.map +1 -0
  170. package/dist/chat-ui/styles.css +815 -0
  171. package/dist/chat-ui/utils.d.ts +14 -0
  172. package/dist/chat-ui/utils.d.ts.map +1 -0
  173. package/dist/chat-ui/utils.js +71 -0
  174. package/dist/chat-ui/utils.js.map +1 -0
  175. package/dist/local-runtime/checkpoint.d.ts +28 -0
  176. package/dist/local-runtime/checkpoint.d.ts.map +1 -0
  177. package/dist/local-runtime/checkpoint.js +2 -0
  178. package/dist/local-runtime/checkpoint.js.map +1 -0
  179. package/dist/local-runtime/daemon-connection.d.ts +27 -0
  180. package/dist/local-runtime/daemon-connection.d.ts.map +1 -0
  181. package/dist/local-runtime/daemon-connection.js +161 -0
  182. package/dist/local-runtime/daemon-connection.js.map +1 -0
  183. package/dist/local-runtime/daemon-host.d.ts +39 -0
  184. package/dist/local-runtime/daemon-host.d.ts.map +1 -0
  185. package/dist/local-runtime/daemon-host.js +88 -0
  186. package/dist/local-runtime/daemon-host.js.map +1 -0
  187. package/dist/local-runtime/index.d.ts +6 -0
  188. package/dist/local-runtime/index.d.ts.map +1 -0
  189. package/dist/local-runtime/index.js +5 -0
  190. package/dist/local-runtime/index.js.map +1 -0
  191. package/dist/local-runtime/runtime.d.ts +36 -0
  192. package/dist/local-runtime/runtime.d.ts.map +1 -0
  193. package/dist/local-runtime/runtime.js +82 -0
  194. package/dist/local-runtime/runtime.js.map +1 -0
  195. package/dist/local-runtime/session-host.d.ts +62 -0
  196. package/dist/local-runtime/session-host.d.ts.map +1 -0
  197. package/dist/local-runtime/session-host.js +477 -0
  198. package/dist/local-runtime/session-host.js.map +1 -0
  199. package/dist/managed-runtime/acp-subagents.d.ts +14 -0
  200. package/dist/managed-runtime/acp-subagents.d.ts.map +1 -0
  201. package/dist/managed-runtime/acp-subagents.js +67 -0
  202. package/dist/managed-runtime/acp-subagents.js.map +1 -0
  203. package/dist/managed-runtime/claimed-environment-work.d.ts +61 -0
  204. package/dist/managed-runtime/claimed-environment-work.d.ts.map +1 -0
  205. package/dist/managed-runtime/claimed-environment-work.js +170 -0
  206. package/dist/managed-runtime/claimed-environment-work.js.map +1 -0
  207. package/dist/managed-runtime/contracts.d.ts +31 -0
  208. package/dist/managed-runtime/contracts.d.ts.map +1 -0
  209. package/dist/managed-runtime/contracts.js +2 -0
  210. package/dist/managed-runtime/contracts.js.map +1 -0
  211. package/dist/managed-runtime/http-control.d.ts +67 -0
  212. package/dist/managed-runtime/http-control.d.ts.map +1 -0
  213. package/dist/managed-runtime/http-control.js +465 -0
  214. package/dist/managed-runtime/http-control.js.map +1 -0
  215. package/dist/managed-runtime/index.d.ts +89 -0
  216. package/dist/managed-runtime/index.d.ts.map +1 -0
  217. package/dist/managed-runtime/index.js +215 -0
  218. package/dist/managed-runtime/index.js.map +1 -0
  219. package/dist/managed-runtime/input-identity.d.ts +2 -0
  220. package/dist/managed-runtime/input-identity.d.ts.map +1 -0
  221. package/dist/managed-runtime/input-identity.js +2 -0
  222. package/dist/managed-runtime/input-identity.js.map +1 -0
  223. package/dist/managed-runtime/managed-event-projector.d.ts +24 -0
  224. package/dist/managed-runtime/managed-event-projector.d.ts.map +1 -0
  225. package/dist/managed-runtime/managed-event-projector.js +333 -0
  226. package/dist/managed-runtime/managed-event-projector.js.map +1 -0
  227. package/dist/managed-runtime/semantic-recovery.d.ts +61 -0
  228. package/dist/managed-runtime/semantic-recovery.d.ts.map +1 -0
  229. package/dist/managed-runtime/semantic-recovery.js +167 -0
  230. package/dist/managed-runtime/semantic-recovery.js.map +1 -0
  231. package/dist/project-ui/CreateProjectDialog.d.ts +15 -0
  232. package/dist/project-ui/CreateProjectDialog.d.ts.map +1 -0
  233. package/dist/project-ui/CreateProjectDialog.js +87 -0
  234. package/dist/project-ui/CreateProjectDialog.js.map +1 -0
  235. package/dist/project-ui/ProjectComposer.d.ts +13 -0
  236. package/dist/project-ui/ProjectComposer.d.ts.map +1 -0
  237. package/dist/project-ui/ProjectComposer.js +70 -0
  238. package/dist/project-ui/ProjectComposer.js.map +1 -0
  239. package/dist/project-ui/ProjectConversation.d.ts +10 -0
  240. package/dist/project-ui/ProjectConversation.d.ts.map +1 -0
  241. package/dist/project-ui/ProjectConversation.js +28 -0
  242. package/dist/project-ui/ProjectConversation.js.map +1 -0
  243. package/dist/project-ui/ProjectMessageAttachments.d.ts +4 -0
  244. package/dist/project-ui/ProjectMessageAttachments.d.ts.map +1 -0
  245. package/dist/project-ui/ProjectMessageAttachments.js +28 -0
  246. package/dist/project-ui/ProjectMessageAttachments.js.map +1 -0
  247. package/dist/project-ui/ProjectSettings.d.ts +8 -0
  248. package/dist/project-ui/ProjectSettings.d.ts.map +1 -0
  249. package/dist/project-ui/ProjectSettings.js +65 -0
  250. package/dist/project-ui/ProjectSettings.js.map +1 -0
  251. package/dist/project-ui/Projects.d.ts +18 -0
  252. package/dist/project-ui/Projects.d.ts.map +1 -0
  253. package/dist/project-ui/Projects.js +377 -0
  254. package/dist/project-ui/Projects.js.map +1 -0
  255. package/dist/project-ui/client.d.ts +234 -0
  256. package/dist/project-ui/client.d.ts.map +1 -0
  257. package/dist/project-ui/client.js +42 -0
  258. package/dist/project-ui/client.js.map +1 -0
  259. package/dist/project-ui/controls.d.ts +15 -0
  260. package/dist/project-ui/controls.d.ts.map +1 -0
  261. package/dist/project-ui/controls.js +17 -0
  262. package/dist/project-ui/controls.js.map +1 -0
  263. package/dist/project-ui/index.d.ts +20 -0
  264. package/dist/project-ui/index.d.ts.map +1 -0
  265. package/dist/project-ui/index.js +17 -0
  266. package/dist/project-ui/index.js.map +1 -0
  267. package/dist/project-ui/project-coordinator.d.ts +3 -0
  268. package/dist/project-ui/project-coordinator.d.ts.map +1 -0
  269. package/dist/project-ui/project-coordinator.js +12 -0
  270. package/dist/project-ui/project-coordinator.js.map +1 -0
  271. package/dist/project-ui/project-goals.d.ts +48 -0
  272. package/dist/project-ui/project-goals.d.ts.map +1 -0
  273. package/dist/project-ui/project-goals.js +169 -0
  274. package/dist/project-ui/project-goals.js.map +1 -0
  275. package/dist/project-ui/projects-query.d.ts +19 -0
  276. package/dist/project-ui/projects-query.d.ts.map +1 -0
  277. package/dist/project-ui/projects-query.js +132 -0
  278. package/dist/project-ui/projects-query.js.map +1 -0
  279. package/dist/project-ui/styles.css +847 -0
  280. package/dist/protocol/acp/index.d.ts +52 -0
  281. package/dist/protocol/acp/index.d.ts.map +1 -0
  282. package/dist/protocol/acp/index.js +1056 -0
  283. package/dist/protocol/acp/index.js.map +1 -0
  284. package/dist/protocol/cursor-cloud/index.d.ts +74 -0
  285. package/dist/protocol/cursor-cloud/index.d.ts.map +1 -0
  286. package/dist/protocol/cursor-cloud/index.js +249 -0
  287. package/dist/protocol/cursor-cloud/index.js.map +1 -0
  288. package/dist/protocol/managed/index.d.ts +32 -0
  289. package/dist/protocol/managed/index.d.ts.map +1 -0
  290. package/dist/protocol/managed/index.js +646 -0
  291. package/dist/protocol/managed/index.js.map +1 -0
  292. package/dist/protocol/managed/input-identity.d.ts +3 -0
  293. package/dist/protocol/managed/input-identity.d.ts.map +1 -0
  294. package/dist/protocol/managed/input-identity.js +6 -0
  295. package/dist/protocol/managed/input-identity.js.map +1 -0
  296. package/dist/protocol/openai-agents/index.d.ts +102 -0
  297. package/dist/protocol/openai-agents/index.d.ts.map +1 -0
  298. package/dist/protocol/openai-agents/index.js +142 -0
  299. package/dist/protocol/openai-agents/index.js.map +1 -0
  300. package/dist/session-events/acp-system-notices.d.ts +10 -0
  301. package/dist/session-events/acp-system-notices.d.ts.map +1 -0
  302. package/dist/session-events/acp-system-notices.js +46 -0
  303. package/dist/session-events/acp-system-notices.js.map +1 -0
  304. package/dist/session-events/acp.d.ts +214 -0
  305. package/dist/session-events/acp.d.ts.map +1 -0
  306. package/dist/session-events/acp.js +956 -0
  307. package/dist/session-events/acp.js.map +1 -0
  308. package/dist/session-events/managed.d.ts +141 -0
  309. package/dist/session-events/managed.d.ts.map +1 -0
  310. package/dist/session-events/managed.js +324 -0
  311. package/dist/session-events/managed.js.map +1 -0
  312. package/dist/session-events/openma.d.ts +304 -0
  313. package/dist/session-events/openma.d.ts.map +1 -0
  314. package/dist/session-events/openma.js +438 -0
  315. package/dist/session-events/openma.js.map +1 -0
  316. package/dist/session-kernel/index.d.ts +118 -0
  317. package/dist/session-kernel/index.d.ts.map +1 -0
  318. package/dist/session-kernel/index.js +215 -0
  319. package/dist/session-kernel/index.js.map +1 -0
  320. package/dist/session-orchestrator/index.d.ts +71 -0
  321. package/dist/session-orchestrator/index.d.ts.map +1 -0
  322. package/dist/session-orchestrator/index.js +177 -0
  323. package/dist/session-orchestrator/index.js.map +1 -0
  324. package/dist/session-ui/index.d.ts +96 -0
  325. package/dist/session-ui/index.d.ts.map +1 -0
  326. package/dist/session-ui/index.js +277 -0
  327. package/dist/session-ui/index.js.map +1 -0
  328. package/package.json +222 -4
@@ -0,0 +1,65 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { ArrowLeftIcon } from "lucide-react";
4
+ import { useState } from "react";
5
+ import { normalizeProjectFolders } from "./client.js";
6
+ import { ProjectButton, projectErrorText } from "./controls.js";
7
+ import { ProjectFolderList } from "./CreateProjectDialog.js";
8
+ import { ProjectEditor } from "./Projects.js";
9
+ import { useProjectView } from "./projects-query.js";
10
+ export function ProjectSettings({ client, projectId, onBack, onDeleted, }) {
11
+ const query = useProjectView(client, projectId, 0);
12
+ const [notice, setNotice] = useState("");
13
+ if (query.isPending)
14
+ return _jsx("p", { role: "status", className: "project-settings", children: "Loading\u2026" });
15
+ if (query.error || !query.data) {
16
+ return _jsx("p", { role: "alert", className: "project-settings", children: projectErrorText(query.error ?? "Project not found") });
17
+ }
18
+ return (_jsxs("div", { className: "project-settings", children: [notice ? _jsx("p", { role: "status", children: notice }) : null, _jsx(ProjectSettingsForm, { client: client, project: query.data.project, view: query.data, onBack: onBack, onDeleted: onDeleted, refresh: query.reload, onSaved: () => setNotice("Project settings saved.") }, `${projectId}:${query.data.project.updated_at}`)] }));
19
+ }
20
+ function ProjectSettingsForm({ client, project, view, onBack, onDeleted, refresh, onSaved, }) {
21
+ const [name, setName] = useState(project.name);
22
+ const [folders, setFolders] = useState(project.source_folders);
23
+ const [coordinator, setCoordinator] = useState(false);
24
+ const [busy, setBusy] = useState(false);
25
+ const [error, setError] = useState("");
26
+ const save = async () => {
27
+ setBusy(true);
28
+ setError("");
29
+ const normalized = normalizeProjectFolders({
30
+ source_folders: folders,
31
+ primary_folder: folders[0],
32
+ });
33
+ try {
34
+ await client.save({
35
+ project_id: project.id,
36
+ name: name.trim(),
37
+ source_folders: [...normalized.source_folders],
38
+ primary_folder: normalized.primary_folder,
39
+ });
40
+ await refresh();
41
+ onSaved();
42
+ }
43
+ catch (cause) {
44
+ setError(projectErrorText(cause));
45
+ }
46
+ finally {
47
+ setBusy(false);
48
+ }
49
+ };
50
+ return (_jsxs(_Fragment, { children: [_jsxs("header", { children: [_jsx("h1", { children: "Project settings" }), onBack ? (_jsxs("button", { type: "button", onClick: onBack, children: [_jsx(ArrowLeftIcon, { className: "size-3.5", "aria-hidden": "true" }), _jsx("span", { children: project.name })] })) : null] }), _jsxs("form", { id: "project-settings-form", className: "project-form", onSubmit: (event) => {
51
+ event.preventDefault();
52
+ void save();
53
+ }, children: [_jsxs("section", { children: [_jsx("h2", { children: "General" }), _jsxs("label", { className: "project-field", children: ["Name", _jsx("input", { "aria-label": "Project name", required: true, value: name, onChange: (event) => setName(event.target.value) })] })] }), _jsxs("section", { children: [_jsx("h2", { children: "Folders" }), _jsx(ProjectFolderList, { folders: folders, onAdd: client.pickFolders ? () => {
54
+ void client.pickFolders?.().then((paths) => {
55
+ setFolders((current) => [...new Set([...current, ...paths])]);
56
+ }).catch((cause) => setError(projectErrorText(cause)));
57
+ } : undefined, onMakePrimary: (folder) => setFolders((current) => [folder, ...current.filter((path) => path !== folder)]), onRemove: (folder) => setFolders((current) => current.filter((path) => path !== folder)) })] }), error ? _jsx("p", { role: "alert", className: "project-error", children: error }) : null, _jsx("div", { className: "project-actions", children: _jsx(ProjectButton, { type: "submit", disabled: busy || !name.trim(), children: "Save" }) })] }), _jsxs("section", { children: [_jsx("h2", { children: "Execution" }), _jsx("p", { className: "project-note", children: "Choose the coordinator, worker, and where the project runs." }), _jsx(ProjectButton, { variant: "outline", onClick: () => setCoordinator(true), children: "Configure" })] }), coordinator ? (_jsx(ProjectEditor, { client: client, project: project, config: view.config ?? undefined, close: () => setCoordinator(false), saved: async () => {
58
+ setCoordinator(false);
59
+ await refresh();
60
+ }, removed: async () => {
61
+ setCoordinator(false);
62
+ onDeleted?.();
63
+ } })) : null] }));
64
+ }
65
+ //# sourceMappingURL=ProjectSettings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProjectSettings.js","sourceRoot":"","sources":["../../src/project-ui/ProjectSettings.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { ProjectClient, ProjectInfo, ProjectWorkConfig } from "./client.js";
2
+ export declare function ProjectsPage({ client, projectId: controlledProjectId, onProjectIdChange, refreshIntervalMs, }: {
3
+ client: ProjectClient;
4
+ /** With `onProjectIdChange`, the host owns which project is open. */
5
+ projectId?: string | null;
6
+ onProjectIdChange?: (projectId: string | null) => void;
7
+ /** Refetch interval for an open project. `0` polls only after local actions. */
8
+ refreshIntervalMs?: number;
9
+ }): import("react").JSX.Element;
10
+ export declare function ProjectEditor({ client, project, config, close, saved, removed, }: {
11
+ client: ProjectClient;
12
+ project?: ProjectInfo;
13
+ config?: ProjectWorkConfig;
14
+ close: () => void;
15
+ saved: (id: string) => Promise<void>;
16
+ removed: () => Promise<void>;
17
+ }): import("react").JSX.Element;
18
+ //# sourceMappingURL=Projects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Projects.d.ts","sourceRoot":"","sources":["../../src/project-ui/Projects.tsx"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EACV,aAAa,EAGb,WAAW,EAEX,iBAAiB,EAIlB,MAAM,aAAa,CAAC;AAmBrB,wBAAgB,YAAY,CAAC,EAC3B,MAAM,EACN,SAAS,EAAE,mBAAmB,EAC9B,iBAAiB,EACjB,iBAAwB,GACzB,EAAE;IACD,MAAM,EAAE,aAAa,CAAC;IACtB,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACvD,gFAAgF;IAChF,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,+BAwHA;AAED,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,OAAO,EACP,MAAM,EACN,KAAK,EACL,KAAK,EACL,OAAO,GACR,EAAE;IACD,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B,+BAwRA"}
@@ -0,0 +1,377 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { ArrowLeftIcon, CheckIcon, CirclePauseIcon, CirclePlayIcon, FileTextIcon, FolderIcon, ListTodoIcon, PencilIcon, PlusIcon, SettingsIcon, XIcon, } from "lucide-react";
4
+ import { useEffect, useRef, useState } from "react";
5
+ import { normalizeProjectFolders } from "./client.js";
6
+ import { ProjectButton, ProjectDialog, projectErrorText } from "./controls.js";
7
+ import { CreateProjectDialog, ProjectFolderList } from "./CreateProjectDialog.js";
8
+ import { ProjectComposer } from "./ProjectComposer.js";
9
+ import { ProjectConversation } from "./ProjectConversation.js";
10
+ import { ProjectMessageAttachments } from "./ProjectMessageAttachments.js";
11
+ import { defaultCoordinatorConfig } from "./project-coordinator.js";
12
+ import { projectCoordinatorTurns, projectGoalPresentation, projectOutcomeLabel, projectResponseText, projectThreads, } from "./project-goals.js";
13
+ import { useProjectView, useProjects } from "./projects-query.js";
14
+ const CONTROLS = ["delegate", "steer", "cancel", "complete"];
15
+ export function ProjectsPage({ client, projectId: controlledProjectId, onProjectIdChange, refreshIntervalMs = 1500, }) {
16
+ const projects = useProjects(client);
17
+ const controlled = onProjectIdChange !== undefined;
18
+ const [uncontrolledId, setUncontrolledId] = useState(null);
19
+ const projectId = controlled ? controlledProjectId ?? null : uncontrolledId;
20
+ const setProjectId = (next) => {
21
+ if (!controlled)
22
+ setUncontrolledId(next);
23
+ onProjectIdChange?.(next);
24
+ };
25
+ const workspace = useProjectView(client, projectId, refreshIntervalMs);
26
+ const [search, setSearch] = useState("");
27
+ const [creating, setCreating] = useState(false);
28
+ const [editing, setEditing] = useState(false);
29
+ const project = workspace.data?.project;
30
+ const visible = projects.data?.filter((item) => item.name.toLowerCase().includes(search.toLowerCase()));
31
+ return (_jsxs("div", { className: "projects-page", children: [projectId && workspace.isPending ? (_jsx("div", { className: "project-loading", role: "status", children: "Opening project\u2026" })) : null, workspace.error && projectId ? (_jsxs("div", { role: "alert", className: "project-error", children: [projectErrorText(workspace.error), " ", _jsx("button", { type: "button", onClick: () => setProjectId(null), children: "Back to projects" })] })) : null, !projectId ? (_jsxs("div", { className: "projects-index", children: [_jsxs("header", { className: "projects-list-header", children: [_jsxs("div", { children: [_jsx("h1", { children: "Projects" }), _jsx("p", { children: "Keep your conversations, knowledge, and work together." })] }), _jsxs(ProjectButton, { onClick: () => setCreating(true), children: [_jsx(PlusIcon, { className: "size-4", "aria-hidden": "true" }), "New project"] })] }), _jsx("input", { className: "projects-search", "aria-label": "Search projects", placeholder: "Search projects", value: search, onChange: (event) => setSearch(event.target.value) }), projects.error ? _jsx("p", { role: "alert", children: projectErrorText(projects.error) }) : null, projects.isPending ? _jsx("p", { role: "status", children: "Loading projects\u2026" }) : (_jsx("div", { className: "projects-grid", children: visible?.map((item) => (_jsxs("button", { type: "button", "data-project-id": item.id, className: "project-card", onClick: () => setProjectId(item.id), children: [_jsx(FolderIcon, { className: "size-5", "aria-hidden": "true" }), _jsx("h2", { children: item.name }), _jsx("p", { children: item.primary_folder || "Conversations and project knowledge" }), _jsxs("span", { children: ["Updated ", new Date(item.updated_at).toLocaleDateString()] })] }, item.id))) })), !projects.isPending && !projects.data?.length ? (_jsxs("div", { className: "projects-empty", children: [_jsx(FolderIcon, { className: "size-9", "aria-hidden": "true" }), _jsx("h2", { children: "A place for work that continues" }), _jsx("p", { children: "Create a project, add what your agents should know, and start a conversation." }), _jsx(ProjectButton, { variant: "outline", onClick: () => setCreating(true), children: "Create your first project" })] })) : null, projects.data?.length && visible && !visible.length ? (_jsxs("p", { className: "projects-empty", children: ["No projects match \u201C", search, "\u201D."] })) : null] })) : workspace.data ? (_jsx(ProjectWorkspace, { client: client, view: workspace.data, refresh: async () => {
32
+ await Promise.all([projects.reload(), workspace.reload()]);
33
+ }, edit: () => setEditing(true) }, projectId)) : null, _jsx(CreateProjectDialog, { client: client, open: creating && !projectId, onOpenChange: setCreating, onCreated: (created) => {
34
+ void projects.reload();
35
+ setProjectId(created.id);
36
+ } }), editing && project ? (_jsx(ProjectEditor, { client: client, project: project, config: workspace.data?.config ?? undefined, close: () => setEditing(false), saved: async (id) => {
37
+ setEditing(false);
38
+ await projects.reload();
39
+ await workspace.reload();
40
+ setProjectId(id);
41
+ }, removed: async () => {
42
+ setEditing(false);
43
+ setProjectId(null);
44
+ await projects.reload();
45
+ } })) : null] }));
46
+ }
47
+ export function ProjectEditor({ client, project, config, close, saved, removed, }) {
48
+ const creating = !project;
49
+ const [draft, setDraft] = useState(() => config ?? defaultCoordinatorConfig(project?.id ?? `proj-${crypto.randomUUID()}`));
50
+ const [name, setName] = useState(project?.name ?? "");
51
+ const [folders, setFolders] = useState(() => uniqueFolders(project));
52
+ const [busy, setBusy] = useState(false);
53
+ const [error, setError] = useState("");
54
+ const [section, setSection] = useState("general");
55
+ const cloud = draft.execution?.kind === "cloud";
56
+ const field = (key, value) => {
57
+ setDraft((current) => ({ ...current, [key]: value }));
58
+ };
59
+ const addFolders = async () => {
60
+ if (!client.pickFolders)
61
+ return;
62
+ try {
63
+ const selected = await client.pickFolders();
64
+ setFolders((current) => [...new Set([...current, ...selected])]);
65
+ }
66
+ catch (cause) {
67
+ setError(projectErrorText(cause));
68
+ }
69
+ };
70
+ const save = async () => {
71
+ if (busy || !name.trim())
72
+ return;
73
+ setBusy(true);
74
+ setError("");
75
+ try {
76
+ if (!creating && (!draft.coordinatorAgent.trim() || !draft.workerAgent.trim())) {
77
+ setSection("agents");
78
+ throw new Error("Choose a coordinator and worker agent to finish setup.");
79
+ }
80
+ if (cloud && (!draft.coordinatorEnvironment?.trim() || !draft.workerEnvironment?.trim())) {
81
+ setSection("agents");
82
+ throw new Error("Choose an environment for both agents.");
83
+ }
84
+ const normalized = normalizeProjectFolders({
85
+ source_folders: folders,
86
+ primary_folder: folders[0],
87
+ });
88
+ await client.save({
89
+ project_id: draft.projectId,
90
+ name: name.trim(),
91
+ source_folders: [...normalized.source_folders],
92
+ primary_folder: normalized.primary_folder,
93
+ });
94
+ await client.saveWork(draft);
95
+ await saved(draft.projectId);
96
+ }
97
+ catch (cause) {
98
+ setError(projectErrorText(cause));
99
+ }
100
+ finally {
101
+ setBusy(false);
102
+ }
103
+ };
104
+ const folderPicker = (_jsx(ProjectFolderList, { folders: folders, onAdd: client.pickFolders ? () => void addFolders() : undefined, onMakePrimary: (folder) => setFolders((current) => [folder, ...current.filter((path) => path !== folder)]), onRemove: (folder) => setFolders((current) => current.filter((path) => path !== folder)) }));
105
+ return (_jsx(ProjectDialog, { open: true, wide: true, title: creating ? "New project" : "Coordinator settings", description: creating
106
+ ? "Start with a goal. You can configure your agents later."
107
+ : "Manage your project’s context and execution.", onClose: close, children: _jsxs("form", { className: "project-form", onSubmit: (event) => {
108
+ event.preventDefault();
109
+ void save();
110
+ }, children: [creating ? (_jsxs("div", { className: "space-y-5", children: [_jsx(Basics, { name: name, setName: setName, draft: draft, field: field }), _jsxs("details", { children: [_jsx("summary", { children: "Add context (optional)" }), _jsxs("div", { children: [folderPicker, _jsxs("label", { className: "project-field", children: ["Context", _jsx("textarea", { "aria-label": "Context", rows: 3, value: draft.context, onChange: (event) => field("context", event.target.value) })] })] })] })] })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: "project-tabs", role: "tablist", "aria-label": "Project settings sections", children: ["general", "context", "agents"].map((item) => (_jsx("button", { type: "button", role: "tab", "aria-selected": section === item, onClick: () => setSection(item), children: item === "general" ? "General" : item === "context" ? "Context" : "Agents" }, item))) }), section === "general" ? (_jsxs("div", { children: [_jsx(Basics, { name: name, setName: setName, draft: draft, field: field }), _jsxs("details", { children: [_jsx("summary", { children: "Advanced" }), _jsxs("label", { className: "project-field", children: ["Conversation continuity", _jsxs("select", { "aria-label": "Conversation continuity", value: draft.continuity, onChange: (event) => field("continuity", event.target.value), children: [_jsx("option", { value: "per-scope", children: "Continue across this project" }), _jsx("option", { value: "per-run", children: "Separate conversations for each run" })] })] }), _jsxs("fieldset", { children: [_jsx("legend", { children: "Coordinator controls" }), _jsx("div", { children: CONTROLS.map((control) => (_jsxs("label", { className: "project-check", children: [_jsx("input", { type: "checkbox", checked: draft.controls.includes(control), onChange: (event) => field("controls", toggleControl(draft.controls, control, event.target.checked)) }), control] }, control))) })] })] })] })) : null, section === "context" ? (_jsxs("div", { children: [cloud ? (_jsx(RepositoryFields, { draft: draft, field: field })) : (_jsxs("div", { children: [_jsx("p", { children: "Source folders" }), folderPicker, _jsxs("label", { className: "project-field", children: ["Base branch or commit", _jsx("input", { "aria-label": "Base branch or commit", value: draft.baseRef ?? "", onChange: (event) => field("baseRef", event.target.value) })] }), _jsx("p", { className: "project-note", children: "New threads start from committed code. Existing threads keep their workspace." })] })), _jsxs("label", { className: "project-field", children: ["Instructions", _jsx("textarea", { "aria-label": "Instructions", rows: 3, value: draft.instructions, onChange: (event) => field("instructions", event.target.value) })] }), _jsxs("label", { className: "project-field", children: ["Context", _jsx("textarea", { "aria-label": "Context", rows: 3, value: draft.context, onChange: (event) => field("context", event.target.value) })] })] })) : null, section === "agents" ? (_jsxs("div", { children: [_jsxs("label", { className: "project-field", children: ["Execution location", _jsxs("select", { "aria-label": "Execution location", value: cloud ? "cloud" : "local", disabled: Boolean(config?.coordinatorAgent), onChange: (event) => {
111
+ const execution = event.target.value === "cloud"
112
+ ? { kind: "cloud", ...(draft.execution?.kind === "cloud" ? draft.execution : {}) }
113
+ : { kind: "local" };
114
+ setDraft((current) => ({ ...current, execution }));
115
+ }, children: [_jsx("option", { value: "local", children: "This computer" }), _jsx("option", { value: "cloud", children: "Cloud" })] })] }), _jsx("p", { className: "project-note", children: cloud
116
+ ? "Runs through the host’s Projects worker."
117
+ : "The host needs to stay available while agents work." }), _jsxs("label", { className: "project-field", children: ["Coordinator agent", _jsx("input", { "aria-label": "Coordinator agent", value: draft.coordinatorAgent, onChange: (event) => field("coordinatorAgent", event.target.value) })] }), _jsxs("label", { className: "project-field", children: ["Worker agent", _jsx("input", { "aria-label": "Worker agent", value: draft.workerAgent, onChange: (event) => field("workerAgent", event.target.value) })] }), cloud ? (_jsxs(_Fragment, { children: [_jsxs("label", { className: "project-field", children: ["Coordinator environment", _jsx("input", { "aria-label": "Coordinator environment", value: draft.coordinatorEnvironment ?? "", onChange: (event) => field("coordinatorEnvironment", event.target.value) })] }), _jsxs("label", { className: "project-field", children: ["Worker environment", _jsx("input", { "aria-label": "Worker environment", value: draft.workerEnvironment ?? "", onChange: (event) => field("workerEnvironment", event.target.value) })] })] })) : null] })) : null] })), error ? _jsx("p", { role: "alert", className: "project-error", children: error }) : null, _jsxs("div", { className: "project-actions", children: [!creating && project ? (_jsx(ProjectButton, { variant: "ghost", disabled: busy, style: { marginRight: "auto" }, onClick: () => {
118
+ setBusy(true);
119
+ setError("");
120
+ void client.delete(project.id).then(removed).catch((cause) => {
121
+ setError(projectErrorText(cause));
122
+ }).finally(() => setBusy(false));
123
+ }, children: "Delete project" })) : null, _jsx(ProjectButton, { variant: "ghost", disabled: busy, onClick: close, children: "Cancel" }), _jsx(ProjectButton, { type: "submit", disabled: busy || !name.trim(), children: creating ? "Create project" : "Save project" })] })] }) }));
124
+ }
125
+ function Basics({ name, setName, draft, field, }) {
126
+ return (_jsxs("div", { children: [_jsxs("label", { className: "project-field", children: ["Project name", _jsx("input", { required: true, value: name, onChange: (event) => setName(event.target.value), placeholder: "e.g. Improve checkout" })] }), _jsxs("label", { className: "project-field", children: ["Goal ", _jsx("span", { className: "project-note", children: "(optional)" }), _jsx("textarea", { "aria-label": "Goal", rows: 3, value: draft.description, onChange: (event) => field("description", event.target.value) })] })] }));
127
+ }
128
+ function RepositoryFields({ draft, field, }) {
129
+ const repositories = draft.repositories ?? [];
130
+ return (_jsxs("div", { children: [_jsx("p", { children: "Repositories" }), repositories.map((repo, index) => (_jsxs("div", { children: [_jsx("input", { "aria-label": `Repository ${index + 1}`, value: repo.url, placeholder: "https://github.com/owner/repo", onChange: (event) => field("repositories", repositories.map((item, itemIndex) => itemIndex === index ? { ...item, url: event.target.value } : item)) }), _jsx("input", { "aria-label": `Base reference ${index + 1}`, value: repo.baseRef ?? "", placeholder: "Default branch", onChange: (event) => field("repositories", repositories.map((item, itemIndex) => itemIndex === index ? { ...item, baseRef: event.target.value } : item)) }), _jsx(ProjectButton, { variant: "ghost", onClick: () => field("repositories", repositories.filter((_, itemIndex) => itemIndex !== index)), children: "Remove" })] }, index))), _jsxs(ProjectButton, { variant: "outline", disabled: repositories.length >= 8, onClick: () => field("repositories", [...repositories, { url: "" }]), children: [_jsx(PlusIcon, { className: "size-4", "aria-hidden": "true" }), "Add repository"] })] }));
131
+ }
132
+ function ProjectOutcomeBar({ goal, busy, onPause, onResume, }) {
133
+ const presentation = projectGoalPresentation(goal);
134
+ return (_jsxs("section", { className: `project-outcome project-outcome-${presentation.tone}`, "aria-label": "Project outcome", children: [_jsxs("div", { className: "project-outcome-copy", children: [_jsx("span", { className: "project-outcome-label", children: "Outcome" }), _jsx("strong", { title: presentation.title, children: presentation.title }), _jsxs("span", { className: "project-outcome-status", children: [projectOutcomeLabel(goal.status), presentation.budgetLabel ? ` · ${presentation.budgetLabel} tokens` : ""] })] }), _jsxs("div", { className: "project-outcome-actions", children: [presentation.actions.pause ? (_jsxs(ProjectButton, { variant: "outline", disabled: busy, onClick: onPause, children: [_jsx(CirclePauseIcon, { className: "size-3.5", "aria-hidden": "true" }), "Pause"] })) : null, presentation.actions.resume ? (_jsxs(ProjectButton, { variant: "outline", disabled: busy, onClick: onResume, children: [_jsx(CirclePlayIcon, { className: "size-3.5", "aria-hidden": "true" }), "Resume"] })) : null] })] }));
135
+ }
136
+ function ProjectWorkspace({ client, view, refresh, edit, }) {
137
+ const { project, config, facts } = view;
138
+ const [tab, setTab] = useState("conversation");
139
+ const [busy, setBusy] = useState(false);
140
+ const [error, setError] = useState("");
141
+ const [action, setAction] = useState(null);
142
+ const [resource, setResource] = useState(false);
143
+ const [selectedWorker, setSelectedWorker] = useState(null);
144
+ const [runId, setRunId] = useState(() => {
145
+ const last = facts.events.at(-1)?.payload;
146
+ const saved = payloadRecord(last).runId;
147
+ return typeof saved === "string" ? saved : crypto.randomUUID();
148
+ });
149
+ const uncertainSubmission = useRef(null);
150
+ const runScoped = config?.continuity === "per-run";
151
+ const sessions = facts.sessions.filter((session) => !runScoped || session.workThreadId.includes(`:run:${runId}:`));
152
+ const coordinator = sessions.filter((session) => session.agentId === "coordinator");
153
+ const workers = sessions.filter((session) => session.agentId === "worker");
154
+ const threads = projectThreads(view, runScoped ? runId : undefined);
155
+ const coordinatorOutcome = threads.find((thread) => thread.role === "coordinator")?.goal;
156
+ const coordinatorTurns = projectCoordinatorTurns(view, runScoped ? runId : undefined);
157
+ const promptPayloads = new Map(coordinatorTurns.map((turn) => {
158
+ const source = facts.turns.find((item) => item.id === turn.id);
159
+ const payload = facts.events.find((event) => event.id === source?.triggerEventId)?.payload;
160
+ return [turn.id, payload];
161
+ }));
162
+ const runs = [...new Set(facts.events.map((event) => {
163
+ const id = payloadRecord(event.payload).runId;
164
+ return typeof id === "string" ? id : "";
165
+ }).filter(Boolean))];
166
+ const setCoordinatorOutcome = async (status) => {
167
+ if (!coordinatorOutcome)
168
+ return;
169
+ setBusy(true);
170
+ setError("");
171
+ try {
172
+ await client.goal({
173
+ projectId: project.id,
174
+ workThreadId: coordinatorOutcome.workThreadId,
175
+ status,
176
+ });
177
+ await refresh();
178
+ }
179
+ catch (cause) {
180
+ setError(projectErrorText(cause));
181
+ }
182
+ finally {
183
+ setBusy(false);
184
+ }
185
+ };
186
+ const submit = async (type, message, workerId, attachments) => {
187
+ setBusy(true);
188
+ setError("");
189
+ const fingerprint = JSON.stringify([type, message, workerId, runId, attachments]);
190
+ const pending = uncertainSubmission.current?.fingerprint === fingerprint
191
+ ? uncertainSubmission.current
192
+ : { fingerprint, id: crypto.randomUUID() };
193
+ uncertainSubmission.current = pending;
194
+ try {
195
+ await client.submit({
196
+ projectId: project.id,
197
+ commandId: pending.id,
198
+ type,
199
+ text: message,
200
+ ...(attachments?.length ? { attachments } : {}),
201
+ ...(workerId ? { workerId } : {}),
202
+ ...(runScoped ? { runId } : {}),
203
+ });
204
+ uncertainSubmission.current = null;
205
+ await refresh();
206
+ return true;
207
+ }
208
+ catch (cause) {
209
+ setError(projectErrorText(cause));
210
+ return false;
211
+ }
212
+ finally {
213
+ setBusy(false);
214
+ }
215
+ };
216
+ const ready = Boolean(config?.coordinatorAgent && config.workerAgent);
217
+ return (_jsxs(_Fragment, { children: [_jsxs("header", { className: "project-topbar", children: [_jsx("button", { type: "button", className: "project-title", title: project.name, onClick: edit, children: project.name }), _jsxs(ProjectButton, { variant: tab !== "conversation" ? "outline" : "ghost", "aria-pressed": tab !== "conversation", onClick: () => {
218
+ setSelectedWorker(null);
219
+ setTab(tab === "conversation" ? "workers" : "conversation");
220
+ }, children: [_jsx(ListTodoIcon, { className: "size-3.5", "aria-hidden": "true" }), "Tasks"] }), _jsx(ProjectButton, { variant: "ghost", icon: true, "aria-label": "Project settings", onClick: edit, children: _jsx(SettingsIcon, { className: "size-4", "aria-hidden": "true" }) })] }), _jsxs("div", { className: `project-columns${tab !== "conversation" ? " project-panel-open" : ""}`, children: [_jsxs("section", { className: "project-main", children: [runScoped ? (_jsxs("div", { className: "project-runs", children: [_jsx("select", { "aria-label": "Select run", value: runId, onChange: (event) => setRunId(event.target.value), children: [...new Set([...runs, runId])].map((id, index) => (_jsxs("option", { value: id, children: ["Run ", index + 1, " \u00B7 ", id.slice(0, 8)] }, id))) }), _jsxs(ProjectButton, { variant: "ghost", onClick: () => setRunId(crypto.randomUUID()), children: [_jsx(PlusIcon, { className: "size-4", "aria-hidden": "true" }), "New run"] })] })) : null, coordinatorOutcome ? (_jsx(ProjectOutcomeBar, { goal: coordinatorOutcome, busy: busy, onPause: () => void setCoordinatorOutcome("paused"), onResume: () => void setCoordinatorOutcome("active") })) : null, ready && config ? (_jsx(ProjectConversation, { turns: coordinatorTurns, cwd: project.primary_folder || null, promptPayloads: promptPayloads, composer: _jsx(ProjectComposer, { agentId: config.coordinatorAgent, placeholder: `Message ${project.name}…`, busy: busy, onSubmit: (message, attachments) => submit("message", message, undefined, attachments), onEditAgents: edit }, `${project.id}:${runId}`) })) : (_jsxs("div", { className: "projects-empty", children: [_jsx("h2", { children: "Make this project your own" }), _jsx("p", { children: "Choose your agents and add instructions to begin." }), _jsx(ProjectButton, { onClick: edit, children: "Set up coordinator" })] })), error || view.error ? _jsx("p", { role: "alert", className: "project-error", children: error || view.error }) : null] }), tab !== "conversation" ? (_jsxs("aside", { className: "project-side-panel", "aria-label": tab === "overview" ? "Project overview" : tab === "workers" ? "Project workers" : "Project activity", children: [_jsxs("div", { className: "project-side-heading", children: [selectedWorker && tab === "workers" ? (_jsxs(ProjectButton, { variant: "ghost", onClick: () => setSelectedWorker(null), children: [_jsx(ArrowLeftIcon, { className: "size-4", "aria-hidden": "true" }), "Threads"] })) : (_jsx("div", { className: "project-tabs", role: "tablist", "aria-label": "Project views", children: ["workers", "overview", "activity"].map((item) => (_jsx("button", { type: "button", role: "tab", "aria-selected": tab === item, onClick: () => {
221
+ setSelectedWorker(null);
222
+ setTab(item);
223
+ }, children: item === "workers" ? "Threads" : item === "overview" ? "Library" : "Activity" }, item))) })), _jsx(ProjectButton, { variant: "ghost", icon: true, "aria-label": "Close panel", onClick: () => setTab("conversation"), children: _jsx(XIcon, { className: "size-4", "aria-hidden": "true" }) })] }), _jsxs("div", { className: "project-panel-content", children: [selectedWorker && tab === "workers" ? (_jsx(ProjectWorkerDetail, { view: view, workerId: selectedWorker, busy: busy, submit: (message, attachments) => submit("steer", message, selectedWorker, attachments), edit: edit })) : null, tab === "overview" && !selectedWorker ? (_jsx(ProjectLibrary, { client: client, view: view, edit: edit, refresh: refresh, onError: setError, onAddResource: () => setResource(true) })) : null, tab === "workers" && !selectedWorker ? (_jsx(ProjectWorkers, { view: view, workers: workers, threads: threads, config: config, onOpen: setSelectedWorker, onDelegate: () => setAction({ type: "delegate" }), onSteer: (workerId) => setAction({ type: "steer", workerId }), onCancel: (workerId) => void submit("cancel", "Cancelled by user", workerId) })) : null, tab === "activity" ? (_jsx(ProjectActivity, { view: view, canComplete: Boolean(config?.controls.includes("complete")), onComplete: () => setAction({ type: "complete" }) })) : null] })] })) : null, action ? (_jsx(ProjectAction, { error: error, action: action, close: () => setAction(null), submit: async (message, id) => {
224
+ if (await submit(action.type, message, id))
225
+ setAction(null);
226
+ } })) : null, resource && config ? (_jsx(ResourceEditor, { close: () => setResource(false), save: async (item) => {
227
+ await client.saveWork({ ...config, resources: [...config.resources, item] });
228
+ setResource(false);
229
+ await refresh();
230
+ } })) : null] })] }));
231
+ }
232
+ function ProjectLibrary({ client, view, edit, refresh, onError, onAddResource, }) {
233
+ const config = view.config;
234
+ return (_jsxs("div", { className: "project-knowledge", "aria-label": "Project knowledge", children: [_jsxs("div", { className: "project-knowledge-heading", children: [_jsx("h2", { children: "Project knowledge" }), _jsx(ProjectButton, { variant: "ghost", icon: true, "aria-label": "Edit knowledge", onClick: edit, children: _jsx(PencilIcon, { className: "size-4", "aria-hidden": "true" }) })] }), _jsxs("section", { children: [_jsx("h3", { children: "Instructions" }), _jsx("p", { children: config?.instructions || "No instructions yet." }), !config?.instructions ? _jsx("button", { type: "button", onClick: edit, children: "Add instructions" }) : null] }), _jsxs("section", { children: [_jsx("h3", { children: "Context" }), config?.description ? _jsx("p", { children: config.description }) : null, _jsx("p", { children: config?.context || "No additional context." })] }), _jsxs("section", { children: [_jsxs("div", { className: "project-knowledge-heading", children: [_jsx("h3", { children: "Resources" }), config ? (_jsx(ProjectButton, { variant: "ghost", icon: true, "aria-label": "Add resource", onClick: onAddResource, children: _jsx(PlusIcon, { className: "size-4", "aria-hidden": "true" }) })) : null] }), config?.resources.map((resource) => (_jsxs("details", { className: "project-resource", children: [_jsxs("summary", { children: [_jsx(FileTextIcon, { className: "size-4", "aria-hidden": "true" }), resource.name] }), _jsx("p", { children: resource.text }), _jsxs(ProjectButton, { variant: "ghost", onClick: () => {
235
+ void client.saveWork({
236
+ ...config,
237
+ resources: config.resources.filter((item) => item.id !== resource.id),
238
+ }).then(refresh).catch((cause) => onError(projectErrorText(cause)));
239
+ }, children: [_jsx(XIcon, { className: "size-4", "aria-hidden": "true" }), "Remove"] })] }, resource.id))), !config?.resources.length ? _jsx("p", { children: "No resources yet." }) : null] }), _jsxs("section", { className: "project-runtime-summary", children: [_jsx("h3", { children: "Agents" }), _jsxs("dl", { children: [_jsx("dt", { children: "Coordinator" }), _jsx("dd", { children: config?.coordinatorAgent || "Not configured" }), _jsx("dt", { children: "Workers" }), _jsx("dd", { children: config?.workerAgent || "Not configured" })] })] }), _jsx(Worktrees, { client: client, projectId: view.project.id, onError: onError })] }));
240
+ }
241
+ function Worktrees({ client, projectId, onError, }) {
242
+ const [trees, setTrees] = useState(null);
243
+ const [name, setName] = useState("");
244
+ useEffect(() => {
245
+ if (!client.listWorktrees)
246
+ return;
247
+ let active = true;
248
+ void client.listWorktrees(projectId).then((next) => {
249
+ if (active)
250
+ setTrees(next);
251
+ }, (cause) => {
252
+ if (active)
253
+ onError(projectErrorText(cause));
254
+ });
255
+ return () => {
256
+ active = false;
257
+ };
258
+ }, [client, onError, projectId]);
259
+ if (!client.listWorktrees)
260
+ return null;
261
+ return (_jsxs("section", { "aria-label": "Worktrees", children: [_jsx("h3", { children: "Worktrees" }), trees?.map((tree) => (_jsxs("article", { className: "project-worker", children: [_jsxs("div", { children: [_jsx("strong", { children: tree.name }), _jsxs("p", { children: [tree.branch ?? "Detached", " \u00B7 ", tree.paths.join(", ") || "No checkout path"] })] }), client.deleteWorktree ? (_jsx(ProjectButton, { variant: "ghost", onClick: () => {
262
+ void client.deleteWorktree?.(tree.id).then(async () => {
263
+ setTrees(await client.listWorktrees?.(projectId) ?? []);
264
+ }).catch((cause) => onError(projectErrorText(cause)));
265
+ }, children: "Remove worktree" })) : null] }, tree.id))), !trees?.length ? _jsx("p", { children: "No worktrees yet." }) : null, client.createWorktree ? (_jsxs("form", { className: "project-form", onSubmit: (event) => {
266
+ event.preventDefault();
267
+ const trimmed = name.trim();
268
+ if (!trimmed)
269
+ return;
270
+ void client.createWorktree?.({ projectId, name: trimmed }).then(async () => {
271
+ setName("");
272
+ setTrees(await client.listWorktrees?.(projectId) ?? []);
273
+ }).catch((cause) => onError(projectErrorText(cause)));
274
+ }, children: [_jsxs("label", { className: "project-field", children: ["New worktree", _jsx("input", { "aria-label": "New worktree", value: name, onChange: (event) => setName(event.target.value) })] }), _jsx(ProjectButton, { type: "submit", variant: "outline", disabled: !name.trim(), children: "Create worktree" })] })) : null] }));
275
+ }
276
+ function ProjectWorkers({ view, workers, threads, config, onOpen, onDelegate, onSteer, onCancel, }) {
277
+ const count = workers.length + (view.external_tasks?.length ?? 0);
278
+ return (_jsxs("div", { className: "project-work-list", children: [_jsxs("div", { className: "project-panel-summary", children: [_jsx("span", { children: count ? `${count} threads` : "No tasks yet" }), config?.controls.includes("delegate") ? (_jsx(ProjectButton, { variant: "ghost", icon: true, "aria-label": "Delegate task", title: "Delegate task", onClick: onDelegate, children: _jsx(PlusIcon, { className: "size-3.5", "aria-hidden": "true" }) })) : null] }), !workers.length && !view.external_tasks?.length ? (_jsxs("div", { className: "project-workers-empty", children: [_jsx("h3", { children: "Tasks appear here" }), _jsx("p", { children: "Delegated work shows up as its own thread." })] })) : null, ["running", "queued", "failed", "completed", "cancelled", "other"].map((state) => {
279
+ const group = workers.filter((worker) => {
280
+ const status = view.facts.turns.filter((turn) => turn.sessionId === worker.id).at(-1)?.state ?? "other";
281
+ return status === state;
282
+ });
283
+ if (!group.length)
284
+ return null;
285
+ const labels = {
286
+ running: "Working",
287
+ queued: "Queued",
288
+ failed: "Failed",
289
+ completed: "Completed",
290
+ cancelled: "Cancelled",
291
+ other: "No turns yet",
292
+ };
293
+ return (_jsxs("section", { className: "project-worker-group", children: [_jsxs("h3", { children: [labels[state], " ", _jsx("span", { children: group.length })] }), group.map((session) => {
294
+ const workerId = workerIdFromThread(session.workThreadId);
295
+ const turns = view.facts.turns.filter((turn) => turn.sessionId === session.id);
296
+ const last = turns.at(-1);
297
+ const workspace = view.workspaces?.find((item) => item.workThreadId === session.workThreadId);
298
+ const outcome = threads.find((thread) => thread.workThreadId === session.workThreadId)?.goal;
299
+ const preview = projectResponseText(view.facts.agentEvents.filter((event) => event.turn_id === last?.id)).slice(0, 160);
300
+ return (_jsxs("article", { className: "project-worker", children: [_jsxs("div", { children: [_jsx("button", { type: "button", className: "project-worker-title", onClick: () => onOpen(workerId), children: workerId }), _jsx("p", { className: "project-worker-attribution", children: "Built-in coordinator" }), _jsx("p", { className: "project-worker-preview", children: preview || "Waiting for output…" }), workspace?.location ? (_jsxs("p", { children: [workspace.location.branch ? `${workspace.location.branch} · ` : "", workspace.location.cwd ?? `OpenMA session ${workspace.location.remoteSessionId ?? ""}`] })) : null, _jsxs("span", { children: [last?.state ?? session.state ?? "open", " \u00B7 ", config?.workerAgent] }), outcome ? _jsxs("span", { className: "project-worker-outcome", children: ["Outcome: ", projectOutcomeLabel(outcome.status)] }) : null] }), _jsxs("div", { className: "project-worker-actions", children: [config?.controls.includes("steer") ? (_jsx(ProjectButton, { variant: "outline", onClick: () => onSteer(workerId), children: "Steer" })) : null, config?.controls.includes("cancel") && last && ["queued", "running"].includes(last.state) ? (_jsx(ProjectButton, { variant: "ghost", onClick: () => onCancel(workerId), children: "Cancel" })) : null, _jsx(ProjectButton, { variant: "ghost", onClick: () => onOpen(workerId), children: "View thread" })] })] }, session.id));
301
+ })] }, state));
302
+ }), view.external_tasks?.map((task) => (_jsxs("article", { className: "project-worker", "data-external-task": "true", children: [_jsx("p", { className: "project-worker-title", children: task.text }), task.status === "cancelled" ? _jsx("span", { children: "Cancelled" }) : null, task.coordinator_name ? _jsx("span", { children: task.coordinator_name }) : null] }, task.id)))] }));
303
+ }
304
+ function ProjectActivity({ view, canComplete, onComplete, }) {
305
+ return (_jsxs("div", { className: "project-work-list", children: [_jsxs("div", { className: "project-section-heading", children: [_jsx("h2", { children: "Activity history" }), canComplete ? (_jsxs(ProjectButton, { variant: "outline", onClick: onComplete, children: [_jsx(CheckIcon, { className: "size-4", "aria-hidden": "true" }), "Complete project"] })) : null] }), !view.facts.events.length ? (_jsx("p", { className: "project-help", children: "Activity appears when you send a message or delegate work." })) : null, [...view.facts.events].reverse().map((event) => {
306
+ const reaction = view.facts.reactions.find((item) => item.eventId === event.id);
307
+ return (_jsxs("details", { className: "project-activity", children: [_jsxs("summary", { children: [_jsx("span", { children: event.type.replace("backchat.project.", "").replace("project.", "").replaceAll(".", " ") }), _jsx("span", { children: reaction?.status ?? "Processing" }), _jsx("time", { children: new Date(event.occurredAt).toLocaleTimeString() })] }), _jsx("pre", { children: JSON.stringify(event.payload, null, 2) }), reaction?.reason ? _jsx("p", { children: reaction.reason }) : null] }, event.id));
308
+ })] }));
309
+ }
310
+ function ProjectWorkerDetail({ view, workerId, busy, submit, edit, }) {
311
+ const sessions = view.facts.sessions.filter((session) => session.agentId === "worker" && session.workThreadId.endsWith(`:worker:${workerId}`));
312
+ const turns = view.facts.turns.filter((turn) => sessions.some((session) => session.id === turn.sessionId));
313
+ return (_jsxs("div", { className: "project-thread-detail", children: [_jsxs("div", { className: "project-thread-transcript", children: [_jsx("h2", { children: workerId }), turns.map((turn) => {
314
+ const trigger = view.facts.events.find((event) => event.id === turn.triggerEventId);
315
+ const payload = payloadRecord(trigger?.payload);
316
+ const prompt = stringField(payload, "text") || stringField(payload, "task") || stringField(payload, "instruction");
317
+ const text = projectResponseText(view.facts.agentEvents.filter((event) => event.turn_id === turn.id));
318
+ return (_jsxs("article", { className: "project-turn", children: [prompt ? _jsx("div", { className: "project-user-message", children: prompt }) : null, _jsx(ProjectMessageAttachments, { payload: trigger?.payload }), _jsx("p", { className: "project-answer", children: text || (turn.state === "running" ? "Working…" : "No output yet.") }), _jsx("p", { className: "project-turn-state", children: turn.state })] }, turn.id));
319
+ })] }), view.config?.controls.includes("steer") ? (_jsx(ProjectComposer, { agentId: view.config.workerAgent, role: "Worker", label: "Message worker", placeholder: "Follow up with this worker\u2026", busy: busy, onSubmit: (message, attachments) => submit(message, attachments), onEditAgents: edit })) : null] }));
320
+ }
321
+ function ProjectAction({ action, close, submit, error, }) {
322
+ const [text, setText] = useState("");
323
+ const [workerId, setWorkerId] = useState(action.workerId ?? "");
324
+ const [busy, setBusy] = useState(false);
325
+ const label = action.type === "delegate" ? "Delegate" : action.type === "steer" ? "Steer" : "Complete";
326
+ return (_jsx(ProjectDialog, { open: true, title: `${label}${action.type === "complete" ? " project" : " task"}`, description: action.type === "steer"
327
+ ? "Queue a follow-up instruction for this worker."
328
+ : action.type === "complete"
329
+ ? "Record a reviewed summary of this project’s work."
330
+ : "Give this independent task a stable name and a clear brief.", onClose: close, children: _jsxs("form", { className: "project-form", onSubmit: (event) => {
331
+ event.preventDefault();
332
+ setBusy(true);
333
+ void submit(text, workerId).finally(() => setBusy(false));
334
+ }, children: [action.type !== "complete" ? (_jsxs("label", { className: "project-field", children: ["Worker ID", _jsx("input", { required: true, value: workerId, readOnly: Boolean(action.workerId), onChange: (event) => setWorkerId(event.target.value) })] })) : null, _jsxs("label", { className: "project-field", children: [action.type === "complete" ? "Summary" : action.type === "steer" ? "Instruction" : "Task", _jsx("textarea", { required: true, rows: 5, value: text, onChange: (event) => setText(event.target.value) })] }), error ? _jsx("p", { role: "alert", className: "project-error", children: error }) : null, _jsxs("div", { className: "project-actions", children: [_jsx(ProjectButton, { variant: "ghost", onClick: close, children: "Cancel" }), _jsx(ProjectButton, { type: "submit", disabled: busy, children: label })] })] }) }));
335
+ }
336
+ function ResourceEditor({ close, save, }) {
337
+ const [text, setText] = useState("");
338
+ const [name, setName] = useState("");
339
+ const [error, setError] = useState("");
340
+ const [busy, setBusy] = useState(false);
341
+ return (_jsx(ProjectDialog, { open: true, title: "Add project resource", description: "Add a note or a text file. It is included in project context.", onClose: close, children: _jsxs("form", { className: "project-form", onSubmit: (event) => {
342
+ event.preventDefault();
343
+ setBusy(true);
344
+ void save({ id: crypto.randomUUID(), name, text })
345
+ .catch((cause) => setError(projectErrorText(cause)))
346
+ .finally(() => setBusy(false));
347
+ }, children: [_jsxs("label", { className: "project-field", children: ["Text file", _jsx("input", { type: "file", accept: ".txt,.md,.csv,.json,text/plain", onChange: (event) => {
348
+ const file = event.target.files?.[0];
349
+ if (!file)
350
+ return;
351
+ if (file.size > 200_000) {
352
+ setError("Choose a text file under 200 KB.");
353
+ return;
354
+ }
355
+ setName(file.name);
356
+ void file.text().then(setText);
357
+ } })] }), _jsxs("label", { className: "project-field", children: ["Resource name", _jsx("input", { required: true, value: name, onChange: (event) => setName(event.target.value) })] }), _jsxs("label", { className: "project-field", children: ["Content", _jsx("textarea", { required: true, rows: 7, value: text, onChange: (event) => setText(event.target.value) })] }), error ? _jsx("p", { role: "alert", className: "project-error", children: error }) : null, _jsxs("div", { className: "project-actions", children: [_jsx(ProjectButton, { variant: "ghost", onClick: close, children: "Cancel" }), _jsx(ProjectButton, { type: "submit", disabled: busy, children: "Add resource" })] })] }) }));
358
+ }
359
+ function uniqueFolders(project) {
360
+ return [...new Set([project?.primary_folder, ...(project?.source_folders ?? [])].filter((path) => Boolean(path)))];
361
+ }
362
+ function toggleControl(controls, control, checked) {
363
+ return checked
364
+ ? [...new Set([...controls, control])]
365
+ : controls.filter((item) => item !== control);
366
+ }
367
+ function workerIdFromThread(workThreadId) {
368
+ return workThreadId.split(":worker:").slice(1).join(":worker:");
369
+ }
370
+ function payloadRecord(payload) {
371
+ return payload && typeof payload === "object" ? payload : {};
372
+ }
373
+ function stringField(record, key) {
374
+ const value = record[key];
375
+ return typeof value === "string" ? value : "";
376
+ }
377
+ //# sourceMappingURL=Projects.js.map