@pellux/goodvibes-agent 0.1.48 → 0.1.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -1
- package/package.json +1 -1
- package/src/input/agent-workspace.ts +41 -1
- package/src/panels/builtin/knowledge.ts +3 -3
- package/src/panels/builtin/shared.ts +3 -0
- package/src/panels/knowledge-panel.ts +80 -9
- package/src/renderer/agent-workspace.ts +1 -0
- package/src/runtime/bootstrap-core.ts +2 -0
- package/src/runtime/bootstrap-shell.ts +1 -0
- package/src/runtime/bootstrap.ts +1 -0
- package/src/tools/agent-local-registry-tool.ts +341 -0
- package/src/version.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,10 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to GoodVibes Agent will be recorded here.
|
|
4
4
|
|
|
5
|
+
## 0.1.49 - 2026-05-31
|
|
6
|
+
|
|
7
|
+
- 445e694 Show isolated Agent Knowledge in TUI panel
|
|
8
|
+
- 632d951 Add agent-local registry tool
|
|
9
|
+
- 4832355 Make agent setup workspace actionable
|
|
10
|
+
|
|
5
11
|
## 0.1.48 - 2026-05-31
|
|
6
12
|
|
|
7
13
|
- 67f8ce0 Remove audit remnants and surface setup checklist
|
|
8
|
-
- 34c3d0b Remove internal
|
|
14
|
+
- 34c3d0b Remove internal development-only surfaces
|
|
9
15
|
|
|
10
16
|
## 0.1.47 - 2026-05-31
|
|
11
17
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pellux/goodvibes-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.49",
|
|
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",
|
|
@@ -20,13 +20,14 @@ export const AGENT_WORKSPACE_MODAL_NAME = 'agentWorkspace';
|
|
|
20
20
|
|
|
21
21
|
export type AgentWorkspaceFocusPane = 'categories' | 'actions';
|
|
22
22
|
|
|
23
|
-
export type AgentWorkspaceActionKind = 'command' | 'guidance';
|
|
23
|
+
export type AgentWorkspaceActionKind = 'command' | 'guidance' | 'workspace';
|
|
24
24
|
|
|
25
25
|
export interface AgentWorkspaceAction {
|
|
26
26
|
readonly id: string;
|
|
27
27
|
readonly label: string;
|
|
28
28
|
readonly detail: string;
|
|
29
29
|
readonly command?: string;
|
|
30
|
+
readonly targetCategoryId?: string;
|
|
30
31
|
readonly kind: AgentWorkspaceActionKind;
|
|
31
32
|
readonly safety: 'safe' | 'read-only' | 'delegates' | 'blocked';
|
|
32
33
|
}
|
|
@@ -307,6 +308,11 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
|
|
|
307
308
|
actions: [
|
|
308
309
|
{ id: 'chat', label: 'Continue assistant chat', detail: 'Close this workspace and type a normal message. Agent work stays serial in the main conversation.', kind: 'guidance', safety: 'safe' },
|
|
309
310
|
{ id: 'model', label: 'Choose model', detail: 'Open the model/provider workspace for the Agent chat route.', command: '/model', kind: 'command', safety: 'safe' },
|
|
311
|
+
{ id: 'setup-home', label: 'Setup checklist', detail: 'Jump to the first-run checklist for provider, knowledge, personas, skills, routines, memory, channels, and voice/media.', targetCategoryId: 'setup', kind: 'workspace', safety: 'safe' },
|
|
312
|
+
{ id: 'knowledge-home', label: 'Agent Knowledge', detail: 'Jump to isolated Agent Knowledge status, ingest, search, and review flows.', targetCategoryId: 'knowledge', kind: 'workspace', safety: 'read-only' },
|
|
313
|
+
{ id: 'memory-home', label: 'Memory, skills, routines', detail: 'Jump to local memory, persona, skill, and routine setup. These are core Agent product features.', targetCategoryId: 'memory', kind: 'workspace', safety: 'safe' },
|
|
314
|
+
{ id: 'channels-home', label: 'Channels', detail: 'Jump to companion pairing and channel readiness without changing daemon lifecycle.', targetCategoryId: 'channels', kind: 'workspace', safety: 'read-only' },
|
|
315
|
+
{ id: 'voice-home', label: 'Voice and media', detail: 'Jump to voice, TTS, image input, browser, and node posture setup.', targetCategoryId: 'voice-media', kind: 'workspace', safety: 'safe' },
|
|
310
316
|
{ id: 'help', label: 'Browse commands', detail: 'Open registry-driven command help.', command: '/help', kind: 'command', safety: 'safe' },
|
|
311
317
|
{ id: 'health', label: 'Review health', detail: 'Show the local health review surface without starting or mutating daemon services.', command: '/health review', kind: 'command', safety: 'read-only' },
|
|
312
318
|
],
|
|
@@ -320,6 +326,15 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
|
|
|
320
326
|
actions: [
|
|
321
327
|
{ id: 'config', label: 'Open config workspace', detail: 'Use the TUI-derived fullscreen settings workspace.', command: '/config', kind: 'command', safety: 'safe' },
|
|
322
328
|
{ id: 'onboarding', label: 'Open setup wizard', detail: 'Review Agent runtime settings in the fullscreen setup flow.', command: '/onboarding', kind: 'command', safety: 'safe' },
|
|
329
|
+
{ id: 'setup-provider-model', label: 'Provider and model', detail: 'Choose the provider/model route for normal assistant chat.', command: '/model', kind: 'command', safety: 'safe' },
|
|
330
|
+
{ id: 'setup-agent-knowledge', label: 'Agent Knowledge', detail: 'Inspect the isolated Agent Knowledge store before ingesting source-backed material.', command: '/knowledge status', kind: 'command', safety: 'read-only' },
|
|
331
|
+
{ id: 'setup-runtime-profiles', label: 'Runtime profiles', detail: 'Browse starter templates for isolated Agent homes and operator identities.', command: '/agent-profile templates', kind: 'command', safety: 'read-only' },
|
|
332
|
+
{ id: 'setup-personas', label: 'Personas', detail: 'Create or select the active local Agent persona.', command: '/personas', kind: 'command', safety: 'safe' },
|
|
333
|
+
{ id: 'setup-skills', label: 'Skills', detail: 'Create, review, and enable reusable local Agent skills.', command: '/agent-skills', kind: 'command', safety: 'safe' },
|
|
334
|
+
{ id: 'setup-routines', label: 'Routines', detail: 'Create, review, and enable local Agent routines before any explicit schedule promotion.', command: '/routines', kind: 'command', safety: 'safe' },
|
|
335
|
+
{ id: 'setup-memory', label: 'Local memory', detail: 'Inspect local/session memory; secrets stay rejected or redacted.', command: '/memory', kind: 'command', safety: 'read-only' },
|
|
336
|
+
{ id: 'setup-channels', label: 'Channels', detail: 'Open companion pairing and channel readiness setup.', command: '/pair', kind: 'command', safety: 'safe' },
|
|
337
|
+
{ id: 'setup-voice-media', label: 'Voice and media', detail: 'Open TTS/media settings for voice and image-capable Agent flows.', command: '/config tts', kind: 'command', safety: 'safe' },
|
|
323
338
|
{ id: 'provider', label: 'Provider status', detail: 'Review provider/model posture.', command: '/provider', kind: 'command', safety: 'read-only' },
|
|
324
339
|
{ id: 'auth', label: 'Auth review', detail: 'Review authentication posture without printing token values.', command: '/auth review', kind: 'command', safety: 'read-only' },
|
|
325
340
|
],
|
|
@@ -566,6 +581,31 @@ export class AgentWorkspace {
|
|
|
566
581
|
const action = this.selectedAction;
|
|
567
582
|
if (!action) return;
|
|
568
583
|
if (action.kind === 'guidance' || !action.command) {
|
|
584
|
+
if (action.kind === 'workspace' && action.targetCategoryId) {
|
|
585
|
+
const targetIndex = this.categories.findIndex((category) => category.id === action.targetCategoryId);
|
|
586
|
+
if (targetIndex >= 0) {
|
|
587
|
+
this.selectedCategoryIndex = targetIndex;
|
|
588
|
+
this.selectedActionIndex = 0;
|
|
589
|
+
this.focusActions();
|
|
590
|
+
this.status = `Opened ${this.selectedCategory.label}.`;
|
|
591
|
+
this.lastActionResult = {
|
|
592
|
+
kind: 'refreshed',
|
|
593
|
+
title: `Opened ${this.selectedCategory.label}`,
|
|
594
|
+
detail: action.detail,
|
|
595
|
+
safety: action.safety,
|
|
596
|
+
};
|
|
597
|
+
this.clampSelection();
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
this.status = `Workspace area unavailable: ${action.targetCategoryId}.`;
|
|
601
|
+
this.lastActionResult = {
|
|
602
|
+
kind: 'error',
|
|
603
|
+
title: 'Workspace area unavailable',
|
|
604
|
+
detail: `No Agent workspace category exists for ${action.targetCategoryId}.`,
|
|
605
|
+
safety: action.safety,
|
|
606
|
+
};
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
569
609
|
this.status = action.detail;
|
|
570
610
|
this.lastActionResult = {
|
|
571
611
|
kind: 'guidance',
|
|
@@ -6,14 +6,14 @@ import type { ResolvedBuiltinPanelDeps } from './shared.ts';
|
|
|
6
6
|
export function registerKnowledgePanels(manager: PanelManager, deps: ResolvedBuiltinPanelDeps): void {
|
|
7
7
|
if (!deps.memoryRegistry) return;
|
|
8
8
|
|
|
9
|
-
const { memoryRegistry } = deps;
|
|
9
|
+
const { agentKnowledgeService, memoryRegistry } = deps;
|
|
10
10
|
manager.registerType({
|
|
11
11
|
id: 'knowledge',
|
|
12
12
|
name: 'Knowledge',
|
|
13
13
|
icon: 'K',
|
|
14
14
|
category: 'agent',
|
|
15
|
-
description: '
|
|
16
|
-
factory: () => new KnowledgePanel(memoryRegistry),
|
|
15
|
+
description: 'Isolated Agent Knowledge plus local non-secret memory review',
|
|
16
|
+
factory: () => new KnowledgePanel(memoryRegistry, agentKnowledgeService ?? null),
|
|
17
17
|
});
|
|
18
18
|
manager.registerType({
|
|
19
19
|
id: 'memory',
|
|
@@ -21,6 +21,7 @@ import type { SessionMemoryStore } from '@pellux/goodvibes-sdk/platform/core';
|
|
|
21
21
|
import type { ExecutionPlanManager } from '@pellux/goodvibes-sdk/platform/core';
|
|
22
22
|
import type { AdaptivePlanner } from '@pellux/goodvibes-sdk/platform/core';
|
|
23
23
|
import type { ProjectPlanningService } from '@pellux/goodvibes-sdk/platform/knowledge';
|
|
24
|
+
import type { KnowledgeService } from '@pellux/goodvibes-sdk/platform/knowledge';
|
|
24
25
|
import type { ApiTokenAuditor } from '@pellux/goodvibes-sdk/platform/security';
|
|
25
26
|
import type { ComponentHealthMonitor } from '../../runtime/perf/panel-health-monitor.ts';
|
|
26
27
|
import type { WorktreeRegistry } from '@/runtime/index.ts';
|
|
@@ -65,6 +66,8 @@ export interface BuiltinPanelDeps {
|
|
|
65
66
|
evalRegistry?: import('../eval-panel.ts').EvalRegistry;
|
|
66
67
|
/** MemoryRegistry for the Memory panel. */
|
|
67
68
|
memoryRegistry?: MemoryRegistry;
|
|
69
|
+
/** Isolated Agent Knowledge service for the Agent Knowledge panel. */
|
|
70
|
+
agentKnowledgeService?: Pick<KnowledgeService, 'getStatus'>;
|
|
68
71
|
/** Shared policy runtime state for governance/policy diagnostics. */
|
|
69
72
|
policyRuntimeState?: import('@/runtime/index.ts').PolicyRuntimeState;
|
|
70
73
|
/** Approval broker for control-plane/operator panels. */
|
|
@@ -2,9 +2,9 @@ import type { Line } from '../types/grid.ts';
|
|
|
2
2
|
import { ScrollableListPanel } from './scrollable-list-panel.ts';
|
|
3
3
|
import { type ConfirmState, handleConfirmInput, renderConfirmLines } from './confirm-state.ts';
|
|
4
4
|
import type { MemoryClass, MemoryRecord, MemoryRegistry, MemoryReviewState } from '@pellux/goodvibes-sdk/platform/state';
|
|
5
|
+
import type { KnowledgeStatus } from '@pellux/goodvibes-sdk/platform/knowledge';
|
|
5
6
|
import {
|
|
6
7
|
buildBodyText,
|
|
7
|
-
buildEmptyState,
|
|
8
8
|
buildGuidanceLine,
|
|
9
9
|
buildKeyValueLine,
|
|
10
10
|
buildPanelLine,
|
|
@@ -12,6 +12,10 @@ import {
|
|
|
12
12
|
DEFAULT_PANEL_PALETTE,
|
|
13
13
|
} from './polish.ts';
|
|
14
14
|
|
|
15
|
+
export interface AgentKnowledgePanelService {
|
|
16
|
+
readonly getStatus: () => Promise<KnowledgeStatus & { readonly note?: string }>;
|
|
17
|
+
}
|
|
18
|
+
|
|
15
19
|
function summarize(records: MemoryRecord[], cls: MemoryClass): MemoryRecord[] {
|
|
16
20
|
return records.filter((record) => record.cls === cls).slice(0, 3);
|
|
17
21
|
}
|
|
@@ -42,19 +46,25 @@ function formatConfidence(confidence: number): string {
|
|
|
42
46
|
|
|
43
47
|
export class KnowledgePanel extends ScrollableListPanel<MemoryRecord> {
|
|
44
48
|
private readonly registry: MemoryRegistry;
|
|
49
|
+
private readonly agentKnowledgeService: AgentKnowledgePanelService | null;
|
|
45
50
|
private unsubscribe?: () => void;
|
|
46
51
|
private records: MemoryRecord[] = [];
|
|
52
|
+
private agentKnowledgeStatus: (KnowledgeStatus & { readonly note?: string }) | null = null;
|
|
53
|
+
private agentKnowledgeError: string | null = null;
|
|
54
|
+
private agentKnowledgeLoading = false;
|
|
47
55
|
// I1: confirm for destructive review-state mutations
|
|
48
56
|
private confirm: ConfirmState<{ id: string; action: 'stale' | 'contradicted' }> | null = null;
|
|
49
57
|
|
|
50
|
-
public constructor(registry: MemoryRegistry) {
|
|
58
|
+
public constructor(registry: MemoryRegistry, agentKnowledgeService: AgentKnowledgePanelService | null = null) {
|
|
51
59
|
super('knowledge', 'Knowledge', 'K', 'agent');
|
|
52
60
|
this.registry = registry;
|
|
61
|
+
this.agentKnowledgeService = agentKnowledgeService;
|
|
53
62
|
}
|
|
54
63
|
|
|
55
64
|
public override onActivate(): void {
|
|
56
65
|
super.onActivate();
|
|
57
66
|
this.refresh();
|
|
67
|
+
this.refreshAgentKnowledgeStatus();
|
|
58
68
|
this.unsubscribe = this.registry.subscribe(() => {
|
|
59
69
|
this.refresh();
|
|
60
70
|
this.markDirty();
|
|
@@ -89,12 +99,13 @@ export class KnowledgePanel extends ScrollableListPanel<MemoryRecord> {
|
|
|
89
99
|
}
|
|
90
100
|
|
|
91
101
|
protected override getPalette() { return C; }
|
|
92
|
-
protected override getEmptyStateMessage() { return 'No
|
|
102
|
+
protected override getEmptyStateMessage() { return 'No Agent Knowledge sources or local memory review records'; }
|
|
93
103
|
protected override getEmptyStateActions() {
|
|
94
104
|
return [
|
|
95
|
-
{ command: '/
|
|
96
|
-
{ command: '/
|
|
97
|
-
{ command: '/
|
|
105
|
+
{ command: '/knowledge status', summary: 'inspect the isolated Agent Knowledge store' },
|
|
106
|
+
{ command: '/knowledge ingest-url <url> --yes', summary: 'ingest source-backed material into Agent Knowledge only' },
|
|
107
|
+
{ command: '/knowledge queue', summary: 'review Agent Knowledge issues' },
|
|
108
|
+
{ command: '/recall add fact <summary>', summary: 'capture a local non-secret memory record when appropriate' },
|
|
98
109
|
];
|
|
99
110
|
}
|
|
100
111
|
|
|
@@ -198,6 +209,64 @@ export class KnowledgePanel extends ScrollableListPanel<MemoryRecord> {
|
|
|
198
209
|
this.clampSelection();
|
|
199
210
|
}
|
|
200
211
|
|
|
212
|
+
private refreshAgentKnowledgeStatus(): void {
|
|
213
|
+
if (!this.agentKnowledgeService || this.agentKnowledgeLoading) return;
|
|
214
|
+
this.agentKnowledgeLoading = true;
|
|
215
|
+
this.agentKnowledgeError = null;
|
|
216
|
+
this.agentKnowledgeService.getStatus()
|
|
217
|
+
.then((status) => {
|
|
218
|
+
this.agentKnowledgeStatus = status;
|
|
219
|
+
this.agentKnowledgeError = null;
|
|
220
|
+
})
|
|
221
|
+
.catch((error: unknown) => {
|
|
222
|
+
this.agentKnowledgeError = error instanceof Error ? error.message : String(error);
|
|
223
|
+
})
|
|
224
|
+
.finally(() => {
|
|
225
|
+
this.agentKnowledgeLoading = false;
|
|
226
|
+
this.markDirty();
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
private buildAgentKnowledgeHeader(width: number): Line[] {
|
|
231
|
+
const lines: Line[] = [
|
|
232
|
+
buildPanelLine(width, [[' Agent Knowledge Segment', C.label]]),
|
|
233
|
+
buildPanelLine(width, [
|
|
234
|
+
[' route ', C.label],
|
|
235
|
+
['/api/goodvibes-agent/knowledge/*', C.info],
|
|
236
|
+
[' isolated: no default Knowledge/Wiki or HomeGraph fallback', C.dim],
|
|
237
|
+
]),
|
|
238
|
+
];
|
|
239
|
+
if (this.agentKnowledgeLoading && !this.agentKnowledgeStatus) {
|
|
240
|
+
lines.push(buildPanelLine(width, [[' loading isolated Agent Knowledge status...', C.dim]]));
|
|
241
|
+
} else if (this.agentKnowledgeStatus) {
|
|
242
|
+
const status = this.agentKnowledgeStatus;
|
|
243
|
+
lines.push(buildKeyValueLine(width, [
|
|
244
|
+
{ label: 'Ready', value: status.ready ? 'yes' : 'no', valueColor: status.ready ? C.good : C.warn },
|
|
245
|
+
{ label: 'Sources', value: String(status.sourceCount), valueColor: status.sourceCount > 0 ? C.info : C.dim },
|
|
246
|
+
{ label: 'Nodes', value: String(status.nodeCount), valueColor: status.nodeCount > 0 ? C.info : C.dim },
|
|
247
|
+
{ label: 'Issues', value: String(status.issueCount), valueColor: status.issueCount > 0 ? C.warn : C.good },
|
|
248
|
+
], C));
|
|
249
|
+
const note = status.note ? ` note: ${status.note}` : '';
|
|
250
|
+
lines.push(buildPanelLine(width, [[' storage: ', C.label], [status.storagePath, C.dim], [note, C.dim]]));
|
|
251
|
+
} else {
|
|
252
|
+
lines.push(buildPanelLine(width, [[' status: not loaded; /knowledge status uses the same isolated route.', C.dim]]));
|
|
253
|
+
}
|
|
254
|
+
if (this.agentKnowledgeError) {
|
|
255
|
+
lines.push(...buildBodyText(width, `Agent Knowledge status warning: ${this.agentKnowledgeError}`, C, C.warn));
|
|
256
|
+
}
|
|
257
|
+
lines.push(buildPanelLine(width, [
|
|
258
|
+
[' actions ', C.label],
|
|
259
|
+
['/knowledge status', C.value],
|
|
260
|
+
[' | ', C.dim],
|
|
261
|
+
['/knowledge ingest-url <url> --yes', C.value],
|
|
262
|
+
[' | ', C.dim],
|
|
263
|
+
['/knowledge search <query>', C.value],
|
|
264
|
+
[' | ', C.dim],
|
|
265
|
+
['/knowledge queue', C.value],
|
|
266
|
+
]));
|
|
267
|
+
return lines;
|
|
268
|
+
}
|
|
269
|
+
|
|
201
270
|
public render(width: number, height: number): Line[] {
|
|
202
271
|
this.clampSelection();
|
|
203
272
|
|
|
@@ -214,12 +283,14 @@ export class KnowledgePanel extends ScrollableListPanel<MemoryRecord> {
|
|
|
214
283
|
|
|
215
284
|
if (this.records.length === 0) this.refresh();
|
|
216
285
|
|
|
217
|
-
const intro = '
|
|
286
|
+
const intro = 'Isolated Agent Knowledge plus local non-secret memory review. This surface never falls back to default Knowledge/Wiki or HomeGraph.';
|
|
218
287
|
const records = this.registry.search({ limit: 200 });
|
|
288
|
+
const agentKnowledgeHeader = this.buildAgentKnowledgeHeader(width);
|
|
219
289
|
|
|
220
290
|
if (records.length === 0) {
|
|
221
291
|
return this.renderList(width, height, {
|
|
222
292
|
title: 'Knowledge Control Room',
|
|
293
|
+
header: agentKnowledgeHeader,
|
|
223
294
|
footer: [buildPanelLine(width, [[' Review keys: Up/Down move r/Enter review s stale c contradicted f fresh', C.dim]])],
|
|
224
295
|
});
|
|
225
296
|
}
|
|
@@ -334,11 +405,11 @@ export class KnowledgePanel extends ScrollableListPanel<MemoryRecord> {
|
|
|
334
405
|
|
|
335
406
|
return this.renderList(width, height, {
|
|
336
407
|
title: 'Knowledge Control Room',
|
|
337
|
-
header: [...classLines, ...reviewLines],
|
|
408
|
+
header: [...agentKnowledgeHeader, ...classLines, ...reviewLines],
|
|
338
409
|
footer: [
|
|
410
|
+
buildPanelLine(width, [[' Up/Down move r/Enter reviewed s stale c contradicted f fresh', C.dim]]),
|
|
339
411
|
...(selectedLines.length > 0 ? selectedLines : []),
|
|
340
412
|
...recentSummaryLines,
|
|
341
|
-
buildPanelLine(width, [[' Up/Down move r/Enter reviewed s stale c contradicted f fresh', C.dim]]),
|
|
342
413
|
],
|
|
343
414
|
});
|
|
344
415
|
}
|
|
@@ -67,6 +67,7 @@ function buildLeftRows(workspace: AgentWorkspace, height: number): WorkspaceRow[
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
function actionCommand(action: AgentWorkspaceAction): string {
|
|
70
|
+
if (action.kind === 'workspace') return action.targetCategoryId ? `open ${action.targetCategoryId}` : '(workspace)';
|
|
70
71
|
return action.command ?? '(guidance)';
|
|
71
72
|
}
|
|
72
73
|
|
|
@@ -30,6 +30,7 @@ import { registerBootstrapRuntimeEvents } from '@/runtime/index.ts';
|
|
|
30
30
|
import { createRuntimeServices, type RuntimeServices } from './services.ts';
|
|
31
31
|
import { createUiRuntimeServices, type UiRuntimeServices } from './ui-services.ts';
|
|
32
32
|
import { installAgentToolPolicyGuard } from '../tools/wrfc-agent-guard.ts';
|
|
33
|
+
import { registerAgentLocalRegistryTool } from '../tools/agent-local-registry-tool.ts';
|
|
33
34
|
import { GOODVIBES_AGENT_SURFACE_ROOT } from '../config/surface.ts';
|
|
34
35
|
|
|
35
36
|
export interface BootstrapCoreState {
|
|
@@ -227,6 +228,7 @@ export async function initializeBootstrapCore(
|
|
|
227
228
|
overflowHandler: services.overflowHandler,
|
|
228
229
|
changeTracker: services.sessionChangeTracker,
|
|
229
230
|
});
|
|
231
|
+
registerAgentLocalRegistryTool(toolRegistry, services.shellPaths);
|
|
230
232
|
installAgentToolPolicyGuard(toolRegistry, {
|
|
231
233
|
getLastUserMessage: () => conversation.getLastUserMessage(),
|
|
232
234
|
});
|
|
@@ -135,6 +135,7 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
|
|
|
135
135
|
sandboxSessionRegistry: services.sandboxSessionRegistry,
|
|
136
136
|
systemMessagesPanel,
|
|
137
137
|
memoryRegistry: services.memoryRegistry,
|
|
138
|
+
agentKnowledgeService: services.agentKnowledgeService,
|
|
138
139
|
uiServices,
|
|
139
140
|
pluginManager: services.pluginManager,
|
|
140
141
|
hookDispatcher: services.hookDispatcher,
|
package/src/runtime/bootstrap.ts
CHANGED
|
@@ -48,6 +48,7 @@ const GOODVIBES_AGENT_OPERATOR_POLICY = [
|
|
|
48
48
|
'## GoodVibes Agent Operator Policy',
|
|
49
49
|
'- Default to serial, proactive assistant work in the main conversation. Answer, inspect, summarize, remember useful non-secret facts, configure local Agent state, use read-only daemon/operator routes, and take safe non-destructive actions without spawning local agents or WRFC.',
|
|
50
50
|
'- GoodVibes Agent connects to an externally managed GoodVibes daemon. Do not start, stop, restart, install, expose, or mutate daemon/listener/control-plane surface posture from Agent runtime.',
|
|
51
|
+
'- Use the `agent_local_registry` tool when a reusable persona, skill, or routine would improve future work. Keep those records local, non-secret, source/provenance tagged, and reviewable. Starting a routine means applying its steps in this same serial conversation, not creating a background job.',
|
|
51
52
|
'- WRFC is never the default Agent reasoning path. Do not create local WRFC chains for planning, research, operations, knowledge, memory, configuration, approvals, automation observability, or ordinary assistant work.',
|
|
52
53
|
'- GoodVibes Agent is not the coding TUI. Do not use the `agent` tool to spawn local Engineer, Reviewer, Tester, Verifier, or batch-spawn roots from Agent.',
|
|
53
54
|
'- When the user explicitly asks to build, implement, fix, patch, or review code, preserve the full original user ask and delegate one build request to GoodVibes TUI through the public shared-session/build-delegation contract. Include clear executionIntent and request WRFC only for explicit build/fix/review work or when the user explicitly asks for WRFC/agent review.',
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import type { Tool } from '@pellux/goodvibes-sdk/platform/types';
|
|
2
|
+
import type { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools';
|
|
3
|
+
import type { ShellPathService } from '@/runtime/index.ts';
|
|
4
|
+
import { AgentPersonaRegistry, type AgentPersonaRecord } from '../agent/persona-registry.ts';
|
|
5
|
+
import { AgentRoutineRegistry, type AgentRoutineRecord } from '../agent/routine-registry.ts';
|
|
6
|
+
import { AgentSkillRegistry, type AgentSkillRecord } from '../agent/skill-registry.ts';
|
|
7
|
+
|
|
8
|
+
export type AgentLocalRegistryDomain = 'persona' | 'skill' | 'routine';
|
|
9
|
+
export type AgentLocalRegistryAction =
|
|
10
|
+
| 'list'
|
|
11
|
+
| 'search'
|
|
12
|
+
| 'get'
|
|
13
|
+
| 'create'
|
|
14
|
+
| 'update'
|
|
15
|
+
| 'enable'
|
|
16
|
+
| 'disable'
|
|
17
|
+
| 'review'
|
|
18
|
+
| 'stale'
|
|
19
|
+
| 'use'
|
|
20
|
+
| 'clear_active'
|
|
21
|
+
| 'start';
|
|
22
|
+
|
|
23
|
+
export interface AgentLocalRegistryToolArgs {
|
|
24
|
+
readonly domain?: unknown;
|
|
25
|
+
readonly action?: unknown;
|
|
26
|
+
readonly id?: unknown;
|
|
27
|
+
readonly query?: unknown;
|
|
28
|
+
readonly name?: unknown;
|
|
29
|
+
readonly description?: unknown;
|
|
30
|
+
readonly body?: unknown;
|
|
31
|
+
readonly procedure?: unknown;
|
|
32
|
+
readonly steps?: unknown;
|
|
33
|
+
readonly triggers?: unknown;
|
|
34
|
+
readonly tags?: unknown;
|
|
35
|
+
readonly reason?: unknown;
|
|
36
|
+
readonly enabled?: unknown;
|
|
37
|
+
readonly provenance?: unknown;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const DOMAINS: readonly AgentLocalRegistryDomain[] = ['persona', 'skill', 'routine'];
|
|
41
|
+
const ACTIONS: readonly AgentLocalRegistryAction[] = [
|
|
42
|
+
'list',
|
|
43
|
+
'search',
|
|
44
|
+
'get',
|
|
45
|
+
'create',
|
|
46
|
+
'update',
|
|
47
|
+
'enable',
|
|
48
|
+
'disable',
|
|
49
|
+
'review',
|
|
50
|
+
'stale',
|
|
51
|
+
'use',
|
|
52
|
+
'clear_active',
|
|
53
|
+
'start',
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
function isDomain(value: unknown): value is AgentLocalRegistryDomain {
|
|
57
|
+
return typeof value === 'string' && DOMAINS.includes(value as AgentLocalRegistryDomain);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function isAction(value: unknown): value is AgentLocalRegistryAction {
|
|
61
|
+
return typeof value === 'string' && ACTIONS.includes(value as AgentLocalRegistryAction);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function readString(value: unknown): string {
|
|
65
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function readStringList(value: unknown): readonly string[] {
|
|
69
|
+
if (typeof value === 'string') {
|
|
70
|
+
return value.split(',').map((entry) => entry.trim()).filter(Boolean);
|
|
71
|
+
}
|
|
72
|
+
if (!Array.isArray(value)) return [];
|
|
73
|
+
return value.filter((entry): entry is string => typeof entry === 'string').map((entry) => entry.trim()).filter(Boolean);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function registryError(message: string): { readonly success: false; readonly error: string } {
|
|
77
|
+
return { success: false, error: message };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function registryOutput(output: string): { readonly success: true; readonly output: string } {
|
|
81
|
+
return { success: true, output };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function requireId(args: AgentLocalRegistryToolArgs): string {
|
|
85
|
+
const id = readString(args.id);
|
|
86
|
+
if (!id) throw new Error('id is required.');
|
|
87
|
+
return id;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function requireName(args: AgentLocalRegistryToolArgs): string {
|
|
91
|
+
const name = readString(args.name);
|
|
92
|
+
if (!name) throw new Error('name is required.');
|
|
93
|
+
return name;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function requireDescription(args: AgentLocalRegistryToolArgs): string {
|
|
97
|
+
const description = readString(args.description);
|
|
98
|
+
if (!description) throw new Error('description is required.');
|
|
99
|
+
return description;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function formatPersona(persona: AgentPersonaRecord, activeId: string | null): string {
|
|
103
|
+
const active = persona.id === activeId ? 'active' : 'inactive';
|
|
104
|
+
return `${persona.id} ${active} ${persona.reviewState} ${persona.name} - ${persona.description}`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function formatSkill(skill: AgentSkillRecord): string {
|
|
108
|
+
const enabled = skill.enabled ? 'enabled' : 'disabled';
|
|
109
|
+
return `${skill.id} ${enabled} ${skill.reviewState} ${skill.name} - ${skill.description}`;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function formatRoutine(routine: AgentRoutineRecord): string {
|
|
113
|
+
const enabled = routine.enabled ? 'enabled' : 'disabled';
|
|
114
|
+
return `${routine.id} ${enabled} ${routine.reviewState} starts=${routine.startCount} ${routine.name} - ${routine.description}`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function listPersonas(registry: AgentPersonaRegistry, records: readonly AgentPersonaRecord[], title: string): string {
|
|
118
|
+
const snapshot = registry.snapshot();
|
|
119
|
+
return records.length === 0
|
|
120
|
+
? `${title}\nNo Agent-local personas.`
|
|
121
|
+
: [title, ...records.map((persona) => formatPersona(persona, snapshot.activePersonaId))].join('\n');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function listSkills(records: readonly AgentSkillRecord[], title: string): string {
|
|
125
|
+
return records.length === 0
|
|
126
|
+
? `${title}\nNo Agent-local skills.`
|
|
127
|
+
: [title, ...records.map(formatSkill)].join('\n');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function listRoutines(records: readonly AgentRoutineRecord[], title: string): string {
|
|
131
|
+
return records.length === 0
|
|
132
|
+
? `${title}\nNo Agent-local routines.`
|
|
133
|
+
: [title, ...records.map(formatRoutine)].join('\n');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function handlePersona(shellPaths: ShellPathService, action: AgentLocalRegistryAction, args: AgentLocalRegistryToolArgs): string {
|
|
137
|
+
const registry = AgentPersonaRegistry.fromShellPaths(shellPaths);
|
|
138
|
+
if (action === 'list') return listPersonas(registry, registry.list(), 'Agent-local personas');
|
|
139
|
+
if (action === 'search') return listPersonas(registry, registry.search(readString(args.query)), 'Agent-local personas search');
|
|
140
|
+
if (action === 'get') {
|
|
141
|
+
const persona = registry.get(requireId(args));
|
|
142
|
+
if (!persona) return `Unknown Agent-local persona: ${readString(args.id)}`;
|
|
143
|
+
return [
|
|
144
|
+
formatPersona(persona, registry.snapshot().activePersonaId),
|
|
145
|
+
`triggers: ${persona.triggers.join(', ') || '(manual)'}`,
|
|
146
|
+
`tags: ${persona.tags.join(', ') || '(none)'}`,
|
|
147
|
+
'',
|
|
148
|
+
persona.body,
|
|
149
|
+
].join('\n');
|
|
150
|
+
}
|
|
151
|
+
if (action === 'create') {
|
|
152
|
+
const persona = registry.create({
|
|
153
|
+
name: requireName(args),
|
|
154
|
+
description: requireDescription(args),
|
|
155
|
+
body: readString(args.body),
|
|
156
|
+
tags: readStringList(args.tags),
|
|
157
|
+
triggers: readStringList(args.triggers),
|
|
158
|
+
source: 'agent',
|
|
159
|
+
provenance: readString(args.provenance) || 'agent-local-registry-tool',
|
|
160
|
+
});
|
|
161
|
+
return `Created Agent-local persona ${persona.id}: ${persona.name}`;
|
|
162
|
+
}
|
|
163
|
+
if (action === 'update') {
|
|
164
|
+
const persona = registry.update(requireId(args), {
|
|
165
|
+
name: readString(args.name) || undefined,
|
|
166
|
+
description: readString(args.description) || undefined,
|
|
167
|
+
body: readString(args.body) || undefined,
|
|
168
|
+
tags: args.tags === undefined ? undefined : readStringList(args.tags),
|
|
169
|
+
triggers: args.triggers === undefined ? undefined : readStringList(args.triggers),
|
|
170
|
+
provenance: readString(args.provenance) || 'agent-local-registry-tool',
|
|
171
|
+
});
|
|
172
|
+
return `Updated Agent-local persona ${persona.id}: ${persona.name}`;
|
|
173
|
+
}
|
|
174
|
+
if (action === 'use') {
|
|
175
|
+
const persona = registry.setActive(requireId(args));
|
|
176
|
+
return `Active Agent-local persona set to ${persona.id}: ${persona.name}`;
|
|
177
|
+
}
|
|
178
|
+
if (action === 'clear_active') {
|
|
179
|
+
registry.clearActive();
|
|
180
|
+
return 'Cleared active Agent-local persona.';
|
|
181
|
+
}
|
|
182
|
+
if (action === 'review') return `Reviewed Agent-local persona ${registry.markReviewed(requireId(args)).id}.`;
|
|
183
|
+
if (action === 'stale') return `Marked Agent-local persona ${registry.markStale(requireId(args), readString(args.reason)).id} stale.`;
|
|
184
|
+
throw new Error(`Action ${action} is not valid for personas.`);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function handleSkill(shellPaths: ShellPathService, action: AgentLocalRegistryAction, args: AgentLocalRegistryToolArgs): string {
|
|
188
|
+
const registry = AgentSkillRegistry.fromShellPaths(shellPaths);
|
|
189
|
+
if (action === 'list') return listSkills(registry.list(), 'Agent-local skills');
|
|
190
|
+
if (action === 'search') return listSkills(registry.search(readString(args.query)), 'Agent-local skills search');
|
|
191
|
+
if (action === 'get') {
|
|
192
|
+
const skill = registry.get(requireId(args));
|
|
193
|
+
if (!skill) return `Unknown Agent-local skill: ${readString(args.id)}`;
|
|
194
|
+
return [
|
|
195
|
+
formatSkill(skill),
|
|
196
|
+
`triggers: ${skill.triggers.join(', ') || '(manual)'}`,
|
|
197
|
+
`tags: ${skill.tags.join(', ') || '(none)'}`,
|
|
198
|
+
'',
|
|
199
|
+
skill.procedure,
|
|
200
|
+
].join('\n');
|
|
201
|
+
}
|
|
202
|
+
if (action === 'create') {
|
|
203
|
+
const skill = registry.create({
|
|
204
|
+
name: requireName(args),
|
|
205
|
+
description: requireDescription(args),
|
|
206
|
+
procedure: readString(args.procedure),
|
|
207
|
+
triggers: readStringList(args.triggers),
|
|
208
|
+
tags: readStringList(args.tags),
|
|
209
|
+
enabled: args.enabled === true,
|
|
210
|
+
source: 'agent',
|
|
211
|
+
provenance: readString(args.provenance) || 'agent-local-registry-tool',
|
|
212
|
+
});
|
|
213
|
+
return `Created Agent-local skill ${skill.id}: ${skill.name}`;
|
|
214
|
+
}
|
|
215
|
+
if (action === 'update') {
|
|
216
|
+
const skill = registry.update(requireId(args), {
|
|
217
|
+
name: readString(args.name) || undefined,
|
|
218
|
+
description: readString(args.description) || undefined,
|
|
219
|
+
procedure: readString(args.procedure) || undefined,
|
|
220
|
+
triggers: args.triggers === undefined ? undefined : readStringList(args.triggers),
|
|
221
|
+
tags: args.tags === undefined ? undefined : readStringList(args.tags),
|
|
222
|
+
provenance: readString(args.provenance) || 'agent-local-registry-tool',
|
|
223
|
+
});
|
|
224
|
+
return `Updated Agent-local skill ${skill.id}: ${skill.name}`;
|
|
225
|
+
}
|
|
226
|
+
if (action === 'enable' || action === 'disable') {
|
|
227
|
+
const skill = registry.setEnabled(requireId(args), action === 'enable');
|
|
228
|
+
return `${action === 'enable' ? 'Enabled' : 'Disabled'} Agent-local skill ${skill.id}: ${skill.name}`;
|
|
229
|
+
}
|
|
230
|
+
if (action === 'review') return `Reviewed Agent-local skill ${registry.markReviewed(requireId(args)).id}.`;
|
|
231
|
+
if (action === 'stale') return `Marked Agent-local skill ${registry.markStale(requireId(args), readString(args.reason)).id} stale.`;
|
|
232
|
+
throw new Error(`Action ${action} is not valid for skills.`);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function handleRoutine(shellPaths: ShellPathService, action: AgentLocalRegistryAction, args: AgentLocalRegistryToolArgs): string {
|
|
236
|
+
const registry = AgentRoutineRegistry.fromShellPaths(shellPaths);
|
|
237
|
+
if (action === 'list') return listRoutines(registry.list(), 'Agent-local routines');
|
|
238
|
+
if (action === 'search') return listRoutines(registry.search(readString(args.query)), 'Agent-local routines search');
|
|
239
|
+
if (action === 'get') {
|
|
240
|
+
const routine = registry.get(requireId(args));
|
|
241
|
+
if (!routine) return `Unknown Agent-local routine: ${readString(args.id)}`;
|
|
242
|
+
return [
|
|
243
|
+
formatRoutine(routine),
|
|
244
|
+
`triggers: ${routine.triggers.join(', ') || '(manual)'}`,
|
|
245
|
+
`tags: ${routine.tags.join(', ') || '(none)'}`,
|
|
246
|
+
'',
|
|
247
|
+
routine.steps,
|
|
248
|
+
].join('\n');
|
|
249
|
+
}
|
|
250
|
+
if (action === 'create') {
|
|
251
|
+
const routine = registry.create({
|
|
252
|
+
name: requireName(args),
|
|
253
|
+
description: requireDescription(args),
|
|
254
|
+
steps: readString(args.steps),
|
|
255
|
+
triggers: readStringList(args.triggers),
|
|
256
|
+
tags: readStringList(args.tags),
|
|
257
|
+
enabled: args.enabled === true,
|
|
258
|
+
source: 'agent',
|
|
259
|
+
provenance: readString(args.provenance) || 'agent-local-registry-tool',
|
|
260
|
+
});
|
|
261
|
+
return `Created Agent-local routine ${routine.id}: ${routine.name}`;
|
|
262
|
+
}
|
|
263
|
+
if (action === 'update') {
|
|
264
|
+
const routine = registry.update(requireId(args), {
|
|
265
|
+
name: readString(args.name) || undefined,
|
|
266
|
+
description: readString(args.description) || undefined,
|
|
267
|
+
steps: readString(args.steps) || undefined,
|
|
268
|
+
triggers: args.triggers === undefined ? undefined : readStringList(args.triggers),
|
|
269
|
+
tags: args.tags === undefined ? undefined : readStringList(args.tags),
|
|
270
|
+
provenance: readString(args.provenance) || 'agent-local-registry-tool',
|
|
271
|
+
});
|
|
272
|
+
return `Updated Agent-local routine ${routine.id}: ${routine.name}`;
|
|
273
|
+
}
|
|
274
|
+
if (action === 'enable' || action === 'disable') {
|
|
275
|
+
const routine = registry.setEnabled(requireId(args), action === 'enable');
|
|
276
|
+
return `${action === 'enable' ? 'Enabled' : 'Disabled'} Agent-local routine ${routine.id}: ${routine.name}`;
|
|
277
|
+
}
|
|
278
|
+
if (action === 'start') {
|
|
279
|
+
const routine = registry.markStarted(requireId(args));
|
|
280
|
+
return [
|
|
281
|
+
`Started Agent-local routine ${routine.id}: ${routine.name}`,
|
|
282
|
+
'Policy: same main conversation; no hidden background job, daemon mutation, or external side effect was started.',
|
|
283
|
+
'',
|
|
284
|
+
routine.steps,
|
|
285
|
+
].join('\n');
|
|
286
|
+
}
|
|
287
|
+
if (action === 'review') return `Reviewed Agent-local routine ${registry.markReviewed(requireId(args)).id}.`;
|
|
288
|
+
if (action === 'stale') return `Marked Agent-local routine ${registry.markStale(requireId(args), readString(args.reason)).id} stale.`;
|
|
289
|
+
throw new Error(`Action ${action} is not valid for routines.`);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export function createAgentLocalRegistryTool(shellPaths: ShellPathService): Tool {
|
|
293
|
+
return {
|
|
294
|
+
definition: {
|
|
295
|
+
name: 'agent_local_registry',
|
|
296
|
+
description: [
|
|
297
|
+
'Inspect and maintain GoodVibes Agent-local personas, skills, and routines from the main conversation.',
|
|
298
|
+
'Use this for safe self-improvement: create or refine reusable behavior, enable skills/routines, choose personas, review/stale records, and start routines in the same serial conversation.',
|
|
299
|
+
'This tool cannot delete records, create schedules, mutate the daemon, send messages, run background jobs, or delegate build work.',
|
|
300
|
+
].join(' '),
|
|
301
|
+
parameters: {
|
|
302
|
+
type: 'object',
|
|
303
|
+
properties: {
|
|
304
|
+
domain: { type: 'string', enum: [...DOMAINS] },
|
|
305
|
+
action: { type: 'string', enum: [...ACTIONS] },
|
|
306
|
+
id: { type: 'string' },
|
|
307
|
+
query: { type: 'string' },
|
|
308
|
+
name: { type: 'string' },
|
|
309
|
+
description: { type: 'string' },
|
|
310
|
+
body: { type: 'string', description: 'Persona body/instructions.' },
|
|
311
|
+
procedure: { type: 'string', description: 'Skill procedure.' },
|
|
312
|
+
steps: { type: 'string', description: 'Routine steps.' },
|
|
313
|
+
triggers: { type: 'array', items: { type: 'string' } },
|
|
314
|
+
tags: { type: 'array', items: { type: 'string' } },
|
|
315
|
+
reason: { type: 'string' },
|
|
316
|
+
enabled: { type: 'boolean' },
|
|
317
|
+
provenance: { type: 'string' },
|
|
318
|
+
},
|
|
319
|
+
required: ['domain', 'action'],
|
|
320
|
+
additionalProperties: false,
|
|
321
|
+
},
|
|
322
|
+
sideEffects: ['state'],
|
|
323
|
+
},
|
|
324
|
+
execute: async (rawArgs: unknown) => {
|
|
325
|
+
const args = rawArgs as AgentLocalRegistryToolArgs;
|
|
326
|
+
if (!isDomain(args.domain)) return registryError(`Unknown domain. Valid: ${DOMAINS.join(', ')}.`);
|
|
327
|
+
if (!isAction(args.action)) return registryError(`Unknown action. Valid: ${ACTIONS.join(', ')}.`);
|
|
328
|
+
try {
|
|
329
|
+
if (args.domain === 'persona') return registryOutput(handlePersona(shellPaths, args.action, args));
|
|
330
|
+
if (args.domain === 'skill') return registryOutput(handleSkill(shellPaths, args.action, args));
|
|
331
|
+
return registryOutput(handleRoutine(shellPaths, args.action, args));
|
|
332
|
+
} catch (error) {
|
|
333
|
+
return registryError(error instanceof Error ? error.message : String(error));
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
export function registerAgentLocalRegistryTool(registry: ToolRegistry, shellPaths: ShellPathService): void {
|
|
340
|
+
registry.register(createAgentLocalRegistryTool(shellPaths));
|
|
341
|
+
}
|
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.
|
|
9
|
+
let _version = '0.1.49';
|
|
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 {
|