@pellux/goodvibes-agent 0.1.9 → 0.1.10

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 (38) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +1 -1
  3. package/docs/getting-started.md +1 -1
  4. package/docs/release-and-publishing.md +2 -2
  5. package/package.json +4 -1
  6. package/src/cli/agent-knowledge-command.ts +18 -19
  7. package/src/cli/help.ts +13 -0
  8. package/src/cli/management-commands.ts +3 -3
  9. package/src/cli/management.ts +7 -1
  10. package/src/cli/parser.ts +3 -0
  11. package/src/cli/service-posture.ts +6 -6
  12. package/src/cli/status.ts +9 -9
  13. package/src/cli/surface-command.ts +3 -3
  14. package/src/cli/types.ts +2 -0
  15. package/src/input/commands/experience-runtime.ts +1 -1
  16. package/src/input/commands/hooks-runtime.ts +30 -2
  17. package/src/input/handler.ts +1 -0
  18. package/src/input/onboarding/onboarding-runtime-status.ts +8 -8
  19. package/src/input/onboarding/onboarding-wizard-apply.ts +13 -53
  20. package/src/input/onboarding/onboarding-wizard-cloudflare-step.ts +4 -4
  21. package/src/input/onboarding/onboarding-wizard-cloudflare.ts +1 -1
  22. package/src/input/onboarding/onboarding-wizard-constants.ts +7 -7
  23. package/src/input/onboarding/onboarding-wizard-external-surface-extra-specs.ts +4 -4
  24. package/src/input/onboarding/onboarding-wizard-steps.ts +13 -13
  25. package/src/input/settings-modal-agent-policy.ts +18 -0
  26. package/src/input/settings-modal-types.ts +17 -0
  27. package/src/input/settings-modal.ts +30 -29
  28. package/src/main.ts +3 -26
  29. package/src/renderer/process-modal.ts +17 -8
  30. package/src/renderer/settings-modal.ts +12 -8
  31. package/src/renderer/ui-factory.ts +4 -32
  32. package/src/runtime/bootstrap-shell.ts +0 -13
  33. package/src/runtime/bootstrap.ts +0 -10
  34. package/src/runtime/onboarding/derivation.ts +6 -6
  35. package/src/verification/live-verifier.ts +148 -13
  36. package/src/version.ts +10 -3
  37. package/src/input/commands/quit-shared.ts +0 -162
  38. package/src/renderer/git-status.ts +0 -89
package/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  All notable changes to GoodVibes Agent will be recorded here.
4
4
 
5
+ ## 0.1.10 - 2026-05-31
6
+
7
+ - 93aba19 Block agent-spawning hook authoring
8
+ - 735839a Prune git header renderer from Agent
9
+ - 95d22fd Remove unused git shell bootstrap wiring
10
+ - 1392ebc Remove Agent write-quit commit helper
11
+ - df6572f Remove coding header posture from Agent shell
12
+ - 2b8e679 Align live verification with Agent routes
13
+ - 70eb800 Add stable typecheck release scripts
14
+ - 6b57500 Hide local agent activity in Agent UI
15
+ - 7166188 Add Agent Knowledge CLI shortcuts
16
+ - 386c19d Align service diagnostics with Agent boundaries
17
+ - e8b19db Lock daemon-owned settings in Agent
18
+
5
19
  ## 0.1.9 - 2026-05-31
6
20
 
7
21
  - 75e5d4a Align shell surface delegation test
package/README.md CHANGED
@@ -35,7 +35,7 @@ bun run dev
35
35
  Useful checks:
36
36
 
37
37
  ```sh
38
- bunx tsc --noEmit
38
+ bun run typecheck
39
39
  bun run build
40
40
  bun run package:install-check
41
41
  bun run publish:check
@@ -1,6 +1,6 @@
1
1
  # Getting Started
2
2
 
3
- GoodVibes Agent `0.1.7` is the current installable public alpha of the personal operator assistant built on the GoodVibes TUI foundation.
3
+ GoodVibes Agent `0.1.9` is the current installable public alpha of the personal operator assistant built on the GoodVibes TUI foundation.
4
4
 
5
5
  ## Requirements
6
6
 
@@ -1,6 +1,6 @@
1
1
  # Release And Publishing
2
2
 
3
- GoodVibes Agent `0.1.7` is the current installable public alpha release.
3
+ GoodVibes Agent `0.1.9` is the current installable public alpha release.
4
4
 
5
5
  ## Package Identity
6
6
 
@@ -17,7 +17,7 @@ Before any release candidate:
17
17
 
18
18
  ```sh
19
19
  bun install
20
- bunx tsc --noEmit
20
+ bun run typecheck
21
21
  bun run build
22
22
  bun run package:install-check
23
23
  bun run publish:check
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pellux/goodvibes-agent",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
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",
@@ -40,6 +40,8 @@
40
40
  "dev": "bun run src/main.ts",
41
41
  "tui": "bun run src/main.ts",
