agentweaver 0.1.15 → 0.1.17
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 +76 -19
- package/dist/artifact-manifest.js +219 -0
- package/dist/artifacts.js +88 -3
- package/dist/doctor/checks/env-diagnostics.js +25 -0
- package/dist/doctor/checks/executors.js +2 -2
- package/dist/doctor/checks/flow-readiness.js +15 -18
- package/dist/flow-state.js +212 -15
- package/dist/index.js +539 -209
- package/dist/interactive/blessed-session.js +361 -0
- package/dist/interactive/controller.js +1326 -0
- package/dist/interactive/create-interactive-session.js +5 -0
- package/dist/interactive/ink/index.js +597 -0
- package/dist/interactive/progress.js +245 -0
- package/dist/interactive/selectors.js +14 -0
- package/dist/interactive/session.js +1 -0
- package/dist/interactive/state.js +34 -0
- package/dist/interactive/tree.js +155 -0
- package/dist/interactive/types.js +1 -0
- package/dist/interactive/view-model.js +1 -0
- package/dist/interactive-ui.js +159 -194
- package/dist/pipeline/auto-flow.js +9 -6
- package/dist/pipeline/context.js +7 -5
- package/dist/pipeline/declarative-flow-runner.js +212 -6
- package/dist/pipeline/declarative-flows.js +63 -17
- package/dist/pipeline/execution-routing-config.js +15 -0
- package/dist/pipeline/flow-catalog.js +50 -12
- package/dist/pipeline/flow-run-resume.js +29 -0
- package/dist/pipeline/flow-specs/auto-common.json +90 -360
- package/dist/pipeline/flow-specs/auto-golang.json +81 -360
- package/dist/pipeline/flow-specs/auto-simple.json +141 -0
- package/dist/pipeline/flow-specs/bugz/bug-analyze.json +2 -0
- package/dist/pipeline/flow-specs/bugz/bug-fix.json +1 -0
- package/dist/pipeline/flow-specs/design-review/design-review-loop.json +316 -0
- package/dist/pipeline/flow-specs/design-review.json +10 -0
- package/dist/pipeline/flow-specs/gitlab/gitlab-diff-review.json +11 -0
- package/dist/pipeline/flow-specs/gitlab/gitlab-review.json +2 -0
- package/dist/pipeline/flow-specs/gitlab/mr-description.json +1 -0
- package/dist/pipeline/flow-specs/go/run-go-linter-loop.json +2 -0
- package/dist/pipeline/flow-specs/go/run-go-tests-loop.json +2 -0
- package/dist/pipeline/flow-specs/implement.json +13 -6
- package/dist/pipeline/flow-specs/instant-task.json +177 -0
- package/dist/pipeline/flow-specs/normalize-task-source.json +311 -0
- package/dist/pipeline/flow-specs/plan-revise.json +7 -1
- package/dist/pipeline/flow-specs/plan.json +51 -71
- package/dist/pipeline/flow-specs/review/review-fix.json +24 -4
- package/dist/pipeline/flow-specs/review/review-loop.json +351 -45
- package/dist/pipeline/flow-specs/review/review-project-loop.json +590 -0
- package/dist/pipeline/flow-specs/review/review-project.json +12 -0
- package/dist/pipeline/flow-specs/review/review.json +37 -31
- package/dist/pipeline/flow-specs/task-describe.json +2 -0
- package/dist/pipeline/flow-specs/task-source/jira-fetch.json +70 -0
- package/dist/pipeline/flow-specs/task-source/manual-input.json +216 -0
- package/dist/pipeline/launch-profile-config.js +30 -18
- package/dist/pipeline/node-contract.js +1 -0
- package/dist/pipeline/node-registry.js +115 -6
- package/dist/pipeline/node-runner.js +3 -2
- package/dist/pipeline/nodes/build-review-fix-prompt-node.js +5 -1
- package/dist/pipeline/nodes/clear-ready-to-merge-node.js +11 -0
- package/dist/pipeline/nodes/commit-message-form-node.js +8 -0
- package/dist/pipeline/nodes/design-review-verdict-node.js +36 -0
- package/dist/pipeline/nodes/ensure-summary-json-node.js +13 -2
- package/dist/pipeline/nodes/fetch-gitlab-diff-node.js +19 -2
- package/dist/pipeline/nodes/fetch-gitlab-review-node.js +19 -2
- package/dist/pipeline/nodes/flow-run-node.js +242 -8
- package/dist/pipeline/nodes/git-commit-form-node.js +8 -0
- package/dist/pipeline/nodes/gitlab-review-artifacts-node.js +19 -2
- package/dist/pipeline/nodes/jira-fetch-node.js +50 -4
- package/dist/pipeline/nodes/llm-prompt-node.js +38 -36
- package/dist/pipeline/nodes/planning-bundle-node.js +10 -0
- package/dist/pipeline/nodes/review-verdict-node.js +86 -0
- package/dist/pipeline/nodes/select-files-form-node.js +8 -0
- package/dist/pipeline/nodes/structured-summary-node.js +24 -0
- package/dist/pipeline/nodes/user-input-node.js +38 -3
- package/dist/pipeline/nodes/write-selection-file-node.js +20 -4
- package/dist/pipeline/plugin-loader.js +389 -0
- package/dist/pipeline/plugin-types.js +1 -0
- package/dist/pipeline/prompt-registry.js +3 -1
- package/dist/pipeline/prompt-runtime.js +4 -1
- package/dist/pipeline/registry.js +71 -4
- package/dist/pipeline/review-iteration.js +26 -0
- package/dist/pipeline/spec-compiler.js +3 -0
- package/dist/pipeline/spec-loader.js +14 -0
- package/dist/pipeline/spec-types.js +3 -0
- package/dist/pipeline/spec-validator.js +20 -0
- package/dist/pipeline/value-resolver.js +76 -2
- package/dist/plugin-sdk.js +1 -0
- package/dist/prompts.js +36 -14
- package/dist/review-severity.js +45 -0
- package/dist/runtime/artifact-registry.js +405 -0
- package/dist/runtime/design-review-input-contract.js +17 -16
- package/dist/runtime/env-loader.js +3 -0
- package/dist/runtime/execution-routing-store.js +134 -0
- package/dist/runtime/execution-routing.js +233 -0
- package/dist/runtime/interactive-execution-routing.js +471 -0
- package/dist/runtime/plan-revise-input-contract.js +35 -32
- package/dist/runtime/planning-bundle.js +123 -0
- package/dist/runtime/ready-to-merge.js +22 -1
- package/dist/runtime/review-input-contract.js +100 -0
- package/dist/structured-artifact-schema-registry.js +9 -0
- package/dist/structured-artifact-schemas.json +140 -1
- package/dist/structured-artifacts.js +77 -6
- package/dist/user-input.js +70 -3
- package/docs/example/.flows/examples/claude-example.json +50 -0
- package/docs/example/.plugins/claude-example-plugin/index.js +149 -0
- package/docs/example/.plugins/claude-example-plugin/plugin.json +8 -0
- package/docs/examples/.flows/claude-example.json +50 -0
- package/docs/examples/.plugins/claude-example-plugin/index.js +149 -0
- package/docs/examples/.plugins/claude-example-plugin/plugin.json +8 -0
- package/docs/plugin-sdk.md +731 -0
- package/package.json +11 -4
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"kind": "claude-example-flow",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"description": "Project-local reference flow for the Claude example plugin.",
|
|
5
|
+
"phases": [
|
|
6
|
+
{
|
|
7
|
+
"id": "example",
|
|
8
|
+
"steps": [
|
|
9
|
+
{
|
|
10
|
+
"id": "run_claude_prompt",
|
|
11
|
+
"node": "llm-prompt",
|
|
12
|
+
"prompt": {
|
|
13
|
+
"inlineTemplate": "Use the current workspace. Create the JSON file `.agentweaver/.artifacts/examples/claude-example-proof.json` with exactly this shape: `{ \"status\": \"ok\", \"executor\": \"claude\", \"message\": \"<one short sentence proving the Claude example plugin executed through llm-prompt>\", \"model\": \"<the exact model name you used, or an empty string if unavailable>\" }`. Write valid JSON only to that file. After the file is written, reply with exactly `wrote .agentweaver/.artifacts/examples/claude-example-proof.json`."
|
|
14
|
+
},
|
|
15
|
+
"params": {
|
|
16
|
+
"labelText": {
|
|
17
|
+
"const": "Run Claude via llm-prompt"
|
|
18
|
+
},
|
|
19
|
+
"executor": {
|
|
20
|
+
"const": "claude"
|
|
21
|
+
},
|
|
22
|
+
"requiredArtifacts": {
|
|
23
|
+
"list": [
|
|
24
|
+
{
|
|
25
|
+
"const": ".agentweaver/.artifacts/examples/claude-example-proof.json"
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"missingArtifactsMessage": {
|
|
30
|
+
"const": "The Claude example flow requires Claude to write the fixed proof artifact."
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"expect": [
|
|
34
|
+
{
|
|
35
|
+
"kind": "require-artifacts",
|
|
36
|
+
"paths": {
|
|
37
|
+
"list": [
|
|
38
|
+
{
|
|
39
|
+
"const": ".agentweaver/.artifacts/examples/claude-example-proof.json"
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"message": "The Claude example flow must write the fixed proof artifact."
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { AGENTWEAVER_PLUGIN_SDK_VERSION } from "agentweaver/plugin-sdk";
|
|
2
|
+
|
|
3
|
+
export const CLAUDE_EXAMPLE_PLUGIN_SDK_VERSION = AGENTWEAVER_PLUGIN_SDK_VERSION;
|
|
4
|
+
export const CLAUDE_EXECUTOR_ID = "claude";
|
|
5
|
+
export const CLAUDE_AUTH_STATUS_ERROR = "Claude CLI authentication is required. Run 'claude auth status' and sign in before using the example flow.";
|
|
6
|
+
export const CLAUDE_NORMALIZATION_ERROR =
|
|
7
|
+
"Claude JSON normalization failed: no supported assistant text was found in result, message.content[*].text, or content[*].text.";
|
|
8
|
+
|
|
9
|
+
function nonEmptyString(value) {
|
|
10
|
+
return typeof value === "string" && value.trim().length > 0 ? value : null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function resolveSetting(override, env, envKey, defaultValue) {
|
|
14
|
+
const direct = nonEmptyString(typeof override === "number" ? String(override) : override);
|
|
15
|
+
if (direct) {
|
|
16
|
+
return direct;
|
|
17
|
+
}
|
|
18
|
+
const fromEnv = nonEmptyString(env?.[envKey]);
|
|
19
|
+
if (fromEnv) {
|
|
20
|
+
return fromEnv;
|
|
21
|
+
}
|
|
22
|
+
return nonEmptyString(defaultValue);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function resolveStringListSetting(override, env, envKey, defaultValue) {
|
|
26
|
+
const direct = nonEmptyString(override);
|
|
27
|
+
const envValue = nonEmptyString(env?.[envKey]);
|
|
28
|
+
const effective = direct ?? envValue ?? nonEmptyString(defaultValue);
|
|
29
|
+
if (!effective) {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
return effective
|
|
33
|
+
.split(/[,\s]+/)
|
|
34
|
+
.map((item) => item.trim())
|
|
35
|
+
.filter((item) => item.length > 0);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function extractTextFragments(items) {
|
|
39
|
+
if (!Array.isArray(items)) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
const fragments = items
|
|
43
|
+
.map((item) => (item && typeof item === "object" ? item.text : undefined))
|
|
44
|
+
.filter((text) => typeof text === "string" && text.trim().length > 0);
|
|
45
|
+
return fragments.length > 0 ? fragments.join("\n") : null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function normalizeClaudePayload(payload, effectiveModel = "") {
|
|
49
|
+
const resultText = nonEmptyString(payload?.result);
|
|
50
|
+
const messageContentText = extractTextFragments(payload?.message?.content);
|
|
51
|
+
const contentText = extractTextFragments(payload?.content);
|
|
52
|
+
const output = resultText ?? messageContentText ?? contentText;
|
|
53
|
+
if (!output) {
|
|
54
|
+
throw new Error(CLAUDE_NORMALIZATION_ERROR);
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
output,
|
|
58
|
+
model: nonEmptyString(payload?.model) ?? effectiveModel,
|
|
59
|
+
rawResponse: payload,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export async function verifyClaudeAuth(runtime, env, config) {
|
|
64
|
+
const command = runtime.resolveCmd(config.defaultCommand, config.commandEnvVar);
|
|
65
|
+
try {
|
|
66
|
+
await runtime.runCommand([command, "auth", "status"], {
|
|
67
|
+
env,
|
|
68
|
+
label: "claude:auth-status",
|
|
69
|
+
printFailureOutput: false,
|
|
70
|
+
});
|
|
71
|
+
} catch {
|
|
72
|
+
throw new Error(CLAUDE_AUTH_STATUS_ERROR);
|
|
73
|
+
}
|
|
74
|
+
return command;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const claudeExecutorDefinition = {
|
|
78
|
+
kind: CLAUDE_EXECUTOR_ID,
|
|
79
|
+
version: 1,
|
|
80
|
+
defaultConfig: {
|
|
81
|
+
commandEnvVar: "CLAUDE_BIN",
|
|
82
|
+
defaultCommand: "claude",
|
|
83
|
+
modelEnvVar: "CLAUDE_MODEL",
|
|
84
|
+
defaultModel: "",
|
|
85
|
+
maxTurnsEnvVar: "CLAUDE_MAX_TURNS",
|
|
86
|
+
defaultMaxTurns: "",
|
|
87
|
+
permissionModeEnvVar: "CLAUDE_PERMISSION_MODE",
|
|
88
|
+
defaultPermissionMode: "bypassPermissions",
|
|
89
|
+
allowedToolsEnvVar: "CLAUDE_ALLOWED_TOOLS",
|
|
90
|
+
defaultAllowedTools: "",
|
|
91
|
+
disallowedToolsEnvVar: "CLAUDE_DISALLOWED_TOOLS",
|
|
92
|
+
defaultDisallowedTools: "",
|
|
93
|
+
addCwdAsAllowedDir: true,
|
|
94
|
+
},
|
|
95
|
+
async execute(context, input, config) {
|
|
96
|
+
const env = input?.env ?? context.env;
|
|
97
|
+
const command = input?.command ?? context.runtime.resolveCmd(config.defaultCommand, config.commandEnvVar);
|
|
98
|
+
const effectiveModel = resolveSetting(input?.model, env, config.modelEnvVar, config.defaultModel);
|
|
99
|
+
const effectiveMaxTurns = resolveSetting(input?.maxTurns, env, config.maxTurnsEnvVar, config.defaultMaxTurns);
|
|
100
|
+
const permissionMode = resolveSetting(undefined, env, config.permissionModeEnvVar, config.defaultPermissionMode);
|
|
101
|
+
const allowedTools = resolveStringListSetting(undefined, env, config.allowedToolsEnvVar, config.defaultAllowedTools);
|
|
102
|
+
const disallowedTools = resolveStringListSetting(undefined, env, config.disallowedToolsEnvVar, config.defaultDisallowedTools);
|
|
103
|
+
const argv = [
|
|
104
|
+
command,
|
|
105
|
+
"-p",
|
|
106
|
+
String(input?.prompt ?? ""),
|
|
107
|
+
"--output-format",
|
|
108
|
+
"json",
|
|
109
|
+
...(config.addCwdAsAllowedDir ? ["--add-dir", context.cwd] : []),
|
|
110
|
+
...(permissionMode ? ["--permission-mode", permissionMode] : []),
|
|
111
|
+
...(allowedTools.length > 0 ? ["--allowedTools", ...allowedTools] : []),
|
|
112
|
+
...(disallowedTools.length > 0 ? ["--disallowedTools", ...disallowedTools] : []),
|
|
113
|
+
...(effectiveModel ? ["--model", effectiveModel] : []),
|
|
114
|
+
...(effectiveMaxTurns ? ["--max-turns", effectiveMaxTurns] : []),
|
|
115
|
+
];
|
|
116
|
+
const stdout = await context.runtime.runCommand(argv, {
|
|
117
|
+
env,
|
|
118
|
+
dryRun: context.dryRun,
|
|
119
|
+
verbose: context.verbose,
|
|
120
|
+
label: `claude:${effectiveModel || "default"}`,
|
|
121
|
+
printFailureOutput: true,
|
|
122
|
+
});
|
|
123
|
+
let payload;
|
|
124
|
+
try {
|
|
125
|
+
payload = JSON.parse(stdout);
|
|
126
|
+
} catch (error) {
|
|
127
|
+
throw new Error(`Claude CLI returned invalid JSON: ${error.message}`);
|
|
128
|
+
}
|
|
129
|
+
const normalized = normalizeClaudePayload(payload, effectiveModel ?? "");
|
|
130
|
+
return {
|
|
131
|
+
output: normalized.output,
|
|
132
|
+
command,
|
|
133
|
+
model: normalized.model ?? "",
|
|
134
|
+
rawResponse: normalized.rawResponse,
|
|
135
|
+
};
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export const executors = [
|
|
140
|
+
{
|
|
141
|
+
id: CLAUDE_EXECUTOR_ID,
|
|
142
|
+
definition: claudeExecutorDefinition,
|
|
143
|
+
routing: {
|
|
144
|
+
kind: "llm",
|
|
145
|
+
defaultModel: "sonnet",
|
|
146
|
+
models: ["sonnet", "opus", "haiku"],
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
];
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"kind": "claude-example-flow",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"description": "Project-local reference flow for the Claude example plugin.",
|
|
5
|
+
"phases": [
|
|
6
|
+
{
|
|
7
|
+
"id": "example",
|
|
8
|
+
"steps": [
|
|
9
|
+
{
|
|
10
|
+
"id": "run_claude_prompt",
|
|
11
|
+
"node": "llm-prompt",
|
|
12
|
+
"prompt": {
|
|
13
|
+
"inlineTemplate": "Use the current workspace. Create the JSON file `.agentweaver/.artifacts/examples/claude-example-proof.json` with exactly this shape: `{ \"status\": \"ok\", \"executor\": \"claude\", \"message\": \"<one short sentence proving the Claude example plugin executed through llm-prompt>\", \"model\": \"<the exact model name you used, or an empty string if unavailable>\" }`. Write valid JSON only to that file. After the file is written, reply with exactly `wrote .agentweaver/.artifacts/examples/claude-example-proof.json`."
|
|
14
|
+
},
|
|
15
|
+
"params": {
|
|
16
|
+
"labelText": {
|
|
17
|
+
"const": "Run Claude via llm-prompt"
|
|
18
|
+
},
|
|
19
|
+
"executor": {
|
|
20
|
+
"const": "claude"
|
|
21
|
+
},
|
|
22
|
+
"requiredArtifacts": {
|
|
23
|
+
"list": [
|
|
24
|
+
{
|
|
25
|
+
"const": ".agentweaver/.artifacts/examples/claude-example-proof.json"
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"missingArtifactsMessage": {
|
|
30
|
+
"const": "The Claude example flow requires Claude to write the fixed proof artifact."
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"expect": [
|
|
34
|
+
{
|
|
35
|
+
"kind": "require-artifacts",
|
|
36
|
+
"paths": {
|
|
37
|
+
"list": [
|
|
38
|
+
{
|
|
39
|
+
"const": ".agentweaver/.artifacts/examples/claude-example-proof.json"
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"message": "The Claude example flow must write the fixed proof artifact."
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { AGENTWEAVER_PLUGIN_SDK_VERSION } from "agentweaver/plugin-sdk";
|
|
2
|
+
|
|
3
|
+
export const CLAUDE_EXAMPLE_PLUGIN_SDK_VERSION = AGENTWEAVER_PLUGIN_SDK_VERSION;
|
|
4
|
+
export const CLAUDE_EXECUTOR_ID = "claude";
|
|
5
|
+
export const CLAUDE_AUTH_STATUS_ERROR = "Claude CLI authentication is required. Run 'claude auth status' and sign in before using the example flow.";
|
|
6
|
+
export const CLAUDE_NORMALIZATION_ERROR =
|
|
7
|
+
"Claude JSON normalization failed: no supported assistant text was found in result, message.content[*].text, or content[*].text.";
|
|
8
|
+
|
|
9
|
+
function nonEmptyString(value) {
|
|
10
|
+
return typeof value === "string" && value.trim().length > 0 ? value : null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function resolveSetting(override, env, envKey, defaultValue) {
|
|
14
|
+
const direct = nonEmptyString(typeof override === "number" ? String(override) : override);
|
|
15
|
+
if (direct) {
|
|
16
|
+
return direct;
|
|
17
|
+
}
|
|
18
|
+
const fromEnv = nonEmptyString(env?.[envKey]);
|
|
19
|
+
if (fromEnv) {
|
|
20
|
+
return fromEnv;
|
|
21
|
+
}
|
|
22
|
+
return nonEmptyString(defaultValue);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function resolveStringListSetting(override, env, envKey, defaultValue) {
|
|
26
|
+
const direct = nonEmptyString(override);
|
|
27
|
+
const envValue = nonEmptyString(env?.[envKey]);
|
|
28
|
+
const effective = direct ?? envValue ?? nonEmptyString(defaultValue);
|
|
29
|
+
if (!effective) {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
return effective
|
|
33
|
+
.split(/[,\s]+/)
|
|
34
|
+
.map((item) => item.trim())
|
|
35
|
+
.filter((item) => item.length > 0);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function extractTextFragments(items) {
|
|
39
|
+
if (!Array.isArray(items)) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
const fragments = items
|
|
43
|
+
.map((item) => (item && typeof item === "object" ? item.text : undefined))
|
|
44
|
+
.filter((text) => typeof text === "string" && text.trim().length > 0);
|
|
45
|
+
return fragments.length > 0 ? fragments.join("\n") : null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function normalizeClaudePayload(payload, effectiveModel = "") {
|
|
49
|
+
const resultText = nonEmptyString(payload?.result);
|
|
50
|
+
const messageContentText = extractTextFragments(payload?.message?.content);
|
|
51
|
+
const contentText = extractTextFragments(payload?.content);
|
|
52
|
+
const output = resultText ?? messageContentText ?? contentText;
|
|
53
|
+
if (!output) {
|
|
54
|
+
throw new Error(CLAUDE_NORMALIZATION_ERROR);
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
output,
|
|
58
|
+
model: nonEmptyString(payload?.model) ?? effectiveModel,
|
|
59
|
+
rawResponse: payload,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export async function verifyClaudeAuth(runtime, env, config) {
|
|
64
|
+
const command = runtime.resolveCmd(config.defaultCommand, config.commandEnvVar);
|
|
65
|
+
try {
|
|
66
|
+
await runtime.runCommand([command, "auth", "status"], {
|
|
67
|
+
env,
|
|
68
|
+
label: "claude:auth-status",
|
|
69
|
+
printFailureOutput: false,
|
|
70
|
+
});
|
|
71
|
+
} catch {
|
|
72
|
+
throw new Error(CLAUDE_AUTH_STATUS_ERROR);
|
|
73
|
+
}
|
|
74
|
+
return command;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const claudeExecutorDefinition = {
|
|
78
|
+
kind: CLAUDE_EXECUTOR_ID,
|
|
79
|
+
version: 1,
|
|
80
|
+
defaultConfig: {
|
|
81
|
+
commandEnvVar: "CLAUDE_BIN",
|
|
82
|
+
defaultCommand: "claude",
|
|
83
|
+
modelEnvVar: "CLAUDE_MODEL",
|
|
84
|
+
defaultModel: "",
|
|
85
|
+
maxTurnsEnvVar: "CLAUDE_MAX_TURNS",
|
|
86
|
+
defaultMaxTurns: "",
|
|
87
|
+
permissionModeEnvVar: "CLAUDE_PERMISSION_MODE",
|
|
88
|
+
defaultPermissionMode: "bypassPermissions",
|
|
89
|
+
allowedToolsEnvVar: "CLAUDE_ALLOWED_TOOLS",
|
|
90
|
+
defaultAllowedTools: "",
|
|
91
|
+
disallowedToolsEnvVar: "CLAUDE_DISALLOWED_TOOLS",
|
|
92
|
+
defaultDisallowedTools: "",
|
|
93
|
+
addCwdAsAllowedDir: true,
|
|
94
|
+
},
|
|
95
|
+
async execute(context, input, config) {
|
|
96
|
+
const env = input?.env ?? context.env;
|
|
97
|
+
const command = input?.command ?? context.runtime.resolveCmd(config.defaultCommand, config.commandEnvVar);
|
|
98
|
+
const effectiveModel = resolveSetting(input?.model, env, config.modelEnvVar, config.defaultModel);
|
|
99
|
+
const effectiveMaxTurns = resolveSetting(input?.maxTurns, env, config.maxTurnsEnvVar, config.defaultMaxTurns);
|
|
100
|
+
const permissionMode = resolveSetting(undefined, env, config.permissionModeEnvVar, config.defaultPermissionMode);
|
|
101
|
+
const allowedTools = resolveStringListSetting(undefined, env, config.allowedToolsEnvVar, config.defaultAllowedTools);
|
|
102
|
+
const disallowedTools = resolveStringListSetting(undefined, env, config.disallowedToolsEnvVar, config.defaultDisallowedTools);
|
|
103
|
+
const argv = [
|
|
104
|
+
command,
|
|
105
|
+
"-p",
|
|
106
|
+
String(input?.prompt ?? ""),
|
|
107
|
+
"--output-format",
|
|
108
|
+
"json",
|
|
109
|
+
...(config.addCwdAsAllowedDir ? ["--add-dir", context.cwd] : []),
|
|
110
|
+
...(permissionMode ? ["--permission-mode", permissionMode] : []),
|
|
111
|
+
...(allowedTools.length > 0 ? ["--allowedTools", ...allowedTools] : []),
|
|
112
|
+
...(disallowedTools.length > 0 ? ["--disallowedTools", ...disallowedTools] : []),
|
|
113
|
+
...(effectiveModel ? ["--model", effectiveModel] : []),
|
|
114
|
+
...(effectiveMaxTurns ? ["--max-turns", effectiveMaxTurns] : []),
|
|
115
|
+
];
|
|
116
|
+
const stdout = await context.runtime.runCommand(argv, {
|
|
117
|
+
env,
|
|
118
|
+
dryRun: context.dryRun,
|
|
119
|
+
verbose: context.verbose,
|
|
120
|
+
label: `claude:${effectiveModel || "default"}`,
|
|
121
|
+
printFailureOutput: true,
|
|
122
|
+
});
|
|
123
|
+
let payload;
|
|
124
|
+
try {
|
|
125
|
+
payload = JSON.parse(stdout);
|
|
126
|
+
} catch (error) {
|
|
127
|
+
throw new Error(`Claude CLI returned invalid JSON: ${error.message}`);
|
|
128
|
+
}
|
|
129
|
+
const normalized = normalizeClaudePayload(payload, effectiveModel ?? "");
|
|
130
|
+
return {
|
|
131
|
+
output: normalized.output,
|
|
132
|
+
command,
|
|
133
|
+
model: normalized.model ?? "",
|
|
134
|
+
rawResponse: normalized.rawResponse,
|
|
135
|
+
};
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export const executors = [
|
|
140
|
+
{
|
|
141
|
+
id: CLAUDE_EXECUTOR_ID,
|
|
142
|
+
definition: claudeExecutorDefinition,
|
|
143
|
+
routing: {
|
|
144
|
+
kind: "llm",
|
|
145
|
+
defaultModel: "sonnet",
|
|
146
|
+
models: ["sonnet", "opus", "haiku"],
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
];
|