promptup-plugin 0.2.0 → 0.2.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.
package/README.md CHANGED
@@ -10,36 +10,86 @@ Zero infrastructure. Just SQLite at `~/.promptup/`.
10
10
  npx promptup-plugin
11
11
  ```
12
12
 
13
- This installs everything: MCP server, skills, hooks, statusline, and default config. Restart Claude Code to activate.
13
+ Installs MCP server, commands, hooks, statusline, and default config. Restart Claude Code to activate.
14
14
 
15
- ## What it does
15
+ ## How it works
16
16
 
17
- **4 MCP Tools:**
17
+ ### Session tracking
18
+ Every Claude Code session is passively tracked via hooks. On session creation, the current git branch is recorded. This links sessions to PRs automatically.
19
+
20
+ ### Evaluation
21
+ `/pup:eval` spawns an independent `claude -p` to analyze your session transcript across 11 dimensions. It extracts developer decisions (steers, rejects, validates, scopes) and generates coaching recommendations with before/after examples from your actual prompts. Falls back to heuristic scoring if Claude is unavailable.
22
+
23
+ ### PR reports
24
+ `/pup:pr-report` matches sessions to the current branch, auto-evaluates unscored sessions, gathers all decisions, and computes a Decision Quality Score (DQS). The session-to-PR link uses `sessions.branch` — set when the session was created. Optionally posts as a GitHub PR comment.
25
+
26
+ ### DQS formula
27
+ ```
28
+ DQS = autonomy * 25% + discipline * 25% + validation * 30% + diversity * 20%
29
+ ```
30
+ - **Autonomy**: How often you steer, reject, or modify AI output vs accepting
31
+ - **Discipline**: Ratio of modifications to blind accepts
32
+ - **Validation**: How often you verify/test output
33
+ - **Diversity**: How many decision types you use (steer, reject, validate, modify, scope, accept)
34
+
35
+ ## Commands
36
+
37
+ | Command | What |
38
+ |---------|------|
39
+ | `/pup:eval` | Evaluate session across 11 skill dimensions |
40
+ | `/pup:pr-report` | DQS report for current branch (add `--post` to comment on PR) |
41
+ | `/pup:status` | Sessions tracked, evaluations, decision counts |
42
+ | `/pup:config` | View/modify settings (`/pup:config evaluation.auto_trigger=prompt_count`) |
43
+ | `/pup:update` | Check for and install updates |
44
+
45
+ ## MCP Tools
18
46
 
19
47
  | Tool | What |
20
48
  |------|------|
21
- | `evaluate_session` | Score a coding session across 11 skill dimensions |
22
- | `generate_pr_report` | Decision Quality Score (DQS) report for a git branch |
23
- | `get_status` | Sessions tracked, evaluations, decision counts |
24
- | `configure` | View/modify all PromptUp settings |
49
+ | `evaluate_session` | Score session, extract decisions, coaching recommendations |
50
+ | `generate_pr_report` | Match sessions to branch, compute DQS, optionally post to GitHub |
51
+ | `get_status` | Tracking status and recent activity |
52
+ | `configure` | Show/modify config (dot-path keys) |
53
+
54
+ ## Statusline
55
+
56
+ `pupmeter` shows your latest composite score in the Claude Code status bar with a recommendation tip.
57
+
58
+ ## Hooks
59
+
60
+ | Hook | What | Async |
61
+ |------|------|-------|
62
+ | `PostToolUse` | Logs tool events to `~/.promptup/tool-events.jsonl` | Yes |
63
+ | `Stop` | Captures session end to `~/.promptup/session-end.json` | Yes |
64
+ | `SessionStart` | Background update check against npm | Yes |
65
+ | `UserPromptSubmit` | Auto-eval every N prompts (off by default) | Yes |
66
+
67
+ ## Configuration
25
68
 
26
- **3 Skills:**
27
- - `/eval` Run an evaluation
28
- - `/pr-report` Generate PR report (optionally post to GitHub)
29
- - `/status` Check tracking status
69
+ ```bash
70
+ /pup:config # show all settings
71
+ /pup:config evaluation.auto_trigger=prompt_count # enable auto-eval
72
+ /pup:config evaluation.interval=5 # eval every 5 prompts
73
+ /pup:config evaluation.weight_profile=bugfix # scoring profile
74
+ /pup:config decisions.signal_filter=all # show all decisions
75
+ ```
76
+
77
+ Config file: `~/.promptup/config.json`
30
78
 
31
- **Statusline:** `pupmeter` shows your latest score in the Claude Code status bar.
79
+ ## 11 Dimensions
32
80
 
33
- **Hooks:** Passive tracking via PostToolUse + session capture on Stop. Auto-eval on prompt count (configurable). Update check on SessionStart.
81
+ **Base (interaction quality):**
82
+ task decomposition, prompt specificity, output validation, iteration quality, strategic tool usage, context management
83
+
84
+ **Domain (depth of understanding):**
85
+ architectural awareness, error anticipation, technical vocabulary, dependency reasoning, tradeoff articulation
34
86
 
35
87
  ## Requirements
36
88
 
37
89
  - Node.js >= 20
38
90
  - Claude Code
39
91
 
40
- ## Manual setup (alternative)
41
-
42
- If you prefer not to use the installer:
92
+ ## Manual setup
43
93
 
44
94
  ```json
