chati-dev 4.5.3 → 4.5.4
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/framework/config.yaml +2 -2
- package/framework/context/root.md +1 -1
- package/framework/i18n/en.yaml +5 -2
- package/framework/i18n/es.yaml +5 -2
- package/framework/i18n/fr.yaml +5 -2
- package/framework/i18n/pt.yaml +5 -2
- package/framework/manifest.json +12 -12
- package/framework/manifest.sig +1 -1
- package/package.json +1 -1
- package/src/license/client.js +24 -1
- package/src/wizard/i18n.js +5 -2
- package/src/wizard/index.js +151 -65
- package/src/wizard/questions.js +32 -13
package/framework/config.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Chati.dev System Context
|
|
2
2
|
|
|
3
3
|
## Framework
|
|
4
|
-
- **Version**: 4.5.
|
|
4
|
+
- **Version**: 4.5.4
|
|
5
5
|
- **Agents**: Specialized discovery and planning agents feeding provider-neutral RAIL execution and a sealed release lane
|
|
6
6
|
- **Constitution**: 25 Articles + Preamble
|
|
7
7
|
- **Quality**: 5 pipeline gates + 3-tier verdicts + Fault Vector Protocol (Article XXII)
|
package/framework/i18n/en.yaml
CHANGED
|
@@ -24,10 +24,13 @@ installer:
|
|
|
24
24
|
ide_selection_title: "Select your IDEs / CLIs (multiple allowed):"
|
|
25
25
|
installation_mode_title: "Select the installation mode"
|
|
26
26
|
installation_mode_open: "Open"
|
|
27
|
-
installation_mode_open_hint: "Public framework
|
|
27
|
+
installation_mode_open_hint: "Public framework"
|
|
28
28
|
installation_mode_internal: "Internal"
|
|
29
|
-
installation_mode_internal_hint: "Requires an authorized license
|
|
29
|
+
installation_mode_internal_hint: "Requires an authorized license"
|
|
30
30
|
installation_mode_label: "Installation mode"
|
|
31
|
+
back: "Back"
|
|
32
|
+
back_hint: "Return to the previous step"
|
|
33
|
+
install: "Install"
|
|
31
34
|
model_routing_label: "Model routing"
|
|
32
35
|
model_routing_automatic: "Automatic per task across all enabled models"
|
|
33
36
|
providers_label: "Providers"
|
package/framework/i18n/es.yaml
CHANGED
|
@@ -24,10 +24,13 @@ installer:
|
|
|
24
24
|
ide_selection_title: "Seleccione sus IDEs / CLIs (multiples permitidos):"
|
|
25
25
|
installation_mode_title: "Seleccione el modo de instalacion"
|
|
26
26
|
installation_mode_open: "Open"
|
|
27
|
-
installation_mode_open_hint: "Framework publico
|
|
27
|
+
installation_mode_open_hint: "Framework publico"
|
|
28
28
|
installation_mode_internal: "Internal"
|
|
29
|
-
installation_mode_internal_hint: "Requiere una licencia autorizada
|
|
29
|
+
installation_mode_internal_hint: "Requiere una licencia autorizada"
|
|
30
30
|
installation_mode_label: "Modo de instalacion"
|
|
31
|
+
back: "Volver"
|
|
32
|
+
back_hint: "Regresar al paso anterior"
|
|
33
|
+
install: "Instalar"
|
|
31
34
|
model_routing_label: "Enrutamiento de modelos"
|
|
32
35
|
model_routing_automatic: "Automatico por tarea entre todos los modelos habilitados"
|
|
33
36
|
providers_label: "Proveedores"
|
package/framework/i18n/fr.yaml
CHANGED
|
@@ -24,10 +24,13 @@ installer:
|
|
|
24
24
|
ide_selection_title: "Selectionnez vos IDEs / CLIs (multiples autorises):"
|
|
25
25
|
installation_mode_title: "Selectionnez le mode d'installation"
|
|
26
26
|
installation_mode_open: "Open"
|
|
27
|
-
installation_mode_open_hint: "Framework public
|
|
27
|
+
installation_mode_open_hint: "Framework public"
|
|
28
28
|
installation_mode_internal: "Internal"
|
|
29
|
-
installation_mode_internal_hint: "Necessite une licence autorisee
|
|
29
|
+
installation_mode_internal_hint: "Necessite une licence autorisee"
|
|
30
30
|
installation_mode_label: "Mode d'installation"
|
|
31
|
+
back: "Retour"
|
|
32
|
+
back_hint: "Revenir a l'etape precedente"
|
|
33
|
+
install: "Installer"
|
|
31
34
|
model_routing_label: "Routage des modeles"
|
|
32
35
|
model_routing_automatic: "Automatique par tache entre tous les modeles actives"
|
|
33
36
|
providers_label: "Fournisseurs"
|
package/framework/i18n/pt.yaml
CHANGED
|
@@ -24,10 +24,13 @@ installer:
|
|
|
24
24
|
ide_selection_title: "Selecione suas IDEs / CLIs (multiplos permitidos):"
|
|
25
25
|
installation_mode_title: "Selecione o modo de instalacao"
|
|
26
26
|
installation_mode_open: "Open"
|
|
27
|
-
installation_mode_open_hint: "Framework publico
|
|
27
|
+
installation_mode_open_hint: "Framework publico"
|
|
28
28
|
installation_mode_internal: "Internal"
|
|
29
|
-
installation_mode_internal_hint: "Exige uma licenca autorizada
|
|
29
|
+
installation_mode_internal_hint: "Exige uma licenca autorizada"
|
|
30
30
|
installation_mode_label: "Modo de instalacao"
|
|
31
|
+
back: "Voltar"
|
|
32
|
+
back_hint: "Retornar a etapa anterior"
|
|
33
|
+
install: "Instalar"
|
|
31
34
|
model_routing_label: "Roteamento de modelos"
|
|
32
35
|
model_routing_automatic: "Automatico por task entre todos os modelos habilitados"
|
|
33
36
|
providers_label: "Provedores"
|
package/framework/manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"createdAt": "2026-08-27T07:
|
|
2
|
+
"createdAt": "2026-08-27T07:55:29.821Z",
|
|
3
3
|
"files": {
|
|
4
4
|
"agents/build/dev.md": {
|
|
5
5
|
"hash": "5c8da2eee3357bbe84a6c468c76fe60a0c77357575503c3797aa94128282c565",
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
"type": "md"
|
|
98
98
|
},
|
|
99
99
|
"config.yaml": {
|
|
100
|
-
"hash": "
|
|
100
|
+
"hash": "c031e5565adc3a1dcbfd2534e20b486fd9563158a36d10e2b1f2f73874eb76f4",
|
|
101
101
|
"size": 2841,
|
|
102
102
|
"type": "yaml"
|
|
103
103
|
},
|
|
@@ -122,7 +122,7 @@
|
|
|
122
122
|
"type": "md"
|
|
123
123
|
},
|
|
124
124
|
"context/root.md": {
|
|
125
|
-
"hash": "
|
|
125
|
+
"hash": "046ff16a4973c4d73d186849bd734914d6b90a9864d5bd41f435991b7004c8b2",
|
|
126
126
|
"size": 1217,
|
|
127
127
|
"type": "md"
|
|
128
128
|
},
|
|
@@ -377,23 +377,23 @@
|
|
|
377
377
|
"type": "js"
|
|
378
378
|
},
|
|
379
379
|
"i18n/en.yaml": {
|
|
380
|
-
"hash": "
|
|
381
|
-
"size":
|
|
380
|
+
"hash": "b5e9bf16c930a61543b17088a7267caea0c94eb32bfe0ae2e874ba15f5cdb4aa",
|
|
381
|
+
"size": 4929,
|
|
382
382
|
"type": "yaml"
|
|
383
383
|
},
|
|
384
384
|
"i18n/es.yaml": {
|
|
385
|
-
"hash": "
|
|
386
|
-
"size":
|
|
385
|
+
"hash": "5407e4c6adba697da8bf2e2dbdf39f1fd32935326166852d5b488487148320f1",
|
|
386
|
+
"size": 5204,
|
|
387
387
|
"type": "yaml"
|
|
388
388
|
},
|
|
389
389
|
"i18n/fr.yaml": {
|
|
390
|
-
"hash": "
|
|
391
|
-
"size":
|
|
390
|
+
"hash": "2e3b50c56ee5f05f81c4e48fd048c679baae2280e3a9c03c589f8f82989eded4",
|
|
391
|
+
"size": 5276,
|
|
392
392
|
"type": "yaml"
|
|
393
393
|
},
|
|
394
394
|
"i18n/pt.yaml": {
|
|
395
|
-
"hash": "
|
|
396
|
-
"size":
|
|
395
|
+
"hash": "da65aff46c8f16b1c6fd6be10b89b566253eec71fea0a42094878dcc9e4671fa",
|
|
396
|
+
"size": 5147,
|
|
397
397
|
"type": "yaml"
|
|
398
398
|
},
|
|
399
399
|
"intelligence/confidence.yaml": {
|
|
@@ -1347,5 +1347,5 @@
|
|
|
1347
1347
|
"type": "yaml"
|
|
1348
1348
|
}
|
|
1349
1349
|
},
|
|
1350
|
-
"version": "4.5.
|
|
1350
|
+
"version": "4.5.4"
|
|
1351
1351
|
}
|
package/framework/manifest.sig
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
8t69CRtft7FLT0qSIiCVC7zuHbWVEVXvYtQTxm9B6/Ln3+J5UC0rlzl3mI69qD2P8tZPUNyCbdaWfLbwSyVaBw==
|
package/package.json
CHANGED
package/src/license/client.js
CHANGED
|
@@ -141,6 +141,26 @@ export function hasLicenseEntitlement(status, entitlement) {
|
|
|
141
141
|
return status?.status === 'VALID' && normalizeEntitlements(status.entitlements).includes(entitlement);
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Verifies that a saved key is registered for the current machine. A copied
|
|
146
|
+
* global license file may contain a valid key associated with another host.
|
|
147
|
+
*/
|
|
148
|
+
export async function ensureCurrentMachineLicense({
|
|
149
|
+
key = getLicenseKey(),
|
|
150
|
+
validate = validateLicense,
|
|
151
|
+
activate = activateLicense,
|
|
152
|
+
} = {}) {
|
|
153
|
+
if (!key) return { status: 'MISSING' };
|
|
154
|
+
const status = await validate(null);
|
|
155
|
+
if (status.status === 'VALID' || status.reason !== 'Machine not authorized') return status;
|
|
156
|
+
const activated = await activate(null, key);
|
|
157
|
+
return {
|
|
158
|
+
...activated,
|
|
159
|
+
status: 'VALID',
|
|
160
|
+
entitlements: normalizeEntitlements(activated.entitlements),
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
144
164
|
/**
|
|
145
165
|
* Refreshes the server-authoritative license status and requires one
|
|
146
166
|
* entitlement before an internal installation can proceed.
|
|
@@ -148,7 +168,10 @@ export function hasLicenseEntitlement(status, entitlement) {
|
|
|
148
168
|
export async function requireLicenseEntitlement(entitlement, { validate = validateLicense } = {}) {
|
|
149
169
|
const status = await validate(null);
|
|
150
170
|
if (!hasLicenseEntitlement(status, entitlement)) {
|
|
151
|
-
|
|
171
|
+
const message = status?.status !== 'VALID' && status?.reason
|
|
172
|
+
? `License validation failed: ${status.reason}.`
|
|
173
|
+
: `The active license is not authorized for ${entitlement} mode.`;
|
|
174
|
+
throw Object.assign(new Error(message), {
|
|
152
175
|
code: 'LICENSE_ENTITLEMENT_REQUIRED',
|
|
153
176
|
entitlement,
|
|
154
177
|
});
|
package/src/wizard/i18n.js
CHANGED
|
@@ -32,10 +32,13 @@ const FALLBACK_EN = {
|
|
|
32
32
|
editor_selection_title: 'Which editor IDEs should get rules files? (optional)',
|
|
33
33
|
installation_mode_title: 'Select the installation mode',
|
|
34
34
|
installation_mode_open: 'Open',
|
|
35
|
-
installation_mode_open_hint: 'Public framework
|
|
35
|
+
installation_mode_open_hint: 'Public framework',
|
|
36
36
|
installation_mode_internal: 'Internal',
|
|
37
|
-
installation_mode_internal_hint: 'Requires an authorized license
|
|
37
|
+
installation_mode_internal_hint: 'Requires an authorized license',
|
|
38
38
|
installation_mode_label: 'Installation mode',
|
|
39
|
+
back: 'Back',
|
|
40
|
+
back_hint: 'Return to the previous step',
|
|
41
|
+
install: 'Install',
|
|
39
42
|
model_routing_label: 'Model routing',
|
|
40
43
|
model_routing_automatic: 'Automatic per task across all enabled models',
|
|
41
44
|
providers_label: 'Providers',
|
package/src/wizard/index.js
CHANGED
|
@@ -3,7 +3,7 @@ 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, stepModelSelection, stepInstallationMode, stepConfirmation, stepTermsOfUse } from './questions.js';
|
|
6
|
+
import { WIZARD_BACK, 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
9
|
import { INSTALLATION_ARTIFACT_PATH, dryRunV2, installV2, reconfigureV2 } from '../installer-v2/index.js';
|
|
@@ -14,7 +14,7 @@ import { initCollector, track as telemetryTrack, flush as telemetryFlush } from
|
|
|
14
14
|
import { sendEvents } from '../telemetry/sender.js';
|
|
15
15
|
import { getTelemetryConfig } from '../telemetry/config.js';
|
|
16
16
|
import { t } from './i18n.js';
|
|
17
|
-
import { getLicenseKey, activateLicense, requireLicenseEntitlement } from '../license/client.js';
|
|
17
|
+
import { getLicenseKey, activateLicense, ensureCurrentMachineLicense, requireLicenseEntitlement } from '../license/client.js';
|
|
18
18
|
import { DEFAULT_MCPS } from '../config/mcp-configs.js';
|
|
19
19
|
import { IDE_CONFIGS } from '../config/ide-configs.js';
|
|
20
20
|
|
|
@@ -56,81 +56,159 @@ export async function runWizard(targetDir, options = {}) {
|
|
|
56
56
|
p.log.success(`System check:\n${preflightFmt}`);
|
|
57
57
|
|
|
58
58
|
// Step 2: Language Selection
|
|
59
|
-
|
|
59
|
+
let language = options.language || await stepLanguage();
|
|
60
60
|
|
|
61
61
|
// Step 2: Terms of Use (must accept to continue)
|
|
62
62
|
if (options.telemetry === undefined) {
|
|
63
63
|
await stepTermsOfUse();
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
// Step 3: Project Type
|
|
67
|
-
const projectType = options.projectType || await stepProjectType(targetDir);
|
|
68
|
-
|
|
69
|
-
// Step 3a: Provider Selection (which AI providers to use)
|
|
70
|
-
const selectedProviders = options.providers || await stepProviderSelection();
|
|
71
|
-
|
|
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
66
|
if (options.capabilityCatalog) {
|
|
75
67
|
throw Object.assign(new Error('unsigned capabilityCatalog injection is forbidden; provide signedCapabilityCatalogEnvelope'), { code: 'UNSIGNED_CATALOG_FORBIDDEN' });
|
|
76
68
|
}
|
|
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
|
-
}
|
|
88
69
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const config = {
|
|
107
|
-
projectName,
|
|
108
|
-
projectType,
|
|
109
|
-
language,
|
|
110
|
-
allProviders: cliProviders,
|
|
111
|
-
selectedIDEs,
|
|
112
|
-
selectedMCPs,
|
|
113
|
-
installationMode,
|
|
114
|
-
modelSelections,
|
|
115
|
-
targetDir,
|
|
116
|
-
version: VERSION,
|
|
70
|
+
let projectType;
|
|
71
|
+
let selectedProviders;
|
|
72
|
+
let catalogResolution;
|
|
73
|
+
let modelSelections;
|
|
74
|
+
let installationMode;
|
|
75
|
+
let selectedEditors;
|
|
76
|
+
let config;
|
|
77
|
+
let v2InstallationInput;
|
|
78
|
+
let stage = 'project';
|
|
79
|
+
|
|
80
|
+
const stageOrder = ['language', 'project', 'providers', 'mode', 'editors', 'confirm'];
|
|
81
|
+
const optionKey = {
|
|
82
|
+
language: 'language',
|
|
83
|
+
project: 'projectType',
|
|
84
|
+
providers: 'providers',
|
|
85
|
+
mode: 'installationMode',
|
|
86
|
+
editors: 'editors',
|
|
117
87
|
};
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
88
|
+
const previousInteractiveStage = (current) => {
|
|
89
|
+
for (let index = stageOrder.indexOf(current) - 1; index >= 0; index -= 1) {
|
|
90
|
+
const candidate = stageOrder[index];
|
|
91
|
+
if (candidate === 'language' ? options.language === undefined : options[optionKey[candidate]] === undefined) {
|
|
92
|
+
return candidate;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return null;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
while (stage !== 'complete') {
|
|
99
|
+
if (stage === 'language') {
|
|
100
|
+
language = await stepLanguage();
|
|
101
|
+
stage = 'project';
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (stage === 'project') {
|
|
106
|
+
const value = options.projectType !== undefined
|
|
107
|
+
? options.projectType
|
|
108
|
+
: await stepProjectType(targetDir, { allowBack: previousInteractiveStage('project') !== null });
|
|
109
|
+
if (value === WIZARD_BACK) {
|
|
110
|
+
stage = previousInteractiveStage('project');
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
projectType = value;
|
|
114
|
+
stage = 'providers';
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (stage === 'providers') {
|
|
119
|
+
const value = options.providers !== undefined
|
|
120
|
+
? options.providers
|
|
121
|
+
: await stepProviderSelection({ allowBack: previousInteractiveStage('providers') !== null });
|
|
122
|
+
if (value === WIZARD_BACK) {
|
|
123
|
+
stage = previousInteractiveStage('providers');
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
selectedProviders = value;
|
|
127
|
+
catalogResolution ??= options.signedCapabilityCatalogEnvelope
|
|
128
|
+
? { source: 'provided-signed', catalog: verifySignedCapabilityCatalog(options.signedCapabilityCatalogEnvelope, { publicKeyPem: options.catalogPublicKeyPem }) }
|
|
129
|
+
: await resolveCapabilityCatalog({ projectDir: targetDir, catalogUrl: options.catalogUrl, fetchImpl: options.catalogFetch });
|
|
130
|
+
modelSelections = options.modelSelections !== undefined
|
|
131
|
+
? options.modelSelections
|
|
132
|
+
: await stepModelSelection(selectedProviders, catalogResolution.catalog);
|
|
133
|
+
stage = 'mode';
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (stage === 'mode') {
|
|
138
|
+
const value = options.installationMode !== undefined
|
|
139
|
+
? options.installationMode
|
|
140
|
+
: await stepInstallationMode({ allowBack: previousInteractiveStage('mode') !== null });
|
|
141
|
+
if (value === WIZARD_BACK) {
|
|
142
|
+
stage = previousInteractiveStage('mode');
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
installationMode = value;
|
|
146
|
+
if (installationMode === 'internal') {
|
|
147
|
+
try {
|
|
148
|
+
await requireLicenseEntitlement('internal', { validate: options.licenseValidator });
|
|
149
|
+
} catch (error) {
|
|
150
|
+
if (options.installationMode !== undefined) throw error;
|
|
151
|
+
p.log.error(error.message);
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
stage = 'editors';
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (stage === 'editors') {
|
|
160
|
+
const value = options.editors !== undefined
|
|
161
|
+
? options.editors
|
|
162
|
+
: await stepEditorSelection({ allowBack: previousInteractiveStage('editors') !== null });
|
|
163
|
+
if (value === WIZARD_BACK) {
|
|
164
|
+
stage = previousInteractiveStage('editors');
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
selectedEditors = value;
|
|
168
|
+
stage = 'confirm';
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const providerToIDE = { claude: 'claude-code', gemini: 'gemini-cli', codex: 'codex-cli', grok: 'grok-cli' };
|
|
173
|
+
const selectedIDEs = options.ides || [
|
|
174
|
+
...selectedProviders.map(provider => providerToIDE[provider]).filter(Boolean),
|
|
175
|
+
...selectedEditors,
|
|
176
|
+
];
|
|
177
|
+
const cliProviders = selectedProviders;
|
|
178
|
+
const selectedMCPs = options.mcps || DEFAULT_MCPS;
|
|
179
|
+
const projectName = basename(targetDir);
|
|
180
|
+
config = {
|
|
181
|
+
projectName,
|
|
182
|
+
projectType,
|
|
183
|
+
language,
|
|
184
|
+
allProviders: cliProviders,
|
|
185
|
+
selectedIDEs,
|
|
186
|
+
selectedMCPs,
|
|
187
|
+
installationMode,
|
|
188
|
+
modelSelections,
|
|
189
|
+
targetDir,
|
|
190
|
+
version: VERSION,
|
|
191
|
+
};
|
|
192
|
+
v2InstallationInput = buildWizardV2InstallationInput({
|
|
193
|
+
projectName,
|
|
194
|
+
selectedProviders: cliProviders,
|
|
195
|
+
modelSelections,
|
|
196
|
+
capabilityCatalog: catalogResolution.catalog,
|
|
197
|
+
installationMode,
|
|
198
|
+
});
|
|
199
|
+
dryRunV2(v2InstallationInput, { projectDir: targetDir });
|
|
200
|
+
if (existsSync(join(targetDir, INSTALLATION_ARTIFACT_PATH)) && options.reconfigure !== true) {
|
|
201
|
+
throw Object.assign(new Error('a v2 installation already exists; use --reconfigure to replace it safely'), { code: 'INSTALLATION_ALREADY_EXISTS' });
|
|
202
|
+
}
|
|
203
|
+
const confirmation = await stepConfirmation(config, { allowBack: previousInteractiveStage('confirm') !== null });
|
|
204
|
+
if (confirmation === WIZARD_BACK) {
|
|
205
|
+
stage = previousInteractiveStage('confirm');
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
stage = 'complete';
|
|
131
209
|
}
|
|
132
210
|
|
|
133
|
-
|
|
211
|
+
const { selectedIDEs, selectedMCPs, allProviders: cliProviders } = config;
|
|
134
212
|
|
|
135
213
|
// Telemetry: enabled by default (opt-out model via ToS)
|
|
136
214
|
config.telemetryEnabled = options.telemetry !== undefined ? options.telemetry : true;
|
|
@@ -250,7 +328,15 @@ export async function runWizard(targetDir, options = {}) {
|
|
|
250
328
|
|
|
251
329
|
async function runLicenseActivationStep() {
|
|
252
330
|
const existingKey = getLicenseKey();
|
|
253
|
-
if (existingKey)
|
|
331
|
+
if (existingKey) {
|
|
332
|
+
try {
|
|
333
|
+
const status = await ensureCurrentMachineLicense({ key: existingKey });
|
|
334
|
+
if (status.status === 'VALID') return;
|
|
335
|
+
p.log.warn(`Saved license is not valid on this machine: ${status.reason || status.status}`);
|
|
336
|
+
} catch (error) {
|
|
337
|
+
p.log.warn(`Could not verify the saved license: ${error.message}`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
254
340
|
|
|
255
341
|
console.log('\n ┌─ License Activation ─────────────────────────────────────────┐');
|
|
256
342
|
console.log(' │ Your license key works across ALL projects on this machine. │');
|
package/src/wizard/questions.js
CHANGED
|
@@ -7,6 +7,12 @@ import { isProviderAvailable } from '../terminal/cli-registry.js';
|
|
|
7
7
|
import { IDE_CONFIGS, IDE_TO_PROVIDER } from '../config/ide-configs.js';
|
|
8
8
|
import { supportedV2WizardProviders, wizardModelSuggestions } from '../installer-v2/wizard-installation.js';
|
|
9
9
|
|
|
10
|
+
export const WIZARD_BACK = '__chati_wizard_back__';
|
|
11
|
+
|
|
12
|
+
function backOption() {
|
|
13
|
+
return { value: WIZARD_BACK, label: `← ${t('installer.back')}`, hint: t('installer.back_hint') };
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
/**
|
|
11
17
|
* Step 1: Language Selection (always in English)
|
|
12
18
|
*/
|
|
@@ -33,7 +39,7 @@ export async function stepLanguage() {
|
|
|
33
39
|
/**
|
|
34
40
|
* Step 2: Project Type
|
|
35
41
|
*/
|
|
36
|
-
export async function stepProjectType(targetDir) {
|
|
42
|
+
export async function stepProjectType(targetDir, { allowBack = false } = {}) {
|
|
37
43
|
const detection = detectProjectType(targetDir);
|
|
38
44
|
|
|
39
45
|
if (detection.suggestion === 'brownfield' && detection.confidence !== 'low') {
|
|
@@ -48,6 +54,7 @@ export async function stepProjectType(targetDir) {
|
|
|
48
54
|
options: [
|
|
49
55
|
{ value: 'greenfield', label: t('installer.greenfield') },
|
|
50
56
|
{ value: 'brownfield', label: t('installer.brownfield') },
|
|
57
|
+
...(allowBack ? [backOption()] : []),
|
|
51
58
|
],
|
|
52
59
|
initialValue: detection.suggestion,
|
|
53
60
|
});
|
|
@@ -76,7 +83,7 @@ const PROVIDER_DISPLAY_NAMES = {
|
|
|
76
83
|
* Asks the user which AI providers they want to use (Claude, Gemini, Codex).
|
|
77
84
|
* Returns an array of provider names (e.g. ['claude', 'gemini']).
|
|
78
85
|
*/
|
|
79
|
-
export async function stepProviderSelection() {
|
|
86
|
+
export async function stepProviderSelection({ allowBack = false } = {}) {
|
|
80
87
|
const cliIDEs = Object.entries(IDE_CONFIGS).filter(([key, c]) => c.group === 'cli' && supportedV2WizardProviders.includes(IDE_TO_PROVIDER[key]));
|
|
81
88
|
const options = [];
|
|
82
89
|
|
|
@@ -100,7 +107,7 @@ export async function stepProviderSelection() {
|
|
|
100
107
|
|
|
101
108
|
const selected = await p.multiselect({
|
|
102
109
|
message: `${t('installer.provider_selection_title')} ${dim('(space to select, enter to confirm)')}`,
|
|
103
|
-
options,
|
|
110
|
+
options: allowBack ? [...options, backOption()] : options,
|
|
104
111
|
required: true,
|
|
105
112
|
});
|
|
106
113
|
|
|
@@ -109,19 +116,20 @@ export async function stepProviderSelection() {
|
|
|
109
116
|
process.exit(0);
|
|
110
117
|
}
|
|
111
118
|
|
|
112
|
-
return selected;
|
|
119
|
+
return selected.includes(WIZARD_BACK) ? WIZARD_BACK : selected;
|
|
113
120
|
}
|
|
114
121
|
|
|
115
122
|
/**
|
|
116
123
|
* Selects the operational policy profile. Focus AI internal projects require
|
|
117
124
|
* ClickUp tracking; standard projects do not gain that external dependency.
|
|
118
125
|
*/
|
|
119
|
-
export async function stepInstallationMode() {
|
|
126
|
+
export async function stepInstallationMode({ allowBack = false } = {}) {
|
|
120
127
|
const mode = await p.select({
|
|
121
128
|
message: t('installer.installation_mode_title'),
|
|
122
129
|
options: [
|
|
123
130
|
{ value: 'open', label: t('installer.installation_mode_open'), hint: t('installer.installation_mode_open_hint') },
|
|
124
131
|
{ value: 'internal', label: t('installer.installation_mode_internal'), hint: t('installer.installation_mode_internal_hint') },
|
|
132
|
+
...(allowBack ? [backOption()] : []),
|
|
125
133
|
],
|
|
126
134
|
initialValue: 'open',
|
|
127
135
|
});
|
|
@@ -142,7 +150,7 @@ export const stepExecutionProfile = stepInstallationMode;
|
|
|
142
150
|
* Asks the user which editor IDEs should receive rules files.
|
|
143
151
|
* Returns an array of IDE keys (e.g. ['vscode', 'cursor']).
|
|
144
152
|
*/
|
|
145
|
-
export async function stepEditorSelection() {
|
|
153
|
+
export async function stepEditorSelection({ allowBack = false } = {}) {
|
|
146
154
|
const editorIDEs = Object.entries(IDE_CONFIGS).filter(([, c]) => c.group === 'editor');
|
|
147
155
|
|
|
148
156
|
if (editorIDEs.length === 0) return [];
|
|
@@ -155,7 +163,7 @@ export async function stepEditorSelection() {
|
|
|
155
163
|
|
|
156
164
|
const selected = await p.multiselect({
|
|
157
165
|
message: `${t('installer.editor_selection_title')} ${dim('(space to select, enter to confirm)')}`,
|
|
158
|
-
options,
|
|
166
|
+
options: allowBack ? [...options, backOption()] : options,
|
|
159
167
|
required: false,
|
|
160
168
|
});
|
|
161
169
|
|
|
@@ -164,7 +172,7 @@ export async function stepEditorSelection() {
|
|
|
164
172
|
process.exit(0);
|
|
165
173
|
}
|
|
166
174
|
|
|
167
|
-
return selected;
|
|
175
|
+
return selected.includes(WIZARD_BACK) ? WIZARD_BACK : selected;
|
|
168
176
|
}
|
|
169
177
|
|
|
170
178
|
/**
|
|
@@ -252,7 +260,7 @@ export async function stepModelSelection(providers, capabilityCatalog) {
|
|
|
252
260
|
/**
|
|
253
261
|
* Step 4: Confirmation
|
|
254
262
|
*/
|
|
255
|
-
export async function stepConfirmation(config) {
|
|
263
|
+
export async function stepConfirmation(config, { allowBack = false } = {}) {
|
|
256
264
|
const { projectName, projectType, language, selectedMCPs, selectedIDEs, allProviders, installationMode } = config;
|
|
257
265
|
|
|
258
266
|
const langName = SUPPORTED_LANGUAGES.find(l => l.value === language)?.label || language;
|
|
@@ -305,10 +313,21 @@ export async function stepConfirmation(config) {
|
|
|
305
313
|
console.log();
|
|
306
314
|
console.log(` ${dim('Target:')} ${config.targetDir}`);
|
|
307
315
|
|
|
308
|
-
const proceed =
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
316
|
+
const proceed = allowBack
|
|
317
|
+
? await p.select({
|
|
318
|
+
message: t('installer.proceed'),
|
|
319
|
+
options: [
|
|
320
|
+
{ value: true, label: t('installer.install') },
|
|
321
|
+
backOption(),
|
|
322
|
+
],
|
|
323
|
+
initialValue: true,
|
|
324
|
+
})
|
|
325
|
+
: await p.confirm({
|
|
326
|
+
message: t('installer.proceed'),
|
|
327
|
+
initialValue: true,
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
if (proceed === WIZARD_BACK) return WIZARD_BACK;
|
|
312
331
|
|
|
313
332
|
if (p.isCancel(proceed) || !proceed) {
|
|
314
333
|
p.cancel('Installation cancelled.');
|