@guyghost/swarm-dao-core 0.4.0 → 0.6.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 (276) hide show
  1. package/dist/adapters/attention/fs-attention.store.d.ts +17 -0
  2. package/dist/adapters/attention/fs-attention.store.d.ts.map +1 -0
  3. package/dist/adapters/attention/fs-attention.store.js +59 -0
  4. package/dist/adapters/attention/fs-attention.store.js.map +1 -0
  5. package/dist/adapters/git-workspace.d.ts +26 -0
  6. package/dist/adapters/git-workspace.d.ts.map +1 -0
  7. package/dist/adapters/git-workspace.js +84 -0
  8. package/dist/adapters/git-workspace.js.map +1 -0
  9. package/dist/adapters/index.d.ts +7 -0
  10. package/dist/adapters/index.d.ts.map +1 -0
  11. package/dist/adapters/index.js +7 -0
  12. package/dist/adapters/index.js.map +1 -0
  13. package/dist/adapters/persistence/file-dao-state.repository.d.ts +15 -0
  14. package/dist/adapters/persistence/file-dao-state.repository.d.ts.map +1 -0
  15. package/dist/adapters/persistence/file-dao-state.repository.js +85 -0
  16. package/dist/adapters/persistence/file-dao-state.repository.js.map +1 -0
  17. package/dist/adapters/persistence/in-memory-dao-state.repository.d.ts +10 -0
  18. package/dist/adapters/persistence/in-memory-dao-state.repository.d.ts.map +1 -0
  19. package/dist/adapters/persistence/in-memory-dao-state.repository.js +14 -0
  20. package/dist/adapters/persistence/in-memory-dao-state.repository.js.map +1 -0
  21. package/dist/adapters/persistence/legacy-dao-state.repository.d.ts +11 -0
  22. package/dist/adapters/persistence/legacy-dao-state.repository.d.ts.map +1 -0
  23. package/dist/adapters/persistence/legacy-dao-state.repository.js +14 -0
  24. package/dist/adapters/persistence/legacy-dao-state.repository.js.map +1 -0
  25. package/dist/adapters/ship-audit/fs-ship-audit.store.d.ts +12 -0
  26. package/dist/adapters/ship-audit/fs-ship-audit.store.d.ts.map +1 -0
  27. package/dist/adapters/ship-audit/fs-ship-audit.store.js +69 -0
  28. package/dist/adapters/ship-audit/fs-ship-audit.store.js.map +1 -0
  29. package/dist/application/index.d.ts +16 -0
  30. package/dist/application/index.d.ts.map +1 -0
  31. package/dist/application/index.js +16 -0
  32. package/dist/application/index.js.map +1 -0
  33. package/dist/application/initialize-dao.use-case.d.ts +20 -0
  34. package/dist/application/initialize-dao.use-case.d.ts.map +1 -0
  35. package/dist/application/initialize-dao.use-case.js +17 -0
  36. package/dist/application/initialize-dao.use-case.js.map +1 -0
  37. package/dist/application/proposals/control-proposal.use-case.d.ts +23 -0
  38. package/dist/application/proposals/control-proposal.use-case.d.ts.map +1 -0
  39. package/dist/application/proposals/control-proposal.use-case.js +53 -0
  40. package/dist/application/proposals/control-proposal.use-case.js.map +1 -0
  41. package/dist/application/proposals/create-amendment-proposal.use-case.d.ts +25 -0
  42. package/dist/application/proposals/create-amendment-proposal.use-case.d.ts.map +1 -0
  43. package/dist/application/proposals/create-amendment-proposal.use-case.js +39 -0
  44. package/dist/application/proposals/create-amendment-proposal.use-case.js.map +1 -0
  45. package/dist/application/proposals/create-proposal.use-case.d.ts +34 -0
  46. package/dist/application/proposals/create-proposal.use-case.d.ts.map +1 -0
  47. package/dist/application/proposals/create-proposal.use-case.js +49 -0
  48. package/dist/application/proposals/create-proposal.use-case.js.map +1 -0
  49. package/dist/application/proposals/deliberate-proposal.use-case.d.ts +35 -0
  50. package/dist/application/proposals/deliberate-proposal.use-case.d.ts.map +1 -0
  51. package/dist/application/proposals/deliberate-proposal.use-case.js +67 -0
  52. package/dist/application/proposals/deliberate-proposal.use-case.js.map +1 -0
  53. package/dist/application/proposals/dry-run-proposal.use-case.d.ts +21 -0
  54. package/dist/application/proposals/dry-run-proposal.use-case.d.ts.map +1 -0
  55. package/dist/application/proposals/dry-run-proposal.use-case.js +20 -0
  56. package/dist/application/proposals/dry-run-proposal.use-case.js.map +1 -0
  57. package/dist/application/proposals/execute-proposal.use-case.d.ts +29 -0
  58. package/dist/application/proposals/execute-proposal.use-case.d.ts.map +1 -0
  59. package/dist/application/proposals/execute-proposal.use-case.js +66 -0
  60. package/dist/application/proposals/execute-proposal.use-case.js.map +1 -0
  61. package/dist/application/proposals/rate-proposal.use-case.d.ts +24 -0
  62. package/dist/application/proposals/rate-proposal.use-case.d.ts.map +1 -0
  63. package/dist/application/proposals/rate-proposal.use-case.js +33 -0
  64. package/dist/application/proposals/rate-proposal.use-case.js.map +1 -0
  65. package/dist/application/proposals/record-deliberation-outputs.use-case.d.ts +21 -0
  66. package/dist/application/proposals/record-deliberation-outputs.use-case.d.ts.map +1 -0
  67. package/dist/application/proposals/record-deliberation-outputs.use-case.js +65 -0
  68. package/dist/application/proposals/record-deliberation-outputs.use-case.js.map +1 -0
  69. package/dist/application/proposals/rollback-proposal.use-case.d.ts +20 -0
  70. package/dist/application/proposals/rollback-proposal.use-case.d.ts.map +1 -0
  71. package/dist/application/proposals/rollback-proposal.use-case.js +17 -0
  72. package/dist/application/proposals/rollback-proposal.use-case.js.map +1 -0
  73. package/dist/application/proposals/round-table.use-case.d.ts +27 -0
  74. package/dist/application/proposals/round-table.use-case.d.ts.map +1 -0
  75. package/dist/application/proposals/round-table.use-case.js +55 -0
  76. package/dist/application/proposals/round-table.use-case.js.map +1 -0
  77. package/dist/application/proposals/ship-proposal.use-case.d.ts +26 -0
  78. package/dist/application/proposals/ship-proposal.use-case.d.ts.map +1 -0
  79. package/dist/application/proposals/ship-proposal.use-case.js +60 -0
  80. package/dist/application/proposals/ship-proposal.use-case.js.map +1 -0
  81. package/dist/application/proposals/start-deliberation.use-case.d.ts +21 -0
  82. package/dist/application/proposals/start-deliberation.use-case.d.ts.map +1 -0
  83. package/dist/application/proposals/start-deliberation.use-case.js +30 -0
  84. package/dist/application/proposals/start-deliberation.use-case.js.map +1 -0
  85. package/dist/application/proposals/transition-proposal.use-case.d.ts +20 -0
  86. package/dist/application/proposals/transition-proposal.use-case.d.ts.map +1 -0
  87. package/dist/application/proposals/transition-proposal.use-case.js +19 -0
  88. package/dist/application/proposals/transition-proposal.use-case.js.map +1 -0
  89. package/dist/application/proposals/update-proposal.use-case.d.ts +26 -0
  90. package/dist/application/proposals/update-proposal.use-case.d.ts.map +1 -0
  91. package/dist/application/proposals/update-proposal.use-case.js +19 -0
  92. package/dist/application/proposals/update-proposal.use-case.js.map +1 -0
  93. package/dist/commands/registry.d.ts.map +1 -1
  94. package/dist/commands/registry.js +18 -3
  95. package/dist/commands/registry.js.map +1 -1
  96. package/dist/config.d.ts +23 -0
  97. package/dist/config.d.ts.map +1 -1
  98. package/dist/config.js +9 -1
  99. package/dist/config.js.map +1 -1
  100. package/dist/control/gates.d.ts +4 -1
  101. package/dist/control/gates.d.ts.map +1 -1
  102. package/dist/control/gates.js +5 -10
  103. package/dist/control/gates.js.map +1 -1
  104. package/dist/delivery/dry-run.d.ts.map +1 -1
  105. package/dist/delivery/dry-run.js +3 -44
  106. package/dist/delivery/dry-run.js.map +1 -1
  107. package/dist/delivery/execution-isolation.d.ts +34 -0
  108. package/dist/delivery/execution-isolation.d.ts.map +1 -0
  109. package/dist/delivery/execution-isolation.js +97 -0
  110. package/dist/delivery/execution-isolation.js.map +1 -0
  111. package/dist/delivery/index.d.ts +2 -0
  112. package/dist/delivery/index.d.ts.map +1 -1
  113. package/dist/delivery/index.js +2 -0
  114. package/dist/delivery/index.js.map +1 -1
  115. package/dist/delivery/plans.d.ts +3 -1
  116. package/dist/delivery/plans.d.ts.map +1 -1
  117. package/dist/delivery/plans.js +2 -2
  118. package/dist/delivery/plans.js.map +1 -1
  119. package/dist/delivery/ship-audit.d.ts +36 -0
  120. package/dist/delivery/ship-audit.d.ts.map +1 -0
  121. package/dist/delivery/ship-audit.js +155 -0
  122. package/dist/delivery/ship-audit.js.map +1 -0
  123. package/dist/domain/dry-run.d.ts +3 -0
  124. package/dist/domain/dry-run.d.ts.map +1 -0
  125. package/dist/domain/dry-run.js +28 -0
  126. package/dist/domain/dry-run.js.map +1 -0
  127. package/dist/domain/index.d.ts +6 -0
  128. package/dist/domain/index.d.ts.map +1 -0
  129. package/dist/domain/index.js +7 -0
  130. package/dist/domain/index.js.map +1 -0
  131. package/dist/governance/agents.d.ts.map +1 -1
  132. package/dist/governance/agents.js +107 -169
  133. package/dist/governance/agents.js.map +1 -1
  134. package/dist/governance/charter.d.ts +14 -0
  135. package/dist/governance/charter.d.ts.map +1 -0
  136. package/dist/governance/charter.js +65 -0
  137. package/dist/governance/charter.js.map +1 -0
  138. package/dist/governance/edit-gate.d.ts +47 -0
  139. package/dist/governance/edit-gate.d.ts.map +1 -0
  140. package/dist/governance/edit-gate.js +156 -0
  141. package/dist/governance/edit-gate.js.map +1 -0
  142. package/dist/governance/index.d.ts +1 -0
  143. package/dist/governance/index.d.ts.map +1 -1
  144. package/dist/governance/index.js +1 -0
  145. package/dist/governance/index.js.map +1 -1
  146. package/dist/governance/proposal.machine.d.ts +2 -114
  147. package/dist/governance/proposal.machine.d.ts.map +1 -1
  148. package/dist/governance/proposal.machine.js +2 -180
  149. package/dist/governance/proposal.machine.js.map +1 -1
  150. package/dist/governance/proposal.utils.d.ts +5 -2
  151. package/dist/governance/proposal.utils.d.ts.map +1 -1
  152. package/dist/governance/proposal.utils.js +7 -4
  153. package/dist/governance/proposal.utils.js.map +1 -1
  154. package/dist/governance/voting.d.ts.map +1 -1
  155. package/dist/governance/voting.js +24 -14
  156. package/dist/governance/voting.js.map +1 -1
  157. package/dist/host-tools/github-config.d.ts.map +1 -1
  158. package/dist/host-tools/github-config.js +17 -5
  159. package/dist/host-tools/github-config.js.map +1 -1
  160. package/dist/host-tools/handlers.d.ts +14 -11
  161. package/dist/host-tools/handlers.d.ts.map +1 -1
  162. package/dist/host-tools/handlers.js +247 -341
  163. package/dist/host-tools/handlers.js.map +1 -1
  164. package/dist/index.d.ts +5 -0
  165. package/dist/index.d.ts.map +1 -1
  166. package/dist/index.js +10 -0
  167. package/dist/index.js.map +1 -1
  168. package/dist/integrations/github.d.ts.map +1 -1
  169. package/dist/integrations/github.js +5 -2
  170. package/dist/integrations/github.js.map +1 -1
  171. package/dist/intelligence/delegation.d.ts +3 -2
  172. package/dist/intelligence/delegation.d.ts.map +1 -1
  173. package/dist/intelligence/delegation.js.map +1 -1
  174. package/dist/intelligence/index.d.ts +1 -0
  175. package/dist/intelligence/index.d.ts.map +1 -1
  176. package/dist/intelligence/index.js +1 -0
  177. package/dist/intelligence/index.js.map +1 -1
  178. package/dist/intelligence/roundtable.d.ts +4 -2
  179. package/dist/intelligence/roundtable.d.ts.map +1 -1
  180. package/dist/intelligence/roundtable.js +2 -2
  181. package/dist/intelligence/roundtable.js.map +1 -1
  182. package/dist/intelligence/sequential.d.ts +36 -0
  183. package/dist/intelligence/sequential.d.ts.map +1 -0
  184. package/dist/intelligence/sequential.js +91 -0
  185. package/dist/intelligence/sequential.js.map +1 -0
  186. package/dist/intelligence/swarm.d.ts +8 -4
  187. package/dist/intelligence/swarm.d.ts.map +1 -1
  188. package/dist/intelligence/swarm.js +10 -3
  189. package/dist/intelligence/swarm.js.map +1 -1
  190. package/dist/intelligence/synthesis.d.ts.map +1 -1
  191. package/dist/intelligence/synthesis.js +16 -4
  192. package/dist/intelligence/synthesis.js.map +1 -1
  193. package/dist/models/graph-engineering.machine.d.ts +219 -0
  194. package/dist/models/graph-engineering.machine.d.ts.map +1 -0
  195. package/dist/models/graph-engineering.machine.js +214 -0
  196. package/dist/models/graph-engineering.machine.js.map +1 -0
  197. package/dist/models/improvement-loop.machine.d.ts +239 -0
  198. package/dist/models/improvement-loop.machine.d.ts.map +1 -0
  199. package/dist/models/improvement-loop.machine.js +254 -0
  200. package/dist/models/improvement-loop.machine.js.map +1 -0
  201. package/dist/models/index.d.ts +6 -0
  202. package/dist/models/index.d.ts.map +1 -0
  203. package/dist/models/index.js +6 -0
  204. package/dist/models/index.js.map +1 -0
  205. package/dist/models/product-loop.machine.d.ts +531 -0
  206. package/dist/models/product-loop.machine.d.ts.map +1 -0
  207. package/dist/models/product-loop.machine.js +699 -0
  208. package/dist/models/product-loop.machine.js.map +1 -0
  209. package/dist/models/proposal.machine.d.ts +82 -0
  210. package/dist/models/proposal.machine.d.ts.map +1 -0
  211. package/dist/models/proposal.machine.js +68 -0
  212. package/dist/models/proposal.machine.js.map +1 -0
  213. package/dist/models/ship-audit.machine.d.ts +103 -0
  214. package/dist/models/ship-audit.machine.d.ts.map +1 -0
  215. package/dist/models/ship-audit.machine.js +113 -0
  216. package/dist/models/ship-audit.machine.js.map +1 -0
  217. package/dist/observability/attention.d.ts +40 -0
  218. package/dist/observability/attention.d.ts.map +1 -0
  219. package/dist/observability/attention.js +119 -0
  220. package/dist/observability/attention.js.map +1 -0
  221. package/dist/observability/index.d.ts +1 -0
  222. package/dist/observability/index.d.ts.map +1 -1
  223. package/dist/observability/index.js +1 -0
  224. package/dist/observability/index.js.map +1 -1
  225. package/dist/observability/logging.d.ts +6 -0
  226. package/dist/observability/logging.d.ts.map +1 -1
  227. package/dist/observability/logging.js +36 -6
  228. package/dist/observability/logging.js.map +1 -1
  229. package/dist/observability/metrics.d.ts +7 -0
  230. package/dist/observability/metrics.d.ts.map +1 -1
  231. package/dist/observability/metrics.js +179 -43
  232. package/dist/observability/metrics.js.map +1 -1
  233. package/dist/persistence.d.ts +3 -0
  234. package/dist/persistence.d.ts.map +1 -1
  235. package/dist/persistence.js +88 -17
  236. package/dist/persistence.js.map +1 -1
  237. package/dist/ports/clock.d.ts +7 -0
  238. package/dist/ports/clock.d.ts.map +1 -0
  239. package/dist/ports/clock.js +5 -0
  240. package/dist/ports/clock.js.map +1 -0
  241. package/dist/ports/host.d.ts +8 -0
  242. package/dist/ports/host.d.ts.map +1 -0
  243. package/dist/ports/host.js +2 -0
  244. package/dist/ports/host.js.map +1 -0
  245. package/dist/ports/index.d.ts +6 -0
  246. package/dist/ports/index.d.ts.map +1 -0
  247. package/dist/ports/index.js +6 -0
  248. package/dist/ports/index.js.map +1 -0
  249. package/dist/ports/repository.d.ts +7 -0
  250. package/dist/ports/repository.d.ts.map +1 -0
  251. package/dist/ports/repository.js +2 -0
  252. package/dist/ports/repository.js.map +1 -0
  253. package/dist/ports/ship-audit.d.ts +26 -0
  254. package/dist/ports/ship-audit.d.ts.map +1 -0
  255. package/dist/ports/ship-audit.js +9 -0
  256. package/dist/ports/ship-audit.js.map +1 -0
  257. package/dist/ports/workspace.d.ts +14 -0
  258. package/dist/ports/workspace.d.ts.map +1 -0
  259. package/dist/ports/workspace.js +14 -0
  260. package/dist/ports/workspace.js.map +1 -0
  261. package/dist/presenters/index.d.ts +2 -0
  262. package/dist/presenters/index.d.ts.map +1 -0
  263. package/dist/presenters/index.js +2 -0
  264. package/dist/presenters/index.js.map +1 -0
  265. package/dist/presenters/proposal.presenter.d.ts +30 -0
  266. package/dist/presenters/proposal.presenter.d.ts.map +1 -0
  267. package/dist/presenters/proposal.presenter.js +47 -0
  268. package/dist/presenters/proposal.presenter.js.map +1 -0
  269. package/dist/utils/host.d.ts.map +1 -1
  270. package/dist/utils/host.js +77 -6
  271. package/dist/utils/host.js.map +1 -1
  272. package/dist/utils/security.d.ts +7 -1
  273. package/dist/utils/security.d.ts.map +1 -1
  274. package/dist/utils/security.js +18 -2
  275. package/dist/utils/security.js.map +1 -1
  276. package/package.json +13 -1
