chati-dev 3.0.1 → 3.0.3

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 CHANGED
@@ -10,8 +10,9 @@
10
10
  <a href="https://www.npmjs.com/package/chati-dev"><img src="https://img.shields.io/npm/v/chati-dev?color=blue&label=npm" alt="npm"></a>
11
11
  <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT"></a>
12
12
  <a href="https://nodejs.org/"><img src="https://img.shields.io/badge/node-%3E%3D20.0.0-brightgreen.svg" alt="Node.js"></a>
13
- <a href="#multi-cli-support"><img src="https://img.shields.io/badge/LLM-Claude%20%7C%20Gemini%20%7C%20Codex%20%7C%20Copilot-blueviolet.svg" alt="Multi-LLM"></a>
13
+ <a href="#multi-cli-support"><img src="https://img.shields.io/badge/LLM-Claude%20%7C%20Gemini%20%7C%20Codex%20%7C%20GitHub%20Copilot-blueviolet.svg" alt="Multi-LLM"></a>
14
14
  <a href="#internationalization"><img src="https://img.shields.io/badge/i18n-EN%20%7C%20PT%20%7C%20ES%20%7C%20FR-informational.svg" alt="i18n"></a>
15
+ <a href="https://github.com/Chati-dev/Chati.dev/actions/workflows/ci.yml"><img src="https://github.com/Chati-dev/Chati.dev/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
15
16
  <a href=".github/CONTRIBUTING.md"><img src="https://img.shields.io/badge/contributions-welcome-brightgreen.svg" alt="Contributions Welcome"></a>
16
17
  </p>
17
18
 
@@ -73,7 +74,7 @@ The wizard guides you through 4 steps:
73
74
  |------|-------------|
74
75
  | **Language** | English, Portuguese, Spanish, or French |
75
76
  | **Project Type** | Greenfield (new) or Brownfield (existing) |
76
- | **AI Provider** | Claude, Gemini, Codex, or Copilot — auto-configures optimal models per agent |
77
+ | **AI Provider** | Claude, Gemini, Codex, or GitHub Copilot — auto-configures optimal models per agent |
77
78
  | **Confirm** | Review summary and proceed |
78
79
 
79
80
  ### 2. Activate the orchestrator
@@ -120,7 +121,7 @@ npx chati-dev status --watch # Auto-refresh every 5s
120
121
  | Feature | What it means |
121
122
  |---------|--------------|
122
123
  | **13 Specialized Agents** | Each agent has a defined mission, success criteria, and handoff protocol — not one AI trying to do everything |
123
- | **Multi-CLI Architecture** | Choose your AI provider at install time: Claude, Gemini, Codex, or Copilot. Each agent gets the optimal model for that provider |
124
+ | **Multi-CLI Architecture** | Choose your AI provider at install time: Claude, Gemini, Codex, or GitHub Copilot. Each agent gets the optimal model for that provider |
124
125
  | **Quality Gates** | Every phase is validated before moving forward. 3-tier verdicts: APPROVED, NEEDS_REVISION, or BLOCKED |
125
126
  | **Context Persistence** | Sessions survive restarts. Close your IDE, come back next week — the system remembers everything |
126
127
  | **Session Lock** | Once activated, you stay inside the system. No accidentally "falling out" into generic AI mode |
@@ -144,7 +145,7 @@ Chati.dev is provider-agnostic. You choose your AI provider during installation,
144
145
  | **Claude** | `claude` | Opus | Sonnet / Haiku | Default |
145
146
  | **Gemini** | `gemini` | Pro | Flash | Full support |
146
147
  | **Codex** | `codex` | Codex | Codex Mini | Full support |
147
- | **Copilot** | `copilot` | Sonnet 4.5 | GPT-5 | Full support |
148
+ | **GitHub Copilot** | `copilot` | Sonnet 4.5 | GPT-5 | Full support |
148
149
 
149
150
  ### How Model Assignment Works
150
151
 
@@ -159,7 +160,7 @@ When you select a provider, the system maps each agent to the best available mod
159
160
  Claude: architect → opus, brief → sonnet, greenfield-wu → haiku
160
161
  Gemini: architect → pro, brief → flash, greenfield-wu → flash
161
162
  Codex: architect → codex, brief → codex-mini
