polymath-society 0.2.5 → 0.2.7
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 +2420 -1573
- package/dist/engine/ingest-export.js +14 -8
- package/dist/engine/public-report.js +14 -8
- package/dist/index.js +1475 -60
- package/dist/pipeline/coding-agglomerate.js +289 -35
- package/dist/pipeline/coding-aggregate.js +15 -9
- package/dist/pipeline/coding-build.js +14 -8
- package/dist/pipeline/coding-coaching.js +273 -21
- package/dist/pipeline/coding-day-digest.js +17 -10
- package/dist/pipeline/coding-delegation.js +62 -17
- package/dist/pipeline/coding-expertise.js +166 -61
- package/dist/pipeline/coding-flow.js +14 -8
- package/dist/pipeline/coding-frontier-detail.js +143 -27
- package/dist/pipeline/coding-frontier.js +14 -8
- package/dist/pipeline/coding-gap-dist.js +14 -8
- package/dist/pipeline/coding-gap.js +140 -39
- package/dist/pipeline/coding-grade.js +44 -14
- package/dist/pipeline/coding-nutshell.js +39 -11
- package/dist/pipeline/coding-projects.js +41 -10
- package/dist/pipeline/coding-walkthrough.js +15 -9
- package/dist/web/app.js +493 -117
- package/dist/web/styles.css +1 -1
- package/package.json +1 -1
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
|
|
1322
|
-
import
|
|
1365
|
+
import { promises as fs22 } from "fs";
|
|
1366
|
+
import path27 from "path";
|
|
1323
1367
|
function manifestPath(dataDir) {
|
|
1324
|
-
return
|
|
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
|
|
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
|
|
1358
|
-
await
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1708
|
+
const path42 = await import("node:path");
|
|
1640
1709
|
for (const dir of ["Downloads", "Desktop", "Documents"]) {
|
|
1641
|
-
for (const f of await scanForExports(
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
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
|
|
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(
|
|
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
|
|
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 =
|
|
1819
|
+
const p = path38.join(root, name17);
|
|
1751
1820
|
let st;
|
|
1752
1821
|
try {
|
|
1753
|
-
st = await
|
|
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:
|
|
1820
|
-
const
|
|
1888
|
+
const { promises: fs37 } = await import("fs");
|
|
1889
|
+
const path42 = await import("path");
|
|
1821
1890
|
const { fileURLToPath: fileURLToPath6 } = await import("url");
|
|
1822
|
-
const here =
|
|
1823
|
-
const pkg = JSON.parse(await
|
|
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
|
|
1899
|
-
import
|
|
1900
|
-
import
|
|
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 =
|
|
1989
|
+
async function detectCodexPlan(home = os9.homedir()) {
|
|
1921
1990
|
try {
|
|
1922
|
-
const raw = JSON.parse(await
|
|
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 =
|
|
2005
|
+
async function detectPlan(home = os9.homedir()) {
|
|
1937
2006
|
let tier = "unknown";
|
|
1938
2007
|
try {
|
|
1939
|
-
const raw = JSON.parse(await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
2029
|
-
import
|
|
2030
|
-
import
|
|
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
|
|
2108
|
+
names = await fs35.readdir(d);
|
|
2040
2109
|
} catch {
|
|
2041
2110
|
return;
|
|
2042
2111
|
}
|
|
2043
2112
|
for (const n of names) {
|
|
2044
|
-
const p =
|
|
2113
|
+
const p = path40.join(d, n);
|
|
2045
2114
|
let st;
|
|
2046
2115
|
try {
|
|
2047
|
-
st = await
|
|
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(
|
|
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(
|
|
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
|
|
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
|
|
2185
|
-
await
|
|
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(
|
|
2207
|
-
for (const f of await scanForExports(
|
|
2208
|
-
for (const f of await scanForObsidianVaults(
|
|
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),
|
|
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(/^~(?=$|\/)/,
|
|
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 ${
|
|
2260
|
-
for (const f of manifest.exports.excluded) say(` ${dim(`\u2717 ${
|
|
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)
|
|
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(`
|
|
2315
|
-
say(` \u2022 keep
|
|
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("
|
|
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
|
|
2505
|
-
import
|
|
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
|
-
//
|
|
2756
|
-
|
|
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
|
|
3955
|
-
import
|
|
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-
|
|
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:
|
|
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
|
-
//
|
|
4181
|
-
//
|
|
4182
|
-
//
|
|
4183
|
-
//
|
|
4184
|
-
|
|
4185
|
-
|
|
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 percentile — it 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:
|
|
6283
|
-
const fullPath = [...
|
|
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,
|
|
6466
|
+
constructor(parent, value, path42, key) {
|
|
6400
6467
|
this._cachedPath = [];
|
|
6401
6468
|
this.parent = parent;
|
|
6402
6469
|
this.data = value;
|
|
6403
|
-
this._path =
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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/
|
|
22818
|
-
|
|
22819
|
-
|
|
22820
|
-
|
|
22821
|
-
|
|
22822
|
-
var
|
|
22823
|
-
|
|
22824
|
-
|
|
22825
|
-
|
|
22826
|
-
".
|
|
22827
|
-
|
|
22828
|
-
|
|
22829
|
-
|
|
22830
|
-
};
|
|
22831
|
-
|
|
22832
|
-
|
|
22833
|
-
|
|
22834
|
-
|
|
22835
|
-
|
|
22836
|
-
|
|
22837
|
-
|
|
22838
|
-
|
|
22839
|
-
|
|
22840
|
-
|
|
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
|
|
22858
|
-
|
|
22859
|
-
|
|
22860
|
-
|
|
22861
|
-
|
|
22862
|
-
|
|
22863
|
-
|
|
22864
|
-
|
|
22865
|
-
|
|
22866
|
-
|
|
22867
|
-
|
|
22868
|
-
}
|
|
22869
|
-
|
|
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
|
-
|
|
22873
|
-
|
|
22874
|
-
|
|
22875
|
-
|
|
22876
|
-
|
|
22877
|
-
|
|
22878
|
-
|
|
22879
|
-
};
|
|
22880
|
-
|
|
22881
|
-
|
|
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
|
-
|
|
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
|
|
22889
|
-
const
|
|
22890
|
-
|
|
22891
|
-
|
|
22892
|
-
|
|
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 (
|
|
22895
|
-
|
|
22896
|
-
|
|
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
|
|
22899
|
-
|
|
22900
|
-
|
|
22901
|
-
|
|
22902
|
-
|
|
22903
|
-
|
|
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
|
-
|
|
22906
|
-
|
|
22907
|
-
|
|
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
|
|
22915
|
-
|
|
22916
|
-
|
|
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, "<")}</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, "<")}</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) }));
|
|
23102
|
-
}
|
|
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
|
-
});
|
|
23127
|
-
});
|
|
23128
|
-
});
|
|
23129
|
-
}
|
|
23130
|
-
|
|
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
23046
|
|
|
23138
|
-
// ../../lib/agents/
|
|
23139
|
-
import {
|
|
23140
|
-
import
|
|
23141
|
-
import path28 from "path";
|
|
23047
|
+
// ../../lib/agents/coding/profile.ts
|
|
23048
|
+
import { promises as fs26 } from "fs";
|
|
23049
|
+
import path30 from "path";
|
|
23142
23050
|
|
|
23143
|
-
// ../../lib/agents/
|
|
23144
|
-
import
|
|
23145
|
-
import
|
|
23146
|
-
|
|
23147
|
-
|
|
23148
|
-
}
|
|
23149
|
-
function agentDir(agent) {
|
|
23150
|
-
return path27.join(polymathHome(), agent);
|
|
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);
|
|
23151
23057
|
}
|
|
23152
23058
|
|
|
23153
|
-
// ../../lib/agents/
|
|
23154
|
-
|
|
23155
|
-
|
|
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`;
|
|
23156
23069
|
}
|
|
23157
|
-
function
|
|
23158
|
-
|
|
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`;
|
|
23159
23074
|
}
|
|
23160
|
-
|
|
23161
|
-
|
|
23162
|
-
|
|
23163
|
-
|
|
23164
|
-
|
|
23165
|
-
|
|
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];
|
|
23166
23082
|
}
|
|
23167
|
-
var
|
|
23168
|
-
|
|
23169
|
-
|
|
23170
|
-
|
|
23171
|
-
|
|
23172
|
-
|
|
23173
|
-
|
|
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;
|
|
23174
23152
|
}
|
|
23175
|
-
|
|
23176
|
-
const
|
|
23177
|
-
|
|
23178
|
-
|
|
23179
|
-
|
|
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)) };
|
|
23180
23159
|
});
|
|
23181
|
-
|
|
23182
|
-
const
|
|
23183
|
-
|
|
23184
|
-
|
|
23185
|
-
|
|
23186
|
-
|
|
23187
|
-
|
|
23188
|
-
|
|
23189
|
-
}
|
|
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.`);
|
|
23190
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
|
+
};
|
|
23191
23193
|
}
|
|
23192
|
-
|
|
23193
|
-
|
|
23194
|
-
|
|
23195
|
-
|
|
23196
|
-
|
|
23197
|
-
|
|
23198
|
-
|
|
23199
|
-
|
|
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;
|
|
23225
|
+
}
|
|
23200
23226
|
}
|
|
23201
|
-
|
|
23202
|
-
|
|
23203
|
-
|
|
23204
|
-
|
|
23205
|
-
|
|
23206
|
-
|
|
23207
|
-
|
|
23208
|
-
|
|
23209
|
-
|
|
23210
|
-
|
|
23211
|
-
|
|
23212
|
-
|
|
23213
|
-
|
|
23214
|
-
|
|
23215
|
-
|
|
23216
|
-
|
|
23217
|
-
|
|
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
|
+
}
|
|
23218
23245
|
}
|
|
23219
|
-
|
|
23220
|
-
|
|
23221
|
-
const
|
|
23222
|
-
|
|
23223
|
-
|
|
23224
|
-
|
|
23225
|
-
|
|
23226
|
-
|
|
23227
|
-
|
|
23228
|
-
|
|
23229
|
-
|
|
23230
|
-
|
|
23231
|
-
|
|
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
|
|
23274
|
+
});
|
|
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
|
|
23232
23291
|
});
|
|
23233
23292
|
}
|
|
23234
|
-
|
|
23235
|
-
|
|
23236
|
-
|
|
23237
|
-
|
|
23238
|
-
|
|
23239
|
-
|
|
23240
|
-
|
|
23241
|
-
|
|
23242
|
-
|
|
23243
|
-
|
|
23244
|
-
|
|
23245
|
-
|
|
23246
|
-
|
|
23247
|
-
|
|
23248
|
-
|
|
23249
|
-
|
|
23250
|
-
|
|
23251
|
-
|
|
23252
|
-
|
|
23253
|
-
ordered.push(sha);
|
|
23254
|
-
}
|
|
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(() => {
|
|
23265
|
-
});
|
|
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);
|
|
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).`);
|
|
23273
23312
|
}
|
|
23274
|
-
|
|
23275
|
-
|
|
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
|
+
};
|
|
23276
23362
|
return {
|
|
23277
|
-
|
|
23278
|
-
|
|
23279
|
-
|
|
23280
|
-
|
|
23281
|
-
|
|
23282
|
-
|
|
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
|
|
23283
23380
|
};
|
|
23284
23381
|
}
|
|
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);
|
|
23290
|
-
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);
|
|
23299
|
-
} catch {
|
|
23300
|
-
return inertRunLog(refPath);
|
|
23301
|
-
}
|
|
23302
|
-
}
|
|
23303
23382
|
|
|
23304
|
-
//
|
|
23305
|
-
var
|
|
23306
|
-
|
|
23307
|
-
|
|
23308
|
-
|
|
23309
|
-
|
|
23310
|
-
|
|
23311
|
-
|
|
23312
|
-
const
|
|
23313
|
-
if (
|
|
23314
|
-
|
|
23315
|
-
|
|
23316
|
-
|
|
23317
|
-
|
|
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
|
|
23345
|
-
];
|
|
23346
|
-
}
|
|
23347
|
-
function bundledPipelineDir() {
|
|
23348
|
-
const d = path29.join(MODULE_DIR2, "pipeline");
|
|
23349
|
-
return existsSync5(path29.join(d, "coding-build.js")) ? d : null;
|
|
23383
|
+
// ../../lib/agents/coding/benchmarks.ts
|
|
23384
|
+
var BEST = DEFAULT_CALIBRATION.codingBenchmarks;
|
|
23385
|
+
|
|
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;
|
|
23350
23397
|
}
|
|
23351
|
-
|
|
23352
|
-
|
|
23353
|
-
|
|
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`);
|
|
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);
|
|
23364
23401
|
}
|
|
23365
|
-
function
|
|
23366
|
-
|
|
23367
|
-
|
|
23368
|
-
|
|
23369
|
-
|
|
23370
|
-
|
|
23371
|
-
|
|
23372
|
-
|
|
23373
|
-
|
|
23374
|
-
|
|
23375
|
-
|
|
23376
|
-
|
|
23377
|
-
});
|
|
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;
|
|
23378
23414
|
}
|
|
23379
|
-
function
|
|
23380
|
-
|
|
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 };
|
|
23381
23427
|
}
|
|
23382
|
-
function
|
|
23383
|
-
|
|
23384
|
-
|
|
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 = [];
|
|
23436
|
+
try {
|
|
23437
|
+
gradeFiles = (await fs26.readdir(GRADES2)).filter((f) => f.endsWith(".json"));
|
|
23438
|
+
} catch {
|
|
23385
23439
|
}
|
|
23386
|
-
|
|
23387
|
-
|
|
23388
|
-
|
|
23389
|
-
|
|
23390
|
-
return files.filter((f) => f.endsWith(".json") && f !== "report-run.json" && !f.startsWith(".")).sort().map((f) => path29.join(codingDir, f));
|
|
23391
|
-
}
|
|
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
|
-
);
|
|
23397
|
-
}
|
|
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 {
|
|
23406
|
-
}
|
|
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);
|
|
23407
23444
|
}
|
|
23408
|
-
const
|
|
23409
|
-
const
|
|
23410
|
-
|
|
23411
|
-
|
|
23412
|
-
|
|
23413
|
-
|
|
23414
|
-
|
|
23415
|
-
|
|
23416
|
-
|
|
23417
|
-
|
|
23418
|
-
|
|
23419
|
-
|
|
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);
|
|
23420
23461
|
}
|
|
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]);
|
|
23428
|
-
}
|
|
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
|
-
}));
|
|
23447
|
-
}
|
|
23448
|
-
log.event("pipeline_completed", { ok: failed.length === 0, failedStages: failed.length, ms: Date.now() - t0 });
|
|
23449
|
-
await log.finish();
|
|
23450
|
-
return { failed };
|
|
23451
|
-
}
|
|
23452
|
-
|
|
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;
|
|
23481
|
-
}
|
|
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() };
|
|
23493
|
-
}
|
|
23494
|
-
throw new Error(`chat-engine stage ${scriptRel}: neither repo scripts/ nor bundled dist/engine/ found`);
|
|
23495
|
-
}
|
|
23496
|
-
function hasChatPipeline(repoRoot) {
|
|
23497
|
-
return existsSync6(path31.join(repoRoot, "scripts", "run-tagger.mts")) || bundledEngineDir() != null;
|
|
23498
|
-
}
|
|
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();
|
|
23504
|
-
}
|
|
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);
|
|
23511
23462
|
}
|
|
23512
|
-
|
|
23513
|
-
|
|
23514
|
-
}
|
|
23515
|
-
function runStage2(repoRoot, st, env, onLine) {
|
|
23516
|
-
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}`)));
|
|
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 };
|
|
23527
23466
|
});
|
|
23528
|
-
|
|
23529
|
-
|
|
23530
|
-
|
|
23531
|
-
|
|
23532
|
-
|
|
23533
|
-
);
|
|
23534
|
-
|
|
23535
|
-
|
|
23536
|
-
|
|
23537
|
-
|
|
23538
|
-
|
|
23539
|
-
|
|
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: [] };
|
|
23543
|
-
}
|
|
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);
|
|
23560
|
-
}
|
|
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")
|
|
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);
|
|
23571
23479
|
}
|
|
23572
|
-
|
|
23573
|
-
|
|
23574
|
-
|
|
23575
|
-
|
|
23576
|
-
|
|
23577
|
-
|
|
23578
|
-
|
|
23579
|
-
|
|
23580
|
-
|
|
23581
|
-
|
|
23582
|
-
|
|
23583
|
-
|
|
23584
|
-
|
|
23585
|
-
|
|
23586
|
-
|
|
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
|
+
};
|
|
23587
23495
|
}
|
|
23588
|
-
log.event("ingest-export", { ok, ms: Date.now() - stStart, source: f.kind });
|
|
23589
23496
|
}
|
|
23590
|
-
|
|
23591
|
-
|
|
23592
|
-
|
|
23593
|
-
|
|
23594
|
-
|
|
23595
|
-
|
|
23596
|
-
|
|
23597
|
-
|
|
23598
|
-
const
|
|
23599
|
-
|
|
23600
|
-
|
|
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);
|
|
23601
23508
|
}
|
|
23602
|
-
const
|
|
23603
|
-
|
|
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 });
|
|
23604
23515
|
}
|
|
23605
|
-
|
|
23606
|
-
|
|
23607
|
-
|
|
23608
|
-
}
|
|
23609
|
-
|
|
23610
|
-
|
|
23611
|
-
|
|
23612
|
-
|
|
23613
|
-
|
|
23614
|
-
|
|
23615
|
-
|
|
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 };
|
|
23604
|
+
});
|
|
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;
|
|
23618
|
+
}
|
|
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
|
|
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;
|
|
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 };
|
|
23751
|
+
}
|
|
23616
23752
|
|
|
23617
|
-
// ../../lib/agents/coding/
|
|
23618
|
-
|
|
23619
|
-
|
|
23620
|
-
|
|
23621
|
-
|
|
23622
|
-
|
|
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 };
|
|
23835
|
+
try {
|
|
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;
|
|
23840
|
+
} catch {
|
|
23841
|
+
}
|
|
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: [] }
|
|
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": {} }
|
|
23912
|
+
}
|
|
23913
|
+
\`\`\``;
|
|
23914
|
+
}
|
|
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
|
+
}
|
|
23941
|
+
}
|
|
23942
|
+
return { dropped };
|
|
23943
|
+
}
|
|
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;
|
|
23950
|
+
}
|
|
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;
|
|
23959
|
+
}
|
|
23960
|
+
}
|
|
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;
|
|
23984
|
+
}
|
|
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;
|
|
24013
|
+
}
|
|
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;
|
|
24018
|
+
}
|
|
24019
|
+
console.error("[public-page] generation FAILED and no previous page exists");
|
|
24020
|
+
return null;
|
|
24021
|
+
}
|
|
24022
|
+
|
|
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;
|
|
24084
|
+
}
|
|
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) } };
|
|
24117
|
+
}
|
|
24118
|
+
}
|
|
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;
|
|
24125
|
+
}
|
|
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 } };
|
|
24130
|
+
}
|
|
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) } };
|
|
24141
|
+
}
|
|
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") });
|
|
24148
|
+
return out;
|
|
24149
|
+
}
|
|
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) {
|
|
24189
|
+
return new Promise((resolve2, reject) => {
|
|
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);
|
|
24203
|
+
});
|
|
24204
|
+
}
|
|
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;
|
|
24212
|
+
}
|
|
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");
|
|
24227
|
+
}
|
|
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;
|
|
24235
|
+
}
|
|
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;
|
|
24244
|
+
}
|
|
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];
|
|
24250
|
+
}
|
|
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];
|
|
24255
|
+
}
|
|
24256
|
+
}
|
|
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) => {
|
|
24299
|
+
try {
|
|
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, "<")}</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, "<")}</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");
|
|
24504
|
+
} catch (e) {
|
|
24505
|
+
res.writeHead(500, { "content-type": "application/json" }).end(JSON.stringify({ ok: false, error: String(e) }));
|
|
24506
|
+
}
|
|
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
|
+
});
|
|
23623
24537
|
}
|
|
23624
24538
|
|
|
23625
|
-
//
|
|
23626
|
-
|
|
23627
|
-
|
|
23628
|
-
|
|
23629
|
-
|
|
23630
|
-
|
|
23631
|
-
|
|
23632
|
-
|
|
23633
|
-
|
|
23634
|
-
|
|
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();
|
|
24546
|
+
|
|
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";
|
|
24551
|
+
|
|
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");
|
|
23635
24557
|
}
|
|
23636
|
-
function
|
|
23637
|
-
|
|
23638
|
-
|
|
23639
|
-
|
|
24558
|
+
function agentDir(agent) {
|
|
24559
|
+
return path34.join(polymathHome(), agent);
|
|
24560
|
+
}
|
|
24561
|
+
|
|
24562
|
+
// ../../lib/agents/shared/runLog.ts
|
|
24563
|
+
function runRefPath() {
|
|
24564
|
+
return path35.join(agentDir("report"), "latest.run.json");
|
|
23640
24565
|
}
|
|
23641
|
-
function
|
|
23642
|
-
|
|
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
|
-
|
|
23650
|
-
|
|
23651
|
-
|
|
23652
|
-
|
|
23653
|
-
|
|
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
|
-
|
|
23720
|
-
|
|
23721
|
-
|
|
23722
|
-
|
|
23723
|
-
|
|
23724
|
-
|
|
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
|
-
|
|
23727
|
-
const
|
|
23728
|
-
|
|
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
|
|
23761
|
-
|
|
23762
|
-
|
|
23763
|
-
|
|
23764
|
-
|
|
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
|
-
});
|
|
23858
|
-
}
|
|
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).`);
|
|
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 {
|
|
23878
24599
|
}
|
|
23879
|
-
|
|
23880
|
-
|
|
23881
|
-
|
|
23882
|
-
|
|
23883
|
-
|
|
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;
|
|
23884
24609
|
}
|
|
23885
|
-
|
|
23886
|
-
|
|
23887
|
-
|
|
23888
|
-
|
|
23889
|
-
|
|
23890
|
-
|
|
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
|
+
});
|
|
23891
24627
|
}
|
|
23892
|
-
|
|
23893
|
-
|
|
23894
|
-
|
|
23895
|
-
|
|
23896
|
-
|
|
23897
|
-
|
|
23898
|
-
|
|
23899
|
-
|
|
23900
|
-
|
|
23901
|
-
|
|
23902
|
-
|
|
23903
|
-
|
|
23904
|
-
|
|
23905
|
-
|
|
23906
|
-
archetype = "Balanced operator \u2014 solid systems knowledge and reasoning move in step, both clearly competent.";
|
|
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
|
+
});
|
|
23907
24642
|
}
|
|
23908
|
-
|
|
23909
|
-
|
|
23910
|
-
|
|
23911
|
-
|
|
23912
|
-
|
|
23913
|
-
|
|
23914
|
-
|
|
23915
|
-
|
|
23916
|
-
|
|
23917
|
-
|
|
23918
|
-
|
|
23919
|
-
|
|
23920
|
-
|
|
23921
|
-
|
|
23922
|
-
|
|
23923
|
-
|
|
23924
|
-
|
|
23925
|
-
|
|
23926
|
-
|
|
23927
|
-
|
|
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);
|
|
24682
|
+
}
|
|
24683
|
+
};
|
|
24684
|
+
function inertRunLog(refPath) {
|
|
23928
24685
|
return {
|
|
23929
|
-
|
|
23930
|
-
|
|
23931
|
-
|
|
23932
|
-
|
|
23933
|
-
|
|
23934
|
-
|
|
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
|
-
//
|
|
23950
|
-
var
|
|
23951
|
-
|
|
23952
|
-
|
|
23953
|
-
|
|
23954
|
-
|
|
23955
|
-
|
|
23956
|
-
|
|
23957
|
-
|
|
23958
|
-
|
|
23959
|
-
const
|
|
23960
|
-
const
|
|
23961
|
-
|
|
23962
|
-
return
|
|
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 };
|
|
23963
24727
|
}
|
|
23964
|
-
|
|
23965
|
-
|
|
23966
|
-
|
|
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
|
+
];
|
|
23967
24771
|
}
|
|
23968
|
-
function
|
|
23969
|
-
|
|
23970
|
-
|
|
23971
|
-
|
|
23972
|
-
|
|
23973
|
-
|
|
23974
|
-
|
|
23975
|
-
|
|
23976
|
-
|
|
23977
|
-
|
|
23978
|
-
|
|
23979
|
-
|
|
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
|
+
});
|
|
24803
|
+
}
|
|
24804
|
+
function hasPipeline(repoRoot) {
|
|
24805
|
+
return existsSync5(path36.join(repoRoot, "scripts", "coding-build.mts")) || bundledPipelineDir() != null;
|
|
24806
|
+
}
|
|
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
|
|
23982
|
-
const
|
|
23983
|
-
|
|
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
|
-
|
|
23995
|
-
const
|
|
23996
|
-
const
|
|
23997
|
-
|
|
23998
|
-
|
|
23999
|
-
|
|
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
|
-
|
|
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
|
-
|
|
24007
|
-
|
|
24008
|
-
|
|
24009
|
-
|
|
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
|
|
24012
|
-
|
|
24013
|
-
|
|
24014
|
-
|
|
24015
|
-
|
|
24016
|
-
|
|
24017
|
-
|
|
24018
|
-
|
|
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
|
|
24030
|
-
|
|
24031
|
-
|
|
24032
|
-
|
|
24033
|
-
const
|
|
24034
|
-
|
|
24035
|
-
|
|
24036
|
-
|
|
24037
|
-
|
|
24038
|
-
|
|
24039
|
-
|
|
24040
|
-
|
|
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
|
|
24064
|
-
const
|
|
24065
|
-
|
|
24066
|
-
|
|
24067
|
-
|
|
24068
|
-
|
|
24069
|
-
|
|
24070
|
-
|
|
24071
|
-
|
|
24072
|
-
|
|
24073
|
-
|
|
24074
|
-
|
|
24075
|
-
|
|
24076
|
-
|
|
24077
|
-
|
|
24078
|
-
|
|
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
|
-
|
|
24083
|
-
|
|
24084
|
-
const
|
|
24085
|
-
const
|
|
24086
|
-
|
|
24087
|
-
|
|
24088
|
-
|
|
24089
|
-
|
|
24090
|
-
|
|
24091
|
-
|
|
24092
|
-
|
|
24093
|
-
|
|
24094
|
-
|
|
24095
|
-
|
|
24096
|
-
|
|
24097
|
-
|
|
24098
|
-
|
|
24099
|
-
|
|
24100
|
-
|
|
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
|
-
|
|
24134
|
-
|
|
24135
|
-
|
|
24136
|
-
|
|
24137
|
-
|
|
24138
|
-
|
|
24139
|
-
|
|
24140
|
-
|
|
24141
|
-
|
|
24142
|
-
|
|
24143
|
-
|
|
24144
|
-
|
|
24145
|
-
|
|
24146
|
-
|
|
24147
|
-
|
|
24148
|
-
|
|
24149
|
-
|
|
24150
|
-
|
|
24151
|
-
|
|
24152
|
-
|
|
24153
|
-
|
|
24154
|
-
|
|
24155
|
-
|
|
24156
|
-
|
|
24157
|
-
|
|
24158
|
-
|
|
24159
|
-
|
|
24160
|
-
|
|
24161
|
-
|
|
24162
|
-
|
|
24163
|
-
|
|
24164
|
-
|
|
24165
|
-
|
|
24166
|
-
|
|
24167
|
-
|
|
24168
|
-
|
|
24169
|
-
|
|
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
|
|
24174
|
-
|
|
24175
|
-
|
|
24176
|
-
|
|
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
|
-
|
|
24186
|
-
|
|
24187
|
-
|
|
24188
|
-
|
|
24189
|
-
|
|
24190
|
-
|
|
24191
|
-
|
|
24192
|
-
|
|
24193
|
-
|
|
24194
|
-
|
|
24195
|
-
|
|
24196
|
-
|
|
24197
|
-
const
|
|
24198
|
-
const
|
|
24199
|
-
const
|
|
24200
|
-
|
|
24201
|
-
|
|
24202
|
-
|
|
24203
|
-
|
|
24204
|
-
|
|
24205
|
-
|
|
24206
|
-
|
|
24207
|
-
|
|
24208
|
-
|
|
24209
|
-
|
|
24210
|
-
|
|
24211
|
-
|
|
24212
|
-
|
|
24213
|
-
|
|
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
|
-
|
|
24217
|
-
|
|
24218
|
-
|
|
24219
|
-
|
|
24220
|
-
|
|
24221
|
-
|
|
24222
|
-
|
|
24223
|
-
|
|
24224
|
-
|
|
24225
|
-
|
|
24226
|
-
|
|
24227
|
-
|
|
24228
|
-
|
|
24229
|
-
|
|
24230
|
-
|
|
24231
|
-
|
|
24232
|
-
|
|
24233
|
-
|
|
24234
|
-
|
|
24235
|
-
|
|
24236
|
-
|
|
24237
|
-
|
|
24238
|
-
|
|
24239
|
-
|
|
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
|
-
|
|
24257
|
-
const
|
|
24258
|
-
const
|
|
24259
|
-
const
|
|
24260
|
-
const
|
|
24261
|
-
|
|
24262
|
-
|
|
24263
|
-
|
|
24264
|
-
|
|
24265
|
-
|
|
24266
|
-
|
|
24267
|
-
|
|
24268
|
-
|
|
24269
|
-
|
|
24270
|
-
|
|
24271
|
-
|
|
24272
|
-
|
|
24273
|
-
|
|
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
|
-
|
|
24310
|
-
|
|
24311
|
-
|
|
24312
|
-
|
|
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
|
-
|
|
25076
|
+
log.event("ingest-export", { ok, ms: Date.now() - stStart, source: f.kind });
|
|
24315
25077
|
}
|
|
24316
|
-
|
|
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
|
-
|
|
24321
|
-
var
|
|
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
|
|
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() {
|
|
@@ -24486,6 +25266,7 @@ async function main() {
|
|
|
24486
25266
|
return;
|
|
24487
25267
|
}
|
|
24488
25268
|
console.error(` data home: ${DATA_ROOT}`);
|
|
25269
|
+
await maybePrintUpdateNotice(opts);
|
|
24489
25270
|
const wantWizard = process.env.POLYMATH_WIZARD === "1" || process.env.POLYMATH_WIZARD !== "0" && process.argv.length <= 2 && !!process.stdin.isTTY && !!process.stdout.isTTY;
|
|
24490
25271
|
if (wantWizard) {
|
|
24491
25272
|
const { runWizard: runWizard2 } = await Promise.resolve().then(() => (init_wizard(), wizard_exports));
|
|
@@ -24501,7 +25282,7 @@ async function main() {
|
|
|
24501
25282
|
const backend = ensureBackend(opts.adapter);
|
|
24502
25283
|
if (!backend) process.exit(1);
|
|
24503
25284
|
console.error(`Using ${backend.name === "cli" ? "Claude Code" : "Codex"} (${backend.detail}).`);
|
|
24504
|
-
const gradeOut =
|
|
25285
|
+
const gradeOut = path41.resolve(opts.out || ".coding-analyzer-grades");
|
|
24505
25286
|
const provider = new LocalGradeProvider({
|
|
24506
25287
|
adapter: opts.adapter,
|
|
24507
25288
|
model: opts.model,
|
|
@@ -24510,8 +25291,8 @@ async function main() {
|
|
|
24510
25291
|
});
|
|
24511
25292
|
const profile2 = await analyze({ codex: opts.codex, idleGapMin: opts.idleGapMin, tz: opts.tz, spanHourMin: opts.spanHourMin, gradeProvider: provider });
|
|
24512
25293
|
const detail = provider.detail();
|
|
24513
|
-
await
|
|
24514
|
-
await
|
|
25294
|
+
await fs36.mkdir(gradeOut, { recursive: true });
|
|
25295
|
+
await fs36.writeFile(path41.join(gradeOut, "graded.json"), JSON.stringify(detail, null, 2));
|
|
24515
25296
|
console.error(`
|
|
24516
25297
|
Graded ${detail.gradedSessions} sessions \u2192 ${gradeOut}/graded.json`);
|
|
24517
25298
|
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 +25301,10 @@ Graded ${detail.gradedSessions} sessions \u2192 ${gradeOut}/graded.json`);
|
|
|
24520
25301
|
}
|
|
24521
25302
|
if (opts.cmd === "serve") {
|
|
24522
25303
|
let earlyHandle = null;
|
|
24523
|
-
const runMarker =
|
|
25304
|
+
const runMarker = path41.join(DATA_ROOT, "coding", ".grade-run.json");
|
|
24524
25305
|
if (!opts.grade) {
|
|
24525
25306
|
try {
|
|
24526
|
-
const mk = JSON.parse(await
|
|
25307
|
+
const mk = JSON.parse(await fs36.readFile(runMarker, "utf8"));
|
|
24527
25308
|
if (mk && mk.done === false) {
|
|
24528
25309
|
console.error(`
|
|
24529
25310
|
\u26A0\uFE0F An analysis started ${mk.startedAt ?? "earlier"} never finished (the process died mid-run).`);
|
|
@@ -24548,16 +25329,20 @@ Graded ${detail.gradedSessions} sessions \u2192 ${gradeOut}/graded.json`);
|
|
|
24548
25329
|
const when = (o) => o ? "at the 02:00 window tonight" : "now";
|
|
24549
25330
|
console.error(`
|
|
24550
25331
|
Running the full analysis on ${backend.name === "cli" ? "Claude Code" : "Codex"} \u2014 coding ${when(opts.overnight)}, chats ${when(chatOvernight)}.`);
|
|
24551
|
-
console.error("
|
|
25332
|
+
console.error("The report link appears right away and fills in as stages finish.\n");
|
|
24552
25333
|
const t0 = Date.now();
|
|
24553
25334
|
try {
|
|
24554
|
-
await
|
|
24555
|
-
await
|
|
25335
|
+
await fs36.mkdir(path41.dirname(runMarker), { recursive: true });
|
|
25336
|
+
await fs36.writeFile(runMarker, JSON.stringify({ startedAt: (/* @__PURE__ */ new Date()).toISOString(), done: false }));
|
|
24556
25337
|
} catch {
|
|
24557
25338
|
}
|
|
25339
|
+
const earlyProfile = await compileCodingProfile();
|
|
24558
25340
|
earlyHandle = await startServer({
|
|
24559
|
-
profile:
|
|
24560
|
-
|
|
25341
|
+
profile: earlyProfile,
|
|
25342
|
+
// Real sections from minute one (whatever's already on disk shares
|
|
25343
|
+
// fine), refreshed below as stages land — an empty {} here made
|
|
25344
|
+
// "Share report" 400 for the entire run (shipped 2026-07-14).
|
|
25345
|
+
shareSections: buildShareSections(earlyProfile),
|
|
24561
25346
|
version: await pkgVersion(),
|
|
24562
25347
|
shareUrl: opts.shareUrl || process.env.PS_SHARE_URL || DEFAULT_SHARE_URL,
|
|
24563
25348
|
port: opts.port,
|
|
@@ -24570,7 +25355,9 @@ Running the full analysis on ${backend.name === "cli" ? "Claude Code" : "Codex"}
|
|
|
24570
25355
|
earlyHandle.setProgress(progress);
|
|
24571
25356
|
const refreshProfile = async () => {
|
|
24572
25357
|
try {
|
|
24573
|
-
|
|
25358
|
+
const p = await compileCodingProfile();
|
|
25359
|
+
earlyHandle.setProfile(p);
|
|
25360
|
+
earlyHandle.setShareSections(buildShareSections(p));
|
|
24574
25361
|
} catch {
|
|
24575
25362
|
}
|
|
24576
25363
|
};
|
|
@@ -24605,13 +25392,14 @@ Running the full analysis on ${backend.name === "cli" ? "Claude Code" : "Codex"}
|
|
|
24605
25392
|
harvestWithin("coding", line);
|
|
24606
25393
|
codingLane.log(` ${line}`);
|
|
24607
25394
|
}
|
|
24608
|
-
}).then(async (
|
|
25395
|
+
}).then(async (codingRes2) => {
|
|
25396
|
+
const { failed: failed2 } = codingRes2;
|
|
24609
25397
|
progress.coding = { ...progress.coding ?? { i: 0, total: 0, label: "" }, done: true, failed: failed2.length };
|
|
24610
25398
|
earlyHandle.setProgress(progress);
|
|
24611
25399
|
await refreshProfile();
|
|
24612
25400
|
openBrowser(earlyHandle.url);
|
|
24613
25401
|
try {
|
|
24614
|
-
const stored = JSON.parse(await
|
|
25402
|
+
const stored = JSON.parse(await fs36.readFile(path41.join(DATA_ROOT, "notify-email.json"), "utf8"));
|
|
24615
25403
|
if (stored.email) {
|
|
24616
25404
|
const { requestEmailReminder: requestEmailReminder2 } = await Promise.resolve().then(() => (init_reminderEmail(), reminderEmail_exports));
|
|
24617
25405
|
const r = await requestEmailReminder2(stored.email, ["report-ready"], 1);
|
|
@@ -24619,7 +25407,7 @@ Running the full analysis on ${backend.name === "cli" ? "Claude Code" : "Codex"}
|
|
|
24619
25407
|
}
|
|
24620
25408
|
} catch {
|
|
24621
25409
|
}
|
|
24622
|
-
return
|
|
25410
|
+
return codingRes2;
|
|
24623
25411
|
});
|
|
24624
25412
|
const chatLane = mbar.lane("chat");
|
|
24625
25413
|
const chatDone = (async () => {
|
|
@@ -24652,7 +25440,8 @@ Running the full analysis on ${backend.name === "cli" ? "Claude Code" : "Codex"}
|
|
|
24652
25440
|
await refreshProfile();
|
|
24653
25441
|
return chat2;
|
|
24654
25442
|
})();
|
|
24655
|
-
const [
|
|
25443
|
+
const [codingRes, chat] = await Promise.all([codingDone, chatDone]);
|
|
25444
|
+
const { failed } = codingRes;
|
|
24656
25445
|
clearInterval(liveRefresh);
|
|
24657
25446
|
mbar.done();
|
|
24658
25447
|
if (failed.length) {
|
|
@@ -24661,6 +25450,11 @@ Running the full analysis on ${backend.name === "cli" ? "Claude Code" : "Codex"}
|
|
|
24661
25450
|
for (const f of failed) console.error(` \u2022 ${f.label} (${f.script}): ${f.error}`);
|
|
24662
25451
|
console.error(` Fix: run \`serve --grade\` again \u2014 it resumes, redoing ONLY the missing work.
|
|
24663
25452
|
`);
|
|
25453
|
+
} else if (codingRes.skippedLlm) {
|
|
25454
|
+
console.error(
|
|
25455
|
+
`
|
|
25456
|
+
\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.`
|
|
25457
|
+
);
|
|
24664
25458
|
} else {
|
|
24665
25459
|
console.error(`
|
|
24666
25460
|
\u2713 coding analysis complete in ${Math.round((Date.now() - t0) / 6e4)} min.`);
|
|
@@ -24679,11 +25473,11 @@ Running the full analysis on ${backend.name === "cli" ? "Claude Code" : "Codex"}
|
|
|
24679
25473
|
}
|
|
24680
25474
|
}
|
|
24681
25475
|
try {
|
|
24682
|
-
await
|
|
25476
|
+
await fs36.writeFile(runMarker, JSON.stringify({ startedAt: (/* @__PURE__ */ new Date()).toISOString(), done: true }));
|
|
24683
25477
|
} catch {
|
|
24684
25478
|
}
|
|
24685
25479
|
}
|
|
24686
|
-
if (!opts.grade && !existsSync7(
|
|
25480
|
+
if (!opts.grade && !existsSync7(path41.join(DATA_ROOT, "coding", "sessions.json")) && hasPipeline(REPO_ROOT)) {
|
|
24687
25481
|
console.error(`
|
|
24688
25482
|
No analysis here yet \u2014 computing the instant deterministic metrics now (free, no AI)\u2026`);
|
|
24689
25483
|
const d0 = Date.now();
|
|
@@ -24724,7 +25518,7 @@ No analysis here yet \u2014 computing the instant deterministic metrics now (fre
|
|
|
24724
25518
|
const nSessions = w.throughput?.sessions ?? 0;
|
|
24725
25519
|
const nGraded = w.gradedSessions ?? 0;
|
|
24726
25520
|
const who = await readIdentity(dataDir);
|
|
24727
|
-
if (nSessions === 0 && !existsSync7(
|
|
25521
|
+
if (nSessions === 0 && !existsSync7(path41.join(dataDir, "coding")) && !existsSync7(path41.join(dataDir, "engine-pilot"))) {
|
|
24728
25522
|
console.error(`
|
|
24729
25523
|
\u26A0\uFE0F ${dataDir} has no analysis artifacts \u2014 this will be an EMPTY report.`);
|
|
24730
25524
|
console.error(` Run from the directory where you ran the analysis, or set POLYMATH_DATA_DIR.`);
|
|
@@ -24750,7 +25544,7 @@ No analysis here yet \u2014 computing the instant deterministic metrics now (fre
|
|
|
24750
25544
|
const profile = await analyze({ codex: opts.codex, idleGapMin: opts.idleGapMin, tz: opts.tz, spanHourMin: opts.spanHourMin });
|
|
24751
25545
|
const payload = opts.cmd === "projects" ? profile.projects : opts.cmd === "flow" ? profile.flow : opts.cmd === "aggregate" ? profile.aggregate : profile;
|
|
24752
25546
|
if (opts.out) {
|
|
24753
|
-
await
|
|
25547
|
+
await fs36.writeFile(opts.out, JSON.stringify(payload, null, 2));
|
|
24754
25548
|
console.error(`wrote ${opts.cmd} \u2192 ${opts.out}`);
|
|
24755
25549
|
return;
|
|
24756
25550
|
}
|
|
@@ -24762,12 +25556,65 @@ No analysis here yet \u2014 computing the instant deterministic metrics now (fre
|
|
|
24762
25556
|
}
|
|
24763
25557
|
async function pkgVersion() {
|
|
24764
25558
|
try {
|
|
24765
|
-
const pkg = JSON.parse(await
|
|
25559
|
+
const pkg = JSON.parse(await fs36.readFile(path41.join(__dirname2, "..", "package.json"), "utf-8"));
|
|
24766
25560
|
return String(pkg.version || "0.0.0");
|
|
24767
25561
|
} catch {
|
|
24768
25562
|
return "0.0.0";
|
|
24769
25563
|
}
|
|
24770
25564
|
}
|
|
25565
|
+
function compareVersions(a, b) {
|
|
25566
|
+
const pa = a.split(".").map((x) => Number.parseInt(x, 10) || 0);
|
|
25567
|
+
const pb = b.split(".").map((x) => Number.parseInt(x, 10) || 0);
|
|
25568
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
25569
|
+
const d = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
25570
|
+
if (d) return d;
|
|
25571
|
+
}
|
|
25572
|
+
return 0;
|
|
25573
|
+
}
|
|
25574
|
+
async function maybePrintUpdateNotice(opts) {
|
|
25575
|
+
if (process.env.POLYMATH_NO_UPDATE_CHECK === "1") return;
|
|
25576
|
+
if (!process.stderr.isTTY) return;
|
|
25577
|
+
if (opts.json || opts.out) return;
|
|
25578
|
+
if (opts.cmd !== "profile" && opts.cmd !== "serve" && opts.cmd !== "grade") return;
|
|
25579
|
+
const cacheFile = path41.join(DATA_ROOT, "update-check.json");
|
|
25580
|
+
const now = Date.now();
|
|
25581
|
+
const ttlMs = 12 * 60 * 60 * 1e3;
|
|
25582
|
+
try {
|
|
25583
|
+
const cached2 = JSON.parse(await fs36.readFile(cacheFile, "utf8"));
|
|
25584
|
+
if (cached2.checkedAt && now - cached2.checkedAt < ttlMs) {
|
|
25585
|
+
const current = await pkgVersion();
|
|
25586
|
+
if (cached2.latest && compareVersions(cached2.latest, current) > 0) {
|
|
25587
|
+
console.error(` update available: polymath-society ${current} \u2192 ${cached2.latest}`);
|
|
25588
|
+
console.error(` run: npm install -g polymath-society@latest
|
|
25589
|
+
`);
|
|
25590
|
+
}
|
|
25591
|
+
return;
|
|
25592
|
+
}
|
|
25593
|
+
} catch {
|
|
25594
|
+
}
|
|
25595
|
+
const controller = new AbortController();
|
|
25596
|
+
const timer = setTimeout(() => controller.abort(), 1200);
|
|
25597
|
+
try {
|
|
25598
|
+
const current = await pkgVersion();
|
|
25599
|
+
const res = await fetch("https://registry.npmjs.org/polymath-society/latest", {
|
|
25600
|
+
signal: controller.signal,
|
|
25601
|
+
headers: { accept: "application/json" }
|
|
25602
|
+
});
|
|
25603
|
+
if (!res.ok) return;
|
|
25604
|
+
const latest = String((await res.json()).version ?? "");
|
|
25605
|
+
if (!latest) return;
|
|
25606
|
+
await fs36.writeFile(cacheFile, JSON.stringify({ checkedAt: now, latest }, null, 2), "utf8").catch(() => {
|
|
25607
|
+
});
|
|
25608
|
+
if (compareVersions(latest, current) > 0) {
|
|
25609
|
+
console.error(` update available: polymath-society ${current} \u2192 ${latest}`);
|
|
25610
|
+
console.error(` run: npm install -g polymath-society@latest
|
|
25611
|
+
`);
|
|
25612
|
+
}
|
|
25613
|
+
} catch {
|
|
25614
|
+
} finally {
|
|
25615
|
+
clearTimeout(timer);
|
|
25616
|
+
}
|
|
25617
|
+
}
|
|
24771
25618
|
function openBrowser(url) {
|
|
24772
25619
|
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
24773
25620
|
try {
|