@harness-mix/cli 0.1.4 → 0.1.6
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 +8 -0
- package/README.md +26 -96
- package/docs/chatgpt-web-sidebar.md +7 -1
- package/docs/cross-platform.md +15 -0
- package/docs/harness-handoff-design.md +377 -0
- package/docs/harness-management.md +28 -1
- package/docs/multi-agent-collaboration.md +9 -9
- package/docs/native-codex.md +21 -10
- package/output/native-build/harness-mix-shim.exe +0 -0
- package/output/native-build/renderer-extension.js +2596 -135
- package/package.json +20 -10
- package/scripts/chatgpt-context-ui-smoke.cjs +16 -0
- package/scripts/codex-accounts-test.cjs +81 -0
- package/scripts/codex-accounts-ui-smoke.cjs +70 -0
- package/scripts/collaboration-test.cjs +8 -3
- package/scripts/collaboration-ui-smoke.cjs +40 -26
- package/scripts/e2e-integrations.cjs +52 -0
- package/scripts/e2e-native-host.cjs +39 -0
- package/scripts/handoff-checkpoint-test.cjs +83 -0
- package/scripts/install-native.cjs +4 -1
- package/scripts/integrations-test.cjs +123 -0
- package/scripts/integrations-ui-smoke.cjs +124 -0
- package/scripts/native-protocol-test.cjs +180 -5
- package/scripts/native-secret-test.cjs +2 -2
- package/scripts/native-shim-test.cjs +20 -4
- package/scripts/native-sidebar-test.cjs +7 -0
- package/scripts/native-skill-roots-test.cjs +90 -0
- package/scripts/native-ui-smoke.cjs +58 -2
- package/scripts/publish-native-package.cjs +8 -5
- package/scripts/support/integrations-mcp-fixture.cjs +15 -0
- package/scripts/switch-harness-test.cjs +27 -1
- package/scripts/test-live-mentions.cjs +152 -0
- package/src/main/adapters/acp.js +3 -3
- package/src/main/adapters/antigravity.js +17 -17
- package/src/main/adapters/claude.js +50 -10
- package/src/main/adapters/codebuddy.js +1 -0
- package/src/main/adapters/codex-app-server.js +20 -13
- package/src/main/adapters/codex.js +25 -5
- package/src/main/adapters/cursor.js +5 -1
- package/src/main/adapters/dsh.js +9 -1
- package/src/main/adapters/grok.js +7 -3
- package/src/main/adapters/hermes.js +8 -0
- package/src/main/adapters/kiro.js +2 -1
- package/src/main/adapters/managed-mcp.js +25 -0
- package/src/main/adapters/native-acp.js +4 -4
- package/src/main/adapters/omp.js +11 -0
- package/src/main/adapters/openclaw.js +6 -0
- package/src/main/adapters/opencode.js +13 -3
- package/src/main/adapters/pi.js +5 -0
- package/src/main/adapters/qoder.js +1 -0
- package/src/main/adapters/trae.js +4 -0
- package/src/main/adapters/zcode.js +3 -0
- package/src/main/harness-adapter/manifest.js +17 -2
- package/src/main/host/collaboration.js +57 -11
- package/src/main/host/handoff-access.js +53 -0
- package/src/main/host/handoff-checkpoints.js +206 -0
- package/src/main/host/handoff-mcp.cjs +38 -0
- package/src/main/host/handoff-tools.js +13 -0
- package/src/main/host/handoff.js +28 -6
- package/src/main/host/integrations.js +339 -0
- package/src/main/host/runtime.js +95 -15
- package/src/main/host/store.js +4 -4
- package/src/main/native/codex-accounts.js +260 -0
- package/src/main/native/host.js +1 -1
- package/src/main/native/launcher.js +2 -2
- package/src/main/native/protocol.js +176 -14
- package/src/main/native/redact.js +1 -1
- package/src/main/native/rs/crates/shim/src/main.rs +155 -12
- package/src/main/native/thread-list.js +3 -0
- package/src/native-ui/desktop-control/dist/tsconfig.tsbuildinfo +1 -1
- package/src/native-ui/renderer-extension/dist/types/harness-mix-settings.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/index.d.ts +4 -0
- package/src/native-ui/renderer-extension/dist/types/index.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-agent-picker.d.ts +2 -0
- 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.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/renderer-chatgpt-context.d.ts +36 -0
- package/src/native-ui/renderer-extension/dist/types/renderer-chatgpt-context.d.ts.map +1 -0
- package/src/native-ui/renderer-extension/dist/types/renderer-codex-account-state.d.ts +1 -0
- 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-composer-dom.d.ts +3 -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-harness-handoff.d.ts +53 -0
- package/src/native-ui/renderer-extension/dist/types/renderer-harness-handoff.d.ts.map +1 -0
- package/src/native-ui/renderer-extension/dist/types/renderer-harness-mentions.d.ts +11 -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-integrations-client.d.ts +105 -0
- package/src/native-ui/renderer-extension/dist/types/renderer-integrations-client.d.ts.map +1 -0
- package/src/native-ui/renderer-extension/dist/types/renderer-model-client.d.ts +7 -1
- 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-settings-lifecycle.d.ts +1 -0
- package/src/native-ui/renderer-extension/dist/types/renderer-settings-lifecycle.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/accounts-list.d.ts +2 -0
- 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 -0
- 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/integrations-page.d.ts +6 -0
- package/src/native-ui/renderer-extension/dist/types/settings/integrations-page.d.ts.map +1 -0
- package/src/native-ui/renderer-extension/dist/types/settings/localization.d.ts +5 -0
- package/src/native-ui/renderer-extension/dist/types/settings/localization.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/pages.d.ts +8 -4
- package/src/native-ui/renderer-extension/dist/types/settings/pages.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/tsconfig.tsbuildinfo +1 -1
- package/src/native-ui/renderer-extension/src/harness-mix-settings.ts +4 -1
- package/src/native-ui/renderer-extension/src/index.ts +28 -0
- package/src/native-ui/renderer-extension/src/renderer-agent-icon.ts +4 -4
- package/src/native-ui/renderer-extension/src/renderer-agent-picker.ts +46 -6
- package/src/native-ui/renderer-extension/src/renderer-binding-probe.ts +115 -18
- package/src/native-ui/renderer-extension/src/renderer-chatgpt-context.ts +87 -0
- package/src/native-ui/renderer-extension/src/renderer-codex-account-state.ts +10 -0
- package/src/native-ui/renderer-extension/src/renderer-composer-dom.ts +10 -0
- package/src/native-ui/renderer-extension/src/renderer-harness-handoff.ts +330 -0
- package/src/native-ui/renderer-extension/src/renderer-harness-mentions.ts +556 -123
- package/src/native-ui/renderer-extension/src/renderer-integrations-client.ts +59 -0
- package/src/native-ui/renderer-extension/src/renderer-model-client.ts +17 -1
- package/src/native-ui/renderer-extension/src/renderer-settings-lifecycle.ts +2 -0
- package/src/native-ui/renderer-extension/src/settings/accounts-list.ts +16 -1
- package/src/native-ui/renderer-extension/src/settings/accounts-page.ts +32 -3
- package/src/native-ui/renderer-extension/src/settings/integrations-page.ts +1474 -0
- package/src/native-ui/renderer-extension/src/settings/localization.ts +32 -13
- package/src/native-ui/renderer-extension/src/settings/pages.ts +49 -18
- package/src/native-ui/renderer-extension/src/settings/shell.css +103 -0
- package/src/native-ui/renderer-extension/test/renderer-agent-picker.test.ts +44 -13
- package/src/native-ui/renderer-extension/test/renderer-chatgpt-context.test.ts +21 -0
- package/src/native-ui/renderer-extension/test/renderer-codex-account-state.test.ts +13 -1
- package/src/native-ui/renderer-extension/test/renderer-harness-handoff.test.ts +20 -0
- package/src/native-ui/renderer-extension/test/renderer-model-client.test.ts +9 -2
- package/src/native-ui/renderer-extension/test/settings/localization.test.ts +1 -1
- package/src/native-ui/renderer-extension/test/settings/pages.test.ts +77 -8
- package/src/native-ui/renderer-extension/test/settings/shell.test.ts +6 -0
- package/src/native-ui/shared-contracts/dist/codex-accounts.d.ts +19 -4
- package/src/native-ui/shared-contracts/dist/codex-accounts.d.ts.map +1 -1
- package/src/native-ui/shared-contracts/dist/codex-accounts.js +2 -0
- package/src/native-ui/shared-contracts/dist/codex-accounts.js.map +1 -1
- package/src/native-ui/shared-contracts/dist/index.d.ts +2 -2
- package/src/native-ui/shared-contracts/dist/index.d.ts.map +1 -1
- package/src/native-ui/shared-contracts/dist/index.js +1 -1
- package/src/native-ui/shared-contracts/dist/index.js.map +1 -1
- package/src/native-ui/shared-contracts/dist/thread-harness-switch.d.ts +29 -0
- package/src/native-ui/shared-contracts/dist/thread-harness-switch.d.ts.map +1 -1
- package/src/native-ui/shared-contracts/dist/thread-harness-switch.js +13 -0
- package/src/native-ui/shared-contracts/dist/thread-harness-switch.js.map +1 -1
- package/src/native-ui/shared-contracts/dist/tsconfig.tsbuildinfo +1 -1
- package/src/native-ui/shared-contracts/src/codex-accounts.ts +2 -0
- package/src/native-ui/shared-contracts/src/index.ts +8 -1
- package/src/native-ui/shared-contracts/src/thread-harness-switch.ts +17 -0
|
@@ -88,7 +88,12 @@ export interface RendererSettingsMessages {
|
|
|
88
88
|
readonly accountDeleteFailed: string;
|
|
89
89
|
readonly accountActive: string;
|
|
90
90
|
readonly accountUse: string;
|
|
91
|
-
readonly accountSignIn: string;
|
|
91
|
+
readonly accountSignIn: string;
|
|
92
|
+
readonly accountSignOut: string;
|
|
93
|
+
readonly accountSignOutConfirm: string;
|
|
94
|
+
readonly accountSigningOut: string;
|
|
95
|
+
readonly accountSignedOut: string;
|
|
96
|
+
readonly accountSignOutFailed: string;
|
|
92
97
|
readonly accountSigningIn: string;
|
|
93
98
|
readonly accountDeviceCodePrerequisite: string;
|
|
94
99
|
readonly accountVerificationDescription: string;
|
|
@@ -299,9 +304,9 @@ const ENGLISH_MESSAGES: RendererSettingsMessages = Object.freeze({
|
|
|
299
304
|
sessionImportRetrying: "Opening...",
|
|
300
305
|
connectionsDescription:
|
|
301
306
|
"View runtime status by Host. Select an item to inspect details or complete its setup.",
|
|
302
|
-
accountsDescription: "
|
|
303
|
-
accountTaskHint:
|
|
304
|
-
"
|
|
307
|
+
accountsDescription: "Manage isolated native Codex accounts and compare each account's live limits.",
|
|
308
|
+
accountTaskHint:
|
|
309
|
+
"Signing in or switching accounts does not affect tasks already running. New tasks use the selected account.",
|
|
305
310
|
accountConnected: "Connected accounts",
|
|
306
311
|
accountDefaultBadge: "Default",
|
|
307
312
|
accountAdd: "Add Account",
|
|
@@ -327,7 +332,12 @@ const ENGLISH_MESSAGES: RendererSettingsMessages = Object.freeze({
|
|
|
327
332
|
accountDeleteFailed: "Could not delete the Account.",
|
|
328
333
|
accountActive: "Default",
|
|
329
334
|
accountUse: "Set as default",
|
|
330
|
-
accountSignIn: "Sign in",
|
|
335
|
+
accountSignIn: "Sign in",
|
|
336
|
+
accountSignOut: "Sign out",
|
|
337
|
+
accountSignOutConfirm: "Sign out of the current official Codex account?",
|
|
338
|
+
accountSigningOut: "Signing out of official Codex...",
|
|
339
|
+
accountSignedOut: "Signed out of official Codex.",
|
|
340
|
+
accountSignOutFailed: "Could not sign out of official Codex.",
|
|
331
341
|
accountSigningIn: "Starting device sign-in...",
|
|
332
342
|
accountDeviceCodePrerequisite:
|
|
333
343
|
"Before signing in, enable “Enable device code authorization for Codex” in Web Settings → Account security & sign-in.",
|
|
@@ -498,9 +508,11 @@ const ENGLISH_MESSAGES: RendererSettingsMessages = Object.freeze({
|
|
|
498
508
|
aboutOpenSource: "Harness Mix is an open-source project. The source code is available at:",
|
|
499
509
|
aboutStarCallout: "⭐ If this project helps you, please give us a Star! ⭐",
|
|
500
510
|
aboutRepository: "Open-source repository",
|
|
501
|
-
pageLabels: Object.freeze({
|
|
502
|
-
connections: "Connections",
|
|
503
|
-
accounts: "Accounts",
|
|
511
|
+
pageLabels: Object.freeze({
|
|
512
|
+
connections: "Connections",
|
|
513
|
+
accounts: "Accounts",
|
|
514
|
+
mcp: 'MCP',
|
|
515
|
+
skills: 'Skills',
|
|
504
516
|
"session-import": "Session Import",
|
|
505
517
|
updates: "Updates",
|
|
506
518
|
about: "About",
|
|
@@ -554,8 +566,8 @@ const CHINESE_MESSAGES: RendererSettingsMessages = Object.freeze({
|
|
|
554
566
|
sessionImportRetryOpen: "重试打开",
|
|
555
567
|
sessionImportRetrying: "正在打开……",
|
|
556
568
|
connectionsDescription: "按 Host 查看运行时状态。选择一项,在右侧检查详情或完成配置。",
|
|
557
|
-
accountsDescription: "
|
|
558
|
-
accountTaskHint: "
|
|
569
|
+
accountsDescription: "管理相互隔离的原生 Codex 账号,并对比每个账号的实时额度。",
|
|
570
|
+
accountTaskHint: "登录或切换账号不会影响已开始的任务;新任务使用当前选中的账号。",
|
|
559
571
|
accountConnected: "已连接账号",
|
|
560
572
|
accountDefaultBadge: "默认",
|
|
561
573
|
accountAdd: "添加账号",
|
|
@@ -581,7 +593,12 @@ const CHINESE_MESSAGES: RendererSettingsMessages = Object.freeze({
|
|
|
581
593
|
accountDeleteFailed: "删除账号失败。",
|
|
582
594
|
accountActive: "默认账号",
|
|
583
595
|
accountUse: "设为默认",
|
|
584
|
-
accountSignIn: "登录",
|
|
596
|
+
accountSignIn: "登录",
|
|
597
|
+
accountSignOut: "退出登录",
|
|
598
|
+
accountSignOutConfirm: "确定退出当前官方 Codex 账号吗?",
|
|
599
|
+
accountSigningOut: "正在退出官方 Codex...",
|
|
600
|
+
accountSignedOut: "已退出官方 Codex。",
|
|
601
|
+
accountSignOutFailed: "退出官方 Codex 失败。",
|
|
585
602
|
accountSigningIn: "正在启动设备登录...",
|
|
586
603
|
accountDeviceCodePrerequisite:
|
|
587
604
|
"登录前,请先在 Web 端的“设置 → 账号安全与登录”中开启“为 Codex 启用设备代码授权”。",
|
|
@@ -750,8 +767,10 @@ const CHINESE_MESSAGES: RendererSettingsMessages = Object.freeze({
|
|
|
750
767
|
aboutRepository: "开源仓库",
|
|
751
768
|
pageLabels: Object.freeze({
|
|
752
769
|
connections: "连接",
|
|
753
|
-
accounts: "账号",
|
|
754
|
-
|
|
770
|
+
accounts: "账号",
|
|
771
|
+
mcp: 'MCP',
|
|
772
|
+
skills: 'Skills',
|
|
773
|
+
"session-import": "会话导入",
|
|
755
774
|
updates: "更新",
|
|
756
775
|
about: "关于",
|
|
757
776
|
}),
|
|
@@ -26,7 +26,9 @@ import {
|
|
|
26
26
|
type RendererSessionImportClient,
|
|
27
27
|
type RendererImportedThreadOpener,
|
|
28
28
|
} from "./session-import-page.js";
|
|
29
|
-
import { createReleaseNotesElement } from "./release-notes.js";
|
|
29
|
+
import { createReleaseNotesElement } from "./release-notes.js";
|
|
30
|
+
import { createMcpSettingsPage, createSkillsSettingsPage } from './integrations-page.js';
|
|
31
|
+
import type { RendererIntegrationsClient } from '../renderer-integrations-client.js';
|
|
30
32
|
import { createAccountsSettingsPage, type RendererCodexAccountClient } from "./accounts-page.js";
|
|
31
33
|
|
|
32
34
|
export type {
|
|
@@ -71,7 +73,9 @@ function windowsInstallerDownloadUrl(window: Window | null | undefined, version:
|
|
|
71
73
|
|
|
72
74
|
export const DEFAULT_RENDERER_SETTINGS_PAGE_IDS = [
|
|
73
75
|
"connections",
|
|
74
|
-
"accounts",
|
|
76
|
+
"accounts",
|
|
77
|
+
"mcp",
|
|
78
|
+
"skills",
|
|
75
79
|
"session-import",
|
|
76
80
|
"updates",
|
|
77
81
|
"about",
|
|
@@ -79,11 +83,12 @@ export const DEFAULT_RENDERER_SETTINGS_PAGE_IDS = [
|
|
|
79
83
|
|
|
80
84
|
export type DefaultRendererSettingsPageId = (typeof DEFAULT_RENDERER_SETTINGS_PAGE_IDS)[number];
|
|
81
85
|
|
|
82
|
-
export interface RendererUpdateClient {
|
|
83
|
-
checkUpdate(): Promise<UpdateCheckResult>;
|
|
84
|
-
startUpdate(): Promise<UpdateStartResult>;
|
|
85
|
-
readUpdateStatus(): Promise<UpdateStatusResult>;
|
|
86
|
-
}
|
|
86
|
+
export interface RendererUpdateClient {
|
|
87
|
+
checkUpdate(): Promise<UpdateCheckResult>;
|
|
88
|
+
startUpdate(): Promise<UpdateStartResult>;
|
|
89
|
+
readUpdateStatus(): Promise<UpdateStatusResult>;
|
|
90
|
+
readCurrentVersion?(): Promise<{ version: string }>;
|
|
91
|
+
}
|
|
87
92
|
|
|
88
93
|
function panelIconName(view: string): RendererSettingsIconName {
|
|
89
94
|
if (view === "failed" || view === "error") return "alert";
|
|
@@ -154,7 +159,10 @@ function formatUpdateBytes(value: number): string {
|
|
|
154
159
|
return `${scaled.toFixed(scaled >= 10 ? 0 : 1)} ${unit}`;
|
|
155
160
|
}
|
|
156
161
|
|
|
157
|
-
export function aboutPage(
|
|
162
|
+
export function aboutPage(
|
|
163
|
+
messages: RendererSettingsMessages,
|
|
164
|
+
getClient: () => RendererUpdateClient | null = () => null,
|
|
165
|
+
): RendererSettingsPageDefinition {
|
|
158
166
|
return Object.freeze({
|
|
159
167
|
id: "about",
|
|
160
168
|
label: messages.pageLabels.about,
|
|
@@ -177,7 +185,7 @@ export function aboutPage(messages: RendererSettingsMessages): RendererSettingsP
|
|
|
177
185
|
versionRow.className = "settings-about-version-row";
|
|
178
186
|
const versionBadge = document.createElement("span");
|
|
179
187
|
versionBadge.className = "settings-about-version-badge";
|
|
180
|
-
versionBadge.textContent = "
|
|
188
|
+
versionBadge.textContent = "v…";
|
|
181
189
|
const checkUpdateBtn = document.createElement("button");
|
|
182
190
|
checkUpdateBtn.type = "button";
|
|
183
191
|
checkUpdateBtn.className = "settings-command-button settings-command-button--secondary";
|
|
@@ -217,9 +225,27 @@ export function aboutPage(messages: RendererSettingsMessages): RendererSettingsP
|
|
|
217
225
|
repositoryUrl,
|
|
218
226
|
);
|
|
219
227
|
repositorySection.append(openSource, repository);
|
|
220
|
-
panel.append(product, tagline, versionRow, introduction, starCallout, repositorySection);
|
|
221
|
-
context.content.append(heading, panel);
|
|
222
|
-
|
|
228
|
+
panel.append(product, tagline, versionRow, introduction, starCallout, repositorySection);
|
|
229
|
+
context.content.append(heading, panel);
|
|
230
|
+
const client = getClient();
|
|
231
|
+
const readVersion = client?.readCurrentVersion
|
|
232
|
+
? () => client.readCurrentVersion!()
|
|
233
|
+
: client
|
|
234
|
+
? () => client.checkUpdate().then(({ currentVersion }) => ({ version: currentVersion }))
|
|
235
|
+
: null;
|
|
236
|
+
if (readVersion) {
|
|
237
|
+
void context.runLatest(readVersion, {
|
|
238
|
+
success(result) {
|
|
239
|
+
versionBadge.textContent = `v${result.version}`;
|
|
240
|
+
},
|
|
241
|
+
failure() {
|
|
242
|
+
versionBadge.textContent = "v—";
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
} else {
|
|
246
|
+
versionBadge.textContent = "v—";
|
|
247
|
+
}
|
|
248
|
+
return undefined;
|
|
223
249
|
},
|
|
224
250
|
});
|
|
225
251
|
}
|
|
@@ -597,15 +623,18 @@ export function createDefaultRendererSettingsPages(
|
|
|
597
623
|
getDiagnostics: () => RendererConnectionDiagnostics | null = () => null,
|
|
598
624
|
getAccountClient: () => RendererCodexAccountClient | null = () => null,
|
|
599
625
|
getSessionImportClient: () => RendererSessionImportClient | null = () => null,
|
|
600
|
-
openImportedThread: RendererImportedThreadOpener = () =>
|
|
601
|
-
Promise.reject(new Error("Imported Thread navigation is unavailable")),
|
|
626
|
+
openImportedThread: RendererImportedThreadOpener = () =>
|
|
627
|
+
Promise.reject(new Error("Imported Thread navigation is unavailable")),
|
|
628
|
+
getIntegrationsClient: () => RendererIntegrationsClient | null = () => null,
|
|
602
629
|
): readonly RendererSettingsPageDefinition[] {
|
|
603
630
|
return Object.freeze([
|
|
604
631
|
createConnectionsSettingsPage(messages, getDiagnostics),
|
|
605
|
-
createAccountsSettingsPage(messages, getAccountClient),
|
|
632
|
+
createAccountsSettingsPage(messages, getAccountClient),
|
|
633
|
+
createMcpSettingsPage(messages, getIntegrationsClient),
|
|
634
|
+
createSkillsSettingsPage(messages, getIntegrationsClient),
|
|
606
635
|
createSessionImportSettingsPage(messages, getSessionImportClient, openImportedThread),
|
|
607
636
|
updatesPage(messages, getUpdateClient),
|
|
608
|
-
aboutPage(messages),
|
|
637
|
+
aboutPage(messages, getUpdateClient),
|
|
609
638
|
]);
|
|
610
639
|
}
|
|
611
640
|
|
|
@@ -615,7 +644,8 @@ export function createDefaultRendererSettingsRegistry(
|
|
|
615
644
|
getDiagnostics: () => RendererConnectionDiagnostics | null = () => null,
|
|
616
645
|
getAccountClient: () => RendererCodexAccountClient | null = () => null,
|
|
617
646
|
getSessionImportClient: () => RendererSessionImportClient | null = () => null,
|
|
618
|
-
openImportedThread?: RendererImportedThreadOpener,
|
|
647
|
+
openImportedThread?: RendererImportedThreadOpener,
|
|
648
|
+
getIntegrationsClient?: () => RendererIntegrationsClient | null,
|
|
619
649
|
): RendererSettingsPageRegistry {
|
|
620
650
|
return createRendererSettingsPageRegistry(
|
|
621
651
|
createDefaultRendererSettingsPages(
|
|
@@ -624,7 +654,8 @@ export function createDefaultRendererSettingsRegistry(
|
|
|
624
654
|
getDiagnostics,
|
|
625
655
|
getAccountClient,
|
|
626
656
|
getSessionImportClient,
|
|
627
|
-
openImportedThread,
|
|
657
|
+
openImportedThread,
|
|
658
|
+
getIntegrationsClient,
|
|
628
659
|
),
|
|
629
660
|
);
|
|
630
661
|
}
|
|
@@ -2236,3 +2236,106 @@ button {
|
|
|
2236
2236
|
.settings-install-steps li {
|
|
2237
2237
|
margin-bottom: 2px;
|
|
2238
2238
|
}
|
|
2239
|
+
/* MCP and Skills share native settings controls while keeping separate flows. */
|
|
2240
|
+
.settings-integrations-controls { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin: 18px 0 12px; }
|
|
2241
|
+
.settings-integrations-controls input { flex: 1; min-width: 180px; }
|
|
2242
|
+
.settings-integrations-controls input[hidden] { display: none; }
|
|
2243
|
+
.settings-integrations-controls select, .settings-integrations-controls input,
|
|
2244
|
+
.settings-integrations-field input, .settings-integrations-toolbar input { box-sizing: border-box; padding: 9px 11px; border: 1px solid var(--settings-border, #8885); border-radius: 8px; color: inherit; background: var(--settings-input, transparent); font: inherit; }
|
|
2245
|
+
.settings-integrations-status { min-height: 18px; margin: 0 0 6px; color: var(--settings-muted); font-size: 12px; }
|
|
2246
|
+
.settings-integrations-body p { font-size: 12px; line-height: 1.6; opacity: .8; }
|
|
2247
|
+
.settings-integrations-toolbar { display: flex; gap: 10px; align-items: center; margin: 8px 0 16px; }
|
|
2248
|
+
.settings-integrations-toolbar input { flex: 1; }
|
|
2249
|
+
.settings-integrations-list { display: grid; gap: 8px; }
|
|
2250
|
+
.settings-integrations-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; border: 1px solid var(--settings-border, #8885); padding: 14px; border-radius: 10px; background: var(--settings-surface, transparent); }
|
|
2251
|
+
.settings-integrations-row > div { flex: 1; min-width: 180px; }
|
|
2252
|
+
.settings-integrations-row p { margin: 3px 0; }
|
|
2253
|
+
.settings-integrations-row code { display: block; overflow-wrap: anywhere; font-size: 11px; color: var(--settings-muted); }
|
|
2254
|
+
.settings-integrations-row--native { border-style: dashed; }
|
|
2255
|
+
.settings-integrations-empty { padding: 36px 18px; border: 1px dashed var(--settings-border, #8885); border-radius: 10px; text-align: center; color: var(--settings-muted); font-size: 12px; }
|
|
2256
|
+
.settings-integrations-editor-head { display: flex; align-items: center; gap: 12px; }
|
|
2257
|
+
.settings-integrations-editor-head h3 { margin: 0; }
|
|
2258
|
+
.settings-integrations-form { display: grid; gap: 14px; margin: 16px 0 28px; }
|
|
2259
|
+
.settings-integrations-form--card { padding: 16px; border: 1px solid var(--settings-border, #8885); border-radius: 12px; }
|
|
2260
|
+
.settings-integrations-field { display: grid; gap: 6px; font-size: 12px; }
|
|
2261
|
+
.settings-integrations-form > button { justify-self: start; }
|
|
2262
|
+
.settings-mcp-args { display: grid; gap: 7px; }
|
|
2263
|
+
.settings-mcp-arg { display: flex; gap: 8px; align-items: center; }
|
|
2264
|
+
.settings-mcp-arg input { flex: 1; }
|
|
2265
|
+
.settings-mcp-kv-row { display: flex; gap: 8px; align-items: center; }
|
|
2266
|
+
.settings-mcp-kv-row input { flex: 1; }
|
|
2267
|
+
.settings-mcp-add-arg { margin-top: 7px; }
|
|
2268
|
+
.settings-mcp-docs-link { display: inline-flex; align-items: center; gap: 4px; color: var(--settings-muted, #888); font-size: 13px; text-decoration: none; transition: color 150ms ease; }
|
|
2269
|
+
.settings-mcp-docs-link:hover { color: var(--settings-text, #fff); text-decoration: underline; }
|
|
2270
|
+
.settings-integrations-editor-head .settings-command-button--danger { margin-left: auto; }
|
|
2271
|
+
.settings-mcp-type-toggle { display: inline-flex; padding: 3px; border-radius: 8px; background: var(--settings-inset, rgba(255, 255, 255, 0.06)); border: 1px solid var(--settings-border, #8885); gap: 2px; width: fit-content; }
|
|
2272
|
+
.settings-mcp-type-btn { padding: 5px 14px; border-radius: 6px; border: none; background: transparent; color: var(--settings-muted, #888); font: inherit; font-size: 12px; font-weight: 500; cursor: pointer; transition: all 120ms ease; }
|
|
2273
|
+
.settings-mcp-type-btn:hover { color: var(--settings-text, #fff); }
|
|
2274
|
+
.settings-mcp-type-btn[data-active="true"] { background: var(--settings-active, rgba(255, 255, 255, 0.15)); color: var(--settings-text, #fff); font-weight: 600; }
|
|
2275
|
+
.settings-mcp-notice { margin: 4px 0 0; color: var(--settings-muted, #888); font-size: 12px; line-height: 1.5; }
|
|
2276
|
+
.settings-mcp-section { display: grid; gap: 14px; }
|
|
2277
|
+
.settings-mcp-icon-btn { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px; padding: 0; border: 1px solid var(--settings-border, #8885); border-radius: 8px; background: var(--settings-input, transparent); color: var(--settings-muted, #888); cursor: pointer; flex: none; transition: all 120ms ease; }
|
|
2278
|
+
.settings-mcp-icon-btn:hover:not(:disabled) { background: rgba(239, 68, 68, 0.15); border-color: rgba(239, 68, 68, 0.4); color: #f87171; }
|
|
2279
|
+
.settings-mcp-icon-btn svg { width: 14px; height: 14px; display: block; }
|
|
2280
|
+
.settings-integrations-callout { margin: 0; padding: 10px 12px; border-radius: 8px; background: var(--settings-inset); }
|
|
2281
|
+
.settings-skill-dropzone { display: grid; justify-items: center; gap: 8px; padding: 34px 22px; margin: 8px 0 18px; border: 1.5px dashed var(--settings-border, #8887); border-radius: 14px; background: var(--settings-inset); text-align: center; transition: border-color 120ms ease, background 120ms ease, transform 120ms ease; }
|
|
2282
|
+
.settings-skill-dropzone > span { max-width: 520px; color: var(--settings-muted); font-size: 12px; line-height: 18px; }
|
|
2283
|
+
.settings-skill-dropzone[data-drag-over="true"] { border-color: var(--settings-accent, #10a37f); background: var(--settings-accent-subtle, rgba(16, 163, 127, .1)); transform: scale(.995); }
|
|
2284
|
+
.settings-skill-dropzone[data-disabled="true"] { opacity: .55; }
|
|
2285
|
+
.settings-skills-target-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; justify-content: center; margin-top: 6px; }
|
|
2286
|
+
.settings-skills-target-row select { padding: 6px 10px; border: 1px solid var(--settings-border, #8885); border-radius: 8px; background: var(--settings-input, transparent); color: inherit; font: inherit; font-size: 12px; }
|
|
2287
|
+
.settings-skills-overview-stats { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin: 6px 0 10px; font-size: 12px; color: var(--settings-muted); }
|
|
2288
|
+
.settings-skills-tabs { display: inline-flex; padding: 3px; border-radius: 8px; background: var(--settings-inset, rgba(255, 255, 255, 0.06)); border: 1px solid var(--settings-border, #8885); gap: 2px; }
|
|
2289
|
+
.settings-skills-tab-btn { padding: 5px 14px; border-radius: 6px; border: none; background: transparent; color: var(--settings-muted, #888); font: inherit; font-size: 12px; font-weight: 500; cursor: pointer; transition: all 120ms ease; }
|
|
2290
|
+
.settings-skills-tab-btn:hover { color: var(--settings-text, #fff); }
|
|
2291
|
+
.settings-skills-tab-btn[data-active="true"] { background: var(--settings-active, rgba(255, 255, 255, 0.15)); color: var(--settings-text, #fff); font-weight: 600; }
|
|
2292
|
+
.settings-skills-overview-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 14px; margin-top: 10px; }
|
|
2293
|
+
.settings-skills-harness-card { border: 1px solid var(--settings-border, #8885); border-radius: 12px; padding: 14px; background: var(--settings-surface, transparent); display: flex; flex-direction: column; gap: 10px; }
|
|
2294
|
+
.settings-skills-harness-head { display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--settings-border, #8883); padding-bottom: 8px; }
|
|
2295
|
+
.settings-skills-harness-head strong { font-size: 14px; }
|
|
2296
|
+
.settings-skills-badge { font-size: 11px; padding: 2px 8px; border-radius: 10px; background: var(--settings-inset, rgba(255, 255, 255, 0.08)); color: var(--settings-muted); }
|
|
2297
|
+
.settings-skills-badge--active { background: rgba(16, 163, 127, 0.15); color: #10a37f; }
|
|
2298
|
+
.settings-skills-list-compact { display: flex; flex-direction: column; gap: 8px; max-height: 280px; overflow-y: auto; }
|
|
2299
|
+
.settings-skills-item-row { display: flex; justify-content: space-between; align-items: center; gap: 8px; padding: 6px 8px; border-radius: 6px; background: var(--settings-inset, rgba(255, 255, 255, 0.03)); font-size: 12px; }
|
|
2300
|
+
.settings-skills-item-row strong { font-size: 13px; }
|
|
2301
|
+
.settings-skills-item-row code { font-size: 10px; color: var(--settings-muted); overflow-wrap: anywhere; display: block; }
|
|
2302
|
+
.settings-skills-item-actions { display: flex; gap: 6px; align-items: center; flex: none; }
|
|
2303
|
+
.settings-skills-matrix-list { display: flex; flex-direction: column; gap: 10px; margin-top: 10px; }
|
|
2304
|
+
.settings-skills-matrix-card { border: 1px solid var(--settings-border, #8885); border-radius: 10px; padding: 12px 14px; background: var(--settings-surface, transparent); display: flex; flex-direction: column; gap: 8px; }
|
|
2305
|
+
.settings-skills-matrix-head { display: flex; justify-content: space-between; align-items: center; }
|
|
2306
|
+
.settings-skills-matrix-head span { font-size: 11px; color: var(--settings-muted); }
|
|
2307
|
+
.settings-skills-tags { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
|
|
2308
|
+
.settings-skills-tag { font-size: 11px; padding: 3px 8px; border-radius: 6px; background: rgba(16, 163, 127, 0.15); color: #10a37f; border: 1px solid rgba(16, 163, 127, 0.3); }
|
|
2309
|
+
.settings-skills-sync-actions { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-top: 4px; }
|
|
2310
|
+
.settings-skills-sync-modal { border: 1px solid var(--settings-border, #8885); border-radius: 12px; background: var(--settings-bg, #1e1e1e); color: inherit; padding: 20px 24px; max-width: 420px; box-shadow: 0 16px 32px rgba(0, 0, 0, 0.5); }
|
|
2311
|
+
.settings-skills-sync-modal::backdrop { background: rgba(0, 0, 0, 0.6); backdrop-filter: blur(2px); }
|
|
2312
|
+
.settings-skills-sync-modal h3 { margin: 0 0 8px; font-size: 16px; }
|
|
2313
|
+
.settings-skills-sync-modal p { margin: 0 0 12px; font-size: 12px; color: var(--settings-muted); }
|
|
2314
|
+
.settings-mcp-overview-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 14px; margin-top: 10px; }
|
|
2315
|
+
.settings-mcp-harness-card { border: 1px solid var(--settings-border, #8885); border-radius: 12px; padding: 14px; background: var(--settings-surface, transparent); display: flex; flex-direction: column; gap: 10px; }
|
|
2316
|
+
.settings-mcp-harness-head { display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--settings-border, #8883); padding-bottom: 8px; }
|
|
2317
|
+
.settings-mcp-harness-head strong { font-size: 14px; }
|
|
2318
|
+
.settings-mcp-native-box { padding: 8px 10px; border-radius: 8px; background: rgba(16, 163, 127, 0.08); border: 1px dashed rgba(16, 163, 127, 0.3); font-size: 11px; display: flex; flex-direction: column; gap: 4px; }
|
|
2319
|
+
.settings-mcp-native-title { font-weight: 600; color: #10a37f; display: flex; align-items: center; gap: 6px; }
|
|
2320
|
+
.settings-mcp-native-item { display: flex; flex-direction: column; gap: 2px; color: var(--settings-muted); }
|
|
2321
|
+
.settings-mcp-native-item code { font-size: 10px; overflow-wrap: anywhere; }
|
|
2322
|
+
.settings-mcp-list-compact { display: flex; flex-direction: column; gap: 8px; max-height: 280px; overflow-y: auto; }
|
|
2323
|
+
.settings-mcp-item-row { display: flex; justify-content: space-between; align-items: center; gap: 8px; padding: 6px 8px; border-radius: 6px; background: var(--settings-inset, rgba(255, 255, 255, 0.03)); font-size: 12px; }
|
|
2324
|
+
.settings-mcp-item-row strong { font-size: 13px; }
|
|
2325
|
+
.settings-mcp-item-row code { font-size: 10px; color: var(--settings-muted); overflow-wrap: anywhere; display: block; }
|
|
2326
|
+
.settings-mcp-item-actions { display: flex; gap: 6px; align-items: center; flex: none; }
|
|
2327
|
+
.settings-mcp-card-footer { display: flex; justify-content: flex-end; margin-top: auto; padding-top: 6px; border-top: 1px solid var(--settings-border, #8882); }
|
|
2328
|
+
.settings-mcp-matrix-list { display: flex; flex-direction: column; gap: 10px; margin-top: 10px; }
|
|
2329
|
+
.settings-mcp-matrix-card { border: 1px solid var(--settings-border, #8885); border-radius: 10px; padding: 12px 14px; background: var(--settings-surface, transparent); display: flex; flex-direction: column; gap: 8px; }
|
|
2330
|
+
.settings-mcp-matrix-head { display: flex; justify-content: space-between; align-items: center; }
|
|
2331
|
+
.settings-mcp-matrix-head span { font-size: 11px; color: var(--settings-muted); }
|
|
2332
|
+
.settings-mcp-tags { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
|
|
2333
|
+
.settings-mcp-tag { font-size: 11px; padding: 3px 8px; border-radius: 6px; background: rgba(16, 163, 127, 0.15); color: #10a37f; border: 1px solid rgba(16, 163, 127, 0.3); }
|
|
2334
|
+
.settings-mcp-tag--disabled { background: rgba(255, 255, 255, 0.05); color: var(--settings-muted); border-color: var(--settings-border, #8885); }
|
|
2335
|
+
.settings-mcp-sync-actions { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-top: 4px; }
|
|
2336
|
+
.settings-mcp-distribute-modal { border: 1px solid var(--settings-border, #8885); border-radius: 12px; background: var(--settings-bg, #1e1e1e); color: inherit; padding: 20px 24px; max-width: 540px; width: 92%; max-height: 85vh; overflow-y: auto; box-shadow: 0 16px 32px rgba(0, 0, 0, 0.5); }
|
|
2337
|
+
.settings-mcp-distribute-modal::backdrop { background: rgba(0, 0, 0, 0.6); backdrop-filter: blur(2px); }
|
|
2338
|
+
.settings-mcp-distribute-modal h3 { margin: 0 0 8px; font-size: 16px; }
|
|
2339
|
+
.settings-mcp-distribute-modal p { margin: 0 0 12px; font-size: 12px; color: var(--settings-muted); }
|
|
2340
|
+
|
|
2341
|
+
|
|
@@ -79,7 +79,7 @@ describe("Renderer Agent picker presentation", () => {
|
|
|
79
79
|
isDefault: false,
|
|
80
80
|
},
|
|
81
81
|
),
|
|
82
|
-
).toBe("Agent: Codex · reviewer@example.com (locked)");
|
|
82
|
+
).toBe("Agent: Codex(官方原生) · reviewer@example.com (locked)");
|
|
83
83
|
expect(rendererAgentPickerTooltip({ agent: "claude-code", phase: "locked" }, undefined)).toBe(
|
|
84
84
|
"Agent: Claude Code (locked)",
|
|
85
85
|
);
|
|
@@ -94,7 +94,7 @@ describe("Renderer Agent picker presentation", () => {
|
|
|
94
94
|
"grok",
|
|
95
95
|
]),
|
|
96
96
|
).toEqual({
|
|
97
|
-
label: "Codex",
|
|
97
|
+
label: "Codex(官方原生)",
|
|
98
98
|
triggerDisabled: false,
|
|
99
99
|
nativeModelHidden: false,
|
|
100
100
|
optionDisabled: { codex: false, pi: true, "claude-code": true, grok: true },
|
|
@@ -107,27 +107,58 @@ describe("Renderer Agent picker presentation", () => {
|
|
|
107
107
|
expect(
|
|
108
108
|
rendererAgentPickerView({ agent: "codex", phase: "draft" }, "ready", false, ["codex"], {}, 2),
|
|
109
109
|
).toMatchObject({
|
|
110
|
-
label: "Codex",
|
|
110
|
+
label: "Codex(官方原生)",
|
|
111
111
|
triggerDisabled: false,
|
|
112
112
|
optionDisabled: { codex: false },
|
|
113
113
|
});
|
|
114
114
|
});
|
|
115
115
|
|
|
116
|
-
it("
|
|
116
|
+
it("turns a submitted external Agent picker into a Harness handoff picker", () => {
|
|
117
117
|
expect(
|
|
118
|
-
rendererAgentPickerView(
|
|
119
|
-
pi: "
|
|
120
|
-
|
|
118
|
+
rendererAgentPickerView(
|
|
119
|
+
{ agent: "pi", phase: "locked" },
|
|
120
|
+
"ready",
|
|
121
|
+
false,
|
|
122
|
+
["codex", "pi", "claude-code"],
|
|
123
|
+
{ pi: "ready", "claude-code": "ready" },
|
|
124
|
+
),
|
|
121
125
|
).toEqual({
|
|
122
126
|
label: "Pi",
|
|
123
|
-
triggerDisabled:
|
|
127
|
+
triggerDisabled: false,
|
|
124
128
|
nativeModelHidden: true,
|
|
125
|
-
optionDisabled: { codex: true, pi: true },
|
|
126
|
-
downloadVisible: { pi: false },
|
|
127
|
-
errorVisible: { pi: false },
|
|
129
|
+
optionDisabled: { codex: true, pi: true, "claude-code": false },
|
|
130
|
+
downloadVisible: { pi: false, "claude-code": false },
|
|
131
|
+
errorVisible: { pi: false, "claude-code": false },
|
|
128
132
|
});
|
|
129
133
|
});
|
|
130
134
|
|
|
135
|
+
it("offers another ready external Harness while keeping official Codex unavailable", () => {
|
|
136
|
+
expect(
|
|
137
|
+
rendererAgentPickerView(
|
|
138
|
+
{ agent: "pi", phase: "locked" },
|
|
139
|
+
"ready",
|
|
140
|
+
false,
|
|
141
|
+
["codex", "pi", "claude-code", "grok"],
|
|
142
|
+
{ pi: "ready", "claude-code": "ready", grok: "unavailable" },
|
|
143
|
+
),
|
|
144
|
+
).toMatchObject({
|
|
145
|
+
triggerDisabled: false,
|
|
146
|
+
optionDisabled: { codex: true, pi: true, "claude-code": false, grok: true },
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("keeps an official Codex conversation locked because HostRuntime does not own it", () => {
|
|
151
|
+
expect(
|
|
152
|
+
rendererAgentPickerView(
|
|
153
|
+
{ agent: "codex", phase: "locked" },
|
|
154
|
+
"ready",
|
|
155
|
+
false,
|
|
156
|
+
["codex", "pi"],
|
|
157
|
+
{ pi: "ready" },
|
|
158
|
+
),
|
|
159
|
+
).toMatchObject({ triggerDisabled: true, optionDisabled: { codex: true, pi: true } });
|
|
160
|
+
});
|
|
161
|
+
|
|
131
162
|
it("hides the native Model and disables all choices while switching", () => {
|
|
132
163
|
expect(
|
|
133
164
|
rendererAgentPickerView({ agent: "codex", phase: "draft" }, "ready", true, ["codex", "pi"]),
|
|
@@ -145,7 +176,7 @@ describe("Renderer Agent picker presentation", () => {
|
|
|
145
176
|
pi: "notInstalled",
|
|
146
177
|
}),
|
|
147
178
|
).toEqual({
|
|
148
|
-
label: "Codex",
|
|
179
|
+
label: "Codex(官方原生)",
|
|
149
180
|
triggerDisabled: false,
|
|
150
181
|
nativeModelHidden: false,
|
|
151
182
|
optionDisabled: { codex: false, pi: true },
|
|
@@ -160,7 +191,7 @@ describe("Renderer Agent picker presentation", () => {
|
|
|
160
191
|
pi: "error",
|
|
161
192
|
}),
|
|
162
193
|
).toEqual({
|
|
163
|
-
label: "Codex",
|
|
194
|
+
label: "Codex(官方原生)",
|
|
164
195
|
triggerDisabled: false,
|
|
165
196
|
nativeModelHidden: false,
|
|
166
197
|
optionDisabled: { codex: false, pi: true },
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { CHATGPT_CONTEXT_MAX_LENGTH, buildChatGptContextDraft, isChatGptQuickChatEditor, redactChatGptContextText, sanitizeChatGptSourceUrl } from "../src/renderer-chatgpt-context.js";
|
|
3
|
+
|
|
4
|
+
describe("ChatGPT context package", () => {
|
|
5
|
+
it("marks imported text as untrusted context", () => {
|
|
6
|
+
const draft = buildChatGptContextDraft({ title: "架构讨论", sourceUrl: "https://chatgpt.com/c/example?utm_source=secret#turn", mode: "loaded-messages", messages: [{ role: "user", text: "给一个迁移方案" }, { role: "assistant", text: "先建立共享契约" }], truncated: false });
|
|
7
|
+
expect(draft).toContain("不可信历史资料"); expect(draft).toContain("不恢复原聊天"); expect(draft).toContain("User: 给一个迁移方案"); expect(draft).toContain("Assistant: 先建立共享契约"); expect(draft).toContain("https://chatgpt.com/c/example"); expect(draft).not.toContain("utm_source");
|
|
8
|
+
});
|
|
9
|
+
it("redacts credentials and caps the package", () => {
|
|
10
|
+
expect(redactChatGptContextText("Authorization: Bearer abcdefghijklmnopqrstuvwxyz sk-abcdefghijklmnopqrstuvwxyz123456")).not.toContain("abcdefghijklmnopqrstuvwxyz");
|
|
11
|
+
const draft = buildChatGptContextDraft({ title: "大段聊天", mode: "selection", messages: [{ role: "user", text: "x".repeat(CHATGPT_CONTEXT_MAX_LENGTH * 2) }], truncated: true });
|
|
12
|
+
expect(draft.length).toBeLessThanOrEqual(CHATGPT_CONTEXT_MAX_LENGTH); expect(draft).toContain("已截断");
|
|
13
|
+
});
|
|
14
|
+
it("accepts only sanitized HTTPS ChatGPT links", () => {
|
|
15
|
+
expect(sanitizeChatGptSourceUrl("https://chatgpt.com/c/abc?token=nope#part")).toBe("https://chatgpt.com/c/abc");
|
|
16
|
+
expect(sanitizeChatGptSourceUrl("http://chatgpt.com/c/abc")).toBeUndefined(); expect(sanitizeChatGptSourceUrl("https://example.com/c/abc")).toBeUndefined();
|
|
17
|
+
});
|
|
18
|
+
it("ignores partial DOM fixtures that are not browser Elements", () => {
|
|
19
|
+
expect(isChatGptQuickChatEditor({} as Element)).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from "vitest";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
codexAccountRouteOverride,
|
|
4
|
+
RendererCodexAccountState,
|
|
5
|
+
} from "../src/renderer-codex-account-state.js";
|
|
3
6
|
import { createRendererModelClient } from "../src/renderer-model-client.js";
|
|
4
7
|
|
|
5
8
|
const account = (accountId: string, active = false) => ({
|
|
@@ -17,6 +20,15 @@ function createState(sendRequest: (method: string, params: unknown) => Promise<u
|
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
describe("Host-scoped Codex Account state", () => {
|
|
23
|
+
it("routes isolated Accounts through Harness Mix even when they are the active default", () => {
|
|
24
|
+
const accounts = [
|
|
25
|
+
{ ...account("official"), management: "native" as const },
|
|
26
|
+
{ ...account("work", true), management: "isolated" as const },
|
|
27
|
+
];
|
|
28
|
+
expect(codexAccountRouteOverride(accounts, "work")).toBe("work");
|
|
29
|
+
expect(codexAccountRouteOverride(accounts, "official")).toBeNull();
|
|
30
|
+
});
|
|
31
|
+
|
|
20
32
|
it("coalesces concurrent refreshes on the same concrete client", async () => {
|
|
21
33
|
const response = Promise.withResolvers<unknown>();
|
|
22
34
|
const sendRequest = vi.fn(() => response.promise);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
HARNESS_HANDOFF_NOTE_MAX_LENGTH,
|
|
5
|
+
rendererHarnessHandoffMessages,
|
|
6
|
+
} from "../src/renderer-harness-handoff.js";
|
|
7
|
+
|
|
8
|
+
describe("Renderer Harness handoff", () => {
|
|
9
|
+
it("uses a bounded note compatible with the Host switch contract", () => {
|
|
10
|
+
expect(HARNESS_HANDOFF_NOTE_MAX_LENGTH).toBe(2000);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("explains that the task and working tree stay in place", () => {
|
|
14
|
+
const messages = rendererHarnessHandoffMessages("zh-CN");
|
|
15
|
+
expect(messages.title).toBe("接力当前任务");
|
|
16
|
+
expect(messages.description).toMatch(/任务窗口.*对话记录.*文件现场/);
|
|
17
|
+
expect(messages.context).toMatch(/近期对话.*最新方案.*计划.*变更文件/);
|
|
18
|
+
expect(messages.running).toMatch(/先停止或等待完成/);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
@@ -278,12 +278,13 @@ describe("Renderer fixed Model request client", () => {
|
|
|
278
278
|
},
|
|
279
279
|
})
|
|
280
280
|
.mockResolvedValueOnce({ status: null })
|
|
281
|
-
.mockResolvedValueOnce({ threadId: "thread-1" });
|
|
281
|
+
.mockResolvedValueOnce({ threadId: "thread-1", checkpointId: "handoff-1" });
|
|
282
282
|
const client = createRendererModelClient([{ addNotificationCallback, sendRequest }]);
|
|
283
283
|
if (!client) throw new Error("Synthetic Model client was not created");
|
|
284
284
|
expect(Object.keys(client).sort()).toEqual([
|
|
285
285
|
"activateCodexAccount",
|
|
286
286
|
"cancelCodexAccountLogin",
|
|
287
|
+
"changeSkill",
|
|
287
288
|
"checkUpdate",
|
|
288
289
|
"consumeCodexAccountResetCredit",
|
|
289
290
|
"createCodexAccount",
|
|
@@ -299,18 +300,24 @@ describe("Renderer fixed Model request client", () => {
|
|
|
299
300
|
"inspectThreadCommands",
|
|
300
301
|
"inspectThreadUsage",
|
|
301
302
|
"installHarness",
|
|
303
|
+
"integrationCatalog",
|
|
302
304
|
"listCodexAccounts",
|
|
303
305
|
"listCollaborationAgents",
|
|
304
306
|
"listHarnessAccounts",
|
|
305
307
|
"listHarnessPlugins",
|
|
306
308
|
"listHarnessSessions",
|
|
309
|
+
"listIntegrations",
|
|
307
310
|
"listSessionImportSources",
|
|
308
311
|
"listThreadOwnership",
|
|
309
312
|
"loginHarnessAccount",
|
|
313
|
+
"logoutCodexAccount",
|
|
310
314
|
"messageThread",
|
|
311
315
|
"openHarnessWebUi",
|
|
316
|
+
"readCurrentVersion",
|
|
312
317
|
"readUpdateStatus",
|
|
313
318
|
"refreshCodexAccounts",
|
|
319
|
+
"removeMcp",
|
|
320
|
+
"saveMcp",
|
|
314
321
|
"selectThreadModel",
|
|
315
322
|
"selectThreadPermissionMode",
|
|
316
323
|
"selectThreadThinking",
|
|
@@ -444,7 +451,7 @@ describe("Renderer fixed Model request client", () => {
|
|
|
444
451
|
harnessId: "claude-code",
|
|
445
452
|
note: "继续补测试",
|
|
446
453
|
}),
|
|
447
|
-
).resolves.toEqual({ threadId: "thread-1" });
|
|
454
|
+
).resolves.toEqual({ threadId: "thread-1", checkpointId: "handoff-1" });
|
|
448
455
|
expect(sendRequest).toHaveBeenNthCalledWith(13, THREAD_HARNESS_SWITCH_METHOD, {
|
|
449
456
|
threadId: "thread-1",
|
|
450
457
|
harnessId: "claude-code",
|
|
@@ -75,6 +75,6 @@ describe("Renderer settings localization", () => {
|
|
|
75
75
|
createDefaultRendererSettingsPages(rendererSettingsMessages("zh-CN")).map(
|
|
76
76
|
({ label }) => label,
|
|
77
77
|
),
|
|
78
|
-
).toEqual(["连接", "账号", "会话导入", "更新", "关于"]);
|
|
78
|
+
).toEqual(["连接", "账号", "MCP", "Skills", "会话导入", "更新", "关于"]);
|
|
79
79
|
});
|
|
80
80
|
});
|