@mafdet/cli 0.3.0 → 0.4.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.
Files changed (72) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +22 -3
  3. package/README.zh-CN.md +17 -1
  4. package/dist/agent/loop.d.ts +17 -0
  5. package/dist/agent/loop.d.ts.map +1 -1
  6. package/dist/agent/loop.js +17 -7
  7. package/dist/agent/session.d.ts +8 -1
  8. package/dist/agent/session.d.ts.map +1 -1
  9. package/dist/agent/session.js +1 -1
  10. package/dist/commands/agent.d.ts +9 -0
  11. package/dist/commands/agent.d.ts.map +1 -1
  12. package/dist/commands/agent.js +3 -3
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +45 -6
  15. package/dist/tui/adapters/auth.d.ts +26 -0
  16. package/dist/tui/adapters/auth.d.ts.map +1 -0
  17. package/dist/tui/adapters/auth.js +76 -0
  18. package/dist/tui/adapters/models.d.ts +47 -0
  19. package/dist/tui/adapters/models.d.ts.map +1 -0
  20. package/dist/tui/adapters/models.js +146 -0
  21. package/dist/tui/agent-surface.d.ts +25 -0
  22. package/dist/tui/agent-surface.d.ts.map +1 -0
  23. package/dist/tui/agent-surface.js +95 -0
  24. package/dist/tui/app.d.ts +25 -0
  25. package/dist/tui/app.d.ts.map +1 -0
  26. package/dist/tui/app.js +159 -0
  27. package/dist/tui/approval.d.ts +27 -0
  28. package/dist/tui/approval.d.ts.map +1 -0
  29. package/dist/tui/approval.js +79 -0
  30. package/dist/tui/banner.d.ts +13 -0
  31. package/dist/tui/banner.d.ts.map +1 -0
  32. package/dist/tui/banner.js +97 -0
  33. package/dist/tui/input.d.ts +17 -0
  34. package/dist/tui/input.d.ts.map +1 -0
  35. package/dist/tui/input.js +57 -0
  36. package/dist/tui/interrupt.d.ts +32 -0
  37. package/dist/tui/interrupt.d.ts.map +1 -0
  38. package/dist/tui/interrupt.js +47 -0
  39. package/dist/tui/keys.d.ts +30 -0
  40. package/dist/tui/keys.d.ts.map +1 -0
  41. package/dist/tui/keys.js +86 -0
  42. package/dist/tui/onboarding.d.ts +28 -0
  43. package/dist/tui/onboarding.d.ts.map +1 -0
  44. package/dist/tui/onboarding.js +117 -0
  45. package/dist/tui/picker.d.ts +24 -0
  46. package/dist/tui/picker.d.ts.map +1 -0
  47. package/dist/tui/picker.js +146 -0
  48. package/dist/tui/resize.d.ts +22 -0
  49. package/dist/tui/resize.d.ts.map +1 -0
  50. package/dist/tui/resize.js +37 -0
  51. package/dist/tui/route.d.ts +26 -0
  52. package/dist/tui/route.d.ts.map +1 -0
  53. package/dist/tui/route.js +68 -0
  54. package/dist/tui/start-agent.d.ts +31 -0
  55. package/dist/tui/start-agent.d.ts.map +1 -0
  56. package/dist/tui/start-agent.js +82 -0
  57. package/dist/tui/terminal.d.ts +41 -0
  58. package/dist/tui/terminal.d.ts.map +1 -0
  59. package/dist/tui/terminal.js +78 -0
  60. package/dist/tui/theme.d.ts +22 -0
  61. package/dist/tui/theme.d.ts.map +1 -0
  62. package/dist/tui/theme.js +59 -0
  63. package/dist/tui/tool-card.d.ts +41 -0
  64. package/dist/tui/tool-card.d.ts.map +1 -0
  65. package/dist/tui/tool-card.js +132 -0
  66. package/dist/tui/widgets.d.ts +44 -0
  67. package/dist/tui/widgets.d.ts.map +1 -0
  68. package/dist/tui/widgets.js +137 -0
  69. package/dist/tui/workspace-summary.d.ts +10 -0
  70. package/dist/tui/workspace-summary.d.ts.map +1 -0
  71. package/dist/tui/workspace-summary.js +49 -0
  72. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -6,6 +6,49 @@ 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.0 - 2026-08-07