162
- Copilot: architect → claude-sonnet, brief → claude-sonnet
163
+ GitHub Copilot: architect → claude-sonnet, brief → claude-sonnet
163
164
  ```
164
165
 
165
166
  ### CLI Invocation Syntax
@@ -171,7 +172,7 @@ Each provider uses its own CLI syntax. Chati.dev handles this transparently:
171
172
  | Claude | `claude --print --model <id>` | `claude --print --model claude-opus-4-6` |
172
173
  | Gemini | `gemini --model <id>` | `gemini --model gemini-2.5-pro` |
173
174
  | Codex | `codex exec -m <id>` | `codex exec -m gpt-5.3-codex` |
174
- | Copilot | `copilot -p --model <id>` | `copilot -p --model claude-sonnet-4.5` |
175
+ | GitHub Copilot | `copilot -p --model <id>` | `copilot -p --model claude-sonnet-4.5` |
175
176
 
176
177
  Prompts are piped via stdin for all providers. You can override individual agent models in `chati.dev/config.yaml` under `agent_overrides`.
177
178
 
Binary file
Binary file
@@ -44,7 +44,7 @@ Extracted from `chati.dev/constitution.md` (19 Articles). Read the full constitu
44
44
  - Circuit breaker: CLOSED -> OPEN (3 failures) -> HALF_OPEN (probe)
45
45
 
46
46
  ## Multi-CLI Governance (Article XIX)
47
- - 4 providers: Claude, Gemini, Codex, Copilot
47
+ - 4 providers: Claude, Gemini, Codex, GitHub Copilot
48
48
  - Provider selected at install time, auto-configures optimal models per agent
49
49
  - Resolution chain: agent_overrides > agent default > primary provider
50
50
  - Context files auto-generated for non-Claude providers (GEMINI.md, AGENTS.md)
@@ -168,7 +168,7 @@ If Smart Continuation is insufficient, the orchestrator spawns a new session:
168
168
 
169
169
  When agents execute on different CLI providers, context injection adapts to the provider's capabilities:
170
170
 
171
- ### Hook-Based Providers (Claude Code, Gemini CLI, Copilot CLI)
171
+ ### Hook-Based Providers (Claude Code, Gemini CLI, GitHub Copilot CLI)
172
172
  - PRISM context injected via `UserPromptSubmit` hook
173
173
  - Mode governance enforced via `PreToolUse` hook
174
174
  - Constitution guard enforced via `PreToolUse` hook
@@ -186,7 +186,7 @@ When agents execute on different CLI providers, context injection adapts to the
186
186
  | Claude Code | CLAUDE.md | Native (already exists) |
187
187
  | Gemini CLI | GEMINI.md | Auto-generated from CLAUDE.md |
188
188
  | Codex CLI | AGENTS.md | Auto-generated from CLAUDE.md |
189
- | Copilot CLI | All three | Reads CLAUDE.md, GEMINI.md, AGENTS.md natively |
189
+ | GitHub Copilot CLI | All three | Reads CLAUDE.md, GEMINI.md, AGENTS.md natively |
190
190
 
191
191
  ### Cross-Provider Handoff
192
192
  Handoff format is identical regardless of which provider executed the agent. The two-layer structure (Article VIII) ensures any provider can read any handoff. Session state in `.chati/session.yaml` is the single source of truth — all providers read from and write to the same session file.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chati-dev",
3
- "version": "3.0.1",
3
+ "version": "3.0.3",
4
4
  "description": "AI-Powered Multi-Agent Orchestration System — Structured vibe coding for Full Stack Development",
5
5
  "type": "module",
6
6
  "bin": {
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * Provider conventions (verified Feb 2026):
9
9
  * - Gemini CLI: auto-loads GEMINI.md, uses .gemini/commands/*.toml, no rules/
10
- * - Codex CLI: auto-loads AGENTS.md, no commands/ or rules/ concept
10
+ * - Codex CLI: auto-loads AGENTS.md, uses .agents/skills/chati/SKILL.md for $chati
11
11
  * - Copilot CLI: auto-loads AGENTS.md + CLAUDE.md + GEMINI.md natively (no COPILOT.md needed)
12
12
  */
13
13
 
@@ -143,20 +143,23 @@ export function generateAgentsMd(content) {
143
143
  * AGENTS.md, CLAUDE.md, and GEMINI.md.
144
144
  *
145
145
  * @param {string} projectDir - Project root directory
146
+ * @param {string} [baseContent] - Optional base content (used when CLAUDE.md doesn't exist on disk)
146
147
  * @returns {{ generated: string[], skipped: string[], warning: string|null }}
147
148
  */
148
- export function generateContextFiles(projectDir) {
149
+ export function generateContextFiles(projectDir, baseContent = null) {
149
150
  const result = { generated: [], skipped: [], warning: null };
150
151
 
151
- // Read CLAUDE.md
152
- const claudeMdPath = join(projectDir, 'CLAUDE.md');
153
- if (!existsSync(claudeMdPath)) {
154
- result.warning = 'CLAUDE.md not found — skipping context file generation';
155
- return result;
152
+ // Use provided base content or read CLAUDE.md from disk
153
+ let claudeContent = baseContent;
154
+ if (!claudeContent) {
155
+ const claudeMdPath = join(projectDir, 'CLAUDE.md');
156
+ if (!existsSync(claudeMdPath)) {
157
+ result.warning = 'CLAUDE.md not found and no base content provided — skipping context file generation';
158
+ return result;
159
+ }
160
+ claudeContent = readFileSync(claudeMdPath, 'utf-8');
156
161
  }
157
162
 
158
- const claudeContent = readFileSync(claudeMdPath, 'utf-8');
159
-
160
163
  // Determine enabled providers from config.yaml
161
164
  const enabledProviders = resolveEnabledProviders(projectDir);
162
165
 
@@ -39,6 +39,15 @@ export const IDE_CONFIGS = {
39
39
  mcpConfigFile: null,
40
40
  formatNotes: 'Cursor rules format',
41
41
  },
42
+ 'codex-cli': {
43
+ name: 'Codex CLI',
44
+ description: 'OpenAI Codex terminal agent',
45
+ recommended: false,
46
+ configPath: '.agents/skills/chati/',
47
+ rulesFile: 'AGENTS.md',
48
+ mcpConfigFile: null,
49
+ formatNotes: 'Codex skill format (SKILL.md with YAML frontmatter)',
50
+ },
42
51
  'gemini-cli': {
43
52
  name: 'Gemini CLI',
44
53
  description: 'Google AI terminal agent',
@@ -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
- const ide = (session.ides || [])[0] || 'unknown';
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('│'),
@@ -3,7 +3,7 @@ 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, generateGeminiRouter, generateCopilotAgent } from './templates.js';
6
+ import { generateSessionYaml, generateConfigYaml, generateClaudeMd, generateClaudeLocalMd, generateCodexSkill, generateGeminiRouter, generateCopilotAgent } from './templates.js';
7
7
  import { generateContextFiles } from '../config/context-file-generator.js';
8
8
  import { verifyManifest } from './manifest.js';
9
9
 
@@ -101,37 +101,31 @@ export async function installFramework(config) {
101
101
  await configureIDE(targetDir, ideKey, selectedMCPs);
102
102
  }
103
103
 
104
- // 4. Copy context files to .claude/rules/chati/ (auto-loaded by Claude Code)
105
- const contextFiles = ['root.md', 'governance.md', 'protocols.md', 'quality.md'];
106
- const claudeRulesDir = join(targetDir, '.claude', 'rules', 'chati');
107
- createDir(claudeRulesDir);
108
- for (const file of contextFiles) {
109
- const src = join(FRAMEWORK_SOURCE, 'context', file);
110
- if (existsSync(src)) {
111
- copyFileSync(src, join(claudeRulesDir, file));
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
+ }
112
120
  }
113
- }
114
-
115
- // 5. Create CLAUDE.md (minimal — framework rules auto-loaded from .claude/rules/chati/)
116
- writeFileSync(
117
- join(targetDir, 'CLAUDE.md'),
118
- generateClaudeMd({ projectName, projectType, language }),
119
- 'utf-8'
120
- );
121
121
 
122
- // 6. Create CLAUDE.local.md (runtime state — session lock, current agent)
123
- writeFileSync(
124
- join(targetDir, 'CLAUDE.local.md'),
125
- generateClaudeLocalMd(),
126
- 'utf-8'
127
- );
122
+ writeFileSync(join(targetDir, 'CLAUDE.md'), baseContent, 'utf-8');
123
+ writeFileSync(join(targetDir, 'CLAUDE.local.md'), generateClaudeLocalMd(), 'utf-8');
124
+ }
128
125
 
129
- // 7. Generate context files for non-Claude providers (GEMINI.md, AGENTS.md)
130
- // Copilot CLI natively reads AGENTS.md + CLAUDE.md + GEMINI.md — no separate COPILOT.md needed.
131
- const hasNonClaudeProvider = (llmProvider && llmProvider !== 'claude') ||
132
- selectedIDEs.some(ide => ['gemini-cli', 'github-copilot'].includes(ide));
133
- if (hasNonClaudeProvider) {
134
- generateContextFiles(targetDir);
126
+ // 6. Non-Claude providers: generate context files (GEMINI.md, AGENTS.md) from base content
127
+ if (hasNonClaude) {
128
+ generateContextFiles(targetDir, baseContent);
135
129
  }
136
130
  }
137
131
 
@@ -307,6 +301,10 @@ Pass through all context: session state, handoffs, artifacts, and user input.
307
301
  'utf-8'
308
302
  );
309
303
  }
304
+ } else if (ideKey === 'codex-cli') {
305
+ // Codex CLI: chati skill via .agents/skills/chati/SKILL.md (invoke with $chati)
306
+ createDir(join(targetDir, '.agents', 'skills', 'chati'));
307
+ writeFileSync(join(targetDir, '.agents', 'skills', 'chati', 'SKILL.md'), generateCodexSkill(), 'utf-8');
310
308
  } else if (ideKey === 'gemini-cli') {
311
309
  // Gemini CLI: TOML command file (native format for /chati command)
312
310
  writeFileSync(join(targetDir, '.gemini', 'commands', 'chati.toml'), generateGeminiRouter(), 'utf-8');
@@ -109,7 +109,7 @@ export function generateConfigYaml(config) {
109
109
  providers: {
110
110
  claude: { enabled: true, primary: provider === 'claude' },
111
111
  gemini: { enabled: provider === 'gemini' || selectedIDEs.includes('gemini-cli'), model_default: 'pro', primary: provider === 'gemini' },
112
- codex: { enabled: provider === 'codex', model_default: 'codex', primary: provider === 'codex' },
112
+ codex: { enabled: provider === 'codex' || selectedIDEs.includes('codex-cli'), model_default: 'codex', primary: provider === 'codex' },
113
113
  copilot: { enabled: provider === 'copilot' || selectedIDEs.includes('github-copilot'), primary: provider === 'copilot' },
114
114
  },
115
115
  };
@@ -146,6 +146,56 @@ Type \`/chati\` to start.
146
146
  `;
