chati-dev 4.5.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/framework/config.yaml +2 -2
- package/framework/context/root.md +1 -1
- 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 +12 -12
- package/framework/manifest.sig +1 -1
- package/node_modules/@chati/provider-registry/src/index.js +21 -5
- package/package.json +1 -1
- package/src/installer/core.js +14 -13
- package/src/installer/provider-overlay.js +8 -15
- package/src/installer/templates.js +9 -22
- package/src/installer/validator.js +4 -9
- package/src/installer-v2/catalog-client.js +32 -8
- package/src/installer-v2/index.js +4 -1
- package/src/installer-v2/model-catalog-envelope.json +224 -5
- package/src/installer-v2/model-catalog.json +101 -4
- package/src/installer-v2/model-catalog.sig +1 -1
- package/src/installer-v2/wizard-installation.js +12 -11
- package/src/license/client.js +26 -0
- package/src/orchestrator/runtime-installation-v2.js +23 -4
- package/src/terminal/cli-registry.js +6 -5
- package/src/terminal/prompt-builder.js +2 -2
- package/src/utils/config-parser.js +3 -8
- package/src/wizard/i18n.js +8 -8
- package/src/wizard/index.js +20 -23
- package/src/wizard/questions.js +31 -66
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"catalog": {
|
|
3
|
-
"snapshot_id": "chati-model-catalog-2026-08-
|
|
4
|
-
"
|
|
3
|
+
"snapshot_id": "chati-model-catalog-2026-08-27",
|
|
4
|
+
"published_at": "2026-08-27T00:00:00.000Z",
|
|
5
|
+
"expires_at": "2026-11-25T00:00:00.000Z",
|
|
5
6
|
"models": [
|
|
6
7
|
{
|
|
7
8
|
"provider_id": "anthropic",
|
|
@@ -13,9 +14,87 @@
|
|
|
13
14
|
"review",
|
|
14
15
|
"adjudication"
|
|
15
16
|
],
|
|
17
|
+
"tier": "frontier",
|
|
18
|
+
"natural_role": "architecture and design",
|
|
19
|
+
"routing_priority": {
|
|
20
|
+
"discovery": 95,
|
|
21
|
+
"planning": 100,
|
|
22
|
+
"build": 45,
|
|
23
|
+
"review": 90,
|
|
24
|
+
"adjudication": 95,
|
|
25
|
+
"architect": 100,
|
|
26
|
+
"detail": 100,
|
|
27
|
+
"ux": 100
|
|
28
|
+
},
|
|
29
|
+
"adjudication_priority": 95,
|
|
30
|
+
"highest_reasoning_configuration": "xhigh"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"provider_id": "anthropic",
|
|
34
|
+
"model_id": "claude-opus-4-8",
|
|
35
|
+
"actions": [
|
|
36
|
+
"discovery",
|
|
37
|
+
"planning",
|
|
38
|
+
"build",
|
|
39
|
+
"review",
|
|
40
|
+
"adjudication"
|
|
41
|
+
],
|
|
42
|
+
"tier": "frontier",
|
|
43
|
+
"natural_role": "quality rules and judgment-heavy work",
|
|
44
|
+
"routing_priority": {
|
|
45
|
+
"discovery": 90,
|
|
46
|
+
"planning": 95,
|
|
47
|
+
"build": 75,
|
|
48
|
+
"review": 95,
|
|
49
|
+
"adjudication": 100,
|
|
50
|
+
"qa-planning": 97,
|
|
51
|
+
"qa-implementation": 97
|
|
52
|
+
},
|
|
16
53
|
"adjudication_priority": 100,
|
|
17
54
|
"highest_reasoning_configuration": "xhigh"
|
|
18
55
|
},
|
|
56
|
+
{
|
|
57
|
+
"provider_id": "anthropic",
|
|
58
|
+
"model_id": "claude-sonnet-5",
|
|
59
|
+
"actions": [
|
|
60
|
+
"discovery",
|
|
61
|
+
"planning",
|
|
62
|
+
"build",
|
|
63
|
+
"review"
|
|
64
|
+
],
|
|
65
|
+
"tier": "workhorse",
|
|
66
|
+
"natural_role": "daily implementation and planning craft",
|
|
67
|
+
"routing_priority": {
|
|
68
|
+
"discovery": 85,
|
|
69
|
+
"planning": 88,
|
|
70
|
+
"build": 98,
|
|
71
|
+
"review": 80,
|
|
72
|
+
"brief": 95,
|
|
73
|
+
"phases": 95,
|
|
74
|
+
"tasks": 95,
|
|
75
|
+
"dev": 98
|
|
76
|
+
},
|
|
77
|
+
"adjudication_priority": 60
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"provider_id": "anthropic",
|
|
81
|
+
"model_id": "claude-haiku-4-5",
|
|
82
|
+
"actions": [
|
|
83
|
+
"discovery",
|
|
84
|
+
"planning",
|
|
85
|
+
"build",
|
|
86
|
+
"review"
|
|
87
|
+
],
|
|
88
|
+
"tier": "worker",
|
|
89
|
+
"natural_role": "small parallel workers and structured transforms",
|
|
90
|
+
"routing_priority": {
|
|
91
|
+
"discovery": 55,
|
|
92
|
+
"planning": 45,
|
|
93
|
+
"build": 65,
|
|
94
|
+
"review": 40
|
|
95
|
+
},
|
|
96
|
+
"adjudication_priority": 20
|
|
97
|
+
},
|
|
19
98
|
{
|
|
20
99
|
"provider_id": "openai",
|
|
21
100
|
"model_id": "gpt-5.6-sol",
|
|
@@ -26,9 +105,79 @@
|
|
|
26
105
|
"review",
|
|
27
106
|
"adjudication"
|
|
28
107
|
],
|
|
108
|
+
"tier": "frontier",
|
|
109
|
+
"natural_role": "independent review and long reliable sessions",
|
|
110
|
+
"routing_priority": {
|
|
111
|
+
"discovery": 90,
|
|
112
|
+
"planning": 93,
|
|
113
|
+
"build": 85,
|
|
114
|
+
"review": 100,
|
|
115
|
+
"adjudication": 100,
|
|
116
|
+
"qa-planning": 100,
|
|
117
|
+
"qa-implementation": 100,
|
|
118
|
+
"qa-visual": 100
|
|
119
|
+
},
|
|
29
120
|
"adjudication_priority": 100,
|
|
30
121
|
"highest_reasoning_configuration": "xhigh"
|
|
31
122
|
},
|
|
123
|
+
{
|
|
124
|
+
"provider_id": "openai",
|
|
125
|
+
"model_id": "terra",
|
|
126
|
+
"actions": [
|
|
127
|
+
"discovery",
|
|
128
|
+
"planning",
|
|
129
|
+
"build",
|
|
130
|
+
"review",
|
|
131
|
+
"adjudication"
|
|
132
|
+
],
|
|
133
|
+
"tier": "workhorse",
|
|
134
|
+
"natural_role": "scoped implementation and efficient review",
|
|
135
|
+
"routing_priority": {
|
|
136
|
+
"discovery": 80,
|
|
137
|
+
"planning": 85,
|
|
138
|
+
"build": 100,
|
|
139
|
+
"review": 92,
|
|
140
|
+
"adjudication": 75,
|
|
141
|
+
"dev": 100,
|
|
142
|
+
"devops": 100
|
|
143
|
+
},
|
|
144
|
+
"adjudication_priority": 75,
|
|
145
|
+
"highest_reasoning_configuration": "xhigh"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"provider_id": "openai",
|
|
149
|
+
"model_id": "luna",
|
|
150
|
+
"actions": [
|
|
151
|
+
"discovery",
|
|
152
|
+
"planning",
|
|
153
|
+
"build",
|
|
154
|
+
"review"
|
|
155
|
+
],
|
|
156
|
+
"tier": "worker",
|
|
157
|
+
"natural_role": "low-cost workers and routine tasks",
|
|
158
|
+
"routing_priority": {
|
|
159
|
+
"discovery": 60,
|
|
160
|
+
"planning": 55,
|
|
161
|
+
"build": 72,
|
|
162
|
+
"review": 60
|
|
163
|
+
},
|
|
164
|
+
"adjudication_priority": 30
|
|
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
|
+
},
|
|
32
181
|
{
|
|
33
182
|
"provider_id": "xai",
|
|
34
183
|
"model_id": "grok-4.6",
|
|
@@ -39,21 +188,91 @@
|
|
|
39
188
|
"review",
|
|
40
189
|
"adjudication"
|
|
41
190
|
],
|
|
42
|
-
"
|
|
191
|
+
"tier": "frontier",
|
|
192
|
+
"natural_role": "high-reasoning escalation and fast execution",
|
|
193
|
+
"routing_priority": {
|
|
194
|
+
"discovery": 88,
|
|
195
|
+
"planning": 92,
|
|
196
|
+
"build": 94,
|
|
197
|
+
"review": 90,
|
|
198
|
+
"adjudication": 92,
|
|
199
|
+
"architect": 94
|
|
200
|
+
},
|
|
201
|
+
"adjudication_priority": 92,
|
|
43
202
|
"highest_reasoning_configuration": "xhigh"
|
|
44
203
|
},
|
|
45
204
|
{
|
|
46
205
|
"provider_id": "xai",
|
|
47
206
|
"model_id": "grok-4.5",
|
|
207
|
+
"actions": [
|
|
208
|
+
"discovery",
|
|
209
|
+
"planning",
|
|
210
|
+
"build",
|
|
211
|
+
"review",
|
|
212
|
+
"adjudication"
|
|
213
|
+
],
|
|
214
|
+
"tier": "workhorse",
|
|
215
|
+
"natural_role": "volume waves and speed-first builds",
|
|
216
|
+
"routing_priority": {
|
|
217
|
+
"discovery": 82,
|
|
218
|
+
"planning": 84,
|
|
219
|
+
"build": 98,
|
|
220
|
+
"review": 82,
|
|
221
|
+
"adjudication": 70,
|
|
222
|
+
"dev": 98
|
|
223
|
+
},
|
|
224
|
+
"adjudication_priority": 70,
|
|
225
|
+
"highest_reasoning_configuration": "xhigh"
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
"provider_id": "xai",
|
|
229
|
+
"model_id": "grok-4.3",
|
|
48
230
|
"actions": [
|
|
49
231
|
"discovery",
|
|
50
232
|
"planning",
|
|
51
233
|
"build",
|
|
52
234
|
"review"
|
|
53
235
|
],
|
|
54
|
-
"
|
|
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
|
|
55
274
|
}
|
|
56
275
|
]
|
|
57
276
|
},
|
|
58
|
-
"signature": "
|
|
277
|
+
"signature": "rNiDCOiVFtrfGUrQWXw3dqR1cYAh/xZElyt0AfLXjhgykWzcw4o0NygK0ciHNXMDwhJUqhsp5fKIPpwli/YdDA=="
|
|
59
278
|
}
|
|
@@ -1,33 +1,130 @@
|
|
|
1
1
|
{
|
|
2
|
-
"snapshot_id": "chati-model-catalog-2026-08-
|
|
3
|
-
"
|
|
2
|
+
"snapshot_id": "chati-model-catalog-2026-08-27",
|
|
3
|
+
"published_at": "2026-08-27T00:00:00.000Z",
|
|
4
|
+
"expires_at": "2026-11-25T00:00:00.000Z",
|
|
4
5
|
"models": [
|
|
5
6
|
{
|
|
6
7
|
"provider_id": "anthropic",
|
|
7
8
|
"model_id": "fable",
|
|
8
9
|
"actions": ["discovery", "planning", "build", "review", "adjudication"],
|
|
10
|
+
"tier": "frontier",
|
|
11
|
+
"natural_role": "architecture and design",
|
|
12
|
+
"routing_priority": { "discovery": 95, "planning": 100, "build": 45, "review": 90, "adjudication": 95, "architect": 100, "detail": 100, "ux": 100 },
|
|
13
|
+
"adjudication_priority": 95,
|
|
14
|
+
"highest_reasoning_configuration": "xhigh"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"provider_id": "anthropic",
|
|
18
|
+
"model_id": "claude-opus-4-8",
|
|
19
|
+
"actions": ["discovery", "planning", "build", "review", "adjudication"],
|
|
20
|
+
"tier": "frontier",
|
|
21
|
+
"natural_role": "quality rules and judgment-heavy work",
|
|
22
|
+
"routing_priority": { "discovery": 90, "planning": 95, "build": 75, "review": 95, "adjudication": 100, "qa-planning": 97, "qa-implementation": 97 },
|
|
9
23
|
"adjudication_priority": 100,
|
|
10
24
|
"highest_reasoning_configuration": "xhigh"
|
|
11
25
|
},
|
|
26
|
+
{
|
|
27
|
+
"provider_id": "anthropic",
|
|
28
|
+
"model_id": "claude-sonnet-5",
|
|
29
|
+
"actions": ["discovery", "planning", "build", "review"],
|
|
30
|
+
"tier": "workhorse",
|
|
31
|
+
"natural_role": "daily implementation and planning craft",
|
|
32
|
+
"routing_priority": { "discovery": 85, "planning": 88, "build": 98, "review": 80, "brief": 95, "phases": 95, "tasks": 95, "dev": 98 },
|
|
33
|
+
"adjudication_priority": 60
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"provider_id": "anthropic",
|
|
37
|
+
"model_id": "claude-haiku-4-5",
|
|
38
|
+
"actions": ["discovery", "planning", "build", "review"],
|
|
39
|
+
"tier": "worker",
|
|
40
|
+
"natural_role": "small parallel workers and structured transforms",
|
|
41
|
+
"routing_priority": { "discovery": 55, "planning": 45, "build": 65, "review": 40 },
|
|
42
|
+
"adjudication_priority": 20
|
|
43
|
+
},
|
|
12
44
|
{
|
|
13
45
|
"provider_id": "openai",
|
|
14
46
|
"model_id": "gpt-5.6-sol",
|
|
15
47
|
"actions": ["discovery", "planning", "build", "review", "adjudication"],
|
|
48
|
+
"tier": "frontier",
|
|
49
|
+
"natural_role": "independent review and long reliable sessions",
|
|
50
|
+
"routing_priority": { "discovery": 90, "planning": 93, "build": 85, "review": 100, "adjudication": 100, "qa-planning": 100, "qa-implementation": 100, "qa-visual": 100 },
|
|
16
51
|
"adjudication_priority": 100,
|
|
17
52
|
"highest_reasoning_configuration": "xhigh"
|
|
18
53
|
},
|
|
54
|
+
{
|
|
55
|
+
"provider_id": "openai",
|
|
56
|
+
"model_id": "terra",
|
|
57
|
+
"actions": ["discovery", "planning", "build", "review", "adjudication"],
|
|
58
|
+
"tier": "workhorse",
|
|
59
|
+
"natural_role": "scoped implementation and efficient review",
|
|
60
|
+
"routing_priority": { "discovery": 80, "planning": 85, "build": 100, "review": 92, "adjudication": 75, "dev": 100, "devops": 100 },
|
|
61
|
+
"adjudication_priority": 75,
|
|
62
|
+
"highest_reasoning_configuration": "xhigh"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"provider_id": "openai",
|
|
66
|
+
"model_id": "luna",
|
|
67
|
+
"actions": ["discovery", "planning", "build", "review"],
|
|
68
|
+
"tier": "worker",
|
|
69
|
+
"natural_role": "low-cost workers and routine tasks",
|
|
70
|
+
"routing_priority": { "discovery": 60, "planning": 55, "build": 72, "review": 60 },
|
|
71
|
+
"adjudication_priority": 30
|
|
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
|
+
},
|
|
19
82
|
{
|
|
20
83
|
"provider_id": "xai",
|
|
21
84
|
"model_id": "grok-4.6",
|
|
22
85
|
"actions": ["discovery", "planning", "build", "review", "adjudication"],
|
|
23
|
-
"
|
|
86
|
+
"tier": "frontier",
|
|
87
|
+
"natural_role": "high-reasoning escalation and fast execution",
|
|
88
|
+
"routing_priority": { "discovery": 88, "planning": 92, "build": 94, "review": 90, "adjudication": 92, "architect": 94 },
|
|
89
|
+
"adjudication_priority": 92,
|
|
24
90
|
"highest_reasoning_configuration": "xhigh"
|
|
25
91
|
},
|
|
26
92
|
{
|
|
27
93
|
"provider_id": "xai",
|
|
28
94
|
"model_id": "grok-4.5",
|
|
95
|
+
"actions": ["discovery", "planning", "build", "review", "adjudication"],
|
|
96
|
+
"tier": "workhorse",
|
|
97
|
+
"natural_role": "volume waves and speed-first builds",
|
|
98
|
+
"routing_priority": { "discovery": 82, "planning": 84, "build": 98, "review": 82, "adjudication": 70, "dev": 98 },
|
|
99
|
+
"adjudication_priority": 70,
|
|
100
|
+
"highest_reasoning_configuration": "xhigh"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"provider_id": "xai",
|
|
104
|
+
"model_id": "grok-4.3",
|
|
29
105
|
"actions": ["discovery", "planning", "build", "review"],
|
|
30
|
-
"
|
|
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
|
|
31
128
|
}
|
|
32
129
|
]
|
|
33
130
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
rNiDCOiVFtrfGUrQWXw3dqR1cYAh/xZElyt0AfLXjhgykWzcw4o0NygK0ciHNXMDwhJUqhsp5fKIPpwli/YdDA==
|
|
@@ -22,9 +22,11 @@ function fail(code, message) {
|
|
|
22
22
|
throw error;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
function normalizeModels(provider, selections) {
|
|
25
|
+
function normalizeModels(provider, selections, capabilityCatalog) {
|
|
26
26
|
const value = selections?.[provider];
|
|
27
|
-
const values = value === undefined
|
|
27
|
+
const values = value === undefined
|
|
28
|
+
? wizardModelSuggestions(provider, capabilityCatalog)
|
|
29
|
+
: (Array.isArray(value) ? value : [value]);
|
|
28
30
|
const models = [...new Set(values.map((model) => typeof model === 'string' ? model.trim() : '').filter(Boolean))];
|
|
29
31
|
if (models.length === 0) fail('WIZARD_MODEL_REQUIRED', `${provider} requires at least one selected model`);
|
|
30
32
|
return models;
|
|
@@ -48,17 +50,16 @@ export function wizardModelSuggestions(provider, capabilityCatalog) {
|
|
|
48
50
|
export function buildWizardV2InstallationInput({
|
|
49
51
|
projectName,
|
|
50
52
|
selectedProviders,
|
|
51
|
-
primaryProvider,
|
|
52
53
|
modelSelections = {},
|
|
53
54
|
capabilityCatalog,
|
|
54
|
-
|
|
55
|
+
installationMode = 'open',
|
|
55
56
|
clock = () => new Date(),
|
|
56
57
|
} = {}) {
|
|
57
58
|
if (typeof projectName !== 'string' || !projectName.trim()) fail('WIZARD_PROJECT_REQUIRED', 'projectName is required');
|
|
58
59
|
if (!Array.isArray(selectedProviders) || selectedProviders.length === 0) fail('WIZARD_PROVIDER_REQUIRED', 'at least one v2 provider is required');
|
|
60
|
+
if (!['open', 'internal'].includes(installationMode)) fail('WIZARD_INSTALLATION_MODE_INVALID', 'installationMode must be open or internal');
|
|
59
61
|
const providers = [...new Set(selectedProviders)];
|
|
60
62
|
for (const provider of providers) if (!PROVIDER_BINDINGS[provider]) fail('V2_PROVIDER_UNSUPPORTED', `${provider} is not supported by v2`);
|
|
61
|
-
if (!providers.includes(primaryProvider)) fail('WIZARD_PRIMARY_PROVIDER_REQUIRED', 'primaryProvider must be selected');
|
|
62
63
|
const now = clock();
|
|
63
64
|
const issuedAt = (now instanceof Date ? now : new Date(now));
|
|
64
65
|
if (Number.isNaN(issuedAt.getTime())) fail('WIZARD_CLOCK_INVALID', 'clock must return a valid time');
|
|
@@ -74,11 +75,10 @@ export function buildWizardV2InstallationInput({
|
|
|
74
75
|
return {
|
|
75
76
|
provider_id: binding.provider_id,
|
|
76
77
|
harness_id: binding.harness_id,
|
|
77
|
-
allowed_models: normalizeModels(provider, modelSelections),
|
|
78
|
+
allowed_models: normalizeModels(provider, modelSelections, capabilityCatalog),
|
|
78
79
|
allowed_reasoning_configurations: ['low', 'medium', 'high', 'xhigh'],
|
|
79
80
|
};
|
|
80
81
|
});
|
|
81
|
-
const primary = PROVIDER_BINDINGS[primaryProvider];
|
|
82
82
|
const models = enabled_providers.flatMap((binding) => binding.allowed_models.map((model_id) => {
|
|
83
83
|
const catalogModel = capabilityCatalog?.models?.find((candidate) => candidate.provider_id === binding.provider_id && candidate.model_id === model_id);
|
|
84
84
|
if (capabilityCatalog && !catalogModel) fail('WIZARD_MODEL_NOT_IN_CATALOG', `${model_id} is not in the signed catalog for ${binding.provider_id}`);
|
|
@@ -86,6 +86,9 @@ export function buildWizardV2InstallationInput({
|
|
|
86
86
|
provider_id: binding.provider_id,
|
|
87
87
|
model_id,
|
|
88
88
|
actions: catalogModel?.actions || V2_ACTIONS,
|
|
89
|
+
...(catalogModel?.routing_priority !== undefined ? { routing_priority: catalogModel.routing_priority } : {}),
|
|
90
|
+
...(catalogModel?.tier !== undefined ? { tier: catalogModel.tier } : {}),
|
|
91
|
+
...(catalogModel?.natural_role !== undefined ? { natural_role: catalogModel.natural_role } : {}),
|
|
89
92
|
...(catalogModel?.adjudication_priority !== undefined ? { adjudication_priority: catalogModel.adjudication_priority } : {}),
|
|
90
93
|
...(catalogModel?.highest_reasoning_configuration !== undefined
|
|
91
94
|
? { highest_reasoning_configuration: catalogModel.highest_reasoning_configuration }
|
|
@@ -97,13 +100,11 @@ export function buildWizardV2InstallationInput({
|
|
|
97
100
|
const projectSlug = projectName.trim().toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '') || 'project';
|
|
98
101
|
const installation = {
|
|
99
102
|
installation_id: `wizard-${projectSlug}`,
|
|
100
|
-
profile,
|
|
101
|
-
primary_harness: primary.harness_id,
|
|
102
|
-
primary_binding: { provider_id: primary.provider_id, harness_id: primary.harness_id },
|
|
103
|
+
profile: installationMode === 'internal' ? 'focus-ai-internal' : 'other-supported-profile',
|
|
103
104
|
enabled_providers,
|
|
104
105
|
capability_snapshot_ref: snapshotId,
|
|
105
106
|
policy_ref: `policy://installation/${snapshotId}`,
|
|
106
|
-
...(
|
|
107
|
+
...(installationMode === 'internal' ? { external_integrations: { clickup: 'required' } } : {}),
|
|
107
108
|
};
|
|
108
109
|
return Object.freeze({
|
|
109
110
|
project_id: `project-${projectSlug}`,
|
package/src/license/client.js
CHANGED
|
@@ -37,6 +37,11 @@ function writeGlobal(data) {
|
|
|
37
37
|
try { chmodSync(path, 0o600); } catch { /* non-POSIX FS — skip silently */ }
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
function normalizeEntitlements(value) {
|
|
41
|
+
if (!Array.isArray(value)) return [];
|
|
42
|
+
return [...new Set(value.filter((item) => typeof item === 'string' && item.trim()).map((item) => item.trim()))];
|
|
43
|
+
}
|
|
44
|
+
|
|
40
45
|
// ---------------------------------------------------------------------------
|
|
41
46
|
// Key helpers
|
|
42
47
|
// ---------------------------------------------------------------------------
|
|
@@ -96,6 +101,7 @@ export async function activateLicense(_projectDir, key) {
|
|
|
96
101
|
plan: data.plan ?? 'trial',
|
|
97
102
|
days_remaining: data.days_remaining ?? null,
|
|
98
103
|
expires_at: data.expires_at ?? null,
|
|
104
|
+
entitlements: normalizeEntitlements(data.entitlements),
|
|
99
105
|
checked_at: new Date().toISOString(),
|
|
100
106
|
});
|
|
101
107
|
|
|
@@ -123,6 +129,7 @@ export async function validateLicense(_projectDir) {
|
|
|
123
129
|
days_remaining: data.days_remaining ?? null,
|
|
124
130
|
expires_at: data.expires_at ?? null,
|
|
125
131
|
reason: data.reason ?? null,
|
|
132
|
+
entitlements: normalizeEntitlements(data.entitlements),
|
|
126
133
|
checked_at: new Date().toISOString(),
|
|
127
134
|
};
|
|
128
135
|
|
|
@@ -130,6 +137,25 @@ export async function validateLicense(_projectDir) {
|
|
|
130
137
|
return result;
|
|
131
138
|
}
|
|
132
139
|
|
|
140
|
+
export function hasLicenseEntitlement(status, entitlement) {
|
|
141
|
+
return status?.status === 'VALID' && normalizeEntitlements(status.entitlements).includes(entitlement);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Refreshes the server-authoritative license status and requires one
|
|
146
|
+
* entitlement before an internal installation can proceed.
|
|
147
|
+
*/
|
|
148
|
+
export async function requireLicenseEntitlement(entitlement, { validate = validateLicense } = {}) {
|
|
149
|
+
const status = await validate(null);
|
|
150
|
+
if (!hasLicenseEntitlement(status, entitlement)) {
|
|
151
|
+
throw Object.assign(new Error(`The active license is not authorized for ${entitlement} mode.`), {
|
|
152
|
+
code: 'LICENSE_ENTITLEMENT_REQUIRED',
|
|
153
|
+
entitlement,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
return status;
|
|
157
|
+
}
|
|
158
|
+
|
|
133
159
|
/**
|
|
134
160
|
* Remove license locally and deactivate machine slot on server (best-effort).
|
|
135
161
|
* Fails silently if API is unreachable.
|
|
@@ -25,10 +25,29 @@ export function loadRuntimeInstallationV2(projectDir, { clock = () => new Date()
|
|
|
25
25
|
export function resolveRuntimeInvocationV2({ artifact, agent, binding, model_id, reasoning_configuration, clock = () => new Date() }) {
|
|
26
26
|
const action = AGENT_ACTIONS[agent];
|
|
27
27
|
if (!action) throw Object.assign(new Error(`No v2 action mapping for agent ${agent}`), { code: 'UNMAPPED_AGENT_ACTION' });
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
.
|
|
31
|
-
|
|
28
|
+
const candidates = artifact.installation.enabled_providers.flatMap((candidateBinding) => {
|
|
29
|
+
if (binding && (candidateBinding.provider_id !== binding.provider_id || candidateBinding.harness_id !== binding.harness_id)) return [];
|
|
30
|
+
return candidateBinding.allowed_models.flatMap((candidateModelId) => {
|
|
31
|
+
if (model_id && candidateModelId !== model_id) return [];
|
|
32
|
+
const catalogModel = artifact.capability_snapshot.models.find((candidate) =>
|
|
33
|
+
candidate.provider_id === candidateBinding.provider_id && candidate.model_id === candidateModelId
|
|
34
|
+
);
|
|
35
|
+
if (!catalogModel?.actions.includes(action)) return [];
|
|
36
|
+
return [{
|
|
37
|
+
binding: candidateBinding,
|
|
38
|
+
model: catalogModel,
|
|
39
|
+
priority: catalogModel.routing_priority?.[agent] ?? catalogModel.routing_priority?.[action] ?? 0,
|
|
40
|
+
}];
|
|
41
|
+
});
|
|
42
|
+
}).sort((left, right) =>
|
|
43
|
+
right.priority - left.priority
|
|
44
|
+
|| (right.model.adjudication_priority ?? 0) - (left.model.adjudication_priority ?? 0)
|
|
45
|
+
|| `${left.binding.harness_id}:${left.model.model_id}`.localeCompare(`${right.binding.harness_id}:${right.model.model_id}`)
|
|
46
|
+
);
|
|
47
|
+
const selectedCandidate = candidates[0];
|
|
48
|
+
if (!selectedCandidate) throw Object.assign(new Error(`No eligible installed model for ${agent}/${action}`), { code: 'NO_ELIGIBLE_MODEL' });
|
|
49
|
+
const selected = selectedCandidate.binding;
|
|
50
|
+
const model = selectedCandidate.model.model_id;
|
|
32
51
|
const invocation = {
|
|
33
52
|
provider_id: selected.provider_id, harness_id: selected.harness_id, action,
|
|
34
53
|
model_pin: { model_id: model, catalog_snapshot_ref: artifact.capability_snapshot.snapshot_id, reasoning_configuration },
|
|
@@ -131,14 +131,14 @@ export function loadEnabledProviders(projectDir) {
|
|
|
131
131
|
|
|
132
132
|
// Filter out invalid provider names (typos in config.yaml)
|
|
133
133
|
const validEnabled = enabled.filter(name => validNames.includes(name));
|
|
134
|
-
const validPrimary = validNames.includes(primary) ? primary :
|
|
134
|
+
const validPrimary = validNames.includes(primary) ? primary : validEnabled[0] || null;
|
|
135
135
|
|
|
136
136
|
return { primary: validPrimary, enabled: validEnabled };
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
/**
|
|
140
140
|
* Resolve which provider should be used for a given agent.
|
|
141
|
-
* Priority: agent_overrides > agent default >
|
|
141
|
+
* Priority: agent_overrides > agent default > first enabled legacy fallback.
|
|
142
142
|
*
|
|
143
143
|
* @param {string} agent - Agent name
|
|
144
144
|
* @param {string} projectDir - Project root directory
|
|
@@ -166,10 +166,11 @@ export function resolveProviderForAgent(agent, projectDir, agentModels) {
|
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
//
|
|
170
|
-
const
|
|
169
|
+
// Legacy fallback only. Installation v2 routes from the signed task catalog.
|
|
170
|
+
const fallbackProvider = primary || enabled[0];
|
|
171
|
+
const provider = PROVIDERS[fallbackProvider];
|
|
171
172
|
const defaultModel = provider ? Object.keys(provider.modelMap)[0] : 'sonnet';
|
|
172
|
-
return { provider:
|
|
173
|
+
return { provider: fallbackProvider, model: defaultModel };
|
|
173
174
|
}
|
|
174
175
|
|
|
175
176
|
/**
|
|
@@ -281,14 +281,14 @@ function buildPrismSection(config) {
|
|
|
281
281
|
|
|
282
282
|
/**
|
|
283
283
|
* Load the agent's full .md definition file.
|
|
284
|
-
* For
|
|
284
|
+
* For enabled providers, resolves via the provider-specific overlay directory.
|
|
285
285
|
*/
|
|
286
286
|
function loadAgentDefinition(agent, projectDir, provider = null) {
|
|
287
287
|
const relToFramework = AGENT_FILE_PATHS[agent];
|
|
288
288
|
if (!relToFramework) return null;
|
|
289
289
|
|
|
290
290
|
let fullPath;
|
|
291
|
-
if (provider
|
|
291
|
+
if (provider) {
|
|
292
292
|
fullPath = resolveOverlayPath(projectDir, relToFramework, provider);
|
|
293
293
|
} else {
|
|
294
294
|
fullPath = join(projectDir, resolveFrameworkDir(projectDir), relToFramework);
|
|
@@ -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
|
|