@pellux/goodvibes-agent 0.1.9 → 0.1.11
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 +41 -0
- package/README.md +1 -1
- package/docs/getting-started.md +1 -1
- package/docs/release-and-publishing.md +2 -2
- package/package.json +4 -1
- package/src/cli/agent-knowledge-command.ts +46 -20
- package/src/cli/help.ts +15 -2
- package/src/cli/management-commands.ts +3 -3
- package/src/cli/management.ts +7 -1
- package/src/cli/parser.ts +3 -0
- package/src/cli/service-posture.ts +6 -6
- package/src/cli/status.ts +9 -9
- package/src/cli/surface-command.ts +3 -3
- package/src/cli/types.ts +2 -0
- package/src/input/commands/cloudflare-runtime.ts +20 -5
- package/src/input/commands/confirmation.ts +24 -0
- package/src/input/commands/discovery-runtime.ts +16 -7
- package/src/input/commands/eval.ts +27 -14
- package/src/input/commands/experience-runtime.ts +66 -27
- package/src/input/commands/health-runtime.ts +1 -1
- package/src/input/commands/hooks-runtime.ts +79 -20
- package/src/input/commands/incident-runtime.ts +17 -6
- package/src/input/commands/integration-runtime.ts +93 -50
- package/src/input/commands/knowledge.ts +38 -12
- package/src/input/commands/local-auth-runtime.ts +36 -13
- package/src/input/commands/local-provider-runtime.ts +22 -11
- package/src/input/commands/local-runtime.ts +21 -11
- package/src/input/commands/local-setup.ts +35 -16
- package/src/input/commands/managed-runtime.ts +51 -20
- package/src/input/commands/marketplace-runtime.ts +31 -16
- package/src/input/commands/mcp-runtime.ts +65 -34
- package/src/input/commands/memory-product-runtime.ts +72 -35
- package/src/input/commands/memory.ts +9 -9
- package/src/input/commands/notify-runtime.ts +27 -8
- package/src/input/commands/operator-runtime.ts +85 -17
- package/src/input/commands/planning-runtime.ts +14 -2
- package/src/input/commands/platform-access-runtime.ts +88 -45
- package/src/input/commands/platform-services-runtime.ts +51 -25
- package/src/input/commands/product-runtime.ts +54 -27
- package/src/input/commands/profile-sync-runtime.ts +17 -6
- package/src/input/commands/recall-bundle.ts +38 -17
- package/src/input/commands/recall-query.ts +15 -4
- package/src/input/commands/recall-review.ts +9 -3
- package/src/input/commands/remote-runtime-setup.ts +45 -18
- package/src/input/commands/remote-runtime.ts +25 -9
- package/src/input/commands/replay-runtime.ts +9 -2
- package/src/input/commands/services-runtime.ts +21 -10
- package/src/input/commands/session-content.ts +53 -51
- package/src/input/commands/session-workflow.ts +10 -4
- package/src/input/commands/session.ts +1 -1
- package/src/input/commands/settings-sync-runtime.ts +40 -17
- package/src/input/commands/share-runtime.ts +12 -4
- package/src/input/commands/shell-core.ts +3 -3
- package/src/input/commands/subscription-runtime.ts +35 -20
- package/src/input/commands/teleport-runtime.ts +16 -5
- package/src/input/commands/work-plan-runtime.ts +23 -12
- package/src/input/handler-content-actions.ts +11 -62
- package/src/input/handler-interactions.ts +1 -1
- package/src/input/handler-onboarding-cloudflare.ts +48 -117
- package/src/input/handler.ts +1 -0
- package/src/input/keybindings.ts +1 -1
- package/src/input/mcp-workspace.ts +25 -49
- package/src/input/onboarding/onboarding-runtime-status.ts +8 -8
- package/src/input/onboarding/onboarding-wizard-apply.ts +13 -53
- package/src/input/onboarding/onboarding-wizard-cloudflare-step.ts +12 -12
- package/src/input/onboarding/onboarding-wizard-cloudflare.ts +2 -7
- package/src/input/onboarding/onboarding-wizard-constants.ts +7 -7
- package/src/input/onboarding/onboarding-wizard-external-surface-extra-specs.ts +4 -4
- package/src/input/onboarding/onboarding-wizard-steps.ts +13 -13
- package/src/input/profile-picker-modal.ts +13 -31
- package/src/input/session-picker-modal.ts +4 -30
- package/src/input/settings-modal-agent-policy.ts +18 -0
- package/src/input/settings-modal-subscriptions.ts +3 -3
- package/src/input/settings-modal-types.ts +17 -0
- package/src/input/settings-modal.ts +30 -29
- package/src/main.ts +3 -26
- package/src/panels/incident-review-panel.ts +1 -1
- package/src/panels/local-auth-panel.ts +4 -4
- package/src/panels/provider-account-snapshot.ts +1 -1
- package/src/panels/provider-health-domains.ts +2 -2
- package/src/panels/settings-sync-panel.ts +2 -2
- package/src/panels/subscription-panel.ts +7 -7
- package/src/renderer/block-actions.ts +1 -1
- package/src/renderer/help-overlay.ts +2 -2
- package/src/renderer/mcp-workspace.ts +12 -12
- package/src/renderer/process-modal.ts +17 -8
- package/src/renderer/profile-picker-modal.ts +3 -11
- package/src/renderer/session-picker-modal.ts +2 -10
- package/src/renderer/settings-modal.ts +12 -8
- package/src/renderer/ui-factory.ts +4 -32
- package/src/runtime/bootstrap-shell.ts +0 -13
- package/src/runtime/bootstrap.ts +0 -10
- package/src/runtime/onboarding/derivation.ts +6 -6
- package/src/verification/live-verifier.ts +148 -13
- package/src/version.ts +10 -3
- package/src/input/commands/quit-shared.ts +0 -162
- package/src/renderer/git-status.ts +0 -89
|
@@ -14,15 +14,18 @@ import {
|
|
|
14
14
|
uninstallEcosystemCatalogEntry,
|
|
15
15
|
} from '@/runtime/index.ts';
|
|
16
16
|
import { requireEcosystemCatalogPaths, requirePluginPathOptions } from './runtime-services.ts';
|
|
17
|
+
import { requireYesFlag, stripYesFlag } from './confirmation.ts';
|
|
17
18
|
|
|
18
19
|
export function registerIntegrationRuntimeCommands(registry: CommandRegistry): void {
|
|
19
20
|
registry.register({
|
|
20
21
|
name: 'plugin',
|
|
21
22
|
aliases: [],
|
|
22
23
|
description: 'Manage plugins, trust, review, and ecosystem paths',
|
|
23
|
-
usage: 'list | dirs | inspect <name> | review | installed | catalog-review <id> | publish-local <id> <path> <summary...> | unpublish <id> | install <id> [project|user] | update <id> [project|user] | uninstall <id> [project|user] | enable <name> | disable <name> | reload',
|
|
24
|
-
argsHint: 'list | dirs | inspect | review | installed | catalog-review | publish-local | unpublish | install | update | uninstall | enable | disable | reload',
|
|
24
|
+
usage: 'list | dirs | inspect <name> | review | installed | catalog-review <id> | publish-local <id> <path> <summary...> --yes | unpublish <id> --yes | install <id> [project|user] --yes | update <id> [project|user] --yes | uninstall <id> [project|user] --yes | enable <name> --yes | disable <name> --yes | reload --yes',
|
|
25
|
+
argsHint: 'list | dirs | inspect | review | installed | catalog-review | publish-local --yes | unpublish --yes | install --yes | update --yes | uninstall --yes | enable --yes | disable --yes | reload --yes',
|
|
25
26
|
async handler(args, ctx) {
|
|
27
|
+
const parsed = stripYesFlag(args);
|
|
28
|
+
const commandArgs = [...parsed.rest];
|
|
26
29
|
const pluginManager = ctx.extensions.pluginManager;
|
|
27
30
|
const ecosystemPaths = requireEcosystemCatalogPaths(ctx);
|
|
28
31
|
const pluginPaths = requirePluginPathOptions(ctx);
|
|
@@ -30,7 +33,7 @@ export function registerIntegrationRuntimeCommands(registry: CommandRegistry): v
|
|
|
30
33
|
ctx.print('Plugin manager is not available in this runtime.');
|
|
31
34
|
return;
|
|
32
35
|
}
|
|
33
|
-
const sub =
|
|
36
|
+
const sub = commandArgs[0];
|
|
34
37
|
|
|
35
38
|
if (!sub || sub === 'open' || sub === 'panel') {
|
|
36
39
|
if (ctx.showPanel) ctx.showPanel('plugins');
|
|
@@ -55,7 +58,7 @@ export function registerIntegrationRuntimeCommands(registry: CommandRegistry): v
|
|
|
55
58
|
if (p.author) lines.push(` by ${p.author}`);
|
|
56
59
|
}
|
|
57
60
|
lines.push('');
|
|
58
|
-
lines.push('Use /plugin enable <name> or /plugin disable <name> to toggle plugins.');
|
|
61
|
+
lines.push('Use /plugin enable <name> --yes or /plugin disable <name> --yes to toggle plugins.');
|
|
59
62
|
ctx.print(lines.join('\n'));
|
|
60
63
|
return;
|
|
61
64
|
}
|
|
@@ -70,7 +73,7 @@ export function registerIntegrationRuntimeCommands(registry: CommandRegistry): v
|
|
|
70
73
|
return;
|
|
71
74
|
}
|
|
72
75
|
if (sub === 'inspect') {
|
|
73
|
-
const name =
|
|
76
|
+
const name = commandArgs[1];
|
|
74
77
|
if (!name) {
|
|
75
78
|
ctx.print('Usage: /plugin inspect <name>');
|
|
76
79
|
return;
|
|
@@ -111,7 +114,7 @@ export function registerIntegrationRuntimeCommands(registry: CommandRegistry): v
|
|
|
111
114
|
return;
|
|
112
115
|
}
|
|
113
116
|
if (sub === 'browse' || sub === 'catalog') {
|
|
114
|
-
const query =
|
|
117
|
+
const query = commandArgs.slice(1).join(' ');
|
|
115
118
|
const entries = query
|
|
116
119
|
? searchEcosystemCatalog('plugin', query, ecosystemPaths)
|
|
117
120
|
: loadEcosystemCatalog('plugin', ecosystemPaths);
|
|
@@ -140,7 +143,7 @@ export function registerIntegrationRuntimeCommands(registry: CommandRegistry): v
|
|
|
140
143
|
return;
|
|
141
144
|
}
|
|
142
145
|
if (sub === 'catalog-review') {
|
|
143
|
-
const entryId =
|
|
146
|
+
const entryId = commandArgs[1];
|
|
144
147
|
if (!entryId) {
|
|
145
148
|
ctx.print('Usage: /plugin catalog-review <catalog-id>');
|
|
146
149
|
return;
|
|
@@ -166,7 +169,7 @@ export function registerIntegrationRuntimeCommands(registry: CommandRegistry): v
|
|
|
166
169
|
return;
|
|
167
170
|
}
|
|
168
171
|
if (sub === 'install-hint') {
|
|
169
|
-
const entryId =
|
|
172
|
+
const entryId = commandArgs[1];
|
|
170
173
|
if (!entryId) {
|
|
171
174
|
ctx.print('Usage: /plugin install-hint <catalog-id>');
|
|
172
175
|
return;
|
|
@@ -182,16 +185,20 @@ export function registerIntegrationRuntimeCommands(registry: CommandRegistry): v
|
|
|
182
185
|
` source: ${entry.source}`,
|
|
183
186
|
` tags: ${entry.tags.join(', ') || '(none)'}`,
|
|
184
187
|
` trust notes: ${entry.trustNotes ?? '(none)'}`,
|
|
185
|
-
` install hint: ${entry.installHint ?? 'Place the plugin under a configured plugin search directory and use /plugin reload.'}`,
|
|
188
|
+
` install hint: ${entry.installHint ?? 'Place the plugin under a configured plugin search directory and use /plugin reload --yes.'}`,
|
|
186
189
|
].join('\n'));
|
|
187
190
|
return;
|
|
188
191
|
}
|
|
189
192
|
if (sub === 'publish-local') {
|
|
190
|
-
const entryId =
|
|
191
|
-
const sourcePath =
|
|
192
|
-
const summary =
|
|
193
|
+
const entryId = commandArgs[1];
|
|
194
|
+
const sourcePath = commandArgs[2];
|
|
195
|
+
const summary = commandArgs.slice(3).join(' ').trim();
|
|
193
196
|
if (!entryId || !sourcePath || !summary) {
|
|
194
|
-
ctx.print('Usage: /plugin publish-local <catalog-id> <path> <summary...>');
|
|
197
|
+
ctx.print('Usage: /plugin publish-local <catalog-id> <path> <summary...> --yes');
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (!parsed.yes) {
|
|
201
|
+
requireYesFlag(ctx, `publish curated plugin ${entryId}`, '/plugin publish-local <catalog-id> <path> <summary...> --yes');
|
|
195
202
|
return;
|
|
196
203
|
}
|
|
197
204
|
const result = upsertEcosystemCatalogEntry({
|
|
@@ -210,9 +217,13 @@ export function registerIntegrationRuntimeCommands(registry: CommandRegistry): v
|
|
|
210
217
|
return;
|
|
211
218
|
}
|
|
212
219
|
if (sub === 'unpublish') {
|
|
213
|
-
const entryId =
|
|
220
|
+
const entryId = commandArgs[1];
|
|
214
221
|
if (!entryId) {
|
|
215
|
-
ctx.print('Usage: /plugin unpublish <catalog-id>');
|
|
222
|
+
ctx.print('Usage: /plugin unpublish <catalog-id> --yes');
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
if (!parsed.yes) {
|
|
226
|
+
requireYesFlag(ctx, `unpublish curated plugin ${entryId}`, '/plugin unpublish <catalog-id> --yes');
|
|
216
227
|
return;
|
|
217
228
|
}
|
|
218
229
|
const result = removeEcosystemCatalogEntry('plugin', entryId, ecosystemPaths);
|
|
@@ -222,10 +233,14 @@ export function registerIntegrationRuntimeCommands(registry: CommandRegistry): v
|
|
|
222
233
|
return;
|
|
223
234
|
}
|
|
224
235
|
if (sub === 'install') {
|
|
225
|
-
const entryId =
|
|
226
|
-
const scopeArg =
|
|
236
|
+
const entryId = commandArgs[1];
|
|
237
|
+
const scopeArg = commandArgs[2];
|
|
227
238
|
if (!entryId) {
|
|
228
|
-
ctx.print('Usage: /plugin install <catalog-id> [project|user]');
|
|
239
|
+
ctx.print('Usage: /plugin install <catalog-id> [project|user] --yes');
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (!parsed.yes) {
|
|
243
|
+
requireYesFlag(ctx, `install curated plugin ${entryId}`, '/plugin install <catalog-id> [project|user] --yes');
|
|
229
244
|
return;
|
|
230
245
|
}
|
|
231
246
|
const scope = scopeArg === 'user' ? 'user' : 'project';
|
|
@@ -236,10 +251,14 @@ export function registerIntegrationRuntimeCommands(registry: CommandRegistry): v
|
|
|
236
251
|
return;
|
|
237
252
|
}
|
|
238
253
|
if (sub === 'update') {
|
|
239
|
-
const entryId =
|
|
240
|
-
const scopeArg =
|
|
254
|
+
const entryId = commandArgs[1];
|
|
255
|
+
const scopeArg = commandArgs[2];
|
|
241
256
|
if (!entryId) {
|
|
242
|
-
ctx.print('Usage: /plugin update <catalog-id> [project|user]');
|
|
257
|
+
ctx.print('Usage: /plugin update <catalog-id> [project|user] --yes');
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
if (!parsed.yes) {
|
|
261
|
+
requireYesFlag(ctx, `update curated plugin ${entryId}`, '/plugin update <catalog-id> [project|user] --yes');
|
|
243
262
|
return;
|
|
244
263
|
}
|
|
245
264
|
const scope = scopeArg === 'user' ? 'user' : 'project';
|
|
@@ -250,10 +269,14 @@ export function registerIntegrationRuntimeCommands(registry: CommandRegistry): v
|
|
|
250
269
|
return;
|
|
251
270
|
}
|
|
252
271
|
if (sub === 'uninstall') {
|
|
253
|
-
const entryId =
|
|
254
|
-
const scopeArg =
|
|
272
|
+
const entryId = commandArgs[1];
|
|
273
|
+
const scopeArg = commandArgs[2];
|
|
255
274
|
if (!entryId) {
|
|
256
|
-
ctx.print('Usage: /plugin uninstall <catalog-id> [project|user]');
|
|
275
|
+
ctx.print('Usage: /plugin uninstall <catalog-id> [project|user] --yes');
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
if (!parsed.yes) {
|
|
279
|
+
requireYesFlag(ctx, `uninstall curated plugin ${entryId}`, '/plugin uninstall <catalog-id> [project|user] --yes');
|
|
257
280
|
return;
|
|
258
281
|
}
|
|
259
282
|
const scope = scopeArg === 'user' ? 'user' : 'project';
|
|
@@ -264,30 +287,46 @@ export function registerIntegrationRuntimeCommands(registry: CommandRegistry): v
|
|
|
264
287
|
return;
|
|
265
288
|
}
|
|
266
289
|
if (sub === 'enable') {
|
|
267
|
-
const name =
|
|
268
|
-
if (!name) { ctx.print('Usage: /plugin enable <name>'); return; }
|
|
290
|
+
const name = commandArgs[1];
|
|
291
|
+
if (!name) { ctx.print('Usage: /plugin enable <name> --yes'); return; }
|
|
292
|
+
if (!parsed.yes) {
|
|
293
|
+
requireYesFlag(ctx, `enable plugin ${name}`, '/plugin enable <name> --yes');
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
269
296
|
const result = await pluginManager.enable(name);
|
|
270
297
|
ctx.print(result.ok ? `Plugin '${name}' enabled and activated.` : `Error: ${result.error}`);
|
|
271
298
|
return;
|
|
272
299
|
}
|
|
273
300
|
if (sub === 'disable') {
|
|
274
|
-
const name =
|
|
275
|
-
if (!name) { ctx.print('Usage: /plugin disable <name>'); return; }
|
|
301
|
+
const name = commandArgs[1];
|
|
302
|
+
if (!name) { ctx.print('Usage: /plugin disable <name> --yes'); return; }
|
|
303
|
+
if (!parsed.yes) {
|
|
304
|
+
requireYesFlag(ctx, `disable plugin ${name}`, '/plugin disable <name> --yes');
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
276
307
|
const result = await pluginManager.disable(name);
|
|
277
308
|
ctx.print(result.ok ? `Plugin '${name}' disabled.` : `Error: ${result.error}`);
|
|
278
309
|
return;
|
|
279
310
|
}
|
|
280
311
|
if (sub === 'reload') {
|
|
312
|
+
if (!parsed.yes) {
|
|
313
|
+
requireYesFlag(ctx, 'reload plugins', '/plugin reload --yes');
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
281
316
|
ctx.print('Reloading plugins...');
|
|
282
317
|
const { reloaded, failed } = await pluginManager.reload();
|
|
283
318
|
ctx.print(`Done. ${reloaded} plugin(s) reloaded${failed > 0 ? `, ${failed} failed` : ''}.`);
|
|
284
319
|
return;
|
|
285
320
|
}
|
|
286
321
|
if (sub === 'trust') {
|
|
287
|
-
const name =
|
|
288
|
-
const rawTier =
|
|
322
|
+
const name = commandArgs[1];
|
|
323
|
+
const rawTier = commandArgs[2];
|
|
289
324
|
if (!name || !rawTier) {
|
|
290
|
-
ctx.print('Usage: /plugin trust <name> <untrusted|limited|trusted> [note]');
|
|
325
|
+
ctx.print('Usage: /plugin trust <name> <untrusted|limited|trusted> [note] --yes');
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
if (!parsed.yes) {
|
|
329
|
+
requireYesFlag(ctx, `set plugin ${name} trust tier`, '/plugin trust <name> <untrusted|limited|trusted> [note] --yes');
|
|
291
330
|
return;
|
|
292
331
|
}
|
|
293
332
|
if (rawTier !== 'untrusted' && rawTier !== 'limited' && rawTier !== 'trusted') {
|
|
@@ -295,7 +334,7 @@ export function registerIntegrationRuntimeCommands(registry: CommandRegistry): v
|
|
|
295
334
|
return;
|
|
296
335
|
}
|
|
297
336
|
const tier = rawTier as 'untrusted' | 'limited' | 'trusted';
|
|
298
|
-
const note =
|
|
337
|
+
const note = commandArgs.slice(3).join(' ') || undefined;
|
|
299
338
|
if (tier === 'trusted') {
|
|
300
339
|
const sigResult = pluginManager.trustSigned(name);
|
|
301
340
|
if (sigResult.ok) {
|
|
@@ -311,7 +350,7 @@ export function registerIntegrationRuntimeCommands(registry: CommandRegistry): v
|
|
|
311
350
|
return;
|
|
312
351
|
}
|
|
313
352
|
if (sub === 'verify') {
|
|
314
|
-
const name =
|
|
353
|
+
const name = commandArgs[1];
|
|
315
354
|
if (!name) { ctx.print('Usage: /plugin verify <name>'); return; }
|
|
316
355
|
const result = pluginManager.verify(name);
|
|
317
356
|
if (!result.ok && result.reason?.includes('not found')) {
|
|
@@ -324,7 +363,7 @@ export function registerIntegrationRuntimeCommands(registry: CommandRegistry): v
|
|
|
324
363
|
return;
|
|
325
364
|
}
|
|
326
365
|
if (sub === 'capabilities') {
|
|
327
|
-
const name =
|
|
366
|
+
const name = commandArgs[1];
|
|
328
367
|
if (!name) { ctx.print('Usage: /plugin capabilities <name>'); return; }
|
|
329
368
|
const info = pluginManager.capabilities(name);
|
|
330
369
|
if (!info) {
|
|
@@ -344,16 +383,20 @@ export function registerIntegrationRuntimeCommands(registry: CommandRegistry): v
|
|
|
344
383
|
if (info.blocked.length > 0) {
|
|
345
384
|
lines.push('');
|
|
346
385
|
lines.push(`${info.blocked.length} high-risk capability/capabilities blocked by trust tier '${info.tier}'.`);
|
|
347
|
-
lines.push(`Use /plugin trust ${name} trusted to escalate.`);
|
|
386
|
+
lines.push(`Use /plugin trust ${name} trusted --yes to escalate.`);
|
|
348
387
|
}
|
|
349
388
|
ctx.print(lines.join('\n'));
|
|
350
389
|
return;
|
|
351
390
|
}
|
|
352
391
|
if (sub === 'quarantine') {
|
|
353
|
-
const name =
|
|
354
|
-
const action =
|
|
392
|
+
const name = commandArgs[1];
|
|
393
|
+
const action = commandArgs[2] ?? 'add';
|
|
355
394
|
if (!name) {
|
|
356
|
-
ctx.print('Usage: /plugin quarantine <name> [add|lift] [reason]');
|
|
395
|
+
ctx.print('Usage: /plugin quarantine <name> [add|lift] [reason] --yes');
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
if (!parsed.yes) {
|
|
399
|
+
requireYesFlag(ctx, `${action === 'lift' ? 'lift quarantine for' : 'quarantine'} plugin ${name}`, '/plugin quarantine <name> [add|lift] [reason] --yes');
|
|
357
400
|
return;
|
|
358
401
|
}
|
|
359
402
|
if (action === 'lift') {
|
|
@@ -361,10 +404,10 @@ export function registerIntegrationRuntimeCommands(registry: CommandRegistry): v
|
|
|
361
404
|
ctx.print(result.ok ? `Plugin '${name}' quarantine lifted. Reload to restore safe capabilities.` : `Error: ${result.error}`);
|
|
362
405
|
return;
|
|
363
406
|
}
|
|
364
|
-
const reason =
|
|
407
|
+
const reason = (action === 'add' ? commandArgs.slice(3) : commandArgs.slice(2)).join(' ') || 'quarantined by operator';
|
|
365
408
|
const result = pluginManager.quarantine(name, reason);
|
|
366
409
|
ctx.print(result.ok
|
|
367
|
-
? `Plugin '${name}' quarantined.\nReason: ${reason}\nHigh-risk capabilities revoked. Reload to fully apply. Use /plugin quarantine <name> lift to restore.`
|
|
410
|
+
? `Plugin '${name}' quarantined.\nReason: ${reason}\nHigh-risk capabilities revoked. Reload to fully apply. Use /plugin quarantine <name> lift --yes to restore.`
|
|
368
411
|
: `Error: ${result.error}`);
|
|
369
412
|
return;
|
|
370
413
|
}
|
|
@@ -372,22 +415,22 @@ export function registerIntegrationRuntimeCommands(registry: CommandRegistry): v
|
|
|
372
415
|
ctx.print(
|
|
373
416
|
'Usage: /plugin <subcommand>\n'
|
|
374
417
|
+ ' list — show installed plugins and their status\n'
|
|
375
|
-
+ ' enable <name>
|
|
376
|
-
+ ' disable <name>
|
|
377
|
-
+ ' reload
|
|
378
|
-
+ ' trust <name> <tier> [note] — set trust tier (untrusted|limited|trusted)\n'
|
|
418
|
+
+ ' enable <name> --yes — enable a plugin\n'
|
|
419
|
+
+ ' disable <name> --yes — disable a plugin\n'
|
|
420
|
+
+ ' reload --yes — reload all enabled plugins\n'
|
|
421
|
+
+ ' trust <name> <tier> [note] --yes — set trust tier (untrusted|limited|trusted)\n'
|
|
379
422
|
+ ' verify <name> — inspect a plugin manifest signature\n'
|
|
380
423
|
+ ' capabilities <name> — show capability grants and blocks\n'
|
|
381
424
|
+ ' browse [query] — browse curated local-first plugin catalog entries\n'
|
|
382
425
|
+ ' installed — list curated catalog installs with provenance receipts\n'
|
|
383
426
|
+ ' catalog-review <id> — review source, provenance, and risk for a curated plugin\n'
|
|
384
|
-
+ ' publish-local <id> <path> <summary...> — publish a local plugin directory into the curated catalog\n'
|
|
385
|
-
+ ' unpublish <id>
|
|
427
|
+
+ ' publish-local <id> <path> <summary...> --yes — publish a local plugin directory into the curated catalog\n'
|
|
428
|
+
+ ' unpublish <id> --yes — remove a local curated plugin catalog entry\n'
|
|
386
429
|
+ ' install-hint <catalog-id> — show install guidance for a curated plugin entry\n'
|
|
387
|
-
+ ' install <catalog-id> [scope] — install a local-path curated plugin into project|user scope\n'
|
|
388
|
-
+ ' uninstall <catalog-id> [scope] — remove a curated plugin install receipt and target path\n'
|
|
389
|
-
+ ' quarantine <name> [reason] — quarantine a plugin (revoke high-risk caps)\n'
|
|
390
|
-
+ ' quarantine <name> lift — lift quarantine from a plugin'
|
|
430
|
+
+ ' install <catalog-id> [scope] --yes — install a local-path curated plugin into project|user scope\n'
|
|
431
|
+
+ ' uninstall <catalog-id> [scope] --yes — remove a curated plugin install receipt and target path\n'
|
|
432
|
+
+ ' quarantine <name> [reason] --yes — quarantine a plugin (revoke high-risk caps)\n'
|
|
433
|
+
+ ' quarantine <name> lift --yes — lift quarantine from a plugin'
|
|
391
434
|
);
|
|
392
435
|
},
|
|
393
436
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { KnowledgeService } from '@pellux/goodvibes-sdk/platform/knowledge';
|
|
2
2
|
import type { CommandContext, SlashCommand } from '../command-registry.ts';
|
|
3
|
+
import { requireYesFlag, stripYesFlag } from './confirmation.ts';
|
|
3
4
|
|
|
4
5
|
const KNOWLEDGE_REVIEW_ACTIONS = ['accept', 'reject', 'resolve', 'reopen', 'edit', 'forget'] as const;
|
|
5
6
|
|
|
@@ -158,7 +159,7 @@ export const knowledgeCommand: SlashCommand = {
|
|
|
158
159
|
aliases: ['know', 'kb'],
|
|
159
160
|
description: 'Agent Knowledge/Wiki: isolated Agent-owned sources, graph, review queue, and compact prompt packets.',
|
|
160
161
|
usage: '<subcommand> [args]',
|
|
161
|
-
argsHint: 'status|ask|ingest-url|import-bookmarks|
|
|
162
|
+
argsHint: 'status|ask|ingest-url --yes|import-bookmarks --yes|list|search|get|queue|review-issue --yes',
|
|
162
163
|
handler: async (args: string[], context: CommandContext): Promise<void> => {
|
|
163
164
|
const knowledge = requireAgentKnowledgeApi(context);
|
|
164
165
|
if (!knowledge) {
|
|
@@ -169,7 +170,8 @@ export const knowledgeCommand: SlashCommand = {
|
|
|
169
170
|
return;
|
|
170
171
|
}
|
|
171
172
|
const sub = (args[0] ?? 'status').toLowerCase();
|
|
172
|
-
const
|
|
173
|
+
const confirmation = stripYesFlag(args.slice(1));
|
|
174
|
+
const rest = [...confirmation.rest];
|
|
173
175
|
const disallowedScopeFlag = findDisallowedKnowledgeScopeFlag(rest);
|
|
174
176
|
if (disallowedScopeFlag) {
|
|
175
177
|
printScopeFlagRejection(context, disallowedScopeFlag);
|
|
@@ -219,7 +221,11 @@ export const knowledgeCommand: SlashCommand = {
|
|
|
219
221
|
case 'ingest-url': {
|
|
220
222
|
const [url] = positionalArgs(rest, ['--title', '--tags', '--folder']);
|
|
221
223
|
if (!url) {
|
|
222
|
-
context.print('[knowledge] Usage: /knowledge ingest-url <url> [--title <title>] [--tags <a,b>] [--folder <path>]');
|
|
224
|
+
context.print('[knowledge] Usage: /knowledge ingest-url <url> [--title <title>] [--tags <a,b>] [--folder <path>] --yes');
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
if (!confirmation.yes) {
|
|
228
|
+
requireYesFlag(context, `ingest URL into Agent Knowledge ${url}`, '/knowledge ingest-url <url> [--title <title>] [--tags <a,b>] [--folder <path>] --yes');
|
|
223
229
|
return;
|
|
224
230
|
}
|
|
225
231
|
const result = await knowledge.ingest.url({
|
|
@@ -240,7 +246,11 @@ export const knowledgeCommand: SlashCommand = {
|
|
|
240
246
|
case 'import-bookmarks': {
|
|
241
247
|
const [path] = positionalArgs(rest);
|
|
242
248
|
if (!path) {
|
|
243
|
-
context.print('[knowledge] Usage: /knowledge import-bookmarks <path>');
|
|
249
|
+
context.print('[knowledge] Usage: /knowledge import-bookmarks <path> --yes');
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (!confirmation.yes) {
|
|
253
|
+
requireYesFlag(context, `import bookmark file into Agent Knowledge ${path}`, '/knowledge import-bookmarks <path> --yes');
|
|
244
254
|
return;
|
|
245
255
|
}
|
|
246
256
|
const result = await knowledge.ingest.bookmarksFile({ path, sessionId: context.session.runtime.sessionId });
|
|
@@ -254,7 +264,11 @@ export const knowledgeCommand: SlashCommand = {
|
|
|
254
264
|
case 'import-urls': {
|
|
255
265
|
const [path] = positionalArgs(rest);
|
|
256
266
|
if (!path) {
|
|
257
|
-
context.print('[knowledge] Usage: /knowledge import-urls <path>');
|
|
267
|
+
context.print('[knowledge] Usage: /knowledge import-urls <path> --yes');
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
if (!confirmation.yes) {
|
|
271
|
+
requireYesFlag(context, `import URL list into Agent Knowledge ${path}`, '/knowledge import-urls <path> --yes');
|
|
258
272
|
return;
|
|
259
273
|
}
|
|
260
274
|
const result = await knowledge.ingest.urlsFile({ path, sessionId: context.session.runtime.sessionId });
|
|
@@ -401,7 +415,11 @@ export const knowledgeCommand: SlashCommand = {
|
|
|
401
415
|
const [issueId, actionValue] = positionalArgs(rest, ['--reviewer', '--value']);
|
|
402
416
|
const action = actionValue?.toLowerCase();
|
|
403
417
|
if (!issueId || !action || !KNOWLEDGE_REVIEW_ACTIONS.includes(action as KnowledgeReviewAction)) {
|
|
404
|
-
context.print('[knowledge] Usage: /knowledge review-issue <issueId> <accept|reject|resolve|reopen|edit|forget> [--reviewer <name>] [--value <json-object>]');
|
|
418
|
+
context.print('[knowledge] Usage: /knowledge review-issue <issueId> <accept|reject|resolve|reopen|edit|forget> [--reviewer <name>] [--value <json-object>] --yes');
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
if (!confirmation.yes) {
|
|
422
|
+
requireYesFlag(context, `review Agent Knowledge issue ${issueId}`, '/knowledge review-issue <issueId> <action> [--reviewer <name>] [--value <json-object>] --yes');
|
|
405
423
|
return;
|
|
406
424
|
}
|
|
407
425
|
const value = readJsonObjectFlag(rest, '--value');
|
|
@@ -513,6 +531,10 @@ export const knowledgeCommand: SlashCommand = {
|
|
|
513
531
|
}
|
|
514
532
|
|
|
515
533
|
case 'reindex': {
|
|
534
|
+
if (!confirmation.yes) {
|
|
535
|
+
requireYesFlag(context, 'reindex Agent Knowledge', '/knowledge reindex --yes');
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
516
538
|
const result = await knowledge.status.reindex();
|
|
517
539
|
context.print([
|
|
518
540
|
'[knowledge] Reindex complete',
|
|
@@ -525,6 +547,10 @@ export const knowledgeCommand: SlashCommand = {
|
|
|
525
547
|
}
|
|
526
548
|
|
|
527
549
|
case 'consolidate': {
|
|
550
|
+
if (!confirmation.yes) {
|
|
551
|
+
requireYesFlag(context, 'run Agent Knowledge consolidation', '/knowledge consolidate [light|deep] --yes');
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
528
554
|
const mode = (positionalArgs(rest)[0] ?? 'light').toLowerCase();
|
|
529
555
|
const jobId = mode === 'deep' ? 'knowledge-deep-consolidation' : 'knowledge-light-consolidation';
|
|
530
556
|
const run = await knowledge.jobs.run(jobId, { mode: 'inline' });
|
|
@@ -537,22 +563,22 @@ export const knowledgeCommand: SlashCommand = {
|
|
|
537
563
|
'Usage: /knowledge <subcommand>',
|
|
538
564
|
' status',
|
|
539
565
|
' ask <query> [--limit <n>] [--mode <concise|standard|detailed>]',
|
|
540
|
-
' ingest-url <url> [--title <title>] [--tags <a,b>] [--folder <path>]',
|
|
541
|
-
' import-bookmarks <path>',
|
|
542
|
-
' import-urls <path>',
|
|
566
|
+
' ingest-url <url> [--title <title>] [--tags <a,b>] [--folder <path>] --yes',
|
|
567
|
+
' import-bookmarks <path> --yes',
|
|
568
|
+
' import-urls <path> --yes',
|
|
543
569
|
' list [--kind <sources|nodes|issues>] [--limit <n>]',
|
|
544
570
|
' search <query> [--limit <n>]',
|
|
545
571
|
' get <id>',
|
|
546
572
|
' queue [limit]',
|
|
547
|
-
' review-issue <issueId> <accept|reject|resolve|reopen|edit|forget> [--reviewer <name>] [--value <json-object>]',
|
|
573
|
+
' review-issue <issueId> <accept|reject|resolve|reopen|edit|forget> [--reviewer <name>] [--value <json-object>] --yes',
|
|
548
574
|
' candidates [limit]',
|
|
549
575
|
' reports [limit]',
|
|
550
576
|
' schedules',
|
|
551
577
|
' lint',
|
|
552
578
|
' packet <task...> [--scope <path> ...]',
|
|
553
579
|
' explain <task...> [--scope <path> ...]',
|
|
554
|
-
' reindex',
|
|
555
|
-
' consolidate [light|deep]',
|
|
580
|
+
' reindex --yes',
|
|
581
|
+
' consolidate [light|deep] --yes',
|
|
556
582
|
].join('\n'));
|
|
557
583
|
}
|
|
558
584
|
},
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import type { CommandContext, CommandRegistry } from '../command-registry.ts';
|
|
2
2
|
import { openCommandPanel, requireLocalUserAuthManager } from './runtime-services.ts';
|
|
3
3
|
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
4
|
+
import { requireYesFlag, stripYesFlag } from './confirmation.ts';
|
|
4
5
|
|
|
5
6
|
function formatRoles(roles: readonly string[]): string {
|
|
6
7
|
return roles.length > 0 ? roles.join(', ') : '(none)';
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
export function handleLocalAuthCommand(args: string[], ctx: CommandContext): void {
|
|
10
|
-
const
|
|
11
|
+
const parsed = stripYesFlag(args);
|
|
12
|
+
const commandArgs = [...parsed.rest];
|
|
13
|
+
const sub = (commandArgs[0] ?? 'review').toLowerCase();
|
|
11
14
|
const auth = requireLocalUserAuthManager(ctx);
|
|
12
15
|
if (sub === 'panel' || sub === 'open') {
|
|
13
16
|
openCommandPanel(ctx, 'local-auth');
|
|
@@ -15,11 +18,15 @@ export function handleLocalAuthCommand(args: string[], ctx: CommandContext): voi
|
|
|
15
18
|
}
|
|
16
19
|
|
|
17
20
|
if (sub === 'add-user') {
|
|
18
|
-
const username =
|
|
19
|
-
const password =
|
|
20
|
-
const roles =
|
|
21
|
+
const username = commandArgs[1];
|
|
22
|
+
const password = commandArgs[2];
|
|
23
|
+
const roles = commandArgs[3]?.split(',').map((value) => value.trim()).filter(Boolean) ?? ['admin'];
|
|
21
24
|
if (!username || !password) {
|
|
22
|
-
ctx.print('Usage: /auth local add-user <username> <password> [roles]');
|
|
25
|
+
ctx.print('Usage: /auth local add-user <username> <password> [roles] --yes');
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (!parsed.yes) {
|
|
29
|
+
requireYesFlag(ctx, `add local auth user ${username}`, '/auth local add-user <username> <password> [roles] --yes');
|
|
23
30
|
return;
|
|
24
31
|
}
|
|
25
32
|
try {
|
|
@@ -32,9 +39,13 @@ export function handleLocalAuthCommand(args: string[], ctx: CommandContext): voi
|
|
|
32
39
|
}
|
|
33
40
|
|
|
34
41
|
if (sub === 'delete-user') {
|
|
35
|
-
const username =
|
|
42
|
+
const username = commandArgs[1];
|
|
36
43
|
if (!username) {
|
|
37
|
-
ctx.print('Usage: /auth local delete-user <username>');
|
|
44
|
+
ctx.print('Usage: /auth local delete-user <username> --yes');
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (!parsed.yes) {
|
|
48
|
+
requireYesFlag(ctx, `delete local auth user ${username}`, '/auth local delete-user <username> --yes');
|
|
38
49
|
return;
|
|
39
50
|
}
|
|
40
51
|
try {
|
|
@@ -47,10 +58,14 @@ export function handleLocalAuthCommand(args: string[], ctx: CommandContext): voi
|
|
|
47
58
|
}
|
|
48
59
|
|
|
49
60
|
if (sub === 'rotate-password') {
|
|
50
|
-
const username =
|
|
51
|
-
const password =
|
|
61
|
+
const username = commandArgs[1];
|
|
62
|
+
const password = commandArgs[2];
|
|
52
63
|
if (!username || !password) {
|
|
53
|
-
ctx.print('Usage: /auth local rotate-password <username> <password>');
|
|
64
|
+
ctx.print('Usage: /auth local rotate-password <username> <password> --yes');
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (!parsed.yes) {
|
|
68
|
+
requireYesFlag(ctx, `rotate password for local auth user ${username}`, '/auth local rotate-password <username> <password> --yes');
|
|
54
69
|
return;
|
|
55
70
|
}
|
|
56
71
|
try {
|
|
@@ -63,9 +78,13 @@ export function handleLocalAuthCommand(args: string[], ctx: CommandContext): voi
|
|
|
63
78
|
}
|
|
64
79
|
|
|
65
80
|
if (sub === 'revoke-session') {
|
|
66
|
-
const token =
|
|
81
|
+
const token = commandArgs[1];
|
|
67
82
|
if (!token) {
|
|
68
|
-
ctx.print('Usage: /auth local revoke-session <token-or-fingerprint>');
|
|
83
|
+
ctx.print('Usage: /auth local revoke-session <token-or-fingerprint> --yes');
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (!parsed.yes) {
|
|
87
|
+
requireYesFlag(ctx, 'revoke local auth session', '/auth local revoke-session <token-or-fingerprint> --yes');
|
|
69
88
|
return;
|
|
70
89
|
}
|
|
71
90
|
ctx.print(auth.revokeSession(token) ? `Revoked session ${token.slice(0, 12)}…` : `Unknown session token or fingerprint: ${token}`);
|
|
@@ -73,6 +92,10 @@ export function handleLocalAuthCommand(args: string[], ctx: CommandContext): voi
|
|
|
73
92
|
}
|
|
74
93
|
|
|
75
94
|
if (sub === 'clear-bootstrap-file') {
|
|
95
|
+
if (!parsed.yes) {
|
|
96
|
+
requireYesFlag(ctx, 'clear the local auth bootstrap credential file', '/auth local clear-bootstrap-file --yes');
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
76
99
|
ctx.print(auth.clearBootstrapCredentialFile()
|
|
77
100
|
? 'Removed bootstrap credential file.'
|
|
78
101
|
: 'No bootstrap credential file was present.');
|
|
@@ -97,7 +120,7 @@ export function registerLocalAuthRuntimeCommands(registry: CommandRegistry): voi
|
|
|
97
120
|
name: 'local-auth',
|
|
98
121
|
aliases: ['auth-local'],
|
|
99
122
|
description: 'Inspect and manage local daemon/listener auth users, sessions, and bootstrap credentials',
|
|
100
|
-
usage: '[review|panel|add-user <username> <password> [roles]|delete-user <username
|
|
123
|
+
usage: '[review|panel|add-user <username> <password> [roles] --yes|delete-user <username> --yes|rotate-password <username> <password> --yes|revoke-session <token-or-fingerprint> --yes|clear-bootstrap-file --yes]',
|
|
101
124
|
handler(args, ctx) {
|
|
102
125
|
handleLocalAuthCommand(args, ctx);
|
|
103
126
|
},
|
|
@@ -7,6 +7,7 @@ import type { CustomProviderConfig } from '@pellux/goodvibes-sdk/platform/provid
|
|
|
7
7
|
import { requireProviderApi, requireShellPaths } from './runtime-services.ts';
|
|
8
8
|
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
9
9
|
import { GOODVIBES_AGENT_SURFACE_ROOT } from '../../config/surface.ts';
|
|
10
|
+
import { requireYesFlag, stripYesFlag } from './confirmation.ts';
|
|
10
11
|
|
|
11
12
|
function isValidProviderName(name: string): boolean {
|
|
12
13
|
return /^[a-zA-Z0-9_-]+$/.test(name);
|
|
@@ -17,17 +18,23 @@ export function registerLocalProviderRuntimeCommands(registry: CommandRegistry):
|
|
|
17
18
|
name: 'provider',
|
|
18
19
|
aliases: ['p'],
|
|
19
20
|
description: 'Switch provider or manage custom providers (add/remove)',
|
|
20
|
-
usage: '[add <name> <baseURL> [apiKey] | remove <name> | <provider-name>]',
|
|
21
|
-
argsHint: '[add|remove
|
|
21
|
+
usage: '[add <name> <baseURL> [apiKey] --yes | remove <name> --yes | <provider-name>]',
|
|
22
|
+
argsHint: '[name|add --yes|remove --yes]',
|
|
22
23
|
async handler(args, ctx) {
|
|
24
|
+
const parsed = stripYesFlag(args);
|
|
25
|
+
const commandArgs = [...parsed.rest];
|
|
23
26
|
const shellPaths = requireShellPaths(ctx);
|
|
24
|
-
if (
|
|
25
|
-
const addArgs =
|
|
27
|
+
if (commandArgs[0] === 'add') {
|
|
28
|
+
const addArgs = commandArgs.slice(1);
|
|
26
29
|
if (addArgs.length < 2) {
|
|
27
|
-
ctx.print('Usage: /provider add <name> <baseURL> [apiKey]\nExample: /provider add my-server http://192.168.0.85:8001/v1');
|
|
30
|
+
ctx.print('Usage: /provider add <name> <baseURL> [apiKey] --yes\nExample: /provider add my-server http://192.168.0.85:8001/v1 --yes');
|
|
28
31
|
return;
|
|
29
32
|
}
|
|
30
33
|
const [name, baseURL, apiKey] = addArgs;
|
|
34
|
+
if (!parsed.yes) {
|
|
35
|
+
requireYesFlag(ctx, `add custom provider ${name}`, '/provider add <name> <baseURL> [apiKey] --yes');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
31
38
|
if (!isValidProviderName(name)) {
|
|
32
39
|
ctx.print('Error: Provider name must contain only letters, numbers, hyphens, and underscores.');
|
|
33
40
|
return;
|
|
@@ -42,7 +49,7 @@ export function registerLocalProviderRuntimeCommands(registry: CommandRegistry):
|
|
|
42
49
|
const providersDir = shellPaths.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, 'providers');
|
|
43
50
|
const providerFile = join(providersDir, `${name}.json`);
|
|
44
51
|
if (existsSync(providerFile)) {
|
|
45
|
-
ctx.print(`Error: Provider '${name}' already exists at ${providerFile}\nRemove it first with: /provider remove ${name}`);
|
|
52
|
+
ctx.print(`Error: Provider '${name}' already exists at ${providerFile}\nRemove it first with: /provider remove ${name} --yes`);
|
|
46
53
|
return;
|
|
47
54
|
}
|
|
48
55
|
|
|
@@ -111,10 +118,14 @@ export function registerLocalProviderRuntimeCommands(registry: CommandRegistry):
|
|
|
111
118
|
return;
|
|
112
119
|
}
|
|
113
120
|
|
|
114
|
-
if (
|
|
115
|
-
const name =
|
|
121
|
+
if (commandArgs[0] === 'remove' || commandArgs[0] === 'rm') {
|
|
122
|
+
const name = commandArgs[1];
|
|
116
123
|
if (!name) {
|
|
117
|
-
ctx.print('Usage: /provider remove <name>');
|
|
124
|
+
ctx.print('Usage: /provider remove <name> --yes');
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (!parsed.yes) {
|
|
128
|
+
requireYesFlag(ctx, `remove custom provider ${name}`, '/provider remove <name> --yes');
|
|
118
129
|
return;
|
|
119
130
|
}
|
|
120
131
|
if (!isValidProviderName(name)) {
|
|
@@ -135,7 +146,7 @@ export function registerLocalProviderRuntimeCommands(registry: CommandRegistry):
|
|
|
135
146
|
return;
|
|
136
147
|
}
|
|
137
148
|
|
|
138
|
-
if (
|
|
149
|
+
if (commandArgs.length === 0) {
|
|
139
150
|
if (ctx.openProviderPicker) {
|
|
140
151
|
ctx.openProviderPicker();
|
|
141
152
|
return;
|
|
@@ -145,7 +156,7 @@ export function registerLocalProviderRuntimeCommands(registry: CommandRegistry):
|
|
|
145
156
|
return;
|
|
146
157
|
}
|
|
147
158
|
|
|
148
|
-
const providerName =
|
|
159
|
+
const providerName = commandArgs[0];
|
|
149
160
|
const providerApi = requireProviderApi(ctx);
|
|
150
161
|
const selectable = await providerApi.listModels({
|
|
151
162
|
providerId: providerName,
|