@pellux/goodvibes-tui 0.19.53 → 0.19.55
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/CHANGELOG.md +35 -0
- package/README.md +10 -13
- package/docs/foundation-artifacts/knowledge-store.sql +27 -0
- package/docs/foundation-artifacts/operator-contract.json +15736 -7265
- package/package.json +2 -2
- package/src/audio/spoken-turn-controller.ts +4 -1
- package/src/input/command-args-hint.ts +36 -0
- package/src/input/command-registry.ts +3 -1
- package/src/input/commands/config.ts +7 -521
- package/src/input/commands/knowledge.ts +111 -1
- package/src/input/commands/local-runtime.ts +0 -80
- package/src/input/commands/operator-runtime.ts +3 -3
- package/src/input/commands/planning-runtime.ts +83 -34
- package/src/input/commands/shell-core.ts +2 -34
- package/src/input/commands/tts-runtime.ts +1 -389
- package/src/input/commands.ts +0 -2
- package/src/input/handler-modal-routes.ts +61 -7
- package/src/input/handler-modal-token-routes.ts +1 -0
- package/src/input/handler-picker-routes.ts +50 -4
- package/src/input/model-picker-provider-filter.ts +28 -0
- package/src/input/model-picker-types.ts +12 -0
- package/src/input/model-picker.ts +65 -23
- package/src/input/selection-modal.ts +1 -1
- package/src/input/settings-modal-behavior.ts +2 -0
- package/src/input/settings-modal-subscriptions.ts +95 -0
- package/src/input/settings-modal-types.ts +50 -3
- package/src/input/settings-modal.ts +106 -134
- package/src/input/tts-settings-actions.ts +100 -0
- package/src/main.ts +50 -45
- package/src/panels/builtin/agent.ts +15 -0
- package/src/panels/builtin/shared.ts +17 -0
- package/src/panels/project-planning-panel.ts +370 -0
- package/src/planning/project-planning-coordinator.ts +249 -0
- package/src/renderer/compositor.ts +2 -1
- package/src/renderer/conversation-overlays.ts +4 -5
- package/src/renderer/model-workspace.ts +488 -0
- package/src/renderer/settings-modal-helpers.ts +16 -1
- package/src/renderer/settings-modal.ts +616 -716
- package/src/runtime/bootstrap-command-context.ts +6 -0
- package/src/runtime/bootstrap-command-parts.ts +5 -0
- package/src/runtime/bootstrap-shell.ts +2 -0
- package/src/runtime/services.ts +33 -2
- package/src/runtime/terminal-output-guard.ts +228 -0
- package/src/runtime/ui-services.ts +4 -0
- package/src/shell/ui-openers.ts +59 -3
- package/src/utils/clipboard.ts +2 -1
- package/src/version.ts +1 -1
- package/src/input/commands/permissions-runtime.ts +0 -104
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { POPULAR_PROVIDERS } from './model-picker-types.ts';
|
|
2
|
+
|
|
3
|
+
export function groupProviders(providers: readonly string[]): { popular: string[]; all: string[] } {
|
|
4
|
+
const popular: string[] = [];
|
|
5
|
+
const all: string[] = [];
|
|
6
|
+
|
|
7
|
+
for (const provider of providers) {
|
|
8
|
+
if (POPULAR_PROVIDERS.has(provider.toLowerCase())) {
|
|
9
|
+
popular.push(provider);
|
|
10
|
+
} else {
|
|
11
|
+
all.push(provider);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
popular.sort((a, b) => a.localeCompare(b));
|
|
16
|
+
all.sort((a, b) => a.localeCompare(b));
|
|
17
|
+
|
|
18
|
+
return { popular, all };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function filterProviders(providers: readonly string[], query: string): string[] {
|
|
22
|
+
const { popular, all } = groupProviders(providers);
|
|
23
|
+
const ordered = [...popular, ...all];
|
|
24
|
+
const normalized = query.trim().toLowerCase();
|
|
25
|
+
return normalized.length === 0
|
|
26
|
+
? ordered
|
|
27
|
+
: ordered.filter((provider) => provider.toLowerCase().includes(normalized));
|
|
28
|
+
}
|
|
@@ -11,6 +11,18 @@ export type PickerMode = 'model' | 'provider' | 'effort' | 'contextCap';
|
|
|
11
11
|
*/
|
|
12
12
|
export type ModelPickerTarget = 'main' | 'helper' | 'tool' | 'tts';
|
|
13
13
|
|
|
14
|
+
export type ModelPickerFocusPane = 'targets' | 'items';
|
|
15
|
+
|
|
16
|
+
export interface ModelPickerTargetInfo {
|
|
17
|
+
readonly target: ModelPickerTarget;
|
|
18
|
+
readonly label: string;
|
|
19
|
+
readonly description: string;
|
|
20
|
+
readonly provider: string;
|
|
21
|
+
readonly model: string;
|
|
22
|
+
readonly enabled: boolean;
|
|
23
|
+
readonly inherited: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
14
26
|
/**
|
|
15
27
|
* Pricing tier filter.
|
|
16
28
|
* 'paid' matches ModelDefinition tiers 'standard' and 'premium' for forward-compat
|
|
@@ -5,10 +5,11 @@ import { getQualityTier, getQualityTierFromScore, compositeScore, A_TIER_THRESHO
|
|
|
5
5
|
import type { BenchmarkStore } from '@pellux/goodvibes-sdk/platform/providers/model-benchmarks';
|
|
6
6
|
import type { ProviderRegistry } from '@pellux/goodvibes-sdk/platform/providers/registry';
|
|
7
7
|
import { detectFamily, POPULAR_PROVIDERS, tierToCategoryFilter } from './model-picker-types.ts';
|
|
8
|
-
import type { BenchmarkSort, CapabilityFilter, CategoryFilter, FilteredModelsCache, FilteredProvidersCache, GroupByMode, ModelItemsCache, ModelPickerTarget, PickerItem, PickerMode, ProviderItemsCache } from './model-picker-types.ts';
|
|
8
|
+
import type { BenchmarkSort, CapabilityFilter, CategoryFilter, FilteredModelsCache, FilteredProvidersCache, GroupByMode, ModelItemsCache, ModelPickerFocusPane, ModelPickerTarget, ModelPickerTargetInfo, PickerItem, PickerMode, ProviderItemsCache } from './model-picker-types.ts';
|
|
9
|
+
import { filterProviders, groupProviders } from './model-picker-provider-filter.ts';
|
|
9
10
|
|
|
10
11
|
export { detectFamily, POPULAR_PROVIDERS, tierToCategoryFilter } from './model-picker-types.ts';
|
|
11
|
-
export type { BenchmarkSort, CapabilityFilter, CategoryFilter, GroupByMode, ModelFamily, ModelPickerTarget, PickerItem, PickerMode } from './model-picker-types.ts';
|
|
12
|
+
export type { BenchmarkSort, CapabilityFilter, CategoryFilter, GroupByMode, ModelFamily, ModelPickerFocusPane, ModelPickerTarget, ModelPickerTargetInfo, PickerItem, PickerMode } from './model-picker-types.ts';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* ModelPickerModal - Multi-step interactive picker for model, provider, and effort.
|
|
@@ -35,6 +36,9 @@ export class ModelPickerModal {
|
|
|
35
36
|
public mode: PickerMode = 'model';
|
|
36
37
|
/** Which config target this picker session will write to on commit. */
|
|
37
38
|
public target: ModelPickerTarget = 'main';
|
|
39
|
+
public focusPane: ModelPickerFocusPane = 'items';
|
|
40
|
+
public targetInfos: ModelPickerTargetInfo[] = [];
|
|
41
|
+
public targetIndex = 0;
|
|
38
42
|
public searchFocused = false;
|
|
39
43
|
/** Tracks the mode we came from, for back-navigation. */
|
|
40
44
|
public previousMode: PickerMode | null = null;
|
|
@@ -78,6 +82,58 @@ export class ModelPickerModal {
|
|
|
78
82
|
private modelItemsCache: ModelItemsCache | null = null;
|
|
79
83
|
private providerItemsCache: ProviderItemsCache | null = null;
|
|
80
84
|
|
|
85
|
+
setTargetInfos(infos: ModelPickerTargetInfo[]): void {
|
|
86
|
+
this.targetInfos = infos;
|
|
87
|
+
const idx = infos.findIndex((entry) => entry.target === this.target);
|
|
88
|
+
this.targetIndex = idx >= 0 ? idx : 0;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
getSelectedTargetInfo(): ModelPickerTargetInfo | null {
|
|
92
|
+
return this.targetInfos[this.targetIndex] ?? null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
focusTargets(): void {
|
|
96
|
+
this.focusPane = 'targets';
|
|
97
|
+
this.searchFocused = false;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
focusItems(): void {
|
|
101
|
+
this.focusPane = 'items';
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
moveTarget(delta: number): void {
|
|
105
|
+
if (this.targetInfos.length === 0) return;
|
|
106
|
+
const nextIndex = (this.targetIndex + delta + this.targetInfos.length) % this.targetInfos.length;
|
|
107
|
+
this.setTarget(this.targetInfos[nextIndex]!.target);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
setTarget(target: ModelPickerTarget): void {
|
|
111
|
+
this.target = target;
|
|
112
|
+
const idx = this.targetInfos.findIndex((entry) => entry.target === target);
|
|
113
|
+
this.targetIndex = idx >= 0 ? idx : this.targetIndex;
|
|
114
|
+
this.alignSelectionToTarget();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
alignSelectionToTarget(): void {
|
|
118
|
+
const info = this.getSelectedTargetInfo();
|
|
119
|
+
if (!info) return;
|
|
120
|
+
if (this.mode === 'provider') {
|
|
121
|
+
const providers = this.getFilteredProviders();
|
|
122
|
+
const providerIdx = providers.findIndex((provider) => provider === info.provider);
|
|
123
|
+
this.selectedIndex = providerIdx >= 0 ? providerIdx : 0;
|
|
124
|
+
this.scrollOffset = 0;
|
|
125
|
+
this._scrollToSelection(20);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (this.mode === 'model') {
|
|
129
|
+
const models = this.getFilteredModels();
|
|
130
|
+
const modelIdx = models.findIndex((model) => model.registryKey === info.model || model.id === info.model);
|
|
131
|
+
this.selectedIndex = modelIdx >= 0 ? modelIdx : 0;
|
|
132
|
+
this.scrollOffset = 0;
|
|
133
|
+
this._scrollToSelection(20);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
81
137
|
// ── Category filter cycling ───────────────────────────────────────────────
|
|
82
138
|
private static readonly CATEGORY_CYCLE: CategoryFilter[] = ['all', 'free', 'paid', 'subscription'];
|
|
83
139
|
/** Cycle to next pricing tier filter. */
|
|
@@ -146,6 +202,7 @@ export class ModelPickerModal {
|
|
|
146
202
|
this.mode = 'model';
|
|
147
203
|
this.active = true;
|
|
148
204
|
this.pendingModel = null;
|
|
205
|
+
this.focusPane = 'items';
|
|
149
206
|
this.searchFocused = false;
|
|
150
207
|
this.query = '';
|
|
151
208
|
this.categoryFilter = 'all';
|
|
@@ -163,6 +220,7 @@ export class ModelPickerModal {
|
|
|
163
220
|
this.mode = 'provider';
|
|
164
221
|
this.active = true;
|
|
165
222
|
this.pendingModel = null;
|
|
223
|
+
this.focusPane = 'items';
|
|
166
224
|
this.searchFocused = false;
|
|
167
225
|
this.query = '';
|
|
168
226
|
this.categoryFilter = 'all';
|
|
@@ -206,6 +264,9 @@ export class ModelPickerModal {
|
|
|
206
264
|
this.active = false;
|
|
207
265
|
this.mode = 'model';
|
|
208
266
|
this.target = 'main';
|
|
267
|
+
this.focusPane = 'items';
|
|
268
|
+
this.targetInfos = [];
|
|
269
|
+
this.targetIndex = 0;
|
|
209
270
|
this.models = [];
|
|
210
271
|
this.providers = [];
|
|
211
272
|
this.pendingModel = null;
|
|
@@ -285,22 +346,7 @@ export class ModelPickerModal {
|
|
|
285
346
|
* renderer and does not affect grouping.
|
|
286
347
|
*/
|
|
287
348
|
getGroupedProviders(): { popular: string[]; all: string[] } {
|
|
288
|
-
|
|
289
|
-
const all: string[] = [];
|
|
290
|
-
|
|
291
|
-
for (const p of this.providers) {
|
|
292
|
-
const pLower = p.toLowerCase();
|
|
293
|
-
if (POPULAR_PROVIDERS.has(pLower)) {
|
|
294
|
-
popular.push(p);
|
|
295
|
-
} else {
|
|
296
|
-
all.push(p);
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
popular.sort((a, b) => a.localeCompare(b));
|
|
301
|
-
all.sort((a, b) => a.localeCompare(b));
|
|
302
|
-
|
|
303
|
-
return { popular, all };
|
|
349
|
+
return groupProviders(this.providers);
|
|
304
350
|
}
|
|
305
351
|
|
|
306
352
|
/** Return providers matching the current query (case-insensitive substring), in grouped order. */
|
|
@@ -314,11 +360,7 @@ export class ModelPickerModal {
|
|
|
314
360
|
return cached.result;
|
|
315
361
|
}
|
|
316
362
|
|
|
317
|
-
const
|
|
318
|
-
const ordered = [...popular, ...all];
|
|
319
|
-
const result = this.query.trim().length === 0
|
|
320
|
-
? ordered
|
|
321
|
-
: ordered.filter(p => p.toLowerCase().includes(this.query.toLowerCase()));
|
|
363
|
+
const result = filterProviders(this.providers, this.query);
|
|
322
364
|
this.filteredProvidersCache = {
|
|
323
365
|
providersRef: this.providers,
|
|
324
366
|
query: this.query,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* SelectionModal - Generic reusable selection modal with fuzzy search.
|
|
3
|
-
* Used by /
|
|
3
|
+
* Used by /template, /sessions, /bookmarks, /tools, and focused pickers.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
export interface SelectionItem {
|
|
@@ -10,6 +10,8 @@ export type ModelPickerLaunch =
|
|
|
10
10
|
* provider first; model rows open directly to models for the same target.
|
|
11
11
|
*/
|
|
12
12
|
export function modelPickerLaunchForKey(key: string): ModelPickerLaunch | null {
|
|
13
|
+
if (key === 'provider.provider') return { flow: 'providerModel', target: 'main' };
|
|
14
|
+
if (key === 'provider.model') return { flow: 'model', target: 'main' };
|
|
13
15
|
if (key === 'helper.globalProvider') return { flow: 'providerModel', target: 'helper' };
|
|
14
16
|
if (key === 'helper.globalModel') return { flow: 'model', target: 'helper' };
|
|
15
17
|
if (key === 'tools.llmProvider') return { flow: 'providerModel', target: 'tool' };
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { ProviderAuthFreshness } from '@pellux/goodvibes-sdk/platform/runtime/provider-accounts/registry';
|
|
2
|
+
import { listBuiltinSubscriptionProviders } from '@pellux/goodvibes-sdk/platform/config/subscription-providers';
|
|
3
|
+
import type { SubscriptionManager } from '@pellux/goodvibes-sdk/platform/config/subscriptions';
|
|
4
|
+
import type { ServiceInspectionQuery } from '../runtime/ui-service-queries.ts';
|
|
5
|
+
import type { SubscriptionEntry } from './settings-modal-types.ts';
|
|
6
|
+
|
|
7
|
+
export function buildSubscriptionEntries(
|
|
8
|
+
manager: SubscriptionManager | null,
|
|
9
|
+
serviceRegistry: Pick<ServiceInspectionQuery, 'getAll'> | null,
|
|
10
|
+
): SubscriptionEntry[] {
|
|
11
|
+
if (!manager) return [];
|
|
12
|
+
|
|
13
|
+
const services = serviceRegistry?.getAll() ?? {};
|
|
14
|
+
const providers = new Map<string, SubscriptionEntry>();
|
|
15
|
+
const builtinProviders = new Set(listBuiltinSubscriptionProviders().map((builtin) => builtin.provider));
|
|
16
|
+
|
|
17
|
+
for (const provider of builtinProviders) {
|
|
18
|
+
providers.set(provider, {
|
|
19
|
+
provider,
|
|
20
|
+
state: 'available',
|
|
21
|
+
oauthConfigured: true,
|
|
22
|
+
preferredRoute: 'subscription',
|
|
23
|
+
activeRoute: 'unconfigured',
|
|
24
|
+
authFreshness: 'unconfigured',
|
|
25
|
+
routeReason: 'Built-in subscription adapter is available, but no active subscription session is stored yet.',
|
|
26
|
+
nextActions: [`Use /subscription login ${provider} start to begin browser sign-in.`],
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
for (const service of Object.values(services)) {
|
|
31
|
+
if (service.authType !== 'oauth' || !service.oauth) continue;
|
|
32
|
+
const provider = service.providerId ?? service.name;
|
|
33
|
+
providers.set(provider, {
|
|
34
|
+
provider,
|
|
35
|
+
state: 'available',
|
|
36
|
+
oauthConfigured: true,
|
|
37
|
+
preferredRoute: 'subscription',
|
|
38
|
+
activeRoute: providers.get(provider)?.activeRoute ?? 'unconfigured',
|
|
39
|
+
authFreshness: providers.get(provider)?.authFreshness ?? 'unconfigured',
|
|
40
|
+
routeReason: providers.get(provider)?.routeReason ?? 'OAuth metadata is configured for this provider.',
|
|
41
|
+
nextActions: providers.get(provider)?.nextActions ?? [`Use /subscription login ${provider} start to begin browser sign-in.`],
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
for (const pending of manager.listPending()) {
|
|
46
|
+
providers.set(pending.provider, {
|
|
47
|
+
provider: pending.provider,
|
|
48
|
+
state: 'pending',
|
|
49
|
+
oauthConfigured: providers.get(pending.provider)?.oauthConfigured ?? false,
|
|
50
|
+
preferredRoute: 'subscription',
|
|
51
|
+
activeRoute: 'unconfigured',
|
|
52
|
+
authFreshness: 'pending',
|
|
53
|
+
routeReason: 'OAuth login is pending completion for this provider.',
|
|
54
|
+
nextActions: [`Finish /subscription login ${pending.provider} finish <code> to activate this session.`],
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
for (const subscription of manager.list()) {
|
|
59
|
+
const freshness = determineFreshness(subscription.expiresAt);
|
|
60
|
+
const issues = freshness === 'expired'
|
|
61
|
+
? ['Stored subscription session is expired and needs refresh.']
|
|
62
|
+
: freshness === 'expiring'
|
|
63
|
+
? ['Stored subscription session expires within 24 hours.']
|
|
64
|
+
: [];
|
|
65
|
+
const nextActions = freshness === 'expired'
|
|
66
|
+
? [`Refresh or replace the ${subscription.provider} subscription session.`]
|
|
67
|
+
: freshness === 'expiring'
|
|
68
|
+
? [`Verify or renew the ${subscription.provider} subscription session soon.`]
|
|
69
|
+
: [];
|
|
70
|
+
providers.set(subscription.provider, {
|
|
71
|
+
provider: subscription.provider,
|
|
72
|
+
state: 'active',
|
|
73
|
+
tokenType: subscription.tokenType,
|
|
74
|
+
expiresAt: subscription.expiresAt,
|
|
75
|
+
oauthConfigured: providers.get(subscription.provider)?.oauthConfigured ?? builtinProviders.has(subscription.provider),
|
|
76
|
+
activeRoute: freshness === 'expired' ? 'unconfigured' : 'subscription',
|
|
77
|
+
preferredRoute: 'subscription',
|
|
78
|
+
authFreshness: freshness,
|
|
79
|
+
routeReason: subscription.overrideAmbientApiKeys
|
|
80
|
+
? 'Subscription route overrides ambient API-key resolution for this provider.'
|
|
81
|
+
: 'Subscription route is stored for supported flows without automatically replacing ambient API-key resolution.',
|
|
82
|
+
issues,
|
|
83
|
+
nextActions,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return [...providers.values()].sort((a, b) => a.provider.localeCompare(b.provider));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function determineFreshness(expiresAt?: number): ProviderAuthFreshness {
|
|
91
|
+
if (typeof expiresAt !== 'number' || !Number.isFinite(expiresAt)) return 'healthy';
|
|
92
|
+
if (expiresAt <= Date.now()) return 'expired';
|
|
93
|
+
if (expiresAt <= Date.now() + 24 * 60 * 60 * 1000) return 'expiring';
|
|
94
|
+
return 'healthy';
|
|
95
|
+
}
|
|
@@ -2,7 +2,39 @@ import type { ConfigSetting } from '@pellux/goodvibes-sdk/platform/config/schema
|
|
|
2
2
|
import type { ProviderAuthFreshness, ProviderAuthRoute } from '@pellux/goodvibes-sdk/platform/runtime/provider-accounts/registry';
|
|
3
3
|
import type { FeatureFlag, FlagState } from '@pellux/goodvibes-sdk/platform/runtime/feature-flags/types';
|
|
4
4
|
|
|
5
|
-
export type SettingsCategory =
|
|
5
|
+
export type SettingsCategory =
|
|
6
|
+
| 'display'
|
|
7
|
+
| 'ui'
|
|
8
|
+
| 'provider'
|
|
9
|
+
| 'subscriptions'
|
|
10
|
+
| 'behavior'
|
|
11
|
+
| 'storage'
|
|
12
|
+
| 'permissions'
|
|
13
|
+
| 'orchestration'
|
|
14
|
+
| 'wrfc'
|
|
15
|
+
| 'tools'
|
|
16
|
+
| 'helper'
|
|
17
|
+
| 'tts'
|
|
18
|
+
| 'service'
|
|
19
|
+
| 'controlPlane'
|
|
20
|
+
| 'httpListener'
|
|
21
|
+
| 'web'
|
|
22
|
+
| 'network'
|
|
23
|
+
| 'surfaces'
|
|
24
|
+
| 'cloudflare'
|
|
25
|
+
| 'batch'
|
|
26
|
+
| 'automation'
|
|
27
|
+
| 'watchers'
|
|
28
|
+
| 'runtime'
|
|
29
|
+
| 'telemetry'
|
|
30
|
+
| 'cache'
|
|
31
|
+
| 'sandbox'
|
|
32
|
+
| 'mcp'
|
|
33
|
+
| 'flags'
|
|
34
|
+
| 'release'
|
|
35
|
+
| 'danger';
|
|
36
|
+
|
|
37
|
+
export type SettingsFocusPane = 'categories' | 'settings';
|
|
6
38
|
|
|
7
39
|
export const SETTINGS_CATEGORIES: SettingsCategory[] = [
|
|
8
40
|
'display',
|
|
@@ -12,14 +44,29 @@ export const SETTINGS_CATEGORIES: SettingsCategory[] = [
|
|
|
12
44
|
'behavior',
|
|
13
45
|
'storage',
|
|
14
46
|
'permissions',
|
|
47
|
+
'orchestration',
|
|
48
|
+
'wrfc',
|
|
49
|
+
'tools',
|
|
50
|
+
'helper',
|
|
51
|
+
'tts',
|
|
52
|
+
'service',
|
|
53
|
+
'controlPlane',
|
|
54
|
+
'httpListener',
|
|
55
|
+
'web',
|
|
56
|
+
'network',
|
|
15
57
|
'mcp',
|
|
16
58
|
'sandbox',
|
|
17
59
|
'surfaces',
|
|
18
60
|
'cloudflare',
|
|
61
|
+
'batch',
|
|
62
|
+
'automation',
|
|
63
|
+
'watchers',
|
|
64
|
+
'runtime',
|
|
65
|
+
'telemetry',
|
|
66
|
+
'cache',
|
|
19
67
|
'danger',
|
|
20
|
-
'tools',
|
|
21
68
|
'flags',
|
|
22
|
-
'
|
|
69
|
+
'release',
|
|
23
70
|
];
|
|
24
71
|
|
|
25
72
|
export interface SettingEntry {
|