chati-dev 4.4.1 → 4.5.1
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/manifest.json +13 -13
- 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 +132 -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/scaffold-applier.js +1 -1
- package/src/installer/templates.js +3 -3
- package/src/installer/validator.js +1 -1
- package/src/installer-v2/catalog-client.js +141 -0
- package/src/installer-v2/index.js +301 -0
- package/src/installer-v2/model-catalog-envelope.json +59 -0
- package/src/installer-v2/model-catalog.json +33 -0
- package/src/installer-v2/model-catalog.sig +1 -0
- package/src/installer-v2/wizard-installation.js +115 -0
- package/src/intelligence/registry-manager.js +1 -1
- package/src/license/client.js +1 -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 +38 -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 +14 -0
- package/src/terminal/prompt-builder.js +2 -0
- 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/wizard/i18n.js +8 -2
- package/src/wizard/index.js +39 -4
- package/src/wizard/questions.js +59 -2
|
@@ -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));
|
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));
|
|
@@ -31,12 +31,18 @@ const FALLBACK_EN = {
|
|
|
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
33
|
primary_provider_title: 'Which is your primary CLI provider?',
|
|
34
|
+
execution_profile_title: 'Select the execution profile',
|
|
35
|
+
execution_profile_standard: 'Standard',
|
|
36
|
+
execution_profile_standard_hint: 'Provider-neutral local project workflow',
|
|
37
|
+
execution_profile_internal: 'Focus AI internal',
|
|
38
|
+
execution_profile_internal_hint: 'Requires ClickUp tracking and completion metrics',
|
|
39
|
+
execution_profile_label: 'Execution profile',
|
|
34
40
|
primary_provider_label: 'Primary Provider',
|
|
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,11 +1,14 @@
|
|
|
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, stepPrimaryProvider, stepConfirmation, stepTermsOfUse } from './questions.js';
|
|
6
|
+
import { stepLanguage, stepProjectType, stepProviderSelection, stepEditorSelection, stepPrimaryProvider, stepModelSelection, stepExecutionProfile, 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';
|
|
@@ -69,11 +72,25 @@ export async function runWizard(targetDir, options = {}) {
|
|
|
69
72
|
// Step 3b: Primary provider (only if multiple)
|
|
70
73
|
const primaryProvider = options.llmProvider || await stepPrimaryProvider(selectedProviders);
|
|
71
74
|
|
|
72
|
-
// Step 3c:
|
|
75
|
+
// Step 3c: Models allowed for each selected provider. Never add a provider
|
|
76
|
+
// or model that the user did not explicitly bind to this installation.
|
|
77
|
+
if (options.capabilityCatalog) {
|
|
78
|
+
throw Object.assign(new Error('unsigned capabilityCatalog injection is forbidden; provide signedCapabilityCatalogEnvelope'), { code: 'UNSIGNED_CATALOG_FORBIDDEN' });
|
|
79
|
+
}
|
|
80
|
+
const catalogResolution = options.signedCapabilityCatalogEnvelope
|
|
81
|
+
? { source: 'provided-signed', catalog: verifySignedCapabilityCatalog(options.signedCapabilityCatalogEnvelope, { publicKeyPem: options.catalogPublicKeyPem }) }
|
|
82
|
+
: await resolveCapabilityCatalog({ projectDir: targetDir, catalogUrl: options.catalogUrl, fetchImpl: options.catalogFetch });
|
|
83
|
+
const modelSelections = options.modelSelections || await stepModelSelection(selectedProviders, catalogResolution.catalog);
|
|
84
|
+
|
|
85
|
+
// Step 3d: Profile controls whether ClickUp and internal completion metrics
|
|
86
|
+
// are mandatory. It must never be silently forced on public installations.
|
|
87
|
+
const executionProfile = options.executionProfile || await stepExecutionProfile();
|
|
88
|
+
|
|
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,
|
|
@@ -94,9 +111,25 @@ export async function runWizard(targetDir, options = {}) {
|
|
|
94
111
|
allProviders: cliProviders,
|
|
95
112
|
selectedIDEs,
|
|
96
113
|
selectedMCPs,
|
|
114
|
+
executionProfile,
|
|
97
115
|
targetDir,
|
|
98
116
|
version: VERSION,
|
|
99
117
|
};
|
|
118
|
+
const v2InstallationInput = buildWizardV2InstallationInput({
|
|
119
|
+
projectName,
|
|
120
|
+
selectedProviders: cliProviders,
|
|
121
|
+
primaryProvider,
|
|
122
|
+
modelSelections,
|
|
123
|
+
capabilityCatalog: catalogResolution.catalog,
|
|
124
|
+
profile: executionProfile,
|
|
125
|
+
});
|
|
126
|
+
// Validate the complete v2 material and refuse a repeated init before the
|
|
127
|
+
// legacy installer writes anything. Reconfiguration uses its own backup and
|
|
128
|
+
// atomic replacement path below.
|
|
129
|
+
dryRunV2(v2InstallationInput, { projectDir: targetDir });
|
|
130
|
+
if (existsSync(join(targetDir, INSTALLATION_ARTIFACT_PATH)) && options.reconfigure !== true) {
|
|
131
|
+
throw Object.assign(new Error('a v2 installation already exists; use --reconfigure to replace it safely'), { code: 'INSTALLATION_ALREADY_EXISTS' });
|
|
132
|
+
}
|
|
100
133
|
|
|
101
134
|
await stepConfirmation(config);
|
|
102
135
|
|
|
@@ -115,6 +148,8 @@ export async function runWizard(targetDir, options = {}) {
|
|
|
115
148
|
|
|
116
149
|
try {
|
|
117
150
|
await installFramework(config);
|
|
151
|
+
if (options.reconfigure === true) reconfigureV2(v2InstallationInput, { projectDir: targetDir });
|
|
152
|
+
else installV2(v2InstallationInput, { projectDir: targetDir });
|
|
118
153
|
installSpinner.stop();
|
|
119
154
|
|
|
120
155
|
showStep(t('installer.created_chati'));
|
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, wizardDefaultModels, 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) {
|
|
@@ -110,6 +112,26 @@ 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 stepExecutionProfile() {
|
|
120
|
+
const profile = await p.select({
|
|
121
|
+
message: t('installer.execution_profile_title'),
|
|
122
|
+
options: [
|
|
123
|
+
{ value: 'other-supported-profile', label: t('installer.execution_profile_standard'), hint: t('installer.execution_profile_standard_hint') },
|
|
124
|
+
{ value: 'focus-ai-internal', label: t('installer.execution_profile_internal'), hint: t('installer.execution_profile_internal_hint') },
|
|
125
|
+
],
|
|
126
|
+
initialValue: 'other-supported-profile',
|
|
127
|
+
});
|
|
128
|
+
if (p.isCancel(profile)) {
|
|
129
|
+
p.cancel('Installation cancelled.');
|
|
130
|
+
process.exit(0);
|
|
131
|
+
}
|
|
132
|
+
return profile;
|
|
133
|
+
}
|
|
134
|
+
|
|
113
135
|
/**
|
|
114
136
|
* Step 3b: Editor Selection (multi-select, optional)
|
|
115
137
|
*
|
|
@@ -228,11 +250,43 @@ export async function stepPrimaryProvider(cliProviders) {
|
|
|
228
250
|
return primary;
|
|
229
251
|
}
|
|
230
252
|
|
|
253
|
+
/**
|
|
254
|
+
* Records exactly which models the installation is allowed to orchestrate.
|
|
255
|
+
* A catalog refresh can replace the suggestion, but the user remains the
|
|
256
|
+
* authority for the final binding stored in the installation artifact.
|
|
257
|
+
*/
|
|
258
|
+
export async function stepModelSelection(providers, capabilityCatalog) {
|
|
259
|
+
const selections = {};
|
|
260
|
+
|
|
261
|
+
for (const provider of providers) {
|
|
262
|
+
const suggestions = wizardModelSuggestions(provider, capabilityCatalog);
|
|
263
|
+
const suggested = suggestions[0] || wizardDefaultModels[provider];
|
|
264
|
+
const answer = await p.text({
|
|
265
|
+
message: `Models for ${PROVIDER_DISPLAY_NAMES[provider] || provider} (comma-separated):`,
|
|
266
|
+
placeholder: suggestions.join(', '),
|
|
267
|
+
initialValue: suggested,
|
|
268
|
+
validate: (value) => {
|
|
269
|
+
const models = String(value || '').split(',').map((item) => item.trim()).filter(Boolean);
|
|
270
|
+
return models.length > 0 ? undefined : 'Select at least one model.';
|
|
271
|
+
},
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
if (p.isCancel(answer)) {
|
|
275
|
+
p.cancel('Installation cancelled.');
|
|
276
|
+
process.exit(0);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
selections[provider] = String(answer).split(',').map((item) => item.trim()).filter(Boolean);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return selections;
|
|
283
|
+
}
|
|
284
|
+
|
|
231
285
|
/**
|
|
232
286
|
* Step 4: Confirmation
|
|
233
287
|
*/
|
|
234
288
|
export async function stepConfirmation(config) {
|
|
235
|
-
const { projectName, projectType, language, llmProvider, selectedMCPs, selectedIDEs, allProviders } = config;
|
|
289
|
+
const { projectName, projectType, language, llmProvider, selectedMCPs, selectedIDEs, allProviders, executionProfile } = config;
|
|
236
290
|
|
|
237
291
|
const langName = SUPPORTED_LANGUAGES.find(l => l.value === language)?.label || language;
|
|
238
292
|
|
|
@@ -256,6 +310,9 @@ export async function stepConfirmation(config) {
|
|
|
256
310
|
[t('installer.project_label')]: `${projectName} (${projectType === 'greenfield' ? 'Greenfield' : 'Brownfield'})`,
|
|
257
311
|
[t('installer.language_label')]: langName,
|
|
258
312
|
[t('installer.providers_label')]: providersDisplay,
|
|
313
|
+
[t('installer.execution_profile_label')]: executionProfile === 'focus-ai-internal'
|
|
314
|
+
? `${t('installer.execution_profile_internal')} (ClickUp required)`
|
|
315
|
+
: t('installer.execution_profile_standard'),
|
|
259
316
|
};
|
|
260
317
|
|
|
261
318
|
// Only show editor IDEs line if any were selected
|