@pellux/goodvibes-agent 0.1.53 → 0.1.55
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 +11 -0
- package/docs/deployment-and-services.md +1 -0
- package/docs/release-and-publishing.md +3 -2
- package/package.json +2 -5
- package/scripts/check-bun.sh +0 -2
- package/src/input/agent-workspace.ts +88 -3
- package/src/input/command-registry.ts +0 -1
- package/src/input/commands/local-runtime.ts +6 -7
- package/src/input/commands/operator-runtime.ts +0 -50
- package/src/input/commands/product-runtime.ts +3 -129
- package/src/input/commands.ts +0 -4
- package/src/main.ts +28 -1
- package/src/panels/builtin/operations.ts +0 -12
- package/src/panels/builtin/shared.ts +0 -2
- package/src/runtime/services.ts +109 -1
- package/src/version.ts +1 -1
- package/src/input/commands/eval.ts +0 -217
- package/src/panels/eval-panel.ts +0 -399
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to GoodVibes Agent will be recorded here.
|
|
4
4
|
|
|
5
|
+
## 0.1.55 - 2026-05-31
|
|
6
|
+
|
|
7
|
+
- d8f4eee Remove copied developer audit surfaces
|
|
8
|
+
|
|
9
|
+
## 0.1.54 - 2026-05-31
|
|
10
|
+
|
|
11
|
+
- dc1a290 Keep release docs version-neutral
|
|
12
|
+
- 07eb275 Stabilize Bun package install smoke
|
|
13
|
+
- d5da8fb Fix Bun global TUI launch smoke
|
|
14
|
+
- 883a11c Add exact-confirm local library delete flow
|
|
15
|
+
|
|
5
16
|
## 0.1.53 - 2026-05-31
|
|
6
17
|
|
|
7
18
|
- 77ad0cf Add local library edit workspace flow
|
|
@@ -27,6 +27,7 @@ The executable is backed by TypeScript-authored source with a Bun shebang. Packa
|
|
|
27
27
|
- `goodvibes-agent --help`
|
|
28
28
|
- `goodvibes-agent --version`
|
|
29
29
|
- `goodvibes-agent status --json`
|
|
30
|
+
- `goodvibes-agent` launches the TUI in a real PTY
|
|
30
31
|
- `goodvibes-agent smoke --json` when that command is available in the baseline being tested
|
|
31
32
|
|
|
32
33
|
## External Daemon Connection
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Release And Publishing
|
|
2
2
|
|
|
3
|
-
GoodVibes Agent
|
|
3
|
+
GoodVibes Agent's current installable public alpha version is recorded in `package.json` and `CHANGELOG.md`.
|
|
4
4
|
|
|
5
5
|
## Package Identity
|
|
6
6
|
|
|
@@ -21,7 +21,7 @@ bun run typecheck
|
|
|
21
21
|
bun run build
|
|
22
22
|
bun run package:install-check
|
|
23
23
|
bun run publish:check
|
|
24
|
-
|
|
24
|
+
bun pm pack --dry-run
|
|
25
25
|
git diff --check
|
|
26
26
|
```
|
|
27
27
|
|
|
@@ -34,6 +34,7 @@ Also run the package install smoke from a packed artifact. It must prove:
|
|
|
34
34
|
- the Bun shebang survives pack/install
|
|
35
35
|
- `goodvibes-agent --help` works
|
|
36
36
|
- `goodvibes-agent --version` reports the package version
|
|
37
|
+
- the installed TUI launches in a PTY and does not exit immediately
|
|
37
38
|
- daemon-backed commands fail clearly when the external daemon is unavailable or unauthenticated
|
|
38
39
|
- no token value is printed
|
|
39
40
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pellux/goodvibes-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.55",
|
|
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",
|
|
@@ -65,10 +65,7 @@
|
|
|
65
65
|
"architecture:check": "bun run scripts/check-architecture.ts",
|
|
66
66
|
"foundation:artifacts": "bun run scripts/export-foundation-artifacts.ts",
|
|
67
67
|
"verification:ledger": "bun run scripts/verification-ledger.ts",
|
|
68
|
-
"verification:live": "bun run scripts/verify-live.ts"
|
|
69
|
-
"eval:gate": "bun run scripts/eval-gate.ts",
|
|
70
|
-
"eval:gate:verbose": "bun run scripts/eval-gate.ts --verbose",
|
|
71
|
-
"eval:baseline": "bun run scripts/eval-gate.ts --save-baseline"
|
|
68
|
+
"verification:live": "bun run scripts/verify-live.ts"
|
|
72
69
|
},
|
|
73
70
|
"license": "MIT",
|
|
74
71
|
"repository": {
|
package/scripts/check-bun.sh
CHANGED
|
@@ -8,8 +8,6 @@ goodvibes-agent requires Bun.
|
|
|
8
8
|
Install Bun first, then install GoodVibes Agent from the npm registry with:
|
|
9
9
|
|
|
10
10
|
bun add -g @pellux/goodvibes-agent
|
|
11
|
-
|
|
12
|
-
npm install -g @pellux/goodvibes-agent also works, but Bun must already be installed and available on PATH.
|
|
13
11
|
EOF
|
|
14
12
|
exit 1
|
|
15
13
|
fi
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { InputToken } from '@pellux/goodvibes-sdk/platform/core';
|
|
2
|
+
import type { ShellPathService } from '@/runtime/index.ts';
|
|
2
3
|
import { basename, sep } from 'node:path';
|
|
3
4
|
import type { CommandContext } from './command-registry.ts';
|
|
4
5
|
import { AgentPersonaRegistry, type AgentPersonaRecord } from '../agent/persona-registry.ts';
|
|
@@ -29,15 +30,18 @@ export type AgentWorkspaceLocalOperation =
|
|
|
29
30
|
| 'persona-use'
|
|
30
31
|
| 'persona-review'
|
|
31
32
|
| 'persona-clear'
|
|
33
|
+
| 'persona-delete'
|
|
32
34
|
| 'skill-edit'
|
|
33
35
|
| 'skill-enable'
|
|
34
36
|
| 'skill-disable'
|
|
35
37
|
| 'skill-review'
|
|
38
|
+
| 'skill-delete'
|
|
36
39
|
| 'routine-edit'
|
|
37
40
|
| 'routine-start'
|
|
38
41
|
| 'routine-enable'
|
|
39
42
|
| 'routine-disable'
|
|
40
|
-
| 'routine-review'
|
|
43
|
+
| 'routine-review'
|
|
44
|
+
| 'routine-delete';
|
|
41
45
|
|
|
42
46
|
export interface AgentWorkspaceEditorField {
|
|
43
47
|
readonly id: string;
|
|
@@ -50,7 +54,7 @@ export interface AgentWorkspaceEditorField {
|
|
|
50
54
|
|
|
51
55
|
export interface AgentWorkspaceLocalEditor {
|
|
52
56
|
readonly kind: AgentWorkspaceLocalEditorKind;
|
|
53
|
-
readonly mode: 'create' | 'update';
|
|
57
|
+
readonly mode: 'create' | 'update' | 'delete';
|
|
54
58
|
readonly recordId?: string;
|
|
55
59
|
readonly title: string;
|
|
56
60
|
readonly fields: readonly AgentWorkspaceEditorField[];
|
|
@@ -542,6 +546,7 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
|
|
|
542
546
|
{ id: 'personas-use', label: 'Use selected', detail: 'Activate the selected local persona for future main-conversation turns.', localKind: 'persona', localOperation: 'persona-use', kind: 'local-operation', safety: 'safe' },
|
|
543
547
|
{ id: 'personas-review', label: 'Review selected', detail: 'Mark the selected local persona reviewed after inspecting it.', localKind: 'persona', localOperation: 'persona-review', kind: 'local-operation', safety: 'safe' },
|
|
544
548
|
{ id: 'personas-clear', label: 'Clear active persona', detail: 'Return to the default Agent policy without deleting any persona.', localKind: 'persona', localOperation: 'persona-clear', kind: 'local-operation', safety: 'safe' },
|
|
549
|
+
{ id: 'personas-delete', label: 'Delete selected', detail: 'Open a confirmation form before deleting the selected local persona.', localKind: 'persona', localOperation: 'persona-delete', kind: 'local-operation', safety: 'safe' },
|
|
545
550
|
],
|
|
546
551
|
},
|
|
547
552
|
{
|
|
@@ -560,6 +565,7 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
|
|
|
560
565
|
{ id: 'skills-enable', label: 'Enable selected', detail: 'Enable the selected local Agent skill for future main-conversation guidance.', localKind: 'skill', localOperation: 'skill-enable', kind: 'local-operation', safety: 'safe' },
|
|
561
566
|
{ id: 'skills-disable', label: 'Disable selected', detail: 'Disable the selected local Agent skill without deleting it.', localKind: 'skill', localOperation: 'skill-disable', kind: 'local-operation', safety: 'safe' },
|
|
562
567
|
{ id: 'skills-review', label: 'Review selected', detail: 'Mark the selected local skill reviewed after inspecting it.', localKind: 'skill', localOperation: 'skill-review', kind: 'local-operation', safety: 'safe' },
|
|
568
|
+
{ id: 'skills-delete', label: 'Delete selected', detail: 'Open a confirmation form before deleting the selected local Agent skill.', localKind: 'skill', localOperation: 'skill-delete', kind: 'local-operation', safety: 'safe' },
|
|
563
569
|
],
|
|
564
570
|
},
|
|
565
571
|
{
|
|
@@ -579,6 +585,7 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
|
|
|
579
585
|
{ id: 'routines-enable', label: 'Enable selected', detail: 'Enable the selected routine for future main-conversation guidance.', localKind: 'routine', localOperation: 'routine-enable', kind: 'local-operation', safety: 'safe' },
|
|
580
586
|
{ id: 'routines-disable', label: 'Disable selected', detail: 'Disable the selected routine without deleting it.', localKind: 'routine', localOperation: 'routine-disable', kind: 'local-operation', safety: 'safe' },
|
|
581
587
|
{ id: 'routines-review', label: 'Review selected', detail: 'Mark the selected local routine reviewed after inspecting it.', localKind: 'routine', localOperation: 'routine-review', kind: 'local-operation', safety: 'safe' },
|
|
588
|
+
{ id: 'routines-delete', label: 'Delete selected', detail: 'Open a confirmation form before deleting the selected local Agent routine.', localKind: 'routine', localOperation: 'routine-delete', kind: 'local-operation', safety: 'safe' },
|
|
582
589
|
{ id: 'routines-promote', label: 'Promote to schedule', detail: 'Create an external daemon schedule from a reviewed routine only with real timing and --yes.', command: '/routines promote <id> --cron <expr> --yes', kind: 'command', safety: 'safe' },
|
|
583
590
|
{ id: 'routines-receipts', label: 'Promotion receipts', detail: 'Inspect local redacted routine schedule promotion receipts.', command: '/routines receipts', kind: 'command', safety: 'read-only' },
|
|
584
591
|
],
|
|
@@ -740,6 +747,21 @@ function createRoutineUpdateEditor(record: AgentRoutineRecord): AgentWorkspaceLo
|
|
|
740
747
|
};
|
|
741
748
|
}
|
|
742
749
|
|
|
750
|
+
function createDeleteEditor(kind: AgentWorkspaceLocalEditorKind, item: AgentWorkspaceLocalLibraryItem): AgentWorkspaceLocalEditor {
|
|
751
|
+
const label = kind[0]!.toUpperCase() + kind.slice(1);
|
|
752
|
+
return {
|
|
753
|
+
kind,
|
|
754
|
+
mode: 'delete',
|
|
755
|
+
recordId: item.id,
|
|
756
|
+
title: `Delete ${label}`,
|
|
757
|
+
selectedFieldIndex: 0,
|
|
758
|
+
message: `Type ${item.id} exactly to delete ${item.name}. This only changes the Agent-local registry.`,
|
|
759
|
+
fields: [
|
|
760
|
+
{ id: 'confirm', label: 'Confirm id', value: '', required: true, multiline: false, hint: `Type ${item.id} exactly.` },
|
|
761
|
+
],
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
|
|
743
765
|
function splitList(value: string): string[] {
|
|
744
766
|
return value.split(',').map((part) => part.trim()).filter(Boolean);
|
|
745
767
|
}
|
|
@@ -1148,6 +1170,8 @@ export class AgentWorkspace {
|
|
|
1148
1170
|
} else if (operation === 'persona-review') {
|
|
1149
1171
|
AgentPersonaRegistry.fromShellPaths(shellPaths).markReviewed(selected.id);
|
|
1150
1172
|
this.finishLocalOperation('persona', `Reviewed persona ${selected.name}`, `${selected.name} is marked reviewed.`);
|
|
1173
|
+
} else if (operation === 'persona-delete') {
|
|
1174
|
+
this.openDeleteEditor('persona', selected);
|
|
1151
1175
|
} else if (operation === 'skill-edit') {
|
|
1152
1176
|
const skill = AgentSkillRegistry.fromShellPaths(shellPaths).get(selected.id);
|
|
1153
1177
|
if (!skill) throw new Error(`Unknown skill: ${selected.id}`);
|
|
@@ -1168,6 +1192,8 @@ export class AgentWorkspace {
|
|
|
1168
1192
|
} else if (operation === 'skill-review') {
|
|
1169
1193
|
AgentSkillRegistry.fromShellPaths(shellPaths).markReviewed(selected.id);
|
|
1170
1194
|
this.finishLocalOperation('skill', `Reviewed skill ${selected.name}`, `${selected.name} is marked reviewed.`);
|
|
1195
|
+
} else if (operation === 'skill-delete') {
|
|
1196
|
+
this.openDeleteEditor('skill', selected);
|
|
1171
1197
|
} else if (operation === 'routine-edit') {
|
|
1172
1198
|
const routine = AgentRoutineRegistry.fromShellPaths(shellPaths).get(selected.id);
|
|
1173
1199
|
if (!routine) throw new Error(`Unknown routine: ${selected.id}`);
|
|
@@ -1188,9 +1214,11 @@ export class AgentWorkspace {
|
|
|
1188
1214
|
} else if (operation === 'routine-disable') {
|
|
1189
1215
|
AgentRoutineRegistry.fromShellPaths(shellPaths).setEnabled(selected.id, false);
|
|
1190
1216
|
this.finishLocalOperation('routine', `Disabled routine ${selected.name}`, `${selected.name} remains saved but is no longer injected into guidance.`);
|
|
1191
|
-
} else {
|
|
1217
|
+
} else if (operation === 'routine-review') {
|
|
1192
1218
|
AgentRoutineRegistry.fromShellPaths(shellPaths).markReviewed(selected.id);
|
|
1193
1219
|
this.finishLocalOperation('routine', `Reviewed routine ${selected.name}`, `${selected.name} is marked reviewed.`);
|
|
1220
|
+
} else {
|
|
1221
|
+
this.openDeleteEditor('routine', selected);
|
|
1194
1222
|
}
|
|
1195
1223
|
} catch (error) {
|
|
1196
1224
|
const detail = error instanceof Error ? error.message : String(error);
|
|
@@ -1221,6 +1249,17 @@ export class AgentWorkspace {
|
|
|
1221
1249
|
};
|
|
1222
1250
|
}
|
|
1223
1251
|
|
|
1252
|
+
private openDeleteEditor(kind: AgentWorkspaceLocalEditorKind, selected: AgentWorkspaceLocalLibraryItem): void {
|
|
1253
|
+
this.localEditor = createDeleteEditor(kind, selected);
|
|
1254
|
+
this.status = `Confirm deletion for ${selected.name}.`;
|
|
1255
|
+
this.lastActionResult = {
|
|
1256
|
+
kind: 'guidance',
|
|
1257
|
+
title: this.localEditor.title,
|
|
1258
|
+
detail: this.localEditor.message,
|
|
1259
|
+
safety: 'safe',
|
|
1260
|
+
};
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1224
1263
|
private replaceEditorField(index: number, value: string, message: string): void {
|
|
1225
1264
|
const editor = this.localEditor;
|
|
1226
1265
|
if (!editor) return;
|
|
@@ -1265,6 +1304,10 @@ export class AgentWorkspace {
|
|
|
1265
1304
|
return;
|
|
1266
1305
|
}
|
|
1267
1306
|
try {
|
|
1307
|
+
if (editor.mode === 'delete') {
|
|
1308
|
+
this.submitLocalDeleteEditor(shellPaths, editor);
|
|
1309
|
+
return;
|
|
1310
|
+
}
|
|
1268
1311
|
if (editor.kind === 'persona') {
|
|
1269
1312
|
const registry = AgentPersonaRegistry.fromShellPaths(shellPaths);
|
|
1270
1313
|
if (editor.mode === 'update' && editor.recordId) {
|
|
@@ -1358,6 +1401,29 @@ export class AgentWorkspace {
|
|
|
1358
1401
|
}
|
|
1359
1402
|
}
|
|
1360
1403
|
|
|
1404
|
+
private submitLocalDeleteEditor(shellPaths: ShellPathService, editor: AgentWorkspaceLocalEditor): void {
|
|
1405
|
+
const expectedId = editor.recordId ?? '';
|
|
1406
|
+
const confirmedId = this.editorField('confirm');
|
|
1407
|
+
if (!expectedId || confirmedId !== expectedId) {
|
|
1408
|
+
this.localEditor = {
|
|
1409
|
+
...editor,
|
|
1410
|
+
message: `Deletion not confirmed. Type ${expectedId} exactly, then press Enter.`,
|
|
1411
|
+
};
|
|
1412
|
+
this.status = 'Deletion not confirmed.';
|
|
1413
|
+
return;
|
|
1414
|
+
}
|
|
1415
|
+
if (editor.kind === 'persona') {
|
|
1416
|
+
const removed = AgentPersonaRegistry.fromShellPaths(shellPaths).deletePersona(expectedId);
|
|
1417
|
+
this.finishLocalDelete(editor.kind, removed.id, removed.name);
|
|
1418
|
+
} else if (editor.kind === 'skill') {
|
|
1419
|
+
const removed = AgentSkillRegistry.fromShellPaths(shellPaths).deleteSkill(expectedId);
|
|
1420
|
+
this.finishLocalDelete(editor.kind, removed.id, removed.name);
|
|
1421
|
+
} else {
|
|
1422
|
+
const removed = AgentRoutineRegistry.fromShellPaths(shellPaths).deleteRoutine(expectedId);
|
|
1423
|
+
this.finishLocalDelete(editor.kind, removed.id, removed.name);
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1361
1427
|
private finishLocalEditor(kind: AgentWorkspaceLocalEditorKind, id: string, name: string, verb: 'Created' | 'Updated'): void {
|
|
1362
1428
|
this.localEditor = null;
|
|
1363
1429
|
const categoryId = editorCategoryId(kind);
|
|
@@ -1376,6 +1442,25 @@ export class AgentWorkspace {
|
|
|
1376
1442
|
};
|
|
1377
1443
|
this.clampSelection();
|
|
1378
1444
|
}
|
|
1445
|
+
|
|
1446
|
+
private finishLocalDelete(kind: AgentWorkspaceLocalEditorKind, id: string, name: string): void {
|
|
1447
|
+
this.localEditor = null;
|
|
1448
|
+
const categoryId = editorCategoryId(kind);
|
|
1449
|
+
const categoryIndex = this.categories.findIndex((category) => category.id === categoryId);
|
|
1450
|
+
if (categoryIndex >= 0) {
|
|
1451
|
+
this.selectedCategoryIndex = categoryIndex;
|
|
1452
|
+
this.selectedActionIndex = 0;
|
|
1453
|
+
}
|
|
1454
|
+
this.runtimeSnapshot = this.context ? buildAgentWorkspaceRuntimeSnapshot(this.context) : this.runtimeSnapshot;
|
|
1455
|
+
this.status = `Deleted ${kind}: ${name}.`;
|
|
1456
|
+
this.lastActionResult = {
|
|
1457
|
+
kind: 'refreshed',
|
|
1458
|
+
title: `Deleted ${kind}`,
|
|
1459
|
+
detail: `${name} (${id}) was removed from the Agent-local ${categoryId} registry.`,
|
|
1460
|
+
safety: 'safe',
|
|
1461
|
+
};
|
|
1462
|
+
this.clampSelection();
|
|
1463
|
+
}
|
|
1379
1464
|
}
|
|
1380
1465
|
|
|
1381
1466
|
export function handleAgentWorkspaceToken(
|
|
@@ -177,7 +177,6 @@ export interface CommandOpsServices
|
|
|
177
177
|
export interface CommandExtensionRegistryServices {
|
|
178
178
|
readonly toolRegistry: ToolRegistry;
|
|
179
179
|
readonly mcpRegistry: McpRegistry;
|
|
180
|
-
readonly evalRegistry?: import('../panels/eval-panel.ts').EvalRegistry;
|
|
181
180
|
}
|
|
182
181
|
|
|
183
182
|
export interface CommandExtensionServices
|
|
@@ -67,7 +67,7 @@ export function registerLocalRuntimeCommands(registry: CommandRegistry): void {
|
|
|
67
67
|
registry.register({
|
|
68
68
|
name: 'tools',
|
|
69
69
|
aliases: ['t'],
|
|
70
|
-
description: 'List available tools and review
|
|
70
|
+
description: 'List available tools and review tool safety/status',
|
|
71
71
|
usage: '[review|panel]',
|
|
72
72
|
handler(args, ctx) {
|
|
73
73
|
const sub = (args[0] ?? '').toLowerCase();
|
|
@@ -79,12 +79,11 @@ export function registerLocalRuntimeCommands(registry: CommandRegistry): void {
|
|
|
79
79
|
}
|
|
80
80
|
if (sub === 'review') {
|
|
81
81
|
ctx.print([
|
|
82
|
-
'Tool
|
|
83
|
-
'
|
|
84
|
-
' Read
|
|
85
|
-
'
|
|
86
|
-
'
|
|
87
|
-
' Use /approval review shell or /approval review file when you need the action-specific why-prompted posture.',
|
|
82
|
+
'Tool Status',
|
|
83
|
+
' Tools are available for the main Agent conversation.',
|
|
84
|
+
' Read-only actions can run directly; writes, destructive changes, network effects, service changes, and external side effects require explicit user intent or approval.',
|
|
85
|
+
' Recent tool activity and approval posture are available in the tools and approvals views.',
|
|
86
|
+
' Build/fix/review work should be delegated explicitly with /delegate.',
|
|
88
87
|
].join('\n'));
|
|
89
88
|
}
|
|
90
89
|
return;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { CommandRegistry } from '../command-registry.ts';
|
|
2
2
|
import type { ProfileData } from '@pellux/goodvibes-sdk/platform/profiles';
|
|
3
|
-
import { ToolContractVerifier } from '@/runtime/index.ts';
|
|
4
3
|
import type { ReplaySnapshotInput } from '@/runtime/index.ts';
|
|
5
4
|
import { logger } from '@pellux/goodvibes-sdk/platform/utils';
|
|
6
5
|
import { registerOperatorPanelCommand } from './operator-panel-runtime.ts';
|
|
@@ -283,55 +282,6 @@ export function registerOperatorRuntimeCommands(registry: CommandRegistry): void
|
|
|
283
282
|
},
|
|
284
283
|
});
|
|
285
284
|
|
|
286
|
-
registry.register({
|
|
287
|
-
name: 'tool',
|
|
288
|
-
description: 'Tool contract verification — verify registered tool contracts',
|
|
289
|
-
usage: 'verify <name> | verify-all | contract show <name>',
|
|
290
|
-
argsHint: 'verify <name> | verify-all | contract show <name>',
|
|
291
|
-
handler(args, ctx) {
|
|
292
|
-
const sub = args[0];
|
|
293
|
-
if (sub === 'verify' && args[1]) {
|
|
294
|
-
const result = ctx.extensions.toolRegistry.verifyContract(args[1]);
|
|
295
|
-
if (!result) {
|
|
296
|
-
ctx.print(`[tool verify] Tool '${args[1]}' is not registered.`);
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
299
|
-
ctx.print(ToolContractVerifier.formatResult(result));
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
if (sub === 'verify-all') {
|
|
303
|
-
ctx.print(ToolContractVerifier.formatAllResults(ctx.extensions.toolRegistry.verifyAllContracts()));
|
|
304
|
-
return;
|
|
305
|
-
}
|
|
306
|
-
if (sub === 'contract' && args[1] === 'show' && args[2]) {
|
|
307
|
-
const toolName = args[2];
|
|
308
|
-
const result = ctx.extensions.toolRegistry.verifyContract(toolName);
|
|
309
|
-
if (!result) {
|
|
310
|
-
ctx.print(`[tool contract show] Tool '${toolName}' is not registered.`);
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
const lines: string[] = [ToolContractVerifier.formatResult(result)];
|
|
314
|
-
const tool = ctx.extensions.toolRegistry.list().find((t) => t.definition.name === toolName);
|
|
315
|
-
if (tool) {
|
|
316
|
-
lines.push('');
|
|
317
|
-
lines.push('Tool Definition:');
|
|
318
|
-
lines.push(` Name: ${tool.definition.name}`);
|
|
319
|
-
lines.push(` Description: ${tool.definition.description}`);
|
|
320
|
-
lines.push(` Parameters: ${JSON.stringify(tool.definition.parameters, null, 2).replace(/\n/g, '\n ')}`);
|
|
321
|
-
}
|
|
322
|
-
ctx.print(lines.join('\n'));
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
ctx.print(
|
|
327
|
-
'Usage: /tool <subcommand>\n'
|
|
328
|
-
+ ' /tool verify <name> — verify contract for a specific registered tool\n'
|
|
329
|
-
+ ' /tool verify-all — verify contracts for all registered tools\n'
|
|
330
|
-
+ ' /tool contract show <name> — show full contract details for a tool'
|
|
331
|
-
);
|
|
332
|
-
},
|
|
333
|
-
});
|
|
334
|
-
|
|
335
285
|
registry.register({
|
|
336
286
|
name: 'forensics',
|
|
337
287
|
aliases: ['foren'],
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { dirname
|
|
1
|
+
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
3
|
import type { CommandContext, CommandRegistry } from '../command-registry.ts';
|
|
4
|
-
import {
|
|
5
|
-
import { BUILTIN_SUITES } from '@/runtime/index.ts';
|
|
6
|
-
import { requireEcosystemCatalogPaths, requireReadModels, requireSecretsManager, requireServiceRegistry, requireShellPaths } from './runtime-services.ts';
|
|
4
|
+
import { requireReadModels, requireSecretsManager, requireServiceRegistry, requireShellPaths } from './runtime-services.ts';
|
|
7
5
|
import { requireYesFlag, stripYesFlag } from './confirmation.ts';
|
|
8
6
|
|
|
9
7
|
interface TrustReviewBundle {
|
|
@@ -29,29 +27,6 @@ interface TrustReviewBundle {
|
|
|
29
27
|
};
|
|
30
28
|
}
|
|
31
29
|
|
|
32
|
-
interface ReleaseBundle {
|
|
33
|
-
readonly version: 1;
|
|
34
|
-
readonly capturedAt: number;
|
|
35
|
-
readonly runtime: {
|
|
36
|
-
readonly provider: string;
|
|
37
|
-
readonly model: string;
|
|
38
|
-
readonly sessionId: string;
|
|
39
|
-
};
|
|
40
|
-
readonly evalSuites: readonly string[];
|
|
41
|
-
readonly incidentCount: number;
|
|
42
|
-
readonly remote: {
|
|
43
|
-
readonly pools: number;
|
|
44
|
-
readonly contracts: number;
|
|
45
|
-
readonly artifacts: number;
|
|
46
|
-
};
|
|
47
|
-
readonly ecosystem: {
|
|
48
|
-
readonly pluginCatalog: number;
|
|
49
|
-
readonly skillCatalog: number;
|
|
50
|
-
readonly installedPlugins: number;
|
|
51
|
-
readonly installedSkills: number;
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
30
|
function countByMode<T extends string>(values: readonly T[], mode: T): number {
|
|
56
31
|
return values.filter((value) => value === mode).length;
|
|
57
32
|
}
|
|
@@ -112,46 +87,6 @@ function inspectTrustBundle(path: string): string {
|
|
|
112
87
|
].join('\n');
|
|
113
88
|
}
|
|
114
89
|
|
|
115
|
-
function buildReleaseBundle(ctx: Parameters<NonNullable<CommandRegistry['register']>>[0]['handler'] extends (args: string[], context: infer C) => unknown ? C : never): ReleaseBundle {
|
|
116
|
-
const remoteRuntime = ctx.ops.remoteRuntime;
|
|
117
|
-
const incidents = ctx.extensions.forensicsRegistry?.getAll() ?? [];
|
|
118
|
-
const ecosystemPaths = requireEcosystemCatalogPaths(ctx);
|
|
119
|
-
return {
|
|
120
|
-
version: 1,
|
|
121
|
-
capturedAt: Date.now(),
|
|
122
|
-
runtime: {
|
|
123
|
-
provider: ctx.session.runtime.provider,
|
|
124
|
-
model: ctx.session.runtime.model,
|
|
125
|
-
sessionId: ctx.session.runtime.sessionId,
|
|
126
|
-
},
|
|
127
|
-
evalSuites: Object.keys(BUILTIN_SUITES),
|
|
128
|
-
incidentCount: incidents.length,
|
|
129
|
-
remote: {
|
|
130
|
-
pools: remoteRuntime?.listPools().length ?? 0,
|
|
131
|
-
contracts: remoteRuntime?.listContracts().length ?? 0,
|
|
132
|
-
artifacts: remoteRuntime?.listArtifacts().length ?? 0,
|
|
133
|
-
},
|
|
134
|
-
ecosystem: {
|
|
135
|
-
pluginCatalog: loadEcosystemCatalog('plugin', ecosystemPaths).length,
|
|
136
|
-
skillCatalog: loadEcosystemCatalog('skill', ecosystemPaths).length,
|
|
137
|
-
installedPlugins: listInstalledEcosystemEntries('plugin', ecosystemPaths).length,
|
|
138
|
-
installedSkills: listInstalledEcosystemEntries('skill', ecosystemPaths).length,
|
|
139
|
-
},
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function inspectReleaseBundle(path: string): string {
|
|
144
|
-
const parsed = JSON.parse(readFileSync(path, 'utf-8')) as ReleaseBundle;
|
|
145
|
-
return [
|
|
146
|
-
'Release Bundle Review',
|
|
147
|
-
` provider/model: ${parsed.runtime.provider || '(unset)'}/${parsed.runtime.model || '(unset)'}`,
|
|
148
|
-
` eval suites: ${parsed.evalSuites.length}`,
|
|
149
|
-
` incidents: ${parsed.incidentCount}`,
|
|
150
|
-
` remote pools/contracts/artifacts: ${parsed.remote.pools}/${parsed.remote.contracts}/${parsed.remote.artifacts}`,
|
|
151
|
-
` ecosystem catalog plugins/skills: ${parsed.ecosystem.pluginCatalog}/${parsed.ecosystem.skillCatalog}`,
|
|
152
|
-
].join('\n');
|
|
153
|
-
}
|
|
154
|
-
|
|
155
90
|
export function registerProductRuntimeCommands(registry: CommandRegistry): void {
|
|
156
91
|
registry.register({
|
|
157
92
|
name: 'trust',
|
|
@@ -314,65 +249,4 @@ export function registerProductRuntimeCommands(registry: CommandRegistry): void
|
|
|
314
249
|
},
|
|
315
250
|
});
|
|
316
251
|
|
|
317
|
-
registry.register({
|
|
318
|
-
name: 'release',
|
|
319
|
-
description: 'Package certification and release-readiness operations',
|
|
320
|
-
usage: '[review|checklist|bundle export <path> --yes|bundle inspect <path>]',
|
|
321
|
-
handler(args, ctx) {
|
|
322
|
-
const parsed = stripYesFlag(args);
|
|
323
|
-
const commandArgs = [...parsed.rest];
|
|
324
|
-
const shellPaths = requireShellPaths(ctx);
|
|
325
|
-
const sub = commandArgs[0] ?? 'review';
|
|
326
|
-
if (sub === 'review') {
|
|
327
|
-
const bundle = buildReleaseBundle(ctx);
|
|
328
|
-
ctx.print([
|
|
329
|
-
'Release Review',
|
|
330
|
-
` provider/model: ${bundle.runtime.provider || '(unset)'}/${bundle.runtime.model || '(unset)'}`,
|
|
331
|
-
` eval suites: ${bundle.evalSuites.length}`,
|
|
332
|
-
` incidents: ${bundle.incidentCount}`,
|
|
333
|
-
` remote pools/contracts/artifacts: ${bundle.remote.pools}/${bundle.remote.contracts}/${bundle.remote.artifacts}`,
|
|
334
|
-
` ecosystem catalog plugins/skills: ${bundle.ecosystem.pluginCatalog}/${bundle.ecosystem.skillCatalog}`,
|
|
335
|
-
` installed plugins/skills: ${bundle.ecosystem.installedPlugins}/${bundle.ecosystem.installedSkills}`,
|
|
336
|
-
].join('\n'));
|
|
337
|
-
return;
|
|
338
|
-
}
|
|
339
|
-
if (sub === 'checklist') {
|
|
340
|
-
ctx.print([
|
|
341
|
-
'Release Checklist',
|
|
342
|
-
' 1. Run /setup review and /setup doctor',
|
|
343
|
-
' 2. Run /security review and /trust review',
|
|
344
|
-
' 3. Run /policy preflight and /policy simulate',
|
|
345
|
-
' 4. Run /eval gate <suite> --yes for required certification suites',
|
|
346
|
-
' 5. Review /incident latest and /bridge status',
|
|
347
|
-
' 6. Export /release bundle export <path> --yes for release evidence',
|
|
348
|
-
].join('\n'));
|
|
349
|
-
return;
|
|
350
|
-
}
|
|
351
|
-
if (sub === 'bundle') {
|
|
352
|
-
const mode = commandArgs[1];
|
|
353
|
-
const pathArg = commandArgs[2];
|
|
354
|
-
if ((mode === 'export' || mode === 'inspect') && !pathArg) {
|
|
355
|
-
ctx.print(`Usage: /release bundle ${mode} <path>${mode === 'export' ? ' --yes' : ''}`);
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
|
-
if (mode === 'export') {
|
|
359
|
-
if (!parsed.yes) {
|
|
360
|
-
requireYesFlag(ctx, `export release bundle to ${pathArg}`, '/release bundle export <path> --yes');
|
|
361
|
-
return;
|
|
362
|
-
}
|
|
363
|
-
const bundle = buildReleaseBundle(ctx);
|
|
364
|
-
const targetPath = shellPaths.resolveWorkspacePath(pathArg!);
|
|
365
|
-
mkdirSync(dirname(targetPath), { recursive: true });
|
|
366
|
-
writeFileSync(targetPath, JSON.stringify(bundle, null, 2) + '\n', 'utf-8');
|
|
367
|
-
ctx.print(`Release bundle exported to ${targetPath}`);
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
if (mode === 'inspect') {
|
|
371
|
-
ctx.print(inspectReleaseBundle(shellPaths.resolveWorkspacePath(pathArg!)));
|
|
372
|
-
return;
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
ctx.print('Usage: /release [review|checklist|bundle export <path> --yes|bundle inspect <path>]');
|
|
376
|
-
},
|
|
377
|
-
});
|
|
378
252
|
}
|
package/src/input/commands.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { CommandRegistry } from './command-registry.ts';
|
|
2
2
|
import { policyCommand } from './commands/policy.ts';
|
|
3
3
|
import { providerCommand } from './commands/provider.ts';
|
|
4
|
-
import { evalCommand } from './commands/eval.ts';
|
|
5
4
|
import { sessionCommand } from './commands/session.ts';
|
|
6
5
|
import { recallCommand } from './commands/memory.ts';
|
|
7
6
|
import { knowledgeCommand } from './commands/knowledge.ts';
|
|
@@ -126,9 +125,6 @@ export function registerBuiltinCommands(registry: CommandRegistry): void {
|
|
|
126
125
|
// ── /provider ─────────────────────────────────────────────────────────────
|
|
127
126
|
registry.register(providerCommand);
|
|
128
127
|
|
|
129
|
-
// ── /eval ─────────────────────────────────────────────────────────────────
|
|
130
|
-
registry.register(evalCommand);
|
|
131
|
-
|
|
132
128
|
// ── /session ─────────────────────────────────────────────────────────────
|
|
133
129
|
registry.register(sessionCommand);
|
|
134
130
|
|
package/src/main.ts
CHANGED
|
@@ -767,4 +767,31 @@ async function main() {
|
|
|
767
767
|
|
|
768
768
|
}
|
|
769
769
|
|
|
770
|
-
|
|
770
|
+
function formatFatalStartupError(error: unknown): string {
|
|
771
|
+
if (error instanceof Error) {
|
|
772
|
+
return error.stack ?? error.message;
|
|
773
|
+
}
|
|
774
|
+
if (typeof error === 'string') {
|
|
775
|
+
return error;
|
|
776
|
+
}
|
|
777
|
+
try {
|
|
778
|
+
return JSON.stringify(error);
|
|
779
|
+
} catch {
|
|
780
|
+
return String(error);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
main().catch((err: unknown) => {
|
|
785
|
+
const detail = formatFatalStartupError(err);
|
|
786
|
+
try {
|
|
787
|
+
logger.error('Fatal error', { error: detail });
|
|
788
|
+
} catch {
|
|
789
|
+
// Startup diagnostics must never hide the original launch failure.
|
|
790
|
+
}
|
|
791
|
+
try {
|
|
792
|
+
process.stderr.write(`goodvibes-agent failed to launch:\n${detail}\n`);
|
|
793
|
+
} catch {
|
|
794
|
+
// Ignore secondary stderr failures during process teardown.
|
|
795
|
+
}
|
|
796
|
+
process.exit(1);
|
|
797
|
+
});
|
|
@@ -27,7 +27,6 @@ import { DebugPanel } from '../debug-panel.ts';
|
|
|
27
27
|
import { IncidentReviewPanel } from '../incident-review-panel.ts';
|
|
28
28
|
import { ForensicsPanel } from '../forensics-panel.ts';
|
|
29
29
|
import { PolicyPanel } from '../policy-panel.ts';
|
|
30
|
-
import { EvalPanel } from '../eval-panel.ts';
|
|
31
30
|
import { createProviderAccountSnapshotQuery } from '../provider-account-snapshot.ts';
|
|
32
31
|
import {
|
|
33
32
|
createEnvironmentVariableQuery,
|
|
@@ -335,15 +334,4 @@ export function registerOperationsPanels(manager: PanelManager, deps: ResolvedBu
|
|
|
335
334
|
factory: () => new PolicyPanel(deps.policyRuntimeState),
|
|
336
335
|
});
|
|
337
336
|
|
|
338
|
-
if (deps.evalRegistry) {
|
|
339
|
-
const { evalRegistry } = deps;
|
|
340
|
-
manager.registerType({
|
|
341
|
-
id: 'eval',
|
|
342
|
-
name: 'Eval',
|
|
343
|
-
icon: 'Y',
|
|
344
|
-
category: 'monitoring',
|
|
345
|
-
description: 'Evaluation harness: benchmark suite results, scorecards, and regression gates',
|
|
346
|
-
factory: () => new EvalPanel(evalRegistry),
|
|
347
|
-
});
|
|
348
|
-
}
|
|
349
337
|
}
|
|
@@ -62,8 +62,6 @@ export interface BuiltinPanelDeps {
|
|
|
62
62
|
dismissPlanning?: () => void;
|
|
63
63
|
/** ForensicsRegistry for the Forensics panel. */
|
|
64
64
|
forensicsRegistry?: import('@/runtime/index.ts').ForensicsRegistry;
|
|
65
|
-
/** EvalRegistry for the Eval panel. */
|
|
66
|
-
evalRegistry?: import('../eval-panel.ts').EvalRegistry;
|
|
67
65
|
/** MemoryRegistry for the Memory panel. */
|
|
68
66
|
memoryRegistry?: MemoryRegistry;
|
|
69
67
|
/** Isolated Agent Knowledge service for the Agent Knowledge panel. */
|