polymath-society 0.2.19 → 0.2.21
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/cli.js +24620 -22073
- package/dist/engine/chat-loops.js +8 -1
- package/dist/engine/exp-allfacets.js +8 -1
- package/dist/engine/exp-person.js +8 -1
- package/dist/engine/exp-pipeline.js +8 -1
- package/dist/engine/ingest-export.js +7 -6
- package/dist/engine/peak-demos.js +8 -1
- package/dist/engine/person-dimension-summary.js +8 -1
- package/dist/engine/person-facet-lines.js +8 -1
- package/dist/engine/person-headline.js +8 -1
- package/dist/engine/person-report.js +8 -1
- package/dist/engine/person-self-image.js +8 -1
- package/dist/engine/public-report.js +15 -7
- package/dist/engine/run-analysis.js +8 -1
- package/dist/engine/run-tagger.js +8 -1
- package/dist/index.js +19600 -17706
- package/dist/pipeline/FOCUS-EXAMPLES.md +127 -0
- package/dist/pipeline/FOCUS-RUBRIC.md +418 -0
- package/dist/pipeline/coding-agglomerate.js +947 -79
- package/dist/pipeline/coding-aggregate.js +443 -23
- package/dist/pipeline/coding-build.js +569 -97
- package/dist/pipeline/coding-coaching.js +651 -101
- package/dist/pipeline/coding-day-digest.js +417 -36
- package/dist/pipeline/coding-delegation.js +564 -68
- package/dist/pipeline/coding-expertise.js +477 -59
- package/dist/pipeline/coding-flow.js +424 -15
- package/dist/pipeline/coding-focus.js +507 -51
- package/dist/pipeline/coding-frontier-detail.js +465 -47
- package/dist/pipeline/coding-frontier.js +7 -6
- package/dist/pipeline/coding-gap-dist.js +424 -15
- package/dist/pipeline/coding-gap.js +679 -128
- package/dist/pipeline/coding-grade.js +469 -42
- package/dist/pipeline/coding-growth.js +17041 -0
- package/dist/pipeline/coding-nutshell.js +168 -151
- package/dist/pipeline/coding-projects.js +7 -6
- package/dist/pipeline/coding-walkthrough.js +461 -37
- package/dist/pipeline/coding-workbrief.js +16387 -0
- package/dist/web/app.js +2095 -1396
- package/dist/web/styles.css +1 -1
- package/package.json +1 -1
|
@@ -134,7 +134,7 @@ var require_secure_json_parse = __commonJS({
|
|
|
134
134
|
});
|
|
135
135
|
|
|
136
136
|
// ../../scripts/coding-focus.mts
|
|
137
|
-
import { promises as
|
|
137
|
+
import { promises as fs8 } from "fs";
|
|
138
138
|
|
|
139
139
|
// ../../lib/agents/coding/promptCache.ts
|
|
140
140
|
import { createHash } from "crypto";
|
|
@@ -147,8 +147,55 @@ function promptSha(parts) {
|
|
|
147
147
|
return h.digest("hex").slice(0, 16);
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
// ../../lib/agents/coding/stageLock.ts
|
|
151
|
+
import { promises as fs } from "fs";
|
|
152
|
+
var STALE_UNKNOWN_MS = 12 * 60 * 60 * 1e3;
|
|
153
|
+
function pidAlive(pid) {
|
|
154
|
+
try {
|
|
155
|
+
process.kill(pid, 0);
|
|
156
|
+
return true;
|
|
157
|
+
} catch (e) {
|
|
158
|
+
return e.code === "EPERM";
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
async function acquireStageLock(lockPath, stage) {
|
|
162
|
+
const mine = String(process.pid);
|
|
163
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
164
|
+
try {
|
|
165
|
+
await fs.writeFile(lockPath, mine, { flag: "wx" });
|
|
166
|
+
return async () => {
|
|
167
|
+
const held = await fs.readFile(lockPath, "utf8").catch(() => null);
|
|
168
|
+
if (held === mine) await fs.unlink(lockPath).catch(() => {
|
|
169
|
+
});
|
|
170
|
+
};
|
|
171
|
+
} catch {
|
|
172
|
+
const raw = (await fs.readFile(lockPath, "utf8").catch(() => "")).trim();
|
|
173
|
+
const pid = /^\d{1,9}$/.test(raw) ? Number(raw) : null;
|
|
174
|
+
if (pid != null && pidAlive(pid)) {
|
|
175
|
+
throw new Error(
|
|
176
|
+
`another ${stage} run is ACTIVE (pid ${pid} is alive, ${lockPath}) \u2014 concurrent runs overwrite each other's output. Wait for it to finish.`
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
if (pid == null) {
|
|
180
|
+
const age = Date.now() - (await fs.stat(lockPath).catch(() => null))?.mtimeMs;
|
|
181
|
+
if (!(age > STALE_UNKNOWN_MS)) {
|
|
182
|
+
throw new Error(
|
|
183
|
+
`a ${stage} lock exists with an unreadable holder (${lockPath}, ${Math.round(age / 6e4)}m old) \u2014 not old enough to declare stale. Wait, or delete it if you know the run is gone.`
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
console.warn(
|
|
188
|
+
`[${stage}] stale lock from ${pid != null ? `dead pid ${pid}` : "an unreadable holder"} \u2014 removing it and proceeding (a crashed run must never strand the next one)`
|
|
189
|
+
);
|
|
190
|
+
await fs.unlink(lockPath).catch(() => {
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
throw new Error(`could not acquire the ${stage} lock (${lockPath}) \u2014 another run raced the stale takeover`);
|
|
195
|
+
}
|
|
196
|
+
|
|
150
197
|
// ../../scripts/coding-focus.mts
|
|
151
|
-
import
|
|
198
|
+
import path11 from "path";
|
|
152
199
|
|
|
153
200
|
// ../../lib/agents/shared/agent.ts
|
|
154
201
|
import { readFileSync } from "fs";
|
|
@@ -156,7 +203,7 @@ import path8 from "path";
|
|
|
156
203
|
|
|
157
204
|
// ../../lib/agents/shared/cliAdapter.ts
|
|
158
205
|
import { spawn } from "child_process";
|
|
159
|
-
import { promises as
|
|
206
|
+
import { promises as fs3 } from "fs";
|
|
160
207
|
import path2 from "path";
|
|
161
208
|
|
|
162
209
|
// ../coding-core/dist/env.js
|
|
@@ -200,7 +247,7 @@ function extractJson(text2) {
|
|
|
200
247
|
}
|
|
201
248
|
|
|
202
249
|
// ../../lib/agents/shared/toolLog.ts
|
|
203
|
-
import { promises as
|
|
250
|
+
import { promises as fs2 } from "fs";
|
|
204
251
|
import path from "path";
|
|
205
252
|
async function writeToolLog(logPath, d) {
|
|
206
253
|
const counts = {};
|
|
@@ -217,8 +264,8 @@ async function writeToolLog(logPath, d) {
|
|
|
217
264
|
L.push(``);
|
|
218
265
|
L.push(`## Full call sequence (${d.toolCalls.length})`);
|
|
219
266
|
d.toolCalls.forEach((c, i) => L.push(` ${String(i + 1).padStart(3, "0")} ${c.tool.padEnd(5)} ${c.target}`));
|
|
220
|
-
await
|
|
221
|
-
await
|
|
267
|
+
await fs2.mkdir(path.dirname(logPath), { recursive: true });
|
|
268
|
+
await fs2.writeFile(logPath, L.join("\n"), "utf-8");
|
|
222
269
|
const json = {
|
|
223
270
|
roots: d.roots,
|
|
224
271
|
toolCounts: counts,
|
|
@@ -228,7 +275,7 @@ async function writeToolLog(logPath, d) {
|
|
|
228
275
|
filesRead: d.filesRead,
|
|
229
276
|
callSequence: d.toolCalls
|
|
230
277
|
};
|
|
231
|
-
await
|
|
278
|
+
await fs2.writeFile(logPath.replace(/\.log$/, ".json"), JSON.stringify(json, null, 2), "utf-8");
|
|
232
279
|
}
|
|
233
280
|
|
|
234
281
|
// ../../lib/agents/shared/cliAdapter.ts
|
|
@@ -237,8 +284,8 @@ var USAGE_LEDGER = () => path2.join(process.env.POLYMATH_DATA_DIR ? path2.resolv
|
|
|
237
284
|
async function appendUsageLedger(line) {
|
|
238
285
|
try {
|
|
239
286
|
const f = USAGE_LEDGER();
|
|
240
|
-
await
|
|
241
|
-
await
|
|
287
|
+
await fs3.mkdir(path2.dirname(f), { recursive: true });
|
|
288
|
+
await fs3.appendFile(f, JSON.stringify(line) + "\n", "utf8");
|
|
242
289
|
} catch {
|
|
243
290
|
}
|
|
244
291
|
}
|
|
@@ -516,6 +563,13 @@ ${report}`);
|
|
|
516
563
|
}
|
|
517
564
|
|
|
518
565
|
// ../../lib/agents/shared/codexAdapter.ts
|
|
566
|
+
var CODEX_DEFAULT_MODEL = "gpt-5.5";
|
|
567
|
+
var CODEX_MINI_MODEL = "gpt-5.4-mini";
|
|
568
|
+
function mapCodexTier(model, env = process.env) {
|
|
569
|
+
if (model && !/^(claude|haiku|sonnet|opus)/i.test(model)) return model;
|
|
570
|
+
if (model && /^haiku/i.test(model)) return env.POLYMATH_CODEX_MODEL_MINI || CODEX_MINI_MODEL;
|
|
571
|
+
return env.POLYMATH_CODEX_MODEL || CODEX_DEFAULT_MODEL;
|
|
572
|
+
}
|
|
519
573
|
function composePrompt(inv, roots) {
|
|
520
574
|
return [
|
|
521
575
|
inv.systemPrompt ? `<system>
|
|
@@ -556,7 +610,7 @@ var codexAdapter = {
|
|
|
556
610
|
"read-only",
|
|
557
611
|
"--json"
|
|
558
612
|
];
|
|
559
|
-
|
|
613
|
+
args.push("--model", mapCodexTier(inv.model));
|
|
560
614
|
args.push(composePrompt(inv, roots));
|
|
561
615
|
const started = Date.now();
|
|
562
616
|
const toolCalls = [];
|
|
@@ -2184,8 +2238,8 @@ function getErrorMap() {
|
|
|
2184
2238
|
|
|
2185
2239
|
// ../../node_modules/zod/v3/helpers/parseUtil.js
|
|
2186
2240
|
var makeIssue = (params) => {
|
|
2187
|
-
const { data, path:
|
|
2188
|
-
const fullPath = [...
|
|
2241
|
+
const { data, path: path12, errorMaps, issueData } = params;
|
|
2242
|
+
const fullPath = [...path12, ...issueData.path || []];
|
|
2189
2243
|
const fullIssue = {
|
|
2190
2244
|
...issueData,
|
|
2191
2245
|
path: fullPath
|
|
@@ -2301,11 +2355,11 @@ var errorUtil;
|
|
|
2301
2355
|
|
|
2302
2356
|
// ../../node_modules/zod/v3/types.js
|
|
2303
2357
|
var ParseInputLazyPath = class {
|
|
2304
|
-
constructor(parent, value,
|
|
2358
|
+
constructor(parent, value, path12, key) {
|
|
2305
2359
|
this._cachedPath = [];
|
|
2306
2360
|
this.parent = parent;
|
|
2307
2361
|
this.data = value;
|
|
2308
|
-
this._path =
|
|
2362
|
+
this._path = path12;
|
|
2309
2363
|
this._key = key;
|
|
2310
2364
|
}
|
|
2311
2365
|
get path() {
|
|
@@ -15092,39 +15146,39 @@ function createOpenAI(options = {}) {
|
|
|
15092
15146
|
});
|
|
15093
15147
|
const createChatModel = (modelId, settings = {}) => new OpenAIChatLanguageModel(modelId, settings, {
|
|
15094
15148
|
provider: `${providerName}.chat`,
|
|
15095
|
-
url: ({ path:
|
|
15149
|
+
url: ({ path: path12 }) => `${baseURL}${path12}`,
|
|
15096
15150
|
headers: getHeaders,
|
|
15097
15151
|
compatibility,
|
|
15098
15152
|
fetch: options.fetch
|
|
15099
15153
|
});
|
|
15100
15154
|
const createCompletionModel = (modelId, settings = {}) => new OpenAICompletionLanguageModel(modelId, settings, {
|
|
15101
15155
|
provider: `${providerName}.completion`,
|
|
15102
|
-
url: ({ path:
|
|
15156
|
+
url: ({ path: path12 }) => `${baseURL}${path12}`,
|
|
15103
15157
|
headers: getHeaders,
|
|
15104
15158
|
compatibility,
|
|
15105
15159
|
fetch: options.fetch
|
|
15106
15160
|
});
|
|
15107
15161
|
const createEmbeddingModel = (modelId, settings = {}) => new OpenAIEmbeddingModel(modelId, settings, {
|
|
15108
15162
|
provider: `${providerName}.embedding`,
|
|
15109
|
-
url: ({ path:
|
|
15163
|
+
url: ({ path: path12 }) => `${baseURL}${path12}`,
|
|
15110
15164
|
headers: getHeaders,
|
|
15111
15165
|
fetch: options.fetch
|
|
15112
15166
|
});
|
|
15113
15167
|
const createImageModel = (modelId, settings = {}) => new OpenAIImageModel(modelId, settings, {
|
|
15114
15168
|
provider: `${providerName}.image`,
|
|
15115
|
-
url: ({ path:
|
|
15169
|
+
url: ({ path: path12 }) => `${baseURL}${path12}`,
|
|
15116
15170
|
headers: getHeaders,
|
|
15117
15171
|
fetch: options.fetch
|
|
15118
15172
|
});
|
|
15119
15173
|
const createTranscriptionModel = (modelId) => new OpenAITranscriptionModel(modelId, {
|
|
15120
15174
|
provider: `${providerName}.transcription`,
|
|
15121
|
-
url: ({ path:
|
|
15175
|
+
url: ({ path: path12 }) => `${baseURL}${path12}`,
|
|
15122
15176
|
headers: getHeaders,
|
|
15123
15177
|
fetch: options.fetch
|
|
15124
15178
|
});
|
|
15125
15179
|
const createSpeechModel = (modelId) => new OpenAISpeechModel(modelId, {
|
|
15126
15180
|
provider: `${providerName}.speech`,
|
|
15127
|
-
url: ({ path:
|
|
15181
|
+
url: ({ path: path12 }) => `${baseURL}${path12}`,
|
|
15128
15182
|
headers: getHeaders,
|
|
15129
15183
|
fetch: options.fetch
|
|
15130
15184
|
});
|
|
@@ -15145,7 +15199,7 @@ function createOpenAI(options = {}) {
|
|
|
15145
15199
|
const createResponsesModel = (modelId) => {
|
|
15146
15200
|
return new OpenAIResponsesLanguageModel(modelId, {
|
|
15147
15201
|
provider: `${providerName}.responses`,
|
|
15148
|
-
url: ({ path:
|
|
15202
|
+
url: ({ path: path12 }) => `${baseURL}${path12}`,
|
|
15149
15203
|
headers: getHeaders,
|
|
15150
15204
|
fetch: options.fetch
|
|
15151
15205
|
});
|
|
@@ -15175,7 +15229,7 @@ var openai = createOpenAI({
|
|
|
15175
15229
|
});
|
|
15176
15230
|
|
|
15177
15231
|
// ../../lib/agents/shared/tools.ts
|
|
15178
|
-
import { promises as
|
|
15232
|
+
import { promises as fs4 } from "fs";
|
|
15179
15233
|
import { execFile } from "child_process";
|
|
15180
15234
|
import { promisify } from "util";
|
|
15181
15235
|
import path5 from "path";
|
|
@@ -15195,7 +15249,7 @@ function fileTools(root) {
|
|
|
15195
15249
|
parameters: external_exports.object({ path: external_exports.string().describe("dir path relative to source root") }),
|
|
15196
15250
|
execute: async ({ path: p }) => {
|
|
15197
15251
|
const dir = safeResolve(root, p);
|
|
15198
|
-
const entries = await
|
|
15252
|
+
const entries = await fs4.readdir(dir, { withFileTypes: true });
|
|
15199
15253
|
return entries.filter((e) => !e.name.startsWith(".git") && e.name !== ".obsidian").map((e) => e.isDirectory() ? `${e.name}/` : e.name).slice(0, 500).join("\n");
|
|
15200
15254
|
}
|
|
15201
15255
|
}),
|
|
@@ -15208,7 +15262,7 @@ function fileTools(root) {
|
|
|
15208
15262
|
}),
|
|
15209
15263
|
execute: async ({ path: p, offset = 0, limit = 600 }) => {
|
|
15210
15264
|
const file2 = safeResolve(root, p);
|
|
15211
|
-
const text2 = await
|
|
15265
|
+
const text2 = await fs4.readFile(file2, "utf-8");
|
|
15212
15266
|
const lines = text2.split("\n");
|
|
15213
15267
|
return lines.slice(offset, offset + limit).join("\n").slice(0, 6e4);
|
|
15214
15268
|
}
|
|
@@ -15642,7 +15696,7 @@ function invokeAgent(inv, opts = {}) {
|
|
|
15642
15696
|
}
|
|
15643
15697
|
|
|
15644
15698
|
// ../coding-core/dist/messages.js
|
|
15645
|
-
import { promises as
|
|
15699
|
+
import { promises as fs6 } from "fs";
|
|
15646
15700
|
|
|
15647
15701
|
// ../coding-core/dist/injected.js
|
|
15648
15702
|
var SYSTEM_REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/g;
|
|
@@ -15677,6 +15731,365 @@ function isHarnessEntry(e) {
|
|
|
15677
15731
|
return e.isMeta === true || e.isCompactSummary === true;
|
|
15678
15732
|
}
|
|
15679
15733
|
|
|
15734
|
+
// ../coding-core/dist/codex.js
|
|
15735
|
+
var SYSTEM_REMINDER_RE2 = /<system-reminder>[\s\S]*?<\/system-reminder>/g;
|
|
15736
|
+
var CODEX_INJECTED_TEXT_RE = /^\s*(<(environment_context|user_instructions|ENVIRONMENT_CONTEXT|turn_aborted)\b|#\s*AGENTS\.md instructions\b)/;
|
|
15737
|
+
function isCodexInjectedUserText(text2) {
|
|
15738
|
+
return CODEX_INJECTED_TEXT_RE.test(text2);
|
|
15739
|
+
}
|
|
15740
|
+
function codexContentText(content) {
|
|
15741
|
+
if (typeof content === "string")
|
|
15742
|
+
return content;
|
|
15743
|
+
if (!Array.isArray(content))
|
|
15744
|
+
return "";
|
|
15745
|
+
const parts = [];
|
|
15746
|
+
for (const item of content) {
|
|
15747
|
+
if (typeof item === "string") {
|
|
15748
|
+
parts.push(item);
|
|
15749
|
+
continue;
|
|
15750
|
+
}
|
|
15751
|
+
if (item && typeof item === "object") {
|
|
15752
|
+
const it = item;
|
|
15753
|
+
if (it.type === "input_text" || it.type === "output_text" || it.type === "text")
|
|
15754
|
+
parts.push(it.text || "");
|
|
15755
|
+
}
|
|
15756
|
+
}
|
|
15757
|
+
return parts.join("\n");
|
|
15758
|
+
}
|
|
15759
|
+
function sniffCodexRaw(raw) {
|
|
15760
|
+
let checked = 0;
|
|
15761
|
+
for (const lineRaw of raw.split("\n")) {
|
|
15762
|
+
const line = lineRaw.trim();
|
|
15763
|
+
if (!line)
|
|
15764
|
+
continue;
|
|
15765
|
+
if (checked++ >= 5)
|
|
15766
|
+
break;
|
|
15767
|
+
try {
|
|
15768
|
+
const e = JSON.parse(line);
|
|
15769
|
+
if (e.type === "session_meta" || e.type === "response_item" || e.type === "turn_context")
|
|
15770
|
+
return true;
|
|
15771
|
+
if (e.type === "user" || e.type === "assistant" || e.type === "summary" || e.type === "queue-operation")
|
|
15772
|
+
return false;
|
|
15773
|
+
} catch {
|
|
15774
|
+
}
|
|
15775
|
+
}
|
|
15776
|
+
return false;
|
|
15777
|
+
}
|
|
15778
|
+
var EXIT_CODE_RE = /(?:Process exited with code|Exit code:)\s+(\d+)/;
|
|
15779
|
+
function extractCodexEvents(raw) {
|
|
15780
|
+
const out = [];
|
|
15781
|
+
for (const lineRaw of raw.split("\n")) {
|
|
15782
|
+
const line = lineRaw.trim();
|
|
15783
|
+
if (!line)
|
|
15784
|
+
continue;
|
|
15785
|
+
let e;
|
|
15786
|
+
try {
|
|
15787
|
+
e = JSON.parse(line);
|
|
15788
|
+
} catch {
|
|
15789
|
+
continue;
|
|
15790
|
+
}
|
|
15791
|
+
if (e.type !== "response_item")
|
|
15792
|
+
continue;
|
|
15793
|
+
const p = e.payload ?? {};
|
|
15794
|
+
const t = typeof e.timestamp === "string" ? Date.parse(e.timestamp) : NaN;
|
|
15795
|
+
const ptype = p.type;
|
|
15796
|
+
if (ptype === "message") {
|
|
15797
|
+
const role = p.role;
|
|
15798
|
+
const text2 = codexContentText(p.content).replace(SYSTEM_REMINDER_RE2, "").trim();
|
|
15799
|
+
if (!text2)
|
|
15800
|
+
continue;
|
|
15801
|
+
if (role === "user") {
|
|
15802
|
+
if (isCodexInjectedUserText(text2))
|
|
15803
|
+
continue;
|
|
15804
|
+
out.push({ kind: "user", t, text: text2 });
|
|
15805
|
+
} else if (role === "assistant") {
|
|
15806
|
+
out.push({ kind: "assistant", t, text: text2 });
|
|
15807
|
+
}
|
|
15808
|
+
continue;
|
|
15809
|
+
}
|
|
15810
|
+
if (ptype === "function_call" || ptype === "custom_tool_call" || ptype === "local_shell_call") {
|
|
15811
|
+
const name17 = typeof p.name === "string" && p.name ? p.name : ptype === "local_shell_call" ? "shell" : String(ptype);
|
|
15812
|
+
const input = typeof p.arguments === "string" ? p.arguments : typeof p.input === "string" ? p.input : "";
|
|
15813
|
+
out.push({ kind: "tool", t, name: name17, input });
|
|
15814
|
+
continue;
|
|
15815
|
+
}
|
|
15816
|
+
if (ptype === "function_call_output" || ptype === "custom_tool_call_output") {
|
|
15817
|
+
const output = typeof p.output === "string" ? p.output : "";
|
|
15818
|
+
const m = EXIT_CODE_RE.exec(output.slice(0, 200));
|
|
15819
|
+
out.push({ kind: "tool_output", t, output, isError: !!m && m[1] !== "0" });
|
|
15820
|
+
}
|
|
15821
|
+
}
|
|
15822
|
+
return out;
|
|
15823
|
+
}
|
|
15824
|
+
|
|
15825
|
+
// ../coding-core/dist/cursor.js
|
|
15826
|
+
import { promises as fs5 } from "fs";
|
|
15827
|
+
var NODE_SQLITE = "node:sqlite";
|
|
15828
|
+
async function openCursorSqlite(dbPath) {
|
|
15829
|
+
try {
|
|
15830
|
+
await fs5.access(dbPath);
|
|
15831
|
+
} catch {
|
|
15832
|
+
return null;
|
|
15833
|
+
}
|
|
15834
|
+
let mod;
|
|
15835
|
+
try {
|
|
15836
|
+
mod = await import(NODE_SQLITE);
|
|
15837
|
+
} catch {
|
|
15838
|
+
return null;
|
|
15839
|
+
}
|
|
15840
|
+
const DatabaseSync = mod?.DatabaseSync;
|
|
15841
|
+
if (!DatabaseSync)
|
|
15842
|
+
return null;
|
|
15843
|
+
let db;
|
|
15844
|
+
try {
|
|
15845
|
+
db = new DatabaseSync(dbPath, { readOnly: true });
|
|
15846
|
+
} catch {
|
|
15847
|
+
try {
|
|
15848
|
+
db = new DatabaseSync(dbPath);
|
|
15849
|
+
} catch {
|
|
15850
|
+
return null;
|
|
15851
|
+
}
|
|
15852
|
+
}
|
|
15853
|
+
const asText = (v) => v == null ? null : typeof v === "string" ? v : Buffer.from(v).toString("utf-8");
|
|
15854
|
+
return {
|
|
15855
|
+
prefix(prefix) {
|
|
15856
|
+
try {
|
|
15857
|
+
const rows = db.prepare("SELECT key, value FROM cursorDiskKV WHERE key LIKE ? ESCAPE '\\'").all(likePrefix(prefix));
|
|
15858
|
+
return rows.map((r) => ({ key: r.key, value: asText(r.value) ?? "" }));
|
|
15859
|
+
} catch {
|
|
15860
|
+
return [];
|
|
15861
|
+
}
|
|
15862
|
+
},
|
|
15863
|
+
get(key) {
|
|
15864
|
+
try {
|
|
15865
|
+
const row = db.prepare("SELECT value FROM cursorDiskKV WHERE key = ?").get(key);
|
|
15866
|
+
return row ? asText(row.value) : null;
|
|
15867
|
+
} catch {
|
|
15868
|
+
return null;
|
|
15869
|
+
}
|
|
15870
|
+
},
|
|
15871
|
+
close() {
|
|
15872
|
+
try {
|
|
15873
|
+
db.close();
|
|
15874
|
+
} catch {
|
|
15875
|
+
}
|
|
15876
|
+
}
|
|
15877
|
+
};
|
|
15878
|
+
}
|
|
15879
|
+
function likePrefix(prefix) {
|
|
15880
|
+
return prefix.replace(/[\\%_]/g, (c) => "\\" + c) + "%";
|
|
15881
|
+
}
|
|
15882
|
+
var CURSOR_USER_QUERY_RE = /<user_query>\s*([\s\S]*?)\s*<\/user_query>/;
|
|
15883
|
+
function cleanUserText(raw) {
|
|
15884
|
+
let t = raw.replace(SYSTEM_REMINDER_RE, "");
|
|
15885
|
+
const m = t.match(CURSOR_USER_QUERY_RE);
|
|
15886
|
+
if (m)
|
|
15887
|
+
t = m[1];
|
|
15888
|
+
return t.trim();
|
|
15889
|
+
}
|
|
15890
|
+
var msFrom = (v) => {
|
|
15891
|
+
if (typeof v === "number" && Number.isFinite(v))
|
|
15892
|
+
return v;
|
|
15893
|
+
if (typeof v === "string") {
|
|
15894
|
+
const n = Date.parse(v);
|
|
15895
|
+
return Number.isFinite(n) ? n : null;
|
|
15896
|
+
}
|
|
15897
|
+
return null;
|
|
15898
|
+
};
|
|
15899
|
+
function readCursorComposer(db, composerId) {
|
|
15900
|
+
const cdRaw = db.get(`composerData:${composerId}`);
|
|
15901
|
+
if (!cdRaw)
|
|
15902
|
+
return null;
|
|
15903
|
+
let cd;
|
|
15904
|
+
try {
|
|
15905
|
+
cd = JSON.parse(cdRaw);
|
|
15906
|
+
} catch {
|
|
15907
|
+
return null;
|
|
15908
|
+
}
|
|
15909
|
+
const headers = Array.isArray(cd.fullConversationHeadersOnly) ? cd.fullConversationHeadersOnly : [];
|
|
15910
|
+
if (headers.length === 0)
|
|
15911
|
+
return null;
|
|
15912
|
+
const bubbles = /* @__PURE__ */ new Map();
|
|
15913
|
+
for (const row of db.prefix(`bubbleId:${composerId}:`)) {
|
|
15914
|
+
const bid = row.key.slice(`bubbleId:${composerId}:`.length);
|
|
15915
|
+
try {
|
|
15916
|
+
bubbles.set(bid, JSON.parse(row.value));
|
|
15917
|
+
} catch {
|
|
15918
|
+
}
|
|
15919
|
+
}
|
|
15920
|
+
const turns = [];
|
|
15921
|
+
let clock = msFrom(cd.createdAt) ?? 0;
|
|
15922
|
+
for (const h of headers) {
|
|
15923
|
+
const b = bubbles.get(h.bubbleId);
|
|
15924
|
+
if (!b)
|
|
15925
|
+
continue;
|
|
15926
|
+
const type = h.type === 1 ? 1 : 2;
|
|
15927
|
+
const tool2 = type === 2 && b.toolFormerData && typeof b.toolFormerData.name === "string" ? b.toolFormerData.name : null;
|
|
15928
|
+
const rawText = typeof b.text === "string" ? b.text : "";
|
|
15929
|
+
const text2 = type === 1 ? cleanUserText(rawText) : rawText.replace(SYSTEM_REMINDER_RE, "").trim();
|
|
15930
|
+
if (!text2 && !tool2)
|
|
15931
|
+
continue;
|
|
15932
|
+
const t = msFrom(b.createdAt);
|
|
15933
|
+
clock = Math.max(clock, t ?? clock + 1);
|
|
15934
|
+
const model = b.modelInfo && typeof b.modelInfo.modelName === "string" ? b.modelInfo.modelName : null;
|
|
15935
|
+
turns.push({ t: clock, type, text: text2, tool: tool2, model });
|
|
15936
|
+
}
|
|
15937
|
+
if (turns.length === 0)
|
|
15938
|
+
return null;
|
|
15939
|
+
const gitRepo = Array.isArray(cd.trackedGitRepos) && cd.trackedGitRepos[0] && typeof cd.trackedGitRepos[0].repoPath === "string" ? cd.trackedGitRepos[0].repoPath : null;
|
|
15940
|
+
return {
|
|
15941
|
+
composerId,
|
|
15942
|
+
createdAt: msFrom(cd.createdAt),
|
|
15943
|
+
updatedAt: msFrom(cd.lastUpdatedAt),
|
|
15944
|
+
name: typeof cd.name === "string" && cd.name.trim() ? cd.name.trim() : null,
|
|
15945
|
+
gitRepo,
|
|
15946
|
+
turns
|
|
15947
|
+
};
|
|
15948
|
+
}
|
|
15949
|
+
function sniffCursorRaw(raw) {
|
|
15950
|
+
for (const lineRaw of raw.split("\n")) {
|
|
15951
|
+
const line = lineRaw.trim();
|
|
15952
|
+
if (!line)
|
|
15953
|
+
continue;
|
|
15954
|
+
try {
|
|
15955
|
+
const e = JSON.parse(line);
|
|
15956
|
+
return (e.role === "user" || e.role === "assistant") && typeof e.message === "object" && e.message !== null && "content" in e.message && !("type" in e);
|
|
15957
|
+
} catch {
|
|
15958
|
+
return false;
|
|
15959
|
+
}
|
|
15960
|
+
}
|
|
15961
|
+
return false;
|
|
15962
|
+
}
|
|
15963
|
+
function jsonlText(content) {
|
|
15964
|
+
const parts = [];
|
|
15965
|
+
const tools = [];
|
|
15966
|
+
if (Array.isArray(content)) {
|
|
15967
|
+
for (const item of content) {
|
|
15968
|
+
if (!item || typeof item !== "object")
|
|
15969
|
+
continue;
|
|
15970
|
+
const it = item;
|
|
15971
|
+
if (it.type === "text" && it.text)
|
|
15972
|
+
parts.push(it.text);
|
|
15973
|
+
else if (it.type === "tool_use" && it.name)
|
|
15974
|
+
tools.push(it.name);
|
|
15975
|
+
}
|
|
15976
|
+
} else if (typeof content === "string")
|
|
15977
|
+
parts.push(content);
|
|
15978
|
+
return { text: parts.join("\n"), tools };
|
|
15979
|
+
}
|
|
15980
|
+
function parseCursorJsonl(raw, base) {
|
|
15981
|
+
const turns = [];
|
|
15982
|
+
let clock = base;
|
|
15983
|
+
for (const lineRaw of raw.split("\n")) {
|
|
15984
|
+
const line = lineRaw.trim();
|
|
15985
|
+
if (!line)
|
|
15986
|
+
continue;
|
|
15987
|
+
let e;
|
|
15988
|
+
try {
|
|
15989
|
+
e = JSON.parse(line);
|
|
15990
|
+
} catch {
|
|
15991
|
+
continue;
|
|
15992
|
+
}
|
|
15993
|
+
if (e.role !== "user" && e.role !== "assistant")
|
|
15994
|
+
continue;
|
|
15995
|
+
const { text: rawText, tools } = jsonlText(e.message?.content);
|
|
15996
|
+
const type = e.role === "user" ? 1 : 2;
|
|
15997
|
+
const text2 = type === 1 ? cleanUserText(rawText) : rawText.replace(SYSTEM_REMINDER_RE, "").trim();
|
|
15998
|
+
if (type === 2 && tools.length) {
|
|
15999
|
+
for (const tool2 of tools) {
|
|
16000
|
+
clock += 1;
|
|
16001
|
+
turns.push({ t: clock, type: 2, text: "", tool: tool2, model: null });
|
|
16002
|
+
}
|
|
16003
|
+
}
|
|
16004
|
+
if (!text2)
|
|
16005
|
+
continue;
|
|
16006
|
+
clock += 1;
|
|
16007
|
+
turns.push({ t: clock, type, text: text2, tool: null, model: null });
|
|
16008
|
+
}
|
|
16009
|
+
if (turns.length === 0)
|
|
16010
|
+
return null;
|
|
16011
|
+
return { composerId: "", createdAt: base, updatedAt: clock, name: null, gitRepo: null, turns };
|
|
16012
|
+
}
|
|
16013
|
+
function cursorMessages(c) {
|
|
16014
|
+
const out = [];
|
|
16015
|
+
let aiStart = 0;
|
|
16016
|
+
let aiParts = [];
|
|
16017
|
+
const flushAI = () => {
|
|
16018
|
+
if (!aiParts.length)
|
|
16019
|
+
return;
|
|
16020
|
+
out.push({ t: aiStart, role: "ai", text: aiParts.join("\n") });
|
|
16021
|
+
aiParts = [];
|
|
16022
|
+
};
|
|
16023
|
+
for (const turn of c.turns) {
|
|
16024
|
+
if (turn.type === 1) {
|
|
16025
|
+
flushAI();
|
|
16026
|
+
out.push({ t: turn.t, role: "user", text: turn.text });
|
|
16027
|
+
} else {
|
|
16028
|
+
if (aiParts.length === 0)
|
|
16029
|
+
aiStart = turn.t;
|
|
16030
|
+
if (turn.text)
|
|
16031
|
+
aiParts.push(turn.text);
|
|
16032
|
+
}
|
|
16033
|
+
}
|
|
16034
|
+
flushAI();
|
|
16035
|
+
return out;
|
|
16036
|
+
}
|
|
16037
|
+
function composerIdFromFile(file2) {
|
|
16038
|
+
const m = file2.match(/agent-transcripts\/([^/]+)\/[^/]+\.jsonl$/);
|
|
16039
|
+
return m ? m[1] : null;
|
|
16040
|
+
}
|
|
16041
|
+
async function loadCursorComposer(file2, raw, dbPath) {
|
|
16042
|
+
const cid = composerIdFromFile(file2);
|
|
16043
|
+
if (cid && dbPath) {
|
|
16044
|
+
const db = await openCursorSqlite(dbPath);
|
|
16045
|
+
if (db) {
|
|
16046
|
+
try {
|
|
16047
|
+
const c = readCursorComposer(db, cid);
|
|
16048
|
+
if (c)
|
|
16049
|
+
return c;
|
|
16050
|
+
} finally {
|
|
16051
|
+
db.close();
|
|
16052
|
+
}
|
|
16053
|
+
}
|
|
16054
|
+
}
|
|
16055
|
+
return parseCursorJsonl(raw, 0);
|
|
16056
|
+
}
|
|
16057
|
+
|
|
16058
|
+
// ../coding-core/dist/raw.js
|
|
16059
|
+
import path9 from "path";
|
|
16060
|
+
import os2 from "os";
|
|
16061
|
+
var SOURCE_ROOT_ENV_VARS = [
|
|
16062
|
+
"CLAUDE_PROJECTS_DIR",
|
|
16063
|
+
"CODEX_SESSIONS_DIR",
|
|
16064
|
+
"CURSOR_WORKSPACE_DIR",
|
|
16065
|
+
"CURSOR_PROJECTS_DIR",
|
|
16066
|
+
// Cursor's globalStorage dir (holds state.vscdb — the composer bubbles that
|
|
16067
|
+
// carry a Cursor session's real per-turn timestamps + content). Same
|
|
16068
|
+
// isolation contract: overriding any root disables every unset source.
|
|
16069
|
+
"CURSOR_GLOBAL_DIR"
|
|
16070
|
+
];
|
|
16071
|
+
var anyRootOverridden = () => SOURCE_ROOT_ENV_VARS.some((v) => !!process.env[v]);
|
|
16072
|
+
function resolveSourceRoot(envVar, ...defaultSegments) {
|
|
16073
|
+
const explicit = process.env[envVar];
|
|
16074
|
+
if (explicit)
|
|
16075
|
+
return explicit;
|
|
16076
|
+
if (anyRootOverridden())
|
|
16077
|
+
return null;
|
|
16078
|
+
return path9.join(os2.homedir(), ...defaultSegments);
|
|
16079
|
+
}
|
|
16080
|
+
var cursorGlobalRoot = () => resolveSourceRoot("CURSOR_GLOBAL_DIR", "Library", "Application Support", "Cursor", "User", "globalStorage");
|
|
16081
|
+
function cursorGlobalDbPath() {
|
|
16082
|
+
const root = cursorGlobalRoot();
|
|
16083
|
+
return root === null ? null : path9.join(root, "state.vscdb");
|
|
16084
|
+
}
|
|
16085
|
+
var MACHINE_CURSOR_FILE_RE = /^(.*[/\\]machines[/\\][^/\\]+[/\\]\.cursor)[/\\]projects[/\\]/;
|
|
16086
|
+
function cursorDbPathForFile(file2) {
|
|
16087
|
+
const m = file2.match(MACHINE_CURSOR_FILE_RE);
|
|
16088
|
+
if (m)
|
|
16089
|
+
return path9.join(m[1], "globalStorage", "state.vscdb");
|
|
16090
|
+
return cursorGlobalDbPath();
|
|
16091
|
+
}
|
|
16092
|
+
|
|
15680
16093
|
// ../coding-core/dist/messages.js
|
|
15681
16094
|
function extractText(content) {
|
|
15682
16095
|
if (typeof content === "string")
|
|
@@ -15688,13 +16101,62 @@ function extractText(content) {
|
|
|
15688
16101
|
function isToolResultOnly(content) {
|
|
15689
16102
|
return Array.isArray(content) && content.length > 0 && content.every((c) => c && typeof c === "object" && c.type === "tool_result");
|
|
15690
16103
|
}
|
|
16104
|
+
function extractMessagesCodex(raw) {
|
|
16105
|
+
const out = [];
|
|
16106
|
+
let aiProse = [];
|
|
16107
|
+
let aiTools = {};
|
|
16108
|
+
let aiStart = 0;
|
|
16109
|
+
const flushAI = () => {
|
|
16110
|
+
if (!aiProse.length && Object.keys(aiTools).length === 0)
|
|
16111
|
+
return;
|
|
16112
|
+
const toolStr = Object.entries(aiTools).map(([n, c]) => c > 1 ? `${n}\xD7${c}` : n).join(", ");
|
|
16113
|
+
let prose = aiProse.join(" ").replace(/\s+/g, " ").trim();
|
|
16114
|
+
if (prose.length > 2200)
|
|
16115
|
+
prose = prose.slice(0, 2200) + "\u2026";
|
|
16116
|
+
let text2 = prose;
|
|
16117
|
+
if (toolStr)
|
|
16118
|
+
text2 = (text2 ? text2 + " " : "") + `[ran ${toolStr}]`;
|
|
16119
|
+
if (text2)
|
|
16120
|
+
out.push({ t: aiStart, role: "ai", text: text2 });
|
|
16121
|
+
aiProse = [];
|
|
16122
|
+
aiTools = {};
|
|
16123
|
+
};
|
|
16124
|
+
for (const ev of extractCodexEvents(raw)) {
|
|
16125
|
+
if (!Number.isFinite(ev.t))
|
|
16126
|
+
continue;
|
|
16127
|
+
if (ev.kind === "user") {
|
|
16128
|
+
const text2 = humanTypedText(ev.text);
|
|
16129
|
+
if (text2) {
|
|
16130
|
+
flushAI();
|
|
16131
|
+
out.push({ t: ev.t, role: "user", text: text2 });
|
|
16132
|
+
}
|
|
16133
|
+
} else if (ev.kind === "assistant") {
|
|
16134
|
+
if (!aiProse.length && Object.keys(aiTools).length === 0)
|
|
16135
|
+
aiStart = ev.t;
|
|
16136
|
+
if (ev.text)
|
|
16137
|
+
aiProse.push(ev.text);
|
|
16138
|
+
} else if (ev.kind === "tool") {
|
|
16139
|
+
if (!aiProse.length && Object.keys(aiTools).length === 0)
|
|
16140
|
+
aiStart = ev.t;
|
|
16141
|
+
aiTools[ev.name] = (aiTools[ev.name] ?? 0) + 1;
|
|
16142
|
+
}
|
|
16143
|
+
}
|
|
16144
|
+
flushAI();
|
|
16145
|
+
return out.sort((a, b) => a.t - b.t);
|
|
16146
|
+
}
|
|
15691
16147
|
async function extractMessages(file2) {
|
|
15692
16148
|
let raw;
|
|
15693
16149
|
try {
|
|
15694
|
-
raw = await
|
|
16150
|
+
raw = await fs6.readFile(file2, "utf-8");
|
|
15695
16151
|
} catch {
|
|
15696
16152
|
return [];
|
|
15697
16153
|
}
|
|
16154
|
+
if (sniffCodexRaw(raw))
|
|
16155
|
+
return extractMessagesCodex(raw);
|
|
16156
|
+
if (sniffCursorRaw(raw)) {
|
|
16157
|
+
const c = await loadCursorComposer(file2, raw, cursorDbPathForFile(file2));
|
|
16158
|
+
return c ? cursorMessages(c) : [];
|
|
16159
|
+
}
|
|
15698
16160
|
const out = [];
|
|
15699
16161
|
const userTexts = /* @__PURE__ */ new Set();
|
|
15700
16162
|
const seenUuids = /* @__PURE__ */ new Set();
|
|
@@ -15780,20 +16242,20 @@ async function extractMessages(file2) {
|
|
|
15780
16242
|
}
|
|
15781
16243
|
|
|
15782
16244
|
// ../../lib/agents/coding/assets.ts
|
|
15783
|
-
import { promises as
|
|
15784
|
-
import
|
|
16245
|
+
import { promises as fs7 } from "fs";
|
|
16246
|
+
import path10 from "path";
|
|
15785
16247
|
import { fileURLToPath } from "url";
|
|
15786
|
-
var MODULE_DIR =
|
|
16248
|
+
var MODULE_DIR = path10.dirname(fileURLToPath(import.meta.url));
|
|
15787
16249
|
async function readCodingAsset(name17) {
|
|
15788
16250
|
const candidates = [
|
|
15789
|
-
|
|
16251
|
+
path10.join(MODULE_DIR, name17),
|
|
15790
16252
|
// dev: beside this file · bundled: beside the bundle
|
|
15791
|
-
|
|
16253
|
+
path10.resolve("lib", "agents", "coding", name17)
|
|
15792
16254
|
// legacy cwd-relative (repo-root cwd)
|
|
15793
16255
|
];
|
|
15794
16256
|
for (const p of candidates) {
|
|
15795
16257
|
try {
|
|
15796
|
-
return { text: await
|
|
16258
|
+
return { text: await fs7.readFile(p, "utf8"), path: p };
|
|
15797
16259
|
} catch {
|
|
15798
16260
|
}
|
|
15799
16261
|
}
|
|
@@ -15869,7 +16331,7 @@ var CELL_MIN = 30;
|
|
|
15869
16331
|
var CELLS = 48;
|
|
15870
16332
|
var GAP_MIN = 45;
|
|
15871
16333
|
if (process.argv.includes("--skip-llm")) process.env.FOCUS_SKIP_LLM = "1";
|
|
15872
|
-
var CODING =
|
|
16334
|
+
var CODING = path11.join(process.env.POLYMATH_DATA_DIR || path11.join(process.cwd(), ".data"), "coding");
|
|
15873
16335
|
var ld = (t) => new Date(t).toLocaleDateString("en-CA", { timeZone: TZ });
|
|
15874
16336
|
var DAY_START_MIN = 4 * 60;
|
|
15875
16337
|
var dayKey = (t) => ld(t - DAY_START_MIN * 6e4);
|
|
@@ -15968,29 +16430,23 @@ function parseModelJson(raw) {
|
|
|
15968
16430
|
}
|
|
15969
16431
|
}
|
|
15970
16432
|
async function main() {
|
|
15971
|
-
const
|
|
15972
|
-
try {
|
|
15973
|
-
await fs6.writeFile(LOCK, String(process.pid), { flag: "wx" });
|
|
15974
|
-
} catch {
|
|
15975
|
-
throw new Error(`another coding-focus run appears active (${LOCK}); delete only if stale`);
|
|
15976
|
-
}
|
|
16433
|
+
const release = await acquireStageLock(path11.join(CODING, ".focus.lock"), "coding-focus");
|
|
15977
16434
|
try {
|
|
15978
16435
|
await run2();
|
|
15979
16436
|
} finally {
|
|
15980
|
-
await
|
|
15981
|
-
});
|
|
16437
|
+
await release();
|
|
15982
16438
|
}
|
|
15983
16439
|
}
|
|
15984
16440
|
async function run2() {
|
|
15985
|
-
const sess = JSON.parse(await
|
|
15986
|
-
const CACHE =
|
|
15987
|
-
const cache = JSON.parse(await
|
|
16441
|
+
const sess = JSON.parse(await fs8.readFile(path11.join(CODING, "sessions.json"), "utf8")).filter((s) => s.klass === "interactive" && !s.duplicateOf);
|
|
16442
|
+
const CACHE = path11.join(CODING, ".msg-cache.json");
|
|
16443
|
+
const cache = JSON.parse(await fs8.readFile(CACHE, "utf8").catch(() => "{}"));
|
|
15988
16444
|
let hits = 0, misses = 0;
|
|
15989
16445
|
const byDay = /* @__PURE__ */ new Map();
|
|
15990
16446
|
const sessInfo = /* @__PURE__ */ new Map();
|
|
15991
16447
|
for (const s of sess) {
|
|
15992
16448
|
let meta;
|
|
15993
|
-
const st = await
|
|
16449
|
+
const st = await fs8.stat(s.file).catch(() => null);
|
|
15994
16450
|
if (!st) continue;
|
|
15995
16451
|
const key = `${Math.round(st.mtimeMs)}:${st.size}`;
|
|
15996
16452
|
const hit = cache[s.sessionId];
|
|
@@ -16038,15 +16494,15 @@ async function run2() {
|
|
|
16038
16494
|
}
|
|
16039
16495
|
if (dropped + deduped > 0) console.log(`focus: cleaned typed stream \u2014 ${dropped} template/loop msgs dropped \xB7 ${deduped} fork copies deduped`);
|
|
16040
16496
|
if (!byDay.size) throw new Error("focus: zero typed messages extracted \u2014 refusing to write an empty focus.json");
|
|
16041
|
-
await
|
|
16497
|
+
await fs8.writeFile(CACHE, JSON.stringify(cache));
|
|
16042
16498
|
console.log(`focus: msg-cache ${hits} hits \xB7 ${misses} parsed fresh`);
|
|
16043
|
-
const chart = JSON.parse(await
|
|
16499
|
+
const chart = JSON.parse(await fs8.readFile(path11.join(CODING, "day-chart.json"), "utf8").catch(() => "[]"));
|
|
16044
16500
|
const sidDayMin = /* @__PURE__ */ new Map();
|
|
16045
16501
|
for (const day of chart) for (const c of day.conversations) {
|
|
16046
16502
|
const m = sidDayMin.get(c.sessionId) ?? sidDayMin.set(c.sessionId, /* @__PURE__ */ new Map()).get(c.sessionId);
|
|
16047
16503
|
m.set(day.date, (m.get(day.date) ?? 0) + c.intervals.reduce((a, [x, y]) => a + (y - x) / 6e4, 0));
|
|
16048
16504
|
}
|
|
16049
|
-
const digest = JSON.parse(await
|
|
16505
|
+
const digest = JSON.parse(await fs8.readFile(path11.join(CODING, "day-digest.json"), "utf8").catch(() => "{}"));
|
|
16050
16506
|
const sidSummary = /* @__PURE__ */ new Map();
|
|
16051
16507
|
for (const day of digest.days ?? []) for (const c of day.conversations ?? []) if (c.summary) sidSummary.set(c.sessionId, c.summary);
|
|
16052
16508
|
const days = [], boundaries = [], gaps = [];
|
|
@@ -16195,7 +16651,7 @@ async function run2() {
|
|
|
16195
16651
|
gaps: gaps.slice(-60),
|
|
16196
16652
|
llm: null
|
|
16197
16653
|
};
|
|
16198
|
-
const prev = JSON.parse(await
|
|
16654
|
+
const prev = JSON.parse(await fs8.readFile(path11.join(CODING, "focus.json"), "utf8").catch(() => "null"));
|
|
16199
16655
|
if (!process.env.FOCUS_SKIP_LLM && !process.env.FOCUS_SKIP_CLUSTER) {
|
|
16200
16656
|
const recentDates = new Set(days.slice(-30).map((d) => d.date));
|
|
16201
16657
|
const recentSess = [...sessInfo.values()].filter((s) => [...s.byDate.keys()].some((d) => recentDates.has(d)) && s.all >= 2);
|
|
@@ -16325,11 +16781,11 @@ Return STRICT JSON only: {"bullets":["3-5 personalized bullets"],"skillMd":"the
|
|
|
16325
16781
|
out.llm.accountability = prev.llm.accountability;
|
|
16326
16782
|
console.log("focus: carrying previous accountability forward");
|
|
16327
16783
|
}
|
|
16328
|
-
await
|
|
16784
|
+
await fs8.writeFile(path11.join(CODING, "focus.json"), JSON.stringify(out, null, 2));
|
|
16329
16785
|
const h = (m) => (m / 60).toFixed(1) + "h";
|
|
16330
16786
|
console.log(`wrote .data/coding/focus.json \u2014 ${days.length} days \xB7 steering ${h(out.totals.steeringMin)} \xB7 nudging ${h(out.totals.nudgingMin)} \xB7 silent-in-span ${h(out.totals.silentMin)} \xB7 ${workstreams.length} workstreams \xB7 llm ${out.llm ? "ok" : "none"}`);
|
|
16331
16787
|
}
|
|
16332
|
-
var isMain = process.argv[1] &&
|
|
16788
|
+
var isMain = process.argv[1] && path11.resolve(process.argv[1]).includes("coding-focus");
|
|
16333
16789
|
if (isMain) main().catch((e) => {
|
|
16334
16790
|
console.error(e);
|
|
16335
16791
|
process.exit(1);
|