@pellux/goodvibes-agent 0.1.55 → 0.1.57

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 (94) hide show
  1. package/.goodvibes/GOODVIBES.md +1 -1
  2. package/CHANGELOG.md +19 -8
  3. package/README.md +10 -3
  4. package/docs/README.md +1 -1
  5. package/docs/getting-started.md +10 -3
  6. package/docs/release-and-publishing.md +12 -3
  7. package/package.json +1 -3
  8. package/scripts/check-bun.sh +5 -1
  9. package/src/agent/routine-schedule-args.ts +219 -0
  10. package/src/agent/routine-schedule-format.ts +173 -0
  11. package/src/agent/routine-schedule-promotion.ts +3 -811
  12. package/src/agent/routine-schedule-receipts.ts +502 -0
  13. package/src/cli/agent-knowledge-command.ts +6 -6
  14. package/src/cli/help.ts +3 -25
  15. package/src/cli/package-verification.ts +23 -16
  16. package/src/cli/redaction.ts +4 -1
  17. package/src/cli/routines-command.ts +10 -6
  18. package/src/cli/service-posture.ts +47 -280
  19. package/src/cli/status.ts +0 -1
  20. package/src/config/secret-config.ts +0 -2
  21. package/src/input/agent-workspace-categories.ts +219 -0
  22. package/src/input/agent-workspace-editors.ts +143 -0
  23. package/src/input/agent-workspace-snapshot.ts +265 -0
  24. package/src/input/agent-workspace-types.ts +142 -0
  25. package/src/input/agent-workspace.ts +22 -766
  26. package/src/input/commands/agent-runtime-profile-runtime.ts +1 -1
  27. package/src/input/commands/delegation-runtime.ts +1 -1
  28. package/src/input/commands/experience-runtime.ts +3 -4
  29. package/src/input/commands/guidance-runtime.ts +1 -2
  30. package/src/input/commands/health-runtime.ts +3 -65
  31. package/src/input/commands/knowledge.ts +7 -7
  32. package/src/input/commands/local-setup-review.ts +0 -61
  33. package/src/input/commands/local-setup-transfer.ts +0 -3
  34. package/src/input/commands/local-setup.ts +2 -15
  35. package/src/input/commands/planning-runtime.ts +4 -1
  36. package/src/input/commands/platform-access-runtime.ts +1 -10
  37. package/src/input/commands/platform-services-runtime.ts +0 -1
  38. package/src/input/commands/recall-query.ts +1 -1
  39. package/src/input/commands/routines-runtime.ts +10 -6
  40. package/src/input/commands/schedule-runtime.ts +10 -6
  41. package/src/input/commands/session-workflow.ts +1 -1
  42. package/src/input/commands/tasks-runtime.ts +1 -14
  43. package/src/input/commands.ts +0 -4
  44. package/src/input/handler-onboarding.ts +10 -120
  45. package/src/input/onboarding/onboarding-wizard-apply.ts +5 -196
  46. package/src/input/onboarding/onboarding-wizard-constants.ts +8 -119
  47. package/src/input/onboarding/onboarding-wizard-helpers.ts +2 -53
  48. package/src/input/onboarding/onboarding-wizard-rules.ts +2 -236
  49. package/src/input/onboarding/onboarding-wizard-state.ts +1 -69
  50. package/src/input/onboarding/onboarding-wizard-steps.ts +584 -737
  51. package/src/input/onboarding/onboarding-wizard-types.ts +8 -26
  52. package/src/input/onboarding/onboarding-wizard.ts +4 -109
  53. package/src/input/settings-modal-agent-policy.ts +10 -0
  54. package/src/input/settings-modal-types.ts +2 -4
  55. package/src/input/settings-modal.ts +3 -1
  56. package/src/input/submission-router.ts +0 -1
  57. package/src/panels/approval-panel.ts +1 -2
  58. package/src/panels/builtin/operations.ts +1 -2
  59. package/src/panels/knowledge-panel.ts +2 -2
  60. package/src/panels/project-planning-panel.ts +4 -1
  61. package/src/panels/provider-health-domains.ts +0 -22
  62. package/src/panels/provider-health-panel.ts +1 -5
  63. package/src/panels/session-browser-panel.ts +0 -5
  64. package/src/panels/tasks-panel.ts +2 -64
  65. package/src/renderer/agent-workspace.ts +1 -1
  66. package/src/renderer/help-overlay.ts +1 -2
  67. package/src/renderer/semantic-diff.ts +1 -1
  68. package/src/renderer/settings-modal-helpers.ts +0 -16
  69. package/src/renderer/settings-modal.ts +3 -5
  70. package/src/runtime/bootstrap-hook-bridge.ts +0 -3
  71. package/src/runtime/bootstrap-shell.ts +2 -1
  72. package/src/runtime/bootstrap.ts +1 -1
  73. package/src/runtime/index.ts +0 -1
  74. package/src/runtime/onboarding/derivation.ts +1 -28
  75. package/src/runtime/onboarding/snapshot.ts +0 -1
  76. package/src/runtime/onboarding/types.ts +1 -4
  77. package/src/runtime/services.ts +4 -23
  78. package/src/runtime/ui-read-models.ts +4 -3
  79. package/src/shell/service-settings-sync.ts +15 -244
  80. package/src/tools/agent-context-policy.ts +1 -1
  81. package/src/tools/wrfc-agent-guard.ts +3 -3
  82. package/src/verification/live-verifier.ts +11 -5
  83. package/src/verification/verification-ledger.ts +3 -6
  84. package/src/version.ts +1 -1
  85. package/src/input/commands/agent-externalized-tui.ts +0 -73
  86. package/src/input/commands/cloudflare-runtime.ts +0 -385
  87. package/src/input/handler-onboarding-cloudflare.ts +0 -322
  88. package/src/input/onboarding/onboarding-runtime-status.ts +0 -87
  89. package/src/input/onboarding/onboarding-wizard-cloudflare-step.ts +0 -494
  90. package/src/input/onboarding/onboarding-wizard-cloudflare.ts +0 -199
  91. package/src/input/onboarding/onboarding-wizard-external-surface-extra-specs.ts +0 -130
  92. package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +0 -762
  93. package/src/runtime/cloudflare-control-plane.ts +0 -350
  94. package/src/runtime/sandbox-public-gaps.ts +0 -358
