chati-dev 4.1.6 → 4.2.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.
- package/README.md +6 -4
- package/framework/agents/build/dev.md +54 -1
- package/framework/agents/plan/architect.md +88 -25
- package/framework/agents/plan/detail.md +44 -0
- package/framework/agents/plan/ux.md +109 -34
- package/framework/agents/quality/qa-implementation.md +162 -2
- package/framework/config.yaml +9 -3
- package/framework/constitution.md +270 -2
- package/framework/context/governance.md +24 -1
- package/framework/context/quality.md +14 -1
- package/framework/context/root.md +4 -3
- package/framework/hooks/license-guard.js +13 -6
- package/framework/hooks/prism-engine.js +31 -1
- package/framework/hooks/settings.json +8 -0
- package/framework/hooks/team-quality-gate.js +145 -0
- package/framework/orchestrator/chati.md +172 -2
- package/framework/schemas/session.schema.json +160 -0
- package/framework/templates/team-build-tasks.yaml +56 -0
- package/framework/templates/team-planning-tasks.yaml +73 -0
- package/package.json +1 -1
- package/scripts/validate-package.js +110 -0
- package/src/autonomy/safety-net.js +32 -0
- package/src/installer/core.js +87 -128
- package/src/installer/templates.js +34 -0
- package/src/orchestrator/cli.js +404 -7
- package/src/terminal/run-team.js +349 -0
- package/src/terminal/team-task-list.js +226 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Team Build Tasks Template (Article XXI)
|
|
2
|
+
# Used by orchestrator when forming a Build Team (BUILD phase)
|
|
3
|
+
# QA reviews EACH task as Dev completes it (per-task review, not batch)
|
|
4
|
+
|
|
5
|
+
team_type: build
|
|
6
|
+
phase: build
|
|
7
|
+
mission: "Implement all tasks with per-task QA review and evidence-based quality gates"
|
|
8
|
+
|
|
9
|
+
# NOTE: Tasks are dynamically populated from tasks.md at team formation time.
|
|
10
|
+
# This template defines the PATTERN, not the actual tasks.
|
|
11
|
+
# The orchestrator reads tasks.md and generates TT-BLD-{NNN} entries per task.
|
|
12
|
+
|
|
13
|
+
task_pattern:
|
|
14
|
+
dev_task:
|
|
15
|
+
id_format: "TT-BLD-{NNN}-DEV"
|
|
16
|
+
assigned_to: dev
|
|
17
|
+
status: pending
|
|
18
|
+
score: null
|
|
19
|
+
blocker: null
|
|
20
|
+
threshold: 95
|
|
21
|
+
on_complete:
|
|
22
|
+
notify: qa-implementation
|
|
23
|
+
message_type: task_ready_for_review
|
|
24
|
+
include: [task_id, commit_hash, score, artifacts, self_critique_findings]
|
|
25
|
+
|
|
26
|
+
qa_review:
|
|
27
|
+
id_format: "TT-BLD-{NNN}-QA"
|
|
28
|
+
assigned_to: qa-implementation
|
|
29
|
+
status: pending
|
|
30
|
+
score: null
|
|
31
|
+
blocker: null
|
|
32
|
+
depends_on: ["TT-BLD-{NNN}-DEV"]
|
|
33
|
+
threshold: 95
|
|
34
|
+
protocol:
|
|
35
|
+
- "Run Evidence Gate (Phase 4c): lint, typecheck, test output required"
|
|
36
|
+
- "Classify fault origin (Phase 4d): INTENT | SPEC | CODE | DEFER"
|
|
37
|
+
- "Check Decision Trail for known-bad states before review"
|
|
38
|
+
- "Issue per-task verdict: pass | warn | block"
|
|
39
|
+
on_block:
|
|
40
|
+
action: notify_dev
|
|
41
|
+
message_type: task_review_findings
|
|
42
|
+
include: [task_id, verdict, findings, evidence, fault_origin]
|
|
43
|
+
|
|
44
|
+
# Example of dynamically generated tasks (orchestrator produces these):
|
|
45
|
+
#
|
|
46
|
+
# tasks:
|
|
47
|
+
# - id: TT-BLD-001-DEV
|
|
48
|
+
# title: "T1.1: Initialize Next.js + App Router"
|
|
49
|
+
# assigned_to: dev
|
|
50
|
+
# source_task: T1.1
|
|
51
|
+
# ...
|
|
52
|
+
# - id: TT-BLD-001-QA
|
|
53
|
+
# title: "T1.1: Review + approve"
|
|
54
|
+
# assigned_to: qa-implementation
|
|
55
|
+
# depends_on: [TT-BLD-001-DEV]
|
|
56
|
+
# ...
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Team Planning Tasks Template (Article XXI)
|
|
2
|
+
# Used by orchestrator when forming a Planning Team (post-Brief)
|
|
3
|
+
# Cross-review assignments form a circular review: Detail -> Architect -> UX -> Detail
|
|
4
|
+
|
|
5
|
+
team_type: planning
|
|
6
|
+
phase: plan
|
|
7
|
+
mission: "Co-design PRD, architecture, and UX specification with cross-validated alignment"
|
|
8
|
+
|
|
9
|
+
tasks:
|
|
10
|
+
- id: TT-PLN-001
|
|
11
|
+
title: "Expand Brief into PRD with acceptance criteria"
|
|
12
|
+
assigned_to: detail
|
|
13
|
+
status: pending
|
|
14
|
+
score: null
|
|
15
|
+
blocker: null
|
|
16
|
+
depends_on: []
|
|
17
|
+
cross_review:
|
|
18
|
+
target: architect
|
|
19
|
+
questions:
|
|
20
|
+
- "Do PRD entities align with the data architecture constraints you anticipate?"
|
|
21
|
+
- "Are there requirements that would create architectural contradictions?"
|
|
22
|
+
- "Are scope decisions in Section 4 likely to conflict with your design?"
|
|
23
|
+
artifacts_produced:
|
|
24
|
+
- prd.md
|
|
25
|
+
threshold: 90
|
|
26
|
+
|
|
27
|
+
- id: TT-PLN-002
|
|
28
|
+
title: "Design system architecture and data architecture"
|
|
29
|
+
assigned_to: architect
|
|
30
|
+
status: pending
|
|
31
|
+
score: null
|
|
32
|
+
blocker: null
|
|
33
|
+
depends_on: []
|
|
34
|
+
cross_review:
|
|
35
|
+
target: ux
|
|
36
|
+
questions:
|
|
37
|
+
- "Does the responsive strategy conflict with deployment architecture constraints?"
|
|
38
|
+
- "Do Design System tokens account for API response latency in loading states?"
|
|
39
|
+
- "Are there component complexity choices that contradict the scalability approach?"
|
|
40
|
+
artifacts_produced:
|
|
41
|
+
- architecture.md
|
|
42
|
+
threshold: 90
|
|
43
|
+
|
|
44
|
+
- id: TT-PLN-003
|
|
45
|
+
title: "Design UX specification with brandbook, user flows, and components"
|
|
46
|
+
assigned_to: ux
|
|
47
|
+
status: pending
|
|
48
|
+
score: null
|
|
49
|
+
blocker: null
|
|
50
|
+
depends_on: []
|
|
51
|
+
cross_review:
|
|
52
|
+
target: detail
|
|
53
|
+
questions:
|
|
54
|
+
- "Do any PRD requirements conflict with the selected visual direction?"
|
|
55
|
+
- "Are there user flows implying requirements not captured in the PRD?"
|
|
56
|
+
- "Is the target user profile consistent with UX research findings?"
|
|
57
|
+
artifacts_produced:
|
|
58
|
+
- ux-specification.md
|
|
59
|
+
- brandbook.md
|
|
60
|
+
- brandbook.html
|
|
61
|
+
threshold: 90
|
|
62
|
+
|
|
63
|
+
- id: TT-PLN-004
|
|
64
|
+
title: "Cross-validate alignment: PRD entities = DB tables = UI components"
|
|
65
|
+
assigned_to: null
|
|
66
|
+
status: pending
|
|
67
|
+
score: null
|
|
68
|
+
blocker: null
|
|
69
|
+
depends_on: [TT-PLN-001, TT-PLN-002, TT-PLN-003]
|
|
70
|
+
cross_review: null
|
|
71
|
+
artifacts_produced: []
|
|
72
|
+
threshold: 95
|
|
73
|
+
notes: "Assigned by Team Lead after individual tasks complete. All 3 members participate."
|
package/package.json
CHANGED
|
@@ -166,6 +166,114 @@ function checkBinExists(packageRoot, results) {
|
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
+
/**
|
|
170
|
+
* Validate that every hook referenced in hooks/settings.json exists on disk.
|
|
171
|
+
* Prevents shipping a bundle where settings.json references a hook file that
|
|
172
|
+
* was never copied.
|
|
173
|
+
*/
|
|
174
|
+
function checkHooksParity(packageRoot, results) {
|
|
175
|
+
results.checks++;
|
|
176
|
+
const settingsPath = join(packageRoot, 'framework', 'hooks', 'settings.json');
|
|
177
|
+
if (!existsSync(settingsPath)) {
|
|
178
|
+
results.warnings.push('framework/hooks/settings.json not found — skipping hooks parity check.');
|
|
179
|
+
results.passed++;
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
const settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
|
185
|
+
const missing = new Set();
|
|
186
|
+
const hooksDir = join(packageRoot, 'framework', 'hooks');
|
|
187
|
+
|
|
188
|
+
// Walk all hook events and collect referenced .js files
|
|
189
|
+
for (const event of Object.keys(settings.hooks || {})) {
|
|
190
|
+
for (const matcher of settings.hooks[event] || []) {
|
|
191
|
+
for (const hook of matcher.hooks || []) {
|
|
192
|
+
if (hook.type === 'command' && typeof hook.command === 'string') {
|
|
193
|
+
// command format: "node chati.dev/hooks/foo.js"
|
|
194
|
+
const match = hook.command.match(/hooks\/([^\s]+\.js)/);
|
|
195
|
+
if (match) {
|
|
196
|
+
const hookFile = match[1];
|
|
197
|
+
if (!existsSync(join(hooksDir, hookFile))) {
|
|
198
|
+
missing.add(hookFile);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (missing.size === 0) {
|
|
207
|
+
results.passed++;
|
|
208
|
+
} else {
|
|
209
|
+
results.errors.push(`Hooks referenced in settings.json but missing from framework/hooks/: ${[...missing].join(', ')}`);
|
|
210
|
+
}
|
|
211
|
+
} catch (err) {
|
|
212
|
+
results.errors.push(`Failed to parse hooks/settings.json: ${err.message}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Parity check: every file in source chati.dev/ (that belongs to a copied
|
|
218
|
+
* directory) must exist in framework/. Catches bundling bugs where new files
|
|
219
|
+
* are added to the source but not included in the bundle.
|
|
220
|
+
*
|
|
221
|
+
* Only runs when the monorepo source is available (skipped inside the
|
|
222
|
+
* published package since the source is not shipped).
|
|
223
|
+
*/
|
|
224
|
+
function checkSourceBundleParity(packageRoot, results) {
|
|
225
|
+
results.checks++;
|
|
226
|
+
const monorepoSource = join(packageRoot, '..', '..', 'chati.dev');
|
|
227
|
+
const bundleDir = join(packageRoot, 'framework');
|
|
228
|
+
|
|
229
|
+
if (!existsSync(monorepoSource)) {
|
|
230
|
+
// Running inside the published package — skip (nothing to compare against)
|
|
231
|
+
results.passed++;
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Collect all files in source, grouped by the top-level directory
|
|
236
|
+
const missing = [];
|
|
237
|
+
const COPIED_DIRS = [
|
|
238
|
+
'orchestrator', 'agents', 'templates', 'workflows', 'quality-gates',
|
|
239
|
+
'schemas', 'frameworks', 'intelligence', 'patterns', 'hooks',
|
|
240
|
+
'domains', 'i18n', 'migrations', 'data', 'context', 'tasks', 'presets',
|
|
241
|
+
];
|
|
242
|
+
const COPIED_ROOT_FILES = ['constitution.md'];
|
|
243
|
+
|
|
244
|
+
function walk(srcDir, relBase) {
|
|
245
|
+
if (!existsSync(srcDir)) return;
|
|
246
|
+
for (const entry of readdirSync(srcDir, { withFileTypes: true })) {
|
|
247
|
+
const srcPath = join(srcDir, entry.name);
|
|
248
|
+
const relPath = relBase ? `${relBase}/${entry.name}` : entry.name;
|
|
249
|
+
if (entry.isDirectory()) {
|
|
250
|
+
walk(srcPath, relPath);
|
|
251
|
+
} else if (entry.isFile()) {
|
|
252
|
+
const bundlePath = join(bundleDir, relPath);
|
|
253
|
+
if (!existsSync(bundlePath)) missing.push(relPath);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
for (const file of COPIED_ROOT_FILES) {
|
|
259
|
+
const src = join(monorepoSource, file);
|
|
260
|
+
const bundled = join(bundleDir, file);
|
|
261
|
+
if (existsSync(src) && !existsSync(bundled)) missing.push(file);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
for (const dir of COPIED_DIRS) {
|
|
265
|
+
walk(join(monorepoSource, dir), dir);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (missing.length === 0) {
|
|
269
|
+
results.passed++;
|
|
270
|
+
} else {
|
|
271
|
+
const sample = missing.slice(0, 10).join(', ');
|
|
272
|
+
const more = missing.length > 10 ? ` (+ ${missing.length - 10} more)` : '';
|
|
273
|
+
results.errors.push(`Files in source chati.dev/ missing from framework/ bundle: ${sample}${more}`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
169
277
|
/**
|
|
170
278
|
* Compare entity count in registry vs actual files in framework/.
|
|
171
279
|
*/
|
|
@@ -216,6 +324,8 @@ export function validatePackage(packageRoot) {
|
|
|
216
324
|
checkExportsResolve(packageRoot, results);
|
|
217
325
|
checkBinExists(packageRoot, results);
|
|
218
326
|
checkEntityCount(packageRoot, results);
|
|
327
|
+
checkHooksParity(packageRoot, results);
|
|
328
|
+
checkSourceBundleParity(packageRoot, results);
|
|
219
329
|
|
|
220
330
|
return results;
|
|
221
331
|
}
|
|
@@ -12,6 +12,7 @@ export const SAFETY_TRIGGERS = {
|
|
|
12
12
|
CRITICAL_RISK: 'critical_risk', // Security/data risk detected
|
|
13
13
|
TIMEOUT: 'timeout', // Agent exceeded time limit
|
|
14
14
|
GOTCHA_SPIKE: 'gotcha_spike', // 5+ new gotchas in current session
|
|
15
|
+
EDIT_LOOP: 'edit_loop', // Same file edited 3+ times in current task (Article XX)
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
// Critical risk keywords
|
|
@@ -98,6 +99,9 @@ export function evaluateTrigger(trigger, state) {
|
|
|
98
99
|
case SAFETY_TRIGGERS.GOTCHA_SPIKE:
|
|
99
100
|
return evaluateGotchaSpike(state);
|
|
100
101
|
|
|
102
|
+
case SAFETY_TRIGGERS.EDIT_LOOP:
|
|
103
|
+
return evaluateEditLoop(state);
|
|
104
|
+
|
|
101
105
|
default:
|
|
102
106
|
return {
|
|
103
107
|
triggered: false,
|
|
@@ -291,6 +295,34 @@ function evaluateGotchaSpike(state) {
|
|
|
291
295
|
};
|
|
292
296
|
}
|
|
293
297
|
|
|
298
|
+
/**
|
|
299
|
+
* Article XX — Detect edit loops (same file edited 3+ times in current task).
|
|
300
|
+
* state.fileEdits should be an object: { 'path/to/file.tsx': 3, ... }
|
|
301
|
+
*/
|
|
302
|
+
function evaluateEditLoop(state) {
|
|
303
|
+
const threshold = 3;
|
|
304
|
+
const fileEdits = state.fileEdits || {};
|
|
305
|
+
const loopedFiles = Object.entries(fileEdits)
|
|
306
|
+
.filter(([, count]) => count >= threshold);
|
|
307
|
+
|
|
308
|
+
if (loopedFiles.length > 0) {
|
|
309
|
+
const details = loopedFiles
|
|
310
|
+
.map(([path, count]) => `${path} (${count} edits)`)
|
|
311
|
+
.join(', ');
|
|
312
|
+
return {
|
|
313
|
+
triggered: true,
|
|
314
|
+
severity: 'critical',
|
|
315
|
+
details: `Edit loop detected (Article XX): ${details}. Stop and diagnose root cause before continuing.`,
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return {
|
|
320
|
+
triggered: false,
|
|
321
|
+
severity: 'warning',
|
|
322
|
+
details: 'No edit loops detected',
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
294
326
|
/**
|
|
295
327
|
* Get critical risk keywords list.
|
|
296
328
|
* @returns {string[]}
|
package/src/installer/core.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdirSync, writeFileSync, copyFileSync, existsSync, readFileSync } from 'fs';
|
|
1
|
+
import { mkdirSync, writeFileSync, copyFileSync, existsSync, readFileSync, readdirSync } from 'fs';
|
|
2
2
|
import { join, dirname } from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import { IDE_CONFIGS, IDE_TO_PROVIDER } from '../config/ide-configs.js';
|
|
@@ -146,144 +146,103 @@ export async function installFramework(config) {
|
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
/**
|
|
149
|
-
*
|
|
149
|
+
* Framework directories to copy recursively from source to target.
|
|
150
|
+
* This list controls WHICH top-level directories under chati.dev/ get copied.
|
|
151
|
+
* Everything inside each directory is copied automatically — no need to
|
|
152
|
+
* enumerate individual files.
|
|
153
|
+
*
|
|
154
|
+
* New files added to the source framework are picked up automatically.
|
|
150
155
|
*/
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
'agents/plan/phases.md',
|
|
171
|
-
'agents/plan/tasks.md',
|
|
172
|
-
// Quality agents
|
|
173
|
-
'agents/quality/qa-planning.md',
|
|
174
|
-
'agents/quality/qa-implementation.md',
|
|
175
|
-
// BUILD + DEPLOY agents
|
|
176
|
-
'agents/build/dev.md',
|
|
177
|
-
'agents/deploy/devops.md',
|
|
178
|
-
// Templates
|
|
179
|
-
'templates/prd-tmpl.yaml',
|
|
180
|
-
'templates/brownfield-prd-tmpl.yaml',
|
|
181
|
-
'templates/fullstack-architecture-tmpl.yaml',
|
|
182
|
-
'templates/task-tmpl.yaml',
|
|
183
|
-
'templates/qa-gate-tmpl.yaml',
|
|
184
|
-
'templates/quick-brief-tmpl.yaml',
|
|
185
|
-
'templates/brandbook-tmpl.yaml',
|
|
186
|
-
'templates/brandbook-html-tmpl.md',
|
|
187
|
-
'templates/design-token-tmpl.yaml',
|
|
188
|
-
'templates/component-spec-tmpl.yaml',
|
|
189
|
-
'templates/icon-system-tmpl.yaml',
|
|
190
|
-
'templates/session-memory-tmpl.yaml',
|
|
191
|
-
// Workflows
|
|
192
|
-
'workflows/greenfield-fullstack.yaml',
|
|
193
|
-
'workflows/brownfield-fullstack.yaml',
|
|
194
|
-
'workflows/brownfield-discovery.yaml',
|
|
195
|
-
'workflows/brownfield-service.yaml',
|
|
196
|
-
'workflows/brownfield-ui.yaml',
|
|
197
|
-
'workflows/quick-flow.yaml',
|
|
198
|
-
'workflows/standard-flow.yaml',
|
|
199
|
-
// Quality gates
|
|
200
|
-
'quality-gates/planning-gate.md',
|
|
201
|
-
'quality-gates/implementation-gate.md',
|
|
202
|
-
// Schemas
|
|
203
|
-
'schemas/session.schema.json',
|
|
204
|
-
'schemas/config.schema.json',
|
|
205
|
-
'schemas/task.schema.json',
|
|
206
|
-
'schemas/context.schema.json',
|
|
207
|
-
'schemas/memory.schema.json',
|
|
208
|
-
// Frameworks
|
|
209
|
-
'frameworks/quality-dimensions.yaml',
|
|
210
|
-
'frameworks/decision-heuristics.yaml',
|
|
211
|
-
// Intelligence
|
|
212
|
-
'intelligence/gotchas.yaml',
|
|
213
|
-
'intelligence/patterns.yaml',
|
|
214
|
-
'intelligence/confidence.yaml',
|
|
215
|
-
'intelligence/context-engine.md',
|
|
216
|
-
'intelligence/memory-layer.md',
|
|
217
|
-
'intelligence/decision-engine.md',
|
|
218
|
-
// Patterns
|
|
219
|
-
'patterns/elicitation.md',
|
|
220
|
-
'patterns/elicitation-library.yaml',
|
|
221
|
-
// Hooks
|
|
222
|
-
'hooks/prism-engine.js',
|
|
223
|
-
'hooks/mode-governance.js',
|
|
224
|
-
'hooks/constitution-guard.js',
|
|
225
|
-
'hooks/session-digest.js',
|
|
226
|
-
'hooks/model-governance.js',
|
|
227
|
-
'hooks/settings.json',
|
|
228
|
-
'hooks/read-protection.js',
|
|
229
|
-
// Domains (PRISM Context Engine)
|
|
230
|
-
'domains/constitution.yaml',
|
|
231
|
-
'domains/global.yaml',
|
|
232
|
-
'domains/agents/orchestrator.yaml',
|
|
233
|
-
'domains/agents/greenfield-wu.yaml',
|
|
234
|
-
'domains/agents/brownfield-wu.yaml',
|
|
235
|
-
'domains/agents/brief.yaml',
|
|
236
|
-
'domains/agents/detail.yaml',
|
|
237
|
-
'domains/agents/architect.yaml',
|
|
238
|
-
'domains/agents/ux.yaml',
|
|
239
|
-
'domains/agents/phases.yaml',
|
|
240
|
-
'domains/agents/tasks.yaml',
|
|
241
|
-
'domains/agents/qa-planning.yaml',
|
|
242
|
-
'domains/agents/qa-implementation.yaml',
|
|
243
|
-
'domains/agents/dev.yaml',
|
|
244
|
-
'domains/agents/devops.yaml',
|
|
245
|
-
'domains/workflows/greenfield-fullstack.yaml',
|
|
246
|
-
'domains/workflows/brownfield-fullstack.yaml',
|
|
247
|
-
'domains/workflows/brownfield-discovery.yaml',
|
|
248
|
-
'domains/workflows/brownfield-service.yaml',
|
|
249
|
-
'domains/workflows/brownfield-ui.yaml',
|
|
250
|
-
'domains/workflows/quick-flow.yaml',
|
|
251
|
-
'domains/workflows/standard-flow.yaml',
|
|
252
|
-
// i18n
|
|
253
|
-
'i18n/en.yaml',
|
|
254
|
-
'i18n/pt.yaml',
|
|
255
|
-
'i18n/es.yaml',
|
|
256
|
-
'i18n/fr.yaml',
|
|
257
|
-
// Migrations
|
|
258
|
-
'migrations/v1.0-to-v1.1.yaml',
|
|
259
|
-
// Data
|
|
260
|
-
'data/entity-registry.yaml',
|
|
261
|
-
// Context (@ import chain for CLAUDE.md)
|
|
262
|
-
'context/root.md',
|
|
263
|
-
'context/governance.md',
|
|
264
|
-
'context/protocols.md',
|
|
265
|
-
'context/quality.md',
|
|
266
|
-
];
|
|
267
|
-
|
|
268
|
-
for (const file of filesToCopy) {
|
|
269
|
-
const src = join(FRAMEWORK_SOURCE, file);
|
|
270
|
-
const dest = join(destDir, file);
|
|
156
|
+
const FRAMEWORK_DIRS_TO_COPY = [
|
|
157
|
+
'orchestrator',
|
|
158
|
+
'agents',
|
|
159
|
+
'templates',
|
|
160
|
+
'workflows',
|
|
161
|
+
'quality-gates',
|
|
162
|
+
'schemas',
|
|
163
|
+
'frameworks',
|
|
164
|
+
'intelligence',
|
|
165
|
+
'patterns',
|
|
166
|
+
'hooks',
|
|
167
|
+
'domains',
|
|
168
|
+
'i18n',
|
|
169
|
+
'migrations',
|
|
170
|
+
'data',
|
|
171
|
+
'context',
|
|
172
|
+
'tasks',
|
|
173
|
+
'presets',
|
|
174
|
+
];
|
|
271
175
|
|
|
272
|
-
|
|
273
|
-
|
|
176
|
+
/**
|
|
177
|
+
* Loose files at the root of chati.dev/ that get copied directly.
|
|
178
|
+
*/
|
|
179
|
+
const FRAMEWORK_ROOT_FILES = [
|
|
180
|
+
'constitution.md',
|
|
181
|
+
];
|
|
274
182
|
|
|
275
|
-
|
|
183
|
+
/**
|
|
184
|
+
* Recursively copy a directory from source to destination, applying provider
|
|
185
|
+
* adaptation for files listed in ADAPTABLE_FILES when the provider is not Claude.
|
|
186
|
+
*/
|
|
187
|
+
function copyDirRecursive(srcDir, destDir, provider, relBase = '') {
|
|
188
|
+
if (!existsSync(srcDir)) return;
|
|
189
|
+
createDir(destDir);
|
|
190
|
+
|
|
191
|
+
const entries = readdirSync(srcDir, { withFileTypes: true });
|
|
192
|
+
for (const entry of entries) {
|
|
193
|
+
const srcPath = join(srcDir, entry.name);
|
|
194
|
+
const destPath = join(destDir, entry.name);
|
|
195
|
+
const relPath = relBase ? join(relBase, entry.name) : entry.name;
|
|
196
|
+
|
|
197
|
+
if (entry.isDirectory()) {
|
|
198
|
+
copyDirRecursive(srcPath, destPath, provider, relPath);
|
|
199
|
+
} else if (entry.isFile()) {
|
|
200
|
+
if (provider !== 'claude' && ADAPTABLE_FILES.has(relPath)) {
|
|
276
201
|
// Non-Claude provider: read, adapt, write
|
|
277
|
-
const content = readFileSync(
|
|
278
|
-
writeFileSync(
|
|
202
|
+
const content = readFileSync(srcPath, 'utf-8');
|
|
203
|
+
writeFileSync(destPath, adaptFrameworkFile(content, relPath, provider), 'utf-8');
|
|
279
204
|
} else {
|
|
280
205
|
// Claude or non-adaptable: direct copy
|
|
281
|
-
copyFileSync(
|
|
206
|
+
copyFileSync(srcPath, destPath);
|
|
282
207
|
}
|
|
283
208
|
}
|
|
284
209
|
}
|
|
285
210
|
}
|
|
286
211
|
|
|
212
|
+
/**
|
|
213
|
+
* Copy framework files from the Chati.dev source directory.
|
|
214
|
+
*
|
|
215
|
+
* Uses recursive directory copy instead of a hardcoded file list, so that
|
|
216
|
+
* new files added to the framework source are automatically picked up.
|
|
217
|
+
*
|
|
218
|
+
* @param {string} destDir - Target framework directory (e.g., {project}/chati.dev/)
|
|
219
|
+
* @param {string} provider - Primary provider for text adaptation ('claude' | 'gemini' | 'codex')
|
|
220
|
+
*/
|
|
221
|
+
export function copyFrameworkFiles(destDir, provider = 'claude') {
|
|
222
|
+
if (!existsSync(FRAMEWORK_SOURCE)) return;
|
|
223
|
+
|
|
224
|
+
// Copy loose root files
|
|
225
|
+
for (const file of FRAMEWORK_ROOT_FILES) {
|
|
226
|
+
const src = join(FRAMEWORK_SOURCE, file);
|
|
227
|
+
if (!existsSync(src)) continue;
|
|
228
|
+
const dest = join(destDir, file);
|
|
229
|
+
createDir(dirname(dest));
|
|
230
|
+
if (provider !== 'claude' && ADAPTABLE_FILES.has(file)) {
|
|
231
|
+
const content = readFileSync(src, 'utf-8');
|
|
232
|
+
writeFileSync(dest, adaptFrameworkFile(content, file, provider), 'utf-8');
|
|
233
|
+
} else {
|
|
234
|
+
copyFileSync(src, dest);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Copy each framework directory recursively
|
|
239
|
+
for (const dir of FRAMEWORK_DIRS_TO_COPY) {
|
|
240
|
+
const srcDir = join(FRAMEWORK_SOURCE, dir);
|
|
241
|
+
const destSubDir = join(destDir, dir);
|
|
242
|
+
copyDirRecursive(srcDir, destSubDir, provider, dir);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
287
246
|
/**
|
|
288
247
|
* Configure a specific IDE
|
|
289
248
|
*/
|
|
@@ -108,6 +108,40 @@ export function generateConfigYaml(config) {
|
|
|
108
108
|
},
|
|
109
109
|
};
|
|
110
110
|
|
|
111
|
+
// Feature flags (Intelligence Upgrade + Article XXI Agent Teams)
|
|
112
|
+
// Must match source chati.dev/config.yaml features block.
|
|
113
|
+
configData.features = {
|
|
114
|
+
hybrid_budget: true,
|
|
115
|
+
anti_dash: true,
|
|
116
|
+
rate_limiter_integration: true,
|
|
117
|
+
l5_keywords: true,
|
|
118
|
+
prompt_size_guard: true,
|
|
119
|
+
ids_decision_engine: true,
|
|
120
|
+
surface_criteria: true,
|
|
121
|
+
parallel_fallback: true,
|
|
122
|
+
tool_mesh: true,
|
|
123
|
+
tech_presets: true,
|
|
124
|
+
doctor_autofix: true,
|
|
125
|
+
brandbook: true,
|
|
126
|
+
// Intelligence Upgrade (v4.0.5 — Claude Code patterns)
|
|
127
|
+
undercover_mode: true,
|
|
128
|
+
memory_extraction: true,
|
|
129
|
+
memory_consolidation: true,
|
|
130
|
+
daily_digest: true,
|
|
131
|
+
structured_session_memory: true,
|
|
132
|
+
static_prism_boundary: true,
|
|
133
|
+
token_bracket_estimation: true,
|
|
134
|
+
model_fallback: true,
|
|
135
|
+
frustration_detection: true,
|
|
136
|
+
bash_security_checks: true,
|
|
137
|
+
// Agent Teams (v4.2.0 — Article XXI)
|
|
138
|
+
agent_teams: false,
|
|
139
|
+
team_planning_size: 3,
|
|
140
|
+
team_build_size: 2,
|
|
141
|
+
team_echo_threshold: 0.92,
|
|
142
|
+
team_correction_cycles_max: 2,
|
|
143
|
+
};
|
|
144
|
+
|
|
111
145
|
// Add telemetry config
|
|
112
146
|
configData.telemetry = {
|
|
113
147
|
enabled: config.telemetryEnabled !== false,
|