@warlock.js/ai-cli 0.0.0-stage → 5.31.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/CHANGELOG.md +31 -0
- package/LICENSE +21 -0
- package/README.md +69 -2
- package/cjs/index.cjs +4576 -0
- package/cjs/index.cjs.map +1 -0
- package/esm/adapters/aider.d.mts +41 -0
- package/esm/adapters/aider.d.mts.map +1 -0
- package/esm/adapters/aider.mjs +294 -0
- package/esm/adapters/aider.mjs.map +1 -0
- package/esm/adapters/amp.d.mts +33 -0
- package/esm/adapters/amp.d.mts.map +1 -0
- package/esm/adapters/amp.mjs +119 -0
- package/esm/adapters/amp.mjs.map +1 -0
- package/esm/adapters/antigravity.d.mts +37 -0
- package/esm/adapters/antigravity.d.mts.map +1 -0
- package/esm/adapters/antigravity.mjs +235 -0
- package/esm/adapters/antigravity.mjs.map +1 -0
- package/esm/adapters/claude-code.d.mts +30 -0
- package/esm/adapters/claude-code.d.mts.map +1 -0
- package/esm/adapters/claude-code.mjs +121 -0
- package/esm/adapters/claude-code.mjs.map +1 -0
- package/esm/adapters/claude-stream.d.mts +32 -0
- package/esm/adapters/claude-stream.d.mts.map +1 -0
- package/esm/adapters/claude-stream.mjs +140 -0
- package/esm/adapters/claude-stream.mjs.map +1 -0
- package/esm/adapters/codex.d.mts +37 -0
- package/esm/adapters/codex.d.mts.map +1 -0
- package/esm/adapters/codex.mjs +320 -0
- package/esm/adapters/codex.mjs.map +1 -0
- package/esm/adapters/copilot.d.mts +35 -0
- package/esm/adapters/copilot.d.mts.map +1 -0
- package/esm/adapters/copilot.mjs +244 -0
- package/esm/adapters/copilot.mjs.map +1 -0
- package/esm/adapters/cursor.d.mts +35 -0
- package/esm/adapters/cursor.d.mts.map +1 -0
- package/esm/adapters/cursor.mjs +203 -0
- package/esm/adapters/cursor.mjs.map +1 -0
- package/esm/adapters/droid.d.mts +32 -0
- package/esm/adapters/droid.d.mts.map +1 -0
- package/esm/adapters/droid.mjs +183 -0
- package/esm/adapters/droid.mjs.map +1 -0
- package/esm/adapters/grok.d.mts +32 -0
- package/esm/adapters/grok.d.mts.map +1 -0
- package/esm/adapters/grok.mjs +199 -0
- package/esm/adapters/grok.mjs.map +1 -0
- package/esm/adapters/index.d.mts +16 -0
- package/esm/adapters/index.mjs +18 -0
- package/esm/adapters/kimi.d.mts +34 -0
- package/esm/adapters/kimi.d.mts.map +1 -0
- package/esm/adapters/kimi.mjs +162 -0
- package/esm/adapters/kimi.mjs.map +1 -0
- package/esm/adapters/mistral-vibe.d.mts +32 -0
- package/esm/adapters/mistral-vibe.d.mts.map +1 -0
- package/esm/adapters/mistral-vibe.mjs +252 -0
- package/esm/adapters/mistral-vibe.mjs.map +1 -0
- package/esm/adapters/opencode.d.mts +36 -0
- package/esm/adapters/opencode.d.mts.map +1 -0
- package/esm/adapters/opencode.mjs +219 -0
- package/esm/adapters/opencode.mjs.map +1 -0
- package/esm/adapters/qwen-code.d.mts +30 -0
- package/esm/adapters/qwen-code.d.mts.map +1 -0
- package/esm/adapters/qwen-code.mjs +94 -0
- package/esm/adapters/qwen-code.mjs.map +1 -0
- package/esm/adapters/reasonix.d.mts +31 -0
- package/esm/adapters/reasonix.d.mts.map +1 -0
- package/esm/adapters/reasonix.mjs +250 -0
- package/esm/adapters/reasonix.mjs.map +1 -0
- package/esm/adapters/shared.d.mts +78 -0
- package/esm/adapters/shared.d.mts.map +1 -0
- package/esm/adapters/shared.mjs +161 -0
- package/esm/adapters/shared.mjs.map +1 -0
- package/esm/cli-agent.d.mts +40 -0
- package/esm/cli-agent.d.mts.map +1 -0
- package/esm/cli-agent.mjs +207 -0
- package/esm/cli-agent.mjs.map +1 -0
- package/esm/cli.d.mts +53 -0
- package/esm/cli.d.mts.map +1 -0
- package/esm/cli.mjs +61 -0
- package/esm/cli.mjs.map +1 -0
- package/esm/contracts/adapter.contract.d.mts +154 -0
- package/esm/contracts/adapter.contract.d.mts.map +1 -0
- package/esm/contracts/events.type.d.mts +111 -0
- package/esm/contracts/events.type.d.mts.map +1 -0
- package/esm/contracts/index.d.mts +4 -0
- package/esm/contracts/mcp.type.d.mts +29 -0
- package/esm/contracts/mcp.type.d.mts.map +1 -0
- package/esm/contracts/options.type.d.mts +87 -0
- package/esm/contracts/options.type.d.mts.map +1 -0
- package/esm/errors.d.mts +46 -0
- package/esm/errors.d.mts.map +1 -0
- package/esm/errors.mjs +32 -0
- package/esm/errors.mjs.map +1 -0
- package/esm/index.d.mts +31 -0
- package/esm/index.mjs +28 -0
- package/esm/model/cli-model.d.mts +48 -0
- package/esm/model/cli-model.d.mts.map +1 -0
- package/esm/model/cli-model.mjs +133 -0
- package/esm/model/cli-model.mjs.map +1 -0
- package/esm/probe/probe.d.mts +18 -0
- package/esm/probe/probe.d.mts.map +1 -0
- package/esm/probe/probe.mjs +148 -0
- package/esm/probe/probe.mjs.map +1 -0
- package/esm/session/aggregate.mjs +86 -0
- package/esm/session/aggregate.mjs.map +1 -0
- package/esm/session/environment.mjs +71 -0
- package/esm/session/environment.mjs.map +1 -0
- package/esm/session/run-directory.mjs +74 -0
- package/esm/session/run-directory.mjs.map +1 -0
- package/esm/session/session.mjs +188 -0
- package/esm/session/session.mjs.map +1 -0
- package/esm/spawn/invocation.d.mts +35 -0
- package/esm/spawn/invocation.d.mts.map +1 -0
- package/esm/spawn/invocation.mjs +76 -0
- package/esm/spawn/invocation.mjs.map +1 -0
- package/esm/spawn/process-tree.mjs +57 -0
- package/esm/spawn/process-tree.mjs.map +1 -0
- package/esm/spawn/resolve-command.d.mts +73 -0
- package/esm/spawn/resolve-command.d.mts.map +1 -0
- package/esm/spawn/resolve-command.mjs +109 -0
- package/esm/spawn/resolve-command.mjs.map +1 -0
- package/esm/stream/event-log.mjs +52 -0
- package/esm/stream/event-log.mjs.map +1 -0
- package/esm/stream/json-lines.d.mts +33 -0
- package/esm/stream/json-lines.d.mts.map +1 -0
- package/esm/stream/json-lines.mjs +65 -0
- package/esm/stream/json-lines.mjs.map +1 -0
- package/esm/stream/line-splitter.mjs +53 -0
- package/esm/stream/line-splitter.mjs.map +1 -0
- package/esm/utils/toml.d.mts +22 -0
- package/esm/utils/toml.d.mts.map +1 -0
- package/esm/utils/toml.mjs +53 -0
- package/esm/utils/toml.mjs.map +1 -0
- package/llms-full.txt +373 -0
- package/llms.txt +10 -0
- package/package.json +39 -4
- package/skills/README.md +13 -0
- package/skills/index.md +22 -0
- package/skills/run-cli-agents/SKILL.md +186 -0
- package/skills/write-a-cli-adapter/SKILL.md +173 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { asArray, asRecord, jsonLinesParser, outputText, stringField } from "../stream/json-lines.mjs";
|
|
2
|
+
import { argvPrompt, jsonFile, mcpServersJson, parseArguments, requirePrivateHome, unsupportedOption } from "./shared.mjs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
//#region ../../packages/ai-cli/src/adapters/kimi.ts
|
|
6
|
+
/**
|
|
7
|
+
* Kimi Code CLI (`kimi`, npm `@moonshot-ai/kimi-code`) — Moonshot AI's
|
|
8
|
+
* coding agent, the successor of the archived Python `kimi-cli`.
|
|
9
|
+
*
|
|
10
|
+
* Verified against the real `kimi --help` of 2.2.0 and the docs/source at
|
|
11
|
+
* that tag (`docs/en/reference/kimi-command.md`, `apps/kimi-code/src/cli/
|
|
12
|
+
* {options.ts,prompt-render.ts,v2/run-v2-print.ts}`), 2026-10-17.
|
|
13
|
+
*
|
|
14
|
+
* - Headless: `kimi -p <prompt> --output-format stream-json`; the prompt is
|
|
15
|
+
* an argv value only (print mode never reads stdin).
|
|
16
|
+
* - Stream: OpenAI-chat-shaped messages, one per line, never deltas:
|
|
17
|
+
* `{"role":"assistant","content","tool_calls"}`, `{"role":"tool",
|
|
18
|
+
* "tool_call_id","content"}`, and `{"role":"meta","type":…}` records. The
|
|
19
|
+
* session id appears only in the final `session.resume_hint` record.
|
|
20
|
+
* No token usage is printed.
|
|
21
|
+
* - Permissions: print mode always runs in "Never Ask" mode (every tool call
|
|
22
|
+
* runs; only static deny rules apply) and rejects `--yolo`/`--plan`, so
|
|
23
|
+
* there is no standard mode to choose. The adapter refuses
|
|
24
|
+
* `permission: "standard"` instead of pretending to enforce it; pass
|
|
25
|
+
* `"bypass"` to accept the CLI's behaviour.
|
|
26
|
+
* - MCP: no flag; `$KIMI_CODE_HOME/mcp.json` (`mcpServers`), so per-run MCP
|
|
27
|
+
* needs a private home.
|
|
28
|
+
* - Auth: shell `KIMI_API_KEY`/`MOONSHOT_API_KEY` are not read. For an API
|
|
29
|
+
* key set `KIMI_MODEL_NAME` (and optionally `KIMI_MODEL_PROVIDER_TYPE`,
|
|
30
|
+
* `KIMI_MODEL_BASE_URL`) in `env`; `apiKey` becomes `KIMI_MODEL_API_KEY`.
|
|
31
|
+
*/
|
|
32
|
+
const kimiAdapter = {
|
|
33
|
+
name: "kimi",
|
|
34
|
+
title: "Kimi Code",
|
|
35
|
+
command: "kimi",
|
|
36
|
+
apiKeyEnv: ["KIMI_MODEL_API_KEY"],
|
|
37
|
+
homeEnv: ["KIMI_CODE_HOME"],
|
|
38
|
+
transports: ["argv"],
|
|
39
|
+
effort: false,
|
|
40
|
+
mcp: true,
|
|
41
|
+
probe: {
|
|
42
|
+
help: [["--help"]],
|
|
43
|
+
version: ["--version"]
|
|
44
|
+
},
|
|
45
|
+
verification: {
|
|
46
|
+
version: "2.2.0",
|
|
47
|
+
verifiedBy: "help",
|
|
48
|
+
sources: [
|
|
49
|
+
"https://moonshotai.github.io/kimi-code/",
|
|
50
|
+
"https://github.com/MoonshotAI/kimi-code/blob/%40moonshot-ai/kimi-code%402.2.0/docs/en/reference/kimi-command.md",
|
|
51
|
+
"https://github.com/MoonshotAI/kimi-code/blob/%40moonshot-ai/kimi-code%402.2.0/docs/en/customization/mcp.md"
|
|
52
|
+
],
|
|
53
|
+
checkedAt: "2026-10-17"
|
|
54
|
+
},
|
|
55
|
+
plan(context) {
|
|
56
|
+
if (context.permission !== "bypass") throw unsupportedOption(kimiAdapter, "print mode runs every tool call without asking and has no standard approval mode; pass `permission: \"bypass\"` to run it.");
|
|
57
|
+
const args = ["--output-format", "stream-json"];
|
|
58
|
+
const requires = [
|
|
59
|
+
"-p",
|
|
60
|
+
"--output-format",
|
|
61
|
+
"stream-json"
|
|
62
|
+
];
|
|
63
|
+
const files = [];
|
|
64
|
+
if (context.model !== void 0) {
|
|
65
|
+
args.push("--model", context.model);
|
|
66
|
+
requires.push("--model");
|
|
67
|
+
}
|
|
68
|
+
if (context.resume !== void 0) {
|
|
69
|
+
args.push("--session", context.resume);
|
|
70
|
+
requires.push("--session");
|
|
71
|
+
}
|
|
72
|
+
if (context.mcp !== void 0) {
|
|
73
|
+
const home = requirePrivateHome(context, kimiAdapter, "MCP servers");
|
|
74
|
+
files.push({
|
|
75
|
+
path: path.join(home, "mcp.json"),
|
|
76
|
+
content: jsonFile({ mcpServers: kimiMcp(context.mcp) })
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
args,
|
|
81
|
+
tail: ["-p", argvPrompt(context.prompt)],
|
|
82
|
+
env: {
|
|
83
|
+
...context.home !== void 0 ? { KIMI_CODE_HOME: context.home } : {},
|
|
84
|
+
KIMI_CODE_NO_AUTO_UPDATE: "1",
|
|
85
|
+
KIMI_DISABLE_TELEMETRY: "1"
|
|
86
|
+
},
|
|
87
|
+
files,
|
|
88
|
+
requires
|
|
89
|
+
};
|
|
90
|
+
},
|
|
91
|
+
parser: createKimiParser
|
|
92
|
+
};
|
|
93
|
+
/** Kimi's `mcpServers`: SSE servers are marked with `transport: "sse"`. */
|
|
94
|
+
function kimiMcp(servers) {
|
|
95
|
+
const rendered = mcpServersJson(servers);
|
|
96
|
+
for (const [name, server] of Object.entries(servers)) {
|
|
97
|
+
const entry = rendered[name];
|
|
98
|
+
if (server.type === "sse" && entry !== void 0) entry.transport = "sse";
|
|
99
|
+
}
|
|
100
|
+
return rendered;
|
|
101
|
+
}
|
|
102
|
+
/** Parser for `kimi -p … --output-format stream-json`. */
|
|
103
|
+
function createKimiParser() {
|
|
104
|
+
let sessionRef;
|
|
105
|
+
return {
|
|
106
|
+
...jsonLinesParser((record) => {
|
|
107
|
+
const role = stringField(record, "role");
|
|
108
|
+
if (role === "meta") {
|
|
109
|
+
const type = stringField(record, "type");
|
|
110
|
+
if (type === "system.version") return [{
|
|
111
|
+
type: "session.started",
|
|
112
|
+
raw: record
|
|
113
|
+
}];
|
|
114
|
+
if (type === "session.resume_hint") {
|
|
115
|
+
sessionRef = stringField(record, "session_id");
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
if (type === "turn.step.retrying") return [{
|
|
119
|
+
type: "error",
|
|
120
|
+
message: `retrying after ${stringField(record, "error_name") ?? "error"}: ${stringField(record, "error_message") ?? ""}`,
|
|
121
|
+
raw: record
|
|
122
|
+
}];
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
if (role === "assistant") {
|
|
126
|
+
const events = [];
|
|
127
|
+
const content = stringField(record, "content");
|
|
128
|
+
if (content !== void 0 && content.length > 0) events.push({
|
|
129
|
+
type: "message",
|
|
130
|
+
text: content,
|
|
131
|
+
delta: false,
|
|
132
|
+
raw: record
|
|
133
|
+
});
|
|
134
|
+
for (const item of asArray(record.tool_calls)) {
|
|
135
|
+
const call = asRecord(item);
|
|
136
|
+
const fn = asRecord(call?.function);
|
|
137
|
+
events.push({
|
|
138
|
+
type: "tool.call",
|
|
139
|
+
id: stringField(call, "id") ?? "",
|
|
140
|
+
name: stringField(fn, "name") ?? "",
|
|
141
|
+
input: parseArguments(fn?.arguments),
|
|
142
|
+
raw: item
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return events;
|
|
146
|
+
}
|
|
147
|
+
if (role === "tool") return [{
|
|
148
|
+
type: "tool.result",
|
|
149
|
+
id: stringField(record, "tool_call_id") ?? "",
|
|
150
|
+
output: outputText(record.content),
|
|
151
|
+
isError: false,
|
|
152
|
+
raw: record
|
|
153
|
+
}];
|
|
154
|
+
return [];
|
|
155
|
+
}),
|
|
156
|
+
sessionRef: () => sessionRef
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
//#endregion
|
|
161
|
+
export { createKimiParser, kimiAdapter };
|
|
162
|
+
//# sourceMappingURL=kimi.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kimi.mjs","names":[],"sources":["../../../../../../../../packages/ai-cli/src/adapters/kimi.ts"],"sourcesContent":["import path from \"node:path\";\nimport type {\n CliAdapter,\n CliLaunchFile,\n CliMcpServers,\n CliParsedEvent,\n CliStreamParser,\n} from \"../contracts\";\nimport { asArray, asRecord, jsonLinesParser, outputText, stringField } from \"../stream/json-lines\";\nimport {\n argvPrompt,\n jsonFile,\n mcpServersJson,\n parseArguments,\n requirePrivateHome,\n unsupportedOption,\n} from \"./shared\";\n\n/**\n * Kimi Code CLI (`kimi`, npm `@moonshot-ai/kimi-code`) — Moonshot AI's\n * coding agent, the successor of the archived Python `kimi-cli`.\n *\n * Verified against the real `kimi --help` of 2.2.0 and the docs/source at\n * that tag (`docs/en/reference/kimi-command.md`, `apps/kimi-code/src/cli/\n * {options.ts,prompt-render.ts,v2/run-v2-print.ts}`), 2026-10-17.\n *\n * - Headless: `kimi -p <prompt> --output-format stream-json`; the prompt is\n * an argv value only (print mode never reads stdin).\n * - Stream: OpenAI-chat-shaped messages, one per line, never deltas:\n * `{\"role\":\"assistant\",\"content\",\"tool_calls\"}`, `{\"role\":\"tool\",\n * \"tool_call_id\",\"content\"}`, and `{\"role\":\"meta\",\"type\":…}` records. The\n * session id appears only in the final `session.resume_hint` record.\n * No token usage is printed.\n * - Permissions: print mode always runs in \"Never Ask\" mode (every tool call\n * runs; only static deny rules apply) and rejects `--yolo`/`--plan`, so\n * there is no standard mode to choose. The adapter refuses\n * `permission: \"standard\"` instead of pretending to enforce it; pass\n * `\"bypass\"` to accept the CLI's behaviour.\n * - MCP: no flag; `$KIMI_CODE_HOME/mcp.json` (`mcpServers`), so per-run MCP\n * needs a private home.\n * - Auth: shell `KIMI_API_KEY`/`MOONSHOT_API_KEY` are not read. For an API\n * key set `KIMI_MODEL_NAME` (and optionally `KIMI_MODEL_PROVIDER_TYPE`,\n * `KIMI_MODEL_BASE_URL`) in `env`; `apiKey` becomes `KIMI_MODEL_API_KEY`.\n */\nexport const kimiAdapter: CliAdapter = {\n name: \"kimi\",\n title: \"Kimi Code\",\n command: \"kimi\",\n apiKeyEnv: [\"KIMI_MODEL_API_KEY\"],\n homeEnv: [\"KIMI_CODE_HOME\"],\n transports: [\"argv\"],\n effort: false,\n mcp: true,\n probe: { help: [[\"--help\"]], version: [\"--version\"] },\n verification: {\n version: \"2.2.0\",\n verifiedBy: \"help\",\n sources: [\n \"https://moonshotai.github.io/kimi-code/\",\n \"https://github.com/MoonshotAI/kimi-code/blob/%40moonshot-ai/kimi-code%402.2.0/docs/en/reference/kimi-command.md\",\n \"https://github.com/MoonshotAI/kimi-code/blob/%40moonshot-ai/kimi-code%402.2.0/docs/en/customization/mcp.md\",\n ],\n checkedAt: \"2026-10-17\",\n },\n plan(context) {\n if (context.permission !== \"bypass\") {\n throw unsupportedOption(\n kimiAdapter,\n 'print mode runs every tool call without asking and has no standard approval mode; pass `permission: \"bypass\"` to run it.',\n );\n }\n\n const args = [\"--output-format\", \"stream-json\"];\n const requires = [\"-p\", \"--output-format\", \"stream-json\"];\n const files: CliLaunchFile[] = [];\n\n if (context.model !== undefined) {\n args.push(\"--model\", context.model);\n requires.push(\"--model\");\n }\n\n if (context.resume !== undefined) {\n args.push(\"--session\", context.resume);\n requires.push(\"--session\");\n }\n\n if (context.mcp !== undefined) {\n const home = requirePrivateHome(context, kimiAdapter, \"MCP servers\");\n\n files.push({\n path: path.join(home, \"mcp.json\"),\n content: jsonFile({ mcpServers: kimiMcp(context.mcp) }),\n });\n }\n\n return {\n args,\n tail: [\"-p\", argvPrompt(context.prompt)],\n env: {\n ...(context.home !== undefined ? { KIMI_CODE_HOME: context.home } : {}),\n KIMI_CODE_NO_AUTO_UPDATE: \"1\",\n KIMI_DISABLE_TELEMETRY: \"1\",\n },\n files,\n requires,\n };\n },\n parser: createKimiParser,\n};\n\n/** Kimi's `mcpServers`: SSE servers are marked with `transport: \"sse\"`. */\nfunction kimiMcp(servers: CliMcpServers): Record<string, unknown> {\n const rendered = mcpServersJson(servers);\n\n for (const [name, server] of Object.entries(servers)) {\n const entry = rendered[name];\n\n if (server.type === \"sse\" && entry !== undefined) {\n entry.transport = \"sse\";\n }\n }\n\n return rendered;\n}\n\n/** Parser for `kimi -p … --output-format stream-json`. */\nexport function createKimiParser(): CliStreamParser {\n let sessionRef: string | undefined;\n\n const parser = jsonLinesParser((record): CliParsedEvent[] => {\n const role = stringField(record, \"role\");\n\n if (role === \"meta\") {\n const type = stringField(record, \"type\");\n\n if (type === \"system.version\") {\n return [{ type: \"session.started\", raw: record }];\n }\n\n if (type === \"session.resume_hint\") {\n sessionRef = stringField(record, \"session_id\");\n\n return [];\n }\n\n if (type === \"turn.step.retrying\") {\n return [\n {\n type: \"error\",\n message: `retrying after ${stringField(record, \"error_name\") ?? \"error\"}: ${stringField(record, \"error_message\") ?? \"\"}`,\n raw: record,\n },\n ];\n }\n\n return [];\n }\n\n if (role === \"assistant\") {\n const events: CliParsedEvent[] = [];\n const content = stringField(record, \"content\");\n\n if (content !== undefined && content.length > 0) {\n events.push({ type: \"message\", text: content, delta: false, raw: record });\n }\n\n for (const item of asArray(record.tool_calls)) {\n const call = asRecord(item);\n const fn = asRecord(call?.function);\n\n events.push({\n type: \"tool.call\",\n id: stringField(call, \"id\") ?? \"\",\n name: stringField(fn, \"name\") ?? \"\",\n input: parseArguments(fn?.arguments),\n raw: item,\n });\n }\n\n return events;\n }\n\n if (role === \"tool\") {\n return [\n {\n type: \"tool.result\",\n id: stringField(record, \"tool_call_id\") ?? \"\",\n output: outputText(record.content),\n isError: false,\n raw: record,\n },\n ];\n }\n\n return [];\n });\n\n return { ...parser, sessionRef: () => sessionRef };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { CliAdapter, CliLaunchContext, CliStreamParser } from "../contracts/adapter.contract.mjs";
|
|
2
|
+
//#region ../../packages/ai-cli/src/adapters/mistral-vibe.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Mistral Vibe (`vibe`, PyPI `mistral-vibe`).
|
|
5
|
+
*
|
|
6
|
+
* Verified against the official repo at tag v2.26.1 only (README,
|
|
7
|
+
* `vibe/cli/entrypoint.py`, `vibe/cli/programmatic.py`,
|
|
8
|
+
* `vibe/app_server/run_export.py`, `vibe/core/config/*`); Vibe needs Python
|
|
9
|
+
* 3.12, so no real `--help` was run, 2026-10-17. The capability probe checks
|
|
10
|
+
* every flag against the installed `--help`.
|
|
11
|
+
*
|
|
12
|
+
* - Headless: `vibe -p <prompt> --output streaming` (or `--prompt-file`;
|
|
13
|
+
* `-p` with no value reads stdin). The stream is NDJSON of completed
|
|
14
|
+
* history entries (camelCase): `message` (`role`, `content[].text`), and
|
|
15
|
+
* `effect` — a tool call and its result in one line (`detail.toolName`,
|
|
16
|
+
* `detail.input`, `state.status`, `state.outputText`/`state.error`).
|
|
17
|
+
* There is no usage, cost or final record in the stream, so the adapter
|
|
18
|
+
* adds `--output-dir` and reads usage, cost, session id and outcome from
|
|
19
|
+
* `export.json` when the stream ends.
|
|
20
|
+
* - Model: no flag; `VIBE_ACTIVE_MODEL=<alias>` (set from `model`). Effort
|
|
21
|
+
* is a per-model config field, so `effort` is refused.
|
|
22
|
+
* - Permissions: headless auto-denies every approval (the default agent
|
|
23
|
+
* only auto-approves file edits); bypass is `--auto-approve`.
|
|
24
|
+
* - MCP: `[[mcp_servers]]` in `$VIBE_HOME/config.toml` (private home).
|
|
25
|
+
* - Auth: `MISTRAL_API_KEY`; home `VIBE_HOME`.
|
|
26
|
+
*/
|
|
27
|
+
declare const mistralVibeAdapter: CliAdapter;
|
|
28
|
+
/** Parser for `vibe -p … --output streaming` (plus the run's `export.json`). */
|
|
29
|
+
declare function createVibeParser(context?: CliLaunchContext): CliStreamParser;
|
|
30
|
+
//#endregion
|
|
31
|
+
export { createVibeParser, mistralVibeAdapter };
|
|
32
|
+
//# sourceMappingURL=mistral-vibe.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mistral-vibe.d.mts","names":[],"sources":["../../../../../../../../packages/ai-cli/src/adapters/mistral-vibe.ts"],"mappings":";;;;;AAkDA;;;;AAuEC;AAiFD;;;;;;;;AAA6E;;;;;;;;cAxJhE,kBAAA,EAAoB,UAuEhC;;iBAiFe,gBAAA,CAAiB,OAAA,GAAU,gBAAA,GAAmB,eAAe"}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { asArray, asRecord, jsonLinesParser, numberField, outputText, parseJsonLine, recordField, stringField } from "../stream/json-lines.mjs";
|
|
2
|
+
import { toToml } from "../utils/toml.mjs";
|
|
3
|
+
import { argvPrompt, promptFile, requirePrivateHome, usageOf } from "./shared.mjs";
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
|
|
7
|
+
//#region ../../packages/ai-cli/src/adapters/mistral-vibe.ts
|
|
8
|
+
/** Folder (inside the run directory) Vibe writes `export.json` to. */
|
|
9
|
+
const EXPORT_DIR = "vibe-output";
|
|
10
|
+
/**
|
|
11
|
+
* Mistral Vibe (`vibe`, PyPI `mistral-vibe`).
|
|
12
|
+
*
|
|
13
|
+
* Verified against the official repo at tag v2.26.1 only (README,
|
|
14
|
+
* `vibe/cli/entrypoint.py`, `vibe/cli/programmatic.py`,
|
|
15
|
+
* `vibe/app_server/run_export.py`, `vibe/core/config/*`); Vibe needs Python
|
|
16
|
+
* 3.12, so no real `--help` was run, 2026-10-17. The capability probe checks
|
|
17
|
+
* every flag against the installed `--help`.
|
|
18
|
+
*
|
|
19
|
+
* - Headless: `vibe -p <prompt> --output streaming` (or `--prompt-file`;
|
|
20
|
+
* `-p` with no value reads stdin). The stream is NDJSON of completed
|
|
21
|
+
* history entries (camelCase): `message` (`role`, `content[].text`), and
|
|
22
|
+
* `effect` — a tool call and its result in one line (`detail.toolName`,
|
|
23
|
+
* `detail.input`, `state.status`, `state.outputText`/`state.error`).
|
|
24
|
+
* There is no usage, cost or final record in the stream, so the adapter
|
|
25
|
+
* adds `--output-dir` and reads usage, cost, session id and outcome from
|
|
26
|
+
* `export.json` when the stream ends.
|
|
27
|
+
* - Model: no flag; `VIBE_ACTIVE_MODEL=<alias>` (set from `model`). Effort
|
|
28
|
+
* is a per-model config field, so `effort` is refused.
|
|
29
|
+
* - Permissions: headless auto-denies every approval (the default agent
|
|
30
|
+
* only auto-approves file edits); bypass is `--auto-approve`.
|
|
31
|
+
* - MCP: `[[mcp_servers]]` in `$VIBE_HOME/config.toml` (private home).
|
|
32
|
+
* - Auth: `MISTRAL_API_KEY`; home `VIBE_HOME`.
|
|
33
|
+
*/
|
|
34
|
+
const mistralVibeAdapter = {
|
|
35
|
+
name: "mistral-vibe",
|
|
36
|
+
title: "Mistral Vibe",
|
|
37
|
+
command: "vibe",
|
|
38
|
+
apiKeyEnv: ["MISTRAL_API_KEY"],
|
|
39
|
+
homeEnv: ["VIBE_HOME"],
|
|
40
|
+
transports: [
|
|
41
|
+
"argv",
|
|
42
|
+
"file",
|
|
43
|
+
"stdin"
|
|
44
|
+
],
|
|
45
|
+
effort: false,
|
|
46
|
+
mcp: true,
|
|
47
|
+
probe: {
|
|
48
|
+
help: [["--help"]],
|
|
49
|
+
version: ["--version"]
|
|
50
|
+
},
|
|
51
|
+
verification: {
|
|
52
|
+
version: "2.26.1",
|
|
53
|
+
verifiedBy: "docs",
|
|
54
|
+
sources: [
|
|
55
|
+
"https://github.com/mistralai/mistral-vibe/blob/v2.26.1/README.md",
|
|
56
|
+
"https://github.com/mistralai/mistral-vibe/blob/v2.26.1/vibe/cli/entrypoint.py",
|
|
57
|
+
"https://github.com/mistralai/mistral-vibe/blob/v2.26.1/vibe/cli/programmatic.py"
|
|
58
|
+
],
|
|
59
|
+
checkedAt: "2026-10-17"
|
|
60
|
+
},
|
|
61
|
+
plan(context) {
|
|
62
|
+
const args = [
|
|
63
|
+
"--output",
|
|
64
|
+
"streaming",
|
|
65
|
+
"--output-dir",
|
|
66
|
+
path.join(context.runDir, EXPORT_DIR)
|
|
67
|
+
];
|
|
68
|
+
const requires = [
|
|
69
|
+
"--output",
|
|
70
|
+
"streaming",
|
|
71
|
+
"--output-dir"
|
|
72
|
+
];
|
|
73
|
+
const files = [];
|
|
74
|
+
const env = {};
|
|
75
|
+
if (context.model !== void 0) env.VIBE_ACTIVE_MODEL = context.model;
|
|
76
|
+
if (context.resume !== void 0) {
|
|
77
|
+
args.push("--resume", context.resume);
|
|
78
|
+
requires.push("--resume");
|
|
79
|
+
}
|
|
80
|
+
if (context.permission === "bypass") {
|
|
81
|
+
args.push("--auto-approve");
|
|
82
|
+
requires.push("--auto-approve");
|
|
83
|
+
}
|
|
84
|
+
if (context.mcp !== void 0) {
|
|
85
|
+
const home = requirePrivateHome(context, mistralVibeAdapter, "MCP servers");
|
|
86
|
+
files.push({
|
|
87
|
+
path: path.join(home, "config.toml"),
|
|
88
|
+
content: toToml({ mcp_servers: vibeMcp(context.mcp) })
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
if (context.home !== void 0) env.VIBE_HOME = context.home;
|
|
92
|
+
if (context.transport === "file") {
|
|
93
|
+
const prompt = promptFile(context);
|
|
94
|
+
files.push(prompt);
|
|
95
|
+
requires.push("--prompt-file");
|
|
96
|
+
return {
|
|
97
|
+
args,
|
|
98
|
+
tail: ["--prompt-file", prompt.path],
|
|
99
|
+
env,
|
|
100
|
+
files,
|
|
101
|
+
requires
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
requires.push("-p");
|
|
105
|
+
if (context.transport === "stdin") return {
|
|
106
|
+
args,
|
|
107
|
+
tail: ["-p"],
|
|
108
|
+
stdin: context.prompt,
|
|
109
|
+
env,
|
|
110
|
+
files,
|
|
111
|
+
requires
|
|
112
|
+
};
|
|
113
|
+
return {
|
|
114
|
+
args,
|
|
115
|
+
tail: ["-p", argvPrompt(context.prompt)],
|
|
116
|
+
env,
|
|
117
|
+
files,
|
|
118
|
+
requires
|
|
119
|
+
};
|
|
120
|
+
},
|
|
121
|
+
parser: createVibeParser
|
|
122
|
+
};
|
|
123
|
+
function vibeMcp(servers) {
|
|
124
|
+
return Object.entries(servers).map(([name, server]) => server.type === "stdio" ? {
|
|
125
|
+
name,
|
|
126
|
+
transport: "stdio",
|
|
127
|
+
command: server.command,
|
|
128
|
+
args: server.args ?? [],
|
|
129
|
+
env: server.env
|
|
130
|
+
} : {
|
|
131
|
+
name,
|
|
132
|
+
transport: server.type === "http" ? "streamable-http" : "http",
|
|
133
|
+
url: server.url,
|
|
134
|
+
auth: server.headers !== void 0 ? {
|
|
135
|
+
type: "static",
|
|
136
|
+
headers: server.headers
|
|
137
|
+
} : void 0
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
/** Read Vibe's `export.json`: usage, cost, session id and outcome of the run. */
|
|
141
|
+
function exportEvents(context) {
|
|
142
|
+
if (context === void 0) return { events: [] };
|
|
143
|
+
let report;
|
|
144
|
+
try {
|
|
145
|
+
report = parseJsonLine(readFileSync(path.join(context.runDir, EXPORT_DIR, "export.json"), "utf8"));
|
|
146
|
+
} catch {
|
|
147
|
+
return { events: [] };
|
|
148
|
+
}
|
|
149
|
+
if (report === void 0) return { events: [] };
|
|
150
|
+
const events = [];
|
|
151
|
+
const usage = recordField(report, "usage");
|
|
152
|
+
if (usage !== void 0) {
|
|
153
|
+
const cached = numberField(usage, "cached_input_tokens");
|
|
154
|
+
events.push({
|
|
155
|
+
type: "usage",
|
|
156
|
+
cumulative: true,
|
|
157
|
+
usage: usageOf({
|
|
158
|
+
input: numberField(usage, "input_tokens"),
|
|
159
|
+
output: numberField(usage, "output_tokens"),
|
|
160
|
+
total: numberField(usage, "total_tokens"),
|
|
161
|
+
cachedTokens: cached !== void 0 && cached > 0 ? cached : void 0,
|
|
162
|
+
costUSD: numberField(report, "cost_usd")
|
|
163
|
+
}),
|
|
164
|
+
raw: report
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
const outcome = stringField(report, "outcome");
|
|
168
|
+
if (outcome !== void 0 && outcome !== "finished") events.push({
|
|
169
|
+
type: "error",
|
|
170
|
+
message: stringField(recordField(report, "error"), "message") ?? `Mistral Vibe stopped: ${outcome}`,
|
|
171
|
+
fatal: true,
|
|
172
|
+
raw: report
|
|
173
|
+
});
|
|
174
|
+
return {
|
|
175
|
+
events,
|
|
176
|
+
sessionRef: stringField(report, "session_id")
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/** Parser for `vibe -p … --output streaming` (plus the run's `export.json`). */
|
|
180
|
+
function createVibeParser(context) {
|
|
181
|
+
let started = false;
|
|
182
|
+
let sessionRef;
|
|
183
|
+
return {
|
|
184
|
+
...jsonLinesParser((record) => {
|
|
185
|
+
const events = [];
|
|
186
|
+
const session = stringField(record, "sessionId");
|
|
187
|
+
if (session !== void 0) sessionRef = session;
|
|
188
|
+
if (!started) {
|
|
189
|
+
started = true;
|
|
190
|
+
events.push({
|
|
191
|
+
type: "session.started",
|
|
192
|
+
sessionRef: session,
|
|
193
|
+
raw: record
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
switch (stringField(record, "type")) {
|
|
197
|
+
case "message": {
|
|
198
|
+
if (stringField(record, "role") !== "assistant") break;
|
|
199
|
+
const text = asArray(record.content).map((block) => stringField(asRecord(block), "text") ?? "").join("");
|
|
200
|
+
if (text.length > 0) events.push({
|
|
201
|
+
type: "message",
|
|
202
|
+
text,
|
|
203
|
+
delta: false,
|
|
204
|
+
raw: record
|
|
205
|
+
});
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
case "effect": {
|
|
209
|
+
const detail = recordField(record, "detail");
|
|
210
|
+
const state = recordField(record, "state");
|
|
211
|
+
const status = stringField(state, "status");
|
|
212
|
+
const id = stringField(record, "id") ?? "";
|
|
213
|
+
events.push({
|
|
214
|
+
type: "tool.call",
|
|
215
|
+
id,
|
|
216
|
+
name: stringField(detail, "toolName") ?? stringField(record, "title") ?? "",
|
|
217
|
+
input: detail?.input,
|
|
218
|
+
raw: record
|
|
219
|
+
});
|
|
220
|
+
if (status === "completed" || status === "failed" || status === "cancelled" || status === "skipped") {
|
|
221
|
+
const error = stringField(recordField(state, "error"), "message");
|
|
222
|
+
events.push({
|
|
223
|
+
type: "tool.result",
|
|
224
|
+
id,
|
|
225
|
+
output: error ?? stringField(state, "outputText") ?? outputText(state?.output),
|
|
226
|
+
isError: status !== "completed",
|
|
227
|
+
raw: record
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
case "notice":
|
|
233
|
+
if (stringField(record, "level") === "error") events.push({
|
|
234
|
+
type: "error",
|
|
235
|
+
message: stringField(record, "message") ?? "error",
|
|
236
|
+
raw: record
|
|
237
|
+
});
|
|
238
|
+
break;
|
|
239
|
+
}
|
|
240
|
+
return events;
|
|
241
|
+
}, () => {
|
|
242
|
+
const exported = exportEvents(context);
|
|
243
|
+
sessionRef = exported.sessionRef ?? sessionRef;
|
|
244
|
+
return exported.events;
|
|
245
|
+
}),
|
|
246
|
+
sessionRef: () => sessionRef
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
//#endregion
|
|
251
|
+
export { createVibeParser, mistralVibeAdapter };
|
|
252
|
+
//# sourceMappingURL=mistral-vibe.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mistral-vibe.mjs","names":[],"sources":["../../../../../../../../packages/ai-cli/src/adapters/mistral-vibe.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type {\n CliAdapter,\n CliLaunchContext,\n CliLaunchFile,\n CliMcpServers,\n CliParsedEvent,\n CliStreamParser,\n} from \"../contracts\";\nimport {\n asArray,\n asRecord,\n jsonLinesParser,\n numberField,\n outputText,\n parseJsonLine,\n recordField,\n stringField,\n} from \"../stream/json-lines\";\nimport { type TomlTable, toToml } from \"../utils/toml\";\nimport { argvPrompt, promptFile, requirePrivateHome, usageOf } from \"./shared\";\n\n/** Folder (inside the run directory) Vibe writes `export.json` to. */\nconst EXPORT_DIR = \"vibe-output\";\n\n/**\n * Mistral Vibe (`vibe`, PyPI `mistral-vibe`).\n *\n * Verified against the official repo at tag v2.26.1 only (README,\n * `vibe/cli/entrypoint.py`, `vibe/cli/programmatic.py`,\n * `vibe/app_server/run_export.py`, `vibe/core/config/*`); Vibe needs Python\n * 3.12, so no real `--help` was run, 2026-10-17. The capability probe checks\n * every flag against the installed `--help`.\n *\n * - Headless: `vibe -p <prompt> --output streaming` (or `--prompt-file`;\n * `-p` with no value reads stdin). The stream is NDJSON of completed\n * history entries (camelCase): `message` (`role`, `content[].text`), and\n * `effect` — a tool call and its result in one line (`detail.toolName`,\n * `detail.input`, `state.status`, `state.outputText`/`state.error`).\n * There is no usage, cost or final record in the stream, so the adapter\n * adds `--output-dir` and reads usage, cost, session id and outcome from\n * `export.json` when the stream ends.\n * - Model: no flag; `VIBE_ACTIVE_MODEL=<alias>` (set from `model`). Effort\n * is a per-model config field, so `effort` is refused.\n * - Permissions: headless auto-denies every approval (the default agent\n * only auto-approves file edits); bypass is `--auto-approve`.\n * - MCP: `[[mcp_servers]]` in `$VIBE_HOME/config.toml` (private home).\n * - Auth: `MISTRAL_API_KEY`; home `VIBE_HOME`.\n */\nexport const mistralVibeAdapter: CliAdapter = {\n name: \"mistral-vibe\",\n title: \"Mistral Vibe\",\n command: \"vibe\",\n apiKeyEnv: [\"MISTRAL_API_KEY\"],\n homeEnv: [\"VIBE_HOME\"],\n transports: [\"argv\", \"file\", \"stdin\"],\n effort: false,\n mcp: true,\n probe: { help: [[\"--help\"]], version: [\"--version\"] },\n verification: {\n version: \"2.26.1\",\n verifiedBy: \"docs\",\n sources: [\n \"https://github.com/mistralai/mistral-vibe/blob/v2.26.1/README.md\",\n \"https://github.com/mistralai/mistral-vibe/blob/v2.26.1/vibe/cli/entrypoint.py\",\n \"https://github.com/mistralai/mistral-vibe/blob/v2.26.1/vibe/cli/programmatic.py\",\n ],\n checkedAt: \"2026-10-17\",\n },\n plan(context) {\n const args = [\"--output\", \"streaming\", \"--output-dir\", path.join(context.runDir, EXPORT_DIR)];\n const requires = [\"--output\", \"streaming\", \"--output-dir\"];\n const files: CliLaunchFile[] = [];\n const env: Record<string, string> = {};\n\n if (context.model !== undefined) {\n env.VIBE_ACTIVE_MODEL = context.model;\n }\n\n if (context.resume !== undefined) {\n args.push(\"--resume\", context.resume);\n requires.push(\"--resume\");\n }\n\n if (context.permission === \"bypass\") {\n args.push(\"--auto-approve\");\n requires.push(\"--auto-approve\");\n }\n\n if (context.mcp !== undefined) {\n const home = requirePrivateHome(context, mistralVibeAdapter, \"MCP servers\");\n\n files.push({\n path: path.join(home, \"config.toml\"),\n content: toToml({ mcp_servers: vibeMcp(context.mcp) }),\n });\n }\n\n if (context.home !== undefined) {\n env.VIBE_HOME = context.home;\n }\n\n if (context.transport === \"file\") {\n const prompt = promptFile(context);\n\n files.push(prompt);\n requires.push(\"--prompt-file\");\n\n return { args, tail: [\"--prompt-file\", prompt.path], env, files, requires };\n }\n\n requires.push(\"-p\");\n\n if (context.transport === \"stdin\") {\n return { args, tail: [\"-p\"], stdin: context.prompt, env, files, requires };\n }\n\n return { args, tail: [\"-p\", argvPrompt(context.prompt)], env, files, requires };\n },\n parser: createVibeParser,\n};\n\nfunction vibeMcp(servers: CliMcpServers): TomlTable[] {\n return Object.entries(servers).map(([name, server]): TomlTable =>\n server.type === \"stdio\"\n ? {\n name,\n transport: \"stdio\",\n command: server.command,\n args: server.args ?? [],\n env: server.env,\n }\n : {\n name,\n transport: server.type === \"http\" ? \"streamable-http\" : \"http\",\n url: server.url,\n auth:\n server.headers !== undefined ? { type: \"static\", headers: server.headers } : undefined,\n },\n );\n}\n\n/** Read Vibe's `export.json`: usage, cost, session id and outcome of the run. */\nfunction exportEvents(context: CliLaunchContext | undefined): {\n events: CliParsedEvent[];\n sessionRef?: string;\n} {\n if (context === undefined) {\n return { events: [] };\n }\n\n let report: Record<string, unknown> | undefined;\n\n try {\n report = parseJsonLine(\n readFileSync(path.join(context.runDir, EXPORT_DIR, \"export.json\"), \"utf8\"),\n );\n } catch {\n return { events: [] };\n }\n\n if (report === undefined) {\n return { events: [] };\n }\n\n const events: CliParsedEvent[] = [];\n const usage = recordField(report, \"usage\");\n\n if (usage !== undefined) {\n const cached = numberField(usage, \"cached_input_tokens\");\n\n events.push({\n type: \"usage\",\n cumulative: true,\n usage: usageOf({\n input: numberField(usage, \"input_tokens\"),\n output: numberField(usage, \"output_tokens\"),\n total: numberField(usage, \"total_tokens\"),\n cachedTokens: cached !== undefined && cached > 0 ? cached : undefined,\n costUSD: numberField(report, \"cost_usd\"),\n }),\n raw: report,\n });\n }\n\n const outcome = stringField(report, \"outcome\");\n\n if (outcome !== undefined && outcome !== \"finished\") {\n events.push({\n type: \"error\",\n message:\n stringField(recordField(report, \"error\"), \"message\") ?? `Mistral Vibe stopped: ${outcome}`,\n fatal: true,\n raw: report,\n });\n }\n\n return { events, sessionRef: stringField(report, \"session_id\") };\n}\n\n/** Parser for `vibe -p … --output streaming` (plus the run's `export.json`). */\nexport function createVibeParser(context?: CliLaunchContext): CliStreamParser {\n let started = false;\n let sessionRef: string | undefined;\n\n const parser = jsonLinesParser(\n (record): CliParsedEvent[] => {\n const events: CliParsedEvent[] = [];\n const session = stringField(record, \"sessionId\");\n\n if (session !== undefined) {\n sessionRef = session;\n }\n\n if (!started) {\n started = true;\n events.push({ type: \"session.started\", sessionRef: session, raw: record });\n }\n\n switch (stringField(record, \"type\")) {\n case \"message\": {\n if (stringField(record, \"role\") !== \"assistant\") {\n break;\n }\n\n const text = asArray(record.content)\n .map((block) => stringField(asRecord(block), \"text\") ?? \"\")\n .join(\"\");\n\n if (text.length > 0) {\n events.push({ type: \"message\", text, delta: false, raw: record });\n }\n break;\n }\n case \"effect\": {\n const detail = recordField(record, \"detail\");\n const state = recordField(record, \"state\");\n const status = stringField(state, \"status\");\n const id = stringField(record, \"id\") ?? \"\";\n\n events.push({\n type: \"tool.call\",\n id,\n name: stringField(detail, \"toolName\") ?? stringField(record, \"title\") ?? \"\",\n input: detail?.input,\n raw: record,\n });\n\n if (\n status === \"completed\" ||\n status === \"failed\" ||\n status === \"cancelled\" ||\n status === \"skipped\"\n ) {\n const error = stringField(recordField(state, \"error\"), \"message\");\n\n events.push({\n type: \"tool.result\",\n id,\n output: error ?? stringField(state, \"outputText\") ?? outputText(state?.output),\n isError: status !== \"completed\",\n raw: record,\n });\n }\n break;\n }\n case \"notice\":\n if (stringField(record, \"level\") === \"error\") {\n events.push({\n type: \"error\",\n message: stringField(record, \"message\") ?? \"error\",\n raw: record,\n });\n }\n break;\n }\n\n return events;\n },\n () => {\n const exported = exportEvents(context);\n\n sessionRef = exported.sessionRef ?? sessionRef;\n\n return exported.events;\n },\n );\n\n return { ...parser, sessionRef: () => sessionRef };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { CliAdapter, CliStreamParser } from "../contracts/adapter.contract.mjs";
|
|
2
|
+
//#region ../../packages/ai-cli/src/adapters/opencode.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* OpenCode (`opencode`, npm `opencode-ai`).
|
|
5
|
+
*
|
|
6
|
+
* Verified against the real `opencode --help` / `opencode run --help` of
|
|
7
|
+
* 1.19.3, the CLI source at that tag (`packages/opencode/src/cli/cmd/run.ts`)
|
|
8
|
+
* and the docs (`cli.mdx`, `config.mdx`, `mcp-servers.mdx`,
|
|
9
|
+
* `permissions.mdx`), 2026-10-17.
|
|
10
|
+
*
|
|
11
|
+
* - Headless: `opencode run --format json <message..>`; with no message,
|
|
12
|
+
* piped stdin is the prompt.
|
|
13
|
+
* - Stream: `{"type","timestamp","sessionID","part"|"error"}` lines of six
|
|
14
|
+
* types: `step_start`, `text` (whole text blocks, no deltas), `reasoning`,
|
|
15
|
+
* `tool_use` (emitted once the tool finished — call and result together,
|
|
16
|
+
* `state.status` `completed`/`error`), `step_finish` (per-step `cost` in
|
|
17
|
+
* USD and `tokens{input,output,reasoning,cache{read,write}}`, input net of
|
|
18
|
+
* cache) and `error{error:{name,data:{message}}}`. No init or final record.
|
|
19
|
+
* - Permissions: `standard` keeps OpenCode's own rules (permissive by
|
|
20
|
+
* default; anything that would ask is auto-rejected in `run`); bypass is
|
|
21
|
+
* `--auto`.
|
|
22
|
+
* - MCP: the `mcp` key of a config file named by `OPENCODE_CONFIG`, written
|
|
23
|
+
* to the run directory — works with any home.
|
|
24
|
+
* - Home: OpenCode follows XDG; a private/owned home sets `XDG_CONFIG_HOME`,
|
|
25
|
+
* `XDG_DATA_HOME` (auth lives here), `XDG_STATE_HOME` and `XDG_CACHE_HOME`
|
|
26
|
+
* beneath it. Provider keys use the provider's own variable
|
|
27
|
+
* (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, …) — pass them through `env`.
|
|
28
|
+
* - The working directory is passed with `--dir`, because OpenCode prefers a
|
|
29
|
+
* (possibly stale) `PWD` over the process cwd.
|
|
30
|
+
*/
|
|
31
|
+
declare const opencodeAdapter: CliAdapter;
|
|
32
|
+
/** Parser for `opencode run --format json`. */
|
|
33
|
+
declare function createOpencodeParser(): CliStreamParser;
|
|
34
|
+
//#endregion
|
|
35
|
+
export { createOpencodeParser, opencodeAdapter };
|
|
36
|
+
//# sourceMappingURL=opencode.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode.d.mts","names":[],"sources":["../../../../../../../../packages/ai-cli/src/adapters/opencode.ts"],"mappings":";;;;;AA6CA;;;;AA8EC;AA0BD;;;;AAAuD;;;;;;;;;;;;;;;;cAxG1C,eAAA,EAAiB,UA8E7B;;iBA0Be,oBAAA,IAAwB,eAAe"}
|