45
95
  {
@@ -52,21 +102,6 @@ If you prefer not to use the installer:
52
102
  }
53
103
  ```
54
104
 
55
- ## Configuration
56
-
57
- Run `configure` with no args to see all settings:
58
-
59
- ```
60
- evaluation.auto_trigger off | prompt_count | session_end
61
- evaluation.interval prompts between auto-evals (default: 10)
62
- evaluation.weight_profile balanced | greenfield | bugfix | refactor | security_review
63
- evaluation.feedback_detail brief | standard | detailed
64
- decisions.signal_filter high | high+medium | all
65
- pr_report.auto_post true | false
66
- ```
67
-
68
- Config file: `~/.promptup/config.json`
69
-
70
105
  ## Uninstall
71
106
 
72
107
  ```bash
package/dist/db.js CHANGED
@@ -40,6 +40,7 @@ export function initDatabase() {
40
40
  id TEXT PRIMARY KEY,
41
41
  project_path TEXT,
42
42
  transcript_path TEXT,
43
+ branch TEXT,
43
44
  status TEXT DEFAULT 'active',
44
45
  message_count INTEGER DEFAULT 0,
45
46
  started_at TEXT NOT NULL,
@@ -131,6 +132,11 @@ export function initDatabase() {
131
132
  );
132
133
  CREATE INDEX IF NOT EXISTS idx_pr_reports_branch ON pr_reports(branch, repo);
133
134
  `);
135
+ // Migrations — add columns to existing databases
136
+ try {
137
+ instance.exec('ALTER TABLE sessions ADD COLUMN branch TEXT');
138
+ }
139
+ catch { /* column already exists */ }
134
140
  db = instance;
135
141
  }
136
142
  export function closeDatabase() {
@@ -143,11 +149,11 @@ export function closeDatabase() {
143
149
  export function insertSession(session) {
144
150
  const d = getDb();
145
151
  d.prepare(`
146
- INSERT OR IGNORE INTO sessions (id, project_path, transcript_path, status,
152
+ INSERT OR IGNORE INTO sessions (id, project_path, transcript_path, branch, status,
147
153
  message_count, started_at, ended_at, created_at)
148
- VALUES (@id, @project_path, @transcript_path, @status,
154
+ VALUES (@id, @project_path, @transcript_path, @branch, @status,
149
155
  @message_count, @started_at, @ended_at, @created_at)
150
- `).run(session);
156
+ `).run({ branch: null, ...session });
151
157
  }
152
158
  export function getSession(id) {
153
159
  const row = getDb()
@@ -279,10 +285,20 @@ export function insertGitActivity(activity) {
279
285
  });
280
286
  }
