@cluesmith/codev 3.3.4 → 3.3.6

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 (290) hide show
  1. package/dashboard-dist/assets/index-BjcqV9Vv.css +32 -0
  2. package/dashboard-dist/assets/index-b7GnZV2i.js +220 -0
  3. package/dashboard-dist/assets/index-b7GnZV2i.js.map +1 -0
  4. package/dashboard-dist/index.html +2 -2
  5. package/dist/agent-farm/cli.d.ts.map +1 -1
  6. package/dist/agent-farm/cli.js +50 -17
  7. package/dist/agent-farm/cli.js.map +1 -1
  8. package/dist/agent-farm/commands/architect.d.ts.map +1 -1
  9. package/dist/agent-farm/commands/architect.js +5 -1
  10. package/dist/agent-farm/commands/architect.js.map +1 -1
  11. package/dist/agent-farm/commands/attach.d.ts +1 -1
  12. package/dist/agent-farm/commands/attach.d.ts.map +1 -1
  13. package/dist/agent-farm/commands/cleanup.d.ts +1 -1
  14. package/dist/agent-farm/commands/cleanup.d.ts.map +1 -1
  15. package/dist/agent-farm/commands/cleanup.js +2 -1
  16. package/dist/agent-farm/commands/cleanup.js.map +1 -1
  17. package/dist/agent-farm/commands/decisions.d.ts +25 -0
  18. package/dist/agent-farm/commands/decisions.d.ts.map +1 -0
  19. package/dist/agent-farm/commands/decisions.js +54 -0
  20. package/dist/agent-farm/commands/decisions.js.map +1 -0
  21. package/dist/agent-farm/commands/ide.d.ts +32 -3
  22. package/dist/agent-farm/commands/ide.d.ts.map +1 -1
  23. package/dist/agent-farm/commands/ide.js +180 -19
  24. package/dist/agent-farm/commands/ide.js.map +1 -1
  25. package/dist/agent-farm/commands/reset/context.d.ts +4 -2
  26. package/dist/agent-farm/commands/reset/context.d.ts.map +1 -1
  27. package/dist/agent-farm/commands/reset/context.js +12 -4
  28. package/dist/agent-farm/commands/reset/context.js.map +1 -1
  29. package/dist/agent-farm/commands/send.d.ts +3 -2
  30. package/dist/agent-farm/commands/send.d.ts.map +1 -1
  31. package/dist/agent-farm/commands/send.js +35 -21
  32. package/dist/agent-farm/commands/send.js.map +1 -1
  33. package/dist/agent-farm/commands/spawn-worktree.d.ts +7 -0
  34. package/dist/agent-farm/commands/spawn-worktree.d.ts.map +1 -1
  35. package/dist/agent-farm/commands/spawn-worktree.js +63 -20
  36. package/dist/agent-farm/commands/spawn-worktree.js.map +1 -1
  37. package/dist/agent-farm/commands/spawn.d.ts +17 -0
  38. package/dist/agent-farm/commands/spawn.d.ts.map +1 -1
  39. package/dist/agent-farm/commands/spawn.js +41 -19
  40. package/dist/agent-farm/commands/spawn.js.map +1 -1
  41. package/dist/agent-farm/lib/builder-lookup.d.ts +3 -2
  42. package/dist/agent-farm/lib/builder-lookup.d.ts.map +1 -1
  43. package/dist/agent-farm/lib/builder-lookup.js +24 -9
  44. package/dist/agent-farm/lib/builder-lookup.js.map +1 -1
  45. package/dist/agent-farm/lib/ide-extensions.d.ts +82 -0
  46. package/dist/agent-farm/lib/ide-extensions.d.ts.map +1 -0
  47. package/dist/agent-farm/lib/ide-extensions.js +179 -0
  48. package/dist/agent-farm/lib/ide-extensions.js.map +1 -0
  49. package/dist/agent-farm/lib/ide-record.d.ts +6 -1
  50. package/dist/agent-farm/lib/ide-record.d.ts.map +1 -1
  51. package/dist/agent-farm/lib/ide-record.js +8 -1
  52. package/dist/agent-farm/lib/ide-record.js.map +1 -1
  53. package/dist/agent-farm/lib/ide-version.d.ts +97 -0
  54. package/dist/agent-farm/lib/ide-version.d.ts.map +1 -0
  55. package/dist/agent-farm/lib/ide-version.js +224 -0
  56. package/dist/agent-farm/lib/ide-version.js.map +1 -0
  57. package/dist/agent-farm/lib/tunnel-client.d.ts.map +1 -1
  58. package/dist/agent-farm/lib/tunnel-client.js +7 -3
  59. package/dist/agent-farm/lib/tunnel-client.js.map +1 -1
  60. package/dist/agent-farm/servers/agent-state/broadcast.d.ts +19 -0
  61. package/dist/agent-farm/servers/agent-state/broadcast.d.ts.map +1 -0
  62. package/dist/agent-farm/servers/agent-state/broadcast.js +30 -0
  63. package/dist/agent-farm/servers/agent-state/broadcast.js.map +1 -0
  64. package/dist/agent-farm/servers/agent-state/identity.d.ts +50 -0
  65. package/dist/agent-farm/servers/agent-state/identity.d.ts.map +1 -0
  66. package/dist/agent-farm/servers/agent-state/identity.js +120 -0
  67. package/dist/agent-farm/servers/agent-state/identity.js.map +1 -0
  68. package/dist/agent-farm/servers/agent-state/liveness.d.ts +107 -0
  69. package/dist/agent-farm/servers/agent-state/liveness.d.ts.map +1 -0
  70. package/dist/agent-farm/servers/agent-state/liveness.js +224 -0
  71. package/dist/agent-farm/servers/agent-state/liveness.js.map +1 -0
  72. package/dist/agent-farm/servers/agent-state/route.d.ts +38 -0
  73. package/dist/agent-farm/servers/agent-state/route.d.ts.map +1 -0
  74. package/dist/agent-farm/servers/agent-state/route.js +170 -0
  75. package/dist/agent-farm/servers/agent-state/route.js.map +1 -0
  76. package/dist/agent-farm/servers/agent-state/serve.d.ts +31 -0
  77. package/dist/agent-farm/servers/agent-state/serve.d.ts.map +1 -0
  78. package/dist/agent-farm/servers/agent-state/serve.js +49 -0
  79. package/dist/agent-farm/servers/agent-state/serve.js.map +1 -0
  80. package/dist/agent-farm/servers/agent-state/store.d.ts +76 -0
  81. package/dist/agent-farm/servers/agent-state/store.d.ts.map +1 -0
  82. package/dist/agent-farm/servers/agent-state/store.js +157 -0
  83. package/dist/agent-farm/servers/agent-state/store.js.map +1 -0
  84. package/dist/agent-farm/servers/decisions/file.d.ts +50 -0
  85. package/dist/agent-farm/servers/decisions/file.d.ts.map +1 -0
  86. package/dist/agent-farm/servers/decisions/file.js +146 -0
  87. package/dist/agent-farm/servers/decisions/file.js.map +1 -0
  88. package/dist/agent-farm/servers/decisions/grammar.d.ts +36 -0
  89. package/dist/agent-farm/servers/decisions/grammar.d.ts.map +1 -0
  90. package/dist/agent-farm/servers/decisions/grammar.js +109 -0
  91. package/dist/agent-farm/servers/decisions/grammar.js.map +1 -0
  92. package/dist/agent-farm/servers/decisions/notice.d.ts +11 -0
  93. package/dist/agent-farm/servers/decisions/notice.d.ts.map +1 -0
  94. package/dist/agent-farm/servers/decisions/notice.js +18 -0
  95. package/dist/agent-farm/servers/decisions/notice.js.map +1 -0
  96. package/dist/agent-farm/servers/decisions/parse.d.ts +36 -0
  97. package/dist/agent-farm/servers/decisions/parse.d.ts.map +1 -0
  98. package/dist/agent-farm/servers/decisions/parse.js +338 -0
  99. package/dist/agent-farm/servers/decisions/parse.js.map +1 -0
  100. package/dist/agent-farm/servers/decisions/routes.d.ts +17 -0
  101. package/dist/agent-farm/servers/decisions/routes.d.ts.map +1 -0
  102. package/dist/agent-farm/servers/decisions/routes.js +160 -0
  103. package/dist/agent-farm/servers/decisions/routes.js.map +1 -0
  104. package/dist/agent-farm/servers/decisions/splice.d.ts +26 -0
  105. package/dist/agent-farm/servers/decisions/splice.d.ts.map +1 -0
  106. package/dist/agent-farm/servers/decisions/splice.js +120 -0
  107. package/dist/agent-farm/servers/decisions/splice.js.map +1 -0
  108. package/dist/agent-farm/servers/decisions/stamp.d.ts +8 -0
  109. package/dist/agent-farm/servers/decisions/stamp.d.ts.map +1 -0
  110. package/dist/agent-farm/servers/decisions/stamp.js +195 -0
  111. package/dist/agent-farm/servers/decisions/stamp.js.map +1 -0
  112. package/dist/agent-farm/servers/decisions/template.d.ts +2 -0
  113. package/dist/agent-farm/servers/decisions/template.d.ts.map +1 -0
  114. package/dist/agent-farm/servers/decisions/template.js +15 -0
  115. package/dist/agent-farm/servers/decisions/template.js.map +1 -0
  116. package/dist/agent-farm/servers/ide-server.d.ts +28 -8
  117. package/dist/agent-farm/servers/ide-server.d.ts.map +1 -1
  118. package/dist/agent-farm/servers/ide-server.js +147 -50
  119. package/dist/agent-farm/servers/ide-server.js.map +1 -1
  120. package/dist/agent-farm/servers/overview.d.ts +31 -4
  121. package/dist/agent-farm/servers/overview.d.ts.map +1 -1
  122. package/dist/agent-farm/servers/overview.js +235 -55
  123. package/dist/agent-farm/servers/overview.js.map +1 -1
  124. package/dist/agent-farm/servers/tower-instances.d.ts +14 -1
  125. package/dist/agent-farm/servers/tower-instances.d.ts.map +1 -1
  126. package/dist/agent-farm/servers/tower-instances.js +51 -9
  127. package/dist/agent-farm/servers/tower-instances.js.map +1 -1
  128. package/dist/agent-farm/servers/tower-routes.d.ts.map +1 -1
  129. package/dist/agent-farm/servers/tower-routes.js +113 -14
  130. package/dist/agent-farm/servers/tower-routes.js.map +1 -1
  131. package/dist/agent-farm/servers/tower-server.js +35 -1
  132. package/dist/agent-farm/servers/tower-server.js.map +1 -1
  133. package/dist/agent-farm/servers/tower-terminals.d.ts +25 -0
  134. package/dist/agent-farm/servers/tower-terminals.d.ts.map +1 -1
  135. package/dist/agent-farm/servers/tower-terminals.js +128 -4
  136. package/dist/agent-farm/servers/tower-terminals.js.map +1 -1
  137. package/dist/agent-farm/servers/tower-utils.d.ts.map +1 -1
  138. package/dist/agent-farm/servers/tower-utils.js +18 -5
  139. package/dist/agent-farm/servers/tower-utils.js.map +1 -1
  140. package/dist/agent-farm/utils/builder-worktree-identity.d.ts +39 -0
  141. package/dist/agent-farm/utils/builder-worktree-identity.d.ts.map +1 -0
  142. package/dist/agent-farm/utils/builder-worktree-identity.js +42 -0
  143. package/dist/agent-farm/utils/builder-worktree-identity.js.map +1 -0
  144. package/dist/agent-farm/utils/harness.d.ts +71 -0
  145. package/dist/agent-farm/utils/harness.d.ts.map +1 -1
  146. package/dist/agent-farm/utils/harness.js +153 -0
  147. package/dist/agent-farm/utils/harness.js.map +1 -1
  148. package/dist/agent-farm/utils/lifecycle-reporter.d.ts +79 -0
  149. package/dist/agent-farm/utils/lifecycle-reporter.d.ts.map +1 -0
  150. package/dist/agent-farm/utils/lifecycle-reporter.js +347 -0
  151. package/dist/agent-farm/utils/lifecycle-reporter.js.map +1 -0
  152. package/dist/agent-farm/utils/message-format.d.ts +8 -0
  153. package/dist/agent-farm/utils/message-format.d.ts.map +1 -1
  154. package/dist/agent-farm/utils/message-format.js +16 -0
  155. package/dist/agent-farm/utils/message-format.js.map +1 -1
  156. package/dist/cli.d.ts.map +1 -1
  157. package/dist/cli.js +17 -0
  158. package/dist/cli.js.map +1 -1
  159. package/dist/commands/adopt.d.ts +16 -2
  160. package/dist/commands/adopt.d.ts.map +1 -1
  161. package/dist/commands/adopt.js +67 -23
  162. package/dist/commands/adopt.js.map +1 -1
  163. package/dist/commands/bootstrap-docs.d.ts +132 -0
  164. package/dist/commands/bootstrap-docs.d.ts.map +1 -0
  165. package/dist/commands/bootstrap-docs.js +725 -0
  166. package/dist/commands/bootstrap-docs.js.map +1 -0
  167. package/dist/commands/consult/index.d.ts +20 -1
  168. package/dist/commands/consult/index.d.ts.map +1 -1
  169. package/dist/commands/consult/index.js +70 -3
  170. package/dist/commands/consult/index.js.map +1 -1
  171. package/dist/commands/consult/tree-tripwire.d.ts +2 -75
  172. package/dist/commands/consult/tree-tripwire.d.ts.map +1 -1
  173. package/dist/commands/consult/tree-tripwire.js +7 -184
  174. package/dist/commands/consult/tree-tripwire.js.map +1 -1
  175. package/dist/commands/doctor.d.ts.map +1 -1
  176. package/dist/commands/doctor.js +36 -4
  177. package/dist/commands/doctor.js.map +1 -1
  178. package/dist/commands/porch/checks.d.ts +7 -1
  179. package/dist/commands/porch/checks.d.ts.map +1 -1
  180. package/dist/commands/porch/checks.js +77 -14
  181. package/dist/commands/porch/checks.js.map +1 -1
  182. package/dist/commands/porch/index.d.ts +38 -1
  183. package/dist/commands/porch/index.d.ts.map +1 -1
  184. package/dist/commands/porch/index.js +79 -43
  185. package/dist/commands/porch/index.js.map +1 -1
  186. package/dist/commands/porch/protocol.d.ts +4 -3
  187. package/dist/commands/porch/protocol.d.ts.map +1 -1
  188. package/dist/commands/porch/protocol.js +32 -5
  189. package/dist/commands/porch/protocol.js.map +1 -1
  190. package/dist/commands/porch/state.d.ts +0 -4
  191. package/dist/commands/porch/state.d.ts.map +1 -1
  192. package/dist/commands/porch/state.js +23 -10
  193. package/dist/commands/porch/state.js.map +1 -1
  194. package/dist/commands/porch/types.d.ts +2 -0
  195. package/dist/commands/porch/types.d.ts.map +1 -1
  196. package/dist/commands/update.d.ts +5 -1
  197. package/dist/commands/update.d.ts.map +1 -1
  198. package/dist/commands/update.js +73 -18
  199. package/dist/commands/update.js.map +1 -1
  200. package/dist/lib/agent-env.d.ts +31 -1
  201. package/dist/lib/agent-env.d.ts.map +1 -1
  202. package/dist/lib/agent-env.js +38 -1
  203. package/dist/lib/agent-env.js.map +1 -1
  204. package/dist/lib/agent-process.d.ts +23 -0
  205. package/dist/lib/agent-process.d.ts.map +1 -0
  206. package/dist/lib/agent-process.js +24 -0
  207. package/dist/lib/agent-process.js.map +1 -0
  208. package/dist/lib/config.d.ts +8 -0
  209. package/dist/lib/config.d.ts.map +1 -1
  210. package/dist/lib/config.js.map +1 -1
  211. package/dist/lib/forge-contracts.d.ts +9 -3
  212. package/dist/lib/forge-contracts.d.ts.map +1 -1
  213. package/dist/lib/forge-contracts.js.map +1 -1
  214. package/dist/lib/forge.d.ts +8 -5
  215. package/dist/lib/forge.d.ts.map +1 -1
  216. package/dist/lib/forge.js +57 -1
  217. package/dist/lib/forge.js.map +1 -1
  218. package/dist/lib/github.d.ts.map +1 -1
  219. package/dist/lib/github.js +38 -0
  220. package/dist/lib/github.js.map +1 -1
  221. package/dist/lib/governance-bootstrap.d.ts +155 -0
  222. package/dist/lib/governance-bootstrap.d.ts.map +1 -0
  223. package/dist/lib/governance-bootstrap.js +469 -0
  224. package/dist/lib/governance-bootstrap.js.map +1 -0
  225. package/dist/lib/issue-id.d.ts +34 -0
  226. package/dist/lib/issue-id.d.ts.map +1 -0
  227. package/dist/lib/issue-id.js +61 -0
  228. package/dist/lib/issue-id.js.map +1 -0
  229. package/dist/lib/scaffold.d.ts +4 -0
  230. package/dist/lib/scaffold.d.ts.map +1 -1
  231. package/dist/lib/scaffold.js +29 -5
  232. package/dist/lib/scaffold.js.map +1 -1
  233. package/dist/lib/shipped-skill-hashes.d.ts +10 -0
  234. package/dist/lib/shipped-skill-hashes.d.ts.map +1 -0
  235. package/dist/lib/shipped-skill-hashes.js +197 -0
  236. package/dist/lib/shipped-skill-hashes.js.map +1 -0
  237. package/dist/lib/skill-refresh.d.ts +90 -0
  238. package/dist/lib/skill-refresh.d.ts.map +1 -0
  239. package/dist/lib/skill-refresh.js +267 -0
  240. package/dist/lib/skill-refresh.js.map +1 -0
  241. package/dist/lib/tree-snapshot.d.ts +172 -0
  242. package/dist/lib/tree-snapshot.d.ts.map +1 -0
  243. package/dist/lib/tree-snapshot.js +393 -0
  244. package/dist/lib/tree-snapshot.js.map +1 -0
  245. package/dist/terminal/pty-session.d.ts +5 -0
  246. package/dist/terminal/pty-session.d.ts.map +1 -1
  247. package/dist/terminal/pty-session.js +7 -0
  248. package/dist/terminal/pty-session.js.map +1 -1
  249. package/ide-extension/codev-vscode.vsix +0 -0
  250. package/ide-extension/manifest.json +7 -0
  251. package/package.json +8 -6
  252. package/scripts/forge/jira/_lib.sh +113 -0
  253. package/scripts/forge/jira/auth-status.sh +29 -0
  254. package/scripts/forge/jira/issue-comment.sh +23 -0
  255. package/scripts/forge/jira/issue-list.sh +32 -0
  256. package/scripts/forge/jira/issue-search.sh +40 -0
  257. package/scripts/forge/jira/issue-view.sh +41 -0
  258. package/scripts/forge/jira/recently-closed.sh +81 -0
  259. package/scripts/forge/jira/user-identity.sh +18 -0
  260. package/skeleton/.claude/skills/afx/SKILL.md +51 -0
  261. package/skeleton/.claude/skills/arch-init/SKILL.md +56 -9
  262. package/skeleton/.claude/skills/arch-save/SKILL.md +100 -9
  263. package/skeleton/.claude/skills/codev/SKILL.md +18 -2
  264. package/skeleton/.claude/skills/consult/SKILL.md +9 -0
  265. package/skeleton/.claude/skills/porch/SKILL.md +18 -0
  266. package/skeleton/.claude/skills/update-arch-docs/SKILL.md +28 -2
  267. package/skeleton/.codex/skills/afx/SKILL.md +51 -0
  268. package/skeleton/.codex/skills/arch-init/SKILL.md +56 -9
  269. package/skeleton/.codex/skills/arch-save/SKILL.md +100 -9
  270. package/skeleton/.codex/skills/codev/SKILL.md +18 -2
  271. package/skeleton/.codex/skills/consult/SKILL.md +9 -0
  272. package/skeleton/.codex/skills/porch/SKILL.md +18 -0
  273. package/skeleton/.codex/skills/update-arch-docs/SKILL.md +28 -2
  274. package/skeleton/protocol-schema.json +6 -0
  275. package/skeleton/protocols/maintain/protocol.md +5 -0
  276. package/skeleton/protocols/pir/prompts/review.md +0 -1
  277. package/skeleton/protocols/protocol-schema.json +6 -0
  278. package/skeleton/resources/commands/agent-farm.md +156 -0
  279. package/skeleton/resources/commands/codev.md +47 -0
  280. package/skeleton/resources/commands/consult.md +9 -2
  281. package/skeleton/resources/commands/overview.md +1 -0
  282. package/skeleton/resources/decision-protocol.md +215 -0
  283. package/skeleton/resources/workflow-reference.md +12 -0
  284. package/skeleton/roles/architect.md +6 -0
  285. package/skeleton/templates/bootstrap-docs-prompt.md +16 -0
  286. package/skeleton/templates/bootstrap-docs-review-prompt.md +19 -0
  287. package/skeleton/templates/cheatsheet.md +2 -1
  288. package/dashboard-dist/assets/index-DZf6pNPE.js +0 -199
  289. package/dashboard-dist/assets/index-DZf6pNPE.js.map +0 -1
  290. package/dashboard-dist/assets/index-DnYLy5C_.css +0 -32
