chati-dev 3.0.1 → 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 +7 -6
- package/assets/logo2.png +0 -0
- package/assets/social-preview.png +0 -0
- package/framework/context/governance.md +1 -1
- package/framework/intelligence/context-engine.md +2 -2
- package/package.json +1 -1
- package/src/config/context-file-generator.js +12 -9
- package/src/config/ide-configs.js +9 -0
- package/src/dashboard/layout.js +3 -1
- package/src/installer/core.js +26 -29
- package/src/installer/templates.js +38 -1
- package/src/terminal/index.js +1 -0
- package/src/terminal/prompt-builder.js +2 -3
- package/src/terminal/spawner.js +43 -1
- package/src/wizard/index.js +23 -5
- package/src/wizard/questions.js +5 -2
- package/assets/logo - c/303/263pia.svg" +0 -42
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
|
|
package/assets/logo2.png
ADDED
|
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
|
@@ -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,
|
|
10
|
+
* - Codex CLI: auto-loads AGENTS.md, uses .codex/commands/*.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
|
-
//
|
|
152
|
-
|
|
153
|
-
if (!
|
|
154
|
-
|
|
155
|
-
|
|
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: '.codex/commands/',
|
|
47
|
+
rulesFile: 'AGENTS.md',
|
|
48
|
+
mcpConfigFile: null,
|
|
49
|
+
formatNotes: 'Markdown command format',
|
|
50
|
+
},
|
|
42
51
|
'gemini-cli': {
|
|
43
52
|
name: 'Gemini CLI',
|
|
44
53
|
description: 'Google AI terminal agent',
|
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('│'),
|
package/src/installer/core.js
CHANGED
|
@@ -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, generateCodexRouter, 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
|
-
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
-
//
|
|
130
|
-
|
|
131
|
-
|
|
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,9 @@ 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 slash command via .codex/commands/
|
|
306
|
+
writeFileSync(join(targetDir, '.codex', 'commands', 'chati.md'), generateCodexRouter(), 'utf-8');
|
|
310
307
|
} else if (ideKey === 'gemini-cli') {
|
|
311
308
|
// Gemini CLI: TOML command file (native format for /chati command)
|
|
312
309
|
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,43 @@ Type \`/chati\` to start.
|
|
|
146
146
|
`;
|
|
147
147
|
}
|
|
148
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
|
+
|
|
149
186
|
/**
|
|
150
187
|
* Generate Gemini CLI TOML command (.gemini/commands/chati.toml)
|
|
151
188
|
*
|
package/src/terminal/index.js
CHANGED
|
@@ -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
|
|
17
|
+
// Import AGENT_MODELS from model-governance (safe — named export,
|
|
18
18
|
// does not trigger main() which is guarded by fileURLToPath check).
|
|
19
|
-
import {
|
|
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).
|
package/src/terminal/spawner.js
CHANGED
|
@@ -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
|
|
package/src/wizard/index.js
CHANGED
|
@@ -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
|
-
//
|
|
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
|
-
|
|
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,13 @@ 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 invokeCmd = primaryIDE === 'github-copilot' ? '@chati' : '/chati';
|
|
106
124
|
showQuickStart(t('installer.quick_start_title'), [
|
|
107
|
-
`${t('installer.quick_start_1')} (
|
|
108
|
-
|
|
125
|
+
`${t('installer.quick_start_1')} (${primaryIDEName})`,
|
|
126
|
+
`Type: ${invokeCmd}`,
|
|
109
127
|
t('installer.quick_start_3'),
|
|
110
128
|
]);
|
|
111
129
|
|
package/src/wizard/questions.js
CHANGED
|
@@ -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 =
|
|
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>
|