@pellux/goodvibes-agent 0.1.1 → 0.1.3

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.
Files changed (52) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +12 -1
  3. package/docs/README.md +2 -0
  4. package/docs/getting-started.md +19 -1
  5. package/docs/release-and-publishing.md +3 -1
  6. package/package.json +10 -1
  7. package/src/agent/persona-registry.ts +379 -0
  8. package/src/agent/skill-registry.ts +360 -0
  9. package/src/audio/spoken-turn-model-routing.ts +2 -1
  10. package/src/cli/agent-knowledge-command.ts +525 -0
  11. package/src/cli/help.ts +35 -0
  12. package/src/cli/management-commands.ts +3 -1
  13. package/src/cli/management.ts +33 -9
  14. package/src/cli/parser.ts +7 -0
  15. package/src/cli/types.ts +3 -0
  16. package/src/config/surface.ts +1 -0
  17. package/src/input/agent-workspace.ts +33 -3
  18. package/src/input/command-registry.ts +4 -1
  19. package/src/input/commands/agent-skills-runtime.ts +216 -0
  20. package/src/input/commands/delegation-runtime.ts +129 -0
  21. package/src/input/commands/knowledge.ts +18 -18
  22. package/src/input/commands/personas-runtime.ts +219 -0
  23. package/src/input/commands/shell-core.ts +9 -6
  24. package/src/input/commands/skills-runtime.ts +7 -2
  25. package/src/input/commands.ts +6 -0
  26. package/src/input/panel-integration-actions.ts +0 -52
  27. package/src/input/submission-router.ts +1 -1
  28. package/src/main.ts +2 -1
  29. package/src/panels/builtin/agent.ts +0 -14
  30. package/src/panels/builtin/session.ts +4 -3
  31. package/src/panels/index.ts +0 -5
  32. package/src/panels/orchestration-panel.ts +4 -5
  33. package/src/panels/qr-panel.ts +3 -2
  34. package/src/panels/tasks-panel.ts +4 -4
  35. package/src/renderer/agent-workspace.ts +2 -0
  36. package/src/runtime/bootstrap-command-context.ts +3 -0
  37. package/src/runtime/bootstrap-command-parts.ts +6 -2
  38. package/src/runtime/bootstrap-core.ts +8 -4
  39. package/src/runtime/bootstrap-shell.ts +5 -2
  40. package/src/runtime/bootstrap.ts +10 -2
  41. package/src/runtime/cloudflare-control-plane.ts +2 -1
  42. package/src/version.ts +1 -1
  43. package/src/daemon/cli.ts +0 -55
  44. package/src/daemon/safe-serve.ts +0 -61
  45. package/src/panels/diff-panel.ts +0 -520
  46. package/src/panels/file-explorer-panel.ts +0 -584
  47. package/src/panels/file-preview-panel.ts +0 -434
  48. package/src/panels/git-panel.ts +0 -638
  49. package/src/panels/sandbox-panel.ts +0 -283
  50. package/src/panels/symbol-outline-panel.ts +0 -486
  51. package/src/panels/worktree-panel.ts +0 -182
  52. package/src/panels/wrfc-panel.ts +0 -609
@@ -7,6 +7,7 @@ import {
7
7
  } from './polish.ts';
8
8
  import { renderQrMatrix, generateQrMatrix } from '../renderer/qr-renderer.ts';
9
9
  import { encodeConnectionPayload } from '@pellux/goodvibes-sdk/platform/pairing';
10
+ import { GOODVIBES_AGENT_PAIRING_SURFACE } from '../config/surface.ts';
10
11
 
11
12
  const C = {
12
13
  ...DEFAULT_PANEL_PALETTE,
@@ -32,7 +33,7 @@ export interface QrPanelConnectionInfo {
32
33
  readonly password?: string;
33
34
  /** SDK/surface version (defaults to '0.0.0' if omitted) */
34
35
  readonly version?: string;
35
- /** Surface identifier (defaults to 'tui' if omitted) */
36
+ /** Surface identifier (defaults to GoodVibes Agent if omitted) */
36
37
  readonly surface?: string;
37
38
  }
38
39
 
@@ -139,7 +140,7 @@ export class QrPanel extends BasePanel {
139
140
  username: this.connectionInfo.username,
140
141
  ...(this.connectionInfo.password !== undefined ? { password: this.connectionInfo.password } : {}),
141
142
  version: this.connectionInfo.version ?? '0.0.0',
142
- surface: this.connectionInfo.surface ?? 'tui',
143
+ surface: this.connectionInfo.surface ?? GOODVIBES_AGENT_PAIRING_SURFACE,
143
144
  });
