sigmap 7.0.0 → 7.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/llms-full.txt CHANGED
@@ -9,7 +9,7 @@ the files relevant to the task — cutting tokens ~97% while keeping answers
9
9
  grounded. Deterministic, offline, no embeddings or vector database. Works with
10
10
  Claude, Cursor, GitHub Copilot, Aider, Windsurf, local LLMs, and MCP.
11
11
 
12
- # Version: 7.0.0 | Benchmark: sigmap-v7.0-main (2026-06-14)
12
+ # Version: 7.1.0 | Benchmark: sigmap-v7.0-main (2026-06-14)
13
13
  # Source: auto-generated from package.json, version.json, src/mcp/tools.js, src/config/defaults.js
14
14
  # Regenerate: npm run generate:llms | Validate: npm run validate:llms
15
15
 
@@ -67,6 +67,13 @@ sigmap --suggest-tool "<task>" Recommend model tier for a task descrip
67
67
  sigmap --suggest-tool "<task>" --json Machine-readable tier recommendation
68
68
  sigmap --health Print composite health score
69
69
  sigmap --health --json Machine-readable health score
70
+ sigmap gain Token-savings dashboard (totals + by-operation)
71
+ sigmap gain --all Add daily / weekly / monthly trend tables
72
+ sigmap gain --json Aggregate savings as JSON
73
+ sigmap gain --since 7d Window filter (7d, 30d, 12h, or ISO date)
74
+ sigmap gain --top <n> | --model <name> Limit rows / set $ pricing model
75
+ sigmap gain --reset Clear the local savings log (.context/gain.ndjson)
76
+ sigmap ... --no-track Disable gain savings capture for this run
70
77
  sigmap --diff Generate context for git-changed files only
71
78
  sigmap --diff <base-ref> Generate context + structural diff vs base ref (e.g. main)
72
79
  sigmap --diff --staged Generate context for staged files only
@@ -273,7 +280,7 @@ the relevant regulation before publication; SigMap makes no legal claims.
273
280
  - Author: Manoj Mallick
274
281
  - License: MIT
275
282
  - Repository: https://github.com/manojmallick/sigmap
276
- - Documentation: https://manojmallick.github.io/sigmap/
283
+ - Documentation: https://sigmap.io/
277
284
  - npm: https://www.npmjs.com/package/sigmap
278
285
  - Benchmark dataset: https://doi.org/10.5281/zenodo.19898842
279
286
  - Issues: https://github.com/manojmallick/sigmap/issues
package/llms.txt CHANGED
@@ -9,7 +9,7 @@ the files relevant to the task — cutting tokens ~97% while keeping answers
9
9
  grounded. Deterministic, offline, no embeddings or vector database. Works with
10
10
  Claude, Cursor, GitHub Copilot, Aider, Windsurf, local LLMs, and MCP.
11
11
 
12
- # Version: 7.0.0 | Benchmark: sigmap-v7.0-main (2026-06-14)
12
+ # Version: 7.1.0 | Benchmark: sigmap-v7.0-main (2026-06-14)
13
13
  # Source: auto-generated from package.json, version.json, src/mcp/tools.js, src/config/defaults.js
14
14
  # Regenerate: npm run generate:llms | Validate: npm run validate:llms
15
15
 
