@rachel_rotenberg/ai-contribution-tracker 1.0.13 → 1.0.15

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 +21 -19
  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();
@@ -60,7 +60,7 @@ function loadState(g: string): TrackerState {
60
60
  }
61
61
  function saveState(g: string, s: TrackerState) { s.lastUpdated = new Date().toISOString(); fs.writeFileSync(getStatePath(g), JSON.stringify(s, null, 2)); }
62
62
  function formatK(n: number) { return n >= 1000 ? `${Math.round(n / 1000)}k` : String(n); }
63
- function formatMarker(s: TrackerState): string {
63
+ function buildMarkerParts(s: TrackerState): string[] {
64
64
  const p: string[] = [];
65
65
  const ma = [...new Set(s.mainAgentTypes)]; if (ma.length) p.push(`Agent mode: ${ma.join(", ")}`);
66
66
  if (s.models.length) p.push(`Model: ${s.models.join(", ")}`);
@@ -74,23 +74,26 @@ 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
+ return p;
78
+ }
79
+ function buildCoAuthoredBy(s: TrackerState): string {
80
+ const models = s.models.join(", ");
81
+ const coAuthorName = models || s.promptCount > 0
82
+ ? `OpenCode (${[models, s.promptCount > 0 ? `${s.promptCount}p` : ""].filter(Boolean).join(", ")})`
83
+ : "OpenCode";
84
+ return `Co-authored-by: ${coAuthorName} <noreply@opencode.dev>`;
85
+ }
86
+ function formatMarker(s: TrackerState, prefix?: string): string {
87
+ const parts = buildMarkerParts(s);
88
+ if (prefix) parts.unshift(prefix);
89
+ const marker = parts.length ? `Impacted by AI (${parts.join(" | ")})` : "Impacted by AI";
90
+ return `${marker}\n${buildCoAuthoredBy(s)}`;
78
91
  }
79
92
  function writeFlag(g: string, s: TrackerState) {
80
93
  if (s.promptCount === 0 && s.mainAgentTypes.length === 0 && s.subagentTypes.length === 0 && s.subagentCount === 0 && Object.keys(s.tokensByModel).length === 0) return;
81
- const fp = getFlagPath(g), marker = formatMarker(s);
82
- if (fs.existsSync(fp)) {
83
- const ex = fs.readFileSync(fp, "utf8").trim();
84
- if (ex.includes("Inline")) {
85
- // Merge: preserve Inline marker, add agent data
86
- const inner = marker.match(/\((.+)\)$/)?.[1];
87
- const merged = inner ? `Impacted by AI (Inline + ${inner})` : "Impacted by AI (Inline)";
88
- fs.writeFileSync(fp, merged.replace(/[^\x20-\x7E\n]/g, ""));
89
- return;
90
- }
91
- // Always overwrite with latest state — state only grows, never shrinks
92
- }
93
- fs.writeFileSync(fp, marker.replace(/[^\x20-\x7E\n]/g, ""));
94
+ const fp = getFlagPath(g);
95
+ const isInline = fs.existsSync(fp) && fs.readFileSync(fp, "utf8").includes("Inline");
96
+ fs.writeFileSync(fp, formatMarker(s, isInline ? "Inline" : undefined));
94
97
  }
95
98
 
96
99
  // ─── Plugin ─────────────────────────────────────────────────
@@ -106,7 +109,7 @@ function appendOrCreateHook(hooksDir: string) {
106
109
  'if [ -f "$IMPACT_FLAG" ]; then',
107
110
  ' MARKER=$(cat "$IMPACT_FLAG")',
108
111
  ' if [ -z "$MARKER" ]; then MARKER="Impacted by AI"; fi',
109
- ' if ! grep -qF "$MARKER" "$1"; then',
112
+ ' if ! grep -qF "Impacted by AI" "$1"; then',
110
113
  ' echo "" >> "$1"',
111
114
  ' echo "$MARKER" >> "$1"',
112
115
  ' fi',
@@ -153,8 +156,7 @@ function extractSessionId(event: any): string | null {
153
156
  }
154
157
 
155
158
  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();
159
+ return name.trim();
158
160
  }
159
161
 
160
162
  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.15",
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",