@agimon-ai/doompi-log 0.0.1-alpha.13 → 0.0.1-alpha.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/README.md +12 -19
  2. package/dist/adapters/node/metricsSource.cjs +2 -0
  3. package/dist/adapters/node/metricsSource.cjs.map +1 -0
  4. package/dist/adapters/node/metricsSource.d.cts +14 -0
  5. package/dist/adapters/node/metricsSource.d.cts.map +1 -0
  6. package/dist/adapters/node/metricsSource.d.mts +14 -0
  7. package/dist/adapters/node/metricsSource.d.mts.map +1 -0
  8. package/dist/adapters/node/metricsSource.mjs.map +1 -0
  9. package/dist/adapters/pi/extension.cjs +1 -1
  10. package/dist/adapters/pi/extension.cjs.map +1 -1
  11. package/dist/adapters/pi/extension.d.cts +4 -3
  12. package/dist/adapters/pi/extension.d.cts.map +1 -1
  13. package/dist/adapters/pi/extension.d.mts +4 -3
  14. package/dist/adapters/pi/extension.d.mts.map +1 -1
  15. package/dist/adapters/pi/extension.mjs +1 -1
  16. package/dist/adapters/pi/extension.mjs.map +1 -1
  17. package/dist/extension.d.cts +1 -1
  18. package/dist/extension.d.mts +1 -1
  19. package/dist/extensions/pi.cjs +1 -2
  20. package/dist/extensions/pi.d.cts +2 -4
  21. package/dist/extensions/pi.d.mts +2 -5
  22. package/dist/extensions/pi.mjs +1 -2
  23. package/dist/index.cjs +1 -1
  24. package/dist/index.d.cts +2 -2
  25. package/dist/index.d.mts +2 -2
  26. package/dist/index.mjs +1 -1
  27. package/dist/metrics.d.cts +1 -1
  28. package/dist/metrics.d.mts +1 -1
  29. package/dist/metricsSource.cjs +1 -1
  30. package/dist/metricsSource.d.cts +3 -2
  31. package/dist/metricsSource.d.mts +3 -2
  32. package/dist/metricsSource.mjs +1 -1
  33. package/dist/tui/logMetricsOverlay.cjs +2 -0
  34. package/dist/tui/logMetricsOverlay.cjs.map +1 -0
  35. package/dist/tui/logMetricsOverlay.d.cts +71 -0
  36. package/dist/tui/logMetricsOverlay.d.cts.map +1 -0
  37. package/dist/tui/logMetricsOverlay.d.mts +71 -0
  38. package/dist/tui/logMetricsOverlay.d.mts.map +1 -0
  39. package/dist/tui/logMetricsOverlay.mjs +2 -0
  40. package/dist/tui/logMetricsOverlay.mjs.map +1 -0
  41. package/dist/tui/metricsOverlay.cjs +1 -2
  42. package/dist/tui/metricsOverlay.d.cts +2 -71
  43. package/dist/tui/metricsOverlay.d.mts +2 -71
  44. package/dist/tui/metricsOverlay.mjs +1 -2
  45. package/dist/types/metricsSource.d.cts +16 -0
  46. package/dist/types/metricsSource.d.cts.map +1 -0
  47. package/dist/types/metricsSource.d.mts +16 -0
  48. package/dist/types/metricsSource.d.mts.map +1 -0
  49. package/package.json +5 -5
  50. package/dist/extensions/pi.cjs.map +0 -1
  51. package/dist/extensions/pi.d.cts.map +0 -1
  52. package/dist/extensions/pi.d.mts.map +0 -1
  53. package/dist/extensions/pi.mjs.map +0 -1
  54. package/dist/services/metricsSource.cjs +0 -2
  55. package/dist/services/metricsSource.cjs.map +0 -1
  56. package/dist/services/metricsSource.d.cts +0 -25
  57. package/dist/services/metricsSource.d.cts.map +0 -1
  58. package/dist/services/metricsSource.d.mts +0 -25
  59. package/dist/services/metricsSource.d.mts.map +0 -1
  60. package/dist/services/metricsSource.mjs.map +0 -1
  61. package/dist/tui/metricsOverlay.cjs.map +0 -1
  62. package/dist/tui/metricsOverlay.d.cts.map +0 -1
  63. package/dist/tui/metricsOverlay.d.mts.map +0 -1
  64. package/dist/tui/metricsOverlay.mjs.map +0 -1
  65. /package/dist/{services → adapters/node}/metricsSource.mjs +0 -0
package/README.md CHANGED
@@ -1,12 +1,13 @@
1
1
  # @agimon-ai/doompi-log
2
2
 
3
- Pi log-sink telemetry extension with session-local metrics and a Log Metrics overlay.
3
+ **If the agent emits telemetry, you should be able to see it.**
4
4
 
5
- Session-local metrics and a log metrics overlay, backed by log-sink telemetry.
5
+ This package turns Doompi's LogSink records into session-local metrics and a terminal
6
+ overlay. Counters and spans stay useful to the person running the session instead of
7
+ disappearing into a database nobody opens.
6
8
 
