@zhushanwen/pi-extension-logger 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhushanwen/pi-extension-logger",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "Shared logging helper for Pi extensions — two-channel routing (audit appendEntry / debug file log; the third AI-realtime channel stays with pi native) (shared library, not a Pi extension - no install.mjs needed)",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -27,7 +27,7 @@ describe("extension-logger", () => {
27
27
  setPiHandle(undefined);
28
28
  clearRateLimiterState();
29
29
  vi.restoreAllMocks();
30
- // 还原环境变量,避免文件日志测试的 XYZ_AGENT_DEBUG/PI_CODING_AGENT_DIR 泄漏到其它用例
30
+ // 还原环境变量,避免文件日志测试的 TAIJI_AGENT_DEBUG/PI_CODING_AGENT_DIR 泄漏到其它用例
31
31
  process.env = { ...prevEnv };
32
32
  });
33
33
 
@@ -140,7 +140,7 @@ describe("extension-logger", () => {
140
140
  });
141
141
  });
142
142
 
143
- describe("XYZ_AGENT_DEBUG 文件日志", () => {
143
+ describe("TAIJI_AGENT_DEBUG 文件日志", () => {
144
144
  // 文件日志的 agentDir 通过 getAgentDir() 推导(读 PI_CODING_AGENT_DIR,
145
145
  // 默认 ~/.pi/agent)。设 PI_CODING_AGENT_DIR 到 tmpdir 子目录,与组 A 的
146
146
  // arch-boundary 改动(fileLog 用 getAgentDir())保持一致。
@@ -159,15 +159,15 @@ describe("extension-logger", () => {
159
159
  }
160
160
  });
161
161
 
162
- it("XYZ_AGENT_DEBUG 未设时 debug 是 no-op(不抛错即可)", () => {
163
- delete process.env.XYZ_AGENT_DEBUG;
162
+ it("TAIJI_AGENT_DEBUG 未设时 debug 是 no-op(不抛错即可)", () => {
163
+ delete process.env.TAIJI_AGENT_DEBUG;
164
164
  const logger = createLogger("test", pi);
165
165
  expect(() => logger.debug("no-op")).not.toThrow();
166
166
  });
167
167
 
168
168
  // ---- Suggestion #8:fileLog 实际写入路径 ----
169
- it("XYZ_AGENT_DEBUG=1 时 debug 写入日志文件,内容含 [debug] 与序列化 data", () => {
170
- process.env.XYZ_AGENT_DEBUG = "1";
169
+ it("TAIJI_AGENT_DEBUG=1 时 debug 写入日志文件,内容含 [debug] 与序列化 data", () => {
170
+ process.env.TAIJI_AGENT_DEBUG = "1";
171
171
  // 固定日期 → 文件名 <extName>-2026-08-01.log
172
172
  vi.setSystemTime(new Date("2026-08-01T12:34:56.789Z"));
173
173
 
@@ -190,8 +190,8 @@ describe("extension-logger", () => {
190
190
  expect(appendSpy).not.toHaveBeenCalled();
191
191
  });
192
192
 
193
- it("XYZ_AGENT_DEBUG=1 时 warn 既写文件又走 appendEntry(文件内容含 [warn])", () => {
194
- process.env.XYZ_AGENT_DEBUG = "1";
193
+ it("TAIJI_AGENT_DEBUG=1 时 warn 既写文件又走 appendEntry(文件内容含 [warn])", () => {
194
+ process.env.TAIJI_AGENT_DEBUG = "1";
195
195
  vi.setSystemTime(new Date("2026-08-01T12:34:56.789Z"));
196
196
 
197
197
  const logger = createLogger("warn-ext", pi);
@@ -207,8 +207,8 @@ describe("extension-logger", () => {
207
207
  expect(appendSpy).toHaveBeenCalledOnce();
208
208
  });
209
209
 
210
- it("XYZ_AGENT_DEBUG=1 写失败(只读目录)不 throw", () => {
211
- process.env.XYZ_AGENT_DEBUG = "1";
210
+ it("TAIJI_AGENT_DEBUG=1 写失败(只读目录)不 throw", () => {
211
+ process.env.TAIJI_AGENT_DEBUG = "1";
212
212
  vi.setSystemTime(new Date("2026-08-01T12:34:56.789Z"));
213
213
 
214
214
  // 已存在的 logs 目录改为只读,让 mkdirSync/appendFileSync 失败。
@@ -243,13 +243,13 @@ describe("extension-logger", () => {
243
243
  const [, entry] = appendSpy.mock.calls[0]!;
244
244
  // appendEntry payload 的 data 字段保留原对象(safeStringify 仅在文件日志路径用)
245
245
  expect(entry).toMatchObject({ level: "warn" });
246
- // 验证 safeStringify 的 fallback 分支:用 XYZ_AGENT_DEBUG=1 触发 fileLog,
246
+ // 验证 safeStringify 的 fallback 分支:用 TAIJI_AGENT_DEBUG=1 触发 fileLog,
247
247
  // 文件内 data 应是 String() 形式(含 [object Object] 或循环结构字符串)
248
248
  expect(() => JSON.stringify(cyclic)).toThrow(); // 对照:原对象确实不可序列化
249
249
  });
250
250
 
251
251
  it("BigInt:warn 不崩,文件日志路径走 String fallback", () => {
252
- process.env.XYZ_AGENT_DEBUG = "1";
252
+ process.env.TAIJI_AGENT_DEBUG = "1";
253
253
  const tmpAgentDir = mkdtempSync(join(tmpdir(), "pi-ext-bigint-"));
254
254
  process.env.PI_CODING_AGENT_DIR = tmpAgentDir;
255
255
  vi.setSystemTime(new Date("2026-08-01T12:34:56.789Z"));
@@ -274,16 +274,16 @@ describe("extension-logger", () => {
274
274
  });
275
275
 
276
276
  // ============================================================
277
- // XYZ_AGENT_EXT_LOG 托管观测档(设计 file-lock-unification-and-reaper-sink §3.2-D4)
277
+ // TAIJI_AGENT_EXT_LOG 托管观测档(设计 file-lock-unification-and-reaper-sink §3.2-D4)
278
278
  // ============================================================
279
- describe("XYZ_AGENT_EXT_LOG 托管观测档", () => {
279
+ describe("TAIJI_AGENT_EXT_LOG 托管观测档", () => {
280
280
  let tmpAgentDir: string;
281
281
 
282
282
  beforeEach(() => {
283
283
  tmpAgentDir = mkdtempSync(join(tmpdir(), "pi-ext-extlog-"));
284
284
  process.env.PI_CODING_AGENT_DIR = tmpAgentDir;
285
- delete process.env.XYZ_AGENT_DEBUG;
286
- delete process.env.XYZ_AGENT_EXT_LOG;
285
+ delete process.env.TAIJI_AGENT_DEBUG;
286
+ delete process.env.TAIJI_AGENT_EXT_LOG;
287
287
  resetExtLogCleanupForTest();
288
288
  vi.useFakeTimers();
289
289
  });
@@ -302,8 +302,8 @@ describe("extension-logger", () => {
302
302
  expect(existsSync(join(tmpAgentDir, "logs"))).toBe(false);
303
303
  });
304
304
 
305
- it("仅 XYZ_AGENT_EXT_LOG=1:debug 调用以 info 级落盘(含序列化 data),不标 debug", () => {
306
- process.env.XYZ_AGENT_EXT_LOG = "1";
305
+ it("仅 TAIJI_AGENT_EXT_LOG=1:debug 调用以 info 级落盘(含序列化 data),不标 debug", () => {
306
+ process.env.TAIJI_AGENT_EXT_LOG = "1";
307
307
  vi.setSystemTime(new Date("2026-08-01T12:34:56.789Z"));
308
308
 
309
309
  const logger = createLogger("extlog-ext", pi);
@@ -320,8 +320,8 @@ describe("extension-logger", () => {
320
320
  expect(appendSpy).not.toHaveBeenCalled();
321
321
  });
322
322
 
323
- it("仅 XYZ_AGENT_EXT_LOG=1:warn/error 照常落盘且保持原级标注", () => {
324
- process.env.XYZ_AGENT_EXT_LOG = "1";
323
+ it("仅 TAIJI_AGENT_EXT_LOG=1:warn/error 照常落盘且保持原级标注", () => {
324
+ process.env.TAIJI_AGENT_EXT_LOG = "1";
325
325
  vi.setSystemTime(new Date("2026-08-01T12:34:56.789Z"));
326
326
 
327
327
  const logger = createLogger("extlog-err", pi);
@@ -335,9 +335,9 @@ describe("extension-logger", () => {
335
335
  expect(content).not.toContain("[info]");
336
336
  });
337
337
 
338
- it("XYZ_AGENT_DEBUG=1 与 EXT_LOG 同注入:按更详细的生效(debug 全量,原级标注)", () => {
339
- process.env.XYZ_AGENT_EXT_LOG = "1";
340
- process.env.XYZ_AGENT_DEBUG = "1";
338
+ it("TAIJI_AGENT_DEBUG=1 与 EXT_LOG 同注入:按更详细的生效(debug 全量,原级标注)", () => {
339
+ process.env.TAIJI_AGENT_EXT_LOG = "1";
340
+ process.env.TAIJI_AGENT_DEBUG = "1";
341
341
  vi.setSystemTime(new Date("2026-08-01T12:34:56.789Z"));
342
342
 
343
343
  const logger = createLogger("both-ext", pi);
@@ -355,7 +355,7 @@ describe("extension-logger", () => {
355
355
  });
356
356
 
357
357
  it("保留期清理:7 天前的 <ext>-<date>.log 被删,近期与本包 pattern 外文件保留", () => {
358
- process.env.XYZ_AGENT_EXT_LOG = "1";
358
+ process.env.TAIJI_AGENT_EXT_LOG = "1";
359
359
  // fake timers 冻结 Date 在真实当前时刻:文件 mtime 走真实时钟,utimesSync 把
360
360
  // old 的 mtime 设为 8 天前(> 7 天保留期),recent 与 unrelated 保留。
361
361
  const logDir = join(tmpAgentDir, "logs");
@@ -381,7 +381,7 @@ describe("extension-logger", () => {
381
381
  });
382
382
 
383
383
  it("清理只认 <ext>-YYYY-MM-DD.log pattern,不动其他 .log 文件", () => {
384
- process.env.XYZ_AGENT_EXT_LOG = "1";
384
+ process.env.TAIJI_AGENT_EXT_LOG = "1";
385
385
  const logDir = join(tmpAgentDir, "logs");
386
386
  mkdirSync(logDir, { recursive: true });
387
387
  const MS_PER_DAY = 24 * 60 * 60 * 1000;
@@ -510,8 +510,8 @@ describe("extension-logger", () => {
510
510
  expect(appendSpy).toHaveBeenCalledTimes(10);
511
511
  });
512
512
 
513
- it("fileLog 通道不受限(XYZ_AGENT_DEBUG=1 时 100 条全写文件)", () => {
514
- process.env.XYZ_AGENT_DEBUG = "1";
513
+ it("fileLog 通道不受限(TAIJI_AGENT_DEBUG=1 时 100 条全写文件)", () => {
514
+ process.env.TAIJI_AGENT_DEBUG = "1";
515
515
  const tmpAgentDir = mkdtempSync(join(tmpdir(), "pi-ext-ratelimit-"));
516
516
  process.env.PI_CODING_AGENT_DIR = tmpAgentDir;
517
517
  vi.setSystemTime(new Date("2026-08-01T12:34:56.789Z"));
package/src/index.ts CHANGED
@@ -11,8 +11,8 @@
11
11
  // 1. AI 实时 → tool result / block reason(pi 原生,本模块不涉及)
12
12
  // 2. 事后排查 → pi.appendEntry(custom entry 不进 LLM 上下文,不显 TUI)【实装】
13
13
  // 3. 开发者调试 → 文件日志,双开关分级(写 <agentDir>/logs/,均未注入默认 no-op)【实装】:
14
- // - XYZ_AGENT_DEBUG=1 → DEBUG 全量(现状语义,level 原样标注)
15
- // - XYZ_AGENT_EXT_LOG=1 → INFO 级落盘(xyz 托管环境由 runtime spawn 时经
14
+ // - TAIJI_AGENT_DEBUG=1 → DEBUG 全量(现状语义,level 原样标注)
15
+ // - TAIJI_AGENT_EXT_LOG=1 → INFO 级落盘(taiji 托管环境由 runtime spawn 时经
16
16
  // buildOutboundChildEnv extras 注入,设计 file-lock-unification-and-reaper-sink
17
17
  // §3.2-D4 / U3-3)+ 7 天保留期清理;debug() 调用此模式下重标 info 写入
18
18
  // - 两变量同时注入按更详细的生效(DEBUG 全量优先)
@@ -22,8 +22,7 @@
22
22
  // 直接调 ctx.ui.notify。
23
23
  //
24
24
  // fileLog 单日文件无 size cap——显式豁免,依据:写入方为每 session 短命 pi 进程
25
- // + 7 天保留期清理 + DEBUG 档系开发者主动排障;重审触发条件见
26
- // docs/design/ext-simplify-14-shared-libs.md §7。
25
+ // + 7 天保留期清理 + DEBUG 档系开发者主动排障。
27
26
 
28
27
  import { getAgentDir } from "@earendil-works/pi-coding-agent";
29
28
  import {
@@ -48,11 +47,11 @@ import { join } from "node:path";
48
47
  // - key = msg 原文(不包含 data 参数)。若调用方把动态 id 拼进 msg
49
48
  // (如 `session=${id}`),每条 msg 不同则限流不命中。根治靠调用方把
50
49
  // 动态值放 data 参数(D4 已声明)。
51
- // - fileLog 通道全量不限流(XYZ_AGENT_DEBUG=1 / XYZ_AGENT_EXT_LOG=1 时日志写文件)。
50
+ // - fileLog 通道全量不限流(TAIJI_AGENT_DEBUG=1 / TAIJI_AGENT_EXT_LOG=1 时日志写文件)。
52
51
  // - Map cap 512 超限时全量清空(简化策略,对齐 cap-1024 先例),
53
52
  // 等价于所有 key 窗口重置,防无界增长。
54
53
  //
55
- // 设计依据:docs/todo/extension-log-cleanup-design.md §3.4 D4
54
+ // 设计依据:extension-log-cleanup-design §3.4 D4
56
55
  // ============================================================
57
56
 
58
57
  /** 同 key 每窗口允许直写 appendEntry 的最大条数。 */
@@ -77,7 +76,7 @@ interface RateLimiterEntry {
77
76
  * key = `${extName}:${level}:${msg}`(msg 为原 msg,非 prefixed)。
78
77
  * 同进程所有 logger 实例共享(模块级 singleton)。
79
78
  *
80
- * ⚠️ 生命周期与进程一致——xyz-agent 每 session 一个独立 pi 进程
79
+ * ⚠️ 生命周期与进程一致——taiji 每 session 一个独立 pi 进程
81
80
  * (见 runtime process-manager.ts 的类注释),故不存在跨 session 残留问题。
82
81
  */
83
82
  const rateLimiterState = new Map<string, RateLimiterEntry>();
@@ -157,7 +156,7 @@ export interface PiLike {
157
156
  appendEntry?(customType: string, data?: unknown): void;
158
157
  }
159
158
 
160
- /** 日志级别。debug = 开发调试;info = XYZ_AGENT_EXT_LOG 模式下 debug() 的落盘标注;warn/error = 内部降级与失败(事后排查价值)。 */
159
+ /** 日志级别。debug = 开发调试;info = TAIJI_AGENT_EXT_LOG 模式下 debug() 的落盘标注;warn/error = 内部降级与失败(事后排查价值)。 */
161
160
  type LogLevel = "debug" | "info" | "warn" | "error";
162
161
 
163
162
  /**
@@ -166,8 +165,8 @@ type LogLevel = "debug" | "info" | "warn" | "error";
166
165
  */
167
166
  export interface ExtensionLogger {
168
167
  /**
169
- * 开发调试日志。默认 no-op;XYZ_AGENT_DEBUG=1 时写文件日志(原级标注);
170
- * XYZ_AGENT_EXT_LOG=1(无 DEBUG)时以 info 级落盘(托管环境 INFO 观测档)。
168
+ * 开发调试日志。默认 no-op;TAIJI_AGENT_DEBUG=1 时写文件日志(原级标注);
169
+ * TAIJI_AGENT_EXT_LOG=1(无 DEBUG)时以 info 级落盘(托管环境 INFO 观测档)。
171
170
  * 不进 appendEntry。
172
171
  */
173
172
  debug(msg: string, data?: unknown): void;
@@ -273,7 +272,7 @@ export function createLogger(extName: string, pi?: PiLike): ExtensionLogger {
273
272
  // appendEntry 失败(session 已 disposed 等)→ 降级文件日志(下方 fileLog 兜底),不 throw
274
273
  void appendErr;
275
274
  }
276
- // fileLog 全量不限流(XYZ_AGENT_DEBUG=1 排障时可见全部)
275
+ // fileLog 全量不限流(TAIJI_AGENT_DEBUG=1 排障时可见全部)
277
276
  fileLog(extName, "warn", prefixed, data);
278
277
  },
279
278
  error(msg: string, data?: unknown): void {
@@ -348,10 +347,10 @@ function prefixMsg(extName: string, msg: string): string {
348
347
  }
349
348
 
350
349
  // ============================================================
351
- // XYZ_AGENT_EXT_LOG 托管观测档 + 保留期清理
350
+ // TAIJI_AGENT_EXT_LOG 托管观测档 + 保留期清理
352
351
  // ============================================================
353
352
 
354
- /** 托管观测档(XYZ_AGENT_EXT_LOG=1)的日志保留天数,超期文件在首次落盘时清理。 */
353
+ /** 托管观测档(TAIJI_AGENT_EXT_LOG=1)的日志保留天数,超期文件在首次落盘时清理。 */
355
354
  const EXT_LOG_KEEP_DAYS = 7;
356
355
  // 一天的毫秒数(数字分隔符形式对齐 session-reader hash-provider 的时间常量惯例)
357
356
  const MS_PER_DAY = 86_400_000;
@@ -412,8 +411,8 @@ export function resetExtLogCleanupForTest(): void {
412
411
  * 写文件日志到 `<agentDir>/logs/<extName>-YYYY-MM-DD.log`。
413
412
  *
414
413
  * 双开关分级(设计 file-lock-unification-and-reaper-sink §3.2-D4):
415
- * - XYZ_AGENT_DEBUG=1 → DEBUG 全量,level 原样标注(现状语义不变);
416
- * - 仅 XYZ_AGENT_EXT_LOG=1 → INFO 级落盘:debug() 调用重标 info 写入,warn/error 照写;
414
+ * - TAIJI_AGENT_DEBUG=1 → DEBUG 全量,level 原样标注(现状语义不变);
415
+ * - 仅 TAIJI_AGENT_EXT_LOG=1 → INFO 级落盘:debug() 调用重标 info 写入,warn/error 照写;
417
416
  * - 均未注入 → no-op(零 fs 调用,裸 pi 独立用户零磁盘/行为影响)。
418
417
  * agentDir 通过 pi 的 SSOT `getAgentDir()` 推导(读
419
418
  * `PI_CODING_AGENT_DIR`/`${APP_NAME}_CODING_AGENT_DIR`,默认 `~/.pi/agent`),
@@ -425,8 +424,8 @@ export function resetExtLogCleanupForTest(): void {
425
424
  * 行可能交错(可接受——debug 日志不要求严格顺序)。
426
425
  */
427
426
  function fileLog(extName: string, level: LogLevel, msg: string, data?: unknown): void {
428
- const debugMode = process.env.XYZ_AGENT_DEBUG === "1";
429
- const extLogMode = !debugMode && process.env.XYZ_AGENT_EXT_LOG === "1";
427
+ const debugMode = process.env.TAIJI_AGENT_DEBUG === "1";
428
+ const extLogMode = !debugMode && process.env.TAIJI_AGENT_EXT_LOG === "1";
430
429
  if (!debugMode && !extLogMode) return;
431
430
  // 托管观测档:debug() 调用降档标注为 info(INFO 级观测,非 DEBUG 全量)
432
431
  const effectiveLevel: LogLevel = extLogMode && level === "debug" ? "info" : level;