@@ -1,289 +1,243 @@
1
+ import { createExecutionWorkspace } from "../adapters/git-workspace.js";
2
+ import { LegacyDaoStateRepository } from "../adapters/persistence/legacy-dao-state.repository.js";
3
+ import { FsShipAuditStore } from "../adapters/ship-audit/fs-ship-audit.store.js";
4
+ import { InitializeDaoUseCase } from "../application/initialize-dao.use-case.js";
5
+ import { ControlProposalUseCase } from "../application/proposals/control-proposal.use-case.js";
6
+ import { CreateAmendmentProposalUseCase } from "../application/proposals/create-amendment-proposal.use-case.js";
7
+ import { CreateProposalUseCase } from "../application/proposals/create-proposal.use-case.js";
8
+ import { DeliberateProposalUseCase } from "../application/proposals/deliberate-proposal.use-case.js";
9
+ import { DryRunProposalUseCase } from "../application/proposals/dry-run-proposal.use-case.js";
10
+ import { ExecuteProposalUseCase } from "../application/proposals/execute-proposal.use-case.js";
11
+ import { RateProposalUseCase } from "../application/proposals/rate-proposal.use-case.js";
12
+ import { RecordDeliberationOutputsUseCase } from "../application/proposals/record-deliberation-outputs.use-case.js";
13
+ import { RollbackProposalUseCase } from "../application/proposals/rollback-proposal.use-case.js";
14
+ import { RoundTableUseCase } from "../application/proposals/round-table.use-case.js";
15
+ import { ShipProposalUseCase } from "../application/proposals/ship-proposal.use-case.js";
16
+ import { StartDeliberationUseCase } from "../application/proposals/start-deliberation.use-case.js";
17
+ import { UpdateProposalUseCase } from "../application/proposals/update-proposal.use-case.js";
1
18
  import { loadConfig } from "../config.js";
