@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.
- package/CHANGELOG.md +36 -0
- package/dist/plugin/loader.d.ts.map +1 -1
- package/dist/plugin/loader.js +10 -12
- package/dist/plugin/loader.js.map +1 -1
- package/dist/public-runtime.d.ts +14 -1
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +14 -1
- package/dist/public-runtime.js.map +1 -1
- package/dist/skills/loader.d.ts.map +1 -1
- package/dist/skills/loader.js +10 -12
- package/dist/skills/loader.js.map +1 -1
- package/dist/utils/log/create-logger.d.ts +3 -3
- package/dist/utils/log/create-logger.d.ts.map +1 -1
- package/dist/utils/log/create-logger.js +10 -8
- package/dist/utils/log/create-logger.js.map +1 -1
- package/dist/utils/log/process-sink.d.ts +7 -4
- package/dist/utils/log/process-sink.d.ts.map +1 -1
- package/dist/utils/log/process-sink.js +19 -13
- package/dist/utils/log/process-sink.js.map +1 -1
- package/dist/utils/log/types.d.ts +12 -7
- package/dist/utils/log/types.d.ts.map +1 -1
- package/dist/utils/log/types.js +6 -6
- package/dist/utils/log/types.js.map +1 -1
- package/dist/utils/logger.d.ts +15 -35
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +18 -136
- package/dist/utils/logger.js.map +1 -1
- package/package.json +1 -1
- package/src/plugin/loader.ts +10 -12
- package/src/public-runtime.ts +14 -1
- package/src/skills/loader.ts +10 -12
- package/src/utils/log/create-logger.ts +10 -8
- package/src/utils/log/process-sink.ts +19 -13
- package/src/utils/log/types.ts +18 -13
- package/src/utils/logger.ts +18 -159
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/utils/log/types.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,EAAE;AACF,
|
|
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"}
|
package/dist/utils/logger.d.ts
CHANGED
|
@@ -9,28 +9,17 @@ export interface Logger {
|
|
|
9
9
|
child(context: LogContext): Logger;
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
*
|
|
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
|
|
42
|
-
*
|
|
43
|
-
* nothing
|
|
44
|
-
*
|
|
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;
|
|
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"}
|
package/dist/utils/logger.js
CHANGED
|
@@ -1,152 +1,34 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getProcessSink
|
|
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
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
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 ??
|
|
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
|
|
98
|
-
*
|
|
99
|
-
* nothing
|
|
100
|
-
*
|
|
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
|
package/dist/utils/logger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
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
package/src/plugin/loader.ts
CHANGED
|
@@ -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
|
|
19
|
-
// `
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
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
|
|
package/src/public-runtime.ts
CHANGED
|
@@ -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 {
|
|
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
|
package/src/skills/loader.ts
CHANGED
|
@@ -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
|
|
171
|
-
// `
|
|
172
|
-
//
|
|
173
|
-
//
|
|
174
|
-
//
|
|
175
|
-
//
|
|
176
|
-
//
|
|
177
|
-
//
|
|
178
|
-
//
|
|
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
|
-
//
|
|
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.
|
|
53
|
-
*
|
|
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.
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
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
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
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
|
package/src/utils/log/types.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// The LogSink seam's record and pipeline types.
|
|
2
2
|
//
|
|
3
|
-
// `../logger.ts` keeps `Logger
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
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. `
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
* `
|
|
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
|