42
42
  "dev:watch": "bun --watch src/main.ts",
43
+ "typecheck": "bunx tsc --noEmit",
44
+ "check:types": "bun run typecheck",
43
45
  "prebuild": "bun run scripts/prebuild.ts",
44
46
  "build": "bun build src/main.ts --compile --outfile dist/goodvibes-agent",
45
47
  "build:linux-x64": "bun build src/main.ts --compile --target=bun-linux-x64 --outfile dist/goodvibes-agent-linux-x64",
@@ -61,6 +63,7 @@
61
63
  "build:all": "bun run scripts/build.ts --all",
62
64
  "perf:check": "bun run scripts/perf-check.ts",
63
65
  "architecture:check": "bun run scripts/check-architecture.ts",
66
+ "audit:home": "bun run scripts/audit-goodvibes-home.ts",
64
67
  "foundation:artifacts": "bun run scripts/export-foundation-artifacts.ts",
65
68
  "verification:ledger": "bun run scripts/verification-ledger.ts",
66
69
  "verification:live": "bun run scripts/verify-live.ts",
@@ -1,8 +1,8 @@
1
1
  import { existsSync, readFileSync } from 'node:fs';
2
- import { dirname, join } from 'node:path';
3
- import { fileURLToPath } from 'node:url';
2
+ import { join } from 'node:path';
4
3
  import { createBrowserAgentSdk } from '@pellux/goodvibes-sdk/browser/agent';
5
4
  import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
5
+ import { SDK_VERSION, VERSION } from '../version.ts';
6
6
  import type { CliCommandOutput } from './types.ts';
7
7
  import type { CliCommandRuntime } from './management.ts';
8
8
  import { formatJsonOrText, yesNo } from './management.ts';
@@ -149,24 +149,8 @@ function hasFlag(args: readonly string[], flag: string): boolean {
149
149
  return args.includes(flag);
150
150
  }
151
151
 
152
- function packageJsonPath(): string {
153
- return join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'package.json');
154
- }
155
-
156
152
  function readPackageMetadata(): { readonly version: string; readonly sdkVersion: string } {
157
- try {
158
- const parsed = JSON.parse(readFileSync(packageJsonPath(), 'utf-8')) as unknown;
159
- if (!isRecord(parsed)) return { version: 'unknown', sdkVersion: 'unknown' };
160
- const dependencies = isRecord(parsed.dependencies) ? parsed.dependencies : {};
161
- return {
162
- version: typeof parsed.version === 'string' ? parsed.version : 'unknown',
163
- sdkVersion: typeof dependencies['@pellux/goodvibes-sdk'] === 'string'
164
- ? dependencies['@pellux/goodvibes-sdk']
165
- : 'unknown',
166
- };
167
- } catch {
168
- return { version: 'unknown', sdkVersion: 'unknown' };
169
- }
153
+ return { version: VERSION, sdkVersion: SDK_VERSION };
170
154
  }
171
155
 
172
156
  function resolveDaemonConnection(runtime: CliCommandRuntime): AgentDaemonConnection {
@@ -553,6 +537,21 @@ export async function handleAgentKnowledgeCommand(runtime: CliCommandRuntime): P
553
537
  };
554
538
  }
555
539
 
