@midhunxavier/code-flow 0.0.0-stage → 0.1.0-preview.3

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 (319) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +141 -2
  3. package/bin/codeflow.mjs +8 -0
  4. package/bin/launcher.mjs +127 -0
  5. package/dist/remote-host.json +1 -0
  6. package/licenses/inter.txt +92 -0
  7. package/licenses/preact.txt +21 -0
  8. package/licenses/signals-core.txt +21 -0
  9. package/licenses/signals.txt +21 -0
  10. package/licenses/typescript-notices.txt +193 -0
  11. package/licenses/typescript.txt +55 -0
  12. package/licenses/uqr.txt +22 -0
  13. package/licenses/xterm-fit.txt +19 -0
  14. package/licenses/xterm.txt +21 -0
  15. package/package.json +34 -4
  16. package/public/assets/changes-62ZIEQSN.js +1 -0
  17. package/public/assets/chunk-2PZVOKID.js +1 -0
  18. package/public/assets/chunk-4D5IENEB.js +1 -0
  19. package/public/assets/chunk-5SARP5MU.js +1 -0
  20. package/public/assets/chunk-63YLZ3PR.js +1 -0
  21. package/public/assets/chunk-7FUHKF2M.js +1 -0
  22. package/public/assets/chunk-APQEVJ2K.js +1 -0
  23. package/public/assets/chunk-CGOZQMEZ.js +2 -0
  24. package/public/assets/chunk-J4VYS3KV.js +2 -0
  25. package/public/assets/chunk-L7TUCIYF.js +1 -0
  26. package/public/assets/chunk-SIHDWM2Y.js +154 -0
  27. package/public/assets/chunk-TEJVYIKC.js +1 -0
  28. package/public/assets/code-browser-VB2HGZSG.js +4 -0
  29. package/public/assets/filtered-tasks-ES5CP4KV.js +1 -0
  30. package/public/assets/interactive-browser-7F5ZXRUV.js +7 -0
  31. package/public/assets/join-project-6RTFHNCA.js +1 -0
  32. package/public/assets/main-65EW73SB.js +1 -0
  33. package/public/assets/project-invitations-view-GMPWGWYM.js +1 -0
  34. package/public/assets/settings-UB5Q4AQM.js +9 -0
  35. package/public/assets/styles-18792BB4.css +32 -0
  36. package/public/assets/team-server-wizard-2GLDWS6D.js +8 -0
  37. package/public/assets/terminal-IWAIM4DE.js +62 -0
  38. package/public/assets.json +1 -0
  39. package/public/bundle-meta.json +1 -0
  40. package/public/docs/.nojekyll +0 -0
  41. package/public/docs/accessibility.html +19 -0
  42. package/public/docs/acp-agents.html +117 -0
  43. package/public/docs/agent-containers.html +79 -0
  44. package/public/docs/api.html +1130 -0
  45. package/public/docs/app.js +342 -0
  46. package/public/docs/application-improvements.html +275 -0
  47. package/public/docs/architecture-explorer.html +19 -0
  48. package/public/docs/architecture.html +149 -0
  49. package/public/docs/auto-team.html +148 -0
  50. package/public/docs/automations.html +109 -0
  51. package/public/docs/checkpoint-review.html +37 -0
  52. package/public/docs/code-hosts.html +35 -0
  53. package/public/docs/code-intelligence.html +35 -0
  54. package/public/docs/configuration.html +346 -0
  55. package/public/docs/context-inspection.html +23 -0
  56. package/public/docs/coordinated-changes.html +28 -0
  57. package/public/docs/deferred-runs.html +25 -0
  58. package/public/docs/dependency-discovery.html +19 -0
  59. package/public/docs/documentation.html +84 -0
  60. package/public/docs/dynamic-teams-evaluation.html +174 -0
  61. package/public/docs/dynamic-teams-implementation-plan.html +882 -0
  62. package/public/docs/dynamic-teams-implementation-review-1.html +141 -0
  63. package/public/docs/dynamic-teams-plan-review-0.html +204 -0
  64. package/public/docs/extensions.html +42 -0
  65. package/public/docs/external-sources.html +96 -0
  66. package/public/docs/filesystem-policy.html +26 -0
  67. package/public/docs/filtered-tasks.html +44 -0
  68. package/public/docs/font-license.txt +92 -0
  69. package/public/docs/getting-started.html +143 -0
  70. package/public/docs/github-review-threads.html +26 -0
  71. package/public/docs/github.html +157 -0
  72. package/public/docs/help.html +69 -0
  73. package/public/docs/index.html +88 -0
  74. package/public/docs/installation.html +80 -0
  75. package/public/docs/launch-profiles.html +48 -0
  76. package/public/docs/maintenance.html +60 -0
  77. package/public/docs/memory-claims.html +31 -0
  78. package/public/docs/memory-storage.html +58 -0
  79. package/public/docs/notifications.html +39 -0
  80. package/public/docs/patterns.html +195 -0
  81. package/public/docs/performance-results.html +210 -0
  82. package/public/docs/performance.html +166 -0
  83. package/public/docs/project-conventions.html +22 -0
  84. package/public/docs/project-first-navigation-plan.html +587 -0
  85. package/public/docs/project-teams-implementation-plan.html +772 -0
  86. package/public/docs/project-teams.html +129 -0
  87. package/public/docs/provider-compatibility.html +20 -0
  88. package/public/docs/releasing.html +65 -0
  89. package/public/docs/remote-workers.html +64 -0
  90. package/public/docs/review-inbox.html +26 -0
  91. package/public/docs/run-storage.html +23 -0
  92. package/public/docs/runs.html +141 -0
  93. package/public/docs/search.json +1 -0
  94. package/public/docs/security.html +133 -0
  95. package/public/docs/shared-projects.html +31 -0
  96. package/public/docs/ssh-projects.html +60 -0
  97. package/public/docs/style.css +768 -0
  98. package/public/docs/task-reruns.html +30 -0
  99. package/public/docs/team-collaboration.html +412 -0
  100. package/public/docs/verification.html +22 -0
  101. package/public/docs/vscode.html +53 -0
  102. package/public/docs/worker-permission-verification.html +131 -0
  103. package/public/index.html +17 -0
  104. package/scripts/check-node.mjs +7 -0
  105. package/scripts/codeflow.mjs +55 -0
  106. package/scripts/computer-use.swift +64 -0
  107. package/scripts/pty.py +273 -0
  108. package/src/acp-connections.js +110 -0
  109. package/src/adapters/acp-presets.js +37 -0
  110. package/src/adapters/acp-types.js +0 -0
  111. package/src/adapters/acp.js +328 -0
  112. package/src/adapters/agent-tools.js +28 -0
  113. package/src/adapters/agy-auth.js +67 -0
  114. package/src/adapters/agy-isolation.js +242 -0
  115. package/src/adapters/agy-tools.js +45 -0
  116. package/src/adapters/agy.js +326 -0
  117. package/src/adapters/claude-stream.js +58 -0
  118. package/src/adapters/claude.js +282 -0
  119. package/src/adapters/codex-app-server.js +555 -0
  120. package/src/adapters/codex.js +311 -0
  121. package/src/adapters/errors.js +57 -0
  122. package/src/adapters/index.js +91 -0
  123. package/src/adapters/managed-permissions.js +37 -0
  124. package/src/adapters/model-discovery.js +100 -0
  125. package/src/adapters/process.js +433 -0
  126. package/src/adapters/team-tools.js +103 -0
  127. package/src/adapters/types.js +0 -0
  128. package/src/agent-browser.js +688 -0
  129. package/src/agent-computer.js +88 -0
  130. package/src/agent-container.js +155 -0
  131. package/src/agent-team-definitions.js +131 -0
  132. package/src/agent-tool-client.mjs +79 -0
  133. package/src/agent-tools.js +296 -0
  134. package/src/approvals.js +134 -0
  135. package/src/architecture.js +456 -0
  136. package/src/assets.js +44 -0
  137. package/src/automation.js +901 -0
  138. package/src/browser-files.js +293 -0
  139. package/src/browser-ownership.js +150 -0
  140. package/src/certificate-renewal.js +75 -0
  141. package/src/chat-family.js +25 -0
  142. package/src/chat-handoff.js +87 -0
  143. package/src/checkpoint-review.js +72 -0
  144. package/src/checks.js +303 -0
  145. package/src/code-host-git.js +102 -0
  146. package/src/code-hosts-api.js +99 -0
  147. package/src/code-hosts.js +482 -0
  148. package/src/code-intelligence-worker.mjs +452 -0
  149. package/src/code-intelligence.js +141 -0
  150. package/src/collab/api.js +365 -0
  151. package/src/collab/checkpoints.js +198 -0
  152. package/src/collab/connections.js +139 -0
  153. package/src/collab/host-execution.js +347 -0
  154. package/src/collab/hub-client.js +210 -0
  155. package/src/collab/link-api.js +229 -0
  156. package/src/collab/link.js +595 -0
  157. package/src/collab/model.js +496 -0
  158. package/src/collab/runner.js +1014 -0
  159. package/src/collab/store.js +1452 -0
  160. package/src/collab/terminals.js +361 -0
  161. package/src/collaboration-reviews.js +116 -0
  162. package/src/config.js +48 -0
  163. package/src/context-budget.js +14 -0
  164. package/src/context-inspection.js +204 -0
  165. package/src/context.js +154 -0
  166. package/src/conventions.js +283 -0
  167. package/src/coordinated-api.js +247 -0
  168. package/src/deferred-launch.js +82 -0
  169. package/src/deferred-runs.js +515 -0
  170. package/src/dependency-health.js +35 -0
  171. package/src/diff.js +43 -0
  172. package/src/docs-help.js +316 -0
  173. package/src/doctor.js +232 -0
  174. package/src/documentation-changes.js +20 -0
  175. package/src/engine.js +5258 -0
  176. package/src/env.js +44 -0
  177. package/src/execution-budget.js +8 -0
  178. package/src/experience.js +50 -0
  179. package/src/extensions.js +144 -0
  180. package/src/filesystem-access.js +107 -0
  181. package/src/filesystem-policy.js +238 -0
  182. package/src/filtered-task-limits.js +93 -0
  183. package/src/filtered-tasks-api.js +53 -0
  184. package/src/filtered-tasks.js +576 -0
  185. package/src/frame-policy.js +66 -0
  186. package/src/fs.js +57 -0
  187. package/src/git.js +626 -0
  188. package/src/github-review-threads.js +181 -0
  189. package/src/github.js +538 -0
  190. package/src/http.js +69 -0
  191. package/src/improve-settings.js +38 -0
  192. package/src/improve.js +187 -0
  193. package/src/integrations.js +373 -0
  194. package/src/integrity.js +259 -0
  195. package/src/journey-api.js +77 -0
  196. package/src/journey-replay.js +65 -0
  197. package/src/journey-store.js +97 -0
  198. package/src/journeys.js +60 -0
  199. package/src/json.js +81 -0
  200. package/src/launch-profiles.js +292 -0
  201. package/src/learnings.js +80 -0
  202. package/src/local-app-url.js +19 -0
  203. package/src/log.js +39 -0
  204. package/src/maintenance.js +335 -0
  205. package/src/memory-analysis.js +182 -0
  206. package/src/memory-claims.js +153 -0
  207. package/src/memory-sqlite.js +236 -0
  208. package/src/memory.js +552 -0
  209. package/src/merge-validation.js +58 -0
  210. package/src/model-catalog.js +239 -0
  211. package/src/model-research.js +91 -0
  212. package/src/notes.js +176 -0
  213. package/src/notifications.js +413 -0
  214. package/src/patterns/auto-team-model.js +230 -0
  215. package/src/patterns/auto-team.js +816 -0
  216. package/src/patterns/council.js +199 -0
  217. package/src/patterns/debate.js +188 -0
  218. package/src/patterns/findings.js +141 -0
  219. package/src/patterns/index.js +21 -0
  220. package/src/patterns/loop.js +158 -0
  221. package/src/patterns/pipeline.js +125 -0
  222. package/src/patterns/prompts.js +181 -0
  223. package/src/patterns/race.js +147 -0
  224. package/src/patterns/schemas.js +40 -0
  225. package/src/patterns/solo.js +46 -0
  226. package/src/patterns/supervisor.js +235 -0
  227. package/src/patterns/task-draft.js +29 -0
  228. package/src/patterns/task-review.js +45 -0
  229. package/src/patterns/tdd.js +231 -0
  230. package/src/patterns/team-strategies.js +67 -0
  231. package/src/performance.js +43 -0
  232. package/src/persistence-status.js +35 -0
  233. package/src/phone-sessions.js +96 -0
  234. package/src/preview-overlay.js +392 -0
  235. package/src/preview.js +230 -0
  236. package/src/privacy.js +23 -0
  237. package/src/project-report.js +22 -0
  238. package/src/project-team-budget.js +22 -0
  239. package/src/project-team-model.js +225 -0
  240. package/src/project-team-policy.js +42 -0
  241. package/src/project-team-store.js +234 -0
  242. package/src/project-team-usage.js +24 -0
  243. package/src/project-teams-api.js +43 -0
  244. package/src/project-teams.js +644 -0
  245. package/src/projects.js +290 -0
  246. package/src/provider-eligibility.js +9 -0
  247. package/src/readiness.js +98 -0
  248. package/src/remote-tls.js +66 -0
  249. package/src/remote-workers/bundles.js +198 -0
  250. package/src/remote-workers/client.js +332 -0
  251. package/src/remote-workers/durability.js +37 -0
  252. package/src/remote-workers/protocol.js +68 -0
  253. package/src/remote-workers/stdio.js +138 -0
  254. package/src/remote-workers/worker.js +304 -0
  255. package/src/remote.js +204 -0
  256. package/src/repo-config.js +201 -0
  257. package/src/repo-coordination.js +725 -0
  258. package/src/repo-tree.js +106 -0
  259. package/src/repository-identity.js +13 -0
  260. package/src/retention-policy.js +466 -0
  261. package/src/review-inbox.js +38 -0
  262. package/src/routing.js +49 -0
  263. package/src/run-analysis.js +111 -0
  264. package/src/run-cold-store.js +231 -0
  265. package/src/run-environment.js +15 -0
  266. package/src/run-history.js +91 -0
  267. package/src/run-log.js +160 -0
  268. package/src/run-permissions.js +111 -0
  269. package/src/run-projection.js +77 -0
  270. package/src/run-recovery.js +53 -0
  271. package/src/run-status.js +56 -0
  272. package/src/serve.js +138 -0
  273. package/src/server.js +2871 -0
  274. package/src/shared-access.js +103 -0
  275. package/src/shared-accounts.js +381 -0
  276. package/src/shared-api.js +239 -0
  277. package/src/shell.js +346 -0
  278. package/src/ship.js +344 -0
  279. package/src/slots.js +74 -0
  280. package/src/snapshot.js +388 -0
  281. package/src/source-context.js +17 -0
  282. package/src/sse-writer.js +70 -0
  283. package/src/ssh-projects/bootstrap.mjs +95 -0
  284. package/src/ssh-projects/config.js +45 -0
  285. package/src/ssh-projects/gateway.js +143 -0
  286. package/src/ssh-projects/manager.js +320 -0
  287. package/src/ssh-projects/team-autostart.mjs +93 -0
  288. package/src/ssh-projects/team-remove.mjs +69 -0
  289. package/src/ssh-projects/team-status.mjs +39 -0
  290. package/src/ssh-projects/transport.js +133 -0
  291. package/src/stats.js +139 -0
  292. package/src/store.js +544 -0
  293. package/src/stream.js +91 -0
  294. package/src/sweeps.js +241 -0
  295. package/src/tailscale.js +101 -0
  296. package/src/task-draft.js +23 -0
  297. package/src/task-team.js +164 -0
  298. package/src/team-evaluation.js +243 -0
  299. package/src/team-mailbox.js +160 -0
  300. package/src/team-memory.js +84 -0
  301. package/src/team-rerun-graph.js +15 -0
  302. package/src/team-reruns.js +130 -0
  303. package/src/team-scheduler.js +121 -0
  304. package/src/team-steering.js +21 -0
  305. package/src/team-template-store.js +98 -0
  306. package/src/team-templates.js +117 -0
  307. package/src/team-tool-client.mjs +79 -0
  308. package/src/team-tools.js +235 -0
  309. package/src/teams.js +0 -0
  310. package/src/templates.js +62 -0
  311. package/src/transcript.js +134 -0
  312. package/src/verification-integrity.js +27 -0
  313. package/src/verification.js +183 -0
  314. package/src/watch.js +195 -0
  315. package/src/work-queue.js +47 -0
  316. package/src/workflow-control.js +83 -0
  317. package/src/workspace-api.js +207 -0
  318. package/src/workspace-changes.js +61 -0
  319. package/src/workspace.js +146 -0
