@pellux/goodvibes-agent 0.1.65 → 0.1.67
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 +12 -0
- package/package.json +1 -1
- package/src/input/agent-workspace-categories.ts +3 -3
- package/src/input/commands/experience-runtime.ts +7 -7
- package/src/input/commands/health-runtime.ts +1 -1
- package/src/input/commands/local-setup-review.ts +1 -1
- package/src/input/commands/local-setup-transfer.ts +1 -1
- package/src/input/commands/local-setup.ts +2 -2
- package/src/input/commands/product-runtime.ts +19 -23
- package/src/input/commands/remote-runtime-pool.ts +25 -42
- package/src/input/commands/remote-runtime-setup.ts +1 -1
- package/src/input/commands/remote-runtime.ts +19 -19
- package/src/input/commands/teleport-runtime.ts +1 -1
- package/src/input/onboarding/onboarding-wizard-steps.ts +0 -7
- package/src/panels/provider-health-domains.ts +2 -2
- package/src/panels/remote-panel.ts +11 -11
- package/src/panels/session-browser-panel.ts +1 -1
- package/src/renderer/agent-workspace.ts +1 -1
- package/src/version.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to GoodVibes Agent will be recorded here.
|
|
4
4
|
|
|
5
|
+
## 0.1.67 - 2026-05-31
|
|
6
|
+
|
|
7
|
+
- Reworked remote bridge and remote review language from copied runner/control-room wording to Agent-facing worker/review wording.
|
|
8
|
+
- Made bridge worker assignment read-only in Agent and removed hidden contract creation from remote show/contract paths.
|
|
9
|
+
- Added regressions around the remote worker review panel and bridge command wording.
|
|
10
|
+
|
|
11
|
+
## 0.1.66 - 2026-05-31
|
|
12
|
+
|
|
13
|
+
- Removed remote-runner and node/device posture wording from first-run Agent setup surfaces.
|
|
14
|
+
- Replaced the blocked remote-runner workspace action with a read-only build-delegation status action.
|
|
15
|
+
- Added onboarding/workspace regressions to keep visible setup focused on Agent features instead of copied runner internals.
|
|
16
|
+
|
|
5
17
|
## 0.1.65 - 2026-05-31
|
|
6
18
|
|
|
7
19
|
- Made the operator workspace more product-facing by replacing foundation/setup jargon with Agent profile, runtime status, voice/media, and browser-tool language.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pellux/goodvibes-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.67",
|
|
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",
|
|
@@ -65,7 +65,7 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
|
|
|
65
65
|
{ id: 'knowledge-search', label: 'Search Agent knowledge', detail: 'Search the isolated Agent Knowledge index. Close this workspace and provide an actual query.', command: '/knowledge search <query>', kind: 'command', safety: 'read-only' },
|
|
66
66
|
{ id: 'knowledge-ingest-url', label: 'Ingest URL', detail: 'Ingest a URL into Agent Knowledge only. Requires an explicit --yes command with a real URL.', command: '/knowledge ingest-url <url> --yes', kind: 'command', safety: 'safe' },
|
|
67
67
|
{ id: 'knowledge-import-bookmarks', label: 'Import bookmarks', detail: 'Import a browser bookmark export into Agent Knowledge only. Requires an explicit --yes command with a real path.', command: '/knowledge import-bookmarks <path> --yes', kind: 'command', safety: 'safe' },
|
|
68
|
-
{ id: 'knowledge-review-queue', label: 'Review queue', detail: 'Inspect source
|
|
68
|
+
{ id: 'knowledge-review-queue', label: 'Review queue', detail: 'Inspect source, item, and issue review work before accepting, rejecting, or resolving anything.', command: '/knowledge queue', kind: 'command', safety: 'read-only' },
|
|
69
69
|
{ id: 'knowledge-consolidation', label: 'Consolidation review', detail: 'Inspect consolidation candidates and reports before running Agent Knowledge mutations.', command: '/knowledge candidates', kind: 'command', safety: 'read-only' },
|
|
70
70
|
{ id: 'knowledge-ask', label: 'Ask Agent knowledge', detail: 'Close this workspace and run /knowledge ask <question> or ask normally in chat.', kind: 'guidance', safety: 'read-only' },
|
|
71
71
|
],
|
|
@@ -81,7 +81,7 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
|
|
|
81
81
|
{ id: 'tts-provider', label: 'Choose TTS provider', detail: 'Open provider/model routing for spoken responses through the settings flow.', command: '/config tts.provider', kind: 'command', safety: 'safe' },
|
|
82
82
|
{ id: 'tts-speak', label: 'Speak a prompt', detail: 'Submit a normal assistant turn and play the reply through configured live TTS. Close this workspace and provide real prompt text.', command: '/tts <prompt>', kind: 'command', safety: 'safe' },
|
|
83
83
|
{ id: 'image-attach', label: 'Attach image input', detail: 'Attach an image to the next assistant turn. Close this workspace and provide a real path and prompt.', command: '/image <path> <prompt>', kind: 'command', safety: 'safe' },
|
|
84
|
-
{ id: 'browser-
|
|
84
|
+
{ id: 'browser-tools', label: 'Browser tools', detail: 'Inspect browser/tool readiness without starting inbound endpoints or runtime services.', command: '/setup services', kind: 'command', safety: 'read-only' },
|
|
85
85
|
{ id: 'mcp-browser', label: 'Browser MCP tools', detail: 'Inspect MCP servers and tools, including browser/automation roles, without mutating server setup.', command: '/mcp servers', kind: 'command', safety: 'read-only' },
|
|
86
86
|
],
|
|
87
87
|
},
|
|
@@ -212,7 +212,7 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
|
|
|
212
212
|
actions: [
|
|
213
213
|
{ id: 'delegate-guidance', label: 'Delegation rule', detail: 'For build/fix/review work, delegate one request to GoodVibes TUI instead of spawning local Engineer/Reviewer/Tester roots.', kind: 'guidance', safety: 'delegates' },
|
|
214
214
|
{ id: 'review-command', label: 'Review delegation command', detail: 'Use /delegate --wrfc <task> only when the user explicitly asks for code review/build execution. Close this workspace and include the actual task text.', kind: 'guidance', safety: 'delegates' },
|
|
215
|
-
{ id: '
|
|
215
|
+
{ id: 'delegation-status', label: 'Delegation status', detail: 'Inspect build-delegation receipts and shared-session status without starting coding work.', command: '/delegate status', kind: 'command', safety: 'read-only' },
|
|
216
216
|
],
|
|
217
217
|
},
|
|
218
218
|
];
|
|
@@ -145,14 +145,14 @@ export function registerExperienceRuntimeCommands(registry: CommandRegistry): vo
|
|
|
145
145
|
});
|
|
146
146
|
|
|
147
147
|
registry.register({
|
|
148
|
-
name: '
|
|
148
|
+
name: 'worker-pool',
|
|
149
149
|
aliases: ['pool'],
|
|
150
|
-
description: 'Dedicated front-door for remote
|
|
151
|
-
usage: '[list|show <id
|
|
150
|
+
description: 'Dedicated front-door for remote worker pool review flows',
|
|
151
|
+
usage: '[list|show <id>]',
|
|
152
152
|
async handler(args, ctx) {
|
|
153
153
|
const sub = (args[0] ?? 'list').toLowerCase();
|
|
154
154
|
if (!ctx.executeCommand) {
|
|
155
|
-
ctx.print('
|
|
155
|
+
ctx.print('Remote worker pool controls are not available in this runtime.');
|
|
156
156
|
return;
|
|
157
157
|
}
|
|
158
158
|
if (sub === 'list') {
|
|
@@ -164,14 +164,14 @@ export function registerExperienceRuntimeCommands(registry: CommandRegistry): vo
|
|
|
164
164
|
return;
|
|
165
165
|
}
|
|
166
166
|
if (sub === 'create' && args[1] && args.length >= 3) {
|
|
167
|
-
|
|
167
|
+
ctx.print('Remote worker pool mutation is blocked in GoodVibes Agent. Use /worker-pool list or /worker-pool show <id>.');
|
|
168
168
|
return;
|
|
169
169
|
}
|
|
170
170
|
if ((sub === 'assign' || sub === 'unassign') && args[1] && args[2]) {
|
|
171
|
-
|
|
171
|
+
ctx.print('Remote worker pool mutation is blocked in GoodVibes Agent. Use /worker-pool list or /worker-pool show <id>.');
|
|
172
172
|
return;
|
|
173
173
|
}
|
|
174
|
-
ctx.print('Usage: /
|
|
174
|
+
ctx.print('Usage: /worker-pool [list|show <id>]');
|
|
175
175
|
},
|
|
176
176
|
});
|
|
177
177
|
|
|
@@ -317,7 +317,7 @@ export function registerHealthRuntimeCommands(registry: CommandRegistry): void {
|
|
|
317
317
|
` settings conflicts: ${settingsSnapshot.conflicts.length}`,
|
|
318
318
|
` managed locks: ${settingsSnapshot.managedLockCount}`,
|
|
319
319
|
` local auth users: ${readModels.localAuth.getSnapshot().userCount}`,
|
|
320
|
-
` remote
|
|
320
|
+
` remote workers: ${snapshot.remoteRunnerCount}`,
|
|
321
321
|
...formatSessionMaintenanceLines(maintenance, 'guided').map((line) => ` ${line}`),
|
|
322
322
|
...(snapshot.issues.length > 0 ? ['', ...snapshot.issues.map((issue) => ` [${issue.severity.toUpperCase()}] ${issue.area}: ${issue.message}`)] : []),
|
|
323
323
|
...(snapshot.serviceIssues.length > 0 ? ['', ...snapshot.serviceIssues.map((issue) => ` service: ${issue}`)] : []),
|
|
@@ -89,7 +89,7 @@ export async function buildSetupReviewSnapshot(ctx: CommandContext): Promise<Set
|
|
|
89
89
|
{
|
|
90
90
|
severity: remoteRunnerCount > 0 ? 'pass' : 'warn',
|
|
91
91
|
area: 'remote',
|
|
92
|
-
message: remoteRunnerCount > 0 ? `${remoteRunnerCount} remote
|
|
92
|
+
message: remoteRunnerCount > 0 ? `${remoteRunnerCount} remote worker contract(s)` : 'no remote worker contracts registered',
|
|
93
93
|
},
|
|
94
94
|
];
|
|
95
95
|
|
|
@@ -56,7 +56,7 @@ export function inspectSetupTransferBundle(bundle: SetupTransferBundle): string
|
|
|
56
56
|
` services: ${bundle.startupReview.serviceCount}`,
|
|
57
57
|
` plugins: ${bundle.startupReview.pluginCount}`,
|
|
58
58
|
` skills: ${bundle.startupReview.skillCount}`,
|
|
59
|
-
` remote
|
|
59
|
+
` remote workers: ${bundle.startupReview.remoteRunnerCount}`,
|
|
60
60
|
` config keys: ${Object.keys(bundle.config ?? {}).length}`,
|
|
61
61
|
` curated plugins: ${ecosystemPluginCount}`,
|
|
62
62
|
` curated skills: ${ecosystemSkillCount}`,
|
|
@@ -57,7 +57,7 @@ export function registerLocalSetupCommands(registry: CommandRegistry): void {
|
|
|
57
57
|
` mcp servers known: ${snapshot.mcpServerCount}`,
|
|
58
58
|
` mcp quarantined: ${snapshot.quarantinedMcpCount}`,
|
|
59
59
|
` mcp elevated: ${snapshot.elevatedMcpCount}`,
|
|
60
|
-
` remote
|
|
60
|
+
` remote workers: ${snapshot.remoteRunnerCount}`,
|
|
61
61
|
'',
|
|
62
62
|
` service ids: ${snapshot.services.join(', ') || '(none)'}`,
|
|
63
63
|
` plugin dirs: ${snapshot.pluginDirectories.join(', ') || '(none)'}`,
|
|
@@ -111,7 +111,7 @@ export function registerLocalSetupCommands(registry: CommandRegistry): void {
|
|
|
111
111
|
const runners = ctx.ops.remoteRuntime?.listContracts() ?? [];
|
|
112
112
|
ctx.print([
|
|
113
113
|
'Startup Remote',
|
|
114
|
-
`
|
|
114
|
+
` worker contracts: ${snapshot.remoteRunnerCount}`,
|
|
115
115
|
...runners.map((runner) => ` ${runner.id} [${runner.trustClass}] ${runner.label}`),
|
|
116
116
|
].join('\n'));
|
|
117
117
|
return;
|
|
@@ -131,14 +131,14 @@ export function registerProductRuntimeCommands(registry: CommandRegistry): void
|
|
|
131
131
|
});
|
|
132
132
|
registry.register({
|
|
133
133
|
name: 'bridge',
|
|
134
|
-
description: 'Review
|
|
135
|
-
usage: '[status|pools|
|
|
134
|
+
description: 'Review self-hosted bridge and remote worker flows',
|
|
135
|
+
usage: '[status|pools|worker <id>|review <artifactId>|export <artifactId> [path] --yes|import <path> --yes]',
|
|
136
136
|
async handler(args, ctx) {
|
|
137
137
|
const parsed = stripYesFlag(args);
|
|
138
138
|
const commandArgs = [...parsed.rest];
|
|
139
139
|
const shellPaths = requireShellPaths(ctx);
|
|
140
140
|
if (!ctx.ops.remoteRuntime) {
|
|
141
|
-
ctx.print('Remote
|
|
141
|
+
ctx.print('Remote worker registry is not available in this runtime.');
|
|
142
142
|
return;
|
|
143
143
|
}
|
|
144
144
|
const remoteRegistry = ctx.ops.remoteRuntime;
|
|
@@ -148,7 +148,7 @@ export function registerProductRuntimeCommands(registry: CommandRegistry): void
|
|
|
148
148
|
ctx.print([
|
|
149
149
|
'Bridge Status',
|
|
150
150
|
` remote pools: ${remote.pools.length}`,
|
|
151
|
-
`
|
|
151
|
+
` worker contracts: ${remote.contracts.length}`,
|
|
152
152
|
` review artifacts: ${remote.artifacts.length}`,
|
|
153
153
|
].join('\n'));
|
|
154
154
|
return;
|
|
@@ -156,42 +156,38 @@ export function registerProductRuntimeCommands(registry: CommandRegistry): void
|
|
|
156
156
|
if (sub === 'pools') {
|
|
157
157
|
const pools = remoteRegistry.listPools();
|
|
158
158
|
ctx.print(pools.length > 0
|
|
159
|
-
? ['Bridge Pools', ...pools.map((pool) => ` ${pool.id}
|
|
160
|
-
: 'Bridge Pools\n No
|
|
159
|
+
? ['Bridge Pools', ...pools.map((pool) => ` ${pool.id} workers=${pool.runnerIds.length} trust=${pool.trustClass}`)].join('\n')
|
|
160
|
+
: 'Bridge Pools\n No worker pools registered yet.');
|
|
161
161
|
return;
|
|
162
162
|
}
|
|
163
163
|
if (sub === 'assign') {
|
|
164
164
|
const poolId = commandArgs[1];
|
|
165
165
|
const runnerId = commandArgs[2];
|
|
166
166
|
if (!poolId || !runnerId) {
|
|
167
|
-
ctx.print('Usage: /bridge assign <pool> <
|
|
167
|
+
ctx.print('Usage: /bridge assign <pool> <worker> --yes');
|
|
168
168
|
return;
|
|
169
169
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
ctx.print(`Unable to assign runner ${runnerId} to pool ${poolId}.`);
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
ctx.print(`Assigned runner ${runnerId} to bridge pool ${poolId}.`);
|
|
170
|
+
ctx.print([
|
|
171
|
+
'Bridge worker assignment is read-only in GoodVibes Agent.',
|
|
172
|
+
` requested: /bridge assign ${poolId} ${runnerId}`,
|
|
173
|
+
' policy: Agent reviews remote bridge state but does not mutate worker topology',
|
|
174
|
+
' next: inspect /bridge pools or delegate explicit build/fix/review work to GoodVibes TUI',
|
|
175
|
+
].join('\n'));
|
|
180
176
|
return;
|
|
181
177
|
}
|
|
182
|
-
if (sub === 'runner') {
|
|
178
|
+
if (sub === 'runner' || sub === 'worker') {
|
|
183
179
|
const runnerId = commandArgs[1];
|
|
184
180
|
if (!runnerId) {
|
|
185
|
-
ctx.print('Usage: /bridge
|
|
181
|
+
ctx.print('Usage: /bridge worker <id>');
|
|
186
182
|
return;
|
|
187
183
|
}
|
|
188
184
|
const contract = remoteRegistry.getContract(runnerId);
|
|
189
185
|
if (!contract) {
|
|
190
|
-
ctx.print(`Unknown
|
|
186
|
+
ctx.print(`Unknown worker contract: ${runnerId}`);
|
|
191
187
|
return;
|
|
192
188
|
}
|
|
193
189
|
ctx.print([
|
|
194
|
-
`Bridge
|
|
190
|
+
`Bridge Worker ${runnerId}`,
|
|
195
191
|
` template: ${contract.template}`,
|
|
196
192
|
` trustClass: ${contract.trustClass}`,
|
|
197
193
|
` transport: ${contract.sourceTransport}/${contract.transport.state}`,
|
|
@@ -242,10 +238,10 @@ export function registerProductRuntimeCommands(registry: CommandRegistry): void
|
|
|
242
238
|
return;
|
|
243
239
|
}
|
|
244
240
|
const artifact = await remoteRegistry.importArtifact(shellPaths.resolveWorkspacePath(pathArg));
|
|
245
|
-
ctx.print(`Imported remote bridge artifact ${artifact.id} for
|
|
241
|
+
ctx.print(`Imported remote bridge artifact ${artifact.id} for worker ${artifact.runnerId}.`);
|
|
246
242
|
return;
|
|
247
243
|
}
|
|
248
|
-
ctx.print('Usage: /bridge [status|pools|
|
|
244
|
+
ctx.print('Usage: /bridge [status|pools|worker <id>|review <artifactId>|export <artifactId> [path] --yes|import <path> --yes]');
|
|
249
245
|
},
|
|
250
246
|
});
|
|
251
247
|
|
|
@@ -13,9 +13,6 @@ type RemotePoolLike = {
|
|
|
13
13
|
type RemoteRegistryLike = {
|
|
14
14
|
listPools(): readonly RemotePoolLike[];
|
|
15
15
|
getPool(id: string): RemotePoolLike | null | undefined;
|
|
16
|
-
createPool(input: { id: string; label: string }): RemotePoolLike;
|
|
17
|
-
assignRunnerToPool(poolId: string, runnerId: string): RemotePoolLike | null | undefined;
|
|
18
|
-
removeRunnerFromPool(poolId: string, runnerId: string): RemotePoolLike | null | undefined;
|
|
19
16
|
};
|
|
20
17
|
|
|
21
18
|
export function handleRemotePoolCommand(
|
|
@@ -29,12 +26,12 @@ export function handleRemotePoolCommand(
|
|
|
29
26
|
if (mode === 'list') {
|
|
30
27
|
const pools = remoteRegistry.listPools();
|
|
31
28
|
if (pools.length === 0) {
|
|
32
|
-
ctx.print('No remote
|
|
29
|
+
ctx.print('No remote worker pools defined yet.');
|
|
33
30
|
return true;
|
|
34
31
|
}
|
|
35
32
|
ctx.print([
|
|
36
|
-
`Remote
|
|
37
|
-
...pools.map((pool) => ` ${pool.id} ${pool.runnerIds.length}
|
|
33
|
+
`Remote Worker Pools (${pools.length})`,
|
|
34
|
+
...pools.map((pool) => ` ${pool.id} ${pool.runnerIds.length} workers trust=${pool.trustClass} template=${pool.preferredTemplate ?? '(none)'}`),
|
|
38
35
|
].join('\n'));
|
|
39
36
|
return true;
|
|
40
37
|
}
|
|
@@ -46,59 +43,45 @@ export function handleRemotePoolCommand(
|
|
|
46
43
|
}
|
|
47
44
|
const pool = remoteRegistry.getPool(poolId);
|
|
48
45
|
if (!pool) {
|
|
49
|
-
ctx.print(`Unknown remote
|
|
46
|
+
ctx.print(`Unknown remote worker pool: ${poolId}`);
|
|
50
47
|
return true;
|
|
51
48
|
}
|
|
52
49
|
ctx.print([
|
|
53
|
-
`Remote
|
|
50
|
+
`Remote Worker Pool ${pool.id}`,
|
|
54
51
|
` label: ${pool.label}`,
|
|
55
52
|
` trustClass: ${pool.trustClass}`,
|
|
56
53
|
` preferredTemplate: ${pool.preferredTemplate ?? '(none)'}`,
|
|
57
|
-
`
|
|
58
|
-
`
|
|
54
|
+
` maxWorkers: ${pool.maxRunners ?? '(unbounded)'}`,
|
|
55
|
+
` workers: ${pool.runnerIds.join(', ') || '(none)'}`,
|
|
59
56
|
` description: ${pool.description ?? '(none)'}`,
|
|
60
57
|
].join('\n'));
|
|
61
58
|
return true;
|
|
62
59
|
}
|
|
63
60
|
if (mode === 'create') {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const pool = remoteRegistry.createPool({ id: poolId, label });
|
|
71
|
-
ctx.print(`Created remote runner pool ${pool.id} (${pool.label}).`);
|
|
61
|
+
ctx.print([
|
|
62
|
+
'Remote worker pool mutation is blocked in GoodVibes Agent.',
|
|
63
|
+
' requested: /remote pool create',
|
|
64
|
+
' policy: Agent inspects remote worker pools but does not manage worker topology',
|
|
65
|
+
' next: use the owning GoodVibes runtime or delegated build environment for worker-pool administration',
|
|
66
|
+
].join('\n'));
|
|
72
67
|
return true;
|
|
73
68
|
}
|
|
74
69
|
if (mode === 'assign') {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const pool = remoteRegistry.assignRunnerToPool(poolId, runnerId);
|
|
82
|
-
if (!pool) {
|
|
83
|
-
ctx.print(`Could not assign ${runnerId} to pool ${poolId}.`);
|
|
84
|
-
return true;
|
|
85
|
-
}
|
|
86
|
-
ctx.print(`Assigned remote runner ${runnerId} to pool ${poolId}.`);
|
|
70
|
+
ctx.print([
|
|
71
|
+
'Remote worker pool mutation is blocked in GoodVibes Agent.',
|
|
72
|
+
' requested: /remote pool assign',
|
|
73
|
+
' policy: Agent inspects remote worker pools but does not manage worker topology',
|
|
74
|
+
' next: use the owning GoodVibes runtime or delegated build environment for worker-pool administration',
|
|
75
|
+
].join('\n'));
|
|
87
76
|
return true;
|
|
88
77
|
}
|
|
89
78
|
if (mode === 'unassign') {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const pool = remoteRegistry.removeRunnerFromPool(poolId, runnerId);
|
|
97
|
-
if (!pool) {
|
|
98
|
-
ctx.print(`Unknown remote runner pool: ${poolId}`);
|
|
99
|
-
return true;
|
|
100
|
-
}
|
|
101
|
-
ctx.print(`Removed remote runner ${runnerId} from pool ${poolId}.`);
|
|
79
|
+
ctx.print([
|
|
80
|
+
'Remote worker pool mutation is blocked in GoodVibes Agent.',
|
|
81
|
+
' requested: /remote pool unassign',
|
|
82
|
+
' policy: Agent inspects remote worker pools but does not manage worker topology',
|
|
83
|
+
' next: use the owning GoodVibes runtime or delegated build environment for worker-pool administration',
|
|
84
|
+
].join('\n'));
|
|
102
85
|
return true;
|
|
103
86
|
}
|
|
104
87
|
ctx.print('Usage: /remote pool <list|show|create|assign|unassign> ...');
|
|
@@ -45,7 +45,7 @@ export async function handleRemoteSetupCommand(
|
|
|
45
45
|
` acp agent command: ${command.join(' ')}`,
|
|
46
46
|
` runtime host enabled: ${danger.daemon ? 'yes' : 'no'}`,
|
|
47
47
|
` inbound listener enabled: ${danger.httpListener ? 'yes' : 'no'}`,
|
|
48
|
-
` remote
|
|
48
|
+
` remote worker contracts: ${remoteRegistry.listContracts().length}`,
|
|
49
49
|
` active acp connections: ${activeConnections.length}`,
|
|
50
50
|
'',
|
|
51
51
|
' guidance:',
|
|
@@ -11,11 +11,11 @@ type RemoteCancelContext = Pick<CommandContext, 'print'>;
|
|
|
11
11
|
|
|
12
12
|
function printRemoteDelegationBoundary(ctx: Pick<CommandContext, 'print'>, requestedAction: string): void {
|
|
13
13
|
ctx.print([
|
|
14
|
-
'GoodVibes Agent does not dispatch remote/local coding
|
|
14
|
+
'GoodVibes Agent does not dispatch remote/local coding workers from this surface.',
|
|
15
15
|
` requested: ${requestedAction}`,
|
|
16
16
|
' policy: keep ordinary work serial in the main assistant conversation',
|
|
17
17
|
' build/fix/review: delegate one request to GoodVibes TUI through the public shared-session/build-delegation contract',
|
|
18
|
-
' preserve: full original user ask and executionIntent; let TUI own
|
|
18
|
+
' preserve: full original user ask and executionIntent; let TUI own execution and WRFC chain details when explicitly requested',
|
|
19
19
|
].join('\n'));
|
|
20
20
|
}
|
|
21
21
|
|
|
@@ -36,7 +36,7 @@ export function handleRemoteCancelCommand(
|
|
|
36
36
|
ctx.print([
|
|
37
37
|
'GoodVibes Agent remote control is read-only.',
|
|
38
38
|
` requested: /remote cancel ${agentId}`,
|
|
39
|
-
' policy: Agent does not cancel local
|
|
39
|
+
' policy: Agent does not cancel local remote-worker processes from this surface',
|
|
40
40
|
' next: inspect with /remote show or delegate explicit build/fix/review work to GoodVibes TUI',
|
|
41
41
|
].join('\n'));
|
|
42
42
|
}
|
|
@@ -45,8 +45,8 @@ export function registerRemoteRuntimeCommands(registry: CommandRegistry): void {
|
|
|
45
45
|
registry.register({
|
|
46
46
|
name: 'remote',
|
|
47
47
|
aliases: [],
|
|
48
|
-
description: 'Inspect,
|
|
49
|
-
usage: '[list | show [agentId] | supervisor [
|
|
48
|
+
description: 'Inspect remote workers, delegated work receipts, and review artifacts',
|
|
49
|
+
usage: '[list | show [agentId] | supervisor [workerId] | support [workerId] | recover [workerId] | setup [export <path> --yes] | env [export <path> --yes] | tunnel [review|export <path> --yes] | bootstrap [export <path> --yes|inspect <path>] | session <export|inspect|import> <path> [--yes] | pool <list|show> ... | dispatch [template] <description> | dispatch-pool <pool> [template] <description> | contract [workerId] | cancel <agentId> | export <agentId> [path] --yes | artifact list | artifact show <id> | artifact export <id> [path] --yes | review <id> | rerun-local <id> | import <path> --yes]',
|
|
50
50
|
async handler(args, ctx) {
|
|
51
51
|
if (args.length === 0) {
|
|
52
52
|
if (ctx.openRemotePanel) {
|
|
@@ -85,8 +85,8 @@ export function registerRemoteRuntimeCommands(registry: CommandRegistry): void {
|
|
|
85
85
|
const lines = [
|
|
86
86
|
'Remote Control Surface',
|
|
87
87
|
` active connections: ${activeConnections.length}`,
|
|
88
|
-
`
|
|
89
|
-
`
|
|
88
|
+
` worker contracts: ${contracts.length}`,
|
|
89
|
+
` worker pools: ${pools.length}`,
|
|
90
90
|
` review artifacts: ${artifacts.length}`,
|
|
91
91
|
` supervisor sessions: ${supervisor.sessions.length}`,
|
|
92
92
|
` degraded sessions: ${supervisor.degradedConnections}`,
|
|
@@ -131,7 +131,7 @@ export function registerRemoteRuntimeCommands(registry: CommandRegistry): void {
|
|
|
131
131
|
` messageCount: ${selected.messageCount}`,
|
|
132
132
|
` errorCount: ${selected.errorCount}`,
|
|
133
133
|
...(selected.lastError ? [` lastError: ${selected.lastError}`] : []),
|
|
134
|
-
'
|
|
134
|
+
' worker support:',
|
|
135
135
|
...selected.capabilities.map((capability) => ` ${capability.id}: ${capability.supported ? 'yes' : 'no'} (${capability.detail})`),
|
|
136
136
|
' recovery:',
|
|
137
137
|
...selected.recovery.map((action) => ` ${action.command} — ${action.reason}`),
|
|
@@ -146,7 +146,7 @@ export function registerRemoteRuntimeCommands(registry: CommandRegistry): void {
|
|
|
146
146
|
? snapshot.sessions.find((entry) => entry.runnerId === runnerId)
|
|
147
147
|
: snapshot.sessions[0];
|
|
148
148
|
if (!selected) {
|
|
149
|
-
ctx.print(runnerId ? `Unknown remote
|
|
149
|
+
ctx.print(runnerId ? `Unknown remote worker: ${runnerId}` : 'No remote supervisor sessions are currently tracked.');
|
|
150
150
|
return;
|
|
151
151
|
}
|
|
152
152
|
ctx.print([
|
|
@@ -157,7 +157,7 @@ export function registerRemoteRuntimeCommands(registry: CommandRegistry): void {
|
|
|
157
157
|
` reviewMode: ${selected.negotiation.reviewMode}`,
|
|
158
158
|
` communicationLane: ${selected.negotiation.communicationLane}`,
|
|
159
159
|
` trustClass: ${selected.negotiation.trustClass}`,
|
|
160
|
-
'
|
|
160
|
+
' worker support:',
|
|
161
161
|
...selected.capabilities.map((capability) => (
|
|
162
162
|
` ${capability.id}: ${capability.supported ? 'supported' : 'missing'} — ${capability.detail}`
|
|
163
163
|
)),
|
|
@@ -172,7 +172,7 @@ export function registerRemoteRuntimeCommands(registry: CommandRegistry): void {
|
|
|
172
172
|
? snapshot.sessions.find((entry) => entry.runnerId === runnerId)
|
|
173
173
|
: snapshot.sessions.find((entry) => entry.recovery.length > 0) ?? snapshot.sessions[0];
|
|
174
174
|
if (!selected) {
|
|
175
|
-
ctx.print(runnerId ? `Unknown remote
|
|
175
|
+
ctx.print(runnerId ? `Unknown remote worker: ${runnerId}` : 'No remote supervisor sessions are currently tracked.');
|
|
176
176
|
return;
|
|
177
177
|
}
|
|
178
178
|
const nextSteps = selected.recovery.length > 0
|
|
@@ -210,7 +210,7 @@ export function registerRemoteRuntimeCommands(registry: CommandRegistry): void {
|
|
|
210
210
|
ctx.print(agentId ? `Unknown remote connection: ${agentId}` : 'No active remote connections.');
|
|
211
211
|
return;
|
|
212
212
|
}
|
|
213
|
-
const contract = remoteRunners.
|
|
213
|
+
const contract = remoteRunners.getContract(connection.agentId);
|
|
214
214
|
ctx.print([
|
|
215
215
|
`Remote connection ${connection.agentId}`,
|
|
216
216
|
` label: ${connection.label}`,
|
|
@@ -254,7 +254,7 @@ export function registerRemoteRuntimeCommands(registry: CommandRegistry): void {
|
|
|
254
254
|
}
|
|
255
255
|
const pool = remoteRunners.getPool(poolId);
|
|
256
256
|
if (!pool) {
|
|
257
|
-
ctx.print(`Unknown remote
|
|
257
|
+
ctx.print(`Unknown remote worker pool: ${poolId}`);
|
|
258
258
|
return;
|
|
259
259
|
}
|
|
260
260
|
let template = pool.preferredTemplate ?? 'general';
|
|
@@ -275,17 +275,17 @@ export function registerRemoteRuntimeCommands(registry: CommandRegistry): void {
|
|
|
275
275
|
if (subcommand === 'contract') {
|
|
276
276
|
const agentId = args[1] ?? activeConnections[0]?.agentId;
|
|
277
277
|
if (!agentId) {
|
|
278
|
-
ctx.print('No remote
|
|
278
|
+
ctx.print('No remote worker contracts are available yet.');
|
|
279
279
|
return;
|
|
280
280
|
}
|
|
281
|
-
const contract = remoteRunners.
|
|
281
|
+
const contract = remoteRunners.getContract(agentId);
|
|
282
282
|
if (!contract) {
|
|
283
|
-
ctx.print(`Unknown remote
|
|
283
|
+
ctx.print(`Unknown remote worker: ${agentId}`);
|
|
284
284
|
return;
|
|
285
285
|
}
|
|
286
286
|
ctx.print([
|
|
287
|
-
`Remote
|
|
288
|
-
`
|
|
287
|
+
`Remote worker contract ${contract.id}`,
|
|
288
|
+
` workerId: ${contract.runnerId}`,
|
|
289
289
|
` label: ${contract.label}`,
|
|
290
290
|
` pool: ${contract.poolId ?? '(none)'}`,
|
|
291
291
|
` trustClass: ${contract.trustClass}`,
|
|
@@ -422,7 +422,7 @@ export function registerRemoteRuntimeCommands(registry: CommandRegistry): void {
|
|
|
422
422
|
return;
|
|
423
423
|
}
|
|
424
424
|
const artifact = await remoteRunners.importArtifact(path);
|
|
425
|
-
ctx.print(`Imported remote review artifact ${artifact.id} for
|
|
425
|
+
ctx.print(`Imported remote review artifact ${artifact.id} for worker ${artifact.runnerId}.`);
|
|
426
426
|
return;
|
|
427
427
|
}
|
|
428
428
|
|
|
@@ -35,7 +35,7 @@ export function registerTeleportRuntimeCommands(registry: CommandRegistry): void
|
|
|
35
35
|
try {
|
|
36
36
|
peerClient = requirePeerClient(ctx);
|
|
37
37
|
} catch {
|
|
38
|
-
ctx.print('Remote
|
|
38
|
+
ctx.print('Remote worker registry is not available in this runtime.');
|
|
39
39
|
return;
|
|
40
40
|
}
|
|
41
41
|
const targetPath = shellPaths.resolveWorkspacePath(pathArg);
|
|
@@ -497,13 +497,6 @@ export function buildVoiceMediaStep(): OnboardingWizardStepDefinition {
|
|
|
497
497
|
hint: 'Media output uses configured providers and visible command/turn flow; external publication still requires explicit approval.',
|
|
498
498
|
defaultValue: 'Policy gated',
|
|
499
499
|
},
|
|
500
|
-
{
|
|
501
|
-
kind: 'status',
|
|
502
|
-
id: 'agent-voice-media.nodes',
|
|
503
|
-
label: 'Node and device posture',
|
|
504
|
-
hint: 'Remote devices and nodes are inspected only when useful. Agent onboarding does not launch runners or background service processes.',
|
|
505
|
-
defaultValue: 'External',
|
|
506
|
-
},
|
|
507
500
|
],
|
|
508
501
|
};
|
|
509
502
|
}
|
|
@@ -85,7 +85,7 @@ export function buildProviderHealthDomainSummaries(
|
|
|
85
85
|
summary: remote.supervisor.sessions.length === 0
|
|
86
86
|
? 'no remote sessions tracked'
|
|
87
87
|
: `${remote.supervisor.sessions.length} sessions / ${remote.supervisor.degradedConnections} degraded`,
|
|
88
|
-
next: remote.supervisor.degradedConnections > 0 ? '/remote recover <
|
|
88
|
+
next: remote.supervisor.degradedConnections > 0 ? '/remote recover <workerId>' : '/remote supervisor',
|
|
89
89
|
details: remote.supervisor.sessions.length === 0
|
|
90
90
|
? ['no remote sessions have been attached yet']
|
|
91
91
|
: remote.supervisor.sessions
|
|
@@ -98,7 +98,7 @@ export function buildProviderHealthDomainSummaries(
|
|
|
98
98
|
.slice(0, 3)
|
|
99
99
|
.map((entry) => `${entry.runnerId}: transport=${entry.transportState} heartbeat=${entry.heartbeat.status}${entry.lastError ? ` error=${entry.lastError}` : ''}`),
|
|
100
100
|
nextSteps: remote.supervisor.degradedConnections > 0
|
|
101
|
-
? ['/remote supervisor', '/remote recover <
|
|
101
|
+
? ['/remote supervisor', '/remote recover <workerId>', '/remote support']
|
|
102
102
|
: ['/remote supervisor'],
|
|
103
103
|
});
|
|
104
104
|
|
|
@@ -111,13 +111,13 @@ export class RemotePanel extends BasePanel {
|
|
|
111
111
|
|
|
112
112
|
public render(width: number, height: number): Line[] {
|
|
113
113
|
this.needsRender = false;
|
|
114
|
-
const intro = '
|
|
114
|
+
const intro = 'Remote worker, bridge, and review-artifact posture for delegated work.';
|
|
115
115
|
|
|
116
116
|
if (!this.readModel) {
|
|
117
117
|
const sectionLines = buildEmptyState(
|
|
118
118
|
width,
|
|
119
119
|
' Runtime store not wired into this panel yet.',
|
|
120
|
-
'The remote
|
|
120
|
+
'The remote review workspace needs the shell read model so it can display worker state and review artifacts.',
|
|
121
121
|
[
|
|
122
122
|
{ command: '/remote setup', summary: 'review bootstrap, env, tunnel, and bridge guidance' },
|
|
123
123
|
{ command: '/remote panel', summary: 'reopen the panel from the shell-owned runtime' },
|
|
@@ -125,7 +125,7 @@ export class RemotePanel extends BasePanel {
|
|
|
125
125
|
C,
|
|
126
126
|
);
|
|
127
127
|
const lines = buildPanelWorkspace(width, height, {
|
|
128
|
-
title: 'Remote
|
|
128
|
+
title: 'Remote Work Review',
|
|
129
129
|
intro,
|
|
130
130
|
sections: [{ lines: sectionLines }],
|
|
131
131
|
palette: C,
|
|
@@ -176,7 +176,7 @@ export class RemotePanel extends BasePanel {
|
|
|
176
176
|
[String(acp.totalMessages), acp.totalMessages > 0 ? C.value : C.dim],
|
|
177
177
|
]),
|
|
178
178
|
buildPanelLine(width, [
|
|
179
|
-
['
|
|
179
|
+
[' worker contracts ', C.label],
|
|
180
180
|
[String(contracts.length), C.info],
|
|
181
181
|
[' pools ', C.label],
|
|
182
182
|
[String(pools.length), pools.length > 0 ? C.info : C.dim],
|
|
@@ -204,7 +204,7 @@ export class RemotePanel extends BasePanel {
|
|
|
204
204
|
]));
|
|
205
205
|
}
|
|
206
206
|
postureLines.push(
|
|
207
|
-
buildGuidanceLine(width, '/remote recover', '
|
|
207
|
+
buildGuidanceLine(width, '/remote recover', 'inspect remote state with worker support and disconnect recovery hints', C),
|
|
208
208
|
buildGuidanceLine(width, '/remote support', 'inspect transport support before routing remote work or reattaching a session', C),
|
|
209
209
|
);
|
|
210
210
|
|
|
@@ -219,17 +219,17 @@ export class RemotePanel extends BasePanel {
|
|
|
219
219
|
...buildEmptyState(
|
|
220
220
|
width,
|
|
221
221
|
' No active ACP or remote subagent connections.',
|
|
222
|
-
'
|
|
222
|
+
'Remote review is healthy but idle. Worker contracts, session bundles, and bridge pools will appear here once delegated work exists.',
|
|
223
223
|
[
|
|
224
224
|
{ command: '/remote setup', summary: 'review remote bootstrap and environment export' },
|
|
225
225
|
{ command: '/remote env', summary: 'emit a reusable remote shell snippet' },
|
|
226
|
-
{ command: '/bridge status', summary: 'inspect
|
|
226
|
+
{ command: '/bridge status', summary: 'inspect worker pools and existing remote artifacts' },
|
|
227
227
|
],
|
|
228
228
|
C,
|
|
229
229
|
),
|
|
230
230
|
];
|
|
231
231
|
const lines = buildPanelWorkspace(width, height, {
|
|
232
|
-
title: 'Remote
|
|
232
|
+
title: 'Remote Work Review',
|
|
233
233
|
intro,
|
|
234
234
|
sections: [{ lines: buildSummaryBlock(width, 'Remote posture', idleLines, C) }],
|
|
235
235
|
footerLines,
|
|
@@ -341,7 +341,7 @@ export class RemotePanel extends BasePanel {
|
|
|
341
341
|
]));
|
|
342
342
|
} else if (selectedContract) {
|
|
343
343
|
detailRows.push(buildPanelLine(width, [
|
|
344
|
-
['
|
|
344
|
+
[' Worker: ', C.label],
|
|
345
345
|
[selectedContract.runnerId, C.value],
|
|
346
346
|
[' Template: ', C.label],
|
|
347
347
|
[selectedContract.template, C.info],
|
|
@@ -392,7 +392,7 @@ export class RemotePanel extends BasePanel {
|
|
|
392
392
|
const detailSection: PanelWorkspaceSection = {
|
|
393
393
|
lines: buildDetailBlock(width, selected ? 'Selected connection' : 'Selected contract', detailRows, C),
|
|
394
394
|
};
|
|
395
|
-
const browseTitle = viewingConnections ? 'Active Connections' : 'Registered Remote
|
|
395
|
+
const browseTitle = viewingConnections ? 'Active Connections' : 'Registered Remote Worker Contracts';
|
|
396
396
|
const rawBrowseLines: Line[] = viewingConnections
|
|
397
397
|
? activeConnections.map((connection, absolute) => {
|
|
398
398
|
return buildPanelListRow(width, [
|
|
@@ -437,7 +437,7 @@ export class RemotePanel extends BasePanel {
|
|
|
437
437
|
detailSection,
|
|
438
438
|
];
|
|
439
439
|
const lines = buildPanelWorkspace(width, height, {
|
|
440
|
-
title: 'Remote
|
|
440
|
+
title: 'Remote Work Review',
|
|
441
441
|
intro,
|
|
442
442
|
sections,
|
|
443
443
|
footerLines,
|
|
@@ -66,7 +66,7 @@ function formatReturnContextLines(returnContext: SessionInfo['returnContext']):
|
|
|
66
66
|
lines.push(`tasks: active=${returnContext.activeTasks ?? 0} blocked=${returnContext.blockedTasks ?? 0} approvals=${returnContext.pendingApprovals ?? 0}`);
|
|
67
67
|
}
|
|
68
68
|
if (returnContext.remoteRunners?.length) {
|
|
69
|
-
lines.push(`remote
|
|
69
|
+
lines.push(`remote workers: ${returnContext.remoteRunners.join(', ')}`);
|
|
70
70
|
}
|
|
71
71
|
if (returnContext.openPanels?.length) {
|
|
72
72
|
lines.push(`open panels: ${returnContext.openPanels.join(', ')}`);
|
|
@@ -196,7 +196,7 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
|
|
|
196
196
|
{ text: `TTS config: provider ${snapshot.ttsProvider}; voice ${snapshot.ttsVoice}; response model ${snapshot.ttsResponseModel}.`, fg: PALETTE.info },
|
|
197
197
|
{ text: `Media providers: ${snapshot.mediaProviderCount}; understanding: ${snapshot.mediaUnderstandingProviderCount}; generation: ${snapshot.mediaGenerationProviderCount}.`, fg: PALETTE.info },
|
|
198
198
|
{ text: `Browser tools: ${snapshot.browserSurfaceEnabled ? 'available' : 'not advertised'}; public base URL ${snapshot.browserSurfacePublicBaseUrl}.`, fg: snapshot.browserSurfaceEnabled ? PALETTE.warn : PALETTE.muted },
|
|
199
|
-
{ text: '
|
|
199
|
+
{ text: 'Build dispatch stays out of setup; explicit delegation is handled from the Build Delegation workspace.', fg: PALETTE.good },
|
|
200
200
|
{ text: 'Image input uses prompt attachments; media generation/provider setup stays behind explicit commands and configured providers.', fg: PALETTE.muted },
|
|
201
201
|
);
|
|
202
202
|
} else if (category.id === 'profiles') {
|
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.67';
|
|
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 {
|