@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
|
@@ -5,164 +5,164 @@ const os = require('node:os');
|
|
|
5
5
|
const path = require('node:path');
|
|
6
6
|
const { PassThrough } = require('node:stream');
|
|
7
7
|
const antigravity = require('../src/main/adapters/antigravity');
|
|
8
|
-
|
|
9
|
-
(async () => {
|
|
8
|
+
|
|
9
|
+
(async () => {
|
|
10
10
|
const { manifest, create, parseModelsOutput, parseUsage, formatPrompt, prepareImageAttachments, formatAntigravityResultError, modelSupportsEffort, ANTIGRAVITY_PERMISSION_MODES } = antigravity;
|
|
11
|
-
|
|
12
|
-
// 1. Manifest
|
|
13
|
-
assert.equal(manifest.id, 'antigravity');
|
|
14
|
-
assert.equal(manifest.name, 'Antigravity');
|
|
15
|
-
assert.equal(manifest.icon, 'antigravity-color.svg');
|
|
16
|
-
assert.equal(manifest.capabilities.streaming, true);
|
|
17
|
-
assert.equal(manifest.capabilities.thinking, true);
|
|
18
|
-
assert.equal(manifest.capabilities.tools, true);
|
|
19
|
-
assert.equal(manifest.capabilities.approvals, true);
|
|
20
|
-
assert.equal(manifest.capabilities.questions, true);
|
|
21
|
-
assert.equal(manifest.capabilities.models, true);
|
|
22
|
-
assert.equal(manifest.capabilities.thinkingLevels, true);
|
|
23
|
-
assert.equal(manifest.capabilities.permissionModes, true);
|
|
24
|
-
assert.equal(manifest.capabilities.resume, true);
|
|
25
|
-
assert.equal(manifest.capabilities.fork, true);
|
|
26
|
-
assert.equal(manifest.capabilities.forkFromMessage, true);
|
|
27
|
-
assert.equal(manifest.capabilities.attachments, true);
|
|
28
|
-
|
|
29
|
-
// 2. parseModelsOutput
|
|
30
|
-
const sampleModelsOutput = `
|
|
31
|
-
Fetching available models...
|
|
32
|
-
gemini-3.8-flash-high\tGemini 3.8 Flash (High)
|
|
33
|
-
gemini-3.8-flash-medium\tGemini 3.8 Flash (Medium)
|
|
34
|
-
gemini-3.8-flash-low\tGemini 3.8 Flash (Low)
|
|
35
|
-
gemini-3.1-pro-high\tGemini 3.1 Pro (High)
|
|
36
|
-
gemini-3.1-pro-low\tGemini 3.1 Pro (Low)
|
|
37
|
-
claude-sonnet-4-6\tClaude Sonnet 4.6 (Thinking)
|
|
38
|
-
gpt-oss-120b-medium\tGPT-OSS 120B (Medium)
|
|
39
|
-
`;
|
|
40
|
-
const models = parseModelsOutput(sampleModelsOutput);
|
|
41
|
-
assert.ok(models.length >= 4);
|
|
42
|
-
|
|
43
|
-
const flash = models.find(m => m.id === 'gemini-3.8-flash');
|
|
44
|
-
assert.ok(flash);
|
|
45
|
-
assert.equal(flash.name, 'Gemini 3.8 Flash');
|
|
46
|
-
assert.equal(flash.provider, 'google');
|
|
47
|
-
assert.equal(flash.efforts.length, 3);
|
|
48
|
-
assert.equal(flash.efforts[0].id, 'low');
|
|
49
|
-
assert.equal(flash.efforts[2].id, 'high');
|
|
11
|
+
|
|
12
|
+
// 1. Manifest
|
|
13
|
+
assert.equal(manifest.id, 'antigravity');
|
|
14
|
+
assert.equal(manifest.name, 'Antigravity');
|
|
15
|
+
assert.equal(manifest.icon, 'antigravity-color.svg');
|
|
16
|
+
assert.equal(manifest.capabilities.streaming, true);
|
|
17
|
+
assert.equal(manifest.capabilities.thinking, true);
|
|
18
|
+
assert.equal(manifest.capabilities.tools, true);
|
|
19
|
+
assert.equal(manifest.capabilities.approvals, true);
|
|
20
|
+
assert.equal(manifest.capabilities.questions, true);
|
|
21
|
+
assert.equal(manifest.capabilities.models, true);
|
|
22
|
+
assert.equal(manifest.capabilities.thinkingLevels, true);
|
|
23
|
+
assert.equal(manifest.capabilities.permissionModes, true);
|
|
24
|
+
assert.equal(manifest.capabilities.resume, true);
|
|
25
|
+
assert.equal(manifest.capabilities.fork, true);
|
|
26
|
+
assert.equal(manifest.capabilities.forkFromMessage, true);
|
|
27
|
+
assert.equal(manifest.capabilities.attachments, true);
|
|
28
|
+
|
|
29
|
+
// 2. parseModelsOutput
|
|
30
|
+
const sampleModelsOutput = `
|
|
31
|
+
Fetching available models...
|
|
32
|
+
gemini-3.8-flash-high\tGemini 3.8 Flash (High)
|
|
33
|
+
gemini-3.8-flash-medium\tGemini 3.8 Flash (Medium)
|
|
34
|
+
gemini-3.8-flash-low\tGemini 3.8 Flash (Low)
|
|
35
|
+
gemini-3.1-pro-high\tGemini 3.1 Pro (High)
|
|
36
|
+
gemini-3.1-pro-low\tGemini 3.1 Pro (Low)
|
|
37
|
+
claude-sonnet-4-6\tClaude Sonnet 4.6 (Thinking)
|
|
38
|
+
gpt-oss-120b-medium\tGPT-OSS 120B (Medium)
|
|
39
|
+
`;
|
|
40
|
+
const models = parseModelsOutput(sampleModelsOutput);
|
|
41
|
+
assert.ok(models.length >= 4);
|
|
42
|
+
|
|
43
|
+
const flash = models.find(m => m.id === 'gemini-3.8-flash');
|
|
44
|
+
assert.ok(flash);
|
|
45
|
+
assert.equal(flash.name, 'Gemini 3.8 Flash');
|
|
46
|
+
assert.equal(flash.provider, 'google');
|
|
47
|
+
assert.equal(flash.efforts.length, 3);
|
|
48
|
+
assert.equal(flash.efforts[0].id, 'low');
|
|
49
|
+
assert.equal(flash.efforts[2].id, 'high');
|
|
50
50
|
assert.equal(flash.defaultEffort, 'high');
|
|
51
51
|
assert.equal(flash.contextWindow, 1_048_576);
|
|
52
52
|
assert.equal(modelSupportsEffort(flash), true);
|
|
53
|
-
|
|
54
|
-
const claude = models.find(m => m.id === 'claude-sonnet-4-6');
|
|
53
|
+
|
|
54
|
+
const claude = models.find(m => m.id === 'claude-sonnet-4-6');
|
|
55
55
|
assert.ok(claude);
|
|
56
56
|
assert.equal(claude.provider, 'anthropic');
|
|
57
57
|
assert.equal(claude.contextWindow, 200_000);
|
|
58
58
|
assert.equal(modelSupportsEffort(claude), false);
|
|
59
59
|
assert.equal(modelSupportsEffort({ id: 'claude-sonnet-4-6' }), false);
|
|
60
|
-
|
|
61
|
-
// 3. parseUsage
|
|
62
|
-
const usage = parseUsage({
|
|
63
|
-
input_tokens: 1200,
|
|
64
|
-
output_tokens: 300,
|
|
65
|
-
thinking_tokens: 150,
|
|
66
|
-
total_tokens: 1650,
|
|
67
|
-
context_used_tokens: 25000,
|
|
68
|
-
}, 'gemini-3.8-flash');
|
|
69
|
-
assert.equal(usage.inputTokens, 1200);
|
|
70
|
-
assert.equal(usage.outputTokens, 300);
|
|
71
|
-
assert.equal(usage.reasoningOutputTokens, 150);
|
|
72
|
-
assert.equal(usage.contextWindow, 1_048_576);
|
|
73
|
-
assert.equal(usage.tokens, 25000);
|
|
74
|
-
assert.ok(usage.contextPercent > 2.3 && usage.contextPercent < 2.5);
|
|
75
|
-
|
|
76
|
-
// 4. formatPrompt
|
|
77
|
-
const rawPrompt = '帮我修改 app.js';
|
|
78
|
-
const formatted = formatPrompt(rawPrompt);
|
|
79
|
-
assert.ok(formatted.includes('write_to_file'));
|
|
80
|
-
assert.ok(formatted.includes('replace_file_content'));
|
|
81
|
-
assert.ok(formatted.includes(rawPrompt));
|
|
82
|
-
|
|
83
|
-
// Slash commands / already instruction formatted should not duplicate
|
|
84
|
-
assert.equal(formatPrompt('/usage'), '/usage');
|
|
85
|
-
assert.equal(formatPrompt(formatted), formatted);
|
|
86
|
-
|
|
87
|
-
// 5. Adapter lifecycle and Session
|
|
88
|
-
const adapter = create(() => {});
|
|
89
|
-
assert.equal(typeof adapter.open, 'function');
|
|
90
|
-
assert.equal(typeof adapter.send, 'function');
|
|
91
|
-
assert.equal(typeof adapter.cancel, 'function');
|
|
92
|
-
assert.equal(typeof adapter.close, 'function');
|
|
93
|
-
assert.equal(typeof adapter.respond, 'function');
|
|
94
|
-
assert.equal(typeof adapter.fork, 'function');
|
|
95
|
-
assert.equal(typeof adapter.listModelsFor, 'function');
|
|
96
|
-
assert.equal(typeof adapter.setModel, 'function');
|
|
97
|
-
assert.equal(typeof adapter.setThinkingLevel, 'function');
|
|
98
|
-
assert.equal(typeof adapter.setPermissionMode, 'function');
|
|
99
|
-
|
|
100
|
-
// 6. Inspect
|
|
101
|
-
const inspection = await adapter.inspect();
|
|
102
|
-
assert.ok(typeof inspection.available === 'boolean');
|
|
103
|
-
assert.ok(typeof inspection.detail === 'string');
|
|
104
|
-
|
|
105
|
-
// 7. Open session
|
|
106
|
-
const openEvents = [];
|
|
107
|
-
const session = await adapter.open({
|
|
108
|
-
thread: {
|
|
109
|
-
id: 'thread-1',
|
|
110
|
-
nativeSessionId: 'conv-12345',
|
|
111
|
-
cwd: 'E:\\harness-mix',
|
|
112
|
-
restore: true,
|
|
113
|
-
options: {
|
|
114
|
-
model: { id: 'gemini-3.8-flash', name: 'Gemini 3.8 Flash' },
|
|
115
|
-
thinking: 'medium',
|
|
116
|
-
permissionMode: 'desktop',
|
|
117
|
-
},
|
|
118
|
-
},
|
|
119
|
-
emit: (event) => openEvents.push(event),
|
|
120
|
-
diagnostic: () => {},
|
|
121
|
-
});
|
|
122
|
-
assert.equal(session.nativeSessionId, 'conv-12345');
|
|
123
|
-
assert.equal(session.thinkingLevel, 'medium');
|
|
124
|
-
assert.equal(session.permissionMode, 'desktop');
|
|
125
|
-
assert.ok(openEvents.some(e => e.kind === 'session' && e.nativeSessionId === 'conv-12345'));
|
|
126
|
-
|
|
127
|
-
// 8. setModel, setThinkingLevel, setPermissionMode
|
|
128
|
-
await adapter.setModel(session, { id: 'gemini-3.1-pro', name: 'Gemini 3.1 Pro' });
|
|
129
|
-
assert.equal(session.model.id, 'gemini-3.1-pro');
|
|
130
|
-
await adapter.setThinkingLevel(session, 'high');
|
|
131
|
-
assert.equal(session.thinkingLevel, 'high');
|
|
132
|
-
await adapter.setPermissionMode(session, 'skip');
|
|
133
|
-
assert.equal(session.permissionMode, 'skip');
|
|
134
|
-
|
|
135
|
-
// 9. Describe
|
|
136
|
-
const desc = await adapter.describe();
|
|
137
|
-
assert.ok(Array.isArray(desc.models));
|
|
138
|
-
assert.equal(desc.thinkingLevels.length, 3);
|
|
139
|
-
assert.equal(desc.permissionModes.length, 3);
|
|
140
|
-
|
|
141
|
-
// 10. Fork session
|
|
142
|
-
const forkEvents = [];
|
|
143
|
-
const forked = await adapter.fork({
|
|
144
|
-
id: 'thread-1',
|
|
145
|
-
nativeSessionId: 'conv-12345',
|
|
146
|
-
cwd: 'E:\\harness-mix',
|
|
147
|
-
model: { id: 'gemini-3.8-flash', name: 'Gemini 3.8 Flash' },
|
|
148
|
-
options: { thinking: 'high', permissionMode: 'default' },
|
|
149
|
-
}, {
|
|
150
|
-
emit: (e) => forkEvents.push(e),
|
|
151
|
-
diagnostic: () => {},
|
|
152
|
-
});
|
|
153
|
-
assert.ok(forked.nativeSessionId);
|
|
154
|
-
assert.notEqual(forked.nativeSessionId, 'conv-12345');
|
|
155
|
-
assert.equal(forked.session.nativeSessionId, forked.nativeSessionId);
|
|
156
|
-
assert.ok(forkEvents.some(e => e.kind === 'session' && e.nativeSessionId === forked.nativeSessionId));
|
|
157
|
-
|
|
158
|
-
// 11. Image attachments
|
|
159
|
-
const tmpRoot = path.join(os.tmpdir(), `agy-attach-test-${Date.now()}`);
|
|
160
|
-
await fs.promises.mkdir(tmpRoot, { recursive: true });
|
|
161
|
-
const localImg = path.join(tmpRoot, 'test.png');
|
|
162
|
-
await fs.promises.writeFile(localImg, Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+jRZkAAAAASUVORK5CYII=', 'base64'));
|
|
163
|
-
const prepared = await prepareImageAttachments([
|
|
164
|
-
{ name: 'test.png', path: localImg },
|
|
165
|
-
{ name: 'inline.png', mime: 'image/png', data: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+jRZkAAAAASUVORK5CYII=' },
|
|
60
|
+
|
|
61
|
+
// 3. parseUsage
|
|
62
|
+
const usage = parseUsage({
|
|
63
|
+
input_tokens: 1200,
|
|
64
|
+
output_tokens: 300,
|
|
65
|
+
thinking_tokens: 150,
|
|
66
|
+
total_tokens: 1650,
|
|
67
|
+
context_used_tokens: 25000,
|
|
68
|
+
}, 'gemini-3.8-flash');
|
|
69
|
+
assert.equal(usage.inputTokens, 1200);
|
|
70
|
+
assert.equal(usage.outputTokens, 300);
|
|
71
|
+
assert.equal(usage.reasoningOutputTokens, 150);
|
|
72
|
+
assert.equal(usage.contextWindow, 1_048_576);
|
|
73
|
+
assert.equal(usage.tokens, 25000);
|
|
74
|
+
assert.ok(usage.contextPercent > 2.3 && usage.contextPercent < 2.5);
|
|
75
|
+
|
|
76
|
+
// 4. formatPrompt
|
|
77
|
+
const rawPrompt = '帮我修改 app.js';
|
|
78
|
+
const formatted = formatPrompt(rawPrompt);
|
|
79
|
+
assert.ok(formatted.includes('write_to_file'));
|
|
80
|
+
assert.ok(formatted.includes('replace_file_content'));
|
|
81
|
+
assert.ok(formatted.includes(rawPrompt));
|
|
82
|
+
|
|
83
|
+
// Slash commands / already instruction formatted should not duplicate
|
|
84
|
+
assert.equal(formatPrompt('/usage'), '/usage');
|
|
85
|
+
assert.equal(formatPrompt(formatted), formatted);
|
|
86
|
+
|
|
87
|
+
// 5. Adapter lifecycle and Session
|
|
88
|
+
const adapter = create(() => {});
|
|
89
|
+
assert.equal(typeof adapter.open, 'function');
|
|
90
|
+
assert.equal(typeof adapter.send, 'function');
|
|
91
|
+
assert.equal(typeof adapter.cancel, 'function');
|
|
92
|
+
assert.equal(typeof adapter.close, 'function');
|
|
93
|
+
assert.equal(typeof adapter.respond, 'function');
|
|
94
|
+
assert.equal(typeof adapter.fork, 'function');
|
|
95
|
+
assert.equal(typeof adapter.listModelsFor, 'function');
|
|
96
|
+
assert.equal(typeof adapter.setModel, 'function');
|
|
97
|
+
assert.equal(typeof adapter.setThinkingLevel, 'function');
|
|
98
|
+
assert.equal(typeof adapter.setPermissionMode, 'function');
|
|
99
|
+
|
|
100
|
+
// 6. Inspect
|
|
101
|
+
const inspection = await adapter.inspect();
|
|
102
|
+
assert.ok(typeof inspection.available === 'boolean');
|
|
103
|
+
assert.ok(typeof inspection.detail === 'string');
|
|
104
|
+
|
|
105
|
+
// 7. Open session
|
|
106
|
+
const openEvents = [];
|
|
107
|
+
const session = await adapter.open({
|
|
108
|
+
thread: {
|
|
109
|
+
id: 'thread-1',
|
|
110
|
+
nativeSessionId: 'conv-12345',
|
|
111
|
+
cwd: 'E:\\harness-mix',
|
|
112
|
+
restore: true,
|
|
113
|
+
options: {
|
|
114
|
+
model: { id: 'gemini-3.8-flash', name: 'Gemini 3.8 Flash' },
|
|
115
|
+
thinking: 'medium',
|
|
116
|
+
permissionMode: 'desktop',
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
emit: (event) => openEvents.push(event),
|
|
120
|
+
diagnostic: () => {},
|
|
121
|
+
});
|
|
122
|
+
assert.equal(session.nativeSessionId, 'conv-12345');
|
|
123
|
+
assert.equal(session.thinkingLevel, 'medium');
|
|
124
|
+
assert.equal(session.permissionMode, 'desktop');
|
|
125
|
+
assert.ok(openEvents.some(e => e.kind === 'session' && e.nativeSessionId === 'conv-12345'));
|
|
126
|
+
|
|
127
|
+
// 8. setModel, setThinkingLevel, setPermissionMode
|
|
128
|
+
await adapter.setModel(session, { id: 'gemini-3.1-pro', name: 'Gemini 3.1 Pro' });
|
|
129
|
+
assert.equal(session.model.id, 'gemini-3.1-pro');
|
|
130
|
+
await adapter.setThinkingLevel(session, 'high');
|
|
131
|
+
assert.equal(session.thinkingLevel, 'high');
|
|
132
|
+
await adapter.setPermissionMode(session, 'skip');
|
|
133
|
+
assert.equal(session.permissionMode, 'skip');
|
|
134
|
+
|
|
135
|
+
// 9. Describe
|
|
136
|
+
const desc = await adapter.describe();
|
|
137
|
+
assert.ok(Array.isArray(desc.models));
|
|
138
|
+
assert.equal(desc.thinkingLevels.length, 3);
|
|
139
|
+
assert.equal(desc.permissionModes.length, 3);
|
|
140
|
+
|
|
141
|
+
// 10. Fork session
|
|
142
|
+
const forkEvents = [];
|
|
143
|
+
const forked = await adapter.fork({
|
|
144
|
+
id: 'thread-1',
|
|
145
|
+
nativeSessionId: 'conv-12345',
|
|
146
|
+
cwd: 'E:\\harness-mix',
|
|
147
|
+
model: { id: 'gemini-3.8-flash', name: 'Gemini 3.8 Flash' },
|
|
148
|
+
options: { thinking: 'high', permissionMode: 'default' },
|
|
149
|
+
}, {
|
|
150
|
+
emit: (e) => forkEvents.push(e),
|
|
151
|
+
diagnostic: () => {},
|
|
152
|
+
});
|
|
153
|
+
assert.ok(forked.nativeSessionId);
|
|
154
|
+
assert.notEqual(forked.nativeSessionId, 'conv-12345');
|
|
155
|
+
assert.equal(forked.session.nativeSessionId, forked.nativeSessionId);
|
|
156
|
+
assert.ok(forkEvents.some(e => e.kind === 'session' && e.nativeSessionId === forked.nativeSessionId));
|
|
157
|
+
|
|
158
|
+
// 11. Image attachments
|
|
159
|
+
const tmpRoot = path.join(os.tmpdir(), `agy-attach-test-${Date.now()}`);
|
|
160
|
+
await fs.promises.mkdir(tmpRoot, { recursive: true });
|
|
161
|
+
const localImg = path.join(tmpRoot, 'test.png');
|
|
162
|
+
await fs.promises.writeFile(localImg, Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+jRZkAAAAASUVORK5CYII=', 'base64'));
|
|
163
|
+
const prepared = await prepareImageAttachments([
|
|
164
|
+
{ name: 'test.png', path: localImg },
|
|
165
|
+
{ name: 'inline.png', mime: 'image/png', data: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+jRZkAAAAASUVORK5CYII=' },
|
|
166
166
|
], tmpRoot);
|
|
167
167
|
assert.equal(prepared.imageEntries.length, 2);
|
|
168
168
|
assert.equal(prepared.imageEntries[0].name, 'test.png');
|
|
@@ -189,105 +189,105 @@ gpt-oss-120b-medium\tGPT-OSS 120B (Medium)
|
|
|
189
189
|
await adapter.close(legacySession);
|
|
190
190
|
await fs.promises.unlink(legacyPath).catch(() => {});
|
|
191
191
|
await fs.promises.rm(tmpRoot, { recursive: true, force: true }).catch(() => {});
|
|
192
|
-
|
|
193
|
-
// 12. mergePendingStep
|
|
194
|
-
const { mergePendingStep, cloneDatabase } = antigravity;
|
|
195
|
-
const activeStep = {
|
|
196
|
-
step_index: 2,
|
|
197
|
-
state: 'ACTIVE',
|
|
198
|
-
step_type: 'tool',
|
|
199
|
-
tool_name: 'write_to_file',
|
|
200
|
-
tool_info: {
|
|
201
|
-
name: 'write_to_file',
|
|
202
|
-
parameters: { TargetFile: 'test.txt', Description: 'create file' },
|
|
203
|
-
},
|
|
204
|
-
};
|
|
205
|
-
const doneStep = {
|
|
206
|
-
step_index: 2,
|
|
207
|
-
state: 'DONE',
|
|
208
|
-
step_type: 'tool',
|
|
209
|
-
tool_info: {
|
|
210
|
-
output: 'File written successfully',
|
|
211
|
-
},
|
|
212
|
-
};
|
|
213
|
-
const merged = mergePendingStep(activeStep, doneStep);
|
|
214
|
-
assert.equal(merged.state, 'DONE');
|
|
215
|
-
assert.equal(merged.tool_name, 'write_to_file');
|
|
216
|
-
assert.equal(merged.tool_info.name, 'write_to_file');
|
|
217
|
-
assert.equal(merged.tool_info.parameters.TargetFile, 'test.txt');
|
|
218
|
-
assert.equal(merged.tool_info.output, 'File written successfully');
|
|
219
|
-
|
|
220
|
-
// 13. cloneDatabase with message turn pruning and summaries.db
|
|
221
|
-
const mockHome = path.join(os.tmpdir(), `agy-mock-home-${Date.now()}`);
|
|
222
|
-
const convDir = path.join(mockHome, '.gemini', 'antigravity-cli', 'conversations');
|
|
223
|
-
await fs.promises.mkdir(convDir, { recursive: true });
|
|
224
|
-
const { DatabaseSync } = require('node:sqlite');
|
|
225
|
-
const sourceDbPath = path.join(convDir, 'source-conv.db');
|
|
226
|
-
const db = new DatabaseSync(sourceDbPath);
|
|
227
|
-
db.exec(`
|
|
228
|
-
CREATE TABLE trajectory_meta (cascade_id TEXT);
|
|
229
|
-
INSERT INTO trajectory_meta VALUES ('source-conv');
|
|
230
|
-
CREATE TABLE steps (idx INTEGER PRIMARY KEY, step_type INTEGER);
|
|
231
|
-
INSERT INTO steps VALUES (1, 14), (2, 1), (3, 14), (4, 1);
|
|
232
|
-
CREATE TABLE gen_metadata (idx INTEGER PRIMARY KEY);
|
|
233
|
-
INSERT INTO gen_metadata VALUES (0), (1);
|
|
234
|
-
CREATE TABLE executor_metadata (idx INTEGER PRIMARY KEY);
|
|
235
|
-
INSERT INTO executor_metadata VALUES (0), (1);
|
|
236
|
-
CREATE TABLE parent_references (idx INTEGER PRIMARY KEY);
|
|
237
|
-
INSERT INTO parent_references VALUES (0), (1);
|
|
238
|
-
CREATE TABLE battle_mode_infos (idx INTEGER PRIMARY KEY);
|
|
239
|
-
INSERT INTO battle_mode_infos VALUES (0), (1);
|
|
240
|
-
`);
|
|
241
|
-
db.close();
|
|
242
|
-
|
|
243
|
-
const sumDbPath = path.join(mockHome, '.gemini', 'antigravity-cli', 'conversation_summaries.db');
|
|
244
|
-
const sumDb = new DatabaseSync(sumDbPath);
|
|
245
|
-
sumDb.exec(`
|
|
246
|
-
CREATE TABLE conversation_summaries (conversation_id TEXT PRIMARY KEY, title TEXT, step_count INTEGER, last_modified_time TEXT);
|
|
247
|
-
INSERT INTO conversation_summaries VALUES ('source-conv', 'Test Session', 4, '2026-09-01T00:00:00.000Z');
|
|
248
|
-
`);
|
|
249
|
-
sumDb.close();
|
|
250
|
-
|
|
251
|
-
const clonedOk = await cloneDatabase('source-conv', 'derived-conv', 1, mockHome);
|
|
252
|
-
assert.equal(clonedOk, true);
|
|
253
|
-
|
|
254
|
-
const derivedDb = new DatabaseSync(path.join(convDir, 'derived-conv.db'));
|
|
255
|
-
const meta = derivedDb.prepare('SELECT cascade_id FROM trajectory_meta').get();
|
|
256
|
-
assert.equal(meta.cascade_id, 'derived-conv');
|
|
257
|
-
const remainingSteps = derivedDb.prepare('SELECT count(*) as c FROM steps').get();
|
|
258
|
-
assert.equal(remainingSteps.c, 2); // only first turn retained
|
|
259
|
-
derivedDb.close();
|
|
260
|
-
|
|
261
|
-
const sumDbCheck = new DatabaseSync(sumDbPath);
|
|
262
|
-
const sumRow = sumDbCheck.prepare('SELECT * FROM conversation_summaries WHERE conversation_id = ?').get('derived-conv');
|
|
263
|
-
assert.ok(sumRow);
|
|
264
|
-
assert.equal(sumRow.title, 'Test Session');
|
|
265
|
-
assert.equal(sumRow.step_count, 2);
|
|
266
|
-
sumDbCheck.close();
|
|
267
|
-
|
|
268
|
-
await fs.promises.rm(mockHome, { recursive: true, force: true }).catch(() => {});
|
|
269
|
-
|
|
270
|
-
// 14. Quota and Credits parsing
|
|
271
|
-
const mockUsageCommand = {
|
|
272
|
-
name: 'usage',
|
|
273
|
-
data: {
|
|
274
|
-
groups: [
|
|
275
|
-
{
|
|
276
|
-
name: 'Gemini Models',
|
|
277
|
-
buckets: [
|
|
278
|
-
{ id: 'gemini-weekly', name: 'Weekly Limit', window: 'weekly', remaining_fraction: 0.45, reset_time: '2026-09-16T01:12:46Z' },
|
|
279
|
-
{ id: 'gemini-5h', name: '5-Hour Limit', window: '5h', remaining_fraction: 0.80, reset_time: '2026-09-12T14:45:59Z' },
|
|
280
|
-
],
|
|
281
|
-
},
|
|
282
|
-
],
|
|
283
|
-
},
|
|
284
|
-
};
|
|
285
|
-
const { parseAntigravityUsageCommand } = antigravity;
|
|
286
|
-
const quotaSnapshot = parseAntigravityUsageCommand(mockUsageCommand);
|
|
287
|
-
assert.ok(quotaSnapshot);
|
|
288
|
-
assert.equal(quotaSnapshot.periodType, 'weekly');
|
|
289
|
-
assert.equal(quotaSnapshot.usedPercent, 55); // (1 - 0.45) * 100
|
|
290
|
-
assert.equal(quotaSnapshot.resetsAt, '2026-09-16T01:12:46Z');
|
|
192
|
+
|
|
193
|
+
// 12. mergePendingStep
|
|
194
|
+
const { mergePendingStep, cloneDatabase } = antigravity;
|
|
195
|
+
const activeStep = {
|
|
196
|
+
step_index: 2,
|
|
197
|
+
state: 'ACTIVE',
|
|
198
|
+
step_type: 'tool',
|
|
199
|
+
tool_name: 'write_to_file',
|
|
200
|
+
tool_info: {
|
|
201
|
+
name: 'write_to_file',
|
|
202
|
+
parameters: { TargetFile: 'test.txt', Description: 'create file' },
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
const doneStep = {
|
|
206
|
+
step_index: 2,
|
|
207
|
+
state: 'DONE',
|
|
208
|
+
step_type: 'tool',
|
|
209
|
+
tool_info: {
|
|
210
|
+
output: 'File written successfully',
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
const merged = mergePendingStep(activeStep, doneStep);
|
|
214
|
+
assert.equal(merged.state, 'DONE');
|
|
215
|
+
assert.equal(merged.tool_name, 'write_to_file');
|
|
216
|
+
assert.equal(merged.tool_info.name, 'write_to_file');
|
|
217
|
+
assert.equal(merged.tool_info.parameters.TargetFile, 'test.txt');
|
|
218
|
+
assert.equal(merged.tool_info.output, 'File written successfully');
|
|
219
|
+
|
|
220
|
+
// 13. cloneDatabase with message turn pruning and summaries.db
|
|
221
|
+
const mockHome = path.join(os.tmpdir(), `agy-mock-home-${Date.now()}`);
|
|
222
|
+
const convDir = path.join(mockHome, '.gemini', 'antigravity-cli', 'conversations');
|
|
223
|
+
await fs.promises.mkdir(convDir, { recursive: true });
|
|
224
|
+
const { DatabaseSync } = require('node:sqlite');
|
|
225
|
+
const sourceDbPath = path.join(convDir, 'source-conv.db');
|
|
226
|
+
const db = new DatabaseSync(sourceDbPath);
|
|
227
|
+
db.exec(`
|
|
228
|
+
CREATE TABLE trajectory_meta (cascade_id TEXT);
|
|
229
|
+
INSERT INTO trajectory_meta VALUES ('source-conv');
|
|
230
|
+
CREATE TABLE steps (idx INTEGER PRIMARY KEY, step_type INTEGER);
|
|
231
|
+
INSERT INTO steps VALUES (1, 14), (2, 1), (3, 14), (4, 1);
|
|
232
|
+
CREATE TABLE gen_metadata (idx INTEGER PRIMARY KEY);
|
|
233
|
+
INSERT INTO gen_metadata VALUES (0), (1);
|
|
234
|
+
CREATE TABLE executor_metadata (idx INTEGER PRIMARY KEY);
|
|
235
|
+
INSERT INTO executor_metadata VALUES (0), (1);
|
|
236
|
+
CREATE TABLE parent_references (idx INTEGER PRIMARY KEY);
|
|
237
|
+
INSERT INTO parent_references VALUES (0), (1);
|
|
238
|
+
CREATE TABLE battle_mode_infos (idx INTEGER PRIMARY KEY);
|
|
239
|
+
INSERT INTO battle_mode_infos VALUES (0), (1);
|
|
240
|
+
`);
|
|
241
|
+
db.close();
|
|
242
|
+
|
|
243
|
+
const sumDbPath = path.join(mockHome, '.gemini', 'antigravity-cli', 'conversation_summaries.db');
|
|
244
|
+
const sumDb = new DatabaseSync(sumDbPath);
|
|
245
|
+
sumDb.exec(`
|
|
246
|
+
CREATE TABLE conversation_summaries (conversation_id TEXT PRIMARY KEY, title TEXT, step_count INTEGER, last_modified_time TEXT);
|
|
247
|
+
INSERT INTO conversation_summaries VALUES ('source-conv', 'Test Session', 4, '2026-09-01T00:00:00.000Z');
|
|
248
|
+
`);
|
|
249
|
+
sumDb.close();
|
|
250
|
+
|
|
251
|
+
const clonedOk = await cloneDatabase('source-conv', 'derived-conv', 1, mockHome);
|
|
252
|
+
assert.equal(clonedOk, true);
|
|
253
|
+
|
|
254
|
+
const derivedDb = new DatabaseSync(path.join(convDir, 'derived-conv.db'));
|
|
255
|
+
const meta = derivedDb.prepare('SELECT cascade_id FROM trajectory_meta').get();
|
|
256
|
+
assert.equal(meta.cascade_id, 'derived-conv');
|
|
257
|
+
const remainingSteps = derivedDb.prepare('SELECT count(*) as c FROM steps').get();
|
|
258
|
+
assert.equal(remainingSteps.c, 2); // only first turn retained
|
|
259
|
+
derivedDb.close();
|
|
260
|
+
|
|
261
|
+
const sumDbCheck = new DatabaseSync(sumDbPath);
|
|
262
|
+
const sumRow = sumDbCheck.prepare('SELECT * FROM conversation_summaries WHERE conversation_id = ?').get('derived-conv');
|
|
263
|
+
assert.ok(sumRow);
|
|
264
|
+
assert.equal(sumRow.title, 'Test Session');
|
|
265
|
+
assert.equal(sumRow.step_count, 2);
|
|
266
|
+
sumDbCheck.close();
|
|
267
|
+
|
|
268
|
+
await fs.promises.rm(mockHome, { recursive: true, force: true }).catch(() => {});
|
|
269
|
+
|
|
270
|
+
// 14. Quota and Credits parsing
|
|
271
|
+
const mockUsageCommand = {
|
|
272
|
+
name: 'usage',
|
|
273
|
+
data: {
|
|
274
|
+
groups: [
|
|
275
|
+
{
|
|
276
|
+
name: 'Gemini Models',
|
|
277
|
+
buckets: [
|
|
278
|
+
{ id: 'gemini-weekly', name: 'Weekly Limit', window: 'weekly', remaining_fraction: 0.45, reset_time: '2026-09-16T01:12:46Z' },
|
|
279
|
+
{ id: 'gemini-5h', name: '5-Hour Limit', window: '5h', remaining_fraction: 0.80, reset_time: '2026-09-12T14:45:59Z' },
|
|
280
|
+
],
|
|
281
|
+
},
|
|
282
|
+
],
|
|
283
|
+
},
|
|
284
|
+
};
|
|
285
|
+
const { parseAntigravityUsageCommand } = antigravity;
|
|
286
|
+
const quotaSnapshot = parseAntigravityUsageCommand(mockUsageCommand);
|
|
287
|
+
assert.ok(quotaSnapshot);
|
|
288
|
+
assert.equal(quotaSnapshot.periodType, 'weekly');
|
|
289
|
+
assert.equal(quotaSnapshot.usedPercent, 55); // (1 - 0.45) * 100
|
|
290
|
+
assert.equal(quotaSnapshot.resetsAt, '2026-09-16T01:12:46Z');
|
|
291
291
|
assert.ok(Array.isArray(quotaSnapshot.productUsage));
|
|
292
292
|
assert.equal(quotaSnapshot.productUsage[0].usagePercent, 20); // (1 - 0.8) * 100
|
|
293
293
|
|
|
@@ -374,43 +374,140 @@ gpt-oss-120b-medium\tGPT-OSS 120B (Medium)
|
|
|
374
374
|
assert.equal(noResultSession.activeTurn, null);
|
|
375
375
|
await noResultAdapter.close(noResultSession);
|
|
376
376
|
|
|
377
|
-
// 17. A SUCCESS result with no assistant text
|
|
378
|
-
//
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
377
|
+
// 17. A SUCCESS result with no assistant text triggers exactly one automatic
|
|
378
|
+
// nudge retry in the same native conversation; only a repeated empty result
|
|
379
|
+
// surfaces as an error.
|
|
380
|
+
const makeEmptySuccessChild = (onPrompt) => {
|
|
381
|
+
const child = new EventEmitter();
|
|
382
|
+
child.stdin = new PassThrough();
|
|
383
|
+
child.stdout = new PassThrough();
|
|
384
|
+
child.stderr = new PassThrough();
|
|
385
|
+
let closed = false;
|
|
386
|
+
const closeChild = () => {
|
|
387
|
+
if (closed) return;
|
|
388
|
+
closed = true;
|
|
389
|
+
child.stdout.end();
|
|
390
|
+
child.stderr.end();
|
|
391
|
+
child.emit('close', 0);
|
|
392
|
+
};
|
|
393
|
+
child.isClosed = () => closed;
|
|
394
|
+
child.stdin.once('data', (chunk) => {
|
|
395
|
+
const content = JSON.parse(String(chunk).trim()).message?.content || '';
|
|
396
|
+
setTimeout(() => onPrompt(child, content, closeChild), 1);
|
|
397
|
+
});
|
|
398
|
+
child.stdin.once('finish', () => setTimeout(closeChild, 0));
|
|
399
|
+
child.kill = closeChild;
|
|
400
|
+
return child;
|
|
390
401
|
};
|
|
391
|
-
|
|
392
|
-
if (!
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
+
const writeStream = (child, event) => {
|
|
403
|
+
if (!child.isClosed()) child.stdout.write(`${JSON.stringify(event)}\n`);
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
// 17a. First attempt empty, nudge retry answers → turn completes, no error.
|
|
407
|
+
const retryChildren = [];
|
|
408
|
+
const retryArgs = [];
|
|
409
|
+
const retryAdapter = create(() => {}, {
|
|
410
|
+
spawnProcess: (_bin, args) => {
|
|
411
|
+
retryArgs.push(args);
|
|
412
|
+
const attempt = retryChildren.length;
|
|
413
|
+
const child = makeEmptySuccessChild((c, content) => {
|
|
414
|
+
if (attempt === 0) {
|
|
415
|
+
writeStream(c, { event: 'init', conversation_id: 'fake-empty-success' });
|
|
416
|
+
writeStream(c, { event: 'result', result: { conversation_id: 'fake-empty-success', status: 'SUCCESS', response: '' } });
|
|
417
|
+
} else {
|
|
418
|
+
c.nudgePrompt = content;
|
|
419
|
+
writeStream(c, { event: 'init', conversation_id: 'fake-empty-success' });
|
|
420
|
+
writeStream(c, {
|
|
421
|
+
event: 'step_update',
|
|
422
|
+
step_update: { conversation_id: 'fake-empty-success', step_index: 1, state: 'DONE', step_type: 'agent_response', text_delta: 'late recovered answer' },
|
|
423
|
+
});
|
|
424
|
+
writeStream(c, { event: 'result', result: { conversation_id: 'fake-empty-success', status: 'SUCCESS', num_turns: 2, response: 'late recovered answer' } });
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
retryChildren.push(child);
|
|
428
|
+
return child;
|
|
429
|
+
},
|
|
430
|
+
resultDrainMs: 10,
|
|
431
|
+
resultDrainMaxMs: 20,
|
|
432
|
+
});
|
|
433
|
+
const retrySession = await retryAdapter.open({
|
|
434
|
+
thread: { id: 'fake-empty-retry-thread', cwd: os.tmpdir(), options: { permissionMode: 'skip' } },
|
|
402
435
|
emit: () => {},
|
|
403
436
|
diagnostic: () => {},
|
|
404
437
|
});
|
|
405
|
-
const
|
|
438
|
+
const retryEvents = [];
|
|
439
|
+
await retryAdapter.send(retrySession, 'return an empty success', { emit: event => retryEvents.push(event) });
|
|
440
|
+
assert.equal(retryChildren.length, 2);
|
|
441
|
+
assert.match(retryChildren[1].nudgePrompt || '', /previous turn ended WITHOUT any visible assistant response/);
|
|
442
|
+
const resumeIdx = retryArgs[1].indexOf('--conversation');
|
|
443
|
+
assert.ok(resumeIdx >= 0);
|
|
444
|
+
assert.equal(retryArgs[1][resumeIdx + 1], 'fake-empty-success');
|
|
445
|
+
assert.equal(retryEvents.filter(event => event.kind === 'error').length, 0);
|
|
446
|
+
assert.ok(retryEvents.some(event => event.kind === 'status' && /自动补问/.test(event.text || '')));
|
|
447
|
+
assert.equal(retryEvents.filter(event => event.kind === 'text-delta').map(event => event.text).join(''), 'late recovered answer');
|
|
448
|
+
assert.ok(retryEvents.some(event => event.kind === 'completed'));
|
|
449
|
+
assert.equal(retrySession.activeTurn, null);
|
|
450
|
+
await retryAdapter.close(retrySession);
|
|
451
|
+
|
|
452
|
+
// 17b. Every attempt empty → rejects, error emitted exactly once (final attempt).
|
|
453
|
+
let alwaysEmptySpawns = 0;
|
|
454
|
+
const alwaysEmptyAdapter = create(() => {}, {
|
|
455
|
+
spawnProcess: () => {
|
|
456
|
+
alwaysEmptySpawns += 1;
|
|
457
|
+
return makeEmptySuccessChild((c) => {
|
|
458
|
+
writeStream(c, { event: 'init', conversation_id: 'fake-empty-success' });
|
|
459
|
+
writeStream(c, { event: 'result', result: { conversation_id: 'fake-empty-success', status: 'SUCCESS', response: '' } });
|
|
460
|
+
});
|
|
461
|
+
},
|
|
462
|
+
resultDrainMaxMs: 20,
|
|
463
|
+
});
|
|
464
|
+
const alwaysEmptySession = await alwaysEmptyAdapter.open({
|
|
465
|
+
thread: { id: 'fake-always-empty-thread', cwd: os.tmpdir(), options: { permissionMode: 'skip' } },
|
|
466
|
+
emit: () => {},
|
|
467
|
+
diagnostic: () => {},
|
|
468
|
+
});
|
|
469
|
+
const alwaysEmptyEvents = [];
|
|
406
470
|
await assert.rejects(
|
|
407
|
-
|
|
471
|
+
alwaysEmptyAdapter.send(alwaysEmptySession, 'return an empty success', { emit: event => alwaysEmptyEvents.push(event) }),
|
|
408
472
|
/没有 assistant 文本/,
|
|
409
473
|
);
|
|
410
|
-
assert.
|
|
411
|
-
assert.equal(
|
|
412
|
-
assert.
|
|
413
|
-
|
|
474
|
+
assert.equal(alwaysEmptySpawns, 2);
|
|
475
|
+
assert.equal(alwaysEmptyEvents.filter(event => event.kind === 'error').length, 1);
|
|
476
|
+
assert.match(alwaysEmptyEvents.find(event => event.kind === 'error')?.message || '', /没有 assistant 文本/);
|
|
477
|
+
assert.equal(alwaysEmptyEvents.some(event => event.kind === 'completed'), false);
|
|
478
|
+
assert.equal(alwaysEmptySession.activeTurn, null);
|
|
479
|
+
await alwaysEmptyAdapter.close(alwaysEmptySession);
|
|
480
|
+
|
|
481
|
+
// 17c. Automatic retry disabled via env → single attempt, immediate error.
|
|
482
|
+
process.env.HARNESSMIX_ANTIGRAVITY_EMPTY_RESULT_RETRIES = '0';
|
|
483
|
+
try {
|
|
484
|
+
let noRetrySpawns = 0;
|
|
485
|
+
const noRetryAdapter = create(() => {}, {
|
|
486
|
+
spawnProcess: () => {
|
|
487
|
+
noRetrySpawns += 1;
|
|
488
|
+
return makeEmptySuccessChild((c) => {
|
|
489
|
+
writeStream(c, { event: 'init', conversation_id: 'fake-empty-success' });
|
|
490
|
+
writeStream(c, { event: 'result', result: { conversation_id: 'fake-empty-success', status: 'SUCCESS', response: '' } });
|
|
491
|
+
});
|
|
492
|
+
},
|
|
493
|
+
resultDrainMaxMs: 20,
|
|
494
|
+
});
|
|
495
|
+
const noRetrySession = await noRetryAdapter.open({
|
|
496
|
+
thread: { id: 'fake-no-retry-thread', cwd: os.tmpdir(), options: { permissionMode: 'skip' } },
|
|
497
|
+
emit: () => {},
|
|
498
|
+
diagnostic: () => {},
|
|
499
|
+
});
|
|
500
|
+
const noRetryEvents = [];
|
|
501
|
+
await assert.rejects(
|
|
502
|
+
noRetryAdapter.send(noRetrySession, 'return an empty success', { emit: event => noRetryEvents.push(event) }),
|
|
503
|
+
/没有 assistant 文本/,
|
|
504
|
+
);
|
|
505
|
+
assert.equal(noRetrySpawns, 1);
|
|
506
|
+
assert.equal(noRetryEvents.filter(event => event.kind === 'error').length, 1);
|
|
507
|
+
await noRetryAdapter.close(noRetrySession);
|
|
508
|
+
} finally {
|
|
509
|
+
delete process.env.HARNESSMIX_ANTIGRAVITY_EMPTY_RESULT_RETRIES;
|
|
510
|
+
}
|
|
414
511
|
|
|
415
512
|
// 18. An empty view_file result must not close the Core turn before a late
|
|
416
513
|
// assistant response. This is the stream shape produced for image files by
|
|
@@ -521,9 +618,9 @@ gpt-oss-120b-medium\tGPT-OSS 120B (Medium)
|
|
|
521
618
|
|
|
522
619
|
// 19. Close session
|
|
523
620
|
await adapter.close(session);
|
|
524
|
-
|
|
525
|
-
console.log('antigravity adapter: manifest, models catalog, usage projection, quota/credits, prompt formatting, image attachments, session lifecycle, model switching, describe, fork, step merging, and turn pruning passed');
|
|
526
|
-
})().catch((err) => {
|
|
527
|
-
console.error(err);
|
|
528
|
-
process.exitCode = 1;
|
|
529
|
-
});
|
|
621
|
+
|
|
622
|
+
console.log('antigravity adapter: manifest, models catalog, usage projection, quota/credits, prompt formatting, image attachments, session lifecycle, model switching, describe, fork, step merging, and turn pruning passed');
|
|
623
|
+
})().catch((err) => {
|
|
624
|
+
console.error(err);
|
|
625
|
+
process.exitCode = 1;
|
|
626
|
+
});
|