polymath-society 0.2.5 → 0.2.6

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
@@ -811,6 +811,50 @@ var init_raw2 = __esm({
811
811
  }
812
812
  });
813
813
 
814
+ // ../coding-core/dist/gate.js
815
+ function isGradable(s) {
816
+ return s.humanChars >= GATE.minHumanChars && s.humanTurns >= GATE.minHumanTurns;
817
+ }
818
+ function isTrivial(s) {
819
+ return s.humanTurns < GATE.trivialHumanTurns || s.humanChars < GATE.trivialHumanChars;
820
+ }
821
+ function partition(sessions) {
822
+ const gradable = [], thin = [], trivial = [];
823
+ for (const s of sessions)
824
+ (isGradable(s) ? gradable : isTrivial(s) ? trivial : thin).push(s);
825
+ return { gradable, thin, trivial };
826
+ }
827
+ var GATE;
828
+ var init_gate = __esm({
829
+ "../coding-core/dist/gate.js"() {
830
+ "use strict";
831
+ GATE = {
832
+ minHumanChars: 800,
833
+ // the user must have actually said something substantial
834
+ minHumanTurns: 3,
835
+ // …over enough back-and-forth to reveal how they work
836
+ trivialHumanChars: 300,
837
+ // below this = a one-liner, definitely trivial
838
+ trivialHumanTurns: 2
839
+ };
840
+ }
841
+ });
842
+
843
+ // src/gate.ts
844
+ var gate_exports = {};
845
+ __export(gate_exports, {
846
+ GATE: () => GATE,
847
+ isGradable: () => isGradable,
848
+ isTrivial: () => isTrivial,
849
+ partition: () => partition
850
+ });
851
+ var init_gate2 = __esm({
852
+ "src/gate.ts"() {
853
+ "use strict";
854
+ init_gate();
855
+ }
856
+ });
857
+
814
858
  // src/grade/adapter.ts