@@ -21,24 +21,27 @@ import { decodeWorkspacePath } from '../lib/tower-client.js';
21
21
  import { readCloudConfig } from '../lib/cloud-config.js';
22
22
  import { fileURLToPath } from 'node:url';
23
23
  import { version } from '../../version.js';
24
- import { sanitizeAgentEnv } from '../../lib/agent-env.js';
24
+ import { sanitizeAgentEnv, withTowerPort } from '../../lib/agent-env.js';
25
25
  const execAsync = promisify(exec);
26
- import { getBuilders, setArchitectByName } from '../state.js';
26
+ import { getArchitectByName, getBuilders, setArchitectByName } from '../state.js';
27
+ import { DEFAULT_ARCHITECT_NAME } from '../utils/architect-name.js';
27
28
  import { DEFAULT_COLS, defaultSessionOptions } from '../../terminal/index.js';
28
29
  import { parseJsonBody, isRequestAllowed, isAllowedOrigin, isAllowedHost, getExpectedKey, escapeHtml } from '../utils/server-utils.js';
29
- import { TOWER_KEY_HEADER, LEGACY_WEB_KEY_HEADER, VSCODE_USER_SENDER } from '@cluesmith/codev-types';
30
+ import { TOWER_KEY_HEADER, LEGACY_WEB_KEY_HEADER, VSCODE_USER_SENDER, DECISIONS_TAB_SENDER } from '@cluesmith/codev-types';
30
31
  import { isRateLimited, normalizeWorkspacePath, getLanguageForExt, getMimeTypeForFile, serveStaticFile, persistableCommand, logSessionIdentity, } from './tower-utils.js';
