@aiaiai-pt/martha-cli 0.23.0 → 0.25.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.
Files changed (2) hide show
  1. package/dist/index.js +314 -84
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -11074,10 +11074,11 @@ ${items.length} ${config.typeNamePlural}`));
11074
11074
 
11075
11075
  // src/commands/chat.ts
11076
11076
  import { createInterface as createInterface2 } from "node:readline";
11077
+ init_config();
11077
11078
  init_errors();
11078
11079
 
11079
11080
  // src/version.ts
11080
- var CLI_VERSION = "0.23.0";
11081
+ var CLI_VERSION = "0.25.0";
11081
11082
 
11082
11083
  // src/commands/sessions.ts
11083
11084
  function relativeTime(iso) {
@@ -11373,15 +11374,26 @@ async function runHostCommand(command, toolCallId, opts) {
11373
11374
  return "";
11374
11375
  }
11375
11376
  };
11377
+ const stdin = opts.stdinData != null ? "pipe" : "ignore";
11376
11378
  return await new Promise((resolve, reject) => {
11377
11379
  let settled = false;
11378
- const child = spawn(command, {
11380
+ const child = opts.argv ? spawn(opts.argv[0], opts.argv.slice(1), {
11381
+ shell: false,
11382
+ cwd: opts.cwd,
11383
+ detached: true,
11384
+ stdio: [stdin, fd, fd]
11385
+ }) : spawn(command, {
11379
11386
  shell: true,
11380
11387
  cwd: opts.cwd,
11381
11388
  detached: true,
11382
- stdio: ["ignore", fd, fd]
11389
+ stdio: [stdin, fd, fd]
11383
11390
  });
11384
11391
  closeSync(fd);
11392
+ if (opts.stdinData != null && child.stdin) {
11393
+ child.stdin.on("error", () => {});
11394
+ child.stdin.write(opts.stdinData);
11395
+ child.stdin.end();
11396
+ }
11385
11397
  const timer = setTimeout(async () => {
11386
11398
  if (settled)
11387
11399
  return;
@@ -11392,7 +11404,8 @@ async function runHostCommand(command, toolCallId, opts) {
11392
11404
  stderr: "",
11393
11405
  exit_code: 0,
11394
11406
  backgrounded: true,
11395
- pid: child.pid
11407
+ pid: child.pid,
11408
+ log_path: logPath
11396
11409
  });
11397
11410
  }, opts.timeoutMs ?? DEFAULT_TIMEOUT_MS);
11398
11411
  child.on("error", (e) => {
@@ -11407,7 +11420,12 @@ async function runHostCommand(command, toolCallId, opts) {
11407
11420
  return;
11408
11421
  settled = true;
11409
11422
  clearTimeout(timer);
11410
- resolve({ stdout: await readLog(), stderr: "", exit_code: code ?? -1 });
11423
+ resolve({
11424
+ stdout: await readLog(),
11425
+ stderr: "",
11426
+ exit_code: code ?? -1,
11427
+ log_path: logPath
11428
+ });
11411
11429
  });
11412
11430
  });
11413
11431
  }
@@ -11816,66 +11834,51 @@ function parseHostFileRequests(data) {
11816
11834
  }
11817
11835
 
11818
11836
  // src/lib/local-agent.ts
11819
- import { spawn as spawn2 } from "node:child_process";
11820
- var DEFAULT_LOCAL_AGENT_CMD = "codex exec";
11837
+ var AGENT_PRESETS = {
11838
+ claude: {
11839
+ name: "claude",
11840
+ command: ["claude", "-p"],
11841
+ promptVia: "argv",
11842
+ description: "Claude Code headless (prompt passed as an argument)."
11843
+ },
11844
+ codex: {
11845
+ name: "codex",
11846
+ command: ["codex", "exec", "--skip-git-repo-check"],
11847
+ promptVia: "stdin",
11848
+ description: "OpenAI Codex CLI (prompt on stdin; runs outside a git repo)."
11849
+ },
11850
+ "cursor-agent": {
11851
+ name: "cursor-agent",
11852
+ command: ["cursor-agent", "--print", "--trust"],
11853
+ promptVia: "argv",
11854
+ description: "Cursor Agent headless (prompt passed as an argument)."
11855
+ }
11856
+ };
11857
+ var DEFAULT_LOCAL_AGENT = "codex";
11821
11858
  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");
11859
+ function resolveAgentInvocation(value) {
11860
+ const trimmed = (value || "").trim();
11861
+ if (!trimmed)
11862
+ throw new Error("local agent command is empty");
11863
+ const preset = AGENT_PRESETS[trimmed];
11864
+ if (preset) {
11865
+ return {
11866
+ command: preset.command,
11867
+ promptVia: preset.promptVia,
11868
+ source: preset.name
11850
11869
  };
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
- });
11870
+ }
11871
+ const parts = trimmed.split(/\s+/).filter(Boolean);
11872
+ return { command: parts, promptVia: "argv", source: trimmed };
11873
+ }
11874
+ function buildSpawn(invocation, task) {
11875
+ if (invocation.command.length === 0)
11876
+ throw new Error("local agent command is empty");
11877
+ const [bin, ...rest] = invocation.command;
11878
+ if (invocation.promptVia === "stdin") {
11879
+ return { bin, args: rest, stdin: task };
11880
+ }
11881
+ return { bin, args: [...rest, task], stdin: null };
11879
11882
  }
11880
11883
  function parseLocalAgentRequests(data) {
11881
11884
  let tools;
@@ -12032,7 +12035,7 @@ async function resolveHostFile(req, state) {
12032
12035
  return { error: true, message: result.message };
12033
12036
  return result;
12034
12037
  }
12035
- async function resolveLocalAgent(req, state) {
12038
+ async function resolveLocalAgent(sessionId, toolCallId, req, state) {
12036
12039
  if (!state.autoYes) {
12037
12040
  process.stderr.write(source_default.yellow(`
