@pellux/goodvibes-agent 0.1.116 → 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 -663
  2. package/README.md +38 -52
  3. package/dist/package/main.js +37826 -35924
  4. package/docs/README.md +5 -4
  5. package/docs/{connected-services.md → connected-host.md} +18 -10
  6. package/docs/getting-started.md +41 -44
  7. package/docs/release-and-publishing.md +6 -4
  8. package/package.json +3 -3
  9. package/src/agent/behavior-discovery-summary.ts +1 -3
  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 +3 -3
  19. package/src/agent/runtime-profile.ts +78 -0
  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 +119 -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 +345 -92
  39. package/src/input/agent-workspace-basic-command-editors.ts +480 -7
  40. package/src/input/agent-workspace-categories.ts +175 -15
  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 +23 -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 +24 -14
  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 +50 -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 +120 -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 +89 -4
  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 +81 -3
  116. package/src/input/onboarding/onboarding-wizard-steps.ts +14 -7
  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 +26 -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 +5 -5
  158. package/src/runtime/onboarding/snapshot.ts +2 -2
  159. package/src/runtime/onboarding/types.ts +26 -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
@@ -0,0 +1,153 @@
1
+ import type { AgentWorkspaceActionResult, AgentWorkspaceLocalEditor } from './agent-workspace-types.ts';
2
+ import { quoteSlashCommandArg } from './slash-command-parser.ts';
3
+
4
+ type AgentWorkspaceFieldReader = (fieldId: string) => string;
5
+
6
+ export type AgentWorkspaceWorkPlanEditorKind = 'workplan-add' | 'workplan-show' | 'workplan-status' | 'workplan-delete' | 'workplan-clear-completed';
7
+
8
+ export type AgentWorkspaceWorkPlanEditorSubmission =
9
+ | {
10
+ readonly kind: 'editor';
11
+ readonly editor: AgentWorkspaceLocalEditor;
12
+ readonly status: string;
13
+ readonly actionResult?: AgentWorkspaceActionResult;
14
+ }
15
+ | {
16
+ readonly kind: 'dispatch';
17
+ readonly command: string;
18
+ readonly status: string;
19
+ readonly actionResult: AgentWorkspaceActionResult;
20
+ };
21
+
22
+ const STATUS_COMMANDS: Record<string, string> = {
23
+ pending: 'pending',
24
+ todo: 'pending',
25
+ start: 'start',
26
+ active: 'start',
27
+ progress: 'start',
28
+ in_progress: 'start',
29
+ blocked: 'blocked',
30
+ block: 'blocked',
31
+ done: 'done',
32
+ complete: 'done',
33
+ completed: 'done',
34
+ failed: 'failed',
35
+ fail: 'failed',
36
+ cancelled: 'cancelled',
37
+ canceled: 'cancelled',
38
+ cancel: 'cancelled',
39
+ };
40
+
41
+ export function isAgentWorkspaceWorkPlanEditorKind(kind: string): kind is AgentWorkspaceWorkPlanEditorKind {
42
+ return kind === 'workplan-add'
43
+ || kind === 'workplan-show'
44
+ || kind === 'workplan-status'
45
+ || kind === 'workplan-delete'
46
+ || kind === 'workplan-clear-completed';
47
+ }
48
+
49
+ function isAffirmative(value: string): boolean {
50
+ return /^(y|yes|true)$/i.test(value.trim());
51
+ }
52
+
53
+ function unconfirmed(editor: AgentWorkspaceLocalEditor, message: string, status: string): AgentWorkspaceWorkPlanEditorSubmission {
54
+ return {
55
+ kind: 'editor',
56
+ editor: { ...editor, message },
57
+ status,
58
+ };
59
+ }
60
+
61
+ function dispatch(command: string, title: string, status: string, detail: string, safety: 'safe' | 'read-only' | 'delegates' | 'blocked'): AgentWorkspaceWorkPlanEditorSubmission {
62
+ return {
63
+ kind: 'dispatch',
64
+ command,
65
+ status,
66
+ actionResult: {
67
+ kind: 'dispatched',
68
+ title,
69
+ detail,
70
+ command,
71
+ safety,
72
+ },
73
+ };
74
+ }
75
+
76
+ export function buildAgentWorkspaceWorkPlanEditorSubmission(
77
+ editor: AgentWorkspaceLocalEditor,
78
+ readField: AgentWorkspaceFieldReader,
79
+ ): AgentWorkspaceWorkPlanEditorSubmission {
80
+ if (editor.kind === 'workplan-add') {
81
+ const parts = ['/workplan', 'add', quoteSlashCommandArg(readField('title'))];
82
+ const owner = readField('owner');
83
+ const source = readField('source');
84
+ const notes = readField('notes');
85
+ if (owner.length > 0) parts.push('--owner', quoteSlashCommandArg(owner));
86
+ if (source.length > 0) parts.push('--source', quoteSlashCommandArg(source));
87
+ if (notes.length > 0) parts.push('--notes', quoteSlashCommandArg(notes));
88
+ return dispatch(
89
+ parts.join(' '),
90
+ 'Opening work plan item creation',
91
+ 'Opening work plan item creation.',
92
+ 'The workspace handed a visible work plan item creation command to the shell-owned command router.',
93
+ 'safe',
94
+ );
95
+ }
96
+
97
+ if (editor.kind === 'workplan-show') {
98
+ const format = readField('format').trim().toLowerCase();
99
+ const command = format === 'markdown' ? '/workplan markdown' : '/workplan show';
100
+ return dispatch(
101
+ command,
102
+ 'Opening work plan detail',
103
+ 'Opening work plan detail.',
104
+ 'The workspace handed read-only work plan detail inspection to the shell-owned command router.',
105
+ 'read-only',
106
+ );
107
+ }
108
+
109
+ if (editor.kind === 'workplan-status') {
110
+ const requested = readField('status').trim().toLowerCase().replace(/[\s-]+/g, '_');
111
+ const commandStatus = STATUS_COMMANDS[requested];
112
+ if (!commandStatus) {
113
+ return {
114
+ kind: 'editor',
115
+ editor: { ...editor, message: 'Invalid status. Use pending, start, blocked, done, failed, or cancelled.' },
116
+ status: 'Work plan status update needs a valid status.',
117
+ };
118
+ }
119
+ const command = `/workplan ${commandStatus} ${quoteSlashCommandArg(readField('id'))}`;
120
+ return dispatch(
121
+ command,
122
+ 'Opening work plan status update',
123
+ 'Opening work plan status update.',
124
+ 'The workspace handed a visible work plan status update command to the shell-owned command router.',
125
+ 'safe',
126
+ );
127
+ }
128
+
129
+ if (editor.kind === 'workplan-delete') {
130
+ if (!isAffirmative(readField('confirm'))) {
131
+ return unconfirmed(editor, 'Work plan removal not confirmed. Type yes, then press Enter.', 'Work plan removal not confirmed.');
132
+ }
133
+ const command = `/workplan remove ${quoteSlashCommandArg(readField('id'))} --yes`;
134
+ return dispatch(
135
+ command,
136
+ 'Opening work plan item removal',
137
+ 'Opening work plan item removal.',
138
+ 'The workspace handed a confirmed work plan removal command to the shell-owned command router.',
139
+ 'safe',
140
+ );
141
+ }
142
+
143
+ if (!isAffirmative(readField('confirm'))) {
144
+ return unconfirmed(editor, 'Clear completed work plan items not confirmed. Type yes, then press Enter.', 'Clear completed work plan items not confirmed.');
145
+ }
146
+ return dispatch(
147
+ '/workplan clear-completed --yes',
148
+ 'Opening completed work plan cleanup',
149
+ 'Opening completed work plan cleanup.',
150
+ 'The workspace handed a confirmed work plan cleanup command to the shell-owned command router.',
151
+ 'safe',
152
+ );
153
+ }
@@ -11,24 +11,15 @@ import { AGENT_WORKSPACE_CATEGORIES } from './agent-workspace-categories.ts';
11
11
  import { buildAgentWorkspaceCommandEditorSubmission, isAgentWorkspaceCommandEditorKind } from './agent-workspace-command-editor.ts';