144
145
  const matrix = generateQrMatrix(payload);
145
146
  const qrLines = renderQrMatrix(matrix.modules, width, { fg: C.qrFg, bg: C.qrBg });
@@ -179,7 +179,7 @@ export class TasksPanel extends ScrollableListPanel<RuntimeTask> {
179
179
  protected override getEmptyStateActions() {
180
180
  return [
181
181
  { command: '/tasks create', summary: 'create a tracked task from the shell' },
182
- { command: '/orchestration', summary: 'review graph-native task execution and WRFC flows' },
182
+ { command: '/delegate <task>', summary: 'send explicit build/fix/review work to GoodVibes TUI' },
183
183
  ];
184
184
  }
185
185
 
@@ -276,8 +276,8 @@ export class TasksPanel extends ScrollableListPanel<RuntimeTask> {
276
276
  ]));
277
277
  }
278
278
  postureLines.push(
279
- buildGuidanceLine(width, '/teamwork review', 'inspect task-family posture, archetype metadata, and recovery options for active work', C),
280
- buildGuidanceLine(width, '/worktree task <task-id>', 'review worktree ownership, restore, and merge posture for the selected task', C),
279
+ buildGuidanceLine(width, '/tasks', 'inspect local runtime task posture without starting background agents', C),
280
+ buildGuidanceLine(width, '/delegate <task>', 'delegate explicit build/fix/review work to GoodVibes TUI when code execution is required', C),
281
281
  );
282
282
 
283
283
  const detailRows: Line[] = [];
@@ -354,7 +354,7 @@ export class TasksPanel extends ScrollableListPanel<RuntimeTask> {
354
354
  [String(attachedWorktrees.paused), attachedWorktrees.paused > 0 ? C.blocked : C.dim],
355
355
  ]));
356
356
  detailRows.push(buildPanelLine(width, [[
357
- ` Next: /worktree task ${selected.id} /worktree recover task ${selected.id}`,
357
+ ' Worktree lifecycle is externalized; open GoodVibes TUI in the target workspace for recovery.',
358
358
  C.dim,
359
359
  ]]));
