@mafdet/cli 0.4.1 → 0.4.2

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 (72) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +61 -0
  3. package/README.zh-CN.md +52 -0
  4. package/dist/agent/loop.d.ts +14 -0
  5. package/dist/agent/loop.d.ts.map +1 -1
  6. package/dist/agent/loop.js +16 -3
  7. package/dist/agent/session.d.ts +5 -0
  8. package/dist/agent/session.d.ts.map +1 -1
  9. package/dist/agent/session.js +1 -1
  10. package/dist/agent/tools/read-only.d.ts.map +1 -1
  11. package/dist/agent/tools/read-only.js +6 -0
  12. package/dist/api/account.d.ts +43 -0
  13. package/dist/api/account.d.ts.map +1 -1
  14. package/dist/api/account.js +40 -0
  15. package/dist/commands/sessions.d.ts +5 -0
  16. package/dist/commands/sessions.d.ts.map +1 -0
  17. package/dist/commands/sessions.js +379 -0
  18. package/dist/config/paths.d.ts +7 -0
  19. package/dist/config/paths.d.ts.map +1 -1
  20. package/dist/config/paths.js +24 -0
  21. package/dist/filesystem/protected-dirs.d.ts +26 -0
  22. package/dist/filesystem/protected-dirs.d.ts.map +1 -0
  23. package/dist/filesystem/protected-dirs.js +78 -0
  24. package/dist/filesystem/workspace.d.ts +12 -1
  25. package/dist/filesystem/workspace.d.ts.map +1 -1
  26. package/dist/filesystem/workspace.js +24 -3
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +8 -0
  29. package/dist/security/redact.d.ts +26 -3
  30. package/dist/security/redact.d.ts.map +1 -1
  31. package/dist/security/redact.js +48 -3
  32. package/dist/sessions/index-file.d.ts +38 -0
  33. package/dist/sessions/index-file.d.ts.map +1 -0
  34. package/dist/sessions/index-file.js +174 -0
  35. package/dist/sessions/lock.d.ts +39 -0
  36. package/dist/sessions/lock.d.ts.map +1 -0
  37. package/dist/sessions/lock.js +134 -0
  38. package/dist/sessions/open.d.ts +45 -0
  39. package/dist/sessions/open.d.ts.map +1 -0
  40. package/dist/sessions/open.js +96 -0
  41. package/dist/sessions/policy.d.ts +32 -0
  42. package/dist/sessions/policy.d.ts.map +1 -0
  43. package/dist/sessions/policy.js +57 -0
  44. package/dist/sessions/reconcile.d.ts +49 -0
  45. package/dist/sessions/reconcile.d.ts.map +1 -0
  46. package/dist/sessions/reconcile.js +115 -0
  47. package/dist/sessions/recorder.d.ts +42 -0
  48. package/dist/sessions/recorder.d.ts.map +1 -0
  49. package/dist/sessions/recorder.js +147 -0
  50. package/dist/sessions/resume.d.ts +67 -0
  51. package/dist/sessions/resume.d.ts.map +1 -0
  52. package/dist/sessions/resume.js +100 -0
  53. package/dist/sessions/store.d.ts +141 -0
  54. package/dist/sessions/store.d.ts.map +1 -0
  55. package/dist/sessions/store.js +272 -0
  56. package/dist/sessions/usage.d.ts +35 -0
  57. package/dist/sessions/usage.d.ts.map +1 -0
  58. package/dist/sessions/usage.js +157 -0
  59. package/dist/tui/agent-surface.d.ts +3 -0
  60. package/dist/tui/agent-surface.d.ts.map +1 -1
  61. package/dist/tui/agent-surface.js +16 -1
  62. package/dist/tui/app.d.ts.map +1 -1
  63. package/dist/tui/app.js +18 -1
  64. package/dist/tui/route.d.ts.map +1 -1
  65. package/dist/tui/route.js +19 -2
  66. package/dist/tui/session-centre.d.ts +15 -0
  67. package/dist/tui/session-centre.d.ts.map +1 -0
  68. package/dist/tui/session-centre.js +59 -0
  69. package/dist/tui/start-agent.d.ts +9 -0
  70. package/dist/tui/start-agent.d.ts.map +1 -1
  71. package/dist/tui/start-agent.js +122 -0
  72. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -6,6 +6,40 @@ The version is the contract for the JSON output shapes and the exit codes.
