@namzu/sdk 29.0.0 → 30.0.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.
Files changed (36) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +57 -419
  3. package/dist/plugin/loader.d.ts.map +1 -1
  4. package/dist/plugin/loader.js +10 -12
  5. package/dist/plugin/loader.js.map +1 -1
  6. package/dist/public-runtime.d.ts +14 -1
  7. package/dist/public-runtime.d.ts.map +1 -1
  8. package/dist/public-runtime.js +14 -1
  9. package/dist/public-runtime.js.map +1 -1
  10. package/dist/skills/loader.d.ts.map +1 -1
  11. package/dist/skills/loader.js +10 -12
  12. package/dist/skills/loader.js.map +1 -1
  13. package/dist/utils/log/create-logger.d.ts +3 -3
  14. package/dist/utils/log/create-logger.d.ts.map +1 -1
  15. package/dist/utils/log/create-logger.js +10 -8
  16. package/dist/utils/log/create-logger.js.map +1 -1
  17. package/dist/utils/log/process-sink.d.ts +7 -4
  18. package/dist/utils/log/process-sink.d.ts.map +1 -1
  19. package/dist/utils/log/process-sink.js +19 -13
  20. package/dist/utils/log/process-sink.js.map +1 -1
  21. package/dist/utils/log/types.d.ts +12 -7
  22. package/dist/utils/log/types.d.ts.map +1 -1
  23. package/dist/utils/log/types.js +6 -6
  24. package/dist/utils/log/types.js.map +1 -1
  25. package/dist/utils/logger.d.ts +15 -35
  26. package/dist/utils/logger.d.ts.map +1 -1
  27. package/dist/utils/logger.js +18 -136
  28. package/dist/utils/logger.js.map +1 -1
  29. package/package.json +1 -1
  30. package/src/plugin/loader.ts +10 -12
  31. package/src/public-runtime.ts +14 -1
  32. package/src/skills/loader.ts +10 -12
  33. package/src/utils/log/create-logger.ts +10 -8
  34. package/src/utils/log/process-sink.ts +19 -13
  35. package/src/utils/log/types.ts +18 -13
  36. package/src/utils/logger.ts +18 -159
@@ -1,24 +1,11 @@
1
- import { createLogger } from './log/create-logger.js'
2
- import { getProcessSink, getProcessSinkCounters } from './log/process-sink.js'
1
+ import { NOOP_LOGGER } from './log/create-logger.js'
2
+ import { getProcessSink } from './log/process-sink.js'
3
3
  import type { LogSinkCounters } from './log/types.js'
4
- import { type LevelFilter, type LogSink, SCOPE_ATTRIBUTE } from './log/types.js'
5
4
 
6
5
  export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent'
7
6
 
8
7
  export type LogContext = Record<string, unknown>
9
8
 
