chati-dev 4.4.1 → 4.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +29 -27
  2. package/bin/chati.js +235 -1
  3. package/framework/agents/plan/tasks.md +46 -1
  4. package/framework/config.yaml +2 -2
  5. package/framework/constitution.md +13 -16
  6. package/framework/context/governance.md +5 -5
  7. package/framework/context/root.md +5 -5
  8. package/framework/i18n/en.yaml +8 -2
  9. package/framework/i18n/es.yaml +8 -2
  10. package/framework/i18n/fr.yaml +8 -2
  11. package/framework/i18n/pt.yaml +8 -2
  12. package/framework/manifest.json +21 -21
  13. package/framework/manifest.sig +1 -1
  14. package/framework/orchestrator/chati.md +43 -12
  15. package/node_modules/@chati/browser-capability/README.md +10 -0
  16. package/node_modules/@chati/browser-capability/package.json +17 -0
  17. package/node_modules/@chati/browser-capability/src/index.js +165 -0
  18. package/node_modules/@chati/core/package.json +13 -0
  19. package/node_modules/@chati/core/src/index.js +111 -0
  20. package/node_modules/@chati/knowledge-context/package.json +17 -0
  21. package/node_modules/@chati/knowledge-context/src/index.js +202 -0
  22. package/node_modules/@chati/planning/package.json +17 -0
  23. package/node_modules/@chati/planning/src/index.js +367 -0
  24. package/node_modules/@chati/provider-registry/package.json +16 -0
  25. package/node_modules/@chati/provider-registry/src/index.js +148 -0
  26. package/node_modules/@chati/rail/README.md +24 -0
  27. package/node_modules/@chati/rail/package.json +19 -0
  28. package/node_modules/@chati/rail/src/index.js +437 -0
  29. package/node_modules/@chati/release-lane/README.md +24 -0
  30. package/node_modules/@chati/release-lane/package.json +17 -0
  31. package/node_modules/@chati/release-lane/src/index.js +172 -0
  32. package/node_modules/@chati/review-council/package.json +17 -0
  33. package/node_modules/@chati/review-council/src/index.js +264 -0
  34. package/node_modules/@chati/tracking-clickup/README.md +55 -0
  35. package/node_modules/@chati/tracking-clickup/package.json +17 -0
  36. package/node_modules/@chati/tracking-clickup/src/index.js +293 -0
  37. package/package.json +25 -3
  38. package/src/config/ide-configs.js +11 -0
  39. package/src/context/domain-loader.js +1 -1
  40. package/src/dashboard/data-reader.js +1 -1
  41. package/src/executors/runner.js +1 -1
  42. package/src/installer/core.js +14 -13
  43. package/src/installer/provider-overlay.js +8 -15
  44. package/src/installer/scaffold-applier.js +1 -1
  45. package/src/installer/templates.js +12 -25
  46. package/src/installer/validator.js +5 -10
  47. package/src/installer-v2/catalog-client.js +165 -0
  48. package/src/installer-v2/index.js +304 -0
  49. package/src/installer-v2/model-catalog-envelope.json +278 -0
  50. package/src/installer-v2/model-catalog.json +130 -0
  51. package/src/installer-v2/model-catalog.sig +1 -0
  52. package/src/installer-v2/wizard-installation.js +116 -0
  53. package/src/intelligence/registry-manager.js +1 -1
  54. package/src/license/client.js +27 -1
  55. package/src/memory/session-digest.js +1 -1
  56. package/src/merger/yaml-merger.js +1 -1
  57. package/src/orchestrator/browser-runtime.js +25 -0
  58. package/src/orchestrator/cli.js +93 -8
  59. package/src/orchestrator/clickup-projection.js +84 -0
  60. package/src/orchestrator/clickup-runtime.js +13 -0
  61. package/src/orchestrator/knowledge-runtime.js +64 -0
  62. package/src/orchestrator/planning-runtime.js +127 -0
  63. package/src/orchestrator/rail-runtime.js +421 -0
  64. package/src/orchestrator/release-runtime.js +14 -0
  65. package/src/orchestrator/review-runtime.js +74 -0
  66. package/src/orchestrator/runtime-installation-v2.js +57 -0
  67. package/src/orchestrator/session-manager.js +1 -1
  68. package/src/telemetry/config.js +1 -1
  69. package/src/terminal/adapters/grok-adapter.js +16 -0
  70. package/src/terminal/adapters/index.js +1 -0
  71. package/src/terminal/cli-registry.js +20 -5
  72. package/src/terminal/prompt-builder.js +4 -2
  73. package/src/terminal/run-agent.js +3 -0
  74. package/src/terminal/run-parallel.js +21 -10
  75. package/src/terminal/spawner.js +7 -1
  76. package/src/terminal/team-task-list.js +1 -1
  77. package/src/upgrade/checker.js +1 -1
  78. package/src/upgrade/migrator.js +1 -1
  79. package/src/utils/config-parser.js +3 -8
  80. package/src/wizard/i18n.js +10 -4
  81. package/src/wizard/index.js +49 -17
  82. package/src/wizard/questions.js +50 -28