2
19
  import { formatAuditTrail } from "../control/audit.js";
3
- import { formatControlResult, runGates } from "../control/gates.js";
4
20
  import { formatAllArtefacts, generateAllArtefacts } from "../delivery/artefacts.js";
5
- import { getUnexecutedDependencies } from "../delivery/dependencies.js";
6
- import { formatDryRun, formatRollback, performDryRun, performRollback } from "../delivery/dry-run.js";
7
- import { executeProposal } from "../delivery/execution.js";
8
- import { formatPlan, generateDeliveryPlan, getPlan } from "../delivery/plans.js";
21
+ import { formatPlan, getPlan } from "../delivery/plans.js";
22
+ import { evaluateShipAuditChallenge } from "../delivery/ship-audit.js";
9
23
  import { formatAgentsTable, initializeAgents, loadAgentDefinitions } from "../governance/agents.js";
10
- import { validateAmendmentPayload } from "../governance/amendments.js";
11
- import { classifyRiskZone } from "../governance/lifecycle.js";
12
- import { dispatchProposalEvent } from "../governance/proposal.utils.js";
13
- import { calculateCompositeScore, formatCompositeScore } from "../governance/scoring.js";
14
- import { formatTallyResult, parseVoteFromOutput, tallyVotes } from "../governance/voting.js";
24
+ import { evaluateEditGate, formatEditGate } from "../governance/edit-gate.js";
15
25
  import { computeHealthScore, formatHealthScore, generateDashboard } from "../health-score.js";