12
12
  import { quoteSlashCommandArg } from './slash-command-parser.ts';
13
13
  import { createDeleteEditor, createMemoryUpdateEditor, createPersonaUpdateEditor, createRoutineUpdateEditor, createSkillUpdateEditor, editorCategoryId, isAffirmative, splitList } from './agent-workspace-editors.ts';
14
+ import { createAgentWorkspaceLearnedBehavior } from './agent-workspace-learned-behavior.ts';
14
15
  import { deleteAgentWorkspaceMemoryEditor, submitAgentWorkspaceMemoryEditor } from './agent-workspace-memory-editor.ts';
16
+ import { jumpAgentWorkspaceSelection, moveAgentWorkspaceSelection, selectAgentWorkspaceCategory } from './agent-workspace-navigation.ts';
17
+ import { buildAgentWorkspaceRequirements } from './agent-workspace-requirements.ts';
15
18
  import { buildAgentWorkspaceRuntimeSnapshot } from './agent-workspace-snapshot.ts';
16
19
  import type { AgentWorkspaceAction, AgentWorkspaceActionResult, AgentWorkspaceCategory, AgentWorkspaceCommandDispatcher, AgentWorkspaceEditorField, AgentWorkspaceFocusPane, AgentWorkspaceLocalEditor, AgentWorkspaceLocalEditorKind, AgentWorkspaceLocalLibraryItem, AgentWorkspaceLocalOperation, AgentWorkspaceRuntimeSnapshot } from './agent-workspace-types.ts';