12038
12041
  [local_agent] refused (re-run with --yes to allow): ${req.task.slice(0, 80)}
@@ -12042,24 +12045,64 @@ async function resolveLocalAgent(req, state) {
12042
12045
  message: "Local agent delegation declined; re-run with --yes to allow."
12043
12046
  };
12044
12047
  }
12045
- const agentCmd = process.env.MARTHA_LOCAL_AGENT_CMD || DEFAULT_LOCAL_AGENT_CMD;
12048
+ let invocation;
12049
+ try {
12050
+ invocation = resolveAgentInvocation(state.localAgent);
12051
+ } catch (e) {
12052
+ return { error: true, message: `invalid local agent config: ${String(e)}` };
12053
+ }
12054
+ const decision = decideFromJournal(await state.journal.lookup(sessionId, toolCallId));
12055
+ if (decision.kind === "replay")
12056
+ return decision.result;
12057
+ if (decision.kind === "crashed") {
12058
+ return {
12059
+ error: true,
12060
+ exit_code: -1,
12061
+ message: `A previous local_agent run (${decision.command}) did not complete; ` + `not re-running. Its log survives under .martha-runner/ — read it with host_read.`
12062
+ };
12063
+ }
12046
12064
  const cwd = req.cwd ? `${state.cwd}/${req.cwd}` : state.cwd;
12065
+ const { bin, args, stdin } = buildSpawn(invocation, req.task);
12047
12066
  process.stderr.write(source_default.dim(`
12048
- [local_agent] (${agentCmd}) ${req.task.slice(0, 100)}
12067
+ [local_agent] (${invocation.source}) ${req.task.slice(0, 100)}
12049
12068
  `));
