@namzu/sdk 29.0.0 → 30.0.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.
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/utils/log/types.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,EAAE;AACF,mEAAmE;AACnE,4EAA4E;AAC5E,4EAA4E;AAC5E,wEAAwE;AACxE,2EAA2E;AAC3E,4BAA4B;AAyF5B;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,kBAAkB,CAAA;AAEtD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,iBAAiB,CAAA;AAEhD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,CAAA"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/utils/log/types.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,EAAE;AACF,4EAA4E;AAC5E,6EAA6E;AAC7E,6EAA6E;AAC7E,wEAAwE;AACxE,8EAA8E;AAC9E,8DAA8D;AAyF9D;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,kBAAkB,CAAA;AAEtD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,iBAAiB,CAAA;AAEhD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,CAAA"}
@@ -9,28 +9,17 @@ export interface Logger {
9
9
  child(context: LogContext): Logger;
10
10
  }
11
11
  /**
12
- * @deprecated Prefer `installProcessSink` (own the process's log
13
- * destination) or `createLogger` (build a logger scoped to a run, tenant or
14
- * subsystem) from `packages/sdk/src/utils/log/`. `getRootLogger` and
15
- * `configureLogger` read and write one process-wide global with no
16
- * destination lever beyond a level threshold the reason every CLI entry
17
- * point historically had only one option: switch it off entirely.
18
- * Unchanged behaviour; this JSDoc is the only edit.
19
- */
20
- export declare function getRootLogger(): Logger;
21
- /**
22
- * Fall back to the process root only when nobody supplied their own. Kept
23
- * here rather than inlined at each call site so a boundary that threads a
24
- * host-supplied logger can stay entirely free of `getRootLogger()` itself.
25
- * `RunContextFactory.buildLogger` was the first caller (LOG-07); LOG-10
26
- * moved every remaining constructor across `packages/sdk/src` onto this
27
- * same seam, so this function's own fallback is now the ONLY place in the
28
- * package that reads the process-wide global outside a host's direct call
29
- * to `getRootLogger()` itself. `getRootLoggerCount` in
30
- * `scripts/log-standard.json` measures exactly that: it cannot reach zero
31
- * while an optional, non-breaking fallback exists at all — removing the
32
- * fallback (flipping the default to `NOOP_LOGGER`) is LOG-20's major, not
33
- * this seam's.
12
+ * A logger that discards, when nobody supplied one.
13
+ *
14
+ * The fallback used to be a process-wide global, so a construction with no
15
+ * logger silently wrote to stderr from a library, on a stream the host may
16
+ * be using for its own protocol. LOG-20 flipped it: a component given no
17
+ * logger produces nothing, and the drop is counted where `getLogCounters()`
18
+ * can read it.
19
+ *
20
+ * The seam stays rather than being inlined at each call site, so every
21
+ * constructor in the package expresses "logger optional" the same way and one
22
+ * line decides what optional means.
34
23
  */
35
24
  export declare function resolveLogger(logger: Logger | undefined): Logger;
36
25
  /**
@@ -38,21 +27,12 @@ export declare function resolveLogger(logger: Logger | undefined): Logger;
38
27
  * when no host has claimed the process's log destination.
39
28
  *
40
29
  * `undefined` is the honest answer for that case, not a zeroed set. With no
41
- * sink installed `getRootLogger` falls back to the legacy stderr writer,
42
- * which has no pipeline and therefore no redaction pass, no size caps and
43
- * nothing to count -- reporting five zeros there would read as "nothing was
44
- * dropped, nothing was redacted", which is a stronger claim than "this was
45
- * never measured" and happens to be the claim a reader most wants to trust.
30
+ * sink installed there is no pipeline, and therefore no redaction pass, no
31
+ * size caps and nothing to count -- reporting five zeros would read as
32
+ * "nothing was dropped, nothing was redacted", a stronger claim than "this
33
+ * was never measured" and the one a reader most wants to trust.
46
34
  * `namzu doctor`'s `logging.pipeline` check turns the absence into its own
47
35
  * row rather than into a clean bill of health.
48
36
  */
