claude-dependency-test 1.0.1 → 1.0.2

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "claude-dependency-test",
3
3
  "displayName": "Claude Dependency Test",
4
- "version": "1.0.1",
4
+ "version": "1.0.2",
5
5
  "description": "How addicted to Claude are you? Computes a 0-100 dependency score from your local Claude Code transcripts and generates a shareable card. Offline, aggregates only.",
6
6
  "author": {
7
7
  "name": "Camille Roux",
package/assets/card.js CHANGED
@@ -115,15 +115,40 @@ export function shareUrl(baseUrl, card) {
115
115
  return `${String(baseUrl).replace(/\/+$/, '')}/r?${encodeCard(card)}`;
116
116
  }
117
117
 
118
+ /** Rankings need a crowd: below this many published reports, no "more addicted than" line. */
119
+ export const MIN_PATIENTS_FOR_RANK = 10;
120
+
121
+ /**
122
+ * { dir: 'more' | 'less', pct, total } from how many published scores are below and above this
123
+ * one. 'more' = more addicted than pct% of patients, 'less' = more reasonable than pct%.
124
+ */
125
+ export function rankFrom(below, above, total) {
126
+ if (!(total >= MIN_PATIENTS_FOR_RANK)) return null;
127
+ const more = Math.floor((below / total) * 100);
128
+ const less = Math.floor((above / total) * 100);
129
+ if (more >= less && more > 0) return { dir: 'more', pct: more, total };
130
+ if (less > 0) return { dir: 'less', pct: less, total };
131
+ return null;
132
+ }
133
+
134
+ /** "More addicted than 72% of patients" in the page language. */
135
+ export function rankText(rank, lang = 'en') {
136
+ if (!rank) return '';
137
+ if (lang === 'fr') return `${rank.dir === 'more' ? 'Plus accro' : 'Plus raisonnable'} que ${rank.pct} % des patients`;
138
+ return `${rank.dir === 'more' ? 'More addicted' : 'More reasonable'} than ${rank.pct}% of patients`;
139
+ }
140
+
118
141
  export function shareText(card, lang = 'en') {
119
142
  if (lang === 'fr') {
120
143
  const st = STAGES_FR[card.stage];
121
144
  const ar = ARCHETYPES_FR[card.archetype];
122
- return `Je viens de passer le Claude Dependency Test : ${card.score}/100, stade ${card.stage} (${st.name.toLowerCase()}).\nDiagnostic : ${ar.name} ${ARCHETYPES[card.archetype].emoji}\nEt toi, à quel point es-tu accro à Claude ?`;
145
+ const rk = card.rank ? `\n${rankText(card.rank, 'fr')}.` : '';
146
+ return `Je viens de passer le Claude Dependency Test : ${card.score}/100, stade ${card.stage} (${st.name.toLowerCase()}).${rk}\nDiagnostic : ${ar.name} ${ARCHETYPES[card.archetype].emoji}\nEt toi, à quel point es-tu accro à Claude ?`;
123
147
  }
124
148
  const st = STAGES[card.stage];
125
149
  const ar = ARCHETYPES[card.archetype];
126
- return `Just got my Claude Dependency Test results: ${card.score}/100, Stage ${card.stage} (${st.name}).\nDiagnosis: ${ar.name} ${ar.emoji}\nHow addicted to Claude are you?`;
150
+ const rk = card.rank ? `\n${rankText(card.rank)}.` : '';
151
+ return `Just got my Claude Dependency Test results: ${card.score}/100, Stage ${card.stage} (${st.name}).${rk}\nDiagnosis: ${ar.name} ${ar.emoji}\nHow addicted to Claude are you?`;
127
152
  }
128
153
 
129
154
  /** One-click share links. `via` credits the author: X shows "via @…" and suggests following. */
@@ -551,6 +576,11 @@ function glowText(ctx, text, x, y, color, blur = 14) {
551
576
  ctx.restore();
552
577
  }
553
578
 
579
+ /** The two card lines for a rank: "▲ MORE ADDICTED THAN 72%" / "OF 21 PATIENTS". English only. */
580
+ export function rankLines(rank) {
581
+ return [`${rank.dir === 'more' ? '▲ MORE ADDICTED' : '▼ MORE REASONABLE'} THAN ${rank.pct}%`, `OF ${rank.total} PATIENTS`];
582
+ }
583
+
554
584
  export function drawCard(ctx, card, { siteLabel = '', credit = '' } = {}) {
555
585
  const c = MONITOR;
556
586
  const W = CARD_WIDTH;
@@ -644,6 +674,13 @@ export function drawCard(ctx, card, { siteLabel = '', credit = '' } = {}) {
644
674
  glowText(ctx, String(card.score), W - 48, 380, '#EFFFF5', 26);
645
675
  ctx.font = `400 34px ${DISPLAY}`;
646
676
  glowText(ctx, `STAGE ${card.stage} · ${stage.name.toUpperCase()}`, W - 48, 428, c.stages[card.stage], 10);
677
+ if (card.rank) {
678
+ const [l1, l2] = rankLines(card.rank);
679
+ ctx.font = `400 24px ${DISPLAY}`;
680
+ glowText(ctx, l1, W - 48, 464, card.rank.dir === 'more' ? c.amber : c.ph, 6);
681
+ ctx.fillStyle = c.dim;
682
+ ctx.fillText(l2, W - 48, 490);
683
+ }
647
684
  ctx.textAlign = 'left';
648
685
 
649
686
  // Readouts row
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-dependency-test",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "How addicted to Claude are you? Scores your Claude Code dependency out of 100 from local usage stats and publishes a shareable patient chart. Your prompts never leave your machine.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,7 +16,7 @@ import { computeMetrics } from './lib/metrics.mjs';
16
16
  import { archetypeFor, scoreMetrics, stageFor } from './lib/score.mjs';
17
17
  import { publish, unpublish } from './lib/publish.mjs';
18
18
  import { buildResult, finalizeShare, renderHtml, renderShareFooter, toPublicReport } from './lib/report.mjs';
19
- import { badgeUrl } from '../assets/card.js';
19
+ import { badgeUrl, rankText, shareText } from '../assets/card.js';
20
20
 
21
21
  const ROOT = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
22
22
  const VERSION = JSON.parse(fs.readFileSync(path.join(ROOT, '.claude-plugin', 'plugin.json'), 'utf8')).version;
@@ -128,6 +128,11 @@ export async function run(argv, env = process.env, { fetchImpl = globalThis.fetc
128
128
  result.published = p;
129
129
  result.share.url = p.url;
130
130
  result.share.badge = badgeUrl(baseUrl, result.card, p.slug);
131
+ if (p.rank) {
132
+ // "More addicted than 72% of patients": computed by the share site from published scores.
133
+ result.rank = { ...p.rank, text: rankText(p.rank) };
134
+ result.share.text = shareText({ ...result.card, rank: p.rank });
135
+ }
131
136
  finalizeShare(result);
132
137
  } catch (err) {
133
138
  result.publishError = `${err.message}. Falling back to a link that carries the card in its URL.`;
@@ -146,6 +151,7 @@ export async function run(argv, env = process.env, { fetchImpl = globalThis.fetc
146
151
  }
147
152
  const lines = [result.bulletin, ''];
148
153
  if (result.published) {
154
+ if (result.rank) lines.push(` ${result.rank.text} (${result.rank.total} diagnosed so far).`);
149
155
  lines.push(` Online: ${result.published.url}${result.published.updated ? ' (updated)' : ''}`);
150
156
  lines.push(' Only aggregate numbers were published. Delete it: --unpublish · Stay offline next time: --no-publish');
151
157
  }
@@ -51,7 +51,7 @@ export async function publish({ baseUrl, report, stateFile, forceNew = false, fe
51
51
  headers: { ...headers, authorization: `Bearer ${state.token}` },
52
52
  body: payload,
53
53
  });
54
- if (status === 200 && body && body.url) return { url: body.url, slug: state.slug, updated: true };
54
+ if (status === 200 && body && body.url) return { url: body.url, slug: state.slug, updated: true, rank: body.rank || null };
55
55
  if (status !== 404 && status !== 403) throw new Error(body?.error || `share site answered ${status}`);
56
56
  // The page expired or was deleted: fall through and create a new one.
57
57
  }
@@ -61,7 +61,7 @@ export async function publish({ baseUrl, report, stateFile, forceNew = false, fe
61
61
  throw new Error(body?.error || `share site answered ${status}`);
62
62
  }
63
63
  writeState(stateFile, { baseUrl, slug: body.slug, token: body.token, url: body.url, publishedAt: new Date().toISOString() });
64
- return { url: body.url, slug: body.slug, updated: false };
64
+ return { url: body.url, slug: body.slug, updated: false, rank: body.rank || null };
65
65
  }
66
66
 
67
67
  export async function unpublish({ stateFile, fetchImpl = fetch }) {