@higrowth/cli 0.3.3 → 0.3.4

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 +201 -27
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -703,7 +703,7 @@ 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, 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.
706
+ description: Helps the user interpret a Higrowth diagnostic, choose a bounded scoped-plan or topic-roadmap 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, create/update content from roadmap gaps, or plan.
707
707
  allowed-tools: mcp__higrowth__execute_typescript
708
708
  ---
709
709
 
@@ -717,7 +717,8 @@ measurable scoped plan that can move the needle.
717
717
 
718
718
  Trigger on: "what should I focus on", "walk me through my report",
719
719
  "prioritize this", "what's the move", "plan my sprint", "what can we
720
- fix in [area/topic/page]".
720
+ fix in [area/topic/page]", "what are the gaps in this topic", "plan this
721
+ roadmap", "what new pages or updates should we create".
721
722
 
722
723
  ## Mental model
723
724
 
@@ -725,20 +726,27 @@ Plans are not giant backlogs. A good plan is a scoped intervention:
725
726
  one topic area, page cluster, gap type, or conversion slice with enough
726
727
  evidence to act and narrow enough boundaries to avoid conflicting work.
727
728
 
728
- The planning stack has four layers:
729
+ The planning stack has five layers:
729
730
 
730
731
  1. **Answer map** \u2014 what questions the site answers for which persona
731
732
  and decision stage.
732
733
  2. **Decision candidates** \u2014 executable moves grounded in answer cells,
733
734
  gaps, GSC, GA, strategy, and conflict checks.
734
- 3. **Imagination candidates** \u2014 adjacent hypotheses HG can infer from
735
+ 3. **Topic roadmap** \u2014 the topic-area execution ledger: new pages to
736
+ create, pages to refresh, consolidation/removal, internal links, and
737
+ measurement/setup rows. When the user asks about a topic's gaps or
738
+ roadmap, these rows are a first-class planning source.
739
+ 4. **Imagination candidates** \u2014 adjacent hypotheses HG can infer from
735
740
  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.
741
+ 5. **Scoped plans** \u2014 a small selected scope that generates execution
742
+ items from roadmap rows, scoped gaps, pages, answer cells, or decision
743
+ candidates.
738
744
 
739
745
  Rank by **leverage, evidence, and executability**, not raw opportunity count.
740
746
  Never create work orders directly from imagination candidates. Promote
741
747
  good imagination candidates into decision candidates first, then plan.
748
+ Roadmap rows do not need promotion: use them directly when the user's
749
+ intent is to execute a topic roadmap.
742
750
 
743
751
  ## The conversation
744
752
 
@@ -818,6 +826,31 @@ If answer-map compute still returns little or no signal, say so. The
818
826
  right prerequisite may be a scan, GSC/GA connection, KB population, or
819
827
  pillar analysis. Do not fabricate a strategic plan from thin data.
820
828
 
