@aiaiai-pt/martha-cli 0.30.0 → 0.32.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 +104 -43
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3528,6 +3528,7 @@ var require_stringify = __commonJS((exports) => {
|
|
|
3528
3528
|
nullStr: "null",
|
|
3529
3529
|
simpleKeys: false,
|
|
3530
3530
|
singleQuote: null,
|
|
3531
|
+
trailingComma: false,
|
|
3531
3532
|
trueStr: "true",
|
|
3532
3533
|
verifyAliasOrder: true
|
|
3533
3534
|
}, doc.schema.toStringOptions, options);
|
|
@@ -4036,13 +4037,20 @@ ${indent}${line}` : `
|
|
|
4036
4037
|
if (comment)
|
|
4037
4038
|
reqNewline = true;
|
|
4038
4039
|
let str = stringify.stringify(item, itemCtx, () => comment = null);
|
|
4039
|
-
|
|
4040
|
+
reqNewline || (reqNewline = lines.length > linesAtValue || str.includes(`
|
|
4041
|
+
`));
|
|
4042
|
+
if (i < items.length - 1) {
|
|
4040
4043
|
str += ",";
|
|
4044
|
+
} else if (ctx.options.trailingComma) {
|
|
4045
|
+
if (ctx.options.lineWidth > 0) {
|
|
4046
|
+
reqNewline || (reqNewline = lines.reduce((sum, line) => sum + line.length + 2, 2) + (str.length + 2) > ctx.options.lineWidth);
|
|
4047
|
+
}
|
|
4048
|
+
if (reqNewline) {
|
|
4049
|
+
str += ",";
|
|
4050
|
+
}
|
|
4051
|
+
}
|
|
4041
4052
|
if (comment)
|
|
4042
4053
|
str += stringifyComment.lineComment(str, itemIndent, commentString(comment));
|
|
4043
|
-
if (!reqNewline && (lines.length > linesAtValue || str.includes(`
|
|
4044
|
-
`)))
|
|
4045
|
-
reqNewline = true;
|
|
4046
4054
|
lines.push(str);
|
|
4047
4055
|
linesAtValue = lines.length;
|
|
4048
4056
|
}
|
|
@@ -6837,17 +6845,22 @@ var require_compose_node = __commonJS((exports) => {
|
|
|
6837
6845
|
case "block-map":
|
|
6838
6846
|
case "block-seq":
|
|
6839
6847
|
case "flow-collection":
|
|
6840
|
-
|
|
6841
|
-
|
|
6842
|
-
|
|
6848
|
+
try {
|
|
6849
|
+
node = composeCollection.composeCollection(CN, ctx, token, props, onError);
|
|
6850
|
+
if (anchor)
|
|
6851
|
+
node.anchor = anchor.source.substring(1);
|
|
6852
|
+
} catch (error) {
|
|
6853
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6854
|
+
onError(token, "RESOURCE_EXHAUSTION", message);
|
|
6855
|
+
}
|
|
6843
6856
|
break;
|
|
6844
6857
|
default: {
|
|
6845
6858
|
const message = token.type === "error" ? token.message : `Unsupported token (type: ${token.type})`;
|
|
6846
6859
|
onError(token, "UNEXPECTED_TOKEN", message);
|
|
6847
|
-
node = composeEmptyNode(ctx, token.offset, undefined, null, props, onError);
|
|
6848
6860
|
isSrcToken = false;
|
|
6849
6861
|
}
|
|
6850
6862
|
}
|
|
6863
|
+
node ?? (node = composeEmptyNode(ctx, token.offset, undefined, null, props, onError));
|
|
6851
6864
|
if (anchor && node.anchor === "")
|
|
6852
6865
|
onError(anchor, "BAD_ALIAS", "Anchor cannot be an empty string");
|
|
6853
6866
|
if (atKey && ctx.options.stringKeys && (!identity.isScalar(node) || typeof node.value !== "string" || node.tag && node.tag !== "tag:yaml.org,2002:str")) {
|
|
@@ -11063,7 +11076,7 @@ init_config();
|
|
|
11063
11076
|
init_errors();
|
|
11064
11077
|
|
|
11065
11078
|
// src/version.ts
|
|
11066
|
-
var CLI_VERSION = "0.
|
|
11079
|
+
var CLI_VERSION = "0.32.0";
|
|
11067
11080
|
|
|
11068
11081
|
// src/commands/sessions.ts
|
|
11069
11082
|
function relativeTime(iso) {
|
|
@@ -16738,6 +16751,52 @@ function registerAskCommands(program2) {
|
|
|
16738
16751
|
import { readFileSync as readFileSync2 } from "node:fs";
|
|
16739
16752
|
init_errors();
|
|
16740
16753
|
var truncate2 = (s, n) => s.length > n ? s.slice(0, n - 1) + "…" : s;
|
|
16754
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
16755
|
+
async function resolveAgentId(ctx, ref) {
|
|
16756
|
+
if (UUID_RE.test(ref))
|
|
16757
|
+
return ref;
|
|
16758
|
+
try {
|
|
16759
|
+
const agent = await ctx.api.get(`/api/admin/definitions/agents/${encodeURIComponent(ref)}`);
|
|
16760
|
+
return agent.id;
|
|
16761
|
+
} catch {
|
|
16762
|
+
throw new CLIError(`Agent '${ref}' not found (pass a valid agent name or UUID)`, 4 /* Validation */);
|
|
16763
|
+
}
|
|
16764
|
+
}
|
|
16765
|
+
async function resolveTeamId(ctx, ref) {
|
|
16766
|
+
if (UUID_RE.test(ref))
|
|
16767
|
+
return ref;
|
|
16768
|
+
const teams = await ctx.api.get("/api/admin/teams");
|
|
16769
|
+
const match = (Array.isArray(teams) ? teams : []).find((t) => t.name === ref);
|
|
16770
|
+
if (!match) {
|
|
16771
|
+
throw new CLIError(`Team '${ref}' not found (pass a valid team name or UUID)`, 4 /* Validation */);
|
|
16772
|
+
}
|
|
16773
|
+
return match.id;
|
|
16774
|
+
}
|
|
16775
|
+
async function buildCreateTaskBody(ctx, opts) {
|
|
16776
|
+
if (opts.agent && opts.team) {
|
|
16777
|
+
throw new CLIError("--agent and --team are mutually exclusive — a task has one assignee", 4 /* Validation */);
|
|
16778
|
+
}
|
|
16779
|
+
const body = {
|
|
16780
|
+
goal: opts.goal,
|
|
16781
|
+
priority: opts.priority
|
|
16782
|
+
};
|
|
16783
|
+
if (opts.agent)
|
|
16784
|
+
body.agent_id = await resolveAgentId(ctx, opts.agent);
|
|
16785
|
+
if (opts.team)
|
|
16786
|
+
body.team_id = await resolveTeamId(ctx, opts.team);
|
|
16787
|
+
if (opts.title)
|
|
16788
|
+
body.title = opts.title;
|
|
16789
|
+
if (opts.context) {
|
|
16790
|
+
try {
|
|
16791
|
+
body.context_data = JSON.parse(opts.context);
|
|
16792
|
+
} catch {
|
|
16793
|
+
throw new CLIError("--context must be valid JSON", 4 /* Validation */);
|
|
16794
|
+
}
|
|
16795
|
+
}
|
|
16796
|
+
if (opts.sticky)
|
|
16797
|
+
body.sticky_assignment = true;
|
|
16798
|
+
return body;
|
|
16799
|
+
}
|
|
16741
16800
|
var sleep4 = (ms, signal) => new Promise((resolve2) => {
|
|
16742
16801
|
if (signal?.aborted) {
|
|
16743
16802
|
resolve2();
|
|
@@ -16876,30 +16935,13 @@ ${items.length} task(s)`));
|
|
|
16876
16935
|
}
|
|
16877
16936
|
console.log(`Open: ${source_default.yellow(data.open ?? 0)} ` + `Running: ${source_default.blue(data.running ?? 0)} ` + `Claimed: ${source_default.magenta(data.claimed ?? 0)} ` + `Completed: ${source_default.green(data.completed ?? 0)} ` + `Failed: ${source_default.red(data.failed ?? 0)} ` + `Cancelled: ${source_default.dim(data.cancelled ?? 0)}`);
|
|
16878
16937
|
});
|
|
16879
|
-
cmd.command("create").description("Create a
|
|
16938
|
+
cmd.command("create").description("Create a task. Assign it to an agent or a team to dispatch it, or omit " + "both to leave it in the backlog (#774: assignment is the dispatch moment).").requiredOption("--goal <text>", "Goal / instruction for the agent").option("--agent <name-or-id>", "Assign to an agent (dispatches; venue derives from its type)").option("--team <name-or-id>", "Assign to a team").option("--title <text>", "Short title for the task").option("--priority <priority>", "Priority (low, medium, high, urgent)", "medium").option("--context <json>", "Structured context as JSON string").option("--sticky", "Keep assignment even if agent goes offline").option("--no-auto-execute", "Deprecated (#774): venue now derives from the assignee. Accepted and ignored.").action(async (opts) => {
|
|
16880
16939
|
const ctx = getCtx();
|
|
16881
|
-
|
|
16882
|
-
|
|
16883
|
-
|
|
16884
|
-
priority: opts.priority
|
|
16885
|
-
};
|
|
16886
|
-
if (opts.title)
|
|
16887
|
-
body.title = opts.title;
|
|
16888
|
-
if (opts.context) {
|
|
16889
|
-
try {
|
|
16890
|
-
body.context_data = JSON.parse(opts.context);
|
|
16891
|
-
} catch {
|
|
16892
|
-
throw new CLIError("--context must be valid JSON", 4 /* Validation */);
|
|
16893
|
-
}
|
|
16940
|
+
if (opts.autoExecute === false) {
|
|
16941
|
+
process.stderr.write("Warning: --no-auto-execute is deprecated (#774) — the venue derives " + `from the assignee. Ignoring.
|
|
16942
|
+
`);
|
|
16894
16943
|
}
|
|
16895
|
-
|
|
16896
|
-
body.assigned_team_id = opts.team;
|
|
16897
|
-
if (opts.assignedAgent)
|
|
16898
|
-
body.assigned_agent_id = opts.assignedAgent;
|
|
16899
|
-
if (opts.sticky)
|
|
16900
|
-
body.sticky_assignment = true;
|
|
16901
|
-
if (opts.autoExecute === false)
|
|
16902
|
-
body.auto_execute = false;
|
|
16944
|
+
const body = await buildCreateTaskBody(ctx, opts);
|
|
16903
16945
|
const result = await ctx.api.post("/api/admin/tasks", body);
|
|
16904
16946
|
if (isJson()) {
|
|
16905
16947
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -16959,7 +17001,7 @@ ${source_default.red("Error:")}`);
|
|
|
16959
17001
|
}
|
|
16960
17002
|
console.log(`Cancelled task ${id}`);
|
|
16961
17003
|
});
|
|
16962
|
-
cmd.command("poll").description("Poll for open tasks available for claiming").option("--agent <id>", "Filter by agent definition ID").option("--limit <n>", "Max results", "10").action(async (opts) => {
|
|
17004
|
+
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) => {
|
|
16963
17005
|
const ctx = getCtx();
|
|
16964
17006
|
const limitN = parseInt(opts.limit, 10);
|
|
16965
17007
|
if (isNaN(limitN) || limitN < 1) {
|
|
@@ -16968,6 +17010,8 @@ ${source_default.red("Error:")}`);
|
|
|
16968
17010
|
const params = { limit: String(limitN) };
|
|
16969
17011
|
if (opts.agent)
|
|
16970
17012
|
params.agent_id = opts.agent;
|
|
17013
|
+
if (opts.team)
|
|
17014
|
+
params.team_id = opts.team;
|
|
16971
17015
|
const items = await ctx.api.get("/api/tasks/poll", { params });
|
|
16972
17016
|
if (isJson()) {
|
|
16973
17017
|
console.log(JSON.stringify(items, null, 2));
|
|
@@ -17226,16 +17270,18 @@ function heartbeatIntervalMs(leaseTimeoutS) {
|
|
|
17226
17270
|
return Math.min(lease / 3, 60) * 1000;
|
|
17227
17271
|
}
|
|
17228
17272
|
async function runOnce(ctx, opts, handled) {
|
|
17229
|
-
const
|
|
17230
|
-
|
|
17231
|
-
|
|
17273
|
+
const params = { limit: String(opts.pollLimit ?? 5) };
|
|
17274
|
+
if (opts.team)
|
|
17275
|
+
params.team_id = opts.team;
|
|
17276
|
+
const tasks = await ctx.api.get("/api/tasks/poll", { params });
|
|
17232
17277
|
const candidates = Array.isArray(tasks) ? tasks : [];
|
|
17233
|
-
const
|
|
17278
|
+
const matchesAgent = (t) => !opts.agent || t.assigned_agent_id === opts.agent || t.agent_definition_id === opts.agent;
|
|
17279
|
+
const task = candidates.find((t) => (t.status ?? "open") === "open" && !handled?.has(t.id) && matchesAgent(t));
|
|
17234
17280
|
if (!task)
|
|
17235
17281
|
return { ran: false };
|
|
17236
|
-
if (!opts.
|
|
17282
|
+
if (!opts.allowHostExec) {
|
|
17237
17283
|
process.stderr.write(source_default.yellow(`
|
|
17238
|
-
[runner] refused task ${task.id} — re-run with --
|
|
17284
|
+
[runner] refused task ${task.id} — re-run with --allow-host-exec to allow host execution
|
|
17239
17285
|
`));
|
|
17240
17286
|
return { ran: false, taskId: task.id, status: "refused" };
|
|
17241
17287
|
}
|
|
@@ -17297,8 +17343,14 @@ async function runOnce(ctx, opts, handled) {
|
|
|
17297
17343
|
`));
|
|
17298
17344
|
return { ran: true, taskId: task.id, status, exitCode: exit_code };
|
|
17299
17345
|
}
|
|
17346
|
+
function startupEchoLine(who, opts) {
|
|
17347
|
+
const identity2 = who ? who.kind === "agent" ? `agent ${who.agent_name ?? "?"} (${(who.agent_id ?? "").slice(0, 8)}…)` : `${who.kind} ${who.sub ?? ""}`.trim() : "identity unknown (whoami unavailable)";
|
|
17348
|
+
const scope = opts.team ? `team:${opts.team}` : "direct";
|
|
17349
|
+
const exec = opts.allowHostExec ? "host exec allowed" : "host exec refused (pass --allow-host-exec)";
|
|
17350
|
+
return `[runner] authenticated as ${identity2}, scope ${scope}, cwd ${opts.cwd}, ${exec}${opts.once ? " — once" : ""}`;
|
|
17351
|
+
}
|
|
17300
17352
|
function registerRunnerCommand(program2) {
|
|
17301
|
-
program2.command("runner").description("Run as an external agent's executor: claim tasks and run them on this host.").
|
|
17353
|
+
program2.command("runner").description("Run as an external agent's executor: claim tasks and run them on this host.").option("--agent <id>", "Deprecated: identity comes from the API token; applied as a client-side filter only").option("--team <name>", "Poll this team's queue (name or UUID) instead of direct-only").option("--once", "Claim + run a single task, then exit").option("--poll-interval <ms>", "Poll interval when idle (ms)", "3000").option("--cwd <dir>", "Scoped workspace for task execution", process.cwd()).option("--allow-host-exec", "Consent to run host commands (required to execute)").option("--yes", "Deprecated alias for --allow-host-exec").action(async (opts) => {
|
|
17302
17354
|
const ctx = createContext({
|
|
17303
17355
|
profileOverride: program2.opts().profile,
|
|
17304
17356
|
verbose: program2.opts().verbose
|
|
@@ -17309,12 +17361,21 @@ function registerRunnerCommand(program2) {
|
|
|
17309
17361
|
if (isNaN(pollInterval) || pollInterval < 250) {
|
|
17310
17362
|
throw new CLIError("--poll-interval must be >= 250 (ms)", 4 /* Validation */);
|
|
17311
17363
|
}
|
|
17364
|
+
if (opts.agent) {
|
|
17365
|
+
process.stderr.write(source_default.yellow(`[runner] --agent is deprecated — identity comes from the API token; the value is applied as a client-side filter only
|
|
17366
|
+
`));
|
|
17367
|
+
}
|
|
17312
17368
|
const runOpts = {
|
|
17313
17369
|
agent: opts.agent,
|
|
17370
|
+
team: opts.team,
|
|
17314
17371
|
cwd: opts.cwd,
|
|
17315
|
-
|
|
17372
|
+
allowHostExec: !!(opts.allowHostExec || opts.yes)
|
|
17316
17373
|
};
|
|
17317
|
-
|
|
17374
|
+
let who;
|
|
17375
|
+
try {
|
|
17376
|
+
who = await ctx.api.get("/api/tasks/whoami");
|
|
17377
|
+
} catch {}
|
|
17378
|
+
process.stderr.write(source_default.dim(`${startupEchoLine(who, { team: opts.team, cwd: opts.cwd, allowHostExec: runOpts.allowHostExec, once: !!opts.once })}
|
|
17318
17379
|
`));
|
|
17319
17380
|
if (opts.once) {
|
|
17320
17381
|
await runOnce(ctx, runOpts);
|
|
@@ -20392,9 +20453,9 @@ init_errors();
|
|
|
20392
20453
|
|
|
20393
20454
|
// src/lib/collections.ts
|
|
20394
20455
|
init_errors();
|
|
20395
|
-
var
|
|
20456
|
+
var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
20396
20457
|
async function resolveCollectionIdForGrant(ctx, ref) {
|
|
20397
|
-
if (
|
|
20458
|
+
if (UUID_RE2.test(ref)) {
|
|
20398
20459
|
return ref;
|
|
20399
20460
|
}
|
|
20400
20461
|
const all = await ctx.api.get("/api/admin/collections", {
|