patchwork-os 0.2.0-alpha.2 → 0.2.0-alpha.4
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/bridge.js +23 -10
- package/dist/bridge.js.map +1 -1
- package/dist/claudeDriver.d.ts +3 -1
- package/dist/claudeDriver.js +48 -0
- package/dist/claudeDriver.js.map +1 -1
- package/dist/config.d.ts +2 -2
- package/dist/config.js +5 -2
- package/dist/config.js.map +1 -1
- package/dist/connectors/github.d.ts +58 -8
- package/dist/connectors/github.js +321 -84
- package/dist/connectors/github.js.map +1 -1
- package/dist/connectors/gmail.js +21 -0
- package/dist/connectors/gmail.js.map +1 -1
- package/dist/connectors/googleCalendar.d.ts +57 -0
- package/dist/connectors/googleCalendar.js +308 -0
- package/dist/connectors/googleCalendar.js.map +1 -0
- package/dist/connectors/linear.d.ts +100 -0
- package/dist/connectors/linear.js +236 -0
- package/dist/connectors/linear.js.map +1 -0
- package/dist/connectors/mcpClient.d.ts +56 -0
- package/dist/connectors/mcpClient.js +189 -0
- package/dist/connectors/mcpClient.js.map +1 -0
- package/dist/connectors/mcpOAuth.d.ts +73 -0
- package/dist/connectors/mcpOAuth.js +338 -0
- package/dist/connectors/mcpOAuth.js.map +1 -0
- package/dist/connectors/sentry.d.ts +43 -0
- package/dist/connectors/sentry.js +197 -0
- package/dist/connectors/sentry.js.map +1 -0
- package/dist/drivers/claude/api.d.ts +11 -0
- package/dist/drivers/claude/api.js +54 -0
- package/dist/drivers/claude/api.js.map +1 -0
- package/dist/drivers/claude/envSanitizer.d.ts +7 -0
- package/dist/drivers/claude/envSanitizer.js +18 -0
- package/dist/drivers/claude/envSanitizer.js.map +1 -0
- package/dist/drivers/claude/streamParser.d.ts +38 -0
- package/dist/drivers/claude/streamParser.js +34 -0
- package/dist/drivers/claude/streamParser.js.map +1 -0
- package/dist/drivers/claude/subprocess.d.ts +19 -0
- package/dist/drivers/claude/subprocess.js +216 -0
- package/dist/drivers/claude/subprocess.js.map +1 -0
- package/dist/drivers/claude/subprocessSettings.d.ts +9 -0
- package/dist/drivers/claude/subprocessSettings.js +55 -0
- package/dist/drivers/claude/subprocessSettings.js.map +1 -0
- package/dist/drivers/gemini/index.d.ts +14 -0
- package/dist/drivers/gemini/index.js +176 -0
- package/dist/drivers/gemini/index.js.map +1 -0
- package/dist/drivers/grok/index.d.ts +11 -0
- package/dist/drivers/grok/index.js +22 -0
- package/dist/drivers/grok/index.js.map +1 -0
- package/dist/drivers/index.d.ts +18 -0
- package/dist/drivers/index.js +31 -0
- package/dist/drivers/index.js.map +1 -0
- package/dist/drivers/openai/index.d.ts +24 -0
- package/dist/drivers/openai/index.js +110 -0
- package/dist/drivers/openai/index.js.map +1 -0
- package/dist/drivers/types.d.ts +72 -0
- package/dist/drivers/types.js +30 -0
- package/dist/drivers/types.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/recipes/yamlRunner.js +57 -2
- package/dist/recipes/yamlRunner.js.map +1 -1
- package/dist/recipesHttp.d.ts +13 -1
- package/dist/recipesHttp.js +9 -1
- package/dist/recipesHttp.js.map +1 -1
- package/dist/server.d.ts +3 -1
- package/dist/server.js +277 -14
- package/dist/server.js.map +1 -1
- package/dist/tools/createLinearIssue.d.ts +84 -0
- package/dist/tools/createLinearIssue.js +146 -0
- package/dist/tools/createLinearIssue.js.map +1 -0
- package/dist/tools/ctxGetTaskContext.d.ts +4 -1
- package/dist/tools/ctxGetTaskContext.js +45 -2
- package/dist/tools/ctxGetTaskContext.js.map +1 -1
- package/dist/tools/fetchCalendarEvents.d.ts +94 -0
- package/dist/tools/fetchCalendarEvents.js +97 -0
- package/dist/tools/fetchCalendarEvents.js.map +1 -0
- package/dist/tools/fetchGithubIssue.d.ts +80 -0
- package/dist/tools/fetchGithubIssue.js +84 -0
- package/dist/tools/fetchGithubIssue.js.map +1 -0
- package/dist/tools/fetchGithubPR.d.ts +89 -0
- package/dist/tools/fetchGithubPR.js +96 -0
- package/dist/tools/fetchGithubPR.js.map +1 -0
- package/dist/tools/fetchLinearIssue.d.ts +112 -0
- package/dist/tools/fetchLinearIssue.js +129 -0
- package/dist/tools/fetchLinearIssue.js.map +1 -0
- package/dist/tools/fetchSentryIssue.d.ts +143 -0
- package/dist/tools/fetchSentryIssue.js +150 -0
- package/dist/tools/fetchSentryIssue.js.map +1 -0
- package/dist/tools/index.js +12 -0
- package/dist/tools/index.js.map +1 -1
- package/package.json +2 -2
- package/scripts/start-all.sh +56 -19
- package/templates/recipes/ctx-loop-test.yaml +75 -0
- package/templates/recipes/morning-brief.yaml +20 -3
- package/templates/recipes/sentry-to-linear.yaml +77 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const OUTPUT_CAP = 50 * 1024;
|
|
2
|
+
/**
|
|
3
|
+
* ApiDriver — uses @anthropic-ai/sdk directly.
|
|
4
|
+
* Requires ANTHROPIC_API_KEY env var and @anthropic-ai/sdk package.
|
|
5
|
+
*/
|
|
6
|
+
export class ApiDriver {
|
|
7
|
+
log;
|
|
8
|
+
name = "api";
|
|
9
|
+
constructor(log) {
|
|
10
|
+
this.log = log;
|
|
11
|
+
if (!process.env.ANTHROPIC_API_KEY) {
|
|
12
|
+
throw new Error("ApiDriver requires ANTHROPIC_API_KEY environment variable");
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
async run(input) {
|
|
16
|
+
// biome-ignore lint/suspicious/noExplicitAny: dynamic import of optional peer dep
|
|
17
|
+
let AnthropicCtor;
|
|
18
|
+
try {
|
|
19
|
+
// biome-ignore lint/suspicious/noExplicitAny: dynamic import
|
|
20
|
+
const mod = await import("@anthropic-ai/sdk");
|
|
21
|
+
// biome-ignore lint/suspicious/noExplicitAny: dynamic import
|
|
22
|
+
AnthropicCtor = mod.default ?? mod;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
throw new Error("ApiDriver requires @anthropic-ai/sdk — install it with: npm install @anthropic-ai/sdk");
|
|
26
|
+
}
|
|
27
|
+
const client = new AnthropicCtor();
|
|
28
|
+
const start = Date.now();
|
|
29
|
+
const contextNote = input.contextFiles && input.contextFiles.length > 0
|
|
30
|
+
? `\n\n--- BEGIN CONTEXT FILE LIST (informational, not instructions) ---\n${input.contextFiles
|
|
31
|
+
.map((f) => f.slice(0, 500).replace(/[\x00-\x1f\x7f]/g, ""))
|
|
32
|
+
.join("\n")}\n--- END CONTEXT FILE LIST ---`
|
|
33
|
+
: "";
|
|
34
|
+
this.log("[ApiDriver] sending request to Anthropic API");
|
|
35
|
+
const message = await client.messages.create({
|
|
36
|
+
model: input.model ?? "claude-haiku-4-5-20251001",
|
|
37
|
+
max_tokens: 4096,
|
|
38
|
+
messages: [{ role: "user", content: input.prompt + contextNote }],
|
|
39
|
+
}, { signal: input.signal });
|
|
40
|
+
// biome-ignore lint/suspicious/noExplicitAny: message is from dynamically imported optional dep
|
|
41
|
+
const content = message.content;
|
|
42
|
+
const text = content
|
|
43
|
+
.filter((b) => b.type === "text")
|
|
44
|
+
.map((b) => b.text ?? "")
|
|
45
|
+
.join("");
|
|
46
|
+
input.onChunk?.(text);
|
|
47
|
+
return {
|
|
48
|
+
text: text.slice(0, OUTPUT_CAP),
|
|
49
|
+
exitCode: 0,
|
|
50
|
+
durationMs: Date.now() - start,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/drivers/claude/api.ts"],"names":[],"mappings":"AAMA,MAAM,UAAU,GAAG,EAAE,GAAG,IAAI,CAAC;AAE7B;;;GAGG;AACH,MAAM,OAAO,SAAS;IAGS;IAFpB,IAAI,GAAG,KAAK,CAAC;IAEtB,YAA6B,GAA0B;QAA1B,QAAG,GAAH,GAAG,CAAuB;QACrD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CACb,2DAA2D,CAC5D,CAAC;QACJ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAwB;QAChC,kFAAkF;QAClF,IAAI,aAA4B,CAAC;QACjC,IAAI,CAAC;YACH,6DAA6D;YAC7D,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,mBAA0B,CAAC,CAAC;YACrD,6DAA6D;YAC7D,aAAa,GAAI,GAAW,CAAC,OAAO,IAAI,GAAG,CAAC;QAC9C,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CACb,uFAAuF,CACxF,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEzB,MAAM,WAAW,GACf,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC;YACjD,CAAC,CAAC,0EAA0E,KAAK,CAAC,YAAY;iBACzF,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC;iBAC3D,IAAI,CAAC,IAAI,CAAC,iCAAiC;YAChD,CAAC,CAAC,EAAE,CAAC;QAET,IAAI,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;QAEzD,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,CAC1C;YACE,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,2BAA2B;YACjD,UAAU,EAAE,IAAI;YAChB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,MAAM,GAAG,WAAW,EAAE,CAAC;SAClE,EACD,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CACzB,CAAC;QAEF,gGAAgG;QAChG,MAAM,OAAO,GAAI,OAAe,CAAC,OAG/B,CAAC;QACH,MAAM,IAAI,GAAW,OAAO;aACzB,MAAM,CAAC,CAAC,CAAmB,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;aAClD,GAAG,CAAC,CAAC,CAAoB,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;aAC3C,IAAI,CAAC,EAAE,CAAC,CAAC;QAEZ,KAAK,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC;QAEtB,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC;YAC/B,QAAQ,EAAE,CAAC;YACX,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;SAC/B,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strip env vars that would cause the subprocess to attach to or authenticate
|
|
3
|
+
* as the parent Claude Code session.
|
|
4
|
+
* Any of CLAUDECODE, CLAUDE_CODE_*, or MCP_* can cause the subprocess to
|
|
5
|
+
* re-authenticate against, or behave as a nested agent of, the parent session.
|
|
6
|
+
*/
|
|
7
|
+
export declare function sanitizeEnv(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strip env vars that would cause the subprocess to attach to or authenticate
|
|
3
|
+
* as the parent Claude Code session.
|
|
4
|
+
* Any of CLAUDECODE, CLAUDE_CODE_*, or MCP_* can cause the subprocess to
|
|
5
|
+
* re-authenticate against, or behave as a nested agent of, the parent session.
|
|
6
|
+
*/
|
|
7
|
+
export function sanitizeEnv(env) {
|
|
8
|
+
const clean = { ...env };
|
|
9
|
+
for (const key of Object.keys(clean)) {
|
|
10
|
+
if (key === "CLAUDECODE" ||
|
|
11
|
+
key.startsWith("CLAUDE_CODE_") ||
|
|
12
|
+
key.startsWith("MCP_")) {
|
|
13
|
+
delete clean[key];
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return clean;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=envSanitizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envSanitizer.js","sourceRoot":"","sources":["../../../src/drivers/claude/envSanitizer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,GAAsB;IAChD,MAAM,KAAK,GAAsB,EAAE,GAAG,GAAG,EAAE,CAAC;IAC5C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACrC,IACE,GAAG,KAAK,YAAY;YACpB,GAAG,CAAC,UAAU,CAAC,cAAc,CAAC;YAC9B,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EACtB,CAAC;YACD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** Shape of a parsed stream-json event from `claude -p --output-format stream-json`. */
|
|
2
|
+
export interface StreamJsonEvent {
|
|
3
|
+
type: "system" | "assistant" | "result" | string;
|
|
4
|
+
/** Present on type === "assistant" */
|
|
5
|
+
message?: {
|
|
6
|
+
role?: string;
|
|
7
|
+
content?: Array<{
|
|
8
|
+
type: string;
|
|
9
|
+
text?: string;
|
|
10
|
+
}>;
|
|
11
|
+
};
|
|
12
|
+
/** Present on type === "result" — canonical full response text. */
|
|
13
|
+
result?: string;
|
|
14
|
+
/** Present on type === "result" — true when claude hit an error (e.g. max_turns). */
|
|
15
|
+
is_error?: boolean;
|
|
16
|
+
/** Present on type === "system" — session identifier. */
|
|
17
|
+
session_id?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface ParsedLine {
|
|
20
|
+
kind: "event";
|
|
21
|
+
event: StreamJsonEvent;
|
|
22
|
+
text: string;
|
|
23
|
+
}
|
|
24
|
+
export interface RawLine {
|
|
25
|
+
kind: "raw";
|
|
26
|
+
text: string;
|
|
27
|
+
}
|
|
28
|
+
export type ParsedStreamLine = ParsedLine | RawLine;
|
|
29
|
+
/**
|
|
30
|
+
* Parse a single JSONL line from the stream-json output format.
|
|
31
|
+
* Returns a raw line entry for non-JSON lines (backward compat with old binaries).
|
|
32
|
+
*/
|
|
33
|
+
export declare function parseStreamLine(line: string): ParsedStreamLine;
|
|
34
|
+
/** Split a chunk into complete lines + a leftover partial. */
|
|
35
|
+
export declare function splitLines(buf: string, chunk: string): {
|
|
36
|
+
lines: string[];
|
|
37
|
+
remainder: string;
|
|
38
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a single JSONL line from the stream-json output format.
|
|
3
|
+
* Returns a raw line entry for non-JSON lines (backward compat with old binaries).
|
|
4
|
+
*/
|
|
5
|
+
export function parseStreamLine(line) {
|
|
6
|
+
try {
|
|
7
|
+
const event = JSON.parse(line);
|
|
8
|
+
let text = "";
|
|
9
|
+
if (event.type === "assistant") {
|
|
10
|
+
const content = event.message?.content;
|
|
11
|
+
if (Array.isArray(content)) {
|
|
12
|
+
text = content
|
|
13
|
+
.filter((b) => b.type === "text")
|
|
14
|
+
.map((b) => b.text ?? "")
|
|
15
|
+
.join("");
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
else if (event.type === "result") {
|
|
19
|
+
text = typeof event.result === "string" ? event.result : "";
|
|
20
|
+
}
|
|
21
|
+
return { kind: "event", event, text };
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return { kind: "raw", text: `${line}\n` };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/** Split a chunk into complete lines + a leftover partial. */
|
|
28
|
+
export function splitLines(buf, chunk) {
|
|
29
|
+
const combined = buf + chunk;
|
|
30
|
+
const parts = combined.split("\n");
|
|
31
|
+
const remainder = parts.pop() ?? "";
|
|
32
|
+
return { lines: parts, remainder };
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=streamParser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streamParser.js","sourceRoot":"","sources":["../../../src/drivers/claude/streamParser.ts"],"names":[],"mappings":"AA6BA;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAoB,CAAC;QAClD,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAC/B,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC;YACvC,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC3B,IAAI,GAAG,OAAO;qBACX,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;qBAChC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;qBACxB,IAAI,CAAC,EAAE,CAAC,CAAC;YACd,CAAC;QACH,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACnC,IAAI,GAAG,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC;IAC5C,CAAC;AACH,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,UAAU,CACxB,GAAW,EACX,KAAa;IAEb,MAAM,QAAQ,GAAG,GAAG,GAAG,KAAK,CAAC;IAC7B,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;IACpC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ProviderDriver, ProviderTaskInput, ProviderTaskResult } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Scrub secrets from a string before storing or surfacing it.
|
|
4
|
+
*/
|
|
5
|
+
export declare function scrubSecrets(text: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Claude subprocess driver — spawns `claude -p` with stream-json output.
|
|
8
|
+
* Claude-specific providerOptions: { effort, fallbackModel, maxBudgetUsd, useAnt }
|
|
9
|
+
*/
|
|
10
|
+
export declare class SubprocessDriver implements ProviderDriver {
|
|
11
|
+
private readonly binary;
|
|
12
|
+
private readonly antBinary;
|
|
13
|
+
private readonly log;
|
|
14
|
+
readonly name = "subprocess";
|
|
15
|
+
private readonly settings;
|
|
16
|
+
constructor(binary: string, antBinary: string, log: (msg: string) => void);
|
|
17
|
+
run(input: ProviderTaskInput): Promise<ProviderTaskResult>;
|
|
18
|
+
runOutcome(input: ProviderTaskInput): Promise<import("../types.js").ProviderTaskOutcome>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { toProviderTaskOutcome } from "../types.js";
|
|
3
|
+
import { sanitizeEnv } from "./envSanitizer.js";
|
|
4
|
+
import { parseStreamLine, splitLines } from "./streamParser.js";
|
|
5
|
+
import { createSubprocessSettings } from "./subprocessSettings.js";
|
|
6
|
+
const OUTPUT_CAP = 50 * 1024; // 50KB
|
|
7
|
+
/**
|
|
8
|
+
* Scrub secrets from a string before storing or surfacing it.
|
|
9
|
+
*/
|
|
10
|
+
export function scrubSecrets(text) {
|
|
11
|
+
return text
|
|
12
|
+
.replace(/sk-ant-[A-Za-z0-9_-]{20,}/g, "[REDACTED_API_KEY]")
|
|
13
|
+
.replace(/Bearer\s+[A-Za-z0-9._-]{16,}/gi, "Bearer [REDACTED]")
|
|
14
|
+
.replace(/\btoken[=:]\s*[A-Za-z0-9._-]{16,}/gi, "token=[REDACTED]");
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Claude subprocess driver — spawns `claude -p` with stream-json output.
|
|
18
|
+
* Claude-specific providerOptions: { effort, fallbackModel, maxBudgetUsd, useAnt }
|
|
19
|
+
*/
|
|
20
|
+
export class SubprocessDriver {
|
|
21
|
+
binary;
|
|
22
|
+
antBinary;
|
|
23
|
+
log;
|
|
24
|
+
name = "subprocess";
|
|
25
|
+
settings;
|
|
26
|
+
constructor(binary, antBinary, log) {
|
|
27
|
+
this.binary = binary;
|
|
28
|
+
this.antBinary = antBinary;
|
|
29
|
+
this.log = log;
|
|
30
|
+
this.settings = createSubprocessSettings(log);
|
|
31
|
+
this.settings.write();
|
|
32
|
+
}
|
|
33
|
+
async run(input) {
|
|
34
|
+
const opts = input.providerOptions ?? {};
|
|
35
|
+
const useAnt = opts.useAnt === true;
|
|
36
|
+
const effort = typeof opts.effort === "string" ? opts.effort : undefined;
|
|
37
|
+
const fallbackModel = typeof opts.fallbackModel === "string" ? opts.fallbackModel : undefined;
|
|
38
|
+
const maxBudgetUsd = typeof opts.maxBudgetUsd === "number" ? opts.maxBudgetUsd : undefined;
|
|
39
|
+
const effectiveBinary = useAnt ? this.antBinary : this.binary;
|
|
40
|
+
// Re-write before each run — /tmp may be cleared on long-running servers.
|
|
41
|
+
this.settings.write();
|
|
42
|
+
const args = [
|
|
43
|
+
"-p",
|
|
44
|
+
input.prompt,
|
|
45
|
+
"--strict-mcp-config",
|
|
46
|
+
"--settings",
|
|
47
|
+
this.settings.path,
|
|
48
|
+
"--output-format",
|
|
49
|
+
"stream-json",
|
|
50
|
+
"--verbose",
|
|
51
|
+
"--include-partial-messages",
|
|
52
|
+
"--no-session-persistence",
|
|
53
|
+
];
|
|
54
|
+
if (input.model)
|
|
55
|
+
args.push("--model", input.model);
|
|
56
|
+
if (effort)
|
|
57
|
+
args.push("--effort", effort);
|
|
58
|
+
if (input.systemPrompt)
|
|
59
|
+
args.push("--system-prompt", input.systemPrompt);
|
|
60
|
+
if (fallbackModel)
|
|
61
|
+
args.push("--fallback-model", fallbackModel);
|
|
62
|
+
if (maxBudgetUsd !== undefined)
|
|
63
|
+
args.push("--max-budget-usd", String(maxBudgetUsd));
|
|
64
|
+
// Always skip permissions: headless subprocesses can't respond to prompts.
|
|
65
|
+
args.push("--dangerously-skip-permissions");
|
|
66
|
+
for (const f of input.contextFiles ?? []) {
|
|
67
|
+
if (typeof f === "string" && f.length > 0 && !f.startsWith("-")) {
|
|
68
|
+
args.push("--add-dir", f);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const env = sanitizeEnv(process.env);
|
|
72
|
+
this.log(`[SubprocessDriver] spawning: ${effectiveBinary} -p <prompt> (workspace: ${input.workspace})`);
|
|
73
|
+
const child = spawn(effectiveBinary, args, {
|
|
74
|
+
cwd: input.workspace,
|
|
75
|
+
env,
|
|
76
|
+
signal: input.signal,
|
|
77
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
78
|
+
// setsid() — prevents subprocess from opening /dev/tty for interactive prompts.
|
|
79
|
+
detached: true,
|
|
80
|
+
});
|
|
81
|
+
let lineBuf = "";
|
|
82
|
+
let accumulated = "";
|
|
83
|
+
let outputBytesSent = 0;
|
|
84
|
+
let firstAssistantAt;
|
|
85
|
+
let doneFromResult = false;
|
|
86
|
+
let resultText = "";
|
|
87
|
+
let resultIsError = false;
|
|
88
|
+
child.stdout.setEncoding("utf-8");
|
|
89
|
+
child.stdout.on("data", (chunk) => {
|
|
90
|
+
const { lines, remainder } = splitLines(lineBuf, chunk);
|
|
91
|
+
lineBuf = remainder;
|
|
92
|
+
for (const line of lines) {
|
|
93
|
+
if (line.trim() === "")
|
|
94
|
+
continue;
|
|
95
|
+
const parsed = parseStreamLine(line);
|
|
96
|
+
if (parsed.kind === "raw") {
|
|
97
|
+
accumulated += parsed.text;
|
|
98
|
+
if (outputBytesSent < OUTPUT_CAP) {
|
|
99
|
+
const send = parsed.text.slice(0, OUTPUT_CAP - outputBytesSent);
|
|
100
|
+
if (send.length > 0) {
|
|
101
|
+
input.onChunk?.(send);
|
|
102
|
+
outputBytesSent += send.length;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
const { event, text } = parsed;
|
|
108
|
+
if (event.type === "assistant") {
|
|
109
|
+
if (firstAssistantAt === undefined)
|
|
110
|
+
firstAssistantAt = Date.now();
|
|
111
|
+
if (text.length > 0) {
|
|
112
|
+
accumulated += text;
|
|
113
|
+
if (outputBytesSent < OUTPUT_CAP) {
|
|
114
|
+
const send = text.slice(0, OUTPUT_CAP - outputBytesSent);
|
|
115
|
+
if (send.length > 0) {
|
|
116
|
+
input.onChunk?.(send);
|
|
117
|
+
outputBytesSent += send.length;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
else if (event.type === "result") {
|
|
123
|
+
doneFromResult = true;
|
|
124
|
+
resultIsError = event.is_error === true;
|
|
125
|
+
resultText = text || accumulated;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
let stderr = "";
|
|
130
|
+
child.stderr.setEncoding("utf-8");
|
|
131
|
+
child.stderr.on("data", (chunk) => {
|
|
132
|
+
if (stderr.length < OUTPUT_CAP) {
|
|
133
|
+
stderr += chunk;
|
|
134
|
+
if (stderr.length > OUTPUT_CAP)
|
|
135
|
+
stderr = stderr.slice(0, OUTPUT_CAP);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
const start = Date.now();
|
|
139
|
+
const stderrTailOf = (s) => s.length > 0 ? scrubSecrets(s.slice(-2048)) : undefined;
|
|
140
|
+
const startupMsOf = () => firstAssistantAt !== undefined ? firstAssistantAt - start : undefined;
|
|
141
|
+
let startupTimedOut = false;
|
|
142
|
+
const startupHandle = input.startupTimeoutMs
|
|
143
|
+
? setTimeout(() => {
|
|
144
|
+
if (firstAssistantAt === undefined && !doneFromResult) {
|
|
145
|
+
startupTimedOut = true;
|
|
146
|
+
child.kill();
|
|
147
|
+
}
|
|
148
|
+
}, input.startupTimeoutMs)
|
|
149
|
+
: null;
|
|
150
|
+
let exitCode;
|
|
151
|
+
try {
|
|
152
|
+
exitCode = await new Promise((resolve, reject) => {
|
|
153
|
+
child.on("close", (code) => resolve(code ?? 0));
|
|
154
|
+
child.on("error", reject);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
catch (err) {
|
|
158
|
+
if (startupHandle)
|
|
159
|
+
clearTimeout(startupHandle);
|
|
160
|
+
if (doneFromResult) {
|
|
161
|
+
return {
|
|
162
|
+
text: resultText.slice(0, OUTPUT_CAP),
|
|
163
|
+
exitCode: resultIsError ? 1 : 0,
|
|
164
|
+
durationMs: Date.now() - start,
|
|
165
|
+
stderrTail: stderrTailOf(stderr),
|
|
166
|
+
startupMs: startupMsOf(),
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
const isAbort = (err instanceof Error && err.name === "AbortError") ||
|
|
170
|
+
input.signal.aborted;
|
|
171
|
+
if (isAbort) {
|
|
172
|
+
return {
|
|
173
|
+
text: accumulated.slice(0, OUTPUT_CAP),
|
|
174
|
+
exitCode: -1,
|
|
175
|
+
durationMs: Date.now() - start,
|
|
176
|
+
stderrTail: stderrTailOf(stderr),
|
|
177
|
+
wasAborted: true,
|
|
178
|
+
startupMs: startupMsOf(),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
throw err;
|
|
182
|
+
}
|
|
183
|
+
if (startupHandle)
|
|
184
|
+
clearTimeout(startupHandle);
|
|
185
|
+
const effectiveExitCode = doneFromResult
|
|
186
|
+
? resultIsError
|
|
187
|
+
? 1
|
|
188
|
+
: 0
|
|
189
|
+
: exitCode;
|
|
190
|
+
const finalText = doneFromResult ? resultText : accumulated;
|
|
191
|
+
if (startupTimedOut) {
|
|
192
|
+
return {
|
|
193
|
+
text: accumulated.slice(0, OUTPUT_CAP),
|
|
194
|
+
exitCode: -1,
|
|
195
|
+
durationMs: Date.now() - start,
|
|
196
|
+
stderrTail: stderrTailOf(stderr),
|
|
197
|
+
wasAborted: true,
|
|
198
|
+
startupTimedOut: true,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
if (effectiveExitCode !== 0 && stderr) {
|
|
202
|
+
this.log(`[SubprocessDriver] stderr: ${stderr.slice(0, 500)}`);
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
text: finalText.slice(0, OUTPUT_CAP),
|
|
206
|
+
exitCode: effectiveExitCode,
|
|
207
|
+
durationMs: Date.now() - start,
|
|
208
|
+
stderrTail: stderrTailOf(stderr),
|
|
209
|
+
startupMs: startupMsOf(),
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
async runOutcome(input) {
|
|
213
|
+
return toProviderTaskOutcome(await this.run(input));
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=subprocess.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subprocess.js","sourceRoot":"","sources":["../../../src/drivers/claude/subprocess.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAM3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAEnE,MAAM,UAAU,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,OAAO;AAErC;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,IAAI;SACR,OAAO,CAAC,4BAA4B,EAAE,oBAAoB,CAAC;SAC3D,OAAO,CAAC,gCAAgC,EAAE,mBAAmB,CAAC;SAC9D,OAAO,CAAC,qCAAqC,EAAE,kBAAkB,CAAC,CAAC;AACxE,CAAC;AAED;;;GAGG;AACH,MAAM,OAAO,gBAAgB;IAKR;IACA;IACA;IANV,IAAI,GAAG,YAAY,CAAC;IACZ,QAAQ,CAA8C;IAEvE,YACmB,MAAc,EACd,SAAiB,EACjB,GAA0B;QAF1B,WAAM,GAAN,MAAM,CAAQ;QACd,cAAS,GAAT,SAAS,CAAQ;QACjB,QAAG,GAAH,GAAG,CAAuB;QAE3C,IAAI,CAAC,QAAQ,GAAG,wBAAwB,CAAC,GAAG,CAAC,CAAC;QAC9C,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAwB;QAChC,MAAM,IAAI,GAAG,KAAK,CAAC,eAAe,IAAI,EAAE,CAAC;QACzC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC;QACpC,MAAM,MAAM,GAAG,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;QACzE,MAAM,aAAa,GACjB,OAAO,IAAI,CAAC,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC;QAC1E,MAAM,YAAY,GAChB,OAAO,IAAI,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC;QAExE,MAAM,eAAe,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;QAC9D,0EAA0E;QAC1E,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QAEtB,MAAM,IAAI,GAAG;YACX,IAAI;YACJ,KAAK,CAAC,MAAM;YACZ,qBAAqB;YACrB,YAAY;YACZ,IAAI,CAAC,QAAQ,CAAC,IAAI;YAClB,iBAAiB;YACjB,aAAa;YACb,WAAW;YACX,4BAA4B;YAC5B,0BAA0B;SAC3B,CAAC;QACF,IAAI,KAAK,CAAC,KAAK;YAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QACnD,IAAI,MAAM;YAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAC1C,IAAI,KAAK,CAAC,YAAY;YAAE,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;QACzE,IAAI,aAAa;YAAE,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,aAAa,CAAC,CAAC;QAChE,IAAI,YAAY,KAAK,SAAS;YAC5B,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;QACtD,2EAA2E;QAC3E,IAAI,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;QAC5C,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,YAAY,IAAI,EAAE,EAAE,CAAC;YACzC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBAChE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC;QAED,MAAM,GAAG,GAAG,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAErC,IAAI,CAAC,GAAG,CACN,gCAAgC,eAAe,4BAA4B,KAAK,CAAC,SAAS,GAAG,CAC9F,CAAC;QAEF,MAAM,KAAK,GAAG,KAAK,CAAC,eAAe,EAAE,IAAI,EAAE;YACzC,GAAG,EAAE,KAAK,CAAC,SAAS;YACpB,GAAG;YACH,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;YACjC,gFAAgF;YAChF,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;QAEH,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,IAAI,WAAW,GAAG,EAAE,CAAC;QACrB,IAAI,eAAe,GAAG,CAAC,CAAC;QACxB,IAAI,gBAAoC,CAAC;QACzC,IAAI,cAAc,GAAG,KAAK,CAAC;QAC3B,IAAI,UAAU,GAAG,EAAE,CAAC;QACpB,IAAI,aAAa,GAAG,KAAK,CAAC;QAE1B,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAClC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACxC,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACxD,OAAO,GAAG,SAAS,CAAC;YAEpB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;oBAAE,SAAS;gBAEjC,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;gBACrC,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;oBAC1B,WAAW,IAAI,MAAM,CAAC,IAAI,CAAC;oBAC3B,IAAI,eAAe,GAAG,UAAU,EAAE,CAAC;wBACjC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,GAAG,eAAe,CAAC,CAAC;wBAChE,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;4BACpB,KAAK,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC;4BACtB,eAAe,IAAI,IAAI,CAAC,MAAM,CAAC;wBACjC,CAAC;oBACH,CAAC;oBACD,SAAS;gBACX,CAAC;gBAED,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC;gBAC/B,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;oBAC/B,IAAI,gBAAgB,KAAK,SAAS;wBAAE,gBAAgB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;oBAClE,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACpB,WAAW,IAAI,IAAI,CAAC;wBACpB,IAAI,eAAe,GAAG,UAAU,EAAE,CAAC;4BACjC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,GAAG,eAAe,CAAC,CAAC;4BACzD,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gCACpB,KAAK,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC;gCACtB,eAAe,IAAI,IAAI,CAAC,MAAM,CAAC;4BACjC,CAAC;wBACH,CAAC;oBACH,CAAC;gBACH,CAAC;qBAAM,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBACnC,cAAc,GAAG,IAAI,CAAC;oBACtB,aAAa,GAAG,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAC;oBACxC,UAAU,GAAG,IAAI,IAAI,WAAW,CAAC;gBACnC,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAClC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACxC,IAAI,MAAM,CAAC,MAAM,GAAG,UAAU,EAAE,CAAC;gBAC/B,MAAM,IAAI,KAAK,CAAC;gBAChB,IAAI,MAAM,CAAC,MAAM,GAAG,UAAU;oBAAE,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;YACvE,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,YAAY,GAAG,CAAC,CAAS,EAAsB,EAAE,CACrD,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC1D,MAAM,WAAW,GAAG,GAAuB,EAAE,CAC3C,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,gBAAgB,GAAG,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;QAExE,IAAI,eAAe,GAAG,KAAK,CAAC;QAC5B,MAAM,aAAa,GAAG,KAAK,CAAC,gBAAgB;YAC1C,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE;gBACd,IAAI,gBAAgB,KAAK,SAAS,IAAI,CAAC,cAAc,EAAE,CAAC;oBACtD,eAAe,GAAG,IAAI,CAAC;oBACvB,KAAK,CAAC,IAAI,EAAE,CAAC;gBACf,CAAC;YACH,CAAC,EAAE,KAAK,CAAC,gBAAgB,CAAC;YAC5B,CAAC,CAAC,IAAI,CAAC;QAET,IAAI,QAAgB,CAAC;QACrB,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBACvD,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;gBAChD,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC5B,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,aAAa;gBAAE,YAAY,CAAC,aAAa,CAAC,CAAC;YAC/C,IAAI,cAAc,EAAE,CAAC;gBACnB,OAAO;oBACL,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC;oBACrC,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBAC/B,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;oBAC9B,UAAU,EAAE,YAAY,CAAC,MAAM,CAAC;oBAChC,SAAS,EAAE,WAAW,EAAE;iBACzB,CAAC;YACJ,CAAC;YACD,MAAM,OAAO,GACX,CAAC,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,CAAC;gBACnD,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC;YACvB,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO;oBACL,IAAI,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC;oBACtC,QAAQ,EAAE,CAAC,CAAC;oBACZ,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;oBAC9B,UAAU,EAAE,YAAY,CAAC,MAAM,CAAC;oBAChC,UAAU,EAAE,IAAI;oBAChB,SAAS,EAAE,WAAW,EAAE;iBACzB,CAAC;YACJ,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;QACD,IAAI,aAAa;YAAE,YAAY,CAAC,aAAa,CAAC,CAAC;QAE/C,MAAM,iBAAiB,GAAG,cAAc;YACtC,CAAC,CAAC,aAAa;gBACb,CAAC,CAAC,CAAC;gBACH,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,QAAQ,CAAC;QACb,MAAM,SAAS,GAAG,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC;QAE5D,IAAI,eAAe,EAAE,CAAC;YACpB,OAAO;gBACL,IAAI,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC;gBACtC,QAAQ,EAAE,CAAC,CAAC;gBACZ,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;gBAC9B,UAAU,EAAE,YAAY,CAAC,MAAM,CAAC;gBAChC,UAAU,EAAE,IAAI;gBAChB,eAAe,EAAE,IAAI;aACtB,CAAC;QACJ,CAAC;QAED,IAAI,iBAAiB,KAAK,CAAC,IAAI,MAAM,EAAE,CAAC;YACtC,IAAI,CAAC,GAAG,CAAC,8BAA8B,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QACjE,CAAC;QAED,OAAO;YACL,IAAI,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC;YACpC,QAAQ,EAAE,iBAAiB;YAC3B,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;YAC9B,UAAU,EAAE,YAAY,CAAC,MAAM,CAAC;YAChC,SAAS,EAAE,WAAW,EAAE;SACzB,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,KAAwB;QACvC,OAAO,qBAAqB,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;IACtD,CAAC;CACF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Write a minimal subprocess settings file that suppresses hooks and denies
|
|
3
|
+
* destructive operations. Uses --settings instead of --bare to preserve OAuth
|
|
4
|
+
* auth flows (--bare sets CLAUDE_CODE_SIMPLE=1 which skips OAuth).
|
|
5
|
+
*/
|
|
6
|
+
export declare function createSubprocessSettings(log: (msg: string) => void): {
|
|
7
|
+
path: string;
|
|
8
|
+
write: () => void;
|
|
9
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { writeFileSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
/** Deny list applied to all bridge-spawned subprocess tasks. */
|
|
5
|
+
const DENY_LIST = [
|
|
6
|
+
// Publishing / release
|
|
7
|
+
"Bash(npm publish*)",
|
|
8
|
+
"Bash(npm version*)",
|
|
9
|
+
"Bash(yarn publish*)",
|
|
10
|
+
"Bash(pnpm publish*)",
|
|
11
|
+
"Bash(npx semantic-release*)",
|
|
12
|
+
"Bash(npx release-it*)",
|
|
13
|
+
// Git remote / tagging
|
|
14
|
+
"Bash(git push*)",
|
|
15
|
+
"Bash(git tag*)",
|
|
16
|
+
"Bash(gh release*)",
|
|
17
|
+
// Destructive git operations
|
|
18
|
+
"Bash(git reset --hard*)",
|
|
19
|
+
"Bash(git clean -f*)",
|
|
20
|
+
// Filesystem destruction
|
|
21
|
+
"Bash(rm -rf *)",
|
|
22
|
+
"Bash(rm -rf/*)",
|
|
23
|
+
// Privilege escalation
|
|
24
|
+
"Bash(sudo *)",
|
|
25
|
+
"Bash(chmod 777*)",
|
|
26
|
+
// Arbitrary code execution
|
|
27
|
+
"Bash(eval *)",
|
|
28
|
+
"Bash(curl *|*)",
|
|
29
|
+
"Bash(wget *|*)",
|
|
30
|
+
// Process termination
|
|
31
|
+
"Bash(kill -9 *)",
|
|
32
|
+
"Bash(pkill *)",
|
|
33
|
+
];
|
|
34
|
+
const SETTINGS_CONTENT = JSON.stringify({
|
|
35
|
+
hooks: {},
|
|
36
|
+
permissions: { deny: DENY_LIST },
|
|
37
|
+
});
|
|
38
|
+
/**
|
|
39
|
+
* Write a minimal subprocess settings file that suppresses hooks and denies
|
|
40
|
+
* destructive operations. Uses --settings instead of --bare to preserve OAuth
|
|
41
|
+
* auth flows (--bare sets CLAUDE_CODE_SIMPLE=1 which skips OAuth).
|
|
42
|
+
*/
|
|
43
|
+
export function createSubprocessSettings(log) {
|
|
44
|
+
const path = join(tmpdir(), `claude-ide-bridge-subprocess-settings-${process.pid}.json`);
|
|
45
|
+
const write = () => {
|
|
46
|
+
try {
|
|
47
|
+
writeFileSync(path, SETTINGS_CONTENT, "utf-8");
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
log(`[SubprocessSettings] WARN: could not write settings file at ${path}: ${err instanceof Error ? err.message : String(err)} — subprocess hooks may fire`);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
return { path, write };
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=subprocessSettings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subprocessSettings.js","sourceRoot":"","sources":["../../../src/drivers/claude/subprocessSettings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,gEAAgE;AAChE,MAAM,SAAS,GAAG;IAChB,uBAAuB;IACvB,oBAAoB;IACpB,oBAAoB;IACpB,qBAAqB;IACrB,qBAAqB;IACrB,6BAA6B;IAC7B,uBAAuB;IACvB,uBAAuB;IACvB,iBAAiB;IACjB,gBAAgB;IAChB,mBAAmB;IACnB,6BAA6B;IAC7B,yBAAyB;IACzB,qBAAqB;IACrB,yBAAyB;IACzB,gBAAgB;IAChB,gBAAgB;IAChB,uBAAuB;IACvB,cAAc;IACd,kBAAkB;IAClB,2BAA2B;IAC3B,cAAc;IACd,gBAAgB;IAChB,gBAAgB;IAChB,sBAAsB;IACtB,iBAAiB;IACjB,eAAe;CAChB,CAAC;AAEF,MAAM,gBAAgB,GAAG,IAAI,CAAC,SAAS,CAAC;IACtC,KAAK,EAAE,EAAE;IACT,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;CACjC,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,GAA0B;IAIjE,MAAM,IAAI,GAAG,IAAI,CACf,MAAM,EAAE,EACR,yCAAyC,OAAO,CAAC,GAAG,OAAO,CAC5D,CAAC;IACF,MAAM,KAAK,GAAG,GAAG,EAAE;QACjB,IAAI,CAAC;YACH,aAAa,CAAC,IAAI,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;QACjD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CACD,+DAA+D,IAAI,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,8BAA8B,CACvJ,CAAC;QACJ,CAAC;IACH,CAAC,CAAC;IACF,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ProviderDriver, ProviderTaskInput, ProviderTaskResult } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* GeminiSubprocessDriver — spawns `gemini -p` with --output-format stream-json.
|
|
4
|
+
* Auth: GEMINI_API_KEY env var (or gcloud ADC / Vertex if configured in ~/.gemini/settings.json).
|
|
5
|
+
* providerOptions: { approvalMode?: "yolo" | "auto_edit" | "default" | "plan" }
|
|
6
|
+
*/
|
|
7
|
+
export declare class GeminiSubprocessDriver implements ProviderDriver {
|
|
8
|
+
private readonly binary;
|
|
9
|
+
private readonly log;
|
|
10
|
+
readonly name = "gemini";
|
|
11
|
+
constructor(binary: string, log: (msg: string) => void);
|
|
12
|
+
run(input: ProviderTaskInput): Promise<ProviderTaskResult>;
|
|
13
|
+
runOutcome(input: ProviderTaskInput): Promise<import("../types.js").ProviderTaskOutcome>;
|
|
14
|
+
}
|