@rachel_rotenberg/ai-contribution-tracker 1.0.20 → 1.0.21
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/cli.js +18 -29
- package/index.ts +1 -0
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -19,7 +19,8 @@ const { execSync, execFileSync } = require("child_process");
|
|
|
19
19
|
|
|
20
20
|
// ─── Constants ──────────────────────────────────────────────
|
|
21
21
|
const PLUGIN_NAME = "@rachel_rotenberg/ai-contribution-tracker";
|
|
22
|
-
const
|
|
22
|
+
const HOOK_BEGIN = "# BEGIN ai-contribution-tracker-cli";
|
|
23
|
+
const HOOK_END = "# END ai-contribution-tracker-cli";
|
|
23
24
|
|
|
24
25
|
// ─── Logging helpers ────────────────────────────────────────
|
|
25
26
|
function ok(msg) { console.log(` \u2713 ${msg}`); }
|
|
@@ -29,20 +30,22 @@ function fail(msg) { console.error(` \u2717 ${msg}`); }
|
|
|
29
30
|
|
|
30
31
|
// ─── Git hook body (shell script, runs on all platforms via Git Bash) ───
|
|
31
32
|
const HOOK_BODY = [
|
|
32
|
-
"",
|
|
33
|
-
"# AI Contribution Tracker \u2014 reads AI_IMPACT_PENDING flag",
|
|
33
|
+
"# BEGIN ai-contribution-tracker-cli",
|
|
34
34
|
'IMPACT_FLAG=$(git rev-parse --git-path AI_IMPACT_PENDING)',
|
|
35
35
|
'STATE_FILE=$(git rev-parse --git-path ai-tracker-state.json)',
|
|
36
36
|
'if [ -f "$IMPACT_FLAG" ]; then',
|
|
37
37
|
' MARKER=$(cat "$IMPACT_FLAG")',
|
|
38
38
|
' if [ -z "$MARKER" ]; then MARKER="Impacted by AI"; fi',
|
|
39
|
-
'
|
|
39
|
+
' FIRST_LINE=$(head -n 1 "$IMPACT_FLAG")',
|
|
40
|
+
' if ! grep -qF "$FIRST_LINE" "$1"; then',
|
|
41
|
+
' if [ -s "$1" ] && [ "$(tail -c 1 "$1" | wc -l)" -eq 0 ]; then printf "\\n" >> "$1"; fi',
|
|
40
42
|
' echo "" >> "$1"',
|
|
41
43
|
' echo "$MARKER" >> "$1"',
|
|
42
44
|
' fi',
|
|
43
45
|
' rm "$IMPACT_FLAG"',
|
|
44
46
|
'fi',
|
|
45
47
|
'if [ -f "$STATE_FILE" ]; then rm "$STATE_FILE"; fi',
|
|
48
|
+
"# END ai-contribution-tracker-cli",
|
|
46
49
|
].join("\n");
|
|
47
50
|
|
|
48
51
|
// ─── Git hook installation ──────────────────────────────────
|
|
@@ -53,7 +56,7 @@ function appendOrCreateHook(hooksDir) {
|
|
|
53
56
|
|
|
54
57
|
if (fs.existsSync(hookPath)) {
|
|
55
58
|
const existing = fs.readFileSync(hookPath, "utf8");
|
|
56
|
-
if (existing.includes(
|
|
59
|
+
if (existing.includes(HOOK_BEGIN)) {
|
|
57
60
|
skip(`commit-msg hook already has AI tracker snippet: ${hookPath}`);
|
|
58
61
|
return;
|
|
59
62
|
}
|
|
@@ -133,7 +136,7 @@ function addPluginToConfig(configDir) {
|
|
|
133
136
|
|
|
134
137
|
// Check if already registered (plain string or [name, options] tuple)
|
|
135
138
|
const alreadyRegistered = plugins.some(
|
|
136
|
-
(p) => (typeof p === "string" ? p : p[0]) === PLUGIN_NAME
|
|
139
|
+
(p) => p && (typeof p === "string" ? p : Array.isArray(p) ? p[0] : null) === PLUGIN_NAME
|
|
137
140
|
);
|
|
138
141
|
|
|
139
142
|
if (alreadyRegistered) {
|
|
@@ -172,7 +175,7 @@ function showStatus() {
|
|
|
172
175
|
|
|
173
176
|
if (hooksPath) {
|
|
174
177
|
const hookFile = path.join(hooksPath, "commit-msg");
|
|
175
|
-
if (fs.existsSync(hookFile) && fs.readFileSync(hookFile, "utf8").includes(
|
|
178
|
+
if (fs.existsSync(hookFile) && fs.readFileSync(hookFile, "utf8").includes(HOOK_BEGIN)) {
|
|
176
179
|
ok(`Git hook installed: ${hookFile}`);
|
|
177
180
|
} else {
|
|
178
181
|
warn(`core.hooksPath set to ${hooksPath} but no AI tracker snippet found`);
|
|
@@ -188,7 +191,7 @@ function showStatus() {
|
|
|
188
191
|
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
189
192
|
const plugins = Array.isArray(config.plugin) ? config.plugin : [];
|
|
190
193
|
const found = plugins.some(
|
|
191
|
-
(p) => (typeof p === "string" ? p : p[0]) === PLUGIN_NAME
|
|
194
|
+
(p) => p && (typeof p === "string" ? p : Array.isArray(p) ? p[0] : null) === PLUGIN_NAME
|
|
192
195
|
);
|
|
193
196
|
if (found) {
|
|
194
197
|
ok(`OpenCode plugin registered: ${configPath}`);
|
|
@@ -228,8 +231,8 @@ function removeGitHook() {
|
|
|
228
231
|
}
|
|
229
232
|
|
|
230
233
|
const content = fs.readFileSync(hookFile, "utf8");
|
|
231
|
-
if (!content.includes(
|
|
232
|
-
skip("commit-msg hook does not contain AI tracker snippet");
|
|
234
|
+
if (!content.includes(HOOK_BEGIN)) {
|
|
235
|
+
skip("commit-msg hook does not contain AI tracker CLI snippet");
|
|
233
236
|
return;
|
|
234
237
|
}
|
|
235
238
|
|
|
@@ -237,24 +240,10 @@ function removeGitHook() {
|
|
|
237
240
|
const filtered = [];
|
|
238
241
|
let skipping = false;
|
|
239
242
|
|
|
240
|
-
for (
|
|
241
|
-
if (
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
245
|
-
if (skipping) {
|
|
246
|
-
if (lines[i].includes('rm "$STATE_FILE"')) {
|
|
247
|
-
// consume the closing `fi` on the next non-empty line, then stop skipping
|
|
248
|
-
for (let j = i + 1; j < lines.length; j++) {
|
|
249
|
-
if (lines[j].trim() === "fi") { i = j; break; }
|
|
250
|
-
if (lines[j].trim() !== "") { i = j - 1; break; }
|
|
251
|
-
}
|
|
252
|
-
skipping = false;
|
|
253
|
-
continue;
|
|
254
|
-
}
|
|
255
|
-
continue;
|
|
256
|
-
}
|
|
257
|
-
filtered.push(lines[i]);
|
|
243
|
+
for (const line of lines) {
|
|
244
|
+
if (line.includes(HOOK_BEGIN)) { skipping = true; continue; }
|
|
245
|
+
if (line.includes(HOOK_END)) { skipping = false; continue; }
|
|
246
|
+
if (!skipping) filtered.push(line);
|
|
258
247
|
}
|
|
259
248
|
|
|
260
249
|
const remaining = filtered.join("\n").trim();
|
|
@@ -298,7 +287,7 @@ function removeOpenCodePlugin() {
|
|
|
298
287
|
|
|
299
288
|
const before = config.plugin.length;
|
|
300
289
|
config.plugin = config.plugin.filter(
|
|
301
|
-
(p) => (typeof p === "string" ? p : p[0]) !== PLUGIN_NAME
|
|
290
|
+
(p) => !p || (typeof p === "string" ? p : Array.isArray(p) ? p[0] : null) !== PLUGIN_NAME
|
|
302
291
|
);
|
|
303
292
|
|
|
304
293
|
if (config.plugin.length === before) {
|
package/index.ts
CHANGED
package/package.json
CHANGED