@pellux/goodvibes-agent 0.1.117 → 1.0.0
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 +13 -4
- package/README.md +35 -14
- package/bin/goodvibes-agent.ts +16 -2
- package/dist/package/main.js +176073 -170980
- package/docs/README.md +11 -5
- package/docs/channels-remote-and-api.md +50 -0
- package/docs/connected-host.md +3 -3
- package/docs/getting-started.md +29 -15
- package/docs/knowledge-artifacts-and-multimodal.md +91 -0
- package/docs/project-planning.md +79 -0
- package/docs/providers-and-routing.md +46 -0
- package/docs/release-and-publishing.md +44 -9
- package/docs/tools-and-commands.md +123 -0
- package/docs/voice-and-live-tts.md +51 -0
- package/package.json +2 -5
- package/src/agent/channel-delivery.ts +201 -0
- package/src/agent/media-generation.ts +159 -0
- package/src/agent/memory-prompt.ts +0 -1
- package/src/agent/note-registry.ts +329 -0
- package/src/agent/operator-actions.ts +343 -0
- package/src/agent/persona-registry.ts +15 -14
- package/src/agent/record-labels.ts +107 -0
- package/src/agent/reminder-schedule-format.ts +33 -24
- package/src/agent/reminder-schedule.ts +26 -25
- package/src/agent/routine-registry.ts +13 -12
- package/src/agent/routine-schedule-args.ts +2 -1
- package/src/agent/routine-schedule-format.ts +77 -53
- package/src/agent/routine-schedule-promotion.ts +34 -32
- package/src/agent/routine-schedule-receipts.ts +28 -26
- package/src/agent/runtime-profile-starters.ts +2 -2
- package/src/agent/runtime-profile.ts +18 -17
- package/src/agent/skill-registry.ts +25 -24
- package/src/cli/agent-knowledge-args.ts +5 -1
- package/src/cli/agent-knowledge-command.ts +39 -33
- package/src/cli/agent-knowledge-format.ts +80 -67
- package/src/cli/agent-knowledge-methods.ts +1 -1
- package/src/cli/agent-knowledge-runtime.ts +32 -26
- package/src/cli/bundle-command.ts +13 -8
- package/src/cli/config-overrides.ts +37 -36
- package/src/cli/external-runtime.ts +10 -4
- package/src/cli/help.ts +29 -11
- package/src/cli/local-library-command.ts +134 -68
- package/src/cli/management-commands.ts +98 -62
- package/src/cli/management.ts +52 -26
- package/src/cli/memory-command.ts +66 -32
- package/src/cli/parser.ts +37 -24
- package/src/cli/profiles-command.ts +52 -35
- package/src/cli/provider-auth-routes.ts +2 -1
- package/src/cli/routines-command.ts +44 -36
- package/src/cli/service-posture.ts +6 -6
- package/src/cli/status.ts +46 -121
- package/src/core/conversation-message-snapshot.ts +131 -0
- package/src/input/agent-workspace-activation.ts +33 -7
- package/src/input/agent-workspace-basic-command-editor-submission.ts +7 -3
- package/src/input/agent-workspace-basic-command-editors.ts +30 -10
- package/src/input/agent-workspace-categories.ts +276 -64
- package/src/input/agent-workspace-channel-command-editor-submission.ts +34 -0
- package/src/input/agent-workspace-channel-command-editors.ts +23 -5
- package/src/input/agent-workspace-channels.ts +35 -2
- package/src/input/agent-workspace-command-editor.ts +18 -2
- package/src/input/agent-workspace-config-reader.ts +16 -0
- package/src/input/agent-workspace-delegation-editor-submission.ts +1 -1
- package/src/input/agent-workspace-editors.ts +140 -2
- package/src/input/agent-workspace-knowledge-query-editor.ts +1 -1
- package/src/input/agent-workspace-learned-behavior.ts +2 -2
- package/src/input/agent-workspace-library-command-editor-submission.ts +1 -1
- package/src/input/agent-workspace-library-command-editors.ts +2 -2
- package/src/input/agent-workspace-local-operations.ts +218 -0
- package/src/input/agent-workspace-local-selection.ts +75 -0
- package/src/input/agent-workspace-media-command-editor-submission.ts +62 -0
- package/src/input/agent-workspace-media-command-editors.ts +27 -0
- package/src/input/agent-workspace-memory-command-editors.ts +1 -1
- package/src/input/agent-workspace-memory-editor.ts +2 -2
- package/src/input/agent-workspace-navigation.ts +38 -2
- package/src/input/agent-workspace-notify-editor-submission.ts +16 -2
- package/src/input/agent-workspace-operations-command-editor-submission.ts +63 -1
- package/src/input/agent-workspace-operations-command-editors.ts +80 -3
- package/src/input/agent-workspace-panel-route.ts +43 -0
- package/src/input/agent-workspace-reminder-schedule-editor.ts +1 -1
- package/src/input/agent-workspace-routine-schedule-editor.ts +2 -2
- package/src/input/agent-workspace-search.ts +169 -0
- package/src/input/agent-workspace-setup.ts +22 -11
- package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +6 -6
- package/src/input/agent-workspace-skill-bundle-command-editors.ts +10 -10
- package/src/input/agent-workspace-snapshot.ts +112 -13
- package/src/input/agent-workspace-task-command-editors.ts +4 -4
- package/src/input/agent-workspace-token.ts +18 -2
- package/src/input/agent-workspace-types.ts +92 -4
- package/src/input/agent-workspace-voice-media.ts +3 -6
- package/src/input/agent-workspace-web-research-editor.ts +104 -0
- package/src/input/agent-workspace.ts +136 -208
- package/src/input/command-registry.ts +4 -1
- package/src/input/commands/agent-runtime-profile-runtime.ts +45 -41
- package/src/input/commands/agent-skills-runtime.ts +83 -70
- package/src/input/commands/agent-workspace-runtime.ts +23 -7
- package/src/input/commands/brief-runtime.ts +25 -24
- package/src/input/commands/channels-runtime.ts +145 -31
- package/src/input/commands/delegation-runtime.ts +29 -23
- package/src/input/commands/experience-runtime.ts +6 -4
- package/src/input/commands/guidance-runtime.ts +4 -4
- package/src/input/commands/health-runtime.ts +140 -115
- package/src/input/commands/knowledge.ts +57 -56
- package/src/input/commands/local-provider-runtime.ts +36 -18
- package/src/input/commands/local-runtime.ts +138 -16
- package/src/input/commands/local-setup-review.ts +7 -7
- package/src/input/commands/mcp-runtime.ts +56 -35
- package/src/input/commands/notify-runtime.ts +38 -9
- package/src/input/commands/operator-actions-runtime.ts +138 -0
- package/src/input/commands/operator-runtime.ts +6 -17
- package/src/input/commands/personas-runtime.ts +45 -30
- package/src/input/commands/planning-runtime.ts +1 -1
- package/src/input/commands/platform-access-runtime.ts +29 -29
- package/src/input/commands/provider-accounts-runtime.ts +60 -39
- package/src/input/commands/qrcode-runtime.ts +45 -6
- package/src/input/commands/recall-bundle.ts +11 -11
- package/src/input/commands/recall-capture.ts +13 -11
- package/src/input/commands/recall-query.ts +29 -21
- package/src/input/commands/recall-review.ts +2 -1
- package/src/input/commands/routines-runtime.ts +59 -43
- package/src/input/commands/schedule-runtime.ts +33 -20
- package/src/input/commands/security-runtime.ts +4 -4
- package/src/input/commands/session-content.ts +80 -78
- package/src/input/commands/session-workflow.ts +132 -93
- package/src/input/commands/session.ts +3 -174
- package/src/input/commands/shell-core.ts +32 -17
- package/src/input/commands/subscription-runtime.ts +53 -179
- package/src/input/commands/tasks-runtime.ts +20 -20
- package/src/input/commands/work-plan-runtime.ts +33 -8
- package/src/input/commands.ts +2 -2
- package/src/input/feed-context-factory.ts +2 -1
- package/src/input/file-picker.ts +3 -2
- package/src/input/handler-command-route.ts +4 -7
- package/src/input/handler-content-actions.ts +89 -1
- package/src/input/handler-feed-routes.ts +19 -12
- package/src/input/handler-feed.ts +6 -3
- package/src/input/handler-interactions.ts +7 -5
- package/src/input/handler-modal-stack.ts +3 -3
- package/src/input/handler-onboarding.ts +24 -80
- package/src/input/handler-shortcuts.ts +15 -4
- package/src/input/handler.ts +47 -17
- package/src/input/input-history.ts +5 -6
- package/src/input/keybindings.ts +22 -11
- package/src/input/onboarding/onboarding-wizard-apply.ts +13 -0
- package/src/input/onboarding/onboarding-wizard-constants.ts +1 -0
- package/src/input/onboarding/onboarding-wizard-operator-steps.ts +147 -57
- package/src/input/onboarding/onboarding-wizard-steps.ts +46 -29
- package/src/input/onboarding/onboarding-wizard-types.ts +3 -1
- package/src/input/onboarding/onboarding-wizard.ts +68 -0
- package/src/input/profile-picker-modal.ts +31 -12
- package/src/input/session-picker-modal.ts +21 -4
- package/src/input/settings-modal-behavior.ts +0 -3
- package/src/input/settings-modal-subscriptions.ts +3 -3
- package/src/input/settings-modal-types.ts +2 -13
- package/src/input/settings-modal.ts +6 -52
- package/src/input/submission-intent.ts +0 -1
- package/src/input/submission-router.ts +3 -3
- package/src/main.ts +18 -8
- package/src/panels/approval-panel.ts +8 -8
- package/src/panels/automation-control-panel.ts +2 -2
- package/src/panels/base-panel.ts +1 -1
- package/src/panels/builtin/agent.ts +1 -1
- package/src/panels/builtin/operations.ts +1 -10
- package/src/panels/builtin/session.ts +9 -9
- package/src/panels/builtin/shared.ts +2 -2
- package/src/panels/cost-tracker-panel.ts +1 -1
- package/src/panels/docs-panel.ts +5 -3
- package/src/panels/index.ts +0 -1
- package/src/panels/knowledge-panel.ts +6 -5
- package/src/panels/memory-panel.ts +7 -6
- package/src/panels/panel-list-panel.ts +36 -80
- package/src/panels/project-planning-panel.ts +18 -11
- package/src/panels/provider-account-snapshot.ts +51 -25
- package/src/panels/provider-accounts-panel.ts +33 -18
- package/src/panels/provider-health-domains.ts +45 -4
- package/src/panels/provider-health-panel.ts +5 -4
- package/src/panels/qr-panel.ts +1 -1
- package/src/panels/schedule-panel.ts +9 -17
- package/src/panels/security-panel.ts +8 -8
- package/src/panels/session-browser-panel.ts +10 -10
- package/src/panels/subscription-panel.ts +3 -3
- package/src/panels/system-messages-panel.ts +1 -1
- package/src/panels/tasks-panel.ts +20 -13
- package/src/panels/tool-inspector-panel.ts +19 -12
- package/src/panels/work-plan-panel.ts +5 -5
- package/src/planning/project-planning-coordinator.ts +1 -1
- package/src/provider-auth-route-display.ts +9 -0
- package/src/renderer/agent-workspace-style.ts +34 -0
- package/src/renderer/agent-workspace.ts +228 -52
- package/src/renderer/autocomplete-overlay.ts +25 -6
- package/src/renderer/bookmark-modal.ts +19 -4
- package/src/renderer/buffer.ts +4 -2
- package/src/renderer/context-inspector.ts +50 -13
- package/src/renderer/diff.ts +1 -1
- package/src/renderer/file-picker-overlay.ts +19 -6
- package/src/renderer/help-overlay.ts +106 -33
- package/src/renderer/history-search-overlay.ts +19 -4
- package/src/renderer/live-tail-modal.ts +27 -5
- package/src/renderer/mcp-workspace.ts +164 -50
- package/src/renderer/model-picker-overlay.ts +58 -2
- package/src/renderer/model-workspace.ts +104 -20
- package/src/renderer/process-modal.ts +27 -6
- package/src/renderer/profile-picker-modal.ts +20 -4
- package/src/renderer/search-overlay.ts +25 -5
- package/src/renderer/selection-modal-overlay.ts +46 -14
- package/src/renderer/session-picker-modal.ts +18 -1
- package/src/renderer/settings-modal-helpers.ts +2 -40
- package/src/renderer/settings-modal.ts +83 -50
- package/src/renderer/tool-call.ts +20 -11
- package/src/runtime/agent-runtime-events.ts +6 -6
- package/src/runtime/bootstrap-command-context.ts +7 -1
- package/src/runtime/bootstrap-command-parts.ts +9 -7
- package/src/runtime/bootstrap-core.ts +19 -1
- package/src/runtime/bootstrap-hook-bridge.ts +7 -18
- package/src/runtime/bootstrap-shell.ts +4 -4
- package/src/runtime/bootstrap.ts +31 -22
- package/src/runtime/connected-host-auth.ts +7 -2
- package/src/runtime/diagnostics/panels/index.ts +2 -2
- package/src/runtime/diagnostics/panels/policy.ts +7 -7
- package/src/runtime/index.ts +2 -1
- package/src/runtime/onboarding/apply-file-helpers.ts +66 -0
- package/src/runtime/onboarding/apply.ts +80 -79
- package/src/runtime/onboarding/derivation.ts +5 -8
- package/src/runtime/onboarding/snapshot.ts +0 -15
- package/src/runtime/onboarding/types.ts +8 -19
- package/src/runtime/onboarding/verify.ts +32 -10
- package/src/runtime/operator-token-cleanup.ts +1 -1
- package/src/runtime/services.ts +91 -22
- package/src/runtime/store/selectors/index.ts +3 -3
- package/src/runtime/store/state.ts +1 -4
- package/src/runtime/surface-feature-flags.ts +41 -6
- package/src/runtime/ui-read-models.ts +3 -4
- package/src/runtime/ui-services.ts +6 -6
- package/src/shell/blocking-input.ts +2 -1
- package/src/shell/ui-openers.ts +3 -13
- package/src/tools/agent-analysis-registry-policy.ts +0 -1
- package/src/tools/agent-channel-send-tool.ts +133 -0
- package/src/tools/agent-context-policy.ts +1 -1
- package/src/tools/agent-knowledge-ingest-tool.ts +405 -0
- package/src/tools/agent-knowledge-tool.ts +170 -0
- package/src/tools/agent-local-registry-tool.ts +269 -69
- package/src/tools/agent-media-generate-tool.ts +133 -0
- package/src/tools/agent-notify-tool.ts +143 -0
- package/src/tools/agent-operator-action-tool.ts +137 -0
- package/src/tools/agent-operator-briefing-tool.ts +217 -0
- package/src/tools/agent-reminder-schedule-tool.ts +237 -0
- package/src/tools/agent-tool-policy-guard.ts +8 -8
- package/src/tools/agent-work-plan-tool.ts +256 -0
- package/src/version.ts +1 -1
- package/src/input/commands/policy-dispatch.ts +0 -339
- package/src/input/commands/policy.ts +0 -13
- package/src/panels/panel-picker.ts +0 -105
- package/src/panels/policy-panel.ts +0 -308
- package/src/renderer/panel-picker-overlay.ts +0 -202
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
buildReminderSchedulePreview,
|
|
9
9
|
createReminderSchedule,
|
|
10
10
|
parseReminderScheduleArgs,
|
|
11
|
-
|
|
11
|
+
resolveReminderConnectedHostConnection,
|
|
12
12
|
} from '../../agent/reminder-schedule.ts';
|
|
13
13
|
import {
|
|
14
14
|
formatReminderScheduleFailure,
|
|
@@ -18,8 +18,8 @@ import {
|
|
|
18
18
|
import { AgentRoutineRegistry } from '../../agent/routine-registry.ts';
|
|
19
19
|
import {
|
|
20
20
|
buildRoutineSchedulePreview,
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
promoteRoutineToConnectedSchedule,
|
|
22
|
+
resolveAgentConnectedHostConnection,
|
|
23
23
|
} from '../../agent/routine-schedule-promotion.ts';
|
|
24
24
|
import { parseRoutineSchedulePromotionArgs } from '../../agent/routine-schedule-args.ts';
|
|
25
25
|
import {
|
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
} from '../../agent/routine-schedule-receipts.ts';
|
|
37
37
|
import type { CommandContext } from '../command-registry.ts';
|
|
38
38
|
import { requireShellPaths } from './runtime-services.ts';
|
|
39
|
+
import { executeConfirmedOperatorAction } from './operator-actions-runtime.ts';
|
|
39
40
|
|
|
40
41
|
function formatSchedule(schedule: AutomationScheduleDefinition): string {
|
|
41
42
|
switch (schedule.kind) {
|
|
@@ -64,10 +65,11 @@ function formatPrompt(job: AutomationJob): string {
|
|
|
64
65
|
function printReadOnlyScheduleBoundary(print: (text: string) => void, requestedAction: string): void {
|
|
65
66
|
print([
|
|
66
67
|
'GoodVibes Agent local schedule commands are read-only in this runtime.',
|
|
67
|
-
` requested
|
|
68
|
-
' policy
|
|
69
|
-
' use
|
|
70
|
-
'
|
|
68
|
+
` requested ${requestedAction}`,
|
|
69
|
+
' policy no hidden local Agent automation jobs or immediate automation runs',
|
|
70
|
+
' use /schedule list',
|
|
71
|
+
' connected run route /automation schedule run <schedule-id> --yes',
|
|
72
|
+
' schedule route use /schedule promote-routine <routine> --cron <expr> --yes to create a connected schedule explicitly',
|
|
71
73
|
].join('\n'));
|
|
72
74
|
}
|
|
73
75
|
|
|
@@ -83,7 +85,7 @@ async function promoteRoutineSchedule(args: readonly string[], ctx: CommandConte
|
|
|
83
85
|
const shellPaths = requireShellPaths(ctx);
|
|
84
86
|
const routine = AgentRoutineRegistry.fromShellPaths(shellPaths).get(parsed.routineId ?? '');
|
|
85
87
|
if (!routine) {
|
|
86
|
-
ctx.print(`Unknown Agent routine
|
|
88
|
+
ctx.print(`Unknown Agent routine ${parsed.routineId ?? ''}`);
|
|
87
89
|
return;
|
|
88
90
|
}
|
|
89
91
|
const preview = buildRoutineSchedulePreview(routine, parsed);
|
|
@@ -91,8 +93,8 @@ async function promoteRoutineSchedule(args: readonly string[], ctx: CommandConte
|
|
|
91
93
|
ctx.print(formatRoutineSchedulePreview(preview));
|
|
92
94
|
return;
|
|
93
95
|
}
|
|
94
|
-
const connection =
|
|
95
|
-
const result = await
|
|
96
|
+
const connection = resolveAgentConnectedHostConnection(ctx.platform.configManager, shellPaths.homeDirectory);
|
|
97
|
+
const result = await promoteRoutineToConnectedSchedule(connection, preview);
|
|
96
98
|
const receipt = RoutineScheduleReceiptStore.fromShellPaths(shellPaths).append(connection, preview, result);
|
|
97
99
|
ctx.print(result.ok ? `${formatRoutineScheduleSuccess(result)}\n receipt: ${receipt.id}` : `${formatRoutineScheduleFailure(result)}\n receipt: ${receipt.id}`);
|
|
98
100
|
}
|
|
@@ -112,7 +114,7 @@ async function createReminder(args: readonly string[], ctx: CommandContext): Pro
|
|
|
112
114
|
return;
|
|
113
115
|
}
|
|
114
116
|
const shellPaths = requireShellPaths(ctx);
|
|
115
|
-
const connection =
|
|
117
|
+
const connection = resolveReminderConnectedHostConnection(ctx.platform.configManager, shellPaths.homeDirectory);
|
|
116
118
|
const result = await createReminderSchedule(connection, preview);
|
|
117
119
|
ctx.print(result.ok ? formatReminderScheduleSuccess(result) : formatReminderScheduleFailure(result));
|
|
118
120
|
}
|
|
@@ -121,7 +123,7 @@ export function registerScheduleRuntimeCommands(registry: CommandRegistry): void
|
|
|
121
123
|
registry.register({
|
|
122
124
|
name: 'schedule',
|
|
123
125
|
aliases: ['sched'],
|
|
124
|
-
description: 'Inspect schedules, create confirmed reminders, and explicitly promote local
|
|
126
|
+
description: 'Inspect schedules, create confirmed reminders, and explicitly promote Agent-local routines to connected schedules',
|
|
125
127
|
usage: 'list | remind --at <iso> --message <text> --yes | receipts | reconcile | receipt <id> | promote-routine <routine-id> --cron <expr> [--delivery-channel slack] --yes',
|
|
126
128
|
argsHint: 'list | remind --at <iso> --message <text> --yes | receipts | reconcile | receipt <id> | promote-routine <routine-id> --cron <expr> [--delivery-channel slack] --yes',
|
|
127
129
|
async handler(args, ctx) {
|
|
@@ -144,7 +146,7 @@ export function registerScheduleRuntimeCommands(registry: CommandRegistry): void
|
|
|
144
146
|
|
|
145
147
|
if (sub === 'reconcile' || sub === 'sync' || sub === 'status') {
|
|
146
148
|
const shellPaths = requireShellPaths(ctx);
|
|
147
|
-
const connection =
|
|
149
|
+
const connection = resolveAgentConnectedHostConnection(ctx.platform.configManager, shellPaths.homeDirectory);
|
|
148
150
|
const result = await reconcileRoutineScheduleReceipts(connection, RoutineScheduleReceiptStore.fromShellPaths(shellPaths).snapshot());
|
|
149
151
|
ctx.print(formatRoutineScheduleCorrelation(result));
|
|
150
152
|
return;
|
|
@@ -157,7 +159,7 @@ export function registerScheduleRuntimeCommands(registry: CommandRegistry): void
|
|
|
157
159
|
return;
|
|
158
160
|
}
|
|
159
161
|
const receipt = RoutineScheduleReceiptStore.fromShellPaths(requireShellPaths(ctx)).get(id);
|
|
160
|
-
ctx.print(receipt ? formatRoutineScheduleReceipt(receipt) : `Unknown routine schedule receipt
|
|
162
|
+
ctx.print(receipt ? formatRoutineScheduleReceipt(receipt) : `Unknown routine schedule receipt ${id}`);
|
|
161
163
|
return;
|
|
162
164
|
}
|
|
163
165
|
|
|
@@ -176,20 +178,30 @@ export function registerScheduleRuntimeCommands(registry: CommandRegistry): void
|
|
|
176
178
|
);
|
|
177
179
|
return;
|
|
178
180
|
}
|
|
179
|
-
const lines = ['Automation jobs
|
|
181
|
+
const lines = ['Automation jobs', ''];
|
|
180
182
|
for (const job of jobs) {
|
|
181
183
|
const status = job.enabled ? '● enabled ' : '○ paused ';
|
|
182
184
|
const next = formatNextRun(job.nextRunAt);
|
|
183
185
|
const last = job.lastRunAt ? new Date(job.lastRunAt).toLocaleString() : 'never';
|
|
184
|
-
lines.push(` ${job.id.slice(0, 12)} ${status} runs
|
|
185
|
-
lines.push(` name
|
|
186
|
-
lines.push(` prompt
|
|
186
|
+
lines.push(` ${job.id.slice(0, 12)} ${status} runs ${job.runCount} next ${next} last ${last}`);
|
|
187
|
+
lines.push(` name ${job.name} schedule ${formatSchedule(job.schedule)}`);
|
|
188
|
+
lines.push(` prompt ${formatPrompt(job)}`);
|
|
187
189
|
}
|
|
188
190
|
ctx.print(lines.join('\n'));
|
|
189
191
|
return;
|
|
190
192
|
}
|
|
191
193
|
|
|
192
|
-
if (sub === '
|
|
194
|
+
if (sub === 'run') {
|
|
195
|
+
const scheduleId = args[1] ?? '';
|
|
196
|
+
if (!scheduleId) {
|
|
197
|
+
ctx.print('Usage: /schedule run <schedule-id> --yes');
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
await executeConfirmedOperatorAction(ctx, 'schedules.run', 'scheduleId', scheduleId, args.slice(2), '/schedule run <schedule-id> --yes');
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (sub === 'add' || sub === 'remove' || sub === 'enable' || sub === 'disable') {
|
|
193
205
|
printReadOnlyScheduleBoundary(ctx.print, `/schedule ${args.join(' ')}`.trim());
|
|
194
206
|
return;
|
|
195
207
|
}
|
|
@@ -200,9 +212,10 @@ export function registerScheduleRuntimeCommands(registry: CommandRegistry): void
|
|
|
200
212
|
+ ' /schedule receipts\n'
|
|
201
213
|
+ ' /schedule reconcile\n'
|
|
202
214
|
+ ' /schedule receipt <receipt-id>\n'
|
|
215
|
+
+ ' /schedule run <schedule-id> --yes\n'
|
|
203
216
|
+ ' /schedule remind (--cron <expr>|--every <interval>|--at <iso-time>) (--message <text>|<text...>) [--delivery-channel <channel>|--delivery-route <route>|--delivery-webhook <url>] --yes\n'
|
|
204
217
|
+ ' /schedule promote-routine <routine-id> (--cron <expr>|--every <interval>|--at <iso-time>) [--delivery-channel <channel>|--delivery-route <route>|--delivery-webhook <url>] --yes\n'
|
|
205
|
-
+ ' Local schedule mutations
|
|
218
|
+
+ ' Local schedule mutations remain blocked; schedule run is a confirmed connected-host action.'
|
|
206
219
|
);
|
|
207
220
|
},
|
|
208
221
|
});
|
|
@@ -12,7 +12,7 @@ export function registerSecurityRuntimeCommands(registry: CommandRegistry): void
|
|
|
12
12
|
handler(args, ctx) {
|
|
13
13
|
const subcommand = args[0]?.toLowerCase() ?? 'review';
|
|
14
14
|
if (subcommand === 'open' || subcommand === 'panel') {
|
|
15
|
-
ctx.print('
|
|
15
|
+
ctx.print('Open Agent Workspace -> Tools & MCP -> Security review for the workspace view, or run /security review for compact command output.');
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
18
18
|
const audit = requireTokenAuditor(ctx).auditAll(Date.now());
|
|
@@ -29,13 +29,13 @@ export function registerSecurityRuntimeCommands(registry: CommandRegistry): void
|
|
|
29
29
|
|
|
30
30
|
if (subcommand === 'tokens') {
|
|
31
31
|
if (audit.results.length === 0) {
|
|
32
|
-
ctx.print('No registered API tokens are currently
|
|
32
|
+
ctx.print('No registered API tokens are currently available for security review.');
|
|
33
33
|
return;
|
|
34
34
|
}
|
|
35
35
|
ctx.print([
|
|
36
|
-
`Token
|
|
36
|
+
`Token Review (${audit.results.length})`,
|
|
37
37
|
...audit.results.map((result) => (
|
|
38
|
-
` ${result.label} policy
|
|
38
|
+
` ${result.label} policy ${result.scope.policyId} scope ${result.scope.outcome} rotation ${result.rotation.outcome} blocked ${result.blocked ? 'yes' : 'no'}`
|
|
39
39
|
)),
|
|
40
40
|
].join('\n'));
|
|
41
41
|
return;
|
|
@@ -1,12 +1,43 @@
|
|
|
1
1
|
import { join, resolve } from 'path';
|
|
2
2
|
import { existsSync, mkdirSync } from 'node:fs';
|
|
3
3
|
import { writeFile } from 'node:fs/promises';
|
|
4
|
-
import type { CommandRegistry } from '../command-registry.ts';
|
|
4
|
+
import type { CommandContext, CommandRegistry } from '../command-registry.ts';
|
|
5
5
|
import type { SelectionItem } from '../selection-modal.ts';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import type { SessionMeta } from '@pellux/goodvibes-sdk/platform/sessions';
|
|
7
|
+
import { exportToMarkdown, extractText } from '@pellux/goodvibes-sdk/platform/export';
|
|
8
|
+
import { requireSessionManager, requireShellPaths } from './runtime-services.ts';
|
|
8
9
|
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
9
10
|
import { requireYesFlag, stripYesFlag } from './confirmation.ts';
|
|
11
|
+
import { readConversationMessageSnapshots } from '../../core/conversation-message-snapshot.ts';
|
|
12
|
+
|
|
13
|
+
function formatSessionFailure(action: string, error: unknown): string {
|
|
14
|
+
return [
|
|
15
|
+
`Failed to ${action}`,
|
|
16
|
+
` error ${summarizeError(error)}`,
|
|
17
|
+
].join('\n');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type ConversationSnapshotReader = {
|
|
21
|
+
readonly getMessageSnapshot?: () => ReturnType<typeof readConversationMessageSnapshots>;
|
|
22
|
+
readonly toJSON?: () => unknown;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
function isObjectArray(value: unknown): value is readonly object[] {
|
|
26
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === 'object' && entry !== null);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function getCurrentConversationMessages(ctx: CommandContext): ReturnType<typeof readConversationMessageSnapshots> {
|
|
30
|
+
const manager = ctx.session.conversationManager as unknown as ConversationSnapshotReader;
|
|
31
|
+
if (typeof manager.getMessageSnapshot === 'function') return manager.getMessageSnapshot();
|
|
32
|
+
if (typeof manager.toJSON === 'function') {
|
|
33
|
+
const serialized = manager.toJSON();
|
|
34
|
+
if (serialized && typeof serialized === 'object' && 'messages' in serialized) {
|
|
35
|
+
const messages = (serialized as { readonly messages?: unknown }).messages;
|
|
36
|
+
if (isObjectArray(messages)) return readConversationMessageSnapshots(messages);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
throw new Error('Conversation manager cannot export message snapshots.');
|
|
40
|
+
}
|
|
10
41
|
|
|
11
42
|
export function registerSessionContentCommands(registry: CommandRegistry): void {
|
|
12
43
|
registry.register({
|
|
@@ -32,7 +63,10 @@ export function registerSessionContentCommands(registry: CommandRegistry): void
|
|
|
32
63
|
}
|
|
33
64
|
const resolvedPath = shellPaths.resolveWorkspacePath(outPath);
|
|
34
65
|
if (!shellPaths.isWithinWorkingDirectory(resolvedPath)) {
|
|
35
|
-
ctx.print(
|
|
66
|
+
ctx.print([
|
|
67
|
+
'Error',
|
|
68
|
+
' message Export path must be within the current directory.',
|
|
69
|
+
].join('\n'));
|
|
36
70
|
return;
|
|
37
71
|
}
|
|
38
72
|
if (!yes) {
|
|
@@ -41,23 +75,10 @@ export function registerSessionContentCommands(registry: CommandRegistry): void
|
|
|
41
75
|
}
|
|
42
76
|
|
|
43
77
|
try {
|
|
44
|
-
const
|
|
45
|
-
const msgs = data.messages ?? [];
|
|
78
|
+
const msgs = getCurrentConversationMessages(ctx);
|
|
46
79
|
let fileContent: string;
|
|
47
80
|
if (format === 'markdown') {
|
|
48
|
-
|
|
49
|
-
role: String(m.role ?? 'user') as 'user' | 'assistant' | 'system' | 'tool',
|
|
50
|
-
content: Array.isArray(m.content)
|
|
51
|
-
? m.content as import('@pellux/goodvibes-sdk/platform/providers').ContentPart[]
|
|
52
|
-
: String(m.content ?? ''),
|
|
53
|
-
toolCalls: m.toolCalls as import('@pellux/goodvibes-sdk/platform/types').ToolCall[] | undefined,
|
|
54
|
-
callId: m.callId as string | undefined,
|
|
55
|
-
toolName: m.toolName as string | undefined,
|
|
56
|
-
reasoningContent: m.reasoningContent as string | undefined,
|
|
57
|
-
reasoningSummary: m.reasoningSummary as string | undefined,
|
|
58
|
-
usage: m.usage as { inputTokens: number; outputTokens: number; cacheReadTokens?: number; cacheWriteTokens?: number } | undefined,
|
|
59
|
-
}));
|
|
60
|
-
fileContent = exportToMarkdown(exportMsgs, {
|
|
81
|
+
fileContent = exportToMarkdown(msgs, {
|
|
61
82
|
model: ctx.session.runtime.model,
|
|
62
83
|
provider: ctx.session.runtime.provider,
|
|
63
84
|
sessionId: ctx.session.runtime.sessionId,
|
|
@@ -66,8 +87,8 @@ export function registerSessionContentCommands(registry: CommandRegistry): void
|
|
|
66
87
|
} else {
|
|
67
88
|
const lines: string[] = [];
|
|
68
89
|
for (const m of msgs) {
|
|
69
|
-
const role =
|
|
70
|
-
const content =
|
|
90
|
+
const role = m.role.toUpperCase();
|
|
91
|
+
const content = extractText(m.content);
|
|
71
92
|
if (!content.trim()) continue;
|
|
72
93
|
lines.push(`[${role}]`);
|
|
73
94
|
lines.push(content);
|
|
@@ -79,9 +100,13 @@ export function registerSessionContentCommands(registry: CommandRegistry): void
|
|
|
79
100
|
const dir = dirname(resolvedPath);
|
|
80
101
|
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
81
102
|
await writeFile(resolvedPath, fileContent, 'utf-8');
|
|
82
|
-
ctx.print(
|
|
103
|
+
ctx.print([
|
|
104
|
+
'Exported conversation',
|
|
105
|
+
` messages ${msgs.length}`,
|
|
106
|
+
` path ${resolvedPath}`,
|
|
107
|
+
].join('\n'));
|
|
83
108
|
} catch (err) {
|
|
84
|
-
ctx.print(
|
|
109
|
+
ctx.print(formatSessionFailure('export conversation', err));
|
|
85
110
|
}
|
|
86
111
|
},
|
|
87
112
|
});
|
|
@@ -92,10 +117,13 @@ export function registerSessionContentCommands(registry: CommandRegistry): void
|
|
|
92
117
|
usage: '[text]',
|
|
93
118
|
argsHint: '[text]',
|
|
94
119
|
handler(args, ctx) {
|
|
95
|
-
if (args.length === 0) ctx.print(ctx.session.conversationManager.title ? `Conversation title
|
|
120
|
+
if (args.length === 0) ctx.print(ctx.session.conversationManager.title ? `Conversation title\n title ${ctx.session.conversationManager.title}` : 'No title set.');
|
|
96
121
|
else {
|
|
97
122
|
ctx.session.conversationManager.title = args.join(' ');
|
|
98
|
-
ctx.print(
|
|
123
|
+
ctx.print([
|
|
124
|
+
'Title set',
|
|
125
|
+
` title ${ctx.session.conversationManager.title}`,
|
|
126
|
+
].join('\n'));
|
|
99
127
|
ctx.renderRequest();
|
|
100
128
|
}
|
|
101
129
|
},
|
|
@@ -109,19 +137,24 @@ export function registerSessionContentCommands(registry: CommandRegistry): void
|
|
|
109
137
|
handler(args, ctx) {
|
|
110
138
|
const sessionManager = requireSessionManager(ctx);
|
|
111
139
|
const rawName = args[0] || ctx.session.conversationManager.title || `session-${Date.now()}`;
|
|
112
|
-
const
|
|
113
|
-
const
|
|
114
|
-
const meta = {
|
|
140
|
+
const messages = ctx.session.conversationManager.getMessageSnapshot();
|
|
141
|
+
const meta: SessionMeta = {
|
|
115
142
|
title: ctx.session.conversationManager.title,
|
|
116
143
|
model: ctx.session.runtime.model,
|
|
117
144
|
provider: ctx.session.runtime.provider,
|
|
118
145
|
timestamp: Date.now(),
|
|
146
|
+
titleSource: ctx.session.conversationManager.getTitleSource(),
|
|
119
147
|
};
|
|
120
148
|
try {
|
|
121
149
|
const { filePath, sanitizedName } = sessionManager.save(rawName, messages, meta);
|
|
122
|
-
ctx.print(
|
|
150
|
+
ctx.print([
|
|
151
|
+
'Session saved',
|
|
152
|
+
` name ${rawName}`,
|
|
153
|
+
...(sanitizedName !== rawName ? [` saved as ${sanitizedName}`] : []),
|
|
154
|
+
` path ${filePath}`,
|
|
155
|
+
].join('\n'));
|
|
123
156
|
} catch (e) {
|
|
124
|
-
ctx.print(
|
|
157
|
+
ctx.print(formatSessionFailure('save session', e));
|
|
125
158
|
}
|
|
126
159
|
},
|
|
127
160
|
});
|
|
@@ -140,13 +173,18 @@ export function registerSessionContentCommands(registry: CommandRegistry): void
|
|
|
140
173
|
try {
|
|
141
174
|
const { meta, messages, agentRecords } = sessionManager.load(args[0]);
|
|
142
175
|
ctx.session.conversationManager.resetAll();
|
|
143
|
-
ctx.session.conversationManager.fromJSON({ messages: messages
|
|
176
|
+
ctx.session.conversationManager.fromJSON({ messages: readConversationMessageSnapshots(messages) });
|
|
144
177
|
if (meta.title) ctx.session.conversationManager.title = meta.title;
|
|
145
178
|
ctx.session.conversationManager.rebuildHistory();
|
|
146
179
|
ctx.renderRequest();
|
|
147
|
-
ctx.print(
|
|
180
|
+
ctx.print([
|
|
181
|
+
'Session loaded',
|
|
182
|
+
` id ${args[0]}`,
|
|
183
|
+
` messages ${messages.length}`,
|
|
184
|
+
...(agentRecords.length > 0 ? [` ignored connected-host records ${agentRecords.length}`] : []),
|
|
185
|
+
].join('\n'));
|
|
148
186
|
} catch (e) {
|
|
149
|
-
ctx.print(
|
|
187
|
+
ctx.print(formatSessionFailure('load session', e));
|
|
150
188
|
}
|
|
151
189
|
},
|
|
152
190
|
});
|
|
@@ -217,67 +255,31 @@ export function registerSessionContentCommands(registry: CommandRegistry): void
|
|
|
217
255
|
const sessions = sessionManager.list();
|
|
218
256
|
if (ctx.openSelection) {
|
|
219
257
|
const items: SelectionItem[] = sessions.length === 0
|
|
220
|
-
? [{ id: '_empty', label: 'No saved sessions', detail: '
|
|
258
|
+
? [{ id: '_empty', label: 'No saved sessions', detail: 'Open Agent Workspace -> Conversation -> Save current session' }]
|
|
221
259
|
: sessions.map(s => ({ id: s.name, label: s.name, detail: s.title || '(untitled)', actions: 'Enter to load' }));
|
|
222
260
|
ctx.openSelection('Sessions', items, { allowSearch: true }, (result) => {
|
|
223
261
|
if (!result) return;
|
|
224
262
|
try {
|
|
225
263
|
const { meta, messages } = sessionManager.load(result.item.id);
|
|
226
264
|
ctx.session.conversationManager.resetAll();
|
|
227
|
-
ctx.session.conversationManager.fromJSON({ messages: messages
|
|
265
|
+
ctx.session.conversationManager.fromJSON({ messages: readConversationMessageSnapshots(messages) });
|
|
228
266
|
if (meta.title) ctx.session.conversationManager.title = meta.title;
|
|
229
267
|
ctx.session.conversationManager.rebuildHistory();
|
|
230
268
|
ctx.renderRequest();
|
|
231
|
-
ctx.print(
|
|
269
|
+
ctx.print([
|
|
270
|
+
'Session loaded',
|
|
271
|
+
` id ${result.item.id}`,
|
|
272
|
+
` messages ${messages.length}`,
|
|
273
|
+
].join('\n'));
|
|
232
274
|
} catch (e) {
|
|
233
|
-
ctx.print(
|
|
275
|
+
ctx.print(formatSessionFailure('load session', e));
|
|
234
276
|
}
|
|
235
277
|
});
|
|
236
278
|
return;
|
|
237
279
|
}
|
|
238
|
-
const lines = ['Saved sessions
|
|
280
|
+
const lines = ['Saved sessions', ''];
|
|
239
281
|
for (const s of sessions) lines.push(` ${s.name.padEnd(30)} ${(s.title || '(untitled)').padEnd(24)} ${new Date(s.timestamp).toLocaleString()} (${s.messageCount} msgs)`);
|
|
240
282
|
ctx.print(lines.join('\n'));
|
|
241
283
|
},
|
|
242
284
|
});
|
|
243
|
-
|
|
244
|
-
registry.register({
|
|
245
|
-
name: 'session-memory',
|
|
246
|
-
aliases: ['smemory'],
|
|
247
|
-
description: 'Manage conversation-pinned memories used during context compaction',
|
|
248
|
-
usage: '[list|add <text>|remove <id> --yes]',
|
|
249
|
-
argsHint: '[list|add|remove]',
|
|
250
|
-
handler(args, ctx) {
|
|
251
|
-
const sub = args[0] ?? 'list';
|
|
252
|
-
if (sub === 'list' || args.length === 0) {
|
|
253
|
-
const memories = requireSessionMemoryStore(ctx).list();
|
|
254
|
-
ctx.print(memories.length === 0
|
|
255
|
-
? 'No conversation-pinned memories. Use !# prefix or /session-memory add <text> to create one.'
|
|
256
|
-
: [`Conversation-Pinned Memories (${memories.length}):`, ...memories.map(m => ` [${m.id}] ${m.text}`)].join('\n'));
|
|
257
|
-
} else if (sub === 'add') {
|
|
258
|
-
const text = args.slice(1).join(' ').trim();
|
|
259
|
-
if (!text) {
|
|
260
|
-
ctx.print('Usage: /session-memory add <text>');
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
const id = requireSessionMemoryStore(ctx).add(text);
|
|
264
|
-
ctx.print(`Memory added: [${id}] ${text}`);
|
|
265
|
-
} else if (sub === 'remove') {
|
|
266
|
-
const parsed = stripYesFlag(args);
|
|
267
|
-
const id = parsed.rest[1];
|
|
268
|
-
if (!id) {
|
|
269
|
-
ctx.print('Usage: /session-memory remove <id> --yes');
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
if (!parsed.yes) {
|
|
273
|
-
requireYesFlag(ctx, `remove conversation-pinned memory ${id}`, '/session-memory remove <id> --yes');
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
const store = requireSessionMemoryStore(ctx);
|
|
277
|
-
ctx.print(store.remove(id) ? `Memory removed: [${id}]` : `Memory not found: ${id}`);
|
|
278
|
-
} else {
|
|
279
|
-
ctx.print('Usage: /session-memory [list|add <text>|remove <id> --yes]\n /session-memory — list conversation-pinned memories\n /session-memory list — list conversation-pinned memories\n /session-memory add <text> — add a memory without sending a message\n /session-memory remove <id> --yes — remove a specific memory');
|
|
280
|
-
}
|
|
281
|
-
},
|
|
282
|
-
});
|
|
283
285
|
}
|