fullstackgtm 0.43.0 → 0.45.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.
Files changed (130) hide show
  1. package/CHANGELOG.md +378 -1
  2. package/README.md +37 -14
  3. package/dist/audit.d.ts +3 -1
  4. package/dist/audit.js +29 -2
  5. package/dist/cli/audit.d.ts +15 -0
  6. package/dist/cli/audit.js +392 -0
  7. package/dist/cli/auth.d.ts +80 -0
  8. package/dist/cli/auth.js +500 -0
  9. package/dist/cli/call.d.ts +1 -0
  10. package/dist/cli/call.js +373 -0
  11. package/dist/cli/capabilities.d.ts +30 -0
  12. package/dist/cli/capabilities.js +197 -0
  13. package/dist/cli/draft.d.ts +7 -0
  14. package/dist/cli/draft.js +87 -0
  15. package/dist/cli/enrich.d.ts +8 -0
  16. package/dist/cli/enrich.js +788 -0
  17. package/dist/cli/fix.d.ts +33 -0
  18. package/dist/cli/fix.js +344 -0
  19. package/dist/cli/help.d.ts +25 -0
  20. package/dist/cli/help.js +609 -0
  21. package/dist/cli/icp.d.ts +7 -0
  22. package/dist/cli/icp.js +229 -0
  23. package/dist/cli/init.d.ts +7 -0
  24. package/dist/cli/init.js +58 -0
  25. package/dist/cli/market.d.ts +1 -0
  26. package/dist/cli/market.js +391 -0
  27. package/dist/cli/plans.d.ts +5 -0
  28. package/dist/cli/plans.js +454 -0
  29. package/dist/cli/schedule.d.ts +8 -0
  30. package/dist/cli/schedule.js +479 -0
  31. package/dist/cli/shared.d.ts +70 -0
  32. package/dist/cli/shared.js +331 -0
  33. package/dist/cli/signals.d.ts +7 -0
  34. package/dist/cli/signals.js +412 -0
  35. package/dist/cli/suggest.d.ts +49 -0
  36. package/dist/cli/suggest.js +135 -0
  37. package/dist/cli/tam.d.ts +9 -0
  38. package/dist/cli/tam.js +387 -0
  39. package/dist/cli/ui.d.ts +121 -0
  40. package/dist/cli/ui.js +375 -0
  41. package/dist/cli.d.ts +1 -57
  42. package/dist/cli.js +104 -4556
  43. package/dist/connector.d.ts +15 -0
  44. package/dist/connector.js +35 -0
  45. package/dist/connectors/hubspot.d.ts +3 -1
  46. package/dist/connectors/hubspot.js +10 -3
  47. package/dist/connectors/outboxChannel.d.ts +64 -0
  48. package/dist/connectors/outboxChannel.js +170 -0
  49. package/dist/connectors/prospectSources.d.ts +22 -0
  50. package/dist/connectors/prospectSources.js +43 -0
  51. package/dist/connectors/salesforce.d.ts +3 -1
  52. package/dist/connectors/salesforce.js +12 -5
  53. package/dist/connectors/signalSources.d.ts +105 -0
  54. package/dist/connectors/signalSources.js +264 -0
  55. package/dist/connectors/theirstack.d.ts +84 -0
  56. package/dist/connectors/theirstack.js +125 -0
  57. package/dist/icp.d.ts +52 -4
  58. package/dist/icp.js +112 -35
  59. package/dist/index.d.ts +1 -0
  60. package/dist/index.js +1 -0
  61. package/dist/init.js +3 -0
  62. package/dist/judge.d.ts +2 -0
  63. package/dist/judge.js +6 -0
  64. package/dist/judgeEval.d.ts +7 -0
  65. package/dist/judgeEval.js +8 -1
  66. package/dist/marketClassify.d.ts +2 -0
  67. package/dist/marketClassify.js +7 -1
  68. package/dist/mcp-bin.js +2 -2
  69. package/dist/mcp.js +259 -166
  70. package/dist/runReport.d.ts +26 -0
  71. package/dist/runReport.js +15 -0
  72. package/dist/schedule.d.ts +80 -2
  73. package/dist/schedule.js +272 -5
  74. package/dist/signals.d.ts +54 -0
  75. package/dist/signals.js +64 -0
  76. package/dist/spoolFiles.d.ts +44 -0
  77. package/dist/spoolFiles.js +114 -0
  78. package/dist/tam.d.ts +225 -0
  79. package/dist/tam.js +470 -0
  80. package/dist/types.d.ts +11 -0
  81. package/docs/api.md +91 -11
  82. package/docs/outbox-format.md +92 -0
  83. package/docs/recipes.md +37 -0
  84. package/docs/roadmap-to-1.0.md +31 -1
  85. package/docs/signal-spool-format.md +175 -0
  86. package/docs/tam.md +195 -0
  87. package/llms.txt +83 -11
  88. package/package.json +1 -1
  89. package/skills/fullstackgtm/SKILL.md +4 -3
  90. package/src/audit.ts +27 -1
  91. package/src/cli/audit.ts +447 -0
  92. package/src/cli/auth.ts +549 -0
  93. package/src/cli/call.ts +398 -0
  94. package/src/cli/capabilities.ts +215 -0
  95. package/src/cli/draft.ts +101 -0
  96. package/src/cli/enrich.ts +885 -0
  97. package/src/cli/fix.ts +372 -0
  98. package/src/cli/help.ts +664 -0
  99. package/src/cli/icp.ts +265 -0
  100. package/src/cli/init.ts +65 -0
  101. package/src/cli/market.ts +423 -0
  102. package/src/cli/plans.ts +523 -0
  103. package/src/cli/schedule.ts +526 -0
  104. package/src/cli/shared.ts +375 -0
  105. package/src/cli/signals.ts +434 -0
  106. package/src/cli/suggest.ts +151 -0
  107. package/src/cli/tam.ts +435 -0
  108. package/src/cli/ui.ts +426 -0
  109. package/src/cli.ts +103 -5170
  110. package/src/connector.ts +46 -0
  111. package/src/connectors/hubspot.ts +14 -2
  112. package/src/connectors/outboxChannel.ts +202 -0
  113. package/src/connectors/prospectSources.ts +57 -0
  114. package/src/connectors/salesforce.ts +18 -2
  115. package/src/connectors/signalSources.ts +314 -0
  116. package/src/connectors/theirstack.ts +170 -0
  117. package/src/icp.ts +120 -34
  118. package/src/index.ts +32 -0
  119. package/src/init.ts +3 -0
  120. package/src/judge.ts +7 -0
  121. package/src/judgeEval.ts +8 -1
  122. package/src/marketClassify.ts +8 -1
  123. package/src/mcp-bin.ts +2 -2
  124. package/src/mcp.ts +130 -57
  125. package/src/runReport.ts +39 -0
  126. package/src/schedule.ts +330 -7
  127. package/src/signals.ts +90 -0
  128. package/src/spoolFiles.ts +116 -0
  129. package/src/tam.ts +654 -0
  130. package/src/types.ts +12 -0
