@pellux/goodvibes-agent 0.1.86 → 0.1.89

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 CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  All notable changes to GoodVibes Agent will be recorded here.
4
4
 
5
+ ## 0.1.89 - 2026-06-01
6
+
7
+ - 6be201c Fix Agent workspace command targets
8
+
9
+ ## 0.1.88 - 2026-06-01
10
+
11
+ - e97d2a2 Fix release test daemon port allocation
12
+
13
+ ## 0.1.87 - 2026-06-01
14
+
15
+ - cd0d9fc Improve Agent TUI startup diagnostics
16
+
5
17
  ## 0.1.86 - 2026-06-01
6
18
 
7
19
  - aac1849 Retry npm publish verification
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pellux/goodvibes-agent",
3
- "version": "0.1.86",
3
+ "version": "0.1.89",
4
4
  "private": false,
5
5
  "description": "GoodVibes personal operator assistant TUI with a proactive Agent product brain, isolated Agent Knowledge, local profiles, routines, skills, personas, and explicit build delegation.",
6
6
  "type": "module",
@@ -9,6 +9,70 @@ export type InteractiveTerminalCheckInput = {
9
9
  readonly stdoutIsTTY: boolean | undefined;
10
10
  };
11
11
 
12
+ type NodeLikeError = Error & {
13
+ readonly code?: string;
14
+ readonly path?: string;
15
+ readonly syscall?: string;
16
+ };
17
+
18
+ export type FatalStartupFormatOptions = {
19
+ readonly binary: string;
20
+ readonly debug?: boolean;
21
+ };
22
+
23
+ function isNodeLikeError(error: unknown): error is NodeLikeError {
24
+ return error instanceof Error;
25
+ }
26
+
27
+ function fatalStartupMessage(error: unknown): string {
28
+ if (error instanceof Error) return error.message;
29
+ if (typeof error === 'string') return error;
30
+ try {
31
+ return JSON.stringify(error);
32
+ } catch {
33
+ return String(error);
34
+ }
35
+ }
36
+
37
+ function fatalStartupStack(error: unknown): string {
38
+ if (error instanceof Error) return error.stack ?? error.message;
39
+ return fatalStartupMessage(error);
40
+ }
41
+
42
+ export function formatFatalStartupErrorForLog(error: unknown): string {
43
+ return fatalStartupStack(error);
44
+ }
45
+
46
+ export function formatFatalStartupErrorForUser(error: unknown, options: FatalStartupFormatOptions): string {
47
+ if (options.debug === true) return fatalStartupStack(error);
48
+
49
+ const message = fatalStartupMessage(error);
50
+ if (isNodeLikeError(error) && (error.code === 'EACCES' || error.code === 'EPERM')) {
51
+ return [
52
+ `${options.binary} could not prepare its local workspace or log directory.`,
53
+ error.path ? ` path: ${error.path}` : '',
54
+ error.syscall ? ` operation: ${error.syscall}` : '',
55
+ ' reason: permission denied',
56
+ ` next: launch from a writable directory, pass '${options.binary} --cd <dir>', or set GOODVIBES_WORKING_DIR to a writable path.`,
57
+ ' note: GOODVIBES_AGENT_HOME can be set to move Agent-local config, sessions, memory, skills, personas, and routines.',
58
+ ].filter((line) => line.length > 0).join('\n');
59
+ }
60
+
61
+ if (isNodeLikeError(error) && error.code === 'ENOENT') {
62
+ return [
63
+ `${options.binary} could not find a required startup path.`,
64
+ error.path ? ` path: ${error.path}` : '',
65
+ ` reason: ${message}`,
66
+ ` next: check '${options.binary} --cd <dir>' and GOODVIBES_WORKING_DIR, then rerun '${options.binary} status'.`,
67
+ ].filter((line) => line.length > 0).join('\n');
68
+ }
69
+
70
+ return [
71
+ message || `${options.binary} failed during startup.`,
72
+ 'Set GOODVIBES_AGENT_DEBUG=1 to print a stack trace.',
73
+ ].join('\n');
74
+ }
75
+
12
76
  export function getInteractiveTerminalLaunchError(input: InteractiveTerminalCheckInput): string | null {
13
77
  const stdinReady = input.stdinIsTTY === true;
14
78
  const stdoutReady = input.stdoutIsTTY === true;
@@ -49,8 +49,8 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
49
49
  detail: 'Agent uses externally managed channels. Pairing, account inspection, and readiness checks are visible here; inbound delivery and public channel exposure stay policy-gated.',
50
50
  actions: [
51
51
  { id: 'pair', label: 'Pair companion', detail: 'Open the QR pairing view for companion app setup.', command: '/pair', kind: 'command', safety: 'safe' },
52
- { id: 'communication', label: 'Communication routes', detail: 'Inspect structured communication routes and recent activity.', command: '/communication', kind: 'command', safety: 'read-only' },
53
- { id: 'setup-review', label: 'Channel setup review', detail: 'Review setup posture without starting inbound endpoints or mutating channel state.', command: '/setup review', kind: 'command', safety: 'read-only' },
52
+ { id: 'notification-routes', label: 'Notification routes', detail: 'Inspect configured webhook notification URLs without sending a test message.', command: '/notify list', kind: 'command', safety: 'read-only' },
53
+ { id: 'setup-review', label: 'Health review', detail: 'Review setup posture without starting inbound endpoints or mutating channel state.', command: '/health review', kind: 'command', safety: 'read-only' },
54
54
  { id: 'channel-safety', label: 'Delivery safety', detail: 'External messages, channel DMs, and public delivery targets require explicit user action and runtime policy. Agent will not silently send or expose channels from this workspace.', kind: 'guidance', safety: 'blocked' },
55
55
  ],
56
56
  },
