polymath-society 0.2.19 → 0.2.20
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 +420 -146
- package/dist/index.js +352 -136
- package/dist/pipeline/FOCUS-EXAMPLES.md +127 -0
- package/dist/pipeline/FOCUS-RUBRIC.md +418 -0
- package/dist/pipeline/coding-agglomerate.js +126 -2
- package/dist/pipeline/coding-aggregate.js +136 -0
- package/dist/pipeline/coding-build.js +118 -4
- package/dist/pipeline/coding-coaching.js +173 -14
- package/dist/pipeline/coding-day-digest.js +109 -0
- package/dist/pipeline/coding-delegation.js +189 -17
- package/dist/pipeline/coding-expertise.js +126 -2
- package/dist/pipeline/coding-flow.js +136 -0
- package/dist/pipeline/coding-focus.js +136 -0
- package/dist/pipeline/coding-frontier-detail.js +126 -2
- package/dist/pipeline/coding-gap-dist.js +136 -0
- package/dist/pipeline/coding-gap.js +173 -14
- package/dist/pipeline/coding-grade.js +132 -2
- package/dist/pipeline/coding-nutshell.js +159 -150
- package/dist/pipeline/coding-walkthrough.js +144 -0
- package/dist/web/app.js +9 -10
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -110,6 +110,103 @@ var init_injected = __esm({
|
|
|
110
110
|
}
|
|
111
111
|
});
|
|
112
112
|
|
|
113
|
+
// ../coding-core/dist/codex.js
|
|
114
|
+
function isCodexInjectedUserText(text2) {
|
|
115
|
+
return CODEX_INJECTED_TEXT_RE.test(text2);
|
|
116
|
+
}
|
|
117
|
+
function codexContentText(content) {
|
|
118
|
+
if (typeof content === "string")
|
|
119
|
+
return content;
|
|
120
|
+
if (!Array.isArray(content))
|
|
121
|
+
return "";
|
|
122
|
+
const parts = [];
|
|
123
|
+
for (const item of content) {
|
|
124
|
+
if (typeof item === "string") {
|
|
125
|
+
parts.push(item);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (item && typeof item === "object") {
|
|
129
|
+
const it = item;
|
|
130
|
+
if (it.type === "input_text" || it.type === "output_text" || it.type === "text")
|
|
131
|
+
parts.push(it.text || "");
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return parts.join("\n");
|
|
135
|
+
}
|
|
136
|
+
function sniffCodexRaw(raw) {
|
|
137
|
+
let checked = 0;
|
|
138
|
+
for (const lineRaw of raw.split("\n")) {
|
|
139
|
+
const line = lineRaw.trim();
|
|
140
|
+
if (!line)
|
|
141
|
+
continue;
|
|
142
|
+
if (checked++ >= 5)
|
|
143
|
+
break;
|
|
144
|
+
try {
|
|
145
|
+
const e = JSON.parse(line);
|
|
146
|
+
if (e.type === "session_meta" || e.type === "response_item" || e.type === "turn_context")
|
|
147
|
+
return true;
|
|
148
|
+
if (e.type === "user" || e.type === "assistant" || e.type === "summary" || e.type === "queue-operation")
|
|
149
|
+
return false;
|
|
150
|
+
} catch {
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
function extractCodexEvents(raw) {
|
|
156
|
+
const out = [];
|
|
157
|
+
for (const lineRaw of raw.split("\n")) {
|
|
158
|
+
const line = lineRaw.trim();
|
|
159
|
+
if (!line)
|
|
160
|
+
continue;
|
|
161
|
+
let e;
|
|
162
|
+
try {
|
|
163
|
+
e = JSON.parse(line);
|
|
164
|
+
} catch {
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (e.type !== "response_item")
|
|
168
|
+
continue;
|
|
169
|
+
const p = e.payload ?? {};
|
|
170
|
+
const t = typeof e.timestamp === "string" ? Date.parse(e.timestamp) : NaN;
|
|
171
|
+
const ptype = p.type;
|
|
172
|
+
if (ptype === "message") {
|
|
173
|
+
const role = p.role;
|
|
174
|
+
const text2 = codexContentText(p.content).replace(SYSTEM_REMINDER_RE2, "").trim();
|
|
175
|
+
if (!text2)
|
|
176
|
+
continue;
|
|
177
|
+
if (role === "user") {
|
|
178
|
+
if (isCodexInjectedUserText(text2))
|
|
179
|
+
continue;
|
|
180
|
+
out.push({ kind: "user", t, text: text2 });
|
|
181
|
+
} else if (role === "assistant") {
|
|
182
|
+
out.push({ kind: "assistant", t, text: text2 });
|
|
183
|
+
}
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
if (ptype === "function_call" || ptype === "custom_tool_call" || ptype === "local_shell_call") {
|
|
187
|
+
const name17 = typeof p.name === "string" && p.name ? p.name : ptype === "local_shell_call" ? "shell" : String(ptype);
|
|
188
|
+
const input = typeof p.arguments === "string" ? p.arguments : typeof p.input === "string" ? p.input : "";
|
|
189
|
+
out.push({ kind: "tool", t, name: name17, input });
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
if (ptype === "function_call_output" || ptype === "custom_tool_call_output") {
|
|
193
|
+
const output = typeof p.output === "string" ? p.output : "";
|
|
194
|
+
const m = EXIT_CODE_RE.exec(output.slice(0, 200));
|
|
195
|
+
out.push({ kind: "tool_output", t, output, isError: !!m && m[1] !== "0" });
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return out;
|
|
199
|
+
}
|
|
200
|
+
var SYSTEM_REMINDER_RE2, CODEX_INJECTED_TEXT_RE, EXIT_CODE_RE;
|
|
201
|
+
var init_codex = __esm({
|
|
202
|
+
"../coding-core/dist/codex.js"() {
|
|
203
|
+
"use strict";
|
|
204
|
+
SYSTEM_REMINDER_RE2 = /<system-reminder>[\s\S]*?<\/system-reminder>/g;
|
|
205
|
+
CODEX_INJECTED_TEXT_RE = /^\s*(<(environment_context|user_instructions|ENVIRONMENT_CONTEXT|turn_aborted)\b|#\s*AGENTS\.md instructions\b)/;
|
|
206
|
+
EXIT_CODE_RE = /(?:Process exited with code|Exit code:)\s+(\d+)/;
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
|
|
113
210
|
// ../coding-core/dist/raw.js
|
|
114
211
|
import { promises as fs } from "fs";
|
|
115
212
|
import path2 from "path";
|
|
@@ -382,7 +479,7 @@ function parseCodex(raw, file2) {
|
|
|
382
479
|
const role = p.role;
|
|
383
480
|
const text2 = codexText(p.content).replace(SYSTEM_REMINDER_RE, "").trim();
|
|
384
481
|
if (role === "user") {
|
|
385
|
-
if (text2 && !
|
|
482
|
+
if (text2 && !isCodexInjectedUserText(text2)) {
|
|
386
483
|
s.humanTurns++;
|
|
387
484
|
s.humanChars += text2.length;
|
|
388
485
|
if (!s.firstHuman)
|
|
@@ -774,11 +871,12 @@ async function readAllSessions(opts = {}) {
|
|
|
774
871
|
demoteTemplateFanouts(all);
|
|
775
872
|
return all;
|
|
776
873
|
}
|
|
777
|
-
var SOURCE_ROOT_ENV_VARS, anyRootOverridden, claudeProjectsRoot, codexSessionsRoot, cursorWorkspaceRoot, cursorProjectsRoot, SKIP_DIR_RE, AGENT_CWD_RE, PERSONA_RE, OUTPUT_CONTRACT_RES, CAPS_HEADER_RE, PING_RE, ms,
|
|
874
|
+
var SOURCE_ROOT_ENV_VARS, anyRootOverridden, claudeProjectsRoot, codexSessionsRoot, cursorWorkspaceRoot, cursorProjectsRoot, SKIP_DIR_RE, AGENT_CWD_RE, PERSONA_RE, OUTPUT_CONTRACT_RES, CAPS_HEADER_RE, PING_RE, ms, CURSOR_USER_QUERY_RE, NODE_SQLITE, FANOUT_PREFIX, FANOUT_MIN_SESSIONS;
|
|
778
875
|
var init_raw = __esm({
|
|
779
876
|
"../coding-core/dist/raw.js"() {
|
|
780
877
|
"use strict";
|
|
781
878
|
init_injected();
|
|
879
|
+
init_codex();
|
|
782
880
|
SOURCE_ROOT_ENV_VARS = [
|
|
783
881
|
"CLAUDE_PROJECTS_DIR",
|
|
784
882
|
"CODEX_SESSIONS_DIR",
|
|
@@ -807,7 +905,6 @@ var init_raw = __esm({
|
|
|
807
905
|
const n = Date.parse(ts);
|
|
808
906
|
return Number.isFinite(n) ? n : null;
|
|
809
907
|
};
|
|
810
|
-
CODEX_INJECTED_RE = /^\s*<(environment_context|user_instructions)>/;
|
|
811
908
|
CURSOR_USER_QUERY_RE = /<user_query>\s*([\s\S]*?)\s*<\/user_query>/;
|
|
812
909
|
NODE_SQLITE = "node:sqlite";
|
|
813
910
|
FANOUT_PREFIX = 80;
|
|
@@ -1486,6 +1583,11 @@ async function readManifest(dataDir) {
|
|
|
1486
1583
|
exports: { included: arr(ex.included), excluded: arr(ex.excluded) }
|
|
1487
1584
|
};
|
|
1488
1585
|
}
|
|
1586
|
+
function agentFlagsFromManifest(m) {
|
|
1587
|
+
if (!m?.agents) return { claudeCode: true, codex: true };
|
|
1588
|
+
const on = (id) => m.agents.included.includes(id);
|
|
1589
|
+
return { claudeCode: on("claude-code"), codex: on("codex") };
|
|
1590
|
+
}
|
|
1489
1591
|
async function writeManifest(dataDir, m) {
|
|
1490
1592
|
await fs22.mkdir(dataDir, { recursive: true });
|
|
1491
1593
|
await fs22.writeFile(manifestPath(dataDir), JSON.stringify(m, null, 2));
|
|
@@ -2182,17 +2284,18 @@ var init_plan = __esm({
|
|
|
2182
2284
|
var wizard_exports = {};
|
|
2183
2285
|
__export(wizard_exports, {
|
|
2184
2286
|
runWizard: () => runWizard,
|
|
2185
|
-
sayExportLinks: () => sayExportLinks
|
|
2287
|
+
sayExportLinks: () => sayExportLinks,
|
|
2288
|
+
scanJsonlDir: () => scanJsonlDir
|
|
2186
2289
|
});
|
|
2187
2290
|
import { promises as fs35 } from "fs";
|
|
2188
2291
|
import os11 from "os";
|
|
2189
2292
|
import path40 from "path";
|
|
2190
2293
|
import * as readline from "node:readline/promises";
|
|
2191
|
-
async function scanJsonlDir(label, dir) {
|
|
2294
|
+
async function scanJsonlDir(label, dir, maxDepth = 1) {
|
|
2192
2295
|
let files = 0;
|
|
2193
2296
|
let newest = 0;
|
|
2194
2297
|
async function walk(d, depth) {
|
|
2195
|
-
if (depth >
|
|
2298
|
+
if (depth > maxDepth) return;
|
|
2196
2299
|
let names = [];
|
|
2197
2300
|
try {
|
|
2198
2301
|
names = await fs35.readdir(d);
|
|
@@ -2317,8 +2420,8 @@ async function runWizard() {
|
|
|
2317
2420
|
});
|
|
2318
2421
|
say(bold(" Step 1 \xB7 Your coding agents"));
|
|
2319
2422
|
const roots = sourceRoots();
|
|
2320
|
-
const scanRoot = (label, dir) => dir ? scanJsonlDir(label, dir) : Promise.resolve({ label, dir: "(disabled \u2014 log roots redirected via env)", files: 0, newest: null });
|
|
2321
|
-
const [cc, cx] = await Promise.all([scanRoot("Claude Code", roots.claudeProjects), scanRoot("Codex", roots.codexSessions)]);
|
|
2423
|
+
const scanRoot = (label, dir, maxDepth) => dir ? scanJsonlDir(label, dir, maxDepth) : Promise.resolve({ label, dir: "(disabled \u2014 log roots redirected via env)", files: 0, newest: null });
|
|
2424
|
+
const [cc, cx] = await Promise.all([scanRoot("Claude Code", roots.claudeProjects, 1), scanRoot("Codex", roots.codexSessions, 3)]);
|
|
2322
2425
|
const agentIds = ["claude-code", "codex"];
|
|
2323
2426
|
const agentScans = [cc, cx];
|
|
2324
2427
|
const present = agentIds.filter((_, i) => agentScans[i].files > 0);
|
|
@@ -2392,8 +2495,11 @@ async function runWizard() {
|
|
|
2392
2495
|
for (const f of await scanForExports(path40.join(os11.homedir(), "Downloads"))) add(f);
|
|
2393
2496
|
for (const f of await scanForObsidianVaults(os11.homedir())) add(f);
|
|
2394
2497
|
for (const f of [...previous?.exports.included ?? [], ...previous?.exports.excluded ?? []]) add(f);
|
|
2498
|
+
let linksShown = false;
|
|
2395
2499
|
if (!found.length) {
|
|
2396
2500
|
say(dim(" Nothing found in the usual places."));
|
|
2501
|
+
await sayExportLinks(say, /* @__PURE__ */ new Set());
|
|
2502
|
+
linksShown = true;
|
|
2397
2503
|
if (await yes(` Search deeper with your own local agent? ${dim("(capped at ~90s)")}`, false)) {
|
|
2398
2504
|
try {
|
|
2399
2505
|
const { invokeAgent: invokeAgent3 } = await Promise.resolve().then(() => (init_agent(), agent_exports));
|
|
@@ -2418,7 +2524,7 @@ async function runWizard() {
|
|
|
2418
2524
|
const defaults = found.map(() => true);
|
|
2419
2525
|
say(` Found ${dim("(identified locally from the files themselves)")}:`);
|
|
2420
2526
|
found.forEach((f, i) => say(describeExport(f, i, defaults[i], hadPrevious)));
|
|
2421
|
-
await sayExportLinks(say, new Set(found.map((f) => f.kind)));
|
|
2527
|
+
if (!linksShown) await sayExportLinks(say, new Set(found.map((f) => f.kind)));
|
|
2422
2528
|
const include = await pick2(defaults, hadPrevious);
|
|
2423
2529
|
const manifest = {
|
|
2424
2530
|
approvedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -2438,7 +2544,7 @@ async function runWizard() {
|
|
|
2438
2544
|
}
|
|
2439
2545
|
} else {
|
|
2440
2546
|
await writeManifest(dataDir, { approvedAt: (/* @__PURE__ */ new Date()).toISOString(), agents, exports: { included: [], excluded: [] } });
|
|
2441
|
-
await sayExportLinks(say, /* @__PURE__ */ new Set());
|
|
2547
|
+
if (!linksShown) await sayExportLinks(say, /* @__PURE__ */ new Set());
|
|
2442
2548
|
}
|
|
2443
2549
|
{
|
|
2444
2550
|
const { EXPORT_LINKS: EXPORT_LINKS2 } = await Promise.resolve().then(() => (init_exportLinks(), exportLinks_exports));
|
|
@@ -2953,6 +3059,7 @@ init_gate2();
|
|
|
2953
3059
|
|
|
2954
3060
|
// ../coding-core/dist/messages.js
|
|
2955
3061
|
init_injected();
|
|
3062
|
+
init_codex();
|
|
2956
3063
|
import { promises as fs2 } from "fs";
|
|
2957
3064
|
function extractText2(content) {
|
|
2958
3065
|
if (typeof content === "string")
|
|
@@ -2964,6 +3071,22 @@ function extractText2(content) {
|
|
|
2964
3071
|
function isToolResultOnly(content) {
|
|
2965
3072
|
return Array.isArray(content) && content.length > 0 && content.every((c) => c && typeof c === "object" && c.type === "tool_result");
|
|
2966
3073
|
}
|
|
3074
|
+
function extractUserMessagesCodex(raw) {
|
|
3075
|
+
const out = [];
|
|
3076
|
+
let lastTs = null;
|
|
3077
|
+
for (const ev of extractCodexEvents(raw)) {
|
|
3078
|
+
const t = ev.t;
|
|
3079
|
+
const gapMs = Number.isFinite(t) && lastTs != null ? t - lastTs : NaN;
|
|
3080
|
+
if (Number.isFinite(t))
|
|
3081
|
+
lastTs = t;
|
|
3082
|
+
if (ev.kind !== "user")
|
|
3083
|
+
continue;
|
|
3084
|
+
const text2 = humanTypedText(ev.text);
|
|
3085
|
+
if (text2 && Number.isFinite(t))
|
|
3086
|
+
out.push({ t, text: text2, gapMs });
|
|
3087
|
+
}
|
|
3088
|
+
return out.sort((a, b) => a.t - b.t);
|
|
3089
|
+
}
|
|
2967
3090
|
async function extractUserMessages(file2) {
|
|
2968
3091
|
let raw;
|
|
2969
3092
|
try {
|
|
@@ -2971,6 +3094,8 @@ async function extractUserMessages(file2) {
|
|
|
2971
3094
|
} catch {
|
|
2972
3095
|
return [];
|
|
2973
3096
|
}
|
|
3097
|
+
if (sniffCodexRaw(raw))
|
|
3098
|
+
return extractUserMessagesCodex(raw);
|
|
2974
3099
|
const out = [];
|
|
2975
3100
|
const userTexts = /* @__PURE__ */ new Set();
|
|
2976
3101
|
const seenUuids = /* @__PURE__ */ new Set();
|
|
@@ -3025,6 +3150,49 @@ function createMessageDeduper() {
|
|
|
3025
3150
|
return true;
|
|
3026
3151
|
};
|
|
3027
3152
|
}
|
|
3153
|
+
function extractMessagesCodex(raw) {
|
|
3154
|
+
const out = [];
|
|
3155
|
+
let aiProse = [];
|
|
3156
|
+
let aiTools = {};
|
|
3157
|
+
let aiStart = 0;
|
|
3158
|
+
const flushAI = () => {
|
|
3159
|
+
if (!aiProse.length && Object.keys(aiTools).length === 0)
|
|
3160
|
+
return;
|
|
3161
|
+
const toolStr = Object.entries(aiTools).map(([n, c]) => c > 1 ? `${n}\xD7${c}` : n).join(", ");
|
|
3162
|
+
let prose = aiProse.join(" ").replace(/\s+/g, " ").trim();
|
|
3163
|
+
if (prose.length > 2200)
|
|
3164
|
+
prose = prose.slice(0, 2200) + "\u2026";
|
|
3165
|
+
let text2 = prose;
|
|
3166
|
+
if (toolStr)
|
|
3167
|
+
text2 = (text2 ? text2 + " " : "") + `[ran ${toolStr}]`;
|
|
3168
|
+
if (text2)
|
|
3169
|
+
out.push({ t: aiStart, role: "ai", text: text2 });
|
|
3170
|
+
aiProse = [];
|
|
3171
|
+
aiTools = {};
|
|
3172
|
+
};
|
|
3173
|
+
for (const ev of extractCodexEvents(raw)) {
|
|
3174
|
+
if (!Number.isFinite(ev.t))
|
|
3175
|
+
continue;
|
|
3176
|
+
if (ev.kind === "user") {
|
|
3177
|
+
const text2 = humanTypedText(ev.text);
|
|
3178
|
+
if (text2) {
|
|
3179
|
+
flushAI();
|
|
3180
|
+
out.push({ t: ev.t, role: "user", text: text2 });
|
|
3181
|
+
}
|
|
3182
|
+
} else if (ev.kind === "assistant") {
|
|
3183
|
+
if (!aiProse.length && Object.keys(aiTools).length === 0)
|
|
3184
|
+
aiStart = ev.t;
|
|
3185
|
+
if (ev.text)
|
|
3186
|
+
aiProse.push(ev.text);
|
|
3187
|
+
} else if (ev.kind === "tool") {
|
|
3188
|
+
if (!aiProse.length && Object.keys(aiTools).length === 0)
|
|
3189
|
+
aiStart = ev.t;
|
|
3190
|
+
aiTools[ev.name] = (aiTools[ev.name] ?? 0) + 1;
|
|
3191
|
+
}
|
|
3192
|
+
}
|
|
3193
|
+
flushAI();
|
|
3194
|
+
return out.sort((a, b) => a.t - b.t);
|
|
3195
|
+
}
|
|
3028
3196
|
async function extractMessages(file2) {
|
|
3029
3197
|
let raw;
|
|
3030
3198
|
try {
|
|
@@ -3032,6 +3200,8 @@ async function extractMessages(file2) {
|
|
|
3032
3200
|
} catch {
|
|
3033
3201
|
return [];
|
|
3034
3202
|
}
|
|
3203
|
+
if (sniffCodexRaw(raw))
|
|
3204
|
+
return extractMessagesCodex(raw);
|
|
3035
3205
|
const out = [];
|
|
3036
3206
|
const userTexts = /* @__PURE__ */ new Set();
|
|
3037
3207
|
const seenUuids = /* @__PURE__ */ new Set();
|
|
@@ -3767,7 +3937,7 @@ var LABEL_BY_UIKEY = Object.fromEntries(GRADED_CRITERIA2.map((c) => [c.uiKey, c.
|
|
|
3767
3937
|
// src/grade/materialize.ts
|
|
3768
3938
|
init_injected();
|
|
3769
3939
|
import { promises as fs3 } from "fs";
|
|
3770
|
-
var
|
|
3940
|
+
var SYSTEM_REMINDER_RE3 = /<system-reminder>[\s\S]*?<\/system-reminder>/g;
|
|
3771
3941
|
var INJECT_GIST = 120;
|
|
3772
3942
|
var INJECTED = [
|
|
3773
3943
|
{ re: /<task-notification>[\s\S]*?<\/task-notification>/g, label: "bg task", gistRe: /<summary>([\s\S]*?)<\/summary>/ },
|
|
@@ -3787,7 +3957,7 @@ function collapseInjected(input) {
|
|
|
3787
3957
|
return "";
|
|
3788
3958
|
});
|
|
3789
3959
|
}
|
|
3790
|
-
return { text: text2.replace(
|
|
3960
|
+
return { text: text2.replace(SYSTEM_REMINDER_RE3, "").trim(), markers };
|
|
3791
3961
|
}
|
|
3792
3962
|
function extractText3(content) {
|
|
3793
3963
|
if (typeof content === "string") return content;
|
|
@@ -21259,8 +21429,9 @@ import path17 from "node:path";
|
|
|
21259
21429
|
|
|
21260
21430
|
// ../../lib/agents/coding/materialize.ts
|
|
21261
21431
|
init_injected();
|
|
21432
|
+
init_codex();
|
|
21262
21433
|
import { promises as fs11 } from "fs";
|
|
21263
|
-
var
|
|
21434
|
+
var SYSTEM_REMINDER_RE4 = /<system-reminder>[\s\S]*?<\/system-reminder>/g;
|
|
21264
21435
|
var INJECT_GIST2 = 120;
|
|
21265
21436
|
var INJECTED2 = [
|
|
21266
21437
|
{ re: /<task-notification>[\s\S]*?<\/task-notification>/g, label: "bg task", gistRe: /<summary>([\s\S]*?)<\/summary>/ },
|
|
@@ -21280,7 +21451,7 @@ function collapseInjected2(input) {
|
|
|
21280
21451
|
return "";
|
|
21281
21452
|
});
|
|
21282
21453
|
}
|
|
21283
|
-
return { text: text2.replace(
|
|
21454
|
+
return { text: text2.replace(SYSTEM_REMINDER_RE4, "").trim(), markers };
|
|
21284
21455
|
}
|
|
21285
21456
|
function extractText4(content) {
|
|
21286
21457
|
if (typeof content === "string") return content;
|
|
@@ -21297,6 +21468,38 @@ function isToolResultOnly3(content) {
|
|
|
21297
21468
|
return Array.isArray(content) && content.length > 0 && content.every((c) => c && typeof c === "object" && c.type === "tool_result");
|
|
21298
21469
|
}
|
|
21299
21470
|
var AI_GIST2 = 160;
|
|
21471
|
+
function materializeCodex(raw) {
|
|
21472
|
+
const lines = [];
|
|
21473
|
+
let humanTurns = 0, humanChars = 0;
|
|
21474
|
+
let aiLastProse = "";
|
|
21475
|
+
const aiTools = /* @__PURE__ */ new Map();
|
|
21476
|
+
const flushAI = () => {
|
|
21477
|
+
if (!aiLastProse && aiTools.size === 0) return;
|
|
21478
|
+
const tools = [...aiTools.entries()].map(([n, c]) => c > 1 ? `${n}\xD7${c}` : n).join(", ");
|
|
21479
|
+
const gist = aiLastProse ? aiLastProse.length > AI_GIST2 ? aiLastProse.slice(0, AI_GIST2) + "\u2026" : aiLastProse : "";
|
|
21480
|
+
const bits = [];
|
|
21481
|
+
if (gist) bits.push(gist);
|
|
21482
|
+
if (tools) bits.push(`ran ${tools}`);
|
|
21483
|
+
lines.push(`[AI: ${bits.join(" \xB7 ")}]`);
|
|
21484
|
+
aiLastProse = "";
|
|
21485
|
+
aiTools.clear();
|
|
21486
|
+
};
|
|
21487
|
+
for (const ev of extractCodexEvents(raw)) {
|
|
21488
|
+
if (ev.kind === "user") {
|
|
21489
|
+
flushAI();
|
|
21490
|
+
humanTurns++;
|
|
21491
|
+
humanChars += ev.text.length;
|
|
21492
|
+
lines.push(`>> ${ev.text}`);
|
|
21493
|
+
} else if (ev.kind === "assistant") {
|
|
21494
|
+
const prose = ev.text.replace(/\s+/g, " ").trim();
|
|
21495
|
+
if (prose) aiLastProse = prose;
|
|
21496
|
+
} else if (ev.kind === "tool") {
|
|
21497
|
+
aiTools.set(ev.name, (aiTools.get(ev.name) ?? 0) + 1);
|
|
21498
|
+
}
|
|
21499
|
+
}
|
|
21500
|
+
flushAI();
|
|
21501
|
+
return { text: lines.join("\n"), humanTurns, humanChars };
|
|
21502
|
+
}
|
|
21300
21503
|
async function materializeSession2(file2) {
|
|
21301
21504
|
let raw;
|
|
21302
21505
|
try {
|
|
@@ -21304,6 +21507,7 @@ async function materializeSession2(file2) {
|
|
|
21304
21507
|
} catch {
|
|
21305
21508
|
return null;
|
|
21306
21509
|
}
|
|
21510
|
+
if (sniffCodexRaw(raw)) return materializeCodex(raw);
|
|
21307
21511
|
const lines = [];
|
|
21308
21512
|
let humanTurns = 0, humanChars = 0;
|
|
21309
21513
|
const pendingQueued = [];
|
|
@@ -21839,124 +22043,6 @@ function handleDiagnostic(method, body, key2) {
|
|
|
21839
22043
|
// src/codingChat.ts
|
|
21840
22044
|
init_agent();
|
|
21841
22045
|
|
|
21842
|
-
// ../../lib/agents/coding/chat-context.ts
|
|
21843
|
-
var RUNGS_BY_KEY = new Map(CODING_CRITERIA.map((c) => [c.key, c.rungs ?? []]));
|
|
21844
|
-
var clip = (s, n) => {
|
|
21845
|
-
const t = (s || "").replace(/\s+/g, " ").trim();
|
|
21846
|
-
return t.length > n ? t.slice(0, n - 1).replace(/\s+\S*$/, "") + "\u2026" : t;
|
|
21847
|
-
};
|
|
21848
|
-
function criterionBlock(c) {
|
|
21849
|
-
if (!c.graded || c.dist.n <= 0) return null;
|
|
21850
|
-
const lines = [];
|
|
21851
|
-
const mean2 = c.dist.mean != null ? `${c.dist.mean}` : "\u2014";
|
|
21852
|
-
lines.push(`### ${c.label} (your mean ${mean2} across ${c.dist.n} graded session${c.dist.n === 1 ? "" : "s"})`);
|
|
21853
|
-
lines.push(`What it measures: ${clip(c.definition, 400)}`);
|
|
21854
|
-
const rungs = RUNGS_BY_KEY.get(c.key) ?? [];
|
|
21855
|
-
if (rungs.length) {
|
|
21856
|
-
lines.push(`The ladder I grade against:`);
|
|
21857
|
-
for (const r of rungs) lines.push(` L${r.level} \u2014 ${r.marker}`);
|
|
21858
|
-
}
|
|
21859
|
-
const takes = (c.takes || []).slice(0, 5);
|
|
21860
|
-
if (takes.length) {
|
|
21861
|
-
lines.push(`How I scored your sessions here:`);
|
|
21862
|
-
for (const t of takes) {
|
|
21863
|
-
const sc = t.score != null ? `${t.score}` : t.best != null ? `~${t.best}` : "\u2014";
|
|
21864
|
-
const parts = [` \u2022 "${clip(t.title, 80)}" (${(t.date || "").slice(0, 10)}) \u2014 scored ${sc}${t.confidence ? ` (${t.confidence})` : ""}.`];
|
|
21865
|
-
if (t.instance) parts.push(`What showed it: ${clip(t.instance, 240)}`);
|
|
21866
|
-
if (t.why) parts.push(`Why that score: ${clip(t.why, 320)}`);
|
|
21867
|
-
const qs = (t.quotes || []).filter(Boolean).slice(0, 2).map((q) => `"${clip(q, 160)}"`);
|
|
21868
|
-
if (qs.length) parts.push(`You said: ${qs.join(" / ")}`);
|
|
21869
|
-
lines.push(parts.join(" "));
|
|
21870
|
-
}
|
|
21871
|
-
}
|
|
21872
|
-
return lines.join("\n");
|
|
21873
|
-
}
|
|
21874
|
-
function buildCodingContext(profile) {
|
|
21875
|
-
const out = [];
|
|
21876
|
-
const t = profile.throughput;
|
|
21877
|
-
const p = profile.parallelism;
|
|
21878
|
-
const meta = [];
|
|
21879
|
-
if (t?.sessions != null) meta.push(`${t.sessions} interactive coding sessions`);
|
|
21880
|
-
if (profile.gradedSessions != null) meta.push(`${profile.gradedSessions} graded`);
|
|
21881
|
-
if (p?.maxConcurrency != null) meta.push(`peak ${p.maxConcurrency} sessions in parallel`);
|
|
21882
|
-
if (meta.length) out.push(`HOW THEY WORK: ${meta.join(" \xB7 ")}.`);
|
|
21883
|
-
const blocks = (profile.criteria || []).map(criterionBlock).filter((b) => !!b);
|
|
21884
|
-
if (blocks.length) {
|
|
21885
|
-
out.push(`
|
|
21886
|
-
YOUR GRADED CRITERIA \u2014 the rubric ladder and how I scored you on each, with your own words as the receipts:`);
|
|
21887
|
-
out.push(blocks.join("\n\n"));
|
|
21888
|
-
} else {
|
|
21889
|
-
out.push(`
|
|
21890
|
-
(No criteria have been graded yet, so I can only speak to how you work, not the qualitative scores.)`);
|
|
21891
|
-
}
|
|
21892
|
-
return out.join("\n");
|
|
21893
|
-
}
|
|
21894
|
-
var CODING_CHAT_SYSTEM = `You are the analyst who graded this person's coding-agent sessions (their Claude Code / Codex logs) against a FIXED rubric, and you are now talking WITH them about their report. Below you are given that rubric \u2014 the definition and the level ladder for each criterion \u2014 AND your own per-session grades: the exact moment that keyed each score, WHY you placed it on that rung, and their verbatim quotes. Everything you claim comes from that material.
|
|
21895
|
-
|
|
21896
|
-
HOW TO ANSWER:
|
|
21897
|
-
- Ground every claim in the receipts you were given. When they ask "why did I get that score on X", name the specific session, the rung you landed them on, what that rung requires, and quote their actual words. Never invent a session, a score, a rung, or a criterion that isn't below.
|
|
21898
|
-
- The rubric is the authority. If they push on a score, explain the ladder honestly: what rung they hit and what the NEXT rung would concretely have required of them. Don't inflate a score to be nice and don't apologize for a low one \u2014 being read accurately is the point. If they're genuinely strong, say so plainly.
|
|
21899
|
-
- Be honest about the instrument's limits. These grades come only from their coding logs, which UNDER-observe real skill (a lot of thinking never reaches the transcript). When it's relevant, say what you can and can't actually see from the logs rather than overclaiming.
|
|
21900
|
-
- Voice: warm, plain, declarative, second person. Specific, never a horoscope, never flattery. Numbers are calibration, not a verdict \u2014 don't recite them at the person.
|
|
21901
|
-
- Keep replies tight and human unless they ask you to go deep. Output ONLY your reply \u2014 no preamble, no meta.
|
|
21902
|
-
|
|
21903
|
-
Do NOT use em dashes. Use a comma or a period instead.`;
|
|
21904
|
-
function stripSlop(raw) {
|
|
21905
|
-
return (raw || "").trim().replace(/\s*—\s*/g, ", ").replace(/\s+–\s+/g, ", ").replace(/\s+,/g, ",");
|
|
21906
|
-
}
|
|
21907
|
-
function buildCodingChatPrompt(profile, messages) {
|
|
21908
|
-
const context = buildCodingContext(profile);
|
|
21909
|
-
const history = messages.map((m) => `${m.role === "user" ? "Them" : "You"}: ${m.content}`).join("\n\n");
|
|
21910
|
-
return `YOUR READ OF THIS PERSON (the rubric + your grades + their receipts):
|
|
21911
|
-
${context}
|
|
21912
|
-
|
|
21913
|
-
--- the conversation so far ---
|
|
21914
|
-
${history}
|
|
21915
|
-
|
|
21916
|
-
Write your next reply to them now.`;
|
|
21917
|
-
}
|
|
21918
|
-
|
|
21919
|
-
// src/codingChat.ts
|
|
21920
|
-
async function handleCodingChat(profile, dataDir, body, res) {
|
|
21921
|
-
const raw = Array.isArray(body.messages) ? body.messages : [];
|
|
21922
|
-
const messages = raw.filter((m) => (m.role === "user" || m.role === "assistant") && typeof m.content === "string").slice(-20);
|
|
21923
|
-
if (!messages.length) {
|
|
21924
|
-
res.writeHead(400, { "Content-Type": "application/json; charset=utf-8" });
|
|
21925
|
-
res.end(JSON.stringify({ error: "no messages" }));
|
|
21926
|
-
return;
|
|
21927
|
-
}
|
|
21928
|
-
const prompt = buildCodingChatPrompt(profile, messages);
|
|
21929
|
-
res.writeHead(200, {
|
|
21930
|
-
"Content-Type": "application/x-ndjson; charset=utf-8",
|
|
21931
|
-
"Cache-Control": "no-store, no-transform",
|
|
21932
|
-
"X-Accel-Buffering": "no"
|
|
21933
|
-
});
|
|
21934
|
-
const send = (o) => {
|
|
21935
|
-
try {
|
|
21936
|
-
res.write(JSON.stringify(o) + "\n");
|
|
21937
|
-
} catch {
|
|
21938
|
-
}
|
|
21939
|
-
};
|
|
21940
|
-
try {
|
|
21941
|
-
const run4 = await invokeAgent({
|
|
21942
|
-
prompt,
|
|
21943
|
-
systemPrompt: CODING_CHAT_SYSTEM,
|
|
21944
|
-
// Everything it needs is in the prompt; dataDir is a harmless read-only
|
|
21945
|
-
// sandbox. maxTurns 2 → answer directly, never a tool-loop.
|
|
21946
|
-
addDir: dataDir,
|
|
21947
|
-
allowedTools: ["Read"],
|
|
21948
|
-
maxTurns: 2,
|
|
21949
|
-
model: "sonnet",
|
|
21950
|
-
onText: (delta) => send({ t: "delta", v: delta })
|
|
21951
|
-
});
|
|
21952
|
-
send({ t: "done", reply: stripSlop(run4.raw || "") || "(no response)" });
|
|
21953
|
-
} catch {
|
|
21954
|
-
send({ t: "error", message: "Couldn't reach your local Claude \u2014 is Claude Code (or Codex) installed and logged in?" });
|
|
21955
|
-
} finally {
|
|
21956
|
-
res.end();
|
|
21957
|
-
}
|
|
21958
|
-
}
|
|
21959
|
-
|
|
21960
22046
|
// src/personApi.ts
|
|
21961
22047
|
init_agent();
|
|
21962
22048
|
import { promises as fs18 } from "fs";
|
|
@@ -22519,6 +22605,137 @@ ${dataMap}`,
|
|
|
22519
22605
|
}
|
|
22520
22606
|
}
|
|
22521
22607
|
|
|
22608
|
+
// ../../lib/agents/coding/chat-context.ts
|
|
22609
|
+
var RUNGS_BY_KEY = new Map(CODING_CRITERIA.map((c) => [c.key, c.rungs ?? []]));
|
|
22610
|
+
var clip = (s, n) => {
|
|
22611
|
+
const t = (s || "").replace(/\s+/g, " ").trim();
|
|
22612
|
+
return t.length > n ? t.slice(0, n - 1).replace(/\s+\S*$/, "") + "\u2026" : t;
|
|
22613
|
+
};
|
|
22614
|
+
function criterionBlock(c) {
|
|
22615
|
+
if (!c.graded || c.dist.n <= 0) return null;
|
|
22616
|
+
const lines = [];
|
|
22617
|
+
const mean2 = c.dist.mean != null ? `${c.dist.mean}` : "\u2014";
|
|
22618
|
+
lines.push(`### ${c.label} (your mean ${mean2} across ${c.dist.n} graded session${c.dist.n === 1 ? "" : "s"})`);
|
|
22619
|
+
lines.push(`What it measures: ${clip(c.definition, 400)}`);
|
|
22620
|
+
const rungs = RUNGS_BY_KEY.get(c.key) ?? [];
|
|
22621
|
+
if (rungs.length) {
|
|
22622
|
+
lines.push(`The ladder I grade against:`);
|
|
22623
|
+
for (const r of rungs) lines.push(` L${r.level} \u2014 ${r.marker}`);
|
|
22624
|
+
}
|
|
22625
|
+
const takes = (c.takes || []).slice(0, 5);
|
|
22626
|
+
if (takes.length) {
|
|
22627
|
+
lines.push(`How I scored your sessions here:`);
|
|
22628
|
+
for (const t of takes) {
|
|
22629
|
+
const sc = t.score != null ? `${t.score}` : t.best != null ? `~${t.best}` : "\u2014";
|
|
22630
|
+
const parts = [` \u2022 "${clip(t.title, 80)}" (${(t.date || "").slice(0, 10)}) \u2014 scored ${sc}${t.confidence ? ` (${t.confidence})` : ""}.`];
|
|
22631
|
+
if (t.instance) parts.push(`What showed it: ${clip(t.instance, 240)}`);
|
|
22632
|
+
if (t.why) parts.push(`Why that score: ${clip(t.why, 320)}`);
|
|
22633
|
+
const qs = (t.quotes || []).filter(Boolean).slice(0, 2).map((q) => `"${clip(q, 160)}"`);
|
|
22634
|
+
if (qs.length) parts.push(`You said: ${qs.join(" / ")}`);
|
|
22635
|
+
lines.push(parts.join(" "));
|
|
22636
|
+
}
|
|
22637
|
+
}
|
|
22638
|
+
return lines.join("\n");
|
|
22639
|
+
}
|
|
22640
|
+
var CODING_DATA_HOME_MAP = `THE DATA HOME YOU CAN READ (tools: Read, Grep, Glob; every path is relative to the extra read-only directory you were given):
|
|
22641
|
+
- coding/sessions.json \u2014 every session: title, times, activeMin, humanTurns, tool counts, klass (only "interactive" sessions are the person; the rest are machine runs), duplicateOf (fork copies \u2014 skip them or you double-count).
|
|
22642
|
+
- coding/focus.json \u2014 the flow analysis: per-day half-hour cells, steering runs, gaps, false starts, workstream features, causal findings. coding/flow.json \u2014 the older looser metric; the report calls it "engaged time", never flow. Do not conflate the two.
|
|
22643
|
+
- coding/day-digest.json and coding/day-chart.json \u2014 per-day narratives and per-conversation active intervals.
|
|
22644
|
+
- coding/projects.json \u2014 per-repo attribution. coding/delegation/ \u2014 delegation pattern reads.
|
|
22645
|
+
- coding/grades/*.json \u2014 per-session rubric grades (score on the 1-11 ladder, keyed instance, why, verbatim quotes). coding/walkthroughs/ \u2014 per-session walkthroughs.
|
|
22646
|
+
- coding/aggregate.json (ability ceilings + the bigPicture nutshell), coding/expertise.json, coding/gap.json (ranked technique recommendations), coding/coaching.json, coding/frontier.json, coding/frontier-detail.json, coding/concurrency.json \u2014 each self-describing; read the file before citing it.
|
|
22647
|
+
Trust the filesystem over this list: Glob/ls a directory before assuming its contents, and a file may simply not exist yet on a fresh run \u2014 say so instead of guessing. Budget 2-4 lookups per question, then answer.`;
|
|
22648
|
+
function buildCodingContext(profile) {
|
|
22649
|
+
const out = [];
|
|
22650
|
+
const t = profile.throughput;
|
|
22651
|
+
const p = profile.parallelism;
|
|
22652
|
+
const meta = [];
|
|
22653
|
+
if (t?.sessions != null) meta.push(`${t.sessions} interactive coding sessions`);
|
|
22654
|
+
if (profile.gradedSessions != null) meta.push(`${profile.gradedSessions} graded`);
|
|
22655
|
+
if (p?.maxConcurrency != null) meta.push(`peak ${p.maxConcurrency} sessions in parallel`);
|
|
22656
|
+
if (meta.length) out.push(`HOW THEY WORK: ${meta.join(" \xB7 ")}.`);
|
|
22657
|
+
const blocks = (profile.criteria || []).map(criterionBlock).filter((b) => !!b);
|
|
22658
|
+
if (blocks.length) {
|
|
22659
|
+
out.push(`
|
|
22660
|
+
YOUR GRADED CRITERIA \u2014 the rubric ladder and how I scored you on each, with your own words as the receipts:`);
|
|
22661
|
+
out.push(blocks.join("\n\n"));
|
|
22662
|
+
} else {
|
|
22663
|
+
out.push(`
|
|
22664
|
+
NO QUALITATIVE GRADES YET: the rubric grading pass has not scored any sessions, so there are no criterion scores, rungs, or graded receipts to cite. If they ask about grades or scores, say that plainly and never fabricate one. Everything measurable is still answerable: read the deterministic artifacts in the data home (sessions, focus/flow, projects, day digests) and give them real numbers with dates instead of shrugging.`);
|
|
22665
|
+
}
|
|
22666
|
+
out.push(`
|
|
22667
|
+
${CODING_DATA_HOME_MAP}`);
|
|
22668
|
+
return out.join("\n");
|
|
22669
|
+
}
|
|
22670
|
+
var CODING_CHAT_SYSTEM = `You are the analyst who graded this person's coding-agent sessions (their Claude Code / Codex logs) against a FIXED rubric, and you are now talking WITH them about their report. Below you are given that rubric \u2014 the definition and the level ladder for each criterion \u2014 AND your own per-session grades: the exact moment that keyed each score, WHY you placed it on that rung, and their verbatim quotes. Everything you claim comes from that material or from the served data-home artifacts you can read with your tools (the grounding block maps them) \u2014 never invent a number, score, session, or quote that no file backs. The person's raw session logs are in bounds only through the artifacts present in the data home; do not hunt outside the directory you were given.
|
|
22671
|
+
|
|
22672
|
+
HOW TO ANSWER:
|
|
22673
|
+
- Ground every claim in the receipts you were given. When they ask "why did I get that score on X", name the specific session, the rung you landed them on, what that rung requires, and quote their actual words. Never invent a session, a score, a rung, or a criterion that isn't below.
|
|
22674
|
+
- The rubric is the authority. If they push on a score, explain the ladder honestly: what rung they hit and what the NEXT rung would concretely have required of them. Don't inflate a score to be nice and don't apologize for a low one \u2014 being read accurately is the point. If they're genuinely strong, say so plainly.
|
|
22675
|
+
- Be honest about the instrument's limits. These grades come only from their coding logs, which UNDER-observe real skill (a lot of thinking never reaches the transcript). When it's relevant, say what you can and can't actually see from the logs rather than overclaiming.
|
|
22676
|
+
- Voice: warm, plain, declarative, second person. Specific, never a horoscope, never flattery. Numbers are calibration, not a verdict \u2014 don't recite them at the person.
|
|
22677
|
+
- Keep replies tight and human unless they ask you to go deep. Output ONLY your reply \u2014 no preamble, no meta.
|
|
22678
|
+
|
|
22679
|
+
Do NOT use em dashes. Use a comma or a period instead.`;
|
|
22680
|
+
function stripSlop(raw) {
|
|
22681
|
+
return (raw || "").trim().replace(/\s*—\s*/g, ", ").replace(/\s+–\s+/g, ", ").replace(/\s+,/g, ",");
|
|
22682
|
+
}
|
|
22683
|
+
function buildCodingChatPrompt(profile, messages) {
|
|
22684
|
+
const context = buildCodingContext(profile);
|
|
22685
|
+
const history = messages.map((m) => `${m.role === "user" ? "Them" : "You"}: ${m.content}`).join("\n\n");
|
|
22686
|
+
return `YOUR READ OF THIS PERSON (the rubric + your grades + their receipts):
|
|
22687
|
+
${context}
|
|
22688
|
+
|
|
22689
|
+
--- the conversation so far ---
|
|
22690
|
+
${history}
|
|
22691
|
+
|
|
22692
|
+
Write your next reply to them now.`;
|
|
22693
|
+
}
|
|
22694
|
+
|
|
22695
|
+
// src/codingChat.ts
|
|
22696
|
+
async function handleCodingChat(profile, dataDir, body, res) {
|
|
22697
|
+
const raw = Array.isArray(body.messages) ? body.messages : [];
|
|
22698
|
+
const messages = raw.filter((m) => (m.role === "user" || m.role === "assistant") && typeof m.content === "string").slice(-20);
|
|
22699
|
+
if (!messages.length) {
|
|
22700
|
+
res.writeHead(400, { "Content-Type": "application/json; charset=utf-8" });
|
|
22701
|
+
res.end(JSON.stringify({ error: "no messages" }));
|
|
22702
|
+
return;
|
|
22703
|
+
}
|
|
22704
|
+
const prompt = buildCodingChatPrompt(profile, messages);
|
|
22705
|
+
res.writeHead(200, {
|
|
22706
|
+
"Content-Type": "application/x-ndjson; charset=utf-8",
|
|
22707
|
+
"Cache-Control": "no-store, no-transform",
|
|
22708
|
+
"X-Accel-Buffering": "no"
|
|
22709
|
+
});
|
|
22710
|
+
const send = (o) => {
|
|
22711
|
+
try {
|
|
22712
|
+
res.write(JSON.stringify(o) + "\n");
|
|
22713
|
+
} catch {
|
|
22714
|
+
}
|
|
22715
|
+
};
|
|
22716
|
+
try {
|
|
22717
|
+
const dataMap = await readDataMap();
|
|
22718
|
+
const run4 = await invokeAgent({
|
|
22719
|
+
prompt,
|
|
22720
|
+
systemPrompt: `${CODING_CHAT_SYSTEM}
|
|
22721
|
+
|
|
22722
|
+
AGENT MODE: you also have read-only tools (Read/Grep/Glob) over the person's local record. Use them whenever the pre-baked context can't answer precisely \u2014 the map below tells you what lives where. Traverse first, then answer with receipts. Never claim you lack access to something the map covers.
|
|
22723
|
+
|
|
22724
|
+
${dataMap}`,
|
|
22725
|
+
addDir: dataDir,
|
|
22726
|
+
allowedTools: ["Read", "Grep", "Glob"],
|
|
22727
|
+
maxTurns: 16,
|
|
22728
|
+
model: "sonnet",
|
|
22729
|
+
onText: (delta) => send({ t: "delta", v: delta })
|
|
22730
|
+
});
|
|
22731
|
+
send({ t: "done", reply: stripSlop(run4.raw || "") || "(no response)" });
|
|
22732
|
+
} catch {
|
|
22733
|
+
send({ t: "error", message: "Couldn't reach your local Claude \u2014 is Claude Code (or Codex) installed and logged in?" });
|
|
22734
|
+
} finally {
|
|
22735
|
+
res.end();
|
|
22736
|
+
}
|
|
22737
|
+
}
|
|
22738
|
+
|
|
22522
22739
|
// src/publicReportApi.ts
|
|
22523
22740
|
init_agent();
|
|
22524
22741
|
|
|
@@ -23555,6 +23772,18 @@ function distOf3(takes) {
|
|
|
23555
23772
|
const hist = [...h.keys()].sort((a, b) => b - a).map((level) => ({ level, count: h.get(level) }));
|
|
23556
23773
|
return { n, observed, mean: mean2, median: median2, hist };
|
|
23557
23774
|
}
|
|
23775
|
+
var phi = (z) => {
|
|
23776
|
+
const t = 1 / (1 + 0.2316419 * Math.abs(z));
|
|
23777
|
+
const d = 0.3989423 * Math.exp(-z * z / 2);
|
|
23778
|
+
let pr = d * t * (0.3193815 + t * (-0.3565638 + t * (1.781478 + t * (-1.821256 + t * 1.330274))));
|
|
23779
|
+
if (z > 0) pr = 1 - pr;
|
|
23780
|
+
return pr;
|
|
23781
|
+
};
|
|
23782
|
+
var lognPct = (x, c) => x == null || !c || x <= 0 ? null : Math.min(99.9, Math.max(0.1, Math.round(phi(Math.log(x / c.median) / c.sigma) * 1e3) / 10));
|
|
23783
|
+
var NO_GRADES_GAP = "no sessions graded for this yet \u2014 this fills in once grading has run";
|
|
23784
|
+
function estimateRowParts(score, nTakes, evidenceGap) {
|
|
23785
|
+
return nTakes === 0 && score == null ? { score: null, gap: NO_GRADES_GAP } : { score, gap: evidenceGap };
|
|
23786
|
+
}
|
|
23558
23787
|
async function compileCodingProfile() {
|
|
23559
23788
|
const allRecords = await readJson2(path30.join(CODING_DIR2, "sessions.json"), []);
|
|
23560
23789
|
const dupIds = new Set(allRecords.filter((s) => s.duplicateOf).map((s) => s.sessionId));
|
|
@@ -23809,15 +24038,11 @@ async function compileCodingProfile() {
|
|
|
23809
24038
|
const unb = ceilOf("unblocking");
|
|
23810
24039
|
const agency = out2 != null && unb != null ? Math.round((out2 + unb) / 2) : out2 ?? unb;
|
|
23811
24040
|
const sRow = (label, score, gap2) => ({ label, score, percentile: pctOf(score), gap: gap2 });
|
|
23812
|
-
const
|
|
23813
|
-
|
|
23814
|
-
|
|
23815
|
-
const d = 0.3989423 * Math.exp(-z * z / 2);
|
|
23816
|
-
let pr = d * t * (0.3193815 + t * (-0.3565638 + t * (1.781478 + t * (-1.821256 + t * 1.330274))));
|
|
23817
|
-
if (z > 0) pr = 1 - pr;
|
|
23818
|
-
return pr;
|
|
24041
|
+
const est = (label, score, key2, evidenceGap) => {
|
|
24042
|
+
const e = estimateRowParts(score, nTk(key2), evidenceGap);
|
|
24043
|
+
return sRow(label, e.score, e.gap);
|
|
23819
24044
|
};
|
|
23820
|
-
const
|
|
24045
|
+
const tiers = DEFAULT_CALIBRATION.codingTiers;
|
|
23821
24046
|
const avgWords = aggregate?.throughput?.avgWordsPerDay ?? null;
|
|
23822
24047
|
const pushPctl = lognPct(avgWords, tiers?.push);
|
|
23823
24048
|
const focusPctl = lognPct(flowPctDay, tiers?.focus);
|
|
@@ -23836,10 +24061,16 @@ async function compileCodingProfile() {
|
|
|
23836
24061
|
null,
|
|
23837
24062
|
workDayHrs != null ? `~${workDayHrs}h of active building on a typical work day \u2014 engaged builders average ~3h, and sustaining 7h+ day after day, week after week, is top-1% territory` : "not enough dated activity yet to measure a typical work day"
|
|
23838
24063
|
),
|
|
24064
|
+
// The copy FOLLOWS the person's actual orchestration band (orchPctl above) —
|
|
24065
|
+
// a hardcoded "single biggest speed-up still on the table" once shipped to a
|
|
24066
|
+
// user at orchPctl 99.5 (18 agents peak, 48% of hours at 2+), flatly
|
|
24067
|
+
// contradicting the gap section's "already strong" on the same page
|
|
24068
|
+
// (2026-07-17). The still-on-the-table claim is reserved for genuinely low
|
|
24069
|
+
// orchestration.
|
|
23839
24070
|
sRow(
|
|
23840
24071
|
"Your AI parallelism",
|
|
23841
24072
|
ceilOf("delegation"),
|
|
23842
|
-
soloPct != null ? `~${soloPct}% of your hours you drive a single agent (${Math.round(soloMin / 60)}h solo vs ${Math.round(parMin / 60)}h with 2+ live) \u2014 the Claude Code lead keeps 10\u201315 going at once, so this is the single biggest speed-up still on the table` : "you brief the AI sharply, but mostly drive one agent at a time \u2014 the top run 10\u201315 in parallel, a several-fold speed-up"
|
|
24073
|
+
soloPct != null ? orchPctl >= 97 ? `you already run parallel at the frontier \u2014 ${Math.round(parMin / 60)}h of your hours with 2+ agents live vs ${Math.round(soloMin / 60)}h solo; the Claude Code lead keeps 10\u201315 going at once, and you work the same way` : `~${soloPct}% of your hours you drive a single agent (${Math.round(soloMin / 60)}h solo vs ${Math.round(parMin / 60)}h with 2+ live) \u2014 the Claude Code lead keeps 10\u201315 going at once, so this is the single biggest speed-up still on the table` : "you brief the AI sharply, but mostly drive one agent at a time \u2014 the top run 10\u201315 in parallel, a several-fold speed-up"
|
|
23843
24074
|
),
|
|
23844
24075
|
// The evidence line cites the RANKING metric (flow as a share of the work
|
|
23845
24076
|
// day), never absolute hours — a friend with MORE flow hours over a longer
|
|
@@ -23855,22 +24086,25 @@ async function compileCodingProfile() {
|
|
|
23855
24086
|
// The four estimates LEAD with a concrete moment from their own sessions, then an
|
|
23856
24087
|
// HONEST caveat — how many graded sessions back the read. No invented weakness, no
|
|
23857
24088
|
// claim about what they "didn't" do (false specifics churn a real user); it's an estimate.
|
|
23858
|
-
|
|
24089
|
+
est(
|
|
23859
24090
|
"Agency",
|
|
23860
24091
|
agency,
|
|
24092
|
+
"outcomes",
|
|
23861
24093
|
`${proud("outcomes", "you ship working systems and unblock yourself")} \u2014 one of ${nTk("outcomes")} sessions behind this read; a strong, consistent signal, still an estimate from your logs`
|
|
23862
24094
|
),
|
|
23863
24095
|
// Judgement/Taste use the SAME numbers their ability cards prove (aggregate
|
|
23864
24096
|
// peak-with-consistency over near-peak instances) — a chip saying "top 1%"
|
|
23865
24097
|
// above a card proving 10/Top 0.1% with ten receipts reads as a bug.
|
|
23866
|
-
|
|
24098
|
+
est(
|
|
23867
24099
|
"Judgement",
|
|
23868
24100
|
aggregate?.ability?.abstraction?.score ?? ceilOf("generative"),
|
|
24101
|
+
"generative",
|
|
23869
24102
|
`${proud("generative", "you make sharp, non-obvious calls on what actually matters")} \u2014 one of ${nTk("generative")} sessions we've graded for this; clear so far, not yet a final verdict`
|
|
23870
24103
|
),
|
|
23871
|
-
|
|
24104
|
+
est(
|
|
23872
24105
|
"Taste",
|
|
23873
24106
|
aggregate?.ability?.taste?.score ?? ceilOf("taste"),
|
|
24107
|
+
"taste",
|
|
23874
24108
|
`${proud("taste", "you hold a high, opinionated quality bar")} \u2014 one of ${nTk("taste")} sessions behind this read; a real signal, still an estimate`
|
|
23875
24109
|
)
|
|
23876
24110
|
// Expertise: NO chip — the scored criterion is deprecated; the real judge is
|
|
@@ -25112,6 +25346,7 @@ function stages(o) {
|
|
|
25112
25346
|
const conc = String(o.conc ?? h.grade);
|
|
25113
25347
|
const buildArgs = [];
|
|
25114
25348
|
if (o.codex === false) buildArgs.push("--no-codex");
|
|
25349
|
+
if (o.claudeCode === false) buildArgs.push("--no-claude");
|
|
25115
25350
|
if (o.idleGapMin != null) buildArgs.push("--idle", String(o.idleGapMin));
|
|
25116
25351
|
const gradeArgs = ["--all", "--model", gradeModel, "--conc", conc];
|
|
25117
25352
|
if (o.regrade) gradeArgs.push("--regrade");
|
|
@@ -25341,6 +25576,7 @@ async function runPipeline(o) {
|
|
|
25341
25576
|
`\u2713 report is up to date \u2014 ${gate2.pending} new session(s) since the last full run (below the ${threshold}-session threshold). Skipping the AI stages; free metrics still refresh. They'll be analyzed once ${threshold}+ accumulate (POLYMATH_MIN_NEW_SESSIONS=0 or --regrade to force now).`
|
|
25342
25577
|
);
|
|
25343
25578
|
} else if (gate2.hasPriorRun) {
|
|
25579
|
+
o.onNewWork?.(gate2.pending);
|
|
25344
25580
|
o.onLine?.(
|
|
25345
25581
|
`\u2713 your finished report from the last run is safe and already serving at the link below \u2014 nothing restarts from scratch. ${gate2.pending >= 0 ? `${gate2.pending} pending session(s)` : "New work"} plus any stages added by an update run on top of it, and sections refresh in place as they finish.`
|
|
25346
25582
|
);
|
|
@@ -25542,6 +25778,8 @@ async function runChatPipeline(o) {
|
|
|
25542
25778
|
upToDate = true;
|
|
25543
25779
|
o.onUpToDate?.();
|
|
25544
25780
|
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.`);
|
|
25781
|
+
} else {
|
|
25782
|
+
o.onNewWork?.(newDocs);
|
|
25545
25783
|
}
|
|
25546
25784
|
}
|
|
25547
25785
|
}
|
|
@@ -25781,6 +26019,11 @@ Graded ${detail.gradedSessions} sessions \u2192 ${gradeOut}/graded.json`);
|
|
|
25781
26019
|
}
|
|
25782
26020
|
if (opts.cmd === "serve") {
|
|
25783
26021
|
let earlyHandle = null;
|
|
26022
|
+
const consentManifest = await readManifest(DATA_ROOT);
|
|
26023
|
+
const consent = agentFlagsFromManifest(consentManifest);
|
|
26024
|
+
const consentWhy = (id) => consentManifest?.agents?.excluded.includes(id) ? "you excluded it during setup" : "setup never asked about it";
|
|
26025
|
+
if (!consent.claudeCode) console.error(` \u26D4 Claude Code logs will NOT be analyzed \u2014 ${consentWhy("claude-code")}. POLYMATH_WIZARD=1 polymath-society to change.`);
|
|
26026
|
+
if (!consent.codex) console.error(` \u26D4 Codex logs will NOT be analyzed \u2014 ${consentWhy("codex")}. POLYMATH_WIZARD=1 polymath-society to change.`);
|
|
25784
26027
|
const runMarker = path41.join(DATA_ROOT, "coding", ".grade-run.json");
|
|
25785
26028
|
if (!opts.grade) {
|
|
25786
26029
|
try {
|
|
@@ -25858,12 +26101,19 @@ Running the full analysis on ${backend.name === "cli" ? "Claude Code" : "Codex"}
|
|
|
25858
26101
|
mbar.setLink(earlyHandle.url);
|
|
25859
26102
|
const codingLane = mbar.lane("coding");
|
|
25860
26103
|
let codingPinned = false;
|
|
26104
|
+
if (await readPriorAnalysis()) {
|
|
26105
|
+
codingPinned = true;
|
|
26106
|
+
progress.coding = { i: 2, total: 1, label: "up to date \u2014 checking for anything new", done: false };
|
|
26107
|
+
earlyHandle.setProgress(progress);
|
|
26108
|
+
codingLane.finish("up to date \u2014 checking for anything new");
|
|
26109
|
+
}
|
|
25861
26110
|
const codingDone = runPipeline({
|
|
25862
26111
|
repoRoot: REPO_ROOT,
|
|
25863
26112
|
model: opts.model,
|
|
25864
26113
|
conc: opts.conc,
|
|
25865
26114
|
overnight: opts.overnight,
|
|
25866
|
-
codex: opts.codex,
|
|
26115
|
+
codex: opts.codex && consent.codex,
|
|
26116
|
+
claudeCode: consent.claudeCode,
|
|
25867
26117
|
idleGapMin: opts.idleGapMin,
|
|
25868
26118
|
regrade: opts.regrade,
|
|
25869
26119
|
onUpToDate: () => {
|
|
@@ -25872,14 +26122,22 @@ Running the full analysis on ${backend.name === "cli" ? "Claude Code" : "Codex"}
|
|
|
25872
26122
|
earlyHandle.setProgress(progress);
|
|
25873
26123
|
codingLane.finish("everything up to date");
|
|
25874
26124
|
},
|
|
26125
|
+
onNewWork: (pending2) => {
|
|
26126
|
+
codingPinned = false;
|
|
26127
|
+
codingLane.log(` ${pending2} new session(s) to analyze \u2014 updating your report in place.`);
|
|
26128
|
+
},
|
|
25875
26129
|
onStage: (i, total, label, llm) => {
|
|
25876
26130
|
if (codingPinned) return;
|
|
25877
26131
|
progress.coding = { ...progress.coding, i, total, label, done: false };
|
|
25878
26132
|
earlyHandle.setProgress(progress);
|
|
25879
26133
|
codingLane.stage(i, total, `${label}${llm ? " (AI)" : ""}`);
|
|
25880
26134
|
},
|
|
26135
|
+
// While pinned, the scrolling stage output stays quiet ("prints hella
|
|
26136
|
+
// things when everything is cached", owner 2026-07-17) — warnings and
|
|
26137
|
+
// failures always pass through.
|
|
25881
26138
|
onLine: (line) => {
|
|
25882
26139
|
harvestWithin("coding", line);
|
|
26140
|
+
if (codingPinned && !/⚠|error|fail/i.test(line)) return;
|
|
25883
26141
|
codingLane.log(` ${line}`);
|
|
25884
26142
|
}
|
|
25885
26143
|
}).then(async (codingRes2) => {
|
|
@@ -25912,6 +26170,16 @@ Running the full analysis on ${backend.name === "cli" ? "Claude Code" : "Codex"}
|
|
|
25912
26170
|
}
|
|
25913
26171
|
chatLane.log(` chat analysis starting over your ${manifest.exports.included.length} approved source(s) \u2014 same engine as the hosted app.`);
|
|
25914
26172
|
let chatPinned = false;
|
|
26173
|
+
const chatComplete = await fs36.readFile(path41.join(DATA_ROOT, "engine-pilot", "public-report.json"), "utf8").then((s) => {
|
|
26174
|
+
const r = JSON.parse(s);
|
|
26175
|
+
return !!(r.headline && (r.spikes?.length ?? 0) > 0);
|
|
26176
|
+
}).catch(() => false);
|
|
26177
|
+
if (chatComplete) {
|
|
26178
|
+
chatPinned = true;
|
|
26179
|
+
progress.chat = { i: 2, total: 1, label: "up to date \u2014 checking for anything new", done: false };
|
|
26180
|
+
earlyHandle.setProgress(progress);
|
|
26181
|
+
chatLane.finish("up to date \u2014 checking for anything new");
|
|
26182
|
+
}
|
|
25915
26183
|
const chat2 = await runChatPipeline({
|
|
25916
26184
|
repoRoot: REPO_ROOT,
|
|
25917
26185
|
model: opts.model,
|
|
@@ -25922,6 +26190,10 @@ Running the full analysis on ${backend.name === "cli" ? "Claude Code" : "Codex"}
|
|
|
25922
26190
|
earlyHandle.setProgress(progress);
|
|
25923
26191
|
chatLane.finish("everything up to date");
|
|
25924
26192
|
},
|
|
26193
|
+
onNewWork: (pending2) => {
|
|
26194
|
+
chatPinned = false;
|
|
26195
|
+
chatLane.log(` ${pending2} new doc(s) to analyze \u2014 updating your chat report in place.`);
|
|
26196
|
+
},
|
|
25925
26197
|
onStage: (i, total, label, llm) => {
|
|
25926
26198
|
if (chatPinned) return;
|
|
25927
26199
|
progress.chat = { ...progress.chat, i, total, label, done: false };
|
|
@@ -25930,6 +26202,7 @@ Running the full analysis on ${backend.name === "cli" ? "Claude Code" : "Codex"}
|
|
|
25930
26202
|
},
|
|
25931
26203
|
onLine: (line) => {
|
|
25932
26204
|
harvestWithin("chat", line);
|
|
26205
|
+
if (chatPinned && !/⚠|error|fail/i.test(line)) return;
|
|
25933
26206
|
chatLane.log(` ${line}`);
|
|
25934
26207
|
}
|
|
25935
26208
|
});
|
|
@@ -25985,7 +26258,8 @@ No analysis here yet \u2014 computing the instant deterministic metrics now (fre
|
|
|
25985
26258
|
const det = await runPipeline({
|
|
25986
26259
|
repoRoot: REPO_ROOT,
|
|
25987
26260
|
deterministicOnly: true,
|
|
25988
|
-
codex: opts.codex,
|
|
26261
|
+
codex: opts.codex && consent.codex,
|
|
26262
|
+
claudeCode: consent.claudeCode,
|
|
25989
26263
|
idleGapMin: opts.idleGapMin,
|
|
25990
26264
|
onStage: (i, total, label) => dbar.stage(i, total, label),
|
|
25991
26265
|
onLine: (line) => dbar.log(` ${line}`)
|