@pellux/goodvibes-agent 0.1.114 → 0.1.117
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 +41 -650
- package/README.md +40 -50
- package/dist/package/main.js +38224 -35673
- package/docs/README.md +5 -4
- package/docs/{connected-services.md → connected-host.md} +18 -10
- package/docs/getting-started.md +43 -42
- package/docs/release-and-publishing.md +6 -4
- package/package.json +3 -3
- package/src/agent/behavior-discovery-summary.ts +165 -0
- package/src/agent/persona-discovery.ts +1 -3
- package/src/agent/persona-registry.ts +5 -3
- package/src/agent/reminder-schedule-format.ts +6 -6
- package/src/agent/reminder-schedule.ts +1 -1
- package/src/agent/routine-registry.ts +43 -4
- package/src/agent/routine-schedule-format.ts +6 -6
- package/src/agent/routine-schedule-promotion.ts +1 -1
- package/src/agent/routine-schedule-receipts.ts +1 -1
- package/src/agent/runtime-profile-starters.ts +331 -0
- package/src/agent/runtime-profile.ts +228 -330
- package/src/agent/skill-registry.ts +190 -13
- package/src/cli/agent-knowledge-command.ts +2 -2
- package/src/cli/agent-knowledge-format.ts +2 -2
- package/src/cli/agent-knowledge-runtime.ts +1 -1
- package/src/cli/bundle-command.ts +1 -1
- package/src/cli/entrypoint.ts +16 -7
- package/src/cli/help.ts +26 -19
- package/src/cli/local-library-command.ts +75 -21
- package/src/cli/management-commands.ts +7 -6
- package/src/cli/management.ts +6 -51
- package/src/cli/parser.ts +23 -2
- package/src/cli/profiles-command.ts +247 -1
- package/src/cli/routines-command.ts +139 -11
- package/src/cli/service-posture.ts +11 -11
- package/src/cli/status.ts +21 -25
- 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 +2 -1
- package/src/input/agent-workspace-basic-command-editor-submission.ts +787 -0
- package/src/input/agent-workspace-basic-command-editors.ts +524 -459
- package/src/input/agent-workspace-categories.ts +177 -14
- package/src/input/agent-workspace-channel-command-editor-submission.ts +49 -0
- package/src/input/agent-workspace-channel-command-editors.ts +47 -0
- package/src/input/agent-workspace-command-editor.ts +25 -1
- package/src/input/agent-workspace-delegation-editor-submission.ts +55 -0
- package/src/input/agent-workspace-editors.ts +27 -0
- 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-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-mcp-command-editor-submission.ts +95 -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-navigation.ts +45 -0
- package/src/input/agent-workspace-notify-editor-submission.ts +107 -0
- package/src/input/agent-workspace-operations-command-editor-submission.ts +146 -0
- package/src/input/agent-workspace-operations-command-editors.ts +119 -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-requirements.ts +11 -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 +49 -19
- 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 +56 -8
- 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-types.ts +124 -0
- package/src/input/agent-workspace-voice-media.ts +1 -1
- package/src/input/agent-workspace-workplan-editor-submission.ts +153 -0
- package/src/input/agent-workspace.ts +47 -37
- package/src/input/command-registry.ts +1 -1
- package/src/input/commands/agent-runtime-profile-runtime.ts +160 -6
- package/src/input/commands/agent-skills-runtime.ts +76 -12
- package/src/input/commands/agent-workspace-runtime.ts +4 -3
- package/src/input/commands/brief-runtime.ts +38 -9
- package/src/input/commands/channels-runtime.ts +3 -3
- package/src/input/commands/compat-runtime.ts +32 -0
- package/src/input/commands/health-runtime.ts +22 -24
- package/src/input/commands/knowledge.ts +26 -5
- package/src/input/commands/local-provider-runtime.ts +7 -3
- package/src/input/commands/local-setup-review.ts +4 -14
- package/src/input/commands/mcp-runtime.ts +8 -12
- package/src/input/commands/operator-runtime.ts +8 -67
- package/src/input/commands/personas-runtime.ts +1 -1
- package/src/input/commands/platform-access-runtime.ts +7 -70
- package/src/input/commands/policy-dispatch.ts +1 -1
- package/src/input/commands/policy.ts +1 -5
- package/src/input/commands/product-runtime.ts +2 -2
- package/src/input/commands/qrcode-runtime.ts +6 -4
- package/src/input/commands/routines-runtime.ts +44 -6
- package/src/input/commands/runtime-services.ts +1 -14
- package/src/input/commands/security-runtime.ts +3 -8
- package/src/input/commands/session-content.ts +1 -1
- package/src/input/commands/session-workflow.ts +5 -14
- package/src/input/commands/shell-core.ts +8 -2
- package/src/input/commands/subscription-runtime.ts +1 -6
- package/src/input/commands/support-bundle-runtime.ts +53 -0
- package/src/input/commands/tasks-runtime.ts +2 -2
- package/src/input/commands.ts +4 -0
- package/src/input/feed-context-factory.ts +0 -1
- package/src/input/handler-content-actions.ts +0 -25
- package/src/input/handler-feed.ts +0 -2
- package/src/input/handler-interactions.ts +2 -31
- package/src/input/handler-onboarding.ts +29 -12
- package/src/input/handler-shortcuts.ts +1 -3
- package/src/input/handler.ts +4 -7
- package/src/input/keybindings.ts +9 -9
- 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 +49 -0
- package/src/input/onboarding/onboarding-wizard-helpers.ts +1 -1
- package/src/input/onboarding/onboarding-wizard-operator-steps.ts +126 -11
- package/src/input/onboarding/onboarding-wizard-steps.ts +15 -8
- package/src/input/onboarding/onboarding-wizard-types.ts +1 -0
- package/src/input/onboarding/onboarding-wizard.ts +19 -2
- package/src/input/profile-picker-modal.ts +2 -2
- package/src/input/settings-modal-agent-policy.ts +6 -6
- package/src/input/settings-modal-subscriptions.ts +3 -3
- package/src/input/settings-modal.ts +14 -14
- package/src/main.ts +0 -2
- package/src/panels/automation-control-panel.ts +3 -3
- package/src/panels/builtin/agent.ts +1 -1
- package/src/panels/builtin/operations.ts +2 -2
- package/src/panels/builtin/session.ts +26 -18
- package/src/panels/builtin/shared.ts +6 -6
- package/src/panels/project-planning-panel.ts +1 -1
- package/src/panels/provider-health-domains.ts +3 -3
- package/src/panels/qr-panel.ts +44 -20
- package/src/panels/subscription-panel.ts +3 -3
- package/src/panels/system-messages-panel.ts +2 -2
- package/src/panels/tasks-panel.ts +4 -4
- package/src/planning/project-planning-coordinator.ts +2 -2
- package/src/renderer/agent-workspace.ts +52 -5
- package/src/renderer/block-actions.ts +1 -3
- package/src/renderer/help-overlay.ts +13 -8
- package/src/renderer/mcp-workspace.ts +32 -13
- package/src/renderer/model-picker-overlay.ts +0 -1
- package/src/renderer/model-workspace.ts +0 -2
- package/src/renderer/onboarding/onboarding-wizard.ts +20 -4
- package/src/renderer/panel-picker-overlay.ts +1 -1
- package/src/renderer/profile-picker-modal.ts +2 -2
- package/src/renderer/settings-modal-helpers.ts +23 -23
- package/src/renderer/settings-modal.ts +18 -18
- package/src/renderer/system-message.ts +1 -1
- package/src/runtime/agent-runtime-events.ts +129 -0
- package/src/runtime/bootstrap-command-parts.ts +3 -2
- package/src/runtime/bootstrap-core.ts +4 -64
- package/src/runtime/bootstrap-shell.ts +42 -4
- package/src/runtime/bootstrap.ts +8 -27
- package/src/runtime/connected-host-auth.ts +42 -0
- package/src/runtime/diagnostics/panels/panel-resources.ts +1 -1
- package/src/runtime/index.ts +1 -5
- package/src/runtime/onboarding/apply.ts +213 -0
- package/src/runtime/onboarding/derivation.ts +25 -6
- package/src/runtime/onboarding/snapshot.ts +4 -2
- package/src/runtime/onboarding/types.ts +28 -1
- package/src/runtime/onboarding/verify.ts +81 -2
- package/src/runtime/operator-token-cleanup.ts +2 -2
- package/src/runtime/services.ts +27 -12
- package/src/shell/service-settings-sync.ts +7 -7
- package/src/shell/ui-openers.ts +27 -38
- package/src/tools/agent-local-registry-tool.ts +10 -4
- package/src/tools/agent-tool-policy-guard.ts +5 -7
- package/src/version.ts +1 -1
- package/src/cli/package-verification.ts +0 -274
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
2
|
+
import type { ConversationFollowUpItem } from '@pellux/goodvibes-sdk/platform/core';
|
|
3
|
+
import type { AgentManager } from '@pellux/goodvibes-sdk/platform/tools';
|
|
4
|
+
import type {
|
|
5
|
+
AgentEvent,
|
|
6
|
+
ProviderEvent,
|
|
7
|
+
RuntimeEventBus,
|
|
8
|
+
} from '@/runtime/index.ts';
|
|
9
|
+
import type { createDomainDispatch } from './store/index.ts';
|
|
10
|
+
|
|
11
|
+
const AGENT_STATUS_INTERVAL_MS = 30_000;
|
|
12
|
+
|
|
13
|
+
export interface AgentRuntimeMessageRouter {
|
|
14
|
+
low(message: string): void;
|
|
15
|
+
high(message: string): void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface AgentRuntimeEventBridgeOptions {
|
|
19
|
+
readonly runtimeBus: RuntimeEventBus;
|
|
20
|
+
readonly domainDispatch: ReturnType<typeof createDomainDispatch>;
|
|
21
|
+
readonly getSystemMessageRouter: () => AgentRuntimeMessageRouter | null;
|
|
22
|
+
readonly queueConversationFollowUp?: (item: ConversationFollowUpItem) => void;
|
|
23
|
+
readonly requestRender: () => void;
|
|
24
|
+
readonly configManager: ConfigManager;
|
|
25
|
+
readonly agentManager: AgentManager;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function withRouter(
|
|
29
|
+
getSystemMessageRouter: () => AgentRuntimeMessageRouter | null,
|
|
30
|
+
action: (router: AgentRuntimeMessageRouter) => void,
|
|
31
|
+
): void {
|
|
32
|
+
const router = getSystemMessageRouter();
|
|
33
|
+
if (router) action(router);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function formatAgentTask(task: string): string {
|
|
37
|
+
return task.length > 50 ? `${task.slice(0, 50)}...` : task;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function registerAgentRuntimeEvents(options: AgentRuntimeEventBridgeOptions): {
|
|
41
|
+
unsubs: Array<() => void>;
|
|
42
|
+
agentStatusIntervalRef: { value: ReturnType<typeof setInterval> | null };
|
|
43
|
+
} {
|
|
44
|
+
const {
|
|
45
|
+
runtimeBus,
|
|
46
|
+
domainDispatch,
|
|
47
|
+
getSystemMessageRouter,
|
|
48
|
+
queueConversationFollowUp,
|
|
49
|
+
requestRender,
|
|
50
|
+
agentManager,
|
|
51
|
+
} = options;
|
|
52
|
+
const unsubs: Array<() => void> = [];
|
|
53
|
+
|
|
54
|
+
unsubs.push(runtimeBus.onDomain('turn', (env) => {
|
|
55
|
+
domainDispatch.dispatchTurnEvent(env.payload);
|
|
56
|
+
}));
|
|
57
|
+
unsubs.push(runtimeBus.onDomain('agents', (env) => {
|
|
58
|
+
domainDispatch.dispatchAgentEvent(env.payload);
|
|
59
|
+
}));
|
|
60
|
+
unsubs.push(runtimeBus.onDomain('orchestration', (env) => {
|
|
61
|
+
domainDispatch.dispatchOrchestrationEvent(env.payload);
|
|
62
|
+
}));
|
|
63
|
+
unsubs.push(runtimeBus.onDomain('communication', (env) => {
|
|
64
|
+
domainDispatch.dispatchCommunicationEvent(env.payload);
|
|
65
|
+
}));
|
|
66
|
+
unsubs.push(runtimeBus.onDomain('compaction', (env) => {
|
|
67
|
+
domainDispatch.dispatchCompactionEvent(env.payload);
|
|
68
|
+
}));
|
|
69
|
+
unsubs.push(runtimeBus.onDomain('transport', (env) => {
|
|
70
|
+
domainDispatch.dispatchTransportEvent(env.payload);
|
|
71
|
+
}));
|
|
72
|
+
|
|
73
|
+
unsubs.push(runtimeBus.on<Extract<ProviderEvent, { type: 'MODEL_FALLBACK' }>>('MODEL_FALLBACK', ({ payload }) => {
|
|
74
|
+
withRouter(getSystemMessageRouter, (router) => {
|
|
75
|
+
router.high(`[Model] ${payload.from} exhausted across all providers. Automatically falling back to ${payload.to} via ${payload.provider}.`);
|
|
76
|
+
});
|
|
77
|
+
requestRender();
|
|
78
|
+
}));
|
|
79
|
+
unsubs.push(runtimeBus.on<Extract<AgentEvent, { type: 'AGENT_STREAM_DELTA' }>>('AGENT_STREAM_DELTA', () => {
|
|
80
|
+
requestRender();
|
|
81
|
+
}));
|
|
82
|
+
unsubs.push(runtimeBus.on<Extract<AgentEvent, { type: 'AGENT_PROGRESS' }>>('AGENT_PROGRESS', () => {
|
|
83
|
+
requestRender();
|
|
84
|
+
}));
|
|
85
|
+
unsubs.push(runtimeBus.on<Extract<AgentEvent, { type: 'AGENT_COMPLETED' }>>('AGENT_COMPLETED', ({ payload }) => {
|
|
86
|
+
const record = agentManager.getStatus(payload.agentId);
|
|
87
|
+
if (record) {
|
|
88
|
+
const durationSeconds = record.completedAt !== undefined ? Math.round((record.completedAt - record.startedAt) / 1000) : 0;
|
|
89
|
+
const taskSnippet = formatAgentTask(record.task);
|
|
90
|
+
withRouter(getSystemMessageRouter, (router) => {
|
|
91
|
+
router.low(`[Agent task] ${record.template} ${payload.agentId.slice(-8)} completed in ${durationSeconds}s: "${taskSnippet}"`);
|
|
92
|
+
});
|
|
93
|
+
queueConversationFollowUp?.({
|
|
94
|
+
key: `agent:${payload.agentId}:completed`,
|
|
95
|
+
summary: `${record.template} agent ${payload.agentId.slice(-8)} completed "${taskSnippet}" in ${durationSeconds}s after ${record.toolCallCount} tool calls.`,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
requestRender();
|
|
99
|
+
}));
|
|
100
|
+
unsubs.push(runtimeBus.on<Extract<AgentEvent, { type: 'AGENT_FAILED' }>>('AGENT_FAILED', ({ payload }) => {
|
|
101
|
+
const record = agentManager.getStatus(payload.agentId);
|
|
102
|
+
if (record && record.status !== 'cancelled') {
|
|
103
|
+
const durationSeconds = record.completedAt !== undefined ? Math.round((record.completedAt - record.startedAt) / 1000) : 0;
|
|
104
|
+
const taskSnippet = formatAgentTask(record.task);
|
|
105
|
+
withRouter(getSystemMessageRouter, (router) => {
|
|
106
|
+
router.low(`[Agent task] ${record.template} ${payload.agentId.slice(-8)} failed in ${durationSeconds}s: ${payload.error.slice(0, 80)}`);
|
|
107
|
+
});
|
|
108
|
+
queueConversationFollowUp?.({
|
|
109
|
+
key: `agent:${payload.agentId}:failed`,
|
|
110
|
+
summary: `${record.template} agent ${payload.agentId.slice(-8)} failed while working on "${taskSnippet}": ${payload.error.slice(0, 120)}`,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
requestRender();
|
|
114
|
+
}));
|
|
115
|
+
|
|
116
|
+
const agentStatusIntervalRef = { value: null as ReturnType<typeof setInterval> | null };
|
|
117
|
+
agentStatusIntervalRef.value = setInterval(() => {
|
|
118
|
+
const running = agentManager.list().filter((agent) => agent.status === 'running');
|
|
119
|
+
if (running.length === 0) return;
|
|
120
|
+
const lines = running.map((agent) => ` ${agent.id.slice(-8)}: ${agent.progress ?? agent.status}`);
|
|
121
|
+
withRouter(getSystemMessageRouter, (router) => {
|
|
122
|
+
router.low(`[Agent task] ${running.length} running:\n${lines.join('\n')}`);
|
|
123
|
+
});
|
|
124
|
+
requestRender();
|
|
125
|
+
}, AGENT_STATUS_INTERVAL_MS);
|
|
126
|
+
agentStatusIntervalRef.value.unref?.();
|
|
127
|
+
|
|
128
|
+
return { unsubs, agentStatusIntervalRef };
|
|
129
|
+
}
|
|
@@ -171,8 +171,9 @@ export function createBootstrapCommandActions(
|
|
|
171
171
|
} = options;
|
|
172
172
|
|
|
173
173
|
const showPanel = (panelId: string, pane?: 'top' | 'bottom') => {
|
|
174
|
-
|
|
175
|
-
panelManager.
|
|
174
|
+
void pane;
|
|
175
|
+
panelManager.hide();
|
|
176
|
+
conversation.log(`Panel "${panelId}" is deferred in GoodVibes Agent. Use /agent for the operator workspace.`, { fg: '214' });
|
|
176
177
|
requestRender();
|
|
177
178
|
};
|
|
178
179
|
|
|
@@ -26,12 +26,12 @@ import {
|
|
|
26
26
|
} from '@/runtime/index.ts';
|
|
27
27
|
import { loadBootstrapSystemPrompt, syncConfiguredServices } from '@/runtime/index.ts';
|
|
28
28
|
import { registerBootstrapHookBridge } from '@/runtime/index.ts';
|
|
29
|
-
import { registerBootstrapRuntimeEvents } from '@/runtime/index.ts';
|
|
30
29
|
import { createRuntimeServices, type RuntimeServices } from './services.ts';
|
|
31
30
|
import { createUiRuntimeServices, type UiRuntimeServices } from './ui-services.ts';
|
|
32
31
|
import { installAgentToolPolicyGuard } from '../tools/agent-tool-policy-guard.ts';
|
|
33
32
|
import { registerAgentLocalRegistryTool } from '../tools/agent-local-registry-tool.ts';
|
|
34
33
|
import { GOODVIBES_AGENT_SURFACE_ROOT } from '../config/surface.ts';
|
|
34
|
+
import { registerAgentRuntimeEvents } from './agent-runtime-events.ts';
|
|
35
35
|
|
|
36
36
|
export interface BootstrapCoreState {
|
|
37
37
|
readonly userSessionId: string;
|
|
@@ -211,7 +211,6 @@ export async function initializeBootstrapCore(
|
|
|
211
211
|
agentManager: services.agentManager,
|
|
212
212
|
agentMessageBus: services.agentMessageBus,
|
|
213
213
|
archetypeLoader: services.archetypeLoader,
|
|
214
|
-
wrfcController: services.wrfcController,
|
|
215
214
|
webSearchService: services.webSearchService,
|
|
216
215
|
channelRegistry: services.channelPlugins,
|
|
217
216
|
remoteRunnerRegistry: services.remoteRunnerRegistry,
|
|
@@ -314,7 +313,7 @@ export async function initializeBootstrapCore(
|
|
|
314
313
|
const runtimeSessionIdRef = { value: userSessionId };
|
|
315
314
|
const systemMessageRouterRef: { value: SystemMessageRouter | null } = { value: null };
|
|
316
315
|
const conversationFollowUpRef: { value: ((item: ConversationFollowUpItem) => void) | null } = { value: null };
|
|
317
|
-
const { unsubs: runtimeUnsubs, agentStatusIntervalRef } =
|
|
316
|
+
const { unsubs: runtimeUnsubs, agentStatusIntervalRef } = registerAgentRuntimeEvents({
|
|
318
317
|
runtimeBus,
|
|
319
318
|
domainDispatch,
|
|
320
319
|
getSystemMessageRouter: () => systemMessageRouterRef.value,
|
|
@@ -322,69 +321,10 @@ export async function initializeBootstrapCore(
|
|
|
322
321
|
requestRender,
|
|
323
322
|
configManager,
|
|
324
323
|
agentManager: services.agentManager,
|
|
325
|
-
wrfcController: services.wrfcController,
|
|
326
324
|
});
|
|
327
325
|
|
|
328
|
-
//
|
|
329
|
-
//
|
|
330
|
-
// core WORKFLOW_REVIEW_COMPLETED / WORKFLOW_CHAIN_CREATED messages.
|
|
331
|
-
// The SDK does not surface constraint-specific system messages; the TUI layer
|
|
332
|
-
// adds them here so operators can observe constraint enumeration and violations
|
|
333
|
-
// in the SystemMessagesPanel and main conversation.
|
|
334
|
-
runtimeUnsubs.push(
|
|
335
|
-
runtimeBus.on<Extract<import('@/runtime/index.ts').WorkflowEvent, { type: 'WORKFLOW_CONSTRAINTS_ENUMERATED' }>>(
|
|
336
|
-
'WORKFLOW_CONSTRAINTS_ENUMERATED',
|
|
337
|
-
({ payload }) => {
|
|
338
|
-
const router = systemMessageRouterRef.value;
|
|
339
|
-
if (!router) return;
|
|
340
|
-
const count = payload.constraints.length;
|
|
341
|
-
if (count > 0) {
|
|
342
|
-
router.wrfc(
|
|
343
|
-
`[WRFC] Engineer enumerated ${count} constraint${count !== 1 ? 's' : ''} for chain ${payload.chainId.slice(0, 12)}`,
|
|
344
|
-
'low',
|
|
345
|
-
);
|
|
346
|
-
}
|
|
347
|
-
requestRender();
|
|
348
|
-
},
|
|
349
|
-
),
|
|
350
|
-
);
|
|
351
|
-
runtimeUnsubs.push(
|
|
352
|
-
runtimeBus.on<Extract<import('@/runtime/index.ts').WorkflowEvent, { type: 'WORKFLOW_FIX_ATTEMPTED' }>>(
|
|
353
|
-
'WORKFLOW_FIX_ATTEMPTED',
|
|
354
|
-
({ payload }) => {
|
|
355
|
-
const router = systemMessageRouterRef.value;
|
|
356
|
-
if (!router) return;
|
|
357
|
-
const targetIds = payload.targetConstraintIds;
|
|
358
|
-
if (targetIds && targetIds.length > 0) {
|
|
359
|
-
router.wrfc(
|
|
360
|
-
`[WRFC] Fix #${payload.attempt} targeting ${targetIds.length} constraint${targetIds.length !== 1 ? 's' : ''} on chain ${payload.chainId.slice(0, 12)}`,
|
|
361
|
-
'low',
|
|
362
|
-
);
|
|
363
|
-
requestRender();
|
|
364
|
-
}
|
|
365
|
-
},
|
|
366
|
-
),
|
|
367
|
-
);
|
|
368
|
-
runtimeUnsubs.push(
|
|
369
|
-
runtimeBus.on<Extract<import('@/runtime/index.ts').WorkflowEvent, { type: 'WORKFLOW_REVIEW_COMPLETED' }>>(
|
|
370
|
-
'WORKFLOW_REVIEW_COMPLETED',
|
|
371
|
-
({ payload }) => {
|
|
372
|
-
const router = systemMessageRouterRef.value;
|
|
373
|
-
if (!router) return;
|
|
374
|
-
const unsatisfied = payload.unsatisfiedConstraintIds;
|
|
375
|
-
if (!payload.passed && unsatisfied && unsatisfied.length > 0) {
|
|
376
|
-
router.wrfc(
|
|
377
|
-
`[WRFC] ✗ Chain ${payload.chainId.slice(0, 12)}: ${unsatisfied.length} constraint violation${unsatisfied.length !== 1 ? 's' : ''} forced failure`,
|
|
378
|
-
'high',
|
|
379
|
-
);
|
|
380
|
-
requestRender();
|
|
381
|
-
}
|
|
382
|
-
},
|
|
383
|
-
),
|
|
384
|
-
);
|
|
385
|
-
|
|
386
|
-
// Subscribe to companion main-chat messages received from the daemon's HTTP layer.
|
|
387
|
-
// The daemon emits COMPANION_MESSAGE_RECEIVED on the runtime bus when a companion
|
|
326
|
+
// Subscribe to companion main-chat messages received from the connected host's HTTP layer.
|
|
327
|
+
// The connected host emits COMPANION_MESSAGE_RECEIVED on the runtime bus when a companion
|
|
388
328
|
// POST /api/sessions/:id/messages with kind='message' arrives.
|
|
389
329
|
//
|
|
390
330
|
// bootstrap.ts patches orchestratorHandleUserInputRef.value after the Orchestrator
|
|
@@ -62,6 +62,43 @@ export interface BootstrapShellOptions {
|
|
|
62
62
|
readonly completeModelSelectionSideEffect?: () => void;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
type PlanningAnswerSubmit = (answer: string) => void;
|
|
66
|
+
|
|
67
|
+
export interface PlanningAnswerSubmitBridgeOptions {
|
|
68
|
+
readonly getSubmitInput: () => PlanningAnswerSubmit | undefined;
|
|
69
|
+
readonly addSystemMessage: (message: string) => void;
|
|
70
|
+
readonly requestRender: () => void;
|
|
71
|
+
readonly defer?: (callback: () => void) => void;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function submitPlanningAnswerWithShellFallback(
|
|
75
|
+
answer: string,
|
|
76
|
+
options: PlanningAnswerSubmitBridgeOptions,
|
|
77
|
+
): void {
|
|
78
|
+
const submit = options.getSubmitInput();
|
|
79
|
+
if (submit) {
|
|
80
|
+
submit(answer);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const defer = options.defer ?? ((callback) => {
|
|
85
|
+
setTimeout(callback, 0);
|
|
86
|
+
});
|
|
87
|
+
defer(() => {
|
|
88
|
+
const deferredSubmit = options.getSubmitInput();
|
|
89
|
+
if (deferredSubmit) {
|
|
90
|
+
deferredSubmit(answer);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
options.addSystemMessage([
|
|
95
|
+
'[Planning] Could not submit the selected answer because the prompt bridge is not ready.',
|
|
96
|
+
`Paste this answer into the prompt to continue planning: ${answer}`,
|
|
97
|
+
].join('\n'));
|
|
98
|
+
options.requestRender();
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
65
102
|
export function createBootstrapShell(options: BootstrapShellOptions): BootstrapShellState {
|
|
66
103
|
const {
|
|
67
104
|
configManager,
|
|
@@ -113,10 +150,11 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
|
|
|
113
150
|
resumeSession,
|
|
114
151
|
requestRender,
|
|
115
152
|
submitPlanningAnswer: (answer) => {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
153
|
+
submitPlanningAnswerWithShellFallback(answer, {
|
|
154
|
+
getSubmitInput: () => commandContextRef?.submitInput,
|
|
155
|
+
addSystemMessage: (message) => conversation.addSystemMessage(message),
|
|
156
|
+
requestRender,
|
|
157
|
+
});
|
|
120
158
|
},
|
|
121
159
|
dismissPlanning: () => {
|
|
122
160
|
services.panelManager.close('project-planning');
|
package/src/runtime/bootstrap.ts
CHANGED
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
* - lifecycle.ts: save/shutdown helpers
|
|
11
11
|
*/
|
|
12
12
|
import { Orchestrator, type OrchestratorUserInputOptions } from '../core/orchestrator.ts';
|
|
13
|
-
import { AcpManager } from '@pellux/goodvibes-sdk/platform/acp';
|
|
14
13
|
import { getTierPromptSupplement, getTierForContextWindow } from '@pellux/goodvibes-sdk/platform/providers';
|
|
15
14
|
import { logger } from '@pellux/goodvibes-sdk/platform/utils';
|
|
16
15
|
import type { PermissionRequestHandler } from '@pellux/goodvibes-sdk/platform/permissions';
|
|
@@ -23,7 +22,6 @@ import type { RuntimeContext, BootstrapOptions } from './context.ts';
|
|
|
23
22
|
import { shutdownRuntime, fireSessionStart, saveSession } from '@/runtime/index.ts';
|
|
24
23
|
import { createTaskManager } from '@/runtime/index.ts';
|
|
25
24
|
import { OpsControlPlane } from '@/runtime/index.ts';
|
|
26
|
-
import { AcpTaskAdapter } from '@/runtime/index.ts';
|
|
27
25
|
import type { SystemMessageRouter } from '../core/system-message-router.ts';
|
|
28
26
|
import { emitSessionReady, emitSessionStarted } from '@/runtime/index.ts';
|
|
29
27
|
import {
|
|
@@ -47,8 +45,8 @@ import { buildReviewedMemoryPrompt } from '../agent/memory-prompt.ts';
|
|
|
47
45
|
|
|
48
46
|
const GOODVIBES_AGENT_OPERATOR_POLICY = [
|
|
49
47
|
'## GoodVibes Agent Operator Policy',
|
|
50
|
-
'- Default to serial, proactive assistant work in the main conversation. Answer, inspect, summarize, remember useful non-secret facts, configure local Agent state, use read-only connected-
|
|
51
|
-
'- GoodVibes Agent connects to GoodVibes
|
|
48
|
+
'- Default to serial, proactive assistant work in the main conversation. Answer, inspect, summarize, remember useful non-secret facts, configure local Agent state, use read-only connected-host/operator routes, and take safe non-destructive actions without spawning local agents or WRFC.',
|
|
49
|
+
'- GoodVibes Agent connects to a GoodVibes host owned outside this package. Do not start, stop, restart, install, expose, or mutate connected-host network/listener posture from Agent.',
|
|
52
50
|
'- Use the `agent_local_registry` tool when a durable memory, reusable persona, skill, skill bundle, or routine would improve future work. Keep those records local, non-secret, source/provenance tagged, and reviewable. Review memory with a confidence score when it should shape future turns. Starting a routine means applying its steps in this same serial conversation, not creating a background job.',
|
|
53
51
|
'- 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.',
|
|
54
52
|
'- 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.',
|
|
@@ -130,7 +128,7 @@ export type BootstrapContext = RuntimeContext & {
|
|
|
130
128
|
* 3. Tool registry + agent wiring
|
|
131
129
|
* 4. Runtime bus subscriptions (WRFC, subagent, hook bridge)
|
|
132
130
|
* 5. Providers, webhooks, PermissionManager, HookDispatcher
|
|
133
|
-
* 6. Orchestrator
|
|
131
|
+
* 6. Orchestrator and Agent-local task read models
|
|
134
132
|
* 7. MCP auto-connect + workspace/panel manager
|
|
135
133
|
* 8. Command registry + plugin init + CommandContext
|
|
136
134
|
* 9. Input handler wiring
|
|
@@ -183,7 +181,7 @@ export async function bootstrapRuntime(
|
|
|
183
181
|
pluginManager,
|
|
184
182
|
} = services;
|
|
185
183
|
|
|
186
|
-
// ── Phase 6: Orchestrator
|
|
184
|
+
// ── Phase 6: Orchestrator and Agent-local task read models ───────────────
|
|
187
185
|
|
|
188
186
|
// Mutable function refs so main.ts can patch these after constructing the scroll/viewport state.
|
|
189
187
|
// The orchestrator closes over these refs, so patching them in main.ts takes immediate effect.
|
|
@@ -243,17 +241,6 @@ export async function bootstrapRuntime(
|
|
|
243
241
|
});
|
|
244
242
|
conversation.setSessionLineageTracker(services.sessionLineageTracker);
|
|
245
243
|
|
|
246
|
-
const acpManager = new AcpManager({
|
|
247
|
-
requestPermission: (request) => permissionPromptRef.requestPermission(request),
|
|
248
|
-
runtimeBus,
|
|
249
|
-
hookDispatcher: services.hookDispatcher,
|
|
250
|
-
});
|
|
251
|
-
const acpTaskAdapter = new AcpTaskAdapter(store);
|
|
252
|
-
const ACP_TASK_SYNC_INTERVAL_MS = 1_000;
|
|
253
|
-
const acpTaskSyncInterval = setInterval(() => {
|
|
254
|
-
acpTaskAdapter.sync(acpManager);
|
|
255
|
-
}, ACP_TASK_SYNC_INTERVAL_MS);
|
|
256
|
-
bootstrapUnsubs.push(() => clearInterval(acpTaskSyncInterval));
|
|
257
244
|
const opsTaskManager = createTaskManager(store, runtimeBus, userSessionId);
|
|
258
245
|
const opsControlPlane = services.featureFlags.isEnabled('operator-control-plane')
|
|
259
246
|
? new OpsControlPlane(opsTaskManager, runtimeBus, store, userSessionId)
|
|
@@ -334,7 +321,7 @@ export async function bootstrapRuntime(
|
|
|
334
321
|
port,
|
|
335
322
|
baseUrl: formatHostServiceBaseUrl(host, port),
|
|
336
323
|
reason: service === 'daemon'
|
|
337
|
-
? 'GoodVibes Agent connects to GoodVibes
|
|
324
|
+
? 'GoodVibes Agent connects to a GoodVibes host owned outside this product and does not start or restart them.'
|
|
338
325
|
: 'GoodVibes Agent does not own listener lifecycle.',
|
|
339
326
|
};
|
|
340
327
|
};
|
|
@@ -375,7 +362,7 @@ export async function bootstrapRuntime(
|
|
|
375
362
|
daemonStatus: createExternalAgentServiceStatus('daemon'),
|
|
376
363
|
httpListenerStatus: createExternalAgentServiceStatus('httpListener'),
|
|
377
364
|
};
|
|
378
|
-
systemMessageRouter.high('[Startup] GoodVibes Agent does not start or restart connected GoodVibes
|
|
365
|
+
systemMessageRouter.high('[Startup] GoodVibes Agent does not start or restart the connected GoodVibes host. Start it from GoodVibes TUI or the owning host, then refresh status.');
|
|
379
366
|
requestRender();
|
|
380
367
|
return inspectExternalServices();
|
|
381
368
|
},
|
|
@@ -452,8 +439,8 @@ export async function bootstrapRuntime(
|
|
|
452
439
|
});
|
|
453
440
|
bootstrapUnsubs.push(() => mcpAutoReload.stop());
|
|
454
441
|
if (configManager.get('automation.enabled')) {
|
|
455
|
-
logger.warn('Local automation startup is disabled in GoodVibes Agent; use connected-
|
|
456
|
-
systemMessageRouter.low('[Startup] Local automation runners are disabled in GoodVibes Agent; use read-only automation observability or explicit connected-
|
|
442
|
+
logger.warn('Local automation startup is disabled in GoodVibes Agent; use connected-host observability instead.');
|
|
443
|
+
systemMessageRouter.low('[Startup] Local automation runners are disabled in GoodVibes Agent; use read-only automation observability or explicit connected-host actions.');
|
|
457
444
|
}
|
|
458
445
|
|
|
459
446
|
// ── Phase 12: Session:start lifecycle hook ─────────────────────────────
|
|
@@ -554,12 +541,6 @@ export async function bootstrapRuntime(
|
|
|
554
541
|
},
|
|
555
542
|
};
|
|
556
543
|
|
|
557
|
-
// ── Phase 12b: Operator intervention wiring (feature-gated) ──────────────
|
|
558
|
-
// Keep service-owned control-plane state internal. GoodVibes Agent does not
|
|
559
|
-
// expose the local ops-control panel; operator control is surfaced
|
|
560
|
-
// through Agent-owned status, approvals, automation, and delegation flows.
|
|
561
|
-
ctx.commandContext.ops.acpManager = acpManager;
|
|
562
|
-
|
|
563
544
|
// Wire exit from options if provided; otherwise main.ts binds the shell bridge.
|
|
564
545
|
if (options?.exit) {
|
|
565
546
|
ctx.commandContext.exit = options.exit;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
type JsonRecord = Record<string, unknown>;
|
|
5
|
+
|
|
6
|
+
export interface ConnectedHostOperatorToken {
|
|
7
|
+
readonly path: string;
|
|
8
|
+
readonly present: boolean;
|
|
9
|
+
readonly token: string | null;
|
|
10
|
+
readonly error?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function isRecord(value: unknown): value is JsonRecord {
|
|
14
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function connectedHostOperatorTokenPath(homeDirectory: string): string {
|
|
18
|
+
return join(homeDirectory, '.goodvibes', 'daemon', 'operator-tokens.json');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function readConnectedHostOperatorToken(homeDirectory: string): ConnectedHostOperatorToken {
|
|
22
|
+
const path = connectedHostOperatorTokenPath(homeDirectory);
|
|
23
|
+
if (!existsSync(path)) return { path, present: false, token: null };
|
|
24
|
+
try {
|
|
25
|
+
const parsed = JSON.parse(readFileSync(path, 'utf-8')) as unknown;
|
|
26
|
+
const token = isRecord(parsed) && typeof parsed.token === 'string' && parsed.token.trim().length > 0
|
|
27
|
+
? parsed.token
|
|
28
|
+
: null;
|
|
29
|
+
return { path, present: true, token };
|
|
30
|
+
} catch (error) {
|
|
31
|
+
return { path, present: true, token: null, error: error instanceof Error ? error.message : String(error) };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function connectedHostTokenRequiredMessage(path: string): string {
|
|
36
|
+
return [
|
|
37
|
+
'Connected-host operator token is required.',
|
|
38
|
+
` token path: ${path}`,
|
|
39
|
+
' Agent does not create or rotate connected-host auth tokens.',
|
|
40
|
+
' Start or repair the owning GoodVibes host, then rerun this command.',
|
|
41
|
+
].join('\n');
|
|
42
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Panel resource diagnostics panel data provider.
|
|
3
3
|
*
|
|
4
|
-
* Polls the shared
|
|
4
|
+
* Polls the shared shell ComponentHealthMonitor and produces PanelResourceSnapshot
|
|
5
5
|
* values for the diagnostics panel to render.
|
|
6
6
|
*/
|
|
7
7
|
import type { ComponentHealthMonitor } from '../../perf/panel-health-monitor.ts';
|
package/src/runtime/index.ts
CHANGED
|
@@ -97,7 +97,6 @@ export const restoreRuntimeModel = bootstrap.restoreRuntimeModel;
|
|
|
97
97
|
export const restoreSavedModel = bootstrap.restoreRuntimeModel;
|
|
98
98
|
export const synchronizeConfiguredServices = bootstrap.synchronizeConfiguredServices;
|
|
99
99
|
export const syncConfiguredServices = bootstrap.synchronizeConfiguredServices;
|
|
100
|
-
export const registerBootstrapRuntimeEvents = bootstrap.registerBootstrapRuntimeEvents;
|
|
101
100
|
export const registerHostRuntimeEvents = bootstrap.registerHostRuntimeEvents;
|
|
102
101
|
function agentExternalHostStatus(
|
|
103
102
|
config: Bootstrap.HostServicesConfig,
|
|
@@ -113,7 +112,7 @@ function agentExternalHostStatus(
|
|
|
113
112
|
port,
|
|
114
113
|
baseUrl: `http://${host}:${port}`,
|
|
115
114
|
reason: service === 'daemon'
|
|
116
|
-
? 'GoodVibes Agent connects to GoodVibes
|
|
115
|
+
? 'GoodVibes Agent connects to a GoodVibes host owned outside this product and does not start or restart them.'
|
|
117
116
|
: 'GoodVibes Agent does not own listener lifecycle.',
|
|
118
117
|
};
|
|
119
118
|
}
|
|
@@ -245,7 +244,6 @@ export type RemoteRuntimeEvents = Transport.RemoteRuntimeEvents;
|
|
|
245
244
|
export type SerializedRuntimeEnvelope = Transport.SerializedRuntimeEnvelope;
|
|
246
245
|
|
|
247
246
|
// Operations compatibility aliases.
|
|
248
|
-
export const AcpTaskAdapter = operations.AcpTaskAdapter;
|
|
249
247
|
export const OpsControlPlane = operations.OpsControlPlane;
|
|
250
248
|
export const OpsIllegalActionError = operations.OpsIllegalActionError;
|
|
251
249
|
export const OpsTargetNotFoundError = operations.OpsTargetNotFoundError;
|
|
@@ -436,7 +434,6 @@ export const uninstallEcosystemCatalogEntry = shell.uninstallEcosystemCatalogEnt
|
|
|
436
434
|
export const updateInstalledEcosystemEntry = shell.updateInstalledEcosystemEntry;
|
|
437
435
|
export const upsertEcosystemCatalogEntry = shell.upsertEcosystemCatalogEntry;
|
|
438
436
|
export const summarizeWorktreeOwnership = shell.summarizeWorktreeOwnership;
|
|
439
|
-
export const WorktreeRegistry = shell.WorktreeRegistry;
|
|
440
437
|
export const listPersistedWorktreeMeta = shell.listPersistedWorktreeMeta;
|
|
441
438
|
export const getPersistedWorktreeMeta = shell.getPersistedWorktreeMeta;
|
|
442
439
|
export const reviewWorktreeAttachments = shell.reviewWorktreeAttachments;
|
|
@@ -458,7 +455,6 @@ export type WorktreeRegistry = Shell.WorktreeRegistry;
|
|
|
458
455
|
export type WorktreeStatusRecord = Shell.WorktreeStatusRecord;
|
|
459
456
|
export type ManagedWorktreeMeta = Shell.ManagedWorktreeMeta;
|
|
460
457
|
export type ShellAgentManagerService = Shell.ShellAgentManagerService;
|
|
461
|
-
export type ShellAcpManagerService = Shell.ShellAcpManagerService;
|
|
462
458
|
export type ShellAutomationManagerService = Shell.ShellAutomationManagerService;
|
|
463
459
|
export type ShellAutomationManagerRuntimeService = Shell.ShellAutomationManagerRuntimeService;
|
|
464
460
|
export type ShellModeManagerService = Shell.ShellModeManagerService;
|