chati-dev 4.4.1 → 4.5.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 +29 -27
- package/bin/chati.js +235 -1
- package/framework/agents/plan/tasks.md +46 -1
- package/framework/config.yaml +2 -2
- package/framework/constitution.md +13 -16
- package/framework/context/governance.md +5 -5
- package/framework/context/root.md +5 -5
- package/framework/i18n/en.yaml +8 -2
- package/framework/i18n/es.yaml +8 -2
- package/framework/i18n/fr.yaml +8 -2
- package/framework/i18n/pt.yaml +8 -2
- package/framework/manifest.json +21 -21
- package/framework/manifest.sig +1 -1
- package/framework/orchestrator/chati.md +43 -12
- package/node_modules/@chati/browser-capability/README.md +10 -0
- package/node_modules/@chati/browser-capability/package.json +17 -0
- package/node_modules/@chati/browser-capability/src/index.js +165 -0
- package/node_modules/@chati/core/package.json +13 -0
- package/node_modules/@chati/core/src/index.js +111 -0
- package/node_modules/@chati/knowledge-context/package.json +17 -0
- package/node_modules/@chati/knowledge-context/src/index.js +202 -0
- package/node_modules/@chati/planning/package.json +17 -0
- package/node_modules/@chati/planning/src/index.js +367 -0
- package/node_modules/@chati/provider-registry/package.json +16 -0
- package/node_modules/@chati/provider-registry/src/index.js +148 -0
- package/node_modules/@chati/rail/README.md +24 -0
- package/node_modules/@chati/rail/package.json +19 -0
- package/node_modules/@chati/rail/src/index.js +437 -0
- package/node_modules/@chati/release-lane/README.md +24 -0
- package/node_modules/@chati/release-lane/package.json +17 -0
- package/node_modules/@chati/release-lane/src/index.js +172 -0
- package/node_modules/@chati/review-council/package.json +17 -0
- package/node_modules/@chati/review-council/src/index.js +264 -0
- package/node_modules/@chati/tracking-clickup/README.md +55 -0
- package/node_modules/@chati/tracking-clickup/package.json +17 -0
- package/node_modules/@chati/tracking-clickup/src/index.js +293 -0
- package/package.json +25 -3
- package/src/config/ide-configs.js +11 -0
- package/src/context/domain-loader.js +1 -1
- package/src/dashboard/data-reader.js +1 -1
- package/src/executors/runner.js +1 -1
- package/src/installer/core.js +14 -13
- package/src/installer/provider-overlay.js +8 -15
- package/src/installer/scaffold-applier.js +1 -1
- package/src/installer/templates.js +12 -25
- package/src/installer/validator.js +5 -10
- package/src/installer-v2/catalog-client.js +165 -0
- package/src/installer-v2/index.js +304 -0
- package/src/installer-v2/model-catalog-envelope.json +278 -0
- package/src/installer-v2/model-catalog.json +130 -0
- package/src/installer-v2/model-catalog.sig +1 -0
- package/src/installer-v2/wizard-installation.js +116 -0
- package/src/intelligence/registry-manager.js +1 -1
- package/src/license/client.js +27 -1
- package/src/memory/session-digest.js +1 -1
- package/src/merger/yaml-merger.js +1 -1
- package/src/orchestrator/browser-runtime.js +25 -0
- package/src/orchestrator/cli.js +93 -8
- package/src/orchestrator/clickup-projection.js +84 -0
- package/src/orchestrator/clickup-runtime.js +13 -0
- package/src/orchestrator/knowledge-runtime.js +64 -0
- package/src/orchestrator/planning-runtime.js +127 -0
- package/src/orchestrator/rail-runtime.js +421 -0
- package/src/orchestrator/release-runtime.js +14 -0
- package/src/orchestrator/review-runtime.js +74 -0
- package/src/orchestrator/runtime-installation-v2.js +57 -0
- package/src/orchestrator/session-manager.js +1 -1
- package/src/telemetry/config.js +1 -1
- package/src/terminal/adapters/grok-adapter.js +16 -0
- package/src/terminal/adapters/index.js +1 -0
- package/src/terminal/cli-registry.js +20 -5
- package/src/terminal/prompt-builder.js +4 -2
- package/src/terminal/run-agent.js +3 -0
- package/src/terminal/run-parallel.js +21 -10
- package/src/terminal/spawner.js +7 -1
- package/src/terminal/team-task-list.js +1 -1
- package/src/upgrade/checker.js +1 -1
- package/src/upgrade/migrator.js +1 -1
- package/src/utils/config-parser.js +3 -8
- package/src/wizard/i18n.js +10 -4
- package/src/wizard/index.js +49 -17
- package/src/wizard/questions.js +50 -28
|
@@ -75,6 +75,20 @@ const PROVIDERS = {
|
|
|
75
75
|
},
|
|
76
76
|
adapter: adapters.codex,
|
|
77
77
|
},
|
|
78
|
+
grok: {
|
|
79
|
+
name: 'grok',
|
|
80
|
+
command: 'grok',
|
|
81
|
+
baseArgs: [],
|
|
82
|
+
modelFlag: '-m',
|
|
83
|
+
stdinSupport: false,
|
|
84
|
+
hooksSupport: true,
|
|
85
|
+
mcpSupport: true,
|
|
86
|
+
contextFile: 'AGENTS.md',
|
|
87
|
+
modelMap: {
|
|
88
|
+
grok: 'grok-4.6',
|
|
89
|
+
},
|
|
90
|
+
adapter: adapters.grok,
|
|
91
|
+
},
|
|
78
92
|
};
|
|
79
93
|
|
|
80
94
|
// ---------------------------------------------------------------------------
|
|
@@ -117,14 +131,14 @@ export function loadEnabledProviders(projectDir) {
|
|
|
117
131
|
|
|
118
132
|
// Filter out invalid provider names (typos in config.yaml)
|
|
119
133
|
const validEnabled = enabled.filter(name => validNames.includes(name));
|
|
120
|
-
const validPrimary = validNames.includes(primary) ? primary :
|
|
134
|
+
const validPrimary = validNames.includes(primary) ? primary : validEnabled[0] || null;
|
|
121
135
|
|
|
122
136
|
return { primary: validPrimary, enabled: validEnabled };
|
|
123
137
|
}
|
|
124
138
|
|
|
125
139
|
/**
|
|
126
140
|
* Resolve which provider should be used for a given agent.
|
|
127
|
-
* Priority: agent_overrides > agent default >
|
|
141
|
+
* Priority: agent_overrides > agent default > first enabled legacy fallback.
|
|
128
142
|
*
|
|
129
143
|
* @param {string} agent - Agent name
|
|
130
144
|
* @param {string} projectDir - Project root directory
|
|
@@ -152,10 +166,11 @@ export function resolveProviderForAgent(agent, projectDir, agentModels) {
|
|
|
152
166
|
}
|
|
153
167
|
}
|
|
154
168
|
|
|
155
|
-
//
|
|
156
|
-
const
|
|
169
|
+
// Legacy fallback only. Installation v2 routes from the signed task catalog.
|
|
170
|
+
const fallbackProvider = primary || enabled[0];
|
|
171
|
+
const provider = PROVIDERS[fallbackProvider];
|
|
157
172
|
const defaultModel = provider ? Object.keys(provider.modelMap)[0] : 'sonnet';
|
|
158
|
-
return { provider:
|
|
173
|
+
return { provider: fallbackProvider, model: defaultModel };
|
|
159
174
|
}
|
|
160
175
|
|
|
161
176
|
/**
|
|
@@ -135,6 +135,8 @@ export function buildToolMeshSection(agent) {
|
|
|
135
135
|
* @property {string[]} [writeScope] - Override write scope
|
|
136
136
|
* @property {string} [additionalContext] - Extra context (e.g. user answer to needs_input)
|
|
137
137
|
* @property {string} [provider] - Active CLI provider (for overlay resolution)
|
|
138
|
+
* @property {string} [model] - Model selected by the installed provider profile
|
|
139
|
+
* @property {boolean} [strictProvider] - Runtime must not substitute a provider
|
|
138
140
|
*/
|
|
139
141
|
|
|
140
142
|
/**
|
|
@@ -279,14 +281,14 @@ function buildPrismSection(config) {
|
|
|
279
281
|
|
|
280
282
|
/**
|
|
281
283
|
* Load the agent's full .md definition file.
|
|
282
|
-
* For
|
|
284
|
+
* For enabled providers, resolves via the provider-specific overlay directory.
|
|
283
285
|
*/
|
|
284
286
|
function loadAgentDefinition(agent, projectDir, provider = null) {
|
|
285
287
|
const relToFramework = AGENT_FILE_PATHS[agent];
|
|
286
288
|
if (!relToFramework) return null;
|
|
287
289
|
|
|
288
290
|
let fullPath;
|
|
289
|
-
if (provider
|
|
291
|
+
if (provider) {
|
|
290
292
|
fullPath = resolveOverlayPath(projectDir, relToFramework, provider);
|
|
291
293
|
} else {
|
|
292
294
|
fullPath = join(projectDir, resolveFrameworkDir(projectDir), relToFramework);
|
|
@@ -94,6 +94,8 @@ async function main() {
|
|
|
94
94
|
sessionState,
|
|
95
95
|
additionalContext: args['additional-context'] || null,
|
|
96
96
|
provider: args.provider || null,
|
|
97
|
+
model: args.model || null,
|
|
98
|
+
strictProvider: args['strict-provider'] === 'true',
|
|
97
99
|
});
|
|
98
100
|
} catch (err) {
|
|
99
101
|
outputError(`Failed to build prompt: ${err.message}`);
|
|
@@ -127,6 +129,7 @@ async function main() {
|
|
|
127
129
|
prompt: promptResult.prompt,
|
|
128
130
|
workingDir: projectDir,
|
|
129
131
|
timeout,
|
|
132
|
+
strictProvider: args['strict-provider'] === 'true',
|
|
130
133
|
});
|
|
131
134
|
} catch (err) {
|
|
132
135
|
outputError(`Failed to spawn terminal: ${err.message}`);
|
|
@@ -45,6 +45,19 @@ function parseArgs(argv) {
|
|
|
45
45
|
return args;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
function createSpawnConfig({ agent, taskId, promptResult, projectDir, timeout, strictProvider }) {
|
|
49
|
+
return {
|
|
50
|
+
agent,
|
|
51
|
+
taskId,
|
|
52
|
+
model: promptResult.model,
|
|
53
|
+
provider: promptResult.provider,
|
|
54
|
+
prompt: promptResult.prompt,
|
|
55
|
+
workingDir: projectDir,
|
|
56
|
+
timeout,
|
|
57
|
+
strictProvider,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
48
61
|
// ---------------------------------------------------------------------------
|
|
49
62
|
// Main
|
|
50
63
|
// ---------------------------------------------------------------------------
|
|
@@ -103,17 +116,14 @@ async function main() {
|
|
|
103
116
|
previousAgent,
|
|
104
117
|
sessionState,
|
|
105
118
|
provider: args.provider || null,
|
|
119
|
+
model: args.model || null,
|
|
120
|
+
strictProvider: args['strict-provider'] === 'true',
|
|
106
121
|
});
|
|
107
122
|
|
|
108
|
-
configs.push({
|
|
109
|
-
agent: agents[i],
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
provider: promptResult.provider,
|
|
113
|
-
prompt: promptResult.prompt,
|
|
114
|
-
workingDir: projectDir,
|
|
115
|
-
timeout,
|
|
116
|
-
});
|
|
123
|
+
configs.push(createSpawnConfig({
|
|
124
|
+
agent: agents[i], taskId: taskIds[i], promptResult, projectDir, timeout,
|
|
125
|
+
strictProvider: args['strict-provider'] === 'true',
|
|
126
|
+
}));
|
|
117
127
|
} catch (err) {
|
|
118
128
|
outputError(`Failed to build prompt for ${agents[i]}: ${err.message}`);
|
|
119
129
|
process.exit(1);
|
|
@@ -268,6 +278,7 @@ async function sequentialFallback(configs, timeout, _spawnFn = spawnTerminal) {
|
|
|
268
278
|
prompt: cfg.prompt,
|
|
269
279
|
workingDir: cfg.workingDir,
|
|
270
280
|
timeout: cfg.timeout || timeout,
|
|
281
|
+
strictProvider: cfg.strictProvider,
|
|
271
282
|
});
|
|
272
283
|
|
|
273
284
|
// Wait for the REAL process exit before spawning the next agent. The old
|
|
@@ -328,4 +339,4 @@ if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
|
328
339
|
});
|
|
329
340
|
}
|
|
330
341
|
|
|
331
|
-
export { parseArgs, determineNextAgent, sequentialFallback };
|
|
342
|
+
export { parseArgs, createSpawnConfig, determineNextAgent, sequentialFallback };
|
package/src/terminal/spawner.js
CHANGED
|
@@ -107,7 +107,8 @@ export function cleanParentEnv(env) {
|
|
|
107
107
|
* @property {string} agent - Agent name (e.g. "architect")
|
|
108
108
|
* @property {string} taskId - Task identifier
|
|
109
109
|
* @property {string} [model] - LLM model tier name (e.g. opus, pro, codex, claude-sonnet)
|
|
110
|
-
* @property {string} [provider] - CLI provider name (claude, gemini, codex)
|
|
110
|
+
* @property {string} [provider] - CLI provider name (claude, gemini, codex, grok)
|
|
111
|
+
* @property {boolean} [strictProvider] - Reject a missing provider rather than using the legacy fallback
|
|
111
112
|
* @property {string} [prompt] - Full prompt string (from prompt-builder, piped via stdin)
|
|
112
113
|
* @property {object} [contextPayload] - Context to inject via env var
|
|
113
114
|
* @property {string[]} [writeScope] - Override write scope
|
|
@@ -181,6 +182,11 @@ export function buildSpawnCommand(config) {
|
|
|
181
182
|
args = adapterResult.args;
|
|
182
183
|
prompt = adapterResult.stdinPrompt;
|
|
183
184
|
} catch (err) {
|
|
185
|
+
if (config.strictProvider) {
|
|
186
|
+
const failure = new Error(`Selected provider "${providerName}" is unavailable: ${err.message}`);
|
|
187
|
+
failure.code = 'SELECTED_PROVIDER_UNAVAILABLE';
|
|
188
|
+
throw failure;
|
|
189
|
+
}
|
|
184
190
|
// Fallback to claude if provider resolution fails (backwards compatibility)
|
|
185
191
|
providerFallback = {
|
|
186
192
|
requested: providerName,
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync, realpathSync } from 'fs';
|
|
12
12
|
import { join, dirname, resolve, relative } from 'path';
|
|
13
|
-
import yaml from 'js-yaml';
|
|
13
|
+
import * as yaml from 'js-yaml';
|
|
14
14
|
import { withLock } from '../utils/file-lock.js';
|
|
15
15
|
|
|
16
16
|
// ---------------------------------------------------------------------------
|
package/src/upgrade/checker.js
CHANGED
package/src/upgrade/migrator.js
CHANGED
|
@@ -2,7 +2,7 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync, rmSync
|
|
|
2
2
|
import { dirname, join } from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import { resolveFrameworkDir } from '../utils/framework-dir.js';
|
|
5
|
-
import yaml from 'js-yaml';
|
|
5
|
+
import * as yaml from 'js-yaml';
|
|
6
6
|
import semver from 'semver';
|
|
7
7
|
|
|
8
8
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Shared YAML config parser for provider configuration.
|
|
3
3
|
*
|
|
4
|
-
* Extracts
|
|
4
|
+
* Extracts enabled providers and legacy primary status from
|
|
5
5
|
* config.yaml using lightweight regex-based parsing. Used by
|
|
6
6
|
* cli-registry.js, context-file-generator.js, and health/engine.js.
|
|
7
7
|
*/
|
|
@@ -23,9 +23,9 @@ export function parseProviderConfig(projectDir) {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
const raw = readFileSync(configPath, 'utf-8');
|
|
26
|
-
const providers = ['claude', 'gemini', 'codex'];
|
|
26
|
+
const providers = ['claude', 'gemini', 'codex', 'grok'];
|
|
27
27
|
const enabled = [];
|
|
28
|
-
let primary =
|
|
28
|
+
let primary = null;
|
|
29
29
|
|
|
30
30
|
for (const name of providers) {
|
|
31
31
|
const enabledMatch = raw.match(new RegExp(`${name}:[\\s\\S]*?enabled:\\s*(true|false)`, 'm'));
|
|
@@ -38,11 +38,6 @@ export function parseProviderConfig(projectDir) {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
// Claude is always enabled as fallback
|
|
42
|
-
if (!enabled.includes('claude')) {
|
|
43
|
-
enabled.unshift('claude');
|
|
44
|
-
}
|
|
45
|
-
|
|
46
41
|
return { primary, enabled, raw };
|
|
47
42
|
}
|
|
48
43
|
|
package/src/wizard/i18n.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFileSync, existsSync } from 'fs';
|
|
2
2
|
import { join, dirname } from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
|
-
import yaml from 'js-yaml';
|
|
4
|
+
import * as yaml from 'js-yaml';
|
|
5
5
|
import { resolveFrameworkDir } from '../utils/framework-dir.js';
|
|
6
6
|
|
|
7
7
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -30,13 +30,19 @@ const FALLBACK_EN = {
|
|
|
30
30
|
ide_selection_title: 'Select your IDEs / CLIs (multiple allowed):',
|
|
31
31
|
provider_selection_title: 'Which AI providers will you use?',
|
|
32
32
|
editor_selection_title: 'Which editor IDEs should get rules files? (optional)',
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
installation_mode_title: 'Select the installation mode',
|
|
34
|
+
installation_mode_open: 'Open',
|
|
35
|
+
installation_mode_open_hint: 'Public framework without mandatory company integrations',
|
|
36
|
+
installation_mode_internal: 'Internal',
|
|
37
|
+
installation_mode_internal_hint: 'Requires an authorized license and enables ClickUp tracking plus internal policies',
|
|
38
|
+
installation_mode_label: 'Installation mode',
|
|
39
|
+
model_routing_label: 'Model routing',
|
|
40
|
+
model_routing_automatic: 'Automatic per task across all enabled models',
|
|
35
41
|
providers_label: 'Providers',
|
|
36
42
|
quick_start_switch_hint: 'Switch CLIs anytime — your session continues from where you left off',
|
|
37
43
|
created_overlays: 'Created provider overlay directories',
|
|
38
44
|
will_install: 'Will install:',
|
|
39
|
-
agents_count: 'Specialized
|
|
45
|
+
agents_count: 'Specialized discovery and planning agents with RAIL execution and release lanes',
|
|
40
46
|
workflows_count: '6 workflow blueprints',
|
|
41
47
|
templates_count: '6 templates (PRD, Brownfield PRD, Architecture, Task, QA Gate, Quick Brief)',
|
|
42
48
|
constitution: 'Constitution (25 Articles + Preamble)',
|
package/src/wizard/index.js
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
import * as p from '@clack/prompts';
|
|
2
|
-
import { readFileSync } from 'fs';
|
|
2
|
+
import { existsSync, readFileSync } from 'fs';
|
|
3
3
|
import { join, dirname, basename } from 'path';
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
5
|
import { logBanner } from '../utils/logger.js';
|
|
6
|
-
import { stepLanguage, stepProjectType, stepProviderSelection, stepEditorSelection,
|
|
6
|
+
import { stepLanguage, stepProjectType, stepProviderSelection, stepEditorSelection, stepModelSelection, stepInstallationMode, stepConfirmation, stepTermsOfUse } from './questions.js';
|
|
7
7
|
import { createSpinner, showStep, showValidation, showQuickStart } from './feedback.js';
|
|
8
8
|
import { installFramework } from '../installer/core.js';
|
|
9
|
+
import { INSTALLATION_ARTIFACT_PATH, dryRunV2, installV2, reconfigureV2 } from '../installer-v2/index.js';
|
|
10
|
+
import { buildWizardV2InstallationInput } from '../installer-v2/wizard-installation.js';
|
|
11
|
+
import { resolveCapabilityCatalog, verifySignedCapabilityCatalog } from '../installer-v2/catalog-client.js';
|
|
9
12
|
import { validateInstallation } from '../installer/validator.js';
|
|
10
13
|
import { initCollector, track as telemetryTrack, flush as telemetryFlush } from '../telemetry/collector.js';
|
|
11
14
|
import { sendEvents } from '../telemetry/sender.js';
|
|
12
15
|
import { getTelemetryConfig } from '../telemetry/config.js';
|
|
13
16
|
import { t } from './i18n.js';
|
|
14
|
-
import { getLicenseKey, activateLicense } from '../license/client.js';
|
|
17
|
+
import { getLicenseKey, activateLicense, requireLicenseEntitlement } from '../license/client.js';
|
|
15
18
|
import { DEFAULT_MCPS } from '../config/mcp-configs.js';
|
|
16
|
-
import { IDE_CONFIGS
|
|
19
|
+
import { IDE_CONFIGS } from '../config/ide-configs.js';
|
|
17
20
|
|
|
18
21
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
19
22
|
const VERSION = JSON.parse(readFileSync(join(__dirname, '..', '..', 'package.json'), 'utf-8')).version;
|
|
@@ -66,14 +69,28 @@ export async function runWizard(targetDir, options = {}) {
|
|
|
66
69
|
// Step 3a: Provider Selection (which AI providers to use)
|
|
67
70
|
const selectedProviders = options.providers || await stepProviderSelection();
|
|
68
71
|
|
|
69
|
-
// Step 3b:
|
|
70
|
-
|
|
72
|
+
// Step 3b: Enable the full signed lineup for every selected provider. Runtime
|
|
73
|
+
// routing selects the right model per task instead of pinning one at install.
|
|
74
|
+
if (options.capabilityCatalog) {
|
|
75
|
+
throw Object.assign(new Error('unsigned capabilityCatalog injection is forbidden; provide signedCapabilityCatalogEnvelope'), { code: 'UNSIGNED_CATALOG_FORBIDDEN' });
|
|
76
|
+
}
|
|
77
|
+
const catalogResolution = options.signedCapabilityCatalogEnvelope
|
|
78
|
+
? { source: 'provided-signed', catalog: verifySignedCapabilityCatalog(options.signedCapabilityCatalogEnvelope, { publicKeyPem: options.catalogPublicKeyPem }) }
|
|
79
|
+
: await resolveCapabilityCatalog({ projectDir: targetDir, catalogUrl: options.catalogUrl, fetchImpl: options.catalogFetch });
|
|
80
|
+
const modelSelections = options.modelSelections || await stepModelSelection(selectedProviders, catalogResolution.catalog);
|
|
81
|
+
|
|
82
|
+
// Step 3c: Internal mode is a server-authorized entitlement. It enables the
|
|
83
|
+
// internal policy bundle, including mandatory ClickUp tracking.
|
|
84
|
+
const installationMode = options.installationMode || await stepInstallationMode();
|
|
85
|
+
if (installationMode === 'internal') {
|
|
86
|
+
await requireLicenseEntitlement('internal', { validate: options.licenseValidator });
|
|
87
|
+
}
|
|
71
88
|
|
|
72
|
-
// Step
|
|
89
|
+
// Step 3e: Editor Selection (which editor IDEs get rules files)
|
|
73
90
|
const selectedEditors = options.editors || await stepEditorSelection();
|
|
74
91
|
|
|
75
92
|
// Combine providers + editors into selectedIDEs for backward compatibility
|
|
76
|
-
const providerToIDE = { claude: 'claude-code', gemini: 'gemini-cli', codex: 'codex-cli' };
|
|
93
|
+
const providerToIDE = { claude: 'claude-code', gemini: 'gemini-cli', codex: 'codex-cli', grok: 'grok-cli' };
|
|
77
94
|
const selectedIDEs = options.ides || [
|
|
78
95
|
...selectedProviders.map(p => providerToIDE[p]).filter(Boolean),
|
|
79
96
|
...selectedEditors,
|
|
@@ -90,13 +107,28 @@ export async function runWizard(targetDir, options = {}) {
|
|
|
90
107
|
projectName,
|
|
91
108
|
projectType,
|
|
92
109
|
language,
|
|
93
|
-
llmProvider: primaryProvider,
|
|
94
110
|
allProviders: cliProviders,
|
|
95
111
|
selectedIDEs,
|
|
96
112
|
selectedMCPs,
|
|
113
|
+
installationMode,
|
|
114
|
+
modelSelections,
|
|
97
115
|
targetDir,
|
|
98
116
|
version: VERSION,
|
|
99
117
|
};
|
|
118
|
+
const v2InstallationInput = buildWizardV2InstallationInput({
|
|
119
|
+
projectName,
|
|
120
|
+
selectedProviders: cliProviders,
|
|
121
|
+
modelSelections,
|
|
122
|
+
capabilityCatalog: catalogResolution.catalog,
|
|
123
|
+
installationMode,
|
|
124
|
+
});
|
|
125
|
+
// Validate the complete v2 material and refuse a repeated init before the
|
|
126
|
+
// legacy installer writes anything. Reconfiguration uses its own backup and
|
|
127
|
+
// atomic replacement path below.
|
|
128
|
+
dryRunV2(v2InstallationInput, { projectDir: targetDir });
|
|
129
|
+
if (existsSync(join(targetDir, INSTALLATION_ARTIFACT_PATH)) && options.reconfigure !== true) {
|
|
130
|
+
throw Object.assign(new Error('a v2 installation already exists; use --reconfigure to replace it safely'), { code: 'INSTALLATION_ALREADY_EXISTS' });
|
|
131
|
+
}
|
|
100
132
|
|
|
101
133
|
await stepConfirmation(config);
|
|
102
134
|
|
|
@@ -104,8 +136,7 @@ export async function runWizard(targetDir, options = {}) {
|
|
|
104
136
|
config.telemetryEnabled = options.telemetry !== undefined ? options.telemetry : true;
|
|
105
137
|
|
|
106
138
|
// Installation + Validation
|
|
107
|
-
const
|
|
108
|
-
const primaryIDEName = IDE_CONFIGS[primaryIDE]?.name || primaryIDE;
|
|
139
|
+
const selectedCLIIDEs = selectedIDEs.filter(ide => IDE_CONFIGS[ide]?.group === 'cli');
|
|
109
140
|
|
|
110
141
|
const installStart = Date.now();
|
|
111
142
|
|
|
@@ -115,6 +146,8 @@ export async function runWizard(targetDir, options = {}) {
|
|
|
115
146
|
|
|
116
147
|
try {
|
|
117
148
|
await installFramework(config);
|
|
149
|
+
if (options.reconfigure === true) reconfigureV2(v2InstallationInput, { projectDir: targetDir });
|
|
150
|
+
else installV2(v2InstallationInput, { projectDir: targetDir });
|
|
118
151
|
installSpinner.stop();
|
|
119
152
|
|
|
120
153
|
showStep(t('installer.created_chati'));
|
|
@@ -126,8 +159,9 @@ export async function runWizard(targetDir, options = {}) {
|
|
|
126
159
|
'gemini-cli': 'Created .gemini/commands/ (TOML command)',
|
|
127
160
|
'codex-cli': 'Created .agents/skills/chati/ (Codex skill)',
|
|
128
161
|
};
|
|
129
|
-
const
|
|
130
|
-
|
|
162
|
+
for (const cliIDE of selectedCLIIDEs) {
|
|
163
|
+
showStep(commandStepMap[cliIDE] || t('installer.created_commands'));
|
|
164
|
+
}
|
|
131
165
|
|
|
132
166
|
showStep(t('installer.installed_constitution'));
|
|
133
167
|
showStep(t('installer.created_session'));
|
|
@@ -176,10 +210,9 @@ export async function runWizard(targetDir, options = {}) {
|
|
|
176
210
|
const invokeCmdMap = {
|
|
177
211
|
'codex-cli': '$chati',
|
|
178
212
|
};
|
|
179
|
-
const invokeCmd = invokeCmdMap[primaryIDE] || '/chati';
|
|
180
213
|
const quickStartSteps = [
|
|
181
|
-
|
|
182
|
-
|
|
214
|
+
t('installer.quick_start_1'),
|
|
215
|
+
...selectedCLIIDEs.map((cliIDE) => `${IDE_CONFIGS[cliIDE]?.name || cliIDE}: ${invokeCmdMap[cliIDE] || '/chati'}`),
|
|
183
216
|
t('installer.quick_start_3'),
|
|
184
217
|
];
|
|
185
218
|
|
|
@@ -197,7 +230,6 @@ export async function runWizard(targetDir, options = {}) {
|
|
|
197
230
|
editors: selectedEditors,
|
|
198
231
|
projectType,
|
|
199
232
|
language,
|
|
200
|
-
primaryProvider,
|
|
201
233
|
installDuration: Date.now() - installStart,
|
|
202
234
|
});
|
|
203
235
|
const installEvents = telemetryFlush();
|
package/src/wizard/questions.js
CHANGED
|
@@ -5,6 +5,7 @@ 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
7
|
import { IDE_CONFIGS, IDE_TO_PROVIDER } from '../config/ide-configs.js';
|
|
8
|
+
import { supportedV2WizardProviders, wizardModelSuggestions } from '../installer-v2/wizard-installation.js';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Step 1: Language Selection (always in English)
|
|
@@ -66,6 +67,7 @@ const PROVIDER_DISPLAY_NAMES = {
|
|
|
66
67
|
claude: 'Claude (Anthropic)',
|
|
67
68
|
gemini: 'Gemini (Google)',
|
|
68
69
|
codex: 'Codex (OpenAI)',
|
|
70
|
+
grok: 'Grok (xAI)',
|
|
69
71
|
};
|
|
70
72
|
|
|
71
73
|
/**
|
|
@@ -75,7 +77,7 @@ const PROVIDER_DISPLAY_NAMES = {
|
|
|
75
77
|
* Returns an array of provider names (e.g. ['claude', 'gemini']).
|
|
76
78
|
*/
|
|
77
79
|
export async function stepProviderSelection() {
|
|
78
|
-
const cliIDEs = Object.entries(IDE_CONFIGS).filter(([, c]) => c.group === 'cli');
|
|
80
|
+
const cliIDEs = Object.entries(IDE_CONFIGS).filter(([key, c]) => c.group === 'cli' && supportedV2WizardProviders.includes(IDE_TO_PROVIDER[key]));
|
|
79
81
|
const options = [];
|
|
80
82
|
|
|
81
83
|
for (const [key, config] of cliIDEs) {
|
|
@@ -91,7 +93,7 @@ export async function stepProviderSelection() {
|
|
|
91
93
|
const providerName = PROVIDER_DISPLAY_NAMES[provider] || config.name;
|
|
92
94
|
options.push({
|
|
93
95
|
value: provider,
|
|
94
|
-
label: `${providerName}${
|
|
96
|
+
label: `${providerName}${suffix}`,
|
|
95
97
|
hint: config.description,
|
|
96
98
|
});
|
|
97
99
|
}
|
|
@@ -110,6 +112,30 @@ export async function stepProviderSelection() {
|
|
|
110
112
|
return selected;
|
|
111
113
|
}
|
|
112
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Selects the operational policy profile. Focus AI internal projects require
|
|
117
|
+
* ClickUp tracking; standard projects do not gain that external dependency.
|
|
118
|
+
*/
|
|
119
|
+
export async function stepInstallationMode() {
|
|
120
|
+
const mode = await p.select({
|
|
121
|
+
message: t('installer.installation_mode_title'),
|
|
122
|
+
options: [
|
|
123
|
+
{ value: 'open', label: t('installer.installation_mode_open'), hint: t('installer.installation_mode_open_hint') },
|
|
124
|
+
{ value: 'internal', label: t('installer.installation_mode_internal'), hint: t('installer.installation_mode_internal_hint') },
|
|
125
|
+
],
|
|
126
|
+
initialValue: 'open',
|
|
127
|
+
});
|
|
128
|
+
if (p.isCancel(mode)) {
|
|
129
|
+
p.cancel('Installation cancelled.');
|
|
130
|
+
process.exit(0);
|
|
131
|
+
}
|
|
132
|
+
return mode;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Backward-compatible programmatic alias. The interactive wizard no longer
|
|
136
|
+
// exposes an abstract execution profile to users.
|
|
137
|
+
export const stepExecutionProfile = stepInstallationMode;
|
|
138
|
+
|
|
113
139
|
/**
|
|
114
140
|
* Step 3b: Editor Selection (multi-select, optional)
|
|
115
141
|
*
|
|
@@ -204,44 +230,36 @@ export async function stepIDESelection() {
|
|
|
204
230
|
}
|
|
205
231
|
|
|
206
232
|
/**
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
* Determines which provider's adapted files go in chati.dev/ (main).
|
|
233
|
+
* Enables every catalog model for each selected provider. Runtime routing
|
|
234
|
+
* chooses a model per task, so installation never collapses a provider to one
|
|
235
|
+
* supposedly universal "recommended" model.
|
|
211
236
|
*/
|
|
212
|
-
export async function
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
})),
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
if (p.isCancel(primary)) {
|
|
224
|
-
p.cancel('Installation cancelled.');
|
|
225
|
-
process.exit(0);
|
|
237
|
+
export async function stepModelSelection(providers, capabilityCatalog) {
|
|
238
|
+
const selections = {};
|
|
239
|
+
const summary = [];
|
|
240
|
+
|
|
241
|
+
for (const provider of providers) {
|
|
242
|
+
const models = wizardModelSuggestions(provider, capabilityCatalog);
|
|
243
|
+
selections[provider] = [...models];
|
|
244
|
+
summary.push(`${PROVIDER_DISPLAY_NAMES[provider] || provider}: ${models.join(', ')}`);
|
|
226
245
|
}
|
|
227
246
|
|
|
228
|
-
|
|
247
|
+
p.note(summary.join('\n'), t('installer.model_routing_label'));
|
|
248
|
+
|
|
249
|
+
return selections;
|
|
229
250
|
}
|
|
230
251
|
|
|
231
252
|
/**
|
|
232
253
|
* Step 4: Confirmation
|
|
233
254
|
*/
|
|
234
255
|
export async function stepConfirmation(config) {
|
|
235
|
-
const { projectName, projectType, language,
|
|
256
|
+
const { projectName, projectType, language, selectedMCPs, selectedIDEs, allProviders, installationMode } = config;
|
|
236
257
|
|
|
237
258
|
const langName = SUPPORTED_LANGUAGES.find(l => l.value === language)?.label || language;
|
|
238
259
|
|
|
239
|
-
// Show all providers
|
|
240
|
-
const providers = allProviders || [
|
|
241
|
-
const providersDisplay = providers.map(prov =>
|
|
242
|
-
const name = PROVIDER_DISPLAY_NAMES[prov] || prov;
|
|
243
|
-
return prov === llmProvider ? `${name} (Primary)` : name;
|
|
244
|
-
}).join(', ');
|
|
260
|
+
// Show all enabled providers symmetrically.
|
|
261
|
+
const providers = allProviders || [];
|
|
262
|
+
const providersDisplay = providers.map(prov => PROVIDER_DISPLAY_NAMES[prov] || prov).join(', ');
|
|
245
263
|
|
|
246
264
|
// Separate editors from CLI IDEs for display
|
|
247
265
|
const editorIDEs = (selectedIDEs || []).filter(id => IDE_CONFIGS[id]?.group === 'editor');
|
|
@@ -256,6 +274,10 @@ export async function stepConfirmation(config) {
|
|
|
256
274
|
[t('installer.project_label')]: `${projectName} (${projectType === 'greenfield' ? 'Greenfield' : 'Brownfield'})`,
|
|
257
275
|
[t('installer.language_label')]: langName,
|
|
258
276
|
[t('installer.providers_label')]: providersDisplay,
|
|
277
|
+
[t('installer.model_routing_label')]: t('installer.model_routing_automatic'),
|
|
278
|
+
[t('installer.installation_mode_label')]: installationMode === 'internal'
|
|
279
|
+
? t('installer.installation_mode_internal')
|
|
280
|
+
: t('installer.installation_mode_open'),
|
|
259
281
|
};
|
|
260
282
|
|
|
261
283
|
// Only show editor IDEs line if any were selected
|