@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.
Files changed (3) hide show
  1. package/cli.js +18 -29
  2. package/index.ts +1 -0
  3. 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 HOOK_MARKER = "AI_IMPACT_PENDING";
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
- ' if ! grep -qF "$MARKER" "$1"; then',
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(HOOK_MARKER)) {
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(HOOK_MARKER)) {
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(HOOK_MARKER)) {
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 (let i = 0; i < lines.length; i++) {
241
- if (lines[i].includes("AI Contribution Tracker")) {
242
- skipping = true;
243
- continue;
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
@@ -306,3 +306,4 @@ const AIContributionTracker: Plugin = async ({ directory, worktree }) => {
306
306
  };
307
307
  export default AIContributionTracker;
308
308
  // Named exports omitted — OpenCode calls all exported functions as plugins
309
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rachel_rotenberg/ai-contribution-tracker",
3
- "version": "1.0.20",
3
+ "version": "1.0.21",
4
4
  "description": "OpenCode plugin — tracks AI coding sessions and tags git commits with Impacted by AI markers",
5
5
  "main": "index.ts",
6
6
  "types": "index.ts",