17
20
 
18
21
  export type { AgentWorkspaceChannelRisk, AgentWorkspaceChannelStatus } from './agent-workspace-channels.ts';
19
- export type {
20
- AgentWorkspaceAction,
21
- AgentWorkspaceActionResult,
22
- AgentWorkspaceCategory,
23
- AgentWorkspaceCommandDispatcher,
24
- AgentWorkspaceEditorField,
25
- AgentWorkspaceFocusPane,
26
- AgentWorkspaceLocalEditor,
27
- AgentWorkspaceLocalEditorKind,
28
- AgentWorkspaceLocalLibraryItem,
29
- AgentWorkspaceLocalOperation,
30
- AgentWorkspaceRuntimeSnapshot,
31
- } from './agent-workspace-types.ts';
22
+ export type { AgentWorkspaceAction, AgentWorkspaceActionResult, AgentWorkspaceCategory, AgentWorkspaceCommandDispatcher, AgentWorkspaceEditorField, AgentWorkspaceFocusPane, AgentWorkspaceLocalEditor, AgentWorkspaceLocalEditorKind, AgentWorkspaceLocalLibraryItem, AgentWorkspaceLocalOperation, AgentWorkspaceRuntimeSnapshot } from './agent-workspace-types.ts';
32
23
  export { AGENT_WORKSPACE_MODAL_NAME } from './agent-workspace-types.ts';
33
24
  export { buildAgentWorkspaceRuntimeSnapshot } from './agent-workspace-snapshot.ts';
34
25
  export { handleAgentWorkspaceToken } from './agent-workspace-token.ts';
