@pellux/goodvibes-agent 1.5.6 → 1.5.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pellux/goodvibes-agent",
3
- "version": "1.5.6",
3
+ "version": "1.5.7",
4
4
  "private": false,
5
5
  "description": "GoodVibes personal operator assistant TUI with a proactive Agent product brain, isolated Agent Knowledge, local profiles, routines, skills, personas, and explicit build delegation.",
6
6
  "type": "module",
@@ -9,7 +9,7 @@ import { AgentPersonaRegistry, buildActivePersonaPrompt } from './persona-regist
9
9
  import { buildProjectContextPrompt, discoverProjectContextFiles } from './project-context-files.ts';
10
10
  import { AgentRoutineRegistry, buildEnabledRoutinesPrompt, evaluateAgentRoutineReadiness } from './routine-registry.ts';
11
11
  import { AgentSkillRegistry, buildEnabledSkillsPrompt, evaluateAgentSkillBundleReadiness, evaluateAgentSkillReadiness } from './skill-registry.ts';
12
- import { buildVibePrompt, discoverVibeFiles } from './vibe-file.ts';
12
+ import { buildVibeProjectionPrompt, discoverVibeFiles } from './vibe-file.ts';
13
13
 
14
14
  export type PromptContextReceiptStatus = 'active' | 'attention' | 'empty' | 'unavailable';
15
15
  export type PromptContextReceiptSource = 'turn' | 'follow_up' | 'manual';
