@skillsmith/core 0.10.0 → 0.11.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/CHANGELOG.md +4 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/src/analysis/tree-sitter/pythonIncremental.d.ts +23 -0
- package/dist/src/analysis/tree-sitter/pythonIncremental.d.ts.map +1 -1
- package/dist/src/analysis/tree-sitter/pythonIncremental.hardening.test.js +137 -0
- package/dist/src/analysis/tree-sitter/pythonIncremental.hardening.test.js.map +1 -1
- package/dist/src/analysis/tree-sitter/pythonIncremental.js +83 -10
- package/dist/src/analysis/tree-sitter/pythonIncremental.js.map +1 -1
- package/dist/src/analysis/tree-sitter/queryExtractionMatchesOrExceedsRegex.test.js +6 -1
- package/dist/src/analysis/tree-sitter/queryExtractionMatchesOrExceedsRegex.test.js.map +1 -1
- package/dist/src/config/audit-notify-state.d.ts +46 -0
- package/dist/src/config/audit-notify-state.d.ts.map +1 -0
- package/dist/src/config/audit-notify-state.js +55 -0
- package/dist/src/config/audit-notify-state.js.map +1 -0
- package/dist/src/config/audit-notify-state.test.d.ts +9 -0
- package/dist/src/config/audit-notify-state.test.d.ts.map +1 -0
- package/dist/src/config/audit-notify-state.test.js +63 -0
- package/dist/src/config/audit-notify-state.test.js.map +1 -0
- package/dist/src/config/index.d.ts +10 -0
- package/dist/src/config/index.d.ts.map +1 -1
- package/dist/src/config/index.js.map +1 -1
- package/dist/src/exports/services.d.ts +1 -1
- package/dist/src/exports/services.d.ts.map +1 -1
- package/dist/src/exports/services.js +3 -1
- package/dist/src/exports/services.js.map +1 -1
- package/dist/src/index.d.ts +4 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +7 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/logging/context.d.ts +58 -0
- package/dist/src/logging/context.d.ts.map +1 -0
- package/dist/src/logging/context.js +62 -0
- package/dist/src/logging/context.js.map +1 -0
- package/dist/src/logging/context.test.d.ts +14 -0
- package/dist/src/logging/context.test.d.ts.map +1 -0
- package/dist/src/logging/context.test.js +88 -0
- package/dist/src/logging/context.test.js.map +1 -0
- package/dist/src/logging/index.d.ts +13 -0
- package/dist/src/logging/index.d.ts.map +1 -0
- package/dist/src/logging/index.js +12 -0
- package/dist/src/logging/index.js.map +1 -0
- package/dist/src/logging/logger.d.ts +71 -0
- package/dist/src/logging/logger.d.ts.map +1 -0
- package/dist/src/logging/logger.js +264 -0
- package/dist/src/logging/logger.js.map +1 -0
- package/dist/src/logging/logger.test.d.ts +9 -0
- package/dist/src/logging/logger.test.d.ts.map +1 -0
- package/dist/src/logging/logger.test.js +320 -0
- package/dist/src/logging/logger.test.js.map +1 -0
- package/dist/src/logging/redact.d.ts +35 -0
- package/dist/src/logging/redact.d.ts.map +1 -0
- package/dist/src/logging/redact.js +152 -0
- package/dist/src/logging/redact.js.map +1 -0
- package/dist/src/logging/redact.test.d.ts +8 -0
- package/dist/src/logging/redact.test.d.ts.map +1 -0
- package/dist/src/logging/redact.test.js +330 -0
- package/dist/src/logging/redact.test.js.map +1 -0
- package/dist/src/logging/rotation.d.ts +75 -0
- package/dist/src/logging/rotation.d.ts.map +1 -0
- package/dist/src/logging/rotation.js +284 -0
- package/dist/src/logging/rotation.js.map +1 -0
- package/dist/src/logging/rotation.test.d.ts +11 -0
- package/dist/src/logging/rotation.test.d.ts.map +1 -0
- package/dist/src/logging/rotation.test.js +132 -0
- package/dist/src/logging/rotation.test.js.map +1 -0
- package/dist/src/logging/types.d.ts +69 -0
- package/dist/src/logging/types.d.ts.map +1 -0
- package/dist/src/logging/types.js +9 -0
- package/dist/src/logging/types.js.map +1 -0
- package/dist/src/security/index.d.ts +2 -0
- package/dist/src/security/index.d.ts.map +1 -1
- package/dist/src/security/index.js +4 -0
- package/dist/src/security/index.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.hostile-update.d.ts +46 -0
- package/dist/src/security/scanner/SecurityScanner.hostile-update.d.ts.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.hostile-update.js +209 -0
- package/dist/src/security/scanner/SecurityScanner.hostile-update.js.map +1 -0
- package/dist/src/security/scanner/index.d.ts +2 -1
- package/dist/src/security/scanner/index.d.ts.map +1 -1
- package/dist/src/security/scanner/index.js +2 -0
- package/dist/src/security/scanner/index.js.map +1 -1
- package/dist/src/security/scanner/types.d.ts +21 -0
- package/dist/src/security/scanner/types.d.ts.map +1 -1
- package/dist/src/services/skill-installation.io.d.ts.map +1 -1
- package/dist/src/services/skill-installation.io.js +19 -2
- package/dist/src/services/skill-installation.io.js.map +1 -1
- package/dist/src/sync/access-token.d.ts +27 -0
- package/dist/src/sync/access-token.d.ts.map +1 -0
- package/dist/src/sync/access-token.js +40 -0
- package/dist/src/sync/access-token.js.map +1 -0
- package/dist/src/sync/audit-notify-client.d.ts +83 -0
- package/dist/src/sync/audit-notify-client.d.ts.map +1 -0
- package/dist/src/sync/audit-notify-client.js +126 -0
- package/dist/src/sync/audit-notify-client.js.map +1 -0
- package/dist/src/sync/audit-notify-client.test.d.ts +14 -0
- package/dist/src/sync/audit-notify-client.test.d.ts.map +1 -0
- package/dist/src/sync/audit-notify-client.test.js +133 -0
- package/dist/src/sync/audit-notify-client.test.js.map +1 -0
- package/dist/src/sync/index.d.ts +1 -0
- package/dist/src/sync/index.d.ts.map +1 -1
- package/dist/src/sync/index.js +2 -0
- package/dist/src/sync/index.js.map +1 -1
- package/dist/src/sync/inventory-client.d.ts.map +1 -1
- package/dist/src/sync/inventory-client.js +5 -16
- package/dist/src/sync/inventory-client.js.map +1 -1
- package/dist/src/telemetry/posthog.d.ts +15 -0
- package/dist/src/telemetry/posthog.d.ts.map +1 -1
- package/dist/src/telemetry/posthog.js +6 -1
- package/dist/src/telemetry/posthog.js.map +1 -1
- package/dist/src/telemetry/wrap.bench.js +5 -0
- package/dist/src/telemetry/wrap.bench.js.map +1 -1
- package/dist/src/telemetry/wrap.correlation.test.d.ts +20 -0
- package/dist/src/telemetry/wrap.correlation.test.d.ts.map +1 -0
- package/dist/src/telemetry/wrap.correlation.test.js +174 -0
- package/dist/src/telemetry/wrap.correlation.test.js.map +1 -0
- package/dist/src/telemetry/wrap.d.ts.map +1 -1
- package/dist/src/telemetry/wrap.gate.test.js +5 -0
- package/dist/src/telemetry/wrap.gate.test.js.map +1 -1
- package/dist/src/telemetry/wrap.js +111 -52
- package/dist/src/telemetry/wrap.js.map +1 -1
- package/dist/src/telemetry/wrap.marker.test.js +5 -0
- package/dist/src/telemetry/wrap.marker.test.js.map +1 -1
- package/dist/src/telemetry/wrap.test.js +10 -0
- package/dist/src/telemetry/wrap.test.js.map +1 -1
- package/dist/src/types.d.ts +6 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/tests/security/scanner-regression-guard.test.js +179 -1
- package/dist/tests/security/scanner-regression-guard.test.js.map +1 -1
- package/package.json +7 -2
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-5615: Shared structured JSON-line logger.
|
|
3
|
+
*
|
|
4
|
+
* Generalized from the dead `packages/mcp-server/src/logger.ts` (SMI-883
|
|
5
|
+
* redaction) into a surface-agnostic module usable by the MCP server, CLI,
|
|
6
|
+
* and VS Code extension independently — `createLogger(surface)` is a
|
|
7
|
+
* factory, not a singleton, so each host process can mint its own logger
|
|
8
|
+
* (optionally stamped with its own package version) while still writing to
|
|
9
|
+
* per-surface files that are safe to share across processes for the same
|
|
10
|
+
* surface (see `rotation.ts`).
|
|
11
|
+
*
|
|
12
|
+
* Call-site invariants (see
|
|
13
|
+
* docs/internal/implementation/production-error-logging.md §1 and the
|
|
14
|
+
* Shared-State / Coordination Audit table, F2/F3):
|
|
15
|
+
*
|
|
16
|
+
* - `getCorrelationId()` is read SYNCHRONOUSLY at the call site, inside
|
|
17
|
+
* `buildRecord`, never inside an async flush/rotation callback (F3) — a
|
|
18
|
+
* deferred read could observe a different call's (or no) correlation ID
|
|
19
|
+
* once the originating call's `AsyncLocalStorage` scope has unwound.
|
|
20
|
+
* - The full JSON-line record (including the synchronously-read
|
|
21
|
+
* correlation ID and synchronously-applied redaction) is built and
|
|
22
|
+
* `JSON.stringify`'d BEFORE handing the string off to `rotation.ts`'s
|
|
23
|
+
* serialized per-surface writer (F2) — only the actual disk write may
|
|
24
|
+
* complete asynchronously; by the time it starts, the record content is
|
|
25
|
+
* already frozen.
|
|
26
|
+
* - Logger calls never throw. Any failure while assembling or persisting a
|
|
27
|
+
* record falls back to `console.error`/`console.warn` (matching level,
|
|
28
|
+
* with `info`/`debug` also routed to `console.error`) rather than being
|
|
29
|
+
* fully silent — stderr remains the safety net of last resort. This
|
|
30
|
+
* differs from the old logger's "silently fail" comment intent, which is
|
|
31
|
+
* no longer acceptable once this is the only durable failure signal.
|
|
32
|
+
* - `warn`/`error` ALWAYS mirror to `console.warn`/`console.error`,
|
|
33
|
+
* synchronously, regardless of whether the disk write succeeds — this is
|
|
34
|
+
* NOT a failure-only fallback for those two levels (only `info`/`debug`
|
|
35
|
+
* use console purely as a write-failure fallback). This is what makes
|
|
36
|
+
* `logger.error`/`logger.warn` a safe drop-in replacement for existing
|
|
37
|
+
* `console.error`/`console.warn` call sites in the MCP server and CLI —
|
|
38
|
+
* the caller-visible terminal/stderr output stays identical to today,
|
|
39
|
+
* with redacted disk persistence added on top rather than instead of it.
|
|
40
|
+
*/
|
|
41
|
+
import type { LogDetails, Surface } from './types.js';
|
|
42
|
+
export interface CreateLoggerOptions {
|
|
43
|
+
/**
|
|
44
|
+
* Package/CLI version stamped on every record from this logger instance.
|
|
45
|
+
* Defaults to `'unknown'` — pass each host package's own `version` (e.g.
|
|
46
|
+
* from its own `package.json`) at its entrypoint for an accurate value.
|
|
47
|
+
*/
|
|
48
|
+
version?: string;
|
|
49
|
+
}
|
|
50
|
+
export interface Logger {
|
|
51
|
+
info(message: string, details?: LogDetails): void;
|
|
52
|
+
warn(message: string, details?: LogDetails): void;
|
|
53
|
+
error(message: string, details?: LogDetails): void;
|
|
54
|
+
debug(message: string, details?: LogDetails): void;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Creates a logger bound to `surface`. Independent instances for different
|
|
58
|
+
* surfaces (or the same surface with different `version` stamps) are safe to
|
|
59
|
+
* create concurrently — they only share state at the `rotation.ts` layer,
|
|
60
|
+
* which is itself safe for concurrent writers to the same surface (F2).
|
|
61
|
+
*/
|
|
62
|
+
export declare function createLogger(surface: Surface, options?: CreateLoggerOptions): Logger;
|
|
63
|
+
/**
|
|
64
|
+
* Memoized per-surface logger created with default options
|
|
65
|
+
* (`version: 'unknown'`). Prefer calling `createLogger(surface, { version })`
|
|
66
|
+
* once at each package's entrypoint so records carry that package's real
|
|
67
|
+
* version; `getLogger` is a convenience for call sites that don't need a
|
|
68
|
+
* custom version stamp and want a single shared instance per surface.
|
|
69
|
+
*/
|
|
70
|
+
export declare function getLogger(surface: Surface): Logger;
|
|
71
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/logging/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAuB,OAAO,EAAE,MAAM,YAAY,CAAA;AA2L1E,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;IACjD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;IACjD,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;IAClD,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;CACnD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,GAAE,mBAAwB,GAAG,MAAM,CA0BxF;AAID;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAOlD"}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-5615: Shared structured JSON-line logger.
|
|
3
|
+
*
|
|
4
|
+
* Generalized from the dead `packages/mcp-server/src/logger.ts` (SMI-883
|
|
5
|
+
* redaction) into a surface-agnostic module usable by the MCP server, CLI,
|
|
6
|
+
* and VS Code extension independently — `createLogger(surface)` is a
|
|
7
|
+
* factory, not a singleton, so each host process can mint its own logger
|
|
8
|
+
* (optionally stamped with its own package version) while still writing to
|
|
9
|
+
* per-surface files that are safe to share across processes for the same
|
|
10
|
+
* surface (see `rotation.ts`).
|
|
11
|
+
*
|
|
12
|
+
* Call-site invariants (see
|
|
13
|
+
* docs/internal/implementation/production-error-logging.md §1 and the
|
|
14
|
+
* Shared-State / Coordination Audit table, F2/F3):
|
|
15
|
+
*
|
|
16
|
+
* - `getCorrelationId()` is read SYNCHRONOUSLY at the call site, inside
|
|
17
|
+
* `buildRecord`, never inside an async flush/rotation callback (F3) — a
|
|
18
|
+
* deferred read could observe a different call's (or no) correlation ID
|
|
19
|
+
* once the originating call's `AsyncLocalStorage` scope has unwound.
|
|
20
|
+
* - The full JSON-line record (including the synchronously-read
|
|
21
|
+
* correlation ID and synchronously-applied redaction) is built and
|
|
22
|
+
* `JSON.stringify`'d BEFORE handing the string off to `rotation.ts`'s
|
|
23
|
+
* serialized per-surface writer (F2) — only the actual disk write may
|
|
24
|
+
* complete asynchronously; by the time it starts, the record content is
|
|
25
|
+
* already frozen.
|
|
26
|
+
* - Logger calls never throw. Any failure while assembling or persisting a
|
|
27
|
+
* record falls back to `console.error`/`console.warn` (matching level,
|
|
28
|
+
* with `info`/`debug` also routed to `console.error`) rather than being
|
|
29
|
+
* fully silent — stderr remains the safety net of last resort. This
|
|
30
|
+
* differs from the old logger's "silently fail" comment intent, which is
|
|
31
|
+
* no longer acceptable once this is the only durable failure signal.
|
|
32
|
+
* - `warn`/`error` ALWAYS mirror to `console.warn`/`console.error`,
|
|
33
|
+
* synchronously, regardless of whether the disk write succeeds — this is
|
|
34
|
+
* NOT a failure-only fallback for those two levels (only `info`/`debug`
|
|
35
|
+
* use console purely as a write-failure fallback). This is what makes
|
|
36
|
+
* `logger.error`/`logger.warn` a safe drop-in replacement for existing
|
|
37
|
+
* `console.error`/`console.warn` call sites in the MCP server and CLI —
|
|
38
|
+
* the caller-visible terminal/stderr output stays identical to today,
|
|
39
|
+
* with redacted disk persistence added on top rather than instead of it.
|
|
40
|
+
*/
|
|
41
|
+
import { getCorrelationId } from './context.js';
|
|
42
|
+
import { redactSensitiveData, redactSensitiveObject, stripAnsi } from './redact.js';
|
|
43
|
+
import { writeLogLine } from './rotation.js';
|
|
44
|
+
const LEVEL_ORDER = {
|
|
45
|
+
debug: 0,
|
|
46
|
+
info: 1,
|
|
47
|
+
warn: 2,
|
|
48
|
+
error: 3,
|
|
49
|
+
};
|
|
50
|
+
const MAX_STACK_FRAMES = 20;
|
|
51
|
+
/**
|
|
52
|
+
* Accepts `'1'`/`'true'` (case-insensitive) — matches the existing
|
|
53
|
+
* `SKILLSMITH_<FEATURE>_DISABLE` convention, e.g.
|
|
54
|
+
* `isInventorySyncDisabledLocally()` at
|
|
55
|
+
* `packages/core/src/config/device-identity.ts:124`
|
|
56
|
+
* (`SKILLSMITH_INVENTORY_DISABLE`).
|
|
57
|
+
*/
|
|
58
|
+
function isLoggingDisabled() {
|
|
59
|
+
const val = process.env.SKILLSMITH_ERROR_LOG_DISABLE;
|
|
60
|
+
if (!val)
|
|
61
|
+
return false;
|
|
62
|
+
return val === '1' || val.toLowerCase() === 'true';
|
|
63
|
+
}
|
|
64
|
+
function configuredLevel() {
|
|
65
|
+
const raw = process.env.SKILLSMITH_LOG_LEVEL?.toLowerCase();
|
|
66
|
+
if (raw === 'debug' || raw === 'info' || raw === 'warn' || raw === 'error') {
|
|
67
|
+
return raw;
|
|
68
|
+
}
|
|
69
|
+
return 'warn';
|
|
70
|
+
}
|
|
71
|
+
function isLevelEnabled(level) {
|
|
72
|
+
return LEVEL_ORDER[level] >= LEVEL_ORDER[configuredLevel()];
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Fallback console channel for a level. `warn` mirrors to `console.warn`
|
|
76
|
+
* (stderr); everything else — including `info`/`debug`, which have no
|
|
77
|
+
* dedicated stderr-only console method — falls back to `console.error`
|
|
78
|
+
* (stderr) so a failure never lands on stdout. MCP servers must keep stdout
|
|
79
|
+
* clean for the stdio JSON-RPC transport; `console.log`/`console.info` write
|
|
80
|
+
* to stdout and would corrupt it.
|
|
81
|
+
*
|
|
82
|
+
* Always redacts `message` before printing (Mode-B diff-audit NEW-1): this is
|
|
83
|
+
* the last-resort channel when the redacted disk record couldn't be built or
|
|
84
|
+
* written, so it must independently uphold the same SMI-883 guarantee — never
|
|
85
|
+
* pass the raw, un-redacted message straight to `console.*`.
|
|
86
|
+
*/
|
|
87
|
+
function consoleFallback(level, message) {
|
|
88
|
+
const redacted = redactSensitiveData(message);
|
|
89
|
+
if (level === 'warn') {
|
|
90
|
+
console.warn(redacted);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
console.error(redacted);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// SMI-5615 Mode-B (Wave 2 pass): ANSI stripped BEFORE redaction on every
|
|
97
|
+
// disk-bound field — see `stripAnsi`'s doc comment in `redact.ts` for why
|
|
98
|
+
// (embedded chalk escape codes are log noise AND can defeat the redaction
|
|
99
|
+
// regex's leading word-boundary check).
|
|
100
|
+
function redactForDisk(text) {
|
|
101
|
+
return redactSensitiveData(stripAnsi(text));
|
|
102
|
+
}
|
|
103
|
+
function normalizeError(err) {
|
|
104
|
+
if (err instanceof Error) {
|
|
105
|
+
const frames = err.stack
|
|
106
|
+
? err.stack.split('\n').slice(0, MAX_STACK_FRAMES).join('\n')
|
|
107
|
+
: undefined;
|
|
108
|
+
return {
|
|
109
|
+
name: err.name,
|
|
110
|
+
message: redactForDisk(err.message),
|
|
111
|
+
stack: frames ? redactForDisk(frames) : undefined,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
if (typeof err === 'string') {
|
|
115
|
+
return { name: 'Error', message: redactForDisk(err) };
|
|
116
|
+
}
|
|
117
|
+
if (err && typeof err === 'object') {
|
|
118
|
+
const asRecord = err;
|
|
119
|
+
const name = typeof asRecord.name === 'string' ? asRecord.name : 'Error';
|
|
120
|
+
const message = typeof asRecord.message === 'string'
|
|
121
|
+
? asRecord.message
|
|
122
|
+
: safeStringify(redactSensitiveObject(asRecord));
|
|
123
|
+
return { name, message: redactForDisk(message) };
|
|
124
|
+
}
|
|
125
|
+
return { name: 'Error', message: redactForDisk(String(err)) };
|
|
126
|
+
}
|
|
127
|
+
function safeStringify(value) {
|
|
128
|
+
try {
|
|
129
|
+
return JSON.stringify(value) ?? String(value);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return '[unserializable value]';
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Builds the complete, already-redacted `LogRecord` synchronously — this is
|
|
137
|
+
* the F2/F3 boundary: everything below runs on the calling stack, before any
|
|
138
|
+
* async write is even scheduled.
|
|
139
|
+
*/
|
|
140
|
+
function buildRecord(surface, level, version, message, details) {
|
|
141
|
+
// F3: correlation ID read synchronously, at the call site — never deferred.
|
|
142
|
+
const correlationId = getCorrelationId();
|
|
143
|
+
const { event, err, toolOrCommand, skillId, ...rest } = details ?? {};
|
|
144
|
+
const record = {
|
|
145
|
+
ts: new Date().toISOString(),
|
|
146
|
+
level,
|
|
147
|
+
surface,
|
|
148
|
+
event: typeof event === 'string' && event.length > 0 ? event : level,
|
|
149
|
+
msg: redactForDisk(message),
|
|
150
|
+
version,
|
|
151
|
+
pid: process.pid,
|
|
152
|
+
};
|
|
153
|
+
if (correlationId)
|
|
154
|
+
record.correlationId = correlationId;
|
|
155
|
+
if (typeof toolOrCommand === 'string')
|
|
156
|
+
record.toolOrCommand = toolOrCommand;
|
|
157
|
+
if (typeof skillId === 'string')
|
|
158
|
+
record.skillId = skillId;
|
|
159
|
+
if (err !== undefined)
|
|
160
|
+
record.err = normalizeError(err);
|
|
161
|
+
if (Object.keys(rest).length > 0) {
|
|
162
|
+
record.details = redactSensitiveObject(rest);
|
|
163
|
+
}
|
|
164
|
+
return record;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Hands the fully-built record off to `rotation.ts`, AND mirrors `warn`/
|
|
168
|
+
* `error` to console UNCONDITIONALLY (not only on a write failure) — per
|
|
169
|
+
* plan §1: "the logger writes to disk AND still emits to stderr for warn/
|
|
170
|
+
* error". This is the mechanism that lets `packages/mcp-server/src/index.ts`
|
|
171
|
+
* and `packages/cli/src` replace their scattered `console.error`/`warn`
|
|
172
|
+
* calls with `logger.error`/`warn` as a drop-in swap: the caller-visible
|
|
173
|
+
* terminal/stderr output must be identical to today, with disk persistence
|
|
174
|
+
* added on top — not replaced by it. `info`/`debug` are disk-only by design
|
|
175
|
+
* (routine/diagnostic detail, not something every caller needs to see live);
|
|
176
|
+
* they still reach console as a write-failure fallback like before, via the
|
|
177
|
+
* `catch` paths below, so a failure is never fully silent at any level.
|
|
178
|
+
*/
|
|
179
|
+
function persistRecord(surface, level, message, record) {
|
|
180
|
+
if (level === 'warn' || level === 'error') {
|
|
181
|
+
consoleFallback(level, message);
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
const line = safeStringifyRecord(record, message);
|
|
185
|
+
writeLogLine(surface, line).catch(() => {
|
|
186
|
+
if (level !== 'warn' && level !== 'error')
|
|
187
|
+
consoleFallback(level, message);
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
// Synchronous failure calling into rotation.ts (should be effectively
|
|
192
|
+
// unreachable — `writeLogLine` itself only throws via its returned
|
|
193
|
+
// Promise — but the invariant is "never throws", full stop).
|
|
194
|
+
if (level !== 'warn' && level !== 'error')
|
|
195
|
+
consoleFallback(level, message);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
function safeStringifyRecord(record, fallbackMessage) {
|
|
199
|
+
try {
|
|
200
|
+
return JSON.stringify(record);
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
// Circular reference or similar inside `details`/`err` — degrade to a
|
|
204
|
+
// minimal, definitely-serializable record rather than losing the
|
|
205
|
+
// message and metadata entirely.
|
|
206
|
+
const { details: _details, err: _err, ...safe } = record;
|
|
207
|
+
return JSON.stringify({
|
|
208
|
+
...safe,
|
|
209
|
+
msg: `${redactForDisk(fallbackMessage)} [unserializable details/err omitted]`,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Creates a logger bound to `surface`. Independent instances for different
|
|
215
|
+
* surfaces (or the same surface with different `version` stamps) are safe to
|
|
216
|
+
* create concurrently — they only share state at the `rotation.ts` layer,
|
|
217
|
+
* which is itself safe for concurrent writers to the same surface (F2).
|
|
218
|
+
*/
|
|
219
|
+
export function createLogger(surface, options = {}) {
|
|
220
|
+
const version = options.version ?? 'unknown';
|
|
221
|
+
function log(level, message, details) {
|
|
222
|
+
try {
|
|
223
|
+
if (isLoggingDisabled())
|
|
224
|
+
return;
|
|
225
|
+
if (!isLevelEnabled(level))
|
|
226
|
+
return;
|
|
227
|
+
const record = buildRecord(surface, level, version, message, details);
|
|
228
|
+
persistRecord(surface, level, message, record);
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
// Absolute last resort — never let a logging call throw into the
|
|
232
|
+
// caller, regardless of what went wrong above.
|
|
233
|
+
try {
|
|
234
|
+
consoleFallback(level, message);
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
// Truly nothing left to do.
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return {
|
|
242
|
+
info: (message, details) => log('info', message, details),
|
|
243
|
+
warn: (message, details) => log('warn', message, details),
|
|
244
|
+
error: (message, details) => log('error', message, details),
|
|
245
|
+
debug: (message, details) => log('debug', message, details),
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
const memoizedLoggers = new Map();
|
|
249
|
+
/**
|
|
250
|
+
* Memoized per-surface logger created with default options
|
|
251
|
+
* (`version: 'unknown'`). Prefer calling `createLogger(surface, { version })`
|
|
252
|
+
* once at each package's entrypoint so records carry that package's real
|
|
253
|
+
* version; `getLogger` is a convenience for call sites that don't need a
|
|
254
|
+
* custom version stamp and want a single shared instance per surface.
|
|
255
|
+
*/
|
|
256
|
+
export function getLogger(surface) {
|
|
257
|
+
let logger = memoizedLoggers.get(surface);
|
|
258
|
+
if (!logger) {
|
|
259
|
+
logger = createLogger(surface);
|
|
260
|
+
memoizedLoggers.set(surface, logger);
|
|
261
|
+
}
|
|
262
|
+
return logger;
|
|
263
|
+
}
|
|
264
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../../src/logging/logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-5615: Tests for the shared `logger.ts` factory — crash-proofing,
|
|
3
|
+
* `SKILLSMITH_ERROR_LOG_DISABLE`, `SKILLSMITH_LOG_LEVEL` filtering,
|
|
4
|
+
* redaction-on-disk, and the correlation-ID call-site invariant (F3). All
|
|
5
|
+
* tests point `SKILLSMITH_LOG_DIR` at a temp directory — never the real
|
|
6
|
+
* `~/.skillsmith/logs/`.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=logger.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.test.d.ts","sourceRoot":"","sources":["../../../src/logging/logger.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|