@lamplitisles/codex-for-love 0.5.0 → 0.6.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.CfdLiH0M.css +2 -0
- package/vendor/build/_app/immutable/chunks/B4it5vzu.js +1 -0
- package/vendor/build/_app/immutable/chunks/{BZwtE-rc.js → C4_NpwM1.js} +4 -4
- package/vendor/build/_app/immutable/chunks/CLwTq0ua.js +3 -0
- package/vendor/build/_app/immutable/chunks/hmUBTeUN.js +1 -0
- package/vendor/build/_app/immutable/entry/app.DWpdogiL.js +2 -0
- package/vendor/build/_app/immutable/entry/start.ZF-Jvc9b.js +1 -0
- package/vendor/build/_app/immutable/nodes/0.DsknM3BK.js +1 -0
- package/vendor/build/_app/immutable/nodes/1.Be8-HBRE.js +1 -0
- package/vendor/build/_app/immutable/nodes/2.Do9ypv2d.js +330 -0
- package/vendor/build/_app/version.json +1 -1
- package/vendor/build/index.html +10 -10
- package/vendor/runtime/cli.mjs +193 -20
- package/vendor/runtime/companion-mcp.mjs +150 -1
- package/vendor/build/_app/immutable/assets/0.CkWBasWr.css +0 -2
- package/vendor/build/_app/immutable/chunks/C2DTc7yw.js +0 -3
- package/vendor/build/_app/immutable/chunks/CyqZh0gB.js +0 -1
- package/vendor/build/_app/immutable/chunks/DFTMMhXH.js +0 -1
- package/vendor/build/_app/immutable/entry/app.Ci6fUWwj.js +0 -2
- package/vendor/build/_app/immutable/entry/start.DWuEW6S3.js +0 -1
- package/vendor/build/_app/immutable/nodes/0.C8SV4li-.js +0 -1
- package/vendor/build/_app/immutable/nodes/1.BQJiYb4b.js +0 -1
- package/vendor/build/_app/immutable/nodes/2.CReDueqi.js +0 -330
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"
|
|
1
|
+
{"version":"1790151901957"}
|
package/vendor/build/index.html
CHANGED
|
@@ -1,27 +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('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.
|
|
4
|
-
<link href="/_app/immutable/chunks/
|
|
5
|
-
<link href="/_app/immutable/chunks/
|
|
6
|
-
<link href="/_app/immutable/chunks/
|
|
7
|
-
<link href="/_app/immutable/entry/app.
|
|
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.ZF-Jvc9b.js" rel="modulepreload">
|
|
4
|
+
<link href="/_app/immutable/chunks/hmUBTeUN.js" rel="modulepreload">
|
|
5
|
+
<link href="/_app/immutable/chunks/CLwTq0ua.js" rel="modulepreload">
|
|
6
|
+
<link href="/_app/immutable/chunks/B4it5vzu.js" rel="modulepreload">
|
|
7
|
+
<link href="/_app/immutable/entry/app.DWpdogiL.js" rel="modulepreload">
|
|
8
8
|
<link href="/_app/immutable/chunks/uBIymjUX.js" rel="modulepreload">
|
|
9
9
|
<link href="/_app/immutable/chunks/xihTtKlq.js" rel="modulepreload">
|
|
10
|
-
<link href="/_app/immutable/nodes/0.
|
|
10
|
+
<link href="/_app/immutable/nodes/0.DsknM3BK.js" rel="modulepreload">
|
|
11
11
|
|
|
12
|
-
<link href="/_app/immutable/assets/0.
|
|
12
|
+
<link href="/_app/immutable/assets/0.CfdLiH0M.css" rel="stylesheet"></head>
|
|
13
13
|
<body data-sveltekit-preload-data="hover"><div style="display: contents">
|
|
14
14
|
<script>
|
|
15
15
|
{
|
|
16
|
-
|
|
16
|
+
__sveltekit_st3em4 = {
|
|
17
17
|
base: ""
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
const element = document.currentScript.parentElement;
|
|
21
21
|
|
|
22
22
|
Promise.all([
|
|
23
|
-
import("/_app/immutable/entry/start.
|
|
24
|
-
import("/_app/immutable/entry/app.
|
|
23
|
+
import("/_app/immutable/entry/start.ZF-Jvc9b.js"),
|
|
24
|
+
import("/_app/immutable/entry/app.DWpdogiL.js")
|
|
25
25
|
]).then(([kit, app]) => {
|
|
26
26
|
kit.start(app, element);
|
|
27
27
|
});
|
package/vendor/runtime/cli.mjs
CHANGED
|
@@ -63240,6 +63240,21 @@ var Store = class {
|
|
|
63240
63240
|
};
|
|
63241
63241
|
}));
|
|
63242
63242
|
}
|
|
63243
|
+
async messageMeta(id) {
|
|
63244
|
+
return this.transaction(() => {
|
|
63245
|
+
const row = this.db.prepare(`
|
|
63246
|
+
SELECT m.sequence,m.id,m.created,r.revision
|
|
63247
|
+
FROM message_meta m JOIN message_revisions r ON r.message_id=m.id
|
|
63248
|
+
WHERE m.id=?
|
|
63249
|
+
`).get(id);
|
|
63250
|
+
return row ? {
|
|
63251
|
+
id: row.id,
|
|
63252
|
+
created: Number(row.created),
|
|
63253
|
+
sequence: Number(row.sequence),
|
|
63254
|
+
revision: Number(row.revision)
|
|
63255
|
+
} : void 0;
|
|
63256
|
+
});
|
|
63257
|
+
}
|
|
63243
63258
|
async pendingMessages() {
|
|
63244
63259
|
return this.transaction(() => this.db.prepare(`
|
|
63245
63260
|
SELECT m.sequence,m.id,m.created,r.revision,p.input
|
|
@@ -64442,6 +64457,7 @@ function buildRollout(extraction, media, threadId, destination, persona, relatio
|
|
|
64442
64457
|
lastByTurn.set(record.turn, index);
|
|
64443
64458
|
}
|
|
64444
64459
|
});
|
|
64460
|
+
const startedAtByTurn = new Map([...firstByTurn].map(([turn, index]) => [turn, Math.floor(extraction.records[index].time / 1e3)]));
|
|
64445
64461
|
for (const [index, record] of extraction.records.entries()) {
|
|
64446
64462
|
const timestamp = new Date(record.time).toISOString();
|
|
64447
64463
|
if (record.type === "compact") {
|
|
@@ -64480,6 +64496,7 @@ function buildRollout(extraction, media, threadId, destination, persona, relatio
|
|
|
64480
64496
|
type: "task_complete",
|
|
64481
64497
|
turn_id: turnId,
|
|
64482
64498
|
last_agent_message: null,
|
|
64499
|
+
started_at: Math.floor(record.time / 1e3),
|
|
64483
64500
|
completed_at: Math.floor(record.time / 1e3)
|
|
64484
64501
|
}, timestamp);
|
|
64485
64502
|
boundaries.push({
|
|
@@ -64492,10 +64509,11 @@ function buildRollout(extraction, media, threadId, destination, persona, relatio
|
|
|
64492
64509
|
continue;
|
|
64493
64510
|
}
|
|
64494
64511
|
const turnId = `turn-${record.turn}`;
|
|
64512
|
+
const startedAt = startedAtByTurn.get(record.turn);
|
|
64495
64513
|
if (firstByTurn.get(record.turn) === index) add("event_msg", {
|
|
64496
64514
|
type: "task_started",
|
|
64497
64515
|
turn_id: turnId,
|
|
64498
|
-
started_at:
|
|
64516
|
+
started_at: startedAt,
|
|
64499
64517
|
model_context_window: null,
|
|
64500
64518
|
collaboration_mode_kind: "default"
|
|
64501
64519
|
}, timestamp);
|
|
@@ -64551,7 +64569,7 @@ function buildRollout(extraction, media, threadId, destination, persona, relatio
|
|
|
64551
64569
|
type: "task_complete",
|
|
64552
64570
|
turn_id: turnId,
|
|
64553
64571
|
last_agent_message: record.type === "assistant" ? record.text : null,
|
|
64554
|
-
started_at:
|
|
64572
|
+
started_at: startedAt,
|
|
64555
64573
|
completed_at: Math.floor(record.time / 1e3),
|
|
64556
64574
|
duration_ms: null
|
|
64557
64575
|
}, timestamp);
|
|
@@ -65556,16 +65574,17 @@ async function writeConversationImages(path, images) {
|
|
|
65556
65574
|
await rename(temporary, target);
|
|
65557
65575
|
}
|
|
65558
65576
|
const HISTORY_PAGE_MESSAGES = 50;
|
|
65577
|
+
const HISTORICAL_FALLBACK_START = new Date(2026, 8, 1).getTime();
|
|
65559
65578
|
/** Match DSH's 50-message history window against CFL's rendered projection. */
|
|
65560
65579
|
function visibleHistoryPage(messages, results, before) {
|
|
65561
65580
|
const candidates = messages.filter((message) => before === void 0 || message.sequence < before);
|
|
65562
|
-
const
|
|
65581
|
+
const resultBySource = new Map(results.map((result) => [result.sourceIds.at(-1), result]));
|
|
65563
65582
|
const selected = [];
|
|
65564
65583
|
let visible = 0;
|
|
65565
65584
|
let index = candidates.length - 1;
|
|
65566
65585
|
for (; index >= 0; index -= 1) {
|
|
65567
65586
|
const message = candidates[index];
|
|
65568
|
-
const result =
|
|
65587
|
+
const result = resultBySource.get(message.id);
|
|
65569
65588
|
const units = 1 + (result ? result.answers.length + result.generatedIds.length + result.voiceIds.length + (result.error || [
|
|
65570
65589
|
"failed",
|
|
65571
65590
|
"interrupted",
|
|
@@ -65608,11 +65627,17 @@ function turnStatus(turn) {
|
|
|
65608
65627
|
function isActiveTurn(turn) {
|
|
65609
65628
|
return turnStatus(turn) === "inProgress" || turnStatus(turn) === "in_progress" || turnStatus(turn) === "active";
|
|
65610
65629
|
}
|
|
65611
|
-
function
|
|
65630
|
+
function recordedTurnTime(value) {
|
|
65612
65631
|
const number = numberOrNull(value);
|
|
65613
|
-
if (number === null) return
|
|
65632
|
+
if (number === null) return void 0;
|
|
65614
65633
|
return number > 1e10 ? Math.round(number) : Math.round(number * 1e3);
|
|
65615
65634
|
}
|
|
65635
|
+
function turnTime(value, fallback) {
|
|
65636
|
+
return recordedTurnTime(value) ?? fallback;
|
|
65637
|
+
}
|
|
65638
|
+
function historicalFallbackTime(sequence) {
|
|
65639
|
+
return HISTORICAL_FALLBACK_START + Math.max(0, sequence - 1) * 1e3;
|
|
65640
|
+
}
|
|
65616
65641
|
function completedTurnTime(value) {
|
|
65617
65642
|
const raw = numberOrNull(value);
|
|
65618
65643
|
if (raw === null) return void 0;
|
|
@@ -65623,7 +65648,7 @@ function inputTimeContext(source, now) {
|
|
|
65623
65648
|
const time = `${String(date.getHours()).padStart(2, "0")}:${String(date.getMinutes()).padStart(2, "0")}`;
|
|
65624
65649
|
return {
|
|
65625
65650
|
kind: "application",
|
|
65626
|
-
value: `${source === "
|
|
65651
|
+
value: `${source === "human" ? "Current human input" : "Qualifying Keet input"} received around local ${time}. Trusted delivery metadata; not user-authored text or an instruction.`
|
|
65627
65652
|
};
|
|
65628
65653
|
}
|
|
65629
65654
|
function textFromUserItem(item) {
|
|
@@ -65871,7 +65896,12 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
65871
65896
|
const store = new Store(paths.database);
|
|
65872
65897
|
const now = dependencies.now ?? Date.now;
|
|
65873
65898
|
const listeners = /* @__PURE__ */ new Set();
|
|
65874
|
-
const
|
|
65899
|
+
const storedMessages = await store.allMessages();
|
|
65900
|
+
const messageIds = new Set(storedMessages.map((message) => message.id));
|
|
65901
|
+
const messagesById = new Map(storedMessages.map((message) => [message.id, {
|
|
65902
|
+
created: message.created,
|
|
65903
|
+
sequence: message.sequence
|
|
65904
|
+
}]));
|
|
65875
65905
|
const turns = /* @__PURE__ */ new Map();
|
|
65876
65906
|
/** One turn owns an ordered list of application input identities. */
|
|
65877
65907
|
const turnInputs = /* @__PURE__ */ new Map();
|
|
@@ -66068,11 +66098,11 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66068
66098
|
return status === "failed" ? "Native image generation failed" : "Native image artifact unavailable";
|
|
66069
66099
|
}
|
|
66070
66100
|
async function markAttachmentError(sourceIds, error) {
|
|
66071
|
-
const
|
|
66072
|
-
if (!
|
|
66073
|
-
const previous = await store.outcome(
|
|
66101
|
+
const sourceId = sourceIds.at(-1);
|
|
66102
|
+
if (!sourceId) return;
|
|
66103
|
+
const previous = await store.outcome(sourceId);
|
|
66074
66104
|
if (previous?.status === "replaced") return;
|
|
66075
|
-
if (previous?.status !== "attachment-error" || previous.error !== error) await store.markOutcome(
|
|
66105
|
+
if (previous?.status !== "attachment-error" || previous.error !== error) await store.markOutcome(sourceId, "attachment-error", error);
|
|
66076
66106
|
}
|
|
66077
66107
|
async function projectGeneratedImage(operationId, sourceIds, item, created) {
|
|
66078
66108
|
if (item.type !== "imageGeneration") return void 0;
|
|
@@ -66089,7 +66119,7 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66089
66119
|
const existing = await store.generatedImageForItem(operationId, itemId);
|
|
66090
66120
|
if (existing) try {
|
|
66091
66121
|
await access(existing.path);
|
|
66092
|
-
await catalogueImage("
|
|
66122
|
+
await catalogueImage("agent", existing, created);
|
|
66093
66123
|
return existing.id;
|
|
66094
66124
|
} catch {
|
|
66095
66125
|
storageError = true;
|
|
@@ -66112,7 +66142,7 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66112
66142
|
return;
|
|
66113
66143
|
}
|
|
66114
66144
|
await store.saveGeneratedImage(generated, itemId);
|
|
66115
|
-
await catalogueImage("
|
|
66145
|
+
await catalogueImage("agent", generated, created);
|
|
66116
66146
|
return generated.id;
|
|
66117
66147
|
} catch (error) {
|
|
66118
66148
|
storageError = true;
|
|
@@ -66199,11 +66229,21 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66199
66229
|
text_offset: 0,
|
|
66200
66230
|
text_length: source.input.length
|
|
66201
66231
|
};
|
|
66202
|
-
|
|
66203
|
-
|
|
66232
|
+
let message = messagesById.get(sourceId);
|
|
66233
|
+
if (!message) {
|
|
66234
|
+
const created = turnTime(turn.startedAt, now());
|
|
66235
|
+
const stored = await store.ensureMessage(sourceId, created, source.input, source.images);
|
|
66204
66236
|
messageIds.add(sourceId);
|
|
66237
|
+
message = {
|
|
66238
|
+
created: stored.created,
|
|
66239
|
+
sequence: stored.sequence
|
|
66240
|
+
};
|
|
66241
|
+
messagesById.set(sourceId, message);
|
|
66242
|
+
}
|
|
66243
|
+
if (!sourceId.startsWith("keet:")) for (const image of source.images) {
|
|
66244
|
+
const origin = isUnder(join(paths.managedRoot, "historical-media"), image.path) ? "historical" : "human";
|
|
66245
|
+
await catalogueImage(origin, image, origin === "historical" ? recordedTurnTime(turn.startedAt) ?? historicalFallbackTime(message.sequence) : message.created);
|
|
66205
66246
|
}
|
|
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()));
|
|
66207
66247
|
await store.markObserved(sourceId, segment);
|
|
66208
66248
|
}
|
|
66209
66249
|
acknowledgeInputIds(officialIds);
|
|
@@ -66423,7 +66463,7 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
66423
66463
|
input: intents.map((intent) => intent.input).join("\n"),
|
|
66424
66464
|
images: intents.flatMap((intent) => intent.images),
|
|
66425
66465
|
transportId: clientIdForInputs(ids),
|
|
66426
|
-
source: intents.every((intent) => intent.source === "
|
|
66466
|
+
source: intents.every((intent) => intent.source === "human") ? "human" : "none"
|
|
66427
66467
|
};
|
|
66428
66468
|
recoveryPromise = (async () => {
|
|
66429
66469
|
try {
|
|
@@ -67108,6 +67148,11 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
67108
67148
|
const materialized = await materializeImages(paths.workspaceRoot, images);
|
|
67109
67149
|
await store.admit(id, input, materialized);
|
|
67110
67150
|
messageIds.add(id);
|
|
67151
|
+
const message = await store.messageMeta(id);
|
|
67152
|
+
if (message) messagesById.set(id, {
|
|
67153
|
+
created: message.created,
|
|
67154
|
+
sequence: message.sequence
|
|
67155
|
+
});
|
|
67111
67156
|
if (operationTurn(id) || pendingStarts.has(id) || pendingSteers.some((intent) => intent.ids.includes(id)) || await store.outcome(id)) return;
|
|
67112
67157
|
if (unresolvedInputIds.has(id) && !replaces.includes(id)) throw new Error("Message delivery is unresolved; inspect the conversation before retrying");
|
|
67113
67158
|
for (const replacedId of replaces) {
|
|
@@ -67125,7 +67170,7 @@ async function createPartner(config, credentials, dependencies = {}) {
|
|
|
67125
67170
|
input,
|
|
67126
67171
|
images: materialized,
|
|
67127
67172
|
transportId: id,
|
|
67128
|
-
source: "
|
|
67173
|
+
source: "human"
|
|
67129
67174
|
};
|
|
67130
67175
|
if (compacting && !activeTurnId) {
|
|
67131
67176
|
rejectedSteers.push(intent);
|
|
@@ -67938,6 +67983,27 @@ function createWebServer(partner, assets, options = {}) {
|
|
|
67938
67983
|
}).strict().refine((value) => value.before === void 0 || value.after === void 0).parse(params);
|
|
67939
67984
|
return json(response, await partner.snapshot(options));
|
|
67940
67985
|
}
|
|
67986
|
+
if (path === "/api/conversation-search" && request.method === "GET") {
|
|
67987
|
+
const params = Object.fromEntries(new URL(request.url, "http://localhost").searchParams);
|
|
67988
|
+
const parsed = object({ q: string().trim().min(1).max(500) }).strict().safeParse(params);
|
|
67989
|
+
if (!parsed.success) return json(response, { error: "Invalid search query" }, 400);
|
|
67990
|
+
try {
|
|
67991
|
+
if (!options.conversationSearch) throw new Error("Search unavailable");
|
|
67992
|
+
return json(response, await options.conversationSearch.search(parsed.data.q));
|
|
67993
|
+
} catch {
|
|
67994
|
+
return json(response, { error: "Search unavailable" }, 503);
|
|
67995
|
+
}
|
|
67996
|
+
}
|
|
67997
|
+
if (path.startsWith("/api/conversation-search/") && request.method === "GET") {
|
|
67998
|
+
const id = path.slice(25);
|
|
67999
|
+
if (!/^[a-f0-9]{64}$/u.test(id)) return json(response, { error: "Invalid record id" }, 400);
|
|
68000
|
+
try {
|
|
68001
|
+
if (!options.conversationSearch) throw new Error("Search unavailable");
|
|
68002
|
+
return json(response, await options.conversationSearch.read(id));
|
|
68003
|
+
} catch {
|
|
68004
|
+
return json(response, { error: "Record unavailable" }, 404);
|
|
68005
|
+
}
|
|
68006
|
+
}
|
|
67941
68007
|
if (path === "/api/diary" && request.method === "GET") try {
|
|
67942
68008
|
return json(response, { entries: await partner.diary() });
|
|
67943
68009
|
} catch {
|
|
@@ -68088,6 +68154,110 @@ function createWebServer(partner, assets, options = {}) {
|
|
|
68088
68154
|
};
|
|
68089
68155
|
}
|
|
68090
68156
|
//#endregion
|
|
68157
|
+
//#region apps/partner/runtime/conversation-search.ts
|
|
68158
|
+
const executeFile = promisify(execFile);
|
|
68159
|
+
const idSchema = string().regex(/^[a-f0-9]{64}$/u);
|
|
68160
|
+
const querySchema = string().trim().min(1).max(500);
|
|
68161
|
+
const resultSchema = object({
|
|
68162
|
+
query: string(),
|
|
68163
|
+
estimatedTotalHits: number$1().int().nonnegative(),
|
|
68164
|
+
hits: array(object({
|
|
68165
|
+
id: idSchema,
|
|
68166
|
+
kind: _enum(["message", "compaction"]),
|
|
68167
|
+
sessionId: string(),
|
|
68168
|
+
sessionName: string().optional(),
|
|
68169
|
+
cwd: string(),
|
|
68170
|
+
role: _enum(["user", "assistant"]).optional(),
|
|
68171
|
+
phase: _enum(["commentary", "final_answer"]).optional(),
|
|
68172
|
+
createdAt: string().optional(),
|
|
68173
|
+
snippet: string()
|
|
68174
|
+
})).max(20)
|
|
68175
|
+
});
|
|
68176
|
+
const recordSchema = object({
|
|
68177
|
+
id: idSchema,
|
|
68178
|
+
kind: _enum(["message", "compaction"]),
|
|
68179
|
+
sessionId: string(),
|
|
68180
|
+
sessionName: string().optional(),
|
|
68181
|
+
cwd: string(),
|
|
68182
|
+
role: _enum(["user", "assistant"]).optional(),
|
|
68183
|
+
phase: _enum(["commentary", "final_answer"]).optional(),
|
|
68184
|
+
createdAt: string().optional(),
|
|
68185
|
+
content: string()
|
|
68186
|
+
});
|
|
68187
|
+
const contextSchema = object({
|
|
68188
|
+
messageId: idSchema,
|
|
68189
|
+
targetSourceRecordIndex: number$1().int(),
|
|
68190
|
+
truncated: boolean(),
|
|
68191
|
+
items: array(object({
|
|
68192
|
+
sourceRecordIndex: number$1().int(),
|
|
68193
|
+
kind: _enum([
|
|
68194
|
+
"message",
|
|
68195
|
+
"compaction",
|
|
68196
|
+
"tool"
|
|
68197
|
+
]),
|
|
68198
|
+
role: _enum(["user", "assistant"]).optional(),
|
|
68199
|
+
phase: string().optional(),
|
|
68200
|
+
content: string(),
|
|
68201
|
+
truncated: boolean().optional()
|
|
68202
|
+
}))
|
|
68203
|
+
});
|
|
68204
|
+
function createConversationSearch(options) {
|
|
68205
|
+
const workspace = resolve(options.workspace);
|
|
68206
|
+
const env = {
|
|
68207
|
+
...process.env,
|
|
68208
|
+
...options.env,
|
|
68209
|
+
...options.codexHome ? { CODEX_HOME: options.codexHome } : {}
|
|
68210
|
+
};
|
|
68211
|
+
const binary = env.FLICKLOG_BIN ?? "flicklog";
|
|
68212
|
+
let pending = Promise.resolve();
|
|
68213
|
+
function run(args) {
|
|
68214
|
+
const task = pending.then(async () => {
|
|
68215
|
+
if (!env.FLICKLOG_MEILI_KEY && env.CREDENTIALS_DIRECTORY) try {
|
|
68216
|
+
env.FLICKLOG_MEILI_KEY = (await readFile(join(env.CREDENTIALS_DIRECTORY, "flicklog-meili-key"), "utf8")).trim();
|
|
68217
|
+
} catch (error) {
|
|
68218
|
+
if (error.code !== "ENOENT") throw error;
|
|
68219
|
+
}
|
|
68220
|
+
const { stdout } = await executeFile(binary, args, {
|
|
68221
|
+
cwd: workspace,
|
|
68222
|
+
env,
|
|
68223
|
+
timeout: 3e5,
|
|
68224
|
+
maxBuffer: 8388608,
|
|
68225
|
+
windowsHide: true
|
|
68226
|
+
});
|
|
68227
|
+
return JSON.parse(stdout);
|
|
68228
|
+
});
|
|
68229
|
+
pending = task.then(() => void 0, () => void 0);
|
|
68230
|
+
return task;
|
|
68231
|
+
}
|
|
68232
|
+
return {
|
|
68233
|
+
async search(query, limit = 20) {
|
|
68234
|
+
const q = querySchema.parse(query);
|
|
68235
|
+
const count = number$1().int().min(1).max(20).parse(limit);
|
|
68236
|
+
const value = object({ results: resultSchema }).parse(await run([
|
|
68237
|
+
"search",
|
|
68238
|
+
q,
|
|
68239
|
+
"--limit",
|
|
68240
|
+
String(count)
|
|
68241
|
+
]));
|
|
68242
|
+
return {
|
|
68243
|
+
...value.results,
|
|
68244
|
+
hits: value.results.hits.filter((hit) => resolve(hit.cwd) === workspace)
|
|
68245
|
+
};
|
|
68246
|
+
},
|
|
68247
|
+
async read(id) {
|
|
68248
|
+
const selected = idSchema.parse(id);
|
|
68249
|
+
const record = recordSchema.parse(await run(["get", selected]));
|
|
68250
|
+
if (resolve(record.cwd) !== workspace) throw new Error("Conversation record is outside this workspace");
|
|
68251
|
+
const context = contextSchema.parse(await run(["context", selected]));
|
|
68252
|
+
if (context.messageId !== selected) throw new Error("Conversation context does not match the record");
|
|
68253
|
+
return {
|
|
68254
|
+
record,
|
|
68255
|
+
context
|
|
68256
|
+
};
|
|
68257
|
+
}
|
|
68258
|
+
};
|
|
68259
|
+
}
|
|
68260
|
+
//#endregion
|
|
68091
68261
|
//#region apps/partner/runtime/migrate-relationship-journal.ts
|
|
68092
68262
|
/** One-time, explicit conversion of a legacy CFL relationship table. */
|
|
68093
68263
|
async function migrateRelationshipJournal(workspace) {
|
|
@@ -68189,7 +68359,10 @@ if (command === "credential") {
|
|
|
68189
68359
|
const partner = await createPartner(config, credentials);
|
|
68190
68360
|
let app;
|
|
68191
68361
|
try {
|
|
68192
|
-
app = createWebServer(partner, assets
|
|
68362
|
+
app = createWebServer(partner, assets, { conversationSearch: createConversationSearch({
|
|
68363
|
+
workspace: config.workspace,
|
|
68364
|
+
codexHome: config.codex.home
|
|
68365
|
+
}) });
|
|
68193
68366
|
} catch (error) {
|
|
68194
68367
|
await partner.close();
|
|
68195
68368
|
throw error;
|
|
@@ -23011,12 +23011,120 @@ async function withAvailability(images) {
|
|
|
23011
23011
|
}));
|
|
23012
23012
|
}
|
|
23013
23013
|
//#endregion
|
|
23014
|
+
//#region apps/partner/runtime/conversation-search.ts
|
|
23015
|
+
const executeFile = promisify(execFile);
|
|
23016
|
+
const idSchema = string().regex(/^[a-f0-9]{64}$/u);
|
|
23017
|
+
const querySchema = string().trim().min(1).max(500);
|
|
23018
|
+
const resultSchema = object({
|
|
23019
|
+
query: string(),
|
|
23020
|
+
estimatedTotalHits: number().int().nonnegative(),
|
|
23021
|
+
hits: array(object({
|
|
23022
|
+
id: idSchema,
|
|
23023
|
+
kind: _enum(["message", "compaction"]),
|
|
23024
|
+
sessionId: string(),
|
|
23025
|
+
sessionName: string().optional(),
|
|
23026
|
+
cwd: string(),
|
|
23027
|
+
role: _enum(["user", "assistant"]).optional(),
|
|
23028
|
+
phase: _enum(["commentary", "final_answer"]).optional(),
|
|
23029
|
+
createdAt: string().optional(),
|
|
23030
|
+
snippet: string()
|
|
23031
|
+
})).max(20)
|
|
23032
|
+
});
|
|
23033
|
+
const recordSchema = object({
|
|
23034
|
+
id: idSchema,
|
|
23035
|
+
kind: _enum(["message", "compaction"]),
|
|
23036
|
+
sessionId: string(),
|
|
23037
|
+
sessionName: string().optional(),
|
|
23038
|
+
cwd: string(),
|
|
23039
|
+
role: _enum(["user", "assistant"]).optional(),
|
|
23040
|
+
phase: _enum(["commentary", "final_answer"]).optional(),
|
|
23041
|
+
createdAt: string().optional(),
|
|
23042
|
+
content: string()
|
|
23043
|
+
});
|
|
23044
|
+
const contextSchema = object({
|
|
23045
|
+
messageId: idSchema,
|
|
23046
|
+
targetSourceRecordIndex: number().int(),
|
|
23047
|
+
truncated: boolean(),
|
|
23048
|
+
items: array(object({
|
|
23049
|
+
sourceRecordIndex: number().int(),
|
|
23050
|
+
kind: _enum([
|
|
23051
|
+
"message",
|
|
23052
|
+
"compaction",
|
|
23053
|
+
"tool"
|
|
23054
|
+
]),
|
|
23055
|
+
role: _enum(["user", "assistant"]).optional(),
|
|
23056
|
+
phase: string().optional(),
|
|
23057
|
+
content: string(),
|
|
23058
|
+
truncated: boolean().optional()
|
|
23059
|
+
}))
|
|
23060
|
+
});
|
|
23061
|
+
function createConversationSearch(options) {
|
|
23062
|
+
const workspace = resolve(options.workspace);
|
|
23063
|
+
const env = {
|
|
23064
|
+
...process.env,
|
|
23065
|
+
...options.env,
|
|
23066
|
+
...options.codexHome ? { CODEX_HOME: options.codexHome } : {}
|
|
23067
|
+
};
|
|
23068
|
+
const binary = env.FLICKLOG_BIN ?? "flicklog";
|
|
23069
|
+
let pending = Promise.resolve();
|
|
23070
|
+
function run(args) {
|
|
23071
|
+
const task = pending.then(async () => {
|
|
23072
|
+
if (!env.FLICKLOG_MEILI_KEY && env.CREDENTIALS_DIRECTORY) try {
|
|
23073
|
+
env.FLICKLOG_MEILI_KEY = (await readFile(join(env.CREDENTIALS_DIRECTORY, "flicklog-meili-key"), "utf8")).trim();
|
|
23074
|
+
} catch (error) {
|
|
23075
|
+
if (error.code !== "ENOENT") throw error;
|
|
23076
|
+
}
|
|
23077
|
+
const { stdout } = await executeFile(binary, args, {
|
|
23078
|
+
cwd: workspace,
|
|
23079
|
+
env,
|
|
23080
|
+
timeout: 3e5,
|
|
23081
|
+
maxBuffer: 8388608,
|
|
23082
|
+
windowsHide: true
|
|
23083
|
+
});
|
|
23084
|
+
return JSON.parse(stdout);
|
|
23085
|
+
});
|
|
23086
|
+
pending = task.then(() => void 0, () => void 0);
|
|
23087
|
+
return task;
|
|
23088
|
+
}
|
|
23089
|
+
return {
|
|
23090
|
+
async search(query, limit = 20) {
|
|
23091
|
+
const q = querySchema.parse(query);
|
|
23092
|
+
const count = number().int().min(1).max(20).parse(limit);
|
|
23093
|
+
const value = object({ results: resultSchema }).parse(await run([
|
|
23094
|
+
"search",
|
|
23095
|
+
q,
|
|
23096
|
+
"--limit",
|
|
23097
|
+
String(count)
|
|
23098
|
+
]));
|
|
23099
|
+
return {
|
|
23100
|
+
...value.results,
|
|
23101
|
+
hits: value.results.hits.filter((hit) => resolve(hit.cwd) === workspace)
|
|
23102
|
+
};
|
|
23103
|
+
},
|
|
23104
|
+
async read(id) {
|
|
23105
|
+
const selected = idSchema.parse(id);
|
|
23106
|
+
const record = recordSchema.parse(await run(["get", selected]));
|
|
23107
|
+
if (resolve(record.cwd) !== workspace) throw new Error("Conversation record is outside this workspace");
|
|
23108
|
+
const context = contextSchema.parse(await run(["context", selected]));
|
|
23109
|
+
if (context.messageId !== selected) throw new Error("Conversation context does not match the record");
|
|
23110
|
+
return {
|
|
23111
|
+
record,
|
|
23112
|
+
context
|
|
23113
|
+
};
|
|
23114
|
+
}
|
|
23115
|
+
};
|
|
23116
|
+
}
|
|
23117
|
+
//#endregion
|
|
23014
23118
|
//#region apps/partner/runtime/companion-mcp.ts
|
|
23015
23119
|
const workspace = process.argv[2];
|
|
23016
23120
|
if (!workspace) throw new Error("Companion MCP requires a workspace path");
|
|
23017
23121
|
const configPath = process.argv[3];
|
|
23018
23122
|
const journal = partnerPaths(workspace).relationshipJournal;
|
|
23019
23123
|
const conversationImages = partnerPaths(workspace).conversationImages;
|
|
23124
|
+
const conversationSearch = createConversationSearch({
|
|
23125
|
+
workspace,
|
|
23126
|
+
codexHome: configPath ? (await loadConfig(configPath)).codex.home : void 0
|
|
23127
|
+
});
|
|
23020
23128
|
const server = new McpServer({
|
|
23021
23129
|
name: "companion",
|
|
23022
23130
|
version: "0.1.0"
|
|
@@ -23060,7 +23168,7 @@ server.registerTool("read_relationship_history", {
|
|
|
23060
23168
|
text: JSON.stringify((await readRelationshipJournal(journal)).reverse().slice(0, canonicalizeHistoryRead(input)))
|
|
23061
23169
|
}] }));
|
|
23062
23170
|
server.registerTool("list_photos", {
|
|
23063
|
-
description: "List our shared photo library:
|
|
23171
|
+
description: "List our shared photo library: human-sent, Agent-generated, and restored historical conversation images, newest first in bounded pages. Returned local paths may be inspected deliberately with native tools.",
|
|
23064
23172
|
inputSchema: {
|
|
23065
23173
|
limit: number().int().min(1).max(50).optional(),
|
|
23066
23174
|
cursor: string().regex(/^[A-Za-z0-9_-]{54}$/u).optional()
|
|
@@ -23083,6 +23191,47 @@ server.registerTool("list_photos", {
|
|
|
23083
23191
|
})
|
|
23084
23192
|
}] };
|
|
23085
23193
|
});
|
|
23194
|
+
server.registerTool("search_conversation", {
|
|
23195
|
+
description: "Find text in our conversation records. Returns bounded highlighted excerpts; read a selected record for its full text and nearby context.",
|
|
23196
|
+
inputSchema: {
|
|
23197
|
+
query: string().trim().min(1).max(500),
|
|
23198
|
+
limit: number().int().min(1).max(20).optional()
|
|
23199
|
+
}
|
|
23200
|
+
}, async ({ query, limit }) => {
|
|
23201
|
+
try {
|
|
23202
|
+
return { content: [{
|
|
23203
|
+
type: "text",
|
|
23204
|
+
text: JSON.stringify(await conversationSearch.search(query, limit ?? 5))
|
|
23205
|
+
}] };
|
|
23206
|
+
} catch {
|
|
23207
|
+
return {
|
|
23208
|
+
content: [{
|
|
23209
|
+
type: "text",
|
|
23210
|
+
text: "Conversation search is unavailable"
|
|
23211
|
+
}],
|
|
23212
|
+
isError: true
|
|
23213
|
+
};
|
|
23214
|
+
}
|
|
23215
|
+
});
|
|
23216
|
+
server.registerTool("read_conversation_record", {
|
|
23217
|
+
description: "Read one selected conversation search result in full with nearby context.",
|
|
23218
|
+
inputSchema: { id: string().regex(/^[a-f0-9]{64}$/u) }
|
|
23219
|
+
}, async ({ id }) => {
|
|
23220
|
+
try {
|
|
23221
|
+
return { content: [{
|
|
23222
|
+
type: "text",
|
|
23223
|
+
text: JSON.stringify(await conversationSearch.read(id))
|
|
23224
|
+
}] };
|
|
23225
|
+
} catch {
|
|
23226
|
+
return {
|
|
23227
|
+
content: [{
|
|
23228
|
+
type: "text",
|
|
23229
|
+
text: "Conversation record is unavailable"
|
|
23230
|
+
}],
|
|
23231
|
+
isError: true
|
|
23232
|
+
};
|
|
23233
|
+
}
|
|
23234
|
+
});
|
|
23086
23235
|
server.registerTool("roll_dice", {
|
|
23087
23236
|
description: "Roll dice with an optional modifier and label.",
|
|
23088
23237
|
inputSchema: {
|