forked from nexu-io/open-design
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclaude.ts
More file actions
98 lines (96 loc) · 4.95 KB
/
Copy pathclaude.ts
File metadata and controls
98 lines (96 loc) · 4.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import { agentCapabilities } from '../capabilities.js';
import { DEFAULT_MODEL_OPTION } from './shared.js';
import { loadMmdRouteModels } from '../mmd-routes.js';
import type { RuntimeAgentDef } from '../types.js';
const CLAUDE_FALLBACK_MODELS = [
DEFAULT_MODEL_OPTION,
{ id: 'sonnet', label: 'Sonnet (alias)' },
{ id: 'opus', label: 'Opus (alias)' },
{ id: 'haiku', label: 'Haiku (alias)' },
{ id: 'claude-opus-4-5', label: 'claude-opus-4-5' },
{ id: 'claude-sonnet-4-5', label: 'claude-sonnet-4-5' },
{ id: 'claude-haiku-4-5', label: 'claude-haiku-4-5' },
];
export const claudeAgentDef = {
id: 'claude',
name: 'Claude Code',
bin: 'claude',
// Drop-in forks that ship a CLI argv-compatible with `claude`. Tried in
// order if `claude` itself isn't on PATH, so users on a single-binary
// install (e.g. only OpenClaude — https://github.com/Gitlawb/openclaude
// — issue #235) get auto-detected without writing wrapper scripts.
fallbackBins: ['openclaude'],
versionArgs: ['--version'],
authProbe: {
args: ['auth', 'status'],
timeoutMs: 5000,
},
helpArgs: ['-p', '--help'],
capabilityFlags: {
// Flag string -> capability key. After probing `--help`, we set
// `agentCapabilities[id][key] = true` for each substring that matches.
// `--add-dir` and `--include-partial-messages` live under `claude -p`
// subcommand, so we probe `claude -p --help` instead of `claude --help`.
// Fixes issue #430: --add-dir never detected because it wasn't in global help.
'--include-partial-messages': 'partialMessages',
'--add-dir': 'addDir',
},
// `claude` has no list-models subcommand. Prefer local mmd/MMS routes
// when present so proxy-backed Claude-compatible models appear in the
// picker, then keep the built-in aliases as fallback hints.
fallbackModels: CLAUDE_FALLBACK_MODELS,
fetchModels: async (_resolvedBin, env) => loadMmdRouteModels(env, CLAUDE_FALLBACK_MODELS),
// Prompt delivered via stdin to avoid both Linux `spawn E2BIG`
// (MAX_ARG_STRLEN caps a single argv entry at ~128 KB) and Windows
// `spawn ENAMETOOLONG` (CreateProcess caps the full command line at
// ~32 KB direct, ~8 KB via .cmd shim). `claude -p` with no positional
// prompt reads the prompt from stdin under `--input-format text` (the
// default), which has no length cap. Mirrors the codex/gemini/opencode/
// cursor/qwen entries below.
buildArgs: (_prompt, _imagePaths, extraAllowedDirs = [], options = {}, runtimeContext = {}) => {
const caps = agentCapabilities.get('claude') || {};
// `--input-format stream-json` lets the daemon stream multiple JSONL
// messages into stdin instead of closing it after the initial prompt,
// keeping the turn open so the daemon can stream further user messages
// mid-conversation. Paired with `--output-format stream-json` so the
// adapter parses structured events (see claude-stream.ts).
const args = ['-p', '--input-format', 'stream-json', '--output-format', 'stream-json', '--verbose'];
// `--include-partial-messages` lands richer streaming events but only
// exists in newer Claude Code builds. Older installs reject it with
// "unknown option" and exit 1, killing the chat. Gate on the probe.
if (caps.partialMessages) {
args.push('--include-partial-messages');
}
if (options.model && options.model !== 'default') {
args.push('--model', options.model);
}
const dirs = (extraAllowedDirs || []).filter(
(d) => typeof d === 'string' && d.length > 0,
);
// `--add-dir` is older but still gate it for symmetry — old/forked
// builds may lack it.
if (dirs.length > 0 && caps.addDir !== false) {
args.push('--add-dir', ...dirs);
}
// Continue Claude's own CLI session across turns so it keeps its
// working memory (files read, edits made, tool history) instead of
// re-deriving everything from the rendered transcript each turn.
// `--resume <id>` continues a stored session; `--session-id <uuid>`
// starts a new one with an id the daemon controls and persists.
if (typeof runtimeContext.resumeSessionId === 'string' && runtimeContext.resumeSessionId) {
args.push('--resume', runtimeContext.resumeSessionId);
} else if (typeof runtimeContext.newSessionId === 'string' && runtimeContext.newSessionId) {
args.push('--session-id', runtimeContext.newSessionId);
}
args.push('--permission-mode', 'bypassPermissions');
return args;
},
promptViaStdin: true,
promptInputFormat: 'stream-json',
streamFormat: 'claude-stream-json',
// Claude Code auto-loads `.mcp.json` from the project cwd at spawn,
// so the daemon writes the user's external MCP servers there before
// launching (server.ts handles the cwd guard).
externalMcpInjection: 'claude-mcp-json',
resumesSessionViaCli: true,
} satisfies RuntimeAgentDef;