@namzu/sdk 28.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 +129 -0
- package/dist/agents/ReactiveAgent.d.ts.map +1 -1
- package/dist/agents/ReactiveAgent.js +0 -1
- package/dist/agents/ReactiveAgent.js.map +1 -1
- package/dist/agents/SupervisorAgent.d.ts.map +1 -1
- package/dist/agents/SupervisorAgent.js +2 -4
- package/dist/agents/SupervisorAgent.js.map +1 -1
- package/dist/config/runtime.d.ts +8 -8
- package/dist/contracts/a2a.d.ts +10 -10
- package/dist/contracts/schemas.d.ts +12 -12
- package/dist/manager/index.d.ts +2 -2
- package/dist/manager/index.d.ts.map +1 -1
- package/dist/manager/index.js +2 -2
- package/dist/manager/index.js.map +1 -1
- 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 +21 -9
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +21 -9
- package/dist/public-runtime.js.map +1 -1
- package/dist/runtime/query/index.d.ts +0 -16
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +3 -10
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/session/handoff/broadcast.d.ts +6 -2
- package/dist/session/handoff/broadcast.d.ts.map +1 -1
- package/dist/session/handoff/broadcast.js +1 -2
- package/dist/session/handoff/broadcast.js.map +1 -1
- package/dist/session/handoff/index.d.ts +1 -1
- package/dist/session/handoff/index.d.ts.map +1 -1
- package/dist/session/handoff/index.js +1 -1
- package/dist/session/handoff/index.js.map +1 -1
- package/dist/session/handoff/single.d.ts +7 -3
- package/dist/session/handoff/single.d.ts.map +1 -1
- package/dist/session/handoff/single.js +1 -7
- package/dist/session/handoff/single.js.map +1 -1
- package/dist/session/migration/id-prefix.d.ts +0 -11
- package/dist/session/migration/id-prefix.d.ts.map +1 -1
- package/dist/session/migration/id-prefix.js +0 -11
- package/dist/session/migration/id-prefix.js.map +1 -1
- package/dist/session/migration/index.d.ts +2 -2
- package/dist/session/migration/index.d.ts.map +1 -1
- package/dist/session/migration/index.js +2 -2
- package/dist/session/migration/index.js.map +1 -1
- package/dist/session/retention/archive.d.ts.map +1 -1
- package/dist/session/retention/archive.js +4 -16
- package/dist/session/retention/archive.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/store/topic/memory.d.ts +4 -4
- package/dist/store/topic/memory.js +4 -4
- package/dist/tools/builtins/computer-use.d.ts +8 -8
- package/dist/types/agent/reactive.d.ts +0 -5
- package/dist/types/agent/reactive.d.ts.map +1 -1
- package/dist/types/agent/scheduler.d.ts +0 -10
- package/dist/types/agent/scheduler.d.ts.map +1 -1
- package/dist/types/agent/supervisor.d.ts +0 -10
- package/dist/types/agent/supervisor.d.ts.map +1 -1
- package/dist/types/authorization/index.d.ts +24 -285
- package/dist/types/authorization/index.d.ts.map +1 -1
- package/dist/types/authorization/index.js +0 -4
- package/dist/types/authorization/index.js.map +1 -1
- package/dist/types/common/index.d.ts +0 -8
- package/dist/types/common/index.d.ts.map +1 -1
- package/dist/types/common/index.js.map +1 -1
- package/dist/types/ids/index.d.ts +0 -15
- package/dist/types/ids/index.d.ts.map +1 -1
- package/dist/types/ids/index.js.map +1 -1
- package/dist/types/plugin/index.d.ts +6 -6
- package/dist/types/run/checkpoint-store.d.ts +0 -6
- package/dist/types/run/checkpoint-store.d.ts.map +1 -1
- package/dist/types/session/ids.d.ts +1 -3
- package/dist/types/session/ids.d.ts.map +1 -1
- package/dist/types/session/index.d.ts +1 -3
- package/dist/types/session/index.d.ts.map +1 -1
- package/dist/types/session/sub-session.d.ts +11 -22
- package/dist/types/session/sub-session.d.ts.map +1 -1
- package/dist/utils/id.d.ts +0 -8
- package/dist/utils/id.d.ts.map +1 -1
- package/dist/utils/id.js +0 -8
- package/dist/utils/id.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/agents/ReactiveAgent.ts +0 -1
- package/src/agents/SupervisorAgent.ts +2 -9
- package/src/manager/index.ts +0 -1
- package/src/plugin/loader.ts +10 -12
- package/src/public-runtime.ts +14 -7
- package/src/runtime/query/index.ts +4 -44
- package/src/session/handoff/broadcast.ts +7 -3
- package/src/session/handoff/index.ts +1 -1
- package/src/session/handoff/single.ts +8 -9
- package/src/session/migration/id-prefix.ts +0 -13
- package/src/session/migration/index.ts +0 -2
- package/src/session/retention/archive.ts +4 -17
- package/src/skills/loader.ts +10 -12
- package/src/store/topic/memory.ts +4 -4
- package/src/types/agent/reactive.ts +0 -5
- package/src/types/agent/scheduler.ts +0 -11
- package/src/types/agent/supervisor.ts +0 -11
- package/src/types/authorization/index.ts +0 -10
- package/src/types/common/index.ts +0 -9
- package/src/types/ids/index.ts +0 -15
- package/src/types/run/checkpoint-store.ts +0 -7
- package/src/types/session/ids.ts +0 -2
- package/src/types/session/index.ts +0 -2
- package/src/types/session/sub-session.ts +11 -23
- package/src/utils/id.ts +0 -9
- 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
- package/dist/deprecated-aliases.d.ts +0 -80
- package/dist/deprecated-aliases.d.ts.map +0 -1
- package/dist/deprecated-aliases.js +0 -60
- package/dist/deprecated-aliases.js.map +0 -1
- package/src/deprecated-aliases.ts +0 -86
|
@@ -115,24 +115,11 @@ export type WorkspaceResolver = (
|
|
|
115
115
|
*/
|
|
116
116
|
const ARCHIVABLE: ReadonlySet<SubSessionDelegationStatus> = new Set(['idle', 'failed'])
|
|
117
117
|
|
|
118
|
-
/**
|
|
119
|
-
* Values no code path in this package can write, kept archivable anyway.
|
|
120
|
-
*
|
|
121
|
-
* `merged` and `merge_rejected` sat in the one set above, and nothing has
|
|
122
|
-
* ever produced either — so that membership described a match that could
|
|
123
|
-
* not happen. The temptation is to delete them, and that would be wrong:
|
|
124
|
-
* `SubSessionStore.updateSubSession` takes a whole `SubSession`, so a HOST
|
|
125
|
-
* could have persisted one of these while the wide union permitted it, and
|
|
126
|
-
* dropping them here would strand exactly those records as permanently
|
|
127
|
-
* un-archivable. The union stays wide for one release precisely so such a
|
|
128
|
-
* host can migrate; this set is the other half of that promise.
|
|
129
|
-
*
|
|
130
|
-
* It goes when the six deprecated members go.
|
|
131
|
-
*/
|
|
132
|
-
const ARCHIVABLE_LEGACY: ReadonlySet<SubSessionStatus> = new Set(['merged', 'merge_rejected'])
|
|
133
|
-
|
|
134
118
|
function isArchivable(status: SubSessionStatus): boolean {
|
|
135
|
-
|
|
119
|
+
// No cast any more. `SubSessionStatus` narrowed to the driven variants in
|
|
120
|
+
// NZ-RUNREC-14, so the set and the argument are the same type and a value
|
|
121
|
+
// outside it cannot be constructed to ask about.
|
|
122
|
+
return ARCHIVABLE.has(status)
|
|
136
123
|
}
|
|
137
124
|
|
|
138
125
|
export interface ArchivalManagerDeps {
|
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,
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
* cross-tenant access throws `TenantIsolationError` with no fallback.
|
|
10
10
|
*
|
|
11
11
|
* NZ-TOPIC-01 renamed this from `InMemoryThreadStore` (moved from
|
|
12
|
-
* `store/thread/memory.ts`)
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* `store/thread/memory.ts`) and re-exported the old name as an identity
|
|
13
|
+
* binding. NZ-TOPIC-05 removed that re-export, once 28.0.0 had carried the
|
|
14
|
+
* deprecation to the registry — the class is reachable only as
|
|
15
|
+
* `InMemoryTopicStore` now.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import { StaleThreadError, TenantIsolationError } from '../../session/errors.js'
|
|
@@ -51,11 +51,6 @@ export interface ReactiveAgentConfig extends BaseAgentConfig {
|
|
|
51
51
|
* canonical brick patterns hard-deny instead of executing
|
|
52
52
|
* silently.
|
|
53
53
|
*/
|
|
54
|
-
/**
|
|
55
|
-
* @deprecated Renamed to `authorizationGate`. Removed in the next major.
|
|
56
|
-
* Setting both to different configs throws.
|
|
57
|
-
*/
|
|
58
|
-
verificationGate?: AuthorizationGateConfig
|
|
59
54
|
|
|
60
55
|
authorizationGate?: AuthorizationGateConfig
|
|
61
56
|
|
|
@@ -143,14 +143,3 @@ export interface TaskScheduler {
|
|
|
143
143
|
*/
|
|
144
144
|
onTaskProgress?(callback: (taskId: TaskId) => void): () => void
|
|
145
145
|
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* @deprecated Renamed to {@link TaskScheduler}. Removed in the next major.
|
|
149
|
-
*
|
|
150
|
-
* "Gateway" names an object that sits at a system boundary and faces
|
|
151
|
-
* outward — Fowler's POEAA Gateway, an API gateway, a payment gateway. This
|
|
152
|
-
* one faces inward: it creates, waits on, continues, cancels and lists
|
|
153
|
-
* in-process agent tasks. A reader who trusted the name expected a facade
|
|
154
|
-
* over something external and found a scheduler.
|
|
155
|
-
*/
|
|
156
|
-
export type TaskGateway = TaskScheduler
|
|
@@ -48,12 +48,6 @@ export interface SupervisorAgentConfig extends BaseAgentConfig {
|
|
|
48
48
|
*/
|
|
49
49
|
allowDelegation?: boolean
|
|
50
50
|
|
|
51
|
-
/**
|
|
52
|
-
* @deprecated Renamed to {@link SupervisorAgentConfig.scheduler}. Removed
|
|
53
|
-
* in the next major. Setting both to different instances throws.
|
|
54
|
-
*/
|
|
55
|
-
gateway?: TaskScheduler
|
|
56
|
-
|
|
57
51
|
scheduler?: TaskScheduler
|
|
58
52
|
|
|
59
53
|
/**
|
|
@@ -167,11 +161,6 @@ export interface SupervisorAgentConfig extends BaseAgentConfig {
|
|
|
167
161
|
* review") so the resumeHandler only fires for the truly
|
|
168
162
|
* non-deterministic cases.
|
|
169
163
|
*/
|
|
170
|
-
/**
|
|
171
|
-
* @deprecated Renamed to `authorizationGate`. Removed in the next major.
|
|
172
|
-
* Setting both to different configs throws.
|
|
173
|
-
*/
|
|
174
|
-
verificationGate?: AuthorizationGateConfig
|
|
175
164
|
|
|
176
165
|
authorizationGate?: AuthorizationGateConfig
|
|
177
166
|
|
|
@@ -187,13 +187,3 @@ export type AuthorizationGateConfig = z.infer<typeof AuthorizationGateConfigSche
|
|
|
187
187
|
* Declared as `const` rather than `type` on purpose: a `type` alias would
|
|
188
188
|
* break `typeof`, which is the only way these were ever usable.
|
|
189
189
|
*/
|
|
190
|
-
|
|
191
|
-
/** @deprecated Renamed to {@link AuthorizationRuleSchema}. Removed in the next major. */
|
|
192
|
-
export const VerificationRuleSchema = AuthorizationRuleSchema
|
|
193
|
-
/** @deprecated Renamed to {@link AuthorizationGateConfigSchema}. Removed in the next major. */
|
|
194
|
-
export const VerificationGateConfigSchema = AuthorizationGateConfigSchema
|
|
195
|
-
|
|
196
|
-
/** @deprecated Renamed to {@link AuthorizationRule}. Removed in the next major. */
|
|
197
|
-
export type VerificationRule = AuthorizationRule
|
|
198
|
-
/** @deprecated Renamed to {@link AuthorizationGateConfig}. Removed in the next major. */
|
|
199
|
-
export type VerificationGateConfig = AuthorizationGateConfig
|
|
@@ -15,15 +15,6 @@ export type RunExecutionStatus =
|
|
|
15
15
|
| 'failed'
|
|
16
16
|
| 'cancelled'
|
|
17
17
|
|
|
18
|
-
/**
|
|
19
|
-
* @deprecated Use {@link RunExecutionStatus}. Removal is a later major.
|
|
20
|
-
*
|
|
21
|
-
* The union is unchanged -- this is a rename, and the alias is here so
|
|
22
|
-
* code written against the old name still compiles and warns for one
|
|
23
|
-
* release, per SemVer's deprecate-before-remove.
|
|
24
|
-
*/
|
|
25
|
-
export type AgentStatus = RunExecutionStatus
|
|
26
|
-
|
|
27
18
|
export function isTerminalStatus(status: RunExecutionStatus): boolean {
|
|
28
19
|
return status === 'completed' || status === 'failed' || status === 'cancelled'
|
|
29
20
|
}
|
package/src/types/ids/index.ts
CHANGED
|
@@ -102,21 +102,6 @@ export type ProjectId = Id<'prj', 'ProjectId'>
|
|
|
102
102
|
* gone (Convention #0, no silent long-lived compat).
|
|
103
103
|
*/
|
|
104
104
|
export type TopicId = Id<'top', 'TopicId'>
|
|
105
|
-
/**
|
|
106
|
-
* @deprecated Use {@link TopicId}. Removal is NZ-TOPIC-05.
|
|
107
|
-
*
|
|
108
|
-
* NZ-TOPIC-01 introduced `TopicId` as an alias OF this name; NZ-TOPIC-04
|
|
109
|
-
* reverses the direction. So this alias now follows `TopicId` to the `top_`
|
|
110
|
-
* prefix instead of keeping `thd_` — a consumer still compiling against the
|
|
111
|
-
* old name gets the new prefix, which is exactly what the major announces.
|
|
112
|
-
*
|
|
113
|
-
* It is kept rather than deleted because the deprecation NZ-TOPIC-01 wrote
|
|
114
|
-
* has never reached a registry: `@namzu/sdk` on npm is 27.1.0, and the
|
|
115
|
-
* changeset that would publish it is still unconsumed in `.changeset/`. A
|
|
116
|
-
* removal here would be a rename with no alias wearing a major's clothes.
|
|
117
|
-
* This release is the one that carries the warning; the next may remove it.
|
|
118
|
-
*/
|
|
119
|
-
export type ThreadId = TopicId
|
|
120
105
|
export type SubSessionId = Id<'sub', 'SubSessionId'>
|
|
121
106
|
export type HandoffId = Id<'hof', 'HandoffId'>
|
|
122
107
|
export type WorkspaceId = Id<'wsp', 'WorkspaceId'>
|
|
@@ -281,13 +281,6 @@ export interface LeaseSummary {
|
|
|
281
281
|
* no reading gain — the opposite of the point.
|
|
282
282
|
*/
|
|
283
283
|
|
|
284
|
-
/** @deprecated Renamed to {@link RunLease}. Removed in the next major. */
|
|
285
|
-
export type RunClaim = RunLease
|
|
286
|
-
/** @deprecated Renamed to {@link FencingToken}. Removed in the next major. */
|
|
287
|
-
export type ClaimFence = FencingToken
|
|
288
|
-
/** @deprecated Renamed to {@link LeaseSummary}. Removed in the next major. */
|
|
289
|
-
export type ClaimSummary = LeaseSummary
|
|
290
|
-
|
|
291
284
|
/** What a caller asks for when taking a run. */
|
|
292
285
|
export interface ClaimRunOptions {
|
|
293
286
|
/** Who is taking it. Recorded so an operator can see what holds a stuck run. */
|
package/src/types/session/ids.ts
CHANGED
|
@@ -26,35 +26,23 @@ import type { SubSessionId, SummaryId, WorkspaceId } from './ids.js'
|
|
|
26
26
|
export type SubSessionDelegationStatus = 'pending' | 'active' | 'idle' | 'failed' | 'archived'
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
|
-
* @deprecated Use {@link SubSessionDelegationStatus}.
|
|
30
|
-
*
|
|
29
|
+
* @deprecated Use {@link SubSessionDelegationStatus}. This is now an alias of
|
|
30
|
+
* it and carries no members of its own; the name goes in a later major.
|
|
31
31
|
*
|
|
32
32
|
* The merge half of this union was declared and never driven. Grepping
|
|
33
33
|
* `packages/sdk` and `packages/cli` for each of `awaiting_merge`,
|
|
34
34
|
* `pending_merge`, `merging`, `merged`, `merge_conflict` and
|
|
35
|
-
* `merge_rejected` AS A SUB-SESSION STATUS
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
35
|
+
* `merge_rejected` AS A SUB-SESSION STATUS found no writer at all — the many
|
|
36
|
+
* hits on `awaiting_merge` are `SessionStatus`, which is the shadowing this
|
|
37
|
+
* type's replacement exists to end. Two of them (`merged`, `merge_rejected`)
|
|
38
|
+
* had a READER: they sat in `ARCHIVABLE_STATUSES`, a set that could never
|
|
39
|
+
* match on them.
|
|
40
40
|
*
|
|
41
|
-
* The union
|
|
42
|
-
*
|
|
41
|
+
* The union stayed wide for one release so a host that had persisted one of
|
|
42
|
+
* those values still typechecked while it migrated. 28.0.0 carried that
|
|
43
|
+
* window to the registry and NZ-RUNREC-14 closed it.
|
|
43
44
|
*/
|
|
44
|
-
export type SubSessionStatus =
|
|
45
|
-
| SubSessionDelegationStatus
|
|
46
|
-
/** @deprecated no producer since ratification */
|
|
47
|
-
| 'awaiting_merge'
|
|
48
|
-
/** @deprecated no producer since ratification */
|
|
49
|
-
| 'pending_merge'
|
|
50
|
-
/** @deprecated no producer since ratification */
|
|
51
|
-
| 'merging'
|
|
52
|
-
/** @deprecated no producer since ratification */
|
|
53
|
-
| 'merged'
|
|
54
|
-
/** @deprecated no producer since ratification */
|
|
55
|
-
| 'merge_conflict'
|
|
56
|
-
/** @deprecated no producer since ratification */
|
|
57
|
-
| 'merge_rejected'
|
|
45
|
+
export type SubSessionStatus = SubSessionDelegationStatus
|
|
58
46
|
|
|
59
47
|
/**
|
|
60
48
|
* Discriminator for how a sub-session was created. Pattern doc §4.4
|
package/src/utils/id.ts
CHANGED
|
@@ -89,15 +89,6 @@ export function generateTopicId(): TopicId {
|
|
|
89
89
|
return generateId('top_')
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
/**
|
|
93
|
-
* @deprecated Use {@link generateTopicId}. Removal is NZ-TOPIC-05.
|
|
94
|
-
*
|
|
95
|
-
* Mints `top_` from NZ-TOPIC-04 on — an alias that kept minting `thd_`
|
|
96
|
-
* would hand two different id spaces to one program depending on which
|
|
97
|
-
* name the caller happened to import.
|
|
98
|
-
*/
|
|
99
|
-
export const generateThreadId = generateTopicId
|
|
100
|
-
|
|
101
92
|
export function generateRunId(): RunId {
|
|
102
93
|
return generateId('run_')
|
|
103
94
|
}
|
|
@@ -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
|
package/src/utils/logger.ts
CHANGED
|
@@ -1,24 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getProcessSink
|
|
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
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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 ??
|
|
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
|
|
120
|
-
*
|
|
121
|
-
* nothing
|
|
122
|
-
*
|
|
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
|
-
}
|