@@ -39,18 +39,18 @@ npx sigmap --mcp # start the MCP server over stdio
39
39
  ```
40
40
 
41
41
  ## Docs
42
- - [Full documentation](https://manojmallick.github.io/sigmap/)
43
- - [CLI reference](https://manojmallick.github.io/sigmap/guide/cli)
44
- - [MCP tools](https://manojmallick.github.io/sigmap/guide/mcp)
45
- - [Benchmark methodology](https://manojmallick.github.io/sigmap/guide/benchmark)
46
- - [Configuration guide](https://manojmallick.github.io/sigmap/guide/config)
42
+ - [Full documentation](https://sigmap.io/)
43
+ - [CLI reference](https://sigmap.io/guide/cli)
44
+ - [MCP tools](https://sigmap.io/guide/mcp)
45
+ - [Benchmark methodology](https://sigmap.io/guide/benchmark)
46
+ - [Configuration guide](https://sigmap.io/guide/config)
47
47
  - [Changelog](https://github.com/manojmallick/sigmap/blob/main/CHANGELOG.md)
48
48
 
49
49
  ## Optional
50
50
  - [GitHub repository](https://github.com/manojmallick/sigmap)
51
51
  - [npm package](https://www.npmjs.com/package/sigmap)
52
52
  - [Benchmark dataset (Zenodo)](https://doi.org/10.5281/zenodo.19898842)
53
- - [Full LLM reference](https://manojmallick.github.io/sigmap/llms-full.txt)
53
+ - [Full LLM reference](https://sigmap.io/llms-full.txt)
54
54
 
55
55
  SigMap — grounded AI coding context. The lightweight, deterministic alternative
56
56
  to embeddings for feeding the right code to AI assistants.
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "sigmap",
3
- "version": "7.0.0",
3
+ "version": "7.1.0",
4
4
  "description": "97% token reduction for AI coding. Extracts function & class signatures with TF-IDF ranking to feed only the right files to Claude, Cursor, Copilot, Aider, Windsurf, local LLMs & MCP. Zero dependencies, runs offline via npx.",
5
- "main": "gen-context.js",
5
+ "main": "packages/core/index.js",
6
6
  "exports": {
7
7
  ".": "./packages/core/index.js",
8
8
  "./cli": "./packages/cli/index.js",
@@ -82,7 +82,7 @@
82
82
  "type": "git",
83
83
  "url": "https://github.com/manojmallick/sigmap.git"
84
84
  },
85
- "homepage": "https://manojmallick.github.io/sigmap/",
85
+ "homepage": "https://sigmap.io/",
86
86
  "bugs": {
87
87
  "url": "https://github.com/manojmallick/sigmap/issues"
88
88
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigmap-cli",
3
- "version": "7.0.0",
3
+ "version": "7.1.0",
4
4
  "description": "SigMap CLI wrapper — thin adapter for programmatic CLI invocation",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -18,7 +18,7 @@
18
18
  "url": "https://github.com/manojmallick/sigmap.git",
19
19
  "directory": "packages/cli"
20
20
  },
21
- "homepage": "https://manojmallick.github.io/sigmap/",
21
+ "homepage": "https://sigmap.io/",
22
22
  "license": "MIT",
23
23
  "engines": {
24
24
  "node": ">=18.0.0"
@@ -1,6 +1,6 @@
1
1
  # sigmap-core
2
2
 
3
- Programmatic API for [SigMap](https://manojmallick.github.io/sigmap/) — zero-dependency code signature extraction, ranked retrieval, secret scanning, project health scoring, and multi-adapter output formatting (v3.0+).
3
+ Programmatic API for [SigMap](https://sigmap.io/) — zero-dependency code signature extraction, ranked retrieval, secret scanning, project health scoring, and multi-adapter output formatting (v3.0+).
4
4
 
5
5
  ## Installation
6
6
 
@@ -145,7 +145,7 @@ const geminiInstruction = adapt(context, 'gemini');
145
145
  // All 6 adapters: copilot | claude | cursor | windsurf | openai | gemini
146
146
  ```
147
147
 
