@aiaiai-pt/martha-cli 0.68.1 → 0.68.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,24 @@
2
2
 
3
3
  All notable changes to `@aiaiai-pt/martha-cli`. Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). This project adheres to semver — `0.x` releases may include breaking changes between minor versions.
4
4
 
5
+ ## [0.68.4] — 2026-11-09
6
+
7
+ ### Fixed
8
+
9
+ - `martha definitions apply` compares a function's `risk_tags` as the server stores them: a legacy spelling (`write`, `delete`, …) matches the canonical tag it maps to, and order no longer matters. It used to report a change on every apply once the server stored the canonical form (MARTHA-602).
10
+
11
+ ## [0.68.3] — 2026-11-09
12
+
13
+ ### Fixed
14
+
15
+ - `martha functions update` and `martha definitions apply` now check the function's `tool` block (the per-tool call timeout, #1833): an update whose `tool` the server did not persist fails instead of reporting success.
16
+
17
+ ## [0.68.2] — 2026-11-08
18
+
19
+ ### Fixed
20
+
21
+ - `martha agents doctor` and `martha agents runner-presence` report runner presence as unknown when the presence registry can't be read (the server sends `present: null, available: false`) or the presence call fails. They used to say "no runner connected", which is wrong during an outage: the runner may be attached.
22
+
5
23
  ## [0.68.1] — 2026-11-03
6
24
 
7
25
  ### Fixed
package/dist/index.js CHANGED
@@ -11244,7 +11244,7 @@ init_config();
11244
11244
  init_errors();
11245
11245
 
11246
11246
  // src/version.ts
11247
- var CLI_VERSION = "0.68.1";
11247
+ var CLI_VERSION = "0.68.5";
11248
11248
 
11249
11249
  // src/commands/sessions.ts
11250
11250
  function relativeTime(iso) {
@@ -11633,18 +11633,25 @@ async function diagnoseHostRunner(ctx, name) {
11633
11633
  fix: takeover ? undefined : setupFix
11634
11634
  });
11635
11635
  let attached = false;
11636
+ let presenceUnknown = false;
11636
11637
  let attachedHost;
11637
11638
  try {
11638
11639
  const pres = await ctx.api.get(`${API_PATH}/runner-presence`);
11639
11640
  const p = pres.presence?.[name];
11640
- attached = !!p?.present;
11641
+ if (p?.present === null || p?.available === false) {
11642
+ presenceUnknown = true;
11643
+ } else {
11644
+ attached = !!p?.present;
11645
+ }
11641
11646
  attachedHost = p?.connections?.[0]?.host;
11642
- } catch {}
11647
+ } catch {
11648
+ presenceUnknown = true;
11649
+ }
11643
11650
  checks.push({
11644
- ok: attached,
11651
+ ok: presenceUnknown ? null : attached,
11645
11652
  label: "a runner is attached now",
11646
- detail: attached ? `host ${attachedHost ?? "?"}` : "no runner connected",
11647
- fix: attached ? undefined : `on the target machine: martha runner --tools --allow-host-exec (and the server needs CHANNEL_ENABLED=1)`
11653
+ detail: presenceUnknown ? "unknown (presence registry unreachable)" : attached ? `host ${attachedHost ?? "?"}` : "no runner connected",
11654
+ fix: presenceUnknown ? "check Redis connectivity on the Martha server" : attached ? undefined : `on the target machine: martha runner --tools --allow-host-exec (and the server needs CHANNEL_ENABLED=1)`
11648
11655
  });
11649
11656
  const isHostRunner = hasKey || hostTools.length > 0;
11650
11657
  const drivableFromChat = marthaHosted && hasKey && hostTools.length > 0 && grantingClients.length > 0 && takeover;
@@ -12008,6 +12015,8 @@ Attach it as this agent's host executor:
12008
12015
  if (p.present && conns.length) {
12009
12016
  const hosts = conns.map((c) => c.host || c.connection_id?.slice(0, 8) || "?").join(", ");
12010
12017
  console.log(`${source_default.green("● connected")} ${name} ${source_default.dim(`(${hosts})`)}`);
12018
+ } else if (p.present === null || p.available === false) {
12019
+ console.log(`${source_default.yellow("? unknown")} ${name}`);
12011
12020
  } else {
12012
12021
  console.log(`${source_default.dim("○ disconnected")} ${name}`);
12013
12022
  }
@@ -15902,7 +15911,8 @@ var MUTABLE_FIELDS = {
15902
15911
  "risk_tags",
15903
15912
  "risk_level",
15904
15913
  "verification_safe",
15905
- "idempotent"
15914
+ "idempotent",
15915
+ "tool"
15906
15916
  ]),
