polymath-society 0.2.20 → 0.2.22

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.
Files changed (38) hide show
  1. package/dist/cli.js +23943 -21630
  2. package/dist/engine/chat-loops.js +8 -1
  3. package/dist/engine/exp-allfacets.js +8 -1
  4. package/dist/engine/exp-person.js +8 -1
  5. package/dist/engine/exp-pipeline.js +8 -1
  6. package/dist/engine/ingest-export.js +7 -6
  7. package/dist/engine/peak-demos.js +8 -1
  8. package/dist/engine/person-dimension-summary.js +8 -1
  9. package/dist/engine/person-facet-lines.js +8 -1
  10. package/dist/engine/person-headline.js +8 -1
  11. package/dist/engine/person-report.js +8 -1
  12. package/dist/engine/person-self-image.js +8 -1
  13. package/dist/engine/public-report.js +15 -7
  14. package/dist/engine/run-analysis.js +8 -1
  15. package/dist/engine/run-tagger.js +8 -1
  16. package/dist/index.js +19647 -17969
  17. package/dist/pipeline/coding-agglomerate.js +826 -82
  18. package/dist/pipeline/coding-aggregate.js +307 -23
  19. package/dist/pipeline/coding-build.js +453 -95
  20. package/dist/pipeline/coding-coaching.js +479 -88
  21. package/dist/pipeline/coding-day-digest.js +308 -36
  22. package/dist/pipeline/coding-delegation.js +376 -52
  23. package/dist/pipeline/coding-expertise.js +356 -62
  24. package/dist/pipeline/coding-flow.js +288 -15
  25. package/dist/pipeline/coding-focus.js +371 -51
  26. package/dist/pipeline/coding-frontier-detail.js +344 -50
  27. package/dist/pipeline/coding-frontier.js +7 -6
  28. package/dist/pipeline/coding-gap-dist.js +288 -15
  29. package/dist/pipeline/coding-gap.js +507 -115
  30. package/dist/pipeline/coding-grade.js +342 -45
  31. package/dist/pipeline/coding-growth.js +17041 -0
  32. package/dist/pipeline/coding-nutshell.js +15 -7
  33. package/dist/pipeline/coding-projects.js +7 -6
  34. package/dist/pipeline/coding-walkthrough.js +317 -37
  35. package/dist/pipeline/coding-workbrief.js +16387 -0
  36. package/dist/web/app.js +2095 -1395
  37. package/dist/web/styles.css +1 -1
  38. package/package.json +1 -1
@@ -134,7 +134,7 @@ var require_secure_json_parse = __commonJS({
134
134
  });
135
135
 
136
136
  // ../../scripts/coding-coaching.mts
137
- import { promises as fs11 } from "fs";
137
+ import { promises as fs12 } from "fs";
138
138
 
139
139
  // ../../lib/agents/shared/agent.ts
140
140
  import { readFileSync } from "fs";
@@ -502,6 +502,13 @@ ${report}`);
502
502
  }
503
503
 
504
504
  // ../../lib/agents/shared/codexAdapter.ts
505
+ var CODEX_DEFAULT_MODEL = "gpt-5.5";
506
+ var CODEX_MINI_MODEL = "gpt-5.4-mini";
507
+ function mapCodexTier(model, env = process.env) {
508
+ if (model && !/^(claude|haiku|sonnet|opus)/i.test(model)) return model;
509
+ if (model && /^haiku/i.test(model)) return env.POLYMATH_CODEX_MODEL_MINI || CODEX_MINI_MODEL;
510
+ return env.POLYMATH_CODEX_MODEL || CODEX_DEFAULT_MODEL;
511
+ }
505
512
  function composePrompt(inv, roots) {
506
513
  return [
507
514
  inv.systemPrompt ? `<system>
@@ -542,7 +549,7 @@ var codexAdapter = {
542
549
  "read-only",
543
550
  "--json"
544
551
  ];
545
- if (inv.model && !/^claude/i.test(inv.model)) args.push("--model", inv.model);
552
+ args.push("--model", mapCodexTier(inv.model));
546
553
  args.push(composePrompt(inv, roots));
547
554
  const started = Date.now();
548
555
  const toolCalls = [];
