@aiaiai-pt/martha-cli 0.66.0 → 0.68.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/CHANGELOG.md +23 -0
- package/dist/index.js +91 -16
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,29 @@
|
|
|
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.0] — 2026-11-02
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `martha prompts version <name> -f <file> [-m <summary>] [--promote [environment]]` creates a new version of a prompt from the file's `content` (the server's `POST /prompts/{name}/versions`) and can promote it in the same step. Until now the CLI had no way to change a prompt's text.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- `martha prompts promote <name>` sends the version and environment the server requires (`--version`, default the newest; `--environment`, default `production`). It used to send `{}`, which the server rejects.
|
|
14
|
+
- `martha prompts update -f <file>` refuses a file with `content` and points at `prompts version`. The update route only changes metadata, so the content was silently dropped while the CLI printed "Updated (v1)".
|
|
15
|
+
|
|
16
|
+
## [0.67.0] — 2026-11-02
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- `martha tasks note <id> <text>` posts a human-lane note to a task's activity log through the existing `POST /api/admin/tasks/{id}/activity` (entry type comment, author set by the server). Empty or whitespace-only text is refused before any request. `--json` prints the created entry (#2377).
|
|
21
|
+
|
|
22
|
+
## [0.66.1] — 2026-11-01
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- `martha runner` and `martha chat --local-exec` no longer run a host command when its gate cannot be claimed. A claim that fails with a network error or 5xx is retried twice, then the gate is skipped. Previously any non-409 failure fell through to execution, and the server, which enforces the claim, rejected the result, so the command ran with nowhere to report. This is what happened for runs Temporal no longer had (#1859).
|
|
27
|
+
|
|
5
28
|
## [0.66.0] — 2026-11-01
|
|
6
29
|
|
|
7
30
|
### Added
|
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.
|
|
11247
|
+
var CLI_VERSION = "0.68.0";
|
|
11248
11248
|
|
|
11249
11249
|
// src/commands/sessions.ts
|
|
11250
11250
|
function relativeTime(iso) {
|
|
@@ -13546,6 +13546,7 @@ async function resolveLocalAgent(sessionId, toolCallId, req, state) {
|
|
|
13546
13546
|
log_path: result.log_path
|
|
13547
13547
|
};
|
|
13548
13548
|
}
|
|
13549
|
+
var CLAIM_RETRY = { delaysMs: [1000, 3000] };
|
|
13549
13550
|
async function claimGate(sessionId, toolCallId, state, transport) {
|
|
13550
13551
|
if (state.claimed.has(toolCallId))
|
|
13551
13552
|
return true;
|
|
@@ -13553,19 +13554,25 @@ async function claimGate(sessionId, toolCallId, state, transport) {
|
|
|
13553
13554
|
const secretHash = createHash2("sha256").update(secret).digest("hex");
|
|
13554
13555
|
state.secrets.set(toolCallId, secret);
|
|
13555
13556
|
await state.journal.recordSecret(sessionId, toolCallId, secret);
|
|
13556
|
-
|
|
13557
|
-
|
|
13558
|
-
|
|
13559
|
-
|
|
13560
|
-
|
|
13561
|
-
|
|
13562
|
-
|
|
13557
|
+
for (let attempt = 0;; attempt++) {
|
|
13558
|
+
try {
|
|
13559
|
+
await transport.claim(toolCallId, secretHash);
|
|
13560
|
+
state.claimed.add(toolCallId);
|
|
13561
|
+
return true;
|
|
13562
|
+
} catch (e) {
|
|
13563
|
+
if (e instanceof MarthaAPIError && e.status === 409) {
|
|
13564
|
+
process.stderr.write(source_default.yellow(`[local-exec] gate ${toolCallId} is not pending (already resolved or timed out) — skipping execution
|
|
13563
13565
|
`));
|
|
13564
|
-
|
|
13565
|
-
|
|
13566
|
-
|
|
13566
|
+
return false;
|
|
13567
|
+
}
|
|
13568
|
+
const final = e instanceof MarthaAPIError && e.status >= 400 && e.status < 500;
|
|
13569
|
+
if (final || attempt >= CLAIM_RETRY.delaysMs.length) {
|
|
13570
|
+
process.stderr.write(source_default.yellow(`[local-exec] failed to claim gate for ${toolCallId}: ${String(e)} — skipping execution
|
|
13567
13571
|
`));
|
|
13568
|
-
|
|
13572
|
+
return false;
|
|
13573
|
+
}
|
|
13574
|
+
await new Promise((r) => setTimeout(r, CLAIM_RETRY.delaysMs[attempt]));
|
|
13575
|
+
}
|
|
13569
13576
|
}
|
|
13570
13577
|
}
|
|
13571
13578
|
async function postToolResult(toolCallId, result, label, transport, execSecret) {
|
|
@@ -17703,7 +17710,32 @@ var workflowsConfig = {
|
|
|
17703
17710
|
};
|
|
17704
17711
|
|
|
17705
17712
|
// src/commands/prompts.ts
|
|
17713
|
+
init_errors();
|
|
17706
17714
|
var API_PATH2 = "/api/admin/definitions/prompts";
|
|
17715
|
+
var ENVIRONMENTS = ["production", "staging"];
|
|
17716
|
+
function promptVersionBody(file, changeSummary) {
|
|
17717
|
+
const content = typeof file.content === "string" ? file.content : "";
|
|
17718
|
+
if (!content.trim()) {
|
|
17719
|
+
throw new CLIError("The file has no `content` to version", 4 /* Validation */, "A prompt version is the whole prompt text: put it under `content:`.");
|
|
17720
|
+
}
|
|
17721
|
+
return changeSummary ? { content, change_summary: changeSummary } : { content };
|
|
17722
|
+
}
|
|
17723
|
+
function promptPromoteBody(version, environment = "production") {
|
|
17724
|
+
if (!Number.isInteger(version) || version < 1) {
|
|
17725
|
+
throw new CLIError(`Invalid version '${version}'`, 4 /* Validation */);
|
|
17726
|
+
}
|
|
17727
|
+
if (!ENVIRONMENTS.includes(environment)) {
|
|
17728
|
+
throw new CLIError(`Invalid environment '${environment}'`, 4 /* Validation */, `Use one of: ${ENVIRONMENTS.join(", ")}`);
|
|
17729
|
+
}
|
|
17730
|
+
return { version, environment };
|
|
17731
|
+
}
|
|
17732
|
+
function latestVersionNumber(data) {
|
|
17733
|
+
const rows = (Array.isArray(data) ? data : data?.items) ?? [];
|
|
17734
|
+
const nums = rows.map((r) => Number(r.version)).filter((n) => Number.isInteger(n) && n > 0);
|
|
17735
|
+
if (!nums.length)
|
|
17736
|
+
throw new CLIError("The prompt has no versions", 1 /* Error */);
|
|
17737
|
+
return Math.max(...nums);
|
|
17738
|
+
}
|
|
17707
17739
|
var promptsConfig = {
|
|
17708
17740
|
typeName: "prompt",
|
|
17709
17741
|
typeNamePlural: "prompts",
|
|
@@ -17785,16 +17817,43 @@ var promptsConfig = {
|
|
|
17785
17817
|
params.is_protected = "true";
|
|
17786
17818
|
return params;
|
|
17787
17819
|
},
|
|
17820
|
+
normalizeBody: (body) => {
|
|
17821
|
+
if ("content" in body) {
|
|
17822
|
+
throw new CLIError("`prompts update` changes metadata only and the server ignores `content`; change the text with " + "`martha prompts version <name> -f <file> --promote`", 4 /* Validation */);
|
|
17823
|
+
}
|
|
17824
|
+
return body;
|
|
17825
|
+
},
|
|
17788
17826
|
extraCommands: (parentCmd, getCtx, isJson) => {
|
|
17789
|
-
|
|
17827
|
+
const promote = async (ctx, name, version, environment) => ctx.api.post(`${API_PATH2}/${encodeURIComponent(name)}/promote`, promptPromoteBody(version, environment));
|
|
17828
|
+
parentCmd.command("version <name>").description("Create a new version of a prompt from a file's `content` (optionally promote it)").requiredOption("-f, --file <path>", "YAML or JSON file with a `content` field").option("-m, --summary <text>", "What changed in this version").option("--promote [environment]", "Promote the new version (default: production)").action(async (name, opts) => {
|
|
17790
17829
|
const ctx = getCtx();
|
|
17791
|
-
const
|
|
17830
|
+
const body = promptVersionBody(loadDefinitionFile(opts.file), opts.summary);
|
|
17831
|
+
const created = await ctx.api.post(`${API_PATH2}/${encodeURIComponent(name)}/versions`, body);
|
|
17832
|
+
const version = Number(created.version);
|
|
17833
|
+
let promoted;
|
|
17834
|
+
if (opts.promote) {
|
|
17835
|
+
const env = typeof opts.promote === "string" ? opts.promote : "production";
|
|
17836
|
+
promoted = await promote(ctx, name, version, env);
|
|
17837
|
+
}
|
|
17838
|
+
if (isJson()) {
|
|
17839
|
+
console.log(JSON.stringify({ version: created, promoted }, null, 2));
|
|
17840
|
+
return;
|
|
17841
|
+
}
|
|
17842
|
+
console.log(`Created '${name}' version ${version}`);
|
|
17843
|
+
if (opts.promote) {
|
|
17844
|
+
const env = typeof opts.promote === "string" ? opts.promote : "production";
|
|
17845
|
+
console.log(`Promoted '${name}' version ${version} → ${env}`);
|
|
17846
|
+
}
|
|
17847
|
+
});
|
|
17848
|
+
parentCmd.command("promote <name>").description("Promote a version (default: the newest) to an environment (default: production)").option("--version <n>", "Version number to promote", (v) => Number(v)).option("--environment <env>", "production | staging", "production").action(async (name, opts) => {
|
|
17849
|
+
const ctx = getCtx();
|
|
17850
|
+
const version = opts.version ?? latestVersionNumber(await ctx.api.get(`${API_PATH2}/${encodeURIComponent(name)}/versions`));
|
|
17851
|
+
const result = await promote(ctx, name, version, opts.environment);
|
|
17792
17852
|
if (isJson()) {
|
|
17793
17853
|
console.log(JSON.stringify(result, null, 2));
|
|
17794
17854
|
return;
|
|
17795
17855
|
}
|
|
17796
|
-
|
|
17797
|
-
console.log(`Promoted '${name}' staging → production (version ${prodVer})`);
|
|
17856
|
+
console.log(`Promoted '${name}' version ${version} → ${opts.environment}`);
|
|
17798
17857
|
});
|
|
17799
17858
|
parentCmd.command("linked-collections <name>").description("List collections using this prompt as an extra prompt").action(async (name) => {
|
|
17800
17859
|
const ctx = getCtx();
|
|
@@ -19262,6 +19321,13 @@ var priorityColor = (priority) => {
|
|
|
19262
19321
|
return priority;
|
|
19263
19322
|
}
|
|
19264
19323
|
};
|
|
19324
|
+
function buildNoteBody(text) {
|
|
19325
|
+
const content = text.trim();
|
|
19326
|
+
if (!content) {
|
|
19327
|
+
throw new CLIError("Note text must not be empty", 4 /* Validation */);
|
|
19328
|
+
}
|
|
19329
|
+
return { content };
|
|
19330
|
+
}
|
|
19265
19331
|
function registerTaskCommands(program) {
|
|
19266
19332
|
const cmd = program.command("tasks").description("Manage agent tasks");
|
|
19267
19333
|
function getCtx() {
|
|
@@ -19418,6 +19484,15 @@ ${source_default.red("Error:")}`);
|
|
|
19418
19484
|
}
|
|
19419
19485
|
console.log(`Cancelled task ${id}`);
|
|
19420
19486
|
});
|
|
19487
|
+
cmd.command("note <id> <text>").description("Add a note to a task's activity log (human lane)").action(async (id, text) => {
|
|
19488
|
+
const ctx = getCtx();
|
|
19489
|
+
const entry = await ctx.api.post(`/api/admin/tasks/${encodeURIComponent(id)}/activity`, buildNoteBody(text));
|
|
19490
|
+
if (isJson()) {
|
|
19491
|
+
console.log(JSON.stringify(entry, null, 2));
|
|
19492
|
+
return;
|
|
19493
|
+
}
|
|
19494
|
+
console.log(`Noted task ${id} (entry ${entry.id ?? "?"})`);
|
|
19495
|
+
});
|
|
19421
19496
|
cmd.command("poll").description("Poll for open tasks available for claiming").option("--agent <id>", "Filter by agent definition ID (human tokens only; ignored under agent auth)").option("--team <name>", "Poll a team's queue (name or UUID)").option("--limit <n>", "Max results", "10").action(async (opts) => {
|
|
19422
19497
|
const ctx = getCtx();
|
|
19423
19498
|
const limitN = parseInt(opts.limit, 10);
|