49
37
  export declare function getLogCounters(): LogSinkCounters | undefined;
50
- /**
51
- * @deprecated See `getRootLogger`'s deprecation note. `installProcessSink`
52
- * is the strictly more capable replacement — it picks a destination, not
53
- * only a threshold. Unchanged behaviour; this JSDoc is the only edit.
54
- */
55
- export declare function configureLogger(options: {
56
- level?: LogLevel;
57
- }): void;
58
38
  //# sourceMappingURL=logger.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAGrD,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAA;AAErE,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAchD,MAAM,WAAW,MAAM;IACtB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;IAC/C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;IAC9C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;IAC9C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;IAC/C,KAAK,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,CAAA;CAClC;AAuCD;;;;;;;;GAQG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAkBtC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAEhE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,IAAI,eAAe,GAAG,SAAS,CAE5D;AAqDD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE;IAAE,KAAK,CAAC,EAAE,QAAQ,CAAA;CAAE,GAAG,IAAI,CAEnE"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAErD,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAA;AAErE,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEhD,MAAM,WAAW,MAAM;IACtB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;IAC/C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;IAC9C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;IAC9C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;IAC/C,KAAK,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,CAAA;CAClC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAEhE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,IAAI,eAAe,GAAG,SAAS,CAE5D"}
@@ -1,152 +1,34 @@
1
- import { createLogger } from './log/create-logger.js';
2
- import { getProcessSink, getProcessSinkCounters } from './log/process-sink.js';
3
- import { SCOPE_ATTRIBUTE } from './log/types.js';
4
- const LOG_LEVELS = {
5
- debug: 0,
6
- info: 1,
7
- warn: 2,
8
- error: 3,
9
- // `silent` sits above every emit level so the `level < minLevelNum`
10
- // guard in `log()` always short-circuits when configured. Used by
11
- // test harnesses to suppress unmocked `getRootLogger()` stderr
12
- // writes; see packages/sdk/src/test-setup.ts.
13
- silent: 4,
14
- };
15
- function createLoggerImpl(name, minLevel, parentContext) {
16
- const minLevelNum = LOG_LEVELS[minLevel];
17
- function log(level, message, data) {
18
- if (LOG_LEVELS[level] < minLevelNum)
19
- return;
20
- const timestamp = new Date().toISOString();
21
- const prefix = `[${timestamp}] [${level.toUpperCase()}] [${name}]`;
22
- const merged = { ...parentContext, ...data };
23
- const hasContext = Object.keys(merged).length > 0;
24
- if (hasContext) {
25
- process.stderr.write(`${prefix} ${message} ${JSON.stringify(merged)}\n`);
26
- }
27
- else {
28
- process.stderr.write(`${prefix} ${message}\n`);
29
- }
30
- }
31
- function child(context) {
32
- const { [SCOPE_ATTRIBUTE]: scopeOverride, ...rest } = context;
33
- return createLoggerImpl(typeof scopeOverride === 'string' ? scopeOverride : name, minLevel, {
34
- ...parentContext,
35
- ...rest,
36
- });
37
- }
38
- return {
39
- debug: (msg, data) => log('debug', msg, data),
40
- info: (msg, data) => log('info', msg, data),
41
- warn: (msg, data) => log('warn', msg, data),
42
- error: (msg, data) => log('error', msg, data),
43
- child,
44
- };
45
- }
46
- let _rootLogger = null;
47
- /**
48
- * @deprecated Prefer `installProcessSink` (own the process's log
49
- * destination) or `createLogger` (build a logger scoped to a run, tenant or
50
- * subsystem) from `packages/sdk/src/utils/log/`. `getRootLogger` and
51
- * `configureLogger` read and write one process-wide global with no
52
- * destination lever beyond a level threshold — the reason every CLI entry
53
- * point historically had only one option: switch it off entirely.
54
- * Unchanged behaviour; this JSDoc is the only edit.
55
- */
56
- export function getRootLogger() {
57
- // A process sink, when one is installed, wins over both the cached logger
58
- // and the stderr default. Resolved per CALL rather than cached, for the
59
- // same reason the new pipeline reads its level per record: a logger handed
60
- // out before `installProcessSink` ran would otherwise keep writing to
61
- // stderr forever, which is the exact shape of the three frozen loaders
62
- // this migration just fixed.
63
- //
64
- // This bridge is what lets the ~39 existing `getRootLogger()` call sites
65
- // reach a host's sink without being rewritten in one commit. They keep the
66
- // old interface and gain the new destination.
67
- const installed = getProcessSink();
68
- if (installed)
69
- return fromSink(installed.sink, installed.level);
70
- if (!_rootLogger) {
71
- _rootLogger = createLoggerImpl('namzu', 'info', {});
72
- }
73
- return _rootLogger;
74
- }
1
+ import { NOOP_LOGGER } from './log/create-logger.js';
2
+ import { getProcessSink } from './log/process-sink.js';
75
3
  /**
76
- * Fall back to the process root only when nobody supplied their own. Kept
77
- * here rather than inlined at each call site so a boundary that threads a
78
- * host-supplied logger can stay entirely free of `getRootLogger()` itself.
79
- * `RunContextFactory.buildLogger` was the first caller (LOG-07); LOG-10
80
- * moved every remaining constructor across `packages/sdk/src` onto this
81
- * same seam, so this function's own fallback is now the ONLY place in the
82
- * package that reads the process-wide global outside a host's direct call
83
- * to `getRootLogger()` itself. `getRootLoggerCount` in
84
- * `scripts/log-standard.json` measures exactly that: it cannot reach zero
85
- * while an optional, non-breaking fallback exists at all removing the
86
- * fallback (flipping the default to `NOOP_LOGGER`) is LOG-20's major, not
87
- * this seam's.
4
+ * A logger that discards, when nobody supplied one.
5
+ *
6
+ * The fallback used to be a process-wide global, so a construction with no
7
+ * logger silently wrote to stderr from a library, on a stream the host may
8
+ * be using for its own protocol. LOG-20 flipped it: a component given no
9
+ * logger produces nothing, and the drop is counted where `getLogCounters()`
10
+ * can read it.
11
+ *
12
+ * The seam stays rather than being inlined at each call site, so every
13
+ * constructor in the package expresses "logger optional" the same way and one
14
+ * line decides what optional means.
88
15
  */