10
+
11
+ An interactive session. Running `mafdet` with no arguments in a terminal now
12
+ opens one: choose how to authenticate, pick a model, then work with the agent.
13
+ Everything else is unchanged; scripts are unaffected (see below).
14
+
15
+ ### The session
16
+
17
+ - The welcome page, then authentication, then a model picker that narrows as
18
+ you type, then the agent.
19
+ - Authentication offers only what the system can serve: the environment key, a
20
+ key pasted for this session only, or instructions for creating one. A pasted
21
+ key is held in memory, never written to a file and never put into the
22
+ environment.
23
+ - The model picker lists only what this key can call. Where any model has
24
+ verified tool calling, only those are offered, so a model the agent cannot
25
+ drive never becomes the default. Route RPM is reported as not published,
26
+ because the catalogue does not publish it.
27
+ - Tool calls appear as cards that move from running to succeeded, refused or
28
+ failed. Changes are shown as a diff and approved one at a time; there is no
29
+ "always allow".
30
+ - Two-stage Ctrl+C: the first cancels what is running, and a second during
31
+ cleanup forces out and says that a charge is still possible.
32
+
33
+ ### Same agent, drawn differently
34
+
35
+ The session drives the same code `mafdet agent` does, so the tools, approvals
36
+ and cost accounting cannot diverge. `--allow-write` and `--allow-command` mean
37
+ exactly what they mean there, and a session given neither has no write or
38
+ command tool loaded at all.
39
+
40
+ ### Nothing that reads the output is affected
41
+
42
+ In a pipeline, under `--json` or `--quiet`, in CI, with `TERM=dumb`, or with
43
+ `--no-tui`, `mafdet` behaves exactly as it did in 0.3: usage on stderr, exit 2.
44
+
45
+ ### Known limitations
46
+
47
+ - macOS and Windows are still unverified. Linux, WSL, tmux, SSH and SSH+tmux
48
+ were checked on real terminals.
49
+ - ASCII is still the default. The block wordmark appears only where the
50
+ encoding is known to be UTF-8: a UTF-8 locale, or Windows Terminal.
51
+
9
52
  ## 0.3.0 — 2026-08-07
10
53
 
11
54
  First published release. It contains everything through the plan's 0.3 scope,
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  The official Mafdet AI command line: model calls, account queries, and a
4
4
  permissioned local agent.
5
5
 
6
- > **0.3.0.** 中文版见 [README.zh-CN.md](./README.zh-CN.md). The CLI never
6
+ > **0.4.0.** 中文版见 [README.zh-CN.md](./README.zh-CN.md). The CLI never
7
7
  > advertises a command it cannot serve, so `mafdet help` always lists exactly
8
8
  > what works.
9
9
  >
@@ -25,10 +25,29 @@ Or build it from this repository:
25
25
 
26
26
  ```bash
27
27
  pnpm --filter @mafdet/cli build
28
- cd packages/cli && npm pack # -> mafdet-cli-0.3.0.tgz
29
- npm install -g ./mafdet-cli-0.3.0.tgz
28
+ cd packages/cli && npm pack # -> mafdet-cli-0.4.0.tgz
29
+ npm install -g ./mafdet-cli-0.4.0.tgz
30
30
  ```
31
31
 
32
+ ## The interactive session
33
+
34
+ Run `mafdet` with no arguments in a terminal and it opens a session: pick how
35
+ to authenticate, choose a model, then talk to the agent.
36
+
37
+ ```bash
38
+ mafdet # read-only
39
+ mafdet --allow-write # changes are shown as a diff and confirmed first
40
+ mafdet --allow-command "pnpm test"
41
+ ```
42
+
43
+ It is the same agent as `mafdet agent`, drawn differently - the same tools, the
44
+ same approvals, the same cost accounting. The flags mean exactly what they mean
45
+ there, and a session given neither has no write or command tool loaded at all.
46
+
47
+ `mafdet` in a pipeline, under `--json`, in CI, or with `--no-tui` behaves
48
+ exactly as it did in 0.3: usage on stderr, exit 2. Nothing that reads the
49
+ CLI's output will start receiving a drawing.
50
+
32
51
  ## Quickstart
33
52
 
34
53
  ```bash
package/README.zh-CN.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Mafdet AI 官方命令行:模型调用、账户查询,以及一个受权限约束的本地 Agent。
4
4
 
5
- > **0.3.0。** 英文版见 [README.md](./README.md)。
5
+ > **0.4.0。** 英文版见 [README.md](./README.md)。
6
6
 
7
7
  ## 环境要求
8
8
 
@@ -14,6 +14,22 @@ Node.js 20 或更高,以及一把 Mafdet API Key。
14
14
  npm install -g @mafdet/cli
15
15
  ```