31
32
  import { handleTunnelEndpoint } from './tower-tunnel.js';
32
33
  import { handleIdeApi } from './ide-server.js';
33
34
  import { matchIdePrefix, forwardIdeHttp } from './ide-forward.js';
34
35
  import { getWorktreeConfig, getActivityHooks } from '../utils/config.js';
35
36
  import { ensureCodevConfigWatcher } from './codev-config-watcher.js';
37
+ import { handleDecisionsGet, handleDecisionsRule } from './decisions/routes.js';
38
+ import { decisionsFilePresent } from './decisions/file.js';
36
39
  import { hasTeam, loadTeamMembers, loadMessages } from '../../lib/team.js';
37
40
  import { fetchTeamGitHubData } from '../../lib/team-github.js';
38
41
  import { resolveTarget, resolveAgentInRegistry, broadcastMessage, isResolveError } from './tower-messages.js';
39
42
  import { handleCommandRoute, COMMAND_ROUTE } from './command-relay.js';
40
43
  import { handleCanvasRoute, CANVAS_ROUTE_PREFIX } from './canvas-relay.js';
41
- import { formatArchitectMessage, formatArchitectToBuilderMessage, formatBuilderMessage, formatUserViaVsCodeMessage, isSafeSenderId, messageTooLargeError, MAX_MESSAGE_BYTES, } from '../utils/message-format.js';
44
+ import { formatArchitectMessage, formatArchitectToBuilderMessage, formatBuilderMessage, formatUserViaVsCodeMessage, formatUserViaDecisionsTabMessage, isSafeSenderId, messageLimitError, messageTooLargeError, MAX_MESSAGE_BYTES, } from '../utils/message-format.js';
42
45
  import { writeMessageToSession, writeEscapeToSession, writeStrategyForApp } from './message-write.js';
