@revfleet/hscli 0.8.11 → 0.9.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 +186 -0
- package/README.md +223 -10
- package/dist/cli.js +29 -3
- package/dist/cli.js.map +1 -1
- package/dist/commands/agent/contracts.d.ts +3 -0
- package/dist/commands/agent/contracts.js +139 -0
- package/dist/commands/agent/contracts.js.map +1 -0
- package/dist/commands/agent/index.d.ts +3 -0
- package/dist/commands/agent/index.js +188 -0
- package/dist/commands/agent/index.js.map +1 -0
- package/dist/commands/agent/recipes.d.ts +13 -0
- package/dist/commands/agent/recipes.js +108 -0
- package/dist/commands/agent/recipes.js.map +1 -0
- package/dist/commands/agent/runner.d.ts +16 -0
- package/dist/commands/agent/runner.js +165 -0
- package/dist/commands/agent/runner.js.map +1 -0
- package/dist/commands/auth/index.js +64 -7
- package/dist/commands/auth/index.js.map +1 -1
- package/dist/commands/automation/index.js +30 -0
- package/dist/commands/automation/index.js.map +1 -1
- package/dist/commands/backup/index.d.ts +12 -0
- package/dist/commands/backup/index.js +459 -0
- package/dist/commands/backup/index.js.map +1 -0
- package/dist/commands/cms/content-ops.js +1 -1
- package/dist/commands/cms/content-ops.js.map +1 -1
- package/dist/commands/communication-preferences/index.js +207 -7
- package/dist/commands/communication-preferences/index.js.map +1 -1
- package/dist/commands/content-permissions/index.d.ts +22 -0
- package/dist/commands/content-permissions/index.js +141 -0
- package/dist/commands/content-permissions/index.js.map +1 -0
- package/dist/commands/context/index.d.ts +3 -0
- package/dist/commands/context/index.js +182 -0
- package/dist/commands/context/index.js.map +1 -0
- package/dist/commands/crm/associations.js +38 -0
- package/dist/commands/crm/associations.js.map +1 -1
- package/dist/commands/crm/custom-objects.js +39 -2
- package/dist/commands/crm/custom-objects.js.map +1 -1
- package/dist/commands/crm/dated.js +3 -3
- package/dist/commands/crm/dated.js.map +1 -1
- package/dist/commands/crm/migration.js +210 -2
- package/dist/commands/crm/migration.js.map +1 -1
- package/dist/commands/crm/properties.js +2 -1
- package/dist/commands/crm/properties.js.map +1 -1
- package/dist/commands/crm/property-batch.d.ts +1 -0
- package/dist/commands/crm/property-batch.js +44 -5
- package/dist/commands/crm/property-batch.js.map +1 -1
- package/dist/commands/crm/shared.js +21 -2
- package/dist/commands/crm/shared.js.map +1 -1
- package/dist/commands/crm/sync.js +1 -1
- package/dist/commands/crm/sync.js.map +1 -1
- package/dist/commands/doctor/index.js +193 -0
- package/dist/commands/doctor/index.js.map +1 -1
- package/dist/commands/email-tracking/index.d.ts +16 -0
- package/dist/commands/email-tracking/index.js +314 -0
- package/dist/commands/email-tracking/index.js.map +1 -0
- package/dist/commands/extensions/index.js +1 -1
- package/dist/commands/extensions/index.js.map +1 -1
- package/dist/commands/forms/index.js +15 -2
- package/dist/commands/forms/index.js.map +1 -1
- package/dist/commands/forms/legacy-v2.d.ts +7 -2
- package/dist/commands/forms/legacy-v2.js +103 -7
- package/dist/commands/forms/legacy-v2.js.map +1 -1
- package/dist/commands/guide/index.d.ts +3 -0
- package/dist/commands/guide/index.js +75 -16
- package/dist/commands/guide/index.js.map +1 -1
- package/dist/commands/internal/catalog.d.ts +1 -0
- package/dist/commands/internal/catalog.js +2 -0
- package/dist/commands/internal/catalog.js.map +1 -0
- package/dist/commands/internal/index.d.ts +26 -0
- package/dist/commands/internal/index.js +823 -0
- package/dist/commands/internal/index.js.map +1 -0
- package/dist/commands/internal-session.d.ts +15 -0
- package/dist/commands/internal-session.js +152 -0
- package/dist/commands/internal-session.js.map +1 -0
- package/dist/commands/lists/index.js +1 -1
- package/dist/commands/lists/index.js.map +1 -1
- package/dist/commands/marketing/email-audit.d.ts +32 -0
- package/dist/commands/marketing/email-audit.js +121 -0
- package/dist/commands/marketing/email-audit.js.map +1 -0
- package/dist/commands/marketing/index.js +2 -0
- package/dist/commands/marketing/index.js.map +1 -1
- package/dist/commands/mcp.js +5 -3
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/playbooks/index.d.ts +3 -0
- package/dist/commands/playbooks/index.js +228 -0
- package/dist/commands/playbooks/index.js.map +1 -0
- package/dist/commands/portals/index.d.ts +3 -0
- package/dist/commands/portals/index.js +132 -0
- package/dist/commands/portals/index.js.map +1 -0
- package/dist/commands/reports/index.d.ts +3 -0
- package/dist/commands/reports/index.js +479 -0
- package/dist/commands/reports/index.js.map +1 -0
- package/dist/commands/sales-content/index.d.ts +13 -0
- package/dist/commands/sales-content/index.js +59 -0
- package/dist/commands/sales-content/index.js.map +1 -0
- package/dist/commands/sales-templates/index.d.ts +3 -0
- package/dist/commands/sales-templates/index.js +88 -0
- package/dist/commands/sales-templates/index.js.map +1 -0
- package/dist/commands/seed/cms.js +28 -45
- package/dist/commands/seed/cms.js.map +1 -1
- package/dist/commands/sequences/index.d.ts +18 -0
- package/dist/commands/sequences/index.js +263 -0
- package/dist/commands/sequences/index.js.map +1 -0
- package/dist/commands/settings/index.js +450 -102
- package/dist/commands/settings/index.js.map +1 -1
- package/dist/commands/settings/site-settings.d.ts +3 -0
- package/dist/commands/settings/site-settings.js +106 -0
- package/dist/commands/settings/site-settings.js.map +1 -0
- package/dist/commands/ui/index.d.ts +3 -0
- package/dist/commands/ui/index.js +422 -0
- package/dist/commands/ui/index.js.map +1 -0
- package/dist/commands/workflows/index.js +2 -0
- package/dist/commands/workflows/index.js.map +1 -1
- package/dist/commands/workflows/preflight.d.ts +23 -0
- package/dist/commands/workflows/preflight.js +295 -0
- package/dist/commands/workflows/preflight.js.map +1 -0
- package/dist/core/action-contract.d.ts +43 -0
- package/dist/core/action-contract.js +207 -0
- package/dist/core/action-contract.js.map +1 -0
- package/dist/core/auth.d.ts +6 -0
- package/dist/core/auth.js +85 -0
- package/dist/core/auth.js.map +1 -1
- package/dist/core/http.d.ts +8 -0
- package/dist/core/http.js +37 -5
- package/dist/core/http.js.map +1 -1
- package/dist/core/id-maps.d.ts +27 -0
- package/dist/core/id-maps.js +204 -0
- package/dist/core/id-maps.js.map +1 -0
- package/dist/core/output.d.ts +2 -1
- package/dist/core/output.js +34 -0
- package/dist/core/output.js.map +1 -1
- package/dist/mcp/profiles.d.ts +14 -0
- package/dist/mcp/profiles.js +68 -0
- package/dist/mcp/profiles.js.map +1 -0
- package/dist/mcp/server.d.ts +5 -3
- package/dist/mcp/server.js +22 -5
- package/dist/mcp/server.js.map +1 -1
- package/docs/CAPABILITY_LIBRARY.md +29 -8
- package/docs/COMMAND_TREE.md +98 -17
- package/docs/COMPARISON.md +8 -5
- package/docs/COOKBOOK.md +127 -5
- package/docs/INTERNAL-ENDPOINTS-DISCOVERY.md +813 -0
- package/docs/INTERNAL-ENDPOINTS.md +371 -0
- package/docs/INTERNAL_ENDPOINTS.md +243 -0
- package/docs/MARKETING_SETUP.md +21 -1
- package/docs/MCP.md +28 -89
- package/docs/MCP_TOOL_CATALOG.md +192 -0
- package/docs/MIGRATION_ADAPTERS.md +115 -0
- package/docs/PORTAL_BACKUP.md +212 -0
- package/docs/PUBLISHING.md +1 -1
- package/docs/SALES_CONTENT_INTERNAL_PUNCH_LIST.md +504 -0
- package/docs/TUTORIALS/secure-agent-writes.md +49 -0
- package/docs/WHY_HOW_WHAT.md +10 -4
- package/package.json +4 -2
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
# Sales Content Internal Punch List
|
|
2
|
+
|
|
3
|
+
Status: staged backlog with a first migration-capable slice implemented.
|
|
4
|
+
Read surfaces are available for sales content, and narrow write/migration
|
|
5
|
+
helpers are available for sequences, sales templates, and playbooks. Broader
|
|
6
|
+
full-fidelity migration still requires sandbox contract testing before it should
|
|
7
|
+
be used on client production-adjacent portals.
|
|
8
|
+
|
|
9
|
+
This captures internal HubSpot surfaces discovered during migration work for
|
|
10
|
+
sequences, playbooks, sales templates, shared content permissions, and related
|
|
11
|
+
analytics. Existing public commands such as `hscli sales sequences` should stay
|
|
12
|
+
public-API first; this punch list describes the future cookie-auth/internal
|
|
13
|
+
surface needed for full-fidelity backup and migration.
|
|
14
|
+
|
|
15
|
+
Reference endpoint details and payload schemas should live in
|
|
16
|
+
`HSCLI-ENDPOINTS.md` or the migration-specific endpoint catalog.
|
|
17
|
+
|
|
18
|
+
Implemented slice:
|
|
19
|
+
|
|
20
|
+
- Browser-session fetch requests now use `credentials: "include"`.
|
|
21
|
+
- Browser-session commands already accept `--cookie`, `--cookie-file`,
|
|
22
|
+
`HSCLI_HUBSPOT_COOKIE`, `HSCLI_HUBSPOT_COOKIE_FILE`, `--csrf`, and
|
|
23
|
+
`HSCLI_HUBSPOT_CSRF`.
|
|
24
|
+
- `hubspotapi-csrf` is accepted as the modern CSRF cookie.
|
|
25
|
+
- `hscli sales-content search` wraps internal sales content search.
|
|
26
|
+
- `hscli sequences list|get|create|delete|migrate` reads, creates, deletes, and
|
|
27
|
+
migrates internal sequence payloads with destination owner/template remapping.
|
|
28
|
+
- `hscli sales-templates list|get|usage|create` reads template payloads and can
|
|
29
|
+
create a destination template from inline or file-backed HTML.
|
|
30
|
+
- `hscli playbooks list|get|questions|create|update|delete|migrate` reads and
|
|
31
|
+
migrates playbook payloads through the read/write Chirp RPC surface.
|
|
32
|
+
- Shared sales-content permission updates are available through the
|
|
33
|
+
sequence/playbook migration helpers when destination teams/users are supplied.
|
|
34
|
+
|
|
35
|
+
Still backlog:
|
|
36
|
+
|
|
37
|
+
- standalone `permissions get|set`
|
|
38
|
+
- standalone `sequences clone`
|
|
39
|
+
- standalone `sales-templates migrate`
|
|
40
|
+
- playbook/template permission verification reads
|
|
41
|
+
- doctor capability probes for these internal surfaces
|
|
42
|
+
- deeper policy gates for write/delete/permissions
|
|
43
|
+
- expanded sandbox contract tests across real portals
|
|
44
|
+
|
|
45
|
+
## 1. Cookie / CSRF Transport
|
|
46
|
+
|
|
47
|
+
Why: internal HubSpot endpoints are same-origin browser-session endpoints, not
|
|
48
|
+
private-app bearer-token endpoints.
|
|
49
|
+
|
|
50
|
+
Code area: `src/core/http.ts` or the shared HubSpot HTTP client/session layer.
|
|
51
|
+
|
|
52
|
+
Add / verify:
|
|
53
|
+
|
|
54
|
+
- auth mode: `cookie`
|
|
55
|
+
- cookie input: `--cookie`, `--cookie-file`, or `HSCLI_HUBSPOT_COOKIE`
|
|
56
|
+
- cookie jar support for Netscape-format browser exports
|
|
57
|
+
- CSRF cookie name: `hubspotapi-csrf`
|
|
58
|
+
- CSRF header name: `X-HubSpot-CSRF-hubspotapi`
|
|
59
|
+
- automatic CSRF extraction from cookie jar or cookie header
|
|
60
|
+
- automatic CSRF header injection for internal calls
|
|
61
|
+
- `credentials: "include"` for fetch options where supported
|
|
62
|
+
- trace redaction for the `hubspotapi-csrf` value
|
|
63
|
+
|
|
64
|
+
Smoke test:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
hscli sequences list --cookie-file ~/.hubspot-cookie.txt
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## 2. Top-Level `hscli sequences`
|
|
71
|
+
|
|
72
|
+
Code area: `src/commands/sequences/index.ts`.
|
|
73
|
+
|
|
74
|
+
### `hscli sequences list`
|
|
75
|
+
|
|
76
|
+
- Endpoint: `POST /api/salescontentsearch/v2/search?portalId={portalId}`
|
|
77
|
+
- Body: `{ "query": "", "limit": <limit>, "offset": <offset> }`
|
|
78
|
+
- Pagination: use `hasMore`
|
|
79
|
+
- Filtering: client-side `contentType === "SEQUENCE"`
|
|
80
|
+
- Output columns: `id`, `name`, `owner`, `folderId`, `dynamic`,
|
|
81
|
+
`lastUsedAt`, `teams`, `visibleToAll`
|
|
82
|
+
|
|
83
|
+
### `hscli sequences get <id>`
|
|
84
|
+
|
|
85
|
+
- Endpoint: `GET /api/sequences/v3/sequences/{id}?portalId={portalId}`
|
|
86
|
+
- Output: `{ sequence, userView }`
|
|
87
|
+
- Pretty print: steps, settings, dependencies
|
|
88
|
+
- Optional: `--with-stats` using sequence enrollment analytics below
|
|
89
|
+
|
|
90
|
+
### `hscli sequences create`
|
|
91
|
+
|
|
92
|
+
- Endpoint: `POST /api/sequences/v3/sequences/create?portalId={portalId}`
|
|
93
|
+
- Body wrapper: `{ "sequenceEgg": <transformed-sequence> }`
|
|
94
|
+
- Inputs: `--from <jsonfile>`, `--remap-templates <mapfile>`
|
|
95
|
+
- Strip server-set fields:
|
|
96
|
+
- `id`
|
|
97
|
+
- `sequenceId`
|
|
98
|
+
- `sequenceStepId`
|
|
99
|
+
- `createdAt`
|
|
100
|
+
- `updatedAt`
|
|
101
|
+
- `deletedAt`
|
|
102
|
+
- Apply template ID remapping before create.
|
|
103
|
+
- If `--permissions <jsonfile>` is provided, call the shared permissions
|
|
104
|
+
helper after create.
|
|
105
|
+
- Log warning: `active: "INACTIVE"` is ignored by the API.
|
|
106
|
+
|
|
107
|
+
### `hscli sequences delete <id...>`
|
|
108
|
+
|
|
109
|
+
- Endpoint: `DELETE /api/sequences/v3/sequences/batch?portalId={portalId}`
|
|
110
|
+
- Body: `{ "ids": ["..."] }`
|
|
111
|
+
- Require confirmation unless `--force`.
|
|
112
|
+
|
|
113
|
+
### `hscli sequences clone <src-id> --dest <portalId>`
|
|
114
|
+
|
|
115
|
+
- Pipeline:
|
|
116
|
+
- fetch source sequence
|
|
117
|
+
- transform payload
|
|
118
|
+
- remap owner
|
|
119
|
+
- remap templates
|
|
120
|
+
- create destination sequence
|
|
121
|
+
- set destination permissions
|
|
122
|
+
- Template mapping strategy: match by `name + subject + normalized_body`
|
|
123
|
+
across portals.
|
|
124
|
+
|
|
125
|
+
## 3. Top-Level `hscli playbooks`
|
|
126
|
+
|
|
127
|
+
Code area: `src/commands/playbooks/index.ts`.
|
|
128
|
+
|
|
129
|
+
Auth: cookie + Chirp RPC through
|
|
130
|
+
`POST /api/chirp-frontend-app/v1/gateway/...`.
|
|
131
|
+
|
|
132
|
+
### `hscli playbooks list`
|
|
133
|
+
|
|
134
|
+
- Endpoint:
|
|
135
|
+
`POST /api/chirp-frontend-app/v1/gateway/com.hubspot.playbooks.rpc.PlaybooksRpc/listPlaybooks`
|
|
136
|
+
- Body: `{}`
|
|
137
|
+
- Response path: `.data.playbooks[]`
|
|
138
|
+
- Includes inline `body` and `htmlBody`.
|
|
139
|
+
|
|
140
|
+
### `hscli playbooks get <id>`
|
|
141
|
+
|
|
142
|
+
- Option A: call `listPlaybooks` and filter by `id`
|
|
143
|
+
- Option B:
|
|
144
|
+
`POST .../com.hubspot.playbooks.rpc.PlaybooksRpc/getLatestPlaybookVersion`
|
|
145
|
+
- Body: `{ "playbookId": <id> }`
|
|
146
|
+
|
|
147
|
+
### `hscli playbooks questions <id>`
|
|
148
|
+
|
|
149
|
+
- Endpoint:
|
|
150
|
+
`POST .../com.hubspot.playbooks.rpc.PlaybookQuestionsRpc/getLatestQuestionsByPlaybook`
|
|
151
|
+
- Body: `{ "playbookId": <id> }`
|
|
152
|
+
- Output: `{ questions: [...] }`
|
|
153
|
+
|
|
154
|
+
### `hscli playbooks clone <src-id> --dest <portalId>`
|
|
155
|
+
|
|
156
|
+
- Status: read-only for now.
|
|
157
|
+
- Playbook write endpoint is not validated.
|
|
158
|
+
- Document as a known migration gap until sandbox write behavior is proven.
|
|
159
|
+
|
|
160
|
+
## 4. Shared `hscli permissions`
|
|
161
|
+
|
|
162
|
+
Code area: `src/commands/permissions.ts`.
|
|
163
|
+
|
|
164
|
+
Used by sequences, sales templates, playbooks, snippets, and documents.
|
|
165
|
+
|
|
166
|
+
### `hscli permissions set <objectType> <id1,id2,...>`
|
|
167
|
+
|
|
168
|
+
Flags:
|
|
169
|
+
|
|
170
|
+
- `--teams <ids>`
|
|
171
|
+
- `--users <ids>`
|
|
172
|
+
- `--visible-to-all`
|
|
173
|
+
- `--private`
|
|
174
|
+
|
|
175
|
+
Endpoint:
|
|
176
|
+
|
|
177
|
+
```text
|
|
178
|
+
PUT /api/contentpermissions/v1/permissions?portalId={portalId}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Body:
|
|
182
|
+
|
|
183
|
+
```json
|
|
184
|
+
{
|
|
185
|
+
"objectType": "SEQUENCE",
|
|
186
|
+
"objectIds": ["123"],
|
|
187
|
+
"permissions": {
|
|
188
|
+
"TEAM": [],
|
|
189
|
+
"USER": []
|
|
190
|
+
},
|
|
191
|
+
"visibleToAll": false,
|
|
192
|
+
"private": true
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Object type enum:
|
|
197
|
+
|
|
198
|
+
- `SEQUENCE`
|
|
199
|
+
- `TEMPLATE`
|
|
200
|
+
- `PLAYBOOK`
|
|
201
|
+
- `DOCUMENT`
|
|
202
|
+
- `SNIPPET`
|
|
203
|
+
|
|
204
|
+
Behavior:
|
|
205
|
+
|
|
206
|
+
- Replace semantics.
|
|
207
|
+
- Fetch current state first.
|
|
208
|
+
- Show diff before overwrite.
|
|
209
|
+
- Gate writes through policy and `--force`.
|
|
210
|
+
|
|
211
|
+
### `hscli permissions get <objectType> <id>`
|
|
212
|
+
|
|
213
|
+
- No standalone GET endpoint is confirmed.
|
|
214
|
+
- Use `salescontentsearch` and extract:
|
|
215
|
+
- `permissionedTeamIds`
|
|
216
|
+
- `permissionedUserIds`
|
|
217
|
+
- `visibleToAll`
|
|
218
|
+
- `private`
|
|
219
|
+
|
|
220
|
+
## 5. Top-Level `hscli sales-templates`
|
|
221
|
+
|
|
222
|
+
Code area: `src/commands/sales-templates/index.ts`.
|
|
223
|
+
|
|
224
|
+
### `hscli sales-templates list`
|
|
225
|
+
|
|
226
|
+
- Endpoint: `GET /api/templates/v1/templates?portalId={portalId}`
|
|
227
|
+
- Response: flat array
|
|
228
|
+
- Pagination: not required for typical portals unless tests prove otherwise
|
|
229
|
+
|
|
230
|
+
### `hscli sales-templates get <id>`
|
|
231
|
+
|
|
232
|
+
- Endpoint: `GET /api/sales-templates/v2/templates/{id}?portalId={portalId}`
|
|
233
|
+
- Output fields:
|
|
234
|
+
- `id`
|
|
235
|
+
- `name`
|
|
236
|
+
- `subject`
|
|
237
|
+
- `body`
|
|
238
|
+
- `htmlBody`
|
|
239
|
+
- `userId`
|
|
240
|
+
- `sharedUsers`
|
|
241
|
+
- `active`
|
|
242
|
+
- `folderId`
|
|
243
|
+
|
|
244
|
+
### `hscli sales-templates usage`
|
|
245
|
+
|
|
246
|
+
- Endpoint:
|
|
247
|
+
`GET /api/sales-templates/v2/templates/usage?portalId={portalId}`
|
|
248
|
+
- Output:
|
|
249
|
+
- `limit`
|
|
250
|
+
- `userLimit`
|
|
251
|
+
- `currentUsage`
|
|
252
|
+
|
|
253
|
+
### `hscli sales-templates create`
|
|
254
|
+
|
|
255
|
+
- Endpoint: `POST /api/sales-templates/v2/templates?portalId={portalId}`
|
|
256
|
+
- Minimum body:
|
|
257
|
+
- `name`
|
|
258
|
+
- `subject`
|
|
259
|
+
- `body`
|
|
260
|
+
- Input: `--from <jsonfile>`
|
|
261
|
+
- Validate optional fields after sandbox contract tests.
|
|
262
|
+
|
|
263
|
+
## 6. Top-Level `hscli sales-content search`
|
|
264
|
+
|
|
265
|
+
Code area: `src/commands/sales-content/index.ts`.
|
|
266
|
+
|
|
267
|
+
Command:
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
hscli sales-content search \
|
|
271
|
+
--type SEQUENCE \
|
|
272
|
+
--owner <ownerId> \
|
|
273
|
+
--query "renewal"
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Endpoint:
|
|
277
|
+
|
|
278
|
+
```text
|
|
279
|
+
POST /api/salescontentsearch/v2/search?portalId={portalId}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Body:
|
|
283
|
+
|
|
284
|
+
```json
|
|
285
|
+
{
|
|
286
|
+
"query": "",
|
|
287
|
+
"limit": 100,
|
|
288
|
+
"offset": 0
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Behavior:
|
|
293
|
+
|
|
294
|
+
- Paginate with `hasMore`.
|
|
295
|
+
- Filter `contentType` client-side because the API `filters[]` shape was
|
|
296
|
+
inconsistent in tests.
|
|
297
|
+
- Output: `type`, `id`, `name`, `owner`, `lastUsedAt`, `teams`,
|
|
298
|
+
`visibleToAll`.
|
|
299
|
+
|
|
300
|
+
## 7. Sequence Enrollment Analytics
|
|
301
|
+
|
|
302
|
+
Used by `sequences list --with-stats` and `sequences get --with-stats`.
|
|
303
|
+
|
|
304
|
+
Object type: `0-68` (`SEQUENCE_ENROLLMENT`).
|
|
305
|
+
|
|
306
|
+
Total count endpoint:
|
|
307
|
+
|
|
308
|
+
```text
|
|
309
|
+
POST /api/crm-search/search?portalId={portalId}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Body:
|
|
313
|
+
|
|
314
|
+
```json
|
|
315
|
+
{
|
|
316
|
+
"objectTypeId": "0-68",
|
|
317
|
+
"count": 1,
|
|
318
|
+
"filterGroups": [
|
|
319
|
+
{
|
|
320
|
+
"filters": [
|
|
321
|
+
{
|
|
322
|
+
"property": "hs_sequence_id",
|
|
323
|
+
"value": "<seqId>",
|
|
324
|
+
"operator": "EQ"
|
|
325
|
+
}
|
|
326
|
+
]
|
|
327
|
+
}
|
|
328
|
+
],
|
|
329
|
+
"requestOptions": {
|
|
330
|
+
"includeAllValues": false
|
|
331
|
+
},
|
|
332
|
+
"sorts": []
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
Breakdown endpoint:
|
|
337
|
+
|
|
338
|
+
```text
|
|
339
|
+
POST /api/crm-search/report?portalId={portalId}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Aggregation:
|
|
343
|
+
|
|
344
|
+
```json
|
|
345
|
+
{
|
|
346
|
+
"aggregations": [
|
|
347
|
+
{
|
|
348
|
+
"name": "enrollment_status",
|
|
349
|
+
"type": "TERMS",
|
|
350
|
+
"size": 20,
|
|
351
|
+
"property": "hs_enrollment_status"
|
|
352
|
+
}
|
|
353
|
+
]
|
|
354
|
+
}
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
Relevant properties:
|
|
358
|
+
|
|
359
|
+
- `hs_sequence_id`
|
|
360
|
+
- `hs_enrolled_at`
|
|
361
|
+
- `hs_ended_at`
|
|
362
|
+
- `hs_enrollment_status`
|
|
363
|
+
- `hs_email_sent_count`
|
|
364
|
+
- `hs_email_open_count`
|
|
365
|
+
- `hs_email_replied_count`
|
|
366
|
+
- `hs_email_bounced_count`
|
|
367
|
+
- `hs_finished_count`
|
|
368
|
+
- `hs_unenrolled_count`
|
|
369
|
+
- `hs_error_count`
|
|
370
|
+
- `hs_ended_no_response_count`
|
|
371
|
+
- `hs_enrolled_by`
|
|
372
|
+
- `hs_recipient_email`
|
|
373
|
+
- `hs_first_name`
|
|
374
|
+
- `hs_last_name`
|
|
375
|
+
|
|
376
|
+
## 8. Migration Adapter: `hscli migrate sequences`
|
|
377
|
+
|
|
378
|
+
Code area: `src/commands/migrate/sequences.ts`.
|
|
379
|
+
|
|
380
|
+
Command:
|
|
381
|
+
|
|
382
|
+
```bash
|
|
383
|
+
hscli migrate sequences \
|
|
384
|
+
--src-portal <source> \
|
|
385
|
+
--dst-portal <target> \
|
|
386
|
+
--ids <id1,id2> \
|
|
387
|
+
--owner-map owners.json \
|
|
388
|
+
--team-map teams.json \
|
|
389
|
+
--dry-run
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
Pipeline:
|
|
393
|
+
|
|
394
|
+
- Discover destination templates with `sales-templates list`.
|
|
395
|
+
- Discover source sequences with `sales-content search --type SEQUENCE`.
|
|
396
|
+
- Fetch each source sequence with `sequences get`.
|
|
397
|
+
- Remap template IDs by `name + subject + normalized_body` similarity.
|
|
398
|
+
- Require similarity ratio `>= 0.95`.
|
|
399
|
+
- Fail if any template is unmappable.
|
|
400
|
+
- Remap owners from `--owner-map`.
|
|
401
|
+
- Default missing owner to running user only when explicitly allowed by policy.
|
|
402
|
+
- Strip server-set fields from sequence, steps, and nested patterns:
|
|
403
|
+
- `id`
|
|
404
|
+
- `sequenceId`
|
|
405
|
+
- `sequenceStepId`
|
|
406
|
+
- `createdAt`
|
|
407
|
+
- `updatedAt`
|
|
408
|
+
- `deletedAt`
|
|
409
|
+
- Preserve dependency fields:
|
|
410
|
+
- `requiredByStepOrder`
|
|
411
|
+
- `reliesOnStepOrder`
|
|
412
|
+
- `branchNumber`
|
|
413
|
+
- Create destination sequence.
|
|
414
|
+
- Set destination permissions with explicit team/user mapping.
|
|
415
|
+
- Never default to `visibleToAll`.
|
|
416
|
+
- Output CSV: `srcId,dstId,status,notes`.
|
|
417
|
+
|
|
418
|
+
Known gotchas:
|
|
419
|
+
|
|
420
|
+
- `active: "INACTIVE"` is overridden by the API to active.
|
|
421
|
+
- New sequences are safe only while they have no enrollments.
|
|
422
|
+
- Permissions in `sequenceEgg` are ignored.
|
|
423
|
+
- Permissions must be set with separate `PUT /api/contentpermissions/v1/permissions`.
|
|
424
|
+
- Dependencies in `sequenceEgg` are respected.
|
|
425
|
+
- The API appends an automatic `FINISH_ENROLLMENT` step.
|
|
426
|
+
- Expected step count: `dst.steps.length = src.steps.length + 1`.
|
|
427
|
+
|
|
428
|
+
## 9. Existing Command Updates
|
|
429
|
+
|
|
430
|
+
### `hscli doctor capabilities`
|
|
431
|
+
|
|
432
|
+
Add probes:
|
|
433
|
+
|
|
434
|
+
- `GET /api/sequences/v3/sequences/{id}`
|
|
435
|
+
- `POST /api/sequences/v3/sequences/create`
|
|
436
|
+
- `PUT /api/contentpermissions/v1/permissions`
|
|
437
|
+
- `POST /api/chirp-frontend-app/v1/gateway/com.hubspot.playbooks.rpc.PlaybooksRpc/getPlaybookCount`
|
|
438
|
+
- `GET /api/sales-templates/v2/templates/usage`
|
|
439
|
+
|
|
440
|
+
Each probe should report:
|
|
441
|
+
|
|
442
|
+
- status
|
|
443
|
+
- response time
|
|
444
|
+
- user permission scopes from `GET /api/login-verify/hub-user-info`
|
|
445
|
+
|
|
446
|
+
### `hscli trace`
|
|
447
|
+
|
|
448
|
+
Add redaction for:
|
|
449
|
+
|
|
450
|
+
- `hubspotapi-csrf` cookie value
|
|
451
|
+
- `X-HubSpot-CSRF-hubspotapi` header value
|
|
452
|
+
- browser cookie values in cookie-mode requests
|
|
453
|
+
|
|
454
|
+
### `hscli policy`
|
|
455
|
+
|
|
456
|
+
Add capabilities:
|
|
457
|
+
|
|
458
|
+
- `sequences.write`
|
|
459
|
+
- `sequences.delete`
|
|
460
|
+
- `permissions.write`
|
|
461
|
+
- `playbooks.write`
|
|
462
|
+
|
|
463
|
+
Policy defaults:
|
|
464
|
+
|
|
465
|
+
- `sequences.write`: require `--force`, dry-run first, optional time window
|
|
466
|
+
- `sequences.delete`: require `--force` and change ticket
|
|
467
|
+
- `permissions.write`: require `--force` and target-team allowlist
|
|
468
|
+
- `playbooks.write`: disabled by default because write endpoint is not proven
|
|
469
|
+
|
|
470
|
+
## 10. Contract Tests
|
|
471
|
+
|
|
472
|
+
Gate with `HSCLI_ENABLE_SANDBOX_CONTRACT=1`.
|
|
473
|
+
|
|
474
|
+
Add:
|
|
475
|
+
|
|
476
|
+
- create test sequence
|
|
477
|
+
- fetch test sequence
|
|
478
|
+
- diff source/create output
|
|
479
|
+
- delete test sequence
|
|
480
|
+
- set permissions
|
|
481
|
+
- search and verify permissions
|
|
482
|
+
- reset permissions
|
|
483
|
+
- run full source-to-target sequence migration between two sandbox portals
|
|
484
|
+
|
|
485
|
+
## Endpoint Catalog
|
|
486
|
+
|
|
487
|
+
| Verb | Path | Command | Auth |
|
|
488
|
+
|---|---|---|---|
|
|
489
|
+
| GET | `/api/sequences/v3/sequences/{id}` | `sequences get` | cookie |
|
|
490
|
+
| POST | `/api/sequences/v3/sequences/create` | `sequences create` | cookie |
|
|
491
|
+
| DELETE | `/api/sequences/v3/sequences/batch` | `sequences delete` | cookie |
|
|
492
|
+
| POST | `/api/salescontentsearch/v2/search` | `sales-content search`, `sequences list` | cookie |
|
|
493
|
+
| POST | `/api/crm-search/search` with `objectTypeId=0-68` | `sequences get --with-stats` | cookie |
|
|
494
|
+
| POST | `/api/crm-search/report` with `objectTypeId=0-68` | `sequences get --with-stats` | cookie |
|
|
495
|
+
| GET | `/api/sales-templates/v2/templates/{id}` | `sales-templates get` | cookie |
|
|
496
|
+
| GET | `/api/sales-templates/v2/templates/usage` | `sales-templates usage` | cookie |
|
|
497
|
+
| POST | `/api/sales-templates/v2/templates` | `sales-templates create` | cookie |
|
|
498
|
+
| GET | `/api/templates/v1/templates` | `sales-templates list` | cookie |
|
|
499
|
+
| POST | `/api/chirp-frontend-app/v1/gateway/com.hubspot.playbooks.rpc.PlaybooksRpc/listPlaybooks` | `playbooks list` | cookie + chirp |
|
|
500
|
+
| POST | `/api/chirp-frontend-app/v1/gateway/com.hubspot.playbooks.rpc.PlaybooksRpc/getPlaybookCount` | `playbooks usage` | cookie + chirp |
|
|
501
|
+
| POST | `/api/chirp-frontend-app/v1/gateway/com.hubspot.playbooks.rpc.PlaybookQuestionsRpc/getLatestQuestionsByPlaybook` | `playbooks questions` | cookie + chirp |
|
|
502
|
+
| PUT | `/api/contentpermissions/v1/permissions` | `permissions set` | cookie |
|
|
503
|
+
| GET | `/api/app-users/v1/teams` | `teams list` | cookie |
|
|
504
|
+
| GET | `/api/login-verify/hub-user-info` | internal doctor whoami | cookie |
|
|
@@ -170,6 +170,55 @@ Now every tool call the agent makes is filtered through the same rules.
|
|
|
170
170
|
- Change tickets travel with the request and are written to telemetry.
|
|
171
171
|
- Off-hours writes are rejected — no more 2am surprises.
|
|
172
172
|
|
|
173
|
+
## Seal an approved action
|
|
174
|
+
|
|
175
|
+
Policies decide whether a request is allowed. Action contracts additionally
|
|
176
|
+
prove exactly which hscli arguments were reviewed. Create a draft without
|
|
177
|
+
credentials or shell commands:
|
|
178
|
+
|
|
179
|
+
```json
|
|
180
|
+
{
|
|
181
|
+
"profile": "sandbox",
|
|
182
|
+
"portalId": "123456",
|
|
183
|
+
"createdAt": "2026-07-09T09:00:00.000Z",
|
|
184
|
+
"expiresAt": "2026-07-09T10:00:00.000Z",
|
|
185
|
+
"changeTicket": "CHG-12345",
|
|
186
|
+
"operation": {
|
|
187
|
+
"summary": "Update one approved contact property",
|
|
188
|
+
"commands": [
|
|
189
|
+
{
|
|
190
|
+
"argv": ["crm", "contacts", "update", "101", "--data", "{\"properties\":{\"lifecyclestage\":\"lead\"}}"],
|
|
191
|
+
"verifyArgv": ["crm", "contacts", "get", "101", "--properties", "lifecyclestage"]
|
|
192
|
+
}
|
|
193
|
+
]
|
|
194
|
+
},
|
|
195
|
+
"limits": { "maxCommands": 1, "maxRecords": 1 }
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Seal and review it:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
hscli --json agent contract create --input ./draft.json | jq '.data' > ./contract.json
|
|
203
|
+
hscli --json --profile sandbox --change-ticket CHG-12345 \
|
|
204
|
+
agent contract verify ./contract.json
|
|
205
|
+
hscli --json --profile sandbox --change-ticket CHG-12345 \
|
|
206
|
+
agent contract apply ./contract.json
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
The last command is still plan-only. Execution requires both approvals:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
hscli --json --profile sandbox --policy-file ./policy.json \
|
|
213
|
+
--change-ticket CHG-12345 --force \
|
|
214
|
+
agent contract apply ./contract.json --execute
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
The runner checks the SHA-256 digest, deterministic contract ID, profile,
|
|
218
|
+
known portal ID, expiry, and ticket before starting. It invokes only hscli
|
|
219
|
+
argument arrays with `shell:false`; `agent`, `auth`, `internal`, `mcp`, and
|
|
220
|
+
global routing flags are forbidden inside contracts.
|
|
221
|
+
|
|
173
222
|
## Going further
|
|
174
223
|
|
|
175
224
|
- Pair this with `hscli trace start` (see the [trace tutorial](trace-replay-repro.md)) to record every request + matched rule to a JSONL file.
|
package/docs/WHY_HOW_WHAT.md
CHANGED
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
> See also: [ARCHITECTURE.md](ARCHITECTURE.md) · [SAFETY_MODEL.md](SAFETY_MODEL.md) · [ROADMAP_PHASE1_TO_3.md](ROADMAP_PHASE1_TO_3.md)
|
|
4
4
|
|
|
5
5
|
## WHY this CLI exists
|
|
6
|
-
`hscli` exists to give operators a safe, automatable, production-grade command interface to HubSpot
|
|
7
|
-
- **Speed:** repetitive CRM
|
|
8
|
-
- **Safety:** write controls prevent accidental destructive mutations.
|
|
9
|
-
- **Reliability:** consistent output
|
|
6
|
+
`hscli` exists to give operators and agents a safe, automatable, production-grade command interface to HubSpot without needing to write one-off scripts each time. HubSpot is moving toward an agent-ready platform where APIs, MCP, CLI, and connectors let agents operate the CRM; `hscli` focuses on the operator layer around that movement:
|
|
7
|
+
- **Speed:** repetitive CRM, migration, backup, and reporting work becomes scriptable and repeatable.
|
|
8
|
+
- **Safety:** write controls, profile boundaries, policy files, and change tickets prevent accidental destructive mutations.
|
|
9
|
+
- **Reliability:** consistent output, retry behavior, rate-limit handling, and trace/audit evidence reduce brittle ad-hoc scripts.
|
|
10
|
+
- **Context:** deterministic portal context, parity checks, and multi-portal plans give agents useful structure before they summarize or act.
|
|
10
11
|
|
|
11
12
|
## WHAT has been built (and what remains)
|
|
12
13
|
|
|
@@ -38,6 +39,11 @@
|
|
|
38
39
|
- secret redaction in output/error serialization
|
|
39
40
|
- profile environment isolation via `HSCLI_HOME`
|
|
40
41
|
- request scope guard, timeout, retries, and correlation id
|
|
42
|
+
- Agent/operator workflows:
|
|
43
|
+
- deterministic `agent plan` runbooks
|
|
44
|
+
- read-only `context build` portal profiles
|
|
45
|
+
- `doctor parity` public/internal/hybrid/UI-only coverage map
|
|
46
|
+
- `portals list|plan` for explicit multi-portal management
|
|
41
47
|
- Auth model expansion:
|
|
42
48
|
- profile listing/inspection
|
|
43
49
|
- OAuth authorize URL + code exchange
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@revfleet/hscli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.9.0",
|
|
4
|
+
"description": "HubSpot operations and migration control plane for humans and agents, with deterministic runbooks, policy guardrails, and auditable evidence.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"hscli": "dist/cli.js"
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
"test:contract": "HSCLI_ENABLE_SANDBOX_CONTRACT=1 vitest run tests/contract.sandbox.test.ts",
|
|
16
16
|
"lint": "eslint src/ tests/",
|
|
17
17
|
"lint:fix": "eslint src/ tests/ --fix",
|
|
18
|
+
"docs:mcp": "npm run build && node scripts/generate-mcp-catalog.mjs",
|
|
19
|
+
"docs:mcp:check": "npm run build && node scripts/generate-mcp-catalog.mjs --check",
|
|
18
20
|
"release:checksums": "node scripts/release-checksums.mjs",
|
|
19
21
|
"audit": "npm audit --audit-level=high",
|
|
20
22
|
"release:verify": "npm run typecheck && npm run lint && npm test && npm run audit && npm run build && npm run release:checksums && shasum -a 256 -c release/checksums.sha256",
|