polymath-society 0.2.10 → 0.2.12
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 +103 -20
- package/dist/engine/chat-loops.js +32 -1
- package/dist/engine/exp-allfacets.js +22 -1
- package/dist/engine/exp-person.js +22 -1
- package/dist/engine/exp-pipeline.js +22 -1
- package/dist/engine/peak-demos.js +22 -1
- package/dist/engine/person-dimension-summary.js +22 -1
- package/dist/engine/person-facet-lines.js +22 -1
- package/dist/engine/person-headline.js +22 -1
- package/dist/engine/person-report.js +22 -1
- package/dist/engine/person-self-image.js +22 -1
- package/dist/engine/public-report.js +22 -1
- package/dist/engine/run-analysis.js +22 -1
- package/dist/engine/run-tagger.js +22 -1
- package/dist/index.js +33 -4
- package/dist/pipeline/coding-agglomerate.js +22 -1
- package/dist/pipeline/coding-coaching.js +22 -1
- package/dist/pipeline/coding-day-digest.js +22 -1
- package/dist/pipeline/coding-delegation.js +22 -1
- package/dist/pipeline/coding-expertise.js +22 -1
- package/dist/pipeline/coding-focus.js +49 -4
- package/dist/pipeline/coding-frontier-detail.js +22 -1
- package/dist/pipeline/coding-gap.js +22 -1
- package/dist/pipeline/coding-grade.js +37 -2
- package/dist/pipeline/coding-nutshell.js +22 -1
- package/dist/pipeline/coding-walkthrough.js +38 -2
- package/dist/web/app.js +63 -0
- package/dist/web/styles.css +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -841,7 +841,19 @@ function aiWindowCutoff(sessions, opts = {}) {
|
|
|
841
841
|
const floorStart = gradableStarts[floor - 1];
|
|
842
842
|
return floorStart < windowCutoff ? floorStart : windowCutoff;
|
|
843
843
|
}
|
|
844
|
-
|
|
844
|
+
function maxGraded() {
|
|
845
|
+
const n = Number(process.env.POLYMATH_MAX_GRADED);
|
|
846
|
+
return Number.isFinite(n) && n >= 0 ? n : MAX_GRADED_DEFAULT;
|
|
847
|
+
}
|
|
848
|
+
function substanceRank(a, b) {
|
|
849
|
+
return b.humanChars * Math.log1p(b.humanTurns) - a.humanChars * Math.log1p(a.humanTurns);
|
|
850
|
+
}
|
|
851
|
+
function capGradable(gradable) {
|
|
852
|
+
const sorted = gradable.slice().sort(substanceRank);
|
|
853
|
+
const cap = maxGraded();
|
|
854
|
+
return cap > 0 && sorted.length > cap ? sorted.slice(0, cap) : sorted;
|
|
855
|
+
}
|
|
856
|
+
var GATE, AI_WINDOW, MAX_GRADED_DEFAULT;
|
|
845
857
|
var init_gate = __esm({
|
|
846
858
|
"../coding-core/dist/gate.js"() {
|
|
847
859
|
"use strict";
|
|
@@ -860,6 +872,7 @@ var init_gate = __esm({
|
|
|
860
872
|
minSessions: 40
|
|
861
873
|
// extend the window back until this many gradable sessions
|
|
862
874
|
};
|
|
875
|
+
MAX_GRADED_DEFAULT = 150;
|
|
863
876
|
}
|
|
864
877
|
});
|
|
865
878
|
|
|
@@ -868,10 +881,14 @@ var gate_exports = {};
|
|
|
868
881
|
__export(gate_exports, {
|
|
869
882
|
AI_WINDOW: () => AI_WINDOW,
|
|
870
883
|
GATE: () => GATE,
|
|
884
|
+
MAX_GRADED_DEFAULT: () => MAX_GRADED_DEFAULT,
|
|
871
885
|
aiWindowCutoff: () => aiWindowCutoff,
|
|
886
|
+
capGradable: () => capGradable,
|
|
872
887
|
isGradable: () => isGradable,
|
|
873
888
|
isTrivial: () => isTrivial,
|
|
874
|
-
|
|
889
|
+
maxGraded: () => maxGraded,
|
|
890
|
+
partition: () => partition,
|
|
891
|
+
substanceRank: () => substanceRank
|
|
875
892
|
});
|
|
876
893
|
var init_gate2 = __esm({
|
|
877
894
|
"src/gate.ts"() {
|
|
@@ -880,6 +897,31 @@ var init_gate2 = __esm({
|
|
|
880
897
|
}
|
|
881
898
|
});
|
|
882
899
|
|
|
900
|
+
// ../coding-core/dist/env.js
|
|
901
|
+
function claudeCliEnv(base2 = process.env) {
|
|
902
|
+
if (process.env.POLYMATH_USE_API_KEY === "1")
|
|
903
|
+
return base2;
|
|
904
|
+
const present = AUTH_VARS.filter((k) => base2[k]);
|
|
905
|
+
if (!present.length)
|
|
906
|
+
return base2;
|
|
907
|
+
if (!warned) {
|
|
908
|
+
warned = true;
|
|
909
|
+
console.error(`[polymath-society] ${present.join(" + ")} is set in your shell \u2014 ignoring it so the analysis runs on your claude.ai login (the key would take over auth and either fail or bill your API account). Set POLYMATH_USE_API_KEY=1 if you really want the API key used.`);
|
|
910
|
+
}
|
|
911
|
+
const scrubbed = { ...base2 };
|
|
912
|
+
for (const k of AUTH_VARS)
|
|
913
|
+
delete scrubbed[k];
|
|
914
|
+
return scrubbed;
|
|
915
|
+
}
|
|
916
|
+
var AUTH_VARS, warned;
|
|
917
|
+
var init_env = __esm({
|
|
918
|
+
"../coding-core/dist/env.js"() {
|
|
919
|
+
"use strict";
|
|
920
|
+
AUTH_VARS = ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN"];
|
|
921
|
+
warned = false;
|
|
922
|
+
}
|
|
923
|
+
});
|
|
924
|
+
|
|
883
925
|
// src/grade/adapter.ts
|
|
884
926
|
function extractJson(text2) {
|
|
885
927
|
const fences = [...text2.matchAll(/```json\s*([\s\S]*?)```/gi)];
|
|
@@ -1013,6 +1055,7 @@ var cliAdapter;
|
|
|
1013
1055
|
var init_cliAdapter = __esm({
|
|
1014
1056
|
"src/grade/cliAdapter.ts"() {
|
|
1015
1057
|
"use strict";
|
|
1058
|
+
init_env();
|
|
1016
1059
|
init_adapter();
|
|
1017
1060
|
init_backends();
|
|
1018
1061
|
cliAdapter = {
|
|
@@ -1049,7 +1092,9 @@ var init_cliAdapter = __esm({
|
|
|
1049
1092
|
await new Promise((resolve2, reject) => {
|
|
1050
1093
|
const child = spawn(bin, args, {
|
|
1051
1094
|
cwd: inv.cwd ?? inv.addDir,
|
|
1052
|
-
|
|
1095
|
+
// scrubbed: a stray ANTHROPIC_API_KEY in the user's shell hijacks the
|
|
1096
|
+
// claude CLI away from their claude.ai login (coding-core/env.ts)
|
|
1097
|
+
env: claudeCliEnv(),
|
|
1053
1098
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1054
1099
|
// Own process group, so a timeout can kill the WHOLE tree (claude spawns
|
|
1055
1100
|
// children that otherwise orphan and pile up).
|
|
@@ -2458,19 +2503,19 @@ function makeMultiBar(out = process.stderr) {
|
|
|
2458
2503
|
const lanes = /* @__PURE__ */ new Map();
|
|
2459
2504
|
let link = "";
|
|
2460
2505
|
let paintedRows = 0;
|
|
2461
|
-
const laneText = (name17, l) => {
|
|
2462
|
-
const w = l.within ? ` ${l.within.done}/${l.within.total}` : "";
|
|
2463
|
-
return `${name17} ${l.i}/${l.total} ${l.label.slice(0, 26)}${w}`;
|
|
2464
|
-
};
|
|
2465
2506
|
const rows = () => {
|
|
2466
|
-
const
|
|
2467
|
-
const parts = [...lanes.entries()].map(([n, l]) => laneText(n, l));
|
|
2468
|
-
const avg2 = lanes.size ? [...lanes.values()].reduce((a, l) => a + frac(l), 0) / lanes.size : 0;
|
|
2469
|
-
const width = 14;
|
|
2470
|
-
const fill = Math.max(0, Math.min(width, Math.round(avg2 * width)));
|
|
2507
|
+
const width = 16;
|
|
2471
2508
|
const elapsedMin = Math.round((Date.now() - t0) / 6e4);
|
|
2472
|
-
const
|
|
2473
|
-
|
|
2509
|
+
const laneRow = ([name17, l]) => {
|
|
2510
|
+
const frac = l.total ? (l.i - 1 + (l.within && l.within.total ? l.within.done / l.within.total : 0)) / l.total : 0;
|
|
2511
|
+
const clamped = Math.max(0, Math.min(1, frac));
|
|
2512
|
+
const fill = Math.round(clamped * width);
|
|
2513
|
+
return ` ${name17.padEnd(6)} [${"\u2588".repeat(fill)}${"\u2591".repeat(width - fill)}] ${String(Math.round(clamped * 100)).padStart(3)}%`;
|
|
2514
|
+
};
|
|
2515
|
+
const out2 = [];
|
|
2516
|
+
if (link) out2.push(`\u21B3 your reports (live, fill in as stages finish) \u2192 ${link} \xB7 ${elapsedMin}m`);
|
|
2517
|
+
out2.push(...[...lanes.entries()].map(laneRow));
|
|
2518
|
+
return out2.length ? out2 : [`(starting\u2026 ${elapsedMin}m)`];
|
|
2474
2519
|
};
|
|
2475
2520
|
const clearPinned = () => {
|
|
2476
2521
|
if (!paintedRows) return;
|
|
@@ -4360,6 +4405,7 @@ import { readFileSync } from "fs";
|
|
|
4360
4405
|
import path13 from "path";
|
|
4361
4406
|
|
|
4362
4407
|
// ../../lib/agents/shared/cliAdapter.ts
|
|
4408
|
+
init_env();
|
|
4363
4409
|
import { spawn as spawn3 } from "child_process";
|
|
4364
4410
|
import { promises as fs7 } from "fs";
|
|
4365
4411
|
import path7 from "path";
|
|
@@ -4468,7 +4514,9 @@ var cliAdapter2 = {
|
|
|
4468
4514
|
await new Promise((resolve2, reject) => {
|
|
4469
4515
|
const child = spawn3(CLAUDE_BIN, args, {
|
|
4470
4516
|
cwd: inv.cwd ?? inv.addDir,
|
|
4471
|
-
|
|
4517
|
+
// scrubbed: a stray ANTHROPIC_API_KEY in the user's shell hijacks the
|
|
4518
|
+
// claude CLI away from their claude.ai login (coding-core/env.ts)
|
|
4519
|
+
env: claudeCliEnv(),
|
|
4472
4520
|
stdio: ["ignore", "pipe", "pipe"],
|
|
4473
4521
|
// Own process group, so a timeout can kill the WHOLE tree (claude spawns
|
|
4474
4522
|
// its own children that otherwise orphan and pile up — the root cause of
|
|
@@ -24494,8 +24542,9 @@ function startServer(opts) {
|
|
|
24494
24542
|
if (req.method === "GET" && route === "/auth/callback") {
|
|
24495
24543
|
try {
|
|
24496
24544
|
const id = await completeLogin(dataDir, new URL(url, serverUrl).searchParams);
|
|
24545
|
+
const back = host === "127.0.0.1" ? serverUrl.replace("//127.0.0.1:", "//localhost:") : serverUrl;
|
|
24497
24546
|
res.writeHead(200, { "content-type": MIME[".html"] });
|
|
24498
|
-
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>`);
|
|
24547
|
+
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}/">Back to your report</a> (or just close this tab \u2014 the report page picks it up on its own).</p></body>`);
|
|
24499
24548
|
} catch (e) {
|
|
24500
24549
|
res.writeHead(400, { "content-type": MIME[".html"] });
|
|
24501
24550
|
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>`);
|
|
@@ -24659,7 +24708,12 @@ function startServer(opts) {
|
|
|
24659
24708
|
}).catch(() => {
|
|
24660
24709
|
});
|
|
24661
24710
|
resolve2({
|
|
24662
|
-
|
|
24711
|
+
// The DISPLAYED/opened URL says localhost — friendlier than 127.0.0.1
|
|
24712
|
+
// (owner call 2026-07-15); same server, same loopback. serverUrl itself
|
|
24713
|
+
// stays on the bound host because the Google sign-in redirect is
|
|
24714
|
+
// allow-listed for http://127.0.0.1:*/** in Supabase — auth flows
|
|
24715
|
+
// through 127.0.0.1 no matter which name the person's tab uses.
|
|
24716
|
+
url: host === "127.0.0.1" ? `http://localhost:${port}` : serverUrl,
|
|
24663
24717
|
port,
|
|
24664
24718
|
close: () => new Promise((r) => server.close(() => r())),
|
|
24665
24719
|
setProfile: (p) => {
|
|
@@ -24863,7 +24917,7 @@ function apportionHeavy(budget) {
|
|
|
24863
24917
|
const grade = Math.max(2, Math.floor(budget * 0.45));
|
|
24864
24918
|
const digest = Math.max(1, Math.floor(budget * 0.17));
|
|
24865
24919
|
const walkthrough = Math.max(1, Math.floor(budget * 0.17));
|
|
24866
|
-
const delegation = Math.max(1, budget - grade - digest - walkthrough -
|
|
24920
|
+
const delegation = Math.max(1, budget - grade - digest - walkthrough - 2);
|
|
24867
24921
|
return { grade, digest, walkthrough, delegation };
|
|
24868
24922
|
}
|
|
24869
24923
|
function stages(o) {
|
|
@@ -24896,6 +24950,14 @@ function stages(o) {
|
|
|
24896
24950
|
{ script: "coding-walkthrough.mts", label: "Per-session walkthroughs", llm: true, args: ["--model", model, "--conc", String(h.walkthrough)], batch: "heavy" },
|
|
24897
24951
|
{ script: "coding-frontier-detail.mts", label: "What you're doing at the frontier", llm: true, args: [], out: "coding/frontier-detail.json", batch: "heavy" },
|
|
24898
24952
|
{ script: "coding-delegation.mts", label: "Delegation patterns", llm: true, args: ["--model", model, "--conc", String(h.delegation)], out: "coding/delegation-rollup.json", batch: "heavy" },
|
|
24953
|
+
// The FULL focus stage: flow-rule judgment + the paste-into-CLAUDE.md block.
|
|
24954
|
+
// The deterministic --skip-llm run above keeps the numbers current every
|
|
24955
|
+
// run; this one produces the AI block — it was MISSING from the graded tier
|
|
24956
|
+
// entirely (688d788 added focus for the numbers-only tier and no one added
|
|
24957
|
+
// the companion), so overnight full runs shipped a report with no flow
|
|
24958
|
+
// rules and nothing failed loud (found 2026-07-15). Both LLM passes are
|
|
24959
|
+
// prompt-hash gated, so an unchanged corpus re-run costs zero calls.
|
|
24960
|
+
{ script: "coding-focus.mts", label: "Flow rules + focus judgment", llm: true, args: [], out: "coding/focus.json", batch: "heavy" },
|
|
24899
24961
|
// ---- corpus aggregate (reads grades; deterministic rollup) ----
|
|
24900
24962
|
{ script: "coding-aggregate.mts", label: "Corpus aggregate \u2014 ability ceiling + flow", llm: false, args: [], out: "coding/aggregate.json" },
|
|
24901
24963
|
// ---- grade readers (grades/* is complete once aggregate ran) ----
|
|
@@ -24962,11 +25024,12 @@ function upToDateSkip(i) {
|
|
|
24962
25024
|
}
|
|
24963
25025
|
async function evalUpToDate(codingDir, threshold, regrade) {
|
|
24964
25026
|
try {
|
|
24965
|
-
const { partition: partition2, aiWindowCutoff: aiWindowCutoff2 } = await Promise.resolve().then(() => (init_gate2(), gate_exports));
|
|
25027
|
+
const { partition: partition2, aiWindowCutoff: aiWindowCutoff2, capGradable: capGradable2 } = await Promise.resolve().then(() => (init_gate2(), gate_exports));
|
|
24966
25028
|
const sessions = JSON.parse(await fs31.readFile(path36.join(codingDir, "sessions.json"), "utf8"));
|
|
24967
25029
|
const live = sessions.filter((s) => s.klass === "interactive" && !s.duplicateOf);
|
|
24968
25030
|
const cutoff = aiWindowCutoff2(live);
|
|
24969
|
-
const { gradable } = partition2(cutoff ? live.filter((s) => (s.start ?? "") >= cutoff) : live);
|
|
25031
|
+
const { gradable: uncapped } = partition2(cutoff ? live.filter((s) => (s.start ?? "") >= cutoff) : live);
|
|
25032
|
+
const gradable = capGradable2(uncapped);
|
|
24970
25033
|
const graded = new Set(
|
|
24971
25034
|
(await fs31.readdir(path36.join(codingDir, "grades")).catch(() => [])).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -5))
|
|
24972
25035
|
);
|
|
@@ -25253,7 +25316,19 @@ async function runChatPipeline(o) {
|
|
|
25253
25316
|
}
|
|
25254
25317
|
log.event("ingest-export", { ok, ms: Date.now() - stStart, source: f.kind });
|
|
25255
25318
|
}
|
|
25319
|
+
const minNewDocs = Number(process.env.POLYMATH_MIN_NEW_DOCS ?? 10);
|
|
25320
|
+
const signalDocs = async () => {
|
|
25321
|
+
const t = await fs32.readFile(path37.join(dataRoot, "signals", "index.jsonl"), "utf8").catch(() => "");
|
|
25322
|
+
return t ? t.split("\n").filter(Boolean).length : 0;
|
|
25323
|
+
};
|
|
25324
|
+
const docsBeforeTagger = await signalDocs();
|
|
25325
|
+
let upToDate = false;
|
|
25256
25326
|
for (const st of chatEngineStages()) {
|
|
25327
|
+
if (upToDate && st.llm) {
|
|
25328
|
+
o.onStage?.(++idx, total, `${st.label} \u2014 up to date, skipped`, st.llm);
|
|
25329
|
+
log.event(st.script.replace(/\.mts$/, ""), { ok: true, ms: 0, skipped: true });
|
|
25330
|
+
continue;
|
|
25331
|
+
}
|
|
25257
25332
|
o.onStage?.(++idx, total, st.label, st.llm);
|
|
25258
25333
|
const stStart = Date.now();
|
|
25259
25334
|
let ok = true;
|
|
@@ -25267,6 +25342,14 @@ async function runChatPipeline(o) {
|
|
|
25267
25342
|
}
|
|
25268
25343
|
const sha = st.out ? await fileSha(path37.join(dataRoot, st.out)) : null;
|
|
25269
25344
|
log.event(st.script.replace(/\.mts$/, ""), { ok, ms: Date.now() - stStart, ...sha ? { sha } : {} });
|
|
25345
|
+
if (st.script === "run-tagger.mts" && ok && minNewDocs > 0) {
|
|
25346
|
+
const newDocs = await signalDocs() - docsBeforeTagger;
|
|
25347
|
+
const report = await fs32.readFile(path37.join(dataRoot, "engine-pilot", "public-report.json"), "utf8").then((s) => JSON.parse(s)).catch(() => null);
|
|
25348
|
+
if (report?.headline && (report.spikes?.length ?? 0) > 0 && newDocs < minNewDocs) {
|
|
25349
|
+
upToDate = true;
|
|
25350
|
+
o.onLine?.(`\u2713 chat report is up to date \u2014 ${newDocs} new doc(s) since the last full run (below the ${minNewDocs}-doc threshold), so the AI stages are skipped and the existing report is served as-is. POLYMATH_MIN_NEW_DOCS=0 forces a full run.`);
|
|
25351
|
+
}
|
|
25352
|
+
}
|
|
25270
25353
|
}
|
|
25271
25354
|
log.event("pipeline_completed", { ok: failed.length === 0, failedStages: failed.length, ms: Date.now() - t0 });
|
|
25272
25355
|
await log.finish();
|
|
@@ -1356,6 +1356,25 @@ import { spawn } from "child_process";
|
|
|
1356
1356
|
import { promises as fs2 } from "fs";
|
|
1357
1357
|
import path2 from "path";
|
|
1358
1358
|
|
|
1359
|
+
// ../coding-core/dist/env.js
|
|
1360
|
+
var AUTH_VARS = ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN"];
|
|
1361
|
+
var warned = false;
|
|
1362
|
+
function claudeCliEnv(base = process.env) {
|
|
1363
|
+
if (process.env.POLYMATH_USE_API_KEY === "1")
|
|
1364
|
+
return base;
|
|
1365
|
+
const present = AUTH_VARS.filter((k) => base[k]);
|
|
1366
|
+
if (!present.length)
|
|
1367
|
+
return base;
|
|
1368
|
+
if (!warned) {
|
|
1369
|
+
warned = true;
|
|
1370
|
+
console.error(`[polymath-society] ${present.join(" + ")} is set in your shell \u2014 ignoring it so the analysis runs on your claude.ai login (the key would take over auth and either fail or bill your API account). Set POLYMATH_USE_API_KEY=1 if you really want the API key used.`);
|
|
1371
|
+
}
|
|
1372
|
+
const scrubbed = { ...base };
|
|
1373
|
+
for (const k of AUTH_VARS)
|
|
1374
|
+
delete scrubbed[k];
|
|
1375
|
+
return scrubbed;
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1359
1378
|
// ../../lib/agents/shared/adapter.ts
|
|
1360
1379
|
function extractJson(text2) {
|
|
1361
1380
|
const fences = [...text2.matchAll(/```json\s*([\s\S]*?)```/gi)];
|
|
@@ -1460,7 +1479,9 @@ var cliAdapter = {
|
|
|
1460
1479
|
await new Promise((resolve2, reject) => {
|
|
1461
1480
|
const child = spawn(CLAUDE_BIN, args, {
|
|
1462
1481
|
cwd: inv.cwd ?? inv.addDir,
|
|
1463
|
-
|
|
1482
|
+
// scrubbed: a stray ANTHROPIC_API_KEY in the user's shell hijacks the
|
|
1483
|
+
// claude CLI away from their claude.ai login (coding-core/env.ts)
|
|
1484
|
+
env: claudeCliEnv(),
|
|
1464
1485
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1465
1486
|
// Own process group, so a timeout can kill the WHOLE tree (claude spawns
|
|
1466
1487
|
// its own children that otherwise orphan and pile up — the root cause of
|
|
@@ -16902,6 +16923,14 @@ async function run2() {
|
|
|
16902
16923
|
}
|
|
16903
16924
|
}
|
|
16904
16925
|
if (!sigs.length) throw new Error("loops: empty signals index \u2014 refusing to write");
|
|
16926
|
+
const fingerprint = `${sigs.length}:${sigs.reduce((a, s) => s.date > a ? s.date : a, "")}`;
|
|
16927
|
+
if (!process.env.LOOPS_REFRESH) {
|
|
16928
|
+
const prev2 = await fs6.readFile(OUT2, "utf8").then(JSON.parse).catch(() => null);
|
|
16929
|
+
if (prev2?.inputFingerprint === fingerprint && prev2?.loops?.loops?.length) {
|
|
16930
|
+
console.log(`loops: inputs unchanged (${sigs.length} signals) \u2014 keeping ${prev2.generatedAt} (LOOPS_REFRESH=1 to redo)`);
|
|
16931
|
+
return;
|
|
16932
|
+
}
|
|
16933
|
+
}
|
|
16905
16934
|
const artifacts = importArtifactDates(sigs);
|
|
16906
16935
|
const dated = sigs.filter((s) => !artifacts.has(s.date));
|
|
16907
16936
|
const chats = dated.filter((s) => s.source === "chatgpt" || s.source === "claude");
|
|
@@ -16988,6 +17017,8 @@ ${sample.join("\n")}`;
|
|
|
16988
17017
|
rules.sort((a, b) => a.date.localeCompare(b.date));
|
|
16989
17018
|
const out = {
|
|
16990
17019
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
17020
|
+
inputFingerprint: fingerprint,
|
|
17021
|
+
// the skip gate above compares against this
|
|
16991
17022
|
totals: { signals: sigs.length, dated: dated.length, chats: chats.length, ruleDeclarations: rules.length, importDatesExcluded: [...artifacts] },
|
|
16992
17023
|
chatsByMonth: monthCounts(chats.map((c) => c.date)),
|
|
16993
17024
|
rules,
|
|
@@ -153,6 +153,25 @@ import { spawn } from "child_process";
|
|
|
153
153
|
import { promises as fs2 } from "fs";
|
|
154
154
|
import path3 from "path";
|
|
155
155
|
|
|
156
|
+
// ../coding-core/dist/env.js
|
|
157
|
+
var AUTH_VARS = ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN"];
|
|
158
|
+
var warned = false;
|
|
159
|
+
function claudeCliEnv(base = process.env) {
|
|
160
|
+
if (process.env.POLYMATH_USE_API_KEY === "1")
|
|
161
|
+
return base;
|
|
162
|
+
const present = AUTH_VARS.filter((k) => base[k]);
|
|
163
|
+
if (!present.length)
|
|
164
|
+
return base;
|
|
165
|
+
if (!warned) {
|
|
166
|
+
warned = true;
|
|
167
|
+
console.error(`[polymath-society] ${present.join(" + ")} is set in your shell \u2014 ignoring it so the analysis runs on your claude.ai login (the key would take over auth and either fail or bill your API account). Set POLYMATH_USE_API_KEY=1 if you really want the API key used.`);
|
|
168
|
+
}
|
|
169
|
+
const scrubbed = { ...base };
|
|
170
|
+
for (const k of AUTH_VARS)
|
|
171
|
+
delete scrubbed[k];
|
|
172
|
+
return scrubbed;
|
|
173
|
+
}
|
|
174
|
+
|
|
156
175
|
// ../../lib/agents/shared/adapter.ts
|
|
157
176
|
function extractJson(text2) {
|
|
158
177
|
const fences = [...text2.matchAll(/```json\s*([\s\S]*?)```/gi)];
|
|
@@ -257,7 +276,9 @@ var cliAdapter = {
|
|
|
257
276
|
await new Promise((resolve2, reject) => {
|
|
258
277
|
const child = spawn(CLAUDE_BIN, args, {
|
|
259
278
|
cwd: inv.cwd ?? inv.addDir,
|
|
260
|
-
|
|
279
|
+
// scrubbed: a stray ANTHROPIC_API_KEY in the user's shell hijacks the
|
|
280
|
+
// claude CLI away from their claude.ai login (coding-core/env.ts)
|
|
281
|
+
env: claudeCliEnv(),
|
|
261
282
|
stdio: ["ignore", "pipe", "pipe"],
|
|
262
283
|
// Own process group, so a timeout can kill the WHOLE tree (claude spawns
|
|
263
284
|
// its own children that otherwise orphan and pile up — the root cause of
|
|
@@ -153,6 +153,25 @@ import { spawn } from "child_process";
|
|
|
153
153
|
import { promises as fs2 } from "fs";
|
|
154
154
|
import path3 from "path";
|
|
155
155
|
|
|
156
|
+
// ../coding-core/dist/env.js
|
|
157
|
+
var AUTH_VARS = ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN"];
|
|
158
|
+
var warned = false;
|
|
159
|
+
function claudeCliEnv(base = process.env) {
|
|
160
|
+
if (process.env.POLYMATH_USE_API_KEY === "1")
|
|
161
|
+
return base;
|
|
162
|
+
const present = AUTH_VARS.filter((k) => base[k]);
|
|
163
|
+
if (!present.length)
|
|
164
|
+
return base;
|
|
165
|
+
if (!warned) {
|
|
166
|
+
warned = true;
|
|
167
|
+
console.error(`[polymath-society] ${present.join(" + ")} is set in your shell \u2014 ignoring it so the analysis runs on your claude.ai login (the key would take over auth and either fail or bill your API account). Set POLYMATH_USE_API_KEY=1 if you really want the API key used.`);
|
|
168
|
+
}
|
|
169
|
+
const scrubbed = { ...base };
|
|
170
|
+
for (const k of AUTH_VARS)
|
|
171
|
+
delete scrubbed[k];
|
|
172
|
+
return scrubbed;
|
|
173
|
+
}
|
|
174
|
+
|
|
156
175
|
// ../../lib/agents/shared/adapter.ts
|
|
157
176
|
function extractJson(text2) {
|
|
158
177
|
const fences = [...text2.matchAll(/```json\s*([\s\S]*?)```/gi)];
|
|
@@ -257,7 +276,9 @@ var cliAdapter = {
|
|
|
257
276
|
await new Promise((resolve2, reject) => {
|
|
258
277
|
const child = spawn(CLAUDE_BIN, args, {
|
|
259
278
|
cwd: inv.cwd ?? inv.addDir,
|
|
260
|
-
|
|
279
|
+
// scrubbed: a stray ANTHROPIC_API_KEY in the user's shell hijacks the
|
|
280
|
+
// claude CLI away from their claude.ai login (coding-core/env.ts)
|
|
281
|
+
env: claudeCliEnv(),
|
|
261
282
|
stdio: ["ignore", "pipe", "pipe"],
|
|
262
283
|
// Own process group, so a timeout can kill the WHOLE tree (claude spawns
|
|
263
284
|
// its own children that otherwise orphan and pile up — the root cause of
|
|
@@ -148,6 +148,25 @@ import { spawn } from "child_process";
|
|
|
148
148
|
import { promises as fs2 } from "fs";
|
|
149
149
|
import path2 from "path";
|
|
150
150
|
|
|
151
|
+
// ../coding-core/dist/env.js
|
|
152
|
+
var AUTH_VARS = ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN"];
|
|
153
|
+
var warned = false;
|
|
154
|
+
function claudeCliEnv(base = process.env) {
|
|
155
|
+
if (process.env.POLYMATH_USE_API_KEY === "1")
|
|
156
|
+
return base;
|
|
157
|
+
const present = AUTH_VARS.filter((k) => base[k]);
|
|
158
|
+
if (!present.length)
|
|
159
|
+
return base;
|
|
160
|
+
if (!warned) {
|
|
161
|
+
warned = true;
|
|
162
|
+
console.error(`[polymath-society] ${present.join(" + ")} is set in your shell \u2014 ignoring it so the analysis runs on your claude.ai login (the key would take over auth and either fail or bill your API account). Set POLYMATH_USE_API_KEY=1 if you really want the API key used.`);
|
|
163
|
+
}
|
|
164
|
+
const scrubbed = { ...base };
|
|
165
|
+
for (const k of AUTH_VARS)
|
|
166
|
+
delete scrubbed[k];
|
|
167
|
+
return scrubbed;
|
|
168
|
+
}
|
|
169
|
+
|
|
151
170
|
// ../../lib/agents/shared/adapter.ts
|
|
152
171
|
function extractJson(text2) {
|
|
153
172
|
const fences = [...text2.matchAll(/```json\s*([\s\S]*?)```/gi)];
|
|
@@ -252,7 +271,9 @@ var cliAdapter = {
|
|
|
252
271
|
await new Promise((resolve2, reject) => {
|
|
253
272
|
const child = spawn(CLAUDE_BIN, args, {
|
|
254
273
|
cwd: inv.cwd ?? inv.addDir,
|
|
255
|
-
|
|
274
|
+
// scrubbed: a stray ANTHROPIC_API_KEY in the user's shell hijacks the
|
|
275
|
+
// claude CLI away from their claude.ai login (coding-core/env.ts)
|
|
276
|
+
env: claudeCliEnv(),
|
|
256
277
|
stdio: ["ignore", "pipe", "pipe"],
|
|
257
278
|
// Own process group, so a timeout can kill the WHOLE tree (claude spawns
|
|
258
279
|
// its own children that otherwise orphan and pile up — the root cause of
|
|
@@ -1144,6 +1144,25 @@ import { spawn } from "child_process";
|
|
|
1144
1144
|
import { promises as fs3 } from "fs";
|
|
1145
1145
|
import path4 from "path";
|
|
1146
1146
|
|
|
1147
|
+
// ../coding-core/dist/env.js
|
|
1148
|
+
var AUTH_VARS = ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN"];
|
|
1149
|
+
var warned = false;
|
|
1150
|
+
function claudeCliEnv(base = process.env) {
|
|
1151
|
+
if (process.env.POLYMATH_USE_API_KEY === "1")
|
|
1152
|
+
return base;
|
|
1153
|
+
const present = AUTH_VARS.filter((k) => base[k]);
|
|
1154
|
+
if (!present.length)
|
|
1155
|
+
return base;
|
|
1156
|
+
if (!warned) {
|
|
1157
|
+
warned = true;
|
|
1158
|
+
console.error(`[polymath-society] ${present.join(" + ")} is set in your shell \u2014 ignoring it so the analysis runs on your claude.ai login (the key would take over auth and either fail or bill your API account). Set POLYMATH_USE_API_KEY=1 if you really want the API key used.`);
|
|
1159
|
+
}
|
|
1160
|
+
const scrubbed = { ...base };
|
|
1161
|
+
for (const k of AUTH_VARS)
|
|
1162
|
+
delete scrubbed[k];
|
|
1163
|
+
return scrubbed;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1147
1166
|
// ../../lib/agents/shared/adapter.ts
|
|
1148
1167
|
function extractJson(text2) {
|
|
1149
1168
|
const fences = [...text2.matchAll(/```json\s*([\s\S]*?)```/gi)];
|
|
@@ -1248,7 +1267,9 @@ var cliAdapter = {
|
|
|
1248
1267
|
await new Promise((resolve2, reject) => {
|
|
1249
1268
|
const child = spawn(CLAUDE_BIN, args, {
|
|
1250
1269
|
cwd: inv.cwd ?? inv.addDir,
|
|
1251
|
-
|
|
1270
|
+
// scrubbed: a stray ANTHROPIC_API_KEY in the user's shell hijacks the
|
|
1271
|
+
// claude CLI away from their claude.ai login (coding-core/env.ts)
|
|
1272
|
+
env: claudeCliEnv(),
|
|
1252
1273
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1253
1274
|
// Own process group, so a timeout can kill the WHOLE tree (claude spawns
|
|
1254
1275
|
// its own children that otherwise orphan and pile up — the root cause of
|
|
@@ -1144,6 +1144,25 @@ import { spawn } from "child_process";
|
|
|
1144
1144
|
import { promises as fs3 } from "fs";
|
|
1145
1145
|
import path4 from "path";
|
|
1146
1146
|
|
|
1147
|
+
// ../coding-core/dist/env.js
|
|
1148
|
+
var AUTH_VARS = ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN"];
|
|
1149
|
+
var warned = false;
|
|
1150
|
+
function claudeCliEnv(base = process.env) {
|
|
1151
|
+
if (process.env.POLYMATH_USE_API_KEY === "1")
|
|
1152
|
+
return base;
|
|
1153
|
+
const present = AUTH_VARS.filter((k) => base[k]);
|
|
1154
|
+
if (!present.length)
|
|
1155
|
+
return base;
|
|
1156
|
+
if (!warned) {
|
|
1157
|
+
warned = true;
|
|
1158
|
+
console.error(`[polymath-society] ${present.join(" + ")} is set in your shell \u2014 ignoring it so the analysis runs on your claude.ai login (the key would take over auth and either fail or bill your API account). Set POLYMATH_USE_API_KEY=1 if you really want the API key used.`);
|
|
1159
|
+
}
|
|
1160
|
+
const scrubbed = { ...base };
|
|
1161
|
+
for (const k of AUTH_VARS)
|
|
1162
|
+
delete scrubbed[k];
|
|
1163
|
+
return scrubbed;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1147
1166
|
// ../../lib/agents/shared/adapter.ts
|
|
1148
1167
|
function extractJson(text2) {
|
|
1149
1168
|
const fences = [...text2.matchAll(/```json\s*([\s\S]*?)```/gi)];
|
|
@@ -1248,7 +1267,9 @@ var cliAdapter = {
|
|
|
1248
1267
|
await new Promise((resolve2, reject) => {
|
|
1249
1268
|
const child = spawn(CLAUDE_BIN, args, {
|
|
1250
1269
|
cwd: inv.cwd ?? inv.addDir,
|
|
1251
|
-
|
|
1270
|
+
// scrubbed: a stray ANTHROPIC_API_KEY in the user's shell hijacks the
|
|
1271
|
+
// claude CLI away from their claude.ai login (coding-core/env.ts)
|
|
1272
|
+
env: claudeCliEnv(),
|
|
1252
1273
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1253
1274
|
// Own process group, so a timeout can kill the WHOLE tree (claude spawns
|
|
1254
1275
|
// its own children that otherwise orphan and pile up — the root cause of
|
|
@@ -1144,6 +1144,25 @@ import { spawn } from "child_process";
|
|
|
1144
1144
|
import { promises as fs3 } from "fs";
|
|
1145
1145
|
import path4 from "path";
|
|
1146
1146
|
|
|
1147
|
+
// ../coding-core/dist/env.js
|
|
1148
|
+
var AUTH_VARS = ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN"];
|
|
1149
|
+
var warned = false;
|
|
1150
|
+
function claudeCliEnv(base = process.env) {
|
|
1151
|
+
if (process.env.POLYMATH_USE_API_KEY === "1")
|
|
1152
|
+
return base;
|
|
1153
|
+
const present = AUTH_VARS.filter((k) => base[k]);
|
|
1154
|
+
if (!present.length)
|
|
1155
|
+
return base;
|
|
1156
|
+
if (!warned) {
|
|
1157
|
+
warned = true;
|
|
1158
|
+
console.error(`[polymath-society] ${present.join(" + ")} is set in your shell \u2014 ignoring it so the analysis runs on your claude.ai login (the key would take over auth and either fail or bill your API account). Set POLYMATH_USE_API_KEY=1 if you really want the API key used.`);
|
|
1159
|
+
}
|
|
1160
|
+
const scrubbed = { ...base };
|
|
1161
|
+
for (const k of AUTH_VARS)
|
|
1162
|
+
delete scrubbed[k];
|
|
1163
|
+
return scrubbed;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1147
1166
|
// ../../lib/agents/shared/adapter.ts
|
|
1148
1167
|
function extractJson(text2) {
|
|
1149
1168
|
const fences = [...text2.matchAll(/```json\s*([\s\S]*?)```/gi)];
|
|
@@ -1248,7 +1267,9 @@ var cliAdapter = {
|
|
|
1248
1267
|
await new Promise((resolve2, reject) => {
|
|
1249
1268
|
const child = spawn(CLAUDE_BIN, args, {
|
|
1250
1269
|
cwd: inv.cwd ?? inv.addDir,
|
|
1251
|
-
|
|
1270
|
+
// scrubbed: a stray ANTHROPIC_API_KEY in the user's shell hijacks the
|
|
1271
|
+
// claude CLI away from their claude.ai login (coding-core/env.ts)
|
|
1272
|
+
env: claudeCliEnv(),
|
|
1252
1273
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1253
1274
|
// Own process group, so a timeout can kill the WHOLE tree (claude spawns
|
|
1254
1275
|
// its own children that otherwise orphan and pile up — the root cause of
|
|
@@ -1144,6 +1144,25 @@ import { spawn } from "child_process";
|
|
|
1144
1144
|
import { promises as fs3 } from "fs";
|
|
1145
1145
|
import path4 from "path";
|
|
1146
1146
|
|
|
1147
|
+
// ../coding-core/dist/env.js
|
|
1148
|
+
var AUTH_VARS = ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN"];
|
|
1149
|
+
var warned = false;
|
|
1150
|
+
function claudeCliEnv(base = process.env) {
|
|
1151
|
+
if (process.env.POLYMATH_USE_API_KEY === "1")
|
|
1152
|
+
return base;
|
|
1153
|
+
const present = AUTH_VARS.filter((k) => base[k]);
|
|
1154
|
+
if (!present.length)
|
|
1155
|
+
return base;
|
|
1156
|
+
if (!warned) {
|
|
1157
|
+
warned = true;
|
|
1158
|
+
console.error(`[polymath-society] ${present.join(" + ")} is set in your shell \u2014 ignoring it so the analysis runs on your claude.ai login (the key would take over auth and either fail or bill your API account). Set POLYMATH_USE_API_KEY=1 if you really want the API key used.`);
|
|
1159
|
+
}
|
|
1160
|
+
const scrubbed = { ...base };
|
|
1161
|
+
for (const k of AUTH_VARS)
|
|
1162
|
+
delete scrubbed[k];
|
|
1163
|
+
return scrubbed;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1147
1166
|
// ../../lib/agents/shared/adapter.ts
|
|
1148
1167
|
function extractJson(text2) {
|
|
1149
1168
|
const fences = [...text2.matchAll(/```json\s*([\s\S]*?)```/gi)];
|
|
@@ -1248,7 +1267,9 @@ var cliAdapter = {
|
|
|
1248
1267
|
await new Promise((resolve2, reject) => {
|
|
1249
1268
|
const child = spawn(CLAUDE_BIN, args, {
|
|
1250
1269
|
cwd: inv.cwd ?? inv.addDir,
|
|
1251
|
-
|
|
1270
|
+
// scrubbed: a stray ANTHROPIC_API_KEY in the user's shell hijacks the
|
|
1271
|
+
// claude CLI away from their claude.ai login (coding-core/env.ts)
|
|
1272
|
+
env: claudeCliEnv(),
|
|
1252
1273
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1253
1274
|
// Own process group, so a timeout can kill the WHOLE tree (claude spawns
|
|
1254
1275
|
// its own children that otherwise orphan and pile up — the root cause of
|
|
@@ -1144,6 +1144,25 @@ import { spawn } from "child_process";
|
|
|
1144
1144
|
import { promises as fs3 } from "fs";
|
|
1145
1145
|
import path4 from "path";
|
|
1146
1146
|
|
|
1147
|
+
// ../coding-core/dist/env.js
|
|
1148
|
+
var AUTH_VARS = ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN"];
|
|
1149
|
+
var warned = false;
|
|
1150
|
+
function claudeCliEnv(base = process.env) {
|
|
1151
|
+
if (process.env.POLYMATH_USE_API_KEY === "1")
|
|
1152
|
+
return base;
|
|
1153
|
+
const present = AUTH_VARS.filter((k) => base[k]);
|
|
1154
|
+
if (!present.length)
|
|
1155
|
+
return base;
|
|
1156
|
+
if (!warned) {
|
|
1157
|
+
warned = true;
|
|
1158
|
+
console.error(`[polymath-society] ${present.join(" + ")} is set in your shell \u2014 ignoring it so the analysis runs on your claude.ai login (the key would take over auth and either fail or bill your API account). Set POLYMATH_USE_API_KEY=1 if you really want the API key used.`);
|
|
1159
|
+
}
|
|
1160
|
+
const scrubbed = { ...base };
|
|
1161
|
+
for (const k of AUTH_VARS)
|
|
1162
|
+
delete scrubbed[k];
|
|
1163
|
+
return scrubbed;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1147
1166
|
// ../../lib/agents/shared/adapter.ts
|
|
1148
1167
|
function extractJson(text2) {
|
|
1149
1168
|
const fences = [...text2.matchAll(/```json\s*([\s\S]*?)```/gi)];
|
|
@@ -1248,7 +1267,9 @@ var cliAdapter = {
|
|
|
1248
1267
|
await new Promise((resolve2, reject) => {
|
|
1249
1268
|
const child = spawn(CLAUDE_BIN, args, {
|
|
1250
1269
|
cwd: inv.cwd ?? inv.addDir,
|
|
1251
|
-
|
|
1270
|
+
// scrubbed: a stray ANTHROPIC_API_KEY in the user's shell hijacks the
|
|
1271
|
+
// claude CLI away from their claude.ai login (coding-core/env.ts)
|
|
1272
|
+
env: claudeCliEnv(),
|
|
1252
1273
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1253
1274
|
// Own process group, so a timeout can kill the WHOLE tree (claude spawns
|
|
1254
1275
|
// its own children that otherwise orphan and pile up — the root cause of
|
|
@@ -1096,6 +1096,25 @@ import { spawn } from "child_process";
|
|
|
1096
1096
|
import { promises as fs4 } from "fs";
|
|
1097
1097
|
import path5 from "path";
|
|
1098
1098
|
|
|
1099
|
+
// ../coding-core/dist/env.js
|
|
1100
|
+
var AUTH_VARS = ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN"];
|
|
1101
|
+
var warned = false;
|
|
1102
|
+
function claudeCliEnv(base = process.env) {
|
|
1103
|
+
if (process.env.POLYMATH_USE_API_KEY === "1")
|
|
1104
|
+
return base;
|
|
1105
|
+
const present = AUTH_VARS.filter((k) => base[k]);
|
|
1106
|
+
if (!present.length)
|
|
1107
|
+
return base;
|
|
1108
|
+
if (!warned) {
|
|
1109
|
+
warned = true;
|
|
1110
|
+
console.error(`[polymath-society] ${present.join(" + ")} is set in your shell \u2014 ignoring it so the analysis runs on your claude.ai login (the key would take over auth and either fail or bill your API account). Set POLYMATH_USE_API_KEY=1 if you really want the API key used.`);
|
|
1111
|
+
}
|
|
1112
|
+
const scrubbed = { ...base };
|
|
1113
|
+
for (const k of AUTH_VARS)
|
|
1114
|
+
delete scrubbed[k];
|
|
1115
|
+
return scrubbed;
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1099
1118
|
// ../../lib/agents/shared/adapter.ts
|
|
1100
1119
|
function extractJson(text2) {
|
|
1101
1120
|
const fences = [...text2.matchAll(/```json\s*([\s\S]*?)```/gi)];
|
|
@@ -1200,7 +1219,9 @@ var cliAdapter = {
|
|
|
1200
1219
|
await new Promise((resolve2, reject) => {
|
|
1201
1220
|
const child = spawn(CLAUDE_BIN, args, {
|
|
1202
1221
|
cwd: inv.cwd ?? inv.addDir,
|
|
1203
|
-
|
|
1222
|
+
// scrubbed: a stray ANTHROPIC_API_KEY in the user's shell hijacks the
|
|
1223
|
+
// claude CLI away from their claude.ai login (coding-core/env.ts)
|
|
1224
|
+
env: claudeCliEnv(),
|
|
1204
1225
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1205
1226
|
// Own process group, so a timeout can kill the WHOLE tree (claude spawns
|
|
1206
1227
|
// its own children that otherwise orphan and pile up — the root cause of
|