540
+ export async function handleAgentKnowledgeShortcutCommand(
541
+ runtime: CliCommandRuntime,
542
+ subcommand: 'ask' | 'search',
543
+ ): Promise<CliCommandOutput> {
544
+ return handleAgentKnowledgeCommand({
545
+ ...runtime,
546
+ cli: {
547
+ ...runtime.cli,
548
+ command: 'knowledge',
549
+ rawCommand: 'knowledge',
550
+ commandArgs: [subcommand, ...runtime.cli.commandArgs],
551
+ },
552
+ });
553
+ }
554
+
556
555
  export async function handleCompatCommand(runtime: CliCommandRuntime): Promise<CliCommandOutput> {
557
556
  const connection = resolveDaemonConnection(runtime);
558
557
  const metadata = readPackageMetadata();
package/src/cli/help.ts CHANGED
@@ -41,6 +41,7 @@ export function renderGoodVibesHelp(binary = 'goodvibes-agent'): string {
41
41
  ' auth Inspect and manage local users, sessions, and bootstrap auth',
42
42
  ' compat Inspect Agent SDK pin, daemon version, and Agent knowledge route readiness',
43
43
  ' knowledge Use isolated Agent Knowledge/Wiki routes',
44
+ ' ask|search Shortcuts for isolated Agent Knowledge ask/search',
44
45
  ' delegate Explicitly delegate build/fix/review work to GoodVibes TUI',
45
46
  ' subscription Start/finish/logout provider subscription sessions',
46
47
  ' secrets List, set, link, delete, and test GoodVibes secret refs',
@@ -95,6 +96,8 @@ export function renderGoodVibesHelp(binary = 'goodvibes-agent'): string {
95
96
  ` ${binary} compat`,
96
97
  ` ${binary} knowledge status`,
97
98
  ` ${binary} knowledge ask "What is GoodVibes Agent?"`,
99
+ ` ${binary} ask "What is GoodVibes Agent?"`,
100
+ ` ${binary} search "release checklist"`,
98
101
  ` ${binary} delegate --wrfc "fix the failing tests in ~/work/project"`,
99
102
  ` ${binary} surfaces`,
100
103
  ` ${binary} surfaces check`,
@@ -174,6 +177,16 @@ const COMMAND_HELP: Record<string, CommandHelp> = {
174
177
  'knowledge ingest-url https://example.com/page --title "Reference"',
175
178
  ],
176
179
  },
180
+ ask: {
181
+ usage: ['ask <question> [--limit <n>] [--mode concise|standard|detailed]'],
182
+ summary: 'Shortcut for isolated Agent Knowledge ask. This never queries default Knowledge/Wiki or HomeGraph.',
183
+ examples: ['ask "What is GoodVibes Agent?"', 'ask "release checklist" --mode concise'],
184
+ },
185
+ search: {
186
+ usage: ['search <query> [--limit <n>]'],
187
+ summary: 'Shortcut for isolated Agent Knowledge search. This never queries default Knowledge/Wiki or HomeGraph.',
188
+ examples: ['search "release checklist"', 'search "operator workspace" --limit 5'],
189
+ },
177
190
  delegate: {
178
191
  usage: ['delegate [--wrfc] <build/fix/review task>'],
179
192
  summary: 'Create one shared-session task request for GoodVibes TUI. WRFC is requested only with --wrfc.',
@@ -329,9 +329,9 @@ export async function buildControlPlaneStatusResult(runtime: CliCommandRuntime):
329
329
  };
330
330
  const issues: string[] = [];
331
331
  if (enabled === true && !reachable) issues.push(`Control plane is enabled but not reachable on ${binding.host}:${binding.port}.`);
332
- if (enabled === true && service.enabled !== true) issues.push('Control plane is enabled but service mode is off.');
333
- if (enabled === true && service.autostart !== true) issues.push('Control plane is enabled but service autostart is off.');
334
- if (enabled === true && service.restartOnFailure !== true) issues.push('Control plane is enabled but service restart-on-failure is off.');
332
+ if (enabled === true && service.enabled !== true) issues.push('Control plane is enabled on the external daemon config, but Agent service ownership is disabled.');
333
+ if (enabled === true && service.autostart !== true) issues.push('Control plane is enabled on the external daemon config, but daemon autostart is off.');
334
+ if (enabled === true && service.restartOnFailure !== true) issues.push('Control plane is enabled on the external daemon config, but restart-on-failure is off.');
335
335
  if (isNetworkFacing(enabled, binding) && !auth.userStorePresent) issues.push('Network-facing control plane has no local auth user store.');
336
336
  if (isNetworkFacing(enabled, binding) && auth.bootstrapCredentialPresent) issues.push('Network-facing control plane still has a bootstrap credential file.');
337
337
  return {
@@ -32,7 +32,7 @@ import { handleServiceCommand } from './service-command.ts';
32
32
  import { handleBundleCommand } from './bundle-command.ts';
33
33
  import { buildListenerTestResult, formatListenerTestResult, handleSurfacesCommand } from './surface-command.ts';
34
34
  import { buildControlPlaneStatusResult, formatControlPlaneStatus, handleSecrets, handleSessions, handleTasks, renderPairing, renderRemote, renderSubscriptions, renderWeb } from './management-commands.ts';
35
- import { handleAgentKnowledgeCommand, handleCompatCommand, handleDelegateCommand } from './agent-knowledge-command.ts';
35
+ import { handleAgentKnowledgeCommand, handleAgentKnowledgeShortcutCommand, handleCompatCommand, handleDelegateCommand } from './agent-knowledge-command.ts';
36
36
  import { GOODVIBES_AGENT_SURFACE_ROOT } from '../config/surface.ts';
37
37
 
38
38
  export interface CliCommandRuntime {
@@ -703,6 +703,12 @@ export async function handleGoodVibesCliCommand(runtime: CliCommandRuntime): Pro
703
703
  console.log(result.output);
704
704
  return { handled: true, exitCode: result.exitCode };
705
705
  }
706
+ case 'ask':
707
+ case 'search': {
708
+ const result = await handleAgentKnowledgeShortcutCommand(runtime, runtime.cli.command);
709
+ console.log(result.output);
710
+ return { handled: true, exitCode: result.exitCode };
711
+ }
706
712
  case 'delegate': {
707
713
  const result = await handleDelegateCommand(runtime);
708
714
  console.log(result.output);
package/src/cli/parser.ts CHANGED
@@ -31,6 +31,9 @@ const COMMAND_ALIASES: Readonly<Record<string, GoodVibesCliCommand>> = {
31
31
  knowledge: 'knowledge',
32
32
  know: 'knowledge',
33
33
  kb: 'knowledge',
34
+ ask: 'ask',
35
+ search: 'search',
36
+ find: 'search',
34
37
  delegate: 'delegate',
35
38
  build: 'delegate',
36
39
  subscription: 'subscription',
@@ -397,19 +397,19 @@ export async function buildCliServicePosture(
397
397
  const issues: string[] = [];
398
398
 
399
399
  if (serverBackedEnabled && !config.enabled) {
400
- issues.push('Server-backed surfaces are enabled but service mode is off.');
400
+ issues.push('Daemon-owned surfaces are configured, but Agent service ownership is disabled.');
401
401
  }
402
402
  if (config.enabled && !config.autostart) {
403
- issues.push('Service mode is enabled but autostart is off.');
403
+ issues.push('External daemon service config has autostart off.');
404
404
  }
405
405
  if (config.enabled && !config.restartOnFailure) {
406
- issues.push('Service mode is enabled but restart-on-failure is off.');
406
+ issues.push('External daemon service config has restart-on-failure off.');
407
407
  }
408
408
  if (config.enabled && !status.installed) {
409
- issues.push('Service mode is enabled but no platform service definition is installed.');
409
+ issues.push('External daemon service config is enabled, but no platform service definition is installed.');
410
410
  }
411
411
  if (config.enabled && !status.running) {
412
- issues.push('Service mode is enabled but the managed service is not running.');
412
+ issues.push('External daemon service config is enabled, but the managed service is not running.');
413
413
  }
414
414
  if (status.actionError) {
415
415
  issues.push(`Service manager reported an error: ${status.actionError}`);
@@ -454,7 +454,7 @@ function yesNo(value: boolean): string {
454
454
  export function formatCliServicePosture(posture: CliServicePosture, json = false): string {
455
455
  if (json) return JSON.stringify(posture, null, 2);
456
456
  return [
457
- 'GoodVibes service',
457
+ 'GoodVibes external daemon service',
458
458
  ` enabled: ${yesNo(posture.config.enabled)}`,
459
459
  ` autostart: ${yesNo(posture.config.autostart)}`,
460
460
  ` restartOnFailure: ${yesNo(posture.config.restartOnFailure)}`,
package/src/cli/status.ts CHANGED
@@ -122,10 +122,10 @@ export function buildCliDoctorFindings(options: CliStatusOptions): readonly CliD
122
122
  id: 'service-disabled-for-server-surfaces',
123
123
  area: 'service',
124
124
  severity: 'warning',
125
- summary: 'Server-backed surfaces are enabled but service mode is off.',
125
+ summary: 'Daemon-owned surfaces are configured while Agent service ownership is disabled.',
126
126
  cause: 'One or more daemon, control-plane, listener, or web settings are enabled while service.enabled is false.',
127
- impact: 'The configured surfaces may not start automatically or survive restarts.',
128
- action: 'Enable service mode or disable the server-backed surfaces you do not want.',
127
+ impact: 'The external daemon host must own availability for those surfaces; Agent will not start or enable them.',
128
+ action: 'Manage surface/service posture from GoodVibes TUI or the daemon host, then use Agent for read-only diagnostics.',
129
129
  });
130
130
  }
131
131
 
@@ -134,10 +134,10 @@ export function buildCliDoctorFindings(options: CliStatusOptions): readonly CliD
134
134
  id: 'service-autostart-disabled',
135
135
  area: 'service',
136
136
  severity: 'warning',
137
- summary: 'Service mode is enabled but autostart is off.',
137
+ summary: 'External daemon service config has autostart off.',
138
138
  cause: 'service.enabled is true and service.autostart is false.',
139
139
  impact: 'The external GoodVibes daemon may not be available after login or reboot even though service mode is selected.',
140
- action: 'Enable service.autostart if the daemon/listener/web surfaces should stay available.',
140
+ action: 'Configure daemon autostart from GoodVibes TUI or the daemon host; Agent will not mutate this setting.',
141
141
  });
142
142
  }
143
143
 
@@ -146,10 +146,10 @@ export function buildCliDoctorFindings(options: CliStatusOptions): readonly CliD
146
146
  id: 'service-restart-disabled',
147
147
  area: 'service',
148
148
  severity: 'warning',
149
- summary: 'Service restart-on-failure is off.',
149
+ summary: 'External daemon service config has restart-on-failure off.',
150
150
  cause: 'service.enabled is true and service.restartOnFailure is false.',
151
151
  impact: 'A crashed daemon or listener may stay down until manually restarted.',
152
- action: 'Enable service.restartOnFailure for durable daemon/listener operation.',
152
+ action: 'Configure restart-on-failure from GoodVibes TUI or the daemon host; Agent will not mutate this setting.',
153
153
  });
154
154
  }
155
155
 
@@ -163,7 +163,7 @@ export function buildCliDoctorFindings(options: CliStatusOptions): readonly CliD
163
163
  summary: issue,
164
164
  cause: 'The service lifecycle inspection found a mismatch between configured service/surface state and observed host state.',
165
165
  impact: 'Daemon, control-plane, listener, or web availability may not match the configuration.',
166
- action: 'Run goodvibes-agent service check, then manage the daemon from GoodVibes TUI or your daemon host tooling.',
166
+ action: 'Use goodvibes-agent service check for read-only detail, then manage the daemon from GoodVibes TUI or your daemon host tooling.',
167
167
  });
