@duffcloudservices/cli
v0.4.7
Published
CLI for DCS site onboarding and configuration
Maintainers
Readme
@duffcloudservices/cli
Command-line interface for initializing and managing DCS (Duff Cloud Services) customer sites.
Installation
npm install -g @duffcloudservices/cli
# or
pnpm add -g @duffcloudservices/cliQuick Start
# 1. Authenticate with Google OAuth
dcs login
# 2. Initialize a new customer site
cd /path/to/customer-site
dcs init --site-slug my-site --site-name "My Site"
# 3. Validate configuration
dcs validate
# 4. Generate integration plans
dcs plansCommands
Authentication
# Login with Google OAuth (device flow)
dcs login
# Check current user
dcs whoami
# Logout and clear credentials
dcs logoutThe CLI talks to the production portal by default (config.portalApiUrl in this
package's package.json). Set DCS_API_URL to point every command - login, token
refresh, logout and the API client - at another portal, for example a staging one:
DCS_API_URL=https://portal-staging.example.test dcs loginSite Management
# List sites you have access to
dcs sites list
# Show details for a specific site
dcs sites show my-siteInitialization
# Initialize DCS integration in current directory
dcs init --site-slug my-site --site-name "My Site"
# Specify target directory
dcs init -s my-site -n "My Site" -t ./my-site
# Specify framework (vue or astro)
dcs init -s my-site -n "My Site" -f astro
# Preview without creating files
dcs init -s my-site -n "My Site" --dry-run
# Overwrite existing files
dcs init -s my-site -n "My Site" --forceValidation
# Validate .dcs configuration files
dcs validate
# Validate a specific directory
dcs validate -t ./my-site
# Show verbose output
dcs validate -vIntegration Plans
# Generate AI-assisted integration plans
dcs plans
# Regenerate existing plans
dcs plans --forcePage Snapshot Capture
# Capture all pages listed in .dcs/pages.yaml
dcs capture-snapshots --target ./customer-site --base-url http://localhost:5173
# Capture only selected page slugs
dcs capture-snapshots --target ./customer-site --base-url http://localhost:5173 --pages home,aboutSnapshot output uses a fixed portal contract:
| File | Portal use | Capture behavior |
| --- | --- | --- |
| site-snapshots/{pageSlug}/full-page.png | Expanded page dialog with auto-scroll | Full scrollable page after a lazy-load pass |
| site-snapshots/{pageSlug}/thumbnail.png | Pages grid cards | Header/hero-focused 16:9 top crop captured at the site desktop viewport |
| site-snapshots/{pageSlug}/sections/{sectionId}.png | Visual-editor section overlays | Individual data-section element screenshots |
Full-page captures must reset scroll after the lazy-load pass and temporarily pin fixed/sticky site navigation to the document origin during page.screenshot({ fullPage: true }). Without that capture-time layout guard, Playwright can render a fixed top nav near the footer because the page was scrolled before the full-page image was assembled.
Keep these names stable across customer-site scripts. Site-specific flexibility belongs in .dcs/pages.yaml (snapshot.viewport, waitAfterLoad, page paths) and in environment variables such as SITE_PREVIEW_URL, not in alternate artifact names.
For managed CSS-style backgrounds or any customer-editable hero/card/staff/gallery image, render a real image layer with ManagedImage from @duffcloudservices/cms/managed-image (or the same local pattern for framework-specific sites), backed by matching .dcs/content.yaml URL and alt keys. The actual <img> must expose data-dcs-image-key, data-dcs-image-url, and data-dcs-image-alt; snapshot capture records those markers as editable image keys, which keeps images visible in full-page screenshots and replaceable from the visual editor.
Generated Files
The init command creates the following structure:
.dcs/
├── site.yaml # Site identity and Azure config
├── pages.yaml # Page registry for CMS
├── content.yaml # Text content (managed by Portal)
├── seo.yaml # SEO configuration (managed by Portal)
└── SECTION-CONVENTIONS.md
.github/
└── copilot-instructions.md
.plans/
├── README.md
├── 00-audit-site.md
├── 01-create-use-text-content.md
├── 02-integrate-home-page.md
├── 03-integrate-remaining-pages.md
├── 04-capture-snapshots.md
└── 05-verify-deployment.mdAuthentication Flow
The CLI uses OAuth 2.0 Device Authorization Grant (RFC 8628):
- Run
dcs login - CLI displays a URL and code
- Open URL in browser, enter code
- Sign in with Google
- CLI receives and stores tokens locally
Token storage
Tokens (access token, refresh token, and basic user info) are stored encrypted at rest, using the best secret store available on your machine. The CLI never writes the tokens to disk in plaintext.
| Platform | Backend | Where |
| --- | --- | --- |
| macOS | Keychain (security generic password) | login keychain, service dcs-cli |
| Linux | libsecret (secret-tool) when present | Secret Service (GNOME Keyring / KWallet) |
| Windows | DPAPI (ProtectedData, CurrentUser scope) | %APPDATA%\dcs-cli-nodejs\auth.dpapi (ciphertext) |
| Fallback | AES-256-GCM encrypted file (machine/user-derived key) | <config dir>/auth.enc |
dcs whoami prints which backend is active. Run dcs logout to delete the
stored tokens.
The encrypted-file fallback is only used when no OS keychain and no DPAPI is
available (e.g. a headless Linux box with no Secret Service daemon). Its key is
derived from the machine + user identity, so it is stronger than plaintext but
is not a substitute for an OS keychain against a determined local attacker;
prefer installing libsecret (secret-tool) on such hosts.
Migration: if you previously authenticated with a build that stored a
plaintext conf JSON, your existing tokens are moved into the keychain
automatically on the next command, and the plaintext file entry is deleted.
Site Access Validation
Before creating configuration files, the CLI validates:
- You're authenticated
- You have access to the specified site (or can create it)
- You have editor/admin permissions
This prevents creating configs for sites you don't have access to.
Next Steps After Init
- Install CMS package:
pnpm add @duffcloudservices/cms - Configure Vite plugins in your build config
- Follow the plans in
.plans/directory - Register site in DCS Portal
Requirements
- Node.js >= 18.0.0
- DCS Portal account with Google OAuth
License
MIT © Duff Cloud Services
