@harness-mix/cli 0.1.5 → 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/README.md +1 -1
- package/docs/harness-management.md +4 -4
- package/docs/multi-agent-collaboration.md +9 -9
- package/output/native-build/renderer-extension.js +1959 -435
- package/package.json +9 -8
- package/scripts/collaboration-test.cjs +8 -3
- package/scripts/collaboration-ui-smoke.cjs +40 -26
- package/scripts/integrations-test.cjs +63 -4
- package/scripts/integrations-ui-smoke.cjs +77 -16
- package/scripts/native-protocol-test.cjs +102 -1
- package/scripts/native-sidebar-test.cjs +7 -0
- package/scripts/native-skill-roots-test.cjs +90 -0
- package/scripts/test-live-mentions.cjs +152 -0
- package/src/main/adapters/antigravity.js +20 -17
- package/src/main/adapters/claude.js +41 -8
- package/src/main/adapters/codebuddy.js +1 -0
- package/src/main/adapters/codex.js +20 -2
- package/src/main/adapters/cursor.js +5 -1
- package/src/main/adapters/dsh.js +8 -1
- package/src/main/adapters/grok.js +4 -1
- package/src/main/adapters/hermes.js +8 -0
- package/src/main/adapters/kiro.js +2 -1
- package/src/main/adapters/managed-mcp.js +15 -2
- package/src/main/adapters/omp.js +11 -0
- package/src/main/adapters/openclaw.js +6 -0
- package/src/main/adapters/opencode.js +5 -1
- package/src/main/adapters/pi.js +5 -1
- 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/host/collaboration.js +57 -11
- package/src/main/host/integrations.js +164 -26
- package/src/main/host/runtime.js +126 -86
- package/src/main/native/protocol.js +189 -78
- package/src/main/native/thread-list.js +3 -0
- package/src/native-ui/renderer-extension/dist/types/harness-mix-settings.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.map +1 -1
- 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 +29 -4
- package/src/native-ui/renderer-extension/dist/types/renderer-integrations-client.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/integrations-page.d.ts +2 -1
- package/src/native-ui/renderer-extension/dist/types/settings/integrations-page.d.ts.map +1 -1
- 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 +1 -1
- 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 +3 -2
- package/src/native-ui/renderer-extension/src/renderer-binding-probe.ts +149 -171
- package/src/native-ui/renderer-extension/src/renderer-chatgpt-context.ts +5 -1
- package/src/native-ui/renderer-extension/src/renderer-harness-mentions.ts +556 -123
- package/src/native-ui/renderer-extension/src/renderer-integrations-client.ts +36 -3
- package/src/native-ui/renderer-extension/src/settings/integrations-page.ts +1434 -62
- package/src/native-ui/renderer-extension/src/settings/localization.ts +4 -2
- package/src/native-ui/renderer-extension/src/settings/pages.ts +5 -3
- package/src/native-ui/renderer-extension/src/settings/shell.css +96 -6
- package/src/native-ui/renderer-extension/test/renderer-chatgpt-context.test.ts +4 -1
- package/src/native-ui/renderer-extension/test/settings/localization.test.ts +1 -1
- package/src/native-ui/renderer-extension/test/settings/shell.test.ts +5 -2
|
@@ -45,10 +45,10 @@ import {
|
|
|
45
45
|
type ExternalPermissionModeControlView,
|
|
46
46
|
} from "./renderer-composer-dom.js";
|
|
47
47
|
import { rendererHarnessMessages } from "./renderer-harness-localization.js";
|
|
48
|
-
import {
|
|
49
|
-
codexAccountRouteOverride,
|
|
50
|
-
RendererCodexAccountState,
|
|
51
|
-
} from "./renderer-codex-account-state.js";
|
|
48
|
+
import {
|
|
49
|
+
codexAccountRouteOverride,
|
|
50
|
+
RendererCodexAccountState,
|
|
51
|
+
} from "./renderer-codex-account-state.js";
|
|
52
52
|
import {
|
|
53
53
|
decodeAntigravityTransportModelId,
|
|
54
54
|
decodeClaudeTransportModelId,
|
|
@@ -79,20 +79,19 @@ import {
|
|
|
79
79
|
writeNewThreadExternalConfigurationPreference,
|
|
80
80
|
} from "./renderer-new-thread-preference.js";
|
|
81
81
|
import { installRendererSidebarAgentIcons } from "./renderer-sidebar-agent-icons.js";
|
|
82
|
-
import { installHarnessMentions } from './renderer-harness-mentions.js';
|
|
83
|
-
import { installCollabCards } from './renderer-collab-cards.js';
|
|
84
|
-
import { installChatGptContextBridge } from './renderer-chatgpt-context.js';
|
|
82
|
+
import { installHarnessMentions } from './renderer-harness-mentions.js';
|
|
83
|
+
import { installCollabCards } from './renderer-collab-cards.js';
|
|
85
84
|
import {
|
|
86
85
|
rendererHarnessCommandExecutesDirectly,
|
|
87
86
|
routeRendererHarnessCommandSelection,
|
|
88
87
|
} from "./renderer-harness-command-claim.js";
|
|
89
88
|
import { installRendererSettingsLifecycle } from "./harness-mix-settings.js";
|
|
90
89
|
import { openRendererThread } from "./renderer-fork-control.js";
|
|
91
|
-
import type {
|
|
92
|
-
RendererConnectionDiagnostics,
|
|
93
|
-
RendererConnectionSnapshot,
|
|
94
|
-
} from "./settings/pages.js";
|
|
95
|
-
import type { RendererHarnessHandoffRequest } from "./renderer-harness-handoff.js";
|
|
90
|
+
import type {
|
|
91
|
+
RendererConnectionDiagnostics,
|
|
92
|
+
RendererConnectionSnapshot,
|
|
93
|
+
} from "./settings/pages.js";
|
|
94
|
+
import type { RendererHarnessHandoffRequest } from "./renderer-harness-handoff.js";
|
|
96
95
|
|
|
97
96
|
const externalHarnessIds = {
|
|
98
97
|
pi: harnessIdSchema.parse("pi"),
|
|
@@ -530,7 +529,7 @@ export function isOwnershipSubmissionBlocked(status: ComposerOwnershipStatus): b
|
|
|
530
529
|
return status === "loading" || status === "error";
|
|
531
530
|
}
|
|
532
531
|
|
|
533
|
-
interface MountedComposer {
|
|
532
|
+
interface MountedComposer {
|
|
534
533
|
composer: Element;
|
|
535
534
|
composerId: string;
|
|
536
535
|
control: ComposerAgentControl;
|
|
@@ -543,9 +542,9 @@ interface MountedComposer {
|
|
|
543
542
|
accountCredits: AccountCreditsSnapshot | null;
|
|
544
543
|
hostId: string | null;
|
|
545
544
|
usageRequestGeneration: number;
|
|
546
|
-
commandRequestGeneration: number;
|
|
547
|
-
harnessSwitching: boolean;
|
|
548
|
-
}
|
|
545
|
+
commandRequestGeneration: number;
|
|
546
|
+
harnessSwitching: boolean;
|
|
547
|
+
}
|
|
549
548
|
|
|
550
549
|
interface PendingComposerReplacement {
|
|
551
550
|
source: MountedComposer;
|
|
@@ -715,14 +714,19 @@ export function installRendererBindingProbe(
|
|
|
715
714
|
const composer = editor.closest('[data-codex-composer-root]');
|
|
716
715
|
if (!composer) return { agents: [], sessions: [] };
|
|
717
716
|
const state = controller.get(composer);
|
|
718
|
-
// Stock Codex tasks bypass HostRuntime; do not advertise Host tools there.
|
|
719
|
-
if (state.agent === 'codex') return { agents: [], sessions: [] };
|
|
720
717
|
const client = modelClientForHost(modelControl?.currentHostId?.() ?? 'local');
|
|
721
718
|
const [agentResult, sessionResult] = await Promise.allSettled([
|
|
722
719
|
client?.listCollaborationAgents?.() ?? Promise.resolve([]),
|
|
723
720
|
client?.listHarnessSessions?.({ harnessId: harnessIdSchema.parse('all-harnesses'), query, offset: 0, limit: 12 }) ?? Promise.resolve({ candidates: [], total: 0 }),
|
|
724
721
|
]);
|
|
725
722
|
const agents = agentResult.status === 'fulfilled' ? agentResult.value : [];
|
|
723
|
+
(window as any).__lastMentionDebug = {
|
|
724
|
+
hasClient: !!client,
|
|
725
|
+
agentStatus: agentResult.status,
|
|
726
|
+
agentValue: agentResult.status === 'fulfilled' ? agentResult.value : (agentResult as any).reason?.message,
|
|
727
|
+
sessionStatus: sessionResult.status,
|
|
728
|
+
sessionValue: sessionResult.status === 'fulfilled' ? sessionResult.value : (sessionResult as any).reason?.message,
|
|
729
|
+
};
|
|
726
730
|
const sessions = sessionResult.status === 'fulfilled' ? sessionResult.value.candidates.map(candidate => {
|
|
727
731
|
const match = /^\[([^\]]+)\]\s*/.exec(candidate.title ?? '');
|
|
728
732
|
return { id: candidate.nativeSessionId, title: (candidate.title ?? '未命名会话').replace(/^\[[^\]]+\]\s*/, ''), harnessId: match?.[1] ?? 'codex', cwd: candidate.cwd, running: candidate.running };
|
|
@@ -744,12 +748,12 @@ export function installRendererBindingProbe(
|
|
|
744
748
|
const settingsLifecycle = installRendererSettingsLifecycle(window, {
|
|
745
749
|
getUpdateClient: () => modelControl,
|
|
746
750
|
getAccountClient: () => modelControl,
|
|
747
|
-
getConnectionDiagnostics: () => connectionDiagnostics,
|
|
748
|
-
getIntegrationsClient: () => {
|
|
749
|
-
const client = modelClientForHost('local');
|
|
750
|
-
if (!client?.integrationCatalog || !client.listIntegrations || !client.saveMcp || !client.removeMcp || !client.changeSkill) return null;
|
|
751
|
-
return { integrationCatalog: () => client.integrationCatalog!(), listIntegrations: input => client.listIntegrations!(input), saveMcp: input => client.saveMcp!(input), removeMcp: input => client.removeMcp!(input), changeSkill: input => client.changeSkill!(input) };
|
|
752
|
-
},
|
|
751
|
+
getConnectionDiagnostics: () => connectionDiagnostics,
|
|
752
|
+
getIntegrationsClient: () => {
|
|
753
|
+
const client = modelClientForHost('local');
|
|
754
|
+
if (!client?.integrationCatalog || !client.listIntegrations || !client.saveMcp || !client.removeMcp || !client.changeSkill) return null;
|
|
755
|
+
return { integrationCatalog: () => client.integrationCatalog!(), listIntegrations: input => client.listIntegrations!(input), saveMcp: input => client.saveMcp!(input), removeMcp: input => client.removeMcp!(input), changeSkill: input => client.changeSkill!(input) };
|
|
756
|
+
},
|
|
753
757
|
getSessionImportClient: () => {
|
|
754
758
|
const client = modelClientForHost("local");
|
|
755
759
|
const sources = client?.listSessionImportSources;
|
|
@@ -824,33 +828,8 @@ export function installRendererBindingProbe(
|
|
|
824
828
|
}
|
|
825
829
|
return state.codexAccounts;
|
|
826
830
|
};
|
|
827
|
-
const composerCodexAccounts = (composer: Element): RendererCodexAccountState | null =>
|
|
828
|
-
codexAccountsForHost(mountedByComposer.get(composer)?.hostId ?? null);
|
|
829
|
-
const chatGptContext = installChatGptContextBridge({
|
|
830
|
-
locale: () => settingsLifecycle.locale,
|
|
831
|
-
resolveTarget: (panel) => {
|
|
832
|
-
const mounted = [...mountedByComposer.values()].filter(
|
|
833
|
-
(candidate) =>
|
|
834
|
-
candidate.composer.isConnected &&
|
|
835
|
-
candidate.control.root.isConnected &&
|
|
836
|
-
!panel.contains(candidate.composer),
|
|
837
|
-
).at(-1);
|
|
838
|
-
if (!mounted) return null;
|
|
839
|
-
const editor = mounted.composer.querySelector<HTMLElement>(EDITOR_SELECTOR);
|
|
840
|
-
if (!editor) return null;
|
|
841
|
-
const state = controller.get(mounted.composer);
|
|
842
|
-
if (state.agent !== "codex") return { editor, kind: "harness", label: state.agent };
|
|
843
|
-
const accounts = composerCodexAccounts(mounted.composer);
|
|
844
|
-
const selectedId = accounts?.selection.selectedAccountId;
|
|
845
|
-
const account = accounts?.accounts.find((candidate) => candidate.accountId === selectedId);
|
|
846
|
-
return {
|
|
847
|
-
editor,
|
|
848
|
-
kind: "codex",
|
|
849
|
-
label: "Codex",
|
|
850
|
-
...(account ? { accountLabel: account.email ?? account.label } : {}),
|
|
851
|
-
};
|
|
852
|
-
},
|
|
853
|
-
});
|
|
831
|
+
const composerCodexAccounts = (composer: Element): RendererCodexAccountState | null =>
|
|
832
|
+
codexAccountsForHost(mountedByComposer.get(composer)?.hostId ?? null);
|
|
854
833
|
let activeAvailabilityHostId = "local";
|
|
855
834
|
const activeHarnessAvailabilityState = (): HostHarnessAvailabilityState =>
|
|
856
835
|
hostHarnessAvailabilityState(activeAvailabilityHostId);
|
|
@@ -907,7 +886,7 @@ export function installRendererBindingProbe(
|
|
|
907
886
|
);
|
|
908
887
|
};
|
|
909
888
|
|
|
910
|
-
const renderMounted = (mounted: MountedComposer): void => {
|
|
889
|
+
const renderMounted = (mounted: MountedComposer): void => {
|
|
911
890
|
const state = controller.get(mounted.composer);
|
|
912
891
|
const accounts = composerCodexAccounts(mounted.composer);
|
|
913
892
|
const selectedCodexAccountId =
|
|
@@ -919,10 +898,10 @@ export function installRendererBindingProbe(
|
|
|
919
898
|
mounted.control,
|
|
920
899
|
controller.get(mounted.composer),
|
|
921
900
|
adapterStatus.state,
|
|
922
|
-
accounts?.switching === true ||
|
|
923
|
-
controller.isSwitching(mounted.composer) ||
|
|
924
|
-
mounted.harnessSwitching ||
|
|
925
|
-
mounted.ownershipStatus === "loading",
|
|
901
|
+
accounts?.switching === true ||
|
|
902
|
+
controller.isSwitching(mounted.composer) ||
|
|
903
|
+
mounted.harnessSwitching ||
|
|
904
|
+
mounted.ownershipStatus === "loading",
|
|
926
905
|
activeHarnessAvailabilityState().availability,
|
|
927
906
|
mounted.modelView,
|
|
928
907
|
mounted.permissionModeView,
|
|
@@ -1207,7 +1186,7 @@ export function installRendererBindingProbe(
|
|
|
1207
1186
|
);
|
|
1208
1187
|
};
|
|
1209
1188
|
|
|
1210
|
-
const loadThreadOwnership = async (mounted: MountedComposer): Promise<void> => {
|
|
1189
|
+
const loadThreadOwnership = async (mounted: MountedComposer): Promise<void> => {
|
|
1211
1190
|
const threadId = threadIdFromComposerModelTarget(mounted.modelTarget);
|
|
1212
1191
|
if (!threadId) {
|
|
1213
1192
|
mounted.ownershipStatus = "not-required";
|
|
@@ -1298,70 +1277,70 @@ export function installRendererBindingProbe(
|
|
|
1298
1277
|
}
|
|
1299
1278
|
}
|
|
1300
1279
|
}
|
|
1301
|
-
};
|
|
1302
|
-
|
|
1303
|
-
const handoffComposerThread = async (
|
|
1304
|
-
mounted: MountedComposer,
|
|
1305
|
-
request: RendererHarnessHandoffRequest,
|
|
1306
|
-
): Promise<void> => {
|
|
1307
|
-
const threadId = threadIdFromComposerModelTarget(mounted.modelTarget);
|
|
1308
|
-
const current = controller.get(mounted.composer);
|
|
1309
|
-
if (
|
|
1310
|
-
!threadId ||
|
|
1311
|
-
current.phase !== "locked" ||
|
|
1312
|
-
current.agent === "codex" ||
|
|
1313
|
-
current.agent !== request.from ||
|
|
1314
|
-
request.to === current.agent ||
|
|
1315
|
-
mounted.harnessSwitching
|
|
1316
|
-
) {
|
|
1317
|
-
return;
|
|
1318
|
-
}
|
|
1319
|
-
const client = modelClientForHostFrom(modelControl, mounted.hostId);
|
|
1320
|
-
if (!client?.switchHarness) {
|
|
1321
|
-
mounted.control.harnessHandoff.showError(
|
|
1322
|
-
settingsLifecycle.locale === "zh-CN" ? "当前任务无法使用 Harness 接力。" : "Harness handoff is unavailable for this task.",
|
|
1323
|
-
);
|
|
1324
|
-
return;
|
|
1325
|
-
}
|
|
1326
|
-
mounted.harnessSwitching = true;
|
|
1327
|
-
mounted.control.harnessHandoff.setSubmitting(true);
|
|
1328
|
-
renderMounted(mounted);
|
|
1329
|
-
try {
|
|
1330
|
-
await client.switchHarness({
|
|
1331
|
-
threadId,
|
|
1332
|
-
harnessId: externalHarnessIds[request.to],
|
|
1333
|
-
...(request.note ? { note: request.note } : {}),
|
|
1334
|
-
intent: request.intent,
|
|
1335
|
-
includes: request.includes,
|
|
1336
|
-
});
|
|
1337
|
-
if (
|
|
1338
|
-
disposed ||
|
|
1339
|
-
mountedByComposer.get(mounted.composer) !== mounted ||
|
|
1340
|
-
threadIdFromComposerModelTarget(mounted.modelTarget) !== threadId
|
|
1341
|
-
) {
|
|
1342
|
-
return;
|
|
1343
|
-
}
|
|
1344
|
-
mounted.harnessSwitching = false;
|
|
1345
|
-
mounted.control.harnessHandoff.setSubmitting(false);
|
|
1346
|
-
mounted.control.harnessHandoff.close();
|
|
1347
|
-
mounted.modelView = { status: "loading" };
|
|
1348
|
-
mounted.permissionModeView = { status: "loading" };
|
|
1349
|
-
mounted.threadConfiguration = undefined;
|
|
1350
|
-
mounted.usage = null;
|
|
1351
|
-
mounted.accountCredits = null;
|
|
1352
|
-
await loadThreadOwnership(mounted);
|
|
1353
|
-
} catch (error) {
|
|
1354
|
-
mounted.control.harnessHandoff.showError(
|
|
1355
|
-
error instanceof Error ? error.message : String(error),
|
|
1356
|
-
);
|
|
1357
|
-
} finally {
|
|
1358
|
-
if (mountedByComposer.get(mounted.composer) === mounted) {
|
|
1359
|
-
mounted.harnessSwitching = false;
|
|
1360
|
-
mounted.control.harnessHandoff.setSubmitting(false);
|
|
1361
|
-
renderMounted(mounted);
|
|
1362
|
-
}
|
|
1363
|
-
}
|
|
1364
|
-
};
|
|
1280
|
+
};
|
|
1281
|
+
|
|
1282
|
+
const handoffComposerThread = async (
|
|
1283
|
+
mounted: MountedComposer,
|
|
1284
|
+
request: RendererHarnessHandoffRequest,
|
|
1285
|
+
): Promise<void> => {
|
|
1286
|
+
const threadId = threadIdFromComposerModelTarget(mounted.modelTarget);
|
|
1287
|
+
const current = controller.get(mounted.composer);
|
|
1288
|
+
if (
|
|
1289
|
+
!threadId ||
|
|
1290
|
+
current.phase !== "locked" ||
|
|
1291
|
+
current.agent === "codex" ||
|
|
1292
|
+
current.agent !== request.from ||
|
|
1293
|
+
request.to === current.agent ||
|
|
1294
|
+
mounted.harnessSwitching
|
|
1295
|
+
) {
|
|
1296
|
+
return;
|
|
1297
|
+
}
|
|
1298
|
+
const client = modelClientForHostFrom(modelControl, mounted.hostId);
|
|
1299
|
+
if (!client?.switchHarness) {
|
|
1300
|
+
mounted.control.harnessHandoff.showError(
|
|
1301
|
+
settingsLifecycle.locale === "zh-CN" ? "当前任务无法使用 Harness 接力。" : "Harness handoff is unavailable for this task.",
|
|
1302
|
+
);
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1305
|
+
mounted.harnessSwitching = true;
|
|
1306
|
+
mounted.control.harnessHandoff.setSubmitting(true);
|
|
1307
|
+
renderMounted(mounted);
|
|
1308
|
+
try {
|
|
1309
|
+
await client.switchHarness({
|
|
1310
|
+
threadId,
|
|
1311
|
+
harnessId: externalHarnessIds[request.to],
|
|
1312
|
+
...(request.note ? { note: request.note } : {}),
|
|
1313
|
+
intent: request.intent,
|
|
1314
|
+
includes: request.includes,
|
|
1315
|
+
});
|
|
1316
|
+
if (
|
|
1317
|
+
disposed ||
|
|
1318
|
+
mountedByComposer.get(mounted.composer) !== mounted ||
|
|
1319
|
+
threadIdFromComposerModelTarget(mounted.modelTarget) !== threadId
|
|
1320
|
+
) {
|
|
1321
|
+
return;
|
|
1322
|
+
}
|
|
1323
|
+
mounted.harnessSwitching = false;
|
|
1324
|
+
mounted.control.harnessHandoff.setSubmitting(false);
|
|
1325
|
+
mounted.control.harnessHandoff.close();
|
|
1326
|
+
mounted.modelView = { status: "loading" };
|
|
1327
|
+
mounted.permissionModeView = { status: "loading" };
|
|
1328
|
+
mounted.threadConfiguration = undefined;
|
|
1329
|
+
mounted.usage = null;
|
|
1330
|
+
mounted.accountCredits = null;
|
|
1331
|
+
await loadThreadOwnership(mounted);
|
|
1332
|
+
} catch (error) {
|
|
1333
|
+
mounted.control.harnessHandoff.showError(
|
|
1334
|
+
error instanceof Error ? error.message : String(error),
|
|
1335
|
+
);
|
|
1336
|
+
} finally {
|
|
1337
|
+
if (mountedByComposer.get(mounted.composer) === mounted) {
|
|
1338
|
+
mounted.harnessSwitching = false;
|
|
1339
|
+
mounted.control.harnessHandoff.setSubmitting(false);
|
|
1340
|
+
renderMounted(mounted);
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
};
|
|
1365
1344
|
|
|
1366
1345
|
const refreshMountedConversationTarget = (mounted: MountedComposer): boolean => {
|
|
1367
1346
|
const currentTarget = findComposerModelTarget(mounted.composer);
|
|
@@ -2199,9 +2178,9 @@ export function installRendererBindingProbe(
|
|
|
2199
2178
|
await policy.clear();
|
|
2200
2179
|
if (!isCurrent() || window.__codexhostDraftPrewarmPolicyV1 !== policy) return;
|
|
2201
2180
|
if (!policy.selectAccount) throw new Error("Codex Account selection is unavailable");
|
|
2202
|
-
policy.selectAccount(codexAccountRouteOverride(accounts.accounts, accountId));
|
|
2203
|
-
accounts.overrideAccountId =
|
|
2204
|
-
accountId === accounts.selection.activeAccountId ? null : accountId;
|
|
2181
|
+
policy.selectAccount(codexAccountRouteOverride(accounts.accounts, accountId));
|
|
2182
|
+
accounts.overrideAccountId =
|
|
2183
|
+
accountId === accounts.selection.activeAccountId ? null : accountId;
|
|
2205
2184
|
} catch {
|
|
2206
2185
|
if (isCurrent()) void loadCodexAccounts();
|
|
2207
2186
|
} finally {
|
|
@@ -2537,17 +2516,17 @@ export function installRendererBindingProbe(
|
|
|
2537
2516
|
state.composerId,
|
|
2538
2517
|
sendButton,
|
|
2539
2518
|
enabledAgents,
|
|
2540
|
-
(agent) => {
|
|
2541
|
-
const mounted = mountedByComposer.get(composer);
|
|
2542
|
-
if (!composer.isConnected || !mounted) return;
|
|
2543
|
-
const current = controller.get(composer);
|
|
2544
|
-
if (current.phase === "locked") {
|
|
2545
|
-
if (current.agent !== "codex" && agent !== "codex") {
|
|
2546
|
-
mounted.control.harnessHandoff.open(current.agent, agent, settingsLifecycle.locale);
|
|
2547
|
-
}
|
|
2548
|
-
return;
|
|
2549
|
-
}
|
|
2550
|
-
void switchComposerAgent(mounted, agent);
|
|
2519
|
+
(agent) => {
|
|
2520
|
+
const mounted = mountedByComposer.get(composer);
|
|
2521
|
+
if (!composer.isConnected || !mounted) return;
|
|
2522
|
+
const current = controller.get(composer);
|
|
2523
|
+
if (current.phase === "locked") {
|
|
2524
|
+
if (current.agent !== "codex" && agent !== "codex") {
|
|
2525
|
+
mounted.control.harnessHandoff.open(current.agent, agent, settingsLifecycle.locale);
|
|
2526
|
+
}
|
|
2527
|
+
return;
|
|
2528
|
+
}
|
|
2529
|
+
void switchComposerAgent(mounted, agent);
|
|
2551
2530
|
},
|
|
2552
2531
|
openInstallPage,
|
|
2553
2532
|
async (accountId) => {
|
|
@@ -2573,16 +2552,16 @@ export function installRendererBindingProbe(
|
|
|
2573
2552
|
if (!composer.isConnected || !mounted) return;
|
|
2574
2553
|
void selectPermissionMode(mounted, permissionModeId);
|
|
2575
2554
|
},
|
|
2576
|
-
(command) => {
|
|
2577
|
-
const mounted = mountedByComposer.get(composer);
|
|
2578
|
-
if (mounted) selectCommand(mounted, command);
|
|
2579
|
-
},
|
|
2580
|
-
(request) => {
|
|
2581
|
-
const mounted = mountedByComposer.get(composer);
|
|
2582
|
-
if (!composer.isConnected || !mounted) return;
|
|
2583
|
-
void handoffComposerThread(mounted, request);
|
|
2584
|
-
},
|
|
2585
|
-
);
|
|
2555
|
+
(command) => {
|
|
2556
|
+
const mounted = mountedByComposer.get(composer);
|
|
2557
|
+
if (mounted) selectCommand(mounted, command);
|
|
2558
|
+
},
|
|
2559
|
+
(request) => {
|
|
2560
|
+
const mounted = mountedByComposer.get(composer);
|
|
2561
|
+
if (!composer.isConnected || !mounted) return;
|
|
2562
|
+
void handoffComposerThread(mounted, request);
|
|
2563
|
+
},
|
|
2564
|
+
);
|
|
2586
2565
|
const mounted: MountedComposer = {
|
|
2587
2566
|
composer,
|
|
2588
2567
|
composerId: state.composerId,
|
|
@@ -2600,9 +2579,9 @@ export function installRendererBindingProbe(
|
|
|
2600
2579
|
accountCredits: inherited?.accountCredits ?? null,
|
|
2601
2580
|
hostId: inherited?.hostId ?? hostId,
|
|
2602
2581
|
usageRequestGeneration: 0,
|
|
2603
|
-
commandRequestGeneration: 0,
|
|
2604
|
-
harnessSwitching: false,
|
|
2605
|
-
};
|
|
2582
|
+
commandRequestGeneration: 0,
|
|
2583
|
+
harnessSwitching: false,
|
|
2584
|
+
};
|
|
2606
2585
|
mountedByComposer.set(composer, mounted);
|
|
2607
2586
|
if (isComposerModelWriteAllowed(modelTarget)) {
|
|
2608
2587
|
const model = controller.modelForAgent(composer, state.agent);
|
|
@@ -2811,10 +2790,10 @@ export function installRendererBindingProbe(
|
|
|
2811
2790
|
controller.isSubmissionPending(composer) && current.codexAccountId
|
|
2812
2791
|
? current.codexAccountId
|
|
2813
2792
|
: selection?.selectedAccountId;
|
|
2814
|
-
const override = codexAccountRouteOverride(
|
|
2815
|
-
composerCodexAccounts(composer)?.accounts ?? [],
|
|
2816
|
-
accountId,
|
|
2817
|
-
);
|
|
2793
|
+
const override = codexAccountRouteOverride(
|
|
2794
|
+
composerCodexAccounts(composer)?.accounts ?? [],
|
|
2795
|
+
accountId,
|
|
2796
|
+
);
|
|
2818
2797
|
const policy = window.__codexhostDraftPrewarmPolicyV1;
|
|
2819
2798
|
if (override !== null && (policy?.hostId !== mounted.hostId || !policy.selectAccount)) {
|
|
2820
2799
|
return false;
|
|
@@ -2841,9 +2820,9 @@ export function installRendererBindingProbe(
|
|
|
2841
2820
|
controller.clearPendingSubmission(composer);
|
|
2842
2821
|
const mounted = mountedByComposer.get(composer);
|
|
2843
2822
|
if (mounted && isOwnershipSubmissionBlocked(mounted.ownershipStatus)) return;
|
|
2844
|
-
// Draft editing must remain available while the native connection recovers.
|
|
2845
|
-
// Submission still goes through prepareComposer and fails closed.
|
|
2846
|
-
if (!controller.isSwitching(composer)) applyComposerAgent(composer);
|
|
2823
|
+
// Draft editing must remain available while the native connection recovers.
|
|
2824
|
+
// Submission still goes through prepareComposer and fails closed.
|
|
2825
|
+
if (!controller.isSwitching(composer)) applyComposerAgent(composer);
|
|
2847
2826
|
};
|
|
2848
2827
|
const onSubmit = (event: Event): void => {
|
|
2849
2828
|
const element = eventElement(event.target);
|
|
@@ -2851,9 +2830,9 @@ export function installRendererBindingProbe(
|
|
|
2851
2830
|
const composer = candidate && isMountedComposer(candidate) ? candidate : null;
|
|
2852
2831
|
if (!composer) return;
|
|
2853
2832
|
const prepared = prepareComposer(composer);
|
|
2854
|
-
if (prepared === null) return;
|
|
2855
|
-
if (!prepared) {
|
|
2856
|
-
blockEvent(event);
|
|
2833
|
+
if (prepared === null) return;
|
|
2834
|
+
if (!prepared) {
|
|
2835
|
+
blockEvent(event);
|
|
2857
2836
|
return;
|
|
2858
2837
|
}
|
|
2859
2838
|
notifySubmission(composer, "submit");
|
|
@@ -2862,20 +2841,20 @@ export function installRendererBindingProbe(
|
|
|
2862
2841
|
const composer = isComposerInputIntent(event) ? composerForTarget(event.target) : null;
|
|
2863
2842
|
const mounted = composer ? mountedByComposer.get(composer) : undefined;
|
|
2864
2843
|
if (
|
|
2865
|
-
composer &&
|
|
2866
|
-
(composerCodexAccounts(composer)?.switching ||
|
|
2867
|
-
controller.isSwitching(composer) ||
|
|
2868
|
-
mounted?.harnessSwitching)
|
|
2869
|
-
) {
|
|
2870
|
-
if (isComposerSubmissionKey(event)) blockEvent(event);
|
|
2844
|
+
composer &&
|
|
2845
|
+
(composerCodexAccounts(composer)?.switching ||
|
|
2846
|
+
controller.isSwitching(composer) ||
|
|
2847
|
+
mounted?.harnessSwitching)
|
|
2848
|
+
) {
|
|
2849
|
+
if (isComposerSubmissionKey(event)) blockEvent(event);
|
|
2871
2850
|
return;
|
|
2872
2851
|
}
|
|
2873
2852
|
if (composer && mounted && isOwnershipSubmissionBlocked(mounted.ownershipStatus)) {
|
|
2874
2853
|
if (isComposerSubmissionKey(event)) blockEvent(event);
|
|
2875
2854
|
return;
|
|
2876
2855
|
}
|
|
2877
|
-
if (composer && !applyComposerAgent(composer)) {
|
|
2878
|
-
if (isComposerSubmissionKey(event)) blockEvent(event);
|
|
2856
|
+
if (composer && !applyComposerAgent(composer)) {
|
|
2857
|
+
if (isComposerSubmissionKey(event)) blockEvent(event);
|
|
2879
2858
|
return;
|
|
2880
2859
|
}
|
|
2881
2860
|
if (!isComposerSubmissionKey(event) || !composer) return;
|
|
@@ -3084,11 +3063,10 @@ export function installRendererBindingProbe(
|
|
|
3084
3063
|
applyAdapterAgent = null;
|
|
3085
3064
|
modelControl = null;
|
|
3086
3065
|
mutationObserver.disconnect();
|
|
3087
|
-
sidebarAgentIcons.dispose();
|
|
3088
|
-
harnessMentions.dispose();
|
|
3089
|
-
collabCards.dispose();
|
|
3090
|
-
|
|
3091
|
-
settingsLifecycle.dispose();
|
|
3066
|
+
sidebarAgentIcons.dispose();
|
|
3067
|
+
harnessMentions.dispose();
|
|
3068
|
+
collabCards.dispose();
|
|
3069
|
+
settingsLifecycle.dispose();
|
|
3092
3070
|
document.removeEventListener("beforeinput", onBeforeInput, true);
|
|
3093
3071
|
document.removeEventListener("submit", onSubmit, true);
|
|
3094
3072
|
document.removeEventListener("keydown", onKeyDown, true);
|
|
@@ -44,7 +44,11 @@ export function buildChatGptContextDraft(capture: ChatGptContextCapture): string
|
|
|
44
44
|
return `${header.join("\n")}\n${body.length > available ? body.slice(body.length - available) : body}${suffix}`;
|
|
45
45
|
}
|
|
46
46
|
function elementDescription(element: Element): string { return [element.getAttribute("placeholder"), element.getAttribute("aria-label"), element.getAttribute("title"), element.getAttribute("data-testid")].filter((value): value is string => typeof value === "string").join(" "); }
|
|
47
|
-
export function isChatGptQuickChatEditor(element: Element): boolean {
|
|
47
|
+
export function isChatGptQuickChatEditor(element: Element): boolean {
|
|
48
|
+
const candidate = element as Element & { matches?: unknown; getAttribute?: unknown };
|
|
49
|
+
if (typeof candidate.matches !== "function" || typeof candidate.getAttribute !== "function") return false;
|
|
50
|
+
return candidate.matches('textarea, [contenteditable="true"], [role="textbox"]') && CHATGPT_EDITOR_PATTERN.test(elementDescription(candidate));
|
|
51
|
+
}
|
|
48
52
|
function directText(element: Element): string { return compactText([...element.childNodes].filter((node) => node.nodeType === Node.TEXT_NODE).map((node) => node.textContent ?? "").join(" ")); }
|
|
49
53
|
function titleElementWithin(root: Element): Element | null { return [...root.querySelectorAll("h1,h2,h3,h4,[role=heading],span,div")].find((element) => CHAT_TITLE_PATTERN.test(directText(element))) ?? null; }
|
|
50
54
|
export function findChatGptQuickChatPanel(editor: Element): Element | null {
|