6
6
  Being 0.x, semver still permits a break in a minor bump; the intent is not to
7
7
  use that latitude, and the promise becomes binding at 1.0.0.
8
8
 
9
+ ## 0.4.2 - 2026-08-11
10
+
11
+ Conversations are now saved on this computer, and a session's cost can be
12
+ reconciled against the billing ledger.
13
+
14
+ `mafdet sessions list|show|usage|delete` browses what is stored locally. None
15
+ of it calls a model, so reading your own history is never charged. Recording
16
+ is on by default for interactive sessions and off wherever a machine is
17
+ reading the output; `--no-history` writes nothing at all.
18
+
19
+ The transcript is plain text and stays on this machine - it is not uploaded,
20
+ and Mafdet holds no copy. That is a statement about the archive, not about the
21
+ model: the messages you send are still sent to the API to be answered and
22
+ still appear in your usage records. The README says where the files live on
23
+ each platform, and that deleting one is an ordinary file delete rather than a
24
+ secure erase.
25
+
26
+ `mafdet sessions usage <id> --refresh` asks the billing ledger what the
27
+ requests actually cost and replaces the local estimate with the settled
28
+ figure. It sends the request IDs already in the transcript and nothing else -
29
+ no messages, no title, no workspace, no session ID. Requests paid for by a
30
+ different API key are left alone and reported rather than guessed at, and a
31
+ request the ledger has not settled stays `pending` rather than being shown as
32
+ zero.
33
+
34
+ The agent cannot read the CLI's own directories, even when you run `mafdet`
35
+ from your home directory and the session store is technically inside the
36
+ workspace.
37
+
38
+ Fixed on the way: the value recorded to attribute usage to a key was the
39
+ display fingerprint, which renders every live key identically - so a session
40
+ that used two keys reported them as one. It is now a digest that actually
41
+ differs per key, and still cannot be turned back into a key.
42
+
9
43
  ## 0.4.1 - 2026-08-07
10
44
 
11
45
  Fixes Ctrl+C in the interactive session, which did nothing while a model
package/README.md CHANGED
@@ -88,6 +88,8 @@ prompt as an argument, or use `--input <file>`.
88
88
  | `mafdet embed [text\|<file>] --model <id> [--output <file>]` | Text to vector |
89
89
  | `mafdet speech [text\|<file>] --model <id> --output <file> --voice <name>` | Text to an audio file |
90
90
  | `mafdet account balance\|usage\|subscription` | Wallet, spend and plan (needs the `account:read` scope) |
91
+ | `mafdet sessions list\|show\|usage\|delete` | Conversations saved on this computer (never calls a model) |
92
+ | `mafdet sessions usage <id> --refresh` | Replace the local estimate with the billing ledger's figure |
91
93
  | `mafdet config list` | The resolved settings and where each came from |
92
94
 
93
95
  `--json` on any query command emits one complete JSON document; `--plain`
@@ -181,6 +183,65 @@ flag: it would put the key into shell history and the process list. Keys are
181
183
  never written to a config file and never printed in full — only as a
182
184
  fingerprint like `sk-mafdet-live-<redacted>`.
183
185
 