@@ -2170,8 +2177,8 @@ function getErrorMap() {
2170
2177
 
2171
2178
  // ../../node_modules/zod/v3/helpers/parseUtil.js
2172
2179
  var makeIssue = (params) => {
2173
- const { data, path: path13, errorMaps, issueData } = params;
2174
- const fullPath = [...path13, ...issueData.path || []];
2180
+ const { data, path: path14, errorMaps, issueData } = params;
2181
+ const fullPath = [...path14, ...issueData.path || []];
2175
2182
  const fullIssue = {
2176
2183
  ...issueData,
2177
2184
  path: fullPath
@@ -2287,11 +2294,11 @@ var errorUtil;
2287
2294
 
2288
2295
  // ../../node_modules/zod/v3/types.js
2289
2296
  var ParseInputLazyPath = class {
2290
- constructor(parent, value, path13, key) {
2297
+ constructor(parent, value, path14, key) {
2291
2298
  this._cachedPath = [];
2292
2299
  this.parent = parent;
2293
2300
  this.data = value;
2294
- this._path = path13;
2301
+ this._path = path14;
2295
2302
  this._key = key;
2296
2303
  }
2297
2304
  get path() {
@@ -15078,39 +15085,39 @@ function createOpenAI(options = {}) {
15078
15085
  });
15079
15086
  const createChatModel = (modelId, settings = {}) => new OpenAIChatLanguageModel(modelId, settings, {
15080
15087
  provider: `${providerName}.chat`,
15081
- url: ({ path: path13 }) => `${baseURL}${path13}`,
15088
+ url: ({ path: path14 }) => `${baseURL}${path14}`,
15082
15089
  headers: getHeaders,
15083
15090
  compatibility,
15084
15091
  fetch: options.fetch
15085
15092
  });
15086
15093
  const createCompletionModel = (modelId, settings = {}) => new OpenAICompletionLanguageModel(modelId, settings, {
15087
15094
  provider: `${providerName}.completion`,
15088
- url: ({ path: path13 }) => `${baseURL}${path13}`,
15095
+ url: ({ path: path14 }) => `${baseURL}${path14}`,
15089
15096
  headers: getHeaders,
15090
15097
  compatibility,
15091
15098
  fetch: options.fetch
15092
15099
  });
15093
15100
  const createEmbeddingModel = (modelId, settings = {}) => new OpenAIEmbeddingModel(modelId, settings, {
15094
15101
  provider: `${providerName}.embedding`,
15095
- url: ({ path: path13 }) => `${baseURL}${path13}`,
15102
+ url: ({ path: path14 }) => `${baseURL}${path14}`,
15096
15103
  headers: getHeaders,
15097
15104
  fetch: options.fetch
15098
15105
  });
15099
15106
  const createImageModel = (modelId, settings = {}) => new OpenAIImageModel(modelId, settings, {
15100
15107
  provider: `${providerName}.image`,
15101
- url: ({ path: path13 }) => `${baseURL}${path13}`,
15108
+ url: ({ path: path14 }) => `${baseURL}${path14}`,
15102
15109
  headers: getHeaders,
15103
15110
  fetch: options.fetch
15104
15111
  });
15105
15112
  const createTranscriptionModel = (modelId) => new OpenAITranscriptionModel(modelId, {
15106
15113
  provider: `${providerName}.transcription`,
15107
- url: ({ path: path13 }) => `${baseURL}${path13}`,
15114
+ url: ({ path: path14 }) => `${baseURL}${path14}`,
15108
15115
  headers: getHeaders,
15109
15116
  fetch: options.fetch
15110
15117
  });
15111
15118
  const createSpeechModel = (modelId) => new OpenAISpeechModel(modelId, {
15112
15119
  provider: `${providerName}.speech`,
15113
- url: ({ path: path13 }) => `${baseURL}${path13}`,
15120
+ url: ({ path: path14 }) => `${baseURL}${path14}`,
15114
15121
  headers: getHeaders,
15115
15122
  fetch: options.fetch
15116
15123
  });
@@ -15131,7 +15138,7 @@ function createOpenAI(options = {}) {
15131
15138
  const createResponsesModel = (modelId) => {
15132
15139
  return new OpenAIResponsesLanguageModel(modelId, {
15133
15140
  provider: `${providerName}.responses`,
15134
- url: ({ path: path13 }) => `${baseURL}${path13}`,
15141
+ url: ({ path: path14 }) => `${baseURL}${path14}`,
15135
15142
  headers: getHeaders,
15136
15143
  fetch: options.fetch
15137
15144
  });
@@ -15628,8 +15635,8 @@ function invokeAgent(inv, opts = {}) {
15628
15635
  }
15629
15636
 
15630
15637
  // ../../lib/agents/coding/profile.ts
15631
- import { promises as fs6 } from "fs";
15632
- import path10 from "path";
15638
+ import { promises as fs7 } from "fs";
15639
+ import path11 from "path";
15633
15640
 
15634
15641
  // ../../lib/calibration/fingerprint.ts
15635
15642
  import { createHash } from "node:crypto";
@@ -15775,7 +15782,7 @@ var GRADED_CRITERIA = CODING_CRITERIA.filter((c) => c.graded);
15775
15782
  var RUBRIC_FINGERPRINT = rubricFingerprint(GRADED_CRITERIA);
15776
15783
 
15777
15784
  // ../coding-core/dist/messages.js
15778
- import { promises as fs4 } from "fs";
15785
+ import { promises as fs5 } from "fs";
15779
15786
 
15780
15787
  // ../coding-core/dist/injected.js
15781
15788
  var SYSTEM_REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/g;
@@ -15901,6 +15908,286 @@ function extractCodexEvents(raw) {
15901
15908
  return out;
15902
15909
  }
15903
15910
 
15911
+ // ../coding-core/dist/cursor.js
15912
+ import { promises as fs4 } from "fs";
15913
+ var NODE_SQLITE = "node:sqlite";
15914
+ async function openCursorSqlite(dbPath) {
15915
+ try {
15916
+ await fs4.access(dbPath);
15917
+ } catch {
15918
+ return null;
15919
+ }
15920
+ let mod;
15921
+ try {
15922
+ mod = await import(NODE_SQLITE);
15923
+ } catch {
15924
+ return null;
15925
+ }
15926
+ const DatabaseSync = mod?.DatabaseSync;
15927
+ if (!DatabaseSync)
15928
+ return null;
15929
+ let db;
15930
+ try {
15931
+ db = new DatabaseSync(dbPath, { readOnly: true });
15932
+ } catch {
15933
+ try {
15934
+ db = new DatabaseSync(dbPath);
15935
+ } catch {
15936
+ return null;
15937
+ }
15938
+ }
15939
+ const asText = (v) => v == null ? null : typeof v === "string" ? v : Buffer.from(v).toString("utf-8");
15940
+ return {
15941
+ prefix(prefix) {
15942
+ try {
15943
+ const rows = db.prepare("SELECT key, value FROM cursorDiskKV WHERE key LIKE ? ESCAPE '\\'").all(likePrefix(prefix));
15944
+ return rows.map((r) => ({ key: r.key, value: asText(r.value) ?? "" }));
15945
+ } catch {
15946
+ return [];
15947
+ }
15948
+ },
15949
+ get(key) {
15950
+ try {
15951
+ const row = db.prepare("SELECT value FROM cursorDiskKV WHERE key = ?").get(key);
15952
+ return row ? asText(row.value) : null;
15953
+ } catch {
15954
+ return null;
15955
+ }
15956
+ },
15957
+ close() {
15958
+ try {
15959
+ db.close();
15960
+ } catch {
15961
+ }
15962
+ }
15963
+ };
15964
+ }
15965
+ function likePrefix(prefix) {
15966
+ return prefix.replace(/[\\%_]/g, (c) => "\\" + c) + "%";
15967
+ }
15968
+ var CURSOR_USER_QUERY_RE = /<user_query>\s*([\s\S]*?)\s*<\/user_query>/;
15969
+ function cleanUserText(raw) {
15970
+ let t = raw.replace(SYSTEM_REMINDER_RE, "");
15971
+ const m = t.match(CURSOR_USER_QUERY_RE);
15972
+ if (m)
15973
+ t = m[1];
15974
+ return t.trim();
15975
+ }
15976
+ var msFrom = (v) => {
15977
+ if (typeof v === "number" && Number.isFinite(v))
15978
+ return v;
15979
+ if (typeof v === "string") {
15980
+ const n = Date.parse(v);
15981
+ return Number.isFinite(n) ? n : null;
15982
+ }
15983
+ return null;
15984
+ };
15985
+ function readCursorComposer(db, composerId) {
15986
+ const cdRaw = db.get(`composerData:${composerId}`);
15987
+ if (!cdRaw)
15988
+ return null;
15989
+ let cd;
15990
+ try {
15991
+ cd = JSON.parse(cdRaw);
15992
+ } catch {
15993
+ return null;
15994
+ }
15995
+ const headers = Array.isArray(cd.fullConversationHeadersOnly) ? cd.fullConversationHeadersOnly : [];
15996
+ if (headers.length === 0)
15997
+ return null;
15998
+ const bubbles = /* @__PURE__ */ new Map();
15999
+ for (const row of db.prefix(`bubbleId:${composerId}:`)) {
16000
+ const bid = row.key.slice(`bubbleId:${composerId}:`.length);
16001
+ try {
16002
+ bubbles.set(bid, JSON.parse(row.value));
16003
+ } catch {
16004
+ }
16005
+ }
16006
+ const turns = [];
16007
+ let clock = msFrom(cd.createdAt) ?? 0;
16008
+ for (const h of headers) {
16009
+ const b = bubbles.get(h.bubbleId);
16010
+ if (!b)
16011
+ continue;
16012
+ const type = h.type === 1 ? 1 : 2;
16013
+ const tool2 = type === 2 && b.toolFormerData && typeof b.toolFormerData.name === "string" ? b.toolFormerData.name : null;
16014
+ const rawText = typeof b.text === "string" ? b.text : "";
16015
+ const text2 = type === 1 ? cleanUserText(rawText) : rawText.replace(SYSTEM_REMINDER_RE, "").trim();
16016
+ if (!text2 && !tool2)
16017
+ continue;
16018
+ const t = msFrom(b.createdAt);
16019
+ clock = Math.max(clock, t ?? clock + 1);
16020
+ const model = b.modelInfo && typeof b.modelInfo.modelName === "string" ? b.modelInfo.modelName : null;
16021
+ turns.push({ t: clock, type, text: text2, tool: tool2, model });
16022
+ }
16023
+ if (turns.length === 0)
16024
+ return null;
16025
+ const gitRepo = Array.isArray(cd.trackedGitRepos) && cd.trackedGitRepos[0] && typeof cd.trackedGitRepos[0].repoPath === "string" ? cd.trackedGitRepos[0].repoPath : null;
16026
+ return {
16027
+ composerId,
16028
+ createdAt: msFrom(cd.createdAt),
16029
+ updatedAt: msFrom(cd.lastUpdatedAt),
16030
+ name: typeof cd.name === "string" && cd.name.trim() ? cd.name.trim() : null,
16031
+ gitRepo,
16032
+ turns
16033
+ };
16034
+ }
16035
+ function sniffCursorRaw(raw) {
16036
+ for (const lineRaw of raw.split("\n")) {
16037
+ const line = lineRaw.trim();
16038
+ if (!line)
16039
+ continue;
16040
+ try {
16041
+ const e = JSON.parse(line);
16042
+ return (e.role === "user" || e.role === "assistant") && typeof e.message === "object" && e.message !== null && "content" in e.message && !("type" in e);
16043
+ } catch {
16044
+ return false;
16045
+ }
16046
+ }
16047
+ return false;
16048
+ }
16049
+ function jsonlText(content) {
16050
+ const parts = [];
16051
+ const tools = [];
16052
+ if (Array.isArray(content)) {
16053
+ for (const item of content) {
16054
+ if (!item || typeof item !== "object")
16055
+ continue;
16056
+ const it = item;
16057
+ if (it.type === "text" && it.text)
16058
+ parts.push(it.text);
16059
+ else if (it.type === "tool_use" && it.name)
16060
+ tools.push(it.name);
16061
+ }
16062
+ } else if (typeof content === "string")
16063
+ parts.push(content);
16064
+ return { text: parts.join("\n"), tools };
16065
+ }
16066
+ function parseCursorJsonl(raw, base) {
16067
+ const turns = [];
16068
+ let clock = base;
16069
+ for (const lineRaw of raw.split("\n")) {
16070
+ const line = lineRaw.trim();
16071
+ if (!line)
16072
+ continue;
16073
+ let e;
16074
+ try {
16075
+ e = JSON.parse(line);
16076
+ } catch {
16077
+ continue;
16078
+ }
16079
+ if (e.role !== "user" && e.role !== "assistant")
16080
+ continue;
16081
+ const { text: rawText, tools } = jsonlText(e.message?.content);
16082
+ const type = e.role === "user" ? 1 : 2;
16083
+ const text2 = type === 1 ? cleanUserText(rawText) : rawText.replace(SYSTEM_REMINDER_RE, "").trim();
16084
+ if (type === 2 && tools.length) {
16085
+ for (const tool2 of tools) {
16086
+ clock += 1;
16087
+ turns.push({ t: clock, type: 2, text: "", tool: tool2, model: null });
16088
+ }
16089
+ }
16090
+ if (!text2)
16091
+ continue;
16092
+ clock += 1;
16093
+ turns.push({ t: clock, type, text: text2, tool: null, model: null });
16094
+ }
16095
+ if (turns.length === 0)
16096
+ return null;
16097
+ return { composerId: "", createdAt: base, updatedAt: clock, name: null, gitRepo: null, turns };
16098
+ }
16099
+ var AI_GIST = 500;
16100
+ function renderCursorTranscript(c) {
16101
+ const lines = [];
16102
+ let humanTurns = 0, humanChars = 0;
16103
+ let aiProse = "";
16104
+ const aiTools = /* @__PURE__ */ new Map();
16105
+ const flushAI = () => {
16106
+ if (!aiProse && aiTools.size === 0)
16107
+ return;
16108
+ const tools = [...aiTools.entries()].map(([n, k]) => k > 1 ? `${n}\xD7${k}` : n).join(", ");
16109
+ const gist = aiProse ? aiProse.length > AI_GIST ? aiProse.slice(0, AI_GIST) + "\u2026" : aiProse : "";
16110
+ const bits = [];
16111
+ if (gist)
16112
+ bits.push(gist);
16113
+ if (tools)
16114
+ bits.push(`ran ${tools}`);
16115
+ lines.push(`[AI: ${bits.join(" \xB7 ")}]`);
16116
+ aiProse = "";
16117
+ aiTools.clear();
16118
+ };
16119
+ for (const turn of c.turns) {
16120
+ if (turn.type === 1) {
16121
+ flushAI();
16122
+ humanTurns++;
16123
+ humanChars += turn.text.length;
16124
+ lines.push(`>> ${turn.text}`);
16125
+ } else {
16126
+ if (turn.tool)
16127
+ aiTools.set(turn.tool, (aiTools.get(turn.tool) ?? 0) + 1);
16128
+ if (turn.text)
16129
+ aiProse = turn.text.replace(/\s+/g, " ").trim();
16130
+ }
16131
+ }
16132
+ flushAI();
16133
+ return { text: lines.join("\n"), humanTurns, humanChars };
16134
+ }
16135
+ function composerIdFromFile(file2) {
16136
+ const m = file2.match(/agent-transcripts\/([^/]+)\/[^/]+\.jsonl$/);
16137
+ return m ? m[1] : null;
16138
+ }
16139
+ async function loadCursorComposer(file2, raw, dbPath) {
16140
+ const cid = composerIdFromFile(file2);
16141
+ if (cid && dbPath) {
16142
+ const db = await openCursorSqlite(dbPath);
16143
+ if (db) {
16144
+ try {
16145
+ const c = readCursorComposer(db, cid);
16146
+ if (c)
16147
+ return c;
16148
+ } finally {
16149
+ db.close();
16150
+ }
16151
+ }
16152
+ }
16153
+ return parseCursorJsonl(raw, 0);
16154
+ }
16155
+
16156
+ // ../coding-core/dist/raw.js
16157
+ import path9 from "path";
16158
+ import os2 from "os";
16159
+ var SOURCE_ROOT_ENV_VARS = [
16160
+ "CLAUDE_PROJECTS_DIR",
16161
+ "CODEX_SESSIONS_DIR",
16162
+ "CURSOR_WORKSPACE_DIR",
16163
+ "CURSOR_PROJECTS_DIR",
16164
+ // Cursor's globalStorage dir (holds state.vscdb — the composer bubbles that
16165
+ // carry a Cursor session's real per-turn timestamps + content). Same
16166
+ // isolation contract: overriding any root disables every unset source.
16167
+ "CURSOR_GLOBAL_DIR"
16168
+ ];
16169
+ var anyRootOverridden = () => SOURCE_ROOT_ENV_VARS.some((v) => !!process.env[v]);
16170
+ function resolveSourceRoot(envVar, ...defaultSegments) {
16171
+ const explicit = process.env[envVar];
16172
+ if (explicit)
16173
+ return explicit;
16174
+ if (anyRootOverridden())
16175
+ return null;
16176
+ return path9.join(os2.homedir(), ...defaultSegments);
16177
+ }
16178
+ var cursorGlobalRoot = () => resolveSourceRoot("CURSOR_GLOBAL_DIR", "Library", "Application Support", "Cursor", "User", "globalStorage");
16179
+ function cursorGlobalDbPath() {
16180
+ const root = cursorGlobalRoot();
16181
+ return root === null ? null : path9.join(root, "state.vscdb");
16182
+ }
16183
+ var MACHINE_CURSOR_FILE_RE = /^(.*[/\\]machines[/\\][^/\\]+[/\\]\.cursor)[/\\]projects[/\\]/;
16184
+ function cursorDbPathForFile(file2) {
16185
+ const m = file2.match(MACHINE_CURSOR_FILE_RE);
16186
+ if (m)
16187
+ return path9.join(m[1], "globalStorage", "state.vscdb");
16188
+ return cursorGlobalDbPath();
16189
+ }
16190
+
15904
16191
  // ../coding-core/dist/messages.js
15905
16192
  function extractText(content) {
15906
16193
  if (typeof content === "string")
@@ -15928,15 +16215,35 @@ function extractUserMessagesCodex(raw) {
15928
16215
  }
15929
16216
  return out.sort((a, b) => a.t - b.t);
15930
16217
  }
16218
+ function extractUserMessagesCursor(c) {
16219
+ const out = [];
16220
+ let lastTs = null;
16221
+ for (const turn of c.turns) {
16222
+ const t = turn.t;
16223
+ const gapMs = Number.isFinite(t) && lastTs != null ? t - lastTs : NaN;
16224
+ if (Number.isFinite(t))
16225
+ lastTs = t;
16226
+ if (turn.type !== 1)
16227
+ continue;
16228
+ const text2 = humanTypedText(turn.text);
16229
+ if (text2 && Number.isFinite(t))
16230
+ out.push({ t, text: text2, gapMs });
16231
+ }
16232
+ return out.sort((a, b) => a.t - b.t);
16233
+ }
15931
16234
  async function extractUserMessages(file2) {
15932
16235
  let raw;
15933
16236
  try {
15934
- raw = await fs4.readFile(file2, "utf-8");
16237
+ raw = await fs5.readFile(file2, "utf-8");
15935
16238
  } catch {
15936
16239
  return [];
15937
16240
  }
15938
16241
  if (sniffCodexRaw(raw))
15939
16242
  return extractUserMessagesCodex(raw);
16243
+ if (sniffCursorRaw(raw)) {
16244
+ const c = await loadCursorComposer(file2, raw, cursorDbPathForFile(file2));
16245
+ return c ? extractUserMessagesCursor(c) : [];
16246
+ }
15940
16247
  const out = [];
15941
16248
  const userTexts = /* @__PURE__ */ new Set();
15942
16249
  const seenUuids = /* @__PURE__ */ new Set();
@@ -15983,11 +16290,11 @@ async function extractUserMessages(file2) {
15983
16290
  }
15984
16291
 
15985
16292
  // ../../lib/agents/coding/walkthrough.ts
15986
- import { promises as fs5 } from "fs";
15987
- import path9 from "path";
16293
+ import { promises as fs6 } from "fs";
16294
+ import path10 from "path";
15988
16295
  var IDLE_CAP_MS = 12 * 6e4;
15989
16296
  async function readWalkthrough(outDir, sessionId) {
15990
- return fs5.readFile(path9.join(outDir, `${sessionId}.json`), "utf8").then(JSON.parse).catch(() => null);
16297
+ return fs6.readFile(path10.join(outDir, `${sessionId}.json`), "utf8").then(JSON.parse).catch(() => null);
15991
16298
  }
15992
16299
 
15993
16300
  // ../coding-core/dist/words.js
@@ -16399,7 +16706,7 @@ function computeWorkstyle(inp) {
16399
16706
 
16400
16707
  // ../../lib/calibration/index.ts
16401
16708
  var DEFAULT_CALIBRATION = {
16402
- version: "2026-07-16.2",
16709
+ version: "2026-07-21.1",
16403
16710
  // = RUBRIC_FINGERPRINT of the shipped npm rubric (packages/coding-analyzer/
16404
16711
  // src/grade/criteria.ts). A unit test fails loud when the rubric changes
16405
16712
  // without this being updated (and re-pushed to the server).
@@ -16495,13 +16802,14 @@ var DEFAULT_CALIBRATION = {
16495
16802
  },
16496
16803
  codingBenchmarks: {
16497
16804
  flow: {
16498
- // typical knowledge worker ≈ 35% of an 8h day focused; ~4h/day is the
16499
- // recognized deep-work ceiling (Newport) 50% most sit far below it.
16805
+ // typical knowledge worker ≈ 35% of an 8h day focused; the ~4h/day
16806
+ // deep-work ceiling (Newport) sits nearer ~40% of a real (9-10h) top
16807
+ // performer's day — 50% overstated it (owner call 2026-07-21).
16500
16808
  typicalPctOfDay: 0.35,
16501
- topPctOfDay: 0.5,
16809
+ topPctOfDay: 0.4,
16502
16810
  tag: "measured",
16503
- source: "RescueTime 2019 (~2h48m focused/day) \xB7 Cal Newport, Deep Work (~4h/day deep-work ceiling)",
16504
- line: "the best spend ~half the workday in true deep flow; ~4h/day is the human ceiling"
16811
+ source: "RescueTime 2019 (~2h48m focused/day) \xB7 Cal Newport, Deep Work (~4h/day deep-work ceiling against a 9-10h day)",
16812
+ line: "the best spend ~40% of the workday in true deep flow; ~4h/day is the human ceiling"
16505
16813
  },
16506
16814
  longestRun: {
16507
16815
  typicalHours: 0.67,
@@ -16550,13 +16858,20 @@ function bandLabel(score, doc = DEFAULT_CALIBRATION) {
16550
16858
  for (const b of doc.scoreBands) if (b.score <= s && (!best || b.score > best.score)) best = b;
16551
16859
  return (best ?? doc.scoreBands[0]).label;
16552
16860
  }
16861
+ function scoreForTopPct(topPct, doc = DEFAULT_CALIBRATION) {
16862
+ for (const b of doc.scoreBands) {
16863
+ const x = parseFloat(b.label.replace(/^Top\s+/i, ""));
16864
+ if (Number.isFinite(x) && topPct <= x) return b.score;
16865
+ }
16866
+ return 1;
16867
+ }
16553
16868
 
16554
16869
  // ../../lib/agents/coding/benchmarks.ts
16555
16870
  var BEST = DEFAULT_CALIBRATION.codingBenchmarks;
16556
16871
 
16557
16872
  // ../../lib/agents/coding/profile.ts
16558
16873
  var ROOT = process.cwd();
16559
- var CODING_DIR = process.env.POLYMATH_DATA_DIR ? path10.join(process.env.POLYMATH_DATA_DIR, "coding") : path10.join(ROOT, ".data", "coding");
16874
+ var CODING_DIR = process.env.POLYMATH_DATA_DIR ? path11.join(process.env.POLYMATH_DATA_DIR, "coding") : path11.join(ROOT, ".data", "coding");
16560
16875
  var UMETA = /* @__PURE__ */ new Map();
16561
16876
  async function userMeta(sessionId, file2) {
16562
16877
  const hit = UMETA.get(sessionId);
@@ -16566,9 +16881,9 @@ async function userMeta(sessionId, file2) {
16566
16881
  UMETA.set(sessionId, meta);
16567
16882
  return meta;
16568
16883
  }
16569
- var GRADES = path10.join(CODING_DIR, "grades");
16884
+ var GRADES = path11.join(CODING_DIR, "grades");
16570
16885
  async function readJson(p, fallback) {
16571
- return fs6.readFile(p, "utf8").then((s) => JSON.parse(s)).catch(() => fallback);
16886
+ return fs7.readFile(p, "utf8").then((s) => JSON.parse(s)).catch(() => fallback);
16572
16887
  }
16573
16888
  function cadenceScore(fraction, multiRatio) {
16574
16889
  let s;
@@ -16608,21 +16923,27 @@ var NO_GRADES_GAP = "no sessions graded for this yet \u2014 this fills in once g
16608
16923
  function estimateRowParts(score, nTakes, evidenceGap) {
16609
16924
  return nTakes === 0 && score == null ? { score: null, gap: NO_GRADES_GAP } : { score, gap: evidenceGap };
16610
16925
  }
16926
+ function verdictRowParts(v, fallback) {
16927
+ if (!v) return fallback;
16928
+ const ranged = v.confidence === "provisional" || (v.qualifying ?? 0) < 2;
16929
+ if (ranged) return { score: null, gap: `best ${v.best} inside an honest ${v.low}-${v.high} range so far. ${v.verdictLine} (${v.statsLine})`.trim() };
16930
+ return { score: v.best, gap: `${v.verdictLine} (${v.statsLine})`.trim() };
16931
+ }
16611
16932
  async function compileCodingProfile() {
16612
- const allRecords = await readJson(path10.join(CODING_DIR, "sessions.json"), []);
16933
+ const allRecords = await readJson(path11.join(CODING_DIR, "sessions.json"), []);
16613
16934
  const dupIds = new Set(allRecords.filter((s) => s.duplicateOf).map((s) => s.sessionId));
16614
16935
  const sessions = allRecords.filter((s) => !s.duplicateOf);
16615
- const conc = await readJson(path10.join(CODING_DIR, "concurrency.json"), null);
16616
- const renames = await readJson(path10.join(CODING_DIR, "renames.json"), []);
16936
+ const conc = await readJson(path11.join(CODING_DIR, "concurrency.json"), null);
16937
+ const renames = await readJson(path11.join(CODING_DIR, "renames.json"), []);
16617
16938
  const byId = new Map(sessions.map((s) => [s.sessionId, s]));
16618
16939
  let gradeFiles = [];
16619
16940
  try {
16620
- gradeFiles = (await fs6.readdir(GRADES)).filter((f) => f.endsWith(".json"));
16941
+ gradeFiles = (await fs7.readdir(GRADES)).filter((f) => f.endsWith(".json"));
16621
16942
  } catch {
16622
16943
  }
16623
16944
  const grades = [];
16624
16945
  for (const f of gradeFiles) {
16625
- const g = await readJson(path10.join(GRADES, f), null);
16946
+ const g = await readJson(path11.join(GRADES, f), null);
16626
16947
  if (g && byId.has(g.sessionId)) grades.push(g);
16627
16948
  }
16628
16949
  const takesByCriterion = /* @__PURE__ */ new Map();
@@ -16699,9 +17020,12 @@ async function compileCodingProfile() {
16699
17020
  const timeline = [...dayMap.values()].sort((a, b) => b.date.localeCompare(a.date));
16700
17021
  const levelHist = conc?.levelHistogramMin ?? {};
16701
17022
  const sumFrom = (min) => Object.entries(levelHist).filter(([k]) => Number(k) >= min).reduce((a, [, v]) => a + v, 0);
17023
+ const totalParallelMin = Object.values(levelHist).reduce((a, v) => a + v, 0);
17024
+ const avgConcurrency = totalParallelMin > 0 ? Math.round(Object.entries(levelHist).reduce((a, [k, v]) => a + Number(k) * v, 0) / totalParallelMin * 10) / 10 : 0;
16702
17025
  const topWindows = (conc?.segments ?? []).slice().sort((a, b) => b.level - a.level || b.minutes - a.minutes).slice(0, 12).map((s) => ({ start: s.start, end: s.end, minutes: s.minutes, level: s.level, titles: [...new Set(s.sessions.map((x) => x.title))] }));
16703
17026
  const parallelism = {
16704
17027
  maxConcurrency: conc?.maxConcurrency ?? 0,
17028
+ avgConcurrency,
16705
17029
  levelHistogramMin: levelHist,
16706
17030
  minutesAt2plus: Math.round(sumFrom(2)),
16707
17031
  minutesAt6plus: Math.round(sumFrom(6)),
@@ -16731,13 +17055,13 @@ async function compileCodingProfile() {
16731
17055
  models: Object.fromEntries([...models.entries()].sort((a, b) => b[1] - a[1])),
16732
17056
  lateNightSessions: lateNight
16733
17057
  };
16734
- const agglomeration = await readJson(path10.join(CODING_DIR, "agglomerate.json"), null);
16735
- const dayDigest = await readJson(path10.join(CODING_DIR, "day-digest.json"), null);
17058
+ const agglomeration = await readJson(path11.join(CODING_DIR, "agglomerate.json"), null);
17059
+ const dayDigest = await readJson(path11.join(CODING_DIR, "day-digest.json"), null);
16736
17060
  if (dayDigest?.days) dayDigest.days = dayDigest.days.map((day) => {
16737
17061
  const convs = day.conversations.filter((c) => byId.has(c.sessionId));
16738
17062
  return { ...day, conversations: convs, conversationsTouched: convs.length, totalMessages: convs.reduce((a, c) => a + c.messageCount, 0) };
16739
17063
  }).filter((day) => day.conversations.length > 0);
16740
- const dayChart = await readJson(path10.join(CODING_DIR, "day-chart.json"), []);
17064
+ const dayChart = await readJson(path11.join(CODING_DIR, "day-chart.json"), []);
16741
17065
  const intervalsBy = /* @__PURE__ */ new Map();
16742
17066
  const titleBy = /* @__PURE__ */ new Map();
16743
17067
  const fileById = new Map(sessions.map((s) => [s.sessionId, s.file]));
@@ -16756,8 +17080,8 @@ async function compileCodingProfile() {
16756
17080
  return ms;
16757
17081
  };
16758
17082
  const walkthroughs = {};
16759
- const wdir = path10.join(CODING_DIR, "walkthroughs");
16760
- for (const f of await fs6.readdir(wdir).catch(() => [])) {
17083
+ const wdir = path11.join(CODING_DIR, "walkthroughs");
17084
+ for (const f of await fs7.readdir(wdir).catch(() => [])) {
16761
17085
  if (!f.endsWith(".json")) continue;
16762
17086
  const w = await readWalkthrough(wdir, f.replace(".json", ""));
16763
17087
  if (!w || !byId.has(w.sessionId)) continue;
@@ -16804,17 +17128,19 @@ async function compileCodingProfile() {
16804
17128
  const tCeiling = throughputCeiling(Object.values(wordsByDay));
16805
17129
  const criteriaMean = {};
16806
17130
  for (const c of criteria) criteriaMean[c.key] = { mean: c.dist.mean, n: c.dist.n };
16807
- const flow = await readJson(path10.join(CODING_DIR, "flow.json"), null);
16808
- const focus = await readJson(path10.join(CODING_DIR, "focus.json"), null);
16809
- const expertiseMap = await readJson(path10.join(CODING_DIR, "expertise.json"), null);
16810
- const frontierArsenal = await readJson(path10.join(CODING_DIR, "frontier.json"), null);
16811
- const frontierDetail = await readJson(path10.join(CODING_DIR, "frontier-detail.json"), null);
16812
- const coaching = await readJson(path10.join(CODING_DIR, "coaching.json"), null);
16813
- const gap = await readJson(path10.join(CODING_DIR, "gap.json"), null);
16814
- const aggregate = await readJson(path10.join(CODING_DIR, "aggregate.json"), null);
16815
- const delegationRollup = await readJson(path10.join(CODING_DIR, "delegation-rollup.json"), null);
16816
- const gapDist = await readJson(path10.join(CODING_DIR, "gap-dist.json"), null);
16817
- const projects = await readJson(path10.join(CODING_DIR, "projects.json"), null);
17131
+ const flow = await readJson(path11.join(CODING_DIR, "flow.json"), null);
17132
+ const focus = await readJson(path11.join(CODING_DIR, "focus.json"), null);
17133
+ const expertiseMap = await readJson(path11.join(CODING_DIR, "expertise.json"), null);
17134
+ const frontierArsenal = await readJson(path11.join(CODING_DIR, "frontier.json"), null);
17135
+ const frontierDetail = await readJson(path11.join(CODING_DIR, "frontier-detail.json"), null);
17136
+ const coaching = await readJson(path11.join(CODING_DIR, "coaching.json"), null);
17137
+ const gap = await readJson(path11.join(CODING_DIR, "gap.json"), null);
17138
+ const aggregate = await readJson(path11.join(CODING_DIR, "aggregate.json"), null);
17139
+ const delegationRollup = await readJson(path11.join(CODING_DIR, "delegation-rollup.json"), null);
17140
+ const gapDist = await readJson(path11.join(CODING_DIR, "gap-dist.json"), null);
17141
+ const projects = await readJson(path11.join(CODING_DIR, "projects.json"), null);
17142
+ const growth = await readJson(path11.join(CODING_DIR, "growth.json"), null);
17143
+ const workbrief = await readJson(path11.join(CODING_DIR, "workbrief.json"), null);
16818
17144
  const workstyle = computeWorkstyle({
16819
17145
  dayChart,
16820
17146
  tz,
@@ -16874,15 +17200,25 @@ async function compileCodingProfile() {
16874
17200
  const hoursPctl = lognPct(workDayHrs, tiers?.hours);
16875
17201
  const hoursAt = (min) => Object.entries(pHist).reduce((a, [k, v]) => Number(k) >= min ? a + v : a, 0) / 60;
16876
17202
  const orchPctl = hoursAt(5) >= 5 || hoursAt(3) >= 10 && parallelism.queueOps >= 1e3 ? 99.5 : hoursAt(3) >= 10 ? 99 : hoursAt(2) >= 0.1 * (soloMin + parMin) / 60 ? 97 : hoursAt(2) >= 2 ? 90 : 70;
17203
+ const estScore = (pctl) => pctl == null ? null : scoreForTopPct(100 - pctl);
16877
17204
  const stackUp = [
17205
+ // The subtext leads with the AVERAGE — that is the number this row is
17206
+ // scored and pool-ranked on (wordsPerDay); a peak-led line once shipped
17207
+ // next to an average-based rank and read as a mismatch (owner call
17208
+ // 2026-07-21). The peak rides along as color.
16878
17209
  sRow(
16879
17210
  "How hard you push",
16880
- aggregate?.throughput?.score ?? tCeiling,
16881
- `you peak at ~${peakWords.toLocaleString()} words of pure direction in a single day \u2014 the very top sustain ~${BEST.throughput.topAvgWordsPerDay.toLocaleString()} every day, week after week; the wildest single days on record push ~${BEST.throughput.topPeakWordsPerDay.toLocaleString()}`
17211
+ estScore(pushPctl) ?? aggregate?.throughput?.score ?? tCeiling,
17212
+ avgWords != null ? `you average ~${Math.round(avgWords).toLocaleString()} words of pure direction a day (peak day ~${peakWords.toLocaleString()}) \u2014 the very top sustain ~${BEST.throughput.topAvgWordsPerDay.toLocaleString()} every day, week after week; the wildest single days on record push ~${BEST.throughput.topPeakWordsPerDay.toLocaleString()}` : `you peak at ~${peakWords.toLocaleString()} words of pure direction in a single day \u2014 the very top sustain ~${BEST.throughput.topAvgWordsPerDay.toLocaleString()} every day, week after week`
16882
17213
  ),
17214
+ // Graded like its siblings from the SAME fitted hours curve that ranks it
17215
+ // (tiers.hours → hoursPctl → estScore) and feeds the shared pool, so the
17216
+ // 1-11 badge can never contradict the pooled rank. Was `null` until
17217
+ // 2026-07-21, which left this the only measured row with no grade shown —
17218
+ // it read as broken next to push/parallelism/focus (owner call).
16883
17219
  sRow(
16884
17220
  "Hours you put in",
16885
- null,
17221
+ estScore(hoursPctl),
16886
17222
  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"
16887
17223
  ),
16888
17224
  // The copy FOLLOWS the person's actual orchestration band (orchPctl above) —
@@ -16893,7 +17229,7 @@ async function compileCodingProfile() {
16893
17229
  // orchestration.
16894
17230
  sRow(
16895
17231
  "Your AI parallelism",
16896
- ceilOf("delegation"),
17232
+ estScore(orchPctl),
16897
17233
  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"
16898
17234
  ),
16899
17235
  // The evidence line cites the RANKING metric (flow as a share of the work
@@ -16904,7 +17240,7 @@ async function compileCodingProfile() {
16904
17240
  // the volume of hours is its own chip above.
16905
17241
  sRow(
16906
17242
  "Focus quality when you work",
16907
- focusScore,
17243
+ estScore(focusPctl) ?? focusScore,
16908
17244
  flowPctDay != null ? `~${Math.round(flowPctDay * 100)}% of your work day is true deep flow${flowHrsDay != null ? ` (~${flowHrsDay}h)` : ""} \u2014 the very best hold ~${Math.round(BEST.flow.topPctOfDay * 100)}% of theirs in one unbroken block; yours fragments across parallel sessions, so the gain is directing your attention at one thread for longer` : "your attention scatters across parallel sessions \u2014 directing it at one thread for longer is the unlock"
16909
17245
  ),
16910
17246
  // The four estimates LEAD with a concrete moment from their own sessions, then an
@@ -16953,24 +17289,39 @@ async function compileCodingProfile() {
16953
17289
  }
16954
17290
  if (r.label === "Your AI parallelism") r.percentile = orchPctl;
16955
17291
  }
16956
- return { generatedAt: (/* @__PURE__ */ new Date()).toISOString(), gradedSessions: grades.length, agglomeration, outcomeCadence, dayDigest, dayChart, timeline, walkthroughs, rubric, wordsByDay, dayThroughput, throughputCeiling: tCeiling, stackUp, criteria, parallelism, throughput, workstyle, flow, focus, expertiseMap, frontierArsenal, frontierDetail, coaching, gap, aggregate, delegationRollup, gapDist, projects };
17292
+ if (agglomeration?.verdicts) {
17293
+ const byLabel = {
17294
+ Judgement: agglomeration.verdicts.judgement,
17295
+ Agency: agglomeration.verdicts.agency,
17296
+ Taste: agglomeration.verdicts.taste
17297
+ };
17298
+ for (const r of stackUp) {
17299
+ const v = byLabel[r.label];
17300
+ if (!v) continue;
17301
+ const p = verdictRowParts(v, { score: r.score, gap: r.gap });
17302
+ r.score = p.score;
17303
+ r.gap = p.gap;
17304
+ r.percentile = pctOf(p.score);
17305
+ }
17306
+ }
17307
+ return { generatedAt: (/* @__PURE__ */ new Date()).toISOString(), gradedSessions: grades.length, agglomeration, outcomeCadence, dayDigest, dayChart, timeline, walkthroughs, rubric, wordsByDay, dayThroughput, throughputCeiling: tCeiling, stackUp, criteria, parallelism, throughput, workstyle, flow, focus, expertiseMap, frontierArsenal, frontierDetail, coaching, gap, aggregate, delegationRollup, gapDist, projects, growth, workbrief };
16957
17308
  }
16958
17309
 
16959
17310
  // ../../lib/agents/coding/assets.ts
16960
- import { promises as fs7 } from "fs";
16961
- import path11 from "path";
17311
+ import { promises as fs8 } from "fs";
17312
+ import path12 from "path";
16962
17313
  import { fileURLToPath } from "url";
16963
- var MODULE_DIR = path11.dirname(fileURLToPath(import.meta.url));
17314
+ var MODULE_DIR = path12.dirname(fileURLToPath(import.meta.url));
16964
17315
  async function readCodingAsset(name17) {
16965
17316
  const candidates = [
16966
- path11.join(MODULE_DIR, name17),
17317
+ path12.join(MODULE_DIR, name17),
16967
17318
  // dev: beside this file · bundled: beside the bundle
16968
- path11.resolve("lib", "agents", "coding", name17)
17319
+ path12.resolve("lib", "agents", "coding", name17)
16969
17320
  // legacy cwd-relative (repo-root cwd)
16970
17321
  ];
16971
17322
  for (const p of candidates) {
16972
17323
  try {
16973
- return { text: await fs7.readFile(p, "utf8"), path: p };
17324
+ return { text: await fs8.readFile(p, "utf8"), path: p };
16974
17325
  } catch {
16975
17326
  }
16976
17327
  }
@@ -16980,11 +17331,11 @@ async function readCodingAsset(name17) {
16980
17331
  }
16981
17332
 
16982
17333
  // ../../lib/agents/coding/docsDir.ts
16983
- import { promises as fs9 } from "fs";
16984
- import path12 from "path";
17334
+ import { promises as fs10 } from "fs";
17335
+ import path13 from "path";
16985
17336
 
16986
17337
  // ../../lib/agents/coding/materialize.ts
16987
- import { promises as fs8 } from "fs";
17338
+ import { promises as fs9 } from "fs";
16988
17339
  var SYSTEM_REMINDER_RE3 = /<system-reminder>[\s\S]*?<\/system-reminder>/g;
16989
17340
  var INJECT_GIST = 120;
16990
17341
  var INJECTED = [
@@ -17021,7 +17372,7 @@ function extractText2(content) {
17021
17372
  function isToolResultOnly2(content) {
17022
17373
  return Array.isArray(content) && content.length > 0 && content.every((c) => c && typeof c === "object" && c.type === "tool_result");
17023
17374
  }
17024
- var AI_GIST = 160;
17375
+ var AI_GIST2 = 160;
17025
17376
  function materializeCodex(raw) {
17026
17377
  const lines = [];
17027
17378
  let humanTurns = 0, humanChars = 0;
@@ -17030,7 +17381,7 @@ function materializeCodex(raw) {
17030
17381
  const flushAI = () => {
17031
17382
  if (!aiLastProse && aiTools.size === 0) return;
17032
17383
  const tools = [...aiTools.entries()].map(([n, c]) => c > 1 ? `${n}\xD7${c}` : n).join(", ");
17033
- const gist = aiLastProse ? aiLastProse.length > AI_GIST ? aiLastProse.slice(0, AI_GIST) + "\u2026" : aiLastProse : "";
17384
+ const gist = aiLastProse ? aiLastProse.length > AI_GIST2 ? aiLastProse.slice(0, AI_GIST2) + "\u2026" : aiLastProse : "";
17034
17385
  const bits = [];
17035
17386
  if (gist) bits.push(gist);
17036
17387
  if (tools) bits.push(`ran ${tools}`);
@@ -17054,14 +17405,19 @@ function materializeCodex(raw) {
17054
17405
  flushAI();
17055
17406
  return { text: lines.join("\n"), humanTurns, humanChars };
17056
17407
  }
17408
+ async function materializeCursor(file2, raw) {
17409
+ const composer = await loadCursorComposer(file2, raw, cursorDbPathForFile(file2));
17410
+ return composer ? renderCursorTranscript(composer) : { text: "", humanTurns: 0, humanChars: 0 };
17411
+ }
17057
17412
  async function materializeSession(file2) {
17058
17413
  let raw;
17059
17414
  try {
17060
- raw = await fs8.readFile(file2, "utf-8");
17415
+ raw = await fs9.readFile(file2, "utf-8");
17061
17416
  } catch {
17062
17417
  return null;
17063
17418
  }
17064
17419
  if (sniffCodexRaw(raw)) return materializeCodex(raw);
17420
+ if (sniffCursorRaw(raw)) return materializeCursor(file2, raw);
17065
17421
  const lines = [];
17066
17422
  let humanTurns = 0, humanChars = 0;
17067
17423
  const pendingQueued = [];
@@ -17074,7 +17430,7 @@ async function materializeSession(file2) {
17074
17430
  const flushAI = () => {
17075
17431
  if (!aiLastProse && aiTools.size === 0) return;
17076
17432
  const tools = [...aiTools.entries()].map(([n, c]) => c > 1 ? `${n}\xD7${c}` : n).join(", ");
17077
- const gist = aiLastProse ? aiLastProse.length > AI_GIST ? aiLastProse.slice(0, AI_GIST) + "\u2026" : aiLastProse : "";
17433
+ const gist = aiLastProse ? aiLastProse.length > AI_GIST2 ? aiLastProse.slice(0, AI_GIST2) + "\u2026" : aiLastProse : "";
17078
17434
  const bits = [];
17079
17435
  if (gist) bits.push(gist);
17080
17436
  if (tools) bits.push(`ran ${tools}`);
@@ -17154,10 +17510,10 @@ async function materializeSession(file2) {
17154
17510
 
17155
17511
  // ../../lib/agents/coding/docsDir.ts
17156
17512
  async function writeScoreboard(codingDir, docs) {
17157
- const gradesDir = path12.join(codingDir, "grades");
17513
+ const gradesDir = path13.join(codingDir, "grades");
17158
17514
  let files = [];
17159
17515
  try {
17160
- files = (await fs9.readdir(gradesDir)).filter((f) => f.endsWith(".json")).sort();
17516
+ files = (await fs10.readdir(gradesDir)).filter((f) => f.endsWith(".json")).sort();
17161
17517
  } catch {
17162
17518
  return;
17163
17519
  }
@@ -17165,7 +17521,7 @@ async function writeScoreboard(codingDir, docs) {
17165
17521
  for (const f of files) {
17166
17522
  let g;
17167
17523
  try {
17168
- g = JSON.parse(await fs9.readFile(path12.join(gradesDir, f), "utf8"));
17524
+ g = JSON.parse(await fs10.readFile(path13.join(gradesDir, f), "utf8"));
17169
17525
  } catch {
17170
17526
  continue;
17171
17527
  }
@@ -17181,8 +17537,8 @@ async function writeScoreboard(codingDir, docs) {
17181
17537
  ([key, rows]) => `## ${key}
17182
17538
  ${rows.sort((a, b) => b.s - a.s).map((r) => r.line).join("\n")}`
17183
17539
  );
17184
- await fs9.writeFile(
17185
- path12.join(docs, "_scoreboard.md"),
17540
+ await fs10.writeFile(
17541
+ path13.join(docs, "_scoreboard.md"),
17186
17542
  `# Scoreboard \u2014 every graded session per criterion, best first.
17187
17543
  # Lx~ = estimate. Format: level \xB7 date \xB7 title \xB7 sessionId \u2014 graded instance.
17188
17544
 
@@ -17191,24 +17547,24 @@ ${blocks.join("\n\n")}
17191
17547
  );
17192
17548
  }
17193
17549
  async function ensureCodingDocs(codingDir, sessions) {
17194
- const docs = path12.join(codingDir, "docs");
17195
- await fs9.mkdir(docs, { recursive: true });
17550
+ const docs = path13.join(codingDir, "docs");
17551
+ await fs10.mkdir(docs, { recursive: true });
17196
17552
  const user = sessions.filter((s) => s.sessionId && !s.duplicateOf && (!("klass" in s) || s.klass === "interactive"));
17197
17553
  let written = 0;
17198
17554
  for (const s of user) {
17199
- const out = path12.join(docs, `${s.sessionId}.txt`);
17555
+ const out = path13.join(docs, `${s.sessionId}.txt`);
17200
17556
  try {
17201
- await fs9.access(out);
17557
+ await fs10.access(out);
17202
17558
  continue;
17203
17559
  } catch {
17204
17560
  }
17205
17561
  const mat = await materializeSession(s.file).catch(() => null);
17206
17562
  if (!mat?.text) continue;
17207
- await fs9.writeFile(out, mat.text);
17563
+ await fs10.writeFile(out, mat.text);
17208
17564
  written++;
17209
17565
  }
17210
17566
  const rows = user.sort((a, b) => (a.start ?? "") < (b.start ?? "") ? -1 : 1).map((s) => `${(s.start ?? "").slice(0, 10)} \xB7 ${(s.title ?? "").replace(/\n.*/s, "").slice(0, 80)} \xB7 ${s.sessionId}`);
17211
- await fs9.writeFile(path12.join(docs, "_map.md"), rows.join("\n") + "\n");
17567
+ await fs10.writeFile(path13.join(docs, "_map.md"), rows.join("\n") + "\n");
17212
17568
  await writeScoreboard(codingDir, docs);
17213
17569
  if (written) console.log(`[docs] materialized ${written} new transcript(s) \u2192 ${docs}`);
17214
17570
  return docs;
@@ -17221,7 +17577,7 @@ SOURCE LOOKUP \u2014 you have Read/Grep/Glob over the working directory, which h
17221
17577
 
17222
17578
  // ../../lib/agents/coding/promptCache.ts
17223
17579
  import { createHash as createHash2 } from "crypto";
17224
- import { promises as fs10 } from "fs";
17580
+ import { promises as fs11 } from "fs";
17225
17581
  function promptSha(parts) {
17226
17582
  const h = createHash2("sha256");
17227
17583
  for (const p of parts) {
@@ -17232,7 +17588,7 @@ function promptSha(parts) {
17232
17588
  }
17233
17589
  async function reusableOutput(outPath, sha, valid, key = "promptSha") {
17234
17590
  try {
17235
- const o = JSON.parse(await fs10.readFile(outPath, "utf8"));
17591
+ const o = JSON.parse(await fs11.readFile(outPath, "utf8"));
17236
17592
  if (o[key] === sha && valid(o)) return o;
17237
17593
  } catch {
17238
17594
  }
@@ -17254,8 +17610,10 @@ async function main() {
17254
17610
  engagedPctOfWorkDay: p.aggregate?.flow?.flow?.pctOfWorkDay,
17255
17611
  engagedHoursPerDay: p.aggregate?.flow?.flow?.flowHoursPerDay,
17256
17612
  avgSessionMin: p.workstyle?.blockCount ? Math.round(p.workstyle.flowHoursTotal * 60 / p.workstyle.blockCount) : null,
17257
- topPctOfDay: 0.5,
17258
- topLongestRunHours: 4,
17613
+ // Benchmarks come from lib/calibration (single-source law) — a 0.5 was
17614
+ // once hardcoded here and drifted when the calibration moved to 0.4.
17615
+ topPctOfDay: BEST.flow.topPctOfDay,
17616
+ topLongestRunHours: BEST.longestRun.topHours,
17259
17617
  // STRICT FLOW (rapid typed exchange only, gaps ≤6min sustained ≥20min) — the
17260
17618
  // "Flow state, day by day" map above this card renders THIS; the coaching line
17261
17619
  // must not contradict it or call the loose number "flow".
@@ -17280,7 +17638,7 @@ async function main() {
17280
17638
  // Person-level judgments (coding-person, when it has run): one traversing
17281
17639
  // agent per criterion already ranked the PERSON with source-verified
17282
17640
  // receipts — the placement runs AFTER those judgments and builds on them.
17283
- personLevelJudgments: await fs11.readFile(`${CODING}/person.json`, "utf8").then((t) => {
17641
+ personLevelJudgments: await fs12.readFile(`${CODING}/person.json`, "utf8").then((t) => {
17284
17642
  const j = JSON.parse(t);
17285
17643
  return Object.values(j.criteria ?? {}).map((g) => ({
17286
17644
  quality: g.label,
@@ -17297,7 +17655,25 @@ async function main() {
17297
17655
  }))
17298
17656
  }
17299
17657
  };
17300
- const SYS = "You write the COACHING and FEEL-SEEN copy for a coding-skills report, strictly following this writing rubric:\n\n" + writing + "\n\nYou are given structured facts (numbers + concrete instances) from one person's Claude Code sessions. Three jobs:\n1) COACHING \u2014 for each section, write ONE sentence: the single most useful thing for THIS person, grounded in their actual numbers \u2014 how to improve, where they're weak, or the best thing to do differently. If a section is genuinely strong, say what to push further. Cite the number. No hedging, no fluff, no generic best-practice. Compare to the top where it helps (top ENGAGED time ~50% of day; the best sustain focus ~4h and run many agents in parallel). Vocabulary law: 'flow' means ONLY the strict metric (strictFlow facts); the loose metric is 'engaged time' \u2014 never call it flow, and never write a line that contradicts the strict flow map shown above this card. Deliberate-choice guard: NEVER recommend git worktrees (this person runs parallel agents on main by design and has never hit clobbering); do not recommend a frontier capability unless it appears in pendingFrontier.\n2) FEEL-SEEN \u2014 for abstraction, agency, and taste, write ONE concrete sentence that makes the person feel SEEN: name a SPECIFIC thing they did (from the instances) so they think 'it actually saw that', not generic praise. Second person, present tense.\n3) WHAT-YOU-ARE \u2014 the report's concluding identity read: a PLACEMENT verdict. Judge, from the receipts and scores, where this person would actually land on a real team, and say it flatteringly AND accurately. 'evidence' = one or two sentences pointing at the 2-3 sharpest receipts (named project, session, date, or number) that prove the line, chosen so the person thinks 'it actually saw that'.\n 'line' has EXACTLY this three-beat shape, hard-hitting and pithy:\n BEAT 1 \u2014 THE SPIKES, first words: name their 1-2 standout qualities flat and confident, plain words ('You have <spike> and you <spike>') \u2014 chosen from the highest scores and sharpest receipts, so the reader's first glance already says what to expect from this person.\n BEAT 2 \u2014 THE PLACEMENT those spikes buy: 'drop you into <team> and you'd be <placement>' \u2014 a coined identity (the register of 'high-agency outcomes machine'), NEVER a job title ('founding engineer', 'senior engineer' = flat, cringe), one clause ending on a punch word, sized to the evidence: star-of-any-startup for truly exceptional receipts, 'top third of engineers at any big tech company \u2014 ships without being managed' for a notch less. A size too big is patronizing, a size too small is a snub.\n BEAT 3 \u2014 a short hard verdict: why that pair is the rare, load-bearing thing, and that it's real.\n Worked examples across the calibration range \u2014 generic people, FORM and SIZE only; never reuse their wording, never treat them as a menu (the spikes must come from THIS person's scores):\n - exceptional agency + push: 'You push harder than almost anyone and you own outcomes end-to-end \u2014 drop you into any small startup and you'd be the engine of the whole thing, relentlessly shipping what's actually good. That pair is the rarest, most load-bearing thing here, and it's real.'\n - exceptional taste + judgement: 'Your taste is the real thing and your calls under ambiguity keep being right \u2014 drop you into any product team and you'd be the bar: the one who knows which version is right before anyone can say why. Now that AI makes output infinite, that's the scarcest seat in the room.'\n - strong delegation + expertise, a notch less: 'You run AI like a staff and your depth shows exactly where the tool runs out \u2014 you'd be in the top third of engineers at any big tech company, the one who ships without being managed. That combination is rarer than it sounds, and yours is proven.'\n - real focus + follow-through, modest spikes: 'You hold deep focus for hours and you finish what you start \u2014 drop you onto any team and you'd be the steady core, the one whose thread always converges. Every team needs exactly one of those; few have one.'\n - Pithy: two sentences max. No receipts crammed into the line (evidence carries those). No qualifier stacks, no consultant words (force multiplier, leverage, north star), no hedging.\n - TESTABLE placement, not adjectives. No population percentages.\n - If the receipts support NO honest flattering placement, output empty strings for both fields \u2014 nothing is better than an inflated or hedged read.\n - Never invent; every claim in 'evidence' must trace to a given receipt." + sourceLookupNote();
17658
+ const SYS = "You write the COACHING and FEEL-SEEN copy for a coding-skills report, strictly following this writing rubric:\n\n" + writing + `
17659
+
17660
+ You are given structured facts (numbers + concrete instances) from one person's Claude Code sessions. Three jobs:
17661
+ 1) COACHING \u2014 for each section, write ONE sentence: the single most useful thing for THIS person, grounded in their actual numbers \u2014 how to improve, where they're weak, or the best thing to do differently. If a section is genuinely strong, say what to push further. Cite the number. No hedging, no fluff, no generic best-practice. Compare to the top where it helps (top ENGAGED time ~${Math.round(BEST.flow.topPctOfDay * 100)}% of day; the best sustain focus ~${BEST.longestRun.topHours}h and run many agents in parallel). Vocabulary law: 'flow' means ONLY the strict metric (strictFlow facts); the loose metric is 'engaged time' \u2014 never call it flow, and never write a line that contradicts the strict flow map shown above this card. Deliberate-choice guard: NEVER recommend git worktrees (this person runs parallel agents on main by design and has never hit clobbering); do not recommend a frontier capability unless it appears in pendingFrontier.
17662
+ 2) FEEL-SEEN \u2014 for abstraction, agency, and taste, write ONE concrete sentence that makes the person feel SEEN: name a SPECIFIC thing they did (from the instances) so they think 'it actually saw that', not generic praise. Second person, present tense.
17663
+ 3) WHAT-YOU-ARE \u2014 the report's concluding identity read: a PLACEMENT verdict. Judge, from the receipts and scores, where this person would actually land on a real team, and say it flatteringly AND accurately. 'evidence' = one or two sentences pointing at the 2-3 sharpest receipts (named project, session, date, or number) that prove the line, chosen so the person thinks 'it actually saw that'.
17664
+ 'line' has EXACTLY this three-beat shape, hard-hitting and pithy:
17665
+ BEAT 1 \u2014 THE SPIKES, first words: name their 1-2 standout qualities flat and confident, plain words ('You have <spike> and you <spike>') \u2014 chosen from the highest scores and sharpest receipts, so the reader's first glance already says what to expect from this person.
17666
+ BEAT 2 \u2014 THE PLACEMENT those spikes buy: 'drop you into <team> and you'd be <placement>' \u2014 a coined identity (the register of 'high-agency outcomes machine'), NEVER a job title ('founding engineer', 'senior engineer' = flat, cringe), one clause ending on a punch word, sized to the evidence: star-of-any-startup for truly exceptional receipts, 'top third of engineers at any big tech company \u2014 ships without being managed' for a notch less. A size too big is patronizing, a size too small is a snub.
17667
+ BEAT 3 \u2014 a short hard verdict: why that pair is the rare, load-bearing thing, and that it's real.
17668
+ Worked examples across the calibration range \u2014 generic people, FORM and SIZE only; never reuse their wording, never treat them as a menu (the spikes must come from THIS person's scores):
17669
+ - exceptional agency + push: 'You push harder than almost anyone and you own outcomes end-to-end \u2014 drop you into any small startup and you'd be the engine of the whole thing, relentlessly shipping what's actually good. That pair is the rarest, most load-bearing thing here, and it's real.'
17670
+ - exceptional taste + judgement: 'Your taste is the real thing and your calls under ambiguity keep being right \u2014 drop you into any product team and you'd be the bar: the one who knows which version is right before anyone can say why. Now that AI makes output infinite, that's the scarcest seat in the room.'
17671
+ - strong delegation + expertise, a notch less: 'You run AI like a staff and your depth shows exactly where the tool runs out \u2014 you'd be in the top third of engineers at any big tech company, the one who ships without being managed. That combination is rarer than it sounds, and yours is proven.'
17672
+ - real focus + follow-through, modest spikes: 'You hold deep focus for hours and you finish what you start \u2014 drop you onto any team and you'd be the steady core, the one whose thread always converges. Every team needs exactly one of those; few have one.'
17673
+ - Pithy: two sentences max. No receipts crammed into the line (evidence carries those). No qualifier stacks, no consultant words (force multiplier, leverage, north star), no hedging.
17674
+ - TESTABLE placement, not adjectives. No population percentages.
17675
+ - If the receipts support NO honest flattering placement, output empty strings for both fields \u2014 nothing is better than an inflated or hedged read.
17676
+ - Never invent; every claim in 'evidence' must trace to a given receipt.` + sourceLookupNote();
17301
17677
  const prompt = `FACTS (numbers + concrete instances per section):
17302
17678
  ${JSON.stringify(facts, null, 1).slice(0, 6e4)}
17303
17679
 
@@ -17318,7 +17694,7 @@ Output a SINGLE fenced json block, every value a single tight sentence (whatYouA
17318
17694
  return;
17319
17695
  }
17320
17696
  }
17321
- const sessions = await fs11.readFile(`${CODING}/sessions.json`, "utf8").then(JSON.parse).catch(() => []);
17697
+ const sessions = await fs12.readFile(`${CODING}/sessions.json`, "utf8").then(JSON.parse).catch(() => []);
17322
17698
  await ensureCodingDocs(CODING, sessions);
17323
17699
  console.log(`coaching \u2014 1 ${model} pass over compiled profile (+source lookups)`);
17324
17700
  let out = { coaching: {}, feelSeen: {} };
@@ -17334,8 +17710,23 @@ Output a SINGLE fenced json block, every value a single tight sentence (whatYouA
17334
17710
  console.error(`REFUSING to write ${CODING}/coaching.json \u2014 incomplete output (coaching:${Object.keys(out.coaching || {}).length} feelSeen:${Object.keys(out.feelSeen || {}).length} whatYouAre:${wya ? "malformed" : "missing"})`);
17335
17711
  process.exit(1);
17336
17712
  }
17713
+ const truncated = [];
17714
+ const scan = (v, at) => {
17715
+ if (typeof v === "string") {
17716
+ const t = v.trim();
17717
+ if (t.length > 80 && /[a-z,;:]$/i.test(t)) truncated.push(`${at}: "\u2026${t.slice(-40)}"`);
17718
+ } else if (v && typeof v === "object") {
17719
+ for (const [k, x] of Object.entries(v)) scan(x, `${at}.${k}`);
17720
+ }
17721
+ };
17722
+ scan({ coaching: out.coaching, feelSeen: out.feelSeen, whatYouAre: out.whatYouAre }, "out");
17723
+ if (truncated.length) {
17724
+ console.error(`REFUSING to write ${CODING}/coaching.json \u2014 ${truncated.length} string(s) end mid-word (model output truncated):
17725
+ ${truncated.join("\n ")}`);
17726
+ process.exit(1);
17727
+ }
17337
17728
  const result = { generatedAt: (/* @__PURE__ */ new Date()).toISOString(), promptSha: sha, ...out };
17338
- await fs11.writeFile(`${CODING}/coaching.json`, JSON.stringify(result, null, 2));
17729
+ await fs12.writeFile(`${CODING}/coaching.json`, JSON.stringify(result, null, 2));
17339
17730
  console.log(`WROTE ${CODING}/coaching.json \u2014 coaching:${Object.keys(out.coaching || {}).length} feelSeen:${Object.keys(out.feelSeen || {}).length} whatYouAre:${wya.line.trim() ? "ok" : "declined"}`);
17340
17731
  }
17341
17732
  main().catch((e) => {