360
360
  for (const record of attachedWorktrees.records.slice(0, 2)) {
@@ -97,6 +97,8 @@ function snapshotLines(category: AgentWorkspaceCategory, snapshot: AgentWorkspac
97
97
  } else if (category.id === 'memory') {
98
98
  base.push(
99
99
  { text: `Session memories: ${snapshot.sessionMemoryCount}`, fg: PALETTE.info },
100
+ { text: `Local skills: ${snapshot.localSkillCount}; enabled: ${snapshot.enabledSkillCount}`, fg: PALETTE.info },
101
+ { text: `Local personas: ${snapshot.localPersonaCount}; active: ${snapshot.activePersonaName}`, fg: PALETTE.info },
100
102
  { text: 'Durable memory, skills, and personas remain Agent-local until shared registry contracts exist.', fg: PALETTE.good },
101
103
  { text: 'Secrets are rejected/redacted; store secret references instead of secret values.', fg: PALETTE.warn },
102
104
  );
@@ -100,6 +100,7 @@ export type CreateBootstrapCommandContextOptions = {
100
100
  sessionOrchestration?: ShellSessionOrchestrationService;
101
101
  operatorClient?: OperatorClient;
102
102
  peerClient?: PeerClient;
103
+ agentKnowledgeApi?: KnowledgeApi;
103
104
  knowledgeApi?: KnowledgeApi;
104
105
  hookApi?: HookApi;
105
106
  mcpApi?: McpApi;
@@ -170,6 +171,7 @@ export function createBootstrapCommandContext(
170
171
  sessionOrchestration,
171
172
  operatorClient,
172
173
  peerClient,
174
+ agentKnowledgeApi,
173
175
  knowledgeApi,
174
176
  hookApi,
175
177
  mcpApi,
@@ -245,6 +247,7 @@ export function createBootstrapCommandContext(
245
247
  const clients = createBootstrapCommandClientsSection({
246
248
  operatorClient,
247
249
  peerClient,
250
+ agentKnowledgeApi,
248
251
  providerApi,
249
252
  knowledgeApi,
250
253
  hookApi,
@@ -117,6 +117,7 @@ export interface BootstrapCommandSectionOptions {
117
117
  readonly operatorClient?: OperatorClient;
118
118
  readonly peerClient?: PeerClient;
119
119
  readonly providerApi?: ProviderApi;
120
+ readonly agentKnowledgeApi?: KnowledgeApi;
120
121
  readonly knowledgeApi?: KnowledgeApi;
121
122
  readonly hookApi?: HookApi;
122
123
  readonly mcpApi?: McpApi;
@@ -360,23 +361,26 @@ export function createBootstrapCommandExtensionsSection(
360
361
  >,
361
362
  shellServices: BootstrapCommandShellServices,
362
363
  ): BootstrapCommandExtensionSection {
364
+ const shellExtensionServices = shellServices.extensions;
363
365
  return {
364
366
  toolRegistry: options.toolRegistry,
365
367
  mcpRegistry: options.mcpRegistry,
366
- ...shellServices.extensions,
368
+ ...shellExtensionServices,
369
+ agentKnowledgeService: shellExtensionServices.knowledgeService,
367
370
  };
368
371
  }
369
372
 
370
373
  export function createBootstrapCommandClientsSection(
371
374
  options: Pick<
372
375
  BootstrapCommandSectionOptions,
373
- 'operatorClient' | 'peerClient' | 'providerApi' | 'knowledgeApi' | 'hookApi' | 'mcpApi' | 'opsApi' | 'directTransport'
376
+ 'operatorClient' | 'peerClient' | 'providerApi' | 'agentKnowledgeApi' | 'knowledgeApi' | 'hookApi' | 'mcpApi' | 'opsApi' | 'directTransport'
374
377
  >,
375
378
  ): BootstrapCommandClientSection {
376
379
  return {
377
380
  operator: options.operatorClient,
378
381
  peer: options.peerClient,
379
382
  providerApi: options.providerApi,
383
+ agentKnowledgeApi: options.agentKnowledgeApi,
380
384
  knowledgeApi: options.knowledgeApi,
381
385
  hookApi: options.hookApi,
382
386
  mcpApi: options.mcpApi,
@@ -126,16 +126,20 @@ export async function initializeBootstrapCore(
126
126
  isRunning: Boolean(configManager.get('controlPlane.enabled')),
127
127
  }, 'bootstrap.control-plane');
128
128
  domainDispatch.syncControlPlaneClient({
129
- id: 'client:tui',
130
- kind: 'tui',
131
- label: 'Terminal UI',
129
+ id: 'client:goodvibes-agent',
130
+ kind: 'service',
131
+ label: 'GoodVibes Agent',
132
132
  transport: 'local',
133
133
  connected: true,
134
134
  sessionId: userSessionId,
135
135
  authenticatedAt: Date.now(),
136
136
  lastSeenAt: Date.now(),
137
137
  capabilities: ['session', 'panels', 'commands', 'automation'],
138
- metadata: {},
138
+ metadata: {
139
+ product: 'goodvibes-agent',
140
+ surfaceRoot: GOODVIBES_AGENT_SURFACE_ROOT,
141
+ clientKindNote: 'SDK has no dedicated agent client kind yet; using service for the Agent operator surface.',
142
+ },
139
143
  }, 'bootstrap.control-plane');
140
144
 
141
145
  const {
@@ -33,6 +33,7 @@ import type { TaskManager } from '@/runtime/index.ts';
33
33
  import type { UiRuntimeServices } from './ui-services.ts';
34
34
  import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
35
35
  import { GOODVIBES_AGENT_SURFACE_ROOT } from '../config/surface.ts';
36
+ import { createKnowledgeApi } from '@pellux/goodvibes-sdk/platform/knowledge';
36
37
 
37
38
  export interface BootstrapShellState {
38
39
  readonly commandRegistry: CommandRegistry;
@@ -176,6 +177,7 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
176
177
  opsApi,
177
178
  providerApi,
178
179
  } = foundationClients;
180
+ const agentKnowledgeApi = createKnowledgeApi(services.agentKnowledgeService, { memoryRegistry: services.memoryRegistry });
179
181
  const remoteRuntime = createShellRemoteCommandService({
180
182
  readModels: uiServices.readModels,
181
183
  remoteRunnerRegistry: services.remoteRunnerRegistry,
@@ -208,7 +210,7 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
208
210
  memoryRegistry: services.memoryRegistry,
209
211
  integrationHelpers: services.integrationHelpers,
210
212
  automationManager: services.automationManager,
211
- knowledgeService: services.knowledgeService,
213
+ knowledgeService: services.agentKnowledgeService,
212
214
  projectPlanningService: services.projectPlanningService,
213
215
  projectPlanningProjectId: services.projectPlanningProjectId,
214
216
  workPlanStore: services.workPlanStore,
@@ -238,7 +240,8 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
238
240
  sessionOrchestration: services.sessionOrchestration,
239
241
  operatorClient: directTransport.operator,
240
242
  peerClient: directTransport.peer,
241
- knowledgeApi,
243
+ agentKnowledgeApi,
244
+ knowledgeApi: agentKnowledgeApi,
242
245
  hookApi,
243
246
  mcpApi,
244
247
  opsApi,
@@ -42,6 +42,8 @@ import { createBootstrapShell } from './bootstrap-shell.ts';
42
42
  import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
43
43
  import { startMcpConfigAutoReload } from '../mcp/runtime-reload.ts';
44
44
  import { GOODVIBES_AGENT_SURFACE_ROOT } from '../config/surface.ts';
45
+ import { buildActivePersonaPrompt } from '../agent/persona-registry.ts';
46
+ import { buildEnabledSkillsPrompt } from '../agent/skill-registry.ts';
45
47
 
46
48
  const GOODVIBES_AGENT_OPERATOR_POLICY = [
47
49
  '## GoodVibes Agent Operator Policy',
@@ -50,7 +52,7 @@ const GOODVIBES_AGENT_OPERATOR_POLICY = [
50
52
  '- WRFC is never the default Agent reasoning path. Do not create local WRFC chains for planning, research, operations, knowledge, memory, configuration, approvals, automation observability, or ordinary assistant work.',
51
53
  '- GoodVibes Agent is not the coding TUI. Do not use the `agent` tool to spawn local Engineer, Reviewer, Tester, Verifier, or batch-spawn roots from Agent.',
52
54
  '- When the user explicitly asks to build, implement, fix, patch, or review code, preserve the full original user ask and delegate one build request to GoodVibes TUI through the public shared-session/build-delegation contract. Include clear executionIntent and request WRFC only for explicit build/fix/review work or when the user explicitly asks for WRFC/agent review.',
53
- '- Do not narrow explicit build/fix/review requests into design-only, read-only, or no-write work unless the user explicitly requested that limitation. TUI owns file edits, git/worktree work, sandbox/QEMU UX, and any WRFC owner chain.',
55
+ '- Do not narrow explicit build/fix/review requests into design-only, read-only, or no-write work unless the user explicitly requested that limitation. TUI owns file edits, git/worktree work, sandbox/QEMU UX, and the WRFC owner chain.',
54
56
  '- If a stable public delegation route is unavailable, say that the task needs GoodVibes TUI delegation and report the missing route instead of pretending to implement it locally or spawning sibling local agents.',
55
57
  ].join('\n');
56
58
 
@@ -205,7 +207,13 @@ export async function bootstrapRuntime(
205
207
  const contextWindow = providerRegistry.getContextWindowForModel(currentModel);
206
208
  const tier = getTierForContextWindow(contextWindow);
207
209
  const supplement = getTierPromptSupplement(tier);
208
- return joinPromptParts(runtime.systemPrompt, GOODVIBES_AGENT_OPERATOR_POLICY, supplement);
210
+ return joinPromptParts(
211
+ runtime.systemPrompt,
212
+ GOODVIBES_AGENT_OPERATOR_POLICY,
213
+ buildEnabledSkillsPrompt(services.shellPaths),
214
+ buildActivePersonaPrompt(services.shellPaths),
215
+ supplement,
216
+ );
209
217
  },
210
218
  hookDispatcher,
211
219
  flagManager: services.featureFlags,
@@ -1,6 +1,7 @@
1
1
  import { join } from 'node:path';
2
2
  import { getOrCreateCompanionToken } from '@pellux/goodvibes-sdk/platform/pairing';
3
3
  import type { ConfigManager } from '../config/index.ts';
4
+ import { GOODVIBES_AGENT_PAIRING_SURFACE } from '../config/surface.ts';
4
5
 
5
6
  export const CLOUDFLARE_COMPONENT_IDS = [
6
7
  'workers',
@@ -296,7 +297,7 @@ export function buildDefaultCloudflareDaemonBaseUrl(configManager: Pick<ConfigMa
296
297
 
297
298
  function readDaemonToken(homeDirectory: string): string {
298
299
  const daemonHomeDir = join(homeDirectory, '.goodvibes', 'daemon');
299
- return getOrCreateCompanionToken('tui', { daemonHomeDir }).token;
300
+ return getOrCreateCompanionToken(GOODVIBES_AGENT_PAIRING_SURFACE, { daemonHomeDir }).token;
300
301
  }
301
302
 
302
303
  async function readJsonResponse<T>(response: Response): Promise<T> {
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.1';
9
+ let _version = '0.1.3';
10
10
  try {
11
11
  const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8'));
12
12
  _version = pkg.version ?? _version;
package/src/daemon/cli.ts DELETED
@@ -1,55 +0,0 @@
1
- #!/usr/bin/env bun
2
- import {
3
- parseGoodVibesCli,
4
- renderGoodVibesDaemonHelp,
5
- renderGoodVibesVersion,
6
- } from '../cli/index.ts';
7
-
8
- function externalDaemonMessage(binary: string): string {
9
- return [
10
- `${binary} is disabled in GoodVibes Agent.`,
11
- 'GoodVibes Agent connects to an already-running GoodVibes daemon and never starts, installs, restarts, or owns daemon/listener lifecycle.',
12
- 'Start or manage the daemon from GoodVibes TUI or your daemon host tooling, then run goodvibes-agent against that external daemon.',
13
- ].join('\n');
14
- }
15
-
16
- async function main(): Promise<void> {
17
- const binary = 'goodvibes-daemon';
18
- const cli = parseGoodVibesCli(process.argv.slice(2), binary);
19
-
20
- if (cli.errors.length > 0) {
21
- console.error(cli.errors.join('\n'));
22
- console.error('');
23
- console.error(renderGoodVibesDaemonHelp(binary));
24
- process.exit(2);
25
- }
26
-
27
- if (cli.flags.help || cli.command === 'help') {
28
- console.log(renderGoodVibesDaemonHelp(binary));
29
- process.exit(0);
30
- }
31
-
32
- if (cli.flags.version || cli.command === 'version') {
33
- console.log(renderGoodVibesVersion('goodvibes-agent'));
34
- process.exit(0);
35
- }
36
-
37
- const message = externalDaemonMessage(binary);
38
- if (cli.flags.outputFormat === 'json') {
39
- console.log(JSON.stringify({
40
- ok: false,
41
- kind: 'daemon_lifecycle_external',
42
- command: binary,
43
- error: message,
44
- }, null, 2));
45
- } else {
46
- console.error(message);
47
- }
48
- process.exit(2);
49
- }
50
-
51
- main().catch((error: unknown) => {
52
- const message = error instanceof Error ? error.message : String(error);
53
- console.error(message);
54
- process.exit(1);
55
- });
@@ -1,61 +0,0 @@
1
- import { logger } from '@pellux/goodvibes-sdk/platform/utils';
2
- import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
3
-
4
- type HostServeFetch = (
5
- request: Request,
6
- server: unknown,
7
- ) => Response | undefined | Promise<Response | undefined>;
8
-
9
- type HostServeOptions = Parameters<typeof Bun.serve>[0] & {
10
- fetch?: HostServeFetch;
11
- };
12
-
13
- function requestPath(request: Request): string {
14
- try {
15
- return new URL(request.url).pathname;
16
- } catch {
17
- return request.url;
18
- }
19
- }
20
-
21
- export function createHostRequestFailureResponse(
22
- surface: string,
23
- request: Request,
24
- error: unknown,
25
- ): Response {
26
- const message = summarizeError(error);
27
- logger.error(`${surface}: request handler failed`, {
28
- method: request.method,
29
- path: requestPath(request),
30
- error: message,
31
- });
32
- return Response.json({
33
- error: message,
34
- code: 'HOST_REQUEST_HANDLER_FAILED',
35
- }, { status: 500 });
36
- }
37
-
38
- export function createSafeHostServeFactory(
39
- surface: string,
40
- baseServeFactory: typeof Bun.serve = Bun.serve,
41
- ): typeof Bun.serve {
42
- return ((options: HostServeOptions) => {
43
- const originalFetch = options.fetch;
44
- if (typeof originalFetch !== 'function') {
45
- return baseServeFactory(options as Parameters<typeof Bun.serve>[0]);
46
- }
47
-
48
- const wrappedFetch: HostServeFetch = async (request, server) => {
49
- try {
50
- return await originalFetch(request, server);
51
- } catch (error) {
52
- return createHostRequestFailureResponse(surface, request, error);
53
- }
54
- };
55
-
56
- return baseServeFactory({
57
- ...options,
58
- fetch: wrappedFetch,
59
- } as Parameters<typeof Bun.serve>[0]);
60
- }) as typeof Bun.serve;
61
- }