@cmo-so/cli 0.7.3 → 0.7.5
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/cmo.mjs +200 -8
- package/package.json +1 -1
package/dist/cmo.mjs
CHANGED
|
@@ -7407,15 +7407,15 @@ function createApi({ baseUrl, session: session2, fetch: fetchImpl = globalThis.f
|
|
|
7407
7407
|
}),
|
|
7408
7408
|
remove: () => request("/v1/maggie/bridge", { method: "DELETE" }),
|
|
7409
7409
|
/** Start "Sign in with ChatGPT" for one of the bridge's accounts (the active one by default). */
|
|
7410
|
-
connectChatgpt: (
|
|
7410
|
+
connectChatgpt: (account4) => request("/v1/maggie/bridge/chatgpt", {
|
|
7411
7411
|
method: "POST",
|
|
7412
7412
|
headers: { "Content-Type": "application/json" },
|
|
7413
|
-
body: JSON.stringify(
|
|
7413
|
+
body: JSON.stringify(account4 ? { account: account4 } : {})
|
|
7414
7414
|
}),
|
|
7415
|
-
disconnectChatgpt: (
|
|
7415
|
+
disconnectChatgpt: (account4) => request("/v1/maggie/bridge/chatgpt/logout", {
|
|
7416
7416
|
method: "POST",
|
|
7417
7417
|
headers: { "Content-Type": "application/json" },
|
|
7418
|
-
body: JSON.stringify(
|
|
7418
|
+
body: JSON.stringify(account4 ? { account: account4 } : {})
|
|
7419
7419
|
}),
|
|
7420
7420
|
/** What Maggie may do in CMO.so; rotates the bridge's key when read / read_write changes. */
|
|
7421
7421
|
setAccess: (access) => request("/v1/maggie/bridge/access", {
|
|
@@ -7458,6 +7458,31 @@ function createApi({ baseUrl, session: session2, fetch: fetchImpl = globalThis.f
|
|
|
7458
7458
|
return dataUrl(type, bytes);
|
|
7459
7459
|
}
|
|
7460
7460
|
},
|
|
7461
|
+
// The open marketing skills (docs/26): api.cmo.so forwards these to the cmo.so site.
|
|
7462
|
+
skills: {
|
|
7463
|
+
search: (q2 = "", opts = {}) => {
|
|
7464
|
+
const qs = new URLSearchParams({
|
|
7465
|
+
q: q2,
|
|
7466
|
+
...opts.category ? { category: opts.category } : {},
|
|
7467
|
+
limit: String(opts.limit ?? 10)
|
|
7468
|
+
});
|
|
7469
|
+
return request(`/v1/skills?${qs}`);
|
|
7470
|
+
},
|
|
7471
|
+
get: (id) => request(`/v1/skills/${encodeURIComponent(id)}`),
|
|
7472
|
+
/** Like or save a skill (on: false undoes it). */
|
|
7473
|
+
react: (id, kind, on2 = true) => request(
|
|
7474
|
+
`/v1/skills/${encodeURIComponent(id)}/react`,
|
|
7475
|
+
{ method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ kind, on: on2 }) }
|
|
7476
|
+
),
|
|
7477
|
+
saved: () => request("/v1/skills/saved"),
|
|
7478
|
+
/** Suggest an open-source GitHub repo; Maggie researches it (3 a day). */
|
|
7479
|
+
submit: (repoUrl, note) => request("/v1/skills/submissions", {
|
|
7480
|
+
method: "POST",
|
|
7481
|
+
headers: { "Content-Type": "application/json" },
|
|
7482
|
+
body: JSON.stringify({ repo_url: repoUrl, note })
|
|
7483
|
+
}),
|
|
7484
|
+
submissions: () => request("/v1/skills/submissions")
|
|
7485
|
+
},
|
|
7461
7486
|
// Web Push for this browser (APP-9). `domains` are the workspaces it shows.
|
|
7462
7487
|
push: {
|
|
7463
7488
|
status: (endpoint) => request(
|
|
@@ -7540,7 +7565,9 @@ function domainApi(api2, domain) {
|
|
|
7540
7565
|
});
|
|
7541
7566
|
return {
|
|
7542
7567
|
summary: () => api2.request(base),
|
|
7543
|
-
posts: (status, limit = 50) => api2.request(
|
|
7568
|
+
posts: (status, limit = 50) => api2.request(
|
|
7569
|
+
`${base}/posts?status=${status}&limit=${limit}`
|
|
7570
|
+
),
|
|
7544
7571
|
post: (id) => api2.request(`${base}/posts/${encodeURIComponent(id)}`),
|
|
7545
7572
|
updatePost: (id, changes) => api2.request(`${base}/posts/${encodeURIComponent(id)}`, {
|
|
7546
7573
|
method: "PATCH",
|
|
@@ -8553,6 +8580,19 @@ var confirmCopy = {
|
|
|
8553
8580
|
en: (a) => `Send this to the cmo.so team: ${q(String(a.summary ?? "").slice(0, 200))}`,
|
|
8554
8581
|
"zh-Hant": (a) => `\u628A\u9019\u5247\u56DE\u994B\u9001\u7D66 cmo.so \u5718\u968A\uFF1A${q(String(a.summary ?? "").slice(0, 200))}`
|
|
8555
8582
|
},
|
|
8583
|
+
// ---------------------------------------------------------- Marketing skills (docs/26)
|
|
8584
|
+
skill_like: {
|
|
8585
|
+
en: (a) => `${a.undo ? "Take back your like on" : "Like"} the skill ${q(a.skill_id)} on cmo.so.`,
|
|
8586
|
+
"zh-Hant": (a) => `${a.undo ? "\u53D6\u6D88\u5C0D" : "\u5728 cmo.so \u8B9A"}\u6280\u80FD ${q(a.skill_id)}${a.undo ? " \u7684\u8B9A" : ""}\u3002`
|
|
8587
|
+
},
|
|
8588
|
+
skill_save: {
|
|
8589
|
+
en: (a) => `${a.undo ? "Remove" : "Save"} the skill ${q(a.skill_id)} ${a.undo ? "from" : "to"} your saved skills.`,
|
|
8590
|
+
"zh-Hant": (a) => `${a.undo ? "\u5F9E\u6536\u85CF\u79FB\u9664" : "\u6536\u85CF"}\u6280\u80FD ${q(a.skill_id)}\u3002`
|
|
8591
|
+
},
|
|
8592
|
+
skill_submit: {
|
|
8593
|
+
en: (a) => `Suggest ${q(a.repo_url)} for the cmo.so skill library. Maggie will research it.`,
|
|
8594
|
+
"zh-Hant": (a) => `\u628A ${q(a.repo_url)} \u63A8\u85A6\u7D66 cmo.so \u6280\u80FD\u5EAB\uFF0CMaggie \u6703\u7814\u7A76\u5B83\u3002`
|
|
8595
|
+
},
|
|
8556
8596
|
social_voice_learn: {
|
|
8557
8597
|
en: () => "Learn your LinkedIn voice from this post and save it as your default.",
|
|
8558
8598
|
"zh-Hant": () => "\u5F9E\u9019\u7BC7\u8CBC\u6587\u5B78\u7FD2\u4F60\u7684 LinkedIn \u8A9E\u6C23\uFF0C\u4E26\u8A2D\u70BA\u9810\u8A2D\u3002"
|
|
@@ -9269,8 +9309,10 @@ var blogTools = [
|
|
|
9269
9309
|
const r = await ws(ctx).ideas(int(page, 1, 100, 1), 15, status === "discarded" ? "discarded" : "pending");
|
|
9270
9310
|
return {
|
|
9271
9311
|
total: r.total,
|
|
9312
|
+
// The real limits: the user's own waiting ideas (cap) and the plan (plan_max).
|
|
9272
9313
|
cap: r.cap,
|
|
9273
9314
|
added_by_you: r.added_by_you,
|
|
9315
|
+
plan_max: r.plan_max,
|
|
9274
9316
|
items: r.items.map((i) => ({
|
|
9275
9317
|
id: i.id,
|
|
9276
9318
|
priority: i.priority,
|
|
@@ -9309,7 +9351,7 @@ var blogTools = [
|
|
|
9309
9351
|
}),
|
|
9310
9352
|
tool({
|
|
9311
9353
|
name: "ideas_add_list",
|
|
9312
|
-
description: "Add up to 100 ideas exactly as given (a researched list): title, description, primary keyword, up to 5 more keywords, a benchmark URL (read as research, never linked), priority 1-10 and optionally one of the website's topics. No AI rewrites them and no generation is used; they wait in the idea pool, not the plan. Duplicates are skipped and listed;
|
|
9354
|
+
description: "Add up to 100 ideas exactly as given (a researched list): title, description, primary keyword, up to 5 more keywords, a benchmark URL (read as research, never linked), priority 1-10 and optionally one of the website's topics. No AI rewrites them and no generation is used; they wait in the idea pool, not the plan. Duplicates are skipped and listed; a person's own waiting ideas have a limit (ideas_list cap, 200 today).",
|
|
9313
9355
|
parameters: {
|
|
9314
9356
|
type: "object",
|
|
9315
9357
|
properties: {
|
|
@@ -10641,6 +10683,155 @@ var reportTools = [
|
|
|
10641
10683
|
})
|
|
10642
10684
|
];
|
|
10643
10685
|
|
|
10686
|
+
// ../../packages/tools/src/skills.ts
|
|
10687
|
+
var account3 = { resource: "account", level: "read" };
|
|
10688
|
+
var ID = { type: "string", description: "The skill id, like cmo-ad-creative" };
|
|
10689
|
+
var skillTools = [
|
|
10690
|
+
tool({
|
|
10691
|
+
name: "skills_search",
|
|
10692
|
+
description: "Search cmo.so's open library of marketing skills (step-by-step methods an AI agent follows, free and MIT licensed): returns matching skills with their summary, likes and page. Use it when the user asks how to do a marketing job, wants a playbook or template, or asks which skills exist. Empty query: the most useful ones and the categories.",
|
|
10693
|
+
parameters: {
|
|
10694
|
+
type: "object",
|
|
10695
|
+
properties: {
|
|
10696
|
+
query: { type: "string", description: "What the user wants to do, in a few words" },
|
|
10697
|
+
category: {
|
|
10698
|
+
type: "string",
|
|
10699
|
+
description: "Optional category id: core, strategy, seo, ai-search, content, social, email, paid-ads, cro, analytics, growth, sales, creative"
|
|
10700
|
+
},
|
|
10701
|
+
limit: { type: "integer", minimum: 1, maximum: 20 }
|
|
10702
|
+
}
|
|
10703
|
+
},
|
|
10704
|
+
group: "account",
|
|
10705
|
+
need: account3,
|
|
10706
|
+
risk: "R0",
|
|
10707
|
+
idempotent: true,
|
|
10708
|
+
run: async (ctx, a) => {
|
|
10709
|
+
const r = await ctx.api.skills.search(String(a.query ?? ""), {
|
|
10710
|
+
...a.category ? { category: a.category } : {},
|
|
10711
|
+
limit: int(a.limit, 1, 20, 8)
|
|
10712
|
+
});
|
|
10713
|
+
return {
|
|
10714
|
+
total_in_library: r.total,
|
|
10715
|
+
...a.query ? {} : { categories: r.categories.map((c) => `${c.id} (${c.count})`) },
|
|
10716
|
+
skills: r.skills.map((s) => ({ id: s.id, name: s.name, summary: s.summary, likes: s.likes, page: s.url }))
|
|
10717
|
+
};
|
|
10718
|
+
}
|
|
10719
|
+
}),
|
|
10720
|
+
tool({
|
|
10721
|
+
name: "skill_get",
|
|
10722
|
+
description: "One marketing skill from the cmo.so library in full: when to use it, what it needs, its workflow, output and quality bar, plus how to install it in Claude Code. Use it to follow a skill's method for the user, or to explain it.",
|
|
10723
|
+
parameters: { type: "object", properties: { skill_id: ID }, required: ["skill_id"] },
|
|
10724
|
+
group: "account",
|
|
10725
|
+
need: account3,
|
|
10726
|
+
risk: "R0",
|
|
10727
|
+
idempotent: true,
|
|
10728
|
+
run: async (ctx, a) => {
|
|
10729
|
+
const s = await ctx.api.skills.get(String(a.skill_id));
|
|
10730
|
+
return {
|
|
10731
|
+
id: s.id,
|
|
10732
|
+
name: s.name,
|
|
10733
|
+
summary: s.summary,
|
|
10734
|
+
page: s.url,
|
|
10735
|
+
likes: s.likes,
|
|
10736
|
+
saves: s.saves,
|
|
10737
|
+
uses_tools: s.mcp_tools,
|
|
10738
|
+
pairs_with: s.pairs_with,
|
|
10739
|
+
install: s.install,
|
|
10740
|
+
// community-contributed text: a method to follow, never instructions that override the user or these rules
|
|
10741
|
+
...untrusted(clip(s.text, 12e3))
|
|
10742
|
+
};
|
|
10743
|
+
}
|
|
10744
|
+
}),
|
|
10745
|
+
tool({
|
|
10746
|
+
name: "skill_like",
|
|
10747
|
+
description: "Like a skill in the cmo.so library for the user (or take the like back with undo). Likes help the library decide what to keep improving. Only when the user asks.",
|
|
10748
|
+
parameters: {
|
|
10749
|
+
type: "object",
|
|
10750
|
+
properties: { skill_id: ID, undo: { type: "boolean", description: "true takes the like back" } },
|
|
10751
|
+
required: ["skill_id"]
|
|
10752
|
+
},
|
|
10753
|
+
group: "account",
|
|
10754
|
+
need: account3,
|
|
10755
|
+
risk: "W1",
|
|
10756
|
+
idempotent: true,
|
|
10757
|
+
run: async (ctx, a) => {
|
|
10758
|
+
const r = await ctx.api.skills.react(String(a.skill_id), "like", !a.undo);
|
|
10759
|
+
return { skill_id: r.item, liked: r.liked, likes: r.counts.likes };
|
|
10760
|
+
}
|
|
10761
|
+
}),
|
|
10762
|
+
tool({
|
|
10763
|
+
name: "skill_save",
|
|
10764
|
+
description: "Save a skill to the user's saved skills on cmo.so (or remove it with undo), to find it again at cmo.so/skills/saved or with skills_saved_list.",
|
|
10765
|
+
parameters: {
|
|
10766
|
+
type: "object",
|
|
10767
|
+
properties: { skill_id: ID, undo: { type: "boolean", description: "true removes it from saved" } },
|
|
10768
|
+
required: ["skill_id"]
|
|
10769
|
+
},
|
|
10770
|
+
group: "account",
|
|
10771
|
+
need: account3,
|
|
10772
|
+
risk: "W1",
|
|
10773
|
+
idempotent: true,
|
|
10774
|
+
run: async (ctx, a) => {
|
|
10775
|
+
const r = await ctx.api.skills.react(String(a.skill_id), "save", !a.undo);
|
|
10776
|
+
return { skill_id: r.item, saved: r.saved };
|
|
10777
|
+
}
|
|
10778
|
+
}),
|
|
10779
|
+
tool({
|
|
10780
|
+
name: "skills_saved_list",
|
|
10781
|
+
description: "The skills the user saved on cmo.so, newest first.",
|
|
10782
|
+
parameters: none,
|
|
10783
|
+
group: "account",
|
|
10784
|
+
need: account3,
|
|
10785
|
+
risk: "R0",
|
|
10786
|
+
run: async (ctx) => ({
|
|
10787
|
+
skills: (await ctx.api.skills.saved()).skills.map((s) => ({
|
|
10788
|
+
id: s.id,
|
|
10789
|
+
name: s.name,
|
|
10790
|
+
summary: s.summary,
|
|
10791
|
+
page: s.url
|
|
10792
|
+
}))
|
|
10793
|
+
})
|
|
10794
|
+
}),
|
|
10795
|
+
tool({
|
|
10796
|
+
name: "skill_submit",
|
|
10797
|
+
description: "Suggest a public open-source GitHub repo for cmo.so's skill library. Maggie researches it within minutes and decides: add a new skill, improve an existing one, keep it as a candidate that needs 10 likes in 30 days, or decline (licence first: permissive licences can be adapted, copyleft only inspires, no licence is declined). 3 suggestions a day. Follow up with skill_submissions_list.",
|
|
10798
|
+
parameters: {
|
|
10799
|
+
type: "object",
|
|
10800
|
+
properties: {
|
|
10801
|
+
repo_url: { type: "string", description: "https://github.com/owner/name" },
|
|
10802
|
+
note: { type: "string", description: "Optional: why it is useful, \u2264500 characters" }
|
|
10803
|
+
},
|
|
10804
|
+
required: ["repo_url"]
|
|
10805
|
+
},
|
|
10806
|
+
group: "account",
|
|
10807
|
+
need: account3,
|
|
10808
|
+
risk: "W1",
|
|
10809
|
+
run: async (ctx, a) => {
|
|
10810
|
+
const r = await ctx.api.skills.submit(String(a.repo_url), a.note ? String(a.note).slice(0, 500) : void 0);
|
|
10811
|
+
return r.duplicate ? { already_suggested: true, id: r.id, status: r.status, reasons: r.reasons ?? null } : { submitted: true, id: r.id, status: r.status, repo: r.repo };
|
|
10812
|
+
}
|
|
10813
|
+
}),
|
|
10814
|
+
tool({
|
|
10815
|
+
name: "skill_submissions_list",
|
|
10816
|
+
description: "The repos the user suggested for the skill library and what happened to each: queued, researching, candidate (with its deadline), publishing, published (with the skill), declined, expired or failed, with Maggie's reasons.",
|
|
10817
|
+
parameters: none,
|
|
10818
|
+
group: "account",
|
|
10819
|
+
need: account3,
|
|
10820
|
+
risk: "R0",
|
|
10821
|
+
run: async (ctx) => ({
|
|
10822
|
+
items: (await ctx.api.skills.submissions()).items.slice(0, 20).map((s) => ({
|
|
10823
|
+
id: s.id,
|
|
10824
|
+
repo: s.repo,
|
|
10825
|
+
status: s.status,
|
|
10826
|
+
skill: s.target_skill,
|
|
10827
|
+
reasons: clip(s.reasons, 500),
|
|
10828
|
+
candidate_until: s.candidate_until,
|
|
10829
|
+
suggested: s.created_at
|
|
10830
|
+
}))
|
|
10831
|
+
})
|
|
10832
|
+
})
|
|
10833
|
+
];
|
|
10834
|
+
|
|
10644
10835
|
// ../../packages/tools/src/social.ts
|
|
10645
10836
|
var read5 = { resource: "autopilot", level: "read" };
|
|
10646
10837
|
var write5 = { resource: "autopilot", level: "write" };
|
|
@@ -12097,7 +12288,8 @@ var tools = [
|
|
|
12097
12288
|
...socialTools,
|
|
12098
12289
|
...teamTools,
|
|
12099
12290
|
...memoryTools,
|
|
12100
|
-
...feedbackTools
|
|
12291
|
+
...feedbackTools,
|
|
12292
|
+
...skillTools
|
|
12101
12293
|
];
|
|
12102
12294
|
var toolByName = new Map(tools.map((t) => [t.name, t]));
|
|
12103
12295
|
function allowed(t, a) {
|
|
@@ -15490,7 +15682,7 @@ var program = new Command();
|
|
|
15490
15682
|
// package.json
|
|
15491
15683
|
var package_default = {
|
|
15492
15684
|
name: "@cmo-so/cli",
|
|
15493
|
-
version: "0.7.
|
|
15685
|
+
version: "0.7.5",
|
|
15494
15686
|
description: "CMO.so on the command line: your websites, ideas, blog posts, LinkedIn queue and results, plus a local MCP server for Claude Desktop, Cursor and other MCP clients.",
|
|
15495
15687
|
type: "module",
|
|
15496
15688
|
license: "MIT",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cmo-so/cli",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.5",
|
|
4
4
|
"description": "CMO.so on the command line: your websites, ideas, blog posts, LinkedIn queue and results, plus a local MCP server for Claude Desktop, Cursor and other MCP clients.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|