12069
+ await state.journal.recordRunning(sessionId, toolCallId, `local_agent:${invocation.source}`, new Date().toISOString());
12070
+ let result;
12050
12071
  try {
12051
- const result = await runLocalAgent(req.task, { cwd, agentCmd });
12052
- return {
12053
- text: result.text || "(local agent produced no output)",
12054
- exit_code: result.exit_code,
12055
- ...result.timed_out ? { timed_out: true } : {}
12056
- };
12072
+ result = await runHostCommand(`local_agent:${invocation.source}`, toolCallId, {
12073
+ cwd,
12074
+ argv: [bin, ...args],
12075
+ stdinData: stdin ?? undefined,
12076
+ timeoutMs: DEFAULT_LOCAL_AGENT_TIMEOUT_MS
12077
+ });
12057
12078
  } catch (e) {
12079
+ const failed = {
12080
+ stdout: "",
12081
+ stderr: String(e),
12082
+ exit_code: -1
12083
+ };
12084
+ await state.journal.recordDone(sessionId, toolCallId, failed);
12058
12085
  return {
12059
12086
  error: true,
12060
- message: `local agent failed to start (${agentCmd}): ${String(e)}. ` + `Set MARTHA_LOCAL_AGENT_CMD to an installed agent command.`
12087
+ message: `local agent failed to start (${invocation.source}): ${String(e)}. ` + `Pick an installed agent with --local-agent <claude|codex|cursor-agent> ` + `or set one via 'martha config set local_agent <name>'.`
12088
+ };
12089
+ }
12090
+ await state.journal.recordDone(sessionId, toolCallId, result);
12091
+ if (result.backgrounded) {
12092
+ const mins = Math.round(DEFAULT_LOCAL_AGENT_TIMEOUT_MS / 60000);
12093
+ return {
12094
+ text: result.stdout || "(no output captured yet)",
12095
+ backgrounded: true,
12096
+ pid: result.pid,
12097
+ log_path: result.log_path,
12098
+ message: `The local agent is still running after ${mins} min; it was left running ` + `in the background (it survives this session). Read its live log and final ` + `result with host_read on ${result.log_path}.`
12061
12099
  };
12062
12100
  }
12101
+ return {
12102
+ text: result.stdout || "(local agent produced no output)",
12103
+ exit_code: result.exit_code,
12104
+ log_path: result.log_path
12105
+ };
12063
12106
  }
