hubspot-cms-sync 0.1.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/LICENSE +21 -0
- package/README.md +52 -0
- package/bin/hubspot-cms-sync.mjs +115 -0
- package/docs/CONFIGURATION.md +83 -0
- package/docs/GITHUB_ACTIONS.md +70 -0
- package/docs/MIGRATION_PLAN.md +361 -0
- package/docs/PLAN_REVIEW.md +42 -0
- package/docs/SKILL_DISTRIBUTION.md +79 -0
- package/examples/github-actions/ci.yml +56 -0
- package/examples/github-actions/preview.yml +71 -0
- package/examples/github-actions/publish.yml +82 -0
- package/examples/hubspot-cms-sync.config.mjs +45 -0
- package/examples/site.manifest.json +19 -0
- package/package.json +41 -0
- package/skill/SKILL.md +54 -0
- package/skill/references/commands.md +54 -0
- package/skill/references/config.md +25 -0
- package/skill/references/failures.md +58 -0
- package/skill/references/github-actions.md +56 -0
- package/skill/references/screenshots-and-fidelity.md +33 -0
- package/src/adapters/assets.mjs +576 -0
- package/src/adapters/blog.mjs +921 -0
- package/src/adapters/content.mjs +213 -0
- package/src/adapters/forms.mjs +569 -0
- package/src/adapters/pages.mjs +463 -0
- package/src/adapters/theme.mjs +503 -0
- package/src/config.mjs +113 -0
- package/src/corpus-scan.mjs +248 -0
- package/src/cta-inventory.mjs +352 -0
- package/src/index.mjs +3 -0
- package/src/lib/canonical.mjs +234 -0
- package/src/lib/hub.mjs +197 -0
- package/src/lib/orchestrate.mjs +141 -0
- package/src/lib/refs.mjs +398 -0
- package/src/lib/sync-state.mjs +86 -0
- package/src/manifest.mjs +353 -0
- package/src/preflight.mjs +385 -0
- package/src/pull.mjs +99 -0
- package/src/push.mjs +354 -0
- package/src/republish.mjs +102 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Plan Review Notes
|
|
2
|
+
|
|
3
|
+
This captures the read-only Claude review of the initial extraction plan.
|
|
4
|
+
|
|
5
|
+
## Critical Findings
|
|
6
|
+
|
|
7
|
+
1. **Move the tests with the engine.** The website repo unit/integration tests
|
|
8
|
+
import `sync/**` directly. If the website deletes local sync code before the
|
|
9
|
+
tests move or repoint to package exports, `npm run test:unit` will fail.
|
|
10
|
+
|
|
11
|
+
2. **Move the corpus scanner.** `hcms corpus` depends on
|
|
12
|
+
`scripts/corpus-scan.mjs`, which lives outside `sync/` and was missing from
|
|
13
|
+
the initial inventory.
|
|
14
|
+
|
|
15
|
+
3. **Make the read-only guard config-driven.** The current single hardcoded
|
|
16
|
+
`READ_ONLY_PORTAL = '529456'` must become `config.readOnlyPortalIds` while
|
|
17
|
+
preserving fail-closed behavior.
|
|
18
|
+
|
|
19
|
+
4. **Thread config explicitly.** Several modules resolve paths from `__dirname`;
|
|
20
|
+
that will point into the npm package once installed. Build a resolved config
|
|
21
|
+
object once in the CLI and pass it into commands/libs/adapters instead of using
|
|
22
|
+
package-relative roots or global mutable config.
|
|
23
|
+
|
|
24
|
+
5. **Scrub publish artifacts.** Docs/examples currently mention private portal
|
|
25
|
+
IDs. Before npm publication, scrub all shipped docs/examples or exclude them
|
|
26
|
+
from `package.json#files`.
|
|
27
|
+
|
|
28
|
+
## Plan Updates Made
|
|
29
|
+
|
|
30
|
+
- Added `scripts/corpus-scan.mjs`, `test/unit/**`, and `test/integration/**` to
|
|
31
|
+
the migration inventory.
|
|
32
|
+
- Added explicit root/config threading requirements and named the affected
|
|
33
|
+
modules.
|
|
34
|
+
- Added acceptance gates for config loader behavior, known portal IDs, and
|
|
35
|
+
read-only portal arrays.
|
|
36
|
+
- Added v1 limitations for CTA/menu producers, legacy asset hosts, and global
|
|
37
|
+
transaction limits.
|
|
38
|
+
- Aligned the example config with the documented schema.
|
|
39
|
+
- Added `prepublishOnly` placeholder guard in `package.json`.
|
|
40
|
+
- Updated the skill plan to keep the deterministic engine in npm and use the
|
|
41
|
+
skill only as an agent workflow wrapper.
|
|
42
|
+
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Skill Distribution Plan
|
|
2
|
+
|
|
3
|
+
The Codex skill should be a companion to the npm CLI, not a replacement for it.
|
|
4
|
+
|
|
5
|
+
## Skill Purpose
|
|
6
|
+
|
|
7
|
+
Help an agent operate `hubspot-cms-sync` correctly inside a project:
|
|
8
|
+
|
|
9
|
+
- inspect config and manifest
|
|
10
|
+
- run preflight and corpus checks
|
|
11
|
+
- perform pull/push/republish flows
|
|
12
|
+
- interpret common failures
|
|
13
|
+
- manage preview/deployment PR gates
|
|
14
|
+
- capture and compare screenshots through the consuming repo's configured tests
|
|
15
|
+
|
|
16
|
+
The npm CLI owns deterministic behavior. The skill owns agent procedure,
|
|
17
|
+
interpretation, and safe sequencing.
|
|
18
|
+
|
|
19
|
+
## Proposed Skill Layout
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
hubspot-cms-sync/
|
|
23
|
+
├── SKILL.md
|
|
24
|
+
└── references/
|
|
25
|
+
├── commands.md
|
|
26
|
+
├── config.md
|
|
27
|
+
├── failures.md
|
|
28
|
+
├── github-actions.md
|
|
29
|
+
└── screenshots-and-fidelity.md
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Do not bundle the full sync implementation into the skill. The deterministic
|
|
33
|
+
engine lives in npm.
|
|
34
|
+
|
|
35
|
+
`SKILL.md` with YAML frontmatter is the portable core. Agent-specific metadata
|
|
36
|
+
files such as `agents/openai.yaml` can be generated later for marketplaces that
|
|
37
|
+
need them, but they should not be the primary source of truth.
|
|
38
|
+
|
|
39
|
+
## SKILL.md Scope
|
|
40
|
+
|
|
41
|
+
The skill body should stay short:
|
|
42
|
+
|
|
43
|
+
1. Confirm `hubspot-cms-sync` / `hcms` is installed.
|
|
44
|
+
2. Read `hubspot-cms-sync.config.mjs`.
|
|
45
|
+
3. Run `hcms doctor` before risky operations.
|
|
46
|
+
4. For pull: run pull, corpus, git diff, and summarize.
|
|
47
|
+
5. For push: run corpus, preflight, plan, push, republish if needed, verify.
|
|
48
|
+
6. For CI failures: inspect logs, classify failure, rerun the minimum command.
|
|
49
|
+
7. Never bypass read-only portal guards.
|
|
50
|
+
8. Surface v1 engine limits clearly: surviving `@cta:*` or `@menu:*` refs fail
|
|
51
|
+
closed until producer adapters exist; global HubSpot writes are rerun-to-
|
|
52
|
+
convergence, not transactional rollback.
|
|
53
|
+
|
|
54
|
+
## References
|
|
55
|
+
|
|
56
|
+
- `commands.md`: command matrix and expected outputs.
|
|
57
|
+
- `config.md`: config schema and examples.
|
|
58
|
+
- `failures.md`: HubSpot API failures and remediation text.
|
|
59
|
+
- `github-actions.md`: environment secrets, preview, deploy, PR gates.
|
|
60
|
+
- `screenshots-and-fidelity.md`: Playwright screenshot workflows and baseline
|
|
61
|
+
update rules.
|
|
62
|
+
|
|
63
|
+
## Example User Prompts
|
|
64
|
+
|
|
65
|
+
- "Pull HubSpot prod into git and summarize the diff."
|
|
66
|
+
- "Deploy this PR to the HubSpot preview sandbox and run fidelity checks."
|
|
67
|
+
- "Why did `hcms preflight dev` fail?"
|
|
68
|
+
- "Republish all live pages after this template change."
|
|
69
|
+
- "Set up HubSpot CMS sync in this repo."
|
|
70
|
+
|
|
71
|
+
## Skill Guardrails
|
|
72
|
+
|
|
73
|
+
- The skill must not tell the agent to edit `.sync-state` manually.
|
|
74
|
+
- The skill must not suggest pushing to a read-only portal.
|
|
75
|
+
- The skill should prefer `hcms push --dry-run` and `hcms preflight` before any write.
|
|
76
|
+
- The skill should report verification gaps clearly if credentials or a live
|
|
77
|
+
preview URL are unavailable.
|
|
78
|
+
- The skill should source common failure explanations from CLI output and
|
|
79
|
+
package references, not invent parallel remediation text.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: HubSpot CMS Sync CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches: [main]
|
|
6
|
+
push:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: hcms-ci-${{ github.workflow }}-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
env:
|
|
17
|
+
HUBSPOT_KEY_DIR: ${{ runner.temp }}/hubspot-keys
|
|
18
|
+
HCMS_TARGET: dev
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
hcms-ci:
|
|
22
|
+
name: Validate HubSpot CMS sync inputs
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
|
|
25
|
+
steps:
|
|
26
|
+
- name: Check out repository
|
|
27
|
+
uses: actions/checkout@v4
|
|
28
|
+
|
|
29
|
+
- name: Set up Node.js
|
|
30
|
+
uses: actions/setup-node@v4
|
|
31
|
+
with:
|
|
32
|
+
node-version: 22
|
|
33
|
+
cache: npm
|
|
34
|
+
|
|
35
|
+
- name: Install project dependencies
|
|
36
|
+
run: npm ci
|
|
37
|
+
|
|
38
|
+
- name: Hydrate read-only HubSpot credentials
|
|
39
|
+
env:
|
|
40
|
+
DEV_TOKEN: ${{ secrets.HUBSPOT_DEV_PRIVATE_APP_TOKEN }}
|
|
41
|
+
run: |
|
|
42
|
+
mkdir -p "$HUBSPOT_KEY_DIR"
|
|
43
|
+
token_path="$HUBSPOT_KEY_DIR/dev.private-app-token"
|
|
44
|
+
printf '%s' "$DEV_TOKEN" > "$token_path"
|
|
45
|
+
chmod 600 "$token_path"
|
|
46
|
+
|
|
47
|
+
- name: Run sync doctor
|
|
48
|
+
run: npx --yes hubspot-cms-sync@latest doctor --root .
|
|
49
|
+
|
|
50
|
+
- name: Validate local corpus
|
|
51
|
+
run: npx --yes hubspot-cms-sync@latest corpus --root .
|
|
52
|
+
|
|
53
|
+
- name: Run read-only preflight
|
|
54
|
+
run: |
|
|
55
|
+
npx --yes hubspot-cms-sync@latest preflight \
|
|
56
|
+
"$HCMS_TARGET" --root . --read-only
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
name: HubSpot CMS Sync Preview
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [opened, synchronize, reopened, ready_for_review]
|
|
6
|
+
branches: [main]
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
pull-requests: write
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: hcms-preview-pr-${{ github.event.pull_request.number }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
env:
|
|
17
|
+
HUBSPOT_KEY_DIR: ${{ runner.temp }}/hubspot-keys
|
|
18
|
+
HCMS_TARGET: preview
|
|
19
|
+
SITE_BASE_URL: ${{ secrets.PREVIEW_SITE_BASE_URL }}
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
preview:
|
|
23
|
+
name: Deploy PR preview
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
if: ${{ !github.event.pull_request.draft }}
|
|
26
|
+
|
|
27
|
+
steps:
|
|
28
|
+
- name: Check out repository
|
|
29
|
+
uses: actions/checkout@v4
|
|
30
|
+
|
|
31
|
+
- name: Set up Node.js
|
|
32
|
+
uses: actions/setup-node@v4
|
|
33
|
+
with:
|
|
34
|
+
node-version: 22
|
|
35
|
+
cache: npm
|
|
36
|
+
|
|
37
|
+
- name: Install project dependencies
|
|
38
|
+
run: npm ci
|
|
39
|
+
|
|
40
|
+
- name: Hydrate preview HubSpot credentials
|
|
41
|
+
env:
|
|
42
|
+
PREVIEW_TOKEN: ${{ secrets.HUBSPOT_PREVIEW_PRIVATE_APP_TOKEN }}
|
|
43
|
+
run: |
|
|
44
|
+
mkdir -p "$HUBSPOT_KEY_DIR"
|
|
45
|
+
token_path="$HUBSPOT_KEY_DIR/preview.private-app-token"
|
|
46
|
+
printf '%s' "$PREVIEW_TOKEN" > "$token_path"
|
|
47
|
+
chmod 600 "$token_path"
|
|
48
|
+
|
|
49
|
+
- name: Validate preview deployment plan
|
|
50
|
+
run: |
|
|
51
|
+
npx --yes hubspot-cms-sync@latest doctor --root .
|
|
52
|
+
npx --yes hubspot-cms-sync@latest corpus --root .
|
|
53
|
+
npx --yes hubspot-cms-sync@latest preflight "$HCMS_TARGET" --root .
|
|
54
|
+
npx --yes hubspot-cms-sync@latest plan \
|
|
55
|
+
"$HCMS_TARGET" --root . --out .hcms/preview-plan.md
|
|
56
|
+
|
|
57
|
+
- name: Push preview content
|
|
58
|
+
run: |
|
|
59
|
+
npx --yes hubspot-cms-sync@latest push \
|
|
60
|
+
"$HCMS_TARGET" --root . --publish
|
|
61
|
+
|
|
62
|
+
- name: Verify preview
|
|
63
|
+
run: npx --yes hubspot-cms-sync@latest verify "$HCMS_TARGET" --root .
|
|
64
|
+
|
|
65
|
+
- name: Upload preview plan
|
|
66
|
+
if: ${{ always() }}
|
|
67
|
+
uses: actions/upload-artifact@v4
|
|
68
|
+
with:
|
|
69
|
+
name: hcms-preview-plan
|
|
70
|
+
path: .hcms/preview-plan.md
|
|
71
|
+
if-no-files-found: ignore
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
name: HubSpot CMS Sync Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
target:
|
|
7
|
+
description: HubSpot sync target from the consuming repo config
|
|
8
|
+
required: true
|
|
9
|
+
default: prod
|
|
10
|
+
type: choice
|
|
11
|
+
options:
|
|
12
|
+
- prod
|
|
13
|
+
- staging
|
|
14
|
+
dry_run:
|
|
15
|
+
description: Build and validate the plan without writing to HubSpot
|
|
16
|
+
required: true
|
|
17
|
+
default: true
|
|
18
|
+
type: boolean
|
|
19
|
+
|
|
20
|
+
permissions:
|
|
21
|
+
contents: read
|
|
22
|
+
deployments: write
|
|
23
|
+
|
|
24
|
+
concurrency:
|
|
25
|
+
group: hcms-publish-${{ inputs.target }}
|
|
26
|
+
cancel-in-progress: false
|
|
27
|
+
|
|
28
|
+
env:
|
|
29
|
+
HUBSPOT_KEY_DIR: ${{ runner.temp }}/hubspot-keys
|
|
30
|
+
HCMS_TARGET: ${{ inputs.target }}
|
|
31
|
+
SITE_BASE_URL: ${{ secrets.SITE_BASE_URL }}
|
|
32
|
+
|
|
33
|
+
jobs:
|
|
34
|
+
publish:
|
|
35
|
+
name: Publish HubSpot CMS target
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
environment: ${{ inputs.target }}
|
|
38
|
+
|
|
39
|
+
steps:
|
|
40
|
+
- name: Check out repository
|
|
41
|
+
uses: actions/checkout@v4
|
|
42
|
+
|
|
43
|
+
- name: Set up Node.js
|
|
44
|
+
uses: actions/setup-node@v4
|
|
45
|
+
with:
|
|
46
|
+
node-version: 22
|
|
47
|
+
cache: npm
|
|
48
|
+
|
|
49
|
+
- name: Install project dependencies
|
|
50
|
+
run: npm ci
|
|
51
|
+
|
|
52
|
+
- name: Hydrate target HubSpot credentials
|
|
53
|
+
env:
|
|
54
|
+
PROD_TOKEN: ${{ secrets.HUBSPOT_PROD_PRIVATE_APP_TOKEN }}
|
|
55
|
+
run: |
|
|
56
|
+
mkdir -p "$HUBSPOT_KEY_DIR"
|
|
57
|
+
token_path="$HUBSPOT_KEY_DIR/prod.private-app-token"
|
|
58
|
+
printf '%s' "$PROD_TOKEN" > "$token_path"
|
|
59
|
+
chmod 600 "$token_path"
|
|
60
|
+
|
|
61
|
+
- name: Build publish plan
|
|
62
|
+
run: |
|
|
63
|
+
npx --yes hubspot-cms-sync@latest doctor --root .
|
|
64
|
+
npx --yes hubspot-cms-sync@latest corpus --root .
|
|
65
|
+
npx --yes hubspot-cms-sync@latest preflight "$HCMS_TARGET" --root .
|
|
66
|
+
npx --yes hubspot-cms-sync@latest plan \
|
|
67
|
+
"$HCMS_TARGET" --root . --out .hcms/publish-plan.md
|
|
68
|
+
|
|
69
|
+
- name: Publish to HubSpot
|
|
70
|
+
if: ${{ !inputs.dry_run }}
|
|
71
|
+
run: |
|
|
72
|
+
npx --yes hubspot-cms-sync@latest push \
|
|
73
|
+
"$HCMS_TARGET" --root . --publish
|
|
74
|
+
npx --yes hubspot-cms-sync@latest verify "$HCMS_TARGET" --root .
|
|
75
|
+
|
|
76
|
+
- name: Upload publish plan
|
|
77
|
+
if: ${{ always() }}
|
|
78
|
+
uses: actions/upload-artifact@v4
|
|
79
|
+
with:
|
|
80
|
+
name: hcms-publish-plan-${{ inputs.target }}
|
|
81
|
+
path: .hcms/publish-plan.md
|
|
82
|
+
if-no-files-found: ignore
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
accountsFile: 'sync/accounts.json',
|
|
3
|
+
keyDirEnv: 'HUBSPOT_KEY_DIR',
|
|
4
|
+
contentDir: 'content',
|
|
5
|
+
syncStateDir: '.sync-state',
|
|
6
|
+
manifestPath: 'site.manifest.json',
|
|
7
|
+
readOnlyPortalIds: [],
|
|
8
|
+
knownPortalIds: [],
|
|
9
|
+
assetHosts: {
|
|
10
|
+
canonicalizeHostPatterns: [
|
|
11
|
+
'hubfs',
|
|
12
|
+
'hubspotusercontent',
|
|
13
|
+
'cdn\\d*\\.hubspot\\.net'
|
|
14
|
+
],
|
|
15
|
+
legacySiteHosts: []
|
|
16
|
+
},
|
|
17
|
+
adapters: {
|
|
18
|
+
externalDirs: []
|
|
19
|
+
},
|
|
20
|
+
theme: {
|
|
21
|
+
name: 'example-theme',
|
|
22
|
+
dirs: ['templates', 'modules', 'css', 'js', 'images'],
|
|
23
|
+
files: ['theme.json', 'fields.json']
|
|
24
|
+
},
|
|
25
|
+
blog: {
|
|
26
|
+
slug: 'blog',
|
|
27
|
+
itemTemplate: 'example-theme/templates/blog-post.html',
|
|
28
|
+
listingTemplate: 'example-theme/templates/blog.html'
|
|
29
|
+
},
|
|
30
|
+
uiGated: [
|
|
31
|
+
'blogContainerCreate',
|
|
32
|
+
'domainConnect',
|
|
33
|
+
'homepageDesignation',
|
|
34
|
+
'themeSettingsValues',
|
|
35
|
+
'nativeMenus'
|
|
36
|
+
],
|
|
37
|
+
verification: {
|
|
38
|
+
baseUrlEnv: 'SITE_BASE_URL',
|
|
39
|
+
commands: {
|
|
40
|
+
unit: 'npm run test:unit',
|
|
41
|
+
corpus: 'hcms corpus',
|
|
42
|
+
playwright: 'npx playwright test verify/fidelity.spec.mjs verify/forms.spec.mjs verify/links.spec.mjs'
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"theme": {
|
|
3
|
+
"name": "example-theme"
|
|
4
|
+
},
|
|
5
|
+
"blog": {
|
|
6
|
+
"slug": "blog",
|
|
7
|
+
"itemTemplate": "example-theme/templates/blog-post.html",
|
|
8
|
+
"listingTemplate": "example-theme/templates/blog.html"
|
|
9
|
+
},
|
|
10
|
+
"forms": [],
|
|
11
|
+
"pages": [],
|
|
12
|
+
"uiGated": [
|
|
13
|
+
"blogContainerCreate",
|
|
14
|
+
"domainConnect",
|
|
15
|
+
"homepageDesignation",
|
|
16
|
+
"themeSettingsValues",
|
|
17
|
+
"nativeMenus"
|
|
18
|
+
]
|
|
19
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "hubspot-cms-sync",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Git-backed bidirectional sync for HubSpot CMS themes, content, blogs, forms, and assets.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=20.10.0",
|
|
9
|
+
"npm": ">=10"
|
|
10
|
+
},
|
|
11
|
+
"bin": {
|
|
12
|
+
"hubspot-cms-sync": "./bin/hubspot-cms-sync.mjs",
|
|
13
|
+
"hcms": "./bin/hubspot-cms-sync.mjs"
|
|
14
|
+
},
|
|
15
|
+
"exports": {
|
|
16
|
+
".": "./src/index.mjs",
|
|
17
|
+
"./adapters/*": "./src/adapters/*.mjs",
|
|
18
|
+
"./lib/*": "./src/lib/*.mjs",
|
|
19
|
+
"./manifest": "./src/manifest.mjs",
|
|
20
|
+
"./preflight": "./src/preflight.mjs",
|
|
21
|
+
"./cta-inventory": "./src/cta-inventory.mjs",
|
|
22
|
+
"./corpus-scan": "./src/corpus-scan.mjs"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"bin/",
|
|
26
|
+
"src/",
|
|
27
|
+
"docs/",
|
|
28
|
+
"examples/",
|
|
29
|
+
"skill/",
|
|
30
|
+
"README.md",
|
|
31
|
+
"LICENSE"
|
|
32
|
+
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"test": "node --test test/**/*.test.mjs",
|
|
35
|
+
"test:unit": "node --test test/unit/*.test.mjs test/integration/corpus.test.mjs",
|
|
36
|
+
"test:integration": "RUN_INTEGRATION=1 node --test test/integration/roundtrip.test.mjs",
|
|
37
|
+
"lint": "node --check bin/hubspot-cms-sync.mjs && node bin/hubspot-cms-sync.mjs --help >/dev/null",
|
|
38
|
+
"prepare": "npm run lint",
|
|
39
|
+
"prepublishOnly": "npm test && npm run lint && npm pack --dry-run"
|
|
40
|
+
}
|
|
41
|
+
}
|
package/skill/SKILL.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hubspot-cms-sync
|
|
3
|
+
description: Use when operating the hubspot-cms-sync CLI in a repository: inspect config and manifest files, run doctor/corpus/preflight/pull/push/republish/verify flows, debug GitHub Actions failures, and safely manage HubSpot CMS preview or publish workflows.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# HubSpot CMS Sync
|
|
7
|
+
|
|
8
|
+
Use this skill to operate `hubspot-cms-sync` or `hcms` inside a consuming repo.
|
|
9
|
+
The CLI owns deterministic sync behavior; the agent owns sequencing,
|
|
10
|
+
interpretation, and clear reporting.
|
|
11
|
+
|
|
12
|
+
## First Checks
|
|
13
|
+
|
|
14
|
+
1. Confirm the repo has `hubspot-cms-sync.config.mjs` and `site.manifest.json`.
|
|
15
|
+
2. Confirm `hubspot-cms-sync` or `hcms` is available. If not, use the package
|
|
16
|
+
command documented by the repo.
|
|
17
|
+
3. Read the config before choosing targets, credential environment variables, or
|
|
18
|
+
verification commands.
|
|
19
|
+
4. Run `hcms doctor` before risky operations.
|
|
20
|
+
5. Never bypass read-only portal guards or write to a production portal from a
|
|
21
|
+
pull request workflow.
|
|
22
|
+
|
|
23
|
+
## Common Flows
|
|
24
|
+
|
|
25
|
+
- Pull: run `hcms pull <target>`, `hcms corpus`, inspect `git diff`, then
|
|
26
|
+
summarize content changes and verification gaps.
|
|
27
|
+
- Push: run `hcms corpus`, `hcms preflight <target>`, `hcms push <target> --dry-run`,
|
|
28
|
+
then `hcms push <target> --publish` only after the checks match intent.
|
|
29
|
+
- Republish: run `hcms preflight <target>`, then `hcms republish <target>` with
|
|
30
|
+
the narrowest flags needed.
|
|
31
|
+
- Verify: use the consuming repo's configured tests after the CLI checks pass.
|
|
32
|
+
- CI failure: inspect logs, classify the failure, rerun the smallest local
|
|
33
|
+
command that reproduces it, and avoid broad retries until the cause is known.
|
|
34
|
+
|
|
35
|
+
## References
|
|
36
|
+
|
|
37
|
+
Load only the reference needed for the task:
|
|
38
|
+
|
|
39
|
+
- `references/commands.md`: command matrix and expected sequencing.
|
|
40
|
+
- `references/config.md`: config and manifest fields to inspect.
|
|
41
|
+
- `references/failures.md`: common failure classes and remediation.
|
|
42
|
+
- `references/github-actions.md`: CI, preview, and publish workflow policy.
|
|
43
|
+
- `references/screenshots-and-fidelity.md`: visual verification workflows.
|
|
44
|
+
|
|
45
|
+
## Guardrails
|
|
46
|
+
|
|
47
|
+
- Do not edit `.sync-state` by hand.
|
|
48
|
+
- Do not suggest pushing to a configured read-only portal.
|
|
49
|
+
- Prefer `hcms push --dry-run` and `hcms preflight` before any write.
|
|
50
|
+
- Report missing credentials or preview URLs as verification gaps.
|
|
51
|
+
- Treat surviving `@cta:*` or `@menu:*` references as closed failures until
|
|
52
|
+
producer adapters exist.
|
|
53
|
+
- Treat HubSpot writes as rerun-to-convergence operations, not transactional
|
|
54
|
+
rollbacks.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Command Reference
|
|
2
|
+
|
|
3
|
+
Commands are shown with the short alias `hcms`. Use `hubspot-cms-sync` if the
|
|
4
|
+
repo has not installed the alias.
|
|
5
|
+
|
|
6
|
+
## Inspection
|
|
7
|
+
|
|
8
|
+
- `hcms doctor`: validate config, credentials, target definitions, and local
|
|
9
|
+
filesystem assumptions.
|
|
10
|
+
- `hcms corpus`: validate the local content corpus and adapter references.
|
|
11
|
+
- `hcms push <target> --dry-run`: produce a write plan without applying it.
|
|
12
|
+
|
|
13
|
+
## Pull
|
|
14
|
+
|
|
15
|
+
Use pull when HubSpot is the source of truth for the current task.
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
hcms doctor
|
|
19
|
+
hcms pull <target>
|
|
20
|
+
hcms corpus
|
|
21
|
+
git diff --stat
|
|
22
|
+
git diff
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Summarize changed files, content objects, and any verification that could not be
|
|
26
|
+
run.
|
|
27
|
+
|
|
28
|
+
## Push
|
|
29
|
+
|
|
30
|
+
Use push when git is the source of truth and the target is write-capable.
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
hcms doctor
|
|
34
|
+
hcms corpus
|
|
35
|
+
hcms preflight <target>
|
|
36
|
+
hcms push <target> --dry-run
|
|
37
|
+
hcms push <target> --publish
|
|
38
|
+
the consuming repo verification commands
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Stop before `push` if preflight or plan output indicates a read-only portal,
|
|
42
|
+
unresolved dependency, missing credential, or unexpected destructive change.
|
|
43
|
+
|
|
44
|
+
## Republish
|
|
45
|
+
|
|
46
|
+
Use the narrowest republish scope that satisfies the change.
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
hcms preflight <target>
|
|
50
|
+
hcms republish <target> --all
|
|
51
|
+
the consuming repo verification commands
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Prefer explicit page, blog, or template scopes when the CLI supports them.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Config And Manifest Reference
|
|
2
|
+
|
|
3
|
+
Read `hubspot-cms-sync.config.mjs` before selecting targets or commands.
|
|
4
|
+
|
|
5
|
+
Key fields:
|
|
6
|
+
|
|
7
|
+
- `accountsFile`: maps target names to HubSpot account details.
|
|
8
|
+
- `keyDirEnv`: environment variable pointing at hydrated credentials.
|
|
9
|
+
- `contentDir`: local CMS content directory.
|
|
10
|
+
- `syncStateDir`: local sync state directory; do not edit by hand.
|
|
11
|
+
- `manifestPath`: path to `site.manifest.json`.
|
|
12
|
+
- `readOnlyPortalIds`: portals that must never receive writes.
|
|
13
|
+
- `knownPortalIds`: expected portal allowlist.
|
|
14
|
+
- `assetHosts`: host canonicalization policy for HubSpot assets.
|
|
15
|
+
- `adapters.externalDirs`: optional consumer-owned adapters.
|
|
16
|
+
- `theme`: theme directory and file layout.
|
|
17
|
+
- `blog`: blog slug and template mapping.
|
|
18
|
+
- `uiGated`: operations that require HubSpot UI action.
|
|
19
|
+
- `verification`: base URL environment variable and repo-specific test commands.
|
|
20
|
+
|
|
21
|
+
`site.manifest.json` is the deployment surface for theme, blog, forms, pages,
|
|
22
|
+
and UI-gated operations. If the manifest and config disagree, stop and ask for
|
|
23
|
+
the intended source of truth.
|
|
24
|
+
|
|
25
|
+
Use paths relative to the repo root unless the config explicitly says otherwise.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Failure Reference
|
|
2
|
+
|
|
3
|
+
Prefer the CLI's error text and remediation output. Use this file to classify
|
|
4
|
+
failures and choose the next diagnostic step.
|
|
5
|
+
|
|
6
|
+
## Configuration
|
|
7
|
+
|
|
8
|
+
Symptoms:
|
|
9
|
+
|
|
10
|
+
- Missing `hubspot-cms-sync.config.mjs`.
|
|
11
|
+
- Invalid config shape.
|
|
12
|
+
- Target name is not present in `accountsFile`.
|
|
13
|
+
- `keyDirEnv` is unset or points at missing credentials.
|
|
14
|
+
|
|
15
|
+
Action: fix config or CI secret hydration before retrying sync commands.
|
|
16
|
+
|
|
17
|
+
## Read-Only Portal
|
|
18
|
+
|
|
19
|
+
Symptoms:
|
|
20
|
+
|
|
21
|
+
- Target portal ID is listed in `readOnlyPortalIds`.
|
|
22
|
+
- Preflight blocks write operations.
|
|
23
|
+
|
|
24
|
+
Action: do not bypass the guard. Choose a write-capable preview target or ask
|
|
25
|
+
for an explicit config change.
|
|
26
|
+
|
|
27
|
+
## Dependency References
|
|
28
|
+
|
|
29
|
+
Symptoms:
|
|
30
|
+
|
|
31
|
+
- Surviving `@cta:*` or `@menu:*` references.
|
|
32
|
+
- Missing producer adapter output.
|
|
33
|
+
- Manifest objects refer to absent content.
|
|
34
|
+
|
|
35
|
+
Action: fail closed until the producer adapter or source content exists.
|
|
36
|
+
|
|
37
|
+
## HubSpot API
|
|
38
|
+
|
|
39
|
+
Symptoms:
|
|
40
|
+
|
|
41
|
+
- Authentication failure.
|
|
42
|
+
- Rate limit or transient 5xx response.
|
|
43
|
+
- Validation error from a HubSpot object endpoint.
|
|
44
|
+
|
|
45
|
+
Action: distinguish credential/config failures from transient API failures. For
|
|
46
|
+
transient failures, retry the smallest failed operation. For validation errors,
|
|
47
|
+
fix the source object or adapter output.
|
|
48
|
+
|
|
49
|
+
## Verification
|
|
50
|
+
|
|
51
|
+
Symptoms:
|
|
52
|
+
|
|
53
|
+
- Missing `SITE_BASE_URL` or configured base URL env var.
|
|
54
|
+
- Playwright or link checks cannot reach the preview.
|
|
55
|
+
- Screenshots differ after a template or module change.
|
|
56
|
+
|
|
57
|
+
Action: report unavailable verification separately from failed verification.
|
|
58
|
+
When screenshots differ, include the affected page and artifact path.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# GitHub Actions Reference
|
|
2
|
+
|
|
3
|
+
Use the repository's workflow files first. If adding new workflows, start from
|
|
4
|
+
the package examples:
|
|
5
|
+
|
|
6
|
+
- `examples/github-actions/ci.yml`
|
|
7
|
+
- `examples/github-actions/preview.yml`
|
|
8
|
+
- `examples/github-actions/publish.yml`
|
|
9
|
+
|
|
10
|
+
## CI
|
|
11
|
+
|
|
12
|
+
CI should be read-only. It can run:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
hcms doctor
|
|
16
|
+
hcms corpus
|
|
17
|
+
hcms preflight <non-prod-target> --read-only
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Do not expose production credentials to `pull_request` events.
|
|
21
|
+
|
|
22
|
+
## Preview
|
|
23
|
+
|
|
24
|
+
Preview workflows should use a non-prod HubSpot target and PR-level
|
|
25
|
+
concurrency.
|
|
26
|
+
|
|
27
|
+
Typical sequence:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
hcms doctor
|
|
31
|
+
hcms corpus
|
|
32
|
+
hcms preflight preview
|
|
33
|
+
hcms push preview --dry-run
|
|
34
|
+
hcms push preview --publish
|
|
35
|
+
the preview verification commands
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Upload the plan and verification artifacts when available.
|
|
39
|
+
|
|
40
|
+
## Publish
|
|
41
|
+
|
|
42
|
+
Publish workflows should be manual or release-driven and protected by a GitHub
|
|
43
|
+
Environment.
|
|
44
|
+
|
|
45
|
+
Typical sequence:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
hcms doctor
|
|
49
|
+
hcms corpus
|
|
50
|
+
hcms preflight prod
|
|
51
|
+
hcms push prod --dry-run
|
|
52
|
+
hcms push prod --publish
|
|
53
|
+
the production verification commands
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Keep a dry-run option for validating the plan without writing to HubSpot.
|