@brawnen/agent-harness-cli 0.1.0 → 0.1.2
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 +59 -7
- package/README.zh-CN.md +16 -4
- package/package.json +12 -4
- package/src/commands/docs.js +19 -13
- package/src/commands/gate.js +1 -1
- package/src/commands/hook.js +43 -0
- package/src/commands/init.js +83 -8
- package/src/commands/report.js +4 -4
- package/src/commands/state.js +10 -2
- package/src/commands/status.js +169 -11
- package/src/commands/sync.js +88 -0
- package/src/index.js +15 -3
- package/src/lib/claude-hooks.js +49 -0
- package/src/lib/codex-hooks.js +48 -0
- package/src/lib/gemini-hooks.js +76 -0
- package/src/lib/hook-core.js +639 -0
- package/src/lib/hook-io/claude.js +23 -0
- package/src/lib/hook-io/codex.js +23 -0
- package/src/lib/hook-io/gemini.js +130 -0
- package/src/lib/hook-io/shared.js +52 -0
- package/src/lib/host-layout.js +1384 -0
- package/src/lib/output-policy.js +6 -6
- package/src/lib/runtime-paths.js +39 -0
- package/src/lib/task-core.js +104 -20
- package/src/runtime-host/index.js +57 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { firstDefined, firstString } from "./shared.js";
|
|
2
|
+
|
|
3
|
+
export function buildGeminiHookOutput(decision) {
|
|
4
|
+
if (decision.status === "block") {
|
|
5
|
+
return {
|
|
6
|
+
decision: "deny",
|
|
7
|
+
reason: decision.reason
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (!decision.additionalContext) {
|
|
12
|
+
return {};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
hookSpecificOutput: {
|
|
17
|
+
additionalContext: decision.additionalContext
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function resolveGeminiCompletionMessage(payload) {
|
|
23
|
+
return firstString([
|
|
24
|
+
payload?.prompt_response,
|
|
25
|
+
payload?.response,
|
|
26
|
+
payload?.last_assistant_message
|
|
27
|
+
]) ?? "";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function resolveGeminiToolName(payload) {
|
|
31
|
+
return firstString([
|
|
32
|
+
payload?.tool_name,
|
|
33
|
+
payload?.toolName,
|
|
34
|
+
payload?.tool?.name,
|
|
35
|
+
payload?.toolUse?.name,
|
|
36
|
+
payload?.name
|
|
37
|
+
]);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function resolveGeminiToolCommand(payload) {
|
|
41
|
+
return firstString([
|
|
42
|
+
payload?.tool_input?.command,
|
|
43
|
+
payload?.toolInput?.command,
|
|
44
|
+
payload?.input?.command,
|
|
45
|
+
payload?.arguments?.command,
|
|
46
|
+
payload?.tool_use?.input?.command,
|
|
47
|
+
payload?.toolUse?.input?.command,
|
|
48
|
+
payload?.command
|
|
49
|
+
]) ?? "";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function resolveGeminiToolPath(payload) {
|
|
53
|
+
return firstString([
|
|
54
|
+
payload?.tool_input?.file_path,
|
|
55
|
+
payload?.tool_input?.path,
|
|
56
|
+
payload?.toolInput?.file_path,
|
|
57
|
+
payload?.toolInput?.path,
|
|
58
|
+
payload?.input?.file_path,
|
|
59
|
+
payload?.input?.path,
|
|
60
|
+
payload?.arguments?.file_path,
|
|
61
|
+
payload?.arguments?.path,
|
|
62
|
+
payload?.tool_use?.input?.file_path,
|
|
63
|
+
payload?.tool_use?.input?.path,
|
|
64
|
+
payload?.toolUse?.input?.file_path,
|
|
65
|
+
payload?.toolUse?.input?.path
|
|
66
|
+
]);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function resolveGeminiToolExitCode(payload) {
|
|
70
|
+
const value = firstDefined([
|
|
71
|
+
payload?.exit_code,
|
|
72
|
+
payload?.exitCode,
|
|
73
|
+
payload?.result?.exit_code,
|
|
74
|
+
payload?.result?.exitCode,
|
|
75
|
+
payload?.tool_response?.exit_code,
|
|
76
|
+
payload?.tool_response?.exitCode,
|
|
77
|
+
payload?.toolResponse?.exit_code,
|
|
78
|
+
payload?.toolResponse?.exitCode,
|
|
79
|
+
payload?.status
|
|
80
|
+
]);
|
|
81
|
+
|
|
82
|
+
if (typeof value === "number") {
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
87
|
+
const parsed = Number(value);
|
|
88
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function resolveGeminiToolOutput(payload) {
|
|
95
|
+
const directOutput = firstString([
|
|
96
|
+
payload?.tool_response?.output,
|
|
97
|
+
payload?.tool_response?.stdout,
|
|
98
|
+
payload?.toolResponse?.output,
|
|
99
|
+
payload?.toolResponse?.stdout,
|
|
100
|
+
payload?.stdout,
|
|
101
|
+
payload?.stderr,
|
|
102
|
+
payload?.result?.output,
|
|
103
|
+
payload?.result?.stdout,
|
|
104
|
+
payload?.output
|
|
105
|
+
]);
|
|
106
|
+
|
|
107
|
+
if (directOutput) {
|
|
108
|
+
return directOutput;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const displayOutput = firstString([
|
|
112
|
+
payload?.tool_response?.returnDisplay,
|
|
113
|
+
payload?.toolResponse?.returnDisplay
|
|
114
|
+
]);
|
|
115
|
+
|
|
116
|
+
if (displayOutput) {
|
|
117
|
+
return displayOutput;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const responsePayload = firstDefined([
|
|
121
|
+
payload?.tool_response,
|
|
122
|
+
payload?.toolResponse
|
|
123
|
+
]);
|
|
124
|
+
|
|
125
|
+
if (!responsePayload || typeof responsePayload === "string") {
|
|
126
|
+
return responsePayload ?? "";
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return JSON.stringify(responsePayload);
|
|
130
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
|
|
3
|
+
import { resolveHarnessProjectRoot } from "../runtime-paths.js";
|
|
4
|
+
|
|
5
|
+
export function readHookPayload() {
|
|
6
|
+
const raw = fs.readFileSync(0, "utf8").trim();
|
|
7
|
+
if (!raw) {
|
|
8
|
+
return {};
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
return JSON.parse(raw);
|
|
13
|
+
} catch {
|
|
14
|
+
throw new Error("hook stdin 不是合法 JSON");
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function resolvePayloadCwd(payload) {
|
|
19
|
+
return resolveHarnessProjectRoot(payload?.cwd || process.cwd());
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function resolvePayloadPrompt(payload) {
|
|
23
|
+
if (typeof payload?.prompt === "string") {
|
|
24
|
+
return payload.prompt;
|
|
25
|
+
}
|
|
26
|
+
if (typeof payload?.input === "string") {
|
|
27
|
+
return payload.input;
|
|
28
|
+
}
|
|
29
|
+
return "";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function firstDefined(values) {
|
|
33
|
+
for (const value of values) {
|
|
34
|
+
if (value !== undefined && value !== null) {
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function firstString(values) {
|
|
42
|
+
for (const value of values) {
|
|
43
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
44
|
+
return value.trim();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function writeHookOutput(result) {
|
|
51
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
52
|
+
}
|