147
147
  }
148
148
 
149
+ /**
150
+ * Generate Codex CLI skill (.agents/skills/chati/SKILL.md)
151
+ *
152
+ * Codex CLI uses the Skills system for extensibility.
153
+ * Skills live in .agents/skills/<name>/SKILL.md with YAML frontmatter.
154
+ * The user invokes with $chati or Codex auto-detects based on description.
155
+ * Also reads AGENTS.md for project context (auto-generated by context-file-generator).
156
+ */
157
+ export function generateCodexSkill() {
158
+ return `---
159
+ name: chati
160
+ description: >
161
+ Use this skill when the user wants to start or continue a Chati.dev session.
162
+ This activates the orchestrator which routes to the correct agent in the pipeline.
163
+ Invoke when the user mentions chati, /chati, wants to plan, build, or deploy a project.
164
+ Do NOT use for general coding questions unrelated to the Chati.dev pipeline.
165
+ ---
166
+
167
+ # Chati.dev Orchestrator
168
+
169
+ ## CRITICAL — Language Override
170
+
171
+ Read \`.chati/session.yaml\` field \`language\` BEFORE anything else.
172
+ ALL responses MUST be in this language. This overrides any global setting.
173
+
174
+ | Value | Language |
175
+ |-------|----------|
176
+ | \`en\` | English |
177
+ | \`pt\` | Portugues |
178
+ | \`es\` | Espanol |
179
+ | \`fr\` | Francais |
180
+
181
+ If session.yaml does not exist or has no language field, default to English.
182
+
183
+ ## Load
184
+
185
+ Read and execute the full orchestrator at \`chati.dev/orchestrator/chati.md\`.
186
+
187
+ Pass through all context: session state, handoffs, artifacts, and user input.
188
+
189
+ **Context to pass:**
190
+ - \`.chati/session.yaml\` (session state — includes language)
191
+ - \`AGENTS.md\` (project context — auto-generated)
192
+ - \`chati.dev/artifacts/handoffs/\` (latest handoff)
193
+ - \`chati.dev/config.yaml\` (version info)
194
+
195
+ **User input:** $ARGUMENTS
196
+ `;
197
+ }
198
+
149
199
  /**
150
200
  * Generate Gemini CLI TOML command (.gemini/commands/chati.toml)
151
201
  *
@@ -8,6 +8,7 @@ export {
8
8
  spawnParallelGroup,
9
9
  killTerminal,
10
10
  getTerminalStatus,
11
+ cleanParentEnv,
11
12
  _resetCounter,
12
13
  } from './spawner.js';
13
14
 
@@ -14,10 +14,9 @@ import { runPrism } from '../context/engine.js';
14
14
  import { loadHandoff, formatHandoff } from '../tasks/handoff.js';
15
15
  import { getWriteScope } from './isolation.js';
16
16
 
17
- // Import DEFAULT_AGENT_MODELS from model-governance (safe — named export,
17
+ // Import AGENT_MODELS from model-governance (safe — named export,
18
18
  // does not trigger main() which is guarded by fileURLToPath check).
19
- import { DEFAULT_AGENT_MODELS } from '../../framework/hooks/model-governance.js';
20
- const AGENT_MODELS = DEFAULT_AGENT_MODELS;
19
+ import { AGENT_MODELS } from '../../framework/hooks/model-governance.js';
21
20
 
22
21
  /**
23
22
  * Map of agent names to their definition file paths (relative to project root).
@@ -35,6 +35,48 @@ export function _resetCounter() {
35
35
  _counter = 0;
36
36
  }
37
37
 
38
+ // ---------------------------------------------------------------------------
39
+ // Environment cleaning
40
+ // ---------------------------------------------------------------------------
41
+
42
+ /**
43
+ * Environment variable prefixes injected by Claude Code that must NOT
44
+ * leak into spawned CLI processes. A spawned `claude --print` that
45
+ * inherits `CLAUDECODE=1` will refuse to start ("cannot be launched
46
+ * inside another Claude Code session").
47
+ *
48
+ * @type {string[]}
49
+ */
50
+ const BLOCKED_ENV_PREFIXES = ['CLAUDE_CODE_', 'CLAUDE_AGENT_SDK_'];
51
+
52
+ /**
53
+ * Exact environment variable names to strip (no prefix match needed).
54
+ * @type {string[]}
55
+ */
56
+ const BLOCKED_ENV_EXACT = ['CLAUDECODE'];
57
+
58
+ /**
59
+ * Return a copy of the given environment with Claude Code-specific
60
+ * variables removed. This prevents "nested session" errors when
61
+ * spawning `claude --print` from inside a Claude Code session.
62
+ *
63
+ * The function is intentionally conservative — it only removes vars
64
+ * that are known to be injected by the Claude Code host process.
65
+ * User-configured vars like CLAUDE_API_KEY are preserved.
66
+ *
67
+ * @param {Record<string, string>} env - Source environment (typically process.env)
68
+ * @returns {Record<string, string>} Cleaned environment (new object)
69
+ */
70
+ export function cleanParentEnv(env) {
71
+ const cleaned = {};
72
+ for (const [key, value] of Object.entries(env)) {
73
+ if (BLOCKED_ENV_EXACT.includes(key)) continue;
74
+ if (BLOCKED_ENV_PREFIXES.some(prefix => key.startsWith(prefix))) continue;
75
+ cleaned[key] = value;
76
+ }
77
+ return cleaned;
78
+ }
79
+
38
80
  // ---------------------------------------------------------------------------
