@pellux/goodvibes-agent 0.1.28 → 0.1.30
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
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to GoodVibes Agent will be recorded here.
|
|
4
4
|
|
|
5
|
+
## 0.1.30 - 2026-05-31
|
|
6
|
+
|
|
7
|
+
- 6a1c818 Add channel readiness to Agent workspace
|
|
8
|
+
|
|
9
|
+
## 0.1.29 - 2026-05-31
|
|
10
|
+
|
|
11
|
+
- 3fafcda Add Agent channel workspace guidance
|
|
12
|
+
|
|
5
13
|
## 0.1.28 - 2026-05-31
|
|
6
14
|
|
|
7
15
|
- 77a9dc4 Add isolated Agent runtime profiles
|
|
@@ -30,11 +30,18 @@ Inside the TUI:
|
|
|
30
30
|
Primary sources used for the benchmark:
|
|
31
31
|
|
|
32
32
|
- OpenClaw README: https://github.com/openclaw/openclaw/blob/main/README.md
|
|
33
|
+
- OpenClaw Docs: https://docs.openclaw.ai/
|
|
34
|
+
- OpenClaw Features: https://docs.openclaw.ai/concepts/features
|
|
33
35
|
- OpenClaw FAQ: https://docs.openclaw.ai/help/faq
|
|
34
36
|
- OpenClaw Memory: https://docs.openclaw.ai/concepts/memory
|
|
35
37
|
- Hermes README: https://github.com/NousResearch/hermes-agent
|
|
38
|
+
- Hermes Features Overview: https://hermes-agent.nousresearch.com/docs/user-guide/features/overview/
|
|
36
39
|
- Hermes Tools: https://hermes-agent.nousresearch.com/docs/user-guide/features/tools/
|
|
40
|
+
- Hermes Skills: https://hermes-agent.nousresearch.com/docs/user-guide/features/skills/
|
|
37
41
|
- Hermes Cron: https://hermes-agent.nousresearch.com/docs/user-guide/features/cron/
|
|
42
|
+
- Hermes MCP: https://hermes-agent.nousresearch.com/docs/user-guide/features/mcp/
|
|
43
|
+
- Hermes Voice: https://hermes-agent.nousresearch.com/docs/user-guide/features/voice-mode/
|
|
44
|
+
- Hermes API Server: https://hermes-agent.nousresearch.com/docs/user-guide/features/api-server/
|
|
38
45
|
- Hermes Profiles: https://hermes-agent.nousresearch.com/docs/user-guide/profiles/
|
|
39
46
|
|
|
40
47
|
## Capability Targets
|
|
@@ -43,7 +50,7 @@ Primary sources used for the benchmark:
|
|
|
43
50
|
| --- | --- | --- |
|
|
44
51
|
| Terminal operator UI | Interactive CLI/TUI, commands, sessions | Near-fork GoodVibes TUI compositor/input/fullscreen foundation |
|
|
45
52
|
| Always-on gateway | Gateway/service owns channels, sessions, tools, events | External GoodVibes daemon, never Agent-owned lifecycle |
|
|
46
|
-
| Channels | WhatsApp, Telegram, Slack, Discord, Signal, iMessage, web chat | GoodVibes daemon channel and companion surfaces with Agent-side policy |
|
|
53
|
+
| Channels | WhatsApp, Telegram, Slack, Discord, Signal, iMessage, web chat | GoodVibes daemon channel and companion surfaces with Agent-side policy, a Channels operator workspace, and per-channel readiness/risk labels |
|
|
47
54
|
| Knowledge/memory | Durable memory, semantic search, wiki/claim layers | Isolated Agent Knowledge routes plus local memory/skills/personas/routines |
|
|
48
55
|
| Skills/procedural memory | Skills directories, registries, skill lifecycle | Local Agent skills with review/stale/source/provenance fields |
|
|
49
56
|
| Scheduling | Natural-language cron, run/pause/resume/edit/remove, delivery | Guarded automation/schedule routes plus local routines; hidden model scheduling blocked |
|
|
@@ -66,7 +73,7 @@ GoodVibes Agent should exceed OpenClaw/Hermes by making these properties true fr
|
|
|
66
73
|
|
|
67
74
|
## Current Gaps To Close
|
|
68
75
|
|
|
69
|
-
-
|
|
76
|
+
- Live daemon account health and last delivery errors in the Channels workspace once a stable read-only route is available.
|
|
70
77
|
- Richer Agent Knowledge ingest/review workspace for URLs, bookmarks, artifacts, issue queues, and consolidation.
|
|
71
78
|
- Profile-aware onboarding summaries and profile export/import shortcuts from the Agent workspace.
|
|
72
79
|
- Voice/media/browser/node setup workspaces.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pellux/goodvibes-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.30",
|
|
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",
|
|
@@ -30,6 +30,20 @@ export interface AgentWorkspaceCategory {
|
|
|
30
30
|
|
|
31
31
|
export type AgentWorkspaceCommandDispatcher = (command: string) => void;
|
|
32
32
|
|
|
33
|
+
export type AgentWorkspaceChannelRisk = 'dm' | 'group' | 'public' | 'webhook' | 'bridge';
|
|
34
|
+
|
|
35
|
+
export interface AgentWorkspaceChannelStatus {
|
|
36
|
+
readonly id: string;
|
|
37
|
+
readonly label: string;
|
|
38
|
+
readonly enabled: boolean;
|
|
39
|
+
readonly ready: boolean;
|
|
40
|
+
readonly missingConfigCount: number;
|
|
41
|
+
readonly defaultTarget: 'configured' | 'missing' | 'not-required';
|
|
42
|
+
readonly delivery: 'disabled' | 'blocked' | 'explicit-target' | 'default-ready';
|
|
43
|
+
readonly risk: AgentWorkspaceChannelRisk;
|
|
44
|
+
readonly riskLabel: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
33
47
|
export type AgentWorkspaceActionResultKind = 'guidance' | 'blocked' | 'dispatched' | 'refreshed' | 'error';
|
|
34
48
|
|
|
35
49
|
export interface AgentWorkspaceActionResult {
|
|
@@ -64,9 +78,140 @@ export interface AgentWorkspaceRuntimeSnapshot {
|
|
|
64
78
|
readonly knowledgeIsolation: 'agent-only';
|
|
65
79
|
readonly executionPolicy: 'serial-proactive';
|
|
66
80
|
readonly wrfcPolicy: 'explicit-build-delegation-only';
|
|
81
|
+
readonly channels: readonly AgentWorkspaceChannelStatus[];
|
|
67
82
|
readonly warnings: readonly string[];
|
|
68
83
|
}
|
|
69
84
|
|
|
85
|
+
interface AgentWorkspaceChannelSpec {
|
|
86
|
+
readonly id: string;
|
|
87
|
+
readonly label: string;
|
|
88
|
+
readonly enabledKey: string;
|
|
89
|
+
readonly requiredKeys: readonly string[];
|
|
90
|
+
readonly defaultTargetKeys: readonly string[];
|
|
91
|
+
readonly risk: AgentWorkspaceChannelRisk;
|
|
92
|
+
readonly riskLabel: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const AGENT_WORKSPACE_CHANNEL_SPECS: readonly AgentWorkspaceChannelSpec[] = [
|
|
96
|
+
{
|
|
97
|
+
id: 'slack',
|
|
98
|
+
label: 'Slack',
|
|
99
|
+
enabledKey: 'surfaces.slack.enabled',
|
|
100
|
+
requiredKeys: ['surfaces.slack.botToken', 'surfaces.slack.signingSecret'],
|
|
101
|
+
defaultTargetKeys: ['surfaces.slack.defaultChannel'],
|
|
102
|
+
risk: 'group',
|
|
103
|
+
riskLabel: 'workspace/group channel',
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
id: 'discord',
|
|
107
|
+
label: 'Discord',
|
|
108
|
+
enabledKey: 'surfaces.discord.enabled',
|
|
109
|
+
requiredKeys: ['surfaces.discord.botToken', 'surfaces.discord.publicKey', 'surfaces.discord.applicationId'],
|
|
110
|
+
defaultTargetKeys: ['surfaces.discord.defaultChannelId'],
|
|
111
|
+
risk: 'group',
|
|
112
|
+
riskLabel: 'server/channel delivery',
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
id: 'telegram',
|
|
116
|
+
label: 'Telegram',
|
|
117
|
+
enabledKey: 'surfaces.telegram.enabled',
|
|
118
|
+
requiredKeys: ['surfaces.telegram.botToken'],
|
|
119
|
+
defaultTargetKeys: ['surfaces.telegram.defaultChatId'],
|
|
120
|
+
risk: 'dm',
|
|
121
|
+
riskLabel: 'bot DM/group delivery',
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
id: 'ntfy',
|
|
125
|
+
label: 'ntfy',
|
|
126
|
+
enabledKey: 'surfaces.ntfy.enabled',
|
|
127
|
+
requiredKeys: ['surfaces.ntfy.baseUrl', 'surfaces.ntfy.chatTopic', 'surfaces.ntfy.agentTopic'],
|
|
128
|
+
defaultTargetKeys: ['surfaces.ntfy.topic'],
|
|
129
|
+
risk: 'public',
|
|
130
|
+
riskLabel: 'topic-based public/private feed',
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
id: 'googleChat',
|
|
134
|
+
label: 'Google Chat',
|
|
135
|
+
enabledKey: 'surfaces.googleChat.enabled',
|
|
136
|
+
requiredKeys: ['surfaces.googleChat.webhookUrl', 'surfaces.googleChat.verificationToken'],
|
|
137
|
+
defaultTargetKeys: ['surfaces.googleChat.spaceId'],
|
|
138
|
+
risk: 'group',
|
|
139
|
+
riskLabel: 'space delivery',
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
id: 'signal',
|
|
143
|
+
label: 'Signal',
|
|
144
|
+
enabledKey: 'surfaces.signal.enabled',
|
|
145
|
+
requiredKeys: ['surfaces.signal.bridgeUrl', 'surfaces.signal.account'],
|
|
146
|
+
defaultTargetKeys: ['surfaces.signal.defaultRecipient'],
|
|
147
|
+
risk: 'bridge',
|
|
148
|
+
riskLabel: 'private bridge delivery',
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
id: 'whatsapp',
|
|
152
|
+
label: 'WhatsApp',
|
|
153
|
+
enabledKey: 'surfaces.whatsapp.enabled',
|
|
154
|
+
requiredKeys: ['surfaces.whatsapp.accessToken', 'surfaces.whatsapp.verifyToken', 'surfaces.whatsapp.phoneNumberId'],
|
|
155
|
+
defaultTargetKeys: ['surfaces.whatsapp.defaultRecipient'],
|
|
156
|
+
risk: 'dm',
|
|
157
|
+
riskLabel: 'phone-number delivery',
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
id: 'imessage',
|
|
161
|
+
label: 'iMessage',
|
|
162
|
+
enabledKey: 'surfaces.imessage.enabled',
|
|
163
|
+
requiredKeys: ['surfaces.imessage.bridgeUrl', 'surfaces.imessage.account'],
|
|
164
|
+
defaultTargetKeys: ['surfaces.imessage.defaultChatId'],
|
|
165
|
+
risk: 'bridge',
|
|
166
|
+
riskLabel: 'Apple bridge delivery',
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
id: 'bluebubbles',
|
|
170
|
+
label: 'BlueBubbles',
|
|
171
|
+
enabledKey: 'surfaces.bluebubbles.enabled',
|
|
172
|
+
requiredKeys: ['surfaces.bluebubbles.serverUrl', 'surfaces.bluebubbles.password'],
|
|
173
|
+
defaultTargetKeys: ['surfaces.bluebubbles.defaultChatGuid'],
|
|
174
|
+
risk: 'bridge',
|
|
175
|
+
riskLabel: 'iMessage bridge delivery',
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
id: 'msteams',
|
|
179
|
+
label: 'Microsoft Teams',
|
|
180
|
+
enabledKey: 'surfaces.msteams.enabled',
|
|
181
|
+
requiredKeys: ['surfaces.msteams.appId', 'surfaces.msteams.appPassword'],
|
|
182
|
+
defaultTargetKeys: ['surfaces.msteams.defaultConversationId', 'surfaces.msteams.defaultChannelId'],
|
|
183
|
+
risk: 'group',
|
|
184
|
+
riskLabel: 'tenant/channel delivery',
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
id: 'mattermost',
|
|
188
|
+
label: 'Mattermost',
|
|
189
|
+
enabledKey: 'surfaces.mattermost.enabled',
|
|
190
|
+
requiredKeys: ['surfaces.mattermost.baseUrl', 'surfaces.mattermost.botToken'],
|
|
191
|
+
defaultTargetKeys: ['surfaces.mattermost.defaultChannelId'],
|
|
192
|
+
risk: 'group',
|
|
193
|
+
riskLabel: 'team/channel delivery',
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
id: 'matrix',
|
|
197
|
+
label: 'Matrix',
|
|
198
|
+
enabledKey: 'surfaces.matrix.enabled',
|
|
199
|
+
requiredKeys: ['surfaces.matrix.homeserverUrl', 'surfaces.matrix.accessToken'],
|
|
200
|
+
defaultTargetKeys: ['surfaces.matrix.defaultRoomId'],
|
|
201
|
+
risk: 'group',
|
|
202
|
+
riskLabel: 'room delivery',
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
id: 'webhook',
|
|
206
|
+
label: 'Webhook',
|
|
207
|
+
enabledKey: 'surfaces.webhook.enabled',
|
|
208
|
+
requiredKeys: ['surfaces.webhook.defaultTarget'],
|
|
209
|
+
defaultTargetKeys: ['surfaces.webhook.defaultTarget'],
|
|
210
|
+
risk: 'webhook',
|
|
211
|
+
riskLabel: 'external HTTP delivery',
|
|
212
|
+
},
|
|
213
|
+
];
|
|
214
|
+
|
|
70
215
|
function readConfigString(context: CommandContext, key: string, fallback: string): string {
|
|
71
216
|
try {
|
|
72
217
|
const configManager = context.platform?.configManager as unknown as AgentWorkspaceConfigReader | undefined;
|
|
@@ -88,6 +233,64 @@ function readConfigNumber(context: CommandContext, key: string, fallback: number
|
|
|
88
233
|
}
|
|
89
234
|
}
|
|
90
235
|
|
|
236
|
+
function readConfigBoolean(context: CommandContext, key: string, fallback: boolean): boolean {
|
|
237
|
+
try {
|
|
238
|
+
const configManager = context.platform?.configManager as unknown as AgentWorkspaceConfigReader | undefined;
|
|
239
|
+
const value = configManager?.get(key);
|
|
240
|
+
if (typeof value === 'boolean') return value;
|
|
241
|
+
if (typeof value === 'string') {
|
|
242
|
+
const normalized = value.trim().toLowerCase();
|
|
243
|
+
if (normalized === 'true') return true;
|
|
244
|
+
if (normalized === 'false') return false;
|
|
245
|
+
}
|
|
246
|
+
return fallback;
|
|
247
|
+
} catch {
|
|
248
|
+
return fallback;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function hasConfigValue(context: CommandContext, key: string): boolean {
|
|
253
|
+
try {
|
|
254
|
+
const configManager = context.platform?.configManager as unknown as AgentWorkspaceConfigReader | undefined;
|
|
255
|
+
const value = configManager?.get(key);
|
|
256
|
+
if (typeof value === 'string') return value.trim().length > 0;
|
|
257
|
+
if (typeof value === 'number') return Number.isFinite(value);
|
|
258
|
+
if (typeof value === 'boolean') return value;
|
|
259
|
+
return value !== null && value !== undefined;
|
|
260
|
+
} catch {
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function buildChannelStatus(context: CommandContext, spec: AgentWorkspaceChannelSpec): AgentWorkspaceChannelStatus {
|
|
266
|
+
const enabled = readConfigBoolean(context, spec.enabledKey, false);
|
|
267
|
+
const missingConfigCount = spec.requiredKeys.filter((key) => !hasConfigValue(context, key)).length;
|
|
268
|
+
const defaultTarget = spec.defaultTargetKeys.length === 0
|
|
269
|
+
? 'not-required'
|
|
270
|
+
: spec.defaultTargetKeys.some((key) => hasConfigValue(context, key))
|
|
271
|
+
? 'configured'
|
|
272
|
+
: 'missing';
|
|
273
|
+
const ready = enabled && missingConfigCount === 0;
|
|
274
|
+
const delivery = !enabled
|
|
275
|
+
? 'disabled'
|
|
276
|
+
: !ready
|
|
277
|
+
? 'blocked'
|
|
278
|
+
: defaultTarget === 'configured'
|
|
279
|
+
? 'default-ready'
|
|
280
|
+
: 'explicit-target';
|
|
281
|
+
return {
|
|
282
|
+
id: spec.id,
|
|
283
|
+
label: spec.label,
|
|
284
|
+
enabled,
|
|
285
|
+
ready,
|
|
286
|
+
missingConfigCount,
|
|
287
|
+
defaultTarget,
|
|
288
|
+
delivery,
|
|
289
|
+
risk: spec.risk,
|
|
290
|
+
riskLabel: spec.riskLabel,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
91
294
|
export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): AgentWorkspaceRuntimeSnapshot {
|
|
92
295
|
const host = readConfigString(context, 'controlPlane.host', '127.0.0.1');
|
|
93
296
|
const port = readConfigNumber(context, 'controlPlane.port', 3421);
|
|
@@ -161,6 +364,7 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
|
|
|
161
364
|
knowledgeIsolation: 'agent-only',
|
|
162
365
|
executionPolicy: 'serial-proactive',
|
|
163
366
|
wrfcPolicy: 'explicit-build-delegation-only',
|
|
367
|
+
channels: AGENT_WORKSPACE_CHANNEL_SPECS.map((spec) => buildChannelStatus(context, spec)),
|
|
164
368
|
warnings,
|
|
165
369
|
};
|
|
166
370
|
}
|
|
@@ -192,6 +396,19 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
|
|
|
192
396
|
{ id: 'auth', label: 'Auth review', detail: 'Review authentication posture without printing token values.', command: '/auth review', kind: 'command', safety: 'read-only' },
|
|
193
397
|
],
|
|
194
398
|
},
|
|
399
|
+
{
|
|
400
|
+
id: 'channels',
|
|
401
|
+
group: 'SETUP',
|
|
402
|
+
label: 'Channels',
|
|
403
|
+
summary: 'Companion pairing, channel posture, and delivery safety.',
|
|
404
|
+
detail: 'Agent uses externally owned daemon channel surfaces. Pairing, account inspection, and readiness checks are visible here; inbound delivery and public channel exposure stay policy-gated.',
|
|
405
|
+
actions: [
|
|
406
|
+
{ id: 'pair', label: 'Pair companion', detail: 'Open the TUI-derived QR pairing surface for companion app setup.', command: '/pair', kind: 'command', safety: 'safe' },
|
|
407
|
+
{ id: 'communication', label: 'Communication routes', detail: 'Inspect structured communication routes and recent activity.', command: '/communication', kind: 'command', safety: 'read-only' },
|
|
408
|
+
{ id: 'setup-review', label: 'Channel setup review', detail: 'Review setup posture without starting listeners or mutating daemon surface state.', command: '/setup review', kind: 'command', safety: 'read-only' },
|
|
409
|
+
{ id: 'channel-safety', label: 'Delivery safety', detail: 'External messages, channel DMs, and public delivery targets require explicit user action and daemon-side policy. Agent will not silently send or expose channels from this workspace.', kind: 'guidance', safety: 'blocked' },
|
|
410
|
+
],
|
|
411
|
+
},
|
|
195
412
|
{
|
|
196
413
|
id: 'knowledge',
|
|
197
414
|
group: 'KNOW',
|
|
@@ -30,11 +30,18 @@ export interface OperatorCapabilityBenchmarkReport {
|
|
|
30
30
|
|
|
31
31
|
export const OPERATOR_CAPABILITY_BENCHMARK_SOURCES = [
|
|
32
32
|
'https://github.com/openclaw/openclaw/blob/main/README.md',
|
|
33
|
+
'https://docs.openclaw.ai/',
|
|
34
|
+
'https://docs.openclaw.ai/concepts/features',
|
|
33
35
|
'https://docs.openclaw.ai/help/faq',
|
|
34
36
|
'https://docs.openclaw.ai/concepts/memory',
|
|
35
37
|
'https://github.com/NousResearch/hermes-agent',
|
|
38
|
+
'https://hermes-agent.nousresearch.com/docs/user-guide/features/overview/',
|
|
36
39
|
'https://hermes-agent.nousresearch.com/docs/user-guide/features/tools/',
|
|
40
|
+
'https://hermes-agent.nousresearch.com/docs/user-guide/features/skills/',
|
|
37
41
|
'https://hermes-agent.nousresearch.com/docs/user-guide/features/cron/',
|
|
42
|
+
'https://hermes-agent.nousresearch.com/docs/user-guide/features/mcp/',
|
|
43
|
+
'https://hermes-agent.nousresearch.com/docs/user-guide/features/voice-mode/',
|
|
44
|
+
'https://hermes-agent.nousresearch.com/docs/user-guide/features/api-server/',
|
|
38
45
|
'https://hermes-agent.nousresearch.com/docs/user-guide/profiles/',
|
|
39
46
|
] as const;
|
|
40
47
|
|
|
@@ -69,11 +76,11 @@ export const OPERATOR_CAPABILITY_BENCHMARKS: readonly OperatorCapabilityBenchmar
|
|
|
69
76
|
posture: 'configurable',
|
|
70
77
|
competitors: ['openclaw', 'hermes'],
|
|
71
78
|
competitorBaseline: 'Messaging gateway for WhatsApp, Telegram, Slack, Discord, Signal, iMessage, web chat, and related platforms.',
|
|
72
|
-
goodvibesAgent: 'Uses GoodVibes daemon channel, companion, pairing, QR, and session surfaces while keeping side effects behind explicit user action.',
|
|
73
|
-
configure: ['goodvibes-agent pair', 'goodvibes-agent qrcode', 'goodvibes-agent surfaces check'],
|
|
74
|
-
use: ['/
|
|
75
|
-
exceedsBy: ['Agent-owned safety policy over shared channel routes', 'read-only inspection by default', 'explicit approval path for external side effects'],
|
|
76
|
-
next: ['
|
|
79
|
+
goodvibesAgent: 'Uses GoodVibes daemon channel, companion, pairing, QR, communication, and session surfaces while keeping side effects behind explicit user action. The Agent workspace exposes channel setup, per-channel readiness, default-target posture, and risk labels as a first-class operator area.',
|
|
80
|
+
configure: ['goodvibes-agent pair', 'goodvibes-agent qrcode', 'goodvibes-agent surfaces check', '/agent → Channels'],
|
|
81
|
+
use: ['/agent → Channels', '/communication', '/pair'],
|
|
82
|
+
exceedsBy: ['Agent-owned safety policy over shared channel routes', 'read-only inspection by default', 'explicit approval path for external side effects', 'channel setup discoverable from the fullscreen operator workspace', 'per-channel readiness and delivery defaults shown without leaking token values'],
|
|
83
|
+
next: ['Pull live daemon account health and last delivery errors into the Channels workspace when a stable read-only route is available.'],
|
|
77
84
|
},
|
|
78
85
|
{
|
|
79
86
|
id: 'isolated-knowledge-wiki',
|
|
@@ -88,6 +88,27 @@ function snapshotLines(category: AgentWorkspaceCategory, snapshot: AgentWorkspac
|
|
|
88
88
|
{ text: `Workspace: ${snapshot.workingDirectory}`, fg: PALETTE.muted },
|
|
89
89
|
{ text: `Home: ${snapshot.homeDirectory}`, fg: PALETTE.muted },
|
|
90
90
|
);
|
|
91
|
+
} else if (category.id === 'channels') {
|
|
92
|
+
const enabledCount = snapshot.channels.filter((channel) => channel.enabled).length;
|
|
93
|
+
const readyCount = snapshot.channels.filter((channel) => channel.ready).length;
|
|
94
|
+
const configuredDefaults = snapshot.channels.filter((channel) => channel.defaultTarget === 'configured').length;
|
|
95
|
+
const disabledChannels = snapshot.channels.filter((channel) => !channel.enabled).map((channel) => channel.label).join(', ');
|
|
96
|
+
base.push(
|
|
97
|
+
{ text: `External daemon: ${snapshot.daemonBaseUrl}`, fg: PALETTE.info },
|
|
98
|
+
{ text: `Readiness: ${readyCount}/${snapshot.channels.length} ready; ${enabledCount} enabled; ${configuredDefaults} default target(s) configured.`, fg: PALETTE.info },
|
|
99
|
+
{ text: `Disabled channels: ${disabledChannels || 'none'}.`, fg: PALETTE.dim },
|
|
100
|
+
{ text: 'Pairing: use /pair or /qrcode for companion setup.', fg: PALETTE.info },
|
|
101
|
+
{ text: 'Channel posture: inspect via /communication and /setup review.', fg: PALETTE.muted },
|
|
102
|
+
{ text: 'Safety: external delivery, unknown senders, and public exposure require explicit policy and user action.', fg: PALETTE.warn },
|
|
103
|
+
);
|
|
104
|
+
for (const channel of snapshot.channels) {
|
|
105
|
+
const enabled = channel.enabled ? 'enabled' : 'disabled';
|
|
106
|
+
const ready = channel.ready ? 'ready' : `${channel.missingConfigCount} missing`;
|
|
107
|
+
base.push({
|
|
108
|
+
text: `${channel.label}: ${enabled}; ${ready}; default ${channel.defaultTarget}; delivery ${channel.delivery}; risk ${channel.riskLabel}.`,
|
|
109
|
+
fg: channel.ready ? PALETTE.good : channel.enabled ? PALETTE.warn : PALETTE.dim,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
91
112
|
} else if (category.id === 'knowledge') {
|
|
92
113
|
base.push(
|
|
93
114
|
{ text: `Route family: ${snapshot.knowledgeRoute}/{status,ask,search}`, fg: PALETTE.info },
|
|
@@ -222,7 +243,8 @@ function footerText(workspace: AgentWorkspace): string {
|
|
|
222
243
|
}
|
|
223
244
|
|
|
224
245
|
export function renderAgentWorkspace(workspace: AgentWorkspace, width: number, height: number): Line[] {
|
|
225
|
-
const
|
|
246
|
+
const layoutOptions = { width, height, leftWidth: width < 90 ? undefined : 30, contextRatio: 0.62, minContextRows: 10 };
|
|
247
|
+
const metrics = getFullscreenWorkspaceMetrics(layoutOptions);
|
|
226
248
|
const category = workspace.selectedCategory;
|
|
227
249
|
const action = workspace.selectedAction;
|
|
228
250
|
|
|
@@ -237,5 +259,8 @@ export function renderAgentWorkspace(workspace: AgentWorkspace, width: number, h
|
|
|
237
259
|
contextRows: buildContextRows(workspace, category, action, metrics.contextWidth),
|
|
238
260
|
controlRows: buildActionRows(workspace, metrics.contextWidth, metrics.controlRows),
|
|
239
261
|
footer: footerText(workspace),
|
|
262
|
+
leftWidth: layoutOptions.leftWidth,
|
|
263
|
+
contextRatio: layoutOptions.contextRatio,
|
|
264
|
+
minContextRows: layoutOptions.minContextRows,
|
|
240
265
|
});
|
|
241
266
|
}
|
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.30';
|
|
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 {
|