chati-dev 4.5.10 → 4.5.12
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/framework/agents/discover/brownfield-wu.md +1 -1
- package/framework/agents/plan/tasks.md +2 -2
- package/framework/config.yaml +2 -2
- package/framework/constitution.md +21 -22
- package/framework/context/governance.md +10 -10
- package/framework/context/quality.md +6 -6
- package/framework/context/root.md +1 -1
- package/framework/data/entity-registry.yaml +1 -1
- package/framework/domains/constitution.yaml +1 -1
- package/framework/domains/workflows/brownfield-fullstack.yaml +5 -3
- package/framework/domains/workflows/brownfield-service.yaml +2 -3
- package/framework/domains/workflows/brownfield-ui.yaml +2 -3
- package/framework/domains/workflows/greenfield-fullstack.yaml +5 -3
- package/framework/domains/workflows/quick-flow.yaml +7 -6
- package/framework/domains/workflows/standard-flow.yaml +4 -5
- package/framework/frameworks/quality-dimensions.yaml +3 -3
- package/framework/hooks/git-push-authority.js +8 -4
- package/framework/manifest.json +49 -49
- package/framework/manifest.sig +1 -1
- package/framework/orchestrator/chati.md +29 -20
- package/framework/schemas/session.schema.json +5 -5
- package/framework/workflows/brownfield-fullstack.yaml +17 -123
- package/framework/workflows/brownfield-service.yaml +15 -109
- package/framework/workflows/brownfield-ui.yaml +15 -115
- package/framework/workflows/greenfield-fullstack.yaml +17 -130
- package/framework/workflows/quick-flow.yaml +20 -111
- package/framework/workflows/standard-flow.yaml +14 -158
- package/package.json +1 -1
- package/src/config/claude-settings-generator.js +4 -3
- package/src/config/context-file-generator.js +10 -1
- package/src/config/framework-adapter.js +10 -2
- package/src/context/layers/l1-global.js +2 -0
- package/src/installer/core.js +94 -13
- package/src/installer/templates.js +5 -4
- package/src/installer/validator.js +8 -2
- package/src/intelligence/registry-manager.js +11 -4
- package/src/orchestrator/cli.js +158 -42
- package/src/orchestrator/pipeline-manager.js +2 -0
- package/src/orchestrator/runtime-installation-v2.js +38 -0
- package/src/orchestrator/session-manager.js +1 -1
- package/src/terminal/handoff-parser.js +23 -4
- package/src/terminal/prompt-builder.js +15 -1
- package/src/terminal/provider-preflight.js +78 -0
- package/src/terminal/run-agent.js +66 -23
- package/src/terminal/spawner.js +5 -1
- package/src/utils/schema-validator.js +5 -2
- package/src/wizard/index.js +1 -0
|
@@ -1,174 +1,30 @@
|
|
|
1
|
-
# Standard Flow Workflow
|
|
2
|
-
# Mid-tier pipeline for moderate tasks: new features, integrations, brownfield enhancements
|
|
3
|
-
# Uses 8 agents — between Quick Flow (4) and Full Flow (12)
|
|
4
|
-
|
|
5
1
|
workflow:
|
|
6
2
|
id: standard-flow
|
|
7
|
-
name: Standard Flow
|
|
8
|
-
version: "
|
|
3
|
+
name: Standard Flow
|
|
4
|
+
version: "2.0.0"
|
|
9
5
|
type: any
|
|
10
6
|
project_types: [feature, integration, enhancement, module, component, brownfield-moderate]
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
but not the full 12-agent pipeline. Skips WU (assumes existing codebase
|
|
14
|
-
context), UX (no design-heavy work), and Phases (tasks agent handles
|
|
15
|
-
scope directly). Ideal for 2-5 requirements in brownfield projects.
|
|
16
|
-
|
|
17
|
-
detection:
|
|
18
|
-
triggers:
|
|
19
|
-
- "Moderate complexity feature with 2-5 requirements"
|
|
20
|
-
- "Brownfield project enhancement or integration"
|
|
21
|
-
- "New module or component within existing architecture"
|
|
22
|
-
- "User explicitly requests standard flow"
|
|
23
|
-
- "Feature that needs architecture review but not full UX design"
|
|
24
|
-
- "API integration or service connection"
|
|
25
|
-
- "Database-backed feature with clear data model"
|
|
26
|
-
disqualifiers:
|
|
27
|
-
- "Quick fix, hotfix, or single-line change (use Quick Flow)"
|
|
28
|
-
- "Enterprise-scale project with compliance requirements (use Full Flow)"
|
|
29
|
-
- "Greenfield project requiring full discovery (use Full Flow)"
|
|
30
|
-
- "UX-heavy feature requiring design system work (use Full Flow)"
|
|
31
|
-
- "Multi-service architecture changes (use Full Flow)"
|
|
32
|
-
- "User explicitly requests full pipeline"
|
|
33
|
-
|
|
34
|
-
confidence_threshold: 0.8
|
|
35
|
-
user_confirmation: true
|
|
36
|
-
|
|
37
|
-
agents:
|
|
38
|
-
included:
|
|
39
|
-
- brief
|
|
40
|
-
- detail
|
|
41
|
-
- architect
|
|
42
|
-
- tasks
|
|
43
|
-
- qa-planning # runs inside Planning Team; score synced via team dissolution
|
|
44
|
-
- dev
|
|
45
|
-
- qa-implementation
|
|
46
|
-
- devops
|
|
47
|
-
excluded:
|
|
48
|
-
- greenfield-wu
|
|
49
|
-
- brownfield-wu
|
|
50
|
-
- ux
|
|
51
|
-
- phases
|
|
7
|
+
execution_authority: rail
|
|
8
|
+
description: Balanced planning followed by the canonical RAIL and Release contracts.
|
|
52
9
|
|
|
53
10
|
phases:
|
|
54
11
|
- phase: 0
|
|
55
12
|
name: Discovery
|
|
56
13
|
category: DISCOVER
|
|
57
14
|
sequence:
|
|
58
|
-
- agent: brief
|
|
59
|
-
action: extract-requirements
|
|
60
|
-
creates: [artifacts/1-Brief/brief.md]
|
|
61
|
-
notes: >
|
|
62
|
-
Full brief extraction (5 phases). Since no WU precedes it,
|
|
63
|
-
Brief must also capture codebase context from user input.
|
|
64
|
-
config:
|
|
65
|
-
max_rounds: 5
|
|
66
|
-
require_approval: true
|
|
67
|
-
|
|
15
|
+
- { agent: brief, action: problem-extraction, creates: [artifacts/1-Brief/brief-report.md] }
|
|
68
16
|
- phase: 1
|
|
69
17
|
name: Planning
|
|
70
18
|
category: PLAN
|
|
71
19
|
sequence:
|
|
72
|
-
- agent: detail
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
- agent: architect
|
|
79
|
-
action: design-architecture
|
|
80
|
-
creates: [artifacts/3-Architecture/architecture.md]
|
|
81
|
-
notes: "Architecture decisions, no UX constraints needed"
|
|
82
|
-
parallel_with: [detail]
|
|
83
|
-
|
|
84
|
-
- agent: tasks
|
|
85
|
-
action: create-tasks
|
|
86
|
-
creates: [artifacts/5-Tasks/tasks.md]
|
|
87
|
-
notes: >
|
|
88
|
-
Tasks agent works directly from PRD + Architecture.
|
|
89
|
-
No phases agent — tasks agent determines task breakdown directly.
|
|
90
|
-
|
|
91
|
-
- agent: qa-planning
|
|
92
|
-
action: validate-plan
|
|
93
|
-
creates: [artifacts/6-QA-Planning/qa-planning-report.md]
|
|
94
|
-
notes: >
|
|
95
|
-
Runs inside Planning Team (Article XXI), not as a standalone step.
|
|
96
|
-
Activates after Detail, Architect complete. Score >= 95% required to advance.
|
|
97
|
-
Score synced to session.yaml by orchestrator on team dissolution.
|
|
98
|
-
config:
|
|
99
|
-
minimum_score: 95
|
|
100
|
-
|
|
101
|
-
- phase: 2
|
|
102
|
-
name: Implementation
|
|
103
|
-
category: BUILD
|
|
104
|
-
sequence:
|
|
105
|
-
- agent: dev
|
|
106
|
-
action: implement-tasks
|
|
107
|
-
notes: "Dev works from full PRD + architecture + tasks"
|
|
108
|
-
|
|
109
|
-
- agent: qa-implementation
|
|
110
|
-
action: validate-code
|
|
111
|
-
creates: [artifacts/9-QA-Implementation/qa-implementation-report.md]
|
|
112
|
-
notes: >
|
|
113
|
-
Full QA-Implementation validation. Score >= 95% required.
|
|
114
|
-
Adversarial review mandatory.
|
|
115
|
-
config:
|
|
116
|
-
adversarial_review: true
|
|
117
|
-
minimum_findings: 5
|
|
118
|
-
minimum_score: 95
|
|
119
|
-
|
|
120
|
-
- phase: 3
|
|
121
|
-
name: Deployment
|
|
122
|
-
category: DEPLOY
|
|
123
|
-
sequence:
|
|
124
|
-
- agent: devops
|
|
125
|
-
action: deploy
|
|
126
|
-
creates: [artifacts/10-Deploy/deploy-report.md]
|
|
127
|
-
notes: "Standard deployment process"
|
|
20
|
+
- { agent: detail, action: create-prd, creates: [artifacts/2-PRD/prd.md] }
|
|
21
|
+
- { agent: architect, action: focused-architecture, creates: [artifacts/3-Architecture/architecture.md] }
|
|
22
|
+
- { agent: tasks, action: seal-task-graph, creates: [artifacts/6-Tasks/tasks.md] }
|
|
23
|
+
- { agent: qa-planning, action: validate-planning, creates: [artifacts/7-QA-Planning/qa-planning-report.md] }
|
|
24
|
+
- { phase: 2, name: RAIL Execution, category: RAIL, runtime: project-local-rail }
|
|
25
|
+
- { phase: 3, name: Release Lane, category: RELEASE, requires: [rail_complete, independent_review_approved, explicit_human_authorization] }
|
|
128
26
|
|
|
129
27
|
transitions:
|
|
130
|
-
discover_to_plan:
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
action: "Advance to PLAN phase"
|
|
134
|
-
plan_to_build:
|
|
135
|
-
trigger: "qa-planning.score >= 95"
|
|
136
|
-
type: automatic
|
|
137
|
-
action: "Advance to BUILD phase"
|
|
138
|
-
build_to_validate:
|
|
139
|
-
trigger: "dev.status == completed"
|
|
140
|
-
type: automatic
|
|
141
|
-
action: "Run QA-Implementation"
|
|
142
|
-
validate_to_deploy:
|
|
143
|
-
trigger: "qa-implementation.score >= 95"
|
|
144
|
-
type: user_preview
|
|
145
|
-
action: "User preview gate, then advance to DEPLOY"
|
|
146
|
-
deploy_to_completed:
|
|
147
|
-
trigger: "devops.status == completed"
|
|
148
|
-
type: automatic
|
|
149
|
-
action: "Pipeline complete"
|
|
150
|
-
|
|
151
|
-
escalation:
|
|
152
|
-
to_full_flow:
|
|
153
|
-
triggers:
|
|
154
|
-
- "Architect discovers multi-service complexity"
|
|
155
|
-
- "QA-Planning finds UX requirements not addressed"
|
|
156
|
-
- "Scope creep: more than 5 distinct requirements discovered"
|
|
157
|
-
- "User requests full pipeline"
|
|
158
|
-
action: >
|
|
159
|
-
Pause standard-flow, notify user:
|
|
160
|
-
"This task is more complex than the standard flow can handle.
|
|
161
|
-
Options:
|
|
162
|
-
1. Switch to full pipeline (Recommended)
|
|
163
|
-
2. Continue with standard flow (document gaps)
|
|
164
|
-
3. Reduce scope and continue"
|
|
165
|
-
to_quick_flow:
|
|
166
|
-
triggers:
|
|
167
|
-
- "Detail agent finds only 1 simple requirement"
|
|
168
|
-
- "Architect confirms no architecture changes needed"
|
|
169
|
-
action: >
|
|
170
|
-
Suggest downgrade:
|
|
171
|
-
"This task might be simpler than expected.
|
|
172
|
-
Options:
|
|
173
|
-
1. Switch to quick flow (faster)
|
|
174
|
-
2. Continue with standard flow"
|
|
28
|
+
discover_to_plan: { trigger: "brief.status == completed", target: plan }
|
|
29
|
+
plan_to_rail: { trigger: "qa-planning.score >= 95 && tasks.handoff == sealed", target: rail }
|
|
30
|
+
rail_to_release: { trigger: "rail.all_tasks_approved == true", target: release }
|
package/package.json
CHANGED
|
@@ -176,10 +176,11 @@ const PERMISSIONS_DENY = [
|
|
|
176
176
|
* Group HOOK_REGISTRY entries by event, then by matcher within each event.
|
|
177
177
|
* Returns the shape Claude Code expects under the top-level "hooks" key.
|
|
178
178
|
*/
|
|
179
|
-
function buildHooksObject() {
|
|
179
|
+
function buildHooksObject(options = {}) {
|
|
180
180
|
const events = {};
|
|
181
181
|
|
|
182
182
|
for (const entry of HOOK_REGISTRY) {
|
|
183
|
+
if (options.runtimeVersion === 2 && entry.name === 'post-dev') continue;
|
|
183
184
|
if (!events[entry.event]) events[entry.event] = new Map();
|
|
184
185
|
const matcherGroups = events[entry.event];
|
|
185
186
|
if (!matcherGroups.has(entry.matcher)) {
|
|
@@ -208,7 +209,7 @@ function buildHooksObject() {
|
|
|
208
209
|
*
|
|
209
210
|
* @returns {string} JSON string with trailing newline, ready to write to disk.
|
|
210
211
|
*/
|
|
211
|
-
export function generateClaudeSettings() {
|
|
212
|
+
export function generateClaudeSettings(options = {}) {
|
|
212
213
|
const settings = {
|
|
213
214
|
$schema: 'https://json.schemastore.org/claude-code-settings.json',
|
|
214
215
|
permissions: {
|
|
@@ -216,7 +217,7 @@ export function generateClaudeSettings() {
|
|
|
216
217
|
deny: PERMISSIONS_DENY,
|
|
217
218
|
defaultMode: 'default',
|
|
218
219
|
},
|
|
219
|
-
hooks: buildHooksObject(),
|
|
220
|
+
hooks: buildHooksObject(options),
|
|
220
221
|
};
|
|
221
222
|
|
|
222
223
|
return JSON.stringify(settings, null, 2) + '\n';
|
|
@@ -68,10 +68,17 @@ function buildCodexReplacements(frameworkDir = 'chati.dev') {
|
|
|
68
68
|
['claude --print', 'codex exec'],
|
|
69
69
|
['claude -p', 'codex exec'],
|
|
70
70
|
['CLAUDE.local.md', 'AGENTS.override.md'],
|
|
71
|
-
['/chati', '$chati'],
|
|
72
71
|
];
|
|
73
72
|
}
|
|
74
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Convert the interactive slash command without touching filesystem paths such
|
|
76
|
+
* as `.chati.dev/orchestrator/chati.md`.
|
|
77
|
+
*/
|
|
78
|
+
function adaptCodexInvocation(content) {
|
|
79
|
+
return content.replace(/(?<![\w/])\/chati(?=\s|$|[`'".,;:!?)]|\b)/gm, '$chati');
|
|
80
|
+
}
|
|
81
|
+
|
|
75
82
|
// ---------------------------------------------------------------------------
|
|
76
83
|
// Generators
|
|
77
84
|
// ---------------------------------------------------------------------------
|
|
@@ -144,6 +151,7 @@ export function generateAgentsMd(content, contextFiles = null, frameworkDir = 'c
|
|
|
144
151
|
for (const [search, replace] of replacements) {
|
|
145
152
|
result = result.replaceAll(search, replace);
|
|
146
153
|
}
|
|
154
|
+
result = adaptCodexInvocation(result);
|
|
147
155
|
|
|
148
156
|
// Clean up any double blank lines left by stripping
|
|
149
157
|
result = result.replace(/\n{3,}/g, '\n\n');
|
|
@@ -166,6 +174,7 @@ export function generateAgentsMd(content, contextFiles = null, frameworkDir = 'c
|
|
|
166
174
|
for (const [search, replace] of replacements) {
|
|
167
175
|
adapted = adapted.replaceAll(search, replace);
|
|
168
176
|
}
|
|
177
|
+
adapted = adaptCodexInvocation(adapted);
|
|
169
178
|
sections.push(adapted.trim());
|
|
170
179
|
}
|
|
171
180
|
}
|
|
@@ -201,11 +201,19 @@ function buildReplacementConfig(provider) {
|
|
|
201
201
|
* @returns {string} Adapted content for the target provider
|
|
202
202
|
*/
|
|
203
203
|
export function adaptFrameworkFile(content, filePath, provider) {
|
|
204
|
-
if (provider === 'claude') return content;
|
|
205
204
|
if (!content) return content;
|
|
206
205
|
|
|
207
|
-
const config = buildReplacementConfig(provider);
|
|
208
206
|
let result = content;
|
|
207
|
+
if (filePath === 'orchestrator/chati.md') {
|
|
208
|
+
result = result.replace(
|
|
209
|
+
/<!-- CHATI_LEGACY_BUILD_START -->[\s\S]*?<!-- CHATI_LEGACY_BUILD_END -->\s*/g,
|
|
210
|
+
'For installations without `.chati/v2/installation.json`, use the separately bundled legacy compatibility runtime.\n\n',
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (provider === 'claude') return result;
|
|
215
|
+
|
|
216
|
+
const config = buildReplacementConfig(provider);
|
|
209
217
|
|
|
210
218
|
// 1. Apply ordered string replacements (most specific first)
|
|
211
219
|
for (const [search, replace] of config.strings) {
|
package/src/installer/core.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdirSync, writeFileSync, copyFileSync, existsSync, readFileSync, readdirSync, statSync } from 'fs';
|
|
1
|
+
import { mkdirSync, writeFileSync, copyFileSync, existsSync, readFileSync, readdirSync, statSync, rmSync } from 'fs';
|
|
2
2
|
import { execFileSync } from 'child_process';
|
|
3
3
|
import { join, dirname } from 'path';
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
@@ -12,6 +12,7 @@ import { generateClaudeSettings } from '../config/claude-settings-generator.js';
|
|
|
12
12
|
import { generateProviderOverlays } from './provider-overlay.js';
|
|
13
13
|
import { applyInstalledPathReplacement } from './path-replacement.js';
|
|
14
14
|
import { verifyManifest } from './manifest.js';
|
|
15
|
+
import * as yaml from 'js-yaml';
|
|
15
16
|
|
|
16
17
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
17
18
|
|
|
@@ -70,7 +71,13 @@ export async function installFramework(config) {
|
|
|
70
71
|
|
|
71
72
|
// 2b. Create artifacts/ at PROJECT ROOT (visible to user — this is their output)
|
|
72
73
|
const artifactsDir = join(targetDir, 'artifacts');
|
|
73
|
-
const
|
|
74
|
+
const isRuntimeV2 = config.runtimeVersion === 2;
|
|
75
|
+
const artifactDirs = isRuntimeV2 ? [
|
|
76
|
+
'0-WU', '1-Brief', '2-PRD',
|
|
77
|
+
'3-Architecture', '4-UX', '5-Phases',
|
|
78
|
+
'6-Tasks', '7-QA-Planning', '8-RAIL', '9-Release',
|
|
79
|
+
'handoffs', 'decisions',
|
|
80
|
+
] : [
|
|
74
81
|
'0-WU', '1-Brief', '2-PRD',
|
|
75
82
|
'3-Architecture', '4-UX', '5-Phases',
|
|
76
83
|
'6-Tasks', '7-QA-Planning', '8-QA-Visual', '9-QA-Implementation', '10-Deploy',
|
|
@@ -96,7 +103,7 @@ export async function installFramework(config) {
|
|
|
96
103
|
|
|
97
104
|
// Create .chati/memories/ directory tree for Memory Layer
|
|
98
105
|
const memoriesBase = join(targetDir, '.chati', 'memories');
|
|
99
|
-
const
|
|
106
|
+
const planningMemoryDirs = [
|
|
100
107
|
'shared/durable', 'shared/daily', 'shared/session',
|
|
101
108
|
'greenfield-wu/durable', 'greenfield-wu/daily',
|
|
102
109
|
'brownfield-wu/durable', 'brownfield-wu/daily',
|
|
@@ -107,11 +114,16 @@ export async function installFramework(config) {
|
|
|
107
114
|
'phases/durable', 'phases/daily',
|
|
108
115
|
'tasks/durable', 'tasks/daily',
|
|
109
116
|
'qa-planning/durable', 'qa-planning/daily',
|
|
117
|
+
];
|
|
118
|
+
const legacyExecutionMemoryDirs = [
|
|
110
119
|
'qa-implementation/durable', 'qa-implementation/daily',
|
|
111
120
|
'qa-visual/durable', 'qa-visual/daily',
|
|
112
121
|
'dev/durable', 'dev/daily',
|
|
113
122
|
'devops/durable', 'devops/daily',
|
|
114
123
|
];
|
|
124
|
+
const memoryDirs = isRuntimeV2
|
|
125
|
+
? [...planningMemoryDirs, 'rail/durable', 'rail/daily', 'release/durable', 'release/daily']
|
|
126
|
+
: [...planningMemoryDirs, ...legacyExecutionMemoryDirs];
|
|
115
127
|
for (const dir of memoryDirs) {
|
|
116
128
|
createDir(join(memoriesBase, dir));
|
|
117
129
|
}
|
|
@@ -125,6 +137,11 @@ export async function installFramework(config) {
|
|
|
125
137
|
generateProviderOverlays(targetDir, FRAMEWORK_SOURCE, allProviders);
|
|
126
138
|
}
|
|
127
139
|
|
|
140
|
+
if (isRuntimeV2) {
|
|
141
|
+
pruneLegacyExecutionSurface(frameworkDir, allProviders || []);
|
|
142
|
+
pruneLegacyRegistryEntities(frameworkDir);
|
|
143
|
+
}
|
|
144
|
+
|
|
128
145
|
// Bundle the CLI source into the framework dir so chati-router.js can run
|
|
129
146
|
// commands locally without depending on `npx chati-dev` (which fetches from
|
|
130
147
|
// the npm registry — version drift causes inconsistent behavior).
|
|
@@ -162,7 +179,7 @@ export async function installFramework(config) {
|
|
|
162
179
|
// Write config.yaml
|
|
163
180
|
writeFileSync(
|
|
164
181
|
join(frameworkDir, 'config.yaml'),
|
|
165
|
-
generateConfigYaml({ version, projectType, language, selectedIDEs, allProviders }),
|
|
182
|
+
generateConfigYaml({ version, projectType, language, selectedIDEs, allProviders, runtimeVersion: config.runtimeVersion }),
|
|
166
183
|
'utf-8'
|
|
167
184
|
);
|
|
168
185
|
|
|
@@ -174,7 +191,12 @@ export async function installFramework(config) {
|
|
|
174
191
|
const orchestratorPath = hasProviderOverlay
|
|
175
192
|
? `.chati.dev/.adapted/${ideProvider}/orchestrator/chati.md`
|
|
176
193
|
: '.chati.dev/orchestrator/chati.md';
|
|
177
|
-
await configureIDE(targetDir, ideKey, selectedMCPs, {
|
|
194
|
+
await configureIDE(targetDir, ideKey, selectedMCPs, {
|
|
195
|
+
orchestratorPath,
|
|
196
|
+
isSecondary: false,
|
|
197
|
+
providerName: ideProvider,
|
|
198
|
+
runtimeVersion: config.runtimeVersion,
|
|
199
|
+
});
|
|
178
200
|
}
|
|
179
201
|
|
|
180
202
|
const hasClaude = selectedIDEs.includes('claude-code');
|
|
@@ -224,6 +246,55 @@ export async function installFramework(config) {
|
|
|
224
246
|
ensureGitRepository(targetDir);
|
|
225
247
|
}
|
|
226
248
|
|
|
249
|
+
function pruneLegacyRegistryEntities(frameworkDir) {
|
|
250
|
+
const registryPath = join(frameworkDir, 'data', 'entity-registry.yaml');
|
|
251
|
+
if (!existsSync(registryPath)) return;
|
|
252
|
+
const registry = yaml.load(readFileSync(registryPath, 'utf-8'));
|
|
253
|
+
if (!registry?.entities) return;
|
|
254
|
+
const legacyPath = /\/(?:agents\/(?:build|deploy)\/|agents\/quality\/qa-(?:implementation|visual)\.md$|hooks\/post-dev\.js$|templates\/team-build-tasks\.yaml$|quality-gates\/implementation-gate\.md$|domains\/agents\/(?:dev|devops|qa-implementation|qa-visual)\.yaml$|tasks\/(?:dev-|devops-|qa-impl-))/;
|
|
255
|
+
let count = 0;
|
|
256
|
+
for (const entities of Object.values(registry.entities)) {
|
|
257
|
+
if (!entities || typeof entities !== 'object') continue;
|
|
258
|
+
for (const [name, entity] of Object.entries(entities)) {
|
|
259
|
+
if (legacyPath.test(entity?.path || '')) delete entities[name];
|
|
260
|
+
else if (entity?.path) count += 1;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
registry.metadata = { ...(registry.metadata || {}), entity_count: count };
|
|
264
|
+
writeFileSync(registryPath, yaml.dump(registry, { lineWidth: -1 }), 'utf-8');
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const V2_LEGACY_EXECUTION_PATHS = [
|
|
268
|
+
'agents/build',
|
|
269
|
+
'agents/deploy',
|
|
270
|
+
'agents/quality/qa-implementation.md',
|
|
271
|
+
'agents/quality/qa-visual.md',
|
|
272
|
+
'quality-gates/implementation-gate.md',
|
|
273
|
+
'templates/team-build-tasks.yaml',
|
|
274
|
+
'hooks/post-dev.js',
|
|
275
|
+
'domains/agents/dev.yaml',
|
|
276
|
+
'domains/agents/devops.yaml',
|
|
277
|
+
'domains/agents/qa-implementation.yaml',
|
|
278
|
+
'domains/agents/qa-visual.yaml',
|
|
279
|
+
];
|
|
280
|
+
|
|
281
|
+
function pruneLegacyExecutionSurface(frameworkDir, providers) {
|
|
282
|
+
const roots = [frameworkDir, ...providers.map(provider => join(frameworkDir, '.adapted', provider))];
|
|
283
|
+
for (const root of roots) {
|
|
284
|
+
for (const relativePath of V2_LEGACY_EXECUTION_PATHS) {
|
|
285
|
+
rmSync(join(root, relativePath), { recursive: true, force: true });
|
|
286
|
+
}
|
|
287
|
+
const tasksDir = join(root, 'tasks');
|
|
288
|
+
if (existsSync(tasksDir)) {
|
|
289
|
+
for (const entry of readdirSync(tasksDir)) {
|
|
290
|
+
if (/^(?:dev-|devops-|qa-impl-)/.test(entry)) {
|
|
291
|
+
rmSync(join(tasksDir, entry), { force: true });
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
227
298
|
export function ensureGitRepository(targetDir) {
|
|
228
299
|
try {
|
|
229
300
|
execFileSync('git', ['-C', targetDir, 'rev-parse', '--show-toplevel'], { stdio: 'ignore' });
|
|
@@ -415,7 +486,7 @@ Parse the JSON output. This single command already handled: license validation,
|
|
|
415
486
|
// hook system and applies a baseline permission policy. THIS IS THE FILE
|
|
416
487
|
// CLAUDE CODE READS — without it, every hook in chati.dev/hooks/ is dormant.
|
|
417
488
|
// (Pre-v4.2.2 bug: this file was never written, hooks never ran.)
|
|
418
|
-
writeClaudeSettingsWithMerge(join(targetDir, '.claude', 'settings.json'));
|
|
489
|
+
writeClaudeSettingsWithMerge(join(targetDir, '.claude', 'settings.json'), { runtimeVersion: options.runtimeVersion });
|
|
419
490
|
|
|
420
491
|
// Claude project-scope MCP config lives at the project root. Preserve
|
|
421
492
|
// unknown user-managed servers while replacing CHATI's known entries.
|
|
@@ -560,16 +631,16 @@ Governance rules are in \`.chati.dev/constitution.md\`.
|
|
|
560
631
|
\`\`\`
|
|
561
632
|
DISCOVER: WU -> Brief
|
|
562
633
|
PLAN: [Planning Team: Detail + Architect + UX + QA-Planning] -> Phases -> Tasks
|
|
563
|
-
|
|
564
|
-
|
|
634
|
+
RAIL: Sealed task graph -> Execute -> Independent Review -> Bounded Rework
|
|
635
|
+
RELEASE: Evidence gate -> Explicit human authorization -> External action
|
|
565
636
|
\`\`\`
|
|
566
637
|
|
|
567
638
|
## Agents
|
|
568
639
|
- DISCOVER: .chati.dev/agents/discover/
|
|
569
640
|
- PLAN: .chati.dev/agents/plan/
|
|
570
|
-
- Quality: .chati.dev/agents/quality/
|
|
571
|
-
-
|
|
572
|
-
-
|
|
641
|
+
- Planning Quality: .chati.dev/agents/quality/qa-planning.md
|
|
642
|
+
- RAIL Runtime: .chati.dev/_cli/ and .chati/v2/rail/
|
|
643
|
+
- Release Lane: RAIL completion evidence plus explicit authorization
|
|
573
644
|
`;
|
|
574
645
|
}
|
|
575
646
|
|
|
@@ -883,9 +954,9 @@ export function copyCliDependencies(pkgDir, destNodeModules) {
|
|
|
883
954
|
* If the file exists but is malformed: leave it alone, log a warning. We will
|
|
884
955
|
* not silently destroy user data.
|
|
885
956
|
*/
|
|
886
|
-
export function writeClaudeSettingsWithMerge(settingsPath) {
|
|
957
|
+
export function writeClaudeSettingsWithMerge(settingsPath, options = {}) {
|
|
887
958
|
createDir(dirname(settingsPath));
|
|
888
|
-
const fresh = JSON.parse(generateClaudeSettings());
|
|
959
|
+
const fresh = JSON.parse(generateClaudeSettings(options));
|
|
889
960
|
|
|
890
961
|
if (!existsSync(settingsPath)) {
|
|
891
962
|
writeFileSync(settingsPath, JSON.stringify(fresh, null, 2) + '\n', 'utf-8');
|
|
@@ -900,6 +971,16 @@ export function writeClaudeSettingsWithMerge(settingsPath) {
|
|
|
900
971
|
return;
|
|
901
972
|
}
|
|
902
973
|
|
|
974
|
+
if (options.runtimeVersion === 2 && existing.hooks) {
|
|
975
|
+
for (const groups of Object.values(existing.hooks)) {
|
|
976
|
+
if (!Array.isArray(groups)) continue;
|
|
977
|
+
for (const group of groups) {
|
|
978
|
+
if (Array.isArray(group.hooks)) {
|
|
979
|
+
group.hooks = group.hooks.filter(hook => !/\.chati\.dev\/hooks\/post-dev\.js$/.test(hook.command || ''));
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
}
|
|
903
984
|
const merged = mergeClaudeSettings(existing, fresh);
|
|
904
985
|
writeFileSync(settingsPath, JSON.stringify(merged, null, 2) + '\n', 'utf-8');
|
|
905
986
|
}
|
|
@@ -62,11 +62,12 @@ export function generateSessionYaml(config) {
|
|
|
62
62
|
reasoning_escalations: [],
|
|
63
63
|
};
|
|
64
64
|
|
|
65
|
-
//
|
|
65
|
+
// V2 ends the classic agent pipeline at Tasks. RAIL owns implementation,
|
|
66
|
+
// independent review, bounded rework and the Release Lane after handoff.
|
|
66
67
|
const agentNames = [
|
|
67
68
|
'greenfield-wu', 'brownfield-wu', 'brief', 'detail',
|
|
68
69
|
'architect', 'ux', 'phases', 'tasks',
|
|
69
|
-
'qa-planning',
|
|
70
|
+
'qa-planning',
|
|
70
71
|
];
|
|
71
72
|
|
|
72
73
|
for (const agent of agentNames) {
|
|
@@ -174,14 +175,14 @@ export function generateConfigYaml(config) {
|
|
|
174
175
|
model_fallback: true,
|
|
175
176
|
frustration_detection: true,
|
|
176
177
|
bash_security_checks: true,
|
|
177
|
-
// Agent Teams
|
|
178
|
+
// Agent Teams are planning-only in runtime v2.
|
|
178
179
|
// Only effective when the active session runs in Claude (gated in cli.js
|
|
179
180
|
// isAgentTeamsEnabled). Gemini and Codex always fall back to sequential
|
|
180
181
|
// pipeline silently. See plan: was previously false for "safe rollout"
|
|
181
182
|
// but the v4.2.0 launch never actually shipped, so this is a fresh start.
|
|
182
183
|
agent_teams: true,
|
|
183
184
|
team_planning_size: 4,
|
|
184
|
-
team_build_size: 2,
|
|
185
|
+
...(config.runtimeVersion === 2 ? {} : { team_build_size: 2 }),
|
|
185
186
|
team_echo_threshold: 0.92,
|
|
186
187
|
team_correction_cycles_max: 2,
|
|
187
188
|
};
|
|
@@ -17,6 +17,7 @@ function resolveFrameworkDir(targetDir) {
|
|
|
17
17
|
* Checks all primary agents, constitution, session, schemas, etc.
|
|
18
18
|
*/
|
|
19
19
|
export async function validateInstallation(targetDir) {
|
|
20
|
+
const isRuntimeV2 = existsSync(join(targetDir, '.chati', 'v2', 'installation.json'));
|
|
20
21
|
const results = {
|
|
21
22
|
agents: { pass: false, details: [] },
|
|
22
23
|
constitution: { pass: false, details: [] },
|
|
@@ -35,7 +36,7 @@ export async function validateInstallation(targetDir) {
|
|
|
35
36
|
};
|
|
36
37
|
|
|
37
38
|
// Check all primary agents (orchestrator + 12 specialized, sub-agents validated by managers)
|
|
38
|
-
const
|
|
39
|
+
const planningAgentFiles = [
|
|
39
40
|
'orchestrator/chati.md',
|
|
40
41
|
'agents/discover/greenfield-wu.md',
|
|
41
42
|
'agents/discover/brownfield-wu.md',
|
|
@@ -46,10 +47,15 @@ export async function validateInstallation(targetDir) {
|
|
|
46
47
|
'agents/plan/phases.md',
|
|
47
48
|
'agents/plan/tasks.md',
|
|
48
49
|
'agents/quality/qa-planning.md',
|
|
50
|
+
];
|
|
51
|
+
const legacyExecutionAgentFiles = [
|
|
49
52
|
'agents/quality/qa-implementation.md',
|
|
50
53
|
'agents/build/dev.md',
|
|
51
54
|
'agents/deploy/devops.md',
|
|
52
55
|
];
|
|
56
|
+
const agentFiles = isRuntimeV2
|
|
57
|
+
? planningAgentFiles
|
|
58
|
+
: [...planningAgentFiles, ...legacyExecutionAgentFiles];
|
|
53
59
|
|
|
54
60
|
let agentCount = 0;
|
|
55
61
|
for (const file of agentFiles) {
|
|
@@ -64,7 +70,7 @@ export async function validateInstallation(targetDir) {
|
|
|
64
70
|
results.agents.details.push({ file, exists: false, hasProtocols: false });
|
|
65
71
|
}
|
|
66
72
|
}
|
|
67
|
-
results.agents.pass = agentCount ===
|
|
73
|
+
results.agents.pass = agentCount === agentFiles.length;
|
|
68
74
|
results.total += 1;
|
|
69
75
|
if (results.agents.pass) results.passed += 1;
|
|
70
76
|
|
|
@@ -158,21 +158,28 @@ export function runHealthCheck(targetDir) {
|
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
// 4. Agent check
|
|
161
|
-
const
|
|
161
|
+
const planningAgentPaths = [
|
|
162
162
|
'orchestrator/chati.md',
|
|
163
163
|
'agents/discover/greenfield-wu.md', 'agents/discover/brownfield-wu.md',
|
|
164
164
|
'agents/discover/brief.md', 'agents/plan/detail.md',
|
|
165
165
|
'agents/plan/architect.md', 'agents/plan/ux.md',
|
|
166
166
|
'agents/plan/phases.md', 'agents/plan/tasks.md',
|
|
167
|
-
'agents/quality/qa-planning.md',
|
|
167
|
+
'agents/quality/qa-planning.md',
|
|
168
|
+
];
|
|
169
|
+
const legacyExecutionAgentPaths = [
|
|
170
|
+
'agents/quality/qa-implementation.md',
|
|
168
171
|
'agents/build/dev.md', 'agents/deploy/devops.md',
|
|
169
172
|
];
|
|
173
|
+
const isRuntimeV2 = existsSync(join(targetDir, '.chati', 'v2', 'installation.json'));
|
|
174
|
+
const agentPaths = isRuntimeV2
|
|
175
|
+
? planningAgentPaths
|
|
176
|
+
: [...planningAgentPaths, ...legacyExecutionAgentPaths];
|
|
170
177
|
let foundAgents = 0;
|
|
171
178
|
for (const p of agentPaths) {
|
|
172
179
|
if (existsSync(join(targetDir, fwDir, p))) foundAgents++;
|
|
173
180
|
}
|
|
174
|
-
checks.agents.pass = foundAgents ===
|
|
175
|
-
checks.agents.details = `${foundAgents}
|
|
181
|
+
checks.agents.pass = foundAgents === agentPaths.length;
|
|
182
|
+
checks.agents.details = `${foundAgents}/${agentPaths.length} present`;
|
|
176
183
|
|
|
177
184
|
// 5. Entity validation (registry vs filesystem)
|
|
178
185
|
const entityResult = validateEntities(targetDir);
|