16
16
 
17
+ ## 交互式会话
18
+
19
+ 在终端里不带参数直接敲 `mafdet` 就进入会话:选认证方式、选模型,然后和 Agent 对话。
20
+
21
+ ```bash
22
+ mafdet # 只读
23
+ mafdet --allow-write # 改动先展示 diff 再确认
24
+ mafdet --allow-command "pnpm test"
25
+ ```
26
+
27
+ 它和 `mafdet agent` 是**同一个 Agent**,只是画法不同——同样的工具、同样的审批、
28
+ 同样的计费。参数含义与那边完全一致,两个都不给的会话**根本没有加载**写工具和命令工具。
29
+
30
+ 管道里、`--json` 下、CI 中、或带 `--no-tui` 时,`mafdet` 的行为与 0.3 完全一样:
31
+ 用法写 stderr、exit 2。**任何读取 CLI 输出的程序都不会突然收到一个界面。**
32
+
17
33
  ## 快速开始
18
34
 
19
35
  ```bash
@@ -56,9 +56,26 @@ export interface AgentOptions {
56
56
  now?: () => number;
57
57
  random?: () => number;
58
58
  }
59
+ /**
60
+ * Progress, for whoever is drawing.
61
+ *
62
+ * The lifecycle events (`tool_started`, `tool_awaiting_approval`) were added
63
+ * for the TUI's tool cards in CLI-021. They are additive: `tool` and
64
+ * `declined` still fire exactly as before, so the line-based session renders
65
+ * unchanged and the two surfaces cannot drift on what happened - only on how
66
+ * it is shown.
67
+ */
59
68
  export type AgentEvent = {
60
69
  type: "turn";
61
70
  turn: number;
71
+ } | {
72
+ type: "tool_started";
73
+ name: string;
74
+ arguments: string;
75
+ } | {
76
+ type: "tool_awaiting_approval";
77
+ name: string;
78
+ summary: string;
62
79
  } | {
63
80
  type: "tool";
64
81
  name: string;
@@ -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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"}
@@ -101,6 +101,11 @@ export async function runAgent(options) {
101
101
  for (const call of calls) {
102
102
  if (options.signal?.aborted)
103
103
  return stop(report, "cancelled");
104
+ options.onEvent?.({
105
+ type: "tool_started",
106
+ name: call.function.name,
107
+ arguments: call.function.arguments,
108
+ });
104
109
  const { text, ok } = await runToolCall(call, byName, options);
105
110
  report.toolRuns.push({ name: call.function.name, ok });
106
111
  options.onEvent?.({
@@ -160,13 +165,18 @@ async function runToolCall(call, byName, options) {
160
165
  // An action can carry advance approval - an --allow-command entry the user
161
166
  // declared up front - which is the only way anything runs unprompted.
162
167
  const approver = options.approver;
163
- const approved = action.preApproved === true ||
164
- (approver
165
- ? await approver.approve({
166
- summary: action.summary,
167
- preview: action.preview,
168
- })
169
- : false);
168
+ let approved = action.preApproved === true;
169
+ if (!approved && approver) {
170
+ options.onEvent?.({
171
+ type: "tool_awaiting_approval",
172
+ name: tool.name,
173
+ summary: action.summary,
174
+ });
175
+ approved = await approver.approve({
176
+ summary: action.summary,
177
+ preview: action.preview,
178
+ });
179
+ }
170
180
  if (!approved) {
171
181
  options.onEvent?.({
172
182
  type: "declined",
@@ -1,7 +1,7 @@
1
1
  import type { HttpClient } from "../api/http.js";
2
2
  import type { CatalogModel } from "../api/models.js";
3
3
  import type { Approver } from "./approvals.js";
4
- import { type ChatMessage } from "./loop.js";
4
+ import { type AgentEvent, type ChatMessage } from "./loop.js";
5
5
  import type { ToolContext, ToolDefinition } from "./tools/types.js";
6
6
  export interface SessionOptions {
7
7
  client: HttpClient;
@@ -25,6 +25,13 @@ export interface SessionOptions {
25
25
  */
26
26
  readLine?: () => Promise<string | undefined>;
27
27
  signal?: AbortSignal;
28
+ /**
29
+ * Where progress goes. Defaults to the line-based rendering below; the TUI
30
+ * (CLI-021) supplies its own so that both surfaces share this session's
31
+ * conversation, cost accounting and approval flow, and differ only in how
32
+ * the same events are drawn.
33
+ */
34
+ onEvent?: (event: AgentEvent) => void;
28
35
  }
29
36
  export interface SessionSummary {
30
37
  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,EAA6B,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;CACtB;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;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"}
@@ -80,7 +80,7 @@ export async function runSession(options) {
80
80
  history,
81
81
  approver: options.approver,
82
82
  signal: options.signal,
83
- onEvent: (event) => reportEvent(event, options),
83
+ onEvent: options.onEvent ?? ((event) => reportEvent(event, options)),
84
84
  });
85
85
  summary.turns += report.turns;
86
86
  summary.modelRequests += report.modelRequests;
@@ -1,5 +1,8 @@
1
+ import { type ApprovalMode } from "../agent/approvals.js";
1
2
  import { ExitCode } from "../output/exit-codes.js";
2
3
  import { type CommandIo } from "./runtime.js";
4
+ export declare const READ_ONLY_PROMPT = "You are the Mafdet CLI agent working inside a user's workspace.\n\nUse the provided tools to inspect the workspace. You cannot modify anything:\nthere are no write or shell tools, so do not claim to have changed a file.\nRead before you conclude - never guess a file's contents. When you have the\nanswer, reply with it directly instead of calling another tool. Be concise.";
5
+ export declare const WRITE_PROMPT = "You are the Mafdet CLI agent working inside a user's workspace.\n\nInspect with the read tools, and change files with edit_file and create_file.\nAlways read a file before editing it, and quote old_text exactly as it appears,\nwith enough surrounding lines to be unique - a near miss is refused rather than\nguessed at. Every change is shown to the user and applied only if they accept\nit; if one is declined, do not retry the same change. There is no shell, so do\nnot claim to have run anything. Be concise.";
3
6
  export interface AgentIo extends CommandIo {
4
7
  signal?: AbortSignal;
5
8
  /** Overridden in tests; production reads the TTY. */
@@ -7,4 +10,10 @@ export interface AgentIo extends CommandIo {
7
10
  approver?: import("../agent/approvals.js").Approver;
8
11
  }
9
12
  export declare function agentCommand(argv: readonly string[], io: AgentIo): Promise<ExitCode>;
13
+ /**
14
+ * A tool the run cannot use is not offered at all. Read-only means the model
15
+ * never sees a write tool, and run_command appears only when the user named at
16
+ * least one allowed command or can approve interactively.
17
+ */
18
+ export declare function buildToolset(mode: ApprovalMode, hasAllowedCommands: boolean): import("../agent/tools/types.js").ToolDefinition<import("zod").ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>>[];
10
19
  //# sourceMappingURL=agent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/commands/agent.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAGnD,OAAO,EAIL,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AA6BtB,MAAM,WAAW,OAAQ,SAAQ,SAAS;IACxC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,qDAAqD;IACrD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,uBAAuB,EAAE,QAAQ,CAAC;CACrD;AAED,wBAAsB,YAAY,CAChC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,EAAE,EAAE,OAAO,GACV,OAAO,CAAC,QAAQ,CAAC,CA+GnB"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/commands/agent.ts"],"names":[],"mappings":"AAKA,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAOvE,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAGnD,OAAO,EAIL,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAatB,eAAO,MAAM,gBAAgB,0XAK+C,CAAC;AAE7E,eAAO,MAAM,YAAY,mgBAOmB,CAAC;AAE7C,MAAM,WAAW,OAAQ,SAAQ,SAAS;IACxC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,qDAAqD;IACrD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,uBAAuB,EAAE,QAAQ,CAAC;CACrD;AAED,wBAAsB,YAAY,CAChC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,EAAE,EAAE,OAAO,GACV,OAAO,CAAC,QAAQ,CAAC,CA+GnB;AAgFD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,YAAY,EAAE,kBAAkB,EAAE,OAAO,0JAI3E"}
@@ -20,13 +20,13 @@ and every change is shown as a diff and confirmed before it is written. There
20
20
  is no flag that approves everything in advance, and a non-interactive run
21
21
  cannot write at all.
22
22
  `;
