@pellux/goodvibes-agent 0.1.35 → 0.1.37

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.
@@ -4,6 +4,18 @@ import {
4
4
  } from '@pellux/goodvibes-sdk/platform/automation';
5
5
  import type { AutomationJob } from '@pellux/goodvibes-sdk/platform/automation';
6
6
  import type { AutomationScheduleDefinition } from '@pellux/goodvibes-sdk/platform/automation';
7
+ import { AgentRoutineRegistry } from '../../agent/routine-registry.ts';
8
+ import {
9
+ buildRoutineSchedulePreview,
10
+ formatRoutineScheduleFailure,
11
+ formatRoutineSchedulePreview,
12
+ formatRoutineScheduleSuccess,
13
+ parseRoutineSchedulePromotionArgs,
14
+ promoteRoutineToDaemonSchedule,
15
+ resolveAgentDaemonConnection,
16
+ } from '../../agent/routine-schedule-promotion.ts';
17
+ import type { CommandContext } from '../command-registry.ts';
18
+ import { requireShellPaths } from './runtime-services.ts';
7
19
 
8
20
  function formatSchedule(schedule: AutomationScheduleDefinition): string {
9
21
  switch (schedule.kind) {
@@ -31,35 +43,66 @@ function formatPrompt(job: AutomationJob): string {
31
43
 
32
44
  function printReadOnlyScheduleBoundary(print: (text: string) => void, requestedAction: string): void {
33
45
  print([
34
- 'GoodVibes Agent schedule commands are read-only in this runtime.',
46
+ 'GoodVibes Agent local schedule commands are read-only in this runtime.',
35
47
  ` requested: ${requestedAction}`,
36
48
  ' policy: no local Agent automation jobs, scheduled spawns, or immediate automation runs',
37
49
  ' use: /schedule list',
38
- ' future: mutate schedules through an Agent-safe public daemon route after explicit approval',
50
+ ' daemon route: use /schedule promote-routine <routine> --cron <expr> --yes to create an external daemon schedule explicitly',
39
51
  ].join('\n'));
40
52
  }
41
53
 
54
+ async function promoteRoutineSchedule(args: readonly string[], ctx: CommandContext): Promise<void> {
55
+ const parsed = parseRoutineSchedulePromotionArgs(args);
56
+ if (parsed.errors.length > 0) {
57
+ ctx.print([
58
+ 'Usage: /schedule promote-routine <routine-id> (--cron <expr>|--every <interval>|--at <iso-time>) [--timezone <tz>] [--name <schedule-name>] [--provider <id>] [--model <model>] [--disabled] --yes',
59
+ ...parsed.errors.map((error) => ` ${error}`),
60
+ ].join('\n'));
61
+ return;
62
+ }
63
+ const shellPaths = requireShellPaths(ctx);
64
+ const routine = AgentRoutineRegistry.fromShellPaths(shellPaths).get(parsed.routineId ?? '');
65
+ if (!routine) {
66
+ ctx.print(`Unknown Agent routine: ${parsed.routineId ?? ''}`);
67
+ return;
68
+ }
69
+ const preview = buildRoutineSchedulePreview(routine, parsed);
70
+ if (!parsed.yes) {
71
+ ctx.print(formatRoutineSchedulePreview(preview));
72
+ return;
73
+ }
74
+ const connection = resolveAgentDaemonConnection(ctx.platform.configManager, shellPaths.homeDirectory);
75
+ const result = await promoteRoutineToDaemonSchedule(connection, preview);
76
+ ctx.print(result.ok ? formatRoutineScheduleSuccess(result) : formatRoutineScheduleFailure(result));
77
+ }
78
+
42
79
  export function registerScheduleRuntimeCommands(registry: CommandRegistry): void {
43
80
  registry.register({
44
81
  name: 'schedule',
45
82
  aliases: ['sched'],
46
- description: 'Inspect automation jobs and scheduled runs',
47
- usage: 'list',
48
- argsHint: 'list',
83
+ description: 'Inspect schedules and explicitly promote local Agent routines to daemon schedules',
84
+ usage: 'list | promote-routine <routine-id> --cron <expr> --yes',
85
+ argsHint: 'list | promote-routine <routine-id> --cron <expr> --yes',
49
86
  async handler(args, ctx) {
87
+ const sub = args[0];
88
+
89
+ if (sub === 'promote-routine' || sub === 'promote' || sub === 'create-routine-schedule') {
90
+ await promoteRoutineSchedule(args.slice(1), ctx);
91
+ return;
92
+ }
93
+
50
94
  const manager = ctx.ops.automationManager;
51
95
  if (!manager) {
52
96
  ctx.print('Automation manager is not available in this runtime.');
53
97
  return;
54
98
  }
55
- const sub = args[0];
56
99
 
57
100
  if (!sub || sub === 'list') {
58
101
  const jobs = manager.listJobs();
59
102
  if (jobs.length === 0) {
60
103
  ctx.print(
61
104
  'No automation jobs.\n'
62
- + 'Agent schedule commands are read-only here; create/run/enable/disable/remove are blocked until an Agent-safe route exists.'
105
+ + 'Local add/run/enable/disable/remove are blocked. Use /schedule promote-routine <routine> --cron <expr> --yes for an explicit external daemon schedule.'
63
106
  );
64
107
  return;
65
108
  }
@@ -84,7 +127,8 @@ export function registerScheduleRuntimeCommands(registry: CommandRegistry): void
84
127
  ctx.print(
85
128
  'Usage:\n'
86
129
  + ' /schedule list\n'
87
- + ' Agent schedule mutations and runs are blocked until an Agent-safe route exists.'
130
+ + ' /schedule promote-routine <routine-id> (--cron <expr>|--every <interval>|--at <iso-time>) --yes\n'
131
+ + ' Local schedule mutations and runs remain blocked.'
88
132
  );
89
133
  },
90
134
  });
@@ -53,6 +53,7 @@ import { registerTtsRuntimeCommands } from './commands/tts-runtime.ts';
53
53
  import { registerCloudflareRuntimeCommands } from './commands/cloudflare-runtime.ts';
54
54
  import { registerWorkPlanRuntimeCommands } from './commands/work-plan-runtime.ts';
55
55
  import { registerAgentWorkspaceRuntimeCommands } from './commands/agent-workspace-runtime.ts';
56
+ import { registerAgentRuntimeProfileRuntimeCommands } from './commands/agent-runtime-profile-runtime.ts';
56
57
  import { registerAgentExternalizedTuiCommands } from './commands/agent-externalized-tui.ts';
57
58
  import { registerDelegationRuntimeCommands } from './commands/delegation-runtime.ts';
58
59
  import { registerPersonasRuntimeCommands } from './commands/personas-runtime.ts';
@@ -67,6 +68,7 @@ import { registerCapabilitiesRuntimeCommands } from './commands/capabilities-run
67
68
  export function registerBuiltinCommands(registry: CommandRegistry): void {
68
69
  registerShellCoreCommands(registry);
69
70
  registerAgentWorkspaceRuntimeCommands(registry);
71
+ registerAgentRuntimeProfileRuntimeCommands(registry);
70
72
  registerCapabilitiesRuntimeCommands(registry);
71
73
  registerPersonasRuntimeCommands(registry);
72
74
  registerAgentSkillsRuntimeCommands(registry);
@@ -160,11 +160,11 @@ export const OPERATOR_CAPABILITY_BENCHMARKS: readonly OperatorCapabilityBenchmar
160
160
  posture: 'ready',
161
161
  competitors: ['hermes'],
162
162
  competitorBaseline: 'Profiles run independent agents with isolated configs, sessions, skills, memory, cron jobs, and gateway state.',
163
- goodvibesAgent: 'Supports GOODVIBES_AGENT_HOME and named --agent-profile homes for isolated Agent-local config, sessions, memory, personas, skills, routines, setup, and bundles; daemon remains shared/external by design. The Agent workspace exposes runtime profile posture, config profiles, profile sync, setup transfer shortcuts, starter profile templates, and local starter import/export.',
164
- configure: ['GOODVIBES_AGENT_HOME=<path> goodvibes-agent status', 'goodvibes-agent profiles create household --template household --yes', 'goodvibes-agent profiles templates export research ./starter.json --yes', '/agent → Profiles & Portability'],
165
- use: ['goodvibes-agent --agent-profile household', '/profiles', '/profilesync list', '/setup transfer export <path> --yes'],
166
- exceedsBy: ['Typed support bundles', 'explicit daemon boundary', 'no accidental cross-product knowledge fallback', 'profile isolation without hidden daemon lifecycle ownership', 'fullscreen profile and portability workflow discovery', 'curated local starter packs', 'editable starter templates'],
167
- next: ['Add guided starter authoring inside the fullscreen Agent workspace.'],
163
+ goodvibesAgent: 'Supports GOODVIBES_AGENT_HOME and named --agent-profile homes for isolated Agent-local config, sessions, memory, personas, skills, routines, setup, and bundles; daemon remains shared/external by design. The Agent workspace exposes runtime profile posture, config profiles, profile sync, setup transfer shortcuts, starter profile templates, and local starter authoring.',
164
+ configure: ['GOODVIBES_AGENT_HOME=<path> goodvibes-agent status', 'goodvibes-agent profiles create household --template household --yes', 'goodvibes-agent profiles templates export research ./starter.json --yes', '/agent-profile guide', '/agent → Profiles & Portability'],
165
+ use: ['goodvibes-agent --agent-profile household', '/agent-profile templates', '/profiles', '/profilesync list', '/setup transfer export <path> --yes'],
166
+ exceedsBy: ['Typed support bundles', 'explicit daemon boundary', 'no accidental cross-product knowledge fallback', 'profile isolation without hidden daemon lifecycle ownership', 'fullscreen profile and portability workflow discovery', 'curated local starter packs', 'editable starter templates', 'TUI-guided starter authoring'],
167
+ next: ['Add visual starter-template editing inside the fullscreen Agent workspace.'],
168
168
  },
169
169
  {
170
170
  id: 'security-approvals',
@@ -132,9 +132,10 @@ function snapshotLines(category: AgentWorkspaceCategory, snapshot: AgentWorkspac
132
132
  { text: `Active runtime profile: ${snapshot.activeRuntimeProfile}`, fg: PALETTE.info },
133
133
  { text: `Runtime profiles under this home: ${snapshot.runtimeProfileCount}`, fg: PALETTE.info },
134
134
  { text: `Runtime profile root: ${snapshot.runtimeProfileRoot}`, fg: PALETTE.muted },
135
+ { text: `Starter templates: ${snapshot.runtimeStarterTemplateCount}; local custom: ${snapshot.localStarterTemplateCount}`, fg: PALETTE.info },
135
136
  { text: `Config profiles: ${snapshot.configProfileCount}`, fg: PALETTE.info },
136
137
  { text: 'Named runtime profiles isolate Agent-local config, sessions, memory, personas, skills, routines, setup, and bundles.', fg: PALETTE.good },
137
- { text: 'Starter templates: household, research, travel, operations, personal-productivity.', fg: PALETTE.info },
138
+ { text: 'Starter authoring: browse, export, edit, import, and create Agent profiles from inside this workspace via /agent-profile.', fg: PALETTE.info },
138
139
  { text: 'The external daemon remains shared unless the daemon host is configured separately.', fg: PALETTE.warn },
139
140
  { text: 'Portable bundles require explicit export/import commands with real paths and --yes.', fg: PALETTE.muted },
140
141
  );
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.35';
9
+ let _version = '0.1.37';
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 {