@marcopeg/hal 1.0.23 → 1.0.26
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 +9 -12
- package/dist/bot/commands/engine-callback.d.ts +4 -0
- package/dist/bot/commands/engine-callback.d.ts.map +1 -0
- package/dist/bot/commands/engine-callback.js +39 -0
- package/dist/bot/commands/engine-callback.js.map +1 -0
- package/dist/bot/commands/engine.d.ts +4 -0
- package/dist/bot/commands/engine.d.ts.map +1 -0
- package/dist/bot/commands/engine.js +65 -0
- package/dist/bot/commands/engine.js.map +1 -0
- package/dist/bot/commands/loader.d.ts +7 -1
- package/dist/bot/commands/loader.d.ts.map +1 -1
- package/dist/bot/commands/loader.js +18 -3
- package/dist/bot/commands/loader.js.map +1 -1
- package/dist/bot/commands/message.d.ts.map +1 -1
- package/dist/bot/commands/message.js +2 -1
- package/dist/bot/commands/message.js.map +1 -1
- package/dist/bot/commands/model-callback.d.ts.map +1 -1
- package/dist/bot/commands/model-callback.js +7 -1
- package/dist/bot/commands/model-callback.js.map +1 -1
- package/dist/bot/commands/model.d.ts.map +1 -1
- package/dist/bot/commands/model.js +17 -3
- package/dist/bot/commands/model.js.map +1 -1
- package/dist/bot/commands/tasks.d.ts +5 -0
- package/dist/bot/commands/tasks.d.ts.map +1 -0
- package/dist/bot/commands/tasks.js +123 -0
- package/dist/bot/commands/tasks.js.map +1 -0
- package/dist/bot/commands/watcher.d.ts.map +1 -1
- package/dist/bot/commands/watcher.js +6 -5
- package/dist/bot/commands/watcher.js.map +1 -1
- package/dist/bot/handlers/index.d.ts +1 -0
- package/dist/bot/handlers/index.d.ts.map +1 -1
- package/dist/bot/handlers/index.js +1 -0
- package/dist/bot/handlers/index.js.map +1 -1
- package/dist/bot/handlers/mjs-callback.d.ts +15 -0
- package/dist/bot/handlers/mjs-callback.d.ts.map +1 -0
- package/dist/bot/handlers/mjs-callback.js +84 -0
- package/dist/bot/handlers/mjs-callback.js.map +1 -0
- package/dist/bot.d.ts.map +1 -1
- package/dist/bot.js +19 -6
- package/dist/bot.js.map +1 -1
- package/dist/cli.js +199 -68
- package/dist/cli.js.map +1 -1
- package/dist/config-writer.d.ts +2 -6
- package/dist/config-writer.d.ts.map +1 -1
- package/dist/config-writer.js +32 -28
- package/dist/config-writer.js.map +1 -1
- package/dist/config.d.ts +103 -56
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +154 -46
- package/dist/config.js.map +1 -1
- package/dist/engine/adapters/codex.d.ts.map +1 -1
- package/dist/engine/adapters/codex.js +4 -2
- package/dist/engine/adapters/codex.js.map +1 -1
- package/dist/engine/adapters/copilot.d.ts.map +1 -1
- package/dist/engine/adapters/copilot.js +8 -5
- package/dist/engine/adapters/copilot.js.map +1 -1
- package/dist/engine/adapters/cursor.d.ts.map +1 -1
- package/dist/engine/adapters/cursor.js +8 -3
- package/dist/engine/adapters/cursor.js.map +1 -1
- package/dist/engine/adapters/opencode.d.ts.map +1 -1
- package/dist/engine/adapters/opencode.js +4 -2
- package/dist/engine/adapters/opencode.js.map +1 -1
- package/dist/engine/cli-available.d.ts +6 -0
- package/dist/engine/cli-available.d.ts.map +1 -0
- package/dist/engine/cli-available.js +19 -0
- package/dist/engine/cli-available.js.map +1 -0
- package/dist/engine/opencode-models.d.ts +30 -0
- package/dist/engine/opencode-models.d.ts.map +1 -0
- package/dist/engine/opencode-models.js +96 -0
- package/dist/engine/opencode-models.js.map +1 -0
- package/dist/init-template.yaml +32 -0
- package/dist/user/setup.d.ts.map +1 -1
- package/dist/user/setup.js +5 -1
- package/dist/user/setup.js.map +1 -1
- package/package.json +2 -2
package/dist/config.d.ts
CHANGED
|
@@ -7,6 +7,38 @@ declare const EngineNameSchema: z.ZodEnum<{
|
|
|
7
7
|
cursor: "cursor";
|
|
8
8
|
antigravity: "antigravity";
|
|
9
9
|
}>;
|
|
10
|
+
declare const ProvidersConfigSchema: z.ZodOptional<z.ZodObject<{
|
|
11
|
+
claude: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
12
|
+
name: z.ZodString;
|
|
13
|
+
description: z.ZodOptional<z.ZodString>;
|
|
14
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
15
|
+
}, z.core.$strip>>>;
|
|
16
|
+
copilot: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
17
|
+
name: z.ZodString;
|
|
18
|
+
description: z.ZodOptional<z.ZodString>;
|
|
19
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
20
|
+
}, z.core.$strip>>>;
|
|
21
|
+
codex: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
22
|
+
name: z.ZodString;
|
|
23
|
+
description: z.ZodOptional<z.ZodString>;
|
|
24
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
25
|
+
}, z.core.$strip>>>;
|
|
26
|
+
opencode: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
27
|
+
name: z.ZodString;
|
|
28
|
+
description: z.ZodOptional<z.ZodString>;
|
|
29
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
30
|
+
}, z.core.$strip>>>;
|
|
31
|
+
cursor: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
32
|
+
name: z.ZodString;
|
|
33
|
+
description: z.ZodOptional<z.ZodString>;
|
|
34
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
35
|
+
}, z.core.$strip>>>;
|
|
36
|
+
antigravity: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
37
|
+
name: z.ZodString;
|
|
38
|
+
description: z.ZodOptional<z.ZodString>;
|
|
39
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
40
|
+
}, z.core.$strip>>>;
|
|
41
|
+
}, z.core.$strip>>;
|
|
10
42
|
declare const GlobalsFileSchema: z.ZodOptional<z.ZodObject<{
|
|
11
43
|
access: z.ZodOptional<z.ZodObject<{
|
|
12
44
|
allowedUserIds: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>>;
|
|
@@ -39,32 +71,6 @@ declare const GlobalsFileSchema: z.ZodOptional<z.ZodObject<{
|
|
|
39
71
|
sandbox: z.ZodOptional<z.ZodBoolean>;
|
|
40
72
|
}, z.core.$strip>>>;
|
|
41
73
|
}, z.core.$strip>>;
|
|
42
|
-
providers: z.ZodOptional<z.ZodObject<{
|
|
43
|
-
claude: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
44
|
-
name: z.ZodString;
|
|
45
|
-
description: z.ZodOptional<z.ZodString>;
|
|
46
|
-
}, z.core.$strip>>>;
|
|
47
|
-
copilot: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
48
|
-
name: z.ZodString;
|
|
49
|
-
description: z.ZodOptional<z.ZodString>;
|
|
50
|
-
}, z.core.$strip>>>;
|
|
51
|
-
codex: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
52
|
-
name: z.ZodString;
|
|
53
|
-
description: z.ZodOptional<z.ZodString>;
|
|
54
|
-
}, z.core.$strip>>>;
|
|
55
|
-
opencode: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
56
|
-
name: z.ZodString;
|
|
57
|
-
description: z.ZodOptional<z.ZodString>;
|
|
58
|
-
}, z.core.$strip>>>;
|
|
59
|
-
cursor: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
60
|
-
name: z.ZodString;
|
|
61
|
-
description: z.ZodOptional<z.ZodString>;
|
|
62
|
-
}, z.core.$strip>>>;
|
|
63
|
-
antigravity: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
64
|
-
name: z.ZodString;
|
|
65
|
-
description: z.ZodOptional<z.ZodString>;
|
|
66
|
-
}, z.core.$strip>>>;
|
|
67
|
-
}, z.core.$strip>>;
|
|
68
74
|
logging: z.ZodOptional<z.ZodObject<{
|
|
69
75
|
level: z.ZodOptional<z.ZodEnum<{
|
|
70
76
|
debug: "debug";
|
|
@@ -138,12 +144,15 @@ declare const GlobalsFileSchema: z.ZodOptional<z.ZodObject<{
|
|
|
138
144
|
model: z.ZodOptional<z.ZodObject<{
|
|
139
145
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
140
146
|
}, z.core.$strip>>;
|
|
147
|
+
engine: z.ZodOptional<z.ZodObject<{
|
|
148
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
149
|
+
}, z.core.$strip>>;
|
|
141
150
|
}, z.core.$strip>>;
|
|
142
151
|
}, z.core.$strip>>;
|
|
143
152
|
declare const ProjectFileSchema: z.ZodObject<{
|
|
144
153
|
name: z.ZodOptional<z.ZodString>;
|
|
145
154
|
active: z.ZodOptional<z.ZodBoolean>;
|
|
146
|
-
cwd: z.ZodString
|
|
155
|
+
cwd: z.ZodOptional<z.ZodString>;
|
|
147
156
|
telegram: z.ZodObject<{
|
|
148
157
|
botToken: z.ZodString;
|
|
149
158
|
}, z.core.$strip>;
|
|
@@ -182,26 +191,32 @@ declare const ProjectFileSchema: z.ZodObject<{
|
|
|
182
191
|
claude: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
183
192
|
name: z.ZodString;
|
|
184
193
|
description: z.ZodOptional<z.ZodString>;
|
|
194
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
185
195
|
}, z.core.$strip>>>;
|
|
186
196
|
copilot: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
187
197
|
name: z.ZodString;
|
|
188
198
|
description: z.ZodOptional<z.ZodString>;
|
|
199
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
189
200
|
}, z.core.$strip>>>;
|
|
190
201
|
codex: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
191
202
|
name: z.ZodString;
|
|
192
203
|
description: z.ZodOptional<z.ZodString>;
|
|
204
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
193
205
|
}, z.core.$strip>>>;
|
|
194
206
|
opencode: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
195
207
|
name: z.ZodString;
|
|
196
208
|
description: z.ZodOptional<z.ZodString>;
|
|
209
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
197
210
|
}, z.core.$strip>>>;
|
|
198
211
|
cursor: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
199
212
|
name: z.ZodString;
|
|
200
213
|
description: z.ZodOptional<z.ZodString>;
|
|
214
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
201
215
|
}, z.core.$strip>>>;
|
|
202
216
|
antigravity: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
203
217
|
name: z.ZodString;
|
|
204
218
|
description: z.ZodOptional<z.ZodString>;
|
|
219
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
205
220
|
}, z.core.$strip>>>;
|
|
206
221
|
}, z.core.$strip>>;
|
|
207
222
|
logging: z.ZodOptional<z.ZodObject<{
|
|
@@ -278,6 +293,9 @@ declare const ProjectFileSchema: z.ZodObject<{
|
|
|
278
293
|
model: z.ZodOptional<z.ZodObject<{
|
|
279
294
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
280
295
|
}, z.core.$strip>>;
|
|
296
|
+
engine: z.ZodOptional<z.ZodObject<{
|
|
297
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
298
|
+
}, z.core.$strip>>;
|
|
281
299
|
}, z.core.$strip>>;
|
|
282
300
|
}, z.core.$strip>;
|
|
283
301
|
declare const MultiConfigFileSchema: z.ZodObject<{
|
|
@@ -313,32 +331,6 @@ declare const MultiConfigFileSchema: z.ZodObject<{
|
|
|
313
331
|
sandbox: z.ZodOptional<z.ZodBoolean>;
|
|
314
332
|
}, z.core.$strip>>>;
|
|
315
333
|
}, z.core.$strip>>;
|
|
316
|
-
providers: z.ZodOptional<z.ZodObject<{
|
|
317
|
-
claude: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
318
|
-
name: z.ZodString;
|
|
319
|
-
description: z.ZodOptional<z.ZodString>;
|
|
320
|
-
}, z.core.$strip>>>;
|
|
321
|
-
copilot: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
322
|
-
name: z.ZodString;
|
|
323
|
-
description: z.ZodOptional<z.ZodString>;
|
|
324
|
-
}, z.core.$strip>>>;
|
|
325
|
-
codex: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
326
|
-
name: z.ZodString;
|
|
327
|
-
description: z.ZodOptional<z.ZodString>;
|
|
328
|
-
}, z.core.$strip>>>;
|
|
329
|
-
opencode: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
330
|
-
name: z.ZodString;
|
|
331
|
-
description: z.ZodOptional<z.ZodString>;
|
|
332
|
-
}, z.core.$strip>>>;
|
|
333
|
-
cursor: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
334
|
-
name: z.ZodString;
|
|
335
|
-
description: z.ZodOptional<z.ZodString>;
|
|
336
|
-
}, z.core.$strip>>>;
|
|
337
|
-
antigravity: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
338
|
-
name: z.ZodString;
|
|
339
|
-
description: z.ZodOptional<z.ZodString>;
|
|
340
|
-
}, z.core.$strip>>>;
|
|
341
|
-
}, z.core.$strip>>;
|
|
342
334
|
logging: z.ZodOptional<z.ZodObject<{
|
|
343
335
|
level: z.ZodOptional<z.ZodEnum<{
|
|
344
336
|
debug: "debug";
|
|
@@ -412,13 +404,48 @@ declare const MultiConfigFileSchema: z.ZodObject<{
|
|
|
412
404
|
model: z.ZodOptional<z.ZodObject<{
|
|
413
405
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
414
406
|
}, z.core.$strip>>;
|
|
407
|
+
engine: z.ZodOptional<z.ZodObject<{
|
|
408
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
409
|
+
}, z.core.$strip>>;
|
|
415
410
|
}, z.core.$strip>>;
|
|
416
411
|
}, z.core.$strip>>;
|
|
412
|
+
providers: z.ZodOptional<z.ZodObject<{
|
|
413
|
+
claude: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
414
|
+
name: z.ZodString;
|
|
415
|
+
description: z.ZodOptional<z.ZodString>;
|
|
416
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
417
|
+
}, z.core.$strip>>>;
|
|
418
|
+
copilot: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
419
|
+
name: z.ZodString;
|
|
420
|
+
description: z.ZodOptional<z.ZodString>;
|
|
421
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
422
|
+
}, z.core.$strip>>>;
|
|
423
|
+
codex: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
424
|
+
name: z.ZodString;
|
|
425
|
+
description: z.ZodOptional<z.ZodString>;
|
|
426
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
427
|
+
}, z.core.$strip>>>;
|
|
428
|
+
opencode: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
429
|
+
name: z.ZodString;
|
|
430
|
+
description: z.ZodOptional<z.ZodString>;
|
|
431
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
432
|
+
}, z.core.$strip>>>;
|
|
433
|
+
cursor: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
434
|
+
name: z.ZodString;
|
|
435
|
+
description: z.ZodOptional<z.ZodString>;
|
|
436
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
437
|
+
}, z.core.$strip>>>;
|
|
438
|
+
antigravity: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
439
|
+
name: z.ZodString;
|
|
440
|
+
description: z.ZodOptional<z.ZodString>;
|
|
441
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
442
|
+
}, z.core.$strip>>>;
|
|
443
|
+
}, z.core.$strip>>;
|
|
417
444
|
context: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
418
|
-
projects: z.
|
|
445
|
+
projects: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
419
446
|
name: z.ZodOptional<z.ZodString>;
|
|
420
447
|
active: z.ZodOptional<z.ZodBoolean>;
|
|
421
|
-
cwd: z.ZodString
|
|
448
|
+
cwd: z.ZodOptional<z.ZodString>;
|
|
422
449
|
telegram: z.ZodObject<{
|
|
423
450
|
botToken: z.ZodString;
|
|
424
451
|
}, z.core.$strip>;
|
|
@@ -457,26 +484,32 @@ declare const MultiConfigFileSchema: z.ZodObject<{
|
|
|
457
484
|
claude: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
458
485
|
name: z.ZodString;
|
|
459
486
|
description: z.ZodOptional<z.ZodString>;
|
|
487
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
460
488
|
}, z.core.$strip>>>;
|
|
461
489
|
copilot: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
462
490
|
name: z.ZodString;
|
|
463
491
|
description: z.ZodOptional<z.ZodString>;
|
|
492
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
464
493
|
}, z.core.$strip>>>;
|
|
465
494
|
codex: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
466
495
|
name: z.ZodString;
|
|
467
496
|
description: z.ZodOptional<z.ZodString>;
|
|
497
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
468
498
|
}, z.core.$strip>>>;
|
|
469
499
|
opencode: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
470
500
|
name: z.ZodString;
|
|
471
501
|
description: z.ZodOptional<z.ZodString>;
|
|
502
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
472
503
|
}, z.core.$strip>>>;
|
|
473
504
|
cursor: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
474
505
|
name: z.ZodString;
|
|
475
506
|
description: z.ZodOptional<z.ZodString>;
|
|
507
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
476
508
|
}, z.core.$strip>>>;
|
|
477
509
|
antigravity: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
478
510
|
name: z.ZodString;
|
|
479
511
|
description: z.ZodOptional<z.ZodString>;
|
|
512
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
480
513
|
}, z.core.$strip>>>;
|
|
481
514
|
}, z.core.$strip>>;
|
|
482
515
|
logging: z.ZodOptional<z.ZodObject<{
|
|
@@ -553,6 +586,9 @@ declare const MultiConfigFileSchema: z.ZodObject<{
|
|
|
553
586
|
model: z.ZodOptional<z.ZodObject<{
|
|
554
587
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
555
588
|
}, z.core.$strip>>;
|
|
589
|
+
engine: z.ZodOptional<z.ZodObject<{
|
|
590
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
591
|
+
}, z.core.$strip>>;
|
|
556
592
|
}, z.core.$strip>>;
|
|
557
593
|
}, z.core.$strip>>;
|
|
558
594
|
}, z.core.$strip>;
|
|
@@ -563,6 +599,7 @@ export type EngineName = z.infer<typeof EngineNameSchema>;
|
|
|
563
599
|
export interface ProviderModel {
|
|
564
600
|
name: string;
|
|
565
601
|
description?: string;
|
|
602
|
+
default?: boolean;
|
|
566
603
|
}
|
|
567
604
|
export interface ResolvedProjectConfig {
|
|
568
605
|
slug: string;
|
|
@@ -607,6 +644,8 @@ export interface ResolvedProjectConfig {
|
|
|
607
644
|
} | undefined;
|
|
608
645
|
context: Record<string, string> | undefined;
|
|
609
646
|
providerModels: ProviderModel[];
|
|
647
|
+
providerDefaultModel: string | undefined;
|
|
648
|
+
availableEngines: EngineName[];
|
|
610
649
|
commands: {
|
|
611
650
|
start: {
|
|
612
651
|
enabled: boolean;
|
|
@@ -636,6 +675,9 @@ export interface ResolvedProjectConfig {
|
|
|
636
675
|
model: {
|
|
637
676
|
enabled: boolean;
|
|
638
677
|
};
|
|
678
|
+
engine: {
|
|
679
|
+
enabled: boolean;
|
|
680
|
+
};
|
|
639
681
|
};
|
|
640
682
|
}
|
|
641
683
|
export declare class ConfigLoadError extends Error {
|
|
@@ -646,9 +688,14 @@ export interface LoadedConfigResult {
|
|
|
646
688
|
loadedFiles: string[];
|
|
647
689
|
}
|
|
648
690
|
export declare function deriveSlug(name: string | undefined, cwd: string): string;
|
|
649
|
-
export declare function resolveProjectConfig(project: ProjectFileEntry, globals: GlobalsFile, configDir: string, rootContext?: Record<string, string>): ResolvedProjectConfig;
|
|
691
|
+
export declare function resolveProjectConfig(key: string, project: ProjectFileEntry, globals: GlobalsFile, configDir: string, rootContext?: Record<string, string>, providers?: z.infer<typeof ProvidersConfigSchema>): ResolvedProjectConfig;
|
|
650
692
|
export declare function validateProjects(projects: ResolvedProjectConfig[]): void;
|
|
651
693
|
export declare function validateAccessPolicies(projects: ResolvedProjectConfig[]): void;
|
|
694
|
+
/**
|
|
695
|
+
* Validates that at most one model per providers.<engine> list has default: true.
|
|
696
|
+
* Call after config load and env substitution, before resolving project configs.
|
|
697
|
+
*/
|
|
698
|
+
export declare function validateProviderDefaultUniqueness(config: MultiConfigFile): void;
|
|
652
699
|
export type ConfigFormat = "json" | "jsonc" | "yaml";
|
|
653
700
|
interface ResolvedConfigFile {
|
|
654
701
|
path: string;
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/config.js
CHANGED
|
@@ -4,6 +4,7 @@ import { parse as parseEnv } from "dotenv";
|
|
|
4
4
|
import stripJsonComments from "strip-json-comments";
|
|
5
5
|
import { parse as parseYaml } from "yaml";
|
|
6
6
|
import { z } from "zod";
|
|
7
|
+
import { isCliAvailable } from "./engine/cli-available.js";
|
|
7
8
|
// ─── Zod helpers ──────────────────────────────────────────────────────────────
|
|
8
9
|
const TranscriptionModelSchema = z.enum([
|
|
9
10
|
"tiny",
|
|
@@ -102,11 +103,13 @@ const CommandsConfigSchema = z
|
|
|
102
103
|
clean: SimpleCommandConfigSchema,
|
|
103
104
|
git: GitConfigSchema,
|
|
104
105
|
model: GitConfigSchema,
|
|
106
|
+
engine: GitConfigSchema,
|
|
105
107
|
})
|
|
106
108
|
.optional();
|
|
107
109
|
const ProviderModelSchema = z.object({
|
|
108
110
|
name: z.string().min(1),
|
|
109
111
|
description: z.string().optional(),
|
|
112
|
+
default: z.boolean().optional(),
|
|
110
113
|
});
|
|
111
114
|
const ProvidersConfigSchema = z
|
|
112
115
|
.object({
|
|
@@ -130,7 +133,6 @@ const GlobalsFileSchema = z
|
|
|
130
133
|
.object({
|
|
131
134
|
access: AccessSchema,
|
|
132
135
|
engine: EngineConfigSchema,
|
|
133
|
-
providers: ProvidersConfigSchema,
|
|
134
136
|
logging: z
|
|
135
137
|
.object({
|
|
136
138
|
level: LogLevelSchema,
|
|
@@ -154,11 +156,17 @@ const GlobalsFileSchema = z
|
|
|
154
156
|
commands: CommandsConfigSchema,
|
|
155
157
|
})
|
|
156
158
|
.optional();
|
|
159
|
+
// ─── Project map key (slug-like: safe for default cwd path segment) ─────────────
|
|
160
|
+
const PROJECT_KEY_REGEX = /^[a-zA-Z0-9_-]+$/;
|
|
161
|
+
/** Project map keys must be slug-like so default cwd is a safe path segment. */
|
|
162
|
+
const ProjectKeySchema = z
|
|
163
|
+
.string()
|
|
164
|
+
.regex(PROJECT_KEY_REGEX, "project key must be slug-like (letters, numbers, dashes, underscores only)");
|
|
157
165
|
// ─── Per-project schema ────────────────────────────────────────────────────────
|
|
158
166
|
const ProjectFileSchema = z.object({
|
|
159
167
|
name: z.string().optional(),
|
|
160
168
|
active: z.boolean().optional(),
|
|
161
|
-
cwd: z.string().min(1, "project.cwd
|
|
169
|
+
cwd: z.string().min(1, "project.cwd must be non-empty when set").optional(),
|
|
162
170
|
telegram: z.object({
|
|
163
171
|
botToken: z.string().min(1, "project.telegram.botToken is required"),
|
|
164
172
|
}),
|
|
@@ -189,12 +197,16 @@ const ProjectFileSchema = z.object({
|
|
|
189
197
|
commands: CommandsConfigSchema,
|
|
190
198
|
});
|
|
191
199
|
// ─── Multi-project config file schema ─────────────────────────────────────────
|
|
200
|
+
const ProjectsMapSchema = z
|
|
201
|
+
.record(ProjectKeySchema, ProjectFileSchema)
|
|
202
|
+
.refine((rec) => Object.keys(rec).length >= 1, {
|
|
203
|
+
message: "At least one project is required",
|
|
204
|
+
});
|
|
192
205
|
const MultiConfigFileSchema = z.object({
|
|
193
206
|
globals: GlobalsFileSchema,
|
|
207
|
+
providers: ProvidersConfigSchema,
|
|
194
208
|
context: z.record(z.string(), z.string()).optional(),
|
|
195
|
-
projects:
|
|
196
|
-
.array(ProjectFileSchema)
|
|
197
|
-
.min(1, "At least one project is required"),
|
|
209
|
+
projects: ProjectsMapSchema,
|
|
198
210
|
});
|
|
199
211
|
// ─── Local config partial schema ──────────────────────────────────────────────
|
|
200
212
|
const LocalProjectSchema = ProjectFileSchema.partial().extend({
|
|
@@ -204,8 +216,9 @@ const LocalProjectSchema = ProjectFileSchema.partial().extend({
|
|
|
204
216
|
const LocalConfigFileSchema = z
|
|
205
217
|
.object({
|
|
206
218
|
globals: GlobalsFileSchema,
|
|
219
|
+
providers: ProvidersConfigSchema,
|
|
207
220
|
context: z.record(z.string(), z.string()).optional(),
|
|
208
|
-
projects: z.
|
|
221
|
+
projects: z.record(ProjectKeySchema, LocalProjectSchema).optional(),
|
|
209
222
|
})
|
|
210
223
|
.optional();
|
|
211
224
|
// ─── Config load result & errors ───────────────────────────────────────────────
|
|
@@ -231,6 +244,13 @@ function parseTelegramUserId(value, path) {
|
|
|
231
244
|
}
|
|
232
245
|
return num;
|
|
233
246
|
}
|
|
247
|
+
/** Set name/cwd from map key when omitted. Mutates entries in place. */
|
|
248
|
+
function normalizeProjectMap(projects) {
|
|
249
|
+
for (const [key, entry] of Object.entries(projects)) {
|
|
250
|
+
entry.name = entry.name ?? key;
|
|
251
|
+
entry.cwd = entry.cwd ?? key;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
234
254
|
function normalizeAllowedUserIdsInConfig(config) {
|
|
235
255
|
const globalsAccess = config.globals?.access;
|
|
236
256
|
if (globalsAccess?.allowedUserIds != null) {
|
|
@@ -241,15 +261,14 @@ function normalizeAllowedUserIdsInConfig(config) {
|
|
|
241
261
|
}
|
|
242
262
|
globalsAccess.allowedUserIds = normalized;
|
|
243
263
|
}
|
|
244
|
-
for (
|
|
245
|
-
const project = config.projects[j];
|
|
264
|
+
for (const [key, project] of Object.entries(config.projects)) {
|
|
246
265
|
const access = project.access;
|
|
247
266
|
if (access?.allowedUserIds == null)
|
|
248
267
|
continue;
|
|
249
268
|
const raw = access.allowedUserIds;
|
|
250
269
|
const normalized = [];
|
|
251
270
|
for (let i = 0; i < raw.length; i++) {
|
|
252
|
-
normalized.push(parseTelegramUserId(raw[i], `projects
|
|
271
|
+
normalized.push(parseTelegramUserId(raw[i], `projects.${key}.access.allowedUserIds[${i}]`));
|
|
253
272
|
}
|
|
254
273
|
access.allowedUserIds = normalized;
|
|
255
274
|
}
|
|
@@ -280,11 +299,11 @@ function resolveDataDir(dataDirRaw, projectCwd, configDir, slug) {
|
|
|
280
299
|
return resolve(projectCwd, dataDirRaw);
|
|
281
300
|
}
|
|
282
301
|
// ─── Merge: project over globals over defaults ─────────────────────────────────
|
|
283
|
-
export function resolveProjectConfig(project, globals, configDir, rootContext) {
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
const
|
|
302
|
+
export function resolveProjectConfig(key, project, globals, configDir, rootContext, providers) {
|
|
303
|
+
const slug = key;
|
|
304
|
+
const name = project.name ?? key;
|
|
305
|
+
const cwd = project.cwd ?? key;
|
|
306
|
+
const resolvedCwd = isAbsolute(cwd) ? cwd : resolve(configDir, cwd);
|
|
288
307
|
const logDir = resolve(configDir, ".hal", "logs", slug);
|
|
289
308
|
const dataDir = resolveDataDir(project.dataDir ?? globals.dataDir, resolvedCwd, configDir, slug);
|
|
290
309
|
const hasTranscription = project.transcription !== undefined || globals.transcription !== undefined;
|
|
@@ -304,11 +323,54 @@ export function resolveProjectConfig(project, globals, configDir, rootContext) {
|
|
|
304
323
|
}
|
|
305
324
|
return msg.text;
|
|
306
325
|
}
|
|
326
|
+
// Resolve engine and provider models early (needed for command enabled flags)
|
|
327
|
+
const rawEngineName = project.engine?.name ?? globals.engine?.name;
|
|
328
|
+
if (!rawEngineName) {
|
|
329
|
+
throw new ConfigLoadError(`Configuration error: project "${key}" has no engine configured. ` +
|
|
330
|
+
"Set engine.name in the project or in globals.");
|
|
331
|
+
}
|
|
332
|
+
const engineName = rawEngineName;
|
|
333
|
+
const mergedProviders = {
|
|
334
|
+
...(providers ?? {}),
|
|
335
|
+
...(project.providers ?? {}),
|
|
336
|
+
};
|
|
337
|
+
const availableEngines = Object.keys(mergedProviders).filter((k) => {
|
|
338
|
+
const list = mergedProviders[k];
|
|
339
|
+
return Array.isArray(list) && list.length > 0;
|
|
340
|
+
});
|
|
341
|
+
const rawProviderModels = project.providers?.[engineName] ?? providers?.[engineName] ?? [];
|
|
342
|
+
const providerModels = rawProviderModels.map((m) => ({
|
|
343
|
+
name: m.name,
|
|
344
|
+
description: m.description,
|
|
345
|
+
default: m.default,
|
|
346
|
+
}));
|
|
347
|
+
const defaultEntries = providerModels.filter((m) => m.default === true);
|
|
348
|
+
const providerDefaultModel = defaultEntries.length === 1 ? defaultEntries[0].name : undefined;
|
|
307
349
|
// Resolve command enabled flags (project > globals > default)
|
|
308
350
|
const rawStart = project.commands?.start ?? globals.commands?.start;
|
|
309
351
|
const rawHelp = project.commands?.help ?? globals.commands?.help;
|
|
310
352
|
const rawReset = project.commands?.reset ?? globals.commands?.reset;
|
|
311
353
|
const rawClean = project.commands?.clean ?? globals.commands?.clean;
|
|
354
|
+
// Enable /model when we have a config list, or when the engine supports self-discovery and its CLI is available
|
|
355
|
+
const effectiveEngineCommand = project.engine?.command ?? globals.engine?.command ?? undefined;
|
|
356
|
+
const defaultCommandForEngine = engineName === "opencode"
|
|
357
|
+
? "opencode"
|
|
358
|
+
: engineName === "cursor"
|
|
359
|
+
? "agent"
|
|
360
|
+
: null;
|
|
361
|
+
const modelCliCommand = effectiveEngineCommand ?? defaultCommandForEngine;
|
|
362
|
+
const selfDiscoveryEnabled = rawProviderModels.length === 0 &&
|
|
363
|
+
(engineName === "opencode" || engineName === "cursor") &&
|
|
364
|
+
modelCliCommand !== null &&
|
|
365
|
+
isCliAvailable(modelCliCommand);
|
|
366
|
+
const modelEnabled = (project.commands?.model?.enabled ??
|
|
367
|
+
globals.commands?.model?.enabled ??
|
|
368
|
+
true) &&
|
|
369
|
+
(providerModels.length > 1 || selfDiscoveryEnabled);
|
|
370
|
+
const engineEnabled = (project.commands?.engine?.enabled ??
|
|
371
|
+
globals.commands?.engine?.enabled ??
|
|
372
|
+
true) &&
|
|
373
|
+
availableEngines.length > 1;
|
|
312
374
|
const resolvedCommands = {
|
|
313
375
|
start: {
|
|
314
376
|
enabled: project.commands?.start?.enabled ??
|
|
@@ -351,23 +413,12 @@ export function resolveProjectConfig(project, globals, configDir, rootContext) {
|
|
|
351
413
|
globals.commands?.git?.enabled ??
|
|
352
414
|
false,
|
|
353
415
|
},
|
|
354
|
-
model: {
|
|
355
|
-
|
|
356
|
-
globals.commands?.model?.enabled ??
|
|
357
|
-
true,
|
|
358
|
-
},
|
|
416
|
+
model: { enabled: modelEnabled },
|
|
417
|
+
engine: { enabled: engineEnabled },
|
|
359
418
|
};
|
|
360
|
-
const engineName = (project.engine?.name ??
|
|
361
|
-
globals.engine?.name ??
|
|
362
|
-
"claude");
|
|
363
|
-
const rawProviderModels = project.providers?.[engineName] ?? globals.providers?.[engineName] ?? [];
|
|
364
|
-
const providerModels = rawProviderModels.map((m) => ({
|
|
365
|
-
name: m.name,
|
|
366
|
-
description: m.description,
|
|
367
|
-
}));
|
|
368
419
|
return {
|
|
369
420
|
slug,
|
|
370
|
-
name
|
|
421
|
+
name,
|
|
371
422
|
cwd: resolvedCwd,
|
|
372
423
|
configDir,
|
|
373
424
|
dataDir,
|
|
@@ -425,6 +476,8 @@ export function resolveProjectConfig(project, globals, configDir, rootContext) {
|
|
|
425
476
|
}
|
|
426
477
|
: undefined,
|
|
427
478
|
providerModels,
|
|
479
|
+
providerDefaultModel,
|
|
480
|
+
availableEngines,
|
|
428
481
|
context: hasContext ? { ...rootContext, ...project.context } : undefined,
|
|
429
482
|
commands: resolvedCommands,
|
|
430
483
|
};
|
|
@@ -467,6 +520,49 @@ export function validateAccessPolicies(projects) {
|
|
|
467
520
|
throw new ConfigLoadError(`Configuration error: invalid access policy\n${errors.map((e) => ` - ${e}`).join("\n")}`);
|
|
468
521
|
}
|
|
469
522
|
}
|
|
523
|
+
// ─── Boot-time provider default uniqueness ────────────────────────────────────
|
|
524
|
+
const PROVIDER_ENGINE_KEYS = [
|
|
525
|
+
"claude",
|
|
526
|
+
"copilot",
|
|
527
|
+
"codex",
|
|
528
|
+
"opencode",
|
|
529
|
+
"cursor",
|
|
530
|
+
"antigravity",
|
|
531
|
+
];
|
|
532
|
+
function countProviderDefaults(list) {
|
|
533
|
+
if (!Array.isArray(list))
|
|
534
|
+
return 0;
|
|
535
|
+
return list.filter((m) => m.default === true).length;
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* Validates that at most one model per providers.<engine> list has default: true.
|
|
539
|
+
* Call after config load and env substitution, before resolving project configs.
|
|
540
|
+
*/
|
|
541
|
+
export function validateProviderDefaultUniqueness(config) {
|
|
542
|
+
const topProviders = config.providers;
|
|
543
|
+
if (topProviders) {
|
|
544
|
+
for (const engine of PROVIDER_ENGINE_KEYS) {
|
|
545
|
+
const list = topProviders[engine];
|
|
546
|
+
const n = countProviderDefaults(list);
|
|
547
|
+
if (n > 1) {
|
|
548
|
+
throw new ConfigLoadError(`Configuration error: at most one model in providers.${engine} may have default: true (found ${n}).`);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
for (const [key, project] of Object.entries(config.projects)) {
|
|
553
|
+
const projectProviders = project.providers;
|
|
554
|
+
if (!projectProviders)
|
|
555
|
+
continue;
|
|
556
|
+
const projectLabel = project.name ?? key;
|
|
557
|
+
for (const engine of PROVIDER_ENGINE_KEYS) {
|
|
558
|
+
const list = projectProviders[engine];
|
|
559
|
+
const n = countProviderDefaults(list);
|
|
560
|
+
if (n > 1) {
|
|
561
|
+
throw new ConfigLoadError(`Configuration error: at most one model in projects["${key}"].providers.${engine} may have default: true (found ${n}). Project: ${projectLabel}.`);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
470
566
|
function loadEnvFiles(configDir, projectCwds) {
|
|
471
567
|
const loadedFiles = [];
|
|
472
568
|
const vars = {};
|
|
@@ -619,32 +715,36 @@ function mergeLocalIntoBase(base, local, baseFileName, localFileName) {
|
|
|
619
715
|
const mergedGlobals = local.globals !== undefined
|
|
620
716
|
? deepMerge(base.globals ?? {}, local.globals)
|
|
621
717
|
: base.globals;
|
|
718
|
+
const mergedProviders = local.providers !== undefined
|
|
719
|
+
? base.providers
|
|
720
|
+
? deepMerge(base.providers, local.providers)
|
|
721
|
+
: local.providers
|
|
722
|
+
: base.providers;
|
|
622
723
|
const mergedContext = local.context !== undefined
|
|
623
724
|
? base.context
|
|
624
725
|
? { ...base.context, ...local.context }
|
|
625
726
|
: local.context
|
|
626
727
|
: base.context;
|
|
627
|
-
if (!local.projects || local.projects.length === 0) {
|
|
628
|
-
return {
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
if (idx === -1) {
|
|
641
|
-
throw new ConfigLoadError(`Configuration error: local project "${matchKey}" not found in ${baseFileName}.\n` +
|
|
642
|
-
` Every entry in ${localFileName} projects must match a base project by name or cwd.`);
|
|
728
|
+
if (!local.projects || Object.keys(local.projects).length === 0) {
|
|
729
|
+
return {
|
|
730
|
+
...base,
|
|
731
|
+
globals: mergedGlobals,
|
|
732
|
+
providers: mergedProviders,
|
|
733
|
+
context: mergedContext,
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
const mergedProjects = { ...base.projects };
|
|
737
|
+
for (const [localKey, localProject] of Object.entries(local.projects)) {
|
|
738
|
+
if (!(localKey in mergedProjects)) {
|
|
739
|
+
throw new ConfigLoadError(`Configuration error: local project key "${localKey}" not found in ${baseFileName}.\n` +
|
|
740
|
+
` Every key in ${localFileName} projects must exist in the base config.`);
|
|
643
741
|
}
|
|
644
|
-
mergedProjects[
|
|
742
|
+
mergedProjects[localKey] = deepMerge(mergedProjects[localKey], localProject);
|
|
645
743
|
}
|
|
744
|
+
normalizeProjectMap(mergedProjects);
|
|
646
745
|
return {
|
|
647
746
|
globals: mergedGlobals,
|
|
747
|
+
providers: mergedProviders,
|
|
648
748
|
context: mergedContext,
|
|
649
749
|
projects: mergedProjects,
|
|
650
750
|
};
|
|
@@ -681,6 +781,7 @@ function loadMultiConfigInternal(configDir) {
|
|
|
681
781
|
throw new ConfigLoadError(`Configuration error in ${baseFileName}:\n${issues}`);
|
|
682
782
|
}
|
|
683
783
|
let merged = baseResult.data;
|
|
784
|
+
normalizeProjectMap(merged.projects);
|
|
684
785
|
// 3. Load and merge local config
|
|
685
786
|
const localResult = loadLocalConfig(configDir);
|
|
686
787
|
if (localResult !== null) {
|
|
@@ -689,7 +790,13 @@ function loadMultiConfigInternal(configDir) {
|
|
|
689
790
|
merged = mergeLocalIntoBase(merged, localResult.config, baseFileName, localFileName);
|
|
690
791
|
}
|
|
691
792
|
// 4. Load .env files (using raw cwds from merged config for path resolution)
|
|
692
|
-
|
|
793
|
+
// Stable order: sort project keys so iteration is deterministic.
|
|
794
|
+
const projectKeys = Object.keys(merged.projects).sort();
|
|
795
|
+
const rawCwds = projectKeys.map((key) => {
|
|
796
|
+
const p = merged.projects[key];
|
|
797
|
+
const cwd = p.cwd ?? key;
|
|
798
|
+
return isAbsolute(cwd) ? cwd : resolve(configDir, cwd);
|
|
799
|
+
});
|
|
693
800
|
const envSources = loadEnvFiles(configDir, rawCwds);
|
|
694
801
|
// 5. Substitute env vars in the merged raw object (before final Zod pass)
|
|
695
802
|
const substituted = substituteEnvVars(merged, envSources.vars);
|
|
@@ -701,6 +808,7 @@ function loadMultiConfigInternal(configDir) {
|
|
|
701
808
|
.join("\n");
|
|
702
809
|
throw new ConfigLoadError(`Configuration error after environment variable substitution:\n${issues}`);
|
|
703
810
|
}
|
|
811
|
+
normalizeProjectMap(finalResult.data.projects);
|
|
704
812
|
// 7. Normalize allowedUserIds (string | number)[] → number[] with validation
|
|
705
813
|
normalizeAllowedUserIdsInConfig(finalResult.data);
|
|
706
814
|
return {
|