@@ -0,0 +1,278 @@
1
+ {
2
+ "catalog": {
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",
6
+ "models": [
7
+ {
8
+ "provider_id": "anthropic",
9
+ "model_id": "fable",
10
+ "actions": [
11
+ "discovery",
12
+ "planning",
13
+ "build",
14
+ "review",
15
+ "adjudication"
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
+ },
53
+ "adjudication_priority": 100,
54
+ "highest_reasoning_configuration": "xhigh"
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
+ },
98
+ {
99
+ "provider_id": "openai",
100
+ "model_id": "gpt-5.6-sol",
101
+ "actions": [
102
+ "discovery",
103
+ "planning",
104
+ "build",
105
+ "review",
106
+ "adjudication"
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
+ },
120
+ "adjudication_priority": 100,
121
+ "highest_reasoning_configuration": "xhigh"
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
+ },
181
+ {
182
+ "provider_id": "xai",
183
+ "model_id": "grok-4.6",
184
+ "actions": [
185
+ "discovery",
186
+ "planning",
187
+ "build",
188
+ "review",
189
+ "adjudication"
190
+ ],
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,
202
+ "highest_reasoning_configuration": "xhigh"
203
+ },
204
+ {
205
+ "provider_id": "xai",
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",
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
+ }
275
+ ]
276
+ },
277
+ "signature": "rNiDCOiVFtrfGUrQWXw3dqR1cYAh/xZElyt0AfLXjhgykWzcw4o0NygK0ciHNXMDwhJUqhsp5fKIPpwli/YdDA=="
278
+ }
@@ -0,0 +1,130 @@
1
+ {
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",
5
+ "models": [
6
+ {
7
+ "provider_id": "anthropic",
8
+ "model_id": "fable",
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 },
23
+ "adjudication_priority": 100,
24
+ "highest_reasoning_configuration": "xhigh"
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
+ },
44
+ {
45
+ "provider_id": "openai",
46
+ "model_id": "gpt-5.6-sol",
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 },
51
+ "adjudication_priority": 100,
52
+ "highest_reasoning_configuration": "xhigh"
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
+ },
82
+ {
83
+ "provider_id": "xai",
84
+ "model_id": "grok-4.6",
85
+ "actions": ["discovery", "planning", "build", "review", "adjudication"],
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,
90
+ "highest_reasoning_configuration": "xhigh"
91
+ },
92
+ {
93
+ "provider_id": "xai",
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",
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
+ }
129
+ ]
130
+ }
@@ -0,0 +1 @@
1
+ rNiDCOiVFtrfGUrQWXw3dqR1cYAh/xZElyt0AfLXjhgykWzcw4o0NygK0ciHNXMDwhJUqhsp5fKIPpwli/YdDA==
@@ -0,0 +1,116 @@
1
+ import { sha256 } from '@chati/core';
2
+
3
+ const PROVIDER_BINDINGS = Object.freeze({
4
+ claude: Object.freeze({ provider_id: 'anthropic', harness_id: 'claude', default_model: 'fable' }),
5
+ codex: Object.freeze({ provider_id: 'openai', harness_id: 'codex', default_model: 'gpt-5.6-sol' }),
6
+ grok: Object.freeze({ provider_id: 'xai', harness_id: 'grok', default_model: 'grok-4.6' }),
7
+ });
8
+
9
+ /**
10
+ * Bootstrap suggestions used only when the installer has no fresh capability
11
+ * catalog. The selected values are always written explicitly to C-01.
12
+ */
13
+ export const wizardDefaultModels = Object.freeze(Object.fromEntries(
14
+ Object.entries(PROVIDER_BINDINGS).map(([provider, binding]) => [provider, binding.default_model])
15
+ ));
16
+
17
+ const V2_ACTIONS = Object.freeze(['discovery', 'planning', 'build', 'review', 'adjudication']);
18
+
19
+ function fail(code, message) {
20
+ const error = new Error(message);
21
+ error.code = code;
22
+ throw error;
23
+ }
24
+
25
+ function normalizeModels(provider, selections, capabilityCatalog) {
26
+ const value = selections?.[provider];
27
+ const values = value === undefined
28
+ ? wizardModelSuggestions(provider, capabilityCatalog)
29
+ : (Array.isArray(value) ? value : [value]);
30
+ const models = [...new Set(values.map((model) => typeof model === 'string' ? model.trim() : '').filter(Boolean))];
31
+ if (models.length === 0) fail('WIZARD_MODEL_REQUIRED', `${provider} requires at least one selected model`);
32
+ return models;
33
+ }
34
+
35
+ export function wizardModelSuggestions(provider, capabilityCatalog) {
36
+ const binding = PROVIDER_BINDINGS[provider];
37
+ if (!binding) fail('V2_PROVIDER_UNSUPPORTED', `${provider} is not supported by v2`);
38
+ const models = capabilityCatalog?.models
39
+ ?.filter((model) => model.provider_id === binding.provider_id)
40
+ .sort((left, right) => (right.adjudication_priority ?? 0) - (left.adjudication_priority ?? 0))
41
+ .map((model) => model.model_id);
42
+ return Object.freeze(models?.length ? [...new Set(models)] : [binding.default_model]);
43
+ }
44
+
45
+ /**
46
+ * Builds the explicit C-01 input consumed by installV2. This deliberately does
47
+ * not inspect installed binaries or silently add a provider. A future catalog
48
+ * refresh may replace defaults, but its result must be supplied as selections.
49
+ */
50
+ export function buildWizardV2InstallationInput({
51
+ projectName,
52
+ selectedProviders,
53
+ modelSelections = {},
54
+ capabilityCatalog,
55
+ installationMode = 'open',
56
+ clock = () => new Date(),
57
+ } = {}) {
58
+ if (typeof projectName !== 'string' || !projectName.trim()) fail('WIZARD_PROJECT_REQUIRED', 'projectName is required');
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');
61
+ const providers = [...new Set(selectedProviders)];
62
+ for (const provider of providers) if (!PROVIDER_BINDINGS[provider]) fail('V2_PROVIDER_UNSUPPORTED', `${provider} is not supported by v2`);
63
+ const now = clock();
64
+ const issuedAt = (now instanceof Date ? now : new Date(now));
65
+ if (Number.isNaN(issuedAt.getTime())) fail('WIZARD_CLOCK_INVALID', 'clock must return a valid time');
66
+ const localExpiry = issuedAt.getTime() + (7 * 24 * 60 * 60 * 1000);
67
+ const sourceExpiry = capabilityCatalog ? Date.parse(capabilityCatalog.expires_at) : localExpiry;
68
+ if (Number.isNaN(sourceExpiry) || sourceExpiry <= issuedAt.getTime()) fail('WIZARD_CATALOG_EXPIRED', 'capability catalog is expired');
69
+ // A verified signed catalog keeps its authoritative expiry. The short local
70
+ // TTL applies only to the unsigned bootstrap seam used by direct API tests.
71
+ const expiresAt = new Date(capabilityCatalog ? sourceExpiry : localExpiry).toISOString();
72
+ const sourceCatalogId = capabilityCatalog?.snapshot_id || 'bootstrap';
73
+ const enabled_providers = providers.map((provider) => {
74
+ const binding = PROVIDER_BINDINGS[provider];
75
+ return {
76
+ provider_id: binding.provider_id,
77
+ harness_id: binding.harness_id,
78
+ allowed_models: normalizeModels(provider, modelSelections, capabilityCatalog),
79
+ allowed_reasoning_configurations: ['low', 'medium', 'high', 'xhigh'],
80
+ };
81
+ });
82
+ const models = enabled_providers.flatMap((binding) => binding.allowed_models.map((model_id) => {
83
+ const catalogModel = capabilityCatalog?.models?.find((candidate) => candidate.provider_id === binding.provider_id && candidate.model_id === model_id);
84
+ if (capabilityCatalog && !catalogModel) fail('WIZARD_MODEL_NOT_IN_CATALOG', `${model_id} is not in the signed catalog for ${binding.provider_id}`);
85
+ return {
86
+ provider_id: binding.provider_id,
87
+ model_id,
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 } : {}),
92
+ ...(catalogModel?.adjudication_priority !== undefined ? { adjudication_priority: catalogModel.adjudication_priority } : {}),
93
+ ...(catalogModel?.highest_reasoning_configuration !== undefined
94
+ ? { highest_reasoning_configuration: catalogModel.highest_reasoning_configuration }
95
+ : (!capabilityCatalog ? { highest_reasoning_configuration: 'xhigh' } : {})),
96
+ };
97
+ }));
98
+ const selectionDigest = sha256({ source_catalog_ref: sourceCatalogId, models, enabled_providers }).slice(0, 20);
99
+ const snapshotId = `wizard-catalog-${selectionDigest}`;
100
+ const projectSlug = projectName.trim().toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '') || 'project';
101
+ const installation = {
102
+ installation_id: `wizard-${projectSlug}`,
103
+ profile: installationMode === 'internal' ? 'focus-ai-internal' : 'other-supported-profile',
104
+ enabled_providers,
105
+ capability_snapshot_ref: snapshotId,
106
+ policy_ref: `policy://installation/${snapshotId}`,
107
+ ...(installationMode === 'internal' ? { external_integrations: { clickup: 'required' } } : {}),
108
+ };
109
+ return Object.freeze({
110
+ project_id: `project-${projectSlug}`,
111
+ installation,
112
+ capability_snapshot: { snapshot_id: snapshotId, expires_at: expiresAt, models },
113
+ });
114
+ }
115
+
116
+ export const supportedV2WizardProviders = Object.freeze(Object.keys(PROVIDER_BINDINGS));
@@ -1,6 +1,6 @@
1
1
  import { existsSync, readFileSync } from 'fs';
