open-think 0.3.4 → 0.3.5
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/dist/index.js +354 -236
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -39,8 +39,8 @@ import {
|
|
|
39
39
|
} from "./chunk-HUBRLTY3.js";
|
|
40
40
|
|
|
41
41
|
// src/index.ts
|
|
42
|
-
import
|
|
43
|
-
import
|
|
42
|
+
import fs13 from "fs";
|
|
43
|
+
import path7 from "path";
|
|
44
44
|
import { Command as Command20 } from "commander";
|
|
45
45
|
|
|
46
46
|
// src/commands/log.ts
|
|
@@ -1977,6 +1977,103 @@ cortexCommand.addCommand(autoCurateCommand);
|
|
|
1977
1977
|
import { Command as Command10 } from "commander";
|
|
1978
1978
|
import readline3 from "readline";
|
|
1979
1979
|
import chalk10 from "chalk";
|
|
1980
|
+
|
|
1981
|
+
// src/lib/curate-lock.ts
|
|
1982
|
+
import fs10 from "fs";
|
|
1983
|
+
import path6 from "path";
|
|
1984
|
+
function getLockPath(cortex) {
|
|
1985
|
+
return path6.join(getThinkDir(), `curate-${cortex}.lock`);
|
|
1986
|
+
}
|
|
1987
|
+
function isProcessAlive(pid) {
|
|
1988
|
+
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
1989
|
+
try {
|
|
1990
|
+
process.kill(pid, 0);
|
|
1991
|
+
return true;
|
|
1992
|
+
} catch (err) {
|
|
1993
|
+
const code = err.code;
|
|
1994
|
+
return code === "EPERM";
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
function acquireCurateLock(cortex) {
|
|
1998
|
+
const lockPath = getLockPath(cortex);
|
|
1999
|
+
fs10.mkdirSync(path6.dirname(lockPath), { recursive: true });
|
|
2000
|
+
try {
|
|
2001
|
+
fs10.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
|
|
2002
|
+
return makeAcquired(lockPath);
|
|
2003
|
+
} catch (err) {
|
|
2004
|
+
if (err.code !== "EEXIST") throw err;
|
|
2005
|
+
}
|
|
2006
|
+
let heldByPid = null;
|
|
2007
|
+
try {
|
|
2008
|
+
const raw = fs10.readFileSync(lockPath, "utf-8").trim();
|
|
2009
|
+
const parsed = parseInt(raw, 10);
|
|
2010
|
+
if (Number.isFinite(parsed) && parsed > 0) heldByPid = parsed;
|
|
2011
|
+
} catch {
|
|
2012
|
+
}
|
|
2013
|
+
if (heldByPid && isProcessAlive(heldByPid)) {
|
|
2014
|
+
return { acquired: false, heldByPid };
|
|
2015
|
+
}
|
|
2016
|
+
try {
|
|
2017
|
+
fs10.unlinkSync(lockPath);
|
|
2018
|
+
} catch {
|
|
2019
|
+
}
|
|
2020
|
+
try {
|
|
2021
|
+
fs10.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
|
|
2022
|
+
return makeAcquired(lockPath);
|
|
2023
|
+
} catch (err) {
|
|
2024
|
+
if (err.code === "EEXIST") {
|
|
2025
|
+
let nowHeldBy = null;
|
|
2026
|
+
try {
|
|
2027
|
+
const raw = fs10.readFileSync(lockPath, "utf-8").trim();
|
|
2028
|
+
const parsed = parseInt(raw, 10);
|
|
2029
|
+
if (Number.isFinite(parsed) && parsed > 0) nowHeldBy = parsed;
|
|
2030
|
+
} catch {
|
|
2031
|
+
}
|
|
2032
|
+
return { acquired: false, heldByPid: nowHeldBy };
|
|
2033
|
+
}
|
|
2034
|
+
throw err;
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
function makeAcquired(lockPath) {
|
|
2038
|
+
let released = false;
|
|
2039
|
+
const unlinkIfHeld = () => {
|
|
2040
|
+
if (released) return;
|
|
2041
|
+
released = true;
|
|
2042
|
+
try {
|
|
2043
|
+
fs10.unlinkSync(lockPath);
|
|
2044
|
+
} catch {
|
|
2045
|
+
}
|
|
2046
|
+
};
|
|
2047
|
+
const exitHandler = () => {
|
|
2048
|
+
unlinkIfHeld();
|
|
2049
|
+
};
|
|
2050
|
+
const sigintHandler = () => {
|
|
2051
|
+
unlinkIfHeld();
|
|
2052
|
+
process.exit(130);
|
|
2053
|
+
};
|
|
2054
|
+
const sigtermHandler = () => {
|
|
2055
|
+
unlinkIfHeld();
|
|
2056
|
+
process.exit(143);
|
|
2057
|
+
};
|
|
2058
|
+
process.on("exit", exitHandler);
|
|
2059
|
+
process.on("SIGINT", sigintHandler);
|
|
2060
|
+
process.on("SIGTERM", sigtermHandler);
|
|
2061
|
+
const release = () => {
|
|
2062
|
+
if (released) {
|
|
2063
|
+
process.removeListener("exit", exitHandler);
|
|
2064
|
+
process.removeListener("SIGINT", sigintHandler);
|
|
2065
|
+
process.removeListener("SIGTERM", sigtermHandler);
|
|
2066
|
+
return;
|
|
2067
|
+
}
|
|
2068
|
+
unlinkIfHeld();
|
|
2069
|
+
process.removeListener("exit", exitHandler);
|
|
2070
|
+
process.removeListener("SIGINT", sigintHandler);
|
|
2071
|
+
process.removeListener("SIGTERM", sigtermHandler);
|
|
2072
|
+
};
|
|
2073
|
+
return { acquired: true, release };
|
|
2074
|
+
}
|
|
2075
|
+
|
|
2076
|
+
// src/commands/curate.ts
|
|
1980
2077
|
var curateCommand = new Command10("curate").description("Run curation: evaluate pending engrams and promote to memories").option("--dry-run", "Preview what would be committed without saving").option("--consolidate", "Run long-term memory consolidation only (no curation)").option("--episode <key>", "Curate a specific episode into a narrative memory").option("--if-idle", "Only curate if the user appears idle (used by auto-curation scheduler)").action(async (opts) => {
|
|
1981
2078
|
const config = getConfig();
|
|
1982
2079
|
const cortex = config.cortex?.active;
|
|
@@ -1988,271 +2085,292 @@ var curateCommand = new Command10("curate").description("Run curation: evaluate
|
|
|
1988
2085
|
process.exit(1);
|
|
1989
2086
|
}
|
|
1990
2087
|
const author = config.cortex.author;
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
2088
|
+
let releaseLock = () => {
|
|
2089
|
+
};
|
|
2090
|
+
if (!opts.dryRun) {
|
|
2091
|
+
const lock = acquireCurateLock(cortex);
|
|
2092
|
+
if (!lock.acquired) {
|
|
2093
|
+
if (opts.ifIdle) {
|
|
2094
|
+
if (process.env.THINK_IDLE_DEBUG) {
|
|
2095
|
+
console.log(chalk10.dim(`[auto-curate] skipped: another curation is running (pid ${lock.heldByPid ?? "?"})`));
|
|
2096
|
+
}
|
|
2097
|
+
} else {
|
|
2098
|
+
console.log(chalk10.yellow(`Another curation is already running (pid ${lock.heldByPid ?? "?"}). Skipping.`));
|
|
1996
2099
|
}
|
|
1997
2100
|
closeCortexDb(cortex);
|
|
1998
2101
|
return;
|
|
1999
2102
|
}
|
|
2000
|
-
|
|
2001
|
-
console.log(chalk10.dim(`[auto-curate] running: ${shouldRun.reason}`));
|
|
2002
|
-
}
|
|
2103
|
+
releaseLock = lock.release;
|
|
2003
2104
|
}
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2105
|
+
try {
|
|
2106
|
+
if (opts.ifIdle && !opts.episode && !opts.consolidate) {
|
|
2107
|
+
const shouldRun = shouldRunIdleCuration(cortex, config.cortex);
|
|
2108
|
+
if (!shouldRun.run) {
|
|
2109
|
+
if (process.env.THINK_IDLE_DEBUG) {
|
|
2110
|
+
console.log(chalk10.dim(`[auto-curate] skipped: ${shouldRun.reason}`));
|
|
2111
|
+
}
|
|
2112
|
+
closeCortexDb(cortex);
|
|
2113
|
+
return;
|
|
2114
|
+
}
|
|
2115
|
+
if (process.env.THINK_IDLE_DEBUG) {
|
|
2116
|
+
console.log(chalk10.dim(`[auto-curate] running: ${shouldRun.reason}`));
|
|
2010
2117
|
}
|
|
2011
|
-
} catch {
|
|
2012
|
-
console.log(chalk10.dim(" Sync pull skipped (remote unavailable)"));
|
|
2013
2118
|
}
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2119
|
+
const adapter = getSyncAdapter();
|
|
2120
|
+
if (adapter?.isAvailable()) {
|
|
2121
|
+
try {
|
|
2122
|
+
const pullResult = await adapter.pull(cortex);
|
|
2123
|
+
if (pullResult.pulled > 0) {
|
|
2124
|
+
console.log(chalk10.dim(` Pulled ${pullResult.pulled} memories from ${adapter.name}`));
|
|
2125
|
+
}
|
|
2126
|
+
} catch {
|
|
2127
|
+
console.log(chalk10.dim(" Sync pull skipped (remote unavailable)"));
|
|
2128
|
+
}
|
|
2021
2129
|
}
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2130
|
+
if (opts.episode) {
|
|
2131
|
+
const episodeEngrams = getPendingEpisodeEngrams(cortex, opts.episode);
|
|
2132
|
+
if (episodeEngrams.length === 0) {
|
|
2133
|
+
console.log(chalk10.dim(`No pending engrams for episode: ${opts.episode}`));
|
|
2134
|
+
closeCortexDb(cortex);
|
|
2135
|
+
return;
|
|
2136
|
+
}
|
|
2137
|
+
const existingMemoryRow = getMemoryByEpisodeKey(cortex, opts.episode);
|
|
2138
|
+
const existingMemory = existingMemoryRow ? {
|
|
2139
|
+
ts: existingMemoryRow.ts,
|
|
2140
|
+
author: existingMemoryRow.author,
|
|
2141
|
+
content: existingMemoryRow.content,
|
|
2142
|
+
source_ids: JSON.parse(existingMemoryRow.source_ids)
|
|
2143
|
+
} : null;
|
|
2144
|
+
console.log(chalk10.cyan(`Curating episode: ${opts.episode} (${episodeEngrams.length} engrams${existingMemory ? ", updating existing narrative" : ""})...`));
|
|
2145
|
+
const prompt3 = assembleEpisodeCurationPrompt({
|
|
2146
|
+
episodeKey: opts.episode,
|
|
2147
|
+
pendingEngrams: episodeEngrams,
|
|
2148
|
+
existingMemory,
|
|
2149
|
+
author
|
|
2150
|
+
});
|
|
2151
|
+
if (opts.dryRun) {
|
|
2152
|
+
console.log();
|
|
2153
|
+
console.log(chalk10.cyan("Episode prompt would be sent to LLM:"));
|
|
2154
|
+
console.log(chalk10.dim(` ${episodeEngrams.length} engrams, ${existingMemory ? "updating" : "creating"} narrative`));
|
|
2155
|
+
for (const e of episodeEngrams) {
|
|
2156
|
+
const ts = e.created_at.slice(0, 16).replace("T", " ");
|
|
2157
|
+
console.log(chalk10.dim(` ${ts}: ${e.content.slice(0, 100)}${e.content.length > 100 ? "..." : ""}`));
|
|
2158
|
+
}
|
|
2159
|
+
closeCortexDb(cortex);
|
|
2160
|
+
return;
|
|
2161
|
+
}
|
|
2162
|
+
let narrative;
|
|
2163
|
+
try {
|
|
2164
|
+
narrative = await runEpisodeCuration(prompt3);
|
|
2165
|
+
} catch (err) {
|
|
2166
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2167
|
+
console.error(chalk10.red(`Episode curation failed: ${message}`));
|
|
2168
|
+
closeCortexDb(cortex);
|
|
2169
|
+
process.exit(1);
|
|
2043
2170
|
}
|
|
2171
|
+
if (existingMemoryRow) {
|
|
2172
|
+
tombstoneMemory(cortex, existingMemoryRow.id);
|
|
2173
|
+
}
|
|
2174
|
+
const allSourceIds = [
|
|
2175
|
+
...existingMemory?.source_ids ?? [],
|
|
2176
|
+
...episodeEngrams.map((e) => e.id)
|
|
2177
|
+
];
|
|
2178
|
+
insertMemory(cortex, {
|
|
2179
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2180
|
+
author,
|
|
2181
|
+
content: narrative,
|
|
2182
|
+
source_ids: allSourceIds,
|
|
2183
|
+
episode_key: opts.episode
|
|
2184
|
+
});
|
|
2185
|
+
markPromoted(cortex, episodeEngrams.map((e) => e.id));
|
|
2186
|
+
if (adapter?.isAvailable()) {
|
|
2187
|
+
try {
|
|
2188
|
+
const pushResult = await adapter.push(cortex);
|
|
2189
|
+
if (pushResult.pushed > 0) {
|
|
2190
|
+
console.log(chalk10.dim(` Pushed ${pushResult.pushed} memories to ${adapter.name}`));
|
|
2191
|
+
}
|
|
2192
|
+
} catch {
|
|
2193
|
+
console.log(chalk10.dim(" Sync push skipped (remote unavailable)"));
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
console.log();
|
|
2197
|
+
console.log(`${chalk10.green("\u2713")} Episode curated: ${opts.episode}`);
|
|
2198
|
+
console.log(` ${episodeEngrams.length} engrams synthesized into narrative`);
|
|
2044
2199
|
closeCortexDb(cortex);
|
|
2045
2200
|
return;
|
|
2046
2201
|
}
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
if (
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
];
|
|
2063
|
-
insertMemory(cortex, {
|
|
2064
|
-
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2065
|
-
author,
|
|
2066
|
-
content: narrative,
|
|
2067
|
-
source_ids: allSourceIds,
|
|
2068
|
-
episode_key: opts.episode
|
|
2069
|
-
});
|
|
2070
|
-
markPromoted(cortex, episodeEngrams.map((e) => e.id));
|
|
2071
|
-
if (adapter?.isAvailable()) {
|
|
2202
|
+
const allMemories = getMemories(cortex);
|
|
2203
|
+
const memoryEntries = allMemories.map((m) => ({
|
|
2204
|
+
ts: m.ts,
|
|
2205
|
+
author: m.author,
|
|
2206
|
+
content: m.content,
|
|
2207
|
+
source_ids: JSON.parse(m.source_ids)
|
|
2208
|
+
}));
|
|
2209
|
+
const { recent, older } = filterRecentMemories(memoryEntries);
|
|
2210
|
+
const longtermSummary = getLongtermSummary(cortex);
|
|
2211
|
+
if (opts.consolidate) {
|
|
2212
|
+
if (older.length === 0) {
|
|
2213
|
+
console.log(chalk10.dim("No memories older than 2 weeks to consolidate."));
|
|
2214
|
+
return;
|
|
2215
|
+
}
|
|
2216
|
+
console.log(chalk10.cyan(`Consolidating ${older.length} older memories into long-term summary...`));
|
|
2072
2217
|
try {
|
|
2073
|
-
const
|
|
2074
|
-
if (
|
|
2075
|
-
console.log(
|
|
2218
|
+
const newSummary = await runConsolidation(longtermSummary, older);
|
|
2219
|
+
if (opts.dryRun) {
|
|
2220
|
+
console.log();
|
|
2221
|
+
console.log(chalk10.cyan("Proposed long-term summary:"));
|
|
2222
|
+
console.log(newSummary);
|
|
2223
|
+
return;
|
|
2076
2224
|
}
|
|
2077
|
-
|
|
2078
|
-
console.log(chalk10.
|
|
2225
|
+
setLongtermSummary(cortex, newSummary);
|
|
2226
|
+
console.log(chalk10.green("\u2713") + ` Long-term summary updated (${older.length} memories consolidated)`);
|
|
2227
|
+
} catch (err) {
|
|
2228
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2229
|
+
console.error(chalk10.red(`Consolidation failed: ${message}`));
|
|
2230
|
+
process.exit(1);
|
|
2079
2231
|
}
|
|
2232
|
+
return;
|
|
2080
2233
|
}
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
return;
|
|
2086
|
-
}
|
|
2087
|
-
const allMemories = getMemories(cortex);
|
|
2088
|
-
const memoryEntries = allMemories.map((m) => ({
|
|
2089
|
-
ts: m.ts,
|
|
2090
|
-
author: m.author,
|
|
2091
|
-
content: m.content,
|
|
2092
|
-
source_ids: JSON.parse(m.source_ids)
|
|
2093
|
-
}));
|
|
2094
|
-
const { recent, older } = filterRecentMemories(memoryEntries);
|
|
2095
|
-
const longtermSummary = getLongtermSummary(cortex);
|
|
2096
|
-
if (opts.consolidate) {
|
|
2097
|
-
if (older.length === 0) {
|
|
2098
|
-
console.log(chalk10.dim("No memories older than 2 weeks to consolidate."));
|
|
2234
|
+
const pending = getPendingEngrams(cortex);
|
|
2235
|
+
if (pending.length === 0) {
|
|
2236
|
+
console.log(chalk10.dim("No pending engrams to evaluate."));
|
|
2237
|
+
closeCortexDb(cortex);
|
|
2099
2238
|
return;
|
|
2100
2239
|
}
|
|
2101
|
-
console.log(chalk10.cyan(`
|
|
2240
|
+
console.log(chalk10.cyan(`Evaluating ${pending.length} engrams (${recent.length} recent memories, long-term summary ${longtermSummary ? "loaded" : "absent"})...`));
|
|
2241
|
+
const curatorMd = readCuratorMd();
|
|
2242
|
+
const curationPrompt = assembleCurationPrompt({
|
|
2243
|
+
recentMemories: recent,
|
|
2244
|
+
longtermSummary,
|
|
2245
|
+
curatorMd,
|
|
2246
|
+
pendingEngrams: pending,
|
|
2247
|
+
author,
|
|
2248
|
+
selectivity: config.cortex?.selectivity,
|
|
2249
|
+
granularity: config.cortex?.granularity,
|
|
2250
|
+
maxMemoriesPerRun: config.cortex?.maxMemoriesPerRun
|
|
2251
|
+
});
|
|
2252
|
+
let curationResult;
|
|
2102
2253
|
try {
|
|
2103
|
-
|
|
2104
|
-
if (opts.dryRun) {
|
|
2105
|
-
console.log();
|
|
2106
|
-
console.log(chalk10.cyan("Proposed long-term summary:"));
|
|
2107
|
-
console.log(newSummary);
|
|
2108
|
-
return;
|
|
2109
|
-
}
|
|
2110
|
-
setLongtermSummary(cortex, newSummary);
|
|
2111
|
-
console.log(chalk10.green("\u2713") + ` Long-term summary updated (${older.length} memories consolidated)`);
|
|
2254
|
+
curationResult = await runCuration(curationPrompt);
|
|
2112
2255
|
} catch (err) {
|
|
2113
2256
|
const message = err instanceof Error ? err.message : String(err);
|
|
2114
|
-
console.error(chalk10.red(`
|
|
2257
|
+
console.error(chalk10.red(`Curation failed: ${message}`));
|
|
2258
|
+
closeCortexDb(cortex);
|
|
2115
2259
|
process.exit(1);
|
|
2116
2260
|
}
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
console.log(chalk10.dim("No pending engrams to evaluate."));
|
|
2122
|
-
closeCortexDb(cortex);
|
|
2123
|
-
return;
|
|
2124
|
-
}
|
|
2125
|
-
console.log(chalk10.cyan(`Evaluating ${pending.length} engrams (${recent.length} recent memories, long-term summary ${longtermSummary ? "loaded" : "absent"})...`));
|
|
2126
|
-
const curatorMd = readCuratorMd();
|
|
2127
|
-
const curationPrompt = assembleCurationPrompt({
|
|
2128
|
-
recentMemories: recent,
|
|
2129
|
-
longtermSummary,
|
|
2130
|
-
curatorMd,
|
|
2131
|
-
pendingEngrams: pending,
|
|
2132
|
-
author,
|
|
2133
|
-
selectivity: config.cortex?.selectivity,
|
|
2134
|
-
granularity: config.cortex?.granularity,
|
|
2135
|
-
maxMemoriesPerRun: config.cortex?.maxMemoriesPerRun
|
|
2136
|
-
});
|
|
2137
|
-
let curationResult;
|
|
2138
|
-
try {
|
|
2139
|
-
curationResult = await runCuration(curationPrompt);
|
|
2140
|
-
} catch (err) {
|
|
2141
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
2142
|
-
console.error(chalk10.red(`Curation failed: ${message}`));
|
|
2143
|
-
closeCortexDb(cortex);
|
|
2144
|
-
process.exit(1);
|
|
2145
|
-
}
|
|
2146
|
-
const newEntries = curationResult.memories;
|
|
2147
|
-
for (const entry of newEntries) {
|
|
2148
|
-
entry.author = author;
|
|
2149
|
-
if (!entry.ts) entry.ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
2150
|
-
}
|
|
2151
|
-
const promotedIds = /* @__PURE__ */ new Set();
|
|
2152
|
-
for (const entry of newEntries) {
|
|
2153
|
-
for (const id of entry.source_ids) {
|
|
2154
|
-
promotedIds.add(id);
|
|
2261
|
+
const newEntries = curationResult.memories;
|
|
2262
|
+
for (const entry of newEntries) {
|
|
2263
|
+
entry.author = author;
|
|
2264
|
+
if (!entry.ts) entry.ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
2155
2265
|
}
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
if (opts.dryRun) {
|
|
2161
|
-
console.log();
|
|
2162
|
-
if (newEntries.length === 0) {
|
|
2163
|
-
console.log(chalk10.dim("Curator would produce no new memories."));
|
|
2164
|
-
} else {
|
|
2165
|
-
console.log(chalk10.cyan("Would append:"));
|
|
2166
|
-
for (const entry of newEntries) {
|
|
2167
|
-
console.log(chalk10.green(` + `) + `[${entry.ts}] ${entry.content}`);
|
|
2266
|
+
const promotedIds = /* @__PURE__ */ new Set();
|
|
2267
|
+
for (const entry of newEntries) {
|
|
2268
|
+
for (const id of entry.source_ids) {
|
|
2269
|
+
promotedIds.add(id);
|
|
2168
2270
|
}
|
|
2169
2271
|
}
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
rl.close();
|
|
2186
|
-
resolve(ans.trim().toLowerCase());
|
|
2187
|
-
});
|
|
2188
|
-
});
|
|
2189
|
-
if (answer === "n" || answer === "no") {
|
|
2190
|
-
console.log(chalk10.dim(" Aborted. Engrams left as pending."));
|
|
2272
|
+
const pendingIdSet = new Set(pending.map((e) => e.id));
|
|
2273
|
+
const purgedIds = curationResult.purgeIds.filter((id) => pendingIdSet.has(id) && !promotedIds.has(id));
|
|
2274
|
+
const heldCount = pending.length - promotedIds.size - purgedIds.length;
|
|
2275
|
+
if (opts.dryRun) {
|
|
2276
|
+
console.log();
|
|
2277
|
+
if (newEntries.length === 0) {
|
|
2278
|
+
console.log(chalk10.dim("Curator would produce no new memories."));
|
|
2279
|
+
} else {
|
|
2280
|
+
console.log(chalk10.cyan("Would append:"));
|
|
2281
|
+
for (const entry of newEntries) {
|
|
2282
|
+
console.log(chalk10.green(` + `) + `[${entry.ts}] ${entry.content}`);
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2285
|
+
console.log();
|
|
2286
|
+
console.log(`${pending.length} evaluated, ${newEntries.length} would promote, ${purgedIds.length} would purge, ${heldCount} would stay pending`);
|
|
2191
2287
|
closeCortexDb(cortex);
|
|
2192
2288
|
return;
|
|
2193
2289
|
}
|
|
2194
|
-
if (
|
|
2290
|
+
if (config.cortex?.confirmBeforeCommit && newEntries.length > 0) {
|
|
2291
|
+
console.log();
|
|
2292
|
+
console.log(chalk10.cyan("Proposed memories:"));
|
|
2195
2293
|
for (let i = 0; i < newEntries.length; i++) {
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2294
|
+
console.log(chalk10.green(` ${i + 1}. `) + newEntries[i].content);
|
|
2295
|
+
}
|
|
2296
|
+
console.log();
|
|
2297
|
+
const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
|
|
2298
|
+
const answer = await new Promise((resolve) => {
|
|
2299
|
+
rl.question(" Save these memories? [Y/n/edit] ", (ans) => {
|
|
2300
|
+
rl.close();
|
|
2301
|
+
resolve(ans.trim().toLowerCase());
|
|
2302
|
+
});
|
|
2303
|
+
});
|
|
2304
|
+
if (answer === "n" || answer === "no") {
|
|
2305
|
+
console.log(chalk10.dim(" Aborted. Engrams left as pending."));
|
|
2306
|
+
closeCortexDb(cortex);
|
|
2307
|
+
return;
|
|
2308
|
+
}
|
|
2309
|
+
if (answer === "e" || answer === "edit") {
|
|
2310
|
+
for (let i = 0; i < newEntries.length; i++) {
|
|
2311
|
+
const editRl = readline3.createInterface({ input: process.stdin, output: process.stdout });
|
|
2312
|
+
const edited = await new Promise((resolve) => {
|
|
2313
|
+
editRl.question(` ${i + 1}. ${chalk10.dim("(enter to keep, or type replacement)")}
|
|
2199
2314
|
${newEntries[i].content}
|
|
2200
2315
|
> `, (ans) => {
|
|
2201
|
-
|
|
2202
|
-
|
|
2316
|
+
editRl.close();
|
|
2317
|
+
resolve(ans.trim());
|
|
2318
|
+
});
|
|
2203
2319
|
});
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2320
|
+
if (edited) {
|
|
2321
|
+
newEntries[i].content = edited;
|
|
2322
|
+
}
|
|
2207
2323
|
}
|
|
2208
2324
|
}
|
|
2209
2325
|
}
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
}
|
|
2326
|
+
if (newEntries.length > 0) {
|
|
2327
|
+
for (const entry of newEntries) {
|
|
2328
|
+
insertMemory(cortex, {
|
|
2329
|
+
ts: entry.ts,
|
|
2330
|
+
author: entry.author,
|
|
2331
|
+
content: entry.content,
|
|
2332
|
+
source_ids: entry.source_ids,
|
|
2333
|
+
decisions: entry.decisions
|
|
2334
|
+
});
|
|
2335
|
+
}
|
|
2220
2336
|
}
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
markPromoted(cortex, [...promotedIds]);
|
|
2224
|
-
}
|
|
2225
|
-
if (purgedIds.length > 0) {
|
|
2226
|
-
markPurged(cortex, purgedIds);
|
|
2227
|
-
}
|
|
2228
|
-
const pruned = pruneExpiredEngrams(cortex);
|
|
2229
|
-
if (older.length > 0 && !longtermSummary) {
|
|
2230
|
-
console.log(chalk10.dim(` Consolidating ${older.length} older memories into long-term summary...`));
|
|
2231
|
-
try {
|
|
2232
|
-
const newSummary = await runConsolidation(null, older);
|
|
2233
|
-
setLongtermSummary(cortex, newSummary);
|
|
2234
|
-
console.log(chalk10.dim(` Long-term summary created`));
|
|
2235
|
-
} catch {
|
|
2236
|
-
console.log(chalk10.dim(` Long-term consolidation skipped (will retry next run)`));
|
|
2337
|
+
if (promotedIds.size > 0) {
|
|
2338
|
+
markPromoted(cortex, [...promotedIds]);
|
|
2237
2339
|
}
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2340
|
+
if (purgedIds.length > 0) {
|
|
2341
|
+
markPurged(cortex, purgedIds);
|
|
2342
|
+
}
|
|
2343
|
+
const pruned = pruneExpiredEngrams(cortex);
|
|
2344
|
+
if (older.length > 0 && !longtermSummary) {
|
|
2345
|
+
console.log(chalk10.dim(` Consolidating ${older.length} older memories into long-term summary...`));
|
|
2346
|
+
try {
|
|
2347
|
+
const newSummary = await runConsolidation(null, older);
|
|
2348
|
+
setLongtermSummary(cortex, newSummary);
|
|
2349
|
+
console.log(chalk10.dim(` Long-term summary created`));
|
|
2350
|
+
} catch {
|
|
2351
|
+
console.log(chalk10.dim(` Long-term consolidation skipped (will retry next run)`));
|
|
2244
2352
|
}
|
|
2245
|
-
} catch {
|
|
2246
|
-
console.log(chalk10.dim(" Sync push skipped (remote unavailable) \u2014 will push on next sync"));
|
|
2247
2353
|
}
|
|
2354
|
+
if (adapter?.isAvailable() && newEntries.length > 0) {
|
|
2355
|
+
try {
|
|
2356
|
+
const pushResult = await adapter.push(cortex);
|
|
2357
|
+
if (pushResult.pushed > 0) {
|
|
2358
|
+
console.log(chalk10.dim(` Pushed ${pushResult.pushed} memories to ${adapter.name}`));
|
|
2359
|
+
}
|
|
2360
|
+
} catch {
|
|
2361
|
+
console.log(chalk10.dim(" Sync push skipped (remote unavailable) \u2014 will push on next sync"));
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2364
|
+
console.log();
|
|
2365
|
+
console.log(`${chalk10.green("\u2713")} Curation complete`);
|
|
2366
|
+
console.log(` ${pending.length} evaluated, ${newEntries.length} promoted, ${purgedIds.length} purged, ${heldCount} still pending`);
|
|
2367
|
+
if (pruned > 0) {
|
|
2368
|
+
console.log(` ${pruned} expired engrams pruned`);
|
|
2369
|
+
}
|
|
2370
|
+
closeCortexDb(cortex);
|
|
2371
|
+
} finally {
|
|
2372
|
+
releaseLock();
|
|
2248
2373
|
}
|
|
2249
|
-
console.log();
|
|
2250
|
-
console.log(`${chalk10.green("\u2713")} Curation complete`);
|
|
2251
|
-
console.log(` ${pending.length} evaluated, ${newEntries.length} promoted, ${purgedIds.length} purged, ${heldCount} still pending`);
|
|
2252
|
-
if (pruned > 0) {
|
|
2253
|
-
console.log(` ${pruned} expired engrams pruned`);
|
|
2254
|
-
}
|
|
2255
|
-
closeCortexDb(cortex);
|
|
2256
2374
|
});
|
|
2257
2375
|
var DEFAULT_IDLE_WINDOW_MINUTES = 3;
|
|
2258
2376
|
var DEFAULT_STALE_WINDOW_MINUTES = 60;
|
|
@@ -2496,7 +2614,7 @@ memoryCommand.addCommand(addCommand);
|
|
|
2496
2614
|
// src/commands/curator-cmd.ts
|
|
2497
2615
|
import { Command as Command14 } from "commander";
|
|
2498
2616
|
import { spawnSync } from "child_process";
|
|
2499
|
-
import
|
|
2617
|
+
import fs11 from "fs";
|
|
2500
2618
|
import chalk14 from "chalk";
|
|
2501
2619
|
var CURATOR_TEMPLATE = `# Curator Guidance
|
|
2502
2620
|
|
|
@@ -2515,8 +2633,8 @@ var curatorCommand = new Command14("curator").description("Manage personal curat
|
|
|
2515
2633
|
curatorCommand.addCommand(new Command14("edit").description("Edit your curator guidance in $EDITOR").action(() => {
|
|
2516
2634
|
ensureThinkDirs();
|
|
2517
2635
|
const mdPath = getCuratorMdPath();
|
|
2518
|
-
if (!
|
|
2519
|
-
|
|
2636
|
+
if (!fs11.existsSync(mdPath)) {
|
|
2637
|
+
fs11.writeFileSync(mdPath, CURATOR_TEMPLATE, "utf-8");
|
|
2520
2638
|
}
|
|
2521
2639
|
const editor = process.env.EDITOR || "vi";
|
|
2522
2640
|
const result = spawnSync(editor, [mdPath], { stdio: "inherit" });
|
|
@@ -2528,8 +2646,8 @@ curatorCommand.addCommand(new Command14("edit").description("Edit your curator g
|
|
|
2528
2646
|
}));
|
|
2529
2647
|
curatorCommand.addCommand(new Command14("show").description("Print your current curator guidance").action(() => {
|
|
2530
2648
|
const mdPath = getCuratorMdPath();
|
|
2531
|
-
if (
|
|
2532
|
-
console.log(
|
|
2649
|
+
if (fs11.existsSync(mdPath)) {
|
|
2650
|
+
console.log(fs11.readFileSync(mdPath, "utf-8"));
|
|
2533
2651
|
} else {
|
|
2534
2652
|
console.log(chalk14.dim("No curator guidance configured. Run: think curator edit"));
|
|
2535
2653
|
}
|
|
@@ -2651,7 +2769,7 @@ var updateCommand = new Command18("update").description("Update think to the lat
|
|
|
2651
2769
|
|
|
2652
2770
|
// src/commands/migrate-data.ts
|
|
2653
2771
|
import { Command as Command19 } from "commander";
|
|
2654
|
-
import
|
|
2772
|
+
import fs12 from "fs";
|
|
2655
2773
|
import chalk19 from "chalk";
|
|
2656
2774
|
var migrateDataCommand = new Command19("migrate-data").description("Import existing memories from git into local SQLite (one-time migration)").action(async () => {
|
|
2657
2775
|
const config = getConfig();
|
|
@@ -2689,8 +2807,8 @@ var migrateDataCommand = new Command19("migrate-data").description("Import exist
|
|
|
2689
2807
|
if (wasInserted) inserted++;
|
|
2690
2808
|
}
|
|
2691
2809
|
const ltPath = getLongtermPath(cortex);
|
|
2692
|
-
if (
|
|
2693
|
-
const ltContent =
|
|
2810
|
+
if (fs12.existsSync(ltPath)) {
|
|
2811
|
+
const ltContent = fs12.readFileSync(ltPath, "utf-8").trim();
|
|
2694
2812
|
if (ltContent) {
|
|
2695
2813
|
setLongtermSummary(cortex, ltContent);
|
|
2696
2814
|
console.log(chalk19.green(" \u2713") + " Long-term summary migrated");
|
|
@@ -2709,8 +2827,8 @@ var migrateDataCommand = new Command19("migrate-data").description("Import exist
|
|
|
2709
2827
|
// src/index.ts
|
|
2710
2828
|
function readPackageVersion() {
|
|
2711
2829
|
try {
|
|
2712
|
-
const pkgPath =
|
|
2713
|
-
return JSON.parse(
|
|
2830
|
+
const pkgPath = path7.join(import.meta.dirname, "..", "package.json");
|
|
2831
|
+
return JSON.parse(fs13.readFileSync(pkgPath, "utf-8")).version ?? "0.0.0";
|
|
2714
2832
|
} catch {
|
|
2715
2833
|
return "0.0.0";
|
|
2716
2834
|
}
|