@tanagram/cli 0.5.53 → 0.5.55
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/dist/npm/darwin-arm64/tanagram +0 -0
- package/dist/npm/darwin-x64/tanagram +0 -0
- package/dist/npm/linux-arm64/tanagram +0 -0
- package/dist/npm/linux-x64/tanagram +0 -0
- package/dist/npm/tanagram_0.5.55_darwin_amd64.tar.gz +0 -0
- package/dist/npm/tanagram_0.5.55_darwin_arm64.tar.gz +0 -0
- package/dist/npm/tanagram_0.5.55_linux_amd64.tar.gz +0 -0
- package/dist/npm/tanagram_0.5.55_linux_arm64.tar.gz +0 -0
- package/dist/npm/tanagram_0.5.55_windows_amd64.zip +0 -0
- package/dist/npm/win32-x64/tanagram.exe +0 -0
- package/install.js +59 -0
- package/package.json +3 -1
- package/uninstall.js +142 -0
- package/dist/npm/tanagram_0.5.53_darwin_amd64.tar.gz +0 -0
- package/dist/npm/tanagram_0.5.53_darwin_arm64.tar.gz +0 -0
- package/dist/npm/tanagram_0.5.53_linux_amd64.tar.gz +0 -0
- package/dist/npm/tanagram_0.5.53_linux_arm64.tar.gz +0 -0
- package/dist/npm/tanagram_0.5.53_windows_amd64.zip +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/install.js
CHANGED
|
@@ -171,6 +171,62 @@ function installClaudeSkill() {
|
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
+
function installStopHook() {
|
|
175
|
+
if (process.env.TANAGRAM_SKIP_HOOK === '1' || process.env.TANAGRAM_SKIP_HOOK === 'true') {
|
|
176
|
+
console.error('Skipping Tanagram Stop hook installation (TANAGRAM_SKIP_HOOK set).');
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (isCIEnvironment()) {
|
|
180
|
+
console.error('Skipping Tanagram Stop hook installation (CI environment).');
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
console.error('Installing Tanagram Stop hook for Claude Code...');
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
const settingsPath = path.join(os.homedir(), '.claude', 'settings.json');
|
|
188
|
+
let settings = {};
|
|
189
|
+
|
|
190
|
+
if (fs.existsSync(settingsPath)) {
|
|
191
|
+
const raw = fs.readFileSync(settingsPath, 'utf8');
|
|
192
|
+
settings = JSON.parse(raw);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Ensure hooks.Stop array exists
|
|
196
|
+
if (!settings.hooks) settings.hooks = {};
|
|
197
|
+
if (!Array.isArray(settings.hooks.Stop)) settings.hooks.Stop = [];
|
|
198
|
+
|
|
199
|
+
// Check if tanagram stop-hook is already configured
|
|
200
|
+
const alreadyInstalled = settings.hooks.Stop.some(entry =>
|
|
201
|
+
Array.isArray(entry.hooks) && entry.hooks.some(h => h.command === 'tanagram stop-hook')
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
if (alreadyInstalled) {
|
|
205
|
+
console.error('✓ Tanagram Stop hook already configured');
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
settings.hooks.Stop.push({
|
|
210
|
+
hooks: [
|
|
211
|
+
{
|
|
212
|
+
type: 'command',
|
|
213
|
+
command: 'tanagram stop-hook',
|
|
214
|
+
timeout: 120
|
|
215
|
+
}
|
|
216
|
+
]
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
|
|
220
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
|
|
221
|
+
|
|
222
|
+
console.error(`✓ Tanagram Stop hook installed to ${settingsPath}`);
|
|
223
|
+
track('cli.stop_hook.install.success');
|
|
224
|
+
} catch (err) {
|
|
225
|
+
console.error('Warning: Failed to install Stop hook:', err.message);
|
|
226
|
+
track('cli.stop_hook.install.failure', { error: err.message });
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
174
230
|
function ensureOpenCode() {
|
|
175
231
|
if (isCIEnvironment()) {
|
|
176
232
|
return;
|
|
@@ -217,6 +273,9 @@ function ensureOpenCode() {
|
|
|
217
273
|
// Install Claude skill
|
|
218
274
|
installClaudeSkill();
|
|
219
275
|
|
|
276
|
+
// Install Stop hook for Claude Code
|
|
277
|
+
installStopHook();
|
|
278
|
+
|
|
220
279
|
// Install OpenCode (LLM agent for eval)
|
|
221
280
|
ensureOpenCode();
|
|
222
281
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanagram/cli",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.55",
|
|
4
4
|
"description": "Tanagram - Catch sloppy code before it ships",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"postinstall": "node install.js",
|
|
11
|
+
"preuninstall": "node uninstall.js",
|
|
11
12
|
"test": "go test ./..."
|
|
12
13
|
},
|
|
13
14
|
"keywords": [
|
|
@@ -33,6 +34,7 @@
|
|
|
33
34
|
"bin/tanagram.js",
|
|
34
35
|
"dist/npm/",
|
|
35
36
|
"install.js",
|
|
37
|
+
"uninstall.js",
|
|
36
38
|
"skills/",
|
|
37
39
|
"README.md",
|
|
38
40
|
"LICENSE"
|
package/uninstall.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
const https = require('https');
|
|
7
|
+
const crypto = require('crypto');
|
|
8
|
+
const pkg = require('./package.json');
|
|
9
|
+
|
|
10
|
+
const POSTHOG_KEY = 'phc_sMsUvf0nK50rZdztSlX9rDJqIreLcXj4dyGS0tORQpQ';
|
|
11
|
+
const POSTHOG_HOST = 'phe.tanagram.ai';
|
|
12
|
+
|
|
13
|
+
function getDistinctId() {
|
|
14
|
+
const machineId = os.hostname() + os.userInfo().username;
|
|
15
|
+
return crypto.createHash('sha256').update(machineId).digest('hex').slice(0, 16);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function track(event, properties = {}) {
|
|
19
|
+
if (isCIEnvironment()) return;
|
|
20
|
+
|
|
21
|
+
const data = JSON.stringify({
|
|
22
|
+
api_key: POSTHOG_KEY,
|
|
23
|
+
event: event,
|
|
24
|
+
properties: {
|
|
25
|
+
distinct_id: getDistinctId(),
|
|
26
|
+
version: pkg.version,
|
|
27
|
+
platform: os.platform(),
|
|
28
|
+
arch: os.arch(),
|
|
29
|
+
node_version: process.version,
|
|
30
|
+
...properties
|
|
31
|
+
},
|
|
32
|
+
timestamp: new Date().toISOString()
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const req = https.request({
|
|
36
|
+
hostname: POSTHOG_HOST,
|
|
37
|
+
port: 443,
|
|
38
|
+
path: '/capture/',
|
|
39
|
+
method: 'POST',
|
|
40
|
+
headers: {
|
|
41
|
+
'Content-Type': 'application/json',
|
|
42
|
+
'Content-Length': data.length
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
req.on('error', () => {});
|
|
47
|
+
req.write(data);
|
|
48
|
+
req.end();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function isCIEnvironment() {
|
|
52
|
+
return (
|
|
53
|
+
process.env.CI === 'true' ||
|
|
54
|
+
process.env.GITHUB_ACTIONS === 'true' ||
|
|
55
|
+
process.env.BUILDKITE === 'true' ||
|
|
56
|
+
process.env.GITLAB_CI === 'true' ||
|
|
57
|
+
process.env.TF_BUILD === 'True'
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function removeClaudeSkill() {
|
|
62
|
+
const skillsDir = path.join(os.homedir(), '.claude', 'skills', 'tanagram');
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
if (fs.existsSync(skillsDir)) {
|
|
66
|
+
fs.rmSync(skillsDir, { recursive: true });
|
|
67
|
+
console.error('✓ Tanagram skill removed');
|
|
68
|
+
track('cli.skill.uninstall.success');
|
|
69
|
+
}
|
|
70
|
+
} catch (err) {
|
|
71
|
+
console.error('Warning: Failed to remove Tanagram skill:', err.message);
|
|
72
|
+
track('cli.skill.uninstall.failure', { error: err.message });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function removeStopHook() {
|
|
77
|
+
const settingsPath = path.join(os.homedir(), '.claude', 'settings.json');
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
if (!fs.existsSync(settingsPath)) return;
|
|
81
|
+
|
|
82
|
+
const raw = fs.readFileSync(settingsPath, 'utf8');
|
|
83
|
+
const settings = JSON.parse(raw);
|
|
84
|
+
|
|
85
|
+
if (!settings.hooks || !Array.isArray(settings.hooks.Stop)) return;
|
|
86
|
+
|
|
87
|
+
const before = settings.hooks.Stop.length;
|
|
88
|
+
settings.hooks.Stop = settings.hooks.Stop.filter(entry =>
|
|
89
|
+
!(Array.isArray(entry.hooks) && entry.hooks.some(h => h.command === 'tanagram stop-hook'))
|
|
90
|
+
);
|
|
91
|
+
const after = settings.hooks.Stop.length;
|
|
92
|
+
|
|
93
|
+
if (before === after) return;
|
|
94
|
+
|
|
95
|
+
// Clean up empty arrays/objects
|
|
96
|
+
if (settings.hooks.Stop.length === 0) {
|
|
97
|
+
delete settings.hooks.Stop;
|
|
98
|
+
}
|
|
99
|
+
if (Object.keys(settings.hooks).length === 0) {
|
|
100
|
+
delete settings.hooks;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
|
|
104
|
+
console.error('✓ Tanagram Stop hook removed');
|
|
105
|
+
track('cli.stop_hook.uninstall.success');
|
|
106
|
+
} catch (err) {
|
|
107
|
+
console.error('Warning: Failed to remove Stop hook:', err.message);
|
|
108
|
+
track('cli.stop_hook.uninstall.failure', { error: err.message });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function removeOpenCode() {
|
|
113
|
+
if (isCIEnvironment()) return;
|
|
114
|
+
|
|
115
|
+
const { execSync } = require('child_process');
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
execSync('opencode --version', { stdio: 'ignore' });
|
|
119
|
+
} catch {
|
|
120
|
+
// Not installed, nothing to do
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
execSync('npm uninstall -g opencode-ai', { stdio: 'pipe' });
|
|
126
|
+
console.error('✓ OpenCode uninstalled');
|
|
127
|
+
track('cli.opencode.uninstall.success');
|
|
128
|
+
} catch (err) {
|
|
129
|
+
console.error('Warning: Failed to uninstall OpenCode:', err.message);
|
|
130
|
+
track('cli.opencode.uninstall.failure', { error: err.message });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Main uninstall flow
|
|
135
|
+
track('cli.uninstall.start');
|
|
136
|
+
|
|
137
|
+
removeClaudeSkill();
|
|
138
|
+
removeStopHook();
|
|
139
|
+
removeOpenCode();
|
|
140
|
+
|
|
141
|
+
track('cli.uninstall.success');
|
|
142
|
+
console.error('✓ Tanagram CLI uninstalled successfully');
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|