@pellux/goodvibes-agent 0.1.10 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/package.json +1 -1
  3. package/src/cli/agent-knowledge-command.ts +30 -3
  4. package/src/cli/help.ts +2 -2
  5. package/src/input/commands/cloudflare-runtime.ts +20 -5
  6. package/src/input/commands/confirmation.ts +24 -0
  7. package/src/input/commands/discovery-runtime.ts +16 -7
  8. package/src/input/commands/eval.ts +27 -14
  9. package/src/input/commands/experience-runtime.ts +65 -26
  10. package/src/input/commands/health-runtime.ts +1 -1
  11. package/src/input/commands/hooks-runtime.ts +50 -19
  12. package/src/input/commands/incident-runtime.ts +17 -6
  13. package/src/input/commands/integration-runtime.ts +93 -50
  14. package/src/input/commands/knowledge.ts +38 -12
  15. package/src/input/commands/local-auth-runtime.ts +36 -13
  16. package/src/input/commands/local-provider-runtime.ts +22 -11
  17. package/src/input/commands/local-runtime.ts +21 -11
  18. package/src/input/commands/local-setup.ts +35 -16
  19. package/src/input/commands/managed-runtime.ts +51 -20
  20. package/src/input/commands/marketplace-runtime.ts +31 -16
  21. package/src/input/commands/mcp-runtime.ts +65 -34
  22. package/src/input/commands/memory-product-runtime.ts +72 -35
  23. package/src/input/commands/memory.ts +9 -9
  24. package/src/input/commands/notify-runtime.ts +27 -8
  25. package/src/input/commands/operator-runtime.ts +85 -17
  26. package/src/input/commands/planning-runtime.ts +14 -2
  27. package/src/input/commands/platform-access-runtime.ts +88 -45
  28. package/src/input/commands/platform-services-runtime.ts +51 -25
  29. package/src/input/commands/product-runtime.ts +54 -27
  30. package/src/input/commands/profile-sync-runtime.ts +17 -6
  31. package/src/input/commands/recall-bundle.ts +38 -17
  32. package/src/input/commands/recall-query.ts +15 -4
  33. package/src/input/commands/recall-review.ts +9 -3
  34. package/src/input/commands/remote-runtime-setup.ts +45 -18
  35. package/src/input/commands/remote-runtime.ts +25 -9
  36. package/src/input/commands/replay-runtime.ts +9 -2
  37. package/src/input/commands/services-runtime.ts +21 -10
  38. package/src/input/commands/session-content.ts +53 -51
  39. package/src/input/commands/session-workflow.ts +10 -4
  40. package/src/input/commands/session.ts +1 -1
  41. package/src/input/commands/settings-sync-runtime.ts +40 -17
  42. package/src/input/commands/share-runtime.ts +12 -4
  43. package/src/input/commands/shell-core.ts +3 -3
  44. package/src/input/commands/subscription-runtime.ts +35 -20
  45. package/src/input/commands/teleport-runtime.ts +16 -5
  46. package/src/input/commands/work-plan-runtime.ts +23 -12
  47. package/src/input/handler-content-actions.ts +11 -62
  48. package/src/input/handler-interactions.ts +1 -1
  49. package/src/input/handler-onboarding-cloudflare.ts +48 -117
  50. package/src/input/keybindings.ts +1 -1
  51. package/src/input/mcp-workspace.ts +25 -49
  52. package/src/input/onboarding/onboarding-wizard-cloudflare-step.ts +8 -8
  53. package/src/input/onboarding/onboarding-wizard-cloudflare.ts +1 -6
  54. package/src/input/profile-picker-modal.ts +13 -31
  55. package/src/input/session-picker-modal.ts +4 -30
  56. package/src/input/settings-modal-subscriptions.ts +3 -3
  57. package/src/panels/incident-review-panel.ts +1 -1
  58. package/src/panels/local-auth-panel.ts +4 -4
  59. package/src/panels/provider-account-snapshot.ts +1 -1
  60. package/src/panels/provider-health-domains.ts +2 -2
  61. package/src/panels/settings-sync-panel.ts +2 -2
  62. package/src/panels/subscription-panel.ts +7 -7
  63. package/src/renderer/block-actions.ts +1 -1
  64. package/src/renderer/help-overlay.ts +2 -2
  65. package/src/renderer/mcp-workspace.ts +12 -12
  66. package/src/renderer/profile-picker-modal.ts +3 -11
  67. package/src/renderer/session-picker-modal.ts +2 -10
  68. package/src/verification/live-verifier.ts +100 -68
  69. package/src/version.ts +1 -1