@@ -140,7 +140,9 @@ function receiptSegment(input: Omit<PromptContextReceiptSegment, 'approxTokens'>
140
140
 
141
141
  function buildRuntimePromptReceiptSegments(input: RuntimePromptCompositionInput): readonly PromptContextReceiptSegment[] {
142
142
  const vibe = discoverVibeFiles(input.shellPaths);
143
- const vibePrompt = buildVibePrompt(input.shellPaths) ?? '';
143
+ // W6-C2 (E6): the VIBE prompt is a PROJECTION of persona/constraint records, not a
144
+ // re-read of the files (discoverVibeFiles above stays for the file-discovery receipt).
145
+ const vibePrompt = buildVibeProjectionPrompt(input.memoryRegistry) ?? '';
144
146
  const projectContext = discoverProjectContextFiles(input.shellPaths);
145
147
  const projectContextPrompt = buildProjectContextPrompt(input.shellPaths) ?? '';
146
148
  const memoryRecords = input.memoryRegistry.getAll();
@@ -341,7 +343,7 @@ export function composeRuntimePromptWithReceipt(input: RuntimePromptCompositionI
341
343
  const supplement = getTierPromptSupplement(tier);
342
344
  const prompt = joinPromptParts(
343
345
  input.runtimePrompt,
344
- buildVibePrompt(input.shellPaths),
346
+ buildVibeProjectionPrompt(input.memoryRegistry),
345
347
  buildProjectContextPrompt(input.shellPaths),
346
348
  input.operatorPolicy,
347
349
  buildReviewedMemoryPrompt(input.memoryRegistry, { turnText: input.turnText }),
@@ -1,4 +1,5 @@
1
1
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { createHash } from 'node:crypto';
2
3
  import { dirname, isAbsolute, join, resolve } from 'node:path';
3
4
  import type { ShellPathService } from '@/runtime/index.ts';
4
5
  import { GOODVIBES_AGENT_SURFACE_ROOT } from '../config/surface.ts';
@@ -9,7 +10,7 @@ import { parseMarkdownFrontmatter, stripMarkdownFrontmatter } from './markdown-f
9
10
  // the same '## VIBE.md' block from those records (caveat preserved); the file is
10
11
  // demoted to an import/export FORMAT folded in via vibeBodyToConstraintOptions.
11
12
  import { renderVibeProjection, vibeBodyToConstraintOptions } from '@pellux/goodvibes-sdk/platform/state';
12
- import type { MemoryRegistry, MemoryScope } from '@pellux/goodvibes-sdk/platform/state';
13
+ import type { MemoryRecord, MemoryRegistry, MemoryScope } from '@pellux/goodvibes-sdk/platform/state';
13
14
 
14
15
  export type AgentVibeScope = 'project' | 'global';
15
16
 
@@ -220,8 +221,8 @@ export function buildVibePrompt(shellPaths: AgentVibePaths): string | null {
220
221
  * store, so persona instructions have a single source of truth alongside every other
221
222
  * durable fact. Returns null when there are no persona records to project.
222
223
  */
223
- export function buildVibeProjectionPrompt(memoryRegistry: MemoryRegistry): string | null {
224
- return renderVibeProjection(memoryRegistry.getAll());
224
+ export function buildVibeProjectionPrompt(memoryRecords: { getAll(): readonly MemoryRecord[] }): string | null {
225
+ return renderVibeProjection(memoryRecords.getAll());
225
226
  }
226
227
 
227
228
  /**
@@ -255,6 +256,86 @@ export async function importVibeFilesIntoMemory(
255
256
  return created;
256
257
  }
257
258
 
259
+ /**
260
+ * W6-C2 (E6): the persisted marker that makes the VIBE.md → memory import a strictly
261
+ * ONE-TIME migration. Keyed by absolute file path → content hash, so importing the same
262
+ * VIBE.md twice is a no-op (re-import would create near-duplicate persona records), while
263
+ * a NEW project's VIBE.md still migrates exactly once. Mirrors the sessions.spine-folded
264
+ * marker precedent (bootstrap.ts) — a small JSON sidecar, read before and written after.
265
+ */
266
+ interface VibeImportMarker {
267
+ readonly migrated: Record<string, string>;
268
+ }
269
+
270
+ function vibeImportMarkerPath(shellPaths: Pick<ShellPathService, 'resolveUserPath'>): string {
271
+ return shellPaths.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, 'vibe-import.migrated.json');
272
+ }
273
+
274
+ function readVibeImportMarker(path: string): VibeImportMarker {
275
+ if (!existsSync(path)) return { migrated: {} };
276
+ try {
277
+ const parsed = JSON.parse(readFileSync(path, 'utf-8')) as unknown;
278
+ const migrated = (parsed as { migrated?: unknown })?.migrated;
279
+ if (migrated && typeof migrated === 'object' && !Array.isArray(migrated)) {
280
+ const out: Record<string, string> = {};
281
+ for (const [key, value] of Object.entries(migrated as Record<string, unknown>)) {
282
+ if (typeof value === 'string') out[key] = value;
283
+ }
284
+ return { migrated: out };
285
+ }
286
+ } catch {
287
+ // Corrupt marker → treat as "nothing migrated"; the path+hash guard still prevents
288
+ // duplicating any record that was already imported in a prior clean run.
289
+ }
290
+ return { migrated: {} };
291
+ }
292
+
293
+ function writeVibeImportMarker(path: string, marker: VibeImportMarker): void {
294
+ mkdirSync(dirname(path), { recursive: true });
295
+ writeFileSync(path, `${JSON.stringify(marker, null, 2)}\n`, 'utf-8');
296
+ }
297
+
298
+ function hashVibeBody(body: string): string {
299
+ return createHash('sha256').update(body, 'utf-8').digest('hex');
300
+ }
301
+
302
+ /**
303
+ * W6-C2 (E6): fold discovered VIBE.md files into persona/constraint records ONCE.
304
+ * Guarded by a persisted path→hash marker so it never re-imports the same file (which
305
+ * would create near-duplicate persona records). Called at boot AFTER memoryStore.init().
306
+ * Returns the number of records created this run (0 when everything is already migrated).
307
+ */
308
+ export async function importVibeFilesIntoMemoryOnce(
309
+ memoryRegistry: MemoryRegistry,
310
+ shellPaths: AgentVibePaths,
311
+ ): Promise<number> {
312
+ const markerPath = vibeImportMarkerPath(shellPaths);
313
+ const marker = readVibeImportMarker(markerPath);
314
+ const snapshot = discoverVibeFiles(shellPaths);
315
+ let created = 0;
316
+ let changed = false;
317
+ for (const file of snapshot.files) {
318
+ const key = resolve(file.path);
319
+ const hash = hashVibeBody(file.body);
320
+ if (marker.migrated[key] === hash) continue; // already migrated this exact content
321
+ const scope: MemoryScope = file.scope === 'global' ? 'team' : 'project';
322
+ const name = file.frontmatter.name?.trim();
323
+ const options = vibeBodyToConstraintOptions(file.body, {
324
+ scope,
325
+ ...(name ? { name } : {}),
326
+ sourceRef: file.path,
327
+ });
328
+ for (const opts of options) {
329
+ await memoryRegistry.add(opts);
330
+ created += 1;
331
+ }
332
+ marker.migrated[key] = hash;
333
+ changed = true;
334
+ }
335
+ if (changed) writeVibeImportMarker(markerPath, marker);
336
+ return created;
337
+ }
338
+
258
339
  export function formatVibeStatus(snapshot: AgentVibeSnapshot): string {
259
340
  const lines: string[] = [
260
341
  'GoodVibes Agent VIBE.md',
@@ -0,0 +1,165 @@
1
+ /**
2
+ * credential-status.ts — client-side, secret-FREE credential STATUS read.
3
+ *
4
+ * W6-C1 (E7 config sharing). When GoodVibes Agent acts as a CLIENT of an adopted
5
+ * external daemon, it reads credential *status* (configured / usable) from the
6
+ * daemon's shared store over the wire — the `credentials.get` operator method
7
+ * (GET /config/credentials, admin + read:config). It NEVER receives raw secret
8
+ * bytes: the wire contract (CREDENTIALS_SNAPSHOT_SCHEMA) carries status metadata
9
+ * only. This is a VISIBILITY path, not secret transport.
10
+ *
11
+ * Host-vs-client (see the SDK decision record 2026-07-06-config-sharing): a surface
12
+ * that IS the daemon host reads its own local SecretsManager directly (no wire hop —
13
+ * src/config/secrets.ts). A surface acting as a daemon client reads STATUS here.
14
+ * Secret RESOLUTION (the value provider auth needs) always stays local/env; only the
15
+ * status read moves to the daemon path.
16
+ *
17
+ * The degrade contract mirrors goodvibes-webui v1.0.1 `deriveCredentialAvailability`
18
+ * exactly: a 503 CREDENTIAL_STORE_UNAVAILABLE (by machine code), a METHOD_NOT_FOUND
19
+ * from an older daemon, or any transport failure yields an honest reason-carrying
20
+ * `available: false` — NEVER a fabricated "configured", NEVER a surfaced secret byte.
21
+ */
22
+
23
+ /** One credential's status metadata from the daemon's shared store — never bytes. */
24
+ export interface CredentialStatusEntry {
25
+ readonly key: string;
26
+ readonly configured: boolean;
27
+ readonly usable: boolean;
28
+ readonly source?: string;
29
+ readonly scope?: string;
30
+ readonly secure?: boolean;
31
+ readonly overriddenByEnv?: boolean;
32
+ readonly refSource?: string;
33
+ }
34
+
35
+ export type CredentialAvailability =
36
+ | { readonly available: true; readonly credentials: readonly CredentialStatusEntry[] }
37
+ | { readonly available: false; readonly reason: string };
38
+
39
+ /** Minimal connection shape for the daemon-client status read. */
40
+ export interface CredentialStatusConnection {
41
+ readonly baseUrl: string;
42
+ readonly token: string | null;
43
+ }
44
+
45
+ type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
46
+
47
+ const CREDENTIALS_ROUTE = '/config/credentials';
48
+ const CREDENTIAL_STATUS_TIMEOUT_MS = 1500;
49
+
50
+ function asRecord(value: unknown): Record<string, unknown> | null {
51
+ return value && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : null;
52
+ }
53
+
54
+ function firstString(record: Record<string, unknown>, keys: readonly string[]): string {
55
+ for (const key of keys) {
56
+ const item = record[key];
57
+ if (typeof item === 'string' && item.trim()) return item;
58
+ }
59
+ return '';
60
+ }
61
+
62
+ /**
63
+ * Fold a `credentials.get` outcome into an honest availability value. Pure — this is
64
+ * the exact degrade contract mirrored from webui v1.0.1: keyed on the MACHINE CODE, it
65
+ * never fabricates "configured" and never carries a secret value. A malformed body (no
66
+ * credentials array) is treated as unavailable, not silently empty-but-configured.
67
+ */
68
+ export function deriveCredentialAvailability(
69
+ outcome: { ok: true; value: unknown } | { ok: false; error: unknown },
70
+ ): CredentialAvailability {
71
+ if (!outcome.ok) {
72
+ const err = asRecord(outcome.error);
73
+ const code = err ? firstString(err, ['code']) : '';
74
+ if (code === 'CREDENTIAL_STORE_UNAVAILABLE') {
75
+ return { available: false, reason: 'The daemon has no shared credential store wired.' };
76
+ }
77
+ if (code === 'METHOD_NOT_FOUND' || code === 'NOT_INVOKABLE') {
78
+ return { available: false, reason: 'This daemon does not serve credential status yet.' };
79
+ }
80
+ return { available: false, reason: 'Credential status unavailable right now.' };
81
+ }
82
+ const value = asRecord(outcome.value);
83
+ const raw = value?.credentials;
84
+ if (!Array.isArray(raw)) return { available: false, reason: 'Credential status unavailable right now.' };
85
+ const credentials: CredentialStatusEntry[] = [];
86
+ for (const item of raw) {
87
+ const rec = asRecord(item);
88
+ const key = rec ? firstString(rec, ['key']) : '';
89
+ if (!rec || !key) continue;
90
+ credentials.push({
91
+ key,
92
+ configured: rec.configured === true,
93
+ usable: rec.usable === true,
94
+ source: firstString(rec, ['source']) || undefined,
95
+ scope: firstString(rec, ['scope']) || undefined,
96
+ secure: rec.secure === true ? true : rec.secure === false ? false : undefined,
97
+ overriddenByEnv: rec.overriddenByEnv === true ? true : rec.overriddenByEnv === false ? false : undefined,
98
+ refSource: firstString(rec, ['refSource']) || undefined,
99
+ });
100
+ }
101
+ return { available: true, credentials };
102
+ }
103
+
104
+ /**
105
+ * Extract the machine code from a non-2xx daemon response body, falling back to the
106
+ * HTTP status for legacy daemons that predate the code field. A 404 with no code is
107
+ * treated as METHOD_NOT_FOUND (older daemon without the route — same as webui's
108
+ * isMethodUnavailableError); a 503 with no code as CREDENTIAL_STORE_UNAVAILABLE.
109
+ */
110
+ function machineCodeFromResponse(body: unknown, status: number): string {
111
+ const record = asRecord(body);
112
+ const direct = record ? firstString(record, ['code']) : '';
113
+ if (direct) return direct;
114
+ const nested = record ? asRecord(record.error) : null;
115
+ const nestedCode = nested ? firstString(nested, ['code']) : '';
116
+ if (nestedCode) return nestedCode;
117
+ if (status === 404) return 'METHOD_NOT_FOUND';
118
+ if (status === 503) return 'CREDENTIAL_STORE_UNAVAILABLE';
119
+ return '';
120
+ }
121
+
122
+ /**
123
+ * Read credential status from the connected daemon as a client, honestly degraded.
124
+ * Status only — the response is folded through {@link deriveCredentialAvailability},
125
+ * so a down store, an older daemon, an absent token, or a transport failure all become
126
+ * a reason-carrying `available: false`, never a fabricated "configured" and never a
127
+ * secret byte. `key` narrows to a single credential (the daemon's caller-named probe).
128
+ */
129
+ export async function fetchDaemonCredentialAvailability(
130
+ connection: CredentialStatusConnection,
131
+ options: { readonly key?: string; readonly fetchImpl?: FetchLike } = {},
132
+ ): Promise<CredentialAvailability> {
133
+ if (!connection.token) {
134
+ return { available: false, reason: 'No connected-host operator token; credential status is unavailable.' };
135
+ }
136
+ const fetchImpl = options.fetchImpl ?? (globalThis.fetch as FetchLike | undefined);
137
+ if (!fetchImpl) {
138
+ return { available: false, reason: 'Credential status unavailable right now.' };
139
+ }
140
+ const query = options.key ? `?key=${encodeURIComponent(options.key)}` : '';
141
+ const url = `${connection.baseUrl}${CREDENTIALS_ROUTE}${query}`;
142
+ try {
143
+ const response = await fetchImpl(url, {
144
+ method: 'GET',
145
+ headers: { authorization: `Bearer ${connection.token}` },
146
+ signal: AbortSignal.timeout(CREDENTIAL_STATUS_TIMEOUT_MS),
147
+ });
148
+ const text = await response.text();
149
+ let body: unknown = text;
150
+ try {
151
+ body = text.trim() ? JSON.parse(text) as unknown : {};
152
+ } catch {
153
+ body = text;
154
+ }
155
+ if (!response.ok) {
156
+ return deriveCredentialAvailability({
157
+ ok: false,
158
+ error: { code: machineCodeFromResponse(body, response.status), status: response.status },
159
+ });
160
+ }
161
+ return deriveCredentialAvailability({ ok: true, value: body });
162
+ } catch (error) {
163
+ return deriveCredentialAvailability({ ok: false, error });
164
+ }
165
+ }
@@ -55,3 +55,15 @@ export function getConfiguredSystemPrompt(configManager: Pick<ConfigManager, 'ge
55
55
  }
56
56
 
57
57
  export { getConfiguredApiKeys, resolveApiKeys } from '@pellux/goodvibes-sdk/platform/config';
58
+
59
+ // W6-C1 (E7): the daemon-client credential STATUS read (secret-free, honest-degrade).
60
+ // Value reads above stay local/env; only the status VISIBILITY path moves to the daemon.
61
+ export {
62
+ deriveCredentialAvailability,
63
+ fetchDaemonCredentialAvailability,
64
+ } from './credential-status.ts';
65
+ export type {
66
+ CredentialAvailability,
67
+ CredentialStatusConnection,
68
+ CredentialStatusEntry,
69
+ } from './credential-status.ts';
@@ -16,6 +16,23 @@ import {
16
16
  import { isSecretRefInput } from '@pellux/goodvibes-sdk/platform/config';
17
17
  import { GOODVIBES_AGENT_SURFACE_ROOT } from './surface.ts';
18
18
 
19
+ // W6-C1 host-vs-client split (E7 config sharing): this SecretsManager is the LOCAL-HOST
20
+ // read path — pinned to GOODVIBES_AGENT_SURFACE_ROOT, it resolves secret VALUES from the
21
+ // surface store/env for provider auth, unchanged. When the Agent acts as a CLIENT of an
22
+ // adopted external daemon, credential *status* (configured/usable — never bytes) is read
23
+ // over the wire via ./credential-status.ts (`fetchDaemonCredentialAvailability`), which
24
+ // degrades honestly and never fabricates "configured". Only STATUS visibility moves to
25
+ // the daemon path; value resolution stays here, local and env-only for API keys.
26
+ export {
27
+ deriveCredentialAvailability,
28
+ fetchDaemonCredentialAvailability,
29
+ } from './credential-status.ts';
30
+ export type {
31
+ CredentialAvailability,
32
+ CredentialStatusConnection,
33
+ CredentialStatusEntry,
34
+ } from './credential-status.ts';
35
+
19
36
  export type SecretsManagerOptions = Omit<SdkSecretsManagerOptions, 'surfaceRoot'>;
20
37
 
21
38
  const RAW_SECRET_LITERAL_PREFIX = '__GOODVIBES_LITERAL_V1__';
@@ -26,7 +26,10 @@ import {
26
26
  } from '@/runtime/index.ts';
27
27
  import { loadBootstrapSystemPrompt, syncConfiguredServices } from '@/runtime/index.ts';
28
28
  import { registerBootstrapHookBridge } from '@/runtime/index.ts';
29
- import { createRuntimeServices, type RuntimeServices } from './services.ts';
29
+ import { createRuntimeServices, foldAgentLegacyMemory, type RuntimeServices } from './services.ts';
30
+ import { formatMemoryFoldReport } from '@pellux/goodvibes-sdk/platform/state';
31
+ import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
32
+ import { importVibeFilesIntoMemoryOnce } from '../agent/vibe-file.ts';
30
33
  import { createUiRuntimeServices, type UiRuntimeServices } from './ui-services.ts';
31
34
  import { installAgentToolPolicyGuard } from '../tools/agent-tool-policy-guard.ts';
32
35
  import { registerAgentChannelSendTool } from '../tools/agent-channel-send-tool.ts';
@@ -345,6 +348,34 @@ export async function initializeBootstrapCore(
345
348
  memoryStore.close();
346
349
  });
347
350
 
351
+ // W6-C2 (E6): fold the agent's legacy per-surface memory into the canonical
352
+ // cross-surface store (id-keyed, idempotent, never deletes the legacy file) and
353
+ // SURFACE the fold report — migration honesty requires that what moved is visible,
354
+ // not silently swallowed. Non-fatal: a fold failure must never block startup.
355
+ try {
356
+ const foldReport = await foldAgentLegacyMemory(
357
+ services.memoryStore,
358
+ services.memoryEmbeddingRegistry,
359
+ services.shellPaths,
360
+ );
361
+ logger.info('agent legacy memory fold report', { report: formatMemoryFoldReport(foldReport) });
362
+ } catch (err) {
363
+ logger.warn('agent legacy memory fold failed (non-fatal)', { error: summarizeError(err) });
364
+ }
365
+
366
+ // W6-C2 (E6): ONE-TIME migration of discovered VIBE.md files into persona/constraint
367
+ // records, guarded by a persisted path→hash marker so it never re-imports the same
368
+ // file (which would create near-duplicate persona records). After this, the VIBE
369
+ // prompt is a PROJECTION of those records (buildVibeProjectionPrompt).
370
+ try {
371
+ const importedPersona = await importVibeFilesIntoMemoryOnce(services.memoryRegistry, services.shellPaths);
372
+ if (importedPersona > 0) {
373
+ logger.info('agent VIBE.md persona migration', { records: importedPersona });
374
+ }
375
+ } catch (err) {
376
+ logger.warn('agent VIBE.md persona migration failed (non-fatal)', { error: summarizeError(err) });
377
+ }
378
+
348
379
  const renderRequestRef = { value: (): void => {} };
349
380
  // R1: Coalescing render scheduler — collapses N same-microtask requestRender() calls into 1.
350
381
  // Also enforces a 16ms minimum interval to cap at ~60fps during streaming.
@@ -6,7 +6,7 @@ import { AgentPersonaRegistry, buildActivePersonaPrompt } from '../agent/persona
6
6
  import { buildProjectContextPrompt, discoverProjectContextFiles } from '../agent/project-context-files.ts';
7
7
  import { AgentRoutineRegistry, buildEnabledRoutinesPrompt, evaluateAgentRoutineReadiness } from '../agent/routine-registry.ts';
8
8
  import { AgentSkillRegistry, buildEnabledSkillsPrompt, evaluateAgentSkillBundleReadiness, evaluateAgentSkillReadiness } from '../agent/skill-registry.ts';
9
- import { buildVibePrompt, discoverVibeFiles } from '../agent/vibe-file.ts';
9
+ import { buildVibeProjectionPrompt, discoverVibeFiles } from '../agent/vibe-file.ts';
10
10
  import type { PromptContextReceipt } from '../agent/prompt-context-receipts.ts';
11
11
  import type { CommandContext } from '../input/command-registry.ts';
12
12
  import { previewHarnessText } from './agent-harness-text.ts';
@@ -399,7 +399,10 @@ function promptContextSegments(context: CommandContext, includeParameters: boole
399
399
  }
400
400
 
401
401
  const vibe = discoverVibeFiles(shellPaths);
402
- const vibePrompt = buildVibePrompt(shellPaths) ?? '';
402
+ // W6-C2 (E6): mirror the runtime — the VIBE prompt is a PROJECTION of persona records,
403
+ // not a file re-read (discoverVibeFiles stays for the file-discovery receipt below).
404
+ const vibeMemory = promptMemoryApi(context.clients?.agentKnowledgeApi?.memory);
405
+ const vibePrompt = (vibeMemory ? buildVibeProjectionPrompt(vibeMemory) : null) ?? '';
403
406
  const projectContext = discoverProjectContextFiles(shellPaths);
404
407
  const projectContextPrompt = buildProjectContextPrompt(shellPaths) ?? '';
405
408
  const personaSnapshot = AgentPersonaRegistry.fromShellPaths(shellPaths).snapshot();
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 = '1.5.6';
9
+ let _version = '1.5.7';
10
10
  try {
11
11
  const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8')) as {
12
12
  readonly version?: unknown;