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.
Files changed (40) hide show
  1. package/dist/cli.js +24620 -22073
  2. package/dist/engine/chat-loops.js +8 -1
  3. package/dist/engine/exp-allfacets.js +8 -1
  4. package/dist/engine/exp-person.js +8 -1
  5. package/dist/engine/exp-pipeline.js +8 -1
  6. package/dist/engine/ingest-export.js +7 -6
  7. package/dist/engine/peak-demos.js +8 -1
  8. package/dist/engine/person-dimension-summary.js +8 -1
  9. package/dist/engine/person-facet-lines.js +8 -1
  10. package/dist/engine/person-headline.js +8 -1
  11. package/dist/engine/person-report.js +8 -1
  12. package/dist/engine/person-self-image.js +8 -1
  13. package/dist/engine/public-report.js +15 -7
  14. package/dist/engine/run-analysis.js +8 -1
  15. package/dist/engine/run-tagger.js +8 -1
  16. package/dist/index.js +19600 -17706
  17. package/dist/pipeline/FOCUS-EXAMPLES.md +127 -0
  18. package/dist/pipeline/FOCUS-RUBRIC.md +418 -0
  19. package/dist/pipeline/coding-agglomerate.js +947 -79
  20. package/dist/pipeline/coding-aggregate.js +443 -23
  21. package/dist/pipeline/coding-build.js +569 -97
  22. package/dist/pipeline/coding-coaching.js +651 -101
  23. package/dist/pipeline/coding-day-digest.js +417 -36
  24. package/dist/pipeline/coding-delegation.js +564 -68
  25. package/dist/pipeline/coding-expertise.js +477 -59
  26. package/dist/pipeline/coding-flow.js +424 -15
  27. package/dist/pipeline/coding-focus.js +507 -51
  28. package/dist/pipeline/coding-frontier-detail.js +465 -47
  29. package/dist/pipeline/coding-frontier.js +7 -6
  30. package/dist/pipeline/coding-gap-dist.js +424 -15
  31. package/dist/pipeline/coding-gap.js +679 -128
  32. package/dist/pipeline/coding-grade.js +469 -42
  33. package/dist/pipeline/coding-growth.js +17041 -0
  34. package/dist/pipeline/coding-nutshell.js +168 -151
  35. package/dist/pipeline/coding-projects.js +7 -6
  36. package/dist/pipeline/coding-walkthrough.js +461 -37
  37. package/dist/pipeline/coding-workbrief.js +16387 -0
  38. package/dist/web/app.js +2095 -1396
  39. package/dist/web/styles.css +1 -1
  40. 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 fs6 } from "fs";
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 path10 from "path";
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 fs2 } from "fs";
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 fs } from "fs";
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 fs.mkdir(path.dirname(logPath), { recursive: true });
221
- await fs.writeFile(logPath, L.join("\n"), "utf-8");
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 fs.writeFile(logPath.replace(/\.log$/, ".json"), JSON.stringify(json, null, 2), "utf-8");
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 fs2.mkdir(path2.dirname(f), { recursive: true });
241
- await fs2.appendFile(f, JSON.stringify(line) + "\n", "utf8");
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
- if (inv.model && !/^claude/i.test(inv.model)) args.push("--model", inv.model);
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: path11, errorMaps, issueData } = params;
2188
- const fullPath = [...path11, ...issueData.path || []];
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, path11, key) {
2358
+ constructor(parent, value, path12, key) {
2305
2359
  this._cachedPath = [];
2306
2360
  this.parent = parent;
2307
2361
  this.data = value;
2308
- this._path = path11;
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: path11 }) => `${baseURL}${path11}`,
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: path11 }) => `${baseURL}${path11}`,
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: path11 }) => `${baseURL}${path11}`,
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: path11 }) => `${baseURL}${path11}`,
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: path11 }) => `${baseURL}${path11}`,
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: path11 }) => `${baseURL}${path11}`,
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: path11 }) => `${baseURL}${path11}`,
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 fs3 } from "fs";
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 fs3.readdir(dir, { withFileTypes: true });
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 fs3.readFile(file2, "utf-8");
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 fs4 } from "fs";
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 fs4.readFile(file2, "utf-8");
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 fs5 } from "fs";
15784
- import path9 from "path";
16245
+ import { promises as fs7 } from "fs";
16246
+ import path10 from "path";
15785
16247
  import { fileURLToPath } from "url";
15786
- var MODULE_DIR = path9.dirname(fileURLToPath(import.meta.url));
16248
+ var MODULE_DIR = path10.dirname(fileURLToPath(import.meta.url));
15787
16249
  async function readCodingAsset(name17) {
15788
16250
  const candidates = [
15789
- path9.join(MODULE_DIR, name17),
16251
+ path10.join(MODULE_DIR, name17),
15790
16252
  // dev: beside this file · bundled: beside the bundle
15791
- path9.resolve("lib", "agents", "coding", name17)
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 fs5.readFile(p, "utf8"), path: p };
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 = path10.join(process.env.POLYMATH_DATA_DIR || path10.join(process.cwd(), ".data"), "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 LOCK = path10.join(CODING, ".focus.lock");
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 fs6.unlink(LOCK).catch(() => {
15981
- });
16437
+ await release();
15982
16438
  }
15983
16439
  }
15984
16440
  async function run2() {
15985
- const sess = JSON.parse(await fs6.readFile(path10.join(CODING, "sessions.json"), "utf8")).filter((s) => s.klass === "interactive" && !s.duplicateOf);
15986
- const CACHE = path10.join(CODING, ".msg-cache.json");
15987
- const cache = JSON.parse(await fs6.readFile(CACHE, "utf8").catch(() => "{}"));
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 fs6.stat(s.file).catch(() => null);
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 fs6.writeFile(CACHE, JSON.stringify(cache));
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 fs6.readFile(path10.join(CODING, "day-chart.json"), "utf8").catch(() => "[]"));
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 fs6.readFile(path10.join(CODING, "day-digest.json"), "utf8").catch(() => "{}"));
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 fs6.readFile(path10.join(CODING, "focus.json"), "utf8").catch(() => "null"));
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 fs6.writeFile(path10.join(CODING, "focus.json"), JSON.stringify(out, null, 2));
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] && path10.resolve(process.argv[1]).includes("coding-focus");
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);