@@ -90,14 +90,14 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
90
90
  group: 'SETUP',
91
91
  label: 'Profiles',
92
92
  summary: 'Isolated Agent homes, config profiles, and setup bundles.',
93
- detail: 'Profiles isolate Agent state. GoodVibes Agent exposes named homes, config profile pickers, profile-sync bundles, setup transfer bundles, and support bundles while keeping the shared runtime external.',
93
+ detail: 'Profiles isolate Agent state. GoodVibes Agent exposes named homes, starter templates, and config profile pickers while keeping the shared runtime external.',
94
94
  actions: [
95
95
  { id: 'profiles-open', label: 'Open config profiles', detail: 'Open the config profile picker for display/provider/behavior profile files.', command: '/profiles', kind: 'command', safety: 'safe' },
96
96
  { id: 'runtime-profile-guide', label: 'Starter authoring guide', detail: 'Open the Agent-local starter authoring flow inside the Agent TUI.', command: '/agent-profile guide', kind: 'command', safety: 'safe' },
97
97
  { id: 'runtime-profile-templates', label: 'Browse starter templates', detail: 'List built-in and local Agent starter templates with persona, skill, routine, and source details.', command: '/agent-profile templates', kind: 'command', safety: 'read-only' },
98
- { id: 'profile-sync-list', label: 'Profile sync list', detail: 'Inspect saved config profiles available for export/import.', command: '/profilesync list', kind: 'command', safety: 'read-only' },
99
- { id: 'profile-sync-export', label: 'Export profile sync', detail: 'Export config profiles to a portable bundle. Requires a real path and explicit --yes.', command: '/profilesync export <path> --yes', kind: 'command', safety: 'safe' },
100
- { id: 'setup-transfer-export', label: 'Export setup transfer', detail: 'Export Agent setup transfer data from the current home. Requires a real path and explicit --yes.', command: '/setup transfer export <path> --yes', kind: 'command', safety: 'safe' },
98
+ { id: 'runtime-profile-list', label: 'List Agent profiles', detail: 'List isolated Agent profile homes under this Agent home.', command: '/agent-profile list', kind: 'command', safety: 'read-only' },
99
+ { id: 'runtime-profile-template-export', label: 'Export starter template', detail: 'Export a starter template JSON file. Requires a real starter id, path, and explicit --yes.', command: '/agent-profile template export <id> <path> --yes', kind: 'command', safety: 'safe' },
100
+ { id: 'runtime-profile-template-import', label: 'Import starter template', detail: 'Import a reviewed starter template JSON file into this Agent home. Requires a real path and explicit --yes.', command: '/agent-profile template import <path> --yes', kind: 'command', safety: 'safe' },
101
101
  { id: 'runtime-profile-create', label: 'Create Agent profile', detail: 'Open an in-workspace form that creates an isolated Agent home from a built-in or local starter.', editorKind: 'profile', kind: 'editor', safety: 'safe' },
102
102
  { id: 'runtime-profile-template-edit', label: 'Customize starter', detail: 'Export a starter JSON file, edit it, import it as a local starter, then create a profile from it.', command: '/agent-profile template export <id> <path> --yes', kind: 'command', safety: 'safe' },
103
103
  { id: 'runtime-profile-switch', label: 'Switch Agent profile', detail: 'Launch goodvibes-agent --agent-profile <name> to use that isolated Agent home. This workspace cannot switch the current process home after startup.', kind: 'guidance', safety: 'safe' },
package/src/main.ts CHANGED
@@ -45,7 +45,7 @@ import { deriveComposerState } from './core/composer-state.ts';
45
45
  import { buildPersistedSessionContext, formatReturnContextForDisplay, getReturnContextMode, maybeAssistReturnContextSummary } from '@/runtime/index.ts';
46
46
  import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
47
47
  import { prepareShellCliRuntime } from './cli/entrypoint.ts';
48
- import { applyInitialTuiCliState, getInteractiveTerminalLaunchError } from './cli/tui-startup.ts';
48
+ import { applyInitialTuiCliState, formatFatalStartupErrorForLog, formatFatalStartupErrorForUser, getInteractiveTerminalLaunchError } from './cli/tui-startup.ts';
49
49
  import { wireSpokenTurnRuntime } from './audio/spoken-turn-wiring.ts';
50
50
  import { attachSpokenTurnModelRouting, createSpokenTurnInputOptions } from './audio/spoken-turn-model-routing.ts';
51
51
  import { allowTerminalWrite, installTuiTerminalOutputGuard } from './runtime/terminal-output-guard.ts';
@@ -768,29 +768,19 @@ async function main() {
768
768
 
769
769
  }
770
770
 
771
- function formatFatalStartupError(error: unknown): string {
772
- if (error instanceof Error) {
773
- return error.stack ?? error.message;
774
- }
775
- if (typeof error === 'string') {
776
- return error;
777
- }
778
- try {
779
- return JSON.stringify(error);
780
- } catch {
781
- return String(error);
782
- }
783
- }
784
-
785
771
  main().catch((err: unknown) => {
786
- const detail = formatFatalStartupError(err);
772
+ const detail = formatFatalStartupErrorForLog(err);
787
773
  try {
788
774
  logger.error('Fatal error', { error: detail });
789
775
  } catch {
790
776
  // Startup diagnostics must never hide the original launch failure.
791
777
  }
778
+ const userDetail = formatFatalStartupErrorForUser(err, {
779
+ binary: 'goodvibes-agent',
780
+ debug: process.env['GOODVIBES_AGENT_DEBUG'] === '1',
781
+ });
792
782
  try {
793
- process.stderr.write(`goodvibes-agent failed to launch:\n${detail}\n`);
783
+ process.stderr.write(`goodvibes-agent failed to launch:\n${userDetail}\n`);
794
784
  } catch {
795
785
  // Ignore secondary stderr failures during process teardown.
796
786
  }
@@ -232,7 +232,7 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
232
232
  });
233
233
  }
234
234
  base.push({ text: 'Only config key names and readiness state are rendered here.', fg: PALETTE.muted });
235
- base.push({ text: 'Pairing: use /pair or /qrcode; inspect routed activity with /communication and /setup review.', fg: PALETTE.info });
235
+ base.push({ text: 'Pairing: use /pair or /qrcode; inspect notification targets with /notify list and health with /health review.', fg: PALETTE.info });
236
236
  } else if (category.id === 'knowledge') {
237
237
  base.push(
238
238
  { text: `Route family: ${snapshot.knowledgeRoute}/{status,ask,search}`, fg: PALETTE.info },
package/src/version.ts CHANGED
@@ -6,7 +6,7 @@ import { join } from 'node:path';
6
6
  // The prebuild script updates the fallback value before compilation.
7
7
  // Uses import.meta.dir (Bun) to locate package.json relative to this file,
8
8
  // which is correct regardless of the process working directory.
9
- let _version = '0.1.86';
9
+ let _version = '0.1.89';
10
10
  let _sdkVersion = '0.33.35';
11
11
  try {
12
12
  const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8')) as {