@@ -6,6 +6,7 @@ import { listBuiltinSubscriptionProviders } from '@pellux/goodvibes-sdk/platform
6
6
  import { handleLocalAuthCommand } from './local-auth-runtime.ts';
7
7
  import { buildAuthInspectionSnapshot, inspectProviderAuth } from '@/runtime/index.ts';
8
8
  import { requireProfileManager, requireSecretsManager, requireServiceRegistry, requireShellPaths, requireSubscriptionManager } from './runtime-services.ts';
9
+ import { requireYesFlag, stripYesFlag } from './confirmation.ts';
9
10
 
10
11
  interface InstallBundle {
11
12
  readonly version: 1;
@@ -81,61 +82,79 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
81
82
  registry.register({
82
83
  name: 'login',
83
84
  description: 'Front-door login flow for provider subscriptions and local service sessions',
84
- usage: '[provider <name> start|finish <code>|service <daemon|listener> <baseUrl> <username> <password> [secretKey]]',
85
+ usage: '[provider <name> start|finish <code> --yes|service <daemon|listener> <baseUrl> <username> <password> [secretKey] --yes]',
85
86
  async handler(args, ctx) {
87
+ const parsed = stripYesFlag(args);
88
+ const commandArgs = [...parsed.rest];
86
89
  const shellPaths = requireShellPaths(ctx);
87
- const target = (args[0] ?? '').toLowerCase();
90
+ const target = (commandArgs[0] ?? '').toLowerCase();
88
91
  if (target === 'provider') {
89
- const provider = args[1];
90
- const mode = args[2]?.toLowerCase();
92
+ const provider = commandArgs[1];
93
+ const mode = commandArgs[2]?.toLowerCase();
91
94
  if (!provider || !mode) {
92
- ctx.print('Usage: /login provider <name> start|finish <code>');
95
+ ctx.print('Usage: /login provider <name> start|finish <code> --yes');
96
+ return;
97
+ }
98
+ if (!parsed.yes) {
99
+ requireYesFlag(ctx, `${mode} provider subscription login for ${provider}`, '/login provider <name> start|finish <code> --yes');
93
100
  return;
94
101
  }
95
102
  if (ctx.executeCommand) {
96
- await ctx.executeCommand('subscription', ['login', provider, mode, ...args.slice(3)]);
103
+ await ctx.executeCommand('subscription', ['login', provider, mode, ...commandArgs.slice(3), '--yes']);
97
104
  return;
98
105
  }
99
- ctx.print(`Use /subscription login ${provider} ${mode}${args[3] ? ` ${args[3]}` : ''}`);
106
+ ctx.print(`Use /subscription login ${provider} ${mode}${commandArgs[3] ? ` ${commandArgs[3]}` : ''} --yes`);
100
107
  return;
101
108
  }
102
109
  if (target === 'service') {
110
+ if (!parsed.yes) {
111
+ requireYesFlag(ctx, 'store a local service session token', '/login service <daemon|listener> <baseUrl> <username> <password> [secretKey] --yes');
112
+ return;
113
+ }
103
114
  if (ctx.executeCommand) {
104
- await ctx.executeCommand('auth', ['login', ...args.slice(1)]);
115
+ await ctx.executeCommand('auth', ['login', ...commandArgs.slice(1), '--yes']);
105
116
  return;
106
117
  }
107
- ctx.print('Use /auth login <daemon|listener> <baseUrl> <username> <password> [secretKey]');
118
+ ctx.print('Use /auth login <daemon|listener> <baseUrl> <username> <password> [secretKey] --yes');
108
119
  return;
109
120
  }
110
- ctx.print('Usage: /login [provider <name> start|finish <code>|service <daemon|listener> <baseUrl> <username> <password> [secretKey]]');
121
+ ctx.print('Usage: /login [provider <name> start|finish <code> --yes|service <daemon|listener> <baseUrl> <username> <password> [secretKey] --yes]');
111
122
  },
112
123
  });
113
124
 
114
125
  registry.register({
115
126
  name: 'logout',
116
127
  description: 'Front-door logout flow for provider subscription sessions and supported overrides',
117
- usage: 'provider <name>',
128
+ usage: 'provider <name> --yes',
118
129
  async handler(args, ctx) {
119
- const target = (args[0] ?? '').toLowerCase();
120
- if (target !== 'provider' || !args[1]) {
121
- ctx.print('Usage: /logout provider <name>');
130
+ const parsed = stripYesFlag(args);
131
+ const commandArgs = [...parsed.rest];
132
+ const target = (commandArgs[0] ?? '').toLowerCase();
133
+ if (target !== 'provider' || !commandArgs[1]) {
134
+ ctx.print('Usage: /logout provider <name> --yes');
135
+ return;
136
+ }
137
+ if (!parsed.yes) {
138
+ requireYesFlag(ctx, `log out provider subscription ${commandArgs[1]}`, '/logout provider <name> --yes');
122
139
  return;
123
140
  }
124
141
  if (ctx.executeCommand) {
125
- await ctx.executeCommand('subscription', ['logout', args[1]]);
142
+ await ctx.executeCommand('subscription', ['logout', commandArgs[1], '--yes']);
126
143
  return;
127
144
  }
128
- ctx.print(`Use /subscription logout ${args[1]}`);
145
+ ctx.print(`Use /subscription logout ${commandArgs[1]} --yes`);
129
146
  },
130
147
  });
131
148
 
132
149
  registry.register({
133
150
  name: 'install',
134
151
  description: 'Review install posture and export portable install bundles',
135
- usage: '[review|bundle export <path>|bundle inspect <path>]',
152
+ usage: '[review|bundle export <path> --yes|bundle inspect <path>]',
136
153
  async handler(args, ctx) {
154
+ const parsed = stripYesFlag(args);
155
+ const commandArgs = [...parsed.rest];
137
156
  const shellPaths = requireShellPaths(ctx);
138
- const sub = args[0] ?? 'review';
157
+ const sub = commandArgs[0] ?? 'review';
139
158
  if (sub === 'review') {
140
159
  const profiles = requireProfileManager(ctx).list();
141
160
  const secretKeys = await requireSecretsManager(ctx).list();
@@ -149,14 +168,18 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
149
168
  return;
150
169
  }
151
170
  if (sub === 'bundle') {
152
- const mode = args[1];
153
- const pathArg = args[2];
171
+ const mode = commandArgs[1];
172
+ const pathArg = commandArgs[2];
154
173
  if ((mode === 'export' || mode === 'inspect') && !pathArg) {
155
- ctx.print(`Usage: /install bundle ${mode} <path>`);
174
+ ctx.print(`Usage: /install bundle ${mode} <path>${mode === 'export' ? ' --yes' : ''}`);
156
175
  return;
157
176
  }
158
177
  const targetPath = shellPaths.resolveWorkspacePath(pathArg!);
159
178
  if (mode === 'export') {
179
+ if (!parsed.yes) {
180
+ requireYesFlag(ctx, `export install bundle to ${pathArg}`, '/install bundle export <path> --yes');
181
+ return;
182
+ }
160
183
  const profiles = requireProfileManager(ctx).list();
161
184
  const secretKeys = await requireSecretsManager(ctx).list();
162
185
  const bundle: InstallBundle = {
@@ -185,7 +208,7 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
185
208
  return;
186
209
  }
187
210
  }
188
- ctx.print('Usage: /install [review|bundle export <path>|bundle inspect <path>]');
211
+ ctx.print('Usage: /install [review|bundle export <path> --yes|bundle inspect <path>]');
189
212
  },
190
213
  });
191
214
 
@@ -193,10 +216,12 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
193
216
  name: 'update',
194
217
  aliases: ['upgrade'],
195
218
  description: 'Review update posture, choose release channel guidance, and package portable update bundles',
196
- usage: '[review|channel <stable|preview>|bundle export <path>|bundle inspect <path>]',
219
+ usage: '[review|channel <stable|preview> --yes|bundle export <path> --yes|bundle inspect <path>]',
197
220
  handler(args, ctx) {
221
+ const parsed = stripYesFlag(args);
222
+ const commandArgs = [...parsed.rest];
198
223
  const shellPaths = requireShellPaths(ctx);
199
- const sub = args[0] ?? 'review';
224
+ const sub = commandArgs[0] ?? 'review';
200
225
  const subscriptions = requireSubscriptionManager(ctx);
201
226
  const serviceRegistry = requireServiceRegistry(ctx);
202
227
  const secretsManager = requireSecretsManager(ctx);
@@ -216,14 +241,18 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
216
241
  ` built-in subscription providers: ${builtinProviders.length}${builtinProviders.length > 0 ? ` (${builtinProviders.join(', ')})` : ''}`,
217
242
  ` active subscriptions: ${activeSubscriptions.length}${activeSubscriptions.length > 0 ? ` (${activeSubscriptions.join(', ')})` : ''}`,
218
243
  ` sandbox profile: ${sandboxProfile}`,
219
- ' use /update channel <stable|preview> to change release posture',
244
+ ' use /update channel <stable|preview> --yes to change release posture',
220
245
  ].join('\n'));
221
246
  return;
222
247
  }
223
248
  if (sub === 'channel') {
224
- const channel = args[1];
249
+ const channel = commandArgs[1];
225
250
  if (channel !== 'stable' && channel !== 'preview') {
226
- ctx.print('Usage: /update channel <stable|preview>');
251
+ ctx.print('Usage: /update channel <stable|preview> --yes');
252
+ return;
253
+ }
254
+ if (!parsed.yes) {
255
+ requireYesFlag(ctx, `set update channel to ${channel}`, '/update channel <stable|preview> --yes');
227
256
  return;
228
257
  }
229
258
  ctx.platform.configManager.setDynamic('release.channel', channel);
@@ -231,14 +260,18 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
231
260
  return;
232
261
  }
233
262
  if (sub === 'bundle') {
234
- const mode = args[1];
235
- const pathArg = args[2];
263
+ const mode = commandArgs[1];
264
+ const pathArg = commandArgs[2];
236
265
  if ((mode === 'export' || mode === 'inspect') && !pathArg) {
237
- ctx.print(`Usage: /update bundle ${mode} <path>`);
266
+ ctx.print(`Usage: /update bundle ${mode} <path>${mode === 'export' ? ' --yes' : ''}`);
238
267
  return;
239
268
  }
240
269
  const targetPath = shellPaths.resolveWorkspacePath(pathArg!);
241
270
  if (mode === 'export') {
271
+ if (!parsed.yes) {
272
+ requireYesFlag(ctx, `export update bundle to ${pathArg}`, '/update bundle export <path> --yes');
273
+ return;
274
+ }
242
275
  const bundle: UpdateBundle = {
243
276
  version: 1,
244
277
  exportedAt: Date.now(),
@@ -262,17 +295,19 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
262
295
  return;
263
296
  }
264
297
  }
265
- ctx.print('Usage: /update [review|channel <stable|preview>|bundle export <path>|bundle inspect <path>]');
298
+ ctx.print('Usage: /update [review|channel <stable|preview> --yes|bundle export <path> --yes|bundle inspect <path>]');
266
299
  },
267
300
  });