148
- See the full [roadmap](https://manojmallick.github.io/sigmap/roadmap.html).
148
+ See the full [roadmap](https://sigmap.io/roadmap.html).
149
149
 
150
150
  ## Zero dependencies
151
151
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigmap-core",
3
- "version": "7.0.0",
3
+ "version": "7.1.0",
4
4
  "description": "SigMap core library — zero-dependency code signature extraction, retrieval, and security scanning",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -20,7 +20,7 @@
20
20
  "url": "https://github.com/manojmallick/sigmap.git",
21
21
  "directory": "packages/core"
22
22
  },
23
- "homepage": "https://manojmallick.github.io/sigmap/",
23
+ "homepage": "https://sigmap.io/",
24
24
  "license": "MIT",
25
25
  "engines": {
26
26
  "node": ">=18.0.0"
@@ -34,12 +34,12 @@ function loadBaseConfig(extendsVal, cwd) {
34
34
  }).on('error', reject);
35
35
  });
36
36
  })();
37
- // sync fallback: use execSync with node -e
38
- const { execSync } = require('child_process');
39
- const out = execSync(
40
- `node -e "const h=require('${extendsVal.startsWith('https') ? 'https' : 'http'}');let d='';h.get(${JSON.stringify(extendsVal)},r=>{r.on('data',c=>d+=c);r.on('end',()=>process.stdout.write(d))}).on('error',()=>process.exit(1))"`,
41
- { timeout: 10000, encoding: 'utf8' }
42
- );
37
+ // Sync fallback: run a tiny fetch in a child node process. Shell-free —
38
+ // execFileSync runs the node binary directly (no /bin/sh) and the URL is
39
+ // passed as an argv value, never interpolated into a command string.
40
+ const { execFileSync } = require('child_process');
41
+ const SYNC_FETCH = "const u=process.argv[1];const h=require(u.startsWith('https')?'https':'http');let d='';h.get(u,r=>{r.on('data',c=>d+=c);r.on('end',()=>process.stdout.write(d))}).on('error',()=>process.exit(1))";
42
+ const out = execFileSync(process.execPath, ['-e', SYNC_FETCH, extendsVal], { timeout: 10000, encoding: 'utf8' });
43
43
  const parsed = JSON.parse(out);
44
44
  if (!fs.existsSync(cacheDir)) fs.mkdirSync(cacheDir, { recursive: true });
45
45
  fs.writeFileSync(cachePath, JSON.stringify(parsed), 'utf8');
@@ -2,7 +2,7 @@
2
2
 
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
- const { execSync } = require('child_process');
5
+ const { git } = require('../util/git');
6
6
 
