@zhivex-ai/harness 1.2.0 → 1.3.0-rc.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/CHANGELOG.md +19 -0
- package/README.md +7 -8
- package/contracts/engine-api.json +2587 -0
- package/dist/acp-cli.js +95 -14996
- package/dist/cli/cli-options.d.ts +2 -41
- package/dist/cli/cli-stream.d.ts +2 -167
- package/dist/cli/run-document.d.ts +2 -91
- package/dist/cli/terminal/terminal-continuation.d.ts +2 -3
- package/dist/{cli-entry-427869g9.js → cli-entry-0mmeag20.js} +49 -1
- package/dist/{cli-entry-b1mfvmxe.js → cli-entry-7h9savv5.js} +1 -2
- package/dist/{cli-entry-c2f58zj2.js → cli-entry-xmf48p6a.js} +27 -18
- package/dist/{cli-3jmy4h5h.js → cli-qgwvtk0w.js} +5 -6
- package/dist/cli.js +2 -2
- package/dist/client/continuation.d.ts +3 -0
- package/dist/client/run-document.d.ts +91 -0
- package/dist/client/stream.d.ts +167 -0
- package/dist/compat/cli-options.d.ts +41 -0
- package/dist/compat/code-support.d.ts +22 -0
- package/dist/compat/code-support.js +138 -0
- package/dist/config-6gtpxvjv.js +59 -0
- package/dist/{config-1k9t4jhh.js → config-q32jm1e6.js} +1 -1
- package/dist/engine/acp.d.ts +4 -0
- package/dist/engine/acp.js +9 -0
- package/dist/engine/client.d.ts +6 -0
- package/dist/engine/client.js +21 -0
- package/dist/engine/index.d.ts +61 -0
- package/dist/engine/index.js +477 -0
- package/dist/engine/protocol.d.ts +6 -0
- package/dist/engine/protocol.js +158 -0
- package/dist/engine/service.d.ts +5 -0
- package/dist/engine/service.js +21 -0
- package/dist/hostile-repository-demo.js +59 -1
- package/dist/index-1bx83sw4.js +4 -0
- package/dist/index-2aymdsqc.js +150 -0
- package/dist/index-41fkzt91.js +293 -0
- package/dist/index-5wjwe91x.js +9434 -0
- package/dist/index-77h9qr5h.js +326 -0
- package/dist/index-d0wrghff.js +3271 -0
- package/dist/index-f4sb0e2q.js +318 -0
- package/dist/index-fvca1xea.js +2069 -0
- package/dist/index-kfgt9yqq.js +526 -0
- package/dist/index-pgqz45fj.js +2449 -0
- package/dist/index.js +238 -18649
- package/dist/service-cli.js +10 -14502
- package/dist/{service-client-cli-yx56n0hc.js → service-client-cli-gs78wrxe.js} +2 -2
- package/dist/verify-historical-migrations.js +59 -1
- package/dist/zhx.js +2 -2
- package/docs/CODE_RELEASE.md +93 -0
- package/docs/ENGINE_API.md +111 -0
- package/docs/FIRST_USE.md +6 -6
- package/docs/README.md +5 -0
- package/docs/STABILITY.md +6 -0
- package/evaluations/representative-assembly-matrix.json +28 -1
- package/examples/README.md +1 -1
- package/package.json +35 -4
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
// src/cli/terminal/session-grants.ts
|
|
2
|
+
function checkApprovalGrant(approval, workspace) {
|
|
3
|
+
if (approval.kind !== "local-tool" || approval.name !== "run_check")
|
|
4
|
+
return;
|
|
5
|
+
try {
|
|
6
|
+
const args = JSON.parse(approval.arguments);
|
|
7
|
+
if (!args || typeof args !== "object" || Array.isArray(args))
|
|
8
|
+
return;
|
|
9
|
+
const value = args;
|
|
10
|
+
if (Object.keys(value).sort().join(",") !== "check,expectedScript" || typeof value.check !== "string" || typeof value.expectedScript !== "string" || !value.expectedScript.trim())
|
|
11
|
+
return;
|
|
12
|
+
return JSON.stringify([workspace, approval.provider, approval.childAgentId ?? "", approval.name, value.check, value.expectedScript]);
|
|
13
|
+
} catch {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// src/cli/terminal/terminal-ui.ts
|
|
19
|
+
var DEFAULT_APPROVAL_SUMMARY_CHARACTERS = 1200;
|
|
20
|
+
var EXACT_REVIEW_TOOLS = new Set([
|
|
21
|
+
"apply_patch",
|
|
22
|
+
"apply_reviewed_edits",
|
|
23
|
+
"apply_reviewed_replacement",
|
|
24
|
+
"verify_and_apply_reviewed_edits",
|
|
25
|
+
"move_file",
|
|
26
|
+
"quarantine_file",
|
|
27
|
+
"restore_file",
|
|
28
|
+
"run_check",
|
|
29
|
+
"run_environment_command",
|
|
30
|
+
"run_environment_batch",
|
|
31
|
+
"run_environment_shell",
|
|
32
|
+
"apply_environment_patch",
|
|
33
|
+
"verify_and_apply_environment_patch"
|
|
34
|
+
]);
|
|
35
|
+
var TERMINAL_CONTROL_CHARACTERS = /[\u0000-\u0008\u000b\u000c\u000d\u000e-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/gu;
|
|
36
|
+
var escapeCodePoint = (character) => {
|
|
37
|
+
const codePoint = character.codePointAt(0) ?? 0;
|
|
38
|
+
return codePoint <= 65535 ? `\\u${codePoint.toString(16).padStart(4, "0")}` : `\\u{${codePoint.toString(16)}}`;
|
|
39
|
+
};
|
|
40
|
+
var sanitizeTerminalText = (value) => value.replace(TERMINAL_CONTROL_CHARACTERS, escapeCodePoint);
|
|
41
|
+
var readableApprovalArguments = (argumentsText) => {
|
|
42
|
+
try {
|
|
43
|
+
return sanitizeTerminalText(JSON.stringify(JSON.parse(argumentsText), null, 2));
|
|
44
|
+
} catch {
|
|
45
|
+
return sanitizeTerminalText(argumentsText);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
var boundedText = (value, maximumCharacters) => {
|
|
49
|
+
if (value.length <= maximumCharacters) {
|
|
50
|
+
return { text: value, omitted: 0 };
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
text: `${value.slice(0, maximumCharacters)}…`,
|
|
54
|
+
omitted: value.length - maximumCharacters
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
var formatApproval = (approval, options = {}) => {
|
|
58
|
+
const detail = options.detail ?? "summary";
|
|
59
|
+
const maximumCharacters = options.maxSummaryCharacters ?? DEFAULT_APPROVAL_SUMMARY_CHARACTERS;
|
|
60
|
+
if (!Number.isSafeInteger(maximumCharacters) || maximumCharacters < 1) {
|
|
61
|
+
throw new Error("Approval summary length must be a positive safe integer.");
|
|
62
|
+
}
|
|
63
|
+
const completePayload = readableApprovalArguments(approval.arguments);
|
|
64
|
+
const shouldShowComplete = detail === "full" || EXACT_REVIEW_TOOLS.has(approval.name);
|
|
65
|
+
const payload = shouldShowComplete ? { text: completePayload, omitted: 0 } : boundedText(completePayload, maximumCharacters);
|
|
66
|
+
const identity = [
|
|
67
|
+
detail === "full" && approval.id ? `approval ${sanitizeTerminalText(approval.id)}` : undefined,
|
|
68
|
+
detail === "full" && approval.inputDigest ? `input ${sanitizeTerminalText(approval.inputDigest)}` : undefined,
|
|
69
|
+
approval.serverLabel ? `server ${sanitizeTerminalText(approval.serverLabel)}` : undefined,
|
|
70
|
+
approval.childAgentId ? `child ${sanitizeTerminalText(approval.childAgentId)}` : undefined
|
|
71
|
+
].filter((value) => value !== undefined);
|
|
72
|
+
const header = `[${sanitizeTerminalText(approval.kind ?? "provider")}] ` + `${sanitizeTerminalText(approval.name)}` + (identity.length > 0 ? ` · ${identity.join(" · ")}` : "");
|
|
73
|
+
const omissionNotice = payload.omitted > 0 ? `
|
|
74
|
+
[${payload.omitted} characters omitted; press v to view the complete payload]` : "";
|
|
75
|
+
const scope = [];
|
|
76
|
+
if (EXACT_REVIEW_TOOLS.has(approval.name)) {
|
|
77
|
+
try {
|
|
78
|
+
const args = JSON.parse(approval.arguments);
|
|
79
|
+
if (Array.isArray(args.changes))
|
|
80
|
+
for (const change of args.changes) {
|
|
81
|
+
if (typeof change?.path === "string")
|
|
82
|
+
scope.push(`${change.expectedDigest === null ? "ADD" : "MODIFY"} ${change.path}`);
|
|
83
|
+
}
|
|
84
|
+
if (approval.name === "quarantine_file" && typeof args.path === "string")
|
|
85
|
+
scope.push(`REMOVE (recoverable quarantine) ${args.path}`);
|
|
86
|
+
if (approval.name === "move_file")
|
|
87
|
+
scope.push(`MOVE ${args.source} -> ${args.destination}`);
|
|
88
|
+
if (approval.name.includes("verify_and_apply"))
|
|
89
|
+
scope.push("Verification: pending; approval authorizes the checks and conditional application, not a successful result.");
|
|
90
|
+
} catch {}
|
|
91
|
+
}
|
|
92
|
+
if (detail === "summary" && approval.kind === "local-tool" && approval.name === "run_check") {
|
|
93
|
+
try {
|
|
94
|
+
const args = JSON.parse(approval.arguments);
|
|
95
|
+
if (typeof args.check === "string" && typeof args.expectedScript === "string" && Object.keys(args).every((key) => ["check", "expectedScript"].includes(key))) {
|
|
96
|
+
return `Run check: ${sanitizeTerminalText(args.check)}${identity.length ? ` · ${identity.join(" · ")}` : ""}
|
|
97
|
+
|
|
98
|
+
${sanitizeTerminalText(args.expectedScript)}
|
|
99
|
+
`;
|
|
100
|
+
}
|
|
101
|
+
} catch {}
|
|
102
|
+
}
|
|
103
|
+
return `${header}
|
|
104
|
+
${scope.map(sanitizeTerminalText).map((line) => `${line}
|
|
105
|
+
`).join("")}${payload.text}${omissionNotice}`;
|
|
106
|
+
};
|
|
107
|
+
var promptEnded = (error) => {
|
|
108
|
+
if (!error || typeof error !== "object")
|
|
109
|
+
return false;
|
|
110
|
+
const candidate = error;
|
|
111
|
+
return candidate.name === "AbortError" || candidate.code === "ABORT_ERR" || candidate.code === "ERR_USE_AFTER_CLOSE";
|
|
112
|
+
};
|
|
113
|
+
var normalizedDecision = (answer) => answer.trim().toLowerCase();
|
|
114
|
+
var resolveTerminalApprovals = async (approvals, options) => {
|
|
115
|
+
const responses = [];
|
|
116
|
+
const staged = new Set(options.sessionGrants);
|
|
117
|
+
for (let index = 0;index < approvals.length; index += 1) {
|
|
118
|
+
const approval = approvals[index];
|
|
119
|
+
const grant = options.sessionGrants && options.workspace ? checkApprovalGrant(approval, options.workspace) : undefined;
|
|
120
|
+
if (grant && staged.has(grant)) {
|
|
121
|
+
responses.push({ provider: approval.provider, approvalRequestId: approval.id, approve: true, reason: "Exact check approved for this CLI session." });
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
options.write(`
|
|
125
|
+
Approval required ${index + 1}/${approvals.length}:
|
|
126
|
+
` + `${formatApproval(approval, {
|
|
127
|
+
detail: "summary",
|
|
128
|
+
...options.maxSummaryCharacters !== undefined ? { maxSummaryCharacters: options.maxSummaryCharacters } : {}
|
|
129
|
+
})}
|
|
130
|
+
`);
|
|
131
|
+
if (options.workspace)
|
|
132
|
+
options.write(`Workspace: ${sanitizeTerminalText(options.workspace)}
|
|
133
|
+
`);
|
|
134
|
+
for (;; ) {
|
|
135
|
+
let answer;
|
|
136
|
+
try {
|
|
137
|
+
const received = options.select ? await options.select("Permission required", [
|
|
138
|
+
{ value: "n", label: "Reject" },
|
|
139
|
+
{ value: "y", label: "Allow once", detail: "Only the action shown above" },
|
|
140
|
+
...grant ? [{ value: "s", label: "Allow this exact check for this session", detail: "Changing the script requires approval again" }] : [],
|
|
141
|
+
{ value: "v", label: "View technical details" },
|
|
142
|
+
{ value: "q", label: "Leave pending" }
|
|
143
|
+
]) : await options.ask(`Approve? [y]es/${grant ? "[s]ession/" : ""}[n]o/[v]iew/[q]uit (default: no) `);
|
|
144
|
+
if (typeof received !== "string")
|
|
145
|
+
return;
|
|
146
|
+
answer = normalizedDecision(received);
|
|
147
|
+
} catch (error) {
|
|
148
|
+
if (promptEnded(error))
|
|
149
|
+
return;
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
if (answer === "v" || answer === "view") {
|
|
153
|
+
options.write(`
|
|
154
|
+
Complete approval payload:
|
|
155
|
+
${formatApproval(approval, { detail: "full" })}
|
|
156
|
+
`);
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (answer === "q" || answer === "quit") {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (answer === "y" || answer === "yes" || answer === "s" && grant) {
|
|
163
|
+
if (answer === "s" && grant)
|
|
164
|
+
staged.add(grant);
|
|
165
|
+
responses.push({
|
|
166
|
+
provider: approval.provider,
|
|
167
|
+
approvalRequestId: approval.id,
|
|
168
|
+
approve: true,
|
|
169
|
+
reason: options.approvedReason ?? "Approved interactively."
|
|
170
|
+
});
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
if (answer === "" || answer === "n" || answer === "no") {
|
|
174
|
+
responses.push({
|
|
175
|
+
provider: approval.provider,
|
|
176
|
+
approvalRequestId: approval.id,
|
|
177
|
+
approve: false,
|
|
178
|
+
reason: options.deniedReason ?? "Denied by the operator."
|
|
179
|
+
});
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
options.write(`Choose y, n, v, or q.
|
|
183
|
+
`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
for (const key of staged)
|
|
187
|
+
options.sessionGrants?.add(key);
|
|
188
|
+
return responses;
|
|
189
|
+
};
|
|
190
|
+
var terminalSupportsColor = (isTTY, env = process.env) => isTTY && !Object.prototype.hasOwnProperty.call(env, "NO_COLOR") && env.TERM !== "dumb" && env.FORCE_COLOR !== "0";
|
|
191
|
+
var verificationReceipt = (name, output) => {
|
|
192
|
+
if (!output || typeof output !== "object")
|
|
193
|
+
return;
|
|
194
|
+
const value = output;
|
|
195
|
+
const receipt = name === "run_check" || name === "run_environment_command" ? value : name.startsWith("verify_and_apply_") && value.verification && typeof value.verification === "object" ? value.verification : undefined;
|
|
196
|
+
if (!receipt || !Number.isSafeInteger(receipt.exitCode))
|
|
197
|
+
return;
|
|
198
|
+
const command = receipt.command;
|
|
199
|
+
const prefix = Array.isArray(command) ? JSON.stringify(command.slice(0, -1)) : "";
|
|
200
|
+
const supported = [
|
|
201
|
+
'["bun","--no-env-file","run"]',
|
|
202
|
+
'["npm","--ignore-scripts","run"]',
|
|
203
|
+
'["pnpm","--ignore-scripts","run"]',
|
|
204
|
+
'["yarn","run"]'
|
|
205
|
+
];
|
|
206
|
+
const last = Array.isArray(command) ? command.at(-1) : undefined;
|
|
207
|
+
const check = name === "run_check" && supported.includes(prefix) && typeof last === "string" && /^[A-Za-z0-9:_-]{1,100}$/.test(last) ? last : undefined;
|
|
208
|
+
return { exitCode: receipt.exitCode, timedOut: receipt.timedOut === true, check };
|
|
209
|
+
};
|
|
210
|
+
var paint = (text, code, color) => color ? `\x1B[${code}m${text}\x1B[0m` : text;
|
|
211
|
+
var terminalRunFailure = (error) => {
|
|
212
|
+
const message = error instanceof Error ? error.message : error && typeof error === "object" && ("message" in error) && typeof error.message === "string" ? error.message : "";
|
|
213
|
+
const provider = /^(Meta|Qwen|OpenAI|Gemini) request failed with status ([45]\d{2})(?: \((previous response unavailable|context length exceeded|tools rejected|input rejected|output token limit rejected|previous response rejected|reason unavailable)\))?\.$/.exec(message);
|
|
214
|
+
if (provider)
|
|
215
|
+
return `${provider[1]} request failed · HTTP ${provider[2]}${provider[3] ? ` · ${provider[3]}` : ""}`;
|
|
216
|
+
const budget = /^Agent budget exceeded including child runs: (maxInputTokens|maxOutputTokens|maxTotalTokens|maxToolCalls|maxToolErrors|maxSteps) limit (\d+), actual (\d+)\.$/.exec(message);
|
|
217
|
+
if (budget)
|
|
218
|
+
return `budget exceeded · ${budget[1]} · ${budget[3]} / ${budget[2]}`;
|
|
219
|
+
const denied = /^Tool "(read_file|read_files|list_files|search_files|search_many)" failed: The path is protected by the harness policy: (node_modules|\.git|\.zhivex-harness|dist|coverage|\.next|\.turbo)$/.exec(message);
|
|
220
|
+
if (denied)
|
|
221
|
+
return `read denied · protected path ${denied[2]}`;
|
|
222
|
+
if (message === "Agent compaction result still exceeds maxEstimatedInputTokens." || message === "Agent compaction cannot satisfy its limits without removing protected messages.") {
|
|
223
|
+
return "context could not fit after compaction · retained messages exceed the input limit";
|
|
224
|
+
}
|
|
225
|
+
const streamOverflow = /^Stream replay buffer exceeded its limit of (\d+) events\.$/.exec(message);
|
|
226
|
+
if (streamOverflow)
|
|
227
|
+
return `event replay limit reached · ${streamOverflow[1]} events`;
|
|
228
|
+
const stateOverflow = /^Agent run state is (\d+) bytes and exceeds maxStateBytes=(\d+)\. Offload large tool outputs to artifacts or raise the explicit limit\.$/.exec(message);
|
|
229
|
+
if (stateOverflow)
|
|
230
|
+
return `durable state limit reached · ${stateOverflow[1]} / ${stateOverflow[2]} bytes · inspect /status before /continue`;
|
|
231
|
+
if (/^Tool is not registered \(sha256:[a-f0-9]{64}\)\.$/.test(message)) {
|
|
232
|
+
return "requested tool is not registered · use an available tool with its exact name";
|
|
233
|
+
}
|
|
234
|
+
const cap = /^(maxInputTokens|maxOutputTokens|maxTotalTokens) budget (exceeded|exhausted)$/.exec(message);
|
|
235
|
+
if (cap)
|
|
236
|
+
return `budget ${cap[2]} · ${cap[1]}`;
|
|
237
|
+
if (message === "Agent exhausted maxSteps before reaching a terminal response.") {
|
|
238
|
+
return "step limit reached before a final response";
|
|
239
|
+
}
|
|
240
|
+
return "run failed · cause unavailable (inspect run diagnostics)";
|
|
241
|
+
};
|
|
242
|
+
var formatTerminalEvent = (event, options = {}) => {
|
|
243
|
+
const color = options.color ?? false;
|
|
244
|
+
switch (event.type) {
|
|
245
|
+
case "text-delta":
|
|
246
|
+
return;
|
|
247
|
+
case "tool-call":
|
|
248
|
+
return `${paint("↳", 36, color)} tool · ${sanitizeTerminalText(event.toolCall.name)}`;
|
|
249
|
+
case "tool-result": {
|
|
250
|
+
const receipt = verificationReceipt(event.toolResult.toolName, event.toolResult.output);
|
|
251
|
+
if (receipt) {
|
|
252
|
+
const failed = event.toolResult.isError || receipt.timedOut || receipt.exitCode !== 0;
|
|
253
|
+
return `${paint(failed ? "✗" : "✓", failed ? 31 : 32, color)} check · ${receipt.check ?? sanitizeTerminalText(event.toolResult.toolName)} · exit ${receipt.exitCode}${receipt.timedOut ? " · timed out" : ""}`;
|
|
254
|
+
}
|
|
255
|
+
return event.toolResult.isError ? `${paint("✗", 31, color)} tool · ${sanitizeTerminalText(event.toolResult.toolName)} · error` : `${paint("✓", 32, color)} tool · ${sanitizeTerminalText(event.toolResult.toolName)}`;
|
|
256
|
+
}
|
|
257
|
+
case "tool-approval-request":
|
|
258
|
+
case "agent-approval-request":
|
|
259
|
+
return `${paint("!", 33, color)} approval · ` + `${sanitizeTerminalText(event.approval.kind ?? "provider")} · ` + sanitizeTerminalText(event.approval.name);
|
|
260
|
+
case "agent-approval-resolved":
|
|
261
|
+
return event.approval.approve ? `${paint("✓", 32, color)} approval · approved` : `${paint("✗", 31, color)} approval · denied`;
|
|
262
|
+
case "provider-data":
|
|
263
|
+
return `${paint("·", 90, color)} provider · ${sanitizeTerminalText(event.provider)}`;
|
|
264
|
+
case "image-generation":
|
|
265
|
+
return `${paint("·", 36, color)} image · ${sanitizeTerminalText(event.provider)}` + (event.partial ? " · partial" : " · complete");
|
|
266
|
+
case "finish":
|
|
267
|
+
return `${paint("·", 90, color)} model stream` + (event.finishReason ? ` · ${sanitizeTerminalText(event.finishReason)}` : " · finished");
|
|
268
|
+
case "error":
|
|
269
|
+
return `${paint("✗", 31, color)} ${terminalRunFailure(event.error)}`;
|
|
270
|
+
case "agent-run-start":
|
|
271
|
+
return `${paint("●", 36, color)} run · step ${event.currentStep}/${event.maxSteps}`;
|
|
272
|
+
case "agent-step-start":
|
|
273
|
+
return `${paint("●", 36, color)} step ${event.stepIndex + 1}`;
|
|
274
|
+
case "agent-step-finish":
|
|
275
|
+
return `${paint(event.step.status === "failed" ? "✗" : "✓", event.step.status === "failed" ? 31 : 32, color)} ` + `step ${event.step.index + 1} · ${sanitizeTerminalText(event.step.status)} · ` + `${event.step.toolResults.length} tool${event.step.toolResults.length === 1 ? "" : "s"}`;
|
|
276
|
+
case "agent-compaction":
|
|
277
|
+
return `${paint("↺", 36, color)} context · ${event.compaction.messageCountBefore} → ` + `${event.compaction.messageCountAfter} messages`;
|
|
278
|
+
case "agent-run-finish":
|
|
279
|
+
if (event.status === "failed") {
|
|
280
|
+
const cause = terminalRunFailure(event.state.error);
|
|
281
|
+
return `${paint("✗", 31, color)} ${cause}` + (cause === "step limit reached before a final response" ? ` (${event.state.currentStep}/${event.state.maxSteps}). Session retained; use /limits to adjust the next turn, then ask to continue.` : "");
|
|
282
|
+
}
|
|
283
|
+
return `${paint(event.status === "completed" ? "✓" : "●", event.status === "completed" ? 32 : 33, color)} ` + `run · ${sanitizeTerminalText(event.status)} · ` + `${sanitizeTerminalText(event.state.provider)}/${sanitizeTerminalText(event.state.modelId)}`;
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
var formatTerminalHeader = (input, options = {}) => {
|
|
287
|
+
const color = options.color ?? false;
|
|
288
|
+
const title = input.sessionTitle ? ` · ${sanitizeTerminalText(input.sessionTitle)}` : "";
|
|
289
|
+
return `${paint(`Zhivex Harness ${sanitizeTerminalText(input.version)}`, 36, color)} · ` + `${sanitizeTerminalText(input.provider)}/${sanitizeTerminalText(input.model)}
|
|
290
|
+
` + `session ${sanitizeTerminalText(input.sessionId)}${title}`;
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
export { DEFAULT_APPROVAL_SUMMARY_CHARACTERS, sanitizeTerminalText, formatApproval, resolveTerminalApprovals, terminalSupportsColor, formatTerminalEvent, formatTerminalHeader };
|