2
2
  import { join } from 'path';
3
- import yaml from 'js-yaml';
3
+ import * as yaml from 'js-yaml';
4
4
  import { resolveFrameworkDir } from '../utils/framework-dir.js';
5
5
  import { EXPECTED_ARTICLE_COUNT } from '../utils/constitution-meta.js';
6
6
  import { flattenEntitiesMap } from '../utils/flatten-entities.js';
@@ -1,7 +1,7 @@
1
1
  import { homedir } from 'os';
2
2
  import { existsSync, readFileSync, writeFileSync, mkdirSync, chmodSync } from 'fs';
3
3
  import { join } from 'path';
4
- import yaml from 'js-yaml';
4
+ import * as yaml from 'js-yaml';
5
5
  import { getMachineId, getMachineName } from './machine-id.js';
6
6
 
7
7
  const API_BASE = 'https://chati.dev/api';
@@ -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.
@@ -1,6 +1,6 @@
1
1
  import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync, unlinkSync } from 'fs';
2
2
  import { join } from 'path';
3
- import yaml from 'js-yaml';
3
+ import * as yaml from 'js-yaml';
4
4
 
5
5
  const DIGEST_DIR = '.chati/memories/shared/session';
6
6
 
@@ -1,4 +1,4 @@
1
- import yaml from 'js-yaml';
1
+ import * as yaml from 'js-yaml';
2
2
 