168
168
  }
169
169
  }
@@ -326,7 +326,7 @@ export function renderCliStatus(options: CliStatusOptions): string {
326
326
  ? ` operatorTokens: ${options.auth.operatorTokenPresent ? 'present' : 'missing'} (${options.auth.operatorTokenPath})`
327
327
  : ' operatorTokens: unknown',
328
328
  '',
329
- 'Service:',
329
+ 'External Daemon Service:',
330
330
  ` enabled: ${yesNo(serviceEnabled)}`,
331
331
  ` autostart: ${yesNo(serviceAutostart)}`,
332
332
  ` restartOnFailure: ${yesNo(restartOnFailure)}`,
@@ -217,9 +217,9 @@ export async function buildListenerTestResult(runtime: CliCommandRuntime): Promi
217
217
  }).filter((surface) => surface.enabled === true);
218
218
  const issues: string[] = [];
219
219
  if (enabled !== true) issues.push('HTTP listener is disabled.');
220
- if (enabled === true && service.enabled !== true) issues.push('HTTP listener is enabled but service mode is off.');
221
- if (enabled === true && service.autostart !== true) issues.push('HTTP listener is enabled but service autostart is off.');
222
- if (enabled === true && service.restartOnFailure !== true) issues.push('HTTP listener is enabled but service restart-on-failure is off.');
220
+ if (enabled === true && service.enabled !== true) issues.push('HTTP listener is enabled on the external daemon config, but Agent service ownership is disabled.');
221
+ if (enabled === true && service.autostart !== true) issues.push('HTTP listener is enabled on the external daemon config, but daemon autostart is off.');
222
+ if (enabled === true && service.restartOnFailure !== true) issues.push('HTTP listener is enabled on the external daemon config, but restart-on-failure is off.');
223
223
  if (isNetworkFacing(enabled, binding) && !auth.userStorePresent) issues.push('Network-facing listener has no local auth user store.');
