@pellux/goodvibes-agent 0.1.114 → 0.1.117

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 (168) hide show
  1. package/CHANGELOG.md +41 -650
  2. package/README.md +40 -50
  3. package/dist/package/main.js +38224 -35673
  4. package/docs/README.md +5 -4
  5. package/docs/{connected-services.md → connected-host.md} +18 -10
  6. package/docs/getting-started.md +43 -42
  7. package/docs/release-and-publishing.md +6 -4
  8. package/package.json +3 -3
  9. package/src/agent/behavior-discovery-summary.ts +165 -0
  10. package/src/agent/persona-discovery.ts +1 -3
  11. package/src/agent/persona-registry.ts +5 -3
  12. package/src/agent/reminder-schedule-format.ts +6 -6
  13. package/src/agent/reminder-schedule.ts +1 -1
  14. package/src/agent/routine-registry.ts +43 -4
  15. package/src/agent/routine-schedule-format.ts +6 -6
  16. package/src/agent/routine-schedule-promotion.ts +1 -1
  17. package/src/agent/routine-schedule-receipts.ts +1 -1
  18. package/src/agent/runtime-profile-starters.ts +331 -0
  19. package/src/agent/runtime-profile.ts +228 -330
  20. package/src/agent/skill-registry.ts +190 -13
  21. package/src/cli/agent-knowledge-command.ts +2 -2
  22. package/src/cli/agent-knowledge-format.ts +2 -2
  23. package/src/cli/agent-knowledge-runtime.ts +1 -1
  24. package/src/cli/bundle-command.ts +1 -1
  25. package/src/cli/entrypoint.ts +16 -7
  26. package/src/cli/help.ts +26 -19
  27. package/src/cli/local-library-command.ts +75 -21
  28. package/src/cli/management-commands.ts +7 -6
  29. package/src/cli/management.ts +6 -51
  30. package/src/cli/parser.ts +23 -2
  31. package/src/cli/profiles-command.ts +247 -1
  32. package/src/cli/routines-command.ts +139 -11
  33. package/src/cli/service-posture.ts +11 -11
  34. package/src/cli/status.ts +21 -25
  35. package/src/input/agent-workspace-access-command-editor-submission.ts +149 -0
  36. package/src/input/agent-workspace-access-command-editors.ts +170 -0
  37. package/src/input/agent-workspace-activation.ts +2 -1
  38. package/src/input/agent-workspace-basic-command-editor-submission.ts +787 -0
  39. package/src/input/agent-workspace-basic-command-editors.ts +524 -459
  40. package/src/input/agent-workspace-categories.ts +177 -14
  41. package/src/input/agent-workspace-channel-command-editor-submission.ts +49 -0
  42. package/src/input/agent-workspace-channel-command-editors.ts +47 -0
  43. package/src/input/agent-workspace-command-editor.ts +25 -1
  44. package/src/input/agent-workspace-delegation-editor-submission.ts +55 -0
  45. package/src/input/agent-workspace-editors.ts +27 -0
  46. package/src/input/agent-workspace-knowledge-command-editor-submission.ts +132 -0
  47. package/src/input/agent-workspace-knowledge-command-editors.ts +110 -0
  48. package/src/input/agent-workspace-learned-behavior.ts +67 -0
  49. package/src/input/agent-workspace-library-command-editor-submission.ts +50 -0
  50. package/src/input/agent-workspace-library-command-editors.ts +35 -0
  51. package/src/input/agent-workspace-mcp-command-editor-submission.ts +95 -0
  52. package/src/input/agent-workspace-memory-command-editor-submission.ts +232 -0
  53. package/src/input/agent-workspace-memory-command-editors.ts +180 -0
  54. package/src/input/agent-workspace-navigation.ts +45 -0
  55. package/src/input/agent-workspace-notify-editor-submission.ts +107 -0
  56. package/src/input/agent-workspace-operations-command-editor-submission.ts +146 -0
  57. package/src/input/agent-workspace-operations-command-editors.ts +119 -0
  58. package/src/input/agent-workspace-provider-command-editor-submission.ts +155 -0
  59. package/src/input/agent-workspace-provider-command-editors.ts +93 -0
  60. package/src/input/agent-workspace-requirements.ts +11 -0
  61. package/src/input/agent-workspace-secret-editor-submission.ts +153 -0
  62. package/src/input/agent-workspace-session-command-editor-submission.ts +199 -0
  63. package/src/input/agent-workspace-session-command-editors.ts +249 -0
  64. package/src/input/agent-workspace-setup.ts +49 -19
  65. package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +101 -0
  66. package/src/input/agent-workspace-skill-bundle-command-editors.ts +110 -0
  67. package/src/input/agent-workspace-snapshot.ts +56 -8
  68. package/src/input/agent-workspace-task-command-editor-submission.ts +61 -0
  69. package/src/input/agent-workspace-task-command-editors.ts +47 -0
  70. package/src/input/agent-workspace-types.ts +124 -0
  71. package/src/input/agent-workspace-voice-media.ts +1 -1
  72. package/src/input/agent-workspace-workplan-editor-submission.ts +153 -0
  73. package/src/input/agent-workspace.ts +47 -37
  74. package/src/input/command-registry.ts +1 -1
  75. package/src/input/commands/agent-runtime-profile-runtime.ts +160 -6
  76. package/src/input/commands/agent-skills-runtime.ts +76 -12
  77. package/src/input/commands/agent-workspace-runtime.ts +4 -3
  78. package/src/input/commands/brief-runtime.ts +38 -9
  79. package/src/input/commands/channels-runtime.ts +3 -3
  80. package/src/input/commands/compat-runtime.ts +32 -0
  81. package/src/input/commands/health-runtime.ts +22 -24
  82. package/src/input/commands/knowledge.ts +26 -5
  83. package/src/input/commands/local-provider-runtime.ts +7 -3
  84. package/src/input/commands/local-setup-review.ts +4 -14
  85. package/src/input/commands/mcp-runtime.ts +8 -12
  86. package/src/input/commands/operator-runtime.ts +8 -67
  87. package/src/input/commands/personas-runtime.ts +1 -1
  88. package/src/input/commands/platform-access-runtime.ts +7 -70
  89. package/src/input/commands/policy-dispatch.ts +1 -1
  90. package/src/input/commands/policy.ts +1 -5
  91. package/src/input/commands/product-runtime.ts +2 -2
  92. package/src/input/commands/qrcode-runtime.ts +6 -4
  93. package/src/input/commands/routines-runtime.ts +44 -6
  94. package/src/input/commands/runtime-services.ts +1 -14
  95. package/src/input/commands/security-runtime.ts +3 -8
  96. package/src/input/commands/session-content.ts +1 -1
  97. package/src/input/commands/session-workflow.ts +5 -14
  98. package/src/input/commands/shell-core.ts +8 -2
  99. package/src/input/commands/subscription-runtime.ts +1 -6
  100. package/src/input/commands/support-bundle-runtime.ts +53 -0
  101. package/src/input/commands/tasks-runtime.ts +2 -2
  102. package/src/input/commands.ts +4 -0
  103. package/src/input/feed-context-factory.ts +0 -1
  104. package/src/input/handler-content-actions.ts +0 -25
  105. package/src/input/handler-feed.ts +0 -2
  106. package/src/input/handler-interactions.ts +2 -31
  107. package/src/input/handler-onboarding.ts +29 -12
  108. package/src/input/handler-shortcuts.ts +1 -3
  109. package/src/input/handler.ts +4 -7
  110. package/src/input/keybindings.ts +9 -9
  111. package/src/input/mcp-workspace.ts +90 -26
  112. package/src/input/onboarding/handler-onboarding-routes.ts +3 -1
  113. package/src/input/onboarding/onboarding-wizard-apply.ts +49 -0
  114. package/src/input/onboarding/onboarding-wizard-helpers.ts +1 -1
  115. package/src/input/onboarding/onboarding-wizard-operator-steps.ts +126 -11
  116. package/src/input/onboarding/onboarding-wizard-steps.ts +15 -8
  117. package/src/input/onboarding/onboarding-wizard-types.ts +1 -0
  118. package/src/input/onboarding/onboarding-wizard.ts +19 -2
  119. package/src/input/profile-picker-modal.ts +2 -2
  120. package/src/input/settings-modal-agent-policy.ts +6 -6
  121. package/src/input/settings-modal-subscriptions.ts +3 -3
  122. package/src/input/settings-modal.ts +14 -14
  123. package/src/main.ts +0 -2
  124. package/src/panels/automation-control-panel.ts +3 -3
  125. package/src/panels/builtin/agent.ts +1 -1
  126. package/src/panels/builtin/operations.ts +2 -2
  127. package/src/panels/builtin/session.ts +26 -18
  128. package/src/panels/builtin/shared.ts +6 -6
  129. package/src/panels/project-planning-panel.ts +1 -1
  130. package/src/panels/provider-health-domains.ts +3 -3
  131. package/src/panels/qr-panel.ts +44 -20
  132. package/src/panels/subscription-panel.ts +3 -3
  133. package/src/panels/system-messages-panel.ts +2 -2
  134. package/src/panels/tasks-panel.ts +4 -4
  135. package/src/planning/project-planning-coordinator.ts +2 -2
  136. package/src/renderer/agent-workspace.ts +52 -5
  137. package/src/renderer/block-actions.ts +1 -3
  138. package/src/renderer/help-overlay.ts +13 -8
  139. package/src/renderer/mcp-workspace.ts +32 -13
  140. package/src/renderer/model-picker-overlay.ts +0 -1
  141. package/src/renderer/model-workspace.ts +0 -2
  142. package/src/renderer/onboarding/onboarding-wizard.ts +20 -4
  143. package/src/renderer/panel-picker-overlay.ts +1 -1
  144. package/src/renderer/profile-picker-modal.ts +2 -2
  145. package/src/renderer/settings-modal-helpers.ts +23 -23
  146. package/src/renderer/settings-modal.ts +18 -18
  147. package/src/renderer/system-message.ts +1 -1
  148. package/src/runtime/agent-runtime-events.ts +129 -0
  149. package/src/runtime/bootstrap-command-parts.ts +3 -2
  150. package/src/runtime/bootstrap-core.ts +4 -64
  151. package/src/runtime/bootstrap-shell.ts +42 -4
  152. package/src/runtime/bootstrap.ts +8 -27
  153. package/src/runtime/connected-host-auth.ts +42 -0
  154. package/src/runtime/diagnostics/panels/panel-resources.ts +1 -1
  155. package/src/runtime/index.ts +1 -5
  156. package/src/runtime/onboarding/apply.ts +213 -0
  157. package/src/runtime/onboarding/derivation.ts +25 -6
  158. package/src/runtime/onboarding/snapshot.ts +4 -2
  159. package/src/runtime/onboarding/types.ts +28 -1
  160. package/src/runtime/onboarding/verify.ts +81 -2
  161. package/src/runtime/operator-token-cleanup.ts +2 -2
  162. package/src/runtime/services.ts +27 -12
  163. package/src/shell/service-settings-sync.ts +7 -7
  164. package/src/shell/ui-openers.ts +27 -38
  165. package/src/tools/agent-local-registry-tool.ts +10 -4
  166. package/src/tools/agent-tool-policy-guard.ts +5 -7
  167. package/src/version.ts +1 -1
  168. package/src/cli/package-verification.ts +0 -274
