@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.
Files changed (139) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/LICENSE +21 -0
  3. package/README.md +69 -2
  4. package/cjs/index.cjs +4576 -0
  5. package/cjs/index.cjs.map +1 -0
  6. package/esm/adapters/aider.d.mts +41 -0
  7. package/esm/adapters/aider.d.mts.map +1 -0
  8. package/esm/adapters/aider.mjs +294 -0
  9. package/esm/adapters/aider.mjs.map +1 -0
  10. package/esm/adapters/amp.d.mts +33 -0
  11. package/esm/adapters/amp.d.mts.map +1 -0
  12. package/esm/adapters/amp.mjs +119 -0
  13. package/esm/adapters/amp.mjs.map +1 -0
  14. package/esm/adapters/antigravity.d.mts +37 -0
  15. package/esm/adapters/antigravity.d.mts.map +1 -0
  16. package/esm/adapters/antigravity.mjs +235 -0
  17. package/esm/adapters/antigravity.mjs.map +1 -0
  18. package/esm/adapters/claude-code.d.mts +30 -0
  19. package/esm/adapters/claude-code.d.mts.map +1 -0
  20. package/esm/adapters/claude-code.mjs +121 -0
  21. package/esm/adapters/claude-code.mjs.map +1 -0
  22. package/esm/adapters/claude-stream.d.mts +32 -0
  23. package/esm/adapters/claude-stream.d.mts.map +1 -0
  24. package/esm/adapters/claude-stream.mjs +140 -0
  25. package/esm/adapters/claude-stream.mjs.map +1 -0
  26. package/esm/adapters/codex.d.mts +37 -0
  27. package/esm/adapters/codex.d.mts.map +1 -0
  28. package/esm/adapters/codex.mjs +320 -0
  29. package/esm/adapters/codex.mjs.map +1 -0
  30. package/esm/adapters/copilot.d.mts +35 -0
  31. package/esm/adapters/copilot.d.mts.map +1 -0
  32. package/esm/adapters/copilot.mjs +244 -0
  33. package/esm/adapters/copilot.mjs.map +1 -0
  34. package/esm/adapters/cursor.d.mts +35 -0
  35. package/esm/adapters/cursor.d.mts.map +1 -0
  36. package/esm/adapters/cursor.mjs +203 -0
  37. package/esm/adapters/cursor.mjs.map +1 -0
  38. package/esm/adapters/droid.d.mts +32 -0
  39. package/esm/adapters/droid.d.mts.map +1 -0
  40. package/esm/adapters/droid.mjs +183 -0
  41. package/esm/adapters/droid.mjs.map +1 -0
  42. package/esm/adapters/grok.d.mts +32 -0
  43. package/esm/adapters/grok.d.mts.map +1 -0
  44. package/esm/adapters/grok.mjs +199 -0
  45. package/esm/adapters/grok.mjs.map +1 -0
  46. package/esm/adapters/index.d.mts +16 -0
  47. package/esm/adapters/index.mjs +18 -0
  48. package/esm/adapters/kimi.d.mts +34 -0
  49. package/esm/adapters/kimi.d.mts.map +1 -0
  50. package/esm/adapters/kimi.mjs +162 -0
  51. package/esm/adapters/kimi.mjs.map +1 -0
  52. package/esm/adapters/mistral-vibe.d.mts +32 -0
  53. package/esm/adapters/mistral-vibe.d.mts.map +1 -0
  54. package/esm/adapters/mistral-vibe.mjs +252 -0
  55. package/esm/adapters/mistral-vibe.mjs.map +1 -0
  56. package/esm/adapters/opencode.d.mts +36 -0
  57. package/esm/adapters/opencode.d.mts.map +1 -0
  58. package/esm/adapters/opencode.mjs +219 -0
  59. package/esm/adapters/opencode.mjs.map +1 -0
  60. package/esm/adapters/qwen-code.d.mts +30 -0
  61. package/esm/adapters/qwen-code.d.mts.map +1 -0
  62. package/esm/adapters/qwen-code.mjs +94 -0
  63. package/esm/adapters/qwen-code.mjs.map +1 -0
  64. package/esm/adapters/reasonix.d.mts +31 -0
  65. package/esm/adapters/reasonix.d.mts.map +1 -0
  66. package/esm/adapters/reasonix.mjs +250 -0
  67. package/esm/adapters/reasonix.mjs.map +1 -0
  68. package/esm/adapters/shared.d.mts +78 -0
  69. package/esm/adapters/shared.d.mts.map +1 -0
  70. package/esm/adapters/shared.mjs +161 -0
  71. package/esm/adapters/shared.mjs.map +1 -0
  72. package/esm/cli-agent.d.mts +40 -0
  73. package/esm/cli-agent.d.mts.map +1 -0
  74. package/esm/cli-agent.mjs +207 -0
  75. package/esm/cli-agent.mjs.map +1 -0
  76. package/esm/cli.d.mts +53 -0
  77. package/esm/cli.d.mts.map +1 -0
  78. package/esm/cli.mjs +61 -0
  79. package/esm/cli.mjs.map +1 -0
  80. package/esm/contracts/adapter.contract.d.mts +154 -0
  81. package/esm/contracts/adapter.contract.d.mts.map +1 -0
  82. package/esm/contracts/events.type.d.mts +111 -0
  83. package/esm/contracts/events.type.d.mts.map +1 -0
  84. package/esm/contracts/index.d.mts +4 -0
  85. package/esm/contracts/mcp.type.d.mts +29 -0
  86. package/esm/contracts/mcp.type.d.mts.map +1 -0
  87. package/esm/contracts/options.type.d.mts +87 -0
  88. package/esm/contracts/options.type.d.mts.map +1 -0
  89. package/esm/errors.d.mts +46 -0
  90. package/esm/errors.d.mts.map +1 -0
  91. package/esm/errors.mjs +32 -0
  92. package/esm/errors.mjs.map +1 -0
  93. package/esm/index.d.mts +31 -0
  94. package/esm/index.mjs +28 -0
  95. package/esm/model/cli-model.d.mts +48 -0
  96. package/esm/model/cli-model.d.mts.map +1 -0
  97. package/esm/model/cli-model.mjs +133 -0
  98. package/esm/model/cli-model.mjs.map +1 -0
  99. package/esm/probe/probe.d.mts +18 -0
  100. package/esm/probe/probe.d.mts.map +1 -0
  101. package/esm/probe/probe.mjs +148 -0
  102. package/esm/probe/probe.mjs.map +1 -0
  103. package/esm/session/aggregate.mjs +86 -0
  104. package/esm/session/aggregate.mjs.map +1 -0
  105. package/esm/session/environment.mjs +71 -0
  106. package/esm/session/environment.mjs.map +1 -0
  107. package/esm/session/run-directory.mjs +74 -0
  108. package/esm/session/run-directory.mjs.map +1 -0
  109. package/esm/session/session.mjs +188 -0
  110. package/esm/session/session.mjs.map +1 -0
  111. package/esm/spawn/invocation.d.mts +35 -0
  112. package/esm/spawn/invocation.d.mts.map +1 -0
  113. package/esm/spawn/invocation.mjs +76 -0
  114. package/esm/spawn/invocation.mjs.map +1 -0
  115. package/esm/spawn/process-tree.mjs +57 -0
  116. package/esm/spawn/process-tree.mjs.map +1 -0
  117. package/esm/spawn/resolve-command.d.mts +73 -0
  118. package/esm/spawn/resolve-command.d.mts.map +1 -0
  119. package/esm/spawn/resolve-command.mjs +109 -0
  120. package/esm/spawn/resolve-command.mjs.map +1 -0
  121. package/esm/stream/event-log.mjs +52 -0
  122. package/esm/stream/event-log.mjs.map +1 -0
  123. package/esm/stream/json-lines.d.mts +33 -0
  124. package/esm/stream/json-lines.d.mts.map +1 -0
  125. package/esm/stream/json-lines.mjs +65 -0
  126. package/esm/stream/json-lines.mjs.map +1 -0
  127. package/esm/stream/line-splitter.mjs +53 -0
  128. package/esm/stream/line-splitter.mjs.map +1 -0
  129. package/esm/utils/toml.d.mts +22 -0
  130. package/esm/utils/toml.d.mts.map +1 -0
  131. package/esm/utils/toml.mjs +53 -0
  132. package/esm/utils/toml.mjs.map +1 -0
  133. package/llms-full.txt +373 -0
  134. package/llms.txt +10 -0
  135. package/package.json +39 -4
  136. package/skills/README.md +13 -0
  137. package/skills/index.md +22 -0
  138. package/skills/run-cli-agents/SKILL.md +186 -0
  139. package/skills/write-a-cli-adapter/SKILL.md +173 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reasonix.mjs","names":[],"sources":["../../../../../../../../packages/ai-cli/src/adapters/reasonix.ts"],"sourcesContent":["import path from \"node:path\";\nimport type {\n CliAdapter,\n CliLaunchFile,\n CliMcpServers,\n CliParsedEvent,\n CliStreamParser,\n CliUsage,\n} from \"../contracts\";\nimport {\n asRecord,\n jsonLinesParser,\n numberField,\n recordField,\n stringField,\n type JsonRecord,\n} from \"../stream/json-lines\";\nimport { type TomlTable, toToml } from \"../utils/toml\";\nimport {\n argvPrompt,\n dotenvFile,\n mapEffort,\n parseArguments,\n requirePrivateHome,\n usageOf,\n} from \"./shared\";\n\n/**\n * Reasonix (`reasonix`, npm `reasonix`) — a cache-first coding agent built\n * around DeepSeek (now multi-provider); the npm package launches a prebuilt\n * Go binary.\n *\n * Verified against the real `reasonix run --help` / `--version` of 2.43.0,\n * real stream-json output (captured against a local fake model server) and\n * the docs at that tag (`docs/CLI.md`, `docs/CONFIG_PATHS.md`), 2026-10-17.\n *\n * - Headless: `reasonix run --output-format stream-json <task>`; with no\n * positional task, piped stdin is the prompt.\n * - Stream: every line has `kind` (`text` deltas, `message` full text,\n * `tool_dispatch`/`tool_started`/`tool_result` with a `tool` object whose\n * non-empty `err` marks a failure, `usage` per model call, `turn_done`) plus\n * `sessionId`; the final line is `{\"type\":\"result\",…}` with totals.\n * - Permissions: headless \"ask\" mode refuses writes (listed in\n * `permission_denials`; exit 4 in an untrusted folder); bypass is `--yolo`.\n * - MCP: no flag; `[[plugins]]` in `$REASONIX_HOME/config.toml`.\n * - Auth: provider keys are read only from `$REASONIX_HOME/.env`, never the\n * shell environment, so `apiKey` is written there (0600) as\n * `DEEPSEEK_API_KEY` — this needs a private home. For another provider,\n * put its variable in that file yourself via a caller-owned home.\n */\nexport const reasonixAdapter: CliAdapter = {\n name: \"reasonix\",\n title: \"Reasonix\",\n command: \"reasonix\",\n apiKeyEnv: [\"DEEPSEEK_API_KEY\"],\n homeEnv: [\"REASONIX_HOME\"],\n transports: [\"argv\", \"stdin\"],\n effort: true,\n mcp: true,\n probe: { help: [[\"run\", \"--help\"]], version: [\"--version\"] },\n verification: {\n version: \"2.43.0\",\n verifiedBy: \"help\",\n sources: [\n \"https://github.com/esengine/DeepSeek-Reasonix/blob/v2.43.0/docs/CLI.md\",\n \"https://github.com/esengine/DeepSeek-Reasonix/blob/v2.43.0/docs/CONFIG_PATHS.md\",\n \"https://www.npmjs.com/package/reasonix\",\n ],\n checkedAt: \"2026-10-17\",\n },\n plan(context) {\n const args = [\"run\", \"--output-format\", \"stream-json\"];\n const requires = [\"--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.effort !== undefined) {\n // DeepSeek levels per docs/REASONING_PROVIDERS.md: auto | disabled | low | high | max.\n args.push(\n \"--effort\",\n mapEffort(context.effort, { none: \"disabled\", low: \"low\", high: \"high\", max: \"max\" }),\n );\n requires.push(\"--effort\");\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(\"--yolo\");\n requires.push(\"--yolo\");\n }\n\n if (context.mcp !== undefined) {\n const home = requirePrivateHome(context, reasonixAdapter, \"MCP servers\");\n\n files.push({\n path: path.join(home, \"config.toml\"),\n content: toToml({ plugins: reasonixPlugins(context.mcp) }),\n });\n }\n\n if (context.apiKey !== undefined) {\n const home = requirePrivateHome(context, reasonixAdapter, \"API keys (its .env file)\");\n\n files.push({\n path: path.join(home, \".env\"),\n content: dotenvFile({ DEEPSEEK_API_KEY: context.apiKey }),\n });\n }\n\n return {\n args,\n tail: context.transport === \"argv\" ? [argvPrompt(context.prompt)] : [],\n stdin: context.transport === \"stdin\" ? context.prompt : undefined,\n env: {\n ...(context.home !== undefined ? { REASONIX_HOME: context.home } : {}),\n REASONIX_TELEMETRY: \"off\",\n },\n files,\n requires,\n };\n },\n parser: createReasonixParser,\n};\n\nfunction reasonixPlugins(servers: CliMcpServers): TomlTable[] {\n return Object.entries(servers).map(([name, server]): TomlTable =>\n server.type === \"stdio\"\n ? { name, type: \"stdio\", command: server.command, args: server.args ?? [], env: server.env }\n : { name, type: server.type, url: server.url, headers: server.headers },\n );\n}\n\n/** Reasonix per-call usage (`promptTokens` includes cache hits). */\nfunction callUsage(usage: JsonRecord | undefined): CliUsage | undefined {\n if (usage === undefined) {\n return undefined;\n }\n\n const cacheHit = numberField(usage, \"cacheHitTokens\");\n\n return usageOf({\n input: numberField(usage, \"promptTokens\"),\n output: numberField(usage, \"completionTokens\"),\n total: numberField(usage, \"totalTokens\"),\n cachedTokens: cacheHit !== undefined && cacheHit > 0 ? cacheHit : undefined,\n reasoningTokens: numberField(usage, \"reasoningTokens\"),\n costUSD: numberField(usage, \"costUsd\"),\n });\n}\n\n/** Parser for `reasonix run --output-format stream-json`. */\nexport function createReasonixParser(): CliStreamParser {\n let started = false;\n let sessionRef: string | undefined;\n\n return {\n ...jsonLinesParser((record): CliParsedEvent[] => {\n const events: CliParsedEvent[] = [];\n const recordSession = stringField(record, \"sessionId\") ?? stringField(record, \"session_id\");\n\n if (recordSession !== undefined) {\n sessionRef = recordSession;\n }\n\n if (!started && recordSession !== undefined) {\n started = true;\n events.push({ type: \"session.started\", sessionRef: recordSession, raw: record });\n }\n\n if (stringField(record, \"type\") === \"result\") {\n const usage = recordField(record, \"usage\");\n\n if (usage !== undefined) {\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 cachedTokens: numberField(usage, \"cache_read_input_tokens\") || undefined,\n costUSD: numberField(record, \"total_cost_usd\"),\n }),\n raw: record,\n });\n }\n\n const result = stringField(record, \"result\") ?? \"\";\n\n if (record.is_error === true) {\n events.push({\n type: \"error\",\n message: result || \"Reasonix run failed\",\n fatal: true,\n raw: record,\n });\n } else if (result.length > 0) {\n events.push({ type: \"message\", text: result, delta: false, final: true, raw: record });\n }\n\n return events;\n }\n\n const tool = asRecord(record.tool);\n\n switch (stringField(record, \"kind\")) {\n case \"text\": {\n const text = stringField(record, \"text\") ?? \"\";\n\n if (text.length > 0) {\n events.push({ type: \"message\", text, delta: true, raw: record });\n }\n break;\n }\n case \"message\":\n events.push({\n type: \"message\",\n text: stringField(record, \"text\") ?? \"\",\n delta: false,\n raw: record,\n });\n break;\n case \"tool_dispatch\":\n // The first dispatch streams arguments (`partial: true`); report the complete one.\n if (tool !== undefined && tool.partial !== true) {\n events.push({\n type: \"tool.call\",\n id: stringField(tool, \"id\") ?? \"\",\n name: stringField(tool, \"name\") ?? \"\",\n input: parseArguments(tool.args),\n raw: record,\n });\n }\n break;\n case \"tool_result\": {\n const error = stringField(tool, \"err\") ?? \"\";\n\n events.push({\n type: \"tool.result\",\n id: stringField(tool, \"id\") ?? \"\",\n output: error.length > 0 ? error : (stringField(tool, \"output\") ?? \"\"),\n isError: error.length > 0,\n raw: record,\n });\n break;\n }\n case \"usage\": {\n const usage = callUsage(recordField(record, \"usage\"));\n\n if (usage !== undefined) {\n events.push({ type: \"usage\", usage, cumulative: false, raw: record });\n }\n break;\n }\n case \"turn_done\":\n if (stringField(record, \"status\") === \"failed\") {\n events.push({\n type: \"error\",\n message: stringField(record, \"err\") ?? \"Reasonix turn failed\",\n fatal: true,\n raw: record,\n });\n }\n break;\n }\n\n return events;\n }),\n sessionRef: () => sessionRef,\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ import { CliUsage } from "../contracts/events.type.mjs";
