polymath-society 0.2.4

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 (45) hide show
  1. package/LICENSE +52 -0
  2. package/README.md +311 -0
  3. package/dist/DATA-MAP.md +109 -0
  4. package/dist/cli.js +24136 -0
  5. package/dist/engine/closing-rubric.md +50 -0
  6. package/dist/engine/exp-allfacets.js +16832 -0
  7. package/dist/engine/exp-person.js +16922 -0
  8. package/dist/engine/exp-pipeline.js +16700 -0
  9. package/dist/engine/feel-seen-rubric.md +192 -0
  10. package/dist/engine/ingest-export.js +1423 -0
  11. package/dist/engine/peak-demos.js +16752 -0
  12. package/dist/engine/person-dimension-summary.js +16744 -0
  13. package/dist/engine/person-facet-lines.js +16784 -0
  14. package/dist/engine/person-headline.js +16733 -0
  15. package/dist/engine/person-report.js +16845 -0
  16. package/dist/engine/person-self-image.js +16689 -0
  17. package/dist/engine/public-report-guidelines.md +80 -0
  18. package/dist/engine/public-report.js +17284 -0
  19. package/dist/engine/run-analysis.js +16035 -0
  20. package/dist/engine/run-tagger.js +16092 -0
  21. package/dist/engine/top-companies.md +41 -0
  22. package/dist/engine/writing-well.md +56 -0
  23. package/dist/index.js +22021 -0
  24. package/dist/pipeline/TECHNIQUES.md +406 -0
  25. package/dist/pipeline/WRITING.md +48 -0
  26. package/dist/pipeline/coding-agglomerate.js +15876 -0
  27. package/dist/pipeline/coding-aggregate.js +440 -0
  28. package/dist/pipeline/coding-build.js +1168 -0
  29. package/dist/pipeline/coding-coaching.js +16893 -0
  30. package/dist/pipeline/coding-day-digest.js +15869 -0
  31. package/dist/pipeline/coding-delegation.js +16292 -0
  32. package/dist/pipeline/coding-expertise.js +15925 -0
  33. package/dist/pipeline/coding-flow.js +313 -0
  34. package/dist/pipeline/coding-frontier-detail.js +15878 -0
  35. package/dist/pipeline/coding-frontier.js +51 -0
  36. package/dist/pipeline/coding-gap-dist.js +293 -0
  37. package/dist/pipeline/coding-gap.js +17108 -0
  38. package/dist/pipeline/coding-grade.js +16195 -0
  39. package/dist/pipeline/coding-nutshell.js +15725 -0
  40. package/dist/pipeline/coding-projects.js +104 -0
  41. package/dist/pipeline/coding-walkthrough.js +15947 -0
  42. package/dist/web/app.js +12024 -0
  43. package/dist/web/index.html +1 -0
  44. package/dist/web/styles.css +1 -0
  45. package/package.json +61 -0
