@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.
- package/CHANGELOG.md +41 -650
- package/README.md +40 -50
- package/dist/package/main.js +38224 -35673
- package/docs/README.md +5 -4
- package/docs/{connected-services.md → connected-host.md} +18 -10
- package/docs/getting-started.md +43 -42
- package/docs/release-and-publishing.md +6 -4
- package/package.json +3 -3
- package/src/agent/behavior-discovery-summary.ts +165 -0
- package/src/agent/persona-discovery.ts +1 -3
- package/src/agent/persona-registry.ts +5 -3
- package/src/agent/reminder-schedule-format.ts +6 -6
- package/src/agent/reminder-schedule.ts +1 -1
- package/src/agent/routine-registry.ts +43 -4
- package/src/agent/routine-schedule-format.ts +6 -6
- package/src/agent/routine-schedule-promotion.ts +1 -1
- package/src/agent/routine-schedule-receipts.ts +1 -1
- package/src/agent/runtime-profile-starters.ts +331 -0
- package/src/agent/runtime-profile.ts +228 -330
- package/src/agent/skill-registry.ts +190 -13
- package/src/cli/agent-knowledge-command.ts +2 -2
- package/src/cli/agent-knowledge-format.ts +2 -2
- package/src/cli/agent-knowledge-runtime.ts +1 -1
- package/src/cli/bundle-command.ts +1 -1
- package/src/cli/entrypoint.ts +16 -7
- package/src/cli/help.ts +26 -19
- package/src/cli/local-library-command.ts +75 -21
- package/src/cli/management-commands.ts +7 -6
- package/src/cli/management.ts +6 -51
- package/src/cli/parser.ts +23 -2
- package/src/cli/profiles-command.ts +247 -1
- package/src/cli/routines-command.ts +139 -11
- package/src/cli/service-posture.ts +11 -11
- package/src/cli/status.ts +21 -25
- package/src/input/agent-workspace-access-command-editor-submission.ts +149 -0
- package/src/input/agent-workspace-access-command-editors.ts +170 -0
- package/src/input/agent-workspace-activation.ts +2 -1
- package/src/input/agent-workspace-basic-command-editor-submission.ts +787 -0
- package/src/input/agent-workspace-basic-command-editors.ts +524 -459
- package/src/input/agent-workspace-categories.ts +177 -14
- package/src/input/agent-workspace-channel-command-editor-submission.ts +49 -0
- package/src/input/agent-workspace-channel-command-editors.ts +47 -0
- package/src/input/agent-workspace-command-editor.ts +25 -1
- package/src/input/agent-workspace-delegation-editor-submission.ts +55 -0
- package/src/input/agent-workspace-editors.ts +27 -0
- package/src/input/agent-workspace-knowledge-command-editor-submission.ts +132 -0
- package/src/input/agent-workspace-knowledge-command-editors.ts +110 -0
- package/src/input/agent-workspace-learned-behavior.ts +67 -0
- package/src/input/agent-workspace-library-command-editor-submission.ts +50 -0
- package/src/input/agent-workspace-library-command-editors.ts +35 -0
- package/src/input/agent-workspace-mcp-command-editor-submission.ts +95 -0
- package/src/input/agent-workspace-memory-command-editor-submission.ts +232 -0
- package/src/input/agent-workspace-memory-command-editors.ts +180 -0
- package/src/input/agent-workspace-navigation.ts +45 -0
- package/src/input/agent-workspace-notify-editor-submission.ts +107 -0
- package/src/input/agent-workspace-operations-command-editor-submission.ts +146 -0
- package/src/input/agent-workspace-operations-command-editors.ts +119 -0
- package/src/input/agent-workspace-provider-command-editor-submission.ts +155 -0
- package/src/input/agent-workspace-provider-command-editors.ts +93 -0
- package/src/input/agent-workspace-requirements.ts +11 -0
- package/src/input/agent-workspace-secret-editor-submission.ts +153 -0
- package/src/input/agent-workspace-session-command-editor-submission.ts +199 -0
- package/src/input/agent-workspace-session-command-editors.ts +249 -0
- package/src/input/agent-workspace-setup.ts +49 -19
- package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +101 -0
- package/src/input/agent-workspace-skill-bundle-command-editors.ts +110 -0
- package/src/input/agent-workspace-snapshot.ts +56 -8
- package/src/input/agent-workspace-task-command-editor-submission.ts +61 -0
- package/src/input/agent-workspace-task-command-editors.ts +47 -0
- package/src/input/agent-workspace-types.ts +124 -0
- package/src/input/agent-workspace-voice-media.ts +1 -1
- package/src/input/agent-workspace-workplan-editor-submission.ts +153 -0
- package/src/input/agent-workspace.ts +47 -37
- package/src/input/command-registry.ts +1 -1
- package/src/input/commands/agent-runtime-profile-runtime.ts +160 -6
- package/src/input/commands/agent-skills-runtime.ts +76 -12
- package/src/input/commands/agent-workspace-runtime.ts +4 -3
- package/src/input/commands/brief-runtime.ts +38 -9
- package/src/input/commands/channels-runtime.ts +3 -3
- package/src/input/commands/compat-runtime.ts +32 -0
- package/src/input/commands/health-runtime.ts +22 -24
- package/src/input/commands/knowledge.ts +26 -5
- package/src/input/commands/local-provider-runtime.ts +7 -3
- package/src/input/commands/local-setup-review.ts +4 -14
- package/src/input/commands/mcp-runtime.ts +8 -12
- package/src/input/commands/operator-runtime.ts +8 -67
- package/src/input/commands/personas-runtime.ts +1 -1
- package/src/input/commands/platform-access-runtime.ts +7 -70
- package/src/input/commands/policy-dispatch.ts +1 -1
- package/src/input/commands/policy.ts +1 -5
- package/src/input/commands/product-runtime.ts +2 -2
- package/src/input/commands/qrcode-runtime.ts +6 -4
- package/src/input/commands/routines-runtime.ts +44 -6
- package/src/input/commands/runtime-services.ts +1 -14
- package/src/input/commands/security-runtime.ts +3 -8
- package/src/input/commands/session-content.ts +1 -1
- package/src/input/commands/session-workflow.ts +5 -14
- package/src/input/commands/shell-core.ts +8 -2
- package/src/input/commands/subscription-runtime.ts +1 -6
- package/src/input/commands/support-bundle-runtime.ts +53 -0
- package/src/input/commands/tasks-runtime.ts +2 -2
- package/src/input/commands.ts +4 -0
- package/src/input/feed-context-factory.ts +0 -1
- package/src/input/handler-content-actions.ts +0 -25
- package/src/input/handler-feed.ts +0 -2
- package/src/input/handler-interactions.ts +2 -31
- package/src/input/handler-onboarding.ts +29 -12
- package/src/input/handler-shortcuts.ts +1 -3
- package/src/input/handler.ts +4 -7
- package/src/input/keybindings.ts +9 -9
- package/src/input/mcp-workspace.ts +90 -26
- package/src/input/onboarding/handler-onboarding-routes.ts +3 -1
- package/src/input/onboarding/onboarding-wizard-apply.ts +49 -0
- package/src/input/onboarding/onboarding-wizard-helpers.ts +1 -1
- package/src/input/onboarding/onboarding-wizard-operator-steps.ts +126 -11
- package/src/input/onboarding/onboarding-wizard-steps.ts +15 -8
- package/src/input/onboarding/onboarding-wizard-types.ts +1 -0
- package/src/input/onboarding/onboarding-wizard.ts +19 -2
- package/src/input/profile-picker-modal.ts +2 -2
- package/src/input/settings-modal-agent-policy.ts +6 -6
- package/src/input/settings-modal-subscriptions.ts +3 -3
- package/src/input/settings-modal.ts +14 -14
- package/src/main.ts +0 -2
- package/src/panels/automation-control-panel.ts +3 -3
- package/src/panels/builtin/agent.ts +1 -1
- package/src/panels/builtin/operations.ts +2 -2
- package/src/panels/builtin/session.ts +26 -18
- package/src/panels/builtin/shared.ts +6 -6
- package/src/panels/project-planning-panel.ts +1 -1
- package/src/panels/provider-health-domains.ts +3 -3
- package/src/panels/qr-panel.ts +44 -20
- package/src/panels/subscription-panel.ts +3 -3
- package/src/panels/system-messages-panel.ts +2 -2
- package/src/panels/tasks-panel.ts +4 -4
- package/src/planning/project-planning-coordinator.ts +2 -2
- package/src/renderer/agent-workspace.ts +52 -5
- package/src/renderer/block-actions.ts +1 -3
- package/src/renderer/help-overlay.ts +13 -8
- package/src/renderer/mcp-workspace.ts +32 -13
- package/src/renderer/model-picker-overlay.ts +0 -1
- package/src/renderer/model-workspace.ts +0 -2
- package/src/renderer/onboarding/onboarding-wizard.ts +20 -4
- package/src/renderer/panel-picker-overlay.ts +1 -1
- package/src/renderer/profile-picker-modal.ts +2 -2
- package/src/renderer/settings-modal-helpers.ts +23 -23
- package/src/renderer/settings-modal.ts +18 -18
- package/src/renderer/system-message.ts +1 -1
- package/src/runtime/agent-runtime-events.ts +129 -0
- package/src/runtime/bootstrap-command-parts.ts +3 -2
- package/src/runtime/bootstrap-core.ts +4 -64
- package/src/runtime/bootstrap-shell.ts +42 -4
- package/src/runtime/bootstrap.ts +8 -27
- package/src/runtime/connected-host-auth.ts +42 -0
- package/src/runtime/diagnostics/panels/panel-resources.ts +1 -1
- package/src/runtime/index.ts +1 -5
- package/src/runtime/onboarding/apply.ts +213 -0
- package/src/runtime/onboarding/derivation.ts +25 -6
- package/src/runtime/onboarding/snapshot.ts +4 -2
- package/src/runtime/onboarding/types.ts +28 -1
- package/src/runtime/onboarding/verify.ts +81 -2
- package/src/runtime/operator-token-cleanup.ts +2 -2
- package/src/runtime/services.ts +27 -12
- package/src/shell/service-settings-sync.ts +7 -7
- package/src/shell/ui-openers.ts +27 -38
- package/src/tools/agent-local-registry-tool.ts +10 -4
- package/src/tools/agent-tool-policy-guard.ts +5 -7
- package/src/version.ts +1 -1
- package/src/cli/package-verification.ts +0 -274
|
@@ -16,7 +16,7 @@ export const MCP_WORKSPACE_MODAL_NAME = 'mcpWorkspace';
|
|
|
16
16
|
const MCP_ROLES = ['general', 'docs', 'filesystem', 'git', 'database', 'browser', 'automation', 'ops', 'remote'] as const;
|
|
17
17
|
const MCP_FORM_TRUST_MODES = ['constrained', 'ask-on-risk', 'blocked'] as const;
|
|
18
18
|
|
|
19
|
-
export type McpWorkspaceMode = 'browse' | 'form' | 'delete-confirm';
|
|
19
|
+
export type McpWorkspaceMode = 'browse' | 'form' | 'delete-confirm' | 'reload-confirm';
|
|
20
20
|
|
|
21
21
|
export interface McpWorkspaceServerRow {
|
|
22
22
|
readonly name: string;
|
|
@@ -62,6 +62,7 @@ export interface McpWorkspaceForm {
|
|
|
62
62
|
env: string;
|
|
63
63
|
allowedPaths: string;
|
|
64
64
|
allowedHosts: string;
|
|
65
|
+
confirm: string;
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
interface McpWorkspaceSnapshot {
|
|
@@ -71,8 +72,12 @@ interface McpWorkspaceSnapshot {
|
|
|
71
72
|
readonly servers: readonly McpWorkspaceServerRow[];
|
|
72
73
|
}
|
|
73
74
|
|
|
74
|
-
function isTextField(field: keyof McpWorkspaceForm | 'save' | 'cancel'): field is 'name' | 'command' | 'args' | 'env' | 'allowedPaths' | 'allowedHosts' {
|
|
75
|
-
return field === 'name' || field === 'command' || field === 'args' || field === 'env' || field === 'allowedPaths' || field === 'allowedHosts';
|
|
75
|
+
function isTextField(field: keyof McpWorkspaceForm | 'save' | 'cancel'): field is 'name' | 'command' | 'args' | 'env' | 'allowedPaths' | 'allowedHosts' | 'confirm' {
|
|
76
|
+
return field === 'name' || field === 'command' || field === 'args' || field === 'env' || field === 'allowedPaths' || field === 'allowedHosts' || field === 'confirm';
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function isAffirmative(value: string): boolean {
|
|
80
|
+
return /^(y|yes|true)$/i.test(value.trim());
|
|
76
81
|
}
|
|
77
82
|
|
|
78
83
|
function splitList(value: string): string[] {
|
|
@@ -141,6 +146,7 @@ function serverConfigToForm(server?: McpServerConfig): McpWorkspaceForm {
|
|
|
141
146
|
env: server?.env ? Object.entries(server.env).map(([key, value]) => `${key}=${value}`).join(', ') : '',
|
|
142
147
|
allowedPaths: server?.allowedPaths?.join(', ') ?? '',
|
|
143
148
|
allowedHosts: server?.allowedHosts?.join(', ') ?? '',
|
|
149
|
+
confirm: '',
|
|
144
150
|
};
|
|
145
151
|
}
|
|
146
152
|
|
|
@@ -214,7 +220,7 @@ export class McpWorkspace {
|
|
|
214
220
|
public formIndex = 0;
|
|
215
221
|
public form: McpWorkspaceForm = serverConfigToForm();
|
|
216
222
|
public editingServerName: string | null = null;
|
|
217
|
-
public status = 'Ready. Inspect MCP servers and tools. Config writes/reloads require explicit
|
|
223
|
+
public status = 'Ready. Inspect MCP servers and tools. Config writes/reloads require explicit workspace confirmation.';
|
|
218
224
|
public tools: readonly RegisteredTool[] = [];
|
|
219
225
|
public loadingTools = false;
|
|
220
226
|
public lastError: string | null = null;
|
|
@@ -257,8 +263,8 @@ export class McpWorkspace {
|
|
|
257
263
|
get rows(): readonly McpWorkspaceRow[] {
|
|
258
264
|
return [
|
|
259
265
|
...this.snapshot.servers.map((server): McpWorkspaceRow => ({ type: 'server', server })),
|
|
260
|
-
{ type: 'action', id: 'add', label: 'Add server
|
|
261
|
-
{ type: 'action', id: 'reload', label: 'Reload
|
|
266
|
+
{ type: 'action', id: 'add', label: 'Add or update server', detail: `Open a confirmed Agent workspace form to save an MCP server in ${this.form.scope} scope.` },
|
|
267
|
+
{ type: 'action', id: 'reload', label: 'Reload runtime', detail: 'Confirm an MCP runtime reload from this workspace after external config edits.' },
|
|
262
268
|
{ type: 'action', id: 'refresh-tools', label: 'Refresh tools', detail: 'Fetch the currently available MCP tool list from connected servers.' },
|
|
263
269
|
{ type: 'action', id: 'config', label: 'Config locations', detail: 'Show SDK-scanned config files and writable project/global paths.' },
|
|
264
270
|
];
|
|
@@ -284,7 +290,8 @@ export class McpWorkspace {
|
|
|
284
290
|
{ id: 'env', label: 'Environment', value: this.form.env, help: 'Comma-separated KEY=VALUE entries. Prefer env var references or secure secrets for sensitive values.', editable: true },
|
|
285
291
|
{ id: 'allowedPaths', label: 'Allowed paths', value: this.form.allowedPaths, help: 'Comma-separated path prefixes for filesystem-oriented servers.', editable: true },
|
|
286
292
|
{ id: 'allowedHosts', label: 'Allowed hosts', value: this.form.allowedHosts, help: 'Comma-separated hostnames for network-oriented servers.', editable: true },
|
|
287
|
-
{ id: '
|
|
293
|
+
{ id: 'confirm', label: 'Confirm', value: this.form.confirm, help: 'Type yes to save this MCP server through the TUI command dispatcher.', editable: true },
|
|
294
|
+
{ id: 'save', label: 'Save server', value: '', help: 'Dispatch the confirmed MCP server add/update through the workspace.', editable: false },
|
|
288
295
|
{ id: 'cancel', label: 'Cancel', value: '', help: 'Return to the MCP server browser without changing config.', editable: false },
|
|
289
296
|
];
|
|
290
297
|
}
|
|
@@ -323,11 +330,15 @@ export class McpWorkspace {
|
|
|
323
330
|
}
|
|
324
331
|
}
|
|
325
332
|
|
|
326
|
-
|
|
327
|
-
if (!this.context) return;
|
|
333
|
+
requestReload(): void {
|
|
328
334
|
this.lastError = null;
|
|
329
|
-
this.
|
|
330
|
-
this.
|
|
335
|
+
this.mode = 'reload-confirm';
|
|
336
|
+
this.status = 'Confirm MCP runtime reload. Press Enter or y to reload; Esc or n cancels.';
|
|
337
|
+
this.context?.renderRequest();
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
async reloadRuntime(): Promise<void> {
|
|
341
|
+
await this.dispatchMcpCommand(['reload', '--yes'], 'MCP runtime reload');
|
|
331
342
|
}
|
|
332
343
|
|
|
333
344
|
openAddForm(): void {
|
|
@@ -335,7 +346,7 @@ export class McpWorkspace {
|
|
|
335
346
|
this.formIndex = 0;
|
|
336
347
|
this.editingServerName = null;
|
|
337
348
|
this.form = serverConfigToForm();
|
|
338
|
-
this.status = 'Draft an MCP server.
|
|
349
|
+
this.status = 'Draft an MCP server. Type yes on the Confirm field, then press Enter on Save server.';
|
|
339
350
|
}
|
|
340
351
|
|
|
341
352
|
openEditForm(serverName: string): void {
|
|
@@ -345,7 +356,7 @@ export class McpWorkspace {
|
|
|
345
356
|
this.editingServerName = serverName;
|
|
346
357
|
this.form = { ...serverConfigToForm(entry?.server), scope: entry?.source.scope === 'global' ? 'global' : 'project' };
|
|
347
358
|
this.status = entry
|
|
348
|
-
? `
|
|
359
|
+
? `Editing ${serverName}. Type yes on the Confirm field, then press Enter on Save server to update it.`
|
|
349
360
|
: `Viewing ${serverName}. Runtime status exists, but no launch config was found.`;
|
|
350
361
|
}
|
|
351
362
|
|
|
@@ -354,23 +365,38 @@ export class McpWorkspace {
|
|
|
354
365
|
this.editingServerName = serverName;
|
|
355
366
|
const entry = this.snapshot.effectiveConfig.servers.find((configEntry) => configEntry.server.name === serverName);
|
|
356
367
|
const scope = entry?.source.scope === 'global' ? 'global' : 'project';
|
|
357
|
-
this.status = `
|
|
368
|
+
this.status = `Confirm removal of ${serverName} from ${scope} MCP config. Press Enter or y to remove; Esc or n cancels.`;
|
|
358
369
|
}
|
|
359
370
|
|
|
360
371
|
async saveForm(): Promise<void> {
|
|
361
372
|
if (!this.context) return;
|
|
362
373
|
try {
|
|
374
|
+
if (!isAffirmative(this.form.confirm)) {
|
|
375
|
+
this.status = 'MCP server add/update not confirmed. Type yes on the Confirm field, then press Enter on Save server.';
|
|
376
|
+
this.context.renderRequest();
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
363
379
|
const server = formToServerConfig(this.form);
|
|
380
|
+
const args = [
|
|
381
|
+
'add',
|
|
382
|
+
server.name,
|
|
383
|
+
server.command,
|
|
384
|
+
...(server.args ?? []),
|
|
385
|
+
'--scope',
|
|
386
|
+
this.form.scope,
|
|
387
|
+
];
|
|
388
|
+
if (server.role) args.push('--role', server.role);
|
|
389
|
+
if (server.trustMode) args.push('--trust', server.trustMode);
|
|
390
|
+
for (const [key, value] of Object.entries(server.env ?? {})) args.push('--env', `${key}=${value}`);
|
|
391
|
+
for (const path of server.allowedPaths ?? []) args.push('--path', path);
|
|
392
|
+
for (const host of server.allowedHosts ?? []) args.push('--host', host);
|
|
393
|
+
args.push('--yes');
|
|
364
394
|
this.mode = 'browse';
|
|
365
395
|
this.editingServerName = null;
|
|
366
|
-
|
|
367
|
-
const role = server.role ? ` --role ${server.role}` : '';
|
|
368
|
-
const trust = server.trustMode ? ` --trust ${server.trustMode}` : '';
|
|
369
|
-
this.status = `MCP config write blocked here. Run: /mcp add ${server.name} ${server.command}${args} --scope ${this.form.scope}${role}${trust} --yes`;
|
|
370
|
-
this.context.renderRequest();
|
|
396
|
+
await this.dispatchMcpCommand(args, `MCP server ${server.name} add/update`);
|
|
371
397
|
} catch (error) {
|
|
372
398
|
this.lastError = summarizeError(error);
|
|
373
|
-
this.status = `
|
|
399
|
+
this.status = `MCP server save failed before dispatch: ${this.lastError}`;
|
|
374
400
|
this.context.renderRequest();
|
|
375
401
|
}
|
|
376
402
|
}
|
|
@@ -382,8 +408,7 @@ export class McpWorkspace {
|
|
|
382
408
|
const scope = server?.source.scope === 'global' ? 'global' : 'project';
|
|
383
409
|
this.mode = 'browse';
|
|
384
410
|
this.editingServerName = null;
|
|
385
|
-
this.
|
|
386
|
-
this.context.renderRequest();
|
|
411
|
+
await this.dispatchMcpCommand(['remove', name, '--scope', scope, '--yes'], `MCP server ${name} removal`);
|
|
387
412
|
}
|
|
388
413
|
|
|
389
414
|
cancelForm(): void {
|
|
@@ -392,6 +417,35 @@ export class McpWorkspace {
|
|
|
392
417
|
this.status = 'Returned to MCP server browser.';
|
|
393
418
|
}
|
|
394
419
|
|
|
420
|
+
private async dispatchMcpCommand(args: readonly string[], summary: string): Promise<void> {
|
|
421
|
+
const context = this.context;
|
|
422
|
+
if (!context?.executeCommand) {
|
|
423
|
+
this.status = `${summary} blocked: command dispatch is unavailable in this workspace.`;
|
|
424
|
+
this.lastError = 'Command dispatch is unavailable.';
|
|
425
|
+
context?.renderRequest();
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
this.status = `${summary} dispatched from MCP workspace.`;
|
|
429
|
+
this.lastError = null;
|
|
430
|
+
context.renderRequest();
|
|
431
|
+
try {
|
|
432
|
+
const handled = await context.executeCommand('mcp', [...args]);
|
|
433
|
+
if (!handled) {
|
|
434
|
+
this.status = `${summary} failed: the command router did not handle /mcp.`;
|
|
435
|
+
this.lastError = 'Command router did not handle /mcp.';
|
|
436
|
+
context.renderRequest();
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
this.refreshSnapshot();
|
|
440
|
+
this.status = `${summary} completed through MCP workspace.`;
|
|
441
|
+
} catch (error) {
|
|
442
|
+
this.lastError = summarizeError(error);
|
|
443
|
+
this.status = `${summary} failed: ${this.lastError}`;
|
|
444
|
+
} finally {
|
|
445
|
+
context.renderRequest();
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
395
449
|
moveSelection(delta: number): void {
|
|
396
450
|
const total = this.mode === 'form' ? this.formFields.length : this.rows.length;
|
|
397
451
|
if (total <= 0) return;
|
|
@@ -413,6 +467,11 @@ export class McpWorkspace {
|
|
|
413
467
|
await this.confirmDelete();
|
|
414
468
|
return;
|
|
415
469
|
}
|
|
470
|
+
if (this.mode === 'reload-confirm') {
|
|
471
|
+
this.mode = 'browse';
|
|
472
|
+
await this.reloadRuntime();
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
416
475
|
const row = this.selectedRow;
|
|
417
476
|
if (!row) return;
|
|
418
477
|
if (row.type === 'server') {
|
|
@@ -420,7 +479,7 @@ export class McpWorkspace {
|
|
|
420
479
|
return;
|
|
421
480
|
}
|
|
422
481
|
if (row.id === 'add') this.openAddForm();
|
|
423
|
-
else if (row.id === 'reload')
|
|
482
|
+
else if (row.id === 'reload') this.requestReload();
|
|
424
483
|
else if (row.id === 'refresh-tools') await this.refreshTools();
|
|
425
484
|
else if (row.id === 'config') {
|
|
426
485
|
this.status = [
|
|
@@ -478,12 +537,17 @@ export function handleMcpWorkspaceToken(
|
|
|
478
537
|
} else if (workspace.mode === 'delete-confirm') {
|
|
479
538
|
if (token.value.toLowerCase() === 'y') void workspace.confirmDelete();
|
|
480
539
|
else if (token.value.toLowerCase() === 'n') workspace.cancelForm();
|
|
540
|
+
} else if (workspace.mode === 'reload-confirm') {
|
|
541
|
+
if (token.value.toLowerCase() === 'y') {
|
|
542
|
+
workspace.mode = 'browse';
|
|
543
|
+
void workspace.reloadRuntime();
|
|
544
|
+
} else if (token.value.toLowerCase() === 'n') workspace.cancelForm();
|
|
481
545
|
} else {
|
|
482
546
|
const value = token.value.toLowerCase();
|
|
483
547
|
if (value === 'a') workspace.openAddForm();
|
|
484
548
|
else if (value === 'e' && workspace.selectedServer) workspace.openEditForm(workspace.selectedServer.name);
|
|
485
549
|
else if (value === 'd' && workspace.selectedServer) workspace.requestDelete(workspace.selectedServer.name);
|
|
486
|
-
else if (value === 'r')
|
|
550
|
+
else if (value === 'r') workspace.requestReload();
|
|
487
551
|
else if (value === 't') void workspace.refreshTools();
|
|
488
552
|
}
|
|
489
553
|
requestRender();
|
|
@@ -492,7 +556,7 @@ export function handleMcpWorkspaceToken(
|
|
|
492
556
|
|
|
493
557
|
if (token.type !== 'key') return true;
|
|
494
558
|
if (token.logicalName === 'escape') {
|
|
495
|
-
if (workspace.mode === 'form' || workspace.mode === 'delete-confirm') {
|
|
559
|
+
if (workspace.mode === 'form' || workspace.mode === 'delete-confirm' || workspace.mode === 'reload-confirm') {
|
|
496
560
|
workspace.cancelForm();
|
|
497
561
|
requestRender();
|
|
498
562
|
} else {
|
|
@@ -520,7 +584,7 @@ export function handleMcpWorkspaceToken(
|
|
|
520
584
|
} else if (token.logicalName === 'd' && workspace.mode === 'browse' && workspace.selectedServer) {
|
|
521
585
|
workspace.requestDelete(workspace.selectedServer.name);
|
|
522
586
|
} else if (token.logicalName === 'r' && workspace.mode === 'browse') {
|
|
523
|
-
|
|
587
|
+
workspace.requestReload();
|
|
524
588
|
} else if (token.logicalName === 't' && workspace.mode === 'browse') {
|
|
525
589
|
void workspace.refreshTools();
|
|
526
590
|
}
|
|
@@ -62,7 +62,9 @@ export function handleOnboardingWizardToken(state: OnboardingRouteState, token:
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
if (editing) {
|
|
65
|
-
if (isEnterKey(token)) {
|
|
65
|
+
if (token.ctrl && (token.logicalName === 'j' || isEnterKey(token))) {
|
|
66
|
+
state.onboardingWizard.editNewline();
|
|
67
|
+
} else if (isEnterKey(token)) {
|
|
66
68
|
state.onboardingWizard.commitEdit();
|
|
67
69
|
} else if ((token.ctrl && token.logicalName === 'u') || token.logicalName === 'delete') {
|
|
68
70
|
state.onboardingWizard.clearEditingValue();
|
|
@@ -21,6 +21,46 @@ export function buildOnboardingApplyRequest(controller: OnboardingWizardControll
|
|
|
21
21
|
medium,
|
|
22
22
|
});
|
|
23
23
|
};
|
|
24
|
+
const readText = (fieldId: string): string => controller.getStringFieldValue(fieldId, '').trim();
|
|
25
|
+
const maybeCreateLocalPersona = (): void => {
|
|
26
|
+
const name = readText('agent-local-state.persona-name');
|
|
27
|
+
const description = readText('agent-local-state.persona-description');
|
|
28
|
+
const body = readText('agent-local-state.persona-body');
|
|
29
|
+
if (!name && !description && !body) return;
|
|
30
|
+
operations.push({
|
|
31
|
+
kind: 'create-local-persona',
|
|
32
|
+
name,
|
|
33
|
+
description,
|
|
34
|
+
body,
|
|
35
|
+
activate: true,
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
const maybeCreateLocalSkill = (): void => {
|
|
39
|
+
const name = readText('agent-local-state.skill-name');
|
|
40
|
+
const description = readText('agent-local-state.skill-description');
|
|
41
|
+
const procedure = readText('agent-local-state.skill-procedure');
|
|
42
|
+
if (!name && !description && !procedure) return;
|
|
43
|
+
operations.push({
|
|
44
|
+
kind: 'create-local-skill',
|
|
45
|
+
name,
|
|
46
|
+
description,
|
|
47
|
+
procedure,
|
|
48
|
+
enabled: true,
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
const maybeCreateLocalRoutine = (): void => {
|
|
52
|
+
const name = readText('agent-local-state.routine-name');
|
|
53
|
+
const description = readText('agent-local-state.routine-description');
|
|
54
|
+
const steps = readText('agent-local-state.routine-steps');
|
|
55
|
+
if (!name && !description && !steps) return;
|
|
56
|
+
operations.push({
|
|
57
|
+
kind: 'create-local-routine',
|
|
58
|
+
name,
|
|
59
|
+
description,
|
|
60
|
+
steps,
|
|
61
|
+
enabled: true,
|
|
62
|
+
});
|
|
63
|
+
};
|
|
24
64
|
|
|
25
65
|
// GoodVibes Agent onboarding owns only Agent-local setup and provider
|
|
26
66
|
// routing. Server lifecycle, non-Agent entrypoints, and non-Agent knowledge
|
|
@@ -46,7 +86,16 @@ export function buildOnboardingApplyRequest(controller: OnboardingWizardControll
|
|
|
46
86
|
name: profileName,
|
|
47
87
|
...(selectedTemplate.length > 0 && selectedTemplate !== 'none' ? { templateId: selectedTemplate } : {}),
|
|
48
88
|
});
|
|
89
|
+
if (controller.getBooleanFieldValue('agent-setup.profile-default', true)) {
|
|
90
|
+
operations.push({
|
|
91
|
+
kind: 'select-agent-profile',
|
|
92
|
+
name: profileName,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
49
95
|
}
|
|
96
|
+
maybeCreateLocalPersona();
|
|
97
|
+
maybeCreateLocalSkill();
|
|
98
|
+
maybeCreateLocalRoutine();
|
|
50
99
|
|
|
51
100
|
return {
|
|
52
101
|
mode: controller.mode,
|
|
@@ -49,7 +49,7 @@ export function buildDefaultDerivedState(): OnboardingStepDerivationState {
|
|
|
49
49
|
required: false,
|
|
50
50
|
accepted: false,
|
|
51
51
|
reason: 'not-needed',
|
|
52
|
-
detail: 'No connected-
|
|
52
|
+
detail: 'No connected-host auth signal needs confirmation.',
|
|
53
53
|
},
|
|
54
54
|
},
|
|
55
55
|
};
|
|
@@ -1,4 +1,31 @@
|
|
|
1
1
|
import type { OnboardingWizardStepDefinition } from './onboarding-wizard-types.ts';
|
|
2
|
+
import type { AgentBehaviorDiscoverySnapshot } from '../../agent/behavior-discovery-summary.ts';
|
|
3
|
+
|
|
4
|
+
function discoveryCount(discovery: AgentBehaviorDiscoverySnapshot | undefined): number {
|
|
5
|
+
if (!discovery) return 0;
|
|
6
|
+
return discovery.personas.count + discovery.skills.count + discovery.routines.count;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function discoverySummary(discovery: AgentBehaviorDiscoverySnapshot | undefined): string {
|
|
10
|
+
if (!discovery || discoveryCount(discovery) === 0) return 'No importable local behavior files found yet';
|
|
11
|
+
return [
|
|
12
|
+
`${discovery.personas.count} persona file(s)`,
|
|
13
|
+
`${discovery.skills.count} skill file(s)`,
|
|
14
|
+
`${discovery.routines.count} routine file(s)`,
|
|
15
|
+
].join('; ');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function discoverySample(discovery: AgentBehaviorDiscoverySnapshot | undefined): string {
|
|
19
|
+
if (!discovery) return '';
|
|
20
|
+
const names = [
|
|
21
|
+
...discovery.personas.names,
|
|
22
|
+
...discovery.skills.names,
|
|
23
|
+
...discovery.routines.names,
|
|
24
|
+
].slice(0, 4);
|
|
25
|
+
if (names.length === 0) return 'Use /personas discover, /agent-skills discover, and /routines discover after setup to rescan.';
|
|
26
|
+
const remaining = discoveryCount(discovery) > names.length ? `, +${discoveryCount(discovery) - names.length} more` : '';
|
|
27
|
+
return `Import candidates: ${names.join(', ')}${remaining}.`;
|
|
28
|
+
}
|
|
2
29
|
|
|
3
30
|
export function buildCommunicationStep(): OnboardingWizardStepDefinition {
|
|
4
31
|
return {
|
|
@@ -8,7 +35,7 @@ export function buildCommunicationStep(): OnboardingWizardStepDefinition {
|
|
|
8
35
|
description: 'Prepare companion pairing, messaging-channel readiness, notification delivery, and safe outbound communication for day-one Agent use.',
|
|
9
36
|
summaryTitle: 'Communication posture',
|
|
10
37
|
summaryLines: [
|
|
11
|
-
'Companion chat: paired through connected GoodVibes
|
|
38
|
+
'Companion chat: paired through the connected GoodVibes host',
|
|
12
39
|
'Channel accounts: inspect readiness before using them',
|
|
13
40
|
'Outbound messages: explicit user action only',
|
|
14
41
|
],
|
|
@@ -17,7 +44,7 @@ export function buildCommunicationStep(): OnboardingWizardStepDefinition {
|
|
|
17
44
|
kind: 'status',
|
|
18
45
|
id: 'agent-communication.companion',
|
|
19
46
|
label: 'Companion pairing',
|
|
20
|
-
hint: 'Use /pair from the Agent workspace to pair companion clients through connected GoodVibes
|
|
47
|
+
hint: 'Use /pair from the Agent workspace to pair companion clients through the connected GoodVibes host.',
|
|
21
48
|
defaultValue: 'Pair when ready',
|
|
22
49
|
},
|
|
23
50
|
{
|
|
@@ -128,15 +155,19 @@ export function buildAgentKnowledgeStep(): OnboardingWizardStepDefinition {
|
|
|
128
155
|
};
|
|
129
156
|
}
|
|
130
157
|
|
|
131
|
-
export function buildLocalStateStep(): OnboardingWizardStepDefinition {
|
|
158
|
+
export function buildLocalStateStep(discovery?: AgentBehaviorDiscoverySnapshot): OnboardingWizardStepDefinition {
|
|
159
|
+
const discoveredCount = discoveryCount(discovery);
|
|
132
160
|
return {
|
|
133
161
|
id: 'agent-local-state',
|
|
134
162
|
title: 'Local memory and behavior',
|
|
135
|
-
shortLabel: '
|
|
136
|
-
description:
|
|
163
|
+
shortLabel: 'Behavior',
|
|
164
|
+
description: discoveredCount > 0
|
|
165
|
+
? 'Review importable Agent-local behavior files, then create an isolated profile from them or import individual records.'
|
|
166
|
+
: 'Review the Agent-local behavior model. Memory, personas, skills, routines, and Agent profiles stay local until a stable shared registry exists.',
|
|
137
167
|
summaryTitle: 'Local Agent state',
|
|
138
168
|
summaryLines: [
|
|
139
169
|
'Memory/personas/skills/routines: local Agent registries',
|
|
170
|
+
`Discovered behavior files: ${discoverySummary(discovery)}`,
|
|
140
171
|
'Secrets: rejected or stored by secret reference',
|
|
141
172
|
'Profiles: isolated Agent homes',
|
|
142
173
|
],
|
|
@@ -152,22 +183,106 @@ export function buildLocalStateStep(): OnboardingWizardStepDefinition {
|
|
|
152
183
|
kind: 'status',
|
|
153
184
|
id: 'agent-local-state.personas',
|
|
154
185
|
label: 'Personas',
|
|
155
|
-
hint:
|
|
156
|
-
|
|
186
|
+
hint: discovery?.personas.count && discovery.personas.count > 0
|
|
187
|
+
? `${discovery.personas.count} persona file(s) are available. Use the Profiles workspace to create a profile from discovered behavior, or preview individual files with /personas discover.`
|
|
188
|
+
: 'Use /personas to create and activate serial operating modes for the main conversation.',
|
|
189
|
+
defaultValue: discovery?.personas.count && discovery.personas.count > 0 ? `${discovery.personas.count} discovered` : 'Local registry',
|
|
157
190
|
},
|
|
158
191
|
{
|
|
159
192
|
kind: 'status',
|
|
160
193
|
id: 'agent-local-state.skills',
|
|
161
194
|
label: 'Skills',
|
|
162
|
-
hint:
|
|
163
|
-
|
|
195
|
+
hint: discovery?.skills.count && discovery.skills.count > 0
|
|
196
|
+
? `${discovery.skills.count} skill file(s) are available. Use the Profiles workspace to create a profile from discovered behavior, or preview individual files with /agent-skills discover.`
|
|
197
|
+
: 'Use /agent-skills and /skills local to manage reusable Agent procedures.',
|
|
198
|
+
defaultValue: discovery?.skills.count && discovery.skills.count > 0 ? `${discovery.skills.count} discovered` : 'Local registry',
|
|
164
199
|
},
|
|
165
200
|
{
|
|
166
201
|
kind: 'status',
|
|
167
202
|
id: 'agent-local-state.routines',
|
|
168
203
|
label: 'Routines',
|
|
169
|
-
hint:
|
|
170
|
-
|
|
204
|
+
hint: discovery?.routines.count && discovery.routines.count > 0
|
|
205
|
+
? `${discovery.routines.count} routine file(s) are available. Use the Profiles workspace to create a profile from discovered behavior, or preview individual files with /routines discover. ${discoverySample(discovery)}`
|
|
206
|
+
: 'Use /routines for reusable local procedures. Starting a routine prints steps in the main conversation and does not launch local workers.',
|
|
207
|
+
defaultValue: discovery?.routines.count && discovery.routines.count > 0 ? `${discovery.routines.count} discovered` : 'Local registry',
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
kind: 'text',
|
|
211
|
+
id: 'agent-local-state.persona-name',
|
|
212
|
+
label: 'Initial persona name',
|
|
213
|
+
hint: 'Optional: create and activate a serial Agent persona during setup. Leave persona fields blank to skip.',
|
|
214
|
+
placeholder: 'Household Operator',
|
|
215
|
+
defaultValue: '',
|
|
216
|
+
spacerBeforeRows: 1,
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
kind: 'text',
|
|
220
|
+
id: 'agent-local-state.persona-description',
|
|
221
|
+
label: 'Initial persona description',
|
|
222
|
+
hint: 'Describe when this persona should shape the main conversation.',
|
|
223
|
+
placeholder: 'Handles day-to-day planning, reminders, device checks, and household coordination.',
|
|
224
|
+
defaultValue: '',
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
kind: 'text',
|
|
228
|
+
id: 'agent-local-state.persona-body',
|
|
229
|
+
label: 'Initial persona instructions',
|
|
230
|
+
hint: 'Tell Agent how to behave when this persona is active.',
|
|
231
|
+
placeholder: 'Be concise, proactive, and use safe local actions before asking for follow-up details.',
|
|
232
|
+
defaultValue: '',
|
|
233
|
+
multiline: true,
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
kind: 'text',
|
|
237
|
+
id: 'agent-local-state.skill-name',
|
|
238
|
+
label: 'Initial skill name',
|
|
239
|
+
hint: 'Optional: create and enable a reusable local procedure during setup.',
|
|
240
|
+
placeholder: 'Daily Briefing',
|
|
241
|
+
defaultValue: '',
|
|
242
|
+
spacerBeforeRows: 1,
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
kind: 'text',
|
|
246
|
+
id: 'agent-local-state.skill-description',
|
|
247
|
+
label: 'Initial skill description',
|
|
248
|
+
hint: 'Describe when Agent should use this skill.',
|
|
249
|
+
placeholder: 'Prepares a concise morning briefing from calendar, tasks, and current priorities.',
|
|
250
|
+
defaultValue: '',
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
kind: 'text',
|
|
254
|
+
id: 'agent-local-state.skill-procedure',
|
|
255
|
+
label: 'Initial skill procedure',
|
|
256
|
+
hint: 'Write the procedure Agent should reuse in the main conversation.',
|
|
257
|
+
placeholder: 'Check tasks, summarize important events, identify blockers, and ask only for missing critical inputs.',
|
|
258
|
+
defaultValue: '',
|
|
259
|
+
multiline: true,
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
kind: 'text',
|
|
263
|
+
id: 'agent-local-state.routine-name',
|
|
264
|
+
label: 'Initial routine name',
|
|
265
|
+
hint: 'Optional: create and enable a local routine. Routines print steps in the main conversation and do not launch hidden jobs.',
|
|
266
|
+
placeholder: 'Evening Reset',
|
|
267
|
+
defaultValue: '',
|
|
268
|
+
spacerBeforeRows: 1,
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
kind: 'text',
|
|
272
|
+
id: 'agent-local-state.routine-description',
|
|
273
|
+
label: 'Initial routine description',
|
|
274
|
+
hint: 'Describe when the routine should be suggested or started.',
|
|
275
|
+
placeholder: 'Reviews open tasks, tomorrow priorities, and pending approvals before the day ends.',
|
|
276
|
+
defaultValue: '',
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
kind: 'text',
|
|
280
|
+
id: 'agent-local-state.routine-steps',
|
|
281
|
+
label: 'Initial routine steps',
|
|
282
|
+
hint: 'Write the local routine steps. This stays in Agent-local state only.',
|
|
283
|
+
placeholder: 'Review open tasks; summarize unresolved approvals; list tomorrow priorities; ask what to defer.',
|
|
284
|
+
defaultValue: '',
|
|
285
|
+
multiline: true,
|
|
171
286
|
},
|
|
172
287
|
],
|
|
173
288
|
};
|
|
@@ -31,7 +31,7 @@ export function buildOnboardingWizardSteps(controller: OnboardingWizardControlle
|
|
|
31
31
|
buildCommunicationStep(),
|
|
32
32
|
buildToolsStep(),
|
|
33
33
|
buildAgentKnowledgeStep(),
|
|
34
|
-
buildLocalStateStep(),
|
|
34
|
+
buildLocalStateStep(controller.runtimeSnapshot?.localBehaviorDiscovery),
|
|
35
35
|
buildAutomationStep(),
|
|
36
36
|
buildVoiceMediaStep(),
|
|
37
37
|
buildDelegationPolicyStep(),
|
|
@@ -114,10 +114,10 @@ function buildReviewReadinessFields(controller: OnboardingWizardController): rea
|
|
|
114
114
|
{
|
|
115
115
|
kind: 'status',
|
|
116
116
|
id: 'review.readiness.connection',
|
|
117
|
-
label: 'Connected
|
|
117
|
+
label: 'Connected host snapshot',
|
|
118
118
|
hint: collectionIssues > 0
|
|
119
119
|
? `${collectionIssues} setup snapshot issue(s) need attention before this Agent is day-one ready.`
|
|
120
|
-
: 'The setup snapshot loaded cleanly from connected GoodVibes
|
|
120
|
+
: 'The setup snapshot loaded cleanly from the connected GoodVibes host.',
|
|
121
121
|
defaultValue: collectionIssues > 0 ? 'Needs attention' : 'Ready',
|
|
122
122
|
spacerBeforeRows: 1,
|
|
123
123
|
},
|
|
@@ -226,10 +226,10 @@ export function buildAgentSetupStep(controller: OnboardingWizardController): Onb
|
|
|
226
226
|
{
|
|
227
227
|
kind: 'status',
|
|
228
228
|
id: 'agent-setup.connection',
|
|
229
|
-
label: 'Connected GoodVibes
|
|
229
|
+
label: 'Connected GoodVibes host',
|
|
230
230
|
hint: collectionIssues > 0
|
|
231
231
|
? `${collectionIssues} setup snapshot issue(s) were reported. Status and doctor commands show connection details.`
|
|
232
|
-
: 'Agent uses connected GoodVibes
|
|
232
|
+
: 'Agent uses the connected GoodVibes host for companion chat, work plans, approvals, automation, and Agent Knowledge.',
|
|
233
233
|
defaultValue: collectionIssues > 0 ? `${collectionIssues} issue(s)` : 'Connected',
|
|
234
234
|
},
|
|
235
235
|
{
|
|
@@ -256,6 +256,13 @@ export function buildAgentSetupStep(controller: OnboardingWizardController): Onb
|
|
|
256
256
|
options: buildStarterTemplateOptions(),
|
|
257
257
|
defaultValue: 'none',
|
|
258
258
|
},
|
|
259
|
+
{
|
|
260
|
+
kind: 'checklist',
|
|
261
|
+
id: 'agent-setup.profile-default',
|
|
262
|
+
label: 'Use created profile by default',
|
|
263
|
+
hint: 'When a starter profile name is provided, make that isolated Agent profile the default for future plain goodvibes-agent launches.',
|
|
264
|
+
defaultValue: true,
|
|
265
|
+
},
|
|
259
266
|
{
|
|
260
267
|
kind: 'status',
|
|
261
268
|
id: 'agent-setup.profile-guide',
|
|
@@ -505,9 +512,9 @@ export function buildReviewStep(controller: OnboardingWizardController): Onboard
|
|
|
505
512
|
{
|
|
506
513
|
kind: 'status',
|
|
507
514
|
id: 'review.global-marker',
|
|
508
|
-
label: 'Agent setup
|
|
509
|
-
hint: '
|
|
510
|
-
defaultValue: '
|
|
515
|
+
label: 'Agent setup completion',
|
|
516
|
+
hint: 'Successful apply marks Agent setup complete for this user account, so a bare launch opens the operator workspace next time.',
|
|
517
|
+
defaultValue: 'Marked after apply',
|
|
511
518
|
},
|
|
512
519
|
{
|
|
513
520
|
kind: 'action',
|
|
@@ -87,6 +87,7 @@ export interface OnboardingWizardTextFieldDefinition extends OnboardingWizardFie
|
|
|
87
87
|
readonly defaultValue: string;
|
|
88
88
|
readonly placeholder: string;
|
|
89
89
|
readonly required?: boolean;
|
|
90
|
+
readonly multiline?: boolean;
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
export interface OnboardingWizardMaskedFieldDefinition extends OnboardingWizardFieldBase {
|
|
@@ -295,6 +295,12 @@ export class OnboardingWizardController {
|
|
|
295
295
|
return this.editingFieldId !== null;
|
|
296
296
|
}
|
|
297
297
|
|
|
298
|
+
public isEditingMultilineTextField(): boolean {
|
|
299
|
+
if (this.editingFieldId === null) return false;
|
|
300
|
+
const field = this.getFieldById(this.editingFieldId);
|
|
301
|
+
return field?.kind === 'text' && field.multiline === true;
|
|
302
|
+
}
|
|
303
|
+
|
|
298
304
|
public getFieldWindow(visibleFields: number): OnboardingWizardFieldWindow {
|
|
299
305
|
const fields = this.currentStep.fields;
|
|
300
306
|
const total = fields.length;
|
|
@@ -408,7 +414,7 @@ export class OnboardingWizardController {
|
|
|
408
414
|
const field = this.getSelectedField();
|
|
409
415
|
if (!field || (field.kind !== 'text' && field.kind !== 'masked')) return false;
|
|
410
416
|
this.beginEdit(field.id);
|
|
411
|
-
this.editBuffer = initialText;
|
|
417
|
+
this.editBuffer = this.prepareTextInput(initialText);
|
|
412
418
|
return true;
|
|
413
419
|
}
|
|
414
420
|
|
|
@@ -432,7 +438,13 @@ export class OnboardingWizardController {
|
|
|
432
438
|
|
|
433
439
|
public editChar(char: string): void {
|
|
434
440
|
if (this.editingFieldId === null || char.length === 0) return;
|
|
435
|
-
this.editBuffer += char;
|
|
441
|
+
this.editBuffer += this.prepareTextInput(char);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
public editNewline(): boolean {
|
|
445
|
+
if (!this.isEditingMultilineTextField()) return false;
|
|
446
|
+
this.editBuffer += '\n';
|
|
447
|
+
return true;
|
|
436
448
|
}
|
|
437
449
|
|
|
438
450
|
public editBackspace(): void {
|
|
@@ -455,6 +467,11 @@ export class OnboardingWizardController {
|
|
|
455
467
|
return true;
|
|
456
468
|
}
|
|
457
469
|
|
|
470
|
+
private prepareTextInput(text: string): string {
|
|
471
|
+
if (this.isEditingMultilineTextField()) return text.replace(/\r\n?/g, '\n');
|
|
472
|
+
return text.replace(/[\r\n]+/g, ' ');
|
|
473
|
+
}
|
|
474
|
+
|
|
458
475
|
public setFieldValue(fieldId: string, value: boolean | string): void {
|
|
459
476
|
const field = this.getFieldById(fieldId);
|
|
460
477
|
if (!field) return;
|