268
301
 
269
302
  registry.register({
270
303
  name: 'auth',
271
304
  description: 'Review auth posture and exchange session login tokens with local services',
272
- usage: '[review|show <provider>|repair <provider>|bundle export <path>|bundle inspect <path>|login <daemon|listener> <baseUrl> <username> <password> [secretKey]|local <review|panel|add-user|delete-user|rotate-password|revoke-session|clear-bootstrap-file>]',
305
+ usage: '[review|show <provider>|repair <provider>|bundle export <path> --yes|bundle inspect <path>|login <daemon|listener> <baseUrl> <username> <password> [secretKey] --yes|local <review|panel|add-user --yes|delete-user --yes|rotate-password --yes|revoke-session --yes|clear-bootstrap-file --yes>]',
273
306
  async handler(args, ctx) {
307
+ const parsed = stripYesFlag(args);
308
+ const commandArgs = [...parsed.rest];
274
309
  const shellPaths = requireShellPaths(ctx);
275
- const sub = args[0] ?? 'review';
310
+ const sub = commandArgs[0] ?? 'review';
276
311
  const subscriptions = requireSubscriptionManager(ctx);
277
312
  const serviceRegistry = requireServiceRegistry(ctx);
278
313
  const secretsManager = requireSecretsManager(ctx);
@@ -301,7 +336,7 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
301
336
  }
302
337
 
303
338
  if (sub === 'show') {
304
- const provider = args[1];
339
+ const provider = commandArgs[1];
305
340
  if (!provider) {
306
341
  ctx.print('Usage: /auth show <provider>');
307
342
  return;
@@ -331,7 +366,7 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
331
366
  }
332
367
 
333
368
  if (sub === 'repair') {
334
- const provider = args[1];
369
+ const provider = commandArgs[1];
335
370
  if (!provider) {
336
371
  ctx.print('Usage: /auth repair <provider>');
337
372
  return;
@@ -355,14 +390,18 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
355
390
  }
356
391
 
357
392
  if (sub === 'bundle') {
358
- const mode = args[1];
359
- const pathArg = args[2];
393
+ const mode = commandArgs[1];
394
+ const pathArg = commandArgs[2];
360
395
  if ((mode === 'export' || mode === 'inspect') && !pathArg) {
361
- ctx.print(`Usage: /auth bundle ${mode} <path>`);
396
+ ctx.print(`Usage: /auth bundle ${mode} <path>${mode === 'export' ? ' --yes' : ''}`);
362
397
  return;
363
398
  }
364
399
  const targetPath = shellPaths.resolveWorkspacePath(pathArg!);
365
400
  if (mode === 'export') {
401
+ if (!parsed.yes) {
402
+ requireYesFlag(ctx, `export auth review bundle to ${pathArg}`, '/auth bundle export <path> --yes');
403
+ return;
404
+ }
366
405
  const secretKeys = await secretsManager.list();
367
406
  const bundle: AuthReviewBundle = {
368
407
  version: 1,
@@ -386,13 +425,17 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
386
425
  }
387
426
 
388
427
  if (sub === 'login') {
389
- const target = args[1];
390
- const baseUrl = args[2];
391
- const username = args[3];
392
- const password = args[4];
393
- const secretKey = args[5] ?? `${target?.toUpperCase() ?? 'SERVICE'}_SESSION_TOKEN`;
428
+ const target = commandArgs[1];
429
+ const baseUrl = commandArgs[2];
430
+ const username = commandArgs[3];
431
+ const password = commandArgs[4];
432
+ const secretKey = commandArgs[5] ?? `${target?.toUpperCase() ?? 'SERVICE'}_SESSION_TOKEN`;
394
433
  if ((target !== 'daemon' && target !== 'listener') || !baseUrl || !username || !password) {
395
- ctx.print('Usage: /auth login <daemon|listener> <baseUrl> <username> <password> [secretKey]');
434
+ ctx.print('Usage: /auth login <daemon|listener> <baseUrl> <username> <password> [secretKey] --yes');
435
+ return;
436
+ }
437
+ if (!parsed.yes) {
438
+ requireYesFlag(ctx, `store ${target} session token`, '/auth login <daemon|listener> <baseUrl> <username> <password> [secretKey] --yes');
396
439
  return;
397
440
  }
398
441
  const url = new URL('/login', baseUrl).toString();
@@ -416,7 +459,7 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
416
459
  return;
417
460
  }
418
461
 
419
- ctx.print('Usage: /auth [review|show <provider>|bundle export <path>|bundle inspect <path>|login <daemon|listener> <baseUrl> <username> <password> [secretKey]|local <review|panel|add-user|delete-user|rotate-password|revoke-session|clear-bootstrap-file>]');
462
+ ctx.print('Usage: /auth [review|show <provider>|bundle export <path> --yes|bundle inspect <path>|login <daemon|listener> <baseUrl> <username> <password> [secretKey] --yes|local <review|panel|add-user --yes|delete-user --yes|rotate-password --yes|revoke-session --yes|clear-bootstrap-file --yes>]');
420
463
  },
421
464
  });
422
465
  }
@@ -2,6 +2,7 @@ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
2
  import { dirname, resolve } from 'node:path';
3
3
  import type { CommandRegistry } from '../command-registry.ts';
4
4
  import { requireSecretsManager, requireShellPaths } from './runtime-services.ts';
5
+ import { requireYesFlag, stripYesFlag } from './confirmation.ts';
5
6
 
6
7
  interface SecureStorageBundle {
7
8
  readonly version: 1;
@@ -58,11 +59,13 @@ export function registerPlatformServicesRuntimeCommands(registry: CommandRegistr
58
59
  registry.register({
59
60
  name: 'storage',
60
61
  description: 'Review secure storage posture and export portable storage metadata bundles',
61
- usage: '[review|list|delete <key>|bundle export <path>|bundle inspect <path>]',
62
+ usage: '[review|list|delete <key> --yes|bundle export <path> --yes|bundle inspect <path>]',
62
63
  async handler(args, ctx) {
64
+ const parsed = stripYesFlag(args);
65
+ const commandArgs = [...parsed.rest];
63
66
  const shellPaths = requireShellPaths(ctx);
64
67
  const manager = requireSecretsManager(ctx);
65
- const sub = args[0] ?? 'review';
68
+ const sub = commandArgs[0] ?? 'review';
66
69
  const review = await manager.inspect();
67
70
  const storedKeys = await manager.list();
68
71
  const detailedKeys = await manager.listDetailed();
@@ -88,9 +91,13 @@ export function registerPlatformServicesRuntimeCommands(registry: CommandRegistr
88
91
  return;
89
92
  }
90
93
  if (sub === 'delete') {
91
- const key = args[1];
94
+ const key = commandArgs[1];
92
95
  if (!key) {
93
- ctx.print('Usage: /storage delete <key>');
96
+ ctx.print('Usage: /storage delete <key> --yes');
97
+ return;
98
+ }
99
+ if (!parsed.yes) {
100
+ requireYesFlag(ctx, `delete secure storage key ${key}`, '/storage delete <key> --yes');
94
101
  return;
95
102
  }
96
103
  await manager.delete(key);
@@ -98,14 +105,18 @@ export function registerPlatformServicesRuntimeCommands(registry: CommandRegistr
98
105
  return;
99
106
  }
100
107
  if (sub === 'bundle') {
101
- const mode = args[1];
102
- const pathArg = args[2];
108
+ const mode = commandArgs[1];
109
+ const pathArg = commandArgs[2];
103
110
  if ((mode === 'export' || mode === 'inspect') && !pathArg) {
104
- ctx.print(`Usage: /storage bundle ${mode} <path>`);
111
+ ctx.print(`Usage: /storage bundle ${mode} <path>${mode === 'export' ? ' --yes' : ''}`);
105
112
  return;
106
113
  }
107
- const targetPath = shellPaths.resolveWorkspacePath(pathArg!);
108
114
  if (mode === 'export') {
115
+ if (!parsed.yes) {
116
+ requireYesFlag(ctx, `export secure storage metadata bundle to ${pathArg}`, '/storage bundle export <path> --yes');
117
+ return;
118
+ }
119
+ const targetPath = shellPaths.resolveWorkspacePath(pathArg!);
109
120
  const bundle: SecureStorageBundle = {
110
121
  version: 1,
111
122
  exportedAt: Date.now(),
@@ -118,12 +129,13 @@ export function registerPlatformServicesRuntimeCommands(registry: CommandRegistr
118
129
  return;
119
130
  }
120
131
  if (mode === 'inspect') {
132
+ const targetPath = shellPaths.resolveWorkspacePath(pathArg!);
121
133
  const bundle = JSON.parse(readFileSync(targetPath, 'utf-8')) as SecureStorageBundle;
122
134
  ctx.print(inspectStorageBundle(bundle));
123
135
  return;
124
136
  }
125
137
  }
126
- ctx.print('Usage: /storage [review|list|delete <key>|bundle export <path>|bundle inspect <path>]');
138
+ ctx.print('Usage: /storage [review|list|delete <key> --yes|bundle export <path> --yes|bundle inspect <path>]');
127
139
  },
128
140
  });
129
141
 
@@ -131,10 +143,12 @@ export function registerPlatformServicesRuntimeCommands(registry: CommandRegistr
131
143
  name: 'helpers',
132
144
  aliases: ['integration-api'],
133
145
  description: 'Review local integration helper API surfaces for remote clients and future web frontends',
134
- usage: '[review|bundle export <path>|bundle inspect <path>]',
146
+ usage: '[review|bundle export <path> --yes|bundle inspect <path>]',
135
147
  handler(args, ctx) {
148
+ const parsed = stripYesFlag(args);
149
+ const commandArgs = [...parsed.rest];
136
150
  const shellPaths = requireShellPaths(ctx);
137
- const sub = args[0] ?? 'review';
151
+ const sub = commandArgs[0] ?? 'review';
138
152
  const review = ctx.extensions.integrationHelpers?.buildReview();
139
153
  if (!review) {
140
154
  ctx.print('Integration helper service unavailable in this runtime.');
@@ -156,14 +170,18 @@ export function registerPlatformServicesRuntimeCommands(registry: CommandRegistr
156
170
  return;
157
171
  }
158
172
  if (sub === 'bundle') {
159
- const mode = args[1];
160
- const pathArg = args[2];
173
+ const mode = commandArgs[1];
174
+ const pathArg = commandArgs[2];
161
175
  if ((mode === 'export' || mode === 'inspect') && !pathArg) {
162
- ctx.print(`Usage: /helpers bundle ${mode} <path>`);
176
+ ctx.print(`Usage: /helpers bundle ${mode} <path>${mode === 'export' ? ' --yes' : ''}`);
163
177
  return;
164
178
  }
165
- const targetPath = shellPaths.resolveWorkspacePath(pathArg!);
166
179
  if (mode === 'export') {
180
+ if (!parsed.yes) {
181
+ requireYesFlag(ctx, `export integration helper bundle to ${pathArg}`, '/helpers bundle export <path> --yes');
182
+ return;
183
+ }
184
+ const targetPath = shellPaths.resolveWorkspacePath(pathArg!);
167
185
  const bundle: IntegrationHelperBundle = {
168
186
  version: 1,
169
187
  exportedAt: Date.now(),
@@ -176,12 +194,13 @@ export function registerPlatformServicesRuntimeCommands(registry: CommandRegistr
176
194
  return;
177
195
  }
178
196
  if (mode === 'inspect') {
197
+ const targetPath = shellPaths.resolveWorkspacePath(pathArg!);
179
198
  const bundle = JSON.parse(readFileSync(targetPath, 'utf-8')) as IntegrationHelperBundle;
180
199
  ctx.print(inspectIntegrationHelperBundle(bundle));
181
200
  return;
182
201
  }
183
202
  }
184
- ctx.print('Usage: /helpers [review|bundle export <path>|bundle inspect <path>]');
203
+ ctx.print('Usage: /helpers [review|bundle export <path> --yes|bundle inspect <path>]');
185
204
  },
186
205
  });
187
206
 
@@ -189,10 +208,12 @@ export function registerPlatformServicesRuntimeCommands(registry: CommandRegistr
189
208
  name: 'deeplink',
190
209
  aliases: ['link'],
191
210
  description: 'Review and package deep-link entrypoints for setup and operator surfaces',
192
- usage: '[review|open <surface> [target]|bundle export <path>|bundle inspect <path>]',
211
+ usage: '[review|open <surface> [target]|bundle export <path> --yes|bundle inspect <path>]',
193
212
  handler(args, ctx) {
213
+ const parsed = stripYesFlag(args);
214
+ const commandArgs = [...parsed.rest];
194
215
  const shellPaths = requireShellPaths(ctx);
195
- const sub = args[0] ?? 'review';
216
+ const sub = commandArgs[0] ?? 'review';
196
217
  const links = [
197
218
  buildSetupLink('cockpit'),
198
219
  buildSetupLink('security'),
@@ -206,8 +227,8 @@ export function registerPlatformServicesRuntimeCommands(registry: CommandRegistr
206
227
  return;
207
228
  }
208
229
  if (sub === 'open') {
209
- const surface = args[1];
210
- const target = args[2];
230
+ const surface = commandArgs[1];
231
+ const target = commandArgs[2];
211
232
  if (!surface) {
212
233
  ctx.print('Usage: /deeplink open <surface> [target]');
213
234
  return;
@@ -216,14 +237,18 @@ export function registerPlatformServicesRuntimeCommands(registry: CommandRegistr
216
237
  return;
217
238
  }
218
239
  if (sub === 'bundle') {
219
- const mode = args[1];
220
- const pathArg = args[2];
240
+ const mode = commandArgs[1];
241
+ const pathArg = commandArgs[2];
221
242
  if ((mode === 'export' || mode === 'inspect') && !pathArg) {
222
- ctx.print(`Usage: /deeplink bundle ${mode} <path>`);
243
+ ctx.print(`Usage: /deeplink bundle ${mode} <path>${mode === 'export' ? ' --yes' : ''}`);
223
244
  return;
224
245
  }
225
- const targetPath = shellPaths.resolveWorkspacePath(pathArg!);
226
246
  if (mode === 'export') {
247
+ if (!parsed.yes) {
248
+ requireYesFlag(ctx, `export deep link bundle to ${pathArg}`, '/deeplink bundle export <path> --yes');
249
+ return;
250
+ }
251
+ const targetPath = shellPaths.resolveWorkspacePath(pathArg!);
227
252
  const bundle: DeepLinkBundle = {
228
253
  version: 1,
229
254
  exportedAt: Date.now(),
@@ -235,12 +260,13 @@ export function registerPlatformServicesRuntimeCommands(registry: CommandRegistr
235
260
  return;
236
261
  }
237
262
  if (mode === 'inspect') {
263
+ const targetPath = shellPaths.resolveWorkspacePath(pathArg!);
238
264
  const bundle = JSON.parse(readFileSync(targetPath, 'utf-8')) as DeepLinkBundle;
239
265
  ctx.print(inspectDeepLinkBundle(bundle));
240
266
  return;
241
267
  }
242
268
  }
243
- ctx.print('Usage: /deeplink [review|open <surface> [target]|bundle export <path>|bundle inspect <path>]');
269
+ ctx.print('Usage: /deeplink [review|open <surface> [target]|bundle export <path> --yes|bundle inspect <path>]');
244
270
  },
245
271
  });
246
272
  }