@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.
Files changed (129) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/src/analysis/tree-sitter/pythonIncremental.d.ts +23 -0
  4. package/dist/src/analysis/tree-sitter/pythonIncremental.d.ts.map +1 -1
  5. package/dist/src/analysis/tree-sitter/pythonIncremental.hardening.test.js +137 -0
  6. package/dist/src/analysis/tree-sitter/pythonIncremental.hardening.test.js.map +1 -1
  7. package/dist/src/analysis/tree-sitter/pythonIncremental.js +83 -10
  8. package/dist/src/analysis/tree-sitter/pythonIncremental.js.map +1 -1
  9. package/dist/src/analysis/tree-sitter/queryExtractionMatchesOrExceedsRegex.test.js +6 -1
  10. package/dist/src/analysis/tree-sitter/queryExtractionMatchesOrExceedsRegex.test.js.map +1 -1
  11. package/dist/src/config/audit-notify-state.d.ts +46 -0
  12. package/dist/src/config/audit-notify-state.d.ts.map +1 -0
  13. package/dist/src/config/audit-notify-state.js +55 -0
  14. package/dist/src/config/audit-notify-state.js.map +1 -0
  15. package/dist/src/config/audit-notify-state.test.d.ts +9 -0
  16. package/dist/src/config/audit-notify-state.test.d.ts.map +1 -0
  17. package/dist/src/config/audit-notify-state.test.js +63 -0
  18. package/dist/src/config/audit-notify-state.test.js.map +1 -0
  19. package/dist/src/config/index.d.ts +10 -0
  20. package/dist/src/config/index.d.ts.map +1 -1
  21. package/dist/src/config/index.js.map +1 -1
  22. package/dist/src/exports/services.d.ts +1 -1
  23. package/dist/src/exports/services.d.ts.map +1 -1
  24. package/dist/src/exports/services.js +3 -1
  25. package/dist/src/exports/services.js.map +1 -1
  26. package/dist/src/index.d.ts +4 -1
  27. package/dist/src/index.d.ts.map +1 -1
  28. package/dist/src/index.js +7 -1
  29. package/dist/src/index.js.map +1 -1
  30. package/dist/src/logging/context.d.ts +58 -0
  31. package/dist/src/logging/context.d.ts.map +1 -0
  32. package/dist/src/logging/context.js +62 -0
  33. package/dist/src/logging/context.js.map +1 -0
  34. package/dist/src/logging/context.test.d.ts +14 -0
  35. package/dist/src/logging/context.test.d.ts.map +1 -0
  36. package/dist/src/logging/context.test.js +88 -0
  37. package/dist/src/logging/context.test.js.map +1 -0
  38. package/dist/src/logging/index.d.ts +13 -0
  39. package/dist/src/logging/index.d.ts.map +1 -0
  40. package/dist/src/logging/index.js +12 -0
  41. package/dist/src/logging/index.js.map +1 -0
  42. package/dist/src/logging/logger.d.ts +71 -0
  43. package/dist/src/logging/logger.d.ts.map +1 -0
  44. package/dist/src/logging/logger.js +264 -0
  45. package/dist/src/logging/logger.js.map +1 -0
  46. package/dist/src/logging/logger.test.d.ts +9 -0
  47. package/dist/src/logging/logger.test.d.ts.map +1 -0
  48. package/dist/src/logging/logger.test.js +320 -0
  49. package/dist/src/logging/logger.test.js.map +1 -0
  50. package/dist/src/logging/redact.d.ts +35 -0
  51. package/dist/src/logging/redact.d.ts.map +1 -0
  52. package/dist/src/logging/redact.js +152 -0
  53. package/dist/src/logging/redact.js.map +1 -0
  54. package/dist/src/logging/redact.test.d.ts +8 -0
  55. package/dist/src/logging/redact.test.d.ts.map +1 -0
  56. package/dist/src/logging/redact.test.js +330 -0
  57. package/dist/src/logging/redact.test.js.map +1 -0
  58. package/dist/src/logging/rotation.d.ts +75 -0
  59. package/dist/src/logging/rotation.d.ts.map +1 -0
  60. package/dist/src/logging/rotation.js +284 -0
  61. package/dist/src/logging/rotation.js.map +1 -0
  62. package/dist/src/logging/rotation.test.d.ts +11 -0
  63. package/dist/src/logging/rotation.test.d.ts.map +1 -0
  64. package/dist/src/logging/rotation.test.js +132 -0
  65. package/dist/src/logging/rotation.test.js.map +1 -0
  66. package/dist/src/logging/types.d.ts +69 -0
  67. package/dist/src/logging/types.d.ts.map +1 -0
  68. package/dist/src/logging/types.js +9 -0
  69. package/dist/src/logging/types.js.map +1 -0
  70. package/dist/src/security/index.d.ts +2 -0
  71. package/dist/src/security/index.d.ts.map +1 -1
  72. package/dist/src/security/index.js +4 -0
  73. package/dist/src/security/index.js.map +1 -1
  74. package/dist/src/security/scanner/SecurityScanner.hostile-update.d.ts +46 -0
  75. package/dist/src/security/scanner/SecurityScanner.hostile-update.d.ts.map +1 -0
  76. package/dist/src/security/scanner/SecurityScanner.hostile-update.js +209 -0
  77. package/dist/src/security/scanner/SecurityScanner.hostile-update.js.map +1 -0
  78. package/dist/src/security/scanner/index.d.ts +2 -1
  79. package/dist/src/security/scanner/index.d.ts.map +1 -1
  80. package/dist/src/security/scanner/index.js +2 -0
  81. package/dist/src/security/scanner/index.js.map +1 -1
  82. package/dist/src/security/scanner/types.d.ts +21 -0
  83. package/dist/src/security/scanner/types.d.ts.map +1 -1
  84. package/dist/src/services/skill-installation.io.d.ts.map +1 -1
  85. package/dist/src/services/skill-installation.io.js +19 -2
  86. package/dist/src/services/skill-installation.io.js.map +1 -1
  87. package/dist/src/sync/access-token.d.ts +27 -0
  88. package/dist/src/sync/access-token.d.ts.map +1 -0
  89. package/dist/src/sync/access-token.js +40 -0
  90. package/dist/src/sync/access-token.js.map +1 -0
  91. package/dist/src/sync/audit-notify-client.d.ts +83 -0
  92. package/dist/src/sync/audit-notify-client.d.ts.map +1 -0
  93. package/dist/src/sync/audit-notify-client.js +126 -0
  94. package/dist/src/sync/audit-notify-client.js.map +1 -0
  95. package/dist/src/sync/audit-notify-client.test.d.ts +14 -0
  96. package/dist/src/sync/audit-notify-client.test.d.ts.map +1 -0
  97. package/dist/src/sync/audit-notify-client.test.js +133 -0
  98. package/dist/src/sync/audit-notify-client.test.js.map +1 -0
  99. package/dist/src/sync/index.d.ts +1 -0
  100. package/dist/src/sync/index.d.ts.map +1 -1
  101. package/dist/src/sync/index.js +2 -0
  102. package/dist/src/sync/index.js.map +1 -1
  103. package/dist/src/sync/inventory-client.d.ts.map +1 -1
  104. package/dist/src/sync/inventory-client.js +5 -16
  105. package/dist/src/sync/inventory-client.js.map +1 -1
  106. package/dist/src/telemetry/posthog.d.ts +15 -0
  107. package/dist/src/telemetry/posthog.d.ts.map +1 -1
  108. package/dist/src/telemetry/posthog.js +6 -1
  109. package/dist/src/telemetry/posthog.js.map +1 -1
  110. package/dist/src/telemetry/wrap.bench.js +5 -0
  111. package/dist/src/telemetry/wrap.bench.js.map +1 -1
  112. package/dist/src/telemetry/wrap.correlation.test.d.ts +20 -0
  113. package/dist/src/telemetry/wrap.correlation.test.d.ts.map +1 -0
  114. package/dist/src/telemetry/wrap.correlation.test.js +174 -0
  115. package/dist/src/telemetry/wrap.correlation.test.js.map +1 -0
  116. package/dist/src/telemetry/wrap.d.ts.map +1 -1
  117. package/dist/src/telemetry/wrap.gate.test.js +5 -0
  118. package/dist/src/telemetry/wrap.gate.test.js.map +1 -1
  119. package/dist/src/telemetry/wrap.js +111 -52
  120. package/dist/src/telemetry/wrap.js.map +1 -1
  121. package/dist/src/telemetry/wrap.marker.test.js +5 -0
  122. package/dist/src/telemetry/wrap.marker.test.js.map +1 -1
  123. package/dist/src/telemetry/wrap.test.js +10 -0
  124. package/dist/src/telemetry/wrap.test.js.map +1 -1
  125. package/dist/src/types.d.ts +6 -0
  126. package/dist/src/types.d.ts.map +1 -1
  127. package/dist/tests/security/scanner-regression-guard.test.js +179 -1
  128. package/dist/tests/security/scanner-regression-guard.test.js.map +1 -1
  129. 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"}