@pellux/goodvibes-agent 0.1.57 → 0.1.58

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,10 @@
2
2
 
3
3
  All notable changes to GoodVibes Agent will be recorded here.
4
4
 
5
+ ## 0.1.58 - 2026-05-31
6
+
7
+ - e137f90 Fail cleanly for non-TTY TUI launch
8
+
5
9
  ## 0.1.57 - 2026-05-31
6
10
 
7
11
  - 90edab3 Expand Agent onboarding setup surfaces
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pellux/goodvibes-agent",
3
- "version": "0.1.57",
3
+ "version": "0.1.58",
4
4
  "private": false,
5
5
  "description": "Near-fork GoodVibes operator assistant with the GoodVibes TUI shell, renderer, input, fullscreen workspace, and daemon-connected Agent product brain.",
6
6
  "type": "module",
@@ -3,6 +3,29 @@ import type { InputHandler } from '../input/handler.ts';
3
3
  import { readOnboardingCheckMarker } from '../runtime/onboarding/index.ts';
4
4
  import type { GoodVibesCliParseResult } from './types.ts';
5
5
 
6
+ export type InteractiveTerminalCheckInput = {
7
+ readonly binary: string;
8
+ readonly stdinIsTTY: boolean | undefined;
9
+ readonly stdoutIsTTY: boolean | undefined;
10
+ };
11
+
12
+ export function getInteractiveTerminalLaunchError(input: InteractiveTerminalCheckInput): string | null {
13
+ const stdinReady = input.stdinIsTTY === true;
14
+ const stdoutReady = input.stdoutIsTTY === true;
15
+ if (stdinReady && stdoutReady) return null;
16
+
17
+ const missing = [
18
+ stdinReady ? null : 'stdin',
19
+ stdoutReady ? null : 'stdout',
20
+ ].filter((entry): entry is string => entry !== null);
21
+ const missingLabel = missing.length === 1 ? `${missing[0]} is` : `${missing.join(' and ')} are`;
22
+
23
+ return [
24
+ `${input.binary} requires an interactive terminal for the TUI (${missingLabel} not a TTY).`,
25
+ `Run it from a terminal, or use non-interactive commands such as '${input.binary} --help', '${input.binary} status --json', or '${input.binary} run --print "<prompt>"'.`,
26
+ ].join('\n');
27
+ }
28
+
6
29
  export function applyInitialTuiCliState(options: {
7
30
  readonly cli: GoodVibesCliParseResult;
8
31
  readonly input: InputHandler;
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 } from './cli/tui-startup.ts';
48
+ import { applyInitialTuiCliState, 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';
@@ -53,17 +53,8 @@ import { ProjectPlanningCoordinator } from './planning/project-planning-coordina
53
53
  import { buildCommandArgsHint } from './input/command-args-hint.ts';
54
54
  import { GOODVIBES_AGENT_PAIRING_SURFACE } from './config/surface.ts';
55
55
 
56
- const ALT_SCREEN_ENTER = '\x1b[?1049h';
57
- const ALT_SCREEN_EXIT = '\x1b[?1049l';
58
- const MOUSE_ENABLE = '\x1b[?1000h\x1b[?1002h\x1b[?1006h';
59
- const MOUSE_DISABLE = '\x1b[?1006l\x1b[?1002l\x1b[?1000l';
60
- const CURSOR_HIDE = '\x1b[?25l';
61
- const CURSOR_SHOW = '\x1b[?25h';
62
- const CLEAR_SCREEN = '\x1b[2J\x1b[3J\x1b[H';
63
- const KEYBOARD_EXT_ENABLE = '\x1b[>4;2m' + '\x1b[?1u';
64
- const KEYBOARD_EXT_DISABLE = '\x1b[>4;0m' + '\x1b[?1l';
65
- const PASTE_ENABLE = '\x1b[?2004h';
66
- const PASTE_DISABLE = '\x1b[?2004l';
56
+ const ALT_SCREEN_ENTER = '\x1b[?1049h', ALT_SCREEN_EXIT = '\x1b[?1049l', MOUSE_ENABLE = '\x1b[?1000h\x1b[?1002h\x1b[?1006h', MOUSE_DISABLE = '\x1b[?1006l\x1b[?1002l\x1b[?1000l', CURSOR_HIDE = '\x1b[?25l', CURSOR_SHOW = '\x1b[?25h', CLEAR_SCREEN = '\x1b[2J\x1b[3J\x1b[H';
57
+ const KEYBOARD_EXT_ENABLE = '\x1b[>4;2m' + '\x1b[?1u', KEYBOARD_EXT_DISABLE = '\x1b[>4;0m' + '\x1b[?1l', PASTE_ENABLE = '\x1b[?2004h', PASTE_DISABLE = '\x1b[?2004l';
67
58
 
68
59
  async function main() {
69
60
  const stdout = process.stdout;
@@ -73,6 +64,16 @@ async function main() {
73
64
  homeDirectory: process.env['GOODVIBES_AGENT_HOME'] ?? homedir(),
74
65
  }, 'goodvibes-agent');
75
66
 
67
+ const terminalLaunchError = getInteractiveTerminalLaunchError({
68
+ binary: cli.binary,
69
+ stdinIsTTY: stdin.isTTY,
70
+ stdoutIsTTY: stdout.isTTY,
71
+ });
72
+ if (terminalLaunchError !== null) {
73
+ process.stderr.write(`${terminalLaunchError}\n`);
74
+ process.exit(2);
75
+ }
76
+
76
77
  const ctx: BootstrapContext = await bootstrapRuntime(stdout, {
77
78
  configManager,
78
79
  workingDir: bootstrapWorkingDir,
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.57';
9
+ let _version = '0.1.58';
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 {