@@ -4,6 +4,10 @@ import { AgentPersonaRegistry, type AgentPersonaRecord } from '../agent/persona-
4
4
  import { discoverSkills, type SkillRecord } from '../agent/skill-discovery.ts';
5
5
  import {
6
6
  AgentSkillRegistry,
7
+ buildAgentSkillRequirements,
8
+ evaluateAgentSkillBundleReadiness,
9
+ evaluateAgentSkillReadiness,
10
+ formatAgentSkillRequirement,
7
11
  type AgentSkillBundleRecord,
8
12
  type AgentSkillRecord,
9
13
  } from '../agent/skill-registry.ts';
@@ -170,7 +174,7 @@ function renderDiscoveredPersonaList(personas: readonly DiscoveredPersonaRecord[
170
174
  return [
171
175
  'Discovered Agent persona files',
172
176
  ' No persona markdown files found in Agent persona folders.',
173
- ' Search roots: .goodvibes/personas, .goodvibes/agent/personas, .goodvibes/agents, ~/.goodvibes/personas, ~/.goodvibes/agent/personas, ~/.goodvibes/agents',
177
+ ' Search roots: .goodvibes/personas, .goodvibes/agent/personas, ~/.goodvibes/personas, ~/.goodvibes/agent/personas',
174
178
  ].join('\n');
175
179
  }
176
180
  return [
@@ -204,21 +208,29 @@ function discoveredPersonaFrontmatterList(persona: DiscoveredPersonaRecord, key:
204
208
  function summarizeSkill(skill: AgentSkillRecord): string {
205
209
  const enabled = skill.enabled ? 'enabled' : 'disabled';
206
210
  const tags = skill.tags.length > 0 ? ` tags=${skill.tags.join(',')}` : '';
207
- return ` ${skill.id} ${enabled} ${skill.reviewState} ${skill.name} - ${skill.description}${tags}`;
211
+ const readiness = evaluateAgentSkillReadiness(skill);
212
+ const ready = readiness.ready ? 'ready' : `needs ${readiness.missing.map(formatAgentSkillRequirement).join(',')}`;
213
+ return ` ${skill.id} ${enabled} ${skill.reviewState} ${ready} ${skill.name} - ${skill.description}${tags}`;
208
214
  }
209
215
 
210
- function summarizeBundle(bundle: AgentSkillBundleRecord): string {
216
+ function summarizeBundle(bundle: AgentSkillBundleRecord, skills: readonly AgentSkillRecord[]): string {
211
217
  const enabled = bundle.enabled ? 'enabled' : 'disabled';
212
- return ` ${bundle.id} ${enabled} ${bundle.reviewState} ${bundle.name} - ${bundle.description} skills=${bundle.skillIds.join(',')}`;
218
+ const readiness = evaluateAgentSkillBundleReadiness(bundle, skills);
219
+ const missing = [
220
+ ...readiness.missingRequirements.map(formatAgentSkillRequirement),
221
+ ...readiness.missingSkillIds.map((skillId) => `skill:${skillId}`),
222
+ ];
223
+ const ready = readiness.ready ? 'ready' : `needs ${missing.join(',')}`;
224
+ return ` ${bundle.id} ${enabled} ${bundle.reviewState} ${ready} ${bundle.name} - ${bundle.description} skills=${bundle.skillIds.join(',')}`;
213
225
  }
214
226
 
215
- function renderSkillList(title: string, path: string, skills: readonly AgentSkillRecord[]): string {
227
+ function renderSkillList(title: string, path: string, skills: readonly AgentSkillRecord[], emptyMessage?: string): string {
216
228
  if (skills.length === 0) {
217
229
  return [
218
230
  title,
219
- ' No local Agent skills yet.',
220
- ' Create one with: goodvibes-agent skills create --name <name> --description <summary> --procedure <steps>',
221
- ].join('\n');
231
+ ` ${emptyMessage ?? 'No local Agent skills yet.'}`,
232
+ emptyMessage ? '' : ' Create one with: goodvibes-agent skills create --name <name> --description <summary> --procedure <steps>',
233
+ ].filter(Boolean).join('\n');
222
234
  }
223
235
  return [
224
236
  `${title} (${skills.length})`,
@@ -273,26 +285,38 @@ function discoveredFrontmatterList(skill: SkillRecord, key: string): readonly st
273
285
  return value.split(',').map((entry) => entry.trim()).filter(Boolean);
274
286
  }
275
287
 
276
- function renderBundleList(title: string, path: string, bundles: readonly AgentSkillBundleRecord[]): string {
288
+ function discoveredFrontmatterAnyList(skill: SkillRecord, keys: readonly string[]): readonly string[] {
289
+ for (const key of keys) {
290
+ const values = discoveredFrontmatterList(skill, key);
291
+ if (values.length > 0) return values;
292
+ }
293
+ return [];
294
+ }
295
+
296
+ function renderBundleList(title: string, path: string, bundles: readonly AgentSkillBundleRecord[], skills: readonly AgentSkillRecord[], emptyMessage?: string): string {
277
297
  if (bundles.length === 0) {
278
298
  return [
279
299
  title,
280
- ' No local Agent skill bundles yet.',
281
- ' Create one with: goodvibes-agent skills bundle create --name <name> --description <summary> --skills <id,id>',
282
- ].join('\n');
300
+ ` ${emptyMessage ?? 'No local Agent skill bundles yet.'}`,
301
+ emptyMessage ? '' : ' Create one with: goodvibes-agent skills bundle create --name <name> --description <summary> --skills <id,id>',
302
+ ].filter(Boolean).join('\n');
283
303
  }
284
304
  return [
285
305
  `${title} (${bundles.length})`,
286
306
  ` store: ${path}`,
287
- ...bundles.map(summarizeBundle),
307
+ ...bundles.map((bundle) => summarizeBundle(bundle, skills)),
288
308
  ].join('\n');
289
309
  }
290
310
 
291
311
  function renderSkill(skill: AgentSkillRecord): string {
312
+ const readiness = evaluateAgentSkillReadiness(skill);
292
313
  return [
293
314
  `Skill ${skill.name}`,
294
315
  ` id: ${skill.id}`,
295
316
  ` enabled: ${skill.enabled ? 'yes' : 'no'}`,
317
+ ` readiness: ${readiness.ready ? 'ready' : 'needs setup'}`,
318
+ ` requirements: ${skill.requirements.map(formatAgentSkillRequirement).join(', ') || '(none)'}`,
319
+ readiness.missing.length > 0 ? ` missing: ${readiness.missing.map(formatAgentSkillRequirement).join(', ')}` : '',
296
320
  ` review: ${skill.reviewState}`,
297
321
  ` source: ${skill.source}`,
298
322
  ` provenance: ${skill.provenance}`,
@@ -308,11 +332,18 @@ function renderSkill(skill: AgentSkillRecord): string {
308
332
  ].filter((line): line is string => Boolean(line)).join('\n');
309
333
  }
310
334
 
311
- function renderBundle(bundle: AgentSkillBundleRecord): string {
335
+ function renderBundle(bundle: AgentSkillBundleRecord, skills: readonly AgentSkillRecord[]): string {
336
+ const readiness = evaluateAgentSkillBundleReadiness(bundle, skills);
337
+ const missing = [
338
+ ...readiness.missingRequirements.map(formatAgentSkillRequirement),
339
+ ...readiness.missingSkillIds.map((skillId) => `skill:${skillId}`),
340
+ ];
312
341
  return [
313
342
  `Skill bundle ${bundle.name}`,
314
343
  ` id: ${bundle.id}`,
315
344
  ` enabled: ${bundle.enabled ? 'yes' : 'no'}`,
345
+ ` readiness: ${readiness.ready ? 'ready' : 'needs setup'}`,
346
+ missing.length > 0 ? ` missing: ${missing.join(', ')}` : '',
316
347
  ` review: ${bundle.reviewState}`,
317
348
  ` source: ${bundle.source}`,
318
349
  ` provenance: ${bundle.provenance}`,
@@ -330,11 +361,11 @@ function usagePersonas(): string {
330
361
  }
331
362
 
332
363
  function usageSkills(): string {
333
- return 'Usage: goodvibes-agent skills [list|enabled|active|discover|import-discovered <name> --yes|search <query>|show <id>|create|update <id>|enable <id>|disable <id>|review <id>|stale <id> <reason>|delete <id> --yes|bundle ...]';
364
+ return 'Usage: goodvibes-agent skills [list|enabled|active|attention|discover|import-discovered <name> --yes|search <query>|show <id>|create [--requires-env A,B] [--requires-command gh,jq]|update <id>|enable <id>|disable <id>|review <id>|stale <id> <reason>|delete <id> --yes|bundle ...]';
334
365
  }
335
366
 
336
367
  function usageBundles(): string {
337
- return 'Usage: goodvibes-agent skills bundle [list|enabled|search <query>|show <id>|create|update <id>|enable <id>|disable <id>|review <id>|stale <id> <reason>|delete <id> --yes]';
368
+ return 'Usage: goodvibes-agent skills bundle [list|enabled|attention|search <query>|show <id>|create|update <id>|enable <id>|disable <id>|review <id>|stale <id> <reason>|delete <id> --yes]';
338
369
  }
339
370
 
340
371
  function errorOutput(runtime: CliCommandRuntime, error: unknown, kind: string): CliCommandOutput {
@@ -473,6 +504,7 @@ function skillPayloadFromOptions(options: ParsedOptions): {
473
504
  readonly procedure: string;
474
505
  readonly tags: readonly string[] | undefined;
475
506
  readonly triggers: readonly string[] | undefined;
507
+ readonly requirements: ReturnType<typeof buildAgentSkillRequirements>;
476
508
  readonly enabled: boolean | undefined;
477
509
  readonly provenance: string;
478
510
  } {
@@ -483,6 +515,10 @@ function skillPayloadFromOptions(options: ParsedOptions): {
483
515
  procedure: requiredOption(options, 'procedure', usage),
484
516
  tags: csvOption(options, 'tags'),
485
517
  triggers: csvOption(options, 'triggers'),
518
+ requirements: buildAgentSkillRequirements({
519
+ env: csvOption(options, 'requires-env'),
520
+ commands: csvOption(options, 'requires-command') ?? csvOption(options, 'requires-commands'),
521
+ }),
486
522
  enabled: hasFlag(options, 'enabled') ? true : undefined,
487
523
  provenance: optionValue(options, 'provenance') ?? 'cli',
488
524
  };
@@ -495,22 +531,26 @@ async function handleSkillBundleCommand(runtime: CliCommandRuntime, args: readon
495
531
  const registry = skillRegistry(runtime);
496
532
  const snapshot = registry.snapshot();
497
533
  if (normalized === 'list' || normalized === 'ls') {
498
- return success(runtime, 'agent.skills.bundles.list', { path: snapshot.path, bundles: snapshot.bundles }, renderBundleList('Agent skill bundles', snapshot.path, snapshot.bundles));
534
+ return success(runtime, 'agent.skills.bundles.list', { path: snapshot.path, bundles: snapshot.bundles }, renderBundleList('Agent skill bundles', snapshot.path, snapshot.bundles, snapshot.skills));
499
535
  }
500
536
  if (normalized === 'enabled') {
501
- return success(runtime, 'agent.skills.bundles.enabled', { path: snapshot.path, bundles: snapshot.enabledBundles }, renderBundleList('Enabled Agent skill bundles', snapshot.path, snapshot.enabledBundles));
537
+ return success(runtime, 'agent.skills.bundles.enabled', { path: snapshot.path, bundles: snapshot.enabledBundles }, renderBundleList('Enabled Agent skill bundles', snapshot.path, snapshot.enabledBundles, snapshot.skills));
538
+ }
539
+ if (normalized === 'attention' || normalized === 'needs-setup') {
540
+ const bundles = snapshot.bundles.filter((bundle) => !evaluateAgentSkillBundleReadiness(bundle, snapshot.skills).ready);
541
+ return success(runtime, 'agent.skills.bundles.attention', { path: snapshot.path, bundles }, renderBundleList('Agent skill bundles needing setup', snapshot.path, bundles, snapshot.skills, 'No local Agent skill bundles need setup.'));
502
542
  }
503
543
  if (normalized === 'search' || normalized === 'find') {
504
544
  const query = rest.join(' ').trim();
505
545
  const results = registry.searchBundles(query);
506
- return success(runtime, 'agent.skills.bundles.search', { query, results }, renderBundleList(`Agent skill bundles matching "${query}"`, snapshot.path, results));
546
+ return success(runtime, 'agent.skills.bundles.search', { query, results }, renderBundleList(`Agent skill bundles matching "${query}"`, snapshot.path, results, snapshot.skills));
507
547
  }
508
548
  if (normalized === 'show' || normalized === 'get') {
509
549
  const id = rest[0];
510
550
  if (!id) return failure(runtime, 'invalid_skill_bundle_command', 'Usage: goodvibes-agent skills bundle show <id>', 2);
511
551
  const bundle = registry.getBundle(id);
512
552
  if (!bundle) return failure(runtime, 'skill_bundle_not_found', `Unknown Agent skill bundle: ${id}`, 1);
513
- return success(runtime, 'agent.skills.bundles.show', bundle, renderBundle(bundle));
553
+ return success(runtime, 'agent.skills.bundles.show', bundle, renderBundle(bundle, snapshot.skills));
514
554
  }
515
555
  if (normalized === 'create') {
516
556
  const options = parseOptions(rest);
@@ -584,9 +624,13 @@ export async function handleSkillsCommand(runtime: CliCommandRuntime): Promise<C
584
624
  if (normalized === 'active') {
585
625
  return success(runtime, 'agent.skills.active', { path: snapshot.path, skills: snapshot.activeSkills, bundles: snapshot.enabledBundles }, [
586
626
  renderSkillList('Active Agent skills', snapshot.path, snapshot.activeSkills),
587
- snapshot.enabledBundles.length > 0 ? renderBundleList('Enabled Agent skill bundles', snapshot.path, snapshot.enabledBundles) : '',
627
+ snapshot.enabledBundles.length > 0 ? renderBundleList('Enabled Agent skill bundles', snapshot.path, snapshot.enabledBundles, snapshot.skills) : '',
588
628
  ].filter(Boolean).join('\n\n'));
589
629
  }
630
+ if (normalized === 'attention' || normalized === 'needs-setup') {
631
+ const skills = snapshot.skills.filter((skill) => !evaluateAgentSkillReadiness(skill).ready);
632
+ return success(runtime, 'agent.skills.attention', { path: snapshot.path, skills }, renderSkillList('Agent skills needing setup', snapshot.path, skills, 'No local Agent skills need setup.'));
633
+ }
590
634
  if (normalized === 'discover') {
591
635
  const discovered = await discoverSkills(shellPaths(runtime));
592
636
  return success(runtime, 'agent.skills.discover', { skills: discovered }, renderDiscoveredSkillList(discovered));
@@ -616,6 +660,10 @@ export async function handleSkillsCommand(runtime: CliCommandRuntime): Promise<C
616
660
  procedure: discovered.body,
617
661
  tags: discoveredFrontmatterList(discovered, 'tags'),
618
662
  triggers: discoveredFrontmatterList(discovered, 'triggers'),
663
+ requirements: buildAgentSkillRequirements({
664
+ env: discoveredFrontmatterAnyList(discovered, ['requiresEnv', 'requires-env', 'requires_env']),
665
+ commands: discoveredFrontmatterAnyList(discovered, ['requiresCommands', 'requires-commands', 'requires_commands', 'commands']),
666
+ }),
619
667
  enabled: hasFlag(options, 'enabled'),
620
668
  source: 'imported',
621
669
  provenance: `discovered:${discovered.origin}:${discovered.path}`,
@@ -648,6 +696,12 @@ export async function handleSkillsCommand(runtime: CliCommandRuntime): Promise<C
648
696
  procedure: optionValue(options, 'procedure'),
649
697
  tags: csvOption(options, 'tags'),
650
698
  triggers: csvOption(options, 'triggers'),
699
+ requirements: options.values.has('requires-env') || options.values.has('requires-command') || options.values.has('requires-commands')
700
+ ? buildAgentSkillRequirements({
701
+ env: csvOption(options, 'requires-env'),
702
+ commands: csvOption(options, 'requires-command') ?? csvOption(options, 'requires-commands'),
703
+ })
704
+ : undefined,
651
705
  provenance: optionValue(options, 'provenance'),
652
706
  });
653
707
  return success(runtime, 'agent.skills.update', skill, `Agent skill updated: ${skill.id}`);
@@ -1,16 +1,17 @@
1
1
  import { mkdirSync, writeFileSync } from 'node:fs';
2
- import { dirname, join } from 'node:path';
2
+ import { dirname } from 'node:path';
3
3
  import { SecretsManager } from '../config/secrets.ts';
4
4
  import { BUILTIN_SECRET_PROVIDER_SOURCES, describeSecretRef, isSecretRefInput, resolveSecretRef } from '@pellux/goodvibes-sdk/platform/config';
5
5
  import { getSubscriptionProviderConfig, listAvailableSubscriptionProviders } from '@pellux/goodvibes-sdk/platform/config';
6
6
  import { beginOpenAICodexLogin, exchangeOpenAICodexCode } from '@pellux/goodvibes-sdk/platform/config';
7
7
  import { inspectProviderAuth } from '@/runtime/index.ts';
8
- import { getOrCreateCompanionToken, buildCompanionConnectionInfo, encodeConnectionPayload, formatConnectionBlock } from '@pellux/goodvibes-sdk/platform/pairing';
8
+ import { buildCompanionConnectionInfo, encodeConnectionPayload, formatConnectionBlock } from '@pellux/goodvibes-sdk/platform/pairing';
9
9
  import { generateQrMatrix, renderQrToString } from '@pellux/goodvibes-sdk/platform/pairing';
10
10
  import { resolveRuntimeEndpointBinding } from './endpoints.ts';
11
11
  import type { CliCommandRuntime } from './management.ts';
12
12
  import { extractAuthorizationCode, formatJsonOrText, hasCommandFlag, openBrowser, urlHostForBindHost, withRuntimeServices, yesNo } from './management.ts';
13
13
  import { GOODVIBES_AGENT_PAIRING_SURFACE } from '../config/surface.ts';
14
+ import { connectedHostTokenRequiredMessage, readConnectedHostOperatorToken } from '../runtime/connected-host-auth.ts';
14
15
 
15
16
  export async function renderSubscriptions(runtime: CliCommandRuntime): Promise<string> {
16
17
  return await withRuntimeServices(runtime, async (services) => {
@@ -279,7 +280,7 @@ export async function handleTasks(runtime: CliCommandRuntime): Promise<string> {
279
280
  const [sub = 'list', ...rest] = runtime.cli.commandArgs;
280
281
  if (sub === 'submit') {
281
282
  return [
282
- 'GoodVibes Agent blocks CLI task submission from the service-owned task workflow.',
283
+ 'GoodVibes Agent blocks CLI task submission from the host-owned task workflow.',
283
284
  ' policy: do normal assistant work in the main Agent conversation or use `goodvibes-agent run <prompt>` for an explicit one-shot run.',
284
285
  ' build/fix/review: use `goodvibes-agent delegate <task>` for explicit GoodVibes TUI handoff.',
285
286
  ' result: no local task was started.',
@@ -289,7 +290,7 @@ export async function handleTasks(runtime: CliCommandRuntime): Promise<string> {
289
290
  const tasks = [...services.runtimeStore.getState().tasks.tasks.values()];
290
291
  if (sub === 'list') {
291
292
  return tasks.length === 0
292
- ? 'GoodVibes tasks\n No connected-service tasks are currently recorded.'
293
+ ? 'GoodVibes tasks\n No connected-host tasks are currently recorded.'
293
294
  : ['GoodVibes tasks', ...tasks.map((task) => ` ${task.id} ${task.status} ${task.kind} ${task.title}`)].join('\n');
294
295
  }
295
296
  if (sub === 'show') {
@@ -302,8 +303,8 @@ export async function handleTasks(runtime: CliCommandRuntime): Promise<string> {
302
303
  }
303
304
 
304
305
  export async function renderPairing(runtime: CliCommandRuntime): Promise<string> {
305
- const daemonHomeDir = join(runtime.homeDirectory, '.goodvibes', 'daemon');
306
- const tokenRecord = getOrCreateCompanionToken(GOODVIBES_AGENT_PAIRING_SURFACE, { daemonHomeDir });
306
+ const tokenRecord = readConnectedHostOperatorToken(runtime.homeDirectory);
307
+ if (!tokenRecord.token) return connectedHostTokenRequiredMessage(tokenRecord.path);
307
308
  const binding = resolveRuntimeEndpointBinding(runtime.configManager, 'controlPlane');
308
309
  const daemonUrl = `http://${urlHostForBindHost(binding.host)}:${binding.port}`;
309
310
  const info = buildCompanionConnectionInfo({
@@ -19,14 +19,9 @@ import { BUILTIN_SECRET_PROVIDER_SOURCES, describeSecretRef, isSecretRefInput, r
19
19
  import { getSubscriptionProviderConfig, listAvailableSubscriptionProviders } from '@pellux/goodvibes-sdk/platform/config';
20
20
  import { beginOpenAICodexLogin, exchangeOpenAICodexCode } from '@pellux/goodvibes-sdk/platform/config';
21
21
  import { inspectProviderAuth } from '@/runtime/index.ts';
22
- import { getOrCreateCompanionToken, buildCompanionConnectionInfo, encodeConnectionPayload, formatConnectionBlock } from '@pellux/goodvibes-sdk/platform/pairing';
23
- import { generateQrMatrix, renderQrToString } from '@pellux/goodvibes-sdk/platform/pairing';
24
22
  import type { GoodVibesCliParseResult } from './types.ts';
25
23
  import { formatProviderAuthRoute, summarizeProviderAuthRoutes } from './provider-auth-routes.ts';
26
24
  import { classifyProviderSetup } from './provider-classification.ts';
27
- import { resolveRuntimeEndpointBinding } from './endpoints.ts';
28
- import { applyRuntimeEndpointFlagOverrides } from './config-overrides.ts';
29
- import type { RuntimeEndpointId } from './endpoints.ts';
30
25
  import { handleBundleCommand } from './bundle-command.ts';
31
26
  import { handleSecrets, handleSessions, handleTasks, renderPairing, renderSubscriptions } from './management-commands.ts';
32
27
  import { handleAgentKnowledgeCommand, handleAgentKnowledgeShortcutCommand, handleCompatCommand, handleDelegateCommand } from './agent-knowledge-command.ts';
@@ -132,46 +127,6 @@ export function urlHostForBindHost(host: string): string {
132
127
  return host || '127.0.0.1';
133
128
  }
134
129
 
135
- export function enableServicePosture(config: ConfigManager): void {
136
- config.setDynamic('service.enabled', true);
137
- config.setDynamic('service.autostart', true);
138
- config.setDynamic('service.restartOnFailure', true);
139
- }
140
-
141
- export function enableEndpointLanDefault(config: ConfigManager, endpoint: RuntimeEndpointId): void {
142
- const binding = resolveRuntimeEndpointBinding(config, endpoint);
143
- if (binding.hostMode === 'custom') return;
144
- if (endpoint === 'controlPlane') {
145
- config.setDynamic('controlPlane.hostMode', 'network');
146
- config.setDynamic('controlPlane.host', '0.0.0.0');
147
- config.setDynamic('controlPlane.allowRemote', true);
148
- return;
149
- }
150
- if (endpoint === 'httpListener') {
151
- config.setDynamic('httpListener.hostMode', 'network');
152
- config.setDynamic('httpListener.host', '0.0.0.0');
153
- return;
154
- }
155
- config.setDynamic('web.hostMode', 'network');
156
- config.setDynamic('web.host', '0.0.0.0');
157
- }
158
-
159
- export function applyTargetEndpointFlagsOrDefault(
160
- runtime: CliCommandRuntime,
161
- endpoint: RuntimeEndpointId,
162
- ): string | null {
163
- const errors = applyRuntimeEndpointFlagOverrides(runtime.configManager, endpoint, runtime.cli.flags);
164
- if (errors.length > 0) return errors.join('\n');
165
- if (runtime.cli.flags.hostname === undefined) {
166
- enableEndpointLanDefault(runtime.configManager, endpoint);
167
- }
168
- if (endpoint === 'controlPlane') {
169
- const binding = resolveRuntimeEndpointBinding(runtime.configManager, endpoint);
170
- runtime.configManager.setDynamic('controlPlane.allowRemote', binding.hostMode !== 'local');
171
- }
172
- return null;
173
- }
174
-
175
130
  export function openBrowser(url: string): string {
176
131
  const platform = process.platform;
177
132
  const command = platform === 'darwin' ? 'open' : platform === 'win32' ? 'cmd' : 'xdg-open';
@@ -544,8 +499,8 @@ async function renderAuth(runtime: CliCommandRuntime): Promise<string> {
544
499
  ]);
545
500
  if (blocked.has(sub)) {
546
501
  return [
547
- 'Unsupported: connected-service auth user/session administration is outside GoodVibes Agent.',
548
- 'GoodVibes Agent does not create, delete, rotate, revoke, or clear connected-service users, sessions, or bootstrap credentials.',
502
+ 'Unsupported: connected-host auth user/session administration is outside GoodVibes Agent.',
503
+ 'GoodVibes Agent does not create, delete, rotate, revoke, or clear connected-host users, sessions, or bootstrap credentials.',
549
504
  'Use the owning GoodVibes host for auth administration.',
550
505
  ].join('\n');
551
506
  }
@@ -566,21 +521,21 @@ async function renderAuth(runtime: CliCommandRuntime): Promise<string> {
566
521
  if (sub === 'users' || sub === 'sessions') {
567
522
  return formatJsonOrText(runtime.cli)(value, [
568
523
  `GoodVibes Agent auth ${sub}`,
569
- ' owner: connected GoodVibes services',
524
+ ' owner: connected GoodVibes host',
570
525
  ` operator token: ${paths.operatorTokenPresent ? 'present' : 'missing'}`,
571
526
  ` operator token path: ${paths.operatorTokenPath}`,
572
527
  ` ${sub}: managed outside Agent`,
573
- ' Agent does not enumerate or mutate connected-service users/sessions from the local CLI.',
528
+ ' Agent does not enumerate or mutate connected-host users/sessions from the local CLI.',
574
529
  ].join('\n'));
575
530
  }
576
531
  return formatJsonOrText(runtime.cli)(value, [
577
532
  'GoodVibes Agent auth',
578
- ' owner: connected GoodVibes services',
533
+ ' owner: connected GoodVibes host',
579
534
  ` permission mode: ${String(value.permissionMode)}`,
580
535
  ` operator token: ${paths.operatorTokenPresent ? 'present' : 'missing'} (${paths.operatorTokenPath})`,
581
536
  ` compatibility user store: ${paths.userStorePresent ? 'present' : 'missing'} (${paths.userStorePath})`,
582
537
  ` compatibility bootstrap credential: ${paths.bootstrapCredentialPresent ? 'present' : 'missing'} (${paths.bootstrapCredentialPath})`,
583
- ' connected-service user/session administration: outside Agent',
538
+ ' connected-host user/session administration: outside Agent',
584
539
  ' next: goodvibes-agent providers',
585
540
  ' next: goodvibes-agent subscription providers',
586
541
  ].join('\n'));
package/src/cli/parser.ts CHANGED
@@ -58,7 +58,28 @@ const COMMAND_ALIASES: Readonly<Record<string, GoodVibesCliCommand>> = {
58
58
  version: 'version',
59
59
  };
60
60
 
61
- const RETIRED_LAUNCHER_ALIASES = new Set(['app', 'launch', 'start', 'tui']);
61
+ const BLOCKED_PRODUCT_COMMANDS = new Set([
62
+ 'app',
63
+ 'bridge',
64
+ 'control-plane',
65
+ 'controlplane',
66
+ 'cp',
67
+ 'daemon',
68
+ 'http-listener',
69
+ 'launch',
70
+ 'listener',
71
+ 'remote',
72
+ 'serve',
73
+ 'server',
74
+ 'service',
75
+ 'services',
76
+ 'start',
77
+ 'surface',
78
+ 'surfaces',
79
+ 'tui',
80
+ 'web',
81
+ 'webhook',
82
+ ]);
62
83
 
63
84
  function createDefaultFlags(): GoodVibesCliFlags {
64
85
  return {
@@ -200,7 +221,7 @@ export function parseGoodVibesCli(
200
221
  if (!token.startsWith('-') || token === '-') {
201
222
  if (!sawCommand) {
202
223
  const commandToken = token.toLowerCase();
203
- if (RETIRED_LAUNCHER_ALIASES.has(commandToken)) {
224
+ if (BLOCKED_PRODUCT_COMMANDS.has(commandToken)) {
204
225
  command = 'unknown';
205
226
  rawCommand = token;
206
227
  sawCommand = true;