@pellux/goodvibes-agent 0.1.77 → 0.1.78

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,11 @@
2
2
 
3
3
  All notable changes to GoodVibes Agent will be recorded here.
4
4
 
5
+ ## 0.1.78 - 2026-06-01
6
+
7
+ - Expanded the Agent channel workspace into a concrete readiness matrix with setup state, missing runtime config keys, default-target posture, and safe next steps for each externally owned channel.
8
+ - Kept channel setup read-only inside Agent: no runtime lifecycle ownership, no hidden sends, and no secret values rendered.
9
+
5
10
  ## 0.1.77 - 2026-06-01
6
11
 
7
12
  - Added a first-class Agent profile creation form inside the fullscreen operator workspace instead of dispatching a placeholder command template.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pellux/goodvibes-agent",
3
- "version": "0.1.77",
3
+ "version": "0.1.78",
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",
@@ -7,11 +7,17 @@ export interface AgentWorkspaceChannelStatus {
7
7
  readonly label: string;
8
8
  readonly enabled: boolean;
9
9
  readonly ready: boolean;
10
+ readonly requiredKeys: readonly string[];
11
+ readonly missingRequiredKeys: readonly string[];
10
12
  readonly missingConfigCount: number;
13
+ readonly defaultTargetKeys: readonly string[];
14
+ readonly configuredDefaultTargetKeys: readonly string[];
11
15
  readonly defaultTarget: 'configured' | 'missing' | 'not-required';
12
16
  readonly delivery: 'disabled' | 'blocked' | 'explicit-target' | 'default-ready';
13
17
  readonly risk: AgentWorkspaceChannelRisk;
14
18
  readonly riskLabel: string;
19
+ readonly setupState: 'disabled' | 'needs-config' | 'needs-target' | 'ready';
20
+ readonly nextStep: string;
15
21
  }
16
22
 