@@ -2,18 +2,22 @@ import { createShellPathService } from '@/runtime/index.ts';
2
2
  import { AgentRoutineRegistry, type AgentRoutineRecord } from '../agent/routine-registry.ts';
3
3
  import {
4
4
  buildRoutineSchedulePreview,
5
+ promoteRoutineToDaemonSchedule,
6
+ resolveAgentDaemonConnection,
7
+ } from '../agent/routine-schedule-promotion.ts';
8
+ import { parseRoutineSchedulePromotionArgs } from '../agent/routine-schedule-args.ts';
9
+ import {
5
10
  formatRoutineScheduleCorrelation,
6
- formatRoutineScheduleReceipt,
7
- formatRoutineScheduleReceipts,
8
11
  formatRoutineScheduleFailure,
9
12
  formatRoutineSchedulePreview,
13
+ formatRoutineScheduleReceipt,
14
+ formatRoutineScheduleReceipts,
10
15
  formatRoutineScheduleSuccess,
11
- parseRoutineSchedulePromotionArgs,
12
- promoteRoutineToDaemonSchedule,
16
+ } from '../agent/routine-schedule-format.ts';
17
+ import {
13
18
  reconcileRoutineScheduleReceipts,
14
- resolveAgentDaemonConnection,
15
19
  RoutineScheduleReceiptStore,
16
- } from '../agent/routine-schedule-promotion.ts';
20
+ } from '../agent/routine-schedule-receipts.ts';
17
21
  import type { CliCommandOutput } from './types.ts';
18
22
  import type { CliCommandRuntime } from './management.ts';
19
23
 
@@ -1,10 +1,6 @@
1
- import { spawnSync } from 'node:child_process';
2
- import { accessSync, closeSync, constants, existsSync, openSync, readSync, realpathSync, statSync } from 'node:fs';
1
+ import { closeSync, existsSync, openSync, readSync, statSync } from 'node:fs';
3
2
  import net from 'node:net';
