@glasstrace/sdk 0.9.1 → 0.10.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/dist/{chunk-Y6V7BTF3.js → chunk-5MAHIPFH.js} +2 -2
- package/dist/chunk-KOYJ2UQE.js +417 -0
- package/dist/chunk-KOYJ2UQE.js.map +1 -0
- package/dist/{chunk-PQWAKVQ5.js → chunk-O3Y45VGV.js} +33 -102
- package/dist/chunk-O3Y45VGV.js.map +1 -0
- package/dist/chunk-ZRNG36LU.js +77 -0
- package/dist/chunk-ZRNG36LU.js.map +1 -0
- package/dist/cli/init.cjs +55 -18
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.js +3 -2
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/mcp-add.js +2 -1
- package/dist/cli/mcp-add.js.map +1 -1
- package/dist/cli/uninit.cjs +57 -18
- package/dist/cli/uninit.cjs.map +1 -1
- package/dist/cli/uninit.d.cts +34 -2
- package/dist/cli/uninit.d.ts +34 -2
- package/dist/cli/uninit.js +55 -18
- package/dist/cli/uninit.js.map +1 -1
- package/dist/index.cjs +15837 -15140
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +38 -404
- package/dist/index.js.map +1 -1
- package/dist/source-map-uploader-OA5NCDOK.js +25 -0
- package/dist/source-map-uploader-OA5NCDOK.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-PQWAKVQ5.js.map +0 -1
- /package/dist/{chunk-Y6V7BTF3.js.map → chunk-5MAHIPFH.js.map} +0 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AnonApiKeySchema,
|
|
3
|
+
createAnonApiKey
|
|
4
|
+
} from "./chunk-O3Y45VGV.js";
|
|
5
|
+
|
|
6
|
+
// src/anon-key.ts
|
|
7
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
8
|
+
import { join } from "path";
|
|
9
|
+
var GLASSTRACE_DIR = ".glasstrace";
|
|
10
|
+
var ANON_KEY_FILE = "anon_key";
|
|
11
|
+
var ephemeralKeyCache = /* @__PURE__ */ new Map();
|
|
12
|
+
async function readAnonKey(projectRoot) {
|
|
13
|
+
const root = projectRoot ?? process.cwd();
|
|
14
|
+
const keyPath = join(root, GLASSTRACE_DIR, ANON_KEY_FILE);
|
|
15
|
+
try {
|
|
16
|
+
const content = await readFile(keyPath, "utf-8");
|
|
17
|
+
const result = AnonApiKeySchema.safeParse(content);
|
|
18
|
+
if (result.success) {
|
|
19
|
+
return result.data;
|
|
20
|
+
}
|
|
21
|
+
} catch {
|
|
22
|
+
}
|
|
23
|
+
const cached = ephemeralKeyCache.get(root);
|
|
24
|
+
if (cached !== void 0) {
|
|
25
|
+
return cached;
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
async function getOrCreateAnonKey(projectRoot) {
|
|
30
|
+
const root = projectRoot ?? process.cwd();
|
|
31
|
+
const dirPath = join(root, GLASSTRACE_DIR);
|
|
32
|
+
const keyPath = join(dirPath, ANON_KEY_FILE);
|
|
33
|
+
const existingKey = await readAnonKey(root);
|
|
34
|
+
if (existingKey !== null) {
|
|
35
|
+
return existingKey;
|
|
36
|
+
}
|
|
37
|
+
const cached = ephemeralKeyCache.get(root);
|
|
38
|
+
if (cached !== void 0) {
|
|
39
|
+
return cached;
|
|
40
|
+
}
|
|
41
|
+
const newKey = createAnonApiKey();
|
|
42
|
+
try {
|
|
43
|
+
await mkdir(dirPath, { recursive: true, mode: 448 });
|
|
44
|
+
await writeFile(keyPath, newKey, { flag: "wx", mode: 384 });
|
|
45
|
+
return newKey;
|
|
46
|
+
} catch (err) {
|
|
47
|
+
const code = err.code;
|
|
48
|
+
if (code === "EEXIST") {
|
|
49
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
50
|
+
const winnerKey = await readAnonKey(root);
|
|
51
|
+
if (winnerKey !== null) {
|
|
52
|
+
return winnerKey;
|
|
53
|
+
}
|
|
54
|
+
if (attempt < 2) {
|
|
55
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
await writeFile(keyPath, newKey, { mode: 384 });
|
|
60
|
+
await chmod(keyPath, 384);
|
|
61
|
+
return newKey;
|
|
62
|
+
} catch {
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
ephemeralKeyCache.set(root, newKey);
|
|
66
|
+
console.warn(
|
|
67
|
+
`[glasstrace] Failed to persist anonymous key to ${keyPath}: ${err instanceof Error ? err.message : String(err)}. Using ephemeral key.`
|
|
68
|
+
);
|
|
69
|
+
return newKey;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export {
|
|
74
|
+
readAnonKey,
|
|
75
|
+
getOrCreateAnonKey
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=chunk-ZRNG36LU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/anon-key.ts"],"sourcesContent":["import { readFile, writeFile, mkdir, chmod } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { AnonApiKeySchema, createAnonApiKey } from \"@glasstrace/protocol\";\nimport type { AnonApiKey } from \"@glasstrace/protocol\";\n\nconst GLASSTRACE_DIR = \".glasstrace\";\nconst ANON_KEY_FILE = \"anon_key\";\n\n/**\n * In-memory cache for ephemeral keys when filesystem persistence fails.\n * Keyed by resolved project root to support multiple roots in tests.\n */\nconst ephemeralKeyCache = new Map<string, AnonApiKey>();\n\n/**\n * Reads an existing anonymous key from the filesystem.\n * Returns the key if valid, or null if:\n * - The file does not exist\n * - The file content is invalid\n * - An I/O error occurs\n */\nexport async function readAnonKey(projectRoot?: string): Promise<AnonApiKey | null> {\n const root = projectRoot ?? process.cwd();\n const keyPath = join(root, GLASSTRACE_DIR, ANON_KEY_FILE);\n\n try {\n const content = await readFile(keyPath, \"utf-8\");\n const result = AnonApiKeySchema.safeParse(content);\n if (result.success) {\n return result.data;\n }\n } catch {\n // Fall through to check ephemeral cache\n }\n\n // Check in-memory cache (used when filesystem persistence failed)\n const cached = ephemeralKeyCache.get(root);\n if (cached !== undefined) {\n return cached;\n }\n\n return null;\n}\n\n/**\n * Gets an existing anonymous key from the filesystem, or creates a new one.\n *\n * - If file exists and contains a valid key, returns it\n * - If file does not exist or content is invalid, generates a new key via createAnonApiKey()\n * - Writes the new key to `.glasstrace/anon_key`, creating the directory if needed\n * - On file write failure: logs a warning, caches an ephemeral in-memory key so\n * repeated calls in the same process return the same key\n */\nexport async function getOrCreateAnonKey(projectRoot?: string): Promise<AnonApiKey> {\n const root = projectRoot ?? process.cwd();\n const dirPath = join(root, GLASSTRACE_DIR);\n const keyPath = join(dirPath, ANON_KEY_FILE);\n\n // Try reading existing key from filesystem\n const existingKey = await readAnonKey(root);\n if (existingKey !== null) {\n return existingKey;\n }\n\n // Check in-memory cache (used when filesystem is unavailable)\n const cached = ephemeralKeyCache.get(root);\n if (cached !== undefined) {\n return cached;\n }\n\n // Generate a new key\n const newKey = createAnonApiKey();\n\n // Persist to filesystem using atomic create-or-fail (O_CREAT | O_EXCL)\n // to prevent TOCTOU races where concurrent cold starts both generate keys.\n try {\n await mkdir(dirPath, { recursive: true, mode: 0o700 });\n await writeFile(keyPath, newKey, { flag: \"wx\", mode: 0o600 });\n return newKey;\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === \"EEXIST\") {\n // Another process won the race. Retry reading their key with\n // short delays — the winner's writeFile is atomic for small\n // payloads but the filesystem may not have flushed yet.\n for (let attempt = 0; attempt < 3; attempt++) {\n const winnerKey = await readAnonKey(root);\n if (winnerKey !== null) {\n return winnerKey;\n }\n // Short delay before next retry (50ms), skip after final attempt\n if (attempt < 2) {\n await new Promise((resolve) => setTimeout(resolve, 50));\n }\n }\n // All retries exhausted — overwrite as last resort.\n // Use explicit chmod after overwrite since writeFile mode only\n // applies on creation on some platforms.\n try {\n await writeFile(keyPath, newKey, { mode: 0o600 });\n await chmod(keyPath, 0o600);\n return newKey;\n } catch {\n // Overwrite failed — fall through to ephemeral cache\n }\n }\n\n // Non-EEXIST error (EACCES, ENOTDIR, etc.) — cache in memory so\n // repeated calls get the same ephemeral key within this process.\n ephemeralKeyCache.set(root, newKey);\n console.warn(\n `[glasstrace] Failed to persist anonymous key to ${keyPath}: ${err instanceof Error ? err.message : String(err)}. Using ephemeral key.`,\n );\n return newKey;\n }\n}\n"],"mappings":";;;;;;AAAA,SAAS,UAAU,WAAW,OAAO,aAAa;AAClD,SAAS,YAAY;AAIrB,IAAM,iBAAiB;AACvB,IAAM,gBAAgB;AAMtB,IAAM,oBAAoB,oBAAI,IAAwB;AAStD,eAAsB,YAAY,aAAkD;AAClF,QAAM,OAAO,eAAe,QAAQ,IAAI;AACxC,QAAM,UAAU,KAAK,MAAM,gBAAgB,aAAa;AAExD,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,SAAS,OAAO;AAC/C,UAAM,SAAS,iBAAiB,UAAU,OAAO;AACjD,QAAI,OAAO,SAAS;AAClB,aAAO,OAAO;AAAA,IAChB;AAAA,EACF,QAAQ;AAAA,EAER;AAGA,QAAM,SAAS,kBAAkB,IAAI,IAAI;AACzC,MAAI,WAAW,QAAW;AACxB,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAWA,eAAsB,mBAAmB,aAA2C;AAClF,QAAM,OAAO,eAAe,QAAQ,IAAI;AACxC,QAAM,UAAU,KAAK,MAAM,cAAc;AACzC,QAAM,UAAU,KAAK,SAAS,aAAa;AAG3C,QAAM,cAAc,MAAM,YAAY,IAAI;AAC1C,MAAI,gBAAgB,MAAM;AACxB,WAAO;AAAA,EACT;AAGA,QAAM,SAAS,kBAAkB,IAAI,IAAI;AACzC,MAAI,WAAW,QAAW;AACxB,WAAO;AAAA,EACT;AAGA,QAAM,SAAS,iBAAiB;AAIhC,MAAI;AACF,UAAM,MAAM,SAAS,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AACrD,UAAM,UAAU,SAAS,QAAQ,EAAE,MAAM,MAAM,MAAM,IAAM,CAAC;AAC5D,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,UAAM,OAAQ,IAA8B;AAC5C,QAAI,SAAS,UAAU;AAIrB,eAAS,UAAU,GAAG,UAAU,GAAG,WAAW;AAC5C,cAAM,YAAY,MAAM,YAAY,IAAI;AACxC,YAAI,cAAc,MAAM;AACtB,iBAAO;AAAA,QACT;AAEA,YAAI,UAAU,GAAG;AACf,gBAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAAA,QACxD;AAAA,MACF;AAIA,UAAI;AACF,cAAM,UAAU,SAAS,QAAQ,EAAE,MAAM,IAAM,CAAC;AAChD,cAAM,MAAM,SAAS,GAAK;AAC1B,eAAO;AAAA,MACT,QAAQ;AAAA,MAER;AAAA,IACF;AAIA,sBAAkB,IAAI,MAAM,MAAM;AAClC,YAAQ;AAAA,MACN,mDAAmD,OAAO,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IACjH;AACA,WAAO;AAAA,EACT;AACF;","names":[]}
|
package/dist/cli/init.cjs
CHANGED
|
@@ -15658,6 +15658,7 @@ var init_mcp_add = __esm({
|
|
|
15658
15658
|
// src/cli/uninit.ts
|
|
15659
15659
|
var uninit_exports = {};
|
|
15660
15660
|
__export(uninit_exports, {
|
|
15661
|
+
findMatchingDelimiter: () => findMatchingDelimiter,
|
|
15661
15662
|
findMatchingParen: () => findMatchingParen,
|
|
15662
15663
|
isInitCreatedInstrumentation: () => isInitCreatedInstrumentation,
|
|
15663
15664
|
processJsonMcpConfig: () => processJsonMcpConfig,
|
|
@@ -15666,23 +15667,64 @@ __export(uninit_exports, {
|
|
|
15666
15667
|
removeMarkerSection: () => removeMarkerSection,
|
|
15667
15668
|
removeRegisterGlasstrace: () => removeRegisterGlasstrace,
|
|
15668
15669
|
runUninit: () => runUninit,
|
|
15670
|
+
skipString: () => skipString,
|
|
15669
15671
|
unwrapCJSExport: () => unwrapCJSExport,
|
|
15670
15672
|
unwrapExport: () => unwrapExport
|
|
15671
15673
|
});
|
|
15672
|
-
function
|
|
15674
|
+
function skipString(text, start, quote) {
|
|
15675
|
+
let i = start + 1;
|
|
15676
|
+
while (i < text.length) {
|
|
15677
|
+
if (text[i] === "\\") {
|
|
15678
|
+
i += 2;
|
|
15679
|
+
continue;
|
|
15680
|
+
}
|
|
15681
|
+
if (text[i] === quote) {
|
|
15682
|
+
return i + 1;
|
|
15683
|
+
}
|
|
15684
|
+
i++;
|
|
15685
|
+
}
|
|
15686
|
+
return text.length;
|
|
15687
|
+
}
|
|
15688
|
+
function findMatchingDelimiter(text, openPos, openChar, closeChar) {
|
|
15673
15689
|
let depth = 0;
|
|
15674
|
-
|
|
15675
|
-
|
|
15690
|
+
let i = openPos;
|
|
15691
|
+
while (i < text.length) {
|
|
15692
|
+
const ch = text[i];
|
|
15693
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
15694
|
+
i = skipString(text, i, ch);
|
|
15695
|
+
continue;
|
|
15696
|
+
}
|
|
15697
|
+
if (ch === "/" && text[i + 1] === "/") {
|
|
15698
|
+
const newline = text.indexOf("\n", i);
|
|
15699
|
+
if (newline === -1) {
|
|
15700
|
+
return -1;
|
|
15701
|
+
}
|
|
15702
|
+
i = newline + 1;
|
|
15703
|
+
continue;
|
|
15704
|
+
}
|
|
15705
|
+
if (ch === "/" && text[i + 1] === "*") {
|
|
15706
|
+
const end = text.indexOf("*/", i + 2);
|
|
15707
|
+
if (end === -1) {
|
|
15708
|
+
return -1;
|
|
15709
|
+
}
|
|
15710
|
+
i = end + 2;
|
|
15711
|
+
continue;
|
|
15712
|
+
}
|
|
15713
|
+
if (ch === openChar) {
|
|
15676
15714
|
depth++;
|
|
15677
|
-
} else if (
|
|
15715
|
+
} else if (ch === closeChar) {
|
|
15678
15716
|
depth--;
|
|
15679
15717
|
if (depth === 0) {
|
|
15680
15718
|
return i;
|
|
15681
15719
|
}
|
|
15682
15720
|
}
|
|
15721
|
+
i++;
|
|
15683
15722
|
}
|
|
15684
15723
|
return -1;
|
|
15685
15724
|
}
|
|
15725
|
+
function findMatchingParen(text, openPos) {
|
|
15726
|
+
return findMatchingDelimiter(text, openPos, "(", ")");
|
|
15727
|
+
}
|
|
15686
15728
|
function unwrapExport(content) {
|
|
15687
15729
|
const pattern = /export\s+default\s+withGlasstraceConfig\s*\(/;
|
|
15688
15730
|
const match = pattern.exec(content);
|
|
@@ -15813,18 +15855,7 @@ function isInitCreatedInstrumentation(content) {
|
|
|
15813
15855
|
return topLevelBefore.length === 0 && topLevelAfter.length === 0;
|
|
15814
15856
|
}
|
|
15815
15857
|
function findMatchingBrace(text, openPos) {
|
|
15816
|
-
|
|
15817
|
-
for (let i = openPos; i < text.length; i++) {
|
|
15818
|
-
if (text[i] === "{") {
|
|
15819
|
-
depth++;
|
|
15820
|
-
} else if (text[i] === "}") {
|
|
15821
|
-
depth--;
|
|
15822
|
-
if (depth === 0) {
|
|
15823
|
-
return i;
|
|
15824
|
-
}
|
|
15825
|
-
}
|
|
15826
|
-
}
|
|
15827
|
-
return -1;
|
|
15858
|
+
return findMatchingDelimiter(text, openPos, "{", "}");
|
|
15828
15859
|
}
|
|
15829
15860
|
function removeRegisterGlasstrace(content) {
|
|
15830
15861
|
let result = content;
|
|
@@ -16134,16 +16165,22 @@ async function runUninit(options) {
|
|
|
16134
16165
|
if (fs5.existsSync(windsurfConfigPath)) {
|
|
16135
16166
|
const content = fs5.readFileSync(windsurfConfigPath, "utf-8");
|
|
16136
16167
|
const windsurfResult = processJsonMcpConfig(content);
|
|
16168
|
+
const home = os.homedir();
|
|
16169
|
+
const displayPath = windsurfConfigPath.startsWith(home) ? "~" + windsurfConfigPath.slice(home.length) : windsurfConfigPath;
|
|
16137
16170
|
if (windsurfResult.action === "deleted") {
|
|
16138
16171
|
if (!dryRun) {
|
|
16139
16172
|
fs5.unlinkSync(windsurfConfigPath);
|
|
16140
16173
|
}
|
|
16141
|
-
summary.push(
|
|
16174
|
+
summary.push(
|
|
16175
|
+
`${prefix}Deleted global Windsurf config (${displayPath})`
|
|
16176
|
+
);
|
|
16142
16177
|
} else if (windsurfResult.action === "removed-key" && windsurfResult.content !== void 0) {
|
|
16143
16178
|
if (!dryRun) {
|
|
16144
16179
|
fs5.writeFileSync(windsurfConfigPath, windsurfResult.content, "utf-8");
|
|
16145
16180
|
}
|
|
16146
|
-
summary.push(
|
|
16181
|
+
summary.push(
|
|
16182
|
+
`${prefix}Removed glasstrace from global Windsurf config (${displayPath})`
|
|
16183
|
+
);
|
|
16147
16184
|
}
|
|
16148
16185
|
}
|
|
16149
16186
|
}
|