@pellux/goodvibes-agent 1.1.7 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +170 -0
- package/README.md +46 -30
- package/dist/package/{ast-grep-napi.linux-x64-gnu-mkk8xwww.node → ast-grep-napi.linux-x64-gnu-swtppvy9.node} +0 -0
- package/dist/package/{ast-grep-napi.linux-x64-musl-ryqtgdv6.node → ast-grep-napi.linux-x64-musl-ttfcdtap.node} +0 -0
- package/dist/package/main.js +132577 -91483
- package/docs/README.md +14 -7
- package/docs/channels-remote-and-api.md +8 -5
- package/docs/connected-host.md +14 -12
- package/docs/getting-started.md +56 -30
- package/docs/knowledge-artifacts-and-multimodal.md +7 -5
- package/docs/project-planning.md +2 -2
- package/docs/providers-and-routing.md +11 -3
- package/docs/tools-and-commands.md +114 -45
- package/docs/voice-and-live-tts.md +3 -1
- package/package.json +3 -2
- package/release/release-notes.md +130 -5
- package/release/release-readiness.json +120 -90
- package/src/agent/assistant-cockpit.ts +247 -0
- package/src/agent/autonomy-schedule-format.ts +96 -0
- package/src/agent/autonomy-schedule.ts +514 -0
- package/src/agent/channel-delivery-receipts.ts +292 -0
- package/src/agent/competitive-feature-inventory.ts +296 -0
- package/src/agent/document-registry-types.ts +106 -0
- package/src/agent/document-registry.ts +734 -0
- package/src/agent/harness-control.ts +2 -2
- package/src/agent/memory-prompt.ts +2 -2
- package/src/agent/operator-actions.ts +50 -6
- package/src/agent/persona-registry.ts +8 -0
- package/src/agent/project-context-files.ts +273 -0
- package/src/agent/prompt-context-receipts.ts +502 -0
- package/src/agent/reminder-schedule-format.ts +16 -2
- package/src/agent/research-run-registry.ts +582 -0
- package/src/agent/research-source-registry.ts +441 -0
- package/src/agent/routine-registry.ts +19 -3
- package/src/agent/routine-schedule-format.ts +27 -2
- package/src/agent/runtime-profile-starters.ts +7 -0
- package/src/agent/runtime-profile.ts +106 -4
- package/src/agent/schedule-edit-format.ts +129 -0
- package/src/agent/schedule-edit.ts +496 -0
- package/src/agent/schedule-next-routes.ts +42 -0
- package/src/agent/setup-wizard-checkpoint.ts +140 -0
- package/src/agent/setup-wizard.ts +447 -0
- package/src/agent/skill-registry-types.ts +102 -0
- package/src/agent/skill-registry.ts +81 -107
- package/src/agent/vibe-confirmation-routes.ts +62 -0
- package/src/agent/vibe-file.ts +285 -0
- package/src/cli/agent-knowledge-command.ts +45 -2
- package/src/cli/help.ts +3 -0
- package/src/cli/profiles-command.ts +25 -11
- package/src/config/agent-settings-policy.ts +1 -18
- package/src/input/agent-workspace-activation.ts +53 -0
- package/src/input/agent-workspace-artifact-browser-editor.ts +494 -0
- package/src/input/agent-workspace-artifact-metadata.ts +17 -0
- package/src/input/agent-workspace-basic-command-editors.ts +5 -1
- package/src/input/agent-workspace-categories.ts +153 -155
- package/src/input/agent-workspace-channel-triage.ts +481 -0
- package/src/input/agent-workspace-channels.ts +263 -0
- package/src/input/agent-workspace-command-editor.ts +152 -0
- package/src/input/agent-workspace-context-snapshot.ts +349 -0
- package/src/input/agent-workspace-delegation-editor-submission.ts +8 -0
- package/src/input/agent-workspace-document-editor.ts +502 -0
- package/src/input/agent-workspace-document-ops-editor.ts +523 -0
- package/src/input/agent-workspace-host-category.ts +1 -1
- package/src/input/agent-workspace-local-library-snapshot.ts +167 -0
- package/src/input/agent-workspace-model-compare-editor.ts +376 -0
- package/src/input/agent-workspace-model-compare-prompt-submission.ts +552 -0
- package/src/input/agent-workspace-model-compare-types.ts +82 -0
- package/src/input/agent-workspace-model-compare-utils.ts +35 -0
- package/src/input/agent-workspace-onboarding-categories.ts +141 -0
- package/src/input/agent-workspace-operations-command-editor-submission.ts +53 -0
- package/src/input/agent-workspace-operations-command-editors.ts +22 -0
- package/src/input/agent-workspace-research-report-editor.ts +212 -0
- package/src/input/agent-workspace-research-run-editor.ts +144 -0
- package/src/input/agent-workspace-research-source-editor.ts +167 -0
- package/src/input/agent-workspace-review-packet-snapshot.ts +593 -0
- package/src/input/agent-workspace-review-packet-utils.ts +265 -0
- package/src/input/agent-workspace-settings.ts +262 -30
- package/src/input/agent-workspace-setup-checkpoint-action.ts +127 -0
- package/src/input/agent-workspace-setup-snapshot.ts +198 -0
- package/src/input/agent-workspace-setup.ts +34 -1
- package/src/input/agent-workspace-snapshot.ts +162 -147
- package/src/input/agent-workspace-types.ts +287 -2
- package/src/input/agent-workspace.ts +18 -0
- package/src/input/command-registry.ts +9 -2
- package/src/input/commands/agent-runtime-profile-runtime.ts +28 -13
- package/src/input/commands/channels-runtime.ts +102 -114
- package/src/input/commands/delegation-runtime.ts +87 -24
- package/src/input/commands/knowledge-browser-flags.ts +12 -0
- package/src/input/commands/knowledge.ts +28 -14
- package/src/input/commands/operator-actions-runtime.ts +6 -3
- package/src/input/commands/schedule-runtime.ts +71 -14
- package/src/input/commands/session-content.ts +2 -2
- package/src/input/commands/shell-core.ts +2 -0
- package/src/input/commands/vibe-runtime.ts +140 -0
- package/src/input/commands.ts +2 -0
- package/src/input/connected-host-routes.ts +123 -0
- package/src/input/settings-modal-types.ts +14 -0
- package/src/main.ts +15 -15
- package/src/panels/qr-panel.ts +2 -2
- package/src/renderer/agent-workspace-context-lines.ts +686 -0
- package/src/renderer/agent-workspace.ts +30 -419
- package/src/renderer/settings-modal-helpers.ts +12 -0
- package/src/renderer/settings-modal.ts +12 -0
- package/src/runtime/bootstrap-command-context.ts +11 -1
- package/src/runtime/bootstrap-command-parts.ts +14 -3
- package/src/runtime/bootstrap-core.ts +39 -1
- package/src/runtime/bootstrap-shell.ts +6 -0
- package/src/runtime/bootstrap.ts +113 -30
- package/src/runtime/connected-host-auth.ts +3 -2
- package/src/runtime/execution-ledger.ts +231 -0
- package/src/runtime/services.ts +88 -10
- package/src/runtime/tool-permission-safety.ts +199 -5
- package/src/shell/session-continuity-hints.ts +39 -0
- package/src/tools/agent-artifacts-tool.ts +606 -0
- package/src/tools/agent-audit-tool.ts +155 -0
- package/src/tools/agent-autonomy-schedule-tool.ts +238 -0
- package/src/tools/agent-autonomy-tool.ts +140 -0
- package/src/tools/agent-channel-send-tool.ts +24 -2
- package/src/tools/agent-channels-tool.ts +140 -0
- package/src/tools/agent-computer-tool.ts +168 -0
- package/src/tools/agent-context-policy.ts +137 -7
- package/src/tools/agent-context-tool.ts +143 -0
- package/src/tools/agent-delegation-tool.ts +128 -0
- package/src/tools/agent-device-tool.ts +240 -0
- package/src/tools/agent-documents-tool.ts +684 -0
- package/src/tools/agent-execution-tool.ts +230 -0
- package/src/tools/agent-harness-agent-orchestration.ts +703 -0
- package/src/tools/agent-harness-autonomy-intake.ts +785 -0
- package/src/tools/agent-harness-autonomy-live-records.ts +588 -0
- package/src/tools/agent-harness-autonomy-queue-types.ts +88 -0
- package/src/tools/agent-harness-autonomy-queue.ts +560 -0
- package/src/tools/agent-harness-background-processes-types.ts +35 -0
- package/src/tools/agent-harness-background-processes.ts +794 -0
- package/src/tools/agent-harness-browser-cockpit-route.ts +219 -0
- package/src/tools/agent-harness-browser-control.ts +338 -0
- package/src/tools/agent-harness-channel-metadata.ts +168 -10
- package/src/tools/agent-harness-cli-command-policy.ts +110 -0
- package/src/tools/agent-harness-command-catalog.ts +4 -2
- package/src/tools/agent-harness-command-runner.ts +42 -0
- package/src/tools/agent-harness-connected-host-status.ts +7 -4
- package/src/tools/agent-harness-delegation-posture.ts +234 -19
- package/src/tools/agent-harness-document-ops-reviewer-readiness.ts +234 -0
- package/src/tools/agent-harness-document-ops-types.ts +72 -0
- package/src/tools/agent-harness-document-ops.ts +671 -0
- package/src/tools/agent-harness-execution-history.ts +489 -0
- package/src/tools/agent-harness-execution-posture.ts +382 -0
- package/src/tools/agent-harness-file-recovery.ts +135 -0
- package/src/tools/agent-harness-keybinding-metadata.ts +16 -12
- package/src/tools/agent-harness-learning-curator-common.ts +102 -0
- package/src/tools/agent-harness-learning-curator-consolidation.ts +295 -0
- package/src/tools/agent-harness-learning-curator-proposals.ts +606 -0
- package/src/tools/agent-harness-learning-curator-types.ts +151 -0
- package/src/tools/agent-harness-learning-curator.ts +417 -0
- package/src/tools/agent-harness-local-model-benchmarks.ts +199 -0
- package/src/tools/agent-harness-local-model-cookbook.ts +238 -0
- package/src/tools/agent-harness-local-model-endpoints.ts +673 -0
- package/src/tools/agent-harness-media-posture.ts +208 -2
- package/src/tools/agent-harness-memory-posture.ts +556 -0
- package/src/tools/agent-harness-metadata.ts +100 -168
- package/src/tools/agent-harness-mode-catalog.ts +84 -33
- package/src/tools/agent-harness-model-catalog.ts +162 -0
- package/src/tools/agent-harness-model-provider-health.ts +186 -0
- package/src/tools/agent-harness-model-readiness.ts +406 -0
- package/src/tools/agent-harness-model-routing-types.ts +266 -0
- package/src/tools/agent-harness-model-routing-utils.ts +30 -0
- package/src/tools/agent-harness-model-routing.ts +137 -190
- package/src/tools/agent-harness-operator-methods.ts +115 -133
- package/src/tools/agent-harness-pairing-posture.ts +431 -18
- package/src/tools/agent-harness-personal-ops-discovery.ts +533 -0
- package/src/tools/agent-harness-personal-ops-intake.ts +385 -0
- package/src/tools/agent-harness-personal-ops-lanes.ts +204 -0
- package/src/tools/agent-harness-personal-ops-records.ts +732 -0
- package/src/tools/agent-harness-personal-ops-runner.ts +637 -0
- package/src/tools/agent-harness-personal-ops-types.ts +222 -0
- package/src/tools/agent-harness-personal-ops.ts +606 -0
- package/src/tools/agent-harness-project-context.ts +144 -0
- package/src/tools/agent-harness-prompt-context.ts +589 -0
- package/src/tools/agent-harness-provider-account-metadata.ts +2 -2
- package/src/tools/agent-harness-release-evidence.ts +9 -7
- package/src/tools/agent-harness-release-readiness.ts +9 -7
- package/src/tools/agent-harness-research-briefing.ts +427 -0
- package/src/tools/agent-harness-research-queue.ts +250 -0
- package/src/tools/agent-harness-research-runs.ts +295 -0
- package/src/tools/agent-harness-research-workflow.ts +322 -0
- package/src/tools/agent-harness-security-posture.ts +2 -2
- package/src/tools/agent-harness-service-posture.ts +9 -9
- package/src/tools/agent-harness-session-metadata.ts +3 -3
- package/src/tools/agent-harness-setup-connected-host.ts +501 -0
- package/src/tools/agent-harness-setup-describe.ts +557 -0
- package/src/tools/agent-harness-setup-handoffs.ts +502 -0
- package/src/tools/agent-harness-setup-model-helpers.ts +101 -0
- package/src/tools/agent-harness-setup-plan.ts +253 -0
- package/src/tools/agent-harness-setup-posture-types.ts +218 -0
- package/src/tools/agent-harness-setup-posture-utils.ts +173 -0
- package/src/tools/agent-harness-setup-posture.ts +449 -221
- package/src/tools/agent-harness-setup-smoke.ts +508 -0
- package/src/tools/agent-harness-sudo-posture.ts +114 -0
- package/src/tools/agent-harness-tool-schema.ts +120 -7
- package/src/tools/agent-harness-tool-types.ts +78 -0
- package/src/tools/agent-harness-tool-utils.ts +43 -0
- package/src/tools/agent-harness-tool.ts +311 -370
- package/src/tools/agent-harness-ui-surface-metadata.ts +76 -69
- package/src/tools/agent-harness-ui-surface-types.ts +46 -0
- package/src/tools/agent-harness-vibe-health.ts +105 -0
- package/src/tools/agent-harness-workspace-action-runner.ts +149 -0
- package/src/tools/agent-harness-workspace-actions.ts +114 -8
- package/src/tools/agent-harness-workspace-editor-execution.ts +214 -0
- package/src/tools/agent-harness-workspace-editor-runner.ts +755 -0
- package/src/tools/agent-host-tool.ts +159 -0
- package/src/tools/agent-knowledge-ingest-tool.ts +34 -1
- package/src/tools/agent-learning-consolidation-core.ts +327 -0
- package/src/tools/agent-learning-consolidation-tool.ts +758 -0
- package/src/tools/agent-memory-tool.ts +214 -0
- package/src/tools/agent-model-compare-export.ts +315 -0
- package/src/tools/agent-model-compare-handoff.ts +592 -0
- package/src/tools/agent-model-compare-judgment.ts +633 -0
- package/src/tools/agent-model-compare-run.ts +722 -0
- package/src/tools/agent-model-compare-tool.ts +698 -0
- package/src/tools/agent-model-compare-types.ts +191 -0
- package/src/tools/agent-model-compare-utils.ts +93 -0
- package/src/tools/agent-models-tool.ts +208 -0
- package/src/tools/agent-operator-action-tool.ts +1 -1
- package/src/tools/agent-operator-method-tool.ts +643 -0
- package/src/tools/agent-personal-ops-tool.ts +197 -0
- package/src/tools/agent-policy-explanation.ts +415 -0
- package/src/tools/agent-research-report-tool.ts +608 -0
- package/src/tools/agent-research-runs-tool.ts +434 -0
- package/src/tools/agent-research-sources-tool.ts +443 -0
- package/src/tools/agent-research-tool.ts +687 -0
- package/src/tools/agent-review-packet-presets-core.ts +757 -0
- package/src/tools/agent-review-packet-presets-tool.ts +466 -0
- package/src/tools/agent-review-packet-share-tool.ts +305 -0
- package/src/tools/agent-route-planner-candidates-setup.ts +411 -0
- package/src/tools/agent-route-planner-candidates-surfaces.ts +432 -0
- package/src/tools/agent-route-planner-candidates-work.ts +251 -0
- package/src/tools/agent-route-planner-helpers.ts +667 -0
- package/src/tools/agent-route-planner.ts +185 -0
- package/src/tools/agent-route-tool.ts +105 -0
- package/src/tools/agent-schedule-edit-tool.ts +210 -0
- package/src/tools/agent-schedule-tool.ts +282 -0
- package/src/tools/agent-security-tool.ts +145 -0
- package/src/tools/agent-sessions-tool.ts +122 -0
- package/src/tools/agent-settings-import-tool.ts +104 -0
- package/src/tools/agent-settings-tool.ts +176 -0
- package/src/tools/agent-setup-tool.ts +226 -0
- package/src/tools/agent-support-tool.ts +122 -0
- package/src/tools/agent-terminal-process-tools.ts +167 -0
- package/src/tools/agent-tool-policy-guard-types.ts +77 -0
- package/src/tools/agent-tool-policy-guard.ts +106 -85
- package/src/tools/agent-vibe-tool.ts +297 -0
- package/src/tools/agent-work-plan-tool.ts +265 -6
- package/src/tools/agent-workspace-tool.ts +305 -0
- package/src/tools/artifact-archive.ts +169 -0
- package/src/tools/tool-definition-compaction.ts +36 -0
- package/src/version.ts +1 -1
|
@@ -3,7 +3,10 @@ import type { CommandContext } from '../input/command-registry.ts';
|
|
|
3
3
|
import { GOODVIBES_AGENT_PAIRING_SURFACE } from '../config/surface.ts';
|
|
4
4
|
import { resolveRuntimeEndpointBinding } from '../cli/endpoints.ts';
|
|
5
5
|
import { connectedHostOperatorTokenFingerprint, readConnectedHostOperatorToken } from '../runtime/connected-host-auth.ts';
|
|
6
|
+
import { buildAgentWorkspaceChannels } from '../input/agent-workspace-channels.ts';
|
|
7
|
+
import { buildAgentWorkspaceVoiceMediaReadiness } from '../input/agent-workspace-voice-media.ts';
|
|
6
8
|
import { requirePlatform, requireShellPaths } from '../input/commands/runtime-services.ts';
|
|
9
|
+
import { browserControlPosture } from './agent-harness-browser-control.ts';
|
|
7
10
|
import { previewHarnessText } from './agent-harness-text.ts';
|
|
8
11
|
|
|
9
12
|
export interface AgentHarnessPairingArgs {
|
|
@@ -25,13 +28,44 @@ interface PairingRoute {
|
|
|
25
28
|
readonly id: string;
|
|
26
29
|
readonly label: string;
|
|
27
30
|
readonly detail: string;
|
|
28
|
-
readonly effect: 'read-only' | 'visible-navigation' | 'external-network' | 'confirmation-gated-secret-display';
|
|
31
|
+
readonly effect: 'read-only' | 'visible-navigation' | 'external-network' | 'confirmation-gated-secret-display' | 'confirmed-local-auth-provisioning';
|
|
29
32
|
readonly command?: string;
|
|
30
33
|
readonly harnessRoute?: string;
|
|
31
34
|
readonly capabilityIds?: readonly string[];
|
|
32
35
|
readonly requiresConfirmation?: boolean;
|
|
33
36
|
}
|
|
34
37
|
|
|
38
|
+
type DeviceCapabilityStatus = 'ready' | 'attention' | 'setup-needed' | 'not-published';
|
|
39
|
+
|
|
40
|
+
interface DeviceCapability {
|
|
41
|
+
readonly id: string;
|
|
42
|
+
readonly label: string;
|
|
43
|
+
readonly domain: 'companion' | 'browser' | 'voice' | 'delivery' | 'desktop' | 'device';
|
|
44
|
+
readonly status: DeviceCapabilityStatus;
|
|
45
|
+
readonly userOutcome: string;
|
|
46
|
+
readonly summary: string;
|
|
47
|
+
readonly nextStep: string;
|
|
48
|
+
readonly capabilities: readonly string[];
|
|
49
|
+
readonly modelRoute: string;
|
|
50
|
+
readonly userRoute?: string;
|
|
51
|
+
readonly setupRoutes?: readonly string[];
|
|
52
|
+
readonly evidence?: Record<string, unknown>;
|
|
53
|
+
readonly policy: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface DeviceCapabilityMap {
|
|
57
|
+
readonly summary: {
|
|
58
|
+
readonly total: number;
|
|
59
|
+
readonly ready: number;
|
|
60
|
+
readonly attention: number;
|
|
61
|
+
readonly setupNeeded: number;
|
|
62
|
+
readonly notPublished: number;
|
|
63
|
+
readonly primaryNextStep: string;
|
|
64
|
+
};
|
|
65
|
+
readonly capabilities: readonly DeviceCapability[];
|
|
66
|
+
readonly policy: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
35
69
|
function readString(value: unknown): string {
|
|
36
70
|
return typeof value === 'string' ? value.trim() : '';
|
|
37
71
|
}
|
|
@@ -42,6 +76,32 @@ function readLimit(value: unknown, fallback: number): number {
|
|
|
42
76
|
return Math.max(1, Math.min(500, Math.trunc(parsed)));
|
|
43
77
|
}
|
|
44
78
|
|
|
79
|
+
function readConfigBoolean(context: CommandContext, key: string, fallback: boolean): boolean {
|
|
80
|
+
try {
|
|
81
|
+
const value = (context.platform.configManager as { get(settingKey: string): unknown }).get(key);
|
|
82
|
+
if (typeof value === 'boolean') return value;
|
|
83
|
+
if (typeof value === 'string') {
|
|
84
|
+
const normalized = value.trim().toLowerCase();
|
|
85
|
+
if (normalized === 'true') return true;
|
|
86
|
+
if (normalized === 'false') return false;
|
|
87
|
+
}
|
|
88
|
+
return fallback;
|
|
89
|
+
} catch {
|
|
90
|
+
return fallback;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function readConfigStringArray(context: CommandContext, key: string): readonly string[] {
|
|
95
|
+
try {
|
|
96
|
+
const value = (context.platform.configManager as { get(settingKey: string): unknown }).get(key);
|
|
97
|
+
if (Array.isArray(value)) return value.filter((entry): entry is string => typeof entry === 'string' && entry.trim().length > 0);
|
|
98
|
+
if (typeof value === 'string' && value.trim().length > 0) return [value.trim()];
|
|
99
|
+
return [];
|
|
100
|
+
} catch {
|
|
101
|
+
return [];
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
45
105
|
function localNetworkIp(): string {
|
|
46
106
|
try {
|
|
47
107
|
const nets = networkInterfaces();
|
|
@@ -99,12 +159,21 @@ function pairingRoutes(): readonly PairingRoute[] {
|
|
|
99
159
|
harnessRoute: 'agent_harness mode:"workspace_action" target:"pair"',
|
|
100
160
|
capabilityIds: ['companion-pairing', 'mobile-command-routing'],
|
|
101
161
|
},
|
|
162
|
+
{
|
|
163
|
+
id: 'connected-host-token-provisioning',
|
|
164
|
+
label: 'Connected-host token provisioning',
|
|
165
|
+
detail: 'Confirmed SDK-backed route that creates or repairs the local canonical connected-host token file without printing the raw token.',
|
|
166
|
+
effect: 'confirmed-local-auth-provisioning',
|
|
167
|
+
harnessRoute: 'setup action:"token" setupItemId:"connected-host-auth" confirm:true explicitUserRequest:"..."',
|
|
168
|
+
capabilityIds: ['connected-host-status', 'companion-pairing'],
|
|
169
|
+
requiresConfirmation: true,
|
|
170
|
+
},
|
|
102
171
|
{
|
|
103
172
|
id: 'connected-host-status',
|
|
104
173
|
label: 'Connected host live posture',
|
|
105
174
|
detail: 'Read-only reachability, token posture, and route readiness used before companion setup.',
|
|
106
175
|
effect: 'read-only',
|
|
107
|
-
harnessRoute: '
|
|
176
|
+
harnessRoute: 'host action:"status"',
|
|
108
177
|
capabilityIds: ['connected-host-status'],
|
|
109
178
|
},
|
|
110
179
|
{
|
|
@@ -112,7 +181,7 @@ function pairingRoutes(): readonly PairingRoute[] {
|
|
|
112
181
|
label: 'Companion capability map',
|
|
113
182
|
detail: 'Allowed and blocked companion route families for pairing, shared sessions, tasks, approvals, provider/model changes, attachments, and mobile command surfaces.',
|
|
114
183
|
effect: 'read-only',
|
|
115
|
-
harnessRoute: '
|
|
184
|
+
harnessRoute: 'host action:"capabilities"',
|
|
116
185
|
capabilityIds: [
|
|
117
186
|
'companion-pairing',
|
|
118
187
|
'shared-session',
|
|
@@ -123,13 +192,30 @@ function pairingRoutes(): readonly PairingRoute[] {
|
|
|
123
192
|
'mobile-command-routing',
|
|
124
193
|
],
|
|
125
194
|
},
|
|
195
|
+
{
|
|
196
|
+
id: 'device-capability-map',
|
|
197
|
+
label: 'Device capability map',
|
|
198
|
+
detail: 'Read-only mobile, browser/PWA, voice, notification, browser/desktop, camera, screen, location, and device-command readiness map with honest setup and not-published states.',
|
|
199
|
+
effect: 'read-only',
|
|
200
|
+
harnessRoute: 'agent_harness mode:"pairing_posture" query:"device" includeParameters:true',
|
|
201
|
+
capabilityIds: [
|
|
202
|
+
'companion-pairing',
|
|
203
|
+
'mobile-command-routing',
|
|
204
|
+
'browser-cockpit-pwa',
|
|
205
|
+
'voice-controls',
|
|
206
|
+
'tts-spoken-responses',
|
|
207
|
+
'notifications',
|
|
208
|
+
'browser-desktop-control',
|
|
209
|
+
'camera-location-sensors',
|
|
210
|
+
],
|
|
211
|
+
},
|
|
126
212
|
{
|
|
127
213
|
id: 'channels-readiness',
|
|
128
214
|
label: 'Channel readiness',
|
|
129
215
|
detail: 'Read-only channel setup and delivery posture used after pairing when messages or reminders need an explicit delivery target.',
|
|
130
216
|
effect: 'read-only',
|
|
131
217
|
command: '/channels',
|
|
132
|
-
harnessRoute: '
|
|
218
|
+
harnessRoute: 'channels action:"status"',
|
|
133
219
|
capabilityIds: ['channels', 'notifications'],
|
|
134
220
|
},
|
|
135
221
|
];
|
|
@@ -147,6 +233,14 @@ function routeSearchText(route: PairingRoute): string {
|
|
|
147
233
|
].join('\n').toLowerCase();
|
|
148
234
|
}
|
|
149
235
|
|
|
236
|
+
function routeMatches(route: PairingRoute, query: string): boolean {
|
|
237
|
+
if (!query) return true;
|
|
238
|
+
const text = routeSearchText(route);
|
|
239
|
+
if (text.includes(query)) return true;
|
|
240
|
+
const tokens = query.split(/\s+/).map((token) => token.trim()).filter(Boolean);
|
|
241
|
+
return tokens.length > 0 && tokens.every((token) => text.includes(token));
|
|
242
|
+
}
|
|
243
|
+
|
|
150
244
|
function describeCandidate(route: PairingRoute): Record<string, unknown> {
|
|
151
245
|
return {
|
|
152
246
|
pairingRouteId: route.id,
|
|
@@ -157,7 +251,11 @@ function describeCandidate(route: PairingRoute): Record<string, unknown> {
|
|
|
157
251
|
};
|
|
158
252
|
}
|
|
159
253
|
|
|
160
|
-
function describeRoute(route: PairingRoute, options: {
|
|
254
|
+
function describeRoute(route: PairingRoute, options: {
|
|
255
|
+
readonly includeParameters?: boolean;
|
|
256
|
+
readonly lookup?: Record<string, unknown>;
|
|
257
|
+
readonly context?: CommandContext;
|
|
258
|
+
} = {}): Record<string, unknown> {
|
|
161
259
|
return {
|
|
162
260
|
pairingRouteId: route.id,
|
|
163
261
|
label: route.label,
|
|
@@ -180,11 +278,14 @@ function describeRoute(route: PairingRoute, options: { readonly includeParameter
|
|
|
180
278
|
modelAccess: {
|
|
181
279
|
inspectPairing: 'agent_harness mode:"pairing_posture"',
|
|
182
280
|
inspectRoute: 'agent_harness mode:"pairing_route"',
|
|
183
|
-
connectedHostStatus: '
|
|
184
|
-
connectedHostCapabilities: '
|
|
185
|
-
channels: '
|
|
281
|
+
connectedHostStatus: 'host action:"status"',
|
|
282
|
+
connectedHostCapabilities: 'host action:"capabilities"',
|
|
283
|
+
channels: 'channels action:"status"',
|
|
186
284
|
},
|
|
187
285
|
} : {}),
|
|
286
|
+
...(options.includeParameters && route.id === 'device-capability-map' && options.context ? {
|
|
287
|
+
deviceCapabilityMap: buildDeviceCapabilityMap(options.context),
|
|
288
|
+
} : {}),
|
|
188
289
|
};
|
|
189
290
|
}
|
|
190
291
|
|
|
@@ -205,6 +306,7 @@ function pairingState(context: CommandContext): Record<string, unknown> {
|
|
|
205
306
|
surface: GOODVIBES_AGENT_PAIRING_SURFACE,
|
|
206
307
|
endpoint: {
|
|
207
308
|
endpointId: 'controlPlane',
|
|
309
|
+
enabled: readConfigBoolean(context, 'controlPlane.enabled', false),
|
|
208
310
|
bindHost: binding.host,
|
|
209
311
|
advertisedHost: host,
|
|
210
312
|
port: binding.port,
|
|
@@ -220,12 +322,305 @@ function pairingState(context: CommandContext): Record<string, unknown> {
|
|
|
220
322
|
};
|
|
221
323
|
}
|
|
222
324
|
|
|
325
|
+
function tokenPresent(state: Record<string, unknown>): boolean {
|
|
326
|
+
const token = state.token as { readonly present?: boolean } | undefined;
|
|
327
|
+
return token?.present === true;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function endpointEnabled(state: Record<string, unknown>): boolean {
|
|
331
|
+
const endpoint = state.endpoint as { readonly enabled?: boolean } | undefined;
|
|
332
|
+
return endpoint?.enabled === true;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function deviceStatusRank(status: DeviceCapabilityStatus): number {
|
|
336
|
+
if (status === 'attention') return 0;
|
|
337
|
+
if (status === 'setup-needed') return 1;
|
|
338
|
+
if (status === 'not-published') return 2;
|
|
339
|
+
return 3;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function deviceCapabilitySearchText(capability: DeviceCapability): string {
|
|
343
|
+
return [
|
|
344
|
+
capability.id,
|
|
345
|
+
capability.label,
|
|
346
|
+
capability.domain,
|
|
347
|
+
capability.status,
|
|
348
|
+
capability.userOutcome,
|
|
349
|
+
capability.summary,
|
|
350
|
+
capability.nextStep,
|
|
351
|
+
capability.modelRoute,
|
|
352
|
+
capability.userRoute ?? '',
|
|
353
|
+
...(capability.setupRoutes ?? []),
|
|
354
|
+
...capability.capabilities,
|
|
355
|
+
].join('\n').toLowerCase();
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function deviceCapabilityMatches(capability: DeviceCapability, query: string): boolean {
|
|
359
|
+
if (!query) return true;
|
|
360
|
+
const text = deviceCapabilitySearchText(capability);
|
|
361
|
+
if (text.includes(query)) return true;
|
|
362
|
+
const tokens = query.split(/\s+/).map((token) => token.trim()).filter(Boolean);
|
|
363
|
+
return tokens.length > 0 && tokens.every((token) => text.includes(token));
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function queryRequestsWholeDeviceMap(query: string): boolean {
|
|
367
|
+
if (!query) return true;
|
|
368
|
+
const tokens = query.split(/\s+/).map((token) => token.trim()).filter(Boolean);
|
|
369
|
+
if (query === 'device' || query === 'mobile' || query === 'phone') return true;
|
|
370
|
+
return tokens.includes('device') && (tokens.includes('capability') || tokens.includes('capabilities') || tokens.includes('map'));
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function buildDeviceCapabilityMap(context: CommandContext): DeviceCapabilityMap {
|
|
374
|
+
const state = pairingState(context);
|
|
375
|
+
const hasToken = tokenPresent(state);
|
|
376
|
+
const controlPlaneReady = endpointEnabled(state) && hasToken;
|
|
377
|
+
const webEnabled = readConfigBoolean(context, 'web.enabled', false);
|
|
378
|
+
const webBinding = resolveRuntimeEndpointBinding(requirePlatform(context).configManager, 'web');
|
|
379
|
+
const webHost = urlHostForBindHost(webBinding.host);
|
|
380
|
+
const webUrl = `http://${webHost}:${webBinding.port}`;
|
|
381
|
+
const voiceEnabled = readConfigBoolean(context, 'ui.voiceEnabled', false);
|
|
382
|
+
const voiceReadiness = buildAgentWorkspaceVoiceMediaReadiness({
|
|
383
|
+
context,
|
|
384
|
+
voiceProviders: context.platform.voiceProviderRegistry?.list() ?? [],
|
|
385
|
+
mediaProviders: context.platform.mediaProviderRegistry?.list() ?? [],
|
|
386
|
+
});
|
|
387
|
+
const channels = buildAgentWorkspaceChannels(context);
|
|
388
|
+
const readyChannels = channels.filter((channel) => channel.ready);
|
|
389
|
+
const enabledChannels = channels.filter((channel) => channel.enabled);
|
|
390
|
+
const notificationWebhookCount = readConfigStringArray(context, 'notifications.webhookUrls').length;
|
|
391
|
+
const browserPosture = browserControlPosture(context);
|
|
392
|
+
const ttsStatus: DeviceCapabilityStatus = voiceReadiness.selectedTtsProviderStatus === 'ready' && voiceReadiness.ttsVoiceConfigured
|
|
393
|
+
? 'ready'
|
|
394
|
+
: voiceReadiness.selectedTtsProviderStatus === 'ready' || voiceReadiness.selectedTtsProviderStatus === 'registered'
|
|
395
|
+
? 'attention'
|
|
396
|
+
: 'setup-needed';
|
|
397
|
+
const notificationStatus: DeviceCapabilityStatus = readyChannels.length > 0 || notificationWebhookCount > 0
|
|
398
|
+
? 'ready'
|
|
399
|
+
: enabledChannels.length > 0
|
|
400
|
+
? 'attention'
|
|
401
|
+
: 'setup-needed';
|
|
402
|
+
const capabilities: DeviceCapability[] = [
|
|
403
|
+
{
|
|
404
|
+
id: 'companion-pairing',
|
|
405
|
+
label: 'Companion pairing',
|
|
406
|
+
domain: 'companion',
|
|
407
|
+
status: hasToken ? 'ready' : 'setup-needed',
|
|
408
|
+
userOutcome: 'Pair a phone or companion surface without exposing the raw operator token in chat.',
|
|
409
|
+
summary: hasToken
|
|
410
|
+
? 'A connected-host operator token is present; QR and manual setup still require visible confirmed routes.'
|
|
411
|
+
: 'No connected-host operator token is present, so companion pairing needs local token provisioning first.',
|
|
412
|
+
nextStep: hasToken
|
|
413
|
+
? 'Use /pair or inspect the QR/manual routes when the user asks to pair a companion.'
|
|
414
|
+
: 'Provision connected-host auth, then return to QR pairing.',
|
|
415
|
+
capabilities: ['QR pairing', 'manual setup fallback', 'token-safe handoff'],
|
|
416
|
+
modelRoute: 'agent_harness mode:"pairing_route" pairingRouteId:"qr-pairing"',
|
|
417
|
+
userRoute: '/pair',
|
|
418
|
+
setupRoutes: [
|
|
419
|
+
'setup action:"item" setupItemId:"connected-host-auth"',
|
|
420
|
+
'setup action:"token" setupItemId:"connected-host-auth" confirm:true explicitUserRequest:"..."',
|
|
421
|
+
],
|
|
422
|
+
evidence: {
|
|
423
|
+
tokenPresent: hasToken,
|
|
424
|
+
rawTokenReturned: false,
|
|
425
|
+
},
|
|
426
|
+
policy: 'Pairing display and raw-token fallback are visible, confirmation-gated user flows.',
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
id: 'mobile-command-routing',
|
|
430
|
+
label: 'Mobile command routing',
|
|
431
|
+
domain: 'companion',
|
|
432
|
+
status: controlPlaneReady ? 'ready' : endpointEnabled(state) ? 'attention' : 'setup-needed',
|
|
433
|
+
userOutcome: 'Send commands from a companion surface into the same visible Agent control plane.',
|
|
434
|
+
summary: controlPlaneReady
|
|
435
|
+
? 'Control-plane routing and operator auth are both configured.'
|
|
436
|
+
: endpointEnabled(state)
|
|
437
|
+
? 'The control plane is enabled, but companion auth is not ready.'
|
|
438
|
+
: 'The control plane is disabled, so mobile command routing is not reachable yet.',
|
|
439
|
+
nextStep: controlPlaneReady
|
|
440
|
+
? 'Use connected-host status before accepting companion-originated work.'
|
|
441
|
+
: 'Enable and authenticate the control plane before relying on mobile command routing.',
|
|
442
|
+
capabilities: ['shared session routing', 'task handoff', 'approval handoff', 'provider/model routing'],
|
|
443
|
+
modelRoute: 'host action:"status"',
|
|
444
|
+
setupRoutes: [
|
|
445
|
+
'host action:"service" endpointId:"controlPlane"',
|
|
446
|
+
'setup action:"item" setupItemId:"connected-host-auth"',
|
|
447
|
+
],
|
|
448
|
+
evidence: {
|
|
449
|
+
controlPlaneEnabled: endpointEnabled(state),
|
|
450
|
+
tokenPresent: hasToken,
|
|
451
|
+
},
|
|
452
|
+
policy: 'Companion-originated tasks, approvals, sends, and provider/model changes remain explicit visible routes.',
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
id: 'browser-cockpit-pwa',
|
|
456
|
+
label: 'Browser cockpit/PWA',
|
|
457
|
+
domain: 'browser',
|
|
458
|
+
status: webEnabled ? 'ready' : 'setup-needed',
|
|
459
|
+
userOutcome: 'Use the connected-host browser cockpit from desktop or mobile without returning to the terminal.',
|
|
460
|
+
summary: webEnabled
|
|
461
|
+
? `The connected-host web endpoint is enabled at ${webUrl}.`
|
|
462
|
+
: 'The connected-host web endpoint is disabled, so the browser cockpit/PWA cannot open yet.',
|
|
463
|
+
nextStep: webEnabled
|
|
464
|
+
? 'Open the connected browser cockpit when the user confirms a browser handoff.'
|
|
465
|
+
: 'Inspect the web service endpoint and enable the host web surface only when the user wants browser access.',
|
|
466
|
+
capabilities: ['responsive browser workspace', 'PWA route', 'mobile-friendly cockpit'],
|
|
467
|
+
modelRoute: 'agent_harness mode:"open_ui_surface" surfaceId:"connected-browser-cockpit" confirm:true explicitUserRequest:"..."',
|
|
468
|
+
setupRoutes: [
|
|
469
|
+
'agent_harness mode:"ui_surface" surfaceId:"connected-browser-cockpit"',
|
|
470
|
+
'host action:"service" endpointId:"web"',
|
|
471
|
+
],
|
|
472
|
+
evidence: {
|
|
473
|
+
webEnabled,
|
|
474
|
+
webEndpoint: webEnabled ? webUrl : null,
|
|
475
|
+
},
|
|
476
|
+
policy: 'Opening external browser surfaces is confirmation-gated and never mutates host state by inspection alone.',
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
id: 'voice-controls',
|
|
480
|
+
label: 'Voice controls',
|
|
481
|
+
domain: 'voice',
|
|
482
|
+
status: voiceEnabled && voiceReadiness.readyVoiceProviderCount > 0 ? 'ready' : voiceEnabled ? 'attention' : 'setup-needed',
|
|
483
|
+
userOutcome: 'Talk to the assistant through an intentionally enabled voice surface.',
|
|
484
|
+
summary: voiceEnabled
|
|
485
|
+
? `${voiceReadiness.readyVoiceProviderCount}/${voiceReadiness.voiceProviders.length} voice provider(s) are ready.`
|
|
486
|
+
: 'The voice surface is disabled.',
|
|
487
|
+
nextStep: voiceEnabled
|
|
488
|
+
? 'Review media posture for provider or voice setup blockers before claiming hands-free use.'
|
|
489
|
+
: 'Enable voice only after the user asks for spoken or push-to-talk interaction.',
|
|
490
|
+
capabilities: ['voice surface toggle', 'push-to-talk setup posture', 'provider readiness'],
|
|
491
|
+
modelRoute: 'agent_harness mode:"media_posture" query:"voice" includeParameters:true',
|
|
492
|
+
setupRoutes: [
|
|
493
|
+
'settings action:"get" query:"ui.voiceEnabled" includeParameters:true',
|
|
494
|
+
'agent_harness mode:"media_posture" query:"voice" includeParameters:true',
|
|
495
|
+
],
|
|
496
|
+
evidence: {
|
|
497
|
+
voiceSurfaceEnabled: voiceEnabled,
|
|
498
|
+
readyVoiceProviders: voiceReadiness.readyVoiceProviderCount,
|
|
499
|
+
totalVoiceProviders: voiceReadiness.voiceProviders.length,
|
|
500
|
+
},
|
|
501
|
+
policy: 'Voice enablement and provider changes stay visible settings or media-provider flows.',
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
id: 'tts-spoken-responses',
|
|
505
|
+
label: 'Spoken responses',
|
|
506
|
+
domain: 'voice',
|
|
507
|
+
status: ttsStatus,
|
|
508
|
+
userOutcome: 'Hear assistant responses with a predictable provider and voice.',
|
|
509
|
+
summary: `${voiceReadiness.selectedTtsProviderLabel} is ${voiceReadiness.selectedTtsProviderStatus}; voice configured=${voiceReadiness.ttsVoiceConfigured ? 'yes' : 'no'}.`,
|
|
510
|
+
nextStep: ttsStatus === 'ready'
|
|
511
|
+
? 'Use explicit TTS routes when the user asks for spoken output.'
|
|
512
|
+
: 'Choose a ready TTS provider and voice before presenting spoken replies as ready.',
|
|
513
|
+
capabilities: ['TTS provider selection', 'voice picker', 'spoken reply route'],
|
|
514
|
+
modelRoute: 'agent_harness mode:"media_posture" query:"tts" includeParameters:true',
|
|
515
|
+
setupRoutes: [
|
|
516
|
+
'agent_harness mode:"open_ui_surface" surfaceId:"tts-provider-picker" confirm:true explicitUserRequest:"..."',
|
|
517
|
+
'agent_harness mode:"open_ui_surface" surfaceId:"tts-voice-picker" confirm:true explicitUserRequest:"..."',
|
|
518
|
+
],
|
|
519
|
+
evidence: {
|
|
520
|
+
selectedTtsProviderStatus: voiceReadiness.selectedTtsProviderStatus,
|
|
521
|
+
ttsVoiceConfigured: voiceReadiness.ttsVoiceConfigured,
|
|
522
|
+
},
|
|
523
|
+
policy: 'Spoken replies and TTS setting changes require explicit user-visible routes.',
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
id: 'notifications',
|
|
527
|
+
label: 'Notifications and delivery',
|
|
528
|
+
domain: 'delivery',
|
|
529
|
+
status: notificationStatus,
|
|
530
|
+
userOutcome: 'Receive completion/status messages through a chosen channel without hidden sends.',
|
|
531
|
+
summary: `${readyChannels.length}/${channels.length} channel(s) ready; ${notificationWebhookCount} notification webhook target(s) configured.`,
|
|
532
|
+
nextStep: notificationStatus === 'ready'
|
|
533
|
+
? 'Use explicit confirmed send/test routes only for the channel the user chose.'
|
|
534
|
+
: enabledChannels.length > 0
|
|
535
|
+
? 'Finish setup for enabled channels before relying on notifications.'
|
|
536
|
+
: 'Choose one notification channel intentionally, then configure only that surface.',
|
|
537
|
+
capabilities: ['channel delivery', 'desktop notification posture', 'webhook notification posture'],
|
|
538
|
+
modelRoute: 'channels action:"setup"',
|
|
539
|
+
userRoute: '/channels',
|
|
540
|
+
setupRoutes: [
|
|
541
|
+
'channels action:"status" includeParameters:true',
|
|
542
|
+
'channels action:"setup"',
|
|
543
|
+
'agent_harness mode:"notifications"',
|
|
544
|
+
],
|
|
545
|
+
evidence: {
|
|
546
|
+
readyChannels: readyChannels.length,
|
|
547
|
+
enabledChannels: enabledChannels.length,
|
|
548
|
+
notificationWebhookTargets: notificationWebhookCount,
|
|
549
|
+
},
|
|
550
|
+
policy: 'Delivery tests and outbound messages require explicit confirmed user action.',
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
id: 'browser-desktop-control',
|
|
554
|
+
label: 'Browser and desktop control',
|
|
555
|
+
domain: 'desktop',
|
|
556
|
+
status: browserPosture.status,
|
|
557
|
+
userOutcome: 'Control browser, screen, or desktop surfaces only through trusted configured tools.',
|
|
558
|
+
summary: browserPosture.configured
|
|
559
|
+
? 'A browser/desktop control route is configured.'
|
|
560
|
+
: browserPosture.needsReview
|
|
561
|
+
? 'Browser/desktop tooling exists but needs trust or schema review.'
|
|
562
|
+
: 'No trusted browser/desktop control route is configured.',
|
|
563
|
+
nextStep: browserPosture.recommendedRoute,
|
|
564
|
+
capabilities: ['browser navigation', 'screenshot/screen observation', 'desktop control'],
|
|
565
|
+
modelRoute: browserPosture.recommendedRoute,
|
|
566
|
+
setupRoutes: [
|
|
567
|
+
browserPosture.setupRoute,
|
|
568
|
+
'execution action:"status" query:"browser desktop" includeParameters:true',
|
|
569
|
+
],
|
|
570
|
+
evidence: {
|
|
571
|
+
toolMatches: browserPosture.toolMatches,
|
|
572
|
+
mcpServers: browserPosture.mcpServers.length,
|
|
573
|
+
},
|
|
574
|
+
policy: browserPosture.policy,
|
|
575
|
+
},
|
|
576
|
+
{
|
|
577
|
+
id: 'camera-location-sensors',
|
|
578
|
+
label: 'Camera and location sensors',
|
|
579
|
+
domain: 'device',
|
|
580
|
+
status: 'not-published',
|
|
581
|
+
userOutcome: 'Use phone camera or location only after the daemon/companion publishes permission-scoped records.',
|
|
582
|
+
summary: 'Camera and location sensor adapters are not published by the current Agent-visible SDK/daemon contract.',
|
|
583
|
+
nextStep: 'Inspect operator methods for newly published camera/location contracts before claiming device access.',
|
|
584
|
+
capabilities: ['camera permission posture', 'location permission posture', 'device sensor commands'],
|
|
585
|
+
modelRoute: 'host action:"methods" query:"camera location device"',
|
|
586
|
+
setupRoutes: [
|
|
587
|
+
'host action:"methods" query:"camera location device"',
|
|
588
|
+
'host action:"capabilities" includeParameters:true',
|
|
589
|
+
],
|
|
590
|
+
evidence: {
|
|
591
|
+
publishedByCurrentAgentContract: false,
|
|
592
|
+
},
|
|
593
|
+
policy: 'Agent reports unpublished device sensor APIs honestly instead of simulating camera or location access.',
|
|
594
|
+
},
|
|
595
|
+
];
|
|
596
|
+
capabilities.sort((left, right) => deviceStatusRank(left.status) - deviceStatusRank(right.status) || left.label.localeCompare(right.label));
|
|
597
|
+
const counts = {
|
|
598
|
+
ready: capabilities.filter((capability) => capability.status === 'ready').length,
|
|
599
|
+
attention: capabilities.filter((capability) => capability.status === 'attention').length,
|
|
600
|
+
setupNeeded: capabilities.filter((capability) => capability.status === 'setup-needed').length,
|
|
601
|
+
notPublished: capabilities.filter((capability) => capability.status === 'not-published').length,
|
|
602
|
+
};
|
|
603
|
+
const primaryNextStep = capabilities.find((capability) => capability.status !== 'ready')?.nextStep
|
|
604
|
+
?? 'All published companion device capabilities are ready; use explicit confirmed routes for effects.';
|
|
605
|
+
return {
|
|
606
|
+
summary: {
|
|
607
|
+
total: capabilities.length,
|
|
608
|
+
...counts,
|
|
609
|
+
primaryNextStep,
|
|
610
|
+
},
|
|
611
|
+
capabilities,
|
|
612
|
+
policy: 'Read-only device capability map. It does not pair devices, send notifications, open browsers, change voice settings, capture screens, or claim unpublished sensor APIs.',
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
|
|
223
616
|
export function pairingPostureCatalogStatus(context: CommandContext): Record<string, unknown> {
|
|
224
617
|
const state = pairingState(context);
|
|
618
|
+
const deviceMap = buildDeviceCapabilityMap(context);
|
|
225
619
|
return {
|
|
226
620
|
modes: ['pairing_posture', 'pairing_route'],
|
|
227
621
|
routes: pairingRoutes().length,
|
|
228
|
-
tokenPresent: (state
|
|
622
|
+
tokenPresent: tokenPresent(state),
|
|
623
|
+
deviceCapabilitySummary: deviceMap.summary,
|
|
229
624
|
readOnly: true,
|
|
230
625
|
};
|
|
231
626
|
}
|
|
@@ -234,20 +629,38 @@ export function pairingPostureSummary(context: CommandContext, args: AgentHarnes
|
|
|
234
629
|
const query = readString(args.query).toLowerCase();
|
|
235
630
|
const includeParameters = args.includeParameters === true;
|
|
236
631
|
const routes = pairingRoutes();
|
|
632
|
+
const deviceMap = buildDeviceCapabilityMap(context);
|
|
633
|
+
const limit = readLimit(args.limit, 100);
|
|
237
634
|
const filtered = routes
|
|
238
|
-
.filter((route) =>
|
|
239
|
-
.slice(0,
|
|
635
|
+
.filter((route) => routeMatches(route, query))
|
|
636
|
+
.slice(0, limit);
|
|
637
|
+
const includeWholeDeviceMap = queryRequestsWholeDeviceMap(query);
|
|
638
|
+
const filteredCapabilities = deviceMap.capabilities
|
|
639
|
+
.filter((capability) => includeWholeDeviceMap || deviceCapabilityMatches(capability, query))
|
|
640
|
+
.slice(0, limit);
|
|
240
641
|
return {
|
|
241
642
|
status: 'available',
|
|
643
|
+
summary: {
|
|
644
|
+
deviceCapabilities: deviceMap.summary,
|
|
645
|
+
returnedDeviceCapabilities: filteredCapabilities.length,
|
|
646
|
+
},
|
|
242
647
|
pairing: pairingState(context),
|
|
243
|
-
|
|
648
|
+
deviceCapabilities: filteredCapabilities.map((capability) => includeParameters ? capability : {
|
|
649
|
+
capabilityId: capability.id,
|
|
650
|
+
label: capability.label,
|
|
651
|
+
domain: capability.domain,
|
|
652
|
+
status: capability.status,
|
|
653
|
+
summary: previewHarnessText(capability.summary),
|
|
654
|
+
modelRoute: capability.modelRoute,
|
|
655
|
+
}),
|
|
656
|
+
routes: filtered.map((route) => describeRoute(route, { includeParameters, context })),
|
|
244
657
|
returned: filtered.length,
|
|
245
658
|
total: routes.length,
|
|
246
|
-
policy:
|
|
659
|
+
policy: `${deviceMap.policy} QR display, manual token display, companion connection, channel delivery, task, approval, provider/model, and attachment actions remain explicit visible user flows.`,
|
|
247
660
|
};
|
|
248
661
|
}
|
|
249
662
|
|
|
250
|
-
export function describeHarnessPairingRoute(
|
|
663
|
+
export function describeHarnessPairingRoute(context: CommandContext, args: AgentHarnessPairingArgs): PairingResolution {
|
|
251
664
|
const lookup = lookupFromArgs(args);
|
|
252
665
|
if (!lookup) {
|
|
253
666
|
return {
|
|
@@ -258,11 +671,11 @@ export function describeHarnessPairingRoute(_context: CommandContext, args: Agen
|
|
|
258
671
|
const routes = pairingRoutes();
|
|
259
672
|
const normalized = lookup.input.toLowerCase();
|
|
260
673
|
const exact = routes.find((route) => route.id === lookup.input);
|
|
261
|
-
if (exact) return { status: 'found', route: describeRoute(exact, { includeParameters: true, lookup: { ...lookup, resolvedBy: 'id' } }) };
|
|
674
|
+
if (exact) return { status: 'found', route: describeRoute(exact, { includeParameters: true, lookup: { ...lookup, resolvedBy: 'id' }, context }) };
|
|
262
675
|
const insensitive = routes.find((route) => route.id.toLowerCase() === normalized);
|
|
263
|
-
if (insensitive) return { status: 'found', route: describeRoute(insensitive, { includeParameters: true, lookup: { ...lookup, resolvedBy: 'case-insensitive-id' } }) };
|
|
264
|
-
const searched = routes.filter((route) =>
|
|
265
|
-
if (searched.length === 1) return { status: 'found', route: describeRoute(searched[0]!, { includeParameters: true, lookup: { ...lookup, resolvedBy: 'search' } }) };
|
|
676
|
+
if (insensitive) return { status: 'found', route: describeRoute(insensitive, { includeParameters: true, lookup: { ...lookup, resolvedBy: 'case-insensitive-id' }, context }) };
|
|
677
|
+
const searched = routes.filter((route) => routeMatches(route, normalized));
|
|
678
|
+
if (searched.length === 1) return { status: 'found', route: describeRoute(searched[0]!, { includeParameters: true, lookup: { ...lookup, resolvedBy: 'search' }, context }) };
|
|
266
679
|
if (searched.length > 1) {
|
|
267
680
|
return {
|
|
268
681
|
status: 'ambiguous',
|