89
16
  export function resolveLogger(logger) {
90
- return logger ?? getRootLogger();
17
+ return logger ?? NOOP_LOGGER;
91
18
  }
92
19
  /**
93
20
  * What the record pipeline did to the records it was given, or `undefined`
94
21
  * when no host has claimed the process's log destination.
95
22
  *
96
23
  * `undefined` is the honest answer for that case, not a zeroed set. With no
97
- * sink installed `getRootLogger` falls back to the legacy stderr writer,
98
- * which has no pipeline and therefore no redaction pass, no size caps and
99
- * nothing to count -- reporting five zeros there would read as "nothing was
100
- * dropped, nothing was redacted", which is a stronger claim than "this was
101
- * never measured" and happens to be the claim a reader most wants to trust.
24
+ * sink installed there is no pipeline, and therefore no redaction pass, no
25
+ * size caps and nothing to count -- reporting five zeros would read as
26
+ * "nothing was dropped, nothing was redacted", a stronger claim than "this
27
+ * was never measured" and the one a reader most wants to trust.
102
28
  * `namzu doctor`'s `logging.pipeline` check turns the absence into its own
103
29
  * row rather than into a clean bill of health.
104
30
  */
105
31
  export function getLogCounters() {
106
32
  return getProcessSink()?.counters;
107
33
  }
