codex-plus-patcher 0.6.0 → 0.7.1
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 +3 -1
- package/package.json +5 -3
- package/src/cli.js +88 -0
- package/src/core/dev-mode.js +274 -0
- package/src/core/plugin-audit.js +1267 -0
- package/src/patches/26.623.41415-4505.js +44 -0
- package/src/patches/index.js +8 -1
- package/src/patches/lib/common-patches.js +411 -248
- package/src/patches/lib/hooks/about.js +7 -0
- package/src/patches/lib/hooks/diagnostics.js +7 -0
- package/src/patches/lib/hooks/mermaid.js +7 -0
- package/src/patches/lib/hooks/message-composer.js +7 -0
- package/src/patches/lib/hooks/native-main.js +7 -0
- package/src/patches/lib/hooks/project-selector.js +12 -0
- package/src/patches/lib/hooks/review.js +9 -0
- package/src/patches/lib/hooks/settings-commands.js +13 -0
- package/src/patches/lib/hooks/sidebar.js +7 -0
- package/src/patches/lib/hooks/thread-header.js +7 -0
- package/src/patches/lib/hooks/worker.js +7 -0
- package/src/patches/lib/project-selector-shortcut-patch.js +84 -8
- package/src/runtime/api/about.js +16 -0
- package/src/runtime/api/commands.js +85 -0
- package/src/runtime/api/composer.js +14 -0
- package/src/runtime/api/diagnostics.js +38 -0
- package/src/runtime/api/errors.js +20 -0
- package/src/runtime/api/index.js +82 -0
- package/src/runtime/api/mermaid.js +14 -0
- package/src/runtime/api/message.js +14 -0
- package/src/runtime/api/modules.js +57 -0
- package/src/runtime/api/native.js +14 -0
- package/src/runtime/api/patches.js +31 -0
- package/src/runtime/api/review.js +20 -0
- package/src/runtime/api/settings.js +76 -0
- package/src/runtime/api/sidebar.js +24 -0
- package/src/runtime/api/styles.js +28 -0
- package/src/runtime/api/threadHeader.js +41 -0
- package/src/runtime/assets.js +59 -18
- package/src/runtime/host/messageComposer.js +16 -0
- package/src/runtime/host/nativeMain.js +159 -0
- package/src/runtime/host/projectSelector.js +58 -0
- package/src/runtime/host/review.js +62 -0
- package/src/runtime/host/sidebar.js +21 -0
- package/src/runtime/host/threadHeader.js +9 -0
- package/src/runtime/{worker.js → host/worker.js} +7 -0
- package/src/runtime/plugins/mermaidFullscreen.js +19 -6
- package/src/runtime/plugins/nestedRepositories.js +72 -11
- package/src/runtime/plugins/projectColors.js +94 -7
- package/src/runtime/plugins/projectSelectorShortcut.js +67 -12
- package/src/runtime/plugins/sidebarNameBlur.js +1 -1
- package/src/runtime/runtime.js +23 -441
|
@@ -13,6 +13,43 @@
|
|
|
13
13
|
return JSON.stringify([hostId, conversationId, cwd]);
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
function workerRequest(workerId, method, params, signal) {
|
|
17
|
+
const bridge = window.electronBridge;
|
|
18
|
+
if (typeof bridge?.sendWorkerMessageFromView !== "function" || typeof bridge?.subscribeToWorkerMessages !== "function") {
|
|
19
|
+
return Promise.reject(new Error("Electron worker bridge is unavailable"));
|
|
20
|
+
}
|
|
21
|
+
if (signal?.aborted) return Promise.reject(new DOMException("Aborted", "AbortError"));
|
|
22
|
+
const id = `codex-plus-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
23
|
+
const request = { id, method, params };
|
|
24
|
+
return new Promise((resolve, reject) => {
|
|
25
|
+
let unsubscribe = null;
|
|
26
|
+
let done = false;
|
|
27
|
+
const cleanup = () => {
|
|
28
|
+
if (done) return;
|
|
29
|
+
done = true;
|
|
30
|
+
unsubscribe?.();
|
|
31
|
+
signal?.removeEventListener?.("abort", abort);
|
|
32
|
+
};
|
|
33
|
+
const abort = () => {
|
|
34
|
+
cleanup();
|
|
35
|
+
bridge.sendWorkerMessageFromView(workerId, { type: "worker-request-cancel", workerId, id }).catch(() => {});
|
|
36
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
37
|
+
};
|
|
38
|
+
unsubscribe = bridge.subscribeToWorkerMessages(workerId, (message) => {
|
|
39
|
+
if (message?.type !== "worker-response" || message?.workerId !== workerId || message?.response?.id !== id) return;
|
|
40
|
+
cleanup();
|
|
41
|
+
const result = message.response.result;
|
|
42
|
+
if (result?.type === "ok") resolve(result.value);
|
|
43
|
+
else reject(new Error(result?.error?.message || "Worker request failed"));
|
|
44
|
+
});
|
|
45
|
+
signal?.addEventListener?.("abort", abort, { once: true });
|
|
46
|
+
bridge.sendWorkerMessageFromView(workerId, { type: "worker-request", workerId, request }).catch((error) => {
|
|
47
|
+
cleanup();
|
|
48
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
16
53
|
function debugText(value) {
|
|
17
54
|
try {
|
|
18
55
|
return JSON.stringify(value, (_key, item) => (typeof item === "bigint" ? String(item) : item), 2) ?? "";
|
|
@@ -86,6 +123,7 @@
|
|
|
86
123
|
function RepoDiffBody({ cwd, hostConfig, conversationId, diffMode, diffText, statusText, error, isLoading }, deps) {
|
|
87
124
|
const { jsx, createElement, parseDiff, DiffCard, pathValue } = deps;
|
|
88
125
|
if (error != null || isLoading || diffText == null) return PlainDiff({ text: statusText }, deps);
|
|
126
|
+
if (typeof parseDiff !== "function" || typeof DiffCard !== "function") return PlainDiff({ text: diffText }, deps);
|
|
89
127
|
let parsed;
|
|
90
128
|
try {
|
|
91
129
|
parsed = parseDiff(diffText);
|
|
@@ -193,6 +231,27 @@
|
|
|
193
231
|
}, [open, query, repo.root, hostConfig.id]);
|
|
194
232
|
|
|
195
233
|
const title = selected || "Unstaged";
|
|
234
|
+
if (!Button || !Tooltip || !Icon || !Dropdown || !DropdownMenu || !BranchPickerDropdownContent) {
|
|
235
|
+
const options = branches.length > 0 ? branches : searchedBranches;
|
|
236
|
+
return jsxs("label", {
|
|
237
|
+
className: "flex min-w-32 max-w-52 shrink-0 items-center gap-1 text-xs text-token-description-foreground",
|
|
238
|
+
children: [
|
|
239
|
+
jsx("span", { className: "sr-only", children: "Base branch" }),
|
|
240
|
+
jsx("select", {
|
|
241
|
+
className:
|
|
242
|
+
"min-w-0 flex-1 rounded-md border border-token-border bg-token-main-surface-primary px-1.5 py-1 text-xs text-token-foreground",
|
|
243
|
+
value: selected,
|
|
244
|
+
disabled: loading || error != null,
|
|
245
|
+
onFocus: loadBranches,
|
|
246
|
+
onChange: (event) => setBaseBranch(event.target.value),
|
|
247
|
+
children: [
|
|
248
|
+
jsx("option", { value: "", children: loading ? "Loading..." : "Unstaged" }, "unstaged"),
|
|
249
|
+
...options.map((branch) => jsx("option", { value: branch.name ?? branch, children: branch.name ?? branch }, branch.name ?? branch)),
|
|
250
|
+
],
|
|
251
|
+
}),
|
|
252
|
+
],
|
|
253
|
+
});
|
|
254
|
+
}
|
|
196
255
|
const button = jsxs(Button, {
|
|
197
256
|
type: "button",
|
|
198
257
|
color: selected ? "ghostActive" : "ghost",
|
|
@@ -317,14 +376,16 @@
|
|
|
317
376
|
],
|
|
318
377
|
}),
|
|
319
378
|
jsx(BranchPicker, { repo, hostConfig, baseBranch, setBaseBranch, deps }),
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
379
|
+
ReviewToolbar
|
|
380
|
+
? jsx(ReviewToolbar, {
|
|
381
|
+
conversationId,
|
|
382
|
+
cwd: repo.cwd,
|
|
383
|
+
hostId,
|
|
384
|
+
codexWorktree: false,
|
|
385
|
+
surface: "review-toolbar",
|
|
386
|
+
reviewToolbarCompact: true,
|
|
387
|
+
}, repo.id)
|
|
388
|
+
: null,
|
|
328
389
|
],
|
|
329
390
|
}),
|
|
330
391
|
collapsed ? null : RepoDiffBody({ cwd: repo.cwd, hostConfig, conversationId, diffMode, diffText, statusText, error, isLoading: loading }, deps),
|
|
@@ -338,7 +399,7 @@
|
|
|
338
399
|
const cwd = useAtom(cwdAtom);
|
|
339
400
|
const hostId = useAtom(hostIdAtom);
|
|
340
401
|
const hostConfig = useAtom(hostConfigAtom);
|
|
341
|
-
const conversationAtomValue = useAtom(conversationIdAtom);
|
|
402
|
+
const conversationAtomValue = conversationIdAtom ? useAtom(conversationIdAtom) : null;
|
|
342
403
|
const conversationId = routeStore.value.routeKind === "local-thread" ? routeStore.value.conversationId : null;
|
|
343
404
|
const [targets, setTargets] = React.useState(null);
|
|
344
405
|
const [collapsed, setCollapsedState] = React.useState(() => new Map());
|
|
@@ -438,8 +499,8 @@
|
|
|
438
499
|
start(api) {
|
|
439
500
|
api.ui.review.wrapBody((props, deps) => ReviewMux(props, deps));
|
|
440
501
|
api.modules.registerHostModule("codex-plus:native:repository-targets", {
|
|
441
|
-
request(params) {
|
|
442
|
-
return
|
|
502
|
+
request(params, signal) {
|
|
503
|
+
return workerRequest("git", "repository-targets", params, signal);
|
|
443
504
|
},
|
|
444
505
|
});
|
|
445
506
|
},
|
|
@@ -58,6 +58,90 @@
|
|
|
58
58
|
return palette[fnv1a32(colorKey(project)) % palette.length];
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
const projectByPath = new Map();
|
|
62
|
+
const projectByName = new Map();
|
|
63
|
+
|
|
64
|
+
function pathBasename(value) {
|
|
65
|
+
const trimmed = String(value || "").replace(/\/+$/, "");
|
|
66
|
+
if (trimmed === "") return "";
|
|
67
|
+
return trimmed.split("/").pop() || "";
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function projectPathKeys(project) {
|
|
71
|
+
if (project == null || typeof project === "string") return [];
|
|
72
|
+
const host = project.hostId ?? project.host ?? project.remoteHostId ?? "local";
|
|
73
|
+
const paths = [project.path, project.cwd, project.projectPath, project.remotePath, project.root, project.workspaceRoot]
|
|
74
|
+
.filter((value) => value != null && String(value).trim() !== "")
|
|
75
|
+
.map((value) => String(value).trim());
|
|
76
|
+
return paths.map((path) => `${host}:${path}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function projectNameKeys(project) {
|
|
80
|
+
if (project == null || typeof project === "string") return [];
|
|
81
|
+
const repositoryRoot = project.repositoryData?.rootFolder;
|
|
82
|
+
const values = [
|
|
83
|
+
project.label,
|
|
84
|
+
project.name,
|
|
85
|
+
repositoryRoot,
|
|
86
|
+
pathBasename(project.projectId),
|
|
87
|
+
pathBasename(project.id),
|
|
88
|
+
...projectPathKeys(project).map((key) => pathBasename(key)),
|
|
89
|
+
];
|
|
90
|
+
return Array.from(new Set(values
|
|
91
|
+
.filter((value) => value != null && String(value).trim() !== "")
|
|
92
|
+
.map((value) => String(value).trim())));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function rememberProjectName(key, project) {
|
|
96
|
+
if (key === "") return;
|
|
97
|
+
const existing = projectByName.get(key);
|
|
98
|
+
if (existing === undefined) {
|
|
99
|
+
projectByName.set(key, project);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (existing != null && colorKey(existing) !== colorKey(project)) projectByName.set(key, null);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function rememberProject(project) {
|
|
106
|
+
const key = colorKey(project);
|
|
107
|
+
if (key.trim() === "") return project;
|
|
108
|
+
for (const pathKey of projectPathKeys(project)) projectByPath.set(pathKey, project);
|
|
109
|
+
for (const nameKey of projectNameKeys(project)) rememberProjectName(nameKey, project);
|
|
110
|
+
return project;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function resolveProject(project) {
|
|
114
|
+
for (const pathKey of projectPathKeys(project)) {
|
|
115
|
+
const knownProject = projectByPath.get(pathKey);
|
|
116
|
+
if (knownProject) return knownProject;
|
|
117
|
+
}
|
|
118
|
+
for (const nameKey of projectNameKeys(project)) {
|
|
119
|
+
const knownProject = projectByName.get(nameKey);
|
|
120
|
+
if (knownProject) return knownProject;
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function activeSidebarStyle() {
|
|
126
|
+
const active = document.querySelector('[data-app-action-sidebar-thread-active="true"][data-codex-plus-project-color]');
|
|
127
|
+
if (!active) return undefined;
|
|
128
|
+
const computed = getComputedStyle(active);
|
|
129
|
+
const accent = computed.getPropertyValue("--codex-plus-project-accent").trim();
|
|
130
|
+
if (accent === "") return undefined;
|
|
131
|
+
return {
|
|
132
|
+
"--codex-plus-project-accent": accent,
|
|
133
|
+
"--codex-plus-project-bg-light": computed.getPropertyValue("--codex-plus-project-bg-light").trim(),
|
|
134
|
+
"--codex-plus-project-fg-light": computed.getPropertyValue("--codex-plus-project-fg-light").trim(),
|
|
135
|
+
"--codex-plus-project-soft-light": computed.getPropertyValue("--codex-plus-project-soft-light").trim(),
|
|
136
|
+
"--codex-plus-project-bg-dark": computed.getPropertyValue("--codex-plus-project-bg-dark").trim(),
|
|
137
|
+
"--codex-plus-project-fg-dark": computed.getPropertyValue("--codex-plus-project-fg-dark").trim(),
|
|
138
|
+
"--codex-plus-project-border-dark": computed.getPropertyValue("--codex-plus-project-border-dark").trim(),
|
|
139
|
+
"--codex-plus-project-separator-light": computed.getPropertyValue("--codex-plus-project-separator-light").trim(),
|
|
140
|
+
"--codex-plus-project-separator-dark": computed.getPropertyValue("--codex-plus-project-separator-dark").trim(),
|
|
141
|
+
borderLeft: `6px solid ${accent}`,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
61
145
|
function style(project) {
|
|
62
146
|
const key = colorKey(project);
|
|
63
147
|
if (!readEnabled() || key.trim() === "") return undefined;
|
|
@@ -77,7 +161,9 @@
|
|
|
77
161
|
}
|
|
78
162
|
|
|
79
163
|
function dataAttributes(project, sidebar) {
|
|
80
|
-
const
|
|
164
|
+
const resolvedProject = sidebar ? rememberProject(project) : resolveProject(project);
|
|
165
|
+
const directStyle = style(project);
|
|
166
|
+
const inlineStyle = resolvedProject ? style(resolvedProject) : directStyle ?? activeSidebarStyle();
|
|
81
167
|
if (inlineStyle == null) return undefined;
|
|
82
168
|
return {
|
|
83
169
|
"data-codex-plus-project-color": "",
|
|
@@ -114,14 +200,15 @@
|
|
|
114
200
|
description: "Provides deterministic project accent colors across sidebar, messages, and composer surfaces.",
|
|
115
201
|
required: true,
|
|
116
202
|
styles:
|
|
117
|
-
":root:not(.dark):not(.electron-dark) [data-codex-plus-project-sidebar-color]{border-radius:0;background-color:var(--codex-plus-project-soft-light);border-left-color:var(--codex-plus-project-accent)}" +
|
|
118
|
-
":root:not(.dark):not(.electron-dark) [data-app-action-sidebar-thread-
|
|
119
|
-
":root.dark [data-codex-plus-project-sidebar-color],:root.electron-dark [data-codex-plus-project-sidebar-color]{border-radius:0;background-color:var(--codex-plus-project-bg-dark);border-left-color:var(--codex-plus-project-border-dark)}" +
|
|
120
|
-
":root.dark [data-app-action-sidebar-thread-
|
|
203
|
+
":root:not(.dark):not(.electron-dark) :is([data-app-action-sidebar-project-row],[data-app-action-sidebar-thread-row][data-codex-plus-project-sidebar-color],[data-app-action-sidebar-project-list-id][data-codex-plus-project-sidebar-color] [data-app-action-sidebar-thread-row]){border-radius:0;background-color:var(--codex-plus-project-soft-light);border-left-color:var(--codex-plus-project-accent)}" +
|
|
204
|
+
":root:not(.dark):not(.electron-dark) :is([data-app-action-sidebar-thread-row][data-codex-plus-project-sidebar-color],[data-app-action-sidebar-project-list-id][data-codex-plus-project-sidebar-color] [data-app-action-sidebar-thread-row])[data-app-action-sidebar-thread-active=\"true\"]{background-color:var(--codex-plus-project-bg-light);box-shadow:inset 5px 0 0 var(--codex-plus-project-accent)}" +
|
|
205
|
+
":root.dark :is([data-app-action-sidebar-project-row],[data-app-action-sidebar-thread-row][data-codex-plus-project-sidebar-color],[data-app-action-sidebar-project-list-id][data-codex-plus-project-sidebar-color] [data-app-action-sidebar-thread-row]),:root.electron-dark :is([data-app-action-sidebar-project-row],[data-app-action-sidebar-thread-row][data-codex-plus-project-sidebar-color],[data-app-action-sidebar-project-list-id][data-codex-plus-project-sidebar-color] [data-app-action-sidebar-thread-row]){border-radius:0;background-color:var(--codex-plus-project-bg-dark);border-left-color:var(--codex-plus-project-border-dark)}" +
|
|
206
|
+
":root.dark :is([data-app-action-sidebar-thread-row][data-codex-plus-project-sidebar-color],[data-app-action-sidebar-project-list-id][data-codex-plus-project-sidebar-color] [data-app-action-sidebar-thread-row])[data-app-action-sidebar-thread-active=\"true\"],:root.electron-dark :is([data-app-action-sidebar-thread-row][data-codex-plus-project-sidebar-color],[data-app-action-sidebar-project-list-id][data-codex-plus-project-sidebar-color] [data-app-action-sidebar-thread-row])[data-app-action-sidebar-thread-active=\"true\"]{background-color:color-mix(in srgb,var(--codex-plus-project-accent) 38%,transparent);border-left-color:color-mix(in srgb,var(--codex-plus-project-accent) 88%,transparent);box-shadow:inset 5px 0 0 var(--codex-plus-project-accent)}" +
|
|
121
207
|
":root:not(.dark):not(.electron-dark) [data-codex-plus-project-color]{border-left-color:var(--codex-plus-project-accent)}" +
|
|
122
208
|
":root.dark [data-codex-plus-project-color],:root.electron-dark [data-codex-plus-project-color]{border-left-color:var(--codex-plus-project-border-dark)}" +
|
|
123
|
-
":root:not(.dark):not(.electron-dark) [data-codex-plus-project-color]:not([data-codex-plus-project-sidebar-color]){
|
|
124
|
-
":root.dark [data-codex-plus-project-color]:not([data-codex-plus-project-sidebar-color]),:root.electron-dark [data-codex-plus-project-color]:not([data-codex-plus-project-sidebar-color]){
|
|
209
|
+
":root:not(.dark):not(.electron-dark) [data-codex-plus-project-color]:not([data-codex-plus-project-sidebar-color]){box-shadow:inset 6px 0 0 var(--codex-plus-project-accent);border-left-color:var(--codex-plus-project-accent)}" +
|
|
210
|
+
":root.dark [data-codex-plus-project-color]:not([data-codex-plus-project-sidebar-color]),:root.electron-dark [data-codex-plus-project-color]:not([data-codex-plus-project-sidebar-color]){box-shadow:inset 6px 0 0 var(--codex-plus-project-accent);border-left-color:var(--codex-plus-project-border-dark)}" +
|
|
211
|
+
"[data-codex-plus-user-entry][data-codex-plus-project-color]{box-shadow:inset 6px 0 0 var(--codex-plus-project-accent),0 0 0 .5px rgba(255,255,255,.2)!important}",
|
|
125
212
|
exports: {
|
|
126
213
|
colorFor,
|
|
127
214
|
colorKey,
|
|
@@ -36,14 +36,71 @@
|
|
|
36
36
|
].map((value) => normalizeForFzf(value).text.trim()).filter(Boolean).join(" ");
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
function projectSearchFields(project) {
|
|
40
|
+
return [
|
|
41
|
+
{ text: project?.label, weight: 0 },
|
|
42
|
+
{ text: project?.repositoryData?.rootFolder, weight: 10 },
|
|
43
|
+
{ text: project?.hostDisplayName, weight: 20 },
|
|
44
|
+
{ text: project?.path, weight: 40 },
|
|
45
|
+
].map((field) => ({ ...field, text: normalizeForFzf(field.text).text.trim() })).filter((field) => field.text);
|
|
46
|
+
}
|
|
47
|
+
|
|
39
48
|
function fzfConstructor() {
|
|
40
49
|
return window.fzf?.Fzf;
|
|
41
50
|
}
|
|
42
51
|
|
|
43
|
-
function
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
52
|
+
function fallbackPositions(text, query) {
|
|
53
|
+
const normalizedText = normalizeForFzf(text);
|
|
54
|
+
const normalizedQuery = normalizeForFzf(query).text.trim().toLowerCase();
|
|
55
|
+
if (!normalizedText.text || !normalizedQuery) return null;
|
|
56
|
+
|
|
57
|
+
const haystack = normalizedText.text.toLowerCase();
|
|
58
|
+
const positions = [];
|
|
59
|
+
let cursor = 0;
|
|
60
|
+
|
|
61
|
+
for (const char of normalizedQuery) {
|
|
62
|
+
cursor = haystack.indexOf(char, cursor);
|
|
63
|
+
if (cursor === -1) return null;
|
|
64
|
+
positions.push(cursor);
|
|
65
|
+
cursor += 1;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return positions;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function fallbackScore(text, query) {
|
|
72
|
+
const positions = fallbackPositions(text, query);
|
|
73
|
+
if (positions == null) return null;
|
|
74
|
+
|
|
75
|
+
let score = positions[0] + (positions[positions.length - 1] - positions[0]);
|
|
76
|
+
for (let index = 1; index < positions.length; index += 1) {
|
|
77
|
+
score += positions[index] - positions[index - 1] - 1;
|
|
78
|
+
}
|
|
79
|
+
for (const position of positions) {
|
|
80
|
+
if (position === 0 || /\s/.test(text[position - 1] ?? "")) score -= 2;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return score;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function rankedFilter(items, query) {
|
|
87
|
+
return items
|
|
88
|
+
.map((item, index) => {
|
|
89
|
+
const scores = projectSearchFields(item)
|
|
90
|
+
.map((field) => {
|
|
91
|
+
const score = fallbackScore(field.text, query);
|
|
92
|
+
return score == null ? null : score + field.weight;
|
|
93
|
+
})
|
|
94
|
+
.filter((score) => score != null);
|
|
95
|
+
return { item, index, score: scores.length === 0 ? null : Math.min(...scores) };
|
|
96
|
+
})
|
|
97
|
+
.filter((entry) => entry.score != null)
|
|
98
|
+
.sort((left, right) =>
|
|
99
|
+
left.score - right.score ||
|
|
100
|
+
projectSearchText(left.item).length - projectSearchText(right.item).length ||
|
|
101
|
+
left.index - right.index,
|
|
102
|
+
)
|
|
103
|
+
.map((entry) => entry.item);
|
|
47
104
|
}
|
|
48
105
|
|
|
49
106
|
function fuzzyFilter(items, query) {
|
|
@@ -51,18 +108,16 @@
|
|
|
51
108
|
const normalizedQuery = normalizeForFzf(query).text.trim();
|
|
52
109
|
if (!normalizedQuery) return list;
|
|
53
110
|
|
|
54
|
-
|
|
55
|
-
if (typeof Fzf !== "function") return fallbackFilter(list, query);
|
|
56
|
-
|
|
57
|
-
return new Fzf(
|
|
58
|
-
list.map((project) => ({ project, searchText: projectSearchText(project) })),
|
|
59
|
-
{ selector: (entry) => entry.searchText },
|
|
60
|
-
).find(normalizedQuery).map((entry) => entry.item.project);
|
|
111
|
+
return rankedFilter(list, query);
|
|
61
112
|
}
|
|
62
113
|
|
|
63
114
|
function labelPositions(text, query) {
|
|
64
115
|
const Fzf = fzfConstructor();
|
|
65
|
-
if (typeof Fzf !== "function")
|
|
116
|
+
if (typeof Fzf !== "function") {
|
|
117
|
+
const positions = fallbackPositions(text, query);
|
|
118
|
+
const normalizedText = normalizeForFzf(text);
|
|
119
|
+
return positions?.map((index) => normalizedText.map[index]).filter((index) => Number.isInteger(index)) ?? null;
|
|
120
|
+
}
|
|
66
121
|
|
|
67
122
|
const normalizedText = normalizeForFzf(text);
|
|
68
123
|
const normalizedQuery = normalizeForFzf(query).text.trim();
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
name: "Sidebar Name Blur",
|
|
7
7
|
description: "Registers the session-only Toggle sidebar blur command.",
|
|
8
8
|
required: true,
|
|
9
|
-
styles: ':root[data-codex-plus-sidebar-names-blurred="true"] :is([data-thread-title],[data-codex-plus-sidebar-name]){filter:blur(4px);user-select:none}',
|
|
9
|
+
styles: ':root[data-codex-plus-sidebar-names-blurred="true"] :is([data-thread-title],[data-codex-plus-sidebar-name],[data-app-action-sidebar-project-row]){filter:blur(4px);user-select:none}',
|
|
10
10
|
commands: [
|
|
11
11
|
{
|
|
12
12
|
id: "codexPlusToggleSidebarNameBlur",
|