@pellux/goodvibes-agent 0.1.80 → 0.1.82

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.
@@ -8,7 +8,6 @@ import { getSettingsControlPlaneSnapshot } from '@/runtime/index.ts';
8
8
  import { checkRecoveryFile, readLastSessionPointer } from '@/runtime/index.ts';
9
9
  import {
10
10
  openCommandPanel,
11
- requireLocalUserAuthManager,
12
11
  requireOperatorClient,
13
12
  requireProviderApi,
14
13
  requireReadModels,
@@ -78,12 +77,13 @@ export function registerHealthRuntimeCommands(registry: CommandRegistry): void {
78
77
  if (sub === 'auth') {
79
78
  const auth = readModels.localAuth.getSnapshot();
80
79
  ctx.print([
81
- 'Health Review: Local Auth',
82
- ` users: ${auth.userCount}`,
83
- ` sessions: ${auth.sessionCount}`,
84
- ` bootstrap file: ${auth.bootstrapCredentialPresent ? 'present' : 'cleared'}`,
85
- ...(auth.userCount <= 1 ? [' issue: only one local auth user configured'] : []),
86
- ...(auth.bootstrapCredentialPresent ? [' issue: bootstrap credential file still present; rotate or clear it when no longer needed'] : []),
80
+ 'Health Review: Runtime Auth',
81
+ ' owner: external GoodVibes runtime host',
82
+ ` compatibility users visible: ${auth.userCount}`,
83
+ ` compatibility sessions visible: ${auth.sessionCount}`,
84
+ ` bootstrap file signal: ${auth.bootstrapCredentialPresent ? 'present' : 'cleared'}`,
85
+ ' Agent action: review provider/subscription auth only; do not mutate runtime auth users or bootstrap credentials.',
86
+ ...(auth.bootstrapCredentialPresent ? [' issue: bootstrap cleanup belongs to the runtime-owning TUI or host tooling'] : []),
87
87
  ].join('\n'));
88
88
  return;
89
89
  }
@@ -222,13 +222,11 @@ export function registerHealthRuntimeCommands(registry: CommandRegistry): void {
222
222
  ));
223
223
  lines.push(' verify: /health settings');
224
224
  } else if (domain === 'auth') {
225
- const auth = requireLocalUserAuthManager(ctx).inspect();
226
225
  lines.push(' domain: auth');
227
- lines.push(...(
228
- auth.bootstrapCredentialPresent
229
- ? [' /auth local review', ' /auth local rotate-password admin <password> --yes', ' /auth local clear-bootstrap-file --yes']
230
- : [' /auth local review']
231
- ));
226
+ lines.push(' /auth review');
227
+ lines.push(' /providers');
228
+ lines.push(' /subscription providers');
229
+ lines.push(' runtime auth users/bootstrap cleanup: use the runtime-owning GoodVibes TUI or host tooling');
232
230
  lines.push(' verify: /health auth');
233
231
  } else if (domain === 'accounts') {
234
232
  lines.push(' domain: accounts');
@@ -316,7 +314,7 @@ export function registerHealthRuntimeCommands(registry: CommandRegistry): void {
316
314
  ` account issues: ${accountSnapshot.issueCount}`,
317
315
  ` settings conflicts: ${settingsSnapshot.conflicts.length}`,
318
316
  ` managed locks: ${settingsSnapshot.managedLockCount}`,
319
- ` local auth users: ${readModels.localAuth.getSnapshot().userCount}`,
317
+ ` runtime auth owner: external`,
320
318
  ` remote workers: ${snapshot.remoteRunnerCount}`,
321
319
  ...formatSessionMaintenanceLines(maintenance, 'guided').map((line) => ` ${line}`),
322
320
  ...(snapshot.issues.length > 0 ? ['', ...snapshot.issues.map((issue) => ` [${issue.severity.toUpperCase()}] ${issue.area}: ${issue.message}`)] : []),
@@ -2,7 +2,6 @@ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
2
  import { dirname } from 'node:path';
3
3
  import type { CommandRegistry } from '../command-registry.ts';
4
4
  import { listBuiltinSubscriptionProviders } from '@pellux/goodvibes-sdk/platform/config';
5
- import { handleLocalAuthCommand } from './local-auth-runtime.ts';
6
5
  import { buildAuthInspectionSnapshot, inspectProviderAuth } from '@/runtime/index.ts';
7
6
  import { requireSecretsManager, requireServiceRegistry, requireShellPaths, requireSubscriptionManager } from './runtime-services.ts';
8
7
  import { requireYesFlag, stripYesFlag } from './confirmation.ts';
@@ -113,7 +112,7 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
113
112
  registry.register({
114
113
  name: 'auth',
115
114
  description: 'Review auth posture and exchange session login tokens with local services',
116
- usage: '[review|show <provider>|repair <provider>|bundle export <path> --yes|bundle inspect <path>|login <runtime|listener> <baseUrl> <username> <password> [secretKey] --yes|local <review|panel|add-user --yes|delete-user --yes|rotate-password --yes|revoke-session --yes|clear-bootstrap-file --yes>]',
115
+ usage: '[review|show <provider>|repair <provider>|bundle export <path> --yes|bundle inspect <path>|login <runtime|listener> <baseUrl> <username> <password> [secretKey] --yes]',
117
116
  async handler(args, ctx) {
118
117
  const parsed = stripYesFlag(args);
119
118
  const commandArgs = [...parsed.rest];
@@ -123,7 +122,12 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
123
122
  const serviceRegistry = requireServiceRegistry(ctx);
124
123
  const secretsManager = requireSecretsManager(ctx);
125
124
  if (sub === 'local') {
126
- handleLocalAuthCommand(args.slice(1), ctx);
125
+ ctx.print([
126
+ 'Local runtime auth management is external to GoodVibes Agent.',
127
+ 'Agent connects to an already-running GoodVibes runtime and does not create, delete, rotate, revoke, or clear runtime auth users, sessions, or bootstrap credentials.',
128
+ 'Use the runtime-owning GoodVibes TUI or host tooling for runtime auth administration.',
129
+ 'Agent auth commands available here: /auth review, /auth show <provider>, /auth repair <provider>, /auth login <runtime|listener> ... --yes.',
130
+ ].join('\n'));
127
131
  return;
128
132
  }
129
133
  if (sub === 'review') {
@@ -270,7 +274,7 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
270
274
  return;
271
275
  }
272
276
 
273
- ctx.print('Usage: /auth [review|show <provider>|bundle export <path> --yes|bundle inspect <path>|login <runtime|listener> <baseUrl> <username> <password> [secretKey] --yes|local <review|panel|add-user --yes|delete-user --yes|rotate-password --yes|revoke-session --yes|clear-bootstrap-file --yes>]');
277
+ ctx.print('Usage: /auth [review|show <provider>|bundle export <path> --yes|bundle inspect <path>|login <runtime|listener> <baseUrl> <username> <password> [secretKey] --yes]');
274
278
  },
275
279
  });
276
280
  }
@@ -23,7 +23,6 @@ import { registerTasksRuntimeCommands } from './commands/tasks-runtime.ts';
23
23
  import { registerLocalProviderRuntimeCommands } from './commands/local-provider-runtime.ts';
24
24
  import { registerHealthRuntimeCommands } from './commands/health-runtime.ts';
25
25
  import { registerProviderAccountsRuntimeCommands } from './commands/provider-accounts-runtime.ts';
26
- import { registerLocalAuthRuntimeCommands } from './commands/local-auth-runtime.ts';
27
26
  import { registerConversationRuntimeCommands } from './commands/conversation-runtime.ts';
28
27
  import { registerQrcodeRuntimeCommands } from './commands/qrcode-runtime.ts';
29
28
  import { registerOnboardingRuntimeCommands } from './commands/onboarding-runtime.ts';
@@ -62,7 +61,6 @@ export function registerBuiltinCommands(registry: CommandRegistry): void {
62
61
  registerLocalProviderRuntimeCommands(registry);
63
62
  registerHealthRuntimeCommands(registry);
64
63
  registerProviderAccountsRuntimeCommands(registry);
65
- registerLocalAuthRuntimeCommands(registry);
66
64
  registerConversationRuntimeCommands(registry);
67
65
  registerQrcodeRuntimeCommands(registry);
68
66
  registerOnboardingRuntimeCommands(registry);
@@ -49,7 +49,7 @@ export function buildDefaultDerivedState(): OnboardingStepDerivationState {
49
49
  required: false,
50
50
  accepted: false,
51
51
  reason: 'not-needed',
52
- detail: 'No local auth state needs confirmation.',
52
+ detail: 'No external runtime auth signal needs confirmation.',
53
53
  },
54
54
  },
55
55
  };
