@aiaiai-pt/martha-cli 0.25.0 → 0.26.0
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/index.js +60 -15
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2158,6 +2158,8 @@ function extractDetail(body) {
|
|
|
2158
2158
|
const nested = obj.detail;
|
|
2159
2159
|
if (typeof nested.message === "string")
|
|
2160
2160
|
return nested.message;
|
|
2161
|
+
if (typeof nested.code === "string")
|
|
2162
|
+
return nested.code;
|
|
2161
2163
|
if (nested.code === "mcp_oauth_authorization_required" && typeof nested.authorization_url === "string") {
|
|
2162
2164
|
return "MCP OAuth authorization required";
|
|
2163
2165
|
}
|
|
@@ -11073,12 +11075,13 @@ ${items.length} ${config.typeNamePlural}`));
|
|
|
11073
11075
|
}
|
|
11074
11076
|
|
|
11075
11077
|
// src/commands/chat.ts
|
|
11078
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
11076
11079
|
import { createInterface as createInterface2 } from "node:readline";
|
|
11077
11080
|
init_config();
|
|
11078
11081
|
init_errors();
|
|
11079
11082
|
|
|
11080
11083
|
// src/version.ts
|
|
11081
|
-
var CLI_VERSION = "0.
|
|
11084
|
+
var CLI_VERSION = "0.26.0";
|
|
11082
11085
|
|
|
11083
11086
|
// src/commands/sessions.ts
|
|
11084
11087
|
function relativeTime(iso) {
|
|
@@ -11352,6 +11355,7 @@ function createApprovalTagStripper() {
|
|
|
11352
11355
|
|
|
11353
11356
|
// src/lib/local-exec.ts
|
|
11354
11357
|
import { spawn } from "node:child_process";
|
|
11358
|
+
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
11355
11359
|
import { closeSync, openSync, promises as fs5 } from "node:fs";
|
|
11356
11360
|
import * as path4 from "node:path";
|
|
11357
11361
|
var DEFAULT_TIMEOUT_MS = 20000;
|
|
@@ -11432,6 +11436,9 @@ async function runHostCommand(command, toolCallId, opts) {
|
|
|
11432
11436
|
function safeName(s) {
|
|
11433
11437
|
return s.replace(/[^a-zA-Z0-9_.-]/g, "_").slice(0, 120) || "task";
|
|
11434
11438
|
}
|
|
11439
|
+
function mintExecSecret() {
|
|
11440
|
+
return randomBytes2(32).toString("hex");
|
|
11441
|
+
}
|
|
11435
11442
|
|
|
11436
11443
|
class Journal {
|
|
11437
11444
|
cwd;
|
|
@@ -11443,9 +11450,13 @@ class Journal {
|
|
|
11443
11450
|
}
|
|
11444
11451
|
async load() {
|
|
11445
11452
|
try {
|
|
11446
|
-
|
|
11453
|
+
const raw = JSON.parse(await fs5.readFile(this.file(), "utf8"));
|
|
11454
|
+
if (raw["entries"] !== undefined) {
|
|
11455
|
+
return raw;
|
|
11456
|
+
}
|
|
11457
|
+
return { entries: raw, secrets: {} };
|
|
11447
11458
|
} catch {
|
|
11448
|
-
return {};
|
|
11459
|
+
return { entries: {}, secrets: {} };
|
|
11449
11460
|
}
|
|
11450
11461
|
}
|
|
11451
11462
|
async save(data) {
|
|
@@ -11456,11 +11467,11 @@ class Journal {
|
|
|
11456
11467
|
return `${sessionId}:${toolCallId}`;
|
|
11457
11468
|
}
|
|
11458
11469
|
async lookup(sessionId, toolCallId) {
|
|
11459
|
-
return (await this.load())[Journal.key(sessionId, toolCallId)];
|
|
11470
|
+
return (await this.load()).entries[Journal.key(sessionId, toolCallId)];
|
|
11460
11471
|
}
|
|
11461
11472
|
async recordRunning(sessionId, toolCallId, command, now) {
|
|
11462
11473
|
const data = await this.load();
|
|
11463
|
-
data[Journal.key(sessionId, toolCallId)] = {
|
|
11474
|
+
data.entries[Journal.key(sessionId, toolCallId)] = {
|
|
11464
11475
|
state: "running",
|
|
11465
11476
|
command,
|
|
11466
11477
|
started_at: now
|
|
@@ -11470,8 +11481,8 @@ class Journal {
|
|
|
11470
11481
|
async recordDone(sessionId, toolCallId, result) {
|
|
11471
11482
|
const data = await this.load();
|
|
11472
11483
|
const k = Journal.key(sessionId, toolCallId);
|
|
11473
|
-
const prev = data[k];
|
|
11474
|
-
data[k] = {
|
|
11484
|
+
const prev = data.entries[k];
|
|
11485
|
+
data.entries[k] = {
|
|
11475
11486
|
state: "done",
|
|
11476
11487
|
command: prev?.command ?? "",
|
|
11477
11488
|
started_at: prev?.started_at ?? "",
|
|
@@ -11479,6 +11490,14 @@ class Journal {
|
|
|
11479
11490
|
};
|
|
11480
11491
|
await this.save(data);
|
|
11481
11492
|
}
|
|
11493
|
+
async recordSecret(sessionId, toolCallId, secret) {
|
|
11494
|
+
const data = await this.load();
|
|
11495
|
+
data.secrets[Journal.key(sessionId, toolCallId)] = secret;
|
|
11496
|
+
await this.save(data);
|
|
11497
|
+
}
|
|
11498
|
+
async lookupSecret(sessionId, toolCallId) {
|
|
11499
|
+
return (await this.load()).secrets[Journal.key(sessionId, toolCallId)];
|
|
11500
|
+
}
|
|
11482
11501
|
}
|
|
11483
11502
|
function decideFromJournal(entry) {
|
|
11484
11503
|
if (!entry)
|
|
@@ -12104,9 +12123,28 @@ async function resolveLocalAgent(sessionId, toolCallId, req, state) {
|
|
|
12104
12123
|
log_path: result.log_path
|
|
12105
12124
|
};
|
|
12106
12125
|
}
|
|
12107
|
-
async function
|
|
12126
|
+
async function claimGate(ctx, sessionId, toolCallId, state) {
|
|
12127
|
+
if (state.claimed.has(toolCallId))
|
|
12128
|
+
return;
|
|
12129
|
+
const secret = state.secrets.get(toolCallId) ?? mintExecSecret();
|
|
12130
|
+
const secretHash = createHash2("sha256").update(secret).digest("hex");
|
|
12131
|
+
state.secrets.set(toolCallId, secret);
|
|
12132
|
+
await state.journal.recordSecret(sessionId, toolCallId, secret);
|
|
12108
12133
|
try {
|
|
12109
|
-
await ctx.api.post(`/api/chat/${encodeURIComponent(sessionId)}/tool-
|
|
12134
|
+
await ctx.api.post(`/api/chat/${encodeURIComponent(sessionId)}/tool-claim`, { tool_call_id: toolCallId, secret_hash: secretHash });
|
|
12135
|
+
state.claimed.add(toolCallId);
|
|
12136
|
+
} catch (e) {
|
|
12137
|
+
process.stderr.write(source_default.yellow(`[local-exec] failed to claim gate for ${toolCallId}: ${String(e)}
|
|
12138
|
+
`));
|
|
12139
|
+
}
|
|
12140
|
+
}
|
|
12141
|
+
async function _postToolResult(ctx, sessionId, toolCallId, result, label, execSecret) {
|
|
12142
|
+
try {
|
|
12143
|
+
await ctx.api.post(`/api/chat/${encodeURIComponent(sessionId)}/tool-result`, {
|
|
12144
|
+
tool_call_id: toolCallId,
|
|
12145
|
+
result,
|
|
12146
|
+
...execSecret !== undefined ? { exec_secret: execSecret } : {}
|
|
12147
|
+
});
|
|
12110
12148
|
} catch (e) {
|
|
12111
12149
|
process.stderr.write(source_default.red(`[${label}] failed to POST result: ${String(e)}
|
|
12112
12150
|
`));
|
|
@@ -12118,40 +12156,45 @@ async function handleHostExecFrame(ctx, sessionId, data, state) {
|
|
|
12118
12156
|
if (state.handled.has(id))
|
|
12119
12157
|
continue;
|
|
12120
12158
|
state.handled.add(id);
|
|
12159
|
+
await claimGate(ctx, sessionId, id, state);
|
|
12121
12160
|
const result = await resolveHostExec(sessionId, id, req.command, state);
|
|
12122
|
-
await _postToolResult(ctx, sessionId, id, result, "host_exec");
|
|
12161
|
+
await _postToolResult(ctx, sessionId, id, result, "host_exec", state.secrets.get(id));
|
|
12123
12162
|
}
|
|
12124
12163
|
for (const req of parseHostScreenshotRequests(data)) {
|
|
12125
12164
|
const id = req.toolCallId;
|
|
12126
12165
|
if (state.handled.has(id))
|
|
12127
12166
|
continue;
|
|
12128
12167
|
state.handled.add(id);
|
|
12168
|
+
await claimGate(ctx, sessionId, id, state);
|
|
12129
12169
|
const result = await resolveHostScreenshot(ctx, sessionId, req, state);
|
|
12130
|
-
await _postToolResult(ctx, sessionId, id, result, "host_screenshot");
|
|
12170
|
+
await _postToolResult(ctx, sessionId, id, result, "host_screenshot", state.secrets.get(id));
|
|
12131
12171
|
}
|
|
12132
12172
|
for (const req of parseHostBrowserRequests(data)) {
|
|
12133
12173
|
const id = req.toolCallId;
|
|
12134
12174
|
if (state.handled.has(id))
|
|
12135
12175
|
continue;
|
|
12136
12176
|
state.handled.add(id);
|
|
12177
|
+
await claimGate(ctx, sessionId, id, state);
|
|
12137
12178
|
const result = await resolveHostBrowser(ctx, sessionId, req, state);
|
|
12138
|
-
await _postToolResult(ctx, sessionId, id, result, "host_browser");
|
|
12179
|
+
await _postToolResult(ctx, sessionId, id, result, "host_browser", state.secrets.get(id));
|
|
12139
12180
|
}
|
|
12140
12181
|
for (const req of parseHostFileRequests(data)) {
|
|
12141
12182
|
const id = req.toolCallId;
|
|
12142
12183
|
if (state.handled.has(id))
|
|
12143
12184
|
continue;
|
|
12144
12185
|
state.handled.add(id);
|
|
12186
|
+
await claimGate(ctx, sessionId, id, state);
|
|
12145
12187
|
const result = await resolveHostFile(req, state);
|
|
12146
|
-
await _postToolResult(ctx, sessionId, id, result, req.action);
|
|
12188
|
+
await _postToolResult(ctx, sessionId, id, result, req.action, state.secrets.get(id));
|
|
12147
12189
|
}
|
|
12148
12190
|
for (const req of parseLocalAgentRequests(data)) {
|
|
12149
12191
|
const id = req.toolCallId;
|
|
12150
12192
|
if (state.handled.has(id))
|
|
12151
12193
|
continue;
|
|
12152
12194
|
state.handled.add(id);
|
|
12195
|
+
await claimGate(ctx, sessionId, id, state);
|
|
12153
12196
|
const result = await resolveLocalAgent(sessionId, id, req, state);
|
|
12154
|
-
await _postToolResult(ctx, sessionId, id, result, "local_agent");
|
|
12197
|
+
await _postToolResult(ctx, sessionId, id, result, "local_agent", state.secrets.get(id));
|
|
12155
12198
|
}
|
|
12156
12199
|
}
|
|
12157
12200
|
function parseSlashCommand(input) {
|
|
@@ -12209,7 +12252,9 @@ async function sendMessage(ctx, sessionId, message, opts = {}) {
|
|
|
12209
12252
|
autoYes: opts.localExec.autoYes,
|
|
12210
12253
|
localAgent: opts.localExec.agent,
|
|
12211
12254
|
handled: new Set,
|
|
12212
|
-
journal: new Journal(opts.localExec.cwd)
|
|
12255
|
+
journal: new Journal(opts.localExec.cwd),
|
|
12256
|
+
secrets: new Map,
|
|
12257
|
+
claimed: new Set
|
|
12213
12258
|
} : null;
|
|
12214
12259
|
const reqBody = { content: message };
|
|
12215
12260
|
if (opts.localExec)
|