@ghostystudio/cli 0.15.0 → 0.16.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/README.md +9 -0
- package/dist/index.js +149 -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,14 @@ 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.0
|
|
91
|
+
|
|
92
|
+
- `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.
|
|
93
|
+
- `skills house <id> --only a,b | --enable | --disable`: Ghosty's skills in bulk.
|
|
94
|
+
- `agents docs grant <id> A B …` and `--like <agent>`.
|
|
95
|
+
- `agents get --fields toolsets,connectors`: effective toolsets and each connector (connected, granted, effective).
|
|
96
|
+
- `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.
|
|
97
|
+
|
|
89
98
|
### Changes in 0.15.0
|
|
90
99
|
|
|
91
100
|
- `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.0"}`, "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.0"}`,
|
|
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 } : {} });
|
|
577
|
+
else if (v["dry-run"]) throw usage("--dry-run goes with --like (it lists what would be copied).");
|
|
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.0"}`
|
|
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] [--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,8 @@ 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"],
|
|
1992
2082
|
["--workspace SLUG", "create: born in that workspace (you own or administer it), owned by its owner and active in its Teams"],
|
|
1993
2083
|
["--channels k=on|off,\u2026", "create/set: turn channels on/off: teams, web, whatsapp, messenger, wa (personal WhatsApp)"],
|
|
1994
2084
|
["--toolsets LIST", "set: gs tool groups it gets (crm, sales\u2026): a list replaces; +x / -x add or remove"],
|
|
@@ -2029,6 +2119,9 @@ var HELPS = {
|
|
|
2029
2119
|
"ghosty agents set <id> --toolsets +crm",
|
|
2030
2120
|
"ghosty agents share <id> ana@empresa.com --role admin",
|
|
2031
2121
|
"ghosty agents get <id> --prompt-out PROMPT.md",
|
|
2122
|
+
"ghosty agents get <id> --fields toolsets,connectors # what it really has: effective toolsets, connectors connected + granted",
|
|
2123
|
+
"ghosty agents create --name tania-mkt --like <pia-id> --dry-run",
|
|
2124
|
+
'ghosty agents docs grant <id> "Cat\xE1logo.pdf" "Precios.xlsx" \xB7 ghosty agents docs grant <id> --like <other-id>',
|
|
2032
2125
|
"ghosty agents set <pia-id> --prompt-base <tania-id> --prompt-overlay capa.json --dry-run --out /tmp/pia.md",
|
|
2033
2126
|
'ghosty agents demo <id> --slug guardias --on --vence "2026-10-15T20:00" --starter "Ens\xE9\xF1ame c\xF3mo empezar"',
|
|
2034
2127
|
"ghosty agents box <id> --contains /opt/claude-worker/skills/pdf-doc/render-doc.mjs=pdf-templates"
|
|
@@ -2041,6 +2134,7 @@ var HELPS = {
|
|
|
2041
2134
|
usage: [
|
|
2042
2135
|
"ghosty skills ls <agent-id>",
|
|
2043
2136
|
"ghosty skills on|off <agent-id> <slug>",
|
|
2137
|
+
"ghosty skills house <agent-id> [--only a,b | --enable a,b | --disable a,b] [--dry-run]",
|
|
2044
2138
|
"ghosty skills get <agent-id> <slug> [--out DIR]",
|
|
2045
2139
|
"ghosty skills templates <agent-id>",
|
|
2046
2140
|
"ghosty skills add <agent-id> <slug> [--file SKILL.md | --dir FOLDER]",
|
|
@@ -2048,6 +2142,8 @@ var HELPS = {
|
|
|
2048
2142
|
],
|
|
2049
2143
|
flags: [
|
|
2050
2144
|
["--out DIR", "get: folder to write into; without it, get only lists the files"],
|
|
2145
|
+
["--only a,b", "house: leave ONLY these of Ghosty's skills on (the rest off)"],
|
|
2146
|
+
["--enable / --disable a,b", "house: turn these of Ghosty's skills on / off"],
|
|
2051
2147
|
["--file FILE", "add: upload one SKILL.md"],
|
|
2052
2148
|
["--dir FOLDER", "add: upload a whole skill folder (SKILL.md + assets); restores a backup"],
|
|
2053
2149
|
["--yes", "rm: skip the confirmation (required without a terminal)"]
|
|
@@ -2241,6 +2337,26 @@ HELPS.channels = {
|
|
|
2241
2337
|
],
|
|
2242
2338
|
learn: `${REF}#canales-de-whatsapp`
|
|
2243
2339
|
};
|
|
2340
|
+
HELPS.boards = {
|
|
2341
|
+
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.",
|
|
2342
|
+
usage: [
|
|
2343
|
+
"ghosty boards ls <workspace>",
|
|
2344
|
+
'ghosty boards create <workspace> "Name" [--columns-from main|<board>]',
|
|
2345
|
+
"ghosty boards assign <agent-id> <board|main>",
|
|
2346
|
+
"ghosty boards move-cards <workspace> --from <board> --to <board> [--integration ID | --phone N | --all] [--dry-run] [--yes]",
|
|
2347
|
+
'ghosty boards rm <workspace> "Name" [--yes]'
|
|
2348
|
+
],
|
|
2349
|
+
flags: [
|
|
2350
|
+
["--columns-from B", "create: copy the columns of that board (main, a name or an id) instead of the default ones"],
|
|
2351
|
+
["--from / --to B", "move-cards: boards by name, id or main"],
|
|
2352
|
+
["--integration ID | --phone N | --all", "move-cards: which cards (a filter is required)"],
|
|
2353
|
+
["-n, --dry-run", "move-cards: count and show a sample, change nothing"],
|
|
2354
|
+
["--yes", "move-cards: skip the confirmation (required without a terminal)"]
|
|
2355
|
+
],
|
|
2356
|
+
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'],
|
|
2357
|
+
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."],
|
|
2358
|
+
learn: `${REF}#tablero`
|
|
2359
|
+
};
|
|
2244
2360
|
HELPS.board = {
|
|
2245
2361
|
summary: "The agent's sales board. It belongs to the WORKSPACE: you must be a member, a shared agent is not enough.",
|
|
2246
2362
|
usage: [
|
|
@@ -2332,6 +2448,7 @@ ${bold("Agents")}
|
|
|
2332
2448
|
agents ls List your agents
|
|
2333
2449
|
agents create Create an agent --name [--engine] [--model] [--prompt | --prompt-file FILE] [--env K=V,\u2026]
|
|
2334
2450
|
[--workspace SLUG] [--channels teams=off,\u2026] born in a workspace, active in its Teams
|
|
2451
|
+
[--like AGENT [--copy-dbs] [--dry-run]] with another agent's setup (not its prompt, env or channels)
|
|
2335
2452
|
agents get <id> Show an agent's config [--fields name,model,prompt] [--prompt-out FILE]
|
|
2336
2453
|
agents set <id> Change identity or engine [--name] [--engine] [--model] [--prompt | --prompt-file FILE] [--env K=V,\u2026]
|
|
2337
2454
|
[--connect google-drive,\u2026] [--disconnect \u2026] give/remove access to your connectors
|
|
@@ -2341,6 +2458,7 @@ ${bold("Agents")}
|
|
|
2341
2458
|
[--prompt-base AGENT|none --prompt-overlay FILE [--dry-run]] prompt = another agent's + edits, kept in sync
|
|
2342
2459
|
agents doctor <id> Check the config: overlapping skills, tools the prompt names, broken grants, failing turns
|
|
2343
2460
|
agents docs ls|grant|revoke <id> [doc] Documents it reads and may send [--write] [--no-deliver]
|
|
2461
|
+
agents docs grant <id> A B\u2026 Grant several documents at once [--like AGENT] copies another agent's
|
|
2344
2462
|
agents docs add <id> Upload a document and grant it --url URL | --file PATH [--description] [--grant read|write|no]
|
|
2345
2463
|
agents share|unshare <id> <email> Share it without handing it over [--role editor|admin] \xB7 agents shares <id> lists them
|
|
2346
2464
|
agents rm <id> Delete an agent (owner only; asks you to type its name, or --yes)
|
|
@@ -2352,6 +2470,7 @@ ${bold("Agents")}
|
|
|
2352
2470
|
${bold("Configure an agent")}
|
|
2353
2471
|
files ls|get|put|rm <id> [path] Files in the agent's machine [--file LOCAL] [--out LOCAL]
|
|
2354
2472
|
skills on|off <id> <slug> Turn one of its skills (or one of Ghosty's) on or off
|
|
2473
|
+
skills house <id> Ghosty's skills in bulk [--only a,b | --enable a,b | --disable a,b] [--dry-run]
|
|
2355
2474
|
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
2475
|
skills templates <id> pdf-doc templates it sees: its own and Ghosty's, and which folder wins
|
|
2357
2476
|
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 +2482,7 @@ ${bold("Configure an agent")}
|
|
|
2363
2482
|
channels wa pair <id> --phone N Pair a personal WhatsApp by code (no QR)
|
|
2364
2483
|
channels wa status|pause <id> Personal WhatsApp: how it is / pause it (keeps the session)
|
|
2365
2484
|
channels wa groups ls|set|create <id> [group] Personal WhatsApp groups it answers, and as whom [--role equipo|cliente] [--on|--off] [--dry-run]
|
|
2485
|
+
boards ls|create|assign|move-cards|rm A workspace's boards: create (--columns-from), where an agent sends cards, move cards
|
|
2366
2486
|
board ls <id> Recent cards on its sales board [--q TEXT] [--limit 20]
|
|
2367
2487
|
board show <id> <card> A card's thread: who wrote, text, attachments and whether gs kept a copy (folio, phone or id)
|
|
2368
2488
|
board archive <id> Archive cards in bulk (reversible) --integration X | --column X | --before 30d [--dry-run]
|
|
@@ -2401,7 +2521,7 @@ ${bold("Global options")}
|
|
|
2401
2521
|
${bold("Exit codes")} 0 ok \xB7 1 API error \xB7 2 usage error \xB7 3 not signed in
|
|
2402
2522
|
${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
2523
|
${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"];
|
|
2524
|
+
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
2525
|
var AGENTS_SUBS = ["ls", "create", "get", "set", "doctor", "docs", "share", "unshare", "shares", "rm", "restart", "demo", "box"];
|
|
2406
2526
|
function unknown(what, input, known, helpCmd) {
|
|
2407
2527
|
const s = suggest(input, known);
|
|
@@ -2482,6 +2602,14 @@ async function main() {
|
|
|
2482
2602
|
verbose: { type: "boolean" },
|
|
2483
2603
|
full: { type: "boolean" },
|
|
2484
2604
|
"as-formmy": { type: "boolean" },
|
|
2605
|
+
like: { type: "string" },
|
|
2606
|
+
"copy-dbs": { type: "boolean" },
|
|
2607
|
+
only: { type: "string" },
|
|
2608
|
+
enable: { type: "string" },
|
|
2609
|
+
disable: { type: "string" },
|
|
2610
|
+
"columns-from": { type: "string" },
|
|
2611
|
+
to: { type: "string" },
|
|
2612
|
+
all: { type: "boolean" },
|
|
2485
2613
|
q: { type: "string" },
|
|
2486
2614
|
"prompt-out": { type: "string" },
|
|
2487
2615
|
toolsets: { type: "string" },
|
|
@@ -2522,7 +2650,7 @@ async function main() {
|
|
|
2522
2650
|
const tokens = splitTokens(pos, v);
|
|
2523
2651
|
globals.token = tokens.session;
|
|
2524
2652
|
globals.profile = v.profile;
|
|
2525
|
-
if (v.version) return out({ version: "0.
|
|
2653
|
+
if (v.version) return out({ version: "0.16.0" }, () => "0.16.0");
|
|
2526
2654
|
const [cmd, sub, a1, a2] = pos;
|
|
2527
2655
|
if (cmd === "partner" && (v.help || !sub || sub === "help")) return out({ help: PARTNER_HELP }, () => PARTNER_HELP);
|
|
2528
2656
|
const topic = cmd === "help" ? sub : v.help ? cmd : void 0;
|
|
@@ -2556,7 +2684,7 @@ async function main() {
|
|
|
2556
2684
|
if (sub === "set") return agentsSet(a1, v);
|
|
2557
2685
|
if (sub === "rm" || sub === "delete") return agentsRm(a1, v);
|
|
2558
2686
|
if (sub === "doctor") return agentsDoctor(a1, v);
|
|
2559
|
-
if (sub === "docs" || sub === "documents") return agentDocsCmd(a1, a2, pos
|
|
2687
|
+
if (sub === "docs" || sub === "documents") return agentDocsCmd(a1, a2, pos.slice(4).filter((x) => x !== void 0), v);
|
|
2560
2688
|
if (sub === "restart") return agentsRestart(a1);
|
|
2561
2689
|
if (sub === "demo") return agentsDemo(a1, v);
|
|
2562
2690
|
if (sub === "box") return agentsBox(a1, v);
|
|
@@ -2574,6 +2702,8 @@ async function main() {
|
|
|
2574
2702
|
return turnsCmd(sub, a1, a2, v);
|
|
2575
2703
|
case "board":
|
|
2576
2704
|
return boardCmd(sub, a1, v, a2);
|
|
2705
|
+
case "boards":
|
|
2706
|
+
return boardsCmd(sub, a1, a2, v);
|
|
2577
2707
|
case "channels":
|
|
2578
2708
|
if (a1 === "groups") return groupsCmd(pos.slice(3).filter((x) => x !== void 0), v);
|
|
2579
2709
|
return channelsCmd(sub, a1, a2, pos.slice(4).join(" ") || void 0, v);
|
|
@@ -2608,7 +2738,7 @@ async function main() {
|
|
|
2608
2738
|
throw unknown(cmd, cmd, COMMANDS, "ghosty --help");
|
|
2609
2739
|
}
|
|
2610
2740
|
}
|
|
2611
|
-
var notice = updateNotice("0.
|
|
2741
|
+
var notice = updateNotice("0.16.0").catch(() => null);
|
|
2612
2742
|
main().then(
|
|
2613
2743
|
async () => {
|
|
2614
2744
|
const n = await notice;
|
package/package.json
CHANGED