12064
12107
  async function _postToolResult(ctx, sessionId, toolCallId, result, label) {
12065
12108
  try {
@@ -12107,7 +12150,7 @@ async function handleHostExecFrame(ctx, sessionId, data, state) {
12107
12150
  if (state.handled.has(id))
12108
12151
  continue;
12109
12152
  state.handled.add(id);
12110
- const result = await resolveLocalAgent(req, state);
12153
+ const result = await resolveLocalAgent(sessionId, id, req, state);
12111
12154
  await _postToolResult(ctx, sessionId, id, result, "local_agent");
12112
12155
  }
12113
12156
  }
@@ -12164,6 +12207,7 @@ async function sendMessage(ctx, sessionId, message, opts = {}) {
12164
12207
  const localExecState = opts.localExec ? {
12165
12208
  cwd: opts.localExec.cwd,
12166
12209
  autoYes: opts.localExec.autoYes,
12210
+ localAgent: opts.localExec.agent,
12167
12211
  handled: new Set,
12168
12212
  journal: new Journal(opts.localExec.cwd)
12169
12213
  } : null;
@@ -12685,7 +12729,7 @@ async function runOneShot(ctx, sessionId, message, isJson, clientId, agentName,
12685
12729
  }
12686
12730
  }
12687
12731
  function registerChatCommand(program2) {
12688
- program2.command("chat").description("Chat with a Martha agent").option("--session <id>", "Resume an existing session").option("--client <nameOrId>", "Use a specific client (name or ID)").option("--agent <name>", "Drive the chat with a specific copilot agent (defaults to profile.default_agent)").option("--message <text>", "Send a single message (non-interactive)").option("--show-tools", "Show tool calls and results during chat").option("--local-exec", "Allow the agent to run host tools on THIS machine (#568). Requires the server to have LOCAL_EXEC_ENABLED=1.").option("--yes", "Auto-approve host tool execution (required with --local-exec for non-interactive runs).").option("--timeout <seconds>", "Per-message HTTP timeout in seconds (default: 600)").action(async (opts) => {
12732
+ program2.command("chat").description("Chat with a Martha agent").option("--session <id>", "Resume an existing session").option("--client <nameOrId>", "Use a specific client (name or ID)").option("--agent <name>", "Drive the chat with a specific copilot agent (defaults to profile.default_agent)").option("--message <text>", "Send a single message (non-interactive)").option("--show-tools", "Show tool calls and results during chat").option("--local-exec", "Allow the agent to run host tools on THIS machine (#568). Requires the server to have LOCAL_EXEC_ENABLED=1.").option("--yes", "Auto-approve host tool execution (required with --local-exec for non-interactive runs).").option("--local-agent <name>", "Which local coding agent `local_agent` delegates to: a preset (claude | codex | cursor-agent) or a raw command. Overrides MARTHA_LOCAL_AGENT_CMD and `config local_agent` for this run.").option("--timeout <seconds>", "Per-message HTTP timeout in seconds (default: 600)").action(async (opts) => {
12689
12733
  const ctx = createContext({
12690
12734
  profileOverride: program2.opts().profile,
12691
12735
  verbose: program2.opts().verbose
@@ -12720,7 +12764,8 @@ function registerChatCommand(program2) {
12720
12764
  }
12721
12765
  const showTools = !!opts.showTools;
12722
12766
  const timeoutMs = opts.timeout ? parseTimeoutSeconds(opts.timeout) * 1000 : undefined;
12723
- const localExec = opts.localExec ? { cwd: process.cwd(), autoYes: !!opts.yes } : undefined;
12767
+ const localAgentChoice = opts.localAgent || process.env.MARTHA_LOCAL_AGENT_CMD || loadConfig().settings.local_agent || DEFAULT_LOCAL_AGENT;
12768
+ const localExec = opts.localExec ? { cwd: process.cwd(), autoYes: !!opts.yes, agent: localAgentChoice } : undefined;
12724
12769
  if (opts.message) {
12725
12770
  await runOneShot(ctx, sessionId, opts.message, isJson, clientId, agentName, showTools, timeoutMs, localExec);
12726
12771
  } else {
@@ -12841,6 +12886,8 @@ Global Settings
12841
12886
  console.log(` Editor: ${settings.editor}`);
12842
12887
  if (settings.pager)
12843
12888
  console.log(` Pager: ${settings.pager}`);
12889
+ if (settings.local_agent)
12890
+ console.log(` Local agent: ${settings.local_agent}`);
12844
12891
  if (settings.chat) {
12845
12892
  if (settings.chat.show_tool_calls)
12846
12893
  console.log(` Tool calls: ${settings.chat.show_tool_calls}`);
@@ -12879,6 +12926,7 @@ var SETTINGS_KEYS = {
12879
12926
  color: (s) => s.color,
12880
12927
  editor: (s) => s.editor,
12881
12928
  pager: (s) => s.pager,
12929
+ local_agent: (s) => s.local_agent,
12882
12930
  "chat.show_tool_calls": (s) => s.chat?.show_tool_calls,
12883
12931
  "chat.markdown": (s) => s.chat?.markdown,
12884
12932
  "chat.history_file": (s) => s.chat?.history_file
@@ -14772,6 +14820,128 @@ Usage:
14772
14820
  }
14773
14821
  };
14774
14822
 
14823
+ // src/commands/prompts.ts
14824
+ var API_PATH2 = "/api/admin/definitions/prompts";
14825
+ var promptsConfig = {
14826
+ typeName: "prompt",
14827
+ typeNamePlural: "prompts",
14828
+ apiPath: API_PATH2,
14829
+ extractList: (data) => {
14830
+ const d = data;
14831
+ if (d.items && Array.isArray(d.items)) {
14832
+ return d.items;
14833
+ }
14834
+ throw new Error("Unexpected API response shape for prompts list");
14835
+ },
14836
+ extractTotal: (data) => {
14837
+ const d = data;
14838
+ return d.total;
14839
+ },
14840
+ listColumns: [
14841
+ { header: "NAME", accessor: (item) => String(item.name ?? "") },
14842
+ {
14843
+ header: "SCOPE",
14844
+ accessor: (item) => String(item.scope ?? "-")
14845
+ },
14846
+ {
14847
+ header: "PROD VER",
14848
+ accessor: (item) => {
14849
+ const prod = item.production;
14850
+ return prod?.version ? String(prod.version) : "-";
14851
+ }
14852
+ },
14853
+ {
14854
+ header: "STAGING VER",
14855
+ accessor: (item) => {
14856
+ const staging = item.staging;
14857
+ return staging?.version ? String(staging.version) : "-";
14858
+ }
14859
+ },
14860
+ {
14861
+ header: "PROTECTED",
14862
+ accessor: (item) => item.is_protected ? "yes" : "no"
14863
+ }
14864
+ ],
14865
+ renderDetail: (prompt2) => {
14866
+ console.log(source_default.bold(`Prompt: ${prompt2.name}
14867
+ `));
14868
+ if (prompt2.description)
14869
+ console.log(` ${prompt2.description}
14870
+ `);
14871
+ console.log(` Scope: ${prompt2.scope ?? "-"}`);
14872
+ console.log(` Protected: ${prompt2.is_protected ? source_default.yellow("yes") : "no"}`);
14873
+ const prod = prompt2.production;
14874
+ const staging = prompt2.staging;
14875
+ console.log(` Prod Ver: ${prod?.version ?? "-"}`);
14876
+ console.log(` Staging Ver: ${staging?.version ?? "-"}`);
14877
+ if (prompt2.updated_at)
14878
+ console.log(` Updated: ${prompt2.updated_at}`);
14879
+ const content = prompt2.content;
14880
+ if (content) {
14881
+ console.log(`
14882
+ ${source_default.bold("Content:")}`);
14883
+ const lines = content.split(`
14884
+ `).slice(0, 10);
14885
+ for (const line of lines) {
14886
+ console.log(` ${line}`);
14887
+ }
14888
+ if (content.split(`
14889
+ `).length > 10) {
14890
+ console.log(source_default.dim(` ... (${content.split(`
14891
+ `).length - 10} more lines)`));
14892
+ }
14893
+ }
14894
+ },
14895
+ extraListOptions: (cmd) => {
14896
+ cmd.option("--scope <scope>", "Filter by scope (global, tenant, agent)").option("--protected", "Show only protected prompts");
14897
+ },
14898
+ buildListParams: (opts) => {
14899
+ const params = {};
14900
+ if (opts.scope)
14901
+ params.scope = opts.scope;
14902
+ if (opts.protected)
14903
+ params.is_protected = "true";
14904
+ return params;
14905
+ },
14906
+ extraCommands: (parentCmd, getCtx, isJson) => {
14907
+ parentCmd.command("promote <name>").description("Promote staging version to production").action(async (name) => {
14908
+ const ctx = getCtx();
14909
+ const result = await ctx.api.post(`${API_PATH2}/${encodeURIComponent(name)}/promote`, {});
14910
+ if (isJson()) {
14911
+ console.log(JSON.stringify(result, null, 2));
14912
+ return;
14913
+ }
14914
+ const prodVer = result.production_version_number ?? result.version;
14915
+ console.log(`Promoted '${name}' staging → production (version ${prodVer})`);
14916
+ });
14917
+ parentCmd.command("linked-collections <name>").description("List collections using this prompt as an extra prompt").action(async (name) => {
14918
+ const ctx = getCtx();
14919
+ const response = await ctx.api.get(`${API_PATH2}/${encodeURIComponent(name)}/linked-collections`);
14920
+ const items = response.linked_collections ?? [];
14921
+ if (isJson()) {
14922
+ console.log(JSON.stringify(response, null, 2));
14923
+ return;
14924
+ }
14925
+ if (items.length === 0) {
14926
+ console.log(source_default.dim("No collections linked to this prompt."));
14927
+ return;
14928
+ }
14929
+ const nameW = Math.max(10, ...items.map((c) => String(c.collection_name ?? "").length));
14930
+ const header = ["COLLECTION", "DOCS", "PAGES", "CHUNKS"].map((h, i) => h.padEnd([nameW, 8, 8, 8][i])).join(" ");
14931
+ console.log(source_default.bold(header));
14932
+ console.log(source_default.dim("-".repeat(header.length)));
14933
+ for (const c of items) {
14934
+ console.log([
14935
+ String(c.collection_name ?? "").padEnd(nameW),
14936
+ String(c.document_count ?? 0).padEnd(8),
14937
+ String(c.page_count ?? 0).padEnd(8),
14938
+ String(c.chunk_count ?? 0).padEnd(8)
14939
+ ].join(" "));
14940
+ }
14941
+ });
14942
+ }
14943
+ };
14944
+
14775
14945
  // src/commands/triggers.ts
14776
14946
  init_errors();
14777
14947
  function triggerKind(item) {
@@ -15140,6 +15310,65 @@ ${items.length} collections`));
15140
15310
  if (col.updated_at)
15141
15311
  console.log(` Updated: ${col.updated_at}`);
15142
15312
  });
15313
+ cmd.command("collection-available-prompts <id>").description("List prompts available for a collection's extra prompts").action(async (id) => {
15314
+ const ctx = getCtx();
15315
+ const col = await resolveCollection(ctx, id);
15316
+ const items = await ctx.api.get(`/api/admin/collections/${encodeURIComponent(col.id)}/available-prompts`);
15317
+ if (isJson()) {
15318
+ console.log(JSON.stringify(items, null, 2));
15319
+ return;
15320
+ }
15321
+ if (items.length === 0) {
15322
+ console.log(source_default.dim("No prompts available."));
15323
+ return;
15324
+ }
15325
+ const nameW = Math.max(10, ...items.map((p) => String(p.name ?? "").length));
15326
+ const scopeW = Math.max(6, ...items.map((p) => String(p.scope ?? "").length));
15327
+ const header = ["NAME", "SCOPE", "DESCRIPTION"].map((h, i) => h.padEnd([nameW, scopeW, 40][i])).join(" ");
15328
+ console.log(source_default.bold(header));
15329
+ console.log(source_default.dim("-".repeat(header.length)));
15330
+ for (const p of items) {
15331
+ const desc = String(p.description ?? "-").slice(0, 40);
15332
+ console.log([
15333
+ String(p.name ?? "").padEnd(nameW),
15334
+ String(p.scope ?? "-").padEnd(scopeW),
15335
+ desc
15336
+ ].join(" "));
15337
+ }
15338
+ });
15339
+ cmd.command("collection-get-prompts <id>").description("Get current extra prompts for a collection").action(async (id) => {
15340
+ const ctx = getCtx();
15341
+ const col = await ctx.api.get(`/api/admin/collections/${encodeURIComponent(id)}`);
15342
+ if (isJson()) {
15343
+ console.log(JSON.stringify({ extra_prompt_ids: col.extra_prompt_ids ?? [] }, null, 2));
15344
+ return;
15345
+ }
15346
+ const promptIds = col.extra_prompt_ids ?? [];
15347
+ if (promptIds.length === 0) {
15348
+ console.log(source_default.dim("No extra prompts configured."));
15349
+ return;
15350
+ }
15351
+ console.log(source_default.bold(`Extra Prompts for '${col.name}':`));
15352
+ for (const pid of promptIds) {
15353
+ console.log(` - ${pid}`);
15354
+ }
15355
+ });
15356
+ 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) => {
15357
+ const ctx = getCtx();
15358
+ const col = await resolveCollection(ctx, id);
15359
+ const extraPromptIds = opts.clear ? [] : promptIds;
15360
+ const result = await ctx.api.put(`/api/admin/collections/${encodeURIComponent(col.id)}`, { extra_prompt_ids: extraPromptIds });
15361
+ if (isJson()) {
15362
+ console.log(JSON.stringify({ extra_prompt_ids: result.extra_prompt_ids ?? [] }, null, 2));
15363
+ return;
15364
+ }
15365
+ const newIds = result.extra_prompt_ids ?? [];
15366
+ if (newIds.length === 0) {
15367
+ console.log(`Cleared extra prompts for '${col.name}'`);
15368
+ } else {
15369
+ console.log(`Set ${newIds.length} extra prompt(s) for '${col.name}'`);
15370
+ }
15371
+ });
15143
15372
  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) => {
15144
15373
  const ctx = getCtx();
15145
15374
  const tenantId = await ctx.getTenantId();
@@ -16290,7 +16519,7 @@ ${items.length} task(s) available`));
16290
16519
 
16291
16520
  // src/commands/teams.ts
16292
16521
  init_errors();
16293
- var API_PATH2 = "/api/admin/teams";
16522
+ var API_PATH3 = "/api/admin/teams";
16294
16523
  var fmtDate3 = (v) => typeof v === "string" ? new Date(v).toISOString().slice(0, 16).replace("T", " ") : "-";
16295
16524
  function registerTeamCommands(program2) {
16296
16525
  const cmd = program2.command("teams").description("Manage agent teams");
@@ -16314,7 +16543,7 @@ function registerTeamCommands(program2) {
16314
16543
  };
16315
16544
  if (opts.description)
16316
16545
  body.description = opts.description;
16317
- const result = await ctx.api.post(API_PATH2, body);
16546
+ const result = await ctx.api.post(API_PATH3, body);
16318
16547
  if (isJson()) {
16319
16548
  console.log(JSON.stringify(result, null, 2));
16320
16549
  return;
@@ -16325,7 +16554,7 @@ function registerTeamCommands(program2) {
16325
16554
  });
16326
16555
  cmd.command("list").description("List teams").action(async () => {
16327
16556
  const ctx = getCtx();
16328
- const items = await ctx.api.get(API_PATH2);
16557
+ const items = await ctx.api.get(API_PATH3);
16329
16558
  if (isJson()) {
16330
16559
  console.log(JSON.stringify(items, null, 2));
16331
16560
  return;
@@ -16364,7 +16593,7 @@ ${items.length} team(s)`));
16364
16593
  });
16365
16594
  cmd.command("view <nameOrId>").description("View team details with members").action(async (nameOrId) => {
16366
16595
  const ctx = getCtx();
16367
- const item = await ctx.api.get(`${API_PATH2}/${encodeURIComponent(nameOrId)}`);
16596
+ const item = await ctx.api.get(`${API_PATH3}/${encodeURIComponent(nameOrId)}`);
16368
16597
  if (isJson()) {
16369
16598
  console.log(JSON.stringify(item, null, 2));
16370
16599
  return;
@@ -16401,7 +16630,7 @@ ${items.length} team(s)`));
16401
16630
  if (Object.keys(body).length === 0) {
16402
16631
  throw new CLIError("No fields to update. Use --name, --description, or --routing.", 4 /* Validation */);
16403
16632
  }
16404
- const result = await ctx.api.put(`${API_PATH2}/${encodeURIComponent(nameOrId)}`, body);
16633
+ const result = await ctx.api.put(`${API_PATH3}/${encodeURIComponent(nameOrId)}`, body);
16405
16634
  if (isJson()) {
16406
16635
  console.log(JSON.stringify(result, null, 2));
16407
16636
  return;
@@ -16416,7 +16645,7 @@ ${items.length} team(s)`));
16416
16645
  throw new CLIError("Cancelled. Use --yes to skip confirmation.", 1 /* Error */);
16417
16646
  }
16418
16647
  }
16419
- await ctx.api.del(`${API_PATH2}/${encodeURIComponent(nameOrId)}`);
16648
+ await ctx.api.del(`${API_PATH3}/${encodeURIComponent(nameOrId)}`);
16420
16649
  if (isJson()) {
16421
16650
  console.log(JSON.stringify({ name: nameOrId, deleted: true }));
16422
16651
  return;
@@ -16429,7 +16658,7 @@ ${items.length} team(s)`));
16429
16658
  agent_name: agentName,
16430
16659
  role: opts.role
16431
16660
  };
16432
- const result = await ctx.api.post(`${API_PATH2}/${encodeURIComponent(team)}/members`, body);
16661
+ const result = await ctx.api.post(`${API_PATH3}/${encodeURIComponent(team)}/members`, body);
16433
16662
  if (isJson()) {
16434
16663
  console.log(JSON.stringify(result, null, 2));
16435
16664
  return;
@@ -16438,7 +16667,7 @@ ${items.length} team(s)`));
16438
16667
  });
16439
16668
  cmd.command("remove-member <team> <agentId>").description("Remove an agent from a team").action(async (team, agentId) => {
16440
16669
  const ctx = getCtx();
16441
- await ctx.api.del(`${API_PATH2}/${encodeURIComponent(team)}/members/${encodeURIComponent(agentId)}`);
16670
+ await ctx.api.del(`${API_PATH3}/${encodeURIComponent(team)}/members/${encodeURIComponent(agentId)}`);
16442
16671
  if (isJson()) {
16443
16672
  console.log(JSON.stringify({ team, agent_id: agentId, removed: true }));
16444
16673
  return;
@@ -20585,6 +20814,7 @@ registerConfigCommand(program2);
20585
20814
  registerDefinitionCommands(program2, functionsConfig);
20586
20815
  registerDefinitionCommands(program2, workflowsConfig);
20587
20816
  registerDefinitionCommands(program2, agentsConfig);
20817
+ registerDefinitionCommands(program2, promptsConfig);
20588
20818
  registerDefinitionCommands(program2, triggersConfig);
20589
20819
  registerDefinitionsApply(program2);
20590
20820
  registerDefinitionsExport(program2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiaiai-pt/martha-cli",
3
- "version": "0.23.0",
3
+ "version": "0.25.0",
4
4
  "description": "Terminal-first client for the Martha AI platform",
5
5
  "homepage": "https://docs.martha.nomadriver.co",
6
6
  "repository": {