@@ -0,0 +1,609 @@
1
+ // Extracted verbatim from src/cli.ts (mechanical split, no behavior change).
2
+ import { DEFAULT_LOOPBACK_PORT } from "../connectors/hubspotAuth.js";
3
+ export function usage() {
4
+ return `FullStackGTM — audit GTM data across providers, propose reviewable patch plans,
5
+ and apply only explicitly approved operations.
6
+
7
+ Usage:
8
+ fullstackgtm login --via <hosted url> pair with a team deployment (recommended)
9
+ fullstackgtm login hubspot [--no-validate]
10
+ fullstackgtm login hubspot --oauth --client-id <id> [--port ${DEFAULT_LOOPBACK_PORT}] [--scopes a,b]
11
+ fullstackgtm login salesforce --device --client-id <consumer key> [--login-url <url>]
12
+ fullstackgtm login salesforce --instance-url <url> [--no-validate]
13
+ fullstackgtm login stripe [--no-validate]
14
+ fullstackgtm login anthropic | openai store an LLM API key for call parse/score
15
+ fullstackgtm login apollo store an Apollo API key for enrich pulls\n fullstackgtm login pipe0 | explorium | theirstack store a discovery-provider key (theirstack = technographic TAM)\n fullstackgtm login heyreach store a HeyReach key for enrich acquire --source linkedin\n fullstackgtm logout <hubspot|salesforce|stripe|anthropic|openai|apollo|pipe0|explorium|heyreach|broker>
16
+
17
+ Secrets (tokens, client secrets) are NEVER passed as flags — they leak via
18
+ the process list and shell history. Pipe them on stdin or enter them at the
19
+ interactive prompt:
20
+ echo "$HUBSPOT_TOKEN" | fullstackgtm login hubspot
21
+ fullstackgtm init [--source pipe0|explorium|linkedin] [--provider hubspot|salesforce] [--out <dir>] [--force]
22
+ cold start: scaffold icp.json + enrich.config.json + a
23
+ PLAYBOOK wired for this workspace (the CLI ships primitives,
24
+ your agent is the orchestrator — see docs/recipes.md)
25
+ fullstackgtm snapshot [source options] [--since <iso>] [--out <path> | --archive <dir>]
26
+ fullstackgtm audit [source options] [audit options] [--save]
27
+ fullstackgtm report [source options] [audit options] [report options]
28
+ fullstackgtm diff --before <a.json> --after <b.json> [--json] [--fail-on-new-findings]
29
+ fullstackgtm merge --input <a.json> --input <b.json> [...] --out <merged.json> [--json]
30
+ fullstackgtm call parse --transcript <file> [--title t] [--source fathom|granola|...] [--model m] [--deterministic] [--json|--ndjson] [--out <path>]
31
+ fullstackgtm call classify --transcript <file>|--call <parsed.json> [--llm] [--deterministic] [--json]
32
+ fullstackgtm call score --transcript <file>|--call <parsed.json> [--call-type <t>] [--rubric <rubric.json>] [--model m] [--json|--out <path>]
33
+ fullstackgtm call link --attendees <a@x.com,...> | --domain <x.com> [source options] [--json]
34
+ fullstackgtm call plan --transcript <file>|--call <parsed.json> --deal <id> [source options] [--save|--json]
35
+ calls become evidence: LLM extraction by default (bring your own
36
+ Anthropic or OpenAI key — captured once on first use, or
37
+ ANTHROPIC_API_KEY/OPENAI_API_KEY, or \`login anthropic|openai\`);
38
+ --deterministic uses the free keyword baseline. Then link the call
39
+ to its deal and propose governed next-step writes.
40
+ fullstackgtm resolve <account|contact|deal> [--name N] [--domain D] [--email E] [--account-id A] [source options] [--json]
41
+ the create gate: exit 0 = safe to create, exit 2 = match
42
+ found (exists/ambiguous) — call before ANY record creation
43
+ fullstackgtm market init --category <name> start a market map: vendors + claim taxonomy as reviewable config
44
+ fullstackgtm market capture [--config <path>] [--run <label>]
45
+ fullstackgtm market classify [--run <label>] [--vendor <id>] [--model m] [--out <path>]
46
+ fullstackgtm market worksheet --vendor <id> [--out <path>]
47
+ fullstackgtm market observe --from <observations.json|sets.jsonl|spool-dir> [--unverified]
48
+ fullstackgtm market fronts [--run <label>] [--diff <prior-run>] [--json]
49
+ fullstackgtm market axes [--run <label>] [--json]
50
+ fullstackgtm market report [--run <label>] [--format md|html] [--out <path>]
51
+ fullstackgtm market overlay --snapshot <crm.json> [--calls <files>] [--save]
52
+ fullstackgtm market scale [--json]
53
+ fullstackgtm market refresh [--run <label>] [--model m]
54
+ the live competitive map: capture vendor pages (content-addressed),
55
+ classify intensity per claim (LLM bring-your-own-key, or fill the
56
+ worksheet with any agent) — every quoted span is verified verbatim
57
+ against the stored capture it cites before it's accepted — then
58
+ compute deterministic front states and drift, render the field
59
+ report. refresh = capture → classify → drift → report in one step
60
+ fullstackgtm tam estimate [--name <n>] [--icp <path>] (--accounts <n> | --source theirstack|explorium) (--acv <annual-usd> | --acv-from-crm --deal-period monthly|quarterly|annual) [--acv-basis account|buyer] [--buyers-per-account <n>] [--cross-checks <file.json>] [source options] [--json]
61
+ fullstackgtm tam status [--name <n>] <source options> [--save] [--json]
62
+ fullstackgtm tam report [--name <n>] [--out <path>]
63
+ fullstackgtm tam populate [--name <n>] --cron "<expr>" [--source pipe0|explorium|linkedin] [--provider hubspot|salesforce] [--label <l>]
64
+ size the reachable market FROM the ICP (a real account count ×
65
+ ACV; buyers/account = the contact population target), then fill
66
+ it: populate schedules plan-only enrich acquire --save (apply
67
+ stays gated), status --save stamps a coverage timeline, report
68
+ projects a burn-up + ETA. estimate --source probes the provider's
69
+ ICP-match count (else --accounts), always labeled provider-vs-assumption
70
+ fullstackgtm enrich append [--source apollo] [--objects companies,contacts] [--save] [--config <path>] [source options]
71
+ fullstackgtm enrich refresh [--source apollo] [--stale-days <n>] [--save] [--config <path>] [source options]
72
+ fullstackgtm enrich ingest <file.csv|payload.json|spool.jsonl|spool-dir> --source clay [--run-label <label>]
73
+ fullstackgtm enrich status [--runs] [--source <id>] [--json]
74
+ governed enrichment: pull (Apollo) or stage (Clay) third-party
75
+ data, match it to CRM records deterministically, and emit a
76
+ fill-blanks-only patch plan through the normal dry-run →
77
+ approve → apply gate. refresh re-checks stale stamped fields
78
+ and proposes updates only where the source value changed.
79
+ fullstackgtm signals fetch [--bucket job,…] [--source greenhouse,lever,ashby] [--watchlist <path|crm:seg>] [--keywords …] [--from <file.json|spool.jsonl|spool-dir>] [--save]
80
+ fullstackgtm signals list [--since 7d] [--bucket b] [--account d] [--unjudged]
81
+ fullstackgtm signals outcome --account <d> [--touch <id>] --result replied|meeting|bounced|no_reply
82
+ fullstackgtm signals weights [--explain]
83
+ detect fresh buying triggers (ATS hiring scrapes + staged
84
+ funding/company/social ingest), rank them, persist a local
85
+ signal ledger. READ-ONLY re: CRM — fetch NEVER emits a plan;
86
+ --save persists only the signal ledger. outcome feeds the
87
+ learned per-bucket weights.
88
+ fullstackgtm icp interview | set <answers.json> | show
89
+ fullstackgtm icp judge [--signals-from latest|<label>] [--with-history] [--prompt <path>] [--min-score 0] [--save]
90
+ fullstackgtm icp eval [--golden <path>|default] [--against-outcomes] [--min-accuracy 0.8] [--json]
91
+ build the ICP, then judge fresh signals into
92
+ send/nurture/skip (timing × fit × memory). Deterministic
93
+ baseline; LLM why-now + play with a key (gated verbatim).
94
+ eval grades the judge and exits 2 below the bar — the
95
+ probabilistic-judgment gate. Read-only; --save writes only
96
+ the local judge store.
97
+ fullstackgtm draft [--from-judge latest|<label>] [--min-score 80] [--prompt <path>] [--channel email|linkedin|task] [--save]
98
+ author one trigger-grounded opener per hot judge decision as
99
+ a governed create_task plan. First line must contain a
100
+ verbatim span of the why-now or the draft is rejected. Never
101
+ sends — --save stages a needs_approval plan for approve → apply.
102
+ fullstackgtm bulk-update <account|contact|deal> --where <expr> [--where …] (--set <field>=<value> [--set …] | --archive [--force-archive-duplicates] | --create-task <text>) [--require <field>=<value> …] [--guard <object>:<where>[;<where>]:<none|some> …] [source options] [--save] [--json] [--out <path>]
103
+ governed generic writes: filter the snapshot
104
+ (field=value, field!=value, field~substr, field!~substr,
105
+ field:empty, field:notempty, '|' = any-of; canonical fields
106
+ like ownerId, stage, closeDate, amount; relational
107
+ pseudo-fields account.name/domain/ownerId/contactCount/
108
+ openDealStages on deals and contacts, contactCount/
109
+ openDealCount/openDealStages on accounts) into a dry-run
110
+ patch plan. The full filter is re-verified per record at
111
+ apply time (incl. mid-apply rechecks); equality filters
112
+ double as preconditions; per-record ops apply
113
+ all-or-nothing; guards assert cross-record conditions.
114
+ --set <field>=from:<sourceField> derives the value PER
115
+ RECORD from the snapshot (relational sources like
116
+ account.ownerId included); records whose source is empty
117
+ are skipped and counted, never guessed. --archive refuses
118
+ records that share their identity key (account domain /
119
+ contact email) with another record — merge those with
120
+ \`dedupe\` instead, or --force-archive-duplicates.
121
+ fullstackgtm dedupe <account|contact|deal> --key <domain|email|name> [--keep richest|oldest] [source options] [--reason <text>] [--max-operations <n>] [--save] [--json] [--out <path>]
122
+ find duplicate groups by normalized identity key and build
123
+ a dry-run plan of merge_records operations — one per group,
124
+ deterministic survivor (richest = most populated data
125
+ fields, ties to lowest id; oldest = lowest id). Approve and
126
+ apply like any plan; merges are IRREVERSIBLE on apply.
127
+ fullstackgtm reassign (--from <ownerId> | --assign-unowned) --to <ownerId> [--objects account,contact,deal] [--where <expr> …] [--except-deal-stage <stage>] [--include-closed-deals] [source options] [--save] [--json] [--out <path>]
128
+ ownership handoff playbook: one bulk-update-style plan per
129
+ object type (ownerId=<from> → <to>). --assign-unowned instead
130
+ claims every ownerless record (ownerId:empty) for --to. Extra --where scoping
131
+ is account-lifted for deals/contacts (domain~.de becomes
132
+ account.domain~.de); --except-deal-stage <stage> excludes
133
+ deals in that stage AND every record whose account has an
134
+ open deal in it, re-verified per record at apply time.
135
+ Deal plans cover open deals only unless
136
+ --include-closed-deals.
137
+ fullstackgtm fix --rule <ruleId> --provider <name> [--min-confidence high|low] [--include-creates] [--today <iso>] [--yes|--confirm] [--dry-run]
138
+ one-shot composite: audit ONE rule → save the plan →
139
+ suggest values → approve only suggestion-backed operations
140
+ meeting the confidence bar (plus operations that need no
141
+ value) → with --yes (alias: --confirm), apply through the
142
+ provider and print a stage-by-stage summary. Without --yes
143
+ it stops after approval and prints the apply command;
144
+ --dry-run locks that stop even if --yes is present.
145
+ fullstackgtm schedule add "<command>" --cron "<expr>" [--label <name>] [--provider local]
146
+ fullstackgtm schedule list | remove <id> | enable <id> | disable <id> | run <id>
147
+ fullstackgtm schedule install | uninstall [--provider local]
148
+ fullstackgtm schedule status [<id>] [--runs <n>]
149
+ declare a cadence for any read/plan-side command (audit,
150
+ snapshot, enrich append|refresh, market capture|refresh,
151
+ suggest, report, doctor); install materializes enabled
152
+ entries into a sentinel-delimited managed crontab block.
153
+ Scheduling never auto-approves: apply is schedulable only
154
+ as apply --plan-id <id>, re-checked approved at run time.
155
+ fullstackgtm suggest --plan-id <id> | --plan <path> [source options] [--json] [--out <path>]
156
+ derive values for requires_human_* placeholders
157
+ from snapshot evidence, with confidence + reasons
158
+ fullstackgtm plans list [--status <s>] | show <id> | reject <id>
159
+ fullstackgtm plans approve <id> --operations <ids|all> [--value <opId>=<v>]
160
+ fullstackgtm plans approve <id> --values-from <suggestions.json> [--min-confidence high|low] [--include-creates]
161
+ fullstackgtm apply --plan-id <id> --provider <name>
162
+ fullstackgtm apply --plan-id <id> --channel outbox (render approved openers; transmits nothing)
163
+ fullstackgtm apply --plan <path> --provider <name> --approve <ids|all> [options]
164
+ fullstackgtm audit-log export [--out <path>] | verify --in <path> tamper-evident apply-run record
165
+ fullstackgtm rules [--json]
166
+ fullstackgtm profiles [--json] list credential profiles
167
+ fullstackgtm doctor [--json] check install, credentials, and next step
168
+ fullstackgtm capabilities [--json] machine-readable CLI contract for agents
169
+ fullstackgtm robot-docs print the shipped agent guide (SKILL.md)
170
+
171
+ Profiles (multi-organization use):
172
+ --profile <name> Scope credentials AND stored plans to a named profile
173
+ (also: FULLSTACKGTM_PROFILE). One profile per client
174
+ org keeps logins isolated and prevents a plan proposed
175
+ against one CRM from being applied through another's
176
+ credentials. Omitted = the default profile.
177
+
178
+ Plan lifecycle:
179
+ audit --save persists the dry-run plan to ~/.fullstackgtm/plans. Approve
180
+ specific operations (optionally with --value <opId>=<v> for placeholders),
181
+ then apply by id — the store enforces approval and records every run.
182
+
183
+ Authentication (checked in order):
184
+ 1. --token-env <name> explicit env var for this invocation (hubspot)
185
+ 2. ambient env HUBSPOT_ACCESS_TOKEN, or SALESFORCE_ACCESS_TOKEN +
186
+ SALESFORCE_INSTANCE_URL (CI, agent sandboxes)
187
+ 3. stored provider login fullstackgtm login <provider>; kept in ~/.fullstackgtm
188
+ (hubspot: private app token or loopback OAuth;
189
+ salesforce: device flow — code on any device, no
190
+ secret, silent refresh)
191
+ 4. broker pairing fullstackgtm login --via <url>: the team connects the
192
+ CRM once in the hosted dashboard; every paired CLI
193
+ uses those stored sync credentials from then on
194
+
195
+ Source options (snapshot and audit):
196
+ --sample Built-in minimal mock CRM data (default)
197
+ --demo Realistic generated mid-market CRM with injected hygiene issues
198
+ --seed <n> Demo PRNG seed (default 7; same seed, same data)
199
+ --input <path> Canonical GTM snapshot JSON file
200
+ --provider <name> Live provider snapshot: hubspot | salesforce | stripe (read-only)
201
+ --token-env <name> Env var holding the provider access token
202
+
203
+ Audit options:
204
+ --config <path> Config file (default: ./fullstackgtm.config.json if present)
205
+ { "policy": {...}, "rules": {"enabled":[],"disabled":[]},
206
+ "rulePackages": ["./team-rules.mjs"] }
207
+ --rules <ids> Comma-separated rule ids to run (default: all; see \`rules\`)
208
+ --json Print the JSON patch plan instead of markdown
209
+ --out <path> Also write the JSON patch plan to a file
210
+ --today <date> Override today's date for deterministic audits
211
+ --stale-days <n> Days without activity before an open deal is stale
212
+ --fail-on <severity> Exit 2 if any finding is at or above info|warning|critical
213
+
214
+ Report options (report renders the audit as a client-ready deliverable):
215
+ --plan <path> Render an existing plan JSON instead of re-auditing
216
+ (add --input <snapshot.json> for record counts)
217
+ --client <name> Organization name shown in the heading and summary
218
+ --title <text> Report heading (default "GTM Data Health Report")
219
+ --prepared-by <name> Attribution shown in the footer
220
+ --format <fmt> markdown (default) or html (self-contained, printable;
221
+ inferred from an --out path ending in .html)
222
+ --max-examples <n> Example records listed per rule (default 10)
223
+ --out <path> Write the report to a file instead of stdout
224
+
225
+ Apply options:
226
+ --plan <path> Patch plan JSON produced by \`audit --out\`
227
+ --provider hubspot Connector to apply through
228
+ --token-env <name> Env var holding the provider access token
229
+ --approve <ids|all> Comma-separated operation ids to apply, or "all"
230
+ --value <opId>=<v> Concrete value for a requires_human_* placeholder (repeatable)
231
+ --json Print the JSON run record instead of markdown
232
+
233
+ Exit codes:
234
+ 0 success · 1 error · 2 audit findings at/above the --fail-on threshold
235
+
236
+ Safety:
237
+ Audits are read-only. Apply writes only operations you explicitly approve,
238
+ and never writes requires_human_* placeholders without a --value override.`;
239
+ }
240
+ // Exported as the CLI's single source of truth for the command inventory:
241
+ // `capabilities` and `--help --json` derive their command lists and
242
+ // read-only/write-shaped classification from this table (via each entry's
243
+ // `phase`) instead of maintaining parallel hand-written lists.
244
+ export const HELP = {
245
+ // Get started
246
+ init: {
247
+ summary: "scaffold a workspace (icp.json + enrich.config.json + PLAYBOOK)",
248
+ phase: "Setup",
249
+ synopsis: [
250
+ "fullstackgtm init [--source pipe0|explorium|linkedin] [--provider hubspot|salesforce] [--out <dir>] [--force]",
251
+ ],
252
+ detail: "Cold start: writes a starter ICP, an acquire-ready enrich.config.json (with a visible assign seam so leads are never ownerless), and a PLAYBOOK wired with the cold-start + outbound-loop recipes for this workspace. Pure file-writer — no network, keeps existing files unless --force. The CLI ships governed primitives; your coding agent is the orchestrator (see docs/recipes.md).",
253
+ seeAlso: ["icp", "enrich", "signals"],
254
+ },
255
+ // Setup & health
256
+ login: {
257
+ summary: "connect a provider or LLM key (secrets via stdin/env, never argv)",
258
+ phase: "Setup",
259
+ synopsis: [
260
+ "fullstackgtm login --via <hosted url> pair with a team deployment",
261
+ "fullstackgtm login hubspot | salesforce | stripe",
262
+ "fullstackgtm login anthropic | openai | apollo",
263
+ ],
264
+ detail: "Secrets are NEVER passed as flags (they leak via the process list and shell history) — pipe on stdin or enter at the prompt: `echo \"$TOKEN\" | fullstackgtm login hubspot`.",
265
+ seeAlso: ["doctor", "logout", "profiles"],
266
+ },
267
+ logout: {
268
+ summary: "remove stored credentials for a provider",
269
+ phase: "Setup",
270
+ synopsis: ["fullstackgtm logout <hubspot|salesforce|stripe|anthropic|openai|apollo|pipe0|explorium|broker>"],
271
+ seeAlso: ["login", "doctor"],
272
+ },
273
+ doctor: {
274
+ summary: "check install, credentials, and the next step",
275
+ phase: "Setup",
276
+ synopsis: ["fullstackgtm doctor [--json]"],
277
+ detail: "Verifies Node version, the credential store, MCP peers, and prints what to run next.",
278
+ seeAlso: ["login", "audit"],
279
+ },
280
+ capabilities: {
281
+ summary: "print the machine-readable CLI contract (JSON)",
282
+ phase: "Setup",
283
+ synopsis: ["fullstackgtm capabilities [--json]"],
284
+ detail: "The agent front door: the command inventory with read-only vs write-shaped access (derived from this help table), the exit-code contract, safety defaults, and the MCP entrypoint — as JSON. Always prints JSON; --json is accepted for symmetry.",
285
+ seeAlso: ["robot-docs", "doctor"],
286
+ },
287
+ "robot-docs": {
288
+ summary: "print the shipped agent operating guide (SKILL.md)",
289
+ phase: "Setup",
290
+ synopsis: ["fullstackgtm robot-docs"],
291
+ detail: "Prints the packaged skills/fullstackgtm/SKILL.md — the maintained agent guide (the governed loop, safety invariants, and verb map; the same content `npx skills add fullstackgtm/core` installs) — instead of a third parallel hand-written guide.",
292
+ seeAlso: ["capabilities", "doctor"],
293
+ },
294
+ profiles: {
295
+ summary: "list credential profiles (one per client org)",
296
+ phase: "Setup",
297
+ synopsis: ["fullstackgtm profiles [--json]"],
298
+ detail: "`--profile <name>` (or FULLSTACKGTM_PROFILE) scopes credentials AND stored plans per org, so a plan proposed against one CRM can't be applied through another's credentials.",
299
+ seeAlso: ["login", "plans", "health"],
300
+ },
301
+ health: {
302
+ summary: "CRM health score + trend for the active profile (read-only)",
303
+ phase: "Detect",
304
+ synopsis: ["fullstackgtm health [--json]"],
305
+ detail: "The engagement-workspace rollup. Each `audit --save` stamps a deterministic 0–100 hygiene score (100 / (1 + severity-weighted findings per record)) onto the profile's timeline; `health` reports the current score, the change since the last audit, and per-rule deltas — turning episodic audits into a continuous record. Scope per client with `--profile <name>`.",
306
+ seeAlso: ["audit", "profiles", "report"],
307
+ },
308
+ // Detect — read-only
309
+ snapshot: {
310
+ summary: "pull a canonical GTM snapshot (read-only)",
311
+ phase: "Detect",
312
+ synopsis: ["fullstackgtm snapshot [source options] [--since <iso>] [--out <path> | --archive <dir>]"],
313
+ detail: "Materializes the provider's records as canonical JSON — the input every audit and write verb reads.",
314
+ options: [
315
+ ["--provider <name>", "hubspot | salesforce | stripe (read-only)"],
316
+ ["--demo", "realistic generated CRM with injected hygiene issues"],
317
+ ["--out <path>", "write the snapshot JSON to a file"],
318
+ ],
319
+ seeAlso: ["audit", "diff"],
320
+ },
321
+ audit: {
322
+ summary: "read-only hygiene audit → reviewable dry-run patch plan",
323
+ phase: "Detect",
324
+ synopsis: ["fullstackgtm audit [source options] [audit options] [--save]"],
325
+ detail: "The Detect layer of the loop. Runs deterministic rules over a snapshot and proposes a typed patch plan — nothing is written. Prints a summary (rule table + counts) by default; `--full` shows every operation. `--save` persists the plan for the suggest → approve → apply spine. For a client-ready writeup use `report`; for machine output add `--json`.",
326
+ options: [
327
+ ["--provider <name>", "live snapshot: hubspot | salesforce | stripe"],
328
+ ["--input <path>", "load a canonical GTM snapshot JSON file (from `snapshot --out`)"],
329
+ ["--demo", "try it with zero credentials on a messy generated CRM"],
330
+ ["--full", "show every operation, not just the rule summary"],
331
+ ["--rules <ids>", "comma-separated rule ids (default: all; see `rules`)"],
332
+ ["--fail-on <sev>", "exit 2 if any finding ≥ info|warning|critical"],
333
+ ["--save", "persist the dry-run plan for approve → apply"],
334
+ ["--json / --out <p>", "machine-readable plan to stdout / file"],
335
+ ],
336
+ seeAlso: ["report", "suggest", "plans", "apply", "diff"],
337
+ },
338
+ report: {
339
+ summary: "render an audit as a client-ready deliverable (md/html)",
340
+ phase: "Detect",
341
+ synopsis: ["fullstackgtm report [source options] [audit options] [report options]"],
342
+ detail: "The human-readable counterpart to `audit` — a clean summary instead of the full per-operation dump.",
343
+ options: [
344
+ ["--plan <path>", "render an existing plan JSON instead of re-auditing"],
345
+ ["--client <name>", "organization name in the heading/summary"],
346
+ ["--format <fmt>", "markdown (default) or self-contained html"],
347
+ ["--out <path>", "write to a file (html inferred from .html)"],
348
+ ],
349
+ seeAlso: ["audit"],
350
+ },
351
+ diff: {
352
+ summary: "compare two snapshots/plans; gate on new findings",
353
+ phase: "Detect",
354
+ synopsis: ["fullstackgtm diff --before <a.json> --after <b.json> [--json] [--fail-on-new-findings]"],
355
+ detail: "The regression primitive. Exit 2 when a (rule, record) pair fires that didn't before — wire it into CI to catch CRM rot.",
356
+ seeAlso: ["audit", "snapshot", "merge"],
357
+ },
358
+ rules: {
359
+ summary: "list the audit rule registry",
360
+ phase: "Detect",
361
+ synopsis: ["fullstackgtm rules [--json]"],
362
+ seeAlso: ["audit"],
363
+ },
364
+ // Prevent — gate writes before they happen
365
+ resolve: {
366
+ summary: "the create gate: exit 0 = safe to create, 2 = match exists",
367
+ phase: "Prevent",
368
+ synopsis: ["fullstackgtm resolve <account|contact|deal> [--name N] [--domain D] [--email E] [source options] [--json]"],
369
+ detail: "Prevention, not cleanup. Call before ANY record creation — a sync job, webhook, agent, or script. Returns exists/ambiguous/safe_to_create with matches and reasons; exit 2 = do not create.",
370
+ seeAlso: ["dedupe", "audit"],
371
+ },
372
+ // Remediate — governed writes (all produce plans; nothing writes outside approve → apply)
373
+ fix: {
374
+ summary: "one-shot composite: audit one rule → suggest → approve → apply",
375
+ phase: "Remediate",
376
+ synopsis: ["fullstackgtm fix --rule <ruleId> --provider <name> [--min-confidence high|low] [--include-creates] [--yes|--confirm] [--dry-run]"],
377
+ detail: "The whole governed loop for a single rule in one command. Without `--yes` (alias: `--confirm`) it stops after approval and prints the apply command; with `--yes` it applies suggestion-backed operations meeting the confidence bar and prints a stage-by-stage summary. `--dry-run` locks the stop-before-apply path even when `--yes` is present.",
378
+ seeAlso: ["audit", "suggest", "plans", "apply"],
379
+ },
380
+ // bulk-update previously had NO entry here even though shortUsage()'s
381
+ // Remediate group listed it — the render loop silently skipped it, so the
382
+ // front door never showed the verb and `help bulk-update` fell back to the
383
+ // short map. The entry also completes the derived `capabilities` inventory.
384
+ "bulk-update": {
385
+ summary: "governed generic writes: filter the snapshot into a dry-run plan",
386
+ phase: "Remediate",
387
+ synopsis: [
388
+ "fullstackgtm bulk-update <account|contact|deal> --where <expr> (--set <field>=<value> | --archive | --create-task <text>) [--save] … (run `bulk-update --help` for full options)",
389
+ ],
390
+ detail: "Filters the snapshot (field=value, field~substr, field:empty, '|' = any-of; relational pseudo-fields like account.domain) into a dry-run patch plan. The full filter is re-verified per record at apply time, equality filters double as preconditions, and per-record ops apply all-or-nothing.",
391
+ seeAlso: ["dedupe", "reassign", "plans", "apply"],
392
+ },
393
+ dedupe: {
394
+ summary: "merge duplicate groups by identity key (irreversible on apply)",
395
+ phase: "Remediate",
396
+ synopsis: ["fullstackgtm dedupe <account|contact|deal> --key <domain|email|name> [--keep richest|oldest] [--save] [--json]"],
397
+ detail: "Builds a dry-run plan of one merge_records op per duplicate group with a deterministic survivor (richest = most populated fields; oldest = lowest id). Approve and apply like any plan; merges are IRREVERSIBLE on apply.",
398
+ seeAlso: ["resolve", "plans", "apply"],
399
+ },
400
+ reassign: {
401
+ summary: "ownership handoff: one plan per object type",
402
+ phase: "Remediate",
403
+ synopsis: ["fullstackgtm reassign (--from <ownerId> | --assign-unowned) --to <ownerId> [--objects account,contact,deal] [--where <expr> …] [--save] [--json]"],
404
+ detail: "Extra `--where` scoping is account-lifted for deals/contacts. `--except-deal-stage <stage>` excludes that stage and any record whose account has an open deal in it, re-verified per record at apply.",
405
+ seeAlso: ["bulk-update", "plans", "apply"],
406
+ },
407
+ enrich: {
408
+ summary: "governed third-party enrichment (Apollo/Clay), fill-blanks-only",
409
+ phase: "Remediate",
410
+ synopsis: ["fullstackgtm enrich append|refresh|ingest|status … (run `enrich --help` for full options)"],
411
+ detail: "Pull (Apollo) or stage (Clay) data, match it to CRM records deterministically, and emit a fill-blanks-only patch plan through the normal dry-run → approve → apply gate. `refresh` re-checks stale stamped fields.",
412
+ seeAlso: ["plans", "apply", "schedule"],
413
+ },
414
+ // Calls → evidence
415
+ call: {
416
+ summary: "transcripts → evidence, rubric scores, deal links, governed writes",
417
+ phase: "Remediate",
418
+ synopsis: ["fullstackgtm call parse|classify|score|link|plan … (run `call --help` for full options)"],
419
+ detail: "`parse` normalizes any transcript into canonical segments + evidence (LLM by default, bring your own key; `--deterministic` for the free baseline). `classify` picks the call type, `score` rates it against the type's rubric, `link` finds the deal, `plan` proposes governed next-step writes.",
420
+ seeAlso: ["plans", "apply"],
421
+ },
422
+ // Govern — the plan/apply spine
423
+ suggest: {
424
+ summary: "derive values for requires_human_* placeholders (evidence-backed)",
425
+ phase: "Govern",
426
+ synopsis: ["fullstackgtm suggest --plan-id <id> | --plan <path> [source options] [--json] [--out <path>]"],
427
+ detail: "Read-only. Proposes concrete values with confidence + reasons from snapshot evidence; feed the output to `plans approve --values-from`. Never guesses — low/create/none-confidence entries are left to the human.",
428
+ seeAlso: ["audit", "plans", "apply"],
429
+ },
430
+ plans: {
431
+ summary: "plan lifecycle: list / show / approve / reject saved plans",
432
+ phase: "Govern",
433
+ synopsis: [
434
+ "fullstackgtm plans list [--status <s>] | show <id> | reject <id>",
435
+ "fullstackgtm plans approve <id> --operations <ids|all> [--value <opId>=<v>]",
436
+ "fullstackgtm plans approve <id> --values-from <suggestions.json> [--min-confidence high|low]",
437
+ ],
438
+ detail: "Approval is explicit and per-operation; placeholders need a concrete --value or a suggestion to be approvable.",
439
+ seeAlso: ["audit", "suggest", "apply"],
440
+ },
441
+ apply: {
442
+ summary: "write ONLY explicitly approved operations to a provider",
443
+ phase: "Govern / Verify",
444
+ synopsis: [
445
+ "fullstackgtm apply --plan-id <id> --provider <name>",
446
+ "fullstackgtm apply --plan-id <id> --channel outbox (render approved drafted openers to the outbox; transmits nothing)",
447
+ "fullstackgtm apply --plan <path> --provider <name> --approve <ids|all> [--value <opId>=<v>]",
448
+ ],
449
+ detail: "The only verb that mutates a CRM. Writes only operations approved via `plans approve` or `--approve`, with compare-and-set and readback. Never writes requires_human_* placeholders without a --value override.",
450
+ seeAlso: ["plans", "suggest", "audit-log"],
451
+ },
452
+ "audit-log": {
453
+ summary: "tamper-evident record of apply runs (export / verify)",
454
+ phase: "Verify",
455
+ synopsis: ["fullstackgtm audit-log export [--out <path>] | verify --in <path>"],
456
+ detail: "The Verify/Attribute layer — a signed, append-only record of every applied write.",
457
+ seeAlso: ["apply"],
458
+ },
459
+ merge: {
460
+ summary: "merge multiple plan/snapshot JSONs into one",
461
+ phase: "Govern",
462
+ synopsis: ["fullstackgtm merge --input <a.json> --input <b.json> [...] --out <merged.json> [--json]"],
463
+ seeAlso: ["diff", "audit"],
464
+ },
465
+ // Continuous
466
+ schedule: {
467
+ summary: "declare a cadence for read/plan-side commands (never auto-approves)",
468
+ phase: "Continuous",
469
+ synopsis: ["fullstackgtm schedule add|list|remove|enable|disable|run|install|status … (run `schedule --help` for full options)"],
470
+ detail: "Makes the loop continuous instead of episodic. Read/plan-side allowlist only (audit, snapshot, enrich, market, suggest, report, doctor). Scheduling NEVER auto-approves: apply is schedulable only as `apply --plan-id <id>`, re-checked approved at run time.",
471
+ seeAlso: ["audit", "enrich", "apply"],
472
+ },
473
+ // Market intelligence
474
+ market: {
475
+ summary: "live competitive category map (capture → classify → drift → report)",
476
+ phase: "Intelligence",
477
+ synopsis: ["fullstackgtm market init|capture|classify|worksheet|observe|fronts|axes|overlay|scale|report|refresh … (run `market --help` for full options)"],
478
+ detail: "Capture vendor pages (content-addressed), classify intensity per claim (LLM bring-your-own-key, or fill the worksheet with any agent), then compute deterministic front states and drift. Every quoted span is verified verbatim against the stored capture before it's accepted.",
479
+ seeAlso: ["tam"],
480
+ },
481
+ tam: {
482
+ summary: "size the reachable market from your ICP, then populate + track coverage",
483
+ phase: "Intelligence",
484
+ synopsis: ["fullstackgtm tam estimate|status|report|populate … (run `tam --help` for full options)"],
485
+ detail: "Estimate a defensible TAM from the ICP: a real account count (Explorium company count or --accounts) × a confirmed ANNUAL ACV (explicit --acv, or --acv-from-crm --deal-period to derive+annualize from closed-won — no band defaults, a bare --provider does NOT set ACV, refuses without one); buyers/account (explicit or CRM-derived) gives the contact target. Then iteratively fill it with scheduled `enrich acquire --save` runs (plan-only; apply stays gated). `status --save` stamps a coverage timeline so `report` projects how long full coverage will take.",
486
+ seeAlso: ["icp", "enrich", "schedule", "market"],
487
+ },
488
+ // Outbound intelligence — signals → judge → draft (the GTM brain)
489
+ signals: {
490
+ summary: "detect fresh buying triggers (ATS hiring + source connectors), ranked",
491
+ phase: "Detect",
492
+ synopsis: [
493
+ "fullstackgtm signals fetch [--bucket job,…] [--source greenhouse,lever,ashby] [--connector file,serpapi-news,hubspot-forms] [--connector-opt k=v] [--watchlist <path|crm:seg>] [--keywords …] [--from <file.json|spool.jsonl|spool-dir>] [--save]",
494
+ "fullstackgtm signals list [--since 7d] [--bucket b] [--account d] [--unjudged]",
495
+ "fullstackgtm signals outcome --account <d> [--touch <id>] --result replied|meeting|bounced|no_reply",
496
+ "fullstackgtm signals weights [--explain]",
497
+ ],
498
+ detail: "Read-only re: CRM — `fetch` NEVER emits a patch plan; `--save` persists only the local signal ledger. ATS adapters are no-auth; source connectors (`--connector`) pull from connected platforms with secrets via the credential ladder, never argv. `outcome` feeds the learned per-bucket `weights`.",
499
+ seeAlso: ["icp", "draft"],
500
+ },
501
+ icp: {
502
+ summary: "build the ICP, then judge fresh signals into send/nurture/skip",
503
+ phase: "Detect",
504
+ synopsis: [
505
+ "fullstackgtm icp interview | set <answers.json> | show",
506
+ "fullstackgtm icp judge [--signals-from latest|<label>] [--with-history] [--prompt <path>] [--min-score 0] [--save]",
507
+ "fullstackgtm icp eval [--golden <path>|default] [--against-outcomes] [--min-accuracy 0.8] [--json]",
508
+ ],
509
+ detail: "`judge` ranks unjudged signals by timing × fit × memory (deterministic baseline; LLM why-now + play with a key, gated verbatim). `eval` is the probabilistic-judgment gate — exits 2 below the bar. Read-only; --save writes only the local judge store.",
510
+ seeAlso: ["signals", "draft", "enrich"],
511
+ },
512
+ draft: {
513
+ summary: "author one trigger-grounded opener per hot decision as a governed plan",
514
+ phase: "Remediate",
515
+ synopsis: [
516
+ "fullstackgtm draft [--from-judge latest|<label>] [--min-score 80] [--prompt <path>] [--channel email|linkedin|task] [--save]",
517
+ ],
518
+ detail: "Takes hot judge decisions (send, score>=min) and stages ONE create_task opener each. The first line must contain a verbatim span of the why-now or the draft is rejected. Never sends — --save stages a needs_approval plan for `plans approve` -> `apply`.",
519
+ seeAlso: ["icp", "plans", "apply"],
520
+ },
521
+ };
522
+ // Verbs that print their own richer multi-subcommand help; runCli routes their
523
+ // `--help` to themselves, so commandHelp() only renders these via `help <verb>`.
524
+ export const BESPOKE_HELP = ["init", "call", "market", "tam", "enrich", "bulk-update", "schedule", "signals", "icp", "draft"];
525
+ // Lifecycle-grouped front door. One line per verb, organized by the
526
+ // Prevent→Detect→Remediate→Verify loop so a new user sees ~6 jobs, not 22 verbs.
527
+ export function shortUsage() {
528
+ const groups = [
529
+ ["Get started", ["init"]],
530
+ ["Setup & health", ["login", "logout", "doctor", "capabilities", "robot-docs", "profiles", "health"]],
531
+ ["Detect — read-only", ["audit", "report", "snapshot", "diff", "rules"]],
532
+ ["Prevent — gate writes", ["resolve"]],
533
+ ["Remediate — governed writes", ["fix", "bulk-update", "dedupe", "reassign", "enrich"]],
534
+ ["Calls → evidence", ["call"]],
535
+ ["Govern — the plan/apply spine", ["suggest", "plans", "apply", "audit-log", "merge"]],
536
+ ["Market intelligence", ["market", "tam"]],
537
+ ["Outbound — signals → judge → draft", ["signals", "icp", "draft"]],
538
+ ["Schedule — make it continuous", ["schedule"]],
539
+ ];
540
+ const pad = Math.max(...Object.keys(HELP).map((k) => k.length)) + 2;
541
+ const lines = [
542
+ "FullStackGTM — plan/apply for your GTM stack.",
543
+ "Audit CRM data, propose reviewable patch plans, apply only what you approve.",
544
+ "",
545
+ "Usage: fullstackgtm <command> [options]",
546
+ "",
547
+ ];
548
+ for (const [title, cmds] of groups) {
549
+ lines.push(`${title}:`);
550
+ for (const cmd of cmds) {
551
+ const entry = HELP[cmd];
552
+ if (!entry)
553
+ continue;
554
+ lines.push(` ${cmd.padEnd(pad)}${entry.summary}`);
555
+ }
556
+ lines.push("");
557
+ }
558
+ lines.push("Zoom in: fullstackgtm <command> --help focused help for one command", "Full ref: fullstackgtm help --full every flag and option", "Try it: fullstackgtm audit --demo zero-credential demo CRM", "", "Safety: audits are read-only; apply writes only operations you approve.");
559
+ return lines.join("\n");
560
+ }
561
+ /**
562
+ * Interactive-terminal styling for the short front door: a dimmed one-line
563
+ * brand header (name · version · active profile), bold title and command
564
+ * names, cyan lifecycle-group titles. Never applied to piped output — the
565
+ * plain shortUsage() text stays byte-identical (and `capabilities` keeps
566
+ * deriving from the HELP table, which this never touches).
567
+ */
568
+ export function stylizeShortUsage(text, p, info) {
569
+ if (!p.enabled)
570
+ return text;
571
+ const lines = text.split("\n").map((line, index) => {
572
+ if (index === 0)
573
+ return p.bold(line);
574
+ if (/^[A-Z][^:]*:$/.test(line))
575
+ return p.cyan(line);
576
+ const row = line.match(/^ (\S+)(\s{2,})(.*)$/);
577
+ if (row)
578
+ return ` ${p.bold(row[1])}${row[2]}${row[3]}`;
579
+ if (line.startsWith("Safety:"))
580
+ return p.dim(line);
581
+ return line;
582
+ });
583
+ return [p.dim(`fullstackgtm ${info.version} · profile ${info.profile}`), "", ...lines].join("\n");
584
+ }
585
+ // Focused help for a single command. Falls back to shortUsage() for anything
586
+ // unknown so `--help` never dead-ends on the full wall.
587
+ export function commandHelp(command) {
588
+ const entry = HELP[command];
589
+ if (!entry)
590
+ return shortUsage();
591
+ const lines = [`fullstackgtm ${command} — ${entry.summary}`, "", "Usage:"];
592
+ for (const s of entry.synopsis)
593
+ lines.push(` ${s}`);
594
+ if (entry.detail)
595
+ lines.push("", entry.detail);
596
+ if (entry.options?.length) {
597
+ lines.push("", "Options:");
598
+ const pad = Math.max(...entry.options.map(([f]) => f.length)) + 2;
599
+ for (const [flag, desc] of entry.options)
600
+ lines.push(` ${flag.padEnd(pad)}${desc}`);
601
+ }
602
+ lines.push("", `Lifecycle phase: ${entry.phase}`);
603
+ if (entry.seeAlso?.length)
604
+ lines.push(`See also: ${entry.seeAlso.join(", ")}`);
605
+ if (BESPOKE_HELP.includes(command))
606
+ lines.push("", `Run \`fullstackgtm ${command} --help\` for the full subcommand reference.`);
607
+ lines.push("", "Full reference: fullstackgtm help --full");
608
+ return lines.join("\n");
609
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * `icp` — develop and inspect the Ideal Customer Profile that targets acquire.
3
+ * The CLI can't run AskUserQuestion itself; `icp interview` emits the question
4
+ * spec an agent (Claude Code / Codex) drives with its AskUserQuestion tool, then
5
+ * `icp set` writes icp.json from the collected answers.
6
+ */
7
+ export declare function icpCommand(args: string[]): Promise<void>;