829
+ Also check the topic roadmap when the user asks about a topic, gaps,
830
+ new content, content updates, or comprehensiveness:
831
+
832
+ \`\`\`ts
833
+ const roadmap = topicId
834
+ ? await api.get(\`/api/topics/\${topicId}/roadmap\`)
835
+ : null;
836
+ const openRoadmapItems =
837
+ roadmap?.items?.filter(item => item.status === 'open') ?? [];
838
+
839
+ console.log(openRoadmapItems.map(item => ({
840
+ id: item.id,
841
+ actionType: item.actionType,
842
+ title: item.title,
843
+ targetPageUrl: item.targetPageUrl,
844
+ queries: item.queries?.slice(0, 5) ?? [],
845
+ existingCoverage: item.coverage?.length ?? 0,
846
+ })));
847
+ \`\`\`
848
+
849
+ Roadmap rows answer: what new pages to create, which pages to update,
850
+ what to consolidate or remove, where internal links are missing, and
851
+ what measurement/setup work blocks confidence. Treat open roadmap rows
852
+ as source evidence, not as loose suggestions.
853
+
821
854
  ### Step 4 \u2014 Use imagination only when useful
822
855
 
823
856
  When the user asks "what else could we do here?", "what are we missing?",
@@ -857,6 +890,97 @@ with observed-gap candidates.
857
890
 
858
891
  ### Step 5 \u2014 Choose a bounded scope
859
892
 
893
+ If the user explicitly asked to execute a topic roadmap, prefer a
894
+ roadmap-derived scope over a generic candidate. The open roadmap rows
895
+ are the scope thesis.
896
+
897
+ \`\`\`ts
898
+ function compactRoadmapSourceId(topicId, items) {
899
+ const key = (items ?? [])
900
+ .map(item => item.id)
901
+ .sort()
902
+ .join('_')
903
+ .replace(/[^a-zA-Z0-9_-]/g, '')
904
+ .slice(0, 96) || 'open';
905
+ return \`roadmap_topic_v6_\${topicId}_\${key}\`;
906
+ }
907
+
908
+ function analysisTypesFromRoadmap(items) {
909
+ const types = new Set(['supply_tactical']);
910
+ for (const item of items ?? []) {
911
+ if (item.actionType === 'new_content') types.add('demand_pull');
912
+ if (item.actionType === 'internal_linking') types.add('structural');
913
+ if (item.actionType === 'page_refresh') types.add('positioning');
914
+ if (item.actionType === 'measurement') types.add('conversion');
915
+ }
916
+ return [...types];
917
+ }
918
+
919
+ function roadmapScope(topicId, topicName, entityId, openItems) {
920
+ const analysisTypes = analysisTypesFromRoadmap(openItems);
921
+ return {
922
+ version: 1,
923
+ selectedAt: new Date().toISOString(),
924
+ selectedBy: 'agent',
925
+ sourceCandidateId: compactRoadmapSourceId(topicId, openItems),
926
+ entityId,
927
+ label: \`\${topicName ?? 'Topic'} roadmap execution scope\`,
928
+ scopeType: 'subtopic',
929
+ topicId,
930
+ subtopicIds: [],
931
+ pageIds: [],
932
+ gapIds: [],
933
+ answerCellIds: [],
934
+ decisionCandidateIds: [],
935
+ primaryPersonaIds: [],
936
+ decisionStages: [],
937
+ scopeThesis: [
938
+ \`Use the \${topicName ?? 'selected topic'} roadmap as the execution source of truth.\`,
939
+ ...openItems.slice(0, 8).map((item, index) =>
940
+ [
941
+ \`\${index + 1}. \${item.title}\`,
942
+ \`Action: \${item.actionType} (\${item.priority} priority).\`,
943
+ item.recommendedAction ? \`Recommended move: \${item.recommendedAction}\` : null,
944
+ item.targetPageUrl ? \`Target page: \${item.targetPageUrl}\` : null,
945
+ item.queries?.length ? \`Queries/questions: \${item.queries.join('; ')}\` : null,
946
+ item.why ? \`Why: \${item.why}\` : null,
947
+ ].filter(Boolean).join(' ')
948
+ ),
949
+ ].join('\\n'),
950
+ analysisTypes,
951
+ includedSignals: [
952
+ 'topic_roadmap',
953
+ 'gap_inventory',
954
+ 'question_pool',
955
+ 'page_summaries',
956
+ 'serp_opportunities',
957
+ ...analysisTypes,
958
+ ],
959
+ excludedAdjacentScopes: [],
960
+ reasonForScope:
961
+ 'The user requested a plan that executes the currently open roadmap gaps for this topic.',
962
+ expectedOutcome:
963
+ 'Generate concrete plan items to create, refresh, consolidate, remove, link, or measure the pages called out by the open roadmap rows without cannibalizing existing topic coverage.',
964
+ };
965
+ }
966
+
967
+ const useRoadmapScope = topicId && openRoadmapItems.length > 0 &&
968
+ /roadmap|gaps|gap|new pages|new content|updates|refresh|comprehensive/i.test(userIntent ?? '');
969
+
970
+ let selected = null;
971
+ let preview = null;
972
+ if (useRoadmapScope) {
973
+ const scope = roadmapScope(topicId, topicName, entityId, openRoadmapItems);
974
+ preview = await api.post(\`/api/entities/\${entityId}/plan-scopes/preview\`, {
975
+ selectedBy: 'agent',
976
+ userIntent: q,
977
+ scope,
978
+ });
979
+ }
980
+ \`\`\`
981
+
982
+ If you are not in roadmap mode, use ranked scoped candidates:
983
+
860
984
  \`\`\`ts
861
985
  const candidates = await api.get(
862
986
  \`/api/entities/\${entityId}/plan-scopes/candidates?q=\${encodeURIComponent(q)}&limit=8&maxItems=8\`
@@ -866,14 +990,14 @@ const candidates = await api.get(
866
990
  Show the top 3 candidates with:
867
991
  - label
868
992
  - scope type
869
- - pages, gaps, answer cells, and decision candidates included
993
+ - pages, gaps, answer cells, roadmap rows, and decision candidates included
870
994
  - personas and decision stages if present
871
995
  - expected outcome
872
996
  - conflict state and warnings
873
997
  - why you prefer one
874
998
 
875
999
  Prefer scopes that are:
876
- - decision-backed
1000
+ - roadmap-backed or decision-backed
877
1001
  - page-bounded or small topic-bounded
878
1002
  - clear about persona x decision stage x question
879
1003
  - conflict-clear
@@ -881,17 +1005,18 @@ Prefer scopes that are:
881
1005
 
882
1006
  If every candidate is weak, broaden the query once. If candidates are
883
1007
  still thin, say the source data is missing and suggest the prerequisite
884
- connection, scan, or KB work.
1008
+ connection, scan, KB work, or roadmap generation.
885
1009
 
886
1010
  ### Step 6 \u2014 Inspect conflicts before committing
887
1011
 
888
1012
  Never stage a scope blindly. Use preview when the user is leaning toward
889
1013
  a candidate or asks why it is safe.
890
1014
 
891
- Convert the candidate to a full scope without dropping the evidence
892
- bindings:
1015
+ For non-roadmap scopes, convert the candidate to a full scope without
1016
+ dropping the evidence bindings:
893
1017
 
894
1018
  \`\`\`ts
1019
+ selected = candidates.candidates[0];
895
1020
  function toScope(selected) {
896
1021
  return {
897
1022
  version: 1,
@@ -923,12 +1048,13 @@ function toScope(selected) {
923
1048
  };
924
1049
  }
925
1050
 
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
- });
1051
+ if (!preview) {
1052
+ preview = await api.post(\`/api/entities/\${entityId}/plan-scopes/preview\`, {
1053
+ selectedBy: 'agent',
1054
+ userIntent: q,
1055
+ scope: toScope(selected),
1056
+ });
1057
+ }
932
1058
  \`\`\`
933
1059
 
934
1060
  If preview returns blocked conflicts, do not create the plan. Explain
@@ -956,9 +1082,11 @@ Create from the selected scope. Do not use legacy topic-plan or
956
1082
  opportunity-basket endpoints.
957
1083
 
958
1084
  \`\`\`ts
1085
+ const planLabel = selected?.label ?? preview.scope.label;
1086
+ const planDescription = selected?.expectedOutcome ?? preview.scope.expectedOutcome;
959
1087
  const plan = await api.post(\`/api/entities/\${entityId}/plans/from-scope\`, {
960
- name: selected.label,
961
- description: selected.expectedOutcome,
1088
+ name: planLabel,
1089
+ description: planDescription,
962
1090
  scope: preview.scope,
963
1091
  conflictOverride:
964
1092
  preview.conflicts.some(c => c.severity === 'warn')
@@ -975,9 +1103,11 @@ console.log(generation);
975
1103
  \`\`\`
976
1104
 
977
1105
  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.
1106
+ the gaps and pages in the scope, cite the selected evidence spine
1107
+ (\`topic_roadmap\` rows, scoped gaps, pages, answer cells, or
1108
+ \`decisionCandidateIds\`), carry conflict warnings into the audit, and
1109
+ return deferred or not-recommended items instead of stretching the scope
1110
+ to look productive.
981
1111
 
982
1112
  After generation, read the plan and verify it stayed grounded:
983
1113
 
@@ -992,7 +1122,36 @@ console.log(detail.items.map(i => ({
992
1122
  Explain what to review and which first 1-3 items are safest to move into
993
1123
  execution.
994
1124
 
995
- ### Step 10 \u2014 Set expectations
1125
+ ### Step 10 \u2014 Generate content briefs when the plan item is ready
1126
+
1127
+ For roadmap new-page rows or plan items that need a writer-ready brief,
1128
+ use the brief generator only when you can resolve a source question id
1129
+ from the roadmap row or its covered opportunity keys. Let the user add a
1130
+ thesis, proof point, competitor angle, product workflow, related product,
1131
+ use case, benefit, or unique take as \`guidance\`.
1132
+
1133
+ \`\`\`ts
1134
+ const brief = await api.post(
1135
+ \`/api/diagnostics/\${diagnosticId}/questions/\${questionId}/generate-brief\`,
1136
+ {
1137
+ targetPlanItemId: planItemId ?? null,
1138
+ guidance: userBriefGuidance ?? null,
1139
+ previousFailure: previousBriefFailure ?? null,
1140
+ }
1141
+ );
1142
+ console.log(brief);
1143
+ \`\`\`
1144
+
1145
+ A useful brief should cover focus keyword, secondary keywords, target
1146
+ questions, competitor/SERP and AEO shape, related products, use cases,
1147
+ benefits to include, the company's unique angle or thesis, outline, and
1148
+ key facts/proof the writer can cite.
1149
+
1150
+ If the generator asks for missing inputs, do not invent them. Surface the
1151
+ open questions to the user and use the brief chat/context flow to fill
1152
+ only those blanks. Then regenerate with the user's guidance.
1153
+
1154
+ ### Step 11 \u2014 Set expectations
996
1155
 
997
1156
  End with reality:
998
1157
 
@@ -1004,7 +1163,11 @@ End with reality:
1004
1163
 
1005
1164
  - **One bounded scope per plan.** Always.
1006
1165
  - **Decision candidates are the execution menu.** If a plan ignores them,
1007
- stop and investigate.
1166
+ stop and investigate, unless this is a roadmap-derived scope whose
1167
+ execution menu is the open roadmap rows.
1168
+ - **Topic roadmap rows are execution evidence.** Use them directly for
1169
+ topic-gap, new-page, page-refresh, consolidation, internal-link, and
1170
+ measurement planning.
1008
1171
  - **Imagination is hypothesis generation.** Promote it before planning;
1009
1172
  never execute it directly.
1010
1173
  - **Prefer conflict-clear scopes.** Warning scopes require explicit user acceptance.
@@ -1019,13 +1182,17 @@ End with reality:
1019
1182
  ## What success looks like
1020
1183
 
1021
1184
  - Source signal checked
1185
+ - Topic roadmap checked when the user asks about topic gaps, new pages,
1186
+ updates, or comprehensiveness
1022
1187
  - Decision candidates refreshed
1023
1188
  - Imagination candidates reviewed when useful
1024
1189
  - One bounded scope picked
1025
1190
  - Conflicts reviewed
1026
1191
  - One scoped plan created
1027
1192
  - Scoped generation run
1028
- - Generated items cite decision candidates
1193
+ - Generated items cite the selected evidence spine
1194
+ - Content briefs generated only from resolvable roadmap/plan-item source
1195
+ questions, with user guidance captured when needed
1029
1196
  - First execution items are obvious
1030
1197
  - User knows when to come back: 14 days for outcomes, sooner for approvals
1031
1198
 
@@ -1037,10 +1204,17 @@ End with reality:
1037
1204
  or \`POST /api/plans/:id/generate-topic\`.
1038
1205
  - Don't sort opportunities by score and list the top 10. That's not strategy.
1039
1206
  - Don't let URLs alone classify scope. Use the evidence Higrowth gathered.
1207
+ - Don't ignore open topic roadmap rows when the user asks for topic gaps,
1208
+ comprehensiveness, new pages, or content updates.
1040
1209
  - Don't drop \`answerCellIds\`, \`decisionCandidateIds\`, \`primaryPersonaIds\`,
1041
1210
  \`decisionStages\`, or \`scopeThesis\` when previewing or creating a scope.
1211
+ For roadmap scopes, preserve the roadmap rows in \`scopeThesis\` and
1212
+ include \`topic_roadmap\` in \`includedSignals\`.
1042
1213
  - Don't create a plan that overlaps blocked active work.
1043
1214
  - Don't create work orders from imagination candidates.
1215
+ - Don't hand-write content briefs when the brief generator has a source
1216
+ question. Generate, inspect open questions, collect guidance, then
1217
+ regenerate.
1044
1218
  - Don't run a new scan by default. Check answer map, decision candidates,
1045
1219
  GSC, GA, and KB first; scan only when source signal is missing or stale.
1046
1220
  - Don't gloss over the KB. If the KB is empty, stop and run the
@@ -1228,7 +1402,7 @@ var SKILLS = [
1228
1402
  {
1229
1403
  slug: "higrowth-marketing-strategy",
1230
1404
  title: "Marketing strategy chat",
1231
- description: "Walk a diagnostic, pick a pillar, build the sprint plan.",
1405
+ description: "Walk a diagnostic, pick a scoped topic or roadmap, build the sprint plan.",
1232
1406
  body: MARKETING_STRATEGY
1233
1407
  },
1234
1408
  {
@@ -1473,7 +1647,7 @@ function beginUpdateCheck(currentVersion) {
1473
1647
  // package.json
1474
1648
  var package_default = {
1475
1649
  name: "@higrowth/cli",
1476
- version: "0.3.3",
1650
+ version: "0.3.4",
1477
1651
  description: "Higrowth CLI \u2014 log in via browser, install Claude Code / Codex skills, manage the MCP connection.",
1478
1652
  type: "module",
1479
1653
  license: "Apache-2.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@higrowth/cli",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
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",