@harness-mix/cli 0.1.11 → 0.1.12
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 +16 -0
- package/NOTICE +16 -2
- package/README.md +265 -3
- package/docs/cross-platform.md +3 -3
- package/docs/multi-agent-collaboration.md +37 -23
- package/docs/native-acp.md +2 -2
- package/docs/native-codex.md +5 -5
- package/docs/{superpowers/specs → specs}/2026-09-13-native-hardening-design.md +2 -2
- package/docs/storage-verification-design.md +5 -5
- package/licenses/lobe-icons-MIT.txt +21 -0
- package/output/native-build/desktop-controller.mjs +24 -24
- package/output/native-build/harness-mix-secret.exe +0 -0
- package/output/native-build/harness-mix-shim.exe +0 -0
- package/output/native-build/renderer-extension.js +1325 -658
- package/package.json +2 -2
- package/scripts/adapters-test.cjs +9 -1
- package/scripts/antigravity-adapter-test.cjs +381 -284
- package/scripts/build-native.cjs +64 -46
- package/scripts/codex-accounts-test.cjs +1 -1
- package/scripts/codex-accounts-ui-smoke.cjs +1 -1
- package/scripts/collaboration-recovery-test.cjs +11 -2
- package/scripts/collaboration-test.cjs +114 -27
- package/scripts/collaboration-ui-smoke.cjs +45 -8
- package/scripts/concurrency-layers-test.cjs +5 -0
- package/scripts/diagnostics.cjs +1 -1
- package/scripts/e2e-native-host.cjs +13 -13
- package/scripts/error-kind-test.cjs +3 -3
- package/scripts/integrations-test.cjs +2 -2
- package/scripts/integrations-ui-smoke.cjs +6 -6
- package/scripts/native-config-test.cjs +6 -6
- package/scripts/native-job-object-test.cjs +1 -1
- package/scripts/native-protocol-test.cjs +44 -38
- package/scripts/native-rollback-test.cjs +1 -1
- package/scripts/native-secret-test.cjs +1 -1
- package/scripts/native-shim-test.cjs +1 -1
- package/scripts/native-sidebar-test.cjs +4 -4
- package/scripts/native-ui-smoke.cjs +12 -12
- package/scripts/pets-test.cjs +223 -3
- package/scripts/platform-test.cjs +6 -6
- package/scripts/publish-native-package.cjs +1 -1
- package/scripts/test-live-mentions.cjs +2 -2
- package/scripts/workspace-test.cjs +4 -2
- package/src/assets/icons/PROVENANCE.md +92 -0
- package/src/main/adapters/antigravity.js +1415 -1368
- package/src/main/adapters/claude.js +1 -1
- package/src/main/adapters/codex-app-server.js +1 -1
- package/src/main/adapters/dsh.js +1 -1
- package/src/main/adapters/index.js +1 -1
- package/src/main/adapters/pi-usage.js +2 -2
- package/src/main/harness-adapter/error-kind.js +1 -1
- package/src/main/harness-adapter/manifest.js +7 -1
- package/src/main/host/collaboration-tools.js +8 -1
- package/src/main/host/collaboration-worktree.js +27 -1
- package/src/main/host/collaboration.js +348 -15
- package/src/main/host/runtime.js +23 -15
- package/src/main/native/codex-accounts.js +1 -1
- package/src/main/native/config.js +9 -9
- package/src/main/native/host.js +1 -1
- package/src/main/native/launcher.js +10 -8
- package/src/main/native/pets.js +188 -49
- package/src/main/native/platform.js +19 -9
- package/src/main/native/protocol.js +83 -80
- package/src/main/native/rs/crates/appx/Cargo.toml +1 -1
- package/src/main/native/rs/crates/secret/Cargo.toml +1 -1
- package/src/main/native/rs/crates/secret/src/main.rs +3 -3
- package/src/main/native/rs/crates/shim/Cargo.toml +1 -1
- package/src/main/native/rs/crates/shim/src/main.rs +2 -2
- package/src/main/native/thread-list.js +1 -1
- package/src/main/shared-contracts/capability.js +3 -1
- package/src/main/workspace/core-review.js +4 -3
- package/src/native-ui/README.md +2 -2
- package/src/native-ui/desktop-control/dist/contract-audit.js +4 -4
- package/src/native-ui/desktop-control/dist/index.d.ts +1 -1
- package/src/native-ui/desktop-control/dist/index.js +2 -2
- package/src/native-ui/desktop-control/dist/index.js.map +1 -1
- package/src/native-ui/desktop-control/dist/main-process-title-policy.js +5 -5
- package/src/native-ui/desktop-control/dist/main-process-title-policy.js.map +1 -1
- package/src/native-ui/desktop-control/dist/production-controller.js +3 -3
- package/src/native-ui/desktop-control/dist/production-controller.js.map +1 -1
- package/src/native-ui/desktop-control/dist/release-main.js +1 -1
- package/src/native-ui/desktop-control/dist/release-main.js.map +1 -1
- package/src/native-ui/desktop-control/dist/renderer-cdp-control-session.js +1 -1
- package/src/native-ui/desktop-control/dist/renderer-cdp-control-session.js.map +1 -1
- package/src/native-ui/desktop-control/dist/renderer-control-session.js +3 -3
- package/src/native-ui/desktop-control/dist/renderer-control-session.js.map +1 -1
- package/src/native-ui/desktop-control/dist/renderer-draft-prewarm-runtime.js +25 -25
- package/src/native-ui/desktop-control/dist/renderer-draft-prewarm-runtime.js.map +1 -1
- package/src/native-ui/desktop-control/dist/tsconfig.tsbuildinfo +1 -1
- package/src/native-ui/desktop-control/package.json +2 -2
- package/src/native-ui/desktop-control/scripts/build-release.mjs +2 -2
- package/src/native-ui/desktop-control/src/contract-audit.ts +4 -4
- package/src/native-ui/desktop-control/src/index.ts +2 -2
- package/src/native-ui/desktop-control/src/main-process-title-policy.ts +5 -5
- package/src/native-ui/desktop-control/src/production-controller.ts +3 -3
- package/src/native-ui/desktop-control/src/release-main.ts +1 -1
- package/src/native-ui/desktop-control/src/renderer-cdp-control-session.ts +1 -1
- package/src/native-ui/desktop-control/src/renderer-control-session.ts +3 -3
- package/src/native-ui/desktop-control/src/renderer-draft-prewarm-runtime.ts +25 -25
- package/src/native-ui/desktop-control/test/index.test.ts +1 -1
- package/src/native-ui/desktop-control/test/production-controller.test.ts +1 -1
- package/src/native-ui/desktop-control/test/renderer-cdp-control-session.test.ts +1 -1
- package/src/native-ui/desktop-control/test/renderer-draft-prewarm-policy.test.ts +43 -43
- package/src/native-ui/renderer-extension/dist/types/agent-group-preference.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/agent-group-preference.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/agent-selection-state.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/agent-selection-state.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/contract-audit.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/contract-audit.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/index.d.ts +3 -1
- package/src/native-ui/renderer-extension/dist/types/index.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/production-entry.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/production-entry.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-agent-picker.d.ts +2 -2
- package/src/native-ui/renderer-extension/dist/types/renderer-agent-picker.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-binding-probe.d.ts +3 -3
- package/src/native-ui/renderer-extension/dist/types/renderer-binding-probe.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-codex-account-options.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-codex-account-options.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-codex-account-state.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-codex-account-state.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-collab-cards.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-collab-cards.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-composer-dom.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-composer-dom.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-credits-control.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-credits-control.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-fork-control.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-fork-control.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-harness-command-claim.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-harness-command-claim.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-harness-command-control.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-harness-command-control.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-harness-handoff.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-harness-handoff.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-harness-localization.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-harness-localization.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-harness-mentions.d.ts +1 -0
- package/src/native-ui/renderer-extension/dist/types/renderer-harness-mentions.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-model-client.d.ts +36 -31
- package/src/native-ui/renderer-extension/dist/types/renderer-model-client.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-model-picker.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-model-picker.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-new-thread-preference.d.ts +2 -2
- package/src/native-ui/renderer-extension/dist/types/renderer-new-thread-preference.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-permission-mode-picker.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-permission-mode-picker.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-permission-mode-preference.d.ts +2 -2
- package/src/native-ui/renderer-extension/dist/types/renderer-permission-mode-preference.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-request-sender.d.ts +18 -2
- package/src/native-ui/renderer-extension/dist/types/renderer-request-sender.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-session-import-client.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-session-import-client.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-sidebar-agent-icons.d.ts +2 -2
- package/src/native-ui/renderer-extension/dist/types/renderer-sidebar-agent-icons.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-team-cards.d.ts +58 -0
- package/src/native-ui/renderer-extension/dist/types/renderer-team-cards.d.ts.map +1 -0
- package/src/native-ui/renderer-extension/dist/types/renderer-transcript-dom.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-trigger-chip-style.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-trigger-chip-style.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-usage-control.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-usage-control.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/accounts-list.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/accounts-list.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/accounts-page.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/accounts-page.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/accounts-usage.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/accounts-usage.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/connections-page.d.ts +3 -3
- package/src/native-ui/renderer-extension/dist/types/settings/connections-page.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/harness-accounts.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/harness-accounts.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/pages.d.ts +4 -4
- package/src/native-ui/renderer-extension/dist/types/settings/pages.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/pet-market.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/session-import-list-controls.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/session-import-list-controls.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/session-import-page.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/session-import-page.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/shell.d.ts +2 -2
- package/src/native-ui/renderer-extension/dist/types/settings/shell.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/trigger.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/trigger.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/tsconfig.tsbuildinfo +1 -1
- package/src/native-ui/renderer-extension/dist/types/versioned-renderer-adapter.d.ts +18 -18
- package/src/native-ui/renderer-extension/dist/types/versioned-renderer-adapter.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/package.json +2 -2
- package/src/native-ui/renderer-extension/src/agent-group-preference.ts +1 -1
- package/src/native-ui/renderer-extension/src/agent-selection-state.ts +31 -16
- package/src/native-ui/renderer-extension/src/audit-entry.ts +1 -1
- package/src/native-ui/renderer-extension/src/contract-audit.ts +4 -4
- package/src/native-ui/renderer-extension/src/index.ts +4 -2
- package/src/native-ui/renderer-extension/src/install-renderer-binding.ts +2 -2
- package/src/native-ui/renderer-extension/src/production-entry.ts +3 -3
- package/src/native-ui/renderer-extension/src/renderer-agent-picker.ts +7 -7
- package/src/native-ui/renderer-extension/src/renderer-binding-probe.ts +112 -89
- package/src/native-ui/renderer-extension/src/renderer-codex-account-options.ts +1 -1
- package/src/native-ui/renderer-extension/src/renderer-codex-account-state.ts +1 -1
- package/src/native-ui/renderer-extension/src/renderer-collab-cards.ts +1 -1
- package/src/native-ui/renderer-extension/src/renderer-composer-dom.ts +12 -12
- package/src/native-ui/renderer-extension/src/renderer-credits-control.ts +7 -7
- package/src/native-ui/renderer-extension/src/renderer-external-steering.ts +3 -3
- package/src/native-ui/renderer-extension/src/renderer-fork-control.ts +1 -1
- package/src/native-ui/renderer-extension/src/renderer-harness-command-claim.ts +1 -1
- package/src/native-ui/renderer-extension/src/renderer-harness-command-control.ts +3 -3
- package/src/native-ui/renderer-extension/src/renderer-harness-handoff.ts +1 -1
- package/src/native-ui/renderer-extension/src/renderer-harness-localization.ts +1 -1
- package/src/native-ui/renderer-extension/src/renderer-harness-mentions.ts +4 -0
- package/src/native-ui/renderer-extension/src/renderer-integrations-client.ts +5 -5
- package/src/native-ui/renderer-extension/src/renderer-model-client.ts +63 -42
- package/src/native-ui/renderer-extension/src/renderer-model-picker.ts +16 -16
- package/src/native-ui/renderer-extension/src/renderer-new-thread-preference.ts +2 -2
- package/src/native-ui/renderer-extension/src/renderer-permission-mode-picker.ts +3 -3
- package/src/native-ui/renderer-extension/src/renderer-permission-mode-preference.ts +2 -2
- package/src/native-ui/renderer-extension/src/renderer-request-sender.ts +46 -3
- package/src/native-ui/renderer-extension/src/renderer-session-import-client.ts +4 -4
- package/src/native-ui/renderer-extension/src/renderer-sidebar-agent-icons.ts +24 -20
- package/src/native-ui/renderer-extension/src/renderer-team-cards.ts +312 -0
- package/src/native-ui/renderer-extension/src/renderer-transcript-dom.ts +1 -1
- package/src/native-ui/renderer-extension/src/renderer-trigger-chip-style.ts +2 -2
- package/src/native-ui/renderer-extension/src/renderer-usage-control.ts +4 -4
- package/src/native-ui/renderer-extension/src/settings/accounts-list.ts +1 -1
- package/src/native-ui/renderer-extension/src/settings/accounts-page.ts +1 -1
- package/src/native-ui/renderer-extension/src/settings/accounts-usage.ts +1 -1
- package/src/native-ui/renderer-extension/src/settings/connections-page.ts +7 -7
- package/src/native-ui/renderer-extension/src/settings/harness-accounts.ts +1 -1
- package/src/native-ui/renderer-extension/src/settings/icons.ts +2 -2
- package/src/native-ui/renderer-extension/src/settings/pages.ts +11 -11
- package/src/native-ui/renderer-extension/src/settings/pet-market.css +33 -0
- package/src/native-ui/renderer-extension/src/settings/pet-market.ts +173 -91
- package/src/native-ui/renderer-extension/src/settings/pets-client.ts +5 -5
- package/src/native-ui/renderer-extension/src/settings/release-notes.ts +1 -1
- package/src/native-ui/renderer-extension/src/settings/session-import-list-controls.ts +1 -1
- package/src/native-ui/renderer-extension/src/settings/session-import-page.ts +1 -1
- package/src/native-ui/renderer-extension/src/settings/shell.css +15 -15
- package/src/native-ui/renderer-extension/src/settings/shell.ts +11 -11
- package/src/native-ui/renderer-extension/src/settings/skin-runtime.ts +17 -17
- package/src/native-ui/renderer-extension/src/settings/trigger.ts +1 -1
- package/src/native-ui/renderer-extension/src/versioned-renderer-adapter.ts +20 -20
- package/src/native-ui/renderer-extension/test/agent-selection-state.test.ts +60 -1
- package/src/native-ui/renderer-extension/test/codebuddy-migration.test.ts +1 -1
- package/src/native-ui/renderer-extension/test/renderer-agent-picker.test.ts +1 -1
- package/src/native-ui/renderer-extension/test/renderer-binding-probe-host-catalog.test.ts +15 -9
- package/src/native-ui/renderer-extension/test/renderer-binding-probe.test.ts +15 -15
- package/src/native-ui/renderer-extension/test/renderer-codex-account-state.test.ts +1 -1
- package/src/native-ui/renderer-extension/test/renderer-composer-permissions.test.ts +4 -4
- package/src/native-ui/renderer-extension/test/renderer-external-steering-rpc.test.ts +2 -2
- package/src/native-ui/renderer-extension/test/renderer-external-steering.test.ts +3 -3
- package/src/native-ui/renderer-extension/test/renderer-fork-control.test.ts +4 -4
- package/src/native-ui/renderer-extension/test/renderer-harness-command-claim.test.ts +1 -1
- package/src/native-ui/renderer-extension/test/renderer-harness-command-control.test.ts +1 -1
- package/src/native-ui/renderer-extension/test/renderer-model-client.test.ts +12 -11
- package/src/native-ui/renderer-extension/test/renderer-model-picker.test.ts +1 -1
- package/src/native-ui/renderer-extension/test/renderer-native-thread-ownership.test.ts +6 -6
- package/src/native-ui/renderer-extension/test/renderer-new-thread-preference.test.ts +1 -1
- package/src/native-ui/renderer-extension/test/renderer-permission-mode-picker.test.ts +1 -1
- package/src/native-ui/renderer-extension/test/renderer-permission-mode-preference.test.ts +1 -1
- package/src/native-ui/renderer-extension/test/renderer-request-timeout.test.ts +80 -0
- package/src/native-ui/renderer-extension/test/renderer-settings-lifecycle.test.ts +2 -2
- package/src/native-ui/renderer-extension/test/renderer-sidebar-agent-icons.test.ts +10 -3
- package/src/native-ui/renderer-extension/test/renderer-unsupported-methods.test.ts +1 -1
- package/src/native-ui/renderer-extension/test/settings/pages.test.ts +5 -5
- package/src/native-ui/renderer-extension/test/settings/release-notes.test.ts +9 -9
- package/src/native-ui/renderer-extension/test/versioned-renderer-adapter.test.ts +3 -3
- package/src/native-ui/shared-contracts/dist/errors.d.ts +2 -2
- package/src/native-ui/shared-contracts/dist/errors.d.ts.map +1 -1
- package/src/native-ui/shared-contracts/dist/errors.js +1 -1
- package/src/native-ui/shared-contracts/dist/errors.js.map +1 -1
- package/src/native-ui/shared-contracts/dist/harness-models.d.ts +40 -0
- package/src/native-ui/shared-contracts/dist/harness-models.d.ts.map +1 -1
- package/src/native-ui/shared-contracts/dist/harness-models.js +23 -2
- package/src/native-ui/shared-contracts/dist/harness-models.js.map +1 -1
- package/src/native-ui/shared-contracts/dist/harness-route.d.ts +1 -1
- package/src/native-ui/shared-contracts/dist/harness-route.d.ts.map +1 -1
- package/src/native-ui/shared-contracts/dist/harness-route.js +1 -1
- package/src/native-ui/shared-contracts/dist/harness-route.js.map +1 -1
- package/src/native-ui/shared-contracts/dist/harness-session-import.d.ts +1 -1
- package/src/native-ui/shared-contracts/dist/harness-session-import.d.ts.map +1 -1
- package/src/native-ui/shared-contracts/dist/harness-session-import.js +1 -1
- package/src/native-ui/shared-contracts/dist/harness-session-import.js.map +1 -1
- package/src/native-ui/shared-contracts/dist/index.d.ts +3 -3
- package/src/native-ui/shared-contracts/dist/index.d.ts.map +1 -1
- package/src/native-ui/shared-contracts/dist/index.js +2 -2
- package/src/native-ui/shared-contracts/dist/index.js.map +1 -1
- package/src/native-ui/shared-contracts/dist/tsconfig.tsbuildinfo +1 -1
- package/src/native-ui/shared-contracts/dist/updates.js +1 -1
- package/src/native-ui/shared-contracts/dist/updates.js.map +1 -1
- package/src/native-ui/shared-contracts/package.json +1 -1
- package/src/native-ui/shared-contracts/src/errors.ts +3 -3
- package/src/native-ui/shared-contracts/src/harness-models.ts +23 -2
- package/src/native-ui/shared-contracts/src/harness-route.ts +1 -1
- package/src/native-ui/shared-contracts/src/harness-session-import.ts +1 -1
- package/src/native-ui/shared-contracts/src/index.ts +3 -3
- package/src/native-ui/shared-contracts/src/updates.ts +1 -1
- package/src/native-ui/shared-contracts/test/browser-bundle.test.ts +3 -3
- package/src/native-ui/shared-contracts/test/deepseek-modern-sessions.test.ts +1 -1
- package/src/native-ui/shared-contracts/test/errors.test.ts +9 -9
- package/src/native-ui/shared-contracts/test/harness-commands.test.ts +1 -1
- package/src/native-ui/shared-contracts/test/harness-models.test.ts +3 -3
- package/src/native-ui/shared-contracts/test/harness-permission-modes.test.ts +1 -1
- package/src/native-ui/shared-contracts/test/harness-plugins.test.ts +1 -1
- package/src/native-ui/shared-contracts/test/harness-session-import.test.ts +1 -1
- package/src/native-ui/shared-contracts/test/index.test.ts +3 -3
- package/src/native-ui/shared-contracts/test/json-rpc.test.ts +1 -1
- package/src/native-ui/shared-contracts/test/thread-usage.test.ts +1 -1
- package/src/native-ui/shared-contracts/test/updates.test.ts +4 -4
- /package/licenses/{codex-host-MIT.txt → bytepioneer-MIT.txt} +0 -0
|
@@ -119,8 +119,8 @@ async function main() {
|
|
|
119
119
|
const globalOnly = await blocked.ensureSkillRoots({ cwd: 'relative-not-absolute' }, adapters.get('codex'), {});
|
|
120
120
|
assert.equal(globalOnly.length, 1);
|
|
121
121
|
// Exercise the real protocol dispatcher without starting native processes.
|
|
122
|
-
assert.equal((await NativeProtocol.prototype.request.call({ runtime }, '
|
|
123
|
-
assert.equal((await NativeProtocol.prototype.request.call({ runtime }, '
|
|
122
|
+
assert.equal((await NativeProtocol.prototype.request.call({ runtime }, 'harnessmix/integrations/catalog', {})).harnesses.length, 17);
|
|
123
|
+
assert.equal((await NativeProtocol.prototype.request.call({ runtime }, 'harnessmix/integrations/list', local)).skills.length, 3);
|
|
124
124
|
console.log('integrations: scope precedence, persistence, native status projection, no credential fields, unsupported capabilities, skill install/disable/restore, links, and protocol PASS');
|
|
125
125
|
}
|
|
126
126
|
main().catch(error => { console.error(error); process.exitCode = 1; });
|
|
@@ -17,10 +17,10 @@ app.whenReady().then(async () => {
|
|
|
17
17
|
const preload = path.join(out, 'preload.cjs');
|
|
18
18
|
await fs.writeFile(preload, `const {contextBridge,ipcRenderer}=require('electron');contextBridge.exposeInMainWorld('integrationTest',{request:(method,params)=>ipcRenderer.invoke('integrations-test',method,params)});`);
|
|
19
19
|
ipcMain.handle('integrations-test', (_event, method, params) => {
|
|
20
|
-
assert.ok(method.startsWith('
|
|
20
|
+
assert.ok(method.startsWith('harnessmix/integrations/'));
|
|
21
21
|
return NativeProtocol.prototype.request.call({ runtime }, method, params);
|
|
22
22
|
});
|
|
23
|
-
const build = await esbuild.build({ stdin: { contents: `export {createMcpSettingsPage,createSkillsSettingsPage} from './src/native-ui/renderer-extension/src/settings/integrations-page.ts'; export {mountRendererSettingsShell} from './src/native-ui/renderer-extension/src/settings/shell.ts'; export {createRendererSettingsPageRegistry} from './src/native-ui/renderer-extension/src/settings/core.ts'; export {rendererSettingsMessages} from './src/native-ui/renderer-extension/src/settings/localization.ts'; export {createRendererIntegrationsClient} from './src/native-ui/renderer-extension/src/renderer-integrations-client.ts';`, resolveDir: process.cwd() }, bundle: true, platform: 'browser', format: 'iife', globalName: 'IntegrationUI', write: false, alias: { '@
|
|
23
|
+
const build = await esbuild.build({ stdin: { contents: `export {createMcpSettingsPage,createSkillsSettingsPage} from './src/native-ui/renderer-extension/src/settings/integrations-page.ts'; export {mountRendererSettingsShell} from './src/native-ui/renderer-extension/src/settings/shell.ts'; export {createRendererSettingsPageRegistry} from './src/native-ui/renderer-extension/src/settings/core.ts'; export {rendererSettingsMessages} from './src/native-ui/renderer-extension/src/settings/localization.ts'; export {createRendererIntegrationsClient} from './src/native-ui/renderer-extension/src/renderer-integrations-client.ts';`, resolveDir: process.cwd() }, bundle: true, platform: 'browser', format: 'iife', globalName: 'IntegrationUI', write: false, alias: { '@harnessmix/shared-contracts': path.resolve('src/native-ui/shared-contracts/src/index.ts') }, loader: { '.svg': 'dataurl', '.png': 'dataurl', '.css': 'text' } });
|
|
24
24
|
const consoleProblems = [];
|
|
25
25
|
const win = new BrowserWindow({ show: false, width: 1100, height: 900, webPreferences: { preload, contextIsolation: true, sandbox: true, offscreen: true } });
|
|
26
26
|
win.webContents.on('console-message', (_event, details) => { if (details.level === 'error' || details.level === 'warning') consoleProblems.push(details.message); });
|
|
@@ -74,7 +74,7 @@ app.whenReady().then(async () => {
|
|
|
74
74
|
await fs.writeFile(path.join(out, 'settings.png'), overviewImage);
|
|
75
75
|
await fs.writeFile(path.join(out, 'skills.png'), overviewImage);
|
|
76
76
|
await win.webContents.executeJavaScript(`(async()=>{
|
|
77
|
-
const root=document.querySelector('[data-
|
|
77
|
+
const root=document.querySelector('[data-harnessmix-settings-shell]').shadowRoot;
|
|
78
78
|
root.querySelector('button[data-page-id="mcp"]').click();
|
|
79
79
|
const wait=async predicate=>{for(let i=0;i<100;i++){if(predicate())return;await new Promise(r=>setTimeout(r,30));}throw Error('MCP screenshot timed out');};
|
|
80
80
|
await wait(()=>root.querySelector('select')?.options.length===17&&!root.querySelector('select').disabled);
|
|
@@ -92,7 +92,7 @@ app.whenReady().then(async () => {
|
|
|
92
92
|
await new Promise(r => setTimeout(r, 60));
|
|
93
93
|
await fs.writeFile(path.join(out, 'mcp-matrix.png'), (await win.webContents.capturePage()).toPNG());
|
|
94
94
|
await win.webContents.executeJavaScript(`(async()=>{
|
|
95
|
-
const root=document.querySelector('[data-
|
|
95
|
+
const root=document.querySelector('[data-harnessmix-settings-shell]').shadowRoot;
|
|
96
96
|
const byHarnessBtn=Array.from(root.querySelectorAll('.settings-mcp-tabs button')).find(b=>b.textContent.includes('Harness'));
|
|
97
97
|
byHarnessBtn?.click();
|
|
98
98
|
const wait=async predicate=>{for(let i=0;i<100;i++){if(predicate())return;await new Promise(r=>setTimeout(r,30));}throw Error('MCP switch timed out');};
|
|
@@ -101,7 +101,7 @@ app.whenReady().then(async () => {
|
|
|
101
101
|
await new Promise(r => setTimeout(r, 60));
|
|
102
102
|
await fs.writeFile(path.join(out, 'mcp-overview.png'), (await win.webContents.capturePage()).toPNG());
|
|
103
103
|
await win.webContents.executeJavaScript(`(async()=>{
|
|
104
|
-
const root=document.querySelector('[data-
|
|
104
|
+
const root=document.querySelector('[data-harnessmix-settings-shell]').shadowRoot;
|
|
105
105
|
const [harness,scope]=root.querySelectorAll('select');
|
|
106
106
|
harness.value='claude';harness.dispatchEvent(new Event('change'));
|
|
107
107
|
const wait=async predicate=>{for(let i=0;i<100;i++){if(predicate())return;await new Promise(r=>setTimeout(r,30));}throw Error('MCP reload timed out');};
|
|
@@ -111,7 +111,7 @@ app.whenReady().then(async () => {
|
|
|
111
111
|
})()`);
|
|
112
112
|
await fs.writeFile(path.join(out, 'mcp.png'), (await win.webContents.capturePage()).toPNG());
|
|
113
113
|
await win.webContents.executeJavaScript(`(async()=>{
|
|
114
|
-
const root=document.querySelector('[data-
|
|
114
|
+
const root=document.querySelector('[data-harnessmix-settings-shell]').shadowRoot;
|
|
115
115
|
const mcpRow=Array.from(root.querySelectorAll('.settings-integrations-row')).find(r=>r.querySelector('strong')?.textContent?.includes('ui-probe'));
|
|
116
116
|
mcpRow.querySelector('button').click();
|
|
117
117
|
const wait=async predicate=>{for(let i=0;i<100;i++){if(predicate())return;await new Promise(r=>setTimeout(r,30));}throw Error('MCP editor timed out');};
|
|
@@ -7,16 +7,16 @@ const { isCodexTaskEnvironment, readLiveHostInstance } = require('../src/main/na
|
|
|
7
7
|
|
|
8
8
|
const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-mix-config-'));
|
|
9
9
|
try {
|
|
10
|
-
const source = {
|
|
10
|
+
const source = { HARNESSMIX_DATA_DIR: directory, HARNESSMIX_PI_COMMAND: 'C:\\Native tools\\pi.cmd', PRIVATE_TEST_VALUE: 'do-not-persist' };
|
|
11
11
|
const env = nativeEnvironment(source);
|
|
12
|
-
assert.equal(source.
|
|
13
|
-
assert.equal(env.
|
|
12
|
+
assert.equal(source.HARNESSMIX_DEFAULT_AGENT, undefined, 'Input environment is not mutated');
|
|
13
|
+
assert.equal(env.HARNESSMIX_DEFAULT_AGENT, 'codex');
|
|
14
14
|
saveNativeSettings(env);
|
|
15
15
|
const saved = JSON.parse(fs.readFileSync(path.join(directory, 'harness-mix-settings.json'), 'utf8'));
|
|
16
|
-
assert.deepEqual(saved, {
|
|
17
|
-
assert.equal(nativeEnvironment({
|
|
16
|
+
assert.deepEqual(saved, { HARNESSMIX_PI_COMMAND: source.HARNESSMIX_PI_COMMAND });
|
|
17
|
+
assert.equal(nativeEnvironment({ HARNESSMIX_DATA_DIR: directory }).HARNESSMIX_PI_COMMAND, source.HARNESSMIX_PI_COMMAND,
|
|
18
18
|
'AppX child recovers command settings from the data directory');
|
|
19
|
-
assert.equal(nativeEnvironment({
|
|
19
|
+
assert.equal(nativeEnvironment({ HARNESSMIX_DATA_DIR: directory, HARNESSMIX_PI_COMMAND: 'D:\\other\\pi.cmd' }).HARNESSMIX_PI_COMMAND,
|
|
20
20
|
'D:\\other\\pi.cmd', 'Explicit environment takes priority');
|
|
21
21
|
for (const file of Object.values(nativePaths())) assert.ok(fs.statSync(file).isFile(), file);
|
|
22
22
|
const runtimeDirectory = path.join(directory, 'runtime');
|
|
@@ -54,7 +54,7 @@ const alive = pid => {
|
|
|
54
54
|
...process.env,
|
|
55
55
|
HARNESS_MIX_HOST_SCRIPT: fixture,
|
|
56
56
|
HARNESS_MIX_NODE_PATH: process.execPath,
|
|
57
|
-
|
|
57
|
+
HARNESSMIX_STOCK_CODEX_PATH: process.execPath,
|
|
58
58
|
FAKE_HOST_PIDS: pidFile,
|
|
59
59
|
},
|
|
60
60
|
stdio: ['ignore', 'ignore', 'pipe'],
|
|
@@ -74,22 +74,22 @@ async function main() {
|
|
|
74
74
|
const schemas = require(schemaPath);
|
|
75
75
|
const version = await bridge.request('harness-mix/runtime/version');
|
|
76
76
|
assert.equal(version.version, require('../package.json').version, 'About page reads the installed package version');
|
|
77
|
-
const accounts = await bridge.request('
|
|
77
|
+
const accounts = await bridge.request('harnessmix/account/list');
|
|
78
78
|
schemas.codexAccountListResultSchema.parse(accounts);
|
|
79
79
|
assert.equal(accounts.accounts[0].email, 'native@example.com', 'Official account/read is projected into Account management');
|
|
80
80
|
assert.equal(accounts.accounts[0].authenticated, true);
|
|
81
81
|
assert.equal(accounts.accounts[0].management, 'native');
|
|
82
|
-
const accountUsage = await bridge.request('
|
|
82
|
+
const accountUsage = await bridge.request('harnessmix/account/usage/inspect', { accountId: 'official-codex' });
|
|
83
83
|
schemas.codexAccountUsageResultSchema.parse(accountUsage);
|
|
84
84
|
assert.equal(accountUsage.usage.planFiveHourUsedPercent, 33);
|
|
85
85
|
assert.equal(accountUsage.usage.planSevenDayUsedPercent, 29);
|
|
86
86
|
assert.equal(accountUsage.accountCredits.periodType, 'five_hour');
|
|
87
87
|
assert.equal(accountUsage.accountCredits.productUsage[0].product, '7-day window');
|
|
88
|
-
const login = await bridge.request('
|
|
88
|
+
const login = await bridge.request('harnessmix/account/login/start', { accountId: 'official-codex' });
|
|
89
89
|
schemas.codexAccountLoginStartResultSchema.parse(login);
|
|
90
90
|
assert.equal(login.userCode, 'ABCD-EFGH');
|
|
91
|
-
assert.deepEqual(await bridge.request('
|
|
92
|
-
const loggedOut = await bridge.request('
|
|
91
|
+
assert.deepEqual(await bridge.request('harnessmix/account/login/cancel', { accountId: 'official-codex', loginId: 'native-login' }), { cancelled: true });
|
|
92
|
+
const loggedOut = await bridge.request('harnessmix/account/logout');
|
|
93
93
|
schemas.codexAccountMutationResultSchema.parse(loggedOut);
|
|
94
94
|
assert.equal(loggedOut.account.authenticated, false);
|
|
95
95
|
let openedCodexThread = null;
|
|
@@ -109,30 +109,36 @@ async function main() {
|
|
|
109
109
|
},
|
|
110
110
|
close() {},
|
|
111
111
|
};
|
|
112
|
-
const isolated = await bridge.request('thread/start', { cwd: root, model: 'gpt-test',
|
|
112
|
+
const isolated = await bridge.request('thread/start', { cwd: root, model: 'gpt-test', __harnessmixAccountId: 'account-work' });
|
|
113
113
|
assert.equal(decodeRoute(isolated.thread.model).harnessId, 'codex-harness', 'An isolated Codex Account becomes an owned Codex adapter Thread');
|
|
114
114
|
assert.equal(openedCodexThread.options.accountId, 'account-work');
|
|
115
115
|
assert.equal(openedCodexThread.options.codexHome, path.join(root, 'isolated-codex-home'));
|
|
116
116
|
assert.equal(openedCodexThread.options.model.id, 'gpt-test');
|
|
117
117
|
const inspection = await bridge.inspect('pi');
|
|
118
118
|
schemas.harnessInspectionSchema.parse(inspection);
|
|
119
|
+
assert.deepEqual(inspection.capabilities.workspace, { git: true, worktree: true, finalDiff: true, nativeDiff: false, nativePatch: false });
|
|
119
120
|
assert.equal(inspection.catalog.defaultThinkingOptionId, 'high', 'Declared default thinking level projects to the catalog');
|
|
120
121
|
assert.ok(inspection.catalog.models.every(m => m.supportedThinkingOptionIds?.join(',') === 'high,low'), 'Every catalog model carries the selectable thinking set');
|
|
121
|
-
schemas.harnessPluginListResultSchema.parse(await bridge.request('
|
|
122
|
+
schemas.harnessPluginListResultSchema.parse(await bridge.request('harnessmix/harness/plugins/list'));
|
|
122
123
|
const started = await bridge.request('thread/start', { cwd: root, model: routeModel('pi') });
|
|
123
124
|
const threadId = started.thread.id;
|
|
125
|
+
const threadInspection = await bridge.request('harnessmix/thread/inspect', { threadId });
|
|
126
|
+
schemas.threadInspectionSchema.parse(threadInspection);
|
|
127
|
+
assert.equal(threadInspection.workspace.hostManaged, true);
|
|
128
|
+
assert.equal(threadInspection.workspace.finalDiff.source, 'snapshot');
|
|
129
|
+
assert.equal(threadInspection.workspace.worktree.available, true);
|
|
124
130
|
assert.equal(started.thread.sessionId, threadId, 'Desktop session identity is the host thread, not a native session id');
|
|
125
|
-
assert.equal(started.thread.model, '
|
|
131
|
+
assert.equal(started.thread.model, 'harnessmix/pi-native');
|
|
126
132
|
const { includesThread } = require('../src/main/native/thread-list');
|
|
127
133
|
const storedThread = runtime.threads.find(t => t.id === threadId);
|
|
128
|
-
const hostCommands = await bridge.request('
|
|
134
|
+
const hostCommands = await bridge.request('harnessmix/thread/commands/inspect', { threadId });
|
|
129
135
|
assert.ok(hostCommands.commands.some(command => command.id === 'verify'));
|
|
130
136
|
assert.ok(hostCommands.commands.some(command => command.id === 'gate'));
|
|
131
|
-
const gate = await bridge.request('
|
|
137
|
+
const gate = await bridge.request('harnessmix/thread/verification/configure', { threadId, policy: { mode: 'required', checks: { cleanWorkingTree: false } } });
|
|
132
138
|
assert.equal(gate.policy.mode, 'required');
|
|
133
139
|
assert.equal(gate.satisfied, false);
|
|
134
|
-
assert.equal((await bridge.request('
|
|
135
|
-
const storage = await bridge.request('
|
|
140
|
+
assert.equal((await bridge.request('harnessmix/thread/verification/get', { threadId })).policy.mode, 'required');
|
|
141
|
+
const storage = await bridge.request('harnessmix/storage/inspect');
|
|
136
142
|
assert.equal(storage.schemaVersion, 2);
|
|
137
143
|
assert.ok(storage.threadCount >= 1);
|
|
138
144
|
assert.equal(includesThread(storedThread, { sectionId: section.id }), false);
|
|
@@ -155,7 +161,7 @@ async function main() {
|
|
|
155
161
|
await bridge.request('turn/interrupt', { threadId: prewarmed.thread.id });
|
|
156
162
|
await wait(() => !runtime.threads.find(t => t.id === prewarmed.thread.id).reviewPending && !runtime.sending.has(prewarmed.thread.id));
|
|
157
163
|
emit = emits[0]; // 恢复主线程的事件源(open 顺序:主线程序,预热线程后)
|
|
158
|
-
schemas.threadInspectionSchema.parse(await bridge.request('
|
|
164
|
+
schemas.threadInspectionSchema.parse(await bridge.request('harnessmix/thread/inspect', { threadId }));
|
|
159
165
|
const turn = await bridge.request('turn/start', { threadId, input: [{ type: 'text', text: 'test' }], approvalPolicy: 'never', sandboxPolicy: { type: 'dangerFullAccess' } });
|
|
160
166
|
// turn/start 在 currentTurn 建立后即返回,adapter.send 的调用在其后;等待透传到达
|
|
161
167
|
await wait(() => sendExtras.at(-1)?.turnPermissions != null);
|
|
@@ -252,7 +258,7 @@ async function main() {
|
|
|
252
258
|
]) {
|
|
253
259
|
assert.equal(await bridge.request(method, params), undefined, `Official Codex ${method} passes through`);
|
|
254
260
|
}
|
|
255
|
-
assert.deepEqual(await bridge.request('
|
|
261
|
+
assert.deepEqual(await bridge.request('harnessmix/thread/ownership/list', { threadIds: ['official-thread', threadId] }), {
|
|
256
262
|
threads: [
|
|
257
263
|
{ threadId: 'official-thread', owner: 'codex' },
|
|
258
264
|
{ threadId, owner: 'external', harnessId: 'pi' },
|
|
@@ -267,25 +273,25 @@ async function main() {
|
|
|
267
273
|
hooks.emit({ kind: 'usage', usage: { input: 20, output: 5, cacheRead: 10, tokens: 30, contextWindow: 100, cost: 0.01 } });
|
|
268
274
|
hooks.emit({ kind: 'completed', finalAnswer: true });
|
|
269
275
|
};
|
|
270
|
-
const command = await bridge.request('
|
|
276
|
+
const command = await bridge.request('harnessmix/thread/command/execute', { threadId, commandId: 'compact' });
|
|
271
277
|
schemas.threadCommandExecuteResultSchema.parse(command);
|
|
272
278
|
await wait(() => compactCalls === 1 && !runtime.threads.find(t => t.id === threadId).reviewPending && !runtime.sending.has(threadId));
|
|
273
|
-
const usage = await bridge.request('
|
|
279
|
+
const usage = await bridge.request('harnessmix/thread/usage/inspect', { threadId });
|
|
274
280
|
schemas.threadUsageInspectionSchema.parse(usage);
|
|
275
281
|
assert.equal(usage.usage.inputTokens, 20);
|
|
276
282
|
assert.equal(usage.usage.contextUsagePercent, 30);
|
|
277
|
-
assert.ok(events.some(e => e.method === '
|
|
278
|
-
await assert.rejects(bridge.request('
|
|
283
|
+
assert.ok(events.some(e => e.method === 'harnessmix/thread/usage/updated' && e.params.usage?.cachedInputTokens === 10));
|
|
284
|
+
await assert.rejects(bridge.request('harnessmix/thread/command/execute', { threadId, commandId: 'missing' }), /不支持此指令/);
|
|
279
285
|
// ===== 新 Harness 路由:omp / opencode / grok 的 legacy 传输串解码与投影 =====
|
|
280
|
-
assert.equal(routeModel('omp'), '
|
|
281
|
-
assert.equal(routeModel('opencode'), '
|
|
282
|
-
assert.equal(routeModel('grok'), '
|
|
283
|
-
assert.deepEqual(decodeRoute('
|
|
284
|
-
assert.deepEqual(decodeRoute('
|
|
285
|
-
assert.deepEqual(decodeRoute('
|
|
286
|
-
assert.deepEqual(decodeRoute('
|
|
287
|
-
assert.deepEqual(decodeRoute('
|
|
288
|
-
assert.throws(() => decodeRoute('
|
|
286
|
+
assert.equal(routeModel('omp'), 'harnessmix/omp-native');
|
|
287
|
+
assert.equal(routeModel('opencode'), 'harnessmix/opencode-native');
|
|
288
|
+
assert.equal(routeModel('grok'), 'harnessmix/grok-native');
|
|
289
|
+
assert.deepEqual(decodeRoute('harnessmix/omp-native'), { harnessId: 'omp' });
|
|
290
|
+
assert.deepEqual(decodeRoute('harnessmix/omp-native@model-x@high'), { harnessId: 'omp', model: { id: 'model-x' }, thinkingOptionId: 'high' }, 'OMP 两段式 = model@thinking');
|
|
291
|
+
assert.deepEqual(decodeRoute('harnessmix/omp-native@model-x@approve@high'), { harnessId: 'omp', model: { id: 'model-x' }, permissionModeId: 'approve', thinkingOptionId: 'high' }, 'OMP 三段式 = model@permission@thinking');
|
|
292
|
+
assert.deepEqual(decodeRoute('harnessmix/opencode-native@m@perm'), { harnessId: 'opencode', model: { id: 'm' }, permissionModeId: 'perm' });
|
|
293
|
+
assert.deepEqual(decodeRoute('harnessmix/grok-native@m@@think'), { harnessId: 'grok', model: { id: 'm' }, thinkingOptionId: 'think' });
|
|
294
|
+
assert.throws(() => decodeRoute('harnessmix/omp-native@a@b@c@d'), /Invalid native Harness route/);
|
|
289
295
|
// ===== 跨 Harness 协作:委派 → 消息 → 等待 → 级联取消 =====
|
|
290
296
|
const childEmits = [];
|
|
291
297
|
let childSend;
|
|
@@ -298,11 +304,11 @@ async function main() {
|
|
|
298
304
|
async close() {} };
|
|
299
305
|
runtime.adapters.set('claude', childAdapter); runtime.status.claude = { available: true };
|
|
300
306
|
// Host 级 /delegate 指令出现在命令目录中(insert 型,填入输入框)
|
|
301
|
-
const commandList = await bridge.request('
|
|
307
|
+
const commandList = await bridge.request('harnessmix/thread/commands/inspect', { threadId });
|
|
302
308
|
assert.ok(commandList.commands.some(c => c.invocation === '/delegate' && c.argumentMode === 'text'), 'Host 级 /delegate 指令应出现在命令目录');
|
|
303
309
|
// 委派:协议入口创建子任务线程并挂起父线程协作 Turn
|
|
304
310
|
childSend = hooks => { hooks.emit({ kind: 'text-delta', text: '子任务结论' }); hooks.emit({ kind: 'completed', finalAnswer: true }); };
|
|
305
|
-
const delegated = await bridge.request('
|
|
311
|
+
const delegated = await bridge.request('harnessmix/thread/delegate', { threadId, harnessId: 'claude-code', task: '审查代码' });
|
|
306
312
|
schemas.threadDelegationResultSchema.parse(delegated);
|
|
307
313
|
assert.equal(delegated.turn.status, 'inProgress', '委派后父线程协作 Turn 保持活动');
|
|
308
314
|
assert.ok(delegated.turn?.id, 'Delegation starts a parent collaboration Turn');
|
|
@@ -322,13 +328,13 @@ async function main() {
|
|
|
322
328
|
assert.equal(delegateTool.status, 'completed', '子任务结算后协作工具项完成');
|
|
323
329
|
assert.ok(String(delegateTool.output).includes('子任务结论'), '协作工具项携带子任务最终答复');
|
|
324
330
|
// 消息链:向同一子任务跟进(复用既有子线程)
|
|
325
|
-
const followUp = await bridge.request('
|
|
331
|
+
const followUp = await bridge.request('harnessmix/thread/message', { threadId, childThreadId: childId, text: '再检查一遍' });
|
|
326
332
|
schemas.threadDelegationResultSchema.parse(followUp);
|
|
327
333
|
await wait(() => !runtime.execution.isRunning(threadId));
|
|
328
334
|
assert.deepEqual(childAdapter.sendCalls, ['审查代码', '再检查一遍'], '跟进消息进入同一子任务');
|
|
329
335
|
assert.equal(followUp.childThreadId, childId);
|
|
330
336
|
// 循环防护:子任务不能继续委派
|
|
331
|
-
await assert.rejects(bridge.request('
|
|
337
|
+
await assert.rejects(bridge.request('harnessmix/thread/delegate', { threadId: childId, harnessId: 'pi', task: 'x' }), /暂不支持继续委派/);
|
|
332
338
|
// 斜杠通道:/delegate 文本走同一委派链路
|
|
333
339
|
childSend = hooks => { hooks.emit({ kind: 'text-delta', text: '斜杠委派完成' }); hooks.emit({ kind: 'completed', finalAnswer: true }); };
|
|
334
340
|
const slashTurn = await bridge.request('turn/start', { threadId, input: [{ type: 'text', text: '/delegate claude 用斜杠通道' }] });
|
|
@@ -338,7 +344,7 @@ async function main() {
|
|
|
338
344
|
await assert.rejects(bridge.request('turn/start', { threadId, input: [{ type: 'text', text: '/delegate' }] }), /用法:\/delegate/);
|
|
339
345
|
// 级联取消:中断父线程协作 Turn ⇒ 子任务被取消
|
|
340
346
|
childSend = () => new Promise(() => {}); // 子任务永不自行结算
|
|
341
|
-
const stuck = await bridge.request('
|
|
347
|
+
const stuck = await bridge.request('harnessmix/thread/delegate', { threadId, harnessId: 'claude', task: '长跑任务' });
|
|
342
348
|
assert.ok(runtime.execution.isRunning(threadId), '父线程协作 Turn 等待子任务');
|
|
343
349
|
await bridge.request('turn/interrupt', { threadId });
|
|
344
350
|
await wait(() => !runtime.execution.isRunning(threadId) && !runtime.execution.isRunning(stuck.childThreadId));
|
|
@@ -350,8 +356,8 @@ async function main() {
|
|
|
350
356
|
await assert.rejects(bridge.request('thread/fork', { threadId, excludeTurns: true }), /Ephemeral fork is not supported/);
|
|
351
357
|
await assert.rejects(bridge.request('thread/start', { cwd: root, model: routeModel('pi'), ephemeral: true, threadSource: 'thread_description' }), /Ephemeral background thread is not supported/);
|
|
352
358
|
// Worktree 隔离工作区丢弃与推送协议接口
|
|
353
|
-
await assert.rejects(bridge.request('
|
|
354
|
-
await assert.rejects(bridge.request('
|
|
359
|
+
await assert.rejects(bridge.request('harnessmix/thread/workspace/discard', { threadId }), /该任务未使用 Worktree 隔离工作区/);
|
|
360
|
+
await assert.rejects(bridge.request('harnessmix/thread/workspace/push', { threadId }), /该任务未使用 Worktree 隔离工作区/);
|
|
355
361
|
const dummyWorktreeThread = await bridge.request('thread/start', { cwd: root, model: routeModel('pi') });
|
|
356
362
|
const dummyThreadId = dummyWorktreeThread.thread.id;
|
|
357
363
|
const dummyWorkspaceDir = path.join(root, 'dummy-wt');
|
|
@@ -362,12 +368,12 @@ async function main() {
|
|
|
362
368
|
root: dummyWorkspaceDir,
|
|
363
369
|
cwd: dummyWorkspaceDir,
|
|
364
370
|
source: root,
|
|
365
|
-
branch: '
|
|
371
|
+
branch: 'harnessmix/test-wt-branch',
|
|
366
372
|
};
|
|
367
|
-
await assert.rejects(bridge.request('
|
|
368
|
-
const discardResult = await bridge.request('
|
|
373
|
+
await assert.rejects(bridge.request('harnessmix/thread/workspace/push', { threadId: dummyThreadId }), /git/i);
|
|
374
|
+
const discardResult = await bridge.request('harnessmix/thread/workspace/discard', { threadId: dummyThreadId });
|
|
369
375
|
assert.equal(discardResult.discarded, true);
|
|
370
|
-
assert.equal(discardResult.branch, '
|
|
376
|
+
assert.equal(discardResult.branch, 'harnessmix/test-wt-branch');
|
|
371
377
|
assert.equal(dummyTargetThread.workspace, undefined, 'Discard deletes thread.workspace');
|
|
372
378
|
|
|
373
379
|
// 消息排队(thread/queue/add, list, update, reorder, delete, start)能力验证
|
|
@@ -20,7 +20,7 @@ const wait = async fn => { for (let n = 0; n < 400; n++) { if (fn()) return; awa
|
|
|
20
20
|
runtime.adapters.set('pi', adapter); runtime.status.pi = { available: true };
|
|
21
21
|
const bridge = new NativeProtocol(runtime, () => {});
|
|
22
22
|
try {
|
|
23
|
-
const { thread } = await bridge.request('thread/start', { cwd: root, model: '
|
|
23
|
+
const { thread } = await bridge.request('thread/start', { cwd: root, model: 'harnessmix/pi-native' });
|
|
24
24
|
for (const text of ['kept', 'removed']) {
|
|
25
25
|
await bridge.request('turn/start', { threadId: thread.id, input: [{ type: 'text', text }] });
|
|
26
26
|
await wait(() => !runtime.execution.isRunning(thread.id) && !runtime.threads[0].reviewPending);
|
|
@@ -31,7 +31,7 @@ const helper = [
|
|
|
31
31
|
|
|
32
32
|
// --- real helper: DPAPI vault round-trip on a temp data dir ---
|
|
33
33
|
const data = fs.mkdtempSync(path.join(os.tmpdir(), 'hm-secret-'));
|
|
34
|
-
const env = { ...process.env,
|
|
34
|
+
const env = { ...process.env, HARNESSMIX_DATA_DIR: data };
|
|
35
35
|
const call = (args, input) => execFileSync(helper, args, { encoding: 'utf8', windowsHide: true, env, input });
|
|
36
36
|
call(['set', 'demo.token'], 'super-secret-value');
|
|
37
37
|
assert.equal(call(['get', 'demo.token']), 'super-secret-value');
|
|
@@ -12,7 +12,7 @@ async function main() {
|
|
|
12
12
|
const host = path.join(work, 'fixture host.cjs');
|
|
13
13
|
const stockProbe = path.join(work, 'stock probe.cjs');
|
|
14
14
|
const env = { ...process.env, HARNESS_MIX_NODE_PATH: process.execPath,
|
|
15
|
-
|
|
15
|
+
HARNESSMIX_STOCK_CODEX_PATH: process.execPath, HARNESS_MIX_HOST_SCRIPT: host, CODEX_CLI_PATH: 'must-be-removed' };
|
|
16
16
|
let child;
|
|
17
17
|
try {
|
|
18
18
|
fs.writeFileSync(host, `const readline = require('node:readline');
|
|
@@ -55,13 +55,13 @@ async function testPrewarm() {
|
|
|
55
55
|
const manager = { onNotification() {}, onRequest() {}, dispatchAppServerResponse() {} };
|
|
56
56
|
const target = {};
|
|
57
57
|
installDraftPrewarmPolicyBridge(manager, bridge, 'local', target, { discardAllPrewarmedThreads() {} });
|
|
58
|
-
const policy = target.
|
|
58
|
+
const policy = target.__harnessmixDraftPrewarmPolicyV1;
|
|
59
59
|
for (const harness of ['pi', 'claude-code', 'deepseek-harness', 'antigravity']) {
|
|
60
|
-
policy.select(`
|
|
60
|
+
policy.select(`harnessmix/${harness}-native`);
|
|
61
61
|
bridge.prewarmThreadStart({ cwd: 'E:/project', model: 'gpt-test' });
|
|
62
62
|
bridge.sendRequest('thread/start', { cwd: 'E:/project', model: 'gpt-test' });
|
|
63
63
|
assert.equal(prewarmed.at(-1).ephemeral, true);
|
|
64
|
-
assert.equal(prewarmed.at(-1).model, `
|
|
64
|
+
assert.equal(prewarmed.at(-1).model, `harnessmix/${harness}-native`);
|
|
65
65
|
assert.equal(sent.at(-1).params.ephemeral, undefined);
|
|
66
66
|
}
|
|
67
67
|
bridge.prewarmThreadStart({ ephemeral: true, model: 'gpt-title' });
|
|
@@ -72,7 +72,7 @@ async function testPrewarm() {
|
|
|
72
72
|
policy.dispose();
|
|
73
73
|
console.log('PASS: all four external prewarm routes stay ephemeral; actual starts and Codex internal tasks are preserved');
|
|
74
74
|
const sidebarFile = path.join(root, 'sidebar.cjs');
|
|
75
|
-
await require('esbuild').build({ entryPoints: ['src/native-ui/renderer-extension/src/renderer-sidebar-agent-icons.ts'], outfile: sidebarFile, bundle: true, platform: 'node', format: 'cjs', alias: { '@
|
|
75
|
+
await require('esbuild').build({ entryPoints: ['src/native-ui/renderer-extension/src/renderer-sidebar-agent-icons.ts'], outfile: sidebarFile, bundle: true, platform: 'node', format: 'cjs', alias: { '@harnessmix/shared-contracts': path.resolve('src/native-ui/shared-contracts/src/index.ts') }, loader: { '.png': 'dataurl', '.svg': 'dataurl' }, logLevel: 'silent' });
|
|
76
76
|
const { installRendererSidebarAgentIcons } = require(sidebarFile);
|
|
77
77
|
let cleared = 0;
|
|
78
78
|
let agent = null;
|
|
@@ -12,13 +12,13 @@ app.whenReady().then(async () => {
|
|
|
12
12
|
const icons = getAllIconsDictionary();
|
|
13
13
|
icons.harnesses['claude-code'] = icons.harnesses.claude;
|
|
14
14
|
icons.harnesses['deepseek-harness'] = icons.harnesses.dsh;
|
|
15
|
-
const bundle = await esbuild.build({ stdin: { contents: `export { createRendererAgentIcon } from './src/native-ui/renderer-extension/src/renderer-agent-icon.ts'; export { mountRendererAgentPicker, renderRendererAgentPicker } from './src/native-ui/renderer-extension/src/renderer-agent-picker.ts'; export { mountRendererModelPicker, renderRendererModelPicker } from './src/native-ui/renderer-extension/src/renderer-model-picker.ts'; export { mountRendererHarnessHandoff } from './src/native-ui/renderer-extension/src/renderer-harness-handoff.ts'; export { restoredThreadOwnership } from './src/native-ui/renderer-extension/src/renderer-binding-probe.ts'; export { installRendererSidebarAgentIcons } from './src/native-ui/renderer-extension/src/renderer-sidebar-agent-icons.ts'; export { installRendererSettingsLifecycle } from './src/native-ui/renderer-extension/src/harness-mix-settings.ts'; export { createAccountsSettingsPage } from './src/native-ui/renderer-extension/src/settings/accounts-page.ts'; export { createStorageSettingsPage } from './src/native-ui/renderer-extension/src/settings/storage-page.ts'; export { createSkinSettingsPage } from './src/native-ui/renderer-extension/src/settings/skin-market.ts'; export { applyRendererSkin } from './src/native-ui/renderer-extension/src/settings/skin-runtime.ts'; export { aboutPage } from './src/native-ui/renderer-extension/src/settings/pages.ts'; export { rendererSettingsMessages } from './src/native-ui/renderer-extension/src/settings/localization.ts'; export { installRendererSettingsShell } from './src/native-ui/renderer-extension/src/settings/shell.ts';`, resolveDir: process.cwd() }, bundle: true, alias: { '@
|
|
15
|
+
const bundle = await esbuild.build({ stdin: { contents: `export { createRendererAgentIcon } from './src/native-ui/renderer-extension/src/renderer-agent-icon.ts'; export { mountRendererAgentPicker, renderRendererAgentPicker } from './src/native-ui/renderer-extension/src/renderer-agent-picker.ts'; export { mountRendererModelPicker, renderRendererModelPicker } from './src/native-ui/renderer-extension/src/renderer-model-picker.ts'; export { mountRendererHarnessHandoff } from './src/native-ui/renderer-extension/src/renderer-harness-handoff.ts'; export { restoredThreadOwnership } from './src/native-ui/renderer-extension/src/renderer-binding-probe.ts'; export { installRendererSidebarAgentIcons } from './src/native-ui/renderer-extension/src/renderer-sidebar-agent-icons.ts'; export { installRendererSettingsLifecycle } from './src/native-ui/renderer-extension/src/harness-mix-settings.ts'; export { createAccountsSettingsPage } from './src/native-ui/renderer-extension/src/settings/accounts-page.ts'; export { createStorageSettingsPage } from './src/native-ui/renderer-extension/src/settings/storage-page.ts'; export { createSkinSettingsPage } from './src/native-ui/renderer-extension/src/settings/skin-market.ts'; export { applyRendererSkin } from './src/native-ui/renderer-extension/src/settings/skin-runtime.ts'; export { aboutPage } from './src/native-ui/renderer-extension/src/settings/pages.ts'; export { rendererSettingsMessages } from './src/native-ui/renderer-extension/src/settings/localization.ts'; export { installRendererSettingsShell } from './src/native-ui/renderer-extension/src/settings/shell.ts';`, resolveDir: process.cwd() }, bundle: true, alias: { '@harnessmix/shared-contracts': path.resolve('src/native-ui/shared-contracts/src/index.ts') }, platform: 'browser', format: 'iife', globalName: 'NativeUI', write: false, loader: { '.svg': 'dataurl', '.png': 'dataurl', '.webp': 'dataurl', '.css': 'text' }, logLevel: 'silent' });
|
|
16
16
|
const win = new BrowserWindow({ show: false, width: 900, height: 650, webPreferences: { contextIsolation: true, sandbox: true, offscreen: true, backgroundThrottling: false } });
|
|
17
17
|
await win.loadURL('data:text/html,<html><head><style>body{background:%2317191d;color:white;font:16px Arial;padding:40px}button{background:%23272a30;color:white;border:0;padding:12px}img{vertical-align:middle}main{display:flex;gap:25px;margin-bottom:40px}</style></head><body><h2>Harness Mix native components</h2><main></main></body></html>');
|
|
18
18
|
await win.webContents.executeJavaScript(`globalThis.__HARNESS_MIX_ICONS__=${JSON.stringify(icons)};globalThis.__HARNESS_MIX_MODEL_FAMILIES__=${JSON.stringify(MODEL_FAMILIES.map(f => ({ id: f.id, pattern: f.regex.source })))};${bundle.outputFiles[0].text}`);
|
|
19
19
|
const liveSettingsPages = await win.webContents.executeJavaScript(`(() => {
|
|
20
20
|
const lifecycle = NativeUI.installRendererSettingsLifecycle(window, {});
|
|
21
|
-
const pageIds = globalThis.
|
|
21
|
+
const pageIds = globalThis.__harnessmixSettingsShellV1.registry.pages.map(page => page.id);
|
|
22
22
|
lifecycle.dispose();
|
|
23
23
|
return pageIds;
|
|
24
24
|
})()`);
|
|
@@ -26,7 +26,7 @@ app.whenReady().then(async () => {
|
|
|
26
26
|
const { NativeProtocol } = require('../src/main/native/protocol');
|
|
27
27
|
const nativeThreads = ['pi', 'claude', 'dsh', 'antigravity'].map((harnessId, index) => ({ id: 'sidebar-' + index, harnessId, model: { id: 'model-' + index, provider: 'native' }, options: {} }));
|
|
28
28
|
const protocol = new NativeProtocol({ threads: nativeThreads, getThread: id => nativeThreads.find(thread => thread.id === id), subscribe: () => () => {}, core: { subscribe: () => () => {} }, describe: async () => ({}), getCapabilities: () => ({}) }, () => {});
|
|
29
|
-
const inspections = await Promise.all(nativeThreads.map(thread => protocol.request('
|
|
29
|
+
const inspections = await Promise.all(nativeThreads.map(thread => protocol.request('harnessmix/thread/inspect', { threadId: thread.id })));
|
|
30
30
|
await win.webContents.executeJavaScript(`globalThis.testInspections=${JSON.stringify(inspections)}`);
|
|
31
31
|
const result = await win.webContents.executeJavaScript(`(async () => {
|
|
32
32
|
const agents = ['codex','pi','claude-code','deepseek-harness','antigravity','omp','opencode','grok'];
|
|
@@ -43,10 +43,10 @@ app.whenReady().then(async () => {
|
|
|
43
43
|
}
|
|
44
44
|
const decoration = NativeUI.installRendererSidebarAgentIcons({ getClient: () => ({ listThreadOwnership: async ({threadIds}) => ({threads: threadIds.map(threadId => { const agent = agents[Number(threadId.slice(4))]; return agent === 'codex' ? {threadId, owner:'codex'} : {threadId, owner:'external', harnessId:agent}; })}) }) });
|
|
45
45
|
await new Promise(resolve => setTimeout(resolve, 50));
|
|
46
|
-
const sidebarIcons = [...sidebar.querySelectorAll('[data-
|
|
46
|
+
const sidebarIcons = [...sidebar.querySelectorAll('[data-harnessmix-sidebar-agent-icon]')].map(icon => icon.getAttribute('data-harnessmix-sidebar-agent-icon'));
|
|
47
47
|
// Rescan a React-updated row: no duplicate icon and no loss of ownership.
|
|
48
48
|
decoration.refresh(); await new Promise(resolve => setTimeout(resolve, 50));
|
|
49
|
-
const sidebarIconCount = sidebar.querySelectorAll('[data-
|
|
49
|
+
const sidebarIconCount = sidebar.querySelectorAll('[data-harnessmix-sidebar-agent-icon]').length;
|
|
50
50
|
globalThis.testSidebarDecoration = decoration;
|
|
51
51
|
for(const agent of agents) { const el=document.createElement('div'); el.append(NativeUI.createRendererAgentIcon(agent,28),document.createTextNode(' '+agent));document.querySelector('main').append(el); }
|
|
52
52
|
let selected;
|
|
@@ -150,16 +150,16 @@ app.whenReady().then(async () => {
|
|
|
150
150
|
assert.equal(settingsResult.addHidden, false, 'multi-account Add Account action remains visible');
|
|
151
151
|
fs.writeFileSync(path.join(out, 'settings-account.png'), (await win.webContents.capturePage()).toPNG());
|
|
152
152
|
const storageText = await win.webContents.executeJavaScript(`(async () => {
|
|
153
|
-
globalThis.
|
|
153
|
+
globalThis.__harnessmixSettingsShellV1.openSettings(undefined, 'storage');
|
|
154
154
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
155
|
-
return globalThis.
|
|
155
|
+
return globalThis.__harnessmixSettingsShellV1.root.shadowRoot.textContent;
|
|
156
156
|
})()`);
|
|
157
157
|
assert.match(storageText, /Schema v3/);
|
|
158
158
|
assert.match(storageText, /12 个任务/);
|
|
159
159
|
fs.writeFileSync(path.join(out, 'settings-storage.png'), (await win.webContents.capturePage()).toPNG());
|
|
160
160
|
const skinResult = await win.webContents.executeJavaScript(`(async () => {
|
|
161
|
-
globalThis.
|
|
162
|
-
const shadow = globalThis.
|
|
161
|
+
globalThis.__harnessmixSettingsShellV1.openSettings(undefined, 'skins');
|
|
162
|
+
const shadow = globalThis.__harnessmixSettingsShellV1.root.shadowRoot;
|
|
163
163
|
const firstButton = shadow.querySelector('button[data-skin-action="styler-nocturne-studio"]');
|
|
164
164
|
const mikuButton = shadow.querySelector('button[data-skin-action="miku-488137"]');
|
|
165
165
|
firstButton.click();
|
|
@@ -180,16 +180,16 @@ app.whenReady().then(async () => {
|
|
|
180
180
|
assert.equal(skinResult.bundledPreviewCount, 16);
|
|
181
181
|
fs.writeFileSync(path.join(out, 'settings-skins.png'), (await win.webContents.capturePage()).toPNG());
|
|
182
182
|
await win.webContents.executeJavaScript(`(() => {
|
|
183
|
-
const shadow = globalThis.
|
|
183
|
+
const shadow = globalThis.__harnessmixSettingsShellV1.root.shadowRoot;
|
|
184
184
|
const page = shadow.querySelector('.settings-page');
|
|
185
185
|
page.scrollTop = page.scrollHeight;
|
|
186
186
|
})()`);
|
|
187
187
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
188
188
|
fs.writeFileSync(path.join(out, 'settings-skins-discovery.png'), (await win.webContents.capturePage()).toPNG());
|
|
189
189
|
const aboutText = await win.webContents.executeJavaScript(`(async () => {
|
|
190
|
-
globalThis.
|
|
190
|
+
globalThis.__harnessmixSettingsShellV1.openSettings(undefined, 'about');
|
|
191
191
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
192
|
-
return globalThis.
|
|
192
|
+
return globalThis.__harnessmixSettingsShellV1.root.shadowRoot.textContent;
|
|
193
193
|
})()`);
|
|
194
194
|
assert.match(aboutText, /v0\.1\.4/);
|
|
195
195
|
fs.writeFileSync(path.join(out, 'settings-about.png'), (await win.webContents.capturePage()).toPNG());
|