@pellux/goodvibes-agent 0.1.116 → 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 +48 -661
- package/README.md +64 -57
- package/bin/goodvibes-agent.ts +16 -2
- package/dist/package/main.js +199180 -192185
- package/docs/README.md +15 -8
- package/docs/channels-remote-and-api.md +50 -0
- package/docs/connected-host.md +59 -0
- package/docs/getting-started.md +61 -50
- 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 +48 -11
- package/docs/tools-and-commands.md +123 -0
- package/docs/voice-and-live-tts.md +51 -0
- package/package.json +3 -6
- package/src/agent/behavior-discovery-summary.ts +1 -3
- 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-discovery.ts +1 -3
- package/src/agent/persona-registry.ts +19 -16
- package/src/agent/record-labels.ts +107 -0
- package/src/agent/reminder-schedule-format.ts +33 -24
- package/src/agent/reminder-schedule.ts +27 -26
- package/src/agent/routine-registry.ts +54 -14
- 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 +35 -33
- package/src/agent/routine-schedule-receipts.ts +29 -27
- package/src/agent/runtime-profile-starters.ts +5 -5
- package/src/agent/runtime-profile.ts +91 -12
- package/src/agent/skill-registry.ts +210 -32
- package/src/cli/agent-knowledge-args.ts +5 -1
- package/src/cli/agent-knowledge-command.ts +40 -34
- 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 +14 -9
- package/src/cli/config-overrides.ts +37 -36
- package/src/cli/entrypoint.ts +16 -7
- package/src/cli/external-runtime.ts +10 -4
- package/src/cli/help.ts +54 -29
- package/src/cli/local-library-command.ts +203 -83
- package/src/cli/management-commands.ts +105 -68
- package/src/cli/management.ts +55 -74
- package/src/cli/memory-command.ts +66 -32
- package/src/cli/parser.ts +37 -3
- package/src/cli/profiles-command.ts +166 -31
- package/src/cli/provider-auth-routes.ts +2 -1
- package/src/cli/routines-command.ts +176 -40
- package/src/cli/service-posture.ts +16 -16
- package/src/cli/status.ts +56 -135
- package/src/core/conversation-message-snapshot.ts +131 -0
- package/src/input/agent-workspace-access-command-editor-submission.ts +149 -0
- package/src/input/agent-workspace-access-command-editors.ts +170 -0
- package/src/input/agent-workspace-activation.ts +35 -8
- package/src/input/agent-workspace-basic-command-editor-submission.ts +351 -94
- package/src/input/agent-workspace-basic-command-editors.ts +502 -9
- package/src/input/agent-workspace-categories.ts +423 -51
- package/src/input/agent-workspace-channel-command-editor-submission.ts +83 -0
- package/src/input/agent-workspace-channel-command-editors.ts +65 -0
- package/src/input/agent-workspace-channels.ts +35 -2
- package/src/input/agent-workspace-command-editor.ts +41 -3
- package/src/input/agent-workspace-config-reader.ts +16 -0
- package/src/input/agent-workspace-delegation-editor-submission.ts +55 -0
- package/src/input/agent-workspace-editors.ts +166 -1
- package/src/input/agent-workspace-knowledge-command-editor-submission.ts +132 -0
- package/src/input/agent-workspace-knowledge-command-editors.ts +110 -0
- package/src/input/agent-workspace-knowledge-query-editor.ts +1 -1
- package/src/input/agent-workspace-learned-behavior.ts +67 -0
- package/src/input/agent-workspace-library-command-editor-submission.ts +50 -0
- package/src/input/agent-workspace-library-command-editors.ts +35 -0
- 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-mcp-command-editor-submission.ts +95 -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-editor-submission.ts +232 -0
- package/src/input/agent-workspace-memory-command-editors.ts +180 -0
- package/src/input/agent-workspace-memory-editor.ts +2 -2
- package/src/input/agent-workspace-navigation.ts +81 -0
- package/src/input/agent-workspace-notify-editor-submission.ts +121 -0
- package/src/input/agent-workspace-operations-command-editor-submission.ts +208 -0
- package/src/input/agent-workspace-operations-command-editors.ts +196 -0
- package/src/input/agent-workspace-panel-route.ts +43 -0
- package/src/input/agent-workspace-provider-command-editor-submission.ts +155 -0
- package/src/input/agent-workspace-provider-command-editors.ts +93 -0
- package/src/input/agent-workspace-reminder-schedule-editor.ts +1 -1
- package/src/input/agent-workspace-requirements.ts +11 -0
- 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-secret-editor-submission.ts +153 -0
- package/src/input/agent-workspace-session-command-editor-submission.ts +199 -0
- package/src/input/agent-workspace-session-command-editors.ts +249 -0
- package/src/input/agent-workspace-setup.ts +37 -16
- package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +101 -0
- package/src/input/agent-workspace-skill-bundle-command-editors.ts +110 -0
- package/src/input/agent-workspace-snapshot.ts +162 -21
- package/src/input/agent-workspace-task-command-editor-submission.ts +61 -0
- package/src/input/agent-workspace-task-command-editors.ts +47 -0
- package/src/input/agent-workspace-token.ts +18 -2
- package/src/input/agent-workspace-types.ts +212 -4
- package/src/input/agent-workspace-voice-media.ts +4 -7
- package/src/input/agent-workspace-web-research-editor.ts +104 -0
- package/src/input/agent-workspace-workplan-editor-submission.ts +153 -0
- package/src/input/agent-workspace.ts +178 -240
- package/src/input/command-registry.ts +5 -2
- package/src/input/commands/agent-runtime-profile-runtime.ts +126 -37
- package/src/input/commands/agent-skills-runtime.ts +149 -72
- package/src/input/commands/agent-workspace-runtime.ts +23 -6
- package/src/input/commands/brief-runtime.ts +55 -25
- package/src/input/commands/channels-runtime.ts +147 -33
- package/src/input/commands/compat-runtime.ts +32 -0
- 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 +149 -126
- package/src/input/commands/knowledge.ts +82 -60
- package/src/input/commands/local-provider-runtime.ts +43 -21
- package/src/input/commands/local-runtime.ts +138 -16
- package/src/input/commands/local-setup-review.ts +10 -20
- package/src/input/commands/mcp-runtime.ts +63 -46
- 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 -76
- package/src/input/commands/personas-runtime.ts +46 -31
- package/src/input/commands/planning-runtime.ts +1 -1
- package/src/input/commands/platform-access-runtime.ts +35 -98
- package/src/input/commands/product-runtime.ts +2 -2
- package/src/input/commands/provider-accounts-runtime.ts +60 -39
- package/src/input/commands/qrcode-runtime.ts +50 -9
- 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 +99 -45
- package/src/input/commands/runtime-services.ts +1 -14
- package/src/input/commands/schedule-runtime.ts +33 -20
- package/src/input/commands/security-runtime.ts +6 -11
- package/src/input/commands/session-content.ts +80 -78
- package/src/input/commands/session-workflow.ts +134 -104
- package/src/input/commands/session.ts +3 -174
- package/src/input/commands/shell-core.ts +38 -17
- package/src/input/commands/subscription-runtime.ts +54 -185
- package/src/input/commands/support-bundle-runtime.ts +53 -0
- package/src/input/commands/tasks-runtime.ts +21 -21
- package/src/input/commands/work-plan-runtime.ts +33 -8
- package/src/input/commands.ts +6 -2
- package/src/input/feed-context-factory.ts +2 -2
- 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 -26
- package/src/input/handler-feed-routes.ts +19 -12
- package/src/input/handler-feed.ts +6 -5
- package/src/input/handler-interactions.ts +9 -36
- package/src/input/handler-modal-stack.ts +3 -3
- package/src/input/handler-onboarding.ts +52 -91
- package/src/input/handler-shortcuts.ts +16 -7
- package/src/input/handler.ts +50 -23
- package/src/input/input-history.ts +5 -6
- package/src/input/keybindings.ts +27 -16
- package/src/input/mcp-workspace.ts +90 -26
- package/src/input/onboarding/handler-onboarding-routes.ts +3 -1
- package/src/input/onboarding/onboarding-wizard-apply.ts +62 -0
- package/src/input/onboarding/onboarding-wizard-constants.ts +1 -0
- package/src/input/onboarding/onboarding-wizard-helpers.ts +1 -1
- package/src/input/onboarding/onboarding-wizard-operator-steps.ts +223 -55
- package/src/input/onboarding/onboarding-wizard-steps.ts +59 -35
- package/src/input/onboarding/onboarding-wizard-types.ts +4 -1
- package/src/input/onboarding/onboarding-wizard.ts +87 -2
- package/src/input/profile-picker-modal.ts +31 -12
- package/src/input/session-picker-modal.ts +21 -4
- package/src/input/settings-modal-agent-policy.ts +6 -6
- 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 +20 -66
- package/src/input/submission-intent.ts +0 -1
- package/src/input/submission-router.ts +3 -3
- package/src/main.ts +18 -10
- package/src/panels/approval-panel.ts +8 -8
- package/src/panels/automation-control-panel.ts +4 -4
- package/src/panels/base-panel.ts +1 -1
- package/src/panels/builtin/agent.ts +1 -1
- package/src/panels/builtin/operations.ts +3 -12
- package/src/panels/builtin/session.ts +32 -24
- package/src/panels/builtin/shared.ts +7 -7
- 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 +19 -12
- 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 +48 -7
- package/src/panels/provider-health-panel.ts +5 -4
- package/src/panels/qr-panel.ts +44 -20
- 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 +6 -6
- package/src/panels/system-messages-panel.ts +3 -3
- package/src/panels/tasks-panel.ts +21 -14
- 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 +3 -3
- package/src/provider-auth-route-display.ts +9 -0
- package/src/renderer/agent-workspace-style.ts +34 -0
- package/src/renderer/agent-workspace.ts +254 -57
- package/src/renderer/autocomplete-overlay.ts +25 -6
- package/src/renderer/block-actions.ts +1 -3
- 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 +112 -34
- package/src/renderer/history-search-overlay.ts +19 -4
- package/src/renderer/live-tail-modal.ts +27 -5
- package/src/renderer/mcp-workspace.ts +176 -43
- package/src/renderer/model-picker-overlay.ts +58 -3
- package/src/renderer/model-workspace.ts +104 -22
- package/src/renderer/onboarding/onboarding-wizard.ts +20 -4
- package/src/renderer/process-modal.ts +27 -6
- package/src/renderer/profile-picker-modal.ts +21 -5
- 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 +88 -55
- package/src/renderer/system-message.ts +1 -1
- package/src/renderer/tool-call.ts +20 -11
- package/src/runtime/agent-runtime-events.ts +129 -0
- package/src/runtime/bootstrap-command-context.ts +7 -1
- package/src/runtime/bootstrap-command-parts.ts +11 -8
- package/src/runtime/bootstrap-core.ts +23 -65
- package/src/runtime/bootstrap-hook-bridge.ts +7 -18
- package/src/runtime/bootstrap-shell.ts +46 -8
- package/src/runtime/bootstrap.ts +36 -46
- package/src/runtime/connected-host-auth.ts +47 -0
- package/src/runtime/diagnostics/panels/index.ts +2 -2
- package/src/runtime/diagnostics/panels/panel-resources.ts +1 -1
- package/src/runtime/diagnostics/panels/policy.ts +7 -7
- package/src/runtime/index.ts +2 -5
- package/src/runtime/onboarding/apply-file-helpers.ts +66 -0
- package/src/runtime/onboarding/apply.ts +288 -74
- package/src/runtime/onboarding/derivation.ts +10 -13
- package/src/runtime/onboarding/snapshot.ts +2 -17
- package/src/runtime/onboarding/types.ts +34 -20
- package/src/runtime/onboarding/verify.ts +105 -4
- package/src/runtime/operator-token-cleanup.ts +3 -3
- package/src/runtime/services.ts +95 -11
- 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/service-settings-sync.ts +7 -7
- package/src/shell/ui-openers.ts +17 -38
- 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 +279 -73
- 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 +13 -15
- package/src/tools/agent-work-plan-tool.ts +256 -0
- package/src/version.ts +1 -1
- package/docs/connected-services.md +0 -51
- package/src/cli/package-verification.ts +0 -274
- package/src/input/commands/policy-dispatch.ts +0 -339
- package/src/input/commands/policy.ts +0 -17
- 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
|
@@ -5,6 +5,7 @@ import type { OperatorMethodInput, OperatorMethodOutput } from '@pellux/goodvibe
|
|
|
5
5
|
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
6
6
|
import { getModelIdFromProviderModel, getProviderIdFromModel } from '../config/provider-model.ts';
|
|
7
7
|
import { SDK_VERSION } from '../version.ts';
|
|
8
|
+
import { formatAgentRecordReviewState } from './record-labels.ts';
|
|
8
9
|
import type { AgentRoutineRecord } from './routine-registry.ts';
|
|
9
10
|
|
|
10
11
|
export const ROUTINE_SCHEDULE_ROUTE = '/api/automation/schedules';
|
|
@@ -16,11 +17,11 @@ type ScheduleCreateOutput = OperatorMethodOutput<'schedules.create'>;
|
|
|
16
17
|
type ScheduleDeliveryInput = NonNullable<ScheduleCreateInput['delivery']>;
|
|
17
18
|
type ScheduleDeliveryTargetInput = ScheduleDeliveryInput['targets'] extends readonly (infer T)[] ? T : never;
|
|
18
19
|
|
|
19
|
-
export interface
|
|
20
|
+
export interface AgentConnectedHostConfigReader {
|
|
20
21
|
get(key: string): unknown;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
export interface
|
|
24
|
+
export interface AgentConnectedHostConnection {
|
|
24
25
|
readonly baseUrl: string;
|
|
25
26
|
readonly token: string | null;
|
|
26
27
|
readonly tokenPath: string;
|
|
@@ -46,6 +47,7 @@ export type RoutineScheduleDeliverySurfaceKind =
|
|
|
46
47
|
| 'google-chat'
|
|
47
48
|
| 'signal'
|
|
48
49
|
| 'whatsapp'
|
|
50
|
+
| 'telephony'
|
|
49
51
|
| 'imessage'
|
|
50
52
|
| 'msteams'
|
|
51
53
|
| 'bluebubbles'
|
|
@@ -105,14 +107,14 @@ export interface RoutineSchedulePromotionFailure {
|
|
|
105
107
|
readonly kind:
|
|
106
108
|
| 'confirmation_required'
|
|
107
109
|
| 'auth_required'
|
|
108
|
-
| '
|
|
110
|
+
| 'connected_host_unavailable'
|
|
109
111
|
| 'version_mismatch'
|
|
110
|
-
| '
|
|
111
|
-
| '
|
|
112
|
+
| 'connected_host_route_unavailable'
|
|
113
|
+
| 'connected_host_error';
|
|
112
114
|
readonly error: string;
|
|
113
115
|
readonly route: typeof ROUTINE_SCHEDULE_ROUTE;
|
|
114
116
|
readonly baseUrl?: string;
|
|
115
|
-
readonly
|
|
117
|
+
readonly connectedHostVersion?: string;
|
|
116
118
|
readonly expectedSdkVersion?: string;
|
|
117
119
|
}
|
|
118
120
|
|
|
@@ -128,7 +130,7 @@ export interface RoutineScheduleReceipt {
|
|
|
128
130
|
readonly route: typeof ROUTINE_SCHEDULE_ROUTE;
|
|
129
131
|
readonly method: typeof ROUTINE_SCHEDULE_METHOD;
|
|
130
132
|
readonly status: 'created' | 'failed';
|
|
131
|
-
readonly
|
|
133
|
+
readonly connectedHostBaseUrl: string;
|
|
132
134
|
readonly scheduleId?: string;
|
|
133
135
|
readonly scheduleStatus?: string;
|
|
134
136
|
readonly scheduleName: string;
|
|
@@ -191,14 +193,14 @@ export interface RoutineScheduleCorrelationFailure {
|
|
|
191
193
|
readonly ok: false;
|
|
192
194
|
readonly kind:
|
|
193
195
|
| 'auth_required'
|
|
194
|
-
| '
|
|
196
|
+
| 'connected_host_unavailable'
|
|
195
197
|
| 'version_mismatch'
|
|
196
|
-
| '
|
|
197
|
-
| '
|
|
198
|
+
| 'connected_host_route_unavailable'
|
|
199
|
+
| 'connected_host_error';
|
|
198
200
|
readonly error: string;
|
|
199
201
|
readonly route: typeof ROUTINE_SCHEDULE_ROUTE;
|
|
200
202
|
readonly baseUrl?: string;
|
|
201
|
-
readonly
|
|
203
|
+
readonly connectedHostVersion?: string;
|
|
202
204
|
readonly expectedSdkVersion?: string;
|
|
203
205
|
}
|
|
204
206
|
|
|
@@ -236,17 +238,17 @@ function deliveryModeFromTargets(targets: readonly RoutineScheduleDeliveryTarget
|
|
|
236
238
|
function toDeliveryTargetInput(target: RoutineScheduleDeliveryTargetSpec): ScheduleDeliveryTargetInput {
|
|
237
239
|
return {
|
|
238
240
|
kind: target.kind,
|
|
239
|
-
surfaceKind: target.surfaceKind,
|
|
241
|
+
surfaceKind: target.surfaceKind as ScheduleDeliveryTargetInput['surfaceKind'],
|
|
240
242
|
address: target.address,
|
|
241
243
|
routeId: target.routeId,
|
|
242
244
|
label: target.label,
|
|
243
245
|
};
|
|
244
246
|
}
|
|
245
247
|
|
|
246
|
-
export function
|
|
247
|
-
configManager:
|
|
248
|
+
export function resolveAgentConnectedHostConnection(
|
|
249
|
+
configManager: AgentConnectedHostConfigReader,
|
|
248
250
|
homeDirectory: string,
|
|
249
|
-
):
|
|
251
|
+
): AgentConnectedHostConnection {
|
|
250
252
|
const host = String(configManager.get('controlPlane.host') ?? '127.0.0.1');
|
|
251
253
|
const port = Number(configManager.get('controlPlane.port') ?? 3421);
|
|
252
254
|
const tokenPath = join(homeDirectory, '.goodvibes', 'daemon', 'operator-tokens.json');
|
|
@@ -265,16 +267,16 @@ export function buildRoutineSchedulePrompt(routine: AgentRoutineRecord): string
|
|
|
265
267
|
'GoodVibes Agent scheduled routine.',
|
|
266
268
|
'',
|
|
267
269
|
`Routine: ${routine.name}`,
|
|
268
|
-
`Routine
|
|
269
|
-
`Review
|
|
270
|
+
`Routine reference: ${routine.id}`,
|
|
271
|
+
`Review: ${formatAgentRecordReviewState(routine.reviewState)}`,
|
|
270
272
|
`Tags: ${routine.tags.join(', ') || '(none)'}`,
|
|
271
273
|
`Triggers: ${routine.triggers.join(', ') || '(manual)'}`,
|
|
272
274
|
'',
|
|
273
275
|
'Operator policy:',
|
|
274
276
|
'- Run this as a serial GoodVibes Agent operator routine.',
|
|
275
|
-
'- Use isolated Agent Knowledge routes only; never use default
|
|
277
|
+
'- Use isolated Agent Knowledge routes only; never use default knowledge or non-Agent knowledge spaces as fallback.',
|
|
276
278
|
'- Do not perform destructive, costly, externally visible, or secret-handling actions without explicit approval.',
|
|
277
|
-
'- Do not request
|
|
279
|
+
'- Do not request GoodVibes TUI delegation unless this scheduled routine explicitly delegates build/fix/review work to GoodVibes TUI.',
|
|
278
280
|
'- Summarize what was checked, what changed, and what still needs user review.',
|
|
279
281
|
'',
|
|
280
282
|
'Routine description:',
|
|
@@ -354,7 +356,7 @@ export function buildRoutineSchedulePreview(
|
|
|
354
356
|
};
|
|
355
357
|
}
|
|
356
358
|
|
|
357
|
-
async function
|
|
359
|
+
async function fetchConnectedHostStatus(connection: AgentConnectedHostConnection): Promise<{
|
|
358
360
|
readonly ok: boolean;
|
|
359
361
|
readonly status: number;
|
|
360
362
|
readonly body: unknown;
|
|
@@ -378,7 +380,7 @@ async function fetchDaemonStatus(connection: AgentDaemonConnection): Promise<{
|
|
|
378
380
|
|
|
379
381
|
async function classifyScheduleError(
|
|
380
382
|
error: unknown,
|
|
381
|
-
connection:
|
|
383
|
+
connection: AgentConnectedHostConnection,
|
|
382
384
|
): Promise<RoutineSchedulePromotionFailure> {
|
|
383
385
|
const message = summarizeError(error);
|
|
384
386
|
const lower = message.toLowerCase();
|
|
@@ -386,37 +388,37 @@ async function classifyScheduleError(
|
|
|
386
388
|
return { ok: false, kind: 'auth_required', error: message, route: ROUTINE_SCHEDULE_ROUTE, baseUrl: connection.baseUrl };
|
|
387
389
|
}
|
|
388
390
|
if (lower.includes('404') || lower.includes('not found')) {
|
|
389
|
-
const
|
|
390
|
-
const record = isRecord(
|
|
391
|
-
const
|
|
392
|
-
if (
|
|
391
|
+
const connectedHost = await fetchConnectedHostStatus(connection);
|
|
392
|
+
const record = isRecord(connectedHost.body) ? connectedHost.body : {};
|
|
393
|
+
const connectedHostVersion = readString(record, 'version') ?? 'unknown';
|
|
394
|
+
if (connectedHost.ok && connectedHostVersion !== SDK_VERSION) {
|
|
393
395
|
return {
|
|
394
396
|
ok: false,
|
|
395
397
|
kind: 'version_mismatch',
|
|
396
|
-
error: `Connected GoodVibes
|
|
398
|
+
error: `Connected GoodVibes host SDK version ${connectedHostVersion} does not match Agent SDK pin ${SDK_VERSION}; schedules.create is unavailable.`,
|
|
397
399
|
route: ROUTINE_SCHEDULE_ROUTE,
|
|
398
400
|
baseUrl: connection.baseUrl,
|
|
399
|
-
|
|
401
|
+
connectedHostVersion,
|
|
400
402
|
expectedSdkVersion: SDK_VERSION,
|
|
401
403
|
};
|
|
402
404
|
}
|
|
403
|
-
return { ok: false, kind: '
|
|
405
|
+
return { ok: false, kind: 'connected_host_route_unavailable', error: message, route: ROUTINE_SCHEDULE_ROUTE, baseUrl: connection.baseUrl };
|
|
404
406
|
}
|
|
405
407
|
if (lower.includes('fetch') || lower.includes('connect') || lower.includes('econnrefused')) {
|
|
406
|
-
return { ok: false, kind: '
|
|
408
|
+
return { ok: false, kind: 'connected_host_unavailable', error: message, route: ROUTINE_SCHEDULE_ROUTE, baseUrl: connection.baseUrl };
|
|
407
409
|
}
|
|
408
|
-
return { ok: false, kind: '
|
|
410
|
+
return { ok: false, kind: 'connected_host_error', error: message, route: ROUTINE_SCHEDULE_ROUTE, baseUrl: connection.baseUrl };
|
|
409
411
|
}
|
|
410
412
|
|
|
411
|
-
export async function
|
|
412
|
-
connection:
|
|
413
|
+
export async function promoteRoutineToConnectedSchedule(
|
|
414
|
+
connection: AgentConnectedHostConnection,
|
|
413
415
|
preview: RoutineSchedulePromotionPreview,
|
|
414
416
|
): Promise<RoutineSchedulePromotionResult> {
|
|
415
417
|
if (!connection.token) {
|
|
416
418
|
return {
|
|
417
419
|
ok: false,
|
|
418
420
|
kind: 'auth_required',
|
|
419
|
-
error: `No
|
|
421
|
+
error: `No connected-host operator token found at ${connection.tokenPath}`,
|
|
420
422
|
route: ROUTINE_SCHEDULE_ROUTE,
|
|
421
423
|
baseUrl: connection.baseUrl,
|
|
422
424
|
};
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
ROUTINE_SCHEDULE_LIST_METHOD,
|
|
13
13
|
ROUTINE_SCHEDULE_METHOD,
|
|
14
14
|
ROUTINE_SCHEDULE_ROUTE,
|
|
15
|
-
type
|
|
15
|
+
type AgentConnectedHostConnection,
|
|
16
16
|
type RoutineScheduleCorrelation,
|
|
17
17
|
type RoutineScheduleCorrelationFailure,
|
|
18
18
|
type RoutineScheduleCorrelationResult,
|
|
@@ -82,6 +82,15 @@ function redactedDeliveryTargets(delivery: ScheduleDeliveryInput | undefined): r
|
|
|
82
82
|
}));
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
function normalizeFailureKind(value: unknown): RoutineScheduleReceipt['failureKind'] {
|
|
86
|
+
if (value === 'confirmation_required' || value === 'auth_required' || value === 'version_mismatch') return value;
|
|
87
|
+
if (value === 'connected_host_unavailable' || value === 'connected_host_route_unavailable' || value === 'connected_host_error') return value;
|
|
88
|
+
if (value === 'daemon_unavailable') return 'connected_host_unavailable';
|
|
89
|
+
if (value === 'daemon_route_unavailable') return 'connected_host_route_unavailable';
|
|
90
|
+
if (value === 'daemon_error') return 'connected_host_error';
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
|
|
85
94
|
function readReceipt(value: unknown): RoutineScheduleReceipt | null {
|
|
86
95
|
if (!isRecord(value)) return null;
|
|
87
96
|
const id = readString(value, 'id')?.trim();
|
|
@@ -120,7 +129,7 @@ function readReceipt(value: unknown): RoutineScheduleReceipt | null {
|
|
|
120
129
|
route: ROUTINE_SCHEDULE_ROUTE,
|
|
121
130
|
method: ROUTINE_SCHEDULE_METHOD,
|
|
122
131
|
status,
|
|
123
|
-
|
|
132
|
+
connectedHostBaseUrl: readString(value, 'connectedHostBaseUrl') ?? readString(value, 'daemonBaseUrl') ?? '',
|
|
124
133
|
scheduleId: readString(value, 'scheduleId') ?? undefined,
|
|
125
134
|
scheduleStatus: readString(value, 'scheduleStatus') ?? undefined,
|
|
126
135
|
scheduleName: readString(value, 'scheduleName') ?? routineName,
|
|
@@ -138,14 +147,7 @@ function readReceipt(value: unknown): RoutineScheduleReceipt | null {
|
|
|
138
147
|
},
|
|
139
148
|
deliveryMode: readString(value, 'deliveryMode') ?? undefined,
|
|
140
149
|
deliveryTargets,
|
|
141
|
-
failureKind: value.failureKind
|
|
142
|
-
|| value.failureKind === 'auth_required'
|
|
143
|
-
|| value.failureKind === 'daemon_unavailable'
|
|
144
|
-
|| value.failureKind === 'version_mismatch'
|
|
145
|
-
|| value.failureKind === 'daemon_route_unavailable'
|
|
146
|
-
|| value.failureKind === 'daemon_error'
|
|
147
|
-
? value.failureKind
|
|
148
|
-
: undefined,
|
|
150
|
+
failureKind: normalizeFailureKind(value.failureKind),
|
|
149
151
|
failureError: readString(value, 'failureError') ?? undefined,
|
|
150
152
|
};
|
|
151
153
|
}
|
|
@@ -209,7 +211,7 @@ function resultScheduleRecord(result: RoutineSchedulePromotionResult): Record<st
|
|
|
209
211
|
|
|
210
212
|
function buildReceipt(
|
|
211
213
|
existing: readonly RoutineScheduleReceipt[],
|
|
212
|
-
connection:
|
|
214
|
+
connection: AgentConnectedHostConnection,
|
|
213
215
|
preview: RoutineSchedulePromotionPreview,
|
|
214
216
|
result: RoutineSchedulePromotionResult,
|
|
215
217
|
): RoutineScheduleReceipt {
|
|
@@ -226,7 +228,7 @@ function buildReceipt(
|
|
|
226
228
|
route: ROUTINE_SCHEDULE_ROUTE,
|
|
227
229
|
method: ROUTINE_SCHEDULE_METHOD,
|
|
228
230
|
status: result.ok ? 'created' : 'failed',
|
|
229
|
-
|
|
231
|
+
connectedHostBaseUrl: connection.baseUrl,
|
|
230
232
|
scheduleId,
|
|
231
233
|
scheduleStatus,
|
|
232
234
|
scheduleName: String(preview.payload.name ?? `Agent routine: ${preview.routineName}`),
|
|
@@ -269,7 +271,7 @@ export class RoutineScheduleReceiptStore {
|
|
|
269
271
|
return this.snapshot().receipts.find((receipt) => receipt.id.toLowerCase() === normalized) ?? null;
|
|
270
272
|
}
|
|
271
273
|
|
|
272
|
-
public append(connection:
|
|
274
|
+
public append(connection: AgentConnectedHostConnection, preview: RoutineSchedulePromotionPreview, result: RoutineSchedulePromotionResult): RoutineScheduleReceipt {
|
|
273
275
|
const store = this.readStore();
|
|
274
276
|
const receipt = buildReceipt(store.receipts, connection, preview, result);
|
|
275
277
|
this.writeStore({ ...store, receipts: [...store.receipts, receipt] });
|
|
@@ -281,7 +283,7 @@ export class RoutineScheduleReceiptStore {
|
|
|
281
283
|
try {
|
|
282
284
|
return parseReceiptStore(readFileSync(this.storePath, 'utf-8'));
|
|
283
285
|
} catch (error) {
|
|
284
|
-
throw new Error(`Could not read Agent routine schedule receipt store
|
|
286
|
+
throw new Error(`Could not read Agent routine schedule receipt store ${summarizeError(error)}`);
|
|
285
287
|
}
|
|
286
288
|
}
|
|
287
289
|
|
|
@@ -415,7 +417,7 @@ function correlateReceipts(
|
|
|
415
417
|
});
|
|
416
418
|
}
|
|
417
419
|
|
|
418
|
-
async function
|
|
420
|
+
async function fetchConnectedHostStatus(connection: AgentConnectedHostConnection): Promise<{
|
|
419
421
|
readonly ok: boolean;
|
|
420
422
|
readonly status: number;
|
|
421
423
|
readonly body: unknown;
|
|
@@ -439,7 +441,7 @@ async function fetchDaemonStatus(connection: AgentDaemonConnection): Promise<{
|
|
|
439
441
|
|
|
440
442
|
async function classifyScheduleListError(
|
|
441
443
|
error: unknown,
|
|
442
|
-
connection:
|
|
444
|
+
connection: AgentConnectedHostConnection,
|
|
443
445
|
): Promise<RoutineScheduleCorrelationFailure> {
|
|
444
446
|
const message = summarizeError(error);
|
|
445
447
|
const lower = message.toLowerCase();
|
|
@@ -447,37 +449,37 @@ async function classifyScheduleListError(
|
|
|
447
449
|
return { ok: false, kind: 'auth_required', error: message, route: ROUTINE_SCHEDULE_ROUTE, baseUrl: connection.baseUrl };
|
|
448
450
|
}
|
|
449
451
|
if (lower.includes('404') || lower.includes('not found')) {
|
|
450
|
-
const
|
|
451
|
-
const record = isRecord(
|
|
452
|
-
const
|
|
453
|
-
if (
|
|
452
|
+
const connectedHost = await fetchConnectedHostStatus(connection);
|
|
453
|
+
const record = isRecord(connectedHost.body) ? connectedHost.body : {};
|
|
454
|
+
const connectedHostVersion = readString(record, 'version') ?? 'unknown';
|
|
455
|
+
if (connectedHost.ok && connectedHostVersion !== SDK_VERSION) {
|
|
454
456
|
return {
|
|
455
457
|
ok: false,
|
|
456
458
|
kind: 'version_mismatch',
|
|
457
|
-
error: `Connected GoodVibes
|
|
459
|
+
error: `Connected GoodVibes host SDK version ${connectedHostVersion} does not match Agent SDK pin ${SDK_VERSION}; schedules.list is unavailable.`,
|
|
458
460
|
route: ROUTINE_SCHEDULE_ROUTE,
|
|
459
461
|
baseUrl: connection.baseUrl,
|
|
460
|
-
|
|
462
|
+
connectedHostVersion,
|
|
461
463
|
expectedSdkVersion: SDK_VERSION,
|
|
462
464
|
};
|
|
463
465
|
}
|
|
464
|
-
return { ok: false, kind: '
|
|
466
|
+
return { ok: false, kind: 'connected_host_route_unavailable', error: message, route: ROUTINE_SCHEDULE_ROUTE, baseUrl: connection.baseUrl };
|
|
465
467
|
}
|
|
466
468
|
if (lower.includes('fetch') || lower.includes('connect') || lower.includes('econnrefused')) {
|
|
467
|
-
return { ok: false, kind: '
|
|
469
|
+
return { ok: false, kind: 'connected_host_unavailable', error: message, route: ROUTINE_SCHEDULE_ROUTE, baseUrl: connection.baseUrl };
|
|
468
470
|
}
|
|
469
|
-
return { ok: false, kind: '
|
|
471
|
+
return { ok: false, kind: 'connected_host_error', error: message, route: ROUTINE_SCHEDULE_ROUTE, baseUrl: connection.baseUrl };
|
|
470
472
|
}
|
|
471
473
|
|
|
472
474
|
export async function reconcileRoutineScheduleReceipts(
|
|
473
|
-
connection:
|
|
475
|
+
connection: AgentConnectedHostConnection,
|
|
474
476
|
snapshot: RoutineScheduleReceiptSnapshot,
|
|
475
477
|
): Promise<RoutineScheduleCorrelationResult> {
|
|
476
478
|
if (!connection.token) {
|
|
477
479
|
return {
|
|
478
480
|
ok: false,
|
|
479
481
|
kind: 'auth_required',
|
|
480
|
-
error: `No
|
|
482
|
+
error: `No connected-host operator token found at ${connection.tokenPath}`,
|
|
481
483
|
route: ROUTINE_SCHEDULE_ROUTE,
|
|
482
484
|
baseUrl: connection.baseUrl,
|
|
483
485
|
};
|
|
@@ -44,7 +44,7 @@ export const STARTER_TEMPLATES: readonly AgentRuntimeProfileStarterTemplate[] =
|
|
|
44
44
|
body: [
|
|
45
45
|
'Operate as a calm household coordinator.',
|
|
46
46
|
'Track preferences, routines, device/service notes, and recurring decisions in Agent-local memory after they are durable and non-secret.',
|
|
47
|
-
'Use read-only
|
|
47
|
+
'Use read-only connected-host/operator routes for status checks. Require explicit approval for purchases, messages to other people, service changes, deletions, or secret handling.',
|
|
48
48
|
'Keep replies concrete: next action, owner, date, and open question when one is needed.',
|
|
49
49
|
].join('\n'),
|
|
50
50
|
tags: ['household', 'home', 'coordination'],
|
|
@@ -81,7 +81,7 @@ export const STARTER_TEMPLATES: readonly AgentRuntimeProfileStarterTemplate[] =
|
|
|
81
81
|
description: 'Review open household commitments, pending approvals, and stale home notes.',
|
|
82
82
|
steps: [
|
|
83
83
|
'1. List pending local routines, workplan tasks, and approvals.',
|
|
84
|
-
'2. Summarize what changed since the last review from local
|
|
84
|
+
'2. Summarize what changed since the last review from Agent-local state.',
|
|
85
85
|
'3. Ask for confirmation before scheduling, sending messages, purchasing, or changing services.',
|
|
86
86
|
'4. Record reviewed preferences and stale notes locally.',
|
|
87
87
|
].join('\n'),
|
|
@@ -200,7 +200,7 @@ export const STARTER_TEMPLATES: readonly AgentRuntimeProfileStarterTemplate[] =
|
|
|
200
200
|
name: 'Pre-trip Readiness Review',
|
|
201
201
|
description: 'Check documents, reservations, transport, packing, weather, and open decisions.',
|
|
202
202
|
steps: [
|
|
203
|
-
'1. Review trip dates, locations, reservations, and open decisions from local
|
|
203
|
+
'1. Review trip dates, locations, reservations, and open decisions from Agent-local state.',
|
|
204
204
|
'2. Refresh current weather, schedule, and rule data when needed.',
|
|
205
205
|
'3. Summarize blockers and next confirmed action.',
|
|
206
206
|
'4. Ask before external sends, purchases, or reservation changes.',
|
|
@@ -223,7 +223,7 @@ export const STARTER_TEMPLATES: readonly AgentRuntimeProfileStarterTemplate[] =
|
|
|
223
223
|
description: 'Operator persona for systems, incidents, runbooks, approvals, and service posture.',
|
|
224
224
|
body: [
|
|
225
225
|
'Favor explicit state, logs, health, approvals, and next action.',
|
|
226
|
-
'Use read-only
|
|
226
|
+
'Use read-only connected-host/operator routes by default.',
|
|
227
227
|
'Require explicit confirmation for run, pause, resume, cancel, retry, approve, deny, service changes, or writes.',
|
|
228
228
|
'Delegate code/build fixes to GoodVibes TUI when explicitly requested.',
|
|
229
229
|
].join('\n'),
|
|
@@ -260,7 +260,7 @@ export const STARTER_TEMPLATES: readonly AgentRuntimeProfileStarterTemplate[] =
|
|
|
260
260
|
name: 'Daily Operations Sweep',
|
|
261
261
|
description: 'Inspect service posture, pending approvals, failed runs, and stale tasks.',
|
|
262
262
|
steps: [
|
|
263
|
-
'1. Refresh
|
|
263
|
+
'1. Refresh connected-host status, compat, approvals, workplan, automation snapshot, runs, schedules, and capacity.',
|
|
264
264
|
'2. Summarize degraded items and blocked work.',
|
|
265
265
|
'3. Recommend exact follow-up commands with confirmation gates for side effects.',
|
|
266
266
|
].join('\n'),
|
|
@@ -36,6 +36,12 @@ export interface AgentRuntimeProfileInfo extends AgentRuntimeProfileResolution {
|
|
|
36
36
|
readonly starterTemplateApplication?: AgentRuntimeProfileTemplateApplication;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
export interface AgentRuntimeProfileSelection extends AgentRuntimeProfileResolution {
|
|
40
|
+
readonly selectedAt: string | null;
|
|
41
|
+
readonly path: string;
|
|
42
|
+
readonly exists: boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
39
45
|
export interface AgentRuntimeProfileTemplateApplication {
|
|
40
46
|
readonly id: AgentRuntimeProfileTemplateId;
|
|
41
47
|
readonly name: string;
|
|
@@ -76,11 +82,14 @@ export interface AgentRuntimeProfileCommandResult {
|
|
|
76
82
|
| 'agent.profiles.template.from_discovered'
|
|
77
83
|
| 'agent.profiles.create_from_discovered'
|
|
78
84
|
| 'agent.profiles.create'
|
|
85
|
+
| 'agent.profiles.default'
|
|
86
|
+
| 'agent.profiles.default.clear'
|
|
79
87
|
| 'agent.profiles.delete'
|
|
80
88
|
| 'agent.profiles.error';
|
|
81
89
|
readonly data?: {
|
|
82
90
|
readonly profiles?: readonly AgentRuntimeProfileInfo[];
|
|
83
91
|
readonly profile?: AgentRuntimeProfileInfo;
|
|
92
|
+
readonly selectedProfile?: AgentRuntimeProfileSelection;
|
|
84
93
|
readonly templates?: readonly AgentRuntimeProfileTemplateSummary[];
|
|
85
94
|
readonly appliedTemplate?: AgentRuntimeProfileTemplateApplication;
|
|
86
95
|
readonly template?: AgentRuntimeProfileTemplateSummary;
|
|
@@ -91,8 +100,13 @@ export interface AgentRuntimeProfileCommandResult {
|
|
|
91
100
|
}
|
|
92
101
|
|
|
93
102
|
const PROFILE_CREATED_FILE = 'profile.json';
|
|
103
|
+
const PROFILE_SELECTION_FILE = 'profile-selection.json';
|
|
94
104
|
const PROFILE_ID_PATTERN = /^[a-z0-9](?:[a-z0-9._-]{0,62}[a-z0-9])?$/;
|
|
95
105
|
|
|
106
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
107
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
108
|
+
}
|
|
109
|
+
|
|
96
110
|
export function normalizeAgentRuntimeProfileId(value: string): string {
|
|
97
111
|
return value
|
|
98
112
|
.trim()
|
|
@@ -122,6 +136,10 @@ export function getAgentRuntimeProfileTemplatesRoot(baseHomeDirectory: string):
|
|
|
122
136
|
return join(baseHomeDirectory, '.goodvibes', GOODVIBES_AGENT_SURFACE_ROOT, 'profile-starters');
|
|
123
137
|
}
|
|
124
138
|
|
|
139
|
+
export function getAgentRuntimeProfileSelectionPath(baseHomeDirectory: string): string {
|
|
140
|
+
return join(baseHomeDirectory, '.goodvibes', GOODVIBES_AGENT_SURFACE_ROOT, PROFILE_SELECTION_FILE);
|
|
141
|
+
}
|
|
142
|
+
|
|
125
143
|
export function resolveAgentRuntimeProfileHome(baseHomeDirectory: string, profileName: string): AgentRuntimeProfileResolution {
|
|
126
144
|
const id = assertValidAgentRuntimeProfileId(profileName);
|
|
127
145
|
return {
|
|
@@ -130,6 +148,36 @@ export function resolveAgentRuntimeProfileHome(baseHomeDirectory: string, profil
|
|
|
130
148
|
};
|
|
131
149
|
}
|
|
132
150
|
|
|
151
|
+
export function readAgentRuntimeProfileSelection(baseHomeDirectory: string): AgentRuntimeProfileSelection | null {
|
|
152
|
+
const path = getAgentRuntimeProfileSelectionPath(baseHomeDirectory);
|
|
153
|
+
if (!existsSync(path)) return null;
|
|
154
|
+
try {
|
|
155
|
+
const raw: unknown = JSON.parse(readFileSync(path, 'utf-8'));
|
|
156
|
+
if (!isRecord(raw)) return null;
|
|
157
|
+
const profileId = raw.profileId;
|
|
158
|
+
if (typeof profileId !== 'string') return null;
|
|
159
|
+
const resolution = resolveAgentRuntimeProfileHome(baseHomeDirectory, profileId);
|
|
160
|
+
const selectedAt = typeof raw.selectedAt === 'string' ? raw.selectedAt : null;
|
|
161
|
+
return {
|
|
162
|
+
...resolution,
|
|
163
|
+
selectedAt,
|
|
164
|
+
path,
|
|
165
|
+
exists: existsSync(resolution.homeDirectory),
|
|
166
|
+
};
|
|
167
|
+
} catch {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function resolveSelectedAgentRuntimeProfileHome(baseHomeDirectory: string): AgentRuntimeProfileResolution | null {
|
|
173
|
+
const selection = readAgentRuntimeProfileSelection(baseHomeDirectory);
|
|
174
|
+
if (!selection?.exists) return null;
|
|
175
|
+
return {
|
|
176
|
+
id: selection.id,
|
|
177
|
+
homeDirectory: selection.homeDirectory,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
133
181
|
function readProfileCreatedAt(homeDirectory: string): string | null {
|
|
134
182
|
const path = join(homeDirectory, PROFILE_CREATED_FILE);
|
|
135
183
|
if (!existsSync(path)) return null;
|
|
@@ -147,13 +195,11 @@ function readProfileStarterTemplate(homeDirectory: string): Pick<AgentRuntimePro
|
|
|
147
195
|
if (!existsSync(path)) return {};
|
|
148
196
|
try {
|
|
149
197
|
const raw: unknown = JSON.parse(readFileSync(path, 'utf-8'));
|
|
150
|
-
if (!
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
const id = starterRecord.id;
|
|
156
|
-
const name = starterRecord.name;
|
|
198
|
+
if (!isRecord(raw)) return {};
|
|
199
|
+
const starter = raw.starterTemplate;
|
|
200
|
+
if (!isRecord(starter)) return {};
|
|
201
|
+
const id = starter.id;
|
|
202
|
+
const name = starter.name;
|
|
157
203
|
if (!isAgentRuntimeProfileTemplateId(id) || typeof name !== 'string') return {};
|
|
158
204
|
return {
|
|
159
205
|
starterTemplateId: id,
|
|
@@ -226,7 +272,7 @@ function selectDiscoveredRecord<T extends { readonly name: string; readonly path
|
|
|
226
272
|
if (!selector?.trim()) return records[0]!;
|
|
227
273
|
const lookup = selector.trim().toLowerCase();
|
|
228
274
|
const match = records.find((record) => normalizedLookupValues(record.name, record.path).includes(lookup));
|
|
229
|
-
if (!match) throw new Error(`Unknown discovered Agent ${label}
|
|
275
|
+
if (!match) throw new Error(`Unknown discovered Agent ${label} ${selector}.`);
|
|
230
276
|
return match;
|
|
231
277
|
}
|
|
232
278
|
|
|
@@ -278,8 +324,8 @@ function readTemplateTextBlock(value: unknown, field: string): string {
|
|
|
278
324
|
}
|
|
279
325
|
|
|
280
326
|
function readTemplateObject(value: unknown, field: string): Record<string, unknown> {
|
|
281
|
-
if (!
|
|
282
|
-
return value
|
|
327
|
+
if (!isRecord(value)) throw new Error(`Starter template ${field} must be an object.`);
|
|
328
|
+
return value;
|
|
283
329
|
}
|
|
284
330
|
|
|
285
331
|
function parseTemplateSkill(value: unknown): AgentRuntimeProfileStarterTemplate['skills'][number] {
|
|
@@ -360,7 +406,7 @@ function resolveAgentRuntimeProfileTemplate(templateId: AgentRuntimeProfileTempl
|
|
|
360
406
|
const local = baseHomeDirectory ? listLocalTemplates(baseHomeDirectory).find((template) => template.id === id) : undefined;
|
|
361
407
|
if (local) return local;
|
|
362
408
|
const suffix = baseHomeDirectory ? ' Use profiles templates to list starters.' : '';
|
|
363
|
-
throw new Error(`Unknown Agent starter profile template
|
|
409
|
+
throw new Error(`Unknown Agent starter profile template ${templateId}.${suffix}`);
|
|
364
410
|
}
|
|
365
411
|
|
|
366
412
|
export function listAgentRuntimeProfileTemplates(baseHomeDirectory?: string): readonly AgentRuntimeProfileTemplateSummary[] {
|
|
@@ -423,7 +469,7 @@ export async function createAgentRuntimeProfileTemplateFromDiscovered(
|
|
|
423
469
|
const selectedRoutines = selectDiscoveredRecords(routines, options.routines, 'routine');
|
|
424
470
|
const target = join(getAgentRuntimeProfileTemplatesRoot(shellPaths.homeDirectory), `${id}.json`);
|
|
425
471
|
if (existsSync(target) && options.replace !== true) {
|
|
426
|
-
throw new Error(`Agent starter template already exists
|
|
472
|
+
throw new Error(`Agent starter template already exists ${id}. Rerun with --replace to overwrite it.`);
|
|
427
473
|
}
|
|
428
474
|
const persona = discoveredPersonaToTemplate(selectedPersona);
|
|
429
475
|
const template: AgentRuntimeProfileStarterTemplate = {
|
|
@@ -573,9 +619,42 @@ export function createAgentRuntimeProfile(baseHomeDirectory: string, profileName
|
|
|
573
619
|
};
|
|
574
620
|
}
|
|
575
621
|
|
|
622
|
+
export function setAgentRuntimeProfileSelection(baseHomeDirectory: string, profileName: string): AgentRuntimeProfileSelection {
|
|
623
|
+
const resolution = resolveAgentRuntimeProfileHome(baseHomeDirectory, profileName);
|
|
624
|
+
if (!existsSync(resolution.homeDirectory)) {
|
|
625
|
+
throw new Error(`Agent profile not found ${resolution.id}`);
|
|
626
|
+
}
|
|
627
|
+
const path = getAgentRuntimeProfileSelectionPath(baseHomeDirectory);
|
|
628
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
629
|
+
const selectedAt = new Date().toISOString();
|
|
630
|
+
writeFileSync(
|
|
631
|
+
path,
|
|
632
|
+
`${JSON.stringify({
|
|
633
|
+
profileId: resolution.id,
|
|
634
|
+
selectedAt,
|
|
635
|
+
}, null, 2)}\n`,
|
|
636
|
+
'utf-8',
|
|
637
|
+
);
|
|
638
|
+
return {
|
|
639
|
+
...resolution,
|
|
640
|
+
selectedAt,
|
|
641
|
+
path,
|
|
642
|
+
exists: true,
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
export function clearAgentRuntimeProfileSelection(baseHomeDirectory: string): boolean {
|
|
647
|
+
const path = getAgentRuntimeProfileSelectionPath(baseHomeDirectory);
|
|
648
|
+
if (!existsSync(path)) return false;
|
|
649
|
+
rmSync(path, { force: true });
|
|
650
|
+
return true;
|
|
651
|
+
}
|
|
652
|
+
|
|
576
653
|
export function deleteAgentRuntimeProfile(baseHomeDirectory: string, profileName: string): boolean {
|
|
577
654
|
const resolution = resolveAgentRuntimeProfileHome(baseHomeDirectory, profileName);
|
|
578
655
|
if (!existsSync(resolution.homeDirectory)) return false;
|
|
579
656
|
rmSync(resolution.homeDirectory, { recursive: true, force: true });
|
|
657
|
+
const selection = readAgentRuntimeProfileSelection(baseHomeDirectory);
|
|
658
|
+
if (selection?.id === resolution.id) clearAgentRuntimeProfileSelection(baseHomeDirectory);
|
|
580
659
|
return true;
|
|
581
660
|
}
|