toldya 0.1.0 โ 0.3.0
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/README.md +11 -1
- package/assets/mark.webp +0 -0
- package/bin/toldya.mjs +17 -2
- package/lib/card.mjs +53 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
<p align="center"><b>Stop repeating yourself to your AI.</b></p>
|
|
6
6
|
|
|
7
|
+
<p align="center">Part of <a href="https://singhlabs.dev/toldya/">Singh Labs</a>, small tools for people who code with AI.</p>
|
|
8
|
+
|
|
7
9
|
<p align="center">
|
|
8
10
|
<a href="https://www.npmjs.com/package/toldya"><img src="https://img.shields.io/npm/v/toldya?color=ffd23f&label=npm" alt="npm version"></a>
|
|
9
11
|
<img src="https://img.shields.io/badge/dependencies-0-98a179" alt="zero dependencies">
|
|
@@ -41,6 +43,7 @@ npx toldya --to AGENTS.md # write rules somewhere else
|
|
|
41
43
|
npx toldya --add 1,3 # take repeats 1 and 3 without the prompts
|
|
42
44
|
npx toldya --min 5 # only things you said 5+ times
|
|
43
45
|
npx toldya --json # machine-readable report
|
|
46
|
+
npx toldya --card # an image of your top repeats, to share
|
|
44
47
|
```
|
|
45
48
|
|
|
46
49
|
Without `--dry` or `--add`, it asks about each repeat: **y** adds it, **n** skips it,
|
|
@@ -50,6 +53,14 @@ Nothing is written without a yes.
|
|
|
50
53
|
Run it again a week later and every rule it added shows how often you said it before,
|
|
51
54
|
and how often since.
|
|
52
55
|
|
|
56
|
+
## Share it
|
|
57
|
+
|
|
58
|
+
`npx toldya --all --card` opens your card in the browser. Save it as a PNG, then use the
|
|
59
|
+
**Post on X** or **Share on LinkedIn** button: the post text is written for you. The card is
|
|
60
|
+
drawn on your machine; nothing leaves it unless you click share.
|
|
61
|
+
|
|
62
|
+
<p align="center"><img src="assets/card.png" width="100%" alt="toldya card: Things I keep telling my AI. keep it simple 41 times, dont complex this 29 times, dont assume 15 times"></p>
|
|
63
|
+
|
|
53
64
|
## What it reads, and what it doesn't
|
|
54
65
|
|
|
55
66
|
- Only **your own messages** in Claude Code's history on this machine (`~/.claude/projects`).
|
|
@@ -68,7 +79,6 @@ roughly a month.
|
|
|
68
79
|
|
|
69
80
|
- **Team mode:** `npx toldya owner/repo` reads a repo's pull-request review comments (from
|
|
70
81
|
people or any review bot), finds what reviewers keep writing, and opens one PR into `AGENTS.md`.
|
|
71
|
-
- **A share card:** one image of your top repeats, for when you want to show someone.
|
|
72
82
|
- Codex history (not tested on real files yet, so not claimed).
|
|
73
83
|
|
|
74
84
|
## Requirements
|
package/assets/mark.webp
ADDED
|
Binary file
|
package/bin/toldya.mjs
CHANGED
|
@@ -5,15 +5,17 @@
|
|
|
5
5
|
// finds the corrections you keep repeating, offers each one as a line for the
|
|
6
6
|
// rule file your agent reads, and next time counts whether you still say it.
|
|
7
7
|
import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync } from 'node:fs';
|
|
8
|
+
import { spawn } from 'node:child_process';
|
|
8
9
|
import { join, resolve } from 'node:path';
|
|
9
|
-
import { homedir } from 'node:os';
|
|
10
|
+
import { homedir, tmpdir } from 'node:os';
|
|
10
11
|
import { createInterface } from 'node:readline/promises';
|
|
11
12
|
import {
|
|
12
13
|
CLAUDE_ROOT, claudeProjects, projectFor, readClaudeSession,
|
|
13
14
|
corrections, group, repeats, toRule, alreadyWritten, beforeAfter, isRetry,
|
|
14
15
|
} from '../lib/core.mjs';
|
|
16
|
+
import { cardHtml } from '../lib/card.mjs';
|
|
15
17
|
|
|
16
|
-
const VERSION = '0.
|
|
18
|
+
const VERSION = '0.3.0';
|
|
17
19
|
const argv = process.argv.slice(2);
|
|
18
20
|
const has = (f) => argv.includes(f);
|
|
19
21
|
const opt = (f, d) => { const i = argv.indexOf(f); return i >= 0 && argv[i + 1] ? argv[i + 1] : d; };
|
|
@@ -27,6 +29,7 @@ if (has('--help') || has('-h')) {
|
|
|
27
29
|
--to FILE write rules to FILE instead (e.g. AGENTS.md)
|
|
28
30
|
--add 1,3 add repeats by their number, without asking
|
|
29
31
|
--dry show the report, change nothing
|
|
32
|
+
--card make an image of your top repeats, to share
|
|
30
33
|
--json machine-readable report, change nothing
|
|
31
34
|
|
|
32
35
|
Reads Claude Code's own history on this machine. Sends nothing anywhere.`);
|
|
@@ -112,6 +115,18 @@ if (!fresh.length) {
|
|
|
112
115
|
process.exit(0);
|
|
113
116
|
}
|
|
114
117
|
|
|
118
|
+
if (has('--card')) {
|
|
119
|
+
if (!found.length) { console.log(`No correction said ${min}+ times yet, so no card.`); process.exit(0); }
|
|
120
|
+
const file = join(tmpdir(), 'toldya-card.html');
|
|
121
|
+
writeFileSync(file, cardHtml({ repeats: found, sessions, from: day(dates[0]), to: day(dates.at(-1)) }));
|
|
122
|
+
const open = process.platform === 'win32' ? ['cmd', ['/c', 'start', '', file]]
|
|
123
|
+
: [process.platform === 'darwin' ? 'open' : 'xdg-open', [file]];
|
|
124
|
+
try { spawn(open[0], open[1], { detached: true, stdio: 'ignore' }).on('error', () => {}).unref(); } catch {}
|
|
125
|
+
console.log(`Your card: ${file}
|
|
126
|
+
It opens in your browser: save it as a PNG, then post it. Nothing leaves your machine unless you click share.`);
|
|
127
|
+
process.exit(0);
|
|
128
|
+
}
|
|
129
|
+
|
|
115
130
|
console.log('You keep telling your AI:');
|
|
116
131
|
const shown = fresh.slice(0, 10);
|
|
117
132
|
shown.forEach((r, n) => {
|
package/lib/card.mjs
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// toldya --card: one image of your top repeats, for when you want to show someone.
|
|
2
|
+
// Writes a local HTML page that draws the card and saves it as a PNG. No network,
|
|
3
|
+
// unless you click a share button: that opens X or LinkedIn with a pre-filled post.
|
|
4
|
+
import { readFileSync } from 'node:fs';
|
|
5
|
+
|
|
6
|
+
const MARK = new URL('../assets/mark.webp', import.meta.url);
|
|
7
|
+
|
|
8
|
+
export function cardHtml({ repeats, sessions, from, to }) {
|
|
9
|
+
let mark = '';
|
|
10
|
+
try { mark = 'data:image/webp;base64,' + readFileSync(MARK).toString('base64'); } catch {}
|
|
11
|
+
const data = { rows: repeats.slice(0, 5).map((r) => [r.count, r.phrase]), sessions, from, to, mark };
|
|
12
|
+
// JSON inside <script>: escape "<" so a phrase like "</script>" can't end the block.
|
|
13
|
+
const json = JSON.stringify(data).replace(/</g, '\\u003c');
|
|
14
|
+
return `<!doctype html><meta charset="utf-8"><title>toldya card</title>
|
|
15
|
+
<style>body{margin:0;background:#eee;font:16px system-ui;display:grid;place-items:center;min-height:100vh;gap:16px}
|
|
16
|
+
canvas{max-width:95vw;height:auto;box-shadow:0 2px 12px #0002}.row{display:flex;gap:14px;flex-wrap:wrap;justify-content:center}p{margin:0;color:#555;max-width:60ch;text-align:center}a{font-weight:700;color:#0d0d0d;background:#ffd23f;border:3px solid #0d0d0d;padding:10px 18px;border-radius:30px;text-decoration:none;box-shadow:4px 4px 0 #0d0d0d}</style>
|
|
17
|
+
<canvas id="c" width="1200" height="675"></canvas>
|
|
18
|
+
<div class="row"><a id="save" download="toldya.png" href="#">1. Save as PNG</a><a id="x" target="_blank" rel="noopener" href="#">2. Post on X</a><a id="li" target="_blank" rel="noopener" href="#">2. Share on LinkedIn</a></div>
|
|
19
|
+
<p>Save the picture first, then attach it to your post. The card is drawn on your machine; nothing leaves it unless you click a share button.</p>
|
|
20
|
+
<script>
|
|
21
|
+
const D = ${json}, c = document.getElementById('c'), x = c.getContext('2d'), INK = '#0d0d0d';
|
|
22
|
+
const REPO = 'github.com/singhlabsdev/toldya';
|
|
23
|
+
const first = D.rows[0] || [0, ''];
|
|
24
|
+
const post = 'My AI has heard "' + first[1] + '" ' + first[0] + ' times ๐
Counted from my own Claude Code history with npx toldya';
|
|
25
|
+
document.getElementById('x').href = 'https://x.com/intent/post?text=' + encodeURIComponent(post) + '&url=' + encodeURIComponent('https://' + REPO);
|
|
26
|
+
document.getElementById('li').href = 'https://www.linkedin.com/feed/?shareActive=true&text=' + encodeURIComponent(post + ' https://' + REPO);
|
|
27
|
+
const font = (w, s) => (x.font = w + ' ' + s + 'px system-ui, "Segoe UI", sans-serif');
|
|
28
|
+
const pill = (px, py, w, h, fill) => {
|
|
29
|
+
x.fillStyle = INK; x.beginPath(); x.roundRect(px + 5, py + 5, w, h, h / 2); x.fill();
|
|
30
|
+
x.fillStyle = fill; x.beginPath(); x.roundRect(px, py, w, h, h / 2); x.fill();
|
|
31
|
+
x.lineWidth = 3; x.strokeStyle = INK; x.stroke();
|
|
32
|
+
};
|
|
33
|
+
const fit = (s, max) => { if (x.measureText(s).width <= max) return s;
|
|
34
|
+
while (s.length > 1 && x.measureText(s + 'โฆ').width > max) s = s.slice(0, -1); return s + 'โฆ'; };
|
|
35
|
+
function draw(img) {
|
|
36
|
+
x.fillStyle = '#fff'; x.fillRect(0, 0, 1200, 675);
|
|
37
|
+
if (img) x.drawImage(img, 30, 150, 330, 330);
|
|
38
|
+
x.fillStyle = INK; font(800, 46); x.fillText('Things I keep telling my AI', 390, 100);
|
|
39
|
+
D.rows.forEach(([n, p], i) => {
|
|
40
|
+
const y = 150 + i * 88;
|
|
41
|
+
pill(390, y, 118, 58, '#ffd23f');
|
|
42
|
+
x.fillStyle = INK; font(800, 30); x.textAlign = 'center'; x.fillText(n + 'ร', 449, y + 40);
|
|
43
|
+
x.textAlign = 'left'; font(600, 32); x.fillText(fit('โ' + p + 'โ', 640), 532, y + 41);
|
|
44
|
+
});
|
|
45
|
+
font(500, 22); x.fillStyle = '#6b6b6b';
|
|
46
|
+
x.fillText(D.sessions + ' Claude Code sessions ยท ' + D.from + ' โ ' + D.to, 390, 628);
|
|
47
|
+
pill(990, 596, 180, 50, INK); x.fillStyle = '#fff'; font(700, 24); x.fillText('npx toldya', 1017, 629);
|
|
48
|
+
x.fillStyle = '#6b6b6b'; font(500, 18); x.textAlign = 'right'; x.fillText(REPO, 1170, 580); x.textAlign = 'left';
|
|
49
|
+
document.getElementById('save').href = c.toDataURL('image/png');
|
|
50
|
+
}
|
|
51
|
+
if (D.mark) { const i = new Image(); i.onload = () => draw(i); i.onerror = () => draw(); i.src = D.mark; } else draw();
|
|
52
|
+
</script>`;
|
|
53
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toldya",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Stop repeating yourself to your AI. Finds what you keep telling your coding agent, writes it into CLAUDE.md / AGENTS.md, and counts whether it stopped.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"toldya": "bin/toldya.mjs"
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"files": [
|
|
9
9
|
"bin",
|
|
10
10
|
"lib",
|
|
11
|
+
"assets/mark.webp",
|
|
11
12
|
"README.md",
|
|
12
13
|
"LICENSE"
|
|
13
14
|
],
|