canicode 0.6.1 → 0.6.3
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/README.md +12 -3
- package/dist/cli/index.js +114 -230
- package/dist/cli/index.js.map +1 -1
- package/dist/mcp/server.js +115 -230
- package/dist/mcp/server.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -103,7 +103,16 @@ canicode init --token figd_xxxxxxxxxxxxx
|
|
|
103
103
|
|
|
104
104
|
### MCP Server (Claude Code / Cursor / Claude Desktop)
|
|
105
105
|
|
|
106
|
-
**Claude Code:**
|
|
106
|
+
**Claude Code (recommended — with official Figma MCP, no token needed):**
|
|
107
|
+
```bash
|
|
108
|
+
# 1. Install canicode MCP server
|
|
109
|
+
claude mcp add canicode -- npx -y -p canicode canicode-mcp
|
|
110
|
+
|
|
111
|
+
# 2. Install official Figma MCP (enables token-free analysis)
|
|
112
|
+
claude mcp add -s project -t http figma https://mcp.figma.com/mcp
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Claude Code (with Figma API token):**
|
|
107
116
|
```bash
|
|
108
117
|
claude mcp add canicode -e FIGMA_TOKEN=figd_xxxxxxxxxxxxx -- npx -y -p canicode canicode-mcp
|
|
109
118
|
```
|
|
@@ -114,7 +123,7 @@ claude mcp add canicode -e FIGMA_TOKEN=figd_xxxxxxxxxxxxx -- npx -y -p canicode
|
|
|
114
123
|
"mcpServers": {
|
|
115
124
|
"canicode": {
|
|
116
125
|
"command": "npx",
|
|
117
|
-
"args": ["-y", "canicode", "canicode-mcp"],
|
|
126
|
+
"args": ["-y", "-p", "canicode", "canicode-mcp"],
|
|
118
127
|
"env": {
|
|
119
128
|
"FIGMA_TOKEN": "figd_xxxxxxxxxxxxx"
|
|
120
129
|
}
|
|
@@ -129,7 +138,7 @@ claude mcp add canicode -e FIGMA_TOKEN=figd_xxxxxxxxxxxxx -- npx -y -p canicode
|
|
|
129
138
|
"mcpServers": {
|
|
130
139
|
"canicode": {
|
|
131
140
|
"command": "npx",
|
|
132
|
-
"args": ["-y", "canicode", "canicode-mcp"],
|
|
141
|
+
"args": ["-y", "-p", "canicode", "canicode-mcp"],
|
|
133
142
|
"env": {
|
|
134
143
|
"FIGMA_TOKEN": "figd_xxxxxxxxxxxxx"
|
|
135
144
|
}
|
package/dist/cli/index.js
CHANGED
|
@@ -2,209 +2,13 @@
|
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
3
3
|
import { writeFile, readFile, appendFile } from 'fs/promises';
|
|
4
4
|
import { join, resolve, dirname, basename } from 'path';
|
|
5
|
+
import { createRequire } from 'module';
|
|
5
6
|
import { config } from 'dotenv';
|
|
6
7
|
import cac from 'cac';
|
|
7
8
|
import { z } from 'zod';
|
|
9
|
+
import { randomUUID } from 'crypto';
|
|
8
10
|
import { homedir } from 'os';
|
|
9
11
|
|
|
10
|
-
var __defProp = Object.defineProperty;
|
|
11
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
12
|
-
var __esm = (fn, res) => function __init() {
|
|
13
|
-
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
14
|
-
};
|
|
15
|
-
var __export = (target, all) => {
|
|
16
|
-
for (var name in all)
|
|
17
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
// src/monitoring/browser.ts
|
|
21
|
-
var browser_exports = {};
|
|
22
|
-
__export(browser_exports, {
|
|
23
|
-
initBrowserMonitoring: () => initBrowserMonitoring,
|
|
24
|
-
shutdownBrowserMonitoring: () => shutdownBrowserMonitoring,
|
|
25
|
-
trackBrowserError: () => trackBrowserError,
|
|
26
|
-
trackBrowserEvent: () => trackBrowserEvent
|
|
27
|
-
});
|
|
28
|
-
function getGlobal() {
|
|
29
|
-
return globalThis;
|
|
30
|
-
}
|
|
31
|
-
function injectScript(src) {
|
|
32
|
-
return new Promise((resolve7, reject) => {
|
|
33
|
-
const g = getGlobal();
|
|
34
|
-
const doc = g["document"];
|
|
35
|
-
if (!doc) {
|
|
36
|
-
resolve7();
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
const script = doc["createElement"]("script");
|
|
40
|
-
script["src"] = src;
|
|
41
|
-
script["async"] = true;
|
|
42
|
-
script["onload"] = () => resolve7();
|
|
43
|
-
script["onerror"] = () => reject(new Error(`Failed to load script: ${src}`));
|
|
44
|
-
doc["head"]["appendChild"](script);
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
async function initBrowserMonitoring(config2) {
|
|
48
|
-
if (config2.enabled === false) return;
|
|
49
|
-
const g = getGlobal();
|
|
50
|
-
if (!g["document"]) return;
|
|
51
|
-
monitoringEnabled = true;
|
|
52
|
-
if (config2.posthogApiKey) {
|
|
53
|
-
try {
|
|
54
|
-
await injectScript("https://us-assets.i.posthog.com/static/array.js");
|
|
55
|
-
g["posthog"]?.["init"]?.(config2.posthogApiKey, {
|
|
56
|
-
api_host: "https://us.i.posthog.com",
|
|
57
|
-
autocapture: false,
|
|
58
|
-
capture_pageview: true
|
|
59
|
-
});
|
|
60
|
-
} catch {
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
if (config2.sentryDsn) {
|
|
64
|
-
try {
|
|
65
|
-
await injectScript("https://browser.sentry-cdn.com/8.0.0/bundle.min.js");
|
|
66
|
-
g["Sentry"]?.["init"]?.({
|
|
67
|
-
dsn: config2.sentryDsn,
|
|
68
|
-
environment: config2.environment ?? "web",
|
|
69
|
-
release: config2.version,
|
|
70
|
-
tracesSampleRate: 0
|
|
71
|
-
});
|
|
72
|
-
} catch {
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
function trackBrowserEvent(event, properties) {
|
|
77
|
-
if (!monitoringEnabled) return;
|
|
78
|
-
try {
|
|
79
|
-
getGlobal()["posthog"]?.["capture"]?.(event, properties);
|
|
80
|
-
} catch {
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
function trackBrowserError(error, context) {
|
|
84
|
-
if (!monitoringEnabled) return;
|
|
85
|
-
try {
|
|
86
|
-
getGlobal()["Sentry"]?.["captureException"]?.(
|
|
87
|
-
error,
|
|
88
|
-
context ? { extra: context } : void 0
|
|
89
|
-
);
|
|
90
|
-
} catch {
|
|
91
|
-
}
|
|
92
|
-
try {
|
|
93
|
-
getGlobal()["posthog"]?.["capture"]?.("error", {
|
|
94
|
-
error: error.message,
|
|
95
|
-
...context
|
|
96
|
-
});
|
|
97
|
-
} catch {
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
async function shutdownBrowserMonitoring() {
|
|
101
|
-
monitoringEnabled = false;
|
|
102
|
-
}
|
|
103
|
-
var monitoringEnabled;
|
|
104
|
-
var init_browser = __esm({
|
|
105
|
-
"src/monitoring/browser.ts"() {
|
|
106
|
-
monitoringEnabled = false;
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
// src/monitoring/node.ts
|
|
111
|
-
var node_exports = {};
|
|
112
|
-
__export(node_exports, {
|
|
113
|
-
initNodeMonitoring: () => initNodeMonitoring,
|
|
114
|
-
shutdownNodeMonitoring: () => shutdownNodeMonitoring,
|
|
115
|
-
trackNodeError: () => trackNodeError,
|
|
116
|
-
trackNodeEvent: () => trackNodeEvent
|
|
117
|
-
});
|
|
118
|
-
async function initNodeMonitoring(config2) {
|
|
119
|
-
if (config2.enabled === false) return;
|
|
120
|
-
monitoringEnabled2 = true;
|
|
121
|
-
commonProps = {
|
|
122
|
-
_sdk: "canicode",
|
|
123
|
-
_sdk_version: config2.version ?? "unknown",
|
|
124
|
-
_env: config2.environment ?? "unknown"
|
|
125
|
-
};
|
|
126
|
-
if (config2.posthogApiKey) {
|
|
127
|
-
try {
|
|
128
|
-
const mod = await import('posthog-node');
|
|
129
|
-
const PostHog = mod.PostHog;
|
|
130
|
-
posthogClient = new PostHog(config2.posthogApiKey, {
|
|
131
|
-
host: "https://us.i.posthog.com",
|
|
132
|
-
flushAt: 10,
|
|
133
|
-
flushInterval: 1e4
|
|
134
|
-
});
|
|
135
|
-
} catch {
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
if (config2.sentryDsn) {
|
|
139
|
-
try {
|
|
140
|
-
const mod = await import('@sentry/node');
|
|
141
|
-
sentryModule = mod;
|
|
142
|
-
sentryModule.init({
|
|
143
|
-
dsn: config2.sentryDsn,
|
|
144
|
-
environment: config2.environment ?? "cli",
|
|
145
|
-
release: config2.version,
|
|
146
|
-
tracesSampleRate: 0
|
|
147
|
-
});
|
|
148
|
-
} catch {
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
function trackNodeEvent(event, properties) {
|
|
153
|
-
if (!monitoringEnabled2 || !posthogClient) return;
|
|
154
|
-
try {
|
|
155
|
-
const captureOpts = {
|
|
156
|
-
distinctId: "anonymous",
|
|
157
|
-
event
|
|
158
|
-
};
|
|
159
|
-
captureOpts.properties = { ...commonProps, ...properties };
|
|
160
|
-
posthogClient.capture(captureOpts);
|
|
161
|
-
} catch {
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
function trackNodeError(error, context) {
|
|
165
|
-
if (!monitoringEnabled2) return;
|
|
166
|
-
try {
|
|
167
|
-
sentryModule?.captureException(error, context ? { extra: context } : void 0);
|
|
168
|
-
} catch {
|
|
169
|
-
}
|
|
170
|
-
try {
|
|
171
|
-
posthogClient?.capture({
|
|
172
|
-
distinctId: "anonymous",
|
|
173
|
-
event: "cic_error",
|
|
174
|
-
properties: { ...commonProps, error: error.message, ...context }
|
|
175
|
-
});
|
|
176
|
-
} catch {
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
async function shutdownNodeMonitoring() {
|
|
180
|
-
if (!monitoringEnabled2) return;
|
|
181
|
-
const tasks = [];
|
|
182
|
-
if (posthogClient) {
|
|
183
|
-
tasks.push(
|
|
184
|
-
posthogClient.shutdown().catch(() => {
|
|
185
|
-
})
|
|
186
|
-
);
|
|
187
|
-
}
|
|
188
|
-
if (sentryModule) {
|
|
189
|
-
tasks.push(
|
|
190
|
-
sentryModule.close(2e3).catch(() => {
|
|
191
|
-
})
|
|
192
|
-
);
|
|
193
|
-
}
|
|
194
|
-
await Promise.allSettled(tasks);
|
|
195
|
-
posthogClient = null;
|
|
196
|
-
sentryModule = null;
|
|
197
|
-
monitoringEnabled2 = false;
|
|
198
|
-
}
|
|
199
|
-
var posthogClient, sentryModule, monitoringEnabled2, commonProps;
|
|
200
|
-
var init_node = __esm({
|
|
201
|
-
"src/monitoring/node.ts"() {
|
|
202
|
-
posthogClient = null;
|
|
203
|
-
sentryModule = null;
|
|
204
|
-
monitoringEnabled2 = false;
|
|
205
|
-
commonProps = {};
|
|
206
|
-
}
|
|
207
|
-
});
|
|
208
12
|
z.object({
|
|
209
13
|
fileKey: z.string(),
|
|
210
14
|
nodeId: z.string().optional(),
|
|
@@ -1114,6 +918,14 @@ function getPosthogApiKey() {
|
|
|
1114
918
|
function getSentryDsn() {
|
|
1115
919
|
return process.env["SENTRY_DSN"] ?? readConfig().sentryDsn;
|
|
1116
920
|
}
|
|
921
|
+
function getDeviceId() {
|
|
922
|
+
const config2 = readConfig();
|
|
923
|
+
if (config2.deviceId) return config2.deviceId;
|
|
924
|
+
const id = randomUUID();
|
|
925
|
+
config2.deviceId = id;
|
|
926
|
+
writeConfig(config2);
|
|
927
|
+
return id;
|
|
928
|
+
}
|
|
1117
929
|
function initAiready(token) {
|
|
1118
930
|
setFigmaToken(token);
|
|
1119
931
|
ensureReportsDir();
|
|
@@ -2949,51 +2761,122 @@ var EVENTS = {
|
|
|
2949
2761
|
CLI_INIT: `${EVENT_PREFIX}cli_init`
|
|
2950
2762
|
};
|
|
2951
2763
|
|
|
2952
|
-
// src/monitoring/
|
|
2953
|
-
var
|
|
2954
|
-
|
|
2955
|
-
var
|
|
2956
|
-
|
|
2957
|
-
var
|
|
2958
|
-
function
|
|
2959
|
-
|
|
2960
|
-
|
|
2764
|
+
// src/monitoring/capture.ts
|
|
2765
|
+
var monitoringEnabled = false;
|
|
2766
|
+
var posthogApiKey;
|
|
2767
|
+
var sentryDsn;
|
|
2768
|
+
var distinctId = "anonymous";
|
|
2769
|
+
var commonProps = {};
|
|
2770
|
+
function uuid4() {
|
|
2771
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
2772
|
+
const r = Math.random() * 16 | 0;
|
|
2773
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
2774
|
+
return v.toString(16);
|
|
2775
|
+
});
|
|
2961
2776
|
}
|
|
2962
|
-
|
|
2777
|
+
function parseSentryDsn(dsn) {
|
|
2778
|
+
try {
|
|
2779
|
+
const url = new URL(dsn);
|
|
2780
|
+
const key = url.username;
|
|
2781
|
+
const projectId = url.pathname.slice(1);
|
|
2782
|
+
const host = url.protocol + "//" + url.host;
|
|
2783
|
+
if (!key || !projectId) return null;
|
|
2784
|
+
return { key, host, projectId };
|
|
2785
|
+
} catch {
|
|
2786
|
+
return null;
|
|
2787
|
+
}
|
|
2788
|
+
}
|
|
2789
|
+
function initCapture(config2) {
|
|
2963
2790
|
if (config2.enabled === false) return;
|
|
2964
2791
|
if (!config2.posthogApiKey && !config2.sentryDsn) return;
|
|
2792
|
+
monitoringEnabled = true;
|
|
2793
|
+
posthogApiKey = config2.posthogApiKey;
|
|
2794
|
+
sentryDsn = config2.sentryDsn;
|
|
2795
|
+
distinctId = config2.distinctId ?? "anonymous";
|
|
2796
|
+
commonProps = {
|
|
2797
|
+
_sdk: "canicode",
|
|
2798
|
+
_sdk_version: config2.version ?? "unknown",
|
|
2799
|
+
_env: config2.environment ?? "unknown"
|
|
2800
|
+
};
|
|
2801
|
+
}
|
|
2802
|
+
function captureEvent(event, properties) {
|
|
2803
|
+
if (!monitoringEnabled || !posthogApiKey) return;
|
|
2965
2804
|
try {
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
}
|
|
2805
|
+
fetch("https://us.i.posthog.com/i/v0/e/", {
|
|
2806
|
+
method: "POST",
|
|
2807
|
+
headers: { "Content-Type": "application/json" },
|
|
2808
|
+
body: JSON.stringify({
|
|
2809
|
+
api_key: posthogApiKey,
|
|
2810
|
+
event,
|
|
2811
|
+
distinct_id: distinctId,
|
|
2812
|
+
properties: { ...commonProps, ...properties },
|
|
2813
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2814
|
+
})
|
|
2815
|
+
}).catch(() => {
|
|
2816
|
+
});
|
|
2979
2817
|
} catch {
|
|
2980
2818
|
}
|
|
2981
2819
|
}
|
|
2820
|
+
function captureError(error, context) {
|
|
2821
|
+
if (!monitoringEnabled) return;
|
|
2822
|
+
if (sentryDsn) {
|
|
2823
|
+
const parsed = parseSentryDsn(sentryDsn);
|
|
2824
|
+
if (parsed) {
|
|
2825
|
+
try {
|
|
2826
|
+
const eventId = uuid4();
|
|
2827
|
+
const envelope = [
|
|
2828
|
+
JSON.stringify({ event_id: eventId, sent_at: (/* @__PURE__ */ new Date()).toISOString(), dsn: sentryDsn }),
|
|
2829
|
+
JSON.stringify({ type: "event", content_type: "application/json" }),
|
|
2830
|
+
JSON.stringify({
|
|
2831
|
+
event_id: eventId,
|
|
2832
|
+
exception: { values: [{ type: error.name, value: error.message }] },
|
|
2833
|
+
platform: "node",
|
|
2834
|
+
timestamp: Date.now() / 1e3,
|
|
2835
|
+
extra: context
|
|
2836
|
+
})
|
|
2837
|
+
].join("\n");
|
|
2838
|
+
fetch(`${parsed.host}/api/${parsed.projectId}/envelope/`, {
|
|
2839
|
+
method: "POST",
|
|
2840
|
+
headers: {
|
|
2841
|
+
"Content-Type": "application/x-sentry-envelope",
|
|
2842
|
+
"X-Sentry-Auth": `Sentry sentry_version=7, sentry_key=${parsed.key}`
|
|
2843
|
+
},
|
|
2844
|
+
body: envelope
|
|
2845
|
+
}).catch(() => {
|
|
2846
|
+
});
|
|
2847
|
+
} catch {
|
|
2848
|
+
}
|
|
2849
|
+
}
|
|
2850
|
+
}
|
|
2851
|
+
captureEvent("cic_error", { error: error.message, ...context });
|
|
2852
|
+
}
|
|
2853
|
+
function shutdownCapture() {
|
|
2854
|
+
monitoringEnabled = false;
|
|
2855
|
+
posthogApiKey = void 0;
|
|
2856
|
+
sentryDsn = void 0;
|
|
2857
|
+
distinctId = "anonymous";
|
|
2858
|
+
commonProps = {};
|
|
2859
|
+
}
|
|
2860
|
+
|
|
2861
|
+
// src/monitoring/index.ts
|
|
2862
|
+
function initMonitoring(config2) {
|
|
2863
|
+
initCapture(config2);
|
|
2864
|
+
}
|
|
2982
2865
|
function trackEvent(event, properties) {
|
|
2983
2866
|
try {
|
|
2984
|
-
|
|
2867
|
+
captureEvent(event, properties);
|
|
2985
2868
|
} catch {
|
|
2986
2869
|
}
|
|
2987
2870
|
}
|
|
2988
2871
|
function trackError(error, context) {
|
|
2989
2872
|
try {
|
|
2990
|
-
|
|
2873
|
+
captureError(error, context);
|
|
2991
2874
|
} catch {
|
|
2992
2875
|
}
|
|
2993
2876
|
}
|
|
2994
|
-
|
|
2877
|
+
function shutdownMonitoring() {
|
|
2995
2878
|
try {
|
|
2996
|
-
|
|
2879
|
+
shutdownCapture();
|
|
2997
2880
|
} catch {
|
|
2998
2881
|
}
|
|
2999
2882
|
}
|
|
@@ -4170,23 +4053,24 @@ defineRule({
|
|
|
4170
4053
|
|
|
4171
4054
|
// src/cli/index.ts
|
|
4172
4055
|
config();
|
|
4056
|
+
var require2 = createRequire(import.meta.url);
|
|
4057
|
+
var pkg = require2("../../package.json");
|
|
4173
4058
|
var cli = cac("canicode");
|
|
4174
4059
|
{
|
|
4175
4060
|
const monitoringConfig = {
|
|
4176
4061
|
environment: "cli",
|
|
4177
|
-
version:
|
|
4062
|
+
version: pkg.version,
|
|
4178
4063
|
enabled: getTelemetryEnabled()
|
|
4179
4064
|
};
|
|
4180
4065
|
const phKey = getPosthogApiKey() || POSTHOG_API_KEY;
|
|
4181
4066
|
monitoringConfig.posthogApiKey = phKey;
|
|
4182
4067
|
const sDsn = getSentryDsn() || SENTRY_DSN;
|
|
4183
4068
|
monitoringConfig.sentryDsn = sDsn;
|
|
4184
|
-
|
|
4185
|
-
|
|
4069
|
+
monitoringConfig.distinctId = getDeviceId();
|
|
4070
|
+
initMonitoring(monitoringConfig);
|
|
4186
4071
|
}
|
|
4187
4072
|
process.on("beforeExit", () => {
|
|
4188
|
-
shutdownMonitoring()
|
|
4189
|
-
});
|
|
4073
|
+
shutdownMonitoring();
|
|
4190
4074
|
});
|
|
4191
4075
|
var MAX_NODES_WITHOUT_SCOPE = 500;
|
|
4192
4076
|
function pickRandomScope(root) {
|