108
- /**
109
- * Adapts the record pipeline back to the legacy `Logger` shape. `scope`
110
- * threads through recursive `child()` calls the same way `bound` does.
111
- * Previously fixed at `'namzu'` on every recursive call regardless of what
112
- * a caller bound — meaning every `getRootLogger()`-derived child logger
113
- * (the majority of call sites in this package) reported the SAME
114
- * `scope.name` no matter what `SCOPE_ATTRIBUTE` it was given. This is the
115
- * single highest-leverage line in the LOG-09 migration: see the direct
116
- * regression test in `runtime/query/__tests__/context.test.ts` and
117
- * `utils/__tests__/log-scope-attribute.test.ts`.
118
- */
119
- function fromSink(sink, level, bound = {}, scope = 'namzu') {
120
- // The process's counter set, not a fresh one. `getRootLogger` resolves
121
- // PER CALL and lands here every time, so a logger built with its own
122
- // counters would throw the totals away between one log line and the
123
- // next -- which is what made `LogSinkCounters` unreadable by anything.
124
- const created = createLogger({
125
- sink,
126
- level: { current: level },
127
- resource: { 'service.name': 'namzu' },
128
- scope,
129
- }, getProcessSinkCounters());
130
- const write = (severity) => (message, data) => {
131
- created[severity](message, { ...bound, ...data });
132
- };
133
- return {
134
- debug: write('debug'),
135
- info: write('info'),
136
- warn: write('warn'),
137
- error: write('error'),
138
- child: (context) => {
139
- const { [SCOPE_ATTRIBUTE]: scopeOverride, ...rest } = context;
140
- return fromSink(sink, level, { ...bound, ...rest }, typeof scopeOverride === 'string' ? scopeOverride : scope);
141
- },
142
- };
143
- }
144
- /**
145
- * @deprecated See `getRootLogger`'s deprecation note. `installProcessSink`
146
- * is the strictly more capable replacement — it picks a destination, not
147
- * only a threshold. Unchanged behaviour; this JSDoc is the only edit.
148
- */
149
- export function configureLogger(options) {
150
- _rootLogger = createLoggerImpl('namzu', options.level ?? 'info', {});
151
- }
152
34
  //# sourceMappingURL=logger.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAetD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,aAAa,CAAC,MAA0B;IACvD,OAAO,MAAM,IAAI,WAAW,CAAA;AAC7B,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,cAAc;IAC7B,OAAO,cAAc,EAAE,EAAE,QAAQ,CAAA;AAClC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@namzu/sdk",
3
- "version": "29.0.0",
3
+ "version": "30.0.0",
4
4
  "description": "Open-source AI agent SDK with a built-in runtime. Nothing between you and your agents.",
5
5
  "license": "FSL-1.1-MIT",
6
6
  "type": "module",
@@ -15,18 +15,16 @@ import { type Logger, resolveLogger } from '../utils/logger.js'
15
15
  * Returns an array of absolute paths to plugin directories.
16
16
  */