3
3
  const MANAGED_START = '# CHATI-MANAGED-START';
4
4
  const MANAGED_END = '# CHATI-MANAGED-END';
@@ -0,0 +1,25 @@
1
+ import { assertBrowserCapabilityForTask, BrowserCapability } from '@chati/browser-capability';
2
+
3
+ /**
4
+ * G3 browser boundary. This runtime has no reference to Playwright, Chrome,
5
+ * MCP, credentials or a shared profile. It can only validate a task policy and
6
+ * use the internal fake adapter supplied by BrowserCapability.
7
+ */
8
+ export function createProjectBrowserSession({ task, request } = {}) {
9
+ const policy = assertBrowserCapabilityForTask(task);
10
+ if (!policy) return Object.freeze({ state: 'not-required', manifest: null, capability: null });
11
+ const capability = new BrowserCapability({});
12
+ const manifest = capability.preflight({ ...request, policy });
13
+ return Object.freeze({ state: 'preflighted', policy, manifest, capability });
14
+ }
15
+
16
+ /** Only the same local session may advance its fake adapter past preflight. */
17
+ export function launchProjectBrowserSession({ session, request } = {}) {
18
+ if (!session || session.state !== 'preflighted' || !session.capability || !session.policy) {
19
+ const error = new Error('browser launch requires a preflighted project-local browser session');
20
+ error.code = 'BROWSER_PREFLIGHT_REQUIRED';
21
+ throw error;
22
+ }
23
+ const manifest = session.capability.launch({ ...request, policy: session.policy });
24
+ return Object.freeze({ state: 'launched', manifest, fake_launches: session.capability.fakeLaunches, capability: session.capability, policy: session.policy });
25
+ }