chati-dev 3.0.0 → 3.0.2
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 +96 -24
- package/assets/logo2.png +0 -0
- package/assets/social-preview.png +0 -0
- package/bin/chati.js +1 -1
- package/framework/agents/plan/phases.md +2 -2
- package/framework/config.yaml +2 -2
- package/framework/constitution.md +4 -4
- package/framework/context/governance.md +16 -3
- package/framework/context/root.md +3 -3
- package/framework/data/entity-registry.yaml +1 -1
- package/framework/domains/agents/detail.yaml +1 -1
- package/framework/domains/agents/phases.yaml +2 -2
- package/framework/domains/agents/tasks.yaml +2 -2
- package/framework/domains/constitution.yaml +2 -2
- package/framework/hooks/read-protection.js +1 -0
- package/framework/i18n/en.yaml +11 -4
- package/framework/i18n/es.yaml +11 -4
- package/framework/i18n/fr.yaml +11 -4
- package/framework/i18n/pt.yaml +11 -4
- package/framework/intelligence/context-engine.md +4 -4
- package/framework/intelligence/decision-engine.md +1 -1
- package/framework/patterns/elicitation-library.yaml +2 -2
- package/framework/tasks/brownfield-wu-dependency-scan.md +1 -1
- package/framework/tasks/brownfield-wu-migration-plan.md +4 -4
- package/framework/tasks/brownfield-wu-risk-assess.md +2 -2
- package/framework/tasks/detail-expand-prd.md +2 -2
- package/framework/tasks/greenfield-wu-report.md +1 -1
- package/framework/tasks/orchestrator-handoff.md +2 -2
- package/framework/tasks/orchestrator-resume.md +1 -1
- package/framework/tasks/qa-impl-performance-test.md +2 -2
- package/framework/tasks/qa-impl-sast-scan.md +6 -6
- package/framework/tasks/qa-planning-consolidate.md +1 -1
- package/framework/tasks/qa-planning-coverage-plan.md +9 -9
- package/framework/tasks/qa-planning-gate-define.md +6 -6
- package/framework/tasks/qa-planning-risk-matrix.md +1 -1
- package/framework/tasks/tasks-consolidate.md +5 -5
- package/package.json +1 -1
- package/scripts/changelog-generator.js +2 -2
- package/scripts/ide-sync.js +9 -4
- package/scripts/pr-review.js +5 -5
- package/scripts/semantic-lint.js +3 -3
- package/src/autonomy/build-state.js +1 -1
- package/src/autonomy/execution-profile.js +1 -1
- package/src/config/context-file-generator.js +31 -34
- package/src/config/ide-configs.js +15 -6
- package/src/dashboard/layout.js +3 -1
- package/src/gates/g2-qa-planning.js +1 -1
- package/src/gates/g4-qa-implementation.js +1 -1
- package/src/health/engine.js +7 -12
- package/src/installer/core.js +69 -34
- package/src/installer/templates.js +168 -2
- package/src/installer/validator.js +5 -3
- package/src/intelligence/registry-manager.js +2 -2
- package/src/preview/detector.js +1 -1
- package/src/terminal/adapters/claude-adapter.js +3 -13
- package/src/terminal/adapters/codex-adapter.js +3 -13
- package/src/terminal/adapters/copilot-adapter.js +3 -13
- package/src/terminal/adapters/gemini-adapter.js +3 -17
- package/src/terminal/cli-registry.js +20 -48
- package/src/terminal/index.js +1 -0
- package/src/terminal/prompt-builder.js +3 -18
- package/src/terminal/run-agent.js +2 -1
- package/src/terminal/spawner.js +70 -8
- package/src/terminal/wave-analyzer.js +1 -1
- package/src/utils/config-parser.js +97 -0
- package/src/wizard/feedback.js +1 -1
- package/src/wizard/i18n.js +11 -4
- package/src/wizard/index.js +45 -15
- package/src/wizard/questions.js +54 -3
- package/assets/logo - c/303/263pia.svg" +0 -42
package/src/dashboard/layout.js
CHANGED
|
@@ -64,7 +64,9 @@ export function buildProjectInfo(data) {
|
|
|
64
64
|
const state = formatState(project.state);
|
|
65
65
|
const mode = formatMode(session.execution_mode);
|
|
66
66
|
const lang = session.language || 'en';
|
|
67
|
-
|
|
67
|
+
// Show the provider-specific IDE (last in the list) rather than always claude-code
|
|
68
|
+
const ides = session.ides || [];
|
|
69
|
+
const ide = ides[ides.length - 1] || 'unknown';
|
|
68
70
|
|
|
69
71
|
return [
|
|
70
72
|
brand('│') + ` ${dim('Project:')} ${name}` + ' '.repeat(Math.max(1, 30 - name.length)) + `${dim('Type:')} ${type}` + ' '.repeat(Math.max(1, 18 - type.length)) + brand('│'),
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { existsSync, readdirSync } from 'node:fs';
|
|
9
9
|
import { join } from 'node:path';
|
|
10
|
-
import { GateBase,
|
|
10
|
+
import { GateBase, determineVerdict } from './gate-base.js';
|
|
11
11
|
import { loadSession } from '../orchestrator/session-manager.js';
|
|
12
12
|
import { loadHandoff } from '../tasks/handoff.js';
|
|
13
13
|
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
import { existsSync } from 'node:fs';
|
|
16
16
|
import { join } from 'node:path';
|
|
17
|
-
import { GateBase,
|
|
17
|
+
import { GateBase, determineVerdict } from './gate-base.js';
|
|
18
18
|
import { loadSession } from '../orchestrator/session-manager.js';
|
|
19
19
|
import { loadHandoff } from '../tasks/handoff.js';
|
|
20
20
|
|
package/src/health/engine.js
CHANGED
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* Constitution Article XIV — Framework Registry Governance.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { existsSync, readFileSync
|
|
9
|
+
import { existsSync, readFileSync } from 'fs';
|
|
10
10
|
import { join } from 'path';
|
|
11
|
+
import { isCommandAvailable, parseProviderConfig } from '../utils/config-parser.js';
|
|
11
12
|
|
|
12
13
|
// ---------------------------------------------------------------------------
|
|
13
14
|
// Check Result Types
|
|
@@ -50,19 +51,13 @@ export async function checkCliAvailability(projectDir) {
|
|
|
50
51
|
return { name: 'cli-availability', status: 'warn', message: 'No config.yaml found', duration: Date.now() - start };
|
|
51
52
|
}
|
|
52
53
|
|
|
53
|
-
const
|
|
54
|
-
const providers = ['claude', 'gemini', 'codex', 'copilot'];
|
|
54
|
+
const { enabled } = parseProviderConfig(projectDir);
|
|
55
55
|
const missing = [];
|
|
56
56
|
|
|
57
|
-
for (const provider of
|
|
58
|
-
const
|
|
59
|
-
if (
|
|
60
|
-
|
|
61
|
-
try {
|
|
62
|
-
execSync(`which ${provider}`, { stdio: 'ignore' });
|
|
63
|
-
} catch {
|
|
64
|
-
missing.push(provider);
|
|
65
|
-
}
|
|
57
|
+
for (const provider of enabled) {
|
|
58
|
+
const available = await isCommandAvailable(provider);
|
|
59
|
+
if (!available) {
|
|
60
|
+
missing.push(provider);
|
|
66
61
|
}
|
|
67
62
|
}
|
|
68
63
|
|
package/src/installer/core.js
CHANGED
|
@@ -3,7 +3,8 @@ import { join, dirname } from 'path';
|
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import { IDE_CONFIGS } from '../config/ide-configs.js';
|
|
5
5
|
import { generateClaudeMCPConfig } from '../config/mcp-configs.js';
|
|
6
|
-
import { generateSessionYaml, generateConfigYaml, generateClaudeMd, generateClaudeLocalMd } from './templates.js';
|
|
6
|
+
import { generateSessionYaml, generateConfigYaml, generateClaudeMd, generateClaudeLocalMd, generateCodexRouter, generateGeminiRouter, generateCopilotAgent } from './templates.js';
|
|
7
|
+
import { generateContextFiles } from '../config/context-file-generator.js';
|
|
7
8
|
import { verifyManifest } from './manifest.js';
|
|
8
9
|
|
|
9
10
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -18,7 +19,7 @@ const FRAMEWORK_SOURCE = existsSync(BUNDLED_SOURCE) ? BUNDLED_SOURCE : MONOREPO_
|
|
|
18
19
|
* Install Chati.dev framework into target directory
|
|
19
20
|
*/
|
|
20
21
|
export async function installFramework(config) {
|
|
21
|
-
const { targetDir, projectType, language, selectedIDEs, selectedMCPs, projectName, version } = config;
|
|
22
|
+
const { targetDir, projectType, language, selectedIDEs, selectedMCPs, projectName, version, llmProvider } = config;
|
|
22
23
|
|
|
23
24
|
// 0. Verify framework signature (supply chain protection)
|
|
24
25
|
const manifestPath = join(FRAMEWORK_SOURCE, 'manifest.json');
|
|
@@ -38,7 +39,7 @@ export async function installFramework(config) {
|
|
|
38
39
|
createDir(join(targetDir, '.chati'));
|
|
39
40
|
writeFileSync(
|
|
40
41
|
join(targetDir, '.chati', 'session.yaml'),
|
|
41
|
-
generateSessionYaml({ projectName, projectType, language, selectedIDEs, selectedMCPs }),
|
|
42
|
+
generateSessionYaml({ projectName, projectType, language, selectedIDEs, selectedMCPs, llmProvider }),
|
|
42
43
|
'utf-8'
|
|
43
44
|
);
|
|
44
45
|
|
|
@@ -91,7 +92,7 @@ export async function installFramework(config) {
|
|
|
91
92
|
// Write config.yaml
|
|
92
93
|
writeFileSync(
|
|
93
94
|
join(frameworkDir, 'config.yaml'),
|
|
94
|
-
generateConfigYaml({ version, projectType, language, selectedIDEs }),
|
|
95
|
+
generateConfigYaml({ version, projectType, language, selectedIDEs, llmProvider }),
|
|
95
96
|
'utf-8'
|
|
96
97
|
);
|
|
97
98
|
|
|
@@ -100,30 +101,32 @@ export async function installFramework(config) {
|
|
|
100
101
|
await configureIDE(targetDir, ideKey, selectedMCPs);
|
|
101
102
|
}
|
|
102
103
|
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
104
|
+
const hasClaude = selectedIDEs.includes('claude-code');
|
|
105
|
+
const hasNonClaude = selectedIDEs.some(ide => ide !== 'claude-code');
|
|
106
|
+
|
|
107
|
+
// 4. Generate base content (used as source for all provider context files)
|
|
108
|
+
const baseContent = generateClaudeMd({ projectName, projectType, language });
|
|
109
|
+
|
|
110
|
+
// 5. Claude Code specific: .claude/rules/chati/, CLAUDE.md, CLAUDE.local.md
|
|
111
|
+
if (hasClaude) {
|
|
112
|
+
const contextFiles = ['root.md', 'governance.md', 'protocols.md', 'quality.md'];
|
|
113
|
+
const claudeRulesDir = join(targetDir, '.claude', 'rules', 'chati');
|
|
114
|
+
createDir(claudeRulesDir);
|
|
115
|
+
for (const file of contextFiles) {
|
|
116
|
+
const src = join(FRAMEWORK_SOURCE, 'context', file);
|
|
117
|
+
if (existsSync(src)) {
|
|
118
|
+
copyFileSync(src, join(claudeRulesDir, file));
|
|
119
|
+
}
|
|
111
120
|
}
|
|
112
|
-
}
|
|
113
121
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
generateClaudeMd({ projectName, projectType, language }),
|
|
118
|
-
'utf-8'
|
|
119
|
-
);
|
|
122
|
+
writeFileSync(join(targetDir, 'CLAUDE.md'), baseContent, 'utf-8');
|
|
123
|
+
writeFileSync(join(targetDir, 'CLAUDE.local.md'), generateClaudeLocalMd(), 'utf-8');
|
|
124
|
+
}
|
|
120
125
|
|
|
121
|
-
// 6.
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
'utf-8'
|
|
126
|
-
);
|
|
126
|
+
// 6. Non-Claude providers: generate context files (GEMINI.md, AGENTS.md) from base content
|
|
127
|
+
if (hasNonClaude) {
|
|
128
|
+
generateContextFiles(targetDir, baseContent);
|
|
129
|
+
}
|
|
127
130
|
}
|
|
128
131
|
|
|
129
132
|
/**
|
|
@@ -157,12 +160,14 @@ function copyFrameworkFiles(destDir) {
|
|
|
157
160
|
'templates/fullstack-architecture-tmpl.yaml',
|
|
158
161
|
'templates/task-tmpl.yaml',
|
|
159
162
|
'templates/qa-gate-tmpl.yaml',
|
|
163
|
+
'templates/quick-brief-tmpl.yaml',
|
|
160
164
|
// Workflows
|
|
161
165
|
'workflows/greenfield-fullstack.yaml',
|
|
162
166
|
'workflows/brownfield-fullstack.yaml',
|
|
163
167
|
'workflows/brownfield-discovery.yaml',
|
|
164
168
|
'workflows/brownfield-service.yaml',
|
|
165
169
|
'workflows/brownfield-ui.yaml',
|
|
170
|
+
'workflows/quick-flow.yaml',
|
|
166
171
|
// Quality gates
|
|
167
172
|
'quality-gates/planning-gate.md',
|
|
168
173
|
'quality-gates/implementation-gate.md',
|
|
@@ -191,6 +196,7 @@ function copyFrameworkFiles(destDir) {
|
|
|
191
196
|
'hooks/session-digest.js',
|
|
192
197
|
'hooks/model-governance.js',
|
|
193
198
|
'hooks/settings.json',
|
|
199
|
+
'hooks/read-protection.js',
|
|
194
200
|
// Domains (PRISM Context Engine)
|
|
195
201
|
'domains/constitution.yaml',
|
|
196
202
|
'domains/global.yaml',
|
|
@@ -212,6 +218,7 @@ function copyFrameworkFiles(destDir) {
|
|
|
212
218
|
'domains/workflows/brownfield-discovery.yaml',
|
|
213
219
|
'domains/workflows/brownfield-service.yaml',
|
|
214
220
|
'domains/workflows/brownfield-ui.yaml',
|
|
221
|
+
'domains/workflows/quick-flow.yaml',
|
|
215
222
|
// i18n
|
|
216
223
|
'i18n/en.yaml',
|
|
217
224
|
'i18n/pt.yaml',
|
|
@@ -294,10 +301,35 @@ Pass through all context: session state, handoffs, artifacts, and user input.
|
|
|
294
301
|
'utf-8'
|
|
295
302
|
);
|
|
296
303
|
}
|
|
304
|
+
} else if (ideKey === 'codex-cli') {
|
|
305
|
+
// Codex CLI: /chati slash command via .codex/commands/
|
|
306
|
+
writeFileSync(join(targetDir, '.codex', 'commands', 'chati.md'), generateCodexRouter(), 'utf-8');
|
|
307
|
+
} else if (ideKey === 'gemini-cli') {
|
|
308
|
+
// Gemini CLI: TOML command file (native format for /chati command)
|
|
309
|
+
writeFileSync(join(targetDir, '.gemini', 'commands', 'chati.toml'), generateGeminiRouter(), 'utf-8');
|
|
310
|
+
} else if (ideKey === 'github-copilot') {
|
|
311
|
+
// GitHub Copilot: agent file (.github/agents/chati.md) for @chati invocation
|
|
312
|
+
writeFileSync(join(targetDir, '.github', 'agents', 'chati.md'), generateCopilotAgent(), 'utf-8');
|
|
313
|
+
|
|
314
|
+
// Copilot instructions file (auto-loaded by Copilot CLI)
|
|
315
|
+
createDir(dirname(join(targetDir, config.rulesFile)));
|
|
316
|
+
writeFileSync(join(targetDir, config.rulesFile), generateProviderInstructions(config.name), 'utf-8');
|
|
297
317
|
} else {
|
|
298
|
-
//
|
|
299
|
-
|
|
300
|
-
|
|
318
|
+
// VS Code, Cursor, AntiGravity — generic rules file
|
|
319
|
+
if (config.rulesFile) {
|
|
320
|
+
createDir(dirname(join(targetDir, config.rulesFile)));
|
|
321
|
+
writeFileSync(join(targetDir, config.rulesFile), generateProviderInstructions(config.name), 'utf-8');
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Generate provider-agnostic instructions file content.
|
|
328
|
+
* Used for non-Claude IDEs (.github/copilot-instructions.md, .vscode/chati/rules.md, etc.)
|
|
329
|
+
*/
|
|
330
|
+
function generateProviderInstructions(providerName) {
|
|
331
|
+
return `# Chati.dev System Rules
|
|
332
|
+
# This file configures ${providerName} to work with Chati.dev
|
|
301
333
|
|
|
302
334
|
## System Location
|
|
303
335
|
All system content is in the \`chati.dev/\` directory.
|
|
@@ -310,7 +342,15 @@ The orchestrator is at \`chati.dev/orchestrator/chati.md\`.
|
|
|
310
342
|
Read it to understand routing, session management, and agent activation.
|
|
311
343
|
|
|
312
344
|
## Constitution
|
|
313
|
-
Governance rules are in \`chati.dev/constitution.md\` (
|
|
345
|
+
Governance rules are in \`chati.dev/constitution.md\` (19 Articles).
|
|
346
|
+
|
|
347
|
+
## Pipeline
|
|
348
|
+
\`\`\`
|
|
349
|
+
DISCOVER: WU -> Brief
|
|
350
|
+
PLAN: Detail -> Architect -> UX -> Phases -> Tasks -> QA-Planning
|
|
351
|
+
BUILD: Dev -> QA-Implementation
|
|
352
|
+
DEPLOY: DevOps
|
|
353
|
+
\`\`\`
|
|
314
354
|
|
|
315
355
|
## Agents
|
|
316
356
|
- DISCOVER: chati.dev/agents/discover/ (3 agents)
|
|
@@ -319,11 +359,6 @@ Governance rules are in \`chati.dev/constitution.md\` (17 Articles).
|
|
|
319
359
|
- BUILD: chati.dev/agents/build/ (1 agent)
|
|
320
360
|
- DEPLOY: chati.dev/agents/deploy/ (1 agent)
|
|
321
361
|
`;
|
|
322
|
-
if (config.rulesFile) {
|
|
323
|
-
createDir(dirname(join(targetDir, config.rulesFile)));
|
|
324
|
-
writeFileSync(join(targetDir, config.rulesFile), rulesContent, 'utf-8');
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
362
|
}
|
|
328
363
|
|
|
329
364
|
/**
|
|
@@ -4,7 +4,7 @@ import yaml from 'js-yaml';
|
|
|
4
4
|
* Generate session.yaml content
|
|
5
5
|
*/
|
|
6
6
|
export function generateSessionYaml(config) {
|
|
7
|
-
const { projectName, projectType, language, selectedIDEs, selectedMCPs } = config;
|
|
7
|
+
const { projectName, projectType, language, selectedIDEs, selectedMCPs, llmProvider } = config;
|
|
8
8
|
|
|
9
9
|
const session = {
|
|
10
10
|
project: {
|
|
@@ -13,16 +13,19 @@ export function generateSessionYaml(config) {
|
|
|
13
13
|
state: 'discover',
|
|
14
14
|
},
|
|
15
15
|
execution_mode: 'interactive',
|
|
16
|
+
execution_profile: 'guided',
|
|
16
17
|
current_agent: '',
|
|
17
18
|
language: language,
|
|
18
19
|
ides: selectedIDEs,
|
|
19
20
|
mcps: selectedMCPs,
|
|
21
|
+
providers_enabled: [llmProvider || 'claude'],
|
|
20
22
|
user_level: 'auto',
|
|
21
23
|
user_level_confidence: 0.0,
|
|
22
24
|
agents: {},
|
|
23
25
|
backlog: [],
|
|
24
26
|
last_handoff: '',
|
|
25
27
|
deviations: [],
|
|
28
|
+
profile_transitions: [],
|
|
26
29
|
};
|
|
27
30
|
|
|
28
31
|
// Initialize all 12 agent statuses
|
|
@@ -44,11 +47,56 @@ export function generateSessionYaml(config) {
|
|
|
44
47
|
return yaml.dump(session, { lineWidth: -1, quotingType: '"', forceQuotes: false });
|
|
45
48
|
}
|
|
46
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Optimal model assignments per provider.
|
|
52
|
+
* Deep reasoning agents (architect, qa, dev, detail, brownfield-wu) get the top model.
|
|
53
|
+
* Lightweight agents (brief, phases, ux, greenfield-wu, devops, orchestrator) get the fast model.
|
|
54
|
+
*/
|
|
55
|
+
const PROVIDER_MODEL_MAPS = {
|
|
56
|
+
claude: {
|
|
57
|
+
deep: 'opus', light: 'sonnet', minimal: 'haiku',
|
|
58
|
+
agents: {
|
|
59
|
+
orchestrator: 'sonnet', 'greenfield-wu': 'haiku', 'brownfield-wu': 'opus',
|
|
60
|
+
brief: 'sonnet', detail: 'opus', architect: 'opus', ux: 'sonnet',
|
|
61
|
+
phases: 'sonnet', tasks: 'sonnet', 'qa-planning': 'opus',
|
|
62
|
+
dev: 'opus', 'qa-implementation': 'opus', devops: 'sonnet',
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
gemini: {
|
|
66
|
+
deep: 'pro', light: 'flash', minimal: 'flash',
|
|
67
|
+
agents: {
|
|
68
|
+
orchestrator: 'flash', 'greenfield-wu': 'flash', 'brownfield-wu': 'pro',
|
|
69
|
+
brief: 'flash', detail: 'pro', architect: 'pro', ux: 'flash',
|
|
70
|
+
phases: 'flash', tasks: 'flash', 'qa-planning': 'pro',
|
|
71
|
+
dev: 'pro', 'qa-implementation': 'pro', devops: 'flash',
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
codex: {
|
|
75
|
+
deep: 'codex', light: 'mini', minimal: 'mini',
|
|
76
|
+
agents: {
|
|
77
|
+
orchestrator: 'mini', 'greenfield-wu': 'mini', 'brownfield-wu': 'codex',
|
|
78
|
+
brief: 'mini', detail: 'codex', architect: 'codex', ux: 'mini',
|
|
79
|
+
phases: 'mini', tasks: 'mini', 'qa-planning': 'codex',
|
|
80
|
+
dev: 'codex', 'qa-implementation': 'codex', devops: 'mini',
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
copilot: {
|
|
84
|
+
deep: 'claude-sonnet', light: 'claude-sonnet', minimal: 'gpt-5',
|
|
85
|
+
agents: {
|
|
86
|
+
orchestrator: 'claude-sonnet', 'greenfield-wu': 'gpt-5', 'brownfield-wu': 'claude-sonnet',
|
|
87
|
+
brief: 'claude-sonnet', detail: 'claude-sonnet', architect: 'claude-sonnet', ux: 'claude-sonnet',
|
|
88
|
+
phases: 'claude-sonnet', tasks: 'claude-sonnet', 'qa-planning': 'claude-sonnet',
|
|
89
|
+
dev: 'claude-sonnet', 'qa-implementation': 'claude-sonnet', devops: 'claude-sonnet',
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
|
|
47
94
|
/**
|
|
48
95
|
* Generate config.yaml content
|
|
49
96
|
*/
|
|
50
97
|
export function generateConfigYaml(config) {
|
|
51
|
-
const { version, projectType, language, selectedIDEs } = config;
|
|
98
|
+
const { version, projectType, language, selectedIDEs, llmProvider } = config;
|
|
99
|
+
const provider = llmProvider || 'claude';
|
|
52
100
|
|
|
53
101
|
const configData = {
|
|
54
102
|
version: version,
|
|
@@ -58,8 +106,25 @@ export function generateConfigYaml(config) {
|
|
|
58
106
|
project_type: projectType,
|
|
59
107
|
language: language,
|
|
60
108
|
ides: selectedIDEs,
|
|
109
|
+
providers: {
|
|
110
|
+
claude: { enabled: true, primary: provider === 'claude' },
|
|
111
|
+
gemini: { enabled: provider === 'gemini' || selectedIDEs.includes('gemini-cli'), model_default: 'pro', primary: provider === 'gemini' },
|
|
112
|
+
codex: { enabled: provider === 'codex' || selectedIDEs.includes('codex-cli'), model_default: 'codex', primary: provider === 'codex' },
|
|
113
|
+
copilot: { enabled: provider === 'copilot' || selectedIDEs.includes('github-copilot'), primary: provider === 'copilot' },
|
|
114
|
+
},
|
|
61
115
|
};
|
|
62
116
|
|
|
117
|
+
// Add agent_overrides with optimal model map for the selected provider
|
|
118
|
+
if (provider !== 'claude') {
|
|
119
|
+
const modelMap = PROVIDER_MODEL_MAPS[provider];
|
|
120
|
+
if (modelMap) {
|
|
121
|
+
configData.agent_overrides = {};
|
|
122
|
+
for (const [agent, model] of Object.entries(modelMap.agents)) {
|
|
123
|
+
configData.agent_overrides[agent] = { provider, model };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
63
128
|
return yaml.dump(configData, { lineWidth: -1, quotingType: '"', forceQuotes: false });
|
|
64
129
|
}
|
|
65
130
|
|
|
@@ -81,6 +146,107 @@ Type \`/chati\` to start.
|
|
|
81
146
|
`;
|
|
82
147
|
}
|
|
83
148
|
|
|
149
|
+
/**
|
|
150
|
+
* Generate Codex CLI command (.codex/commands/chati.md)
|
|
151
|
+
*
|
|
152
|
+
* Codex CLI supports /chati slash command via .codex/commands/.
|
|
153
|
+
* Also reads AGENTS.md for project context (auto-generated by context-file-generator).
|
|
154
|
+
*/
|
|
155
|
+
export function generateCodexRouter() {
|
|
156
|
+
return `# /chati — Thin Router
|
|
157
|
+
|
|
158
|
+
## CRITICAL — Language Override
|
|
159
|
+
|
|
160
|
+
Read \`.chati/session.yaml\` field \`language\` BEFORE anything else.
|
|
161
|
+
ALL responses MUST be in this language. This overrides any global setting.
|
|
162
|
+
|
|
163
|
+
| Value | Language |
|
|
164
|
+
|-------|----------|
|
|
165
|
+
| \`en\` | English |
|
|
166
|
+
| \`pt\` | Portugues |
|
|
167
|
+
| \`es\` | Espanol |
|
|
168
|
+
| \`fr\` | Francais |
|
|
169
|
+
|
|
170
|
+
If session.yaml does not exist or has no language field, default to English.
|
|
171
|
+
|
|
172
|
+
## Load
|
|
173
|
+
|
|
174
|
+
Read and execute the full orchestrator at \`chati.dev/orchestrator/chati.md\`.
|
|
175
|
+
|
|
176
|
+
Pass through all context: session state, handoffs, artifacts, and user input.
|
|
177
|
+
|
|
178
|
+
**Context to pass:**
|
|
179
|
+
- \`.chati/session.yaml\` (session state — includes language)
|
|
180
|
+
- \`AGENTS.md\` (project context — auto-generated)
|
|
181
|
+
- \`chati.dev/artifacts/handoffs/\` (latest handoff)
|
|
182
|
+
- \`chati.dev/config.yaml\` (version info)
|
|
183
|
+
`;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Generate Gemini CLI TOML command (.gemini/commands/chati.toml)
|
|
188
|
+
*
|
|
189
|
+
* Gemini CLI custom commands use TOML format with `description` and `prompt` fields.
|
|
190
|
+
* Supports {{args}} for user arguments and @{file} for file injection.
|
|
191
|
+
*/
|
|
192
|
+
export function generateGeminiRouter() {
|
|
193
|
+
return `description = "Activate Chati.dev orchestrator"
|
|
194
|
+
prompt = """
|
|
195
|
+
CRITICAL — Language Override:
|
|
196
|
+
Read \`.chati/session.yaml\` field \`language\` BEFORE anything else.
|
|
197
|
+
ALL responses MUST be in this language (en, pt, es, fr).
|
|
198
|
+
If session.yaml does not exist or has no language field, default to English.
|
|
199
|
+
|
|
200
|
+
Read and execute the full orchestrator at \`chati.dev/orchestrator/chati.md\`.
|
|
201
|
+
|
|
202
|
+
Context to load:
|
|
203
|
+
- \`.chati/session.yaml\` (session state — includes language)
|
|
204
|
+
- \`chati.dev/artifacts/handoffs/\` (latest handoff)
|
|
205
|
+
- \`chati.dev/config.yaml\` (version info)
|
|
206
|
+
|
|
207
|
+
User input: {{args}}
|
|
208
|
+
"""
|
|
209
|
+
`;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Generate GitHub Copilot agent file (.github/agents/chati.md)
|
|
214
|
+
*
|
|
215
|
+
* Copilot CLI uses .github/agents/*.md for custom agents.
|
|
216
|
+
* The user invokes with @chati in the Copilot CLI.
|
|
217
|
+
*/
|
|
218
|
+
export function generateCopilotAgent() {
|
|
219
|
+
return `# Chati.dev Orchestrator
|
|
220
|
+
|
|
221
|
+
You are the Chati.dev orchestrator agent for GitHub Copilot CLI.
|
|
222
|
+
|
|
223
|
+
## CRITICAL — Language Override
|
|
224
|
+
|
|
225
|
+
Read \`.chati/session.yaml\` field \`language\` BEFORE anything else.
|
|
226
|
+
ALL responses MUST be in this language. This overrides any global setting.
|
|
227
|
+
|
|
228
|
+
| Value | Language |
|
|
229
|
+
|-------|----------|
|
|
230
|
+
| \`en\` | English |
|
|
231
|
+
| \`pt\` | Portugues |
|
|
232
|
+
| \`es\` | Espanol |
|
|
233
|
+
| \`fr\` | Francais |
|
|
234
|
+
|
|
235
|
+
If session.yaml does not exist or has no language field, default to English.
|
|
236
|
+
|
|
237
|
+
## Load
|
|
238
|
+
|
|
239
|
+
Read and execute the full orchestrator at \`chati.dev/orchestrator/chati.md\`.
|
|
240
|
+
|
|
241
|
+
Pass through all context: session state, handoffs, artifacts, and user input.
|
|
242
|
+
|
|
243
|
+
**Context to pass:**
|
|
244
|
+
- \`.chati/session.yaml\` (session state — includes language)
|
|
245
|
+
- \`chati.dev/artifacts/handoffs/\` (latest handoff)
|
|
246
|
+
- \`chati.dev/config.yaml\` (version info)
|
|
247
|
+
`;
|
|
248
|
+
}
|
|
249
|
+
|
|
84
250
|
/**
|
|
85
251
|
* Generate CLAUDE.local.md content (runtime state — auto-gitignored, never committed)
|
|
86
252
|
*/
|
|
@@ -63,7 +63,7 @@ export async function validateInstallation(targetDir) {
|
|
|
63
63
|
if (existsSync(constitutionPath)) {
|
|
64
64
|
const content = readFileSync(constitutionPath, 'utf-8');
|
|
65
65
|
const articleCount = (content.match(/^## Article/gm) || []).length;
|
|
66
|
-
results.constitution.pass = articleCount >=
|
|
66
|
+
results.constitution.pass = articleCount >= 19;
|
|
67
67
|
results.constitution.details.push({ articleCount });
|
|
68
68
|
}
|
|
69
69
|
results.total += 1;
|
|
@@ -94,6 +94,7 @@ export async function validateInstallation(targetDir) {
|
|
|
94
94
|
const workflowFiles = [
|
|
95
95
|
'greenfield-fullstack.yaml', 'brownfield-fullstack.yaml',
|
|
96
96
|
'brownfield-discovery.yaml', 'brownfield-service.yaml', 'brownfield-ui.yaml',
|
|
97
|
+
'quick-flow.yaml',
|
|
97
98
|
];
|
|
98
99
|
let workflowCount = 0;
|
|
99
100
|
for (const file of workflowFiles) {
|
|
@@ -101,7 +102,7 @@ export async function validateInstallation(targetDir) {
|
|
|
101
102
|
workflowCount++;
|
|
102
103
|
}
|
|
103
104
|
}
|
|
104
|
-
results.workflows.pass = workflowCount ===
|
|
105
|
+
results.workflows.pass = workflowCount === 6;
|
|
105
106
|
results.total += 1;
|
|
106
107
|
if (results.workflows.pass) results.passed += 1;
|
|
107
108
|
|
|
@@ -109,6 +110,7 @@ export async function validateInstallation(targetDir) {
|
|
|
109
110
|
const templateFiles = [
|
|
110
111
|
'prd-tmpl.yaml', 'brownfield-prd-tmpl.yaml',
|
|
111
112
|
'fullstack-architecture-tmpl.yaml', 'task-tmpl.yaml', 'qa-gate-tmpl.yaml',
|
|
113
|
+
'quick-brief-tmpl.yaml',
|
|
112
114
|
];
|
|
113
115
|
let templateCount = 0;
|
|
114
116
|
for (const file of templateFiles) {
|
|
@@ -116,7 +118,7 @@ export async function validateInstallation(targetDir) {
|
|
|
116
118
|
templateCount++;
|
|
117
119
|
}
|
|
118
120
|
}
|
|
119
|
-
results.templates.pass = templateCount ===
|
|
121
|
+
results.templates.pass = templateCount === 6;
|
|
120
122
|
results.total += 1;
|
|
121
123
|
if (results.templates.pass) results.passed += 1;
|
|
122
124
|
|
|
@@ -131,8 +131,8 @@ export function runHealthCheck(targetDir) {
|
|
|
131
131
|
if (existsSync(constitutionPath)) {
|
|
132
132
|
const content = readFileSync(constitutionPath, 'utf-8');
|
|
133
133
|
const articleCount = (content.match(/^## Article/gm) || []).length;
|
|
134
|
-
checks.constitution.pass = articleCount >=
|
|
135
|
-
checks.constitution.details = `${articleCount}/
|
|
134
|
+
checks.constitution.pass = articleCount >= 19;
|
|
135
|
+
checks.constitution.details = `${articleCount}/19 articles`;
|
|
136
136
|
} else {
|
|
137
137
|
checks.constitution.details = 'Not found';
|
|
138
138
|
}
|
package/src/preview/detector.js
CHANGED
|
@@ -191,7 +191,7 @@ export function detectProjectKind(projectDir) {
|
|
|
191
191
|
* @returns {{ command: string, args: string[], description: string, framework: string, defaultPort: number }}
|
|
192
192
|
*/
|
|
193
193
|
function resolveFrameworkCommand(projectDir, detector) {
|
|
194
|
-
const { framework, defaultPort
|
|
194
|
+
const { framework, defaultPort } = detector;
|
|
195
195
|
|
|
196
196
|
// Django has its own command
|
|
197
197
|
if (framework === 'django') {
|
|
@@ -18,26 +18,16 @@
|
|
|
18
18
|
* @returns {{ command: string, args: string[], stdinPrompt: string|null }}
|
|
19
19
|
*/
|
|
20
20
|
export function buildCommand(config, provider) {
|
|
21
|
-
const args = [
|
|
21
|
+
const args = [...provider.baseArgs];
|
|
22
22
|
|
|
23
23
|
if (config.model) {
|
|
24
24
|
const resolvedModel = provider.modelMap[config.model] || config.model;
|
|
25
|
-
args.push(
|
|
25
|
+
args.push(provider.modelFlag, resolvedModel);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
return {
|
|
29
|
-
command:
|
|
29
|
+
command: provider.command,
|
|
30
30
|
args,
|
|
31
31
|
stdinPrompt: config.prompt || null,
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Build environment variables specific to Claude Code.
|
|
37
|
-
*
|
|
38
|
-
* @param {SpawnConfig} config
|
|
39
|
-
* @returns {Record<string, string>}
|
|
40
|
-
*/
|
|
41
|
-
export function buildEnv(config) {
|
|
42
|
-
return {};
|
|
43
|
-
}
|
|
@@ -13,29 +13,19 @@
|
|
|
13
13
|
* @returns {{ command: string, args: string[], stdinPrompt: string|null }}
|
|
14
14
|
*/
|
|
15
15
|
export function buildCommand(config, provider) {
|
|
16
|
-
const args = [
|
|
16
|
+
const args = [...provider.baseArgs];
|
|
17
17
|
|
|
18
18
|
if (config.model) {
|
|
19
19
|
const resolvedModel = provider.modelMap[config.model] || config.model;
|
|
20
|
-
args.push(
|
|
20
|
+
args.push(provider.modelFlag, resolvedModel);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
// Codex exec reads prompt from stdin when `-` is passed
|
|
24
24
|
args.push('-');
|
|
25
25
|
|
|
26
26
|
return {
|
|
27
|
-
command:
|
|
27
|
+
command: provider.command,
|
|
28
28
|
args,
|
|
29
29
|
stdinPrompt: config.prompt || null,
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Build environment variables specific to Codex CLI.
|
|
35
|
-
*
|
|
36
|
-
* @param {import('../spawner.js').SpawnConfig} config
|
|
37
|
-
* @returns {Record<string, string>}
|
|
38
|
-
*/
|
|
39
|
-
export function buildEnv(config) {
|
|
40
|
-
return {};
|
|
41
|
-
}
|
|
@@ -13,26 +13,16 @@
|
|
|
13
13
|
* @returns {{ command: string, args: string[], stdinPrompt: string|null }}
|
|
14
14
|
*/
|
|
15
15
|
export function buildCommand(config, provider) {
|
|
16
|
-
const args = [
|
|
16
|
+
const args = [...provider.baseArgs];
|
|
17
17
|
|
|
18
18
|
if (config.model) {
|
|
19
19
|
const resolvedModel = provider.modelMap[config.model] || config.model;
|
|
20
|
-
args.push(
|
|
20
|
+
args.push(provider.modelFlag, resolvedModel);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
return {
|
|
24
|
-
command:
|
|
24
|
+
command: provider.command,
|
|
25
25
|
args,
|
|
26
26
|
stdinPrompt: config.prompt || null,
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Build environment variables specific to Copilot CLI.
|
|
32
|
-
*
|
|
33
|
-
* @param {import('../spawner.js').SpawnConfig} config
|
|
34
|
-
* @returns {Record<string, string>}
|
|
35
|
-
*/
|
|
36
|
-
export function buildEnv(config) {
|
|
37
|
-
return {};
|
|
38
|
-
}
|
|
@@ -13,30 +13,16 @@
|
|
|
13
13
|
* @returns {{ command: string, args: string[], stdinPrompt: string|null }}
|
|
14
14
|
*/
|
|
15
15
|
export function buildCommand(config, provider) {
|
|
16
|
-
const args = [];
|
|
16
|
+
const args = [...provider.baseArgs];
|
|
17
17
|
|
|
18
18
|
if (config.model) {
|
|
19
19
|
const resolvedModel = provider.modelMap[config.model] || config.model;
|
|
20
|
-
args.push(
|
|
20
|
+
args.push(provider.modelFlag, resolvedModel);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
// Gemini CLI uses --prompt for non-interactive mode
|
|
24
|
-
// When stdin is piped, Gemini reads from stdin automatically
|
|
25
|
-
args.push('--prompt');
|
|
26
|
-
|
|
27
23
|
return {
|
|
28
|
-
command:
|
|
24
|
+
command: provider.command,
|
|
29
25
|
args,
|
|
30
26
|
stdinPrompt: config.prompt || null,
|
|
31
27
|
};
|
|
32
28
|
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Build environment variables specific to Gemini CLI.
|
|
36
|
-
*
|
|
37
|
-
* @param {import('../spawner.js').SpawnConfig} config
|
|
38
|
-
* @returns {Record<string, string>}
|
|
39
|
-
*/
|
|
40
|
-
export function buildEnv(config) {
|
|
41
|
-
return {};
|
|
42
|
-
}
|