16
26
  import { ghBranchNameFor, ghCreateBranch, ghCreatePullRequest, isGitHubEnabled } from "../integrations/github.js";
17
- import { formatRoundTableResults, runRoundTable } from "../intelligence/roundtable.js";
18
- import { buildDispatchInstructions, createDispatchModelContext, dispatchSwarm, formatDispatchPlan, } from "../intelligence/swarm.js";
19
- import { synthesize } from "../intelligence/synthesis.js";
20
- import { addRating, createProposal, createProposalsBatch, getAllAuditLog, getOrCreateState, getProposal, getState, initStorage, recordAudit, saveState, storeCompositeScore, storeDeliberationBatch, storeDeliveryPlan, storeSynthesis, } from "../persistence.js";
21
- import { PROPOSAL_TYPE_LABELS, PROPOSAL_TYPES } from "../types/index.js";
27
+ import { formatRoundTableResults } from "../intelligence/roundtable.js";
28
+ import { buildDispatchInstructions, createDispatchModelContext, formatDispatchPlan } from "../intelligence/swarm.js";
29
+ import { recordProposalExecuted } from "../observability/metrics.js";
30
+ import { getAllAuditLog, getOrCreateState, getProposal, getState, initStorage } from "../persistence.js";
31
+ import { systemClock } from "../ports/clock.js";
32
+ import { presentAmendment, presentControl, presentDeliberation, presentDryRun, presentExecution, presentInitialization, presentProposalCreated, presentProposalUpdated, presentRating, presentRollback, presentShip, } from "../presenters/proposal.presenter.js";
33
+ import { PROPOSAL_TYPES } from "../types/index.js";
22
34
  import { loadGitHubConfigFromDaoRoot, saveGitHubConfigToDaoRoot } from "./github-config.js";
23
35
  import { DAO_ONBOARDING_MESSAGE } from "./messages.js";
24
36
  import { parseSafeJson } from "./utils.js";