4
- import { basename, delimiter, dirname, isAbsolute, join, resolve } from 'node:path';
5
- import { fileURLToPath } from 'node:url';
6
- import { PlatformServiceManager } from '@pellux/goodvibes-sdk/platform/daemon';
7
- import type { ManagedServiceStatus } from '@pellux/goodvibes-sdk/platform/daemon';
3
+ import { isAbsolute, join } from 'node:path';
8
4
  import type { ConfigManager } from '../config/index.ts';
9
5
  import { resolveRuntimeEndpointBinding } from './endpoints.ts';
10
6
  import type { RuntimeEndpointBinding, RuntimeEndpointId } from './endpoints.ts';
@@ -36,6 +32,21 @@ export interface CliServiceLogPosture {
36
32
  readonly readError?: string;
37
33
  }
38
34
 
35
+ export interface CliExternalDaemonLifecyclePosture {
36
+ readonly platform: 'manual';
37
+ readonly path: string;
38
+ readonly installed: false;
39
+ readonly autostart: false;
40
+ readonly running: false;
41
+ readonly logPath?: string;
42
+ readonly commandPreview: string;
43
+ readonly suggestedCommands: readonly string[];
44
+ readonly lastAction: 'status';
45
+ readonly actionError?: string;
46
+ readonly pidPath: string;
47
+ readonly lastError: null;
48
+ }
49
+
39
50
  export interface CliServicePosture {
40
51
  readonly config: {
41
52
  readonly enabled: boolean;
@@ -43,10 +54,7 @@ export interface CliServicePosture {
43
54
  readonly restartOnFailure: boolean;
44
55
  readonly daemonEnabled: boolean;
45
56
  };
46
- readonly managed: ManagedServiceStatus & {
47
- readonly pidPath: string;
48
- readonly lastError: string | null;
49
- };
57
+ readonly managed: CliExternalDaemonLifecyclePosture;
50
58
  readonly endpoints: readonly CliServiceEndpointPosture[];
51
59
  readonly log: CliServiceLogPosture;
52
60
  readonly issues: readonly string[];
@@ -58,46 +66,9 @@ const ENDPOINTS: readonly { readonly id: RuntimeEndpointId; readonly label: stri
58
66
  { id: 'web', label: 'web surface', enabledKey: 'web.enabled' },
59
67
  ];
60
68
 
61
- const SOURCE_PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..');
62
-
63
- export interface DaemonExecutableResolutionOptions {
64
- readonly env?: NodeJS.ProcessEnv;
65
- readonly argv?: readonly string[];
66
- readonly execPath?: string;
67
- readonly packageRoot?: string;
68
- }
69
-
70
- export interface DaemonExecutableResolution {
71
- readonly command: string;
72
- readonly source: 'env' | 'sibling' | 'package' | 'path' | 'fallback';
73
- readonly absolute: boolean;
74
- }
75
-
76
- interface ServiceDefinitionOverride {
77
- readonly name: string;
78
- readonly description: string;
79
- readonly workingDirectory: string;
80
- readonly command: string;
81
- readonly args: readonly string[];
82
- readonly env: Readonly<Record<string, string>>;
83
- readonly restartOnFailure: boolean;
84
- }
85
-
86
- interface CliServiceStatusCommandResult {
87
- readonly status: number | null;
88
- readonly stdout?: string;
89
- readonly stderr?: string;
90
- }
91
-
92
- interface CliServiceStatusManager {
93
- status(): ManagedServiceStatus;
94
- }
95
-
96
69
  interface CliServicePostureOptions {
97
70
  readonly probe?: boolean;
98
71
  readonly logTailBytes?: number;
99
- readonly manager?: CliServiceStatusManager;
100
- readonly runCommand?: (command: string, args: readonly string[]) => CliServiceStatusCommandResult;
101
72
  }
102
73
 
103
74
  function connectHostForBindHost(host: string): string {
@@ -120,183 +91,6 @@ async function probeTcp(host: string, port: number, timeoutMs = 750): Promise<bo
120
91
  });
121
92
  }
122
93
 
