polymath-society 0.2.29 → 0.2.31
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 +439 -285
- package/dist/engine/chat-loops.js +1 -1
- package/dist/engine/exp-allfacets.js +1 -1
- package/dist/engine/exp-person.js +1 -1
- package/dist/engine/exp-pipeline.js +1 -1
- package/dist/engine/peak-demos.js +1 -1
- package/dist/engine/person-dimension-summary.js +1 -1
- package/dist/engine/person-facet-lines.js +1 -1
- package/dist/engine/person-headline.js +1 -1
- package/dist/engine/person-report.js +1 -1
- package/dist/engine/person-self-image.js +1 -1
- package/dist/engine/public-report.js +1 -1
- package/dist/engine/run-analysis.js +1 -1
- package/dist/engine/run-tagger.js +6 -5
- package/dist/index.js +26 -20
- package/dist/pipeline/coding-agglomerate.js +1 -1
- package/dist/pipeline/coding-build.js +25 -16
- package/dist/pipeline/coding-coaching.js +1 -1
- package/dist/pipeline/coding-day-digest.js +9 -7
- package/dist/pipeline/coding-delegation.js +6 -5
- package/dist/pipeline/coding-expertise.js +1 -1
- package/dist/pipeline/coding-focus.js +1 -1
- package/dist/pipeline/coding-frontier-detail.js +1 -1
- package/dist/pipeline/coding-gap.js +1 -1
- package/dist/pipeline/coding-grade.js +13 -8
- package/dist/pipeline/coding-growth.js +1 -1
- package/dist/pipeline/coding-nutshell.js +1 -1
- package/dist/pipeline/coding-walkthrough.js +7 -6
- package/dist/pipeline/coding-workbrief.js +1 -1
- package/dist/web/app.js +13 -10
- package/dist/web/styles.css +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -55,13 +55,10 @@ function electronAppData() {
|
|
|
55
55
|
function resolveDataRoot(env = process.env, cwd = process.cwd(), appData = electronAppData, home = os.homedir()) {
|
|
56
56
|
const fromEnv = env.POLYMATH_DATA_DIR;
|
|
57
57
|
if (fromEnv && fromEnv.trim()) return path.resolve(fromEnv);
|
|
58
|
-
const local = path.join(cwd, ".data");
|
|
59
58
|
const dflt = path.join(home, ".polymath-society", "data");
|
|
60
|
-
if (existsSync(local) && hasCompletedAnalysis(local)) return local;
|
|
61
59
|
const fromApp = appData();
|
|
62
60
|
if (fromApp && hasCompletedAnalysis(fromApp)) return fromApp;
|
|
63
61
|
if (hasCompletedAnalysis(dflt)) return dflt;
|
|
64
|
-
if (existsSync(local)) return local;
|
|
65
62
|
if (fromApp) return fromApp;
|
|
66
63
|
return dflt;
|
|
67
64
|
}
|
|
@@ -484,7 +481,8 @@ var init_cursor = __esm({
|
|
|
484
481
|
});
|
|
485
482
|
|
|
486
483
|
// ../coding-core/dist/raw.js
|
|
487
|
-
import { promises as fs2 } from "fs";
|
|
484
|
+
import { promises as fs2, createReadStream } from "fs";
|
|
485
|
+
import readline from "readline";
|
|
488
486
|
import path2 from "path";
|
|
489
487
|
import os2 from "os";
|
|
490
488
|
function resolveSourceRoot(envVar, ...defaultSegments) {
|
|
@@ -600,10 +598,18 @@ function blank(sessionId, source, file2) {
|
|
|
600
598
|
klassReason: ""
|
|
601
599
|
};
|
|
602
600
|
}
|
|
603
|
-
function
|
|
601
|
+
function jsonlLines(file2) {
|
|
602
|
+
return readline.createInterface({ input: createReadStream(file2, { encoding: "utf-8" }), crlfDelay: Infinity });
|
|
603
|
+
}
|
|
604
|
+
function shedAgentBulk(s) {
|
|
605
|
+
if (s.klass === "agent" && s.events.length > 2)
|
|
606
|
+
s.events = [s.events[0], s.events[s.events.length - 1]];
|
|
607
|
+
return s;
|
|
608
|
+
}
|
|
609
|
+
async function parseClaudeCode(input, sessionId, file2) {
|
|
604
610
|
const s = blank(sessionId, "claude-code", file2);
|
|
605
611
|
const seen = /* @__PURE__ */ new Set();
|
|
606
|
-
for (const lineRaw of
|
|
612
|
+
for await (const lineRaw of typeof input === "string" ? input.split("\n") : input) {
|
|
607
613
|
const line = lineRaw.trim();
|
|
608
614
|
if (!line)
|
|
609
615
|
continue;
|
|
@@ -705,7 +711,7 @@ function parseClaudeCode(raw, sessionId, file2) {
|
|
|
705
711
|
const c = classify(s);
|
|
706
712
|
s.klass = c.klass;
|
|
707
713
|
s.klassReason = c.reason;
|
|
708
|
-
return s;
|
|
714
|
+
return shedAgentBulk(s);
|
|
709
715
|
}
|
|
710
716
|
function codexText(content) {
|
|
711
717
|
if (typeof content === "string")
|
|
@@ -727,10 +733,10 @@ function codexText(content) {
|
|
|
727
733
|
}
|
|
728
734
|
return "";
|
|
729
735
|
}
|
|
730
|
-
function parseCodex(
|
|
736
|
+
async function parseCodex(input, file2) {
|
|
731
737
|
let sessionId = path2.basename(file2, ".jsonl");
|
|
732
738
|
const s = blank(sessionId, "codex", file2);
|
|
733
|
-
for (const lineRaw of
|
|
739
|
+
for await (const lineRaw of typeof input === "string" ? input.split("\n") : input) {
|
|
734
740
|
const line = lineRaw.trim();
|
|
735
741
|
if (!line)
|
|
736
742
|
continue;
|
|
@@ -796,7 +802,7 @@ function parseCodex(raw, file2) {
|
|
|
796
802
|
const c = classify(s);
|
|
797
803
|
s.klass = c.klass;
|
|
798
804
|
s.klassReason = c.reason;
|
|
799
|
-
return s;
|
|
805
|
+
return shedAgentBulk(s);
|
|
800
806
|
}
|
|
801
807
|
async function readClaudeCodeAt(base2, machine) {
|
|
802
808
|
const out = [];
|
|
@@ -820,13 +826,12 @@ async function readClaudeCodeAt(base2, machine) {
|
|
|
820
826
|
}
|
|
821
827
|
for (const f of files) {
|
|
822
828
|
const file2 = path2.join(full, f);
|
|
823
|
-
let
|
|
829
|
+
let s = null;
|
|
824
830
|
try {
|
|
825
|
-
|
|
831
|
+
s = await parseClaudeCode(jsonlLines(file2), path2.basename(f, ".jsonl"), file2);
|
|
826
832
|
} catch {
|
|
827
833
|
continue;
|
|
828
834
|
}
|
|
829
|
-
const s = parseClaudeCode(raw, path2.basename(f, ".jsonl"), file2);
|
|
830
835
|
if (s) {
|
|
831
836
|
if (machine)
|
|
832
837
|
s.machine = machine;
|
|
@@ -861,13 +866,12 @@ async function readCodexAt(base2, machine) {
|
|
|
861
866
|
await walkJsonl(base2, files);
|
|
862
867
|
const out = [];
|
|
863
868
|
for (const file2 of files) {
|
|
864
|
-
let
|
|
869
|
+
let s = null;
|
|
865
870
|
try {
|
|
866
|
-
|
|
871
|
+
s = await parseCodex(jsonlLines(file2), file2);
|
|
867
872
|
} catch {
|
|
868
873
|
continue;
|
|
869
874
|
}
|
|
870
|
-
const s = parseCodex(raw, file2);
|
|
871
875
|
if (s) {
|
|
872
876
|
if (machine)
|
|
873
877
|
s.machine = machine;
|
|
@@ -1073,7 +1077,7 @@ function rawSessionFromCursorComposer(c, file2, cwd) {
|
|
|
1073
1077
|
const cl = classify(s);
|
|
1074
1078
|
s.klass = cl.klass;
|
|
1075
1079
|
s.klassReason = cl.reason;
|
|
1076
|
-
return s;
|
|
1080
|
+
return shedAgentBulk(s);
|
|
1077
1081
|
}
|
|
1078
1082
|
function parseCursorTranscript(raw, composerId, file2, ws, fileMtime) {
|
|
1079
1083
|
const s = blank(composerId, "cursor", file2);
|
|
@@ -1118,7 +1122,7 @@ function parseCursorTranscript(raw, composerId, file2, ws, fileMtime) {
|
|
|
1118
1122
|
const c = classify(s);
|
|
1119
1123
|
s.klass = c.klass;
|
|
1120
1124
|
s.klassReason = c.reason;
|
|
1121
|
-
return s;
|
|
1125
|
+
return shedAgentBulk(s);
|
|
1122
1126
|
}
|
|
1123
1127
|
function cursorWorkspaceSession(ws, idx) {
|
|
1124
1128
|
if (ws.generations.length === 0)
|
|
@@ -1140,7 +1144,7 @@ function cursorWorkspaceSession(ws, idx) {
|
|
|
1140
1144
|
const c = classify(s);
|
|
1141
1145
|
s.klass = c.klass;
|
|
1142
1146
|
s.klassReason = c.reason;
|
|
1143
|
-
return s;
|
|
1147
|
+
return shedAgentBulk(s);
|
|
1144
1148
|
}
|
|
1145
1149
|
async function readCursorAt(roots, machine) {
|
|
1146
1150
|
const workspaces = await readCursorWorkspaces(roots.workspace);
|
|
@@ -1254,6 +1258,8 @@ async function readAllSessions(opts2 = {}) {
|
|
|
1254
1258
|
]);
|
|
1255
1259
|
const all = [...cc, ...cx, ...cr, ...mm];
|
|
1256
1260
|
demoteTemplateFanouts(all);
|
|
1261
|
+
for (const s of all)
|
|
1262
|
+
shedAgentBulk(s);
|
|
1257
1263
|
return all;
|
|
1258
1264
|
}
|
|
1259
1265
|
var SOURCE_ROOT_ENV_VARS, anyRootOverridden, claudeProjectsRoot, codexSessionsRoot, cursorWorkspaceRoot, cursorProjectsRoot, cursorGlobalRoot, MACHINE_CURSOR_FILE_RE, SKIP_DIR_RE, AGENT_CWD_RE, PERSONA_RE, OUTPUT_CONTRACT_RES, CAPS_HEADER_RE, PING_RE, ms, CURSOR_USER_QUERY_RE2, NODE_SQLITE2, FANOUT_PREFIX, FANOUT_MIN_SESSIONS;
|
|
@@ -18779,7 +18785,7 @@ var init_runStats = __esm({
|
|
|
18779
18785
|
"../../lib/agents/shared/runStats.ts"() {
|
|
18780
18786
|
"use strict";
|
|
18781
18787
|
G = globalThis;
|
|
18782
|
-
file = () => path11.join(process.cwd(), ".data", "run-stats.jsonl");
|
|
18788
|
+
file = () => path11.join(process.env.POLYMATH_DATA_DIR || path11.join(process.cwd(), ".data"), "run-stats.jsonl");
|
|
18783
18789
|
}
|
|
18784
18790
|
});
|
|
18785
18791
|
|
|
@@ -22822,15 +22828,167 @@ var init_publicCodingPageApi = __esm({
|
|
|
22822
22828
|
}
|
|
22823
22829
|
});
|
|
22824
22830
|
|
|
22831
|
+
// src/plan.ts
|
|
22832
|
+
var plan_exports = {};
|
|
22833
|
+
__export(plan_exports, {
|
|
22834
|
+
UNSUPPORTED_FULL_TIERS: () => UNSUPPORTED_FULL_TIERS,
|
|
22835
|
+
detectCodexPlan: () => detectCodexPlan,
|
|
22836
|
+
detectPlan: () => detectPlan,
|
|
22837
|
+
estimateLaneCosts: () => estimateLaneCosts,
|
|
22838
|
+
opusAvailable: () => opusAvailable,
|
|
22839
|
+
remainingFractions: () => remainingFractions,
|
|
22840
|
+
scheduleLanes: () => scheduleLanes,
|
|
22841
|
+
supportsFullAnalysis: () => supportsFullAnalysis,
|
|
22842
|
+
tierFromChatgptPlan: () => tierFromChatgptPlan,
|
|
22843
|
+
tierFromStrings: () => tierFromStrings
|
|
22844
|
+
});
|
|
22845
|
+
import { promises as fs32 } from "fs";
|
|
22846
|
+
import os8 from "os";
|
|
22847
|
+
import path38 from "path";
|
|
22848
|
+
function supportsFullAnalysis(tier) {
|
|
22849
|
+
if (process.env.POLYMATH_FORCE_FULL === "1") return true;
|
|
22850
|
+
return !UNSUPPORTED_FULL_TIERS.includes(tier);
|
|
22851
|
+
}
|
|
22852
|
+
function opusAvailable(tier) {
|
|
22853
|
+
return tier === "max_20x" || tier === "max_5x";
|
|
22854
|
+
}
|
|
22855
|
+
function tierFromStrings(...hints) {
|
|
22856
|
+
for (const h of hints) {
|
|
22857
|
+
if (!h) continue;
|
|
22858
|
+
const s = h.toLowerCase();
|
|
22859
|
+
if (s.includes("max_20x") || s.includes("max20x")) return "max_20x";
|
|
22860
|
+
if (s.includes("max_5x") || s.includes("max5x")) return "max_5x";
|
|
22861
|
+
if (s.includes("pro")) return "pro";
|
|
22862
|
+
if (s.includes("claude_max")) return "max_5x";
|
|
22863
|
+
}
|
|
22864
|
+
return "unknown";
|
|
22865
|
+
}
|
|
22866
|
+
function tierFromChatgptPlan(planType) {
|
|
22867
|
+
const s = (planType ?? "").toLowerCase();
|
|
22868
|
+
if (s === "pro") return "gpt_pro";
|
|
22869
|
+
if (s === "plus") return "gpt_plus";
|
|
22870
|
+
if (s === "team" || s === "enterprise" || s === "business") return "gpt_team";
|
|
22871
|
+
if (s === "free") return "gpt_free";
|
|
22872
|
+
return "unknown";
|
|
22873
|
+
}
|
|
22874
|
+
async function detectCodexPlan(home = os8.homedir()) {
|
|
22875
|
+
try {
|
|
22876
|
+
const raw = JSON.parse(await fs32.readFile(path38.join(home, ".codex", "auth.json"), "utf8"));
|
|
22877
|
+
for (const tok of [raw.tokens?.id_token, raw.tokens?.access_token]) {
|
|
22878
|
+
if (!tok) continue;
|
|
22879
|
+
try {
|
|
22880
|
+
const payload = JSON.parse(Buffer.from(tok.split(".")[1], "base64url").toString("utf8"));
|
|
22881
|
+
const t = tierFromChatgptPlan(payload["https://api.openai.com/auth"]?.chatgpt_plan_type);
|
|
22882
|
+
if (t !== "unknown") return t;
|
|
22883
|
+
} catch {
|
|
22884
|
+
}
|
|
22885
|
+
}
|
|
22886
|
+
} catch {
|
|
22887
|
+
}
|
|
22888
|
+
return "unknown";
|
|
22889
|
+
}
|
|
22890
|
+
async function detectPlan(home = os8.homedir()) {
|
|
22891
|
+
let tier = "unknown";
|
|
22892
|
+
try {
|
|
22893
|
+
const raw = JSON.parse(await fs32.readFile(path38.join(home, ".claude.json"), "utf8"));
|
|
22894
|
+
const oa = raw.oauthAccount ?? {};
|
|
22895
|
+
tier = tierFromStrings(oa.userRateLimitTier, oa.organizationRateLimitTier, oa.organizationType);
|
|
22896
|
+
} catch {
|
|
22897
|
+
}
|
|
22898
|
+
if (tier === "unknown") tier = await detectCodexPlan(home);
|
|
22899
|
+
return { tier, label: LABEL[tier], windowUsd: WINDOW_USD[tier] };
|
|
22900
|
+
}
|
|
22901
|
+
function estimateLaneCosts(input) {
|
|
22902
|
+
const codingUsd = Math.max(5, Math.min(32, Math.round(input.agentLogFiles * 9e-4)));
|
|
22903
|
+
const chatUsd = input.chatIncluded ? Math.round(40 + input.exportTotalMB * 0.8) : 0;
|
|
22904
|
+
return { codingUsd, chatUsd };
|
|
22905
|
+
}
|
|
22906
|
+
async function remainingFractions(dataRoot, agentLogFiles) {
|
|
22907
|
+
const clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, v));
|
|
22908
|
+
let coding = 1;
|
|
22909
|
+
try {
|
|
22910
|
+
const graded = (await fs32.readdir(path38.join(dataRoot, "coding", "grades"))).filter((f) => f.endsWith(".json")).length;
|
|
22911
|
+
const expected = Math.max(1, agentLogFiles * 56e-4);
|
|
22912
|
+
coding = clamp(1 - graded / expected, 0.05, 1);
|
|
22913
|
+
} catch {
|
|
22914
|
+
}
|
|
22915
|
+
let chatDone = 0;
|
|
22916
|
+
try {
|
|
22917
|
+
const st = await fs32.stat(path38.join(dataRoot, "signals", "index.jsonl"));
|
|
22918
|
+
if (st.size > 0) chatDone += 0.3;
|
|
22919
|
+
} catch {
|
|
22920
|
+
}
|
|
22921
|
+
try {
|
|
22922
|
+
const lenses = await fs32.readdir(path38.join(dataRoot, "engine-pilot", "grades"));
|
|
22923
|
+
let withPerson = 0;
|
|
22924
|
+
for (const l of lenses) {
|
|
22925
|
+
try {
|
|
22926
|
+
await fs32.stat(path38.join(dataRoot, "engine-pilot", "grades", l, "_person.json"));
|
|
22927
|
+
withPerson++;
|
|
22928
|
+
} catch {
|
|
22929
|
+
}
|
|
22930
|
+
}
|
|
22931
|
+
chatDone += 0.6 * Math.min(1, withPerson / 5);
|
|
22932
|
+
} catch {
|
|
22933
|
+
}
|
|
22934
|
+
return { coding, chat: clamp(1 - chatDone, 0.1, 1) };
|
|
22935
|
+
}
|
|
22936
|
+
function scheduleLanes(plan, est) {
|
|
22937
|
+
const chat = est.chatUsd === 0 || est.chatUsd <= plan.windowUsd * 0.9 ? "now" : "overnight";
|
|
22938
|
+
return {
|
|
22939
|
+
coding: "now",
|
|
22940
|
+
chat,
|
|
22941
|
+
// No plan name here — the schedule header names the plan once, and
|
|
22942
|
+
// repeating it doubled the clumsy unknown-plan label (2026-07-22
|
|
22943
|
+
// walkthrough). Phrased for the two-column "Proposed schedule" rows:
|
|
22944
|
+
// "<lane> <verdict> — <reason>".
|
|
22945
|
+
codingReason: `runs now \u2014 the report link appears right away and fills in as it goes`,
|
|
22946
|
+
chatReason: est.chatUsd === 0 ? "not planned \u2014 no chat sources included" : chat === "overnight" ? `starts at 2:00 am tonight \u2014 a chat corpus this size is an overnight job; it runs while you sleep` : `runs now, alongside coding`
|
|
22947
|
+
};
|
|
22948
|
+
}
|
|
22949
|
+
var UNSUPPORTED_FULL_TIERS, WINDOW_USD, LABEL;
|
|
22950
|
+
var init_plan = __esm({
|
|
22951
|
+
"src/plan.ts"() {
|
|
22952
|
+
"use strict";
|
|
22953
|
+
UNSUPPORTED_FULL_TIERS = ["gpt_plus", "gpt_free"];
|
|
22954
|
+
WINDOW_USD = {
|
|
22955
|
+
max_20x: 300,
|
|
22956
|
+
max_5x: 75,
|
|
22957
|
+
pro: 15,
|
|
22958
|
+
// ChatGPT tiers, mapped to rough Claude-window parity by monthly price
|
|
22959
|
+
// ($200 Pro ≈ Max 20x; $20 Plus ≈ Claude Pro; Team between; free ≈ nothing).
|
|
22960
|
+
gpt_pro: 300,
|
|
22961
|
+
gpt_plus: 20,
|
|
22962
|
+
gpt_team: 50,
|
|
22963
|
+
gpt_free: 5,
|
|
22964
|
+
unknown: 15
|
|
22965
|
+
// conservative: schedule like Pro when we can't tell
|
|
22966
|
+
};
|
|
22967
|
+
LABEL = {
|
|
22968
|
+
max_20x: "Claude Max 20x",
|
|
22969
|
+
max_5x: "Claude Max 5x",
|
|
22970
|
+
pro: "Claude Pro",
|
|
22971
|
+
gpt_pro: "ChatGPT Pro (Codex)",
|
|
22972
|
+
gpt_plus: "ChatGPT Plus (Codex)",
|
|
22973
|
+
gpt_team: "ChatGPT Team (Codex)",
|
|
22974
|
+
gpt_free: "ChatGPT Free (Codex)",
|
|
22975
|
+
unknown: "an undetected plan (scheduling conservatively)"
|
|
22976
|
+
};
|
|
22977
|
+
}
|
|
22978
|
+
});
|
|
22979
|
+
|
|
22825
22980
|
// src/pipeline.ts
|
|
22826
22981
|
var pipeline_exports = {};
|
|
22827
22982
|
__export(pipeline_exports, {
|
|
22983
|
+
TAIL_MODEL_ENV: () => TAIL_MODEL_ENV,
|
|
22984
|
+
applyTailModelEnv: () => applyTailModelEnv,
|
|
22828
22985
|
apportionHeavy: () => apportionHeavy,
|
|
22829
22986
|
codingDataRoot: () => codingDataRoot,
|
|
22830
22987
|
evalUpToDate: () => evalUpToDate,
|
|
22831
22988
|
expectedLlmArtifacts: () => expectedLlmArtifacts,
|
|
22832
22989
|
hasPipeline: () => hasPipeline,
|
|
22833
22990
|
machineBudget: () => machineBudget,
|
|
22991
|
+
resolveTailModel: () => resolveTailModel,
|
|
22834
22992
|
runPipeline: () => runPipeline,
|
|
22835
22993
|
stages: () => stages,
|
|
22836
22994
|
startKeepAwake: () => startKeepAwake,
|
|
@@ -22839,11 +22997,11 @@ __export(pipeline_exports, {
|
|
|
22839
22997
|
upToDateSkip: () => upToDateSkip
|
|
22840
22998
|
});
|
|
22841
22999
|
import { spawn as spawn7 } from "child_process";
|
|
22842
|
-
import
|
|
22843
|
-
import
|
|
22844
|
-
import { existsSync as existsSync5, promises as
|
|
23000
|
+
import os9 from "os";
|
|
23001
|
+
import path39 from "path";
|
|
23002
|
+
import { existsSync as existsSync5, promises as fs33 } from "fs";
|
|
22845
23003
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
22846
|
-
function machineBudget(totalMemBytes =
|
|
23004
|
+
function machineBudget(totalMemBytes = os9.totalmem(), cpus = os9.availableParallelism?.() ?? os9.cpus().length, envOverride = process.env.POLYMATH_CONC) {
|
|
22847
23005
|
const envB = Number(envOverride);
|
|
22848
23006
|
if (Number.isFinite(envB) && envB >= 1) return Math.min(32, Math.floor(envB));
|
|
22849
23007
|
const byMem = Math.floor(totalMemBytes / 2 ** 30 * 0.35 / 0.45);
|
|
@@ -22870,6 +23028,8 @@ function stages(o) {
|
|
|
22870
23028
|
if (o.idleGapMin != null) buildArgs.push("--idle", String(o.idleGapMin));
|
|
22871
23029
|
const gradeArgs = ["--all", "--model", gradeModel, "--conc", conc];
|
|
22872
23030
|
if (o.regrade) gradeArgs.push("--regrade");
|
|
23031
|
+
const tailModel = o.model ?? o.tailModel;
|
|
23032
|
+
const tailArgs = tailModel ? ["--model", tailModel] : [];
|
|
22873
23033
|
return [
|
|
22874
23034
|
// ---- deterministic foundation (fast, free) ----
|
|
22875
23035
|
{ script: "coding-build.mts", label: "Scrape + classify your sessions", llm: false, args: buildArgs, out: "coding/sessions.json" },
|
|
@@ -22901,10 +23061,10 @@ function stages(o) {
|
|
|
22901
23061
|
// ---- corpus aggregate (reads grades; deterministic rollup) ----
|
|
22902
23062
|
{ script: "coding-aggregate.mts", label: "Corpus aggregate \u2014 ability ceiling + flow", llm: false, args: [], out: "coding/aggregate.json" },
|
|
22903
23063
|
// ---- grade readers (grades/* is complete once aggregate ran) ----
|
|
22904
|
-
//
|
|
22905
|
-
//
|
|
22906
|
-
//
|
|
22907
|
-
{ script: "coding-agglomerate.mts", label: "Agglomerated criteria + verdicts + signature moves", llm: true, weight: 4, args:
|
|
23064
|
+
// The agglomerate script defaults itself to Opus (one call per run; the
|
|
23065
|
+
// axis verdicts are the most judgment-heavy output). tailArgs overrides
|
|
23066
|
+
// that on plans that can't run Opus; an explicit user model choice wins.
|
|
23067
|
+
{ script: "coding-agglomerate.mts", label: "Agglomerated criteria + verdicts + signature moves", llm: true, weight: 4, args: [...tailArgs], out: "coding/agglomerate.json", batch: "grade-readers" },
|
|
22908
23068
|
// Domain-expertise map DISABLED (owner call 2026-07-22): the single most
|
|
22909
23069
|
// expensive stage of the whole run ($13.88 of $49.34 measured — 129 sonnet
|
|
22910
23070
|
// calls) and for most users the hiring-bar filter correctly returns ZERO
|
|
@@ -22918,34 +23078,44 @@ function stages(o) {
|
|
|
22918
23078
|
// Work brief — the hiring-manager narrative + continuous timeline. Consumes
|
|
22919
23079
|
// day-digest.json (heavy batch, already complete) + concurrency/projects;
|
|
22920
23080
|
// disjoint output, so it rides the synthesis batch. Defaults itself to Opus
|
|
22921
|
-
// (the journey's significance calls are judgment-heavy);
|
|
22922
|
-
// choice
|
|
22923
|
-
{ script: "coding-workbrief.mts", label: "Work brief \u2014 narrative timeline", llm: true, weight: 3, args:
|
|
23081
|
+
// (the journey's significance calls are judgment-heavy); tailArgs / an
|
|
23082
|
+
// explicit model choice win. Prompt-hash gated + up-to-date-skip like its siblings.
|
|
23083
|
+
{ script: "coding-workbrief.mts", label: "Work brief \u2014 narrative timeline", llm: true, weight: 3, args: [...tailArgs], out: "coding/workbrief.json", batch: "synthesis" },
|
|
22924
23084
|
// Growth reads grades/* + deterministic artifacts only (no per-session AI
|
|
22925
23085
|
// calls — it deliberately ignores the AI recency window and covers the full
|
|
22926
23086
|
// history); disjoint output, so it rides the synthesis batch. Like
|
|
22927
|
-
// agglomerate it defaults itself to Opus; an explicit model choice
|
|
22928
|
-
{ script: "coding-growth.mts", label: "Growth arcs + learning rate", llm: true, weight: 3, args:
|
|
23087
|
+
// agglomerate it defaults itself to Opus; tailArgs / an explicit model choice win.
|
|
23088
|
+
{ script: "coding-growth.mts", label: "Growth arcs + learning rate", llm: true, weight: 3, args: [...tailArgs], out: "coding/growth.json", batch: "synthesis" },
|
|
22929
23089
|
// nutshell stays LAST + alone: it merges INTO aggregate.json while the two
|
|
22930
23090
|
// above read the compiled profile — racing them re-reads mid-write.
|
|
22931
23091
|
{ script: "coding-nutshell.mts", label: "Big-picture nutshell", llm: true, weight: 1, args: [], out: "coding/aggregate.json" }
|
|
22932
23092
|
// merges bigPicture INTO aggregate.json
|
|
22933
23093
|
];
|
|
22934
23094
|
}
|
|
23095
|
+
function applyTailModelEnv(env, tailModel) {
|
|
23096
|
+
if (!tailModel) return;
|
|
23097
|
+
for (const key2 of Object.values(TAIL_MODEL_ENV)) if (!env[key2]) env[key2] = tailModel;
|
|
23098
|
+
}
|
|
23099
|
+
async function resolveTailModel(o, home) {
|
|
23100
|
+
if (o.model || o.tailModel) return o.tailModel;
|
|
23101
|
+
const { detectPlan: detectPlan2, opusAvailable: opusAvailable2 } = await Promise.resolve().then(() => (init_plan(), plan_exports));
|
|
23102
|
+
const { tier } = await detectPlan2(home);
|
|
23103
|
+
return opusAvailable2(tier) ? void 0 : "sonnet";
|
|
23104
|
+
}
|
|
22935
23105
|
function bundledPipelineDir() {
|
|
22936
|
-
const d =
|
|
22937
|
-
return existsSync5(
|
|
23106
|
+
const d = path39.join(MODULE_DIR2, "pipeline");
|
|
23107
|
+
return existsSync5(path39.join(d, "coding-build.js")) ? d : null;
|
|
22938
23108
|
}
|
|
22939
23109
|
function stageInvocation(repoRoot, scriptRel, args) {
|
|
22940
|
-
const scriptAbs =
|
|
23110
|
+
const scriptAbs = path39.join(repoRoot, "scripts", scriptRel);
|
|
22941
23111
|
if (existsSync5(scriptAbs)) {
|
|
22942
|
-
const local =
|
|
23112
|
+
const local = path39.join(repoRoot, "node_modules", ".bin", "tsx");
|
|
22943
23113
|
if (existsSync5(local)) return { cmd: local, argv: [scriptAbs, ...args], cwd: repoRoot };
|
|
22944
23114
|
return { cmd: "npx", argv: ["tsx", scriptAbs, ...args], cwd: repoRoot };
|
|
22945
23115
|
}
|
|
22946
23116
|
const bundled = bundledPipelineDir();
|
|
22947
23117
|
if (bundled) {
|
|
22948
|
-
const js =
|
|
23118
|
+
const js = path39.join(bundled, scriptRel.replace(/\.mts$/, ".js"));
|
|
22949
23119
|
return { cmd: process.execPath, argv: [js, ...args], cwd: process.cwd() };
|
|
22950
23120
|
}
|
|
22951
23121
|
throw new Error(`pipeline stage ${scriptRel}: neither repo scripts/ nor bundled dist/pipeline/ found`);
|
|
@@ -23001,17 +23171,17 @@ function runStage(repoRoot, st, env, onLine) {
|
|
|
23001
23171
|
});
|
|
23002
23172
|
}
|
|
23003
23173
|
function hasPipeline(repoRoot) {
|
|
23004
|
-
return existsSync5(
|
|
23174
|
+
return existsSync5(path39.join(repoRoot, "scripts", "coding-build.mts")) || bundledPipelineDir() != null;
|
|
23005
23175
|
}
|
|
23006
23176
|
function codingDataRoot(repoRoot) {
|
|
23007
|
-
if (!process.env.POLYMATH_DATA_DIR && existsSync5(
|
|
23008
|
-
return
|
|
23177
|
+
if (!process.env.POLYMATH_DATA_DIR && existsSync5(path39.join(repoRoot, "scripts", "coding-build.mts"))) {
|
|
23178
|
+
return path39.join(repoRoot, ".data");
|
|
23009
23179
|
}
|
|
23010
23180
|
return resolveDataRoot();
|
|
23011
23181
|
}
|
|
23012
23182
|
async function finalCodingArtifacts(codingDir) {
|
|
23013
|
-
const files = await
|
|
23014
|
-
return files.filter((f) => f.endsWith(".json") && f !== "report-run.json" && !f.startsWith(".")).sort().map((f) =>
|
|
23183
|
+
const files = await fs33.readdir(codingDir).catch(() => []);
|
|
23184
|
+
return files.filter((f) => f.endsWith(".json") && f !== "report-run.json" && !f.startsWith(".")).sort().map((f) => path39.join(codingDir, f));
|
|
23015
23185
|
}
|
|
23016
23186
|
function upToDateSkip(i) {
|
|
23017
23187
|
const pending2 = i.gradableIds.filter((id) => !i.gradedIds.has(id)).length;
|
|
@@ -23024,22 +23194,22 @@ function expectedLlmArtifacts(o) {
|
|
|
23024
23194
|
}
|
|
23025
23195
|
async function evalUpToDate(codingDir, threshold, regrade, opts2) {
|
|
23026
23196
|
try {
|
|
23027
|
-
const dataDir =
|
|
23197
|
+
const dataDir = path39.dirname(codingDir);
|
|
23028
23198
|
const missing = [];
|
|
23029
23199
|
for (const rel of expectedLlmArtifacts(opts2 ?? {})) {
|
|
23030
|
-
const ok = await
|
|
23200
|
+
const ok = await fs33.stat(path39.join(dataDir, rel)).then(() => true).catch(() => false);
|
|
23031
23201
|
if (!ok) missing.push(rel);
|
|
23032
23202
|
}
|
|
23033
23203
|
const { partition: partition2, aiWindowCutoff: aiWindowCutoff2, capGradable: capGradable2 } = await Promise.resolve().then(() => (init_gate2(), gate_exports));
|
|
23034
|
-
const sessions = JSON.parse(await
|
|
23204
|
+
const sessions = JSON.parse(await fs33.readFile(path39.join(codingDir, "sessions.json"), "utf8"));
|
|
23035
23205
|
const live = sessions.filter((s) => s.klass === "interactive" && !s.duplicateOf);
|
|
23036
23206
|
const cutoff = aiWindowCutoff2(live);
|
|
23037
23207
|
const { gradable: uncapped } = partition2(cutoff ? live.filter((s) => (s.start ?? "") >= cutoff) : live);
|
|
23038
23208
|
const gradable = capGradable2(uncapped);
|
|
23039
23209
|
const graded = new Set(
|
|
23040
|
-
(await
|
|
23210
|
+
(await fs33.readdir(path39.join(codingDir, "grades")).catch(() => [])).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -5))
|
|
23041
23211
|
);
|
|
23042
|
-
const agg = JSON.parse(await
|
|
23212
|
+
const agg = JSON.parse(await fs33.readFile(path39.join(codingDir, "aggregate.json"), "utf8").catch(() => "{}"));
|
|
23043
23213
|
const hasPriorRun = typeof agg.bigPicture === "string" && agg.bigPicture.trim().length > 0;
|
|
23044
23214
|
return {
|
|
23045
23215
|
...upToDateSkip({
|
|
@@ -23104,14 +23274,19 @@ async function runPipeline(o) {
|
|
|
23104
23274
|
const dataRoot = codingDataRoot(o.repoRoot);
|
|
23105
23275
|
const env = { ...process.env, POLYMATH_RESILIENT: "1", POLYMATH_DATA_DIR: dataRoot };
|
|
23106
23276
|
if (!/max-old-space-size/.test(env.NODE_OPTIONS ?? "")) {
|
|
23107
|
-
const headroomMb = Math.min(12288, Math.max(4096, Math.round(
|
|
23277
|
+
const headroomMb = Math.min(12288, Math.max(4096, Math.round(os9.totalmem() / 2 ** 20 * 0.6)));
|
|
23108
23278
|
env.NODE_OPTIONS = `${env.NODE_OPTIONS ?? ""} --max-old-space-size=${headroomMb}`.trim();
|
|
23109
23279
|
}
|
|
23110
23280
|
if (!o.overnight) env.POLYMATH_RESILIENT_NO_WINDOW = "1";
|
|
23111
23281
|
const stopKeepAwake = o.overnight ? startKeepAwake() : () => {
|
|
23112
23282
|
};
|
|
23113
|
-
const
|
|
23114
|
-
|
|
23283
|
+
const tailModel = await resolveTailModel(o);
|
|
23284
|
+
applyTailModelEnv(env, tailModel);
|
|
23285
|
+
if (tailModel && !o.deterministicOnly) {
|
|
23286
|
+
o.onLine?.(`\u24D8 synthesis stages run on ${tailModel} \u2014 this plan doesn't include Opus (Max plans keep the Opus default)`);
|
|
23287
|
+
}
|
|
23288
|
+
const list = stages({ ...o, tailModel }).filter((st) => !o.deterministicOnly || !st.llm);
|
|
23289
|
+
const codingDir = path39.join(dataRoot, "coding");
|
|
23115
23290
|
const central = centralConfig();
|
|
23116
23291
|
const t0 = Date.now();
|
|
23117
23292
|
const log = await startRunLog(
|
|
@@ -23120,7 +23295,7 @@ async function runPipeline(o) {
|
|
|
23120
23295
|
supabaseUrl: central.supabaseUrl,
|
|
23121
23296
|
supabaseAnonKey: central.supabaseAnonKey,
|
|
23122
23297
|
artifacts: () => finalCodingArtifacts(codingDir),
|
|
23123
|
-
refPath:
|
|
23298
|
+
refPath: path39.join(codingDir, "report-run.json")
|
|
23124
23299
|
// next to the served artifacts
|
|
23125
23300
|
}
|
|
23126
23301
|
);
|
|
@@ -23157,7 +23332,7 @@ async function runPipeline(o) {
|
|
|
23157
23332
|
failed.push({ label: st.label, script: st.script, error });
|
|
23158
23333
|
o.onLine?.(`\u26A0\uFE0F stage FAILED (continuing): ${st.label} \u2014 ${error}`);
|
|
23159
23334
|
}
|
|
23160
|
-
const sha = st.out ? await fileSha(
|
|
23335
|
+
const sha = st.out ? await fileSha(path39.join(dataRoot, st.out)) : null;
|
|
23161
23336
|
log.event(st.script.replace(/\.mts$/, ""), { ok, ms: Date.now() - stStart, ...sha ? { sha } : {} });
|
|
23162
23337
|
stageTimes.push({ script: st.script, label: st.label, ms: Date.now() - stStart, ok });
|
|
23163
23338
|
o.onStageDone?.(st.label, st.llm, ok, st.script);
|
|
@@ -23193,7 +23368,7 @@ async function runPipeline(o) {
|
|
|
23193
23368
|
model: o.model ?? "sonnet(+haiku grade)",
|
|
23194
23369
|
budget: machineBudget()
|
|
23195
23370
|
};
|
|
23196
|
-
await
|
|
23371
|
+
await fs33.appendFile(path39.join(codingDir, "run-times.jsonl"), JSON.stringify(record) + "\n");
|
|
23197
23372
|
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 ");
|
|
23198
23373
|
o.onLine?.(`\u23F1 run took ${fmt(totalMs)} (${record.kind}) \u2014 slowest: ${slowest} \xB7 ledger: .data/coding/run-times.jsonl`);
|
|
23199
23374
|
} catch {
|
|
@@ -23201,14 +23376,18 @@ async function runPipeline(o) {
|
|
|
23201
23376
|
stopKeepAwake();
|
|
23202
23377
|
return { failed, ...skippedLlm ? { skippedLlm } : {} };
|
|
23203
23378
|
}
|
|
23204
|
-
var MODULE_DIR2, liveStages, killHooked;
|
|
23379
|
+
var MODULE_DIR2, TAIL_MODEL_ENV, liveStages, killHooked;
|
|
23205
23380
|
var init_pipeline2 = __esm({
|
|
23206
23381
|
"src/pipeline.ts"() {
|
|
23207
23382
|
"use strict";
|
|
23208
23383
|
init_central();
|
|
23209
23384
|
init_dataHome();
|
|
23210
23385
|
init_runLog();
|
|
23211
|
-
MODULE_DIR2 =
|
|
23386
|
+
MODULE_DIR2 = path39.dirname(fileURLToPath3(import.meta.url));
|
|
23387
|
+
TAIL_MODEL_ENV = {
|
|
23388
|
+
"coding-coaching.mts": "AGENT_MODEL",
|
|
23389
|
+
"coding-focus.mts": "FOCUS_JUDGE_MODEL"
|
|
23390
|
+
};
|
|
23212
23391
|
liveStages = /* @__PURE__ */ new Set();
|
|
23213
23392
|
killHooked = false;
|
|
23214
23393
|
}
|
|
@@ -23224,9 +23403,9 @@ __export(chatPipeline_exports, {
|
|
|
23224
23403
|
runChatPipeline: () => runChatPipeline
|
|
23225
23404
|
});
|
|
23226
23405
|
import { spawn as spawn8 } from "child_process";
|
|
23227
|
-
import
|
|
23228
|
-
import
|
|
23229
|
-
import { existsSync as existsSync6, promises as
|
|
23406
|
+
import os10 from "os";
|
|
23407
|
+
import path40 from "path";
|
|
23408
|
+
import { existsSync as existsSync6, promises as fs34 } from "fs";
|
|
23230
23409
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
23231
23410
|
function chatEngineStages() {
|
|
23232
23411
|
return [
|
|
@@ -23246,40 +23425,40 @@ function chatEngineStages() {
|
|
|
23246
23425
|
];
|
|
23247
23426
|
}
|
|
23248
23427
|
function bundledEngineDir() {
|
|
23249
|
-
const d =
|
|
23250
|
-
return existsSync6(
|
|
23428
|
+
const d = path40.join(MODULE_DIR3, "engine");
|
|
23429
|
+
return existsSync6(path40.join(d, "run-tagger.js")) ? d : null;
|
|
23251
23430
|
}
|
|
23252
23431
|
function stageInvocation2(repoRoot, scriptRel, args) {
|
|
23253
|
-
const scriptAbs =
|
|
23432
|
+
const scriptAbs = path40.join(repoRoot, "scripts", scriptRel);
|
|
23254
23433
|
if (existsSync6(scriptAbs)) {
|
|
23255
|
-
const local =
|
|
23434
|
+
const local = path40.join(repoRoot, "node_modules", ".bin", "tsx");
|
|
23256
23435
|
if (existsSync6(local)) return { cmd: local, argv: [scriptAbs, ...args], cwd: repoRoot };
|
|
23257
23436
|
return { cmd: "npx", argv: ["tsx", scriptAbs, ...args], cwd: repoRoot };
|
|
23258
23437
|
}
|
|
23259
23438
|
const bundled = bundledEngineDir();
|
|
23260
23439
|
if (bundled) {
|
|
23261
|
-
const js =
|
|
23440
|
+
const js = path40.join(bundled, scriptRel.replace(/\.mts$/, ".js"));
|
|
23262
23441
|
return { cmd: process.execPath, argv: [js, ...args], cwd: process.cwd() };
|
|
23263
23442
|
}
|
|
23264
23443
|
throw new Error(`chat-engine stage ${scriptRel}: neither repo scripts/ nor bundled dist/engine/ found`);
|
|
23265
23444
|
}
|
|
23266
23445
|
function hasChatPipeline(repoRoot) {
|
|
23267
|
-
return existsSync6(
|
|
23446
|
+
return existsSync6(path40.join(repoRoot, "scripts", "run-tagger.mts")) || bundledEngineDir() != null;
|
|
23268
23447
|
}
|
|
23269
23448
|
function chatDataRoot(repoRoot) {
|
|
23270
|
-
if (!process.env.POLYMATH_DATA_DIR && existsSync6(
|
|
23271
|
-
return
|
|
23449
|
+
if (!process.env.POLYMATH_DATA_DIR && existsSync6(path40.join(repoRoot, "scripts", "run-tagger.mts"))) {
|
|
23450
|
+
return path40.join(repoRoot, ".data");
|
|
23272
23451
|
}
|
|
23273
23452
|
return resolveDataRoot();
|
|
23274
23453
|
}
|
|
23275
23454
|
async function finalChatArtifacts(dataRoot) {
|
|
23276
|
-
const gradesDir =
|
|
23455
|
+
const gradesDir = path40.join(dataRoot, "engine-pilot", "grades");
|
|
23277
23456
|
const out = [];
|
|
23278
|
-
for (const lens of (await
|
|
23279
|
-
const p =
|
|
23457
|
+
for (const lens of (await fs34.readdir(gradesDir).catch(() => [])).sort()) {
|
|
23458
|
+
const p = path40.join(gradesDir, lens, "_person.json");
|
|
23280
23459
|
if (existsSync6(p)) out.push(p);
|
|
23281
23460
|
}
|
|
23282
|
-
out.push(
|
|
23461
|
+
out.push(path40.join(dataRoot, "engine-pilot", "public-report.json"));
|
|
23283
23462
|
return out;
|
|
23284
23463
|
}
|
|
23285
23464
|
function runStage2(repoRoot, st, env, onLine) {
|
|
@@ -23329,7 +23508,7 @@ async function runChatPipeline(o) {
|
|
|
23329
23508
|
};
|
|
23330
23509
|
if (!o.overnight) env.POLYMATH_RESILIENT_NO_WINDOW = "1";
|
|
23331
23510
|
if (!/max-old-space-size/.test(env.NODE_OPTIONS ?? "")) {
|
|
23332
|
-
const headroomMb = Math.min(12288, Math.max(4096, Math.round(
|
|
23511
|
+
const headroomMb = Math.min(12288, Math.max(4096, Math.round(os10.totalmem() / 2 ** 20 * 0.6)));
|
|
23333
23512
|
env.NODE_OPTIONS = `${env.NODE_OPTIONS ?? ""} --max-old-space-size=${headroomMb}`.trim();
|
|
23334
23513
|
}
|
|
23335
23514
|
const failed = [];
|
|
@@ -23348,12 +23527,12 @@ async function runChatPipeline(o) {
|
|
|
23348
23527
|
supabaseUrl: central.supabaseUrl,
|
|
23349
23528
|
supabaseAnonKey: central.supabaseAnonKey,
|
|
23350
23529
|
artifacts: () => finalChatArtifacts(dataRoot),
|
|
23351
|
-
refPath:
|
|
23530
|
+
refPath: path40.join(dataRoot, "report-run.json")
|
|
23352
23531
|
}
|
|
23353
23532
|
);
|
|
23354
23533
|
let idx = 0;
|
|
23355
23534
|
for (const f of ingestable) {
|
|
23356
|
-
const st = { script: "ingest-export.mts", label: `Ingest ${f.kind} \u2014 ${
|
|
23535
|
+
const st = { script: "ingest-export.mts", label: `Ingest ${f.kind} \u2014 ${path40.basename(f.path)}`, llm: false, args: [f.kind, f.path] };
|
|
23357
23536
|
o.onStage?.(++idx, total, st.label, false);
|
|
23358
23537
|
const stStart = Date.now();
|
|
23359
23538
|
let ok = true;
|
|
@@ -23370,7 +23549,7 @@ async function runChatPipeline(o) {
|
|
|
23370
23549
|
}
|
|
23371
23550
|
const minNewDocs = Number(process.env.POLYMATH_MIN_NEW_DOCS ?? 10);
|
|
23372
23551
|
const signalDocs = async () => {
|
|
23373
|
-
const t = await
|
|
23552
|
+
const t = await fs34.readFile(path40.join(dataRoot, "signals", "index.jsonl"), "utf8").catch(() => "");
|
|
23374
23553
|
return t ? t.split("\n").filter(Boolean).length : 0;
|
|
23375
23554
|
};
|
|
23376
23555
|
const docsBeforeTagger = await signalDocs();
|
|
@@ -23392,11 +23571,11 @@ async function runChatPipeline(o) {
|
|
|
23392
23571
|
failed.push({ label: st.label, script: st.script, error });
|
|
23393
23572
|
o.onLine?.(`\u26A0\uFE0F stage FAILED (continuing): ${st.label} \u2014 ${error}`);
|
|
23394
23573
|
}
|
|
23395
|
-
const sha = st.out ? await fileSha(
|
|
23574
|
+
const sha = st.out ? await fileSha(path40.join(dataRoot, st.out)) : null;
|
|
23396
23575
|
log.event(st.script.replace(/\.mts$/, ""), { ok, ms: Date.now() - stStart, ...sha ? { sha } : {} });
|
|
23397
23576
|
if (st.script === "run-tagger.mts" && ok && minNewDocs > 0) {
|
|
23398
23577
|
const newDocs = await signalDocs() - docsBeforeTagger;
|
|
23399
|
-
const report = await
|
|
23578
|
+
const report = await fs34.readFile(path40.join(dataRoot, "engine-pilot", "public-report.json"), "utf8").then((s) => JSON.parse(s)).catch(() => null);
|
|
23400
23579
|
if (report?.headline && (report.spikes?.length ?? 0) > 0 && newDocs < minNewDocs) {
|
|
23401
23580
|
upToDate = true;
|
|
23402
23581
|
o.onUpToDate?.();
|
|
@@ -23419,11 +23598,79 @@ var init_chatPipeline = __esm({
|
|
|
23419
23598
|
init_central();
|
|
23420
23599
|
init_dataHome();
|
|
23421
23600
|
init_runLog();
|
|
23422
|
-
MODULE_DIR3 =
|
|
23601
|
+
MODULE_DIR3 = path40.dirname(fileURLToPath4(import.meta.url));
|
|
23423
23602
|
INGESTABLE_KINDS = ["chatgpt", "claude", "notion", "obsidian"];
|
|
23424
23603
|
}
|
|
23425
23604
|
});
|
|
23426
23605
|
|
|
23606
|
+
// src/ttyGuard.ts
|
|
23607
|
+
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
23608
|
+
function stty(...args) {
|
|
23609
|
+
try {
|
|
23610
|
+
const r = spawnSync3("stty", args, { stdio: ["inherit", "pipe", "ignore"] });
|
|
23611
|
+
return r.status === 0 ? String(r.stdout ?? "").trim() : null;
|
|
23612
|
+
} catch {
|
|
23613
|
+
return null;
|
|
23614
|
+
}
|
|
23615
|
+
}
|
|
23616
|
+
function guardTty() {
|
|
23617
|
+
if (guarded || process.platform === "win32" || !process.stdin.isTTY) return;
|
|
23618
|
+
guarded = true;
|
|
23619
|
+
stty("isig", "icrnl");
|
|
23620
|
+
const saved = stty("-g");
|
|
23621
|
+
if (saved) process.on("exit", () => void stty(saved));
|
|
23622
|
+
}
|
|
23623
|
+
function attachPromptAbort(rl) {
|
|
23624
|
+
rl.on("SIGINT", () => {
|
|
23625
|
+
process.stderr.write("^C\n");
|
|
23626
|
+
rl.close();
|
|
23627
|
+
process.exit(130);
|
|
23628
|
+
});
|
|
23629
|
+
}
|
|
23630
|
+
function watchCtrlC(onCtrlC) {
|
|
23631
|
+
const stdin = process.stdin;
|
|
23632
|
+
if (process.platform === "win32" || !stdin.isTTY || typeof stdin.setRawMode !== "function") {
|
|
23633
|
+
return () => {
|
|
23634
|
+
};
|
|
23635
|
+
}
|
|
23636
|
+
const onData = (b) => {
|
|
23637
|
+
for (const byte of b) {
|
|
23638
|
+
if (byte === 3 || byte === 28) {
|
|
23639
|
+
onCtrlC();
|
|
23640
|
+
return;
|
|
23641
|
+
}
|
|
23642
|
+
if (byte === 26) {
|
|
23643
|
+
stdin.setRawMode(false);
|
|
23644
|
+
process.once("SIGCONT", () => {
|
|
23645
|
+
try {
|
|
23646
|
+
stdin.setRawMode(true);
|
|
23647
|
+
} catch {
|
|
23648
|
+
}
|
|
23649
|
+
});
|
|
23650
|
+
process.kill(process.pid, "SIGTSTP");
|
|
23651
|
+
}
|
|
23652
|
+
}
|
|
23653
|
+
};
|
|
23654
|
+
stdin.setRawMode(true);
|
|
23655
|
+
stdin.resume();
|
|
23656
|
+
stdin.on("data", onData);
|
|
23657
|
+
return () => {
|
|
23658
|
+
stdin.off("data", onData);
|
|
23659
|
+
try {
|
|
23660
|
+
stdin.setRawMode(false);
|
|
23661
|
+
} catch {
|
|
23662
|
+
}
|
|
23663
|
+
stdin.pause();
|
|
23664
|
+
};
|
|
23665
|
+
}
|
|
23666
|
+
var guarded;
|
|
23667
|
+
var init_ttyGuard = __esm({
|
|
23668
|
+
"src/ttyGuard.ts"() {
|
|
23669
|
+
"use strict";
|
|
23670
|
+
guarded = false;
|
|
23671
|
+
}
|
|
23672
|
+
});
|
|
23673
|
+
|
|
23427
23674
|
// src/notify.ts
|
|
23428
23675
|
import { spawn as spawn9 } from "node:child_process";
|
|
23429
23676
|
function systemNotify(title, body) {
|
|
@@ -23561,10 +23808,10 @@ __export(exportScan_exports, {
|
|
|
23561
23808
|
scanForExports: () => scanForExports,
|
|
23562
23809
|
scanForObsidianVaults: () => scanForObsidianVaults
|
|
23563
23810
|
});
|
|
23564
|
-
import { promises as
|
|
23811
|
+
import { promises as fs35 } from "fs";
|
|
23565
23812
|
import { execFile as execFile2 } from "child_process";
|
|
23566
23813
|
import { promisify as promisify2 } from "util";
|
|
23567
|
-
import
|
|
23814
|
+
import path41 from "path";
|
|
23568
23815
|
function latestPerSource(found) {
|
|
23569
23816
|
const newest = /* @__PURE__ */ new Map();
|
|
23570
23817
|
const keyOf = (f) => f.kind === "obsidian" || f.kind === "unknown" ? null : `${f.kind}:${f.account ?? "(unknown-account)"}`;
|
|
@@ -23634,7 +23881,7 @@ async function identifyZip(zip, stat) {
|
|
|
23634
23881
|
note: ""
|
|
23635
23882
|
};
|
|
23636
23883
|
if (!entries) {
|
|
23637
|
-
const n =
|
|
23884
|
+
const n = path41.basename(zip).toLowerCase();
|
|
23638
23885
|
if (n.includes("chatgpt") || n.includes("openai")) {
|
|
23639
23886
|
found.kind = "chatgpt";
|
|
23640
23887
|
found.note = "matched by filename only (no unzip binary to verify)";
|
|
@@ -23654,7 +23901,7 @@ async function identifyZip(zip, stat) {
|
|
|
23654
23901
|
}
|
|
23655
23902
|
let { kind, note } = classify2(entries);
|
|
23656
23903
|
if (kind === "unknown") {
|
|
23657
|
-
const nb =
|
|
23904
|
+
const nb = path41.basename(zip).toLowerCase();
|
|
23658
23905
|
const nameHint = nb.includes("notion") || /(^|[-_ ])export-/.test(nb);
|
|
23659
23906
|
const inner = entries.filter((e) => e.toLowerCase().endsWith(".zip"));
|
|
23660
23907
|
const partZips = inner.some((e) => /export[^/]*part[-_ ]?\d+\.zip$/i.test(e.toLowerCase()));
|
|
@@ -23683,17 +23930,17 @@ async function identifyZip(zip, stat) {
|
|
|
23683
23930
|
async function identifyDir(dir) {
|
|
23684
23931
|
let names;
|
|
23685
23932
|
try {
|
|
23686
|
-
names = await
|
|
23933
|
+
names = await fs35.readdir(dir);
|
|
23687
23934
|
} catch {
|
|
23688
23935
|
return null;
|
|
23689
23936
|
}
|
|
23690
23937
|
const { kind, note } = classify2(names);
|
|
23691
23938
|
if (kind === "unknown") return null;
|
|
23692
|
-
const st = await
|
|
23939
|
+
const st = await fs35.stat(dir);
|
|
23693
23940
|
const found = { kind, path: dir, account: null, sizeMB: 0, modified: st.mtime.toISOString().slice(0, 10), note };
|
|
23694
23941
|
const read = async (n) => {
|
|
23695
23942
|
try {
|
|
23696
|
-
return await
|
|
23943
|
+
return await fs35.readFile(path41.join(dir, n), "utf8");
|
|
23697
23944
|
} catch {
|
|
23698
23945
|
return null;
|
|
23699
23946
|
}
|
|
@@ -23706,7 +23953,7 @@ async function identifyPath(p) {
|
|
|
23706
23953
|
if (/\/\.data\//.test(p)) return null;
|
|
23707
23954
|
let st;
|
|
23708
23955
|
try {
|
|
23709
|
-
st = await
|
|
23956
|
+
st = await fs35.stat(p);
|
|
23710
23957
|
} catch {
|
|
23711
23958
|
return null;
|
|
23712
23959
|
}
|
|
@@ -23768,14 +24015,14 @@ async function countMdNotes(root, cap = 2e3) {
|
|
|
23768
24015
|
if (n >= cap || depth > 6) return;
|
|
23769
24016
|
let entries;
|
|
23770
24017
|
try {
|
|
23771
|
-
entries = await
|
|
24018
|
+
entries = await fs35.readdir(d, { withFileTypes: true });
|
|
23772
24019
|
} catch {
|
|
23773
24020
|
return;
|
|
23774
24021
|
}
|
|
23775
24022
|
for (const e of entries) {
|
|
23776
24023
|
if (n >= cap) return;
|
|
23777
24024
|
if (e.name.startsWith(".")) continue;
|
|
23778
|
-
if (e.isDirectory()) await walk(
|
|
24025
|
+
if (e.isDirectory()) await walk(path41.join(d, e.name), depth + 1);
|
|
23779
24026
|
else if (e.name.endsWith(".md")) n++;
|
|
23780
24027
|
}
|
|
23781
24028
|
}
|
|
@@ -23784,12 +24031,12 @@ async function countMdNotes(root, cap = 2e3) {
|
|
|
23784
24031
|
}
|
|
23785
24032
|
async function identifyObsidianVault(dir) {
|
|
23786
24033
|
try {
|
|
23787
|
-
const st = await
|
|
24034
|
+
const st = await fs35.stat(path41.join(dir, ".obsidian"));
|
|
23788
24035
|
if (!st.isDirectory()) return null;
|
|
23789
24036
|
} catch {
|
|
23790
24037
|
return null;
|
|
23791
24038
|
}
|
|
23792
|
-
const rootSt = await
|
|
24039
|
+
const rootSt = await fs35.stat(dir).catch(() => null);
|
|
23793
24040
|
if (!rootSt) return null;
|
|
23794
24041
|
const notes = await countMdNotes(dir);
|
|
23795
24042
|
return {
|
|
@@ -23811,21 +24058,21 @@ async function scanForObsidianVaults(home) {
|
|
|
23811
24058
|
}
|
|
23812
24059
|
};
|
|
23813
24060
|
const roots = [
|
|
23814
|
-
|
|
23815
|
-
|
|
23816
|
-
|
|
24061
|
+
path41.join(home, "Library", "Mobile Documents", "iCloud~md~obsidian", "Documents"),
|
|
24062
|
+
path41.join(home, "Documents"),
|
|
24063
|
+
path41.join(home, "Desktop"),
|
|
23817
24064
|
home
|
|
23818
24065
|
];
|
|
23819
24066
|
for (const root of roots) {
|
|
23820
24067
|
let names = [];
|
|
23821
24068
|
try {
|
|
23822
|
-
names = await
|
|
24069
|
+
names = await fs35.readdir(root);
|
|
23823
24070
|
} catch {
|
|
23824
24071
|
continue;
|
|
23825
24072
|
}
|
|
23826
24073
|
for (const name17 of names) {
|
|
23827
24074
|
if (name17.startsWith(".")) continue;
|
|
23828
|
-
add(await identifyObsidianVault(
|
|
24075
|
+
add(await identifyObsidianVault(path41.join(root, name17)));
|
|
23829
24076
|
}
|
|
23830
24077
|
}
|
|
23831
24078
|
return out;
|
|
@@ -23834,16 +24081,16 @@ async function scanForExports(root) {
|
|
|
23834
24081
|
const out = [];
|
|
23835
24082
|
let names;
|
|
23836
24083
|
try {
|
|
23837
|
-
names = await
|
|
24084
|
+
names = await fs35.readdir(root);
|
|
23838
24085
|
} catch {
|
|
23839
24086
|
return out;
|
|
23840
24087
|
}
|
|
23841
24088
|
for (const name17 of names) {
|
|
23842
24089
|
if (name17.startsWith(".")) continue;
|
|
23843
|
-
const p =
|
|
24090
|
+
const p = path41.join(root, name17);
|
|
23844
24091
|
let st;
|
|
23845
24092
|
try {
|
|
23846
|
-
st = await
|
|
24093
|
+
st = await fs35.stat(p);
|
|
23847
24094
|
} catch {
|
|
23848
24095
|
continue;
|
|
23849
24096
|
}
|
|
@@ -23971,16 +24218,16 @@ __export(reminderState_exports, {
|
|
|
23971
24218
|
recordQueued: () => recordQueued,
|
|
23972
24219
|
trackedLinkUrl: () => trackedLinkUrl
|
|
23973
24220
|
});
|
|
23974
|
-
import { promises as
|
|
23975
|
-
import
|
|
24221
|
+
import { promises as fs36 } from "node:fs";
|
|
24222
|
+
import path42 from "node:path";
|
|
23976
24223
|
import crypto4 from "node:crypto";
|
|
23977
24224
|
function newToken() {
|
|
23978
24225
|
return crypto4.randomBytes(12).toString("base64url");
|
|
23979
24226
|
}
|
|
23980
24227
|
async function ensureReminderState(dataDir) {
|
|
23981
|
-
const file2 =
|
|
24228
|
+
const file2 = path42.join(dataDir, FILE);
|
|
23982
24229
|
try {
|
|
23983
|
-
const s = JSON.parse(await
|
|
24230
|
+
const s = JSON.parse(await fs36.readFile(file2, "utf8"));
|
|
23984
24231
|
if (typeof s.token === "string" && s.token.length >= 8) {
|
|
23985
24232
|
return {
|
|
23986
24233
|
token: s.token,
|
|
@@ -23994,8 +24241,8 @@ async function ensureReminderState(dataDir) {
|
|
|
23994
24241
|
}
|
|
23995
24242
|
const state = { token: newToken(), queuedKinds: [] };
|
|
23996
24243
|
try {
|
|
23997
|
-
await
|
|
23998
|
-
await
|
|
24244
|
+
await fs36.mkdir(dataDir, { recursive: true });
|
|
24245
|
+
await fs36.writeFile(file2, JSON.stringify(state));
|
|
23999
24246
|
} catch {
|
|
24000
24247
|
}
|
|
24001
24248
|
return state;
|
|
@@ -24010,8 +24257,8 @@ async function recordQueued(dataDir, state, kinds) {
|
|
|
24010
24257
|
queuedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
24011
24258
|
};
|
|
24012
24259
|
try {
|
|
24013
|
-
await
|
|
24014
|
-
await
|
|
24260
|
+
await fs36.mkdir(dataDir, { recursive: true });
|
|
24261
|
+
await fs36.writeFile(path42.join(dataDir, FILE), JSON.stringify(next));
|
|
24015
24262
|
} catch {
|
|
24016
24263
|
}
|
|
24017
24264
|
return next;
|
|
@@ -24024,8 +24271,8 @@ async function recordOffered(dataDir, state, kinds) {
|
|
|
24024
24271
|
offeredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
24025
24272
|
};
|
|
24026
24273
|
try {
|
|
24027
|
-
await
|
|
24028
|
-
await
|
|
24274
|
+
await fs36.mkdir(dataDir, { recursive: true });
|
|
24275
|
+
await fs36.writeFile(path42.join(dataDir, FILE), JSON.stringify(next));
|
|
24029
24276
|
} catch {
|
|
24030
24277
|
}
|
|
24031
24278
|
return next;
|
|
@@ -24042,151 +24289,6 @@ var init_reminderState = __esm({
|
|
|
24042
24289
|
}
|
|
24043
24290
|
});
|
|
24044
24291
|
|
|
24045
|
-
// src/plan.ts
|
|
24046
|
-
var plan_exports = {};
|
|
24047
|
-
__export(plan_exports, {
|
|
24048
|
-
UNSUPPORTED_FULL_TIERS: () => UNSUPPORTED_FULL_TIERS,
|
|
24049
|
-
detectCodexPlan: () => detectCodexPlan,
|
|
24050
|
-
detectPlan: () => detectPlan,
|
|
24051
|
-
estimateLaneCosts: () => estimateLaneCosts,
|
|
24052
|
-
remainingFractions: () => remainingFractions,
|
|
24053
|
-
scheduleLanes: () => scheduleLanes,
|
|
24054
|
-
supportsFullAnalysis: () => supportsFullAnalysis,
|
|
24055
|
-
tierFromChatgptPlan: () => tierFromChatgptPlan,
|
|
24056
|
-
tierFromStrings: () => tierFromStrings
|
|
24057
|
-
});
|
|
24058
|
-
import { promises as fs36 } from "fs";
|
|
24059
|
-
import os10 from "os";
|
|
24060
|
-
import path42 from "path";
|
|
24061
|
-
function supportsFullAnalysis(tier) {
|
|
24062
|
-
if (process.env.POLYMATH_FORCE_FULL === "1") return true;
|
|
24063
|
-
return !UNSUPPORTED_FULL_TIERS.includes(tier);
|
|
24064
|
-
}
|
|
24065
|
-
function tierFromStrings(...hints) {
|
|
24066
|
-
for (const h of hints) {
|
|
24067
|
-
if (!h) continue;
|
|
24068
|
-
const s = h.toLowerCase();
|
|
24069
|
-
if (s.includes("max_20x") || s.includes("max20x")) return "max_20x";
|
|
24070
|
-
if (s.includes("max_5x") || s.includes("max5x")) return "max_5x";
|
|
24071
|
-
if (s.includes("pro")) return "pro";
|
|
24072
|
-
if (s.includes("claude_max")) return "max_5x";
|
|
24073
|
-
}
|
|
24074
|
-
return "unknown";
|
|
24075
|
-
}
|
|
24076
|
-
function tierFromChatgptPlan(planType) {
|
|
24077
|
-
const s = (planType ?? "").toLowerCase();
|
|
24078
|
-
if (s === "pro") return "gpt_pro";
|
|
24079
|
-
if (s === "plus") return "gpt_plus";
|
|
24080
|
-
if (s === "team" || s === "enterprise" || s === "business") return "gpt_team";
|
|
24081
|
-
if (s === "free") return "gpt_free";
|
|
24082
|
-
return "unknown";
|
|
24083
|
-
}
|
|
24084
|
-
async function detectCodexPlan(home = os10.homedir()) {
|
|
24085
|
-
try {
|
|
24086
|
-
const raw = JSON.parse(await fs36.readFile(path42.join(home, ".codex", "auth.json"), "utf8"));
|
|
24087
|
-
for (const tok of [raw.tokens?.id_token, raw.tokens?.access_token]) {
|
|
24088
|
-
if (!tok) continue;
|
|
24089
|
-
try {
|
|
24090
|
-
const payload = JSON.parse(Buffer.from(tok.split(".")[1], "base64url").toString("utf8"));
|
|
24091
|
-
const t = tierFromChatgptPlan(payload["https://api.openai.com/auth"]?.chatgpt_plan_type);
|
|
24092
|
-
if (t !== "unknown") return t;
|
|
24093
|
-
} catch {
|
|
24094
|
-
}
|
|
24095
|
-
}
|
|
24096
|
-
} catch {
|
|
24097
|
-
}
|
|
24098
|
-
return "unknown";
|
|
24099
|
-
}
|
|
24100
|
-
async function detectPlan(home = os10.homedir()) {
|
|
24101
|
-
let tier = "unknown";
|
|
24102
|
-
try {
|
|
24103
|
-
const raw = JSON.parse(await fs36.readFile(path42.join(home, ".claude.json"), "utf8"));
|
|
24104
|
-
const oa = raw.oauthAccount ?? {};
|
|
24105
|
-
tier = tierFromStrings(oa.userRateLimitTier, oa.organizationRateLimitTier, oa.organizationType);
|
|
24106
|
-
} catch {
|
|
24107
|
-
}
|
|
24108
|
-
if (tier === "unknown") tier = await detectCodexPlan(home);
|
|
24109
|
-
return { tier, label: LABEL[tier], windowUsd: WINDOW_USD[tier] };
|
|
24110
|
-
}
|
|
24111
|
-
function estimateLaneCosts(input) {
|
|
24112
|
-
const codingUsd = Math.max(5, Math.min(32, Math.round(input.agentLogFiles * 9e-4)));
|
|
24113
|
-
const chatUsd = input.chatIncluded ? Math.round(40 + input.exportTotalMB * 0.8) : 0;
|
|
24114
|
-
return { codingUsd, chatUsd };
|
|
24115
|
-
}
|
|
24116
|
-
async function remainingFractions(dataRoot, agentLogFiles) {
|
|
24117
|
-
const clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, v));
|
|
24118
|
-
let coding = 1;
|
|
24119
|
-
try {
|
|
24120
|
-
const graded = (await fs36.readdir(path42.join(dataRoot, "coding", "grades"))).filter((f) => f.endsWith(".json")).length;
|
|
24121
|
-
const expected = Math.max(1, agentLogFiles * 56e-4);
|
|
24122
|
-
coding = clamp(1 - graded / expected, 0.05, 1);
|
|
24123
|
-
} catch {
|
|
24124
|
-
}
|
|
24125
|
-
let chatDone = 0;
|
|
24126
|
-
try {
|
|
24127
|
-
const st = await fs36.stat(path42.join(dataRoot, "signals", "index.jsonl"));
|
|
24128
|
-
if (st.size > 0) chatDone += 0.3;
|
|
24129
|
-
} catch {
|
|
24130
|
-
}
|
|
24131
|
-
try {
|
|
24132
|
-
const lenses = await fs36.readdir(path42.join(dataRoot, "engine-pilot", "grades"));
|
|
24133
|
-
let withPerson = 0;
|
|
24134
|
-
for (const l of lenses) {
|
|
24135
|
-
try {
|
|
24136
|
-
await fs36.stat(path42.join(dataRoot, "engine-pilot", "grades", l, "_person.json"));
|
|
24137
|
-
withPerson++;
|
|
24138
|
-
} catch {
|
|
24139
|
-
}
|
|
24140
|
-
}
|
|
24141
|
-
chatDone += 0.6 * Math.min(1, withPerson / 5);
|
|
24142
|
-
} catch {
|
|
24143
|
-
}
|
|
24144
|
-
return { coding, chat: clamp(1 - chatDone, 0.1, 1) };
|
|
24145
|
-
}
|
|
24146
|
-
function scheduleLanes(plan, est) {
|
|
24147
|
-
const chat = est.chatUsd === 0 || est.chatUsd <= plan.windowUsd * 0.9 ? "now" : "overnight";
|
|
24148
|
-
return {
|
|
24149
|
-
coding: "now",
|
|
24150
|
-
chat,
|
|
24151
|
-
// No plan name here — the schedule header names the plan once, and
|
|
24152
|
-
// repeating it doubled the clumsy unknown-plan label (2026-07-22
|
|
24153
|
-
// walkthrough). Phrased for the two-column "Proposed schedule" rows:
|
|
24154
|
-
// "<lane> <verdict> — <reason>".
|
|
24155
|
-
codingReason: `runs now \u2014 the report link appears right away and fills in as it goes`,
|
|
24156
|
-
chatReason: est.chatUsd === 0 ? "not planned \u2014 no chat sources included" : chat === "overnight" ? `starts at 2:00 am tonight \u2014 a chat corpus this size is an overnight job; it runs while you sleep` : `runs now, alongside coding`
|
|
24157
|
-
};
|
|
24158
|
-
}
|
|
24159
|
-
var UNSUPPORTED_FULL_TIERS, WINDOW_USD, LABEL;
|
|
24160
|
-
var init_plan = __esm({
|
|
24161
|
-
"src/plan.ts"() {
|
|
24162
|
-
"use strict";
|
|
24163
|
-
UNSUPPORTED_FULL_TIERS = ["pro", "gpt_plus", "gpt_free"];
|
|
24164
|
-
WINDOW_USD = {
|
|
24165
|
-
max_20x: 300,
|
|
24166
|
-
max_5x: 75,
|
|
24167
|
-
pro: 15,
|
|
24168
|
-
// ChatGPT tiers, mapped to rough Claude-window parity by monthly price
|
|
24169
|
-
// ($200 Pro ≈ Max 20x; $20 Plus ≈ Claude Pro; Team between; free ≈ nothing).
|
|
24170
|
-
gpt_pro: 300,
|
|
24171
|
-
gpt_plus: 20,
|
|
24172
|
-
gpt_team: 50,
|
|
24173
|
-
gpt_free: 5,
|
|
24174
|
-
unknown: 15
|
|
24175
|
-
// conservative: schedule like Pro when we can't tell
|
|
24176
|
-
};
|
|
24177
|
-
LABEL = {
|
|
24178
|
-
max_20x: "Claude Max 20x",
|
|
24179
|
-
max_5x: "Claude Max 5x",
|
|
24180
|
-
pro: "Claude Pro",
|
|
24181
|
-
gpt_pro: "ChatGPT Pro (Codex)",
|
|
24182
|
-
gpt_plus: "ChatGPT Plus (Codex)",
|
|
24183
|
-
gpt_team: "ChatGPT Team (Codex)",
|
|
24184
|
-
gpt_free: "ChatGPT Free (Codex)",
|
|
24185
|
-
unknown: "an undetected plan (scheduling conservatively)"
|
|
24186
|
-
};
|
|
24187
|
-
}
|
|
24188
|
-
});
|
|
24189
|
-
|
|
24190
24292
|
// src/wizard.ts
|
|
24191
24293
|
var wizard_exports = {};
|
|
24192
24294
|
__export(wizard_exports, {
|
|
@@ -24211,7 +24313,7 @@ __export(wizard_exports, {
|
|
|
24211
24313
|
import { promises as fs37 } from "fs";
|
|
24212
24314
|
import os11 from "os";
|
|
24213
24315
|
import path43 from "path";
|
|
24214
|
-
import * as
|
|
24316
|
+
import * as readline2 from "node:readline/promises";
|
|
24215
24317
|
async function scanJsonlDir(label, dir, maxDepth = 1) {
|
|
24216
24318
|
let files = 0;
|
|
24217
24319
|
let newest = 0;
|
|
@@ -24324,7 +24426,8 @@ function describeExport(f, i, included, hadPrevious) {
|
|
|
24324
24426
|
${dim(path43.basename(f.path))} ${dim(`(${f.note})`)}`;
|
|
24325
24427
|
}
|
|
24326
24428
|
async function runWizard() {
|
|
24327
|
-
const rl =
|
|
24429
|
+
const rl = readline2.createInterface({ input: process.stdin, output: process.stderr });
|
|
24430
|
+
attachPromptAbort(rl);
|
|
24328
24431
|
const say = (s = "") => console.error(s);
|
|
24329
24432
|
const lineQueue = [];
|
|
24330
24433
|
let waiting = null;
|
|
@@ -24454,22 +24557,19 @@ async function runWizard() {
|
|
|
24454
24557
|
{
|
|
24455
24558
|
const { looksLikeEmail: looksLikeEmail2, recordContact: recordContact2 } = await Promise.resolve().then(() => (init_reminderEmail(), reminderEmail_exports));
|
|
24456
24559
|
say();
|
|
24457
|
-
|
|
24458
|
-
|
|
24459
|
-
|
|
24460
|
-
|
|
24461
|
-
|
|
24462
|
-
|
|
24463
|
-
|
|
24464
|
-
|
|
24465
|
-
await fs37.writeFile(path43.join(dataDir, "notify-email.json"), JSON.stringify({ email: e }));
|
|
24466
|
-
} catch {
|
|
24467
|
-
}
|
|
24468
|
-
await recordContact2(e, "wizard", reminderState.token).catch(() => false);
|
|
24469
|
-
say(` ${green("\u2713")} Got it, we'll keep you posted at ${bold(e)}.`);
|
|
24470
|
-
} else if (e) {
|
|
24471
|
-
say(dim(` "${e}" doesn't look like an email \u2014 skipping.`));
|
|
24560
|
+
const e = (await ask(notifyEmail ? ` Your email ${dim(`(currently ${notifyEmail} \u2014 Enter if this is correct, or type a new one)`)}: ` : ` Your email ${dim("(recommended \u2014 we'll send your report link and occasional Polymath updates, and can nudge you when an export arrives; Enter to skip)")}: `)).trim();
|
|
24561
|
+
if (e && looksLikeEmail2(e)) {
|
|
24562
|
+
const correcting = !!notifyEmail;
|
|
24563
|
+
notifyEmail = e;
|
|
24564
|
+
try {
|
|
24565
|
+
await fs37.mkdir(dataDir, { recursive: true });
|
|
24566
|
+
await fs37.writeFile(path43.join(dataDir, "notify-email.json"), JSON.stringify({ email: e }));
|
|
24567
|
+
} catch {
|
|
24472
24568
|
}
|
|
24569
|
+
await recordContact2(e, correcting ? "wizard-correction" : "wizard", reminderState.token).catch(() => false);
|
|
24570
|
+
say(` ${green("\u2713")} Got it, we'll keep you posted at ${bold(e)}.`);
|
|
24571
|
+
} else if (e) {
|
|
24572
|
+
say(dim(notifyEmail ? ` "${e}" doesn't look like an email \u2014 keeping ${notifyEmail}.` : ` "${e}" doesn't look like an email \u2014 skipping.`));
|
|
24473
24573
|
}
|
|
24474
24574
|
}
|
|
24475
24575
|
const tracked = { token: reminderState.token };
|
|
@@ -24582,12 +24682,52 @@ async function runWizard() {
|
|
|
24582
24682
|
say(` ${bold("Proposed schedule")} \u2014 sized to your plan (${plan.label}):`);
|
|
24583
24683
|
say();
|
|
24584
24684
|
say(` ${bold("Your analysis")} runs now \u2014 everything measured from your logs: words/day, flow state, focus, projects, parallelism`);
|
|
24585
|
-
|
|
24685
|
+
const planPhrase = plan.tier === "gpt_plus" ? "the $20 ChatGPT Plus plan" : "the free ChatGPT plan";
|
|
24686
|
+
say(` ${bold("AI sections")} not supported on ${planPhrase} just yet \u2014 coming soon! Only the AI-graded sections (judgement, agency, taste, growth) won't be visible`);
|
|
24586
24687
|
say();
|
|
24587
24688
|
await ask(` Press Enter to run your analysis`).catch(() => "");
|
|
24588
24689
|
say(dim(" On it. The report link appears right away.\n"));
|
|
24589
24690
|
return { cmd: "serve", grade: false, overnight: false, chatOvernight: false, open: true };
|
|
24590
24691
|
}
|
|
24692
|
+
if (plan.tier === "pro") {
|
|
24693
|
+
say(` ${bold("Proposed schedule")} \u2014 sized to your plan (${plan.label}):`);
|
|
24694
|
+
if (resumed) say(dim(" (an earlier run already processed most of this \u2014 only what's new is scheduled; nothing done is redone)"));
|
|
24695
|
+
say();
|
|
24696
|
+
say(` ${bold("Deterministic sections")} run now \u2014 everything measured from your logs: words/day, flow state, focus, projects, parallelism`);
|
|
24697
|
+
say();
|
|
24698
|
+
say(` ${bold("AI sections")} run overnight, starting 1:00 am \u2014 grades, judgement, agency, taste, growth`);
|
|
24699
|
+
say();
|
|
24700
|
+
say(` Why overnight: a full AI run costs about two of your plan's 5-hour usage windows.`);
|
|
24701
|
+
say(` Running it at night spends windows you're asleep for \u2014 it hits the limit around`);
|
|
24702
|
+
say(` halfway, pauses, and resumes on its own when the window resets (~6:00 am).`);
|
|
24703
|
+
say();
|
|
24704
|
+
say(` ${bold("1) Run on this schedule \u2014 RECOMMENDED")}`);
|
|
24705
|
+
say(` \u2022 keep your laptop plugged in`);
|
|
24706
|
+
say(` \u2022 keep the lid open \u2014 closed means sleep, and the run stalls until morning`);
|
|
24707
|
+
say(` ${bold("2)")} Run the AI sections now instead \u2014 you'll likely hit your plan's usage limit partway;`);
|
|
24708
|
+
say(` the run pauses and resumes by itself when the limit resets (~5h), and the report`);
|
|
24709
|
+
say(` link works the whole time, filling in as stages finish`);
|
|
24710
|
+
say();
|
|
24711
|
+
const proDepth = await ask(` Choose ${dim("[1/2, default 1]")}: `) || "1";
|
|
24712
|
+
const proOvernight = proDepth !== "2";
|
|
24713
|
+
if (proOvernight) {
|
|
24714
|
+
if (!process.env.POLYMATH_NIGHTLY_START) process.env.POLYMATH_NIGHTLY_START = "1";
|
|
24715
|
+
say(` ${bold("VERY IMPORTANT for the overnight part:")}`);
|
|
24716
|
+
say(` \u2022 keep your laptop plugged in`);
|
|
24717
|
+
say(` \u2022 keep the lid open \u2014 closed means sleep, and the run stalls until morning`);
|
|
24718
|
+
say(dim(` (the report page shows this too)`));
|
|
24719
|
+
}
|
|
24720
|
+
say(dim(" On it. The report link appears right away and fills in as stages finish \u2014 Ctrl-C anytime.\n"));
|
|
24721
|
+
return {
|
|
24722
|
+
cmd: "serve",
|
|
24723
|
+
grade: true,
|
|
24724
|
+
overnight: proOvernight,
|
|
24725
|
+
// The chat corpus is unbounded (~$390 measured on 450 MB) — on a $15
|
|
24726
|
+
// window it is ALWAYS an overnight job, whatever the coding choice.
|
|
24727
|
+
chatOvernight: est.chatUsd > 0 ? true : proOvernight,
|
|
24728
|
+
open: true
|
|
24729
|
+
};
|
|
24730
|
+
}
|
|
24591
24731
|
const planBit = plan.label.includes("undetected") ? "your corpus (plan undetected \u2014 scheduling conservatively)" : `your plan (${plan.label}) and your corpus`;
|
|
24592
24732
|
say(` ${bold("Proposed schedule")} \u2014 sized to ${planBit}:`);
|
|
24593
24733
|
if (resumed) say(dim(" (an earlier run already processed most of this \u2014 only what's new is scheduled; nothing done is redone)"));
|
|
@@ -24645,7 +24785,8 @@ function newExportsSince(found, m) {
|
|
|
24645
24785
|
}
|
|
24646
24786
|
async function returningUserFlow(dataDir) {
|
|
24647
24787
|
const say = (s = "") => console.error(s);
|
|
24648
|
-
const rl =
|
|
24788
|
+
const rl = readline2.createInterface({ input: process.stdin, output: process.stderr });
|
|
24789
|
+
attachPromptAbort(rl);
|
|
24649
24790
|
try {
|
|
24650
24791
|
say();
|
|
24651
24792
|
say(bold(" What would you like to do?"));
|
|
@@ -24692,17 +24833,18 @@ async function askEmailAndQueueReminder(dataDir, say, ask) {
|
|
|
24692
24833
|
}
|
|
24693
24834
|
const clicked = await fetchClickedKinds2(state.token);
|
|
24694
24835
|
if (!clicked.length) return;
|
|
24695
|
-
|
|
24696
|
-
const e = (await ask(` Leave your email and we'll remind you when your exports should be ready ${dim("(Enter to skip)")}`)).trim();
|
|
24836
|
+
{
|
|
24837
|
+
const e = (await ask(email ? ` Your email ${dim(`(currently ${email} \u2014 Enter if this is correct, or type a new one)`)}: ` : ` Leave your email and we'll remind you when your exports should be ready ${dim("(Enter to skip)")}`)).trim();
|
|
24697
24838
|
if (e && looksLikeEmail2(e)) {
|
|
24839
|
+
const correcting = !!email;
|
|
24698
24840
|
email = e;
|
|
24699
24841
|
await fs37.mkdir(dataDir, { recursive: true }).catch(() => {
|
|
24700
24842
|
});
|
|
24701
24843
|
await fs37.writeFile(path43.join(dataDir, "notify-email.json"), JSON.stringify({ email: e })).catch(() => {
|
|
24702
24844
|
});
|
|
24703
|
-
await recordContact2(e, "add-sources", state.token).catch(() => false);
|
|
24845
|
+
await recordContact2(e, correcting ? "wizard-correction" : "add-sources", state.token).catch(() => false);
|
|
24704
24846
|
} else if (e) {
|
|
24705
|
-
say(dim(` "${e}" doesn't look like an email \u2014 skipping the reminder.`));
|
|
24847
|
+
say(dim(email ? ` "${e}" doesn't look like an email \u2014 keeping ${email}.` : ` "${e}" doesn't look like an email \u2014 skipping the reminder.`));
|
|
24706
24848
|
}
|
|
24707
24849
|
}
|
|
24708
24850
|
if (!email) return;
|
|
@@ -24844,6 +24986,7 @@ var init_wizard = __esm({
|
|
|
24844
24986
|
init_exportScan();
|
|
24845
24987
|
init_manifest();
|
|
24846
24988
|
init_dataHome();
|
|
24989
|
+
init_ttyGuard();
|
|
24847
24990
|
init_raw2();
|
|
24848
24991
|
color = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
24849
24992
|
dim = (s) => color ? `\x1B[2m${s}\x1B[0m` : s;
|
|
@@ -24891,6 +25034,7 @@ function makeMultiBar(out = process.stderr) {
|
|
|
24891
25034
|
return ` ${name17.padEnd(6)} [${"\u2588".repeat(fill)}${"\u2591".repeat(width - fill)}] ${String(Math.round(l.shown * 100)).padStart(3)}%`;
|
|
24892
25035
|
};
|
|
24893
25036
|
const out2 = [];
|
|
25037
|
+
out2.push("");
|
|
24894
25038
|
out2.push("This is a background process. We'll let you know when it's finished.");
|
|
24895
25039
|
out2.push("It may take anywhere from 30 minutes to an hour.");
|
|
24896
25040
|
out2.push("");
|
|
@@ -25068,8 +25212,8 @@ try {
|
|
|
25068
25212
|
import { promises as fs38, existsSync as existsSync7 } from "fs";
|
|
25069
25213
|
import path44 from "path";
|
|
25070
25214
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
25071
|
-
import { spawnSync as
|
|
25072
|
-
import
|
|
25215
|
+
import { spawnSync as spawnSync4 } from "child_process";
|
|
25216
|
+
import readline3 from "readline";
|
|
25073
25217
|
|
|
25074
25218
|
// src/openBrowser.ts
|
|
25075
25219
|
import { spawn } from "child_process";
|
|
@@ -28105,6 +28249,7 @@ init_auth();
|
|
|
28105
28249
|
init_pipeline2();
|
|
28106
28250
|
init_chatPipeline();
|
|
28107
28251
|
init_manifest();
|
|
28252
|
+
init_ttyGuard();
|
|
28108
28253
|
init_profile();
|
|
28109
28254
|
var __dirname2 = path44.dirname(fileURLToPath5(import.meta.url));
|
|
28110
28255
|
var REPO_ROOT = path44.resolve(__dirname2, "..", "..", "..");
|
|
@@ -28256,8 +28401,9 @@ PROJECTS`);
|
|
|
28256
28401
|
log(``);
|
|
28257
28402
|
}
|
|
28258
28403
|
async function askYesNo(q, def = true) {
|
|
28259
|
-
const
|
|
28260
|
-
const rl =
|
|
28404
|
+
const readline4 = await import("node:readline/promises");
|
|
28405
|
+
const rl = readline4.createInterface({ input: process.stdin, output: process.stderr });
|
|
28406
|
+
attachPromptAbort(rl);
|
|
28261
28407
|
try {
|
|
28262
28408
|
for (; ; ) {
|
|
28263
28409
|
const a = (await rl.question(`${q} `)).trim().toLowerCase();
|
|
@@ -28286,6 +28432,7 @@ async function runGrade(opts2, provider, profile) {
|
|
|
28286
28432
|
await provider.criteriaMean(profile.sessions);
|
|
28287
28433
|
}
|
|
28288
28434
|
async function main() {
|
|
28435
|
+
guardTty();
|
|
28289
28436
|
if (process.argv[2] === "remind-exports") {
|
|
28290
28437
|
const { runReminder: runReminder2 } = await Promise.resolve().then(() => (init_remind(), remind_exports));
|
|
28291
28438
|
const argv = process.argv.slice(3);
|
|
@@ -28313,8 +28460,13 @@ async function main() {
|
|
|
28313
28460
|
await printBanner2();
|
|
28314
28461
|
console.error("");
|
|
28315
28462
|
await maybePrintUpdateNotice(opts2);
|
|
28316
|
-
|
|
28317
|
-
|
|
28463
|
+
{
|
|
28464
|
+
const { osc8: osc82 } = await Promise.resolve().then(() => (init_exportLinks(), exportLinks_exports));
|
|
28465
|
+
const boldTty = process.stderr.isTTY && !process.env.NO_COLOR;
|
|
28466
|
+
const b = (t) => boldTty ? `\x1B[1m${t}\x1B[0m` : t;
|
|
28467
|
+
console.error(` ${b("Step 0 \xB7 Want to see some sample reports before you run?")} ${osc82("https://polymathsociety.us/sample", "https://polymathsociety.us/sample")}`);
|
|
28468
|
+
console.error("");
|
|
28469
|
+
}
|
|
28318
28470
|
const prior = process.env.POLYMATH_WIZARD === "1" ? null : await readPriorAnalysis();
|
|
28319
28471
|
if (prior) {
|
|
28320
28472
|
console.error(` Found your finished report \u2014 ${prior.graded} graded sessions, last updated ${prior.when}.`);
|
|
@@ -28769,6 +28921,7 @@ No analysis here yet \u2014 computing the instant deterministic metrics now (fre
|
|
|
28769
28921
|
};
|
|
28770
28922
|
process.on("SIGINT", shutdown(130));
|
|
28771
28923
|
process.on("SIGTERM", shutdown(143));
|
|
28924
|
+
watchCtrlC(() => void shutdown(130)());
|
|
28772
28925
|
return;
|
|
28773
28926
|
}
|
|
28774
28927
|
const profile = await analyze({ codex: opts2.codex, idleGapMin: opts2.idleGapMin, tz: opts2.tz, spanHourMin: opts2.spanHourMin });
|
|
@@ -28805,7 +28958,8 @@ async function promptAutoUpdate(current, latest) {
|
|
|
28805
28958
|
console.error(`
|
|
28806
28959
|
New version available: polymath-society ${current} \u2192 ${latest}`);
|
|
28807
28960
|
const answer = await new Promise((resolve2) => {
|
|
28808
|
-
const rl =
|
|
28961
|
+
const rl = readline3.createInterface({ input: process.stdin, output: process.stderr });
|
|
28962
|
+
attachPromptAbort(rl);
|
|
28809
28963
|
const timer = setTimeout(() => {
|
|
28810
28964
|
rl.close();
|
|
28811
28965
|
resolve2("");
|
|
@@ -28823,7 +28977,7 @@ async function promptAutoUpdate(current, latest) {
|
|
|
28823
28977
|
console.error(`
|
|
28824
28978
|
Updating\u2026
|
|
28825
28979
|
`);
|
|
28826
|
-
const install =
|
|
28980
|
+
const install = spawnSync4("npm", ["install", "-g", "polymath-society@latest"], {
|
|
28827
28981
|
stdio: "inherit",
|
|
28828
28982
|
shell: process.platform === "win32"
|
|
28829
28983
|
});
|
|
@@ -28837,7 +28991,7 @@ async function promptAutoUpdate(current, latest) {
|
|
|
28837
28991
|
console.error(`
|
|
28838
28992
|
Updated to ${latest}. Relaunching\u2026
|
|
28839
28993
|
`);
|
|
28840
|
-
const relaunch =
|
|
28994
|
+
const relaunch = spawnSync4("polymath-society", process.argv.slice(2), {
|
|
28841
28995
|
stdio: "inherit",
|
|
28842
28996
|
shell: process.platform === "win32"
|
|
28843
28997
|
});
|