@@ -52,7 +43,7 @@ export class AgentWorkspace {
52
43
  private context: CommandContext | null = null;
53
44
  private dispatchCommand: AgentWorkspaceCommandDispatcher | null = null;
54
45
 
55
- open(context: CommandContext, dispatchCommand: AgentWorkspaceCommandDispatcher): void {
46
+ open(context: CommandContext, dispatchCommand: AgentWorkspaceCommandDispatcher, categoryId?: string): void {
56
47
  this.context = context;
57
48
  this.dispatchCommand = dispatchCommand;
58
49
  this.runtimeSnapshot = buildAgentWorkspaceRuntimeSnapshot(context);
@@ -61,6 +52,16 @@ export class AgentWorkspace {
61
52
  this.status = 'Ready. Choose an operator flow; ordinary assistant work stays in the main conversation.';
62
53
  this.lastActionResult = null;
63
54
  this.localEditor = null;
55
+ if (categoryId && !this.selectCategory(categoryId)) {
56
+ const normalized = categoryId.trim();
57
+ this.status = `Unknown Agent workspace area: ${normalized}.`;
58
+ this.lastActionResult = {
59
+ kind: 'guidance',
60
+ title: 'Unknown Agent workspace area',
61
+ detail: `Use one of: ${this.categories.map((category) => category.id).join(', ')}.`,
62
+ safety: 'safe',
63
+ };
64
+ }
64
65
  this.clampSelection();
65
66
  }
66
67
 
@@ -90,6 +91,10 @@ export class AgentWorkspace {
90
91
  return this.actions[this.selectedActionIndex] ?? null;
91
92
  }
92
93
 
94
+ selectCategory(categoryIdOrLabel: string): boolean {
95
+ return selectAgentWorkspaceCategory(this, categoryIdOrLabel);
96
+ }
97
+
93
98
  selectedLocalLibraryItem(kind: AgentWorkspaceLocalEditorKind): AgentWorkspaceLocalLibraryItem | null {
94
99
  const items = this.localLibraryItems(kind);
95
100
  if (items.length === 0) return null;
@@ -110,35 +115,19 @@ export class AgentWorkspace {
110
115
  }
111
116
 
112
117
  moveUp(): void {
113
- if (this.focusPane === 'categories') {
114
- this.selectedCategoryIndex = Math.max(0, this.selectedCategoryIndex - 1);
115
- this.selectedActionIndex = 0;
116
- } else {
117
- this.selectedActionIndex = Math.max(0, this.selectedActionIndex - 1);
118
- }
119
- this.clampSelection();
118
+ moveAgentWorkspaceSelection(this, -1);
120
119
  }
121
120
 
122
121
  moveDown(): void {
123
- if (this.focusPane === 'categories') {
124
- this.selectedCategoryIndex = Math.min(this.categories.length - 1, this.selectedCategoryIndex + 1);
125
- this.selectedActionIndex = 0;
126
- } else {
127
- this.selectedActionIndex = Math.min(this.actions.length - 1, this.selectedActionIndex + 1);
128
- }
129
- this.clampSelection();
122
+ moveAgentWorkspaceSelection(this, 1);
130
123
  }
131
124
 
132
125
  jumpHome(): void {
133
- if (this.focusPane === 'categories') this.selectedCategoryIndex = 0;
134
- else this.selectedActionIndex = 0;
135
- this.clampSelection();
126
+ jumpAgentWorkspaceSelection(this, 'home');
136
127
  }
137
128
 
138
129
  jumpEnd(): void {
139
- if (this.focusPane === 'categories') this.selectedCategoryIndex = this.categories.length - 1;
140
- else this.selectedActionIndex = this.actions.length - 1;
141
- this.clampSelection();
130
+ jumpAgentWorkspaceSelection(this, 'end');
142
131
  }
143
132
 
144
133
  refreshRuntimeSnapshot(): void {
@@ -184,7 +173,7 @@ export class AgentWorkspace {
184
173
  if (!editor || text.length === 0) return;
185
174
  const field = editor.fields[editor.selectedFieldIndex];
186
175
  if (!field) return;
187
- this.replaceEditorField(editor.selectedFieldIndex, `${field.value}${text}`, editor.message);
176
+ this.replaceEditorField(editor.selectedFieldIndex, `${field.value}${field.multiline ? text.replace(/\r\n?/g, '\n') : text.replace(/[\r\n]+/g, ' ')}`, editor.message);
188
177
  }
189
178
 
190
179
  appendEditorNewline(): void {
@@ -432,6 +421,12 @@ export class AgentWorkspace {
432
421
  return memory;
433
422
  }
434
423
 
424
+ private learnedBehaviorTarget(): Exclude<AgentWorkspaceLocalEditorKind, 'memory' | 'profile'> {
425
+ const target = this.editorField('target').trim().toLowerCase();
426
+ if (target === 'persona' || target === 'skill' || target === 'routine') return target;
427
+ throw new Error('Behavior type must be skill, routine, or persona.');
428
+ }
429
+
435
430
  private finishLocalOperation(kind: AgentWorkspaceLocalEditorKind, title: string, detail: string): void {
436
431
  this.runtimeSnapshot = this.context ? buildAgentWorkspaceRuntimeSnapshot(this.context) : this.runtimeSnapshot;
437
432
  this.clampLocalLibrarySelection(kind);
@@ -528,7 +523,18 @@ export class AgentWorkspace {
528
523
  this.submitLocalDeleteEditor(shellPaths, editor);
529
524
  return;
530
525
  }
531
- if (editor.kind === 'profile') {
526
+ if (editor.kind === 'learned-behavior') {
527
+ const created = createAgentWorkspaceLearnedBehavior(shellPaths, {
528
+ target: this.learnedBehaviorTarget(),
529
+ name: this.editorField('name'),
530
+ description: this.editorField('description'),
531
+ notes: this.editorField('notes'),
532
+ tags: splitList(this.editorField('tags')),
533
+ triggers: splitList(this.editorField('triggers')),
534
+ enable: isAffirmative(this.editorField('enable')),
535
+ });
536
+ this.finishLocalEditor(created.kind, created.id, created.name, 'Created');
537
+ } else if (editor.kind === 'profile') {
532
538
  const template = this.editorField('template');
533
539
  const templateId = template && template.toLowerCase() !== 'none' ? template : undefined;
534
540
  const profile = createAgentRuntimeProfile(shellPaths.homeDirectory, this.editorField('name'), {
@@ -572,6 +578,7 @@ export class AgentWorkspace {
572
578
  procedure: this.editorField('procedure'),
573
579
  triggers: splitList(this.editorField('triggers')),
574
580
  tags: splitList(this.editorField('tags')),
581
+ requirements: buildAgentWorkspaceRequirements((id) => this.editorField(id)),
575
582
  provenance: 'agent-workspace',
576
583
  });
577
584
  registry.setEnabled(updated.id, isAffirmative(this.editorField('enabled')));
@@ -584,6 +591,7 @@ export class AgentWorkspace {
584
591
  procedure: this.editorField('procedure'),
585
592
  triggers: splitList(this.editorField('triggers')),
586
593
  tags: splitList(this.editorField('tags')),
594
+ requirements: buildAgentWorkspaceRequirements((id) => this.editorField(id)),
587
595
  enabled: isAffirmative(this.editorField('enabled')),
588
596
  source: 'user',
589
597
  provenance: 'agent-workspace',
@@ -598,6 +606,7 @@ export class AgentWorkspace {
598
606
  steps: this.editorField('steps'),
599
607
  triggers: splitList(this.editorField('triggers')),
600
608
  tags: splitList(this.editorField('tags')),
609
+ requirements: buildAgentWorkspaceRequirements((id) => this.editorField(id)),
601
610
  provenance: 'agent-workspace',
602
611
  });
603
612
  registry.setEnabled(updated.id, isAffirmative(this.editorField('enabled')));
@@ -610,6 +619,7 @@ export class AgentWorkspace {
610
619
  steps: this.editorField('steps'),
611
620
  triggers: splitList(this.editorField('triggers')),
612
621
  tags: splitList(this.editorField('tags')),
622
+ requirements: buildAgentWorkspaceRequirements((id) => this.editorField(id)),
613
623
  enabled: isAffirmative(this.editorField('enabled')),
614
624
  source: 'user',
615
625
  provenance: 'agent-workspace',
@@ -755,7 +765,7 @@ export class AgentWorkspace {
755
765
  this.lastActionResult = {
756
766
  kind: 'refreshed',
757
767
  title: 'Created Agent profile',
758
- detail: `Created isolated Agent profile ${profile.id}${starter}. Launch it with goodvibes-agent --agent-profile ${profile.id}. The current TUI session was not switched.`,
768
+ detail: `Created isolated Agent profile ${profile.id}${starter}. Launch it with goodvibes-agent --agent-profile ${profile.id}. The current Agent session was not switched.`,
759
769
  safety: 'safe',
760
770
  };
761
771
  this.clampSelection();
@@ -110,7 +110,7 @@ export interface CommandShellUiOpeners {
110
110
  focusPrompt?: () => void;
111
111
  openPolicyPanel?: () => void;
112
112
  openMcpWorkspace?: () => void;
113
- openAgentWorkspace?: () => void;
113
+ openAgentWorkspace?: (categoryId?: string) => void;
114
114
  openSecurityPanel?: () => void;
115
115
  openKnowledgePanel?: () => void;
116
116
  openSubscriptionPanel?: () => void;
@@ -1,6 +1,7 @@
1
1
  import { mkdirSync } from 'node:fs';
2
2
  import { dirname } from 'node:path';
3
3
  import {
4
+ clearAgentRuntimeProfileSelection,
4
5
  createAgentRuntimeProfileFromDiscovered,
5
6
  createAgentRuntimeProfileTemplateFromDiscovered,
6
7
  createAgentRuntimeProfile,
@@ -10,6 +11,9 @@ import {
10
11
  importAgentRuntimeProfileTemplate,
11
12
  listAgentRuntimeProfiles,
12
13
  listAgentRuntimeProfileTemplates,
14
+ readAgentRuntimeProfileSelection,
15
+ resolveAgentRuntimeProfileHome,
16
+ setAgentRuntimeProfileSelection,
13
17
  type AgentRuntimeProfileInfo,
14
18
  type AgentRuntimeProfileTemplateSummary,
15
19
  } from '../../agent/runtime-profile.ts';
@@ -49,14 +53,29 @@ function templateLine(template: AgentRuntimeProfileTemplateSummary): string {
49
53
 
50
54
  function renderProfiles(homeDirectory: string): string {
51
55
  const profiles = listAgentRuntimeProfiles(homeDirectory);
56
+ const selected = readAgentRuntimeProfileSelection(homeDirectory);
57
+ const defaultLine = selected ? ` default: ${selected.id}${selected.exists ? '' : ' (missing)'}` : ' default: (base Agent home)';
52
58
  if (profiles.length === 0) {
53
59
  return [
54
60
  'Agent Profiles',
61
+ defaultLine,
55
62
  ' No isolated Agent profiles yet.',
56
63
  ' Create one with /agent-profile create <name> --template <id> --yes.',
57
64
  ].join('\n');
58
65
  }
59
- return ['Agent Profiles', ...profiles.map(profileLine)].join('\n');
66
+ return ['Agent Profiles', defaultLine, ...profiles.map(profileLine)].join('\n');
67
+ }
68
+
69
+ function renderProfileDetail(homeDirectory: string, name: string): string {
70
+ const profile = resolveAgentRuntimeProfileHome(homeDirectory, name);
71
+ const info = listAgentRuntimeProfiles(homeDirectory).find((entry) => entry.id === profile.id) ?? { ...profile, createdAt: null };
72
+ const starter = info.starterTemplateId ? [` starter: ${info.starterTemplateId} (${info.starterTemplateName ?? info.starterTemplateId})`] : [];
73
+ return [
74
+ `Agent profile: ${profile.id}`,
75
+ ` home: ${profile.homeDirectory}`,
76
+ ...starter,
77
+ ` use: goodvibes-agent --agent-profile ${profile.id}`,
78
+ ].join('\n');
60
79
  }
61
80
 
62
81
  function renderTemplates(homeDirectory: string): string {
@@ -92,7 +111,7 @@ function renderGuide(homeDirectory: string): string {
92
111
  '5. Create an Agent profile from the imported starter:',
93
112
  ' /agent-profile create <name> --template <imported-id> --yes',
94
113
  '',
95
- 'This writes only Agent-local starter/profile state. It does not mutate connected GoodVibes services, default wiki, or non-Agent knowledge segments.',
114
+ 'This writes only Agent-local starter/profile state. It does not mutate connected GoodVibes host, default wiki, or non-Agent knowledge segments.',
96
115
  ].join('\n');
97
116
  }
98
117
 
@@ -117,7 +136,7 @@ export function registerAgentRuntimeProfileRuntimeCommands(registry: CommandRegi
117
136
  name: 'agent-profile',
118
137
  aliases: ['runtime-profile', 'agent-profiles'],
119
138
  description: 'Manage isolated Agent profiles and starter templates',
120
- usage: '[list|templates|guide|template show|template export|template import|template from-discovered|create|create-from-discovered|delete]',
139
+ usage: '[list|show|default|use|templates|guide|template show|template export|template import|template from-discovered|create|create-from-discovered|delete]',
121
140
  async handler(args, ctx) {
122
141
  const shellPaths = requireShellPaths(ctx);
123
142
  const homeDirectory = shellPaths.homeDirectory;
@@ -136,6 +155,72 @@ export function registerAgentRuntimeProfileRuntimeCommands(registry: CommandRegi
136
155
  return;
137
156
  }
138
157
 
158
+ if (sub === 'show' || sub === 'path' || sub === 'home') {
159
+ const name = commandArgs[1];
160
+ if (!name) {
161
+ ctx.print('Usage: /agent-profile show <name>');
162
+ return;
163
+ }
164
+ ctx.print(renderProfileDetail(homeDirectory, name));
165
+ return;
166
+ }
167
+
168
+ if (sub === 'default') {
169
+ const target = commandArgs[1];
170
+ if (target === 'clear' || target === 'none' || target === 'base') {
171
+ if (!parsed.yes) {
172
+ requireYesFlag(ctx, 'clear the default Agent profile', '/agent-profile default clear --yes');
173
+ return;
174
+ }
175
+ clearAgentRuntimeProfileSelection(homeDirectory);
176
+ ctx.print('Default Agent profile cleared. Next launch uses the base Agent home unless --agent-profile is provided.');
177
+ return;
178
+ }
179
+ if (target) {
180
+ if (!parsed.yes) {
181
+ requireYesFlag(ctx, `set default Agent profile ${target}`, '/agent-profile default <name> --yes');
182
+ return;
183
+ }
184
+ const selected = setAgentRuntimeProfileSelection(homeDirectory, target);
185
+ ctx.print([
186
+ `Default Agent profile selected: ${selected.id}`,
187
+ ` home: ${selected.homeDirectory}`,
188
+ ' next launch: goodvibes-agent',
189
+ ' explicit override: goodvibes-agent --agent-profile <name>',
190
+ ].join('\n'));
191
+ return;
192
+ }
193
+ const selected = readAgentRuntimeProfileSelection(homeDirectory);
194
+ ctx.print(selected
195
+ ? [
196
+ `Default Agent profile: ${selected.id}${selected.exists ? '' : ' (missing)'}`,
197
+ ` home: ${selected.homeDirectory}`,
198
+ ' next launch: goodvibes-agent',
199
+ ].join('\n')
200
+ : 'No default Agent profile selected. Next launch uses the base Agent home.');
201
+ return;
202
+ }
203
+
204
+ if (sub === 'use' || sub === 'select' || sub === 'switch') {
205
+ const name = commandArgs[1];
206
+ if (!name) {
207
+ ctx.print('Usage: /agent-profile use <name> --yes');
208
+ return;
209
+ }
210
+ if (!parsed.yes) {
211
+ requireYesFlag(ctx, `set default Agent profile ${name}`, '/agent-profile use <name> --yes');
212
+ return;
213
+ }
214
+ const selected = setAgentRuntimeProfileSelection(homeDirectory, name);
215
+ ctx.print([
216
+ `Default Agent profile selected: ${selected.id}`,
217
+ ` home: ${selected.homeDirectory}`,
218
+ ' next launch: goodvibes-agent',
219
+ ' explicit override: goodvibes-agent --agent-profile <name>',
220
+ ].join('\n'));
221
+ return;
222
+ }
223
+
139
224
  if (sub === 'guide' || sub === 'author') {
140
225
  ctx.print(renderGuide(homeDirectory));
141
226
  return;
@@ -283,7 +368,7 @@ export function registerAgentRuntimeProfileRuntimeCommands(registry: CommandRegi
283
368
  return;
284
369
  }
285
370
 
286
- ctx.print('Usage: /agent-profile [list|templates|guide|template show <id>|template export <id> <path> --yes|template import <path> --yes|create <name> [--template <id>] --yes|create-from-discovered <name> --yes|delete <name> --yes]');
371
+ ctx.print('Usage: /agent-profile [list|show <name>|default [<name>|clear] --yes|use <name> --yes|templates|guide|template show <id>|template export <id> <path> --yes|template import <path> --yes|create <name> [--template <id>] --yes|create-from-discovered <name> --yes|delete <name> --yes]');
287
372
  } catch (error) {
288
373
  ctx.print(`Error: ${error instanceof Error ? error.message : String(error)}`);
289
374
  }