polymath-society 0.2.20 → 0.2.22
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 +23943 -21630
- 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 +19647 -17969
- package/dist/pipeline/coding-agglomerate.js +826 -82
- package/dist/pipeline/coding-aggregate.js +307 -23
- package/dist/pipeline/coding-build.js +453 -95
- package/dist/pipeline/coding-coaching.js +479 -88
- package/dist/pipeline/coding-day-digest.js +308 -36
- package/dist/pipeline/coding-delegation.js +376 -52
- package/dist/pipeline/coding-expertise.js +356 -62
- package/dist/pipeline/coding-flow.js +288 -15
- package/dist/pipeline/coding-focus.js +371 -51
- package/dist/pipeline/coding-frontier-detail.js +344 -50
- package/dist/pipeline/coding-frontier.js +7 -6
- package/dist/pipeline/coding-gap-dist.js +288 -15
- package/dist/pipeline/coding-gap.js +507 -115
- package/dist/pipeline/coding-grade.js +342 -45
- package/dist/pipeline/coding-growth.js +17041 -0
- package/dist/pipeline/coding-nutshell.js +15 -7
- package/dist/pipeline/coding-projects.js +7 -6
- package/dist/pipeline/coding-walkthrough.js +317 -37
- package/dist/pipeline/coding-workbrief.js +16387 -0
- package/dist/web/app.js +2095 -1395
- 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;
|
|
@@ -15768,6 +15822,274 @@ function extractCodexEvents(raw) {
|
|
|
15768
15822
|
return out;
|
|
15769
15823
|
}
|
|
15770
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
|
+
|
|
15771
16093
|
// ../coding-core/dist/messages.js
|
|
15772
16094
|
function extractText(content) {
|
|
15773
16095
|
if (typeof content === "string")
|
|
@@ -15825,12 +16147,16 @@ function extractMessagesCodex(raw) {
|
|
|
15825
16147
|
async function extractMessages(file2) {
|
|
15826
16148
|
let raw;
|
|
15827
16149
|
try {
|
|
15828
|
-
raw = await
|
|
16150
|
+
raw = await fs6.readFile(file2, "utf-8");
|
|
15829
16151
|
} catch {
|
|
15830
16152
|
return [];
|
|
15831
16153
|
}
|
|
15832
16154
|
if (sniffCodexRaw(raw))
|
|
15833
16155
|
return extractMessagesCodex(raw);
|
|
16156
|
+
if (sniffCursorRaw(raw)) {
|
|
16157
|
+
const c = await loadCursorComposer(file2, raw, cursorDbPathForFile(file2));
|
|
16158
|
+
return c ? cursorMessages(c) : [];
|
|
16159
|
+
}
|
|
15834
16160
|
const out = [];
|
|
15835
16161
|
const userTexts = /* @__PURE__ */ new Set();
|
|
15836
16162
|
const seenUuids = /* @__PURE__ */ new Set();
|
|
@@ -15916,20 +16242,20 @@ async function extractMessages(file2) {
|
|
|
15916
16242
|
}
|
|
15917
16243
|
|
|
15918
16244
|
// ../../lib/agents/coding/assets.ts
|
|
15919
|
-
import { promises as
|
|
15920
|
-
import
|
|
16245
|
+
import { promises as fs7 } from "fs";
|
|
16246
|
+
import path10 from "path";
|
|
15921
16247
|
import { fileURLToPath } from "url";
|
|
15922
|
-
var MODULE_DIR =
|
|
16248
|
+
var MODULE_DIR = path10.dirname(fileURLToPath(import.meta.url));
|
|
15923
16249
|
async function readCodingAsset(name17) {
|
|
15924
16250
|
const candidates = [
|
|
15925
|
-
|
|
16251
|
+
path10.join(MODULE_DIR, name17),
|
|
15926
16252
|
// dev: beside this file · bundled: beside the bundle
|
|
15927
|
-
|
|
16253
|
+
path10.resolve("lib", "agents", "coding", name17)
|
|
15928
16254
|
// legacy cwd-relative (repo-root cwd)
|
|
15929
16255
|
];
|
|
15930
16256
|
for (const p of candidates) {
|
|
15931
16257
|
try {
|
|
15932
|
-
return { text: await
|
|
16258
|
+
return { text: await fs7.readFile(p, "utf8"), path: p };
|
|
15933
16259
|
} catch {
|
|
15934
16260
|
}
|
|
15935
16261
|
}
|
|
@@ -16005,7 +16331,7 @@ var CELL_MIN = 30;
|
|
|
16005
16331
|
var CELLS = 48;
|
|
16006
16332
|
var GAP_MIN = 45;
|
|
16007
16333
|
if (process.argv.includes("--skip-llm")) process.env.FOCUS_SKIP_LLM = "1";
|
|
16008
|
-
var CODING =
|
|
16334
|
+
var CODING = path11.join(process.env.POLYMATH_DATA_DIR || path11.join(process.cwd(), ".data"), "coding");
|
|
16009
16335
|
var ld = (t) => new Date(t).toLocaleDateString("en-CA", { timeZone: TZ });
|
|
16010
16336
|
var DAY_START_MIN = 4 * 60;
|
|
16011
16337
|
var dayKey = (t) => ld(t - DAY_START_MIN * 6e4);
|
|
@@ -16104,29 +16430,23 @@ function parseModelJson(raw) {
|
|
|
16104
16430
|
}
|
|
16105
16431
|
}
|
|
16106
16432
|
async function main() {
|
|
16107
|
-
const
|
|
16108
|
-
try {
|
|
16109
|
-
await fs6.writeFile(LOCK, String(process.pid), { flag: "wx" });
|
|
16110
|
-
} catch {
|
|
16111
|
-
throw new Error(`another coding-focus run appears active (${LOCK}); delete only if stale`);
|
|
16112
|
-
}
|
|
16433
|
+
const release = await acquireStageLock(path11.join(CODING, ".focus.lock"), "coding-focus");
|
|
16113
16434
|
try {
|
|
16114
16435
|
await run2();
|
|
16115
16436
|
} finally {
|
|
16116
|
-
await
|
|
16117
|
-
});
|
|
16437
|
+
await release();
|
|
16118
16438
|
}
|
|
16119
16439
|
}
|
|
16120
16440
|
async function run2() {
|
|
16121
|
-
const sess = JSON.parse(await
|
|
16122
|
-
const CACHE =
|
|
16123
|
-
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(() => "{}"));
|
|
16124
16444
|
let hits = 0, misses = 0;
|
|
16125
16445
|
const byDay = /* @__PURE__ */ new Map();
|
|
16126
16446
|
const sessInfo = /* @__PURE__ */ new Map();
|
|
16127
16447
|
for (const s of sess) {
|
|
16128
16448
|
let meta;
|
|
16129
|
-
const st = await
|
|
16449
|
+
const st = await fs8.stat(s.file).catch(() => null);
|
|
16130
16450
|
if (!st) continue;
|
|
16131
16451
|
const key = `${Math.round(st.mtimeMs)}:${st.size}`;
|
|
16132
16452
|
const hit = cache[s.sessionId];
|
|
@@ -16174,15 +16494,15 @@ async function run2() {
|
|
|
16174
16494
|
}
|
|
16175
16495
|
if (dropped + deduped > 0) console.log(`focus: cleaned typed stream \u2014 ${dropped} template/loop msgs dropped \xB7 ${deduped} fork copies deduped`);
|
|
16176
16496
|
if (!byDay.size) throw new Error("focus: zero typed messages extracted \u2014 refusing to write an empty focus.json");
|
|
16177
|
-
await
|
|
16497
|
+
await fs8.writeFile(CACHE, JSON.stringify(cache));
|
|
16178
16498
|
console.log(`focus: msg-cache ${hits} hits \xB7 ${misses} parsed fresh`);
|
|
16179
|
-
const chart = JSON.parse(await
|
|
16499
|
+
const chart = JSON.parse(await fs8.readFile(path11.join(CODING, "day-chart.json"), "utf8").catch(() => "[]"));
|
|
16180
16500
|
const sidDayMin = /* @__PURE__ */ new Map();
|
|
16181
16501
|
for (const day of chart) for (const c of day.conversations) {
|
|
16182
16502
|
const m = sidDayMin.get(c.sessionId) ?? sidDayMin.set(c.sessionId, /* @__PURE__ */ new Map()).get(c.sessionId);
|
|
16183
16503
|
m.set(day.date, (m.get(day.date) ?? 0) + c.intervals.reduce((a, [x, y]) => a + (y - x) / 6e4, 0));
|
|
16184
16504
|
}
|
|
16185
|
-
const digest = JSON.parse(await
|
|
16505
|
+
const digest = JSON.parse(await fs8.readFile(path11.join(CODING, "day-digest.json"), "utf8").catch(() => "{}"));
|
|
16186
16506
|
const sidSummary = /* @__PURE__ */ new Map();
|
|
16187
16507
|
for (const day of digest.days ?? []) for (const c of day.conversations ?? []) if (c.summary) sidSummary.set(c.sessionId, c.summary);
|
|
16188
16508
|
const days = [], boundaries = [], gaps = [];
|
|
@@ -16331,7 +16651,7 @@ async function run2() {
|
|
|
16331
16651
|
gaps: gaps.slice(-60),
|
|
16332
16652
|
llm: null
|
|
16333
16653
|
};
|
|
16334
|
-
const prev = JSON.parse(await
|
|
16654
|
+
const prev = JSON.parse(await fs8.readFile(path11.join(CODING, "focus.json"), "utf8").catch(() => "null"));
|
|
16335
16655
|
if (!process.env.FOCUS_SKIP_LLM && !process.env.FOCUS_SKIP_CLUSTER) {
|
|
16336
16656
|
const recentDates = new Set(days.slice(-30).map((d) => d.date));
|
|
16337
16657
|
const recentSess = [...sessInfo.values()].filter((s) => [...s.byDate.keys()].some((d) => recentDates.has(d)) && s.all >= 2);
|
|
@@ -16461,11 +16781,11 @@ Return STRICT JSON only: {"bullets":["3-5 personalized bullets"],"skillMd":"the
|
|
|
16461
16781
|
out.llm.accountability = prev.llm.accountability;
|
|
16462
16782
|
console.log("focus: carrying previous accountability forward");
|
|
16463
16783
|
}
|
|
16464
|
-
await
|
|
16784
|
+
await fs8.writeFile(path11.join(CODING, "focus.json"), JSON.stringify(out, null, 2));
|
|
16465
16785
|
const h = (m) => (m / 60).toFixed(1) + "h";
|
|
16466
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"}`);
|
|
16467
16787
|
}
|
|
16468
|
-
var isMain = process.argv[1] &&
|
|
16788
|
+
var isMain = process.argv[1] && path11.resolve(process.argv[1]).includes("coding-focus");
|
|
16469
16789
|
if (isMain) main().catch((e) => {
|
|
16470
16790
|
console.error(e);
|
|
16471
16791
|
process.exit(1);
|