7
- Part of [Doompi](https://www.npmjs.com/package/@agimon-ai/doompi), a coding agent that loads
8
- only the skills and tools you name. This package is composed by Doompi and is not usually
9
- installed on its own.
9
+ This is part of [Doompi](https://www.npmjs.com/package/@agimon-ai/doompi). Most users get
10
+ it with the distribution.
10
11
 
11
12
  ## Install
12
13
 
@@ -16,25 +17,17 @@ npm install @agimon-ai/doompi-log
16
17
 
17
18
  ## How it loads
18
19
 
19
- Doompi loads this unconditionally. It is core, not a layer, so it does not appear in
20
- `.doom/modes.yaml`: making it optional would only create broken configurations.
21
-
22
- Extension entry: `@agimon-ai/doompi-log/extensions/pi`
20
+ Doompi loads the log viewer as core. It is not a layer and does not appear in
21
+ `.doom/modes.yaml`. The bare package name follows its Pi manifest and loads the Pi adapter.
23
22
 
24
23
  ## Leader
25
24
 
26
- `SPC h l` opens log metrics, once the extension is loaded.
25
+ `SPC h l` opens the Log Metrics overlay for the current session.
27
26
 
28
- ## Entry points
27
+ ## Public API
29
28
 
30
- | Import |
31
- | ------------------------------------------ |
32
- | `@agimon-ai/doompi-log` |
33
- | `@agimon-ai/doompi-log/extension` |
34
- | `@agimon-ai/doompi-log/extensions/pi` |
35
- | `@agimon-ai/doompi-log/metrics` |
36
- | `@agimon-ai/doompi-log/metricsSource` |
37
- | `@agimon-ai/doompi-log/tui/metricsOverlay` |
29
+ The package exports the extension, metrics source, overlay, and Pi adapter through declared
30
+ subpaths. See `package.json` for the complete list.
38
31
 
39
32
  ## License
40
33
 
@@ -0,0 +1,2 @@
1
+ const e=require("../../_virtual/_rolldown/runtime.cjs");let t=require("node:child_process"),n=require("node:module"),r=require("node:path");r=e.__toESM(r,1);let i=require("@agimon-ai/log-sink-mcp");const a=`total-tokens`;function o(){let e=(0,n.createRequire)(require("url").pathToFileURL(__filename).href).resolve(`@agimon-ai/log-sink-mcp/package.json`);return r.default.join(r.default.dirname(e),`dist`,`cli.mjs`)}function s(e){return new URLSearchParams({groupBy:e.groupBy,period:e.period,sort:a,limit:String(e.limit),toolLimit:`1`}).toString()}async function c(e,t,n){let r=await n(`${e}/api/metrics?${s(t)}`,{signal:AbortSignal.timeout(5e3)});if(!r.ok)throw Error(`sink responded ${r.status}`);let i=await r.json();if(i.error||!Array.isArray(i.timeline))throw Error(i.error??`sink is an older version`);return i}function l(e){return new Promise((n,r)=>{(0,t.execFile)(process.execPath,[o(),`logs`,`metrics`,`--group-by`,e.groupBy,`--period`,e.period,`--sort`,a,`--limit`,String(e.limit),`--tool-limit`,`1`],{timeout:3e4,maxBuffer:33554432},(e,t,i)=>{if(e){r(Error(i.trim()||e.message));return}try{n(JSON.parse(t))}catch{r(Error(`metrics CLI returned unparsable output`))}})})}function u(e={}){let t=e.fetchImpl??globalThis.fetch,n=e.cliRunner??l,r,a,o=async()=>{if(a!==void 0)return a??void 0;try{a=(await(0,i.resolveLogSinkPort)({env:e.env,cwd:e.cwd,healthCheck:!0}))?.endpoint??null}catch{a=null}return a??void 0};return{lastTransport:()=>r,async query(e){let i=await o();if(i&&t)try{let n=await c(i,e,t);return r=`http`,n}catch{a=null}let s=await n(e);return r=`cli`,s}}}exports.createMetricsSource=u;
2
+ //# sourceMappingURL=metricsSource.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metricsSource.cjs","names":["createRequire","path","resolveLogSinkPort"],"sources":["../../../src/adapters/node/metricsSource.ts"],"sourcesContent":["/**\n * Historical metrics access for the `SPC h l` overlay.\n *\n * Two transports, in order: the running sink's HTTP API, then the installed\n * CLI as a subprocess. The sink daemon is long-lived and often lags the\n * installed package, so a daemon that rejects newer query parameters is treated\n * as unavailable rather than fatal. The reader exported by log-sink-mcp is\n * deliberately not used in-process: better-sqlite3 is synchronous and a\n * one-day window blocks for seconds, which would freeze the TUI.\n */\nimport { execFile } from 'node:child_process';\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\nimport type { LogMetricsReport } from '@agimon-ai/log-sink-mcp';\nimport { resolveLogSinkPort } from '@agimon-ai/log-sink-mcp';\nimport type { MetricsQueryParams, MetricsSource, MetricsTransport } from '../../types/metricsSource.ts';\n\nconst PACKAGE_NAME = '@agimon-ai/log-sink-mcp';\nconst HTTP_TIMEOUT_MS = 5000;\nconst CLI_TIMEOUT_MS = 30000;\n/** A day of dev telemetry is already ~140k records; keep the payload bounded. */\nconst MAX_CLI_BUFFER = 32 * 1024 * 1024;\nconst TOOL_LIMIT = '1';\n/** The panel ranks consumers, so ask for the biggest rather than the most recent. */\nconst TOKEN_SORT = 'total-tokens';\n\nexport interface MetricsSourceOptions {\n env?: NodeJS.ProcessEnv;\n cwd?: string;\n /** Overrides transport discovery in tests. */\n fetchImpl?: typeof fetch;\n cliRunner?: (params: MetricsQueryParams) => Promise<LogMetricsReport>;\n}\n\nfunction cliEntryPoint(): string {\n const require = createRequire(import.meta.url);\n // The published bin is CJS; the ESM build sits beside it and starts faster.\n const packageJson = require.resolve(`${PACKAGE_NAME}/package.json`);\n return path.join(path.dirname(packageJson), 'dist', 'cli.mjs');\n}\n\nfunction searchParams(params: MetricsQueryParams): string {\n return new URLSearchParams({\n groupBy: params.groupBy,\n period: params.period,\n sort: TOKEN_SORT,\n limit: String(params.limit),\n toolLimit: TOOL_LIMIT,\n }).toString();\n}\n\nasync function queryHttp(\n endpoint: string,\n params: MetricsQueryParams,\n fetchImpl: typeof fetch,\n): Promise<LogMetricsReport> {\n const response = await fetchImpl(`${endpoint}/api/metrics?${searchParams(params)}`, {\n signal: AbortSignal.timeout(HTTP_TIMEOUT_MS),\n });\n if (!response.ok) throw new Error(`sink responded ${response.status}`);\n\n const body = (await response.json()) as LogMetricsReport & { error?: string };\n // An older daemon rejects unknown group-by values and omits the timeline.\n if (body.error || !Array.isArray(body.timeline)) throw new Error(body.error ?? 'sink is an older version');\n return body;\n}\n\nfunction runCli(params: MetricsQueryParams): Promise<LogMetricsReport> {\n return new Promise((resolve, reject) => {\n execFile(\n process.execPath,\n [\n cliEntryPoint(),\n 'logs',\n 'metrics',\n '--group-by',\n params.groupBy,\n '--period',\n params.period,\n '--sort',\n TOKEN_SORT,\n '--limit',\n String(params.limit),\n '--tool-limit',\n TOOL_LIMIT,\n ],\n { timeout: CLI_TIMEOUT_MS, maxBuffer: MAX_CLI_BUFFER },\n (error, stdout, stderr) => {\n if (error) {\n reject(new Error(stderr.trim() || error.message));\n return;\n }\n try {\n resolve(JSON.parse(stdout) as LogMetricsReport);\n } catch {\n reject(new Error('metrics CLI returned unparsable output'));\n }\n },\n );\n });\n}\n\nexport function createMetricsSource(options: MetricsSourceOptions = {}): MetricsSource {\n const fetchImpl = options.fetchImpl ?? globalThis.fetch;\n const cliRunner = options.cliRunner ?? runCli;\n let transport: MetricsTransport | undefined;\n let endpoint: string | undefined | null;\n\n const resolveEndpoint = async (): Promise<string | undefined> => {\n if (endpoint !== undefined) return endpoint ?? undefined;\n try {\n const resolved = await resolveLogSinkPort({ env: options.env, cwd: options.cwd, healthCheck: true });\n endpoint = resolved?.endpoint ?? null;\n } catch {\n endpoint = null;\n }\n return endpoint ?? undefined;\n };\n\n return {\n lastTransport: () => transport,\n async query(params) {\n const httpEndpoint = await resolveEndpoint();\n if (httpEndpoint && fetchImpl) {\n try {\n const report = await queryHttp(httpEndpoint, params, fetchImpl);\n transport = 'http';\n return report;\n } catch {\n // A stale or unhealthy daemon must not hide data the CLI can still read.\n endpoint = null;\n }\n }\n\n const report = await cliRunner(params);\n transport = 'cli';\n return report;\n },\n };\n}\n"],"mappings":"sMAiBA,MAOM,EAAa,eAUnB,SAAS,GAAwB,CAG/B,IAAM,GAAA,EAFUA,EAAAA,cAAAA,CAAAA,QAAAA,KAAAA,CAAAA,CAAAA,cAAAA,UAAAA,CAAAA,CAAAA,IAEU,CAAC,CAAC,QAAQ,sCAA8B,EAClE,OAAOC,EAAAA,QAAK,KAAKA,EAAAA,QAAK,QAAQ,CAAW,EAAG,OAAQ,SAAS,CAC/D,CAEA,SAAS,EAAa,EAAoC,CACxD,OAAO,IAAI,gBAAgB,CACzB,QAAS,EAAO,QAChB,OAAQ,EAAO,OACf,KAAM,EACN,MAAO,OAAO,EAAO,KAAK,EAC1B,UAAW,GACb,CAAC,CAAC,CAAC,SAAS,CACd,CAEA,eAAe,EACb,EACA,EACA,EAC2B,CAC3B,IAAM,EAAW,MAAM,EAAU,GAAG,EAAS,eAAe,EAAa,CAAM,IAAK,CAClF,OAAQ,YAAY,QAAQ,GAAe,CAC7C,CAAC,EACD,GAAI,CAAC,EAAS,GAAI,MAAU,MAAM,kBAAkB,EAAS,QAAQ,EAErE,IAAM,EAAQ,MAAM,EAAS,KAAK,EAElC,GAAI,EAAK,OAAS,CAAC,MAAM,QAAQ,EAAK,QAAQ,EAAG,MAAU,MAAM,EAAK,OAAS,0BAA0B,EACzG,OAAO,CACT,CAEA,SAAS,EAAO,EAAuD,CACrE,OAAO,IAAI,SAAS,EAAS,IAAW,EACtC,EAAA,EAAA,SAAA,CACE,QAAQ,SACR,CACE,EAAc,EACd,OACA,UACA,aACA,EAAO,QACP,WACA,EAAO,OACP,SACA,EACA,UACA,OAAO,EAAO,KAAK,EACnB,eACA,GACF,EACA,CAAE,QAAS,IAAgB,UAAW,QAAe,GACpD,EAAO,EAAQ,IAAW,CACzB,GAAI,EAAO,CACT,EAAW,MAAM,EAAO,KAAK,GAAK,EAAM,OAAO,CAAC,EAChD,MACF,CACA,GAAI,CACF,EAAQ,KAAK,MAAM,CAAM,CAAqB,CAChD,MAAQ,CACN,EAAW,MAAM,wCAAwC,CAAC,CAC5D,CACF,CACF,CACF,CAAC,CACH,CAEA,SAAgB,EAAoB,EAAgC,CAAC,EAAkB,CACrF,IAAM,EAAY,EAAQ,WAAa,WAAW,MAC5C,EAAY,EAAQ,WAAa,EACnC,EACA,EAEE,EAAkB,SAAyC,CAC/D,GAAI,IAAa,IAAA,GAAW,OAAO,GAAY,IAAA,GAC/C,GAAI,CAEF,GAAW,MAAA,EADYC,EAAAA,mBAAAA,CAAmB,CAAE,IAAK,EAAQ,IAAK,IAAK,EAAQ,IAAK,YAAa,EAAK,CAAC,EAAA,EAC9E,UAAY,IACnC,MAAQ,CACN,EAAW,IACb,CACA,OAAO,GAAY,IAAA,EACrB,EAEA,MAAO,CACL,kBAAqB,EACrB,MAAM,MAAM,EAAQ,CAClB,IAAM,EAAe,MAAM,EAAgB,EAC3C,GAAI,GAAgB,EAClB,GAAI,CACF,IAAM,EAAS,MAAM,EAAU,EAAc,EAAQ,CAAS,EAE9D,MADA,GAAY,OACL,CACT,MAAQ,CAEN,EAAW,IACb,CAGF,IAAM,EAAS,MAAM,EAAU,CAAM,EAErC,MADA,GAAY,MACL,CACT,CACF,CACF"}
@@ -0,0 +1,14 @@
1
+ import { MetricsQueryParams, MetricsSource } from "../../types/metricsSource.cjs";
2
+ import { LogMetricsReport } from "@agimon-ai/log-sink-mcp";
3
+ //#region src/adapters/node/metricsSource.d.ts
4
+ interface MetricsSourceOptions {
5
+ env?: NodeJS.ProcessEnv;
6
+ cwd?: string;
7
+ /** Overrides transport discovery in tests. */
8
+ fetchImpl?: typeof fetch;
9
+ cliRunner?: (params: MetricsQueryParams) => Promise<LogMetricsReport>;
10
+ }
11
+ declare function createMetricsSource(options?: MetricsSourceOptions): MetricsSource;
12
+ //#endregion
13
+ export { MetricsSourceOptions, createMetricsSource };
14
+ //# sourceMappingURL=metricsSource.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metricsSource.d.cts","names":[],"sources":["../../../src/adapters/node/metricsSource.ts"],"mappings":";;;UA0BiB;EACf,MAAM,OAAO;EACb;;EAEA,mBAAmB;EACnB,aAAa,QAAQ,uBAAuB,QAAQ;;iBAuEtC,oBAAoB,UAAS,uBAA4B"}
@@ -0,0 +1,14 @@
1
+ import { MetricsQueryParams, MetricsSource } from "../../types/metricsSource.mjs";
2
+ import { LogMetricsReport } from "@agimon-ai/log-sink-mcp";
3
+ //#region src/adapters/node/metricsSource.d.ts
4
+ interface MetricsSourceOptions {
5
+ env?: NodeJS.ProcessEnv;
6
+ cwd?: string;
7
+ /** Overrides transport discovery in tests. */
8
+ fetchImpl?: typeof fetch;
9
+ cliRunner?: (params: MetricsQueryParams) => Promise<LogMetricsReport>;
10
+ }
11
+ declare function createMetricsSource(options?: MetricsSourceOptions): MetricsSource;
12
+ //#endregion
13
+ export { MetricsSourceOptions, createMetricsSource };
14
+ //# sourceMappingURL=metricsSource.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metricsSource.d.mts","names":[],"sources":["../../../src/adapters/node/metricsSource.ts"],"mappings":";;;UA0BiB;EACf,MAAM,OAAO;EACb;;EAEA,mBAAmB;EACnB,aAAa,QAAQ,uBAAuB,QAAQ;;iBAuEtC,oBAAoB,UAAS,uBAA4B"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metricsSource.mjs","names":[],"sources":["../../../src/adapters/node/metricsSource.ts"],"sourcesContent":["/**\n * Historical metrics access for the `SPC h l` overlay.\n *\n * Two transports, in order: the running sink's HTTP API, then the installed\n * CLI as a subprocess. The sink daemon is long-lived and often lags the\n * installed package, so a daemon that rejects newer query parameters is treated\n * as unavailable rather than fatal. The reader exported by log-sink-mcp is\n * deliberately not used in-process: better-sqlite3 is synchronous and a\n * one-day window blocks for seconds, which would freeze the TUI.\n */\nimport { execFile } from 'node:child_process';\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\nimport type { LogMetricsReport } from '@agimon-ai/log-sink-mcp';\nimport { resolveLogSinkPort } from '@agimon-ai/log-sink-mcp';\nimport type { MetricsQueryParams, MetricsSource, MetricsTransport } from '../../types/metricsSource.ts';\n\nconst PACKAGE_NAME = '@agimon-ai/log-sink-mcp';\nconst HTTP_TIMEOUT_MS = 5000;\nconst CLI_TIMEOUT_MS = 30000;\n/** A day of dev telemetry is already ~140k records; keep the payload bounded. */\nconst MAX_CLI_BUFFER = 32 * 1024 * 1024;\nconst TOOL_LIMIT = '1';\n/** The panel ranks consumers, so ask for the biggest rather than the most recent. */\nconst TOKEN_SORT = 'total-tokens';\n\nexport interface MetricsSourceOptions {\n env?: NodeJS.ProcessEnv;\n cwd?: string;\n /** Overrides transport discovery in tests. */\n fetchImpl?: typeof fetch;\n cliRunner?: (params: MetricsQueryParams) => Promise<LogMetricsReport>;\n}\n\nfunction cliEntryPoint(): string {\n const require = createRequire(import.meta.url);\n // The published bin is CJS; the ESM build sits beside it and starts faster.\n const packageJson = require.resolve(`${PACKAGE_NAME}/package.json`);\n return path.join(path.dirname(packageJson), 'dist', 'cli.mjs');\n}\n\nfunction searchParams(params: MetricsQueryParams): string {\n return new URLSearchParams({\n groupBy: params.groupBy,\n period: params.period,\n sort: TOKEN_SORT,\n limit: String(params.limit),\n toolLimit: TOOL_LIMIT,\n }).toString();\n}\n\nasync function queryHttp(\n endpoint: string,\n params: MetricsQueryParams,\n fetchImpl: typeof fetch,\n): Promise<LogMetricsReport> {\n const response = await fetchImpl(`${endpoint}/api/metrics?${searchParams(params)}`, {\n signal: AbortSignal.timeout(HTTP_TIMEOUT_MS),\n });\n if (!response.ok) throw new Error(`sink responded ${response.status}`);\n\n const body = (await response.json()) as LogMetricsReport & { error?: string };\n // An older daemon rejects unknown group-by values and omits the timeline.\n if (body.error || !Array.isArray(body.timeline)) throw new Error(body.error ?? 'sink is an older version');\n return body;\n}\n\nfunction runCli(params: MetricsQueryParams): Promise<LogMetricsReport> {\n return new Promise((resolve, reject) => {\n execFile(\n process.execPath,\n [\n cliEntryPoint(),\n 'logs',\n 'metrics',\n '--group-by',\n params.groupBy,\n '--period',\n params.period,\n '--sort',\n TOKEN_SORT,\n '--limit',\n String(params.limit),\n '--tool-limit',\n TOOL_LIMIT,\n ],\n { timeout: CLI_TIMEOUT_MS, maxBuffer: MAX_CLI_BUFFER },\n (error, stdout, stderr) => {\n if (error) {\n reject(new Error(stderr.trim() || error.message));\n return;\n }\n try {\n resolve(JSON.parse(stdout) as LogMetricsReport);\n } catch {\n reject(new Error('metrics CLI returned unparsable output'));\n }\n },\n );\n });\n}\n\nexport function createMetricsSource(options: MetricsSourceOptions = {}): MetricsSource {\n const fetchImpl = options.fetchImpl ?? globalThis.fetch;\n const cliRunner = options.cliRunner ?? runCli;\n let transport: MetricsTransport | undefined;\n let endpoint: string | undefined | null;\n\n const resolveEndpoint = async (): Promise<string | undefined> => {\n if (endpoint !== undefined) return endpoint ?? undefined;\n try {\n const resolved = await resolveLogSinkPort({ env: options.env, cwd: options.cwd, healthCheck: true });\n endpoint = resolved?.endpoint ?? null;\n } catch {\n endpoint = null;\n }\n return endpoint ?? undefined;\n };\n\n return {\n lastTransport: () => transport,\n async query(params) {\n const httpEndpoint = await resolveEndpoint();\n if (httpEndpoint && fetchImpl) {\n try {\n const report = await queryHttp(httpEndpoint, params, fetchImpl);\n transport = 'http';\n return report;\n } catch {\n // A stale or unhealthy daemon must not hide data the CLI can still read.\n endpoint = null;\n }\n }\n\n const report = await cliRunner(params);\n transport = 'cli';\n return report;\n },\n };\n}\n"],"mappings":"gLAiBA,MAOM,EAAa,eAUnB,SAAS,GAAwB,CAG/B,IAAM,EAFU,EAAc,YAAY,GAEhB,CAAC,CAAC,QAAQ,sCAA8B,EAClE,OAAO,EAAK,KAAK,EAAK,QAAQ,CAAW,EAAG,OAAQ,SAAS,CAC/D,CAEA,SAAS,EAAa,EAAoC,CACxD,OAAO,IAAI,gBAAgB,CACzB,QAAS,EAAO,QAChB,OAAQ,EAAO,OACf,KAAM,EACN,MAAO,OAAO,EAAO,KAAK,EAC1B,UAAW,GACb,CAAC,CAAC,CAAC,SAAS,CACd,CAEA,eAAe,EACb,EACA,EACA,EAC2B,CAC3B,IAAM,EAAW,MAAM,EAAU,GAAG,EAAS,eAAe,EAAa,CAAM,IAAK,CAClF,OAAQ,YAAY,QAAQ,GAAe,CAC7C,CAAC,EACD,GAAI,CAAC,EAAS,GAAI,MAAU,MAAM,kBAAkB,EAAS,QAAQ,EAErE,IAAM,EAAQ,MAAM,EAAS,KAAK,EAElC,GAAI,EAAK,OAAS,CAAC,MAAM,QAAQ,EAAK,QAAQ,EAAG,MAAU,MAAM,EAAK,OAAS,0BAA0B,EACzG,OAAO,CACT,CAEA,SAAS,EAAO,EAAuD,CACrE,OAAO,IAAI,SAAS,EAAS,IAAW,CACtC,EACE,QAAQ,SACR,CACE,EAAc,EACd,OACA,UACA,aACA,EAAO,QACP,WACA,EAAO,OACP,SACA,EACA,UACA,OAAO,EAAO,KAAK,EACnB,eACA,GACF,EACA,CAAE,QAAS,IAAgB,UAAW,QAAe,GACpD,EAAO,EAAQ,IAAW,CACzB,GAAI,EAAO,CACT,EAAW,MAAM,EAAO,KAAK,GAAK,EAAM,OAAO,CAAC,EAChD,MACF,CACA,GAAI,CACF,EAAQ,KAAK,MAAM,CAAM,CAAqB,CAChD,MAAQ,CACN,EAAW,MAAM,wCAAwC,CAAC,CAC5D,CACF,CACF,CACF,CAAC,CACH,CAEA,SAAgB,EAAoB,EAAgC,CAAC,EAAkB,CACrF,IAAM,EAAY,EAAQ,WAAa,WAAW,MAC5C,EAAY,EAAQ,WAAa,EACnC,EACA,EAEE,EAAkB,SAAyC,CAC/D,GAAI,IAAa,IAAA,GAAW,OAAO,GAAY,IAAA,GAC/C,GAAI,CAEF,GAAW,MADY,EAAmB,CAAE,IAAK,EAAQ,IAAK,IAAK,EAAQ,IAAK,YAAa,EAAK,CAAC,EAAA,EAC9E,UAAY,IACnC,MAAQ,CACN,EAAW,IACb,CACA,OAAO,GAAY,IAAA,EACrB,EAEA,MAAO,CACL,kBAAqB,EACrB,MAAM,MAAM,EAAQ,CAClB,IAAM,EAAe,MAAM,EAAgB,EAC3C,GAAI,GAAgB,EAClB,GAAI,CACF,IAAM,EAAS,MAAM,EAAU,EAAc,EAAQ,CAAS,EAE9D,MADA,GAAY,OACL,CACT,MAAQ,CAEN,EAAW,IACb,CAGF,IAAM,EAAS,MAAM,EAAU,CAAM,EAErC,MADA,GAAY,MACL,CACT,CACF,CACF"}
@@ -1,2 +1,2 @@
1
- const e=require("../../services/metrics.cjs"),t=require("../../services/metricsSource.cjs"),n=require("../../tui/metricsOverlay.cjs");let r=require("@agimon-ai/doompi-extension-contracts/leader"),i=require("@agimon-ai/doompi-telemetry");const a=`log-metrics`,o=new Set([`error`,`aborted`]);function s(e){return e===`1`||e?.toLowerCase()===`true`||e?.toLowerCase()===`yes`}function c(e){let t={"pi.mode":e.mode,"pi.session.id":e.sessionManager.getSessionId()};return e.thinkingLevel&&(t[`pi.thinking_level`]=e.thinkingLevel),e.model&&(t[`gen_ai.provider.name`]=e.model.provider,t[`gen_ai.request.model`]=e.model.id),t}function l(e){if(e.role!==`assistant`)return;let t={"gen_ai.response.model":e.responseModel??e.model,"gen_ai.response.finish_reasons":e.stopReason,"gen_ai.usage.input_tokens":e.usage.input,"gen_ai.usage.output_tokens":e.usage.output,"gen_ai.usage.cache_read_tokens":e.usage.cacheRead,"gen_ai.usage.cache_write_tokens":e.usage.cacheWrite,"gen_ai.usage.total_tokens":e.usage.totalTokens,"gen_ai.usage.cost":e.usage.cost.total};return e.usage.reasoning!==void 0&&(t[`gen_ai.usage.reasoning_tokens`]=e.usage.reasoning),t}function u(e){if(e.role!==`assistant`)return{"error.type":`AgentError`,outcome:`error`};let t=e.stopReason===`aborted`;return{"error.type":`ProviderError`,"error.code":e.stopReason,outcome:t?`aborted`:`error`}}function d(e){return{service:e.serviceName,backend:e.backend,endpoint:e.endpoint??`none`,endpointSource:e.endpointSource,traces:e.traces,redaction:!0,fileFallback:e.fileFallback}}function f(e={}){return function(t){let n=e.env??process.env,r=e.metrics,a=new Map,f,p,m=async(e,t,n)=>{p&&(e===`debug`?await p.recordDebug(t,n):e===`warn`?await p.recordWarning(t,void 0,n):e===`error`?await p.recordError(t,void 0,n):await p.recordEvent(t,n))},h=t=>(p??=(0,i.createDoomTelemetry)({serviceName:e.serviceName??`pi`,packageName:`@agimon-ai/doompi-log`,cwd:t.cwd,env:n,allowFileFallback:e.allowFileFallback,telemetryFactory:e.telemetryFactory,warn:e.onDiagnostic,enableLogs:!0,enableTraces:n.AGENT_OTEL_TRACES===void 0||s(n.AGENT_OTEL_TRACES),onRecord:e=>r?.record(e.event,e.attributes),onStatus:t=>e.onSinkStatus?.(d(t))}),e.onSinkStatus?.(d(p.status())),p);t.on(`session_start`,async(e,t)=>{h(t),await m(`info`,`pi.session.started`,{...c(t),"pi.session.reason":e.reason,"pi.session.previous":e.previousSessionFile!==void 0})}),t.on(`before_agent_start`,async(e,t)=>{h(t),await m(`info`,`pi.user_prompt`,{...c(t),"pi.user_message.length":e.prompt.length,"pi.user_message.image_count":e.images?.length??0})}),t.on(`agent_start`,async(e,t)=>{f=Date.now(),h(t),await m(`info`,`pi.agent.started`,c(t))}),t.on(`turn_start`,async(e,t)=>{h(t),await m(`debug`,`pi.turn.started`,{...c(t),"pi.turn.index":e.turnIndex})}),t.on(`turn_end`,async(e,t)=>{h(t);let n=l(e.message);if(await m(`info`,`pi.turn.finished`,{...c(t),"pi.turn.index":e.turnIndex,"pi.tool_result.count":e.toolResults.length,...n}),e.message.role===`assistant`&&o.has(e.message.stopReason)&&await m(e.message.stopReason===`aborted`?`warn`:`error`,`pi.turn.failed`,{...c(t),"pi.turn.index":e.turnIndex,...u(e.message),...n}),n)for(let r of e.toolResults)await m(`debug`,`pi.tool_token_sample`,{...c(t),...n,"tool.name":r.toolName,token_attribution:`toolCallTurn`})}),t.on(`tool_execution_start`,async(e,t)=>{a.set(e.toolCallId,Date.now()),h(t),await m(`debug`,`pi.tool_call`,{...c(t),"tool.name":e.toolName,"tool.call.id":e.toolCallId})}),t.on(`tool_execution_end`,async(e,t)=>{let n=a.get(e.toolCallId);a.delete(e.toolCallId),h(t),await m(`info`,`pi.tool_result`,{...c(t),success:!e.isError,"tool.name":e.toolName,"tool.call.id":e.toolCallId,"tool.result.error":e.isError,...n===void 0?{}:{"tool.duration_ms":Date.now()-n}})}),t.on(`after_provider_response`,async(e,t)=>{h(t);let n={...c(t),"http.response.status_code":e.status};e.status>=400?await m(`error`,`pi.api_error`,n):await m(`debug`,`pi.api_response`,n)}),t.on(`model_select`,async(e,t)=>{h(t),await m(`info`,`pi.model.selected`,{...c(t),"pi.model.source":e.source,"gen_ai.provider.name":e.model.provider,"gen_ai.request.model":e.model.id})}),t.on(`agent_end`,async(e,t)=>{h(t),await m(`info`,`pi.agent.finished`,{...c(t),"pi.message.count":e.messages.length,...f===void 0?{}:{"pi.agent.duration_ms":Date.now()-f}}),f=void 0,await p?.flush()}),t.on(`agent_settled`,async(e,t)=>{h(t),await m(`debug`,`pi.agent.settled`,c(t))}),t.on(`session_shutdown`,async(e,t)=>{h(t),await m(`info`,`pi.session.finished`,{...c(t),"pi.session.reason":e.reason}),await p?.shutdown()})}}function p(e,t={}){return(0,r.registerDoomLeaderContribution)(e,{source:t.source??`@agimon-ai/doompi-log`,bindings:[{id:`log.metrics`,path:[{key:`h`,label:`help`,order:70},{key:`l`,label:`logs`,detail:`telemetry`}],command:{name:a}}]})}async function m(e,t,r){await e.ui.custom((e,i,a,o)=>new n.LogMetricsOverlayComponent(e,i,t,o,r),{overlay:!0,overlayOptions:{anchor:`top-left`,width:`100%`,maxHeight:`100%`,margin:0}})}function h(n={}){return function(r){let i=n.env??process.env,o=new e.LogMetricsAggregator,c=n.metricsSource??t.createMetricsSource({env:i}),l,u;f({...n,metrics:o,onDiagnostic:e=>{u=e,n.onDiagnostic?n.onDiagnostic(e):i.AGENT_OTEL_DIAGNOSTICS===`stderr`&&process.emitWarning(e)},onSinkStatus:e=>{l=e,n.onSinkStatus?.(e)}})(r),p(r,{source:n.leaderSource}),r.registerCommand(a,{description:`Show session-local log metrics`,handler:async(e,t)=>{await m(t,()=>({disabled:s(i.AGENT_TELEMETRY_DISABLED)||s(i.OTEL_SDK_DISABLED),snapshot:o.snapshot(),sink:l,transport:c.lastTransport(),lastDiagnostic:u}),c.query)}})}}exports.createDoomLogExtension=h,exports.createPiTelemetryExtension=f,exports.openLogMetricsOverlay=m,exports.registerLogMetricsLeaderBinding=p;
1
+ const e=require("../../services/metrics.cjs"),t=require("../../tui/logMetricsOverlay.cjs"),n=require("../node/metricsSource.cjs");let r=require("@agimon-ai/doompi-extension-contracts/leader"),i=require("@agimon-ai/doompi-telemetry");const a=`log-metrics`,o=new Set([`error`,`aborted`]);function s(e){return e===`1`||e?.toLowerCase()===`true`||e?.toLowerCase()===`yes`}function c(e){let t={"pi.mode":e.mode,"pi.session.id":e.sessionManager.getSessionId()};return e.thinkingLevel&&(t[`pi.thinking_level`]=e.thinkingLevel),e.model&&(t[`gen_ai.provider.name`]=e.model.provider,t[`gen_ai.request.model`]=e.model.id),t}function l(e){if(e.role!==`assistant`)return;let t={"gen_ai.response.model":e.responseModel??e.model,"gen_ai.response.finish_reasons":e.stopReason,"gen_ai.usage.input_tokens":e.usage.input,"gen_ai.usage.output_tokens":e.usage.output,"gen_ai.usage.cache_read_tokens":e.usage.cacheRead,"gen_ai.usage.cache_write_tokens":e.usage.cacheWrite,"gen_ai.usage.total_tokens":e.usage.totalTokens,"gen_ai.usage.cost":e.usage.cost.total};return e.usage.reasoning!==void 0&&(t[`gen_ai.usage.reasoning_tokens`]=e.usage.reasoning),t}function u(e){if(e.role!==`assistant`)return{"error.type":`AgentError`,outcome:`error`};let t=e.stopReason===`aborted`;return{"error.type":`ProviderError`,"error.code":e.stopReason,outcome:t?`aborted`:`error`}}function d(e){return{service:e.serviceName,backend:e.backend,endpoint:e.endpoint??`none`,endpointSource:e.endpointSource,traces:e.traces,redaction:!0,fileFallback:e.fileFallback}}function f(e={}){return function(t){let n=e.env??process.env,r=e.metrics,a=new Map,f,p,m=async(e,t,n)=>{p&&(e===`debug`?await p.recordDebug(t,n):e===`warn`?await p.recordWarning(t,void 0,n):e===`error`?await p.recordError(t,void 0,n):await p.recordEvent(t,n))},h=t=>(p??=(0,i.createDoomTelemetry)({serviceName:e.serviceName??`pi`,packageName:`@agimon-ai/doompi-log`,cwd:t.cwd,env:n,allowFileFallback:e.allowFileFallback,telemetryFactory:e.telemetryFactory,warn:e.onDiagnostic,enableLogs:!0,enableTraces:n.AGENT_OTEL_TRACES===void 0||s(n.AGENT_OTEL_TRACES),onRecord:e=>r?.record(e.event,e.attributes),onStatus:t=>e.onSinkStatus?.(d(t))}),e.onSinkStatus?.(d(p.status())),p);t.on(`session_start`,async(e,t)=>{h(t),await m(`info`,`pi.session.started`,{...c(t),"pi.session.reason":e.reason,"pi.session.previous":e.previousSessionFile!==void 0})}),t.on(`before_agent_start`,async(e,t)=>{h(t),await m(`info`,`pi.user_prompt`,{...c(t),"pi.user_message.length":e.prompt.length,"pi.user_message.image_count":e.images?.length??0})}),t.on(`agent_start`,async(e,t)=>{f=Date.now(),h(t),await m(`info`,`pi.agent.started`,c(t))}),t.on(`turn_start`,async(e,t)=>{h(t),await m(`debug`,`pi.turn.started`,{...c(t),"pi.turn.index":e.turnIndex})}),t.on(`turn_end`,async(e,t)=>{h(t);let n=l(e.message);if(await m(`info`,`pi.turn.finished`,{...c(t),"pi.turn.index":e.turnIndex,"pi.tool_result.count":e.toolResults.length,...n}),e.message.role===`assistant`&&o.has(e.message.stopReason)&&await m(e.message.stopReason===`aborted`?`warn`:`error`,`pi.turn.failed`,{...c(t),"pi.turn.index":e.turnIndex,...u(e.message),...n}),n)for(let r of e.toolResults)await m(`debug`,`pi.tool_token_sample`,{...c(t),...n,"tool.name":r.toolName,token_attribution:`toolCallTurn`})}),t.on(`tool_execution_start`,async(e,t)=>{a.set(e.toolCallId,Date.now()),h(t),await m(`debug`,`pi.tool_call`,{...c(t),"tool.name":e.toolName,"tool.call.id":e.toolCallId})}),t.on(`tool_execution_end`,async(e,t)=>{let n=a.get(e.toolCallId);a.delete(e.toolCallId),h(t),await m(`info`,`pi.tool_result`,{...c(t),success:!e.isError,"tool.name":e.toolName,"tool.call.id":e.toolCallId,"tool.result.error":e.isError,...n===void 0?{}:{"tool.duration_ms":Date.now()-n}})}),t.on(`after_provider_response`,async(e,t)=>{h(t);let n={...c(t),"http.response.status_code":e.status};e.status>=400?await m(`error`,`pi.api_error`,n):await m(`debug`,`pi.api_response`,n)}),t.on(`model_select`,async(e,t)=>{h(t),await m(`info`,`pi.model.selected`,{...c(t),"pi.model.source":e.source,"gen_ai.provider.name":e.model.provider,"gen_ai.request.model":e.model.id})}),t.on(`agent_end`,async(e,t)=>{h(t),await m(`info`,`pi.agent.finished`,{...c(t),"pi.message.count":e.messages.length,...f===void 0?{}:{"pi.agent.duration_ms":Date.now()-f}}),f=void 0,await p?.flush()}),t.on(`agent_settled`,async(e,t)=>{h(t),await m(`debug`,`pi.agent.settled`,c(t))}),t.on(`session_shutdown`,async(e,t)=>{h(t),await m(`info`,`pi.session.finished`,{...c(t),"pi.session.reason":e.reason}),await p?.shutdown()})}}function p(e,t={}){return(0,r.registerDoomLeaderContribution)(e,{source:t.source??`@agimon-ai/doompi-log`,bindings:[{id:`log.metrics`,path:[{key:`h`,label:`help`,order:70},{key:`l`,label:`logs`,detail:`telemetry`}],command:{name:a}}]})}async function m(e,n,r){await e.ui.custom((e,i,a,o)=>new t.LogMetricsOverlayComponent(e,i,n,o,r),{overlay:!0,overlayOptions:{anchor:`top-left`,width:`100%`,maxHeight:`100%`,margin:0}})}function h(t={}){return function(r){let i=t.env??process.env,o=new e.LogMetricsAggregator,c=t.metricsSource??n.createMetricsSource({env:i}),l,u;f({...t,metrics:o,onDiagnostic:e=>{u=e,t.onDiagnostic?t.onDiagnostic(e):i.AGENT_OTEL_DIAGNOSTICS===`stderr`&&process.emitWarning(e)},onSinkStatus:e=>{l=e,t.onSinkStatus?.(e)}})(r),p(r,{source:t.leaderSource}),r.registerCommand(a,{description:`Show session-local log metrics`,handler:async(e,t)=>{await m(t,()=>({disabled:s(i.AGENT_TELEMETRY_DISABLED)||s(i.OTEL_SDK_DISABLED),snapshot:o.snapshot(),sink:l,transport:c.lastTransport(),lastDiagnostic:u}),c.query)}})}}const g=h();exports.createDoomLogExtension=h,exports.createPiTelemetryExtension=f,exports.doomLogExtension=g,exports.openLogMetricsOverlay=m,exports.registerLogMetricsLeaderBinding=p;
2
2
  //# sourceMappingURL=extension.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension.cjs","names":["createDoomTelemetry","registerDoomLeaderContribution","LogMetricsOverlayComponent","LogMetricsAggregator","createMetricsSource"],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["/**\n * Pi telemetry wiring for the Doom harness.\n *\n * This extension deliberately emits metadata-only records. Prompt, message,\n * tool payload, file path, diagnostic text, exception, and stack data never\n * cross the shared telemetry boundary.\n */\n\nimport { registerDoomLeaderContribution } from '@agimon-ai/doompi-extension-contracts/leader';\nimport { createDoomTelemetry, type DoomTelemetry, type DoomTelemetryOptions } from '@agimon-ai/doompi-telemetry';\nimport type { ExtensionAPI, ExtensionContext, TurnEndEvent } from '@earendil-works/pi-coding-agent';\nimport { LogMetricsAggregator, type LogMetricsRecorder } from '../../services/metrics.ts';\nimport { createMetricsSource, type MetricsQuery, type MetricsSource } from '../../services/metricsSource.ts';\nimport { LogMetricsOverlayComponent, type LogMetricsView, type SinkStatus } from '../../tui/metricsOverlay.ts';\n\nconst SERVICE_NAME = 'pi';\nconst PACKAGE_NAME = '@agimon-ai/doompi-log';\n/** Opt back into stderr diagnostics when debugging outside a live TUI. */\nconst DIAGNOSTICS_STDERR = 'stderr';\nconst LEADER_SOURCE = '@agimon-ai/doompi-log';\nconst LOG_METRICS_COMMAND = 'log-metrics';\nconst LOG_METRICS_DESCRIPTION = 'Show session-local log metrics';\nconst HELP_GROUP_ORDER = 70;\nconst NO_ENDPOINT = 'none';\nconst API_ERROR_STATUS = 400;\nconst FAILURE_STOP_REASONS = new Set(['error', 'aborted']);\n\ntype TelemetryFactory = NonNullable<DoomTelemetryOptions['telemetryFactory']>;\ntype TelemetryAttributes = Record<string, string | number | boolean>;\ntype RecordLevel = 'debug' | 'info' | 'warn' | 'error';\n\nexport interface PiTelemetryExtensionOptions {\n allowFileFallback?: boolean;\n /** Overrides the telemetry service identity. */\n serviceName?: string;\n /** Overrides the leader contribution owner. */\n leaderSource?: string;\n env?: NodeJS.ProcessEnv;\n telemetryFactory?: TelemetryFactory;\n /** Receives every sanitized record, whether or not a sink is live. */\n metrics?: LogMetricsRecorder;\n /** Called once the sink backend is resolved, so the overlay can report it. */\n onSinkStatus?: (status: SinkStatus | undefined) => void;\n /** Overrides the sink-history transport; injected in tests. */\n metricsSource?: MetricsSource;\n /** Receives telemetry lifecycle failures without writing into the TUI. */\n onDiagnostic?: (message: string) => void;\n}\n\nfunction isEnabled(value: string | undefined): boolean {\n return value === '1' || value?.toLowerCase() === 'true' || value?.toLowerCase() === 'yes';\n}\n\nfunction contextAttributes(ctx: ExtensionContext): TelemetryAttributes {\n const attributes: TelemetryAttributes = {\n 'pi.mode': ctx.mode,\n 'pi.session.id': ctx.sessionManager.getSessionId(),\n };\n if (ctx.thinkingLevel) attributes['pi.thinking_level'] = ctx.thinkingLevel;\n if (ctx.model) {\n attributes['gen_ai.provider.name'] = ctx.model.provider;\n attributes['gen_ai.request.model'] = ctx.model.id;\n }\n return attributes;\n}\n\nfunction usageAttributes(message: TurnEndEvent['message']): TelemetryAttributes | undefined {\n if (message.role !== 'assistant') return undefined;\n const attributes: TelemetryAttributes = {\n 'gen_ai.response.model': message.responseModel ?? message.model,\n 'gen_ai.response.finish_reasons': message.stopReason,\n 'gen_ai.usage.input_tokens': message.usage.input,\n 'gen_ai.usage.output_tokens': message.usage.output,\n 'gen_ai.usage.cache_read_tokens': message.usage.cacheRead,\n 'gen_ai.usage.cache_write_tokens': message.usage.cacheWrite,\n 'gen_ai.usage.total_tokens': message.usage.totalTokens,\n 'gen_ai.usage.cost': message.usage.cost.total,\n };\n if (message.usage.reasoning !== undefined) attributes['gen_ai.usage.reasoning_tokens'] = message.usage.reasoning;\n return attributes;\n}\n\nfunction failureAttributes(message: TurnEndEvent['message']): TelemetryAttributes {\n if (message.role !== 'assistant') return { 'error.type': 'AgentError', outcome: 'error' };\n const aborted = message.stopReason === 'aborted';\n return {\n 'error.type': 'ProviderError',\n 'error.code': message.stopReason,\n outcome: aborted ? 'aborted' : 'error',\n };\n}\n\nfunction statusFromTelemetry(status: ReturnType<DoomTelemetry['status']>): SinkStatus {\n return {\n service: status.serviceName,\n backend: status.backend,\n endpoint: status.endpoint ?? NO_ENDPOINT,\n endpointSource: status.endpointSource,\n traces: status.traces,\n redaction: true,\n fileFallback: status.fileFallback,\n };\n}\n\nexport function createPiTelemetryExtension(options: PiTelemetryExtensionOptions = {}) {\n return function registerPiTelemetry(pi: ExtensionAPI): void {\n const env = options.env ?? process.env;\n const metrics = options.metrics;\n const toolStartedAt = new Map<string, number>();\n let agentStartedAt: number | undefined;\n let telemetry: DoomTelemetry | undefined;\n\n const emit = async (level: RecordLevel, name: string, attributes: TelemetryAttributes): Promise<void> => {\n if (!telemetry) return;\n if (level === 'debug') await telemetry.recordDebug(name, attributes);\n else if (level === 'warn') await telemetry.recordWarning(name, undefined, attributes);\n else if (level === 'error') await telemetry.recordError(name, undefined, attributes);\n else await telemetry.recordEvent(name, attributes);\n };\n\n const getTelemetry = (ctx: ExtensionContext): DoomTelemetry => {\n telemetry ??= createDoomTelemetry({\n serviceName: options.serviceName ?? SERVICE_NAME,\n packageName: PACKAGE_NAME,\n cwd: ctx.cwd,\n env,\n allowFileFallback: options.allowFileFallback,\n telemetryFactory: options.telemetryFactory,\n warn: options.onDiagnostic,\n enableLogs: true,\n enableTraces: env.AGENT_OTEL_TRACES === undefined || isEnabled(env.AGENT_OTEL_TRACES),\n onRecord: (record) => metrics?.record(record.event, record.attributes),\n onStatus: (status) => options.onSinkStatus?.(statusFromTelemetry(status)),\n });\n options.onSinkStatus?.(statusFromTelemetry(telemetry.status()));\n return telemetry;\n };\n\n pi.on('session_start', async (event, ctx) => {\n getTelemetry(ctx);\n await emit('info', 'pi.session.started', {\n ...contextAttributes(ctx),\n 'pi.session.reason': event.reason,\n 'pi.session.previous': event.previousSessionFile !== undefined,\n });\n });\n\n pi.on('before_agent_start', async (event, ctx) => {\n getTelemetry(ctx);\n await emit('info', 'pi.user_prompt', {\n ...contextAttributes(ctx),\n 'pi.user_message.length': event.prompt.length,\n 'pi.user_message.image_count': event.images?.length ?? 0,\n });\n });\n\n pi.on('agent_start', async (_event, ctx) => {\n agentStartedAt = Date.now();\n getTelemetry(ctx);\n await emit('info', 'pi.agent.started', contextAttributes(ctx));\n });\n\n pi.on('turn_start', async (event, ctx) => {\n getTelemetry(ctx);\n await emit('debug', 'pi.turn.started', {\n ...contextAttributes(ctx),\n 'pi.turn.index': event.turnIndex,\n });\n });\n\n pi.on('turn_end', async (event, ctx) => {\n getTelemetry(ctx);\n const usage = usageAttributes(event.message);\n await emit('info', 'pi.turn.finished', {\n ...contextAttributes(ctx),\n 'pi.turn.index': event.turnIndex,\n 'pi.tool_result.count': event.toolResults.length,\n ...usage,\n });\n if (event.message.role === 'assistant' && FAILURE_STOP_REASONS.has(event.message.stopReason)) {\n await emit(event.message.stopReason === 'aborted' ? 'warn' : 'error', 'pi.turn.failed', {\n ...contextAttributes(ctx),\n 'pi.turn.index': event.turnIndex,\n ...failureAttributes(event.message),\n ...usage,\n });\n }\n if (!usage) return;\n for (const result of event.toolResults) {\n await emit('debug', 'pi.tool_token_sample', {\n ...contextAttributes(ctx),\n ...usage,\n 'tool.name': result.toolName,\n token_attribution: 'toolCallTurn',\n });\n }\n });\n\n pi.on('tool_execution_start', async (event, ctx) => {\n toolStartedAt.set(event.toolCallId, Date.now());\n getTelemetry(ctx);\n await emit('debug', 'pi.tool_call', {\n ...contextAttributes(ctx),\n 'tool.name': event.toolName,\n 'tool.call.id': event.toolCallId,\n });\n });\n\n pi.on('tool_execution_end', async (event, ctx) => {\n const startedAt = toolStartedAt.get(event.toolCallId);\n toolStartedAt.delete(event.toolCallId);\n getTelemetry(ctx);\n await emit('info', 'pi.tool_result', {\n ...contextAttributes(ctx),\n success: !event.isError,\n 'tool.name': event.toolName,\n 'tool.call.id': event.toolCallId,\n 'tool.result.error': event.isError,\n ...(startedAt === undefined ? {} : { 'tool.duration_ms': Date.now() - startedAt }),\n });\n });\n\n pi.on('after_provider_response', async (event, ctx) => {\n getTelemetry(ctx);\n const attributes = {\n ...contextAttributes(ctx),\n 'http.response.status_code': event.status,\n };\n if (event.status >= API_ERROR_STATUS) await emit('error', 'pi.api_error', attributes);\n else await emit('debug', 'pi.api_response', attributes);\n });\n\n pi.on('model_select', async (event, ctx) => {\n getTelemetry(ctx);\n await emit('info', 'pi.model.selected', {\n ...contextAttributes(ctx),\n 'pi.model.source': event.source,\n 'gen_ai.provider.name': event.model.provider,\n 'gen_ai.request.model': event.model.id,\n });\n });\n\n pi.on('agent_end', async (event, ctx) => {\n getTelemetry(ctx);\n await emit('info', 'pi.agent.finished', {\n ...contextAttributes(ctx),\n 'pi.message.count': event.messages.length,\n ...(agentStartedAt === undefined ? {} : { 'pi.agent.duration_ms': Date.now() - agentStartedAt }),\n });\n agentStartedAt = undefined;\n await telemetry?.flush();\n });\n\n pi.on('agent_settled', async (_event, ctx) => {\n getTelemetry(ctx);\n await emit('debug', 'pi.agent.settled', contextAttributes(ctx));\n });\n\n pi.on('session_shutdown', async (event, ctx) => {\n getTelemetry(ctx);\n await emit('info', 'pi.session.finished', {\n ...contextAttributes(ctx),\n 'pi.session.reason': event.reason,\n });\n await telemetry?.shutdown();\n });\n };\n}\n\nexport function registerLogMetricsLeaderBinding(\n pi: Pick<ExtensionAPI, 'events' | 'on'>,\n options: { source?: string } = {},\n): () => void {\n return registerDoomLeaderContribution(pi, {\n source: options.source ?? LEADER_SOURCE,\n bindings: [\n {\n id: 'log.metrics',\n path: [\n { key: 'h', label: 'help', order: HELP_GROUP_ORDER },\n { key: 'l', label: 'logs', detail: 'telemetry' },\n ],\n command: { name: LOG_METRICS_COMMAND },\n },\n ],\n });\n}\n\nexport async function openLogMetricsOverlay(\n ctx: ExtensionContext,\n getView: () => LogMetricsView,\n query?: MetricsQuery,\n): Promise<void> {\n await ctx.ui.custom<undefined>(\n (tui, theme, _keybindings, done) => new LogMetricsOverlayComponent(tui, theme, getView, done, query),\n {\n overlay: true,\n overlayOptions: {\n anchor: 'top-left',\n width: '100%',\n maxHeight: '100%',\n margin: 0,\n },\n },\n );\n}\n\nexport function createDoomLogExtension(options: PiTelemetryExtensionOptions = {}) {\n return function registerDoomLog(pi: ExtensionAPI): void {\n const env = options.env ?? process.env;\n const metrics = new LogMetricsAggregator();\n const metricsSource = options.metricsSource ?? createMetricsSource({ env });\n let sink: SinkStatus | undefined;\n let lastDiagnostic: string | undefined;\n\n createPiTelemetryExtension({\n ...options,\n metrics,\n // Always supply a sink so doom-telemetry never falls back to\n // process.emitWarning, which writes raw stderr over the TUI frame.\n // Diagnostics surface in the Log Metrics overlay instead.\n onDiagnostic: (message) => {\n lastDiagnostic = message;\n if (options.onDiagnostic) options.onDiagnostic(message);\n else if (env.AGENT_OTEL_DIAGNOSTICS === DIAGNOSTICS_STDERR) process.emitWarning(message);\n },\n onSinkStatus: (status) => {\n sink = status;\n options.onSinkStatus?.(status);\n },\n })(pi);\n\n registerLogMetricsLeaderBinding(pi, { source: options.leaderSource });\n pi.registerCommand(LOG_METRICS_COMMAND, {\n description: LOG_METRICS_DESCRIPTION,\n handler: async (_args, ctx) => {\n await openLogMetricsOverlay(\n ctx,\n () => ({\n disabled: isEnabled(env.AGENT_TELEMETRY_DISABLED) || isEnabled(env.OTEL_SDK_DISABLED),\n snapshot: metrics.snapshot(),\n sink,\n transport: metricsSource.lastTransport(),\n lastDiagnostic,\n }),\n metricsSource.query,\n );\n },\n });\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"extension.cjs","names":["createDoomTelemetry","registerDoomLeaderContribution","LogMetricsOverlayComponent","LogMetricsAggregator","createMetricsSource"],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["/**\n * Pi telemetry wiring for the Doom harness.\n *\n * This extension deliberately emits metadata-only records. Prompt, message,\n * tool payload, file path, diagnostic text, exception, and stack data never\n * cross the shared telemetry boundary.\n */\n\nimport { registerDoomLeaderContribution } from '@agimon-ai/doompi-extension-contracts/leader';\nimport { createDoomTelemetry, type DoomTelemetry, type DoomTelemetryOptions } from '@agimon-ai/doompi-telemetry';\nimport type { ExtensionAPI, ExtensionContext, TurnEndEvent } from '@earendil-works/pi-coding-agent';\nimport { LogMetricsAggregator, type LogMetricsRecorder } from '../../services/metrics.ts';\nimport { LogMetricsOverlayComponent, type LogMetricsView, type SinkStatus } from '../../tui/logMetricsOverlay.ts';\nimport type { MetricsQuery, MetricsSource } from '../../types/metricsSource.ts';\nimport { createMetricsSource } from '../node/metricsSource.ts';\n\nconst SERVICE_NAME = 'pi';\nconst PACKAGE_NAME = '@agimon-ai/doompi-log';\n/** Opt back into stderr diagnostics when debugging outside a live TUI. */\nconst DIAGNOSTICS_STDERR = 'stderr';\nconst LEADER_SOURCE = '@agimon-ai/doompi-log';\nconst LOG_METRICS_COMMAND = 'log-metrics';\nconst LOG_METRICS_DESCRIPTION = 'Show session-local log metrics';\nconst HELP_GROUP_ORDER = 70;\nconst NO_ENDPOINT = 'none';\nconst API_ERROR_STATUS = 400;\nconst FAILURE_STOP_REASONS = new Set(['error', 'aborted']);\n\ntype TelemetryFactory = NonNullable<DoomTelemetryOptions['telemetryFactory']>;\ntype TelemetryAttributes = Record<string, string | number | boolean>;\ntype RecordLevel = 'debug' | 'info' | 'warn' | 'error';\n\nexport interface PiTelemetryExtensionOptions {\n allowFileFallback?: boolean;\n /** Overrides the telemetry service identity. */\n serviceName?: string;\n /** Overrides the leader contribution owner. */\n leaderSource?: string;\n env?: NodeJS.ProcessEnv;\n telemetryFactory?: TelemetryFactory;\n /** Receives every sanitized record, whether or not a sink is live. */\n metrics?: LogMetricsRecorder;\n /** Called once the sink backend is resolved, so the overlay can report it. */\n onSinkStatus?: (status: SinkStatus | undefined) => void;\n /** Overrides the sink-history transport; injected in tests. */\n metricsSource?: MetricsSource;\n /** Receives telemetry lifecycle failures without writing into the TUI. */\n onDiagnostic?: (message: string) => void;\n}\n\nfunction isEnabled(value: string | undefined): boolean {\n return value === '1' || value?.toLowerCase() === 'true' || value?.toLowerCase() === 'yes';\n}\n\nfunction contextAttributes(ctx: ExtensionContext): TelemetryAttributes {\n const attributes: TelemetryAttributes = {\n 'pi.mode': ctx.mode,\n 'pi.session.id': ctx.sessionManager.getSessionId(),\n };\n if (ctx.thinkingLevel) attributes['pi.thinking_level'] = ctx.thinkingLevel;\n if (ctx.model) {\n attributes['gen_ai.provider.name'] = ctx.model.provider;\n attributes['gen_ai.request.model'] = ctx.model.id;\n }\n return attributes;\n}\n\nfunction usageAttributes(message: TurnEndEvent['message']): TelemetryAttributes | undefined {\n if (message.role !== 'assistant') return undefined;\n const attributes: TelemetryAttributes = {\n 'gen_ai.response.model': message.responseModel ?? message.model,\n 'gen_ai.response.finish_reasons': message.stopReason,\n 'gen_ai.usage.input_tokens': message.usage.input,\n 'gen_ai.usage.output_tokens': message.usage.output,\n 'gen_ai.usage.cache_read_tokens': message.usage.cacheRead,\n 'gen_ai.usage.cache_write_tokens': message.usage.cacheWrite,\n 'gen_ai.usage.total_tokens': message.usage.totalTokens,\n 'gen_ai.usage.cost': message.usage.cost.total,\n };\n if (message.usage.reasoning !== undefined) attributes['gen_ai.usage.reasoning_tokens'] = message.usage.reasoning;\n return attributes;\n}\n\nfunction failureAttributes(message: TurnEndEvent['message']): TelemetryAttributes {\n if (message.role !== 'assistant') return { 'error.type': 'AgentError', outcome: 'error' };\n const aborted = message.stopReason === 'aborted';\n return {\n 'error.type': 'ProviderError',\n 'error.code': message.stopReason,\n outcome: aborted ? 'aborted' : 'error',\n };\n}\n\nfunction statusFromTelemetry(status: ReturnType<DoomTelemetry['status']>): SinkStatus {\n return {\n service: status.serviceName,\n backend: status.backend,\n endpoint: status.endpoint ?? NO_ENDPOINT,\n endpointSource: status.endpointSource,\n traces: status.traces,\n redaction: true,\n fileFallback: status.fileFallback,\n };\n}\n\nexport function createPiTelemetryExtension(options: PiTelemetryExtensionOptions = {}) {\n return function registerPiTelemetry(pi: ExtensionAPI): void {\n const env = options.env ?? process.env;\n const metrics = options.metrics;\n const toolStartedAt = new Map<string, number>();\n let agentStartedAt: number | undefined;\n let telemetry: DoomTelemetry | undefined;\n\n const emit = async (level: RecordLevel, name: string, attributes: TelemetryAttributes): Promise<void> => {\n if (!telemetry) return;\n if (level === 'debug') await telemetry.recordDebug(name, attributes);\n else if (level === 'warn') await telemetry.recordWarning(name, undefined, attributes);\n else if (level === 'error') await telemetry.recordError(name, undefined, attributes);\n else await telemetry.recordEvent(name, attributes);\n };\n\n const getTelemetry = (ctx: ExtensionContext): DoomTelemetry => {\n telemetry ??= createDoomTelemetry({\n serviceName: options.serviceName ?? SERVICE_NAME,\n packageName: PACKAGE_NAME,\n cwd: ctx.cwd,\n env,\n allowFileFallback: options.allowFileFallback,\n telemetryFactory: options.telemetryFactory,\n warn: options.onDiagnostic,\n enableLogs: true,\n enableTraces: env.AGENT_OTEL_TRACES === undefined || isEnabled(env.AGENT_OTEL_TRACES),\n onRecord: (record) => metrics?.record(record.event, record.attributes),\n onStatus: (status) => options.onSinkStatus?.(statusFromTelemetry(status)),\n });\n options.onSinkStatus?.(statusFromTelemetry(telemetry.status()));\n return telemetry;\n };\n\n pi.on('session_start', async (event, ctx) => {\n getTelemetry(ctx);\n await emit('info', 'pi.session.started', {\n ...contextAttributes(ctx),\n 'pi.session.reason': event.reason,\n 'pi.session.previous': event.previousSessionFile !== undefined,\n });\n });\n\n pi.on('before_agent_start', async (event, ctx) => {\n getTelemetry(ctx);\n await emit('info', 'pi.user_prompt', {\n ...contextAttributes(ctx),\n 'pi.user_message.length': event.prompt.length,\n 'pi.user_message.image_count': event.images?.length ?? 0,\n });\n });\n\n pi.on('agent_start', async (_event, ctx) => {\n agentStartedAt = Date.now();\n getTelemetry(ctx);\n await emit('info', 'pi.agent.started', contextAttributes(ctx));\n });\n\n pi.on('turn_start', async (event, ctx) => {\n getTelemetry(ctx);\n await emit('debug', 'pi.turn.started', {\n ...contextAttributes(ctx),\n 'pi.turn.index': event.turnIndex,\n });\n });\n\n pi.on('turn_end', async (event, ctx) => {\n getTelemetry(ctx);\n const usage = usageAttributes(event.message);\n await emit('info', 'pi.turn.finished', {\n ...contextAttributes(ctx),\n 'pi.turn.index': event.turnIndex,\n 'pi.tool_result.count': event.toolResults.length,\n ...usage,\n });\n if (event.message.role === 'assistant' && FAILURE_STOP_REASONS.has(event.message.stopReason)) {\n await emit(event.message.stopReason === 'aborted' ? 'warn' : 'error', 'pi.turn.failed', {\n ...contextAttributes(ctx),\n 'pi.turn.index': event.turnIndex,\n ...failureAttributes(event.message),\n ...usage,\n });\n }\n if (!usage) return;\n for (const result of event.toolResults) {\n await emit('debug', 'pi.tool_token_sample', {\n ...contextAttributes(ctx),\n ...usage,\n 'tool.name': result.toolName,\n token_attribution: 'toolCallTurn',\n });\n }\n });\n\n pi.on('tool_execution_start', async (event, ctx) => {\n toolStartedAt.set(event.toolCallId, Date.now());\n getTelemetry(ctx);\n await emit('debug', 'pi.tool_call', {\n ...contextAttributes(ctx),\n 'tool.name': event.toolName,\n 'tool.call.id': event.toolCallId,\n });\n });\n\n pi.on('tool_execution_end', async (event, ctx) => {\n const startedAt = toolStartedAt.get(event.toolCallId);\n toolStartedAt.delete(event.toolCallId);\n getTelemetry(ctx);\n await emit('info', 'pi.tool_result', {\n ...contextAttributes(ctx),\n success: !event.isError,\n 'tool.name': event.toolName,\n 'tool.call.id': event.toolCallId,\n 'tool.result.error': event.isError,\n ...(startedAt === undefined ? {} : { 'tool.duration_ms': Date.now() - startedAt }),\n });\n });\n\n pi.on('after_provider_response', async (event, ctx) => {\n getTelemetry(ctx);\n const attributes = {\n ...contextAttributes(ctx),\n 'http.response.status_code': event.status,\n };\n if (event.status >= API_ERROR_STATUS) await emit('error', 'pi.api_error', attributes);\n else await emit('debug', 'pi.api_response', attributes);\n });\n\n pi.on('model_select', async (event, ctx) => {\n getTelemetry(ctx);\n await emit('info', 'pi.model.selected', {\n ...contextAttributes(ctx),\n 'pi.model.source': event.source,\n 'gen_ai.provider.name': event.model.provider,\n 'gen_ai.request.model': event.model.id,\n });\n });\n\n pi.on('agent_end', async (event, ctx) => {\n getTelemetry(ctx);\n await emit('info', 'pi.agent.finished', {\n ...contextAttributes(ctx),\n 'pi.message.count': event.messages.length,\n ...(agentStartedAt === undefined ? {} : { 'pi.agent.duration_ms': Date.now() - agentStartedAt }),\n });\n agentStartedAt = undefined;\n await telemetry?.flush();\n });\n\n pi.on('agent_settled', async (_event, ctx) => {\n getTelemetry(ctx);\n await emit('debug', 'pi.agent.settled', contextAttributes(ctx));\n });\n\n pi.on('session_shutdown', async (event, ctx) => {\n getTelemetry(ctx);\n await emit('info', 'pi.session.finished', {\n ...contextAttributes(ctx),\n 'pi.session.reason': event.reason,\n });\n await telemetry?.shutdown();\n });\n };\n}\n\nexport function registerLogMetricsLeaderBinding(\n pi: Pick<ExtensionAPI, 'events' | 'on'>,\n options: { source?: string } = {},\n): () => void {\n return registerDoomLeaderContribution(pi, {\n source: options.source ?? LEADER_SOURCE,\n bindings: [\n {\n id: 'log.metrics',\n path: [\n { key: 'h', label: 'help', order: HELP_GROUP_ORDER },\n { key: 'l', label: 'logs', detail: 'telemetry' },\n ],\n command: { name: LOG_METRICS_COMMAND },\n },\n ],\n });\n}\n\nexport async function openLogMetricsOverlay(\n ctx: ExtensionContext,\n getView: () => LogMetricsView,\n query?: MetricsQuery,\n): Promise<void> {\n await ctx.ui.custom<undefined>(\n (tui, theme, _keybindings, done) => new LogMetricsOverlayComponent(tui, theme, getView, done, query),\n {\n overlay: true,\n overlayOptions: {\n anchor: 'top-left',\n width: '100%',\n maxHeight: '100%',\n margin: 0,\n },\n },\n );\n}\n\nexport function createDoomLogExtension(options: PiTelemetryExtensionOptions = {}) {\n return function registerDoomLog(pi: ExtensionAPI): void {\n const env = options.env ?? process.env;\n const metrics = new LogMetricsAggregator();\n const metricsSource = options.metricsSource ?? createMetricsSource({ env });\n let sink: SinkStatus | undefined;\n let lastDiagnostic: string | undefined;\n\n createPiTelemetryExtension({\n ...options,\n metrics,\n // Always supply a sink so doom-telemetry never falls back to\n // process.emitWarning, which writes raw stderr over the TUI frame.\n // Diagnostics surface in the Log Metrics overlay instead.\n onDiagnostic: (message) => {\n lastDiagnostic = message;\n if (options.onDiagnostic) options.onDiagnostic(message);\n else if (env.AGENT_OTEL_DIAGNOSTICS === DIAGNOSTICS_STDERR) process.emitWarning(message);\n },\n onSinkStatus: (status) => {\n sink = status;\n options.onSinkStatus?.(status);\n },\n })(pi);\n\n registerLogMetricsLeaderBinding(pi, { source: options.leaderSource });\n pi.registerCommand(LOG_METRICS_COMMAND, {\n description: LOG_METRICS_DESCRIPTION,\n handler: async (_args, ctx) => {\n await openLogMetricsOverlay(\n ctx,\n () => ({\n disabled: isEnabled(env.AGENT_TELEMETRY_DISABLED) || isEnabled(env.OTEL_SDK_DISABLED),\n snapshot: metrics.snapshot(),\n sink,\n transport: metricsSource.lastTransport(),\n lastDiagnostic,\n }),\n metricsSource.query,\n );\n },\n });\n };\n}\n\nexport const doomLogExtension = createDoomLogExtension();\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { LogMetricsRecorder } from "../../services/metrics.cjs";
2
- import { MetricsQuery, MetricsSource } from "../../services/metricsSource.cjs";
3
- import { LogMetricsView, SinkStatus } from "../../tui/metricsOverlay.cjs";
2
+ import { MetricsQuery, MetricsSource } from "../../types/metricsSource.cjs";
3
+ import { LogMetricsView, SinkStatus } from "../../tui/logMetricsOverlay.cjs";
4
4
  import { DoomTelemetryOptions } from "@agimon-ai/doompi-telemetry";
5
5
  import { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
6
6
  //#region src/adapters/pi/extension.d.ts
@@ -28,6 +28,7 @@ declare function registerLogMetricsLeaderBinding(pi: Pick<ExtensionAPI, 'events'
28
28
  }): () => void;
29
29
  declare function openLogMetricsOverlay(ctx: ExtensionContext, getView: () => LogMetricsView, query?: MetricsQuery): Promise<void>;
30
30
  declare function createDoomLogExtension(options?: PiTelemetryExtensionOptions): (pi: ExtensionAPI) => void;
31
+ declare const doomLogExtension: (pi: ExtensionAPI) => void;
31
32
  //#endregion
32
- export { PiTelemetryExtensionOptions, createDoomLogExtension, createPiTelemetryExtension, openLogMetricsOverlay, registerLogMetricsLeaderBinding };
33
+ export { PiTelemetryExtensionOptions, createDoomLogExtension, createPiTelemetryExtension, doomLogExtension, openLogMetricsOverlay, registerLogMetricsLeaderBinding };
33
34
  //# sourceMappingURL=extension.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension.d.cts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;;;KA2BK,mBAAmB,YAAY;UAInB;EACf;;EAEA;;EAEA;EACA,MAAM,OAAO;EACb,mBAAmB;;EAEnB,UAAU;;EAEV,gBAAgB,QAAQ;;EAExB,gBAAgB;;EAEhB,gBAAgB;;iBA0DF,2BAA2B,UAAS,+BACd,IAAI;iBAoK1B,gCACd,IAAI,KAAK,gCACT;EAAW;;iBAiBS,sBACpB,KAAK,kBACL,eAAe,gBACf,QAAQ,eACP;iBAea,uBAAuB,UAAS,+BACd,IAAI"}
1
+ {"version":3,"file":"extension.d.cts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;;;KA4BK,mBAAmB,YAAY;UAInB;EACf;;EAEA;;EAEA;EACA,MAAM,OAAO;EACb,mBAAmB;;EAEnB,UAAU;;EAEV,gBAAgB,QAAQ;;EAExB,gBAAgB;;EAEhB,gBAAgB;;iBA0DF,2BAA2B,UAAS,+BACd,IAAI;iBAoK1B,gCACd,IAAI,KAAK,gCACT;EAAW;;iBAiBS,sBACpB,KAAK,kBACL,eAAe,gBACf,QAAQ,eACP;iBAea,uBAAuB,UAAS,+BACd,IAAI;cA4CzB,mBAAgB,IA5CS"}
@@ -1,6 +1,6 @@
1
1
  import { LogMetricsRecorder } from "../../services/metrics.mjs";
2
- import { MetricsQuery, MetricsSource } from "../../services/metricsSource.mjs";
3
- import { LogMetricsView, SinkStatus } from "../../tui/metricsOverlay.mjs";
2
+ import { MetricsQuery, MetricsSource } from "../../types/metricsSource.mjs";
3
+ import { LogMetricsView, SinkStatus } from "../../tui/logMetricsOverlay.mjs";
4
4
  import { DoomTelemetryOptions } from "@agimon-ai/doompi-telemetry";
5
5
  import { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
6
6
  //#region src/adapters/pi/extension.d.ts
@@ -28,6 +28,7 @@ declare function registerLogMetricsLeaderBinding(pi: Pick<ExtensionAPI, 'events'
28
28
  }): () => void;
29
29
  declare function openLogMetricsOverlay(ctx: ExtensionContext, getView: () => LogMetricsView, query?: MetricsQuery): Promise<void>;
30
30
  declare function createDoomLogExtension(options?: PiTelemetryExtensionOptions): (pi: ExtensionAPI) => void;
31
+ declare const doomLogExtension: (pi: ExtensionAPI) => void;
31
32
  //#endregion
32
- export { PiTelemetryExtensionOptions, createDoomLogExtension, createPiTelemetryExtension, openLogMetricsOverlay, registerLogMetricsLeaderBinding };
33
+ export { PiTelemetryExtensionOptions, createDoomLogExtension, createPiTelemetryExtension, doomLogExtension, openLogMetricsOverlay, registerLogMetricsLeaderBinding };
33
34
  //# sourceMappingURL=extension.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension.d.mts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;;;KA2BK,mBAAmB,YAAY;UAInB;EACf;;EAEA;;EAEA;EACA,MAAM,OAAO;EACb,mBAAmB;;EAEnB,UAAU;;EAEV,gBAAgB,QAAQ;;EAExB,gBAAgB;;EAEhB,gBAAgB;;iBA0DF,2BAA2B,UAAS,+BACd,IAAI;iBAoK1B,gCACd,IAAI,KAAK,gCACT;EAAW;;iBAiBS,sBACpB,KAAK,kBACL,eAAe,gBACf,QAAQ,eACP;iBAea,uBAAuB,UAAS,+BACd,IAAI"}
1
+ {"version":3,"file":"extension.d.mts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;;;KA4BK,mBAAmB,YAAY;UAInB;EACf;;EAEA;;EAEA;EACA,MAAM,OAAO;EACb,mBAAmB;;EAEnB,UAAU;;EAEV,gBAAgB,QAAQ;;EAExB,gBAAgB;;EAEhB,gBAAgB;;iBA0DF,2BAA2B,UAAS,+BACd,IAAI;iBAoK1B,gCACd,IAAI,KAAK,gCACT;EAAW;;iBAiBS,sBACpB,KAAK,kBACL,eAAe,gBACf,QAAQ,eACP;iBAea,uBAAuB,UAAS,+BACd,IAAI;cA4CzB,mBAAgB,IA5CS"}
@@ -1,2 +1,2 @@
1
- import{LogMetricsAggregator as e}from"../../services/metrics.mjs";import{createMetricsSource as t}from"../../services/metricsSource.mjs";import{LogMetricsOverlayComponent as n}from"../../tui/metricsOverlay.mjs";import{registerDoomLeaderContribution as r}from"@agimon-ai/doompi-extension-contracts/leader";import{createDoomTelemetry as i}from"@agimon-ai/doompi-telemetry";const a=`log-metrics`,o=new Set([`error`,`aborted`]);function s(e){return e===`1`||e?.toLowerCase()===`true`||e?.toLowerCase()===`yes`}function c(e){let t={"pi.mode":e.mode,"pi.session.id":e.sessionManager.getSessionId()};return e.thinkingLevel&&(t[`pi.thinking_level`]=e.thinkingLevel),e.model&&(t[`gen_ai.provider.name`]=e.model.provider,t[`gen_ai.request.model`]=e.model.id),t}function l(e){if(e.role!==`assistant`)return;let t={"gen_ai.response.model":e.responseModel??e.model,"gen_ai.response.finish_reasons":e.stopReason,"gen_ai.usage.input_tokens":e.usage.input,"gen_ai.usage.output_tokens":e.usage.output,"gen_ai.usage.cache_read_tokens":e.usage.cacheRead,"gen_ai.usage.cache_write_tokens":e.usage.cacheWrite,"gen_ai.usage.total_tokens":e.usage.totalTokens,"gen_ai.usage.cost":e.usage.cost.total};return e.usage.reasoning!==void 0&&(t[`gen_ai.usage.reasoning_tokens`]=e.usage.reasoning),t}function u(e){if(e.role!==`assistant`)return{"error.type":`AgentError`,outcome:`error`};let t=e.stopReason===`aborted`;return{"error.type":`ProviderError`,"error.code":e.stopReason,outcome:t?`aborted`:`error`}}function d(e){return{service:e.serviceName,backend:e.backend,endpoint:e.endpoint??`none`,endpointSource:e.endpointSource,traces:e.traces,redaction:!0,fileFallback:e.fileFallback}}function f(e={}){return function(t){let n=e.env??process.env,r=e.metrics,a=new Map,f,p,m=async(e,t,n)=>{p&&(e===`debug`?await p.recordDebug(t,n):e===`warn`?await p.recordWarning(t,void 0,n):e===`error`?await p.recordError(t,void 0,n):await p.recordEvent(t,n))},h=t=>(p??=i({serviceName:e.serviceName??`pi`,packageName:`@agimon-ai/doompi-log`,cwd:t.cwd,env:n,allowFileFallback:e.allowFileFallback,telemetryFactory:e.telemetryFactory,warn:e.onDiagnostic,enableLogs:!0,enableTraces:n.AGENT_OTEL_TRACES===void 0||s(n.AGENT_OTEL_TRACES),onRecord:e=>r?.record(e.event,e.attributes),onStatus:t=>e.onSinkStatus?.(d(t))}),e.onSinkStatus?.(d(p.status())),p);t.on(`session_start`,async(e,t)=>{h(t),await m(`info`,`pi.session.started`,{...c(t),"pi.session.reason":e.reason,"pi.session.previous":e.previousSessionFile!==void 0})}),t.on(`before_agent_start`,async(e,t)=>{h(t),await m(`info`,`pi.user_prompt`,{...c(t),"pi.user_message.length":e.prompt.length,"pi.user_message.image_count":e.images?.length??0})}),t.on(`agent_start`,async(e,t)=>{f=Date.now(),h(t),await m(`info`,`pi.agent.started`,c(t))}),t.on(`turn_start`,async(e,t)=>{h(t),await m(`debug`,`pi.turn.started`,{...c(t),"pi.turn.index":e.turnIndex})}),t.on(`turn_end`,async(e,t)=>{h(t);let n=l(e.message);if(await m(`info`,`pi.turn.finished`,{...c(t),"pi.turn.index":e.turnIndex,"pi.tool_result.count":e.toolResults.length,...n}),e.message.role===`assistant`&&o.has(e.message.stopReason)&&await m(e.message.stopReason===`aborted`?`warn`:`error`,`pi.turn.failed`,{...c(t),"pi.turn.index":e.turnIndex,...u(e.message),...n}),n)for(let r of e.toolResults)await m(`debug`,`pi.tool_token_sample`,{...c(t),...n,"tool.name":r.toolName,token_attribution:`toolCallTurn`})}),t.on(`tool_execution_start`,async(e,t)=>{a.set(e.toolCallId,Date.now()),h(t),await m(`debug`,`pi.tool_call`,{...c(t),"tool.name":e.toolName,"tool.call.id":e.toolCallId})}),t.on(`tool_execution_end`,async(e,t)=>{let n=a.get(e.toolCallId);a.delete(e.toolCallId),h(t),await m(`info`,`pi.tool_result`,{...c(t),success:!e.isError,"tool.name":e.toolName,"tool.call.id":e.toolCallId,"tool.result.error":e.isError,...n===void 0?{}:{"tool.duration_ms":Date.now()-n}})}),t.on(`after_provider_response`,async(e,t)=>{h(t);let n={...c(t),"http.response.status_code":e.status};e.status>=400?await m(`error`,`pi.api_error`,n):await m(`debug`,`pi.api_response`,n)}),t.on(`model_select`,async(e,t)=>{h(t),await m(`info`,`pi.model.selected`,{...c(t),"pi.model.source":e.source,"gen_ai.provider.name":e.model.provider,"gen_ai.request.model":e.model.id})}),t.on(`agent_end`,async(e,t)=>{h(t),await m(`info`,`pi.agent.finished`,{...c(t),"pi.message.count":e.messages.length,...f===void 0?{}:{"pi.agent.duration_ms":Date.now()-f}}),f=void 0,await p?.flush()}),t.on(`agent_settled`,async(e,t)=>{h(t),await m(`debug`,`pi.agent.settled`,c(t))}),t.on(`session_shutdown`,async(e,t)=>{h(t),await m(`info`,`pi.session.finished`,{...c(t),"pi.session.reason":e.reason}),await p?.shutdown()})}}function p(e,t={}){return r(e,{source:t.source??`@agimon-ai/doompi-log`,bindings:[{id:`log.metrics`,path:[{key:`h`,label:`help`,order:70},{key:`l`,label:`logs`,detail:`telemetry`}],command:{name:a}}]})}async function m(e,t,r){await e.ui.custom((e,i,a,o)=>new n(e,i,t,o,r),{overlay:!0,overlayOptions:{anchor:`top-left`,width:`100%`,maxHeight:`100%`,margin:0}})}function h(n={}){return function(r){let i=n.env??process.env,o=new e,c=n.metricsSource??t({env:i}),l,u;f({...n,metrics:o,onDiagnostic:e=>{u=e,n.onDiagnostic?n.onDiagnostic(e):i.AGENT_OTEL_DIAGNOSTICS===`stderr`&&process.emitWarning(e)},onSinkStatus:e=>{l=e,n.onSinkStatus?.(e)}})(r),p(r,{source:n.leaderSource}),r.registerCommand(a,{description:`Show session-local log metrics`,handler:async(e,t)=>{await m(t,()=>({disabled:s(i.AGENT_TELEMETRY_DISABLED)||s(i.OTEL_SDK_DISABLED),snapshot:o.snapshot(),sink:l,transport:c.lastTransport(),lastDiagnostic:u}),c.query)}})}}export{h as createDoomLogExtension,f as createPiTelemetryExtension,m as openLogMetricsOverlay,p as registerLogMetricsLeaderBinding};
1
+ import{LogMetricsAggregator as e}from"../../services/metrics.mjs";import{LogMetricsOverlayComponent as t}from"../../tui/logMetricsOverlay.mjs";import{createMetricsSource as n}from"../node/metricsSource.mjs";import{registerDoomLeaderContribution as r}from"@agimon-ai/doompi-extension-contracts/leader";import{createDoomTelemetry as i}from"@agimon-ai/doompi-telemetry";const a=`log-metrics`,o=new Set([`error`,`aborted`]);function s(e){return e===`1`||e?.toLowerCase()===`true`||e?.toLowerCase()===`yes`}function c(e){let t={"pi.mode":e.mode,"pi.session.id":e.sessionManager.getSessionId()};return e.thinkingLevel&&(t[`pi.thinking_level`]=e.thinkingLevel),e.model&&(t[`gen_ai.provider.name`]=e.model.provider,t[`gen_ai.request.model`]=e.model.id),t}function l(e){if(e.role!==`assistant`)return;let t={"gen_ai.response.model":e.responseModel??e.model,"gen_ai.response.finish_reasons":e.stopReason,"gen_ai.usage.input_tokens":e.usage.input,"gen_ai.usage.output_tokens":e.usage.output,"gen_ai.usage.cache_read_tokens":e.usage.cacheRead,"gen_ai.usage.cache_write_tokens":e.usage.cacheWrite,"gen_ai.usage.total_tokens":e.usage.totalTokens,"gen_ai.usage.cost":e.usage.cost.total};return e.usage.reasoning!==void 0&&(t[`gen_ai.usage.reasoning_tokens`]=e.usage.reasoning),t}function u(e){if(e.role!==`assistant`)return{"error.type":`AgentError`,outcome:`error`};let t=e.stopReason===`aborted`;return{"error.type":`ProviderError`,"error.code":e.stopReason,outcome:t?`aborted`:`error`}}function d(e){return{service:e.serviceName,backend:e.backend,endpoint:e.endpoint??`none`,endpointSource:e.endpointSource,traces:e.traces,redaction:!0,fileFallback:e.fileFallback}}function f(e={}){return function(t){let n=e.env??process.env,r=e.metrics,a=new Map,f,p,m=async(e,t,n)=>{p&&(e===`debug`?await p.recordDebug(t,n):e===`warn`?await p.recordWarning(t,void 0,n):e===`error`?await p.recordError(t,void 0,n):await p.recordEvent(t,n))},h=t=>(p??=i({serviceName:e.serviceName??`pi`,packageName:`@agimon-ai/doompi-log`,cwd:t.cwd,env:n,allowFileFallback:e.allowFileFallback,telemetryFactory:e.telemetryFactory,warn:e.onDiagnostic,enableLogs:!0,enableTraces:n.AGENT_OTEL_TRACES===void 0||s(n.AGENT_OTEL_TRACES),onRecord:e=>r?.record(e.event,e.attributes),onStatus:t=>e.onSinkStatus?.(d(t))}),e.onSinkStatus?.(d(p.status())),p);t.on(`session_start`,async(e,t)=>{h(t),await m(`info`,`pi.session.started`,{...c(t),"pi.session.reason":e.reason,"pi.session.previous":e.previousSessionFile!==void 0})}),t.on(`before_agent_start`,async(e,t)=>{h(t),await m(`info`,`pi.user_prompt`,{...c(t),"pi.user_message.length":e.prompt.length,"pi.user_message.image_count":e.images?.length??0})}),t.on(`agent_start`,async(e,t)=>{f=Date.now(),h(t),await m(`info`,`pi.agent.started`,c(t))}),t.on(`turn_start`,async(e,t)=>{h(t),await m(`debug`,`pi.turn.started`,{...c(t),"pi.turn.index":e.turnIndex})}),t.on(`turn_end`,async(e,t)=>{h(t);let n=l(e.message);if(await m(`info`,`pi.turn.finished`,{...c(t),"pi.turn.index":e.turnIndex,"pi.tool_result.count":e.toolResults.length,...n}),e.message.role===`assistant`&&o.has(e.message.stopReason)&&await m(e.message.stopReason===`aborted`?`warn`:`error`,`pi.turn.failed`,{...c(t),"pi.turn.index":e.turnIndex,...u(e.message),...n}),n)for(let r of e.toolResults)await m(`debug`,`pi.tool_token_sample`,{...c(t),...n,"tool.name":r.toolName,token_attribution:`toolCallTurn`})}),t.on(`tool_execution_start`,async(e,t)=>{a.set(e.toolCallId,Date.now()),h(t),await m(`debug`,`pi.tool_call`,{...c(t),"tool.name":e.toolName,"tool.call.id":e.toolCallId})}),t.on(`tool_execution_end`,async(e,t)=>{let n=a.get(e.toolCallId);a.delete(e.toolCallId),h(t),await m(`info`,`pi.tool_result`,{...c(t),success:!e.isError,"tool.name":e.toolName,"tool.call.id":e.toolCallId,"tool.result.error":e.isError,...n===void 0?{}:{"tool.duration_ms":Date.now()-n}})}),t.on(`after_provider_response`,async(e,t)=>{h(t);let n={...c(t),"http.response.status_code":e.status};e.status>=400?await m(`error`,`pi.api_error`,n):await m(`debug`,`pi.api_response`,n)}),t.on(`model_select`,async(e,t)=>{h(t),await m(`info`,`pi.model.selected`,{...c(t),"pi.model.source":e.source,"gen_ai.provider.name":e.model.provider,"gen_ai.request.model":e.model.id})}),t.on(`agent_end`,async(e,t)=>{h(t),await m(`info`,`pi.agent.finished`,{...c(t),"pi.message.count":e.messages.length,...f===void 0?{}:{"pi.agent.duration_ms":Date.now()-f}}),f=void 0,await p?.flush()}),t.on(`agent_settled`,async(e,t)=>{h(t),await m(`debug`,`pi.agent.settled`,c(t))}),t.on(`session_shutdown`,async(e,t)=>{h(t),await m(`info`,`pi.session.finished`,{...c(t),"pi.session.reason":e.reason}),await p?.shutdown()})}}function p(e,t={}){return r(e,{source:t.source??`@agimon-ai/doompi-log`,bindings:[{id:`log.metrics`,path:[{key:`h`,label:`help`,order:70},{key:`l`,label:`logs`,detail:`telemetry`}],command:{name:a}}]})}async function m(e,n,r){await e.ui.custom((e,i,a,o)=>new t(e,i,n,o,r),{overlay:!0,overlayOptions:{anchor:`top-left`,width:`100%`,maxHeight:`100%`,margin:0}})}function h(t={}){return function(r){let i=t.env??process.env,o=new e,c=t.metricsSource??n({env:i}),l,u;f({...t,metrics:o,onDiagnostic:e=>{u=e,t.onDiagnostic?t.onDiagnostic(e):i.AGENT_OTEL_DIAGNOSTICS===`stderr`&&process.emitWarning(e)},onSinkStatus:e=>{l=e,t.onSinkStatus?.(e)}})(r),p(r,{source:t.leaderSource}),r.registerCommand(a,{description:`Show session-local log metrics`,handler:async(e,t)=>{await m(t,()=>({disabled:s(i.AGENT_TELEMETRY_DISABLED)||s(i.OTEL_SDK_DISABLED),snapshot:o.snapshot(),sink:l,transport:c.lastTransport(),lastDiagnostic:u}),c.query)}})}}const g=h();export{h as createDoomLogExtension,f as createPiTelemetryExtension,g as doomLogExtension,m as openLogMetricsOverlay,p as registerLogMetricsLeaderBinding};
2
2
  //# sourceMappingURL=extension.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension.mjs","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["/**\n * Pi telemetry wiring for the Doom harness.\n *\n * This extension deliberately emits metadata-only records. Prompt, message,\n * tool payload, file path, diagnostic text, exception, and stack data never\n * cross the shared telemetry boundary.\n */\n\nimport { registerDoomLeaderContribution } from '@agimon-ai/doompi-extension-contracts/leader';\nimport { createDoomTelemetry, type DoomTelemetry, type DoomTelemetryOptions } from '@agimon-ai/doompi-telemetry';\nimport type { ExtensionAPI, ExtensionContext, TurnEndEvent } from '@earendil-works/pi-coding-agent';\nimport { LogMetricsAggregator, type LogMetricsRecorder } from '../../services/metrics.ts';\nimport { createMetricsSource, type MetricsQuery, type MetricsSource } from '../../services/metricsSource.ts';\nimport { LogMetricsOverlayComponent, type LogMetricsView, type SinkStatus } from '../../tui/metricsOverlay.ts';\n\nconst SERVICE_NAME = 'pi';\nconst PACKAGE_NAME = '@agimon-ai/doompi-log';\n/** Opt back into stderr diagnostics when debugging outside a live TUI. */\nconst DIAGNOSTICS_STDERR = 'stderr';\nconst LEADER_SOURCE = '@agimon-ai/doompi-log';\nconst LOG_METRICS_COMMAND = 'log-metrics';\nconst LOG_METRICS_DESCRIPTION = 'Show session-local log metrics';\nconst HELP_GROUP_ORDER = 70;\nconst NO_ENDPOINT = 'none';\nconst API_ERROR_STATUS = 400;\nconst FAILURE_STOP_REASONS = new Set(['error', 'aborted']);\n\ntype TelemetryFactory = NonNullable<DoomTelemetryOptions['telemetryFactory']>;\ntype TelemetryAttributes = Record<string, string | number | boolean>;\ntype RecordLevel = 'debug' | 'info' | 'warn' | 'error';\n\nexport interface PiTelemetryExtensionOptions {\n allowFileFallback?: boolean;\n /** Overrides the telemetry service identity. */\n serviceName?: string;\n /** Overrides the leader contribution owner. */\n leaderSource?: string;\n env?: NodeJS.ProcessEnv;\n telemetryFactory?: TelemetryFactory;\n /** Receives every sanitized record, whether or not a sink is live. */\n metrics?: LogMetricsRecorder;\n /** Called once the sink backend is resolved, so the overlay can report it. */\n onSinkStatus?: (status: SinkStatus | undefined) => void;\n /** Overrides the sink-history transport; injected in tests. */\n metricsSource?: MetricsSource;\n /** Receives telemetry lifecycle failures without writing into the TUI. */\n onDiagnostic?: (message: string) => void;\n}\n\nfunction isEnabled(value: string | undefined): boolean {\n return value === '1' || value?.toLowerCase() === 'true' || value?.toLowerCase() === 'yes';\n}\n\nfunction contextAttributes(ctx: ExtensionContext): TelemetryAttributes {\n const attributes: TelemetryAttributes = {\n 'pi.mode': ctx.mode,\n 'pi.session.id': ctx.sessionManager.getSessionId(),\n };\n if (ctx.thinkingLevel) attributes['pi.thinking_level'] = ctx.thinkingLevel;\n if (ctx.model) {\n attributes['gen_ai.provider.name'] = ctx.model.provider;\n attributes['gen_ai.request.model'] = ctx.model.id;\n }\n return attributes;\n}\n\nfunction usageAttributes(message: TurnEndEvent['message']): TelemetryAttributes | undefined {\n if (message.role !== 'assistant') return undefined;\n const attributes: TelemetryAttributes = {\n 'gen_ai.response.model': message.responseModel ?? message.model,\n 'gen_ai.response.finish_reasons': message.stopReason,\n 'gen_ai.usage.input_tokens': message.usage.input,\n 'gen_ai.usage.output_tokens': message.usage.output,\n 'gen_ai.usage.cache_read_tokens': message.usage.cacheRead,\n 'gen_ai.usage.cache_write_tokens': message.usage.cacheWrite,\n 'gen_ai.usage.total_tokens': message.usage.totalTokens,\n 'gen_ai.usage.cost': message.usage.cost.total,\n };\n if (message.usage.reasoning !== undefined) attributes['gen_ai.usage.reasoning_tokens'] = message.usage.reasoning;\n return attributes;\n}\n\nfunction failureAttributes(message: TurnEndEvent['message']): TelemetryAttributes {\n if (message.role !== 'assistant') return { 'error.type': 'AgentError', outcome: 'error' };\n const aborted = message.stopReason === 'aborted';\n return {\n 'error.type': 'ProviderError',\n 'error.code': message.stopReason,\n outcome: aborted ? 'aborted' : 'error',\n };\n}\n\nfunction statusFromTelemetry(status: ReturnType<DoomTelemetry['status']>): SinkStatus {\n return {\n service: status.serviceName,\n backend: status.backend,\n endpoint: status.endpoint ?? NO_ENDPOINT,\n endpointSource: status.endpointSource,\n traces: status.traces,\n redaction: true,\n fileFallback: status.fileFallback,\n };\n}\n\nexport function createPiTelemetryExtension(options: PiTelemetryExtensionOptions = {}) {\n return function registerPiTelemetry(pi: ExtensionAPI): void {\n const env = options.env ?? process.env;\n const metrics = options.metrics;\n const toolStartedAt = new Map<string, number>();\n let agentStartedAt: number | undefined;\n let telemetry: DoomTelemetry | undefined;\n\n const emit = async (level: RecordLevel, name: string, attributes: TelemetryAttributes): Promise<void> => {\n if (!telemetry) return;\n if (level === 'debug') await telemetry.recordDebug(name, attributes);\n else if (level === 'warn') await telemetry.recordWarning(name, undefined, attributes);\n else if (level === 'error') await telemetry.recordError(name, undefined, attributes);\n else await telemetry.recordEvent(name, attributes);\n };\n\n const getTelemetry = (ctx: ExtensionContext): DoomTelemetry => {\n telemetry ??= createDoomTelemetry({\n serviceName: options.serviceName ?? SERVICE_NAME,\n packageName: PACKAGE_NAME,\n cwd: ctx.cwd,\n env,\n allowFileFallback: options.allowFileFallback,\n telemetryFactory: options.telemetryFactory,\n warn: options.onDiagnostic,\n enableLogs: true,\n enableTraces: env.AGENT_OTEL_TRACES === undefined || isEnabled(env.AGENT_OTEL_TRACES),\n onRecord: (record) => metrics?.record(record.event, record.attributes),\n onStatus: (status) => options.onSinkStatus?.(statusFromTelemetry(status)),\n });\n options.onSinkStatus?.(statusFromTelemetry(telemetry.status()));\n return telemetry;\n };\n\n pi.on('session_start', async (event, ctx) => {\n getTelemetry(ctx);\n await emit('info', 'pi.session.started', {\n ...contextAttributes(ctx),\n 'pi.session.reason': event.reason,\n 'pi.session.previous': event.previousSessionFile !== undefined,\n });\n });\n\n pi.on('before_agent_start', async (event, ctx) => {\n getTelemetry(ctx);\n await emit('info', 'pi.user_prompt', {\n ...contextAttributes(ctx),\n 'pi.user_message.length': event.prompt.length,\n 'pi.user_message.image_count': event.images?.length ?? 0,\n });\n });\n\n pi.on('agent_start', async (_event, ctx) => {\n agentStartedAt = Date.now();\n getTelemetry(ctx);\n await emit('info', 'pi.agent.started', contextAttributes(ctx));\n });\n\n pi.on('turn_start', async (event, ctx) => {\n getTelemetry(ctx);\n await emit('debug', 'pi.turn.started', {\n ...contextAttributes(ctx),\n 'pi.turn.index': event.turnIndex,\n });\n });\n\n pi.on('turn_end', async (event, ctx) => {\n getTelemetry(ctx);\n const usage = usageAttributes(event.message);\n await emit('info', 'pi.turn.finished', {\n ...contextAttributes(ctx),\n 'pi.turn.index': event.turnIndex,\n 'pi.tool_result.count': event.toolResults.length,\n ...usage,\n });\n if (event.message.role === 'assistant' && FAILURE_STOP_REASONS.has(event.message.stopReason)) {\n await emit(event.message.stopReason === 'aborted' ? 'warn' : 'error', 'pi.turn.failed', {\n ...contextAttributes(ctx),\n 'pi.turn.index': event.turnIndex,\n ...failureAttributes(event.message),\n ...usage,\n });\n }\n if (!usage) return;\n for (const result of event.toolResults) {\n await emit('debug', 'pi.tool_token_sample', {\n ...contextAttributes(ctx),\n ...usage,\n 'tool.name': result.toolName,\n token_attribution: 'toolCallTurn',\n });\n }\n });\n\n pi.on('tool_execution_start', async (event, ctx) => {\n toolStartedAt.set(event.toolCallId, Date.now());\n getTelemetry(ctx);\n await emit('debug', 'pi.tool_call', {\n ...contextAttributes(ctx),\n 'tool.name': event.toolName,\n 'tool.call.id': event.toolCallId,\n });\n });\n\n pi.on('tool_execution_end', async (event, ctx) => {\n const startedAt = toolStartedAt.get(event.toolCallId);\n toolStartedAt.delete(event.toolCallId);\n getTelemetry(ctx);\n await emit('info', 'pi.tool_result', {\n ...contextAttributes(ctx),\n success: !event.isError,\n 'tool.name': event.toolName,\n 'tool.call.id': event.toolCallId,\n 'tool.result.error': event.isError,\n ...(startedAt === undefined ? {} : { 'tool.duration_ms': Date.now() - startedAt }),\n });\n });\n\n pi.on('after_provider_response', async (event, ctx) => {\n getTelemetry(ctx);\n const attributes = {\n ...contextAttributes(ctx),\n 'http.response.status_code': event.status,\n };\n if (event.status >= API_ERROR_STATUS) await emit('error', 'pi.api_error', attributes);\n else await emit('debug', 'pi.api_response', attributes);\n });\n\n pi.on('model_select', async (event, ctx) => {\n getTelemetry(ctx);\n await emit('info', 'pi.model.selected', {\n ...contextAttributes(ctx),\n 'pi.model.source': event.source,\n 'gen_ai.provider.name': event.model.provider,\n 'gen_ai.request.model': event.model.id,\n });\n });\n\n pi.on('agent_end', async (event, ctx) => {\n getTelemetry(ctx);\n await emit('info', 'pi.agent.finished', {\n ...contextAttributes(ctx),\n 'pi.message.count': event.messages.length,\n ...(agentStartedAt === undefined ? {} : { 'pi.agent.duration_ms': Date.now() - agentStartedAt }),\n });\n agentStartedAt = undefined;\n await telemetry?.flush();\n });\n\n pi.on('agent_settled', async (_event, ctx) => {\n getTelemetry(ctx);\n await emit('debug', 'pi.agent.settled', contextAttributes(ctx));\n });\n\n pi.on('session_shutdown', async (event, ctx) => {\n getTelemetry(ctx);\n await emit('info', 'pi.session.finished', {\n ...contextAttributes(ctx),\n 'pi.session.reason': event.reason,\n });\n await telemetry?.shutdown();\n });\n };\n}\n\nexport function registerLogMetricsLeaderBinding(\n pi: Pick<ExtensionAPI, 'events' | 'on'>,\n options: { source?: string } = {},\n): () => void {\n return registerDoomLeaderContribution(pi, {\n source: options.source ?? LEADER_SOURCE,\n bindings: [\n {\n id: 'log.metrics',\n path: [\n { key: 'h', label: 'help', order: HELP_GROUP_ORDER },\n { key: 'l', label: 'logs', detail: 'telemetry' },\n ],\n command: { name: LOG_METRICS_COMMAND },\n },\n ],\n });\n}\n\nexport async function openLogMetricsOverlay(\n ctx: ExtensionContext,\n getView: () => LogMetricsView,\n query?: MetricsQuery,\n): Promise<void> {\n await ctx.ui.custom<undefined>(\n (tui, theme, _keybindings, done) => new LogMetricsOverlayComponent(tui, theme, getView, done, query),\n {\n overlay: true,\n overlayOptions: {\n anchor: 'top-left',\n width: '100%',\n maxHeight: '100%',\n margin: 0,\n },\n },\n );\n}\n\nexport function createDoomLogExtension(options: PiTelemetryExtensionOptions = {}) {\n return function registerDoomLog(pi: ExtensionAPI): void {\n const env = options.env ?? process.env;\n const metrics = new LogMetricsAggregator();\n const metricsSource = options.metricsSource ?? createMetricsSource({ env });\n let sink: SinkStatus | undefined;\n let lastDiagnostic: string | undefined;\n\n createPiTelemetryExtension({\n ...options,\n metrics,\n // Always supply a sink so doom-telemetry never falls back to\n // process.emitWarning, which writes raw stderr over the TUI frame.\n // Diagnostics surface in the Log Metrics overlay instead.\n onDiagnostic: (message) => {\n lastDiagnostic = message;\n if (options.onDiagnostic) options.onDiagnostic(message);\n else if (env.AGENT_OTEL_DIAGNOSTICS === DIAGNOSTICS_STDERR) process.emitWarning(message);\n },\n onSinkStatus: (status) => {\n sink = status;\n options.onSinkStatus?.(status);\n },\n })(pi);\n\n registerLogMetricsLeaderBinding(pi, { source: options.leaderSource });\n pi.registerCommand(LOG_METRICS_COMMAND, {\n description: LOG_METRICS_DESCRIPTION,\n handler: async (_args, ctx) => {\n await openLogMetricsOverlay(\n ctx,\n () => ({\n disabled: isEnabled(env.AGENT_TELEMETRY_DISABLED) || isEnabled(env.OTEL_SDK_DISABLED),\n snapshot: metrics.snapshot(),\n sink,\n transport: metricsSource.lastTransport(),\n lastDiagnostic,\n }),\n metricsSource.query,\n );\n },\n });\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"extension.mjs","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["/**\n * Pi telemetry wiring for the Doom harness.\n *\n * This extension deliberately emits metadata-only records. Prompt, message,\n * tool payload, file path, diagnostic text, exception, and stack data never\n * cross the shared telemetry boundary.\n */\n\nimport { registerDoomLeaderContribution } from '@agimon-ai/doompi-extension-contracts/leader';\nimport { createDoomTelemetry, type DoomTelemetry, type DoomTelemetryOptions } from '@agimon-ai/doompi-telemetry';\nimport type { ExtensionAPI, ExtensionContext, TurnEndEvent } from '@earendil-works/pi-coding-agent';\nimport { LogMetricsAggregator, type LogMetricsRecorder } from '../../services/metrics.ts';\nimport { LogMetricsOverlayComponent, type LogMetricsView, type SinkStatus } from '../../tui/logMetricsOverlay.ts';\nimport type { MetricsQuery, MetricsSource } from '../../types/metricsSource.ts';\nimport { createMetricsSource } from '../node/metricsSource.ts';\n\nconst SERVICE_NAME = 'pi';\nconst PACKAGE_NAME = '@agimon-ai/doompi-log';\n/** Opt back into stderr diagnostics when debugging outside a live TUI. */\nconst DIAGNOSTICS_STDERR = 'stderr';\nconst LEADER_SOURCE = '@agimon-ai/doompi-log';\nconst LOG_METRICS_COMMAND = 'log-metrics';\nconst LOG_METRICS_DESCRIPTION = 'Show session-local log metrics';\nconst HELP_GROUP_ORDER = 70;\nconst NO_ENDPOINT = 'none';\nconst API_ERROR_STATUS = 400;\nconst FAILURE_STOP_REASONS = new Set(['error', 'aborted']);\n\ntype TelemetryFactory = NonNullable<DoomTelemetryOptions['telemetryFactory']>;\ntype TelemetryAttributes = Record<string, string | number | boolean>;\ntype RecordLevel = 'debug' | 'info' | 'warn' | 'error';\n\nexport interface PiTelemetryExtensionOptions {\n allowFileFallback?: boolean;\n /** Overrides the telemetry service identity. */\n serviceName?: string;\n /** Overrides the leader contribution owner. */\n leaderSource?: string;\n env?: NodeJS.ProcessEnv;\n telemetryFactory?: TelemetryFactory;\n /** Receives every sanitized record, whether or not a sink is live. */\n metrics?: LogMetricsRecorder;\n /** Called once the sink backend is resolved, so the overlay can report it. */\n onSinkStatus?: (status: SinkStatus | undefined) => void;\n /** Overrides the sink-history transport; injected in tests. */\n metricsSource?: MetricsSource;\n /** Receives telemetry lifecycle failures without writing into the TUI. */\n onDiagnostic?: (message: string) => void;\n}\n\nfunction isEnabled(value: string | undefined): boolean {\n return value === '1' || value?.toLowerCase() === 'true' || value?.toLowerCase() === 'yes';\n}\n\nfunction contextAttributes(ctx: ExtensionContext): TelemetryAttributes {\n const attributes: TelemetryAttributes = {\n 'pi.mode': ctx.mode,\n 'pi.session.id': ctx.sessionManager.getSessionId(),\n };\n if (ctx.thinkingLevel) attributes['pi.thinking_level'] = ctx.thinkingLevel;\n if (ctx.model) {\n attributes['gen_ai.provider.name'] = ctx.model.provider;\n attributes['gen_ai.request.model'] = ctx.model.id;\n }\n return attributes;\n}\n\nfunction usageAttributes(message: TurnEndEvent['message']): TelemetryAttributes | undefined {\n if (message.role !== 'assistant') return undefined;\n const attributes: TelemetryAttributes = {\n 'gen_ai.response.model': message.responseModel ?? message.model,\n 'gen_ai.response.finish_reasons': message.stopReason,\n 'gen_ai.usage.input_tokens': message.usage.input,\n 'gen_ai.usage.output_tokens': message.usage.output,\n 'gen_ai.usage.cache_read_tokens': message.usage.cacheRead,\n 'gen_ai.usage.cache_write_tokens': message.usage.cacheWrite,\n 'gen_ai.usage.total_tokens': message.usage.totalTokens,\n 'gen_ai.usage.cost': message.usage.cost.total,\n };\n if (message.usage.reasoning !== undefined) attributes['gen_ai.usage.reasoning_tokens'] = message.usage.reasoning;\n return attributes;\n}\n\nfunction failureAttributes(message: TurnEndEvent['message']): TelemetryAttributes {\n if (message.role !== 'assistant') return { 'error.type': 'AgentError', outcome: 'error' };\n const aborted = message.stopReason === 'aborted';\n return {\n 'error.type': 'ProviderError',\n 'error.code': message.stopReason,\n outcome: aborted ? 'aborted' : 'error',\n };\n}\n\nfunction statusFromTelemetry(status: ReturnType<DoomTelemetry['status']>): SinkStatus {\n return {\n service: status.serviceName,\n backend: status.backend,\n endpoint: status.endpoint ?? NO_ENDPOINT,\n endpointSource: status.endpointSource,\n traces: status.traces,\n redaction: true,\n fileFallback: status.fileFallback,\n };\n}\n\nexport function createPiTelemetryExtension(options: PiTelemetryExtensionOptions = {}) {\n return function registerPiTelemetry(pi: ExtensionAPI): void {\n const env = options.env ?? process.env;\n const metrics = options.metrics;\n const toolStartedAt = new Map<string, number>();\n let agentStartedAt: number | undefined;\n let telemetry: DoomTelemetry | undefined;\n\n const emit = async (level: RecordLevel, name: string, attributes: TelemetryAttributes): Promise<void> => {\n if (!telemetry) return;\n if (level === 'debug') await telemetry.recordDebug(name, attributes);\n else if (level === 'warn') await telemetry.recordWarning(name, undefined, attributes);\n else if (level === 'error') await telemetry.recordError(name, undefined, attributes);\n else await telemetry.recordEvent(name, attributes);\n };\n\n const getTelemetry = (ctx: ExtensionContext): DoomTelemetry => {\n telemetry ??= createDoomTelemetry({\n serviceName: options.serviceName ?? SERVICE_NAME,\n packageName: PACKAGE_NAME,\n cwd: ctx.cwd,\n env,\n allowFileFallback: options.allowFileFallback,\n telemetryFactory: options.telemetryFactory,\n warn: options.onDiagnostic,\n enableLogs: true,\n enableTraces: env.AGENT_OTEL_TRACES === undefined || isEnabled(env.AGENT_OTEL_TRACES),\n onRecord: (record) => metrics?.record(record.event, record.attributes),\n onStatus: (status) => options.onSinkStatus?.(statusFromTelemetry(status)),\n });\n options.onSinkStatus?.(statusFromTelemetry(telemetry.status()));\n return telemetry;\n };\n\n pi.on('session_start', async (event, ctx) => {\n getTelemetry(ctx);\n await emit('info', 'pi.session.started', {\n ...contextAttributes(ctx),\n 'pi.session.reason': event.reason,\n 'pi.session.previous': event.previousSessionFile !== undefined,\n });\n });\n\n pi.on('before_agent_start', async (event, ctx) => {\n getTelemetry(ctx);\n await emit('info', 'pi.user_prompt', {\n ...contextAttributes(ctx),\n 'pi.user_message.length': event.prompt.length,\n 'pi.user_message.image_count': event.images?.length ?? 0,\n });\n });\n\n pi.on('agent_start', async (_event, ctx) => {\n agentStartedAt = Date.now();\n getTelemetry(ctx);\n await emit('info', 'pi.agent.started', contextAttributes(ctx));\n });\n\n pi.on('turn_start', async (event, ctx) => {\n getTelemetry(ctx);\n await emit('debug', 'pi.turn.started', {\n ...contextAttributes(ctx),\n 'pi.turn.index': event.turnIndex,\n });\n });\n\n pi.on('turn_end', async (event, ctx) => {\n getTelemetry(ctx);\n const usage = usageAttributes(event.message);\n await emit('info', 'pi.turn.finished', {\n ...contextAttributes(ctx),\n 'pi.turn.index': event.turnIndex,\n 'pi.tool_result.count': event.toolResults.length,\n ...usage,\n });\n if (event.message.role === 'assistant' && FAILURE_STOP_REASONS.has(event.message.stopReason)) {\n await emit(event.message.stopReason === 'aborted' ? 'warn' : 'error', 'pi.turn.failed', {\n ...contextAttributes(ctx),\n 'pi.turn.index': event.turnIndex,\n ...failureAttributes(event.message),\n ...usage,\n });\n }\n if (!usage) return;\n for (const result of event.toolResults) {\n await emit('debug', 'pi.tool_token_sample', {\n ...contextAttributes(ctx),\n ...usage,\n 'tool.name': result.toolName,\n token_attribution: 'toolCallTurn',\n });\n }\n });\n\n pi.on('tool_execution_start', async (event, ctx) => {\n toolStartedAt.set(event.toolCallId, Date.now());\n getTelemetry(ctx);\n await emit('debug', 'pi.tool_call', {\n ...contextAttributes(ctx),\n 'tool.name': event.toolName,\n 'tool.call.id': event.toolCallId,\n });\n });\n\n pi.on('tool_execution_end', async (event, ctx) => {\n const startedAt = toolStartedAt.get(event.toolCallId);\n toolStartedAt.delete(event.toolCallId);\n getTelemetry(ctx);\n await emit('info', 'pi.tool_result', {\n ...contextAttributes(ctx),\n success: !event.isError,\n 'tool.name': event.toolName,\n 'tool.call.id': event.toolCallId,\n 'tool.result.error': event.isError,\n ...(startedAt === undefined ? {} : { 'tool.duration_ms': Date.now() - startedAt }),\n });\n });\n\n pi.on('after_provider_response', async (event, ctx) => {\n getTelemetry(ctx);\n const attributes = {\n ...contextAttributes(ctx),\n 'http.response.status_code': event.status,\n };\n if (event.status >= API_ERROR_STATUS) await emit('error', 'pi.api_error', attributes);\n else await emit('debug', 'pi.api_response', attributes);\n });\n\n pi.on('model_select', async (event, ctx) => {\n getTelemetry(ctx);\n await emit('info', 'pi.model.selected', {\n ...contextAttributes(ctx),\n 'pi.model.source': event.source,\n 'gen_ai.provider.name': event.model.provider,\n 'gen_ai.request.model': event.model.id,\n });\n });\n\n pi.on('agent_end', async (event, ctx) => {\n getTelemetry(ctx);\n await emit('info', 'pi.agent.finished', {\n ...contextAttributes(ctx),\n 'pi.message.count': event.messages.length,\n ...(agentStartedAt === undefined ? {} : { 'pi.agent.duration_ms': Date.now() - agentStartedAt }),\n });\n agentStartedAt = undefined;\n await telemetry?.flush();\n });\n\n pi.on('agent_settled', async (_event, ctx) => {\n getTelemetry(ctx);\n await emit('debug', 'pi.agent.settled', contextAttributes(ctx));\n });\n\n pi.on('session_shutdown', async (event, ctx) => {\n getTelemetry(ctx);\n await emit('info', 'pi.session.finished', {\n ...contextAttributes(ctx),\n 'pi.session.reason': event.reason,\n });\n await telemetry?.shutdown();\n });\n };\n}\n\nexport function registerLogMetricsLeaderBinding(\n pi: Pick<ExtensionAPI, 'events' | 'on'>,\n options: { source?: string } = {},\n): () => void {\n return registerDoomLeaderContribution(pi, {\n source: options.source ?? LEADER_SOURCE,\n bindings: [\n {\n id: 'log.metrics',\n path: [\n { key: 'h', label: 'help', order: HELP_GROUP_ORDER },\n { key: 'l', label: 'logs', detail: 'telemetry' },\n ],\n command: { name: LOG_METRICS_COMMAND },\n },\n ],\n });\n}\n\nexport async function openLogMetricsOverlay(\n ctx: ExtensionContext,\n getView: () => LogMetricsView,\n query?: MetricsQuery,\n): Promise<void> {\n await ctx.ui.custom<undefined>(\n (tui, theme, _keybindings, done) => new LogMetricsOverlayComponent(tui, theme, getView, done, query),\n {\n overlay: true,\n overlayOptions: {\n anchor: 'top-left',\n width: '100%',\n maxHeight: '100%',\n margin: 0,\n },\n },\n );\n}\n\nexport function createDoomLogExtension(options: PiTelemetryExtensionOptions = {}) {\n return function registerDoomLog(pi: ExtensionAPI): void {\n const env = options.env ?? process.env;\n const metrics = new LogMetricsAggregator();\n const metricsSource = options.metricsSource ?? createMetricsSource({ env });\n let sink: SinkStatus | undefined;\n let lastDiagnostic: string | undefined;\n\n createPiTelemetryExtension({\n ...options,\n metrics,\n // Always supply a sink so doom-telemetry never falls back to\n // process.emitWarning, which writes raw stderr over the TUI frame.\n // Diagnostics surface in the Log Metrics overlay instead.\n onDiagnostic: (message) => {\n lastDiagnostic = message;\n if (options.onDiagnostic) options.onDiagnostic(message);\n else if (env.AGENT_OTEL_DIAGNOSTICS === DIAGNOSTICS_STDERR) process.emitWarning(message);\n },\n onSinkStatus: (status) => {\n sink = status;\n options.onSinkStatus?.(status);\n },\n })(pi);\n\n registerLogMetricsLeaderBinding(pi, { source: options.leaderSource });\n pi.registerCommand(LOG_METRICS_COMMAND, {\n description: LOG_METRICS_DESCRIPTION,\n handler: async (_args, ctx) => {\n await openLogMetricsOverlay(\n ctx,\n () => ({\n disabled: isEnabled(env.AGENT_TELEMETRY_DISABLED) || isEnabled(env.OTEL_SDK_DISABLED),\n snapshot: metrics.snapshot(),\n sink,\n transport: metricsSource.lastTransport(),\n lastDiagnostic,\n }),\n metricsSource.query,\n );\n },\n });\n };\n}\n\nexport const doomLogExtension = createDoomLogExtension();\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
1
  import { PiTelemetryExtensionOptions, createDoomLogExtension, createPiTelemetryExtension, openLogMetricsOverlay, registerLogMetricsLeaderBinding } from "./adapters/pi/extension.cjs";
2
- export { PiTelemetryExtensionOptions, createDoomLogExtension, createPiTelemetryExtension, openLogMetricsOverlay, registerLogMetricsLeaderBinding };
2
+ export { type PiTelemetryExtensionOptions, createDoomLogExtension, createPiTelemetryExtension, openLogMetricsOverlay, registerLogMetricsLeaderBinding };
@@ -1,2 +1,2 @@
1
1
  import { PiTelemetryExtensionOptions, createDoomLogExtension, createPiTelemetryExtension, openLogMetricsOverlay, registerLogMetricsLeaderBinding } from "./adapters/pi/extension.mjs";
2
- export { PiTelemetryExtensionOptions, createDoomLogExtension, createPiTelemetryExtension, openLogMetricsOverlay, registerLogMetricsLeaderBinding };
2
+ export { type PiTelemetryExtensionOptions, createDoomLogExtension, createPiTelemetryExtension, openLogMetricsOverlay, registerLogMetricsLeaderBinding };
@@ -1,2 +1 @@
1
- var e=require("../adapters/pi/extension.cjs").createDoomLogExtension();module.exports=e;
2
- //# sourceMappingURL=pi.cjs.map
1
+ const e=require("../adapters/pi/extension.cjs");module.exports=e.doomLogExtension;
@@ -1,4 +1,2 @@
1
- //#region src/extensions/pi.d.ts
2
- declare const _default: (pi: import("@earendil-works/pi-coding-agent").ExtensionAPI) => void;
3
- export = _default;
4
- //# sourceMappingURL=pi.d.cts.map
1
+ import { doomLogExtension } from "../adapters/pi/extension.cjs";
2
+ export = doomLogExtension;
@@ -1,5 +1,2 @@
1
- //#region src/extensions/pi.d.ts
2
- declare const _default: (pi: import("@earendil-works/pi-coding-agent").ExtensionAPI) => void;
3
- //#endregion
4
- export { _default as default };
5
- //# sourceMappingURL=pi.d.mts.map
1
+ import { doomLogExtension } from "../adapters/pi/extension.mjs";
2
+ export { doomLogExtension as default };
@@ -1,2 +1 @@
1
- import{createDoomLogExtension as e}from"../adapters/pi/extension.mjs";var t=e();export{t as default};
2
- //# sourceMappingURL=pi.mjs.map
1
+ import{doomLogExtension as e}from"../adapters/pi/extension.mjs";export{e as default};
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./services/metrics.cjs"),t=require("./tui/metricsOverlay.cjs"),n=require("./adapters/pi/extension.cjs");exports.API_ERROR_RECORD=e.API_ERROR_RECORD,exports.LogMetricsAggregator=e.LogMetricsAggregator,exports.LogMetricsOverlayComponent=t.LogMetricsOverlayComponent,exports.MAX_RETAINED_STATE_PER_TOOL=e.MAX_RETAINED_STATE_PER_TOOL,exports.TOOL_RESULT_RECORD=e.TOOL_RESULT_RECORD,exports.TURN_FINISHED_RECORD=e.TURN_FINISHED_RECORD,exports.createDoomLogExtension=n.createDoomLogExtension,exports.createPiTelemetryExtension=n.createPiTelemetryExtension,exports.openLogMetricsOverlay=n.openLogMetricsOverlay,exports.registerLogMetricsLeaderBinding=n.registerLogMetricsLeaderBinding;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./services/metrics.cjs"),t=require("./tui/logMetricsOverlay.cjs"),n=require("./adapters/pi/extension.cjs");exports.API_ERROR_RECORD=e.API_ERROR_RECORD,exports.LogMetricsAggregator=e.LogMetricsAggregator,exports.LogMetricsOverlayComponent=t.LogMetricsOverlayComponent,exports.MAX_RETAINED_STATE_PER_TOOL=e.MAX_RETAINED_STATE_PER_TOOL,exports.TOOL_RESULT_RECORD=e.TOOL_RESULT_RECORD,exports.TURN_FINISHED_RECORD=e.TURN_FINISHED_RECORD,exports.createDoomLogExtension=n.createDoomLogExtension,exports.createPiTelemetryExtension=n.createPiTelemetryExtension,exports.openLogMetricsOverlay=n.openLogMetricsOverlay,exports.registerLogMetricsLeaderBinding=n.registerLogMetricsLeaderBinding;
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
1
  import { API_ERROR_RECORD, LogMetricsAggregator, LogMetricsAggregatorOptions, LogMetricsError, LogMetricsEventCount, LogMetricsOperationDuration, LogMetricsRecorder, LogMetricsSnapshot, LogMetricsTokenTotals, LogMetricsToolLatency, MAX_RETAINED_STATE_PER_TOOL, TOOL_RESULT_RECORD, TURN_FINISHED_RECORD } from "./services/metrics.cjs";
2
- import { LogMetricsOverlayComponent, LogMetricsView, SinkStatus } from "./tui/metricsOverlay.cjs";
2
+ import { LogMetricsOverlayComponent, LogMetricsView, SinkStatus } from "./tui/logMetricsOverlay.cjs";
3
3
  import { PiTelemetryExtensionOptions, createDoomLogExtension, createPiTelemetryExtension, openLogMetricsOverlay, registerLogMetricsLeaderBinding } from "./adapters/pi/extension.cjs";
4
- export { API_ERROR_RECORD, LogMetricsAggregator, LogMetricsAggregatorOptions, LogMetricsError, LogMetricsEventCount, LogMetricsOperationDuration, LogMetricsOverlayComponent, LogMetricsRecorder, LogMetricsSnapshot, LogMetricsTokenTotals, LogMetricsToolLatency, LogMetricsView, MAX_RETAINED_STATE_PER_TOOL, type PiTelemetryExtensionOptions, SinkStatus, TOOL_RESULT_RECORD, TURN_FINISHED_RECORD, createDoomLogExtension, createPiTelemetryExtension, openLogMetricsOverlay, registerLogMetricsLeaderBinding };
4
+ export { API_ERROR_RECORD, LogMetricsAggregator, type LogMetricsAggregatorOptions, type LogMetricsError, type LogMetricsEventCount, type LogMetricsOperationDuration, LogMetricsOverlayComponent, type LogMetricsRecorder, type LogMetricsSnapshot, type LogMetricsTokenTotals, type LogMetricsToolLatency, type LogMetricsView, MAX_RETAINED_STATE_PER_TOOL, type PiTelemetryExtensionOptions, type SinkStatus, TOOL_RESULT_RECORD, TURN_FINISHED_RECORD, createDoomLogExtension, createPiTelemetryExtension, openLogMetricsOverlay, registerLogMetricsLeaderBinding };
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
1
  import { API_ERROR_RECORD, LogMetricsAggregator, LogMetricsAggregatorOptions, LogMetricsError, LogMetricsEventCount, LogMetricsOperationDuration, LogMetricsRecorder, LogMetricsSnapshot, LogMetricsTokenTotals, LogMetricsToolLatency, MAX_RETAINED_STATE_PER_TOOL, TOOL_RESULT_RECORD, TURN_FINISHED_RECORD } from "./services/metrics.mjs";
2
- import { LogMetricsOverlayComponent, LogMetricsView, SinkStatus } from "./tui/metricsOverlay.mjs";
2
+ import { LogMetricsOverlayComponent, LogMetricsView, SinkStatus } from "./tui/logMetricsOverlay.mjs";
3
3
  import { PiTelemetryExtensionOptions, createDoomLogExtension, createPiTelemetryExtension, openLogMetricsOverlay, registerLogMetricsLeaderBinding } from "./adapters/pi/extension.mjs";
4
- export { API_ERROR_RECORD, LogMetricsAggregator, LogMetricsAggregatorOptions, LogMetricsError, LogMetricsEventCount, LogMetricsOperationDuration, LogMetricsOverlayComponent, LogMetricsRecorder, LogMetricsSnapshot, LogMetricsTokenTotals, LogMetricsToolLatency, LogMetricsView, MAX_RETAINED_STATE_PER_TOOL, type PiTelemetryExtensionOptions, SinkStatus, TOOL_RESULT_RECORD, TURN_FINISHED_RECORD, createDoomLogExtension, createPiTelemetryExtension, openLogMetricsOverlay, registerLogMetricsLeaderBinding };
4
+ export { API_ERROR_RECORD, LogMetricsAggregator, type LogMetricsAggregatorOptions, type LogMetricsError, type LogMetricsEventCount, type LogMetricsOperationDuration, LogMetricsOverlayComponent, type LogMetricsRecorder, type LogMetricsSnapshot, type LogMetricsTokenTotals, type LogMetricsToolLatency, type LogMetricsView, MAX_RETAINED_STATE_PER_TOOL, type PiTelemetryExtensionOptions, type SinkStatus, TOOL_RESULT_RECORD, TURN_FINISHED_RECORD, createDoomLogExtension, createPiTelemetryExtension, openLogMetricsOverlay, registerLogMetricsLeaderBinding };
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{API_ERROR_RECORD as e,LogMetricsAggregator as t,MAX_RETAINED_STATE_PER_TOOL as n,TOOL_RESULT_RECORD as r,TURN_FINISHED_RECORD as i}from"./services/metrics.mjs";import{LogMetricsOverlayComponent as a}from"./tui/metricsOverlay.mjs";import{createDoomLogExtension as o,createPiTelemetryExtension as s,openLogMetricsOverlay as c,registerLogMetricsLeaderBinding as l}from"./adapters/pi/extension.mjs";export{e as API_ERROR_RECORD,t as LogMetricsAggregator,a as LogMetricsOverlayComponent,n as MAX_RETAINED_STATE_PER_TOOL,r as TOOL_RESULT_RECORD,i as TURN_FINISHED_RECORD,o as createDoomLogExtension,s as createPiTelemetryExtension,c as openLogMetricsOverlay,l as registerLogMetricsLeaderBinding};
1
+ import{API_ERROR_RECORD as e,LogMetricsAggregator as t,MAX_RETAINED_STATE_PER_TOOL as n,TOOL_RESULT_RECORD as r,TURN_FINISHED_RECORD as i}from"./services/metrics.mjs";import{LogMetricsOverlayComponent as a}from"./tui/logMetricsOverlay.mjs";import{createDoomLogExtension as o,createPiTelemetryExtension as s,openLogMetricsOverlay as c,registerLogMetricsLeaderBinding as l}from"./adapters/pi/extension.mjs";export{e as API_ERROR_RECORD,t as LogMetricsAggregator,a as LogMetricsOverlayComponent,n as MAX_RETAINED_STATE_PER_TOOL,r as TOOL_RESULT_RECORD,i as TURN_FINISHED_RECORD,o as createDoomLogExtension,s as createPiTelemetryExtension,c as openLogMetricsOverlay,l as registerLogMetricsLeaderBinding};
@@ -1,2 +1,2 @@
1
1
  import { API_ERROR_RECORD, LogMetricsAggregator, LogMetricsAggregatorOptions, LogMetricsError, LogMetricsEventCount, LogMetricsOperationDuration, LogMetricsRecorder, LogMetricsSnapshot, LogMetricsTokenTotals, LogMetricsToolLatency, MAX_RETAINED_STATE_PER_TOOL, TOOL_RESULT_RECORD, TURN_FINISHED_RECORD } from "./services/metrics.cjs";
2
- export { API_ERROR_RECORD, LogMetricsAggregator, LogMetricsAggregatorOptions, LogMetricsError, LogMetricsEventCount, LogMetricsOperationDuration, LogMetricsRecorder, LogMetricsSnapshot, LogMetricsTokenTotals, LogMetricsToolLatency, MAX_RETAINED_STATE_PER_TOOL, TOOL_RESULT_RECORD, TURN_FINISHED_RECORD };
2
+ export { API_ERROR_RECORD, LogMetricsAggregator, type LogMetricsAggregatorOptions, type LogMetricsError, type LogMetricsEventCount, type LogMetricsOperationDuration, type LogMetricsRecorder, type LogMetricsSnapshot, type LogMetricsTokenTotals, type LogMetricsToolLatency, MAX_RETAINED_STATE_PER_TOOL, TOOL_RESULT_RECORD, TURN_FINISHED_RECORD };
@@ -1,2 +1,2 @@
1
1
  import { API_ERROR_RECORD, LogMetricsAggregator, LogMetricsAggregatorOptions, LogMetricsError, LogMetricsEventCount, LogMetricsOperationDuration, LogMetricsRecorder, LogMetricsSnapshot, LogMetricsTokenTotals, LogMetricsToolLatency, MAX_RETAINED_STATE_PER_TOOL, TOOL_RESULT_RECORD, TURN_FINISHED_RECORD } from "./services/metrics.mjs";
2
- export { API_ERROR_RECORD, LogMetricsAggregator, LogMetricsAggregatorOptions, LogMetricsError, LogMetricsEventCount, LogMetricsOperationDuration, LogMetricsRecorder, LogMetricsSnapshot, LogMetricsTokenTotals, LogMetricsToolLatency, MAX_RETAINED_STATE_PER_TOOL, TOOL_RESULT_RECORD, TURN_FINISHED_RECORD };
2
+ export { API_ERROR_RECORD, LogMetricsAggregator, type LogMetricsAggregatorOptions, type LogMetricsError, type LogMetricsEventCount, type LogMetricsOperationDuration, type LogMetricsRecorder, type LogMetricsSnapshot, type LogMetricsTokenTotals, type LogMetricsToolLatency, MAX_RETAINED_STATE_PER_TOOL, TOOL_RESULT_RECORD, TURN_FINISHED_RECORD };
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./services/metricsSource.cjs");exports.createMetricsSource=e.createMetricsSource;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./adapters/node/metricsSource.cjs");exports.createMetricsSource=e.createMetricsSource;
@@ -1,2 +1,3 @@
1
- import { MetricsQuery, MetricsQueryParams, MetricsSource, MetricsSourceOptions, MetricsTransport, createMetricsSource } from "./services/metricsSource.cjs";
2
- export { MetricsQuery, MetricsQueryParams, MetricsSource, MetricsSourceOptions, MetricsTransport, createMetricsSource };
1
+ import { MetricsQuery, MetricsQueryParams, MetricsSource, MetricsTransport } from "./types/metricsSource.cjs";
2
+ import { MetricsSourceOptions, createMetricsSource } from "./adapters/node/metricsSource.cjs";
3
+ export { type MetricsQuery, type MetricsQueryParams, type MetricsSource, type MetricsSourceOptions, type MetricsTransport, createMetricsSource };
@@ -1,2 +1,3 @@
1
- import { MetricsQuery, MetricsQueryParams, MetricsSource, MetricsSourceOptions, MetricsTransport, createMetricsSource } from "./services/metricsSource.mjs";
2
- export { MetricsQuery, MetricsQueryParams, MetricsSource, MetricsSourceOptions, MetricsTransport, createMetricsSource };
1
+ import { MetricsQuery, MetricsQueryParams, MetricsSource, MetricsTransport } from "./types/metricsSource.mjs";
2
+ import { MetricsSourceOptions, createMetricsSource } from "./adapters/node/metricsSource.mjs";
3
+ export { type MetricsQuery, type MetricsQueryParams, type MetricsSource, type MetricsSourceOptions, type MetricsTransport, createMetricsSource };
@@ -1 +1 @@
1
- import{createMetricsSource as e}from"./services/metricsSource.mjs";export{e as createMetricsSource};
1
+ import{createMetricsSource as e}from"./adapters/node/metricsSource.mjs";export{e as createMetricsSource};