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