chati-dev 4.5.3 → 4.5.5
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 +3 -4
- package/framework/config.yaml +3 -3
- 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/installer-v2/model-catalog-envelope.json +6 -69
- package/src/installer-v2/model-catalog.json +5 -41
- package/src/installer-v2/model-catalog.sig +1 -1
- package/src/installer-v2/wizard-installation.js +1 -1
- package/src/license/client.js +24 -1
- package/src/wizard/i18n.js +5 -2
- package/src/wizard/index.js +139 -65
- package/src/wizard/questions.js +32 -18
package/README.md
CHANGED
|
@@ -67,15 +67,14 @@ Open a terminal in your project directory:
|
|
|
67
67
|
npx chati-dev init
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
The wizard guides you through
|
|
70
|
+
The wizard guides you through these steps:
|
|
71
71
|
|
|
72
72
|
| Step | What it asks |
|
|
73
73
|
|------|-------------|
|
|
74
74
|
| **Language** | English, Portuguese, Spanish, or French |
|
|
75
75
|
| **Project Type** | Greenfield (new) or Brownfield (existing) |
|
|
76
|
-
| **AI Providers** | Select any combination of Claude, Codex, and Grok |
|
|
77
|
-
| **
|
|
78
|
-
| **Execution Profile** | Standard, or Focus AI internal with mandatory ClickUp tracking and completion metrics |
|
|
76
|
+
| **AI Providers** | Select any combination of Claude, Codex, and Grok; models are routed automatically within this provider pool |
|
|
77
|
+
| **Installation Mode** | Open public framework, or Internal with an authorized license and required company integrations |
|
|
79
78
|
| **Confirm** | Review summary and proceed |
|
|
80
79
|
|
|
81
80
|
### 2. Activate the orchestrator
|
package/framework/config.yaml
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# chati.dev Configuration
|
|
2
|
-
version: "4.5.
|
|
2
|
+
version: "4.5.5"
|
|
3
3
|
installed_at: "2026-02-07T10:00:00Z"
|
|
4
|
-
updated_at: "2026-
|
|
5
|
-
installer_version: "4.5.
|
|
4
|
+
updated_at: "2026-08-27T00:00:00Z"
|
|
5
|
+
installer_version: "4.5.5"
|
|
6
6
|
project_type: greenfield
|
|
7
7
|
language: en
|
|
8
8
|
ides: [claude-code]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Chati.dev System Context
|
|
2
2
|
|
|
3
3
|
## Framework
|
|
4
|
-
- **Version**: 4.5.
|
|
4
|
+
- **Version**: 4.5.5
|
|
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-
|
|
2
|
+
"createdAt": "2026-08-27T08:47:47.618Z",
|
|
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": "46c9b387f94306f10f2d997d4434ee2dbf1d61f33ea5dc8dd3fec4222d4600a5",
|
|
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": "833b0c98763b9d6b6418c33ca2b8333a67bb1ef177c71a9e58cc1c7b0ac2059c",
|
|
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.5"
|
|
1351
1351
|
}
|
package/framework/manifest.sig
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
XENxdEvoK5ATS/SOccXjzQKNM31wPtbN4KdEjNsp8aZvUGdCU2OKZPDJUh1vFC+i4ZvElD0DSFR17EPrYkmPAw==
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"catalog": {
|
|
3
|
-
"snapshot_id": "chati-model-catalog-2026-08-27",
|
|
3
|
+
"snapshot_id": "chati-model-catalog-2026-08-27-v2",
|
|
4
4
|
"published_at": "2026-08-27T00:00:00.000Z",
|
|
5
5
|
"expires_at": "2026-11-25T00:00:00.000Z",
|
|
6
6
|
"models": [
|
|
7
7
|
{
|
|
8
8
|
"provider_id": "anthropic",
|
|
9
|
-
"model_id": "fable",
|
|
9
|
+
"model_id": "claude-fable-5",
|
|
10
10
|
"actions": [
|
|
11
11
|
"discovery",
|
|
12
12
|
"planning",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
"provider_id": "anthropic",
|
|
34
|
-
"model_id": "claude-opus-
|
|
34
|
+
"model_id": "claude-opus-5",
|
|
35
35
|
"actions": [
|
|
36
36
|
"discovery",
|
|
37
37
|
"planning",
|
|
@@ -122,7 +122,7 @@
|
|
|
122
122
|
},
|
|
123
123
|
{
|
|
124
124
|
"provider_id": "openai",
|
|
125
|
-
"model_id": "terra",
|
|
125
|
+
"model_id": "gpt-5.6-terra",
|
|
126
126
|
"actions": [
|
|
127
127
|
"discovery",
|
|
128
128
|
"planning",
|
|
@@ -146,7 +146,7 @@
|
|
|
146
146
|
},
|
|
147
147
|
{
|
|
148
148
|
"provider_id": "openai",
|
|
149
|
-
"model_id": "luna",
|
|
149
|
+
"model_id": "gpt-5.6-luna",
|
|
150
150
|
"actions": [
|
|
151
151
|
"discovery",
|
|
152
152
|
"planning",
|
|
@@ -163,21 +163,6 @@
|
|
|
163
163
|
},
|
|
164
164
|
"adjudication_priority": 30
|
|
165
165
|
},
|
|
166
|
-
{
|
|
167
|
-
"provider_id": "openai",
|
|
168
|
-
"model_id": "nano",
|
|
169
|
-
"actions": [
|
|
170
|
-
"discovery",
|
|
171
|
-
"build"
|
|
172
|
-
],
|
|
173
|
-
"tier": "utility",
|
|
174
|
-
"natural_role": "classification, extraction and cleanup",
|
|
175
|
-
"routing_priority": {
|
|
176
|
-
"discovery": 35,
|
|
177
|
-
"build": 40
|
|
178
|
-
},
|
|
179
|
-
"adjudication_priority": 5
|
|
180
|
-
},
|
|
181
166
|
{
|
|
182
167
|
"provider_id": "xai",
|
|
183
168
|
"model_id": "grok-4.6",
|
|
@@ -223,56 +208,8 @@
|
|
|
223
208
|
},
|
|
224
209
|
"adjudication_priority": 70,
|
|
225
210
|
"highest_reasoning_configuration": "xhigh"
|
|
226
|
-
},
|
|
227
|
-
{
|
|
228
|
-
"provider_id": "xai",
|
|
229
|
-
"model_id": "grok-4.3",
|
|
230
|
-
"actions": [
|
|
231
|
-
"discovery",
|
|
232
|
-
"planning",
|
|
233
|
-
"build",
|
|
234
|
-
"review"
|
|
235
|
-
],
|
|
236
|
-
"tier": "worker",
|
|
237
|
-
"natural_role": "cost-efficient parallel execution",
|
|
238
|
-
"routing_priority": {
|
|
239
|
-
"discovery": 65,
|
|
240
|
-
"planning": 60,
|
|
241
|
-
"build": 78,
|
|
242
|
-
"review": 60
|
|
243
|
-
},
|
|
244
|
-
"adjudication_priority": 35
|
|
245
|
-
},
|
|
246
|
-
{
|
|
247
|
-
"provider_id": "xai",
|
|
248
|
-
"model_id": "grok-4.20",
|
|
249
|
-
"actions": [
|
|
250
|
-
"discovery",
|
|
251
|
-
"build"
|
|
252
|
-
],
|
|
253
|
-
"tier": "worker",
|
|
254
|
-
"natural_role": "high-volume structured tasks",
|
|
255
|
-
"routing_priority": {
|
|
256
|
-
"discovery": 55,
|
|
257
|
-
"build": 70
|
|
258
|
-
},
|
|
259
|
-
"adjudication_priority": 20
|
|
260
|
-
},
|
|
261
|
-
{
|
|
262
|
-
"provider_id": "xai",
|
|
263
|
-
"model_id": "grok-build-0.1",
|
|
264
|
-
"actions": [
|
|
265
|
-
"build"
|
|
266
|
-
],
|
|
267
|
-
"tier": "specialist",
|
|
268
|
-
"natural_role": "speed-first implementation in Grok Build",
|
|
269
|
-
"routing_priority": {
|
|
270
|
-
"build": 90,
|
|
271
|
-
"dev": 92
|
|
272
|
-
},
|
|
273
|
-
"adjudication_priority": 10
|
|
274
211
|
}
|
|
275
212
|
]
|
|
276
213
|
},
|
|
277
|
-
"signature": "
|
|
214
|
+
"signature": "trEytAQJkukerJTwpNvEQ4UO49b+Yth5jtuYNy9WXVSBvKpJCmfuv3tBWyhNgwYG9w3/oKpKDJqJQwIb/oiMAQ=="
|
|
278
215
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"snapshot_id": "chati-model-catalog-2026-08-27",
|
|
2
|
+
"snapshot_id": "chati-model-catalog-2026-08-27-v2",
|
|
3
3
|
"published_at": "2026-08-27T00:00:00.000Z",
|
|
4
4
|
"expires_at": "2026-11-25T00:00:00.000Z",
|
|
5
5
|
"models": [
|
|
6
6
|
{
|
|
7
7
|
"provider_id": "anthropic",
|
|
8
|
-
"model_id": "fable",
|
|
8
|
+
"model_id": "claude-fable-5",
|
|
9
9
|
"actions": ["discovery", "planning", "build", "review", "adjudication"],
|
|
10
10
|
"tier": "frontier",
|
|
11
11
|
"natural_role": "architecture and design",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
},
|
|
16
16
|
{
|
|
17
17
|
"provider_id": "anthropic",
|
|
18
|
-
"model_id": "claude-opus-
|
|
18
|
+
"model_id": "claude-opus-5",
|
|
19
19
|
"actions": ["discovery", "planning", "build", "review", "adjudication"],
|
|
20
20
|
"tier": "frontier",
|
|
21
21
|
"natural_role": "quality rules and judgment-heavy work",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
55
|
"provider_id": "openai",
|
|
56
|
-
"model_id": "terra",
|
|
56
|
+
"model_id": "gpt-5.6-terra",
|
|
57
57
|
"actions": ["discovery", "planning", "build", "review", "adjudication"],
|
|
58
58
|
"tier": "workhorse",
|
|
59
59
|
"natural_role": "scoped implementation and efficient review",
|
|
@@ -63,22 +63,13 @@
|
|
|
63
63
|
},
|
|
64
64
|
{
|
|
65
65
|
"provider_id": "openai",
|
|
66
|
-
"model_id": "luna",
|
|
66
|
+
"model_id": "gpt-5.6-luna",
|
|
67
67
|
"actions": ["discovery", "planning", "build", "review"],
|
|
68
68
|
"tier": "worker",
|
|
69
69
|
"natural_role": "low-cost workers and routine tasks",
|
|
70
70
|
"routing_priority": { "discovery": 60, "planning": 55, "build": 72, "review": 60 },
|
|
71
71
|
"adjudication_priority": 30
|
|
72
72
|
},
|
|
73
|
-
{
|
|
74
|
-
"provider_id": "openai",
|
|
75
|
-
"model_id": "nano",
|
|
76
|
-
"actions": ["discovery", "build"],
|
|
77
|
-
"tier": "utility",
|
|
78
|
-
"natural_role": "classification, extraction and cleanup",
|
|
79
|
-
"routing_priority": { "discovery": 35, "build": 40 },
|
|
80
|
-
"adjudication_priority": 5
|
|
81
|
-
},
|
|
82
73
|
{
|
|
83
74
|
"provider_id": "xai",
|
|
84
75
|
"model_id": "grok-4.6",
|
|
@@ -98,33 +89,6 @@
|
|
|
98
89
|
"routing_priority": { "discovery": 82, "planning": 84, "build": 98, "review": 82, "adjudication": 70, "dev": 98 },
|
|
99
90
|
"adjudication_priority": 70,
|
|
100
91
|
"highest_reasoning_configuration": "xhigh"
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
"provider_id": "xai",
|
|
104
|
-
"model_id": "grok-4.3",
|
|
105
|
-
"actions": ["discovery", "planning", "build", "review"],
|
|
106
|
-
"tier": "worker",
|
|
107
|
-
"natural_role": "cost-efficient parallel execution",
|
|
108
|
-
"routing_priority": { "discovery": 65, "planning": 60, "build": 78, "review": 60 },
|
|
109
|
-
"adjudication_priority": 35
|
|
110
|
-
},
|
|
111
|
-
{
|
|
112
|
-
"provider_id": "xai",
|
|
113
|
-
"model_id": "grok-4.20",
|
|
114
|
-
"actions": ["discovery", "build"],
|
|
115
|
-
"tier": "worker",
|
|
116
|
-
"natural_role": "high-volume structured tasks",
|
|
117
|
-
"routing_priority": { "discovery": 55, "build": 70 },
|
|
118
|
-
"adjudication_priority": 20
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
"provider_id": "xai",
|
|
122
|
-
"model_id": "grok-build-0.1",
|
|
123
|
-
"actions": ["build"],
|
|
124
|
-
"tier": "specialist",
|
|
125
|
-
"natural_role": "speed-first implementation in Grok Build",
|
|
126
|
-
"routing_priority": { "build": 90, "dev": 92 },
|
|
127
|
-
"adjudication_priority": 10
|
|
128
92
|
}
|
|
129
93
|
]
|
|
130
94
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
trEytAQJkukerJTwpNvEQ4UO49b+Yth5jtuYNy9WXVSBvKpJCmfuv3tBWyhNgwYG9w3/oKpKDJqJQwIb/oiMAQ==
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { sha256 } from '@chati/core';
|
|
2
2
|
|
|
3
3
|
const PROVIDER_BINDINGS = Object.freeze({
|
|
4
|
-
claude: Object.freeze({ provider_id: 'anthropic', harness_id: 'claude', default_model: 'fable' }),
|
|
4
|
+
claude: Object.freeze({ provider_id: 'anthropic', harness_id: 'claude', default_model: 'claude-fable-5' }),
|
|
5
5
|
codex: Object.freeze({ provider_id: 'openai', harness_id: 'codex', default_model: 'gpt-5.6-sol' }),
|
|
6
6
|
grok: Object.freeze({ provider_id: 'xai', harness_id: 'grok', default_model: 'grok-4.6' }),
|
|
7
7
|
});
|
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,
|
|
6
|
+
import { WIZARD_BACK, stepLanguage, stepProjectType, stepProviderSelection, 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,147 @@ 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
|
-
|
|
101
|
-
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
+
// Editor rule files are a legacy programmatic integration. The interactive
|
|
76
|
+
// installer configures provider CLIs only, which are the actual runtimes.
|
|
77
|
+
const selectedEditors = options.editors || [];
|
|
78
|
+
let config;
|
|
79
|
+
let v2InstallationInput;
|
|
80
|
+
let stage = 'project';
|
|
81
|
+
|
|
82
|
+
const stageOrder = ['language', 'project', 'providers', 'mode', 'confirm'];
|
|
83
|
+
const optionKey = {
|
|
84
|
+
language: 'language',
|
|
85
|
+
project: 'projectType',
|
|
86
|
+
providers: 'providers',
|
|
87
|
+
mode: 'installationMode',
|
|
117
88
|
};
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
89
|
+
const previousInteractiveStage = (current) => {
|
|
90
|
+
for (let index = stageOrder.indexOf(current) - 1; index >= 0; index -= 1) {
|
|
91
|
+
const candidate = stageOrder[index];
|
|
92
|
+
if (candidate === 'language' ? options.language === undefined : options[optionKey[candidate]] === undefined) {
|
|
93
|
+
return candidate;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
while (stage !== 'complete') {
|
|
100
|
+
if (stage === 'language') {
|
|
101
|
+
language = await stepLanguage();
|
|
102
|
+
stage = 'project';
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (stage === 'project') {
|
|
107
|
+
const value = options.projectType !== undefined
|
|
108
|
+
? options.projectType
|
|
109
|
+
: await stepProjectType(targetDir, { allowBack: previousInteractiveStage('project') !== null });
|
|
110
|
+
if (value === WIZARD_BACK) {
|
|
111
|
+
stage = previousInteractiveStage('project');
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
projectType = value;
|
|
115
|
+
stage = 'providers';
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (stage === 'providers') {
|
|
120
|
+
const value = options.providers !== undefined
|
|
121
|
+
? options.providers
|
|
122
|
+
: await stepProviderSelection({ allowBack: previousInteractiveStage('providers') !== null });
|
|
123
|
+
if (value === WIZARD_BACK) {
|
|
124
|
+
stage = previousInteractiveStage('providers');
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
selectedProviders = value;
|
|
128
|
+
catalogResolution ??= options.signedCapabilityCatalogEnvelope
|
|
129
|
+
? { source: 'provided-signed', catalog: verifySignedCapabilityCatalog(options.signedCapabilityCatalogEnvelope, { publicKeyPem: options.catalogPublicKeyPem }) }
|
|
130
|
+
: await resolveCapabilityCatalog({ projectDir: targetDir, catalogUrl: options.catalogUrl, fetchImpl: options.catalogFetch });
|
|
131
|
+
// Provider selection defines the permitted routing pool. Model discovery
|
|
132
|
+
// and task-specific choice stay inside the control plane.
|
|
133
|
+
modelSelections = options.modelSelections;
|
|
134
|
+
stage = 'mode';
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (stage === 'mode') {
|
|
139
|
+
const value = options.installationMode !== undefined
|
|
140
|
+
? options.installationMode
|
|
141
|
+
: await stepInstallationMode({ allowBack: previousInteractiveStage('mode') !== null });
|
|
142
|
+
if (value === WIZARD_BACK) {
|
|
143
|
+
stage = previousInteractiveStage('mode');
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
installationMode = value;
|
|
147
|
+
if (installationMode === 'internal') {
|
|
148
|
+
try {
|
|
149
|
+
await requireLicenseEntitlement('internal', { validate: options.licenseValidator });
|
|
150
|
+
} catch (error) {
|
|
151
|
+
if (options.installationMode !== undefined) throw error;
|
|
152
|
+
p.log.error(error.message);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
stage = 'confirm';
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const providerToIDE = { claude: 'claude-code', gemini: 'gemini-cli', codex: 'codex-cli', grok: 'grok-cli' };
|
|
161
|
+
const selectedIDEs = options.ides || [
|
|
162
|
+
...selectedProviders.map(provider => providerToIDE[provider]).filter(Boolean),
|
|
163
|
+
...selectedEditors,
|
|
164
|
+
];
|
|
165
|
+
const cliProviders = selectedProviders;
|
|
166
|
+
const selectedMCPs = options.mcps || DEFAULT_MCPS;
|
|
167
|
+
const projectName = basename(targetDir);
|
|
168
|
+
config = {
|
|
169
|
+
projectName,
|
|
170
|
+
projectType,
|
|
171
|
+
language,
|
|
172
|
+
allProviders: cliProviders,
|
|
173
|
+
selectedIDEs,
|
|
174
|
+
selectedMCPs,
|
|
175
|
+
installationMode,
|
|
176
|
+
modelSelections,
|
|
177
|
+
targetDir,
|
|
178
|
+
version: VERSION,
|
|
179
|
+
};
|
|
180
|
+
v2InstallationInput = buildWizardV2InstallationInput({
|
|
181
|
+
projectName,
|
|
182
|
+
selectedProviders: cliProviders,
|
|
183
|
+
modelSelections,
|
|
184
|
+
capabilityCatalog: catalogResolution.catalog,
|
|
185
|
+
installationMode,
|
|
186
|
+
});
|
|
187
|
+
dryRunV2(v2InstallationInput, { projectDir: targetDir });
|
|
188
|
+
if (existsSync(join(targetDir, INSTALLATION_ARTIFACT_PATH)) && options.reconfigure !== true) {
|
|
189
|
+
throw Object.assign(new Error('a v2 installation already exists; use --reconfigure to replace it safely'), { code: 'INSTALLATION_ALREADY_EXISTS' });
|
|
190
|
+
}
|
|
191
|
+
const confirmation = await stepConfirmation(config, { allowBack: previousInteractiveStage('confirm') !== null });
|
|
192
|
+
if (confirmation === WIZARD_BACK) {
|
|
193
|
+
stage = previousInteractiveStage('confirm');
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
stage = 'complete';
|
|
131
197
|
}
|
|
132
198
|
|
|
133
|
-
|
|
199
|
+
const { selectedIDEs, selectedMCPs, allProviders: cliProviders } = config;
|
|
134
200
|
|
|
135
201
|
// Telemetry: enabled by default (opt-out model via ToS)
|
|
136
202
|
config.telemetryEnabled = options.telemetry !== undefined ? options.telemetry : true;
|
|
@@ -250,7 +316,15 @@ export async function runWizard(targetDir, options = {}) {
|
|
|
250
316
|
|
|
251
317
|
async function runLicenseActivationStep() {
|
|
252
318
|
const existingKey = getLicenseKey();
|
|
253
|
-
if (existingKey)
|
|
319
|
+
if (existingKey) {
|
|
320
|
+
try {
|
|
321
|
+
const status = await ensureCurrentMachineLicense({ key: existingKey });
|
|
322
|
+
if (status.status === 'VALID') return;
|
|
323
|
+
p.log.warn(`Saved license is not valid on this machine: ${status.reason || status.status}`);
|
|
324
|
+
} catch (error) {
|
|
325
|
+
p.log.warn(`Could not verify the saved license: ${error.message}`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
254
328
|
|
|
255
329
|
console.log('\n ┌─ License Activation ─────────────────────────────────────────┐');
|
|
256
330
|
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
|
/**
|
|
@@ -236,23 +244,19 @@ export async function stepIDESelection() {
|
|
|
236
244
|
*/
|
|
237
245
|
export async function stepModelSelection(providers, capabilityCatalog) {
|
|
238
246
|
const selections = {};
|
|
239
|
-
const summary = [];
|
|
240
247
|
|
|
241
248
|
for (const provider of providers) {
|
|
242
249
|
const models = wizardModelSuggestions(provider, capabilityCatalog);
|
|
243
250
|
selections[provider] = [...models];
|
|
244
|
-
summary.push(`${PROVIDER_DISPLAY_NAMES[provider] || provider}: ${models.join(', ')}`);
|
|
245
251
|
}
|
|
246
252
|
|
|
247
|
-
p.note(summary.join('\n'), t('installer.model_routing_label'));
|
|
248
|
-
|
|
249
253
|
return selections;
|
|
250
254
|
}
|
|
251
255
|
|
|
252
256
|
/**
|
|
253
257
|
* Step 4: Confirmation
|
|
254
258
|
*/
|
|
255
|
-
export async function stepConfirmation(config) {
|
|
259
|
+
export async function stepConfirmation(config, { allowBack = false } = {}) {
|
|
256
260
|
const { projectName, projectType, language, selectedMCPs, selectedIDEs, allProviders, installationMode } = config;
|
|
257
261
|
|
|
258
262
|
const langName = SUPPORTED_LANGUAGES.find(l => l.value === language)?.label || language;
|
|
@@ -274,7 +278,6 @@ export async function stepConfirmation(config) {
|
|
|
274
278
|
[t('installer.project_label')]: `${projectName} (${projectType === 'greenfield' ? 'Greenfield' : 'Brownfield'})`,
|
|
275
279
|
[t('installer.language_label')]: langName,
|
|
276
280
|
[t('installer.providers_label')]: providersDisplay,
|
|
277
|
-
[t('installer.model_routing_label')]: t('installer.model_routing_automatic'),
|
|
278
281
|
[t('installer.installation_mode_label')]: installationMode === 'internal'
|
|
279
282
|
? t('installer.installation_mode_internal')
|
|
280
283
|
: t('installer.installation_mode_open'),
|
|
@@ -305,10 +308,21 @@ export async function stepConfirmation(config) {
|
|
|
305
308
|
console.log();
|
|
306
309
|
console.log(` ${dim('Target:')} ${config.targetDir}`);
|
|
307
310
|
|
|
308
|
-
const proceed =
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
311
|
+
const proceed = allowBack
|
|
312
|
+
? await p.select({
|
|
313
|
+
message: t('installer.proceed'),
|
|
314
|
+
options: [
|
|
315
|
+
{ value: true, label: t('installer.install') },
|
|
316
|
+
backOption(),
|
|
317
|
+
],
|
|
318
|
+
initialValue: true,
|
|
319
|
+
})
|
|
320
|
+
: await p.confirm({
|
|
321
|
+
message: t('installer.proceed'),
|
|
322
|
+
initialValue: true,
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
if (proceed === WIZARD_BACK) return WIZARD_BACK;
|
|
312
326
|
|
|
313
327
|
if (p.isCancel(proceed) || !proceed) {
|
|
314
328
|
p.cancel('Installation cancelled.');
|