chati-dev 1.4.0 → 2.0.1

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 (200) hide show
  1. package/README.md +3 -3
  2. package/framework/agents/build/dev.md +343 -0
  3. package/framework/agents/clarity/architect.md +112 -0
  4. package/framework/agents/clarity/brief.md +182 -0
  5. package/framework/agents/clarity/brownfield-wu.md +181 -0
  6. package/framework/agents/clarity/detail.md +110 -0
  7. package/framework/agents/clarity/greenfield-wu.md +153 -0
  8. package/framework/agents/clarity/ux.md +112 -0
  9. package/framework/config.yaml +3 -3
  10. package/framework/constitution.md +31 -1
  11. package/framework/context/governance.md +37 -0
  12. package/framework/context/protocols.md +34 -0
  13. package/framework/context/quality.md +27 -0
  14. package/framework/context/root.md +24 -0
  15. package/framework/domains/agents/architect.yaml +51 -0
  16. package/framework/domains/agents/brief.yaml +47 -0
  17. package/framework/domains/agents/brownfield-wu.yaml +49 -0
  18. package/framework/domains/agents/detail.yaml +47 -0
  19. package/framework/domains/agents/dev.yaml +49 -0
  20. package/framework/domains/agents/devops.yaml +43 -0
  21. package/framework/domains/agents/greenfield-wu.yaml +47 -0
  22. package/framework/domains/agents/orchestrator.yaml +49 -0
  23. package/framework/domains/agents/phases.yaml +47 -0
  24. package/framework/domains/agents/qa-implementation.yaml +43 -0
  25. package/framework/domains/agents/qa-planning.yaml +44 -0
  26. package/framework/domains/agents/tasks.yaml +48 -0
  27. package/framework/domains/agents/ux.yaml +50 -0
  28. package/framework/domains/constitution.yaml +77 -0
  29. package/framework/domains/global.yaml +64 -0
  30. package/framework/domains/workflows/brownfield-discovery.yaml +16 -0
  31. package/framework/domains/workflows/brownfield-fullstack.yaml +26 -0
  32. package/framework/domains/workflows/brownfield-service.yaml +22 -0
  33. package/framework/domains/workflows/brownfield-ui.yaml +22 -0
  34. package/framework/domains/workflows/greenfield-fullstack.yaml +26 -0
  35. package/framework/hooks/constitution-guard.js +101 -0
  36. package/framework/hooks/mode-governance.js +92 -0
  37. package/framework/hooks/model-governance.js +76 -0
  38. package/framework/hooks/prism-engine.js +89 -0
  39. package/framework/hooks/session-digest.js +60 -0
  40. package/framework/hooks/settings.json +44 -0
  41. package/framework/migrations/v1.4-to-v2.0.yaml +167 -0
  42. package/framework/migrations/v2.0-to-v2.0.1.yaml +132 -0
  43. package/framework/orchestrator/chati.md +284 -6
  44. package/framework/tasks/architect-api-design.md +63 -0
  45. package/framework/tasks/architect-consolidate.md +47 -0
  46. package/framework/tasks/architect-db-design.md +73 -0
  47. package/framework/tasks/architect-design.md +95 -0
  48. package/framework/tasks/architect-security-review.md +62 -0
  49. package/framework/tasks/architect-stack-selection.md +53 -0
  50. package/framework/tasks/brief-consolidate.md +249 -0
  51. package/framework/tasks/brief-constraint-identify.md +277 -0
  52. package/framework/tasks/brief-extract-requirements.md +339 -0
  53. package/framework/tasks/brief-stakeholder-map.md +176 -0
  54. package/framework/tasks/brief-validate-completeness.md +121 -0
  55. package/framework/tasks/brownfield-wu-architecture-map.md +394 -0
  56. package/framework/tasks/brownfield-wu-deep-discovery.md +312 -0
  57. package/framework/tasks/brownfield-wu-dependency-scan.md +359 -0
  58. package/framework/tasks/brownfield-wu-migration-plan.md +483 -0
  59. package/framework/tasks/brownfield-wu-report.md +325 -0
  60. package/framework/tasks/brownfield-wu-risk-assess.md +424 -0
  61. package/framework/tasks/detail-acceptance-criteria.md +372 -0
  62. package/framework/tasks/detail-consolidate.md +138 -0
  63. package/framework/tasks/detail-edge-case-analysis.md +300 -0
  64. package/framework/tasks/detail-expand-prd.md +389 -0
  65. package/framework/tasks/detail-nfr-extraction.md +223 -0
  66. package/framework/tasks/dev-code-review.md +404 -0
  67. package/framework/tasks/dev-consolidate.md +543 -0
  68. package/framework/tasks/dev-debug.md +322 -0
  69. package/framework/tasks/dev-implement.md +252 -0
  70. package/framework/tasks/dev-iterate.md +411 -0
  71. package/framework/tasks/dev-pr-prepare.md +497 -0
  72. package/framework/tasks/dev-refactor.md +342 -0
  73. package/framework/tasks/dev-test-write.md +306 -0
  74. package/framework/tasks/devops-ci-setup.md +412 -0
  75. package/framework/tasks/devops-consolidate.md +712 -0
  76. package/framework/tasks/devops-deploy-config.md +598 -0
  77. package/framework/tasks/devops-monitoring-setup.md +658 -0
  78. package/framework/tasks/devops-release-prepare.md +673 -0
  79. package/framework/tasks/greenfield-wu-analyze-empty.md +169 -0
  80. package/framework/tasks/greenfield-wu-report.md +266 -0
  81. package/framework/tasks/greenfield-wu-scaffold-detection.md +203 -0
  82. package/framework/tasks/greenfield-wu-tech-stack-assess.md +255 -0
  83. package/framework/tasks/orchestrator-deviation.md +260 -0
  84. package/framework/tasks/orchestrator-escalate.md +276 -0
  85. package/framework/tasks/orchestrator-handoff.md +243 -0
  86. package/framework/tasks/orchestrator-health.md +372 -0
  87. package/framework/tasks/orchestrator-mode-switch.md +262 -0
  88. package/framework/tasks/orchestrator-resume.md +189 -0
  89. package/framework/tasks/orchestrator-route.md +169 -0
  90. package/framework/tasks/orchestrator-spawn-terminal.md +358 -0
  91. package/framework/tasks/orchestrator-status.md +260 -0
  92. package/framework/tasks/orchestrator-suggest-mode.md +372 -0
  93. package/framework/tasks/phases-breakdown.md +91 -0
  94. package/framework/tasks/phases-dependency-mapping.md +67 -0
  95. package/framework/tasks/phases-mvp-scoping.md +94 -0
  96. package/framework/tasks/qa-impl-consolidate.md +522 -0
  97. package/framework/tasks/qa-impl-performance-test.md +487 -0
  98. package/framework/tasks/qa-impl-regression-check.md +413 -0
  99. package/framework/tasks/qa-impl-sast-scan.md +402 -0
  100. package/framework/tasks/qa-impl-test-execute.md +344 -0
  101. package/framework/tasks/qa-impl-verdict.md +339 -0
  102. package/framework/tasks/qa-planning-consolidate.md +309 -0
  103. package/framework/tasks/qa-planning-coverage-plan.md +338 -0
  104. package/framework/tasks/qa-planning-gate-define.md +339 -0
  105. package/framework/tasks/qa-planning-risk-matrix.md +631 -0
  106. package/framework/tasks/qa-planning-test-strategy.md +217 -0
  107. package/framework/tasks/tasks-acceptance-write.md +75 -0
  108. package/framework/tasks/tasks-consolidate.md +57 -0
  109. package/framework/tasks/tasks-decompose.md +80 -0
  110. package/framework/tasks/tasks-estimate.md +66 -0
  111. package/framework/tasks/ux-a11y-check.md +49 -0
  112. package/framework/tasks/ux-component-map.md +55 -0
  113. package/framework/tasks/ux-consolidate.md +46 -0
  114. package/framework/tasks/ux-user-flow.md +46 -0
  115. package/framework/tasks/ux-wireframe.md +76 -0
  116. package/package.json +1 -1
  117. package/scripts/bundle-framework.js +2 -0
  118. package/scripts/changelog-generator.js +222 -0
  119. package/scripts/codebase-mapper.js +728 -0
  120. package/scripts/commit-message-generator.js +167 -0
  121. package/scripts/coverage-analyzer.js +260 -0
  122. package/scripts/dependency-analyzer.js +280 -0
  123. package/scripts/framework-analyzer.js +308 -0
  124. package/scripts/generate-constitution-domain.js +253 -0
  125. package/scripts/health-check.js +481 -0
  126. package/scripts/ide-sync.js +327 -0
  127. package/scripts/performance-analyzer.js +325 -0
  128. package/scripts/plan-tracker.js +278 -0
  129. package/scripts/populate-entity-registry.js +481 -0
  130. package/scripts/pr-review.js +317 -0
  131. package/scripts/rollback-manager.js +310 -0
  132. package/scripts/stuck-detector.js +343 -0
  133. package/scripts/test-quality-assessment.js +257 -0
  134. package/scripts/validate-agents.js +367 -0
  135. package/scripts/validate-tasks.js +465 -0
  136. package/src/autonomy/autonomous-gate.js +293 -0
  137. package/src/autonomy/index.js +51 -0
  138. package/src/autonomy/mode-manager.js +225 -0
  139. package/src/autonomy/mode-suggester.js +283 -0
  140. package/src/autonomy/progress-reporter.js +268 -0
  141. package/src/autonomy/safety-net.js +320 -0
  142. package/src/context/bracket-tracker.js +79 -0
  143. package/src/context/domain-loader.js +107 -0
  144. package/src/context/engine.js +144 -0
  145. package/src/context/formatter.js +184 -0
  146. package/src/context/index.js +4 -0
  147. package/src/context/layers/l0-constitution.js +28 -0
  148. package/src/context/layers/l1-global.js +37 -0
  149. package/src/context/layers/l2-agent.js +39 -0
  150. package/src/context/layers/l3-workflow.js +42 -0
  151. package/src/context/layers/l4-task.js +24 -0
  152. package/src/decision/analyzer.js +167 -0
  153. package/src/decision/engine.js +270 -0
  154. package/src/decision/index.js +38 -0
  155. package/src/decision/registry-healer.js +450 -0
  156. package/src/decision/registry-updater.js +330 -0
  157. package/src/gates/circuit-breaker.js +119 -0
  158. package/src/gates/g1-planning-complete.js +153 -0
  159. package/src/gates/g2-qa-planning.js +153 -0
  160. package/src/gates/g3-implementation.js +188 -0
  161. package/src/gates/g4-qa-implementation.js +207 -0
  162. package/src/gates/g5-deploy-ready.js +180 -0
  163. package/src/gates/gate-base.js +144 -0
  164. package/src/gates/index.js +46 -0
  165. package/src/installer/brownfield-upgrader.js +249 -0
  166. package/src/installer/core.js +55 -3
  167. package/src/installer/file-hasher.js +51 -0
  168. package/src/installer/manifest.js +117 -0
  169. package/src/installer/templates.js +17 -15
  170. package/src/installer/transaction.js +229 -0
  171. package/src/installer/validator.js +18 -1
  172. package/src/memory/agent-memory.js +255 -0
  173. package/src/memory/gotchas-injector.js +72 -0
  174. package/src/memory/gotchas.js +361 -0
  175. package/src/memory/index.js +35 -0
  176. package/src/memory/search.js +233 -0
  177. package/src/memory/session-digest.js +239 -0
  178. package/src/merger/env-merger.js +112 -0
  179. package/src/merger/index.js +56 -0
  180. package/src/merger/replace-merger.js +51 -0
  181. package/src/merger/yaml-merger.js +127 -0
  182. package/src/orchestrator/agent-selector.js +285 -0
  183. package/src/orchestrator/deviation-handler.js +350 -0
  184. package/src/orchestrator/handoff-engine.js +271 -0
  185. package/src/orchestrator/index.js +67 -0
  186. package/src/orchestrator/intent-classifier.js +264 -0
  187. package/src/orchestrator/pipeline-manager.js +492 -0
  188. package/src/orchestrator/pipeline-state.js +223 -0
  189. package/src/orchestrator/session-manager.js +409 -0
  190. package/src/tasks/executor.js +195 -0
  191. package/src/tasks/handoff.js +226 -0
  192. package/src/tasks/index.js +4 -0
  193. package/src/tasks/loader.js +210 -0
  194. package/src/tasks/router.js +182 -0
  195. package/src/terminal/collector.js +216 -0
  196. package/src/terminal/index.js +30 -0
  197. package/src/terminal/isolation.js +129 -0
  198. package/src/terminal/monitor.js +277 -0
  199. package/src/terminal/spawner.js +269 -0
  200. package/src/upgrade/checker.js +1 -1
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Context Formatter — Produces structured XML for agent prompt injection.
3
+ *
4
+ * Output format: <chati-context bracket="..."> with nested sections.
5
+ * Truncates intelligently based on token budget via priority-based pruning.
6
+ */
7
+
8
+ /**
9
+ * Format PRISM pipeline results into XML context block.
10
+ * @param {object} options
11
+ * @param {string} options.bracket - Current bracket name
12
+ * @param {number} options.tokenBudget - Max approximate token count
13
+ * @param {object} options.l0 - L0 Constitution result
14
+ * @param {object} [options.l1] - L1 Global result
15
+ * @param {object} [options.l2] - L2 Agent result
16
+ * @param {object} [options.l3] - L3 Workflow result
17
+ * @param {object} [options.l4] - L4 Task result
18
+ * @returns {string} XML context block
19
+ */
20
+ export function formatContext(options) {
21
+ const { bracket, tokenBudget, l0, l1, l2, l3, l4 } = options;
22
+ const sections = [];
23
+
24
+ // L0 — Constitution (always present)
25
+ if (l0) {
26
+ sections.push(formatConstitution(l0));
27
+ }
28
+
29
+ // L1 — Mode + Global
30
+ if (l1) {
31
+ sections.push(formatGlobal(l1));
32
+ }
33
+
34
+ // L2 — Agent
35
+ if (l2 && l2.agent) {
36
+ sections.push(formatAgent(l2));
37
+ }
38
+
39
+ // L3 — Pipeline/Workflow
40
+ if (l3 && l3.workflow) {
41
+ sections.push(formatWorkflow(l3));
42
+ }
43
+
44
+ // L4 — Task
45
+ if (l4 && l4.taskId) {
46
+ sections.push(formatTask(l4));
47
+ }
48
+
49
+ let body = sections.join('\n\n');
50
+
51
+ // Truncate if over budget (rough estimate: 1 token ≈ 4 chars)
52
+ const maxChars = tokenBudget * 4;
53
+ if (body.length > maxChars) {
54
+ body = truncateByPriority(sections, maxChars);
55
+ }
56
+
57
+ return `<chati-context bracket="${bracket}">\n${body}\n</chati-context>`;
58
+ }
59
+
60
+ function formatConstitution(l0) {
61
+ const rulesText = l0.rules.length > 0
62
+ ? l0.rules.map(r => ` <rule id="${esc(r.id)}" priority="${esc(r.priority)}">${esc(r.text)}</rule>`).join('\n')
63
+ : ` <summary>${esc(l0.summary)}</summary>`;
64
+
65
+ return ` <constitution articles="${l0.articleCount}">\n${rulesText}\n </constitution>`;
66
+ }
67
+
68
+ function formatGlobal(l1) {
69
+ const lines = [];
70
+ lines.push(` <mode name="${esc(l1.mode)}">`);
71
+ if (l1.modeRules.writeScope) {
72
+ lines.push(` <write-scope>${esc(l1.modeRules.writeScope)}</write-scope>`);
73
+ }
74
+ if (l1.modeRules.allowedActions.length > 0) {
75
+ lines.push(` <allowed>${l1.modeRules.allowedActions.map(esc).join(', ')}</allowed>`);
76
+ }
77
+ if (l1.modeRules.blockedActions.length > 0) {
78
+ lines.push(` <blocked>${l1.modeRules.blockedActions.map(esc).join(', ')}</blocked>`);
79
+ }
80
+ lines.push(` </mode>`);
81
+
82
+ if (l1.rules.length > 0) {
83
+ lines.push(` <global-rules>`);
84
+ for (const r of l1.rules) {
85
+ lines.push(` <rule id="${esc(r.id)}">${esc(r.text)}</rule>`);
86
+ }
87
+ lines.push(` </global-rules>`);
88
+ }
89
+
90
+ return lines.join('\n');
91
+ }
92
+
93
+ function formatAgent(l2) {
94
+ const lines = [];
95
+ lines.push(` <agent name="${esc(l2.agent)}">`);
96
+ if (l2.mission) {
97
+ lines.push(` <mission>${esc(l2.mission)}</mission>`);
98
+ }
99
+ if (l2.authority.exclusive.length > 0) {
100
+ lines.push(` <exclusive>${l2.authority.exclusive.map(esc).join(', ')}</exclusive>`);
101
+ }
102
+ if (l2.authority.blocked.length > 0) {
103
+ lines.push(` <blocked>${l2.authority.blocked.map(esc).join(', ')}</blocked>`);
104
+ }
105
+ if (l2.outputs.length > 0) {
106
+ lines.push(` <outputs>${l2.outputs.map(esc).join(', ')}</outputs>`);
107
+ }
108
+ if (l2.rules.length > 0) {
109
+ for (const r of l2.rules) {
110
+ lines.push(` <rule id="${esc(r.id)}">${esc(r.text)}</rule>`);
111
+ }
112
+ }
113
+ lines.push(` </agent>`);
114
+ return lines.join('\n');
115
+ }
116
+
117
+ function formatWorkflow(l3) {
118
+ const p = l3.pipelineContext;
119
+ const lines = [];
120
+ lines.push(` <pipeline workflow="${esc(l3.workflow)}" progress="${p.progress}%">`);
121
+ if (p.previousStep) lines.push(` <previous>${esc(p.previousStep)}</previous>`);
122
+ if (p.currentStep) lines.push(` <current>${esc(p.currentStep)}</current>`);
123
+ if (p.nextStep) lines.push(` <next>${esc(p.nextStep)}</next>`);
124
+ if (l3.rules.length > 0) {
125
+ for (const r of l3.rules) {
126
+ lines.push(` <rule id="${esc(r.id)}">${esc(r.text)}</rule>`);
127
+ }
128
+ }
129
+ lines.push(` </pipeline>`);
130
+ return lines.join('\n');
131
+ }
132
+
133
+ function formatTask(l4) {
134
+ const lines = [];
135
+ lines.push(` <task id="${esc(l4.taskId)}">`);
136
+ if (l4.criteria.length > 0) {
137
+ lines.push(` <criteria>`);
138
+ for (const c of l4.criteria) {
139
+ lines.push(` <criterion>${esc(c)}</criterion>`);
140
+ }
141
+ lines.push(` </criteria>`);
142
+ }
143
+ if (l4.artifacts.length > 0) {
144
+ lines.push(` <artifacts>${l4.artifacts.map(esc).join(', ')}</artifacts>`);
145
+ }
146
+ if (Object.keys(l4.handoff).length > 0) {
147
+ lines.push(` <handoff>`);
148
+ for (const [key, val] of Object.entries(l4.handoff)) {
149
+ lines.push(` <${esc(key)}>${esc(String(val))}</${esc(key)}>`);
150
+ }
151
+ lines.push(` </handoff>`);
152
+ }
153
+ lines.push(` </task>`);
154
+ return lines.join('\n');
155
+ }
156
+
157
+ /**
158
+ * Truncate sections by removing lower-priority layers first (L4 → L3 → L2).
159
+ * L0 and L1 are never truncated.
160
+ */
161
+ function truncateByPriority(sections, maxChars) {
162
+ let result = sections.join('\n\n');
163
+ // Remove from end (lowest priority) until within budget
164
+ const trimmed = [...sections];
165
+ while (trimmed.length > 2 && result.length > maxChars) {
166
+ trimmed.pop();
167
+ result = trimmed.join('\n\n');
168
+ }
169
+ // If still over, hard truncate
170
+ if (result.length > maxChars) {
171
+ result = result.slice(0, maxChars) + '\n <!-- truncated -->';
172
+ }
173
+ return result;
174
+ }
175
+
176
+ /** Escape XML special characters */
177
+ function esc(str) {
178
+ if (!str) return '';
179
+ return String(str)
180
+ .replace(/&/g, '&amp;')
181
+ .replace(/</g, '&lt;')
182
+ .replace(/>/g, '&gt;')
183
+ .replace(/"/g, '&quot;');
184
+ }
@@ -0,0 +1,4 @@
1
+ export { runPrism, getPrismInfo } from './engine.js';
2
+ export { calculateBracket, estimateRemaining, isLayerActive, getBracketDefinitions } from './bracket-tracker.js';
3
+ export { formatContext } from './formatter.js';
4
+ export { loadDomainFile, loadAgentDomains, loadWorkflowDomains, extractRules } from './domain-loader.js';
@@ -0,0 +1,28 @@
1
+ /**
2
+ * L0 Constitution Layer — ALWAYS active, non-negotiable.
3
+ *
4
+ * Loads constitution rules from domain file. These are the fundamental
5
+ * governance rules that every agent must follow at all times.
6
+ */
7
+
8
+ import { loadConstitutionDomain, extractRules } from '../domain-loader.js';
9
+
10
+ /**
11
+ * Process L0: load constitution governance rules.
12
+ * @param {object} ctx - Pipeline context
13
+ * @param {string} ctx.domainsDir - Path to chati.dev/domains/
14
+ * @returns {{ layer: string, rules: Array, summary: string }}
15
+ */
16
+ export function processL0(ctx) {
17
+ const domain = loadConstitutionDomain(ctx.domainsDir);
18
+ const rules = extractRules(domain);
19
+
20
+ const summary = domain?.summary || 'Constitution governance: self-validation, quality >= 95%, guided options, persistent state, two-layer handoff, language protocol, deviation protocol, mode governance.';
21
+
22
+ return {
23
+ layer: 'L0',
24
+ rules,
25
+ summary,
26
+ articleCount: domain?.articleCount || rules.length,
27
+ };
28
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * L1 Global Layer — ALWAYS active.
3
+ *
4
+ * Loads global rules: coding standards, bracket-specific behavioral rules,
5
+ * mode governance constraints (clarity/build/deploy).
6
+ */
7
+
8
+ import { loadGlobalDomain, extractRules } from '../domain-loader.js';
9
+
10
+ /**
11
+ * Process L1: load global rules + mode governance.
12
+ * @param {object} ctx - Pipeline context
13
+ * @param {string} ctx.domainsDir - Path to chati.dev/domains/
14
+ * @param {string} ctx.mode - Current mode (clarity, build, deploy)
15
+ * @param {string} ctx.bracket - Current bracket (FRESH, MODERATE, etc.)
16
+ * @returns {{ layer: string, rules: Array, mode: string, modeRules: object }}
17
+ */
18
+ export function processL1(ctx) {
19
+ const domain = loadGlobalDomain(ctx.domainsDir);
20
+ const rules = extractRules(domain);
21
+ const mode = ctx.mode || 'clarity';
22
+
23
+ const modeRules = domain?.modes?.[mode] || {};
24
+ const bracketRules = domain?.brackets?.[ctx.bracket] || {};
25
+
26
+ return {
27
+ layer: 'L1',
28
+ rules,
29
+ mode,
30
+ modeRules: {
31
+ writeScope: modeRules.writeScope || 'chati.dev/',
32
+ allowedActions: modeRules.allowedActions || [],
33
+ blockedActions: modeRules.blockedActions || [],
34
+ },
35
+ bracketBehavior: bracketRules.behavior || 'normal',
36
+ };
37
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * L2 Agent Layer — Active when an agent is assigned.
3
+ *
4
+ * Loads agent-specific domain rules: authority boundaries,
5
+ * behavioral rules, and task registry.
6
+ */
7
+
8
+ import { loadAgentDomains, extractRules } from '../domain-loader.js';
9
+
10
+ /**
11
+ * Process L2: load agent domain rules.
12
+ * @param {object} ctx - Pipeline context
13
+ * @param {string} ctx.domainsDir - Path to chati.dev/domains/
14
+ * @param {string} ctx.agent - Active agent name (e.g. 'brief', 'dev', 'orchestrator')
15
+ * @returns {{ layer: string, agent: string, rules: Array, authority: object }}
16
+ */
17
+ export function processL2(ctx) {
18
+ if (!ctx.agent) {
19
+ return { layer: 'L2', agent: null, rules: [], authority: {} };
20
+ }
21
+
22
+ const allDomains = loadAgentDomains(ctx.domainsDir);
23
+ const domain = allDomains.get(ctx.agent) || null;
24
+ const rules = extractRules(domain);
25
+
26
+ return {
27
+ layer: 'L2',
28
+ agent: ctx.agent,
29
+ rules,
30
+ authority: {
31
+ exclusive: domain?.authority?.exclusive || [],
32
+ allowed: domain?.authority?.allowed || [],
33
+ blocked: domain?.authority?.blocked || [],
34
+ redirectMessage: domain?.authority?.redirectMessage || null,
35
+ },
36
+ mission: domain?.mission || '',
37
+ outputs: domain?.outputs || [],
38
+ };
39
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * L3 Workflow/Pipeline Layer — Active when session has pipeline state.
3
+ *
4
+ * Loads workflow rules with phase awareness: what came before,
5
+ * what comes next, and constraints for the current pipeline position.
6
+ */
7
+
8
+ import { loadWorkflowDomains, extractRules } from '../domain-loader.js';
9
+
10
+ /**
11
+ * Process L3: load workflow rules with pipeline awareness.
12
+ * @param {object} ctx - Pipeline context
13
+ * @param {string} ctx.domainsDir - Path to chati.dev/domains/
14
+ * @param {string} ctx.workflow - Active workflow name (e.g. 'greenfield-fullstack')
15
+ * @param {string} ctx.pipelinePosition - Current position in pipeline (e.g. 'brief')
16
+ * @returns {{ layer: string, workflow: string, rules: Array, pipelineContext: object }}
17
+ */
18
+ export function processL3(ctx) {
19
+ if (!ctx.workflow) {
20
+ return { layer: 'L3', workflow: null, rules: [], pipelineContext: {} };
21
+ }
22
+
23
+ const allDomains = loadWorkflowDomains(ctx.domainsDir);
24
+ const domain = allDomains.get(ctx.workflow) || null;
25
+ const rules = extractRules(domain);
26
+
27
+ const steps = domain?.steps || [];
28
+ const currentIdx = steps.indexOf(ctx.pipelinePosition);
29
+
30
+ return {
31
+ layer: 'L3',
32
+ workflow: ctx.workflow,
33
+ rules,
34
+ pipelineContext: {
35
+ currentStep: ctx.pipelinePosition || null,
36
+ previousStep: currentIdx > 0 ? steps[currentIdx - 1] : null,
37
+ nextStep: currentIdx >= 0 && currentIdx < steps.length - 1 ? steps[currentIdx + 1] : null,
38
+ totalSteps: steps.length,
39
+ progress: steps.length > 0 ? Math.round(((currentIdx + 1) / steps.length) * 100) : 0,
40
+ },
41
+ };
42
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * L4 Task Layer — Active when a specific task is running.
3
+ *
4
+ * Injects task-specific context: the active task definition,
5
+ * handoff data from the previous agent, and relevant artifacts.
6
+ */
7
+
8
+ /**
9
+ * Process L4: inject task context and handoff data.
10
+ * @param {object} ctx - Pipeline context
11
+ * @param {string} [ctx.taskId] - Active task ID (e.g. 'brief-extract')
12
+ * @param {object} [ctx.handoff] - Handoff data from previous agent
13
+ * @param {string[]} [ctx.artifacts] - List of artifact paths relevant to current task
14
+ * @returns {{ layer: string, taskId: string|null, handoff: object, artifacts: string[] }}
15
+ */
16
+ export function processL4(ctx) {
17
+ return {
18
+ layer: 'L4',
19
+ taskId: ctx.taskId || null,
20
+ handoff: ctx.handoff || {},
21
+ artifacts: ctx.artifacts || [],
22
+ criteria: ctx.taskCriteria || [],
23
+ };
24
+ }
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Impact Analyzer - Dependency analysis for chati.dev
3
+ * Analyzes impact of changes via dependency graph traversal
4
+ *
5
+ * @module decision/analyzer
6
+ */
7
+
8
+ import { readFileSync, existsSync } from 'fs';
9
+ import { join } from 'path';
10
+ import yaml from 'js-yaml';
11
+
12
+ /**
13
+ * Analyze impact of changing an entity.
14
+ * Builds dependency graph from entity-registry and calculates affected entities.
15
+ *
16
+ * @param {string} projectDir
17
+ * @param {string} entityPath - Path of entity being changed
18
+ * @returns {{ impactLevel: 'low'|'medium'|'high'|'critical', affectedEntities: object[], dependencyChain: string[] }}
19
+ */
20
+ export function analyzeImpact(projectDir, entityPath) {
21
+ const graph = buildDependencyGraph(projectDir);
22
+ const affectedPaths = getTransitiveDependents(graph, entityPath);
23
+
24
+ // Determine impact level based on affected entity count
25
+ let impactLevel;
26
+ const affectedCount = affectedPaths.length;
27
+
28
+ if (affectedCount === 0) {
29
+ impactLevel = 'low';
30
+ } else if (affectedCount <= 2) {
31
+ impactLevel = 'low';
32
+ } else if (affectedCount <= 5) {
33
+ impactLevel = 'medium';
34
+ } else if (affectedCount <= 10) {
35
+ impactLevel = 'high';
36
+ } else {
37
+ impactLevel = 'critical';
38
+ }
39
+
40
+ // Load entity details
41
+ const registryPath = join(projectDir, 'chati.dev', 'entity-registry.yaml');
42
+ const registry = existsSync(registryPath)
43
+ ? yaml.load(readFileSync(registryPath, 'utf8'))
44
+ : { entities: {} };
45
+
46
+ const allEntities = flattenEntities(registry);
47
+ const entityMap = new Map(allEntities.map(e => [e.path, e]));
48
+
49
+ const affectedEntities = affectedPaths.map(path => {
50
+ const entity = entityMap.get(path);
51
+ return {
52
+ path,
53
+ type: entity?.type || 'unknown',
54
+ name: entity?.name || path.split('/').pop()
55
+ };
56
+ });
57
+
58
+ return {
59
+ impactLevel,
60
+ affectedEntities,
61
+ dependencyChain: affectedPaths
62
+ };
63
+ }
64
+
65
+ /**
66
+ * Build dependency graph from entity registry.
67
+ * @param {string} projectDir
68
+ * @returns {Map<string, string[]>} Map of entityPath -> [dependentPaths]
69
+ */
70
+ export function buildDependencyGraph(projectDir) {
71
+ const registryPath = join(projectDir, 'chati.dev', 'entity-registry.yaml');
72
+ const graph = new Map();
73
+
74
+ if (!existsSync(registryPath)) {
75
+ return graph;
76
+ }
77
+
78
+ const registry = yaml.load(readFileSync(registryPath, 'utf8'));
79
+ const entities = flattenEntities(registry);
80
+
81
+ // Initialize graph with all entities
82
+ entities.forEach(entity => {
83
+ if (entity.path) {
84
+ graph.set(entity.path, []);
85
+ }
86
+ });
87
+
88
+ // Build reverse dependency map (who depends on whom)
89
+ entities.forEach(entity => {
90
+ if (entity.dependencies && Array.isArray(entity.dependencies)) {
91
+ entity.dependencies.forEach(depPath => {
92
+ if (!graph.has(depPath)) {
93
+ graph.set(depPath, []);
94
+ }
95
+ // Add entity.path as dependent of depPath
96
+ const dependents = graph.get(depPath);
97
+ if (!dependents.includes(entity.path)) {
98
+ dependents.push(entity.path);
99
+ }
100
+ });
101
+ }
102
+ });
103
+
104
+ return graph;
105
+ }
106
+
107
+ /**
108
+ * Get all entities that depend on a given entity (transitive).
109
+ * Uses BFS traversal.
110
+ * @param {Map<string, string[]>} graph
111
+ * @param {string} entityPath
112
+ * @returns {string[]} All affected paths
113
+ */
114
+ export function getTransitiveDependents(graph, entityPath) {
115
+ const visited = new Set();
116
+ const queue = [entityPath];
117
+ const result = [];
118
+
119
+ while (queue.length > 0) {
120
+ const current = queue.shift();
121
+
122
+ if (visited.has(current)) {
123
+ continue;
124
+ }
125
+
126
+ visited.add(current);
127
+
128
+ // Get direct dependents
129
+ const dependents = graph.get(current) || [];
130
+
131
+ dependents.forEach(dependent => {
132
+ if (!visited.has(dependent)) {
133
+ queue.push(dependent);
134
+ result.push(dependent);
135
+ }
136
+ });
137
+ }
138
+
139
+ return result;
140
+ }
141
+
142
+ /**
143
+ * Flatten entity registry into array of entities.
144
+ * @private
145
+ * @param {object} registry
146
+ * @returns {object[]}
147
+ */
148
+ function flattenEntities(registry) {
149
+ const entities = [];
150
+
151
+ if (!registry.entities) {
152
+ return entities;
153
+ }
154
+
155
+ Object.entries(registry.entities).forEach(([type, typeEntities]) => {
156
+ if (Array.isArray(typeEntities)) {
157
+ typeEntities.forEach(entity => {
158
+ entities.push({
159
+ ...entity,
160
+ type
161
+ });
162
+ });
163
+ }
164
+ });
165
+
166
+ return entities;
167
+ }