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.
- package/dist/cli.js +23943 -21630
- package/dist/engine/chat-loops.js +8 -1
- package/dist/engine/exp-allfacets.js +8 -1
- package/dist/engine/exp-person.js +8 -1
- package/dist/engine/exp-pipeline.js +8 -1
- package/dist/engine/ingest-export.js +7 -6
- package/dist/engine/peak-demos.js +8 -1
- package/dist/engine/person-dimension-summary.js +8 -1
- package/dist/engine/person-facet-lines.js +8 -1
- package/dist/engine/person-headline.js +8 -1
- package/dist/engine/person-report.js +8 -1
- package/dist/engine/person-self-image.js +8 -1
- package/dist/engine/public-report.js +15 -7
- package/dist/engine/run-analysis.js +8 -1
- package/dist/engine/run-tagger.js +8 -1
- package/dist/index.js +19647 -17969
- package/dist/pipeline/coding-agglomerate.js +826 -82
- package/dist/pipeline/coding-aggregate.js +307 -23
- package/dist/pipeline/coding-build.js +453 -95
- package/dist/pipeline/coding-coaching.js +479 -88
- package/dist/pipeline/coding-day-digest.js +308 -36
- package/dist/pipeline/coding-delegation.js +376 -52
- package/dist/pipeline/coding-expertise.js +356 -62
- package/dist/pipeline/coding-flow.js +288 -15
- package/dist/pipeline/coding-focus.js +371 -51
- package/dist/pipeline/coding-frontier-detail.js +344 -50
- package/dist/pipeline/coding-frontier.js +7 -6
- package/dist/pipeline/coding-gap-dist.js +288 -15
- package/dist/pipeline/coding-gap.js +507 -115
- package/dist/pipeline/coding-grade.js +342 -45
- package/dist/pipeline/coding-growth.js +17041 -0
- package/dist/pipeline/coding-nutshell.js +15 -7
- package/dist/pipeline/coding-projects.js +7 -6
- package/dist/pipeline/coding-walkthrough.js +317 -37
- package/dist/pipeline/coding-workbrief.js +16387 -0
- package/dist/web/app.js +2095 -1395
- package/dist/web/styles.css +1 -1
- package/package.json +1 -1
|
@@ -134,8 +134,55 @@ var require_secure_json_parse = __commonJS({
|
|
|
134
134
|
});
|
|
135
135
|
|
|
136
136
|
// ../../scripts/coding-gap.mts
|
|
137
|
-
import { promises as
|
|
138
|
-
import
|
|
137
|
+
import { promises as fs13 } from "fs";
|
|
138
|
+
import path14 from "path";
|
|
139
|
+
|
|
140
|
+
// ../../lib/agents/coding/stageLock.ts
|
|
141
|
+
import { promises as fs } from "fs";
|
|
142
|
+
var STALE_UNKNOWN_MS = 12 * 60 * 60 * 1e3;
|
|
143
|
+
function pidAlive(pid) {
|
|
144
|
+
try {
|
|
145
|
+
process.kill(pid, 0);
|
|
146
|
+
return true;
|
|
147
|
+
} catch (e) {
|
|
148
|
+
return e.code === "EPERM";
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
async function acquireStageLock(lockPath, stage) {
|
|
152
|
+
const mine = String(process.pid);
|
|
153
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
154
|
+
try {
|
|
155
|
+
await fs.writeFile(lockPath, mine, { flag: "wx" });
|
|
156
|
+
return async () => {
|
|
157
|
+
const held = await fs.readFile(lockPath, "utf8").catch(() => null);
|
|
158
|
+
if (held === mine) await fs.unlink(lockPath).catch(() => {
|
|
159
|
+
});
|
|
160
|
+
};
|
|
161
|
+
} catch {
|
|
162
|
+
const raw = (await fs.readFile(lockPath, "utf8").catch(() => "")).trim();
|
|
163
|
+
const pid = /^\d{1,9}$/.test(raw) ? Number(raw) : null;
|
|
164
|
+
if (pid != null && pidAlive(pid)) {
|
|
165
|
+
throw new Error(
|
|
166
|
+
`another ${stage} run is ACTIVE (pid ${pid} is alive, ${lockPath}) \u2014 concurrent runs overwrite each other's output. Wait for it to finish.`
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
if (pid == null) {
|
|
170
|
+
const age = Date.now() - (await fs.stat(lockPath).catch(() => null))?.mtimeMs;
|
|
171
|
+
if (!(age > STALE_UNKNOWN_MS)) {
|
|
172
|
+
throw new Error(
|
|
173
|
+
`a ${stage} lock exists with an unreadable holder (${lockPath}, ${Math.round(age / 6e4)}m old) \u2014 not old enough to declare stale. Wait, or delete it if you know the run is gone.`
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
console.warn(
|
|
178
|
+
`[${stage}] stale lock from ${pid != null ? `dead pid ${pid}` : "an unreadable holder"} \u2014 removing it and proceeding (a crashed run must never strand the next one)`
|
|
179
|
+
);
|
|
180
|
+
await fs.unlink(lockPath).catch(() => {
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
throw new Error(`could not acquire the ${stage} lock (${lockPath}) \u2014 another run raced the stale takeover`);
|
|
185
|
+
}
|
|
139
186
|
|
|
140
187
|
// ../../lib/agents/shared/agent.ts
|
|
141
188
|
import { readFileSync } from "fs";
|
|
@@ -143,7 +190,7 @@ import path8 from "path";
|
|
|
143
190
|
|
|
144
191
|
// ../../lib/agents/shared/cliAdapter.ts
|
|
145
192
|
import { spawn } from "child_process";
|
|
146
|
-
import { promises as
|
|
193
|
+
import { promises as fs3 } from "fs";
|
|
147
194
|
import path2 from "path";
|
|
148
195
|
|
|
149
196
|
// ../coding-core/dist/env.js
|
|
@@ -187,7 +234,7 @@ function extractJson(text2) {
|
|
|
187
234
|
}
|
|
188
235
|
|
|
189
236
|
// ../../lib/agents/shared/toolLog.ts
|
|
190
|
-
import { promises as
|
|
237
|
+
import { promises as fs2 } from "fs";
|
|
191
238
|
import path from "path";
|
|
192
239
|
async function writeToolLog(logPath, d) {
|
|
193
240
|
const counts = {};
|
|
@@ -204,8 +251,8 @@ async function writeToolLog(logPath, d) {
|
|
|
204
251
|
L.push(``);
|
|
205
252
|
L.push(`## Full call sequence (${d.toolCalls.length})`);
|
|
206
253
|
d.toolCalls.forEach((c, i) => L.push(` ${String(i + 1).padStart(3, "0")} ${c.tool.padEnd(5)} ${c.target}`));
|
|
207
|
-
await
|
|
208
|
-
await
|
|
254
|
+
await fs2.mkdir(path.dirname(logPath), { recursive: true });
|
|
255
|
+
await fs2.writeFile(logPath, L.join("\n"), "utf-8");
|
|
209
256
|
const json = {
|
|
210
257
|
roots: d.roots,
|
|
211
258
|
toolCounts: counts,
|
|
@@ -215,7 +262,7 @@ async function writeToolLog(logPath, d) {
|
|
|
215
262
|
filesRead: d.filesRead,
|
|
216
263
|
callSequence: d.toolCalls
|
|
217
264
|
};
|
|
218
|
-
await
|
|
265
|
+
await fs2.writeFile(logPath.replace(/\.log$/, ".json"), JSON.stringify(json, null, 2), "utf-8");
|
|
219
266
|
}
|
|
220
267
|
|
|
221
268
|
// ../../lib/agents/shared/cliAdapter.ts
|
|
@@ -224,8 +271,8 @@ var USAGE_LEDGER = () => path2.join(process.env.POLYMATH_DATA_DIR ? path2.resolv
|
|
|
224
271
|
async function appendUsageLedger(line) {
|
|
225
272
|
try {
|
|
226
273
|
const f = USAGE_LEDGER();
|
|
227
|
-
await
|
|
228
|
-
await
|
|
274
|
+
await fs3.mkdir(path2.dirname(f), { recursive: true });
|
|
275
|
+
await fs3.appendFile(f, JSON.stringify(line) + "\n", "utf8");
|
|
229
276
|
} catch {
|
|
230
277
|
}
|
|
231
278
|
}
|
|
@@ -503,6 +550,13 @@ ${report}`);
|
|
|
503
550
|
}
|
|
504
551
|
|
|
505
552
|
// ../../lib/agents/shared/codexAdapter.ts
|
|
553
|
+
var CODEX_DEFAULT_MODEL = "gpt-5.5";
|
|
554
|
+
var CODEX_MINI_MODEL = "gpt-5.4-mini";
|
|
555
|
+
function mapCodexTier(model, env = process.env) {
|
|
556
|
+
if (model && !/^(claude|haiku|sonnet|opus)/i.test(model)) return model;
|
|
557
|
+
if (model && /^haiku/i.test(model)) return env.POLYMATH_CODEX_MODEL_MINI || CODEX_MINI_MODEL;
|
|
558
|
+
return env.POLYMATH_CODEX_MODEL || CODEX_DEFAULT_MODEL;
|
|
559
|
+
}
|
|
506
560
|
function composePrompt(inv, roots) {
|
|
507
561
|
return [
|
|
508
562
|
inv.systemPrompt ? `<system>
|
|
@@ -543,7 +597,7 @@ var codexAdapter = {
|
|
|
543
597
|
"read-only",
|
|
544
598
|
"--json"
|
|
545
599
|
];
|
|
546
|
-
|
|
600
|
+
args.push("--model", mapCodexTier(inv.model));
|
|
547
601
|
args.push(composePrompt(inv, roots));
|
|
548
602
|
const started = Date.now();
|
|
549
603
|
const toolCalls = [];
|
|
@@ -2171,8 +2225,8 @@ function getErrorMap() {
|
|
|
2171
2225
|
|
|
2172
2226
|
// ../../node_modules/zod/v3/helpers/parseUtil.js
|
|
2173
2227
|
var makeIssue = (params) => {
|
|
2174
|
-
const { data, path:
|
|
2175
|
-
const fullPath = [...
|
|
2228
|
+
const { data, path: path15, errorMaps, issueData } = params;
|
|
2229
|
+
const fullPath = [...path15, ...issueData.path || []];
|
|
2176
2230
|
const fullIssue = {
|
|
2177
2231
|
...issueData,
|
|
2178
2232
|
path: fullPath
|
|
@@ -2288,11 +2342,11 @@ var errorUtil;
|
|
|
2288
2342
|
|
|
2289
2343
|
// ../../node_modules/zod/v3/types.js
|
|
2290
2344
|
var ParseInputLazyPath = class {
|
|
2291
|
-
constructor(parent, value,
|
|
2345
|
+
constructor(parent, value, path15, key) {
|
|
2292
2346
|
this._cachedPath = [];
|
|
2293
2347
|
this.parent = parent;
|
|
2294
2348
|
this.data = value;
|
|
2295
|
-
this._path =
|
|
2349
|
+
this._path = path15;
|
|
2296
2350
|
this._key = key;
|
|
2297
2351
|
}
|
|
2298
2352
|
get path() {
|
|
@@ -15079,39 +15133,39 @@ function createOpenAI(options = {}) {
|
|
|
15079
15133
|
});
|
|
15080
15134
|
const createChatModel = (modelId, settings = {}) => new OpenAIChatLanguageModel(modelId, settings, {
|
|
15081
15135
|
provider: `${providerName}.chat`,
|
|
15082
|
-
url: ({ path:
|
|
15136
|
+
url: ({ path: path15 }) => `${baseURL}${path15}`,
|
|
15083
15137
|
headers: getHeaders,
|
|
15084
15138
|
compatibility,
|
|
15085
15139
|
fetch: options.fetch
|
|
15086
15140
|
});
|
|
15087
15141
|
const createCompletionModel = (modelId, settings = {}) => new OpenAICompletionLanguageModel(modelId, settings, {
|
|
15088
15142
|
provider: `${providerName}.completion`,
|
|
15089
|
-
url: ({ path:
|
|
15143
|
+
url: ({ path: path15 }) => `${baseURL}${path15}`,
|
|
15090
15144
|
headers: getHeaders,
|
|
15091
15145
|
compatibility,
|
|
15092
15146
|
fetch: options.fetch
|
|
15093
15147
|
});
|
|
15094
15148
|
const createEmbeddingModel = (modelId, settings = {}) => new OpenAIEmbeddingModel(modelId, settings, {
|
|
15095
15149
|
provider: `${providerName}.embedding`,
|
|
15096
|
-
url: ({ path:
|
|
15150
|
+
url: ({ path: path15 }) => `${baseURL}${path15}`,
|
|
15097
15151
|
headers: getHeaders,
|
|
15098
15152
|
fetch: options.fetch
|
|
15099
15153
|
});
|
|
15100
15154
|
const createImageModel = (modelId, settings = {}) => new OpenAIImageModel(modelId, settings, {
|
|
15101
15155
|
provider: `${providerName}.image`,
|
|
15102
|
-
url: ({ path:
|
|
15156
|
+
url: ({ path: path15 }) => `${baseURL}${path15}`,
|
|
15103
15157
|
headers: getHeaders,
|
|
15104
15158
|
fetch: options.fetch
|
|
15105
15159
|
});
|
|
15106
15160
|
const createTranscriptionModel = (modelId) => new OpenAITranscriptionModel(modelId, {
|
|
15107
15161
|
provider: `${providerName}.transcription`,
|
|
15108
|
-
url: ({ path:
|
|
15162
|
+
url: ({ path: path15 }) => `${baseURL}${path15}`,
|
|
15109
15163
|
headers: getHeaders,
|
|
15110
15164
|
fetch: options.fetch
|
|
15111
15165
|
});
|
|
15112
15166
|
const createSpeechModel = (modelId) => new OpenAISpeechModel(modelId, {
|
|
15113
15167
|
provider: `${providerName}.speech`,
|
|
15114
|
-
url: ({ path:
|
|
15168
|
+
url: ({ path: path15 }) => `${baseURL}${path15}`,
|
|
15115
15169
|
headers: getHeaders,
|
|
15116
15170
|
fetch: options.fetch
|
|
15117
15171
|
});
|
|
@@ -15132,7 +15186,7 @@ function createOpenAI(options = {}) {
|
|
|
15132
15186
|
const createResponsesModel = (modelId) => {
|
|
15133
15187
|
return new OpenAIResponsesLanguageModel(modelId, {
|
|
15134
15188
|
provider: `${providerName}.responses`,
|
|
15135
|
-
url: ({ path:
|
|
15189
|
+
url: ({ path: path15 }) => `${baseURL}${path15}`,
|
|
15136
15190
|
headers: getHeaders,
|
|
15137
15191
|
fetch: options.fetch
|
|
15138
15192
|
});
|
|
@@ -15162,7 +15216,7 @@ var openai = createOpenAI({
|
|
|
15162
15216
|
});
|
|
15163
15217
|
|
|
15164
15218
|
// ../../lib/agents/shared/tools.ts
|
|
15165
|
-
import { promises as
|
|
15219
|
+
import { promises as fs4 } from "fs";
|
|
15166
15220
|
import { execFile } from "child_process";
|
|
15167
15221
|
import { promisify } from "util";
|
|
15168
15222
|
import path5 from "path";
|
|
@@ -15182,7 +15236,7 @@ function fileTools(root) {
|
|
|
15182
15236
|
parameters: external_exports.object({ path: external_exports.string().describe("dir path relative to source root") }),
|
|
15183
15237
|
execute: async ({ path: p }) => {
|
|
15184
15238
|
const dir = safeResolve(root, p);
|
|
15185
|
-
const entries = await
|
|
15239
|
+
const entries = await fs4.readdir(dir, { withFileTypes: true });
|
|
15186
15240
|
return entries.filter((e) => !e.name.startsWith(".git") && e.name !== ".obsidian").map((e) => e.isDirectory() ? `${e.name}/` : e.name).slice(0, 500).join("\n");
|
|
15187
15241
|
}
|
|
15188
15242
|
}),
|
|
@@ -15195,7 +15249,7 @@ function fileTools(root) {
|
|
|
15195
15249
|
}),
|
|
15196
15250
|
execute: async ({ path: p, offset = 0, limit = 600 }) => {
|
|
15197
15251
|
const file2 = safeResolve(root, p);
|
|
15198
|
-
const text2 = await
|
|
15252
|
+
const text2 = await fs4.readFile(file2, "utf-8");
|
|
15199
15253
|
const lines = text2.split("\n");
|
|
15200
15254
|
return lines.slice(offset, offset + limit).join("\n").slice(0, 6e4);
|
|
15201
15255
|
}
|
|
@@ -15629,8 +15683,8 @@ function invokeAgent(inv, opts = {}) {
|
|
|
15629
15683
|
}
|
|
15630
15684
|
|
|
15631
15685
|
// ../../lib/agents/coding/profile.ts
|
|
15632
|
-
import { promises as
|
|
15633
|
-
import
|
|
15686
|
+
import { promises as fs8 } from "fs";
|
|
15687
|
+
import path11 from "path";
|
|
15634
15688
|
|
|
15635
15689
|
// ../../lib/calibration/fingerprint.ts
|
|
15636
15690
|
import { createHash } from "node:crypto";
|
|
@@ -15776,7 +15830,7 @@ var GRADED_CRITERIA = CODING_CRITERIA.filter((c) => c.graded);
|
|
|
15776
15830
|
var RUBRIC_FINGERPRINT = rubricFingerprint(GRADED_CRITERIA);
|
|
15777
15831
|
|
|
15778
15832
|
// ../coding-core/dist/messages.js
|
|
15779
|
-
import { promises as
|
|
15833
|
+
import { promises as fs6 } from "fs";
|
|
15780
15834
|
|
|
15781
15835
|
// ../coding-core/dist/injected.js
|
|
15782
15836
|
var SYSTEM_REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/g;
|
|
@@ -15902,6 +15956,286 @@ function extractCodexEvents(raw) {
|
|
|
15902
15956
|
return out;
|
|
15903
15957
|
}
|
|
15904
15958
|
|
|
15959
|
+
// ../coding-core/dist/cursor.js
|
|
15960
|
+
import { promises as fs5 } from "fs";
|
|
15961
|
+
var NODE_SQLITE = "node:sqlite";
|
|
15962
|
+
async function openCursorSqlite(dbPath) {
|
|
15963
|
+
try {
|
|
15964
|
+
await fs5.access(dbPath);
|
|
15965
|
+
} catch {
|
|
15966
|
+
return null;
|
|
15967
|
+
}
|
|
15968
|
+
let mod;
|
|
15969
|
+
try {
|
|
15970
|
+
mod = await import(NODE_SQLITE);
|
|
15971
|
+
} catch {
|
|
15972
|
+
return null;
|
|
15973
|
+
}
|
|
15974
|
+
const DatabaseSync = mod?.DatabaseSync;
|
|
15975
|
+
if (!DatabaseSync)
|
|
15976
|
+
return null;
|
|
15977
|
+
let db;
|
|
15978
|
+
try {
|
|
15979
|
+
db = new DatabaseSync(dbPath, { readOnly: true });
|
|
15980
|
+
} catch {
|
|
15981
|
+
try {
|
|
15982
|
+
db = new DatabaseSync(dbPath);
|
|
15983
|
+
} catch {
|
|
15984
|
+
return null;
|
|
15985
|
+
}
|
|
15986
|
+
}
|
|
15987
|
+
const asText = (v) => v == null ? null : typeof v === "string" ? v : Buffer.from(v).toString("utf-8");
|
|
15988
|
+
return {
|
|
15989
|
+
prefix(prefix) {
|
|
15990
|
+
try {
|
|
15991
|
+
const rows = db.prepare("SELECT key, value FROM cursorDiskKV WHERE key LIKE ? ESCAPE '\\'").all(likePrefix(prefix));
|
|
15992
|
+
return rows.map((r) => ({ key: r.key, value: asText(r.value) ?? "" }));
|
|
15993
|
+
} catch {
|
|
15994
|
+
return [];
|
|
15995
|
+
}
|
|
15996
|
+
},
|
|
15997
|
+
get(key) {
|
|
15998
|
+
try {
|
|
15999
|
+
const row = db.prepare("SELECT value FROM cursorDiskKV WHERE key = ?").get(key);
|
|
16000
|
+
return row ? asText(row.value) : null;
|
|
16001
|
+
} catch {
|
|
16002
|
+
return null;
|
|
16003
|
+
}
|
|
16004
|
+
},
|
|
16005
|
+
close() {
|
|
16006
|
+
try {
|
|
16007
|
+
db.close();
|
|
16008
|
+
} catch {
|
|
16009
|
+
}
|
|
16010
|
+
}
|
|
16011
|
+
};
|
|
16012
|
+
}
|
|
16013
|
+
function likePrefix(prefix) {
|
|
16014
|
+
return prefix.replace(/[\\%_]/g, (c) => "\\" + c) + "%";
|
|
16015
|
+
}
|
|
16016
|
+
var CURSOR_USER_QUERY_RE = /<user_query>\s*([\s\S]*?)\s*<\/user_query>/;
|
|
16017
|
+
function cleanUserText(raw) {
|
|
16018
|
+
let t = raw.replace(SYSTEM_REMINDER_RE, "");
|
|
16019
|
+
const m = t.match(CURSOR_USER_QUERY_RE);
|
|
16020
|
+
if (m)
|
|
16021
|
+
t = m[1];
|
|
16022
|
+
return t.trim();
|
|
16023
|
+
}
|
|
16024
|
+
var msFrom = (v) => {
|
|
16025
|
+
if (typeof v === "number" && Number.isFinite(v))
|
|
16026
|
+
return v;
|
|
16027
|
+
if (typeof v === "string") {
|
|
16028
|
+
const n = Date.parse(v);
|
|
16029
|
+
return Number.isFinite(n) ? n : null;
|
|
16030
|
+
}
|
|
16031
|
+
return null;
|
|
16032
|
+
};
|
|
16033
|
+
function readCursorComposer(db, composerId) {
|
|
16034
|
+
const cdRaw = db.get(`composerData:${composerId}`);
|
|
16035
|
+
if (!cdRaw)
|
|
16036
|
+
return null;
|
|
16037
|
+
let cd;
|
|
16038
|
+
try {
|
|
16039
|
+
cd = JSON.parse(cdRaw);
|
|
16040
|
+
} catch {
|
|
16041
|
+
return null;
|
|
16042
|
+
}
|
|
16043
|
+
const headers = Array.isArray(cd.fullConversationHeadersOnly) ? cd.fullConversationHeadersOnly : [];
|
|
16044
|
+
if (headers.length === 0)
|
|
16045
|
+
return null;
|
|
16046
|
+
const bubbles = /* @__PURE__ */ new Map();
|
|
16047
|
+
for (const row of db.prefix(`bubbleId:${composerId}:`)) {
|
|
16048
|
+
const bid = row.key.slice(`bubbleId:${composerId}:`.length);
|
|
16049
|
+
try {
|
|
16050
|
+
bubbles.set(bid, JSON.parse(row.value));
|
|
16051
|
+
} catch {
|
|
16052
|
+
}
|
|
16053
|
+
}
|
|
16054
|
+
const turns = [];
|
|
16055
|
+
let clock = msFrom(cd.createdAt) ?? 0;
|
|
16056
|
+
for (const h of headers) {
|
|
16057
|
+
const b = bubbles.get(h.bubbleId);
|
|
16058
|
+
if (!b)
|
|
16059
|
+
continue;
|
|
16060
|
+
const type = h.type === 1 ? 1 : 2;
|
|
16061
|
+
const tool2 = type === 2 && b.toolFormerData && typeof b.toolFormerData.name === "string" ? b.toolFormerData.name : null;
|
|
16062
|
+
const rawText = typeof b.text === "string" ? b.text : "";
|
|
16063
|
+
const text2 = type === 1 ? cleanUserText(rawText) : rawText.replace(SYSTEM_REMINDER_RE, "").trim();
|
|
16064
|
+
if (!text2 && !tool2)
|
|
16065
|
+
continue;
|
|
16066
|
+
const t = msFrom(b.createdAt);
|
|
16067
|
+
clock = Math.max(clock, t ?? clock + 1);
|
|
16068
|
+
const model = b.modelInfo && typeof b.modelInfo.modelName === "string" ? b.modelInfo.modelName : null;
|
|
16069
|
+
turns.push({ t: clock, type, text: text2, tool: tool2, model });
|
|
16070
|
+
}
|
|
16071
|
+
if (turns.length === 0)
|
|
16072
|
+
return null;
|
|
16073
|
+
const gitRepo = Array.isArray(cd.trackedGitRepos) && cd.trackedGitRepos[0] && typeof cd.trackedGitRepos[0].repoPath === "string" ? cd.trackedGitRepos[0].repoPath : null;
|
|
16074
|
+
return {
|
|
16075
|
+
composerId,
|
|
16076
|
+
createdAt: msFrom(cd.createdAt),
|
|
16077
|
+
updatedAt: msFrom(cd.lastUpdatedAt),
|
|
16078
|
+
name: typeof cd.name === "string" && cd.name.trim() ? cd.name.trim() : null,
|
|
16079
|
+
gitRepo,
|
|
16080
|
+
turns
|
|
16081
|
+
};
|
|
16082
|
+
}
|
|
16083
|
+
function sniffCursorRaw(raw) {
|
|
16084
|
+
for (const lineRaw of raw.split("\n")) {
|
|
16085
|
+
const line = lineRaw.trim();
|
|
16086
|
+
if (!line)
|
|
16087
|
+
continue;
|
|
16088
|
+
try {
|
|
16089
|
+
const e = JSON.parse(line);
|
|
16090
|
+
return (e.role === "user" || e.role === "assistant") && typeof e.message === "object" && e.message !== null && "content" in e.message && !("type" in e);
|
|
16091
|
+
} catch {
|
|
16092
|
+
return false;
|
|
16093
|
+
}
|
|
16094
|
+
}
|
|
16095
|
+
return false;
|
|
16096
|
+
}
|
|
16097
|
+
function jsonlText(content) {
|
|
16098
|
+
const parts = [];
|
|
16099
|
+
const tools = [];
|
|
16100
|
+
if (Array.isArray(content)) {
|
|
16101
|
+
for (const item of content) {
|
|
16102
|
+
if (!item || typeof item !== "object")
|
|
16103
|
+
continue;
|
|
16104
|
+
const it = item;
|
|
16105
|
+
if (it.type === "text" && it.text)
|
|
16106
|
+
parts.push(it.text);
|
|
16107
|
+
else if (it.type === "tool_use" && it.name)
|
|
16108
|
+
tools.push(it.name);
|
|
16109
|
+
}
|
|
16110
|
+
} else if (typeof content === "string")
|
|
16111
|
+
parts.push(content);
|
|
16112
|
+
return { text: parts.join("\n"), tools };
|
|
16113
|
+
}
|
|
16114
|
+
function parseCursorJsonl(raw, base) {
|
|
16115
|
+
const turns = [];
|
|
16116
|
+
let clock = base;
|
|
16117
|
+
for (const lineRaw of raw.split("\n")) {
|
|
16118
|
+
const line = lineRaw.trim();
|
|
16119
|
+
if (!line)
|
|
16120
|
+
continue;
|
|
16121
|
+
let e;
|
|
16122
|
+
try {
|
|
16123
|
+
e = JSON.parse(line);
|
|
16124
|
+
} catch {
|
|
16125
|
+
continue;
|
|
16126
|
+
}
|
|
16127
|
+
if (e.role !== "user" && e.role !== "assistant")
|
|
16128
|
+
continue;
|
|
16129
|
+
const { text: rawText, tools } = jsonlText(e.message?.content);
|
|
16130
|
+
const type = e.role === "user" ? 1 : 2;
|
|
16131
|
+
const text2 = type === 1 ? cleanUserText(rawText) : rawText.replace(SYSTEM_REMINDER_RE, "").trim();
|
|
16132
|
+
if (type === 2 && tools.length) {
|
|
16133
|
+
for (const tool2 of tools) {
|
|
16134
|
+
clock += 1;
|
|
16135
|
+
turns.push({ t: clock, type: 2, text: "", tool: tool2, model: null });
|
|
16136
|
+
}
|
|
16137
|
+
}
|
|
16138
|
+
if (!text2)
|
|
16139
|
+
continue;
|
|
16140
|
+
clock += 1;
|
|
16141
|
+
turns.push({ t: clock, type, text: text2, tool: null, model: null });
|
|
16142
|
+
}
|
|
16143
|
+
if (turns.length === 0)
|
|
16144
|
+
return null;
|
|
16145
|
+
return { composerId: "", createdAt: base, updatedAt: clock, name: null, gitRepo: null, turns };
|
|
16146
|
+
}
|
|
16147
|
+
var AI_GIST = 500;
|
|
16148
|
+
function renderCursorTranscript(c) {
|
|
16149
|
+
const lines = [];
|
|
16150
|
+
let humanTurns = 0, humanChars = 0;
|
|
16151
|
+
let aiProse = "";
|
|
16152
|
+
const aiTools = /* @__PURE__ */ new Map();
|
|
16153
|
+
const flushAI = () => {
|
|
16154
|
+
if (!aiProse && aiTools.size === 0)
|
|
16155
|
+
return;
|
|
16156
|
+
const tools = [...aiTools.entries()].map(([n, k]) => k > 1 ? `${n}\xD7${k}` : n).join(", ");
|
|
16157
|
+
const gist = aiProse ? aiProse.length > AI_GIST ? aiProse.slice(0, AI_GIST) + "\u2026" : aiProse : "";
|
|
16158
|
+
const bits = [];
|
|
16159
|
+
if (gist)
|
|
16160
|
+
bits.push(gist);
|
|
16161
|
+
if (tools)
|
|
16162
|
+
bits.push(`ran ${tools}`);
|
|
16163
|
+
lines.push(`[AI: ${bits.join(" \xB7 ")}]`);
|
|
16164
|
+
aiProse = "";
|
|
16165
|
+
aiTools.clear();
|
|
16166
|
+
};
|
|
16167
|
+
for (const turn of c.turns) {
|
|
16168
|
+
if (turn.type === 1) {
|
|
16169
|
+
flushAI();
|
|
16170
|
+
humanTurns++;
|
|
16171
|
+
humanChars += turn.text.length;
|
|
16172
|
+
lines.push(`>> ${turn.text}`);
|
|
16173
|
+
} else {
|
|
16174
|
+
if (turn.tool)
|
|
16175
|
+
aiTools.set(turn.tool, (aiTools.get(turn.tool) ?? 0) + 1);
|
|
16176
|
+
if (turn.text)
|
|
16177
|
+
aiProse = turn.text.replace(/\s+/g, " ").trim();
|
|
16178
|
+
}
|
|
16179
|
+
}
|
|
16180
|
+
flushAI();
|
|
16181
|
+
return { text: lines.join("\n"), humanTurns, humanChars };
|
|
16182
|
+
}
|
|
16183
|
+
function composerIdFromFile(file2) {
|
|
16184
|
+
const m = file2.match(/agent-transcripts\/([^/]+)\/[^/]+\.jsonl$/);
|
|
16185
|
+
return m ? m[1] : null;
|
|
16186
|
+
}
|
|
16187
|
+
async function loadCursorComposer(file2, raw, dbPath) {
|
|
16188
|
+
const cid = composerIdFromFile(file2);
|
|
16189
|
+
if (cid && dbPath) {
|
|
16190
|
+
const db = await openCursorSqlite(dbPath);
|
|
16191
|
+
if (db) {
|
|
16192
|
+
try {
|
|
16193
|
+
const c = readCursorComposer(db, cid);
|
|
16194
|
+
if (c)
|
|
16195
|
+
return c;
|
|
16196
|
+
} finally {
|
|
16197
|
+
db.close();
|
|
16198
|
+
}
|
|
16199
|
+
}
|
|
16200
|
+
}
|
|
16201
|
+
return parseCursorJsonl(raw, 0);
|
|
16202
|
+
}
|
|
16203
|
+
|
|
16204
|
+
// ../coding-core/dist/raw.js
|
|
16205
|
+
import path9 from "path";
|
|
16206
|
+
import os2 from "os";
|
|
16207
|
+
var SOURCE_ROOT_ENV_VARS = [
|
|
16208
|
+
"CLAUDE_PROJECTS_DIR",
|
|
16209
|
+
"CODEX_SESSIONS_DIR",
|
|
16210
|
+
"CURSOR_WORKSPACE_DIR",
|
|
16211
|
+
"CURSOR_PROJECTS_DIR",
|
|
16212
|
+
// Cursor's globalStorage dir (holds state.vscdb — the composer bubbles that
|
|
16213
|
+
// carry a Cursor session's real per-turn timestamps + content). Same
|
|
16214
|
+
// isolation contract: overriding any root disables every unset source.
|
|
16215
|
+
"CURSOR_GLOBAL_DIR"
|
|
16216
|
+
];
|
|
16217
|
+
var anyRootOverridden = () => SOURCE_ROOT_ENV_VARS.some((v) => !!process.env[v]);
|
|
16218
|
+
function resolveSourceRoot(envVar, ...defaultSegments) {
|
|
16219
|
+
const explicit = process.env[envVar];
|
|
16220
|
+
if (explicit)
|
|
16221
|
+
return explicit;
|
|
16222
|
+
if (anyRootOverridden())
|
|
16223
|
+
return null;
|
|
16224
|
+
return path9.join(os2.homedir(), ...defaultSegments);
|
|
16225
|
+
}
|
|
16226
|
+
var cursorGlobalRoot = () => resolveSourceRoot("CURSOR_GLOBAL_DIR", "Library", "Application Support", "Cursor", "User", "globalStorage");
|
|
16227
|
+
function cursorGlobalDbPath() {
|
|
16228
|
+
const root = cursorGlobalRoot();
|
|
16229
|
+
return root === null ? null : path9.join(root, "state.vscdb");
|
|
16230
|
+
}
|
|
16231
|
+
var MACHINE_CURSOR_FILE_RE = /^(.*[/\\]machines[/\\][^/\\]+[/\\]\.cursor)[/\\]projects[/\\]/;
|
|
16232
|
+
function cursorDbPathForFile(file2) {
|
|
16233
|
+
const m = file2.match(MACHINE_CURSOR_FILE_RE);
|
|
16234
|
+
if (m)
|
|
16235
|
+
return path9.join(m[1], "globalStorage", "state.vscdb");
|
|
16236
|
+
return cursorGlobalDbPath();
|
|
16237
|
+
}
|
|
16238
|
+
|
|
15905
16239
|
// ../coding-core/dist/messages.js
|
|
15906
16240
|
function extractText(content) {
|
|
15907
16241
|
if (typeof content === "string")
|
|
@@ -15929,15 +16263,35 @@ function extractUserMessagesCodex(raw) {
|
|
|
15929
16263
|
}
|
|
15930
16264
|
return out.sort((a, b) => a.t - b.t);
|
|
15931
16265
|
}
|
|
16266
|
+
function extractUserMessagesCursor(c) {
|
|
16267
|
+
const out = [];
|
|
16268
|
+
let lastTs = null;
|
|
16269
|
+
for (const turn of c.turns) {
|
|
16270
|
+
const t = turn.t;
|
|
16271
|
+
const gapMs = Number.isFinite(t) && lastTs != null ? t - lastTs : NaN;
|
|
16272
|
+
if (Number.isFinite(t))
|
|
16273
|
+
lastTs = t;
|
|
16274
|
+
if (turn.type !== 1)
|
|
16275
|
+
continue;
|
|
16276
|
+
const text2 = humanTypedText(turn.text);
|
|
16277
|
+
if (text2 && Number.isFinite(t))
|
|
16278
|
+
out.push({ t, text: text2, gapMs });
|
|
16279
|
+
}
|
|
16280
|
+
return out.sort((a, b) => a.t - b.t);
|
|
16281
|
+
}
|
|
15932
16282
|
async function extractUserMessages(file2) {
|
|
15933
16283
|
let raw;
|
|
15934
16284
|
try {
|
|
15935
|
-
raw = await
|
|
16285
|
+
raw = await fs6.readFile(file2, "utf-8");
|
|
15936
16286
|
} catch {
|
|
15937
16287
|
return [];
|
|
15938
16288
|
}
|
|
15939
16289
|
if (sniffCodexRaw(raw))
|
|
15940
16290
|
return extractUserMessagesCodex(raw);
|
|
16291
|
+
if (sniffCursorRaw(raw)) {
|
|
16292
|
+
const c = await loadCursorComposer(file2, raw, cursorDbPathForFile(file2));
|
|
16293
|
+
return c ? extractUserMessagesCursor(c) : [];
|
|
16294
|
+
}
|
|
15941
16295
|
const out = [];
|
|
15942
16296
|
const userTexts = /* @__PURE__ */ new Set();
|
|
15943
16297
|
const seenUuids = /* @__PURE__ */ new Set();
|
|
@@ -15984,11 +16338,11 @@ async function extractUserMessages(file2) {
|
|
|
15984
16338
|
}
|
|
15985
16339
|
|
|
15986
16340
|
// ../../lib/agents/coding/walkthrough.ts
|
|
15987
|
-
import { promises as
|
|
15988
|
-
import
|
|
16341
|
+
import { promises as fs7 } from "fs";
|
|
16342
|
+
import path10 from "path";
|
|
15989
16343
|
var IDLE_CAP_MS = 12 * 6e4;
|
|
15990
16344
|
async function readWalkthrough(outDir, sessionId) {
|
|
15991
|
-
return
|
|
16345
|
+
return fs7.readFile(path10.join(outDir, `${sessionId}.json`), "utf8").then(JSON.parse).catch(() => null);
|
|
15992
16346
|
}
|
|
15993
16347
|
|
|
15994
16348
|
// ../coding-core/dist/words.js
|
|
@@ -16400,7 +16754,7 @@ function computeWorkstyle(inp) {
|
|
|
16400
16754
|
|
|
16401
16755
|
// ../../lib/calibration/index.ts
|
|
16402
16756
|
var DEFAULT_CALIBRATION = {
|
|
16403
|
-
version: "2026-07-
|
|
16757
|
+
version: "2026-07-21.1",
|
|
16404
16758
|
// = RUBRIC_FINGERPRINT of the shipped npm rubric (packages/coding-analyzer/
|
|
16405
16759
|
// src/grade/criteria.ts). A unit test fails loud when the rubric changes
|
|
16406
16760
|
// without this being updated (and re-pushed to the server).
|
|
@@ -16496,13 +16850,14 @@ var DEFAULT_CALIBRATION = {
|
|
|
16496
16850
|
},
|
|
16497
16851
|
codingBenchmarks: {
|
|
16498
16852
|
flow: {
|
|
16499
|
-
// typical knowledge worker ≈ 35% of an 8h day focused; ~4h/day
|
|
16500
|
-
//
|
|
16853
|
+
// typical knowledge worker ≈ 35% of an 8h day focused; the ~4h/day
|
|
16854
|
+
// deep-work ceiling (Newport) sits nearer ~40% of a real (9-10h) top
|
|
16855
|
+
// performer's day — 50% overstated it (owner call 2026-07-21).
|
|
16501
16856
|
typicalPctOfDay: 0.35,
|
|
16502
|
-
topPctOfDay: 0.
|
|
16857
|
+
topPctOfDay: 0.4,
|
|
16503
16858
|
tag: "measured",
|
|
16504
|
-
source: "RescueTime 2019 (~2h48m focused/day) \xB7 Cal Newport, Deep Work (~4h/day deep-work ceiling)",
|
|
16505
|
-
line: "the best spend ~
|
|
16859
|
+
source: "RescueTime 2019 (~2h48m focused/day) \xB7 Cal Newport, Deep Work (~4h/day deep-work ceiling against a 9-10h day)",
|
|
16860
|
+
line: "the best spend ~40% of the workday in true deep flow; ~4h/day is the human ceiling"
|
|
16506
16861
|
},
|
|
16507
16862
|
longestRun: {
|
|
16508
16863
|
typicalHours: 0.67,
|
|
@@ -16551,13 +16906,20 @@ function bandLabel(score, doc = DEFAULT_CALIBRATION) {
|
|
|
16551
16906
|
for (const b of doc.scoreBands) if (b.score <= s && (!best || b.score > best.score)) best = b;
|
|
16552
16907
|
return (best ?? doc.scoreBands[0]).label;
|
|
16553
16908
|
}
|
|
16909
|
+
function scoreForTopPct(topPct, doc = DEFAULT_CALIBRATION) {
|
|
16910
|
+
for (const b of doc.scoreBands) {
|
|
16911
|
+
const x = parseFloat(b.label.replace(/^Top\s+/i, ""));
|
|
16912
|
+
if (Number.isFinite(x) && topPct <= x) return b.score;
|
|
16913
|
+
}
|
|
16914
|
+
return 1;
|
|
16915
|
+
}
|
|
16554
16916
|
|
|
16555
16917
|
// ../../lib/agents/coding/benchmarks.ts
|
|
16556
16918
|
var BEST = DEFAULT_CALIBRATION.codingBenchmarks;
|
|
16557
16919
|
|
|
16558
16920
|
// ../../lib/agents/coding/profile.ts
|
|
16559
16921
|
var ROOT = process.cwd();
|
|
16560
|
-
var CODING_DIR = process.env.POLYMATH_DATA_DIR ?
|
|
16922
|
+
var CODING_DIR = process.env.POLYMATH_DATA_DIR ? path11.join(process.env.POLYMATH_DATA_DIR, "coding") : path11.join(ROOT, ".data", "coding");
|
|
16561
16923
|
var UMETA = /* @__PURE__ */ new Map();
|
|
16562
16924
|
async function userMeta(sessionId, file2) {
|
|
16563
16925
|
const hit = UMETA.get(sessionId);
|
|
@@ -16567,9 +16929,9 @@ async function userMeta(sessionId, file2) {
|
|
|
16567
16929
|
UMETA.set(sessionId, meta);
|
|
16568
16930
|
return meta;
|
|
16569
16931
|
}
|
|
16570
|
-
var GRADES =
|
|
16932
|
+
var GRADES = path11.join(CODING_DIR, "grades");
|
|
16571
16933
|
async function readJson(p, fallback) {
|
|
16572
|
-
return
|
|
16934
|
+
return fs8.readFile(p, "utf8").then((s) => JSON.parse(s)).catch(() => fallback);
|
|
16573
16935
|
}
|
|
16574
16936
|
function cadenceScore(fraction, multiRatio) {
|
|
16575
16937
|
let s;
|
|
@@ -16609,21 +16971,27 @@ var NO_GRADES_GAP = "no sessions graded for this yet \u2014 this fills in once g
|
|
|
16609
16971
|
function estimateRowParts(score, nTakes, evidenceGap) {
|
|
16610
16972
|
return nTakes === 0 && score == null ? { score: null, gap: NO_GRADES_GAP } : { score, gap: evidenceGap };
|
|
16611
16973
|
}
|
|
16974
|
+
function verdictRowParts(v, fallback) {
|
|
16975
|
+
if (!v) return fallback;
|
|
16976
|
+
const ranged = v.confidence === "provisional" || (v.qualifying ?? 0) < 2;
|
|
16977
|
+
if (ranged) return { score: null, gap: `best ${v.best} inside an honest ${v.low}-${v.high} range so far. ${v.verdictLine} (${v.statsLine})`.trim() };
|
|
16978
|
+
return { score: v.best, gap: `${v.verdictLine} (${v.statsLine})`.trim() };
|
|
16979
|
+
}
|
|
16612
16980
|
async function compileCodingProfile() {
|
|
16613
|
-
const allRecords = await readJson(
|
|
16981
|
+
const allRecords = await readJson(path11.join(CODING_DIR, "sessions.json"), []);
|
|
16614
16982
|
const dupIds = new Set(allRecords.filter((s) => s.duplicateOf).map((s) => s.sessionId));
|
|
16615
16983
|
const sessions = allRecords.filter((s) => !s.duplicateOf);
|
|
16616
|
-
const conc = await readJson(
|
|
16617
|
-
const renames = await readJson(
|
|
16984
|
+
const conc = await readJson(path11.join(CODING_DIR, "concurrency.json"), null);
|
|
16985
|
+
const renames = await readJson(path11.join(CODING_DIR, "renames.json"), []);
|
|
16618
16986
|
const byId = new Map(sessions.map((s) => [s.sessionId, s]));
|
|
16619
16987
|
let gradeFiles = [];
|
|
16620
16988
|
try {
|
|
16621
|
-
gradeFiles = (await
|
|
16989
|
+
gradeFiles = (await fs8.readdir(GRADES)).filter((f) => f.endsWith(".json"));
|
|
16622
16990
|
} catch {
|
|
16623
16991
|
}
|
|
16624
16992
|
const grades = [];
|
|
16625
16993
|
for (const f of gradeFiles) {
|
|
16626
|
-
const g = await readJson(
|
|
16994
|
+
const g = await readJson(path11.join(GRADES, f), null);
|
|
16627
16995
|
if (g && byId.has(g.sessionId)) grades.push(g);
|
|
16628
16996
|
}
|
|
16629
16997
|
const takesByCriterion = /* @__PURE__ */ new Map();
|
|
@@ -16700,9 +17068,12 @@ async function compileCodingProfile() {
|
|
|
16700
17068
|
const timeline = [...dayMap.values()].sort((a, b) => b.date.localeCompare(a.date));
|
|
16701
17069
|
const levelHist = conc?.levelHistogramMin ?? {};
|
|
16702
17070
|
const sumFrom = (min) => Object.entries(levelHist).filter(([k]) => Number(k) >= min).reduce((a, [, v]) => a + v, 0);
|
|
17071
|
+
const totalParallelMin = Object.values(levelHist).reduce((a, v) => a + v, 0);
|
|
17072
|
+
const avgConcurrency = totalParallelMin > 0 ? Math.round(Object.entries(levelHist).reduce((a, [k, v]) => a + Number(k) * v, 0) / totalParallelMin * 10) / 10 : 0;
|
|
16703
17073
|
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))] }));
|
|
16704
17074
|
const parallelism = {
|
|
16705
17075
|
maxConcurrency: conc?.maxConcurrency ?? 0,
|
|
17076
|
+
avgConcurrency,
|
|
16706
17077
|
levelHistogramMin: levelHist,
|
|
16707
17078
|
minutesAt2plus: Math.round(sumFrom(2)),
|
|
16708
17079
|
minutesAt6plus: Math.round(sumFrom(6)),
|
|
@@ -16732,13 +17103,13 @@ async function compileCodingProfile() {
|
|
|
16732
17103
|
models: Object.fromEntries([...models.entries()].sort((a, b) => b[1] - a[1])),
|
|
16733
17104
|
lateNightSessions: lateNight
|
|
16734
17105
|
};
|
|
16735
|
-
const agglomeration = await readJson(
|
|
16736
|
-
const dayDigest = await readJson(
|
|
17106
|
+
const agglomeration = await readJson(path11.join(CODING_DIR, "agglomerate.json"), null);
|
|
17107
|
+
const dayDigest = await readJson(path11.join(CODING_DIR, "day-digest.json"), null);
|
|
16737
17108
|
if (dayDigest?.days) dayDigest.days = dayDigest.days.map((day) => {
|
|
16738
17109
|
const convs = day.conversations.filter((c) => byId.has(c.sessionId));
|
|
16739
17110
|
return { ...day, conversations: convs, conversationsTouched: convs.length, totalMessages: convs.reduce((a, c) => a + c.messageCount, 0) };
|
|
16740
17111
|
}).filter((day) => day.conversations.length > 0);
|
|
16741
|
-
const dayChart = await readJson(
|
|
17112
|
+
const dayChart = await readJson(path11.join(CODING_DIR, "day-chart.json"), []);
|
|
16742
17113
|
const intervalsBy = /* @__PURE__ */ new Map();
|
|
16743
17114
|
const titleBy = /* @__PURE__ */ new Map();
|
|
16744
17115
|
const fileById = new Map(sessions.map((s) => [s.sessionId, s.file]));
|
|
@@ -16757,8 +17128,8 @@ async function compileCodingProfile() {
|
|
|
16757
17128
|
return ms;
|
|
16758
17129
|
};
|
|
16759
17130
|
const walkthroughs = {};
|
|
16760
|
-
const wdir =
|
|
16761
|
-
for (const f of await
|
|
17131
|
+
const wdir = path11.join(CODING_DIR, "walkthroughs");
|
|
17132
|
+
for (const f of await fs8.readdir(wdir).catch(() => [])) {
|
|
16762
17133
|
if (!f.endsWith(".json")) continue;
|
|
16763
17134
|
const w = await readWalkthrough(wdir, f.replace(".json", ""));
|
|
16764
17135
|
if (!w || !byId.has(w.sessionId)) continue;
|
|
@@ -16805,17 +17176,19 @@ async function compileCodingProfile() {
|
|
|
16805
17176
|
const tCeiling = throughputCeiling(Object.values(wordsByDay));
|
|
16806
17177
|
const criteriaMean = {};
|
|
16807
17178
|
for (const c of criteria) criteriaMean[c.key] = { mean: c.dist.mean, n: c.dist.n };
|
|
16808
|
-
const flow = await readJson(
|
|
16809
|
-
const focus = await readJson(
|
|
16810
|
-
const expertiseMap = await readJson(
|
|
16811
|
-
const frontierArsenal = await readJson(
|
|
16812
|
-
const frontierDetail = await readJson(
|
|
16813
|
-
const coaching = await readJson(
|
|
16814
|
-
const gap = await readJson(
|
|
16815
|
-
const aggregate = await readJson(
|
|
16816
|
-
const delegationRollup = await readJson(
|
|
16817
|
-
const gapDist = await readJson(
|
|
16818
|
-
const projects = await readJson(
|
|
17179
|
+
const flow = await readJson(path11.join(CODING_DIR, "flow.json"), null);
|
|
17180
|
+
const focus = await readJson(path11.join(CODING_DIR, "focus.json"), null);
|
|
17181
|
+
const expertiseMap = await readJson(path11.join(CODING_DIR, "expertise.json"), null);
|
|
17182
|
+
const frontierArsenal = await readJson(path11.join(CODING_DIR, "frontier.json"), null);
|
|
17183
|
+
const frontierDetail = await readJson(path11.join(CODING_DIR, "frontier-detail.json"), null);
|
|
17184
|
+
const coaching = await readJson(path11.join(CODING_DIR, "coaching.json"), null);
|
|
17185
|
+
const gap = await readJson(path11.join(CODING_DIR, "gap.json"), null);
|
|
17186
|
+
const aggregate = await readJson(path11.join(CODING_DIR, "aggregate.json"), null);
|
|
17187
|
+
const delegationRollup = await readJson(path11.join(CODING_DIR, "delegation-rollup.json"), null);
|
|
17188
|
+
const gapDist = await readJson(path11.join(CODING_DIR, "gap-dist.json"), null);
|
|
17189
|
+
const projects = await readJson(path11.join(CODING_DIR, "projects.json"), null);
|
|
17190
|
+
const growth = await readJson(path11.join(CODING_DIR, "growth.json"), null);
|
|
17191
|
+
const workbrief = await readJson(path11.join(CODING_DIR, "workbrief.json"), null);
|
|
16819
17192
|
const workstyle = computeWorkstyle({
|
|
16820
17193
|
dayChart,
|
|
16821
17194
|
tz,
|
|
@@ -16875,15 +17248,25 @@ async function compileCodingProfile() {
|
|
|
16875
17248
|
const hoursPctl = lognPct(workDayHrs, tiers?.hours);
|
|
16876
17249
|
const hoursAt = (min) => Object.entries(pHist).reduce((a, [k, v]) => Number(k) >= min ? a + v : a, 0) / 60;
|
|
16877
17250
|
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;
|
|
17251
|
+
const estScore = (pctl) => pctl == null ? null : scoreForTopPct(100 - pctl);
|
|
16878
17252
|
const stackUp = [
|
|
17253
|
+
// The subtext leads with the AVERAGE — that is the number this row is
|
|
17254
|
+
// scored and pool-ranked on (wordsPerDay); a peak-led line once shipped
|
|
17255
|
+
// next to an average-based rank and read as a mismatch (owner call
|
|
17256
|
+
// 2026-07-21). The peak rides along as color.
|
|
16879
17257
|
sRow(
|
|
16880
17258
|
"How hard you push",
|
|
16881
|
-
aggregate?.throughput?.score ?? tCeiling,
|
|
16882
|
-
`you
|
|
17259
|
+
estScore(pushPctl) ?? aggregate?.throughput?.score ?? tCeiling,
|
|
17260
|
+
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`
|
|
16883
17261
|
),
|
|
17262
|
+
// Graded like its siblings from the SAME fitted hours curve that ranks it
|
|
17263
|
+
// (tiers.hours → hoursPctl → estScore) and feeds the shared pool, so the
|
|
17264
|
+
// 1-11 badge can never contradict the pooled rank. Was `null` until
|
|
17265
|
+
// 2026-07-21, which left this the only measured row with no grade shown —
|
|
17266
|
+
// it read as broken next to push/parallelism/focus (owner call).
|
|
16884
17267
|
sRow(
|
|
16885
17268
|
"Hours you put in",
|
|
16886
|
-
|
|
17269
|
+
estScore(hoursPctl),
|
|
16887
17270
|
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"
|
|
16888
17271
|
),
|
|
16889
17272
|
// The copy FOLLOWS the person's actual orchestration band (orchPctl above) —
|
|
@@ -16894,7 +17277,7 @@ async function compileCodingProfile() {
|
|
|
16894
17277
|
// orchestration.
|
|
16895
17278
|
sRow(
|
|
16896
17279
|
"Your AI parallelism",
|
|
16897
|
-
|
|
17280
|
+
estScore(orchPctl),
|
|
16898
17281
|
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"
|
|
16899
17282
|
),
|
|
16900
17283
|
// The evidence line cites the RANKING metric (flow as a share of the work
|
|
@@ -16905,7 +17288,7 @@ async function compileCodingProfile() {
|
|
|
16905
17288
|
// the volume of hours is its own chip above.
|
|
16906
17289
|
sRow(
|
|
16907
17290
|
"Focus quality when you work",
|
|
16908
|
-
focusScore,
|
|
17291
|
+
estScore(focusPctl) ?? focusScore,
|
|
16909
17292
|
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"
|
|
16910
17293
|
),
|
|
16911
17294
|
// The four estimates LEAD with a concrete moment from their own sessions, then an
|
|
@@ -16954,24 +17337,39 @@ async function compileCodingProfile() {
|
|
|
16954
17337
|
}
|
|
16955
17338
|
if (r.label === "Your AI parallelism") r.percentile = orchPctl;
|
|
16956
17339
|
}
|
|
16957
|
-
|
|
17340
|
+
if (agglomeration?.verdicts) {
|
|
17341
|
+
const byLabel = {
|
|
17342
|
+
Judgement: agglomeration.verdicts.judgement,
|
|
17343
|
+
Agency: agglomeration.verdicts.agency,
|
|
17344
|
+
Taste: agglomeration.verdicts.taste
|
|
17345
|
+
};
|
|
17346
|
+
for (const r of stackUp) {
|
|
17347
|
+
const v = byLabel[r.label];
|
|
17348
|
+
if (!v) continue;
|
|
17349
|
+
const p = verdictRowParts(v, { score: r.score, gap: r.gap });
|
|
17350
|
+
r.score = p.score;
|
|
17351
|
+
r.gap = p.gap;
|
|
17352
|
+
r.percentile = pctOf(p.score);
|
|
17353
|
+
}
|
|
17354
|
+
}
|
|
17355
|
+
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 };
|
|
16958
17356
|
}
|
|
16959
17357
|
|
|
16960
17358
|
// ../../lib/agents/coding/assets.ts
|
|
16961
|
-
import { promises as
|
|
16962
|
-
import
|
|
17359
|
+
import { promises as fs9 } from "fs";
|
|
17360
|
+
import path12 from "path";
|
|
16963
17361
|
import { fileURLToPath } from "url";
|
|
16964
|
-
var MODULE_DIR =
|
|
17362
|
+
var MODULE_DIR = path12.dirname(fileURLToPath(import.meta.url));
|
|
16965
17363
|
async function readCodingAsset(name17) {
|
|
16966
17364
|
const candidates = [
|
|
16967
|
-
|
|
17365
|
+
path12.join(MODULE_DIR, name17),
|
|
16968
17366
|
// dev: beside this file · bundled: beside the bundle
|
|
16969
|
-
|
|
17367
|
+
path12.resolve("lib", "agents", "coding", name17)
|
|
16970
17368
|
// legacy cwd-relative (repo-root cwd)
|
|
16971
17369
|
];
|
|
16972
17370
|
for (const p of candidates) {
|
|
16973
17371
|
try {
|
|
16974
|
-
return { text: await
|
|
17372
|
+
return { text: await fs9.readFile(p, "utf8"), path: p };
|
|
16975
17373
|
} catch {
|
|
16976
17374
|
}
|
|
16977
17375
|
}
|
|
@@ -16981,11 +17379,11 @@ async function readCodingAsset(name17) {
|
|
|
16981
17379
|
}
|
|
16982
17380
|
|
|
16983
17381
|
// ../../lib/agents/coding/docsDir.ts
|
|
16984
|
-
import { promises as
|
|
16985
|
-
import
|
|
17382
|
+
import { promises as fs11 } from "fs";
|
|
17383
|
+
import path13 from "path";
|
|
16986
17384
|
|
|
16987
17385
|
// ../../lib/agents/coding/materialize.ts
|
|
16988
|
-
import { promises as
|
|
17386
|
+
import { promises as fs10 } from "fs";
|
|
16989
17387
|
var SYSTEM_REMINDER_RE3 = /<system-reminder>[\s\S]*?<\/system-reminder>/g;
|
|
16990
17388
|
var INJECT_GIST = 120;
|
|
16991
17389
|
var INJECTED = [
|
|
@@ -17022,7 +17420,7 @@ function extractText2(content) {
|
|
|
17022
17420
|
function isToolResultOnly2(content) {
|
|
17023
17421
|
return Array.isArray(content) && content.length > 0 && content.every((c) => c && typeof c === "object" && c.type === "tool_result");
|
|
17024
17422
|
}
|
|
17025
|
-
var
|
|
17423
|
+
var AI_GIST2 = 160;
|
|
17026
17424
|
function materializeCodex(raw) {
|
|
17027
17425
|
const lines = [];
|
|
17028
17426
|
let humanTurns = 0, humanChars = 0;
|
|
@@ -17031,7 +17429,7 @@ function materializeCodex(raw) {
|
|
|
17031
17429
|
const flushAI = () => {
|
|
17032
17430
|
if (!aiLastProse && aiTools.size === 0) return;
|
|
17033
17431
|
const tools = [...aiTools.entries()].map(([n, c]) => c > 1 ? `${n}\xD7${c}` : n).join(", ");
|
|
17034
|
-
const gist = aiLastProse ? aiLastProse.length >
|
|
17432
|
+
const gist = aiLastProse ? aiLastProse.length > AI_GIST2 ? aiLastProse.slice(0, AI_GIST2) + "\u2026" : aiLastProse : "";
|
|
17035
17433
|
const bits = [];
|
|
17036
17434
|
if (gist) bits.push(gist);
|
|
17037
17435
|
if (tools) bits.push(`ran ${tools}`);
|
|
@@ -17055,14 +17453,19 @@ function materializeCodex(raw) {
|
|
|
17055
17453
|
flushAI();
|
|
17056
17454
|
return { text: lines.join("\n"), humanTurns, humanChars };
|
|
17057
17455
|
}
|
|
17456
|
+
async function materializeCursor(file2, raw) {
|
|
17457
|
+
const composer = await loadCursorComposer(file2, raw, cursorDbPathForFile(file2));
|
|
17458
|
+
return composer ? renderCursorTranscript(composer) : { text: "", humanTurns: 0, humanChars: 0 };
|
|
17459
|
+
}
|
|
17058
17460
|
async function materializeSession(file2) {
|
|
17059
17461
|
let raw;
|
|
17060
17462
|
try {
|
|
17061
|
-
raw = await
|
|
17463
|
+
raw = await fs10.readFile(file2, "utf-8");
|
|
17062
17464
|
} catch {
|
|
17063
17465
|
return null;
|
|
17064
17466
|
}
|
|
17065
17467
|
if (sniffCodexRaw(raw)) return materializeCodex(raw);
|
|
17468
|
+
if (sniffCursorRaw(raw)) return materializeCursor(file2, raw);
|
|
17066
17469
|
const lines = [];
|
|
17067
17470
|
let humanTurns = 0, humanChars = 0;
|
|
17068
17471
|
const pendingQueued = [];
|
|
@@ -17075,7 +17478,7 @@ async function materializeSession(file2) {
|
|
|
17075
17478
|
const flushAI = () => {
|
|
17076
17479
|
if (!aiLastProse && aiTools.size === 0) return;
|
|
17077
17480
|
const tools = [...aiTools.entries()].map(([n, c]) => c > 1 ? `${n}\xD7${c}` : n).join(", ");
|
|
17078
|
-
const gist = aiLastProse ? aiLastProse.length >
|
|
17481
|
+
const gist = aiLastProse ? aiLastProse.length > AI_GIST2 ? aiLastProse.slice(0, AI_GIST2) + "\u2026" : aiLastProse : "";
|
|
17079
17482
|
const bits = [];
|
|
17080
17483
|
if (gist) bits.push(gist);
|
|
17081
17484
|
if (tools) bits.push(`ran ${tools}`);
|
|
@@ -17155,10 +17558,10 @@ async function materializeSession(file2) {
|
|
|
17155
17558
|
|
|
17156
17559
|
// ../../lib/agents/coding/docsDir.ts
|
|
17157
17560
|
async function writeScoreboard(codingDir, docs) {
|
|
17158
|
-
const gradesDir =
|
|
17561
|
+
const gradesDir = path13.join(codingDir, "grades");
|
|
17159
17562
|
let files = [];
|
|
17160
17563
|
try {
|
|
17161
|
-
files = (await
|
|
17564
|
+
files = (await fs11.readdir(gradesDir)).filter((f) => f.endsWith(".json")).sort();
|
|
17162
17565
|
} catch {
|
|
17163
17566
|
return;
|
|
17164
17567
|
}
|
|
@@ -17166,7 +17569,7 @@ async function writeScoreboard(codingDir, docs) {
|
|
|
17166
17569
|
for (const f of files) {
|
|
17167
17570
|
let g;
|
|
17168
17571
|
try {
|
|
17169
|
-
g = JSON.parse(await
|
|
17572
|
+
g = JSON.parse(await fs11.readFile(path13.join(gradesDir, f), "utf8"));
|
|
17170
17573
|
} catch {
|
|
17171
17574
|
continue;
|
|
17172
17575
|
}
|
|
@@ -17182,8 +17585,8 @@ async function writeScoreboard(codingDir, docs) {
|
|
|
17182
17585
|
([key, rows]) => `## ${key}
|
|
17183
17586
|
${rows.sort((a, b) => b.s - a.s).map((r) => r.line).join("\n")}`
|
|
17184
17587
|
);
|
|
17185
|
-
await
|
|
17186
|
-
|
|
17588
|
+
await fs11.writeFile(
|
|
17589
|
+
path13.join(docs, "_scoreboard.md"),
|
|
17187
17590
|
`# Scoreboard \u2014 every graded session per criterion, best first.
|
|
17188
17591
|
# Lx~ = estimate. Format: level \xB7 date \xB7 title \xB7 sessionId \u2014 graded instance.
|
|
17189
17592
|
|
|
@@ -17192,24 +17595,24 @@ ${blocks.join("\n\n")}
|
|
|
17192
17595
|
);
|
|
17193
17596
|
}
|
|
17194
17597
|
async function ensureCodingDocs(codingDir, sessions) {
|
|
17195
|
-
const docs =
|
|
17196
|
-
await
|
|
17598
|
+
const docs = path13.join(codingDir, "docs");
|
|
17599
|
+
await fs11.mkdir(docs, { recursive: true });
|
|
17197
17600
|
const user = sessions.filter((s) => s.sessionId && !s.duplicateOf && (!("klass" in s) || s.klass === "interactive"));
|
|
17198
17601
|
let written = 0;
|
|
17199
17602
|
for (const s of user) {
|
|
17200
|
-
const out =
|
|
17603
|
+
const out = path13.join(docs, `${s.sessionId}.txt`);
|
|
17201
17604
|
try {
|
|
17202
|
-
await
|
|
17605
|
+
await fs11.access(out);
|
|
17203
17606
|
continue;
|
|
17204
17607
|
} catch {
|
|
17205
17608
|
}
|
|
17206
17609
|
const mat = await materializeSession(s.file).catch(() => null);
|
|
17207
17610
|
if (!mat?.text) continue;
|
|
17208
|
-
await
|
|
17611
|
+
await fs11.writeFile(out, mat.text);
|
|
17209
17612
|
written++;
|
|
17210
17613
|
}
|
|
17211
17614
|
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}`);
|
|
17212
|
-
await
|
|
17615
|
+
await fs11.writeFile(path13.join(docs, "_map.md"), rows.join("\n") + "\n");
|
|
17213
17616
|
await writeScoreboard(codingDir, docs);
|
|
17214
17617
|
if (written) console.log(`[docs] materialized ${written} new transcript(s) \u2192 ${docs}`);
|
|
17215
17618
|
return docs;
|
|
@@ -17222,7 +17625,7 @@ SOURCE LOOKUP \u2014 you have Read/Grep/Glob over the working directory, which h
|
|
|
17222
17625
|
|
|
17223
17626
|
// ../../lib/agents/coding/promptCache.ts
|
|
17224
17627
|
import { createHash as createHash2 } from "crypto";
|
|
17225
|
-
import { promises as
|
|
17628
|
+
import { promises as fs12 } from "fs";
|
|
17226
17629
|
function promptSha(parts) {
|
|
17227
17630
|
const h = createHash2("sha256");
|
|
17228
17631
|
for (const p of parts) {
|
|
@@ -17233,7 +17636,7 @@ function promptSha(parts) {
|
|
|
17233
17636
|
}
|
|
17234
17637
|
async function reusableOutput(outPath, sha, valid, key = "promptSha") {
|
|
17235
17638
|
try {
|
|
17236
|
-
const o = JSON.parse(await
|
|
17639
|
+
const o = JSON.parse(await fs12.readFile(outPath, "utf8"));
|
|
17237
17640
|
if (o[key] === sha && valid(o)) return o;
|
|
17238
17641
|
} catch {
|
|
17239
17642
|
}
|
|
@@ -17253,7 +17656,7 @@ var CLAUDE_AUTO_CAP = /* @__PURE__ */ new Set(["queue-ahead", "deferred-tools",
|
|
|
17253
17656
|
var CLAUDE_AUTO_MCP = /^(visualize|Claude[_ ]?Preview|ccd[_ ]?session|ccd[_ ]?session[_ ]?mgmt|mcp[_ ]?registry)$/i;
|
|
17254
17657
|
async function entrypointOf(file2) {
|
|
17255
17658
|
try {
|
|
17256
|
-
const head = (await
|
|
17659
|
+
const head = (await fs13.readFile(file2, "utf8")).slice(0, 2e4);
|
|
17257
17660
|
if (/[\/."]\.?conductor/i.test(head)) return "conductor";
|
|
17258
17661
|
const m = /"entrypoint":"([^"]+)"/.exec(head);
|
|
17259
17662
|
return m ? m[1] : "unknown";
|
|
@@ -17275,25 +17678,15 @@ var MOBILE_WEB = /^claude-(web|mobile|ios|android)$/;
|
|
|
17275
17678
|
function sumTool(recs, name17) {
|
|
17276
17679
|
return recs.reduce((a, s) => a + (s.toolCounts?.[name17] ?? 0), 0);
|
|
17277
17680
|
}
|
|
17278
|
-
var LOCK =
|
|
17279
|
-
var lockHeld = false;
|
|
17280
|
-
async function acquireLock() {
|
|
17281
|
-
try {
|
|
17282
|
-
await fs11.writeFile(LOCK, String(process.pid), { flag: "wx" });
|
|
17283
|
-
lockHeld = true;
|
|
17284
|
-
} catch {
|
|
17285
|
-
const pid = await fs11.readFile(LOCK, "utf8").catch(() => "?");
|
|
17286
|
-
throw new Error(`another coding-gap run appears active (pid ${pid}, ${LOCK}). Wait for it or delete the lock if it's stale \u2014 concurrent runs overwrite each other's gap.json.`);
|
|
17287
|
-
}
|
|
17288
|
-
}
|
|
17681
|
+
var LOCK = path14.join(CODING, ".gap.lock");
|
|
17289
17682
|
async function main() {
|
|
17290
|
-
await
|
|
17683
|
+
releaseLock = await acquireStageLock(LOCK, "coding-gap");
|
|
17291
17684
|
const p = await compileCodingProfile();
|
|
17292
17685
|
const techniquesAsset = await readCodingAsset("TECHNIQUES.md");
|
|
17293
17686
|
const techniques = techniquesAsset.text;
|
|
17294
|
-
console.log(` rubric: ${techniquesAsset.path} (${(await
|
|
17687
|
+
console.log(` rubric: ${techniquesAsset.path} (${(await fs13.stat(techniquesAsset.path)).mtime.toISOString()})`);
|
|
17295
17688
|
const writing = (await readCodingAsset("WRITING.md")).text;
|
|
17296
|
-
const all = JSON.parse(await
|
|
17689
|
+
const all = JSON.parse(await fs13.readFile(path14.join(CODING, "sessions.json"), "utf8"));
|
|
17297
17690
|
const interactive = all.filter((s) => s.klass === "interactive" && s.start);
|
|
17298
17691
|
const latestMs = Math.max(...interactive.map((s) => Date.parse(s.start)));
|
|
17299
17692
|
const cutoffMs = latestMs - 14 * 864e5;
|
|
@@ -17350,7 +17743,7 @@ async function main() {
|
|
|
17350
17743
|
return m ? `--- "${s.title}" \xB7 ${(s.start || "").slice(0, 10)} ---
|
|
17351
17744
|
${m.text.slice(0, 3e3)}` : "";
|
|
17352
17745
|
}))).filter(Boolean);
|
|
17353
|
-
const digestDays = (await
|
|
17746
|
+
const digestDays = (await fs13.readFile(path14.join(CODING, "day-digest.json"), "utf-8").then(JSON.parse).catch(() => ({ days: [] }))).days ?? [];
|
|
17354
17747
|
const digestLines = digestDays.slice().sort((a, b) => a.date < b.date ? -1 : 1).slice(-21).map((d) => `${d.date}: ${d.overall ?? ""}
|
|
17355
17748
|
${(d.conversations ?? []).slice(0, 4).map((c) => ` - ${c.title ?? ""}: ${c.summary ?? ""}`).join("\n")}`).join("\n").slice(0, 12e3);
|
|
17356
17749
|
const SYS = "You are a Claude Code power-user coach. You judge ONE person against the COMPLETE catalog of best ways to use Claude Code (the rubric below, sourced from Boris Cherny + first-party Claude Code features) and write a comprehensive, honest gap analysis, ORDERED most-difference-making \u2192 least. Rules: (1) Go through the whole catalog and surface the techniques they are NOT doing (or under-using) that would genuinely help \u2014 respecting each tip's [EMPHASIZE]/[DE-EMPHASIZE]/[GATE] curation. (2) ORDER by differenceRank (1 = biggest unlock for THIS person). Follow the rubric's PRIME DIRECTIVE: if usage.parallelism.alreadyParallel is FALSE \u2192 'Do more in parallel' is rank 1; else \u2192 'Invest in your CLAUDE.md / tune your context' is rank 1. Then Plan mode, then 'Give Claude test cases so it can auto-verify and run longer' (Boris's 'most important thing' \u2014 rank it high, right after plan mode), then subagents, and the rest per the rubric order, skipping any that don't apply. (3) GATE the conditional tips on the STRUCTURAL usage facts, NOT on keywords \u2014 and a tip whose gate FAILS is OMITTED from recommendations entirely, never included as a softened/conditional card (recommending something their data says doesn't apply, or that they already do, reads as not having looked): loops require real PR/branch volume in usage.collaboration, else OMIT; the Chrome tip requires ~zero browser-driving in usage.chrome, else OMIT and credit in alreadyStrong; forking uses the RECENT count in usage.forking \u2014 if they fork in the recent window they already do it, OMIT and credit; remote/mobile/EC2 fires only when usage.surface.workstationBound is TRUE; plan mode by usage.planMode; subagents by usage.subagents. If they already do a thing, it goes in alreadyStrong, NOT in recommendations. (4) \u26D4 CRITICAL \u2014 this person BUILDS Claude Code tooling, so their transcripts are full of the words 'worktree', 'pull request', 'fork', 'plan mode', 'by the way', 'teleport'. A keyword in the transcript is NOT evidence they use the feature. Rely on the STRUCTURAL facts only. (5) Ground every recommendation in a RECEIPT \u2014 a structural fact from their usage or a concrete session pain point \u2014 and CONVINCE with a specific case for how it helps THIS person, not a generic benefit. (6) Tailor every action to the Claude Desktop Mac app; NEVER give terminal-only `claude -p` advice. (7) Honor config.deliberateChoices (they stay on `main` on purpose \u2014 do NOT tell them to hand-juggle worktrees; parallel SESSIONS instead) and config.claudeAutoTools (never tell them to 'use' a tool Claude drives itself; for 'explain with visuals' the user just ASKS for a visual \u2014 do not name the tool). (8) Also name what they ALREADY do well. (9) SELF-CONTAINED but not verbose \u2014 lead with the PROBLEM, then the SOLUTION, then HOW to use it in their context. Plain language, no jargon, no enumerating multiple dates. An essay-like rec is a failed rec; so is a cryptic one. Follow this writing rubric strictly:\n\n" + writing + sourceLookupNote();
|
|
@@ -17380,7 +17773,7 @@ Produce the gap analysis. Be thorough: cover every relevant catalog item they're
|
|
|
17380
17773
|
\`applyItHere\` HARD RULES: 3 entries per recommendation when the material supports 3, minimum 2 \u2014 and every moment must be VISIBLY present in THEIR RECENT DAYS or the excerpts (a real dated task, named the way they name it). NEVER invent, generalize, or reuse the same moment across recommendations. If the material truly supports only one real moment, give that one \u2014 a fabricated example is worse than a short list.`;
|
|
17381
17774
|
const sha = promptSha([SYS, prompt, "sonnet"]);
|
|
17382
17775
|
if (!process.argv.includes("--refresh")) {
|
|
17383
|
-
const prev = await reusableOutput(
|
|
17776
|
+
const prev = await reusableOutput(path14.join(CODING, "gap.json"), sha, (o) => Array.isArray(o.recommendations) && o.recommendations.length > 0);
|
|
17384
17777
|
if (prev) {
|
|
17385
17778
|
console.log(`[gap] inputs unchanged \u2014 reusing output from ${prev.generatedAt} (--refresh to regenerate)`);
|
|
17386
17779
|
return;
|
|
@@ -17403,13 +17796,12 @@ Produce the gap analysis. Be thorough: cover every relevant catalog item they're
|
|
|
17403
17796
|
throw new Error("gap run produced 0 recommendations \u2014 refusing to overwrite the existing gap.json. Re-run the builder.");
|
|
17404
17797
|
}
|
|
17405
17798
|
const result = { generatedAt: (/* @__PURE__ */ new Date()).toISOString(), promptSha: sha, ...out };
|
|
17406
|
-
await
|
|
17799
|
+
await fs13.writeFile(path14.join(CODING, "gap.json"), JSON.stringify(result, null, 2));
|
|
17407
17800
|
console.log(`WROTE ${CODING}/gap.json \u2014 recommendations:${(out.recommendations || []).length} \xB7 alreadyStrong:${(out.alreadyStrong || []).length}`);
|
|
17408
17801
|
}
|
|
17802
|
+
var releaseLock = null;
|
|
17409
17803
|
main().catch((e) => {
|
|
17410
17804
|
console.error(e);
|
|
17411
17805
|
process.exitCode = 1;
|
|
17412
|
-
}).finally(() => {
|
|
17413
|
-
|
|
17414
|
-
});
|
|
17415
|
-
});
|
|
17806
|
+
}).finally(() => releaseLock?.().catch(() => {
|
|
17807
|
+
}));
|