@glasstrace/sdk 0.14.2 → 0.15.1
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-A2AZL6MZ.js +309 -0
- package/dist/chunk-A2AZL6MZ.js.map +1 -0
- package/dist/{chunk-ARAOZCZT.js → chunk-ROFOJQWN.js} +118 -16
- package/dist/chunk-ROFOJQWN.js.map +1 -0
- package/dist/{chunk-WV3NIPWJ.js → chunk-ZNOD6FC7.js} +18 -276
- package/dist/chunk-ZNOD6FC7.js.map +1 -0
- package/dist/cli/init.cjs +458 -115
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.d.cts +33 -1
- package/dist/cli/init.d.ts +33 -1
- package/dist/cli/init.js +144 -42
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/mcp-add.cjs.map +1 -1
- package/dist/cli/mcp-add.js +4 -2
- package/dist/cli/mcp-add.js.map +1 -1
- package/dist/cli/uninit.cjs +181 -60
- package/dist/cli/uninit.cjs.map +1 -1
- package/dist/cli/uninit.d.cts +38 -8
- package/dist/cli/uninit.d.ts +38 -8
- package/dist/cli/uninit.js +6 -3
- package/dist/cli/validate.cjs +135 -0
- package/dist/cli/validate.cjs.map +1 -0
- package/dist/cli/validate.d.cts +60 -0
- package/dist/cli/validate.d.ts +60 -0
- package/dist/cli/validate.js +103 -0
- package/dist/cli/validate.js.map +1 -0
- package/dist/index.cjs +76 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +76 -39
- package/dist/index.js.map +1 -1
- package/package.json +6 -4
- package/dist/chunk-ARAOZCZT.js.map +0 -1
- package/dist/chunk-WV3NIPWJ.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/cli/validate.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\n/**\n * A single artifact-state inconsistency detected by `sdk init --validate`.\n */\nexport interface ValidationIssue {\n /** Stable machine-readable identifier for the issue class. */\n code:\n | \"glasstrace-dir-without-register-import\"\n | \"sdk-import-without-glasstrace-dir\"\n | \"mcp-marker-without-configs\"\n | \"mcp-configs-without-marker\";\n /** Human-readable message describing the inconsistency. */\n message: string;\n /** Suggested command or manual action to resolve the issue. */\n fix: string;\n}\n\n/** Options for `runValidate`. */\nexport interface ValidateOptions {\n projectRoot: string;\n}\n\n/** Structured result of running the validator. */\nexport interface ValidateResult {\n /** Zero when no issues; non-zero when any issue is detected. */\n exitCode: number;\n /** Ordered lines of human-friendly summary output. */\n summary: string[];\n /** Detailed per-issue findings. */\n issues: ValidationIssue[];\n}\n\n/** MCP config files init may create. Used to detect stale state. */\nconst MCP_CONFIG_CANDIDATES = [\n \".mcp.json\",\n \".cursor/mcp.json\",\n \".gemini/settings.json\",\n \".codex/config.toml\",\n] as const;\n\n/**\n * Returns true when the given instrumentation file imports\n * `@glasstrace/sdk` (which includes the `registerGlasstrace` import\n * emitted by `sdk init`).\n *\n * @internal Exported for unit testing only.\n */\nexport function hasGlasstraceImport(content: string): boolean {\n return /@glasstrace\\/sdk/.test(content);\n}\n\n/**\n * Returns true when the file imports `registerGlasstrace` specifically\n * (as opposed to other named exports such as `withGlasstraceConfig`).\n *\n * @internal Exported for unit testing only.\n */\nexport function hasRegisterGlasstraceImport(content: string): boolean {\n // Single- or multi-specifier imports from @glasstrace/sdk that include\n // `registerGlasstrace` as a named export.\n const match = /import\\s*\\{([^}]+)\\}\\s*from\\s*[\"']@glasstrace\\/sdk[\"']/;\n const importMatch = match.exec(content);\n if (!importMatch) return false;\n return importMatch[1]\n .split(\",\")\n .map((s) => s.trim())\n .includes(\"registerGlasstrace\");\n}\n\n/**\n * Validates consistency between the filesystem artifacts that `sdk init`\n * produces (DISC-1247 Scenario 4). Detects four classes of inconsistency:\n *\n * 1. `.glasstrace/` exists but `instrumentation.ts` does not import\n * `registerGlasstrace` from `@glasstrace/sdk`.\n * 2. `.glasstrace/` is missing but `instrumentation.ts` still imports\n * from `@glasstrace/sdk`.\n * 3. `.glasstrace/mcp-connected` marker exists but no MCP config files.\n * 4. MCP config files exist but no `.glasstrace/mcp-connected` marker.\n *\n * Each issue includes a stable `code`, a message, and a suggested fix.\n * Exit code is non-zero whenever any issue is detected so CI pipelines\n * can gate on `sdk init --validate`.\n *\n * @param options - Configuration for the validator.\n * @returns A structured result describing detected inconsistencies.\n */\nexport function runValidate(options: ValidateOptions): ValidateResult {\n const { projectRoot } = options;\n const issues: ValidationIssue[] = [];\n\n const glasstraceDir = path.join(projectRoot, \".glasstrace\");\n const instrumentationPath = path.join(projectRoot, \"instrumentation.ts\");\n const markerPath = path.join(glasstraceDir, \"mcp-connected\");\n\n const glasstraceDirExists = isDirectorySafe(glasstraceDir);\n const instrumentationExists = fs.existsSync(instrumentationPath);\n const instrumentationContent = instrumentationExists\n ? safeReadFile(instrumentationPath)\n : null;\n const markerExists = fs.existsSync(markerPath);\n\n const mcpConfigsPresent = MCP_CONFIG_CANDIDATES.filter((rel) =>\n fs.existsSync(path.join(projectRoot, rel)),\n );\n\n // 1. .glasstrace/ present but instrumentation missing the SDK import\n if (glasstraceDirExists) {\n if (\n instrumentationContent === null ||\n !hasRegisterGlasstraceImport(instrumentationContent)\n ) {\n issues.push({\n code: \"glasstrace-dir-without-register-import\",\n message:\n \".glasstrace/ exists but instrumentation.ts is missing the registerGlasstrace import.\",\n fix: \"Run `npx glasstrace init` to re-scaffold instrumentation.ts, or remove .glasstrace/ if the SDK is no longer in use.\",\n });\n }\n }\n\n // 2. .glasstrace/ missing but instrumentation still imports the SDK\n if (!glasstraceDirExists && instrumentationContent !== null) {\n if (hasGlasstraceImport(instrumentationContent)) {\n issues.push({\n code: \"sdk-import-without-glasstrace-dir\",\n message:\n \"instrumentation.ts imports from @glasstrace/sdk but .glasstrace/ is missing.\",\n fix: \"Run `npx glasstrace init` to recreate .glasstrace/, or `npx glasstrace uninit` to fully remove the SDK.\",\n });\n }\n }\n\n // 3. MCP marker present but no MCP config files exist\n if (markerExists && mcpConfigsPresent.length === 0) {\n issues.push({\n code: \"mcp-marker-without-configs\",\n message:\n \".glasstrace/mcp-connected marker is present but no MCP config files were found.\",\n fix: \"Run `npx glasstrace mcp add --force` to regenerate MCP configs, or delete .glasstrace/mcp-connected.\",\n });\n }\n\n // 4. MCP config files exist but no marker\n if (!markerExists && mcpConfigsPresent.length > 0) {\n issues.push({\n code: \"mcp-configs-without-marker\",\n message: `MCP config files exist (${mcpConfigsPresent.join(\", \")}) but .glasstrace/mcp-connected marker is missing.`,\n fix: \"Run `npx glasstrace init` to re-register the marker, or `npx glasstrace uninit` to fully remove MCP configuration.\",\n });\n }\n\n const summary: string[] = [];\n if (issues.length === 0) {\n summary.push(\"Glasstrace install state is consistent.\");\n } else {\n summary.push(\n `Detected ${issues.length} inconsistenc${issues.length === 1 ? \"y\" : \"ies\"} in Glasstrace install state:`,\n );\n }\n\n return {\n exitCode: issues.length > 0 ? 1 : 0,\n summary,\n issues,\n };\n}\n\n/**\n * Reads a file as UTF-8, returning `null` if the file cannot be read.\n */\nfunction safeReadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf-8\");\n } catch {\n return null;\n }\n}\n\n/**\n * Returns true when the path exists and is a directory. Returns false\n * when the path is missing, is not a directory, or when `statSync`\n * throws (permission denied, TOCTOU race between existsSync and\n * statSync, etc). Validation is best-effort and must not throw — a\n * crash here would turn a reporting tool into a hard failure.\n */\nfunction isDirectorySafe(dirPath: string): boolean {\n try {\n if (!fs.existsSync(dirPath)) return false;\n return fs.statSync(dirPath).isDirectory();\n } catch {\n return false;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAoB;AACpB,WAAsB;AAkCtB,IAAM,wBAAwB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AASO,SAAS,oBAAoB,SAA0B;AAC5D,SAAO,mBAAmB,KAAK,OAAO;AACxC;AAQO,SAAS,4BAA4B,SAA0B;AAGpE,QAAM,QAAQ;AACd,QAAM,cAAc,MAAM,KAAK,OAAO;AACtC,MAAI,CAAC,YAAa,QAAO;AACzB,SAAO,YAAY,CAAC,EACjB,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,SAAS,oBAAoB;AAClC;AAoBO,SAAS,YAAY,SAA0C;AACpE,QAAM,EAAE,YAAY,IAAI;AACxB,QAAM,SAA4B,CAAC;AAEnC,QAAM,gBAAqB,UAAK,aAAa,aAAa;AAC1D,QAAM,sBAA2B,UAAK,aAAa,oBAAoB;AACvE,QAAM,aAAkB,UAAK,eAAe,eAAe;AAE3D,QAAM,sBAAsB,gBAAgB,aAAa;AACzD,QAAM,wBAA2B,cAAW,mBAAmB;AAC/D,QAAM,yBAAyB,wBAC3B,aAAa,mBAAmB,IAChC;AACJ,QAAM,eAAkB,cAAW,UAAU;AAE7C,QAAM,oBAAoB,sBAAsB;AAAA,IAAO,CAAC,QACnD,cAAgB,UAAK,aAAa,GAAG,CAAC;AAAA,EAC3C;AAGA,MAAI,qBAAqB;AACvB,QACE,2BAA2B,QAC3B,CAAC,4BAA4B,sBAAsB,GACnD;AACA,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,SACE;AAAA,QACF,KAAK;AAAA,MACP,CAAC;AAAA,IACH;AAAA,EACF;AAGA,MAAI,CAAC,uBAAuB,2BAA2B,MAAM;AAC3D,QAAI,oBAAoB,sBAAsB,GAAG;AAC/C,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,SACE;AAAA,QACF,KAAK;AAAA,MACP,CAAC;AAAA,IACH;AAAA,EACF;AAGA,MAAI,gBAAgB,kBAAkB,WAAW,GAAG;AAClD,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,SACE;AAAA,MACF,KAAK;AAAA,IACP,CAAC;AAAA,EACH;AAGA,MAAI,CAAC,gBAAgB,kBAAkB,SAAS,GAAG;AACjD,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,SAAS,2BAA2B,kBAAkB,KAAK,IAAI,CAAC;AAAA,MAChE,KAAK;AAAA,IACP,CAAC;AAAA,EACH;AAEA,QAAM,UAAoB,CAAC;AAC3B,MAAI,OAAO,WAAW,GAAG;AACvB,YAAQ,KAAK,yCAAyC;AAAA,EACxD,OAAO;AACL,YAAQ;AAAA,MACN,YAAY,OAAO,MAAM,gBAAgB,OAAO,WAAW,IAAI,MAAM,KAAK;AAAA,IAC5E;AAAA,EACF;AAEA,SAAO;AAAA,IACL,UAAU,OAAO,SAAS,IAAI,IAAI;AAAA,IAClC;AAAA,IACA;AAAA,EACF;AACF;AAKA,SAAS,aAAa,UAAiC;AACrD,MAAI;AACF,WAAU,gBAAa,UAAU,OAAO;AAAA,EAC1C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AASA,SAAS,gBAAgB,SAA0B;AACjD,MAAI;AACF,QAAI,CAAI,cAAW,OAAO,EAAG,QAAO;AACpC,WAAU,YAAS,OAAO,EAAE,YAAY;AAAA,EAC1C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A single artifact-state inconsistency detected by `sdk init --validate`.
|
|
3
|
+
*/
|
|
4
|
+
interface ValidationIssue {
|
|
5
|
+
/** Stable machine-readable identifier for the issue class. */
|
|
6
|
+
code: "glasstrace-dir-without-register-import" | "sdk-import-without-glasstrace-dir" | "mcp-marker-without-configs" | "mcp-configs-without-marker";
|
|
7
|
+
/** Human-readable message describing the inconsistency. */
|
|
8
|
+
message: string;
|
|
9
|
+
/** Suggested command or manual action to resolve the issue. */
|
|
10
|
+
fix: string;
|
|
11
|
+
}
|
|
12
|
+
/** Options for `runValidate`. */
|
|
13
|
+
interface ValidateOptions {
|
|
14
|
+
projectRoot: string;
|
|
15
|
+
}
|
|
16
|
+
/** Structured result of running the validator. */
|
|
17
|
+
interface ValidateResult {
|
|
18
|
+
/** Zero when no issues; non-zero when any issue is detected. */
|
|
19
|
+
exitCode: number;
|
|
20
|
+
/** Ordered lines of human-friendly summary output. */
|
|
21
|
+
summary: string[];
|
|
22
|
+
/** Detailed per-issue findings. */
|
|
23
|
+
issues: ValidationIssue[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Returns true when the given instrumentation file imports
|
|
27
|
+
* `@glasstrace/sdk` (which includes the `registerGlasstrace` import
|
|
28
|
+
* emitted by `sdk init`).
|
|
29
|
+
*
|
|
30
|
+
* @internal Exported for unit testing only.
|
|
31
|
+
*/
|
|
32
|
+
declare function hasGlasstraceImport(content: string): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Returns true when the file imports `registerGlasstrace` specifically
|
|
35
|
+
* (as opposed to other named exports such as `withGlasstraceConfig`).
|
|
36
|
+
*
|
|
37
|
+
* @internal Exported for unit testing only.
|
|
38
|
+
*/
|
|
39
|
+
declare function hasRegisterGlasstraceImport(content: string): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Validates consistency between the filesystem artifacts that `sdk init`
|
|
42
|
+
* produces (DISC-1247 Scenario 4). Detects four classes of inconsistency:
|
|
43
|
+
*
|
|
44
|
+
* 1. `.glasstrace/` exists but `instrumentation.ts` does not import
|
|
45
|
+
* `registerGlasstrace` from `@glasstrace/sdk`.
|
|
46
|
+
* 2. `.glasstrace/` is missing but `instrumentation.ts` still imports
|
|
47
|
+
* from `@glasstrace/sdk`.
|
|
48
|
+
* 3. `.glasstrace/mcp-connected` marker exists but no MCP config files.
|
|
49
|
+
* 4. MCP config files exist but no `.glasstrace/mcp-connected` marker.
|
|
50
|
+
*
|
|
51
|
+
* Each issue includes a stable `code`, a message, and a suggested fix.
|
|
52
|
+
* Exit code is non-zero whenever any issue is detected so CI pipelines
|
|
53
|
+
* can gate on `sdk init --validate`.
|
|
54
|
+
*
|
|
55
|
+
* @param options - Configuration for the validator.
|
|
56
|
+
* @returns A structured result describing detected inconsistencies.
|
|
57
|
+
*/
|
|
58
|
+
declare function runValidate(options: ValidateOptions): ValidateResult;
|
|
59
|
+
|
|
60
|
+
export { type ValidateOptions, type ValidateResult, type ValidationIssue, hasGlasstraceImport, hasRegisterGlasstraceImport, runValidate };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A single artifact-state inconsistency detected by `sdk init --validate`.
|
|
3
|
+
*/
|
|
4
|
+
interface ValidationIssue {
|
|
5
|
+
/** Stable machine-readable identifier for the issue class. */
|
|
6
|
+
code: "glasstrace-dir-without-register-import" | "sdk-import-without-glasstrace-dir" | "mcp-marker-without-configs" | "mcp-configs-without-marker";
|
|
7
|
+
/** Human-readable message describing the inconsistency. */
|
|
8
|
+
message: string;
|
|
9
|
+
/** Suggested command or manual action to resolve the issue. */
|
|
10
|
+
fix: string;
|
|
11
|
+
}
|
|
12
|
+
/** Options for `runValidate`. */
|
|
13
|
+
interface ValidateOptions {
|
|
14
|
+
projectRoot: string;
|
|
15
|
+
}
|
|
16
|
+
/** Structured result of running the validator. */
|
|
17
|
+
interface ValidateResult {
|
|
18
|
+
/** Zero when no issues; non-zero when any issue is detected. */
|
|
19
|
+
exitCode: number;
|
|
20
|
+
/** Ordered lines of human-friendly summary output. */
|
|
21
|
+
summary: string[];
|
|
22
|
+
/** Detailed per-issue findings. */
|
|
23
|
+
issues: ValidationIssue[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Returns true when the given instrumentation file imports
|
|
27
|
+
* `@glasstrace/sdk` (which includes the `registerGlasstrace` import
|
|
28
|
+
* emitted by `sdk init`).
|
|
29
|
+
*
|
|
30
|
+
* @internal Exported for unit testing only.
|
|
31
|
+
*/
|
|
32
|
+
declare function hasGlasstraceImport(content: string): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Returns true when the file imports `registerGlasstrace` specifically
|
|
35
|
+
* (as opposed to other named exports such as `withGlasstraceConfig`).
|
|
36
|
+
*
|
|
37
|
+
* @internal Exported for unit testing only.
|
|
38
|
+
*/
|
|
39
|
+
declare function hasRegisterGlasstraceImport(content: string): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Validates consistency between the filesystem artifacts that `sdk init`
|
|
42
|
+
* produces (DISC-1247 Scenario 4). Detects four classes of inconsistency:
|
|
43
|
+
*
|
|
44
|
+
* 1. `.glasstrace/` exists but `instrumentation.ts` does not import
|
|
45
|
+
* `registerGlasstrace` from `@glasstrace/sdk`.
|
|
46
|
+
* 2. `.glasstrace/` is missing but `instrumentation.ts` still imports
|
|
47
|
+
* from `@glasstrace/sdk`.
|
|
48
|
+
* 3. `.glasstrace/mcp-connected` marker exists but no MCP config files.
|
|
49
|
+
* 4. MCP config files exist but no `.glasstrace/mcp-connected` marker.
|
|
50
|
+
*
|
|
51
|
+
* Each issue includes a stable `code`, a message, and a suggested fix.
|
|
52
|
+
* Exit code is non-zero whenever any issue is detected so CI pipelines
|
|
53
|
+
* can gate on `sdk init --validate`.
|
|
54
|
+
*
|
|
55
|
+
* @param options - Configuration for the validator.
|
|
56
|
+
* @returns A structured result describing detected inconsistencies.
|
|
57
|
+
*/
|
|
58
|
+
declare function runValidate(options: ValidateOptions): ValidateResult;
|
|
59
|
+
|
|
60
|
+
export { type ValidateOptions, type ValidateResult, type ValidationIssue, hasGlasstraceImport, hasRegisterGlasstraceImport, runValidate };
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import {
|
|
2
|
+
init_esm_shims
|
|
3
|
+
} from "../chunk-BGZ7J74D.js";
|
|
4
|
+
|
|
5
|
+
// src/cli/validate.ts
|
|
6
|
+
init_esm_shims();
|
|
7
|
+
import * as fs from "fs";
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
var MCP_CONFIG_CANDIDATES = [
|
|
10
|
+
".mcp.json",
|
|
11
|
+
".cursor/mcp.json",
|
|
12
|
+
".gemini/settings.json",
|
|
13
|
+
".codex/config.toml"
|
|
14
|
+
];
|
|
15
|
+
function hasGlasstraceImport(content) {
|
|
16
|
+
return /@glasstrace\/sdk/.test(content);
|
|
17
|
+
}
|
|
18
|
+
function hasRegisterGlasstraceImport(content) {
|
|
19
|
+
const match = /import\s*\{([^}]+)\}\s*from\s*["']@glasstrace\/sdk["']/;
|
|
20
|
+
const importMatch = match.exec(content);
|
|
21
|
+
if (!importMatch) return false;
|
|
22
|
+
return importMatch[1].split(",").map((s) => s.trim()).includes("registerGlasstrace");
|
|
23
|
+
}
|
|
24
|
+
function runValidate(options) {
|
|
25
|
+
const { projectRoot } = options;
|
|
26
|
+
const issues = [];
|
|
27
|
+
const glasstraceDir = path.join(projectRoot, ".glasstrace");
|
|
28
|
+
const instrumentationPath = path.join(projectRoot, "instrumentation.ts");
|
|
29
|
+
const markerPath = path.join(glasstraceDir, "mcp-connected");
|
|
30
|
+
const glasstraceDirExists = isDirectorySafe(glasstraceDir);
|
|
31
|
+
const instrumentationExists = fs.existsSync(instrumentationPath);
|
|
32
|
+
const instrumentationContent = instrumentationExists ? safeReadFile(instrumentationPath) : null;
|
|
33
|
+
const markerExists = fs.existsSync(markerPath);
|
|
34
|
+
const mcpConfigsPresent = MCP_CONFIG_CANDIDATES.filter(
|
|
35
|
+
(rel) => fs.existsSync(path.join(projectRoot, rel))
|
|
36
|
+
);
|
|
37
|
+
if (glasstraceDirExists) {
|
|
38
|
+
if (instrumentationContent === null || !hasRegisterGlasstraceImport(instrumentationContent)) {
|
|
39
|
+
issues.push({
|
|
40
|
+
code: "glasstrace-dir-without-register-import",
|
|
41
|
+
message: ".glasstrace/ exists but instrumentation.ts is missing the registerGlasstrace import.",
|
|
42
|
+
fix: "Run `npx glasstrace init` to re-scaffold instrumentation.ts, or remove .glasstrace/ if the SDK is no longer in use."
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (!glasstraceDirExists && instrumentationContent !== null) {
|
|
47
|
+
if (hasGlasstraceImport(instrumentationContent)) {
|
|
48
|
+
issues.push({
|
|
49
|
+
code: "sdk-import-without-glasstrace-dir",
|
|
50
|
+
message: "instrumentation.ts imports from @glasstrace/sdk but .glasstrace/ is missing.",
|
|
51
|
+
fix: "Run `npx glasstrace init` to recreate .glasstrace/, or `npx glasstrace uninit` to fully remove the SDK."
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (markerExists && mcpConfigsPresent.length === 0) {
|
|
56
|
+
issues.push({
|
|
57
|
+
code: "mcp-marker-without-configs",
|
|
58
|
+
message: ".glasstrace/mcp-connected marker is present but no MCP config files were found.",
|
|
59
|
+
fix: "Run `npx glasstrace mcp add --force` to regenerate MCP configs, or delete .glasstrace/mcp-connected."
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
if (!markerExists && mcpConfigsPresent.length > 0) {
|
|
63
|
+
issues.push({
|
|
64
|
+
code: "mcp-configs-without-marker",
|
|
65
|
+
message: `MCP config files exist (${mcpConfigsPresent.join(", ")}) but .glasstrace/mcp-connected marker is missing.`,
|
|
66
|
+
fix: "Run `npx glasstrace init` to re-register the marker, or `npx glasstrace uninit` to fully remove MCP configuration."
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
const summary = [];
|
|
70
|
+
if (issues.length === 0) {
|
|
71
|
+
summary.push("Glasstrace install state is consistent.");
|
|
72
|
+
} else {
|
|
73
|
+
summary.push(
|
|
74
|
+
`Detected ${issues.length} inconsistenc${issues.length === 1 ? "y" : "ies"} in Glasstrace install state:`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
exitCode: issues.length > 0 ? 1 : 0,
|
|
79
|
+
summary,
|
|
80
|
+
issues
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function safeReadFile(filePath) {
|
|
84
|
+
try {
|
|
85
|
+
return fs.readFileSync(filePath, "utf-8");
|
|
86
|
+
} catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function isDirectorySafe(dirPath) {
|
|
91
|
+
try {
|
|
92
|
+
if (!fs.existsSync(dirPath)) return false;
|
|
93
|
+
return fs.statSync(dirPath).isDirectory();
|
|
94
|
+
} catch {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
export {
|
|
99
|
+
hasGlasstraceImport,
|
|
100
|
+
hasRegisterGlasstraceImport,
|
|
101
|
+
runValidate
|
|
102
|
+
};
|
|
103
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/cli/validate.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\n/**\n * A single artifact-state inconsistency detected by `sdk init --validate`.\n */\nexport interface ValidationIssue {\n /** Stable machine-readable identifier for the issue class. */\n code:\n | \"glasstrace-dir-without-register-import\"\n | \"sdk-import-without-glasstrace-dir\"\n | \"mcp-marker-without-configs\"\n | \"mcp-configs-without-marker\";\n /** Human-readable message describing the inconsistency. */\n message: string;\n /** Suggested command or manual action to resolve the issue. */\n fix: string;\n}\n\n/** Options for `runValidate`. */\nexport interface ValidateOptions {\n projectRoot: string;\n}\n\n/** Structured result of running the validator. */\nexport interface ValidateResult {\n /** Zero when no issues; non-zero when any issue is detected. */\n exitCode: number;\n /** Ordered lines of human-friendly summary output. */\n summary: string[];\n /** Detailed per-issue findings. */\n issues: ValidationIssue[];\n}\n\n/** MCP config files init may create. Used to detect stale state. */\nconst MCP_CONFIG_CANDIDATES = [\n \".mcp.json\",\n \".cursor/mcp.json\",\n \".gemini/settings.json\",\n \".codex/config.toml\",\n] as const;\n\n/**\n * Returns true when the given instrumentation file imports\n * `@glasstrace/sdk` (which includes the `registerGlasstrace` import\n * emitted by `sdk init`).\n *\n * @internal Exported for unit testing only.\n */\nexport function hasGlasstraceImport(content: string): boolean {\n return /@glasstrace\\/sdk/.test(content);\n}\n\n/**\n * Returns true when the file imports `registerGlasstrace` specifically\n * (as opposed to other named exports such as `withGlasstraceConfig`).\n *\n * @internal Exported for unit testing only.\n */\nexport function hasRegisterGlasstraceImport(content: string): boolean {\n // Single- or multi-specifier imports from @glasstrace/sdk that include\n // `registerGlasstrace` as a named export.\n const match = /import\\s*\\{([^}]+)\\}\\s*from\\s*[\"']@glasstrace\\/sdk[\"']/;\n const importMatch = match.exec(content);\n if (!importMatch) return false;\n return importMatch[1]\n .split(\",\")\n .map((s) => s.trim())\n .includes(\"registerGlasstrace\");\n}\n\n/**\n * Validates consistency between the filesystem artifacts that `sdk init`\n * produces (DISC-1247 Scenario 4). Detects four classes of inconsistency:\n *\n * 1. `.glasstrace/` exists but `instrumentation.ts` does not import\n * `registerGlasstrace` from `@glasstrace/sdk`.\n * 2. `.glasstrace/` is missing but `instrumentation.ts` still imports\n * from `@glasstrace/sdk`.\n * 3. `.glasstrace/mcp-connected` marker exists but no MCP config files.\n * 4. MCP config files exist but no `.glasstrace/mcp-connected` marker.\n *\n * Each issue includes a stable `code`, a message, and a suggested fix.\n * Exit code is non-zero whenever any issue is detected so CI pipelines\n * can gate on `sdk init --validate`.\n *\n * @param options - Configuration for the validator.\n * @returns A structured result describing detected inconsistencies.\n */\nexport function runValidate(options: ValidateOptions): ValidateResult {\n const { projectRoot } = options;\n const issues: ValidationIssue[] = [];\n\n const glasstraceDir = path.join(projectRoot, \".glasstrace\");\n const instrumentationPath = path.join(projectRoot, \"instrumentation.ts\");\n const markerPath = path.join(glasstraceDir, \"mcp-connected\");\n\n const glasstraceDirExists = isDirectorySafe(glasstraceDir);\n const instrumentationExists = fs.existsSync(instrumentationPath);\n const instrumentationContent = instrumentationExists\n ? safeReadFile(instrumentationPath)\n : null;\n const markerExists = fs.existsSync(markerPath);\n\n const mcpConfigsPresent = MCP_CONFIG_CANDIDATES.filter((rel) =>\n fs.existsSync(path.join(projectRoot, rel)),\n );\n\n // 1. .glasstrace/ present but instrumentation missing the SDK import\n if (glasstraceDirExists) {\n if (\n instrumentationContent === null ||\n !hasRegisterGlasstraceImport(instrumentationContent)\n ) {\n issues.push({\n code: \"glasstrace-dir-without-register-import\",\n message:\n \".glasstrace/ exists but instrumentation.ts is missing the registerGlasstrace import.\",\n fix: \"Run `npx glasstrace init` to re-scaffold instrumentation.ts, or remove .glasstrace/ if the SDK is no longer in use.\",\n });\n }\n }\n\n // 2. .glasstrace/ missing but instrumentation still imports the SDK\n if (!glasstraceDirExists && instrumentationContent !== null) {\n if (hasGlasstraceImport(instrumentationContent)) {\n issues.push({\n code: \"sdk-import-without-glasstrace-dir\",\n message:\n \"instrumentation.ts imports from @glasstrace/sdk but .glasstrace/ is missing.\",\n fix: \"Run `npx glasstrace init` to recreate .glasstrace/, or `npx glasstrace uninit` to fully remove the SDK.\",\n });\n }\n }\n\n // 3. MCP marker present but no MCP config files exist\n if (markerExists && mcpConfigsPresent.length === 0) {\n issues.push({\n code: \"mcp-marker-without-configs\",\n message:\n \".glasstrace/mcp-connected marker is present but no MCP config files were found.\",\n fix: \"Run `npx glasstrace mcp add --force` to regenerate MCP configs, or delete .glasstrace/mcp-connected.\",\n });\n }\n\n // 4. MCP config files exist but no marker\n if (!markerExists && mcpConfigsPresent.length > 0) {\n issues.push({\n code: \"mcp-configs-without-marker\",\n message: `MCP config files exist (${mcpConfigsPresent.join(\", \")}) but .glasstrace/mcp-connected marker is missing.`,\n fix: \"Run `npx glasstrace init` to re-register the marker, or `npx glasstrace uninit` to fully remove MCP configuration.\",\n });\n }\n\n const summary: string[] = [];\n if (issues.length === 0) {\n summary.push(\"Glasstrace install state is consistent.\");\n } else {\n summary.push(\n `Detected ${issues.length} inconsistenc${issues.length === 1 ? \"y\" : \"ies\"} in Glasstrace install state:`,\n );\n }\n\n return {\n exitCode: issues.length > 0 ? 1 : 0,\n summary,\n issues,\n };\n}\n\n/**\n * Reads a file as UTF-8, returning `null` if the file cannot be read.\n */\nfunction safeReadFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf-8\");\n } catch {\n return null;\n }\n}\n\n/**\n * Returns true when the path exists and is a directory. Returns false\n * when the path is missing, is not a directory, or when `statSync`\n * throws (permission denied, TOCTOU race between existsSync and\n * statSync, etc). Validation is best-effort and must not throw — a\n * crash here would turn a reporting tool into a hard failure.\n */\nfunction isDirectorySafe(dirPath: string): boolean {\n try {\n if (!fs.existsSync(dirPath)) return false;\n return fs.statSync(dirPath).isDirectory();\n } catch {\n return false;\n }\n}\n"],"mappings":";;;;;AAAA;AAAA,YAAY,QAAQ;AACpB,YAAY,UAAU;AAkCtB,IAAM,wBAAwB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AASO,SAAS,oBAAoB,SAA0B;AAC5D,SAAO,mBAAmB,KAAK,OAAO;AACxC;AAQO,SAAS,4BAA4B,SAA0B;AAGpE,QAAM,QAAQ;AACd,QAAM,cAAc,MAAM,KAAK,OAAO;AACtC,MAAI,CAAC,YAAa,QAAO;AACzB,SAAO,YAAY,CAAC,EACjB,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,SAAS,oBAAoB;AAClC;AAoBO,SAAS,YAAY,SAA0C;AACpE,QAAM,EAAE,YAAY,IAAI;AACxB,QAAM,SAA4B,CAAC;AAEnC,QAAM,gBAAqB,UAAK,aAAa,aAAa;AAC1D,QAAM,sBAA2B,UAAK,aAAa,oBAAoB;AACvE,QAAM,aAAkB,UAAK,eAAe,eAAe;AAE3D,QAAM,sBAAsB,gBAAgB,aAAa;AACzD,QAAM,wBAA2B,cAAW,mBAAmB;AAC/D,QAAM,yBAAyB,wBAC3B,aAAa,mBAAmB,IAChC;AACJ,QAAM,eAAkB,cAAW,UAAU;AAE7C,QAAM,oBAAoB,sBAAsB;AAAA,IAAO,CAAC,QACnD,cAAgB,UAAK,aAAa,GAAG,CAAC;AAAA,EAC3C;AAGA,MAAI,qBAAqB;AACvB,QACE,2BAA2B,QAC3B,CAAC,4BAA4B,sBAAsB,GACnD;AACA,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,SACE;AAAA,QACF,KAAK;AAAA,MACP,CAAC;AAAA,IACH;AAAA,EACF;AAGA,MAAI,CAAC,uBAAuB,2BAA2B,MAAM;AAC3D,QAAI,oBAAoB,sBAAsB,GAAG;AAC/C,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,SACE;AAAA,QACF,KAAK;AAAA,MACP,CAAC;AAAA,IACH;AAAA,EACF;AAGA,MAAI,gBAAgB,kBAAkB,WAAW,GAAG;AAClD,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,SACE;AAAA,MACF,KAAK;AAAA,IACP,CAAC;AAAA,EACH;AAGA,MAAI,CAAC,gBAAgB,kBAAkB,SAAS,GAAG;AACjD,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,SAAS,2BAA2B,kBAAkB,KAAK,IAAI,CAAC;AAAA,MAChE,KAAK;AAAA,IACP,CAAC;AAAA,EACH;AAEA,QAAM,UAAoB,CAAC;AAC3B,MAAI,OAAO,WAAW,GAAG;AACvB,YAAQ,KAAK,yCAAyC;AAAA,EACxD,OAAO;AACL,YAAQ;AAAA,MACN,YAAY,OAAO,MAAM,gBAAgB,OAAO,WAAW,IAAI,MAAM,KAAK;AAAA,IAC5E;AAAA,EACF;AAEA,SAAO;AAAA,IACL,UAAU,OAAO,SAAS,IAAI,IAAI;AAAA,IAClC;AAAA,IACA;AAAA,EACF;AACF;AAKA,SAAS,aAAa,UAAiC;AACrD,MAAI;AACF,WAAU,gBAAa,UAAU,OAAO;AAAA,EAC1C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AASA,SAAS,gBAAgB,SAA0B;AACjD,MAAI;AACF,QAAI,CAAI,cAAW,OAAO,EAAG,QAAO;AACpC,WAAU,YAAS,OAAO,EAAE,YAAY;AAAA,EAC1C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -17228,6 +17228,7 @@ async function saveCachedConfig(response, projectRoot) {
|
|
|
17228
17228
|
const root = projectRoot ?? process.cwd();
|
|
17229
17229
|
const dirPath = modules.path.join(root, GLASSTRACE_DIR2);
|
|
17230
17230
|
const configPath = modules.path.join(dirPath, CONFIG_FILE);
|
|
17231
|
+
const tmpPath = `${configPath}.tmp`;
|
|
17231
17232
|
try {
|
|
17232
17233
|
await modules.fs.mkdir(dirPath, { recursive: true, mode: 448 });
|
|
17233
17234
|
await modules.fs.chmod(dirPath, 448);
|
|
@@ -17235,7 +17236,20 @@ async function saveCachedConfig(response, projectRoot) {
|
|
|
17235
17236
|
response,
|
|
17236
17237
|
cachedAt: Date.now()
|
|
17237
17238
|
};
|
|
17238
|
-
await modules.fs.writeFile(
|
|
17239
|
+
await modules.fs.writeFile(tmpPath, JSON.stringify(cached2), {
|
|
17240
|
+
encoding: "utf-8",
|
|
17241
|
+
mode: 384
|
|
17242
|
+
});
|
|
17243
|
+
try {
|
|
17244
|
+
await modules.fs.chmod(tmpPath, 384);
|
|
17245
|
+
await modules.fs.rename(tmpPath, configPath);
|
|
17246
|
+
} catch (renameErr) {
|
|
17247
|
+
try {
|
|
17248
|
+
await modules.fs.unlink(tmpPath);
|
|
17249
|
+
} catch {
|
|
17250
|
+
}
|
|
17251
|
+
throw renameErr;
|
|
17252
|
+
}
|
|
17239
17253
|
await modules.fs.chmod(configPath, 384);
|
|
17240
17254
|
} catch (err) {
|
|
17241
17255
|
console.warn(
|
|
@@ -21383,7 +21397,6 @@ async function configureOtel(config2, sessionManager) {
|
|
|
21383
21397
|
await provider.shutdown();
|
|
21384
21398
|
}
|
|
21385
21399
|
});
|
|
21386
|
-
registerSignalHandlers();
|
|
21387
21400
|
registerBeforeExitTrigger();
|
|
21388
21401
|
const prismaModule = await tryImport("@prisma/instrumentation");
|
|
21389
21402
|
if (prismaModule) {
|
|
@@ -21444,12 +21457,15 @@ var HEARTBEAT_INTERVAL_MS = 5 * 60 * 1e3;
|
|
|
21444
21457
|
var BACKOFF_BASE_MS = HEARTBEAT_INTERVAL_MS;
|
|
21445
21458
|
var BACKOFF_MAX_MS = 30 * 60 * 1e3;
|
|
21446
21459
|
var BACKOFF_JITTER = 0.2;
|
|
21460
|
+
var HEARTBEAT_SHUTDOWN_PRIORITY = 10;
|
|
21461
|
+
var SHUTDOWN_MARKER_RELPATH = ".glasstrace/shutdown-requested";
|
|
21447
21462
|
var heartbeatTimer = null;
|
|
21448
21463
|
var heartbeatGeneration = 0;
|
|
21449
21464
|
var backoffAttempts = 0;
|
|
21450
21465
|
var backoffUntil = 0;
|
|
21451
21466
|
var tickInProgress = false;
|
|
21452
|
-
var
|
|
21467
|
+
var shutdownHookRegistered = false;
|
|
21468
|
+
var shutdownFired = false;
|
|
21453
21469
|
function startHeartbeat(config2, anonKey, sdkVersion, generation, onClaimTransition) {
|
|
21454
21470
|
if (heartbeatTimer !== null) return;
|
|
21455
21471
|
heartbeatGeneration = generation;
|
|
@@ -21457,7 +21473,7 @@ function startHeartbeat(config2, anonKey, sdkVersion, generation, onClaimTransit
|
|
|
21457
21473
|
void heartbeatTick(config2, anonKey, sdkVersion, generation, onClaimTransition);
|
|
21458
21474
|
}, HEARTBEAT_INTERVAL_MS);
|
|
21459
21475
|
heartbeatTimer.unref();
|
|
21460
|
-
|
|
21476
|
+
registerHeartbeatShutdownHook(config2, anonKey, sdkVersion);
|
|
21461
21477
|
if (config2.verbose) {
|
|
21462
21478
|
sdkLog("info", "[glasstrace] Heartbeat started (5-minute interval).");
|
|
21463
21479
|
}
|
|
@@ -21467,7 +21483,26 @@ function stopHeartbeat() {
|
|
|
21467
21483
|
clearInterval(heartbeatTimer);
|
|
21468
21484
|
heartbeatTimer = null;
|
|
21469
21485
|
}
|
|
21470
|
-
|
|
21486
|
+
}
|
|
21487
|
+
function checkShutdownMarker(projectRoot) {
|
|
21488
|
+
let fsSync2 = null;
|
|
21489
|
+
let pathSync = null;
|
|
21490
|
+
try {
|
|
21491
|
+
fsSync2 = require("fs");
|
|
21492
|
+
pathSync = require("path");
|
|
21493
|
+
} catch {
|
|
21494
|
+
return { triggered: false };
|
|
21495
|
+
}
|
|
21496
|
+
const root = projectRoot ?? (typeof process !== "undefined" ? process.cwd() : ".");
|
|
21497
|
+
const markerPath = pathSync.join(root, SHUTDOWN_MARKER_RELPATH);
|
|
21498
|
+
if (!fsSync2.existsSync(markerPath)) return { triggered: false };
|
|
21499
|
+
try {
|
|
21500
|
+
fsSync2.unlinkSync(markerPath);
|
|
21501
|
+
} catch {
|
|
21502
|
+
}
|
|
21503
|
+
const shutdown = executeShutdown().catch(() => {
|
|
21504
|
+
});
|
|
21505
|
+
return { triggered: true, shutdown };
|
|
21471
21506
|
}
|
|
21472
21507
|
async function heartbeatTick(config2, anonKey, sdkVersion, generation, onClaimTransition) {
|
|
21473
21508
|
if (tickInProgress) return;
|
|
@@ -21477,6 +21512,14 @@ async function heartbeatTick(config2, anonKey, sdkVersion, generation, onClaimTr
|
|
|
21477
21512
|
stopHeartbeat();
|
|
21478
21513
|
return;
|
|
21479
21514
|
}
|
|
21515
|
+
const markerResult = checkShutdownMarker();
|
|
21516
|
+
if (markerResult.triggered) {
|
|
21517
|
+
stopHeartbeat();
|
|
21518
|
+
if (markerResult.shutdown) {
|
|
21519
|
+
await markerResult.shutdown;
|
|
21520
|
+
}
|
|
21521
|
+
return;
|
|
21522
|
+
}
|
|
21480
21523
|
if (Date.now() < backoffUntil) {
|
|
21481
21524
|
if (config2.verbose) {
|
|
21482
21525
|
sdkLog("info", "[glasstrace] Heartbeat skipped (rate-limit backoff).");
|
|
@@ -21511,35 +21554,26 @@ async function heartbeatTick(config2, anonKey, sdkVersion, generation, onClaimTr
|
|
|
21511
21554
|
tickInProgress = false;
|
|
21512
21555
|
}
|
|
21513
21556
|
}
|
|
21514
|
-
function
|
|
21515
|
-
if (
|
|
21516
|
-
|
|
21517
|
-
|
|
21518
|
-
|
|
21519
|
-
|
|
21520
|
-
|
|
21521
|
-
|
|
21522
|
-
|
|
21523
|
-
|
|
21524
|
-
|
|
21557
|
+
function registerHeartbeatShutdownHook(config2, anonKey, sdkVersion) {
|
|
21558
|
+
if (shutdownHookRegistered) return;
|
|
21559
|
+
shutdownHookRegistered = true;
|
|
21560
|
+
registerShutdownHook({
|
|
21561
|
+
name: "heartbeat-final-report",
|
|
21562
|
+
priority: HEARTBEAT_SHUTDOWN_PRIORITY,
|
|
21563
|
+
fn: async () => {
|
|
21564
|
+
if (shutdownFired) return;
|
|
21565
|
+
shutdownFired = true;
|
|
21566
|
+
if (heartbeatTimer !== null) {
|
|
21567
|
+
clearInterval(heartbeatTimer);
|
|
21568
|
+
heartbeatTimer = null;
|
|
21569
|
+
}
|
|
21570
|
+
try {
|
|
21571
|
+
const healthReport = collectHealthReport(sdkVersion);
|
|
21572
|
+
await performInit(config2, anonKey, sdkVersion, healthReport);
|
|
21573
|
+
} catch {
|
|
21574
|
+
}
|
|
21525
21575
|
}
|
|
21526
|
-
|
|
21527
|
-
void performInit(config2, anonKey, sdkVersion, healthReport).catch(() => {
|
|
21528
|
-
}).finally(() => {
|
|
21529
|
-
removeShutdownHandlers();
|
|
21530
|
-
process.kill(process.pid, signal);
|
|
21531
|
-
});
|
|
21532
|
-
};
|
|
21533
|
-
_shutdownHandler = handler;
|
|
21534
|
-
process.once("SIGTERM", _shutdownHandler);
|
|
21535
|
-
process.once("SIGINT", _shutdownHandler);
|
|
21536
|
-
}
|
|
21537
|
-
function removeShutdownHandlers() {
|
|
21538
|
-
if (_shutdownHandler && typeof process !== "undefined") {
|
|
21539
|
-
process.removeListener("SIGTERM", _shutdownHandler);
|
|
21540
|
-
process.removeListener("SIGINT", _shutdownHandler);
|
|
21541
|
-
_shutdownHandler = null;
|
|
21542
|
-
}
|
|
21576
|
+
});
|
|
21543
21577
|
}
|
|
21544
21578
|
|
|
21545
21579
|
// src/runtime-state.ts
|
|
@@ -21641,7 +21675,7 @@ function registerGlasstrace(options) {
|
|
|
21641
21675
|
setCoreState(CoreState.REGISTERING);
|
|
21642
21676
|
startRuntimeStateWriter({
|
|
21643
21677
|
projectRoot: process.cwd(),
|
|
21644
|
-
sdkVersion: "0.
|
|
21678
|
+
sdkVersion: "0.15.1"
|
|
21645
21679
|
});
|
|
21646
21680
|
const config2 = resolveConfig(options);
|
|
21647
21681
|
if (config2.verbose) {
|
|
@@ -21657,6 +21691,11 @@ function registerGlasstrace(options) {
|
|
|
21657
21691
|
if (config2.verbose) {
|
|
21658
21692
|
console.info("[glasstrace] Not production-disabled.");
|
|
21659
21693
|
}
|
|
21694
|
+
const existingProbe = trace.getTracerProvider().getTracer("glasstrace-probe");
|
|
21695
|
+
const anotherProviderRegistered = existingProbe.constructor.name !== "ProxyTracer";
|
|
21696
|
+
if (!anotherProviderRegistered) {
|
|
21697
|
+
registerSignalHandlers();
|
|
21698
|
+
}
|
|
21660
21699
|
const anonymous = isAnonymousMode(config2);
|
|
21661
21700
|
let effectiveKey = config2.apiKey;
|
|
21662
21701
|
initAuthState(anonymous ? AuthState.ANONYMOUS : AuthState.AUTHENTICATED);
|
|
@@ -21687,8 +21726,6 @@ function registerGlasstrace(options) {
|
|
|
21687
21726
|
}
|
|
21688
21727
|
setCoreState(CoreState.KEY_PENDING);
|
|
21689
21728
|
const currentGeneration = registrationGeneration;
|
|
21690
|
-
const existingProbe = trace.getTracerProvider().getTracer("glasstrace-probe");
|
|
21691
|
-
const anotherProviderRegistered = existingProbe.constructor.name !== "ProxyTracer";
|
|
21692
21729
|
if (anotherProviderRegistered) {
|
|
21693
21730
|
if (config2.verbose) {
|
|
21694
21731
|
console.info("[glasstrace] Another OTel provider detected \u2014 using existing context manager.");
|
|
@@ -21803,8 +21840,8 @@ async function backgroundInit(config2, anonKeyForInit, generation) {
|
|
|
21803
21840
|
if (config2.verbose) {
|
|
21804
21841
|
console.info("[glasstrace] Background init firing.");
|
|
21805
21842
|
}
|
|
21806
|
-
const healthReport = collectHealthReport("0.
|
|
21807
|
-
const initResult = await performInit(config2, anonKeyForInit, "0.
|
|
21843
|
+
const healthReport = collectHealthReport("0.15.1");
|
|
21844
|
+
const initResult = await performInit(config2, anonKeyForInit, "0.15.1", healthReport);
|
|
21808
21845
|
if (generation !== registrationGeneration) return;
|
|
21809
21846
|
const currentState = getCoreState();
|
|
21810
21847
|
if (currentState === CoreState.SHUTTING_DOWN || currentState === CoreState.SHUTDOWN) {
|
|
@@ -21827,7 +21864,7 @@ async function backgroundInit(config2, anonKeyForInit, generation) {
|
|
|
21827
21864
|
}
|
|
21828
21865
|
maybeInstallConsoleCapture();
|
|
21829
21866
|
if (didLastInitSucceed()) {
|
|
21830
|
-
startHeartbeat(config2, anonKeyForInit, "0.
|
|
21867
|
+
startHeartbeat(config2, anonKeyForInit, "0.15.1", generation, (newApiKey, accountId) => {
|
|
21831
21868
|
setAuthState(AuthState.CLAIMING);
|
|
21832
21869
|
emitLifecycleEvent("auth:claim_started", { accountId });
|
|
21833
21870
|
setResolvedApiKey(newApiKey);
|