@mafdet/cli 0.4.0-preview.0 → 0.4.1
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/CHANGELOG.md +18 -2
- package/README.md +5 -6
- package/README.zh-CN.md +3 -4
- package/dist/tui/agent-surface.d.ts +7 -0
- package/dist/tui/agent-surface.d.ts.map +1 -1
- package/dist/tui/agent-surface.js +11 -2
- package/dist/tui/app.d.ts.map +1 -1
- package/dist/tui/app.js +43 -2
- package/dist/tui/input.d.ts +13 -1
- package/dist/tui/input.d.ts.map +1 -1
- package/dist/tui/input.js +9 -2
- package/dist/tui/start-agent.d.ts +7 -1
- package/dist/tui/start-agent.d.ts.map +1 -1
- package/dist/tui/start-agent.js +3 -1
- package/package.json +2 -3
package/CHANGELOG.md
CHANGED
|
@@ -6,11 +6,27 @@ 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.
|
|
9
|
+
## 0.4.1 - 2026-08-07
|
|
10
|
+
|
|
11
|
+
Fixes Ctrl+C in the interactive session, which did nothing while a model
|
|
12
|
+
request was in flight - the request ran to completion and only then did the
|
|
13
|
+
CLI respond, so it looked like a hang.
|
|
14
|
+
|
|
15
|
+
Two things went wrong. In raw mode Ctrl+C arrives as a byte rather than a
|
|
16
|
+
signal, and nothing was reading keys during a request, so the byte simply
|
|
17
|
+
queued. And the two-stage interrupt logic, though written and unit-tested, was
|
|
18
|
+
never connected to the session.
|
|
19
|
+
|
|
20
|
+
Now the first press cancels the request in flight - the connection is closed,
|
|
21
|
+
verified against a server that records the hang-up - and the session returns to
|
|
22
|
+
the prompt. A press at the prompt exits, and a second press during cleanup
|
|
23
|
+
forces out and says that a charge is still possible.
|
|
24
|
+
|
|
25
|
+
## 0.4.0 - 2026-08-07
|
|
10
26
|
|
|
11
27
|
An interactive session. Running `mafdet` with no arguments in a terminal now
|
|
12
28
|
opens one: choose how to authenticate, pick a model, then work with the agent.
|
|
13
|
-
Everything else is unchanged
|
|
29
|
+
Everything else is unchanged; scripts are unaffected (see below).
|
|
14
30
|
|
|
15
31
|
### The session
|
|
16
32
|
|
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.4.
|
|
6
|
+
> **0.4.1.** 中文版见 [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
|
>
|
|
@@ -18,19 +18,18 @@ Node.js 20 or newer, and a Mafdet API key.
|
|
|
18
18
|
## Install
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
|
-
npm install -g @mafdet/cli
|
|
22
|
-
npm install -g @mafdet/cli@preview # 0.4.0 preview, with the interactive UI
|
|
21
|
+
npm install -g @mafdet/cli
|
|
23
22
|
```
|
|
24
23
|
|
|
25
24
|
Or build it from this repository:
|
|
26
25
|
|
|
27
26
|
```bash
|
|
28
27
|
pnpm --filter @mafdet/cli build
|
|
29
|
-
cd packages/cli && npm pack # -> mafdet-cli-0.4.
|
|
30
|
-
npm install -g ./mafdet-cli-0.4.
|
|
28
|
+
cd packages/cli && npm pack # -> mafdet-cli-0.4.1.tgz
|
|
29
|
+
npm install -g ./mafdet-cli-0.4.1.tgz
|
|
31
30
|
```
|
|
32
31
|
|
|
33
|
-
## The interactive session
|
|
32
|
+
## The interactive session
|
|
34
33
|
|
|
35
34
|
Run `mafdet` with no arguments in a terminal and it opens a session: pick how
|
|
36
35
|
to authenticate, choose a model, then talk to the agent.
|
package/README.zh-CN.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Mafdet AI 官方命令行:模型调用、账户查询,以及一个受权限约束的本地 Agent。
|
|
4
4
|
|
|
5
|
-
> **0.4.
|
|
5
|
+
> **0.4.1。** 英文版见 [README.md](./README.md)。
|
|
6
6
|
|
|
7
7
|
## 环境要求
|
|
8
8
|
|
|
@@ -11,11 +11,10 @@ Node.js 20 或更高,以及一把 Mafdet API Key。
|
|
|
11
11
|
## 安装
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
npm install -g @mafdet/cli
|
|
15
|
-
npm install -g @mafdet/cli@preview # 0.4.0 预览版,带交互界面
|
|
14
|
+
npm install -g @mafdet/cli
|
|
16
15
|
```
|
|
17
16
|
|
|
18
|
-
##
|
|
17
|
+
## 交互式会话
|
|
19
18
|
|
|
20
19
|
在终端里不带参数直接敲 `mafdet` 就进入会话:选认证方式、选模型,然后和 Agent 对话。
|
|
21
20
|
|
|
@@ -9,6 +9,13 @@ export interface AgentSurfaceOptions {
|
|
|
9
9
|
};
|
|
10
10
|
/** Everything runSession needs except the parts this surface supplies. */
|
|
11
11
|
readonly session: Omit<SessionOptions, "stdout" | "stderr" | "readLine" | "approver" | "onEvent">;
|
|
12
|
+
/**
|
|
13
|
+
* Read fresh for every turn, so a cancelled request can be followed by a new
|
|
14
|
+
* one. Passed as a function rather than a getter on `session`: the spread
|
|
15
|
+
* below would evaluate a getter once and copy the result, quietly freezing
|
|
16
|
+
* the signal to whatever controller existed at startup.
|
|
17
|
+
*/
|
|
18
|
+
readonly getSignal?: () => AbortSignal | undefined;
|
|
12
19
|
/** Injected by the tests; production uses runSession. */
|
|
13
20
|
readonly run?: typeof runSession;
|
|
14
21
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-surface.d.ts","sourceRoot":"","sources":["../../src/tui/agent-surface.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,UAAU,EACV,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,qBAAqB,CAAC;AAI7B,OAAO,EAAW,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEhE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IACtB,QAAQ,CAAC,YAAY,EAAE,oBAAoB,CAAC;IAC5C,QAAQ,CAAC,MAAM,EAAE;QAAE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAClD,0EAA0E;IAC1E,QAAQ,CAAC,OAAO,EAAE,IAAI,CACpB,cAAc,EACd,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,CAC1D,CAAC;IACF,yDAAyD;IACzD,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,UAAU,CAAC;CAClC;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA+B7B;AAED,wBAAsB,eAAe,CACnC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,cAAc,CAAC,
|
|
1
|
+
{"version":3,"file":"agent-surface.d.ts","sourceRoot":"","sources":["../../src/tui/agent-surface.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,UAAU,EACV,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,qBAAqB,CAAC;AAI7B,OAAO,EAAW,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEhE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IACtB,QAAQ,CAAC,YAAY,EAAE,oBAAoB,CAAC;IAC5C,QAAQ,CAAC,MAAM,EAAE;QAAE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAClD,0EAA0E;IAC1E,QAAQ,CAAC,OAAO,EAAE,IAAI,CACpB,cAAc,EACd,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,CAC1D,CAAC;IACF;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,WAAW,GAAG,SAAS,CAAC;IACnD,yDAAyD;IACzD,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,UAAU,CAAC;CAClC;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA+B7B;AAED,wBAAsB,eAAe,CACnC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,cAAc,CAAC,CA6CzB;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,cAAc,EACvB,YAAY,EAAE,oBAAoB,GACjC,MAAM,CAgBR"}
|
|
@@ -67,7 +67,7 @@ export async function runAgentSurface(options) {
|
|
|
67
67
|
options.stdout.write(dim(` rate limited - waiting ${Math.round(event.waitMs / 1000)}s\n`));
|
|
68
68
|
}
|
|
69
69
|
};
|
|
70
|
-
const
|
|
70
|
+
const sessionOptions = {
|
|
71
71
|
...options.session,
|
|
72
72
|
stdout: (text) => void options.stdout.write(text),
|
|
73
73
|
// The line session sends progress to stderr so it survives redirection.
|
|
@@ -76,7 +76,16 @@ export async function runAgentSurface(options) {
|
|
|
76
76
|
approver: tuiApprover(io),
|
|
77
77
|
readLine: () => promptLine(io, "> "),
|
|
78
78
|
onEvent,
|
|
79
|
-
}
|
|
79
|
+
};
|
|
80
|
+
// Installed after the spread, on purpose - see getSignal above.
|
|
81
|
+
if (options.getSignal !== undefined) {
|
|
82
|
+
Object.defineProperty(sessionOptions, "signal", {
|
|
83
|
+
get: options.getSignal,
|
|
84
|
+
enumerable: true,
|
|
85
|
+
configurable: true,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
const summary = await run(sessionOptions);
|
|
80
89
|
options.stdout.write(renderSummary(summary, capabilities));
|
|
81
90
|
return summary;
|
|
82
91
|
}
|
package/dist/tui/app.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/tui/app.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/tui/app.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAaxD,OAAO,EAAwB,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAQrE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE;QAAE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAClD,QAAQ,CAAC,MAAM,EAAE;QAAE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAClD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,UAAU,GAAG;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACzE,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IAC3D,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC;AAED,wBAAsB,MAAM,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAgInE"}
|
package/dist/tui/app.js
CHANGED
|
@@ -9,6 +9,7 @@ import { ExitCode } from "../output/exit-codes.js";
|
|
|
9
9
|
import { loadCatalogue, saveDefaultModel } from "./adapters/models.js";
|
|
10
10
|
import { renderBanner } from "./banner.js";
|
|
11
11
|
import { keyboard } from "./input.js";
|
|
12
|
+
import { FORCED_EXIT_NOTICE, InterruptTracker } from "./interrupt.js";
|
|
12
13
|
import { runOnboarding } from "./onboarding.js";
|
|
13
14
|
import { noAgentModelsNotice, pickModel } from "./picker.js";
|
|
14
15
|
import { palette, detectCapabilities, } from "./theme.js";
|
|
@@ -35,10 +36,46 @@ export async function runTui(options) {
|
|
|
35
36
|
options.stderr.write(`mafdet: ${message}\n`);
|
|
36
37
|
},
|
|
37
38
|
});
|
|
38
|
-
|
|
39
|
+
// Two-stage Ctrl+C (plan 19.7). In raw mode Ctrl+C arrives as a byte rather
|
|
40
|
+
// than a signal, and during a model request nothing is reading keys - so
|
|
41
|
+
// without this it did nothing at all until the request finished by itself.
|
|
42
|
+
const interrupts = new InterruptTracker();
|
|
43
|
+
let inFlight;
|
|
44
|
+
const { dim } = palette(capabilities);
|
|
45
|
+
const onInterrupt = () => {
|
|
46
|
+
const outcome = interrupts.press();
|
|
47
|
+
if (outcome.action === "cancel-operation") {
|
|
48
|
+
options.stdout.write(dim("\n cancelling...\n"));
|
|
49
|
+
// Abort what is running, then hand the session a fresh controller so it
|
|
50
|
+
// returns to the prompt instead of ending.
|
|
51
|
+
inFlight?.abort();
|
|
52
|
+
inFlight = new AbortController();
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
if (outcome.action === "force-exit") {
|
|
56
|
+
options.stdout.write(`\n ${FORCED_EXIT_NOTICE}\n`);
|
|
57
|
+
guard.restore();
|
|
58
|
+
options.host.exit(130);
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
// Idle: leave it to whatever is reading, which already treats Ctrl+C as
|
|
62
|
+
// "cancel this prompt" and ends the session.
|
|
63
|
+
return false;
|
|
64
|
+
};
|
|
65
|
+
const keys = keyboard(options.stdin, { onInterrupt });
|
|
39
66
|
const io = {
|
|
40
67
|
write: (text) => void options.stdout.write(text),
|
|
41
|
-
|
|
68
|
+
// Waiting for input is exactly what "idle" means, so the tracker learns it
|
|
69
|
+
// here rather than by being told from inside the session.
|
|
70
|
+
nextKeys: async () => {
|
|
71
|
+
interrupts.finish();
|
|
72
|
+
try {
|
|
73
|
+
return await keys.nextKeys();
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
interrupts.begin();
|
|
77
|
+
}
|
|
78
|
+
},
|
|
42
79
|
capabilities,
|
|
43
80
|
};
|
|
44
81
|
try {
|
|
@@ -76,6 +113,10 @@ export async function runTui(options) {
|
|
|
76
113
|
model: chosen,
|
|
77
114
|
workspace: options.workspace,
|
|
78
115
|
permissions: parsePermissions(options.argv),
|
|
116
|
+
getSignal: () => {
|
|
117
|
+
inFlight ??= new AbortController();
|
|
118
|
+
return inFlight.signal;
|
|
119
|
+
},
|
|
79
120
|
});
|
|
80
121
|
}
|
|
81
122
|
finally {
|
package/dist/tui/input.d.ts
CHANGED
|
@@ -13,5 +13,17 @@ export interface RawStdin {
|
|
|
13
13
|
off?(event: string, listener: (chunk: string) => void): unknown;
|
|
14
14
|
readonly isTTY?: boolean;
|
|
15
15
|
}
|
|
16
|
-
export
|
|
16
|
+
export interface KeyboardOptions {
|
|
17
|
+
/**
|
|
18
|
+
* Called the moment an interrupt key is decoded, whether or not anyone is
|
|
19
|
+
* waiting for input. Return true to consume it, so a Ctrl+C that cancelled a
|
|
20
|
+
* request is not also delivered to the prompt as "quit".
|
|
21
|
+
*
|
|
22
|
+
* Without this the byte simply queued: in raw mode Ctrl+C is not a signal,
|
|
23
|
+
* and during a model request nothing is calling nextKeys(), so pressing it
|
|
24
|
+
* did nothing at all until the request finished on its own.
|
|
25
|
+
*/
|
|
26
|
+
readonly onInterrupt?: () => boolean;
|
|
27
|
+
}
|
|
28
|
+
export declare function keyboard(stdin: RawStdin, options?: KeyboardOptions): KeySource;
|
|
17
29
|
//# sourceMappingURL=input.d.ts.map
|
package/dist/tui/input.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/tui/input.ts"],"names":[],"mappings":"AAQA,OAAO,EAAc,KAAK,GAAG,EAAE,MAAM,WAAW,CAAC;AAEjD,MAAM,WAAW,SAAS;IACxB,QAAQ,IAAI,OAAO,CAAC,SAAS,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC;IAChD,4DAA4D;IAC5D,KAAK,IAAI,IAAI,CAAC;CACf;AAED,MAAM,WAAW,QAAQ;IACvB,UAAU,CAAC,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IACpC,MAAM,CAAC,IAAI,OAAO,CAAC;IACnB,KAAK,CAAC,IAAI,OAAO,CAAC;IAClB,WAAW,CAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IACxC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC;IAC9D,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC;IAChE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,
|
|
1
|
+
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/tui/input.ts"],"names":[],"mappings":"AAQA,OAAO,EAAc,KAAK,GAAG,EAAE,MAAM,WAAW,CAAC;AAEjD,MAAM,WAAW,SAAS;IACxB,QAAQ,IAAI,OAAO,CAAC,SAAS,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC;IAChD,4DAA4D;IAC5D,KAAK,IAAI,IAAI,CAAC;CACf;AAED,MAAM,WAAW,QAAQ;IACvB,UAAU,CAAC,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IACpC,MAAM,CAAC,IAAI,OAAO,CAAC;IACnB,KAAK,CAAC,IAAI,OAAO,CAAC;IAClB,WAAW,CAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IACxC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC;IAC9D,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC;IAChE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B;;;;;;;;OAQG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC;CACtC;AAED,wBAAgB,QAAQ,CACtB,KAAK,EAAE,QAAQ,EACf,OAAO,GAAE,eAAoB,GAC5B,SAAS,CAsDX"}
|
package/dist/tui/input.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// that arrives is decoded and kept, and a widget asking for input drains the
|
|
7
7
|
// queue before it waits.
|
|
8
8
|
import { decodeKeys } from "./keys.js";
|
|
9
|
-
export function keyboard(stdin) {
|
|
9
|
+
export function keyboard(stdin, options = {}) {
|
|
10
10
|
const pending = [];
|
|
11
11
|
let waiting;
|
|
12
12
|
let ended = false;
|
|
@@ -21,7 +21,14 @@ export function keyboard(stdin) {
|
|
|
21
21
|
pending.push([...keys]);
|
|
22
22
|
};
|
|
23
23
|
const onData = (chunk) => {
|
|
24
|
-
|
|
24
|
+
let keys = decodeKeys(chunk);
|
|
25
|
+
if (options.onInterrupt !== undefined &&
|
|
26
|
+
keys.some((k) => k.kind === "interrupt")) {
|
|
27
|
+
// Handled out of band; only drop the key if the handler took it.
|
|
28
|
+
const consumed = options.onInterrupt();
|
|
29
|
+
if (consumed)
|
|
30
|
+
keys = keys.filter((k) => k.kind !== "interrupt");
|
|
31
|
+
}
|
|
25
32
|
if (keys.length > 0)
|
|
26
33
|
deliver(keys);
|
|
27
34
|
};
|
|
@@ -25,7 +25,13 @@ export interface StartAgentOptions {
|
|
|
25
25
|
readonly model: ResolvedModel;
|
|
26
26
|
readonly workspace: string;
|
|
27
27
|
readonly permissions: AgentPermissions;
|
|
28
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Read fresh for every goal. A cancel aborts the request in flight and then
|
|
30
|
+
* swaps in a new controller, so the session survives Ctrl+C instead of
|
|
31
|
+
* ending on it - runSession re-reads `signal` each turn, which is what makes
|
|
32
|
+
* that possible.
|
|
33
|
+
*/
|
|
34
|
+
readonly getSignal?: () => AbortSignal | undefined;
|
|
29
35
|
}
|
|
30
36
|
export declare function startAgent(options: StartAgentOptions): Promise<ExitCode>;
|
|
31
37
|
//# sourceMappingURL=start-agent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"start-agent.d.ts","sourceRoot":"","sources":["../../src/tui/start-agent.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAgB,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEtE,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEnD,OAAO,EAAW,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7C;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,gBAAgB,CAe1E;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IACtB,QAAQ,CAAC,YAAY,EAAE,oBAAoB,CAAC;IAC5C,QAAQ,CAAC,MAAM,EAAE;QAAE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAClD,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC;IACvC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"start-agent.d.ts","sourceRoot":"","sources":["../../src/tui/start-agent.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAgB,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEtE,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEnD,OAAO,EAAW,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7C;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,gBAAgB,CAe1E;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IACtB,QAAQ,CAAC,YAAY,EAAE,oBAAoB,CAAC;IAC5C,QAAQ,CAAC,MAAM,EAAE;QAAE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IAClD,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC;IACvC;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,WAAW,GAAG,SAAS,CAAC;CACpD;AAED,wBAAsB,UAAU,CAC9B,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,QAAQ,CAAC,CA0DnB"}
|
package/dist/tui/start-agent.js
CHANGED
|
@@ -62,6 +62,9 @@ export async function startAgent(options) {
|
|
|
62
62
|
io: options.io,
|
|
63
63
|
capabilities: options.capabilities,
|
|
64
64
|
stdout: options.stdout,
|
|
65
|
+
...(options.getSignal === undefined
|
|
66
|
+
? {}
|
|
67
|
+
: { getSignal: options.getSignal }),
|
|
65
68
|
session: {
|
|
66
69
|
client: runtime.dataPlane,
|
|
67
70
|
model: options.model.modelId,
|
|
@@ -75,7 +78,6 @@ export async function startAgent(options) {
|
|
|
75
78
|
},
|
|
76
79
|
mode,
|
|
77
80
|
allowedCommands: options.permissions.allowedCommands,
|
|
78
|
-
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
79
81
|
},
|
|
80
82
|
});
|
|
81
83
|
return ExitCode.Ok;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mafdet/cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Mafdet AI command line — model calls, account queries, and a permissioned local agent.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,8 +30,7 @@
|
|
|
30
30
|
"LICENSE"
|
|
31
31
|
],
|
|
32
32
|
"publishConfig": {
|
|
33
|
-
"access": "public"
|
|
34
|
-
"tag": "preview"
|
|
33
|
+
"access": "public"
|
|
35
34
|
},
|
|
36
35
|
"scripts": {
|
|
37
36
|
"build": "tsc -p tsconfig.json",
|