@cmo-so/cli 0.7.1 → 0.7.3

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.
Files changed (2) hide show
  1. package/dist/cmo.mjs +119 -3
  2. package/package.json +1 -1
package/dist/cmo.mjs CHANGED
@@ -7353,6 +7353,14 @@ function createApi({ baseUrl, session: session2, fetch: fetchImpl = globalThis.f
7353
7353
  apps: () => request("/v1/me/apps"),
7354
7354
  revokeApp: (grantId) => request(`/v1/me/apps/${encodeURIComponent(grantId)}`, { method: "DELETE" }),
7355
7355
  invoices: () => request("/v1/me/invoices"),
7356
+ /**
7357
+ * Take a website off your own list (archives your claim; reversible on ai.cmo.so). Nothing changes for
7358
+ * anyone else; a team member also leaves the team.
7359
+ */
7360
+ removeWebsite: (domain) => request(
7361
+ `/v1/me/websites/${encodeURIComponent(domain)}/remove`,
7362
+ { method: "POST" }
7363
+ ),
7356
7364
  /** Delete the account (only from the person's own sign-in). Websites stay, unclaimed; plans stop renewing. */
7357
7365
  delete: () => request("/v1/me/delete", {
7358
7366
  method: "POST",
@@ -7640,6 +7648,11 @@ function domainApi(api2, domain) {
7640
7648
  wordpressPlugin: () => api2.request(`${base}/wordpress-plugin`),
7641
7649
  // Writes (need autopilot write on the domain).
7642
7650
  addIdea: (input) => post(`${base}/ideas`, input),
7651
+ /**
7652
+ * Up to 100 ideas exactly as given (no AI, no generation used): they wait in the pool, not the plan, and count
7653
+ * toward the 100 waiting ideas a person may add. Duplicates (title or page) are skipped and listed.
7654
+ */
7655
+ addIdeas: (ideas2) => post(`${base}/ideas/bulk`, { ideas: ideas2 }),
7643
7656
  /** Ideas built on up to 10 photos (base64 JPEG). The server keeps no copy. */
7644
7657
  ideasFromPhotos: (photos, count, brief2 = "") => post(`${base}/ideas/from-photos`, { photos, count, brief: brief2 }),
7645
7658
  generateIdeas: (count, brief2 = "") => post(`${base}/ideas/generate`, { count, brief: brief2 }),
@@ -8089,6 +8102,18 @@ function domainApi(api2, domain) {
8089
8102
  body: JSON.stringify(r)
8090
8103
  }
8091
8104
  ),
8105
+ /** Competitors Maggie found with Google Search, waiting for the user to add or dismiss (docs/25). */
8106
+ competitorSuggestions: () => api2.request(
8107
+ `${base}/competitors/suggestions`
8108
+ ),
8109
+ /** Put a suggestion in the business profile's competitors. */
8110
+ addCompetitorSuggestion: (id) => post(
8111
+ `${base}/competitors/suggestions/${encodeURIComponent(id)}/add`
8112
+ ),
8113
+ /** Not a competitor: never suggested or read for ideas again. */
8114
+ dismissCompetitorSuggestion: (id) => post(`${base}/competitors/suggestions/${encodeURIComponent(id)}/dismiss`),
8115
+ /** Look for new competitors now (once a day; subscribed websites only, else 402). */
8116
+ refreshCompetitorSuggestions: () => post(`${base}/competitors/suggestions/refresh`),
8092
8117
  /** The last time posts delivered by API pull were found in the website's sitemap (gives them their address). */
8093
8118
  sitemapMatch: () => api2.request(`${base}/rewrites/sitemap-match`),
8094
8119
  /** Read the sitemap (found on its own when blank) and match API-pull posts to their live address. */
@@ -9282,6 +9307,41 @@ var blogTools = [
9282
9307
  return ws(ctx).addIdea(url ? { url } : { text: text3 });
9283
9308
  }
9284
9309
  }),
9310
+ tool({
9311
+ 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; at most 100 of a person's own ideas can wait at once.",
9313
+ parameters: {
9314
+ type: "object",
9315
+ properties: {
9316
+ ideas: {
9317
+ type: "array",
9318
+ items: {
9319
+ type: "object",
9320
+ properties: {
9321
+ title: { type: "string" },
9322
+ description: { type: "string" },
9323
+ keyword: { type: "string", description: "The primary keyword" },
9324
+ keywords: { type: "array", items: { type: "string" } },
9325
+ url: { type: "string", description: "A benchmark page" },
9326
+ priority: { type: "integer", minimum: 1, maximum: 10 },
9327
+ topic: { type: "string", description: "One of topics_list, if it fits" }
9328
+ },
9329
+ required: ["title"]
9330
+ }
9331
+ }
9332
+ },
9333
+ required: ["ideas"]
9334
+ },
9335
+ group: "blog",
9336
+ need: write,
9337
+ risk: "W1",
9338
+ run: async (ctx, { ideas: ideas2 }) => {
9339
+ if (!ideas2?.length) throw new Error("Give at least one idea.");
9340
+ if (ideas2.length > 100) throw new Error("Up to 100 ideas at a time.");
9341
+ const out = await ws(ctx).addIdeas(ideas2);
9342
+ return { added: out.added, skipped: out.skipped, room_left: out.room_left };
9343
+ }
9344
+ }),
9285
9345
  tool({
9286
9346
  name: "ideas_generate",
9287
9347
  description: "Let Maggie come up with new ideas (1\u201310) with AI, optionally about a theme.",
@@ -9353,7 +9413,7 @@ var blogTools = [
9353
9413
  }),
9354
9414
  tool({
9355
9415
  name: "idea_plan",
9356
- description: "Add a waiting idea to the end of the plan (the plan holds at most 10).",
9416
+ description: "Add a waiting idea to the end of the plan (the plan holds up to 100).",
9357
9417
  parameters: {
9358
9418
  type: "object",
9359
9419
  properties: {
@@ -9644,6 +9704,60 @@ var brandTools = [
9644
9704
  return { competitors: out.competitors?.map((x) => x.name) };
9645
9705
  }
9646
9706
  }),
9707
+ tool({
9708
+ name: "competitor_suggestions_list",
9709
+ description: "Competitors Maggie found on the web (each website checked) that the user hasn't added to the profile or dismissed yet: name, website, one line, and how many ideas came from their site. Their sitemaps are already used for blog ideas while they wait.",
9710
+ parameters: none,
9711
+ group: "brand",
9712
+ need: { resource: "overview", level: "read" },
9713
+ risk: "R0",
9714
+ run: async (ctx) => {
9715
+ const out = await ws(ctx).competitorSuggestions();
9716
+ return {
9717
+ searched_at: out.searched_at,
9718
+ suggestions: out.items.map(({ id, name, website, description: description2, ideas_found }) => ({
9719
+ id,
9720
+ name,
9721
+ website,
9722
+ description: description2,
9723
+ ideas_found
9724
+ }))
9725
+ };
9726
+ }
9727
+ }),
9728
+ tool({
9729
+ name: "competitor_suggestion_add",
9730
+ description: "Add one of Maggie's competitor suggestions (id from competitor_suggestions_list) to the business profile.",
9731
+ parameters: { type: "object", properties: { id: { type: "string" } }, required: ["id"] },
9732
+ group: "brand",
9733
+ need: write2,
9734
+ risk: "W1",
9735
+ run: async (ctx, { id }) => {
9736
+ const out = await ws(ctx).addCompetitorSuggestion(id);
9737
+ return { competitors: out.competitors.map((c) => c.name) };
9738
+ }
9739
+ }),
9740
+ tool({
9741
+ name: "competitor_suggestion_dismiss",
9742
+ description: "Not a competitor after all: the suggestion is never made again and its site is no longer read for ideas.",
9743
+ parameters: { type: "object", properties: { id: { type: "string" } }, required: ["id"] },
9744
+ group: "brand",
9745
+ need: write2,
9746
+ risk: "W1",
9747
+ run: async (ctx, { id }) => ws(ctx).dismissCompetitorSuggestion(id)
9748
+ }),
9749
+ tool({
9750
+ name: "competitor_suggestions_find",
9751
+ description: "Look for new competitors on the web now (once a day per website, subscribed websites only; Maggie also looks on her own once the website and its known competitors have no new pages left). New ones come back as suggestions; nothing is added to the profile.",
9752
+ parameters: none,
9753
+ group: "brand",
9754
+ need: write2,
9755
+ risk: "W1",
9756
+ run: async (ctx) => {
9757
+ const out = await ws(ctx).refreshCompetitorSuggestions();
9758
+ return { found: out.found, suggestions: out.items.map(({ id, name, website }) => ({ id, name, website })) };
9759
+ }
9760
+ }),
9647
9761
  tool({
9648
9762
  name: "brand_research_update",
9649
9763
  description: "Change the profile's market notes: market_research (text), additional_information (anything else Maggie should know) or the SWOT list (each {name: Strengths|Weaknesses|Opportunities|Threats, description}). A list replaces the whole list.",
@@ -15376,7 +15490,7 @@ var program = new Command();
15376
15490
  // package.json
15377
15491
  var package_default = {
15378
15492
  name: "@cmo-so/cli",
15379
- version: "0.7.1",
15493
+ version: "0.7.3",
15380
15494
  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.",
15381
15495
  type: "module",
15382
15496
  license: "MIT",
@@ -25607,12 +25721,14 @@ var OPEN_WORLD = /* @__PURE__ */ new Set([
25607
25721
  "social_video_add",
25608
25722
  "seo_audit_run",
25609
25723
  "ai_visibility_prompt_check",
25610
- "idea_add"
25724
+ "idea_add",
25725
+ "competitor_suggestions_find"
25611
25726
  ]);
25612
25727
  var OVERWRITES = /* @__PURE__ */ new Set([
25613
25728
  "ai_visibility_keywords_set",
25614
25729
  "brand_research_update",
25615
25730
  "brand_update",
25731
+ "competitor_suggestion_dismiss",
25616
25732
  "draft_rewrite",
25617
25733
  "draft_rewrite_save",
25618
25734
  "draft_update",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cmo-so/cli",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
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",