@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,392 @@
|
|
|
1
|
+
import type { CommandRegistry } from '../command-registry.ts';
|
|
2
|
+
import { ToolContractVerifier } from '@/runtime/index.ts';
|
|
3
|
+
import type { ReplaySnapshotInput } from '@/runtime/index.ts';
|
|
4
|
+
import { logger } from '@pellux/goodvibes-sdk/platform/utils';
|
|
5
|
+
import { registerOperatorPanelCommand } from './operator-panel-runtime.ts';
|
|
6
|
+
import { requireOpsApi, requireProfileManager, requireReplayEngine } from './runtime-services.ts';
|
|
7
|
+
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
8
|
+
|
|
9
|
+
export function registerOperatorRuntimeCommands(registry: CommandRegistry): void {
|
|
10
|
+
registerOperatorPanelCommand(registry);
|
|
11
|
+
|
|
12
|
+
registry.register({
|
|
13
|
+
name: 'settings',
|
|
14
|
+
aliases: ['cfg-ui'],
|
|
15
|
+
description: 'Open the fullscreen configuration workspace',
|
|
16
|
+
handler(_args, ctx) {
|
|
17
|
+
if (ctx.openSettingsModal) ctx.openSettingsModal();
|
|
18
|
+
else ctx.print('Configuration workspace is not available in this runtime.');
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
registry.register({
|
|
23
|
+
name: 'context',
|
|
24
|
+
aliases: ['ctx'],
|
|
25
|
+
description: 'Inspect context window usage (token breakdown per message)',
|
|
26
|
+
handler: (_args, ctx) => {
|
|
27
|
+
if (ctx.openContextInspector) {
|
|
28
|
+
ctx.openContextInspector();
|
|
29
|
+
} else {
|
|
30
|
+
const msgs = ctx.session.conversationManager.getMessagesForLLM();
|
|
31
|
+
if (msgs.length === 0) {
|
|
32
|
+
ctx.print('[context] No messages in conversation.');
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const estimateTokens = (text: string): number => Math.ceil(text.length / 4);
|
|
36
|
+
let total = 0;
|
|
37
|
+
const lines: string[] = ['Context breakdown:'];
|
|
38
|
+
for (const m of msgs) {
|
|
39
|
+
const text = typeof m.content === 'string'
|
|
40
|
+
? m.content
|
|
41
|
+
: (m.content as Array<{ type: string; text?: string }>)
|
|
42
|
+
.filter((p) => p.type === 'text')
|
|
43
|
+
.map((p) => p.text ?? '')
|
|
44
|
+
.join('');
|
|
45
|
+
const t = estimateTokens(text);
|
|
46
|
+
total += t;
|
|
47
|
+
lines.push(` ${m.role.padEnd(12)} ~${t.toLocaleString()} tokens`);
|
|
48
|
+
}
|
|
49
|
+
lines.push(` ${'Total'.padEnd(12)} ~${total.toLocaleString()} tokens (${msgs.length} messages)`);
|
|
50
|
+
ctx.print(lines.join('\n'));
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
registry.register({
|
|
56
|
+
name: 'next-error',
|
|
57
|
+
aliases: ['ne'],
|
|
58
|
+
description: 'Jump to the next error message in the conversation',
|
|
59
|
+
handler(_args, ctx) {
|
|
60
|
+
const nextLine = ctx.session.conversationManager.nextErrorLine(ctx.getScrollTop?.() ?? 0);
|
|
61
|
+
if (nextLine < 0) ctx.print('[No error messages found in conversation]');
|
|
62
|
+
else ctx.scrollToLine?.(nextLine);
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
registry.register({
|
|
67
|
+
name: 'profiles',
|
|
68
|
+
aliases: ['profile'],
|
|
69
|
+
description: 'Browse and load config profiles',
|
|
70
|
+
handler(_args, ctx) {
|
|
71
|
+
if (ctx.openProfilePicker) {
|
|
72
|
+
ctx.openProfilePicker();
|
|
73
|
+
} else {
|
|
74
|
+
const profiles = requireProfileManager(ctx).list();
|
|
75
|
+
if (profiles.length === 0) ctx.print('No profiles saved. Open /profiles and press s to save the current settings as a profile.');
|
|
76
|
+
else ctx.print(['Saved profiles:', ...profiles.map(p => ` ${p.name}`)].join('\n'));
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
registry.register({
|
|
82
|
+
name: 'prev-error',
|
|
83
|
+
aliases: ['pe'],
|
|
84
|
+
description: 'Jump to the previous error message in the conversation',
|
|
85
|
+
handler(_args, ctx) {
|
|
86
|
+
const prevLine = ctx.session.conversationManager.prevErrorLine(ctx.getScrollTop?.() ?? 0);
|
|
87
|
+
if (prevLine < 0) ctx.print('[No error messages found in conversation]');
|
|
88
|
+
else ctx.scrollToLine?.(prevLine);
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
registry.register({
|
|
93
|
+
name: 'mode',
|
|
94
|
+
aliases: ['hitl'],
|
|
95
|
+
description: 'Manage HITL UX notification mode (quiet/balanced/operator)',
|
|
96
|
+
usage: '[quiet|balanced|operator|show|set-domain <domain> <verbosity>]',
|
|
97
|
+
argsHint: '[preset|show|set-domain]',
|
|
98
|
+
handler(args, ctx) {
|
|
99
|
+
const mgr = ctx.ops.modeManager;
|
|
100
|
+
if (!mgr) {
|
|
101
|
+
ctx.print('Interaction mode manager is not available in this runtime.');
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const sub = args[0] ?? 'show';
|
|
105
|
+
|
|
106
|
+
if (sub === 'quiet' || sub === 'balanced' || sub === 'operator') {
|
|
107
|
+
const newMode = sub as 'quiet' | 'balanced' | 'operator';
|
|
108
|
+
mgr.setHITLMode(newMode);
|
|
109
|
+
try {
|
|
110
|
+
ctx.platform.configManager.setDynamic('behavior.hitlMode' as import('@pellux/goodvibes-sdk/platform/config').ConfigKey, newMode);
|
|
111
|
+
} catch (e) {
|
|
112
|
+
logger.warn('[/mode] Failed to persist mode', { error: summarizeError(e) });
|
|
113
|
+
}
|
|
114
|
+
const preset = mgr.getHITLPreset();
|
|
115
|
+
ctx.print(`HITL mode set to: ${preset.name}\n${preset.description}`);
|
|
116
|
+
ctx.renderRequest();
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (sub === 'show') {
|
|
121
|
+
const current = mgr.getHITLMode();
|
|
122
|
+
const preset = mgr.getHITLPreset();
|
|
123
|
+
const overrides = mgr.getDomainOverrides();
|
|
124
|
+
const lines: string[] = [
|
|
125
|
+
`HITL mode: ${current}`,
|
|
126
|
+
` ${preset.description}`,
|
|
127
|
+
` Default domain verbosity: ${preset.defaultDomainVerbosity}`,
|
|
128
|
+
` Quiet-while-typing: ${preset.quietWhileTyping}`,
|
|
129
|
+
` Batch window: ${preset.batchWindowMs}ms`,
|
|
130
|
+
];
|
|
131
|
+
const overrideEntries = Object.entries(overrides);
|
|
132
|
+
if (overrideEntries.length > 0) {
|
|
133
|
+
lines.push(' Per-domain overrides:');
|
|
134
|
+
for (const [domain, verbosity] of overrideEntries) lines.push(` ${domain}: ${verbosity}`);
|
|
135
|
+
} else {
|
|
136
|
+
lines.push(' No per-domain overrides.');
|
|
137
|
+
}
|
|
138
|
+
lines.push('');
|
|
139
|
+
lines.push('Available presets:');
|
|
140
|
+
for (const p of mgr.listHITLPresets()) {
|
|
141
|
+
const marker = p.name === current ? '\u25b6' : ' ';
|
|
142
|
+
lines.push(` ${marker} ${p.name.padEnd(10)} ${p.description}`);
|
|
143
|
+
}
|
|
144
|
+
ctx.print(lines.join('\n'));
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (sub === 'set-domain') {
|
|
149
|
+
const domain = args[1];
|
|
150
|
+
const verbosity = args[2];
|
|
151
|
+
if (!domain || !verbosity) {
|
|
152
|
+
ctx.print('Usage: /mode set-domain <domain> <minimal|normal|verbose>');
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (verbosity !== 'minimal' && verbosity !== 'normal' && verbosity !== 'verbose') {
|
|
156
|
+
ctx.print(`Invalid verbosity "${verbosity}". Valid values: minimal, normal, verbose`);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
mgr.setDomainVerbosity(domain, verbosity as 'minimal' | 'normal' | 'verbose');
|
|
160
|
+
ctx.print(`Domain "${domain}" verbosity set to: ${verbosity}`);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
ctx.print(
|
|
165
|
+
'Usage: /mode [quiet|balanced|operator|show|set-domain <domain> <verbosity>]\n'
|
|
166
|
+
+ ' /mode — show current mode and settings\n'
|
|
167
|
+
+ ' /mode show — show current mode and settings\n'
|
|
168
|
+
+ ' /mode quiet — suppress all non-critical notifications\n'
|
|
169
|
+
+ ' /mode balanced — surface warnings, batch info noise (default)\n'
|
|
170
|
+
+ ' /mode operator — full verbosity, no suppression\n'
|
|
171
|
+
+ ' /mode set-domain <d> <v> — per-domain verbosity override (minimal|normal|verbose)'
|
|
172
|
+
);
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
registry.register({
|
|
177
|
+
name: 'ops',
|
|
178
|
+
description: 'Operator Control Plane: view audit log, cancel/pause/resume/retry tasks and agents',
|
|
179
|
+
usage: 'view | task <cancel|pause|resume|retry> <id> [note] | agent cancel <id> [note]',
|
|
180
|
+
argsHint: '[view|task|agent]',
|
|
181
|
+
handler(args, ctx) {
|
|
182
|
+
const sub = args[0];
|
|
183
|
+
|
|
184
|
+
if (sub === 'view' || sub === undefined) {
|
|
185
|
+
if (ctx.openOpsPanel) ctx.openOpsPanel();
|
|
186
|
+
else ctx.print('Operator Control Plane panel is not available. Enable the operator-control-plane feature flag.');
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (sub === 'task') {
|
|
191
|
+
const action = args[1];
|
|
192
|
+
const taskId = args[2];
|
|
193
|
+
const note = args.slice(3).join(' ') || undefined;
|
|
194
|
+
if (!action || !taskId) {
|
|
195
|
+
ctx.print('Usage: /ops task <cancel|pause|resume|retry> <task-id> [note]');
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const opsApi = requireOpsApi(ctx);
|
|
199
|
+
try {
|
|
200
|
+
switch (action) {
|
|
201
|
+
case 'cancel': opsApi.tasks.cancel(taskId, note); break;
|
|
202
|
+
case 'pause': opsApi.tasks.pause(taskId, note); break;
|
|
203
|
+
case 'resume': opsApi.tasks.resume(taskId, note); break;
|
|
204
|
+
case 'retry': opsApi.tasks.retry(taskId, note); break;
|
|
205
|
+
default:
|
|
206
|
+
ctx.print(`Unknown task action "${action}". Use: cancel, pause, resume, retry`);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
ctx.print(`[Ops] Task ${taskId}: ${action} dispatched.`);
|
|
210
|
+
} catch (e) {
|
|
211
|
+
ctx.print(`[Ops] Error: ${summarizeError(e)}`);
|
|
212
|
+
}
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (sub === 'agent') {
|
|
217
|
+
const action = args[1];
|
|
218
|
+
const agentId = args[2];
|
|
219
|
+
const note = args.slice(3).join(' ') || undefined;
|
|
220
|
+
if (action !== 'cancel' || !agentId) {
|
|
221
|
+
ctx.print('Usage: /ops agent cancel <agent-id> [note]');
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const opsApi = requireOpsApi(ctx);
|
|
225
|
+
try {
|
|
226
|
+
opsApi.agents.cancel(agentId, note);
|
|
227
|
+
ctx.print(`[Ops] Agent ${agentId}: cancel dispatched.`);
|
|
228
|
+
} catch (e) {
|
|
229
|
+
ctx.print(`[Ops] Error: ${summarizeError(e)}`);
|
|
230
|
+
}
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
ctx.print(
|
|
235
|
+
'Usage: /ops <subcommand>\n'
|
|
236
|
+
+ ' /ops view — open the Ops Control panel (Ctrl+O)\n'
|
|
237
|
+
+ ' /ops task cancel <id> [note] — cancel a task\n'
|
|
238
|
+
+ ' /ops task pause <id> [note] — pause a task\n'
|
|
239
|
+
+ ' /ops task resume <id> [note] — resume a blocked task\n'
|
|
240
|
+
+ ' /ops task retry <id> [note] — retry a failed task\n'
|
|
241
|
+
+ ' /ops agent cancel <id> [note] — cancel a running agent'
|
|
242
|
+
);
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
registry.register({
|
|
247
|
+
name: 'tool',
|
|
248
|
+
description: 'Tool contract verification — verify registered tool contracts',
|
|
249
|
+
usage: 'verify <name> | verify-all | contract show <name>',
|
|
250
|
+
argsHint: 'verify <name> | verify-all | contract show <name>',
|
|
251
|
+
handler(args, ctx) {
|
|
252
|
+
const sub = args[0];
|
|
253
|
+
if (sub === 'verify' && args[1]) {
|
|
254
|
+
const result = ctx.extensions.toolRegistry.verifyContract(args[1]);
|
|
255
|
+
if (!result) {
|
|
256
|
+
ctx.print(`[tool verify] Tool '${args[1]}' is not registered.`);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
ctx.print(ToolContractVerifier.formatResult(result));
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (sub === 'verify-all') {
|
|
263
|
+
ctx.print(ToolContractVerifier.formatAllResults(ctx.extensions.toolRegistry.verifyAllContracts()));
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
if (sub === 'contract' && args[1] === 'show' && args[2]) {
|
|
267
|
+
const toolName = args[2];
|
|
268
|
+
const result = ctx.extensions.toolRegistry.verifyContract(toolName);
|
|
269
|
+
if (!result) {
|
|
270
|
+
ctx.print(`[tool contract show] Tool '${toolName}' is not registered.`);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
const lines: string[] = [ToolContractVerifier.formatResult(result)];
|
|
274
|
+
const tool = ctx.extensions.toolRegistry.list().find((t) => t.definition.name === toolName);
|
|
275
|
+
if (tool) {
|
|
276
|
+
lines.push('');
|
|
277
|
+
lines.push('Tool Definition:');
|
|
278
|
+
lines.push(` Name: ${tool.definition.name}`);
|
|
279
|
+
lines.push(` Description: ${tool.definition.description}`);
|
|
280
|
+
lines.push(` Parameters: ${JSON.stringify(tool.definition.parameters, null, 2).replace(/\n/g, '\n ')}`);
|
|
281
|
+
}
|
|
282
|
+
ctx.print(lines.join('\n'));
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
ctx.print(
|
|
287
|
+
'Usage: /tool <subcommand>\n'
|
|
288
|
+
+ ' /tool verify <name> — verify contract for a specific registered tool\n'
|
|
289
|
+
+ ' /tool verify-all — verify contracts for all registered tools\n'
|
|
290
|
+
+ ' /tool contract show <name> — show full contract details for a tool'
|
|
291
|
+
);
|
|
292
|
+
},
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
registry.register({
|
|
296
|
+
name: 'forensics',
|
|
297
|
+
aliases: ['foren'],
|
|
298
|
+
description: 'Failure Forensics: view, inspect, and export auto-classified failure reports',
|
|
299
|
+
usage: '[latest | show <id> | export <id>]',
|
|
300
|
+
argsHint: '[latest|show|export]',
|
|
301
|
+
handler(args, ctx) {
|
|
302
|
+
const sub = args[0];
|
|
303
|
+
if (sub === undefined || sub === 'view') {
|
|
304
|
+
if (ctx.openForensicsPanel) ctx.openForensicsPanel();
|
|
305
|
+
else ctx.print('Forensics panel is not available.');
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
if (sub === 'latest') {
|
|
309
|
+
if (!ctx.extensions.forensicsRegistry) {
|
|
310
|
+
ctx.print('[Forensics] Registry not active.');
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
const report = ctx.extensions.forensicsRegistry.latest();
|
|
314
|
+
if (!report) {
|
|
315
|
+
ctx.print('[Forensics] No failure reports recorded this session.');
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
const lines: string[] = [
|
|
319
|
+
`[Forensics] Latest failure report (id: ${report.id})`,
|
|
320
|
+
` Time: ${new Date(report.generatedAt).toISOString()}`,
|
|
321
|
+
` Classification: ${report.classification}`,
|
|
322
|
+
` Summary: ${report.summary}`,
|
|
323
|
+
];
|
|
324
|
+
if (report.errorMessage) lines.push(` Error: ${report.errorMessage}`);
|
|
325
|
+
if (report.stopReason) lines.push(` Stop reason: ${report.stopReason}`);
|
|
326
|
+
if (report.taskId) lines.push(` Task ID: ${report.taskId}`);
|
|
327
|
+
if (report.turnId) lines.push(` Turn ID: ${report.turnId}`);
|
|
328
|
+
if (report.causalChain.length > 0) {
|
|
329
|
+
lines.push(' Causal chain:');
|
|
330
|
+
for (const entry of report.causalChain) {
|
|
331
|
+
const marker = entry.isRootCause ? ' ● ' : ' · ';
|
|
332
|
+
lines.push(` ${marker}${entry.description}`);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
if (report.jumpLinks.length > 0) {
|
|
336
|
+
lines.push(' Jump links:');
|
|
337
|
+
for (const link of report.jumpLinks) {
|
|
338
|
+
lines.push(` [${link.kind}] ${link.label} → ${link.target}${link.args ? ` (${link.args})` : ''}`);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
lines.push(` Use "/forensics show ${report.id}" for full JSON.`);
|
|
342
|
+
ctx.print(lines.join('\n'));
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
if (sub === 'show') {
|
|
346
|
+
const id = args[1];
|
|
347
|
+
if (!id) {
|
|
348
|
+
ctx.print('Usage: /forensics show <id>');
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
if (!ctx.extensions.forensicsRegistry) {
|
|
352
|
+
ctx.print('[Forensics] Registry not active.');
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
const json = ctx.extensions.forensicsRegistry.exportAsJson(id);
|
|
356
|
+
if (!json) {
|
|
357
|
+
ctx.print(`[Forensics] No report found with id "${id}". Use /forensics latest to see the most recent.`);
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
ctx.print(json);
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
if (sub === 'export') {
|
|
364
|
+
const id = args[1];
|
|
365
|
+
if (!id) {
|
|
366
|
+
ctx.print('Usage: /forensics export <id>');
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
if (!ctx.extensions.forensicsRegistry) {
|
|
370
|
+
ctx.print('[Forensics] Registry not active.');
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
const json = ctx.extensions.forensicsRegistry.exportBundleAsJson(id, {
|
|
374
|
+
replaySnapshot: requireReplayEngine(ctx).getSnapshot() as ReplaySnapshotInput,
|
|
375
|
+
});
|
|
376
|
+
if (!json) {
|
|
377
|
+
ctx.print(`[Forensics] No report found with id "${id}".`);
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
ctx.print(`[Forensics] Incident bundle ${id}:\n${json}`);
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
ctx.print(
|
|
384
|
+
'Usage: /forensics <subcommand>\n'
|
|
385
|
+
+ ' /forensics — open the Forensics panel\n'
|
|
386
|
+
+ ' /forensics latest — print the most recent failure report summary\n'
|
|
387
|
+
+ ' /forensics show <id> — show full JSON for a specific report\n'
|
|
388
|
+
+ ' /forensics export <id> — export incident bundle JSON to the conversation'
|
|
389
|
+
);
|
|
390
|
+
},
|
|
391
|
+
});
|
|
392
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ProjectPlanningEvaluation,
|
|
3
|
+
ProjectPlanningQuestion,
|
|
4
|
+
ProjectPlanningService,
|
|
5
|
+
ProjectPlanningState,
|
|
6
|
+
} from '@pellux/goodvibes-sdk/platform/knowledge';
|
|
7
|
+
import type { CommandRegistry } from '../command-registry.ts';
|
|
8
|
+
import { requirePlanManager, requireSessionLineageTracker } from './runtime-services.ts';
|
|
9
|
+
|
|
10
|
+
function recordNextQuestion(
|
|
11
|
+
state: Partial<ProjectPlanningState>,
|
|
12
|
+
question: ProjectPlanningQuestion | undefined,
|
|
13
|
+
): Partial<ProjectPlanningState> {
|
|
14
|
+
if (!question) return state;
|
|
15
|
+
const answered = new Set((state.answeredQuestions ?? []).map((entry) => entry.id));
|
|
16
|
+
if (answered.has(question.id)) return state;
|
|
17
|
+
const openQuestions = [...(state.openQuestions ?? [])];
|
|
18
|
+
const existingIndex = openQuestions.findIndex((entry) => entry.id === question.id);
|
|
19
|
+
const normalized = { ...question, status: question.status ?? 'open' } satisfies ProjectPlanningQuestion;
|
|
20
|
+
if (existingIndex >= 0) openQuestions[existingIndex] = normalized;
|
|
21
|
+
else openQuestions.unshift(normalized);
|
|
22
|
+
return { ...state, openQuestions };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function persistEvaluatedNextQuestion(
|
|
26
|
+
service: ProjectPlanningService,
|
|
27
|
+
projectId: string,
|
|
28
|
+
state: ProjectPlanningState,
|
|
29
|
+
evaluation: ProjectPlanningEvaluation,
|
|
30
|
+
): Promise<{ state: ProjectPlanningState; evaluation: ProjectPlanningEvaluation }> {
|
|
31
|
+
if (!evaluation.nextQuestion) return { state, evaluation };
|
|
32
|
+
if (state.openQuestions.some((question) => question.id === evaluation.nextQuestion?.id)) {
|
|
33
|
+
return { state, evaluation };
|
|
34
|
+
}
|
|
35
|
+
const withQuestion = recordNextQuestion(evaluation.state ?? state, evaluation.nextQuestion);
|
|
36
|
+
const saved = await service.upsertState({ projectId, state: withQuestion });
|
|
37
|
+
const nextState = saved.state ?? state;
|
|
38
|
+
const nextEvaluation = await service.evaluate({ projectId, state: nextState });
|
|
39
|
+
return { state: nextState, evaluation: nextEvaluation };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function formatNextQuestion(question: ProjectPlanningQuestion | undefined): string {
|
|
43
|
+
if (!question) return 'No next question recorded.';
|
|
44
|
+
const lines = [`Next question: ${question.prompt}`];
|
|
45
|
+
if (question.recommendedAnswer) lines.push(`Recommended answer: ${question.recommendedAnswer}`);
|
|
46
|
+
lines.push('Answer in the prompt, or focus the Planning panel to choose/type an answer.');
|
|
47
|
+
return lines.join('\n');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function registerPlanningRuntimeCommands(registry: CommandRegistry): void {
|
|
51
|
+
registry.register({
|
|
52
|
+
name: 'plan',
|
|
53
|
+
description: 'Inspect or seed TUI-owned project planning state',
|
|
54
|
+
usage: '[panel | approve | list | show <id> | mode | explain | override <strategy> | status | clear | <planning goal>]',
|
|
55
|
+
argsHint: '[panel|approve|status|<goal>]',
|
|
56
|
+
async handler(args, ctx) {
|
|
57
|
+
const planManager = requirePlanManager(ctx);
|
|
58
|
+
const sessionLineageTracker = requireSessionLineageTracker(ctx);
|
|
59
|
+
const plannerSubs = ['mode', 'explain', 'override', 'status', 'clear'];
|
|
60
|
+
if (args.length > 0 && plannerSubs.includes(args[0].toLowerCase())) {
|
|
61
|
+
const result = ctx.ops.planRuntime
|
|
62
|
+
? ctx.ops.planRuntime(args[0], args.slice(1))
|
|
63
|
+
: { ok: false, output: 'Plan runtime bridge is not available in this runtime.' };
|
|
64
|
+
ctx.print(result.output);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const projectPlanningService = ctx.workspace.projectPlanningService;
|
|
69
|
+
const projectId = ctx.workspace.projectPlanningProjectId;
|
|
70
|
+
const openProjectPlanningPanel = () => ctx.showPanel?.('project-planning');
|
|
71
|
+
|
|
72
|
+
if (args.length === 0) {
|
|
73
|
+
if (projectPlanningService && projectId) {
|
|
74
|
+
const [status, stateResult] = await Promise.all([
|
|
75
|
+
projectPlanningService.status({ projectId }),
|
|
76
|
+
projectPlanningService.getState({ projectId }),
|
|
77
|
+
]);
|
|
78
|
+
const initialEvaluation = await projectPlanningService.evaluate({
|
|
79
|
+
projectId,
|
|
80
|
+
...(stateResult.state ? { state: stateResult.state } : {}),
|
|
81
|
+
});
|
|
82
|
+
const { evaluation } = stateResult.state
|
|
83
|
+
? await persistEvaluatedNextQuestion(projectPlanningService, projectId, stateResult.state, initialEvaluation)
|
|
84
|
+
: { evaluation: initialEvaluation };
|
|
85
|
+
openProjectPlanningPanel();
|
|
86
|
+
ctx.print(
|
|
87
|
+
`Project planning: ${evaluation.readiness}\n` +
|
|
88
|
+
`Project: ${status.projectId}\n` +
|
|
89
|
+
`Knowledge space: ${status.knowledgeSpaceId}\n` +
|
|
90
|
+
`Artifacts: ${status.counts.states} state, ${status.counts.decisions} decisions, ${status.counts.languageArtifacts} language\n` +
|
|
91
|
+
formatNextQuestion(evaluation.nextQuestion),
|
|
92
|
+
);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const active = planManager.getActive(ctx.session.runtime.sessionId);
|
|
96
|
+
if (!active) {
|
|
97
|
+
ctx.print('No active execution plan.');
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const summary = planManager.getSummary(active);
|
|
101
|
+
ctx.print(`Active plan: "${active.title}" [${active.status.toUpperCase()}]\n${summary}`);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (args[0] === 'panel') {
|
|
106
|
+
openProjectPlanningPanel();
|
|
107
|
+
ctx.print('Opened project planning panel.');
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (args[0] === 'approve') {
|
|
112
|
+
if (!projectPlanningService || !projectId) {
|
|
113
|
+
ctx.print('Project planning service is not available in this runtime.');
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const current = await projectPlanningService.getState({ projectId });
|
|
117
|
+
if (!current.state) {
|
|
118
|
+
ctx.print('No project planning state exists to approve.');
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const result = await projectPlanningService.upsertState({
|
|
122
|
+
projectId,
|
|
123
|
+
state: {
|
|
124
|
+
...current.state,
|
|
125
|
+
executionApproved: true,
|
|
126
|
+
metadata: {
|
|
127
|
+
...(current.state.metadata ?? {}),
|
|
128
|
+
approvedFrom: 'plan-command',
|
|
129
|
+
approvedAt: Date.now(),
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
const evaluation = await projectPlanningService.evaluate({ projectId });
|
|
134
|
+
openProjectPlanningPanel();
|
|
135
|
+
ctx.print(`Project planning approved. Readiness: ${evaluation.readiness}. State: ${result.state?.id ?? 'current'}.`);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (args[0] === 'list') {
|
|
140
|
+
const plans = planManager.list();
|
|
141
|
+
if (plans.length === 0) {
|
|
142
|
+
ctx.print('No plans found.');
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
ctx.print(`Plans (${plans.length}):\n${plans.map((plan) => {
|
|
146
|
+
const marker = plan.status === 'active' ? '▶' : ' ';
|
|
147
|
+
return ` ${marker} ${plan.id.slice(0, 8)} [${plan.status.padEnd(8)}] ${plan.title}`;
|
|
148
|
+
}).join('\n')}`);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (args[0] === 'show') {
|
|
153
|
+
const id = args[1];
|
|
154
|
+
if (!id) {
|
|
155
|
+
ctx.print('Usage: /plan show <plan-id>');
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const plans = planManager.list();
|
|
159
|
+
const plan = plans.find((entry) => entry.id === id || entry.id.startsWith(id));
|
|
160
|
+
if (!plan) {
|
|
161
|
+
ctx.print(`Plan not found: ${id}`);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
ctx.print(planManager.toMarkdown(plan));
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const taskDescription = args.join(' ');
|
|
169
|
+
if (!projectPlanningService || !projectId) {
|
|
170
|
+
ctx.print('Project planning service is not available in this runtime.');
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const result = await projectPlanningService.upsertState({
|
|
174
|
+
projectId,
|
|
175
|
+
state: {
|
|
176
|
+
goal: taskDescription,
|
|
177
|
+
knownContext: [
|
|
178
|
+
`Workspace planning was seeded from the TUI /plan command.`,
|
|
179
|
+
],
|
|
180
|
+
metadata: {
|
|
181
|
+
active: true,
|
|
182
|
+
owner: 'tui',
|
|
183
|
+
source: 'plan-command',
|
|
184
|
+
lastPromptAt: Date.now(),
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
const initialEvaluation = await projectPlanningService.evaluate({
|
|
189
|
+
projectId,
|
|
190
|
+
...(result.state ? { state: result.state } : {}),
|
|
191
|
+
});
|
|
192
|
+
const { state, evaluation } = result.state
|
|
193
|
+
? await persistEvaluatedNextQuestion(projectPlanningService, projectId, result.state, initialEvaluation)
|
|
194
|
+
: { state: result.state, evaluation: initialEvaluation };
|
|
195
|
+
sessionLineageTracker.setOriginalTask(taskDescription.slice(0, 200));
|
|
196
|
+
openProjectPlanningPanel();
|
|
197
|
+
|
|
198
|
+
ctx.print(
|
|
199
|
+
`Project planning seeded: "${state?.goal ?? taskDescription}"\n` +
|
|
200
|
+
`Readiness: ${evaluation.readiness}\n` +
|
|
201
|
+
formatNextQuestion(evaluation.nextQuestion),
|
|
202
|
+
);
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
}
|