@yagni-app/code 1.0.6 → 1.0.8

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 (92) hide show
  1. package/README.md +91 -46
  2. package/dist/claudeCompat.d.ts +59 -0
  3. package/dist/claudeCompat.js +109 -2
  4. package/dist/claudePlugins.d.ts +45 -5
  5. package/dist/claudePlugins.js +129 -21
  6. package/dist/cli.js +16 -4
  7. package/dist/doctor.d.ts +21 -8
  8. package/dist/doctor.js +53 -28
  9. package/dist/extension/askUserQuestionTool.js +7 -2
  10. package/dist/extension/condensedTools.d.ts +12 -1
  11. package/dist/extension/condensedTools.js +17 -9
  12. package/dist/extension/config.d.ts +6 -0
  13. package/dist/extension/hooks.d.ts +3 -3
  14. package/dist/extension/hooks.js +30 -5
  15. package/dist/extension/index.d.ts +19 -0
  16. package/dist/extension/index.js +248 -43
  17. package/dist/extension/mcp/cliConfig.d.ts +1 -1
  18. package/dist/extension/mcp/cliConfig.js +1 -1
  19. package/dist/extension/mcp/config.d.ts +24 -2
  20. package/dist/extension/mcp/config.js +75 -3
  21. package/dist/extension/mcp/manager.d.ts +3 -1
  22. package/dist/extension/mcp/manager.js +2 -2
  23. package/dist/extension/mcp/panel.d.ts +0 -1
  24. package/dist/extension/mcp/panel.js +13 -3
  25. package/dist/extension/mcp/startup.js +8 -6
  26. package/dist/extension/permission/gate.d.ts +101 -2
  27. package/dist/extension/permission/gate.js +485 -42
  28. package/dist/extension/permissionRules/bashFileArgs.d.ts +39 -0
  29. package/dist/extension/permissionRules/bashFileArgs.js +236 -0
  30. package/dist/extension/permissionRules/engine.d.ts +50 -0
  31. package/dist/extension/permissionRules/engine.js +238 -0
  32. package/dist/extension/permissionRules/loadConfig.d.ts +64 -0
  33. package/dist/extension/permissionRules/loadConfig.js +105 -0
  34. package/dist/extension/permissionRules/parser.d.ts +38 -0
  35. package/dist/extension/permissionRules/parser.js +136 -0
  36. package/dist/extension/permissionRules/pathRules.d.ts +60 -0
  37. package/dist/extension/permissionRules/pathRules.js +122 -0
  38. package/dist/extension/permissionRules/shellRules.d.ts +52 -0
  39. package/dist/extension/permissionRules/shellRules.js +221 -0
  40. package/dist/extension/pipeline/invocation.d.ts +3 -6
  41. package/dist/extension/pipeline/invocation.js +3 -6
  42. package/dist/extension/pipeline/runner.d.ts +0 -1
  43. package/dist/extension/pipeline/runner.js +6 -14
  44. package/dist/extension/plugins/inventory.d.ts +88 -0
  45. package/dist/extension/plugins/inventory.js +144 -0
  46. package/dist/extension/plugins/panel.d.ts +45 -0
  47. package/dist/extension/plugins/panel.js +293 -0
  48. package/dist/extension/sandbox/bash.d.ts +99 -0
  49. package/dist/extension/sandbox/bash.js +190 -0
  50. package/dist/extension/sandbox/config.d.ts +115 -0
  51. package/dist/extension/sandbox/config.js +388 -0
  52. package/dist/extension/sandbox/manager.d.ts +108 -0
  53. package/dist/extension/sandbox/manager.js +243 -0
  54. package/dist/extension/sandbox/panel.d.ts +111 -0
  55. package/dist/extension/sandbox/panel.js +342 -0
  56. package/dist/extension/sandbox/session.d.ts +85 -0
  57. package/dist/extension/sandbox/session.js +829 -0
  58. package/dist/extension/settingsFiles.d.ts +50 -0
  59. package/dist/extension/settingsFiles.js +206 -0
  60. package/dist/extension/telemetry/attrs.d.ts +96 -0
  61. package/dist/extension/telemetry/attrs.js +149 -0
  62. package/dist/extension/telemetry/config.d.ts +103 -0
  63. package/dist/extension/telemetry/config.js +193 -0
  64. package/dist/extension/telemetry/index.d.ts +7 -0
  65. package/dist/extension/telemetry/index.js +7 -0
  66. package/dist/extension/telemetry/probe.d.ts +29 -0
  67. package/dist/extension/telemetry/probe.js +122 -0
  68. package/dist/extension/telemetry/register.d.ts +47 -0
  69. package/dist/extension/telemetry/register.js +207 -0
  70. package/dist/extension/telemetry/sdk.d.ts +63 -0
  71. package/dist/extension/telemetry/sdk.js +207 -0
  72. package/dist/extension/telemetry/tracker.d.ts +131 -0
  73. package/dist/extension/telemetry/tracker.js +551 -0
  74. package/dist/extension/vendor/IGNORE-LICENSE-MIT +21 -0
  75. package/dist/extension/vendor/ignore.d.ts +86 -0
  76. package/dist/extension/vendor/ignore.js +788 -0
  77. package/dist/goHeadless.d.ts +1 -1
  78. package/dist/goHeadless.js +2 -2
  79. package/dist/launch.d.ts +4 -3
  80. package/dist/launch.js +7 -4
  81. package/dist/mcpCommand.d.ts +10 -1
  82. package/dist/mcpCommand.js +42 -10
  83. package/dist/otel.d.ts +67 -90
  84. package/dist/otel.js +152 -195
  85. package/dist/paths.d.ts +13 -0
  86. package/dist/paths.js +18 -0
  87. package/dist/pluginCommand.d.ts +43 -0
  88. package/dist/pluginCommand.js +499 -0
  89. package/dist/pluginStore.d.ts +170 -0
  90. package/dist/pluginStore.js +554 -0
  91. package/dist/upgrade.js +10 -1
  92. package/package.json +19 -3