15907
15917
  Workflow: new Set([
15908
15918
  "description",
@@ -16330,6 +16340,30 @@ async function computeOperations(defs, api) {
16330
16340
  }
16331
16341
  return ops;
16332
16342
  }
16343
+ var EFFECT_TAG_ALIASES = {
16344
+ write: "mutating",
16345
+ delete: "destructive_write",
16346
+ destructive: "destructive_write",
16347
+ host_exec: "host_execution",
16348
+ readonly: "read_only",
16349
+ read: "read_only",
16350
+ payments: "payment",
16351
+ code_execution: "arbitrary_code",
16352
+ fs: "filesystem"
16353
+ };
16354
+ function canonicalEffectTag(tag) {
16355
+ if (typeof tag !== "string")
16356
+ return tag;
16357
+ const key = tag.trim().toLowerCase().replace(/[- ]/g, "_");
16358
+ return EFFECT_TAG_ALIASES[key] ?? key;
16359
+ }
16360
+ function effectTagsMatch(local, remote) {
16361
+ if (!Array.isArray(local) || !Array.isArray(remote))
16362
+ return localSubsetOf(local, remote);
16363
+ const l = new Set(local.map(canonicalEffectTag));
16364
+ const r = new Set(remote.map(canonicalEffectTag));
16365
+ return l.size === r.size && [...l].every((tag) => r.has(tag));
16366
+ }
16333
16367
  function diffFields(local, remote) {
16334
16368
  const flatRemote = flattenDefinitionWrapper(remote);
16335
16369
  const changed = [];
@@ -16342,7 +16376,8 @@ function diffFields(local, remote) {
16342
16376
  continue;
16343
16377
  const localVal = local[key];
16344
16378
  const remoteVal = flatRemote[key];
16345
- if (!localSubsetOf(localVal, remoteVal)) {
16379
+ const same = key === "risk_tags" ? effectTagsMatch(localVal, remoteVal) : localSubsetOf(localVal, remoteVal);
16380
+ if (!same) {
16346
16381
  changed.push(key);
16347
16382
  }
16348
16383
  }
@@ -16614,6 +16649,8 @@ async function applyPrompt(api, op, def) {
16614
16649
  createBody.description = def.body.description;
16615
16650
  if (def.body.scope)
16616
16651
  createBody.scope = def.body.scope;
16652
+ if (def.body.scope_entity_id)
16653
+ createBody.scope_entity_id = def.body.scope_entity_id;
16617
16654
  const res = await api.post(promptPath, createBody);
16618
16655
  const readBack = await api.get(`${promptPath}/${name}`);
16619
16656
  const prodContent = readBack.production?.content;
@@ -16658,7 +16695,8 @@ async function applyPrompt(api, op, def) {
16658
16695
  }
16659
16696
  if (metadataFields.includes("scope")) {
16660
16697
  await api.put(`${promptPath}/${name}/scope`, {
16661
- scope: def.body.scope
16698
+ scope: def.body.scope,
16699
+ ...def.body.scope_entity_id ? { scope_entity_id: def.body.scope_entity_id } : {}
16662
16700
  });
16663
16701
  }
16664
16702
  if (Object.keys(metaBody).length > 0) {
@@ -28182,11 +28220,13 @@ async function checkHostRunners(ctx) {
28182
28220
  detail: "none configured"
28183
28221
  };
28184
28222
  }
28185
- const attached = names.filter((n) => presence[n]?.present).length;
28223
+ const attached = names.filter((n) => presence[n]?.present === true).length;
28224
+ const unknown = names.filter((n) => presence[n]?.present === null || presence[n]?.available === false).length;
28225
+ const detail = unknown ? `${names.length} configured, ${attached} attached, ${unknown} unknown (registry unreachable)` : `${names.length} configured, ${attached} attached`;
28186
28226
  return {
28187
28227
  name: "Host runners",
28188
- status: "pass",
28189
- detail: `${names.length} configured, ${attached} attached`,
28228
+ status: unknown ? "warn" : "pass",
28229
+ detail,
28190
28230
  remedy: `per-agent checkup: martha agents doctor <name>`
28191
28231
  };
28192
28232
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiaiai-pt/martha-cli",
3
- "version": "0.68.1",
3
+ "version": "0.68.5",
4
4
  "description": "Terminal-first client for the Martha AI platform",
5
5
  "homepage": "https://docs.martha.nomadriver.co",
6
6
  "repository": {
@@ -164,6 +164,10 @@ martha functions export [--format yaml|json] [--output FILE]
164
164
 
165
165
  Function `auth` field is the most error-prone part — see the [Function authentication patterns](#function-authentication-patterns) section below.
166
166
 
167
+ **Call timeout (`tool` block, #1833 I5).** To let one call of a slow function run longer than the default, put `tool: { timeout: 60 }` (seconds, 1-900) at the top level of the `functions create|update -f` body. The server stores it in `definition.tool`. In chat the call's activity then gets `timeout` + 15 s (never under 30 s) instead of a fixed 30 s, and the handler bounds the call by `timeout`, with a 401 credential retry sharing the same deadline. A chat session keeps the bound its tool list had when it started, and calls are capped to fit it, so start a new session after raising `timeout`. Out-of-range values or unknown keys return **422**. A function with a `handler` (platform function) may not declare more than its handler's registry `timeout` (30 s unless the decorator sets another): create/update return **422** naming that bound, and a `timeout` on an unknown handler is a 422 too (MARTHA-626; only the `__system__` seed may exceed it, and older tenant rows above it are clamped at dispatch). `tool: {}` clears it. Platform functions get it from their decorator at seed time. `client_timeout_seconds` (1-86400) is stored but not read yet. `definitions apply` does not round-trip the block yet.
168
+
169
+ **Effect tags (`risk_tags`) are a closed vocabulary.** Allowed: `read_only`, `network`, `browser`, `untrusted_content`, `external_io`, `external_write`, `mutating`, `tenant_write`, `filesystem`, `host_execution`, `infra`, `destructive_write`, `payment`, `arbitrary_code`. Legacy spellings are mapped on write (`write`→`mutating`, `delete`→`destructive_write`, `host_exec`→`host_execution`, …), so a re-`get` can show a different tag than the file. Any other tag fails `create` / `update` / `definitions apply` with HTTP 422 `unknown_effect_tag`; the body's `suggestion` is the closest valid tag. Fix the file, don't retry. The live list is `martha policy show --json` → `risk_tag_vocabulary`. Full table: `docs/reference/effect-tags.md`.
170
+
167
171
  ### Workflows CRUD + Execution
168
172
 
169
173
  ```bash