17
17
  export async function discoverPlugins(parentDir: string, log?: Logger): Promise<string[]> {
18
- // Resolved here, not at module scope. A module-scope
19
- // `getRootLogger().child(...)` ran once, at import time — before any
20
- // host's `configureLogger()` call had a chance to run and `child()`
21
- // bakes `minLevel` into the closure `log()` reads from forever after
22
- // (`utils/logger.ts`), so whatever level was live at that one moment
23
- // was permanent. `configureLogger` replaces the `_rootLogger` binding
24
- // rather than mutating the object it points at, so caching the CHILD
25
- // (as this loader did) survives no later call at all — including the
26
- // CLI's own `configureLogger({ level: 'silent' })`.
27
- //
28
- // `log`, when a caller has one, wins over the process default — LOG-10:
29
- // this was the module's own remaining getRootLogger() call site.
18
+ // Resolved here, not at module scope, and the reason outlived the defect
19
+ // it was written for. A module-scope `child(...)` of a process-wide logger
20
+ // ran once at IMPORT time and baked that moment's level in forever, which
21
+ // no later host call could undo. LOG-20 removed the process-wide logger
22
+ // altogether, so that particular trap is gone and per-call resolution
23
+ // matters more now, not less: the logger this function uses comes from its
24
+ // own `log` parameter, and anything resolved at module scope could not see
25
+ // it. Without a `log`, discovery emits nothing (`resolveLogger` is
26
+ // `NOOP_LOGGER`), which is the deliberate default rather than a fallback
27
+ // to somebody else's stream.
30
28
  const logger = resolveLogger(log).child({ [SCOPE_ATTRIBUTE]: 'plugin/loader' })
31
29
  const dirs: string[] = []
32
30
 
@@ -81,7 +81,20 @@ export {
81
81
  // model list, so that check lives in the driver and needs this.
82
82
  export { normaliseModelId, resolveModelPricing, VENDOR_RATES } from './pricing/index.js'
83
83
  export { toErrorMessage } from './utils/error.js'
84
- export { configureLogger, getLogCounters, getRootLogger, Logger } from './utils/logger.js'
84
+ export { getLogCounters, Logger } from './utils/logger.js'
85
+ /**
86
+ * The process sink's own counter set, for a host that installs a sink and
87
+ * then builds its own logger from it.
88
+ *
89
+ * Exported by LOG-20 out of necessity rather than design. Removing
90
+ * `getRootLogger` removed `fromSink`, which was the only thing passing this
91
+ * set into a `createLogger`. Without it every host-written record counts into
92
+ * a private set, `getLogCounters()` reports a permanently zeroed one, and
93
+ * `namzu doctor`'s `logging.pipeline` check reads health it never measured —
94
+ * a check that cannot fail, introduced by the removal that was supposed to
95
+ * end them.
96
+ */
97
+ export { getProcessSinkCounters } from './utils/log/process-sink.js'
85
98
 
86
99
  // The LogSink seam — additive. `Logger`/`getRootLogger`/`configureLogger`
87
100
  // above are unchanged; this is the new seam that replaces them going
@@ -167,18 +167,16 @@ export async function loadSkill(
167
167
  const metadataTokens = estimateTokens(`${metadata.name}: ${metadata.description}`)
168
168
  const bodyTokens = skill.body ? estimateTokens(skill.body) : 0
169
169
 
170
- // Resolved here, not at module scope. A module-scope
171
- // `getRootLogger().child(...)` ran once, at import time — before any
172
- // host's `configureLogger()` call had a chance to run and `child()`
173
- // bakes `minLevel` into the closure `log()` reads from forever after
174
- // (`utils/logger.ts`), so whatever level was live at that one moment
175
- // was permanent. `configureLogger` replaces the `_rootLogger` binding
176
- // rather than mutating the object it points at, so caching the CHILD
177
- // (as this loader did) survives no later call at all — including the
178
- // CLI's own `configureLogger({ level: 'silent' })`.
179
- //
180
- // `log`, when the caller has one (`SkillRegistry` now does), wins over
181
- // the process default.
170
+ // Resolved here, not at module scope, and the reason outlived the defect
171
+ // it was written for. A module-scope `child(...)` of a process-wide logger
172
+ // ran once at IMPORT time and baked that moment's level in forever, which
173
+ // no later host call could undo. LOG-20 removed the process-wide logger
174
+ // altogether, so that particular trap is gone and per-call resolution
175
+ // matters more now, not less: the logger this function uses comes from its
176
+ // own `log` parameter, and anything resolved at module scope could not see
177
+ // it. Without a `log`, this loader emits nothing (`resolveLogger` is
178
+ // `NOOP_LOGGER`), which is the deliberate default rather than a fallback
179
+ // to somebody else's stream.
182
180
  const logger = resolveLogger(log).child({ [SCOPE_ATTRIBUTE]: 'skills/loader' })
183
181
  logger.debug('Loaded skill', {
184
182
  'namzu.skills.name': metadata.name,
@@ -10,7 +10,8 @@
10
10
  // unwrapping, while a caller that wants to observe the pipeline reads
11
11
  // `.counters` off the same reference. That caller is now real: LOG-06's
12
12
  // `logging.pipeline` doctor check. It could not have been while every
13
- // `getRootLogger()` built a logger with its own counters — see `shared`
13
+ // the removed process-wide accessor built a logger with its own counters
14
+ // on every call — see `shared`
14
15
  // below and `utils/__tests__/log-counters-are-process-wide.test.ts`.
15
16
 
16
17
  import { getActiveSpanContext } from '../../telemetry/runtime-accessors.js'
@@ -49,9 +50,9 @@ export function newCounters(): MutableLogSinkCounters {
49
50
  /**
50
51
  * `shared` lets several loggers write through ONE counter set.
51
52
  *
52
- * Without it the counters answer a question nobody asks. `getRootLogger()`
53
- * resolves per call and builds a fresh logger each time, so every count it
54
- * accumulated died with the expression that read it -- the five fields were
53
+ * Without it the counters answer a question nobody asks. The process-wide
54
+ * accessor this seam replaced resolved per call and built a fresh logger each
55
+ * time, so every count it accumulated died with the expression that read it -- the five fields were
55
56
  * incremented on every record in the process and read by nothing, which is
56
57
  * `declared-but-undriven` with a comment above it promising `namzu doctor`
57
58
  * would read them. `installProcessSink` now owns one set for the process,
@@ -71,10 +72,11 @@ function build(
71
72
  ): CreatedLogger {
72
73
  function emit(severityText: Severity, body: string, data?: LogContext): void {
73
74
  // Read per record, off the shared mutable holder — never resolved once
74
- // and captured in this closure. Today's `Logger.child()` bakes its level
75
- // in exactly that way, which is why three module-scope loggers in the
76
- // skills/plugin loaders are frozen at `info` forever and unreachable by
77
- // any later `configureLogger` call.
75
+ // and captured in this closure. That is what lets a host retune a
76
+ // logger it has already handed out: assign `level.current` and the next
77
+ // record honours it. The alternative, resolving once at construction,
78
+ // is what froze three module-scope loggers in the skills and plugin
79
+ // loaders at `info` for the life of the process, reachable by nothing.
78
80
  if (SEVERITY_RANK[severityText] < LEVEL_RANK[options.level.current]) return
79
81
 
80
82
  const now = Date.now()
@@ -1,13 +1,16 @@
1
- // The replacement for `configureLogger`'s "one process, one global" model
2
- // still one process-wide destination (a CLI genuinely owns the whole
3
- // process), but a destination, not only a threshold: `configureLogger` could
4
- // only raise or lower a level against a fixed `process.stderr.write`.
1
+ // One process-wide DESTINATION, and nothing else process-wide.
5
2
  //
6
- // `getRootLogger` reads this: when a sink is installed, the deprecated
7
- // accessor routes through it instead of writing straight to stderr. That
8
- // bridge is what makes the seam reachable without rewriting the ~39 existing
9
- // `getRootLogger()` call sites in one commit they keep the old shape and
10
- // gain the new destination.
3
+ // This replaced a "one process, one global logger" model that could only
4
+ // raise or lower a level against a fixed `process.stderr.write` — a
5
+ // threshold, never a destination. A CLI genuinely does own its whole process,
6
+ // so a single installed sink is the right shape for that half.
7
+ //
8
+ // What it deliberately is NOT is a logger. Installing a sink does not reroute
9
+ // anything on its own: it sets where records go and owns the counter set, and
10
+ // the host builds a logger over it (`createLogger`, passing
11
+ // `getProcessSinkCounters()`) and hands that down. LOG-20 removed the global
12
+ // accessor that used to bridge the two automatically, because "automatically"
13
+ // meant a library nobody handed a logger wrote to the host's stderr.
11
14
 
12
15
  import { newCounters } from './create-logger.js'
13
16
  import type { LevelFilter, LogSink, LogSinkCounters, MutableLogSinkCounters } from './types.js'
@@ -55,10 +58,13 @@ export function getProcessSink():
55
58
  /**
56
59
  * The mutable counter set the installed destination writes through.
57
60
  *
58
- * Internal: a reader wants {@link getProcessSink}'s readonly view. This
59
- * exists so `getRootLogger`'s bridge can hand the SAME object to every
60
- * logger it builds, which is what makes the totals process-wide rather
61
- * than per-call.
61
+ * Internal in spirit, exported in fact: a mere reader wants
62
+ * {@link getProcessSink}'s readonly view. A HOST needs this one, because it
63
+ * is what makes the totals describe the process rather than one logger — it
64
+ * hands the same object to every logger it builds, so `getLogCounters()` and
65
+ * `namzu doctor`'s `logging.pipeline` check see one set of numbers. A global
66
+ * accessor used to do that on the host's behalf; with it gone, the host does
67
+ * it, which is why this is reachable from `@namzu/sdk` at all.
62
68
  */
63
69
  export function getProcessSinkCounters(): MutableLogSinkCounters | undefined {
64
70
  return _processSink?.counters
@@ -1,11 +1,11 @@
1
1
  // The LogSink seam's record and pipeline types.
2
2
  //
3
- // `../logger.ts` keeps `Logger`, `LogContext`, `getRootLogger` and
4
- // `configureLogger` completely unchanged `Logger` is in INPUT position on
5
- // the public surface (`logger?: Logger` on `RunConfig` and tool config), so
6
- // every host's existing implementation must keep satisfying it forever.
7
- // Everything here is additive: a new, structurally separate seam that does
8
- // not touch that interface.
3
+ // `../logger.ts` keeps `Logger` and `LogContext` unchanged — `Logger` is in
4
+ // INPUT position on the public surface (`logger?: Logger` on `RunConfig` and
5
+ // tool config), so every host's existing implementation must keep satisfying
6
+ // it forever. This seam was additive when it landed and stayed that way
7
+ // through LOG-20, which removed the two process-global accessors that used to
8
+ // sit beside those types without touching either type itself.
9
9
 
10
10
  /**
11
11
  * The severity vocabulary Namzu actually emits. `trace` and `fatal` are
@@ -157,13 +157,18 @@ export interface LoggerOptions {
157
157
  readonly sink: LogSink
158
158
  /**
159
159
  * A mutable holder, read per record inside `createLogger`'s dispatch —
160
- * never captured in a closure at construction. `child()` on today's
161
- * `Logger` bakes its level in exactly that way, which is why the
162
- * module-scope loggers in `skills/loader.ts`, `skills/registry.ts` and
163
- * `plugin/loader.ts` are frozen at `info` forever and unreachable by any
164
- * later `configureLogger` call verified live: `skills/loader.ts:12`,
165
- * `skills/registry.ts:10` and `plugin/loader.ts:12` all call
166
- * `getRootLogger().child({...})` at module load time.
160
+ * never captured in a closure at construction. Assigning `level.current`
161
+ * therefore retunes a logger already handed out, which is the whole reason
162
+ * this is a box and not a value.
163
+ *
164
+ * The defect it was designed against: a `child()` that baked its level in
165
+ * at construction, combined with module-scope loggers built at IMPORT
166
+ * time, froze three loaders at `info` for the life of the process and no
167
+ * later call could reach them. Those loaders resolve their logger per call
168
+ * now, and the process-wide accessor they resolved it FROM no longer
169
+ * exists — so this box is what remains of that fix, and the named
170
+ * line numbers that used to be quoted here are deliberately gone: they
171
+ * were a claim about the tree that the tree stopped honouring.
167
172
  */
168
173
  readonly level: { current: LevelFilter }
169
174
  readonly resource: Resource