@makerbi/remodex 3.1.0 → 3.3.0
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/package.json +1 -1
- package/src/bridge.js +160 -30
- package/src/codex-desktop-refresher.js +8 -8
- package/src/codex-runtime-settings.js +113 -0
- package/src/desktop-ipc-action-follower.js +295 -104
- package/src/desktop-ipc-conversation-adapter.js +250 -45
- package/src/desktop-ipc-conversation-projector.js +1 -0
- package/src/desktop-ipc-live-owner.js +269 -178
- package/src/desktop-ipc-shared.js +37 -3
- package/src/git-handler.js +20 -17
- package/src/rollout-live-mirror.js +3 -4
- package/src/runtime-provider-router.js +10 -2
- package/src/thread-activity-projector.js +694 -0
- package/src/thread-activity-store.js +325 -0
- package/src/thread-runtime-settings-store.js +60 -74
|
@@ -26,14 +26,15 @@ const DESKTOP_IPC_METHOD_VERSIONS = new Map([
|
|
|
26
26
|
["thread-stream-following-status-requested", 1],
|
|
27
27
|
["thread-archived", 2],
|
|
28
28
|
["thread-unarchived", 1],
|
|
29
|
-
["thread-
|
|
29
|
+
["thread-owner-discovery", 1],
|
|
30
|
+
["thread-read-state-changed", 3],
|
|
30
31
|
["thread-queued-followups-changed", 1],
|
|
31
|
-
["thread-follower-start-turn",
|
|
32
|
+
["thread-follower-start-turn", 2],
|
|
32
33
|
["thread-follower-load-complete-history", 1],
|
|
33
34
|
["thread-follower-update-thread-settings", 1],
|
|
34
35
|
["thread-follower-compact-thread", 1],
|
|
35
36
|
["thread-follower-steer-turn", 1],
|
|
36
|
-
["thread-follower-interrupt-turn",
|
|
37
|
+
["thread-follower-interrupt-turn", 4],
|
|
37
38
|
["thread-follower-set-model-and-reasoning", 1],
|
|
38
39
|
["thread-follower-set-collaboration-mode", 1],
|
|
39
40
|
["thread-follower-edit-last-user-turn", 2],
|
|
@@ -582,6 +583,38 @@ function buildCompleteThreadReadParams(threadId) {
|
|
|
582
583
|
};
|
|
583
584
|
}
|
|
584
585
|
|
|
586
|
+
// Desktop 26.903 scopes read receipts to the authenticated identity and runtime.
|
|
587
|
+
// Only the local stdio runtime is owned by this bridge; never broadcast tokens.
|
|
588
|
+
function buildThreadReadStateContext(authStatus, hostId = "local") {
|
|
589
|
+
if (!authStatus || hostId !== "local") {
|
|
590
|
+
return null;
|
|
591
|
+
}
|
|
592
|
+
let identity;
|
|
593
|
+
if (authStatus.authMethod === "chatgpt" || authStatus.authMethod === "chatgptAuthTokens") {
|
|
594
|
+
try {
|
|
595
|
+
const payload = JSON.parse(Buffer.from(
|
|
596
|
+
readString(authStatus.authToken).split(".")[1] || "", "base64url"
|
|
597
|
+
).toString("utf8"));
|
|
598
|
+
const auth = payload["https://api.openai.com/auth"];
|
|
599
|
+
const accountId = readString(auth?.chatgpt_account_id ?? auth?.account_id);
|
|
600
|
+
const userId = readString(auth?.user_id ?? auth?.chatgpt_user_id);
|
|
601
|
+
if (!accountId || !userId) {
|
|
602
|
+
return null;
|
|
603
|
+
}
|
|
604
|
+
identity = { kind: "chatgpt", accountId, userId };
|
|
605
|
+
} catch {
|
|
606
|
+
return null;
|
|
607
|
+
}
|
|
608
|
+
} else {
|
|
609
|
+
if (authStatus.authMethod == null && authStatus.requiresOpenaiAuth !== false) {
|
|
610
|
+
return null;
|
|
611
|
+
}
|
|
612
|
+
identity = { kind: "execution-storage", authMode: authStatus.authMethod ?? "none" };
|
|
613
|
+
}
|
|
614
|
+
const hostHash = createHash("sha256").update(JSON.stringify(["local", hostId, null])).digest("hex");
|
|
615
|
+
return { identity, executionHostKey: `${hostId}:${hostHash}` };
|
|
616
|
+
}
|
|
617
|
+
|
|
585
618
|
function resolveIpcSocketPathCandidates() {
|
|
586
619
|
if (process.platform === "win32") {
|
|
587
620
|
return ["\\\\.\\pipe\\codex-ipc"];
|
|
@@ -666,6 +699,7 @@ function responseItemMessageText(payload) {
|
|
|
666
699
|
}
|
|
667
700
|
|
|
668
701
|
module.exports = {
|
|
702
|
+
buildThreadReadStateContext,
|
|
669
703
|
CLIENT_STATUS_CHANGED,
|
|
670
704
|
buildCompleteThreadReadParams,
|
|
671
705
|
buildIpcRequestEnvelope,
|
package/src/git-handler.js
CHANGED
|
@@ -69,9 +69,6 @@ function handleGitRequest(rawMessage, sendResponse, options = {}) {
|
|
|
69
69
|
handleGitMethod(method, params, methodOptions)
|
|
70
70
|
.then((result) => {
|
|
71
71
|
sendResponse(JSON.stringify({ id, result }));
|
|
72
|
-
if (method === "thread/name/set") {
|
|
73
|
-
options.onThreadNameSet?.(result);
|
|
74
|
-
}
|
|
75
72
|
})
|
|
76
73
|
.catch((err) => {
|
|
77
74
|
const errorCode = err.errorCode || "git_error";
|
|
@@ -96,7 +93,7 @@ async function handleGitMethod(method, params, options = {}) {
|
|
|
96
93
|
return threadGenerateTitle(params, options);
|
|
97
94
|
}
|
|
98
95
|
if (method === "thread/name/set") {
|
|
99
|
-
return threadNameSet(params);
|
|
96
|
+
return threadNameSet(params, options);
|
|
100
97
|
}
|
|
101
98
|
|
|
102
99
|
const cwd = await resolveGitCwd(params);
|
|
@@ -153,8 +150,9 @@ async function handleGitMethod(method, params, options = {}) {
|
|
|
153
150
|
}
|
|
154
151
|
}
|
|
155
152
|
|
|
156
|
-
//
|
|
157
|
-
|
|
153
|
+
// Normalize mobile aliases, then persist through the same catalog RPC as Desktop.
|
|
154
|
+
// The app-server emits thread/name/updated to the phone and live IPC owner.
|
|
155
|
+
async function threadNameSet(params, { sendCodexRequest } = {}) {
|
|
158
156
|
const threadId = normalizeNonEmptyLine(params.threadId || params.thread_id || params.conversationId || params.conversation_id);
|
|
159
157
|
const name = normalizeNonEmptyLine(params.name || params.threadName || params.thread_name || params.title);
|
|
160
158
|
if (!threadId) {
|
|
@@ -164,6 +162,11 @@ function threadNameSet(params) {
|
|
|
164
162
|
throw gitError("missing_thread_name", "A thread name is required.");
|
|
165
163
|
}
|
|
166
164
|
|
|
165
|
+
if (typeof sendCodexRequest !== "function") {
|
|
166
|
+
throw gitError("thread_rename_unavailable", "The local Codex connection is unavailable.");
|
|
167
|
+
}
|
|
168
|
+
await sendCodexRequest("thread/name/set", { threadId, name });
|
|
169
|
+
|
|
167
170
|
return { threadId, thread_id: threadId, name, title: name };
|
|
168
171
|
}
|
|
169
172
|
|
|
@@ -184,9 +187,8 @@ async function gitStatus(cwd) {
|
|
|
184
187
|
const localOnlyCommitCount = await countLocalOnlyCommits(cwd, { detached: snapshot.detached }).catch(() => 0);
|
|
185
188
|
const state = computeState(dirty, ahead, behind, snapshot.detached, noUpstream);
|
|
186
189
|
const canPush = hasPushRemote && hasHeadCommit && (ahead > 0 || noUpstream) && !snapshot.detached;
|
|
187
|
-
const diff = await repoDiffTotals(cwd, {
|
|
190
|
+
const diff = await repoDiffTotals(snapshot.repoRoot || cwd, {
|
|
188
191
|
tracking: snapshot.tracking,
|
|
189
|
-
fileLines: snapshot.fileLines,
|
|
190
192
|
}).catch(() => ({ additions: 0, deletions: 0, binaryFiles: 0 }));
|
|
191
193
|
|
|
192
194
|
return {
|
|
@@ -267,17 +269,14 @@ async function gitInit(cwd) {
|
|
|
267
269
|
// ─── Git Diff ─────────────────────────────────────────────────
|
|
268
270
|
|
|
269
271
|
async function gitDiff(cwd) {
|
|
272
|
+
cwd = await resolveRepoRoot(cwd);
|
|
270
273
|
const porcelain = await git(cwd, "status", "--porcelain=v1", "-b");
|
|
271
274
|
const lines = porcelain.trim().split("\n").filter(Boolean);
|
|
272
275
|
const branchLine = lines[0] || "";
|
|
273
|
-
const fileLines = lines.slice(1);
|
|
274
276
|
const tracking = parseTrackingFromStatus(branchLine);
|
|
275
277
|
const baseRef = await resolveRepoDiffBase(cwd, tracking);
|
|
276
278
|
const trackedPatch = await gitDiffAgainstBase(cwd, baseRef);
|
|
277
|
-
const untrackedPaths =
|
|
278
|
-
.filter((line) => line.startsWith("?? "))
|
|
279
|
-
.map((line) => line.substring(3).trim())
|
|
280
|
-
.filter(Boolean);
|
|
279
|
+
const untrackedPaths = await repoUntrackedPaths(cwd);
|
|
281
280
|
const untrackedPatch = await diffPatchForUntrackedFiles(cwd, untrackedPaths);
|
|
282
281
|
const patch = [trackedPatch.trim(), untrackedPatch.trim()].filter(Boolean).join("\n\n").trim();
|
|
283
282
|
return { patch };
|
|
@@ -2349,10 +2348,7 @@ function scopedLocalCheckoutPath(checkoutRootPath, projectRelativePath) {
|
|
|
2349
2348
|
async function repoDiffTotals(cwd, context) {
|
|
2350
2349
|
const baseRef = await resolveRepoDiffBase(cwd, context.tracking);
|
|
2351
2350
|
const trackedTotals = await diffTotalsAgainstBase(cwd, baseRef);
|
|
2352
|
-
const untrackedPaths =
|
|
2353
|
-
.filter((line) => line.startsWith("?? "))
|
|
2354
|
-
.map((line) => line.substring(3).trim())
|
|
2355
|
-
.filter(Boolean);
|
|
2351
|
+
const untrackedPaths = await repoUntrackedPaths(cwd);
|
|
2356
2352
|
const untrackedTotals = await diffTotalsForUntrackedFiles(cwd, untrackedPaths);
|
|
2357
2353
|
|
|
2358
2354
|
return {
|
|
@@ -2362,6 +2358,13 @@ async function repoDiffTotals(cwd, context) {
|
|
|
2362
2358
|
};
|
|
2363
2359
|
}
|
|
2364
2360
|
|
|
2361
|
+
// Porcelain collapses new directories and quotes filenames. Ask Git for the
|
|
2362
|
+
// individual paths so the summary and Changes patch include every new file.
|
|
2363
|
+
async function repoUntrackedPaths(repoRoot) {
|
|
2364
|
+
const output = await git(repoRoot, "ls-files", "--others", "--exclude-standard", "-z");
|
|
2365
|
+
return output.split("\0").filter(Boolean);
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2365
2368
|
// Uses upstream when available; otherwise falls back to commits not yet present on any remote.
|
|
2366
2369
|
async function resolveRepoDiffBase(cwd, tracking) {
|
|
2367
2370
|
if (!(await refExists(cwd, "HEAD"))) {
|
|
@@ -205,10 +205,9 @@ function createThreadRolloutLiveMirror({
|
|
|
205
205
|
|
|
206
206
|
try {
|
|
207
207
|
const currentTime = now();
|
|
208
|
-
const suppressedBeforeScan = isSuppressed();
|
|
208
|
+
const suppressedBeforeScan = isSuppressed({ probeFallbackActivity: true });
|
|
209
209
|
if (suppressedBeforeScan) {
|
|
210
210
|
if (!wasSuppressed) {
|
|
211
|
-
rolloutPath = null;
|
|
212
211
|
lastSize = 0;
|
|
213
212
|
partialLine = "";
|
|
214
213
|
didBootstrap = false;
|
|
@@ -218,7 +217,6 @@ function createThreadRolloutLiveMirror({
|
|
|
218
217
|
return;
|
|
219
218
|
}
|
|
220
219
|
if (wasSuppressed) {
|
|
221
|
-
rolloutPath = null;
|
|
222
220
|
lastSize = 0;
|
|
223
221
|
partialLine = "";
|
|
224
222
|
didBootstrap = false;
|
|
@@ -251,7 +249,8 @@ function createThreadRolloutLiveMirror({
|
|
|
251
249
|
fallbackActivityAt: Number(rolloutStat.mtimeMs) || 0,
|
|
252
250
|
});
|
|
253
251
|
if (suppressed) {
|
|
254
|
-
|
|
252
|
+
// Keep the resolved path so quiet Desktop work needs only a stat on
|
|
253
|
+
// later probes, without repeatedly searching the sessions directory.
|
|
255
254
|
lastSize = 0;
|
|
256
255
|
partialLine = "";
|
|
257
256
|
didBootstrap = false;
|
|
@@ -76,7 +76,11 @@ function createRuntimeProviderRouter({
|
|
|
76
76
|
|
|
77
77
|
if (method === "model/list") {
|
|
78
78
|
respondAsync(parsed, sendResponse, async () => {
|
|
79
|
-
const codexResult = await sendCodexRequest(
|
|
79
|
+
const codexResult = await sendCodexRequest(
|
|
80
|
+
"model/list",
|
|
81
|
+
stripProviderFields(parsed.params || {}),
|
|
82
|
+
String(parsed.id)
|
|
83
|
+
);
|
|
80
84
|
const providerModels = await listProviderModels(runtimeProviders);
|
|
81
85
|
return mergeModelListResult(codexResult, providerModels);
|
|
82
86
|
});
|
|
@@ -85,7 +89,11 @@ function createRuntimeProviderRouter({
|
|
|
85
89
|
|
|
86
90
|
if (method === "thread/list") {
|
|
87
91
|
respondAsync(parsed, sendResponse, async () => {
|
|
88
|
-
const codexResult = await sendCodexRequest(
|
|
92
|
+
const codexResult = await sendCodexRequest(
|
|
93
|
+
"thread/list",
|
|
94
|
+
stripProviderFields(parsed.params || {}),
|
|
95
|
+
String(parsed.id)
|
|
96
|
+
);
|
|
89
97
|
const providerThreads = hasCursor(parsed.params)
|
|
90
98
|
? []
|
|
91
99
|
: await listProviderThreads(runtimeProviders, parsed.params || {});
|