@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
@@ -0,0 +1,155 @@
1
+ // ============================================================
2
+ // Swarm DAO Core — Ship Audit Delivery (fingerprint + gate)
3
+ // ============================================================
4
+ // Deterministic glue between the ship handler and the audit machine:
5
+ // - computeShipFingerprint: canonical sha256 over the proposal's
6
+ // decision-relevant content (anything that changes the decision must
7
+ // re-challenge — INV-2). Uses node:crypto; lives OUTSIDE src/models to
8
+ // respect the models purity contract.
9
+ // - evaluateShipAuditChallenge: the gate the handler consults before
10
+ // ShipProposalUseCase. Never mutates proposal state. The challenge binds
11
+ // the decision fingerprint AND the ship options (cascade): changing the
12
+ // operation between challenge and confirmation re-issues the challenge.
13
+ // The read→transition→write sequence runs under an exclusive cross-process
14
+ // claim, so one confirmation can never authorize concurrent ships (INV-6).
15
+ import { createHash } from "node:crypto";
16
+ import { computeShipAuditDecision, createShipAuditActor, } from "../models/ship-audit.machine.js";
17
+ /** Canonical decision-relevant content of a proposal. Pure data selection. */
18
+ function decisionContent(proposal) {
19
+ const control = proposal.riskZone ? { riskZone: proposal.riskZone } : {};
20
+ return {
21
+ id: proposal.id,
22
+ title: proposal.title,
23
+ type: proposal.type,
24
+ description: proposal.description,
25
+ status: proposal.status,
26
+ dependsOn: proposal.dependsOn ?? [],
27
+ votes: (proposal.votes ?? []).map((vote) => ({
28
+ agentId: vote.agentId,
29
+ position: vote.position,
30
+ weight: vote.weight,
31
+ })),
32
+ control,
33
+ };
34
+ }
35
+ /** sha256 over canonical JSON of the decision content. Deterministic. */
36
+ export function computeShipFingerprint(proposal) {
37
+ const canonical = JSON.stringify(decisionContent(proposal), null, 0);
38
+ return createHash("sha256").update(canonical).digest("hex");
39
+ }
40
+ /**
41
+ * The challenge binds the decision fingerprint plus the operation options:
42
+ * a single-proposal command must not morph into a cascading execution (or
43
+ * the reverse) under one confirmation.
44
+ */
45
+ function requestSignature(fingerprint, options) {
46
+ return createHash("sha256")
47
+ .update(`${fingerprint}|${JSON.stringify({ cascade: options.cascade === true })}`)
48
+ .digest("hex");
49
+ }
50
+ const REQUEST = (fingerprint) => ({ type: "SHIP_REQUESTED", source: "system", fingerprint, occurredAt: "1970-01-01T00:00:00.000Z" });
51
+ function snapshotOf(actor, count) {
52
+ const snap = actor.getSnapshot();
53
+ return {
54
+ proposalId: snap.context.proposalId,
55
+ state: String(snap.value),
56
+ status: String(snap.status),
57
+ context: { ...snap.context, challengeCount: count },
58
+ };
59
+ }
60
+ /**
61
+ * Rebuild a live actor from a persisted snapshot by deterministic replay:
62
+ * challenged = one request with the persisted signature, confirmed = two.
63
+ * Terminal contexts never block later cycles (review: cycle semantics) — a
64
+ * new ship call on a still-controlled proposal starts fresh.
65
+ */
66
+ function hydrate(persisted, proposalId) {
67
+ const count = persisted?.context.challengeCount ?? 0;
68
+ const actor = createShipAuditActor(proposalId);
69
+ const fingerprint = persisted?.context.fingerprint ?? null;
70
+ if (!fingerprint)
71
+ return { actor, count };
72
+ if (persisted?.state === "challenged") {
73
+ actor.send(REQUEST(fingerprint));
74
+ }
75
+ else if (persisted?.state === "confirmed") {
76
+ actor.send(REQUEST(fingerprint));
77
+ actor.send(REQUEST(fingerprint));
78
+ }
79
+ return { actor, count };
80
+ }
81
+ /**
82
+ * The deterministic ship gate (models/ship-audit.md):
83
+ * - challenge disabled → proceed unchanged (N1)
84
+ * - force → human bypass, recorded (N6) — the record MUST persist, so a
85
+ * store failure blocks the bypass instead of silently losing evidence
86
+ * - first call → AUDIT_REQUIRED, nothing executes (N2)
87
+ * - unchanged call (same decision AND same options) → proceed, with a
88
+ * `consume()` that spends the single confirmation (N3, INV-6)
89
+ * - changed decision or options → re-challenge (N4)
90
+ * - concurrent gate for the same proposal → blocked while claimed (INV-6)
91
+ */
92
+ export async function evaluateShipAuditChallenge(input) {
93
+ if (!input.challengeEnabled)
94
+ return { proceed: true };
95
+ const claim = await input.store.claim(input.proposal.id);
96
+ if (!claim.acquired) {
97
+ return {
98
+ proceed: false,
99
+ message: `A concurrent ship gate for proposal #${input.proposal.id} is in flight; retry once it completes.`,
100
+ };
101
+ }
102
+ try {
103
+ return await gate(input);
104
+ }
105
+ finally {
106
+ await claim.release();
107
+ }
108
+ }
109
+ async function gate(input) {
110
+ const persisted = await input.store.load(input.proposal.id).catch(() => null);
111
+ const { actor, count } = hydrate(persisted, input.proposal.id);
112
+ if (input.force) {
113
+ actor.send({
114
+ type: "FORCE_OVERRIDE",
115
+ source: "human",
116
+ reason: input.forceReason ?? "operator force",
117
+ occurredAt: input.occurredAt ?? new Date().toISOString(),
118
+ });
119
+ // A bypass is only as good as its record: fail closed if it cannot persist.
120
+ await input.store.save(snapshotOf(actor, count));
121
+ return { proceed: true, note: "ship audit bypassed by force (recorded)" };
122
+ }
123
+ const fingerprint = computeShipFingerprint(input.proposal);
124
+ const signature = requestSignature(fingerprint, input.options ?? {});
125
+ actor.send({ ...REQUEST(signature), occurredAt: input.occurredAt ?? new Date().toISOString() });
126
+ // The historical challenge counter lives here (the actor's own counter is
127
+ // per-cycle): a new challenge — first of a cycle or a re-challenge after a
128
+ // changed decision or options — increments it; a confirmation does not.
129
+ const stateAfterRequest = String(actor.getSnapshot().value);
130
+ const liveCount = stateAfterRequest === "challenged" ? count + 1 : count;
131
+ await input.store.save(snapshotOf(actor, liveCount));
132
+ const decision = computeShipAuditDecision(actor.getSnapshot().value);
133
+ if (decision === "PROCEED") {
134
+ return {
135
+ proceed: true,
136
+ consume: async () => {
137
+ actor.send({ type: "SHIP_CONSUMED", source: "system", occurredAt: new Date().toISOString() });
138
+ await input.store.save(snapshotOf(actor, liveCount));
139
+ },
140
+ };
141
+ }
142
+ if (decision === "BLOCKED") {
143
+ const state = String(actor.getSnapshot().value);
144
+ return { proceed: false, message: `Ship audit context is ${state}; start a new audit cycle.` };
145
+ }
146
+ return {
147
+ proceed: false,
148
+ message: [
149
+ `AUDIT_REQUIRED — ship challenge ${liveCount} for proposal #${input.proposal.id}.`,
150
+ "The first call never executes. Re-read the proposal and the control results, then call dao_ship again unchanged — the same decision AND the same options (cascade).",
151
+ `Fingerprint: ${fingerprint.slice(0, 12)}… — any change to the decision (votes, gates, scope) or the options re-issues the challenge.`,
152
+ ].join("\n"),
153
+ };
154
+ }
155
+ //# sourceMappingURL=ship-audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ship-audit.js","sourceRoot":"","sources":["../../src/delivery/ship-audit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { DryRunResult, Proposal } from "../types/index.js";
2
+ export declare function analyzeProposalDryRun(proposal: Proposal): DryRunResult;
3
+ //# sourceMappingURL=dry-run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dry-run.d.ts","sourceRoot":"","sources":["../../src/domain/dry-run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAWhE,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,GAAG,YAAY,CAetE"}
@@ -0,0 +1,28 @@
1
+ import { PROPOSAL_TYPE } from "../types/index.js";
2
+ const DURATION_BY_TYPE = {
3
+ [PROPOSAL_TYPE.PRODUCT_FEATURE]: "3-7 days",
4
+ [PROPOSAL_TYPE.SECURITY_CHANGE]: "1-2 weeks",
5
+ [PROPOSAL_TYPE.TECHNICAL_CHANGE]: "2-5 days",
6
+ [PROPOSAL_TYPE.RELEASE_CHANGE]: "1-3 days",
7
+ [PROPOSAL_TYPE.GOVERNANCE_CHANGE]: "1-2 days",
8
+ };
9
+ export function analyzeProposalDryRun(proposal) {
10
+ const filesAffected = [...(proposal.affectedPaths ?? [])];
11
+ const risks = [];
12
+ if (proposal.type === PROPOSAL_TYPE.SECURITY_CHANGE)
13
+ risks.push("Security-sensitive changes require extra review");
14
+ if (proposal.riskZone === "red")
15
+ risks.push("Red-zone proposal: high risk detected");
16
+ if (!proposal.acceptanceCriteria?.length)
17
+ risks.push("No acceptance criteria defined");
18
+ const estimatedDuration = DURATION_BY_TYPE[proposal.type];
19
+ return {
20
+ proposalId: proposal.id,
21
+ preview: `This proposal would modify ${filesAffected.length || "unknown number of"} files and requires ${estimatedDuration}.`,
22
+ filesAffected,
23
+ risks,
24
+ estimatedDuration,
25
+ canProceed: !risks.some((risk) => risk.includes("high risk") || risk.includes("Security-sensitive")),
26
+ };
27
+ }
28
+ //# sourceMappingURL=dry-run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dry-run.js","sourceRoot":"","sources":["../../src/domain/dry-run.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,MAAM,gBAAgB,GAAqC;IACzD,CAAC,aAAa,CAAC,eAAe,CAAC,EAAE,UAAU;IAC3C,CAAC,aAAa,CAAC,eAAe,CAAC,EAAE,WAAW;IAC5C,CAAC,aAAa,CAAC,gBAAgB,CAAC,EAAE,UAAU;IAC5C,CAAC,aAAa,CAAC,cAAc,CAAC,EAAE,UAAU;IAC1C,CAAC,aAAa,CAAC,iBAAiB,CAAC,EAAE,UAAU;CAC9C,CAAC;AAEF,MAAM,UAAU,qBAAqB,CAAC,QAAkB;IACtD,MAAM,aAAa,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,CAAC;IAC1D,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,QAAQ,CAAC,IAAI,KAAK,aAAa,CAAC,eAAe;QAAE,KAAK,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;IACnH,IAAI,QAAQ,CAAC,QAAQ,KAAK,KAAK;QAAE,KAAK,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;IACrF,IAAI,CAAC,QAAQ,CAAC,kBAAkB,EAAE,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;IACvF,MAAM,iBAAiB,GAAG,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC1D,OAAO;QACL,UAAU,EAAE,QAAQ,CAAC,EAAE;QACvB,OAAO,EAAE,8BAA8B,aAAa,CAAC,MAAM,IAAI,mBAAmB,uBAAuB,iBAAiB,GAAG;QAC7H,aAAa;QACb,KAAK;QACL,iBAAiB;QACjB,UAAU,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;KACrG,CAAC;AACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ export * from "../delivery/dependencies.js";
2
+ export * from "../governance/lifecycle.js";
3
+ export * from "../governance/scoring.js";
4
+ export * from "../governance/voting.js";
5
+ export * from "./dry-run.js";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/domain/index.ts"],"names":[],"mappings":"AAEA,cAAc,6BAA6B,CAAC;AAC5C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,cAAc,CAAC"}
@@ -0,0 +1,7 @@
1
+ // Pure domain surface. These modules contain calculations and rules only.
2
+ export * from "../delivery/dependencies.js";
3
+ export * from "../governance/lifecycle.js";
4
+ export * from "../governance/scoring.js";
5
+ export * from "../governance/voting.js";
6
+ export * from "./dry-run.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/domain/index.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAE1E,cAAc,6BAA6B,CAAC;AAC5C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,cAAc,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/governance/agents.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAElD,eAAO,MAAM,mBAAmB,iBAAiB,CAAC;AAElD,eAAO,MAAM,cAAc,EAAE,QAAQ,EAgSpC,CAAC;AA4DF,gFAAgF;AAChF,wBAAgB,2BAA2B,IAAI,IAAI,CAElD;AA8BD,wBAAsB,gCAAgC,CACpD,SAAS,EAAE,MAAM,EACjB,UAAU,GAAE,QAAQ,EAAmB,GACtC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAuCrB;AAED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAuB9G;AAED,wBAAgB,gBAAgB,CAAC,YAAY,CAAC,EAAE,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAKtE;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAM5D;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAMvD;AAED,wBAAgB,sBAAsB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAE/D"}
1
+ {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/governance/agents.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAGlD,eAAO,MAAM,mBAAmB,iBAAiB,CAAC;AAElD,eAAO,MAAM,cAAc,EAAE,QAAQ,EAoJpC,CAAC;AAgEF,gFAAgF;AAChF,wBAAgB,2BAA2B,IAAI,IAAI,CAElD;AA+DD,wBAAsB,gCAAgC,CACpD,SAAS,EAAE,MAAM,EACjB,UAAU,GAAE,QAAQ,EAAmB,GACtC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAiDrB;AAED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CA2B9G;AA2BD,wBAAgB,gBAAgB,CAAC,YAAY,CAAC,EAAE,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAStE;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAM5D;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAMvD;AAED,wBAAgB,sBAAsB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAE/D"}
@@ -4,6 +4,7 @@
4
4
  import { promises as fs } from "node:fs";
5
5
  import path from "node:path";
6
6
  import { filterEnabledAgents } from "../config.js";
7
+ import { AGENT_CHARTER, composeSystemPrompt } from "./charter.js";
7
8
  export const DEFAULT_AGENT_MODEL = "z.ai/GLM-5.1";
8
9
  export const DEFAULT_AGENTS = [
9
10
  {
@@ -20,27 +21,7 @@ For each proposal, analyze:
20
21
  1. Strategic alignment — does this fit the product vision?
21
22
  2. Objectives — which OKRs or goals does this advance?
22
23
  3. Hypotheses — what assumptions underlie this proposal?
23
- 4. Opportunity cost — what are we NOT doing if we do this?
24
-
25
- Output format:
26
- ## Analysis
27
- [Your strategic analysis]
28
-
29
- ## Vote
30
- for | against | abstain
31
-
32
- ## Reasoning
33
- [Why you voted this way]
34
-
35
- ## Composite Score Inputs (0-10)
36
- - userImpact: [0-10]
37
- - businessImpact: [0-10]
38
- - effort: [0-10] (lower = less effort)
39
- - securityRisk: [0-10] (lower = less risk)
40
- - confidence: [0-10]
41
-
42
- ## Risk Score (1-10)
43
- [Overall risk assessment]`,
24
+ 4. Opportunity cost — what are we NOT doing if we do this?`,
44
25
  riskLevel: "medium",
45
26
  councils: [{ council: "product-council", role: "lead" }],
46
27
  enabled: true,
@@ -59,27 +40,7 @@ For each proposal, research:
59
40
  1. Market context — trends, market size, growth
60
41
  2. Competition — what are competitors doing?
61
42
  3. User signals — feedback, requests, pain points
62
- 4. Data availability — do we have evidence to support this?
63
-
64
- Output format:
65
- ## Analysis
66
- [Your research findings]
67
-
68
- ## Vote
69
- for | against | abstain
70
-
71
- ## Reasoning
72
- [Why you voted this way]
73
-
74
- ## Composite Score Inputs (0-10)
75
- - userImpact: [0-10]
76
- - businessImpact: [0-10]
77
- - effort: [0-10]
78
- - securityRisk: [0-10]
79
- - confidence: [0-10]
80
-
81
- ## Risk Score (1-10)
82
- [Overall risk assessment]`,
43
+ 4. Data availability — do we have evidence to support this?`,
83
44
  riskLevel: "low",
84
45
  councils: [{ council: "product-council", role: "member" }],
85
46
  enabled: true,
@@ -99,27 +60,7 @@ For each proposal, analyze:
99
60
  2. Architecture impact — how does this affect system design?
100
61
  3. Tradeoffs — what are the key technical tradeoffs?
101
62
  4. Technical debt — will this create or reduce debt?
102
- 5. Scalability — will this scale with our growth?
103
-
104
- Output format:
105
- ## Analysis
106
- [Your technical analysis]
107
-
108
- ## Vote
109
- for | against | abstain
110
-
111
- ## Reasoning
112
- [Why you voted this way]
113
-
114
- ## Composite Score Inputs (0-10)
115
- - userImpact: [0-10]
116
- - businessImpact: [0-10]
117
- - effort: [0-10]
118
- - securityRisk: [0-10]
119
- - confidence: [0-10]
120
-
121
- ## Risk Score (1-10)
122
- [Overall risk assessment]`,
63
+ 5. Scalability — will this scale with our growth?`,
123
64
  riskLevel: "medium",
124
65
  councils: [{ council: "delivery-council", role: "lead" }],
125
66
  enabled: true,
@@ -139,27 +80,7 @@ For each proposal, scrutinize:
139
80
  2. Edge cases — what scenarios aren't covered?
140
81
  3. Guardrails — are sufficient protections in place?
141
82
  4. Downside — what's the worst-case outcome?
142
- 5. Unknown unknowns — what haven't we considered?
143
-
144
- Output format:
145
- ## Analysis
146
- [Your risk analysis and objections]
147
-
148
- ## Vote
149
- for | against | abstain
150
-
151
- ## Reasoning
152
- [Why you voted this way]
153
-
154
- ## Composite Score Inputs (0-10)
155
- - userImpact: [0-10]
156
- - businessImpact: [0-10]
157
- - effort: [0-10]
158
- - securityRisk: [0-10]
159
- - confidence: [0-10]
160
-
161
- ## Risk Score (1-10)
162
- [Overall risk assessment]`,
83
+ 5. Unknown unknowns — what haven't we considered?`,
163
84
  riskLevel: "high",
164
85
  councils: [
165
86
  { council: "security-council", role: "lead" },
@@ -182,27 +103,7 @@ For each proposal, score:
182
103
  2. Cost — implementation effort, maintenance burden
183
104
  3. Risk — probability of failure, downside exposure
184
105
  4. Roadmap fit — does this belong in our current sequence?
185
- 5. Urgency — how time-sensitive is this?
186
-
187
- Output format:
188
- ## Analysis
189
- [Your prioritization analysis]
190
-
191
- ## Vote
192
- for | against | abstain
193
-
194
- ## Reasoning
195
- [Why you voted this way]
196
-
197
- ## Composite Score Inputs (0-10)
198
- - userImpact: [0-10]
199
- - businessImpact: [0-10]
200
- - effort: [0-10]
201
- - securityRisk: [0-10]
202
- - confidence: [0-10]
203
-
204
- ## Risk Score (1-10)
205
- [Overall risk assessment]`,
106
+ 5. Urgency — how time-sensitive is this?`,
206
107
  riskLevel: "low",
207
108
  councils: [{ council: "product-council", role: "member" }],
208
109
  enabled: true,
@@ -222,27 +123,7 @@ For each proposal, assess:
222
123
  2. Completeness — what's missing from the spec?
223
124
  3. Testability — can we write acceptance criteria?
224
125
  4. User stories — can this be broken into stories?
225
- 5. Edge cases — are boundary conditions defined?
226
-
227
- Output format:
228
- ## Analysis
229
- [Your specification analysis]
230
-
231
- ## Vote
232
- for | against | abstain
233
-
234
- ## Reasoning
235
- [Why you voted this way]
236
-
237
- ## Composite Score Inputs (0-10)
238
- - userImpact: [0-10]
239
- - businessImpact: [0-10]
240
- - effort: [0-10]
241
- - securityRisk: [0-10]
242
- - confidence: [0-10]
243
-
244
- ## Risk Score (1-10)
245
- [Overall risk assessment]`,
126
+ 5. Edge cases — are boundary conditions defined?`,
246
127
  riskLevel: "low",
247
128
  councils: [{ council: "product-council", role: "advisor" }],
248
129
  enabled: true,
@@ -262,27 +143,7 @@ For each proposal, plan:
262
143
  2. Task breakdown — what are the key tasks?
263
144
  3. Effort estimate — rough timeline and resources
264
145
  4. CI/CD impact — how does this affect pipelines?
265
- 5. Dependencies — what must happen first?
266
-
267
- Output format:
268
- ## Analysis
269
- [Your delivery analysis]
270
-
271
- ## Vote
272
- for | against | abstain
273
-
274
- ## Reasoning
275
- [Why you voted this way]
276
-
277
- ## Composite Score Inputs (0-10)
278
- - userImpact: [0-10]
279
- - businessImpact: [0-10]
280
- - effort: [0-10]
281
- - securityRisk: [0-10]
282
- - confidence: [0-10]
283
-
284
- ## Risk Score (1-10)
285
- [Overall risk assessment]`,
146
+ 5. Dependencies — what must happen first?`,
286
147
  riskLevel: "medium",
287
148
  councils: [{ council: "delivery-council", role: "member" }],
288
149
  enabled: true,
@@ -291,7 +152,7 @@ for | against | abstain
291
152
  function parseAgentFrontmatter(content) {
292
153
  const match = content.match(/^---\n([\s\S]*?)\n---/);
293
154
  if (!match?.[1])
294
- return {};
155
+ return { body: content.trim() || undefined };
295
156
  const parsed = {};
296
157
  for (const line of match[1].split("\n")) {
297
158
  const field = line.match(/^([A-Za-z0-9_-]+):\s*(.+)$/);
@@ -321,6 +182,11 @@ function parseAgentFrontmatter(content) {
321
182
  break;
322
183
  }
323
184
  }
185
+ // The markdown body is the per-agent project layer (## Project
186
+ // Instructions); frontmatter fields still override agent metadata.
187
+ const body = content.slice(match[0].length).trim();
188
+ if (body)
189
+ parsed.body = body;
324
190
  return parsed;
325
191
  }
326
192
  const agentDefinitionCache = new Map();
@@ -334,23 +200,48 @@ export function __resetAgentDefinitionCache() {
334
200
  function withDefaultModel(agents) {
335
201
  return agents.map((agent) => ({ ...agent, model: agent.model ?? DEFAULT_AGENT_MODEL }));
336
202
  }
337
- async function readAndMergeMarkdownAgents(absDir, daoEntries, baseAgents) {
203
+ async function readAndMergeMarkdownAgents(absDir, daoEntries, baseAgents, base) {
338
204
  const markdownAgents = new Map();
339
- for (const entry of daoEntries) {
205
+ const parsedEntries = await Promise.all(daoEntries.map(async (entry) => {
340
206
  const content = await fs.readFile(path.join(absDir, entry), "utf-8");
341
- const frontmatter = parseAgentFrontmatter(content);
207
+ return parseAgentFrontmatter(content);
208
+ }));
209
+ for (const frontmatter of parsedEntries) {
342
210
  if (frontmatter.id) {
343
211
  markdownAgents.set(frontmatter.id, frontmatter);
344
212
  }
345
213
  }
346
- return baseAgents.map((agent) => {
214
+ // The per-project charter layer applies to every agent (swarm-forge
215
+ // local-* convention: layers add to the shared law, never replace it).
216
+ // The closest directory wins: .dao/agents beats the repo's agents/.
217
+ let projectCharter = base.projectCharter;
218
+ if (projectCharter === null) {
219
+ try {
220
+ const charter = await fs.readFile(path.join(absDir, "charter.md"), "utf-8");
221
+ if (charter.trim())
222
+ projectCharter = charter.trim();
223
+ }
224
+ catch {
225
+ // No project charter here — keep looking in the remaining dirs.
226
+ }
227
+ }
228
+ const agents = baseAgents.map((agent) => {
347
229
  const override = markdownAgents.get(agent.id);
230
+ if (!override)
231
+ return agent;
232
+ // The markdown body is the agent's role definition — it REPLACES the
233
+ // default role prompt (consistent with the frontmatter, which already
234
+ // overrides name/role/model/weight). The shared charter is never
235
+ // replaceable: composition always prepends it.
236
+ const { body: _body, ...fields } = override;
348
237
  return {
349
238
  ...agent,
350
- ...(override ?? {}),
351
- model: override?.model ?? agent.model ?? DEFAULT_AGENT_MODEL,
239
+ ...fields,
240
+ ...(override.body ? { systemPrompt: override.body } : {}),
241
+ model: override.model ?? agent.model ?? DEFAULT_AGENT_MODEL,
352
242
  };
353
243
  });
244
+ return { agents, projectCharter };
354
245
  }
355
246
  export async function loadAgentDefinitionsFromMarkdown(agentsDir, baseAgents = DEFAULT_AGENTS) {
356
247
  const absDir = path.resolve(agentsDir);
@@ -360,15 +251,21 @@ export async function loadAgentDefinitionsFromMarkdown(agentsDir, baseAgents = D
360
251
  entries = await fs.readdir(absDir);
361
252
  }
362
253
  catch {
363
- // Directory missing/unreadable: behave exactly as before and do NOT cache.
364
- return withDefaultModel(baseAgents);
254
+ // Directory missing/unreadable: do NOT cache, but still compose a
255
+ // missing directory must yield the same charter-backed prompts as an
256
+ // existing empty one.
257
+ return withComposedPrompts(withDefaultModel(baseAgents), null);
365
258
  }
366
259
  const daoEntries = entries.filter((entry) => entry.startsWith("dao-") && entry.endsWith(".md"));
367
- // Build a signature over the dao-*.md entries and their stat metadata so the
368
- // cache invalidates whenever an agent file is added, removed, or modified.
260
+ // Build a signature over the dao-*.md entries (and charter.md, which is
261
+ // also a cached layer) and their stat metadata so the cache invalidates
262
+ // whenever a file is added, removed, or modified.
369
263
  let signature;
370
264
  try {
371
- const parts = await Promise.all(daoEntries.map(async (entry) => {
265
+ const signatureEntries = [...daoEntries];
266
+ if (entries.includes("charter.md"))
267
+ signatureEntries.push("charter.md");
268
+ const parts = await Promise.all(signatureEntries.map(async (entry) => {
372
269
  const fileStat = await fs.stat(path.join(absDir, entry));
373
270
  return `${entry}:${fileStat.mtimeMs}:${fileStat.size}`;
374
271
  }));
@@ -383,7 +280,12 @@ export async function loadAgentDefinitionsFromMarkdown(agentsDir, baseAgents = D
383
280
  // Cache hit: return the merged result without re-reading files.
384
281
  return cached.result;
385
282
  }
386
- const result = await readAndMergeMarkdownAgents(absDir, daoEntries, baseAgents);
283
+ const layers = await readAndMergeMarkdownAgents(absDir, daoEntries, withDefaultModel(baseAgents), {
284
+ agents: withDefaultModel(baseAgents),
285
+ projectCharter: null,
286
+ });
287
+ // Composition happens exactly once, at the exit.
288
+ const result = withComposedPrompts(layers.agents, layers.projectCharter);
387
289
  agentDefinitionCache.set(cacheKey, { signature, result });
388
290
  return result;
389
291
  }
@@ -393,24 +295,60 @@ export async function loadAgentDefinitions(daoRoot, projectConfig) {
393
295
  path.join(daoRoot, "..", "agents"),
394
296
  path.join(daoRoot, "..", "..", "agents"),
395
297
  ];
396
- let agents = initializeAgents();
298
+ // Layer collection over the candidate dirs, closest first. Composition
299
+ // happens exactly once, after collection, so the shared charter is never
300
+ // duplicated across the chain.
301
+ let layers = {
302
+ agents: withDefaultModel(DEFAULT_AGENTS),
303
+ projectCharter: null,
304
+ };
397
305
  for (const agentsDir of candidateDirs) {
398
- const loaded = await loadAgentDefinitionsFromMarkdown(agentsDir, agents);
399
- const hasMarkdownOverrides = loaded.some((agent, index) => agent.model !== agents[index]?.model ||
400
- agent.name !== agents[index]?.name ||
401
- agent.role !== agents[index]?.role);
402
- if (hasMarkdownOverrides) {
403
- agents = loaded;
306
+ const merged = await readMarkdownLayers(agentsDir, layers);
307
+ // Closest layer wins: the first candidate directory holding agent
308
+ // definitions or a charter fully shadows the further ones, so project
309
+ // overrides (.dao/agents) are never replaced by repo defaults (agents/).
310
+ if (merged) {
311
+ layers = merged;
404
312
  break;
405
313
  }
406
314
  }
315
+ const agents = withComposedPrompts(layers.agents, layers.projectCharter);
407
316
  return projectConfig ? filterEnabledAgents(agents, projectConfig) : agents;
408
317
  }
318
+ /** Apply the charter + project layers to role-level agents (composition exit). */
319
+ function withComposedPrompts(agents, projectCharter) {
320
+ // Per-agent: mixed lists (some prompts already composed, some not) compose
321
+ // exactly the ones that need it — composeSystemPrompt is idempotent.
322
+ return agents.map((agent) => ({
323
+ ...agent,
324
+ systemPrompt: composeSystemPrompt(agent.systemPrompt, { projectCharter }),
325
+ }));
326
+ }
327
+ /** Read and merge one directory's markdown layers; null when it has none. */
328
+ async function readMarkdownLayers(agentsDir, base) {
329
+ const absDir = path.resolve(agentsDir);
330
+ let entries;
331
+ try {
332
+ entries = await fs.readdir(absDir);
333
+ }
334
+ catch {
335
+ return null;
336
+ }
337
+ const daoEntries = entries.filter((entry) => entry.startsWith("dao-") && entry.endsWith(".md"));
338
+ const hasCharter = entries.includes("charter.md");
339
+ if (daoEntries.length === 0 && !hasCharter)
340
+ return null;
341
+ return readAndMergeMarkdownAgents(absDir, daoEntries, base.agents, base);
342
+ }
409
343
  export function initializeAgents(customAgents) {
410
344
  if (customAgents && customAgents.length > 0) {
411
345
  return customAgents;
412
346
  }
413
- return DEFAULT_AGENTS.map((a) => ({ ...a, model: a.model ?? DEFAULT_AGENT_MODEL }));
347
+ return DEFAULT_AGENTS.map((a) => ({
348
+ ...a,
349
+ systemPrompt: composeSystemPrompt(a.systemPrompt),
350
+ model: a.model ?? DEFAULT_AGENT_MODEL,
351
+ }));
414
352
  }
415
353
  export function formatAgentsTable(agents) {
416
354
  let table = "| Agent | Weight | Role |\n|-------|--------|------|\n";
@@ -427,6 +365,6 @@ export function formatAgentCard(agent) {
427
365
  - **Description:** ${agent.description}`;
428
366
  }
429
367
  export function getDefaultAgentPrompts() {
430
- return Object.fromEntries(DEFAULT_AGENTS.map((a) => [a.id, a.systemPrompt]));
368
+ return Object.fromEntries(DEFAULT_AGENTS.map((a) => [a.id, composeSystemPrompt(a.systemPrompt)]));
431
369
  }
432
370
  //# sourceMappingURL=agents.js.map