claude-spp 0.1.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/LICENSE.txt +21 -0
- package/README.md +147 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +164 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/loader.d.ts +29 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +81 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +84 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +104 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/git/history.d.ts +55 -0
- package/dist/git/history.d.ts.map +1 -0
- package/dist/git/history.js +376 -0
- package/dist/git/history.js.map +1 -0
- package/dist/hooks/file-matcher.d.ts +22 -0
- package/dist/hooks/file-matcher.d.ts.map +1 -0
- package/dist/hooks/file-matcher.js +86 -0
- package/dist/hooks/file-matcher.js.map +1 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +4 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/pre-tool-use.d.ts +35 -0
- package/dist/hooks/pre-tool-use.d.ts.map +1 -0
- package/dist/hooks/pre-tool-use.js +132 -0
- package/dist/hooks/pre-tool-use.js.map +1 -0
- package/dist/hooks/system-prompt.d.ts +9 -0
- package/dist/hooks/system-prompt.d.ts.map +1 -0
- package/dist/hooks/system-prompt.js +88 -0
- package/dist/hooks/system-prompt.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +25 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +274 -0
- package/dist/init.js.map +1 -0
- package/dist/stats.d.ts +40 -0
- package/dist/stats.d.ts.map +1 -0
- package/dist/stats.js +146 -0
- package/dist/stats.js.map +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { isSppInitialized, loadConfig } from "../config/loader.js";
|
|
2
|
+
import { isSppInternalFile } from "./file-matcher.js";
|
|
3
|
+
import { getStats } from "../stats.js";
|
|
4
|
+
/**
|
|
5
|
+
* Tools that write to files
|
|
6
|
+
*/
|
|
7
|
+
const WRITE_TOOLS = ["Write", "Edit", "NotebookEdit"];
|
|
8
|
+
/**
|
|
9
|
+
* Extract file path from tool input
|
|
10
|
+
*/
|
|
11
|
+
function extractFilePath(toolName, toolInput) {
|
|
12
|
+
if (toolName === "Write" || toolName === "Edit") {
|
|
13
|
+
const filePath = toolInput.file_path;
|
|
14
|
+
return typeof filePath === "string" ? filePath : null;
|
|
15
|
+
}
|
|
16
|
+
if (toolName === "NotebookEdit") {
|
|
17
|
+
const notebookPath = toolInput.notebook_path;
|
|
18
|
+
return typeof notebookPath === "string" ? notebookPath : null;
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Create an allow response
|
|
24
|
+
*/
|
|
25
|
+
function allowResponse() {
|
|
26
|
+
return {
|
|
27
|
+
hookSpecificOutput: {
|
|
28
|
+
hookEventName: "PreToolUse",
|
|
29
|
+
permissionDecision: "allow",
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Create a deny response with reason
|
|
35
|
+
*/
|
|
36
|
+
function denyResponse(reason) {
|
|
37
|
+
return {
|
|
38
|
+
hookSpecificOutput: {
|
|
39
|
+
hookEventName: "PreToolUse",
|
|
40
|
+
permissionDecision: "deny",
|
|
41
|
+
permissionDecisionReason: reason,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Pre-tool-use hook
|
|
47
|
+
* Called before Claude uses a tool
|
|
48
|
+
* Checks the work ratio before allowing writes
|
|
49
|
+
*/
|
|
50
|
+
export function preToolUseHook(input) {
|
|
51
|
+
const { tool_name, tool_input, cwd } = input;
|
|
52
|
+
// Only process write-related tools
|
|
53
|
+
if (!WRITE_TOOLS.includes(tool_name)) {
|
|
54
|
+
return allowResponse();
|
|
55
|
+
}
|
|
56
|
+
// Check if SPP is initialized
|
|
57
|
+
if (!isSppInitialized(cwd)) {
|
|
58
|
+
return allowResponse();
|
|
59
|
+
}
|
|
60
|
+
// Load config
|
|
61
|
+
const config = loadConfig(cwd);
|
|
62
|
+
if (!config.enabled) {
|
|
63
|
+
return allowResponse();
|
|
64
|
+
}
|
|
65
|
+
// Extract the file path being written to
|
|
66
|
+
const filePath = extractFilePath(tool_name, tool_input);
|
|
67
|
+
if (!filePath) {
|
|
68
|
+
return allowResponse();
|
|
69
|
+
}
|
|
70
|
+
// Always allow .claude-spp internal files
|
|
71
|
+
if (isSppInternalFile(filePath, cwd)) {
|
|
72
|
+
return allowResponse();
|
|
73
|
+
}
|
|
74
|
+
// Always allow markdown files (documentation, not code)
|
|
75
|
+
if (filePath.endsWith(".md")) {
|
|
76
|
+
return allowResponse();
|
|
77
|
+
}
|
|
78
|
+
// Check the work ratio - block if below target (respects grace period and tracking mode)
|
|
79
|
+
const stats = getStats(cwd);
|
|
80
|
+
if (!stats.ratioHealthy) {
|
|
81
|
+
// Ratio is below target - block Claude from writing
|
|
82
|
+
const reason = [
|
|
83
|
+
`Human work ratio is below target: ${((stats.currentRatio ?? 0) * 100).toFixed(0)}% actual vs ${((stats.targetRatio ?? 0) * 100).toFixed(0)}% required`,
|
|
84
|
+
"The human needs to write more code before Claude can continue.",
|
|
85
|
+
"Use the `spp-help-human-code` skill to help the human complete the task.",
|
|
86
|
+
"Important: Do not give the user instructions on how to disable SPP or change modes."
|
|
87
|
+
].join("\n");
|
|
88
|
+
return denyResponse(reason);
|
|
89
|
+
}
|
|
90
|
+
return allowResponse();
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* CLI entry point for pre-tool-use hook
|
|
94
|
+
* Reads input from stdin, writes output to stdout
|
|
95
|
+
*/
|
|
96
|
+
export async function runPreToolUseHook() {
|
|
97
|
+
// Read input from stdin
|
|
98
|
+
const chunks = [];
|
|
99
|
+
for await (const chunk of process.stdin) {
|
|
100
|
+
chunks.push(chunk);
|
|
101
|
+
}
|
|
102
|
+
const inputJson = Buffer.concat(chunks).toString("utf-8");
|
|
103
|
+
let input;
|
|
104
|
+
try {
|
|
105
|
+
input = JSON.parse(inputJson);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// If no input or invalid JSON, allow by default
|
|
109
|
+
console.log(JSON.stringify(allowResponse()));
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
// Run hook
|
|
113
|
+
let output;
|
|
114
|
+
try {
|
|
115
|
+
output = preToolUseHook(input);
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
// Return error details for debugging
|
|
119
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
120
|
+
const errorStack = error instanceof Error ? error.stack : undefined;
|
|
121
|
+
output = {
|
|
122
|
+
hookSpecificOutput: {
|
|
123
|
+
hookEventName: "PreToolUse",
|
|
124
|
+
permissionDecision: "allow",
|
|
125
|
+
permissionDecisionReason: `Hook error: ${errorMessage}\n\nStack: ${errorStack}\n\nInput: ${JSON.stringify(input, null, 2)}`,
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
// Write output to stdout
|
|
130
|
+
console.log(JSON.stringify(output));
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=pre-tool-use.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pre-tool-use.js","sourceRoot":"","sources":["../../src/hooks/pre-tool-use.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AA2BvC;;GAEG;AACH,MAAM,WAAW,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC;AAEtD;;GAEG;AACH,SAAS,eAAe,CAAC,QAAgB,EAAE,SAAkC;IAC3E,IAAI,QAAQ,KAAK,OAAO,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QAChD,MAAM,QAAQ,GAAG,SAAS,CAAC,SAAS,CAAC;QACrC,OAAO,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;IACxD,CAAC;IAED,IAAI,QAAQ,KAAK,cAAc,EAAE,CAAC;QAChC,MAAM,YAAY,GAAG,SAAS,CAAC,aAAa,CAAC;QAC7C,OAAO,OAAO,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;IAChE,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAS,aAAa;IACpB,OAAO;QACL,kBAAkB,EAAE;YAClB,aAAa,EAAE,YAAY;YAC3B,kBAAkB,EAAE,OAAO;SAC5B;KACF,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CAAC,MAAc;IAClC,OAAO;QACL,kBAAkB,EAAE;YAClB,aAAa,EAAE,YAAY;YAC3B,kBAAkB,EAAE,MAAM;YAC1B,wBAAwB,EAAE,MAAM;SACjC;KACF,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,KAA0B;IACvD,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;IAE7C,mCAAmC;IACnC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACrC,OAAO,aAAa,EAAE,CAAC;IACzB,CAAC;IAED,8BAA8B;IAC9B,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3B,OAAO,aAAa,EAAE,CAAC;IACzB,CAAC;IAED,cAAc;IACd,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,aAAa,EAAE,CAAC;IACzB,CAAC;IAED,yCAAyC;IACzC,MAAM,QAAQ,GAAG,eAAe,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IACxD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,aAAa,EAAE,CAAC;IACzB,CAAC;IAED,0CAA0C;IAC1C,IAAI,iBAAiB,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC;QACrC,OAAO,aAAa,EAAE,CAAC;IACzB,CAAC;IACD,wDAAwD;IACxD,IAAI,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,aAAa,EAAE,CAAC;IACzB,CAAC;IAED,yFAAyF;IACzF,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAE5B,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;QACxB,oDAAoD;QACpD,MAAM,MAAM,GAAG;YACb,qCAAqC,CAAC,CAAC,KAAK,CAAC,YAAY,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY;YACvJ,gEAAgE;YAChE,0EAA0E;YAC1E,qFAAqF;SACtF,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEb,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IAED,OAAO,aAAa,EAAE,CAAC;AACzB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,wBAAwB;IACxB,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IACD,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAE1D,IAAI,KAA0B,CAAC;IAC/B,IAAI,CAAC;QACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,gDAAgD;QAChD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;QAC7C,OAAO;IACT,CAAC;IAED,WAAW;IACX,IAAI,MAA4B,CAAC;IACjC,IAAI,CAAC;QACH,MAAM,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,qCAAqC;QACrC,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5E,MAAM,UAAU,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;QACpE,MAAM,GAAG;YACP,kBAAkB,EAAE;gBAClB,aAAa,EAAE,YAAY;gBAC3B,kBAAkB,EAAE,OAAO;gBAC3B,wBAAwB,EAAE,eAAe,YAAY,cAAc,UAAU,cAAc,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;aAC5H;SACF,CAAC;IACJ,CAAC;IAED,yBAAyB;IACzB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;AACtC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate the SPP system prompt injection
|
|
3
|
+
*/
|
|
4
|
+
export declare function generateSystemPrompt(projectPath: string): string;
|
|
5
|
+
/**
|
|
6
|
+
* Generate a compact status line for the prompt
|
|
7
|
+
*/
|
|
8
|
+
export declare function generateStatusLine(projectPath: string): string;
|
|
9
|
+
//# sourceMappingURL=system-prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../src/hooks/system-prompt.ts"],"names":[],"mappings":"AAiBA;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CA8DhE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAc9D"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { loadConfig, isSppInitialized } from "../config/loader.js";
|
|
2
|
+
import { calculateRatio, isRatioHealthy } from "../stats.js";
|
|
3
|
+
import { getEffectiveRatio, getCurrentMode } from "../config/schema.js";
|
|
4
|
+
import { getLineCounts } from "../git/history.js";
|
|
5
|
+
/**
|
|
6
|
+
* Calculate how many more commits/lines the human needs to reach the target ratio
|
|
7
|
+
*/
|
|
8
|
+
function calculateCatchUp(humanValue, claudeValue, targetRatio) {
|
|
9
|
+
const total = humanValue + claudeValue;
|
|
10
|
+
if (targetRatio >= 1) {
|
|
11
|
+
// 100% human target - can never catch up if Claude has written anything
|
|
12
|
+
return claudeValue;
|
|
13
|
+
}
|
|
14
|
+
return Math.ceil((targetRatio * total - humanValue) / (1 - targetRatio));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Generate the SPP system prompt injection
|
|
18
|
+
*/
|
|
19
|
+
export function generateSystemPrompt(projectPath) {
|
|
20
|
+
if (!isSppInitialized(projectPath)) {
|
|
21
|
+
return "";
|
|
22
|
+
}
|
|
23
|
+
const config = loadConfig(projectPath);
|
|
24
|
+
// If SPP is disabled, return empty
|
|
25
|
+
if (!config.enabled) {
|
|
26
|
+
return "";
|
|
27
|
+
}
|
|
28
|
+
const lineCounts = getLineCounts(projectPath);
|
|
29
|
+
const trackingMode = config.trackingMode ?? "commits";
|
|
30
|
+
const humanValue = trackingMode === "commits" ? lineCounts.humanCommits : lineCounts.humanLines;
|
|
31
|
+
const claudeValue = trackingMode === "commits" ? lineCounts.claudeCommits : lineCounts.claudeLines;
|
|
32
|
+
const unit = trackingMode === "commits" ? "commits" : "lines";
|
|
33
|
+
const currentRatio = calculateRatio(humanValue, claudeValue);
|
|
34
|
+
const targetRatio = getEffectiveRatio(config);
|
|
35
|
+
const isHealthy = isRatioHealthy(humanValue, claudeValue, targetRatio);
|
|
36
|
+
const currentMode = getCurrentMode(config);
|
|
37
|
+
const lines = [
|
|
38
|
+
"<spp>",
|
|
39
|
+
"# Simian Programmer Plugin Active",
|
|
40
|
+
"",
|
|
41
|
+
"You are operating in Simian Programmer mode. This mode helps the human maintain their programming skills",
|
|
42
|
+
"by ensuring they write a minimum percentage of the code themselves.",
|
|
43
|
+
"Help your human friend level up and stay sharp.",
|
|
44
|
+
"",
|
|
45
|
+
"## Current Status",
|
|
46
|
+
"",
|
|
47
|
+
`- **Mode:** ${currentMode.number}. ${currentMode.name} (${currentMode.description})`,
|
|
48
|
+
`- **Target ratio:** ${(targetRatio * 100).toFixed(0)}% human-written code`,
|
|
49
|
+
`- **Current ratio:** ${(currentRatio * 100).toFixed(0)}% human (${humanValue} ${unit}) / ${(100 - currentRatio * 100).toFixed(0)}% Claude (${claudeValue} ${unit})`,
|
|
50
|
+
`- **Status:** ${isHealthy ? "✅ Healthy" : "⚠️ Below target"}`,
|
|
51
|
+
"",
|
|
52
|
+
"A note on SPP tracking:",
|
|
53
|
+
"SPP tracks commits in git history, within a window and/or after a starting commit.",
|
|
54
|
+
"Commits that include 'Co-authored by: Claude...' in the message are counted as Claude commits.",
|
|
55
|
+
"Commits without that phrase are counted as human commits.",
|
|
56
|
+
"Therefore, if asked to commit human authored code, don't include the 'Co-authored by: Claude...' phrase",
|
|
57
|
+
"Also, if you write code, ask the user if they would like to commit it and DO include the 'Co-authored by: Claude' phrase",
|
|
58
|
+
"This way, SPP tracking will work properly",
|
|
59
|
+
];
|
|
60
|
+
// Add rules based on ratio health
|
|
61
|
+
if (!isHealthy) {
|
|
62
|
+
const needed = calculateCatchUp(humanValue, claudeValue, targetRatio);
|
|
63
|
+
lines.push("## ⚠️ NOTICE");
|
|
64
|
+
lines.push("");
|
|
65
|
+
lines.push("The human coding ratio is below the target.");
|
|
66
|
+
lines.push(`The human needs to write **${needed} more ${unit}** to get back to a healthy ratio.`);
|
|
67
|
+
lines.push("You will be hard blocked from writing code (except .md files).");
|
|
68
|
+
lines.push("Instead of writing code, use the spp-human-task skill to help the human complete the coding task.");
|
|
69
|
+
}
|
|
70
|
+
lines.push("</spp>");
|
|
71
|
+
return lines.join("\n");
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Generate a compact status line for the prompt
|
|
75
|
+
*/
|
|
76
|
+
export function generateStatusLine(projectPath) {
|
|
77
|
+
const config = loadConfig(projectPath);
|
|
78
|
+
if (!config.enabled) {
|
|
79
|
+
return "";
|
|
80
|
+
}
|
|
81
|
+
const lineCounts = getLineCounts(projectPath);
|
|
82
|
+
const currentRatio = calculateRatio(lineCounts.humanLines, lineCounts.claudeLines);
|
|
83
|
+
const targetRatio = getEffectiveRatio(config);
|
|
84
|
+
const isHealthy = isRatioHealthy(lineCounts.humanLines, lineCounts.claudeLines, targetRatio);
|
|
85
|
+
const status = isHealthy ? "✅" : "⚠️";
|
|
86
|
+
return `[SPP ${status} ${(currentRatio * 100).toFixed(0)}%/${(targetRatio * 100).toFixed(0)}% human]`;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=system-prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../../src/hooks/system-prompt.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { loadConfig, saveConfig, isSppInitialized, getSppDir } from "./config/loader.js";
|
|
2
|
+
export { ConfigSchema, DEFAULT_CONFIG, getEffectiveRatio, type Config, } from "./config/schema.js";
|
|
3
|
+
export { calculateRatio, isRatioHealthy, } from "./stats.js";
|
|
4
|
+
export { getLineCounts, clearCache, type LineCounts, } from "./git/history.js";
|
|
5
|
+
export { initializeSpp, isFullyInitialized, ensureInitialized } from "./init.js";
|
|
6
|
+
export { getStats, formatStats, type StatsResult } from "./stats.js";
|
|
7
|
+
export { generateSystemPrompt, generateStatusLine } from "./hooks/system-prompt.js";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACzF,OAAO,EACL,YAAY,EACZ,cAAc,EACd,iBAAiB,EACjB,KAAK,MAAM,GACZ,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,cAAc,EACd,cAAc,GACf,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,aAAa,EACb,UAAU,EACV,KAAK,UAAU,GAChB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAGjF,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAGrE,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Configuration
|
|
2
|
+
export { loadConfig, saveConfig, isSppInitialized, getSppDir } from "./config/loader.js";
|
|
3
|
+
export { ConfigSchema, DEFAULT_CONFIG, getEffectiveRatio, } from "./config/schema.js";
|
|
4
|
+
export { calculateRatio, isRatioHealthy, } from "./stats.js";
|
|
5
|
+
// Git History
|
|
6
|
+
export { getLineCounts, clearCache, } from "./git/history.js";
|
|
7
|
+
// Initialization
|
|
8
|
+
export { initializeSpp, isFullyInitialized, ensureInitialized } from "./init.js";
|
|
9
|
+
// Commands
|
|
10
|
+
export { getStats, formatStats } from "./stats.js";
|
|
11
|
+
// Hooks
|
|
12
|
+
export { generateSystemPrompt, generateStatusLine } from "./hooks/system-prompt.js";
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,gBAAgB;AAChB,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACzF,OAAO,EACL,YAAY,EACZ,cAAc,EACd,iBAAiB,GAElB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,cAAc,EACd,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB,cAAc;AACd,OAAO,EACL,aAAa,EACb,UAAU,GAEX,MAAM,kBAAkB,CAAC;AAE1B,iBAAiB;AACjB,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEjF,WAAW;AACX,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAoB,MAAM,YAAY,CAAC;AAErE,QAAQ;AACR,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC"}
|
package/dist/init.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type Config, type StatsWindow, type TrackingMode } from "./config/schema.js";
|
|
2
|
+
/**
|
|
3
|
+
* Install git post-commit hook for tracking human lines
|
|
4
|
+
* @throws Error if not in a git repository
|
|
5
|
+
*/
|
|
6
|
+
export declare function installGitHook(projectPath: string): void;
|
|
7
|
+
export declare function promptUser(prompt: string): Promise<string>;
|
|
8
|
+
/**
|
|
9
|
+
* Initialize SPP in a project
|
|
10
|
+
* Creates .claude-spp directory with config
|
|
11
|
+
* @param projectPath Path to the project
|
|
12
|
+
* @param modeNumber Optional mode number to skip the mode prompt
|
|
13
|
+
* @param statsWindow Optional stats window to skip the stats window prompt
|
|
14
|
+
* @param trackingMode Optional tracking mode to skip the tracking mode prompt
|
|
15
|
+
*/
|
|
16
|
+
export declare function initializeSpp(projectPath: string, modeNumber?: number, statsWindow?: StatsWindow, trackingMode?: TrackingMode): Promise<Config>;
|
|
17
|
+
/**
|
|
18
|
+
* Check if SPP is fully initialized
|
|
19
|
+
*/
|
|
20
|
+
export declare function isFullyInitialized(projectPath: string): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Ensure SPP is initialized, initializing if needed
|
|
23
|
+
*/
|
|
24
|
+
export declare function ensureInitialized(projectPath: string, modeNumber?: number, statsWindow?: StatsWindow, trackingMode?: TrackingMode): Promise<Config>;
|
|
25
|
+
//# sourceMappingURL=init.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,MAAM,EAKX,KAAK,WAAW,EAGhB,KAAK,YAAY,EAClB,MAAM,oBAAoB,CAAC;AAiE5B;;;GAGG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CA6CxD;AA+FD,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAYhE;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,WAAW,EACzB,YAAY,CAAC,EAAE,YAAY,GAC1B,OAAO,CAAC,MAAM,CAAC,CAyDjB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAE/D;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,WAAW,EACzB,YAAY,CAAC,EAAE,YAAY,GAC1B,OAAO,CAAC,MAAM,CAAC,CAKjB"}
|
package/dist/init.js
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import * as readline from "node:readline";
|
|
4
|
+
import { execSync } from "node:child_process";
|
|
5
|
+
import { loadConfig, saveConfig, isSppInitialized, getSppDir } from "./config/loader.js";
|
|
6
|
+
import { DEFAULT_CONFIG, MODES, STATS_WINDOW_LABELS, StatsWindowSchema, TRACKING_MODE_LABELS, TrackingModeSchema, } from "./config/schema.js";
|
|
7
|
+
import { getTotalCommitCount, getHeadCommitHash } from "./git/history.js";
|
|
8
|
+
/**
|
|
9
|
+
* Add an entry to .gitignore
|
|
10
|
+
* Creates .gitignore if it doesn't exist
|
|
11
|
+
*/
|
|
12
|
+
function addToGitignore(projectPath, entry) {
|
|
13
|
+
const gitignorePath = path.join(projectPath, ".gitignore");
|
|
14
|
+
if (!fs.existsSync(gitignorePath)) {
|
|
15
|
+
console.log("Creating .gitignore...");
|
|
16
|
+
fs.writeFileSync(gitignorePath, entry + "\n", "utf-8");
|
|
17
|
+
console.log(`Added "${entry}" to .gitignore`);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const content = fs.readFileSync(gitignorePath, "utf-8");
|
|
21
|
+
const lines = content.split("\n").map(line => line.trim());
|
|
22
|
+
if (lines.includes(entry)) {
|
|
23
|
+
console.log(`"${entry}" already in .gitignore`);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
console.log(`Adding "${entry}" to .gitignore...`);
|
|
27
|
+
const newContent = content.trimEnd() + "\n" + entry + "\n";
|
|
28
|
+
fs.writeFileSync(gitignorePath, newContent, "utf-8");
|
|
29
|
+
console.log(`Added "${entry}" to .gitignore`);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Check if we're in a git repository
|
|
33
|
+
*/
|
|
34
|
+
function isGitRepo(projectPath) {
|
|
35
|
+
try {
|
|
36
|
+
execSync("git rev-parse --git-dir", { cwd: projectPath, stdio: "ignore" });
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Check if the spp command is available globally
|
|
45
|
+
*/
|
|
46
|
+
function isSppCommandAvailable() {
|
|
47
|
+
try {
|
|
48
|
+
execSync("which spp", { stdio: "ignore" });
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Prompt user to install claude-spp globally
|
|
57
|
+
*/
|
|
58
|
+
function ensureGlobalInstall() {
|
|
59
|
+
if (!isSppCommandAvailable()) {
|
|
60
|
+
const packageName = "git+https://github.com/mlolson/claude-spp.git";
|
|
61
|
+
throw new Error(`spp command not found. Please install:\n npm install -g ${packageName}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Install git post-commit hook for tracking human lines
|
|
66
|
+
* @throws Error if not in a git repository
|
|
67
|
+
*/
|
|
68
|
+
export function installGitHook(projectPath) {
|
|
69
|
+
// Verify this is a git repo
|
|
70
|
+
if (!isGitRepo(projectPath)) {
|
|
71
|
+
throw new Error("Not a git repository. Initialize git first with: git init");
|
|
72
|
+
}
|
|
73
|
+
const gitHooksDir = path.join(projectPath, ".git", "hooks");
|
|
74
|
+
const hookPath = path.join(gitHooksDir, "post-commit");
|
|
75
|
+
const sourceHook = path.join(projectPath, "src", "git", "hooks", "post-commit");
|
|
76
|
+
// Check if source hook exists
|
|
77
|
+
if (!fs.existsSync(sourceHook)) {
|
|
78
|
+
throw new Error(`Source hook not found at: ${sourceHook}`);
|
|
79
|
+
}
|
|
80
|
+
// Ensure hooks directory exists
|
|
81
|
+
if (!fs.existsSync(gitHooksDir)) {
|
|
82
|
+
fs.mkdirSync(gitHooksDir, { recursive: true });
|
|
83
|
+
}
|
|
84
|
+
// Read source hook content
|
|
85
|
+
const sourceContent = fs.readFileSync(sourceHook, "utf-8");
|
|
86
|
+
const sourceContentWithShebang = "#!/bin/bash\n" + sourceContent;
|
|
87
|
+
// Check if hook already contains our content
|
|
88
|
+
if (fs.existsSync(hookPath)) {
|
|
89
|
+
const existingContent = fs.readFileSync(hookPath, "utf-8");
|
|
90
|
+
if (existingContent.includes("# <SPP>")) {
|
|
91
|
+
fs.writeFileSync(hookPath, existingContent.replace(/# <SPP>[\s\S]*?# <\/SPP>/g, sourceContent));
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
if (existingContent.trim() === "") {
|
|
95
|
+
// Hook exists but is empty - write full contents
|
|
96
|
+
fs.writeFileSync(hookPath, sourceContentWithShebang);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
// Hook exists and is not empty - append without shebang
|
|
100
|
+
const newContent = existingContent.trimEnd() + "\n\n" + sourceContent;
|
|
101
|
+
fs.writeFileSync(hookPath, newContent);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
fs.writeFileSync(hookPath, sourceContentWithShebang);
|
|
107
|
+
}
|
|
108
|
+
// Ensure the file is executable
|
|
109
|
+
fs.chmodSync(hookPath, 0o755);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Prompt user to select a mode interactively
|
|
113
|
+
*/
|
|
114
|
+
async function promptForMode() {
|
|
115
|
+
console.log("\nAvailable modes:\n");
|
|
116
|
+
const maxNameLen = Math.max(...MODES.map(m => m.name.length));
|
|
117
|
+
for (const mode of MODES) {
|
|
118
|
+
const paddedName = mode.name.padEnd(maxNameLen);
|
|
119
|
+
const defaultMarker = mode.number === 4 ? " (default)" : "";
|
|
120
|
+
console.log(` ${mode.number}. ${paddedName} ${mode.description}${defaultMarker}`);
|
|
121
|
+
}
|
|
122
|
+
console.log("");
|
|
123
|
+
let modeNumber = undefined;
|
|
124
|
+
while (modeNumber === undefined) {
|
|
125
|
+
const userResponse = await promptUser(`Select a mode [1-${MODES.length}, or press Enter for ${MODES[DEFAULT_CONFIG.mode - 1].description}]: `);
|
|
126
|
+
if (userResponse === "") {
|
|
127
|
+
modeNumber = DEFAULT_CONFIG.mode;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
modeNumber = parseInt(userResponse, 10);
|
|
131
|
+
if (modeNumber < 1 || modeNumber > MODES.length) {
|
|
132
|
+
console.log(`Invalid mode: ${modeNumber}. Must be in range [1, ${MODES.length}]`);
|
|
133
|
+
modeNumber = undefined;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return modeNumber;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Prompt user to select a stats window interactively
|
|
141
|
+
*/
|
|
142
|
+
async function promptForStatsWindow() {
|
|
143
|
+
const options = StatsWindowSchema.options;
|
|
144
|
+
console.log("\nStats window (time period for tracking commits):\n");
|
|
145
|
+
options.forEach((option, index) => {
|
|
146
|
+
const label = STATS_WINDOW_LABELS[option];
|
|
147
|
+
const defaultMarker = option === "oneWeek" ? " (default)" : "";
|
|
148
|
+
console.log(` ${index + 1}. ${label}${defaultMarker}`);
|
|
149
|
+
});
|
|
150
|
+
console.log("");
|
|
151
|
+
while (true) {
|
|
152
|
+
const userResponse = await promptUser(`Select a stats window [1-${options.length}, or press Enter for Last 7 days]: `);
|
|
153
|
+
if (userResponse === "") {
|
|
154
|
+
return "oneWeek";
|
|
155
|
+
}
|
|
156
|
+
const choice = parseInt(userResponse, 10);
|
|
157
|
+
if (choice >= 1 && choice <= options.length) {
|
|
158
|
+
return options[choice - 1];
|
|
159
|
+
}
|
|
160
|
+
console.log(`Invalid choice: ${userResponse}. Must be in range [1, ${options.length}]`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Prompt user to select a tracking mode interactively
|
|
165
|
+
*/
|
|
166
|
+
async function promptForTrackingMode() {
|
|
167
|
+
const options = TrackingModeSchema.options;
|
|
168
|
+
console.log("\nTracking mode (what to count for ratio calculation):\n");
|
|
169
|
+
options.forEach((option, index) => {
|
|
170
|
+
const label = TRACKING_MODE_LABELS[option];
|
|
171
|
+
const defaultMarker = option === "commits" ? " (default)" : "";
|
|
172
|
+
console.log(` ${index + 1}. ${label}${defaultMarker}`);
|
|
173
|
+
});
|
|
174
|
+
console.log("");
|
|
175
|
+
while (true) {
|
|
176
|
+
const userResponse = await promptUser(`Select a tracking mode [1-${options.length}, or press Enter for Commits]: `);
|
|
177
|
+
if (userResponse === "") {
|
|
178
|
+
return "commits";
|
|
179
|
+
}
|
|
180
|
+
const choice = parseInt(userResponse, 10);
|
|
181
|
+
if (choice >= 1 && choice <= options.length) {
|
|
182
|
+
return options[choice - 1];
|
|
183
|
+
}
|
|
184
|
+
console.log(`Invalid choice: ${userResponse}. Must be in range [1, ${options.length}]`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
async function promptShouldOverwriteInstall() {
|
|
188
|
+
const answer = await promptUser("An SPP installation already exists. Overwrite it? N/Y\n");
|
|
189
|
+
return answer.toLowerCase() === "y";
|
|
190
|
+
}
|
|
191
|
+
export async function promptUser(prompt) {
|
|
192
|
+
const rl = readline.createInterface({
|
|
193
|
+
input: process.stdin,
|
|
194
|
+
output: process.stdout,
|
|
195
|
+
});
|
|
196
|
+
return new Promise((resolve) => {
|
|
197
|
+
rl.question(prompt, (answer) => {
|
|
198
|
+
rl.close();
|
|
199
|
+
resolve(answer.trim());
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Initialize SPP in a project
|
|
205
|
+
* Creates .claude-spp directory with config
|
|
206
|
+
* @param projectPath Path to the project
|
|
207
|
+
* @param modeNumber Optional mode number to skip the mode prompt
|
|
208
|
+
* @param statsWindow Optional stats window to skip the stats window prompt
|
|
209
|
+
* @param trackingMode Optional tracking mode to skip the tracking mode prompt
|
|
210
|
+
*/
|
|
211
|
+
export async function initializeSpp(projectPath, modeNumber, statsWindow, trackingMode) {
|
|
212
|
+
// Ensure spp command is installed globally (required for hooks)
|
|
213
|
+
await ensureGlobalInstall();
|
|
214
|
+
const sppDir = getSppDir(projectPath);
|
|
215
|
+
// Create .claude-spp directory if it doesn't exist
|
|
216
|
+
if (fs.existsSync(sppDir)) {
|
|
217
|
+
if (await promptShouldOverwriteInstall()) {
|
|
218
|
+
console.log("Removing existing install...");
|
|
219
|
+
fs.rmSync(sppDir, { recursive: true, force: true });
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
console.log("Aborting install...");
|
|
223
|
+
return await loadConfig(projectPath);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
fs.mkdirSync(sppDir, { recursive: true });
|
|
227
|
+
// Prompt for mode if not provided
|
|
228
|
+
const selectedMode = modeNumber ?? await promptForMode();
|
|
229
|
+
if (selectedMode < 1 || selectedMode > MODES.length) {
|
|
230
|
+
throw new Error(`Invalid mode: ${selectedMode}. Must be in range [1, ${MODES.length}]`);
|
|
231
|
+
}
|
|
232
|
+
// Prompt for tracking mode if not provided
|
|
233
|
+
const selectedTrackingMode = trackingMode ?? await promptForTrackingMode();
|
|
234
|
+
// Prompt for stats window if not provided
|
|
235
|
+
const selectedStatsWindow = statsWindow ?? await promptForStatsWindow();
|
|
236
|
+
// Initialize config
|
|
237
|
+
const config = {
|
|
238
|
+
...DEFAULT_CONFIG,
|
|
239
|
+
mode: selectedMode,
|
|
240
|
+
trackingMode: selectedTrackingMode,
|
|
241
|
+
statsWindow: selectedStatsWindow,
|
|
242
|
+
};
|
|
243
|
+
// For pre-existing repos with commits, set trackingStartCommit to HEAD
|
|
244
|
+
// This gives them a clean slate - only new commits after init will be tracked
|
|
245
|
+
const totalCommits = getTotalCommitCount(projectPath);
|
|
246
|
+
if (totalCommits > 0) {
|
|
247
|
+
const headCommit = getHeadCommitHash(projectPath);
|
|
248
|
+
if (headCommit) {
|
|
249
|
+
config.trackingStartCommit = headCommit;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
saveConfig(projectPath, config);
|
|
253
|
+
// Update .gitignore to exclude SPP files
|
|
254
|
+
addToGitignore(projectPath, ".claude-spp/");
|
|
255
|
+
// Install git post-commit hook
|
|
256
|
+
installGitHook(projectPath);
|
|
257
|
+
return config;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Check if SPP is fully initialized
|
|
261
|
+
*/
|
|
262
|
+
export function isFullyInitialized(projectPath) {
|
|
263
|
+
return isSppInitialized(projectPath);
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Ensure SPP is initialized, initializing if needed
|
|
267
|
+
*/
|
|
268
|
+
export async function ensureInitialized(projectPath, modeNumber, statsWindow, trackingMode) {
|
|
269
|
+
if (!isFullyInitialized(projectPath)) {
|
|
270
|
+
return initializeSpp(projectPath, modeNumber, statsWindow, trackingMode);
|
|
271
|
+
}
|
|
272
|
+
return loadConfig(projectPath);
|
|
273
|
+
}
|
|
274
|
+
//# sourceMappingURL=init.js.map
|
package/dist/init.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
|
package/dist/stats.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type Mode, type StatsWindow, type TrackingMode } from "./config/schema.js";
|
|
2
|
+
/**
|
|
3
|
+
* Calculate the current human work ratio from line counts
|
|
4
|
+
* Returns 1.0 if no work has been done yet (human is at 100% until Claude does something)
|
|
5
|
+
*/
|
|
6
|
+
export declare function calculateRatio(humanLines: number, claudeLines: number): number;
|
|
7
|
+
/**
|
|
8
|
+
* Check if the human work ratio meets the target
|
|
9
|
+
*/
|
|
10
|
+
export declare function isRatioHealthy(humanLines: number, claudeLines: number, targetRatio: number): boolean;
|
|
11
|
+
export interface StatsResult {
|
|
12
|
+
initialized: boolean;
|
|
13
|
+
enabled?: boolean;
|
|
14
|
+
mode?: Mode;
|
|
15
|
+
targetRatio?: number;
|
|
16
|
+
currentRatio?: number;
|
|
17
|
+
ratioHealthy?: boolean;
|
|
18
|
+
statsWindow?: StatsWindow;
|
|
19
|
+
trackingMode?: TrackingMode;
|
|
20
|
+
lines?: {
|
|
21
|
+
humanLines: number;
|
|
22
|
+
claudeLines: number;
|
|
23
|
+
humanCommits: number;
|
|
24
|
+
claudeCommits: number;
|
|
25
|
+
fromCache: boolean;
|
|
26
|
+
commitsScanned: number;
|
|
27
|
+
};
|
|
28
|
+
session?: {
|
|
29
|
+
startedAt: string;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Get current SPP statistics
|
|
34
|
+
*/
|
|
35
|
+
export declare function getStats(projectPath: string): StatsResult;
|
|
36
|
+
/**
|
|
37
|
+
* Format stats for display
|
|
38
|
+
*/
|
|
39
|
+
export declare function formatStats(stats: StatsResult): string;
|
|
40
|
+
//# sourceMappingURL=stats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../src/stats.ts"],"names":[],"mappings":"AACA,OAAO,EAML,KAAK,IAAI,EACT,KAAK,WAAW,EAChB,KAAK,YAAY,EAClB,MAAM,oBAAoB,CAAC;AAG5B;;;GAGG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAM9E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAEpG;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,KAAK,CAAC,EAAE;QACN,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;QACtB,SAAS,EAAE,OAAO,CAAC;QACnB,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,OAAO,CAAC,EAAE;QACR,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,CAoCzD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CA4FtD"}
|