@aiaiai-pt/martha-cli 0.9.0 → 0.10.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 +12 -0
- package/dist/index.js +45 -12
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@ All notable changes to `@aiaiai-pt/martha-cli`. Format: [Keep a Changelog](https
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.10.0] — 2026-06-10
|
|
8
|
+
|
|
9
|
+
### Added — #540 Phase 2.0/2.1 chat copilot + task operator
|
|
10
|
+
- `martha init --agent` provisions a personal **chat copilot** alongside the run-as bootstrap: a `cloud` agent (no extra credentials) linked to your client, with the intent's tools granted to the **agent** surface (where agent grants fire in chat). `--agent-name` names it; `--model` overrides the model (defaults to the platform default). Persists `default_agent` to the profile.
|
|
11
|
+
- `martha chat` now defaults to your bootstrapped client + copilot so its tools work out of the box; `--agent <name>` selects a specific copilot.
|
|
12
|
+
- **Task operator**: with the `tasks` intent, the copilot can `create_task` / `list_tasks` / `get_task` — tasks run on Martha's task pipeline and are scoped to the copilot's own tasks. (Backend platform functions; surfaced through chat.)
|
|
13
|
+
|
|
14
|
+
## [0.9.1] — 2026-06-10
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- `martha --version` (and the `martha doctor` CLI/API version-skew check) reported a stale `0.3.0` — `src/version.ts` was a hand-maintained constant that never got bumped after the 0.3.0 release, so six releases shipped the wrong version string. It's now generated from `package.json` at build time (`scripts/gen-version.mjs`, run first in `build`/`prepack`), keeping the runtime constant (no bundled-path `package.json` read) while making `package.json` the single source of truth. A unit test fails if the two ever drift again.
|
|
18
|
+
|
|
7
19
|
## [0.9.0] — 2026-06-10
|
|
8
20
|
|
|
9
21
|
### Added — #535 Phase 1 onboarding bootstrap
|
package/dist/index.js
CHANGED
|
@@ -11051,7 +11051,7 @@ import { createInterface as createInterface2 } from "node:readline";
|
|
|
11051
11051
|
init_errors();
|
|
11052
11052
|
|
|
11053
11053
|
// src/version.ts
|
|
11054
|
-
var CLI_VERSION = "0.
|
|
11054
|
+
var CLI_VERSION = "0.10.0";
|
|
11055
11055
|
|
|
11056
11056
|
// src/commands/sessions.ts
|
|
11057
11057
|
function relativeTime(iso) {
|
|
@@ -11204,8 +11204,13 @@ async function sendMessage(ctx, sessionId, message, opts = {}) {
|
|
|
11204
11204
|
signal: opts.signal,
|
|
11205
11205
|
timeout: opts.timeoutMs ?? DEFAULT_CHAT_TIMEOUT_MS
|
|
11206
11206
|
};
|
|
11207
|
-
if (opts.clientId) {
|
|
11208
|
-
|
|
11207
|
+
if (opts.clientId || opts.agentName) {
|
|
11208
|
+
const params = {};
|
|
11209
|
+
if (opts.clientId)
|
|
11210
|
+
params.selected_client = opts.clientId;
|
|
11211
|
+
if (opts.agentName)
|
|
11212
|
+
params.selected_agent = opts.agentName;
|
|
11213
|
+
reqOpts.params = params;
|
|
11209
11214
|
}
|
|
11210
11215
|
const res = await ctx.api.postRaw(`/api/chat/${encodeURIComponent(sessionId)}`, { content: message }, reqOpts);
|
|
11211
11216
|
const contentType = res.headers.get("content-type") ?? "";
|
|
@@ -11375,7 +11380,7 @@ async function showHistoryPicker(ctx, rl) {
|
|
|
11375
11380
|
}
|
|
11376
11381
|
return data.items[idx].session_id;
|
|
11377
11382
|
}
|
|
11378
|
-
async function runRepl(ctx, initialSessionId, clientId, showTools, timeoutMs) {
|
|
11383
|
+
async function runRepl(ctx, initialSessionId, clientId, agentName, showTools, timeoutMs) {
|
|
11379
11384
|
let sessionId = initialSessionId;
|
|
11380
11385
|
process.stderr.write(source_default.dim(`martha v${CLI_VERSION} | session: ${sessionId.slice(0, 8)}...
|
|
11381
11386
|
`));
|
|
@@ -11483,7 +11488,8 @@ async function runRepl(ctx, initialSessionId, clientId, showTools, timeoutMs) {
|
|
|
11483
11488
|
onClear: showTools ? () => process.stderr.write(source_default.dim(` --- tool iteration ---
|
|
11484
11489
|
`)) : undefined,
|
|
11485
11490
|
signal: activeAbort.signal,
|
|
11486
|
-
clientId
|
|
11491
|
+
clientId,
|
|
11492
|
+
agentName
|
|
11487
11493
|
});
|
|
11488
11494
|
if (!result.aborted) {
|
|
11489
11495
|
process.stdout.write(`
|
|
@@ -11511,7 +11517,7 @@ Error: ${err instanceof Error ? err.message : String(err)}
|
|
|
11511
11517
|
process.stderr.write(`
|
|
11512
11518
|
`);
|
|
11513
11519
|
}
|
|
11514
|
-
async function runOneShot(ctx, sessionId, message, isJson, clientId, showTools, timeoutMs) {
|
|
11520
|
+
async function runOneShot(ctx, sessionId, message, isJson, clientId, agentName, showTools, timeoutMs) {
|
|
11515
11521
|
const toolCalls = [];
|
|
11516
11522
|
function recordToolStatus(data) {
|
|
11517
11523
|
try {
|
|
@@ -11533,6 +11539,7 @@ async function runOneShot(ctx, sessionId, message, isJson, clientId, showTools,
|
|
|
11533
11539
|
}
|
|
11534
11540
|
const { response } = await sendMessage(ctx, sessionId, message, {
|
|
11535
11541
|
clientId,
|
|
11542
|
+
agentName,
|
|
11536
11543
|
timeoutMs,
|
|
11537
11544
|
onToolStatus: isJson ? recordToolStatus : showTools ? (data) => {
|
|
11538
11545
|
recordToolStatus(data);
|
|
@@ -11557,7 +11564,7 @@ async function runOneShot(ctx, sessionId, message, isJson, clientId, showTools,
|
|
|
11557
11564
|
}
|
|
11558
11565
|
}
|
|
11559
11566
|
function registerChatCommand(program2) {
|
|
11560
|
-
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("--message <text>", "Send a single message (non-interactive)").option("--show-tools", "Show tool calls and results during chat").option("--timeout <seconds>", "Per-message HTTP timeout in seconds (default: 600)").action(async (opts) => {
|
|
11567
|
+
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("--timeout <seconds>", "Per-message HTTP timeout in seconds (default: 600)").action(async (opts) => {
|
|
11561
11568
|
const ctx = createContext({
|
|
11562
11569
|
profileOverride: program2.opts().profile,
|
|
11563
11570
|
verbose: program2.opts().verbose
|
|
@@ -11580,6 +11587,10 @@ function registerChatCommand(program2) {
|
|
|
11580
11587
|
clientId = String(match.id);
|
|
11581
11588
|
}
|
|
11582
11589
|
}
|
|
11590
|
+
if (!clientId && ctx.profile.default_client) {
|
|
11591
|
+
clientId = ctx.profile.default_client;
|
|
11592
|
+
}
|
|
11593
|
+
const agentName = opts.agent ?? ctx.profile.default_agent;
|
|
11583
11594
|
let sessionId;
|
|
11584
11595
|
if (opts.session) {
|
|
11585
11596
|
sessionId = opts.session;
|
|
@@ -11589,12 +11600,12 @@ function registerChatCommand(program2) {
|
|
|
11589
11600
|
const showTools = !!opts.showTools;
|
|
11590
11601
|
const timeoutMs = opts.timeout ? parseTimeoutSeconds(opts.timeout) * 1000 : undefined;
|
|
11591
11602
|
if (opts.message) {
|
|
11592
|
-
await runOneShot(ctx, sessionId, opts.message, isJson, clientId, showTools, timeoutMs);
|
|
11603
|
+
await runOneShot(ctx, sessionId, opts.message, isJson, clientId, agentName, showTools, timeoutMs);
|
|
11593
11604
|
} else {
|
|
11594
11605
|
if (isJson) {
|
|
11595
11606
|
throw new CLIError("The --json flag requires --message for non-interactive mode.", 4 /* Validation */, 'Example: martha --json chat --message "hello"');
|
|
11596
11607
|
}
|
|
11597
|
-
await runRepl(ctx, sessionId, clientId, showTools, timeoutMs);
|
|
11608
|
+
await runRepl(ctx, sessionId, clientId, agentName, showTools, timeoutMs);
|
|
11598
11609
|
}
|
|
11599
11610
|
});
|
|
11600
11611
|
}
|
|
@@ -17732,26 +17743,36 @@ Provision an access principal now so calls just work?`, true);
|
|
|
17732
17743
|
if (intents.length === 0 && workflows.length === 0 && functions.length === 0) {
|
|
17733
17744
|
throw new CLIError("Nothing to grant: declare at least one --intent (rag/documents/workflows/custom) or a --workflow/--function.", 4 /* Validation */);
|
|
17734
17745
|
}
|
|
17746
|
+
let wantAgent = mode === "human" && !!opts.agent;
|
|
17747
|
+
if (mode === "human" && !opts.agent && interactive) {
|
|
17748
|
+
wantAgent = await askYesNo(`
|
|
17749
|
+
Also set up a chat copilot you can talk to (martha chat)?`, true);
|
|
17750
|
+
}
|
|
17735
17751
|
const ctx = createContext({ profileOverride: profileName });
|
|
17736
17752
|
if (opts.apiUrl)
|
|
17737
17753
|
ctx.profile.api_url = opts.apiUrl;
|
|
17738
17754
|
await ensureAuthenticated(ctx, interactive, jsonMode);
|
|
17739
17755
|
if (!jsonMode) {
|
|
17740
17756
|
console.log();
|
|
17741
|
-
console.log(source_default.dim(` Provisioning ${mode === "integration" ? "an integration service account" : "your access principal"}…`));
|
|
17757
|
+
console.log(source_default.dim(` Provisioning ${mode === "integration" ? "an integration service account" : "your access principal"}${wantAgent ? " + copilot" : ""}…`));
|
|
17742
17758
|
}
|
|
17743
17759
|
const body = {
|
|
17744
17760
|
mode,
|
|
17745
17761
|
intents,
|
|
17746
17762
|
workflows,
|
|
17747
17763
|
functions,
|
|
17748
|
-
...opts.label ? { label: opts.label } : {}
|
|
17764
|
+
...opts.label ? { label: opts.label } : {},
|
|
17765
|
+
...wantAgent ? { agent: true } : {},
|
|
17766
|
+
...wantAgent && opts.agentName ? { agent_name: opts.agentName } : {},
|
|
17767
|
+
...wantAgent && opts.model ? { model: opts.model } : {}
|
|
17749
17768
|
};
|
|
17750
17769
|
const resp = await ctx.api.post("/api/admin/definitions/principals/bootstrap", body);
|
|
17751
17770
|
if (mode === "human" && resp.client_key) {
|
|
17752
17771
|
const cfg = loadConfig();
|
|
17753
17772
|
if (cfg.profiles[profileName]) {
|
|
17754
17773
|
cfg.profiles[profileName].default_client = resp.client_key;
|
|
17774
|
+
if (resp.agent)
|
|
17775
|
+
cfg.profiles[profileName].default_agent = resp.agent.name;
|
|
17755
17776
|
saveConfig(cfg);
|
|
17756
17777
|
}
|
|
17757
17778
|
}
|
|
@@ -17799,6 +17820,15 @@ function printBootstrapResult(resp, profileName) {
|
|
|
17799
17820
|
for (const s of resp.skipped) {
|
|
17800
17821
|
console.log(source_default.yellow(` Skipped ${s.name} — ${s.reason}`));
|
|
17801
17822
|
}
|
|
17823
|
+
if (resp.agent) {
|
|
17824
|
+
const a = resp.agent;
|
|
17825
|
+
console.log();
|
|
17826
|
+
const averb = a.adopted ? "Using existing" : "Created";
|
|
17827
|
+
console.log(source_default.green(` ${averb} copilot ${source_default.bold(a.name)}.`));
|
|
17828
|
+
if (a.granted_functions.length > 0) {
|
|
17829
|
+
console.log(` Copilot tools: ${source_default.cyan(a.granted_functions.join(", "))}`);
|
|
17830
|
+
}
|
|
17831
|
+
}
|
|
17802
17832
|
if (resp.service_account) {
|
|
17803
17833
|
const sa = resp.service_account;
|
|
17804
17834
|
console.log();
|
|
@@ -17813,6 +17843,9 @@ function printBootstrapResult(resp, profileName) {
|
|
|
17813
17843
|
console.log(source_default.dim(` Profile ${source_default.cyan(profileName)} will now run as this client.`));
|
|
17814
17844
|
console.log();
|
|
17815
17845
|
console.log(source_default.dim(" Next:"));
|
|
17846
|
+
if (resp.agent) {
|
|
17847
|
+
console.log(source_default.dim(' martha chat "what can you do?"'));
|
|
17848
|
+
}
|
|
17816
17849
|
console.log(source_default.dim(" martha workflows list"));
|
|
17817
17850
|
console.log(source_default.dim(" martha workflows execute <name> --inputs '{}'"));
|
|
17818
17851
|
}
|
|
@@ -17869,7 +17902,7 @@ async function askIntents() {
|
|
|
17869
17902
|
return parseIntents(raw);
|
|
17870
17903
|
}
|
|
17871
17904
|
function registerInitCommand(program2) {
|
|
17872
|
-
program2.command("init").description("Create or update a profile, and optionally bootstrap an access principal").option("--preset <name>", "Preset: cloud or local", "cloud").option("--name <name>", "Profile name (defaults to preset name)").option("--force", "Overwrite an existing profile").option("--api-url <url>", "Override the API URL").option("--keycloak-url <url>", "Override the Keycloak URL").option("--keycloak-realm <realm>", "Override the Keycloak realm").option("--no-interactive", "Skip prompts; use defaults / overrides only").option("--bootstrap", "Provision an intent-scoped principal + grants after saving the profile").option("--mode <mode>", "Bootstrap mode: 'human' (your own client) or 'integration' (service account)").option("--intent <intents...>", "Usage buckets to grant: rag, documents, workflows, custom").option("--workflow <names...>", "Workflow name(s) to grant (workflows/custom intent)").option("--function <names...>", "Extra function name(s) to grant (custom intent)").option("--label <name>", "Integration mode: label for the SA client id").option("--yes", "Acknowledge non-interactive bootstrap side effects").action(async (opts, command) => {
|
|
17905
|
+
program2.command("init").description("Create or update a profile, and optionally bootstrap an access principal").option("--preset <name>", "Preset: cloud or local", "cloud").option("--name <name>", "Profile name (defaults to preset name)").option("--force", "Overwrite an existing profile").option("--api-url <url>", "Override the API URL").option("--keycloak-url <url>", "Override the Keycloak URL").option("--keycloak-realm <realm>", "Override the Keycloak realm").option("--no-interactive", "Skip prompts; use defaults / overrides only").option("--bootstrap", "Provision an intent-scoped principal + grants after saving the profile").option("--mode <mode>", "Bootstrap mode: 'human' (your own client) or 'integration' (service account)").option("--intent <intents...>", "Usage buckets to grant: rag, documents, workflows, custom").option("--workflow <names...>", "Workflow name(s) to grant (workflows/custom intent)").option("--function <names...>", "Extra function name(s) to grant (custom intent)").option("--label <name>", "Integration mode: label for the SA client id").option("--agent", "Also provision a personal chat copilot (human mode) and set it as the default").option("--agent-name <name>", "Copilot agent name (defaults to copilot-{user})").option("--model <id>", "Copilot LLM model id (defaults to the platform default)").option("--yes", "Acknowledge non-interactive bootstrap side effects").action(async (opts, command) => {
|
|
17873
17906
|
const globals = command.parent?.opts() ?? {};
|
|
17874
17907
|
await initCommand({ ...opts, json: !!globals.json });
|
|
17875
17908
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiaiai-pt/martha-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Terminal-first client for the Martha AI platform",
|
|
5
5
|
"homepage": "https://docs.martha.nomadriver.co",
|
|
6
6
|
"repository": {
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"access": "public"
|
|
31
31
|
},
|
|
32
32
|
"scripts": {
|
|
33
|
-
"
|
|
33
|
+
"gen-version": "node scripts/gen-version.mjs",
|
|
34
|
+
"build": "node scripts/gen-version.mjs && bun build src/index.ts --outdir dist --target node",
|
|
34
35
|
"dev": "bun run src/index.ts",
|
|
35
36
|
"test": "vitest",
|
|
36
37
|
"test:run": "vitest run",
|