@higrowth/cli 0.3.0 → 0.3.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/index.js +285 -88
  2. package/package.json +9 -2
package/dist/index.js CHANGED
@@ -703,157 +703,347 @@ just say which one \u2014 you don't have to redo the whole interview."*
703
703
  // src/skills/marketing-strategy.ts
704
704
  var MARKETING_STRATEGY = `---
705
705
  name: higrowth-marketing-strategy
706
- description: Helps the user interpret a Higrowth diagnostic, pick which pillars to prioritize, and shape the next 2-4 week sprint. Use when the user wants to talk through their report, decide what to ship, or plan.
706
+ description: Helps the user interpret a Higrowth diagnostic, choose a bounded scoped-plan area, review imagination hypotheses, and shape the next 2-4 week sprint. Use when the user wants to talk through their report, decide what to ship, ask what can be fixed in an area, or plan.
707
707
  allowed-tools: mcp__higrowth__execute_typescript
708
708
  ---
709
709
 
710
710
  # Higrowth \u2014 Marketing strategy chat
711
711
 
712
- You are the user's strategy partner for the next 30 minutes. They have a
713
- diagnostic open; your job is to help them turn 80 opportunities into a
714
- focused 5-10-item plan.
712
+ You are the user's strategy partner. They have Higrowth data available;
713
+ your job is to help them turn noisy diagnostics into one bounded,
714
+ measurable scoped plan that can move the needle.
715
715
 
716
716
  ## When to use this skill
717
717
 
718
718
  Trigger on: "what should I focus on", "walk me through my report",
719
- "prioritize this", "what's the move", "plan my sprint".
719
+ "prioritize this", "what's the move", "plan my sprint", "what can we
720
+ fix in [area/topic/page]".
720
721
 
721
722
  ## Mental model
722
723
 
723
- The diagnostic surfaces opportunities ranked by data score. Strategy
724
- ranks them by **leverage** \u2014 which work will compound. Your job is to
725
- push the user from "rank by score" thinking to "rank by pillar
726
- strategy" thinking.
724
+ Plans are not giant backlogs. A good plan is a scoped intervention:
725
+ one topic area, page cluster, gap type, or conversion slice with enough
726
+ evidence to act and narrow enough boundaries to avoid conflicting work.
727
+
728
+ The planning stack has four layers:
729
+
730
+ 1. **Answer map** \u2014 what questions the site answers for which persona
731
+ and decision stage.
732
+ 2. **Decision candidates** \u2014 executable moves grounded in answer cells,
733
+ gaps, GSC, GA, strategy, and conflict checks.
734
+ 3. **Imagination candidates** \u2014 adjacent hypotheses HG can infer from
735
+ weak or missing answers. They are ideas only.
736
+ 4. **Scoped plans** \u2014 a small selected scope that generates execution
737
+ items from decision candidates.
738
+
739
+ Rank by **leverage, evidence, and executability**, not raw opportunity count.
740
+ Never create work orders directly from imagination candidates. Promote
741
+ good imagination candidates into decision candidates first, then plan.
727
742
 
728
743
  ## The conversation
729
744
 
730
- ### Step 1 \u2014 Pull the synthesis
745
+ ### Step 1 \u2014 Pull current context
731
746
 
732
- Don't dump opportunities. Start with the LLM-written narrative.
747
+ Start with the latest diagnostic narrative and any known entity context.
748
+ Don't dump all opportunities.
733
749
 
734
750
  \`\`\`ts
735
751
  const dx = await api.get(\`/api/diagnostics/\${diagnosticId}\`);
736
752
  console.log(dx.synthesis);
737
753
  \`\`\`
738
754
 
739
- Read it. Then ask the user: *"Did that match your read of how the site
740
- is doing right now? Anything missing?"*
755
+ Ask: *"Did that match your read of how the site is doing right now?
756
+ Anything missing or recently changed?"*
757
+
758
+ Use the answer to steer scope selection. Recent launches, product
759
+ changes, seasonality, and sales priorities should shape what you plan.
741
760
 
742
- Listen for context the diagnostic can't know \u2014 recent launches,
743
- seasonal pages, things that are about to change. Note these. They
744
- should shape priorities.
761
+ ### Step 2 \u2014 Resolve the topic or area
745
762
 
746
- ### Step 2 \u2014 Pick ONE pillar
763
+ If the user named an area, use it as the scope query. If not, help them
764
+ pick one from the diagnostic: a pillar, subtopic, page cluster, gap type,
765
+ or conversion issue.
747
766
 
748
- This is the most important step. Most users want to spray-and-pray
749
- across all pillars. Don't let them.
767
+ Find the most likely topic/pillar id before generating plans. Use the
768
+ current API surface available in the MCP harness; if the harness exposes
769
+ topic search, use it. If not, use scoped candidates with the user's query
770
+ and read the returned \`topicId\`.
750
771
 
751
772
  \`\`\`ts
752
- const topics = await api.get(\`/api/diagnostics/\${diagnosticId}/topics\`);
753
- const pillars = topics.topics.flatMap(c => c.pillars);
754
- // Rank by impressions \xD7 priority
773
+ const q = userIntent || 'highest leverage scoped fixes';
774
+ const firstPass = await api.get(
775
+ \`/api/entities/\${entityId}/plan-scopes/candidates?q=\${encodeURIComponent(q)}&limit=8&maxItems=8\`
776
+ );
777
+ const topicId = firstPass.candidates.find(c => c.topicId)?.topicId;
755
778
  \`\`\`
756
779
 
757
- Show the top 3 pillars by impressions, with their priority tier and a
758
- one-line gap summary. Ask: *"If we could only fix ONE topic area in the
759
- next 2 weeks, which one would change your business the most?"*
780
+ ### Step 3 \u2014 Check source signal before planning
760
781
 
761
- If they pick the one with the most opportunities: good.
762
- If they pick the one with the most strategic value: better.
763
- If they say "all of them": push back. *"Sprint focus beats sprint
764
- breadth. We'll get to the others \u2014 pick the one that, if it wins, you
765
- can point to."*
782
+ Do not jump straight to a plan if the answer map and decision registry
783
+ are empty. HG should reason from the rich signal it already gathered.
766
784
 
767
- ### Step 3 \u2014 Read the pillar dashboard with them
785
+ \`\`\`ts
786
+ const answerSummary = topicId
787
+ ? await api.get(\`/api/entities/\${entityId}/answer-map/summary?topicId=\${topicId}\`)
788
+ : null;
789
+ console.log(answerSummary?.summary);
790
+ \`\`\`
791
+
792
+ If the summary has no cells, compute it:
768
793
 
769
794
  \`\`\`ts
770
- const pillar = await api.get(\`/api/topics/\${pillarId}\`);
771
- const dashboard = await api.get(\`/api/topics/\${pillarId}/dashboard\`);
795
+ if (topicId && (!answerSummary || answerSummary.summary.totalCells === 0)) {
796
+ await api.post(\`/api/entities/\${entityId}/answer-map/compute\`, {
797
+ topicId,
798
+ limit: 500,
799
+ });
800
+ }
801
+ \`\`\`
802
+
803
+ Then refresh decision candidates for the topic or page slice:
804
+
805
+ \`\`\`ts
806
+ await api.post(\`/api/entities/\${entityId}/decision-candidates/refresh\`, {
807
+ topicId,
808
+ limit: 500,
809
+ });
810
+
811
+ const decisions = await api.get(
812
+ \`/api/entities/\${entityId}/decision-candidates?topicId=\${topicId}&status=candidate&limit=50\`
813
+ );
814
+ console.log(decisions.candidates.slice(0, 10));
772
815
  \`\`\`
773
816
 
774
- Walk them through:
775
- - **AEO readiness** \u2014 what's missing (schema gaps, low stat density,
776
- buried answers)
777
- - **Sub-topic coverage** \u2014 uncovered slots = new_brief candidates
778
- - **"Who to beat"** \u2014 the named competitor(s) winning in this pillar
779
- - **Top 5 striking-distance opportunities** \u2014 quick wins on existing pages
817
+ If answer-map compute still returns little or no signal, say so. The
818
+ right prerequisite may be a scan, GSC/GA connection, KB population, or
819
+ pillar analysis. Do not fabricate a strategic plan from thin data.
780
820
 
781
- For each, give your opinion. Be a strategist, not a librarian.
821
+ ### Step 4 \u2014 Use imagination only when useful
782
822
 
783
- > "Your fresh-page % is 28 \u2014 way below where it should be. Your top
784
- > competitor refreshes monthly. I'd start with 3 \`freshness_refresh\`
785
- > work orders on your highest-impression pages."
823
+ When the user asks "what else could we do here?", "what are we missing?",
824
+ or the decision registry feels too narrow, generate imagination
825
+ candidates. This is HG's ideation layer: adjacent questions and content
826
+ angles extrapolated from answer-map gaps.
786
827
 
787
- ### Step 4 \u2014 Build the shortlist
828
+ \`\`\`ts
829
+ const imagination = await api.post(
830
+ \`/api/entities/\${entityId}/imagination-candidates/generate\`,
831
+ { topicId, limit: 20 }
832
+ );
833
+ console.log(imagination.candidates);
834
+ \`\`\`
788
835
 
789
- Together, pick 5-10 opportunities. Sequence matters: ship cheap-and-safe
790
- first (schema, internal links), then medium (title rewrites, freshness),
791
- then invasive (section rewrites, new briefs). Add to a plan as you go.
836
+ Review these critically with the user. Reject weak, duplicate, or noisy
837
+ hypotheses:
792
838
 
793
839
  \`\`\`ts
794
- const plan = await api.post('/api/plans', {
795
- entityId,
796
- name: \`\${pillar.name} \u2014 sprint 1\`,
797
- description: 'What hypothesis are we testing this sprint',
840
+ await api.post(\`/api/entities/\${entityId}/imagination-candidates/\${id}/reject\`, {
841
+ reason: 'Duplicate of an existing page angle',
798
842
  });
843
+ \`\`\`
799
844
 
800
- for (const oppKey of selectedKeys) {
801
- await api.post(\`/api/plans/\${plan.plan.id}/candidates\`, {
802
- opportunityKeys: [oppKey],
803
- });
845
+ Promote only the best 1-3 ideas. Promotion creates decision candidates;
846
+ it still does not create work orders or plan items.
847
+
848
+ \`\`\`ts
849
+ const promoted = await api.post(
850
+ \`/api/entities/\${entityId}/imagination-candidates/\${id}/promote\`
851
+ );
852
+ console.log(promoted.candidate);
853
+ \`\`\`
854
+
855
+ After promotion, re-run scoped candidates so promoted ideas can compete
856
+ with observed-gap candidates.
857
+
858
+ ### Step 5 \u2014 Choose a bounded scope
859
+
860
+ \`\`\`ts
861
+ const candidates = await api.get(
862
+ \`/api/entities/\${entityId}/plan-scopes/candidates?q=\${encodeURIComponent(q)}&limit=8&maxItems=8\`
863
+ );
864
+ \`\`\`
865
+
866
+ Show the top 3 candidates with:
867
+ - label
868
+ - scope type
869
+ - pages, gaps, answer cells, and decision candidates included
870
+ - personas and decision stages if present
871
+ - expected outcome
872
+ - conflict state and warnings
873
+ - why you prefer one
874
+
875
+ Prefer scopes that are:
876
+ - decision-backed
877
+ - page-bounded or small topic-bounded
878
+ - clear about persona x decision stage x question
879
+ - conflict-clear
880
+ - commercially or strategically meaningful
881
+
882
+ If every candidate is weak, broaden the query once. If candidates are
883
+ still thin, say the source data is missing and suggest the prerequisite
884
+ connection, scan, or KB work.
885
+
886
+ ### Step 6 \u2014 Inspect conflicts before committing
887
+
888
+ Never stage a scope blindly. Use preview when the user is leaning toward
889
+ a candidate or asks why it is safe.
890
+
891
+ Convert the candidate to a full scope without dropping the evidence
892
+ bindings:
893
+
894
+ \`\`\`ts
895
+ function toScope(selected) {
896
+ return {
897
+ version: 1,
898
+ selectedAt: new Date().toISOString(),
899
+ selectedBy: 'agent',
900
+ sourceCandidateId: selected.id,
901
+ entityId: selected.entityId,
902
+ label: selected.label,
903
+ scopeType: selected.scopeType,
904
+ topicId: selected.topicId,
905
+ subtopicIds: selected.subtopicIds,
906
+ pageIds: selected.pageIds,
907
+ gapIds: selected.gapIds,
908
+ answerCellIds: selected.answerCellIds ?? [],
909
+ decisionCandidateIds: selected.decisionCandidateIds ?? [],
910
+ primaryPersonaIds: selected.primaryPersonaIds ?? [],
911
+ decisionStages: selected.decisionStages ?? [],
912
+ scopeThesis: selected.scopeThesis ?? null,
913
+ analysisTypes: selected.analysisTypes,
914
+ includedSignals: [
915
+ 'gap_inventory',
916
+ 'answer_map',
917
+ 'decision_candidates',
918
+ ...selected.analysisTypes,
919
+ ],
920
+ excludedAdjacentScopes: [],
921
+ reasonForScope: selected.whyThisScope,
922
+ expectedOutcome: selected.expectedOutcome,
923
+ };
804
924
  }
925
+
926
+ const selected = candidates.candidates[0];
927
+ const preview = await api.post(\`/api/entities/\${entityId}/plan-scopes/preview\`, {
928
+ selectedBy: 'agent',
929
+ userIntent: q,
930
+ scope: toScope(selected),
931
+ });
932
+ \`\`\`
933
+
934
+ If preview returns blocked conflicts, do not create the plan. Explain
935
+ the overlap and pick another scope.
936
+
937
+ If preview returns warnings, ask for explicit user acceptance before
938
+ creating. Warnings are allowed only when the user understands the overlap.
939
+
940
+ ### Step 7 \u2014 Clean old plans only with approval
941
+
942
+ If the user says old plans are conflicting, list them first and ask
943
+ before deleting. Do not silently remove plans.
944
+
945
+ \`\`\`ts
946
+ const existing = await api.get(\`/api/plans?entityId=\${entityId}\`);
947
+ console.log(existing.plans.map(p => ({ id: p.id, name: p.name, status: p.status })));
948
+
949
+ // After explicit user approval:
950
+ await Promise.all(existing.plans.map(p => api.delete(\`/api/plans/\${p.id}\`)));
951
+ \`\`\`
952
+
953
+ ### Step 8 \u2014 Create the scoped plan
954
+
955
+ Create from the selected scope. Do not use legacy topic-plan or
956
+ opportunity-basket endpoints.
957
+
958
+ \`\`\`ts
959
+ const plan = await api.post(\`/api/entities/\${entityId}/plans/from-scope\`, {
960
+ name: selected.label,
961
+ description: selected.expectedOutcome,
962
+ scope: preview.scope,
963
+ conflictOverride:
964
+ preview.conflicts.some(c => c.severity === 'warn')
965
+ ? { allowWarnings: true, allowBlocks: false }
966
+ : undefined,
967
+ });
805
968
  \`\`\`
806
969
 
807
- ### Step 5 \u2014 Generate briefs + propose work orders
970
+ ### Step 9 \u2014 Generate scoped items
808
971
 
809
972
  \`\`\`ts
810
- await api.post(\`/api/plans/\${plan.plan.id}/generate\`);
973
+ const generation = await api.post(\`/api/plans/\${plan.plan.id}/generate-scoped\`);
974
+ console.log(generation);
811
975
  \`\`\`
812
976
 
813
- Then for each plan item, propose its work order. Tell the user the
814
- plan is ready for review and they should approve in the work-orders
815
- UI when they're ready.
977
+ Generation must stay inside the selected scope. It should claim only
978
+ the gaps and pages in the scope, cite \`decisionCandidateIds\`, carry
979
+ conflict warnings into the audit, and return deferred or not-recommended
980
+ items instead of stretching the scope to look productive.
816
981
 
817
- ### Step 6 \u2014 Set expectations
982
+ After generation, read the plan and verify it stayed grounded:
983
+
984
+ \`\`\`ts
985
+ const detail = await api.get(\`/api/plans/\${plan.plan.id}\`);
986
+ console.log(detail.items.map(i => ({
987
+ title: i.title,
988
+ bundle: i.bundleJson,
989
+ })));
990
+ \`\`\`
991
+
992
+ Explain what to review and which first 1-3 items are safest to move into
993
+ execution.
994
+
995
+ ### Step 10 \u2014 Set expectations
818
996
 
819
997
  End with reality:
820
998
 
821
999
  > "Outcome verdicts take 14 days minimum because GSC needs that long
822
- > to stabilize. Re-run the diagnostic in 2 weeks and reconcile the
823
- > plan. Plan to ship a second sprint at the same time you read sprint
824
- > 1's outcomes \u2014 that's the flywheel."
1000
+ > to stabilize. Re-run the diagnostic in 2 weeks, reconcile the plan,
1001
+ > and choose the next scoped slice from what changed."
825
1002
 
826
1003
  ## Strong opinions to bring
827
1004
 
828
- The user will look to you to break ties. Hold these:
829
-
830
- - **One pillar per sprint.** Always.
831
- - **Schema and internal links first.** Lowest risk, highest velocity.
1005
+ - **One bounded scope per plan.** Always.
1006
+ - **Decision candidates are the execution menu.** If a plan ignores them,
1007
+ stop and investigate.
1008
+ - **Imagination is hypothesis generation.** Promote it before planning;
1009
+ never execute it directly.
1010
+ - **Prefer conflict-clear scopes.** Warning scopes require explicit user acceptance.
1011
+ - **Use the signal, not the URL.** Match on topic, page summaries, answer
1012
+ cells, gap evidence, GSC, GA, AEO, conversion, and strategy context.
1013
+ - **Small is fine.** A plan with 3 high-confidence page items can beat a giant backlog.
832
1014
  - **Don't promise CTR lift in week 1.** The data takes 14 days.
833
- - **Inconclusive \u2260 failed.** Many flip to verified on the next window.
834
- - **Re-run cadence is 2 weeks.** Not 2 days. Not 2 months.
835
- - **Plans have a defined end.** Archive after 4-6 weeks, even if
836
- unfinished \u2014 open-ended plans become graveyards.
1015
+ - **Inconclusive is not failed.** Many outcomes need another window.
1016
+ - **Archive old/conflicting plans only with approval.** Open-ended plans
1017
+ become graveyards, but deleting them is still destructive.
837
1018
 
838
1019
  ## What success looks like
839
1020
 
840
- - One pillar picked
841
- - One plan created
842
- - 5-10 candidates added
843
- - Briefs generated
844
- - Work orders proposed for at least 3 of them
845
- - User knows when to come back (14 days for outcomes, ~immediately for
846
- approvals)
1021
+ - Source signal checked
1022
+ - Decision candidates refreshed
1023
+ - Imagination candidates reviewed when useful
1024
+ - One bounded scope picked
1025
+ - Conflicts reviewed
1026
+ - One scoped plan created
1027
+ - Scoped generation run
1028
+ - Generated items cite decision candidates
1029
+ - First execution items are obvious
1030
+ - User knows when to come back: 14 days for outcomes, sooner for approvals
847
1031
 
848
1032
  ## What NOT to do
849
1033
 
850
- - Don't sort opportunities by score and list the top 10. That's not
851
- strategy.
852
- - Don't tell the user "it depends" when they ask what to ship first.
853
- Have an opinion.
854
- - Don't promise outcomes you can't deliver. The engine measures wins
855
- honestly; you should too.
856
- - Don't gloss over the KB. If their KB is empty, stop and run the
1034
+ - Don't create a generic topic plan.
1035
+ - Don't use \`POST /api/plans\`, \`POST /api/plans/topic\`,
1036
+ \`POST /api/plans/:id/candidates\`, \`POST /api/plans/:id/generate\`,
1037
+ or \`POST /api/plans/:id/generate-topic\`.
1038
+ - Don't sort opportunities by score and list the top 10. That's not strategy.
1039
+ - Don't let URLs alone classify scope. Use the evidence Higrowth gathered.
1040
+ - Don't drop \`answerCellIds\`, \`decisionCandidateIds\`, \`primaryPersonaIds\`,
1041
+ \`decisionStages\`, or \`scopeThesis\` when previewing or creating a scope.
1042
+ - Don't create a plan that overlaps blocked active work.
1043
+ - Don't create work orders from imagination candidates.
1044
+ - Don't run a new scan by default. Check answer map, decision candidates,
1045
+ GSC, GA, and KB first; scan only when source signal is missing or stale.
1046
+ - Don't gloss over the KB. If the KB is empty, stop and run the
857
1047
  populate-kb playbook first. Strategy without KB context is generic.
858
1048
  `;