2
+ import { CliMcpServers } from "../contracts/mcp.type.mjs";
3
+ import { CliLaunchContext, CliLaunchFile } from "../contracts/adapter.contract.mjs";
4
+ import { CliError } from "../errors.mjs";
5
+ import { ReasoningEffort } from "@warlock.js/ai";
6
+
7
+ //#region ../../packages/ai-cli/src/adapters/shared.d.ts
8
+ /**
9
+ * The prompt as an argv value. A prompt starting with `-` would be read as a
10
+ * flag by the CLI's argument parser, so it gets one leading space (harmless
11
+ * to the model, and no parser treats it as an option).
12
+ */
13
+ declare function argvPrompt(prompt: string): string;
14
+ /** The prompt written to `prompt.txt` in the run directory, for `transport: "file"`. */
15
+ declare function promptFile(context: CliLaunchContext): CliLaunchFile;
16
+ /**
17
+ * Fail closed when an option needs a file inside the CLI's config home but
18
+ * the home is not private to this run (writing it into a caller-owned or
19
+ * inherited home would leak tokens into it and race concurrent runs).
20
+ */
21
+ declare function requirePrivateHome(context: CliLaunchContext, adapter: {
22
+ name: string;
23
+ title: string;
24
+ }, option: string): string;
25
+ /** A `.env` file body. Values are written verbatim; newlines are refused. */
26
+ declare function dotenvFile(values: Record<string, string>): string;
27
+ /**
28
+ * Map a framework effort to a vendor's levels, following the framework
29
+ * rule: an exact level wins; otherwise the nearest higher level the vendor
30
+ * has (so `minimal` becomes `low`); a level above the vendor's highest is
31
+ * clamped to it.
32
+ *
33
+ * @example
34
+ * mapEffort("xhigh", { low: "low", medium: "medium", high: "high" }); // "high"
35
+ * mapEffort("minimal", { low: "low", medium: "medium", high: "high" }); // "low"
36
+ */
37
+ declare function mapEffort(effort: ReasoningEffort, levels: Partial<Record<ReasoningEffort, string>>): string;
38
+ /**
39
+ * The common `mcpServers` JSON shape (Claude Code, Cursor, Kimi, Droid,
40
+ * Copilot, Amp, Qwen Code …): stdio servers as `command`/`args`/`env`,
41
+ * remote servers as `url`/`headers`. `typeField` adds the `type` key the
42
+ * vendor expects (`"stdio"`, `"http"`, `"sse"`), or a renamed remote
43
+ * transport (`"streamable-http"`).
44
+ */
45
+ declare function mcpServersJson(servers: CliMcpServers, options?: {
46
+ /** Emit a `type` key on every server. */typeField?: boolean; /** Value of `type` for streamable HTTP servers. Default `"http"`. */
47
+ httpType?: string; /** Extra keys merged into every server (for example `tools: ["*"]`). */
48
+ extra?: Record<string, unknown>; /** Key holding a streamable-HTTP URL. Default `"url"`. */
49
+ httpUrlKey?: string;
50
+ }): Record<string, Record<string, unknown>>;
51
+ /** JSON for a config file, pretty-printed with a trailing newline. */
52
+ declare function jsonFile(value: unknown): string;
53
+ /** Build a `CliUsage`, computing `total` when the vendor omits it. */
54
+ declare function usageOf(fields: {
55
+ input?: number;
56
+ output?: number;
57
+ total?: number;
58
+ cachedTokens?: number;
59
+ cacheWriteTokens?: number;
60
+ reasoningTokens?: number;
61
+ costUSD?: number;
62
+ }): CliUsage;
63
+ /** An `unsupported-option` error for an adapter. */
64
+ declare function unsupportedOption(adapter: {
65
+ name: string;
66
+ title: string;
67
+ }, message: string): CliError;
68
+ /** Parse a JSON-encoded tool-arguments string; keeps the raw string when it is not JSON. */
69
+ declare function parseArguments(value: unknown): unknown;
70
+ /**
71
+ * Usage in the Anthropic Messages shape (`input_tokens` excludes cache reads
72
+ * and writes, which are reported separately). `input` is the sum of all
73
+ * three, matching the framework rule that `input` includes cached tokens.
74
+ */
75
+ declare function anthropicUsage(usage: Record<string, unknown> | undefined, costUSD?: number): CliUsage | undefined;
76
+ //#endregion
77
+ export { anthropicUsage, argvPrompt, dotenvFile, jsonFile, mapEffort, mcpServersJson, parseArguments, promptFile, requirePrivateHome, unsupportedOption, usageOf };
78
+ //# sourceMappingURL=shared.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.mts","names":[],"sources":["../../../../../../../../packages/ai-cli/src/adapters/shared.ts"],"mappings":";;;;;;;;;;;;iBAUgB,UAAA,CAAW,MAAc;;iBAKzB,UAAA,CAAW,OAAA,EAAS,gBAAA,GAAmB,aAAa;;AAL3B;AAKzC;;;iBASgB,kBAAA,CACd,OAAA,EAAS,gBAAgB,EACzB,OAAA;EAAW,IAAA;EAAc,KAAA;AAAA,GACzB,MAAA;;iBAac,UAAA,CAAW,MAA8B,EAAtB,MAAM;AAhBzC;;;;;;;;;;AAAA,iBAkDgB,SAAA,CACd,MAAA,EAAQ,eAAA,EACR,MAAA,EAAQ,OAAA,CAAQ,MAAA,CAAO,eAAA;AAjDT;AAahB;;;;AAAyD;AAkCzD;AA/CgB,iBA6EA,cAAA,CACd,OAAA,EAAS,aAAA,EACT,OAAA;2CAEE,SAAA,YAhCqB;EAkCrB,QAAA,WAlCM;EAoCN,KAAA,GAAQ,MAAA,mBApCK;EAsCb,UAAA;AAAA,IAED,MAAA,SAAe,MAAA;;iBA+BF,QAAA,CAAS,KAAc;;iBAKvB,OAAA,CAAQ,MAAA;EACtB,KAAA;EACA,MAAA;EACA,KAAA;EACA,YAAA;EACA,gBAAA;EACA,eAAA;EACA,OAAA;AAAA,IACE,QAAQ;;iBAmBI,iBAAA,CACd,OAAA;EAAW,IAAA;EAAc,KAAA;AAAA,GACzB,OAAA,WACC,QAAQ;;iBAQK,cAAA,CAAe,KAAc;;;;;;iBAiB7B,cAAA,CACd,KAAA,EAAO,MAAA,+BACP,OAAA,YACC,QAAQ"}
@@ -0,0 +1,161 @@
1
+ import { CliError } from "../errors.mjs";
2
+ import path from "node:path";
3
+
4
+ //#region ../../packages/ai-cli/src/adapters/shared.ts
5
+ /**
6
+ * The prompt as an argv value. A prompt starting with `-` would be read as a
7
+ * flag by the CLI's argument parser, so it gets one leading space (harmless
8
+ * to the model, and no parser treats it as an option).
9
+ */
10
+ function argvPrompt(prompt) {
11
+ return prompt.startsWith("-") ? ` ${prompt}` : prompt;
12
+ }
13
+ /** The prompt written to `prompt.txt` in the run directory, for `transport: "file"`. */
14
+ function promptFile(context) {
15
+ return {
16
+ path: path.join(context.runDir, "prompt.txt"),
17
+ content: context.prompt
18
+ };
19
+ }
20
+ /**
21
+ * Fail closed when an option needs a file inside the CLI's config home but
22
+ * the home is not private to this run (writing it into a caller-owned or
23
+ * inherited home would leak tokens into it and race concurrent runs).
24
+ */
25
+ function requirePrivateHome(context, adapter, option) {
26
+ if (context.home === void 0 || !context.homeIsPrivate) throw new CliError(`${adapter.title} reads ${option} only from its config home; use \`home: "private"\` (the default) for runs with ${option}.`, {
27
+ type: "unsupported-option",
28
+ adapter: adapter.name
29
+ });
30
+ return context.home;
31
+ }
32
+ /** A `.env` file body. Values are written verbatim; newlines are refused. */
33
+ function dotenvFile(values) {
34
+ return Object.entries(values).map(([name, value]) => {
35
+ if (/[\r\n]/.test(value)) throw new Error(`${name} contains a newline and cannot be written to a .env file`);
36
+ return `${name}=${value}`;
37
+ }).join("\n").concat("\n");
38
+ }
39
+ /** The framework effort scale, lowest first. */
40
+ const EFFORT_ORDER = [
41
+ "none",
42
+ "minimal",
43
+ "low",
44
+ "medium",
45
+ "high",
46
+ "xhigh",
47
+ "max"
48
+ ];
49
+ /**
50
+ * Map a framework effort to a vendor's levels, following the framework
51
+ * rule: an exact level wins; otherwise the nearest higher level the vendor
52
+ * has (so `minimal` becomes `low`); a level above the vendor's highest is
53
+ * clamped to it.
54
+ *
55
+ * @example
56
+ * mapEffort("xhigh", { low: "low", medium: "medium", high: "high" }); // "high"
57
+ * mapEffort("minimal", { low: "low", medium: "medium", high: "high" }); // "low"
58
+ */
59
+ function mapEffort(effort, levels) {
60
+ const exact = levels[effort];
61
+ if (exact !== void 0) return exact;
62
+ const requested = EFFORT_ORDER.indexOf(effort);
63
+ const supported = EFFORT_ORDER.filter((level) => levels[level] !== void 0);
64
+ const chosen = supported.find((level) => EFFORT_ORDER.indexOf(level) > requested) ?? supported.at(-1);
65
+ const value = chosen === void 0 ? void 0 : levels[chosen];
66
+ if (value === void 0) throw new Error("mapEffort needs at least one vendor level");
67
+ return value;
68
+ }
69
+ /**
70
+ * The common `mcpServers` JSON shape (Claude Code, Cursor, Kimi, Droid,
71
+ * Copilot, Amp, Qwen Code …): stdio servers as `command`/`args`/`env`,
72
+ * remote servers as `url`/`headers`. `typeField` adds the `type` key the
73
+ * vendor expects (`"stdio"`, `"http"`, `"sse"`), or a renamed remote
74
+ * transport (`"streamable-http"`).
75
+ */
76
+ function mcpServersJson(servers, options = {}) {
77
+ const rendered = {};
78
+ for (const [name, server] of Object.entries(servers)) {
79
+ if (server.type === "stdio") {
80
+ rendered[name] = {
81
+ ...options.typeField ? { type: "stdio" } : {},
82
+ command: server.command,
83
+ args: server.args ?? [],
84
+ ...server.env !== void 0 ? { env: server.env } : {},
85
+ ...options.extra
86
+ };
87
+ continue;
88
+ }
89
+ const urlKey = server.type === "http" ? options.httpUrlKey ?? "url" : "url";
90
+ rendered[name] = {
91
+ ...options.typeField ? { type: server.type === "http" ? options.httpType ?? "http" : "sse" } : {},
92
+ [urlKey]: server.url,
93
+ ...server.headers !== void 0 ? { headers: server.headers } : {},
94
+ ...options.extra
95
+ };
96
+ }
97
+ return rendered;
98
+ }
99
+ /** JSON for a config file, pretty-printed with a trailing newline. */
100
+ function jsonFile(value) {
101
+ return `${JSON.stringify(value, null, 2)}\n`;
102
+ }
103
+ /** Build a `CliUsage`, computing `total` when the vendor omits it. */
104
+ function usageOf(fields) {
105
+ const input = fields.input ?? 0;
106
+ const output = fields.output ?? 0;
107
+ const usage = {
108
+ input,
109
+ output,
110
+ total: fields.total ?? input + output
111
+ };
112
+ if (fields.cachedTokens !== void 0) usage.cachedTokens = fields.cachedTokens;
113
+ if (fields.cacheWriteTokens !== void 0) usage.cacheWriteTokens = fields.cacheWriteTokens;
114
+ if (fields.reasoningTokens !== void 0) usage.reasoningTokens = fields.reasoningTokens;
115
+ if (fields.costUSD !== void 0) usage.costUSD = fields.costUSD;
116
+ return usage;
117
+ }
118
+ /** An `unsupported-option` error for an adapter. */
119
+ function unsupportedOption(adapter, message) {
120
+ return new CliError(`${adapter.title}: ${message}`, {
121
+ type: "unsupported-option",
122
+ adapter: adapter.name
123
+ });
124
+ }
125
+ /** Parse a JSON-encoded tool-arguments string; keeps the raw string when it is not JSON. */
126
+ function parseArguments(value) {
127
+ if (typeof value !== "string") return value;
128
+ try {
129
+ return JSON.parse(value);
130
+ } catch {
131
+ return value;
132
+ }
133
+ }
134
+ /**
135
+ * Usage in the Anthropic Messages shape (`input_tokens` excludes cache reads
136
+ * and writes, which are reported separately). `input` is the sum of all
137
+ * three, matching the framework rule that `input` includes cached tokens.
138
+ */
139
+ function anthropicUsage(usage, costUSD) {
140
+ if (usage === void 0) return;
141
+ const read = (key) => {
142
+ const value = usage[key];
143
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
144
+ };
145
+ const uncached = read("input_tokens") ?? 0;
146
+ const cacheRead = read("cache_read_input_tokens");
147
+ const cacheWrite = read("cache_creation_input_tokens");
148
+ const output = read("output_tokens") ?? 0;
149
+ return usageOf({
150
+ input: uncached + (cacheRead ?? 0) + (cacheWrite ?? 0),
151
+ output,
152
+ cachedTokens: cacheRead !== void 0 && cacheRead > 0 ? cacheRead : void 0,
153
+ cacheWriteTokens: cacheWrite !== void 0 && cacheWrite > 0 ? cacheWrite : void 0,
154
+ reasoningTokens: read("reasoning_tokens") || void 0,
155
+ costUSD
156
+ });
157
+ }
158
+
159
+ //#endregion
160
+ export { anthropicUsage, argvPrompt, dotenvFile, jsonFile, mapEffort, mcpServersJson, parseArguments, promptFile, requirePrivateHome, unsupportedOption, usageOf };
161
+ //# sourceMappingURL=shared.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.mjs","names":[],"sources":["../../../../../../../../packages/ai-cli/src/adapters/shared.ts"],"sourcesContent":["import path from \"node:path\";\nimport type { ReasoningEffort } from \"@warlock.js/ai\";\nimport type { CliLaunchContext, CliLaunchFile, CliMcpServers, CliUsage } from \"../contracts\";\nimport { CliError } from \"../errors\";\n\n/**\n * The prompt as an argv value. A prompt starting with `-` would be read as a\n * flag by the CLI's argument parser, so it gets one leading space (harmless\n * to the model, and no parser treats it as an option).\n */\nexport function argvPrompt(prompt: string): string {\n return prompt.startsWith(\"-\") ? ` ${prompt}` : prompt;\n}\n\n/** The prompt written to `prompt.txt` in the run directory, for `transport: \"file\"`. */\nexport function promptFile(context: CliLaunchContext): CliLaunchFile {\n return { path: path.join(context.runDir, \"prompt.txt\"), content: context.prompt };\n}\n\n/**\n * Fail closed when an option needs a file inside the CLI's config home but\n * the home is not private to this run (writing it into a caller-owned or\n * inherited home would leak tokens into it and race concurrent runs).\n */\nexport function requirePrivateHome(\n context: CliLaunchContext,\n adapter: { name: string; title: string },\n option: string,\n): string {\n if (context.home === undefined || !context.homeIsPrivate) {\n throw new CliError(\n `${adapter.title} reads ${option} only from its config home; use \\`home: \"private\"\\` (the default) for runs with ${option}.`,\n { type: \"unsupported-option\", adapter: adapter.name },\n );\n }\n\n return context.home;\n}\n\n/** A `.env` file body. Values are written verbatim; newlines are refused. */\nexport function dotenvFile(values: Record<string, string>): string {\n return Object.entries(values)\n .map(([name, value]) => {\n if (/[\\r\\n]/.test(value)) {\n throw new Error(`${name} contains a newline and cannot be written to a .env file`);\n }\n\n return `${name}=${value}`;\n })\n .join(\"\\n\")\n .concat(\"\\n\");\n}\n\n/** The framework effort scale, lowest first. */\nconst EFFORT_ORDER: readonly ReasoningEffort[] = [\n \"none\",\n \"minimal\",\n \"low\",\n \"medium\",\n \"high\",\n \"xhigh\",\n \"max\",\n];\n\n/**\n * Map a framework effort to a vendor's levels, following the framework\n * rule: an exact level wins; otherwise the nearest higher level the vendor\n * has (so `minimal` becomes `low`); a level above the vendor's highest is\n * clamped to it.\n *\n * @example\n * mapEffort(\"xhigh\", { low: \"low\", medium: \"medium\", high: \"high\" }); // \"high\"\n * mapEffort(\"minimal\", { low: \"low\", medium: \"medium\", high: \"high\" }); // \"low\"\n */\nexport function mapEffort(\n effort: ReasoningEffort,\n levels: Partial<Record<ReasoningEffort, string>>,\n): string {\n const exact = levels[effort];\n\n if (exact !== undefined) {\n return exact;\n }\n\n const requested = EFFORT_ORDER.indexOf(effort);\n const supported = EFFORT_ORDER.filter((level) => levels[level] !== undefined);\n const higher = supported.find((level) => EFFORT_ORDER.indexOf(level) > requested);\n const chosen = higher ?? supported.at(-1);\n const value = chosen === undefined ? undefined : levels[chosen];\n\n if (value === undefined) {\n throw new Error(\"mapEffort needs at least one vendor level\");\n }\n\n return value;\n}\n\n/**\n * The common `mcpServers` JSON shape (Claude Code, Cursor, Kimi, Droid,\n * Copilot, Amp, Qwen Code …): stdio servers as `command`/`args`/`env`,\n * remote servers as `url`/`headers`. `typeField` adds the `type` key the\n * vendor expects (`\"stdio\"`, `\"http\"`, `\"sse\"`), or a renamed remote\n * transport (`\"streamable-http\"`).\n */\nexport function mcpServersJson(\n servers: CliMcpServers,\n options: {\n /** Emit a `type` key on every server. */\n typeField?: boolean;\n /** Value of `type` for streamable HTTP servers. Default `\"http\"`. */\n httpType?: string;\n /** Extra keys merged into every server (for example `tools: [\"*\"]`). */\n extra?: Record<string, unknown>;\n /** Key holding a streamable-HTTP URL. Default `\"url\"`. */\n httpUrlKey?: string;\n } = {},\n): Record<string, Record<string, unknown>> {\n const rendered: Record<string, Record<string, unknown>> = {};\n\n for (const [name, server] of Object.entries(servers)) {\n if (server.type === \"stdio\") {\n rendered[name] = {\n ...(options.typeField ? { type: \"stdio\" } : {}),\n command: server.command,\n args: server.args ?? [],\n ...(server.env !== undefined ? { env: server.env } : {}),\n ...options.extra,\n };\n continue;\n }\n\n const urlKey = server.type === \"http\" ? (options.httpUrlKey ?? \"url\") : \"url\";\n\n rendered[name] = {\n ...(options.typeField\n ? { type: server.type === \"http\" ? (options.httpType ?? \"http\") : \"sse\" }\n : {}),\n [urlKey]: server.url,\n ...(server.headers !== undefined ? { headers: server.headers } : {}),\n ...options.extra,\n };\n }\n\n return rendered;\n}\n\n/** JSON for a config file, pretty-printed with a trailing newline. */\nexport function jsonFile(value: unknown): string {\n return `${JSON.stringify(value, null, 2)}\\n`;\n}\n\n/** Build a `CliUsage`, computing `total` when the vendor omits it. */\nexport function usageOf(fields: {\n input?: number;\n output?: number;\n total?: number;\n cachedTokens?: number;\n cacheWriteTokens?: number;\n reasoningTokens?: number;\n costUSD?: number;\n}): CliUsage {\n const input = fields.input ?? 0;\n const output = fields.output ?? 0;\n const usage: CliUsage = { input, output, total: fields.total ?? input + output };\n\n if (fields.cachedTokens !== undefined) usage.cachedTokens = fields.cachedTokens;\n if (fields.cacheWriteTokens !== undefined) usage.cacheWriteTokens = fields.cacheWriteTokens;\n if (fields.reasoningTokens !== undefined) usage.reasoningTokens = fields.reasoningTokens;\n if (fields.costUSD !== undefined) usage.costUSD = fields.costUSD;\n\n return usage;\n}\n\n/** The first `undefined`-free value. */\nexport function firstDefined<T>(...values: Array<T | undefined>): T | undefined {\n return values.find((value) => value !== undefined);\n}\n\n/** An `unsupported-option` error for an adapter. */\nexport function unsupportedOption(\n adapter: { name: string; title: string },\n message: string,\n): CliError {\n return new CliError(`${adapter.title}: ${message}`, {\n type: \"unsupported-option\",\n adapter: adapter.name,\n });\n}\n\n/** Parse a JSON-encoded tool-arguments string; keeps the raw string when it is not JSON. */\nexport function parseArguments(value: unknown): unknown {\n if (typeof value !== \"string\") {\n return value;\n }\n\n try {\n return JSON.parse(value) as unknown;\n } catch {\n return value;\n }\n}\n\n/**\n * Usage in the Anthropic Messages shape (`input_tokens` excludes cache reads\n * and writes, which are reported separately). `input` is the sum of all\n * three, matching the framework rule that `input` includes cached tokens.\n */\nexport function anthropicUsage(\n usage: Record<string, unknown> | undefined,\n costUSD?: number,\n): CliUsage | undefined {\n if (usage === undefined) {\n return undefined;\n }\n\n const read = (key: string): number | undefined => {\n const value = usage[key];\n\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n };\n const uncached = read(\"input_tokens\") ?? 0;\n const cacheRead = read(\"cache_read_input_tokens\");\n const cacheWrite = read(\"cache_creation_input_tokens\");\n const output = read(\"output_tokens\") ?? 0;\n const input = uncached + (cacheRead ?? 0) + (cacheWrite ?? 0);\n\n return usageOf({\n input,\n output,\n cachedTokens: cacheRead !== undefined && cacheRead > 0 ? cacheRead : undefined,\n cacheWriteTokens: cacheWrite !== undefined && cacheWrite > 0 ? cacheWrite : undefined,\n reasoningTokens: read(\"reasoning_tokens\") || undefined,\n costUSD,\n });\n}\n"],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import { CliAdapter } from "./contracts/adapter.contract.mjs";
2
+ import { CliAgentOptions, CliProbeResult, CliRunOptions, CliSession } from "./contracts/options.type.mjs";
3
+ import { CliModelConfig } from "./model/cli-model.mjs";
4
+ import { CommandLookup } from "./spawn/resolve-command.mjs";
5
+ import { ModelContract } from "@warlock.js/ai";
6
+
7
+ //#region ../../packages/ai-cli/src/cli-agent.d.ts
8
+ /** A configured coding CLI: run prompts, probe the binary, or use it as an `ai.agent` model. */
9
+ type CliAgent = {
10
+ readonly adapter: CliAdapter;
11
+ readonly options: Readonly<CliAgentOptions>;
12
+ /**
13
+ * Start a session. Rejects (with {@link CliError}) only for setup problems
14
+ * — executable not found, a flag missing from `--help`, an unsupported
15
+ * option; the run's own outcome is reported by `session.done()`.
16
+ */
17
+ run(prompt: string, options?: CliRunOptions): Promise<CliSession>; /** Run (or reuse) the capability probe: resolved executable, version and help text. */
18
+ probe(): Promise<CliProbeResult>; /** This CLI as an `ai.agent` model (see {@link cliModel}). */
19
+ model(config?: CliModelConfig): ModelContract;
20
+ };
21
+ /** Host facts, injectable for tests. */
22
+ type CliHost = CommandLookup & {
23
+ comspec: string;
24
+ };
25
+ /** The current machine as a {@link CliHost}. */
26
+ declare function currentHost(): CliHost;
27
+ /**
28
+ * Create a CLI agent from an adapter. The vendor factories
29
+ * (`cli.claudeCode(...)`, `cli.codex(...)`, …) call this with their
30
+ * built-in adapter; call it directly with your own {@link CliAdapter}.
31
+ *
32
+ * @example
33
+ * const agent = createCliAgent(myAdapter, { model: "fast", permission: "standard" });
34
+ * const session = await agent.run("Summarize README.md", { cwd: "/srv/repo" });
35
+ * console.log((await session.done()).text);
36
+ */
37
+ declare function createCliAgent(adapter: CliAdapter, options?: CliAgentOptions, host?: CliHost): CliAgent;
38
+ //#endregion
39
+ export { CliAgent, CliHost, createCliAgent, currentHost };
40
+ //# sourceMappingURL=cli-agent.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-agent.d.mts","names":[],"sources":["../../../../../../../packages/ai-cli/src/cli-agent.ts"],"mappings":";;;;;;;;KA2BY,QAAA;EAAA,SACD,OAAA,EAAS,UAAA;EAAA,SACT,OAAA,EAAS,QAAA,CAAS,eAAA;EAFjB;;;;;EAQV,GAAA,CAAI,MAAA,UAAgB,OAAA,GAAU,aAAA,GAAgB,OAAA,CAAQ,UAAA,GAAxB;EAE9B,KAAA,IAAS,OAAA,CAAQ,cAAA,GAF6B;EAI9C,KAAA,CAAM,MAAA,GAAS,cAAA,GAAiB,aAAA;AAAA;;KAItB,OAAA,GAAU,aAAa;EAAK,OAAO;AAAA;;iBAmB/B,WAAA,IAAe,OAAO;;;;;;;;;;;iBAoCtB,cAAA,CACd,OAAA,EAAS,UAAA,EACT,OAAA,GAAS,eAAA,EACT,IAAA,GAAM,OAAA,GACL,QAAA"}
@@ -0,0 +1,207 @@
1
+ import { CliError } from "./errors.mjs";
2
+ import { cliModel } from "./model/cli-model.mjs";
3
+ import { buildInvocation, fitsCommandLine } from "./spawn/invocation.mjs";
4
+ import { assertCapabilities, probeCli } from "./probe/probe.mjs";
5
+ import { buildEnvironment } from "./session/environment.mjs";
6
+ import { createRunDirectories, writeLaunchFiles } from "./session/run-directory.mjs";
7
+ import { cancelledSession, startSession } from "./session/session.mjs";
8
+ import { readEnv, resolveSpawnTarget } from "./spawn/resolve-command.mjs";
9
+ import { accessSync, constants, readFileSync, statSync } from "node:fs";
10
+ import path from "node:path";
11
+
12
+ //#region ../../packages/ai-cli/src/cli-agent.ts
13
+ function isRunnableFile(filePath, platform) {
14
+ try {
15
+ if (!statSync(filePath).isFile()) return false;
16
+ if (platform !== "win32") accessSync(filePath, constants.X_OK);
17
+ return true;
18
+ } catch {
19
+ return false;
20
+ }
21
+ }
22
+ /** The current machine as a {@link CliHost}. */
23
+ function currentHost() {
24
+ const platform = process.platform;
25
+ return {
26
+ platform,
27
+ env: process.env,
28
+ isFile: (filePath) => isRunnableFile(filePath, platform),
29
+ readFile: (filePath) => {
30
+ try {
31
+ return readFileSync(filePath, "utf8");
32
+ } catch {
33
+ return;
34
+ }
35
+ },
36
+ execPath: process.execPath,
37
+ comspec: readEnv(process.env, "ComSpec", platform) ?? "cmd.exe"
38
+ };
39
+ }
40
+ function unsupported(adapter, message) {
41
+ return new CliError(`${adapter.title}: ${message}`, {
42
+ type: "unsupported-option",
43
+ adapter: adapter.name
44
+ });
45
+ }
46
+ /**
47
+ * Create a CLI agent from an adapter. The vendor factories
48
+ * (`cli.claudeCode(...)`, `cli.codex(...)`, …) call this with their
49
+ * built-in adapter; call it directly with your own {@link CliAdapter}.
50
+ *
51
+ * @example
52
+ * const agent = createCliAgent(myAdapter, { model: "fast", permission: "standard" });
53
+ * const session = await agent.run("Summarize README.md", { cwd: "/srv/repo" });
54
+ * console.log((await session.done()).text);
55
+ */
56
+ function createCliAgent(adapter, options = {}, host = currentHost()) {
57
+ const probes = /* @__PURE__ */ new Map();
58
+ const command = options.command ?? adapter.command;
59
+ const resolveTarget = () => {
60
+ const target = resolveSpawnTarget(command, host);
61
+ if (target === void 0) throw new CliError(`${adapter.title}: could not find "${command}" on PATH. Install the CLI or pass its absolute path as \`command\`.`, {
62
+ type: "not-found",
63
+ adapter: adapter.name
64
+ });
65
+ return target;
66
+ };
67
+ const probeEnvironment = () => buildEnvironment({
68
+ source: host.env,
69
+ inherit: options.inheritEnv ?? true,
70
+ managed: [],
71
+ user: options.env,
72
+ platform: host.platform
73
+ });
74
+ const probeTarget = (target) => {
75
+ const cached = probes.get(target.executable);
76
+ if (cached !== void 0) return cached;
77
+ const pending = probeCli({
78
+ adapter,
79
+ target,
80
+ env: probeEnvironment(),
81
+ cwd: path.resolve(options.cwd ?? process.cwd()),
82
+ comspec: host.comspec,
83
+ platform: host.platform
84
+ });
85
+ probes.set(target.executable, pending);
86
+ pending.catch(() => probes.delete(target.executable));
87
+ return pending;
88
+ };
89
+ const run = async (prompt, runOptions = {}) => {
90
+ const merged = {
91
+ ...options,
92
+ ...runOptions,
93
+ env: {
94
+ ...options.env,
95
+ ...runOptions.env
96
+ },
97
+ args: [...options.args ?? [], ...runOptions.args ?? []],
98
+ mcp: runOptions.mcp ?? options.mcp
99
+ };
100
+ const permission = merged.permission ?? "standard";
101
+ if (permission !== "standard" && permission !== "bypass") throw unsupported(adapter, `unknown permission "${String(permission)}" (use "standard" or "bypass").`);
102
+ if (merged.effort !== void 0 && adapter.effort !== true) throw unsupported(adapter, "this CLI has no reasoning-effort control; drop `effort`.");
103
+ const mcp = merged.mcp !== void 0 && Object.keys(merged.mcp).length > 0 ? merged.mcp : void 0;
104
+ if (mcp !== void 0 && adapter.mcp !== true) throw unsupported(adapter, "this CLI cannot attach per-run MCP servers; drop `mcp`.");
105
+ if (merged.apiKey !== void 0 && adapter.apiKeyEnv.length === 0) throw unsupported(adapter, "this CLI reads no API key from the environment; drop `apiKey`.");
106
+ const home = options.home ?? "private";
107
+ if (home !== "inherit" && adapter.homeEnv.length === 0) throw unsupported(adapter, "this CLI cannot relocate its config home; use `home: \"inherit\"`.");
108
+ const cwd = path.resolve(merged.cwd ?? process.cwd());
109
+ const target = resolveTarget();
110
+ const probe = options.probe === false ? void 0 : await probeTarget(target);
111
+ if (merged.signal?.aborted) return cancelledSession(adapter.name, merged.resume);
112
+ const directories = await createRunDirectories(home, cwd);
113
+ try {
114
+ let chosen;
115
+ const reasons = [];
116
+ for (const transport of adapter.transports) {
117
+ const context = {
118
+ prompt,
119
+ transport,
120
+ cwd,
121
+ model: merged.model,
122
+ effort: merged.effort,
123
+ permission,
124
+ resume: merged.resume,
125
+ mcp,
126
+ apiKey: merged.apiKey,
127
+ home: directories.home,
128
+ homeIsPrivate: directories.homeIsPrivate,
129
+ runDir: directories.runDir,
130
+ platform: host.platform
131
+ };
132
+ const plan = adapter.plan(context);
133
+ if (probe !== void 0) assertCapabilities(adapter, probe, plan.requires);
134
+ const invocation = buildInvocation(target, [
135
+ ...plan.args,
136
+ ...merged.args ?? [],
137
+ ...plan.tail ?? []
138
+ ], host.comspec);
139
+ if ("refused" in invocation) {
140
+ reasons.push(`${transport}: ${invocation.refused}`);
141
+ continue;
142
+ }
143
+ if (!fitsCommandLine(invocation, host.platform)) {
144
+ reasons.push(`${transport}: the command line exceeds the platform limit`);
145
+ continue;
146
+ }
147
+ chosen = {
148
+ plan,
149
+ invocation,
150
+ context
151
+ };
152
+ break;
153
+ }
154
+ if (chosen === void 0) throw new CliError(`${adapter.title}: the prompt cannot be passed to "${target.executable}" (${reasons.join("; ")}).`, {
155
+ type: "prompt-transport",
156
+ adapter: adapter.name,
157
+ executable: target.executable
158
+ });
159
+ await writeLaunchFiles(chosen.plan.files ?? [], directories);
160
+ const apiKeyEnv = adapter.apiKeyEnv[0];
161
+ const env = buildEnvironment({
162
+ source: host.env,
163
+ inherit: options.inheritEnv ?? true,
164
+ managed: home === "inherit" ? [] : adapter.homeEnv,
165
+ plan: host.platform === "win32" ? chosen.plan.env : {
166
+ PWD: cwd,
167
+ ...chosen.plan.env
168
+ },
169
+ user: merged.env,
170
+ apiKey: merged.apiKey !== void 0 && apiKeyEnv !== void 0 ? {
171
+ name: apiKeyEnv,
172
+ value: merged.apiKey
173
+ } : void 0,
174
+ platform: host.platform
175
+ });
176
+ return startSession({
177
+ adapter: adapter.name,
178
+ invocation: chosen.invocation,
179
+ cwd,
180
+ env,
181
+ stdin: chosen.plan.stdin,
182
+ parser: adapter.parser(chosen.context),
183
+ signal: merged.signal,
184
+ timeoutMs: merged.timeoutMs,
185
+ killGraceMs: options.killGraceMs ?? 2e3,
186
+ platform: host.platform,
187
+ resume: merged.resume,
188
+ cleanup: directories.dispose
189
+ });
190
+ } catch (error) {
191
+ await directories.dispose();
192
+ throw error;
193
+ }
194
+ };
195
+ const agent = {
196
+ adapter,
197
+ options,
198
+ run,
199
+ probe: () => probeTarget(resolveTarget()),
200
+ model: (config) => cliModel(agent, config)
201
+ };
202
+ return agent;
203
+ }
204
+
205
+ //#endregion
206
+ export { createCliAgent, currentHost };
207
+ //# sourceMappingURL=cli-agent.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-agent.mjs","names":[],"sources":["../../../../../../../packages/ai-cli/src/cli-agent.ts"],"sourcesContent":["import { accessSync, constants, readFileSync, statSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type {\n CliAdapter,\n CliAgentOptions,\n CliLaunchContext,\n CliLaunchPlan,\n CliProbeResult,\n CliRunOptions,\n CliSession,\n} from \"./contracts\";\nimport type { ModelContract } from \"@warlock.js/ai\";\nimport { CliError } from \"./errors\";\nimport { type CliModelConfig, cliModel } from \"./model/cli-model\";\nimport { assertCapabilities, probeCli } from \"./probe/probe\";\nimport { buildEnvironment } from \"./session/environment\";\nimport { createRunDirectories, writeLaunchFiles } from \"./session/run-directory\";\nimport { cancelledSession, startSession } from \"./session/session\";\nimport { buildInvocation, fitsCommandLine, type Invocation } from \"./spawn/invocation\";\nimport {\n type CommandLookup,\n readEnv,\n resolveSpawnTarget,\n type SpawnTarget,\n} from \"./spawn/resolve-command\";\n\n/** A configured coding CLI: run prompts, probe the binary, or use it as an `ai.agent` model. */\nexport type CliAgent = {\n readonly adapter: CliAdapter;\n readonly options: Readonly<CliAgentOptions>;\n /**\n * Start a session. Rejects (with {@link CliError}) only for setup problems\n * — executable not found, a flag missing from `--help`, an unsupported\n * option; the run's own outcome is reported by `session.done()`.\n */\n run(prompt: string, options?: CliRunOptions): Promise<CliSession>;\n /** Run (or reuse) the capability probe: resolved executable, version and help text. */\n probe(): Promise<CliProbeResult>;\n /** This CLI as an `ai.agent` model (see {@link cliModel}). */\n model(config?: CliModelConfig): ModelContract;\n};\n\n/** Host facts, injectable for tests. */\nexport type CliHost = CommandLookup & { comspec: string };\n\nfunction isRunnableFile(filePath: string, platform: NodeJS.Platform): boolean {\n try {\n if (!statSync(filePath).isFile()) {\n return false;\n }\n\n if (platform !== \"win32\") {\n accessSync(filePath, constants.X_OK);\n }\n\n return true;\n } catch {\n return false;\n }\n}\n\n/** The current machine as a {@link CliHost}. */\nexport function currentHost(): CliHost {\n const platform = process.platform;\n\n return {\n platform,\n env: process.env,\n isFile: (filePath) => isRunnableFile(filePath, platform),\n readFile: (filePath) => {\n try {\n return readFileSync(filePath, \"utf8\");\n } catch {\n return undefined;\n }\n },\n execPath: process.execPath,\n comspec: readEnv(process.env, \"ComSpec\", platform) ?? \"cmd.exe\",\n };\n}\n\nfunction unsupported(adapter: CliAdapter, message: string): CliError {\n return new CliError(`${adapter.title}: ${message}`, {\n type: \"unsupported-option\",\n adapter: adapter.name,\n });\n}\n\n/**\n * Create a CLI agent from an adapter. The vendor factories\n * (`cli.claudeCode(...)`, `cli.codex(...)`, …) call this with their\n * built-in adapter; call it directly with your own {@link CliAdapter}.\n *\n * @example\n * const agent = createCliAgent(myAdapter, { model: \"fast\", permission: \"standard\" });\n * const session = await agent.run(\"Summarize README.md\", { cwd: \"/srv/repo\" });\n * console.log((await session.done()).text);\n */\nexport function createCliAgent(\n adapter: CliAdapter,\n options: CliAgentOptions = {},\n host: CliHost = currentHost(),\n): CliAgent {\n const probes = new Map<string, Promise<CliProbeResult>>();\n const command = options.command ?? adapter.command;\n\n const resolveTarget = (): SpawnTarget => {\n const target = resolveSpawnTarget(command, host);\n\n if (target === undefined) {\n throw new CliError(\n `${adapter.title}: could not find \"${command}\" on PATH. Install the CLI or pass its absolute path as \\`command\\`.`,\n { type: \"not-found\", adapter: adapter.name },\n );\n }\n\n return target;\n };\n\n const probeEnvironment = (): Record<string, string> =>\n buildEnvironment({\n source: host.env,\n inherit: options.inheritEnv ?? true,\n managed: [],\n user: options.env,\n platform: host.platform,\n });\n\n const probeTarget = (target: SpawnTarget): Promise<CliProbeResult> => {\n const cached = probes.get(target.executable);\n\n if (cached !== undefined) {\n return cached;\n }\n\n const pending = probeCli({\n adapter,\n target,\n env: probeEnvironment(),\n cwd: path.resolve(options.cwd ?? process.cwd()),\n comspec: host.comspec,\n platform: host.platform,\n });\n\n probes.set(target.executable, pending);\n // A failed probe is retried on the next run instead of being cached.\n pending.catch(() => probes.delete(target.executable));\n\n return pending;\n };\n\n const run = async (prompt: string, runOptions: CliRunOptions = {}): Promise<CliSession> => {\n const merged: CliRunOptions = {\n ...options,\n ...runOptions,\n env: { ...options.env, ...runOptions.env },\n args: [...(options.args ?? []), ...(runOptions.args ?? [])],\n mcp: runOptions.mcp ?? options.mcp,\n };\n const permission = merged.permission ?? \"standard\";\n\n if (permission !== \"standard\" && permission !== \"bypass\") {\n throw unsupported(\n adapter,\n `unknown permission \"${String(permission)}\" (use \"standard\" or \"bypass\").`,\n );\n }\n\n if (merged.effort !== undefined && adapter.effort !== true) {\n throw unsupported(adapter, \"this CLI has no reasoning-effort control; drop `effort`.\");\n }\n\n const mcp =\n merged.mcp !== undefined && Object.keys(merged.mcp).length > 0 ? merged.mcp : undefined;\n\n if (mcp !== undefined && adapter.mcp !== true) {\n throw unsupported(adapter, \"this CLI cannot attach per-run MCP servers; drop `mcp`.\");\n }\n\n if (merged.apiKey !== undefined && adapter.apiKeyEnv.length === 0) {\n throw unsupported(adapter, \"this CLI reads no API key from the environment; drop `apiKey`.\");\n }\n\n const home = options.home ?? \"private\";\n\n if (home !== \"inherit\" && adapter.homeEnv.length === 0) {\n throw unsupported(\n adapter,\n 'this CLI cannot relocate its config home; use `home: \"inherit\"`.',\n );\n }\n\n const cwd = path.resolve(merged.cwd ?? process.cwd());\n const target = resolveTarget();\n const probe = options.probe === false ? undefined : await probeTarget(target);\n\n if (merged.signal?.aborted) {\n return cancelledSession(adapter.name, merged.resume);\n }\n\n const directories = await createRunDirectories(home, cwd);\n\n try {\n let chosen:\n | { plan: CliLaunchPlan; invocation: Invocation; context: CliLaunchContext }\n | undefined;\n const reasons: string[] = [];\n\n for (const transport of adapter.transports) {\n const context: CliLaunchContext = {\n prompt,\n transport,\n cwd,\n model: merged.model,\n effort: merged.effort,\n permission,\n resume: merged.resume,\n mcp,\n apiKey: merged.apiKey,\n home: directories.home,\n homeIsPrivate: directories.homeIsPrivate,\n runDir: directories.runDir,\n platform: host.platform,\n };\n const plan = adapter.plan(context);\n\n if (probe !== undefined) {\n assertCapabilities(adapter, probe, plan.requires);\n }\n\n const invocation = buildInvocation(\n target,\n [...plan.args, ...(merged.args ?? []), ...(plan.tail ?? [])],\n host.comspec,\n );\n\n if (\"refused\" in invocation) {\n reasons.push(`${transport}: ${invocation.refused}`);\n continue;\n }\n\n if (!fitsCommandLine(invocation, host.platform)) {\n reasons.push(`${transport}: the command line exceeds the platform limit`);\n continue;\n }\n\n chosen = { plan, invocation, context };\n break;\n }\n\n if (chosen === undefined) {\n throw new CliError(\n `${adapter.title}: the prompt cannot be passed to \"${target.executable}\" (${reasons.join(\"; \")}).`,\n { type: \"prompt-transport\", adapter: adapter.name, executable: target.executable },\n );\n }\n\n await writeLaunchFiles(chosen.plan.files ?? [], directories);\n\n const apiKeyEnv = adapter.apiKeyEnv[0];\n const env = buildEnvironment({\n source: host.env,\n inherit: options.inheritEnv ?? true,\n managed: home === \"inherit\" ? [] : adapter.homeEnv,\n // A CLI that prefers $PWD over its real cwd must not see the host's.\n plan: host.platform === \"win32\" ? chosen.plan.env : { PWD: cwd, ...chosen.plan.env },\n user: merged.env,\n apiKey:\n merged.apiKey !== undefined && apiKeyEnv !== undefined\n ? { name: apiKeyEnv, value: merged.apiKey }\n : undefined,\n platform: host.platform,\n });\n\n return startSession({\n adapter: adapter.name,\n invocation: chosen.invocation,\n cwd,\n env,\n stdin: chosen.plan.stdin,\n parser: adapter.parser(chosen.context),\n signal: merged.signal,\n timeoutMs: merged.timeoutMs,\n killGraceMs: options.killGraceMs ?? 2000,\n platform: host.platform,\n resume: merged.resume,\n cleanup: directories.dispose,\n });\n } catch (error) {\n await directories.dispose();\n throw error;\n }\n };\n\n const agent: CliAgent = {\n adapter,\n options,\n run,\n probe: () => probeTarget(resolveTarget()),\n model: (config) => cliModel(agent, config),\n };\n\n return agent;\n}\n"],"mappings":"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"}
package/esm/cli.d.mts ADDED
@@ -0,0 +1,53 @@
1
+ import { CliAdapter } from "./contracts/adapter.contract.mjs";
2
+ import { CliAgentOptions } from "./contracts/options.type.mjs";
3
+ import { cliModel } from "./model/cli-model.mjs";
4
+ import { CliAgent } from "./cli-agent.mjs";
5
+
6
+ //#region ../../packages/ai-cli/src/cli.d.ts
7
+ /** Every built-in adapter, keyed by its factory name. */
8
+ declare const cliAdapters: {
9
+ readonly claudeCode: CliAdapter;
10
+ readonly codex: CliAdapter;
11
+ readonly antigravity: CliAdapter;
12
+ readonly qwenCode: CliAdapter;
13
+ readonly kimi: CliAdapter;
14
+ readonly cursor: CliAdapter;
15
+ readonly copilot: CliAdapter;
16
+ readonly grok: CliAdapter;
17
+ readonly opencode: CliAdapter;
18
+ readonly amp: CliAdapter;
19
+ readonly droid: CliAdapter;
20
+ readonly mistralVibe: CliAdapter;
21
+ readonly aider: CliAdapter;
22
+ readonly reasonix: CliAdapter;
23
+ };
24
+ /** Name of a built-in adapter factory. */
25
+ type CliVendor = keyof typeof cliAdapters;
26
+ type VendorFactories = { [Vendor in CliVendor]: (options?: CliAgentOptions) => CliAgent };
27
+ /**
28
+ * The CLI-agent namespace: one factory per vendor, `custom()` for your own
29
+ * adapter, `model()` to hand a CLI agent to `ai.agent`. Also available as
30
+ * `ai.cli` once the package is imported.
31
+ *
32
+ * @example
33
+ * import { cli } from "@warlock.js/ai-cli";
34
+ *
35
+ * const claude = cli.claudeCode({ model: "sonnet", cwd: "/srv/repo" });
36
+ * const session = await claude.run("Fix the failing test");
37
+ * for await (const event of session.events) console.log(event.type);
38
+ * const { text, usage, sessionRef } = await session.done();
39
+ */
40
+ declare const cli: VendorFactories & {
41
+ /** A CLI agent for an adapter you wrote. */custom(adapter: CliAdapter, options?: CliAgentOptions): CliAgent; /** A CLI agent as an `ai.agent` model. */
42
+ model: typeof cliModel; /** The built-in adapters, for inspection or extension. */
43
+ adapters: typeof cliAdapters;
44
+ };
45
+ declare module "@warlock.js/ai" {
46
+ interface Ai {
47
+ /** Drive vendor coding CLIs (Claude Code, Codex, Copilot, …) as agents. */
48
+ cli: typeof cli;
49
+ }
50
+ }
51
+ //#endregion
52
+ export { CliVendor, cli, cliAdapters };
53
+ //# sourceMappingURL=cli.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.mts","names":[],"sources":["../../../../../../../packages/ai-cli/src/cli.ts"],"mappings":";;;;;;;cAoBa,WAAA;EAAA;;;;;;;;;;;;;;;;KAkBD,SAAA,gBAAyB,WAAW;AAAA,KAE3C,eAAA,gBAA+B,SAAA,IAAa,OAAA,GAAU,eAAA,KAAoB,QAAA;;;;;;;;;;;;;;cAsBlE,GAAA,EAAK,eAAA;8CAEhB,MAAA,CAAO,OAAA,EAAS,UAAA,EAAY,OAAA,GAAU,eAAA,GAAkB,QAAA;EAExD,KAAA,SAAc,QAAA;EAEd,QAAA,SAAiB,WAAA;AAAA;AAAA;EAAA,UASP,EAAA;;IAER,GAAA,SAAY,GAAG;EAAA;AAAA"}