10
- const LOG_LEVELS: Record<LogLevel, number> = {
11
- debug: 0,
12
- info: 1,
13
- warn: 2,
14
- error: 3,
15
- // `silent` sits above every emit level so the `level < minLevelNum`
16
- // guard in `log()` always short-circuits when configured. Used by
17
- // test harnesses to suppress unmocked `getRootLogger()` stderr
18
- // writes; see packages/sdk/src/test-setup.ts.
19
- silent: 4,
20
- }
21
-
22
9
  export interface Logger {
23
10
  debug(message: string, data?: LogContext): void
24
11
  info(message: string, data?: LogContext): void
@@ -27,88 +14,21 @@ export interface Logger {
27
14
  child(context: LogContext): Logger
28
15
  }
29
16
 
30
- function createLoggerImpl(name: string, minLevel: LogLevel, parentContext: LogContext): Logger {
31
- const minLevelNum = LOG_LEVELS[minLevel]
32
-
33
- function log(level: LogLevel, message: string, data?: LogContext): void {
34
- if (LOG_LEVELS[level] < minLevelNum) return
35
-
36
- const timestamp = new Date().toISOString()
37
- const prefix = `[${timestamp}] [${level.toUpperCase()}] [${name}]`
38
- const merged = { ...parentContext, ...data }
39
- const hasContext = Object.keys(merged).length > 0
40
-
41
- if (hasContext) {
42
- process.stderr.write(`${prefix} ${message} ${JSON.stringify(merged)}\n`)
43
- } else {
44
- process.stderr.write(`${prefix} ${message}\n`)
45
- }
46
- }
47
-
48
- function child(context: LogContext): Logger {
49
- const { [SCOPE_ATTRIBUTE]: scopeOverride, ...rest } = context
50
- return createLoggerImpl(typeof scopeOverride === 'string' ? scopeOverride : name, minLevel, {
51
- ...parentContext,
52
- ...rest,
53
- })
54
- }
55
-
56
- return {
57
- debug: (msg, data) => log('debug', msg, data),
58
- info: (msg, data) => log('info', msg, data),
59
- warn: (msg, data) => log('warn', msg, data),
60
- error: (msg, data) => log('error', msg, data),
61
- child,
62
- }
63
- }
64
-
65
- let _rootLogger: Logger | null = null
66
-
67
17
  /**
68
- * @deprecated Prefer `installProcessSink` (own the process's log
69
- * destination) or `createLogger` (build a logger scoped to a run, tenant or
70
- * subsystem) from `packages/sdk/src/utils/log/`. `getRootLogger` and
71
- * `configureLogger` read and write one process-wide global with no
72
- * destination lever beyond a level threshold the reason every CLI entry
73
- * point historically had only one option: switch it off entirely.
74
- * Unchanged behaviour; this JSDoc is the only edit.
75
- */
76
- export function getRootLogger(): Logger {
77
- // A process sink, when one is installed, wins over both the cached logger
78
- // and the stderr default. Resolved per CALL rather than cached, for the
79
- // same reason the new pipeline reads its level per record: a logger handed
80
- // out before `installProcessSink` ran would otherwise keep writing to
81
- // stderr forever, which is the exact shape of the three frozen loaders
82
- // this migration just fixed.
83
- //
84
- // This bridge is what lets the ~39 existing `getRootLogger()` call sites
85
- // reach a host's sink without being rewritten in one commit. They keep the
86
- // old interface and gain the new destination.
87
- const installed = getProcessSink()
88
- if (installed) return fromSink(installed.sink, installed.level)
89
-
90
- if (!_rootLogger) {
91
- _rootLogger = createLoggerImpl('namzu', 'info', {})
92
- }
93
- return _rootLogger
94
- }
95
-
96
- /**
97
- * Fall back to the process root only when nobody supplied their own. Kept
98
- * here rather than inlined at each call site so a boundary that threads a
99
- * host-supplied logger can stay entirely free of `getRootLogger()` itself.
100
- * `RunContextFactory.buildLogger` was the first caller (LOG-07); LOG-10
101
- * moved every remaining constructor across `packages/sdk/src` onto this
102
- * same seam, so this function's own fallback is now the ONLY place in the
103
- * package that reads the process-wide global outside a host's direct call
104
- * to `getRootLogger()` itself. `getRootLoggerCount` in
105
- * `scripts/log-standard.json` measures exactly that: it cannot reach zero
106
- * while an optional, non-breaking fallback exists at all — removing the
107
- * fallback (flipping the default to `NOOP_LOGGER`) is LOG-20's major, not
108
- * this seam's.
18
+ * A logger that discards, when nobody supplied one.
19
+ *
20
+ * The fallback used to be a process-wide global, so a construction with no
21
+ * logger silently wrote to stderr from a library, on a stream the host may
22
+ * be using for its own protocol. LOG-20 flipped it: a component given no
23
+ * logger produces nothing, and the drop is counted where `getLogCounters()`
24
+ * can read it.
25
+ *
26
+ * The seam stays rather than being inlined at each call site, so every
27
+ * constructor in the package expresses "logger optional" the same way and one
28
+ * line decides what optional means.
109
29
  */
110
30
  export function resolveLogger(logger: Logger | undefined): Logger {
111
- return logger ?? getRootLogger()
31
+ return logger ?? NOOP_LOGGER
112
32
  }
113
33
 
114
34
  /**
@@ -116,74 +36,13 @@ export function resolveLogger(logger: Logger | undefined): Logger {
116
36
  * when no host has claimed the process's log destination.
117
37
  *
118
38
  * `undefined` is the honest answer for that case, not a zeroed set. With no
119
- * sink installed `getRootLogger` falls back to the legacy stderr writer,
120
- * which has no pipeline and therefore no redaction pass, no size caps and
121
- * nothing to count -- reporting five zeros there would read as "nothing was
122
- * dropped, nothing was redacted", which is a stronger claim than "this was
123
- * never measured" and happens to be the claim a reader most wants to trust.
39
+ * sink installed there is no pipeline, and therefore no redaction pass, no
40
+ * size caps and nothing to count -- reporting five zeros would read as
41
+ * "nothing was dropped, nothing was redacted", a stronger claim than "this
42
+ * was never measured" and the one a reader most wants to trust.
124
43
  * `namzu doctor`'s `logging.pipeline` check turns the absence into its own
125
44
  * row rather than into a clean bill of health.
126
45
  */
127
46
  export function getLogCounters(): LogSinkCounters | undefined {
128
47
  return getProcessSink()?.counters
129
48
  }
130
-
131
- /**
132
- * Adapts the record pipeline back to the legacy `Logger` shape. `scope`
133
- * threads through recursive `child()` calls the same way `bound` does.
134
- * Previously fixed at `'namzu'` on every recursive call regardless of what
135
- * a caller bound — meaning every `getRootLogger()`-derived child logger
136
- * (the majority of call sites in this package) reported the SAME
137
- * `scope.name` no matter what `SCOPE_ATTRIBUTE` it was given. This is the
138
- * single highest-leverage line in the LOG-09 migration: see the direct
139
- * regression test in `runtime/query/__tests__/context.test.ts` and
140
- * `utils/__tests__/log-scope-attribute.test.ts`.
141
- */
142
- function fromSink(
143
- sink: LogSink,
144
- level: LevelFilter,
145
- bound: LogContext = {},
146
- scope = 'namzu',
147
- ): Logger {
148
- // The process's counter set, not a fresh one. `getRootLogger` resolves
149
- // PER CALL and lands here every time, so a logger built with its own
150
- // counters would throw the totals away between one log line and the
151
- // next -- which is what made `LogSinkCounters` unreadable by anything.
152
- const created = createLogger(
153
- {
154
- sink,
155
- level: { current: level },
156
- resource: { 'service.name': 'namzu' },
157
- scope,
158
- },
159
- getProcessSinkCounters(),
160
- )
161
- const write =
162
- (severity: 'debug' | 'info' | 'warn' | 'error') => (message: string, data?: LogContext) => {
163
- created[severity](message, { ...bound, ...data })
164
- }
165
- return {
166
- debug: write('debug'),
167
- info: write('info'),
168
- warn: write('warn'),
169
- error: write('error'),
170
- child: (context: LogContext) => {
171
- const { [SCOPE_ATTRIBUTE]: scopeOverride, ...rest } = context
172
- return fromSink(
173
- sink,
174
- level,
175
- { ...bound, ...rest },
176
- typeof scopeOverride === 'string' ? scopeOverride : scope,
177
- )
178
- },
179
- }
180
- }
181
-
182
- /**
183
- * @deprecated See `getRootLogger`'s deprecation note. `installProcessSink`
184
- * is the strictly more capable replacement — it picks a destination, not
185
- * only a threshold. Unchanged behaviour; this JSDoc is the only edit.
186
- */
187
- export function configureLogger(options: { level?: LogLevel }): void {
188
- _rootLogger = createLoggerImpl('namzu', options.level ?? 'info', {})
189
- }