281
287
  export function getSessionsByBranch(branch) {
282
- const rows = getDb()
288
+ const d = getDb();
289
+ // Primary: sessions with branch column set directly
290
+ const direct = d
291
+ .prepare('SELECT id FROM sessions WHERE branch = ? ORDER BY created_at')
292
+ .all(branch)
293
+ .map((r) => r.id);
294
+ // Supplement: sessions linked via git_activities
295
+ const fromGit = d
283
296
  .prepare('SELECT DISTINCT session_id FROM git_activities WHERE branch = ? ORDER BY created_at')
284
- .all(branch);
285
- return rows.map((r) => r.session_id);
297
+ .all(branch)
298
+ .map((r) => r.session_id);
299
+ // Merge, deduplicate
300
+ const all = [...new Set([...direct, ...fromGit])];
301
+ return all;
286
302
  }
287
303
  // ─── Session matching ────────────────────────────────────────────────────────
288
304
  export function getSessionsByTimeRange(from, to, projectPath) {
package/dist/index.js CHANGED
@@ -20,14 +20,14 @@ const server = new McpServer({
20
20
  version: '1.0.0',
21
21
  });
22
22
  // Tool 1: evaluate_session
23
- server.tool('evaluate_session', 'Evaluate a coding session across 11 skill dimensions. Spawns an independent Claude analysis of the session transcript. Returns composite score, dimension breakdown, trends, and recommendations.', {
23
+ server.tool('evaluate_session', 'Evaluate a coding session across 11 skill dimensions. Spawns an independent Claude analysis of the session transcript. Extracts developer decisions (steers, rejects, validates, scopes). Returns composite score, dimension breakdown, trends, coaching recommendations with before/after examples. Session is tagged with current git branch for PR matching.', {
24
24
  session_id: z.string().optional().describe('Session ID to evaluate. If omitted, evaluates the most recent session.'),
25
25
  }, async (args) => {
26
26
  const result = await handleEvaluateSession(args);
27
27
  return { ...result };
28
28
  });
29
29
  // Tool 2: generate_pr_report
30
- server.tool('generate_pr_report', 'Generate a Decision Quality Score (DQS) report for a git branch. Matches commits to sessions, analyzes developer decisions, and produces a structured markdown report. Optionally posts as a GitHub PR comment.', {
30
+ server.tool('generate_pr_report', 'Generate a Decision Quality Score (DQS) report for a git branch. Matches sessions to the branch via sessions.branch column (set on session creation). Auto-evaluates unscored sessions, extracts decisions, computes DQS (autonomy + discipline + validation + diversity). Optionally posts as a GitHub PR comment via gh CLI.', {
31
31
  branch: z.string().optional().describe('Git branch name. Defaults to current branch.'),
32
32
  post: z.boolean().optional().default(false).describe('If true, post the report as a GitHub PR comment via gh CLI.'),
33
33
  }, async (args) => {
@@ -280,6 +280,7 @@ export async function generatePRReport(options) {
280
280
  id: sid,
281
281
  project_path: projectPath ?? process.cwd(),
282
282
  transcript_path: latestTranscript,
283
+ branch: branch,
283
284
  status: 'completed',
284
285
  message_count: msgs.length,
285
286
  started_at: msgs[0].created_at,
package/dist/tools.js CHANGED
@@ -17,6 +17,13 @@ import { ulid } from 'ulid';
17
17
  import { readFileSync, existsSync } from 'node:fs';
18
18
  import { join } from 'node:path';
19
19
  import { homedir } from 'node:os';
20
+ import { execSync } from 'node:child_process';
21
+ function detectBranch() {
22
+ try {
23
+ return execSync('git branch --show-current', { encoding: 'utf-8', timeout: 5000 }).trim() || null;
24
+ }
25
+ catch { return null; }
26
+ }
20
27
  import { loadConfig, updateConfig } from './config.js';
21
28
  function textResponse(text, isError = false) {
22
29
  return { content: [{ type: 'text', text }], ...(isError ? { isError } : {}) };
@@ -167,6 +174,7 @@ export async function handleEvaluateSession(args) {
167
174
  id: sessionId,
168
175
  project_path: process.cwd(),
169
176
  transcript_path: transcriptPath,
177
+ branch: detectBranch(),
170
178
  status: 'completed',
171
179
  message_count: messages.length,
172
180
  started_at: firstMsg.created_at,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "promptup-plugin",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "AI coding skill evaluator for Claude Code — 11-dimension scoring, decision intelligence, PR reports",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",