@dunnewold-labs/mr-manager 0.4.52 → 0.4.55
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/dist/index.mjs +182 -26
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -185,7 +185,7 @@ import { fileURLToPath } from "url";
|
|
|
185
185
|
// cli/package.json
|
|
186
186
|
var package_default = {
|
|
187
187
|
name: "@dunnewold-labs/mr-manager",
|
|
188
|
-
version: "0.4.
|
|
188
|
+
version: "0.4.55",
|
|
189
189
|
description: "Mr. Manager - Task and project management CLI",
|
|
190
190
|
bin: {
|
|
191
191
|
mr: "./dist/index.mjs"
|
|
@@ -1151,6 +1151,118 @@ function getAvailableAgentFallbackChain(agent, availability) {
|
|
|
1151
1151
|
return getAgentFallbackChain(agent).filter((candidate) => availability[candidate] !== false);
|
|
1152
1152
|
}
|
|
1153
1153
|
|
|
1154
|
+
// lib/permissions.ts
|
|
1155
|
+
var DEFAULT_HEADLESS_MODE = "bypass";
|
|
1156
|
+
var ENV_VAR = "MR_HEADLESS_PERMISSION_MODE";
|
|
1157
|
+
var DESTRUCTIVE_BASH_DENY = [
|
|
1158
|
+
// Privilege escalation.
|
|
1159
|
+
"Bash(sudo:*)",
|
|
1160
|
+
"Bash(su:*)",
|
|
1161
|
+
// Recursive deletes of broad / out-of-repo roots.
|
|
1162
|
+
"Bash(rm -rf /:*)",
|
|
1163
|
+
"Bash(rm -rf /*:*)",
|
|
1164
|
+
"Bash(rm -fr /:*)",
|
|
1165
|
+
"Bash(rm -rf ~:*)",
|
|
1166
|
+
"Bash(rm -rf ~/:*)",
|
|
1167
|
+
"Bash(rm -rf $HOME:*)",
|
|
1168
|
+
"Bash(rm -rf ..:*)",
|
|
1169
|
+
// Filesystem / device destruction.
|
|
1170
|
+
"Bash(mkfs:*)",
|
|
1171
|
+
"Bash(dd:*)",
|
|
1172
|
+
// Mass permission/ownership changes from root.
|
|
1173
|
+
"Bash(chmod -R 777 /:*)",
|
|
1174
|
+
"Bash(chown -R:*)",
|
|
1175
|
+
// Force-push (history rewrite / remote clobber).
|
|
1176
|
+
"Bash(git push --force:*)",
|
|
1177
|
+
"Bash(git push -f:*)",
|
|
1178
|
+
"Bash(git push origin --force:*)",
|
|
1179
|
+
"Bash(git push origin -f:*)",
|
|
1180
|
+
// Remote pipe-to-shell (curl|sh / wget|bash).
|
|
1181
|
+
"Bash(curl:* | sh)",
|
|
1182
|
+
"Bash(curl:* | bash)",
|
|
1183
|
+
"Bash(wget:* | sh)",
|
|
1184
|
+
"Bash(wget:* | bash)"
|
|
1185
|
+
];
|
|
1186
|
+
var OUT_OF_REPO_WRITE_DENY = [
|
|
1187
|
+
"Write(/etc/**)",
|
|
1188
|
+
"Edit(/etc/**)",
|
|
1189
|
+
"Write(//usr/**)",
|
|
1190
|
+
"Edit(//usr/**)",
|
|
1191
|
+
"Write(~/.ssh/**)",
|
|
1192
|
+
"Edit(~/.ssh/**)",
|
|
1193
|
+
"Write(~/.aws/**)",
|
|
1194
|
+
"Edit(~/.aws/**)"
|
|
1195
|
+
];
|
|
1196
|
+
var READ_ONLY_EXTRA_DENY = ["Edit", "Write", "MultiEdit", "NotebookEdit"];
|
|
1197
|
+
function resolveHeadlessMode(config) {
|
|
1198
|
+
const fromEnv = process.env[ENV_VAR]?.trim().toLowerCase();
|
|
1199
|
+
if (fromEnv === "auto" || fromEnv === "bypass") return fromEnv;
|
|
1200
|
+
const fromConfig = config?.headlessPermissionMode?.trim().toLowerCase();
|
|
1201
|
+
if (fromConfig === "auto" || fromConfig === "bypass") return fromConfig;
|
|
1202
|
+
if (config?.claudePermissionMode != null && config.headlessPermissionMode == null) {
|
|
1203
|
+
return "bypass";
|
|
1204
|
+
}
|
|
1205
|
+
return DEFAULT_HEADLESS_MODE;
|
|
1206
|
+
}
|
|
1207
|
+
function claudeDenyList(runKind) {
|
|
1208
|
+
const base = [...DESTRUCTIVE_BASH_DENY, ...OUT_OF_REPO_WRITE_DENY];
|
|
1209
|
+
if (runKind === "review" || runKind === "scan") {
|
|
1210
|
+
return [...base, ...READ_ONLY_EXTRA_DENY];
|
|
1211
|
+
}
|
|
1212
|
+
return base;
|
|
1213
|
+
}
|
|
1214
|
+
function resolvePermissionArgs(agent, runKind, mode) {
|
|
1215
|
+
if (runKind === "plan") {
|
|
1216
|
+
if (agent === "claude") {
|
|
1217
|
+
return { args: ["--permission-mode", "plan"], effectiveMode: "plan", mappedToBypassForLackOfSandbox: false };
|
|
1218
|
+
}
|
|
1219
|
+
return resolvePermissionArgs(agent, "execute", mode);
|
|
1220
|
+
}
|
|
1221
|
+
if (mode === "bypass") {
|
|
1222
|
+
return { args: bypassArgs(agent, runKind), effectiveMode: "bypass", mappedToBypassForLackOfSandbox: false };
|
|
1223
|
+
}
|
|
1224
|
+
switch (agent) {
|
|
1225
|
+
case "claude": {
|
|
1226
|
+
const deny = claudeDenyList(runKind);
|
|
1227
|
+
return {
|
|
1228
|
+
args: ["--permission-mode", "acceptEdits", "--disallowedTools", deny.join(",")],
|
|
1229
|
+
effectiveMode: "auto",
|
|
1230
|
+
mappedToBypassForLackOfSandbox: false
|
|
1231
|
+
};
|
|
1232
|
+
}
|
|
1233
|
+
case "codex": {
|
|
1234
|
+
return { args: ["-s", "workspace-write"], effectiveMode: "auto", mappedToBypassForLackOfSandbox: false };
|
|
1235
|
+
}
|
|
1236
|
+
case "antigravity":
|
|
1237
|
+
return { args: ["--dangerously-skip-permissions"], effectiveMode: "bypass", mappedToBypassForLackOfSandbox: true };
|
|
1238
|
+
default:
|
|
1239
|
+
return { args: bypassArgs(agent, runKind), effectiveMode: "bypass", mappedToBypassForLackOfSandbox: true };
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
function bypassArgs(agent, _runKind) {
|
|
1243
|
+
switch (agent) {
|
|
1244
|
+
case "codex":
|
|
1245
|
+
return ["-s", "danger-full-access"];
|
|
1246
|
+
case "antigravity":
|
|
1247
|
+
case "claude":
|
|
1248
|
+
default:
|
|
1249
|
+
return ["--dangerously-skip-permissions"];
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
function describePermissionMode(res) {
|
|
1253
|
+
if (res.mappedToBypassForLackOfSandbox) {
|
|
1254
|
+
return "bypass (no scoped sandbox for this agent \u2014 full access)";
|
|
1255
|
+
}
|
|
1256
|
+
switch (res.effectiveMode) {
|
|
1257
|
+
case "auto":
|
|
1258
|
+
return "auto (scoped: acceptEdits + destructive-command deny-list)";
|
|
1259
|
+
case "plan":
|
|
1260
|
+
return "plan (read-only)";
|
|
1261
|
+
case "bypass":
|
|
1262
|
+
return "bypass (--dangerously-skip-permissions \u2014 full access)";
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1154
1266
|
// lib/task-workflow.ts
|
|
1155
1267
|
function normalizeWhitespace(value) {
|
|
1156
1268
|
return value.replace(/\s+/g, " ").trim();
|
|
@@ -1874,14 +1986,23 @@ function mergePrViaCli(prUrl, repoDir, vcs = "github") {
|
|
|
1874
1986
|
});
|
|
1875
1987
|
});
|
|
1876
1988
|
}
|
|
1877
|
-
function buildPrototypeSection(protoRefs, workingDir) {
|
|
1989
|
+
function buildPrototypeSection(protoRefs, workingDir, mode = "build") {
|
|
1878
1990
|
if (protoRefs.length === 0) return "";
|
|
1879
|
-
const sections = [
|
|
1991
|
+
const sections = mode === "prd" ? [
|
|
1880
1992
|
``,
|
|
1881
1993
|
`## Referenced Prototypes`,
|
|
1882
1994
|
``,
|
|
1883
|
-
`The following prototype designs have been linked to this task
|
|
1884
|
-
|
|
1995
|
+
`The following prototype designs have been linked to this task. They represent the intended product UI. **Read every referenced HTML file in full** (paths below) and base the PRD's UI/functional requirements on what they show: page/screen structure, layout, every component and element, all the states depicted (empty/loading/error/populated, hover/active/disabled, etc.), navigation, and the interactions the design implies. Enumerate these as concrete requirements so the implementation phase builds the complete prototype, not just a restyle.`,
|
|
1996
|
+
``
|
|
1997
|
+
] : [
|
|
1998
|
+
``,
|
|
1999
|
+
`## Referenced Prototypes`,
|
|
2000
|
+
``,
|
|
2001
|
+
`The following prototype designs have been linked to this task. They are not loose visual inspiration \u2014 they are the intended product. Your job is to BUILD what each prototype shows: its full page/screen structure, layout, all the UI components and elements, every state shown (empty/loading/error/populated, hover/active/disabled, etc.), navigation, and the interactions and behaviors the design implies. Do not stop at restyling or "rethemeing" existing UI \u2014 implement the complete structure and functionality, wired to real data and logic where the rest of the task requires it.`,
|
|
2002
|
+
``,
|
|
2003
|
+
`**Before you start implementing, read every referenced HTML file in full** (paths are given below). Do not skip this \u2014 the HTML is the source of truth for what to build. Inspect the markup to enumerate the components, sections, and states you need to create.`,
|
|
2004
|
+
``,
|
|
2005
|
+
`Where the prototype and the task PRD/notes conflict, the PRD/notes win; otherwise treat the prototype as the spec for the UI.`,
|
|
1885
2006
|
``
|
|
1886
2007
|
];
|
|
1887
2008
|
for (const ref of protoRefs) {
|
|
@@ -1889,8 +2010,13 @@ function buildPrototypeSection(protoRefs, workingDir) {
|
|
|
1889
2010
|
const files = proto.files ?? [];
|
|
1890
2011
|
const selected = ref.selectedVariants ?? Array.from({ length: proto.variantCount }, (_, i) => i);
|
|
1891
2012
|
const selectedFiles = files.filter((_, i) => selected.includes(i));
|
|
2013
|
+
const fidelity = (proto.fidelity ?? "high").toLowerCase();
|
|
2014
|
+
const isLowFi = fidelity === "low" || fidelity === "low_fidelity";
|
|
2015
|
+
const fidelityNote = isLowFi ? `This is a LOW-FIDELITY wireframe. Build the full structure, layout, components, and behavior it shows, but do NOT copy its placeholder visual style (greys, boxes, sketchy borders) \u2014 apply the project's real design system / existing styling conventions.` : `This is a HIGH-FIDELITY design. Treat it as the definitive brief for both structure/behavior AND look-and-feel \u2014 match its layout, spacing, colors, typography, and component styling faithfully.`;
|
|
1892
2016
|
sections.push(`### ${proto.title}`);
|
|
1893
2017
|
sections.push(``);
|
|
2018
|
+
sections.push(fidelityNote);
|
|
2019
|
+
sections.push(``);
|
|
1894
2020
|
if (selectedFiles.length === 0) {
|
|
1895
2021
|
sections.push(`(No variant files available)`);
|
|
1896
2022
|
sections.push(``);
|
|
@@ -1905,7 +2031,7 @@ function buildPrototypeSection(protoRefs, workingDir) {
|
|
|
1905
2031
|
try {
|
|
1906
2032
|
writeFileSync3(tmpPath, file.content, "utf-8");
|
|
1907
2033
|
sections.push(`#### ${variantLabel}: ${file.name}`);
|
|
1908
|
-
sections.push(`File: \`${tmpPath}\` \u2014 read this file
|
|
2034
|
+
sections.push(`File: \`${tmpPath}\` \u2014 read this file in full before implementing; it is the source of truth for what to build.`);
|
|
1909
2035
|
} catch {
|
|
1910
2036
|
sections.push(`#### ${variantLabel}: ${file.name}`);
|
|
1911
2037
|
sections.push(`\`\`\`html`);
|
|
@@ -2171,7 +2297,7 @@ ${task.notes}` : "";
|
|
|
2171
2297
|
`Complete all steps autonomously without asking for confirmation. Exit with code 0 when done.`
|
|
2172
2298
|
].join("\n");
|
|
2173
2299
|
}
|
|
2174
|
-
function buildPrdPrompt(task, repoDir, existingPrd, feedbackUpdates = []) {
|
|
2300
|
+
function buildPrdPrompt(task, repoDir, existingPrd, feedbackUpdates = [], protoRefs = []) {
|
|
2175
2301
|
const notes = task.notes ? `
|
|
2176
2302
|
|
|
2177
2303
|
Task notes:
|
|
@@ -2223,6 +2349,7 @@ ${task.notes}` : "";
|
|
|
2223
2349
|
`Title: ${task.title}`,
|
|
2224
2350
|
`ID: ${task.id}${notes}`,
|
|
2225
2351
|
feedbackSection,
|
|
2352
|
+
buildPrototypeSection(protoRefs, repoDir, "prd"),
|
|
2226
2353
|
`## Instructions`,
|
|
2227
2354
|
``,
|
|
2228
2355
|
...revisionInstructions,
|
|
@@ -2836,41 +2963,46 @@ function buildRefinementPrompt(proto, parentFiles, repoDir, options = {}) {
|
|
|
2836
2963
|
].join("\n");
|
|
2837
2964
|
}
|
|
2838
2965
|
function buildAgentArgs(agent, prompt2, mode, sessionId, name, resumeSession = false, systemPrompt, maxTurns, claudeModel) {
|
|
2966
|
+
const headlessMode = resolveHeadlessMode(loadConfig());
|
|
2967
|
+
const runKind = mode === "plan" ? "plan" : "execute";
|
|
2839
2968
|
if (agent === "codex") {
|
|
2969
|
+
const permission2 = resolvePermissionArgs("codex", runKind, headlessMode);
|
|
2840
2970
|
const args = [];
|
|
2841
2971
|
if (mode === "execute") {
|
|
2842
2972
|
args.push("-a", "never");
|
|
2843
2973
|
}
|
|
2844
2974
|
args.push("exec");
|
|
2845
2975
|
if (mode === "execute") {
|
|
2846
|
-
args.push(
|
|
2976
|
+
args.push(...permission2.args);
|
|
2847
2977
|
}
|
|
2848
2978
|
const fullPrompt = systemPrompt ? `${prompt2}
|
|
2849
2979
|
|
|
2850
2980
|
${systemPrompt}` : prompt2;
|
|
2851
2981
|
args.push(fullPrompt);
|
|
2852
|
-
return { bin: "codex", args };
|
|
2982
|
+
return { bin: "codex", args, permission: permission2 };
|
|
2853
2983
|
}
|
|
2854
2984
|
if (agent === "antigravity") {
|
|
2985
|
+
const permission2 = resolvePermissionArgs("antigravity", runKind, headlessMode);
|
|
2855
2986
|
const fullPrompt = systemPrompt ? `${prompt2}
|
|
2856
2987
|
|
|
2857
2988
|
${systemPrompt}` : prompt2;
|
|
2858
2989
|
const args = ["-p", fullPrompt];
|
|
2859
2990
|
if (mode === "execute") {
|
|
2860
|
-
args.push(
|
|
2991
|
+
args.push(...permission2.args);
|
|
2861
2992
|
}
|
|
2862
|
-
return { bin: AGENT_BINARIES.antigravity, args };
|
|
2993
|
+
return { bin: AGENT_BINARIES.antigravity, args, permission: permission2 };
|
|
2863
2994
|
}
|
|
2995
|
+
const permission = resolvePermissionArgs("claude", runKind, headlessMode);
|
|
2864
2996
|
const sessionArgs = sessionId ? resumeSession ? ["--resume", sessionId] : ["--session-id", sessionId] : [];
|
|
2865
2997
|
const nameArgs = name ? ["--name", name] : [];
|
|
2866
2998
|
const systemArgs = systemPrompt ? ["--append-system-prompt", systemPrompt] : [];
|
|
2867
2999
|
const turnsArgs = maxTurns ? ["--max-turns", String(maxTurns)] : [];
|
|
2868
3000
|
const modelArgs = claudeModel ? ["--model", claudeModel] : [];
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
3001
|
+
return {
|
|
3002
|
+
bin: "claude",
|
|
3003
|
+
args: [...sessionArgs, ...nameArgs, ...systemArgs, ...turnsArgs, ...modelArgs, ...permission.args, "-p", prompt2],
|
|
3004
|
+
permission
|
|
3005
|
+
};
|
|
2874
3006
|
}
|
|
2875
3007
|
var AGENT_BINARIES = {
|
|
2876
3008
|
claude: "claude",
|
|
@@ -2953,7 +3085,13 @@ function askYesNo(question) {
|
|
|
2953
3085
|
function spawnAgent(agent, repoDir, prompt2, prefix, onActivity, sessionId, name, resumeSession = false, onSpawnError, systemPrompt, maxTurns, claudeModel, onOutputBytes) {
|
|
2954
3086
|
const jobLabel = name ?? "unknown";
|
|
2955
3087
|
console.log(`${timestamp()} ${prefix} ${paint("dim", tokenLogLine("agent", jobLabel, prompt2, systemPrompt))}`);
|
|
2956
|
-
const { bin, args } = buildAgentArgs(agent, prompt2, "execute", sessionId, name, resumeSession, systemPrompt, maxTurns, claudeModel);
|
|
3088
|
+
const { bin, args, permission } = buildAgentArgs(agent, prompt2, "execute", sessionId, name, resumeSession, systemPrompt, maxTurns, claudeModel);
|
|
3089
|
+
const permLine = `${timestamp()} ${prefix} ${paint("dim", `permission: ${describePermissionMode(permission)}`)}`;
|
|
3090
|
+
if (permission.mappedToBypassForLackOfSandbox) {
|
|
3091
|
+
logWarn(prefix, `permission: ${describePermissionMode(permission)}`);
|
|
3092
|
+
} else {
|
|
3093
|
+
console.log(permLine);
|
|
3094
|
+
}
|
|
2957
3095
|
const child = spawn4(bin, args, { cwd: repoDir, stdio: ["ignore", "pipe", "pipe"] });
|
|
2958
3096
|
child.on("error", (err) => {
|
|
2959
3097
|
logError(prefix, `Failed to spawn ${agent}: ${err.message}`);
|
|
@@ -3489,13 +3627,21 @@ var watchCommand = new Command9("watch").description(
|
|
|
3489
3627
|
}
|
|
3490
3628
|
} catch {
|
|
3491
3629
|
}
|
|
3630
|
+
let protoRefs = [];
|
|
3631
|
+
try {
|
|
3632
|
+
protoRefs = await api.get(`/api/tasks/${task.id}/prototypes`);
|
|
3633
|
+
if (protoRefs.length > 0) {
|
|
3634
|
+
logInfo(prefix, `${paint("cyan", String(protoRefs.length))} linked prototype(s)`);
|
|
3635
|
+
}
|
|
3636
|
+
} catch {
|
|
3637
|
+
}
|
|
3492
3638
|
const isRevision = !!(existingPlanResource && feedbackUpdates.length > 0);
|
|
3493
3639
|
await postTaskUpdate(
|
|
3494
3640
|
task.id,
|
|
3495
3641
|
isRevision ? "Agent dispatched in plan mode \u2014 revising PRD based on feedback" : "Agent dispatched in plan mode \u2014 generating PRD",
|
|
3496
3642
|
"system"
|
|
3497
3643
|
);
|
|
3498
|
-
const prompt2 = buildPrdPrompt(task, repoDir, existingPlanResource?.content, feedbackUpdates);
|
|
3644
|
+
const prompt2 = buildPrdPrompt(task, repoDir, existingPlanResource?.content, feedbackUpdates, protoRefs);
|
|
3499
3645
|
const attemptOrder = await resolveAgentChain(agent);
|
|
3500
3646
|
if (attemptOrder.length === 0) {
|
|
3501
3647
|
logError(prefix, `No available agents found for fallback chain starting at ${agent}`);
|
|
@@ -6096,18 +6242,26 @@ async function resolveReviewAgentChain(preferred2 = "claude") {
|
|
|
6096
6242
|
}
|
|
6097
6243
|
return getAvailableAgentFallbackChain(preferred2, availability);
|
|
6098
6244
|
}
|
|
6099
|
-
function buildArgs(agent, prompt2) {
|
|
6245
|
+
function buildArgs(agent, prompt2, runKind) {
|
|
6246
|
+
const mode = resolveHeadlessMode(loadConfig());
|
|
6247
|
+
const permission = resolvePermissionArgs(agent, runKind, mode);
|
|
6100
6248
|
if (agent === "codex") {
|
|
6101
|
-
return ["-a", "never", "exec",
|
|
6249
|
+
return ["-a", "never", "exec", ...permission.args, prompt2];
|
|
6102
6250
|
}
|
|
6103
6251
|
if (agent === "antigravity") {
|
|
6104
|
-
return ["-p", prompt2,
|
|
6252
|
+
return ["-p", prompt2, ...permission.args];
|
|
6105
6253
|
}
|
|
6106
|
-
return ["-p",
|
|
6254
|
+
return ["-p", ...permission.args, prompt2];
|
|
6255
|
+
}
|
|
6256
|
+
function logPermission(agent, runKind) {
|
|
6257
|
+
const permission = resolvePermissionArgs(agent, runKind, resolveHeadlessMode(loadConfig()));
|
|
6258
|
+
const label = permission.mappedToBypassForLackOfSandbox ? "warning" : "info";
|
|
6259
|
+
console.error(`[review:${label}] ${agent} ${runKind} permission: ${describePermissionMode(permission)}`);
|
|
6107
6260
|
}
|
|
6108
6261
|
function runOnce(agent, prompt2, opts) {
|
|
6109
6262
|
return new Promise((resolve9) => {
|
|
6110
|
-
|
|
6263
|
+
logPermission(agent, opts.runKind);
|
|
6264
|
+
const child = spawn7(AGENT_BINARIES2[agent], buildArgs(agent, prompt2, opts.runKind), {
|
|
6111
6265
|
cwd: opts.cwd,
|
|
6112
6266
|
stdio: opts.capture ? ["ignore", "pipe", "pipe"] : ["ignore", "inherit", "inherit"]
|
|
6113
6267
|
});
|
|
@@ -6133,7 +6287,7 @@ async function runAgentCaptured(prompt2, opts) {
|
|
|
6133
6287
|
}
|
|
6134
6288
|
let lastError = "";
|
|
6135
6289
|
for (const agent of opts.chain) {
|
|
6136
|
-
const result = await runOnce(agent, prompt2, { cwd: opts.cwd, capture: true });
|
|
6290
|
+
const result = await runOnce(agent, prompt2, { cwd: opts.cwd, capture: true, runKind: "review" });
|
|
6137
6291
|
if (result.ok && result.output) {
|
|
6138
6292
|
return { output: result.output, agent };
|
|
6139
6293
|
}
|
|
@@ -6147,7 +6301,7 @@ async function runAgentInteractive(prompt2, opts) {
|
|
|
6147
6301
|
}
|
|
6148
6302
|
let lastError = "";
|
|
6149
6303
|
for (const agent of opts.chain) {
|
|
6150
|
-
const result = await runOnce(agent, prompt2, { cwd: opts.cwd, capture: false });
|
|
6304
|
+
const result = await runOnce(agent, prompt2, { cwd: opts.cwd, capture: false, runKind: "execute" });
|
|
6151
6305
|
if (result.ok) return { agent };
|
|
6152
6306
|
lastError = result.spawnError ? `${agent} could not be spawned` : `${agent} exited non-zero`;
|
|
6153
6307
|
}
|
|
@@ -7846,7 +8000,9 @@ async function fetchScanContext(opts) {
|
|
|
7846
8000
|
}
|
|
7847
8001
|
function runClaude(prompt2) {
|
|
7848
8002
|
return new Promise((resolve9, reject) => {
|
|
7849
|
-
const
|
|
8003
|
+
const permission = resolvePermissionArgs("claude", "scan", resolveHeadlessMode(loadConfig()));
|
|
8004
|
+
console.error(`[scanner] permission: ${describePermissionMode(permission)}`);
|
|
8005
|
+
const child = spawn8("claude", ["-p", ...permission.args, prompt2], {
|
|
7850
8006
|
stdio: ["ignore", "pipe", "pipe"]
|
|
7851
8007
|
});
|
|
7852
8008
|
let output = "";
|