@@ -0,0 +1,63 @@
1
+ /**
2
+ * OpenTelemetry SDK bootstrap for one YAGNI Code process: a tracer, meter,
3
+ * and logger provider, each with the OTLP exporter the config picked
4
+ * (gRPC, http/protobuf, or http/json), plus a diag hook that turns export
5
+ * failures into ONE in-session notice instead of silence.
6
+ *
7
+ * Deliberately built from the signal SDKs (`sdk-trace`, `sdk-metrics`,
8
+ * `sdk-logs`) rather than `sdk-node`: no auto-instrumentation, no Prometheus
9
+ * server, no propagators — this is a client-only process that pushes its own
10
+ * spans. Providers are process-global (the OTel API allows one of each), so
11
+ * the extension initializes once per process even though pi fires
12
+ * session_start again on /new, /resume, and /fork.
13
+ *
14
+ * Everything is fail-soft. Telemetry must never block a launch or a prompt:
15
+ * a bad exporter config degrades to "not exporting", reported through the
16
+ * status callback, never a throw into pi.
17
+ */
18
+ import { type Resource } from "@opentelemetry/resources";
19
+ import { LoggerProvider, type LogRecordExporter } from "@opentelemetry/sdk-logs";
20
+ import { MeterProvider, type PushMetricExporter } from "@opentelemetry/sdk-metrics";
21
+ import { TracerProvider, type SpanExporter } from "@opentelemetry/sdk-trace";
22
+ import type { SignalConfig, TelemetryConfig } from "./config.js";
23
+ export interface TelemetryExporters {
24
+ traces?: SpanExporter;
25
+ metrics?: PushMetricExporter;
26
+ logs?: LogRecordExporter;
27
+ }
28
+ export interface TelemetrySdkOptions {
29
+ /** Injected exporters (tests use the SDKs' in-memory ones). */
30
+ exporters?: TelemetryExporters;
31
+ /** Simple (synchronous) processors instead of batching — tests + the doctor probe. */
32
+ simpleProcessors?: boolean;
33
+ /** Called on the first export failure with a one-line, human-readable reason. */
34
+ onExportError?: (message: string) => void;
35
+ }
36
+ export interface TelemetrySdk {
37
+ tracerProvider: TracerProvider;
38
+ meterProvider: MeterProvider;
39
+ loggerProvider: LoggerProvider;
40
+ resource: Resource;
41
+ /** Flush every processor (bounded), then shut the providers down. */
42
+ shutdown(): Promise<void>;
43
+ /** Flush without shutting down (used between /go stages). */
44
+ forceFlush(): Promise<void>;
45
+ }
46
+ /** Build the trace exporter for a signal config. */
47
+ export declare function makeTraceExporter(cfg: SignalConfig): SpanExporter;
48
+ export declare function makeMetricExporter(cfg: SignalConfig, temporality: TelemetryConfig["metricsTemporality"]): PushMetricExporter;
49
+ export declare function makeLogExporter(cfg: SignalConfig): LogRecordExporter;
50
+ /**
51
+ * Create and register the providers. Returns null (and reports) when the
52
+ * config produced no exporter — never throws.
53
+ */
54
+ export declare function createTelemetrySdk(config: TelemetryConfig, opts?: TelemetrySdkOptions): TelemetrySdk;
55
+ /**
56
+ * Shutdown/flush bound. A blackholing collector (a corp collector with the
57
+ * VPN down) must not hold quit for long: the batch processors already flush
58
+ * every few seconds, so at most one interval of records is at risk.
59
+ */
60
+ export declare const FLUSH_TIMEOUT_MS = 1500;
61
+ /** Let a timeout never keep the process alive on its own (Node timers only). */
62
+ export declare function unrefTimer(timer: unknown): void;
63
+ //# sourceMappingURL=sdk.d.ts.map
@@ -0,0 +1,207 @@
1
+ /**
2
+ * OpenTelemetry SDK bootstrap for one YAGNI Code process: a tracer, meter,
3
+ * and logger provider, each with the OTLP exporter the config picked
4
+ * (gRPC, http/protobuf, or http/json), plus a diag hook that turns export
5
+ * failures into ONE in-session notice instead of silence.
6
+ *
7
+ * Deliberately built from the signal SDKs (`sdk-trace`, `sdk-metrics`,
8
+ * `sdk-logs`) rather than `sdk-node`: no auto-instrumentation, no Prometheus
9
+ * server, no propagators — this is a client-only process that pushes its own
10
+ * spans. Providers are process-global (the OTel API allows one of each), so
11
+ * the extension initializes once per process even though pi fires
12
+ * session_start again on /new, /resume, and /fork.
13
+ *
14
+ * Everything is fail-soft. Telemetry must never block a launch or a prompt:
15
+ * a bad exporter config degrades to "not exporting", reported through the
16
+ * status callback, never a throw into pi.
17
+ */
18
+ import { Metadata } from "@grpc/grpc-js";
19
+ import { diag, DiagLogLevel, metrics, trace } from "@opentelemetry/api";
20
+ import { logs } from "@opentelemetry/api-logs";
21
+ import { OTLPLogExporter as LogGrpcExporter } from "@opentelemetry/exporter-logs-otlp-grpc";
22
+ import { OTLPLogExporter as LogHttpExporter } from "@opentelemetry/exporter-logs-otlp-http";
23
+ import { OTLPLogExporter as LogProtoExporter } from "@opentelemetry/exporter-logs-otlp-proto";
24
+ import { OTLPMetricExporter as MetricGrpcExporter } from "@opentelemetry/exporter-metrics-otlp-grpc";
25
+ import { AggregationTemporalityPreference, OTLPMetricExporter as MetricHttpExporter, } from "@opentelemetry/exporter-metrics-otlp-http";
26
+ import { OTLPMetricExporter as MetricProtoExporter } from "@opentelemetry/exporter-metrics-otlp-proto";
27
+ import { OTLPTraceExporter as TraceGrpcExporter } from "@opentelemetry/exporter-trace-otlp-grpc";
28
+ import { OTLPTraceExporter as TraceHttpExporter } from "@opentelemetry/exporter-trace-otlp-http";
29
+ import { OTLPTraceExporter as TraceProtoExporter } from "@opentelemetry/exporter-trace-otlp-proto";
30
+ import { resourceFromAttributes } from "@opentelemetry/resources";
31
+ import { BatchLogRecordProcessor, LoggerProvider, SimpleLogRecordProcessor, } from "@opentelemetry/sdk-logs";
32
+ import { MeterProvider, PeriodicExportingMetricReader, } from "@opentelemetry/sdk-metrics";
33
+ import { BatchSpanProcessor, SimpleSpanProcessor, TracerProvider, } from "@opentelemetry/sdk-trace";
34
+ import { logEvent } from "../errorSink.js";
35
+ /**
36
+ * gRPC exporters take headers as grpc `Metadata`, not a record. Built from the
37
+ * resolved config rather than left to the exporter's own `process.env` read,
38
+ * so the doctor probe (which runs in-process with a synthetic env) and a
39
+ * session see the same headers.
40
+ */
41
+ function toMetadata(headers) {
42
+ const md = new Metadata();
43
+ for (const [k, v] of Object.entries(headers))
44
+ md.set(k, v);
45
+ return md;
46
+ }
47
+ /** Build the trace exporter for a signal config. */
48
+ export function makeTraceExporter(cfg) {
49
+ return pick(cfg.protocol, {
50
+ grpc: () => new TraceGrpcExporter({ url: cfg.url, metadata: toMetadata(cfg.headers) }),
51
+ proto: () => new TraceProtoExporter({ url: cfg.url, headers: cfg.headers }),
52
+ json: () => new TraceHttpExporter({ url: cfg.url, headers: cfg.headers }),
53
+ });
54
+ }
55
+ export function makeMetricExporter(cfg, temporality) {
56
+ const temporalityPreference = temporality === "cumulative" ? AggregationTemporalityPreference.CUMULATIVE : AggregationTemporalityPreference.DELTA;
57
+ return pick(cfg.protocol, {
58
+ grpc: () => new MetricGrpcExporter({ url: cfg.url, metadata: toMetadata(cfg.headers), temporalityPreference }),
59
+ proto: () => new MetricProtoExporter({ url: cfg.url, headers: cfg.headers, temporalityPreference }),
60
+ json: () => new MetricHttpExporter({ url: cfg.url, headers: cfg.headers, temporalityPreference }),
61
+ });
62
+ }
63
+ export function makeLogExporter(cfg) {
64
+ return pick(cfg.protocol, {
65
+ grpc: () => new LogGrpcExporter({ url: cfg.url, metadata: toMetadata(cfg.headers) }),
66
+ proto: () => new LogProtoExporter({ url: cfg.url, headers: cfg.headers }),
67
+ json: () => new LogHttpExporter({ url: cfg.url, headers: cfg.headers }),
68
+ });
69
+ }
70
+ function pick(protocol, ctors) {
71
+ if (protocol === "http/protobuf")
72
+ return ctors.proto();
73
+ if (protocol === "http/json")
74
+ return ctors.json();
75
+ return ctors.grpc();
76
+ }
77
+ /**
78
+ * A diag logger for exporter failures. OTel routes them — a 403 from a bad
79
+ * API key, ECONNREFUSED, a 404 on the wrong path — through `diag.error` via
80
+ * the global error handler, so this is the only place they surface. The
81
+ * FIRST one is forwarded to the session as a notice (one, never a stream);
82
+ * EVERY one is written to the local error sink (~/.yagni-code error log),
83
+ * so a later "why is nothing in Datadog" investigation has the full trail.
84
+ */
85
+ function makeDiagLogger(onExportError) {
86
+ let reported = false;
87
+ const noop = () => { };
88
+ return {
89
+ verbose: noop,
90
+ debug: noop,
91
+ info: noop,
92
+ warn: noop,
93
+ error: (message, ...args) => {
94
+ const text = [message, ...args]
95
+ .map((a) => (a instanceof Error ? a.message : typeof a === "string" ? a : safeJson(a)))
96
+ .filter(Boolean)
97
+ .join(" ")
98
+ .slice(0, 500);
99
+ logEvent({ source: "telemetry", level: "warn", event: "export_error", fields: { error: text } });
100
+ if (reported || !onExportError)
101
+ return;
102
+ reported = true;
103
+ try {
104
+ onExportError(text);
105
+ }
106
+ catch {
107
+ // A failing notice must not take the session down.
108
+ }
109
+ },
110
+ };
111
+ }
112
+ function safeJson(v) {
113
+ try {
114
+ return JSON.stringify(v) ?? "";
115
+ }
116
+ catch {
117
+ return String(v);
118
+ }
119
+ }
120
+ function buildResource(config) {
121
+ return resourceFromAttributes({
122
+ ...config.resourceAttributes,
123
+ "service.name": config.serviceName,
124
+ ...(config.serviceVersion ? { "service.version": config.serviceVersion } : {}),
125
+ });
126
+ }
127
+ /**
128
+ * Create and register the providers. Returns null (and reports) when the
129
+ * config produced no exporter — never throws.
130
+ */
131
+ export function createTelemetrySdk(config, opts = {}) {
132
+ diag.setLogger(makeDiagLogger(opts.onExportError), { logLevel: DiagLogLevel.ERROR, suppressOverrideMessage: true });
133
+ const resource = buildResource(config);
134
+ const traceExporter = config.traces.enabled ? (opts.exporters?.traces ?? makeTraceExporter(config.traces)) : undefined;
135
+ const metricExporter = config.metrics.enabled
136
+ ? (opts.exporters?.metrics ?? makeMetricExporter(config.metrics, config.metricsTemporality))
137
+ : undefined;
138
+ const logExporter = config.logs.enabled ? (opts.exporters?.logs ?? makeLogExporter(config.logs)) : undefined;
139
+ const tracerProvider = new TracerProvider({
140
+ resource,
141
+ spanProcessors: traceExporter
142
+ ? [
143
+ opts.simpleProcessors
144
+ ? new SimpleSpanProcessor({ exporter: traceExporter })
145
+ : new BatchSpanProcessor({ exporter: traceExporter, scheduledDelayMillis: config.traces.exportIntervalMs }),
146
+ ]
147
+ : [],
148
+ });
149
+ const meterProvider = new MeterProvider({
150
+ resource,
151
+ readers: metricExporter
152
+ ? [
153
+ new PeriodicExportingMetricReader({
154
+ exporter: metricExporter,
155
+ exportIntervalMillis: config.metrics.exportIntervalMs,
156
+ }),
157
+ ]
158
+ : [],
159
+ });
160
+ const loggerProvider = new LoggerProvider({
161
+ resource,
162
+ processors: logExporter
163
+ ? [
164
+ opts.simpleProcessors
165
+ ? new SimpleLogRecordProcessor({ exporter: logExporter })
166
+ : new BatchLogRecordProcessor({ exporter: logExporter, scheduledDelayMillis: config.logs.exportIntervalMs }),
167
+ ]
168
+ : [],
169
+ });
170
+ // Register globally so any OTel-aware code in the process (an MCP client,
171
+ // a future hook) parents into the same providers. The API refuses a second
172
+ // registration and returns false; that is fine — a re-init keeps the first.
173
+ trace.setGlobalTracerProvider(tracerProvider);
174
+ metrics.setGlobalMeterProvider(meterProvider);
175
+ logs.setGlobalLoggerProvider(loggerProvider);
176
+ const bounded = (p, ms) => Promise.race([p, new Promise((resolve) => unrefTimer(setTimeout(resolve, ms)))]);
177
+ return {
178
+ tracerProvider,
179
+ meterProvider,
180
+ loggerProvider,
181
+ resource,
182
+ async forceFlush() {
183
+ await bounded(Promise.allSettled([tracerProvider.forceFlush(), meterProvider.forceFlush(), loggerProvider.forceFlush()]), FLUSH_TIMEOUT_MS);
184
+ },
185
+ async shutdown() {
186
+ // Unregister the globals FIRST, synchronously: a session that replaces
187
+ // this one (/new, /resume) can then register its own providers without
188
+ // waiting on a collector that may be blackholing the final flush.
189
+ trace.disable();
190
+ metrics.disable();
191
+ logs.disable();
192
+ diag.disable();
193
+ await bounded(Promise.allSettled([tracerProvider.shutdown(), meterProvider.shutdown(), loggerProvider.shutdown()]), FLUSH_TIMEOUT_MS);
194
+ },
195
+ };
196
+ }
197
+ /**
198
+ * Shutdown/flush bound. A blackholing collector (a corp collector with the
199
+ * VPN down) must not hold quit for long: the batch processors already flush
200
+ * every few seconds, so at most one interval of records is at risk.
201
+ */
202
+ export const FLUSH_TIMEOUT_MS = 1_500;
203
+ /** Let a timeout never keep the process alive on its own (Node timers only). */
204
+ export function unrefTimer(timer) {
205
+ timer?.unref?.();
206
+ }
207
+ //# sourceMappingURL=sdk.js.map
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Session telemetry tracker: turns pi's lifecycle into spans, metrics, and
3
+ * log events. Pure with respect to pi — `register.ts` feeds it events, tests
4
+ * feed it directly — and it only ever talks to the OTel API (tracer, meter,
5
+ * logger), never to exporters.
6
+ *
7
+ * Shape (Claude Code parity, prefix `yagni_code`):
8
+ *
9
+ * spans yagni_code.interaction ─┬─ yagni_code.turn ─┬─ yagni_code.llm_request
10
+ * │ └─ yagni_code.tool
11
+ * metrics session.count, token.usage, cost.usage, lines_of_code.count,
12
+ * commit.count, pull_request.count, code_edit_tool.decision,
13
+ * active_time.total
14
+ * events user_prompt, assistant_response, api_request, api_error,
15
+ * tool_result, tool_decision, permission_mode_changed
16
+ *
17
+ * Metadata only. Prompt text, model output, tool arguments, and tool results
18
+ * never become attributes — only their lengths.
19
+ */
20
+ import { type Attributes, type Meter, type Tracer } from "@opentelemetry/api";
21
+ import { type Logger } from "@opentelemetry/api-logs";
22
+ import { type Decision, type DecisionSource } from "./attrs.js";
23
+ import type { TelemetryConfig } from "./config.js";
24
+ /** pi's assistant-message usage block (loose: providers differ in what they fill). */
25
+ export interface UsageLike {
26
+ input?: number;
27
+ output?: number;
28
+ cacheRead?: number;
29
+ cacheWrite?: number;
30
+ cost?: number | {
31
+ total?: number;
32
+ };
33
+ }
34
+ export interface AssistantMessageLike {
35
+ model?: string;
36
+ responseModel?: string;
37
+ responseId?: string;
38
+ usage?: UsageLike;
39
+ stopReason?: string;
40
+ errorMessage?: string;
41
+ content?: unknown;
42
+ }
43
+ export interface ToolDecisionInput {
44
+ toolName: string;
45
+ toolCallId?: string;
46
+ decision: Decision;
47
+ source: DecisionSource;
48
+ /** For edit/write tools: the target path, so `language` can be derived. */
49
+ filePath?: string;
50
+ }
51
+ export interface TrackerDeps {
52
+ tracer: Tracer;
53
+ meter: Meter;
54
+ logger: Logger;
55
+ config: TelemetryConfig;
56
+ now?: () => number;
57
+ }
58
+ /** Idle cutoff for user active time: gaps longer than this are not "active". */
59
+ export declare const USER_ACTIVE_IDLE_CUTOFF_MS: number;
60
+ export declare class SessionTelemetry {
61
+ private readonly tracer;
62
+ private readonly meter;
63
+ private readonly logger;
64
+ private readonly config;
65
+ private readonly now;
66
+ private sessionId;
67
+ private sessionCounted;
68
+ private eventSequence;
69
+ private interactionSequence;
70
+ private interaction;
71
+ private turn;
72
+ private llm;
73
+ private readonly tools;
74
+ /** Decision recorded per tool call before it executes (feeds tool_result). */
75
+ private readonly decisions;
76
+ /** When the agent last went idle — the start of the user's active window. */
77
+ private idleSince;
78
+ private readonly counters;
79
+ constructor(deps: TrackerDeps);
80
+ /** Attributes every metric and event carries (Claude Code's standard set). */
81
+ standardAttributes(): Attributes;
82
+ /** Attributes every span carries: session identity in both vocabularies. */
83
+ private spanAttributes;
84
+ private counter;
85
+ private add;
86
+ emitEvent(name: string, attrs: Attributes): void;
87
+ sessionStart(sessionId: string | undefined): void;
88
+ getSessionId(): string | undefined;
89
+ interactionStart(prompt: string | undefined): void;
90
+ interactionEnd(): void;
91
+ turnStart(turnIndex: number | undefined): void;
92
+ turnEnd(): void;
93
+ private parentCtx;
94
+ llmStart(model: string | undefined): void;
95
+ llmResponseHeaders(status: number | undefined, headers: Record<string, string> | undefined): void;
96
+ /**
97
+ * The assistant message ended: attach usage, emit api_request / api_error
98
+ * plus the token and cost counters, and close the LLM span. Opens a span
99
+ * first when pi delivered the message without a before_provider_request
100
+ * (e.g. a replayed or synthetic message) so nothing is lost.
101
+ */
102
+ assistantMessageEnd(message: AssistantMessageLike): void;
103
+ llmEnd(error: Error | undefined): void;
104
+ toolDecision(input: ToolDecisionInput): void;
105
+ toolStart(toolCallId: string, toolName: string, args: unknown): void;
106
+ toolEnd(toolCallId: string, outcome: {
107
+ isError: boolean;
108
+ resultBytes: number;
109
+ errorType?: string;
110
+ }): void;
111
+ /** Lines added/removed by an edit or write, from pi's tool_result details. */
112
+ linesOfCode(added: number, removed: number): void;
113
+ /** A successful bash command: count commits and PR creations. */
114
+ bashSucceeded(command: string | undefined): void;
115
+ permissionModeChanged(fromMode: string, toMode: string): void;
116
+ /** Close everything still open so no span is lost at exit. */
117
+ close(): void;
118
+ }
119
+ /** Cap on the exported error excerpt (characters, one line). */
120
+ export declare const ERROR_EXCERPT_CHARS = 120;
121
+ /** First line of a provider error, capped, never the full body. */
122
+ export declare function errorExcerpt(message: string | undefined): string;
123
+ export declare function byteLength(v: unknown): number;
124
+ /** Count +/- lines in a unified patch, ignoring file headers. */
125
+ export declare function countPatchLines(patch: string | undefined): {
126
+ added: number;
127
+ removed: number;
128
+ };
129
+ /** Line count of freshly written content (a write tool call). */
130
+ export declare function countContentLines(content: unknown): number;
131
+ //# sourceMappingURL=tracker.d.ts.map