@lamplitisles/codex-for-love 0.4.3 → 0.5.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/vendor/build/_app/immutable/assets/0.CkWBasWr.css +2 -0
- package/vendor/build/_app/immutable/chunks/{CtNIUOtb.js → BZwtE-rc.js} +3 -3
- package/vendor/build/_app/immutable/chunks/C2DTc7yw.js +3 -0
- package/vendor/build/_app/immutable/chunks/CyqZh0gB.js +1 -0
- package/vendor/build/_app/immutable/chunks/DFTMMhXH.js +1 -0
- package/vendor/build/_app/immutable/entry/app.Ci6fUWwj.js +2 -0
- package/vendor/build/_app/immutable/entry/start.DWuEW6S3.js +1 -0
- package/vendor/build/_app/immutable/nodes/0.C8SV4li-.js +1 -0
- package/vendor/build/_app/immutable/nodes/1.BQJiYb4b.js +1 -0
- package/vendor/build/_app/immutable/nodes/2.CReDueqi.js +330 -0
- package/vendor/build/_app/version.json +1 -1
- package/vendor/build/index.html +10 -9
- package/vendor/runtime/cli.mjs +216 -54
- package/vendor/runtime/companion-mcp.mjs +91 -3
- package/vendor/build/_app/immutable/assets/0.DfSR8oPO.css +0 -2
- package/vendor/build/_app/immutable/chunks/CTZw3jzS.js +0 -3
- package/vendor/build/_app/immutable/chunks/tYXWoiZl.js +0 -1
- package/vendor/build/_app/immutable/entry/app.C3QvzSBj.js +0 -2
- package/vendor/build/_app/immutable/entry/start.DN_PDYWk.js +0 -1
- package/vendor/build/_app/immutable/nodes/0.PSG_XCTv.js +0 -1
- package/vendor/build/_app/immutable/nodes/1.YrgYwNeI.js +0 -1
- package/vendor/build/_app/immutable/nodes/2.C7zq-Uwo.js +0 -327
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"
|
|
1
|
+
{"version":"1789828770771"}
|
package/vendor/build/index.html
CHANGED
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
<!doctype html>
|
|
2
2
|
<html lang="en" data-theme="sticker-messenger">
|
|
3
|
-
<head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" /><script>(function(){try{var appearance=localStorage.getItem('
|
|
4
|
-
<link href="/_app/immutable/chunks/
|
|
5
|
-
<link href="/_app/immutable/chunks/
|
|
6
|
-
<link href="/_app/immutable/
|
|
3
|
+
<head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" /><script>(function(){try{var appearance=localStorage.getItem('her.companion.appearance');var language=localStorage.getItem('her.companion.language');var systemDark=matchMedia('(prefers-color-scheme: dark)').matches;var dark=appearance==='dark'||(appearance!=='light'&&systemDark);document.documentElement.dataset.theme=dark?'night-voyage':'sticker-messenger';document.documentElement.lang=language==='zh'?'zh-Hans':'en'}catch(_){var systemDark=matchMedia('(prefers-color-scheme: dark)').matches;document.documentElement.dataset.theme=systemDark?'night-voyage':'sticker-messenger'}})();</script><link href="/_app/immutable/entry/start.DWuEW6S3.js" rel="modulepreload">
|
|
4
|
+
<link href="/_app/immutable/chunks/DFTMMhXH.js" rel="modulepreload">
|
|
5
|
+
<link href="/_app/immutable/chunks/C2DTc7yw.js" rel="modulepreload">
|
|
6
|
+
<link href="/_app/immutable/chunks/CyqZh0gB.js" rel="modulepreload">
|
|
7
|
+
<link href="/_app/immutable/entry/app.Ci6fUWwj.js" rel="modulepreload">
|
|
7
8
|
<link href="/_app/immutable/chunks/uBIymjUX.js" rel="modulepreload">
|
|
8
9
|
<link href="/_app/immutable/chunks/xihTtKlq.js" rel="modulepreload">
|
|
9
|
-
<link href="/_app/immutable/nodes/0.
|
|
10
|
+
<link href="/_app/immutable/nodes/0.C8SV4li-.js" rel="modulepreload">
|
|
10
11
|
|
|
11
|
-
<link href="/_app/immutable/assets/0.
|
|
12
|
+
<link href="/_app/immutable/assets/0.CkWBasWr.css" rel="stylesheet"></head>
|
|
12
13
|
<body data-sveltekit-preload-data="hover"><div style="display: contents">
|
|
13
14
|
<script>
|
|
14
15
|
{
|
|
15
|
-
|
|
16
|
+
__sveltekit_17ylz81 = {
|
|
16
17
|
base: ""
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
const element = document.currentScript.parentElement;
|
|
20
21
|
|
|
21
22
|
Promise.all([
|
|
22
|
-
import("/_app/immutable/entry/start.
|
|
23
|
-
import("/_app/immutable/entry/app.
|
|
23
|
+
import("/_app/immutable/entry/start.DWuEW6S3.js"),
|
|
24
|
+
import("/_app/immutable/entry/app.Ci6fUWwj.js")
|
|
24
25
|
]).then(([kit, app]) => {
|
|
25
26
|
kit.start(app, element);
|
|
26
27
|
});
|
package/vendor/runtime/cli.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
|
3
3
|
import { access, copyFile, lstat, mkdir, readFile, readdir, realpath, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
4
4
|
import { basename, dirname, extname, isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { isIP } from "node:net";
|
|
6
7
|
import { zstdDecompressSync } from "node:zlib";
|
|
7
8
|
import { spawn } from "child_process";
|
|
8
9
|
import { once } from "events";
|
|
@@ -12,7 +13,7 @@ import { delimiter, dirname as dirname$1, isAbsolute as isAbsolute$1, join as jo
|
|
|
12
13
|
import { randomUUID as randomUUID$1 } from "crypto";
|
|
13
14
|
import { createInterface } from "readline";
|
|
14
15
|
import { homedir } from "os";
|
|
15
|
-
import { createConnection, isIP } from "net";
|
|
16
|
+
import { createConnection, isIP as isIP$1 } from "net";
|
|
16
17
|
import { DatabaseSync } from "node:sqlite";
|
|
17
18
|
import { execFile } from "node:child_process";
|
|
18
19
|
import { promisify } from "node:util";
|
|
@@ -6196,6 +6197,7 @@ const schema = object({
|
|
|
6196
6197
|
user: string().min(1)
|
|
6197
6198
|
}).strict().optional(),
|
|
6198
6199
|
port: number$1().int().min(1024).max(65535).default(3082),
|
|
6200
|
+
listen_host: string().refine((value) => isIP(value) === 4, "Listen host must be an IPv4 address").default("127.0.0.1"),
|
|
6199
6201
|
codex: object({
|
|
6200
6202
|
command: string().min(1).default("codex-app-server"),
|
|
6201
6203
|
model: string().min(1).default(DEFAULT_CODEX_MODEL),
|
|
@@ -61937,7 +61939,7 @@ function validateBearerToken(value) {
|
|
|
61937
61939
|
function isLoopbackHostname(hostname) {
|
|
61938
61940
|
const normalized = hostname.replace(/^\[|\]$/g, "").replace(/\.$/, "").toLowerCase();
|
|
61939
61941
|
if (normalized === "localhost") return true;
|
|
61940
|
-
const family = isIP(normalized);
|
|
61942
|
+
const family = isIP$1(normalized);
|
|
61941
61943
|
if (family === 4) return normalized.startsWith("127.");
|
|
61942
61944
|
if (family === 6) return normalized === "::1" || normalized.startsWith("::ffff:127.");
|
|
61943
61945
|
return false;
|
|
@@ -62597,7 +62599,8 @@ function partnerPaths(workspace) {
|
|
|
62597
62599
|
database: join(managedRoot, "session.sqlite"),
|
|
62598
62600
|
relationshipJournal: join(managedRoot, "relationship.jsonl"),
|
|
62599
62601
|
attachments: join(managedRoot, "attachments"),
|
|
62600
|
-
audio: join(managedRoot, "audio")
|
|
62602
|
+
audio: join(managedRoot, "audio"),
|
|
62603
|
+
conversationImages: join(managedRoot, "conversation-images.json")
|
|
62601
62604
|
};
|
|
62602
62605
|
}
|
|
62603
62606
|
//#endregion
|
|
@@ -65478,6 +65481,80 @@ async function readClip(root, name, frameCount) {
|
|
|
65478
65481
|
return;
|
|
65479
65482
|
}
|
|
65480
65483
|
}
|
|
65484
|
+
//#endregion
|
|
65485
|
+
//#region apps/partner/runtime/conversation-images.ts
|
|
65486
|
+
const CURSOR_BYTES = 40;
|
|
65487
|
+
const CURSOR_TOKEN = /^[A-Za-z0-9_-]{54}$/u;
|
|
65488
|
+
const IMAGE_ID = /^[a-f0-9]{64}$/u;
|
|
65489
|
+
function cursorFor(image) {
|
|
65490
|
+
if (!Number.isSafeInteger(image.created) || image.created < 0 || !IMAGE_ID.test(image.id)) throw new Error("Invalid conversation image cursor data");
|
|
65491
|
+
const value = Buffer.alloc(CURSOR_BYTES);
|
|
65492
|
+
value.writeBigUInt64BE(BigInt(image.created));
|
|
65493
|
+
Buffer.from(image.id, "hex").copy(value, 8);
|
|
65494
|
+
return value.toString("base64url");
|
|
65495
|
+
}
|
|
65496
|
+
function readCursor(cursor) {
|
|
65497
|
+
if (!cursor) return void 0;
|
|
65498
|
+
if (!CURSOR_TOKEN.test(cursor)) return void 0;
|
|
65499
|
+
try {
|
|
65500
|
+
const value = Buffer.from(cursor, "base64url");
|
|
65501
|
+
if (value.length !== CURSOR_BYTES) return void 0;
|
|
65502
|
+
const created = Number(value.readBigUInt64BE());
|
|
65503
|
+
if (!Number.isSafeInteger(created)) return void 0;
|
|
65504
|
+
return [created, value.subarray(8).toString("hex")];
|
|
65505
|
+
} catch {
|
|
65506
|
+
return;
|
|
65507
|
+
}
|
|
65508
|
+
}
|
|
65509
|
+
function conversationImageId(origin, source) {
|
|
65510
|
+
return createHash("sha256").update(`${origin}:${source}`).digest("hex");
|
|
65511
|
+
}
|
|
65512
|
+
function pageConversationImages(images, limit = 5, cursor) {
|
|
65513
|
+
const after = readCursor(cursor);
|
|
65514
|
+
if (cursor && !after) throw new Error("Invalid conversation image cursor");
|
|
65515
|
+
const ordered = images.filter((image) => !after || image.created < after[0] || image.created === after[0] && image.id < after[1]).sort((a, b) => b.created - a.created || b.id.localeCompare(a.id));
|
|
65516
|
+
const page = ordered.slice(0, limit);
|
|
65517
|
+
return {
|
|
65518
|
+
images: page,
|
|
65519
|
+
...ordered.length > page.length ? { nextCursor: cursorFor(page.at(-1)) } : {}
|
|
65520
|
+
};
|
|
65521
|
+
}
|
|
65522
|
+
async function readConversationImages(path) {
|
|
65523
|
+
try {
|
|
65524
|
+
const value = JSON.parse(await readFile(path, "utf8"));
|
|
65525
|
+
return Array.isArray(value) ? value : [];
|
|
65526
|
+
} catch (error) {
|
|
65527
|
+
if (error.code === "ENOENT") return [];
|
|
65528
|
+
throw error;
|
|
65529
|
+
}
|
|
65530
|
+
}
|
|
65531
|
+
async function withAvailability(images) {
|
|
65532
|
+
return Promise.all(images.map(async (image) => {
|
|
65533
|
+
try {
|
|
65534
|
+
await access(image.path);
|
|
65535
|
+
return {
|
|
65536
|
+
...image,
|
|
65537
|
+
available: true
|
|
65538
|
+
};
|
|
65539
|
+
} catch {
|
|
65540
|
+
return {
|
|
65541
|
+
...image,
|
|
65542
|
+
available: false
|
|
65543
|
+
};
|
|
65544
|
+
}
|
|
65545
|
+
}));
|
|
65546
|
+
}
|
|
65547
|
+
/** Atomic metadata projection shared by the HTTP host and the standalone MCP. */
|
|
65548
|
+
async function writeConversationImages(path, images) {
|
|
65549
|
+
await mkdir(dirname(path), {
|
|
65550
|
+
recursive: true,
|
|
65551
|
+
mode: 448
|
|
65552
|
+
});
|
|
65553
|
+
const target = resolve(path);
|
|
65554
|
+
const temporary = `${target}.${process.pid}.${randomUUID()}.tmp`;
|
|
65555
|
+
await writeFile(temporary, `${JSON.stringify(images)}\n`, { mode: 384 });
|
|
65556
|
+
await rename(temporary, target);
|
|
65557
|
+
}
|
|
65481
65558
|
const HISTORY_PAGE_MESSAGES = 50;
|
|
65482
65559
|
/** Match DSH's 50-message history window against CFL's rendered projection. */
|
|
65483
65560
|
function visibleHistoryPage(messages, results, before) {
|
|
@@ -65654,6 +65731,9 @@ function historyImage(path, operationId, index) {
|
|
|
65654
65731
|
function noHistoryYet(error) {
|
|
65655
65732
|
return error instanceof AppServerInvalidRequestError && error.rpcMessage.includes("thread/turns/list is unavailable before first user message");
|
|
65656
65733
|
}
|
|
65734
|
+
function noRolloutForThread(error) {
|
|
65735
|
+
return error instanceof AppServerInvalidRequestError && error.rpcMessage.startsWith("no rollout found for thread id ");
|
|
65736
|
+
}
|
|
65657
65737
|
function rpcMessage(error) {
|
|
65658
65738
|
return error instanceof AppServerInvalidRequestError ? error.rpcMessage : void 0;
|
|
65659
65739
|
}
|
|
@@ -65770,6 +65850,24 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
65770
65850
|
recursive: true,
|
|
65771
65851
|
mode: 448
|
|
65772
65852
|
});
|
|
65853
|
+
const catalogue = new Map((await readConversationImages(paths.conversationImages)).map((image) => [image.id, image]));
|
|
65854
|
+
let reconcilingCatalogue = false;
|
|
65855
|
+
let reconciledCatalogueIds = /* @__PURE__ */ new Set();
|
|
65856
|
+
async function catalogueImage(origin, image, created) {
|
|
65857
|
+
const id = conversationImageId(origin, `${image.operation_id}:${image.id}`);
|
|
65858
|
+
const previous = catalogue.get(id);
|
|
65859
|
+
catalogue.set(id, {
|
|
65860
|
+
id,
|
|
65861
|
+
filename: image.name,
|
|
65862
|
+
path: resolve(image.path),
|
|
65863
|
+
mediaType: image.media_type,
|
|
65864
|
+
created: reconcilingCatalogue ? created : previous?.created ?? created,
|
|
65865
|
+
origin,
|
|
65866
|
+
available: true
|
|
65867
|
+
});
|
|
65868
|
+
reconciledCatalogueIds.add(id);
|
|
65869
|
+
if (!reconcilingCatalogue) await writeConversationImages(paths.conversationImages, await withAvailability([...catalogue.values()]));
|
|
65870
|
+
}
|
|
65773
65871
|
const store = new Store(paths.database);
|
|
65774
65872
|
const now = dependencies.now ?? Date.now;
|
|
65775
65873
|
const listeners = /* @__PURE__ */ new Set();
|
|
@@ -65801,7 +65899,6 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
65801
65899
|
let unsubscribeAppServer = [];
|
|
65802
65900
|
let startupPending = false;
|
|
65803
65901
|
let compacting = false;
|
|
65804
|
-
let compactWaiter;
|
|
65805
65902
|
let eventChain = Promise.resolve();
|
|
65806
65903
|
let admission = Promise.resolve();
|
|
65807
65904
|
let closePromise;
|
|
@@ -65977,7 +66074,7 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
65977
66074
|
if (previous?.status === "replaced") return;
|
|
65978
66075
|
if (previous?.status !== "attachment-error" || previous.error !== error) await store.markOutcome(owner, "attachment-error", error);
|
|
65979
66076
|
}
|
|
65980
|
-
async function projectGeneratedImage(operationId, sourceIds, item) {
|
|
66077
|
+
async function projectGeneratedImage(operationId, sourceIds, item, created) {
|
|
65981
66078
|
if (item.type !== "imageGeneration") return void 0;
|
|
65982
66079
|
if (item.status === "failed") {
|
|
65983
66080
|
processError("image.generation_failed", new Error(imageFailure("failed")), {
|
|
@@ -65992,6 +66089,7 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
65992
66089
|
const existing = await store.generatedImageForItem(operationId, itemId);
|
|
65993
66090
|
if (existing) try {
|
|
65994
66091
|
await access(existing.path);
|
|
66092
|
+
await catalogueImage("partner", existing, created);
|
|
65995
66093
|
return existing.id;
|
|
65996
66094
|
} catch {
|
|
65997
66095
|
storageError = true;
|
|
@@ -66014,6 +66112,7 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66014
66112
|
return;
|
|
66015
66113
|
}
|
|
66016
66114
|
await store.saveGeneratedImage(generated, itemId);
|
|
66115
|
+
await catalogueImage("partner", generated, created);
|
|
66017
66116
|
return generated.id;
|
|
66018
66117
|
} catch (error) {
|
|
66019
66118
|
storageError = true;
|
|
@@ -66104,6 +66203,7 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66104
66203
|
await store.ensureMessage(sourceId, turnTime(turn.startedAt, now()), source.input, source.images);
|
|
66105
66204
|
messageIds.add(sourceId);
|
|
66106
66205
|
}
|
|
66206
|
+
if (!sourceId.startsWith("keet:")) for (const image of source.images) await catalogueImage(isUnder(join(paths.managedRoot, "historical-media"), image.path) ? "historical" : "owner", image, turnTime(turn.startedAt, now()));
|
|
66107
66207
|
await store.markObserved(sourceId, segment);
|
|
66108
66208
|
}
|
|
66109
66209
|
acknowledgeInputIds(officialIds);
|
|
@@ -66116,7 +66216,7 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66116
66216
|
const completedAt = status === "completed" ? completedTurnTime(turn.completedAt) : void 0;
|
|
66117
66217
|
for (const item of turn.items ?? []) {
|
|
66118
66218
|
if (item.type !== "imageGeneration") continue;
|
|
66119
|
-
const generatedId = await projectGeneratedImage(resultOperationId(turn.id), sourceIds, item);
|
|
66219
|
+
const generatedId = await projectGeneratedImage(resultOperationId(turn.id), sourceIds, item, completedTurnTime(turn.completedAt) ?? turnTime(turn.startedAt, now()));
|
|
66120
66220
|
if (generatedId) generatedIds.push(generatedId);
|
|
66121
66221
|
else if (item.status === "failed") {
|
|
66122
66222
|
resultStatus = "failed";
|
|
@@ -66146,15 +66246,23 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66146
66246
|
}
|
|
66147
66247
|
/** Full history is hydrated once at startup/resume; events update one turn thereafter. */
|
|
66148
66248
|
async function hydrateHistory() {
|
|
66249
|
+
reconcilingCatalogue = true;
|
|
66250
|
+
reconciledCatalogueIds = /* @__PURE__ */ new Set();
|
|
66149
66251
|
const nextTurns = await listTurns();
|
|
66150
66252
|
turns.clear();
|
|
66151
66253
|
turnInputs.clear();
|
|
66152
66254
|
turnResults.clear();
|
|
66153
66255
|
presentationFingerprints.clear();
|
|
66154
|
-
|
|
66155
|
-
|
|
66156
|
-
|
|
66157
|
-
|
|
66256
|
+
try {
|
|
66257
|
+
for (const turn of nextTurns) {
|
|
66258
|
+
registerTurn(turn);
|
|
66259
|
+
const complete = await reconcileTurn(turn.id, turn);
|
|
66260
|
+
if (complete) await projectTurn(complete, false);
|
|
66261
|
+
}
|
|
66262
|
+
} finally {
|
|
66263
|
+
reconcilingCatalogue = false;
|
|
66264
|
+
for (const id of catalogue.keys()) if (!reconciledCatalogueIds.has(id)) catalogue.delete(id);
|
|
66265
|
+
await writeConversationImages(paths.conversationImages, await withAvailability([...catalogue.values()]));
|
|
66158
66266
|
}
|
|
66159
66267
|
const unresolved = await unresolvedMessages();
|
|
66160
66268
|
for (const message of unresolved) unresolvedInputIds.add(message.id);
|
|
@@ -66307,7 +66415,7 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66307
66415
|
}
|
|
66308
66416
|
}
|
|
66309
66417
|
function drainRejectedSteers() {
|
|
66310
|
-
if (closing || activeTurnId || recoveryPromise || !rejectedSteers.length) return recoveryPromise;
|
|
66418
|
+
if (closing || compacting || activeTurnId || recoveryPromise || !rejectedSteers.length) return recoveryPromise;
|
|
66311
66419
|
const intents = rejectedSteers.splice(0);
|
|
66312
66420
|
const ids = intents.flatMap((intent) => intent.ids);
|
|
66313
66421
|
const merged = {
|
|
@@ -66331,7 +66439,7 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66331
66439
|
}
|
|
66332
66440
|
function drainKeet() {
|
|
66333
66441
|
admission = admission.then(async () => {
|
|
66334
|
-
if (closing || activeTurnId || recoveryPromise || !keetEnabled) return;
|
|
66442
|
+
if (closing || compacting || activeTurnId || recoveryPromise || !keetEnabled) return;
|
|
66335
66443
|
const pending = (await store.pendingMessages()).filter((item) => item.id.startsWith("keet:") && !observedInputIds.has(item.id));
|
|
66336
66444
|
if (!pending.length || activeTurnId || closing) return;
|
|
66337
66445
|
const first = pending[0];
|
|
@@ -66433,11 +66541,11 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66433
66541
|
scheduleKeetReconnect();
|
|
66434
66542
|
});
|
|
66435
66543
|
}
|
|
66436
|
-
async function restoreUnconsumed(turnId) {
|
|
66544
|
+
async function restoreUnconsumed(turnId, preserveQueued = false) {
|
|
66437
66545
|
const ids = turnId ? [...sourceIdsForTurn(turnId)] : [];
|
|
66438
66546
|
const selectedSteers = pendingSteers.filter((intent) => turnId === void 0 || intent.turnId === turnId);
|
|
66439
66547
|
const selectedStarts = [...pendingStarts.values()].filter((intent) => turnId === void 0 || intent.turnId === turnId);
|
|
66440
|
-
const selectedRejected = rejectedSteers.filter((intent) => turnId === void 0 || intent.turnId === turnId);
|
|
66548
|
+
const selectedRejected = preserveQueued ? [] : rejectedSteers.filter((intent) => turnId === void 0 || intent.turnId === turnId);
|
|
66441
66549
|
for (const intent of selectedSteers) ids.push(...intent.ids);
|
|
66442
66550
|
for (const intent of selectedStarts) ids.push(...intent.ids);
|
|
66443
66551
|
for (const intent of selectedRejected) ids.push(...intent.ids);
|
|
@@ -66505,18 +66613,14 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66505
66613
|
endedAt: boundary.time
|
|
66506
66614
|
};
|
|
66507
66615
|
await refreshBootstrap();
|
|
66508
|
-
compactWaiter?.resolve();
|
|
66509
|
-
compactWaiter = void 0;
|
|
66510
66616
|
}
|
|
66511
|
-
function failCompaction(
|
|
66617
|
+
function failCompaction() {
|
|
66512
66618
|
if (lifecycle?.status === "running") lifecycle = {
|
|
66513
66619
|
...lifecycle,
|
|
66514
66620
|
status: "failed",
|
|
66515
66621
|
endSeq: eventSequence,
|
|
66516
66622
|
endedAt: now()
|
|
66517
66623
|
};
|
|
66518
|
-
compactWaiter?.reject(error instanceof Error ? error : new Error(String(error)));
|
|
66519
|
-
compactWaiter = void 0;
|
|
66520
66624
|
}
|
|
66521
66625
|
async function handleServerEvent(notification) {
|
|
66522
66626
|
if (closing) return;
|
|
@@ -66598,11 +66702,14 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66598
66702
|
turnControllers.delete(turn.id);
|
|
66599
66703
|
}
|
|
66600
66704
|
if (reconciled && (turnStatus(reconciled) === "interrupted" || turnStatus(reconciled) === "cancelled")) await restoreUnconsumed(completedTurnId);
|
|
66601
|
-
else if (reconciled && !userItems(reconciled).length && completedTurnId) await restoreUnconsumed(completedTurnId);
|
|
66705
|
+
else if (reconciled && !userItems(reconciled).length && completedTurnId) await restoreUnconsumed(completedTurnId, turnStatus(reconciled) === "completed");
|
|
66602
66706
|
syncActiveTurn();
|
|
66603
66707
|
if (compacting) {
|
|
66604
66708
|
compacting = false;
|
|
66605
|
-
if (lifecycle?.status === "running")
|
|
66709
|
+
if (lifecycle?.status === "running") {
|
|
66710
|
+
if (turnStatus(reconciled) === "completed") await finishCompaction(reconciled?.id);
|
|
66711
|
+
else failCompaction();
|
|
66712
|
+
}
|
|
66606
66713
|
}
|
|
66607
66714
|
await refreshBootstrap();
|
|
66608
66715
|
if (!activeTurnId) {
|
|
@@ -66626,6 +66733,9 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66626
66733
|
if (notification.method === "turn/started") {
|
|
66627
66734
|
const turn = registerTurn(record(notification.params).turn);
|
|
66628
66735
|
if (turn) {
|
|
66736
|
+
if (compacting) {
|
|
66737
|
+
for (const intent of rejectedSteers) if (!intent.turnId) intent.turnId = turn.id;
|
|
66738
|
+
}
|
|
66629
66739
|
activeTurnId = turn.id;
|
|
66630
66740
|
activeOperationId = sourceIdsForTurn(turn.id)[0] ?? activeOperationId;
|
|
66631
66741
|
if (!turnControllers.has(turn.id)) turnControllers.set(turn.id, new AbortController());
|
|
@@ -66723,29 +66833,44 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66723
66833
|
} : {}
|
|
66724
66834
|
}
|
|
66725
66835
|
};
|
|
66836
|
+
const connectedAppServer = appServer;
|
|
66837
|
+
if (!connectedAppServer) throw new Error("Codex app-server connection was not initialized");
|
|
66726
66838
|
let response;
|
|
66727
|
-
|
|
66728
|
-
|
|
66729
|
-
...shared,
|
|
66730
|
-
threadId: marker.threadId,
|
|
66731
|
-
excludeTurns: true
|
|
66732
|
-
};
|
|
66733
|
-
response = await appServer.call("thread/resume", resume);
|
|
66734
|
-
threadId = response.thread.id;
|
|
66735
|
-
} else {
|
|
66839
|
+
let resumed = false;
|
|
66840
|
+
const startThread = async () => {
|
|
66736
66841
|
const start = {
|
|
66737
66842
|
...shared,
|
|
66738
66843
|
historyMode: "paginated",
|
|
66739
66844
|
sessionStartSource: "startup"
|
|
66740
66845
|
};
|
|
66741
|
-
|
|
66742
|
-
threadId =
|
|
66846
|
+
const started = await connectedAppServer.call("thread/start", start);
|
|
66847
|
+
threadId = started.thread.id;
|
|
66743
66848
|
if (!threadId) throw new Error("Codex app-server did not return a thread id");
|
|
66744
66849
|
await writeFile(markerPath, JSON.stringify({
|
|
66745
66850
|
threadId,
|
|
66746
66851
|
model: config.codex.model
|
|
66747
66852
|
}), { mode: 384 });
|
|
66748
|
-
|
|
66853
|
+
return started;
|
|
66854
|
+
};
|
|
66855
|
+
if (marker?.threadId) {
|
|
66856
|
+
const resume = {
|
|
66857
|
+
...shared,
|
|
66858
|
+
threadId: marker.threadId,
|
|
66859
|
+
excludeTurns: true
|
|
66860
|
+
};
|
|
66861
|
+
try {
|
|
66862
|
+
response = await connectedAppServer.call("thread/resume", resume);
|
|
66863
|
+
threadId = response.thread.id;
|
|
66864
|
+
resumed = true;
|
|
66865
|
+
} catch (error) {
|
|
66866
|
+
if (!noRolloutForThread(error) || messageIds.size) throw error;
|
|
66867
|
+
await unlink(markerPath);
|
|
66868
|
+
marker = void 0;
|
|
66869
|
+
startupPending = true;
|
|
66870
|
+
await refreshBootstrap();
|
|
66871
|
+
response = await startThread();
|
|
66872
|
+
}
|
|
66873
|
+
} else response = await startThread();
|
|
66749
66874
|
const readinessDeadline = Date.now() + 1e4;
|
|
66750
66875
|
for (;;) {
|
|
66751
66876
|
const mcpStatuses = [];
|
|
@@ -66765,7 +66890,7 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66765
66890
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
66766
66891
|
}
|
|
66767
66892
|
if (response.model !== void 0 && response.model !== config.codex.model) throw new Error(`Codex selected ${String(response.model)} instead of configured ${config.codex.model}`);
|
|
66768
|
-
if (marker?.threadId && marker.model !== config.codex.model) await writeFile(markerPath, JSON.stringify({
|
|
66893
|
+
if (resumed && marker?.threadId && marker.model !== config.codex.model) await writeFile(markerPath, JSON.stringify({
|
|
66769
66894
|
threadId,
|
|
66770
66895
|
model: config.codex.model
|
|
66771
66896
|
}), { mode: 384 });
|
|
@@ -66778,7 +66903,6 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66778
66903
|
closing = true;
|
|
66779
66904
|
for (const unsubscribe of unsubscribeAppServer.splice(0)) unsubscribe();
|
|
66780
66905
|
for (const controller of turnControllers.values()) controller.abort();
|
|
66781
|
-
compactWaiter?.reject(error instanceof Error ? error : new Error(String(error)));
|
|
66782
66906
|
await appServer?.close().catch(() => void 0);
|
|
66783
66907
|
await store.close().catch(() => void 0);
|
|
66784
66908
|
throw error;
|
|
@@ -66841,6 +66965,34 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66841
66965
|
return;
|
|
66842
66966
|
}
|
|
66843
66967
|
},
|
|
66968
|
+
async conversationImages(options = {}) {
|
|
66969
|
+
await eventChain;
|
|
66970
|
+
const page = pageConversationImages(await withAvailability([...catalogue.values()]), options.limit ?? 5, options.cursor);
|
|
66971
|
+
return {
|
|
66972
|
+
images: page.images.map(({ id, filename, mediaType, created, origin, available }) => ({
|
|
66973
|
+
id,
|
|
66974
|
+
filename,
|
|
66975
|
+
mediaType,
|
|
66976
|
+
created,
|
|
66977
|
+
origin,
|
|
66978
|
+
available,
|
|
66979
|
+
url: `/api/conversation-images/${id}`
|
|
66980
|
+
})),
|
|
66981
|
+
...page.nextCursor ? { nextCursor: page.nextCursor } : {}
|
|
66982
|
+
};
|
|
66983
|
+
},
|
|
66984
|
+
async conversationImage(id) {
|
|
66985
|
+
const image = catalogue.get(id);
|
|
66986
|
+
if (!image) return void 0;
|
|
66987
|
+
try {
|
|
66988
|
+
return {
|
|
66989
|
+
media_type: image.mediaType,
|
|
66990
|
+
data: await readFile(image.path)
|
|
66991
|
+
};
|
|
66992
|
+
} catch {
|
|
66993
|
+
return;
|
|
66994
|
+
}
|
|
66995
|
+
},
|
|
66844
66996
|
avatar: (kind) => avatars[kind],
|
|
66845
66997
|
async petAsset(activity) {
|
|
66846
66998
|
return pet ? localPetClip(config.state, activity) : void 0;
|
|
@@ -66968,7 +67120,6 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66968
67120
|
if (replaces.length) await setRestoredDraft([...unresolvedInputIds]);
|
|
66969
67121
|
await eventChain;
|
|
66970
67122
|
syncActiveTurn();
|
|
66971
|
-
if (rejectedSteers.length) await (drainRejectedSteers() ?? Promise.resolve());
|
|
66972
67123
|
const intent = {
|
|
66973
67124
|
ids: [id],
|
|
66974
67125
|
input,
|
|
@@ -66976,6 +67127,12 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66976
67127
|
transportId: id,
|
|
66977
67128
|
source: "owner"
|
|
66978
67129
|
};
|
|
67130
|
+
if (compacting && !activeTurnId) {
|
|
67131
|
+
rejectedSteers.push(intent);
|
|
67132
|
+
notify();
|
|
67133
|
+
return;
|
|
67134
|
+
}
|
|
67135
|
+
if (rejectedSteers.length) await (drainRejectedSteers() ?? Promise.resolve());
|
|
66979
67136
|
if (activeTurnId) await steerIntent(intent, activeTurnId);
|
|
66980
67137
|
else await startIntent(intent);
|
|
66981
67138
|
notify();
|
|
@@ -67009,27 +67166,15 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
67009
67166
|
startedAt: now()
|
|
67010
67167
|
};
|
|
67011
67168
|
compacting = true;
|
|
67012
|
-
|
|
67013
|
-
compactWaiter = {
|
|
67014
|
-
resolve: resolveWait,
|
|
67015
|
-
reject: rejectWait
|
|
67016
|
-
};
|
|
67017
|
-
});
|
|
67018
|
-
let timeout;
|
|
67169
|
+
notify();
|
|
67019
67170
|
try {
|
|
67020
67171
|
await appServer.call("thread/compact/start", { threadId });
|
|
67021
|
-
await Promise.race([wait, new Promise((_, reject) => {
|
|
67022
|
-
timeout = setTimeout(() => reject(/* @__PURE__ */ new Error("Codex compaction timed out")), 6e4);
|
|
67023
|
-
})]);
|
|
67024
67172
|
} catch (error) {
|
|
67025
67173
|
compacting = false;
|
|
67026
|
-
failCompaction(
|
|
67174
|
+
failCompaction();
|
|
67027
67175
|
processError("compaction.failed", error);
|
|
67028
67176
|
notify();
|
|
67029
67177
|
throw error;
|
|
67030
|
-
} finally {
|
|
67031
|
-
if (timeout) clearTimeout(timeout);
|
|
67032
|
-
compactWaiter = void 0;
|
|
67033
67178
|
}
|
|
67034
67179
|
notify();
|
|
67035
67180
|
});
|
|
@@ -67052,8 +67197,6 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
67052
67197
|
keetFeed?.close();
|
|
67053
67198
|
for (const unsubscribe of unsubscribeAppServer.splice(0)) unsubscribe();
|
|
67054
67199
|
for (const controller of turnControllers.values()) controller.abort();
|
|
67055
|
-
compactWaiter?.reject(/* @__PURE__ */ new Error("Partner is closing"));
|
|
67056
|
-
compactWaiter = void 0;
|
|
67057
67200
|
compacting = false;
|
|
67058
67201
|
const serverClose = appServer?.close() ?? Promise.resolve();
|
|
67059
67202
|
closePromise = (async () => {
|
|
@@ -67823,6 +67966,25 @@ function createWebServer(partner, assets, options = {}) {
|
|
|
67823
67966
|
response.end(image.data);
|
|
67824
67967
|
return;
|
|
67825
67968
|
}
|
|
67969
|
+
if (path === "/api/conversation-images" && request.method === "GET") {
|
|
67970
|
+
const params = Object.fromEntries(new URL(request.url, "http://localhost").searchParams);
|
|
67971
|
+
const options = object({
|
|
67972
|
+
limit: number().int().min(1).max(50).optional(),
|
|
67973
|
+
cursor: string().min(1).max(500).optional()
|
|
67974
|
+
}).strict().parse(params);
|
|
67975
|
+
return json(response, await partner.conversationImages(options));
|
|
67976
|
+
}
|
|
67977
|
+
if (path.startsWith("/api/conversation-images/") && request.method === "GET") {
|
|
67978
|
+
const id = string().regex(/^[a-f0-9]{64}$/u).parse(path.slice(25));
|
|
67979
|
+
const image = await partner.conversationImage(id);
|
|
67980
|
+
if (!image) return json(response, { error: "Image not found" }, 404);
|
|
67981
|
+
response.writeHead(200, {
|
|
67982
|
+
"content-type": image.media_type,
|
|
67983
|
+
"cache-control": "private, max-age=31536000, immutable"
|
|
67984
|
+
});
|
|
67985
|
+
response.end(image.data);
|
|
67986
|
+
return;
|
|
67987
|
+
}
|
|
67826
67988
|
if (path.startsWith("/api/audio/") && request.method === "GET") {
|
|
67827
67989
|
const id = string().regex(/^[a-f0-9]{64}\.mp3$/u).parse(path.slice(11));
|
|
67828
67990
|
const audio = await partner.audio(id.slice(0, -4));
|
|
@@ -67878,7 +68040,7 @@ function createWebServer(partner, assets, options = {}) {
|
|
|
67878
68040
|
}
|
|
67879
68041
|
if (path === "/api/compact" && request.method === "POST") {
|
|
67880
68042
|
await partner.compact();
|
|
67881
|
-
return json(response, { ok: true });
|
|
68043
|
+
return json(response, { ok: true }, 202);
|
|
67882
68044
|
}
|
|
67883
68045
|
if (path === "/api/cancel" && request.method === "POST") {
|
|
67884
68046
|
const { id } = object({ id: string().min(1).max(300) }).strict().parse(await body(request));
|
|
@@ -68037,7 +68199,7 @@ if (command === "credential") {
|
|
|
68037
68199
|
await partner.close();
|
|
68038
68200
|
process.exitCode = 1;
|
|
68039
68201
|
});
|
|
68040
|
-
app.server.listen(config.port,
|
|
68202
|
+
app.server.listen(config.port, config.listen_host, () => console.log(`Companion: http://${config.listen_host}:${config.port}`));
|
|
68041
68203
|
let stopping = false;
|
|
68042
68204
|
const stop = async () => {
|
|
68043
68205
|
if (stopping) return;
|