polymath-society 0.2.25 → 0.2.27
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 +170 -51
- package/dist/index.js +8 -1
- package/dist/pipeline/coding-agglomerate.js +1 -0
- package/dist/web/app.js +7 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -22834,6 +22834,8 @@ __export(pipeline_exports, {
|
|
|
22834
22834
|
runPipeline: () => runPipeline,
|
|
22835
22835
|
stages: () => stages,
|
|
22836
22836
|
startKeepAwake: () => startKeepAwake,
|
|
22837
|
+
trackStageChild: () => trackStageChild,
|
|
22838
|
+
untrackStageChild: () => untrackStageChild,
|
|
22837
22839
|
upToDateSkip: () => upToDateSkip
|
|
22838
22840
|
});
|
|
22839
22841
|
import { spawn as spawn7 } from "child_process";
|
|
@@ -22849,8 +22851,8 @@ function machineBudget(totalMemBytes = os8.totalmem(), cpus = os8.availableParal
|
|
|
22849
22851
|
}
|
|
22850
22852
|
function apportionHeavy(budget) {
|
|
22851
22853
|
const grade = Math.max(2, Math.floor(budget * 0.45));
|
|
22852
|
-
const digest = Math.max(1, Math.floor(budget * 0.
|
|
22853
|
-
const walkthrough = Math.max(1, Math.floor(budget * 0.
|
|
22854
|
+
const digest = Math.max(1, Math.floor(budget * 0.13));
|
|
22855
|
+
const walkthrough = Math.max(1, Math.floor(budget * 0.25));
|
|
22854
22856
|
const delegation = Math.max(1, budget - grade - digest - walkthrough - 2);
|
|
22855
22857
|
return { grade, digest, walkthrough, delegation };
|
|
22856
22858
|
}
|
|
@@ -22882,11 +22884,12 @@ function stages(o) {
|
|
|
22882
22884
|
// so they run WHILE grading runs (grading is the wall-clock giant; these
|
|
22883
22885
|
// finish inside its shadow). Budget: grade 8 + digest 3 + walkthrough 3 +
|
|
22884
22886
|
// two single-call stages ≈ 16 peak subprocesses (measured-safe envelope).
|
|
22885
|
-
{ script: "coding-grade.mts", label: "AI-grade every substantial session", llm: true, args: gradeArgs, batch: "heavy" },
|
|
22886
|
-
{ script: "coding-day-digest.mts", label: "Day-by-day digests", llm: true, args: ["--model", narrativeModel, "--conc", String(h.digest)], out: "coding/day-digest.json", batch: "heavy" },
|
|
22887
|
-
|
|
22888
|
-
{ script: "coding-
|
|
22889
|
-
{ script: "coding-
|
|
22887
|
+
{ script: "coding-grade.mts", label: "AI-grade every substantial session", llm: true, weight: 30, args: gradeArgs, batch: "heavy" },
|
|
22888
|
+
{ script: "coding-day-digest.mts", label: "Day-by-day digests", llm: true, weight: 17, args: ["--model", narrativeModel, "--conc", String(h.digest)], out: "coding/day-digest.json", batch: "heavy" },
|
|
22889
|
+
// walkthrough weight 28 = was 55 at 2 workers, ~28 at the rebalanced 4
|
|
22890
|
+
{ script: "coding-walkthrough.mts", label: "Per-session walkthroughs", llm: true, weight: 28, args: ["--model", narrativeModel, "--conc", String(h.walkthrough)], batch: "heavy" },
|
|
22891
|
+
{ script: "coding-frontier-detail.mts", label: "What you're doing at the frontier", llm: true, weight: 3, args: [], out: "coding/frontier-detail.json", batch: "heavy" },
|
|
22892
|
+
{ script: "coding-delegation.mts", label: "Delegation patterns", llm: true, weight: 2, args: ["--model", model, "--conc", String(h.delegation)], out: "coding/delegation-rollup.json", batch: "heavy" },
|
|
22890
22893
|
// The FULL focus stage: flow-rule judgment + the paste-into-CLAUDE.md block.
|
|
22891
22894
|
// The deterministic --skip-llm run above keeps the numbers current every
|
|
22892
22895
|
// run; this one produces the AI block — it was MISSING from the graded tier
|
|
@@ -22894,14 +22897,14 @@ function stages(o) {
|
|
|
22894
22897
|
// the companion), so overnight full runs shipped a report with no flow
|
|
22895
22898
|
// rules and nothing failed loud (found 2026-07-15). Both LLM passes are
|
|
22896
22899
|
// prompt-hash gated, so an unchanged corpus re-run costs zero calls.
|
|
22897
|
-
{ script: "coding-focus.mts", label: "Flow rules + focus judgment", llm: true, args: [], out: "coding/focus.json", batch: "heavy" },
|
|
22900
|
+
{ script: "coding-focus.mts", label: "Flow rules + focus judgment", llm: true, weight: 6, args: [], out: "coding/focus.json", batch: "heavy" },
|
|
22898
22901
|
// ---- corpus aggregate (reads grades; deterministic rollup) ----
|
|
22899
22902
|
{ script: "coding-aggregate.mts", label: "Corpus aggregate \u2014 ability ceiling + flow", llm: false, args: [], out: "coding/aggregate.json" },
|
|
22900
22903
|
// ---- grade readers (grades/* is complete once aggregate ran) ----
|
|
22901
22904
|
// No default --model here: the agglomerate script defaults itself to Opus
|
|
22902
22905
|
// (one call per run; the axis verdicts are the most judgment-heavy output).
|
|
22903
22906
|
// An explicit user model choice still wins.
|
|
22904
|
-
{ script: "coding-agglomerate.mts", label: "Agglomerated criteria + verdicts + signature moves", llm: true, args: o.model ? ["--model", o.model] : [], out: "coding/agglomerate.json", batch: "grade-readers" },
|
|
22907
|
+
{ script: "coding-agglomerate.mts", label: "Agglomerated criteria + verdicts + signature moves", llm: true, weight: 4, args: o.model ? ["--model", o.model] : [], out: "coding/agglomerate.json", batch: "grade-readers" },
|
|
22905
22908
|
// Domain-expertise map DISABLED (owner call 2026-07-22): the single most
|
|
22906
22909
|
// expensive stage of the whole run ($13.88 of $49.34 measured — 129 sonnet
|
|
22907
22910
|
// calls) and for most users the hiring-bar filter correctly returns ZERO
|
|
@@ -22910,22 +22913,22 @@ function stages(o) {
|
|
|
22910
22913
|
// fold into the grade call); the report renders nothing when the artifact
|
|
22911
22914
|
// is absent.
|
|
22912
22915
|
// ---- final synthesis (reads the finished aggregates + batch outputs) ----
|
|
22913
|
-
{ script: "coding-coaching.mts", label: "Coaching + feel-seen copy", llm: true, args: [], out: "coding/coaching.json", batch: "synthesis" },
|
|
22914
|
-
{ script: "coding-gap.mts", label: "Gap-to-close vs best practice", llm: true, args: [], out: "coding/gap.json", batch: "synthesis" },
|
|
22916
|
+
{ script: "coding-coaching.mts", label: "Coaching + feel-seen copy", llm: true, weight: 2, args: [], out: "coding/coaching.json", batch: "synthesis" },
|
|
22917
|
+
{ script: "coding-gap.mts", label: "Gap-to-close vs best practice", llm: true, weight: 5, args: [], out: "coding/gap.json", batch: "synthesis" },
|
|
22915
22918
|
// Work brief — the hiring-manager narrative + continuous timeline. Consumes
|
|
22916
22919
|
// day-digest.json (heavy batch, already complete) + concurrency/projects;
|
|
22917
22920
|
// disjoint output, so it rides the synthesis batch. Defaults itself to Opus
|
|
22918
22921
|
// (the journey's significance calls are judgment-heavy); an explicit model
|
|
22919
22922
|
// choice wins. Prompt-hash gated + up-to-date-skip like its siblings.
|
|
22920
|
-
{ script: "coding-workbrief.mts", label: "Work brief \u2014 narrative timeline", llm: true, args: o.model ? ["--model", o.model] : [], out: "coding/workbrief.json", batch: "synthesis" },
|
|
22923
|
+
{ script: "coding-workbrief.mts", label: "Work brief \u2014 narrative timeline", llm: true, weight: 3, args: o.model ? ["--model", o.model] : [], out: "coding/workbrief.json", batch: "synthesis" },
|
|
22921
22924
|
// Growth reads grades/* + deterministic artifacts only (no per-session AI
|
|
22922
22925
|
// calls — it deliberately ignores the AI recency window and covers the full
|
|
22923
22926
|
// history); disjoint output, so it rides the synthesis batch. Like
|
|
22924
22927
|
// agglomerate it defaults itself to Opus; an explicit model choice wins.
|
|
22925
|
-
{ script: "coding-growth.mts", label: "Growth arcs + learning rate", llm: true, args: o.model ? ["--model", o.model] : [], out: "coding/growth.json", batch: "synthesis" },
|
|
22928
|
+
{ script: "coding-growth.mts", label: "Growth arcs + learning rate", llm: true, weight: 5, args: o.model ? ["--model", o.model] : [], out: "coding/growth.json", batch: "synthesis" },
|
|
22926
22929
|
// nutshell stays LAST + alone: it merges INTO aggregate.json while the two
|
|
22927
22930
|
// above read the compiled profile — racing them re-reads mid-write.
|
|
22928
|
-
{ script: "coding-nutshell.mts", label: "Big-picture nutshell", llm: true, args: [], out: "coding/aggregate.json" }
|
|
22931
|
+
{ script: "coding-nutshell.mts", label: "Big-picture nutshell", llm: true, weight: 1, args: [], out: "coding/aggregate.json" }
|
|
22929
22932
|
// merges bigPicture INTO aggregate.json
|
|
22930
22933
|
];
|
|
22931
22934
|
}
|
|
@@ -22947,18 +22950,54 @@ function stageInvocation(repoRoot, scriptRel, args) {
|
|
|
22947
22950
|
}
|
|
22948
22951
|
throw new Error(`pipeline stage ${scriptRel}: neither repo scripts/ nor bundled dist/pipeline/ found`);
|
|
22949
22952
|
}
|
|
22953
|
+
function killLiveStages() {
|
|
22954
|
+
for (const c of liveStages) {
|
|
22955
|
+
try {
|
|
22956
|
+
if (process.platform === "win32" || !c.pid) c.kill("SIGKILL");
|
|
22957
|
+
else process.kill(-c.pid, "SIGKILL");
|
|
22958
|
+
} catch {
|
|
22959
|
+
}
|
|
22960
|
+
}
|
|
22961
|
+
liveStages.clear();
|
|
22962
|
+
}
|
|
22963
|
+
function hookStageKill() {
|
|
22964
|
+
if (killHooked) return;
|
|
22965
|
+
killHooked = true;
|
|
22966
|
+
process.on("exit", killLiveStages);
|
|
22967
|
+
for (const sig of ["SIGINT", "SIGTERM"]) {
|
|
22968
|
+
process.on(sig, () => {
|
|
22969
|
+
killLiveStages();
|
|
22970
|
+
process.exit(sig === "SIGINT" ? 130 : 143);
|
|
22971
|
+
});
|
|
22972
|
+
}
|
|
22973
|
+
}
|
|
22974
|
+
function trackStageChild(child) {
|
|
22975
|
+
hookStageKill();
|
|
22976
|
+
liveStages.add(child);
|
|
22977
|
+
}
|
|
22978
|
+
function untrackStageChild(child) {
|
|
22979
|
+
liveStages.delete(child);
|
|
22980
|
+
}
|
|
22950
22981
|
function runStage(repoRoot, st, env, onLine) {
|
|
22951
22982
|
return new Promise((resolve2, reject) => {
|
|
22952
22983
|
const { cmd, argv, cwd } = stageInvocation(repoRoot, st.script, st.args);
|
|
22953
|
-
|
|
22984
|
+
hookStageKill();
|
|
22985
|
+
const child = spawn7(cmd, argv, { cwd, env, stdio: ["ignore", "pipe", "pipe"], detached: process.platform !== "win32" });
|
|
22986
|
+
liveStages.add(child);
|
|
22954
22987
|
const pump = (buf) => {
|
|
22955
22988
|
if (!onLine) return;
|
|
22956
22989
|
for (const line of buf.toString().split(/\r?\n/)) if (line.trim()) onLine(line);
|
|
22957
22990
|
};
|
|
22958
22991
|
child.stdout.on("data", pump);
|
|
22959
22992
|
child.stderr.on("data", pump);
|
|
22960
|
-
child.on("error",
|
|
22961
|
-
|
|
22993
|
+
child.on("error", (e) => {
|
|
22994
|
+
liveStages.delete(child);
|
|
22995
|
+
reject(e);
|
|
22996
|
+
});
|
|
22997
|
+
child.on("close", (code) => {
|
|
22998
|
+
liveStages.delete(child);
|
|
22999
|
+
code === 0 ? resolve2() : reject(new Error(`${st.script} exited with code ${code}`));
|
|
23000
|
+
});
|
|
22962
23001
|
});
|
|
22963
23002
|
}
|
|
22964
23003
|
function hasPipeline(repoRoot) {
|
|
@@ -23099,6 +23138,7 @@ async function runPipeline(o) {
|
|
|
23099
23138
|
o.onStage?.(++stageNo, list.length, `${st.label} \u2014 up to date, skipped`, st.llm);
|
|
23100
23139
|
log.event(st.script.replace(/\.mts$/, ""), { ok: true, ms: 0, skipped: true });
|
|
23101
23140
|
stageTimes.push({ script: st.script, label: st.label, ms: 0, ok: true, skipped: true });
|
|
23141
|
+
o.onStageDone?.(st.label, st.llm, true, st.script);
|
|
23102
23142
|
return;
|
|
23103
23143
|
}
|
|
23104
23144
|
o.onStage?.(++stageNo, list.length, group.length > 1 ? `${st.label} (parallel \xD7${group.length})` : st.label, st.llm);
|
|
@@ -23116,6 +23156,7 @@ async function runPipeline(o) {
|
|
|
23116
23156
|
const sha = st.out ? await fileSha(path38.join(dataRoot, st.out)) : null;
|
|
23117
23157
|
log.event(st.script.replace(/\.mts$/, ""), { ok, ms: Date.now() - stStart, ...sha ? { sha } : {} });
|
|
23118
23158
|
stageTimes.push({ script: st.script, label: st.label, ms: Date.now() - stStart, ok });
|
|
23159
|
+
o.onStageDone?.(st.label, st.llm, ok, st.script);
|
|
23119
23160
|
}));
|
|
23120
23161
|
if (!o.deterministicOnly && !skippedLlm && group[0].script === "coding-build.mts") {
|
|
23121
23162
|
const gate2 = await evalUpToDate(codingDir, threshold, o.regrade, o);
|
|
@@ -23156,7 +23197,7 @@ async function runPipeline(o) {
|
|
|
23156
23197
|
stopKeepAwake();
|
|
23157
23198
|
return { failed, ...skippedLlm ? { skippedLlm } : {} };
|
|
23158
23199
|
}
|
|
23159
|
-
var MODULE_DIR2;
|
|
23200
|
+
var MODULE_DIR2, liveStages, killHooked;
|
|
23160
23201
|
var init_pipeline2 = __esm({
|
|
23161
23202
|
"src/pipeline.ts"() {
|
|
23162
23203
|
"use strict";
|
|
@@ -23164,6 +23205,8 @@ var init_pipeline2 = __esm({
|
|
|
23164
23205
|
init_dataHome();
|
|
23165
23206
|
init_runLog();
|
|
23166
23207
|
MODULE_DIR2 = path38.dirname(fileURLToPath3(import.meta.url));
|
|
23208
|
+
liveStages = /* @__PURE__ */ new Set();
|
|
23209
|
+
killHooked = false;
|
|
23167
23210
|
}
|
|
23168
23211
|
});
|
|
23169
23212
|
|
|
@@ -23237,15 +23280,22 @@ async function finalChatArtifacts(dataRoot) {
|
|
|
23237
23280
|
function runStage2(repoRoot, st, env, onLine) {
|
|
23238
23281
|
return new Promise((resolve2, reject) => {
|
|
23239
23282
|
const { cmd, argv, cwd } = stageInvocation2(repoRoot, st.script, st.args);
|
|
23240
|
-
const child = spawn8(cmd, argv, { cwd, env, stdio: ["ignore", "pipe", "pipe"] });
|
|
23283
|
+
const child = spawn8(cmd, argv, { cwd, env, stdio: ["ignore", "pipe", "pipe"], detached: process.platform !== "win32" });
|
|
23284
|
+
trackStageChild(child);
|
|
23241
23285
|
const pump = (buf) => {
|
|
23242
23286
|
if (!onLine) return;
|
|
23243
23287
|
for (const line of buf.toString().split(/\r?\n/)) if (line.trim()) onLine(line);
|
|
23244
23288
|
};
|
|
23245
23289
|
child.stdout.on("data", pump);
|
|
23246
23290
|
child.stderr.on("data", pump);
|
|
23247
|
-
child.on("error",
|
|
23248
|
-
|
|
23291
|
+
child.on("error", (e) => {
|
|
23292
|
+
untrackStageChild(child);
|
|
23293
|
+
reject(e);
|
|
23294
|
+
});
|
|
23295
|
+
child.on("close", (code) => {
|
|
23296
|
+
untrackStageChild(child);
|
|
23297
|
+
code === 0 ? resolve2() : reject(new Error(`${st.script} exited with code ${code}`));
|
|
23298
|
+
});
|
|
23249
23299
|
});
|
|
23250
23300
|
}
|
|
23251
23301
|
async function runChatPipeline(o) {
|
|
@@ -23356,6 +23406,7 @@ var init_chatPipeline = __esm({
|
|
|
23356
23406
|
"src/chatPipeline.ts"() {
|
|
23357
23407
|
"use strict";
|
|
23358
23408
|
init_manifest();
|
|
23409
|
+
init_pipeline2();
|
|
23359
23410
|
init_central();
|
|
23360
23411
|
init_dataHome();
|
|
23361
23412
|
init_runLog();
|
|
@@ -24823,10 +24874,9 @@ function makeMultiBar(out = process.stderr) {
|
|
|
24823
24874
|
const width = 16;
|
|
24824
24875
|
const elapsedMin = Math.round((Date.now() - t0) / 6e4);
|
|
24825
24876
|
const laneRow = ([name17, l]) => {
|
|
24826
|
-
const real = l.
|
|
24827
|
-
const
|
|
24828
|
-
const
|
|
24829
|
-
const frac = l.total ? (l.i - 1 + withinFrac) / l.total : 0;
|
|
24877
|
+
const real = [...l.fracs.values()].reduce((a, f) => a + (f.total ? Math.min(1, f.done / f.total) : 0), 0);
|
|
24878
|
+
const withinFrac = Math.min(Math.max(0, l.total - (l.i - 1)), real);
|
|
24879
|
+
const frac = l.forced ?? (l.total ? (l.i - 1 + withinFrac) / l.total : 0);
|
|
24830
24880
|
l.shown = Math.max(l.shown, Math.max(0, Math.min(1, frac)));
|
|
24831
24881
|
const fill = Math.round(l.shown * width);
|
|
24832
24882
|
return ` ${name17.padEnd(6)} [${"\u2588".repeat(fill)}${"\u2591".repeat(width - fill)}] ${String(Math.round(l.shown * 100)).padStart(3)}%`;
|
|
@@ -24866,36 +24916,56 @@ function makeMultiBar(out = process.stderr) {
|
|
|
24866
24916
|
};
|
|
24867
24917
|
return {
|
|
24868
24918
|
lane(name17) {
|
|
24919
|
+
const getLane = () => {
|
|
24920
|
+
const l = lanes.get(name17) ?? { i: 0, total: 0, label: "", fracs: /* @__PURE__ */ new Map(), forced: null, stageAt: Date.now(), shown: 0 };
|
|
24921
|
+
lanes.set(name17, l);
|
|
24922
|
+
return l;
|
|
24923
|
+
};
|
|
24869
24924
|
return {
|
|
24870
24925
|
stage(i, total, label) {
|
|
24871
|
-
const l =
|
|
24926
|
+
const l = getLane();
|
|
24872
24927
|
l.i = i;
|
|
24873
24928
|
l.total = total;
|
|
24874
24929
|
l.label = label;
|
|
24875
|
-
l.within = null;
|
|
24876
24930
|
l.stageAt = Date.now();
|
|
24877
|
-
|
|
24931
|
+
for (const [k, f] of l.fracs) if (f.total && f.done >= f.total) l.fracs.delete(k);
|
|
24878
24932
|
repaintAround(`\u25B8 ${name17} [${i}/${total}] ${label}`);
|
|
24879
24933
|
},
|
|
24880
24934
|
log(line) {
|
|
24881
24935
|
const l = lanes.get(name17);
|
|
24882
24936
|
if (l) {
|
|
24883
24937
|
const m = /Σ\s+(\d+)\/(\d+)/.exec(line);
|
|
24884
|
-
if (m)
|
|
24938
|
+
if (m) {
|
|
24939
|
+
const tag = /^\s*\[([^\]]+)\]/.exec(line)?.[1] ?? "_";
|
|
24940
|
+
l.fracs.set(tag, { done: Number(m[1]), total: Number(m[2]) });
|
|
24941
|
+
}
|
|
24885
24942
|
}
|
|
24886
24943
|
repaintAround(tty ? line : `[${name17}] ${line.trimStart()}`);
|
|
24887
24944
|
},
|
|
24945
|
+
// The cli's duration-weighted fraction — supersedes local math.
|
|
24946
|
+
setFrac(f) {
|
|
24947
|
+
const l = getLane();
|
|
24948
|
+
l.forced = Math.max(0, Math.min(1, f));
|
|
24949
|
+
if (tty) repaintAround();
|
|
24950
|
+
},
|
|
24951
|
+
// A stage completed: its share now lives in `i`, so drop its running
|
|
24952
|
+
// fraction (fall back to the untagged slot for single stages).
|
|
24953
|
+
stageDone(key2) {
|
|
24954
|
+
const l = lanes.get(name17);
|
|
24955
|
+
if (l && !l.fracs.delete(key2)) l.fracs.delete("_");
|
|
24956
|
+
if (tty) repaintAround();
|
|
24957
|
+
},
|
|
24888
24958
|
// Pin the lane at 100% immediately (up-to-date gate: the report is
|
|
24889
24959
|
// ready NOW; remaining stages are silent housekeeping and must not
|
|
24890
24960
|
// crawl the bar through partial percentages).
|
|
24891
24961
|
finish(label) {
|
|
24892
|
-
const l =
|
|
24962
|
+
const l = getLane();
|
|
24893
24963
|
l.total = l.total || 1;
|
|
24894
24964
|
l.i = l.total + 1;
|
|
24895
24965
|
l.label = label;
|
|
24896
|
-
l.
|
|
24966
|
+
l.fracs.clear();
|
|
24967
|
+
l.forced = null;
|
|
24897
24968
|
l.shown = 1;
|
|
24898
|
-
lanes.set(name17, l);
|
|
24899
24969
|
repaintAround(`\u25B8 ${name17} \u2713 ${label}`);
|
|
24900
24970
|
}
|
|
24901
24971
|
};
|
|
@@ -27998,7 +28068,14 @@ function startServer(opts2) {
|
|
|
27998
28068
|
// through 127.0.0.1 no matter which name the person's tab uses.
|
|
27999
28069
|
url: host === "127.0.0.1" ? `http://localhost:${port}` : serverUrl,
|
|
28000
28070
|
port,
|
|
28001
|
-
|
|
28071
|
+
// closeAllConnections BEFORE close: server.close() waits for every
|
|
28072
|
+
// open socket to drain, and the report tab holds a live progress
|
|
28073
|
+
// connection — an awaited close made Ctrl+C appear completely dead
|
|
28074
|
+
// (owner report 2026-07-22).
|
|
28075
|
+
close: () => new Promise((r) => {
|
|
28076
|
+
server.closeAllConnections?.();
|
|
28077
|
+
server.close(() => r());
|
|
28078
|
+
}),
|
|
28002
28079
|
setProfile: (p) => {
|
|
28003
28080
|
liveProfile = p;
|
|
28004
28081
|
profileRev++;
|
|
@@ -28380,17 +28457,28 @@ Running the full analysis on ${backend.name === "cli" ? "Claude Code" : "Codex"}
|
|
|
28380
28457
|
}, Number(process.env.POLYMATH_LIVE_REFRESH_MS || 45e3));
|
|
28381
28458
|
const { makeMultiBar: makeMultiBar2 } = await Promise.resolve().then(() => (init_progressBar(), progressBar_exports));
|
|
28382
28459
|
const mbar = makeMultiBar2();
|
|
28460
|
+
const withinFracs = { coding: /* @__PURE__ */ new Map(), chat: /* @__PURE__ */ new Map() };
|
|
28461
|
+
const sumFracs = (lane) => [...withinFracs[lane].values()].reduce((a, f) => a + (f.total ? Math.min(1, f.done / f.total) : 0), 0);
|
|
28383
28462
|
const harvestWithin = (lane, line) => {
|
|
28384
28463
|
const m = /Σ\s+(\d+)\/(\d+)/.exec(line);
|
|
28385
28464
|
if (m && progress[lane] && !progress[lane].done) {
|
|
28386
|
-
|
|
28465
|
+
const tag = /^\s*\[([^\]]+)\]/.exec(line)?.[1] ?? "_";
|
|
28466
|
+
withinFracs[lane].set(tag, { done: Number(m[1]), total: Number(m[2]) });
|
|
28467
|
+
progress[lane].withinFrac = Math.round(sumFracs(lane) * 1e3) / 1e3;
|
|
28468
|
+
if (lane === "coding") {
|
|
28469
|
+
const f = codingFracRef();
|
|
28470
|
+
progress.coding.frac = f;
|
|
28471
|
+
codingLane.setFrac(f);
|
|
28472
|
+
}
|
|
28387
28473
|
earlyHandle.setProgress(progress);
|
|
28388
28474
|
}
|
|
28389
28475
|
};
|
|
28476
|
+
let codingFracRef = () => 0;
|
|
28390
28477
|
mbar.setLink(earlyHandle.url);
|
|
28391
28478
|
const codingLane = mbar.lane("coding");
|
|
28392
28479
|
const aiCount = { coding: 0, chat: 0 };
|
|
28393
|
-
const
|
|
28480
|
+
const aiStarted = { coding: 0, chat: 0 };
|
|
28481
|
+
const aiDone = { coding: 0, chat: 0 };
|
|
28394
28482
|
let codingPinned = false;
|
|
28395
28483
|
if (await readPriorAnalysis()) {
|
|
28396
28484
|
codingPinned = true;
|
|
@@ -28413,6 +28501,16 @@ Running the full analysis on ${backend.name === "cli" ? "Claude Code" : "Codex"}
|
|
|
28413
28501
|
const { chatEngineStages: chatEngineStages2 } = await Promise.resolve().then(() => (init_chatPipeline(), chatPipeline_exports));
|
|
28414
28502
|
aiCount.coding = stages2(pipeOpts).filter((st) => st.llm).length;
|
|
28415
28503
|
aiCount.chat = chatEngineStages2().filter((st) => st.llm).length;
|
|
28504
|
+
const tagOf = (script) => script.replace(/^coding-|\.mts$/g, "");
|
|
28505
|
+
const codingWeights = new Map(stages2(pipeOpts).filter((st) => st.llm).map((st) => [tagOf(st.script), st.weight ?? 1]));
|
|
28506
|
+
const codingTotalW = [...codingWeights.values()].reduce((a, b) => a + b, 0) || 1;
|
|
28507
|
+
let codingDoneW = 0;
|
|
28508
|
+
const codingFrac = () => {
|
|
28509
|
+
let f = codingDoneW;
|
|
28510
|
+
for (const [tag, x] of withinFracs.coding) f += (codingWeights.get(tag) ?? 0) * (x.total ? Math.min(1, x.done / x.total) : 0);
|
|
28511
|
+
return Math.min(1, f / codingTotalW);
|
|
28512
|
+
};
|
|
28513
|
+
codingFracRef = codingFrac;
|
|
28416
28514
|
const codingDone = runPipeline({
|
|
28417
28515
|
...pipeOpts,
|
|
28418
28516
|
onUpToDate: () => {
|
|
@@ -28427,11 +28525,23 @@ Running the full analysis on ${backend.name === "cli" ? "Claude Code" : "Codex"}
|
|
|
28427
28525
|
},
|
|
28428
28526
|
onStage: (i, total, label, llm) => {
|
|
28429
28527
|
if (codingPinned) return;
|
|
28430
|
-
if (llm)
|
|
28431
|
-
progress.coding = { ...progress.coding, i:
|
|
28528
|
+
if (llm) aiStarted.coding++;
|
|
28529
|
+
progress.coding = { ...progress.coding, i: llm ? aiDone.coding + 1 : aiDone.coding, total: aiCount.coding, label, done: false };
|
|
28530
|
+
earlyHandle.setProgress(progress);
|
|
28531
|
+
if (llm) codingLane.stage(aiDone.coding + 1, aiCount.coding, `${label} (AI)`);
|
|
28532
|
+
else if (aiStarted.coding === 0) codingLane.stage(0, aiCount.coding, label);
|
|
28533
|
+
},
|
|
28534
|
+
onStageDone: (label, llm, _ok, script) => {
|
|
28535
|
+
if (codingPinned || !llm) return;
|
|
28536
|
+
aiDone.coding++;
|
|
28537
|
+
const key2 = script.replace(/^coding-|\.mts$/g, "");
|
|
28538
|
+
codingDoneW += codingWeights.get(key2) ?? 0;
|
|
28539
|
+
if (!withinFracs.coding.delete(key2)) withinFracs.coding.delete("_");
|
|
28540
|
+
codingLane.stageDone(key2);
|
|
28541
|
+
const f = codingFrac();
|
|
28542
|
+
codingLane.setFrac(f);
|
|
28543
|
+
progress.coding = { ...progress.coding, i: Math.min(aiDone.coding + 1, aiCount.coding), total: aiCount.coding, done: false, frac: f, withinFrac: Math.round(sumFracs("coding") * 1e3) / 1e3 };
|
|
28432
28544
|
earlyHandle.setProgress(progress);
|
|
28433
|
-
if (llm) codingLane.stage(aiSeen.coding, aiCount.coding, `${label} (AI)`);
|
|
28434
|
-
else if (aiSeen.coding === 0) codingLane.stage(0, aiCount.coding, label);
|
|
28435
28545
|
},
|
|
28436
28546
|
// While pinned, the scrolling stage output stays quiet ("prints hella
|
|
28437
28547
|
// things when everything is cached", owner 2026-07-17) — warnings and
|
|
@@ -28503,11 +28613,14 @@ Running the full analysis on ${backend.name === "cli" ? "Claude Code" : "Codex"}
|
|
|
28503
28613
|
},
|
|
28504
28614
|
onStage: (i, total, label, llm) => {
|
|
28505
28615
|
if (chatPinned) return;
|
|
28506
|
-
if (llm)
|
|
28507
|
-
|
|
28616
|
+
if (llm) {
|
|
28617
|
+
aiStarted.chat++;
|
|
28618
|
+
withinFracs.chat.clear();
|
|
28619
|
+
}
|
|
28620
|
+
progress.chat = { ...progress.chat, i: aiStarted.chat, total: aiCount.chat, label, done: false, withinFrac: void 0 };
|
|
28508
28621
|
earlyHandle.setProgress(progress);
|
|
28509
|
-
if (llm) chatLane.stage(
|
|
28510
|
-
else if (
|
|
28622
|
+
if (llm) chatLane.stage(aiStarted.chat, aiCount.chat, `${label} (AI)`);
|
|
28623
|
+
else if (aiStarted.chat === 0) chatLane.stage(0, aiCount.chat, label);
|
|
28511
28624
|
},
|
|
28512
28625
|
onLine: (line) => {
|
|
28513
28626
|
harvestWithin("chat", line);
|
|
@@ -28633,14 +28746,20 @@ No analysis here yet \u2014 computing the instant deterministic metrics now (fre
|
|
|
28633
28746
|
console.error(` (Ctrl-C to stop)
|
|
28634
28747
|
`);
|
|
28635
28748
|
if (opts2.open && !earlyHandle) openBrowser(handle.url);
|
|
28636
|
-
|
|
28637
|
-
|
|
28638
|
-
process.exit(
|
|
28639
|
-
|
|
28640
|
-
|
|
28641
|
-
|
|
28642
|
-
|
|
28643
|
-
|
|
28749
|
+
let dying = false;
|
|
28750
|
+
const shutdown = (code) => async () => {
|
|
28751
|
+
if (dying) process.exit(code);
|
|
28752
|
+
dying = true;
|
|
28753
|
+
const hardExit = setTimeout(() => process.exit(code), 1e3);
|
|
28754
|
+
if (typeof hardExit.unref === "function") hardExit.unref();
|
|
28755
|
+
try {
|
|
28756
|
+
await handle.close();
|
|
28757
|
+
} catch {
|
|
28758
|
+
}
|
|
28759
|
+
process.exit(code);
|
|
28760
|
+
};
|
|
28761
|
+
process.on("SIGINT", shutdown(130));
|
|
28762
|
+
process.on("SIGTERM", shutdown(143));
|
|
28644
28763
|
return;
|
|
28645
28764
|
}
|
|
28646
28765
|
const profile = await analyze({ codex: opts2.codex, idleGapMin: opts2.idleGapMin, tz: opts2.tz, spanHourMin: opts2.spanHourMin });
|
package/dist/index.js
CHANGED
|
@@ -25606,7 +25606,14 @@ function startServer(opts2) {
|
|
|
25606
25606
|
// through 127.0.0.1 no matter which name the person's tab uses.
|
|
25607
25607
|
url: host === "127.0.0.1" ? `http://localhost:${port}` : serverUrl,
|
|
25608
25608
|
port,
|
|
25609
|
-
|
|
25609
|
+
// closeAllConnections BEFORE close: server.close() waits for every
|
|
25610
|
+
// open socket to drain, and the report tab holds a live progress
|
|
25611
|
+
// connection — an awaited close made Ctrl+C appear completely dead
|
|
25612
|
+
// (owner report 2026-07-22).
|
|
25613
|
+
close: () => new Promise((r) => {
|
|
25614
|
+
server.closeAllConnections?.();
|
|
25615
|
+
server.close(() => r());
|
|
25616
|
+
}),
|
|
25610
25617
|
setProfile: (p) => {
|
|
25611
25618
|
liveProfile = p;
|
|
25612
25619
|
profileRev++;
|
|
@@ -16899,6 +16899,7 @@ function validate(raw, grades, costUsd) {
|
|
|
16899
16899
|
const r = raw;
|
|
16900
16900
|
const overall = typeof r.overall === "string" ? r.overall.trim() : "";
|
|
16901
16901
|
if (!overall) return null;
|
|
16902
|
+
if (overall.length > 200 && !/[.!?…"'’)\]]$/.test(overall)) return null;
|
|
16902
16903
|
if (!r.verdicts || typeof r.verdicts !== "object") return null;
|
|
16903
16904
|
const keys = new Set(GRADED_CRITERIA.map((c) => c.key));
|
|
16904
16905
|
const criteria = (Array.isArray(r.criteria) ? r.criteria : []).map((c) => {
|
package/dist/web/app.js
CHANGED
|
@@ -12939,9 +12939,13 @@ function laneFrac(name, l) {
|
|
|
12939
12939
|
m.label = l.label;
|
|
12940
12940
|
m.at = Date.now();
|
|
12941
12941
|
}
|
|
12942
|
-
|
|
12943
|
-
|
|
12944
|
-
|
|
12942
|
+
if (l.frac != null) {
|
|
12943
|
+
m.shown = Math.max(m.shown, Math.min(1, Math.max(0, l.frac)));
|
|
12944
|
+
laneMemo.set(name, m);
|
|
12945
|
+
return m.shown;
|
|
12946
|
+
}
|
|
12947
|
+
const real = l.withinFrac ?? (l.within && l.within.total ? l.within.done / l.within.total : 0);
|
|
12948
|
+
const w = Math.min(Math.max(0, l.total - (l.i - 1)), real);
|
|
12945
12949
|
m.shown = Math.max(m.shown, Math.min(1, Math.max(0, (l.i - 1 + w) / l.total)));
|
|
12946
12950
|
laneMemo.set(name, m);
|
|
12947
12951
|
return m.shown;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "polymath-society",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.27",
|
|
4
4
|
"description": "Deterministic metrics from your local Claude Code / Codex agent logs — parallelism, flow, throughput, projects. Zero LLM, zero server, on-device.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|