186
+ ## Saved conversations
187
+
188
+ Interactive sessions are saved on this computer, and only on this computer.
189
+ They are not uploaded, and Mafdet holds no copy of them.
190
+
191
+ That is a statement about the transcript, not about the model. The messages you
192
+ send are still sent to the API to be answered and still appear in your usage
193
+ records; what stays local is the saved copy.
194
+
195
+ Where they live:
196
+
197
+ | Platform | Path |
198
+ | ----------- | --------------------------------------------------- |
199
+ | Linux / WSL | `${XDG_STATE_HOME:-~/.local/state}/mafdet/sessions` |
200
+ | macOS | `~/Library/Application Support/mafdet/sessions` |
201
+ | Windows | `%LOCALAPPDATA%\mafdet\sessions` |
202
+
203
+ The files are **plain text**. A transcript contains your messages, the model's
204
+ replies, and any source the agent read while working — so treat a session
205
+ directory the way you would treat the project it came from. API keys are the
206
+ one exception: everything is passed through redaction on the way to disk, so a
207
+ key you paste into a prompt is stored as `<redacted>`. Files are created
208
+ `0600` and directories `0700` on Linux and macOS; Windows has no equivalent
209
+ mode bits and inherits the ACL of `%LOCALAPPDATA%`.
210
+
211
+ The agent cannot read these directories, even when you run `mafdet` from your
212
+ home directory and the store is technically inside the workspace. Otherwise an
213
+ agent working on one project could read another project's transcript in full.
214
+
215
+ Turning it off and cleaning up:
216
+
217
+ ```bash
218
+ mafdet --no-history # this run is not recorded at all
219
+ mafdet sessions list # what is saved, and the path when nothing is
220
+ mafdet sessions delete <id> --yes
221
+ ```
222
+
223
+ `--no-history` writes nothing — not an empty directory, not an index entry.
224
+
225
+ Deleting removes the local messages and this session's usage mapping. It does
226
+ **not** remove API usage, billing records or charges: those belong to the API
227
+ key, not to the transcript. And it is an ordinary file delete, not a secure
228
+ erase — backups, snapshots and the filesystem itself may still hold copies.
229
+
230
+ ## Reconciling what a session cost
231
+
232
+ `mafdet sessions usage <id>` adds up what a conversation used from the local
233
+ record. Those charges are estimates, computed with the gateway's own
234
+ arithmetic but computed here.
235
+
236
+ `--refresh` asks the billing ledger for the real figure. It sends the request
237
+ IDs already in the transcript and nothing else — no messages, no title, no
238
+ workspace, no session ID. Requests paid for by a different API key are left
239
+ alone and reported, so you know to run it again with that key.
240
+
241
+ A request that the ledger has not caught up with stays `pending`, and a request
242
+ that never returned an ID stays `unknown`. Neither is ever shown as `0`, which
243
+ would read as "it was free".
244
+
184
245
  ## Cost and cancellation
185
246
 
186
247
  `chat` prints tokens and an estimated charge to stderr, computed with the same
package/README.zh-CN.md CHANGED
@@ -71,6 +71,8 @@ mafdet doctor
71
71
  | `mafdet agent "<目标>" [--allow-write] [--allow-command "<前缀>"]` | 本地 Agent,默认只读 |
72
72
  | `mafdet agent`(不带目标,需终端) | 交互会话 |
73
73
  | `mafdet account balance\|usage\|subscription` | 钱包、用量、套餐(需 `account:read` scope) |
74
+ | `mafdet sessions list\|show\|usage\|delete` | 保存在这台电脑上的会话(不会调用模型) |
75
+ | `mafdet sessions usage <id> --refresh` | 用账单账本的权威金额替换本地估算 |
74
76
  | `mafdet config list` | 当前生效的配置及其来源 |
75
77
 
