@pellux/goodvibes-agent 0.1.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/.goodvibes/GOODVIBES.md +35 -0
- package/.goodvibes/agents/reviewer.md +48 -0
- package/.goodvibes/skills/add-provider/SKILL.md +199 -0
- package/CHANGELOG.md +25 -0
- package/README.md +74 -0
- package/bin/goodvibes-agent.ts +2 -0
- package/docs/README.md +23 -0
- package/docs/deployment-and-services.md +57 -0
- package/docs/getting-started.md +53 -0
- package/docs/release-and-publishing.md +46 -0
- package/package.json +134 -0
- package/scripts/check-bun.sh +20 -0
- package/src/audio/player.ts +156 -0
- package/src/audio/spoken-turn-controller.ts +203 -0
- package/src/audio/spoken-turn-model-routing.ts +117 -0
- package/src/audio/spoken-turn-wiring.ts +44 -0
- package/src/audio/text-chunker.ts +110 -0
- package/src/cli/bundle-command.ts +227 -0
- package/src/cli/completion.ts +90 -0
- package/src/cli/config-overrides.ts +159 -0
- package/src/cli/endpoints.ts +63 -0
- package/src/cli/entrypoint.ts +172 -0
- package/src/cli/help.ts +299 -0
- package/src/cli/index.ts +11 -0
- package/src/cli/management-commands.ts +426 -0
- package/src/cli/management.ts +744 -0
- package/src/cli/network-posture.ts +46 -0
- package/src/cli/package-verification.ts +123 -0
- package/src/cli/parser.ts +369 -0
- package/src/cli/provider-auth-routes.ts +22 -0
- package/src/cli/provider-classification.ts +107 -0
- package/src/cli/redaction.ts +105 -0
- package/src/cli/service-command.ts +26 -0
- package/src/cli/service-posture.ts +482 -0
- package/src/cli/status.ts +383 -0
- package/src/cli/surface-command.ts +247 -0
- package/src/cli/tui-startup.ts +32 -0
- package/src/cli/types.ts +69 -0
- package/src/cli-flags.ts +21 -0
- package/src/config/goodvibes-home-audit.ts +465 -0
- package/src/config/index.ts +57 -0
- package/src/config/provider-model.ts +23 -0
- package/src/config/secret-config.ts +119 -0
- package/src/config/secrets.ts +71 -0
- package/src/config/surface.ts +1 -0
- package/src/core/composer-state.ts +61 -0
- package/src/core/conversation-rendering.ts +359 -0
- package/src/core/conversation.ts +551 -0
- package/src/core/history.ts +45 -0
- package/src/core/orchestrator.ts +7 -0
- package/src/core/system-message-router.ts +171 -0
- package/src/daemon/cli.ts +55 -0
- package/src/daemon/safe-serve.ts +61 -0
- package/src/input/agent-workspace.ts +428 -0
- package/src/input/autocomplete.ts +96 -0
- package/src/input/bookmark-modal.ts +115 -0
- package/src/input/command-args-hint.ts +36 -0
- package/src/input/command-registry.ts +329 -0
- package/src/input/commands/agent-externalized-tui.ts +73 -0
- package/src/input/commands/agent-workspace-runtime.ts +17 -0
- package/src/input/commands/branch-runtime.ts +72 -0
- package/src/input/commands/cloudflare-runtime.ts +370 -0
- package/src/input/commands/config.ts +18 -0
- package/src/input/commands/control-room-runtime.ts +255 -0
- package/src/input/commands/conversation-runtime.ts +207 -0
- package/src/input/commands/discovery-runtime.ts +52 -0
- package/src/input/commands/eval.ts +204 -0
- package/src/input/commands/experience-runtime.ts +278 -0
- package/src/input/commands/guidance-runtime.ts +106 -0
- package/src/input/commands/health-runtime.ts +434 -0
- package/src/input/commands/hooks-runtime.ts +148 -0
- package/src/input/commands/incident-runtime.ts +95 -0
- package/src/input/commands/integration-runtime.ts +394 -0
- package/src/input/commands/intelligence-runtime.ts +223 -0
- package/src/input/commands/knowledge.ts +531 -0
- package/src/input/commands/local-auth-runtime.ts +105 -0
- package/src/input/commands/local-provider-runtime.ts +170 -0
- package/src/input/commands/local-runtime.ts +392 -0
- package/src/input/commands/local-setup-review.ts +199 -0
- package/src/input/commands/local-setup-transfer.ts +135 -0
- package/src/input/commands/local-setup.ts +282 -0
- package/src/input/commands/managed-runtime.ts +209 -0
- package/src/input/commands/marketplace-runtime.ts +290 -0
- package/src/input/commands/mcp-runtime.ts +432 -0
- package/src/input/commands/memory-product-runtime.ts +111 -0
- package/src/input/commands/memory.ts +151 -0
- package/src/input/commands/notify-runtime.ts +83 -0
- package/src/input/commands/onboarding-runtime.ts +14 -0
- package/src/input/commands/operator-panel-runtime.ts +146 -0
- package/src/input/commands/operator-runtime.ts +392 -0
- package/src/input/commands/planning-runtime.ts +205 -0
- package/src/input/commands/platform-access-runtime.ts +422 -0
- package/src/input/commands/platform-services-runtime.ts +246 -0
- package/src/input/commands/policy-dispatch.ts +339 -0
- package/src/input/commands/policy.ts +17 -0
- package/src/input/commands/product-runtime.ts +351 -0
- package/src/input/commands/profile-sync-runtime.ts +99 -0
- package/src/input/commands/provider-accounts-runtime.ts +113 -0
- package/src/input/commands/provider.ts +363 -0
- package/src/input/commands/qrcode-runtime.ts +20 -0
- package/src/input/commands/quit-shared.ts +162 -0
- package/src/input/commands/recall-bundle.ts +132 -0
- package/src/input/commands/recall-capture.ts +152 -0
- package/src/input/commands/recall-query.ts +229 -0
- package/src/input/commands/recall-review.ts +98 -0
- package/src/input/commands/recall-shared.ts +22 -0
- package/src/input/commands/remote-runtime-pool.ts +106 -0
- package/src/input/commands/remote-runtime-setup.ts +199 -0
- package/src/input/commands/remote-runtime.ts +431 -0
- package/src/input/commands/replay-runtime.ts +18 -0
- package/src/input/commands/runtime-services.ts +291 -0
- package/src/input/commands/schedule-runtime.ts +91 -0
- package/src/input/commands/services-runtime.ts +209 -0
- package/src/input/commands/session-content.ts +408 -0
- package/src/input/commands/session-workflow.ts +464 -0
- package/src/input/commands/session.ts +375 -0
- package/src/input/commands/settings-sync-runtime.ts +174 -0
- package/src/input/commands/share-runtime.ts +119 -0
- package/src/input/commands/shell-core.ts +307 -0
- package/src/input/commands/skills-runtime.ts +221 -0
- package/src/input/commands/subscription-runtime.ts +434 -0
- package/src/input/commands/tasks-runtime.ts +230 -0
- package/src/input/commands/teamwork-runtime.ts +339 -0
- package/src/input/commands/teleport-runtime.ts +57 -0
- package/src/input/commands/tts-runtime.ts +29 -0
- package/src/input/commands/work-plan-runtime.ts +169 -0
- package/src/input/commands.ts +131 -0
- package/src/input/feed-context-factory.ts +254 -0
- package/src/input/file-picker.ts +192 -0
- package/src/input/handler-command-route.ts +180 -0
- package/src/input/handler-content-actions.ts +497 -0
- package/src/input/handler-feed-routes.ts +648 -0
- package/src/input/handler-feed.ts +452 -0
- package/src/input/handler-interactions.ts +281 -0
- package/src/input/handler-modal-routes.ts +418 -0
- package/src/input/handler-modal-stack.ts +263 -0
- package/src/input/handler-modal-token-routes.ts +329 -0
- package/src/input/handler-onboarding-cloudflare.ts +391 -0
- package/src/input/handler-onboarding.ts +620 -0
- package/src/input/handler-picker-routes.ts +472 -0
- package/src/input/handler-prompt-buffer.ts +320 -0
- package/src/input/handler-shortcuts.ts +213 -0
- package/src/input/handler-ui-state.ts +372 -0
- package/src/input/handler.ts +729 -0
- package/src/input/input-history.ts +297 -0
- package/src/input/keybindings.ts +292 -0
- package/src/input/mcp-workspace.ts +554 -0
- package/src/input/model-picker-provider-filter.ts +28 -0
- package/src/input/model-picker-types.ts +137 -0
- package/src/input/model-picker.ts +797 -0
- package/src/input/onboarding/handler-onboarding-routes.ts +125 -0
- package/src/input/onboarding/onboarding-runtime-status.ts +87 -0
- package/src/input/onboarding/onboarding-wizard-apply.ts +277 -0
- package/src/input/onboarding/onboarding-wizard-cloudflare-step.ts +494 -0
- package/src/input/onboarding/onboarding-wizard-cloudflare.ts +204 -0
- package/src/input/onboarding/onboarding-wizard-constants.ts +158 -0
- package/src/input/onboarding/onboarding-wizard-external-surface-extra-specs.ts +130 -0
- package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +762 -0
- package/src/input/onboarding/onboarding-wizard-helpers.ts +167 -0
- package/src/input/onboarding/onboarding-wizard-rules.ts +256 -0
- package/src/input/onboarding/onboarding-wizard-state.ts +365 -0
- package/src/input/onboarding/onboarding-wizard-steps.ts +798 -0
- package/src/input/onboarding/onboarding-wizard-types.ts +195 -0
- package/src/input/onboarding/onboarding-wizard.ts +711 -0
- package/src/input/panel-integration-actions.ts +78 -0
- package/src/input/profile-picker-modal.ts +222 -0
- package/src/input/search.ts +100 -0
- package/src/input/selection-modal.ts +163 -0
- package/src/input/selection.ts +135 -0
- package/src/input/session-picker-modal.ts +136 -0
- package/src/input/settings-modal-behavior.ts +37 -0
- package/src/input/settings-modal-secrets.ts +41 -0
- package/src/input/settings-modal-subscriptions.ts +95 -0
- package/src/input/settings-modal-types.ts +91 -0
- package/src/input/settings-modal.ts +793 -0
- package/src/input/submission-intent.ts +17 -0
- package/src/input/submission-router.ts +59 -0
- package/src/input/tts-settings-actions.ts +100 -0
- package/src/main.ts +792 -0
- package/src/mcp/runtime-reload.ts +81 -0
- package/src/panels/agent-inspector-panel.ts +521 -0
- package/src/panels/agent-inspector-shared.ts +94 -0
- package/src/panels/agent-logs-panel.ts +559 -0
- package/src/panels/agent-logs-shared.ts +129 -0
- package/src/panels/approval-panel.ts +150 -0
- package/src/panels/automation-control-panel.ts +212 -0
- package/src/panels/base-panel.ts +254 -0
- package/src/panels/builtin/agent.ts +117 -0
- package/src/panels/builtin/development.ts +31 -0
- package/src/panels/builtin/knowledge.ts +26 -0
- package/src/panels/builtin/operations.ts +349 -0
- package/src/panels/builtin/session.ts +129 -0
- package/src/panels/builtin/shared.ts +274 -0
- package/src/panels/builtin-panels.ts +23 -0
- package/src/panels/cockpit-panel.ts +183 -0
- package/src/panels/communication-panel.ts +153 -0
- package/src/panels/confirm-state.ts +61 -0
- package/src/panels/context-visualizer-panel.ts +204 -0
- package/src/panels/control-plane-panel.ts +211 -0
- package/src/panels/cost-tracker-panel.ts +444 -0
- package/src/panels/debug-panel.ts +432 -0
- package/src/panels/diff-panel.ts +520 -0
- package/src/panels/docs-panel.ts +283 -0
- package/src/panels/eval-panel.ts +399 -0
- package/src/panels/file-explorer-panel.ts +584 -0
- package/src/panels/file-preview-panel.ts +434 -0
- package/src/panels/forensics-panel.ts +364 -0
- package/src/panels/git-panel.ts +638 -0
- package/src/panels/hooks-panel.ts +239 -0
- package/src/panels/incident-review-panel.ts +197 -0
- package/src/panels/index.ts +46 -0
- package/src/panels/intelligence-panel.ts +176 -0
- package/src/panels/knowledge-panel.ts +345 -0
- package/src/panels/local-auth-panel.ts +130 -0
- package/src/panels/marketplace-panel.ts +212 -0
- package/src/panels/memory-panel.ts +225 -0
- package/src/panels/ops-control-panel.ts +150 -0
- package/src/panels/ops-strategy-panel.ts +235 -0
- package/src/panels/orchestration-panel.ts +273 -0
- package/src/panels/panel-list-panel.ts +509 -0
- package/src/panels/panel-manager.ts +570 -0
- package/src/panels/panel-picker.ts +106 -0
- package/src/panels/plan-dashboard-panel.ts +274 -0
- package/src/panels/plugins-panel.ts +178 -0
- package/src/panels/policy-panel.ts +308 -0
- package/src/panels/polish.ts +717 -0
- package/src/panels/project-planning-panel.ts +711 -0
- package/src/panels/provider-account-snapshot.ts +259 -0
- package/src/panels/provider-accounts-panel.ts +218 -0
- package/src/panels/provider-health-domains.ts +215 -0
- package/src/panels/provider-health-panel.ts +727 -0
- package/src/panels/provider-health-tracker.ts +115 -0
- package/src/panels/provider-stats-panel.ts +366 -0
- package/src/panels/qr-panel.ts +182 -0
- package/src/panels/remote-panel.ts +449 -0
- package/src/panels/routes-panel.ts +178 -0
- package/src/panels/sandbox-panel.ts +283 -0
- package/src/panels/schedule-panel.ts +329 -0
- package/src/panels/scrollable-list-panel.ts +491 -0
- package/src/panels/search-focus.ts +32 -0
- package/src/panels/security-panel.ts +295 -0
- package/src/panels/services-panel.ts +231 -0
- package/src/panels/session-browser-panel.ts +400 -0
- package/src/panels/session-maintenance.ts +125 -0
- package/src/panels/settings-sync-panel.ts +120 -0
- package/src/panels/skills-panel.ts +431 -0
- package/src/panels/subscription-panel.ts +263 -0
- package/src/panels/symbol-outline-panel.ts +486 -0
- package/src/panels/system-messages-panel.ts +230 -0
- package/src/panels/tasks-panel.ts +399 -0
- package/src/panels/thinking-panel.ts +304 -0
- package/src/panels/token-budget-panel.ts +475 -0
- package/src/panels/tool-inspector-panel.ts +429 -0
- package/src/panels/types.ts +54 -0
- package/src/panels/watchers-panel.ts +193 -0
- package/src/panels/work-plan-panel.ts +175 -0
- package/src/panels/worktree-panel.ts +182 -0
- package/src/panels/wrfc-panel.ts +609 -0
- package/src/permissions/prompt.ts +165 -0
- package/src/planning/project-planning-coordinator.ts +543 -0
- package/src/plugins/loader.ts +15 -0
- package/src/renderer/agent-detail-modal.ts +331 -0
- package/src/renderer/agent-workspace.ts +238 -0
- package/src/renderer/ansi-sanitize.ts +76 -0
- package/src/renderer/autocomplete-overlay.ts +154 -0
- package/src/renderer/block-actions.ts +76 -0
- package/src/renderer/bookmark-modal.ts +101 -0
- package/src/renderer/bottom-bar.ts +58 -0
- package/src/renderer/buffer.ts +113 -0
- package/src/renderer/code-block.ts +373 -0
- package/src/renderer/compositor.ts +283 -0
- package/src/renderer/context-inspector.ts +219 -0
- package/src/renderer/conversation-layout.ts +67 -0
- package/src/renderer/conversation-overlays.ts +140 -0
- package/src/renderer/conversation-surface.ts +260 -0
- package/src/renderer/diff-view.ts +132 -0
- package/src/renderer/diff.ts +130 -0
- package/src/renderer/file-picker-overlay.ts +101 -0
- package/src/renderer/file-tree.ts +153 -0
- package/src/renderer/fullscreen-primitives.ts +130 -0
- package/src/renderer/fullscreen-workspace.ts +199 -0
- package/src/renderer/git-status.ts +89 -0
- package/src/renderer/help-overlay.ts +267 -0
- package/src/renderer/history-search-overlay.ts +73 -0
- package/src/renderer/layout-engine.ts +97 -0
- package/src/renderer/layout.ts +32 -0
- package/src/renderer/live-tail-modal.ts +156 -0
- package/src/renderer/markdown.ts +635 -0
- package/src/renderer/mcp-workspace.ts +237 -0
- package/src/renderer/modal-factory.ts +467 -0
- package/src/renderer/modal-utils.ts +24 -0
- package/src/renderer/model-picker-overlay.ts +473 -0
- package/src/renderer/model-workspace.ts +488 -0
- package/src/renderer/onboarding/onboarding-wizard.ts +615 -0
- package/src/renderer/overlay-box.ts +146 -0
- package/src/renderer/overlay-viewport.ts +104 -0
- package/src/renderer/panel-composite.ts +158 -0
- package/src/renderer/panel-picker-overlay.ts +202 -0
- package/src/renderer/panel-tab-bar.ts +69 -0
- package/src/renderer/panel-workspace-bar.ts +42 -0
- package/src/renderer/process-indicator.ts +96 -0
- package/src/renderer/process-modal.ts +656 -0
- package/src/renderer/process-summary.ts +67 -0
- package/src/renderer/profile-picker-modal.ts +129 -0
- package/src/renderer/progress.ts +98 -0
- package/src/renderer/qr-renderer.ts +120 -0
- package/src/renderer/search-overlay.ts +54 -0
- package/src/renderer/selection-modal-overlay.ts +214 -0
- package/src/renderer/semantic-diff.ts +369 -0
- package/src/renderer/session-picker-modal.ts +127 -0
- package/src/renderer/settings-modal-helpers.ts +193 -0
- package/src/renderer/settings-modal.ts +537 -0
- package/src/renderer/shell-surface.ts +88 -0
- package/src/renderer/status-glyphs.ts +21 -0
- package/src/renderer/status-token.ts +67 -0
- package/src/renderer/surface-layout.ts +101 -0
- package/src/renderer/syntax-highlighter.ts +542 -0
- package/src/renderer/system-message.ts +83 -0
- package/src/renderer/tab-strip.ts +108 -0
- package/src/renderer/text-layout.ts +31 -0
- package/src/renderer/thinking.ts +17 -0
- package/src/renderer/tool-call.ts +234 -0
- package/src/renderer/ui-factory.ts +524 -0
- package/src/renderer/ui-primitives.ts +96 -0
- package/src/runtime/bootstrap-command-context.ts +278 -0
- package/src/runtime/bootstrap-command-parts.ts +386 -0
- package/src/runtime/bootstrap-core.ts +540 -0
- package/src/runtime/bootstrap-hook-bridge.ts +112 -0
- package/src/runtime/bootstrap-shell.ts +283 -0
- package/src/runtime/bootstrap.ts +575 -0
- package/src/runtime/cloudflare-control-plane.ts +349 -0
- package/src/runtime/context.ts +142 -0
- package/src/runtime/diagnostics/panels/index.ts +24 -0
- package/src/runtime/diagnostics/panels/ops.ts +156 -0
- package/src/runtime/diagnostics/panels/panel-resources.ts +118 -0
- package/src/runtime/diagnostics/panels/policy.ts +177 -0
- package/src/runtime/index.ts +662 -0
- package/src/runtime/onboarding/apply.ts +642 -0
- package/src/runtime/onboarding/derivation.ts +534 -0
- package/src/runtime/onboarding/index.ts +7 -0
- package/src/runtime/onboarding/markers.ts +148 -0
- package/src/runtime/onboarding/snapshot.ts +406 -0
- package/src/runtime/onboarding/state.ts +141 -0
- package/src/runtime/onboarding/types.ts +404 -0
- package/src/runtime/onboarding/verify.ts +171 -0
- package/src/runtime/operator-token-cleanup.ts +27 -0
- package/src/runtime/perf/panel-contracts.ts +32 -0
- package/src/runtime/perf/panel-health-monitor.ts +18 -0
- package/src/runtime/sandbox-public-gaps.ts +358 -0
- package/src/runtime/services.ts +670 -0
- package/src/runtime/store/domains/domain-read-matrix.ts +15 -0
- package/src/runtime/store/domains/index.ts +222 -0
- package/src/runtime/store/domains/panels.ts +117 -0
- package/src/runtime/store/domains/ui-perf.ts +103 -0
- package/src/runtime/store/index.ts +305 -0
- package/src/runtime/store/selectors/index.ts +359 -0
- package/src/runtime/store/state.ts +145 -0
- package/src/runtime/surface-feature-flags.ts +65 -0
- package/src/runtime/terminal-output-guard.ts +228 -0
- package/src/runtime/ui/index.ts +39 -0
- package/src/runtime/ui/model-picker/data-provider.ts +182 -0
- package/src/runtime/ui/model-picker/health-enrichment.ts +228 -0
- package/src/runtime/ui/model-picker/index.ts +59 -0
- package/src/runtime/ui/model-picker/types.ts +149 -0
- package/src/runtime/ui/provider-health/data-provider.ts +244 -0
- package/src/runtime/ui/provider-health/fallback-visualizer.ts +71 -0
- package/src/runtime/ui/provider-health/index.ts +46 -0
- package/src/runtime/ui/provider-health/types.ts +146 -0
- package/src/runtime/ui-events.ts +1 -0
- package/src/runtime/ui-read-model-helpers.ts +1 -0
- package/src/runtime/ui-read-models-observability-maintenance.ts +1 -0
- package/src/runtime/ui-read-models-observability-options.ts +1 -0
- package/src/runtime/ui-read-models-observability-remote.ts +1 -0
- package/src/runtime/ui-read-models-observability-security.ts +1 -0
- package/src/runtime/ui-read-models-observability-system.ts +1 -0
- package/src/runtime/ui-read-models-observability.ts +1 -0
- package/src/runtime/ui-read-models.ts +61 -0
- package/src/runtime/ui-service-queries.ts +1 -0
- package/src/runtime/ui-services.ts +190 -0
- package/src/scripts/process-messages.ts +42 -0
- package/src/shell/blocking-input.ts +98 -0
- package/src/shell/service-settings-sync.ts +273 -0
- package/src/shell/ui-openers.ts +352 -0
- package/src/tools/index.ts +1 -0
- package/src/tools/wrfc-agent-guard.ts +49 -0
- package/src/types/grid.ts +48 -0
- package/src/types/sql-js.d.ts +15 -0
- package/src/utils/clipboard.ts +22 -0
- package/src/utils/splash-lines.ts +46 -0
- package/src/utils/terminal-width.ts +185 -0
- package/src/verification/live-verifier.ts +430 -0
- package/src/verification/verification-ledger.ts +242 -0
- package/src/version.ts +17 -0
- package/src/widget/index.ts +2 -0
- package/src/widget/types.ts +9 -0
- package/src/widget/widget.ts +8 -0
- package/src/work-plans/work-plan-store.ts +374 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
import { getDefaultAcpAgentCommand } from '@pellux/goodvibes-sdk/platform/acp';
|
|
4
|
+
import type { CommandContext, RemoteCommandService } from '../command-registry.ts';
|
|
5
|
+
import type { RemoteSessionBundle } from '@/runtime/index.ts';
|
|
6
|
+
import { requireShellPaths } from './runtime-services.ts';
|
|
7
|
+
|
|
8
|
+
type RemoteRegistryLike = Pick<RemoteCommandService, 'listContracts' | 'exportSessionBundle' | 'importSessionBundle'>;
|
|
9
|
+
|
|
10
|
+
type ActiveConnectionLike = {
|
|
11
|
+
agentId: string;
|
|
12
|
+
transportState: string;
|
|
13
|
+
messageCount: number;
|
|
14
|
+
errorCount: number;
|
|
15
|
+
label: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export function inspectRemoteSessionBundle(bundle: RemoteSessionBundle): string {
|
|
19
|
+
return [
|
|
20
|
+
'Remote Session Bundle Review',
|
|
21
|
+
` session: ${bundle.sessionId}`,
|
|
22
|
+
` exportedAt: ${new Date(bundle.exportedAt).toISOString()}`,
|
|
23
|
+
` active connections: ${bundle.activeConnectionIds.length}`,
|
|
24
|
+
` pools: ${bundle.pools.length}`,
|
|
25
|
+
` contracts: ${bundle.contracts.length}`,
|
|
26
|
+
` artifacts: ${bundle.artifacts.length}`,
|
|
27
|
+
].join('\n');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function handleRemoteSetupCommand(
|
|
31
|
+
args: string[],
|
|
32
|
+
ctx: CommandContext,
|
|
33
|
+
activeConnections: ActiveConnectionLike[],
|
|
34
|
+
remoteRegistry: RemoteRegistryLike,
|
|
35
|
+
): Promise<boolean> {
|
|
36
|
+
const subcommand = args[0]?.toLowerCase() ?? 'show';
|
|
37
|
+
if (subcommand === 'setup') {
|
|
38
|
+
const command = getDefaultAcpAgentCommand();
|
|
39
|
+
const danger = ctx.platform.configManager.getCategory('danger');
|
|
40
|
+
const lines = [
|
|
41
|
+
'Remote Setup Review',
|
|
42
|
+
` acp agent command: ${command.join(' ')}`,
|
|
43
|
+
` daemon enabled: ${danger.daemon ? 'yes' : 'no'}`,
|
|
44
|
+
` http listener enabled: ${danger.httpListener ? 'yes' : 'no'}`,
|
|
45
|
+
` remote runner contracts: ${remoteRegistry.listContracts().length}`,
|
|
46
|
+
` active acp connections: ${activeConnections.length}`,
|
|
47
|
+
'',
|
|
48
|
+
' guidance:',
|
|
49
|
+
' - set ACP_AGENT_CMD to override the spawned remote agent command',
|
|
50
|
+
' - use /remote env to export a reusable shell snippet',
|
|
51
|
+
' - enable danger.daemon / danger.httpListener only when you actually need those remote surfaces',
|
|
52
|
+
];
|
|
53
|
+
if (args[1]?.toLowerCase() === 'export') {
|
|
54
|
+
const pathArg = args[2];
|
|
55
|
+
if (!pathArg) {
|
|
56
|
+
ctx.print('Usage: /remote setup export <path>');
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
const shellPaths = requireShellPaths(ctx);
|
|
60
|
+
const targetPath = shellPaths.resolveWorkspacePath(pathArg);
|
|
61
|
+
mkdirSync(dirname(targetPath), { recursive: true });
|
|
62
|
+
writeFileSync(targetPath, `${JSON.stringify({
|
|
63
|
+
exportedAt: Date.now(),
|
|
64
|
+
acpAgentCommand: command,
|
|
65
|
+
daemonEnabled: Boolean(danger.daemon),
|
|
66
|
+
httpListenerEnabled: Boolean(danger.httpListener),
|
|
67
|
+
remoteRunnerContracts: remoteRegistry.listContracts().length,
|
|
68
|
+
}, null, 2)}\n`, 'utf-8');
|
|
69
|
+
ctx.print(`Exported remote setup bundle to ${targetPath}`);
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
ctx.print(lines.join('\n'));
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (subcommand === 'env') {
|
|
77
|
+
const command = getDefaultAcpAgentCommand();
|
|
78
|
+
const shellSnippet = [
|
|
79
|
+
`export ACP_AGENT_CMD='${command.join(' ')}'`,
|
|
80
|
+
`export GOODVIBES_REMOTE_SESSION='${ctx.session.runtime.sessionId}'`,
|
|
81
|
+
].join('\n');
|
|
82
|
+
if (args[1]?.toLowerCase() === 'export') {
|
|
83
|
+
const pathArg = args[2];
|
|
84
|
+
if (!pathArg) {
|
|
85
|
+
ctx.print('Usage: /remote env export <path>');
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
const shellPaths = requireShellPaths(ctx);
|
|
89
|
+
const targetPath = shellPaths.resolveWorkspacePath(pathArg);
|
|
90
|
+
mkdirSync(dirname(targetPath), { recursive: true });
|
|
91
|
+
writeFileSync(targetPath, `${shellSnippet}\n`, 'utf-8');
|
|
92
|
+
ctx.print(`Exported remote environment snippet to ${targetPath}`);
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
ctx.print(['Remote Environment', shellSnippet].join('\n'));
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (subcommand === 'tunnel') {
|
|
100
|
+
const mode = args[1]?.toLowerCase() ?? 'review';
|
|
101
|
+
const lines = [
|
|
102
|
+
'Remote Tunnel Review',
|
|
103
|
+
' transport: self-hosted ACP / daemon relay',
|
|
104
|
+
` session: ${ctx.session.runtime.sessionId}`,
|
|
105
|
+
` active remote connections: ${activeConnections.length}`,
|
|
106
|
+
' guidance: forward ACP agent traffic through your chosen self-hosted tunnel or SSH transport',
|
|
107
|
+
];
|
|
108
|
+
if (mode === 'export') {
|
|
109
|
+
const pathArg = args[2];
|
|
110
|
+
if (!pathArg) {
|
|
111
|
+
ctx.print('Usage: /remote tunnel export <path>');
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
const shellPaths = requireShellPaths(ctx);
|
|
115
|
+
const targetPath = shellPaths.resolveWorkspacePath(pathArg);
|
|
116
|
+
mkdirSync(dirname(targetPath), { recursive: true });
|
|
117
|
+
writeFileSync(targetPath, `${lines.join('\n')}\n`, 'utf-8');
|
|
118
|
+
ctx.print(`Exported remote tunnel review to ${targetPath}`);
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
ctx.print(lines.join('\n'));
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (subcommand === 'bootstrap') {
|
|
126
|
+
const mode = args[1]?.toLowerCase() ?? 'export';
|
|
127
|
+
const payload = {
|
|
128
|
+
exportedAt: Date.now(),
|
|
129
|
+
sessionId: ctx.session.runtime.sessionId,
|
|
130
|
+
acpAgentCommand: getDefaultAcpAgentCommand(),
|
|
131
|
+
env: {
|
|
132
|
+
ACP_AGENT_CMD: getDefaultAcpAgentCommand().join(' '),
|
|
133
|
+
GOODVIBES_REMOTE_SESSION: ctx.session.runtime.sessionId,
|
|
134
|
+
},
|
|
135
|
+
links: [
|
|
136
|
+
'goodvibes://open/remote',
|
|
137
|
+
'goodvibes://open/cockpit?target=remote',
|
|
138
|
+
],
|
|
139
|
+
};
|
|
140
|
+
if (mode === 'inspect') {
|
|
141
|
+
const pathArg = args[2];
|
|
142
|
+
if (!pathArg) {
|
|
143
|
+
ctx.print('Usage: /remote bootstrap inspect <path>');
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
const shellPaths = requireShellPaths(ctx);
|
|
147
|
+
const targetPath = shellPaths.resolveWorkspacePath(pathArg);
|
|
148
|
+
const parsed = JSON.parse(readFileSync(targetPath, 'utf-8')) as typeof payload;
|
|
149
|
+
ctx.print([
|
|
150
|
+
'Remote Bootstrap Bundle Review',
|
|
151
|
+
` session: ${parsed.sessionId}`,
|
|
152
|
+
` acp agent command: ${parsed.acpAgentCommand.join(' ')}`,
|
|
153
|
+
` links: ${parsed.links.length}`,
|
|
154
|
+
].join('\n'));
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
const pathArg = args[2] ?? args[1];
|
|
158
|
+
if (!pathArg || mode !== 'export') {
|
|
159
|
+
ctx.print('Usage: /remote bootstrap export <path> | /remote bootstrap inspect <path>');
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
const shellPaths = requireShellPaths(ctx);
|
|
163
|
+
const targetPath = shellPaths.resolveWorkspacePath(pathArg);
|
|
164
|
+
mkdirSync(dirname(targetPath), { recursive: true });
|
|
165
|
+
writeFileSync(targetPath, `${JSON.stringify(payload, null, 2)}\n`, 'utf-8');
|
|
166
|
+
ctx.print(`Exported remote bootstrap bundle to ${targetPath}`);
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (subcommand === 'session') {
|
|
171
|
+
const mode = args[1]?.toLowerCase();
|
|
172
|
+
const pathArg = args[2];
|
|
173
|
+
if (!mode || !pathArg) {
|
|
174
|
+
ctx.print('Usage: /remote session <export|inspect|import> <path>');
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
const shellPaths = requireShellPaths(ctx);
|
|
178
|
+
const targetPath = shellPaths.resolveWorkspacePath(pathArg);
|
|
179
|
+
if (mode === 'export') {
|
|
180
|
+
const exported = await remoteRegistry.exportSessionBundle(targetPath);
|
|
181
|
+
ctx.print(`Exported remote session bundle ${exported.bundle.sessionId} to ${exported.path}`);
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
if (mode === 'inspect') {
|
|
185
|
+
const bundle = JSON.parse(readFileSync(targetPath, 'utf-8')) as RemoteSessionBundle;
|
|
186
|
+
ctx.print(inspectRemoteSessionBundle(bundle));
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
if (mode === 'import') {
|
|
190
|
+
const bundle = await remoteRegistry.importSessionBundle(targetPath);
|
|
191
|
+
ctx.print(`Imported remote session bundle ${bundle.sessionId} with ${bundle.contracts.length} contracts.`);
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
ctx.print('Usage: /remote session <export|inspect|import> <path>');
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import type { CommandRegistry, CommandContext } from '../command-registry.ts';
|
|
3
|
+
import { AGENT_TEMPLATES } from '@pellux/goodvibes-sdk/platform/tools';
|
|
4
|
+
import { handleRemoteSetupCommand } from './remote-runtime-setup.ts';
|
|
5
|
+
import { handleRemotePoolCommand } from './remote-runtime-pool.ts';
|
|
6
|
+
import { requireAgentManager, requireAcpManager, requirePeerClient } from './runtime-services.ts';
|
|
7
|
+
|
|
8
|
+
type RemoteConnectionLike = { agentId: string };
|
|
9
|
+
type RemoteCancelContext = Pick<CommandContext, 'print'>;
|
|
10
|
+
type RemoteCancelAgentManager = Pick<ReturnType<typeof requireAgentManager>, 'cancel'>;
|
|
11
|
+
type RemoteCancelAcpManager = Pick<ReturnType<typeof requireAcpManager>, 'cancel'>;
|
|
12
|
+
|
|
13
|
+
function printRemoteDelegationBoundary(ctx: Pick<CommandContext, 'print'>, requestedAction: string): void {
|
|
14
|
+
ctx.print([
|
|
15
|
+
'GoodVibes Agent does not dispatch remote/local coding runners from this surface.',
|
|
16
|
+
` requested: ${requestedAction}`,
|
|
17
|
+
' policy: keep ordinary work serial in the main assistant conversation',
|
|
18
|
+
' build/fix/review: delegate one request to GoodVibes TUI through the public shared-session/build-delegation contract',
|
|
19
|
+
' preserve: full original user ask and executionIntent; let TUI own runner/WRFC topology when explicitly requested',
|
|
20
|
+
].join('\n'));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function handleRemoteCancelCommand(
|
|
24
|
+
agentId: string | undefined,
|
|
25
|
+
activeConnections: RemoteConnectionLike[],
|
|
26
|
+
ctx: RemoteCancelContext,
|
|
27
|
+
agentManager: RemoteCancelAgentManager,
|
|
28
|
+
acpManager?: RemoteCancelAcpManager,
|
|
29
|
+
): void {
|
|
30
|
+
if (!agentId) {
|
|
31
|
+
ctx.print('Usage: /remote cancel <agentId>');
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const connection = activeConnections.find((entry) => entry.agentId === agentId);
|
|
35
|
+
if (!connection) {
|
|
36
|
+
ctx.print(`Unknown remote connection: ${agentId}`);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const localAgentCancelled = agentManager.cancel(agentId);
|
|
40
|
+
if (localAgentCancelled) {
|
|
41
|
+
ctx.print(`Cancelled remote agent ${agentId}.`);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (!acpManager) {
|
|
45
|
+
ctx.print(`Remote agent ${agentId} could not be cancelled in this runtime.`);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
void acpManager.cancel(agentId);
|
|
49
|
+
ctx.print(`Cancellation requested for remote runner ${agentId}.`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function registerRemoteRuntimeCommands(registry: CommandRegistry): void {
|
|
53
|
+
registry.register({
|
|
54
|
+
name: 'remote',
|
|
55
|
+
aliases: [],
|
|
56
|
+
description: 'Inspect, dispatch, and review self-hosted remote runners and artifacts',
|
|
57
|
+
usage: '[list | show [agentId] | supervisor [runnerId] | capabilities [runnerId] | recover [runnerId] | setup [export <path>] | env [export <path>] | tunnel [review|export <path>] | bootstrap [export <path>|inspect <path>] | session <export|inspect|import> <path> | pool <list|show|create|assign|unassign> ... | dispatch [template] <description> | dispatch-pool <pool> [template] <description> | contract [agentId] | cancel <agentId> | export <agentId> [path] | artifact list | artifact show <id> | artifact export <id> [path] | review <id> | rerun-local <id> | import <path>]',
|
|
58
|
+
async handler(args, ctx) {
|
|
59
|
+
if (args.length === 0) {
|
|
60
|
+
if (ctx.openRemotePanel) {
|
|
61
|
+
ctx.openRemotePanel();
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
ctx.print('Remote panel is not available in this runtime.');
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let peerClient;
|
|
69
|
+
try {
|
|
70
|
+
peerClient = requirePeerClient(ctx);
|
|
71
|
+
} catch {
|
|
72
|
+
ctx.print('Remote runtime services are not available in this runtime.');
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const peerSnapshot = peerClient.getSnapshot();
|
|
76
|
+
const remoteRunners = peerClient.runners;
|
|
77
|
+
const activeConnections = [...peerSnapshot.acp.activeConnections];
|
|
78
|
+
const subcommand = args[0]?.toLowerCase() ?? 'show';
|
|
79
|
+
|
|
80
|
+
if (await handleRemoteSetupCommand(args, ctx, activeConnections, {
|
|
81
|
+
listContracts: () => remoteRunners.listContracts(),
|
|
82
|
+
exportSessionBundle: (path) => remoteRunners.exportSessionBundle(path),
|
|
83
|
+
importSessionBundle: (path) => remoteRunners.importSessionBundle(path),
|
|
84
|
+
})) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (subcommand === 'list') {
|
|
89
|
+
const supervisor = peerSnapshot.supervisor;
|
|
90
|
+
const contracts = peerSnapshot.runners.contracts;
|
|
91
|
+
const pools = peerSnapshot.runners.pools;
|
|
92
|
+
const artifacts = peerSnapshot.runners.artifacts;
|
|
93
|
+
const lines = [
|
|
94
|
+
'Remote Control Surface',
|
|
95
|
+
` active connections: ${activeConnections.length}`,
|
|
96
|
+
` runner contracts: ${contracts.length}`,
|
|
97
|
+
` runner pools: ${pools.length}`,
|
|
98
|
+
` review artifacts: ${artifacts.length}`,
|
|
99
|
+
` supervisor sessions: ${supervisor.sessions.length}`,
|
|
100
|
+
` degraded sessions: ${supervisor.degradedConnections}`,
|
|
101
|
+
];
|
|
102
|
+
if (activeConnections.length > 0) {
|
|
103
|
+
lines.push(' connections:');
|
|
104
|
+
for (const connection of activeConnections.slice(0, 12)) {
|
|
105
|
+
lines.push(` ${connection.agentId} ${connection.transportState} msgs=${connection.messageCount} errs=${connection.errorCount} ${connection.label}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (contracts.length > 0) {
|
|
109
|
+
lines.push(' contracts:');
|
|
110
|
+
for (const contract of contracts.slice(0, 12)) {
|
|
111
|
+
lines.push(` ${contract.runnerId} ${contract.template} ${contract.transport.state} ${contract.capabilityCeiling.executionProtocol}/${contract.capabilityCeiling.reviewMode}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
ctx.print(lines.join('\n'));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (subcommand === 'supervisor') {
|
|
119
|
+
const snapshot = peerSnapshot.supervisor;
|
|
120
|
+
const runnerId = args[1];
|
|
121
|
+
const selected = runnerId
|
|
122
|
+
? snapshot.sessions.find((entry) => entry.runnerId === runnerId)
|
|
123
|
+
: snapshot.sessions[0];
|
|
124
|
+
if (!selected) {
|
|
125
|
+
ctx.print(runnerId ? `Unknown remote supervisor session: ${runnerId}` : 'No remote supervisor sessions are currently tracked.');
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
ctx.print([
|
|
129
|
+
`Remote Supervisor ${selected.runnerId}`,
|
|
130
|
+
` label: ${selected.label}`,
|
|
131
|
+
` transport: ${selected.transportState}`,
|
|
132
|
+
` heartbeat: ${selected.heartbeat.status}`,
|
|
133
|
+
` heartbeat detail: ${selected.heartbeat.detail}`,
|
|
134
|
+
` executionProtocol: ${selected.negotiation.executionProtocol}`,
|
|
135
|
+
` reviewMode: ${selected.negotiation.reviewMode}`,
|
|
136
|
+
` communicationLane: ${selected.negotiation.communicationLane}`,
|
|
137
|
+
` trustClass: ${selected.negotiation.trustClass}`,
|
|
138
|
+
` taskId: ${selected.taskId ?? 'n/a'}`,
|
|
139
|
+
` messageCount: ${selected.messageCount}`,
|
|
140
|
+
` errorCount: ${selected.errorCount}`,
|
|
141
|
+
...(selected.lastError ? [` lastError: ${selected.lastError}`] : []),
|
|
142
|
+
' capabilities:',
|
|
143
|
+
...selected.capabilities.map((capability) => ` ${capability.id}: ${capability.supported ? 'yes' : 'no'} (${capability.detail})`),
|
|
144
|
+
' recovery:',
|
|
145
|
+
...selected.recovery.map((action) => ` ${action.command} — ${action.reason}`),
|
|
146
|
+
].join('\n'));
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (subcommand === 'capabilities') {
|
|
151
|
+
const snapshot = peerSnapshot.supervisor;
|
|
152
|
+
const runnerId = args[1];
|
|
153
|
+
const selected = runnerId
|
|
154
|
+
? snapshot.sessions.find((entry) => entry.runnerId === runnerId)
|
|
155
|
+
: snapshot.sessions[0];
|
|
156
|
+
if (!selected) {
|
|
157
|
+
ctx.print(runnerId ? `Unknown remote runner: ${runnerId}` : 'No remote supervisor sessions are currently tracked.');
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
ctx.print([
|
|
161
|
+
`Remote Capabilities ${selected.runnerId}`,
|
|
162
|
+
` label: ${selected.label}`,
|
|
163
|
+
` transport: ${selected.transportState}`,
|
|
164
|
+
` executionProtocol: ${selected.negotiation.executionProtocol}`,
|
|
165
|
+
` reviewMode: ${selected.negotiation.reviewMode}`,
|
|
166
|
+
` communicationLane: ${selected.negotiation.communicationLane}`,
|
|
167
|
+
` trustClass: ${selected.negotiation.trustClass}`,
|
|
168
|
+
' capabilities:',
|
|
169
|
+
...selected.capabilities.map((capability) => (
|
|
170
|
+
` ${capability.id}: ${capability.supported ? 'supported' : 'missing'} — ${capability.detail}`
|
|
171
|
+
)),
|
|
172
|
+
].join('\n'));
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (subcommand === 'recover') {
|
|
177
|
+
const snapshot = peerSnapshot.supervisor;
|
|
178
|
+
const runnerId = args[1];
|
|
179
|
+
const selected = runnerId
|
|
180
|
+
? snapshot.sessions.find((entry) => entry.runnerId === runnerId)
|
|
181
|
+
: snapshot.sessions.find((entry) => entry.recovery.length > 0) ?? snapshot.sessions[0];
|
|
182
|
+
if (!selected) {
|
|
183
|
+
ctx.print(runnerId ? `Unknown remote runner: ${runnerId}` : 'No remote supervisor sessions are currently tracked.');
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const nextSteps = selected.recovery.length > 0
|
|
187
|
+
? selected.recovery
|
|
188
|
+
: [{
|
|
189
|
+
id: 'show',
|
|
190
|
+
label: 'Review remote runtime',
|
|
191
|
+
command: `/remote show ${selected.runnerId}`,
|
|
192
|
+
reason: 'Inspect the current remote session before deciding on recovery.',
|
|
193
|
+
}];
|
|
194
|
+
ctx.print([
|
|
195
|
+
`Remote Recovery ${selected.runnerId}`,
|
|
196
|
+
` label: ${selected.label}`,
|
|
197
|
+
` transport: ${selected.transportState}`,
|
|
198
|
+
` heartbeat: ${selected.heartbeat.status}`,
|
|
199
|
+
` detail: ${selected.heartbeat.detail}`,
|
|
200
|
+
...(selected.lastError ? [` lastError: ${selected.lastError}`] : []),
|
|
201
|
+
...(selected.taskId ? [` bound task: ${selected.taskId}`] : []),
|
|
202
|
+
' actions:',
|
|
203
|
+
...nextSteps.map((action) => ` ${action.command} — ${action.reason}`),
|
|
204
|
+
].join('\n'));
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (handleRemotePoolCommand(args, ctx, remoteRunners)) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (subcommand === 'show') {
|
|
213
|
+
const agentId = args[1];
|
|
214
|
+
const connection = agentId
|
|
215
|
+
? activeConnections.find((entry) => entry.agentId === agentId)
|
|
216
|
+
: activeConnections[0];
|
|
217
|
+
if (!connection) {
|
|
218
|
+
ctx.print(agentId ? `Unknown remote connection: ${agentId}` : 'No active remote connections.');
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
const contract = remoteRunners.upsertContractForAgent(connection.agentId);
|
|
222
|
+
ctx.print([
|
|
223
|
+
`Remote connection ${connection.agentId}`,
|
|
224
|
+
` label: ${connection.label}`,
|
|
225
|
+
` transport: ${connection.transportState}`,
|
|
226
|
+
` completing: ${connection.completing ? 'yes' : 'no'}`,
|
|
227
|
+
` connectedAt: ${connection.connectedAt ? new Date(connection.connectedAt).toISOString() : 'n/a'}`,
|
|
228
|
+
` messageCount: ${connection.messageCount}`,
|
|
229
|
+
` errorCount: ${connection.errorCount}`,
|
|
230
|
+
` taskId: ${connection.taskId ?? 'n/a'}`,
|
|
231
|
+
` lastError: ${connection.lastError ?? 'n/a'}`,
|
|
232
|
+
` contract: ${contract?.id ?? 'n/a'}`,
|
|
233
|
+
` pool: ${contract?.poolId ?? 'n/a'}`,
|
|
234
|
+
` executionProtocol: ${contract?.capabilityCeiling.executionProtocol ?? 'n/a'}`,
|
|
235
|
+
` reviewMode: ${contract?.capabilityCeiling.reviewMode ?? 'n/a'}`,
|
|
236
|
+
` communicationLane: ${contract?.capabilityCeiling.communicationLane ?? 'n/a'}`,
|
|
237
|
+
].join('\n'));
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (subcommand === 'dispatch') {
|
|
242
|
+
let template = 'general';
|
|
243
|
+
let descriptionArgs = args.slice(1);
|
|
244
|
+
if (descriptionArgs.length > 0 && descriptionArgs[0] in AGENT_TEMPLATES) {
|
|
245
|
+
template = descriptionArgs[0]!;
|
|
246
|
+
descriptionArgs = descriptionArgs.slice(1);
|
|
247
|
+
}
|
|
248
|
+
const description = descriptionArgs.join(' ').trim();
|
|
249
|
+
if (description.length === 0) {
|
|
250
|
+
ctx.print('Usage: /remote dispatch [template] <description>');
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
printRemoteDelegationBoundary(ctx, `/remote dispatch ${template} ${description}`);
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (subcommand === 'dispatch-pool') {
|
|
258
|
+
const poolId = args[1];
|
|
259
|
+
if (!poolId) {
|
|
260
|
+
ctx.print('Usage: /remote dispatch-pool <pool> [template] <description>');
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
const pool = remoteRunners.getPool(poolId);
|
|
264
|
+
if (!pool) {
|
|
265
|
+
ctx.print(`Unknown remote runner pool: ${poolId}`);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
let template = pool.preferredTemplate ?? 'general';
|
|
269
|
+
let descriptionArgs = args.slice(2);
|
|
270
|
+
if (descriptionArgs.length > 0 && descriptionArgs[0] in AGENT_TEMPLATES) {
|
|
271
|
+
template = descriptionArgs[0]!;
|
|
272
|
+
descriptionArgs = descriptionArgs.slice(1);
|
|
273
|
+
}
|
|
274
|
+
const description = descriptionArgs.join(' ').trim();
|
|
275
|
+
if (description.length === 0) {
|
|
276
|
+
ctx.print('Usage: /remote dispatch-pool <pool> [template] <description>');
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
printRemoteDelegationBoundary(ctx, `/remote dispatch-pool ${pool.id} ${template} ${description}`);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (subcommand === 'contract') {
|
|
284
|
+
const agentId = args[1] ?? activeConnections[0]?.agentId;
|
|
285
|
+
if (!agentId) {
|
|
286
|
+
ctx.print('No remote runner contracts are available yet.');
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
const contract = remoteRunners.upsertContractForAgent(agentId);
|
|
290
|
+
if (!contract) {
|
|
291
|
+
ctx.print(`Unknown remote runner: ${agentId}`);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
ctx.print([
|
|
295
|
+
`Remote runner contract ${contract.id}`,
|
|
296
|
+
` runnerId: ${contract.runnerId}`,
|
|
297
|
+
` label: ${contract.label}`,
|
|
298
|
+
` pool: ${contract.poolId ?? '(none)'}`,
|
|
299
|
+
` trustClass: ${contract.trustClass}`,
|
|
300
|
+
` template: ${contract.template}`,
|
|
301
|
+
` transport: ${contract.transport.state}`,
|
|
302
|
+
` tools: ${contract.capabilityCeiling.allowedTools.join(', ') || '(none)'}`,
|
|
303
|
+
` ceiling: ${contract.capabilityCeiling.capabilityCeilingTools.join(', ') || '(none)'}`,
|
|
304
|
+
` protocol: ${contract.capabilityCeiling.executionProtocol}`,
|
|
305
|
+
` reviewMode: ${contract.capabilityCeiling.reviewMode}`,
|
|
306
|
+
` communicationLane: ${contract.capabilityCeiling.communicationLane}`,
|
|
307
|
+
` writeScope: ${contract.capabilityCeiling.writeScope.join(', ') || '(none)'}`,
|
|
308
|
+
].join('\n'));
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (subcommand === 'cancel') {
|
|
313
|
+
if (!ctx.ops.agentManager) {
|
|
314
|
+
ctx.print('Agent manager is not available in this runtime.');
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
handleRemoteCancelCommand(
|
|
318
|
+
args[1],
|
|
319
|
+
activeConnections,
|
|
320
|
+
ctx,
|
|
321
|
+
requireAgentManager(ctx),
|
|
322
|
+
ctx.ops.acpManager ? requireAcpManager(ctx) : undefined,
|
|
323
|
+
);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (subcommand === 'export') {
|
|
328
|
+
const agentId = args[1];
|
|
329
|
+
if (!agentId) {
|
|
330
|
+
ctx.print('Usage: /remote export <agentId> [path]');
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
const artifact = remoteRunners.captureArtifactForRunner(agentId);
|
|
334
|
+
if (!artifact) {
|
|
335
|
+
ctx.print(`Remote artifact export failed for ${agentId}.`);
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
const exported = await remoteRunners.exportArtifact(artifact.id, args[2]);
|
|
339
|
+
if (!exported) {
|
|
340
|
+
ctx.print(`Remote artifact export failed for ${agentId}.`);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
ctx.print(`Exported remote review artifact ${exported.artifact.id} to ${exported.path}`);
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (subcommand === 'artifact') {
|
|
348
|
+
const mode = args[1]?.toLowerCase() ?? 'list';
|
|
349
|
+
if (mode === 'list') {
|
|
350
|
+
const artifacts = remoteRunners.listArtifacts();
|
|
351
|
+
if (artifacts.length === 0) {
|
|
352
|
+
ctx.print('No remote review artifacts captured yet.');
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
ctx.print([
|
|
356
|
+
`Remote Review Artifacts (${artifacts.length})`,
|
|
357
|
+
...artifacts.slice(0, 12).map((artifact) => (
|
|
358
|
+
` ${artifact.id} ${artifact.runnerId} ${artifact.task.status} ${artifact.task.summary}`
|
|
359
|
+
)),
|
|
360
|
+
].join('\n'));
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
if (mode === 'show') {
|
|
364
|
+
const artifactId = args[2];
|
|
365
|
+
if (!artifactId) {
|
|
366
|
+
ctx.print('Usage: /remote artifact show <artifactId>');
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
const summary = remoteRunners.buildReviewSummary(artifactId);
|
|
370
|
+
ctx.print(summary ?? `Unknown remote artifact: ${artifactId}`);
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
if (mode === 'export') {
|
|
374
|
+
const artifactId = args[2];
|
|
375
|
+
if (!artifactId) {
|
|
376
|
+
ctx.print('Usage: /remote artifact export <artifactId> [path]');
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
const exported = await remoteRunners.exportArtifact(artifactId, args[3]);
|
|
380
|
+
if (!exported) {
|
|
381
|
+
ctx.print(`Unknown remote artifact: ${artifactId}`);
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
ctx.print(`Exported remote review artifact ${exported.artifact.id} to ${exported.path}`);
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
ctx.print(`Unknown remote artifact subcommand: ${mode}`);
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (subcommand === 'review') {
|
|
392
|
+
const artifactId = args[1];
|
|
393
|
+
if (!artifactId) {
|
|
394
|
+
ctx.print('Usage: /remote review <artifactId>');
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
const summary = remoteRunners.buildReviewSummary(artifactId);
|
|
398
|
+
ctx.print(summary ?? `Unknown remote artifact: ${artifactId}`);
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
if (subcommand === 'rerun-local') {
|
|
403
|
+
const artifactId = args[1];
|
|
404
|
+
if (!artifactId) {
|
|
405
|
+
ctx.print('Usage: /remote rerun-local <artifactId>');
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
const artifact = remoteRunners.getArtifact(artifactId);
|
|
409
|
+
if (!artifact) {
|
|
410
|
+
ctx.print(`Unknown remote artifact: ${artifactId}`);
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
printRemoteDelegationBoundary(ctx, `/remote rerun-local ${artifactId}`);
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
if (subcommand === 'import') {
|
|
418
|
+
const path = args[1];
|
|
419
|
+
if (!path) {
|
|
420
|
+
ctx.print('Usage: /remote import <path>');
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
const artifact = await remoteRunners.importArtifact(path);
|
|
424
|
+
ctx.print(`Imported remote review artifact ${artifact.id} for runner ${artifact.runnerId}.`);
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
ctx.print(`Unknown remote subcommand: ${subcommand}`);
|
|
429
|
+
},
|
|
430
|
+
});
|
|
431
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { CommandRegistry } from '../command-registry.ts';
|
|
2
|
+
import { handleReplayCommand } from '@pellux/goodvibes-sdk/platform/core';
|
|
3
|
+
import { requireReplayEngine } from './runtime-services.ts';
|
|
4
|
+
|
|
5
|
+
export function registerReplayRuntimeCommands(registry: CommandRegistry): void {
|
|
6
|
+
registry.register({
|
|
7
|
+
name: 'replay',
|
|
8
|
+
aliases: ['rep'],
|
|
9
|
+
description: 'Deterministic replay: load, step, seek, diff, and export recorded runs',
|
|
10
|
+
usage: '[load [runId] | step [n] | seek <rev> | diff | export <path>]',
|
|
11
|
+
argsHint: '[load|step|seek|diff|export]',
|
|
12
|
+
handler(args, ctx) {
|
|
13
|
+
const replayEngine = requireReplayEngine(ctx);
|
|
14
|
+
const result = handleReplayCommand({ replayEngine }, args[0] ?? 'help', args.slice(1));
|
|
15
|
+
ctx.print(result.output);
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
}
|