@indianaprado/claude-code-companion 0.1.0 → 0.1.3
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/README.md +50 -0
- package/package.json +1 -1
- package/scripts/claude-companion.mjs +68 -8
- package/scripts/claude-mcp-server.mjs +35 -5
- package/scripts/lib/claude.mjs +61 -9
- package/scripts/lib/jobs.mjs +1 -0
- package/scripts/lib/prompts.mjs +8 -3
- package/scripts/lib/render.mjs +2 -2
- package/skills/claude-code-runtime/SKILL.md +4 -0
package/README.md
CHANGED
|
@@ -99,6 +99,56 @@ The bundled MCP server exposes:
|
|
|
99
99
|
- `cancel`
|
|
100
100
|
|
|
101
101
|
`rescue` is write-capable by default. Pass `readOnly: true` for investigation-only delegation.
|
|
102
|
+
The plugin does not set a default Claude permission mode; pass `permissionMode: "plan"` only when
|
|
103
|
+
you explicitly want Claude's plan mode.
|
|
104
|
+
|
|
105
|
+
Modes only control edit posture:
|
|
106
|
+
|
|
107
|
+
- `normal`: no plugin-imposed permission mode.
|
|
108
|
+
- `no_write`: no plan mode; appends a no-edit instruction and denies Claude edit tools.
|
|
109
|
+
- `plan`: passes Claude `--permission-mode plan`.
|
|
110
|
+
- `auto_accept`: passes Claude `--permission-mode acceptEdits`.
|
|
111
|
+
|
|
112
|
+
The same capability flags are available in every mode:
|
|
113
|
+
|
|
114
|
+
- `tools`
|
|
115
|
+
- `allowedTools`
|
|
116
|
+
- `disallowedTools`
|
|
117
|
+
- `mcpConfig`
|
|
118
|
+
- `strictMcpConfig`
|
|
119
|
+
- `addDir`
|
|
120
|
+
|
|
121
|
+
Use `mcpConfig` to give Claude access to local MCP servers for web/search, DBs, browser tools, or
|
|
122
|
+
other local integrations. Avoid recursively giving Claude this `claude-code-companion` MCP unless you
|
|
123
|
+
explicitly want nested Claude calls.
|
|
124
|
+
|
|
125
|
+
Examples:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# Allow web search/fetch in no-write mode.
|
|
129
|
+
node scripts/claude-companion.mjs rescue --mode no_write \
|
|
130
|
+
--allowed-tools WebSearch,WebFetch \
|
|
131
|
+
"Use web search to summarize today's NBA Finals news."
|
|
132
|
+
|
|
133
|
+
# Allow local shell programs in no-write mode.
|
|
134
|
+
node scripts/claude-companion.mjs rescue --mode no_write \
|
|
135
|
+
--allowed-tools Bash \
|
|
136
|
+
"Run redis-cli PING and report the output."
|
|
137
|
+
|
|
138
|
+
# Give Claude local MCP servers.
|
|
139
|
+
node scripts/claude-companion.mjs rescue --mode no_write \
|
|
140
|
+
--mcp-config /path/to/claude-mcp-config.json \
|
|
141
|
+
--allowed-tools mcp__server_name__tool_name \
|
|
142
|
+
"Use the MCP tool and summarize the result."
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Important: `no_write` blocks Claude's built-in `Edit` and `Write` tools and tells Claude not to edit.
|
|
146
|
+
If you also grant unrestricted `Bash`, a shell command can still mutate files or external systems.
|
|
147
|
+
For hard no-write isolation with Bash/DB tools, run Claude against read-only credentials or an external
|
|
148
|
+
sandbox.
|
|
149
|
+
|
|
150
|
+
`maxBudgetUsd` is optional. Omit it for no cap. Very small caps are rejected by default because
|
|
151
|
+
Claude Code can spend more than that loading context before producing a useful reply.
|
|
102
152
|
|
|
103
153
|
`model` is optional. When omitted, the plugin does not pass `--model`, so Claude CLI chooses its
|
|
104
154
|
current default/latest model. On this machine, that currently selected `claude-opus-4-5-20251101`.
|
package/package.json
CHANGED
|
@@ -62,13 +62,21 @@ async function executeClaudeJob(cwd, job, request) {
|
|
|
62
62
|
});
|
|
63
63
|
const result = await runClaude(request.prompt, {
|
|
64
64
|
cwd,
|
|
65
|
+
mode: request.mode,
|
|
65
66
|
readOnly: request.readOnly,
|
|
66
67
|
resume: request.resume,
|
|
67
68
|
sessionId: request.sessionId,
|
|
68
69
|
model: request.model,
|
|
69
70
|
effort: request.effort,
|
|
70
71
|
maxBudgetUsd: request.maxBudgetUsd,
|
|
72
|
+
allowTinyBudget: request.allowTinyBudget,
|
|
71
73
|
permissionMode: request.permissionMode,
|
|
74
|
+
tools: request.tools,
|
|
75
|
+
allowedTools: request.allowedTools,
|
|
76
|
+
disallowedTools: request.disallowedTools,
|
|
77
|
+
mcpConfig: request.mcpConfig,
|
|
78
|
+
strictMcpConfig: request.strictMcpConfig,
|
|
79
|
+
addDir: request.addDir,
|
|
72
80
|
onStart: (pid) => {
|
|
73
81
|
markJob(cwd, job.id, { pid, phase: "claude-running" });
|
|
74
82
|
appendLog(job.logFile, `[${now()}] Claude process started pid=${pid}.\n`);
|
|
@@ -103,6 +111,7 @@ async function runJobRequest(cwd, request, options = {}) {
|
|
|
103
111
|
kind: request.kind,
|
|
104
112
|
title: request.title,
|
|
105
113
|
summary: request.summary,
|
|
114
|
+
mode: request.mode,
|
|
106
115
|
readOnly: request.readOnly,
|
|
107
116
|
background: request.background
|
|
108
117
|
});
|
|
@@ -125,11 +134,20 @@ export async function reviewCommand(input = {}) {
|
|
|
125
134
|
title: input.adversarial ? "Claude Adversarial Review" : "Claude Review",
|
|
126
135
|
summary: input.adversarial ? summarize(input.focus || "Adversarial review") : "Review current git state",
|
|
127
136
|
prompt,
|
|
137
|
+
mode: input.mode ?? "no_write",
|
|
128
138
|
readOnly: true,
|
|
129
139
|
background: Boolean(input.background),
|
|
130
140
|
model: input.model,
|
|
131
141
|
effort: input.effort,
|
|
132
|
-
maxBudgetUsd: input.maxBudgetUsd
|
|
142
|
+
maxBudgetUsd: input.maxBudgetUsd,
|
|
143
|
+
allowTinyBudget: input.allowTinyBudget,
|
|
144
|
+
permissionMode: input.permissionMode,
|
|
145
|
+
tools: input.tools,
|
|
146
|
+
allowedTools: input.allowedTools,
|
|
147
|
+
disallowedTools: input.disallowedTools,
|
|
148
|
+
mcpConfig: input.mcpConfig,
|
|
149
|
+
strictMcpConfig: input.strictMcpConfig,
|
|
150
|
+
addDir: input.addDir
|
|
133
151
|
});
|
|
134
152
|
}
|
|
135
153
|
|
|
@@ -138,13 +156,15 @@ export async function rescueCommand(input = {}) {
|
|
|
138
156
|
if (!input.prompt || !String(input.prompt).trim()) {
|
|
139
157
|
throw new Error("Provide a task prompt for Claude.");
|
|
140
158
|
}
|
|
141
|
-
const
|
|
142
|
-
const
|
|
159
|
+
const mode = input.mode ?? (input.readOnly ? "no_write" : null);
|
|
160
|
+
const readOnly = mode === "no_write";
|
|
161
|
+
const prompt = buildRescuePrompt(input.prompt, { mode, readOnly });
|
|
143
162
|
return runJobRequest(cwd, {
|
|
144
163
|
kind: "task",
|
|
145
164
|
title: input.resume ? "Claude Resume" : "Claude Task",
|
|
146
165
|
summary: summarize(input.prompt),
|
|
147
166
|
prompt,
|
|
167
|
+
mode,
|
|
148
168
|
readOnly,
|
|
149
169
|
background: Boolean(input.background),
|
|
150
170
|
resume: Boolean(input.resume),
|
|
@@ -153,7 +173,14 @@ export async function rescueCommand(input = {}) {
|
|
|
153
173
|
model: input.model,
|
|
154
174
|
effort: input.effort,
|
|
155
175
|
maxBudgetUsd: input.maxBudgetUsd,
|
|
156
|
-
|
|
176
|
+
allowTinyBudget: input.allowTinyBudget,
|
|
177
|
+
permissionMode: input.permissionMode,
|
|
178
|
+
tools: input.tools,
|
|
179
|
+
allowedTools: input.allowedTools,
|
|
180
|
+
disallowedTools: input.disallowedTools,
|
|
181
|
+
mcpConfig: input.mcpConfig,
|
|
182
|
+
strictMcpConfig: input.strictMcpConfig,
|
|
183
|
+
addDir: input.addDir
|
|
157
184
|
});
|
|
158
185
|
}
|
|
159
186
|
|
|
@@ -188,8 +215,24 @@ async function handleWorker(argv) {
|
|
|
188
215
|
async function main() {
|
|
189
216
|
const [command, ...argv] = process.argv.slice(2);
|
|
190
217
|
const common = {
|
|
191
|
-
valueOptions: [
|
|
192
|
-
|
|
218
|
+
valueOptions: [
|
|
219
|
+
"cwd",
|
|
220
|
+
"job-id",
|
|
221
|
+
"base",
|
|
222
|
+
"scope",
|
|
223
|
+
"model",
|
|
224
|
+
"effort",
|
|
225
|
+
"max-budget-usd",
|
|
226
|
+
"session-id",
|
|
227
|
+
"permission-mode",
|
|
228
|
+
"mode",
|
|
229
|
+
"tools",
|
|
230
|
+
"allowed-tools",
|
|
231
|
+
"disallowed-tools",
|
|
232
|
+
"mcp-config",
|
|
233
|
+
"add-dir"
|
|
234
|
+
],
|
|
235
|
+
booleanOptions: ["json", "background", "read-only", "write", "resume", "fresh", "all", "adversarial", "fork-session", "allow-tiny-budget", "strict-mcp-config"]
|
|
193
236
|
};
|
|
194
237
|
const { options, positionals } = parseArgs(argv, common);
|
|
195
238
|
const cwd = cwdFrom(options);
|
|
@@ -212,9 +255,18 @@ async function main() {
|
|
|
212
255
|
focus: positionals.join(" "),
|
|
213
256
|
adversarial: command === "adversarial-review" || options.adversarial,
|
|
214
257
|
background: options.background,
|
|
258
|
+
mode: options.mode,
|
|
215
259
|
model: options.model,
|
|
216
260
|
effort: options.effort,
|
|
217
|
-
maxBudgetUsd: options["max-budget-usd"]
|
|
261
|
+
maxBudgetUsd: options["max-budget-usd"],
|
|
262
|
+
allowTinyBudget: Boolean(options["allow-tiny-budget"]),
|
|
263
|
+
permissionMode: options["permission-mode"],
|
|
264
|
+
tools: options.tools,
|
|
265
|
+
allowedTools: options["allowed-tools"],
|
|
266
|
+
disallowedTools: options["disallowed-tools"],
|
|
267
|
+
mcpConfig: options["mcp-config"],
|
|
268
|
+
strictMcpConfig: Boolean(options["strict-mcp-config"]),
|
|
269
|
+
addDir: options["add-dir"]
|
|
218
270
|
});
|
|
219
271
|
output(asJson ? response : response.rendered, asJson);
|
|
220
272
|
return;
|
|
@@ -223,6 +275,7 @@ async function main() {
|
|
|
223
275
|
const response = await rescueCommand({
|
|
224
276
|
cwd,
|
|
225
277
|
prompt: positionals.join(" "),
|
|
278
|
+
mode: options.mode,
|
|
226
279
|
readOnly: Boolean(options["read-only"]) && !options.write,
|
|
227
280
|
background: options.background,
|
|
228
281
|
resume: Boolean(options.resume),
|
|
@@ -231,7 +284,14 @@ async function main() {
|
|
|
231
284
|
model: options.model,
|
|
232
285
|
effort: options.effort,
|
|
233
286
|
maxBudgetUsd: options["max-budget-usd"],
|
|
234
|
-
|
|
287
|
+
allowTinyBudget: Boolean(options["allow-tiny-budget"]),
|
|
288
|
+
permissionMode: options["permission-mode"],
|
|
289
|
+
tools: options.tools,
|
|
290
|
+
allowedTools: options["allowed-tools"],
|
|
291
|
+
disallowedTools: options["disallowed-tools"],
|
|
292
|
+
mcpConfig: options["mcp-config"],
|
|
293
|
+
strictMcpConfig: Boolean(options["strict-mcp-config"]),
|
|
294
|
+
addDir: options["add-dir"]
|
|
235
295
|
});
|
|
236
296
|
output(asJson ? response : response.rendered, asJson);
|
|
237
297
|
return;
|
|
@@ -12,6 +12,31 @@ import { renderSetup, renderStatus, renderStoredResult } from "./lib/render.mjs"
|
|
|
12
12
|
|
|
13
13
|
const PROTOCOL_VERSION = "2024-11-05";
|
|
14
14
|
|
|
15
|
+
const modeSchema = {
|
|
16
|
+
type: "string",
|
|
17
|
+
enum: ["normal", "no_write", "plan", "auto_accept"],
|
|
18
|
+
description: "Optional high-level Claude mode. normal adds no permission defaults; no_write blocks edit tools without plan mode; plan uses Claude plan mode; auto_accept uses acceptEdits."
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const stringOrArraySchema = (description) => ({
|
|
22
|
+
oneOf: [
|
|
23
|
+
{ type: "string" },
|
|
24
|
+
{ type: "array", items: { type: "string" } }
|
|
25
|
+
],
|
|
26
|
+
description
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const capabilityProperties = {
|
|
30
|
+
mode: modeSchema,
|
|
31
|
+
tools: { type: "string", description: "Optional pass-through for Claude --tools, for example 'default' or 'Bash,Read,Edit'." },
|
|
32
|
+
allowedTools: stringOrArraySchema("Optional pass-through for Claude --allowedTools."),
|
|
33
|
+
disallowedTools: stringOrArraySchema("Optional pass-through for Claude --disallowedTools."),
|
|
34
|
+
mcpConfig: stringOrArraySchema("Optional path(s) or JSON string(s) passed to Claude --mcp-config."),
|
|
35
|
+
strictMcpConfig: { type: "boolean", default: false, description: "Pass --strict-mcp-config so Claude uses only the supplied MCP config." },
|
|
36
|
+
addDir: stringOrArraySchema("Optional additional directory path(s) passed to Claude --add-dir."),
|
|
37
|
+
permissionMode: { type: "string", description: "Optional raw Claude --permission-mode. Prefer mode unless you need a CLI-specific value." }
|
|
38
|
+
};
|
|
39
|
+
|
|
15
40
|
const tools = [
|
|
16
41
|
{
|
|
17
42
|
name: "setup",
|
|
@@ -35,7 +60,9 @@ const tools = [
|
|
|
35
60
|
background: { type: "boolean", default: false },
|
|
36
61
|
model: { type: "string", description: "Optional Claude model alias or full model name. Omit to let Claude CLI choose its current default/latest model." },
|
|
37
62
|
effort: { type: "string", enum: ["low", "medium", "high", "xhigh", "max"] },
|
|
38
|
-
maxBudgetUsd: { type: "number" }
|
|
63
|
+
maxBudgetUsd: { type: "number", description: "Optional. Omit for no budget cap. Values below 0.25 are rejected unless allowTinyBudget is true." },
|
|
64
|
+
allowTinyBudget: { type: "boolean", default: false },
|
|
65
|
+
...capabilityProperties
|
|
39
66
|
}
|
|
40
67
|
}
|
|
41
68
|
},
|
|
@@ -52,7 +79,9 @@ const tools = [
|
|
|
52
79
|
background: { type: "boolean", default: false },
|
|
53
80
|
model: { type: "string", description: "Optional Claude model alias or full model name. Omit to let Claude CLI choose its current default/latest model." },
|
|
54
81
|
effort: { type: "string", enum: ["low", "medium", "high", "xhigh", "max"] },
|
|
55
|
-
maxBudgetUsd: { type: "number" }
|
|
82
|
+
maxBudgetUsd: { type: "number", description: "Optional. Omit for no budget cap. Values below 0.25 are rejected unless allowTinyBudget is true." },
|
|
83
|
+
allowTinyBudget: { type: "boolean", default: false },
|
|
84
|
+
...capabilityProperties
|
|
56
85
|
},
|
|
57
86
|
required: ["focus"]
|
|
58
87
|
}
|
|
@@ -72,8 +101,9 @@ const tools = [
|
|
|
72
101
|
forkSession: { type: "boolean", default: false, description: "Pass through Claude CLI --fork-session when resuming. Behavior depends on the installed Claude CLI." },
|
|
73
102
|
model: { type: "string", description: "Optional Claude model alias or full model name. Omit to let Claude CLI choose its current default/latest model." },
|
|
74
103
|
effort: { type: "string", enum: ["low", "medium", "high", "xhigh", "max"] },
|
|
75
|
-
maxBudgetUsd: { type: "number" },
|
|
76
|
-
|
|
104
|
+
maxBudgetUsd: { type: "number", description: "Optional. Omit for no budget cap. Values below 0.25 are rejected unless allowTinyBudget is true." },
|
|
105
|
+
allowTinyBudget: { type: "boolean", default: false },
|
|
106
|
+
...capabilityProperties
|
|
77
107
|
},
|
|
78
108
|
required: ["prompt"]
|
|
79
109
|
}
|
|
@@ -227,7 +257,7 @@ async function handle(message) {
|
|
|
227
257
|
result: {
|
|
228
258
|
protocolVersion: PROTOCOL_VERSION,
|
|
229
259
|
capabilities: { tools: {} },
|
|
230
|
-
serverInfo: { name: "claude-code-companion", version: "0.1.
|
|
260
|
+
serverInfo: { name: "claude-code-companion", version: "0.1.3" }
|
|
231
261
|
}
|
|
232
262
|
});
|
|
233
263
|
return;
|
package/scripts/lib/claude.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { binaryStatus, spawnCapture } from "./process.mjs";
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
3
|
+
const MIN_BUDGET_USD = 0.25;
|
|
4
|
+
const NO_WRITE_DISALLOWED_TOOLS = "Edit,Write";
|
|
5
|
+
const VALID_MODES = new Set(["normal", "no_write", "plan", "auto_accept"]);
|
|
5
6
|
|
|
6
7
|
export function getClaudeVersion(cwd) {
|
|
7
8
|
return binaryStatus("claude", ["--version"], { cwd });
|
|
@@ -38,6 +39,28 @@ function normalizeEffort(effort) {
|
|
|
38
39
|
return value;
|
|
39
40
|
}
|
|
40
41
|
|
|
42
|
+
function normalizeMode(mode) {
|
|
43
|
+
if (mode == null || mode === "") {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
const value = String(mode).trim();
|
|
47
|
+
if (!VALID_MODES.has(value)) {
|
|
48
|
+
throw new Error(`Unsupported Claude mode "${mode}". Use normal, no_write, plan, or auto_accept.`);
|
|
49
|
+
}
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function appendStringList(args, flag, value) {
|
|
54
|
+
if (value == null || value === false) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const values = Array.isArray(value) ? value : [value];
|
|
58
|
+
const normalized = values.map((entry) => String(entry).trim()).filter(Boolean);
|
|
59
|
+
if (normalized.length > 0) {
|
|
60
|
+
args.push(flag, ...normalized);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
41
64
|
function parseClaudeJson(stdout) {
|
|
42
65
|
const text = String(stdout ?? "").trim();
|
|
43
66
|
if (!text) {
|
|
@@ -59,6 +82,10 @@ function parseClaudeJson(stdout) {
|
|
|
59
82
|
|
|
60
83
|
export async function runClaude(prompt, options = {}) {
|
|
61
84
|
const args = ["-p", prompt, "--output-format", "json"];
|
|
85
|
+
if (options.mode && options.permissionMode) {
|
|
86
|
+
throw new Error("Use either mode or permissionMode, not both.");
|
|
87
|
+
}
|
|
88
|
+
const mode = normalizeMode(options.mode ?? (options.readOnly ? "no_write" : null));
|
|
62
89
|
if (options.resume) {
|
|
63
90
|
if (options.sessionId) {
|
|
64
91
|
args.push("--resume", options.sessionId);
|
|
@@ -78,15 +105,40 @@ export async function runClaude(prompt, options = {}) {
|
|
|
78
105
|
if (effort) {
|
|
79
106
|
args.push("--effort", effort);
|
|
80
107
|
}
|
|
81
|
-
|
|
82
|
-
|
|
108
|
+
appendStringList(args, "--add-dir", options.addDir);
|
|
109
|
+
appendStringList(args, "--mcp-config", options.mcpConfig);
|
|
110
|
+
if (options.strictMcpConfig) {
|
|
111
|
+
args.push("--strict-mcp-config");
|
|
112
|
+
}
|
|
113
|
+
if (options.tools) {
|
|
114
|
+
args.push("--tools", String(options.tools));
|
|
115
|
+
}
|
|
116
|
+
if (options.maxBudgetUsd != null) {
|
|
117
|
+
const budget = Number(options.maxBudgetUsd);
|
|
118
|
+
if (!Number.isFinite(budget) || budget <= 0) {
|
|
119
|
+
throw new Error("maxBudgetUsd must be a positive number when provided.");
|
|
120
|
+
}
|
|
121
|
+
if (budget < MIN_BUDGET_USD && !options.allowTinyBudget) {
|
|
122
|
+
throw new Error(
|
|
123
|
+
`maxBudgetUsd ${budget} is too low for Claude Code's startup/context cost. Omit maxBudgetUsd for no cap, use at least ${MIN_BUDGET_USD}, or set allowTinyBudget: true.`
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
args.push("--max-budget-usd", String(budget));
|
|
83
127
|
}
|
|
84
|
-
|
|
128
|
+
appendStringList(args, "--allowedTools", options.allowedTools);
|
|
129
|
+
appendStringList(
|
|
130
|
+
args,
|
|
131
|
+
"--disallowedTools",
|
|
132
|
+
mode === "no_write"
|
|
133
|
+
? [NO_WRITE_DISALLOWED_TOOLS, ...(Array.isArray(options.disallowedTools) ? options.disallowedTools : [options.disallowedTools]).filter(Boolean)]
|
|
134
|
+
: options.disallowedTools
|
|
135
|
+
);
|
|
136
|
+
if (mode === "plan") {
|
|
85
137
|
args.push("--permission-mode", "plan");
|
|
86
|
-
|
|
87
|
-
args.push("--
|
|
88
|
-
} else {
|
|
89
|
-
args.push("--permission-mode", options.permissionMode
|
|
138
|
+
} else if (mode === "auto_accept") {
|
|
139
|
+
args.push("--permission-mode", "acceptEdits");
|
|
140
|
+
} else if (options.permissionMode) {
|
|
141
|
+
args.push("--permission-mode", options.permissionMode);
|
|
90
142
|
}
|
|
91
143
|
|
|
92
144
|
const result = await spawnCapture("claude", args, {
|
package/scripts/lib/jobs.mjs
CHANGED
package/scripts/lib/prompts.mjs
CHANGED
|
@@ -16,9 +16,14 @@ export function buildReviewPrompt(cwd, options = {}) {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export function buildRescuePrompt(prompt, options = {}) {
|
|
19
|
-
const mode =
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
const mode =
|
|
20
|
+
options.mode === "no_write" || options.readOnly
|
|
21
|
+
? "No-write mode: investigate, reason, and report. Do not edit files."
|
|
22
|
+
: options.mode === "plan"
|
|
23
|
+
? "Plan mode requested: analyze and propose a plan without editing files."
|
|
24
|
+
: options.mode === "auto_accept"
|
|
25
|
+
? "Auto-accept mode requested: you may edit files in this checkout when needed to satisfy the task."
|
|
26
|
+
: "";
|
|
22
27
|
return [mode, "You are Claude Code being called by Codex as a companion agent.", "Task:", prompt]
|
|
23
28
|
.filter(Boolean)
|
|
24
29
|
.join("\n\n");
|
package/scripts/lib/render.mjs
CHANGED
|
@@ -37,7 +37,7 @@ export function renderTaskResult(job, result) {
|
|
|
37
37
|
"",
|
|
38
38
|
`Job: ${job.id}`,
|
|
39
39
|
`Status: ${result.status === 0 ? "completed" : "failed"}`,
|
|
40
|
-
`Mode: ${job.readOnly ? "
|
|
40
|
+
`Mode: ${job.mode ?? (job.readOnly ? "no_write" : "normal")}`,
|
|
41
41
|
result.sessionId ? `Claude session: ${result.sessionId}` : "",
|
|
42
42
|
result.costUsd != null ? `Cost: $${result.costUsd}` : "",
|
|
43
43
|
"",
|
|
@@ -60,7 +60,7 @@ export function renderStatus(jobs) {
|
|
|
60
60
|
const rows = ["| Job | Kind | Status | Phase | Mode | Elapsed | Summary |", "| --- | --- | --- | --- | --- | --- | --- |"];
|
|
61
61
|
for (const job of jobs) {
|
|
62
62
|
rows.push(
|
|
63
|
-
`| ${job.id} | ${job.kind ?? ""} | ${job.status ?? ""} | ${job.phase ?? ""} | ${job.readOnly ? "
|
|
63
|
+
`| ${job.id} | ${job.kind ?? ""} | ${job.status ?? ""} | ${job.phase ?? ""} | ${job.mode ?? (job.readOnly ? "no_write" : "normal")} | ${elapsed(job)} | ${(job.summary ?? "").replaceAll("|", "\\|")} |`
|
|
64
64
|
);
|
|
65
65
|
}
|
|
66
66
|
return `${rows.join("\n")}\n`;
|
|
@@ -24,5 +24,9 @@ Use the `claude-code-companion` MCP tools as a thin runtime bridge to the instal
|
|
|
24
24
|
- Use read-only review tools when the user asks for critique, planning, diagnosis, or a second opinion without edits.
|
|
25
25
|
- Use write-capable `rescue` when the user explicitly wants Claude to implement or fix something.
|
|
26
26
|
- Omit `model` when the user wants Claude CLI's current default/latest model. Pass `model` only when the user asks for a specific alias or full model name.
|
|
27
|
+
- Omit `maxBudgetUsd` unless the user explicitly asks for a budget cap.
|
|
28
|
+
- Omit `permissionMode` unless the user explicitly asks for a Claude permission mode such as `plan`.
|
|
29
|
+
- Use `mode: "no_write"` when Claude should be able to investigate normally but must not edit files. This is not plan mode.
|
|
30
|
+
- Capability fields (`tools`, `allowedTools`, `disallowedTools`, `mcpConfig`, `strictMcpConfig`, `addDir`) are available in every mode. Pass them only when the user wants Claude to use extra local tools, MCP servers, DB access, browser/search tools, or extra directories.
|
|
27
31
|
- Claude runs in the same checkout. Do not assume worktree isolation.
|
|
28
32
|
- Preserve the user's task text. Add only minimal context needed to make the delegation clear.
|