@nomad-e/bluma-cli 0.1.58 → 0.1.60
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 +5 -3
- package/dist/config/native_tools.json +3 -3
- package/dist/config/skills/git-pr/SKILL.md +1 -1
- package/dist/config/skills/pdf/SKILL.md +153 -22
- package/dist/config/skills/pdf/scripts/__pycache__/create_report.cpython-312.pyc +0 -0
- package/dist/config/skills/pdf/scripts/create_report.py +607 -209
- package/dist/config/skills/pdf/scripts/merge_pdfs.py +1 -1
- package/dist/config/skills/skill-creator/SKILL.md +1 -1
- package/dist/main.js +122 -18
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@ Merge multiple PDF files into a single output PDF.
|
|
|
3
3
|
|
|
4
4
|
Usage:
|
|
5
5
|
python merge_pdfs.py --output merged.pdf file1.pdf file2.pdf file3.pdf
|
|
6
|
-
python merge_pdfs.py --output
|
|
6
|
+
python merge_pdfs.py --output ./.bluma/artifacts/combined.pdf *.pdf
|
|
7
7
|
"""
|
|
8
8
|
import argparse
|
|
9
9
|
import sys
|
|
@@ -193,7 +193,7 @@ Example script header:
|
|
|
193
193
|
{description of what this script does}
|
|
194
194
|
|
|
195
195
|
Usage:
|
|
196
|
-
python {script_name}.py --input data.csv --output
|
|
196
|
+
python {script_name}.py --input data.csv --output ./.bluma/artifacts/result.pdf
|
|
197
197
|
"""
|
|
198
198
|
import argparse
|
|
199
199
|
```
|
package/dist/main.js
CHANGED
|
@@ -113,6 +113,20 @@ function isPathInsideWorkspace(targetPath, policy = getSandboxPolicy()) {
|
|
|
113
113
|
const relative = path6.relative(policy.workspaceRoot, resolved);
|
|
114
114
|
return relative === "" || !relative.startsWith("..") && !path6.isAbsolute(relative);
|
|
115
115
|
}
|
|
116
|
+
function redirectTopLevelArtifactsPath(resolvedAbsolute, workspaceRoot) {
|
|
117
|
+
const wr = path6.resolve(workspaceRoot);
|
|
118
|
+
const abs = path6.resolve(resolvedAbsolute);
|
|
119
|
+
const rel = path6.relative(wr, abs);
|
|
120
|
+
if (rel.startsWith("..") || path6.isAbsolute(rel)) {
|
|
121
|
+
return abs;
|
|
122
|
+
}
|
|
123
|
+
const segments = rel.split(path6.sep).filter((s) => s.length > 0);
|
|
124
|
+
if (segments.length === 0 || segments[0] !== "artifacts") {
|
|
125
|
+
return abs;
|
|
126
|
+
}
|
|
127
|
+
const tail = segments.slice(1);
|
|
128
|
+
return tail.length > 0 ? path6.join(wr, ".bluma", "artifacts", ...tail) : path6.join(wr, ".bluma", "artifacts");
|
|
129
|
+
}
|
|
116
130
|
function resolveWorkspacePath(inputPath, policy = getSandboxPolicy()) {
|
|
117
131
|
const candidate = path6.isAbsolute(inputPath) ? path6.resolve(inputPath) : path6.resolve(policy.workspaceRoot, inputPath);
|
|
118
132
|
if (policy.isSandbox && !isPathInsideWorkspace(candidate, policy)) {
|
|
@@ -120,7 +134,7 @@ function resolveWorkspacePath(inputPath, policy = getSandboxPolicy()) {
|
|
|
120
134
|
`Path "${inputPath}" escapes the sandbox workspace root ${policy.workspaceRoot}`
|
|
121
135
|
);
|
|
122
136
|
}
|
|
123
|
-
return candidate;
|
|
137
|
+
return redirectTopLevelArtifactsPath(candidate, policy.workspaceRoot);
|
|
124
138
|
}
|
|
125
139
|
function resolveCommandCwd(cwd, policy = getSandboxPolicy()) {
|
|
126
140
|
const base = cwd ? path6.resolve(cwd) : policy.workspaceRoot;
|
|
@@ -207,6 +221,9 @@ __export(async_command_exports, {
|
|
|
207
221
|
import os6 from "os";
|
|
208
222
|
import { spawn as spawn2 } from "child_process";
|
|
209
223
|
import { v4 as uuidv42 } from "uuid";
|
|
224
|
+
function normalizeCommandId(raw) {
|
|
225
|
+
return String(raw ?? "").trim().replace(/^[#:\s]+/, "");
|
|
226
|
+
}
|
|
210
227
|
function cleanupOldCommands() {
|
|
211
228
|
if (runningCommands.size <= MAX_STORED_COMMANDS) return;
|
|
212
229
|
const commands = Array.from(runningCommands.entries()).filter(([_, cmd]) => cmd.status !== "running").sort((a, b) => (a[1].endTime || 0) - (b[1].endTime || 0));
|
|
@@ -356,13 +373,14 @@ async function commandStatus(args) {
|
|
|
356
373
|
error: "command_id is required"
|
|
357
374
|
};
|
|
358
375
|
}
|
|
359
|
-
const
|
|
376
|
+
const normalizedCommandId = normalizeCommandId(command_id);
|
|
377
|
+
const entry = runningCommands.get(normalizedCommandId);
|
|
360
378
|
if (!entry) {
|
|
361
379
|
return {
|
|
362
380
|
success: false,
|
|
363
|
-
command_id,
|
|
381
|
+
command_id: normalizedCommandId,
|
|
364
382
|
status: "not_found",
|
|
365
|
-
error: `Command with id "${
|
|
383
|
+
error: `Command with id "${normalizedCommandId}" not found. It may have expired or never existed.`
|
|
366
384
|
};
|
|
367
385
|
}
|
|
368
386
|
const maxWait = Math.min(wait_seconds, 15);
|
|
@@ -394,7 +412,7 @@ async function commandStatus(args) {
|
|
|
394
412
|
const duration = entry.endTime ? (entry.endTime - entry.startTime) / 1e3 : (Date.now() - entry.startTime) / 1e3;
|
|
395
413
|
return {
|
|
396
414
|
success: true,
|
|
397
|
-
command_id,
|
|
415
|
+
command_id: normalizedCommandId,
|
|
398
416
|
status: entry.status,
|
|
399
417
|
stdout: stdout || void 0,
|
|
400
418
|
stderr: stderr || void 0,
|
|
@@ -420,11 +438,12 @@ async function sendCommandInput(args) {
|
|
|
420
438
|
error: "command_id and input are required"
|
|
421
439
|
};
|
|
422
440
|
}
|
|
423
|
-
const
|
|
441
|
+
const normalizedCommandId = normalizeCommandId(command_id);
|
|
442
|
+
const entry = runningCommands.get(normalizedCommandId);
|
|
424
443
|
if (!entry) {
|
|
425
444
|
return {
|
|
426
445
|
success: false,
|
|
427
|
-
error: `Command with id "${
|
|
446
|
+
error: `Command with id "${normalizedCommandId}" not found`
|
|
428
447
|
};
|
|
429
448
|
}
|
|
430
449
|
if (entry.status !== "running" || !entry.process) {
|
|
@@ -436,7 +455,7 @@ async function sendCommandInput(args) {
|
|
|
436
455
|
entry.process.stdin?.write(input);
|
|
437
456
|
return {
|
|
438
457
|
success: true,
|
|
439
|
-
message: `Sent ${input.length} characters to command ${
|
|
458
|
+
message: `Sent ${input.length} characters to command ${normalizedCommandId}`
|
|
440
459
|
};
|
|
441
460
|
} catch (error) {
|
|
442
461
|
return {
|
|
@@ -448,11 +467,12 @@ async function sendCommandInput(args) {
|
|
|
448
467
|
async function killCommand(args) {
|
|
449
468
|
try {
|
|
450
469
|
const { command_id } = args;
|
|
451
|
-
const
|
|
470
|
+
const normalizedCommandId = normalizeCommandId(command_id);
|
|
471
|
+
const entry = runningCommands.get(normalizedCommandId);
|
|
452
472
|
if (!entry) {
|
|
453
473
|
return {
|
|
454
474
|
success: false,
|
|
455
|
-
error: `Command with id "${
|
|
475
|
+
error: `Command with id "${normalizedCommandId}" not found`
|
|
456
476
|
};
|
|
457
477
|
}
|
|
458
478
|
if (entry.status !== "running" || !entry.process) {
|
|
@@ -466,7 +486,7 @@ async function killCommand(args) {
|
|
|
466
486
|
entry.endTime = Date.now();
|
|
467
487
|
return {
|
|
468
488
|
success: true,
|
|
469
|
-
message: `Command ${
|
|
489
|
+
message: `Command ${normalizedCommandId} killed`
|
|
470
490
|
};
|
|
471
491
|
} catch (error) {
|
|
472
492
|
return {
|
|
@@ -3913,7 +3933,7 @@ var renderCommandStatus = ({ args }) => {
|
|
|
3913
3933
|
const parsed = parseArgs(args);
|
|
3914
3934
|
const id = parsed.command_id || "[no id]";
|
|
3915
3935
|
return /* @__PURE__ */ jsx7(Box7, { children: /* @__PURE__ */ jsxs7(Text7, { color: BLUMA_TERMINAL.muted, children: [
|
|
3916
|
-
"
|
|
3936
|
+
"id ",
|
|
3917
3937
|
id
|
|
3918
3938
|
] }) });
|
|
3919
3939
|
};
|
|
@@ -8519,10 +8539,16 @@ var AdvancedFeedbackSystem = class {
|
|
|
8519
8539
|
score: penalty,
|
|
8520
8540
|
message: "You are attempting a direct message without a tool_call. All replies must contain tool_call.",
|
|
8521
8541
|
correction: `
|
|
8522
|
-
|
|
8523
|
-
|
|
8524
|
-
|
|
8525
|
-
|
|
8542
|
+
## PROTOCOL VIOLATION \u2014 STOP WRITING PLAIN ASSISTANT TEXT
|
|
8543
|
+
|
|
8544
|
+
You streamed or returned **user-visible markdown as assistant content** instead of using the **\`message\` tool**. That is prohibited and **does not end the turn** \u2014 the runtime will loop until timeout.
|
|
8545
|
+
|
|
8546
|
+
Do this **immediately** in your next step (single tool call, no prose outside tools):
|
|
8547
|
+
|
|
8548
|
+
- Call **\`message\`** with **\`message_type\`: \`"result"\`**, put the user-facing summary in **\`content\`**, and put deliverable paths in **\`attachments\`** (absolute paths).
|
|
8549
|
+
|
|
8550
|
+
Do **not** repeat the same summary as plain assistant text again.
|
|
8551
|
+
PENALTY APPLIED: ${penalty.toFixed(1)} points deducted.
|
|
8526
8552
|
`.trim()
|
|
8527
8553
|
};
|
|
8528
8554
|
}
|
|
@@ -9945,6 +9971,7 @@ The \\\`message\\\` tool has TWO types \u2014 use them CORRECTLY:
|
|
|
9945
9971
|
- **Use when**: Task is complete, artifacts ready for delivery
|
|
9946
9972
|
- **Use ONCE per turn** \u2014 only at the very end
|
|
9947
9973
|
- **Ends the turn** \u2014 agent waits for next input
|
|
9974
|
+
- **CRITICAL:** Plain assistant markdown (streaming or not) **does not** end the worker or close the HTTP job \u2014 only a \\\`message\\\` tool call with \\\`message_type: "result"\\\` does. If you only write text in chat, the process loops until **timeout** (e.g. 300s).
|
|
9948
9975
|
|
|
9949
9976
|
#### \u274C WRONG: Using "info" to ask questions
|
|
9950
9977
|
\\\`\\\`\\\`typescript
|
|
@@ -10063,9 +10090,18 @@ You (Bluma):
|
|
|
10063
10090
|
|
|
10064
10091
|
- **Sandbox is safe** - You can't break the host system
|
|
10065
10092
|
- **But workspace matters** - Don't pollute /workspace with junk files
|
|
10093
|
+
- **Deliverables path** - Never use a top-level \`./artifacts/\` folder in the job root; use \`./.bluma/artifacts/\` (or the \`artifacts_dir\` from \`task_boundary\`). Shell redirects must use that path \u2014 \`file_write\` remaps \`artifacts/...\` to \`.bluma/artifacts/...\` automatically.
|
|
10066
10094
|
- **Clean up after yourself** - Remove temporary files when done
|
|
10067
10095
|
- **Respect session boundaries** - Stay in your session workspace
|
|
10068
10096
|
|
|
10097
|
+
### Job wall-clock timeout (orchestrator) \u2014 read this
|
|
10098
|
+
|
|
10099
|
+
The coordinator sets a **single deadline** for the whole stream (e.g. \`timeout_seconds: 60\`). The timer **starts at job start** and counts **everything**: first LLM call (often **30\u201360s+** of \u201CThinking\u201D), tools, follow-up LLM calls, and your final \`message\`+\`result\`.
|
|
10100
|
+
|
|
10101
|
+
- **60 seconds is usually too short** for \`generate_document\` / PDF / multi-step work \u2014 the job can die **after** \`file_write\` succeeds but **before** \`shell_command\` or \`message(result)\`, with \`Job excedeu 60.0s\` / exit \`-9\`. That is **not** proof the sandbox is broken; it means the **budget was too tight**.
|
|
10102
|
+
- Prefer asking coordinators (or docs) to use **\u2265180s** for document generation, **\u2265300s** for heavy tasks.
|
|
10103
|
+
- When a job times out, **do not** claim \u201Csandbox unavailable\u201D unless you have real infra evidence (connection errors, 5xx). Timeout = **deadline exceeded**, often fixable by **raising \`timeout_seconds\`** on the caller side.
|
|
10104
|
+
|
|
10069
10105
|
### You Represent the Platform
|
|
10070
10106
|
|
|
10071
10107
|
- **Severino trusts you** - Don't let him down
|
|
@@ -10288,6 +10324,10 @@ Auto-generated map (may be stale after pull/install). Confirm with tools before
|
|
|
10288
10324
|
<<<BLUMA_WORKSPACE_SNAPSHOT_BODY>>>
|
|
10289
10325
|
</workspace_snapshot>
|
|
10290
10326
|
|
|
10327
|
+
<deliverables>
|
|
10328
|
+
**Local and sandbox:** generated artifacts (reports, PDFs, exports, plans you attach) must live under \`<workdir>/.bluma/\` \u2014 use \`.bluma/artifacts/\` (or the \`artifacts_dir\` path returned by \`task_boundary\` after starting a task). Do **not** create a top-level \`./artifacts/\` folder in the project root. \`file_write\` / \`edit_tool\` / \`read_file_lines\` automatically remap \`artifacts/...\` \u2192 \`.bluma/artifacts/...\`. For \`shell_command\` redirects (\`>\` / \`>>\`), target \`.bluma/artifacts/...\` explicitly.
|
|
10329
|
+
</deliverables>
|
|
10330
|
+
|
|
10291
10331
|
<coding_memory>
|
|
10292
10332
|
Persistent store (~/.bluma/coding_memory.json). Do not invent entries: \`list\` / \`search\` if unsure. \`<coding_memory_snapshot>\` is bootstrap only \u2014 after add/update/remove, list or search again. Operations: add | list | search | update (id) | remove (id), one mutating call at a time.
|
|
10293
10333
|
</coding_memory>
|
|
@@ -10313,7 +10353,7 @@ Output is truncated (~30KB / ~200 lines); use head/tail or write to a file. Use
|
|
|
10313
10353
|
The user **only** sees chat content you send through the \`message\` tool (\`content\` as Markdown). Bare assistant text is **not** a substitute \u2014 **you should use \`message\` liberally**.
|
|
10314
10354
|
|
|
10315
10355
|
**Types**
|
|
10316
|
-
- \`message_type: "result"\` \u2014 **ends the turn**: final answer, deliverable, or a **question** that needs a user reply; then the agent waits for the user.
|
|
10356
|
+
- \`message_type: "result"\` \u2014 **ends the turn**: final answer, deliverable, or a **question** that needs a user reply; then the agent waits for the user. **Sandbox/worker:** only this stops the job; writing markdown as normal assistant output does **not** finish the task and can cause a **timeout loop**.
|
|
10317
10357
|
- \`message_type: "info"\` \u2014 **non-terminal**: shown in chat, does **not** end the turn. **Expected behavior:** call \`info\` **multiple times** in a single turn whenever there is something worth saying (even briefly). Under-using \`info\` is a **mistake** in this product.
|
|
10318
10358
|
|
|
10319
10359
|
**\u26A0\uFE0F CRITICAL: "info" is for INFORMATION ONLY \u2014 NEVER for asking questions**
|
|
@@ -11449,6 +11489,8 @@ var BluMaAgent = class {
|
|
|
11449
11489
|
factorRouterTurnClosed = false;
|
|
11450
11490
|
/** Passos seguidos sem tool_calls nem texto visível (só raciocínio) — evita loop lento no mesmo turno. */
|
|
11451
11491
|
emptyAssistantReplySteps = 0;
|
|
11492
|
+
/** Passos seguidos com texto do assistente sem tool_calls (violação de protocolo) — evita loop até timeout do job. */
|
|
11493
|
+
directTextProtocolSteps = 0;
|
|
11452
11494
|
constructor(sessionId, eventBus, llm, mcpClient, feedbackSystem) {
|
|
11453
11495
|
this.sessionId = sessionId;
|
|
11454
11496
|
this.eventBus = eventBus;
|
|
@@ -11592,6 +11634,7 @@ var BluMaAgent = class {
|
|
|
11592
11634
|
const userContent = buildUserMessageContent(inputText, process.cwd());
|
|
11593
11635
|
this.history.push({ role: "user", content: userContent });
|
|
11594
11636
|
this.emptyAssistantReplySteps = 0;
|
|
11637
|
+
this.directTextProtocolSteps = 0;
|
|
11595
11638
|
this.eventBus.emit(
|
|
11596
11639
|
"backend_message",
|
|
11597
11640
|
buildTurnStartBackendMessage({
|
|
@@ -12149,6 +12192,7 @@ ${editData.error.display}`;
|
|
|
12149
12192
|
this.history.push(normalizedMessage);
|
|
12150
12193
|
if (normalizedMessage.tool_calls && normalizedMessage.tool_calls.length > 0) {
|
|
12151
12194
|
this.emptyAssistantReplySteps = 0;
|
|
12195
|
+
this.directTextProtocolSteps = 0;
|
|
12152
12196
|
const validToolCalls = normalizedMessage.tool_calls.filter(
|
|
12153
12197
|
(call) => ToolCallNormalizer.isValidToolCall(call)
|
|
12154
12198
|
);
|
|
@@ -12188,9 +12232,20 @@ ${editData.error.display}`;
|
|
|
12188
12232
|
}
|
|
12189
12233
|
} else if (trimmedText) {
|
|
12190
12234
|
this.emptyAssistantReplySteps = 0;
|
|
12235
|
+
this.directTextProtocolSteps += 1;
|
|
12236
|
+
const MAX_DIRECT_TEXT_PROTOCOL = 3;
|
|
12191
12237
|
if (!hasEmittedStart) {
|
|
12192
12238
|
this.eventBus.emit("backend_message", { type: "assistant_message", content: accumulatedContent });
|
|
12193
12239
|
}
|
|
12240
|
+
if (this.directTextProtocolSteps >= MAX_DIRECT_TEXT_PROTOCOL) {
|
|
12241
|
+
this.eventBus.emit("backend_message", {
|
|
12242
|
+
type: "error",
|
|
12243
|
+
message: 'Agent kept answering with plain assistant text instead of the `message` tool with message_type "result". Turn forcibly closed to avoid job timeout; fix prompts or model routing.'
|
|
12244
|
+
});
|
|
12245
|
+
await this.notifyFactorTurnEndIfNeeded("protocol_direct_text_exhausted");
|
|
12246
|
+
this.emitTurnCompleted();
|
|
12247
|
+
return;
|
|
12248
|
+
}
|
|
12194
12249
|
const feedback = this.feedbackSystem.generateFeedback({
|
|
12195
12250
|
event: "protocol_violation_direct_text",
|
|
12196
12251
|
details: { violationContent: accumulatedContent }
|
|
@@ -12226,6 +12281,7 @@ ${editData.error.display}`;
|
|
|
12226
12281
|
this.history.push(message2);
|
|
12227
12282
|
if (message2.tool_calls && message2.tool_calls.length > 0) {
|
|
12228
12283
|
this.emptyAssistantReplySteps = 0;
|
|
12284
|
+
this.directTextProtocolSteps = 0;
|
|
12229
12285
|
const validToolCalls = message2.tool_calls.filter(
|
|
12230
12286
|
(call) => ToolCallNormalizer.isValidToolCall(call)
|
|
12231
12287
|
);
|
|
@@ -12265,7 +12321,18 @@ ${editData.error.display}`;
|
|
|
12265
12321
|
}
|
|
12266
12322
|
} else if (typeof message2.content === "string" && message2.content.trim()) {
|
|
12267
12323
|
this.emptyAssistantReplySteps = 0;
|
|
12324
|
+
this.directTextProtocolSteps += 1;
|
|
12325
|
+
const MAX_DIRECT_TEXT_PROTOCOL = 3;
|
|
12268
12326
|
this.eventBus.emit("backend_message", { type: "assistant_message", content: message2.content });
|
|
12327
|
+
if (this.directTextProtocolSteps >= MAX_DIRECT_TEXT_PROTOCOL) {
|
|
12328
|
+
this.eventBus.emit("backend_message", {
|
|
12329
|
+
type: "error",
|
|
12330
|
+
message: 'Agent kept answering with plain assistant text instead of the `message` tool with message_type "result". Turn forcibly closed to avoid job timeout.'
|
|
12331
|
+
});
|
|
12332
|
+
await this.notifyFactorTurnEndIfNeeded("protocol_direct_text_exhausted");
|
|
12333
|
+
this.emitTurnCompleted();
|
|
12334
|
+
return;
|
|
12335
|
+
}
|
|
12269
12336
|
const feedback = this.feedbackSystem.generateFeedback({
|
|
12270
12337
|
event: "protocol_violation_direct_text",
|
|
12271
12338
|
details: { violationContent: message2.content }
|
|
@@ -14182,6 +14249,40 @@ var ToolResultDisplayComponent = ({
|
|
|
14182
14249
|
}
|
|
14183
14250
|
return /* @__PURE__ */ jsx12(ResultGutter, { children: /* @__PURE__ */ jsx12(MarkdownRenderer, { markdown: String(body) }) });
|
|
14184
14251
|
}
|
|
14252
|
+
if (toolName.includes("ask_user_question")) {
|
|
14253
|
+
const success = parsed?.success === true;
|
|
14254
|
+
const selectedLabel = typeof parsed?.selected_label === "string" ? parsed.selected_label : "";
|
|
14255
|
+
const selectedIndex = typeof parsed?.selected_index === "number" ? parsed.selected_index : null;
|
|
14256
|
+
const questionIndex = typeof parsed?.question_index === "number" ? parsed.question_index : 0;
|
|
14257
|
+
const qs = Array.isArray(args?.questions) ? args.questions : [];
|
|
14258
|
+
const q = qs[questionIndex];
|
|
14259
|
+
const questionText = typeof q?.question === "string" ? q.question : "";
|
|
14260
|
+
if (success && selectedLabel) {
|
|
14261
|
+
return /* @__PURE__ */ jsx12(ResultGutter, { children: /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
|
|
14262
|
+
/* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
14263
|
+
/* @__PURE__ */ jsx12(Text12, { bold: true, children: "Response" }),
|
|
14264
|
+
" \xB7 ",
|
|
14265
|
+
selectedLabel
|
|
14266
|
+
] }),
|
|
14267
|
+
questionText ? /* @__PURE__ */ jsxs12(Text12, { dimColor: true, wrap: "wrap", children: [
|
|
14268
|
+
truncate3(questionText, 140),
|
|
14269
|
+
selectedIndex !== null ? ` \xB7 option ${selectedIndex + 1}` : ""
|
|
14270
|
+
] }) : null
|
|
14271
|
+
] }) });
|
|
14272
|
+
}
|
|
14273
|
+
if (parsed?.cancelled === true) {
|
|
14274
|
+
return /* @__PURE__ */ jsx12(ResultGutter, { children: /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
14275
|
+
/* @__PURE__ */ jsx12(Text12, { bold: true, children: "Response" }),
|
|
14276
|
+
" \xB7 cancelled by user"
|
|
14277
|
+
] }) });
|
|
14278
|
+
}
|
|
14279
|
+
const err = typeof parsed?.error === "string" ? parsed.error : "";
|
|
14280
|
+
return /* @__PURE__ */ jsx12(ResultGutter, { children: /* @__PURE__ */ jsxs12(Text12, { color: err ? BLUMA_TERMINAL.err : void 0, dimColor: !err, wrap: "wrap", children: [
|
|
14281
|
+
/* @__PURE__ */ jsx12(Text12, { bold: true, children: "Response" }),
|
|
14282
|
+
" \xB7 ",
|
|
14283
|
+
err || "No answer returned"
|
|
14284
|
+
] }) });
|
|
14285
|
+
}
|
|
14185
14286
|
if (toolName.includes("file_write") && parsed) {
|
|
14186
14287
|
return /* @__PURE__ */ jsx12(ResultGutter, { children: /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
14187
14288
|
parsed.created ? "Created " : "Wrote to ",
|
|
@@ -15990,6 +16091,9 @@ Run: npm i -g ${BLUMA_PACKAGE_NAME} to update.`;
|
|
|
15990
16091
|
}
|
|
15991
16092
|
}
|
|
15992
16093
|
|
|
16094
|
+
// src/app/ui/App.tsx
|
|
16095
|
+
init_sandbox_policy();
|
|
16096
|
+
|
|
15993
16097
|
// src/app/ui/components/UpdateNotice.tsx
|
|
15994
16098
|
import { Box as Box17, Text as Text16 } from "ink";
|
|
15995
16099
|
import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
@@ -16640,7 +16744,7 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
|
16640
16744
|
const [liveToolArgs, setLiveToolArgs] = useState11(void 0);
|
|
16641
16745
|
const [isReasoning, setIsReasoning] = useState11(false);
|
|
16642
16746
|
const alwaysAcceptList = useRef6([]);
|
|
16643
|
-
const workdir =
|
|
16747
|
+
const workdir = getSandboxPolicy().workspaceRoot;
|
|
16644
16748
|
const turnStartedAtRef = useRef6(null);
|
|
16645
16749
|
const [processingStartMs, setProcessingStartMs] = useState11(null);
|
|
16646
16750
|
const markTurnStarted = useCallback4(() => {
|