25
- function requireInitialized() {
26
- const state = getState();
37
+ function repositoryOrLegacy(repository) {
38
+ return repository ?? new LegacyDaoStateRepository();
39
+ }
40
+ function requireInitialized(repository) {
41
+ const state = repository ? repository.get() : getState();
27
42
  if (!state.initialized)
28
43
  return DAO_ONBOARDING_MESSAGE;
29
44
  return null;
30
45
  }
31
46
  export async function handleDaoSetup(ctx, useDefaults = true) {
32
47
  await initStorage(ctx.workDir);
33
- const state = getOrCreateState(ctx.workDir);
34
- if (state.initialized) {
35
- return `DAO already initialized with ${state.agents.length} agents.`;
36
- }
48
+ if (!ctx.repository)
49
+ getOrCreateState(ctx.workDir);
37
50
  const agents = initializeAgents(useDefaults ? undefined : []);
38
- state.agents = agents;
39
- state.initialized = true;
40
- await saveState();
41
- return `# DAO Initialized\n\n${formatAgentsTable(agents)}\n\nRun \`dao_help\` to discover the workflow, then \`dao_propose\` to create proposals.`;
51
+ const result = await new InitializeDaoUseCase({ repository: repositoryOrLegacy(ctx.repository) }).execute({ agents });
52
+ return presentInitialization(result);
42
53
  }
43
- export async function handleDaoPropose(args) {
44
- const notReady = requireInitialized();
45
- if (notReady)
46
- return notReady;
47
- const proposal = await createProposal(args.title, args.type, args.description, "user", args.context);
48
- if (args.problemStatement !== undefined)
49
- proposal.problemStatement = args.problemStatement;
50
- if (args.acceptanceCriteria !== undefined)
51
- proposal.acceptanceCriteria = args.acceptanceCriteria;
52
- if (args.successMetrics !== undefined)
53
- proposal.successMetrics = args.successMetrics;
54
- if (args.rollbackConditions !== undefined)
55
- proposal.rollbackConditions = args.rollbackConditions;
56
- if (args.affectedPaths !== undefined)
57
- proposal.affectedPaths = args.affectedPaths;
58
- proposal.riskZone = classifyRiskZone(proposal);
59
- await saveState();
60
- await recordAudit(proposal.id, "governance", "proposal_created", "user", `Proposal "${args.title}" created`);
61
- const typeLabel = PROPOSAL_TYPE_LABELS[args.type] ?? args.type;
62
- return `# 📋 Proposal Created — #${proposal.id}\n\n**Title:** ${args.title}\n**Type:** ${typeLabel}\n**Zone:** ${proposal.riskZone}\n\nRun \`dao_deliberate proposalId=${proposal.id}\``;
54
+ export async function handleDaoPropose(args, repository) {
55
+ const useCase = new CreateProposalUseCase({ repository: repositoryOrLegacy(repository), clock: systemClock });
56
+ const result = await useCase.execute({ ...args, proposedBy: "user" });
57
+ if (!result.ok)
58
+ return result.error === "DAO not initialized. Run dao_setup first." ? DAO_ONBOARDING_MESSAGE : result.error;
59
+ return presentProposalCreated(result.proposal);
63
60
  }
64
61
  export async function handleDaoDeliberate(ctx, proposalId) {
65
- const notReady = requireInitialized();
62
+ const notReady = requireInitialized(ctx.repository);
66
63
  if (notReady)
67
64
  return notReady;
68
- const state = getState();
69
- const proposal = getProposal(proposalId);
65
+ const state = repositoryOrLegacy(ctx.repository).get();
66
+ const proposal = state.proposals.find((candidate) => candidate.id === proposalId);
70
67
  if (!proposal)
71
68
  return `Proposal #${proposalId} not found.`;
72
69
  if (proposal.status !== "open")
73
70
  return `Proposal #${proposal.id} is ${proposal.status}, must be open.`;
74
- const deliberation = dispatchProposalEvent(proposal, { type: "DELIBERATE" });
75
- if (!deliberation.ok)
76
- return `Cannot deliberate: ${deliberation.error}`;
77
- await recordAudit(proposal.id, "governance", "deliberation_started", "system", `Deliberation on #${proposal.id}`);
78
- await saveState();
79
71
  const projectConfig = await loadConfig(state.daoRoot);
80
72
  const agents = await loadAgentDefinitions(state.daoRoot, projectConfig);
81
- const modelContext = createDispatchModelContext(state.config.defaultModel, ctx.adapter, {
82
- parentSessionModel: ctx.getSessionModel?.(),
83
- hostDefaultModel: ctx.hostDefaultModel,
84
- });
85
73
  if (ctx.deliberationMode === "manual") {
74
+ const deliberation = await new StartDeliberationUseCase({
75
+ repository: repositoryOrLegacy(ctx.repository),
76
+ clock: systemClock,
77
+ }).execute({ proposalId });
78
+ if (!deliberation.ok)
79
+ return `Cannot deliberate: ${deliberation.error}`;
80
+ const modelContext = createDispatchModelContext(state.config.defaultModel, ctx.adapter, {
81
+ parentSessionModel: ctx.getSessionModel?.(),
82
+ hostDefaultModel: ctx.hostDefaultModel,
83
+ });
86
84
  const instructions = buildDispatchInstructions(proposal, agents, modelContext);
87
- const plan = formatDispatchPlan(proposal, instructions);
85
+ const plan = formatDispatchPlan(proposal, instructions, {
86
+ strategy: projectConfig.deliberation?.strategy,
87
+ charsPerAgent: projectConfig.deliberation?.charsPerAgent,
88
+ });
88
89
  const parentModel = ctx.getSessionModel?.() ?? ctx.hostDefaultModel;
89
90
  const parentNote = parentModel ? `\n\n**Parent session model:** ${parentModel}` : "";
90
91
  return `${plan}${parentNote}`;
91
92
  }
92
93
  const startTime = Date.now();
93
- const outputs = await dispatchSwarm(proposal, agents, ctx.adapter, state.config.maxConcurrent, modelContext, (update) => ctx.onDeliberationProgress?.(update));
94
- const votes = [];
95
- const persistedOutputs = [];
96
- const agentById = new Map(agents.map((a) => [a.id, a]));
97
- for (const output of outputs) {
98
- if (output.content) {
99
- const weight = agentById.get(output.agentId)?.weight ?? 1;
100
- const vote = parseVoteFromOutput(output.agentId, output.agentName, weight, output.content);
101
- if (vote) {
102
- vote.weight = weight;
103
- votes.push(vote);
104
- }
105
- }
106
- persistedOutputs.push(output);
107
- }
108
- if (votes.length > 0 || persistedOutputs.length > 0) {
109
- await storeDeliberationBatch(proposal.id, votes, persistedOutputs);
110
- }
111
- proposal.votes = votes;
112
- const compositeScore = calculateCompositeScore(outputs);
113
- proposal.compositeScore = compositeScore;
114
- await storeCompositeScore(proposal.id, compositeScore);
115
- const tally = tallyVotes(proposal, state.config);
116
- const synthesisText = synthesize(proposal, agents, outputs, tally);
117
- proposal.synthesis = synthesisText;
118
- await storeSynthesis(proposal.id, synthesisText);
119
- if (tally.approved) {
120
- dispatchProposalEvent(proposal, { type: "APPROVE", tally });
121
- await recordAudit(proposal.id, "intelligence", "deliberation_approved", "system", `Approved: ${tally.approvalScore}%`);
122
- }
123
- else {
124
- dispatchProposalEvent(proposal, { type: "REJECT" });
125
- await recordAudit(proposal.id, "intelligence", "deliberation_rejected", "system", `Rejected: ${tally.approvalScore}%`);
126
- }
127
- await saveState();
94
+ const useCase = new DeliberateProposalUseCase({
95
+ repository: repositoryOrLegacy(ctx.repository),
96
+ worker: ctx.adapter,
97
+ clock: systemClock,
98
+ });
99
+ const result = await useCase.execute({
100
+ proposalId,
101
+ agents,
102
+ strategy: projectConfig.deliberation?.strategy,
103
+ charsPerAgent: projectConfig.deliberation?.charsPerAgent,
104
+ parentSessionModel: ctx.getSessionModel?.(),
105
+ hostDefaultModel: ctx.hostDefaultModel,
106
+ onUpdate: (update) => ctx.onDeliberationProgress?.(update),
107
+ });
108
+ if (!result.ok)
109
+ return `Cannot deliberate: ${result.error}`;
128
110
  const duration = Date.now() - startTime;
129
- return `# 🗳️ Deliberation Complete — #${proposal.id} (${duration}ms)\n\n${formatTallyResult(tally)}\n\n${formatCompositeScore(compositeScore)}\n\n${synthesisText}\n\n> Next: \`${ctx.controlToolName} proposalId=${proposal.id}\``;
111
+ return presentDeliberation(proposal.id, result, { durationMs: duration, controlToolName: ctx.controlToolName });
130
112
  }
131
113
  export async function handleDaoRecordOutputs(ctx, proposalId, outputs) {
132
- const notReady = requireInitialized();
114
+ const useCase = new RecordDeliberationOutputsUseCase({
115
+ repository: repositoryOrLegacy(ctx.repository),
116
+ clock: systemClock,
117
+ });
118
+ const result = await useCase.execute({ proposalId, outputs });
119
+ if (!result.ok)
120
+ return result.error;
121
+ return presentDeliberation(proposalId, result, { controlToolName: ctx.controlToolName });
122
+ }
123
+ export async function handleDaoControl(ctx, proposalId) {
124
+ const notReady = requireInitialized(ctx.repository);
133
125
  if (notReady)
134
126
  return notReady;
135
- const state = getState();
136
- const proposal = getProposal(proposalId);
137
- if (!proposal)
138
- return `Proposal #${proposalId} not found.`;
139
- if (proposal.status !== "deliberating")
140
- return `Expected deliberating (current: ${proposal.status})`;
141
- const votes = [];
142
- const enrichedOutputs = [];
143
- for (const raw of outputs) {
144
- const agent = state.agents.find((a) => a.id === raw.agentId);
145
- if (!agent)
146
- continue;
147
- const output = {
148
- agentId: agent.id,
149
- agentName: agent.name,
150
- role: agent.role,
151
- content: raw.content || "",
152
- durationMs: raw.durationMs ?? 0,
153
- error: raw.error,
154
- };
155
- const vote = parseVoteFromOutput(agent.id, agent.name, agent.weight, output.content);
156
- if (vote) {
157
- output.vote = vote;
158
- votes.push(vote);
159
- }
160
- enrichedOutputs.push(output);
161
- }
162
- await storeDeliberationBatch(proposal.id, votes, enrichedOutputs);
163
- proposal.votes = votes;
164
- const compositeScore = calculateCompositeScore(enrichedOutputs);
165
- proposal.compositeScore = compositeScore;
166
- await storeCompositeScore(proposal.id, compositeScore);
167
- const synthesisText = synthesize(proposal, state.agents, enrichedOutputs);
168
- proposal.synthesis = synthesisText;
169
- await storeSynthesis(proposal.id, synthesisText);
170
- const tally = tallyVotes(proposal, state.config);
171
- if (tally.approved) {
172
- dispatchProposalEvent(proposal, { type: "APPROVE", tally });
173
- await recordAudit(proposal.id, "intelligence", "deliberation_approved", "system", `Approved: ${tally.approvalScore}%`);
174
- }
175
- else {
176
- dispatchProposalEvent(proposal, { type: "REJECT" });
177
- await recordAudit(proposal.id, "intelligence", "deliberation_rejected", "system", `Rejected: ${tally.approvalScore}%`);
178
- }
179
- await saveState();
180
- return `# 🗳️ Deliberation Complete — #${proposal.id}\n\n${formatTallyResult(tally)}\n\n${formatCompositeScore(compositeScore)}\n\n${synthesisText}\n\n> Next: \`${ctx.controlToolName} proposalId=${proposal.id}\``;
127
+ const useCase = new ControlProposalUseCase({ repository: repositoryOrLegacy(ctx.repository), clock: systemClock });
128
+ const result = await useCase.execute({ proposalId, failOnGateFailure: ctx.failOnGateFailure });
129
+ if (!result.ok)
130
+ return result.error;
131
+ return presentControl(result.control);
181
132
  }
182
- export async function handleDaoControl(ctx, proposalId) {
183
- const notReady = requireInitialized();
133
+ export async function handleDaoExecute(ctx, proposalId) {
134
+ const repository = repositoryOrLegacy(ctx.repository);
135
+ const projectConfig = await loadConfig(repository.get().daoRoot);
136
+ const workspace = createExecutionWorkspace(projectConfig.execution, ctx.adapter, ctx.workDir);
137
+ const useCase = new ExecuteProposalUseCase({ repository, clock: systemClock, workspace });
138
+ const result = await useCase.execute({ proposalId, actor: "user" });
139
+ if (!result.ok)
140
+ return result.error;
141
+ recordProposalExecuted(result.proposal.id, result.proposal.type);
142
+ return presentExecution(result);
143
+ }
144
+ export async function handleDaoShip(ctx, proposalId, options) {
145
+ const notReady = requireInitialized(ctx.repository);
184
146
  if (notReady)
185
147
  return notReady;
186
- const state = getState();
187
- const proposal = getProposal(proposalId);
188
- if (!proposal)
189
- return `Proposal #${proposalId} not found.`;
190
- if (proposal.status !== "approved")
191
- return `Must be approved (current: ${proposal.status})`;
192
- const result = runGates(proposal, state.config);
193
- if (result.allGatesPassed) {
194
- dispatchProposalEvent(proposal, { type: "CONTROL_PASS", result });
195
- await recordAudit(proposal.id, "control", "gates_passed", "system", "All gates passed");
196
- if (!state.deliveryPlans[proposal.id]) {
197
- const plan = generateDeliveryPlan(proposal);
198
- await storeDeliveryPlan(proposal.id, plan);
199
- }
200
- }
201
- else {
202
- if (ctx.failOnGateFailure) {
203
- dispatchProposalEvent(proposal, { type: "CONTROL_FAIL" });
148
+ const repository = repositoryOrLegacy(ctx.repository);
149
+ // Ship audit challenge (opt-in): the first call challenges instead of
150
+ // executing; only an unchanged second call proceeds (models/ship-audit.md).
151
+ const shipConfig = await loadConfig(repository.get().daoRoot);
152
+ if (shipConfig.ship?.auditChallenge === true) {
153
+ const proposal = repository.get().proposals.find((candidate) => candidate.id === proposalId);
154
+ if (!proposal)
155
+ return `Proposal #${proposalId} not found.`;
156
+ const gate = await evaluateShipAuditChallenge({
157
+ proposal,
158
+ store: new FsShipAuditStore(ctx.workDir),
159
+ challengeEnabled: true,
160
+ force: options?.force === true,
161
+ forceReason: options?.force === true ? "dao_ship force" : undefined,
162
+ options: { cascade: options?.cascade === true },
163
+ });
164
+ if (!gate.proceed)
165
+ return `# 🛑 Ship Audit — Do Not Proceed
166
+
167
+ ${gate.message}
168
+
169
+ Force with an explicit reason when genuinely required: re-run with \`force=true\` (recorded as a human bypass).`;
170
+ // Shipping executes controlled proposals, so it must honour the same
171
+ // execution isolation as dao_execute — otherwise host shipping would
172
+ // bypass a configured worktree.
173
+ const workspace = createExecutionWorkspace(shipConfig.execution, ctx.adapter, ctx.workDir);
174
+ const auditedUseCase = new ShipProposalUseCase({ repository, clock: systemClock, workspace });
175
+ // The audited path: force means "bypass the audit challenge" ONLY —
176
+ // dependency checks still run inside the use-case (review resolution:
177
+ // the bypass satisfies INV-1, nothing else).
178
+ const auditedResult = await auditedUseCase.execute({
179
+ proposalId,
180
+ actor: ctx.adapter.hostId,
181
+ cascade: options?.cascade,
182
+ });
183
+ await gate.consume?.();
184
+ if (!auditedResult.ok)
185
+ return auditedResult.error;
186
+ for (const id of auditedResult.shipped) {
187
+ const shipped = repository.get().proposals.find((candidate) => candidate.id === id);
188
+ if (shipped)
189
+ recordProposalExecuted(shipped.id, shipped.type);
204
190
  }
205
- await recordAudit(proposal.id, "control", "gates_failed", "system", `${result.blockerCount} blockers`);
191
+ return `${presentShip(auditedResult)}${gate.note ? `\n\n*${gate.note}*` : ""}`;
206
192
  }
207
- await saveState();
208
- return formatControlResult(result);
209
- }
210
- export async function handleDaoExecute(proposalId) {
211
- const proposal = getProposal(proposalId);
212
- if (!proposal)
213
- return `Proposal #${proposalId} not found.`;
214
- if (proposal.status !== "controlled") {
215
- return `Must be controlled (current: ${proposal.status}). Run dao_control first.`;
193
+ // Shipping executes controlled proposals, so it must honour the same
194
+ // execution isolation as dao_execute — otherwise host shipping would
195
+ // bypass a configured worktree.
196
+ const workspace = createExecutionWorkspace(shipConfig.execution, ctx.adapter, ctx.workDir);
197
+ const useCase = new ShipProposalUseCase({ repository, clock: systemClock, workspace });
198
+ const result = await useCase.execute({
199
+ proposalId,
200
+ actor: ctx.adapter.hostId,
201
+ cascade: options?.cascade,
202
+ force: options?.force,
203
+ });
204
+ if (!result.ok)
205
+ return result.error;
206
+ for (const id of result.shipped) {
207
+ const proposal = repositoryOrLegacy(ctx.repository)
208
+ .get()
209
+ .proposals.find((candidate) => candidate.id === id);
210
+ if (proposal)
211
+ recordProposalExecuted(proposal.id, proposal.type);
216
212
  }
217
- const result = await executeProposal(proposal);
218
- await saveState();
219
- await recordAudit(proposal.id, "delivery", "proposal_executed", "user", `Executed #${proposal.id}`);
220
- return result.result;
213
+ return presentShip(result);
221
214
  }
222
- export async function handleDaoShip(ctx, proposalId, options) {
223
- const notReady = requireInitialized();
215
+ export async function handleDaoCheckEdit(ctx, paths) {
216
+ const repository = repositoryOrLegacy(ctx.repository);
217
+ const notReady = requireInitialized(ctx.repository);
224
218
  if (notReady)
225
219
  return notReady;
226
- const state = getState();
227
- const proposal = getProposal(proposalId);
228
- if (!proposal)
229
- return `Proposal #${proposalId} not found.`;
230
- const cascade = options?.cascade === true;
231
- const force = options?.force === true;
232
- const shipped = [];
233
- const shipOne = async (id) => {
234
- const target = getProposal(id);
235
- if (!target)
236
- return `Proposal #${id} not found.`;
237
- if (target.status !== "controlled") {
238
- return `Proposal #${target.id} must be in 'controlled' state to ship (current: ${target.status})`;
239
- }
240
- const result = await executeProposal(target);
241
- if (!result.success)
242
- return result.result;
243
- await recordAudit(target.id, "delivery", "proposal-shipped", ctx.adapter.hostId, "shipped via dao_ship");
244
- return null;
245
- };
246
- if (!force) {
247
- const depsResolution = getUnexecutedDependencies(proposal.id, state.proposals);
248
- if (depsResolution.error)
249
- return depsResolution.error;
250
- const pendingDeps = depsResolution.order ?? [];
251
- if (pendingDeps.length > 0 && !cascade) {
252
- const lines = pendingDeps.map((depId) => {
253
- const dep = getProposal(depId);
254
- return dep ? `- #${dep.id} [${dep.status}] ${dep.title}` : `- #${depId} [missing]`;
255
- });
256
- return `Cannot ship proposal #${proposal.id}: unexecuted dependencies found.\n\n${lines.join("\n")}\n\nRetry with \`dao_ship proposalId=${proposal.id} cascade=true\` or \`force=true\`.`;
257
- }
258
- if (cascade && pendingDeps.length > 0) {
259
- const notControlled = pendingDeps.filter((depId) => getProposal(depId)?.status !== "controlled");
260
- if (notControlled.length > 0) {
261
- const details = notControlled
262
- .map((depId) => {
263
- const dep = getProposal(depId);
264
- return dep ? `#${dep.id} (${dep.status})` : `#${depId} (missing)`;
265
- })
266
- .join(", ");
267
- return `Cannot cascade ship: dependencies not in 'controlled' state: ${details}`;
268
- }
269
- for (const depId of pendingDeps) {
270
- const dep = getProposal(depId);
271
- if (!dep || dep.status === "executed")
272
- continue;
273
- const depError = await shipOne(depId);
274
- if (depError)
275
- return depError;
276
- shipped.push(depId);
277
- }
278
- }
220
+ const cleaned = [...new Set(paths.map((path) => path.trim()).filter(Boolean))];
221
+ // Refuse oversized requests outright: silently truncating could let a
222
+ // protected file ride just past the cutoff and come back as allowed.
223
+ if (cleaned.length > 200) {
224
+ return `Too many paths provided (${cleaned.length}). Pass at most 200 paths per edit check.`;
279
225
  }
280
- const targetError = await shipOne(proposal.id);
281
- if (targetError)
282
- return targetError;
283
- shipped.push(proposal.id);
284
- await saveState();
285
- const summary = shipped.map((id) => `- #${id}`).join("\n");
286
- return `# 🚀 Ship Complete\n\nShipped proposals:\n${summary}`;
226
+ if (cleaned.length === 0)
227
+ return "No paths provided. Pass the files you are about to edit.";
228
+ const state = repository.get();
229
+ const projectConfig = await loadConfig(state.daoRoot);
230
+ const decision = evaluateEditGate({
231
+ paths: cleaned,
232
+ mode: projectConfig.mode,
233
+ criticalPaths: projectConfig.criticalPaths ?? [],
234
+ approved: state.proposals.map((proposal) => ({
235
+ proposalId: proposal.id,
236
+ affectedPaths: proposal.affectedPaths,
237
+ status: proposal.status,
238
+ })),
239
+ });
240
+ return formatEditGate(decision);
287
241
  }
288
242
  export async function handleDaoList() {
289
243
  const notReady = requireInitialized();
@@ -335,117 +289,71 @@ export async function handleDaoArtefacts(proposalId) {
335
289
  return `Proposal #${proposalId} not found.`;
336
290
  return formatAllArtefacts(generateAllArtefacts(proposal));
337
291
  }
338
- export async function handleDaoDryRun(proposalId) {
339
- const proposal = getProposal(proposalId);
340
- if (!proposal)
341
- return `Proposal #${proposalId} not found.`;
342
- const result = await performDryRun(proposal);
343
- proposal.dryRunAt = new Date().toISOString();
344
- proposal.dryRunCanProceed = result.canProceed;
345
- await saveState();
346
- return formatDryRun(result);
292
+ export async function handleDaoDryRun(proposalId, repository) {
293
+ const result = await new DryRunProposalUseCase({
294
+ repository: repositoryOrLegacy(repository),
295
+ clock: systemClock,
296
+ }).execute({ proposalId });
297
+ return result.ok ? presentDryRun(result.analysis) : result.error;
347
298
  }
348
- export async function handleDaoRollback(proposalId) {
349
- return formatRollback(await performRollback(proposalId));
299
+ export async function handleDaoRollback(proposalId, repository) {
300
+ const result = await new RollbackProposalUseCase({ repository: repositoryOrLegacy(repository) }).execute({
301
+ proposalId,
302
+ });
303
+ return presentRollback(result);
350
304
  }
351
- export async function handleDaoDashboard() {
352
- const notReady = requireInitialized();
305
+ export async function handleDaoDashboard(repository) {
306
+ const notReady = requireInitialized(repository);
353
307
  if (notReady)
354
308
  return notReady;
355
- const state = getState();
309
+ const state = repositoryOrLegacy(repository).get();
356
310
  const dashboard = generateDashboard(state.proposals, state.outcomes, state.agents, state.healthSnapshots);
357
311
  const health = computeHealthScore(state.proposals, state.outcomes, state.config.healthWeights);
358
312
  return `${dashboard}\n\n${formatHealthScore(health)}`;
359
313
  }
360
314
  export async function handleDaoRoundtable(ctx) {
361
- const notReady = requireInitialized();
315
+ const notReady = requireInitialized(ctx.repository);
362
316
  if (notReady)
363
317
  return notReady;
364
318
  const state = getState();
365
319
  const projectConfig = await loadConfig(state.daoRoot);
366
320
  const agents = await loadAgentDefinitions(state.daoRoot, projectConfig);
367
- const modelContext = createDispatchModelContext(state.config.defaultModel, ctx.adapter, {
321
+ const result = await new RoundTableUseCase({
322
+ repository: repositoryOrLegacy(ctx.repository),
323
+ worker: ctx.adapter,
324
+ clock: systemClock,
325
+ }).execute({
326
+ agents,
368
327
  parentSessionModel: ctx.getSessionModel?.(),
369
328
  hostDefaultModel: ctx.hostDefaultModel,
370
329
  });
371
- const suggestions = await runRoundTable(ctx.adapter, agents, state.config.maxConcurrent, modelContext);
372
- const proposalIds = new Map();
373
- const parsedSuggestions = suggestions
374
- .map((suggestion) => ({ suggestion, parsed: suggestion.parsed }))
375
- .filter((entry) => Boolean(entry.parsed));
376
- try {
377
- const proposals = await createProposalsBatch(parsedSuggestions.map(({ suggestion, parsed }) => ({
378
- title: parsed.title,
379
- type: parsed.type,
380
- description: parsed.description,
381
- proposedBy: suggestion.agentId,
382
- })));
383
- for (const [index, { suggestion }] of parsedSuggestions.entries()) {
384
- const proposal = proposals[index];
385
- if (!proposal)
386
- continue;
387
- proposal.riskZone = classifyRiskZone(proposal);
388
- suggestion.proposalId = proposal.id;
389
- proposalIds.set(suggestion.agentId, proposal.id);
390
- state.auditLog.push({
391
- id: state.nextAuditId++,
392
- timestamp: new Date().toISOString(),
393
- proposalId: proposal.id,
394
- layer: "intelligence",
395
- action: "roundtable_proposal_created",
396
- actor: suggestion.agentId,
397
- details: "Auto-created from round table",
398
- });
399
- }
400
- }
401
- catch (error) {
402
- const message = error instanceof Error ? error.message : String(error);
403
- for (const { suggestion } of parsedSuggestions) {
404
- suggestion.error = `Failed to create proposal: ${message}`;
405
- }
406
- }
407
- await saveState();
408
- return formatRoundTableResults(suggestions, proposalIds);
330
+ return result.ok ? formatRoundTableResults(result.suggestions, result.proposalIds) : result.error;
409
331
  }
410
332
  export async function handleDaoAudit(proposalId) {
411
333
  const entries = proposalId ? getAllAuditLog().filter((e) => e.proposalId === proposalId) : getAllAuditLog();
412
334
  return formatAuditTrail(entries, proposalId);
413
335
  }
414
- export async function handleDaoRate(proposalId, score, comment) {
415
- const proposal = getProposal(proposalId);
416
- if (!proposal)
417
- return `Proposal #${proposalId} not found.`;
418
- if (proposal.status !== "executed")
419
- return `Proposal #${proposal.id} is ${proposal.status}, must be executed.`;
420
- await addRating(proposal.id, {
421
- proposalId: proposal.id,
336
+ export async function handleDaoRate(proposalId, score, comment, repository) {
337
+ const result = await new RateProposalUseCase({
338
+ repository: repositoryOrLegacy(repository),
339
+ clock: systemClock,
340
+ }).execute({
341
+ proposalId,
422
342
  rater: "user",
423
343
  score,
424
344
  comment,
425
- ratedAt: new Date().toISOString(),
426
345
  });
427
- await saveState();
428
- return `# ⭐ Rating Recorded — #${proposal.id}\n\n**Score:** ${score}/5\n**Comment:** ${comment}`;
346
+ return result.ok ? presentRating(result.rating) : result.error;
429
347
  }
430
- export async function handleDaoUpdateProposal(proposalId, fields) {
431
- const proposal = getProposal(proposalId);
432
- if (!proposal)
433
- return `Proposal #${proposalId} not found.`;
434
- if (proposal.status !== "open")
435
- return `Must be open (current: ${proposal.status})`;
436
- if (fields.problemStatement !== undefined)
437
- proposal.problemStatement = fields.problemStatement;
438
- if (fields.acceptanceCriteria !== undefined)
439
- proposal.acceptanceCriteria = fields.acceptanceCriteria;
440
- if (fields.successMetrics !== undefined)
441
- proposal.successMetrics = fields.successMetrics;
442
- if (fields.rollbackConditions !== undefined)
443
- proposal.rollbackConditions = fields.rollbackConditions;
444
- await saveState();
445
- return `# 📝 Proposal Updated — #${proposal.id}\n\nUpdated fields applied.`;
348
+ export async function handleDaoUpdateProposal(proposalId, fields, repository) {
349
+ const result = await new UpdateProposalUseCase({ repository: repositoryOrLegacy(repository) }).execute({
350
+ proposalId,
351
+ fields,
352
+ });
353
+ return result.ok ? presentProposalUpdated(result.proposal) : result.error;
446
354
  }
447
- export async function handleDaoProposeAmendment(args) {
448
- const notReady = requireInitialized();
355
+ export async function handleDaoProposeAmendment(args, repository) {
356
+ const notReady = requireInitialized(repository);
449
357
  if (notReady)
450
358
  return notReady;
451
359
  let payload;
@@ -492,20 +400,16 @@ export async function handleDaoProposeAmendment(args) {
492
400
  }
493
401
  if (!payload)
494
402
  return "Error: amendment payload could not be constructed";
495
- const validation = validateAmendmentPayload(payload);
496
- if (!validation.valid)
497
- return `❌ Validation failed:\n${validation.errors.join("\n")}`;
498
- const proposal = await createProposal(args.title, "governance-change", args.description, "user");
499
- proposal.amendmentPayload = payload;
500
- proposal.amendmentOrigin = { source: "human" };
501
- proposal.amendmentState = "pending-vote";
502
- proposal.riskZone = classifyRiskZone(proposal);
503
- await saveState();
504
- await recordAudit(proposal.id, "governance", "amendment_proposed", "user", `Amendment: ${payload.type}`);
505
- return `# 📜 Amendment Proposed — #${proposal.id}\n\nType: ${payload.type}\n\nRun \`dao_deliberate proposalId=${proposal.id}\``;
403
+ const result = await new CreateAmendmentProposalUseCase({
404
+ repository: repositoryOrLegacy(repository),
405
+ clock: systemClock,
406
+ }).execute({ title: args.title, description: args.description, payload, proposedBy: "user" });
407
+ if (!result.ok)
408
+ return `❌ ${result.error}`;
409
+ return presentAmendment(result);
506
410
  }
507
- export async function handleDaoConfigGithub(_ctx, args) {
508
- const state = getState();
411
+ export async function handleDaoConfigGithub(ctx, args) {
412
+ const state = repositoryOrLegacy(ctx.repository).get();
509
413
  await saveGitHubConfigToDaoRoot(state.daoRoot, args);
510
414
  return [
511
415
  `# GitHub Configured`,
@@ -517,14 +421,15 @@ export async function handleDaoConfigGithub(_ctx, args) {
517
421
  "Available: `dao_github_create_branch`, `dao_github_open_pr`",
518
422
  ].join("\n");
519
423
  }
520
- export async function handleDaoGithubCreateBranch(_ctx, proposalId) {
521
- const notReady = requireInitialized();
424
+ export async function handleDaoGithubCreateBranch(ctx, proposalId) {
425
+ const repository = repositoryOrLegacy(ctx.repository);
426
+ const notReady = requireInitialized(ctx.repository);
522
427
  if (notReady)
523
428
  return notReady;
524
- const proposal = getProposal(proposalId);
429
+ const proposal = repository.get().proposals.find((candidate) => candidate.id === proposalId);
525
430
  if (!proposal)
526
431
  return `Proposal #${proposalId} not found.`;
527
- const configured = await loadGitHubConfigFromDaoRoot(getState().daoRoot);
432
+ const configured = await loadGitHubConfigFromDaoRoot(repository.get().daoRoot);
528
433
  if (!configured || !isGitHubEnabled()) {
529
434
  return "GitHub not configured. Run `dao_config_github` with token, owner, and repo.";
530
435
  }
@@ -534,16 +439,17 @@ export async function handleDaoGithubCreateBranch(_ctx, proposalId) {
534
439
  return "Failed to create branch (GitHub API returned null)";
535
440
  return `# Branch Created\n\n**Branch:** ${branchName}\n**SHA:** ${result.sha.slice(0, 7)}`;
536
441
  }
537
- export async function handleDaoGithubOpenPr(_ctx, proposalId, headBranch) {
538
- const notReady = requireInitialized();
442
+ export async function handleDaoGithubOpenPr(ctx, proposalId, headBranch) {
443
+ const repository = repositoryOrLegacy(ctx.repository);
444
+ const notReady = requireInitialized(ctx.repository);
539
445
  if (notReady)
540
446
  return notReady;
541
- const proposal = getProposal(proposalId);
447
+ const proposal = repository.get().proposals.find((candidate) => candidate.id === proposalId);
542
448
  if (!proposal)
543
449
  return `Proposal #${proposalId} not found.`;
544
450
  if (!headBranch)
545
451
  return "headBranch is required";
546
- const configured = await loadGitHubConfigFromDaoRoot(getState().daoRoot);
452
+ const configured = await loadGitHubConfigFromDaoRoot(repository.get().daoRoot);
547
453
  if (!configured || !isGitHubEnabled()) {
548
454
  return "GitHub not configured. Run `dao_config_github` with token, owner, and repo.";
549
455
  }