@ghostystudio/cli 0.15.0 → 0.16.1
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/README.md +13 -0
- package/dist/index.js +153 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,6 +44,7 @@ ghosty channels whatsapp history <id> --integration ID [--days 7] [--dry-run]
|
|
|
44
44
|
ghosty channels wa import <id> --from-file F | --from-dir DIR --own-number yes|no [--dry-run] # personal WhatsApp session, no QR
|
|
45
45
|
ghosty channels wa pair|status|pause <id> [--phone N]
|
|
46
46
|
ghosty channels wa groups ls|set|create <id> [group] [--role equipo|cliente] [--on|--off] [--dry-run] # personal WhatsApp groups
|
|
47
|
+
ghosty boards ls|create|assign|move-cards|rm <workspace|agent> … [--columns-from main] [--from A --to B --integration X --dry-run]
|
|
47
48
|
ghosty board ls <id> [--q TEXT] [--limit 20] # recent cards on its sales board
|
|
48
49
|
ghosty board show <id> <folio|phone|id> [--limit 20] # a card's thread, attachments and whether gs kept a copy
|
|
49
50
|
ghosty board archive <id> --integration X | --column X | --before 30d [--dry-run]
|
|
@@ -86,6 +87,18 @@ Exit codes: `0` ok · `1` API error · `2` usage error · `3` not signed in.
|
|
|
86
87
|
- `try --replay FILE --out DIR`: replays real conversations from your machine. The report is written after every step, survives Ghosty deploys (it honors `Retry-After`), and `--resume` continues a partial run.
|
|
87
88
|
- `agents doctor` speaks English like the rest of the CLI; `channels whatsapp ls` returns a full URL.
|
|
88
89
|
|
|
90
|
+
### Changes in 0.16.1
|
|
91
|
+
|
|
92
|
+
- `agents create --like`: `--board same|main|new|NAME` (`new` = its own board with the source's columns, one per number) and `--no-notify` (shared with the same people, no email).
|
|
93
|
+
|
|
94
|
+
### Changes in 0.16.0
|
|
95
|
+
|
|
96
|
+
- `agents create --like <agent> [--copy-dbs] [--dry-run]`: a new agent with another's setup (skills and their switches, toolsets, connectors, voice, databases, documents, board, shares), never its prompt, env or channels.
|
|
97
|
+
- `skills house <id> --only a,b | --enable | --disable`: Ghosty's skills in bulk.
|
|
98
|
+
- `agents docs grant <id> A B …` and `--like <agent>`.
|
|
99
|
+
- `agents get --fields toolsets,connectors`: effective toolsets and each connector (connected, granted, effective).
|
|
100
|
+
- `boards ls|create|assign|move-cards`: a workspace's boards, one per number if you like, with the columns of another and the cards moved over.
|
|
101
|
+
|
|
89
102
|
### Changes in 0.15.0
|
|
90
103
|
|
|
91
104
|
- `try --waba` lists everything the agent would send, tools included: 📍 location, 📄 files, 🎤 voice, ↩️ quotes, 🔘 buttons, 👤 contacts, reactions. Quotes and reactions now find the test message to point at.
|
package/dist/index.js
CHANGED
|
@@ -288,7 +288,7 @@ async function postLong(path, body, timeoutMs = 9e5) {
|
|
|
288
288
|
const req = httpsRequest(`${base}${path}`, {
|
|
289
289
|
method: "POST",
|
|
290
290
|
timeout: timeoutMs,
|
|
291
|
-
headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.
|
|
291
|
+
headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.16.1"}`, "content-type": "application/json", "content-length": Buffer.byteLength(data) }
|
|
292
292
|
}, (res) => {
|
|
293
293
|
let buf = "";
|
|
294
294
|
res.on("data", (c) => buf += c);
|
|
@@ -330,7 +330,7 @@ async function request(path, opts = {}, retried = false) {
|
|
|
330
330
|
method: opts.method ?? (opts.body !== void 0 || opts.raw !== void 0 ? "POST" : "GET"),
|
|
331
331
|
headers: {
|
|
332
332
|
authorization: `Bearer ${token}`,
|
|
333
|
-
"user-agent": `ghosty-cli/${"0.
|
|
333
|
+
"user-agent": `ghosty-cli/${"0.16.1"}`,
|
|
334
334
|
...opts.body !== void 0 ? { "content-type": "application/json" } : {},
|
|
335
335
|
...opts.headers
|
|
336
336
|
},
|
|
@@ -573,11 +573,22 @@ async function agentsCreate(v) {
|
|
|
573
573
|
if (v.workspace) body.workspace = v.workspace;
|
|
574
574
|
const channels = parseChannels(v.channels);
|
|
575
575
|
if (channels) body.channels = channels;
|
|
576
|
+
if (v.like) Object.assign(body, { like: v.like, ...v["copy-dbs"] ? { copyDbs: true } : {}, ...v["dry-run"] ? { dryRun: true } : {}, ...v.board ? { board: v.board } : {}, ...v["no-notify"] ? { notify: false } : {} });
|
|
577
|
+
else if (v["dry-run"] || v.board || v["no-notify"]) throw usage("--dry-run, --board and --no-notify go with --like.");
|
|
578
|
+
if (v.like && v["dry-run"]) {
|
|
579
|
+
const p = await api("/api/v2/me/agents", { method: "POST", body });
|
|
580
|
+
return out(p, () => `${dim(`like ${v.like} \xB7 ${p.engine ?? "?"} \xB7 ${p.model ?? "default"}${p.workspace ? ` \xB7 workspace ${p.workspace}` : ""}`)}
|
|
581
|
+
${p.plan.join("\n")}
|
|
582
|
+
${dim("Not copied: prompt, env, channels. Dry run: nothing created.")}`);
|
|
583
|
+
}
|
|
576
584
|
const r = await api("/api/v2/me/agents", { method: "POST", body });
|
|
577
585
|
const where = r.workspace ? `
|
|
578
586
|
workspace: ${r.workspace}${r.handle ? ` \xB7 @${r.handle} in Teams` : dim(" \xB7 not active in Teams")}` : "";
|
|
587
|
+
const copied = r.copied?.length ? `
|
|
588
|
+
${r.copied.map((l) => ` ${l}`).join("\n")}
|
|
589
|
+
${dim(" Now give it its own prompt: ghosty agents set " + r.id + " --prompt-file PROMPT.md")}` : "";
|
|
579
590
|
out(r, () => `${lavender("\u2713")} Created ${r.name} ${dim(`(${r.engine} \xB7 ${r.model ?? "default"})`)}
|
|
580
|
-
id: ${r.id}${where}`);
|
|
591
|
+
id: ${r.id}${where}${copied}`);
|
|
581
592
|
}
|
|
582
593
|
async function agentsGet(id, fields, promptOut) {
|
|
583
594
|
id = need(id, "agent id", "ghosty agents get <agent-id>");
|
|
@@ -772,7 +783,7 @@ async function readSkillDir(dir) {
|
|
|
772
783
|
}
|
|
773
784
|
var trashDir = (id, slug) => join3(process.env.XDG_CONFIG_HOME || join3(homedir2(), ".config"), "ghosty", "trash", id, `${slug}-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`);
|
|
774
785
|
async function skillsCmd(sub, id, slug, v) {
|
|
775
|
-
const ex = "ghosty skills ls <agent-id> | on|off <agent-id> <slug> | get <agent-id> <slug> [--out DIR] | templates <agent-id> | add <agent-id> <slug> [--file SKILL.md | --dir FOLDER] | rm <agent-id> <slug>";
|
|
786
|
+
const ex = "ghosty skills ls <agent-id> | on|off <agent-id> <slug> | house <agent-id> [--only a,b] | get <agent-id> <slug> [--out DIR] | templates <agent-id> | add <agent-id> <slug> [--file SKILL.md | --dir FOLDER] | rm <agent-id> <slug>";
|
|
776
787
|
id = need(id, "agent id", ex);
|
|
777
788
|
switch (sub ?? "ls") {
|
|
778
789
|
case "ls":
|
|
@@ -788,6 +799,21 @@ async function skillsCmd(sub, id, slug, v) {
|
|
|
788
799
|
${dim(`${more} more in the community catalog: ghosty skills add <agent-id> <slug> (--json lists them) \xB7 overlaps: ghosty agents doctor ${id}`)}`);
|
|
789
800
|
return;
|
|
790
801
|
}
|
|
802
|
+
case "house": {
|
|
803
|
+
const list = (x) => x ? x.split(",").map((s) => s.trim()).filter(Boolean) : void 0;
|
|
804
|
+
const only = list(v.only), on = list(v.enable), off = list(v.disable);
|
|
805
|
+
if (!only && !on && !off) {
|
|
806
|
+
const r2 = await api(agentPath(id, "/skills/house"));
|
|
807
|
+
out(r2, () => `${table(r2.house.map((h) => ({ slug: h.slug, on: h.enabled ? "on" : "off" })), ["slug", "on"])}
|
|
808
|
+
${dim(`Change: ghosty skills house ${id} --only a,b | --enable a | --disable b [--dry-run]`)}`);
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
const body = { ...only ? { only } : {}, ...on ? { on } : {}, ...off ? { off } : {}, ...v["dry-run"] ? { dryRun: true } : {} };
|
|
812
|
+
const r = await api(agentPath(id, "/skills/house"), { method: "PUT", body });
|
|
813
|
+
out(r, () => `${r.changes.map((c) => `${c.enabled ? "+" : "-"} ${c.slug}`).join("\n") || dim("Nothing to change.")}
|
|
814
|
+
${dim(`On now: ${r.on.join(", ") || "none"}${r.dryRun ? " \xB7 dry run: nothing changed" : ""}`)}`);
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
791
817
|
case "on":
|
|
792
818
|
case "off": {
|
|
793
819
|
slug = need(slug, "skill slug", `ghosty skills ${sub} <agent-id> <slug>`);
|
|
@@ -1243,7 +1269,7 @@ async function call(path, v, init = {}) {
|
|
|
1243
1269
|
"x-ghosty-ts": ts,
|
|
1244
1270
|
"x-ghosty-sig": sig,
|
|
1245
1271
|
"content-type": "application/json",
|
|
1246
|
-
"user-agent": `ghosty-cli/${"0.
|
|
1272
|
+
"user-agent": `ghosty-cli/${"0.16.1"}`
|
|
1247
1273
|
},
|
|
1248
1274
|
body: method === "GET" ? void 0 : raw
|
|
1249
1275
|
});
|
|
@@ -1523,7 +1549,8 @@ ${dim(`${rows.length} row(s) \xB7 ${Math.round(r.ms)} ms`)}`;
|
|
|
1523
1549
|
throw usage(`Unknown dbs subcommand: ${sub}.`, "Try: ghosty dbs ls | tables | query | import | grant | revoke (ghosty dbs --help)");
|
|
1524
1550
|
}
|
|
1525
1551
|
}
|
|
1526
|
-
async function agentDocsCmd(sub, id,
|
|
1552
|
+
async function agentDocsCmd(sub, id, docs, v) {
|
|
1553
|
+
let doc = docs[0];
|
|
1527
1554
|
id = need2(id, "agent id", "ghosty agents docs ls <agent-id>");
|
|
1528
1555
|
switch (sub ?? "ls") {
|
|
1529
1556
|
case "ls":
|
|
@@ -1533,13 +1560,23 @@ async function agentDocsCmd(sub, id, doc, v) {
|
|
|
1533
1560
|
return out(r.documents, () => rows.length ? table(rows, ["name", "access", "delivers", "id"]) : dim("This account has no documents yet: upload them at /app/datos."));
|
|
1534
1561
|
}
|
|
1535
1562
|
case "grant": {
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1563
|
+
let wanted;
|
|
1564
|
+
if (v.like) {
|
|
1565
|
+
if (docs.length) throw usage("Use document names or --like, not both.");
|
|
1566
|
+
const other = await api(agentPath2(v.like, "/documents"));
|
|
1567
|
+
wanted = other.documents.filter((d) => d.granted).map((d) => ({ ref: d.id, body: { mode: d.mode ?? "read", deliverable: d.deliverable ?? true } }));
|
|
1568
|
+
if (!wanted.length) return out({ granted: [] }, () => dim(`${v.like} has no documents granted.`));
|
|
1569
|
+
} else {
|
|
1570
|
+
if (!docs.length) throw usage("Missing document (id or exact name).", 'Example: ghosty agents docs grant <agent-id> "Cat\xE1logo.pdf" "Precios.xlsx" (or --like <other-agent>)');
|
|
1571
|
+
const body = {};
|
|
1572
|
+
if (v.write) body.mode = "write";
|
|
1573
|
+
if (v["no-deliver"]) body.deliverable = false;
|
|
1574
|
+
else if (v.deliver) body.deliverable = true;
|
|
1575
|
+
wanted = docs.map((ref) => ({ ref, body }));
|
|
1576
|
+
}
|
|
1577
|
+
const done = [];
|
|
1578
|
+
for (const w of wanted) done.push(await api(agentPath2(id, `/documents/${enc6(w.ref)}`), { method: "PUT", body: w.body }));
|
|
1579
|
+
return out(done.length === 1 ? done[0] : { granted: done }, () => done.map((r) => `${lavender("\u2713")} ${r.name}: ${r.mode === "write" ? "reads and replaces it" : "reads it"}${r.deliverable ? ", and can send it" : ", never sends it"}.`).join("\n"));
|
|
1543
1580
|
}
|
|
1544
1581
|
case "add": {
|
|
1545
1582
|
if (!v.url === !v.file) throw usage("Use --url URL or --file PATH (one of them).", 'Example: ghosty agents docs add <agent-id> --url https://\u2026/lista.pdf --description "Precios 2026"');
|
|
@@ -1963,6 +2000,57 @@ Archive ${plan.matched} card(s) on \xAB${plan.board}\xBB? (reversible: a new mes
|
|
|
1963
2000
|
out(r, () => `${lavender("\u2713")} Archived ${r.archived} card(s) on \xAB${r.board}\xBB.`);
|
|
1964
2001
|
}
|
|
1965
2002
|
|
|
2003
|
+
// src/commands/boards.ts
|
|
2004
|
+
var enc8 = encodeURIComponent;
|
|
2005
|
+
async function boardsCmd(sub, a1, a2, v) {
|
|
2006
|
+
switch (sub ?? "ls") {
|
|
2007
|
+
case "ls":
|
|
2008
|
+
case "list": {
|
|
2009
|
+
if (!a1) throw usage("Missing workspace.", "Example: ghosty boards ls <workspace-slug>");
|
|
2010
|
+
const r = await api(`/api/v2/workspaces/${enc8(a1)}/boards`);
|
|
2011
|
+
const rows = r.boards.map((b) => ({ name: b.main ? `${b.name} (main)` : b.name, cards: b.cards, agents: b.agents.map((x) => x.name ?? x.id).join(", "), columns: b.columns.length, id: b.id }));
|
|
2012
|
+
return out(r, () => table(rows, ["name", "cards", "agents", "columns", "id"]));
|
|
2013
|
+
}
|
|
2014
|
+
case "create": {
|
|
2015
|
+
if (!a1 || !a2) throw usage("Missing workspace or name.", 'Example: ghosty boards create <workspace> "Siiqtec - Ixmiquilpan" --columns-from main');
|
|
2016
|
+
const r = await api(`/api/v2/workspaces/${enc8(a1)}/boards`, { method: "POST", body: { name: a2, ...v["columns-from"] ? { columnsFrom: v["columns-from"] } : {} } });
|
|
2017
|
+
return out(r, () => `${lavender("\u2713")} Board \xAB${r.name}\xBB created${r.columnsFrom ? ` with the ${r.columns} column(s) of \xAB${r.columnsFrom}\xBB` : ""}. ${dim(`Send an agent's cards there: ghosty boards assign <agent-id> "${r.name}"`)}`);
|
|
2018
|
+
}
|
|
2019
|
+
case "rm": {
|
|
2020
|
+
if (!a1 || !a2) throw usage("Missing workspace or board.", 'Example: ghosty boards rm <workspace> "Prueba"');
|
|
2021
|
+
requireYesIfHeadless(v.yes, `ghosty boards rm ${a1} ${JSON.stringify(a2)}`);
|
|
2022
|
+
await confirm(`Delete the board \xAB${a2}\xBB of ${a1}? (only an empty one; its agents go back to the main board)`, { yes: v.yes, retry: `ghosty boards rm ${a1} ${JSON.stringify(a2)}` });
|
|
2023
|
+
const r = await api(`/api/v2/workspaces/${enc8(a1)}/boards`, { method: "DELETE", body: { board: a2 } });
|
|
2024
|
+
return out(r, () => `${lavender("\u2713")} Board \xAB${r.deleted}\xBB deleted.`);
|
|
2025
|
+
}
|
|
2026
|
+
case "assign": {
|
|
2027
|
+
if (!a1 || !a2) throw usage("Missing agent or board.", 'Example: ghosty boards assign <agent-id> "Siiqtec - Ixmiquilpan" (or main)');
|
|
2028
|
+
const r = await api(`/api/v2/agents/${enc8(a1)}`, { method: "PATCH", body: { board: a2 } });
|
|
2029
|
+
return out(r, () => `${lavender("\u2713")} New cards of ${a1} go to \xAB${r.board}\xBB. ${dim(`Existing ones stay where they are: ghosty boards move-cards ${r.workspace} --from \u2026 --to "${r.board}" \u2026`)}`);
|
|
2030
|
+
}
|
|
2031
|
+
case "move-cards": {
|
|
2032
|
+
if (!a1 || !v.from || !v.to) throw usage("Missing workspace, --from or --to.", 'Example: ghosty boards move-cards <workspace> --from main --to "Siiqtec - Ixmiquilpan" --integration 6a3b02ad\u2026 --dry-run');
|
|
2033
|
+
if (!v.integration && !v.phone && !v.all) throw usage("Add a filter: --integration ID, --phone N or --all.", "A filter-less move would empty the board.");
|
|
2034
|
+
const path = `/api/v2/workspaces/${enc8(a1)}/boards/move-cards`;
|
|
2035
|
+
const body = { from: v.from, to: v.to, ...v.integration ? { integration: v.integration } : {}, ...v.phone ? { phone: v.phone } : {}, ...v.all ? { all: true } : {} };
|
|
2036
|
+
const retry = `ghosty boards move-cards ${a1} --from ${JSON.stringify(v.from)} --to ${JSON.stringify(v.to)}${v.integration ? ` --integration ${v.integration}` : ""}${v.phone ? ` --phone ${v.phone}` : ""}${v.all ? " --all" : ""}`;
|
|
2037
|
+
if (!v["dry-run"]) requireYesIfHeadless(v.yes, retry);
|
|
2038
|
+
const plan = await api(path, { method: "POST", body: { ...body, dryRun: true } });
|
|
2039
|
+
const sample = table(plan.sample.map((c) => ({ folio: c.folio ? `#${c.folio}` : "", name: c.name ?? "", phone: c.phone })), ["folio", "name", "phone"]);
|
|
2040
|
+
const text = `${sample}
|
|
2041
|
+
${plan.moved} of ${plan.matched} card(s) \xAB${plan.from}\xBB \u2192 \xAB${plan.to}\xBB${plan.skipped.length ? dim(` \xB7 ${plan.skipped.length} already in \xAB${plan.to}\xBB, skipped`) : ""}`;
|
|
2042
|
+
if (v["dry-run"] || !plan.moved) return out(plan, () => `${text}
|
|
2043
|
+
${dim("Dry run: nothing changed.")}`);
|
|
2044
|
+
await confirm(`${text}
|
|
2045
|
+
Move them with their threads and orders? (they get a new folio there)`, { yes: v.yes, retry });
|
|
2046
|
+
const r = await api(path, { method: "POST", body });
|
|
2047
|
+
return out(r, () => `${lavender("\u2713")} Moved ${r.moved} card(s) (${r.messages} message(s), ${r.orders} order(s)) to \xAB${r.to}\xBB.${r.skipped.length ? dim(` Skipped ${r.skipped.length}.`) : ""}`);
|
|
2048
|
+
}
|
|
2049
|
+
default:
|
|
2050
|
+
throw usage(`Unknown boards subcommand: ${sub}.`, "Try: ghosty boards ls | create | assign | move-cards | rm");
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
|
|
1966
2054
|
// src/help.ts
|
|
1967
2055
|
var DOCS = "https://www.ghosty.studio/docs/cli";
|
|
1968
2056
|
var REF = `${DOCS}/comandos`;
|
|
@@ -1971,12 +2059,12 @@ var HELPS = {
|
|
|
1971
2059
|
summary: "Create, inspect, change, check and delete agents.",
|
|
1972
2060
|
usage: [
|
|
1973
2061
|
"ghosty agents ls",
|
|
1974
|
-
"ghosty agents create --name NAME [--engine E] [--model M] [--prompt TEXT | --prompt-file FILE] [--env K=V,\u2026] [--workspace SLUG] [--channels teams=off,\u2026]",
|
|
2062
|
+
"ghosty agents create --name NAME [--engine E] [--model M] [--prompt TEXT | --prompt-file FILE] [--env K=V,\u2026] [--workspace SLUG] [--channels teams=off,\u2026] [--like AGENT [--copy-dbs] [--board same|main|new|NAME] [--no-notify] [--dry-run]]",
|
|
1975
2063
|
"ghosty agents get <agent-id> [--fields name,model,prompt] [--prompt-out FILE]",
|
|
1976
2064
|
"ghosty agents set <agent-id> [--name] [--engine] [--model] [--prompt | --prompt-file] [--env K=V,\u2026] [--connect ID,\u2026] [--disconnect ID,\u2026] [--voice E:ID] [--voice-replies auto|off] [--auto-stage on|off] [--toolsets crm,sales | +crm,-sales]",
|
|
1977
2065
|
"ghosty agents set <agent-id> --prompt-base <base-agent-id> --prompt-overlay overlay.json [--dry-run [--out FILE]] | --prompt-base none",
|
|
1978
2066
|
"ghosty agents doctor <agent-id> [--verbose]",
|
|
1979
|
-
"ghosty agents docs ls|grant|revoke <agent-id> [doc] [--write] [--no-deliver]",
|
|
2067
|
+
"ghosty agents docs ls|grant|revoke <agent-id> [doc\u2026] [--write] [--no-deliver] [--like AGENT]",
|
|
1980
2068
|
"ghosty agents docs add <agent-id> --url URL | --file PATH [--name N] [--description TEXT] [--grant read|write|no] [--no-deliver]",
|
|
1981
2069
|
"ghosty agents share <agent-id> <email> [--role editor|admin]",
|
|
1982
2070
|
"ghosty agents unshare <agent-id> <email> [--yes]",
|
|
@@ -1989,6 +2077,10 @@ var HELPS = {
|
|
|
1989
2077
|
flags: [
|
|
1990
2078
|
["--fields a,b", "get: return only these fields"],
|
|
1991
2079
|
["--prompt-out FILE", "get: write the prompt to FILE (edit it and come back with set --prompt-file)"],
|
|
2080
|
+
["--like AGENT", "create: copy that agent's setup (skills and their switches, toolsets, connectors, voice, databases, documents, board, shares) \u2014 not its prompt, env or channels. docs grant: the same documents"],
|
|
2081
|
+
["--copy-dbs", "create --like: duplicate its databases with their rows instead of granting the same ones"],
|
|
2082
|
+
["--board B", "create --like: same (the source's board, default) \xB7 main \xB7 new (a board named like the agent, with the source's columns: one board per number) \xB7 or an existing board"],
|
|
2083
|
+
["--no-notify", "create --like: share it with the same people WITHOUT emailing them"],
|
|
1992
2084
|
["--workspace SLUG", "create: born in that workspace (you own or administer it), owned by its owner and active in its Teams"],
|
|
1993
2085
|
["--channels k=on|off,\u2026", "create/set: turn channels on/off: teams, web, whatsapp, messenger, wa (personal WhatsApp)"],
|
|
1994
2086
|
["--toolsets LIST", "set: gs tool groups it gets (crm, sales\u2026): a list replaces; +x / -x add or remove"],
|
|
@@ -2029,6 +2121,9 @@ var HELPS = {
|
|
|
2029
2121
|
"ghosty agents set <id> --toolsets +crm",
|
|
2030
2122
|
"ghosty agents share <id> ana@empresa.com --role admin",
|
|
2031
2123
|
"ghosty agents get <id> --prompt-out PROMPT.md",
|
|
2124
|
+
"ghosty agents get <id> --fields toolsets,connectors # what it really has: effective toolsets, connectors connected + granted",
|
|
2125
|
+
"ghosty agents create --name tania-mkt --like <pia-id> --board new --no-notify --dry-run",
|
|
2126
|
+
'ghosty agents docs grant <id> "Cat\xE1logo.pdf" "Precios.xlsx" \xB7 ghosty agents docs grant <id> --like <other-id>',
|
|
2032
2127
|
"ghosty agents set <pia-id> --prompt-base <tania-id> --prompt-overlay capa.json --dry-run --out /tmp/pia.md",
|
|
2033
2128
|
'ghosty agents demo <id> --slug guardias --on --vence "2026-10-15T20:00" --starter "Ens\xE9\xF1ame c\xF3mo empezar"',
|
|
2034
2129
|
"ghosty agents box <id> --contains /opt/claude-worker/skills/pdf-doc/render-doc.mjs=pdf-templates"
|
|
@@ -2041,6 +2136,7 @@ var HELPS = {
|
|
|
2041
2136
|
usage: [
|
|
2042
2137
|
"ghosty skills ls <agent-id>",
|
|
2043
2138
|
"ghosty skills on|off <agent-id> <slug>",
|
|
2139
|
+
"ghosty skills house <agent-id> [--only a,b | --enable a,b | --disable a,b] [--dry-run]",
|
|
2044
2140
|
"ghosty skills get <agent-id> <slug> [--out DIR]",
|
|
2045
2141
|
"ghosty skills templates <agent-id>",
|
|
2046
2142
|
"ghosty skills add <agent-id> <slug> [--file SKILL.md | --dir FOLDER]",
|
|
@@ -2048,6 +2144,8 @@ var HELPS = {
|
|
|
2048
2144
|
],
|
|
2049
2145
|
flags: [
|
|
2050
2146
|
["--out DIR", "get: folder to write into; without it, get only lists the files"],
|
|
2147
|
+
["--only a,b", "house: leave ONLY these of Ghosty's skills on (the rest off)"],
|
|
2148
|
+
["--enable / --disable a,b", "house: turn these of Ghosty's skills on / off"],
|
|
2051
2149
|
["--file FILE", "add: upload one SKILL.md"],
|
|
2052
2150
|
["--dir FOLDER", "add: upload a whole skill folder (SKILL.md + assets); restores a backup"],
|
|
2053
2151
|
["--yes", "rm: skip the confirmation (required without a terminal)"]
|
|
@@ -2241,6 +2339,26 @@ HELPS.channels = {
|
|
|
2241
2339
|
],
|
|
2242
2340
|
learn: `${REF}#canales-de-whatsapp`
|
|
2243
2341
|
};
|
|
2342
|
+
HELPS.boards = {
|
|
2343
|
+
summary: "A WORKSPACE's sales boards: list them, create one (copying another's columns), choose where an agent sends its cards, and move cards between boards.",
|
|
2344
|
+
usage: [
|
|
2345
|
+
"ghosty boards ls <workspace>",
|
|
2346
|
+
'ghosty boards create <workspace> "Name" [--columns-from main|<board>]',
|
|
2347
|
+
"ghosty boards assign <agent-id> <board|main>",
|
|
2348
|
+
"ghosty boards move-cards <workspace> --from <board> --to <board> [--integration ID | --phone N | --all] [--dry-run] [--yes]",
|
|
2349
|
+
'ghosty boards rm <workspace> "Name" [--yes]'
|
|
2350
|
+
],
|
|
2351
|
+
flags: [
|
|
2352
|
+
["--columns-from B", "create: copy the columns of that board (main, a name or an id) instead of the default ones"],
|
|
2353
|
+
["--from / --to B", "move-cards: boards by name, id or main"],
|
|
2354
|
+
["--integration ID | --phone N | --all", "move-cards: which cards (a filter is required)"],
|
|
2355
|
+
["-n, --dry-run", "move-cards: count and show a sample, change nothing"],
|
|
2356
|
+
["--yes", "move-cards: skip the confirmation (required without a terminal)"]
|
|
2357
|
+
],
|
|
2358
|
+
examples: ["ghosty boards ls siiqtec", 'ghosty boards create siiqtec "Siiqtec - Ixmiquilpan" --columns-from main', 'ghosty boards assign <agent-id> "Siiqtec - Ixmiquilpan"', 'ghosty boards move-cards siiqtec --from main --to "Siiqtec - Ixmiquilpan" --integration 6a3b02ad\u2026 --dry-run'],
|
|
2359
|
+
notes: ["assign changes where NEW cards go; move-cards brings the existing ones (thread, orders, activity) with a new folio. A card whose conversation is already on the target board is skipped.", "Reading needs membership; changing needs owner or staff of the workspace.", "rm only deletes an empty board that is not the main one."],
|
|
2360
|
+
learn: `${REF}#tablero`
|
|
2361
|
+
};
|
|
2244
2362
|
HELPS.board = {
|
|
2245
2363
|
summary: "The agent's sales board. It belongs to the WORKSPACE: you must be a member, a shared agent is not enough.",
|
|
2246
2364
|
usage: [
|
|
@@ -2332,6 +2450,7 @@ ${bold("Agents")}
|
|
|
2332
2450
|
agents ls List your agents
|
|
2333
2451
|
agents create Create an agent --name [--engine] [--model] [--prompt | --prompt-file FILE] [--env K=V,\u2026]
|
|
2334
2452
|
[--workspace SLUG] [--channels teams=off,\u2026] born in a workspace, active in its Teams
|
|
2453
|
+
[--like AGENT [--copy-dbs] [--board same|main|new|NAME] [--no-notify] [--dry-run]] with another agent's setup (not its prompt, env or channels)
|
|
2335
2454
|
agents get <id> Show an agent's config [--fields name,model,prompt] [--prompt-out FILE]
|
|
2336
2455
|
agents set <id> Change identity or engine [--name] [--engine] [--model] [--prompt | --prompt-file FILE] [--env K=V,\u2026]
|
|
2337
2456
|
[--connect google-drive,\u2026] [--disconnect \u2026] give/remove access to your connectors
|
|
@@ -2341,6 +2460,7 @@ ${bold("Agents")}
|
|
|
2341
2460
|
[--prompt-base AGENT|none --prompt-overlay FILE [--dry-run]] prompt = another agent's + edits, kept in sync
|
|
2342
2461
|
agents doctor <id> Check the config: overlapping skills, tools the prompt names, broken grants, failing turns
|
|
2343
2462
|
agents docs ls|grant|revoke <id> [doc] Documents it reads and may send [--write] [--no-deliver]
|
|
2463
|
+
agents docs grant <id> A B\u2026 Grant several documents at once [--like AGENT] copies another agent's
|
|
2344
2464
|
agents docs add <id> Upload a document and grant it --url URL | --file PATH [--description] [--grant read|write|no]
|
|
2345
2465
|
agents share|unshare <id> <email> Share it without handing it over [--role editor|admin] \xB7 agents shares <id> lists them
|
|
2346
2466
|
agents rm <id> Delete an agent (owner only; asks you to type its name, or --yes)
|
|
@@ -2352,6 +2472,7 @@ ${bold("Agents")}
|
|
|
2352
2472
|
${bold("Configure an agent")}
|
|
2353
2473
|
files ls|get|put|rm <id> [path] Files in the agent's machine [--file LOCAL] [--out LOCAL]
|
|
2354
2474
|
skills on|off <id> <slug> Turn one of its skills (or one of Ghosty's) on or off
|
|
2475
|
+
skills house <id> Ghosty's skills in bulk [--only a,b | --enable a,b | --disable a,b] [--dry-run]
|
|
2355
2476
|
skills ls|get|add|rm <id> [slug] Skills (add from catalog, --file SKILL.md or --dir FOLDER; get lists, --out DIR saves; rm keeps a copy)
|
|
2356
2477
|
skills templates <id> pdf-doc templates it sees: its own and Ghosty's, and which folder wins
|
|
2357
2478
|
dbs ls|tables|query|import|grant|revoke <id> [db] Databases it uses [--write] [--external-write t1,t2] [--external-rows t:col] [--from easybits:ID --dry-run]
|
|
@@ -2363,6 +2484,7 @@ ${bold("Configure an agent")}
|
|
|
2363
2484
|
channels wa pair <id> --phone N Pair a personal WhatsApp by code (no QR)
|
|
2364
2485
|
channels wa status|pause <id> Personal WhatsApp: how it is / pause it (keeps the session)
|
|
2365
2486
|
channels wa groups ls|set|create <id> [group] Personal WhatsApp groups it answers, and as whom [--role equipo|cliente] [--on|--off] [--dry-run]
|
|
2487
|
+
boards ls|create|assign|move-cards|rm A workspace's boards: create (--columns-from), where an agent sends cards, move cards
|
|
2366
2488
|
board ls <id> Recent cards on its sales board [--q TEXT] [--limit 20]
|
|
2367
2489
|
board show <id> <card> A card's thread: who wrote, text, attachments and whether gs kept a copy (folio, phone or id)
|
|
2368
2490
|
board archive <id> Archive cards in bulk (reversible) --integration X | --column X | --before 30d [--dry-run]
|
|
@@ -2401,7 +2523,7 @@ ${bold("Global options")}
|
|
|
2401
2523
|
${bold("Exit codes")} 0 ok \xB7 1 API error \xB7 2 usage error \xB7 3 not signed in
|
|
2402
2524
|
${dim("Note: `ghosty` may collide with another binary on your PATH (e.g. the Ghosty TUI). Check with `which -a ghosty`; run `npx @ghostystudio/cli` to be sure.")}
|
|
2403
2525
|
${dim("Docs: https://www.ghosty.studio/docs/cli")}`;
|
|
2404
|
-
var COMMANDS = ["login", "logout", "whoami", "usage", "agents", "files", "skills", "mcp", "dbs", "turns", "try", "chat", "conversations", "schedule", "partner", "me", "channels", "board", "credentials", "docs", "help"];
|
|
2526
|
+
var COMMANDS = ["login", "logout", "whoami", "usage", "agents", "files", "skills", "mcp", "dbs", "turns", "try", "chat", "conversations", "schedule", "partner", "me", "channels", "board", "boards", "credentials", "docs", "help"];
|
|
2405
2527
|
var AGENTS_SUBS = ["ls", "create", "get", "set", "doctor", "docs", "share", "unshare", "shares", "rm", "restart", "demo", "box"];
|
|
2406
2528
|
function unknown(what, input, known, helpCmd) {
|
|
2407
2529
|
const s = suggest(input, known);
|
|
@@ -2482,6 +2604,16 @@ async function main() {
|
|
|
2482
2604
|
verbose: { type: "boolean" },
|
|
2483
2605
|
full: { type: "boolean" },
|
|
2484
2606
|
"as-formmy": { type: "boolean" },
|
|
2607
|
+
like: { type: "string" },
|
|
2608
|
+
"copy-dbs": { type: "boolean" },
|
|
2609
|
+
"no-notify": { type: "boolean" },
|
|
2610
|
+
board: { type: "string" },
|
|
2611
|
+
only: { type: "string" },
|
|
2612
|
+
enable: { type: "string" },
|
|
2613
|
+
disable: { type: "string" },
|
|
2614
|
+
"columns-from": { type: "string" },
|
|
2615
|
+
to: { type: "string" },
|
|
2616
|
+
all: { type: "boolean" },
|
|
2485
2617
|
q: { type: "string" },
|
|
2486
2618
|
"prompt-out": { type: "string" },
|
|
2487
2619
|
toolsets: { type: "string" },
|
|
@@ -2522,7 +2654,7 @@ async function main() {
|
|
|
2522
2654
|
const tokens = splitTokens(pos, v);
|
|
2523
2655
|
globals.token = tokens.session;
|
|
2524
2656
|
globals.profile = v.profile;
|
|
2525
|
-
if (v.version) return out({ version: "0.
|
|
2657
|
+
if (v.version) return out({ version: "0.16.1" }, () => "0.16.1");
|
|
2526
2658
|
const [cmd, sub, a1, a2] = pos;
|
|
2527
2659
|
if (cmd === "partner" && (v.help || !sub || sub === "help")) return out({ help: PARTNER_HELP }, () => PARTNER_HELP);
|
|
2528
2660
|
const topic = cmd === "help" ? sub : v.help ? cmd : void 0;
|
|
@@ -2556,7 +2688,7 @@ async function main() {
|
|
|
2556
2688
|
if (sub === "set") return agentsSet(a1, v);
|
|
2557
2689
|
if (sub === "rm" || sub === "delete") return agentsRm(a1, v);
|
|
2558
2690
|
if (sub === "doctor") return agentsDoctor(a1, v);
|
|
2559
|
-
if (sub === "docs" || sub === "documents") return agentDocsCmd(a1, a2, pos
|
|
2691
|
+
if (sub === "docs" || sub === "documents") return agentDocsCmd(a1, a2, pos.slice(4).filter((x) => x !== void 0), v);
|
|
2560
2692
|
if (sub === "restart") return agentsRestart(a1);
|
|
2561
2693
|
if (sub === "demo") return agentsDemo(a1, v);
|
|
2562
2694
|
if (sub === "box") return agentsBox(a1, v);
|
|
@@ -2574,6 +2706,8 @@ async function main() {
|
|
|
2574
2706
|
return turnsCmd(sub, a1, a2, v);
|
|
2575
2707
|
case "board":
|
|
2576
2708
|
return boardCmd(sub, a1, v, a2);
|
|
2709
|
+
case "boards":
|
|
2710
|
+
return boardsCmd(sub, a1, a2, v);
|
|
2577
2711
|
case "channels":
|
|
2578
2712
|
if (a1 === "groups") return groupsCmd(pos.slice(3).filter((x) => x !== void 0), v);
|
|
2579
2713
|
return channelsCmd(sub, a1, a2, pos.slice(4).join(" ") || void 0, v);
|
|
@@ -2608,7 +2742,7 @@ async function main() {
|
|
|
2608
2742
|
throw unknown(cmd, cmd, COMMANDS, "ghosty --help");
|
|
2609
2743
|
}
|
|
2610
2744
|
}
|
|
2611
|
-
var notice = updateNotice("0.
|
|
2745
|
+
var notice = updateNotice("0.16.1").catch(() => null);
|
|
2612
2746
|
main().then(
|
|
2613
2747
|
async () => {
|
|
2614
2748
|
const n = await notice;
|
package/package.json
CHANGED