17
23
  interface AgentWorkspaceConfigReader {
@@ -182,10 +188,12 @@ function hasConfigValue(context: CommandContext, key: string): boolean {
182
188
 
183
189
  function buildChannelStatus(context: CommandContext, spec: AgentWorkspaceChannelSpec): AgentWorkspaceChannelStatus {
184
190
  const enabled = readConfigBoolean(context, spec.enabledKey, false);
185
- const missingConfigCount = spec.requiredKeys.filter((key) => !hasConfigValue(context, key)).length;
191
+ const missingRequiredKeys = spec.requiredKeys.filter((key) => !hasConfigValue(context, key));
192
+ const configuredDefaultTargetKeys = spec.defaultTargetKeys.filter((key) => hasConfigValue(context, key));
193
+ const missingConfigCount = missingRequiredKeys.length;
186
194
  const defaultTarget = spec.defaultTargetKeys.length === 0
187
195
  ? 'not-required'
188
- : spec.defaultTargetKeys.some((key) => hasConfigValue(context, key))
196
+ : configuredDefaultTargetKeys.length > 0
189
197
  ? 'configured'
190
198
  : 'missing';
191
199
  const ready = enabled && missingConfigCount === 0;
@@ -196,16 +204,36 @@ function buildChannelStatus(context: CommandContext, spec: AgentWorkspaceChannel
196
204
  : defaultTarget === 'configured'
197
205
  ? 'default-ready'
198
206
  : 'explicit-target';
207
+ const setupState = !enabled
208
+ ? 'disabled'
209
+ : missingConfigCount > 0
210
+ ? 'needs-config'
211
+ : defaultTarget === 'missing'
212
+ ? 'needs-target'
213
+ : 'ready';
214
+ const nextStep = setupState === 'disabled'
215
+ ? `Enable ${spec.label} in the owning GoodVibes runtime before Agent can use it.`
216
+ : setupState === 'needs-config'
217
+ ? `Configure ${missingRequiredKeys.join(', ')} in the owning runtime or secret manager.`
218
+ : setupState === 'needs-target'
219
+ ? `Provide an explicit delivery target per send, or configure one of ${spec.defaultTargetKeys.join(', ')}.`
220
+ : `Use explicit user action or runtime policy to send through ${spec.label}.`;
199
221
  return {
200
222
  id: spec.id,
201
223
  label: spec.label,
202
224
  enabled,
203
225
  ready,
226
+ requiredKeys: spec.requiredKeys,
227
+ missingRequiredKeys,
204
228
  missingConfigCount,
229
+ defaultTargetKeys: spec.defaultTargetKeys,
230
+ configuredDefaultTargetKeys,
205
231
  defaultTarget,
206
232
  delivery,
207
233
  risk: spec.risk,
208
234
  riskLabel: spec.riskLabel,
235
+ setupState,
236
+ nextStep,
209
237
  };
210
238
  }
211
239
 
@@ -205,23 +205,34 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
205
205
  const enabledCount = snapshot.channels.filter((channel) => channel.enabled).length;
206
206
  const readyCount = snapshot.channels.filter((channel) => channel.ready).length;
207
207
  const configuredDefaults = snapshot.channels.filter((channel) => channel.defaultTarget === 'configured').length;
208
- const disabledChannels = snapshot.channels.filter((channel) => !channel.enabled).map((channel) => channel.label).join(', ');
208
+ const readyChannels = snapshot.channels.filter((channel) => channel.ready).map((channel) => channel.label);
209
+ const needsTarget = snapshot.channels.filter((channel) => channel.setupState === 'needs-target');
210
+ const needsConfig = snapshot.channels.filter((channel) => channel.setupState === 'needs-config');
211
+ const disabledChannels = snapshot.channels.filter((channel) => !channel.enabled).map((channel) => channel.label);
212
+ const disabledPreview = disabledChannels.slice(0, 6).join(', ');
213
+ const disabledSuffix = disabledChannels.length > 6 ? `, +${disabledChannels.length - 6} more` : '';
214
+ const orderedChannels = [
215
+ ...snapshot.channels.filter((channel) => channel.enabled),
216
+ ...snapshot.channels.filter((channel) => !channel.enabled),
217
+ ].slice(0, 6);
209
218
  base.push(
210
219
  { text: `GoodVibes runtime: ${snapshot.daemonBaseUrl}`, fg: PALETTE.info },
211
220
  { text: `Readiness: ${readyCount}/${snapshot.channels.length} ready; ${enabledCount} enabled; ${configuredDefaults} default target(s) configured.`, fg: PALETTE.info },
212
- { text: `Disabled channels: ${disabledChannels || 'none'}.`, fg: PALETTE.dim },
213
- { text: 'Pairing: use /pair or /qrcode for companion setup.', fg: PALETTE.info },
214
- { text: 'Channel posture: inspect via /communication and /setup review.', fg: PALETTE.muted },
215
- { text: 'Safety: external delivery, unknown senders, and public exposure require explicit policy and user action.', fg: PALETTE.warn },
221
+ { text: `Ready channels: ${readyChannels.join(', ') || 'none'}.`, fg: readyChannels.length > 0 ? PALETTE.good : PALETTE.warn },
222
+ { text: `Needs default target: ${needsTarget.map((channel) => `${channel.label} -> ${channel.defaultTargetKeys.join('|')}`).join(', ') || 'none'}.`, fg: needsTarget.length > 0 ? PALETTE.warn : PALETTE.muted },
223
+ { text: `Needs config: ${needsConfig.map((channel) => `${channel.label} -> ${channel.missingRequiredKeys.join('|')}`).join(', ') || 'none'}.`, fg: needsConfig.length > 0 ? PALETTE.warn : PALETTE.muted },
224
+ { text: `Disabled channels: ${disabledPreview || 'none'}${disabledSuffix}.`, fg: PALETTE.dim },
225
+ { text: 'Safety: no secret values; sends and public exposure require explicit user action and runtime policy.', fg: PALETTE.warn },
216
226
  );
217
- for (const channel of snapshot.channels) {
218
- const enabled = channel.enabled ? 'enabled' : 'disabled';
227
+ for (const channel of orderedChannels) {
219
228
  const ready = channel.ready ? 'ready' : `${channel.missingConfigCount} missing`;
220
229
  base.push({
221
- text: `${channel.label}: ${enabled}; ${ready}; default ${channel.defaultTarget}; delivery ${channel.delivery}; risk ${channel.riskLabel}.`,
230
+ text: `${channel.label}: ${channel.setupState}; ${ready}; target ${channel.defaultTarget}; delivery ${channel.delivery}; risk ${channel.risk}.`,
222
231
  fg: channel.ready ? PALETTE.good : channel.enabled ? PALETTE.warn : PALETTE.dim,
223
232
  });
224
233
  }
234
+ base.push({ text: 'Only config key names and readiness state are rendered here.', fg: PALETTE.muted });
235
+ base.push({ text: 'Pairing: use /pair or /qrcode; inspect routed activity with /communication and /setup review.', fg: PALETTE.info });
225
236
  } else if (category.id === 'knowledge') {
226
237
  base.push(
227
238
  { text: `Route family: ${snapshot.knowledgeRoute}/{status,ask,search}`, fg: PALETTE.info },
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.77';
9
+ let _version = '0.1.78';
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 {