@pellux/goodvibes-agent 0.1.55 → 0.1.57
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/.goodvibes/GOODVIBES.md +1 -1
- package/CHANGELOG.md +19 -8
- package/README.md +10 -3
- package/docs/README.md +1 -1
- package/docs/getting-started.md +10 -3
- package/docs/release-and-publishing.md +12 -3
- package/package.json +1 -3
- package/scripts/check-bun.sh +5 -1
- package/src/agent/routine-schedule-args.ts +219 -0
- package/src/agent/routine-schedule-format.ts +173 -0
- package/src/agent/routine-schedule-promotion.ts +3 -811
- package/src/agent/routine-schedule-receipts.ts +502 -0
- package/src/cli/agent-knowledge-command.ts +6 -6
- package/src/cli/help.ts +3 -25
- package/src/cli/package-verification.ts +23 -16
- package/src/cli/redaction.ts +4 -1
- package/src/cli/routines-command.ts +10 -6
- package/src/cli/service-posture.ts +47 -280
- package/src/cli/status.ts +0 -1
- package/src/config/secret-config.ts +0 -2
- package/src/input/agent-workspace-categories.ts +219 -0
- package/src/input/agent-workspace-editors.ts +143 -0
- package/src/input/agent-workspace-snapshot.ts +265 -0
- package/src/input/agent-workspace-types.ts +142 -0
- package/src/input/agent-workspace.ts +22 -766
- package/src/input/commands/agent-runtime-profile-runtime.ts +1 -1
- package/src/input/commands/delegation-runtime.ts +1 -1
- package/src/input/commands/experience-runtime.ts +3 -4
- package/src/input/commands/guidance-runtime.ts +1 -2
- package/src/input/commands/health-runtime.ts +3 -65
- package/src/input/commands/knowledge.ts +7 -7
- package/src/input/commands/local-setup-review.ts +0 -61
- package/src/input/commands/local-setup-transfer.ts +0 -3
- package/src/input/commands/local-setup.ts +2 -15
- package/src/input/commands/planning-runtime.ts +4 -1
- package/src/input/commands/platform-access-runtime.ts +1 -10
- package/src/input/commands/platform-services-runtime.ts +0 -1
- package/src/input/commands/recall-query.ts +1 -1
- package/src/input/commands/routines-runtime.ts +10 -6
- package/src/input/commands/schedule-runtime.ts +10 -6
- package/src/input/commands/session-workflow.ts +1 -1
- package/src/input/commands/tasks-runtime.ts +1 -14
- package/src/input/commands.ts +0 -4
- package/src/input/handler-onboarding.ts +10 -120
- package/src/input/onboarding/onboarding-wizard-apply.ts +5 -196
- package/src/input/onboarding/onboarding-wizard-constants.ts +8 -119
- package/src/input/onboarding/onboarding-wizard-helpers.ts +2 -53
- package/src/input/onboarding/onboarding-wizard-rules.ts +2 -236
- package/src/input/onboarding/onboarding-wizard-state.ts +1 -69
- package/src/input/onboarding/onboarding-wizard-steps.ts +584 -737
- package/src/input/onboarding/onboarding-wizard-types.ts +8 -26
- package/src/input/onboarding/onboarding-wizard.ts +4 -109
- package/src/input/settings-modal-agent-policy.ts +10 -0
- package/src/input/settings-modal-types.ts +2 -4
- package/src/input/settings-modal.ts +3 -1
- package/src/input/submission-router.ts +0 -1
- package/src/panels/approval-panel.ts +1 -2
- package/src/panels/builtin/operations.ts +1 -2
- package/src/panels/knowledge-panel.ts +2 -2
- package/src/panels/project-planning-panel.ts +4 -1
- package/src/panels/provider-health-domains.ts +0 -22
- package/src/panels/provider-health-panel.ts +1 -5
- package/src/panels/session-browser-panel.ts +0 -5
- package/src/panels/tasks-panel.ts +2 -64
- package/src/renderer/agent-workspace.ts +1 -1
- package/src/renderer/help-overlay.ts +1 -2
- package/src/renderer/semantic-diff.ts +1 -1
- package/src/renderer/settings-modal-helpers.ts +0 -16
- package/src/renderer/settings-modal.ts +3 -5
- package/src/runtime/bootstrap-hook-bridge.ts +0 -3
- package/src/runtime/bootstrap-shell.ts +2 -1
- package/src/runtime/bootstrap.ts +1 -1
- package/src/runtime/index.ts +0 -1
- package/src/runtime/onboarding/derivation.ts +1 -28
- package/src/runtime/onboarding/snapshot.ts +0 -1
- package/src/runtime/onboarding/types.ts +1 -4
- package/src/runtime/services.ts +4 -23
- package/src/runtime/ui-read-models.ts +4 -3
- package/src/shell/service-settings-sync.ts +15 -244
- package/src/tools/agent-context-policy.ts +1 -1
- package/src/tools/wrfc-agent-guard.ts +3 -3
- package/src/verification/live-verifier.ts +11 -5
- package/src/verification/verification-ledger.ts +3 -6
- package/src/version.ts +1 -1
- package/src/input/commands/agent-externalized-tui.ts +0 -73
- package/src/input/commands/cloudflare-runtime.ts +0 -385
- package/src/input/handler-onboarding-cloudflare.ts +0 -322
- package/src/input/onboarding/onboarding-runtime-status.ts +0 -87
- package/src/input/onboarding/onboarding-wizard-cloudflare-step.ts +0 -494
- package/src/input/onboarding/onboarding-wizard-cloudflare.ts +0 -199
- package/src/input/onboarding/onboarding-wizard-external-surface-extra-specs.ts +0 -130
- package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +0 -762
- package/src/runtime/cloudflare-control-plane.ts +0 -350
- package/src/runtime/sandbox-public-gaps.ts +0 -358
|
@@ -97,9 +97,7 @@ export const CATEGORY_LABELS: Record<(typeof SETTINGS_CATEGORIES)[number], strin
|
|
|
97
97
|
telemetry: 'Telemetry',
|
|
98
98
|
cache: 'Cache',
|
|
99
99
|
mcp: 'MCP',
|
|
100
|
-
sandbox: 'External Sandbox',
|
|
101
100
|
surfaces: 'Surfaces',
|
|
102
|
-
cloudflare: 'Cloudflare',
|
|
103
101
|
release: 'Release',
|
|
104
102
|
danger: 'Danger',
|
|
105
103
|
tools: 'Tools',
|
|
@@ -117,11 +115,6 @@ export const SETTING_LABELS: Partial<Record<string, string>> = {
|
|
|
117
115
|
'behavior.returnContextMode': 'Return Context',
|
|
118
116
|
'behavior.guidanceMode': 'Guidance Mode',
|
|
119
117
|
'storage.secretPolicy': 'Secret Policy',
|
|
120
|
-
'sandbox.vmBackend': 'External Sandbox Backend',
|
|
121
|
-
'sandbox.qemuBinary': 'External QEMU Binary',
|
|
122
|
-
'sandbox.qemuImagePath': 'External QEMU Image',
|
|
123
|
-
'sandbox.qemuExecWrapper': 'External QEMU Wrapper',
|
|
124
|
-
'sandbox.replJavaScriptCommand': 'REPL JS Command',
|
|
125
118
|
'tools.llmProvider': 'Tool LLM Provider',
|
|
126
119
|
'tools.llmModel': 'Tool LLM Model',
|
|
127
120
|
'tools.autoHeal': 'Auto-Heal',
|
|
@@ -164,15 +157,6 @@ export const SETTING_LABELS: Partial<Record<string, string>> = {
|
|
|
164
157
|
'surfaces.ntfy.remoteTopic': 'ntfy Daemon-Only Remote Topic',
|
|
165
158
|
'surfaces.ntfy.token': 'ntfy Token',
|
|
166
159
|
'surfaces.ntfy.defaultPriority': 'ntfy Default Priority',
|
|
167
|
-
'surfaces.homeassistant.enabled': 'Home Assistant Enabled',
|
|
168
|
-
'surfaces.homeassistant.instanceUrl': 'Home Assistant URL',
|
|
169
|
-
'surfaces.homeassistant.accessToken': 'Home Assistant Access Token',
|
|
170
|
-
'surfaces.homeassistant.webhookSecret': 'Home Assistant Webhook Secret',
|
|
171
|
-
'surfaces.homeassistant.defaultConversationId': 'Home Assistant Conversation ID',
|
|
172
|
-
'surfaces.homeassistant.remoteSessionTtlMs': 'Home Assistant Remote Session TTL',
|
|
173
|
-
'surfaces.homeassistant.deviceId': 'Home Assistant Device ID',
|
|
174
|
-
'surfaces.homeassistant.deviceName': 'Home Assistant Device Name',
|
|
175
|
-
'surfaces.homeassistant.eventType': 'Home Assistant Event Type',
|
|
176
160
|
};
|
|
177
161
|
|
|
178
162
|
export function getSettingLabel(entry: SettingEntry): string {
|
|
@@ -28,7 +28,7 @@ const CATEGORY_INFO: Record<SettingsCategory, string> = {
|
|
|
28
28
|
provider: 'Default model routing for normal chat turns, embeddings, reasoning effort, and persistent system prompt file.',
|
|
29
29
|
subscriptions: 'Provider subscription login state and routing posture. Active sessions can be reviewed or signed out here; API keys remain managed through secrets.',
|
|
30
30
|
behavior: 'Day-to-day shell behavior: approval posture, compaction, history, guidance, notifications, stale-context warnings, return context, and Human-in-the-Loop mode.',
|
|
31
|
-
storage: 'Local storage posture, including secret storage policy and maximum artifact size for
|
|
31
|
+
storage: 'Local storage posture, including secret storage policy and maximum artifact size for Agent Knowledge, artifacts, and document ingestion.',
|
|
32
32
|
permissions: 'Permission mode and tool-class policy. These settings decide whether the shell prompts before read/write/exec/network/agent actions.',
|
|
33
33
|
orchestration: 'Agent orchestration limits and recursion controls.',
|
|
34
34
|
wrfc: 'WRFC is external to normal Agent operation. Review these copied compatibility values only for explicit GoodVibes TUI build delegation.',
|
|
@@ -38,16 +38,14 @@ const CATEGORY_INFO: Record<SettingsCategory, string> = {
|
|
|
38
38
|
controlPlane: 'External daemon control-plane settings for local admin/API access. Agent connects to this daemon and does not mutate its bind posture.',
|
|
39
39
|
httpListener: 'External HTTP listener settings for webhook and integration ingress. Agent does not start or expose the listener.',
|
|
40
40
|
web: 'External browser surface settings. Agent does not own the web listener or network bind lifecycle.',
|
|
41
|
-
batch: 'Batch execution settings
|
|
41
|
+
batch: 'Batch execution settings reported from the external daemon. Agent does not own remote queue provisioning.',
|
|
42
42
|
automation: 'Scheduled and automated run settings, concurrency, timeout, catch-up, cooldown, and retention behavior.',
|
|
43
43
|
watchers: 'File/process watcher heartbeat, polling, and recovery-window behavior.',
|
|
44
44
|
runtime: 'Runtime guardrails such as companion chat limiter and event bus listener caps.',
|
|
45
45
|
telemetry: 'Telemetry payload policy.',
|
|
46
46
|
cache: 'Provider and model cache behavior, TTL, and hit-rate monitoring.',
|
|
47
47
|
mcp: 'MCP server trust and scope review. Trust changes can expose local files, tools, databases, browsers, or remote automation depending on the server.',
|
|
48
|
-
|
|
49
|
-
surfaces: 'External app surfaces such as Slack, Discord, ntfy, Home Assistant, Telegram, webhooks, chat bridges, and messaging providers.',
|
|
50
|
-
cloudflare: 'Optional Cloudflare control plane, batch queue, Worker, Tunnel, Access, DNS, KV, Durable Objects, Secrets Store, and R2 settings.',
|
|
48
|
+
surfaces: 'External app surfaces such as Slack, Discord, ntfy, Telegram, webhooks, chat bridges, and messaging providers.',
|
|
51
49
|
release: 'Release-channel preference.',
|
|
52
50
|
danger: 'High-impact daemon and listener switches. Agent renders daemon-owned switches read-only; use GoodVibes TUI or the daemon host to change them.',
|
|
53
51
|
tools: 'Tool LLM and helper model routing. Empty provider/model values inherit the active chat route unless a specific helper/tool route is set.',
|
|
@@ -76,9 +76,6 @@ export function createResumeSessionHandler(options: ResumeSessionOptions): (sess
|
|
|
76
76
|
if ((meta.returnContext.remoteRunners?.length ?? 0) > 0) {
|
|
77
77
|
options.conversation.log(`Resume: Remote re-entry -> /remote recover ${meta.returnContext.remoteRunners![0]}`, { fg: '244' });
|
|
78
78
|
}
|
|
79
|
-
if ((meta.returnContext.worktreePaths?.length ?? 0) > 0) {
|
|
80
|
-
options.conversation.log('Resume: Worktree re-entry -> /worktree review', { fg: '244' });
|
|
81
|
-
}
|
|
82
79
|
if (returnContextMode === 'assisted') {
|
|
83
80
|
const helperModel = new HelperModel({
|
|
84
81
|
configManager: options.configManager,
|
|
@@ -160,8 +160,9 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
|
|
|
160
160
|
|
|
161
161
|
const commandRegistry = new CommandRegistry();
|
|
162
162
|
registerBuiltinCommands(commandRegistry);
|
|
163
|
+
type RuntimeFoundationInput = Parameters<typeof createRuntimeFoundationClients>[0];
|
|
163
164
|
const foundationClients = createRuntimeFoundationClients({
|
|
164
|
-
runtimeServices: services,
|
|
165
|
+
runtimeServices: services as unknown as RuntimeFoundationInput['runtimeServices'],
|
|
165
166
|
tasksReadModel: uiServices.readModels.tasks,
|
|
166
167
|
taskManager,
|
|
167
168
|
opsControlPlane,
|
package/src/runtime/bootstrap.ts
CHANGED
|
@@ -52,7 +52,7 @@ const GOODVIBES_AGENT_OPERATOR_POLICY = [
|
|
|
52
52
|
'- WRFC is never the default Agent reasoning path. Do not create local WRFC chains for planning, research, operations, knowledge, memory, configuration, approvals, automation observability, or ordinary assistant work.',
|
|
53
53
|
'- GoodVibes Agent is not the coding TUI. Do not use the `agent` tool to spawn local Engineer, Reviewer, Tester, Verifier, or batch-spawn roots from Agent.',
|
|
54
54
|
'- When the user explicitly asks to build, implement, fix, patch, or review code, preserve the full original user ask and delegate one build request to GoodVibes TUI through the public shared-session/build-delegation contract. Include clear executionIntent and request WRFC only for explicit build/fix/review work or when the user explicitly asks for WRFC/agent review.',
|
|
55
|
-
'- Do not narrow explicit build/fix/review requests into design-only, read-only, or no-write work unless the user explicitly requested that limitation. TUI owns file edits, git/worktree work,
|
|
55
|
+
'- Do not narrow explicit build/fix/review requests into design-only, read-only, or no-write work unless the user explicitly requested that limitation. TUI owns file edits, git/worktree work, runtime-isolation UX, and the WRFC owner chain.',
|
|
56
56
|
'- If a stable public delegation route is unavailable, say that the task needs GoodVibes TUI delegation and report the missing route instead of pretending to implement it locally or spawning sibling local agents.',
|
|
57
57
|
].join('\n');
|
|
58
58
|
|
package/src/runtime/index.ts
CHANGED
|
@@ -57,7 +57,6 @@ export * from '@pellux/goodvibes-sdk/platform/runtime/ui';
|
|
|
57
57
|
export * from '@pellux/goodvibes-sdk/platform/runtime/observability';
|
|
58
58
|
export * from '@pellux/goodvibes-sdk/platform/runtime/settings';
|
|
59
59
|
export * from '@pellux/goodvibes-sdk/platform/runtime/sandbox';
|
|
60
|
-
export * from './sandbox-public-gaps.ts';
|
|
61
60
|
export {
|
|
62
61
|
CONTROL_PLANE_CLIENT_KINDS,
|
|
63
62
|
CONTROL_PLANE_TRANSPORT_KINDS,
|
|
@@ -40,7 +40,6 @@ const PROVIDER_SECRET_ENV_ALIASES = {
|
|
|
40
40
|
xai: ['XAI_API_KEY'],
|
|
41
41
|
xiaomi: ['XIAOMI_API_KEY'],
|
|
42
42
|
zai: ['ZAI_API_KEY', 'Z_AI_API_KEY'],
|
|
43
|
-
'cloudflare-ai-gateway': ['CLOUDFLARE_AI_GATEWAY_API_KEY'],
|
|
44
43
|
'vercel-ai-gateway': ['AI_GATEWAY_API_KEY'],
|
|
45
44
|
litellm: ['LITELLM_API_KEY'],
|
|
46
45
|
'copilot-proxy': ['COPILOT_PROXY_API_KEY'],
|
|
@@ -55,7 +54,6 @@ const INBOUND_EVENT_SURFACE_KINDS = new Set<string>([
|
|
|
55
54
|
'discord',
|
|
56
55
|
'google-chat',
|
|
57
56
|
'googleChat',
|
|
58
|
-
'homeassistant',
|
|
59
57
|
'imessage',
|
|
60
58
|
'mattermost',
|
|
61
59
|
'matrix',
|
|
@@ -253,15 +251,6 @@ function hasExternalIntegrations(snapshot: OnboardingSnapshotState): boolean {
|
|
|
253
251
|
|| countConfiguredSurfaceKinds(snapshot) > 0;
|
|
254
252
|
}
|
|
255
253
|
|
|
256
|
-
function hasCloudflareBatch(snapshot: OnboardingSnapshotState): boolean {
|
|
257
|
-
return snapshot.config.cloudflare.enabled
|
|
258
|
-
|| snapshot.config.batch.queueBackend === 'cloudflare'
|
|
259
|
-
|| snapshot.config.batch.mode !== 'off'
|
|
260
|
-
|| snapshot.config.cloudflare.accountId.trim().length > 0
|
|
261
|
-
|| snapshot.config.cloudflare.apiTokenRef.trim().length > 0
|
|
262
|
-
|| snapshot.config.cloudflare.workerBaseUrl.trim().length > 0;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
254
|
function describeLocalTuiOnly(snapshot: OnboardingSnapshotState): string {
|
|
266
255
|
if (!hasAnyServerEnabled(snapshot)) {
|
|
267
256
|
return 'Use GoodVibes Agent in this terminal while connecting only to an externally managed daemon. Agent does not enable service mode, HTTP listeners, external app surfaces, or network setup.';
|
|
@@ -295,20 +284,12 @@ function describeExternalIntegrations(snapshot: OnboardingSnapshotState): string
|
|
|
295
284
|
]).size;
|
|
296
285
|
|
|
297
286
|
if (integrationCount === 0) {
|
|
298
|
-
return 'Enable setup screens for Slack, Discord, Telegram,
|
|
287
|
+
return 'Enable setup screens for Slack, Discord, Telegram, Teams, Matrix, and other app surfaces you choose.';
|
|
299
288
|
}
|
|
300
289
|
|
|
301
290
|
return `Review and configure ${integrationCount} detected external app, service, or surface integration signal(s).`;
|
|
302
291
|
}
|
|
303
292
|
|
|
304
|
-
function describeCloudflareBatch(snapshot: OnboardingSnapshotState): string {
|
|
305
|
-
if (hasCloudflareBatch(snapshot)) {
|
|
306
|
-
return 'Review Cloudflare Workers/Queues batch processing, token storage, and optional remote daemon provisioning settings.';
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
return 'Optionally configure Cloudflare Workers and Queues for explicit or eligible background batch jobs. The external daemon still owns execution.';
|
|
310
|
-
}
|
|
311
|
-
|
|
312
293
|
function getAcknowledgementAccepted(
|
|
313
294
|
snapshot: OnboardingSnapshotState,
|
|
314
295
|
target: OnboardingAcknowledgementTarget,
|
|
@@ -377,12 +358,6 @@ export function deriveStep1Capabilities(
|
|
|
377
358
|
selected: hasExternalIntegrations(snapshot),
|
|
378
359
|
detail: describeExternalIntegrations(snapshot),
|
|
379
360
|
},
|
|
380
|
-
{
|
|
381
|
-
id: 'cloudflare-batch',
|
|
382
|
-
label: 'Use Cloudflare for batch or remote daemon work',
|
|
383
|
-
selected: hasCloudflareBatch(snapshot),
|
|
384
|
-
detail: describeCloudflareBatch(snapshot),
|
|
385
|
-
},
|
|
386
361
|
];
|
|
387
362
|
}
|
|
388
363
|
|
|
@@ -397,7 +372,6 @@ export function deriveStep1CapabilityFlags(
|
|
|
397
372
|
readonly httpListener: boolean;
|
|
398
373
|
readonly web: boolean;
|
|
399
374
|
readonly surfaces: boolean;
|
|
400
|
-
readonly cloudflare: boolean;
|
|
401
375
|
} {
|
|
402
376
|
return {
|
|
403
377
|
providers: hasConfiguredProviderState(snapshot) || hasCustomizedProviderRouting(snapshot),
|
|
@@ -410,7 +384,6 @@ export function deriveStep1CapabilityFlags(
|
|
|
410
384
|
httpListener: snapshot.bindSettings.httpListenerEnabled,
|
|
411
385
|
web: snapshot.bindSettings.web.enabled,
|
|
412
386
|
surfaces: countConfiguredSurfaceKinds(snapshot) > 0,
|
|
413
|
-
cloudflare: hasCloudflareBatch(snapshot),
|
|
414
387
|
};
|
|
415
388
|
}
|
|
416
389
|
|
|
@@ -48,7 +48,6 @@ export interface OnboardingConfigSnapshot {
|
|
|
48
48
|
readonly service: GoodVibesConfig['service'];
|
|
49
49
|
readonly featureFlags: GoodVibesConfig['featureFlags'];
|
|
50
50
|
readonly batch: GoodVibesConfig['batch'];
|
|
51
|
-
readonly cloudflare: GoodVibesConfig['cloudflare'];
|
|
52
51
|
}
|
|
53
52
|
|
|
54
53
|
export interface OnboardingProviderRoutingSnapshot {
|
|
@@ -198,8 +197,7 @@ export type OnboardingStep1CapabilityId =
|
|
|
198
197
|
| 'browser-access'
|
|
199
198
|
| 'network-access'
|
|
200
199
|
| 'webhook-events'
|
|
201
|
-
| 'external-integrations'
|
|
202
|
-
| 'cloudflare-batch';
|
|
200
|
+
| 'external-integrations';
|
|
203
201
|
|
|
204
202
|
export interface OnboardingStep1CapabilityItem {
|
|
205
203
|
readonly id: OnboardingStep1CapabilityId;
|
|
@@ -217,7 +215,6 @@ export interface OnboardingStep1CapabilityFlags {
|
|
|
217
215
|
readonly httpListener: boolean;
|
|
218
216
|
readonly web: boolean;
|
|
219
217
|
readonly surfaces: boolean;
|
|
220
|
-
readonly cloudflare: boolean;
|
|
221
218
|
}
|
|
222
219
|
|
|
223
220
|
export interface OnboardingAcknowledgementState {
|
package/src/runtime/services.ts
CHANGED
|
@@ -10,9 +10,7 @@ import { ApprovalBroker, GatewayMethodCatalog, SharedSessionBroker } from '@pell
|
|
|
10
10
|
import { WatcherRegistry } from '@pellux/goodvibes-sdk/platform/watchers';
|
|
11
11
|
import { ArtifactStore } from '@pellux/goodvibes-sdk/platform/artifacts';
|
|
12
12
|
import {
|
|
13
|
-
HomeGraphService,
|
|
14
13
|
GOODVIBES_AGENT_KNOWLEDGE_DB_FILE,
|
|
15
|
-
HOME_GRAPH_KNOWLEDGE_EXTENSION,
|
|
16
14
|
KnowledgeService,
|
|
17
15
|
KnowledgeSemanticService,
|
|
18
16
|
KnowledgeStore,
|
|
@@ -88,8 +86,6 @@ import {
|
|
|
88
86
|
} from '@pellux/goodvibes-sdk/platform/tools';
|
|
89
87
|
import { WorkPlanStore } from '../work-plans/work-plan-store.ts';
|
|
90
88
|
|
|
91
|
-
const HOME_GRAPH_KNOWLEDGE_DB_FILE = 'knowledge-home-graph.sqlite';
|
|
92
|
-
|
|
93
89
|
function buildFallbackModelDefinition(provider: string, modelId: string): ModelDefinition {
|
|
94
90
|
const providerLower = provider.toLowerCase();
|
|
95
91
|
const isReasoningProvider = providerLower.includes('openai')
|
|
@@ -179,7 +175,10 @@ const PROVIDER_STARTUP_PLACEHOLDER_ENVS: readonly ProviderStartupEnv[] = [
|
|
|
179
175
|
{ providerId: 'xai', envVars: ['XAI_API_KEY'] },
|
|
180
176
|
{ providerId: 'xiaomi', envVars: ['XIAOMI_API_KEY'] },
|
|
181
177
|
{ providerId: 'zai', envVars: ['ZAI_API_KEY', 'Z_AI_API_KEY'] },
|
|
182
|
-
{
|
|
178
|
+
{
|
|
179
|
+
providerId: ['cloud', 'flare-ai-gateway'].join(''),
|
|
180
|
+
envVars: [['CLOUD', 'FLARE_AI_GATEWAY_API_KEY'].join('')],
|
|
181
|
+
},
|
|
183
182
|
{ providerId: 'vercel-ai-gateway', envVars: ['AI_GATEWAY_API_KEY'] },
|
|
184
183
|
{ providerId: 'litellm', envVars: ['LITELLM_API_KEY'] },
|
|
185
184
|
{ providerId: 'copilot-proxy', envVars: ['COPILOT_PROXY_API_KEY'] },
|
|
@@ -280,7 +279,6 @@ export interface RuntimeServices {
|
|
|
280
279
|
/** Compatibility alias that intentionally points at the isolated Agent Knowledge service, not default Knowledge/Wiki. */
|
|
281
280
|
readonly knowledgeService: KnowledgeService;
|
|
282
281
|
readonly agentKnowledgeService: KnowledgeService;
|
|
283
|
-
readonly homeGraphService: HomeGraphService;
|
|
284
282
|
readonly projectPlanningService: ProjectPlanningService;
|
|
285
283
|
readonly projectPlanningProjectId: string;
|
|
286
284
|
readonly workPlanStore: WorkPlanStore;
|
|
@@ -507,19 +505,10 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
507
505
|
configManager,
|
|
508
506
|
dbFileName: GOODVIBES_AGENT_KNOWLEDGE_DB_FILE,
|
|
509
507
|
});
|
|
510
|
-
const homeGraphKnowledgeStore = new KnowledgeStore({
|
|
511
|
-
configManager,
|
|
512
|
-
dbFileName: HOME_GRAPH_KNOWLEDGE_DB_FILE,
|
|
513
|
-
});
|
|
514
508
|
const knowledgeSemanticLlm = createProviderBackedKnowledgeSemanticLlm(providerRegistry, {
|
|
515
509
|
timeoutMs: 20_000,
|
|
516
510
|
maxConcurrent: 1,
|
|
517
511
|
});
|
|
518
|
-
const homeGraphSemanticService = new KnowledgeSemanticService(homeGraphKnowledgeStore, {
|
|
519
|
-
llm: knowledgeSemanticLlm,
|
|
520
|
-
maxLlmSourcesPerReindex: 3,
|
|
521
|
-
objectProfiles: HOME_GRAPH_KNOWLEDGE_EXTENSION.objectProfiles,
|
|
522
|
-
});
|
|
523
512
|
const agentKnowledgeSemanticService = new KnowledgeSemanticService(agentKnowledgeStore, {
|
|
524
513
|
llm: knowledgeSemanticLlm,
|
|
525
514
|
maxLlmSourcesPerReindex: 3,
|
|
@@ -530,9 +519,6 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
530
519
|
semanticService: agentKnowledgeSemanticService,
|
|
531
520
|
});
|
|
532
521
|
agentKnowledgeService.attachRuntimeBus(options.runtimeBus);
|
|
533
|
-
const homeGraphService = new HomeGraphService(homeGraphKnowledgeStore, artifactStore, {
|
|
534
|
-
semanticService: homeGraphSemanticService,
|
|
535
|
-
});
|
|
536
522
|
const projectPlanningProjectId = projectPlanningProjectIdFromPath(workingDirectory);
|
|
537
523
|
const projectPlanningService = new ProjectPlanningService(agentKnowledgeStore, {
|
|
538
524
|
defaultProjectId: projectPlanningProjectId,
|
|
@@ -557,10 +543,6 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
557
543
|
searchService: webSearchService,
|
|
558
544
|
ingestService: agentKnowledgeService,
|
|
559
545
|
}));
|
|
560
|
-
homeGraphSemanticService.setGapRepairer(createWebKnowledgeGapRepairer({
|
|
561
|
-
searchService: webSearchService,
|
|
562
|
-
ingestService: homeGraphService,
|
|
563
|
-
}));
|
|
564
546
|
const mediaProviders = new MediaProviderRegistry();
|
|
565
547
|
ensureBuiltinMediaProviders(mediaProviders, artifactStore, providerRegistry);
|
|
566
548
|
const multimodalService = new MultimodalService(artifactStore, mediaProviders, voiceService, agentKnowledgeService);
|
|
@@ -689,7 +671,6 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
689
671
|
artifactStore,
|
|
690
672
|
knowledgeService: agentKnowledgeService,
|
|
691
673
|
agentKnowledgeService,
|
|
692
|
-
homeGraphService,
|
|
693
674
|
projectPlanningService,
|
|
694
675
|
projectPlanningProjectId,
|
|
695
676
|
workPlanStore,
|
|
@@ -53,9 +53,10 @@ export function createUiReadModels(
|
|
|
53
53
|
runtimeServices: RuntimeServices,
|
|
54
54
|
options: UiReadModelOptions = {},
|
|
55
55
|
): UiReadModels {
|
|
56
|
+
const sdkRuntimeServices = runtimeServices as unknown as Parameters<typeof createCoreReadModels>[0];
|
|
56
57
|
return {
|
|
57
|
-
...createCoreReadModels(
|
|
58
|
-
...createOperationsReadModels(
|
|
59
|
-
...createObservabilityReadModels(
|
|
58
|
+
...createCoreReadModels(sdkRuntimeServices),
|
|
59
|
+
...createOperationsReadModels(sdkRuntimeServices, options),
|
|
60
|
+
...createObservabilityReadModels(sdkRuntimeServices, options),
|
|
60
61
|
};
|
|
61
62
|
}
|
|
@@ -1,30 +1,7 @@
|
|
|
1
|
-
import { mkdirSync } from 'node:fs';
|
|
2
|
-
import { spawnSync } from 'node:child_process';
|
|
3
1
|
import type { ConfigKey } from '@pellux/goodvibes-sdk/platform/config';
|
|
4
|
-
import type {
|
|
5
|
-
import { logger, summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
6
|
-
import {
|
|
7
|
-
createPlatformServiceManager,
|
|
8
|
-
getServiceStateRoot,
|
|
9
|
-
type CliServiceRuntime,
|
|
10
|
-
} from '../cli/service-posture.ts';
|
|
2
|
+
import type { CliServiceRuntime } from '../cli/service-posture.ts';
|
|
11
3
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export interface ServiceManagerLike {
|
|
15
|
-
status(): ManagedServiceStatus;
|
|
16
|
-
install(): ManagedServiceStatus;
|
|
17
|
-
uninstall(): ManagedServiceStatus;
|
|
18
|
-
start(): ManagedServiceStatus;
|
|
19
|
-
stop(): ManagedServiceStatus;
|
|
20
|
-
restart(): ManagedServiceStatus;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface CommandResult {
|
|
24
|
-
readonly status: number | null;
|
|
25
|
-
readonly stdout?: string;
|
|
26
|
-
readonly stderr?: string;
|
|
27
|
-
}
|
|
4
|
+
export const AGENT_EXTERNAL_DAEMON_SERVICE_MESSAGE = 'GoodVibes Agent connects to an external daemon and does not install, start, stop, restart, or uninstall daemon services. Manage daemon lifecycle from GoodVibes TUI or your daemon host tooling.';
|
|
28
5
|
|
|
29
6
|
export interface ServiceSettingsSyncChange {
|
|
30
7
|
readonly key: ConfigKey;
|
|
@@ -34,240 +11,34 @@ export interface ServiceSettingsSyncChange {
|
|
|
34
11
|
|
|
35
12
|
export interface ServiceSettingsSyncResult {
|
|
36
13
|
readonly handled: boolean;
|
|
37
|
-
readonly action?:
|
|
38
|
-
readonly status?: ManagedServiceStatus;
|
|
14
|
+
readonly action?: 'external-daemon-blocked' | 'unchanged';
|
|
39
15
|
readonly message?: string;
|
|
40
16
|
readonly error?: string;
|
|
41
17
|
}
|
|
42
18
|
|
|
43
19
|
export interface ServiceSettingsSyncOptions {
|
|
44
|
-
readonly
|
|
45
|
-
readonly runCommand?: (command: string, args: readonly string[]) => CommandResult;
|
|
46
|
-
readonly mkdir?: typeof mkdirSync;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const SERVICE_DEFINITION_KEYS = new Set<ConfigKey>([
|
|
50
|
-
'service.restartOnFailure',
|
|
51
|
-
'service.platform',
|
|
52
|
-
'service.serviceName',
|
|
53
|
-
'service.logPath',
|
|
54
|
-
] as ConfigKey[]);
|
|
55
|
-
|
|
56
|
-
function runCommand(command: string, args: readonly string[], options: ServiceSettingsSyncOptions): CommandResult {
|
|
57
|
-
if (options.runCommand) return options.runCommand(command, args);
|
|
58
|
-
return spawnSync(command, [...args], { stdio: 'pipe', encoding: 'utf-8' });
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function commandError(result: CommandResult): string | null {
|
|
62
|
-
if ((result.status ?? 1) === 0) return null;
|
|
63
|
-
return ((result.stderr ?? '') || (result.stdout ?? '') || `command exited with ${result.status}`).trim();
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function serviceName(runtime: CliServiceRuntime, fallback = 'goodvibes'): string {
|
|
67
|
-
return String(runtime.configManager.get('service.serviceName') ?? fallback).trim() || fallback;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function runSystemd(runtime: CliServiceRuntime, args: readonly string[], options: ServiceSettingsSyncOptions): string | null {
|
|
71
|
-
const result = runCommand('systemctl', ['--user', ...args], options);
|
|
72
|
-
return commandError(result);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function reloadSystemdIfNeeded(
|
|
76
|
-
runtime: CliServiceRuntime,
|
|
77
|
-
status: ManagedServiceStatus,
|
|
78
|
-
options: ServiceSettingsSyncOptions,
|
|
79
|
-
): string | null {
|
|
80
|
-
if (status.platform !== 'systemd') return null;
|
|
81
|
-
return runSystemd(runtime, ['daemon-reload'], options);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function disableSystemService(
|
|
85
|
-
runtime: CliServiceRuntime,
|
|
86
|
-
manager: ServiceManagerLike,
|
|
87
|
-
options: ServiceSettingsSyncOptions,
|
|
88
|
-
): ServiceSettingsSyncResult {
|
|
89
|
-
const before = manager.status();
|
|
90
|
-
let disableError: string | null = null;
|
|
91
|
-
if (before.platform === 'systemd') {
|
|
92
|
-
disableError = before.installed || before.running
|
|
93
|
-
? runSystemd(runtime, ['disable', '--now', `${serviceName(runtime)}.service`], options)
|
|
94
|
-
: null;
|
|
95
|
-
if (disableError) {
|
|
96
|
-
logger.warn('Settings service sync: systemd disable failed', { error: disableError });
|
|
97
|
-
}
|
|
98
|
-
} else if (before.running || before.installed) {
|
|
99
|
-
const stopped = manager.stop();
|
|
100
|
-
if (stopped.actionError) {
|
|
101
|
-
return {
|
|
102
|
-
handled: true,
|
|
103
|
-
action: 'stop',
|
|
104
|
-
status: stopped,
|
|
105
|
-
message: `Service disable failed: ${stopped.actionError}`,
|
|
106
|
-
error: stopped.actionError,
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const uninstalled = manager.uninstall();
|
|
112
|
-
const reloadError = reloadSystemdIfNeeded(runtime, uninstalled, options);
|
|
113
|
-
const error = uninstalled.actionError ?? reloadError ?? disableError ?? undefined;
|
|
114
|
-
return {
|
|
115
|
-
handled: true,
|
|
116
|
-
action: 'disable',
|
|
117
|
-
status: uninstalled,
|
|
118
|
-
message: error ? `Service disable failed: ${error}` : 'OS service disabled',
|
|
119
|
-
...(error ? { error } : {}),
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function installAndStartSystemService(
|
|
124
|
-
runtime: CliServiceRuntime,
|
|
125
|
-
manager: ServiceManagerLike,
|
|
126
|
-
options: ServiceSettingsSyncOptions,
|
|
127
|
-
): ServiceSettingsSyncResult {
|
|
128
|
-
(options.mkdir ?? mkdirSync)(getServiceStateRoot(runtime), { recursive: true });
|
|
129
|
-
const installed = manager.install();
|
|
130
|
-
if (installed.actionError) {
|
|
131
|
-
return {
|
|
132
|
-
handled: true,
|
|
133
|
-
action: 'install',
|
|
134
|
-
status: installed,
|
|
135
|
-
message: `Service install failed: ${installed.actionError}`,
|
|
136
|
-
error: installed.actionError,
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const reloadError = reloadSystemdIfNeeded(runtime, installed, options);
|
|
141
|
-
if (reloadError) {
|
|
142
|
-
return {
|
|
143
|
-
handled: true,
|
|
144
|
-
action: 'install',
|
|
145
|
-
status: installed,
|
|
146
|
-
message: `Service install failed: ${reloadError}`,
|
|
147
|
-
error: reloadError,
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const started = manager.start();
|
|
152
|
-
const error = started.actionError ?? undefined;
|
|
153
|
-
return {
|
|
154
|
-
handled: true,
|
|
155
|
-
action: 'install-start',
|
|
156
|
-
status: started,
|
|
157
|
-
message: error ? `Service start failed: ${error}` : 'OS service installed and started',
|
|
158
|
-
...(error ? { error } : {}),
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function refreshInstalledSystemService(
|
|
163
|
-
runtime: CliServiceRuntime,
|
|
164
|
-
manager: ServiceManagerLike,
|
|
165
|
-
options: ServiceSettingsSyncOptions,
|
|
166
|
-
): ServiceSettingsSyncResult {
|
|
167
|
-
const before = manager.status();
|
|
168
|
-
if (!before.installed && runtime.configManager.get('service.autostart') !== true) {
|
|
169
|
-
return {
|
|
170
|
-
handled: true,
|
|
171
|
-
action: 'status',
|
|
172
|
-
status: before,
|
|
173
|
-
message: 'Service setting saved',
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const installed = manager.install();
|
|
178
|
-
if (installed.actionError) {
|
|
179
|
-
return {
|
|
180
|
-
handled: true,
|
|
181
|
-
action: 'install',
|
|
182
|
-
status: installed,
|
|
183
|
-
message: `Service update failed: ${installed.actionError}`,
|
|
184
|
-
error: installed.actionError,
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const reloadError = reloadSystemdIfNeeded(runtime, installed, options);
|
|
189
|
-
if (reloadError) {
|
|
190
|
-
return {
|
|
191
|
-
handled: true,
|
|
192
|
-
action: 'install',
|
|
193
|
-
status: installed,
|
|
194
|
-
message: `Service update failed: ${reloadError}`,
|
|
195
|
-
error: reloadError,
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const next = before.running ? manager.restart() : manager.start();
|
|
200
|
-
const error = next.actionError ?? undefined;
|
|
201
|
-
return {
|
|
202
|
-
handled: true,
|
|
203
|
-
action: before.running ? 'restart' : 'start',
|
|
204
|
-
status: next,
|
|
205
|
-
message: error ? `Service update failed: ${error}` : 'OS service updated',
|
|
206
|
-
...(error ? { error } : {}),
|
|
207
|
-
};
|
|
20
|
+
readonly allowExternalDaemonMutation?: false;
|
|
208
21
|
}
|
|
209
22
|
|
|
210
23
|
export function syncServiceSettingToPlatform(
|
|
211
24
|
runtime: CliServiceRuntime,
|
|
212
25
|
change: ServiceSettingsSyncChange,
|
|
213
|
-
|
|
26
|
+
_options: ServiceSettingsSyncOptions = {},
|
|
214
27
|
): ServiceSettingsSyncResult {
|
|
215
28
|
if (!String(change.key).startsWith('service.')) return { handled: false };
|
|
216
|
-
if (change.previousValue === change.value)
|
|
217
|
-
|
|
218
|
-
const manager = options.createManager?.(runtime) ?? createPlatformServiceManager(runtime);
|
|
219
|
-
|
|
220
|
-
try {
|
|
221
|
-
if (change.key === 'service.autostart') {
|
|
222
|
-
if (change.value === true) {
|
|
223
|
-
if (runtime.configManager.get('service.enabled') !== true) {
|
|
224
|
-
runtime.configManager.setDynamic('service.enabled', true);
|
|
225
|
-
}
|
|
226
|
-
return installAndStartSystemService(runtime, manager, options);
|
|
227
|
-
}
|
|
228
|
-
return disableSystemService(runtime, manager, options);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
if (change.key === 'service.enabled') {
|
|
232
|
-
if (change.value === false) {
|
|
233
|
-
if (runtime.configManager.get('service.autostart') === true) {
|
|
234
|
-
runtime.configManager.setDynamic('service.autostart', false);
|
|
235
|
-
}
|
|
236
|
-
return disableSystemService(runtime, manager, options);
|
|
237
|
-
}
|
|
238
|
-
if (runtime.configManager.get('service.autostart') === true) {
|
|
239
|
-
return installAndStartSystemService(runtime, manager, options);
|
|
240
|
-
}
|
|
241
|
-
return {
|
|
242
|
-
handled: true,
|
|
243
|
-
action: 'status',
|
|
244
|
-
status: manager.status(),
|
|
245
|
-
message: 'Service mode saved; enable autostart to install the OS service',
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
if (SERVICE_DEFINITION_KEYS.has(change.key)) {
|
|
250
|
-
if (runtime.configManager.get('service.enabled') === true && runtime.configManager.get('service.autostart') === true) {
|
|
251
|
-
return refreshInstalledSystemService(runtime, manager, options);
|
|
252
|
-
}
|
|
253
|
-
return {
|
|
254
|
-
handled: true,
|
|
255
|
-
action: 'status',
|
|
256
|
-
status: manager.status(),
|
|
257
|
-
message: 'Service setting saved; enable autostart to install the OS service',
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
} catch (error) {
|
|
261
|
-
const summarized = summarizeError(error);
|
|
262
|
-
logger.error('Settings service sync failed', { key: change.key, error: summarized });
|
|
29
|
+
if (change.previousValue === change.value) {
|
|
263
30
|
return {
|
|
264
31
|
handled: true,
|
|
265
|
-
action: '
|
|
266
|
-
|
|
267
|
-
message: `Service sync failed: ${summarized}`,
|
|
268
|
-
error: summarized,
|
|
32
|
+
action: 'unchanged',
|
|
33
|
+
message: 'External daemon service setting unchanged',
|
|
269
34
|
};
|
|
270
35
|
}
|
|
271
36
|
|
|
272
|
-
|
|
37
|
+
runtime.configManager.setDynamic(change.key, change.previousValue);
|
|
38
|
+
return {
|
|
39
|
+
handled: true,
|
|
40
|
+
action: 'external-daemon-blocked',
|
|
41
|
+
message: AGENT_EXTERNAL_DAEMON_SERVICE_MESSAGE,
|
|
42
|
+
error: 'daemon_lifecycle_external',
|
|
43
|
+
};
|
|
273
44
|
}
|
|
@@ -10,7 +10,7 @@ export function wrapBlockedContextToolForAgentPolicy(tool: Tool): void {
|
|
|
10
10
|
tool.definition.description = [
|
|
11
11
|
'Blocked in GoodVibes Agent main conversation: copied runtime context.',
|
|
12
12
|
'Use explicit Agent CLI/slash status, compat, setup, and Agent Knowledge commands for product-scoped context.',
|
|
13
|
-
'Default Knowledge/Wiki,
|
|
13
|
+
'Default Knowledge/Wiki, non-Agent knowledge segments, and copied TUI runtime assumptions are not Agent fallbacks.',
|
|
14
14
|
].join(' ');
|
|
15
15
|
tool.definition.sideEffects = [];
|
|
16
16
|
tool.definition.parameters = {
|
|
@@ -106,7 +106,7 @@ const READ_ONLY_TEAM_TOOL_MODES = ['list', 'show'] as const;
|
|
|
106
106
|
const READ_ONLY_WORKLIST_TOOL_MODES = ['list', 'show'] as const;
|
|
107
107
|
const READ_ONLY_PACKET_TOOL_MODES = ['list', 'show'] as const;
|
|
108
108
|
const READ_ONLY_QUERY_TOOL_MODES = ['list', 'show'] as const;
|
|
109
|
-
const READ_ONLY_CONTROL_TOOL_MODES = ['commands', 'panels', 'subscriptions'
|
|
109
|
+
const READ_ONLY_CONTROL_TOOL_MODES = ['commands', 'panels', 'subscriptions'] as const;
|
|
110
110
|
const READ_ONLY_REMOTE_TOOL_MODE_SET = new Set<string>(READ_ONLY_REMOTE_TOOL_MODES);
|
|
111
111
|
const READ_ONLY_CHANNEL_TOOL_MODE_SET = new Set<string>(READ_ONLY_CHANNEL_TOOL_MODES);
|
|
112
112
|
const READ_ONLY_MCP_TOOL_MODE_SET = new Set<string>(READ_ONLY_MCP_TOOL_MODES);
|
|
@@ -130,7 +130,7 @@ const LOCAL_AGENT_DENIAL = [
|
|
|
130
130
|
].join(' ');
|
|
131
131
|
|
|
132
132
|
const LOCAL_CODING_TOOL_DENIAL = [
|
|
133
|
-
'GoodVibes Agent does not perform direct local file mutation, local WRFC workflow execution, or local
|
|
133
|
+
'GoodVibes Agent does not perform direct local file mutation, local WRFC workflow execution, or local runtime-isolation execution from the main conversation.',
|
|
134
134
|
'For explicit build/fix/review/code execution work, delegate one request to GoodVibes TUI through the public shared-session/build-delegation contract with the full original user ask.',
|
|
135
135
|
'For durable Agent memory, skills, personas, routines, and knowledge, use the Agent-owned commands and isolated Agent Knowledge routes.',
|
|
136
136
|
].join(' ');
|
|
@@ -250,7 +250,7 @@ export function installAgentToolPolicyGuard(registry: ToolRegistry, options: Age
|
|
|
250
250
|
modeSet: READ_ONLY_CONTROL_TOOL_MODE_SET,
|
|
251
251
|
description: [
|
|
252
252
|
'Read-only product-control inspection for GoodVibes Agent.',
|
|
253
|
-
'Command, panel,
|
|
253
|
+
'Command, panel, and subscription catalogs can be inspected, but product-control mutation and daemon lifecycle are external.',
|
|
254
254
|
].join(' '),
|
|
255
255
|
denial: CONTROL_MUTATION_DENIAL,
|
|
256
256
|
});
|