polymath-society 0.2.10 → 0.2.11
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 +29 -1
- package/dist/engine/chat-loops.js +10 -0
- package/dist/pipeline/coding-focus.js +27 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -24863,7 +24863,7 @@ function apportionHeavy(budget) {
|
|
|
24863
24863
|
const grade = Math.max(2, Math.floor(budget * 0.45));
|
|
24864
24864
|
const digest = Math.max(1, Math.floor(budget * 0.17));
|
|
24865
24865
|
const walkthrough = Math.max(1, Math.floor(budget * 0.17));
|
|
24866
|
-
const delegation = Math.max(1, budget - grade - digest - walkthrough -
|
|
24866
|
+
const delegation = Math.max(1, budget - grade - digest - walkthrough - 2);
|
|
24867
24867
|
return { grade, digest, walkthrough, delegation };
|
|
24868
24868
|
}
|
|
24869
24869
|
function stages(o) {
|
|
@@ -24896,6 +24896,14 @@ function stages(o) {
|
|
|
24896
24896
|
{ script: "coding-walkthrough.mts", label: "Per-session walkthroughs", llm: true, args: ["--model", model, "--conc", String(h.walkthrough)], batch: "heavy" },
|
|
24897
24897
|
{ script: "coding-frontier-detail.mts", label: "What you're doing at the frontier", llm: true, args: [], out: "coding/frontier-detail.json", batch: "heavy" },
|
|
24898
24898
|
{ script: "coding-delegation.mts", label: "Delegation patterns", llm: true, args: ["--model", model, "--conc", String(h.delegation)], out: "coding/delegation-rollup.json", batch: "heavy" },
|
|
24899
|
+
// The FULL focus stage: flow-rule judgment + the paste-into-CLAUDE.md block.
|
|
24900
|
+
// The deterministic --skip-llm run above keeps the numbers current every
|
|
24901
|
+
// run; this one produces the AI block — it was MISSING from the graded tier
|
|
24902
|
+
// entirely (688d788 added focus for the numbers-only tier and no one added
|
|
24903
|
+
// the companion), so overnight full runs shipped a report with no flow
|
|
24904
|
+
// rules and nothing failed loud (found 2026-07-15). Both LLM passes are
|
|
24905
|
+
// prompt-hash gated, so an unchanged corpus re-run costs zero calls.
|
|
24906
|
+
{ script: "coding-focus.mts", label: "Flow rules + focus judgment", llm: true, args: [], out: "coding/focus.json", batch: "heavy" },
|
|
24899
24907
|
// ---- corpus aggregate (reads grades; deterministic rollup) ----
|
|
24900
24908
|
{ script: "coding-aggregate.mts", label: "Corpus aggregate \u2014 ability ceiling + flow", llm: false, args: [], out: "coding/aggregate.json" },
|
|
24901
24909
|
// ---- grade readers (grades/* is complete once aggregate ran) ----
|
|
@@ -25253,7 +25261,19 @@ async function runChatPipeline(o) {
|
|
|
25253
25261
|
}
|
|
25254
25262
|
log.event("ingest-export", { ok, ms: Date.now() - stStart, source: f.kind });
|
|
25255
25263
|
}
|
|
25264
|
+
const minNewDocs = Number(process.env.POLYMATH_MIN_NEW_DOCS ?? 10);
|
|
25265
|
+
const signalDocs = async () => {
|
|
25266
|
+
const t = await fs32.readFile(path37.join(dataRoot, "signals", "index.jsonl"), "utf8").catch(() => "");
|
|
25267
|
+
return t ? t.split("\n").filter(Boolean).length : 0;
|
|
25268
|
+
};
|
|
25269
|
+
const docsBeforeTagger = await signalDocs();
|
|
25270
|
+
let upToDate = false;
|
|
25256
25271
|
for (const st of chatEngineStages()) {
|
|
25272
|
+
if (upToDate && st.llm) {
|
|
25273
|
+
o.onStage?.(++idx, total, `${st.label} \u2014 up to date, skipped`, st.llm);
|
|
25274
|
+
log.event(st.script.replace(/\.mts$/, ""), { ok: true, ms: 0, skipped: true });
|
|
25275
|
+
continue;
|
|
25276
|
+
}
|
|
25257
25277
|
o.onStage?.(++idx, total, st.label, st.llm);
|
|
25258
25278
|
const stStart = Date.now();
|
|
25259
25279
|
let ok = true;
|
|
@@ -25267,6 +25287,14 @@ async function runChatPipeline(o) {
|
|
|
25267
25287
|
}
|
|
25268
25288
|
const sha = st.out ? await fileSha(path37.join(dataRoot, st.out)) : null;
|
|
25269
25289
|
log.event(st.script.replace(/\.mts$/, ""), { ok, ms: Date.now() - stStart, ...sha ? { sha } : {} });
|
|
25290
|
+
if (st.script === "run-tagger.mts" && ok && minNewDocs > 0) {
|
|
25291
|
+
const newDocs = await signalDocs() - docsBeforeTagger;
|
|
25292
|
+
const report = await fs32.readFile(path37.join(dataRoot, "engine-pilot", "public-report.json"), "utf8").then((s) => JSON.parse(s)).catch(() => null);
|
|
25293
|
+
if (report?.headline && (report.spikes?.length ?? 0) > 0 && newDocs < minNewDocs) {
|
|
25294
|
+
upToDate = true;
|
|
25295
|
+
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.`);
|
|
25296
|
+
}
|
|
25297
|
+
}
|
|
25270
25298
|
}
|
|
25271
25299
|
log.event("pipeline_completed", { ok: failed.length === 0, failedStages: failed.length, ms: Date.now() - t0 });
|
|
25272
25300
|
await log.finish();
|
|
@@ -16902,6 +16902,14 @@ async function run2() {
|
|
|
16902
16902
|
}
|
|
16903
16903
|
}
|
|
16904
16904
|
if (!sigs.length) throw new Error("loops: empty signals index \u2014 refusing to write");
|
|
16905
|
+
const fingerprint = `${sigs.length}:${sigs.reduce((a, s) => s.date > a ? s.date : a, "")}`;
|
|
16906
|
+
if (!process.env.LOOPS_REFRESH) {
|
|
16907
|
+
const prev2 = await fs6.readFile(OUT2, "utf8").then(JSON.parse).catch(() => null);
|
|
16908
|
+
if (prev2?.inputFingerprint === fingerprint && prev2?.loops?.loops?.length) {
|
|
16909
|
+
console.log(`loops: inputs unchanged (${sigs.length} signals) \u2014 keeping ${prev2.generatedAt} (LOOPS_REFRESH=1 to redo)`);
|
|
16910
|
+
return;
|
|
16911
|
+
}
|
|
16912
|
+
}
|
|
16905
16913
|
const artifacts = importArtifactDates(sigs);
|
|
16906
16914
|
const dated = sigs.filter((s) => !artifacts.has(s.date));
|
|
16907
16915
|
const chats = dated.filter((s) => s.source === "chatgpt" || s.source === "claude");
|
|
@@ -16988,6 +16996,8 @@ ${sample.join("\n")}`;
|
|
|
16988
16996
|
rules.sort((a, b) => a.date.localeCompare(b.date));
|
|
16989
16997
|
const out = {
|
|
16990
16998
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16999
|
+
inputFingerprint: fingerprint,
|
|
17000
|
+
// the skip gate above compares against this
|
|
16991
17001
|
totals: { signals: sigs.length, dated: dated.length, chats: chats.length, ruleDeclarations: rules.length, importDatesExcluded: [...artifacts] },
|
|
16992
17002
|
chatsByMonth: monthCounts(chats.map((c) => c.date)),
|
|
16993
17003
|
rules,
|
|
@@ -135,6 +135,19 @@ var require_secure_json_parse = __commonJS({
|
|
|
135
135
|
|
|
136
136
|
// ../../scripts/coding-focus.mts
|
|
137
137
|
import { promises as fs6 } from "fs";
|
|
138
|
+
|
|
139
|
+
// ../../lib/agents/coding/promptCache.ts
|
|
140
|
+
import { createHash } from "crypto";
|
|
141
|
+
function promptSha(parts) {
|
|
142
|
+
const h = createHash("sha256");
|
|
143
|
+
for (const p of parts) {
|
|
144
|
+
h.update(p ?? "");
|
|
145
|
+
h.update("\0");
|
|
146
|
+
}
|
|
147
|
+
return h.digest("hex").slice(0, 16);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ../../scripts/coding-focus.mts
|
|
138
151
|
import path10 from "path";
|
|
139
152
|
|
|
140
153
|
// ../../lib/agents/shared/agent.ts
|
|
@@ -16170,7 +16183,13 @@ async function run2() {
|
|
|
16170
16183
|
|
|
16171
16184
|
SESSIONS:
|
|
16172
16185
|
${JSON.stringify(listing, null, 1)}`;
|
|
16173
|
-
|
|
16186
|
+
const clusterSha = promptSha([cprompt]);
|
|
16187
|
+
if (prev?.features?.length && prev?.featuresPromptSha === clusterSha && !process.env.FOCUS_REFRESH) {
|
|
16188
|
+
out.features = prev.features;
|
|
16189
|
+
out.featuresDaysUnit = prev.featuresDaysUnit ?? "min";
|
|
16190
|
+
out.featuresPromptSha = clusterSha;
|
|
16191
|
+
console.log("focus: cluster inputs unchanged \u2014 reusing features (FOCUS_REFRESH=1 to redo)");
|
|
16192
|
+
} else try {
|
|
16174
16193
|
const cr = await invokeAgent({ prompt: cprompt, systemPrompt: "You produce strict JSON only.", maxTurns: 3, timeoutMs: 48e4, model: "sonnet" });
|
|
16175
16194
|
let cj = cr.json ?? null;
|
|
16176
16195
|
if (!cj) cj = parseModelJson(cr.raw);
|
|
@@ -16205,6 +16224,7 @@ ${JSON.stringify(listing, null, 1)}`;
|
|
|
16205
16224
|
}
|
|
16206
16225
|
out.features = feats.sort((a, b) => Object.keys(b.days).length - Object.keys(a.days).length);
|
|
16207
16226
|
out.featuresDaysUnit = "min";
|
|
16227
|
+
out.featuresPromptSha = clusterSha;
|
|
16208
16228
|
console.log(`focus: ${out.features.length} semantic features from ${recentSess.length} sessions (${stray.length} unmapped \u2192 Everything else)`);
|
|
16209
16229
|
} else console.error(`focus: feature clustering returned no usable JSON (raw ${String(cr.raw || "").length} chars)`);
|
|
16210
16230
|
} catch (e) {
|
|
@@ -16229,7 +16249,11 @@ ${examples}
|
|
|
16229
16249
|
${summary}
|
|
16230
16250
|
|
|
16231
16251
|
Return the Part 5 JSON only.`;
|
|
16232
|
-
|
|
16252
|
+
const judgeSha = promptSha([prompt, process.env.FOCUS_JUDGE_MODEL || "opus"]);
|
|
16253
|
+
if (prev?.llm?.promptSha === judgeSha && !process.env.FOCUS_REFRESH) {
|
|
16254
|
+
out.llm = prev.llm;
|
|
16255
|
+
console.log("focus: judgment inputs unchanged \u2014 reusing llm block (FOCUS_REFRESH=1 to redo)");
|
|
16256
|
+
} else try {
|
|
16233
16257
|
const judgeModel = process.env.FOCUS_JUDGE_MODEL || "opus";
|
|
16234
16258
|
const run22 = await invokeAgent({ prompt, systemPrompt: "You produce strict JSON per the rubric's output contract. No prose outside the JSON.", maxTurns: 3, timeoutMs: 48e4, model: judgeModel });
|
|
16235
16259
|
let parsed = run22.json ?? null;
|
|
@@ -16242,7 +16266,7 @@ Return the Part 5 JSON only.`;
|
|
|
16242
16266
|
The block to append in step 1:
|
|
16243
16267
|
${parsed.claudeMdSnippet}`;
|
|
16244
16268
|
}
|
|
16245
|
-
if (parsed && (parsed.causalFindings?.length || parsed.flowKinds)) out.llm = { ...parsed, model: judgeModel, generatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
16269
|
+
if (parsed && (parsed.causalFindings?.length || parsed.flowKinds)) out.llm = { ...parsed, model: judgeModel, generatedAt: (/* @__PURE__ */ new Date()).toISOString(), promptSha: judgeSha };
|
|
16246
16270
|
else console.error(`focus: LLM pass returned no usable JSON (raw ${String(run22.raw || "").length} chars) \u2014 deterministic data written, causal block empty`);
|
|
16247
16271
|
} catch (e) {
|
|
16248
16272
|
console.error("focus: LLM pass failed \u2014", e.message);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "polymath-society",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.11",
|
|
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",
|