promptup-plugin 0.1.1
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/LICENSE +21 -0
- package/README.md +78 -0
- package/bin/install.cjs +306 -0
- package/bin/promptup-plugin +8 -0
- package/dist/config.d.ts +40 -0
- package/dist/config.js +123 -0
- package/dist/db.d.ts +35 -0
- package/dist/db.js +327 -0
- package/dist/decision-detector.d.ts +11 -0
- package/dist/decision-detector.js +47 -0
- package/dist/evaluator.d.ts +10 -0
- package/dist/evaluator.js +844 -0
- package/dist/git-activity-extractor.d.ts +35 -0
- package/dist/git-activity-extractor.js +167 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +54 -0
- package/dist/pr-report-generator.d.ts +20 -0
- package/dist/pr-report-generator.js +421 -0
- package/dist/shared/decision-classifier.d.ts +60 -0
- package/dist/shared/decision-classifier.js +385 -0
- package/dist/shared/decision-score.d.ts +7 -0
- package/dist/shared/decision-score.js +31 -0
- package/dist/shared/dimensions.d.ts +43 -0
- package/dist/shared/dimensions.js +361 -0
- package/dist/shared/scoring.d.ts +89 -0
- package/dist/shared/scoring.js +161 -0
- package/dist/shared/types.d.ts +108 -0
- package/dist/shared/types.js +9 -0
- package/dist/tools.d.ts +30 -0
- package/dist/tools.js +456 -0
- package/dist/transcript-parser.d.ts +36 -0
- package/dist/transcript-parser.js +201 -0
- package/hooks/auto-eval.sh +44 -0
- package/hooks/check-update.sh +26 -0
- package/hooks/debug-hook.sh +3 -0
- package/hooks/hooks.json +36 -0
- package/hooks/render-eval.sh +137 -0
- package/package.json +60 -0
- package/skills/eval/SKILL.md +12 -0
- package/skills/pr-report/SKILL.md +37 -0
- package/skills/status/SKILL.md +28 -0
- package/statusline.sh +46 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git Activity Extractor
|
|
3
|
+
*
|
|
4
|
+
* Parses stored tool_uses from MessageRow records to extract git operations
|
|
5
|
+
* (checkout, commit, push, branch_create, merge). Provides exact
|
|
6
|
+
* session → branch → commit mappings without relying on timestamp heuristics.
|
|
7
|
+
*
|
|
8
|
+
* Bash commands from Claude Code may be:
|
|
9
|
+
* - Simple: git checkout -b feature/auth
|
|
10
|
+
* - Chained: cd /repo && git commit -m "fix"
|
|
11
|
+
* - Heredoc: git commit -m "$(cat <<'EOF'\nFix bug\nEOF\n)"
|
|
12
|
+
*
|
|
13
|
+
* STANDALONE port — no imports from @promptup/shared or workspace packages.
|
|
14
|
+
*/
|
|
15
|
+
import type { MessageRow, GitActivityRow } from './shared/types.js';
|
|
16
|
+
export interface ExtractedGitOp {
|
|
17
|
+
type: 'checkout' | 'commit' | 'push' | 'branch_create' | 'merge';
|
|
18
|
+
branch: string | null;
|
|
19
|
+
commitHash: string | null;
|
|
20
|
+
commitMessage: string | null;
|
|
21
|
+
remote: string | null;
|
|
22
|
+
rawCommand: string;
|
|
23
|
+
messageIndex: number;
|
|
24
|
+
createdAt: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Parse tool_uses from a list of MessageRows and extract git operations.
|
|
28
|
+
* Only inspects assistant messages with Bash tool uses.
|
|
29
|
+
*/
|
|
30
|
+
export declare function extractGitOps(messages: MessageRow[]): ExtractedGitOp[];
|
|
31
|
+
/**
|
|
32
|
+
* Extract git operations from messages and persist them to the git_activities table.
|
|
33
|
+
* Returns the list of stored rows.
|
|
34
|
+
*/
|
|
35
|
+
export declare function extractAndStoreGitActivity(messages: MessageRow[], sessionId: string): GitActivityRow[];
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git Activity Extractor
|
|
3
|
+
*
|
|
4
|
+
* Parses stored tool_uses from MessageRow records to extract git operations
|
|
5
|
+
* (checkout, commit, push, branch_create, merge). Provides exact
|
|
6
|
+
* session → branch → commit mappings without relying on timestamp heuristics.
|
|
7
|
+
*
|
|
8
|
+
* Bash commands from Claude Code may be:
|
|
9
|
+
* - Simple: git checkout -b feature/auth
|
|
10
|
+
* - Chained: cd /repo && git commit -m "fix"
|
|
11
|
+
* - Heredoc: git commit -m "$(cat <<'EOF'\nFix bug\nEOF\n)"
|
|
12
|
+
*
|
|
13
|
+
* STANDALONE port — no imports from @promptup/shared or workspace packages.
|
|
14
|
+
*/
|
|
15
|
+
import { ulid } from 'ulid';
|
|
16
|
+
import { insertGitActivity } from './db.js';
|
|
17
|
+
// ─── Regex patterns ──────────────────────────────────────────────────────────
|
|
18
|
+
// git checkout [-b] <branch> — optional flags like --track before branch name
|
|
19
|
+
const RE_CHECKOUT = /\bgit\s+checkout\s+((?:-[^\s]+\s+)*?)(-b\s+)?([A-Za-z0-9_.\-/]+)\b/;
|
|
20
|
+
// git switch [-c] <branch>
|
|
21
|
+
const RE_SWITCH = /\bgit\s+switch\s+((?:-[^\s]+\s+)*?)(-c\s+)?([A-Za-z0-9_.\-/]+)\b/;
|
|
22
|
+
// git commit — captures quoted message (including heredoc first-line)
|
|
23
|
+
const RE_COMMIT = /\bgit\s+commit\b[^"']*?(?:-m\s*(?:"([^"]*?)"|'([^']*?)'))/s;
|
|
24
|
+
// git commit with heredoc: -m "$(cat <<'EOF'\nFirst line\n..."
|
|
25
|
+
const RE_COMMIT_HEREDOC = /\bgit\s+commit\b.*?-m\s*"\$\(cat\s*<<'?EOF'?\s*\\?n([^\n\\]+)/s;
|
|
26
|
+
// git push [flags] [remote] [branch]
|
|
27
|
+
const RE_PUSH = /\bgit\s+push\b((?:\s+(?:--force|-f|--set-upstream|-u))*)\s+([A-Za-z0-9_.\-/]+)\s+([A-Za-z0-9_.\-/]+)/;
|
|
28
|
+
// git push with just remote and branch (no flags)
|
|
29
|
+
const RE_PUSH_SIMPLE = /\bgit\s+push\s+([A-Za-z0-9_.\-/]+)\s+([A-Za-z0-9_.\-/]+)/;
|
|
30
|
+
// git merge <branch>
|
|
31
|
+
const RE_MERGE = /\bgit\s+merge\s+([A-Za-z0-9_.\-/]+)/;
|
|
32
|
+
// Read-only operations to ignore
|
|
33
|
+
const RE_READONLY = /\bgit\s+(?:log|status|diff|show|blame|fetch|clone|remote|branch\s+-[lav]|stash\s+list|tag\b)/;
|
|
34
|
+
// ─── Segment-level parser ────────────────────────────────────────────────────
|
|
35
|
+
function parseSegment(segment) {
|
|
36
|
+
const s = segment.trim();
|
|
37
|
+
// Skip read-only git operations early
|
|
38
|
+
if (RE_READONLY.test(s))
|
|
39
|
+
return null;
|
|
40
|
+
// Skip if no git command at all
|
|
41
|
+
if (!/\bgit\b/.test(s))
|
|
42
|
+
return null;
|
|
43
|
+
// git commit (heredoc form takes priority — matches $(...) syntax)
|
|
44
|
+
const heredocMatch = RE_COMMIT_HEREDOC.exec(s);
|
|
45
|
+
if (heredocMatch) {
|
|
46
|
+
const firstLine = (heredocMatch[1] ?? '').trim();
|
|
47
|
+
return { type: 'commit', branch: null, commitHash: null, commitMessage: firstLine || null, remote: null };
|
|
48
|
+
}
|
|
49
|
+
// git commit (quoted -m form)
|
|
50
|
+
const commitMatch = RE_COMMIT.exec(s);
|
|
51
|
+
if (commitMatch) {
|
|
52
|
+
const msg = (commitMatch[1] ?? commitMatch[2] ?? '').split('\n')[0].trim();
|
|
53
|
+
return { type: 'commit', branch: null, commitHash: null, commitMessage: msg || null, remote: null };
|
|
54
|
+
}
|
|
55
|
+
// git push (with flags — try full form first)
|
|
56
|
+
const pushMatch = RE_PUSH.exec(s);
|
|
57
|
+
if (pushMatch) {
|
|
58
|
+
const remote = pushMatch[2] ?? null;
|
|
59
|
+
const branch = pushMatch[3] ?? null;
|
|
60
|
+
return { type: 'push', branch, commitHash: null, commitMessage: null, remote };
|
|
61
|
+
}
|
|
62
|
+
// git push simple (no flags)
|
|
63
|
+
const pushSimple = RE_PUSH_SIMPLE.exec(s);
|
|
64
|
+
if (pushSimple) {
|
|
65
|
+
const remote = pushSimple[1] ?? null;
|
|
66
|
+
const branch = pushSimple[2] ?? null;
|
|
67
|
+
return { type: 'push', branch, commitHash: null, commitMessage: null, remote };
|
|
68
|
+
}
|
|
69
|
+
// git switch [-c] <branch>
|
|
70
|
+
const switchMatch = RE_SWITCH.exec(s);
|
|
71
|
+
if (switchMatch) {
|
|
72
|
+
const isCreate = !!switchMatch[2];
|
|
73
|
+
const branch = switchMatch[3] ?? null;
|
|
74
|
+
return { type: isCreate ? 'branch_create' : 'checkout', branch, commitHash: null, commitMessage: null, remote: null };
|
|
75
|
+
}
|
|
76
|
+
// git checkout [-b] <branch>
|
|
77
|
+
const checkoutMatch = RE_CHECKOUT.exec(s);
|
|
78
|
+
if (checkoutMatch) {
|
|
79
|
+
const isCreate = !!checkoutMatch[2];
|
|
80
|
+
const branch = checkoutMatch[3] ?? null;
|
|
81
|
+
// Skip if this looks like a file path restore (git checkout -- file.ts)
|
|
82
|
+
if (branch === '--')
|
|
83
|
+
return null;
|
|
84
|
+
return { type: isCreate ? 'branch_create' : 'checkout', branch, commitHash: null, commitMessage: null, remote: null };
|
|
85
|
+
}
|
|
86
|
+
// git merge <branch>
|
|
87
|
+
const mergeMatch = RE_MERGE.exec(s);
|
|
88
|
+
if (mergeMatch) {
|
|
89
|
+
const branch = mergeMatch[1] ?? null;
|
|
90
|
+
return { type: 'merge', branch, commitHash: null, commitMessage: null, remote: null };
|
|
91
|
+
}
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
// ─── Command-level parser (handles chaining with &&) ────────────────────────
|
|
95
|
+
function parseCommand(rawCommand, messageIndex, createdAt) {
|
|
96
|
+
const ops = [];
|
|
97
|
+
// Split on && — each segment may independently contain a git operation
|
|
98
|
+
const segments = rawCommand.split('&&');
|
|
99
|
+
for (const segment of segments) {
|
|
100
|
+
const result = parseSegment(segment);
|
|
101
|
+
if (result) {
|
|
102
|
+
ops.push({ ...result, rawCommand: rawCommand.trim(), messageIndex, createdAt });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return ops;
|
|
106
|
+
}
|
|
107
|
+
// ─── Main extraction function ────────────────────────────────────────────────
|
|
108
|
+
/**
|
|
109
|
+
* Parse tool_uses from a list of MessageRows and extract git operations.
|
|
110
|
+
* Only inspects assistant messages with Bash tool uses.
|
|
111
|
+
*/
|
|
112
|
+
export function extractGitOps(messages) {
|
|
113
|
+
const allOps = [];
|
|
114
|
+
for (const message of messages) {
|
|
115
|
+
// Only assistant messages contain tool_uses
|
|
116
|
+
if (message.role !== 'assistant')
|
|
117
|
+
continue;
|
|
118
|
+
if (!message.tool_uses)
|
|
119
|
+
continue;
|
|
120
|
+
let toolUses;
|
|
121
|
+
try {
|
|
122
|
+
toolUses = JSON.parse(message.tool_uses);
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (!Array.isArray(toolUses))
|
|
128
|
+
continue;
|
|
129
|
+
for (const tool of toolUses) {
|
|
130
|
+
// Only Bash tool calls contain shell commands
|
|
131
|
+
if (tool.name !== 'Bash')
|
|
132
|
+
continue;
|
|
133
|
+
const command = tool.input?.command;
|
|
134
|
+
if (typeof command !== 'string')
|
|
135
|
+
continue;
|
|
136
|
+
const ops = parseCommand(command, message.sequence_number, message.created_at);
|
|
137
|
+
allOps.push(...ops);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return allOps;
|
|
141
|
+
}
|
|
142
|
+
// ─── Store extracted git activity ─────────────────────────────────────────────
|
|
143
|
+
/**
|
|
144
|
+
* Extract git operations from messages and persist them to the git_activities table.
|
|
145
|
+
* Returns the list of stored rows.
|
|
146
|
+
*/
|
|
147
|
+
export function extractAndStoreGitActivity(messages, sessionId) {
|
|
148
|
+
const ops = extractGitOps(messages);
|
|
149
|
+
const rows = [];
|
|
150
|
+
for (const op of ops) {
|
|
151
|
+
const row = {
|
|
152
|
+
id: ulid(),
|
|
153
|
+
session_id: sessionId,
|
|
154
|
+
type: op.type,
|
|
155
|
+
branch: op.branch,
|
|
156
|
+
commit_hash: op.commitHash,
|
|
157
|
+
commit_message: op.commitMessage,
|
|
158
|
+
remote: op.remote,
|
|
159
|
+
raw_command: op.rawCommand,
|
|
160
|
+
message_index: op.messageIndex,
|
|
161
|
+
created_at: op.createdAt,
|
|
162
|
+
};
|
|
163
|
+
insertGitActivity(row);
|
|
164
|
+
rows.push(row);
|
|
165
|
+
}
|
|
166
|
+
return rows;
|
|
167
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* PromptUp MCP Server — standalone stdio plugin for Claude Code.
|
|
4
|
+
*
|
|
5
|
+
* Registers 3 tools:
|
|
6
|
+
* - evaluate_session — evaluate a coding session across 11 skill dimensions
|
|
7
|
+
* - generate_pr_report — generate a DQS report for a git branch
|
|
8
|
+
* - get_status — show tracking status and recent activity
|
|
9
|
+
*
|
|
10
|
+
* Zero infrastructure — just SQLite at ~/.promptup/promptup.db.
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* PromptUp MCP Server — standalone stdio plugin for Claude Code.
|
|
4
|
+
*
|
|
5
|
+
* Registers 3 tools:
|
|
6
|
+
* - evaluate_session — evaluate a coding session across 11 skill dimensions
|
|
7
|
+
* - generate_pr_report — generate a DQS report for a git branch
|
|
8
|
+
* - get_status — show tracking status and recent activity
|
|
9
|
+
*
|
|
10
|
+
* Zero infrastructure — just SQLite at ~/.promptup/promptup.db.
|
|
11
|
+
*/
|
|
12
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
13
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
14
|
+
import { z } from 'zod';
|
|
15
|
+
import { initDatabase, closeDatabase } from './db.js';
|
|
16
|
+
import { handleEvaluateSession, handleGeneratePRReport, handleGetStatus, handleConfigure } from './tools.js';
|
|
17
|
+
initDatabase();
|
|
18
|
+
const server = new McpServer({
|
|
19
|
+
name: 'promptup',
|
|
20
|
+
version: '1.0.0',
|
|
21
|
+
});
|
|
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.', {
|
|
24
|
+
session_id: z.string().optional().describe('Session ID to evaluate. If omitted, evaluates the most recent session.'),
|
|
25
|
+
}, async (args) => {
|
|
26
|
+
const result = await handleEvaluateSession(args);
|
|
27
|
+
return { ...result };
|
|
28
|
+
});
|
|
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.', {
|
|
31
|
+
branch: z.string().optional().describe('Git branch name. Defaults to current branch.'),
|
|
32
|
+
post: z.boolean().optional().default(false).describe('If true, post the report as a GitHub PR comment via gh CLI.'),
|
|
33
|
+
}, async (args) => {
|
|
34
|
+
const result = await handleGeneratePRReport(args);
|
|
35
|
+
return { ...result };
|
|
36
|
+
});
|
|
37
|
+
// Tool 3: get_status
|
|
38
|
+
server.tool('get_status', 'Show PromptUp tracking status: session count, evaluation history, decision counts, and recent activity.', {}, async () => {
|
|
39
|
+
const result = await handleGetStatus({});
|
|
40
|
+
return { ...result };
|
|
41
|
+
});
|
|
42
|
+
// Tool 4: configure
|
|
43
|
+
server.tool('configure', 'Show or modify PromptUp configuration. Call with no args to see all settings. Use "set" to change values (dot-path keys like "evaluation.interval"). Use "get" to read a specific value.', {
|
|
44
|
+
get: z.string().optional().describe('Dot-path to read a specific config value, e.g. "evaluation.interval"'),
|
|
45
|
+
set: z.record(z.unknown()).optional().describe('Key-value pairs to update, e.g. {"evaluation.interval": 5, "evaluation.auto_trigger": "prompt_count"}'),
|
|
46
|
+
}, async (args) => {
|
|
47
|
+
const result = await handleConfigure(args);
|
|
48
|
+
return { ...result };
|
|
49
|
+
});
|
|
50
|
+
// Start
|
|
51
|
+
const transport = new StdioServerTransport();
|
|
52
|
+
await server.connect(transport);
|
|
53
|
+
process.on('SIGINT', () => { closeDatabase(); process.exit(0); });
|
|
54
|
+
process.on('SIGTERM', () => { closeDatabase(); process.exit(0); });
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PR Report Generator
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates generating a Decision Quality Score (DQS) report for a pull request.
|
|
5
|
+
* Uses git + gh CLI to gather branch/PR/commit data, then matches commits to sessions
|
|
6
|
+
* via timestamp and project_path. Falls back to heuristic detection if no plugin
|
|
7
|
+
* decisions are captured.
|
|
8
|
+
*
|
|
9
|
+
* STANDALONE port — no imports from @promptup/shared or workspace packages.
|
|
10
|
+
*/
|
|
11
|
+
import type { PRReportRow } from './shared/types.js';
|
|
12
|
+
export interface GeneratedPRReport {
|
|
13
|
+
report: PRReportRow;
|
|
14
|
+
isNew: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function generatePRReport(options: {
|
|
17
|
+
branch?: string;
|
|
18
|
+
post?: boolean;
|
|
19
|
+
projectPath?: string;
|
|
20
|
+
}): Promise<GeneratedPRReport>;
|