76
78
  查询类命令都支持 `--json`(输出一份完整 JSON 文档)与 `--plain`(无表头的 TSV,方便
@@ -156,6 +158,56 @@ Key 只从 `MAFDET_API_KEY` 读取。**刻意不提供 `--api-key` 参数**—
156
158
  shell 历史和进程列表。Key 不会被写入任何配置文件,也不会完整出现在任何输出里,
157
159
  只以 `sk-mafdet-live-<redacted>` 这样的指纹形式展示。
158
160
 
161
+ ## 保存下来的会话
162
+
163
+ 交互式会话会保存在这台电脑上,**也只在这台电脑上**。它们不会上传,Mafdet 没有副本。
164
+
165
+ 这是关于**存档**的说法,不是关于模型的。你发送的消息仍然会送到 API 去作答,
166
+ 仍然出现在你的用量记录里;留在本地的是那份保存下来的副本。
167
+
168
+ 存放位置:
169
+
170
+ | 平台 | 路径 |
171
+ | ----------- | --------------------------------------------------- |
172
+ | Linux / WSL | `${XDG_STATE_HOME:-~/.local/state}/mafdet/sessions` |
173
+ | macOS | `~/Library/Application Support/mafdet/sessions` |
174
+ | Windows | `%LOCALAPPDATA%\mafdet\sessions` |
175
+
176
+ 这些文件是**明文**。一份存档包含你的消息、模型的回复,以及 agent 工作时读过的任何源码——
177
+ 所以请把会话目录当作它所对应的那个项目本身来对待。API Key 是唯一的例外:
178
+ 所有内容在写盘前都会过一遍脱敏,你粘进提示词里的 Key 会以 `<redacted>` 的形式存下来。
179
+ Linux 与 macOS 上文件权限 `0600`、目录 `0700`;**Windows 没有等价的权限位**,
180
+ 继承 `%LOCALAPPDATA%` 的 ACL。
181
+
182
+ **Agent 读不到这些目录**——即使你在家目录里运行 `mafdet`、存档实际落在工作区内也一样。
183
+ 否则在 A 项目里工作的 agent 就能读到 B 项目会话的完整明文。
184
+
185
+ 关闭与清理:
186
+
187
+ ```bash
188
+ mafdet --no-history # 这一次运行完全不记录
189
+ mafdet sessions list # 已保存的会话;没有时会告诉你路径
190
+ mafdet sessions delete <id> --yes
191
+ ```
192
+
193
+ `--no-history` 什么都不留——不留空目录,也不留索引条目。
194
+
195
+ 删除会移除本地消息和这个会话的用量映射。它**不会**移除 API 用量、账单记录或扣费:
196
+ 那些属于 API Key,不属于存档。而且它只是一次普通的文件删除,**不是安全擦除**——
197
+ 备份、快照和文件系统本身仍可能保有副本。
198
+
199
+ ## 对账:这次会话到底花了多少
200
+
201
+ `mafdet sessions usage <id>` 从本地记录累加一次会话的用量。那些金额是**估算**,
202
+ 算法与网关一致,但是在本地算的。
203
+
204
+ `--refresh` 会去问账单账本要真实金额。它只发送存档里已有的 request ID,**别的什么都不发**——
205
+ 不发消息、不发标题、不发工作区路径、不发 session ID。由另一把 API Key 支付的请求会被跳过
206
+ 并如实告知,好让你知道该换那把 Key 再跑一次。
207
+
208
+ 账本还没跟上的请求保持 `pending`,从未拿到 ID 的请求保持 `unknown`。
209
+ **两者都绝不显示为 `0`**——0 读起来像「免费」。
210
+
159
211
  ## 费用与取消
160
212
 
161
213
  `chat` 会在 stderr 打印 token 数与预估费用,算法与网关计费一致,但**以钱包为准**。
@@ -88,6 +88,20 @@ export type AgentEvent = {
88
88
  } | {
89
89
  type: "text";
90
90
  text: string;
91
+ }
92
+ /**
93
+ * One model request's accounting, as it happens. The summary already
94
+ * aggregates this; the event exists so a recorder can attribute each request
95
+ * to the ledger row it became (CLI-024/025) - `requestId` is the gateway's
96
+ * x-litellm-call-id, which is unique per row in request_ledger.
97
+ */
98
+ | {
99
+ type: "usage";
100
+ model: string;
101
+ requestId?: string;
102
+ promptTokens: number;
103
+ completionTokens: number;
104
+ costMicroUsd: bigint;
91
105
  } | {
92
106
  type: "rate_limited";
93
107
  waitMs: number;
@@ -1 +1 @@
1
- {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/agent/loop.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/agent/loop.ts"],"names":[],"mappings":"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"}
@@ -78,7 +78,18 @@ export async function runAgent(options) {
78
78
  report.completionTokens += usage?.completion_tokens ?? 0;
79
79
  // Cost comes from returned usage, never from the reservation: CLI-000B
80
80
  // showed the reserve cannot see the tool schema and under-counts badly.
81
- report.costMicroUsd += priceTurn(options.pricing, usage);
81
+ const turnCost = priceTurn(options.pricing, usage);
82
+ report.costMicroUsd += turnCost;
83
+ options.onEvent?.({
84
+ type: "usage",
85
+ model: options.model,
86
+ ...(response.requestId === undefined
87
+ ? {}
88
+ : { requestId: response.requestId }),
89
+ promptTokens: usage?.prompt_tokens ?? 0,
90
+ completionTokens: usage?.completion_tokens ?? 0,
91
+ costMicroUsd: turnCost,
92
+ });
82
93
  const choice = response.choices?.[0];
83
94
  const message = choice?.message;
84
95
  const calls = message?.tool_calls ?? [];
@@ -198,8 +209,10 @@ async function requestWithRateLimitHandling(options, limits, body, report, clock
198
209
  for (let attempt = 0;; attempt += 1) {
199
210
  try {
200
211
  report.modelRequests += 1;
201
- const { data } = await options.client.postJson("/chat/completions", body, { signal: options.signal });
202
- return data;
212
+ const { data, requestId } = await options.client.postJson("/chat/completions", body, { signal: options.signal });
213
+ // Carried on the response so the caller can tie this turn to its ledger
214
+ // row without the loop needing to know what a session is.
215
+ return { ...data, requestId };
203
216
  }
204
217
  catch (error) {
205
218
  // Everything except an explicit 429 propagates. A timeout or a 5xx may
@@ -32,6 +32,11 @@ export interface SessionOptions {
32
32
  * the same events are drawn.
33
33
  */
34
34
  onEvent?: (event: AgentEvent) => void;
35
+ /**
36
+ * A conversation to continue, rebuilt from a saved session (CLI-024).
37
+ * Appended to in place, exactly as the fresh array would be.
38
+ */
39
+ history?: ChatMessage[];
35
40
  }
36
41
  export interface SessionSummary {
37
42
  goals: number;
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/agent/session.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAY,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AACxE,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAapE,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,oEAAoE;IACpE,OAAO,EAAE,SAAS,YAAY,EAAE,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,WAAW,EAAE,WAAW,CAAC;IACzB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC7C,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,cAAc,CAAC,CAwFzB;AAgHD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,CA2B7D"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/agent/session.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAY,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AACxE,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAapE,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,oEAAoE;IACpE,OAAO,EAAE,SAAS,YAAY,EAAE,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,WAAW,EAAE,WAAW,CAAC;IACzB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC7C,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC;;;OAGG;IACH,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,cAAc,CAAC,CAwFzB;AAgHD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,CA2B7D"}
@@ -22,7 +22,7 @@ Anything else is sent to the model as the next goal.
22
22
  * rather than the last question.
23
23
  */
24
24
  export async function runSession(options) {
25
- const history = [];
25
+ const history = options.history ?? [];
26
26
  const summary = {
27
27
  goals: 0,
28
28
  turns: 0,
@@ -1 +1 @@
1
- {"version":3,"file":"read-only.d.ts","sourceRoot":"","sources":["../../../src/agent/tools/read-only.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,YAAY,CAAC;AAmB9D;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAYjD;AAED,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAuBjD;AAmLD,eAAO,MAAM,eAAe,EAAE,cAAc,EAM3C,CAAC"}
1
+ {"version":3,"file":"read-only.d.ts","sourceRoot":"","sources":["../../../src/agent/tools/read-only.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,YAAY,CAAC;AAmB9D;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAYjD;AAED,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAuBjD;AAwLD,eAAO,MAAM,eAAe,EAAE,cAAc,EAM3C,CAAC"}
@@ -87,6 +87,12 @@ function walk(workspace, onFile) {
87
87
  if (entry.isDirectory()) {
88
88
  if (SKIPPED_DIRECTORIES.has(entry.name))
89
89
  continue;
90
+ // The CLI's own directories, uniformly. Dot-directories are skipped
91
+ // anyway, which covers Linux and Windows by accident - but on macOS
92
+ // the state directory is `Library/Application Support/mafdet`, so
93
+ // without this the session ids would be listed there and nowhere else.
94
+ if (workspace.isOwnedByCli(full))
95
+ continue;
90
96
  stack.push(full);
91
97
  continue;
92
98
  }
@@ -36,4 +36,47 @@ export interface Subscription {
36
36
  export declare function fetchWallet(client: HttpClient): Promise<Wallet>;
37
37
  export declare function fetchUsage(client: HttpClient, days?: number): Promise<UsageSummary>;
38
38
  export declare function fetchSubscription(client: HttpClient): Promise<Subscription>;
39
+ /**
40
+ * CLI-027 · One settled request as the ledger holds it.
41
+ *
42
+ * The whole whitelist the server returns (CLI-026): no prompt, no response, no
43
+ * tool arguments, no file content, and no session id - the CLI matches on
44
+ * `request_id` alone, which is why none of that has to leave the machine.
45
+ */
46
+ export interface LedgerUsageEvent {
47
+ request_id: string;
48
+ model_id: string;
49
+ input_tokens: number;
50
+ output_tokens: number;
51
+ platform_charge_micro_usd: string;
52
+ status: string;
53
+ created_at: string;
54
+ }
55
+ export interface UsageEventsResult {
56
+ readonly events: readonly LedgerUsageEvent[];
57
+ readonly pages: number;
58
+ /**
59
+ * True when the walk reached the end of the window.
60
+ *
61
+ * When it is false the caller stopped early, and "not found" then means "not
62
+ * found yet" - reporting it as "the ledger has no such request" would be a
63
+ * claim the walk did not earn.
64
+ */
65
+ readonly exhausted: boolean;
66
+ }
67
+ /** Hard stop on paging, so a busy key cannot turn one command into hundreds. */
68
+ export declare const MAX_USAGE_EVENT_PAGES = 20;
69
+ /**
70
+ * Walk this key's settled requests, newest first.
71
+ *
72
+ * Stops as soon as every id in `wanted` has been seen: a session of three
73
+ * requests should cost one page, not a full sweep of the window. Passing no
74
+ * `wanted` set walks until the pages run out.
75
+ */
76
+ export declare function fetchUsageEvents(client: HttpClient, options?: {
77
+ days?: number;
78
+ wanted?: ReadonlySet<string>;
79
+ maxPages?: number;
80
+ signal?: AbortSignal;
81
+ }): Promise<UsageEventsResult>;
39
82
  //# sourceMappingURL=account.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"account.d.ts","sourceRoot":"","sources":["../../src/api/account.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C;;;GAGG;AAEH,MAAM,WAAW,MAAM;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,UAAU,CAAC,EAAE;QACX,mBAAmB,EAAE,MAAM,CAAC;QAC5B,cAAc,EAAE,MAAM,CAAC;QACvB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,aAAa,EAAE,MAAM,CAAC;QACtB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AAyBD,wBAAsB,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAKrE;AAED,wBAAsB,UAAU,CAC9B,MAAM,EAAE,UAAU,EAClB,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,YAAY,CAAC,CAMvB;AAED,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,YAAY,CAAC,CAKvB"}
1
+ {"version":3,"file":"account.d.ts","sourceRoot":"","sources":["../../src/api/account.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C;;;GAGG;AAEH,MAAM,WAAW,MAAM;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,UAAU,CAAC,EAAE;QACX,mBAAmB,EAAE,MAAM,CAAC;QAC5B,cAAc,EAAE,MAAM,CAAC;QACvB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,aAAa,EAAE,MAAM,CAAC;QACtB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AAyBD,wBAAsB,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAKrE;AAED,wBAAsB,UAAU,CAC9B,MAAM,EAAE,UAAU,EAClB,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,YAAY,CAAC,CAMvB;AAED,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,YAAY,CAAC,CAKvB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,yBAAyB,EAAE,MAAM,CAAC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AAOD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC7C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAED,gFAAgF;AAChF,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAExC;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,UAAU,EAClB,OAAO,GAAE;IACP,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,WAAW,CAAC;CACjB,GACL,OAAO,CAAC,iBAAiB,CAAC,CAgC5B"}
@@ -37,3 +37,43 @@ export async function fetchSubscription(client) {
37
37
  .catch(explainScope);
38
38
  return data;
39
39
  }
40
+ /** Hard stop on paging, so a busy key cannot turn one command into hundreds. */
41
+ export const MAX_USAGE_EVENT_PAGES = 20;
42
+ /**
43
+ * Walk this key's settled requests, newest first.
44
+ *
45
+ * Stops as soon as every id in `wanted` has been seen: a session of three
46
+ * requests should cost one page, not a full sweep of the window. Passing no
47
+ * `wanted` set walks until the pages run out.
48
+ */
49
+ export async function fetchUsageEvents(client, options = {}) {
50
+ const maxPages = options.maxPages ?? MAX_USAGE_EVENT_PAGES;
51
+ const remaining = options.wanted ? new Set(options.wanted) : undefined;
52
+ const events = [];
53
+ let cursor = null;
54
+ let pages = 0;
55
+ while (pages < maxPages) {
56
+ const query = new URLSearchParams();
57
+ if (options.days !== undefined)
58
+ query.set("days", String(options.days));
59
+ if (cursor !== null)
60
+ query.set("cursor", cursor);
61
+ const { data } = await client
62
+ .getJson(`/keyinfo/usage-events?${query.toString()}`, {
63
+ signal: options.signal,
64
+ })
65
+ .catch(explainScope);
66
+ pages += 1;
67
+ for (const event of data.data ?? []) {
68
+ events.push(event);
69
+ remaining?.delete(event.request_id);
70
+ }
71
+ if (remaining !== undefined && remaining.size === 0) {
72
+ return { events, pages, exhausted: true };
73
+ }
74
+ cursor = data.next_cursor ?? null;
75
+ if (cursor === null)
76
+ return { events, pages, exhausted: true };
77
+ }
78
+ return { events, pages, exhausted: false };
79
+ }
@@ -0,0 +1,5 @@
1
+ import { ExitCode } from "../output/exit-codes.js";
2
+ import { type CommandIo } from "./runtime.js";
3
+ export declare function sessionsCommand(argv: readonly string[], io: CommandIo): Promise<ExitCode>;
4
+ export declare const DELETION_NOTICE: (id: string) => string;
5
+ //# sourceMappingURL=sessions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../src/commands/sessions.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAuBnD,OAAO,EAIL,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAgBtB,wBAAsB,eAAe,CACnC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,EAAE,EAAE,SAAS,GACZ,OAAO,CAAC,QAAQ,CAAC,CAenB;AAqID,eAAO,MAAM,eAAe,GAAI,IAAI,MAAM,KAAG,MAUX,CAAC"}