224
224
  if (isNetworkFacing(enabled, binding) && auth.bootstrapCredentialPresent) issues.push('Network-facing listener still has a bootstrap credential file.');
225
225
  for (const surface of surfaces) {
package/src/cli/types.ts CHANGED
@@ -12,6 +12,8 @@ export type GoodVibesCliCommand =
12
12
  | 'auth'
13
13
  | 'compat'
14
14
  | 'knowledge'
15
+ | 'ask'
16
+ | 'search'
15
17
  | 'delegate'
16
18
  | 'subscription'
17
19
  | 'secrets'
@@ -165,7 +165,7 @@ export function registerExperienceRuntimeCommands(registry: CommandRegistry): vo
165
165
  ['shell', 'Shell execution approval with side-effect and credential review.'],
166
166
  ['file', 'File mutation approval with config/notebook differentiation.'],
167
167
  ['network', 'Network access approval with host/scope review.'],
168
- ['delegate', 'Agent spawn/delegation approval with recursion ceilings.'],
168
+ ['delegate', 'Explicit GoodVibes TUI build delegation approval; local Agent spawn is blocked.'],
169
169
  ['mcp', 'MCP trust escalation approval with host/path review.'],
170
170
  ['remote', 'Remote dispatch approval with trust/artifact review.'],
171
171
  ['hook', 'Hook execution approval with deny/mutate authority review.'],
@@ -1,6 +1,26 @@
1
+ import { readFileSync } from 'node:fs';
1
2
  import type { CommandRegistry } from '../command-registry.ts';
2
3
  import { requireHookApi } from './runtime-services.ts';
3
4
 
5
+ function isRecord(value: unknown): value is Record<string, unknown> {
6
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
7
+ }
8
+
9
+ function containsAgentHookType(value: unknown): boolean {
10
+ if (Array.isArray(value)) return value.some((entry) => containsAgentHookType(entry));
11
+ if (!isRecord(value)) return false;
12
+ if (value.type === 'agent') return true;
13
+ return Object.values(value).some((entry) => containsAgentHookType(entry));
14
+ }
15
+
16
+ function fileContainsAgentHookType(path: string): boolean {
17
+ try {
18
+ return containsAgentHookType(JSON.parse(readFileSync(path, 'utf-8')) as unknown);
19
+ } catch {
20
+ return false;
21
+ }
22
+ }
23
+
4
24
  export function registerHooksRuntimeCommands(registry: CommandRegistry): void {
5
25
  registry.register({
6
26
  name: 'hooks',
@@ -25,10 +45,14 @@ export function registerHooksRuntimeCommands(registry: CommandRegistry): void {
25
45
  if (subcommand === 'scaffold') {
26
46
  const [name, match, type] = args.slice(1);
27
47
  if (!name || !match || !type) {
28
- ctx.print('Usage: /hooks scaffold <name> <match> <command|prompt|agent|http|ts>');
48
+ ctx.print('Usage: /hooks scaffold <name> <match> <command|prompt|http|ts>');
49
+ return;
50
+ }
51
+ if (type === 'agent') {
52
+ ctx.print('Blocked: GoodVibes Agent does not author local agent-spawning hooks. Use command, prompt, http, or ts hooks, or delegate explicit build work to GoodVibes TUI.');
29
53
  return;
30
54
  }
31
- if (!['command', 'prompt', 'agent', 'http', 'ts'].includes(type)) {
55
+ if (!['command', 'prompt', 'http', 'ts'].includes(type)) {
32
56
  ctx.print(`Unknown hook type: ${type}`);
33
57
  return;
34
58
  }
@@ -118,6 +142,10 @@ export function registerHooksRuntimeCommands(registry: CommandRegistry): void {
118
142
  ctx.print('Usage: /hooks import <path> [merge|replace]');
119
143
  return;
120
144
  }
145
+ if (fileContainsAgentHookType(path)) {
146
+ ctx.print('Blocked: hook bundle contains type=agent entries. GoodVibes Agent does not import local agent-spawning hooks.');
147
+ return;
148
+ }
121
149
  await workbench.import(path, strategy);
122
150
  ctx.print(`Imported managed hooks from ${path} using ${strategy} strategy.`);
123
151
  return;
@@ -238,6 +238,7 @@ export class InputHandler {
238
238
  agentManager: uiServices.agents.agentManager,
239
239
  processManager: uiServices.shell.processManager,
240
240
  wrfcController: uiServices.agents.wrfcController,
241
+ agentEntries: 'hidden',
241
242
  });
242
243
  this.liveTailModal = new LiveTailModal({
243
244
  agentManager: uiServices.agents.agentManager,
@@ -19,24 +19,24 @@ export function runtimePortDiagnostic(
19
19
  if (status) {
20
20
  const reason = status.reason ? ` ${status.reason}` : '';
21
21
  if (status.mode === 'blocked') {
22
- return `The configured endpoint ${status.baseUrl} is occupied but was not usable by this TUI instance.${reason}`;
22
+ return `The configured endpoint ${status.baseUrl} is occupied but was not usable by this Agent instance.${reason}`;
23
23
  }
24
24
  if (status.mode === 'disabled') {
25
25
  return `The configured endpoint ${status.baseUrl} is disabled in the runtime service configuration.${reason}`;
26
26
  }
27
27
  if (status.mode === 'unavailable') {
28
- return `The configured endpoint ${status.baseUrl} is unavailable after startup or restart.${reason}`;
28
+ return `The configured endpoint ${status.baseUrl} is unavailable to Agent.${reason}`;
29
29
  }
30
30
  if (status.mode === 'external') {
31
31
  const version = status.version ? ` version ${status.version}` : '';
32
32
  return `An existing GoodVibes service was verified at ${status.baseUrl}${version}.`;
33
33
  }
34
- return `An embedded GoodVibes service is running at ${status.baseUrl}.`;
34
+ return `A GoodVibes service reports embedded mode at ${status.baseUrl}; Agent still treats daemon lifecycle as external.`;
35
35
  }
36
36
  if (portInUse) {
37
- return `The configured port ${binding.host}:${binding.port} is occupied after restart; another GoodVibes process, an overlapping restart, or another service may still own it.`;
37
+ return `The configured port ${binding.host}:${binding.port} is occupied; another GoodVibes process or another service may own it.`;
38
38
  }
39
- return `No process is listening on ${binding.host}:${binding.port} after restart.`;
39
+ return `No process is listening on ${binding.host}:${binding.port}.`;
40
40
  }
41
41
 
42
42
  export function getRuntimeEndpointStatus(
@@ -79,9 +79,9 @@ export function formatRuntimeActiveSuccessMessage(
79
79
  return `${label} is already running as a verified external GoodVibes service at ${status.baseUrl}${version}.`;
80
80
  }
81
81
  if (status?.mode === 'embedded') {
82
- return `${label} is running as an embedded service at ${status.baseUrl}.`;
82
+ return `${label} reports embedded mode at ${status.baseUrl}; Agent does not own that service lifecycle.`;
83
83
  }
84
84
  return endpoint === 'daemon'
85
- ? 'The GoodVibes daemon is running with the applied onboarding settings.'
86
- : 'The HTTP listener is running with the applied onboarding settings.';
85
+ ? 'The GoodVibes daemon is reachable to Agent.'
86
+ : 'The HTTP listener is reachable to Agent.';
87
87
  }
@@ -15,7 +15,7 @@ import {
15
15
  getExternalSurfaceAutoStartFieldId,
16
16
  isExternalSurfaceSelectedByDefault,
17
17
  } from './onboarding-wizard-external-surfaces.ts';
18
- import { buildGoodVibesSecretKey, buildGoodVibesSecretRef, isLoopbackAddress, isSecretReferenceValue } from './onboarding-wizard-helpers.ts';
18
+ import { buildGoodVibesSecretKey, buildGoodVibesSecretRef, isSecretReferenceValue } from './onboarding-wizard-helpers.ts';
19
19
  import type { OnboardingWizardController } from './onboarding-wizard.ts';
20
20
 
21
21
  export function buildOnboardingApplyRequest(controller: OnboardingWizardController): OnboardingApplyRequest {
@@ -203,7 +203,7 @@ function addCloudflareOperations(
203
203
  setConfig('cloudflare.workerCron', controller.getStringFieldValue('cloudflare.worker-cron', config?.workerCron ?? '*/5 * * * *'));
204
204
  setConfig('cloudflare.queueName', controller.getStringFieldValue('cloudflare.queue-name', config?.queueName ?? 'goodvibes-batch'));
205
205
  setConfig('cloudflare.deadLetterQueueName', controller.getStringFieldValue('cloudflare.dead-letter-queue-name', config?.deadLetterQueueName ?? 'goodvibes-batch-dlq'));
206
- setConfig('cloudflare.tunnelName', controller.getStringFieldValue('cloudflare.tunnel-name', config?.tunnelName ?? 'goodvibes-daemon'));
206
+ setConfig('cloudflare.tunnelName', controller.getStringFieldValue('cloudflare.tunnel-name', config?.tunnelName ?? 'goodvibes-agent-daemon'));
207
207
  setConfig('cloudflare.tunnelId', controller.getStringFieldValue('cloudflare.tunnel-id', config?.tunnelId ?? ''));
208
208
  setConfig('cloudflare.tunnelTokenRef', controller.getStringFieldValue('cloudflare.tunnel-token-ref', config?.tunnelTokenRef ?? ''));
209
209
  setConfig('cloudflare.accessAppId', controller.getStringFieldValue('cloudflare.access-app-id', config?.accessAppId ?? ''));
@@ -222,56 +222,16 @@ function addCloudflareOperations(
222
222
  }
223
223
 
224
224
  export function addNetworkOperations(
225
- controller: OnboardingWizardController,
226
- operations: OnboardingApplyOperation[],
227
- customNetwork: boolean,
228
- enabled: {
229
- readonly controlPlane: boolean;
230
- readonly controlPlaneRemote: boolean;
231
- readonly httpListener: boolean;
232
- readonly web: boolean;
233
- },
225
+ _controller: OnboardingWizardController,
226
+ _operations: OnboardingApplyOperation[],
227
+ _customNetwork: boolean,
228
+ _enabled: {
229
+ readonly controlPlane: boolean;
230
+ readonly controlPlaneRemote: boolean;
231
+ readonly httpListener: boolean;
232
+ readonly web: boolean;
233
+ },
234
234
  ): void {
235
- const setConfig = (
236
- key: Extract<OnboardingApplyOperation, { kind: 'set-config' }>['key'],
237
- value: unknown,
238
- ): void => {
239
- operations.push({ kind: 'set-config', key, value });
240
- };
241
- const networkFacingEnabled = {
242
- controlPlane: enabled.controlPlaneRemote,
243
- httpListener: enabled.httpListener,
244
- web: enabled.web,
245
- };
246
- const sharedIpDefault = controller.getSharedIpDefault(networkFacingEnabled);
247
- const sharedIp = controller.getBooleanFieldValue('network.shared-ip', sharedIpDefault);
248
- const sharedHost = controller.getStringFieldValue('network.shared-ip-address', controller.getSharedIpHostDefault(networkFacingEnabled)) || '0.0.0.0';
249
- const controlPlaneHost = sharedIp
250
- ? sharedHost
251
- : controller.getStringFieldValue('network.service-ip', controller.runtimeSnapshot?.bindSettings.controlPlane.host ?? '0.0.0.0');
252
- const httpListenerHost = sharedIp
253
- ? sharedHost
254
- : controller.getStringFieldValue('network.webhook-ip', controller.runtimeSnapshot?.bindSettings.httpListener.host ?? '0.0.0.0');
255
- const webHost = sharedIp
256
- ? sharedHost
257
- : controller.getStringFieldValue('network.browser-ip', controller.runtimeSnapshot?.bindSettings.web.host ?? '0.0.0.0');
258
-
259
- if (enabled.controlPlane) {
260
- setConfig('controlPlane.hostMode', enabled.controlPlaneRemote ? (customNetwork ? 'custom' : 'network') : 'local');
261
- setConfig('controlPlane.host', enabled.controlPlaneRemote ? (customNetwork ? controlPlaneHost : '0.0.0.0') : '127.0.0.1');
262
- setConfig('controlPlane.port', controller.getPortFieldValue('network.service-port', controller.runtimeSnapshot?.bindSettings.controlPlane.port ?? 3421));
263
- setConfig('controlPlane.allowRemote', enabled.controlPlaneRemote && (customNetwork ? !isLoopbackAddress(controlPlaneHost) : true));
264
- }
265
-
266
- if (enabled.httpListener) {
267
- setConfig('httpListener.hostMode', customNetwork ? 'custom' : 'network');
268
- setConfig('httpListener.host', customNetwork ? httpListenerHost : '0.0.0.0');
269
- setConfig('httpListener.port', controller.getPortFieldValue('network.webhook-port', controller.runtimeSnapshot?.bindSettings.httpListener.port ?? 3422));
270
- }
271
-
272
- if (enabled.web) {
273
- setConfig('web.hostMode', customNetwork ? 'custom' : 'network');
274
- setConfig('web.host', customNetwork ? webHost : '0.0.0.0');
275
- setConfig('web.port', controller.getPortFieldValue('network.browser-port', controller.runtimeSnapshot?.bindSettings.web.port ?? 3423));
276
- }
235
+ // Agent onboarding intentionally never mutates daemon/listener/web bind posture.
236
+ // Network fields are advisory for the external daemon owner.
277
237
  }
@@ -26,7 +26,7 @@ export function buildCloudflareStep(controller: OnboardingWizardController): Onb
26
26
  const bind = controller.runtimeSnapshot?.bindSettings.controlPlane;
27
27
  const defaultDaemonBaseUrl = normalizeText(config?.daemonBaseUrl)
28
28
  || `http://${bind?.host && bind.host !== '0.0.0.0' && bind.host !== '::' ? bind.host : '127.0.0.1'}:${bind?.port ?? 3421}`;
29
- const resultMessage = controller.textState.get('cloudflare.action-status') ?? 'No Cloudflare daemon action has run in this wizard session.';
29
+ const resultMessage = controller.textState.get('cloudflare.action-status') ?? 'No Cloudflare action has run in this wizard session.';
30
30
  const fields: OnboardingWizardFieldDefinition[] = [
31
31
  {
32
32
  kind: 'checklist',
@@ -96,7 +96,7 @@ export function buildCloudflareStep(controller: OnboardingWizardController): Onb
96
96
  kind: 'text',
97
97
  id: 'cloudflare.bootstrap-env-name',
98
98
  label: 'Bootstrap token environment variable',
99
- hint: 'The TUI reads this environment variable once and passes the value to the SDK token-create route. It is not persisted.',
99
+ hint: 'Agent reads this environment variable once and passes the value to the SDK token-create route. It is not persisted.',
100
100
  placeholder: 'GOODVIBES_CLOUDFLARE_BOOTSTRAP_TOKEN',
101
101
  defaultValue: 'GOODVIBES_CLOUDFLARE_BOOTSTRAP_TOKEN',
102
102
  });
@@ -227,8 +227,8 @@ export function buildCloudflareStep(controller: OnboardingWizardController): Onb
227
227
  id: 'cloudflare.tunnel-name',
228
228
  label: 'Tunnel name',
229
229
  hint: 'Cloudflare Tunnel name to create or reuse.',
230
- placeholder: 'goodvibes-daemon',
231
- defaultValue: config?.tunnelName || 'goodvibes-daemon',
230
+ placeholder: 'goodvibes-agent-daemon',
231
+ defaultValue: config?.tunnelName || 'goodvibes-agent-daemon',
232
232
  },
233
233
  {
234
234
  kind: 'text',
@@ -176,7 +176,7 @@ export function buildCloudflareProvisionRequest(controller: OnboardingWizardCont
176
176
  daemonHostname: controller.getStringFieldValue('cloudflare.daemon-hostname', controller.runtimeSnapshot?.config.cloudflare.daemonHostname ?? ''),
177
177
  queueName: controller.getStringFieldValue('cloudflare.queue-name', controller.runtimeSnapshot?.config.cloudflare.queueName ?? 'goodvibes-batch'),
178
178
  deadLetterQueueName: controller.getStringFieldValue('cloudflare.dead-letter-queue-name', controller.runtimeSnapshot?.config.cloudflare.deadLetterQueueName ?? 'goodvibes-batch-dlq'),
179
- tunnelName: controller.getStringFieldValue('cloudflare.tunnel-name', controller.runtimeSnapshot?.config.cloudflare.tunnelName ?? 'goodvibes-daemon'),
179
+ tunnelName: controller.getStringFieldValue('cloudflare.tunnel-name', controller.runtimeSnapshot?.config.cloudflare.tunnelName ?? 'goodvibes-agent-daemon'),
180
180
  tunnelId: controller.getStringFieldValue('cloudflare.tunnel-id', controller.runtimeSnapshot?.config.cloudflare.tunnelId ?? ''),
181
181
  tunnelServiceUrl: controller.getStringFieldValue('cloudflare.tunnel-service-url', ''),
182
182
  tunnelTokenRef: controller.getStringFieldValue('cloudflare.tunnel-token-ref', controller.runtimeSnapshot?.config.cloudflare.tunnelTokenRef ?? ''),