@@ -0,0 +1,313 @@
1
+ import{createRequire as __cr}from'module';const require=__cr(import.meta.url);
2
+
3
+ // ../../scripts/coding-flow.mts
4
+ import { promises as fs2 } from "fs";
5
+ import path from "path";
6
+
7
+ // ../../lib/agents/shared/cliAdapter.ts
8
+ var CLAUDE_BIN = process.env.CLAUDE_BIN || "claude";
9
+
10
+ // ../../lib/agents/shared/backends.ts
11
+ import os from "os";
12
+ var HOME = os.homedir();
13
+
14
+ // ../../lib/agents/shared/tools.ts
15
+ import { execFile } from "child_process";
16
+ import { promisify } from "util";
17
+ var exec = promisify(execFile);
18
+
19
+ // ../../lib/agents/shared/limitGate.ts
20
+ import { AsyncLocalStorage } from "async_hooks";
21
+ var MIN = 6e4;
22
+ var HOUR = 60 * MIN;
23
+ var STALL_BACKOFFS_MS = [6e4, 3 * MIN, 10 * MIN, 20 * MIN];
24
+ var SLEEP_CHUNK_MS = 5 * MIN;
25
+ var CANONICAL = [
26
+ /claude (ai )?usage limit reached/i,
27
+ /\busage limit reached\b/i,
28
+ // "session" variant seen live 2026-07-06: "You've hit your session limit ·
29
+ // resets 4:10am (America/Los_Angeles)" — unrecognized, it failed EVERY
30
+ // post-wall stage of the overnight rehearsal instead of pausing. Keep the
31
+ // subject alternatives in sync with what the CLI actually emits.
32
+ /you'?ve (?:hit|reached) your (?:usage |session |weekly |daily )?limit/i,
33
+ /\bsession limit\b[^.]{0,40}resets?/i,
34
+ /reached your usage limit/i,
35
+ /5[\s-]?hour limit (?:reached|hit)/i,
36
+ /limit will reset/i
37
+ ];
38
+ var LIBERAL = [
39
+ ...CANONICAL,
40
+ /usage limit/i,
41
+ /\bsession limit\b/i,
42
+ /\brate[\s-]?limit(?:ed|s|\b)/i,
43
+ /\btoo many requests\b/i,
44
+ /\b429\b/,
45
+ /quota (?:exceeded|reached|exhausted)/i,
46
+ /resets? (?:at|in)\b/i,
47
+ /resets? \d{1,2}(?::\d{2})?\s*(?:am|pm)/i
48
+ // "resets 4:10am" — no "at" (live form)
49
+ ];
50
+ var ALS = new AsyncLocalStorage();
51
+
52
+ // ../coding-core/dist/messages.js
53
+ import { promises as fs } from "fs";
54
+
55
+ // ../coding-core/dist/injected.js
56
+ var SYSTEM_REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/g;
57
+ var INJECTED_RES = [
58
+ /<task-notification>[\s\S]*?<\/task-notification>/g,
59
+ /<local-command-stdout>[\s\S]*?<\/local-command-stdout>/g,
60
+ /<local-command-caveat>[\s\S]*?<\/local-command-caveat>/g,
61
+ /<ide_opened_file>[\s\S]*?<\/ide_opened_file>/g
62
+ ];
63
+ var HARNESS_TURN_RES = [
64
+ /^Non user activity$/i,
65
+ /^<<autonomous-loop(-dynamic)?>>$/,
66
+ /^This session is being continued from a previous conversation/,
67
+ // the loop skill's expanded wake-up prompt — older CLI versions wrote it as a
68
+ // plain user turn with no isMeta flag (found counting 601 words, 2026-07-07)
69
+ /^(-{3,}\s*)?#\s*Autonomous loop (check|tick)/
70
+ ];
71
+ function stripInjected(t) {
72
+ for (const re of INJECTED_RES)
73
+ t = t.replace(re, "");
74
+ return t.replace(SYSTEM_REMINDER_RE, "");
75
+ }
76
+ function isHarnessTurn(t) {
77
+ const s = t.trim();
78
+ return HARNESS_TURN_RES.some((re) => re.test(s));
79
+ }
80
+ function humanTypedText(t) {
81
+ const s = stripInjected(t).trim();
82
+ return s && !isHarnessTurn(s) ? s : "";
83
+ }
84
+ function isHarnessEntry(e) {
85
+ return e.isMeta === true || e.isCompactSummary === true;
86
+ }
87
+
88
+ // ../coding-core/dist/messages.js
89
+ function extractText(content) {
90
+ if (typeof content === "string")
91
+ return content;
92
+ if (Array.isArray(content))
93
+ return content.filter((c) => c && typeof c === "object" && c.type === "text").map((c) => c.text || "").join("\n");
94
+ return "";
95
+ }
96
+ function isToolResultOnly(content) {
97
+ return Array.isArray(content) && content.length > 0 && content.every((c) => c && typeof c === "object" && c.type === "tool_result");
98
+ }
99
+ async function extractMessages(file) {
100
+ let raw;
101
+ try {
102
+ raw = await fs.readFile(file, "utf-8");
103
+ } catch {
104
+ return [];
105
+ }
106
+ const out = [];
107
+ const userTexts = /* @__PURE__ */ new Set();
108
+ const seenUuids = /* @__PURE__ */ new Set();
109
+ let aiProse = [];
110
+ let aiTools = {};
111
+ let aiStart = 0;
112
+ const flushAI = () => {
113
+ if (!aiProse.length && Object.keys(aiTools).length === 0)
114
+ return;
115
+ const toolStr = Object.entries(aiTools).map(([n, c]) => c > 1 ? `${n}\xD7${c}` : n).join(", ");
116
+ let prose = aiProse.join(" ").replace(/\s+/g, " ").trim();
117
+ if (prose.length > 2200)
118
+ prose = prose.slice(0, 2200) + "\u2026";
119
+ let text = prose;
120
+ if (toolStr)
121
+ text = (text ? text + " " : "") + `[ran ${toolStr}]`;
122
+ if (text)
123
+ out.push({ t: aiStart, role: "ai", text });
124
+ aiProse = [];
125
+ aiTools = {};
126
+ };
127
+ for (const line of raw.split("\n")) {
128
+ const s = line.trim();
129
+ if (!s)
130
+ continue;
131
+ let e;
132
+ try {
133
+ e = JSON.parse(s);
134
+ } catch {
135
+ continue;
136
+ }
137
+ const t = typeof e.timestamp === "string" ? Date.parse(e.timestamp) : NaN;
138
+ if (!Number.isFinite(t))
139
+ continue;
140
+ if (e.type === "queue-operation" && e.operation === "enqueue" && typeof e.content === "string") {
141
+ const qt = humanTypedText(e.content);
142
+ if (qt) {
143
+ flushAI();
144
+ out.push({ t, role: "user", text: qt, q: true });
145
+ }
146
+ continue;
147
+ }
148
+ if (e.type === "user") {
149
+ if (isHarnessEntry(e))
150
+ continue;
151
+ const uuid = typeof e.uuid === "string" ? e.uuid : "";
152
+ if (uuid && seenUuids.has(uuid))
153
+ continue;
154
+ const content = e.message?.content;
155
+ if (isToolResultOnly(content))
156
+ continue;
157
+ const text = humanTypedText(extractText(content));
158
+ if (text) {
159
+ if (uuid)
160
+ seenUuids.add(uuid);
161
+ userTexts.add(text);
162
+ flushAI();
163
+ out.push({ t, role: "user", text });
164
+ }
165
+ continue;
166
+ }
167
+ if (e.type === "assistant") {
168
+ const msg = e.message ?? {};
169
+ if (!aiProse.length && Object.keys(aiTools).length === 0)
170
+ aiStart = t;
171
+ if (Array.isArray(msg.content)) {
172
+ for (const item of msg.content) {
173
+ const it = item;
174
+ if (it.type === "text" && it.text)
175
+ aiProse.push(it.text);
176
+ else if (it.type === "tool_use" && it.name)
177
+ aiTools[it.name] = (aiTools[it.name] ?? 0) + 1;
178
+ }
179
+ } else {
180
+ const p = extractText(msg.content);
181
+ if (p)
182
+ aiProse.push(p);
183
+ }
184
+ }
185
+ }
186
+ flushAI();
187
+ return out.filter((m) => !(m.q && userTexts.has(m.text))).map(({ q, ...m }) => m).sort((a, b) => a.t - b.t);
188
+ }
189
+
190
+ // ../coding-core/dist/words.js
191
+ var CODE_START = /^\s*(import |export |const |let |var |function\b|class |def |async |await |return |if\s*\(|for\s*\(|while\s*\(|switch\s*\(|#include|<\/?[a-zA-Z][\w-]*[\s>]|[}{)\]]|@[A-Za-z]|\$\s|npm |npx |git |cd |sudo )/;
192
+ var SEAM_RE = /\n\s*\n\s*\n+/;
193
+ var SEGMENT_CEILING = 400;
194
+ var NOTE = "((ran|created|edited|read|wrote|searched) (a|an|\\d+) [a-z]+|updated todos)";
195
+ var TRANSCRIPT_LINE_RE = new RegExp(`^\\s*(${NOTE})((,| and) ${NOTE})*\\s*$|^\\s*thought for .{1,30}$`, "im");
196
+ var EM_DASH_RE = / — /g;
197
+ var MAX_WPM = 1e3;
198
+ var DEFAULT_GAP_MIN = 5;
199
+ function typedWords(text, gapMs) {
200
+ const typed = humanTypedText(text);
201
+ const msgDashes = (typed.match(EM_DASH_RE) || []).length;
202
+ const msgWords = proseWords(typed);
203
+ const draftedMsg = msgDashes >= 6 && msgWords > 0 && msgDashes / msgWords >= 1 / 200;
204
+ let counted = 0;
205
+ for (const seg of typed.split(SEAM_RE)) {
206
+ if (TRANSCRIPT_LINE_RE.test(seg))
207
+ continue;
208
+ const w = proseWords(seg);
209
+ if (!w)
210
+ continue;
211
+ const dashes = (seg.match(EM_DASH_RE) || []).length;
212
+ if (dashes >= 3 && dashes / w >= 1 / 200)
213
+ continue;
214
+ if (draftedMsg && dashes >= 1)
215
+ continue;
216
+ counted += Math.min(w, SEGMENT_CEILING);
217
+ }
218
+ const mins = gapMs / 6e4;
219
+ const window = Number.isFinite(mins) && mins > 0 ? mins : DEFAULT_GAP_MIN;
220
+ return Math.min(counted, Math.round(MAX_WPM * window));
221
+ }
222
+ function proseWords(text) {
223
+ let t = text;
224
+ const skillAt = t.indexOf("Base directory for this skill:");
225
+ if (skillAt >= 0)
226
+ t = t.slice(0, skillAt);
227
+ const contAt = t.indexOf("This session is being continued from a previous conversation");
228
+ if (contAt >= 0)
229
+ t = t.slice(0, contAt);
230
+ t = t.replace(/<command-[a-z-]+>[\s\S]*?<\/command-[a-z-]+>/gi, " ");
231
+ t = t.replace(/```[\s\S]*?```/g, " ");
232
+ t = t.replace(/`[^`\n]{2,}`/g, " ");
233
+ const kept = t.split("\n").filter((ln) => {
234
+ const s = ln.trim();
235
+ if (s.length < 8)
236
+ return true;
237
+ const letters = (s.match(/[A-Za-z]/g) || []).length;
238
+ const symbols = (s.match(/[{}()[\];=<>+\-*/%&|^~$@\\]/g) || []).length;
239
+ const codey = CODE_START.test(s) || symbols > 3 && symbols / s.length > 0.25 || // symbol-dense → code
240
+ letters / s.length < 0.45;
241
+ return !codey;
242
+ });
243
+ return (kept.join(" ").trim().match(/\S+/g) || []).length;
244
+ }
245
+
246
+ // ../../scripts/coding-flow.mts
247
+ var WPM = 130;
248
+ var FLOW_GAP = 5;
249
+ var BREAK = 15;
250
+ var WIN = 10;
251
+ var WINMS = WIN * 6e4;
252
+ var TZ = "America/Los_Angeles";
253
+ var ld = (t) => new Date(t).toLocaleDateString("en-CA", { timeZone: TZ });
254
+ var slotOfDay = (t) => {
255
+ const [h, m] = new Date(t).toLocaleTimeString("en-GB", { timeZone: TZ, hour12: false }).split(":").map(Number);
256
+ return h * 6 + Math.floor(m / 10);
257
+ };
258
+ async function main() {
259
+ const CODING = path.join(process.cwd(), ".data", "coding");
260
+ const sess = JSON.parse(await fs2.readFile(path.join(CODING, "sessions.json"), "utf8")).filter((s) => !s.duplicateOf);
261
+ const ev = [];
262
+ for (const s of sess) {
263
+ let ms = [];
264
+ try {
265
+ ms = await extractMessages(s.file);
266
+ } catch {
267
+ continue;
268
+ }
269
+ for (const m of ms) ev.push({ t: m.t, role: m.role, words: m.role === "user" ? typedWords(m.text || "", NaN) : 0 });
270
+ }
271
+ ev.sort((a, b) => a.t - b.t);
272
+ const cell = {};
273
+ const add = (b, k, v) => {
274
+ (cell[b] = cell[b] || { flow: 0, loss: 0 })[k] += v;
275
+ };
276
+ for (let i = 1; i < ev.length; i++) {
277
+ const t0 = ev[i - 1].t, t1 = ev[i].t, g = (t1 - t0) / 6e4;
278
+ if (g > BREAK || g <= 0) continue;
279
+ const isLoss = g - (ev[i].role === "user" ? ev[i].words / WPM : 0) > FLOW_GAP;
280
+ for (let b = Math.floor(t0 / WINMS); b <= Math.floor((t1 - 1) / WINMS); b++) {
281
+ const lo = Math.max(t0, b * WINMS), hi = Math.min(t1, (b + 1) * WINMS);
282
+ if (hi > lo) add(b, isLoss ? "loss" : "flow", (hi - lo) / 6e4);
283
+ }
284
+ }
285
+ const byDay = {};
286
+ for (const [bk, w] of Object.entries(cell)) {
287
+ if (w.flow + w.loss < 3) continue;
288
+ const t = Number(bk) * WINMS, date = ld(t), green = w.flow > w.loss;
289
+ const d = byDay[date] || (byDay[date] = { date, flowSlots: 0, activeSlots: 0, flowHours: 0, flowFraction: 0, flowMin: 0, pauseMin: 0, slots: {} });
290
+ d.slots[slotOfDay(t)] = green ? "F" : "A";
291
+ d.activeSlots++;
292
+ if (green) d.flowSlots++;
293
+ d.flowMin += w.flow;
294
+ d.pauseMin += w.loss;
295
+ }
296
+ const days = Object.values(byDay).sort((a, b) => a.date.localeCompare(b.date));
297
+ for (const d of days) {
298
+ d.flowHours = Math.round(d.flowSlots / 6 * 10) / 10;
299
+ d.flowFraction = Math.round(d.flowSlots / d.activeSlots * 100) / 100;
300
+ d.flowMin = Math.round(d.flowMin);
301
+ d.pauseMin = Math.round(d.pauseMin);
302
+ }
303
+ const fs22 = days.reduce((a, d) => a + d.flowSlots, 0), as = days.reduce((a, d) => a + d.activeSlots, 0);
304
+ const out = { generatedAt: (/* @__PURE__ */ new Date()).toISOString(), params: { wpm: WPM, flowGapMin: FLOW_GAP, breakMin: BREAK, windowMin: WIN, tz: TZ }, totals: { activeDays: days.length, flowSlots: fs22, activeSlots: as, flowFraction: Math.round(fs22 / as * 100) / 100 }, days };
305
+ await fs2.writeFile(path.join(CODING, "flow.json"), JSON.stringify(out, null, 2));
306
+ console.log(`wrote .data/coding/flow.json \u2014 ${days.length} days \xB7 ${fs22}/${as} slots in flow (${Math.round(100 * fs22 / as)}%)`);
307
+ console.log(`top flow days:`);
308
+ [...days].sort((a, b) => b.flowSlots - a.flowSlots).slice(0, 5).forEach((d) => console.log(` ${d.date} ${d.flowSlots} flow slots (${d.flowHours}h) \xB7 ${Math.round(d.flowFraction * 100)}% of active`));
309
+ }
310
+ main().catch((e) => {
311
+ console.error(e);
312
+ process.exit(1);
313
+ });