815
859
  function extractJson(text2) {
816
860
  const fences = [...text2.matchAll(/```json\s*([\s\S]*?)```/gi)];
@@ -1318,16 +1362,16 @@ var require_secure_json_parse = __commonJS({
1318
1362
  });
1319
1363
 
1320
1364
  // src/manifest.ts
1321
- import { promises as fs24 } from "fs";
1322
- import path30 from "path";
1365
+ import { promises as fs22 } from "fs";
1366
+ import path27 from "path";
1323
1367
  function manifestPath(dataDir) {
1324
- return path30.join(dataDir, MANIFEST_BASENAME);
1368
+ return path27.join(dataDir, MANIFEST_BASENAME);
1325
1369
  }
1326
1370
  async function readManifest(dataDir) {
1327
1371
  const p = manifestPath(dataDir);
1328
1372
  let raw;
1329
1373
  try {
1330
- raw = await fs24.readFile(p, "utf-8");
1374
+ raw = await fs22.readFile(p, "utf-8");
1331
1375
  } catch {
1332
1376
  return null;
1333
1377
  }
@@ -1354,8 +1398,8 @@ async function readManifest(dataDir) {
1354
1398
  };
1355
1399
  }
1356
1400
  async function writeManifest(dataDir, m) {
1357
- await fs24.mkdir(dataDir, { recursive: true });
1358
- await fs24.writeFile(manifestPath(dataDir), JSON.stringify(m, null, 2));
1401
+ await fs22.mkdir(dataDir, { recursive: true });
1402
+ await fs22.writeFile(manifestPath(dataDir), JSON.stringify(m, null, 2));
1359
1403
  }
1360
1404
  function parsePicker(input, defaults) {
1361
1405
  const t = input.trim().toLowerCase();
@@ -1380,30 +1424,6 @@ var init_manifest = __esm({
1380
1424
  }
1381
1425
  });
1382
1426
 
1383
- // src/notify.ts
1384
- import { spawn as spawn8 } from "node:child_process";
1385
- function systemNotify(title, body) {
1386
- try {
1387
- const opts = { stdio: "ignore" };
1388
- if (process.platform === "darwin") {
1389
- spawn8("osascript", ["-e", `display notification ${JSON.stringify(body)} with title ${JSON.stringify(title)} sound name "Glass"`], opts).on("error", () => {
1390
- });
1391
- } else if (process.platform === "linux") {
1392
- spawn8("notify-send", [title, body], opts).on("error", () => {
1393
- });
1394
- }
1395
- } catch {
1396
- }
1397
- console.error(`
1398
- \u{1F514} ${title} \u2014 ${body}
1399
- `);
1400
- }
1401
- var init_notify = __esm({
1402
- "src/notify.ts"() {
1403
- "use strict";
1404
- }
1405
- });
1406
-
1407
1427
  // src/exportLinks.ts
1408
1428
  var exportLinks_exports = {};
1409
1429
  __export(exportLinks_exports, {
@@ -1450,6 +1470,30 @@ var init_exportLinks = __esm({
1450
1470
  }
1451
1471
  });
1452
1472
 
1473
+ // src/notify.ts
1474
+ import { spawn as spawn8 } from "node:child_process";
1475
+ function systemNotify(title, body) {
1476
+ try {
1477
+ const opts = { stdio: "ignore" };
1478
+ if (process.platform === "darwin") {
1479
+ spawn8("osascript", ["-e", `display notification ${JSON.stringify(body)} with title ${JSON.stringify(title)} sound name "Glass"`], opts).on("error", () => {
1480
+ });
1481
+ } else if (process.platform === "linux") {
1482
+ spawn8("notify-send", [title, body], opts).on("error", () => {
1483
+ });
1484
+ }
1485
+ } catch {
1486
+ }
1487
+ console.error(`
1488
+ \u{1F514} ${title} \u2014 ${body}
1489
+ `);
1490
+ }
1491
+ var init_notify = __esm({
1492
+ "src/notify.ts"() {
1493
+ "use strict";
1494
+ }
1495
+ });
1496
+
1453
1497
  // src/remind.ts
1454
1498
  var remind_exports = {};
1455
1499
  __export(remind_exports, {
@@ -1484,10 +1528,35 @@ var init_remind = __esm({
1484
1528
  });
1485
1529
 
1486
1530
  // src/exportScan.ts
1487
- import { promises as fs28 } from "fs";
1531
+ var exportScan_exports = {};
1532
+ __export(exportScan_exports, {
1533
+ agentDiscoverCandidates: () => agentDiscoverCandidates,
1534
+ deterministicDiscover: () => deterministicDiscover,
1535
+ identifyPath: () => identifyPath,
1536
+ latestPerSource: () => latestPerSource,
1537
+ scanForExports: () => scanForExports,
1538
+ scanForObsidianVaults: () => scanForObsidianVaults
1539
+ });
1540
+ import { promises as fs33 } from "fs";
1488
1541
  import { execFile as execFile2 } from "child_process";
1489
1542
  import { promisify as promisify2 } from "util";
1490
- import path34 from "path";
1543
+ import path38 from "path";
1544
+ function latestPerSource(found) {
1545
+ const newest = /* @__PURE__ */ new Map();
1546
+ const keyOf = (f) => f.kind === "obsidian" || f.kind === "unknown" ? null : `${f.kind}:${f.account ?? "(unknown-account)"}`;
1547
+ for (const f of found) {
1548
+ const k = keyOf(f);
1549
+ if (k && (!newest.has(k) || f.modified > newest.get(k))) newest.set(k, f.modified);
1550
+ }
1551
+ const taken = /* @__PURE__ */ new Set();
1552
+ return found.map((f) => {
1553
+ const k = keyOf(f);
1554
+ if (!k) return true;
1555
+ if (f.modified !== newest.get(k) || taken.has(k)) return false;
1556
+ taken.add(k);
1557
+ return true;
1558
+ });
1559
+ }
1491
1560
  async function zipEntries(zip) {
1492
1561
  try {
1493
1562
  const { stdout } = await run3("unzip", ["-Z1", zip], { maxBuffer: 8 * 1024 * 1024 });
@@ -1541,7 +1610,7 @@ async function identifyZip(zip, stat) {
1541
1610
  note: ""
1542
1611
  };
1543
1612
  if (!entries) {
1544
- const n = path34.basename(zip).toLowerCase();
1613
+ const n = path38.basename(zip).toLowerCase();
1545
1614
  if (n.includes("chatgpt") || n.includes("openai")) {
1546
1615
  found.kind = "chatgpt";
1547
1616
  found.note = "matched by filename only (no unzip binary to verify)";
@@ -1561,7 +1630,7 @@ async function identifyZip(zip, stat) {
1561
1630
  }
1562
1631
  let { kind, note } = classify2(entries);
1563
1632
  if (kind === "unknown") {
1564
- const nb = path34.basename(zip).toLowerCase();
1633
+ const nb = path38.basename(zip).toLowerCase();
1565
1634
  const nameHint = nb.includes("notion") || /(^|[-_ ])export-/.test(nb);
1566
1635
  const inner = entries.filter((e) => e.toLowerCase().endsWith(".zip"));
1567
1636
  const partZips = inner.some((e) => /export[^/]*part[-_ ]?\d+\.zip$/i.test(e.toLowerCase()));
@@ -1590,17 +1659,17 @@ async function identifyZip(zip, stat) {
1590
1659
  async function identifyDir(dir) {
1591
1660
  let names;
1592
1661
  try {
1593
- names = await fs28.readdir(dir);
1662
+ names = await fs33.readdir(dir);
1594
1663
  } catch {
1595
1664
  return null;
1596
1665
  }
1597
1666
  const { kind, note } = classify2(names);
1598
1667
  if (kind === "unknown") return null;
1599
- const st = await fs28.stat(dir);
1668
+ const st = await fs33.stat(dir);
1600
1669
  const found = { kind, path: dir, account: null, sizeMB: 0, modified: st.mtime.toISOString().slice(0, 10), note };
1601
1670
  const read = async (n) => {
1602
1671
  try {
1603
- return await fs28.readFile(path34.join(dir, n), "utf8");
1672
+ return await fs33.readFile(path38.join(dir, n), "utf8");
1604
1673
  } catch {
1605
1674
  return null;
1606
1675
  }
@@ -1613,7 +1682,7 @@ async function identifyPath(p) {
1613
1682
  if (/\/\.data\//.test(p)) return null;
1614
1683
  let st;
1615
1684
  try {
1616
- st = await fs28.stat(p);
1685
+ st = await fs33.stat(p);
1617
1686
  } catch {
1618
1687
  return null;
1619
1688
  }
@@ -1636,9 +1705,9 @@ async function deterministicDiscover(home) {
1636
1705
  }
1637
1706
  }
1638
1707
  }
1639
- const path38 = await import("node:path");
1708
+ const path42 = await import("node:path");
1640
1709
  for (const dir of ["Downloads", "Desktop", "Documents"]) {
1641
- for (const f of await scanForExports(path38.join(home, dir)).catch(() => [])) out.push(f.path);
1710
+ for (const f of await scanForExports(path42.join(home, dir)).catch(() => [])) out.push(f.path);
1642
1711
  }
1643
1712
  return [...new Set(out)].slice(0, 80);
1644
1713
  }
@@ -1675,14 +1744,14 @@ async function countMdNotes(root, cap = 2e3) {
1675
1744
  if (n >= cap || depth > 6) return;
1676
1745
  let entries;
1677
1746
  try {
1678
- entries = await fs28.readdir(d, { withFileTypes: true });
1747
+ entries = await fs33.readdir(d, { withFileTypes: true });
1679
1748
  } catch {
1680
1749
  return;
1681
1750
  }
1682
1751
  for (const e of entries) {
1683
1752
  if (n >= cap) return;
1684
1753
  if (e.name.startsWith(".")) continue;
1685
- if (e.isDirectory()) await walk(path34.join(d, e.name), depth + 1);
1754
+ if (e.isDirectory()) await walk(path38.join(d, e.name), depth + 1);
1686
1755
  else if (e.name.endsWith(".md")) n++;
1687
1756
  }
1688
1757
  }
@@ -1691,12 +1760,12 @@ async function countMdNotes(root, cap = 2e3) {
1691
1760
  }
1692
1761
  async function identifyObsidianVault(dir) {
1693
1762
  try {
1694
- const st = await fs28.stat(path34.join(dir, ".obsidian"));
1763
+ const st = await fs33.stat(path38.join(dir, ".obsidian"));
1695
1764
  if (!st.isDirectory()) return null;
1696
1765
  } catch {
1697
1766
  return null;
1698
1767
  }
1699
- const rootSt = await fs28.stat(dir).catch(() => null);
1768
+ const rootSt = await fs33.stat(dir).catch(() => null);
1700
1769
  if (!rootSt) return null;
1701
1770
  const notes = await countMdNotes(dir);
1702
1771
  return {
@@ -1718,21 +1787,21 @@ async function scanForObsidianVaults(home) {
1718
1787
  }
1719
1788
  };
1720
1789
  const roots = [
1721
- path34.join(home, "Library", "Mobile Documents", "iCloud~md~obsidian", "Documents"),
1722
- path34.join(home, "Documents"),
1723
- path34.join(home, "Desktop"),
1790
+ path38.join(home, "Library", "Mobile Documents", "iCloud~md~obsidian", "Documents"),
1791
+ path38.join(home, "Documents"),
1792
+ path38.join(home, "Desktop"),
1724
1793
  home
1725
1794
  ];
1726
1795
  for (const root of roots) {
1727
1796
  let names = [];
1728
1797
  try {
1729
- names = await fs28.readdir(root);
1798
+ names = await fs33.readdir(root);
1730
1799
  } catch {
1731
1800
  continue;
1732
1801
  }
1733
1802
  for (const name17 of names) {
1734
1803
  if (name17.startsWith(".")) continue;
1735
- add(await identifyObsidianVault(path34.join(root, name17)));
1804
+ add(await identifyObsidianVault(path38.join(root, name17)));
1736
1805
  }
1737
1806
  }
1738
1807
  return out;
@@ -1741,16 +1810,16 @@ async function scanForExports(root) {
1741
1810
  const out = [];
1742
1811
  let names;
1743
1812
  try {
1744
- names = await fs28.readdir(root);
1813
+ names = await fs33.readdir(root);
1745
1814
  } catch {
1746
1815
  return out;
1747
1816
  }
1748
1817
  for (const name17 of names) {
1749
1818
  if (name17.startsWith(".")) continue;
1750
- const p = path34.join(root, name17);
1819
+ const p = path38.join(root, name17);
1751
1820
  let st;
1752
1821
  try {
1753
- st = await fs28.stat(p);
1822
+ st = await fs33.stat(p);
1754
1823
  } catch {
1755
1824
  continue;
1756
1825
  }
@@ -1816,11 +1885,11 @@ ${mark.join("\n")}
1816
1885
  async function printBanner(out = process.stderr) {
1817
1886
  let version = "0.0.0";
1818
1887
  try {
1819
- const { promises: fs32 } = await import("fs");
1820
- const path38 = await import("path");
1888
+ const { promises: fs37 } = await import("fs");
1889
+ const path42 = await import("path");
1821
1890
  const { fileURLToPath: fileURLToPath6 } = await import("url");
1822
- const here = path38.dirname(fileURLToPath6(import.meta.url));
1823
- const pkg = JSON.parse(await fs32.readFile(path38.join(here, "..", "package.json"), "utf-8"));
1891
+ const here = path42.dirname(fileURLToPath6(import.meta.url));
1892
+ const pkg = JSON.parse(await fs37.readFile(path42.join(here, "..", "package.json"), "utf-8"));
1824
1893
  version = String(pkg.version || version);
1825
1894
  } catch {
1826
1895
  }
@@ -1895,9 +1964,9 @@ __export(plan_exports, {
1895
1964
  tierFromChatgptPlan: () => tierFromChatgptPlan,
1896
1965
  tierFromStrings: () => tierFromStrings
1897
1966
  });
1898
- import { promises as fs29 } from "fs";
1899
- import os7 from "os";
1900
- import path35 from "path";
1967
+ import { promises as fs34 } from "fs";
1968
+ import os9 from "os";
1969
+ import path39 from "path";
1901
1970
  function tierFromStrings(...hints) {
1902
1971
  for (const h of hints) {
1903
1972
  if (!h) continue;
@@ -1917,9 +1986,9 @@ function tierFromChatgptPlan(planType) {
1917
1986
  if (s === "free") return "gpt_free";
1918
1987
  return "unknown";
1919
1988
  }
1920
- async function detectCodexPlan(home = os7.homedir()) {
1989
+ async function detectCodexPlan(home = os9.homedir()) {
1921
1990
  try {
1922
- const raw = JSON.parse(await fs29.readFile(path35.join(home, ".codex", "auth.json"), "utf8"));
1991
+ const raw = JSON.parse(await fs34.readFile(path39.join(home, ".codex", "auth.json"), "utf8"));
1923
1992
  for (const tok of [raw.tokens?.id_token, raw.tokens?.access_token]) {
1924
1993
  if (!tok) continue;
1925
1994
  try {
@@ -1933,10 +2002,10 @@ async function detectCodexPlan(home = os7.homedir()) {
1933
2002
  }
1934
2003
  return "unknown";
1935
2004
  }
1936
- async function detectPlan(home = os7.homedir()) {
2005
+ async function detectPlan(home = os9.homedir()) {
1937
2006
  let tier = "unknown";
1938
2007
  try {
1939
- const raw = JSON.parse(await fs29.readFile(path35.join(home, ".claude.json"), "utf8"));
2008
+ const raw = JSON.parse(await fs34.readFile(path39.join(home, ".claude.json"), "utf8"));
1940
2009
  const oa = raw.oauthAccount ?? {};
1941
2010
  tier = tierFromStrings(oa.userRateLimitTier, oa.organizationRateLimitTier, oa.organizationType);
1942
2011
  } catch {
@@ -1953,23 +2022,23 @@ async function remainingFractions(dataRoot, agentLogFiles) {
1953
2022
  const clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, v));
1954
2023
  let coding = 1;
1955
2024
  try {
1956
- const graded = (await fs29.readdir(path35.join(dataRoot, "coding", "grades"))).filter((f) => f.endsWith(".json")).length;
2025
+ const graded = (await fs34.readdir(path39.join(dataRoot, "coding", "grades"))).filter((f) => f.endsWith(".json")).length;
1957
2026
  const expected = Math.max(1, agentLogFiles * 56e-4);
1958
2027
  coding = clamp(1 - graded / expected, 0.05, 1);
1959
2028
  } catch {
1960
2029
  }
1961
2030
  let chatDone = 0;
1962
2031
  try {
1963
- const st = await fs29.stat(path35.join(dataRoot, "signals", "index.jsonl"));
2032
+ const st = await fs34.stat(path39.join(dataRoot, "signals", "index.jsonl"));
1964
2033
  if (st.size > 0) chatDone += 0.3;
1965
2034
  } catch {
1966
2035
  }
1967
2036
  try {
1968
- const lenses = await fs29.readdir(path35.join(dataRoot, "engine-pilot", "grades"));
2037
+ const lenses = await fs34.readdir(path39.join(dataRoot, "engine-pilot", "grades"));
1969
2038
  let withPerson = 0;
1970
2039
  for (const l of lenses) {
1971
2040
  try {
1972
- await fs29.stat(path35.join(dataRoot, "engine-pilot", "grades", l, "_person.json"));
2041
+ await fs34.stat(path39.join(dataRoot, "engine-pilot", "grades", l, "_person.json"));
1973
2042
  withPerson++;
1974
2043
  } catch {
1975
2044
  }
@@ -2025,9 +2094,9 @@ var wizard_exports = {};
2025
2094
  __export(wizard_exports, {
2026
2095
  runWizard: () => runWizard
2027
2096
  });
2028
- import { promises as fs30 } from "fs";
2029
- import os8 from "os";
2030
- import path36 from "path";
2097
+ import { promises as fs35 } from "fs";
2098
+ import os10 from "os";
2099
+ import path40 from "path";
2031
2100
  import * as readline from "node:readline/promises";
2032
2101
  async function scanJsonlDir(label, dir) {
2033
2102
  let files = 0;
@@ -2036,15 +2105,15 @@ async function scanJsonlDir(label, dir) {
2036
2105
  if (depth > 1) return;
2037
2106
  let names = [];
2038
2107
  try {
2039
- names = await fs30.readdir(d);
2108
+ names = await fs35.readdir(d);
2040
2109
  } catch {
2041
2110
  return;
2042
2111
  }
2043
2112
  for (const n of names) {
2044
- const p = path36.join(d, n);
2113
+ const p = path40.join(d, n);
2045
2114
  let st;
2046
2115
  try {
2047
- st = await fs30.stat(p);
2116
+ st = await fs35.stat(p);
2048
2117
  } catch {
2049
2118
  continue;
2050
2119
  }
@@ -2070,7 +2139,7 @@ function describeExport(f, i, included, hadPrevious) {
2070
2139
  const size = f.sizeMB ? ` \xB7 ${f.sizeMB} MB` : "";
2071
2140
  const state = hadPrevious ? included ? green(" [use]") : dim(" [skip \u2014 previously excluded]") : "";
2072
2141
  return ` ${i + 1}. ${bold(kind)}${who}${size} \xB7 ${f.modified}${state}
2073
- ${dim(path36.basename(f.path))} ${dim(`(${f.note})`)}`;
2142
+ ${dim(path40.basename(f.path))} ${dim(`(${f.note})`)}`;
2074
2143
  }
2075
2144
  async function runWizard() {
2076
2145
  const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
@@ -2140,7 +2209,7 @@ async function runWizard() {
2140
2209
  for (let i = 0; i < agentScans.length; i++) {
2141
2210
  const s = agentScans[i];
2142
2211
  const idx = present.indexOf(agentIds[i]);
2143
- say(s.files > 0 ? ` ${idx + 1}. ${green("\u2713")} ${bold(s.label)} \u2014 ${s.files.toLocaleString()} log files \xB7 newest ${s.newest} ${dim(s.dir.replace(os8.homedir(), "~"))}` : ` ${dim("\xB7")} ${dim(`${s.label} \u2014 none found`)} ${dim(s.dir.replace(os8.homedir(), "~"))}`);
2212
+ say(s.files > 0 ? ` ${idx + 1}. ${green("\u2713")} ${bold(s.label)} \u2014 ${s.files.toLocaleString()} log files \xB7 newest ${s.newest} ${dim(s.dir.replace(os10.homedir(), "~"))}` : ` ${dim("\xB7")} ${dim(`${s.label} \u2014 none found`)} ${dim(s.dir.replace(os10.homedir(), "~"))}`);
2144
2213
  }
2145
2214
  say(dim(" (log files include forks and agent runs \u2014 the report separates your real sessions out)"));
2146
2215
  if (present.length === 0) {
@@ -2168,7 +2237,7 @@ async function runWizard() {
2168
2237
  for (const id of agents.excluded) say(` ${dim(`\u2717 ${id} excluded \u2014 its logs will not be read.`)}`);
2169
2238
  let notifyEmail = null;
2170
2239
  try {
2171
- notifyEmail = JSON.parse(await fs30.readFile(path36.join(dataDir, "notify-email.json"), "utf8")).email ?? null;
2240
+ notifyEmail = JSON.parse(await fs35.readFile(path40.join(dataDir, "notify-email.json"), "utf8")).email ?? null;
2172
2241
  } catch {
2173
2242
  }
2174
2243
  {
@@ -2181,8 +2250,8 @@ async function runWizard() {
2181
2250
  if (e && looksLikeEmail2(e)) {
2182
2251
  notifyEmail = e;
2183
2252
  try {
2184
- await fs30.mkdir(dataDir, { recursive: true });
2185
- await fs30.writeFile(path36.join(dataDir, "notify-email.json"), JSON.stringify({ email: e }));
2253
+ await fs35.mkdir(dataDir, { recursive: true });
2254
+ await fs35.writeFile(path40.join(dataDir, "notify-email.json"), JSON.stringify({ email: e }));
2186
2255
  } catch {
2187
2256
  }
2188
2257
  say(` ${green("\u2713")} Saved on this machine only.`);
@@ -2203,9 +2272,9 @@ async function runWizard() {
2203
2272
  }
2204
2273
  };
2205
2274
  say(dim(" Scanning for known export formats (Spotlight + the usual folders, a few seconds)..."));
2206
- for (const c of await deterministicDiscover(os8.homedir())) add(await identifyPath(c));
2207
- for (const f of await scanForExports(path36.join(os8.homedir(), "Downloads"))) add(f);
2208
- for (const f of await scanForObsidianVaults(os8.homedir())) add(f);
2275
+ for (const c of await deterministicDiscover(os10.homedir())) add(await identifyPath(c));
2276
+ for (const f of await scanForExports(path40.join(os10.homedir(), "Downloads"))) add(f);
2277
+ for (const f of await scanForObsidianVaults(os10.homedir())) add(f);
2209
2278
  for (const f of [...previous?.exports.included ?? [], ...previous?.exports.excluded ?? []]) add(f);
2210
2279
  if (!found.length) {
2211
2280
  say(dim(" Nothing found in the usual places."));
@@ -2213,7 +2282,7 @@ async function runWizard() {
2213
2282
  try {
2214
2283
  const { invokeAgent: invokeAgent3 } = await Promise.resolve().then(() => (init_agent(), agent_exports));
2215
2284
  say(dim(" Searching (your agent writes its own filesystem searches; nothing leaves this machine; 90s max)..."));
2216
- const candidates = await agentDiscoverCandidates((inv) => invokeAgent3(inv), os8.homedir(), []);
2285
+ const candidates = await agentDiscoverCandidates((inv) => invokeAgent3(inv), os10.homedir(), []);
2217
2286
  for (const c of candidates) add(await identifyPath(c));
2218
2287
  } catch (e) {
2219
2288
  say(dim(` Agent search unavailable (${e instanceof Error ? e.message.slice(0, 80) : "failed"}).`));
@@ -2221,12 +2290,15 @@ async function runWizard() {
2221
2290
  }
2222
2291
  if (!found.length) {
2223
2292
  const folder = await ask(` Got them in a specific folder? ${dim("(path, or Enter to skip)")}: `);
2224
- if (folder) for (const f of await scanForExports(folder.replace(/^~(?=$|\/)/, os8.homedir()))) add(f);
2293
+ if (folder) for (const f of await scanForExports(folder.replace(/^~(?=$|\/)/, os10.homedir()))) add(f);
2225
2294
  }
2226
2295
  }
2227
2296
  if (found.length) {
2228
2297
  found.sort((a, b) => a.modified < b.modified ? 1 : -1);
2229
2298
  const hadPrevious = false;
2299
+ const { latestPerSource: latestPerSource2 } = await Promise.resolve().then(() => (init_exportScan(), exportScan_exports));
2300
+ const keep = latestPerSource2(found);
2301
+ found = found.filter((_, i) => keep[i]);
2230
2302
  const defaults = found.map(() => true);
2231
2303
  say(` Found ${dim("(identified locally from the files themselves)")}:`);
2232
2304
  found.forEach((f, i) => say(describeExport(f, i, defaults[i], hadPrevious)));
@@ -2256,8 +2328,8 @@ async function runWizard() {
2256
2328
  approvedExports = manifest.exports.included;
2257
2329
  await writeManifest(dataDir, manifest);
2258
2330
  const nIn = manifest.exports.included.length;
2259
- say(` ${green("\u2713")} Saved to ${path36.join(dataDir, "exports-manifest.json").replace(os8.homedir(), "~")} \u2014 ${nIn} source${nIn === 1 ? "" : "s"} approved, ${manifest.exports.excluded.length} excluded (re-run anytime to change).`);
2260
- for (const f of manifest.exports.excluded) say(` ${dim(`\u2717 ${path36.basename(f.path)} \u2014 excluded, never read past identification.`)}`);
2331
+ say(` ${green("\u2713")} Saved to ${path40.join(dataDir, "exports-manifest.json").replace(os10.homedir(), "~")} \u2014 ${nIn} source${nIn === 1 ? "" : "s"} approved, ${manifest.exports.excluded.length} excluded (re-run anytime to change).`);
2332
+ for (const f of manifest.exports.excluded) say(` ${dim(`\u2717 ${path40.basename(f.path)} \u2014 excluded, never read past identification.`)}`);
2261
2333
  if (manifest.exports.included.some((f) => f.kind !== "unknown")) {
2262
2334
  say(` ${dim("These are ingested and analyzed locally when you pick the full analysis below.")}`);
2263
2335
  }
@@ -2309,17 +2381,20 @@ async function runWizard() {
2309
2381
  if (resumed) say(dim(" (an earlier run already processed most of this \u2014 the estimate covers only what's new; nothing done is redone)"));
2310
2382
  say(` \u2022 coding: ${sched.codingReason}`);
2311
2383
  if (est.chatUsd > 0) say(` \u2022 chats/notes: ${sched.chatReason}`);
2312
- say(` ${bold("1)")} Full analysis on the schedule above ${dim("(recommended)")}`);
2384
+ say(` ${bold("1) Full analysis on the schedule above \u2014 RECOMMENDED")}`);
2385
+ say();
2313
2386
  say(` ${bold("2)")} Full analysis, everything overnight \u2014 all grading waits for the 02:00 window`);
2314
- say(` ${bold("VERY IMPORTANT")} whenever anything runs overnight:`);
2315
- say(` \u2022 keep your laptop plugged in`);
2316
- say(` \u2022 keep the lid open \u2014 closed means sleep, and the run stalls until morning`);
2387
+ say(dim(` \u2022 keep your laptop plugged in`));
2388
+ say(dim(` \u2022 keep the lid open \u2014 closed means sleep, and the run stalls until morning`));
2317
2389
  say(` ${bold("3)")} Just the numbers \u2014 instant deterministic metrics (words/day, flow, parallelism), free, ~a minute`);
2318
2390
  const depth = await ask(` Choose ${dim("[1/2/3, default 1]")}: `) || "1";
2319
2391
  const chosenOvernight = depth === "2" || depth === "1" && anyOvernight;
2320
2392
  if (depth !== "3" && chosenOvernight) {
2321
2393
  say();
2322
- say(` ${bold("Reminder for the overnight part:")} laptop plugged in, lid open. The report page shows this too.`);
2394
+ say(` ${bold("VERY IMPORTANT for the overnight part:")}`);
2395
+ say(` \u2022 keep your laptop plugged in`);
2396
+ say(` \u2022 keep the lid open \u2014 closed means sleep, and the run stalls until morning`);
2397
+ say(dim(` (the report page shows this too)`));
2323
2398
  }
2324
2399
  say();
2325
2400
  say(dim(" On it. The report link appears right away and fills in as stages finish \u2014 Ctrl-C anytime.\n"));
@@ -2501,8 +2576,8 @@ try {
2501
2576
  }
2502
2577
 
2503
2578
  // src/cli.ts
2504
- import { promises as fs31, existsSync as existsSync7 } from "fs";
2505
- import path37 from "path";
2579
+ import { promises as fs36, existsSync as existsSync7 } from "fs";
2580
+ import path41 from "path";
2506
2581
  import { fileURLToPath as fileURLToPath5 } from "url";
2507
2582
  import { spawn as spawn9 } from "child_process";
2508
2583
 
@@ -2752,28 +2827,8 @@ function nextLocalMidnight(fromMs, tz) {
2752
2827
  return fromMs + 24 * 60 * MIN;
2753
2828
  }
2754
2829
 
2755
- // ../coding-core/dist/gate.js
2756
- var GATE = {
2757
- minHumanChars: 800,
2758
- // the user must have actually said something substantial
2759
- minHumanTurns: 3,
2760
- // …over enough back-and-forth to reveal how they work
2761
- trivialHumanChars: 300,
2762
- // below this = a one-liner, definitely trivial
2763
- trivialHumanTurns: 2
2764
- };
2765
- function isGradable(s) {
2766
- return s.humanChars >= GATE.minHumanChars && s.humanTurns >= GATE.minHumanTurns;
2767
- }
2768
- function isTrivial(s) {
2769
- return s.humanTurns < GATE.trivialHumanTurns || s.humanChars < GATE.trivialHumanChars;
2770
- }
2771
- function partition(sessions) {
2772
- const gradable = [], thin = [], trivial = [];
2773
- for (const s of sessions)
2774
- (isGradable(s) ? gradable : isTrivial(s) ? trivial : thin).push(s);
2775
- return { gradable, thin, trivial };
2776
- }
2830
+ // src/analyze.ts
2831
+ init_gate2();
2777
2832
 
2778
2833
  // ../coding-core/dist/messages.js
2779
2834
  init_injected();
@@ -3415,12 +3470,18 @@ async function analyze(opts = {}) {
3415
3470
  };
3416
3471
  }
3417
3472
 
3473
+ // src/grade/provider.ts
3474
+ init_gate2();
3475
+
3418
3476
  // src/grade/grade.ts
3419
3477
  init_agent();
3420
3478
  import { promises as fs4 } from "fs";
3421
3479
  import os4 from "os";
3422
3480
  import path4 from "path";
3423
3481
 
3482
+ // ../../lib/agents/coding/grade-calibration.ts
3483
+ var GRADE_CALIBRATION = "\n\nSCORE CALIBRATION \u2014 graders systematically COMPRESS to the middle: real peaks get hedged down to 6-7, and routine sessions get polite 5-6s instead of null. Both are failures; fight them explicitly. Work each criterion in EXACTLY this order:\nSTEP 1 \xB7 EVIDENCE GATE \u2014 find the 1-3 verbatim '>> ' quotes that bear on the criterion. INCLUDE a criterion whenever genuine evidence is present (do not MISS quiet evidence \u2014 check every thread of the session, not just the dominant one). But with NO quotable moment the score is null, full stop: a session can be long, competent, and productive while being null on most criteria. Routine hand-holding earns null, never a 5 \u2014 and null is never a deduction.\nSTEP 2 \xB7 LADDER MATCH \u2014 with quotes in hand, read the criterion's rungs and pick the ONE rung whose marker best describes the quoted moment; name that rung in 'why'. AWARD THE RUNG THE EVIDENCE MATCHES: if your own 'why' describes rung N's criteria, give rung N \u2014 never deny it for lacking the NEXT rung's criteria.\nSTEP 3 \xB7 THE SINGLE BEST MOMENT IS THE SCORE \u2014 set the score by the strongest quoted moment, as if it were the whole session. NEVER average a peak down because the surrounding session is routine (the high-water rule), and never raise a score for volume, effort, or topic prestige without a matching moment.\nSTEP 4 \xB7 ANTI-HEDGE \u2014 if the moment genuinely matches an L8-10 anchor (an override the AI conceded, a shipped-and-verified capability, an 'oh shit, they're right' call, a first-principles redefinition that held), the score IS 8-10. Hedging a real L9 to a 7 is exactly as wrong as inventing a 6 for nothing. The middle is NOT a safe default: commit high on anchor-matching evidence, or go null.\nSTEP 5 \xB7 'CONSERVATIVE' \u2260 SUBTRACT \u2014 when a criterion's ladder says to grade conservatively, that means DO NOT EXCEED the rung whose marker the evidence matches; it NEVER means subtracting rungs from matched evidence. Evidence that matches a rung's marker gets that rung under a conservative reading too.";
3484
+
3424
3485
  // ../../lib/calibration/fingerprint.ts
3425
3486
  import { createHash } from "node:crypto";
3426
3487
  function rubricFingerprint(criteria) {
@@ -3732,7 +3793,7 @@ ${c.rungs.map((r) => ` ${r.level} \u2014 ${r.marker}`).join("\n")}`
3732
3793
  }
3733
3794
  var SYSTEM = "You grade how a person WORKS from one of their coding-agent sessions (Claude Code / Codex). You read mostly THEIR words; the model's code and output are compressed to context and you ignore the mechanical scaffolding. You never flatter: most sessions are routine hand-holding and should score low or null on most criteria. A score is a placement on the ladder backed by VERBATIM quotes of the user's own lines \u2014 never a vibe.\n\nSTANDING RULES (apply to every criterion):\n1. ABSENCE IS NEVER A DEDUCTION. If a criterion had no chance to show, its score is null \u2014 NOT a low. Don't invent a number for routine work.\n2. HIGH-WATER MARK. Taste and abstraction are PEAK measures \u2014 one genuinely brilliant move in a session counts, even surrounded by routine work. Never grade the person at their worst.\n3. LOW-EFFORT-UNTIL-NEEDED IS THE IDEAL. A terse or vague prompt on routine work is correct economy \u2014 never penalize a vague ask, never reward word-count.\n4. DISCOUNT THE LITERAL HARSHNESS OF SELF-TALK. Profanity aimed at self or AI is DRIVE and high standards, not defects.\n5. PER-CONVERSATION CEILING IS 10. Never output 11 \u2014 scores run 2\u201310.\n6. LOG THE SPIKES IN HIGH DETAIL. When a moment is genuinely good, name it CONCRETELY and quote it.";
3734
3795
  function gradeSystemPrompt() {
3735
- return `${SYSTEM}
3796
+ return `${SYSTEM}${GRADE_CALIBRATION}
3736
3797
 
3737
3798
  Grade ONE coding session (provided in the user message) along the criteria below. ">> " lines are the USER's own words (the signal). ALL bracketed lines are machine context, never the user: "[AI: \u2026]" is the model working, "[bg task: \u2026]" / "[cmd output: \u2026]" are harness notifications, "[mode \u2192 \u2026]" marks a mode switch (context only \u2014 do not grade or quote them). ">> (queued \u2026)" is the user queuing work while the AI runs.
3738
3799
 
@@ -3951,8 +4012,8 @@ function buildShareSections(p) {
3951
4012
 
3952
4013
  // src/server.ts
3953
4014
  import http from "http";
3954
- import { promises as fs21 } from "fs";
3955
- import path26 from "path";
4015
+ import { promises as fs29 } from "fs";
4016
+ import path33 from "path";
3956
4017
  import { fileURLToPath as fileURLToPath2 } from "url";
3957
4018
 
3958
4019
  // src/auth.ts
@@ -4055,7 +4116,7 @@ async function getAccessToken(dataDir) {
4055
4116
 
4056
4117
  // ../../lib/calibration/index.ts
4057
4118
  var DEFAULT_CALIBRATION = {
4058
- version: "2026-07-12.2",
4119
+ version: "2026-07-14.2",
4059
4120
  // = RUBRIC_FINGERPRINT of the shipped npm rubric (packages/coding-analyzer/
4060
4121
  // src/grade/criteria.ts). A unit test fails loud when the rubric changes
4061
4122
  // without this being updated (and re-pushed to the server).
@@ -4144,7 +4205,7 @@ var DEFAULT_CALIBRATION = {
4144
4205
  }
4145
4206
  ],
4146
4207
  codingTiers: {
4147
- push: { median: 300, sigma: 1.121, tag: "estimated \u2014 log-normal fit", source: "Anthropic 2026 Claude Code study (400k sessions): median engaged user ~8 prompts/day at ~35 words \u2014 ~300 directed words/day; tail shape from its actions-per-prompt distribution. AVERAGE over substantial days, cumulative not spiky." },
4208
+ push: { median: 300, sigma: 0.91, tag: "estimated \u2014 log-normal fit", source: "Anthropic 2026 Claude Code study (400k sessions): median engaged user ~8 prompts/day at ~35 words \u2014 ~300 directed words/day; tail: a 1-in-1,000 user AVERAGES ~5k directed words/day (near-daily heavy dictation, clearly below the ~10k single-day record). AVERAGE over substantial days, cumulative not spiky." },
4148
4209
  focus: { median: 0.08, sigma: 0.559, tag: "estimated \u2014 proxy-anchored", source: "median: Anthropic 20h/week engaged-user figure implies ~1h/day of true rapid exchange against an 8h working day; ceiling anchored to the ~4h/day deep-work limit (45% share = 1-in-1,000). AVERAGE share, cumulative not spiky." },
4149
4210
  orchestration: { tag: "estimated \u2014 behavior bands", source: "no published concurrency distribution exists; ceiling anchored to the Claude Code lead's documented 10-15 parallel sessions" }
4150
4211
  },
@@ -4177,12 +4238,18 @@ var DEFAULT_CALIBRATION = {
4177
4238
  line: "the Claude Code lead runs 10\u201315 sessions at once; his #1 tip is 3\u20135 git worktrees in parallel"
4178
4239
  },
4179
4240
  throughput: {
4180
- // Top-0.1% words/day reference lines, anchored to the throughput ladder
4181
- // (THROUGHPUT_LADDER in throughput.ts): score 10 "world-class sustained" =
4182
- // 9k/day, score 11 "superhuman ceiling" = 12k/day. Calibrated to the person's
4183
- // own anchors, not a wild guess but still a target, not a measured population.
4184
- topAvgWordsPerDay: 9e3,
4185
- topPeakWordsPerDay: 12e3,
4241
+ // Two DIFFERENT kinds of line (2026-07-14.2): topAvg is a PERCENTILE
4242
+ // claim — what a 1-in-1,000 user AVERAGES over substantial days (5k/day:
4243
+ // near-daily heavy dictation; a measured top dictating power user
4244
+ // averages ~3.9k). topPeak is NOT a percentileit is the CEILING
4245
+ // reference, the wildest single days on record (~10k: a 14-16h
4246
+ // launch-day marathon), rendered as "wildest single days", never
4247
+ // "top X% peak". An avg-percentile and a peak-percentile can't both be
4248
+ // shown at a same-ish value (avg≈peak reads broken — user call), and a
4249
+ // peak PERCENTILE line is unknowable anyway; the record framing is
4250
+ // honest and keeps the visual gap.
4251
+ topAvgWordsPerDay: 5e3,
4252
+ topPeakWordsPerDay: 1e4,
4186
4253
  benchLabel: "top 0.1%",
4187
4254
  // No published "words typed/day" for heavy users — the real story is OUTPUT.
4188
4255
  loopsHeadline: ">1,000,000 lines of Rust at 99.8% tests passing",
@@ -6279,8 +6346,8 @@ function getErrorMap() {
6279
6346
 
6280
6347
  // ../../node_modules/zod/v3/helpers/parseUtil.js
6281
6348
  var makeIssue = (params) => {
6282
- const { data, path: path38, errorMaps, issueData } = params;
6283
- const fullPath = [...path38, ...issueData.path || []];
6349
+ const { data, path: path42, errorMaps, issueData } = params;
6350
+ const fullPath = [...path42, ...issueData.path || []];
6284
6351
  const fullIssue = {
6285
6352
  ...issueData,
6286
6353
  path: fullPath
@@ -6396,11 +6463,11 @@ var errorUtil;
6396
6463
 
6397
6464
  // ../../node_modules/zod/v3/types.js
6398
6465
  var ParseInputLazyPath = class {
6399
- constructor(parent, value, path38, key) {
6466
+ constructor(parent, value, path42, key) {
6400
6467
  this._cachedPath = [];
6401
6468
  this.parent = parent;
6402
6469
  this.data = value;
6403
- this._path = path38;
6470
+ this._path = path42;
6404
6471
  this._key = key;
6405
6472
  }
6406
6473
  get path() {
@@ -19187,39 +19254,39 @@ function createOpenAI(options = {}) {
19187
19254
  });
19188
19255
  const createChatModel = (modelId, settings = {}) => new OpenAIChatLanguageModel(modelId, settings, {
19189
19256
  provider: `${providerName}.chat`,
19190
- url: ({ path: path38 }) => `${baseURL}${path38}`,
19257
+ url: ({ path: path42 }) => `${baseURL}${path42}`,
19191
19258
  headers: getHeaders,
19192
19259
  compatibility,
19193
19260
  fetch: options.fetch
19194
19261
  });
19195
19262
  const createCompletionModel = (modelId, settings = {}) => new OpenAICompletionLanguageModel(modelId, settings, {
19196
19263
  provider: `${providerName}.completion`,
19197
- url: ({ path: path38 }) => `${baseURL}${path38}`,
19264
+ url: ({ path: path42 }) => `${baseURL}${path42}`,
19198
19265
  headers: getHeaders,
19199
19266
  compatibility,
19200
19267
  fetch: options.fetch
19201
19268
  });
19202
19269
  const createEmbeddingModel = (modelId, settings = {}) => new OpenAIEmbeddingModel(modelId, settings, {
19203
19270
  provider: `${providerName}.embedding`,
19204
- url: ({ path: path38 }) => `${baseURL}${path38}`,
19271
+ url: ({ path: path42 }) => `${baseURL}${path42}`,
19205
19272
  headers: getHeaders,
19206
19273
  fetch: options.fetch
19207
19274
  });
19208
19275
  const createImageModel = (modelId, settings = {}) => new OpenAIImageModel(modelId, settings, {
19209
19276
  provider: `${providerName}.image`,
19210
- url: ({ path: path38 }) => `${baseURL}${path38}`,
19277
+ url: ({ path: path42 }) => `${baseURL}${path42}`,
19211
19278
  headers: getHeaders,
19212
19279
  fetch: options.fetch
19213
19280
  });
19214
19281
  const createTranscriptionModel = (modelId) => new OpenAITranscriptionModel(modelId, {
19215
19282
  provider: `${providerName}.transcription`,
19216
- url: ({ path: path38 }) => `${baseURL}${path38}`,
19283
+ url: ({ path: path42 }) => `${baseURL}${path42}`,
19217
19284
  headers: getHeaders,
19218
19285
  fetch: options.fetch
19219
19286
  });
19220
19287
  const createSpeechModel = (modelId) => new OpenAISpeechModel(modelId, {
19221
19288
  provider: `${providerName}.speech`,
19222
- url: ({ path: path38 }) => `${baseURL}${path38}`,
19289
+ url: ({ path: path42 }) => `${baseURL}${path42}`,
19223
19290
  headers: getHeaders,
19224
19291
  fetch: options.fetch
19225
19292
  });
@@ -19240,7 +19307,7 @@ function createOpenAI(options = {}) {
19240
19307
  const createResponsesModel = (modelId) => {
19241
19308
  return new OpenAIResponsesLanguageModel(modelId, {
19242
19309
  provider: `${providerName}.responses`,
19243
- url: ({ path: path38 }) => `${baseURL}${path38}`,
19310
+ url: ({ path: path42 }) => `${baseURL}${path42}`,
19244
19311
  headers: getHeaders,
19245
19312
  fetch: options.fetch
19246
19313
  });
@@ -22779,7 +22846,7 @@ async function profilesRow(cfg, token, userId) {
22779
22846
  const rows = await r.json();
22780
22847
  return rows[0] ?? null;
22781
22848
  }
22782
- async function handleVisibility(dataDir, method, body) {
22849
+ async function handleVisibility(dataDir, method, body, pool) {
22783
22850
  const cfg = centralConfig();
22784
22851
  if (!cfg.configured) return { status: 503, json: { error: "central services are disabled in this build" } };
22785
22852
  const auth = await getAccessToken(dataDir);
@@ -22795,6 +22862,26 @@ async function handleVisibility(dataDir, method, body) {
22795
22862
  const isPublic = body?.isPublic;
22796
22863
  if (typeof isPublic !== "boolean") return { status: 400, json: { error: "bad-input", message: "isPublic must be a boolean." } };
22797
22864
  try {
22865
+ if (isPublic) {
22866
+ const report = await loadPublicReport();
22867
+ if (!report || !hasContent(report)) {
22868
+ return { status: 409, json: { error: "nothing to publish yet \u2014 run the full analysis first so the public report exists, then publish" } };
22869
+ }
22870
+ let numbers = body?.numbers;
22871
+ if (numbers && typeof numbers === "object" && !Array.isArray(numbers) && pool) {
22872
+ numbers = Object.fromEntries(Object.entries(numbers).filter(([k, v]) => k in pool && v != null));
22873
+ } else {
22874
+ numbers = pool && Object.keys(pool).length ? pool : void 0;
22875
+ }
22876
+ const up = await fetch(`${cfg.supabaseUrl}/rest/v1/rpc/submit_report`, {
22877
+ method: "POST",
22878
+ headers: { apikey: cfg.supabaseAnonKey, authorization: `Bearer ${auth.token}`, "content-type": "application/json" },
22879
+ body: JSON.stringify({ p_session_id: null, p_content: JSON.stringify({ format: "pr1", report, ...numbers && Object.keys(numbers).length ? { numbers } : {} }) })
22880
+ });
22881
+ if (!up.ok) {
22882
+ return { status: 502, json: { error: `report upload failed (HTTP ${up.status}) \u2014 refusing to publish a link with nothing behind it` } };
22883
+ }
22884
+ }
22798
22885
  const row = await profilesRow(cfg, auth.token, auth.identity.userId);
22799
22886
  let slug = row?.public_slug ?? null;
22800
22887
  const patch = { is_public: isPublic };
@@ -22814,1511 +22901,2204 @@ async function handleVisibility(dataDir, method, body) {
22814
22901
  }
22815
22902
  }
22816
22903
 
22817
- // src/server.ts
22818
- init_dataHome();
22819
- var __dirname = path26.dirname(fileURLToPath2(import.meta.url));
22820
- var UI_DIR = path26.join(__dirname, "web");
22821
- var DEFAULT_SHARE_URL = "https://polymathsociety.us/api/coding-share";
22822
- var MIME = {
22823
- ".html": "text/html; charset=utf-8",
22824
- ".js": "text/javascript; charset=utf-8",
22825
- ".css": "text/css; charset=utf-8",
22826
- ".json": "application/json; charset=utf-8",
22827
- ".svg": "image/svg+xml",
22828
- ".ico": "image/x-icon",
22829
- ".map": "application/json; charset=utf-8"
22830
- };
22831
- async function readBody(req, maxBytes = 8e6) {
22832
- return new Promise((resolve2, reject) => {
22833
- let size = 0;
22834
- const chunks = [];
22835
- req.on("data", (c) => {
22836
- size += c.length;
22837
- if (size > maxBytes) {
22838
- reject(new Error("payload too large"));
22839
- req.destroy();
22840
- return;
22841
- }
22842
- chunks.push(c);
22843
- });
22844
- req.on("end", () => resolve2(Buffer.concat(chunks).toString("utf-8")));
22845
- req.on("error", reject);
22846
- });
22847
- }
22848
- async function serveStatic(res, urlPath) {
22849
- const clean = urlPath.split("?")[0];
22850
- const rel = clean === "/" ? "index.html" : clean.replace(/^\/+/, "");
22851
- const full = path26.normalize(path26.join(UI_DIR, rel));
22852
- if (!full.startsWith(UI_DIR)) {
22853
- res.writeHead(403).end("forbidden");
22854
- return;
22855
- }
22904
+ // src/shareEdit.ts
22905
+ init_agent();
22906
+ import { promises as fs21 } from "fs";
22907
+ import os6 from "os";
22908
+ import path26 from "path";
22909
+ var SYSTEM3 = `You edit a SMALL numbers-only JSON payload a person is about to share (their coding working-style summary). They tell you what to hide or change; you return the COMPLETE updated payload every time.
22910
+ ALLOWED EDITS ONLY: remove a whole section; remove a field inside a section ('don't share my words per day' \u2192 delete avgWordsPerDay); round/coarsen a number ('just say ~4000'); shorten or rename a label. FORBIDDEN: adding fields or sections, inventing numbers, increasing any score or percentile, adding text content. If asked for a forbidden edit, keep the payload unchanged and say why in the reply.
22911
+ Output ONE fenced \`\`\`json block: { "sections": { ...the complete updated payload... } } \u2014 then, AFTER the block, ONE short plain sentence describing what you changed (e.g. "Removed words-per-day and the project names.").`;
22912
+ async function handleShareEdit(pool, body) {
22913
+ const sections = body.sections && typeof body.sections === "object" ? body.sections : null;
22914
+ const messages = Array.isArray(body.messages) ? body.messages : [];
22915
+ const last = messages.filter((m) => m.role === "user").pop();
22916
+ if (!sections || !last?.content?.trim()) return { status: 400, json: { error: "sections + a user instruction are required" } };
22917
+ const convo = messages.slice(-6).map((m) => `${m.role === "user" ? "USER" : "EDITOR"}: ${m.content}`).join("\n");
22918
+ const prompt = `CURRENT PAYLOAD (what would be shared right now):
22919
+ \`\`\`json
22920
+ ${JSON.stringify(sections, null, 1)}
22921
+ \`\`\`
22922
+
22923
+ CONVERSATION:
22924
+ ${convo}
22925
+
22926
+ Apply the user's LAST instruction and return the complete updated payload.`;
22927
+ const sandbox = await fs21.mkdtemp(path26.join(os6.tmpdir(), "share-edit-"));
22856
22928
  try {
22857
- const data = await fs21.readFile(full);
22858
- res.writeHead(200, { "content-type": MIME[path26.extname(full)] ?? "application/octet-stream" });
22859
- res.end(data);
22860
- } catch {
22861
- if (!path26.extname(full)) {
22862
- try {
22863
- const idx = await fs21.readFile(path26.join(UI_DIR, "index.html"));
22864
- res.writeHead(200, { "content-type": MIME[".html"] }).end(idx);
22865
- return;
22866
- } catch {
22867
- }
22868
- }
22869
- res.writeHead(404).end("not found");
22929
+ const run4 = await invokeAgent({ prompt, systemPrompt: SYSTEM3, addDir: sandbox, allowedTools: [], maxTurns: 2, timeoutMs: 12e4, model: "haiku" });
22930
+ const j = run4.json ?? null;
22931
+ const raw = j && typeof j === "object" && "sections" in j ? j.sections : j;
22932
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return { status: 502, json: { error: "the edit didn't produce a valid payload \u2014 try rephrasing" } };
22933
+ const out = {};
22934
+ for (const k of Object.keys(raw)) if (k in pool && raw[k] != null) out[k] = raw[k];
22935
+ const reply = (run4.raw ?? "").split("```").pop()?.trim().split("\n").filter(Boolean).pop()?.slice(0, 300) || "Done.";
22936
+ return { status: 200, json: { sections: out, reply } };
22937
+ } catch (e) {
22938
+ return { status: 502, json: { error: e.message.slice(0, 200) } };
22939
+ } finally {
22940
+ await fs21.rm(sandbox, { recursive: true, force: true }).catch(() => {
22941
+ });
22870
22942
  }
22871
22943
  }
22872
- var isLoopback = (u) => {
22873
- try {
22874
- const h = new URL(u).hostname;
22875
- return h === "localhost" || h === "127.0.0.1" || h === "::1";
22876
- } catch {
22877
- return false;
22878
- }
22879
- };
22880
- async function handleShare(res, body, opts, dataDir) {
22881
- let parsed;
22944
+
22945
+ // src/server.ts
22946
+ init_dataHome();
22947
+ init_manifest();
22948
+ init_exportLinks();
22949
+
22950
+ // src/publicCodingPageApi.ts
22951
+ import { promises as fs28 } from "fs";
22952
+ import path32 from "path";
22953
+
22954
+ // ../../lib/agents/coding/publicPage.ts
22955
+ import { promises as fs27 } from "fs";
22956
+ import path31 from "path";
22957
+
22958
+ // ../../lib/agents/coding/docsDir.ts
22959
+ import { promises as fs23 } from "fs";
22960
+ import path28 from "path";
22961
+ async function writeScoreboard(codingDir, docs) {
22962
+ const gradesDir = path28.join(codingDir, "grades");
22963
+ let files = [];
22882
22964
  try {
22883
- parsed = JSON.parse(body);
22965
+ files = (await fs23.readdir(gradesDir)).filter((f) => f.endsWith(".json")).sort();
22884
22966
  } catch {
22885
- res.writeHead(400, { "content-type": "application/json" }).end(JSON.stringify({ ok: false, error: "bad JSON" }));
22886
22967
  return;
22887
22968
  }
22888
- const all = opts.shareSections ?? opts.profile?.sections ?? {};
22889
- const wanted = parsed.all ? Object.keys(all) : Array.isArray(parsed.sections) ? parsed.sections : [];
22890
- const sections = {};
22891
- for (const key of wanted) {
22892
- if (key in all && all[key] != null) sections[key] = all[key];
22969
+ const byCriterion = /* @__PURE__ */ new Map();
22970
+ for (const f of files) {
22971
+ let g;
22972
+ try {
22973
+ g = JSON.parse(await fs23.readFile(path28.join(gradesDir, f), "utf8"));
22974
+ } catch {
22975
+ continue;
22976
+ }
22977
+ for (const c of g.criteria ?? []) {
22978
+ const s = c.score ?? c.bestEstimate;
22979
+ if (s == null) continue;
22980
+ const line = `L${s}${c.score == null ? "~" : ""} \xB7 ${(g.date ?? "").slice(0, 10)} \xB7 ${(g.title ?? g.sessionId ?? "").replace(/\n.*/s, "").slice(0, 60)} \xB7 ${g.sessionId} \u2014 ${(c.instance ?? "").slice(0, 110)}`;
22981
+ (byCriterion.get(c.key) ?? byCriterion.set(c.key, []).get(c.key)).push({ s, line });
22982
+ }
22893
22983
  }
22894
- if (Object.keys(sections).length === 0) {
22895
- res.writeHead(400, { "content-type": "application/json" }).end(JSON.stringify({ ok: false, error: "no shareable sections selected" }));
22896
- return;
22984
+ if (!byCriterion.size) return;
22985
+ const blocks = [...byCriterion.entries()].sort(([a], [b]) => a < b ? -1 : 1).map(
22986
+ ([key, rows]) => `## ${key}
22987
+ ${rows.sort((a, b) => b.s - a.s).map((r) => r.line).join("\n")}`
22988
+ );
22989
+ await fs23.writeFile(
22990
+ path28.join(docs, "_scoreboard.md"),
22991
+ `# Scoreboard \u2014 every graded session per criterion, best first.
22992
+ # Lx~ = estimate. Format: level \xB7 date \xB7 title \xB7 sessionId \u2014 graded instance.
22993
+
22994
+ ${blocks.join("\n\n")}
22995
+ `
22996
+ );
22997
+ }
22998
+ async function ensureCodingDocs(codingDir, sessions) {
22999
+ const docs = path28.join(codingDir, "docs");
23000
+ await fs23.mkdir(docs, { recursive: true });
23001
+ const user = sessions.filter((s) => s.sessionId && !s.duplicateOf && (!("klass" in s) || s.klass === "interactive"));
23002
+ let written = 0;
23003
+ for (const s of user) {
23004
+ const out = path28.join(docs, `${s.sessionId}.txt`);
23005
+ try {
23006
+ await fs23.access(out);
23007
+ continue;
23008
+ } catch {
23009
+ }
23010
+ const mat = await materializeSession2(s.file).catch(() => null);
23011
+ if (!mat?.text) continue;
23012
+ await fs23.writeFile(out, mat.text);
23013
+ written++;
22897
23014
  }
22898
- const shareUrl = opts.shareUrl || DEFAULT_SHARE_URL;
22899
- const auth = await getAccessToken(dataDir);
22900
- if (!auth && !isLoopback(shareUrl)) {
22901
- res.writeHead(401, { "content-type": "application/json" });
22902
- res.end(JSON.stringify({ ok: false, error: "sign in with Google (top right) to share your report" }));
22903
- return;
23015
+ const rows = user.sort((a, b) => (a.start ?? "") < (b.start ?? "") ? -1 : 1).map((s) => `${(s.start ?? "").slice(0, 10)} \xB7 ${(s.title ?? "").replace(/\n.*/s, "").slice(0, 80)} \xB7 ${s.sessionId}`);
23016
+ await fs23.writeFile(path28.join(docs, "_map.md"), rows.join("\n") + "\n");
23017
+ await writeScoreboard(codingDir, docs);
23018
+ if (written) console.log(`[docs] materialized ${written} new transcript(s) \u2192 ${docs}`);
23019
+ return docs;
23020
+ }
23021
+ function sourceLookupNote() {
23022
+ return `
23023
+
23024
+ SOURCE LOOKUP \u2014 you have Read/Grep/Glob over the working directory, which holds EVERYTHING known about this person's coding work. MAPS FIRST, grep second (the engine rule): docs/_scoreboard.md ranks every graded session per criterion, best first \u2014 one glance shows where the spikes/flair are, so start there when hunting peaks or checking whether a high mark is consistent or a one-off; day-digest.json is the day-by-day story of what they did in order \u2014 read the relevant days to get the arc before searching; docs/_map.md lists every session (date \xB7 title \xB7 sessionId). Then drill down: walkthroughs/<sessionId>.json is that session's phase-by-phase account (cheap, already distilled), grades/<sessionId>.json its graded findings with quotes, and docs/<sessionId>.txt the FULL transcript (">> " = the person, "[AI]" = the model) \u2014 the ground truth, read it when the distilled layers can't settle it. Other artifacts (flow.json, delegation/, expertise/, aggregate.json) are there too if a claim depends on them. The digest you were given is the spine \u2014 use lookups when a CLAIM-MOVING question cannot be settled from it (a moment you are about to headline, a promotion/depth call, an ambiguous engagement, whether detail was vision or boilerplate). VERIFY every verbatim quote you cite by finding it in the transcript first; if you cannot find it, do not use it. Look up what changes the output \u2014 do not re-read the whole corpus.`;
23025
+ }
23026
+
23027
+ // ../../lib/agents/coding/promptCache.ts
23028
+ import { createHash as createHash3 } from "crypto";
23029
+ import { promises as fs24 } from "fs";
23030
+ function promptSha(parts) {
23031
+ const h = createHash3("sha256");
23032
+ for (const p of parts) {
23033
+ h.update(p ?? "");
23034
+ h.update("\0");
22904
23035
  }
22905
- const payload = {
22906
- source: "coding-analyzer",
22907
- version: opts.version,
22908
- name: typeof parsed.name === "string" && parsed.name.trim() ? parsed.name.trim() : void 0,
22909
- sharedAt: (/* @__PURE__ */ new Date()).toISOString(),
22910
- ...auth ? { owner: { userId: auth.identity.userId, email: auth.identity.email } } : {},
22911
- sections
22912
- };
23036
+ return h.digest("hex").slice(0, 16);
23037
+ }
23038
+ async function reusableOutput(outPath, sha, valid, key = "promptSha") {
22913
23039
  try {
22914
- const upstream = await fetch(shareUrl, {
22915
- method: "POST",
22916
- headers: { "content-type": "application/json", ...auth ? { authorization: `Bearer ${auth.token}` } : {} },
22917
- body: JSON.stringify(payload)
22918
- });
22919
- const text2 = await upstream.text();
22920
- res.writeHead(upstream.ok ? 200 : 502, { "content-type": "application/json" });
22921
- res.end(JSON.stringify({ ok: upstream.ok, status: upstream.status, endpoint: shareUrl, shared: Object.keys(sections), upstream: text2.slice(0, 2e3) }));
22922
- } catch (e) {
22923
- res.writeHead(502, { "content-type": "application/json" });
22924
- res.end(JSON.stringify({ ok: false, error: String(e instanceof Error ? e.message : e), endpoint: shareUrl }));
23040
+ const o = JSON.parse(await fs24.readFile(outPath, "utf8"));
23041
+ if (o[key] === sha && valid(o)) return o;
23042
+ } catch {
22925
23043
  }
23044
+ return null;
22926
23045
  }
22927
- function startServer(opts) {
22928
- let liveProfile = opts.profile;
22929
- let liveProgress = {};
22930
- const host = opts.host ?? "127.0.0.1";
22931
- const dataDir = opts.dataDir ?? resolveDataRoot();
22932
- let serverUrl = "";
22933
- const json = (res, status, body) => res.writeHead(status, { "content-type": MIME[".json"] }).end(JSON.stringify(body));
22934
- const server = http.createServer(async (req, res) => {
22935
- try {
22936
- const url = req.url ?? "/";
22937
- const route = url.split("?")[0];
22938
- if (req.method === "GET" && (url === "/api/coding" || url === "/profile.json" || url.startsWith("/profile.json?"))) {
22939
- res.writeHead(200, { "content-type": MIME[".json"] }).end(JSON.stringify(liveProfile));
22940
- return;
22941
- }
22942
- if (req.method === "GET" && url === "/api/progress") {
22943
- res.writeHead(200, { "content-type": MIME[".json"] }).end(JSON.stringify(liveProgress));
22944
- return;
22945
- }
22946
- if (req.method === "GET" && route === "/meta.json") {
22947
- const identity = await readIdentity(dataDir);
22948
- const central = centralConfig();
22949
- json(res, 200, {
22950
- version: opts.version,
22951
- shareUrl: opts.shareUrl || DEFAULT_SHARE_URL,
22952
- standalone: true,
22953
- capabilities: {
22954
- preview: true,
22955
- state: true,
22956
- diagnostic: false,
22957
- // corpus audit is engine-report-only
22958
- submit: central.configured,
22959
- auth: central.configured,
22960
- share: true,
22961
- person: true,
22962
- // the chat-analysis tab's /api/person* routes
22963
- publicReport: true
22964
- // the public-report tab's /api/public-report route
22965
- },
22966
- identity: identity ? { email: identity.email, name: identity.name ?? null } : null
22967
- });
22968
- return;
22969
- }
22970
- if (req.method === "GET" && (route === "/api/config/calibration" || route === "/api/calibration")) {
22971
- const cal = await getCalibration();
22972
- json(res, 200, { ...cal, localRubricVersion: RUBRIC_FINGERPRINT2 });
22973
- return;
22974
- }
22975
- if (req.method === "GET" && route === "/auth/login") {
22976
- const r = beginLogin(serverUrl);
22977
- if ("error" in r) {
22978
- json(res, 503, { error: r.error });
22979
- return;
22980
- }
22981
- res.writeHead(302, { location: r.redirect }).end();
22982
- return;
22983
- }
22984
- if (req.method === "GET" && route === "/auth/callback") {
22985
- try {
22986
- const id = await completeLogin(dataDir, new URL(url, serverUrl).searchParams);
22987
- res.writeHead(200, { "content-type": MIME[".html"] });
22988
- res.end(`<!doctype html><meta charset="utf-8"><title>Signed in</title><body style="font-family:system-ui;padding:40px"><p>Signed in as <b>${id.email.replace(/</g, "&lt;")}</b>.</p><p><a href="/">Back to your report</a> (or just close this tab \u2014 the report page picks it up on its own).</p></body>`);
22989
- } catch (e) {
22990
- res.writeHead(400, { "content-type": MIME[".html"] });
22991
- res.end(`<!doctype html><meta charset="utf-8"><title>Sign-in failed</title><body style="font-family:system-ui;padding:40px"><p><b>Sign-in failed.</b></p><p>${String(e.message).replace(/</g, "&lt;")}</p><p><a href="/auth/login">Try again</a></p></body>`);
22992
- }
22993
- return;
22994
- }
22995
- if (req.method === "POST" && route === "/auth/logout") {
22996
- await signOut(dataDir);
22997
- json(res, 200, { ok: true });
22998
- return;
22999
- }
23000
- if (route === "/api/feedback/preview" && req.method === "POST") {
23001
- const body = JSON.parse(await readBody(req) || "{}");
23002
- const out = await handlePreview(body);
23003
- json(res, out.status, out.json);
23004
- return;
23005
- }
23006
- if (route === "/api/feedback/state" && (req.method === "GET" || req.method === "POST")) {
23007
- const body = req.method === "POST" ? JSON.parse(await readBody(req) || "{}") : void 0;
23008
- const out = await handleState(dataDir, req.method, body);
23009
- json(res, out.status, out.json);
23010
- return;
23011
- }
23012
- if (route === "/api/feedback/submit" && req.method === "POST") {
23013
- const body = JSON.parse(await readBody(req) || "{}");
23014
- const out = await handleSubmit(dataDir, body);
23015
- json(res, out.status, out.json);
23016
- return;
23017
- }
23018
- if (route === "/api/feedback/diagnostic") {
23019
- let body;
23020
- if (req.method === "POST") {
23021
- try {
23022
- body = JSON.parse(await readBody(req));
23023
- } catch {
23024
- json(res, 400, { error: "bad json" });
23025
- return;
23026
- }
23027
- }
23028
- const key = new URL(url, serverUrl || "http://localhost").searchParams.get("key") || void 0;
23029
- const out = handleDiagnostic(req.method || "GET", body, key);
23030
- json(res, out.status, out.json);
23031
- return;
23032
- }
23033
- if (route === "/api/person" && req.method === "GET") {
23034
- const out = await handlePerson();
23035
- json(res, out.status, out.json);
23036
- return;
23037
- }
23038
- if (route === "/api/person/feedback" && (req.method === "GET" || req.method === "POST")) {
23039
- const body = req.method === "POST" ? JSON.parse(await readBody(req) || "{}") : void 0;
23040
- const out = await handlePersonFeedback(req.method, body);
23041
- json(res, out.status, out.json);
23042
- return;
23043
- }
23044
- if (route === "/api/person/loops" && req.method === "GET") {
23045
- const out = await handleLoops();
23046
- json(res, out.status, out.json);
23047
- return;
23048
- }
23049
- if (route === "/api/person/grade" && req.method === "GET") {
23050
- const out = await handleGrade(new URL(url, serverUrl || "http://localhost").searchParams);
23051
- json(res, out.status, out.json);
23052
- return;
23053
- }
23054
- if (route === "/api/person/transcript" && req.method === "GET") {
23055
- const out = await handleTranscript(new URL(url, serverUrl || "http://localhost").searchParams);
23056
- res.writeHead(out.status, { "Content-Type": "text/plain; charset=utf-8" }).end(out.text);
23057
- return;
23058
- }
23059
- if (route === "/api/person/chat" && req.method === "POST") {
23060
- const body = JSON.parse(await readBody(req) || "{}");
23061
- await handlePersonChat(body, res);
23062
- return;
23063
- }
23064
- if (route === "/api/public-report" && req.method === "GET") {
23065
- const out = await handlePublicReportGet();
23066
- json(res, out.status, out.json);
23067
- return;
23068
- }
23069
- if (route === "/api/public-report" && req.method === "POST") {
23070
- const body = JSON.parse(await readBody(req) || "{}");
23071
- const out = await handlePublicReportEdit(body);
23072
- json(res, out.status, out.json);
23073
- return;
23074
- }
23075
- if (route === "/api/profile/visibility" && (req.method === "GET" || req.method === "POST")) {
23076
- const body = req.method === "POST" ? JSON.parse(await readBody(req) || "{}") : void 0;
23077
- const out = await handleVisibility(dataDir, req.method, body);
23078
- json(res, out.status, out.json);
23079
- return;
23080
- }
23081
- if (route === "/api/coding/chat" && req.method === "POST") {
23082
- const body = JSON.parse(await readBody(req) || "{}");
23083
- await handleCodingChat(liveProfile, dataDir, body, res);
23084
- return;
23085
- }
23086
- if (req.method === "POST" && url === "/share") {
23087
- const body = await readBody(req);
23088
- await handleShare(res, body, opts, dataDir);
23089
- return;
23090
- }
23091
- if (route.startsWith("/api/")) {
23092
- json(res, 404, { error: `this viewer doesn't serve ${route}` });
23093
- return;
23094
- }
23095
- if (req.method === "GET") {
23096
- await serveStatic(res, url);
23097
- return;
23098
- }
23099
- res.writeHead(405).end("method not allowed");
23100
- } catch (e) {
23101
- res.writeHead(500, { "content-type": "application/json" }).end(JSON.stringify({ ok: false, error: String(e) }));
23046
+
23047
+ // ../../lib/agents/coding/profile.ts
23048
+ import { promises as fs26 } from "fs";
23049
+ import path30 from "path";
23050
+
23051
+ // ../../lib/agents/coding/walkthrough.ts
23052
+ import { promises as fs25 } from "fs";
23053
+ import path29 from "path";
23054
+ var IDLE_CAP_MS = 12 * 6e4;
23055
+ async function readWalkthrough(outDir, sessionId) {
23056
+ return fs25.readFile(path29.join(outDir, `${sessionId}.json`), "utf8").then(JSON.parse).catch(() => null);
23057
+ }
23058
+
23059
+ // ../../lib/agents/coding/workstyle.ts
23060
+ var MIN3 = 6e4;
23061
+ var DAY_CUTOFF_H = 5;
23062
+ var FLOW_THRESHOLD_MIN = 30;
23063
+ var pct = (x) => `${Math.round(x * 100)}%`;
23064
+ var fmtN = (n) => n.toLocaleString("en-US");
23065
+ var round12 = (x) => Math.round(x * 10) / 10;
23066
+ var median = (xs) => xs.length ? [...xs].sort((a, b) => a - b)[Math.floor(xs.length / 2)] : 0;
23067
+ function fmtDur2(min) {
23068
+ return min >= 60 ? `${round12(min / 60)}h` : `${Math.round(min)}m`;
23069
+ }
23070
+ function clockLabel(h) {
23071
+ if (h === 0) return "midnight";
23072
+ if (h === 12) return "noon";
23073
+ return h < 12 ? `${h}am` : `${h - 12}pm`;
23074
+ }
23075
+ function pick(ladder, score, fallback = "not enough signal yet") {
23076
+ if (score == null) return fallback;
23077
+ const r = Math.round(score);
23078
+ const keys = Object.keys(ladder).map(Number).sort((a, b) => a - b);
23079
+ let chosen = keys[0];
23080
+ for (const k of keys) if (k <= r) chosen = k;
23081
+ return ladder[chosen];
23082
+ }
23083
+ var TASTE = {
23084
+ 4: "mostly rubber-stamps what the AI produces",
23085
+ 5: "an ordinary reviewer's bar",
23086
+ 6: "rejects the obviously-bad version and iterates toward something better",
23087
+ 7: "holds a real, specific quality bar and pushes past the AI's first answer",
23088
+ 8: "makes the call the AI couldn't reach on its own \u2014 opinionated, specific, vindicated",
23089
+ 9: "high, particular taste \u2014 names AI slop the moment it appears",
23090
+ 10: "brings a developed vision up front, and knows where not to impose it",
23091
+ 11: "world-class taste"
23092
+ };
23093
+ var DELEGATION = {
23094
+ 4: "still uneven \u2014 sometimes under-briefs work they had opinions about",
23095
+ 6: "roughly calibrated on when to do the thinking themselves vs. let the AI run",
23096
+ 8: "well-calibrated \u2014 front-loads the specifiable, reserves correction for genuine AI errors, lets rote run",
23097
+ 10: "near-perfect prompt economy \u2014 almost everything knowable is front-loaded"
23098
+ };
23099
+ var OUTCOMES = {
23100
+ 4: "sessions often wrap before a real capability lands",
23101
+ 6: "one real, confirmed thing shipped is the typical bar",
23102
+ 8: "a substantial, verified capability per session is routine",
23103
+ 10: "ships end-to-end-checked work that unblocks a lot downstream"
23104
+ };
23105
+ var GENERATIVE = {
23106
+ 4: "reaches workable answers with effort",
23107
+ 6: "real ideas and sound tradeoff reasoning",
23108
+ 7: "collapses messy situations to their essence and reasons from first principles",
23109
+ 8: "fast collapse to the core, plus its own approach and the exact fix",
23110
+ 9: "generates frameworks and reframes others wouldn't reach",
23111
+ 10: "out-reasons the tool \u2014 lands insights the AI itself missed"
23112
+ };
23113
+ var METACOGNITION = {
23114
+ 4: "notices friction but mostly just flags it",
23115
+ 6: "spots a bottleneck and adjusts how they work for the case at hand",
23116
+ 8: "treats their own throughput as an engineering problem \u2014 names recurring friction and restructures to kill it",
23117
+ 10: "re-architects the whole way of working mid-stream to get unstuck"
23118
+ };
23119
+ var EXPERTISE = {
23120
+ 2: "defers to the AI on system decisions \u2014 no specific knowledge surfaces",
23121
+ 4: "opinions are mostly generic best-practice the AI already had",
23122
+ 6: "knows their own stack well and corrects the AI on real systems facts",
23123
+ 8: "repeatedly catches what the AI misses with specific systems/tooling calls a junior wouldn't make",
23124
+ 9: "deep, specific directives about their own infra a junior wouldn't know",
23125
+ 10: "makes counter-intuitive, deep-operating-knowledge calls the AI would have gotten backwards"
23126
+ };
23127
+ var FRONTIER = {
23128
+ 2: "one session at a time, default settings",
23129
+ 4: "occasionally runs two things; no structural tooling",
23130
+ 6: "routinely parallel, queuing work ahead and organizing sessions",
23131
+ 8: "real leverage \u2014 overnight/remote runs, subagents, scripts that drive the AI",
23132
+ 10: "builds harnesses and workflows; loops and scales the AI across machines"
23133
+ };
23134
+ function flowRunsFromSlots(slots) {
23135
+ const fSlots = Object.keys(slots).map(Number).filter((s) => slots[String(s)] === "F").sort((a, b) => a - b);
23136
+ const runs = [];
23137
+ let start = null, prev = null;
23138
+ const flush = () => {
23139
+ if (start !== null && prev !== null) runs.push((prev - start + 1) * 10);
23140
+ };
23141
+ for (const s of fSlots) {
23142
+ if (prev !== null && s === prev + 1) {
23143
+ prev = s;
23144
+ } else {
23145
+ flush();
23146
+ start = s;
23147
+ prev = s;
23148
+ }
23149
+ }
23150
+ flush();
23151
+ return runs;
23152
+ }
23153
+ function buildFlow(runMin, ctx) {
23154
+ const sorted = [...runMin].sort((a, b) => a - b);
23155
+ const BUCKET_DEFS = [["\u2264 20m", 0, 30], ["30m\u20131h", 30, 60], ["1\u20132h", 60, 120], ["2h+", 120, Infinity]];
23156
+ const flowBlocks = BUCKET_DEFS.map(([label, lo, hi]) => {
23157
+ const inB = sorted.filter((x) => x >= lo && x < hi);
23158
+ return { label, lo, hi, count: inB.length, min: round12(inB.reduce((a, b) => a + b, 0)) };
23159
+ });
23160
+ const deepBlocks = sorted.filter((x) => x >= FLOW_THRESHOLD_MIN).length;
23161
+ const flowHoursPerDay = ctx.activeDays ? ctx.flowHoursTotal / ctx.activeDays : 0;
23162
+ const deepBlocksPerDay = ctx.activeDays ? deepBlocks / ctx.activeDays : 0;
23163
+ const flowCadence = ctx.flowFraction >= 0.45 && flowHoursPerDay >= 1.5 ? "frequent" : ctx.flowFraction < 0.18 ? "rare" : "interspersed";
23164
+ const longest = sorted.length ? Math.max(...sorted) : 0;
23165
+ const med2 = median(sorted);
23166
+ const flowBullets = [];
23167
+ flowBullets.push(`${round12(ctx.flowHoursTotal)}h of genuine flow over ${ctx.activeDays} working days \u2014 about ${round12(flowHoursPerDay)}h a day.`);
23168
+ flowBullets.push(`${pct(ctx.flowFraction)} of active working time is true flow (rapid rhythm or dictation); the rest is thinking-pauses and switching.`);
23169
+ if (flowCadence === "frequent") {
23170
+ flowBullets.push(`Deep flow is a daily norm \u2014 ${deepBlocks} runs of ${FLOW_THRESHOLD_MIN}m+, longest ${fmtDur2(longest)}; highly productive once locked in.`);
23171
+ } else if (flowCadence === "interspersed") {
23172
+ flowBullets.push(`Flow comes in solid bursts \u2014 ${med2}\u2013${longest}m at a time, ${deepBlocks} runs of ${FLOW_THRESHOLD_MIN}m+ \u2014 interspersed with pauses and rapid context-switching across parallel sessions.`);
23173
+ } else {
23174
+ flowBullets.push(`Flow is sporadic \u2014 mostly short focused windows rather than long unbroken runs.`);
23175
+ }
23176
+ if (ctx.peakFlowDay) flowBullets.push(`Best day: ${round12(ctx.peakFlowDay.hours)}h in flow (${pct(ctx.peakFlowDay.fraction)} of that day's working time).`);
23177
+ return {
23178
+ flowSource: ctx.source,
23179
+ flowThresholdMin: FLOW_THRESHOLD_MIN,
23180
+ flowBlocks,
23181
+ blockCount: sorted.length,
23182
+ deepBlocks,
23183
+ longestBlockMin: round12(longest),
23184
+ medianBlockMin: round12(med2),
23185
+ flowFraction: Math.round(ctx.flowFraction * 100) / 100,
23186
+ flowHoursTotal: round12(ctx.flowHoursTotal),
23187
+ flowHoursPerDay: round12(flowHoursPerDay),
23188
+ deepBlocksPerDay: round12(deepBlocksPerDay),
23189
+ flowCadence,
23190
+ peakFlowDay: ctx.peakFlowDay,
23191
+ flowBullets
23192
+ };
23193
+ }
23194
+ function computeWorkstyle(inp) {
23195
+ const { tz, idleGapMin } = inp;
23196
+ const idleGapMs = idleGapMin * MIN3;
23197
+ const all = [];
23198
+ for (const day of inp.dayChart) for (const c of day.conversations) for (const iv of c.intervals) all.push(iv);
23199
+ all.sort((a, b) => a[0] - b[0]);
23200
+ const parts = (ms2) => {
23201
+ const [h, m2, s] = new Date(ms2).toLocaleTimeString("en-GB", { timeZone: tz, hour12: false }).split(":").map(Number);
23202
+ return { h, m: m2, s };
23203
+ };
23204
+ const localDate2 = (ms2) => new Date(ms2).toLocaleDateString("en-CA", { timeZone: tz });
23205
+ const sinceCutoff = (ms2) => {
23206
+ const { h, m: m2 } = parts(ms2);
23207
+ let x = (h - DAY_CUTOFF_H) * 60 + m2;
23208
+ if (x < 0) x += 1440;
23209
+ return x;
23210
+ };
23211
+ const logicalDate = (ms2) => localDate2(ms2 - DAY_CUTOFF_H * 36e5);
23212
+ const fromCutoff = (x) => {
23213
+ const t = (x + DAY_CUTOFF_H * 60) % 1440;
23214
+ return `${String(Math.floor(t / 60)).padStart(2, "0")}:${String(Math.round(t % 60)).padStart(2, "0")}`;
23215
+ };
23216
+ const hourMin = new Array(24).fill(0);
23217
+ for (const [a, b] of all) {
23218
+ let cur = a;
23219
+ while (cur < b) {
23220
+ const { h, m: m2, s } = parts(cur);
23221
+ const msToNextHour = ((59 - m2) * 60 + (60 - s)) * 1e3;
23222
+ const segEnd = Math.min(b, cur + msToNextHour);
23223
+ hourMin[h] += (segEnd - cur) / MIN3;
23224
+ cur = segEnd;
23102
23225
  }
23103
- });
23104
- return new Promise((resolve2, reject) => {
23105
- server.on("error", reject);
23106
- server.listen(opts.port ?? 0, host, () => {
23107
- const addr = server.address();
23108
- const port = typeof addr === "object" && addr ? addr.port : 0;
23109
- serverUrl = `http://${host}:${port}`;
23110
- void getCalibration().then((cal) => {
23111
- if (cal.source === "central" && cal.doc.rubricVersion !== RUBRIC_FINGERPRINT2) {
23112
- console.warn(`[polymath-society] a newer grading rubric is published (${cal.doc.rubricVersion}; this install: ${RUBRIC_FINGERPRINT2}) \u2014 update the package and re-grade to stay comparable.`);
23113
- }
23114
- }).catch(() => {
23115
- });
23116
- resolve2({
23117
- url: serverUrl,
23118
- port,
23119
- close: () => new Promise((r) => server.close(() => r())),
23120
- setProfile: (p) => {
23121
- liveProfile = p;
23122
- },
23123
- setProgress: (p) => {
23124
- liveProgress = p;
23125
- }
23126
- });
23226
+ }
23227
+ const hourly = hourMin.map((min, hour) => ({ hour, min: round12(min) }));
23228
+ const totalMin = hourMin.reduce((a, b) => a + b, 0) || 1;
23229
+ const sumHours = (hs) => hs.reduce((a, h) => a + hourMin[h], 0);
23230
+ const shares = {
23231
+ morning: sumHours([5, 6, 7, 8, 9, 10, 11]) / totalMin,
23232
+ afternoon: sumHours([12, 13, 14, 15, 16, 17]) / totalMin,
23233
+ evening: sumHours([18, 19, 20, 21]) / totalMin,
23234
+ lateNight: sumHours([22, 23, 0, 1, 2, 3, 4]) / totalMin
23235
+ };
23236
+ const peakHours = [...hourMin.keys()].filter((h) => hourMin[h] > 0).sort((a, b) => hourMin[b] - hourMin[a]).slice(0, 3);
23237
+ const peak0 = peakHours[0] ?? 12;
23238
+ const isNightOwl = shares.lateNight >= 0.2 || peak0 >= 22 || peak0 <= 3;
23239
+ let lunchDip = null;
23240
+ const dipFloor = totalMin / 40;
23241
+ for (const h of [12, 13, 14]) {
23242
+ if (hourMin[h] < hourMin[h - 1] * 0.7 && hourMin[h] < hourMin[h + 1] * 0.7 && hourMin[h - 1] > dipFloor && hourMin[h + 1] > dipFloor) {
23243
+ if (lunchDip == null || hourMin[h] < hourMin[lunchDip]) lunchDip = h;
23244
+ }
23245
+ }
23246
+ const env = /* @__PURE__ */ new Map();
23247
+ for (const [a, b] of all) {
23248
+ const ld = logicalDate(a);
23249
+ let s = sinceCutoff(a), e = sinceCutoff(b);
23250
+ if (e < s) e += 1440;
23251
+ const cur = env.get(ld) ?? { first: Infinity, last: -Infinity };
23252
+ cur.first = Math.min(cur.first, s);
23253
+ cur.last = Math.max(cur.last, e);
23254
+ env.set(ld, cur);
23255
+ }
23256
+ const startsM = [...env.values()].map((v) => v.first);
23257
+ const endsM = [...env.values()].map((v) => v.last);
23258
+ const daysObserved = env.size;
23259
+ const typicalStart = startsM.length ? fromCutoff(median(startsM)) : "\u2014";
23260
+ const typicalEnd = endsM.length ? fromCutoff(median(endsM)) : "\u2014";
23261
+ const earliestStart = startsM.length ? fromCutoff(Math.min(...startsM)) : "\u2014";
23262
+ const latestEnd = endsM.length ? fromCutoff(Math.max(...endsM)) : "\u2014";
23263
+ let flow;
23264
+ if (inp.flow && inp.flow.days.length) {
23265
+ const runs = [];
23266
+ for (const d of inp.flow.days) runs.push(...flowRunsFromSlots(d.slots));
23267
+ const peak = [...inp.flow.days].sort((a, b) => b.flowHours - a.flowHours)[0];
23268
+ flow = buildFlow(runs, {
23269
+ source: "flow.json",
23270
+ activeDays: inp.flow.totals.activeDays,
23271
+ flowFraction: inp.flow.totals.flowFraction,
23272
+ flowHoursTotal: inp.flow.totals.flowSlots / 6,
23273
+ peakFlowDay: peak ? { date: peak.date, hours: peak.flowHours, fraction: peak.flowFraction } : null
23127
23274
  });
23128
- });
23275
+ } else {
23276
+ const merged = [];
23277
+ for (const [a, b] of all) {
23278
+ const last = merged[merged.length - 1];
23279
+ if (last && a <= last[1] + idleGapMs) last[1] = Math.max(last[1], b);
23280
+ else merged.push([a, b]);
23281
+ }
23282
+ const blocks = merged.map(([a, b]) => (b - a) / MIN3);
23283
+ const totalBlockMin = blocks.reduce((a, b) => a + b, 0) || 1;
23284
+ const deepMin = blocks.filter((x) => x >= FLOW_THRESHOLD_MIN).reduce((a, b) => a + b, 0);
23285
+ flow = buildFlow(blocks, {
23286
+ source: "intervals",
23287
+ activeDays: daysObserved,
23288
+ flowFraction: deepMin / totalBlockMin,
23289
+ flowHoursTotal: deepMin / 60,
23290
+ peakFlowDay: null
23291
+ });
23292
+ }
23293
+ const m = (k) => inp.criteriaMean[k] ?? { mean: null, n: 0 };
23294
+ const judgment = [
23295
+ { key: "taste", label: "Taste", score: m("taste").mean, n: m("taste").n },
23296
+ { key: "delegation", label: "Calibration", score: m("delegation").mean, n: m("delegation").n },
23297
+ { key: "generative", label: "Under ambiguity", score: m("generative").mean, n: m("generative").n },
23298
+ { key: "metacognition", label: "Self-direction", score: m("metacognition").mean, n: m("metacognition").n },
23299
+ { key: "outcomes", label: "Outcomes", score: m("outcomes").mean, n: m("outcomes").n }
23300
+ ];
23301
+ const rhythmBullets = [];
23302
+ const lateTail = /^(0[0-5]|2[3])/.test(latestEnd);
23303
+ rhythmBullets.push(`Works roughly ${typicalStart}\u2013${typicalEnd} on a typical day${lateTail ? `, with sessions running as late as ${latestEnd}` : ""}.`);
23304
+ if (isNightOwl) {
23305
+ rhythmBullets.push(`A night owl \u2014 ${pct(shares.lateNight)} of the work lands after 10pm or in the small hours.`);
23306
+ } else if (shares.morning >= shares.afternoon && shares.morning >= shares.evening) {
23307
+ rhythmBullets.push(`An early bird \u2014 most of the work happens before noon (${pct(shares.morning)} of active time).`);
23308
+ } else if (shares.afternoon >= shares.evening) {
23309
+ rhythmBullets.push(`An afternoon worker \u2014 ${pct(shares.afternoon)} of active time falls between noon and 6pm, only ${pct(shares.lateNight)} in the small hours.`);
23310
+ } else {
23311
+ rhythmBullets.push(`An evening worker \u2014 work concentrates after 6pm (${pct(shares.evening)} of active time).`);
23312
+ }
23313
+ {
23314
+ let txt = `Productivity peaks around ${clockLabel(peak0)}`;
23315
+ const p1 = peakHours.find((h) => Math.abs(h - peak0) >= 3);
23316
+ if (p1 != null) txt += `, with a second push around ${clockLabel(p1)}`;
23317
+ rhythmBullets.push(txt + ".");
23318
+ }
23319
+ if (lunchDip != null) rhythmBullets.push(`Takes a visible midday breather around ${clockLabel(lunchDip)}.`);
23320
+ const judgmentBullets = [];
23321
+ judgmentBullets.push(`Judgment & taste \u2014 ${pick(TASTE, m("taste").mean)}; on delegation, ${pick(DELEGATION, m("delegation").mean)}.`);
23322
+ {
23323
+ const cad = inp.outcomeCadence ? `ships something meaningful ~${round12(inp.outcomeCadence.perWeek)}\xD7/week (${pct(inp.outcomeCadence.fraction)} of working days), and ` : "";
23324
+ judgmentBullets.push(`High-outcome work \u2014 ${cad}${pick(OUTCOMES, m("outcomes").mean)}.`);
23325
+ }
23326
+ judgmentBullets.push(`Under ambiguity \u2014 ${pick(GENERATIVE, m("generative").mean)}; strongest where there's no ground truth and the task is to invent what to measure.`);
23327
+ judgmentBullets.push(`Prioritizing the work \u2014 ${pick(METACOGNITION, m("metacognition").mean)}.`);
23328
+ const exp = m("expertise").mean, cog = m("generative").mean, fr = m("frontier").mean;
23329
+ const sig = inp.signals;
23330
+ let archetype;
23331
+ if (exp == null || cog == null) {
23332
+ archetype = "Not enough graded signal yet to place the technical profile.";
23333
+ } else if (cog - exp >= 1.2) {
23334
+ archetype = "Cognition-forward \u2014 reasoning runs ahead of hands-on systems depth: thinks like a senior, with some stack-specific knowledge still leveling up.";
23335
+ } else if (exp - cog >= 1.2) {
23336
+ archetype = "Specialist \u2014 deep, specific systems and architecture knowledge is the anchor, ahead of raw abstraction.";
23337
+ } else if (exp >= 8 && cog >= 8) {
23338
+ archetype = "Deep and sharp \u2014 strong systems knowledge matched by top-tier reasoning.";
23339
+ } else {
23340
+ archetype = "Balanced operator \u2014 solid systems knowledge and reasoning move in step, both clearly competent.";
23341
+ }
23342
+ const gap = exp != null && cog != null ? cog > exp + 0.8 ? "noticeably ahead of the stack-specific knowledge" : exp > cog + 0.8 ? "with the systems depth running slightly ahead" : "roughly in step with the systems depth" : "";
23343
+ const sigBits = [];
23344
+ if (sig.maxConcurrency >= 2) sigBits.push(`up to \xD7${sig.maxConcurrency} sessions at once`);
23345
+ if (sig.subagents > 0) sigBits.push(`${fmtN(sig.subagents)} subagent spawns`);
23346
+ if (sig.queueOps > 0) sigBits.push(`${fmtN(sig.queueOps)} queue-ahead ops`);
23347
+ if (sig.mcpTools > 0) sigBits.push(`${sig.mcpTools} MCP tool${sig.mcpTools > 1 ? "s" : ""}`);
23348
+ const sigSentence = sigBits.length ? sigBits.join(", ") : "mostly single-session work";
23349
+ const experienced = sig.maxConcurrency >= 3 && (sig.queueOps > 50 || sig.subagents > 0 || sig.mcpTools > 0);
23350
+ const technical = {
23351
+ expertise: exp,
23352
+ cognition: cog,
23353
+ frontier: fr,
23354
+ signals: sig,
23355
+ archetype,
23356
+ bullets: [
23357
+ `Systems & architecture \u2014 ${pick(EXPERTISE, exp)}.`,
23358
+ `Raw cognition \u2014 ${pick(GENERATIVE, cog)}${gap ? `, ${gap}` : ""}.`,
23359
+ `Agent fluency \u2014 ${experienced ? "clearly an experienced agent operator; " : ""}${pick(FRONTIER, fr)} (${sigSentence}).`
23360
+ ]
23361
+ };
23362
+ return {
23363
+ tz,
23364
+ daysObserved,
23365
+ activeHours: round12(totalMin / 60),
23366
+ typicalStart,
23367
+ typicalEnd,
23368
+ earliestStart,
23369
+ latestEnd,
23370
+ hourly,
23371
+ peakHours,
23372
+ shares,
23373
+ isNightOwl,
23374
+ lunchDip,
23375
+ rhythmBullets,
23376
+ ...flow,
23377
+ judgment,
23378
+ judgmentBullets,
23379
+ technical
23380
+ };
23129
23381
  }
23130
23382
 
23131
- // src/pipeline.ts
23132
- import { spawn as spawn6 } from "child_process";
23133
- import path29 from "path";
23134
- import { existsSync as existsSync5, promises as fs23 } from "fs";
23135
- import { fileURLToPath as fileURLToPath3 } from "url";
23136
- init_dataHome();
23137
-
23138
- // ../../lib/agents/shared/runLog.ts
23139
- import { createHash as createHash3 } from "crypto";
23140
- import { promises as fs22 } from "fs";
23141
- import path28 from "path";
23142
-
23143
- // ../../lib/agents/shared/paths.ts
23144
- import os6 from "os";
23145
- import path27 from "path";
23146
- function polymathHome() {
23147
- return process.env.POLYMATH_HOME || path27.join(os6.homedir(), ".polymath-society");
23148
- }
23149
- function agentDir(agent) {
23150
- return path27.join(polymathHome(), agent);
23151
- }
23383
+ // ../../lib/agents/coding/benchmarks.ts
23384
+ var BEST = DEFAULT_CALIBRATION.codingBenchmarks;
23152
23385
 
23153
- // ../../lib/agents/shared/runLog.ts
23154
- function runRefPath() {
23155
- return path28.join(agentDir("report"), "latest.run.json");
23156
- }
23157
- function sha256Hex(s) {
23158
- return createHash3("sha256").update(s, "utf8").digest("hex");
23386
+ // ../../lib/agents/coding/profile.ts
23387
+ var ROOT2 = process.cwd();
23388
+ var CODING_DIR2 = process.env.POLYMATH_DATA_DIR ? path30.join(process.env.POLYMATH_DATA_DIR, "coding") : path30.join(ROOT2, ".data", "coding");
23389
+ var UMETA = /* @__PURE__ */ new Map();
23390
+ async function userMeta(sessionId, file2) {
23391
+ const hit = UMETA.get(sessionId);
23392
+ if (hit) return hit;
23393
+ const msgs = await extractUserMessages(file2).catch(() => []);
23394
+ const meta = msgs.map((m) => ({ t: m.t, words: typedWords(m.text, m.gapMs), key: m.uuid ?? `${m.t}|${m.text}` }));
23395
+ UMETA.set(sessionId, meta);
23396
+ return meta;
23159
23397
  }
23160
- async function fileSha(filePath) {
23161
- try {
23162
- return sha256Hex(await fs22.readFile(filePath, "utf-8"));
23163
- } catch {
23164
- return null;
23165
- }
23398
+ var GRADES2 = path30.join(CODING_DIR2, "grades");
23399
+ async function readJson2(p, fallback) {
23400
+ return fs26.readFile(p, "utf8").then((s) => JSON.parse(s)).catch(() => fallback);
23166
23401
  }
23167
- var RPC_TIMEOUT_MS = 15e3;
23168
- var MAX_CONSECUTIVE_FAILURES = 3;
23169
- function withTimeout(p) {
23170
- return Promise.race([
23171
- p,
23172
- new Promise((_, rej) => setTimeout(() => rej(new Error("runlog timeout")), RPC_TIMEOUT_MS).unref?.())
23173
- ]);
23402
+ function cadenceScore(fraction, multiRatio) {
23403
+ let s;
23404
+ if (fraction >= 0.85) s = 10;
23405
+ else if (fraction >= 0.6) s = 9;
23406
+ else if (fraction >= 0.45) s = 8;
23407
+ else if (fraction >= 0.3) s = 7;
23408
+ else if (fraction >= 0.2) s = 6;
23409
+ else if (fraction >= 0.12) s = 5;
23410
+ else if (fraction >= 0.06) s = 4;
23411
+ else s = 3;
23412
+ if (s >= 10 && multiRatio >= 0.3) s = 11;
23413
+ return s;
23174
23414
  }
23175
- async function rpc(url, key, fn, args) {
23176
- const res = await fetch(`${url.replace(/\/$/, "")}/rest/v1/rpc/${fn}`, {
23177
- method: "POST",
23178
- headers: { "content-type": "application/json", apikey: key, authorization: `Bearer ${key}` },
23179
- body: JSON.stringify(args)
23180
- });
23181
- if (!res.ok) throw new Error(`${fn} \u2192 HTTP ${res.status}`);
23182
- const text2 = await res.text();
23183
- return text2 ? JSON.parse(text2) : null;
23415
+ function distOf3(takes) {
23416
+ const vals = takes.map((t) => t.score ?? t.best).filter((v) => v != null);
23417
+ const n = vals.length;
23418
+ if (!n) return { n: 0, observed: 0, mean: null, median: null, hist: [] };
23419
+ const observed = takes.filter((t) => t.score != null).length;
23420
+ const mean2 = Math.round(vals.reduce((a, b) => a + b, 0) / n * 100) / 100;
23421
+ const sorted = [...vals].sort((a, b) => a - b);
23422
+ const median2 = n % 2 ? sorted[(n - 1) / 2] : (sorted[n / 2 - 1] + sorted[n / 2]) / 2;
23423
+ const h = /* @__PURE__ */ new Map();
23424
+ for (const v of vals) h.set(Math.round(v), (h.get(Math.round(v)) ?? 0) + 1);
23425
+ const hist = [...h.keys()].sort((a, b) => b - a).map((level) => ({ level, count: h.get(level) }));
23426
+ return { n, observed, mean: mean2, median: median2, hist };
23184
23427
  }
23185
- async function writeRef(refPath, ref) {
23428
+ async function compileCodingProfile() {
23429
+ const allRecords = await readJson2(path30.join(CODING_DIR2, "sessions.json"), []);
23430
+ const dupIds = new Set(allRecords.filter((s) => s.duplicateOf).map((s) => s.sessionId));
23431
+ const sessions = allRecords.filter((s) => !s.duplicateOf);
23432
+ const conc = await readJson2(path30.join(CODING_DIR2, "concurrency.json"), null);
23433
+ const renames = await readJson2(path30.join(CODING_DIR2, "renames.json"), []);
23434
+ const byId = new Map(sessions.map((s) => [s.sessionId, s]));
23435
+ let gradeFiles = [];
23186
23436
  try {
23187
- await fs22.mkdir(path28.dirname(refPath), { recursive: true });
23188
- await fs22.writeFile(refPath, JSON.stringify(ref, null, 2), "utf-8");
23437
+ gradeFiles = (await fs26.readdir(GRADES2)).filter((f) => f.endsWith(".json"));
23189
23438
  } catch {
23190
23439
  }
23191
- }
23192
- var LiveRunLog = class {
23193
- constructor(url, key, sessionId, token, nonce, opts) {
23194
- this.url = url;
23195
- this.key = key;
23196
- this.token = token;
23197
- this.nonce = nonce;
23198
- this.opts = opts;
23199
- this.sessionId = sessionId;
23440
+ const grades = [];
23441
+ for (const f of gradeFiles) {
23442
+ const g = await readJson2(path30.join(GRADES2, f), null);
23443
+ if (g && byId.has(g.sessionId)) grades.push(g);
23200
23444
  }
23201
- sessionId;
23202
- seq = 0;
23203
- chain = Promise.resolve();
23204
- failures = 0;
23205
- dead = false;
23206
- finished = false;
23207
- post(fn) {
23208
- if (this.dead) return;
23209
- this.chain = this.chain.then(async () => {
23210
- if (this.dead) return;
23211
- try {
23212
- await withTimeout(fn());
23213
- this.failures = 0;
23214
- } catch {
23215
- if (++this.failures >= MAX_CONSECUTIVE_FAILURES) this.dead = true;
23216
- }
23217
- });
23445
+ const takesByCriterion = /* @__PURE__ */ new Map();
23446
+ for (const g of grades) {
23447
+ for (const c of g.criteria) {
23448
+ const t = {
23449
+ sessionId: g.sessionId,
23450
+ title: g.title || byId.get(g.sessionId)?.title || g.sessionId,
23451
+ date: (g.date || "").slice(0, 10),
23452
+ score: c.score,
23453
+ best: c.bestEstimate,
23454
+ instance: c.instance,
23455
+ why: c.why,
23456
+ quotes: c.quotes,
23457
+ confidence: c.confidence
23458
+ };
23459
+ if (c.score == null && c.bestEstimate == null) continue;
23460
+ (takesByCriterion.get(c.key) ?? takesByCriterion.set(c.key, []).get(c.key)).push(t);
23461
+ }
23218
23462
  }
23219
- event(kind, payload = {}) {
23220
- if (this.dead || this.finished) return;
23221
- const seq = ++this.seq;
23222
- const clientAt = (/* @__PURE__ */ new Date()).toISOString();
23223
- this.post(async () => {
23224
- await rpc(this.url, this.key, "append_analysis_event", {
23225
- p_session_id: this.sessionId,
23226
- p_token: this.token,
23227
- p_seq: seq,
23228
- p_kind: kind,
23229
- p_payload: payload,
23230
- p_client_at: clientAt
23231
- });
23232
- });
23463
+ const criteria = CODING_CRITERIA.map((c) => {
23464
+ const takes = (takesByCriterion.get(c.key) ?? []).sort((a, b) => (b.score ?? b.best ?? 0) - (a.score ?? a.best ?? 0));
23465
+ return { key: c.key, label: c.label, graded: c.graded, definition: c.definition, dist: distOf3(takes), takes };
23466
+ });
23467
+ const tz = conc?.tz || "America/Los_Angeles";
23468
+ const localDate2 = (iso) => iso ? new Date(Date.parse(iso)).toLocaleDateString("en-CA", { timeZone: tz }) : "";
23469
+ let outcomeCadence = null;
23470
+ {
23471
+ const activeDates = new Set(sessions.map((s) => localDate2(s.start)).filter(Boolean));
23472
+ const meaningfulPerDay = /* @__PURE__ */ new Map();
23473
+ for (const g of grades) {
23474
+ const date = localDate2(byId.get(g.sessionId)?.start || g.date || "");
23475
+ if (!date) continue;
23476
+ const out = g.criteria.find((c) => c.key === "outcomes")?.score ?? null;
23477
+ const meta = g.criteria.find((c) => c.key === "metacognition")?.score ?? null;
23478
+ if (out != null && out >= 6 || meta != null && meta >= 8) meaningfulPerDay.set(date, (meaningfulPerDay.get(date) ?? 0) + 1);
23479
+ }
23480
+ const activeDays = activeDates.size;
23481
+ const meaningfulDays = meaningfulPerDay.size;
23482
+ const multiMeaningfulDays = [...meaningfulPerDay.values()].filter((n) => n >= 2).length;
23483
+ if (activeDays > 0) {
23484
+ const dates2 = [...activeDates].sort();
23485
+ const spanDays = Math.max(1, (Date.parse(dates2[dates2.length - 1]) - Date.parse(dates2[0])) / 864e5 + 1);
23486
+ const fraction = meaningfulDays / activeDays;
23487
+ outcomeCadence = {
23488
+ activeDays,
23489
+ meaningfulDays,
23490
+ multiMeaningfulDays,
23491
+ fraction: Math.round(fraction * 100) / 100,
23492
+ perWeek: Math.round(meaningfulDays / (spanDays / 7) * 10) / 10,
23493
+ score: cadenceScore(fraction, meaningfulDays ? multiMeaningfulDays / meaningfulDays : 0)
23494
+ };
23495
+ }
23233
23496
  }
23234
- async finish() {
23235
- if (this.finished) return;
23236
- this.finished = true;
23237
- const legacy = this.opts.artifacts === void 0;
23238
- const list = legacy ? [path28.join(agentDir("report"), "latest.json")] : typeof this.opts.artifacts === "function" ? await this.opts.artifacts().catch(() => []) : this.opts.artifacts;
23239
- const refPath = this.opts.refPath ?? runRefPath();
23240
- const shas = {};
23241
- const ordered = [];
23242
- let firstRaw = null;
23243
- for (const p of list) {
23244
- let raw;
23245
- try {
23246
- raw = await fs22.readFile(p, "utf-8");
23247
- } catch {
23248
- continue;
23249
- }
23250
- if (firstRaw === null) firstRaw = raw;
23251
- const sha = sha256Hex(raw);
23252
- shas[path28.relative(path28.dirname(refPath), p).split(path28.sep).join("/")] = sha;
23253
- ordered.push(sha);
23497
+ const perDayMeta = new Map((conc?.perDay ?? []).map((d) => [d.date, d]));
23498
+ const gradeById = new Map(grades.map((g) => [g.sessionId, g]));
23499
+ const dayMap = /* @__PURE__ */ new Map();
23500
+ for (const s of sessions) {
23501
+ const date = localDate2(s.start);
23502
+ if (!date) continue;
23503
+ let day = dayMap.get(date);
23504
+ if (!day) {
23505
+ const m = perDayMeta.get(date);
23506
+ day = { date, peakConcurrency: m?.peakConcurrency ?? 1, sessionsStarted: m?.sessionsStarted ?? 0, activeMin: m?.activeMin ?? 0, sessions: [] };
23507
+ dayMap.set(date, day);
23254
23508
  }
23255
- this.post(async () => {
23256
- if (ordered.length === 0) throw new Error("no artifacts to close against");
23257
- const commitment = legacy ? sha256Hex(this.nonce + firstRaw) : sha256Hex(this.nonce + ordered.join(""));
23258
- await rpc(this.url, this.key, "close_analysis_session", {
23259
- p_session_id: this.sessionId,
23260
- p_token: this.token,
23261
- p_commitment: commitment
23262
- });
23263
- });
23264
- await this.chain.catch(() => {
23509
+ const g = gradeById.get(s.sessionId);
23510
+ const findings = {};
23511
+ if (g) {
23512
+ for (const c of g.criteria) if (c.instance && (c.score != null || c.bestEstimate != null)) findings[c.key] = { score: c.score ?? c.bestEstimate, instance: c.instance, why: c.why || "", quotes: c.quotes || [] };
23513
+ }
23514
+ day.sessions.push({ sessionId: s.sessionId, title: s.title, gradable: !!g, findings });
23515
+ }
23516
+ const timeline = [...dayMap.values()].sort((a, b) => b.date.localeCompare(a.date));
23517
+ const levelHist = conc?.levelHistogramMin ?? {};
23518
+ const sumFrom = (min) => Object.entries(levelHist).filter(([k]) => Number(k) >= min).reduce((a, [, v]) => a + v, 0);
23519
+ const topWindows = (conc?.segments ?? []).slice().sort((a, b) => b.level - a.level || b.minutes - a.minutes).slice(0, 12).map((s) => ({ start: s.start, end: s.end, minutes: s.minutes, level: s.level, titles: [...new Set(s.sessions.map((x) => x.title))] }));
23520
+ const parallelism = {
23521
+ maxConcurrency: conc?.maxConcurrency ?? 0,
23522
+ levelHistogramMin: levelHist,
23523
+ minutesAt2plus: Math.round(sumFrom(2)),
23524
+ minutesAt6plus: Math.round(sumFrom(6)),
23525
+ topWindows,
23526
+ queueOps: sessions.reduce((a, s) => a + s.queueOps, 0),
23527
+ renames,
23528
+ renamedSessions: sessions.filter((s) => s.renamed).length,
23529
+ tz: conc?.tz ?? "",
23530
+ idleGapMin: conc?.idleGapMin ?? 5
23531
+ };
23532
+ const dates = sessions.map((s) => s.start).filter(Boolean).sort();
23533
+ const models = /* @__PURE__ */ new Map();
23534
+ for (const s of sessions) for (const [m, n] of Object.entries(s.models)) models.set(m, (models.get(m) ?? 0) + n);
23535
+ const topDays = (conc?.perDay ?? []).slice().sort((a, b) => b.activeMin - a.activeMin).slice(0, 12).map((d) => ({ date: d.date, activeMin: d.activeMin, sessionsStarted: d.sessionsStarted, peakConcurrency: d.peakConcurrency, firstStart: d.firstStart, lastEnd: d.lastEnd, spanMin: d.spanMin }));
23536
+ const lateNight = (conc?.perDay ?? []).filter((d) => {
23537
+ const h = Number(d.firstStart.slice(0, 2));
23538
+ const e = Number(d.lastEnd.slice(0, 2));
23539
+ return e >= 22 || e < 5 || h < 5;
23540
+ }).length;
23541
+ const throughput = {
23542
+ sessions: sessions.length,
23543
+ activeHours: Math.round(sessions.reduce((a, s) => a + s.activeMin, 0) / 60 * 10) / 10,
23544
+ dateRange: { from: (dates[0] || "").slice(0, 10), to: (dates[dates.length - 1] || "").slice(0, 10) },
23545
+ topDays,
23546
+ toolCalls: sessions.reduce((a, s) => a + s.toolCalls, 0),
23547
+ subagents: sessions.reduce((a, s) => a + s.subagentSpawns, 0),
23548
+ models: Object.fromEntries([...models.entries()].sort((a, b) => b[1] - a[1])),
23549
+ lateNightSessions: lateNight
23550
+ };
23551
+ const agglomeration = await readJson2(path30.join(CODING_DIR2, "agglomerate.json"), null);
23552
+ const dayDigest = await readJson2(path30.join(CODING_DIR2, "day-digest.json"), null);
23553
+ if (dayDigest?.days) dayDigest.days = dayDigest.days.map((day) => {
23554
+ const convs = day.conversations.filter((c) => byId.has(c.sessionId));
23555
+ return { ...day, conversations: convs, conversationsTouched: convs.length, totalMessages: convs.reduce((a, c) => a + c.messageCount, 0) };
23556
+ }).filter((day) => day.conversations.length > 0);
23557
+ const dayChart = await readJson2(path30.join(CODING_DIR2, "day-chart.json"), []);
23558
+ const intervalsBy = /* @__PURE__ */ new Map();
23559
+ const titleBy = /* @__PURE__ */ new Map();
23560
+ const fileById = new Map(sessions.map((s) => [s.sessionId, s.file]));
23561
+ for (const day of dayChart) for (const c of day.conversations) {
23562
+ const arr = intervalsBy.get(c.sessionId) ?? [];
23563
+ arr.push(...c.intervals);
23564
+ intervalsBy.set(c.sessionId, arr);
23565
+ titleBy.set(c.sessionId, c.title);
23566
+ }
23567
+ const listOverlapMs = (A, B) => {
23568
+ let ms2 = 0;
23569
+ for (const [a0, a1] of A) for (const [b0, b1] of B) {
23570
+ const lo = Math.max(a0, b0), hi = Math.min(a1, b1);
23571
+ if (hi > lo) ms2 += hi - lo;
23572
+ }
23573
+ return ms2;
23574
+ };
23575
+ const walkthroughs = {};
23576
+ const wdir = path30.join(CODING_DIR2, "walkthroughs");
23577
+ for (const f of await fs26.readdir(wdir).catch(() => [])) {
23578
+ if (!f.endsWith(".json")) continue;
23579
+ const w = await readWalkthrough(wdir, f.replace(".json", ""));
23580
+ if (!w || !byId.has(w.sessionId)) continue;
23581
+ const own = intervalsBy.get(w.sessionId) ?? [];
23582
+ const ownTitle = titleBy.get(w.sessionId) ?? w.title;
23583
+ const um = await userMeta(w.sessionId, fileById.get(w.sessionId) ?? "");
23584
+ const sessionEnd = own.length ? Math.max(...own.map((iv) => iv[1])) : w.phases[w.phases.length - 1]?.fromMs ?? 0;
23585
+ const phases = w.phases.map((p, i) => {
23586
+ const w0 = p.fromMs;
23587
+ const w1 = i + 1 < w.phases.length ? w.phases[i + 1].fromMs : sessionEnd + 1;
23588
+ const inPhase = um.filter((m) => m.t >= w0 && m.t < w1);
23589
+ const userPrompts = inPhase.length;
23590
+ const words = inPhase.reduce((s, m) => s + m.words, 0);
23591
+ const wordsPerMsg = userPrompts ? Math.round(words / userPrompts) : 0;
23592
+ const ownInWin = own.map(([a, b]) => [Math.max(a, w0), Math.min(b, w1)]).filter(([a, b]) => b > a);
23593
+ const durationMin = Math.round(ownInWin.reduce((s, [a, b]) => s + (b - a), 0) / 6e4);
23594
+ const byTitle = /* @__PURE__ */ new Map();
23595
+ for (const [sid, ivs] of intervalsBy) {
23596
+ if (sid === w.sessionId) continue;
23597
+ const t = titleBy.get(sid) ?? "(untitled)";
23598
+ if (t === ownTitle) continue;
23599
+ const ms2 = listOverlapMs(ownInWin, ivs);
23600
+ if (ms2 >= 6e4) byTitle.set(t, (byTitle.get(t) ?? 0) + ms2);
23601
+ }
23602
+ const parallel = [...byTitle.entries()].map(([title, ms2]) => ({ title, overlapMin: Math.round(ms2 / 6e4) })).sort((a, b) => b.overlapMin - a.overlapMin).slice(0, 6);
23603
+ return { what: p.what, durationMin, fromMs: w0, toMs: w1, userPrompts, words, wordsPerMsg, parallel };
23265
23604
  });
23266
- const ref = this.dead || ordered.length === 0 ? { sessionId: null } : {
23267
- sessionId: this.sessionId,
23268
- artifacts: shas,
23269
- ...legacy ? { reportSha256: ordered[0] } : {},
23270
- closedAt: (/* @__PURE__ */ new Date()).toISOString()
23271
- };
23272
- await writeRef(refPath, ref);
23605
+ walkthroughs[w.sessionId] = { phases, totalActiveMin: w.totalActiveMin, userTurns: w.userTurns };
23606
+ }
23607
+ const rubric2 = Object.fromEntries(
23608
+ CODING_CRITERIA.filter((c) => c.graded).map((c) => [c.key, { label: c.label, definition: c.definition, read: c.read, rungs: c.rungs ?? [] }])
23609
+ );
23610
+ await Promise.all(sessions.map((s) => userMeta(s.sessionId, s.file)));
23611
+ const wordsByDay = {};
23612
+ const seenMsg = /* @__PURE__ */ new Set();
23613
+ for (const s of sessions) for (const m of UMETA.get(s.sessionId) ?? []) {
23614
+ if (seenMsg.has(m.key)) continue;
23615
+ seenMsg.add(m.key);
23616
+ const d = new Date(m.t).toLocaleDateString("en-CA", { timeZone: tz });
23617
+ wordsByDay[d] = (wordsByDay[d] ?? 0) + m.words;
23273
23618
  }
23274
- };
23275
- function inertRunLog(refPath) {
23276
- return {
23277
- sessionId: null,
23278
- event() {
23279
- },
23280
- async finish() {
23281
- await writeRef(refPath, { sessionId: null });
23619
+ const dayThroughput = {};
23620
+ for (const [d, n] of Object.entries(wordsByDay)) dayThroughput[d] = throughputScore(n);
23621
+ const tCeiling = throughputCeiling(Object.values(wordsByDay));
23622
+ const criteriaMean = {};
23623
+ for (const c of criteria) criteriaMean[c.key] = { mean: c.dist.mean, n: c.dist.n };
23624
+ const flow = await readJson2(path30.join(CODING_DIR2, "flow.json"), null);
23625
+ const focus = await readJson2(path30.join(CODING_DIR2, "focus.json"), null);
23626
+ const expertiseMap = await readJson2(path30.join(CODING_DIR2, "expertise.json"), null);
23627
+ const frontierArsenal = await readJson2(path30.join(CODING_DIR2, "frontier.json"), null);
23628
+ const frontierDetail = await readJson2(path30.join(CODING_DIR2, "frontier-detail.json"), null);
23629
+ const coaching = await readJson2(path30.join(CODING_DIR2, "coaching.json"), null);
23630
+ const gap = await readJson2(path30.join(CODING_DIR2, "gap.json"), null);
23631
+ const aggregate = await readJson2(path30.join(CODING_DIR2, "aggregate.json"), null);
23632
+ const delegationRollup = await readJson2(path30.join(CODING_DIR2, "delegation-rollup.json"), null);
23633
+ const gapDist = await readJson2(path30.join(CODING_DIR2, "gap-dist.json"), null);
23634
+ const projects = await readJson2(path30.join(CODING_DIR2, "projects.json"), null);
23635
+ const workstyle = computeWorkstyle({
23636
+ dayChart,
23637
+ tz,
23638
+ idleGapMin: conc?.idleGapMin ?? 5,
23639
+ criteriaMean,
23640
+ outcomeCadence: outcomeCadence ? { perWeek: outcomeCadence.perWeek, fraction: outcomeCadence.fraction } : null,
23641
+ flow,
23642
+ signals: {
23643
+ maxConcurrency: parallelism.maxConcurrency,
23644
+ subagents: throughput.subagents,
23645
+ queueOps: parallelism.queueOps,
23646
+ mcpTools: new Set(sessions.flatMap((s) => s.mcpTools ?? [])).size,
23647
+ parallelHours: Math.round(parallelism.minutesAt2plus / 60 * 10) / 10
23282
23648
  }
23649
+ });
23650
+ const pctOf = (sc) => {
23651
+ if (sc == null) return null;
23652
+ const label = bandLabel(sc, DEFAULT_CALIBRATION);
23653
+ const m = /([\d.]+)\s*%/.exec(label);
23654
+ return m ? 100 - parseFloat(m[1]) : null;
23655
+ };
23656
+ const ceilOf = (key) => {
23657
+ const c = criteria.find((x) => x.key === key);
23658
+ const scores = (c?.takes ?? []).map((t) => t.score ?? t.best).filter((x) => x != null).sort((a, b) => b - a);
23659
+ return scores.length ? scores[Math.min(3, scores.length) - 1] : null;
23660
+ };
23661
+ const proud = (key, fallback) => {
23662
+ const t = (criteria.find((x) => x.key === key)?.takes ?? [])[0];
23663
+ if (!t?.instance) return fallback;
23664
+ let h = t.instance.split(/:\s|\s[—–]\s|\swith an?\s/)[0].trim().replace(/\s+/g, " ");
23665
+ h = h.replace(/^The user\b/, "You").replace(/\bThe user\b/g, "you").replace(/([.?!]['"’”)\]]*\s+)you\b/g, (_m, p) => p + "You");
23666
+ if (h.length > 150) h = h.slice(0, 148).replace(/\s+\S*$/, "") + "\u2026";
23667
+ return h;
23668
+ };
23669
+ const nTk = (key) => criteria.find((x) => x.key === key)?.takes.length ?? 0;
23670
+ const peakWords = Object.values(wordsByDay).length ? Math.max(...Object.values(wordsByDay)) : 0;
23671
+ const pHist = parallelism.levelHistogramMin || {};
23672
+ const soloMin = pHist["1"] ?? 0;
23673
+ const parMin = Object.entries(pHist).reduce((a, [k, v]) => Number(k) >= 2 ? a + v : a, 0);
23674
+ const soloPct = soloMin + parMin ? Math.round(soloMin / (soloMin + parMin) * 100) : null;
23675
+ const flowPctDay = aggregate?.flow?.flow?.pctOfWorkDay ?? null;
23676
+ const flowHrsDay = workstyle.flowHoursPerDay ? Math.round(workstyle.flowHoursPerDay * 10) / 10 : null;
23677
+ const focusScore = flowPctDay == null ? null : Math.max(1, Math.min(10, Math.round(2 + flowPctDay / BEST.flow.topPctOfDay * 7)));
23678
+ const out2 = ceilOf("outcomes");
23679
+ const unb = ceilOf("unblocking");
23680
+ const agency = out2 != null && unb != null ? Math.round((out2 + unb) / 2) : out2 ?? unb;
23681
+ const sRow = (label, score, gap2) => ({ label, score, percentile: pctOf(score), gap: gap2 });
23682
+ const tiers = DEFAULT_CALIBRATION.codingTiers;
23683
+ const phi = (z) => {
23684
+ const t = 1 / (1 + 0.2316419 * Math.abs(z));
23685
+ const d = 0.3989423 * Math.exp(-z * z / 2);
23686
+ let pr = d * t * (0.3193815 + t * (-0.3565638 + t * (1.781478 + t * (-1.821256 + t * 1.330274))));
23687
+ if (z > 0) pr = 1 - pr;
23688
+ return pr;
23283
23689
  };
23690
+ const lognPct = (x, c) => x == null || !c || x <= 0 ? null : Math.round(phi(Math.log(x / c.median) / c.sigma) * 1e3) / 10;
23691
+ const avgWords = aggregate?.throughput?.avgWordsPerDay ?? null;
23692
+ const pushPctl = lognPct(avgWords, tiers?.push);
23693
+ const focusPctl = lognPct(flowPctDay, tiers?.focus);
23694
+ const hoursAt = (min) => Object.entries(pHist).reduce((a, [k, v]) => Number(k) >= min ? a + v : a, 0) / 60;
23695
+ const orchPctl = hoursAt(5) >= 5 || hoursAt(3) >= 10 && parallelism.queueOps >= 1e3 ? 99.5 : hoursAt(3) >= 10 ? 99 : hoursAt(2) >= 0.1 * (soloMin + parMin) / 60 ? 97 : hoursAt(2) >= 2 ? 90 : 70;
23696
+ const stackUp = [
23697
+ sRow(
23698
+ "How hard you push",
23699
+ aggregate?.throughput?.score ?? tCeiling,
23700
+ `you peak at ~${peakWords.toLocaleString()} words of pure direction in a single day \u2014 the very top sustain ~${BEST.throughput.topAvgWordsPerDay.toLocaleString()} every day, week after week; the wildest single days on record push ~${BEST.throughput.topPeakWordsPerDay.toLocaleString()}`
23701
+ ),
23702
+ sRow(
23703
+ "How well you use AI",
23704
+ ceilOf("delegation"),
23705
+ soloPct != null ? `~${soloPct}% of your hours you drive a single agent (${Math.round(soloMin / 60)}h solo vs ${Math.round(parMin / 60)}h with 2+ live) \u2014 the Claude Code lead keeps 10\u201315 going at once, so this is the single biggest speed-up still on the table` : "you brief the AI sharply, but mostly drive one agent at a time \u2014 the top run 10\u201315 in parallel, a several-fold speed-up"
23706
+ ),
23707
+ sRow(
23708
+ "How well you focus",
23709
+ focusScore,
23710
+ flowHrsDay != null ? `only ~${flowHrsDay}h of your day is true deep flow \u2014 the best hold ~4h in one unbroken block; yours fragments across parallel sessions, so the gain is directing your attention at one thread for longer` : "your attention scatters across parallel sessions \u2014 directing it at one thread for longer is the unlock"
23711
+ ),
23712
+ // The four estimates LEAD with a concrete moment from their own sessions, then an
23713
+ // HONEST caveat — how many graded sessions back the read. No invented weakness, no
23714
+ // claim about what they "didn't" do (false specifics churn a real user); it's an estimate.
23715
+ sRow(
23716
+ "Agency",
23717
+ agency,
23718
+ `${proud("outcomes", "you ship working systems and unblock yourself")} \u2014 one of ${nTk("outcomes")} sessions behind this read; a strong, consistent signal, still an estimate from your logs`
23719
+ ),
23720
+ // Judgement/Taste use the SAME numbers their ability cards prove (aggregate
23721
+ // peak-with-consistency over near-peak instances) — a chip saying "top 1%"
23722
+ // above a card proving 10/Top 0.1% with ten receipts reads as a bug.
23723
+ sRow(
23724
+ "Judgement",
23725
+ aggregate?.ability?.abstraction?.score ?? ceilOf("generative"),
23726
+ `${proud("generative", "you make sharp, non-obvious calls on what actually matters")} \u2014 one of ${nTk("generative")} sessions we've graded for this; clear so far, not yet a final verdict`
23727
+ ),
23728
+ sRow(
23729
+ "Taste",
23730
+ aggregate?.ability?.taste?.score ?? ceilOf("taste"),
23731
+ `${proud("taste", "you hold a high, opinionated quality bar")} \u2014 one of ${nTk("taste")} sessions behind this read; a real signal, still an estimate`
23732
+ )
23733
+ // Expertise: NO chip — the scored criterion is deprecated; the real judge is
23734
+ // the qualitative domains map (expertise-floor), and a chip must never say
23735
+ // "top X%" while that section shows no qualifying domains.
23736
+ ];
23737
+ for (const r of stackUp) {
23738
+ if (r.label === "How hard you push" && pushPctl != null) {
23739
+ r.percentile = pushPctl;
23740
+ r.metric = avgWords;
23741
+ r.curve = "push";
23742
+ }
23743
+ if (r.label === "How well you focus" && focusPctl != null) {
23744
+ r.percentile = focusPctl;
23745
+ r.metric = flowPctDay;
23746
+ r.curve = "focus";
23747
+ }
23748
+ if (r.label === "How well you use AI") r.percentile = orchPctl;
23749
+ }
23750
+ return { generatedAt: (/* @__PURE__ */ new Date()).toISOString(), gradedSessions: grades.length, agglomeration, outcomeCadence, dayDigest, dayChart, timeline, walkthroughs, rubric: rubric2, wordsByDay, dayThroughput, throughputCeiling: tCeiling, stackUp, criteria, parallelism, throughput, workstyle, flow, focus, expertiseMap, frontierArsenal, frontierDetail, coaching, gap, aggregate, delegationRollup, gapDist, projects };
23284
23751
  }
23285
- async function startRunLog(clientInfo = {}, opts = {}) {
23286
- const url = opts.supabaseUrl ?? process.env.NEXT_PUBLIC_SUPABASE_URL;
23287
- const key = opts.supabaseAnonKey ?? process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
23288
- const refPath = opts.refPath ?? runRefPath();
23289
- if (!url || !key) return inertRunLog(refPath);
23752
+
23753
+ // ../../lib/agents/coding/publicPage.ts
23754
+ var readJson3 = async (f, d) => fs27.readFile(f, "utf8").then((t) => JSON.parse(t)).catch(() => d);
23755
+ var thirdPerson = (s) => s;
23756
+ function weeklyCadence(wordsByDay) {
23757
+ const days = Object.keys(wordsByDay).sort();
23758
+ const weeks = /* @__PURE__ */ new Map();
23759
+ for (const d of days) {
23760
+ const dt = /* @__PURE__ */ new Date(d + "T00:00:00Z");
23761
+ const jan1 = new Date(Date.UTC(dt.getUTCFullYear(), 0, 1));
23762
+ const wk = `${dt.getUTCFullYear()}-W${String(Math.ceil(((+dt - +jan1) / 864e5 + jan1.getUTCDay() + 1) / 7)).padStart(2, "0")}`;
23763
+ weeks.set(wk, (weeks.get(wk) ?? 0) + 1);
23764
+ }
23765
+ const full = [...weeks.values()].slice(1, -1);
23766
+ const sevenStreak = (() => {
23767
+ let best = 0, cur = 0;
23768
+ for (const n of full) {
23769
+ cur = n >= 7 ? cur + 1 : 0;
23770
+ best = Math.max(best, cur);
23771
+ }
23772
+ return best;
23773
+ })();
23774
+ const recent = full.slice(-6);
23775
+ const recentAvg = recent.length ? Math.round(recent.reduce((a, b) => a + b, 0) / recent.length * 10) / 10 : 0;
23776
+ const first = full.slice(0, 3), firstAvg = first.length ? Math.round(first.reduce((a, b) => a + b, 0) / first.length * 10) / 10 : 0;
23777
+ return { recentAvg, firstAvg, sevenStreak };
23778
+ }
23779
+ function rhythmFacts(wordsByDay, workstyle, flow) {
23780
+ const days = Object.keys(wordsByDay).sort();
23781
+ const { recentAvg, firstAvg, sevenStreak } = weeklyCadence(wordsByDay);
23782
+ const facts = [];
23783
+ facts.push(recentAvg >= 6.5 ? { big: "7 days a week", rest: sevenStreak >= 2 ? `${sevenStreak} consecutive weeks without a single day off` : "in recent weeks" } : { big: `${recentAvg} days a week`, rest: "averaged over the recent weeks" });
23784
+ if (flow?.workDayHours) facts.push({ big: `${flow.workDayHours}-hour`, rest: "working days, typically" });
23785
+ if (firstAvg && recentAvg > firstAvg + 1.5) facts.push({ big: `${Math.round(firstAvg)} \u2192 ${Math.round(recentAvg)} days/week`, rest: "the ramp from the first weeks to now" });
23786
+ if (workstyle?.activeHours) facts.push({ big: `${Math.round(workstyle.activeHours)} hours`, rest: `hands-on across ${workstyle.daysObserved ?? days.length} observed days${flow?.flowHoursPerDay ? `, ${flow.flowHoursPerDay}h of it in deep flow daily` : ""}` });
23787
+ return facts.slice(0, 4);
23788
+ }
23789
+ function detailedReportCards(profile) {
23790
+ const cards = [];
23791
+ const t = profile?.throughput;
23792
+ if (t?.sessions) {
23793
+ cards.push({ section: "Throughput", stats: [
23794
+ { big: t.sessions.toLocaleString(), lab: "sessions" },
23795
+ { big: `${Math.round(t.activeHours ?? 0)}h`, lab: "active time" },
23796
+ { big: (t.toolCalls ?? 0).toLocaleString(), lab: `tool calls (${(t.subagents ?? 0).toLocaleString()} subagents)` },
23797
+ { big: String(t.lateNightSessions ?? 0), lab: "late-night days (ends 22:00\u201305:00)" }
23798
+ ] });
23799
+ }
23800
+ const ws = profile?.workstyle, af = profile?.aggregate?.flow;
23801
+ const stats = [];
23802
+ if (af?.workWindow?.typicalStart) stats.push({ big: `${af.workWindow.typicalStart}\u2013${af.workWindow.typicalEnd}`, lab: "work window, typical day" });
23803
+ if (af?.flow?.pctOfWorkDay != null) stats.push({ big: `${Math.round(af.flow.pctOfWorkDay * 100)}%`, lab: `in flow, of the work day (${af.flow.flowHoursPerDay}h/day)` });
23804
+ if (af?.peakWindow) stats.push({ big: String(af.peakWindow), lab: "peak flow" });
23805
+ if (af?.parallelism?.maxConcurrent) stats.push({ big: `\xD7${af.parallelism.maxConcurrent}`, lab: "max parallel" });
23806
+ if (ws?.blockCount) stats.push({ big: `${Math.round((ws.flowHoursTotal ?? 0) * 60 / ws.blockCount)} min`, lab: `mean unbroken stretch (${ws.blockCount} runs, ${ws.deepBlocks} \u2265${ws.flowThresholdMin ?? 30}m)` });
23807
+ if (ws?.longestBlockMin) stats.push({ big: `${ws.longestBlockMin} min`, lab: "longest flow run, unbroken rapid exchange" });
23808
+ const focusDays = profile?.focus?.days ?? [];
23809
+ const rngMin = (rngs) => (rngs ?? []).reduce((a, [x, y]) => a + (y - x), 0);
23810
+ const totalAct = focusDays.reduce((a, d) => a + rngMin(d.ranges?.act ?? []), 0);
23811
+ const totalBrk = focusDays.reduce((a, d) => a + rngMin(d.ranges?.brk ?? []), 0);
23812
+ if (totalAct + totalBrk > 0) stats.push({ big: `${Math.round(100 * totalBrk / (totalAct + totalBrk))}%`, lab: "of the working span spent in breaks" });
23813
+ if (stats.length) cards.push({ section: "Flow & rhythm", stats, note: af?.insight ? String(af.insight) : void 0 });
23814
+ return cards;
23815
+ }
23816
+ async function buildSkeleton(codingDir, stackUp) {
23817
+ const agg = await readJson3(path31.join(codingDir, "aggregate.json"), {});
23818
+ const coaching = await readJson3(path31.join(codingDir, "coaching.json"), {});
23819
+ const agglom = await readJson3(path31.join(codingDir, "agglomerate.json"), {});
23820
+ const projectsDoc = await readJson3(path31.join(codingDir, "projects.json"), {});
23821
+ const focus = await readJson3(path31.join(codingDir, "focus.json"), {});
23822
+ const sessions = await readJson3(path31.join(codingDir, "sessions.json"), []);
23823
+ const profile = await compileCodingProfile().catch(() => null);
23824
+ const wordsByDay = agg?.throughput?.wordsByDay ?? {};
23825
+ const wbd = Object.keys(wordsByDay).length ? wordsByDay : Object.fromEntries((focus?.days ?? []).map((d) => [d.date, d.activeMin ?? 1]));
23826
+ const pct2 = (label) => {
23827
+ const r = (stackUp ?? []).find((x) => x.label.toLowerCase().includes(label));
23828
+ return r?.percentile != null ? Math.round((100 - r.percentile) * 100) / 100 : null;
23829
+ };
23830
+ const gradedOn = (key) => (agglom?.criteria ?? []).length ? 0 : 0;
23831
+ const interactive = sessions.filter((s) => s.klass === "interactive" && !s.duplicateOf);
23832
+ const flow = agg?.flow?.flow ?? {};
23833
+ const thr = agg?.throughput ?? {};
23834
+ const par = { max: 0, hours2plus: 0, queueOps: 0 };
23290
23835
  try {
23291
- const data = await withTimeout(
23292
- rpc(url, key, "begin_analysis_session", {
23293
- p_client_info: { platform: process.platform, ...clientInfo }
23294
- })
23295
- );
23296
- const d = data ?? {};
23297
- if (!d.session_id || !d.token || !d.nonce) return inertRunLog(refPath);
23298
- return new LiveRunLog(url, key, d.session_id, d.token, d.nonce, opts);
23836
+ const conc = await readJson3(path31.join(codingDir, "concurrency.json"), {});
23837
+ par.max = conc?.maxConcurrency ?? 0;
23838
+ par.hours2plus = Math.round((conc?.minutesAt2plus ?? 0) / 60);
23839
+ par.queueOps = conc?.queueOps ?? 0;
23299
23840
  } catch {
23300
- return inertRunLog(refPath);
23301
23841
  }
23302
- }
23303
-
23304
- // src/pipeline.ts
23305
- var MODULE_DIR2 = path29.dirname(fileURLToPath3(import.meta.url));
23306
- function stages(o) {
23307
- const model = o.model ?? "sonnet";
23308
- const conc = String(o.conc ?? 8);
23309
- const buildArgs = [];
23310
- if (o.codex === false) buildArgs.push("--no-codex");
23311
- if (o.idleGapMin != null) buildArgs.push("--idle", String(o.idleGapMin));
23312
- const gradeArgs = ["--all", "--model", model, "--conc", conc];
23313
- if (o.regrade) gradeArgs.push("--regrade");
23314
- return [
23315
- // ---- deterministic foundation (fast, free) ----
23316
- { script: "coding-build.mts", label: "Scrape + classify your sessions", llm: false, args: buildArgs, out: "coding/sessions.json" },
23317
- // ---- deterministic metrics: all read ONLY sessions.json, disjoint outputs ----
23318
- { script: "coding-flow.mts", label: "Flow-state slots", llm: false, args: [], out: "coding/flow.json", batch: "metrics" },
23319
- { script: "coding-focus.mts", label: "Focus map + breaks (deterministic)", llm: false, args: ["--skip-llm"], out: "coding/focus.json", batch: "metrics" },
23320
- { script: "coding-gap-dist.mts", label: "Inter-prompt gap distribution", llm: false, args: [], out: "coding/gap-dist.json", batch: "metrics" },
23321
- { script: "coding-frontier.mts", label: "Frontier tech arsenal", llm: false, args: [], out: "coding/frontier.json", batch: "metrics" },
23322
- { script: "coding-projects.mts", label: "Projects + contributions", llm: false, args: [], out: "coding/projects.json", batch: "metrics" },
23323
- // ---- THE HEAVY BATCH — grading + everything that needs ONLY sessions.json.
23324
- // Digests, walkthroughs, frontier detail, and delegation never read grades,
23325
- // so they run WHILE grading runs (grading is the wall-clock giant; these
23326
- // finish inside its shadow). Budget: grade 8 + digest 3 + walkthrough 3 +
23327
- // two single-call stages ≈ 16 peak subprocesses (measured-safe envelope).
23328
- { script: "coding-grade.mts", label: "AI-grade every substantial session", llm: true, args: gradeArgs, batch: "heavy" },
23329
- { script: "coding-day-digest.mts", label: "Day-by-day digests", llm: true, args: ["--model", model, "--conc", "3"], out: "coding/day-digest.json", batch: "heavy" },
23330
- { script: "coding-walkthrough.mts", label: "Per-session walkthroughs", llm: true, args: ["--model", model, "--conc", "3"], batch: "heavy" },
23331
- { script: "coding-frontier-detail.mts", label: "What you're doing at the frontier", llm: true, args: [], out: "coding/frontier-detail.json", batch: "heavy" },
23332
- { script: "coding-delegation.mts", label: "Delegation patterns", llm: true, args: ["--model", model], out: "coding/delegation-rollup.json", batch: "heavy" },
23333
- // ---- corpus aggregate (reads grades; deterministic rollup) ----
23334
- { script: "coding-aggregate.mts", label: "Corpus aggregate \u2014 ability ceiling + flow", llm: false, args: [], out: "coding/aggregate.json" },
23335
- // ---- grade readers (grades/* is complete once aggregate ran) ----
23336
- { script: "coding-agglomerate.mts", label: "Agglomerated criteria + signature moves", llm: true, args: ["--model", model], out: "coding/agglomerate.json", batch: "grade-readers" },
23337
- { script: "coding-expertise.mts", label: "Domain-expertise map", llm: true, args: [], out: "coding/expertise.json", batch: "grade-readers" },
23338
- // ---- final synthesis (reads the finished aggregates + batch outputs) ----
23339
- { script: "coding-coaching.mts", label: "Coaching + feel-seen copy", llm: true, args: [], out: "coding/coaching.json", batch: "synthesis" },
23340
- { script: "coding-gap.mts", label: "Gap-to-close vs best practice", llm: true, args: [], out: "coding/gap.json", batch: "synthesis" },
23341
- // nutshell stays LAST + alone: it merges INTO aggregate.json while the two
23342
- // above read the compiled profile — racing them re-reads mid-write.
23343
- { script: "coding-nutshell.mts", label: "Big-picture nutshell", llm: true, args: [], out: "coding/aggregate.json" }
23344
- // merges bigPicture INTO aggregate.json
23842
+ const wk = weeklyCadence(wbd);
23843
+ const workWindow = agg?.flow?.workWindow;
23844
+ const axes = [
23845
+ { key: "judgement", label: "Judgement", topPct: pct2("judgement"), sub: "AI-graded on an anchored rubric", claim: "", read: "", numbers: [], moments: [] },
23846
+ { key: "agency", label: "Agency", topPct: pct2("agency"), sub: "full ship arcs, verified", claim: "", read: "", numbers: [], moments: [] },
23847
+ { key: "taste", label: "Taste", topPct: pct2("taste"), sub: "AI-graded on an anchored rubric", claim: "", read: "", numbers: [], moments: [] },
23848
+ { key: "push", label: "How hard they push", topPct: pct2("push"), sub: "counted, not graded", claim: "", read: "", numbers: [
23849
+ ...wk.recentAvg ? [{ big: wk.recentAvg >= 6.5 ? "7 days a week" : `${wk.recentAvg} days a week`, lab: "worked, averaged over recent weeks" }] : [],
23850
+ ...workWindow?.typicalStart ? [{ big: `${workWindow.typicalStart}\u2013${workWindow.typicalEnd}`, lab: "work window, typical day" }] : [],
23851
+ ...thr.avgWordsPerDay ? [{ big: String(Math.round(thr.avgWordsPerDay).toLocaleString()), lab: "typed/dictated words per day, averaged (~300 for the median active user)" }] : [],
23852
+ ...thr.substantialDays ? [{ big: `${thr.substantialDays}/${thr.totalCodingDays}`, lab: "coding days were substantial (3h+ span)" }] : []
23853
+ ], moments: [] },
23854
+ { key: "ai", label: "How they use AI", topPct: pct2("use ai"), sub: "orchestration, measured", claim: "", read: "", numbers: [
23855
+ ...par.max ? [{ big: String(par.max), lab: "agents at once, peak" }] : [],
23856
+ ...par.hours2plus ? [{ big: `${par.hours2plus}h`, lab: "working 2+ live agents" }] : [],
23857
+ ...par.queueOps ? [{ big: par.queueOps.toLocaleString(), lab: "instructions queued ahead" }] : []
23858
+ ], moments: [] },
23859
+ { key: "focus", label: "Focus", topPct: pct2("focus"), sub: "strict definition", claim: "", read: "", numbers: [
23860
+ ...flow.pctOfWorkDay != null ? [{ big: `${Math.round(flow.pctOfWorkDay * 100)}%`, lab: "of the work day in strict deep flow (gaps under 6 min)" }] : [],
23861
+ ...flow.flowHoursPerDay ? [{ big: `${flow.flowHoursPerDay}h`, lab: "deep flow per day" }] : [],
23862
+ ...flow.totalFlowHours ? [{ big: `${Math.round(flow.totalFlowHours)}h`, lab: "total flow across the period" }] : []
23863
+ ], moments: [] }
23345
23864
  ];
23865
+ const projects = (Array.isArray(projectsDoc?.projects) ? projectsDoc.projects : Array.isArray(projectsDoc) ? projectsDoc : []).filter((p) => (p.hours ?? 0) >= 1).slice(0, 6).map((p) => ({ name: String(p.project ?? p.name ?? ""), meta: `${p.days ?? "?"} days \xB7 ${Math.round(p.hours ?? 0)}h` }));
23866
+ const moreNumbers = detailedReportCards(profile);
23867
+ const page = {
23868
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
23869
+ verdict: thirdPerson(String(coaching?.whatYouAre?.line ?? "")),
23870
+ provenance: { sessions: interactive.length, days: Object.keys(wbd).length, graded: 0 },
23871
+ rhythm: { facts: rhythmFacts(wbd, profile?.workstyle ?? {}, flow) },
23872
+ missionArc: "",
23873
+ overall: "",
23874
+ axes,
23875
+ projects,
23876
+ moreNumbers,
23877
+ howToWork: [],
23878
+ nutshell: String(agg?.bigPicture ?? "")
23879
+ };
23880
+ const evidence = [
23881
+ `PLACEMENT VERDICT (rewrite to third person, keep the punch): ${coaching?.whatYouAre?.line ?? ""}
23882
+ EVIDENCE BEHIND IT: ${coaching?.whatYouAre?.evidence ?? ""}`,
23883
+ `OVERALL READ (compress to 2-4 sentences, keep the behavioral signature): ${String(agglom?.overall ?? "").slice(0, 2200)}`,
23884
+ `PER-CRITERION INSIGHTS:
23885
+ ${(agglom?.criteria ?? []).map((c) => `[${c.key}] ${c.headline} \u2014 ${String(c.insight ?? "").slice(0, 400)}`).join("\n")}`,
23886
+ `SIGNATURE MOVES (the moment pool \u2014 verify quotes at the source before using):
23887
+ ${(agglom?.signatureMoves ?? []).map((m) => `- ${m.what} \xB7 ${m.session} \xB7 quote: "${m.quote}"`).join("\n")}`,
23888
+ `FEEL-SEEN LINES (material, not to copy verbatim): ${JSON.stringify(coaching?.feelSeen ?? {})}`
23889
+ ].join("\n\n");
23890
+ return { page, evidence };
23891
+ }
23892
+ var SYSTEM4 = "You write the COPY for a public, hiring-manager-facing coding profile page. The skeleton (axes, numbers, percentiles) is already computed; you write the words: per-axis claims, reads, and dated concrete moments; the mission arc; the overall read; flow patterns; how-to-work-with bullets. REGISTER: third person throughout (the reader is a hiring manager, not the person). Claims are CLAIMS, not category names ('Kills the wrong metric before it gets built', never 'Strong judgement'). Every moment is dated, concrete, self-contained, and carries the person's VERBATIM words when a quote earns its place \u2014 you MUST verify every quote by finding it in the transcript (docs/<sessionId>.txt) before citing it; can't find it, don't use it. MOMENTS: every axis gets 3-4, and DIVERSE ones: different sessions, different projects, different weeks wherever the evidence allows \u2014 more distinct concrete verified moments is strictly better than fewer, but never pad with a weak restatement of a story already told on that axis. For graded axes pick the sharpest verified moments (the scoreboard ranks candidates). For counted axes (push/focus) turn the person's real peak DAYS into moments: what the day's number was and what they were building (day-digest.json tells you). The AGENCY axis must include one SELF-CONTAINED mission arc moment: what they took on, the insight that redirected it, what shipped \u2014 a stranger should get the whole story from that one entry. MISSION ARC (separate field): the same story at 2-3 sentences, self-contained, concrete. FLOW PATTERNS: from the data (focus.json day ranges, break clusters, day-digest), name what reliably precedes their longest flow runs (inFlow) and what reliably precedes breaks (outFlow) \u2014 one sentence each, evidence-grounded, no speculation. HOW TO WORK WITH THEM: 3-4 bullets derived from the measured behavioral signatures (delegation style, verification habits, standing-rule habit) \u2014 each a practical instruction to a future teammate, not praise. STYLE (hard rules): NO EM DASHES (\u2014) anywhere; use commas, periods, colons. Plain words, no jargon, no consultant-speak, no hedging. Never invent a number, date, quote, or outcome. Numbers you cite must come from the skeleton or the artifacts. Honest edges are stated plainly where the data shows them (the focus axis carries one when flow fragments). BE ECONOMICAL WITH TURNS: verify only the quotes you actually cite, batch several verifications into one Grep call (multiple patterns / one file read covers many quotes), never narrate what you are about to do, and reserve your last turns for emitting the final json block.";
23893
+ function copyPrompt(skeleton) {
23894
+ return `THE SKELETON (numbers + axes already computed, copy fields empty):
23895
+ \`\`\`json
23896
+ ${JSON.stringify(skeleton.page, null, 1)}
23897
+ \`\`\`
23898
+
23899
+ THE DISTILLED EVIDENCE:
23900
+ ${skeleton.evidence}
23901
+
23902
+ Write the copy. Output ONE fenced json block with EXACTLY these fields:
23903
+ \`\`\`json
23904
+ {
23905
+ "verdict": "third-person rewrite of the placement line",
23906
+ "overall": "2-4 sentences: how they actually work",
23907
+ "missionArc": "2-3 sentences, self-contained story",
23908
+ "inFlow": "what reliably precedes their longest flow runs",
23909
+ "outFlow": "what reliably precedes their breaks",
23910
+ "howToWork": ["3-4 bullets"],
23911
+ "axes": { "judgement": { "claim": "", "read": "", "moments": [ { "date": "YYYY-MM-DD or a range", "what": "", "quote": "verbatim, verified, omit if none earns it", "sessionId": "when known" } ], "edge": "optional honest footnote" }, "agency": {}, "taste": {}, "push": {}, "ai": {}, "focus": {} }
23346
23912
  }
23347
- function bundledPipelineDir() {
23348
- const d = path29.join(MODULE_DIR2, "pipeline");
23349
- return existsSync5(path29.join(d, "coding-build.js")) ? d : null;
23350
- }
23351
- function stageInvocation(repoRoot, scriptRel, args) {
23352
- const scriptAbs = path29.join(repoRoot, "scripts", scriptRel);
23353
- if (existsSync5(scriptAbs)) {
23354
- const local = path29.join(repoRoot, "node_modules", ".bin", "tsx");
23355
- if (existsSync5(local)) return { cmd: local, argv: [scriptAbs, ...args], cwd: repoRoot };
23356
- return { cmd: "npx", argv: ["tsx", scriptAbs, ...args], cwd: repoRoot };
23357
- }
23358
- const bundled = bundledPipelineDir();
23359
- if (bundled) {
23360
- const js = path29.join(bundled, scriptRel.replace(/\.mts$/, ".js"));
23361
- return { cmd: process.execPath, argv: [js, ...args], cwd: process.cwd() };
23362
- }
23363
- throw new Error(`pipeline stage ${scriptRel}: neither repo scripts/ nor bundled dist/pipeline/ found`);
23364
- }
23365
- function runStage(repoRoot, st, env, onLine) {
23366
- return new Promise((resolve2, reject) => {
23367
- const { cmd, argv, cwd } = stageInvocation(repoRoot, st.script, st.args);
23368
- const child = spawn6(cmd, argv, { cwd, env, stdio: ["ignore", "pipe", "pipe"] });
23369
- const pump = (buf) => {
23370
- if (!onLine) return;
23371
- for (const line of buf.toString().split(/\r?\n/)) if (line.trim()) onLine(line);
23372
- };
23373
- child.stdout.on("data", pump);
23374
- child.stderr.on("data", pump);
23375
- child.on("error", reject);
23376
- child.on("close", (code) => code === 0 ? resolve2() : reject(new Error(`${st.script} exited with code ${code}`)));
23377
- });
23378
- }
23379
- function hasPipeline(repoRoot) {
23380
- return existsSync5(path29.join(repoRoot, "scripts", "coding-build.mts")) || bundledPipelineDir() != null;
23913
+ \`\`\``;
23381
23914
  }
23382
- function codingDataRoot(repoRoot) {
23383
- if (!process.env.POLYMATH_DATA_DIR && existsSync5(path29.join(repoRoot, "scripts", "coding-build.mts"))) {
23384
- return path29.join(repoRoot, ".data");
23915
+ async function verifyQuotes(codingDir, axes) {
23916
+ const docs = path31.join(codingDir, "docs");
23917
+ let files = null;
23918
+ const norm2 = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
23919
+ const inDoc = async (file2, q) => norm2(await fs27.readFile(path31.join(docs, file2), "utf8").catch(() => "")).includes(norm2(q).slice(0, 80));
23920
+ let dropped = 0;
23921
+ for (const ax of Object.values(axes ?? {})) {
23922
+ for (const m of ax?.moments ?? []) {
23923
+ if (!m.quote) continue;
23924
+ let ok = false;
23925
+ if (m.sessionId) ok = await inDoc(`${m.sessionId}.txt`, m.quote);
23926
+ if (!ok) {
23927
+ files = files ?? (await fs27.readdir(docs).catch(() => [])).filter((f) => f.endsWith(".txt"));
23928
+ for (const f of files) {
23929
+ if (await inDoc(f, m.quote)) {
23930
+ ok = true;
23931
+ break;
23932
+ }
23933
+ }
23934
+ }
23935
+ if (!ok) {
23936
+ console.log(`[public-page] DROPPED unverifiable quote: "${m.quote.slice(0, 60)}\u2026"`);
23937
+ delete m.quote;
23938
+ dropped++;
23939
+ }
23940
+ }
23385
23941
  }
23386
- return resolveDataRoot();
23387
- }
23388
- async function finalCodingArtifacts(codingDir) {
23389
- const files = await fs23.readdir(codingDir).catch(() => []);
23390
- return files.filter((f) => f.endsWith(".json") && f !== "report-run.json" && !f.startsWith(".")).sort().map((f) => path29.join(codingDir, f));
23942
+ return { dropped };
23391
23943
  }
23392
- async function runPipeline(o) {
23393
- if (!hasPipeline(o.repoRoot)) {
23394
- throw new Error(
23395
- "full-pipeline refresh: neither the polymath repo (scripts/coding-*.mts at " + o.repoRoot + ") nor the bundled pipeline (dist/pipeline/) was found \u2014 the package build is broken."
23396
- );
23944
+ async function generatePublicPage(opts) {
23945
+ const outFile = path31.join(opts.codingDir, "coding-public.json");
23946
+ const skeleton = await buildSkeleton(opts.codingDir, opts.stackUp);
23947
+ if (!skeleton.page.verdict && !skeleton.evidence.includes("[")) {
23948
+ console.log("[public-page] no upstream artifacts yet \u2014 run the analysis first");
23949
+ return null;
23397
23950
  }
23398
- const dataRoot = codingDataRoot(o.repoRoot);
23399
- const env = { ...process.env, POLYMATH_RESILIENT: "1", POLYMATH_DATA_DIR: dataRoot };
23400
- if (!o.overnight) env.POLYMATH_RESILIENT_NO_WINDOW = "1";
23401
- if (o.overnight && process.platform === "darwin") {
23402
- try {
23403
- const { spawn: spawn10 } = await import("node:child_process");
23404
- spawn10("caffeinate", ["-ims", "-w", String(process.pid)], { detached: true, stdio: "ignore" }).unref();
23405
- } catch {
23951
+ const system = SYSTEM4 + sourceLookupNote();
23952
+ const prompt = copyPrompt(skeleton);
23953
+ const sha = promptSha([system, prompt, opts.model ?? "sonnet"]);
23954
+ if (!opts.refresh) {
23955
+ const prev = await reusableOutput(outFile, sha, (o) => !!o.verdict && (o.axes ?? []).length === 6);
23956
+ if (prev) {
23957
+ console.log(`[public-page] inputs unchanged \u2014 reusing page from ${prev.generatedAt} (--refresh to regenerate)`);
23958
+ return prev;
23406
23959
  }
23407
23960
  }
23408
- const list = stages(o).filter((st) => !o.deterministicOnly || !st.llm);
23409
- const codingDir = path29.join(dataRoot, "coding");
23410
- const central = centralConfig();
23411
- const t0 = Date.now();
23412
- const log = await startRunLog(
23413
- { app: "npm-package", pipeline: "coding", stages: list.length },
23414
- {
23415
- supabaseUrl: central.supabaseUrl,
23416
- supabaseAnonKey: central.supabaseAnonKey,
23417
- artifacts: () => finalCodingArtifacts(codingDir),
23418
- refPath: path29.join(codingDir, "report-run.json")
23419
- // next to the served artifacts
23961
+ await ensureCodingDocs(opts.codingDir, opts.sessions);
23962
+ for (let attempt = 1; attempt <= 2; attempt++) {
23963
+ const run4 = await invokeAgent2({
23964
+ prompt: attempt === 1 ? prompt : prompt + "\n\nREMINDER: your previous attempt contained an em dash (\u2014). That is a hard style violation. Rewrite with ZERO em dashes.",
23965
+ systemPrompt: system,
23966
+ // 40 turns: quote verification is turn-hungry (one grep per citation) and
23967
+ // the run DIED at 14 twice on 2026-07-14, always mid-verification. Batch
23968
+ // instruction in SYSTEM keeps it economical; the engine's corpus agents
23969
+ // get 80 for the same reason.
23970
+ addDir: opts.codingDir,
23971
+ allowedTools: ["Read", "Grep", "Glob"],
23972
+ maxTurns: 40,
23973
+ timeoutMs: 6e5,
23974
+ model: opts.model ?? "sonnet"
23975
+ });
23976
+ const j = run4.json;
23977
+ if (!j?.verdict || !j?.axes) {
23978
+ console.log(`[public-page] attempt ${attempt}: no usable copy`);
23979
+ continue;
23980
+ }
23981
+ if (JSON.stringify(j).includes("\u2014")) {
23982
+ console.log(`[public-page] attempt ${attempt}: em dash in output, retrying once`);
23983
+ continue;
23420
23984
  }
23421
- );
23422
- const failed = [];
23423
- const groups = [];
23424
- for (const st of list) {
23425
- const g = groups[groups.length - 1];
23426
- if (g && st.batch && g[0].batch === st.batch) g.push(st);
23427
- else groups.push([st]);
23985
+ await verifyQuotes(opts.codingDir, j.axes);
23986
+ const page = skeleton.page;
23987
+ page.verdict = String(j.verdict).slice(0, 500);
23988
+ page.overall = String(j.overall ?? "").slice(0, 900);
23989
+ page.missionArc = String(j.missionArc ?? "").slice(0, 700);
23990
+ page.rhythm.inFlow = String(j.inFlow ?? "").slice(0, 300) || void 0;
23991
+ page.rhythm.outFlow = String(j.outFlow ?? "").slice(0, 300) || void 0;
23992
+ page.howToWork = (Array.isArray(j.howToWork) ? j.howToWork : []).map((x) => String(x).slice(0, 250)).slice(0, 5);
23993
+ for (const ax of page.axes) {
23994
+ const c = j.axes[ax.key];
23995
+ if (!c) continue;
23996
+ ax.claim = String(c.claim ?? "").slice(0, 200);
23997
+ ax.read = String(c.read ?? "").slice(0, 500);
23998
+ ax.edge = c.edge ? String(c.edge).slice(0, 350) : void 0;
23999
+ ax.moments = (Array.isArray(c.moments) ? c.moments : []).slice(0, 4).map((m) => ({
24000
+ date: String(m.date ?? "").slice(0, 30),
24001
+ what: String(m.what ?? "").slice(0, 500),
24002
+ ...m.quote ? { quote: String(m.quote).slice(0, 300) } : {},
24003
+ ...m.sessionId ? { sessionId: String(m.sessionId) } : {}
24004
+ })).filter((m) => m.what);
24005
+ }
24006
+ if (page.axes.filter((a) => a.claim).length < 4) {
24007
+ console.log(`[public-page] attempt ${attempt}: too few axis claims`);
24008
+ continue;
24009
+ }
24010
+ page.promptSha = sha;
24011
+ await fs27.writeFile(outFile, JSON.stringify(page, null, 2));
24012
+ return page;
23428
24013
  }
23429
- let stageNo = 0;
23430
- for (const group of groups) {
23431
- await Promise.all(group.map(async (st) => {
23432
- o.onStage?.(++stageNo, list.length, group.length > 1 ? `${st.label} (parallel \xD7${group.length})` : st.label, st.llm);
23433
- const stStart = Date.now();
23434
- let ok = true;
23435
- const tag = group.length > 1 ? `[${st.script.replace(/^coding-|\.mts$/g, "")}] ` : "";
23436
- try {
23437
- await runStage(o.repoRoot, st, env, o.onLine && ((line) => o.onLine(`${tag}${line}`)));
23438
- } catch (e) {
23439
- ok = false;
23440
- const error = e.message.slice(0, 200);
23441
- failed.push({ label: st.label, script: st.script, error });
23442
- o.onLine?.(`\u26A0\uFE0F stage FAILED (continuing): ${st.label} \u2014 ${error}`);
23443
- }
23444
- const sha = st.out ? await fileSha(path29.join(dataRoot, st.out)) : null;
23445
- log.event(st.script.replace(/\.mts$/, ""), { ok, ms: Date.now() - stStart, ...sha ? { sha } : {} });
23446
- }));
24014
+ const existing = await readJson3(outFile, null);
24015
+ if (existing?.verdict) {
24016
+ console.error("[public-page] generation FAILED twice, keeping the existing page");
24017
+ return null;
23447
24018
  }
23448
- log.event("pipeline_completed", { ok: failed.length === 0, failedStages: failed.length, ms: Date.now() - t0 });
23449
- await log.finish();
23450
- return { failed };
24019
+ console.error("[public-page] generation FAILED and no previous page exists");
24020
+ return null;
23451
24021
  }
23452
24022
 
23453
- // src/chatPipeline.ts
23454
- init_manifest();
23455
- import { spawn as spawn7 } from "child_process";
23456
- import path31 from "path";
23457
- import { existsSync as existsSync6, promises as fs25 } from "fs";
23458
- import { fileURLToPath as fileURLToPath4 } from "url";
23459
- init_dataHome();
23460
- var MODULE_DIR3 = path31.dirname(fileURLToPath4(import.meta.url));
23461
- var INGESTABLE_KINDS = ["chatgpt", "claude", "notion", "obsidian"];
23462
- function chatEngineStages() {
23463
- return [
23464
- { script: "run-tagger.mts", label: "Tag your conversations", llm: true, args: ["--model", "haiku"], out: "signals/index.jsonl" },
23465
- { script: "run-analysis.mts", label: "Docs + growth/drivers/circumstances agents", llm: true, args: [], out: "engine-pilot/growth-latest.json" },
23466
- { script: "exp-pipeline.mts", label: "Select the conversations to grade", llm: true, args: ["--lenses", "reasoning,agency,interpersonal", "--select-only"], out: "engine-pilot/grades/reasoning/_selected.json" },
23467
- { script: "exp-allfacets.mts", label: "Per-conversation grades", llm: true, args: ["--lenses", "all", "--all"] },
23468
- { script: "exp-person.mts", label: "Person synthesis", llm: true, args: ["--lenses", "all"], out: "engine-pilot/grades/reasoning/_person.json" },
23469
- { script: "person-self-image.mts", label: "Self-image read", llm: true, args: [], out: "engine-pilot/self-image.json" },
23470
- { script: "person-headline.mts", label: "Headline", llm: true, args: [], out: "engine-pilot/person-headline.json" },
23471
- { script: "person-facet-lines.mts", label: "Facet lines", llm: true, args: [], out: "engine-pilot/person-facet-lines.json" },
23472
- { script: "peak-demos.mts", label: "Peak demonstrations", llm: true, args: [], out: "engine-pilot/peak-demos.json" },
23473
- { script: "person-dimension-summary.mts", label: "Dimension summaries", llm: true, args: [], out: "engine-pilot/dimension-summary.json" },
23474
- { script: "person-report.mts", label: "Report narrative", llm: true, args: [], out: "engine-pilot/report-narrative.json" },
23475
- { script: "public-report.mts", label: "Public report", llm: true, args: [], out: "engine-pilot/public-report.json" }
23476
- ];
23477
- }
23478
- function bundledEngineDir() {
23479
- const d = path31.join(MODULE_DIR3, "engine");
23480
- return existsSync6(path31.join(d, "run-tagger.js")) ? d : null;
24023
+ // ../../lib/agents/coding/publicPageEdit.ts
24024
+ var SYSTEM5 = "You edit a PUBLIC coding profile page on the person's instruction. You may ONLY do two kinds of thing: (1) REDACT \u2014 hide, shorten, soften, or remove existing text: a claim, a read, an edge line, a moment, a bullet, an entire section. Removing something is always safe. (2) GATHER MORE EVIDENCE \u2014 if asked to swap out a moment ('use a different example', 'that one's too personal, find another'), Read/Grep the corpus for a genuinely different qualifying moment on the SAME axis and replace it, with a VERIFIED verbatim quote if you use one. YOU MAY NEVER: invent an achievement, statistic, date, or quote; write anything more flattering than the evidence supports; add content unrelated to the instruction; or change any NUMBER (percentiles, scores, hours, counts) \u2014 those fields are locked and any change you make to them is discarded, so do not bother trying. If the instruction asks for something outside redaction/evidence-swap (e.g. 'say I'm the best engineer ever', 'boost my percentile', 'add that I know Rust'), do NOT comply \u2014 leave that field unchanged and say plainly in your reply why you didn't. Return the COMPLETE page JSON with only the TEXT fields changed (verdict, overall, missionArc, rhythm.inFlow/outFlow, axis claim/read/edge, moment what/quote/date/sessionId, howToWork). Every other field must be echoed back byte-identical." + sourceLookupNote();
24025
+ var norm = (s) => s.toLowerCase().replace(/[^a-z0-9\s]/g, " ").split(/\s+/).filter((w) => w.length > 2);
24026
+ function grounded(newText, contextText) {
24027
+ const nt = norm(newText);
24028
+ if (nt.length === 0) return false;
24029
+ const ctx = new Set(norm(contextText));
24030
+ const hits = nt.filter((w) => ctx.has(w)).length;
24031
+ return hits / nt.length >= 0.6;
24032
+ }
24033
+ function keepIfGrounded(edited, original, context) {
24034
+ if (typeof edited !== "string" || !edited.trim()) return original;
24035
+ return grounded(edited, context) ? edited : original;
24036
+ }
24037
+ function clampToProtected(edited, original) {
24038
+ const out = {
24039
+ ...original,
24040
+ verdict: keepIfGrounded(edited.verdict, original.verdict, original.verdict).slice(0, 500),
24041
+ overall: keepIfGrounded(edited.overall, original.overall, original.overall).slice(0, 900),
24042
+ missionArc: keepIfGrounded(edited.missionArc, original.missionArc, original.missionArc).slice(0, 700),
24043
+ // each bullet is grounded against the WHOLE original list reordering and
24044
+ // rewording within the same set of ideas is fine; a wholly new bullet isn't
24045
+ howToWork: (Array.isArray(edited.howToWork) ? edited.howToWork : original.howToWork).map((x) => keepIfGrounded(x, "", original.howToWork.join(" "))).filter((x) => !!x).map((x) => x.slice(0, 250)).slice(0, 5) || original.howToWork,
24046
+ rhythm: {
24047
+ facts: original.rhythm.facts,
24048
+ // counters: NEVER editable
24049
+ inFlow: keepIfGrounded(edited.rhythm?.inFlow, original.rhythm.inFlow ?? "", original.rhythm.inFlow ?? "").slice(0, 300) || void 0,
24050
+ outFlow: keepIfGrounded(edited.rhythm?.outFlow, original.rhythm.outFlow ?? "", original.rhythm.outFlow ?? "").slice(0, 300) || void 0
24051
+ },
24052
+ // PROTECTED, always restored: provenance, projects, moreNumbers (raw stats)
24053
+ provenance: original.provenance,
24054
+ projects: original.projects,
24055
+ moreNumbers: original.moreNumbers,
24056
+ nutshell: original.nutshell
24057
+ // the local report owns this; not editable here
24058
+ };
24059
+ const editedAxes = new Map((edited.axes ?? []).map((a) => [a.key, a]));
24060
+ out.axes = original.axes.map((orig) => {
24061
+ const e = editedAxes.get(orig.key);
24062
+ const axisCtx = `${orig.claim} ${orig.read} ${orig.moments.map((m) => m.what).join(" ")}`;
24063
+ const base2 = {
24064
+ ...orig,
24065
+ // topPct, sub, numbers: PROTECTED, always from orig
24066
+ claim: keepIfGrounded(e?.claim, orig.claim, axisCtx).slice(0, 200),
24067
+ read: keepIfGrounded(e?.read, orig.read, axisCtx).slice(0, 500),
24068
+ edge: e?.edge === void 0 ? orig.edge : e.edge ? keepIfGrounded(e.edge, orig.edge ?? "", `${orig.edge ?? ""} ${axisCtx}`).slice(0, 350) || void 0 : void 0
24069
+ };
24070
+ const origById = new Map(orig.moments.filter((m) => m.sessionId).map((m) => [m.sessionId, m]));
24071
+ base2.moments = (Array.isArray(e?.moments) ? e.moments : orig.moments).slice(0, 3).map((m) => {
24072
+ const matched = m?.sessionId ? origById.get(String(m.sessionId)) : void 0;
24073
+ if (matched) return matched;
24074
+ return {
24075
+ date: String(m?.date ?? "").slice(0, 30),
24076
+ what: String(m?.what ?? "").slice(0, 500),
24077
+ ...m?.quote ? { quote: String(m.quote).slice(0, 300) } : {},
24078
+ ...m?.sessionId ? { sessionId: String(m.sessionId) } : {}
24079
+ };
24080
+ }).filter((m) => m.what && (origById.has(m.sessionId ?? "") || m.quote));
24081
+ return base2;
24082
+ });
24083
+ return out;
23481
24084
  }
23482
- function stageInvocation2(repoRoot, scriptRel, args) {
23483
- const scriptAbs = path31.join(repoRoot, "scripts", scriptRel);
23484
- if (existsSync6(scriptAbs)) {
23485
- const local = path31.join(repoRoot, "node_modules", ".bin", "tsx");
23486
- if (existsSync6(local)) return { cmd: local, argv: [scriptAbs, ...args], cwd: repoRoot };
23487
- return { cmd: "npx", argv: ["tsx", scriptAbs, ...args], cwd: repoRoot };
23488
- }
23489
- const bundled = bundledEngineDir();
23490
- if (bundled) {
23491
- const js = path31.join(bundled, scriptRel.replace(/\.mts$/, ".js"));
23492
- return { cmd: process.execPath, argv: [js, ...args], cwd: process.cwd() };
24085
+ async function editPublicPage(opts) {
24086
+ const last = opts.messages.filter((m) => m.role === "user").pop();
24087
+ if (!last?.content?.trim()) return { status: 400, json: { error: "an instruction is required" } };
24088
+ const convo = opts.messages.slice(-6).map((m) => `${m.role === "user" ? "USER" : "EDITOR"}: ${m.content}`).join("\n");
24089
+ const prompt = `CURRENT PAGE:
24090
+ \`\`\`json
24091
+ ${JSON.stringify(opts.page, null, 1)}
24092
+ \`\`\`
24093
+
24094
+ CONVERSATION:
24095
+ ${convo}
24096
+
24097
+ Apply the user's LAST instruction within your allowed actions (redact, or gather-more-evidence). Output ONE fenced json block: { "page": <complete page, text fields updated>, "reply": "one short plain sentence on what you did or why you declined" }`;
24098
+ try {
24099
+ const run4 = await invokeAgent2({
24100
+ prompt,
24101
+ systemPrompt: SYSTEM5,
24102
+ addDir: opts.codingDir,
24103
+ allowedTools: ["Read", "Grep", "Glob"],
24104
+ maxTurns: 10,
24105
+ timeoutMs: 24e4,
24106
+ model: opts.model ?? "sonnet"
24107
+ });
24108
+ const j = run4.json;
24109
+ if (!j?.page) return { status: 502, json: { error: "the edit didn't produce a valid page \u2014 try rephrasing" } };
24110
+ const clamped = clampToProtected(j.page, opts.page);
24111
+ const originalIds = new Set(opts.page.axes.flatMap((a) => a.moments.map((m) => m.sessionId).filter(Boolean)));
24112
+ await verifyQuotes(opts.codingDir, clamped.axes);
24113
+ for (const ax of clamped.axes) ax.moments = ax.moments.filter((m) => m.sessionId && originalIds.has(m.sessionId) || m.quote);
24114
+ return { status: 200, json: { page: clamped, reply: String(j.reply ?? "Done.").slice(0, 300) } };
24115
+ } catch (e) {
24116
+ return { status: 502, json: { error: e.message.slice(0, 200) } };
23493
24117
  }
23494
- throw new Error(`chat-engine stage ${scriptRel}: neither repo scripts/ nor bundled dist/engine/ found`);
23495
24118
  }
23496
- function hasChatPipeline(repoRoot) {
23497
- return existsSync6(path31.join(repoRoot, "scripts", "run-tagger.mts")) || bundledEngineDir() != null;
24119
+
24120
+ // src/publicCodingPageApi.ts
24121
+ var readJson4 = async (f, d) => fs28.readFile(f, "utf8").then((t) => JSON.parse(t)).catch(() => d);
24122
+ async function localChatReport() {
24123
+ const rep = await loadPublicReport().catch(() => null);
24124
+ return rep && hasContent(rep) ? rep : null;
23498
24125
  }
23499
- function chatDataRoot(repoRoot) {
23500
- if (!process.env.POLYMATH_DATA_DIR && existsSync6(path31.join(repoRoot, "scripts", "run-tagger.mts"))) {
23501
- return path31.join(repoRoot, ".data");
23502
- }
23503
- return resolveDataRoot();
24126
+ async function handlePublicCodingPageGet(dataDir) {
24127
+ const page = await readJson4(path32.join(dataDir, "coding", "coding-public.json"), null);
24128
+ const chatReport = await localChatReport();
24129
+ return { status: 200, json: { page, chatReport } };
23504
24130
  }
23505
- async function finalChatArtifacts(dataRoot) {
23506
- const gradesDir = path31.join(dataRoot, "engine-pilot", "grades");
23507
- const out = [];
23508
- for (const lens of (await fs25.readdir(gradesDir).catch(() => [])).sort()) {
23509
- const p = path31.join(gradesDir, lens, "_person.json");
23510
- if (existsSync6(p)) out.push(p);
24131
+ async function handlePublicCodingPageGenerate(dataDir, liveProfile) {
24132
+ const codingDir = path32.join(dataDir, "coding");
24133
+ const stackUp = liveProfile?.stackUp ?? null;
24134
+ const sessions = await readJson4(path32.join(codingDir, "sessions.json"), []);
24135
+ try {
24136
+ const page = await generatePublicPage({ codingDir, stackUp, sessions });
24137
+ if (!page) return { status: 502, json: { error: "generation failed \u2014 see the server log, or run the analysis first" } };
24138
+ return { status: 200, json: { page } };
24139
+ } catch (e) {
24140
+ return { status: 502, json: { error: e.message.slice(0, 300) } };
23511
24141
  }
23512
- out.push(path31.join(dataRoot, "engine-pilot", "public-report.json"));
24142
+ }
24143
+ async function handlePublicCodingPageEdit(dataDir, body) {
24144
+ const page = body.page;
24145
+ const messages = Array.isArray(body.messages) ? body.messages : [];
24146
+ if (!page || !Array.isArray(page.axes)) return { status: 400, json: { error: "page + messages are required" } };
24147
+ const out = await editPublicPage({ page, messages, codingDir: path32.join(dataDir, "coding") });
23513
24148
  return out;
23514
24149
  }
23515
- function runStage2(repoRoot, st, env, onLine) {
24150
+ async function handlePublicCodingPageShare(dataDir, body) {
24151
+ const cfg = centralConfig();
24152
+ if (!cfg.configured) return { status: 503, json: { error: "central services are disabled in this build" } };
24153
+ const auth = await getAccessToken(dataDir);
24154
+ if (!auth) return { status: 401, json: { error: "sign in with Google (top right) to share with Polymath" } };
24155
+ const page = body.page;
24156
+ if (!page?.verdict || !Array.isArray(page.axes) || page.axes.length < 4) {
24157
+ return { status: 409, json: { error: "nothing to share yet \u2014 generate your page first" } };
24158
+ }
24159
+ const chatReport = body.includeChat === false ? null : await localChatReport();
24160
+ try {
24161
+ const payload = JSON.stringify({ format: "coding-pr1", page, ...chatReport ? { chatReport } : {} });
24162
+ const up = await fetch(`${cfg.supabaseUrl}/rest/v1/rpc/submit_report`, {
24163
+ method: "POST",
24164
+ headers: { apikey: cfg.supabaseAnonKey, authorization: `Bearer ${auth.token}`, "content-type": "application/json" },
24165
+ body: JSON.stringify({ p_session_id: null, p_content: payload })
24166
+ });
24167
+ if (!up.ok) return { status: 502, json: { error: `share failed (HTTP ${up.status})` } };
24168
+ const verification = String(await up.json().catch(() => "unverified"));
24169
+ return { status: 200, json: { ok: true, includedChat: !!chatReport, verification } };
24170
+ } catch (e) {
24171
+ return { status: 502, json: { error: e.message.slice(0, 200) } };
24172
+ }
24173
+ }
24174
+
24175
+ // src/server.ts
24176
+ var __dirname = path33.dirname(fileURLToPath2(import.meta.url));
24177
+ var UI_DIR = path33.join(__dirname, "web");
24178
+ var DEFAULT_SHARE_URL = "https://polymathsociety.us/api/coding-share";
24179
+ var MIME = {
24180
+ ".html": "text/html; charset=utf-8",
24181
+ ".js": "text/javascript; charset=utf-8",
24182
+ ".css": "text/css; charset=utf-8",
24183
+ ".json": "application/json; charset=utf-8",
24184
+ ".svg": "image/svg+xml",
24185
+ ".ico": "image/x-icon",
24186
+ ".map": "application/json; charset=utf-8"
24187
+ };
24188
+ async function readBody(req, maxBytes = 8e6) {
23516
24189
  return new Promise((resolve2, reject) => {
23517
- const { cmd, argv, cwd } = stageInvocation2(repoRoot, st.script, st.args);
23518
- const child = spawn7(cmd, argv, { cwd, env, stdio: ["ignore", "pipe", "pipe"] });
23519
- const pump = (buf) => {
23520
- if (!onLine) return;
23521
- for (const line of buf.toString().split(/\r?\n/)) if (line.trim()) onLine(line);
23522
- };
23523
- child.stdout.on("data", pump);
23524
- child.stderr.on("data", pump);
23525
- child.on("error", reject);
23526
- child.on("close", (code) => code === 0 ? resolve2() : reject(new Error(`${st.script} exited with code ${code}`)));
24190
+ let size = 0;
24191
+ const chunks = [];
24192
+ req.on("data", (c) => {
24193
+ size += c.length;
24194
+ if (size > maxBytes) {
24195
+ reject(new Error("payload too large"));
24196
+ req.destroy();
24197
+ return;
24198
+ }
24199
+ chunks.push(c);
24200
+ });
24201
+ req.on("end", () => resolve2(Buffer.concat(chunks).toString("utf-8")));
24202
+ req.on("error", reject);
23527
24203
  });
23528
24204
  }
23529
- async function runChatPipeline(o) {
23530
- if (!hasChatPipeline(o.repoRoot)) {
23531
- throw new Error(
23532
- "chat pipeline: neither the polymath repo (scripts/run-tagger.mts at " + o.repoRoot + ") nor the bundled engine (dist/engine/) was found \u2014 the package build is broken."
23533
- );
24205
+ async function serveStatic(res, urlPath) {
24206
+ const clean = urlPath.split("?")[0];
24207
+ const rel = clean === "/" ? "index.html" : clean.replace(/^\/+/, "");
24208
+ const full = path33.normalize(path33.join(UI_DIR, rel));
24209
+ if (!full.startsWith(UI_DIR)) {
24210
+ res.writeHead(403).end("forbidden");
24211
+ return;
23534
24212
  }
23535
- const dataRoot = chatDataRoot(o.repoRoot);
23536
- const manifest = await readManifest(dataRoot);
23537
- if (!manifest) {
23538
- return { skipped: true, skipReason: "no exports-manifest.json \u2014 run the wizard (bare `polymath-society`) to approve chat/notes sources", ingested: [], notIngestable: [], failed: [] };
24213
+ try {
24214
+ const data = await fs29.readFile(full);
24215
+ res.writeHead(200, { "content-type": MIME[path33.extname(full)] ?? "application/octet-stream" });
24216
+ res.end(data);
24217
+ } catch {
24218
+ if (!path33.extname(full)) {
24219
+ try {
24220
+ const idx = await fs29.readFile(path33.join(UI_DIR, "index.html"));
24221
+ res.writeHead(200, { "content-type": MIME[".html"] }).end(idx);
24222
+ return;
24223
+ } catch {
24224
+ }
24225
+ }
24226
+ res.writeHead(404).end("not found");
23539
24227
  }
23540
- const included = manifest.exports.included;
23541
- if (included.length === 0) {
23542
- return { skipped: true, skipReason: "manifest present but no sources are included \u2014 re-run the wizard to change your choices", ingested: [], notIngestable: [], failed: [] };
24228
+ }
24229
+ var isLoopback = (u) => {
24230
+ try {
24231
+ const h = new URL(u).hostname;
24232
+ return h === "localhost" || h === "127.0.0.1" || h === "::1";
24233
+ } catch {
24234
+ return false;
23543
24235
  }
23544
- const env = {
23545
- ...process.env,
23546
- POLYMATH_RESILIENT: "1",
23547
- POLYMATH_ANALYZE_MODE: "off",
23548
- // WE run the engine, in order — no auto-trigger
23549
- POLYMATH_DATA_DIR: dataRoot,
23550
- // one root for store + engine artifacts
23551
- AGENT_MODEL: o.model ?? process.env.AGENT_MODEL ?? "sonnet"
23552
- };
23553
- if (!o.overnight) env.POLYMATH_RESILIENT_NO_WINDOW = "1";
23554
- const failed = [];
23555
- const ingested = [];
23556
- const notIngestable = [];
23557
- const ingestable = included.filter((f) => INGESTABLE_KINDS.includes(f.kind));
23558
- for (const f of included) {
23559
- if (!INGESTABLE_KINDS.includes(f.kind)) notIngestable.push(f.path);
24236
+ };
24237
+ async function handleShare(res, body, opts, dataDir) {
24238
+ let parsed;
24239
+ try {
24240
+ parsed = JSON.parse(body);
24241
+ } catch {
24242
+ res.writeHead(400, { "content-type": "application/json" }).end(JSON.stringify({ ok: false, error: "bad JSON" }));
24243
+ return;
23560
24244
  }
23561
- const total = ingestable.length + chatEngineStages().length;
23562
- const central = centralConfig();
23563
- const t0 = Date.now();
23564
- const log = await startRunLog(
23565
- { app: "npm-package", pipeline: "chat", stages: total },
23566
- {
23567
- supabaseUrl: central.supabaseUrl,
23568
- supabaseAnonKey: central.supabaseAnonKey,
23569
- artifacts: () => finalChatArtifacts(dataRoot),
23570
- refPath: path31.join(dataRoot, "report-run.json")
24245
+ const all = opts.shareSections ?? opts.profile?.sections ?? {};
24246
+ const sections = {};
24247
+ if (parsed.sectionsData && typeof parsed.sectionsData === "object" && !Array.isArray(parsed.sectionsData)) {
24248
+ for (const key of Object.keys(parsed.sectionsData)) {
24249
+ if (key in all && parsed.sectionsData[key] != null) sections[key] = parsed.sectionsData[key];
23571
24250
  }
23572
- );
23573
- let idx = 0;
23574
- for (const f of ingestable) {
23575
- const st = { script: "ingest-export.mts", label: `Ingest ${f.kind} \u2014 ${path31.basename(f.path)}`, llm: false, args: [f.kind, f.path] };
23576
- o.onStage?.(++idx, total, st.label, false);
23577
- const stStart = Date.now();
23578
- let ok = true;
23579
- try {
23580
- await runStage2(o.repoRoot, st, env, o.onLine);
23581
- ingested.push(f.path);
23582
- } catch (e) {
23583
- ok = false;
23584
- const error = e.message.slice(0, 200);
23585
- failed.push({ label: st.label, script: st.script, error });
23586
- o.onLine?.(`\u26A0\uFE0F ingest FAILED (continuing): ${f.path} \u2014 ${error}`);
24251
+ } else {
24252
+ const wanted = parsed.all ? Object.keys(all) : Array.isArray(parsed.sections) ? parsed.sections : [];
24253
+ for (const key of wanted) {
24254
+ if (key in all && all[key] != null) sections[key] = all[key];
23587
24255
  }
23588
- log.event("ingest-export", { ok, ms: Date.now() - stStart, source: f.kind });
23589
24256
  }
23590
- for (const st of chatEngineStages()) {
23591
- o.onStage?.(++idx, total, st.label, st.llm);
23592
- const stStart = Date.now();
23593
- let ok = true;
24257
+ if (Object.keys(sections).length === 0) {
24258
+ res.writeHead(400, { "content-type": "application/json" }).end(JSON.stringify({ ok: false, error: "no shareable sections selected" }));
24259
+ return;
24260
+ }
24261
+ const shareUrl = opts.shareUrl || DEFAULT_SHARE_URL;
24262
+ const auth = await getAccessToken(dataDir);
24263
+ if (!auth && !isLoopback(shareUrl)) {
24264
+ res.writeHead(401, { "content-type": "application/json" });
24265
+ res.end(JSON.stringify({ ok: false, error: "sign in with Google (top right) to share your report" }));
24266
+ return;
24267
+ }
24268
+ const payload = {
24269
+ source: "coding-analyzer",
24270
+ version: opts.version,
24271
+ name: typeof parsed.name === "string" && parsed.name.trim() ? parsed.name.trim() : void 0,
24272
+ sharedAt: (/* @__PURE__ */ new Date()).toISOString(),
24273
+ ...auth ? { owner: { userId: auth.identity.userId, email: auth.identity.email } } : {},
24274
+ sections
24275
+ };
24276
+ try {
24277
+ const upstream = await fetch(shareUrl, {
24278
+ method: "POST",
24279
+ headers: { "content-type": "application/json", ...auth ? { authorization: `Bearer ${auth.token}` } : {} },
24280
+ body: JSON.stringify(payload)
24281
+ });
24282
+ const text2 = await upstream.text();
24283
+ res.writeHead(upstream.ok ? 200 : 502, { "content-type": "application/json" });
24284
+ res.end(JSON.stringify({ ok: upstream.ok, status: upstream.status, endpoint: shareUrl, shared: Object.keys(sections), upstream: text2.slice(0, 2e3) }));
24285
+ } catch (e) {
24286
+ res.writeHead(502, { "content-type": "application/json" });
24287
+ res.end(JSON.stringify({ ok: false, error: String(e instanceof Error ? e.message : e), endpoint: shareUrl }));
24288
+ }
24289
+ }
24290
+ function startServer(opts) {
24291
+ let liveProfile = opts.profile;
24292
+ let liveProgress = {};
24293
+ let profileRev = 0;
24294
+ const host = opts.host ?? "127.0.0.1";
24295
+ const dataDir = opts.dataDir ?? resolveDataRoot();
24296
+ let serverUrl = "";
24297
+ const json = (res, status, body) => res.writeHead(status, { "content-type": MIME[".json"] }).end(JSON.stringify(body));
24298
+ const server = http.createServer(async (req, res) => {
23594
24299
  try {
23595
- await runStage2(o.repoRoot, st, env, o.onLine);
24300
+ const url = req.url ?? "/";
24301
+ const route = url.split("?")[0];
24302
+ if (req.method === "GET" && (url === "/api/coding" || url === "/profile.json" || url.startsWith("/profile.json?"))) {
24303
+ res.writeHead(200, { "content-type": MIME[".json"] }).end(JSON.stringify(liveProfile));
24304
+ return;
24305
+ }
24306
+ if (req.method === "GET" && url === "/api/progress") {
24307
+ res.writeHead(200, { "content-type": MIME[".json"] }).end(JSON.stringify({ ...liveProgress, profileRev }));
24308
+ return;
24309
+ }
24310
+ if (req.method === "GET" && route === "/api/exports-manifest") {
24311
+ const m = await readManifest(dataDir).catch(() => null);
24312
+ const kinds = new Set((m?.exports?.included ?? []).map((e) => e.kind));
24313
+ json(res, 200, { connectedKinds: [...kinds], links: EXPORT_LINKS });
24314
+ return;
24315
+ }
24316
+ if (req.method === "GET" && route === "/meta.json") {
24317
+ const identity = await readIdentity(dataDir);
24318
+ const central = centralConfig();
24319
+ json(res, 200, {
24320
+ version: opts.version,
24321
+ shareUrl: opts.shareUrl || DEFAULT_SHARE_URL,
24322
+ standalone: true,
24323
+ capabilities: {
24324
+ preview: true,
24325
+ state: true,
24326
+ diagnostic: false,
24327
+ // corpus audit is engine-report-only
24328
+ submit: central.configured,
24329
+ auth: central.configured,
24330
+ share: true,
24331
+ shareEdit: true,
24332
+ // the review modal's chat editor (/api/share/edit)
24333
+ publicCodingPage: true,
24334
+ // the hiring-manager page (/api/public-coding-page*)
24335
+ person: true,
24336
+ // the chat-analysis tab's /api/person* routes
24337
+ publicReport: true
24338
+ // the public-report tab's /api/public-report route
24339
+ },
24340
+ identity: identity ? { email: identity.email, name: identity.name ?? null } : null
24341
+ });
24342
+ return;
24343
+ }
24344
+ if (req.method === "GET" && (route === "/api/config/calibration" || route === "/api/calibration")) {
24345
+ const cal = await getCalibration();
24346
+ json(res, 200, { ...cal, localRubricVersion: RUBRIC_FINGERPRINT2 });
24347
+ return;
24348
+ }
24349
+ if (req.method === "GET" && route === "/auth/login") {
24350
+ const r = beginLogin(serverUrl);
24351
+ if ("error" in r) {
24352
+ json(res, 503, { error: r.error });
24353
+ return;
24354
+ }
24355
+ res.writeHead(302, { location: r.redirect }).end();
24356
+ return;
24357
+ }
24358
+ if (req.method === "GET" && route === "/auth/callback") {
24359
+ try {
24360
+ const id = await completeLogin(dataDir, new URL(url, serverUrl).searchParams);
24361
+ res.writeHead(200, { "content-type": MIME[".html"] });
24362
+ res.end(`<!doctype html><meta charset="utf-8"><title>Signed in</title><body style="font-family:system-ui;padding:40px"><p>Signed in as <b>${id.email.replace(/</g, "&lt;")}</b>.</p><p><a href="/">Back to your report</a> (or just close this tab \u2014 the report page picks it up on its own).</p></body>`);
24363
+ } catch (e) {
24364
+ res.writeHead(400, { "content-type": MIME[".html"] });
24365
+ res.end(`<!doctype html><meta charset="utf-8"><title>Sign-in failed</title><body style="font-family:system-ui;padding:40px"><p><b>Sign-in failed.</b></p><p>${String(e.message).replace(/</g, "&lt;")}</p><p><a href="/auth/login">Try again</a></p></body>`);
24366
+ }
24367
+ return;
24368
+ }
24369
+ if (req.method === "POST" && route === "/auth/logout") {
24370
+ await signOut(dataDir);
24371
+ json(res, 200, { ok: true });
24372
+ return;
24373
+ }
24374
+ if (route === "/api/feedback/preview" && req.method === "POST") {
24375
+ const body = JSON.parse(await readBody(req) || "{}");
24376
+ const out = await handlePreview(body);
24377
+ json(res, out.status, out.json);
24378
+ return;
24379
+ }
24380
+ if (route === "/api/feedback/state" && (req.method === "GET" || req.method === "POST")) {
24381
+ const body = req.method === "POST" ? JSON.parse(await readBody(req) || "{}") : void 0;
24382
+ const out = await handleState(dataDir, req.method, body);
24383
+ json(res, out.status, out.json);
24384
+ return;
24385
+ }
24386
+ if (route === "/api/feedback/submit" && req.method === "POST") {
24387
+ const body = JSON.parse(await readBody(req) || "{}");
24388
+ const out = await handleSubmit(dataDir, body);
24389
+ json(res, out.status, out.json);
24390
+ return;
24391
+ }
24392
+ if (route === "/api/feedback/diagnostic") {
24393
+ let body;
24394
+ if (req.method === "POST") {
24395
+ try {
24396
+ body = JSON.parse(await readBody(req));
24397
+ } catch {
24398
+ json(res, 400, { error: "bad json" });
24399
+ return;
24400
+ }
24401
+ }
24402
+ const key = new URL(url, serverUrl || "http://localhost").searchParams.get("key") || void 0;
24403
+ const out = handleDiagnostic(req.method || "GET", body, key);
24404
+ json(res, out.status, out.json);
24405
+ return;
24406
+ }
24407
+ if (route === "/api/person" && req.method === "GET") {
24408
+ const out = await handlePerson();
24409
+ json(res, out.status, out.json);
24410
+ return;
24411
+ }
24412
+ if (route === "/api/person/feedback" && (req.method === "GET" || req.method === "POST")) {
24413
+ const body = req.method === "POST" ? JSON.parse(await readBody(req) || "{}") : void 0;
24414
+ const out = await handlePersonFeedback(req.method, body);
24415
+ json(res, out.status, out.json);
24416
+ return;
24417
+ }
24418
+ if (route === "/api/person/loops" && req.method === "GET") {
24419
+ const out = await handleLoops();
24420
+ json(res, out.status, out.json);
24421
+ return;
24422
+ }
24423
+ if (route === "/api/person/grade" && req.method === "GET") {
24424
+ const out = await handleGrade(new URL(url, serverUrl || "http://localhost").searchParams);
24425
+ json(res, out.status, out.json);
24426
+ return;
24427
+ }
24428
+ if (route === "/api/person/transcript" && req.method === "GET") {
24429
+ const out = await handleTranscript(new URL(url, serverUrl || "http://localhost").searchParams);
24430
+ res.writeHead(out.status, { "Content-Type": "text/plain; charset=utf-8" }).end(out.text);
24431
+ return;
24432
+ }
24433
+ if (route === "/api/person/chat" && req.method === "POST") {
24434
+ const body = JSON.parse(await readBody(req) || "{}");
24435
+ await handlePersonChat(body, res);
24436
+ return;
24437
+ }
24438
+ if (route === "/api/public-report" && req.method === "GET") {
24439
+ const out = await handlePublicReportGet();
24440
+ json(res, out.status, out.json);
24441
+ return;
24442
+ }
24443
+ if (route === "/api/public-report" && req.method === "POST") {
24444
+ const body = JSON.parse(await readBody(req) || "{}");
24445
+ const out = await handlePublicReportEdit(body);
24446
+ json(res, out.status, out.json);
24447
+ return;
24448
+ }
24449
+ if (route === "/api/profile/visibility" && (req.method === "GET" || req.method === "POST")) {
24450
+ const body = req.method === "POST" ? JSON.parse(await readBody(req) || "{}") : void 0;
24451
+ const pool = opts.shareSections ?? opts.profile?.sections ?? {};
24452
+ const out = await handleVisibility(dataDir, req.method, body, pool);
24453
+ json(res, out.status, out.json);
24454
+ return;
24455
+ }
24456
+ if (route === "/api/coding/chat" && req.method === "POST") {
24457
+ const body = JSON.parse(await readBody(req) || "{}");
24458
+ await handleCodingChat(liveProfile, dataDir, body, res);
24459
+ return;
24460
+ }
24461
+ if (req.method === "POST" && url === "/share") {
24462
+ const body = await readBody(req);
24463
+ await handleShare(res, body, opts, dataDir);
24464
+ return;
24465
+ }
24466
+ if (req.method === "POST" && route === "/api/share/edit") {
24467
+ const body = JSON.parse(await readBody(req) || "{}");
24468
+ const pool = opts.shareSections ?? opts.profile?.sections ?? {};
24469
+ const out = await handleShareEdit(pool, body);
24470
+ json(res, out.status, out.json);
24471
+ return;
24472
+ }
24473
+ if (req.method === "GET" && route === "/api/public-coding-page") {
24474
+ const out = await handlePublicCodingPageGet(dataDir);
24475
+ json(res, out.status, out.json);
24476
+ return;
24477
+ }
24478
+ if (req.method === "POST" && route === "/api/public-coding-page/generate") {
24479
+ const out = await handlePublicCodingPageGenerate(dataDir, liveProfile);
24480
+ json(res, out.status, out.json);
24481
+ return;
24482
+ }
24483
+ if (req.method === "POST" && route === "/api/public-coding-page/edit") {
24484
+ const body = JSON.parse(await readBody(req) || "{}");
24485
+ const out = await handlePublicCodingPageEdit(dataDir, body);
24486
+ json(res, out.status, out.json);
24487
+ return;
24488
+ }
24489
+ if (req.method === "POST" && route === "/api/public-coding-page/share") {
24490
+ const body = JSON.parse(await readBody(req) || "{}");
24491
+ const out = await handlePublicCodingPageShare(dataDir, body);
24492
+ json(res, out.status, out.json);
24493
+ return;
24494
+ }
24495
+ if (route.startsWith("/api/")) {
24496
+ json(res, 404, { error: `this viewer doesn't serve ${route}` });
24497
+ return;
24498
+ }
24499
+ if (req.method === "GET") {
24500
+ await serveStatic(res, url);
24501
+ return;
24502
+ }
24503
+ res.writeHead(405).end("method not allowed");
23596
24504
  } catch (e) {
23597
- ok = false;
23598
- const error = e.message.slice(0, 200);
23599
- failed.push({ label: st.label, script: st.script, error });
23600
- o.onLine?.(`\u26A0\uFE0F stage FAILED (continuing): ${st.label} \u2014 ${error}`);
24505
+ res.writeHead(500, { "content-type": "application/json" }).end(JSON.stringify({ ok: false, error: String(e) }));
23601
24506
  }
23602
- const sha = st.out ? await fileSha(path31.join(dataRoot, st.out)) : null;
23603
- log.event(st.script.replace(/\.mts$/, ""), { ok, ms: Date.now() - stStart, ...sha ? { sha } : {} });
23604
- }
23605
- log.event("pipeline_completed", { ok: failed.length === 0, failedStages: failed.length, ms: Date.now() - t0 });
23606
- await log.finish();
23607
- return { skipped: false, ingested, notIngestable, failed };
24507
+ });
24508
+ return new Promise((resolve2, reject) => {
24509
+ server.on("error", reject);
24510
+ server.listen(opts.port ?? 0, host, () => {
24511
+ const addr = server.address();
24512
+ const port = typeof addr === "object" && addr ? addr.port : 0;
24513
+ serverUrl = `http://${host}:${port}`;
24514
+ void getCalibration().then((cal) => {
24515
+ if (cal.source === "central" && cal.doc.rubricVersion !== RUBRIC_FINGERPRINT2) {
24516
+ console.warn(`[polymath-society] a newer grading rubric is published (${cal.doc.rubricVersion}; this install: ${RUBRIC_FINGERPRINT2}) \u2014 update the package and re-grade to stay comparable.`);
24517
+ }
24518
+ }).catch(() => {
24519
+ });
24520
+ resolve2({
24521
+ url: serverUrl,
24522
+ port,
24523
+ close: () => new Promise((r) => server.close(() => r())),
24524
+ setProfile: (p) => {
24525
+ liveProfile = p;
24526
+ profileRev++;
24527
+ },
24528
+ setShareSections: (s) => {
24529
+ opts.shareSections = s;
24530
+ },
24531
+ setProgress: (p) => {
24532
+ liveProgress = p;
24533
+ }
24534
+ });
24535
+ });
24536
+ });
23608
24537
  }
23609
24538
 
23610
- // src/cli.ts
23611
- init_manifest();
24539
+ // src/pipeline.ts
24540
+ import { spawn as spawn6 } from "child_process";
24541
+ import os8 from "os";
24542
+ import path36 from "path";
24543
+ import { existsSync as existsSync5, promises as fs31 } from "fs";
24544
+ import { fileURLToPath as fileURLToPath3 } from "url";
24545
+ init_dataHome();
23612
24546
 
23613
- // ../../lib/agents/coding/profile.ts
23614
- import { promises as fs27 } from "fs";
23615
- import path33 from "path";
24547
+ // ../../lib/agents/shared/runLog.ts
24548
+ import { createHash as createHash4 } from "crypto";
24549
+ import { promises as fs30 } from "fs";
24550
+ import path35 from "path";
23616
24551
 
23617
- // ../../lib/agents/coding/walkthrough.ts
23618
- import { promises as fs26 } from "fs";
23619
- import path32 from "path";
23620
- var IDLE_CAP_MS = 12 * 6e4;
23621
- async function readWalkthrough(outDir, sessionId) {
23622
- return fs26.readFile(path32.join(outDir, `${sessionId}.json`), "utf8").then(JSON.parse).catch(() => null);
24552
+ // ../../lib/agents/shared/paths.ts
24553
+ import os7 from "os";
24554
+ import path34 from "path";
24555
+ function polymathHome() {
24556
+ return process.env.POLYMATH_HOME || path34.join(os7.homedir(), ".polymath-society");
23623
24557
  }
23624
-
23625
- // ../../lib/agents/coding/workstyle.ts
23626
- var MIN3 = 6e4;
23627
- var DAY_CUTOFF_H = 5;
23628
- var FLOW_THRESHOLD_MIN = 30;
23629
- var pct = (x) => `${Math.round(x * 100)}%`;
23630
- var fmtN = (n) => n.toLocaleString("en-US");
23631
- var round12 = (x) => Math.round(x * 10) / 10;
23632
- var median = (xs) => xs.length ? [...xs].sort((a, b) => a - b)[Math.floor(xs.length / 2)] : 0;
23633
- function fmtDur2(min) {
23634
- return min >= 60 ? `${round12(min / 60)}h` : `${Math.round(min)}m`;
24558
+ function agentDir(agent) {
24559
+ return path34.join(polymathHome(), agent);
23635
24560
  }
23636
- function clockLabel(h) {
23637
- if (h === 0) return "midnight";
23638
- if (h === 12) return "noon";
23639
- return h < 12 ? `${h}am` : `${h - 12}pm`;
24561
+
24562
+ // ../../lib/agents/shared/runLog.ts
24563
+ function runRefPath() {
24564
+ return path35.join(agentDir("report"), "latest.run.json");
23640
24565
  }
23641
- function pick(ladder, score, fallback = "not enough signal yet") {
23642
- if (score == null) return fallback;
23643
- const r = Math.round(score);
23644
- const keys = Object.keys(ladder).map(Number).sort((a, b) => a - b);
23645
- let chosen = keys[0];
23646
- for (const k of keys) if (k <= r) chosen = k;
23647
- return ladder[chosen];
24566
+ function sha256Hex(s) {
24567
+ return createHash4("sha256").update(s, "utf8").digest("hex");
23648
24568
  }
23649
- var TASTE = {
23650
- 4: "mostly rubber-stamps what the AI produces",
23651
- 5: "an ordinary reviewer's bar",
23652
- 6: "rejects the obviously-bad version and iterates toward something better",
23653
- 7: "holds a real, specific quality bar and pushes past the AI's first answer",
23654
- 8: "makes the call the AI couldn't reach on its own \u2014 opinionated, specific, vindicated",
23655
- 9: "high, particular taste \u2014 names AI slop the moment it appears",
23656
- 10: "brings a developed vision up front, and knows where not to impose it",
23657
- 11: "world-class taste"
23658
- };
23659
- var DELEGATION = {
23660
- 4: "still uneven \u2014 sometimes under-briefs work they had opinions about",
23661
- 6: "roughly calibrated on when to do the thinking themselves vs. let the AI run",
23662
- 8: "well-calibrated \u2014 front-loads the specifiable, reserves correction for genuine AI errors, lets rote run",
23663
- 10: "near-perfect prompt economy \u2014 almost everything knowable is front-loaded"
23664
- };
23665
- var OUTCOMES = {
23666
- 4: "sessions often wrap before a real capability lands",
23667
- 6: "one real, confirmed thing shipped is the typical bar",
23668
- 8: "a substantial, verified capability per session is routine",
23669
- 10: "ships end-to-end-checked work that unblocks a lot downstream"
23670
- };
23671
- var GENERATIVE = {
23672
- 4: "reaches workable answers with effort",
23673
- 6: "real ideas and sound tradeoff reasoning",
23674
- 7: "collapses messy situations to their essence and reasons from first principles",
23675
- 8: "fast collapse to the core, plus its own approach and the exact fix",
23676
- 9: "generates frameworks and reframes others wouldn't reach",
23677
- 10: "out-reasons the tool \u2014 lands insights the AI itself missed"
23678
- };
23679
- var METACOGNITION = {
23680
- 4: "notices friction but mostly just flags it",
23681
- 6: "spots a bottleneck and adjusts how they work for the case at hand",
23682
- 8: "treats their own throughput as an engineering problem \u2014 names recurring friction and restructures to kill it",
23683
- 10: "re-architects the whole way of working mid-stream to get unstuck"
23684
- };
23685
- var EXPERTISE = {
23686
- 2: "defers to the AI on system decisions \u2014 no specific knowledge surfaces",
23687
- 4: "opinions are mostly generic best-practice the AI already had",
23688
- 6: "knows their own stack well and corrects the AI on real systems facts",
23689
- 8: "repeatedly catches what the AI misses with specific systems/tooling calls a junior wouldn't make",
23690
- 9: "deep, specific directives about their own infra a junior wouldn't know",
23691
- 10: "makes counter-intuitive, deep-operating-knowledge calls the AI would have gotten backwards"
23692
- };
23693
- var FRONTIER = {
23694
- 2: "one session at a time, default settings",
23695
- 4: "occasionally runs two things; no structural tooling",
23696
- 6: "routinely parallel, queuing work ahead and organizing sessions",
23697
- 8: "real leverage \u2014 overnight/remote runs, subagents, scripts that drive the AI",
23698
- 10: "builds harnesses and workflows; loops and scales the AI across machines"
23699
- };
23700
- function flowRunsFromSlots(slots) {
23701
- const fSlots = Object.keys(slots).map(Number).filter((s) => slots[String(s)] === "F").sort((a, b) => a - b);
23702
- const runs = [];
23703
- let start = null, prev = null;
23704
- const flush = () => {
23705
- if (start !== null && prev !== null) runs.push((prev - start + 1) * 10);
23706
- };
23707
- for (const s of fSlots) {
23708
- if (prev !== null && s === prev + 1) {
23709
- prev = s;
23710
- } else {
23711
- flush();
23712
- start = s;
23713
- prev = s;
23714
- }
24569
+ async function fileSha(filePath) {
24570
+ try {
24571
+ return sha256Hex(await fs30.readFile(filePath, "utf-8"));
24572
+ } catch {
24573
+ return null;
23715
24574
  }
23716
- flush();
23717
- return runs;
23718
24575
  }
23719
- function buildFlow(runMin, ctx) {
23720
- const sorted = [...runMin].sort((a, b) => a - b);
23721
- const BUCKET_DEFS = [["\u2264 20m", 0, 30], ["30m\u20131h", 30, 60], ["1\u20132h", 60, 120], ["2h+", 120, Infinity]];
23722
- const flowBlocks = BUCKET_DEFS.map(([label, lo, hi]) => {
23723
- const inB = sorted.filter((x) => x >= lo && x < hi);
23724
- return { label, lo, hi, count: inB.length, min: round12(inB.reduce((a, b) => a + b, 0)) };
24576
+ var RPC_TIMEOUT_MS = 15e3;
24577
+ var MAX_CONSECUTIVE_FAILURES = 3;
24578
+ function withTimeout(p) {
24579
+ return Promise.race([
24580
+ p,
24581
+ new Promise((_, rej) => setTimeout(() => rej(new Error("runlog timeout")), RPC_TIMEOUT_MS).unref?.())
24582
+ ]);
24583
+ }
24584
+ async function rpc(url, key, fn, args) {
24585
+ const res = await fetch(`${url.replace(/\/$/, "")}/rest/v1/rpc/${fn}`, {
24586
+ method: "POST",
24587
+ headers: { "content-type": "application/json", apikey: key, authorization: `Bearer ${key}` },
24588
+ body: JSON.stringify(args)
23725
24589
  });
23726
- const deepBlocks = sorted.filter((x) => x >= FLOW_THRESHOLD_MIN).length;
23727
- const flowHoursPerDay = ctx.activeDays ? ctx.flowHoursTotal / ctx.activeDays : 0;
23728
- const deepBlocksPerDay = ctx.activeDays ? deepBlocks / ctx.activeDays : 0;
23729
- const flowCadence = ctx.flowFraction >= 0.45 && flowHoursPerDay >= 1.5 ? "frequent" : ctx.flowFraction < 0.18 ? "rare" : "interspersed";
23730
- const longest = sorted.length ? Math.max(...sorted) : 0;
23731
- const med2 = median(sorted);
23732
- const flowBullets = [];
23733
- flowBullets.push(`${round12(ctx.flowHoursTotal)}h of genuine flow over ${ctx.activeDays} working days \u2014 about ${round12(flowHoursPerDay)}h a day.`);
23734
- flowBullets.push(`${pct(ctx.flowFraction)} of active working time is true flow (rapid rhythm or dictation); the rest is thinking-pauses and switching.`);
23735
- if (flowCadence === "frequent") {
23736
- flowBullets.push(`Deep flow is a daily norm \u2014 ${deepBlocks} runs of ${FLOW_THRESHOLD_MIN}m+, longest ${fmtDur2(longest)}; highly productive once locked in.`);
23737
- } else if (flowCadence === "interspersed") {
23738
- flowBullets.push(`Flow comes in solid bursts \u2014 ${med2}\u2013${longest}m at a time, ${deepBlocks} runs of ${FLOW_THRESHOLD_MIN}m+ \u2014 interspersed with pauses and rapid context-switching across parallel sessions.`);
23739
- } else {
23740
- flowBullets.push(`Flow is sporadic \u2014 mostly short focused windows rather than long unbroken runs.`);
23741
- }
23742
- if (ctx.peakFlowDay) flowBullets.push(`Best day: ${round12(ctx.peakFlowDay.hours)}h in flow (${pct(ctx.peakFlowDay.fraction)} of that day's working time).`);
23743
- return {
23744
- flowSource: ctx.source,
23745
- flowThresholdMin: FLOW_THRESHOLD_MIN,
23746
- flowBlocks,
23747
- blockCount: sorted.length,
23748
- deepBlocks,
23749
- longestBlockMin: round12(longest),
23750
- medianBlockMin: round12(med2),
23751
- flowFraction: Math.round(ctx.flowFraction * 100) / 100,
23752
- flowHoursTotal: round12(ctx.flowHoursTotal),
23753
- flowHoursPerDay: round12(flowHoursPerDay),
23754
- deepBlocksPerDay: round12(deepBlocksPerDay),
23755
- flowCadence,
23756
- peakFlowDay: ctx.peakFlowDay,
23757
- flowBullets
23758
- };
24590
+ if (!res.ok) throw new Error(`${fn} \u2192 HTTP ${res.status}`);
24591
+ const text2 = await res.text();
24592
+ return text2 ? JSON.parse(text2) : null;
23759
24593
  }
23760
- function computeWorkstyle(inp) {
23761
- const { tz, idleGapMin } = inp;
23762
- const idleGapMs = idleGapMin * MIN3;
23763
- const all = [];
23764
- for (const day of inp.dayChart) for (const c of day.conversations) for (const iv of c.intervals) all.push(iv);
23765
- all.sort((a, b) => a[0] - b[0]);
23766
- const parts = (ms2) => {
23767
- const [h, m2, s] = new Date(ms2).toLocaleTimeString("en-GB", { timeZone: tz, hour12: false }).split(":").map(Number);
23768
- return { h, m: m2, s };
23769
- };
23770
- const localDate2 = (ms2) => new Date(ms2).toLocaleDateString("en-CA", { timeZone: tz });
23771
- const sinceCutoff = (ms2) => {
23772
- const { h, m: m2 } = parts(ms2);
23773
- let x = (h - DAY_CUTOFF_H) * 60 + m2;
23774
- if (x < 0) x += 1440;
23775
- return x;
23776
- };
23777
- const logicalDate = (ms2) => localDate2(ms2 - DAY_CUTOFF_H * 36e5);
23778
- const fromCutoff = (x) => {
23779
- const t = (x + DAY_CUTOFF_H * 60) % 1440;
23780
- return `${String(Math.floor(t / 60)).padStart(2, "0")}:${String(Math.round(t % 60)).padStart(2, "0")}`;
23781
- };
23782
- const hourMin = new Array(24).fill(0);
23783
- for (const [a, b] of all) {
23784
- let cur = a;
23785
- while (cur < b) {
23786
- const { h, m: m2, s } = parts(cur);
23787
- const msToNextHour = ((59 - m2) * 60 + (60 - s)) * 1e3;
23788
- const segEnd = Math.min(b, cur + msToNextHour);
23789
- hourMin[h] += (segEnd - cur) / MIN3;
23790
- cur = segEnd;
23791
- }
23792
- }
23793
- const hourly = hourMin.map((min, hour) => ({ hour, min: round12(min) }));
23794
- const totalMin = hourMin.reduce((a, b) => a + b, 0) || 1;
23795
- const sumHours = (hs) => hs.reduce((a, h) => a + hourMin[h], 0);
23796
- const shares = {
23797
- morning: sumHours([5, 6, 7, 8, 9, 10, 11]) / totalMin,
23798
- afternoon: sumHours([12, 13, 14, 15, 16, 17]) / totalMin,
23799
- evening: sumHours([18, 19, 20, 21]) / totalMin,
23800
- lateNight: sumHours([22, 23, 0, 1, 2, 3, 4]) / totalMin
23801
- };
23802
- const peakHours = [...hourMin.keys()].filter((h) => hourMin[h] > 0).sort((a, b) => hourMin[b] - hourMin[a]).slice(0, 3);
23803
- const peak0 = peakHours[0] ?? 12;
23804
- const isNightOwl = shares.lateNight >= 0.2 || peak0 >= 22 || peak0 <= 3;
23805
- let lunchDip = null;
23806
- const dipFloor = totalMin / 40;
23807
- for (const h of [12, 13, 14]) {
23808
- if (hourMin[h] < hourMin[h - 1] * 0.7 && hourMin[h] < hourMin[h + 1] * 0.7 && hourMin[h - 1] > dipFloor && hourMin[h + 1] > dipFloor) {
23809
- if (lunchDip == null || hourMin[h] < hourMin[lunchDip]) lunchDip = h;
23810
- }
23811
- }
23812
- const env = /* @__PURE__ */ new Map();
23813
- for (const [a, b] of all) {
23814
- const ld = logicalDate(a);
23815
- let s = sinceCutoff(a), e = sinceCutoff(b);
23816
- if (e < s) e += 1440;
23817
- const cur = env.get(ld) ?? { first: Infinity, last: -Infinity };
23818
- cur.first = Math.min(cur.first, s);
23819
- cur.last = Math.max(cur.last, e);
23820
- env.set(ld, cur);
23821
- }
23822
- const startsM = [...env.values()].map((v) => v.first);
23823
- const endsM = [...env.values()].map((v) => v.last);
23824
- const daysObserved = env.size;
23825
- const typicalStart = startsM.length ? fromCutoff(median(startsM)) : "\u2014";
23826
- const typicalEnd = endsM.length ? fromCutoff(median(endsM)) : "\u2014";
23827
- const earliestStart = startsM.length ? fromCutoff(Math.min(...startsM)) : "\u2014";
23828
- const latestEnd = endsM.length ? fromCutoff(Math.max(...endsM)) : "\u2014";
23829
- let flow;
23830
- if (inp.flow && inp.flow.days.length) {
23831
- const runs = [];
23832
- for (const d of inp.flow.days) runs.push(...flowRunsFromSlots(d.slots));
23833
- const peak = [...inp.flow.days].sort((a, b) => b.flowHours - a.flowHours)[0];
23834
- flow = buildFlow(runs, {
23835
- source: "flow.json",
23836
- activeDays: inp.flow.totals.activeDays,
23837
- flowFraction: inp.flow.totals.flowFraction,
23838
- flowHoursTotal: inp.flow.totals.flowSlots / 6,
23839
- peakFlowDay: peak ? { date: peak.date, hours: peak.flowHours, fraction: peak.flowFraction } : null
23840
- });
23841
- } else {
23842
- const merged = [];
23843
- for (const [a, b] of all) {
23844
- const last = merged[merged.length - 1];
23845
- if (last && a <= last[1] + idleGapMs) last[1] = Math.max(last[1], b);
23846
- else merged.push([a, b]);
23847
- }
23848
- const blocks = merged.map(([a, b]) => (b - a) / MIN3);
23849
- const totalBlockMin = blocks.reduce((a, b) => a + b, 0) || 1;
23850
- const deepMin = blocks.filter((x) => x >= FLOW_THRESHOLD_MIN).reduce((a, b) => a + b, 0);
23851
- flow = buildFlow(blocks, {
23852
- source: "intervals",
23853
- activeDays: daysObserved,
23854
- flowFraction: deepMin / totalBlockMin,
23855
- flowHoursTotal: deepMin / 60,
23856
- peakFlowDay: null
23857
- });
24594
+ async function writeRef(refPath, ref) {
24595
+ try {
24596
+ await fs30.mkdir(path35.dirname(refPath), { recursive: true });
24597
+ await fs30.writeFile(refPath, JSON.stringify(ref, null, 2), "utf-8");
24598
+ } catch {
23858
24599
  }
23859
- const m = (k) => inp.criteriaMean[k] ?? { mean: null, n: 0 };
23860
- const judgment = [
23861
- { key: "taste", label: "Taste", score: m("taste").mean, n: m("taste").n },
23862
- { key: "delegation", label: "Calibration", score: m("delegation").mean, n: m("delegation").n },
23863
- { key: "generative", label: "Under ambiguity", score: m("generative").mean, n: m("generative").n },
23864
- { key: "metacognition", label: "Self-direction", score: m("metacognition").mean, n: m("metacognition").n },
23865
- { key: "outcomes", label: "Outcomes", score: m("outcomes").mean, n: m("outcomes").n }
23866
- ];
23867
- const rhythmBullets = [];
23868
- const lateTail = /^(0[0-5]|2[3])/.test(latestEnd);
23869
- rhythmBullets.push(`Works roughly ${typicalStart}\u2013${typicalEnd} on a typical day${lateTail ? `, with sessions running as late as ${latestEnd}` : ""}.`);
23870
- if (isNightOwl) {
23871
- rhythmBullets.push(`A night owl \u2014 ${pct(shares.lateNight)} of the work lands after 10pm or in the small hours.`);
23872
- } else if (shares.morning >= shares.afternoon && shares.morning >= shares.evening) {
23873
- rhythmBullets.push(`An early bird \u2014 most of the work happens before noon (${pct(shares.morning)} of active time).`);
23874
- } else if (shares.afternoon >= shares.evening) {
23875
- rhythmBullets.push(`An afternoon worker \u2014 ${pct(shares.afternoon)} of active time falls between noon and 6pm, only ${pct(shares.lateNight)} in the small hours.`);
23876
- } else {
23877
- rhythmBullets.push(`An evening worker \u2014 work concentrates after 6pm (${pct(shares.evening)} of active time).`);
24600
+ }
24601
+ var LiveRunLog = class {
24602
+ constructor(url, key, sessionId, token, nonce, opts) {
24603
+ this.url = url;
24604
+ this.key = key;
24605
+ this.token = token;
24606
+ this.nonce = nonce;
24607
+ this.opts = opts;
24608
+ this.sessionId = sessionId;
23878
24609
  }
23879
- {
23880
- let txt = `Productivity peaks around ${clockLabel(peak0)}`;
23881
- const p1 = peakHours.find((h) => Math.abs(h - peak0) >= 3);
23882
- if (p1 != null) txt += `, with a second push around ${clockLabel(p1)}`;
23883
- rhythmBullets.push(txt + ".");
24610
+ sessionId;
24611
+ seq = 0;
24612
+ chain = Promise.resolve();
24613
+ failures = 0;
24614
+ dead = false;
24615
+ finished = false;
24616
+ post(fn) {
24617
+ if (this.dead) return;
24618
+ this.chain = this.chain.then(async () => {
24619
+ if (this.dead) return;
24620
+ try {
24621
+ await withTimeout(fn());
24622
+ this.failures = 0;
24623
+ } catch {
24624
+ if (++this.failures >= MAX_CONSECUTIVE_FAILURES) this.dead = true;
24625
+ }
24626
+ });
23884
24627
  }
23885
- if (lunchDip != null) rhythmBullets.push(`Takes a visible midday breather around ${clockLabel(lunchDip)}.`);
23886
- const judgmentBullets = [];
23887
- judgmentBullets.push(`Judgment & taste \u2014 ${pick(TASTE, m("taste").mean)}; on delegation, ${pick(DELEGATION, m("delegation").mean)}.`);
23888
- {
23889
- const cad = inp.outcomeCadence ? `ships something meaningful ~${round12(inp.outcomeCadence.perWeek)}\xD7/week (${pct(inp.outcomeCadence.fraction)} of working days), and ` : "";
23890
- judgmentBullets.push(`High-outcome work \u2014 ${cad}${pick(OUTCOMES, m("outcomes").mean)}.`);
24628
+ event(kind, payload = {}) {
24629
+ if (this.dead || this.finished) return;
24630
+ const seq = ++this.seq;
24631
+ const clientAt = (/* @__PURE__ */ new Date()).toISOString();
24632
+ this.post(async () => {
24633
+ await rpc(this.url, this.key, "append_analysis_event", {
24634
+ p_session_id: this.sessionId,
24635
+ p_token: this.token,
24636
+ p_seq: seq,
24637
+ p_kind: kind,
24638
+ p_payload: payload,
24639
+ p_client_at: clientAt
24640
+ });
24641
+ });
23891
24642
  }
23892
- judgmentBullets.push(`Under ambiguity \u2014 ${pick(GENERATIVE, m("generative").mean)}; strongest where there's no ground truth and the task is to invent what to measure.`);
23893
- judgmentBullets.push(`Prioritizing the work \u2014 ${pick(METACOGNITION, m("metacognition").mean)}.`);
23894
- const exp = m("expertise").mean, cog = m("generative").mean, fr = m("frontier").mean;
23895
- const sig = inp.signals;
23896
- let archetype;
23897
- if (exp == null || cog == null) {
23898
- archetype = "Not enough graded signal yet to place the technical profile.";
23899
- } else if (cog - exp >= 1.2) {
23900
- archetype = "Cognition-forward \u2014 reasoning runs ahead of hands-on systems depth: thinks like a senior, with some stack-specific knowledge still leveling up.";
23901
- } else if (exp - cog >= 1.2) {
23902
- archetype = "Specialist \u2014 deep, specific systems and architecture knowledge is the anchor, ahead of raw abstraction.";
23903
- } else if (exp >= 8 && cog >= 8) {
23904
- archetype = "Deep and sharp \u2014 strong systems knowledge matched by top-tier reasoning.";
23905
- } else {
23906
- archetype = "Balanced operator \u2014 solid systems knowledge and reasoning move in step, both clearly competent.";
24643
+ async finish() {
24644
+ if (this.finished) return;
24645
+ this.finished = true;
24646
+ const legacy = this.opts.artifacts === void 0;
24647
+ const list = legacy ? [path35.join(agentDir("report"), "latest.json")] : typeof this.opts.artifacts === "function" ? await this.opts.artifacts().catch(() => []) : this.opts.artifacts;
24648
+ const refPath = this.opts.refPath ?? runRefPath();
24649
+ const shas = {};
24650
+ const ordered = [];
24651
+ let firstRaw = null;
24652
+ for (const p of list) {
24653
+ let raw;
24654
+ try {
24655
+ raw = await fs30.readFile(p, "utf-8");
24656
+ } catch {
24657
+ continue;
24658
+ }
24659
+ if (firstRaw === null) firstRaw = raw;
24660
+ const sha = sha256Hex(raw);
24661
+ shas[path35.relative(path35.dirname(refPath), p).split(path35.sep).join("/")] = sha;
24662
+ ordered.push(sha);
24663
+ }
24664
+ this.post(async () => {
24665
+ if (ordered.length === 0) throw new Error("no artifacts to close against");
24666
+ const commitment = legacy ? sha256Hex(this.nonce + firstRaw) : sha256Hex(this.nonce + ordered.join(""));
24667
+ await rpc(this.url, this.key, "close_analysis_session", {
24668
+ p_session_id: this.sessionId,
24669
+ p_token: this.token,
24670
+ p_commitment: commitment
24671
+ });
24672
+ });
24673
+ await this.chain.catch(() => {
24674
+ });
24675
+ const ref = this.dead || ordered.length === 0 ? { sessionId: null } : {
24676
+ sessionId: this.sessionId,
24677
+ artifacts: shas,
24678
+ ...legacy ? { reportSha256: ordered[0] } : {},
24679
+ closedAt: (/* @__PURE__ */ new Date()).toISOString()
24680
+ };
24681
+ await writeRef(refPath, ref);
23907
24682
  }
23908
- const gap = exp != null && cog != null ? cog > exp + 0.8 ? "noticeably ahead of the stack-specific knowledge" : exp > cog + 0.8 ? "with the systems depth running slightly ahead" : "roughly in step with the systems depth" : "";
23909
- const sigBits = [];
23910
- if (sig.maxConcurrency >= 2) sigBits.push(`up to \xD7${sig.maxConcurrency} sessions at once`);
23911
- if (sig.subagents > 0) sigBits.push(`${fmtN(sig.subagents)} subagent spawns`);
23912
- if (sig.queueOps > 0) sigBits.push(`${fmtN(sig.queueOps)} queue-ahead ops`);
23913
- if (sig.mcpTools > 0) sigBits.push(`${sig.mcpTools} MCP tool${sig.mcpTools > 1 ? "s" : ""}`);
23914
- const sigSentence = sigBits.length ? sigBits.join(", ") : "mostly single-session work";
23915
- const experienced = sig.maxConcurrency >= 3 && (sig.queueOps > 50 || sig.subagents > 0 || sig.mcpTools > 0);
23916
- const technical = {
23917
- expertise: exp,
23918
- cognition: cog,
23919
- frontier: fr,
23920
- signals: sig,
23921
- archetype,
23922
- bullets: [
23923
- `Systems & architecture \u2014 ${pick(EXPERTISE, exp)}.`,
23924
- `Raw cognition \u2014 ${pick(GENERATIVE, cog)}${gap ? `, ${gap}` : ""}.`,
23925
- `Agent fluency \u2014 ${experienced ? "clearly an experienced agent operator; " : ""}${pick(FRONTIER, fr)} (${sigSentence}).`
23926
- ]
23927
- };
24683
+ };
24684
+ function inertRunLog(refPath) {
23928
24685
  return {
23929
- tz,
23930
- daysObserved,
23931
- activeHours: round12(totalMin / 60),
23932
- typicalStart,
23933
- typicalEnd,
23934
- earliestStart,
23935
- latestEnd,
23936
- hourly,
23937
- peakHours,
23938
- shares,
23939
- isNightOwl,
23940
- lunchDip,
23941
- rhythmBullets,
23942
- ...flow,
23943
- judgment,
23944
- judgmentBullets,
23945
- technical
24686
+ sessionId: null,
24687
+ event() {
24688
+ },
24689
+ async finish() {
24690
+ await writeRef(refPath, { sessionId: null });
24691
+ }
23946
24692
  };
23947
24693
  }
24694
+ async function startRunLog(clientInfo = {}, opts = {}) {
24695
+ const url = opts.supabaseUrl ?? process.env.NEXT_PUBLIC_SUPABASE_URL;
24696
+ const key = opts.supabaseAnonKey ?? process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
24697
+ const refPath = opts.refPath ?? runRefPath();
24698
+ if (!url || !key) return inertRunLog(refPath);
24699
+ try {
24700
+ const data = await withTimeout(
24701
+ rpc(url, key, "begin_analysis_session", {
24702
+ p_client_info: { platform: process.platform, ...clientInfo }
24703
+ })
24704
+ );
24705
+ const d = data ?? {};
24706
+ if (!d.session_id || !d.token || !d.nonce) return inertRunLog(refPath);
24707
+ return new LiveRunLog(url, key, d.session_id, d.token, d.nonce, opts);
24708
+ } catch {
24709
+ return inertRunLog(refPath);
24710
+ }
24711
+ }
23948
24712
 
23949
- // ../../lib/agents/coding/benchmarks.ts
23950
- var BEST = DEFAULT_CALIBRATION.codingBenchmarks;
23951
-
23952
- // ../../lib/agents/coding/profile.ts
23953
- var ROOT2 = process.cwd();
23954
- var CODING_DIR2 = process.env.POLYMATH_DATA_DIR ? path33.join(process.env.POLYMATH_DATA_DIR, "coding") : path33.join(ROOT2, ".data", "coding");
23955
- var UMETA = /* @__PURE__ */ new Map();
23956
- async function userMeta(sessionId, file2) {
23957
- const hit = UMETA.get(sessionId);
23958
- if (hit) return hit;
23959
- const msgs = await extractUserMessages(file2).catch(() => []);
23960
- const meta = msgs.map((m) => ({ t: m.t, words: typedWords(m.text, m.gapMs), key: m.uuid ?? `${m.t}|${m.text}` }));
23961
- UMETA.set(sessionId, meta);
23962
- return meta;
24713
+ // src/pipeline.ts
24714
+ var MODULE_DIR2 = path36.dirname(fileURLToPath3(import.meta.url));
24715
+ function machineBudget(totalMemBytes = os8.totalmem(), cpus = os8.availableParallelism?.() ?? os8.cpus().length, envOverride = process.env.POLYMATH_CONC) {
24716
+ const envB = Number(envOverride);
24717
+ if (Number.isFinite(envB) && envB >= 1) return Math.min(32, Math.floor(envB));
24718
+ const byMem = Math.floor(totalMemBytes / 2 ** 30 * 0.35 / 0.45);
24719
+ return Math.max(2, Math.min(16, cpus - 1, byMem));
24720
+ }
24721
+ function apportionHeavy(budget) {
24722
+ const grade = Math.max(2, Math.floor(budget * 0.45));
24723
+ const digest = Math.max(1, Math.floor(budget * 0.17));
24724
+ const walkthrough = Math.max(1, Math.floor(budget * 0.17));
24725
+ const delegation = Math.max(1, budget - grade - digest - walkthrough - 1);
24726
+ return { grade, digest, walkthrough, delegation };
24727
+ }
24728
+ function stages(o) {
24729
+ const model = o.model ?? "sonnet";
24730
+ const gradeModel = o.model ?? "haiku";
24731
+ const budget = machineBudget();
24732
+ const h = apportionHeavy(budget);
24733
+ const conc = String(o.conc ?? h.grade);
24734
+ const buildArgs = [];
24735
+ if (o.codex === false) buildArgs.push("--no-codex");
24736
+ if (o.idleGapMin != null) buildArgs.push("--idle", String(o.idleGapMin));
24737
+ const gradeArgs = ["--all", "--model", gradeModel, "--conc", conc];
24738
+ if (o.regrade) gradeArgs.push("--regrade");
24739
+ return [
24740
+ // ---- deterministic foundation (fast, free) ----
24741
+ { script: "coding-build.mts", label: "Scrape + classify your sessions", llm: false, args: buildArgs, out: "coding/sessions.json" },
24742
+ // ---- deterministic metrics: all read ONLY sessions.json, disjoint outputs ----
24743
+ { script: "coding-flow.mts", label: "Flow-state slots", llm: false, args: [], out: "coding/flow.json", batch: "metrics" },
24744
+ { script: "coding-focus.mts", label: "Focus map + breaks (deterministic)", llm: false, args: ["--skip-llm"], out: "coding/focus.json", batch: "metrics" },
24745
+ { script: "coding-gap-dist.mts", label: "Inter-prompt gap distribution", llm: false, args: [], out: "coding/gap-dist.json", batch: "metrics" },
24746
+ { script: "coding-frontier.mts", label: "Frontier tech arsenal", llm: false, args: [], out: "coding/frontier.json", batch: "metrics" },
24747
+ { script: "coding-projects.mts", label: "Projects + contributions", llm: false, args: [], out: "coding/projects.json", batch: "metrics" },
24748
+ // ---- THE HEAVY BATCH — grading + everything that needs ONLY sessions.json.
24749
+ // Digests, walkthroughs, frontier detail, and delegation never read grades,
24750
+ // so they run WHILE grading runs (grading is the wall-clock giant; these
24751
+ // finish inside its shadow). Budget: grade 8 + digest 3 + walkthrough 3 +
24752
+ // two single-call stages ≈ 16 peak subprocesses (measured-safe envelope).
24753
+ { script: "coding-grade.mts", label: "AI-grade every substantial session", llm: true, args: gradeArgs, batch: "heavy" },
24754
+ { script: "coding-day-digest.mts", label: "Day-by-day digests", llm: true, args: ["--model", model, "--conc", String(h.digest)], out: "coding/day-digest.json", batch: "heavy" },
24755
+ { script: "coding-walkthrough.mts", label: "Per-session walkthroughs", llm: true, args: ["--model", model, "--conc", String(h.walkthrough)], batch: "heavy" },
24756
+ { script: "coding-frontier-detail.mts", label: "What you're doing at the frontier", llm: true, args: [], out: "coding/frontier-detail.json", batch: "heavy" },
24757
+ { script: "coding-delegation.mts", label: "Delegation patterns", llm: true, args: ["--model", model, "--conc", String(h.delegation)], out: "coding/delegation-rollup.json", batch: "heavy" },
24758
+ // ---- corpus aggregate (reads grades; deterministic rollup) ----
24759
+ { script: "coding-aggregate.mts", label: "Corpus aggregate \u2014 ability ceiling + flow", llm: false, args: [], out: "coding/aggregate.json" },
24760
+ // ---- grade readers (grades/* is complete once aggregate ran) ----
24761
+ { script: "coding-agglomerate.mts", label: "Agglomerated criteria + signature moves", llm: true, args: ["--model", model], out: "coding/agglomerate.json", batch: "grade-readers" },
24762
+ { script: "coding-expertise.mts", label: "Domain-expertise map", llm: true, args: ["--conc", String(Math.max(2, budget - 1))], out: "coding/expertise.json", batch: "grade-readers" },
24763
+ // ---- final synthesis (reads the finished aggregates + batch outputs) ----
24764
+ { script: "coding-coaching.mts", label: "Coaching + feel-seen copy", llm: true, args: [], out: "coding/coaching.json", batch: "synthesis" },
24765
+ { script: "coding-gap.mts", label: "Gap-to-close vs best practice", llm: true, args: [], out: "coding/gap.json", batch: "synthesis" },
24766
+ // nutshell stays LAST + alone: it merges INTO aggregate.json while the two
24767
+ // above read the compiled profile — racing them re-reads mid-write.
24768
+ { script: "coding-nutshell.mts", label: "Big-picture nutshell", llm: true, args: [], out: "coding/aggregate.json" }
24769
+ // merges bigPicture INTO aggregate.json
24770
+ ];
24771
+ }
24772
+ function bundledPipelineDir() {
24773
+ const d = path36.join(MODULE_DIR2, "pipeline");
24774
+ return existsSync5(path36.join(d, "coding-build.js")) ? d : null;
24775
+ }
24776
+ function stageInvocation(repoRoot, scriptRel, args) {
24777
+ const scriptAbs = path36.join(repoRoot, "scripts", scriptRel);
24778
+ if (existsSync5(scriptAbs)) {
24779
+ const local = path36.join(repoRoot, "node_modules", ".bin", "tsx");
24780
+ if (existsSync5(local)) return { cmd: local, argv: [scriptAbs, ...args], cwd: repoRoot };
24781
+ return { cmd: "npx", argv: ["tsx", scriptAbs, ...args], cwd: repoRoot };
24782
+ }
24783
+ const bundled = bundledPipelineDir();
24784
+ if (bundled) {
24785
+ const js = path36.join(bundled, scriptRel.replace(/\.mts$/, ".js"));
24786
+ return { cmd: process.execPath, argv: [js, ...args], cwd: process.cwd() };
24787
+ }
24788
+ throw new Error(`pipeline stage ${scriptRel}: neither repo scripts/ nor bundled dist/pipeline/ found`);
24789
+ }
24790
+ function runStage(repoRoot, st, env, onLine) {
24791
+ return new Promise((resolve2, reject) => {
24792
+ const { cmd, argv, cwd } = stageInvocation(repoRoot, st.script, st.args);
24793
+ const child = spawn6(cmd, argv, { cwd, env, stdio: ["ignore", "pipe", "pipe"] });
24794
+ const pump = (buf) => {
24795
+ if (!onLine) return;
24796
+ for (const line of buf.toString().split(/\r?\n/)) if (line.trim()) onLine(line);
24797
+ };
24798
+ child.stdout.on("data", pump);
24799
+ child.stderr.on("data", pump);
24800
+ child.on("error", reject);
24801
+ child.on("close", (code) => code === 0 ? resolve2() : reject(new Error(`${st.script} exited with code ${code}`)));
24802
+ });
23963
24803
  }
23964
- var GRADES2 = path33.join(CODING_DIR2, "grades");
23965
- async function readJson2(p, fallback) {
23966
- return fs27.readFile(p, "utf8").then((s) => JSON.parse(s)).catch(() => fallback);
24804
+ function hasPipeline(repoRoot) {
24805
+ return existsSync5(path36.join(repoRoot, "scripts", "coding-build.mts")) || bundledPipelineDir() != null;
23967
24806
  }
23968
- function cadenceScore(fraction, multiRatio) {
23969
- let s;
23970
- if (fraction >= 0.85) s = 10;
23971
- else if (fraction >= 0.6) s = 9;
23972
- else if (fraction >= 0.45) s = 8;
23973
- else if (fraction >= 0.3) s = 7;
23974
- else if (fraction >= 0.2) s = 6;
23975
- else if (fraction >= 0.12) s = 5;
23976
- else if (fraction >= 0.06) s = 4;
23977
- else s = 3;
23978
- if (s >= 10 && multiRatio >= 0.3) s = 11;
23979
- return s;
24807
+ function codingDataRoot(repoRoot) {
24808
+ if (!process.env.POLYMATH_DATA_DIR && existsSync5(path36.join(repoRoot, "scripts", "coding-build.mts"))) {
24809
+ return path36.join(repoRoot, ".data");
24810
+ }
24811
+ return resolveDataRoot();
23980
24812
  }
23981
- function distOf3(takes) {
23982
- const vals = takes.map((t) => t.score ?? t.best).filter((v) => v != null);
23983
- const n = vals.length;
23984
- if (!n) return { n: 0, observed: 0, mean: null, median: null, hist: [] };
23985
- const observed = takes.filter((t) => t.score != null).length;
23986
- const mean2 = Math.round(vals.reduce((a, b) => a + b, 0) / n * 100) / 100;
23987
- const sorted = [...vals].sort((a, b) => a - b);
23988
- const median2 = n % 2 ? sorted[(n - 1) / 2] : (sorted[n / 2 - 1] + sorted[n / 2]) / 2;
23989
- const h = /* @__PURE__ */ new Map();
23990
- for (const v of vals) h.set(Math.round(v), (h.get(Math.round(v)) ?? 0) + 1);
23991
- const hist = [...h.keys()].sort((a, b) => b - a).map((level) => ({ level, count: h.get(level) }));
23992
- return { n, observed, mean: mean2, median: median2, hist };
24813
+ async function finalCodingArtifacts(codingDir) {
24814
+ const files = await fs31.readdir(codingDir).catch(() => []);
24815
+ return files.filter((f) => f.endsWith(".json") && f !== "report-run.json" && !f.startsWith(".")).sort().map((f) => path36.join(codingDir, f));
23993
24816
  }
23994
- async function compileCodingProfile() {
23995
- const allRecords = await readJson2(path33.join(CODING_DIR2, "sessions.json"), []);
23996
- const dupIds = new Set(allRecords.filter((s) => s.duplicateOf).map((s) => s.sessionId));
23997
- const sessions = allRecords.filter((s) => !s.duplicateOf);
23998
- const conc = await readJson2(path33.join(CODING_DIR2, "concurrency.json"), null);
23999
- const renames = await readJson2(path33.join(CODING_DIR2, "renames.json"), []);
24000
- const byId = new Map(sessions.map((s) => [s.sessionId, s]));
24001
- let gradeFiles = [];
24817
+ function upToDateSkip(i) {
24818
+ const pending2 = i.gradableIds.filter((id) => !i.gradedIds.has(id)).length;
24819
+ const skip = !i.regrade && i.threshold > 0 && i.hasBigPicture && pending2 < i.threshold;
24820
+ return { skip, pending: pending2 };
24821
+ }
24822
+ async function evalUpToDate(codingDir, threshold, regrade) {
24002
24823
  try {
24003
- gradeFiles = (await fs27.readdir(GRADES2)).filter((f) => f.endsWith(".json"));
24824
+ const { partition: partition2 } = await Promise.resolve().then(() => (init_gate2(), gate_exports));
24825
+ const sessions = JSON.parse(await fs31.readFile(path36.join(codingDir, "sessions.json"), "utf8"));
24826
+ const { gradable } = partition2(sessions.filter((s) => s.klass === "interactive" && !s.duplicateOf));
24827
+ const graded = new Set(
24828
+ (await fs31.readdir(path36.join(codingDir, "grades")).catch(() => [])).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -5))
24829
+ );
24830
+ const agg = JSON.parse(await fs31.readFile(path36.join(codingDir, "aggregate.json"), "utf8").catch(() => "{}"));
24831
+ return upToDateSkip({
24832
+ gradableIds: gradable.map((s) => s.sessionId),
24833
+ gradedIds: graded,
24834
+ hasBigPicture: typeof agg.bigPicture === "string" && agg.bigPicture.trim().length > 0,
24835
+ threshold,
24836
+ regrade
24837
+ });
24004
24838
  } catch {
24839
+ return { skip: false, pending: -1 };
24005
24840
  }
24006
- const grades = [];
24007
- for (const f of gradeFiles) {
24008
- const g = await readJson2(path33.join(GRADES2, f), null);
24009
- if (g && byId.has(g.sessionId)) grades.push(g);
24841
+ }
24842
+ async function runPipeline(o) {
24843
+ if (!hasPipeline(o.repoRoot)) {
24844
+ throw new Error(
24845
+ "full-pipeline refresh: neither the polymath repo (scripts/coding-*.mts at " + o.repoRoot + ") nor the bundled pipeline (dist/pipeline/) was found \u2014 the package build is broken."
24846
+ );
24010
24847
  }
24011
- const takesByCriterion = /* @__PURE__ */ new Map();
24012
- for (const g of grades) {
24013
- for (const c of g.criteria) {
24014
- const t = {
24015
- sessionId: g.sessionId,
24016
- title: g.title || byId.get(g.sessionId)?.title || g.sessionId,
24017
- date: (g.date || "").slice(0, 10),
24018
- score: c.score,
24019
- best: c.bestEstimate,
24020
- instance: c.instance,
24021
- why: c.why,
24022
- quotes: c.quotes,
24023
- confidence: c.confidence
24024
- };
24025
- if (c.score == null && c.bestEstimate == null) continue;
24026
- (takesByCriterion.get(c.key) ?? takesByCriterion.set(c.key, []).get(c.key)).push(t);
24848
+ const dataRoot = codingDataRoot(o.repoRoot);
24849
+ const env = { ...process.env, POLYMATH_RESILIENT: "1", POLYMATH_DATA_DIR: dataRoot };
24850
+ if (!o.overnight) env.POLYMATH_RESILIENT_NO_WINDOW = "1";
24851
+ if (o.overnight && process.platform === "darwin") {
24852
+ try {
24853
+ const { spawn: spawn10 } = await import("node:child_process");
24854
+ spawn10("caffeinate", ["-ims", "-w", String(process.pid)], { detached: true, stdio: "ignore" }).unref();
24855
+ } catch {
24027
24856
  }
24028
24857
  }
24029
- const criteria = CODING_CRITERIA.map((c) => {
24030
- const takes = (takesByCriterion.get(c.key) ?? []).sort((a, b) => (b.score ?? b.best ?? 0) - (a.score ?? a.best ?? 0));
24031
- return { key: c.key, label: c.label, graded: c.graded, definition: c.definition, dist: distOf3(takes), takes };
24032
- });
24033
- const tz = conc?.tz || "America/Los_Angeles";
24034
- const localDate2 = (iso) => iso ? new Date(Date.parse(iso)).toLocaleDateString("en-CA", { timeZone: tz }) : "";
24035
- let outcomeCadence = null;
24036
- {
24037
- const activeDates = new Set(sessions.map((s) => localDate2(s.start)).filter(Boolean));
24038
- const meaningfulPerDay = /* @__PURE__ */ new Map();
24039
- for (const g of grades) {
24040
- const date = localDate2(byId.get(g.sessionId)?.start || g.date || "");
24041
- if (!date) continue;
24042
- const out = g.criteria.find((c) => c.key === "outcomes")?.score ?? null;
24043
- const meta = g.criteria.find((c) => c.key === "metacognition")?.score ?? null;
24044
- if (out != null && out >= 6 || meta != null && meta >= 8) meaningfulPerDay.set(date, (meaningfulPerDay.get(date) ?? 0) + 1);
24045
- }
24046
- const activeDays = activeDates.size;
24047
- const meaningfulDays = meaningfulPerDay.size;
24048
- const multiMeaningfulDays = [...meaningfulPerDay.values()].filter((n) => n >= 2).length;
24049
- if (activeDays > 0) {
24050
- const dates2 = [...activeDates].sort();
24051
- const spanDays = Math.max(1, (Date.parse(dates2[dates2.length - 1]) - Date.parse(dates2[0])) / 864e5 + 1);
24052
- const fraction = meaningfulDays / activeDays;
24053
- outcomeCadence = {
24054
- activeDays,
24055
- meaningfulDays,
24056
- multiMeaningfulDays,
24057
- fraction: Math.round(fraction * 100) / 100,
24058
- perWeek: Math.round(meaningfulDays / (spanDays / 7) * 10) / 10,
24059
- score: cadenceScore(fraction, meaningfulDays ? multiMeaningfulDays / meaningfulDays : 0)
24060
- };
24858
+ const list = stages(o).filter((st) => !o.deterministicOnly || !st.llm);
24859
+ const codingDir = path36.join(dataRoot, "coding");
24860
+ const central = centralConfig();
24861
+ const t0 = Date.now();
24862
+ const log = await startRunLog(
24863
+ { app: "npm-package", pipeline: "coding", stages: list.length },
24864
+ {
24865
+ supabaseUrl: central.supabaseUrl,
24866
+ supabaseAnonKey: central.supabaseAnonKey,
24867
+ artifacts: () => finalCodingArtifacts(codingDir),
24868
+ refPath: path36.join(codingDir, "report-run.json")
24869
+ // next to the served artifacts
24061
24870
  }
24871
+ );
24872
+ const failed = [];
24873
+ const groups = [];
24874
+ for (const st of list) {
24875
+ const g = groups[groups.length - 1];
24876
+ if (g && st.batch && g[0].batch === st.batch) g.push(st);
24877
+ else groups.push([st]);
24062
24878
  }
24063
- const perDayMeta = new Map((conc?.perDay ?? []).map((d) => [d.date, d]));
24064
- const gradeById = new Map(grades.map((g) => [g.sessionId, g]));
24065
- const dayMap = /* @__PURE__ */ new Map();
24066
- for (const s of sessions) {
24067
- const date = localDate2(s.start);
24068
- if (!date) continue;
24069
- let day = dayMap.get(date);
24070
- if (!day) {
24071
- const m = perDayMeta.get(date);
24072
- day = { date, peakConcurrency: m?.peakConcurrency ?? 1, sessionsStarted: m?.sessionsStarted ?? 0, activeMin: m?.activeMin ?? 0, sessions: [] };
24073
- dayMap.set(date, day);
24074
- }
24075
- const g = gradeById.get(s.sessionId);
24076
- const findings = {};
24077
- if (g) {
24078
- for (const c of g.criteria) if (c.instance && (c.score != null || c.bestEstimate != null)) findings[c.key] = { score: c.score ?? c.bestEstimate, instance: c.instance, why: c.why || "", quotes: c.quotes || [] };
24879
+ const envThreshold = Number(process.env.POLYMATH_MIN_NEW_SESSIONS);
24880
+ const threshold = o.minNewSessions ?? (Number.isFinite(envThreshold) && envThreshold >= 0 ? envThreshold : 5);
24881
+ let skippedLlm;
24882
+ const stageTimes = [];
24883
+ let stageNo = 0;
24884
+ for (const group of groups) {
24885
+ await Promise.all(group.map(async (st) => {
24886
+ if (st.llm && skippedLlm) {
24887
+ o.onStage?.(++stageNo, list.length, `${st.label} \u2014 up to date, skipped`, st.llm);
24888
+ log.event(st.script.replace(/\.mts$/, ""), { ok: true, ms: 0, skipped: true });
24889
+ stageTimes.push({ script: st.script, label: st.label, ms: 0, ok: true, skipped: true });
24890
+ return;
24891
+ }
24892
+ o.onStage?.(++stageNo, list.length, group.length > 1 ? `${st.label} (parallel \xD7${group.length})` : st.label, st.llm);
24893
+ const stStart = Date.now();
24894
+ let ok = true;
24895
+ const tag = group.length > 1 ? `[${st.script.replace(/^coding-|\.mts$/g, "")}] ` : "";
24896
+ try {
24897
+ await runStage(o.repoRoot, st, env, o.onLine && ((line) => o.onLine(`${tag}${line}`)));
24898
+ } catch (e) {
24899
+ ok = false;
24900
+ const error = e.message.slice(0, 200);
24901
+ failed.push({ label: st.label, script: st.script, error });
24902
+ o.onLine?.(`\u26A0\uFE0F stage FAILED (continuing): ${st.label} \u2014 ${error}`);
24903
+ }
24904
+ const sha = st.out ? await fileSha(path36.join(dataRoot, st.out)) : null;
24905
+ log.event(st.script.replace(/\.mts$/, ""), { ok, ms: Date.now() - stStart, ...sha ? { sha } : {} });
24906
+ stageTimes.push({ script: st.script, label: st.label, ms: Date.now() - stStart, ok });
24907
+ }));
24908
+ if (!o.deterministicOnly && !skippedLlm && group[0].script === "coding-build.mts") {
24909
+ const gate2 = await evalUpToDate(codingDir, threshold, o.regrade);
24910
+ if (gate2.skip) {
24911
+ skippedLlm = { pending: gate2.pending, threshold };
24912
+ o.onLine?.(
24913
+ `\u2713 report is up to date \u2014 ${gate2.pending} new session(s) since the last full run (below the ${threshold}-session threshold). Skipping the AI stages; free metrics still refresh. They'll be analyzed once ${threshold}+ accumulate (POLYMATH_MIN_NEW_SESSIONS=0 or --regrade to force now).`
24914
+ );
24915
+ }
24079
24916
  }
24080
- day.sessions.push({ sessionId: s.sessionId, title: s.title, gradable: !!g, findings });
24081
24917
  }
24082
- const timeline = [...dayMap.values()].sort((a, b) => b.date.localeCompare(a.date));
24083
- const levelHist = conc?.levelHistogramMin ?? {};
24084
- const sumFrom = (min) => Object.entries(levelHist).filter(([k]) => Number(k) >= min).reduce((a, [, v]) => a + v, 0);
24085
- const topWindows = (conc?.segments ?? []).slice().sort((a, b) => b.level - a.level || b.minutes - a.minutes).slice(0, 12).map((s) => ({ start: s.start, end: s.end, minutes: s.minutes, level: s.level, titles: [...new Set(s.sessions.map((x) => x.title))] }));
24086
- const parallelism = {
24087
- maxConcurrency: conc?.maxConcurrency ?? 0,
24088
- levelHistogramMin: levelHist,
24089
- minutesAt2plus: Math.round(sumFrom(2)),
24090
- minutesAt6plus: Math.round(sumFrom(6)),
24091
- topWindows,
24092
- queueOps: sessions.reduce((a, s) => a + s.queueOps, 0),
24093
- renames,
24094
- renamedSessions: sessions.filter((s) => s.renamed).length,
24095
- tz: conc?.tz ?? "",
24096
- idleGapMin: conc?.idleGapMin ?? 5
24097
- };
24098
- const dates = sessions.map((s) => s.start).filter(Boolean).sort();
24099
- const models = /* @__PURE__ */ new Map();
24100
- for (const s of sessions) for (const [m, n] of Object.entries(s.models)) models.set(m, (models.get(m) ?? 0) + n);
24101
- const topDays = (conc?.perDay ?? []).slice().sort((a, b) => b.activeMin - a.activeMin).slice(0, 12).map((d) => ({ date: d.date, activeMin: d.activeMin, sessionsStarted: d.sessionsStarted, peakConcurrency: d.peakConcurrency, firstStart: d.firstStart, lastEnd: d.lastEnd, spanMin: d.spanMin }));
24102
- const lateNight = (conc?.perDay ?? []).filter((d) => {
24103
- const h = Number(d.firstStart.slice(0, 2));
24104
- const e = Number(d.lastEnd.slice(0, 2));
24105
- return e >= 22 || e < 5 || h < 5;
24106
- }).length;
24107
- const throughput = {
24108
- sessions: sessions.length,
24109
- activeHours: Math.round(sessions.reduce((a, s) => a + s.activeMin, 0) / 60 * 10) / 10,
24110
- dateRange: { from: (dates[0] || "").slice(0, 10), to: (dates[dates.length - 1] || "").slice(0, 10) },
24111
- topDays,
24112
- toolCalls: sessions.reduce((a, s) => a + s.toolCalls, 0),
24113
- subagents: sessions.reduce((a, s) => a + s.subagentSpawns, 0),
24114
- models: Object.fromEntries([...models.entries()].sort((a, b) => b[1] - a[1])),
24115
- lateNightSessions: lateNight
24116
- };
24117
- const agglomeration = await readJson2(path33.join(CODING_DIR2, "agglomerate.json"), null);
24118
- const dayDigest = await readJson2(path33.join(CODING_DIR2, "day-digest.json"), null);
24119
- if (dayDigest?.days) dayDigest.days = dayDigest.days.map((day) => {
24120
- const convs = day.conversations.filter((c) => byId.has(c.sessionId));
24121
- return { ...day, conversations: convs, conversationsTouched: convs.length, totalMessages: convs.reduce((a, c) => a + c.messageCount, 0) };
24122
- }).filter((day) => day.conversations.length > 0);
24123
- const dayChart = await readJson2(path33.join(CODING_DIR2, "day-chart.json"), []);
24124
- const intervalsBy = /* @__PURE__ */ new Map();
24125
- const titleBy = /* @__PURE__ */ new Map();
24126
- const fileById = new Map(sessions.map((s) => [s.sessionId, s.file]));
24127
- for (const day of dayChart) for (const c of day.conversations) {
24128
- const arr = intervalsBy.get(c.sessionId) ?? [];
24129
- arr.push(...c.intervals);
24130
- intervalsBy.set(c.sessionId, arr);
24131
- titleBy.set(c.sessionId, c.title);
24918
+ log.event("pipeline_completed", { ok: failed.length === 0, failedStages: failed.length, ms: Date.now() - t0, ...skippedLlm ? { skippedLlm: true, pending: skippedLlm.pending } : {} });
24919
+ await log.finish();
24920
+ const totalMs = Date.now() - t0;
24921
+ const fmt = (ms2) => ms2 >= 9e4 ? `${(ms2 / 6e4).toFixed(1)}m` : `${Math.round(ms2 / 1e3)}s`;
24922
+ try {
24923
+ const record = {
24924
+ at: new Date(t0).toISOString(),
24925
+ kind: skippedLlm ? "skip" : o.deterministicOnly ? "deterministic" : "full",
24926
+ totalMs,
24927
+ stages: stageTimes,
24928
+ failed: failed.length,
24929
+ ...skippedLlm ? { pendingSessions: skippedLlm.pending } : {},
24930
+ model: o.model ?? "sonnet(+haiku grade)",
24931
+ budget: machineBudget()
24932
+ };
24933
+ await fs31.appendFile(path36.join(codingDir, "run-times.jsonl"), JSON.stringify(record) + "\n");
24934
+ const slowest = stageTimes.filter((s) => !s.skipped).sort((a, b) => b.ms - a.ms).slice(0, 3).map((s) => `${s.script.replace(/^coding-|\.mts$/g, "")} ${fmt(s.ms)}`).join(" \xB7 ");
24935
+ o.onLine?.(`\u23F1 run took ${fmt(totalMs)} (${record.kind}) \u2014 slowest: ${slowest} \xB7 ledger: .data/coding/run-times.jsonl`);
24936
+ } catch {
24132
24937
  }
24133
- const listOverlapMs = (A, B) => {
24134
- let ms2 = 0;
24135
- for (const [a0, a1] of A) for (const [b0, b1] of B) {
24136
- const lo = Math.max(a0, b0), hi = Math.min(a1, b1);
24137
- if (hi > lo) ms2 += hi - lo;
24138
- }
24139
- return ms2;
24140
- };
24141
- const walkthroughs = {};
24142
- const wdir = path33.join(CODING_DIR2, "walkthroughs");
24143
- for (const f of await fs27.readdir(wdir).catch(() => [])) {
24144
- if (!f.endsWith(".json")) continue;
24145
- const w = await readWalkthrough(wdir, f.replace(".json", ""));
24146
- if (!w || !byId.has(w.sessionId)) continue;
24147
- const own = intervalsBy.get(w.sessionId) ?? [];
24148
- const ownTitle = titleBy.get(w.sessionId) ?? w.title;
24149
- const um = await userMeta(w.sessionId, fileById.get(w.sessionId) ?? "");
24150
- const sessionEnd = own.length ? Math.max(...own.map((iv) => iv[1])) : w.phases[w.phases.length - 1]?.fromMs ?? 0;
24151
- const phases = w.phases.map((p, i) => {
24152
- const w0 = p.fromMs;
24153
- const w1 = i + 1 < w.phases.length ? w.phases[i + 1].fromMs : sessionEnd + 1;
24154
- const inPhase = um.filter((m) => m.t >= w0 && m.t < w1);
24155
- const userPrompts = inPhase.length;
24156
- const words = inPhase.reduce((s, m) => s + m.words, 0);
24157
- const wordsPerMsg = userPrompts ? Math.round(words / userPrompts) : 0;
24158
- const ownInWin = own.map(([a, b]) => [Math.max(a, w0), Math.min(b, w1)]).filter(([a, b]) => b > a);
24159
- const durationMin = Math.round(ownInWin.reduce((s, [a, b]) => s + (b - a), 0) / 6e4);
24160
- const byTitle = /* @__PURE__ */ new Map();
24161
- for (const [sid, ivs] of intervalsBy) {
24162
- if (sid === w.sessionId) continue;
24163
- const t = titleBy.get(sid) ?? "(untitled)";
24164
- if (t === ownTitle) continue;
24165
- const ms2 = listOverlapMs(ownInWin, ivs);
24166
- if (ms2 >= 6e4) byTitle.set(t, (byTitle.get(t) ?? 0) + ms2);
24167
- }
24168
- const parallel = [...byTitle.entries()].map(([title, ms2]) => ({ title, overlapMin: Math.round(ms2 / 6e4) })).sort((a, b) => b.overlapMin - a.overlapMin).slice(0, 6);
24169
- return { what: p.what, durationMin, fromMs: w0, toMs: w1, userPrompts, words, wordsPerMsg, parallel };
24170
- });
24171
- walkthroughs[w.sessionId] = { phases, totalActiveMin: w.totalActiveMin, userTurns: w.userTurns };
24938
+ return { failed, ...skippedLlm ? { skippedLlm } : {} };
24939
+ }
24940
+
24941
+ // src/chatPipeline.ts
24942
+ init_manifest();
24943
+ import { spawn as spawn7 } from "child_process";
24944
+ import path37 from "path";
24945
+ import { existsSync as existsSync6, promises as fs32 } from "fs";
24946
+ import { fileURLToPath as fileURLToPath4 } from "url";
24947
+ init_dataHome();
24948
+ var MODULE_DIR3 = path37.dirname(fileURLToPath4(import.meta.url));
24949
+ var INGESTABLE_KINDS = ["chatgpt", "claude", "notion", "obsidian"];
24950
+ function chatEngineStages() {
24951
+ return [
24952
+ { script: "run-tagger.mts", label: "Tag your conversations", llm: true, args: ["--model", "haiku"], out: "signals/index.jsonl" },
24953
+ { script: "run-analysis.mts", label: "Docs + growth/drivers/circumstances agents", llm: true, args: [], out: "engine-pilot/growth-latest.json" },
24954
+ { script: "exp-pipeline.mts", label: "Select the conversations to grade", llm: true, args: ["--lenses", "reasoning,agency,interpersonal", "--select-only"], out: "engine-pilot/grades/reasoning/_selected.json" },
24955
+ { script: "exp-allfacets.mts", label: "Per-conversation grades", llm: true, args: ["--lenses", "all", "--all"] },
24956
+ { script: "exp-person.mts", label: "Person synthesis", llm: true, args: ["--lenses", "all"], out: "engine-pilot/grades/reasoning/_person.json" },
24957
+ { script: "person-self-image.mts", label: "Self-image read", llm: true, args: [], out: "engine-pilot/self-image.json" },
24958
+ { script: "person-headline.mts", label: "Headline", llm: true, args: [], out: "engine-pilot/person-headline.json" },
24959
+ { script: "person-facet-lines.mts", label: "Facet lines", llm: true, args: [], out: "engine-pilot/person-facet-lines.json" },
24960
+ { script: "peak-demos.mts", label: "Peak demonstrations", llm: true, args: [], out: "engine-pilot/peak-demos.json" },
24961
+ { script: "person-dimension-summary.mts", label: "Dimension summaries", llm: true, args: [], out: "engine-pilot/dimension-summary.json" },
24962
+ { script: "person-report.mts", label: "Report narrative", llm: true, args: [], out: "engine-pilot/report-narrative.json" },
24963
+ { script: "public-report.mts", label: "Public report", llm: true, args: [], out: "engine-pilot/public-report.json" }
24964
+ ];
24965
+ }
24966
+ function bundledEngineDir() {
24967
+ const d = path37.join(MODULE_DIR3, "engine");
24968
+ return existsSync6(path37.join(d, "run-tagger.js")) ? d : null;
24969
+ }
24970
+ function stageInvocation2(repoRoot, scriptRel, args) {
24971
+ const scriptAbs = path37.join(repoRoot, "scripts", scriptRel);
24972
+ if (existsSync6(scriptAbs)) {
24973
+ const local = path37.join(repoRoot, "node_modules", ".bin", "tsx");
24974
+ if (existsSync6(local)) return { cmd: local, argv: [scriptAbs, ...args], cwd: repoRoot };
24975
+ return { cmd: "npx", argv: ["tsx", scriptAbs, ...args], cwd: repoRoot };
24172
24976
  }
24173
- const rubric2 = Object.fromEntries(
24174
- CODING_CRITERIA.filter((c) => c.graded).map((c) => [c.key, { label: c.label, definition: c.definition, read: c.read, rungs: c.rungs ?? [] }])
24175
- );
24176
- await Promise.all(sessions.map((s) => userMeta(s.sessionId, s.file)));
24177
- const wordsByDay = {};
24178
- const seenMsg = /* @__PURE__ */ new Set();
24179
- for (const s of sessions) for (const m of UMETA.get(s.sessionId) ?? []) {
24180
- if (seenMsg.has(m.key)) continue;
24181
- seenMsg.add(m.key);
24182
- const d = new Date(m.t).toLocaleDateString("en-CA", { timeZone: tz });
24183
- wordsByDay[d] = (wordsByDay[d] ?? 0) + m.words;
24977
+ const bundled = bundledEngineDir();
24978
+ if (bundled) {
24979
+ const js = path37.join(bundled, scriptRel.replace(/\.mts$/, ".js"));
24980
+ return { cmd: process.execPath, argv: [js, ...args], cwd: process.cwd() };
24184
24981
  }
24185
- const dayThroughput = {};
24186
- for (const [d, n] of Object.entries(wordsByDay)) dayThroughput[d] = throughputScore(n);
24187
- const tCeiling = throughputCeiling(Object.values(wordsByDay));
24188
- const criteriaMean = {};
24189
- for (const c of criteria) criteriaMean[c.key] = { mean: c.dist.mean, n: c.dist.n };
24190
- const flow = await readJson2(path33.join(CODING_DIR2, "flow.json"), null);
24191
- const focus = await readJson2(path33.join(CODING_DIR2, "focus.json"), null);
24192
- const expertiseMap = await readJson2(path33.join(CODING_DIR2, "expertise.json"), null);
24193
- const frontierArsenal = await readJson2(path33.join(CODING_DIR2, "frontier.json"), null);
24194
- const frontierDetail = await readJson2(path33.join(CODING_DIR2, "frontier-detail.json"), null);
24195
- const coaching = await readJson2(path33.join(CODING_DIR2, "coaching.json"), null);
24196
- const gap = await readJson2(path33.join(CODING_DIR2, "gap.json"), null);
24197
- const aggregate = await readJson2(path33.join(CODING_DIR2, "aggregate.json"), null);
24198
- const delegationRollup = await readJson2(path33.join(CODING_DIR2, "delegation-rollup.json"), null);
24199
- const gapDist = await readJson2(path33.join(CODING_DIR2, "gap-dist.json"), null);
24200
- const projects = await readJson2(path33.join(CODING_DIR2, "projects.json"), null);
24201
- const workstyle = computeWorkstyle({
24202
- dayChart,
24203
- tz,
24204
- idleGapMin: conc?.idleGapMin ?? 5,
24205
- criteriaMean,
24206
- outcomeCadence: outcomeCadence ? { perWeek: outcomeCadence.perWeek, fraction: outcomeCadence.fraction } : null,
24207
- flow,
24208
- signals: {
24209
- maxConcurrency: parallelism.maxConcurrency,
24210
- subagents: throughput.subagents,
24211
- queueOps: parallelism.queueOps,
24212
- mcpTools: new Set(sessions.flatMap((s) => s.mcpTools ?? [])).size,
24213
- parallelHours: Math.round(parallelism.minutesAt2plus / 60 * 10) / 10
24214
- }
24982
+ throw new Error(`chat-engine stage ${scriptRel}: neither repo scripts/ nor bundled dist/engine/ found`);
24983
+ }
24984
+ function hasChatPipeline(repoRoot) {
24985
+ return existsSync6(path37.join(repoRoot, "scripts", "run-tagger.mts")) || bundledEngineDir() != null;
24986
+ }
24987
+ function chatDataRoot(repoRoot) {
24988
+ if (!process.env.POLYMATH_DATA_DIR && existsSync6(path37.join(repoRoot, "scripts", "run-tagger.mts"))) {
24989
+ return path37.join(repoRoot, ".data");
24990
+ }
24991
+ return resolveDataRoot();
24992
+ }
24993
+ async function finalChatArtifacts(dataRoot) {
24994
+ const gradesDir = path37.join(dataRoot, "engine-pilot", "grades");
24995
+ const out = [];
24996
+ for (const lens of (await fs32.readdir(gradesDir).catch(() => [])).sort()) {
24997
+ const p = path37.join(gradesDir, lens, "_person.json");
24998
+ if (existsSync6(p)) out.push(p);
24999
+ }
25000
+ out.push(path37.join(dataRoot, "engine-pilot", "public-report.json"));
25001
+ return out;
25002
+ }
25003
+ function runStage2(repoRoot, st, env, onLine) {
25004
+ return new Promise((resolve2, reject) => {
25005
+ const { cmd, argv, cwd } = stageInvocation2(repoRoot, st.script, st.args);
25006
+ const child = spawn7(cmd, argv, { cwd, env, stdio: ["ignore", "pipe", "pipe"] });
25007
+ const pump = (buf) => {
25008
+ if (!onLine) return;
25009
+ for (const line of buf.toString().split(/\r?\n/)) if (line.trim()) onLine(line);
25010
+ };
25011
+ child.stdout.on("data", pump);
25012
+ child.stderr.on("data", pump);
25013
+ child.on("error", reject);
25014
+ child.on("close", (code) => code === 0 ? resolve2() : reject(new Error(`${st.script} exited with code ${code}`)));
24215
25015
  });
24216
- const pctOf = (sc) => {
24217
- if (sc == null) return null;
24218
- const label = bandLabel(sc, DEFAULT_CALIBRATION);
24219
- const m = /([\d.]+)\s*%/.exec(label);
24220
- return m ? 100 - parseFloat(m[1]) : null;
24221
- };
24222
- const ceilOf = (key) => {
24223
- const c = criteria.find((x) => x.key === key);
24224
- const scores = (c?.takes ?? []).map((t) => t.score ?? t.best).filter((x) => x != null).sort((a, b) => b - a);
24225
- return scores.length ? scores[Math.min(3, scores.length) - 1] : null;
24226
- };
24227
- const proud = (key, fallback) => {
24228
- const t = (criteria.find((x) => x.key === key)?.takes ?? [])[0];
24229
- if (!t?.instance) return fallback;
24230
- let h = t.instance.split(/:\s|\s[—–]\s|\swith an?\s/)[0].trim().replace(/\s+/g, " ");
24231
- h = h.replace(/^The user\b/, "You").replace(/\bThe user\b/g, "you").replace(/([.?!]['"’”)\]]*\s+)you\b/g, (_m, p) => p + "You");
24232
- if (h.length > 150) h = h.slice(0, 148).replace(/\s+\S*$/, "") + "\u2026";
24233
- return h;
24234
- };
24235
- const nTk = (key) => criteria.find((x) => x.key === key)?.takes.length ?? 0;
24236
- const peakWords = Object.values(wordsByDay).length ? Math.max(...Object.values(wordsByDay)) : 0;
24237
- const pHist = parallelism.levelHistogramMin || {};
24238
- const soloMin = pHist["1"] ?? 0;
24239
- const parMin = Object.entries(pHist).reduce((a, [k, v]) => Number(k) >= 2 ? a + v : a, 0);
24240
- const soloPct = soloMin + parMin ? Math.round(soloMin / (soloMin + parMin) * 100) : null;
24241
- const flowPctDay = aggregate?.flow?.flow?.pctOfWorkDay ?? null;
24242
- const flowHrsDay = workstyle.flowHoursPerDay ? Math.round(workstyle.flowHoursPerDay * 10) / 10 : null;
24243
- const focusScore = flowPctDay == null ? null : Math.max(1, Math.min(10, Math.round(2 + flowPctDay / BEST.flow.topPctOfDay * 7)));
24244
- const out2 = ceilOf("outcomes");
24245
- const unb = ceilOf("unblocking");
24246
- const agency = out2 != null && unb != null ? Math.round((out2 + unb) / 2) : out2 ?? unb;
24247
- const sRow = (label, score, gap2) => ({ label, score, percentile: pctOf(score), gap: gap2 });
24248
- const tiers = DEFAULT_CALIBRATION.codingTiers;
24249
- const phi = (z) => {
24250
- const t = 1 / (1 + 0.2316419 * Math.abs(z));
24251
- const d = 0.3989423 * Math.exp(-z * z / 2);
24252
- let pr = d * t * (0.3193815 + t * (-0.3565638 + t * (1.781478 + t * (-1.821256 + t * 1.330274))));
24253
- if (z > 0) pr = 1 - pr;
24254
- return pr;
25016
+ }
25017
+ async function runChatPipeline(o) {
25018
+ if (!hasChatPipeline(o.repoRoot)) {
25019
+ throw new Error(
25020
+ "chat pipeline: neither the polymath repo (scripts/run-tagger.mts at " + o.repoRoot + ") nor the bundled engine (dist/engine/) was found \u2014 the package build is broken."
25021
+ );
25022
+ }
25023
+ const dataRoot = chatDataRoot(o.repoRoot);
25024
+ const manifest = await readManifest(dataRoot);
25025
+ if (!manifest) {
25026
+ return { skipped: true, skipReason: "no exports-manifest.json \u2014 run the wizard (bare `polymath-society`) to approve chat/notes sources", ingested: [], notIngestable: [], failed: [] };
25027
+ }
25028
+ const included = manifest.exports.included;
25029
+ if (included.length === 0) {
25030
+ return { skipped: true, skipReason: "manifest present but no sources are included \u2014 re-run the wizard to change your choices", ingested: [], notIngestable: [], failed: [] };
25031
+ }
25032
+ const env = {
25033
+ ...process.env,
25034
+ POLYMATH_RESILIENT: "1",
25035
+ POLYMATH_ANALYZE_MODE: "off",
25036
+ // WE run the engine, in order — no auto-trigger
25037
+ POLYMATH_DATA_DIR: dataRoot,
25038
+ // one root for store + engine artifacts
25039
+ AGENT_MODEL: o.model ?? process.env.AGENT_MODEL ?? "sonnet"
24255
25040
  };
24256
- const lognPct = (x, c) => x == null || !c || x <= 0 ? null : Math.round(phi(Math.log(x / c.median) / c.sigma) * 1e3) / 10;
24257
- const avgWords = aggregate?.throughput?.avgWordsPerDay ?? null;
24258
- const pushPctl = lognPct(avgWords, tiers?.push);
24259
- const focusPctl = lognPct(flowPctDay, tiers?.focus);
24260
- const hoursAt = (min) => Object.entries(pHist).reduce((a, [k, v]) => Number(k) >= min ? a + v : a, 0) / 60;
24261
- const orchPctl = hoursAt(5) >= 5 || hoursAt(3) >= 10 && parallelism.queueOps >= 1e3 ? 99.5 : hoursAt(3) >= 10 ? 99 : hoursAt(2) >= 0.1 * (soloMin + parMin) / 60 ? 97 : hoursAt(2) >= 2 ? 90 : 70;
24262
- const stackUp = [
24263
- sRow(
24264
- "How hard you push",
24265
- aggregate?.throughput?.score ?? tCeiling,
24266
- `you peak at ~${peakWords.toLocaleString()} words of pure direction in a single day \u2014 the very top sustain ~${BEST.throughput.topAvgWordsPerDay.toLocaleString()} every day, week after week, and crest past ${BEST.throughput.topPeakWordsPerDay.toLocaleString()}`
24267
- ),
24268
- sRow(
24269
- "How well you use AI",
24270
- ceilOf("delegation"),
24271
- soloPct != null ? `~${soloPct}% of your hours you drive a single agent (${Math.round(soloMin / 60)}h solo vs ${Math.round(parMin / 60)}h with 2+ live) \u2014 the Claude Code lead keeps 10\u201315 going at once, so this is the single biggest speed-up still on the table` : "you brief the AI sharply, but mostly drive one agent at a time \u2014 the top run 10\u201315 in parallel, a several-fold speed-up"
24272
- ),
24273
- sRow(
24274
- "How well you focus",
24275
- focusScore,
24276
- flowHrsDay != null ? `only ~${flowHrsDay}h of your day is true deep flow \u2014 the best hold ~4h in one unbroken block; yours fragments across parallel sessions, so the gain is directing your attention at one thread for longer` : "your attention scatters across parallel sessions \u2014 directing it at one thread for longer is the unlock"
24277
- ),
24278
- // The four estimates LEAD with a concrete moment from their own sessions, then an
24279
- // HONEST caveat — how many graded sessions back the read. No invented weakness, no
24280
- // claim about what they "didn't" do (false specifics churn a real user); it's an estimate.
24281
- sRow(
24282
- "Agency",
24283
- agency,
24284
- `${proud("outcomes", "you ship working systems and unblock yourself")} \u2014 one of ${nTk("outcomes")} sessions behind this read; a strong, consistent signal, still an estimate from your logs`
24285
- ),
24286
- // Judgement/Taste use the SAME numbers their ability cards prove (aggregate
24287
- // peak-with-consistency over near-peak instances) — a chip saying "top 1%"
24288
- // above a card proving 10/Top 0.1% with ten receipts reads as a bug.
24289
- sRow(
24290
- "Judgement",
24291
- aggregate?.ability?.abstraction?.score ?? ceilOf("generative"),
24292
- `${proud("generative", "you make sharp, non-obvious calls on what actually matters")} \u2014 one of ${nTk("generative")} sessions we've graded for this; clear so far, not yet a final verdict`
24293
- ),
24294
- sRow(
24295
- "Taste",
24296
- aggregate?.ability?.taste?.score ?? ceilOf("taste"),
24297
- `${proud("taste", "you hold a high, opinionated quality bar")} \u2014 one of ${nTk("taste")} sessions behind this read; a real signal, still an estimate`
24298
- )
24299
- // Expertise: NO chip — the scored criterion is deprecated; the real judge is
24300
- // the qualitative domains map (expertise-floor), and a chip must never say
24301
- // "top X%" while that section shows no qualifying domains.
24302
- ];
24303
- for (const r of stackUp) {
24304
- if (r.label === "How hard you push" && pushPctl != null) {
24305
- r.percentile = pushPctl;
24306
- r.metric = avgWords;
24307
- r.curve = "push";
25041
+ if (!o.overnight) env.POLYMATH_RESILIENT_NO_WINDOW = "1";
25042
+ const failed = [];
25043
+ const ingested = [];
25044
+ const notIngestable = [];
25045
+ const ingestable = included.filter((f) => INGESTABLE_KINDS.includes(f.kind));
25046
+ for (const f of included) {
25047
+ if (!INGESTABLE_KINDS.includes(f.kind)) notIngestable.push(f.path);
25048
+ }
25049
+ const total = ingestable.length + chatEngineStages().length;
25050
+ const central = centralConfig();
25051
+ const t0 = Date.now();
25052
+ const log = await startRunLog(
25053
+ { app: "npm-package", pipeline: "chat", stages: total },
25054
+ {
25055
+ supabaseUrl: central.supabaseUrl,
25056
+ supabaseAnonKey: central.supabaseAnonKey,
25057
+ artifacts: () => finalChatArtifacts(dataRoot),
25058
+ refPath: path37.join(dataRoot, "report-run.json")
24308
25059
  }
24309
- if (r.label === "How well you focus" && focusPctl != null) {
24310
- r.percentile = focusPctl;
24311
- r.metric = flowPctDay;
24312
- r.curve = "focus";
25060
+ );
25061
+ let idx = 0;
25062
+ for (const f of ingestable) {
25063
+ const st = { script: "ingest-export.mts", label: `Ingest ${f.kind} \u2014 ${path37.basename(f.path)}`, llm: false, args: [f.kind, f.path] };
25064
+ o.onStage?.(++idx, total, st.label, false);
25065
+ const stStart = Date.now();
25066
+ let ok = true;
25067
+ try {
25068
+ await runStage2(o.repoRoot, st, env, o.onLine);
25069
+ ingested.push(f.path);
25070
+ } catch (e) {
25071
+ ok = false;
25072
+ const error = e.message.slice(0, 200);
25073
+ failed.push({ label: st.label, script: st.script, error });
25074
+ o.onLine?.(`\u26A0\uFE0F ingest FAILED (continuing): ${f.path} \u2014 ${error}`);
24313
25075
  }
24314
- if (r.label === "How well you use AI") r.percentile = orchPctl;
25076
+ log.event("ingest-export", { ok, ms: Date.now() - stStart, source: f.kind });
24315
25077
  }
24316
- return { generatedAt: (/* @__PURE__ */ new Date()).toISOString(), gradedSessions: grades.length, agglomeration, outcomeCadence, dayDigest, dayChart, timeline, walkthroughs, rubric: rubric2, wordsByDay, dayThroughput, throughputCeiling: tCeiling, stackUp, criteria, parallelism, throughput, workstyle, flow, focus, expertiseMap, frontierArsenal, frontierDetail, coaching, gap, aggregate, delegationRollup, gapDist, projects };
25078
+ for (const st of chatEngineStages()) {
25079
+ o.onStage?.(++idx, total, st.label, st.llm);
25080
+ const stStart = Date.now();
25081
+ let ok = true;
25082
+ try {
25083
+ await runStage2(o.repoRoot, st, env, o.onLine);
25084
+ } catch (e) {
25085
+ ok = false;
25086
+ const error = e.message.slice(0, 200);
25087
+ failed.push({ label: st.label, script: st.script, error });
25088
+ o.onLine?.(`\u26A0\uFE0F stage FAILED (continuing): ${st.label} \u2014 ${error}`);
25089
+ }
25090
+ const sha = st.out ? await fileSha(path37.join(dataRoot, st.out)) : null;
25091
+ log.event(st.script.replace(/\.mts$/, ""), { ok, ms: Date.now() - stStart, ...sha ? { sha } : {} });
25092
+ }
25093
+ log.event("pipeline_completed", { ok: failed.length === 0, failedStages: failed.length, ms: Date.now() - t0 });
25094
+ await log.finish();
25095
+ return { skipped: false, ingested, notIngestable, failed };
24317
25096
  }
24318
25097
 
24319
25098
  // src/cli.ts
24320
- var __dirname2 = path37.dirname(fileURLToPath5(import.meta.url));
24321
- var REPO_ROOT = path37.resolve(__dirname2, "..", "..", "..");
25099
+ init_manifest();
25100
+ var __dirname2 = path41.dirname(fileURLToPath5(import.meta.url));
25101
+ var REPO_ROOT = path41.resolve(__dirname2, "..", "..", "..");
24322
25102
  function parseArgs(argv) {
24323
25103
  const p = {
24324
25104
  cmd: "profile",
@@ -24464,7 +25244,7 @@ function ensureBackend(prefer) {
24464
25244
  async function runGrade(opts, provider, profile) {
24465
25245
  const gradable = profile.gate.gradable;
24466
25246
  const total = opts.maxSessions != null ? Math.min(opts.maxSessions, gradable) : gradable;
24467
- console.error(`Grading ${total} session${total === 1 ? "" : "s"} on your local agent (this spends your subscription tokens)\u2026`);
25247
+ console.error(`Grading ${total} session${total === 1 ? "" : "s"} on your local agent\u2026`);
24468
25248
  await provider.criteriaMean(profile.sessions);
24469
25249
  }
24470
25250
  async function main() {
@@ -24501,7 +25281,7 @@ async function main() {
24501
25281
  const backend = ensureBackend(opts.adapter);
24502
25282
  if (!backend) process.exit(1);
24503
25283
  console.error(`Using ${backend.name === "cli" ? "Claude Code" : "Codex"} (${backend.detail}).`);
24504
- const gradeOut = path37.resolve(opts.out || ".coding-analyzer-grades");
25284
+ const gradeOut = path41.resolve(opts.out || ".coding-analyzer-grades");
24505
25285
  const provider = new LocalGradeProvider({
24506
25286
  adapter: opts.adapter,
24507
25287
  model: opts.model,
@@ -24510,8 +25290,8 @@ async function main() {
24510
25290
  });
24511
25291
  const profile2 = await analyze({ codex: opts.codex, idleGapMin: opts.idleGapMin, tz: opts.tz, spanHourMin: opts.spanHourMin, gradeProvider: provider });
24512
25292
  const detail = provider.detail();
24513
- await fs31.mkdir(gradeOut, { recursive: true });
24514
- await fs31.writeFile(path37.join(gradeOut, "graded.json"), JSON.stringify(detail, null, 2));
25293
+ await fs36.mkdir(gradeOut, { recursive: true });
25294
+ await fs36.writeFile(path41.join(gradeOut, "graded.json"), JSON.stringify(detail, null, 2));
24515
25295
  console.error(`
24516
25296
  Graded ${detail.gradedSessions} sessions \u2192 ${gradeOut}/graded.json`);
24517
25297
  for (const c of detail.criteria) console.error(` ${c.key.padEnd(12)} ${c.mean != null ? `mean ${c.mean} \xB7 ${c.n} sessions` : "no signal"}`);
@@ -24520,10 +25300,10 @@ Graded ${detail.gradedSessions} sessions \u2192 ${gradeOut}/graded.json`);
24520
25300
  }
24521
25301
  if (opts.cmd === "serve") {
24522
25302
  let earlyHandle = null;
24523
- const runMarker = path37.join(DATA_ROOT, "coding", ".grade-run.json");
25303
+ const runMarker = path41.join(DATA_ROOT, "coding", ".grade-run.json");
24524
25304
  if (!opts.grade) {
24525
25305
  try {
24526
- const mk = JSON.parse(await fs31.readFile(runMarker, "utf8"));
25306
+ const mk = JSON.parse(await fs36.readFile(runMarker, "utf8"));
24527
25307
  if (mk && mk.done === false) {
24528
25308
  console.error(`
24529
25309
  \u26A0\uFE0F An analysis started ${mk.startedAt ?? "earlier"} never finished (the process died mid-run).`);
@@ -24548,16 +25328,20 @@ Graded ${detail.gradedSessions} sessions \u2192 ${gradeOut}/graded.json`);
24548
25328
  const when = (o) => o ? "at the 02:00 window tonight" : "now";
24549
25329
  console.error(`
24550
25330
  Running the full analysis on ${backend.name === "cli" ? "Claude Code" : "Codex"} \u2014 coding ${when(opts.overnight)}, chats ${when(chatOvernight)}.`);
24551
- console.error("This spends your subscription tokens and can take a while. The report link appears right away and fills in as stages finish.\n");
25331
+ console.error("The report link appears right away and fills in as stages finish.\n");
24552
25332
  const t0 = Date.now();
24553
25333
  try {
24554
- await fs31.mkdir(path37.dirname(runMarker), { recursive: true });
24555
- await fs31.writeFile(runMarker, JSON.stringify({ startedAt: (/* @__PURE__ */ new Date()).toISOString(), done: false }));
25334
+ await fs36.mkdir(path41.dirname(runMarker), { recursive: true });
25335
+ await fs36.writeFile(runMarker, JSON.stringify({ startedAt: (/* @__PURE__ */ new Date()).toISOString(), done: false }));
24556
25336
  } catch {
24557
25337
  }
25338
+ const earlyProfile = await compileCodingProfile();
24558
25339
  earlyHandle = await startServer({
24559
- profile: await compileCodingProfile(),
24560
- shareSections: {},
25340
+ profile: earlyProfile,
25341
+ // Real sections from minute one (whatever's already on disk shares
25342
+ // fine), refreshed below as stages land — an empty {} here made
25343
+ // "Share report" 400 for the entire run (shipped 2026-07-14).
25344
+ shareSections: buildShareSections(earlyProfile),
24561
25345
  version: await pkgVersion(),
24562
25346
  shareUrl: opts.shareUrl || process.env.PS_SHARE_URL || DEFAULT_SHARE_URL,
24563
25347
  port: opts.port,
@@ -24570,7 +25354,9 @@ Running the full analysis on ${backend.name === "cli" ? "Claude Code" : "Codex"}
24570
25354
  earlyHandle.setProgress(progress);
24571
25355
  const refreshProfile = async () => {
24572
25356
  try {
24573
- earlyHandle.setProfile(await compileCodingProfile());
25357
+ const p = await compileCodingProfile();
25358
+ earlyHandle.setProfile(p);
25359
+ earlyHandle.setShareSections(buildShareSections(p));
24574
25360
  } catch {
24575
25361
  }
24576
25362
  };
@@ -24605,13 +25391,14 @@ Running the full analysis on ${backend.name === "cli" ? "Claude Code" : "Codex"}
24605
25391
  harvestWithin("coding", line);
24606
25392
  codingLane.log(` ${line}`);
24607
25393
  }
24608
- }).then(async ({ failed: failed2 }) => {
25394
+ }).then(async (codingRes2) => {
25395
+ const { failed: failed2 } = codingRes2;
24609
25396
  progress.coding = { ...progress.coding ?? { i: 0, total: 0, label: "" }, done: true, failed: failed2.length };
24610
25397
  earlyHandle.setProgress(progress);
24611
25398
  await refreshProfile();
24612
25399
  openBrowser(earlyHandle.url);
24613
25400
  try {
24614
- const stored = JSON.parse(await fs31.readFile(path37.join(DATA_ROOT, "notify-email.json"), "utf8"));
25401
+ const stored = JSON.parse(await fs36.readFile(path41.join(DATA_ROOT, "notify-email.json"), "utf8"));
24615
25402
  if (stored.email) {
24616
25403
  const { requestEmailReminder: requestEmailReminder2 } = await Promise.resolve().then(() => (init_reminderEmail(), reminderEmail_exports));
24617
25404
  const r = await requestEmailReminder2(stored.email, ["report-ready"], 1);
@@ -24619,7 +25406,7 @@ Running the full analysis on ${backend.name === "cli" ? "Claude Code" : "Codex"}
24619
25406
  }
24620
25407
  } catch {
24621
25408
  }
24622
- return { failed: failed2 };
25409
+ return codingRes2;
24623
25410
  });
24624
25411
  const chatLane = mbar.lane("chat");
24625
25412
  const chatDone = (async () => {
@@ -24652,7 +25439,8 @@ Running the full analysis on ${backend.name === "cli" ? "Claude Code" : "Codex"}
24652
25439
  await refreshProfile();
24653
25440
  return chat2;
24654
25441
  })();
24655
- const [{ failed }, chat] = await Promise.all([codingDone, chatDone]);
25442
+ const [codingRes, chat] = await Promise.all([codingDone, chatDone]);
25443
+ const { failed } = codingRes;
24656
25444
  clearInterval(liveRefresh);
24657
25445
  mbar.done();
24658
25446
  if (failed.length) {
@@ -24661,6 +25449,11 @@ Running the full analysis on ${backend.name === "cli" ? "Claude Code" : "Codex"}
24661
25449
  for (const f of failed) console.error(` \u2022 ${f.label} (${f.script}): ${f.error}`);
24662
25450
  console.error(` Fix: run \`serve --grade\` again \u2014 it resumes, redoing ONLY the missing work.
24663
25451
  `);
25452
+ } else if (codingRes.skippedLlm) {
25453
+ console.error(
25454
+ `
25455
+ \u2713 coding report is up to date \u2014 only ${codingRes.skippedLlm.pending} new session(s) since the last full run (below the ${codingRes.skippedLlm.threshold}-session threshold), so the AI stages were skipped and the existing report is served as-is. POLYMATH_MIN_NEW_SESSIONS=0 or --regrade forces a full run.`
25456
+ );
24664
25457
  } else {
24665
25458
  console.error(`
24666
25459
  \u2713 coding analysis complete in ${Math.round((Date.now() - t0) / 6e4)} min.`);
@@ -24679,11 +25472,11 @@ Running the full analysis on ${backend.name === "cli" ? "Claude Code" : "Codex"}
24679
25472
  }
24680
25473
  }
24681
25474
  try {
24682
- await fs31.writeFile(runMarker, JSON.stringify({ startedAt: (/* @__PURE__ */ new Date()).toISOString(), done: true }));
25475
+ await fs36.writeFile(runMarker, JSON.stringify({ startedAt: (/* @__PURE__ */ new Date()).toISOString(), done: true }));
24683
25476
  } catch {
24684
25477
  }
24685
25478
  }
24686
- if (!opts.grade && !existsSync7(path37.join(DATA_ROOT, "coding", "sessions.json")) && hasPipeline(REPO_ROOT)) {
25479
+ if (!opts.grade && !existsSync7(path41.join(DATA_ROOT, "coding", "sessions.json")) && hasPipeline(REPO_ROOT)) {
24687
25480
  console.error(`
24688
25481
  No analysis here yet \u2014 computing the instant deterministic metrics now (free, no AI)\u2026`);
24689
25482
  const d0 = Date.now();
@@ -24724,7 +25517,7 @@ No analysis here yet \u2014 computing the instant deterministic metrics now (fre
24724
25517
  const nSessions = w.throughput?.sessions ?? 0;
24725
25518
  const nGraded = w.gradedSessions ?? 0;
24726
25519
  const who = await readIdentity(dataDir);
24727
- if (nSessions === 0 && !existsSync7(path37.join(dataDir, "coding")) && !existsSync7(path37.join(dataDir, "engine-pilot"))) {
25520
+ if (nSessions === 0 && !existsSync7(path41.join(dataDir, "coding")) && !existsSync7(path41.join(dataDir, "engine-pilot"))) {
24728
25521
  console.error(`
24729
25522
  \u26A0\uFE0F ${dataDir} has no analysis artifacts \u2014 this will be an EMPTY report.`);
24730
25523
  console.error(` Run from the directory where you ran the analysis, or set POLYMATH_DATA_DIR.`);
@@ -24750,7 +25543,7 @@ No analysis here yet \u2014 computing the instant deterministic metrics now (fre
24750
25543
  const profile = await analyze({ codex: opts.codex, idleGapMin: opts.idleGapMin, tz: opts.tz, spanHourMin: opts.spanHourMin });
24751
25544
  const payload = opts.cmd === "projects" ? profile.projects : opts.cmd === "flow" ? profile.flow : opts.cmd === "aggregate" ? profile.aggregate : profile;
24752
25545
  if (opts.out) {
24753
- await fs31.writeFile(opts.out, JSON.stringify(payload, null, 2));
25546
+ await fs36.writeFile(opts.out, JSON.stringify(payload, null, 2));
24754
25547
  console.error(`wrote ${opts.cmd} \u2192 ${opts.out}`);
24755
25548
  return;
24756
25549
  }
@@ -24762,7 +25555,7 @@ No analysis here yet \u2014 computing the instant deterministic metrics now (fre
24762
25555
  }
24763
25556
  async function pkgVersion() {
24764
25557
  try {
24765
- const pkg = JSON.parse(await fs31.readFile(path37.join(__dirname2, "..", "package.json"), "utf-8"));
25558
+ const pkg = JSON.parse(await fs36.readFile(path41.join(__dirname2, "..", "package.json"), "utf-8"));
24766
25559
  return String(pkg.version || "0.0.0");
24767
25560
  } catch {
24768
25561
  return "0.0.0";