43
46
  import { makeDeliveryPorts, getMailboxDrainer, resolveProfileForSession } from './mailbox-wiring.js';
44
47
  import { deliverAgentMailSerialized } from './mailbox-delivery.js';
@@ -56,8 +59,12 @@ import { submitToSession, OPERATOR_SUBMIT_WAIT_CEILING_MS } from './session-subm
56
59
  // triggers a gated drain (see handleSend), so a delayed message delivers onto a
57
60
  // render-verified empty prompt like any normal send — never force-injected.
58
61
  import { scheduleDelayedSend, validateDelaySeconds } from './delayed-send.js';
59
- import { getKnownWorkspacePaths, getInstances, getDirectorySuggestions, launchInstance, killTerminalWithShellper, instancesReady, stopInstance, addArchitect, removeArchitect, } from './tower-instances.js';
62
+ import { getKnownWorkspacePaths, getAllKnownWorkspacePaths, getInstances, getDirectorySuggestions, launchInstance, killTerminalWithShellper, instancesReady, stopInstance, addArchitect, removeArchitect, } from './tower-instances.js';
60
63
  import { OverviewCache } from './overview.js';
64
+ import { handleAgentLifecycle } from './agent-state/route.js';
65
+ import { agentStateStore } from './agent-state/store.js';
66
+ import { resolveAgentIdentity } from './agent-state/identity.js';
67
+ import { serveAgentState } from './agent-state/serve.js';
61
68
  import { fetchIssue, fetchPR, searchIssues, fetchPRList, fetchCurrentUser, probeGhGraphqlRateLimit, parseLinkedIssue, parseArea, } from '../../lib/github.js';