@@ -0,0 +1,229 @@
1
+ import { isAbsolute } from "node:path";
2
+ import { isAgentId, validateAgentSettings } from "../adapters/index.js";
3
+ import { readJson, send } from "../http.js";
4
+ import { logError } from "../log.js";
5
+ import { CHECKPOINT_ID, CollabError, validatePathId } from "./model.js";
6
+ import { ownerActor } from "./store.js";
7
+ const BODY_LIMIT = 16 * 1024, START_BODY_LIMIT = 64 * 1024, BODY_TIMEOUT = { timeoutMs: 1e4 };
8
+ const TRUSTS = ["safe", "standard", "trusted", "full"], START_FIELDS = ["repo", "pattern", "roles", "agentSettings", "roleSettings", "trust", "loop", "fromCheckpointId"], LOOP_FIELDS = ["check", "setup", "maxMinutes", "maxSteps"];
9
+ const object = (v) => !!v && typeof v === "object" && !Array.isArray(v);
10
+ const absent = (v) => v === void 0 || v === null || v === "";
11
+ const body = (req, limit = BODY_LIMIT) => readJson(req, limit, BODY_TIMEOUT);
12
+ function assertKeys(value, allowed, what) {
13
+ const extra = Object.keys(value).find((key) => !allowed.includes(key));
14
+ if (extra !== void 0) throw new CollabError(`Unknown ${what} field ${JSON.stringify(extra.slice(0, 40))}; the allowed fields are ${allowed.join(", ")}`);
15
+ }
16
+ function repoPath(value, required) {
17
+ if (absent(value)) {
18
+ if (required) throw new CollabError("Send the absolute path of your clone as repo");
19
+ return void 0;
20
+ }
21
+ if (typeof value !== "string" || !isAbsolute(value) || value.length > 4096) throw new CollabError("Repository must be an absolute path");
22
+ return value;
23
+ }
24
+ function validateRoles(pattern, input, installed) {
25
+ if (!object(input)) throw new CollabError("Send roles as { <role>: [agent ids] }");
26
+ const known = pattern.roles.map((spec) => spec.id), extra = Object.keys(input).find((key) => !known.includes(key));
27
+ if (extra !== void 0) throw new CollabError(`The ${pattern.name} pattern has no role ${JSON.stringify(extra.slice(0, 40))}; its roles are ${known.join(", ")}`);
28
+ const roles = {};
29
+ for (const spec of pattern.roles) {
30
+ const raw = input[spec.id], list = raw === void 0 || raw === null ? [] : Array.isArray(raw) ? raw : [raw];
31
+ if (list.length > 6) throw new CollabError(`Pick at most 6 agents for "${spec.label}"`);
32
+ const agents = [];
33
+ for (const entry of list) {
34
+ if (!isAgentId(entry)) throw new CollabError(`Pick an installed agent for "${spec.label}" (claude, codex or agy)`);
35
+ if (!installed.includes(entry)) throw new CollabError(`${entry} is not installed or not on PATH on this computer`);
36
+ if (!agents.includes(entry)) agents.push(entry);
37
+ }
38
+ const chosen = spec.multiple ? agents : agents.slice(0, 1);
39
+ if (!chosen.length && !spec.optional) throw new CollabError(`Pick an agent for "${spec.label}"`);
40
+ roles[spec.id] = chosen;
41
+ }
42
+ return roles;
43
+ }
44
+ function settings(value, label) {
45
+ if (!object(value)) throw new CollabError(`Send ${label} as { <agent>: { model?, effort? } }`);
46
+ try {
47
+ return validateAgentSettings(value);
48
+ } catch (error) {
49
+ throw new CollabError(error instanceof Error ? error.message : String(error));
50
+ }
51
+ }
52
+ function roleSettings(value) {
53
+ if (!object(value)) throw new CollabError("Send roleSettings as { <role>: { <agent>: { model?, effort? } } }");
54
+ const out = {};
55
+ for (const [role, entry] of Object.entries(value)) {
56
+ if (!/^[\w-]{1,40}$/.test(role)) throw new CollabError(`Role settings name an unknown role ${JSON.stringify(role.slice(0, 40))}`);
57
+ const valid = settings(entry, `roleSettings.${role}`);
58
+ if (Object.keys(valid).length) out[role] = valid;
59
+ }
60
+ return out;
61
+ }
62
+ function loop(value) {
63
+ if (!object(value)) throw new CollabError("Send loop as { check?, setup?, maxMinutes?, maxSteps? }");
64
+ assertKeys(value, LOOP_FIELDS, "loop");
65
+ const out = {};
66
+ const command = (key) => {
67
+ if (absent(value[key])) return;
68
+ const line = value[key];
69
+ if (typeof line !== "string" || line.length > 1e3 || /[\r\n\x00]/.test(line)) throw new CollabError(`The ${key} command must be a single line of at most 1000 characters`);
70
+ if (line.trim()) out[key] = line.trim();
71
+ };
72
+ const number = (key, min, max) => {
73
+ if (absent(value[key])) return;
74
+ const n = Number(value[key]);
75
+ if (!Number.isFinite(n)) throw new CollabError(`Send ${key} as a number between ${min} and ${max}`);
76
+ out[key] = Math.min(max, Math.max(min, Math.round(n)));
77
+ };
78
+ command("check");
79
+ command("setup");
80
+ number("maxMinutes", 1, 720);
81
+ number("maxSteps", 1, 200);
82
+ return out;
83
+ }
84
+ function validateStartBody(raw, host) {
85
+ assertKeys(raw, START_FIELDS, "start");
86
+ const pattern = typeof raw.pattern === "string" && /^[a-z0-9-]{1,40}$/.test(raw.pattern) ? host.findPattern(raw.pattern) : void 0;
87
+ if (!pattern) throw new CollabError("Unknown pattern");
88
+ const input = { pattern, roles: validateRoles(pattern, raw.roles ?? {}, host.agents()) }, repo = repoPath(raw.repo, false);
89
+ if (repo) input.repo = repo;
90
+ if (!absent(raw.trust)) {
91
+ if (typeof raw.trust !== "string" || !TRUSTS.includes(raw.trust)) throw new CollabError("Choose agent permissions: safe, standard, trusted or full");
92
+ input.trust = raw.trust;
93
+ }
94
+ if (!absent(raw.agentSettings)) input.agentSettings = settings(raw.agentSettings, "agentSettings");
95
+ if (!absent(raw.roleSettings)) input.roleSettings = roleSettings(raw.roleSettings);
96
+ if (!absent(raw.loop)) input.loop = loop(raw.loop);
97
+ if (!absent(raw.fromCheckpointId)) {
98
+ if (typeof raw.fromCheckpointId !== "string" || !CHECKPOINT_ID.test(raw.fromCheckpointId)) throw new CollabError("Send the checkpoint id as 32 lowercase hexadecimal characters");
99
+ input.fromCheckpointId = raw.fromCheckpointId;
100
+ }
101
+ return input;
102
+ }
103
+ function validateDraftBody(raw, installed) {
104
+ assertKeys(raw, ["projectId", "repository", "idea", "agent", "repo", "baseRef", "agentSettings"], "draft");
105
+ const text = (key, max, required = true) => {
106
+ const value = raw[key];
107
+ if (!required && absent(value)) return void 0;
108
+ if (typeof value !== "string" || !value.trim() || value.length > max || value.includes("\0")) throw new CollabError(`Send ${key} as text of 1\u2013${max} characters`);
109
+ return value.trim();
110
+ };
111
+ if (!isAgentId(raw.agent) || !installed.includes(raw.agent)) throw new CollabError("Choose an installed drafting agent on this computer");
112
+ return {
113
+ projectId: text("projectId", 100),
114
+ repository: text("repository", 64),
115
+ idea: text("idea", 16384),
116
+ agent: raw.agent,
117
+ repo: repoPath(raw.repo, false),
118
+ baseRef: text("baseRef", 100, false),
119
+ ...!absent(raw.agentSettings) ? { agentSettings: settings(raw.agentSettings, "agentSettings") } : {}
120
+ };
121
+ }
122
+ async function linkInfo(host) {
123
+ const state = host.link.state(), info = { ...state };
124
+ if (!state.linked && host.hubName && !info.hubName) info.hubName = host.hubName;
125
+ if (state.linked) {
126
+ try {
127
+ const me = await host.runner.hub.me();
128
+ const runner = me.runners.find((entry) => entry.id === state.runnerId);
129
+ if (runner) info.runner = runner;
130
+ else info.error ??= "The team server no longer lists this computer's runner; reconnect in Settings \u2192 Team";
131
+ } catch (error) {
132
+ info.error ??= error instanceof Error ? error.message : String(error);
133
+ }
134
+ }
135
+ return info;
136
+ }
137
+ async function dispatch(req, res, _url, parts, host) {
138
+ const method = (req.method ?? "GET").toUpperCase(), [, , head, id, action] = parts;
139
+ if (head === void 0 && parts.length === 2) {
140
+ if (method === "GET") return send(res, 200, await linkInfo(host));
141
+ if (method === "DELETE") {
142
+ await host.link.disconnect();
143
+ const state = host.link.state();
144
+ await host.onLinkChanged?.(state);
145
+ return send(res, 200, { ...state });
146
+ }
147
+ }
148
+ if (head === "connect" && parts.length === 3 && method === "POST") {
149
+ const raw = await body(req);
150
+ assertKeys(raw, ["url", "username", "password", "name"], "connect");
151
+ if (host.link.linked) throw new CollabError(`This computer is already connected to ${host.link.state().url}; disconnect it first`, 409);
152
+ const local = await host.store.board(ownerActor(host.store.ownerName));
153
+ if (local.tasks.length) throw new CollabError(`This computer's own team board holds ${local.tasks.length} task${local.tasks.length === 1 ? "" : "s"}; delete them (or keep using this computer as the team server) before connecting it to another team server`, 409);
154
+ const state = await host.link.connect({ url: raw.url, username: raw.username, password: raw.password, name: raw.name });
155
+ await host.onLinkChanged?.(state);
156
+ host.runner.reconcile().catch((error) => logError("Local attempts could not be reconciled after connecting to the team server", error));
157
+ return send(res, 201, await linkInfo(host));
158
+ }
159
+ if (head === "draft" && parts.length === 3 && method === "POST") return send(res, 201, await host.runner.draftTask(validateDraftBody(await body(req, START_BODY_LIMIT), host.agents())));
160
+ if (head === "reconcile" && parts.length === 3 && method === "POST") return send(res, 200, await host.runner.reconcile());
161
+ if (head === "mappings" && parts.length === 3 && method === "PUT") {
162
+ const raw = await body(req);
163
+ assertKeys(raw, ["projectId", "repository", "path"], "mapping");
164
+ const mappings = await host.link.setMapping(raw.projectId, raw.repository, raw.path);
165
+ return send(res, 200, { mappings });
166
+ }
167
+ if (head === "attempts" && parts.length === 3 && method === "GET") {
168
+ const attempts = await host.runner.attempts();
169
+ return send(res, 200, attempts.map((record) => {
170
+ const run = record.runId ? host.manager.get(record.runId) : void 0;
171
+ return run ? { ...record, runStatus: run.status } : record;
172
+ }));
173
+ }
174
+ if (head === "tasks" && id !== void 0 && action !== void 0 && parts.length === 5 && method === "POST") {
175
+ const taskId = validatePathId(id, "task id"), runner = host.runner;
176
+ switch (action) {
177
+ case "start": {
178
+ const input = validateStartBody(await body(req, START_BODY_LIMIT), host);
179
+ return send(res, 201, await runner.startAttempt(taskId, input));
180
+ }
181
+ case "stop": {
182
+ const record = await runner.attemptForTask(taskId, ["claimed", "running"]);
183
+ if (!record) throw new CollabError("No attempt of this task is running on this computer", 409);
184
+ return send(res, 200, await runner.stopAttempt(record.attemptId));
185
+ }
186
+ case "resume": {
187
+ const record = await runner.attemptForTask(taskId, ["paused", "stopped", "unknown"]);
188
+ if (!record) throw new CollabError("No paused attempt of this task is on this computer; start a new attempt instead", 409);
189
+ return send(res, 200, await runner.resumeAttempt(record.attemptId));
190
+ }
191
+ case "handover": {
192
+ const raw = await body(req);
193
+ assertKeys(raw, ["to", "note", "includeUncommitted"], "hand-over");
194
+ if (typeof raw.to !== "string" || !raw.to) throw new CollabError("Choose the teammate to hand over to");
195
+ if (raw.includeUncommitted !== void 0 && typeof raw.includeUncommitted !== "boolean") throw new CollabError("Send includeUncommitted as true or false");
196
+ if (raw.note !== void 0 && raw.note !== null && typeof raw.note !== "string") throw new CollabError("Enter the note as text");
197
+ return send(res, 200, await runner.handOver(taskId, { to: raw.to, note: typeof raw.note === "string" ? raw.note : "", includeUncommitted: raw.includeUncommitted === true }));
198
+ }
199
+ case "accept": {
200
+ const raw = await body(req);
201
+ assertKeys(raw, ["handoffId", "repo"], "accept");
202
+ const handoffId = validatePathId(raw.handoffId, "hand-over id"), repo = repoPath(raw.repo, false);
203
+ return send(res, 200, await runner.acceptHandoff(taskId, handoffId, repo ? { repo } : {}));
204
+ }
205
+ }
206
+ }
207
+ if (head === "checkpoints" && id !== void 0 && action === "fetch" && parts.length === 5 && method === "POST") {
208
+ const raw = await body(req);
209
+ assertKeys(raw, ["repo"], "fetch");
210
+ const repo = repoPath(raw.repo, true);
211
+ return send(res, 200, await host.runner.fetchCheckpoint(validatePathId(id, "checkpoint id"), { repo }));
212
+ }
213
+ throw new CollabError("Unknown team link operation", 404);
214
+ }
215
+ async function handleTeamLinkApi(req, res, url, parts, host) {
216
+ try {
217
+ await dispatch(req, res, url, parts, host);
218
+ } catch (error) {
219
+ if (error instanceof CollabError) return send(res, error.status, { error: error.message });
220
+ throw error;
221
+ }
222
+ }
223
+ export {
224
+ handleTeamLinkApi,
225
+ linkInfo,
226
+ validateDraftBody,
227
+ validateRoles,
228
+ validateStartBody
229
+ };