39
81
  // Public API
40
82
  // ---------------------------------------------------------------------------
@@ -145,7 +187,7 @@ export function spawnTerminal(config) {
145
187
 
146
188
  const child = spawn(command, args, {
147
189
  cwd,
148
- env: { ...process.env, ...env },
190
+ env: { ...cleanParentEnv(process.env), ...env },
149
191
  stdio: ['pipe', 'pipe', 'pipe'],
150
192
  });
151
193
 
@@ -9,6 +9,18 @@ import { installFramework } from '../installer/core.js';
9
9
  import { validateInstallation } from '../installer/validator.js';
10
10
  import { t } from './i18n.js';
11
11
  import { DEFAULT_MCPS } from '../config/mcp-configs.js';
12
+ import { IDE_CONFIGS } from '../config/ide-configs.js';
13
+
14
+ /**
15
+ * Map LLM provider to its primary IDE.
16
+ * Each provider maps to its own standalone IDE — no cross-contamination.
17
+ */
18
+ const PROVIDER_TO_IDE = {
19
+ claude: ['claude-code'],
20
+ gemini: ['gemini-cli'],
21
+ codex: ['codex-cli'],
22
+ copilot: ['github-copilot'],
23
+ };
12
24
 
13
25
  const __dirname = dirname(fileURLToPath(import.meta.url));
14
26
  const VERSION = JSON.parse(readFileSync(join(__dirname, '..', '..', 'package.json'), 'utf-8')).version;
@@ -38,8 +50,8 @@ export async function runWizard(targetDir, options = {}) {
38
50
  // Step 3: LLM Provider
39
51
  const llmProvider = options.llmProvider || await stepLlmProvider();
40
52
 
41
- // Auto-configured: Claude Code + default MCPs
42
- const selectedIDEs = options.ides || ['claude-code'];
53
+ // Map provider to its standalone IDE(s)
54
+ const selectedIDEs = options.ides || PROVIDER_TO_IDE[llmProvider] || ['claude-code'];
43
55
  const selectedMCPs = options.mcps || DEFAULT_MCPS;
44
56
 
45
57
  // Step 4: Confirmation
@@ -71,7 +83,9 @@ export async function runWizard(targetDir, options = {}) {
71
83
  showStep(t('installer.created_commands'));
72
84
  showStep(t('installer.installed_constitution'));
73
85
  showStep(t('installer.created_session'));
74
- showStep(t('installer.created_claude_md'));
86
+ if (selectedIDEs.includes('claude-code')) {
87
+ showStep(t('installer.created_claude_md'));
88
+ }
75
89
  showStep(t('installer.created_memories'));
76
90
  showStep(t('installer.installed_intelligence'));
77
91
  showStep(`${t('installer.configured_mcps')} ${selectedMCPs.join(', ')}`);
@@ -103,9 +117,17 @@ export async function runWizard(targetDir, options = {}) {
103
117
  console.log();
104
118
  p.outro(t('installer.success'));
105
119
 
120
+ // Show quick start — same experience across all providers
121
+ const primaryIDE = selectedIDEs[selectedIDEs.length - 1];
122
+ const primaryIDEName = IDE_CONFIGS[primaryIDE]?.name || primaryIDE;
123
+ const invokeCmdMap = {
124
+ 'github-copilot': '@chati',
125
+ 'codex-cli': '$chati',
126
+ };
127
+ const invokeCmd = invokeCmdMap[primaryIDE] || '/chati';
106
128
  showQuickStart(t('installer.quick_start_title'), [
107
- `${t('installer.quick_start_1')} (Claude Code)`,
108
- t('installer.quick_start_2'),
129
+ `${t('installer.quick_start_1')} (${primaryIDEName})`,
130
+ `Type: ${invokeCmd}`,
109
131
  t('installer.quick_start_3'),
110
132
  ]);
111
133
 
@@ -4,6 +4,7 @@ import { detectProjectType } from '../utils/detector.js';
4
4
  import { showSummary, showChecklist } from './feedback.js';
5
5
  import { brand, dim, success } from '../utils/colors.js';
6
6
  import { isProviderAvailable } from '../terminal/cli-registry.js';
7
+ import { IDE_CONFIGS } from '../config/ide-configs.js';
7
8
 
8
9
  /**
9
10
  * Step 1: Language Selection (always in English)
@@ -106,12 +107,14 @@ export async function stepLlmProvider() {
106
107
  * Step 4: Confirmation
107
108
  */
108
109
  export async function stepConfirmation(config) {
109
- const { projectName, projectType, language, llmProvider, selectedMCPs } = config;
110
+ const { projectName, projectType, language, llmProvider, selectedMCPs, selectedIDEs } = config;
110
111
 
111
112
  const langName = SUPPORTED_LANGUAGES.find(l => l.value === language)?.label || language;
112
113
  const providerNames = { claude: 'Claude (Anthropic)', gemini: 'Gemini (Google)', codex: 'Codex (OpenAI)', copilot: 'Copilot (GitHub)' };
113
114
  const providerDisplay = providerNames[llmProvider] || llmProvider;
114
- const ideNames = 'Claude Code (auto-configured)';
115
+ const ideNames = (selectedIDEs || ['claude-code'])
116
+ .map(id => IDE_CONFIGS[id]?.name || id)
117
+ .join(', ') + ' (auto-configured)';
115
118
  const mcpNames = selectedMCPs.length > 0
116
119
  ? `${selectedMCPs.join(', ')} (auto-installed)`
117
120
  : 'None';
@@ -1,42 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 620 200">
2
- <defs>
3
- <clipPath id="c">
4
- <path d="M100,8 C155,8 190,40 190,90 C190,140 155,172 100,172 C82,172 66,167 52,159 L22,192 L34,155 C18,140 10,118 10,90 C10,40 45,8 100,8 Z"/>
5
- </clipPath>
6
- <radialGradient id="g" cx="38%" cy="30%" r="68%">
7
- <stop offset="0%" stop-color="#8EC5F5"/>
8
- <stop offset="40%" stop-color="#5DA2E2"/>
9
- <stop offset="75%" stop-color="#4A90D9"/>
10
- <stop offset="100%" stop-color="#2D6BAF"/>
11
- </radialGradient>
12
- <linearGradient id="r" x1="0" y1="0" x2="0" y2="1">
13
- <stop offset="0%" stop-color="rgba(255,255,255,0.5)"/>
14
- <stop offset="30%" stop-color="rgba(255,255,255,0.15)"/>
15
- <stop offset="100%" stop-color="rgba(0,0,0,0)"/>
16
- </linearGradient>
17
- <linearGradient id="bs" x1="0" y1="0" x2="0" y2="1">
18
- <stop offset="0%" stop-color="rgba(0,0,0,0)"/>
19
- <stop offset="65%" stop-color="rgba(0,0,0,0)"/>
20
- <stop offset="100%" stop-color="rgba(15,30,60,0.25)"/>
21
- </linearGradient>
22
- </defs>
23
-
24
- <!-- Chat bubble -->
25
- <path d="M100,8 C155,8 190,40 190,90 C190,140 155,172 100,172 C82,172 66,167 52,159 L22,192 L34,155 C18,140 10,118 10,90 C10,40 45,8 100,8 Z" fill="url(#g)"/>
26
- <ellipse cx="82" cy="38" rx="52" ry="25" fill="rgba(255,255,255,0.18)" clip-path="url(#c)"/>
27
- <path d="M100,8 C155,8 190,40 190,90 C190,140 155,172 100,172 C82,172 66,167 52,159 L22,192 L34,155 C18,140 10,118 10,90 C10,40 45,8 100,8 Z" fill="url(#bs)" clip-path="url(#c)"/>
28
- <path d="M100,8 C155,8 190,40 190,90 C190,140 155,172 100,172 C82,172 66,167 52,159 L22,192 L34,155 C18,140 10,118 10,90 C10,40 45,8 100,8 Z" fill="none" stroke="url(#r)" stroke-width="1.5"/>
29
-
30
- <!-- Eyes -->
31
- <ellipse cx="72" cy="95" rx="18" ry="20" fill="#1a1a2e"/>
32
- <ellipse cx="128" cy="95" rx="18" ry="20" fill="#1a1a2e"/>
33
- <ellipse cx="65" cy="86" rx="7" ry="5" fill="rgba(255,255,255,0.55)"/>
34
- <ellipse cx="121" cy="86" rx="7" ry="5" fill="rgba(255,255,255,0.55)"/>
35
- <ellipse cx="77" cy="100" rx="3.5" ry="2.5" fill="rgba(255,255,255,0.3)"/>
36
- <ellipse cx="133" cy="100" rx="3.5" ry="2.5" fill="rgba(255,255,255,0.3)"/>
37
-
38
- <!-- "Chati.dev" text inline -->
39
- <text x="210" y="122" font-family="ui-monospace,'SF Mono','Menlo','Consolas','Liberation Mono',monospace" font-weight="700" font-size="68" letter-spacing="-1">
40
- <tspan fill="#e6edf3">Chati</tspan><tspan fill="#4A90D9">.</tspan><tspan fill="#e6edf3">dev</tspan>
41
- </text>
42
- </svg>