@lucascouts/claude-agent-acp-plus 0.12.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/accounts.d.ts +143 -0
- package/dist/accounts.d.ts.map +1 -0
- package/dist/accounts.js +196 -0
- package/dist/acp-agent.d.ts +81 -3
- package/dist/acp-agent.d.ts.map +1 -1
- package/dist/acp-agent.js +426 -67
- package/dist/context-compaction-meta.d.ts +73 -0
- package/dist/context-compaction-meta.d.ts.map +1 -0
- package/dist/context-compaction-meta.js +53 -0
- package/dist/context-compaction.d.ts +160 -0
- package/dist/context-compaction.d.ts.map +1 -0
- package/dist/context-compaction.js +275 -0
- package/dist/usage-markdown.d.ts +92 -0
- package/dist/usage-markdown.d.ts.map +1 -0
- package/dist/usage-markdown.js +373 -0
- package/package.json +1 -1
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The versioned `_meta` extension that carries context-compaction facts on the
|
|
3
|
+
* synthetic ACP tool call (story 010, R2.1/D3).
|
|
4
|
+
*
|
|
5
|
+
* Why an extension rather than the protocol's own variant: ACP 1.4 does define
|
|
6
|
+
* a `compaction_update`, but the Rust crate the packaged Zed links
|
|
7
|
+
* (`agent-client-protocol 2.0.0`) carries no `compaction` symbol at all, so
|
|
8
|
+
* that variant cannot be deserialised no matter what this adapter sends. The
|
|
9
|
+
* reachable pattern is the one downstream patch `0011` already proves: emit a
|
|
10
|
+
* `_meta` key no ACP variant claims, and let a downstream patch read it. The
|
|
11
|
+
* tool call renders with `ToolKind::Think`'s icon even with no patch present,
|
|
12
|
+
* so R2.1 ships and works on its own.
|
|
13
|
+
*
|
|
14
|
+
* Why the version field is not optional (D3): it is what makes the two halves
|
|
15
|
+
* independently releasable in BOTH directions — a newer adapter against an
|
|
16
|
+
* older Zed degrades to generic tool rendering, and an older adapter against a
|
|
17
|
+
* newer Zed simply never sends the key. A payload with no version is a payload
|
|
18
|
+
* a reader cannot degrade from, so it can only be guessed at.
|
|
19
|
+
*
|
|
20
|
+
* Kept self-contained — no import from `acp-agent.ts`, mirroring
|
|
21
|
+
* `thinking-option.ts` and `rewind-command.ts`. The reason is merge cost:
|
|
22
|
+
* `acp-agent.ts` is a ~9,700-line file that changes upstream almost daily, so
|
|
23
|
+
* every coupling to it is paid again at each sync.
|
|
24
|
+
*/
|
|
25
|
+
/** The `_meta` key the downstream Zed patch looks for. */
|
|
26
|
+
export declare const CONTEXT_COMPACTION_META_KEY = "contextCompaction";
|
|
27
|
+
/**
|
|
28
|
+
* Schema version of the payload under {@link CONTEXT_COMPACTION_META_KEY}.
|
|
29
|
+
* Bump it whenever a field's meaning changes; a reader that does not know the
|
|
30
|
+
* value it receives must fall back to generic tool rendering rather than
|
|
31
|
+
* interpret unknown fields.
|
|
32
|
+
*/
|
|
33
|
+
export declare const CONTEXT_COMPACTION_META_VERSION = 1;
|
|
34
|
+
/**
|
|
35
|
+
* Why the compaction ran: `"manual"` for a user-issued `/compact`,
|
|
36
|
+
* `"automatic"` when the SDK compacted on its own to stay inside the window.
|
|
37
|
+
* Provider-neutral by design — the SDK spells the automatic case `"auto"`.
|
|
38
|
+
*/
|
|
39
|
+
export type ContextCompactionTrigger = "manual" | "automatic";
|
|
40
|
+
/**
|
|
41
|
+
* Compaction-specific facts carried alongside the tool call. Every field
|
|
42
|
+
* except `version` is optional because the SDK frame that produced the event
|
|
43
|
+
* may not carry it: a terminal-only `status` message has no token counts, and
|
|
44
|
+
* an older CLI's `compact_boundary` omits `post_tokens`/`duration_ms`.
|
|
45
|
+
*/
|
|
46
|
+
export interface ContextCompactionMetadata {
|
|
47
|
+
/** Always {@link CONTEXT_COMPACTION_META_VERSION}; see D3 above. */
|
|
48
|
+
version: typeof CONTEXT_COMPACTION_META_VERSION;
|
|
49
|
+
/** Manual `/compact` or an automatic window-pressure compaction. */
|
|
50
|
+
trigger?: ContextCompactionTrigger;
|
|
51
|
+
/** Tokens occupying the context window before compaction. */
|
|
52
|
+
preTokens?: number;
|
|
53
|
+
/** Tokens occupying it after — absent on CLIs that don't report it. */
|
|
54
|
+
postTokens?: number;
|
|
55
|
+
/** How long the compaction took, in milliseconds. */
|
|
56
|
+
durationMs?: number;
|
|
57
|
+
/** Failure reason, present only on a `failed` lifecycle. */
|
|
58
|
+
error?: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Provider-neutral metadata for a synthetic ACP context-compaction tool call.
|
|
62
|
+
*
|
|
63
|
+
* The standard `toolCallId` and `status` fields own lifecycle identity and
|
|
64
|
+
* phase; this extension deliberately carries only compaction-specific facts,
|
|
65
|
+
* so a client that ignores `_meta` entirely still sees a correct tool
|
|
66
|
+
* lifecycle.
|
|
67
|
+
*
|
|
68
|
+
* @param metadata The facts known at this point in the lifecycle; the version
|
|
69
|
+
* is stamped here rather than by each call site, so no caller can emit an
|
|
70
|
+
* unversioned payload.
|
|
71
|
+
*/
|
|
72
|
+
export declare function createContextCompactionMeta(metadata?: Omit<ContextCompactionMetadata, "version">): Record<typeof CONTEXT_COMPACTION_META_KEY, ContextCompactionMetadata>;
|
|
73
|
+
//# sourceMappingURL=context-compaction-meta.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-compaction-meta.d.ts","sourceRoot":"","sources":["../src/context-compaction-meta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,0DAA0D;AAC1D,eAAO,MAAM,2BAA2B,sBAAsB,CAAC;AAE/D;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B,IAAI,CAAC;AAEjD;;;;GAIG;AACH,MAAM,MAAM,wBAAwB,GAAG,QAAQ,GAAG,WAAW,CAAC;AAE9D;;;;;GAKG;AACH,MAAM,WAAW,yBAAyB;IACxC,oEAAoE;IACpE,OAAO,EAAE,OAAO,+BAA+B,CAAC;IAChD,oEAAoE;IACpE,OAAO,CAAC,EAAE,wBAAwB,CAAC;IACnC,6DAA6D;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,GAAE,IAAI,CAAC,yBAAyB,EAAE,SAAS,CAAM,GACxD,MAAM,CAAC,OAAO,2BAA2B,EAAE,yBAAyB,CAAC,CAOvE"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The versioned `_meta` extension that carries context-compaction facts on the
|
|
3
|
+
* synthetic ACP tool call (story 010, R2.1/D3).
|
|
4
|
+
*
|
|
5
|
+
* Why an extension rather than the protocol's own variant: ACP 1.4 does define
|
|
6
|
+
* a `compaction_update`, but the Rust crate the packaged Zed links
|
|
7
|
+
* (`agent-client-protocol 2.0.0`) carries no `compaction` symbol at all, so
|
|
8
|
+
* that variant cannot be deserialised no matter what this adapter sends. The
|
|
9
|
+
* reachable pattern is the one downstream patch `0011` already proves: emit a
|
|
10
|
+
* `_meta` key no ACP variant claims, and let a downstream patch read it. The
|
|
11
|
+
* tool call renders with `ToolKind::Think`'s icon even with no patch present,
|
|
12
|
+
* so R2.1 ships and works on its own.
|
|
13
|
+
*
|
|
14
|
+
* Why the version field is not optional (D3): it is what makes the two halves
|
|
15
|
+
* independently releasable in BOTH directions — a newer adapter against an
|
|
16
|
+
* older Zed degrades to generic tool rendering, and an older adapter against a
|
|
17
|
+
* newer Zed simply never sends the key. A payload with no version is a payload
|
|
18
|
+
* a reader cannot degrade from, so it can only be guessed at.
|
|
19
|
+
*
|
|
20
|
+
* Kept self-contained — no import from `acp-agent.ts`, mirroring
|
|
21
|
+
* `thinking-option.ts` and `rewind-command.ts`. The reason is merge cost:
|
|
22
|
+
* `acp-agent.ts` is a ~9,700-line file that changes upstream almost daily, so
|
|
23
|
+
* every coupling to it is paid again at each sync.
|
|
24
|
+
*/
|
|
25
|
+
/** The `_meta` key the downstream Zed patch looks for. */
|
|
26
|
+
export const CONTEXT_COMPACTION_META_KEY = "contextCompaction";
|
|
27
|
+
/**
|
|
28
|
+
* Schema version of the payload under {@link CONTEXT_COMPACTION_META_KEY}.
|
|
29
|
+
* Bump it whenever a field's meaning changes; a reader that does not know the
|
|
30
|
+
* value it receives must fall back to generic tool rendering rather than
|
|
31
|
+
* interpret unknown fields.
|
|
32
|
+
*/
|
|
33
|
+
export const CONTEXT_COMPACTION_META_VERSION = 1;
|
|
34
|
+
/**
|
|
35
|
+
* Provider-neutral metadata for a synthetic ACP context-compaction tool call.
|
|
36
|
+
*
|
|
37
|
+
* The standard `toolCallId` and `status` fields own lifecycle identity and
|
|
38
|
+
* phase; this extension deliberately carries only compaction-specific facts,
|
|
39
|
+
* so a client that ignores `_meta` entirely still sees a correct tool
|
|
40
|
+
* lifecycle.
|
|
41
|
+
*
|
|
42
|
+
* @param metadata The facts known at this point in the lifecycle; the version
|
|
43
|
+
* is stamped here rather than by each call site, so no caller can emit an
|
|
44
|
+
* unversioned payload.
|
|
45
|
+
*/
|
|
46
|
+
export function createContextCompactionMeta(metadata = {}) {
|
|
47
|
+
return {
|
|
48
|
+
[CONTEXT_COMPACTION_META_KEY]: {
|
|
49
|
+
version: CONTEXT_COMPACTION_META_VERSION,
|
|
50
|
+
...metadata,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context compaction as ONE idempotent ACP tool lifecycle (story 010, R2.1/R2.2).
|
|
3
|
+
*
|
|
4
|
+
* What this replaces: the adapter used to infer compaction from a
|
|
5
|
+
* `compactionInProgress` boolean and narrate it as assistant text
|
|
6
|
+
* ("Compacting…", "Compacting completed."). The flag existed only because, in
|
|
7
|
+
* the adapter's own comment, the SDK's two terminal `status` messages were
|
|
8
|
+
* "indistinguishable" — a guess, not a signal. Once the lifecycle is explicit
|
|
9
|
+
* the guess is not merely redundant, it double-reports: the tool call says the
|
|
10
|
+
* compaction finished and the banner says so again. So the inference is
|
|
11
|
+
* DELETED, not left inert (D4) — a flag that no longer decides anything is a
|
|
12
|
+
* thing the next reader has to prove is inert.
|
|
13
|
+
*
|
|
14
|
+
* What replaces it: a small state machine that folds every event shape the SDK
|
|
15
|
+
* can produce onto a single tool call.
|
|
16
|
+
*
|
|
17
|
+
* SDK event → lifecycle call
|
|
18
|
+
* ------------------------------------------- -----------------------------
|
|
19
|
+
* `status` = "compacting" → start() tool_call, in_progress
|
|
20
|
+
* `stream_event` compaction block/delta → heartbeat() tool_call_update, in_progress
|
|
21
|
+
* `status` with compact_result success/failed → finish() tool_call_update, terminal
|
|
22
|
+
* `compact_boundary` (token counts) → finish(enrich) tool_call_update, metadata only
|
|
23
|
+
* a terminal with no preceding "compacting" → finish() tool_call, terminal (standalone)
|
|
24
|
+
* a DUPLICATED terminal → finish() nothing
|
|
25
|
+
*
|
|
26
|
+
* The two hard cases pull in opposite directions and both are real:
|
|
27
|
+
*
|
|
28
|
+
* - The SDK duplicates the terminal `compact_result` message for a single
|
|
29
|
+
* failed compaction. Two terminals for one compaction must stay ONE report.
|
|
30
|
+
* - One model turn can legitimately compact more than once. Two genuine
|
|
31
|
+
* compactions must stay TWO distinguishable reports.
|
|
32
|
+
*
|
|
33
|
+
* The state machine separates them by phase rather than by identity: a
|
|
34
|
+
* terminal that arrives when the lifecycle has already terminated is a
|
|
35
|
+
* duplicate and changes nothing, while a fresh `compacting` status AFTER a
|
|
36
|
+
* terminal opens a new lifecycle with a new tool call id. A rule that instead
|
|
37
|
+
* suppressed by matching ids or payloads would satisfy one case by breaking
|
|
38
|
+
* the other.
|
|
39
|
+
*
|
|
40
|
+
* State lives until the owning turn's `result` (or an abort) rather than being
|
|
41
|
+
* cleared at each terminal, because the SDK can also omit the opening status
|
|
42
|
+
* on replay — the terminal has to be able to stand alone.
|
|
43
|
+
*
|
|
44
|
+
* Kept self-contained — no import from `acp-agent.ts`, mirroring
|
|
45
|
+
* `thinking-option.ts` and `rewind-command.ts`; what it needs from the adapter
|
|
46
|
+
* (the send chokepoint) is injected, which also leaves the whole state machine
|
|
47
|
+
* unit-testable without a live SDK session. The reason is merge cost:
|
|
48
|
+
* `acp-agent.ts` is a ~9,700-line file that changes upstream almost daily, so
|
|
49
|
+
* every coupling to it is paid again at each sync.
|
|
50
|
+
*/
|
|
51
|
+
import { SessionNotification } from "@agentclientprotocol/sdk";
|
|
52
|
+
import { ContextCompactionMetadata } from "./context-compaction-meta.js";
|
|
53
|
+
/** The phases a compaction can END in. `in_progress` is not terminal. */
|
|
54
|
+
type CompactionStatus = "completed" | "failed";
|
|
55
|
+
/** One compaction's identity and phase. */
|
|
56
|
+
type CompactionState = {
|
|
57
|
+
/** The ACP tool call id every update for this compaction carries. */
|
|
58
|
+
toolCallId: string;
|
|
59
|
+
/** Set once the lifecycle has reported an outcome; the duplicate guard. */
|
|
60
|
+
terminalStatus?: CompactionStatus;
|
|
61
|
+
/** Stream heartbeats are collapsed to one keep-alive per lifecycle. */
|
|
62
|
+
heartbeatSent: boolean;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* The adapter's send chokepoint, injected. Deliberately the ACP SDK's
|
|
66
|
+
* `SessionNotification` rather than an adapter-local alias, so this module
|
|
67
|
+
* needs nothing from `acp-agent.ts`.
|
|
68
|
+
*/
|
|
69
|
+
type SendUpdate = (notification: SessionNotification) => Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Translates Claude's compaction signals into one idempotent ACP tool
|
|
72
|
+
* lifecycle. One instance per consumer; `reset()` at each turn boundary.
|
|
73
|
+
*/
|
|
74
|
+
export declare class ContextCompactionLifecycle {
|
|
75
|
+
private readonly sendUpdate;
|
|
76
|
+
private activeCompaction;
|
|
77
|
+
private outputDelivered;
|
|
78
|
+
private duplicateErrorOutput;
|
|
79
|
+
constructor(sendUpdate: SendUpdate);
|
|
80
|
+
/**
|
|
81
|
+
* Whether this turn already showed the user something about a compaction.
|
|
82
|
+
*
|
|
83
|
+
* The adapter reads it for two decisions the deleted banners used to make
|
|
84
|
+
* implicitly, by counting as delivered assistant text: an echo-less turn
|
|
85
|
+
* that only compacted (e.g. `/compact`) must not have its result text
|
|
86
|
+
* re-emitted by the issue-#453 fallback, and a replayed synthetic
|
|
87
|
+
* local-command frame from an earlier compact attempt must not be forwarded
|
|
88
|
+
* on top of the lifecycle.
|
|
89
|
+
*/
|
|
90
|
+
get hasDeliveredOutput(): boolean;
|
|
91
|
+
/** Return to the unstarted state; call at each turn boundary. */
|
|
92
|
+
reset(): void;
|
|
93
|
+
/**
|
|
94
|
+
* Claude also emits a failed manual compaction's error as local-command
|
|
95
|
+
* stdout. Consume that one duplicate after the tool lifecycle already
|
|
96
|
+
* carried it, without hiding unrelated command output.
|
|
97
|
+
*
|
|
98
|
+
* Matching is by exact (trimmed) text and consumes at most once, so a
|
|
99
|
+
* command that genuinely prints the same string later still reaches the
|
|
100
|
+
* client.
|
|
101
|
+
*
|
|
102
|
+
* @returns `true` when the caller should drop this content.
|
|
103
|
+
*/
|
|
104
|
+
consumeDuplicateErrorOutput(content: string): boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Open the tool call the client renders. Idempotent while a compaction is
|
|
107
|
+
* still running (a repeated `compacting` status re-uses the open call); a
|
|
108
|
+
* `compacting` that arrives AFTER a terminal starts a fresh lifecycle, which
|
|
109
|
+
* is how two real compactions in one turn stay two reports.
|
|
110
|
+
*
|
|
111
|
+
* @param toolCallId The SDK message uuid — replay-stable, so a re-delivered
|
|
112
|
+
* frame addresses the same tool call rather than inventing one.
|
|
113
|
+
*/
|
|
114
|
+
start(sessionId: string, toolCallId: string): Promise<CompactionState>;
|
|
115
|
+
/**
|
|
116
|
+
* Keep the open call alive while compaction streams. Sent at most once per
|
|
117
|
+
* lifecycle: the deltas carry the generated summary, which stays internal to
|
|
118
|
+
* the agent, so repeating them would add noise and no information.
|
|
119
|
+
*
|
|
120
|
+
* @param fallbackId Used only when the opening status never arrived (replay).
|
|
121
|
+
*/
|
|
122
|
+
heartbeat(sessionId: string, fallbackId: string): Promise<void>;
|
|
123
|
+
/**
|
|
124
|
+
* Report the outcome — exactly once per compaction.
|
|
125
|
+
*
|
|
126
|
+
* Three shapes converge here:
|
|
127
|
+
* - no lifecycle open (the SDK omitted the opening status on replay): emit a
|
|
128
|
+
* standalone terminal `tool_call`, so the event is reported rather than
|
|
129
|
+
* dropped for lack of a start;
|
|
130
|
+
* - the first terminal for an open lifecycle: a `tool_call_update` carrying
|
|
131
|
+
* the status;
|
|
132
|
+
* - a duplicate terminal: nothing at all.
|
|
133
|
+
*
|
|
134
|
+
* @param fallbackId Tool call id for the standalone shape.
|
|
135
|
+
* @param metadata Compaction facts; also emitted as `rawOutput` when non-empty,
|
|
136
|
+
* so a client that ignores `_meta` can still show something.
|
|
137
|
+
* @param enrichTerminal Allow a SECOND update on an already-terminal
|
|
138
|
+
* lifecycle that adds facts without re-reporting the outcome. Used by
|
|
139
|
+
* `compact_boundary`, which arrives after the terminal `status` and is the
|
|
140
|
+
* only frame carrying the token counts. The status field is omitted on that
|
|
141
|
+
* update, so the client still sees exactly one terminal transition.
|
|
142
|
+
*/
|
|
143
|
+
finish(sessionId: string, fallbackId: string, status: CompactionStatus, metadata?: Omit<ContextCompactionMetadata, "version">, enrichTerminal?: boolean): Promise<void>;
|
|
144
|
+
/** Arm {@link consumeDuplicateErrorOutput} for the stdout copy Claude emits. */
|
|
145
|
+
private rememberDuplicateErrorOutput;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Map the SDK's `compact_boundary` metadata onto the provider-neutral names of
|
|
149
|
+
* {@link ContextCompactionMetadata}. Fields an older CLI omits stay omitted
|
|
150
|
+
* rather than becoming `undefined` keys, so `rawOutput` and `_meta` never
|
|
151
|
+
* advertise a number nobody reported.
|
|
152
|
+
*/
|
|
153
|
+
export declare function contextCompactionMetadataFromBoundary(compactMetadata: {
|
|
154
|
+
trigger: "manual" | "auto";
|
|
155
|
+
pre_tokens: number;
|
|
156
|
+
post_tokens?: number;
|
|
157
|
+
duration_ms?: number;
|
|
158
|
+
}): Omit<ContextCompactionMetadata, "version">;
|
|
159
|
+
export {};
|
|
160
|
+
//# sourceMappingURL=context-compaction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-compaction.d.ts","sourceRoot":"","sources":["../src/context-compaction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EACL,yBAAyB,EAE1B,MAAM,8BAA8B,CAAC;AAEtC,yEAAyE;AACzE,KAAK,gBAAgB,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE/C,2CAA2C;AAC3C,KAAK,eAAe,GAAG;IACrB,qEAAqE;IACrE,UAAU,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,uEAAuE;IACvE,aAAa,EAAE,OAAO,CAAC;CACxB,CAAC;AAEF;;;;GAIG;AACH,KAAK,UAAU,GAAG,CAAC,YAAY,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEvE;;;GAGG;AACH,qBAAa,0BAA0B;IAKzB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAJvC,OAAO,CAAC,gBAAgB,CAA8B;IACtD,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,oBAAoB,CAAqB;gBAEpB,UAAU,EAAE,UAAU;IAEnD;;;;;;;;;OASG;IACH,IAAI,kBAAkB,IAAI,OAAO,CAEhC;IAED,iEAAiE;IACjE,KAAK,IAAI,IAAI;IAMb;;;;;;;;;;OAUG;IACH,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAWrD;;;;;;;;OAQG;IACG,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAqB5E;;;;;;OAMG;IACG,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBrE;;;;;;;;;;;;;;;;;;;OAmBG;IACG,MAAM,CACV,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,gBAAgB,EACxB,QAAQ,GAAE,IAAI,CAAC,yBAAyB,EAAE,SAAS,CAAM,EACzD,cAAc,UAAQ,GACrB,OAAO,CAAC,IAAI,CAAC;IAgDhB,gFAAgF;IAChF,OAAO,CAAC,4BAA4B;CAQrC;AAED;;;;;GAKG;AACH,wBAAgB,qCAAqC,CAAC,eAAe,EAAE;IACrE,OAAO,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,IAAI,CAAC,yBAAyB,EAAE,SAAS,CAAC,CAW7C"}
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context compaction as ONE idempotent ACP tool lifecycle (story 010, R2.1/R2.2).
|
|
3
|
+
*
|
|
4
|
+
* What this replaces: the adapter used to infer compaction from a
|
|
5
|
+
* `compactionInProgress` boolean and narrate it as assistant text
|
|
6
|
+
* ("Compacting…", "Compacting completed."). The flag existed only because, in
|
|
7
|
+
* the adapter's own comment, the SDK's two terminal `status` messages were
|
|
8
|
+
* "indistinguishable" — a guess, not a signal. Once the lifecycle is explicit
|
|
9
|
+
* the guess is not merely redundant, it double-reports: the tool call says the
|
|
10
|
+
* compaction finished and the banner says so again. So the inference is
|
|
11
|
+
* DELETED, not left inert (D4) — a flag that no longer decides anything is a
|
|
12
|
+
* thing the next reader has to prove is inert.
|
|
13
|
+
*
|
|
14
|
+
* What replaces it: a small state machine that folds every event shape the SDK
|
|
15
|
+
* can produce onto a single tool call.
|
|
16
|
+
*
|
|
17
|
+
* SDK event → lifecycle call
|
|
18
|
+
* ------------------------------------------- -----------------------------
|
|
19
|
+
* `status` = "compacting" → start() tool_call, in_progress
|
|
20
|
+
* `stream_event` compaction block/delta → heartbeat() tool_call_update, in_progress
|
|
21
|
+
* `status` with compact_result success/failed → finish() tool_call_update, terminal
|
|
22
|
+
* `compact_boundary` (token counts) → finish(enrich) tool_call_update, metadata only
|
|
23
|
+
* a terminal with no preceding "compacting" → finish() tool_call, terminal (standalone)
|
|
24
|
+
* a DUPLICATED terminal → finish() nothing
|
|
25
|
+
*
|
|
26
|
+
* The two hard cases pull in opposite directions and both are real:
|
|
27
|
+
*
|
|
28
|
+
* - The SDK duplicates the terminal `compact_result` message for a single
|
|
29
|
+
* failed compaction. Two terminals for one compaction must stay ONE report.
|
|
30
|
+
* - One model turn can legitimately compact more than once. Two genuine
|
|
31
|
+
* compactions must stay TWO distinguishable reports.
|
|
32
|
+
*
|
|
33
|
+
* The state machine separates them by phase rather than by identity: a
|
|
34
|
+
* terminal that arrives when the lifecycle has already terminated is a
|
|
35
|
+
* duplicate and changes nothing, while a fresh `compacting` status AFTER a
|
|
36
|
+
* terminal opens a new lifecycle with a new tool call id. A rule that instead
|
|
37
|
+
* suppressed by matching ids or payloads would satisfy one case by breaking
|
|
38
|
+
* the other.
|
|
39
|
+
*
|
|
40
|
+
* State lives until the owning turn's `result` (or an abort) rather than being
|
|
41
|
+
* cleared at each terminal, because the SDK can also omit the opening status
|
|
42
|
+
* on replay — the terminal has to be able to stand alone.
|
|
43
|
+
*
|
|
44
|
+
* Kept self-contained — no import from `acp-agent.ts`, mirroring
|
|
45
|
+
* `thinking-option.ts` and `rewind-command.ts`; what it needs from the adapter
|
|
46
|
+
* (the send chokepoint) is injected, which also leaves the whole state machine
|
|
47
|
+
* unit-testable without a live SDK session. The reason is merge cost:
|
|
48
|
+
* `acp-agent.ts` is a ~9,700-line file that changes upstream almost daily, so
|
|
49
|
+
* every coupling to it is paid again at each sync.
|
|
50
|
+
*/
|
|
51
|
+
import { createContextCompactionMeta, } from "./context-compaction-meta.js";
|
|
52
|
+
/**
|
|
53
|
+
* Translates Claude's compaction signals into one idempotent ACP tool
|
|
54
|
+
* lifecycle. One instance per consumer; `reset()` at each turn boundary.
|
|
55
|
+
*/
|
|
56
|
+
export class ContextCompactionLifecycle {
|
|
57
|
+
sendUpdate;
|
|
58
|
+
activeCompaction;
|
|
59
|
+
outputDelivered = false;
|
|
60
|
+
duplicateErrorOutput;
|
|
61
|
+
constructor(sendUpdate) {
|
|
62
|
+
this.sendUpdate = sendUpdate;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Whether this turn already showed the user something about a compaction.
|
|
66
|
+
*
|
|
67
|
+
* The adapter reads it for two decisions the deleted banners used to make
|
|
68
|
+
* implicitly, by counting as delivered assistant text: an echo-less turn
|
|
69
|
+
* that only compacted (e.g. `/compact`) must not have its result text
|
|
70
|
+
* re-emitted by the issue-#453 fallback, and a replayed synthetic
|
|
71
|
+
* local-command frame from an earlier compact attempt must not be forwarded
|
|
72
|
+
* on top of the lifecycle.
|
|
73
|
+
*/
|
|
74
|
+
get hasDeliveredOutput() {
|
|
75
|
+
return this.outputDelivered;
|
|
76
|
+
}
|
|
77
|
+
/** Return to the unstarted state; call at each turn boundary. */
|
|
78
|
+
reset() {
|
|
79
|
+
this.activeCompaction = undefined;
|
|
80
|
+
this.outputDelivered = false;
|
|
81
|
+
this.duplicateErrorOutput = undefined;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Claude also emits a failed manual compaction's error as local-command
|
|
85
|
+
* stdout. Consume that one duplicate after the tool lifecycle already
|
|
86
|
+
* carried it, without hiding unrelated command output.
|
|
87
|
+
*
|
|
88
|
+
* Matching is by exact (trimmed) text and consumes at most once, so a
|
|
89
|
+
* command that genuinely prints the same string later still reaches the
|
|
90
|
+
* client.
|
|
91
|
+
*
|
|
92
|
+
* @returns `true` when the caller should drop this content.
|
|
93
|
+
*/
|
|
94
|
+
consumeDuplicateErrorOutput(content) {
|
|
95
|
+
if (this.duplicateErrorOutput === undefined ||
|
|
96
|
+
content.trim() !== this.duplicateErrorOutput.trim()) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
this.duplicateErrorOutput = undefined;
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Open the tool call the client renders. Idempotent while a compaction is
|
|
104
|
+
* still running (a repeated `compacting` status re-uses the open call); a
|
|
105
|
+
* `compacting` that arrives AFTER a terminal starts a fresh lifecycle, which
|
|
106
|
+
* is how two real compactions in one turn stay two reports.
|
|
107
|
+
*
|
|
108
|
+
* @param toolCallId The SDK message uuid — replay-stable, so a re-delivered
|
|
109
|
+
* frame addresses the same tool call rather than inventing one.
|
|
110
|
+
*/
|
|
111
|
+
async start(sessionId, toolCallId) {
|
|
112
|
+
if (this.activeCompaction && !this.activeCompaction.terminalStatus) {
|
|
113
|
+
return this.activeCompaction;
|
|
114
|
+
}
|
|
115
|
+
this.activeCompaction = { toolCallId, heartbeatSent: false };
|
|
116
|
+
this.outputDelivered = true;
|
|
117
|
+
await this.sendUpdate({
|
|
118
|
+
sessionId,
|
|
119
|
+
update: {
|
|
120
|
+
sessionUpdate: "tool_call",
|
|
121
|
+
toolCallId,
|
|
122
|
+
title: COMPACTION_TOOL_TITLE,
|
|
123
|
+
kind: "think",
|
|
124
|
+
status: "in_progress",
|
|
125
|
+
_meta: compactionToolMeta(),
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
return this.activeCompaction;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Keep the open call alive while compaction streams. Sent at most once per
|
|
132
|
+
* lifecycle: the deltas carry the generated summary, which stays internal to
|
|
133
|
+
* the agent, so repeating them would add noise and no information.
|
|
134
|
+
*
|
|
135
|
+
* @param fallbackId Used only when the opening status never arrived (replay).
|
|
136
|
+
*/
|
|
137
|
+
async heartbeat(sessionId, fallbackId) {
|
|
138
|
+
const state = this.activeCompaction ?? (await this.start(sessionId, fallbackId));
|
|
139
|
+
if (state.terminalStatus || state.heartbeatSent)
|
|
140
|
+
return;
|
|
141
|
+
state.heartbeatSent = true;
|
|
142
|
+
await this.sendUpdate({
|
|
143
|
+
sessionId,
|
|
144
|
+
update: {
|
|
145
|
+
sessionUpdate: "tool_call_update",
|
|
146
|
+
toolCallId: state.toolCallId,
|
|
147
|
+
status: "in_progress",
|
|
148
|
+
_meta: compactionToolMeta(),
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Report the outcome — exactly once per compaction.
|
|
154
|
+
*
|
|
155
|
+
* Three shapes converge here:
|
|
156
|
+
* - no lifecycle open (the SDK omitted the opening status on replay): emit a
|
|
157
|
+
* standalone terminal `tool_call`, so the event is reported rather than
|
|
158
|
+
* dropped for lack of a start;
|
|
159
|
+
* - the first terminal for an open lifecycle: a `tool_call_update` carrying
|
|
160
|
+
* the status;
|
|
161
|
+
* - a duplicate terminal: nothing at all.
|
|
162
|
+
*
|
|
163
|
+
* @param fallbackId Tool call id for the standalone shape.
|
|
164
|
+
* @param metadata Compaction facts; also emitted as `rawOutput` when non-empty,
|
|
165
|
+
* so a client that ignores `_meta` can still show something.
|
|
166
|
+
* @param enrichTerminal Allow a SECOND update on an already-terminal
|
|
167
|
+
* lifecycle that adds facts without re-reporting the outcome. Used by
|
|
168
|
+
* `compact_boundary`, which arrives after the terminal `status` and is the
|
|
169
|
+
* only frame carrying the token counts. The status field is omitted on that
|
|
170
|
+
* update, so the client still sees exactly one terminal transition.
|
|
171
|
+
*/
|
|
172
|
+
async finish(sessionId, fallbackId, status, metadata = {}, enrichTerminal = false) {
|
|
173
|
+
const rawOutput = Object.keys(metadata).length > 0 ? metadata : undefined;
|
|
174
|
+
if (!this.activeCompaction) {
|
|
175
|
+
this.activeCompaction = {
|
|
176
|
+
toolCallId: fallbackId,
|
|
177
|
+
heartbeatSent: false,
|
|
178
|
+
terminalStatus: status,
|
|
179
|
+
};
|
|
180
|
+
this.outputDelivered = true;
|
|
181
|
+
this.rememberDuplicateErrorOutput(status, metadata);
|
|
182
|
+
await this.sendUpdate({
|
|
183
|
+
sessionId,
|
|
184
|
+
update: {
|
|
185
|
+
sessionUpdate: "tool_call",
|
|
186
|
+
toolCallId: fallbackId,
|
|
187
|
+
title: COMPACTION_TOOL_TITLE,
|
|
188
|
+
kind: "think",
|
|
189
|
+
status,
|
|
190
|
+
...compactionErrorFields(status, metadata),
|
|
191
|
+
...(rawOutput ? { rawOutput } : {}),
|
|
192
|
+
_meta: compactionToolMeta(metadata),
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const state = this.activeCompaction;
|
|
198
|
+
// The duplicate guard: a terminal on an already-terminal lifecycle is the
|
|
199
|
+
// SDK repeating itself, and must change nothing the client can see.
|
|
200
|
+
if (state.terminalStatus && !enrichTerminal)
|
|
201
|
+
return;
|
|
202
|
+
const firstTerminal = state.terminalStatus === undefined;
|
|
203
|
+
if (firstTerminal)
|
|
204
|
+
state.terminalStatus = status;
|
|
205
|
+
this.rememberDuplicateErrorOutput(status, metadata);
|
|
206
|
+
await this.sendUpdate({
|
|
207
|
+
sessionId,
|
|
208
|
+
update: {
|
|
209
|
+
sessionUpdate: "tool_call_update",
|
|
210
|
+
toolCallId: state.toolCallId,
|
|
211
|
+
...(firstTerminal ? { status } : {}),
|
|
212
|
+
...compactionErrorFields(status, metadata),
|
|
213
|
+
...(rawOutput ? { rawOutput } : {}),
|
|
214
|
+
_meta: compactionToolMeta(metadata),
|
|
215
|
+
},
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
/** Arm {@link consumeDuplicateErrorOutput} for the stdout copy Claude emits. */
|
|
219
|
+
rememberDuplicateErrorOutput(status, metadata) {
|
|
220
|
+
if (status === "failed" && metadata.error) {
|
|
221
|
+
this.duplicateErrorOutput = metadata.error;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Map the SDK's `compact_boundary` metadata onto the provider-neutral names of
|
|
227
|
+
* {@link ContextCompactionMetadata}. Fields an older CLI omits stay omitted
|
|
228
|
+
* rather than becoming `undefined` keys, so `rawOutput` and `_meta` never
|
|
229
|
+
* advertise a number nobody reported.
|
|
230
|
+
*/
|
|
231
|
+
export function contextCompactionMetadataFromBoundary(compactMetadata) {
|
|
232
|
+
return {
|
|
233
|
+
trigger: compactMetadata.trigger === "auto" ? "automatic" : "manual",
|
|
234
|
+
preTokens: compactMetadata.pre_tokens,
|
|
235
|
+
...(compactMetadata.post_tokens !== undefined
|
|
236
|
+
? { postTokens: compactMetadata.post_tokens }
|
|
237
|
+
: {}),
|
|
238
|
+
...(compactMetadata.duration_ms !== undefined
|
|
239
|
+
? { durationMs: compactMetadata.duration_ms }
|
|
240
|
+
: {}),
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
/** The title every compaction tool call carries; part of the R2.1 contract. */
|
|
244
|
+
const COMPACTION_TOOL_TITLE = "Compact conversation";
|
|
245
|
+
/**
|
|
246
|
+
* The `_meta` payload for a compaction tool update: the versioned extension
|
|
247
|
+
* plus the `claudeCode.toolName` every other tool call in this adapter carries,
|
|
248
|
+
* so a client keying off it treats the synthetic call like any real one.
|
|
249
|
+
*
|
|
250
|
+
* Returns a plain record rather than the adapter's `ToolUpdateMeta` to keep the
|
|
251
|
+
* module free of `acp-agent.ts` imports; the adapter widens `ToolUpdateMeta`
|
|
252
|
+
* with the matching optional field for its own call sites.
|
|
253
|
+
*/
|
|
254
|
+
function compactionToolMeta(metadata = {}) {
|
|
255
|
+
return {
|
|
256
|
+
...createContextCompactionMeta(metadata),
|
|
257
|
+
claudeCode: { toolName: "compact" },
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* The failure reason as renderable tool content — `_meta` is optional for a
|
|
262
|
+
* client, the reason for a failure is not.
|
|
263
|
+
*/
|
|
264
|
+
function compactionErrorFields(status, metadata) {
|
|
265
|
+
if (status !== "failed" || !metadata.error)
|
|
266
|
+
return {};
|
|
267
|
+
return {
|
|
268
|
+
content: [
|
|
269
|
+
{
|
|
270
|
+
type: "content",
|
|
271
|
+
content: { type: "text", text: `Compaction failed: ${metadata.error}` },
|
|
272
|
+
},
|
|
273
|
+
],
|
|
274
|
+
};
|
|
275
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `/usage` rendered as Markdown, and the bounded wait that decides whether it
|
|
3
|
+
* renders at all (story 011, R2.3/R2.4, design D5).
|
|
4
|
+
*
|
|
5
|
+
* The command ALWAYS runs through Claude Code. What this module produces is a
|
|
6
|
+
* best-effort overlay on top of an answer the user already has, so every
|
|
7
|
+
* failure here costs the overlay and nothing else — the caller forwards Claude
|
|
8
|
+
* Code's own text byte-for-byte instead. Three ways out, all of them ending in
|
|
9
|
+
* `null` from {@link structuredUsageMarkdown}:
|
|
10
|
+
*
|
|
11
|
+
* 1. unavailable — the control request rejects, or the method is gone
|
|
12
|
+
* 2. incompatible — the response does not match the shape the renderer reads
|
|
13
|
+
* 3. slow — the response does not arrive inside the bound below
|
|
14
|
+
*
|
|
15
|
+
* THE BOUND IS LOAD-BEARING, NOT DEFENSIVE. Control requests on a fresh session
|
|
16
|
+
* are not serviced until the first turn runs (SDK issues #886/#880), and
|
|
17
|
+
* `/usage` is frequently that first turn — so an unbounded wait would withhold
|
|
18
|
+
* an answer the CLI had already printed, forever. That is why the race below
|
|
19
|
+
* has three legs and not one: the report, a timeout, and the turn's abort
|
|
20
|
+
* signal.
|
|
21
|
+
*
|
|
22
|
+
* ONE READER FOR THE REPORT'S NUMBERS. `account-usage.ts` already maps this same
|
|
23
|
+
* `SDKControlGetUsageResponse` onto the client's rate-limit `_meta`, and it owns
|
|
24
|
+
* the two scalar readings the report needs: `normalizeUtilization` (0..100 ->
|
|
25
|
+
* 0..1, clamped) and `toEpochSeconds` (ISO 8601 -> Unix seconds). Both are
|
|
26
|
+
* imported here rather than re-derived, so the bar this module draws and the bar
|
|
27
|
+
* the client's usage panel draws cannot disagree about what `utilization: 3`
|
|
28
|
+
* means. What is NOT shared is validation: `account-usage.ts` reads defensively
|
|
29
|
+
* and never rejects a report, because a missing field there costs one window,
|
|
30
|
+
* while here an unreadable report has to become a hard "no" so way out 2 can
|
|
31
|
+
* fire. Different questions, so different code — but the same answers to the
|
|
32
|
+
* two questions both of them ask.
|
|
33
|
+
*
|
|
34
|
+
* Kept self-contained — no import from `acp-agent.ts`, mirroring
|
|
35
|
+
* `thinking-option.ts` and `context-compaction.ts`. The reason is merge cost:
|
|
36
|
+
* `acp-agent.ts` is a ~9,700-line file that changes upstream almost daily, so
|
|
37
|
+
* every coupling to it is paid again at each sync. `acp-agent.ts` wires this in
|
|
38
|
+
* at the `/usage` turn: it decides which turn owns a structured render, and
|
|
39
|
+
* publishes the result at most once across the message shapes the SDK can
|
|
40
|
+
* deliver one local command through.
|
|
41
|
+
*/
|
|
42
|
+
import type { Query, SDKControlGetUsageResponse } from "@anthropic-ai/claude-agent-sdk";
|
|
43
|
+
/**
|
|
44
|
+
* How long the structured report may take before the original output wins.
|
|
45
|
+
*
|
|
46
|
+
* Not a guess at network latency: the request may never be serviced at all (see
|
|
47
|
+
* the header), so this is the ceiling on how long a user waits for a decoration
|
|
48
|
+
* on an answer that is already sitting in the buffer.
|
|
49
|
+
*/
|
|
50
|
+
export declare const STRUCTURED_USAGE_TIMEOUT_MS = 5000;
|
|
51
|
+
/**
|
|
52
|
+
* Validate the experimental SDK response at the runtime boundary — way out 2.
|
|
53
|
+
* Null means "this is not a report this renderer can read", which the caller
|
|
54
|
+
* turns into Claude Code's original text.
|
|
55
|
+
*/
|
|
56
|
+
export declare function parseUsageResponse(value: unknown): SDKControlGetUsageResponse | null;
|
|
57
|
+
/**
|
|
58
|
+
* Whether a prompt is exactly the local `/usage` command.
|
|
59
|
+
*
|
|
60
|
+
* Exact, not a prefix: `/usage now` is an argument form this renderer has no
|
|
61
|
+
* mapping for, and prose that merely mentions the word is a model turn.
|
|
62
|
+
*/
|
|
63
|
+
export declare function isUsageCommandText(text: string): boolean;
|
|
64
|
+
/** Render the SDK's structured `/usage` response as Markdown (R2.3). */
|
|
65
|
+
export declare function formatUsageResponse(usage: SDKControlGetUsageResponse): string;
|
|
66
|
+
/**
|
|
67
|
+
* The one SDK surface this module needs.
|
|
68
|
+
*
|
|
69
|
+
* `Pick` on the literal method name is the compile-time tripwire the ToDo asks
|
|
70
|
+
* for: when the SDK stabilises this API and renames the method, the key stops
|
|
71
|
+
* being a `keyof Query` and the BUILD fails here. Without it, a rename would
|
|
72
|
+
* only ever surface as `/usage` degrading to way out 1 forever — a silent loss
|
|
73
|
+
* of the whole feature, indistinguishable from a session where the report is
|
|
74
|
+
* genuinely unavailable.
|
|
75
|
+
*/
|
|
76
|
+
export type UsageReportQuery = Pick<Query, "usage_EXPERIMENTAL_MAY_CHANGE_DO_NOT_RELY_ON_THIS_API_YET">;
|
|
77
|
+
/** The slice of the adapter's logger this module uses. */
|
|
78
|
+
export type UsageMarkdownLogger = {
|
|
79
|
+
error: (message: string) => void;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* The structured `/usage` render for one turn, or null when any of the three
|
|
83
|
+
* ways out fired (R2.4). Never throws and never resolves late: the caller is
|
|
84
|
+
* holding a completed local command's output while it awaits this.
|
|
85
|
+
*
|
|
86
|
+
* Raced against BOTH a timeout and the turn's abort signal. The timeout covers
|
|
87
|
+
* a request that is never serviced (see the header); the signal covers a turn
|
|
88
|
+
* that ended — cancelled, or settled — while the request was still in flight,
|
|
89
|
+
* so a dead turn's overlay is abandoned rather than merely ignored.
|
|
90
|
+
*/
|
|
91
|
+
export declare function structuredUsageMarkdown(query: UsageReportQuery, signal: AbortSignal, logger: UsageMarkdownLogger): Promise<string | null>;
|
|
92
|
+
//# sourceMappingURL=usage-markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-markdown.d.ts","sourceRoot":"","sources":["../src/usage-markdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,0BAA0B,EAAE,MAAM,gCAAgC,CAAC;AAKxF;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,OAAQ,CAAC;AA6DjD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,0BAA0B,GAAG,IAAI,CAOpF;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AA0OD,wEAAwE;AACxE,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,0BAA0B,GAAG,MAAM,CAS7E;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,gBAAgB,GAAG,IAAI,CACjC,KAAK,EACL,2DAA2D,CAC5D,CAAC;AAEF,0DAA0D;AAC1D,MAAM,MAAM,mBAAmB,GAAG;IAAE,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,CAAC;AAQvE;;;;;;;;;GASG;AACH,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,gBAAgB,EACvB,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAwDxB"}
|