@harness-mix/cli 0.1.5 → 0.1.7
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 +86 -56
- package/docs/harness-management.md +4 -4
- package/docs/multi-agent-collaboration.md +9 -9
- package/docs/storage-verification-design.md +49 -0
- package/output/native-build/renderer-extension.js +4210 -2273
- package/package.json +11 -9
- package/scripts/codebuddy-migration-test.cjs +1 -1
- package/scripts/collaboration-test.cjs +8 -3
- package/scripts/collaboration-ui-smoke.cjs +40 -26
- package/scripts/core-runtime-test.cjs +9 -1
- package/scripts/integrations-test.cjs +63 -4
- package/scripts/integrations-ui-smoke.cjs +77 -16
- package/scripts/native-protocol-test.cjs +113 -2
- package/scripts/native-sidebar-test.cjs +7 -0
- package/scripts/native-skill-roots-test.cjs +90 -0
- package/scripts/native-ui-smoke.cjs +23 -4
- package/scripts/projector-test.cjs +13 -0
- package/scripts/storage-verification-test.cjs +78 -0
- package/scripts/switch-harness-test.cjs +1 -1
- 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 +59 -11
- package/src/main/host/core-session.js +7 -1
- package/src/main/host/handoff-checkpoints.js +8 -1
- package/src/main/host/integrations.js +164 -26
- package/src/main/host/runtime.js +270 -116
- package/src/main/host/store.js +32 -11
- package/src/main/host/thread-storage.js +73 -0
- package/src/main/host/thread-store.js +123 -0
- package/src/main/host/verification-gates.js +118 -0
- package/src/main/native/protocol.js +209 -83
- package/src/main/native/thread-list.js +3 -0
- package/src/main/protocol-core/projector.js +20 -3
- package/src/main/shared-contracts/event.js +2 -1
- package/src/main/shared-contracts/item.js +1 -0
- package/src/native-ui/renderer-extension/dist/types/harness-mix-settings.d.ts +2 -2
- 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/renderer-model-client.d.ts +5 -0
- 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 +2 -1
- 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/icons.d.ts +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/icons.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 +5 -3
- package/src/native-ui/renderer-extension/dist/types/settings/pages.d.ts.map +1 -1
- package/src/native-ui/renderer-extension/dist/types/settings/storage-page.d.ts +20 -0
- package/src/native-ui/renderer-extension/dist/types/settings/storage-page.d.ts.map +1 -0
- package/src/native-ui/renderer-extension/dist/types/tsconfig.tsbuildinfo +1 -1
- package/src/native-ui/renderer-extension/src/harness-mix-settings.ts +8 -88
- package/src/native-ui/renderer-extension/src/renderer-binding-probe.ts +150 -168
- 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/renderer-model-client.ts +4 -0
- package/src/native-ui/renderer-extension/src/renderer-settings-lifecycle.ts +12 -0
- package/src/native-ui/renderer-extension/src/settings/icons.ts +6 -3
- package/src/native-ui/renderer-extension/src/settings/integrations-page.ts +1434 -62
- package/src/native-ui/renderer-extension/src/settings/localization.ts +8 -4
- package/src/native-ui/renderer-extension/src/settings/pages.ts +17 -8
- package/src/native-ui/renderer-extension/src/settings/shell.css +103 -8
- package/src/native-ui/renderer-extension/src/settings/storage-page.ts +74 -0
- package/src/native-ui/renderer-extension/test/renderer-chatgpt-context.test.ts +4 -1
- package/src/native-ui/renderer-extension/test/renderer-model-client.test.ts +2 -0
- package/src/native-ui/renderer-extension/test/settings/harness-settings.test.ts +5 -0
- package/src/native-ui/renderer-extension/test/settings/localization.test.ts +1 -1
- package/src/native-ui/renderer-extension/test/settings/pages.test.ts +50 -4
- package/src/native-ui/renderer-extension/test/settings/shell.test.ts +8 -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 };
|
|
@@ -745,11 +749,15 @@ export function installRendererBindingProbe(
|
|
|
745
749
|
getUpdateClient: () => modelControl,
|
|
746
750
|
getAccountClient: () => modelControl,
|
|
747
751
|
getConnectionDiagnostics: () => connectionDiagnostics,
|
|
748
|
-
|
|
752
|
+
getStorageClient: () => {
|
|
749
753
|
const client = modelClientForHost('local');
|
|
750
|
-
|
|
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) };
|
|
754
|
+
return client?.inspectStorage && client.optimizeStorage ? { inspectStorage: () => client.inspectStorage!(), optimizeStorage: () => client.optimizeStorage!() } : null;
|
|
752
755
|
},
|
|
756
|
+
getIntegrationsClient: () => {
|
|
757
|
+
const client = modelClientForHost('local');
|
|
758
|
+
if (!client?.integrationCatalog || !client.listIntegrations || !client.saveMcp || !client.removeMcp || !client.changeSkill) return null;
|
|
759
|
+
return { integrationCatalog: () => client.integrationCatalog!(), listIntegrations: input => client.listIntegrations!(input), saveMcp: input => client.saveMcp!(input), removeMcp: input => client.removeMcp!(input), changeSkill: input => client.changeSkill!(input) };
|
|
760
|
+
},
|
|
753
761
|
getSessionImportClient: () => {
|
|
754
762
|
const client = modelClientForHost("local");
|
|
755
763
|
const sources = client?.listSessionImportSources;
|
|
@@ -824,33 +832,8 @@ export function installRendererBindingProbe(
|
|
|
824
832
|
}
|
|
825
833
|
return state.codexAccounts;
|
|
826
834
|
};
|
|
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
|
-
});
|
|
835
|
+
const composerCodexAccounts = (composer: Element): RendererCodexAccountState | null =>
|
|
836
|
+
codexAccountsForHost(mountedByComposer.get(composer)?.hostId ?? null);
|
|
854
837
|
let activeAvailabilityHostId = "local";
|
|
855
838
|
const activeHarnessAvailabilityState = (): HostHarnessAvailabilityState =>
|
|
856
839
|
hostHarnessAvailabilityState(activeAvailabilityHostId);
|
|
@@ -907,7 +890,7 @@ export function installRendererBindingProbe(
|
|
|
907
890
|
);
|
|
908
891
|
};
|
|
909
892
|
|
|
910
|
-
const renderMounted = (mounted: MountedComposer): void => {
|
|
893
|
+
const renderMounted = (mounted: MountedComposer): void => {
|
|
911
894
|
const state = controller.get(mounted.composer);
|
|
912
895
|
const accounts = composerCodexAccounts(mounted.composer);
|
|
913
896
|
const selectedCodexAccountId =
|
|
@@ -919,10 +902,10 @@ export function installRendererBindingProbe(
|
|
|
919
902
|
mounted.control,
|
|
920
903
|
controller.get(mounted.composer),
|
|
921
904
|
adapterStatus.state,
|
|
922
|
-
accounts?.switching === true ||
|
|
923
|
-
controller.isSwitching(mounted.composer) ||
|
|
924
|
-
mounted.harnessSwitching ||
|
|
925
|
-
mounted.ownershipStatus === "loading",
|
|
905
|
+
accounts?.switching === true ||
|
|
906
|
+
controller.isSwitching(mounted.composer) ||
|
|
907
|
+
mounted.harnessSwitching ||
|
|
908
|
+
mounted.ownershipStatus === "loading",
|
|
926
909
|
activeHarnessAvailabilityState().availability,
|
|
927
910
|
mounted.modelView,
|
|
928
911
|
mounted.permissionModeView,
|
|
@@ -1207,7 +1190,7 @@ export function installRendererBindingProbe(
|
|
|
1207
1190
|
);
|
|
1208
1191
|
};
|
|
1209
1192
|
|
|
1210
|
-
const loadThreadOwnership = async (mounted: MountedComposer): Promise<void> => {
|
|
1193
|
+
const loadThreadOwnership = async (mounted: MountedComposer): Promise<void> => {
|
|
1211
1194
|
const threadId = threadIdFromComposerModelTarget(mounted.modelTarget);
|
|
1212
1195
|
if (!threadId) {
|
|
1213
1196
|
mounted.ownershipStatus = "not-required";
|
|
@@ -1298,70 +1281,70 @@ export function installRendererBindingProbe(
|
|
|
1298
1281
|
}
|
|
1299
1282
|
}
|
|
1300
1283
|
}
|
|
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
|
-
};
|
|
1284
|
+
};
|
|
1285
|
+
|
|
1286
|
+
const handoffComposerThread = async (
|
|
1287
|
+
mounted: MountedComposer,
|
|
1288
|
+
request: RendererHarnessHandoffRequest,
|
|
1289
|
+
): Promise<void> => {
|
|
1290
|
+
const threadId = threadIdFromComposerModelTarget(mounted.modelTarget);
|
|
1291
|
+
const current = controller.get(mounted.composer);
|
|
1292
|
+
if (
|
|
1293
|
+
!threadId ||
|
|
1294
|
+
current.phase !== "locked" ||
|
|
1295
|
+
current.agent === "codex" ||
|
|
1296
|
+
current.agent !== request.from ||
|
|
1297
|
+
request.to === current.agent ||
|
|
1298
|
+
mounted.harnessSwitching
|
|
1299
|
+
) {
|
|
1300
|
+
return;
|
|
1301
|
+
}
|
|
1302
|
+
const client = modelClientForHostFrom(modelControl, mounted.hostId);
|
|
1303
|
+
if (!client?.switchHarness) {
|
|
1304
|
+
mounted.control.harnessHandoff.showError(
|
|
1305
|
+
settingsLifecycle.locale === "zh-CN" ? "当前任务无法使用 Harness 接力。" : "Harness handoff is unavailable for this task.",
|
|
1306
|
+
);
|
|
1307
|
+
return;
|
|
1308
|
+
}
|
|
1309
|
+
mounted.harnessSwitching = true;
|
|
1310
|
+
mounted.control.harnessHandoff.setSubmitting(true);
|
|
1311
|
+
renderMounted(mounted);
|
|
1312
|
+
try {
|
|
1313
|
+
await client.switchHarness({
|
|
1314
|
+
threadId,
|
|
1315
|
+
harnessId: externalHarnessIds[request.to],
|
|
1316
|
+
...(request.note ? { note: request.note } : {}),
|
|
1317
|
+
intent: request.intent,
|
|
1318
|
+
includes: request.includes,
|
|
1319
|
+
});
|
|
1320
|
+
if (
|
|
1321
|
+
disposed ||
|
|
1322
|
+
mountedByComposer.get(mounted.composer) !== mounted ||
|
|
1323
|
+
threadIdFromComposerModelTarget(mounted.modelTarget) !== threadId
|
|
1324
|
+
) {
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1327
|
+
mounted.harnessSwitching = false;
|
|
1328
|
+
mounted.control.harnessHandoff.setSubmitting(false);
|
|
1329
|
+
mounted.control.harnessHandoff.close();
|
|
1330
|
+
mounted.modelView = { status: "loading" };
|
|
1331
|
+
mounted.permissionModeView = { status: "loading" };
|
|
1332
|
+
mounted.threadConfiguration = undefined;
|
|
1333
|
+
mounted.usage = null;
|
|
1334
|
+
mounted.accountCredits = null;
|
|
1335
|
+
await loadThreadOwnership(mounted);
|
|
1336
|
+
} catch (error) {
|
|
1337
|
+
mounted.control.harnessHandoff.showError(
|
|
1338
|
+
error instanceof Error ? error.message : String(error),
|
|
1339
|
+
);
|
|
1340
|
+
} finally {
|
|
1341
|
+
if (mountedByComposer.get(mounted.composer) === mounted) {
|
|
1342
|
+
mounted.harnessSwitching = false;
|
|
1343
|
+
mounted.control.harnessHandoff.setSubmitting(false);
|
|
1344
|
+
renderMounted(mounted);
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
};
|
|
1365
1348
|
|
|
1366
1349
|
const refreshMountedConversationTarget = (mounted: MountedComposer): boolean => {
|
|
1367
1350
|
const currentTarget = findComposerModelTarget(mounted.composer);
|
|
@@ -2199,9 +2182,9 @@ export function installRendererBindingProbe(
|
|
|
2199
2182
|
await policy.clear();
|
|
2200
2183
|
if (!isCurrent() || window.__codexhostDraftPrewarmPolicyV1 !== policy) return;
|
|
2201
2184
|
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;
|
|
2185
|
+
policy.selectAccount(codexAccountRouteOverride(accounts.accounts, accountId));
|
|
2186
|
+
accounts.overrideAccountId =
|
|
2187
|
+
accountId === accounts.selection.activeAccountId ? null : accountId;
|
|
2205
2188
|
} catch {
|
|
2206
2189
|
if (isCurrent()) void loadCodexAccounts();
|
|
2207
2190
|
} finally {
|
|
@@ -2537,17 +2520,17 @@ export function installRendererBindingProbe(
|
|
|
2537
2520
|
state.composerId,
|
|
2538
2521
|
sendButton,
|
|
2539
2522
|
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);
|
|
2523
|
+
(agent) => {
|
|
2524
|
+
const mounted = mountedByComposer.get(composer);
|
|
2525
|
+
if (!composer.isConnected || !mounted) return;
|
|
2526
|
+
const current = controller.get(composer);
|
|
2527
|
+
if (current.phase === "locked") {
|
|
2528
|
+
if (current.agent !== "codex" && agent !== "codex") {
|
|
2529
|
+
mounted.control.harnessHandoff.open(current.agent, agent, settingsLifecycle.locale);
|
|
2530
|
+
}
|
|
2531
|
+
return;
|
|
2532
|
+
}
|
|
2533
|
+
void switchComposerAgent(mounted, agent);
|
|
2551
2534
|
},
|
|
2552
2535
|
openInstallPage,
|
|
2553
2536
|
async (accountId) => {
|
|
@@ -2573,16 +2556,16 @@ export function installRendererBindingProbe(
|
|
|
2573
2556
|
if (!composer.isConnected || !mounted) return;
|
|
2574
2557
|
void selectPermissionMode(mounted, permissionModeId);
|
|
2575
2558
|
},
|
|
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
|
-
);
|
|
2559
|
+
(command) => {
|
|
2560
|
+
const mounted = mountedByComposer.get(composer);
|
|
2561
|
+
if (mounted) selectCommand(mounted, command);
|
|
2562
|
+
},
|
|
2563
|
+
(request) => {
|
|
2564
|
+
const mounted = mountedByComposer.get(composer);
|
|
2565
|
+
if (!composer.isConnected || !mounted) return;
|
|
2566
|
+
void handoffComposerThread(mounted, request);
|
|
2567
|
+
},
|
|
2568
|
+
);
|
|
2586
2569
|
const mounted: MountedComposer = {
|
|
2587
2570
|
composer,
|
|
2588
2571
|
composerId: state.composerId,
|
|
@@ -2600,9 +2583,9 @@ export function installRendererBindingProbe(
|
|
|
2600
2583
|
accountCredits: inherited?.accountCredits ?? null,
|
|
2601
2584
|
hostId: inherited?.hostId ?? hostId,
|
|
2602
2585
|
usageRequestGeneration: 0,
|
|
2603
|
-
commandRequestGeneration: 0,
|
|
2604
|
-
harnessSwitching: false,
|
|
2605
|
-
};
|
|
2586
|
+
commandRequestGeneration: 0,
|
|
2587
|
+
harnessSwitching: false,
|
|
2588
|
+
};
|
|
2606
2589
|
mountedByComposer.set(composer, mounted);
|
|
2607
2590
|
if (isComposerModelWriteAllowed(modelTarget)) {
|
|
2608
2591
|
const model = controller.modelForAgent(composer, state.agent);
|
|
@@ -2811,10 +2794,10 @@ export function installRendererBindingProbe(
|
|
|
2811
2794
|
controller.isSubmissionPending(composer) && current.codexAccountId
|
|
2812
2795
|
? current.codexAccountId
|
|
2813
2796
|
: selection?.selectedAccountId;
|
|
2814
|
-
const override = codexAccountRouteOverride(
|
|
2815
|
-
composerCodexAccounts(composer)?.accounts ?? [],
|
|
2816
|
-
accountId,
|
|
2817
|
-
);
|
|
2797
|
+
const override = codexAccountRouteOverride(
|
|
2798
|
+
composerCodexAccounts(composer)?.accounts ?? [],
|
|
2799
|
+
accountId,
|
|
2800
|
+
);
|
|
2818
2801
|
const policy = window.__codexhostDraftPrewarmPolicyV1;
|
|
2819
2802
|
if (override !== null && (policy?.hostId !== mounted.hostId || !policy.selectAccount)) {
|
|
2820
2803
|
return false;
|
|
@@ -2841,9 +2824,9 @@ export function installRendererBindingProbe(
|
|
|
2841
2824
|
controller.clearPendingSubmission(composer);
|
|
2842
2825
|
const mounted = mountedByComposer.get(composer);
|
|
2843
2826
|
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);
|
|
2827
|
+
// Draft editing must remain available while the native connection recovers.
|
|
2828
|
+
// Submission still goes through prepareComposer and fails closed.
|
|
2829
|
+
if (!controller.isSwitching(composer)) applyComposerAgent(composer);
|
|
2847
2830
|
};
|
|
2848
2831
|
const onSubmit = (event: Event): void => {
|
|
2849
2832
|
const element = eventElement(event.target);
|
|
@@ -2851,9 +2834,9 @@ export function installRendererBindingProbe(
|
|
|
2851
2834
|
const composer = candidate && isMountedComposer(candidate) ? candidate : null;
|
|
2852
2835
|
if (!composer) return;
|
|
2853
2836
|
const prepared = prepareComposer(composer);
|
|
2854
|
-
if (prepared === null) return;
|
|
2855
|
-
if (!prepared) {
|
|
2856
|
-
blockEvent(event);
|
|
2837
|
+
if (prepared === null) return;
|
|
2838
|
+
if (!prepared) {
|
|
2839
|
+
blockEvent(event);
|
|
2857
2840
|
return;
|
|
2858
2841
|
}
|
|
2859
2842
|
notifySubmission(composer, "submit");
|
|
@@ -2862,20 +2845,20 @@ export function installRendererBindingProbe(
|
|
|
2862
2845
|
const composer = isComposerInputIntent(event) ? composerForTarget(event.target) : null;
|
|
2863
2846
|
const mounted = composer ? mountedByComposer.get(composer) : undefined;
|
|
2864
2847
|
if (
|
|
2865
|
-
composer &&
|
|
2866
|
-
(composerCodexAccounts(composer)?.switching ||
|
|
2867
|
-
controller.isSwitching(composer) ||
|
|
2868
|
-
mounted?.harnessSwitching)
|
|
2869
|
-
) {
|
|
2870
|
-
if (isComposerSubmissionKey(event)) blockEvent(event);
|
|
2848
|
+
composer &&
|
|
2849
|
+
(composerCodexAccounts(composer)?.switching ||
|
|
2850
|
+
controller.isSwitching(composer) ||
|
|
2851
|
+
mounted?.harnessSwitching)
|
|
2852
|
+
) {
|
|
2853
|
+
if (isComposerSubmissionKey(event)) blockEvent(event);
|
|
2871
2854
|
return;
|
|
2872
2855
|
}
|
|
2873
2856
|
if (composer && mounted && isOwnershipSubmissionBlocked(mounted.ownershipStatus)) {
|
|
2874
2857
|
if (isComposerSubmissionKey(event)) blockEvent(event);
|
|
2875
2858
|
return;
|
|
2876
2859
|
}
|
|
2877
|
-
if (composer && !applyComposerAgent(composer)) {
|
|
2878
|
-
if (isComposerSubmissionKey(event)) blockEvent(event);
|
|
2860
|
+
if (composer && !applyComposerAgent(composer)) {
|
|
2861
|
+
if (isComposerSubmissionKey(event)) blockEvent(event);
|
|
2879
2862
|
return;
|
|
2880
2863
|
}
|
|
2881
2864
|
if (!isComposerSubmissionKey(event) || !composer) return;
|
|
@@ -3084,11 +3067,10 @@ export function installRendererBindingProbe(
|
|
|
3084
3067
|
applyAdapterAgent = null;
|
|
3085
3068
|
modelControl = null;
|
|
3086
3069
|
mutationObserver.disconnect();
|
|
3087
|
-
sidebarAgentIcons.dispose();
|
|
3088
|
-
harnessMentions.dispose();
|
|
3089
|
-
collabCards.dispose();
|
|
3090
|
-
|
|
3091
|
-
settingsLifecycle.dispose();
|
|
3070
|
+
sidebarAgentIcons.dispose();
|
|
3071
|
+
harnessMentions.dispose();
|
|
3072
|
+
collabCards.dispose();
|
|
3073
|
+
settingsLifecycle.dispose();
|
|
3092
3074
|
document.removeEventListener("beforeinput", onBeforeInput, true);
|
|
3093
3075
|
document.removeEventListener("submit", onSubmit, true);
|
|
3094
3076
|
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 {
|