@aiaiai-pt/martha-cli 0.22.0 → 0.24.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 +745 -94
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11077,7 +11077,7 @@ import { createInterface as createInterface2 } from "node:readline";
|
|
|
11077
11077
|
init_errors();
|
|
11078
11078
|
|
|
11079
11079
|
// src/version.ts
|
|
11080
|
-
var CLI_VERSION = "0.
|
|
11080
|
+
var CLI_VERSION = "0.24.0";
|
|
11081
11081
|
|
|
11082
11082
|
// src/commands/sessions.ts
|
|
11083
11083
|
function relativeTime(iso) {
|
|
@@ -11538,7 +11538,387 @@ function parseHostScreenshotRequests(data) {
|
|
|
11538
11538
|
return out;
|
|
11539
11539
|
}
|
|
11540
11540
|
|
|
11541
|
+
// src/lib/host-browser.ts
|
|
11542
|
+
var DOM_CAP = 16 * 1024;
|
|
11543
|
+
var CONSOLE_CAP = 200;
|
|
11544
|
+
function parseHostBrowserRequests(data) {
|
|
11545
|
+
let tools;
|
|
11546
|
+
try {
|
|
11547
|
+
tools = JSON.parse(data);
|
|
11548
|
+
} catch {
|
|
11549
|
+
return [];
|
|
11550
|
+
}
|
|
11551
|
+
if (!Array.isArray(tools))
|
|
11552
|
+
return [];
|
|
11553
|
+
const valid = [
|
|
11554
|
+
"navigate",
|
|
11555
|
+
"click",
|
|
11556
|
+
"read_console",
|
|
11557
|
+
"read_dom",
|
|
11558
|
+
"screenshot"
|
|
11559
|
+
];
|
|
11560
|
+
const out = [];
|
|
11561
|
+
for (const t of tools) {
|
|
11562
|
+
if (t.tool_name !== "host_browser" || t.status !== "awaiting_input")
|
|
11563
|
+
continue;
|
|
11564
|
+
if (!t.tool_call_id)
|
|
11565
|
+
continue;
|
|
11566
|
+
const action = t.args?.action;
|
|
11567
|
+
if (!action || !valid.includes(action))
|
|
11568
|
+
continue;
|
|
11569
|
+
out.push({
|
|
11570
|
+
toolCallId: t.tool_call_id,
|
|
11571
|
+
action,
|
|
11572
|
+
url: t.args?.url,
|
|
11573
|
+
selector: t.args?.selector,
|
|
11574
|
+
waitMs: typeof t.args?.wait_ms === "number" ? t.args.wait_ms : 500,
|
|
11575
|
+
fullPage: t.args?.full_page !== false
|
|
11576
|
+
});
|
|
11577
|
+
}
|
|
11578
|
+
return out;
|
|
11579
|
+
}
|
|
11580
|
+
async function applyBrowserAction(page, consoleBuffer, req) {
|
|
11581
|
+
try {
|
|
11582
|
+
switch (req.action) {
|
|
11583
|
+
case "navigate": {
|
|
11584
|
+
if (!req.url)
|
|
11585
|
+
return { error: true, message: "navigate requires `url`" };
|
|
11586
|
+
await page.goto(req.url, { waitUntil: "load", timeout: 30000 });
|
|
11587
|
+
if (req.waitMs > 0)
|
|
11588
|
+
await page.waitForTimeout(req.waitMs);
|
|
11589
|
+
const title = await page.title();
|
|
11590
|
+
const url = page.url();
|
|
11591
|
+
return { text: `Navigated to ${url} (title: ${title || "<none>"}).` };
|
|
11592
|
+
}
|
|
11593
|
+
case "click": {
|
|
11594
|
+
if (!req.selector)
|
|
11595
|
+
return { error: true, message: "click requires `selector`" };
|
|
11596
|
+
await page.click(req.selector, { timeout: 1e4 });
|
|
11597
|
+
if (req.waitMs > 0)
|
|
11598
|
+
await page.waitForTimeout(req.waitMs);
|
|
11599
|
+
return { text: `Clicked ${req.selector}.` };
|
|
11600
|
+
}
|
|
11601
|
+
case "read_console": {
|
|
11602
|
+
if (req.waitMs > 0)
|
|
11603
|
+
await page.waitForTimeout(req.waitMs);
|
|
11604
|
+
const entries = consoleBuffer.slice(-CONSOLE_CAP);
|
|
11605
|
+
if (entries.length === 0)
|
|
11606
|
+
return {
|
|
11607
|
+
text: "No console messages, page errors, or failed requests captured yet."
|
|
11608
|
+
};
|
|
11609
|
+
const lines = entries.map((e) => {
|
|
11610
|
+
if (e.kind === "console")
|
|
11611
|
+
return `[console.${e.level}] ${e.text}`;
|
|
11612
|
+
if (e.kind === "pageerror")
|
|
11613
|
+
return `[pageerror] ${e.text}`;
|
|
11614
|
+
return `[requestfailed] ${e.url} — ${e.text}`;
|
|
11615
|
+
});
|
|
11616
|
+
return {
|
|
11617
|
+
text: `Captured ${entries.length} console/error/network entries:
|
|
11618
|
+
${lines.join(`
|
|
11619
|
+
`)}`
|
|
11620
|
+
};
|
|
11621
|
+
}
|
|
11622
|
+
case "read_dom": {
|
|
11623
|
+
if (req.waitMs > 0)
|
|
11624
|
+
await page.waitForTimeout(req.waitMs);
|
|
11625
|
+
let html;
|
|
11626
|
+
if (req.selector) {
|
|
11627
|
+
html = await page.evaluate((sel) => {
|
|
11628
|
+
const el = document.querySelector(sel);
|
|
11629
|
+
return el ? el.outerHTML : `__NOT_FOUND__:${sel}`;
|
|
11630
|
+
}, req.selector);
|
|
11631
|
+
if (typeof html === "string" && html.startsWith("__NOT_FOUND__:"))
|
|
11632
|
+
return {
|
|
11633
|
+
error: true,
|
|
11634
|
+
message: `No element matched selector: ${req.selector}`
|
|
11635
|
+
};
|
|
11636
|
+
} else {
|
|
11637
|
+
html = await page.content();
|
|
11638
|
+
}
|
|
11639
|
+
const truncated = html.length > DOM_CAP;
|
|
11640
|
+
return {
|
|
11641
|
+
text: (truncated ? html.slice(0, DOM_CAP) + `
|
|
11642
|
+
…[truncated]` : html) || ""
|
|
11643
|
+
};
|
|
11644
|
+
}
|
|
11645
|
+
case "screenshot": {
|
|
11646
|
+
if (req.waitMs > 0)
|
|
11647
|
+
await page.waitForTimeout(req.waitMs);
|
|
11648
|
+
const buf = await page.screenshot({
|
|
11649
|
+
fullPage: req.fullPage,
|
|
11650
|
+
type: "png"
|
|
11651
|
+
});
|
|
11652
|
+
return { png: buf };
|
|
11653
|
+
}
|
|
11654
|
+
default:
|
|
11655
|
+
return { error: true, message: `unknown action: ${req.action}` };
|
|
11656
|
+
}
|
|
11657
|
+
} catch (e) {
|
|
11658
|
+
return { error: true, message: `${req.action} failed: ${String(e)}` };
|
|
11659
|
+
}
|
|
11660
|
+
}
|
|
11661
|
+
|
|
11662
|
+
class BrowserSession {
|
|
11663
|
+
browser = null;
|
|
11664
|
+
page = null;
|
|
11665
|
+
consoleBuffer = [];
|
|
11666
|
+
async ensurePage() {
|
|
11667
|
+
if (this.page)
|
|
11668
|
+
return this.page;
|
|
11669
|
+
const moduleName = "playwright";
|
|
11670
|
+
let chromium;
|
|
11671
|
+
try {
|
|
11672
|
+
({ chromium } = await import(moduleName));
|
|
11673
|
+
} catch {
|
|
11674
|
+
throw new Error("playwright is not installed on the runner. Install it to use host_browser: `npm i -D playwright && npx playwright install chromium`");
|
|
11675
|
+
}
|
|
11676
|
+
this.browser = await chromium.launch({ headless: true });
|
|
11677
|
+
this.page = await this.browser.newPage();
|
|
11678
|
+
this.page.on("console", (msg) => this.consoleBuffer.push({
|
|
11679
|
+
kind: "console",
|
|
11680
|
+
level: msg.type(),
|
|
11681
|
+
text: msg.text()
|
|
11682
|
+
}));
|
|
11683
|
+
this.page.on("pageerror", (err) => this.consoleBuffer.push({
|
|
11684
|
+
kind: "pageerror",
|
|
11685
|
+
text: String(err?.message ?? err)
|
|
11686
|
+
}));
|
|
11687
|
+
this.page.on("requestfailed", (request) => this.consoleBuffer.push({
|
|
11688
|
+
kind: "requestfailed",
|
|
11689
|
+
url: request.url(),
|
|
11690
|
+
text: request.failure()?.errorText ?? "failed"
|
|
11691
|
+
}));
|
|
11692
|
+
return this.page;
|
|
11693
|
+
}
|
|
11694
|
+
async run(req) {
|
|
11695
|
+
let page;
|
|
11696
|
+
try {
|
|
11697
|
+
page = await this.ensurePage();
|
|
11698
|
+
} catch (e) {
|
|
11699
|
+
return { error: true, message: String(e) };
|
|
11700
|
+
}
|
|
11701
|
+
return applyBrowserAction(page, this.consoleBuffer, req);
|
|
11702
|
+
}
|
|
11703
|
+
async close() {
|
|
11704
|
+
if (this.browser) {
|
|
11705
|
+
try {
|
|
11706
|
+
await this.browser.close();
|
|
11707
|
+
} catch {}
|
|
11708
|
+
this.browser = null;
|
|
11709
|
+
this.page = null;
|
|
11710
|
+
}
|
|
11711
|
+
}
|
|
11712
|
+
}
|
|
11713
|
+
|
|
11714
|
+
// src/lib/host-files.ts
|
|
11715
|
+
import { promises as fs6 } from "node:fs";
|
|
11716
|
+
import * as path5 from "node:path";
|
|
11717
|
+
var READ_CAP = 256 * 1024;
|
|
11718
|
+
function resolvePath(cwd, p) {
|
|
11719
|
+
return path5.isAbsolute(p) ? p : path5.resolve(cwd, p);
|
|
11720
|
+
}
|
|
11721
|
+
async function applyFileAction(cwd, req) {
|
|
11722
|
+
if (!req.path)
|
|
11723
|
+
return { error: true, message: `${req.action} requires \`path\`` };
|
|
11724
|
+
const abs = resolvePath(cwd, req.path);
|
|
11725
|
+
try {
|
|
11726
|
+
switch (req.action) {
|
|
11727
|
+
case "host_read": {
|
|
11728
|
+
const raw = await fs6.readFile(abs, "utf8");
|
|
11729
|
+
let body = raw;
|
|
11730
|
+
if (typeof req.offset === "number" || typeof req.limit === "number") {
|
|
11731
|
+
const lines = raw.split(`
|
|
11732
|
+
`);
|
|
11733
|
+
const start = Math.max(0, (req.offset ?? 1) - 1);
|
|
11734
|
+
const end = typeof req.limit === "number" ? start + req.limit : lines.length;
|
|
11735
|
+
body = lines.slice(start, end).join(`
|
|
11736
|
+
`);
|
|
11737
|
+
}
|
|
11738
|
+
const truncated = body.length > READ_CAP;
|
|
11739
|
+
if (truncated)
|
|
11740
|
+
body = body.slice(0, READ_CAP) + `
|
|
11741
|
+
…[truncated]`;
|
|
11742
|
+
return { text: body === "" ? "(empty file)" : body };
|
|
11743
|
+
}
|
|
11744
|
+
case "host_write": {
|
|
11745
|
+
if (typeof req.content !== "string")
|
|
11746
|
+
return { error: true, message: "host_write requires `content`" };
|
|
11747
|
+
await fs6.mkdir(path5.dirname(abs), { recursive: true });
|
|
11748
|
+
await fs6.writeFile(abs, req.content, "utf8");
|
|
11749
|
+
return {
|
|
11750
|
+
text: `Wrote ${Buffer.byteLength(req.content, "utf8")} bytes to ${req.path}.`
|
|
11751
|
+
};
|
|
11752
|
+
}
|
|
11753
|
+
case "host_edit": {
|
|
11754
|
+
if (typeof req.oldString !== "string" || typeof req.newString !== "string")
|
|
11755
|
+
return {
|
|
11756
|
+
error: true,
|
|
11757
|
+
message: "host_edit requires `old_string` and `new_string`"
|
|
11758
|
+
};
|
|
11759
|
+
if (req.oldString === req.newString)
|
|
11760
|
+
return {
|
|
11761
|
+
error: true,
|
|
11762
|
+
message: "old_string and new_string are identical"
|
|
11763
|
+
};
|
|
11764
|
+
const raw = await fs6.readFile(abs, "utf8");
|
|
11765
|
+
const count = req.oldString ? raw.split(req.oldString).length - 1 : 0;
|
|
11766
|
+
if (count === 0)
|
|
11767
|
+
return { error: true, message: "old_string not found in file" };
|
|
11768
|
+
if (count > 1 && !req.replaceAll)
|
|
11769
|
+
return {
|
|
11770
|
+
error: true,
|
|
11771
|
+
message: `old_string is not unique (${count} matches); pass replace_all=true to replace all`
|
|
11772
|
+
};
|
|
11773
|
+
const next = req.replaceAll ? raw.split(req.oldString).join(req.newString) : raw.replace(req.oldString, req.newString);
|
|
11774
|
+
await fs6.writeFile(abs, next, "utf8");
|
|
11775
|
+
return {
|
|
11776
|
+
text: `Edited ${req.path} (${req.replaceAll ? count : 1} replacement${(req.replaceAll ? count : 1) === 1 ? "" : "s"}).`
|
|
11777
|
+
};
|
|
11778
|
+
}
|
|
11779
|
+
default:
|
|
11780
|
+
return { error: true, message: `unknown file action: ${req.action}` };
|
|
11781
|
+
}
|
|
11782
|
+
} catch (e) {
|
|
11783
|
+
return { error: true, message: `${req.action} failed: ${String(e)}` };
|
|
11784
|
+
}
|
|
11785
|
+
}
|
|
11786
|
+
var VALID = ["host_read", "host_write", "host_edit"];
|
|
11787
|
+
function parseHostFileRequests(data) {
|
|
11788
|
+
let tools;
|
|
11789
|
+
try {
|
|
11790
|
+
tools = JSON.parse(data);
|
|
11791
|
+
} catch {
|
|
11792
|
+
return [];
|
|
11793
|
+
}
|
|
11794
|
+
if (!Array.isArray(tools))
|
|
11795
|
+
return [];
|
|
11796
|
+
const out = [];
|
|
11797
|
+
for (const t of tools) {
|
|
11798
|
+
if (t.status !== "awaiting_input" || !t.tool_call_id)
|
|
11799
|
+
continue;
|
|
11800
|
+
if (!VALID.includes(t.tool_name))
|
|
11801
|
+
continue;
|
|
11802
|
+
const a = t.args ?? {};
|
|
11803
|
+
out.push({
|
|
11804
|
+
toolCallId: t.tool_call_id,
|
|
11805
|
+
action: t.tool_name,
|
|
11806
|
+
path: a.path,
|
|
11807
|
+
offset: typeof a.offset === "number" ? a.offset : undefined,
|
|
11808
|
+
limit: typeof a.limit === "number" ? a.limit : undefined,
|
|
11809
|
+
content: typeof a.content === "string" ? a.content : undefined,
|
|
11810
|
+
oldString: typeof a.old_string === "string" ? a.old_string : undefined,
|
|
11811
|
+
newString: typeof a.new_string === "string" ? a.new_string : undefined,
|
|
11812
|
+
replaceAll: a.replace_all === true
|
|
11813
|
+
});
|
|
11814
|
+
}
|
|
11815
|
+
return out;
|
|
11816
|
+
}
|
|
11817
|
+
|
|
11818
|
+
// src/lib/local-agent.ts
|
|
11819
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
11820
|
+
var DEFAULT_LOCAL_AGENT_CMD = "codex exec";
|
|
11821
|
+
var DEFAULT_LOCAL_AGENT_TIMEOUT_MS = 30 * 60 * 1000;
|
|
11822
|
+
var MAX_OUTPUT2 = 256 * 1024;
|
|
11823
|
+
function buildAgentArgv(agentCmd, task) {
|
|
11824
|
+
const parts = agentCmd.trim().split(/\s+/).filter(Boolean);
|
|
11825
|
+
if (parts.length === 0)
|
|
11826
|
+
throw new Error("MARTHA_LOCAL_AGENT_CMD is empty");
|
|
11827
|
+
return [...parts, task];
|
|
11828
|
+
}
|
|
11829
|
+
async function runLocalAgent(task, opts) {
|
|
11830
|
+
const argv = buildAgentArgv(opts.agentCmd, task);
|
|
11831
|
+
const cap = opts.maxOutputBytes ?? MAX_OUTPUT2;
|
|
11832
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_LOCAL_AGENT_TIMEOUT_MS;
|
|
11833
|
+
return await new Promise((resolve2, reject) => {
|
|
11834
|
+
let out = "";
|
|
11835
|
+
let settled = false;
|
|
11836
|
+
let child;
|
|
11837
|
+
try {
|
|
11838
|
+
child = spawn2(argv[0], argv.slice(1), {
|
|
11839
|
+
cwd: opts.cwd,
|
|
11840
|
+
shell: false,
|
|
11841
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
11842
|
+
});
|
|
11843
|
+
} catch (e) {
|
|
11844
|
+
reject(e);
|
|
11845
|
+
return;
|
|
11846
|
+
}
|
|
11847
|
+
const append = (chunk) => {
|
|
11848
|
+
if (out.length < cap)
|
|
11849
|
+
out += chunk.toString("utf8");
|
|
11850
|
+
};
|
|
11851
|
+
child.stdout?.on("data", append);
|
|
11852
|
+
child.stderr?.on("data", append);
|
|
11853
|
+
const timer = setTimeout(() => {
|
|
11854
|
+
if (settled)
|
|
11855
|
+
return;
|
|
11856
|
+
settled = true;
|
|
11857
|
+
child.kill("SIGKILL");
|
|
11858
|
+
resolve2({
|
|
11859
|
+
text: out.slice(0, cap),
|
|
11860
|
+
exit_code: -1,
|
|
11861
|
+
timed_out: true
|
|
11862
|
+
});
|
|
11863
|
+
}, timeoutMs);
|
|
11864
|
+
child.on("error", (e) => {
|
|
11865
|
+
if (settled)
|
|
11866
|
+
return;
|
|
11867
|
+
settled = true;
|
|
11868
|
+
clearTimeout(timer);
|
|
11869
|
+
reject(e);
|
|
11870
|
+
});
|
|
11871
|
+
child.on("close", (code) => {
|
|
11872
|
+
if (settled)
|
|
11873
|
+
return;
|
|
11874
|
+
settled = true;
|
|
11875
|
+
clearTimeout(timer);
|
|
11876
|
+
resolve2({ text: out.slice(0, cap), exit_code: code ?? -1 });
|
|
11877
|
+
});
|
|
11878
|
+
});
|
|
11879
|
+
}
|
|
11880
|
+
function parseLocalAgentRequests(data) {
|
|
11881
|
+
let tools;
|
|
11882
|
+
try {
|
|
11883
|
+
tools = JSON.parse(data);
|
|
11884
|
+
} catch {
|
|
11885
|
+
return [];
|
|
11886
|
+
}
|
|
11887
|
+
if (!Array.isArray(tools))
|
|
11888
|
+
return [];
|
|
11889
|
+
const out = [];
|
|
11890
|
+
for (const t of tools) {
|
|
11891
|
+
if (t.tool_name !== "local_agent" || t.status !== "awaiting_input")
|
|
11892
|
+
continue;
|
|
11893
|
+
if (!t.tool_call_id || !t.args?.task)
|
|
11894
|
+
continue;
|
|
11895
|
+
out.push({
|
|
11896
|
+
toolCallId: t.tool_call_id,
|
|
11897
|
+
task: t.args.task,
|
|
11898
|
+
cwd: typeof t.args.cwd === "string" ? t.args.cwd : undefined
|
|
11899
|
+
});
|
|
11900
|
+
}
|
|
11901
|
+
return out;
|
|
11902
|
+
}
|
|
11903
|
+
|
|
11541
11904
|
// src/commands/chat.ts
|
|
11905
|
+
async function uploadImageArtifact(ctx, sessionId, png) {
|
|
11906
|
+
try {
|
|
11907
|
+
const mint = await ctx.api.post(`/api/chat/${encodeURIComponent(sessionId)}/local-artifact-upload`, {
|
|
11908
|
+
content_type: "image/png"
|
|
11909
|
+
});
|
|
11910
|
+
const put = await fetch(mint.upload_url, {
|
|
11911
|
+
method: "PUT",
|
|
11912
|
+
headers: { "Content-Type": "image/png" },
|
|
11913
|
+
body: new Uint8Array(png)
|
|
11914
|
+
});
|
|
11915
|
+
if (!put.ok)
|
|
11916
|
+
return { error: `image upload failed: HTTP ${put.status}` };
|
|
11917
|
+
return { storage_key: mint.storage_key };
|
|
11918
|
+
} catch (e) {
|
|
11919
|
+
return { error: `image upload failed: ${String(e)}` };
|
|
11920
|
+
}
|
|
11921
|
+
}
|
|
11542
11922
|
async function resolveHostExec(sessionId, toolCallId, command, state) {
|
|
11543
11923
|
const decision = decideFromJournal(await state.journal.lookup(sessionId, toolCallId));
|
|
11544
11924
|
if (decision.kind === "replay")
|
|
@@ -11596,27 +11976,89 @@ async function resolveHostScreenshot(ctx, sessionId, req, state) {
|
|
|
11596
11976
|
} catch (e) {
|
|
11597
11977
|
return { error: true, message: `screenshot failed: ${String(e)}` };
|
|
11598
11978
|
}
|
|
11979
|
+
const uploaded = await uploadImageArtifact(ctx, sessionId, png);
|
|
11980
|
+
if ("error" in uploaded)
|
|
11981
|
+
return { error: true, message: uploaded.error };
|
|
11982
|
+
return {
|
|
11983
|
+
text: `Screenshot of ${req.url} captured (${png.length} bytes).`,
|
|
11984
|
+
_images: [{ storage_key: uploaded.storage_key }]
|
|
11985
|
+
};
|
|
11986
|
+
}
|
|
11987
|
+
async function resolveHostBrowser(ctx, sessionId, req, state) {
|
|
11988
|
+
if (!state.autoYes) {
|
|
11989
|
+
process.stderr.write(source_default.yellow(`
|
|
11990
|
+
[host_browser] refused (re-run with --yes to allow): ${req.action}${req.url ? ` ${req.url}` : ""}
|
|
11991
|
+
`));
|
|
11992
|
+
return {
|
|
11993
|
+
declined: true,
|
|
11994
|
+
message: "Host browser declined; re-run with --yes to allow."
|
|
11995
|
+
};
|
|
11996
|
+
}
|
|
11997
|
+
process.stderr.write(source_default.dim(`
|
|
11998
|
+
[host_browser] ${req.action}${req.url ? ` ${req.url}` : ""}${req.selector ? ` (${req.selector})` : ""}
|
|
11999
|
+
`));
|
|
12000
|
+
if (!state.browser)
|
|
12001
|
+
state.browser = new BrowserSession;
|
|
12002
|
+
const result = await state.browser.run(req);
|
|
12003
|
+
if ("error" in result)
|
|
12004
|
+
return { error: true, message: result.message };
|
|
12005
|
+
if ("png" in result) {
|
|
12006
|
+
const uploaded = await uploadImageArtifact(ctx, sessionId, result.png);
|
|
12007
|
+
if ("error" in uploaded)
|
|
12008
|
+
return { error: true, message: uploaded.error };
|
|
12009
|
+
return {
|
|
12010
|
+
text: `Screenshot of the current page captured (${result.png.length} bytes).`,
|
|
12011
|
+
_images: [{ storage_key: uploaded.storage_key }]
|
|
12012
|
+
};
|
|
12013
|
+
}
|
|
12014
|
+
return result;
|
|
12015
|
+
}
|
|
12016
|
+
async function resolveHostFile(req, state) {
|
|
12017
|
+
const mutating = req.action === "host_write" || req.action === "host_edit";
|
|
12018
|
+
if (mutating && !state.autoYes) {
|
|
12019
|
+
process.stderr.write(source_default.yellow(`
|
|
12020
|
+
[${req.action}] refused (re-run with --yes to allow): ${req.path}
|
|
12021
|
+
`));
|
|
12022
|
+
return {
|
|
12023
|
+
declined: true,
|
|
12024
|
+
message: `${req.action} declined; re-run with --yes to allow.`
|
|
12025
|
+
};
|
|
12026
|
+
}
|
|
12027
|
+
process.stderr.write(source_default.dim(`
|
|
12028
|
+
[${req.action}] ${req.path ?? "<no path>"}
|
|
12029
|
+
`));
|
|
12030
|
+
const result = await applyFileAction(state.cwd, req);
|
|
12031
|
+
if ("error" in result)
|
|
12032
|
+
return { error: true, message: result.message };
|
|
12033
|
+
return result;
|
|
12034
|
+
}
|
|
12035
|
+
async function resolveLocalAgent(req, state) {
|
|
12036
|
+
if (!state.autoYes) {
|
|
12037
|
+
process.stderr.write(source_default.yellow(`
|
|
12038
|
+
[local_agent] refused (re-run with --yes to allow): ${req.task.slice(0, 80)}
|
|
12039
|
+
`));
|
|
12040
|
+
return {
|
|
12041
|
+
declined: true,
|
|
12042
|
+
message: "Local agent delegation declined; re-run with --yes to allow."
|
|
12043
|
+
};
|
|
12044
|
+
}
|
|
12045
|
+
const agentCmd = process.env.MARTHA_LOCAL_AGENT_CMD || DEFAULT_LOCAL_AGENT_CMD;
|
|
12046
|
+
const cwd = req.cwd ? `${state.cwd}/${req.cwd}` : state.cwd;
|
|
12047
|
+
process.stderr.write(source_default.dim(`
|
|
12048
|
+
[local_agent] (${agentCmd}) ${req.task.slice(0, 100)}
|
|
12049
|
+
`));
|
|
11599
12050
|
try {
|
|
11600
|
-
const
|
|
11601
|
-
content_type: "image/png"
|
|
11602
|
-
});
|
|
11603
|
-
const put = await fetch(mint.upload_url, {
|
|
11604
|
-
method: "PUT",
|
|
11605
|
-
headers: { "Content-Type": "image/png" },
|
|
11606
|
-
body: new Uint8Array(png)
|
|
11607
|
-
});
|
|
11608
|
-
if (!put.ok) {
|
|
11609
|
-
return {
|
|
11610
|
-
error: true,
|
|
11611
|
-
message: `image upload failed: HTTP ${put.status}`
|
|
11612
|
-
};
|
|
11613
|
-
}
|
|
12051
|
+
const result = await runLocalAgent(req.task, { cwd, agentCmd });
|
|
11614
12052
|
return {
|
|
11615
|
-
text:
|
|
11616
|
-
|
|
12053
|
+
text: result.text || "(local agent produced no output)",
|
|
12054
|
+
exit_code: result.exit_code,
|
|
12055
|
+
...result.timed_out ? { timed_out: true } : {}
|
|
11617
12056
|
};
|
|
11618
12057
|
} catch (e) {
|
|
11619
|
-
return {
|
|
12058
|
+
return {
|
|
12059
|
+
error: true,
|
|
12060
|
+
message: `local agent failed to start (${agentCmd}): ${String(e)}. ` + `Set MARTHA_LOCAL_AGENT_CMD to an installed agent command.`
|
|
12061
|
+
};
|
|
11620
12062
|
}
|
|
11621
12063
|
}
|
|
11622
12064
|
async function _postToolResult(ctx, sessionId, toolCallId, result, label) {
|
|
@@ -11644,6 +12086,30 @@ async function handleHostExecFrame(ctx, sessionId, data, state) {
|
|
|
11644
12086
|
const result = await resolveHostScreenshot(ctx, sessionId, req, state);
|
|
11645
12087
|
await _postToolResult(ctx, sessionId, id, result, "host_screenshot");
|
|
11646
12088
|
}
|
|
12089
|
+
for (const req of parseHostBrowserRequests(data)) {
|
|
12090
|
+
const id = req.toolCallId;
|
|
12091
|
+
if (state.handled.has(id))
|
|
12092
|
+
continue;
|
|
12093
|
+
state.handled.add(id);
|
|
12094
|
+
const result = await resolveHostBrowser(ctx, sessionId, req, state);
|
|
12095
|
+
await _postToolResult(ctx, sessionId, id, result, "host_browser");
|
|
12096
|
+
}
|
|
12097
|
+
for (const req of parseHostFileRequests(data)) {
|
|
12098
|
+
const id = req.toolCallId;
|
|
12099
|
+
if (state.handled.has(id))
|
|
12100
|
+
continue;
|
|
12101
|
+
state.handled.add(id);
|
|
12102
|
+
const result = await resolveHostFile(req, state);
|
|
12103
|
+
await _postToolResult(ctx, sessionId, id, result, req.action);
|
|
12104
|
+
}
|
|
12105
|
+
for (const req of parseLocalAgentRequests(data)) {
|
|
12106
|
+
const id = req.toolCallId;
|
|
12107
|
+
if (state.handled.has(id))
|
|
12108
|
+
continue;
|
|
12109
|
+
state.handled.add(id);
|
|
12110
|
+
const result = await resolveLocalAgent(req, state);
|
|
12111
|
+
await _postToolResult(ctx, sessionId, id, result, "local_agent");
|
|
12112
|
+
}
|
|
11647
12113
|
}
|
|
11648
12114
|
function parseSlashCommand(input) {
|
|
11649
12115
|
const trimmed = input.trim();
|
|
@@ -11768,6 +12234,9 @@ async function sendMessage(ctx, sessionId, message, opts = {}) {
|
|
|
11768
12234
|
return { response: fullResponse, aborted: true };
|
|
11769
12235
|
}
|
|
11770
12236
|
throw err;
|
|
12237
|
+
} finally {
|
|
12238
|
+
if (localExecState?.browser)
|
|
12239
|
+
await localExecState.browser.close();
|
|
11771
12240
|
}
|
|
11772
12241
|
} else {
|
|
11773
12242
|
const text = await res.text();
|
|
@@ -11818,11 +12287,11 @@ function formatToolStatus(data) {
|
|
|
11818
12287
|
}
|
|
11819
12288
|
}
|
|
11820
12289
|
function promptPick(rl, count) {
|
|
11821
|
-
return new Promise((
|
|
12290
|
+
return new Promise((resolve2) => {
|
|
11822
12291
|
rl.question(source_default.dim(`Pick 1-${count} (or Enter to cancel): `), (ans) => {
|
|
11823
12292
|
const trimmed = ans.trim();
|
|
11824
12293
|
if (!trimmed) {
|
|
11825
|
-
|
|
12294
|
+
resolve2(-1);
|
|
11826
12295
|
return;
|
|
11827
12296
|
}
|
|
11828
12297
|
const n = parseInt(trimmed, 10);
|
|
@@ -11830,10 +12299,10 @@ function promptPick(rl, count) {
|
|
|
11830
12299
|
process.stderr.write(source_default.yellow(`Invalid choice.
|
|
11831
12300
|
|
|
11832
12301
|
`));
|
|
11833
|
-
|
|
12302
|
+
resolve2(-1);
|
|
11834
12303
|
return;
|
|
11835
12304
|
}
|
|
11836
|
-
|
|
12305
|
+
resolve2(n - 1);
|
|
11837
12306
|
});
|
|
11838
12307
|
});
|
|
11839
12308
|
}
|
|
@@ -12276,9 +12745,9 @@ init_errors();
|
|
|
12276
12745
|
import { createInterface as createInterface3 } from "node:readline";
|
|
12277
12746
|
function prompt(rl, question, defaultValue) {
|
|
12278
12747
|
const suffix = defaultValue ? ` [${defaultValue}]` : "";
|
|
12279
|
-
return new Promise((
|
|
12748
|
+
return new Promise((resolve2) => {
|
|
12280
12749
|
rl.question(`${question}${suffix}: `, (answer) => {
|
|
12281
|
-
|
|
12750
|
+
resolve2(answer.trim() || defaultValue || "");
|
|
12282
12751
|
});
|
|
12283
12752
|
});
|
|
12284
12753
|
}
|
|
@@ -12574,14 +13043,14 @@ function registerConfigCommand(program2) {
|
|
|
12574
13043
|
if (!process.stdin.isTTY) {
|
|
12575
13044
|
throw new CLIError("Cannot confirm in non-interactive mode.", 4 /* Validation */, "Use --yes to skip confirmation.");
|
|
12576
13045
|
}
|
|
12577
|
-
const ok = await new Promise((
|
|
13046
|
+
const ok = await new Promise((resolve2) => {
|
|
12578
13047
|
const rl = createInterface3({
|
|
12579
13048
|
input: process.stdin,
|
|
12580
13049
|
output: process.stderr
|
|
12581
13050
|
});
|
|
12582
13051
|
rl.question(`Delete profile '${name}'? (y/N) `, (answer) => {
|
|
12583
13052
|
rl.close();
|
|
12584
|
-
|
|
13053
|
+
resolve2(answer.trim().toLowerCase() === "y");
|
|
12585
13054
|
});
|
|
12586
13055
|
});
|
|
12587
13056
|
if (!ok) {
|
|
@@ -12604,8 +13073,8 @@ function registerConfigCommand(program2) {
|
|
|
12604
13073
|
}
|
|
12605
13074
|
|
|
12606
13075
|
// src/commands/definitions-apply.ts
|
|
12607
|
-
import
|
|
12608
|
-
import
|
|
13076
|
+
import fs7 from "node:fs";
|
|
13077
|
+
import path6 from "node:path";
|
|
12609
13078
|
init_dist();
|
|
12610
13079
|
init_errors();
|
|
12611
13080
|
var VALID_KINDS = new Set([
|
|
@@ -12647,20 +13116,20 @@ var SERVER_GENERATED_FIELDS = new Set([
|
|
|
12647
13116
|
]);
|
|
12648
13117
|
var AGENT_MANAGED_FIELDS = new Set(["functions", "workflows"]);
|
|
12649
13118
|
function loadDefinitions(inputPath) {
|
|
12650
|
-
const resolved =
|
|
12651
|
-
if (!
|
|
13119
|
+
const resolved = path6.resolve(inputPath);
|
|
13120
|
+
if (!fs7.existsSync(resolved)) {
|
|
12652
13121
|
throw new CLIError(`Path not found: ${inputPath}`, 1 /* Error */);
|
|
12653
13122
|
}
|
|
12654
|
-
const stat =
|
|
13123
|
+
const stat = fs7.statSync(resolved);
|
|
12655
13124
|
if (stat.isDirectory()) {
|
|
12656
13125
|
return loadDirectory(resolved);
|
|
12657
13126
|
}
|
|
12658
13127
|
return loadFile(resolved);
|
|
12659
13128
|
}
|
|
12660
13129
|
function loadDirectory(dirPath) {
|
|
12661
|
-
const entries =
|
|
13130
|
+
const entries = fs7.readdirSync(dirPath).sort();
|
|
12662
13131
|
const validExts = new Set([".yaml", ".yml", ".json"]);
|
|
12663
|
-
const files = entries.filter((e) => validExts.has(
|
|
13132
|
+
const files = entries.filter((e) => validExts.has(path6.extname(e).toLowerCase())).map((e) => path6.join(dirPath, e));
|
|
12664
13133
|
if (files.length === 0) {
|
|
12665
13134
|
throw new CLIError(`No YAML or JSON files found in ${dirPath}`, 4 /* Validation */);
|
|
12666
13135
|
}
|
|
@@ -12671,8 +13140,8 @@ function loadDirectory(dirPath) {
|
|
|
12671
13140
|
return results;
|
|
12672
13141
|
}
|
|
12673
13142
|
function loadFile(filePath) {
|
|
12674
|
-
const content =
|
|
12675
|
-
const ext =
|
|
13143
|
+
const content = fs7.readFileSync(filePath, "utf-8");
|
|
13144
|
+
const ext = path6.extname(filePath).toLowerCase();
|
|
12676
13145
|
if (ext === ".json") {
|
|
12677
13146
|
const parsed = parseJsonFile(content, filePath);
|
|
12678
13147
|
return [toLocalDefinition(parsed, filePath)];
|
|
@@ -13094,7 +13563,7 @@ Examples:
|
|
|
13094
13563
|
}
|
|
13095
13564
|
|
|
13096
13565
|
// src/commands/definitions-export.ts
|
|
13097
|
-
import
|
|
13566
|
+
import fs8 from "node:fs";
|
|
13098
13567
|
init_errors();
|
|
13099
13568
|
async function exportDefinitions(ctx, opts, isJsonMode) {
|
|
13100
13569
|
const params = {};
|
|
@@ -13110,7 +13579,7 @@ async function exportDefinitions(ctx, opts, isJsonMode) {
|
|
|
13110
13579
|
const text = await res.text();
|
|
13111
13580
|
if (opts.output) {
|
|
13112
13581
|
try {
|
|
13113
|
-
|
|
13582
|
+
fs8.writeFileSync(opts.output, text);
|
|
13114
13583
|
} catch (err) {
|
|
13115
13584
|
throw new CLIError(`Failed to write ${opts.output}: ${err instanceof Error ? err.message : String(err)}`, 1 /* Error */);
|
|
13116
13585
|
}
|
|
@@ -13419,7 +13888,7 @@ function colorStatus(status) {
|
|
|
13419
13888
|
return fn(status);
|
|
13420
13889
|
}
|
|
13421
13890
|
function sleep(ms) {
|
|
13422
|
-
return new Promise((
|
|
13891
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
13423
13892
|
}
|
|
13424
13893
|
async function pollUntilDone(ctx, executionId, intervalMs = 2000, timeoutMs = 300000) {
|
|
13425
13894
|
const deadline = Date.now() + timeoutMs;
|
|
@@ -13830,8 +14299,8 @@ function registerProjectionCommands(parentCmd, getCtx, isJson) {
|
|
|
13830
14299
|
} catch {}
|
|
13831
14300
|
}
|
|
13832
14301
|
if (opts.output) {
|
|
13833
|
-
const
|
|
13834
|
-
await
|
|
14302
|
+
const fs9 = await import("node:fs/promises");
|
|
14303
|
+
await fs9.writeFile(opts.output, toWrite, "utf-8");
|
|
13835
14304
|
if (!isJson()) {
|
|
13836
14305
|
console.error(source_default.dim(`Wrote ${format} projection of '${name}' to ${opts.output}`));
|
|
13837
14306
|
}
|
|
@@ -14238,8 +14707,8 @@ Usage:
|
|
|
14238
14707
|
});
|
|
14239
14708
|
parentCmd.command("self-grant <agent>").description("View or configure an agent's self-provisioning policy (request-then-approve). " + "With no flags, prints the current policy.").option("--enable", "Allow the agent to REQUEST capability grants").option("--disable", "Disallow self-provisioning").option("--scope <scope>", "Scope ceiling: none | read_only | read_write").option("--allow <ref...>", "Add allow-list refs (function:NAME or mcp:integration/name)").option("--remove <ref...>", "Remove allow-list refs").option("--collection-root <id...>", "Add collection-subtree roots the agent may self-grant collection-scoped functions into").option("--remove-collection-root <id...>", "Remove collection roots").option("--max-pending <n>", "Max concurrently-pending requests").action(async (agent, opts) => {
|
|
14240
14709
|
const ctx = getCtx();
|
|
14241
|
-
const
|
|
14242
|
-
const current = await ctx.api.get(
|
|
14710
|
+
const path7 = `${API_PATH}/${encodeURIComponent(agent)}`;
|
|
14711
|
+
const current = await ctx.api.get(path7);
|
|
14243
14712
|
const mutating = opts.enable || opts.disable || opts.scope !== undefined || (opts.allow?.length ?? 0) > 0 || (opts.remove?.length ?? 0) > 0 || (opts.collectionRoot?.length ?? 0) > 0 || (opts.removeCollectionRoot?.length ?? 0) > 0 || opts.maxPending !== undefined;
|
|
14244
14713
|
if (!mutating) {
|
|
14245
14714
|
if (isJson()) {
|
|
@@ -14291,7 +14760,7 @@ Usage:
|
|
|
14291
14760
|
roots.delete(c);
|
|
14292
14761
|
body.self_grant_collection_roots = [...roots];
|
|
14293
14762
|
}
|
|
14294
|
-
const updated = await ctx.api.put(
|
|
14763
|
+
const updated = await ctx.api.put(path7, body);
|
|
14295
14764
|
if (isJson()) {
|
|
14296
14765
|
console.log(JSON.stringify(policyView(updated), null, 2));
|
|
14297
14766
|
return;
|
|
@@ -14303,6 +14772,128 @@ Usage:
|
|
|
14303
14772
|
}
|
|
14304
14773
|
};
|
|
14305
14774
|
|
|
14775
|
+
// src/commands/prompts.ts
|
|
14776
|
+
var API_PATH2 = "/api/admin/definitions/prompts";
|
|
14777
|
+
var promptsConfig = {
|
|
14778
|
+
typeName: "prompt",
|
|
14779
|
+
typeNamePlural: "prompts",
|
|
14780
|
+
apiPath: API_PATH2,
|
|
14781
|
+
extractList: (data) => {
|
|
14782
|
+
const d = data;
|
|
14783
|
+
if (d.items && Array.isArray(d.items)) {
|
|
14784
|
+
return d.items;
|
|
14785
|
+
}
|
|
14786
|
+
throw new Error("Unexpected API response shape for prompts list");
|
|
14787
|
+
},
|
|
14788
|
+
extractTotal: (data) => {
|
|
14789
|
+
const d = data;
|
|
14790
|
+
return d.total;
|
|
14791
|
+
},
|
|
14792
|
+
listColumns: [
|
|
14793
|
+
{ header: "NAME", accessor: (item) => String(item.name ?? "") },
|
|
14794
|
+
{
|
|
14795
|
+
header: "SCOPE",
|
|
14796
|
+
accessor: (item) => String(item.scope ?? "-")
|
|
14797
|
+
},
|
|
14798
|
+
{
|
|
14799
|
+
header: "PROD VER",
|
|
14800
|
+
accessor: (item) => {
|
|
14801
|
+
const prod = item.production;
|
|
14802
|
+
return prod?.version ? String(prod.version) : "-";
|
|
14803
|
+
}
|
|
14804
|
+
},
|
|
14805
|
+
{
|
|
14806
|
+
header: "STAGING VER",
|
|
14807
|
+
accessor: (item) => {
|
|
14808
|
+
const staging = item.staging;
|
|
14809
|
+
return staging?.version ? String(staging.version) : "-";
|
|
14810
|
+
}
|
|
14811
|
+
},
|
|
14812
|
+
{
|
|
14813
|
+
header: "PROTECTED",
|
|
14814
|
+
accessor: (item) => item.is_protected ? "yes" : "no"
|
|
14815
|
+
}
|
|
14816
|
+
],
|
|
14817
|
+
renderDetail: (prompt2) => {
|
|
14818
|
+
console.log(source_default.bold(`Prompt: ${prompt2.name}
|
|
14819
|
+
`));
|
|
14820
|
+
if (prompt2.description)
|
|
14821
|
+
console.log(` ${prompt2.description}
|
|
14822
|
+
`);
|
|
14823
|
+
console.log(` Scope: ${prompt2.scope ?? "-"}`);
|
|
14824
|
+
console.log(` Protected: ${prompt2.is_protected ? source_default.yellow("yes") : "no"}`);
|
|
14825
|
+
const prod = prompt2.production;
|
|
14826
|
+
const staging = prompt2.staging;
|
|
14827
|
+
console.log(` Prod Ver: ${prod?.version ?? "-"}`);
|
|
14828
|
+
console.log(` Staging Ver: ${staging?.version ?? "-"}`);
|
|
14829
|
+
if (prompt2.updated_at)
|
|
14830
|
+
console.log(` Updated: ${prompt2.updated_at}`);
|
|
14831
|
+
const content = prompt2.content;
|
|
14832
|
+
if (content) {
|
|
14833
|
+
console.log(`
|
|
14834
|
+
${source_default.bold("Content:")}`);
|
|
14835
|
+
const lines = content.split(`
|
|
14836
|
+
`).slice(0, 10);
|
|
14837
|
+
for (const line of lines) {
|
|
14838
|
+
console.log(` ${line}`);
|
|
14839
|
+
}
|
|
14840
|
+
if (content.split(`
|
|
14841
|
+
`).length > 10) {
|
|
14842
|
+
console.log(source_default.dim(` ... (${content.split(`
|
|
14843
|
+
`).length - 10} more lines)`));
|
|
14844
|
+
}
|
|
14845
|
+
}
|
|
14846
|
+
},
|
|
14847
|
+
extraListOptions: (cmd) => {
|
|
14848
|
+
cmd.option("--scope <scope>", "Filter by scope (global, tenant, agent)").option("--protected", "Show only protected prompts");
|
|
14849
|
+
},
|
|
14850
|
+
buildListParams: (opts) => {
|
|
14851
|
+
const params = {};
|
|
14852
|
+
if (opts.scope)
|
|
14853
|
+
params.scope = opts.scope;
|
|
14854
|
+
if (opts.protected)
|
|
14855
|
+
params.is_protected = "true";
|
|
14856
|
+
return params;
|
|
14857
|
+
},
|
|
14858
|
+
extraCommands: (parentCmd, getCtx, isJson) => {
|
|
14859
|
+
parentCmd.command("promote <name>").description("Promote staging version to production").action(async (name) => {
|
|
14860
|
+
const ctx = getCtx();
|
|
14861
|
+
const result = await ctx.api.post(`${API_PATH2}/${encodeURIComponent(name)}/promote`, {});
|
|
14862
|
+
if (isJson()) {
|
|
14863
|
+
console.log(JSON.stringify(result, null, 2));
|
|
14864
|
+
return;
|
|
14865
|
+
}
|
|
14866
|
+
const prodVer = result.production_version_number ?? result.version;
|
|
14867
|
+
console.log(`Promoted '${name}' staging → production (version ${prodVer})`);
|
|
14868
|
+
});
|
|
14869
|
+
parentCmd.command("linked-collections <name>").description("List collections using this prompt as an extra prompt").action(async (name) => {
|
|
14870
|
+
const ctx = getCtx();
|
|
14871
|
+
const response = await ctx.api.get(`${API_PATH2}/${encodeURIComponent(name)}/linked-collections`);
|
|
14872
|
+
const items = response.linked_collections ?? [];
|
|
14873
|
+
if (isJson()) {
|
|
14874
|
+
console.log(JSON.stringify(response, null, 2));
|
|
14875
|
+
return;
|
|
14876
|
+
}
|
|
14877
|
+
if (items.length === 0) {
|
|
14878
|
+
console.log(source_default.dim("No collections linked to this prompt."));
|
|
14879
|
+
return;
|
|
14880
|
+
}
|
|
14881
|
+
const nameW = Math.max(10, ...items.map((c) => String(c.collection_name ?? "").length));
|
|
14882
|
+
const header = ["COLLECTION", "DOCS", "PAGES", "CHUNKS"].map((h, i) => h.padEnd([nameW, 8, 8, 8][i])).join(" ");
|
|
14883
|
+
console.log(source_default.bold(header));
|
|
14884
|
+
console.log(source_default.dim("-".repeat(header.length)));
|
|
14885
|
+
for (const c of items) {
|
|
14886
|
+
console.log([
|
|
14887
|
+
String(c.collection_name ?? "").padEnd(nameW),
|
|
14888
|
+
String(c.document_count ?? 0).padEnd(8),
|
|
14889
|
+
String(c.page_count ?? 0).padEnd(8),
|
|
14890
|
+
String(c.chunk_count ?? 0).padEnd(8)
|
|
14891
|
+
].join(" "));
|
|
14892
|
+
}
|
|
14893
|
+
});
|
|
14894
|
+
}
|
|
14895
|
+
};
|
|
14896
|
+
|
|
14306
14897
|
// src/commands/triggers.ts
|
|
14307
14898
|
init_errors();
|
|
14308
14899
|
function triggerKind(item) {
|
|
@@ -14416,7 +15007,7 @@ var triggersConfig = {
|
|
|
14416
15007
|
};
|
|
14417
15008
|
|
|
14418
15009
|
// src/commands/documents.ts
|
|
14419
|
-
import
|
|
15010
|
+
import fs9 from "node:fs";
|
|
14420
15011
|
init_errors();
|
|
14421
15012
|
var TERMINAL_STATUSES2 = new Set(["ready", "error"]);
|
|
14422
15013
|
var SPINNER_FRAMES2 = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
@@ -14427,7 +15018,7 @@ function nextSpinner() {
|
|
|
14427
15018
|
return frame;
|
|
14428
15019
|
}
|
|
14429
15020
|
function sleep2(ms) {
|
|
14430
|
-
return new Promise((
|
|
15021
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
14431
15022
|
}
|
|
14432
15023
|
function formatBytes(bytes) {
|
|
14433
15024
|
if (bytes < 1024)
|
|
@@ -14671,6 +15262,65 @@ ${items.length} collections`));
|
|
|
14671
15262
|
if (col.updated_at)
|
|
14672
15263
|
console.log(` Updated: ${col.updated_at}`);
|
|
14673
15264
|
});
|
|
15265
|
+
cmd.command("collection-available-prompts <id>").description("List prompts available for a collection's extra prompts").action(async (id) => {
|
|
15266
|
+
const ctx = getCtx();
|
|
15267
|
+
const col = await resolveCollection(ctx, id);
|
|
15268
|
+
const items = await ctx.api.get(`/api/admin/collections/${encodeURIComponent(col.id)}/available-prompts`);
|
|
15269
|
+
if (isJson()) {
|
|
15270
|
+
console.log(JSON.stringify(items, null, 2));
|
|
15271
|
+
return;
|
|
15272
|
+
}
|
|
15273
|
+
if (items.length === 0) {
|
|
15274
|
+
console.log(source_default.dim("No prompts available."));
|
|
15275
|
+
return;
|
|
15276
|
+
}
|
|
15277
|
+
const nameW = Math.max(10, ...items.map((p) => String(p.name ?? "").length));
|
|
15278
|
+
const scopeW = Math.max(6, ...items.map((p) => String(p.scope ?? "").length));
|
|
15279
|
+
const header = ["NAME", "SCOPE", "DESCRIPTION"].map((h, i) => h.padEnd([nameW, scopeW, 40][i])).join(" ");
|
|
15280
|
+
console.log(source_default.bold(header));
|
|
15281
|
+
console.log(source_default.dim("-".repeat(header.length)));
|
|
15282
|
+
for (const p of items) {
|
|
15283
|
+
const desc = String(p.description ?? "-").slice(0, 40);
|
|
15284
|
+
console.log([
|
|
15285
|
+
String(p.name ?? "").padEnd(nameW),
|
|
15286
|
+
String(p.scope ?? "-").padEnd(scopeW),
|
|
15287
|
+
desc
|
|
15288
|
+
].join(" "));
|
|
15289
|
+
}
|
|
15290
|
+
});
|
|
15291
|
+
cmd.command("collection-get-prompts <id>").description("Get current extra prompts for a collection").action(async (id) => {
|
|
15292
|
+
const ctx = getCtx();
|
|
15293
|
+
const col = await ctx.api.get(`/api/admin/collections/${encodeURIComponent(id)}`);
|
|
15294
|
+
if (isJson()) {
|
|
15295
|
+
console.log(JSON.stringify({ extra_prompt_ids: col.extra_prompt_ids ?? [] }, null, 2));
|
|
15296
|
+
return;
|
|
15297
|
+
}
|
|
15298
|
+
const promptIds = col.extra_prompt_ids ?? [];
|
|
15299
|
+
if (promptIds.length === 0) {
|
|
15300
|
+
console.log(source_default.dim("No extra prompts configured."));
|
|
15301
|
+
return;
|
|
15302
|
+
}
|
|
15303
|
+
console.log(source_default.bold(`Extra Prompts for '${col.name}':`));
|
|
15304
|
+
for (const pid of promptIds) {
|
|
15305
|
+
console.log(` - ${pid}`);
|
|
15306
|
+
}
|
|
15307
|
+
});
|
|
15308
|
+
cmd.command("collection-set-prompts <id> [prompt-ids...]").description("Set extra prompts for a collection (replaces existing)").option("--clear", "Clear all extra prompts").action(async (id, promptIds, opts) => {
|
|
15309
|
+
const ctx = getCtx();
|
|
15310
|
+
const col = await resolveCollection(ctx, id);
|
|
15311
|
+
const extraPromptIds = opts.clear ? [] : promptIds;
|
|
15312
|
+
const result = await ctx.api.put(`/api/admin/collections/${encodeURIComponent(col.id)}`, { extra_prompt_ids: extraPromptIds });
|
|
15313
|
+
if (isJson()) {
|
|
15314
|
+
console.log(JSON.stringify({ extra_prompt_ids: result.extra_prompt_ids ?? [] }, null, 2));
|
|
15315
|
+
return;
|
|
15316
|
+
}
|
|
15317
|
+
const newIds = result.extra_prompt_ids ?? [];
|
|
15318
|
+
if (newIds.length === 0) {
|
|
15319
|
+
console.log(`Cleared extra prompts for '${col.name}'`);
|
|
15320
|
+
} else {
|
|
15321
|
+
console.log(`Set ${newIds.length} extra prompt(s) for '${col.name}'`);
|
|
15322
|
+
}
|
|
15323
|
+
});
|
|
14674
15324
|
cmd.command("create-collection").description("Create a new document collection").requiredOption("--name <name>", "Collection name").option("--description <text>", "Collection description").option("--parent <slug-or-id>", "Create as a sub-collection of the given collection (#372 PR1)").action(async (opts) => {
|
|
14675
15325
|
const ctx = getCtx();
|
|
14676
15326
|
const tenantId = await ctx.getTenantId();
|
|
@@ -14718,7 +15368,7 @@ ${items.length} collections`));
|
|
|
14718
15368
|
});
|
|
14719
15369
|
cmd.command("upload <collection-id> <file>").description("Upload a document to a collection").option("--wait", "Wait for ingestion to complete").option("--follow", "Follow ingestion progress in real time").action(async (collectionId, filePath, opts) => {
|
|
14720
15370
|
const ctx = getCtx();
|
|
14721
|
-
if (!
|
|
15371
|
+
if (!fs9.existsSync(filePath)) {
|
|
14722
15372
|
throw new CLIError(`File not found: ${filePath}`, 4 /* Validation */);
|
|
14723
15373
|
}
|
|
14724
15374
|
const result = await ctx.api.upload(`/api/admin/collections/${encodeURIComponent(collectionId)}/documents`, filePath);
|
|
@@ -15350,18 +16000,18 @@ function registerApprovalCommands(program2) {
|
|
|
15350
16000
|
import { readFileSync } from "node:fs";
|
|
15351
16001
|
init_errors();
|
|
15352
16002
|
var truncate2 = (s, n) => s.length > n ? s.slice(0, n - 1) + "…" : s;
|
|
15353
|
-
var sleep3 = (ms, signal) => new Promise((
|
|
16003
|
+
var sleep3 = (ms, signal) => new Promise((resolve2) => {
|
|
15354
16004
|
if (signal?.aborted) {
|
|
15355
|
-
|
|
16005
|
+
resolve2();
|
|
15356
16006
|
return;
|
|
15357
16007
|
}
|
|
15358
16008
|
const t = setTimeout(() => {
|
|
15359
16009
|
signal?.removeEventListener("abort", onAbort);
|
|
15360
|
-
|
|
16010
|
+
resolve2();
|
|
15361
16011
|
}, ms);
|
|
15362
16012
|
const onAbort = () => {
|
|
15363
16013
|
clearTimeout(t);
|
|
15364
|
-
|
|
16014
|
+
resolve2();
|
|
15365
16015
|
};
|
|
15366
16016
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
15367
16017
|
});
|
|
@@ -15821,7 +16471,7 @@ ${items.length} task(s) available`));
|
|
|
15821
16471
|
|
|
15822
16472
|
// src/commands/teams.ts
|
|
15823
16473
|
init_errors();
|
|
15824
|
-
var
|
|
16474
|
+
var API_PATH3 = "/api/admin/teams";
|
|
15825
16475
|
var fmtDate3 = (v) => typeof v === "string" ? new Date(v).toISOString().slice(0, 16).replace("T", " ") : "-";
|
|
15826
16476
|
function registerTeamCommands(program2) {
|
|
15827
16477
|
const cmd = program2.command("teams").description("Manage agent teams");
|
|
@@ -15845,7 +16495,7 @@ function registerTeamCommands(program2) {
|
|
|
15845
16495
|
};
|
|
15846
16496
|
if (opts.description)
|
|
15847
16497
|
body.description = opts.description;
|
|
15848
|
-
const result = await ctx.api.post(
|
|
16498
|
+
const result = await ctx.api.post(API_PATH3, body);
|
|
15849
16499
|
if (isJson()) {
|
|
15850
16500
|
console.log(JSON.stringify(result, null, 2));
|
|
15851
16501
|
return;
|
|
@@ -15856,7 +16506,7 @@ function registerTeamCommands(program2) {
|
|
|
15856
16506
|
});
|
|
15857
16507
|
cmd.command("list").description("List teams").action(async () => {
|
|
15858
16508
|
const ctx = getCtx();
|
|
15859
|
-
const items = await ctx.api.get(
|
|
16509
|
+
const items = await ctx.api.get(API_PATH3);
|
|
15860
16510
|
if (isJson()) {
|
|
15861
16511
|
console.log(JSON.stringify(items, null, 2));
|
|
15862
16512
|
return;
|
|
@@ -15895,7 +16545,7 @@ ${items.length} team(s)`));
|
|
|
15895
16545
|
});
|
|
15896
16546
|
cmd.command("view <nameOrId>").description("View team details with members").action(async (nameOrId) => {
|
|
15897
16547
|
const ctx = getCtx();
|
|
15898
|
-
const item = await ctx.api.get(`${
|
|
16548
|
+
const item = await ctx.api.get(`${API_PATH3}/${encodeURIComponent(nameOrId)}`);
|
|
15899
16549
|
if (isJson()) {
|
|
15900
16550
|
console.log(JSON.stringify(item, null, 2));
|
|
15901
16551
|
return;
|
|
@@ -15932,7 +16582,7 @@ ${items.length} team(s)`));
|
|
|
15932
16582
|
if (Object.keys(body).length === 0) {
|
|
15933
16583
|
throw new CLIError("No fields to update. Use --name, --description, or --routing.", 4 /* Validation */);
|
|
15934
16584
|
}
|
|
15935
|
-
const result = await ctx.api.put(`${
|
|
16585
|
+
const result = await ctx.api.put(`${API_PATH3}/${encodeURIComponent(nameOrId)}`, body);
|
|
15936
16586
|
if (isJson()) {
|
|
15937
16587
|
console.log(JSON.stringify(result, null, 2));
|
|
15938
16588
|
return;
|
|
@@ -15947,7 +16597,7 @@ ${items.length} team(s)`));
|
|
|
15947
16597
|
throw new CLIError("Cancelled. Use --yes to skip confirmation.", 1 /* Error */);
|
|
15948
16598
|
}
|
|
15949
16599
|
}
|
|
15950
|
-
await ctx.api.del(`${
|
|
16600
|
+
await ctx.api.del(`${API_PATH3}/${encodeURIComponent(nameOrId)}`);
|
|
15951
16601
|
if (isJson()) {
|
|
15952
16602
|
console.log(JSON.stringify({ name: nameOrId, deleted: true }));
|
|
15953
16603
|
return;
|
|
@@ -15960,7 +16610,7 @@ ${items.length} team(s)`));
|
|
|
15960
16610
|
agent_name: agentName,
|
|
15961
16611
|
role: opts.role
|
|
15962
16612
|
};
|
|
15963
|
-
const result = await ctx.api.post(`${
|
|
16613
|
+
const result = await ctx.api.post(`${API_PATH3}/${encodeURIComponent(team)}/members`, body);
|
|
15964
16614
|
if (isJson()) {
|
|
15965
16615
|
console.log(JSON.stringify(result, null, 2));
|
|
15966
16616
|
return;
|
|
@@ -15969,7 +16619,7 @@ ${items.length} team(s)`));
|
|
|
15969
16619
|
});
|
|
15970
16620
|
cmd.command("remove-member <team> <agentId>").description("Remove an agent from a team").action(async (team, agentId) => {
|
|
15971
16621
|
const ctx = getCtx();
|
|
15972
|
-
await ctx.api.del(`${
|
|
16622
|
+
await ctx.api.del(`${API_PATH3}/${encodeURIComponent(team)}/members/${encodeURIComponent(agentId)}`);
|
|
15973
16623
|
if (isJson()) {
|
|
15974
16624
|
console.log(JSON.stringify({ team, agent_id: agentId, removed: true }));
|
|
15975
16625
|
return;
|
|
@@ -16295,8 +16945,8 @@ ${data.length} spec(s)`));
|
|
|
16295
16945
|
Resources:
|
|
16296
16946
|
`));
|
|
16297
16947
|
for (const r of resources) {
|
|
16298
|
-
const
|
|
16299
|
-
console.log(` ${source_default.cyan(r.label || r.name)}` + source_default.dim(` → ${
|
|
16948
|
+
const path7 = r.path || `/${r.name}`;
|
|
16949
|
+
console.log(` ${source_default.cyan(r.label || r.name)}` + source_default.dim(` → ${path7}`));
|
|
16300
16950
|
}
|
|
16301
16951
|
}
|
|
16302
16952
|
try {
|
|
@@ -16316,14 +16966,14 @@ Functions:
|
|
|
16316
16966
|
console.log(source_default.dim(`
|
|
16317
16967
|
Proxy: martha integrations proxy ${name} GET /<path>`));
|
|
16318
16968
|
});
|
|
16319
|
-
cmd.command("proxy <name> <method> <path>").description("Send a request through the plugin proxy").option("--data <json>", "JSON request body").option("--query <params>", "Query params as key=val&key=val").action(async (name, method,
|
|
16969
|
+
cmd.command("proxy <name> <method> <path>").description("Send a request through the plugin proxy").option("--data <json>", "JSON request body").option("--query <params>", "Query params as key=val&key=val").action(async (name, method, path7, opts) => {
|
|
16320
16970
|
const ctx = getCtx();
|
|
16321
16971
|
const upperMethod = method.toUpperCase();
|
|
16322
16972
|
const allowed = new Set(["GET", "POST", "PUT", "PATCH", "DELETE"]);
|
|
16323
16973
|
if (!allowed.has(upperMethod)) {
|
|
16324
16974
|
throw new CLIError(`Invalid method: ${method}`, 4 /* Validation */, "Allowed: GET, POST, PUT, PATCH, DELETE");
|
|
16325
16975
|
}
|
|
16326
|
-
const cleanPath =
|
|
16976
|
+
const cleanPath = path7.startsWith("/") ? path7.slice(1) : path7;
|
|
16327
16977
|
const proxyUrl = `/api/admin/plugins/${encodeURIComponent(name)}/${cleanPath}`;
|
|
16328
16978
|
const params = {};
|
|
16329
16979
|
if (opts.query) {
|
|
@@ -16533,8 +17183,8 @@ async function resolveCredentialValue(value) {
|
|
|
16533
17183
|
if (value === "-")
|
|
16534
17184
|
return readStdin();
|
|
16535
17185
|
if (value.startsWith("@")) {
|
|
16536
|
-
const
|
|
16537
|
-
return (await
|
|
17186
|
+
const fs10 = await import("node:fs/promises");
|
|
17187
|
+
return (await fs10.readFile(value.slice(1), "utf-8")).trim();
|
|
16538
17188
|
}
|
|
16539
17189
|
return value;
|
|
16540
17190
|
}
|
|
@@ -16649,8 +17299,8 @@ Notification connections`));
|
|
|
16649
17299
|
if (credentialValue === "-") {
|
|
16650
17300
|
credentialValue = await readStdin2();
|
|
16651
17301
|
} else if (credentialValue?.startsWith("@")) {
|
|
16652
|
-
const
|
|
16653
|
-
credentialValue = await
|
|
17302
|
+
const fs10 = await import("node:fs/promises");
|
|
17303
|
+
credentialValue = await fs10.readFile(credentialValue.slice(1), "utf-8");
|
|
16654
17304
|
}
|
|
16655
17305
|
if (!credentialValue) {
|
|
16656
17306
|
throw new Error("--credential-value is required (use '-' for stdin or '@path' for file).");
|
|
@@ -16700,11 +17350,11 @@ async function readStdin2() {
|
|
|
16700
17350
|
|
|
16701
17351
|
// src/commands/messaging.ts
|
|
16702
17352
|
init_errors();
|
|
16703
|
-
async function messagingFetch(baseUrl,
|
|
16704
|
-
if (/^(https?:)?\/\//i.test(
|
|
17353
|
+
async function messagingFetch(baseUrl, path7, opts) {
|
|
17354
|
+
if (/^(https?:)?\/\//i.test(path7)) {
|
|
16705
17355
|
throw new CLIError("Absolute URL paths are not allowed", 1 /* Error */);
|
|
16706
17356
|
}
|
|
16707
|
-
const url = new URL(
|
|
17357
|
+
const url = new URL(path7, baseUrl);
|
|
16708
17358
|
const headers = {
|
|
16709
17359
|
"Content-Type": "application/json"
|
|
16710
17360
|
};
|
|
@@ -17984,7 +18634,7 @@ ${models.length} models`));
|
|
|
17984
18634
|
}
|
|
17985
18635
|
|
|
17986
18636
|
// src/commands/wiki.ts
|
|
17987
|
-
import
|
|
18637
|
+
import fs10 from "node:fs";
|
|
17988
18638
|
init_errors();
|
|
17989
18639
|
function registerWikiCommands(program2) {
|
|
17990
18640
|
const cmd = program2.command("wiki").description("Manage tenant wiki pages, settings, schema, recompile (#245 D5.4)");
|
|
@@ -18031,14 +18681,14 @@ function registerWikiCommands(program2) {
|
|
|
18031
18681
|
console.log(source_default.dim(`
|
|
18032
18682
|
${pages.length} pages`));
|
|
18033
18683
|
});
|
|
18034
|
-
cmd.command("get <path>").description("Fetch the raw markdown body of a wiki page").option("--out <file>", "Write body to file instead of stdout").action(async (
|
|
18684
|
+
cmd.command("get <path>").description("Fetch the raw markdown body of a wiki page").option("--out <file>", "Write body to file instead of stdout").action(async (path7, opts) => {
|
|
18035
18685
|
const ctx = getCtx();
|
|
18036
|
-
const safe =
|
|
18686
|
+
const safe = path7.split("/").map(encodeURIComponent).join("/");
|
|
18037
18687
|
const resp = await ctx.api.getRaw(`/api/wiki/pages/${safe}`, {
|
|
18038
18688
|
headers: { Accept: "text/markdown,*/*" }
|
|
18039
18689
|
});
|
|
18040
18690
|
if (resp.status === 404) {
|
|
18041
|
-
throw new CLIError(`page not found: ${
|
|
18691
|
+
throw new CLIError(`page not found: ${path7}`, 3 /* NotFound */);
|
|
18042
18692
|
}
|
|
18043
18693
|
if (!resp.ok) {
|
|
18044
18694
|
const detail = await resp.text();
|
|
@@ -18046,16 +18696,16 @@ ${pages.length} pages`));
|
|
|
18046
18696
|
}
|
|
18047
18697
|
const body = await resp.text();
|
|
18048
18698
|
if (opts.out) {
|
|
18049
|
-
|
|
18699
|
+
fs10.writeFileSync(opts.out, body);
|
|
18050
18700
|
if (!isJson()) {
|
|
18051
18701
|
console.log(source_default.dim(`wrote ${body.length} bytes to ${opts.out}`));
|
|
18052
18702
|
} else {
|
|
18053
|
-
console.log(JSON.stringify({ path:
|
|
18703
|
+
console.log(JSON.stringify({ path: path7, bytes: body.length, file: opts.out }));
|
|
18054
18704
|
}
|
|
18055
18705
|
return;
|
|
18056
18706
|
}
|
|
18057
18707
|
if (isJson()) {
|
|
18058
|
-
console.log(JSON.stringify({ path:
|
|
18708
|
+
console.log(JSON.stringify({ path: path7, body, etag: resp.headers.get("ETag") }));
|
|
18059
18709
|
} else {
|
|
18060
18710
|
process.stdout.write(body);
|
|
18061
18711
|
}
|
|
@@ -18150,10 +18800,10 @@ ${pages.length} pages`));
|
|
|
18150
18800
|
}
|
|
18151
18801
|
if (opts.compilePromptOverrideFile) {
|
|
18152
18802
|
const file = String(opts.compilePromptOverrideFile);
|
|
18153
|
-
if (!
|
|
18803
|
+
if (!fs10.existsSync(file)) {
|
|
18154
18804
|
throw new CLIError(`override file not found: ${file}`, 3 /* NotFound */);
|
|
18155
18805
|
}
|
|
18156
|
-
const content =
|
|
18806
|
+
const content = fs10.readFileSync(file, "utf8");
|
|
18157
18807
|
const bytes = Buffer.byteLength(content, "utf8");
|
|
18158
18808
|
if (bytes > 16 * 1024) {
|
|
18159
18809
|
throw new CLIError(`compile prompt override exceeds 16 KB (${bytes} bytes)`, 4 /* Validation */);
|
|
@@ -18177,7 +18827,7 @@ ${pages.length} pages`));
|
|
|
18177
18827
|
const ctx = getCtx();
|
|
18178
18828
|
const resp = await ctx.api.get("/api/wiki/schema");
|
|
18179
18829
|
if (opts.out) {
|
|
18180
|
-
|
|
18830
|
+
fs10.writeFileSync(opts.out, resp.body);
|
|
18181
18831
|
if (!isJson()) {
|
|
18182
18832
|
console.log(source_default.dim(`wrote ${resp.body.length} bytes to ${opts.out}`));
|
|
18183
18833
|
} else {
|
|
@@ -18193,10 +18843,10 @@ ${pages.length} pages`));
|
|
|
18193
18843
|
});
|
|
18194
18844
|
schemaCmd.command("set").description("Replace the tenant wiki schema with the contents of <file>").requiredOption("--file <file>", "Path to schema markdown file").action(async (opts) => {
|
|
18195
18845
|
const ctx = getCtx();
|
|
18196
|
-
if (!
|
|
18846
|
+
if (!fs10.existsSync(opts.file)) {
|
|
18197
18847
|
throw new CLIError(`schema file not found: ${opts.file}`, 3 /* NotFound */);
|
|
18198
18848
|
}
|
|
18199
|
-
const body =
|
|
18849
|
+
const body = fs10.readFileSync(opts.file, "utf8");
|
|
18200
18850
|
const bytes = Buffer.byteLength(body, "utf8");
|
|
18201
18851
|
if (bytes > 64 * 1024) {
|
|
18202
18852
|
throw new CLIError(`schema body exceeds 64 KB (${bytes} bytes)`, 4 /* Validation */);
|
|
@@ -18532,7 +19182,7 @@ async function pollConnectionActive(ctx, connectionId) {
|
|
|
18532
19182
|
});
|
|
18533
19183
|
if (conn?.status === "active")
|
|
18534
19184
|
return;
|
|
18535
|
-
await new Promise((
|
|
19185
|
+
await new Promise((resolve2) => setTimeout(resolve2, intervalMs));
|
|
18536
19186
|
}
|
|
18537
19187
|
throw new CLIError(`Timed out waiting for OAuth authorization (${Math.round(timeoutMs / 1000)}s).`, 1 /* Error */, "The browser consent may not have completed. Re-run to try again, or check " + "the connection status in the admin UI.");
|
|
18538
19188
|
}
|
|
@@ -18594,7 +19244,7 @@ async function pollExecution(ctx, executionId, timeoutMs) {
|
|
|
18594
19244
|
if (["completed", "failed", "cancelled", "timeout"].includes(last.status)) {
|
|
18595
19245
|
return last;
|
|
18596
19246
|
}
|
|
18597
|
-
await new Promise((
|
|
19247
|
+
await new Promise((resolve2) => setTimeout(resolve2, 1000));
|
|
18598
19248
|
}
|
|
18599
19249
|
throw new CLIError(`Timed out waiting for MCP workflow execution ${executionId}`, 1 /* Error */, last ? `Last status: ${last.status}` : undefined);
|
|
18600
19250
|
}
|
|
@@ -18722,8 +19372,8 @@ async function resolveCredentialFlag(value) {
|
|
|
18722
19372
|
return Buffer.concat(chunks).toString("utf-8").trim();
|
|
18723
19373
|
}
|
|
18724
19374
|
if (value.startsWith("@")) {
|
|
18725
|
-
const
|
|
18726
|
-
return (await
|
|
19375
|
+
const fs11 = await import("node:fs/promises");
|
|
19376
|
+
return (await fs11.readFile(value.slice(1), "utf-8")).trim();
|
|
18727
19377
|
}
|
|
18728
19378
|
return value;
|
|
18729
19379
|
}
|
|
@@ -19909,19 +20559,19 @@ function registerDoctorCommand(program2) {
|
|
|
19909
20559
|
|
|
19910
20560
|
// src/commands/skill.ts
|
|
19911
20561
|
init_errors();
|
|
19912
|
-
import
|
|
19913
|
-
import
|
|
20562
|
+
import fs11 from "node:fs";
|
|
20563
|
+
import path7 from "node:path";
|
|
19914
20564
|
import { fileURLToPath } from "node:url";
|
|
19915
20565
|
function locateSkill() {
|
|
19916
|
-
const here =
|
|
20566
|
+
const here = path7.dirname(fileURLToPath(import.meta.url));
|
|
19917
20567
|
const candidates = [
|
|
19918
|
-
|
|
19919
|
-
|
|
19920
|
-
|
|
19921
|
-
|
|
20568
|
+
path7.join(here, "skills", "martha-cli", "SKILL.md"),
|
|
20569
|
+
path7.join(here, "..", "skills", "martha-cli", "SKILL.md"),
|
|
20570
|
+
path7.join(here, "..", "..", "..", "skills", "martha-cli", "SKILL.md"),
|
|
20571
|
+
path7.join(here, "..", "..", "skills", "martha-cli", "SKILL.md")
|
|
19922
20572
|
];
|
|
19923
20573
|
for (const p of candidates) {
|
|
19924
|
-
if (
|
|
20574
|
+
if (fs11.existsSync(p))
|
|
19925
20575
|
return p;
|
|
19926
20576
|
}
|
|
19927
20577
|
return null;
|
|
@@ -19931,7 +20581,7 @@ async function skillCommand() {
|
|
|
19931
20581
|
if (!skillPath) {
|
|
19932
20582
|
throw new CLIError("SKILL.md not found in the installed package. Reinstall via `npm i -g @aiaiai-pt/martha-cli` or `npx -y @aiaiai-pt/martha-cli@latest skill`.", 1 /* Error */);
|
|
19933
20583
|
}
|
|
19934
|
-
const body =
|
|
20584
|
+
const body = fs11.readFileSync(skillPath, "utf-8");
|
|
19935
20585
|
process.stdout.write(body);
|
|
19936
20586
|
}
|
|
19937
20587
|
function registerSkillCommand(program2) {
|
|
@@ -20116,6 +20766,7 @@ registerConfigCommand(program2);
|
|
|
20116
20766
|
registerDefinitionCommands(program2, functionsConfig);
|
|
20117
20767
|
registerDefinitionCommands(program2, workflowsConfig);
|
|
20118
20768
|
registerDefinitionCommands(program2, agentsConfig);
|
|
20769
|
+
registerDefinitionCommands(program2, promptsConfig);
|
|
20119
20770
|
registerDefinitionCommands(program2, triggersConfig);
|
|
20120
20771
|
registerDefinitionsApply(program2);
|
|
20121
20772
|
registerDefinitionsExport(program2);
|