7
7
  const CODE_EXTS = new Set([
8
8
  '.js','.mjs','.cjs','.ts','.tsx','.jsx',
@@ -35,7 +35,7 @@ const ROOT_ENTRYPOINTS = {
35
35
 
36
36
  function getRecentlyChangedDirs(cwd) {
37
37
  try {
38
- const out = execSync('git log --name-only --format="" HEAD~10 2>/dev/null', { cwd, timeout: 3000 }).toString();
38
+ const out = git(['log', '--name-only', '--format=', 'HEAD~10'], { cwd, timeout: 3000 }).toString();
39
39
  return new Set(out.split('\n').filter(Boolean).map(f => f.split('/')[0]));
40
40
  } catch { return new Set(); }
41
41
  }
@@ -0,0 +1,206 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * SigMap `gain` — terminal renderer.
5
+ *
6
+ * Zero-dependency ANSI dashboard for token savings. Honors NO_COLOR and
7
+ * non-TTY output (plain text for pipes / --json consumers elsewhere).
8
+ *
9
+ * "saved" is a counterfactual estimate (whole-file baseline − actual context),
10
+ * never a measured delta — the footer says so on every view.
11
+ */
12
+
13
+ const USE_COLOR = !process.env.NO_COLOR && process.stdout.isTTY;
14
+
15
+ const C = {
16
+ reset: USE_COLOR ? '\x1b[0m' : '',
17
+ dim: USE_COLOR ? '\x1b[2m' : '',
18
+ bold: USE_COLOR ? '\x1b[1m' : '',
19
+ green: USE_COLOR ? '\x1b[32m' : '',
20
+ yellow: USE_COLOR ? '\x1b[33m' : '',
21
+ red: USE_COLOR ? '\x1b[31m' : '',
22
+ cyan: USE_COLOR ? '\x1b[36m' : '',
23
+ gray: USE_COLOR ? '\x1b[90m' : '',
24
+ };
25
+
26
+ // ── formatters ───────────────────────────────────────────────────────────
27
+ function humanTokens(n) {
28
+ n = Number(n) || 0;
29
+ if (n >= 1e9) return (n / 1e9).toFixed(1) + 'B';
30
+ if (n >= 1e6) return (n / 1e6).toFixed(1) + 'M';
31
+ if (n >= 1e3) return (n / 1e3).toFixed(1) + 'K';
32
+ return String(Math.round(n));
33
+ }
34
+
35
+ function fmtInt(n) {
36
+ return (Number(n) || 0).toLocaleString('en-US');
37
+ }
38
+
39
+ function fmtUSD(n) {
40
+ n = Number(n) || 0;
41
+ if (n >= 1000) return '$' + n.toLocaleString('en-US', { maximumFractionDigits: 0 });
42
+ return '$' + n.toFixed(2);
43
+ }
44
+
45
+ function fmtDuration(ms) {
46
+ ms = Number(ms) || 0;
47
+ if (ms >= 3.6e6) return (ms / 3.6e6).toFixed(1) + 'h';
48
+ if (ms >= 60000) return (ms / 60000).toFixed(1) + 'm';
49
+ if (ms >= 1000) return (ms / 1000).toFixed(1) + 's';
50
+ return Math.round(ms) + 'ms';
51
+ }
52
+
53
+ function fmtPct(p) {
54
+ return (Number(p) || 0).toFixed(1) + '%';
55
+ }
56
+
57
+ function colorPct(p, text) {
58
+ if (!USE_COLOR) return text;
59
+ const c = p >= 85 ? C.green : p >= 60 ? C.yellow : C.red;
60
+ return c + text + C.reset;
61
+ }
62
+
63
+ function pad(s, w, align) {
64
+ s = String(s);
65
+ const visible = s.replace(/\x1b\[[0-9;]*m/g, '');
66
+ const gap = Math.max(0, w - visible.length);
67
+ return align === 'right' ? ' '.repeat(gap) + s : s + ' '.repeat(gap);
68
+ }
69
+
70
+ /** Solid horizontal efficiency bar with a dotted remainder. */
71
+ function bar(pct, width) {
72
+ const filled = Math.round((clamp(pct, 0, 100) / 100) * width);
73
+ const solid = '█'.repeat(filled);
74
+ const rest = '░'.repeat(Math.max(0, width - filled));
75
+ return (USE_COLOR ? C.green : '') + solid + (USE_COLOR ? C.gray : '') + rest + C.reset;
76
+ }
77
+
78
+ /** Proportional impact bar (share of total saved). */
79
+ function impactBar(sharePct, width) {
80
+ const n = Math.max(1, Math.round((clamp(sharePct, 0, 100) / 100) * width));
81
+ return (USE_COLOR ? C.cyan : '') + '█'.repeat(n) + C.reset;
82
+ }
83
+
84
+ const clamp = (n, lo, hi) => Math.max(lo, Math.min(hi, n));
85
+ const rule = (w) => C.gray + '─'.repeat(w) + C.reset;
86
+
87
+ // ── views ──────────────────────────────────────────────────────────────
88
+ /**
89
+ * Render the global summary + by-operation table.
90
+ * @param {object} agg output of aggregate()
91
+ * @param {object} [opts] { version, scope }
92
+ * @returns {string}
93
+ */
94
+ function renderSummary(agg, opts = {}) {
95
+ const W = 74;
96
+ const t = agg.totals;
97
+ const L = [];
98
+ const scope = opts.scope || 'this repo';
99
+ const ver = opts.version ? `v${opts.version}` : '';
100
+
101
+ L.push('');
102
+ const heading = `⚡ SigMap — Token Savings (${scope})`;
103
+ L.push(' ' + C.bold + C.cyan + heading + C.reset +
104
+ pad(`${C.green}✓${C.reset} ${C.dim}${ver}${C.reset}`, W - heading.length, 'right'));
105
+ L.push(' ' + rule(W));
106
+ L.push('');
107
+
108
+ if (t.count === 0) {
109
+ L.push(` ${C.yellow}No usage recorded yet.${C.reset}`);
110
+ L.push(` ${C.dim}Run a few queries (sigmap ask "...") or seed a demo:${C.reset}`);
111
+ L.push(` ${C.dim} node scripts/gain.mjs --demo${C.reset}`);
112
+ L.push('');
113
+ return L.join('\n');
114
+ }
115
+
116
+ const label = (k) => C.dim + pad(k, 21) + C.reset;
117
+ L.push(' ' + label('Total operations') + ': ' + C.bold + fmtInt(t.count) + C.reset);
118
+ L.push(' ' + label('Whole-file baseline') + ': ' + humanTokens(t.baseline) + ' tok' +
119
+ ` ${C.dim}← est. cost of feeding full files${C.reset}`);
120
+ L.push(' ' + label('SigMap context') + ': ' + humanTokens(t.actual) + ' tok');
121
+ L.push(' ' + label('Tokens saved') + ': ' + C.bold + humanTokens(t.saved) + C.reset +
122
+ ' (' + colorPct(t.savedPct, fmtPct(t.savedPct)) + ')');
123
+ L.push(' ' + label('Est. money saved') + ': ' + C.bold + C.green + fmtUSD(t.usdSaved) + C.reset +
124
+ ` ${C.dim}(${agg.price.model} input @ $${agg.price.perMtok}/M · --model to change)${C.reset}`);
125
+ L.push(' ' + label('Avg latency') + ': ' + fmtDuration(t.avgMs) + ' / op' +
126
+ ` ${C.dim}(local, no API round-trip)${C.reset}`);
127
+ L.push('');
128
+ L.push(' ' + label('Efficiency') + ': ▕' + bar(t.savedPct, 30) + '▏ ' +
129
+ colorPct(t.savedPct, C.bold + fmtPct(t.savedPct) + C.reset));
130
+ L.push('');
131
+
132
+ // By operation table
133
+ L.push(` ${C.bold}By operation${C.reset}`);
134
+ L.push(' ' + rule(W));
135
+ L.push(' ' + C.dim +
136
+ pad('#', 3) + pad('Operation', 24) + pad('Count', 8, 'right') +
137
+ pad('Saved', 9, 'right') + pad('Avg%', 8, 'right') + pad('Time', 8, 'right') +
138
+ ' Impact' + C.reset);
139
+ agg.byOp.forEach((o, i) => {
140
+ L.push(' ' +
141
+ pad(`${i + 1}.`, 3) +
142
+ pad(o.op, 24) +
143
+ pad(fmtInt(o.count), 8, 'right') +
144
+ pad(humanTokens(o.saved), 9, 'right') +
145
+ pad(colorPct(o.avgPct, fmtPct(o.avgPct)), 8, 'right') +
146
+ pad(fmtDuration(o.avgMs), 8, 'right') +
147
+ ' ' + impactBar(o.sharePct, 12));
148
+ });
149
+ L.push(' ' + rule(W));
150
+ L.push(` ${C.dim}saved = baseline − actual · estimated vs whole-file reads · local-only${C.reset}`);
151
+ L.push('');
152
+ return L.join('\n');
153
+ }
154
+
155
+ /**
156
+ * Render daily / weekly / monthly trend tables.
157
+ * @param {object} agg
158
+ * @returns {string}
159
+ */
160
+ function renderBreakdown(agg) {
161
+ const L = [];
162
+ if (agg.totals.count === 0) return renderSummary(agg);
163
+
164
+ const section = (icon, title, rows, keyHeader) => {
165
+ L.push('');
166
+ L.push(` ${C.bold}${icon} ${title}${C.reset}`);
167
+ L.push(' ' + C.dim +
168
+ pad(keyHeader, 14) + pad('Ops', 7, 'right') + pad('Baseline', 11, 'right') +
169
+ pad('Actual', 10, 'right') + pad('Saved', 10, 'right') + pad('Save%', 8, 'right') +
170
+ pad('Time', 8, 'right') + C.reset);
171
+ let TB = 0, TA = 0, TS = 0, TC = 0, TM = 0;
172
+ for (const r of rows) {
173
+ TB += r.baseline; TA += r.actual; TS += r.saved; TC += r.count; TM += r.ms;
174
+ L.push(' ' +
175
+ pad(r.key, 14) + pad(fmtInt(r.count), 7, 'right') +
176
+ pad(humanTokens(r.baseline), 11, 'right') + pad(humanTokens(r.actual), 10, 'right') +
177
+ pad(humanTokens(r.saved), 10, 'right') +
178
+ pad(colorPct(r.savedPct, fmtPct(r.savedPct)), 8, 'right') +
179
+ pad(fmtDuration(r.ms), 8, 'right'));
180
+ }
181
+ const tp = TB > 0 ? (TS / TB) * 100 : 0;
182
+ L.push(' ' + C.bold +
183
+ pad('TOTAL', 14) + pad(fmtInt(TC), 7, 'right') +
184
+ pad(humanTokens(TB), 11, 'right') + pad(humanTokens(TA), 10, 'right') +
185
+ pad(humanTokens(TS), 10, 'right') + pad(fmtPct(tp), 8, 'right') +
186
+ pad(fmtDuration(TM), 8, 'right') + C.reset);
187
+ };
188
+
189
+ const daily = agg.buckets.daily.slice(-30);
190
+ section('📅', `Daily (last ${daily.length})`, daily, 'Date');
191
+ const weekly = agg.buckets.weekly.slice(-6);
192
+ section('📆', `Weekly (last ${weekly.length})`, weekly, 'Week of');
193
+ const monthly = agg.buckets.monthly.slice(-3);
194
+ section('🗓️', `Monthly (last ${monthly.length})`, monthly, 'Month');
195
+ L.push('');
196
+ L.push(` ${C.dim}saved = baseline − actual · estimated vs whole-file reads · local-only${C.reset}`);
197
+ L.push('');
198
+ return L.join('\n');
199
+ }
200
+
201
+ module.exports = {
202
+ renderSummary,
203
+ renderBreakdown,
204
+ // exported for tests
205
+ humanTokens, fmtUSD, fmtDuration, fmtPct,
206
+ };
@@ -1,14 +1,13 @@
1
1
  'use strict';
2
2
  const path = require('path');
3
3
  const fs = require('fs');
4
- const { execSync } = require('child_process');
4
+ const { tryGit } = require('../util/git');
5
5
  module.exports = { format, outputPath };
6
6
 
7
7
  function outputPath(cwd) { return path.join(cwd, 'llms.txt'); }
8
8
 
9
9
  function getShortCommit(cwd) {
10
- try { return execSync('git rev-parse --short HEAD', { cwd, timeout: 2000 }).toString().trim(); }
11
- catch (_) { return ''; }
10
+ return tryGit(['rev-parse', '--short', 'HEAD'], { cwd, timeout: 2000 });
12
11
  }
13
12
 
14
13
  function detectVersion(cwd) {
@@ -2,7 +2,7 @@
2
2
 
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
- const { execSync } = require('child_process');
5
+ const { git } = require('../util/git');
6
6
 
7
7
  const CONTEXT_FILE = path.join('.github', 'copilot-instructions.md');
8
8
  const CONTEXT_COLD_FILE = path.join('.github', 'context-cold.md');
@@ -149,19 +149,14 @@ function createCheckpoint(args, cwd) {
149
149
  // ── Git info ────────────────────────────────────────────────────────────
150
150
  lines.push('## Git state');
151
151
  try {
152
- const branch = execSync('git rev-parse --abbrev-ref HEAD', {
153
- cwd, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'],
154
- }).trim();
152
+ const branch = git(['rev-parse', '--abbrev-ref', 'HEAD'], { cwd }).trim();
155
153
  lines.push(`**Branch:** ${branch}`);
156
154
  } catch (_) {
157
155
  lines.push('**Branch:** (not a git repo)');
158
156
  }
159
157
 
160
158
  try {
161
- const log = execSync(
162
- 'git log --oneline -5 --no-decorate 2>/dev/null',
163
- { cwd, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }
164
- ).trim();
159
+ const log = git(['log', '--oneline', '-5', '--no-decorate'], { cwd }).trim();
165
160
  if (log) {
166
161
  lines.push('');
167
162
  lines.push('**Recent commits:**');
package/src/mcp/server.js CHANGED
@@ -18,7 +18,7 @@ const { readContext, searchSignatures, getMap, createCheckpoint, getRouting, exp
18
18
 
19
19
  const SERVER_INFO = {
20
20
  name: 'sigmap',
21
- version: '7.0.0',
21
+ version: '7.1.0',
22
22
  description: 'SigMap MCP server — code signatures on demand',
23
23
  };
24
24
 
package/src/nudge.js CHANGED
@@ -11,8 +11,6 @@
11
11
 
12
12
  const fs = require('fs');
13
13
  const path = require('path');
14
- const os = require('os');
15
- const crypto = require('crypto');
16
14
 
17
15
  const RUN_THRESHOLD = 10;
18
16
  const SUCCESS_THRESHOLD = 8;
@@ -22,7 +20,7 @@ function usagePath(cwd) { return path.join(cwd, '.context', 'usage.json'); }
22
20
  function defaultUsage() {
23
21
  return {
24
22
  totalRuns: 0, successfulRuns: 0, squeezeOffered: 0, squeezeAccepted: 0,
25
- starNudgeShown: false, machineId: '', firstRunDate: null, lastRunDate: null,
23
+ starNudgeShown: false, firstRunDate: null, lastRunDate: null,
26
24
  };
27
25
  }
28
26
 
@@ -75,9 +73,6 @@ function checkStarNudge(cwd, runSuccess, opts = {}) {
75
73
  const today = opts.today || new Date().toISOString().slice(0, 10);
76
74
  if (!usage.firstRunDate) usage.firstRunDate = today;
77
75
  usage.lastRunDate = today;
78
- if (!usage.machineId) {
79
- try { usage.machineId = 'sha256-' + crypto.createHash('sha256').update(os.hostname()).digest('hex').slice(0, 16); } catch (_) {}
80
- }
81
76
 
82
77
  let nudged = false;
83
78
  if (!usage.starNudgeShown && usage.totalRuns >= RUN_THRESHOLD && usage.successfulRuns >= SUCCESS_THRESHOLD) {
@@ -15,7 +15,7 @@
15
15
 
16
16
  const fs = require('fs');
17
17
  const path = require('path');
18
- const { execSync } = require('child_process');
18
+ const { tryGit } = require('../util/git');
19
19
 
20
20
  const NOTES_FILE = path.join('.context', 'notes.ndjson');
21
21
  const MAX_TEXT = 2000;
@@ -25,13 +25,7 @@ function notesPath(cwd) {
25
25
  }
26
26
 
27
27
  function _currentBranch(cwd) {
28
- try {
29
- return execSync('git rev-parse --abbrev-ref HEAD', {
30
- cwd, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'],
31
- }).trim() || null;
32
- } catch (_) {
33
- return null;
34
- }
28
+ return tryGit(['rev-parse', '--abbrev-ref', 'HEAD'], { cwd }) || null;
35
29
  }
36
30
 
37
31
  /**