123
- function isExecutable(path: string): boolean {
124
- try {
125
- accessSync(path, constants.X_OK);
126
- return true;
127
- } catch {
128
- return false;
129
- }
130
- }
131
-
132
- function platformDaemonArtifactName(platform = process.platform, arch = process.arch): string {
133
- if (platform === 'linux' && arch === 'x64') return 'goodvibes-daemon-linux-x64';
134
- if (platform === 'linux' && arch === 'arm64') return 'goodvibes-daemon-linux-arm64';
135
- if (platform === 'darwin' && arch === 'x64') return 'goodvibes-daemon-macos-x64';
136
- if (platform === 'darwin' && arch === 'arm64') return 'goodvibes-daemon-macos-arm64';
137
- if (platform === 'win32') return 'goodvibes-daemon-windows.exe';
138
- return 'goodvibes-daemon';
139
- }
140
-
141
- function executablePathCandidates(path: string): string[] {
142
- if (!path.trim() || !isAbsolute(path)) return [];
143
- const dir = dirname(path);
144
- const name = basename(path);
145
- const artifact = platformDaemonArtifactName();
146
- const candidates = [
147
- join(dir, 'goodvibes-daemon'),
148
- join(dir, artifact),
149
- ];
150
- if (name.startsWith('goodvibes-') && !name.startsWith('goodvibes-daemon-')) {
151
- candidates.push(join(dir, name.replace(/^goodvibes-/, 'goodvibes-daemon-')));
152
- }
153
- if (name === 'goodvibes') candidates.push(join(dir, 'goodvibes-daemon'));
154
- return [...new Set(candidates)];
155
- }
156
-
157
- function resolveCommandFromPath(command: string, pathValue: string | undefined): string | null {
158
- const pathEntries = (pathValue ?? '').split(delimiter).filter(Boolean);
159
- const extensions = process.platform === 'win32'
160
- ? (process.env.PATHEXT ?? '.EXE;.CMD;.BAT;.COM').split(';').filter(Boolean)
161
- : [''];
162
- for (const entry of pathEntries) {
163
- for (const extension of extensions) {
164
- const candidate = join(entry, `${command}${extension}`);
165
- if (isExecutable(candidate)) return candidate;
166
- }
167
- }
168
- return null;
169
- }
170
-
171
- function firstExecutable(paths: readonly string[]): string | null {
172
- for (const path of paths) {
173
- if (isExecutable(path)) return path;
174
- }
175
- return null;
176
- }
177
-
178
- function packageArtifactForBinWrapper(path: string): string | null {
179
- let realPath = path;
180
- try {
181
- realPath = realpathSync(path);
182
- } catch {
183
- // Keep the original path if resolving a symlink fails.
184
- }
185
- if (basename(realPath) !== 'goodvibes-daemon') return null;
186
- const binDir = dirname(realPath);
187
- if (basename(binDir) !== 'bin') return null;
188
- const packageRoot = dirname(binDir);
189
- return firstExecutable([
190
- join(packageRoot, 'vendor', platformDaemonArtifactName()),
191
- join(packageRoot, 'dist', platformDaemonArtifactName()),
192
- join(packageRoot, 'dist', 'goodvibes-daemon'),
193
- ]);
194
- }
195
-
196
- export function resolveGoodVibesDaemonExecutable(
197
- options: DaemonExecutableResolutionOptions = {},
198
- ): DaemonExecutableResolution {
199
- const env = options.env ?? process.env;
200
- const override = env.GOODVIBES_DAEMON_COMMAND?.trim();
201
- if (override) {
202
- return { command: override, source: 'env', absolute: isAbsolute(override) };
203
- }
204
-
205
- const packageRoot = options.packageRoot ?? SOURCE_PACKAGE_ROOT;
206
- const packaged = firstExecutable([
207
- join(packageRoot, 'dist', platformDaemonArtifactName()),
208
- join(packageRoot, 'dist', 'goodvibes-daemon'),
209
- join(packageRoot, 'vendor', platformDaemonArtifactName()),
210
- join(packageRoot, 'bin', 'goodvibes-daemon'),
211
- ]);
212
- if (packaged) return { command: packaged, source: 'package', absolute: true };
213
-
214
- const argv = options.argv ?? process.argv;
215
- const execPath = options.execPath ?? process.execPath;
216
- const sibling = firstExecutable([
217
- ...executablePathCandidates(execPath),
218
- ...executablePathCandidates(argv[1] ?? ''),
219
- ]);
220
- if (sibling) {
221
- return {
222
- command: packageArtifactForBinWrapper(sibling) ?? sibling,
223
- source: 'sibling',
224
- absolute: true,
225
- };
226
- }
227
-
228
- const pathResolved = resolveCommandFromPath('goodvibes-daemon', env.PATH);
229
- if (pathResolved) {
230
- return {
231
- command: packageArtifactForBinWrapper(pathResolved) ?? pathResolved,
232
- source: 'path',
233
- absolute: true,
234
- };
235
- }
236
-
237
- return { command: 'goodvibes-daemon', source: 'fallback', absolute: false };
238
- }
239
-
240
- export function getServiceStateRoot(runtime: CliServiceRuntime): string {
241
- return join(runtime.homeDirectory, '.goodvibes', 'daemon');
242
- }
243
-
244
- function pidFilePath(runtime: CliServiceRuntime, platform: ManagedServiceStatus['platform']): string {
245
- return join(getServiceStateRoot(runtime), 'service', `${platform}.pid`);
246
- }
247
-
248
- function runStatusCommand(
249
- command: string,
250
- args: readonly string[],
251
- options: CliServicePostureOptions,
252
- ): CliServiceStatusCommandResult {
253
- if (options.runCommand) return options.runCommand(command, args);
254
- return spawnSync(command, [...args], {
255
- stdio: 'pipe',
256
- encoding: 'utf-8',
257
- timeout: 1500,
258
- });
259
- }
260
-
261
- function parseSystemdShowValue(lines: readonly string[], key: string): string | null {
262
- const prefix = `${key}=`;
263
- const match = lines.find((line) => line.startsWith(prefix));
264
- return match ? match.slice(prefix.length).trim() : null;
265
- }
266
-
267
- function reconcileSystemdServiceStatus(
268
- runtime: CliServiceRuntime,
269
- status: ManagedServiceStatus,
270
- options: CliServicePostureOptions,
271
- ): ManagedServiceStatus {
272
- if (status.platform !== 'systemd') return status;
273
-
274
- const name = String(runtime.configManager.get('service.serviceName') ?? 'goodvibes').trim() || 'goodvibes';
275
- const result = runStatusCommand('systemctl', [
276
- '--user',
277
- 'show',
278
- `${name}.service`,
279
- '--property=LoadState,ActiveState,UnitFileState,MainPID',
280
- '--no-page',
281
- ], options);
282
- if ((result.status ?? 1) !== 0) return status;
283
-
284
- const lines = (result.stdout ?? '').split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
285
- const loadState = parseSystemdShowValue(lines, 'LoadState');
286
- const activeState = parseSystemdShowValue(lines, 'ActiveState');
287
- const unitFileState = parseSystemdShowValue(lines, 'UnitFileState');
288
- const rawPid = Number.parseInt(parseSystemdShowValue(lines, 'MainPID') ?? '', 10);
289
- const pid = Number.isFinite(rawPid) && rawPid > 0 ? rawPid : undefined;
290
-
291
- return {
292
- ...status,
293
- installed: loadState === 'loaded' || status.installed,
294
- autostart: unitFileState === 'enabled' || unitFileState === 'linked' || status.autostart,
295
- running: activeState === 'active',
296
- ...(pid === undefined ? {} : { pid }),
297
- };
298
- }
299
-
300
94
  function readLogPosture(path: string | undefined, tailBytes: number): CliServiceLogPosture {
301
95
  if (!path) return { path: null, exists: false, size: 0, modifiedAt: null };
302
96
  if (!existsSync(path)) return { path, exists: false, size: 0, modifiedAt: null };
@@ -338,41 +132,34 @@ function endpointsConflict(a: CliServiceEndpointPosture, b: CliServiceEndpointPo
338
132
  return hostA === hostB || hostA === '0.0.0.0' || hostB === '0.0.0.0' || hostA === '::' || hostB === '::';
339
133
  }
340
134
 
341
- export function createPlatformServiceManager(runtime: CliServiceRuntime): PlatformServiceManager {
342
- const daemonHomeDir = getServiceStateRoot(runtime);
343
- const serviceName = String(runtime.configManager.get('service.serviceName') ?? 'goodvibes').trim() || 'goodvibes';
344
- const daemonExecutable = resolveGoodVibesDaemonExecutable();
345
- const definition: ServiceDefinitionOverride = {
346
- name: serviceName,
347
- description: 'GoodVibes daemon, control-plane, listener, and web host',
348
- workingDirectory: daemonHomeDir,
349
- command: daemonExecutable.command,
350
- args: [],
351
- env: {
352
- // The daemon CLI treats this as the GoodVibes home root, not the daemon state directory.
353
- GOODVIBES_DAEMON_HOME: runtime.homeDirectory,
354
- GOODVIBES_DAEMON_TOKEN: process.env.GOODVIBES_DAEMON_TOKEN ?? '',
355
- GOODVIBES_HTTP_TOKEN: process.env.GOODVIBES_HTTP_TOKEN ?? '',
356
- NODE_ENV: process.env.NODE_ENV ?? 'production',
357
- },
358
- restartOnFailure: runtime.configManager.get('service.restartOnFailure') === true,
135
+ function resolveConfiguredLogPath(runtime: CliServiceRuntime): string | undefined {
136
+ const value = runtime.configManager.get('service.logPath');
137
+ if (typeof value !== 'string') return undefined;
138
+ const trimmed = value.trim();
139
+ if (!trimmed) return undefined;
140
+ return isAbsolute(trimmed) ? trimmed : join(runtime.homeDirectory, trimmed);
141
+ }
142
+
143
+ function createExternalDaemonLifecycle(logPath: string | undefined): CliExternalDaemonLifecyclePosture {
144
+ return {
145
+ platform: 'manual',
146
+ path: 'external daemon host',
147
+ installed: false,
148
+ autostart: false,
149
+ running: false,
150
+ ...(logPath ? { logPath } : {}),
151
+ commandPreview: 'managed outside goodvibes-agent',
152
+ suggestedCommands: [],
153
+ lastAction: 'status',
154
+ pidPath: 'external daemon host',
155
+ lastError: null,
359
156
  };
360
- return new PlatformServiceManager(runtime.configManager, {
361
- workingDirectory: runtime.homeDirectory,
362
- homeDirectory: runtime.homeDirectory,
363
- surfaceRoot: 'daemon',
364
- definitionOverride: definition,
365
- defaultServiceName: 'goodvibes',
366
- defaultServiceDescription: 'GoodVibes daemon, control-plane, listener, and web host',
367
- });
368
157
  }
369
158
 
370
159
  export async function buildCliServicePosture(
371
160
  runtime: CliServiceRuntime,
372
161
  options: CliServicePostureOptions = {},
373
162
  ): Promise<CliServicePosture> {
374
- const manager = options.manager ?? createPlatformServiceManager(runtime);
375
- const status = reconcileSystemdServiceStatus(runtime, manager.status(), options);
376
163
  const endpoints = await Promise.all(ENDPOINTS.map(async (endpoint): Promise<CliServiceEndpointPosture> => {
377
164
  const enabled = runtime.configManager.get(endpoint.enabledKey as never) === true;
378
165
  const binding = resolveRuntimeEndpointBinding(runtime.configManager, endpoint.id);
@@ -405,15 +192,6 @@ export async function buildCliServicePosture(
405
192
  if (config.enabled && !config.restartOnFailure) {
406
193
  issues.push('External daemon service config has restart-on-failure off.');
407
194
  }
408
- if (config.enabled && !status.installed) {
409
- issues.push('External daemon service config is enabled, but no platform service definition is installed.');
410
- }
411
- if (config.enabled && !status.running) {
412
- issues.push('External daemon service config is enabled, but the managed service is not running.');
413
- }
414
- if (status.actionError) {
415
- issues.push(`Service manager reported an error: ${status.actionError}`);
416
- }
417
195
  for (const endpoint of endpoints) {
418
196
  if (endpoint.enabled && options.probe && endpoint.reachable === false) {
419
197
  issues.push(`${endpoint.label} is enabled but not reachable on ${endpoint.binding.host}:${endpoint.binding.port}.`);
@@ -429,18 +207,15 @@ export async function buildCliServicePosture(
429
207
  }
430
208
  }
431
209
  }
432
- const log = readLogPosture(status.logPath, options.logTailBytes ?? 4096);
210
+ const configuredLogPath = resolveConfiguredLogPath(runtime);
211
+ const log = readLogPosture(configuredLogPath, options.logTailBytes ?? 4096);
433
212
  if (log.readError) {
434
213
  issues.push(`Service log exists but could not be read: ${log.readError}`);
435
214
  }
436
215
 
437
216
  return {
438
217
  config,
439
- managed: {
440
- ...status,
441
- pidPath: pidFilePath(runtime, status.platform),
442
- lastError: status.actionError ?? null,
443
- },
218
+ managed: createExternalDaemonLifecycle(configuredLogPath),
444
219
  endpoints,
445
220
  log,
446
221
  issues,
@@ -454,22 +229,14 @@ function yesNo(value: boolean): string {
454
229
  export function formatCliServicePosture(posture: CliServicePosture, json = false): string {
455
230
  if (json) return JSON.stringify(posture, null, 2);
456
231
  return [
457
- 'GoodVibes external daemon service',
458
- ` enabled: ${yesNo(posture.config.enabled)}`,
459
- ` autostart: ${yesNo(posture.config.autostart)}`,
460
- ` restartOnFailure: ${yesNo(posture.config.restartOnFailure)}`,
232
+ 'GoodVibes external daemon diagnostics',
233
+ ' lifecycle: managed outside goodvibes-agent',
234
+ ` service config enabled: ${yesNo(posture.config.enabled)}`,
235
+ ` autostart config: ${yesNo(posture.config.autostart)}`,
236
+ ` restartOnFailure config: ${yesNo(posture.config.restartOnFailure)}`,
461
237
  ` daemon flag: ${yesNo(posture.config.daemonEnabled)}`,
462
- '',
463
- 'Managed service:',
464
- ` platform: ${posture.managed.platform}`,
465
- ` installed: ${yesNo(posture.managed.installed)}`,
466
- ` running: ${yesNo(posture.managed.running)}`,
467
- ` pid: ${posture.managed.pid ?? 'n/a'}`,
468
- ` definition: ${posture.managed.path}`,
469
- ` pid file: ${posture.managed.pidPath}`,
470
238
  ` log: ${posture.log.path ?? 'n/a'} (${posture.log.exists ? 'present' : 'missing'})`,
471
239
  ...(posture.log.readError ? [` log read error: ${posture.log.readError}`] : []),
472
- ` command: ${posture.managed.commandPreview}`,
473
240
  '',
474
241
  'Endpoints:',
475
242
  ...posture.endpoints.map((endpoint) =>
package/src/cli/status.ts CHANGED
@@ -334,7 +334,6 @@ export function renderCliStatus(options: CliStatusOptions): string {
334
334
  ` platform: ${options.service.managed.platform}`,
335
335
  ` installed: ${yesNo(options.service.managed.installed)}`,
336
336
  ` running: ${yesNo(options.service.managed.running)}`,
337
- ` pid: ${options.service.managed.pid ?? 'n/a'}`,
338
337
  ` definition: ${options.service.managed.path}`,
339
338
  ` log: ${options.service.log.path ?? 'n/a'} (${options.service.log.exists ? 'present' : 'missing'})`,
340
339
  ] : []),
@@ -9,8 +9,6 @@ export const SECRET_CONFIG_KEYS = new Set<ConfigKey>([
9
9
  'surfaces.discord.botToken',
10
10
  'surfaces.ntfy.token',
11
11
  'surfaces.webhook.secret',
12
- 'surfaces.homeassistant.accessToken',
13
- 'surfaces.homeassistant.webhookSecret',
14
12
  'surfaces.telegram.botToken',
15
13
  'surfaces.telegram.webhookSecret',
16
14
  'surfaces.googleChat.verificationToken',