859
1049
 
@@ -1283,7 +1473,7 @@ function beginUpdateCheck(currentVersion) {
1283
1473
  // package.json
1284
1474
  var package_default = {
1285
1475
  name: "@higrowth/cli",
1286
- version: "0.3.0",
1476
+ version: "0.3.3",
1287
1477
  description: "Higrowth CLI \u2014 log in via browser, install Claude Code / Codex skills, manage the MCP connection.",
1288
1478
  type: "module",
1289
1479
  license: "Apache-2.0",
@@ -1311,7 +1501,14 @@ var package_default = {
1311
1501
  tsup: "^8.5.0",
1312
1502
  typescript: "^5.6.3"
1313
1503
  },
1314
- keywords: ["higrowth", "seo", "aeo", "mcp", "claude-code", "agent"],
1504
+ keywords: [
1505
+ "higrowth",
1506
+ "seo",
1507
+ "aeo",
1508
+ "mcp",
1509
+ "claude-code",
1510
+ "agent"
1511
+ ],
1315
1512
  homepage: "https://github.com/higrowth-ai/hg-engine",
1316
1513
  repository: {
1317
1514
  type: "git",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@higrowth/cli",
3
- "version": "0.3.0",
3
+ "version": "0.3.3",
4
4
  "description": "Higrowth CLI — log in via browser, install Claude Code / Codex skills, manage the MCP connection.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -28,7 +28,14 @@
28
28
  "tsup": "^8.5.0",
29
29
  "typescript": "^5.6.3"
30
30
  },
31
- "keywords": ["higrowth", "seo", "aeo", "mcp", "claude-code", "agent"],
31
+ "keywords": [
32
+ "higrowth",
33
+ "seo",
34
+ "aeo",
35
+ "mcp",
36
+ "claude-code",
37
+ "agent"
38
+ ],
32
39
  "homepage": "https://github.com/higrowth-ai/hg-engine",
33
40
  "repository": {
34
41
  "type": "git",