23
- const READ_ONLY_PROMPT = `You are the Mafdet CLI agent working inside a user's workspace.
23
+ export const READ_ONLY_PROMPT = `You are the Mafdet CLI agent working inside a user's workspace.
24
24
 
25
25
  Use the provided tools to inspect the workspace. You cannot modify anything:
26
26
  there are no write or shell tools, so do not claim to have changed a file.
27
27
  Read before you conclude - never guess a file's contents. When you have the
28
28
  answer, reply with it directly instead of calling another tool. Be concise.`;
29
- const WRITE_PROMPT = `You are the Mafdet CLI agent working inside a user's workspace.
29
+ export const WRITE_PROMPT = `You are the Mafdet CLI agent working inside a user's workspace.
30
30
 
31
31
  Inspect with the read tools, and change files with edit_file and create_file.
32
32
  Always read a file before editing it, and quote old_text exactly as it appears,
@@ -205,7 +205,7 @@ function parseArgs(argv, io) {
205
205
  * never sees a write tool, and run_command appears only when the user named at
206
206
  * least one allowed command or can approve interactively.
207
207
  */
208
- function buildToolset(mode, hasAllowedCommands) {
208
+ export function buildToolset(mode, hasAllowedCommands) {
209
209
  if (mode === "read-only" && !hasAllowedCommands)
210
210
  return READ_ONLY_TOOLS;
211
211
  if (mode === "read-only")
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAcA,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AA+ClD,wBAAsB,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CA4DpE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAcA,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAgDlD,wBAAsB,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAsGpE"}
package/dist/index.js CHANGED
@@ -11,6 +11,7 @@ import { embedCommand } from "./commands/embed.js";
11
11
  import { speechCommand } from "./commands/speech.js";
12
12
  import { modelsCommand } from "./commands/models.js";
13
13
  import { ExitCode } from "./output/exit-codes.js";
14
+ import { decideEntry, explainRefusal } from "./tui/route.js";
14
15
  // Read from the installed package rather than baking a literal in at build
15
16
  // time, so `mafdet --version` can never disagree with what npm installed.
16
17
  function version() {
@@ -54,12 +55,8 @@ async function readStdin() {
54
55
  }
55
56
  export async function run(argv) {
56
57
  const [command] = argv;
57
- if (command === undefined) {
58
- // Not an error the user asked for, but not a result either: usage goes to
59
- // stderr so a bare `mafdet` in a pipeline never pollutes stdout.
60
- process.stderr.write(HELP);
61
- return ExitCode.Usage;
62
- }
58
+ // Asking for help or the version is always answered the same way, terminal
59
+ // or not. These come first so that neither can be swallowed by the TUI.
63
60
  if (command === "help" || command === "--help" || command === "-h") {
64
61
  process.stdout.write(HELP);
65
62
  return ExitCode.Ok;
@@ -68,6 +65,48 @@ export async function run(argv) {
68
65
  process.stdout.write(`${version()}\n`);
69
66
  return ExitCode.Ok;
70
67
  }
68
+ // CLI-018: a bare `mafdet` (or one carrying only flags) opens the TUI on an
69
+ // interactive terminal, and keeps its 0.3 behaviour everywhere else.
70
+ // `mafdet <command>` never reaches this branch, so the command surface and
71
+ // its exit codes are untouched.
72
+ if (command === undefined || command.startsWith("-")) {
73
+ const decision = decideEntry({
74
+ argv,
75
+ stdinIsTTY: process.stdin.isTTY === true,
76
+ stdoutIsTTY: process.stdout.isTTY === true,
77
+ env: process.env,
78
+ });
79
+ if (decision.kind === "tui") {
80
+ // Imported here, not at the top: the command path must not pay for
81
+ // loading the TUI, and `mafdet version` staying fast is the check.
82
+ const { runTui } = await import("./tui/app.js");
83
+ return runTui({
84
+ version: version(),
85
+ workspace: process.cwd(),
86
+ stdout: process.stdout,
87
+ stderr: process.stderr,
88
+ stdin: process.stdin,
89
+ env: process.env,
90
+ host: process,
91
+ columns: process.stdout.columns,
92
+ argv,
93
+ commandIo: {
94
+ stdout: (text) => process.stdout.write(text),
95
+ stderr: (text) => process.stderr.write(text),
96
+ env: process.env,
97
+ cwd: process.cwd(),
98
+ version: version(),
99
+ },
100
+ });
101
+ }
102
+ // Not an error the user asked for, but not a result either: usage goes to
103
+ // stderr so a bare `mafdet` in a pipeline never pollutes stdout.
104
+ process.stderr.write(HELP);
105
+ if (decision.kind === "usage") {
106
+ process.stderr.write(`\nmafdet: ${explainRefusal(decision.refusedBecause)}.\n`);
107
+ }
108
+ return ExitCode.Usage;
109
+ }
71
110
  const io = {
72
111
  stdout: (text) => process.stdout.write(text),
73
112
  stderr: (text) => process.stderr.write(text),
@@ -0,0 +1,26 @@
1
+ import { type CommandIo } from "../../commands/runtime.js";
2
+ export interface KeyDiagnosis {
3
+ readonly ok: boolean;
4
+ /** Never the key itself. `sk-mafdet-live-<redacted>`, as everywhere else. */
5
+ readonly fingerprint: string;
6
+ readonly modelCount: number;
7
+ /** Undefined when account:read was not granted - not an error. */
8
+ readonly balance?: string;
9
+ /** Present when account:read is missing, so the UI can say so once. */
10
+ readonly missingAccountRead: boolean;
11
+ /** Set when the key does not work at all. Already redacted. */
12
+ readonly problem?: string;
13
+ }
14
+ export interface DiagnoseOptions {
15
+ readonly apiKey: string;
16
+ readonly io: CommandIo;
17
+ }
18
+ /**
19
+ * Verify a key with the cheapest calls that prove it works.
20
+ *
21
+ * Deliberately never a model completion: asking a model to prove a key is
22
+ * valid spends the user's money to learn something a catalogue read already
23
+ * tells us.
24
+ */
25
+ export declare function diagnoseKey(options: DiagnoseOptions): Promise<KeyDiagnosis>;
26
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/tui/adapters/auth.ts"],"names":[],"mappings":"AAUA,OAAO,EAAgB,KAAK,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAIzE,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,6EAA6E;IAC7E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,kEAAkE;IAClE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,uEAAuE;IACvE,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;IACrC,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,EAAE,SAAS,CAAC;CACxB;AAED;;;;;;GAMG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,YAAY,CAAC,CA4CvB"}
@@ -0,0 +1,76 @@
1
+ // CLI-019 · Checking a key, using the machinery that already exists.
2
+ //
3
+ // The TUI owns no API client and no idea of what a valid key is. It calls the
4
+ // same two planes `doctor` does, and it reaches them by building a runtime
5
+ // over an env object it constructs - never by writing to process.env, so a
6
+ // session-only key cannot leak into a child process or a later read.
7
+ import { ApiError } from "../../api/errors.js";
8
+ import { fetchAccessibleModels } from "../../api/models.js";
9
+ import { fetchWallet } from "../../api/account.js";
10
+ import { buildRuntime } from "../../commands/runtime.js";
11
+ import { formatUsd } from "../../output/money.js";
12
+ import { keyFingerprint } from "../../security/redact.js";
13
+ /**
14
+ * Verify a key with the cheapest calls that prove it works.
15
+ *
16
+ * Deliberately never a model completion: asking a model to prove a key is
17
+ * valid spends the user's money to learn something a catalogue read already
18
+ * tells us.
19
+ */
20
+ export async function diagnoseKey(options) {
21
+ const fingerprint = keyFingerprint(options.apiKey);
22
+ // A constructed env, not process.env: the key stays inside this call.
23
+ const runtime = buildRuntime({
24
+ ...options.io,
25
+ env: { ...options.io.env, MAFDET_API_KEY: options.apiKey },
26
+ });
27
+ let modelCount = 0;
28
+ try {
29
+ const models = await fetchAccessibleModels(runtime.dataPlane);
30
+ modelCount = models.length;
31
+ }
32
+ catch (error) {
33
+ return {
34
+ ok: false,
35
+ fingerprint,
36
+ modelCount: 0,
37
+ missingAccountRead: false,
38
+ problem: describeAuthFailure(error),
39
+ };
40
+ }
41
+ // account:read is optional. Without it model calls still work, so its
42
+ // absence downgrades the display and nothing else.
43
+ try {
44
+ const wallet = await fetchWallet(runtime.accountPlane);
45
+ return {
46
+ ok: true,
47
+ fingerprint,
48
+ modelCount,
49
+ balance: formatUsd(wallet.available_micro_usd),
50
+ missingAccountRead: false,
51
+ };
52
+ }
53
+ catch (error) {
54
+ const scopeProblem = error instanceof ApiError && error.kind === "auth";
55
+ return {
56
+ ok: true,
57
+ fingerprint,
58
+ modelCount,
59
+ missingAccountRead: scopeProblem,
60
+ problem: scopeProblem ? undefined : describeAuthFailure(error),
61
+ };
62
+ }
63
+ }
64
+ /**
65
+ * A sentence for the welcome page. ApiError redacts on construction, so this
66
+ * cannot reintroduce a key that the error was carrying.
67
+ */
68
+ function describeAuthFailure(error) {
69
+ if (error instanceof ApiError) {
70
+ if (error.kind === "auth") {
71
+ return "the key was rejected - check it was copied whole, and that it is not revoked";
72
+ }
73
+ return error.message;
74
+ }
75
+ return error instanceof Error ? error.message : String(error);
76
+ }
@@ -0,0 +1,47 @@
1
+ import { type ModelSets, type ResolvedModel } from "../../api/models.js";
2
+ import { type CommandIo } from "../../commands/runtime.js";
3
+ /**
4
+ * The catalogue does not publish a per-route RPM - checked against the live
5
+ * `/models` response, which has 31 models and no rate field at all. Plan §19.5
6
+ * says to show `unknown` rather than guess from the model id, so this constant
7
+ * exists to make the absence explicit instead of quietly dropping the column.
8
+ */
9
+ export declare const ROUTE_RPM_AVAILABLE = false;
10
+ export interface ModelCatalogue extends ModelSets {
11
+ /** Callable, described, chat-surface models: what the picker lists. */
12
+ readonly chat: readonly ResolvedModel[];
13
+ /** Of those, the ones the agent is allowed to drive. */
14
+ readonly agentReady: readonly ResolvedModel[];
15
+ }
16
+ export declare function loadCatalogue(options: {
17
+ readonly apiKey: string;
18
+ readonly io: CommandIo;
19
+ }): Promise<ModelCatalogue>;
20
+ /** One line of facts under a model's name. Only what the catalogue states. */
21
+ export declare function describeModel(model: ResolvedModel): string;
22
+ /**
23
+ * Filter by a typed query. Matches the id, the display name, the provider and
24
+ * the capabilities, so "tool", "deepseek" and "flash" all narrow the list the
25
+ * way a user would expect.
26
+ */
27
+ export declare function filterModels(models: readonly ResolvedModel[], query: string): readonly ResolvedModel[];
28
+ export interface SaveResult {
29
+ readonly saved: boolean;
30
+ /** Shown to the user: they should know where a preference landed. */
31
+ readonly path: string;
32
+ readonly problem?: string;
33
+ }
34
+ /**
35
+ * Remember a default model in the user config.
36
+ *
37
+ * Only `model` is written, and the existing file is re-validated on the way
38
+ * through, so this can never introduce a credential or an endpoint into a file
39
+ * that is not allowed to carry one. The write is atomic: a crash must not
40
+ * leave a half-written config that the next run refuses to parse.
41
+ */
42
+ export declare function saveDefaultModel(options: {
43
+ readonly modelId: string;
44
+ readonly env: NodeJS.ProcessEnv;
45
+ readonly configPath?: string;
46
+ }): SaveResult;
47
+ //# sourceMappingURL=models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../../src/tui/adapters/models.ts"],"names":[],"mappings":"AAiBA,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,aAAa,EACnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAgB,KAAK,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAKzE;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,QAAQ,CAAC;AAEzC,MAAM,WAAW,cAAe,SAAQ,SAAS;IAC/C,uEAAuE;IACvE,QAAQ,CAAC,IAAI,EAAE,SAAS,aAAa,EAAE,CAAC;IACxC,wDAAwD;IACxD,QAAQ,CAAC,UAAU,EAAE,SAAS,aAAa,EAAE,CAAC;CAC/C;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAC3C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,EAAE,SAAS,CAAC;CACxB,GAAG,OAAO,CAAC,cAAc,CAAC,CAoB1B;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAkB1D;AASD;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,SAAS,aAAa,EAAE,EAChC,KAAK,EAAE,MAAM,GACZ,SAAS,aAAa,EAAE,CAgB1B;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,qEAAqE;IACrE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE;IACxC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAChC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B,GAAG,UAAU,CA8Cb"}