@@ -2,7 +2,6 @@ import type { PanelManager } from '../panel-manager.ts';
2
2
  import { ApprovalPanel } from '../approval-panel.ts';
3
3
  import { AutomationControlPanel } from '../automation-control-panel.ts';
4
4
  import { SubscriptionPanel } from '../subscription-panel.ts';
5
- import { LocalAuthPanel } from '../local-auth-panel.ts';
6
5
  import { ProviderAccountsPanel } from '../provider-accounts-panel.ts';
7
6
  import { SecurityPanel } from '../security-panel.ts';
8
7
  import { TasksPanel } from '../tasks-panel.ts';
@@ -59,15 +58,6 @@ export function registerOperationsPanels(manager: PanelManager, deps: ResolvedBu
59
58
  factory: () => new SubscriptionPanel(deps.serviceRegistry, deps.subscriptionManager),
60
59
  });
61
60
 
62
- manager.registerType({
63
- id: 'local-auth',
64
- name: 'Local Auth',
65
- icon: 'U',
66
- category: 'monitoring',
67
- description: 'Local runtime auth users, bootstrap posture, and active sessions',
68
- factory: () => new LocalAuthPanel(deps.localUserAuthManager),
69
- });
70
-
71
61
  manager.registerType({
72
62
  id: 'accounts',
73
63
  name: 'Accounts',
@@ -44,18 +44,19 @@ export function buildProviderHealthDomainSummaries(
44
44
 
45
45
  summaries.push({
46
46
  name: 'auth',
47
- level: auth.bootstrapCredentialPresent || auth.userCount <= 1 ? 'warn' : 'good',
47
+ level: auth.bootstrapCredentialPresent ? 'warn' : 'info',
48
48
  summary: auth.bootstrapCredentialPresent
49
- ? 'bootstrap credential file still present'
50
- : `${auth.userCount} users / ${auth.sessionCount} sessions`,
51
- next: auth.bootstrapCredentialPresent ? '/auth local clear-bootstrap-file --yes' : '/auth local review',
49
+ ? 'external runtime bootstrap credential visible in local compatibility state'
50
+ : 'runtime auth administration belongs to the external runtime owner',
51
+ next: '/auth review',
52
52
  details: [
53
- auth.bootstrapCredentialPresent ? 'bootstrap credential file should be cleared after rotation' : `${auth.userCount} local auth users configured`,
54
- auth.userCount <= 1 ? 'only one local auth user configured' : `${auth.sessionCount} active local auth sessions`,
53
+ 'GoodVibes Agent does not create, delete, rotate, revoke, or clear runtime auth users or sessions.',
54
+ `${auth.userCount} compatibility user record(s) and ${auth.sessionCount} session record(s) are visible for diagnostics only.`,
55
+ auth.bootstrapCredentialPresent ? 'Runtime bootstrap cleanup must be done from the runtime-owning TUI or host tooling.' : '',
55
56
  ].filter(Boolean),
56
57
  nextSteps: auth.bootstrapCredentialPresent
57
- ? ['/auth local review', '/auth local rotate-password <user> <password> --yes', '/auth local clear-bootstrap-file --yes']
58
- : ['/auth local review'],
58
+ ? ['/auth review', '/providers', '/subscription providers']
59
+ : ['/auth review', '/providers'],
59
60
  });
60
61
 
61
62
  const settingIssueCount = settings.conflictCount + settings.recentFailureCount + (settings.hasStagedManagedBundle ? 1 : 0);
@@ -196,10 +196,10 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
196
196
  base.push(
197
197
  { text: `GoodVibes runtime: ${snapshot.daemonBaseUrl}`, fg: PALETTE.info },
198
198
  { text: `Runtime owner: ${snapshot.daemonOwnership}; Agent connects but never starts or restarts it`, fg: PALETTE.good },
199
+ ...setupChecklistLines(snapshot),
200
+ { text: '' },
199
201
  { text: `Workspace: ${snapshot.workingDirectory}`, fg: PALETTE.muted },
200
202
  { text: `Home: ${snapshot.homeDirectory}`, fg: PALETTE.muted },
201
- { text: '' },
202
- ...setupChecklistLines(snapshot),
203
203
  );
204
204
  } else if (category.id === 'channels') {
205
205
  const enabledCount = snapshot.channels.filter((channel) => channel.enabled).length;
@@ -283,10 +283,11 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
283
283
  base.push(
284
284
  { text: `Active Agent profile: ${snapshot.activeRuntimeProfile}`, fg: PALETTE.info },
285
285
  { text: `Agent profiles under this home: ${snapshot.runtimeProfileCount}`, fg: PALETTE.info },
286
- { text: `Agent profile root: ${snapshot.runtimeProfileRoot}`, fg: PALETTE.muted },
287
286
  { text: `Starter templates: ${snapshot.runtimeStarterTemplateCount}; local custom: ${snapshot.localStarterTemplateCount}`, fg: PALETTE.info },
288
287
  { text: `Config profiles: ${snapshot.configProfileCount}`, fg: PALETTE.info },
289
288
  { text: `Starter ids: ${snapshot.runtimeStarterTemplates.map((template) => template.id).join(', ') || 'none'}`, fg: PALETTE.info },
289
+ { text: 'Starter Templates', fg: PALETTE.title, bold: true },
290
+ { text: `Agent profile root: ${snapshot.runtimeProfileRoot}`, fg: PALETTE.muted },
290
291
  { text: '' },
291
292
  ...profileLines(snapshot),
292
293
  { text: '' },
@@ -301,7 +302,7 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
301
302
  base.push(
302
303
  { text: `Session memories: ${snapshot.sessionMemoryCount}`, fg: PALETTE.info },
303
304
  { text: `Local routines: ${snapshot.localRoutineCount}; enabled: ${snapshot.enabledRoutineCount}`, fg: PALETTE.info },
304
- { text: `Local skills: ${snapshot.localSkillCount}; enabled: ${snapshot.enabledSkillCount}`, fg: PALETTE.info },
305
+ { text: `Local skills: ${snapshot.localSkillCount}; enabled: ${snapshot.enabledSkillCount}; bundles: ${snapshot.localSkillBundleCount}; active skills: ${snapshot.activeSkillCount}`, fg: PALETTE.info },
305
306
  { text: `Local personas: ${snapshot.localPersonaCount}; active: ${snapshot.activePersonaName}`, fg: PALETTE.info },
306
307
  { text: 'Durable memory, routines, skills, and personas remain Agent-local until shared registry contracts exist.', fg: PALETTE.good },
307
308
  { text: 'Secrets are rejected/redacted; store secret references instead of secret values.', fg: PALETTE.warn },
@@ -316,11 +317,13 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
316
317
  );
317
318
  } else if (category.id === 'skills') {
318
319
  base.push(
319
- { text: `Skills: ${snapshot.localSkillCount}; enabled: ${snapshot.enabledSkillCount}`, fg: PALETTE.info },
320
+ { text: `Skills: ${snapshot.localSkillCount}; enabled: ${snapshot.enabledSkillCount}; bundles: ${snapshot.localSkillBundleCount}; enabled bundles: ${snapshot.enabledSkillBundleCount}; active skills: ${snapshot.activeSkillCount}`, fg: PALETTE.info },
320
321
  { text: 'Skills are reusable local procedures the assistant can apply from the main conversation.', fg: PALETTE.good },
321
- { text: 'Enabled skills are injected as operating guidance; secret-looking content is rejected.', fg: PALETTE.warn },
322
+ { text: 'Enabled skills and enabled bundles are injected as operating guidance; secret-looking content is rejected.', fg: PALETTE.warn },
322
323
  { text: '' },
323
324
  ...localLibraryLines('Skill Library', snapshot.localSkills, 'No local skills yet. Create one here with Create skill.', workspace.selectedLocalLibraryItem('skill')?.id ?? null),
325
+ { text: '' },
326
+ ...localLibraryLines('Skill Bundles', snapshot.localSkillBundles, 'No local skill bundles yet. Use Skill bundles and Create bundle after creating skills.', null),
324
327
  );
325
328
  } else if (category.id === 'routines') {
326
329
  base.push(
@@ -62,22 +62,6 @@ function setNestedValue(root: Record<string, unknown>, key: string, value: unkno
62
62
 
63
63
  type RollbackAction = () => Promise<void> | void;
64
64
 
65
- interface BootstrapCredential {
66
- readonly username: string;
67
- readonly password: string;
68
- }
69
-
70
- interface PersistedAuthUser {
71
- readonly username: string;
72
- readonly passwordHash: string;
73
- readonly roles?: readonly string[];
74
- }
75
-
76
- interface MutableAuthManager {
77
- readonly users?: Map<string, PersistedAuthUser>;
78
- readonly sessions?: Map<string, { readonly token: string; readonly username: string; readonly expiresAt: number }>;
79
- }
80
-
81
65
  function restoreFile(path: string, previous: string | null, reload?: () => void): void {
82
66
  if (previous === null) {
83
67
  if (existsSync(path)) unlinkSync(path);
@@ -88,31 +72,6 @@ function restoreFile(path: string, previous: string | null, reload?: () => void)
88
72
  reload?.();
89
73
  }
90
74
 
91
- function parseBootstrapCredential(content: string | null): BootstrapCredential | null {
92
- if (content === null) return null;
93
- let username = '';
94
- let password = '';
95
- for (const rawLine of content.split('\n')) {
96
- const line = rawLine.trim();
97
- if (line.startsWith('username=')) username = line.slice('username='.length);
98
- if (line.startsWith('password=')) password = line.slice('password='.length);
99
- }
100
- return username.length > 0 && password.length > 0 ? { username, password } : null;
101
- }
102
-
103
- function parsePersistedAuthUsers(content: string): readonly PersistedAuthUser[] {
104
- const parsed = JSON.parse(content) as unknown;
105
- if (!isPlainObject(parsed) || parsed.version !== 1 || !Array.isArray(parsed.users)) {
106
- throw new Error('Expected a version 1 local auth user store.');
107
- }
108
- return parsed.users.filter((user): user is PersistedAuthUser => (
109
- isPlainObject(user)
110
- && typeof user.username === 'string'
111
- && typeof user.passwordHash === 'string'
112
- && (user.roles === undefined || (Array.isArray(user.roles) && user.roles.every((role) => typeof role === 'string')))
113
- ));
114
- }
115
-
116
75
  function snapshotFileRollback(path: string, reload?: () => void): RollbackAction {
117
76
  const previous = existsSync(path) ? readFileSync(path, 'utf-8') : null;
118
77
  return () => restoreFile(path, previous, reload);
@@ -227,18 +186,10 @@ function validateSecretOperation(
227
186
  }
228
187
 
229
188
  function validateAuthOperation(
230
- deps: OnboardingApplyDependencies,
231
- operation: Extract<OnboardingApplyOperation, { kind: 'ensure-auth-user' }>,
189
+ _deps: OnboardingApplyDependencies,
190
+ _operation: Extract<OnboardingApplyOperation, { kind: 'ensure-auth-user' }>,
232
191
  ): void {
233
- if (!deps.auth) throw new Error('Local auth management is unavailable.');
234
- if (operation.username.trim().length === 0) throw new Error('Local auth username is required.');
235
- if (operation.password.length === 0) throw new Error(`Local auth password for ${operation.username} is required.`);
236
- const username = operation.username.trim();
237
- const existing = deps.auth.inspect().users.find((user) => user.username === username);
238
- const requiredRoles = operation.roles ?? ['admin'];
239
- if (existing && !requiredRoles.every((role) => existing.roles.includes(role))) {
240
- throw new Error(`Existing local auth user ${username} is missing required role(s): ${requiredRoles.join(', ')}.`);
241
- }
192
+ throw new Error('Runtime auth user/session administration is external to GoodVibes Agent onboarding.');
242
193
  }
243
194
 
244
195
  function validateAcknowledgementOperation(
@@ -313,44 +264,6 @@ async function applySecretOperation(
313
264
  };
314
265
  }
315
266
 
316
- function applyAuthOperation(
317
- deps: OnboardingApplyDependencies,
318
- operation: Extract<OnboardingApplyOperation, { kind: 'ensure-auth-user' }>,
319
- ): OnboardingAppliedOperation {
320
- validateAuthOperation(deps, operation);
321
- const auth = deps.auth!;
322
- const username = operation.username.trim();
323
- const before = auth.inspect();
324
- const existing = before.users.find((user) => user.username === username);
325
- const bootstrapCredential = before.bootstrapCredentialPresent
326
- ? parseBootstrapCredential(readFileSync(before.bootstrapCredentialPath, 'utf-8'))
327
- : null;
328
-
329
- if (existing) {
330
- auth.rotatePassword(username, operation.password);
331
- } else {
332
- auth.addUser(username, operation.password, operation.roles ?? ['admin']);
333
- }
334
-
335
- if (operation.retireBootstrapCredential) {
336
- if (bootstrapCredential && bootstrapCredential.username !== username && auth.getUser(bootstrapCredential.username)) {
337
- auth.deleteUser(bootstrapCredential.username);
338
- }
339
- auth.clearBootstrapCredentialFile();
340
- }
341
-
342
- if (operation.createSession ?? true) {
343
- auth.createSession(username);
344
- }
345
-
346
- return {
347
- kind: operation.kind,
348
- summary: existing
349
- ? `Updated local auth user ${username}.`
350
- : `Created local auth user ${username}.`,
351
- };
352
- }
353
-
354
267
  async function buildSecretRollbackAction(
355
268
  deps: OnboardingApplyDependencies,
356
269
  operation: Extract<OnboardingApplyOperation, { kind: 'set-secret' }>,
@@ -369,67 +282,6 @@ async function buildSecretRollbackAction(
369
282
  };
370
283
  }
371
284
 
372
- function buildAuthRollbackAction(
373
- deps: OnboardingApplyDependencies,
374
- operation: Extract<OnboardingApplyOperation, { kind: 'ensure-auth-user' }>,
375
- ): RollbackAction {
376
- validateAuthOperation(deps, operation);
377
- const auth = deps.auth!;
378
- const mutable = auth as unknown as MutableAuthManager;
379
- const username = operation.username.trim();
380
- const before = auth.inspect();
381
- const existingUser = before.users.find((user) => user.username === username);
382
- const existingSessionFingerprints = new Set(before.sessions
383
- .filter((session) => session.username === username)
384
- .map((session) => session.tokenFingerprint));
385
- const userStoreSnapshot = existsSync(before.userStorePath) ? readFileSync(before.userStorePath, 'utf-8') : null;
386
- const bootstrapCredentialSnapshot = existsSync(before.bootstrapCredentialPath)
387
- ? readFileSync(before.bootstrapCredentialPath, 'utf-8')
388
- : null;
389
- const bootstrapCredential = parseBootstrapCredential(bootstrapCredentialSnapshot);
390
- const beforeSessions = mutable.sessions instanceof Map
391
- ? [...mutable.sessions.entries()].map(([token, session]) => [token, { ...session }] as const)
392
- : [];
393
-
394
- return () => {
395
- for (const session of auth.inspect().sessions) {
396
- if (session.username === username && !existingSessionFingerprints.has(session.tokenFingerprint)) {
397
- auth.revokeSession(session.tokenFingerprint);
398
- }
399
- }
400
-
401
- if (bootstrapCredential && !auth.getUser(bootstrapCredential.username)) {
402
- auth.addUser(bootstrapCredential.username, bootstrapCredential.password, ['admin']);
403
- }
404
-
405
- if (!existingUser && auth.getUser(username)) {
406
- try {
407
- auth.deleteUser(username);
408
- } catch (error) {
409
- if (mutable.users instanceof Map) mutable.users.delete(username);
410
- else throw error;
411
- }
412
- }
413
-
414
- restoreFile(before.bootstrapCredentialPath, bootstrapCredentialSnapshot);
415
- restoreFile(before.userStorePath, userStoreSnapshot);
416
-
417
- if (mutable.users instanceof Map) {
418
- if (userStoreSnapshot === null) {
419
- if (before.users.length === 0) mutable.users.clear();
420
- } else {
421
- mutable.users.clear();
422
- for (const user of parsePersistedAuthUsers(userStoreSnapshot)) mutable.users.set(user.username, user);
423
- }
424
- }
425
-
426
- if (mutable.sessions instanceof Map) {
427
- mutable.sessions.clear();
428
- for (const [token, session] of beforeSessions) mutable.sessions.set(token, session);
429
- }
430
- };
431
- }
432
-
433
285
  async function buildRollbackAction(
434
286
  deps: OnboardingApplyDependencies,
435
287
  operation: OnboardingApplyOperation,
@@ -453,7 +305,8 @@ async function buildRollbackAction(
453
305
  }
454
306
 
455
307
  if (operation.kind === 'ensure-auth-user') {
456
- return buildAuthRollbackAction(deps, operation);
308
+ validateAuthOperation(deps, operation);
309
+ return () => {};
457
310
  }
458
311
 
459
312
  if (operation.kind === 'acknowledge') {
@@ -633,8 +486,7 @@ export async function applyOnboardingRequest(
633
486
  }
634
487
 
635
488
  if (operation.kind === 'ensure-auth-user') {
636
- applied.push(applyAuthOperation(deps, operation));
637
- rollbacks.push(rollback);
489
+ validateAuthOperation(deps, operation);
638
490
  continue;
639
491
  }
640
492
 
@@ -500,23 +500,23 @@ export function deriveReopenEditAcknowledgementState(
500
500
  snapshot,
501
501
  'auth',
502
502
  'bootstrap-credential',
503
- 'The local auth bootstrap credential file is still present.',
503
+ 'An external runtime bootstrap credential signal is still visible to Agent.',
504
504
  )
505
505
  : authSessionCount > 0
506
506
  ? buildRequiredAcknowledgement(
507
507
  snapshot,
508
508
  'auth',
509
509
  'active-sessions',
510
- `${authSessionCount} local auth session(s) are currently active.`,
510
+ `${authSessionCount} external runtime auth session signal(s) are currently visible.`,
511
511
  )
512
512
  : authUserCount > 0
513
513
  ? buildRequiredAcknowledgement(
514
514
  snapshot,
515
515
  'auth',
516
516
  'auth-state',
517
- `${authUserCount} local auth user(s) are already configured.`,
517
+ `${authUserCount} external runtime auth user signal(s) are already visible.`,
518
518
  )
519
- : buildNotNeededAcknowledgement(snapshot, 'auth', 'No local auth state needs confirmation.');
519
+ : buildNotNeededAcknowledgement(snapshot, 'auth', 'No external runtime auth signal needs confirmation.');
520
520
 
521
521
  return {
522
522
  providers,
@@ -383,17 +383,7 @@ export interface OnboardingApplyDependencies {
383
383
  readonly clock?: () => number;
384
384
  readonly config: Pick<ConfigManager, 'get' | 'getRaw' | 'load' | 'setDynamic'>;
385
385
  readonly secrets?: Pick<SecretsManager, 'delete' | 'get' | 'inspect' | 'set'>;
386
- readonly auth?: Pick<
387
- UserAuthManager,
388
- 'addUser'
389
- | 'clearBootstrapCredentialFile'
390
- | 'createSession'
391
- | 'deleteUser'
392
- | 'getUser'
393
- | 'inspect'
394
- | 'revokeSession'
395
- | 'rotatePassword'
396
- >;
386
+ readonly auth?: Pick<UserAuthManager, 'inspect'>;
397
387
  readonly shellPaths: OnboardingShellPaths;
398
388
  readonly acknowledgementScope?: OnboardingStateScope;
399
389
  }
@@ -116,36 +116,14 @@ async function verifySecretOperation(
116
116
  }
117
117
 
118
118
  function verifyAuthOperation(
119
- deps: OnboardingVerificationDependencies,
119
+ _deps: OnboardingVerificationDependencies,
120
120
  operation: Extract<OnboardingApplyOperation, { kind: 'ensure-auth-user' }>,
121
121
  ): OnboardingVerificationItem {
122
- if (!deps.auth) {
123
- return {
124
- id: `auth:${operation.username}`,
125
- status: 'fail',
126
- message: 'Local auth manager is unavailable.',
127
- target: operation.username,
128
- };
129
- }
130
-
131
- const snapshot = deps.auth.inspect();
132
122
  const username = operation.username.trim();
133
- const user = snapshot.users.find((entry) => entry.username === username);
134
- const requiredRoles = operation.roles ?? ['admin'];
135
- const userExists = Boolean(user) && requiredRoles.every((role) => user!.roles.includes(role));
136
- const sessionExists = operation.createSession === false
137
- ? true
138
- : snapshot.sessions.some((session) => session.username === username);
139
- const bootstrapRetired = operation.retireBootstrapCredential
140
- ? snapshot.bootstrapCredentialPresent === false
141
- : true;
142
- const ok = userExists && sessionExists && bootstrapRetired;
143
123
  return {
144
124
  id: `auth:${username}`,
145
- status: ok ? 'pass' : 'fail',
146
- message: ok
147
- ? `${username} local auth user has required role(s) and session state.`
148
- : `${username} local auth user/session/role/bootstrap state was not created.`,
125
+ status: 'fail',
126
+ message: 'Runtime auth user/session administration is external to GoodVibes Agent onboarding.',
149
127
  target: username,
150
128
  };
151
129
  }
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.80';
9
+ let _version = '0.1.82';
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 {