polymath-society 0.2.29 → 0.2.30

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 CHANGED
@@ -55,13 +55,10 @@ function electronAppData() {
55
55
  function resolveDataRoot(env = process.env, cwd = process.cwd(), appData = electronAppData, home = os.homedir()) {
56
56
  const fromEnv = env.POLYMATH_DATA_DIR;
57
57
  if (fromEnv && fromEnv.trim()) return path.resolve(fromEnv);
58
- const local = path.join(cwd, ".data");
59
58
  const dflt = path.join(home, ".polymath-society", "data");
60
- if (existsSync(local) && hasCompletedAnalysis(local)) return local;
61
59
  const fromApp = appData();
62
60
  if (fromApp && hasCompletedAnalysis(fromApp)) return fromApp;
63
61
  if (hasCompletedAnalysis(dflt)) return dflt;
64
- if (existsSync(local)) return local;
65
62
  if (fromApp) return fromApp;
66
63
  return dflt;
67
64
  }
@@ -484,7 +481,8 @@ var init_cursor = __esm({
484
481
  });
485
482
 
486
483
  // ../coding-core/dist/raw.js
487
- import { promises as fs2 } from "fs";
484
+ import { promises as fs2, createReadStream } from "fs";
485
+ import readline from "readline";
488
486
  import path2 from "path";
489
487
  import os2 from "os";
490
488
  function resolveSourceRoot(envVar, ...defaultSegments) {
@@ -600,10 +598,18 @@ function blank(sessionId, source, file2) {
600
598
  klassReason: ""
601
599
  };
602
600
  }
603
- function parseClaudeCode(raw, sessionId, file2) {
601
+ function jsonlLines(file2) {
602
+ return readline.createInterface({ input: createReadStream(file2, { encoding: "utf-8" }), crlfDelay: Infinity });
603
+ }
604
+ function shedAgentBulk(s) {
605
+ if (s.klass === "agent" && s.events.length > 2)
606
+ s.events = [s.events[0], s.events[s.events.length - 1]];
607
+ return s;
608
+ }
609
+ async function parseClaudeCode(input, sessionId, file2) {
604
610
  const s = blank(sessionId, "claude-code", file2);
605
611
  const seen = /* @__PURE__ */ new Set();
606
- for (const lineRaw of raw.split("\n")) {
612
+ for await (const lineRaw of typeof input === "string" ? input.split("\n") : input) {
607
613
  const line = lineRaw.trim();
608
614
  if (!line)
609
615
  continue;
@@ -705,7 +711,7 @@ function parseClaudeCode(raw, sessionId, file2) {
705
711
  const c = classify(s);
706
712
  s.klass = c.klass;
707
713
  s.klassReason = c.reason;
708
- return s;
714
+ return shedAgentBulk(s);
709
715
  }
710
716
  function codexText(content) {
711
717
  if (typeof content === "string")
@@ -727,10 +733,10 @@ function codexText(content) {
727
733
  }
728
734
  return "";
729
735
  }
730
- function parseCodex(raw, file2) {
736
+ async function parseCodex(input, file2) {
731
737
  let sessionId = path2.basename(file2, ".jsonl");
732
738
  const s = blank(sessionId, "codex", file2);
733
- for (const lineRaw of raw.split("\n")) {
739
+ for await (const lineRaw of typeof input === "string" ? input.split("\n") : input) {
734
740
  const line = lineRaw.trim();
735
741
  if (!line)
736
742
  continue;
@@ -796,7 +802,7 @@ function parseCodex(raw, file2) {
796
802
  const c = classify(s);
797
803
  s.klass = c.klass;
798
804
  s.klassReason = c.reason;
799
- return s;
805
+ return shedAgentBulk(s);
800
806
  }
801
807
  async function readClaudeCodeAt(base2, machine) {
802
808
  const out = [];
@@ -820,13 +826,12 @@ async function readClaudeCodeAt(base2, machine) {
820
826
  }
821
827
  for (const f of files) {
822
828
  const file2 = path2.join(full, f);
823
- let raw;
829
+ let s = null;
824
830
  try {
825
- raw = await fs2.readFile(file2, "utf-8");
831
+ s = await parseClaudeCode(jsonlLines(file2), path2.basename(f, ".jsonl"), file2);
826
832
  } catch {
827
833
  continue;
828
834
  }
829
- const s = parseClaudeCode(raw, path2.basename(f, ".jsonl"), file2);
830
835
  if (s) {
831
836
  if (machine)
832
837
  s.machine = machine;
@@ -861,13 +866,12 @@ async function readCodexAt(base2, machine) {
861
866
  await walkJsonl(base2, files);
862
867
  const out = [];
863
868
  for (const file2 of files) {
864
- let raw;
869
+ let s = null;
865
870
  try {
866
- raw = await fs2.readFile(file2, "utf-8");
871
+ s = await parseCodex(jsonlLines(file2), file2);
867
872
  } catch {
868
873
  continue;
869
874
  }
870
- const s = parseCodex(raw, file2);
871
875
  if (s) {
872
876
  if (machine)
873
877
  s.machine = machine;
@@ -1073,7 +1077,7 @@ function rawSessionFromCursorComposer(c, file2, cwd) {
1073
1077
  const cl = classify(s);
1074
1078
  s.klass = cl.klass;
1075
1079
  s.klassReason = cl.reason;
1076
- return s;
1080
+ return shedAgentBulk(s);
1077
1081
  }
1078
1082
  function parseCursorTranscript(raw, composerId, file2, ws, fileMtime) {
1079
1083
  const s = blank(composerId, "cursor", file2);
@@ -1118,7 +1122,7 @@ function parseCursorTranscript(raw, composerId, file2, ws, fileMtime) {
1118
1122
  const c = classify(s);
1119
1123
  s.klass = c.klass;
1120
1124
  s.klassReason = c.reason;
1121
- return s;
1125
+ return shedAgentBulk(s);
1122
1126
  }
1123
1127
  function cursorWorkspaceSession(ws, idx) {
1124
1128
  if (ws.generations.length === 0)
@@ -1140,7 +1144,7 @@ function cursorWorkspaceSession(ws, idx) {
1140
1144
  const c = classify(s);
1141
1145
  s.klass = c.klass;
1142
1146
  s.klassReason = c.reason;
1143
- return s;
1147
+ return shedAgentBulk(s);
1144
1148
  }
1145
1149
  async function readCursorAt(roots, machine) {
1146
1150
  const workspaces = await readCursorWorkspaces(roots.workspace);
@@ -1254,6 +1258,8 @@ async function readAllSessions(opts2 = {}) {
1254
1258
  ]);
1255
1259
  const all = [...cc, ...cx, ...cr, ...mm];
1256
1260
  demoteTemplateFanouts(all);
1261
+ for (const s of all)
1262
+ shedAgentBulk(s);
1257
1263
  return all;
1258
1264
  }
1259
1265
  var SOURCE_ROOT_ENV_VARS, anyRootOverridden, claudeProjectsRoot, codexSessionsRoot, cursorWorkspaceRoot, cursorProjectsRoot, cursorGlobalRoot, MACHINE_CURSOR_FILE_RE, SKIP_DIR_RE, AGENT_CWD_RE, PERSONA_RE, OUTPUT_CONTRACT_RES, CAPS_HEADER_RE, PING_RE, ms, CURSOR_USER_QUERY_RE2, NODE_SQLITE2, FANOUT_PREFIX, FANOUT_MIN_SESSIONS;
@@ -18779,7 +18785,7 @@ var init_runStats = __esm({
18779
18785
  "../../lib/agents/shared/runStats.ts"() {
18780
18786
  "use strict";
18781
18787
  G = globalThis;
18782
- file = () => path11.join(process.cwd(), ".data", "run-stats.jsonl");
18788
+ file = () => path11.join(process.env.POLYMATH_DATA_DIR || path11.join(process.cwd(), ".data"), "run-stats.jsonl");
18783
18789
  }
18784
18790
  });
18785
18791
 
@@ -23424,6 +23430,74 @@ var init_chatPipeline = __esm({
23424
23430
  }
23425
23431
  });
23426
23432
 
23433
+ // src/ttyGuard.ts
23434
+ import { spawnSync as spawnSync3 } from "node:child_process";
23435
+ function stty(...args) {
23436
+ try {
23437
+ const r = spawnSync3("stty", args, { stdio: ["inherit", "pipe", "ignore"] });
23438
+ return r.status === 0 ? String(r.stdout ?? "").trim() : null;
23439
+ } catch {
23440
+ return null;
23441
+ }
23442
+ }
23443
+ function guardTty() {
23444
+ if (guarded || process.platform === "win32" || !process.stdin.isTTY) return;
23445
+ guarded = true;
23446
+ stty("isig", "icrnl");
23447
+ const saved = stty("-g");
23448
+ if (saved) process.on("exit", () => void stty(saved));
23449
+ }
23450
+ function attachPromptAbort(rl) {
23451
+ rl.on("SIGINT", () => {
23452
+ process.stderr.write("^C\n");
23453
+ rl.close();
23454
+ process.exit(130);
23455
+ });
23456
+ }
23457
+ function watchCtrlC(onCtrlC) {
23458
+ const stdin = process.stdin;
23459
+ if (process.platform === "win32" || !stdin.isTTY || typeof stdin.setRawMode !== "function") {
23460
+ return () => {
23461
+ };
23462
+ }
23463
+ const onData = (b) => {
23464
+ for (const byte of b) {
23465
+ if (byte === 3 || byte === 28) {
23466
+ onCtrlC();
23467
+ return;
23468
+ }
23469
+ if (byte === 26) {
23470
+ stdin.setRawMode(false);
23471
+ process.once("SIGCONT", () => {
23472
+ try {
23473
+ stdin.setRawMode(true);
23474
+ } catch {
23475
+ }
23476
+ });
23477
+ process.kill(process.pid, "SIGTSTP");
23478
+ }
23479
+ }
23480
+ };
23481
+ stdin.setRawMode(true);
23482
+ stdin.resume();
23483
+ stdin.on("data", onData);
23484
+ return () => {
23485
+ stdin.off("data", onData);
23486
+ try {
23487
+ stdin.setRawMode(false);
23488
+ } catch {
23489
+ }
23490
+ stdin.pause();
23491
+ };
23492
+ }
23493
+ var guarded;
23494
+ var init_ttyGuard = __esm({
23495
+ "src/ttyGuard.ts"() {
23496
+ "use strict";
23497
+ guarded = false;
23498
+ }
23499
+ });
23500
+
23427
23501
  // src/notify.ts
23428
23502
  import { spawn as spawn9 } from "node:child_process";
23429
23503
  function systemNotify(title, body) {
@@ -24211,7 +24285,7 @@ __export(wizard_exports, {
24211
24285
  import { promises as fs37 } from "fs";
24212
24286
  import os11 from "os";
24213
24287
  import path43 from "path";
24214
- import * as readline from "node:readline/promises";
24288
+ import * as readline2 from "node:readline/promises";
24215
24289
  async function scanJsonlDir(label, dir, maxDepth = 1) {
24216
24290
  let files = 0;
24217
24291
  let newest = 0;
@@ -24324,7 +24398,8 @@ function describeExport(f, i, included, hadPrevious) {
24324
24398
  ${dim(path43.basename(f.path))} ${dim(`(${f.note})`)}`;
24325
24399
  }
24326
24400
  async function runWizard() {
24327
- const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
24401
+ const rl = readline2.createInterface({ input: process.stdin, output: process.stderr });
24402
+ attachPromptAbort(rl);
24328
24403
  const say = (s = "") => console.error(s);
24329
24404
  const lineQueue = [];
24330
24405
  let waiting = null;
@@ -24454,22 +24529,19 @@ async function runWizard() {
24454
24529
  {
24455
24530
  const { looksLikeEmail: looksLikeEmail2, recordContact: recordContact2 } = await Promise.resolve().then(() => (init_reminderEmail(), reminderEmail_exports));
24456
24531
  say();
24457
- if (notifyEmail) {
24458
- say(` Updates go to ${bold(notifyEmail)}`);
24459
- } else {
24460
- const e = (await ask(` Your email ${dim("(recommended \u2014 we'll send your report link and occasional Polymath updates, and can nudge you when an export arrives; Enter to skip)")}: `)).trim();
24461
- if (e && looksLikeEmail2(e)) {
24462
- notifyEmail = e;
24463
- try {
24464
- await fs37.mkdir(dataDir, { recursive: true });
24465
- await fs37.writeFile(path43.join(dataDir, "notify-email.json"), JSON.stringify({ email: e }));
24466
- } catch {
24467
- }
24468
- await recordContact2(e, "wizard", reminderState.token).catch(() => false);
24469
- say(` ${green("\u2713")} Got it, we'll keep you posted at ${bold(e)}.`);
24470
- } else if (e) {
24471
- say(dim(` "${e}" doesn't look like an email \u2014 skipping.`));
24532
+ const e = (await ask(notifyEmail ? ` Your email ${dim(`(currently ${notifyEmail} \u2014 Enter if this is correct, or type a new one)`)}: ` : ` Your email ${dim("(recommended \u2014 we'll send your report link and occasional Polymath updates, and can nudge you when an export arrives; Enter to skip)")}: `)).trim();
24533
+ if (e && looksLikeEmail2(e)) {
24534
+ const correcting = !!notifyEmail;
24535
+ notifyEmail = e;
24536
+ try {
24537
+ await fs37.mkdir(dataDir, { recursive: true });
24538
+ await fs37.writeFile(path43.join(dataDir, "notify-email.json"), JSON.stringify({ email: e }));
24539
+ } catch {
24472
24540
  }
24541
+ await recordContact2(e, correcting ? "wizard-correction" : "wizard", reminderState.token).catch(() => false);
24542
+ say(` ${green("\u2713")} Got it, we'll keep you posted at ${bold(e)}.`);
24543
+ } else if (e) {
24544
+ say(dim(notifyEmail ? ` "${e}" doesn't look like an email \u2014 keeping ${notifyEmail}.` : ` "${e}" doesn't look like an email \u2014 skipping.`));
24473
24545
  }
24474
24546
  }
24475
24547
  const tracked = { token: reminderState.token };
@@ -24582,7 +24654,8 @@ async function runWizard() {
24582
24654
  say(` ${bold("Proposed schedule")} \u2014 sized to your plan (${plan.label}):`);
24583
24655
  say();
24584
24656
  say(` ${bold("Your analysis")} runs now \u2014 everything measured from your logs: words/day, flow state, focus, projects, parallelism`);
24585
- say(` ${bold("AI sections")} support for your plan is coming soon! Only the AI-graded sections (judgement, agency, taste, growth) won't be visible yet`);
24657
+ const planPhrase = plan.tier === "pro" ? "the $20 Claude Pro plan" : plan.tier === "gpt_plus" ? "the $20 ChatGPT Plus plan" : "the free ChatGPT plan";
24658
+ say(` ${bold("AI sections")} not supported on ${planPhrase} just yet \u2014 coming soon! Only the AI-graded sections (judgement, agency, taste, growth) won't be visible`);
24586
24659
  say();
24587
24660
  await ask(` Press Enter to run your analysis`).catch(() => "");
24588
24661
  say(dim(" On it. The report link appears right away.\n"));
@@ -24645,7 +24718,8 @@ function newExportsSince(found, m) {
24645
24718
  }
24646
24719
  async function returningUserFlow(dataDir) {
24647
24720
  const say = (s = "") => console.error(s);
24648
- const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
24721
+ const rl = readline2.createInterface({ input: process.stdin, output: process.stderr });
24722
+ attachPromptAbort(rl);
24649
24723
  try {
24650
24724
  say();
24651
24725
  say(bold(" What would you like to do?"));
@@ -24692,17 +24766,18 @@ async function askEmailAndQueueReminder(dataDir, say, ask) {
24692
24766
  }
24693
24767
  const clicked = await fetchClickedKinds2(state.token);
24694
24768
  if (!clicked.length) return;
24695
- if (!email) {
24696
- const e = (await ask(` Leave your email and we'll remind you when your exports should be ready ${dim("(Enter to skip)")}`)).trim();
24769
+ {
24770
+ const e = (await ask(email ? ` Your email ${dim(`(currently ${email} \u2014 Enter if this is correct, or type a new one)`)}: ` : ` Leave your email and we'll remind you when your exports should be ready ${dim("(Enter to skip)")}`)).trim();
24697
24771
  if (e && looksLikeEmail2(e)) {
24772
+ const correcting = !!email;
24698
24773
  email = e;
24699
24774
  await fs37.mkdir(dataDir, { recursive: true }).catch(() => {
24700
24775
  });
24701
24776
  await fs37.writeFile(path43.join(dataDir, "notify-email.json"), JSON.stringify({ email: e })).catch(() => {
24702
24777
  });
24703
- await recordContact2(e, "add-sources", state.token).catch(() => false);
24778
+ await recordContact2(e, correcting ? "wizard-correction" : "add-sources", state.token).catch(() => false);
24704
24779
  } else if (e) {
24705
- say(dim(` "${e}" doesn't look like an email \u2014 skipping the reminder.`));
24780
+ say(dim(email ? ` "${e}" doesn't look like an email \u2014 keeping ${email}.` : ` "${e}" doesn't look like an email \u2014 skipping the reminder.`));
24706
24781
  }
24707
24782
  }
24708
24783
  if (!email) return;
@@ -24844,6 +24919,7 @@ var init_wizard = __esm({
24844
24919
  init_exportScan();
24845
24920
  init_manifest();
24846
24921
  init_dataHome();
24922
+ init_ttyGuard();
24847
24923
  init_raw2();
24848
24924
  color = process.stdout.isTTY && !process.env.NO_COLOR;
24849
24925
  dim = (s) => color ? `\x1B[2m${s}\x1B[0m` : s;
@@ -24891,6 +24967,7 @@ function makeMultiBar(out = process.stderr) {
24891
24967
  return ` ${name17.padEnd(6)} [${"\u2588".repeat(fill)}${"\u2591".repeat(width - fill)}] ${String(Math.round(l.shown * 100)).padStart(3)}%`;
24892
24968
  };
24893
24969
  const out2 = [];
24970
+ out2.push("");
24894
24971
  out2.push("This is a background process. We'll let you know when it's finished.");
24895
24972
  out2.push("It may take anywhere from 30 minutes to an hour.");
24896
24973
  out2.push("");
@@ -25068,8 +25145,8 @@ try {
25068
25145
  import { promises as fs38, existsSync as existsSync7 } from "fs";
25069
25146
  import path44 from "path";
25070
25147
  import { fileURLToPath as fileURLToPath5 } from "url";
25071
- import { spawnSync as spawnSync3 } from "child_process";
25072
- import readline2 from "readline";
25148
+ import { spawnSync as spawnSync4 } from "child_process";
25149
+ import readline3 from "readline";
25073
25150
 
25074
25151
  // src/openBrowser.ts
25075
25152
  import { spawn } from "child_process";
@@ -28105,6 +28182,7 @@ init_auth();
28105
28182
  init_pipeline2();
28106
28183
  init_chatPipeline();
28107
28184
  init_manifest();
28185
+ init_ttyGuard();
28108
28186
  init_profile();
28109
28187
  var __dirname2 = path44.dirname(fileURLToPath5(import.meta.url));
28110
28188
  var REPO_ROOT = path44.resolve(__dirname2, "..", "..", "..");
@@ -28256,8 +28334,9 @@ PROJECTS`);
28256
28334
  log(``);
28257
28335
  }
28258
28336
  async function askYesNo(q, def = true) {
28259
- const readline3 = await import("node:readline/promises");
28260
- const rl = readline3.createInterface({ input: process.stdin, output: process.stderr });
28337
+ const readline4 = await import("node:readline/promises");
28338
+ const rl = readline4.createInterface({ input: process.stdin, output: process.stderr });
28339
+ attachPromptAbort(rl);
28261
28340
  try {
28262
28341
  for (; ; ) {
28263
28342
  const a = (await rl.question(`${q} `)).trim().toLowerCase();
@@ -28286,6 +28365,7 @@ async function runGrade(opts2, provider, profile) {
28286
28365
  await provider.criteriaMean(profile.sessions);
28287
28366
  }
28288
28367
  async function main() {
28368
+ guardTty();
28289
28369
  if (process.argv[2] === "remind-exports") {
28290
28370
  const { runReminder: runReminder2 } = await Promise.resolve().then(() => (init_remind(), remind_exports));
28291
28371
  const argv = process.argv.slice(3);
@@ -28313,8 +28393,13 @@ async function main() {
28313
28393
  await printBanner2();
28314
28394
  console.error("");
28315
28395
  await maybePrintUpdateNotice(opts2);
28316
- console.error(` data home: ${DATA_ROOT}`);
28317
- console.error(" Checking for existing analysis\u2026");
28396
+ {
28397
+ const { osc8: osc82 } = await Promise.resolve().then(() => (init_exportLinks(), exportLinks_exports));
28398
+ const boldTty = process.stderr.isTTY && !process.env.NO_COLOR;
28399
+ const b = (t) => boldTty ? `\x1B[1m${t}\x1B[0m` : t;
28400
+ console.error(` ${b("Step 0 \xB7 Want to see some sample reports before you run?")} ${osc82("https://polymathsociety.us/sample", "https://polymathsociety.us/sample")}`);
28401
+ console.error("");
28402
+ }
28318
28403
  const prior = process.env.POLYMATH_WIZARD === "1" ? null : await readPriorAnalysis();
28319
28404
  if (prior) {
28320
28405
  console.error(` Found your finished report \u2014 ${prior.graded} graded sessions, last updated ${prior.when}.`);
@@ -28769,6 +28854,7 @@ No analysis here yet \u2014 computing the instant deterministic metrics now (fre
28769
28854
  };
28770
28855
  process.on("SIGINT", shutdown(130));
28771
28856
  process.on("SIGTERM", shutdown(143));
28857
+ watchCtrlC(() => void shutdown(130)());
28772
28858
  return;
28773
28859
  }
28774
28860
  const profile = await analyze({ codex: opts2.codex, idleGapMin: opts2.idleGapMin, tz: opts2.tz, spanHourMin: opts2.spanHourMin });
@@ -28805,7 +28891,8 @@ async function promptAutoUpdate(current, latest) {
28805
28891
  console.error(`
28806
28892
  New version available: polymath-society ${current} \u2192 ${latest}`);
28807
28893
  const answer = await new Promise((resolve2) => {
28808
- const rl = readline2.createInterface({ input: process.stdin, output: process.stderr });
28894
+ const rl = readline3.createInterface({ input: process.stdin, output: process.stderr });
28895
+ attachPromptAbort(rl);
28809
28896
  const timer = setTimeout(() => {
28810
28897
  rl.close();
28811
28898
  resolve2("");
@@ -28823,7 +28910,7 @@ async function promptAutoUpdate(current, latest) {
28823
28910
  console.error(`
28824
28911
  Updating\u2026
28825
28912
  `);
28826
- const install = spawnSync3("npm", ["install", "-g", "polymath-society@latest"], {
28913
+ const install = spawnSync4("npm", ["install", "-g", "polymath-society@latest"], {
28827
28914
  stdio: "inherit",
28828
28915
  shell: process.platform === "win32"
28829
28916
  });
@@ -28837,7 +28924,7 @@ async function promptAutoUpdate(current, latest) {
28837
28924
  console.error(`
28838
28925
  Updated to ${latest}. Relaunching\u2026
28839
28926
  `);
28840
- const relaunch = spawnSync3("polymath-society", process.argv.slice(2), {
28927
+ const relaunch = spawnSync4("polymath-society", process.argv.slice(2), {
28841
28928
  stdio: "inherit",
28842
28929
  shell: process.platform === "win32"
28843
28930
  });
@@ -16505,7 +16505,7 @@ import path7 from "path";
16505
16505
  import { appendFileSync, mkdirSync } from "fs";
16506
16506
  import path6 from "path";
16507
16507
  var G = globalThis;
16508
- var file = () => path6.join(process.cwd(), ".data", "run-stats.jsonl");
16508
+ var file = () => path6.join(process.env.POLYMATH_DATA_DIR || path6.join(process.cwd(), ".data"), "run-stats.jsonl");
16509
16509
  function write(ev) {
16510
16510
  try {
16511
16511
  mkdirSync(path6.dirname(file()), { recursive: true });
@@ -15302,7 +15302,7 @@ import path8 from "path";
15302
15302
  import { appendFileSync, mkdirSync } from "fs";
15303
15303
  import path7 from "path";
15304
15304
  var G = globalThis;
15305
- var file = () => path7.join(process.cwd(), ".data", "run-stats.jsonl");
15305
+ var file = () => path7.join(process.env.POLYMATH_DATA_DIR || path7.join(process.cwd(), ".data"), "run-stats.jsonl");
15306
15306
  function write(ev) {
15307
15307
  try {
15308
15308
  mkdirSync(path7.dirname(file()), { recursive: true });
@@ -15302,7 +15302,7 @@ import path8 from "path";
15302
15302
  import { appendFileSync, mkdirSync } from "fs";
15303
15303
  import path7 from "path";
15304
15304
  var G = globalThis;
15305
- var file = () => path7.join(process.cwd(), ".data", "run-stats.jsonl");
15305
+ var file = () => path7.join(process.env.POLYMATH_DATA_DIR || path7.join(process.cwd(), ".data"), "run-stats.jsonl");
15306
15306
  function write(ev) {
15307
15307
  try {
15308
15308
  mkdirSync(path7.dirname(file()), { recursive: true });
@@ -15297,7 +15297,7 @@ import path7 from "path";
15297
15297
  import { appendFileSync, mkdirSync } from "fs";
15298
15298
  import path6 from "path";
15299
15299
  var G = globalThis;
15300
- var file = () => path6.join(process.cwd(), ".data", "run-stats.jsonl");
15300
+ var file = () => path6.join(process.env.POLYMATH_DATA_DIR || path6.join(process.cwd(), ".data"), "run-stats.jsonl");
15301
15301
  function write(ev) {
15302
15302
  try {
15303
15303
  mkdirSync(path6.dirname(file()), { recursive: true });
@@ -16293,7 +16293,7 @@ import path9 from "path";
16293
16293
  import { appendFileSync, mkdirSync } from "fs";
16294
16294
  import path8 from "path";
16295
16295
  var G = globalThis;
16296
- var file = () => path8.join(process.cwd(), ".data", "run-stats.jsonl");
16296
+ var file = () => path8.join(process.env.POLYMATH_DATA_DIR || path8.join(process.cwd(), ".data"), "run-stats.jsonl");
16297
16297
  function write(ev) {
16298
16298
  try {
16299
16299
  mkdirSync(path8.dirname(file()), { recursive: true });
@@ -16293,7 +16293,7 @@ import path9 from "path";
16293
16293
  import { appendFileSync, mkdirSync } from "fs";
16294
16294
  import path8 from "path";
16295
16295
  var G = globalThis;
16296
- var file = () => path8.join(process.cwd(), ".data", "run-stats.jsonl");
16296
+ var file = () => path8.join(process.env.POLYMATH_DATA_DIR || path8.join(process.cwd(), ".data"), "run-stats.jsonl");
16297
16297
  function write(ev) {
16298
16298
  try {
16299
16299
  mkdirSync(path8.dirname(file()), { recursive: true });
@@ -16293,7 +16293,7 @@ import path9 from "path";
16293
16293
  import { appendFileSync, mkdirSync } from "fs";
16294
16294
  import path8 from "path";
16295
16295
  var G = globalThis;
16296
- var file = () => path8.join(process.cwd(), ".data", "run-stats.jsonl");
16296
+ var file = () => path8.join(process.env.POLYMATH_DATA_DIR || path8.join(process.cwd(), ".data"), "run-stats.jsonl");
16297
16297
  function write(ev) {
16298
16298
  try {
16299
16299
  mkdirSync(path8.dirname(file()), { recursive: true });
@@ -16293,7 +16293,7 @@ import path9 from "path";
16293
16293
  import { appendFileSync, mkdirSync } from "fs";
16294
16294
  import path8 from "path";
16295
16295
  var G = globalThis;
16296
- var file = () => path8.join(process.cwd(), ".data", "run-stats.jsonl");
16296
+ var file = () => path8.join(process.env.POLYMATH_DATA_DIR || path8.join(process.cwd(), ".data"), "run-stats.jsonl");
16297
16297
  function write(ev) {
16298
16298
  try {
16299
16299
  mkdirSync(path8.dirname(file()), { recursive: true });
@@ -16293,7 +16293,7 @@ import path9 from "path";
16293
16293
  import { appendFileSync, mkdirSync } from "fs";
16294
16294
  import path8 from "path";
16295
16295
  var G = globalThis;
16296
- var file = () => path8.join(process.cwd(), ".data", "run-stats.jsonl");
16296
+ var file = () => path8.join(process.env.POLYMATH_DATA_DIR || path8.join(process.cwd(), ".data"), "run-stats.jsonl");
16297
16297
  function write(ev) {
16298
16298
  try {
16299
16299
  mkdirSync(path8.dirname(file()), { recursive: true });
@@ -16245,7 +16245,7 @@ import path10 from "path";
16245
16245
  import { appendFileSync, mkdirSync } from "fs";
16246
16246
  import path9 from "path";
16247
16247
  var G = globalThis;
16248
- var file = () => path9.join(process.cwd(), ".data", "run-stats.jsonl");
16248
+ var file = () => path9.join(process.env.POLYMATH_DATA_DIR || path9.join(process.cwd(), ".data"), "run-stats.jsonl");
16249
16249
  function write(ev) {
16250
16250
  try {
16251
16251
  mkdirSync(path9.dirname(file()), { recursive: true });
@@ -15291,7 +15291,7 @@ import path7 from "path";
15291
15291
  import { appendFileSync, mkdirSync } from "fs";
15292
15292
  import path6 from "path";
15293
15293
  var G = globalThis;
15294
- var file = () => path6.join(process.cwd(), ".data", "run-stats.jsonl");
15294
+ var file = () => path6.join(process.env.POLYMATH_DATA_DIR || path6.join(process.cwd(), ".data"), "run-stats.jsonl");
15295
15295
  function write(ev) {
15296
15296
  try {
15297
15297
  mkdirSync(path6.dirname(file()), { recursive: true });
@@ -15414,7 +15414,7 @@ import path10 from "path";
15414
15414
  import { appendFileSync, mkdirSync } from "fs";
15415
15415
  import path9 from "path";
15416
15416
  var G = globalThis;
15417
- var file = () => path9.join(process.cwd(), ".data", "run-stats.jsonl");
15417
+ var file = () => path9.join(process.env.POLYMATH_DATA_DIR || path9.join(process.cwd(), ".data"), "run-stats.jsonl");
15418
15418
  function write(ev) {
15419
15419
  try {
15420
15420
  mkdirSync(path9.dirname(file()), { recursive: true });
@@ -15391,7 +15391,7 @@ import path9 from "path";
15391
15391
  import { appendFileSync, mkdirSync } from "fs";
15392
15392
  import path8 from "path";
15393
15393
  var G = globalThis;
15394
- var file = () => path8.join(process.cwd(), ".data", "run-stats.jsonl");
15394
+ var file = () => path8.join(process.env.POLYMATH_DATA_DIR || path8.join(process.cwd(), ".data"), "run-stats.jsonl");
15395
15395
  function write(ev) {
15396
15396
  try {
15397
15397
  mkdirSync(path8.dirname(file()), { recursive: true });
@@ -15403,10 +15403,11 @@ function hhmm() {
15403
15403
  const d = /* @__PURE__ */ new Date();
15404
15404
  return `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`;
15405
15405
  }
15406
- function startRun(label, total) {
15407
- G.__runStats = { label, total, done: 0, failed: 0, startedAt: Date.now(), limitHits: 0, lastWall: 0 };
15408
- console.log(`[run-stats] START "${label}" \u2014 ${total} items @ ${hhmm()}`);
15409
- write({ event: "start", label, total });
15406
+ function startRun(label, total, alreadyDone = 0) {
15407
+ G.__runStats = { label, total, done: alreadyDone, failed: 0, startedAt: Date.now(), limitHits: 0, lastWall: 0 };
15408
+ console.log(`[run-stats] START "${label}" \u2014 ${total} items${alreadyDone ? ` (${alreadyDone} already done, resuming)` : ""} @ ${hhmm()}`);
15409
+ if (alreadyDone > 0) console.log(` \u03A3 ${alreadyDone}/${total}`);
15410
+ write({ event: "start", label, total, ...alreadyDone ? { alreadyDone } : {} });
15410
15411
  }
15411
15412
  function snapshot() {
15412
15413
  const p = G.__runStats;