@rachel_rotenberg/ai-contribution-tracker 1.0.13 → 1.0.14

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 (2) hide show
  1. package/index.ts +14 -6
  2. package/package.json +1 -1
package/index.ts CHANGED
@@ -48,7 +48,7 @@ function loadState(g: string): TrackerState {
48
48
  const p = getStatePath(g);
49
49
  if (fs.existsSync(p)) { try {
50
50
  const s = JSON.parse(fs.readFileSync(p, "utf8")) as TrackerState;
51
- s.mainAgentTypes = (s.mainAgentTypes ?? []).map((a: string) => a.replace(/[\p{Cf}]/gu, "")); s.subagentTypes ??= []; s.models ??= []; s.subagentModels ??= []; s.tokensByModel ??= {};
51
+ s.mainAgentTypes ??= []; s.subagentTypes ??= []; s.models ??= []; s.subagentModels ??= []; s.tokensByModel ??= {};
52
52
  if (typeof s.subagentCount !== "number") s.subagentCount = 0;
53
53
  if (typeof s.activeSubagents !== "number") s.activeSubagents = 0;
54
54
  if (typeof s.stateCreatedAt !== "string") s.stateCreatedAt = s.lastUpdated || new Date().toISOString();
@@ -74,7 +74,16 @@ function formatMarker(s: TrackerState): string {
74
74
  if (t.reasoningTokens > 0) r += ` +${formatK(t.reasoningTokens)} reasoning`;
75
75
  return r;
76
76
  }).join(" | ")}`); }
77
- return p.length ? `Impacted by AI (${p.join(" | ")})` : "Impacted by AI";
77
+ const marker = p.length ? `Impacted by AI (${p.join(" | ")})` : "Impacted by AI";
78
+ // Append Co-authored-by trailer — GitHub preserves these through squash merges,
79
+ // so AI attribution survives even when the source branch is deleted after merge.
80
+ // Essential metadata (model, prompts) is encoded in the name field as a fallback
81
+ // when the full "Impacted by AI" body text is lost in squash merge.
82
+ const models = s.models.join(", ");
83
+ const coAuthorName = models || s.promptCount > 0
84
+ ? `OpenCode (${[models, s.promptCount > 0 ? `${s.promptCount}p` : ""].filter(Boolean).join(", ")})`
85
+ : "OpenCode";
86
+ return `${marker}\nCo-authored-by: ${coAuthorName} <noreply@opencode.dev>`;
78
87
  }
79
88
  function writeFlag(g: string, s: TrackerState) {
80
89
  if (s.promptCount === 0 && s.mainAgentTypes.length === 0 && s.subagentTypes.length === 0 && s.subagentCount === 0 && Object.keys(s.tokensByModel).length === 0) return;
@@ -85,12 +94,12 @@ function writeFlag(g: string, s: TrackerState) {
85
94
  // Merge: preserve Inline marker, add agent data
86
95
  const inner = marker.match(/\((.+)\)$/)?.[1];
87
96
  const merged = inner ? `Impacted by AI (Inline + ${inner})` : "Impacted by AI (Inline)";
88
- fs.writeFileSync(fp, merged.replace(/[^\x20-\x7E\n]/g, ""));
97
+ fs.writeFileSync(fp, merged);
89
98
  return;
90
99
  }
91
100
  // Always overwrite with latest state — state only grows, never shrinks
92
101
  }
93
- fs.writeFileSync(fp, marker.replace(/[^\x20-\x7E\n]/g, ""));
102
+ fs.writeFileSync(fp, marker);
94
103
  }
95
104
 
96
105
  // ─── Plugin ─────────────────────────────────────────────────
@@ -153,8 +162,7 @@ function extractSessionId(event: any): string | null {
153
162
  }
154
163
 
155
164
  function sanitizeAgentName(name: string): string {
156
- // Strip zero-width and other invisible Unicode characters that break dashboard parsing
157
- return name.replace(/[\p{Cf}]/gu, "").trim();
165
+ return name.trim();
158
166
  }
159
167
 
160
168
  function getOrCreateSession(sid: string, agent?: string): SessionState {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rachel_rotenberg/ai-contribution-tracker",
3
- "version": "1.0.13",
3
+ "version": "1.0.14",
4
4
  "description": "OpenCode plugin \u2014 tracks AI coding sessions and tags git commits with Impacted by AI markers",
5
5
  "main": "index.ts",
6
6
  "types": "index.ts",