62
69
  import { computeAnalytics } from './analytics.js';
63
70
  import { getAllTasks, executeTask, getTaskId } from './tower-cron.js';
@@ -90,6 +97,11 @@ const ROUTES = {
90
97
  'POST /api/overview/refresh': (_req, res, _url, ctx) => handleOverviewRefresh(res, ctx),
91
98
  'GET /api/events': (req, res, _url, ctx) => handleSSEEvents(req, res, ctx),
92
99
  'POST /api/notify': (req, res, _url, ctx) => handleNotify(req, res, ctx),
100
+ // Spec 1595: write-only lifecycle ingestion; key-authenticated like every non-public route.
101
+ 'POST /api/agent-lifecycle': (req, res) => handleAgentLifecycle(req, res, {
102
+ store: agentStateStore,
103
+ resolve: identity => resolveAgentIdentity(identity),
104
+ }),
93
105
  'GET /api/browse': (_req, res, url) => handleBrowse(res, url),
94
106
  'POST /api/create': (req, res, _url, ctx) => handleCreateWorkspace(req, res, ctx),
95
107
  'POST /api/launch': (req, res) => handleLaunchInstance(req, res),
@@ -240,6 +252,10 @@ export async function handleRequest(req, res, ctx) {
240
252
  }
241
253
  catch (err) {
242
254
  ctx.log('ERROR', `Request error: ${err.message}`);
255
+ // A handler may fail after it has answered (the Decisions route keeps working past its
256
+ // `res.end()`); a second writeHead would throw ERR_HTTP_HEADERS_SENT out of here.
257
+ if (res.headersSent)
258
+ return;
243
259
  res.writeHead(500, { 'Content-Type': 'application/json' });
244
260
  res.end(JSON.stringify({ error: err.message }));
245
261
  }
@@ -576,7 +592,9 @@ async function handleWorkspaceAction(req, res, ctx, match) {
576
592
  }
577
593
  // POST /api/workspaces/:path/deactivate
578
594
  if (req.method === 'POST' && action === 'deactivate') {
579
- const knownPaths = getKnownWorkspacePaths();
595
+ // Unfiltered on purpose (#1809): a stray architect left running in a builder
596
+ // worktree is excluded from the listing but must still be stoppable.
597
+ const knownPaths = getAllKnownWorkspacePaths();
580
598
  const resolvedPath = fs.existsSync(workspacePath) ? fs.realpathSync(workspacePath) : workspacePath;
581
599
  const isKnown = knownPaths.some((p) => p === workspacePath || p === resolvedPath);
582
600
  if (!isKnown) {
@@ -629,8 +647,9 @@ async function handleTerminalCreate(req, res, ctx) {
629
647
  // Strip Claude Code session markers so spawned Claude processes don't
630
648
  // detect nesting and disable transcript saving (#1219). `env` is normally
631
649
  // absent — `createPtySession` sends no env — so this is the path by which
632
- // Tower's own environment becomes every builder's environment.
633
- const sessionEnv = sanitizeAgentEnv(env || process.env);
650
+ // Tower's own environment becomes every builder's environment. Spec 1595:
651
+ // Tower's port is set last, so an inherited value never survives.
652
+ const sessionEnv = withTowerPort(sanitizeAgentEnv(env || process.env), ctx.port);
634
653
  const client = await shellperManager.createSession({
635
654
  sessionId,
636
655
  command,
@@ -685,7 +704,10 @@ async function handleTerminalCreate(req, res, ctx) {
685
704
  // Fallback: non-persistent session (graceful degradation per plan)
686
705
  // Shellper is the only persistence backend for new sessions.
687
706
  if (!info) {
688
- info = await manager.createSession({ command, args, cols, rows, cwd, env: env && sanitizeAgentEnv(env), label });
707
+ // Spec 1595: the manager merges this over its own base env, so Tower's port
708
+ // reaches the session whether or not the client supplied an env.
709
+ const sessionEnv = withTowerPort(sanitizeAgentEnv(env ?? {}), ctx.port);
710
+ info = await manager.createSession({ command, args, cols, rows, cwd, env: sessionEnv, label });
689
711
  persistent = false;
690
712
  if (workspacePath && termType && roleId) {
691
713
  const entry = getWorkspaceTerminalsEntry(normalizeWorkspacePath(workspacePath));
@@ -916,19 +938,29 @@ async function handleStatus(res) {
916
938
  * dashboard-state handler (`/api/state`) and the overview handler
917
939
  * (`/api/overview`), so the two payloads list an identical set and can't drift.
918
940
  * Extracted verbatim from the dashboard-state builder's former inline loop.
941
+ *
942
+ * Spec 1595: each architect also carries its served `agentState` (read by
943
+ * `(workspace, name)` from the agent-state store and liveness, projected per
944
+ * request) and its session's `lastDataAt`, for the sdk's staleness rule.
919
945
  */
920
- function liveArchitects(entry, manager) {
946
+ function liveArchitects(entry, manager, workspacePath) {
947
+ const agentWorkspace = normalizeWorkspacePath(workspacePath);
921
948
  const architects = [];
922
949
  for (const [architectName, terminalId] of entry.architects) {
923
950
  const session = manager.getSession(terminalId);
924
951
  if (!session)
925
952
  continue;
953
+ let lastDataAt = null;
954
+ if (Number.isFinite(session.lastDataAt))
955
+ lastDataAt = new Date(session.lastDataAt).toISOString();
926
956
  architects.push({
927
957
  name: architectName,
928
958
  port: 0,
929
959
  pid: session.pid || 0,
930
960
  terminalId,
931
961
  persistent: isSessionPersistent(terminalId, session),
962
+ agentState: serveAgentState(agentWorkspace, architectName, { blocked: false, blockedSince: null, phase: '' }),
963
+ lastDataAt,
932
964
  });
933
965
  }
934
966
  const mainIdx = architects.findIndex(a => a.name === 'main');
@@ -987,11 +1019,27 @@ async function handleOverview(res, url, workspaceOverride, ctx) {
987
1019
  }
988
1020
  builder.lastDataAt = new Date(ptySession.lastDataAt).toISOString();
989
1021
  }
1022
+ // Spec 1595: project the served agent state over EVERY listed builder, not
1023
+ // inside the loop above, which skips a builder whose session is gone (the
1024
+ // case liveness reports as dead). Every listed builder is registered: the
1025
+ // list is filtered to `entry.builders`, and its `roleId` is the lowercased
1026
+ // registry key, the same key the store and liveness use. `blocked` reuses the
1027
+ // gate the overview already detected (no second parse of status.yaml).
1028
+ const agentWorkspace = normalizeWorkspacePath(workspaceRoot);
1029
+ for (const builder of data.builders) {
1030
+ if (builder.roleId === null)
1031
+ continue;
1032
+ builder.agentState = serveAgentState(agentWorkspace, builder.roleId, {
1033
+ blocked: builder.blocked !== null,
1034
+ blockedSince: builder.blockedSince,
1035
+ phase: builder.phase,
1036
+ });
1037
+ }
990
1038
  // Issue 1104: enrich with the live architects (main-first) so the VSCode
991
1039
  // Agents tree can render its architect tier and attribution badge straight
992
1040
  // off the overview cache. Same `liveArchitects` helper (and so the same set)
993
1041
  // the dashboard-state handler uses.
994
- data.architects = liveArchitects(entry, terminalManager);
1042
+ data.architects = liveArchitects(entry, terminalManager, workspaceRoot);
995
1043
  res.writeHead(200, { 'Content-Type': 'application/json' });
996
1044
  res.end(JSON.stringify(data));
997
1045
  }
@@ -1332,6 +1380,9 @@ function formatMessageForTarget(isArchitectTarget, from, toAgent, message, raw)
1332
1380
  // header, so the architect can tell it from a peer-architect instruction.
1333
1381
  if (isArchitectTarget && from === VSCODE_USER_SENDER)
1334
1382
  return formatUserViaVsCodeMessage(toAgent, message, undefined, raw);
1383
+ // #1828: likewise the owner's ruling relayed by the Decisions tab — never a builder frame.
1384
+ if (isArchitectTarget && from === DECISIONS_TAB_SENDER)
1385
+ return formatUserViaDecisionsTabMessage(toAgent, message, raw);
1335
1386
  if (isArchitectTarget && from)
1336
1387
  return formatBuilderMessage(from, toAgent, message, undefined, raw); // builder → architect
1337
1388
  // any → builder: thread the sender so an `architect:<name>` origin is named in the
@@ -1397,6 +1448,45 @@ export async function deliverCronMessage(task, message, log) {
1397
1448
  log('WARN', `Cron '${task.name}': target '${task.target}' not found — message not delivered`);
1398
1449
  return { outcome: 'unresolved', reason: null, detail: null, mailboxId: null };
1399
1450
  }
1451
+ /**
1452
+ * Tell a workspace's hub architect about a ruling the owner just wrote from the
1453
+ * Decisions tab (#1828). The hub is the architect registered as `main` and no other:
1454
+ * the registry's "first registered" order is by name (#1633), so a workspace without
1455
+ * `main` gets no notice rather than a guess, and a `main` that is offline holds it
1456
+ * (`no-live-pty`). One mailbox row is persisted, then offered to the same gated delivery
1457
+ * `handleSend` uses; a busy line holds it for the backstop. Throws, persisting nothing,
1458
+ * when `main` is not registered or the notice is over the send limit.
1459
+ */
1460
+ async function notifyHubOfRuling(workspacePath, message, log) {
1461
+ const tooLarge = messageLimitError(message);
1462
+ if (tooLarge)
1463
+ throw new Error(tooLarge);
1464
+ const toAgent = DEFAULT_ARCHITECT_NAME;
1465
+ if (!getArchitectByName(workspacePath, toAgent)) {
1466
+ throw new Error(`no architect named '${toAgent}' is registered in workspace ${workspacePath}`);
1467
+ }
1468
+ const db = getGlobalDb();
1469
+ const row = enqueueMailbox(db, {
1470
+ workspacePath,
1471
+ toAgent,
1472
+ body: message,
1473
+ formattedMessage: formatMessageForTarget(true, DECISIONS_TAB_SENDER, toAgent, message, false),
1474
+ fromAgent: DECISIONS_TAB_SENDER,
1475
+ fromWorkspace: workspacePath,
1476
+ });
1477
+ const ports = makeDeliveryPorts(log);
1478
+ ports.onHeldStateChange();
1479
+ try {
1480
+ const outcome = await deliverAgentMailSerialized(ports, db, workspacePath, toAgent);
1481
+ getMailboxDrainer().noteOutcome(workspacePath, toAgent, outcome);
1482
+ }
1483
+ catch (err) {
1484
+ log('ERROR', `Decisions notice delivery errored for ${toAgent} (row ${row.id.slice(0, 8)}... stays held): ${err.message}`);
1485
+ }
1486
+ const stored = getMailboxById(db, row.id);
1487
+ const fate = stored?.status === 'delivered' ? 'delivered' : `held (${stored?.reason ?? 'unknown'})`;
1488
+ log('INFO', `Decisions notice ${fate} → ${toAgent} @ ${path.basename(workspacePath)} (mailbox ${row.id.slice(0, 8)}...)`);
1489
+ }
1400
1490
  /**
1401
1491
  * Persist a `held` mailbox row and write the Spec 1313 `held` send response. Used
1402
1492
  * for both dead-session cases (no live PTY, held `no-live-pty`). The row exists
@@ -2397,7 +2487,7 @@ async function handleWorkspaceRoutes(req, res, ctx, url) {
2397
2487
  const apiPath = subPath.replace(/^api\/?/, '');
2398
2488
  // GET /api/state - Return workspace state (architect, builders, shells)
2399
2489
  if (req.method === 'GET' && (apiPath === 'state' || apiPath === '')) {
2400
- return handleWorkspaceState(res, workspacePath);
2490
+ return handleWorkspaceState(res, ctx, workspacePath);
2401
2491
  }
2402
2492
  // POST /api/tabs/shell - Create a new shell terminal
2403
2493
  if (req.method === 'POST' && apiPath === 'tabs/shell') {
@@ -2477,6 +2567,14 @@ async function handleWorkspaceRoutes(req, res, ctx, url) {
2477
2567
  if (req.method === 'GET' && apiPath === 'team') {
2478
2568
  return handleWorkspaceTeam(res, workspacePath);
2479
2569
  }
2570
+ // GET /api/decisions, POST /api/decisions/rule — the Decisions tab (Spec 1819).
2571
+ // The file is the configured one; neither route takes a path from the request.
2572
+ if (req.method === 'GET' && apiPath === 'decisions') {
2573
+ return handleDecisionsGet(res, workspacePath);
2574
+ }
2575
+ if (req.method === 'POST' && apiPath === 'decisions/rule') {
2576
+ return handleDecisionsRule(req, res, workspacePath, ctx.log, message => notifyHubOfRuling(workspacePath, message, ctx.log));
2577
+ }
2480
2578
  // GET /api/annotate/:tabId/* — Serve rich annotator template and sub-APIs
2481
2579
  const annotateMatch = apiPath.match(/^annotate\/([^/]+)(\/(.*))?$/);
2482
2580
  if (annotateMatch) {
@@ -2587,7 +2685,7 @@ async function handleWorkspaceRoutes(req, res, ctx, url) {
2587
2685
  // ============================================================================
2588
2686
  // Workspace API sub-handlers
2589
2687
  // ============================================================================
2590
- async function handleWorkspaceState(res, workspacePath) {
2688
+ async function handleWorkspaceState(res, ctx, workspacePath) {
2591
2689
  // Rehydrate wsTerminals (SQLite sync + shellper reconnect) before reading.
2592
2690
  // Shared with /api/overview so both endpoints always see a freshly-reconciled
2593
2691
  // entry — see getRehydratedTerminalsEntry doc.
@@ -2610,13 +2708,14 @@ async function handleWorkspaceState(res, workspacePath) {
2610
2708
  return undefined;
2611
2709
  } })(),
2612
2710
  teamEnabled: await hasTeam(path.join(workspacePath, 'codev', 'team')),
2711
+ decisionsEnabled: await decisionsFilePresent(workspacePath, ctx.log),
2613
2712
  };
2614
2713
  // Spec 761: build the architects collection from entry.architects (skip dead
2615
2714
  // sessions, main-first). Shared with /api/overview via `liveArchitects`
2616
2715
  // (Issue 1104) so both payloads list an identical set.
2617
2716
  // Spec 755: the scalar `state.architect` is preserved as a backward-compat
2618
2717
  // pointer to the same default architect (architects[0] when present).
2619
- const architects = liveArchitects(entry, manager);
2718
+ const architects = liveArchitects(entry, manager, workspacePath);
2620
2719
  state.architects = architects;
2621
2720
  state.architect = architects[0] ?? null;
2622
2721
  // Add shells from refreshed cache