diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..16cdc57 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +# EditorConfig — https://editorconfig.org +# Keep editors aligned with the Prettier config (.prettierrc). +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +# Markdown uses two trailing spaces for hard line breaks — don't strip them. +[*.md] +trim_trailing_whitespace = false diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..4a865eb --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,63 @@ +name: Bug report +description: Report a problem with the dcd CLI or dcd-mcp server +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to file a bug! Please fill in the details below. + + ⚠️ **Do not report security vulnerabilities here** — see our + [Security Policy](https://github.com/devicecloud-dev/dcd-cli/blob/dev/SECURITY.md). + - type: textarea + id: what-happened + attributes: + label: What happened? + description: A clear description of the bug, including what you expected to happen instead. + validations: + required: true + - type: textarea + id: repro + attributes: + label: Steps to reproduce + description: The exact `dcd` command(s) you ran and what followed. Redact any API keys. + placeholder: | + 1. Run `dcd cloud --apiKey *** app.apk flows/` + 2. ... + 3. See error + validations: + required: true + - type: input + id: version + attributes: + label: CLI version + description: Output of `dcd --version`. + placeholder: "e.g. 5.0.0" + validations: + required: true + - type: dropdown + id: os + attributes: + label: Operating system + options: + - macOS + - Linux + - Windows + - Other (note in description) + validations: + required: true + - type: input + id: install + attributes: + label: How did you install dcd? + placeholder: "binary (curl/irm), npm global, npx, …" + validations: + required: false + - type: textarea + id: logs + attributes: + label: Logs / output + description: Relevant output. Re-run with more detail if you can. This is automatically formatted as code. + render: shell + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..8769523 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,11 @@ +blank_issues_enabled: false +contact_links: + - name: Questions & help + url: https://discord.gg/gm3mJwcNw8 + about: For usage questions and general help, ask in our Discord rather than opening an issue. + - name: Documentation + url: https://docs.devicecloud.dev + about: Check the docs for installation, usage, and command reference. + - name: Report a security vulnerability + url: https://github.com/devicecloud-dev/dcd-cli/blob/dev/SECURITY.md + about: Do not file security issues publicly — email security@devicecloud.dev (see our Security Policy). diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..ece12e5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,35 @@ +name: Feature request +description: Suggest an idea or improvement for the dcd CLI or dcd-mcp server +labels: ["enhancement"] +body: + - type: markdown + attributes: + value: Thanks for the suggestion! Please describe the problem before the solution. + - type: textarea + id: problem + attributes: + label: What problem are you trying to solve? + description: What are you trying to do, and where does the CLI get in the way today? + validations: + required: true + - type: textarea + id: solution + attributes: + label: Proposed solution + description: What would you like to happen? A concrete command/flag/output sketch helps. + validations: + required: true + - type: textarea + id: alternatives + attributes: + label: Alternatives considered + description: Other approaches or workarounds you've thought about. + validations: + required: false + - type: textarea + id: context + attributes: + label: Additional context + description: Anything else — links, screenshots, related issues. + validations: + required: false diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..288cc94 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,36 @@ + + +## What & why + + + +## Type of change + + + +- [ ] `fix` — bug fix +- [ ] `feat` — new feature +- [ ] `perf` — performance improvement +- [ ] `refactor` — code change that's neither a fix nor a feature +- [ ] `docs` — documentation only +- [ ] `chore` / `ci` / `build` / `test` — tooling, no user-facing change +- [ ] Breaking change (title has `!` or PR notes a `BREAKING CHANGE:`) + +## Checklist + +- [ ] PR title follows the Conventional Commits format (see comment above) +- [ ] `pnpm lint` passes +- [ ] `pnpm typecheck` passes +- [ ] `pnpm build` passes +- [ ] I have **not** bumped the version or edited `CHANGELOG.md` (release-please handles this) +- [ ] I have signed the CLA (the bot will prompt on first contribution) +- [ ] Docs / `README.md` / `STYLE_GUIDE.md` updated if behaviour or output changed + +## How to test + + diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..e792454 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,34 @@ +version: 2 +updates: + # npm / pnpm dependencies. + - package-ecosystem: npm + directory: "/" + schedule: + interval: weekly + target-branch: dev + open-pull-requests-limit: 10 + commit-message: + # Conventional Commit prefix so the squashed PR title matches our PR-title + # lint and release-please picks dependency bumps into the changelog. + prefix: deps + prefix-development: chore + groups: + # Collapse the noise: one PR for all non-major updates. + minor-and-patch: + update-types: + - minor + - patch + + # GitHub Actions used by our workflows. + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: weekly + target-branch: dev + commit-message: + prefix: ci + groups: + actions: + update-types: + - minor + - patch diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml new file mode 100644 index 0000000..bcab57c --- /dev/null +++ b/.github/workflows/cla.yml @@ -0,0 +1,49 @@ +name: CLA Assistant + +# Gates merges on a signed Contributor License Agreement. +# +# Uses CLA Assistant Lite (contributor-assistant/github-action): signatures are +# stored as a JSON file committed to a branch of THIS repo (no third-party +# service holds the data). Contributors sign by commenting the configured phrase +# on their PR; the action records it and flips the check green. +# +# SETUP REQUIRED before this can work: +# 1. Create a token with repo write access and add it as the `PERSONAL_ACCESS_TOKEN` +# secret (a fine-grained PAT or the release GitHub App token both work). The +# default GITHUB_TOKEN is also passed, but a PAT is needed to commit the +# signature file back to the repo. +# 2. Create the `cla-signatures` branch (e.g. an empty orphan branch) so the +# action has somewhere to write `signatures/version1/cla.json`. +# 3. Finalise CLA.md (legal review) — it's the document contributors agree to. +on: + issue_comment: + types: [created] + pull_request_target: + types: [opened, closed, synchronize] + +permissions: + actions: write + contents: write + pull-requests: write + statuses: write + +jobs: + cla: + runs-on: ubuntu-latest + # Only act on the signature comment or on PR events (not every comment). + if: (github.event.issue.pull_request && contains(github.event.comment.body, 'I have read the CLA Document and I hereby sign the CLA')) || github.event_name == 'pull_request_target' + steps: + - uses: contributor-assistant/github-action@v2.6.1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + with: + path-to-signatures: "signatures/version1/cla.json" + path-to-document: "https://github.com/devicecloud-dev/dcd-cli/blob/dev/CLA.md" + branch: "cla-signatures" + # PR target branches the CLA applies to. + allowlist: dependabot[bot],renovate[bot],*[bot] + # Customise the bot's prompts if desired: + custom-notsigned-prompt: "Thanks for your contribution! Please sign our Contributor License Agreement before we can merge. Comment the line below to sign:" + custom-pr-sign-comment: "I have read the CLA Document and I hereby sign the CLA" + custom-allsigned-prompt: "All contributors have signed the CLA. ✍️ ✅" diff --git a/.github/workflows/cli-ci.yml b/.github/workflows/cli-ci.yml index 71d6ae3..d4bb529 100644 --- a/.github/workflows/cli-ci.yml +++ b/.github/workflows/cli-ci.yml @@ -2,9 +2,11 @@ name: CLI CI on: push: - branches: [ dev ] + branches: [ dev, production ] pull_request: - branches: [ dev ] + # `production` is included so the dev→production promotion PR is also gated + # by lint/typecheck/build (and is required by the production ruleset). + branches: [ dev, production ] workflow_dispatch: permissions: diff --git a/.github/workflows/pr-title-lint.yml b/.github/workflows/pr-title-lint.yml new file mode 100644 index 0000000..c16aa6d --- /dev/null +++ b/.github/workflows/pr-title-lint.yml @@ -0,0 +1,43 @@ +name: PR Title + +# Enforces Conventional Commits on the PR *title*. Because PRs are squash-merged +# with the title as the commit subject, this is what release-please parses to +# compute version bumps and the changelog — so the allowed types below must stay +# in sync with `changelog-sections` in release-please-config.json. +# +# Uses pull_request_target so it also runs (and reports a required status check) +# on PRs from forks. It only reads the title — no untrusted code is checked out. +on: + pull_request_target: + types: + - opened + - edited + - synchronize + - reopened + +permissions: + pull-requests: read + +jobs: + validate: + name: Validate PR title + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + # Keep in lockstep with release-please-config.json changelog-sections. + types: | + feat + fix + perf + deps + revert + refactor + docs + chore + test + ci + build + style diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 284b290..f28914a 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -22,15 +22,28 @@ jobs: release-please-prod: if: github.ref_name == 'production' runs-on: ubuntu-latest + # Empty until the release GitHub App secrets are configured. We use an App + # token (not GITHUB_TOKEN) so the Release PR triggers CI / PR-title / CLA + # checks — PRs opened by GITHUB_TOKEN do not, which would deadlock branch + # protection. Falls back to GITHUB_TOKEN (today's behaviour) until the App + # is set up, so this is safe to merge before then. + env: + RELEASE_PLEASE_APP_ID: ${{ secrets.RELEASE_PLEASE_APP_ID }} outputs: release_created: ${{ steps.release.outputs.release_created }} tag_name: ${{ steps.release.outputs.tag_name }} version: ${{ steps.release.outputs.version }} steps: + - uses: actions/create-github-app-token@v2 + id: app-token + if: env.RELEASE_PLEASE_APP_ID != '' + with: + app-id: ${{ secrets.RELEASE_PLEASE_APP_ID }} + private-key: ${{ secrets.RELEASE_PLEASE_APP_PRIVATE_KEY }} - uses: googleapis/release-please-action@v4 id: release with: - token: ${{ secrets.GITHUB_TOKEN }} + token: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }} target-branch: production config-file: release-please-config.json manifest-file: .release-please-manifest.json @@ -38,15 +51,25 @@ jobs: release-please-beta: if: github.ref_name == 'dev' runs-on: ubuntu-latest + # See release-please-prod above for why this uses an App token with a + # GITHUB_TOKEN fallback. + env: + RELEASE_PLEASE_APP_ID: ${{ secrets.RELEASE_PLEASE_APP_ID }} outputs: release_created: ${{ steps.release.outputs.release_created }} tag_name: ${{ steps.release.outputs.tag_name }} version: ${{ steps.release.outputs.version }} steps: + - uses: actions/create-github-app-token@v2 + id: app-token + if: env.RELEASE_PLEASE_APP_ID != '' + with: + app-id: ${{ secrets.RELEASE_PLEASE_APP_ID }} + private-key: ${{ secrets.RELEASE_PLEASE_APP_PRIVATE_KEY }} - uses: googleapis/release-please-action@v4 id: release with: - token: ${{ secrets.GITHUB_TOKEN }} + token: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }} target-branch: dev config-file: release-please-config-beta.json manifest-file: .release-please-manifest-beta.json diff --git a/CLA.md b/CLA.md new file mode 100644 index 0000000..1c8930d --- /dev/null +++ b/CLA.md @@ -0,0 +1,140 @@ +# Contributor License Agreement (CLA) + +> [!IMPORTANT] +> **This is a starting-point template, not final legal text.** It is adapted from +> the Apache Software Foundation Individual and Corporate CLAs. **Have it reviewed +> by legal counsel and replace the bracketed placeholders before relying on it.** +> Once finalised, this document is what the CLA Assistant bot links contributors +> to when they sign on a pull request. + +Thank you for your interest in contributing to software projects managed by +**[Legal Entity Name] ("devicecloud.dev", "we", "us")**. To clarify the +intellectual property licence granted with contributions from any person or +entity, we must have a Contributor License Agreement (CLA) on file that has been +signed by each contributor, indicating agreement to the licence terms below. + +This licence is for your protection as a contributor as well as the protection of +devicecloud.dev and its users; it does not change your rights to use your own +contributions for any other purpose. + +By signing via the CLA Assistant bot on a pull request, you accept and agree to +the applicable terms below for your present and future contributions submitted to +devicecloud.dev. + +--- + +## Individual Contributor License Agreement + +You accept and agree to the following terms and conditions for your present and +future Contributions submitted to devicecloud.dev. Except for the licence granted +herein to devicecloud.dev and recipients of software distributed by +devicecloud.dev, you reserve all right, title, and interest in and to your +Contributions. + +1. **Definitions.** "You" (or "Your") means the copyright owner or legal entity + authorised by the copyright owner that is making this Agreement. "Contribution" + means any original work of authorship, including any modifications or additions + to an existing work, that is intentionally submitted by You to devicecloud.dev + for inclusion in, or documentation of, any of the products owned or managed by + devicecloud.dev (the "Work"). "Submitted" means any form of electronic, verbal, + or written communication sent to devicecloud.dev or its representatives, + including but not limited to communication on electronic mailing lists, source + code control systems, and issue tracking systems that are managed by, or on + behalf of, devicecloud.dev for the purpose of discussing and improving the + Work, but excluding communication that is conspicuously marked or otherwise + designated in writing by You as "Not a Contribution." + +2. **Grant of Copyright Licence.** Subject to the terms and conditions of this + Agreement, You hereby grant to devicecloud.dev and to recipients of software + distributed by devicecloud.dev a perpetual, worldwide, non-exclusive, + no-charge, royalty-free, irrevocable copyright licence to reproduce, prepare + derivative works of, publicly display, publicly perform, sublicense, and + distribute Your Contributions and such derivative works. + +3. **Grant of Patent Licence.** Subject to the terms and conditions of this + Agreement, You hereby grant to devicecloud.dev and to recipients of software + distributed by devicecloud.dev a perpetual, worldwide, non-exclusive, + no-charge, royalty-free, irrevocable (except as stated in this section) patent + licence to make, have made, use, offer to sell, sell, import, and otherwise + transfer the Work, where such licence applies only to those patent claims + licensable by You that are necessarily infringed by Your Contribution(s) alone + or by combination of Your Contribution(s) with the Work to which such + Contribution(s) was submitted. If any entity institutes patent litigation + against You or any other entity (including a cross-claim or counterclaim in a + lawsuit) alleging that Your Contribution, or the Work to which You have + contributed, constitutes direct or contributory patent infringement, then any + patent licences granted to that entity under this Agreement for that + Contribution or Work shall terminate as of the date such litigation is filed. + +4. **Representations.** You represent that You are legally entitled to grant the + above licence. If Your employer(s) has rights to intellectual property that You + create that includes Your Contributions, You represent that You have received + permission to make Contributions on behalf of that employer, that Your employer + has waived such rights for Your Contributions to devicecloud.dev, or that Your + employer has executed a separate Corporate CLA with devicecloud.dev. + +5. **Original Work.** You represent that each of Your Contributions is Your + original creation (see section 7 for submissions on behalf of others). You + represent that Your Contribution submissions include complete details of any + third-party licence or other restriction (including, but not limited to, + related patents and trademarks) of which You are personally aware and which are + associated with any part of Your Contributions. + +6. **No Warranty.** You are not expected to provide support for Your + Contributions, except to the extent You desire to provide support. You may + provide support for free, for a fee, or not at all. Unless required by + applicable law or agreed to in writing, You provide Your Contributions on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions of TITLE, + NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + +7. **Third-Party Works.** Should You wish to submit work that is not Your original + creation, You may submit it to devicecloud.dev separately from any + Contribution, identifying the complete details of its source and of any + licence or other restriction (including, but not limited to, related patents, + trademarks, and licence agreements) of which You are personally aware, and + conspicuously marking the work as "Submitted on behalf of a third-party: + [named here]". + +8. **Notification.** You agree to notify devicecloud.dev of any facts or + circumstances of which You become aware that would make these representations + inaccurate in any respect. + +--- + +## Corporate Contributor License Agreement + +This version is for a corporation (or other legal entity) that wishes to authorise +employees to submit Contributions. It covers the same copyright and patent grants, +representations, and disclaimers as the Individual CLA above, made on behalf of the +entity, plus a schedule of authorised contributors. + +1. The definitions, copyright licence, patent licence, "no warranty", and + third-party works provisions in sections 1–3 and 6–7 of the Individual CLA + above apply equally to this Corporate CLA, with "You" referring to the + **Corporation** identified below. + +2. **Authorisation.** The Corporation represents that each employee designated on + **Schedule A** is authorised to submit Contributions on behalf of the + Corporation. The Corporation agrees to maintain Schedule A and to notify + devicecloud.dev when an individual's authorisation to submit Contributions on + behalf of the Corporation is terminated. + +3. **Representations.** The Corporation represents that each Contribution is an + original creation (per section 5 of the Individual CLA) and that it is legally + entitled to grant the above licences. The Corporation agrees to notify + devicecloud.dev of any facts or circumstances of which it becomes aware that + would make these representations inaccurate. + +**Schedule A — Designated Employees** + +| Full name | GitHub username | Email | +| --- | --- | --- | +| | | | + +**Corporation details** + +- Corporation name: ______________________________ +- Corporation address: ___________________________ +- Authorised signatory (name & title): ___________ +- Signature / date: ______________________________ diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..fd6b573 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,132 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official email address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +**conduct@devicecloud.dev**. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..1761173 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,147 @@ +# Contributing to the devicecloud.dev CLI + +Thanks for your interest in improving `@devicecloud.dev/dcd`! This guide covers +everything you need to land a change: local setup, our commit/PR conventions, and +how releases work. + +By participating you agree to abide by our [Code of Conduct](CODE_OF_CONDUCT.md). + +## Contributor License Agreement (CLA) + +Before your first contribution can be merged, you must sign our Contributor +License Agreement. When you open your first pull request, the **CLA Assistant** +bot will comment with a link and instructions — signing takes under a minute and +is a one-time step. PRs cannot be merged until the CLA check is green. + +- Individuals: sign the [Individual CLA](CLA.md#individual-contributor-license-agreement). +- Contributing on behalf of an employer? Have an authorised signatory complete the + [Corporate CLA](CLA.md#corporate-contributor-license-agreement). + +## Getting started + +You need **Node.js 22+** and **[pnpm](https://pnpm.io)** (`packageManager` pins +the exact version; [Corepack](https://nodejs.org/api/corepack.html) will pick it +up automatically). + +```sh-session +$ git clone https://github.com/devicecloud-dev/dcd-cli.git +$ cd dcd-cli +$ pnpm install # installs deps, builds, and sets up git hooks +$ pnpm dcd # run the CLI from source +``` + +Useful scripts: + +| Command | What it does | +| --- | --- | +| `pnpm lint` | ESLint over `src/` and `test/` | +| `pnpm typecheck` | Strict `tsc --noEmit` over `src/` and `test/` | +| `pnpm build` | Compile to `dist/` | +| `pnpm test` | Build + boot the mock API + run integration/unit tests | + +**Before pushing, make sure `pnpm lint`, `pnpm typecheck`, and `pnpm build` +pass.** These run for every PR (including from forks) and are required to merge. + +### About the test suite + +`pnpm test` boots a **mock API that lives in a private repository**, so the full +integration suite only runs on branches inside this repo. **On pull requests from +forks the integration tests are automatically skipped** — you'll see a CI notice +saying so. That's expected: lint, typecheck, and build still run and gate your +PR, and a maintainer runs the full suite before merge. You don't need backend +access to contribute. + +### Secret scanning + +A [gitleaks](https://github.com/gitleaks/gitleaks) scan runs as a pre-commit hook +and in CI (sharing the allowlist in `.gitleaks.toml`). Installing the binary +locally (`brew install gitleaks`) catches secrets before you commit; without it +the hook skips with a warning and CI remains the backstop. **Never commit real +credentials.** + +## Branching & pull requests + +1. Branch off **`dev`** (the default branch). Name it descriptively, e.g. + `fix/upload-retry` or `feat/json-output`. +2. Open your pull request **against `dev`**. (The `production` branch is the + stable release track and is maintainer-only — don't target it.) +3. Keep PRs focused. Smaller, single-purpose PRs are reviewed and merged faster. +4. Fill in the PR template, including the checklist. +5. PRs are merged via **squash merge**, so your PR ends up as a single commit on + `dev` whose message is your **PR title** — which is why the title must follow + the Conventional Commits format below. + +## Commit & PR title conventions + +We use [Conventional Commits](https://www.conventionalcommits.org). Because we +squash-merge, **only your PR title needs to follow the format** — individual +commit messages on your branch are squashed away, so commit however you like +while developing. A CI check (`PR Title`) validates the title and must pass to +merge. + +Format: + +``` +(): +``` + +Allowed types and how they affect the next release: + +| Type | Use for | Changelog | Version bump | +| --- | --- | --- | --- | +| `feat` | A new feature | **Features** | minor | +| `fix` | A bug fix | **Bug Fixes** | patch | +| `perf` | A performance improvement | **Performance** | patch | +| `deps` | Dependency updates | **Dependencies** | patch | +| `revert` | Reverting a previous change | **Reverts** | patch | +| `refactor` | Code change that neither fixes a bug nor adds a feature | **Code Refactoring** | patch | +| `docs` | Documentation only | hidden | none | +| `chore` | Tooling/maintenance | hidden | none | +| `test` | Adding or fixing tests | hidden | none | +| `ci` | CI configuration | hidden | none | +| `build` | Build system | hidden | none | +| `style` | Formatting, whitespace | hidden | none | + +**Breaking changes:** append `!` after the type (e.g. `feat!: drop Node 20`) or +add a `BREAKING CHANGE:` footer in the PR description. While the CLI is pre-1.0, +`feat` bumps the minor version and breaking changes bump the minor too. + +Examples: + +``` +feat(cloud): add --json output for run results +fix: retry binary upload on transient 5xx +docs: clarify dcd login flow in README +deps: bump @modelcontextprotocol/sdk to 1.x +``` + +## Code style + +- TypeScript, strict mode. Run `pnpm lint` and `pnpm typecheck` before pushing. +- Formatting is handled by Prettier (config in `.prettierrc`); an `.editorconfig` + keeps editors consistent. +- All human-facing CLI output goes through the rendering layer described in + [`STYLE_GUIDE.md`](STYLE_GUIDE.md) — please read it before adding output. Don't + hand-roll layouts or call `console.log` directly. + +## How releases work + +You don't need to do anything for releases — **do not bump the version in +`package.json` or edit `CHANGELOG.md`** in your PR. + +Releases are automated by [release-please](https://github.com/googleapis/release-please): + +- Merges to `dev` accumulate into a **beta** release (published to npm under the + `beta` tag). +- Maintainers promote `dev` → `production` for **stable** releases (npm `latest`). + +release-please reads the Conventional Commit titles of merged PRs to compute the +next version and generate the changelog — which is exactly why the PR title +convention matters. + +## Questions + +- General questions and help: [Discord](https://discord.gg/gm3mJwcNw8). +- Security vulnerabilities: **do not** open an issue — see [SECURITY.md](SECURITY.md). + +Thanks for contributing! 🎉 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e983d13 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 devicecloud.dev + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index a656931..b1acb0c 100644 --- a/README.md +++ b/README.md @@ -92,3 +92,20 @@ A [gitleaks](https://github.com/gitleaks/gitleaks) scan runs in two places, both - **CI** — the `secret-scan` job scans the full history on every push and pull request, and is the enforced backstop regardless of local setup. +## Contributing + +Contributions are welcome! Read **[CONTRIBUTING.md](CONTRIBUTING.md)** for local +setup, our commit/PR conventions (Conventional Commit PR titles, squash-merge), +and how releases work. All contributors sign our +[Contributor License Agreement](CLA.md) — the bot prompts you on your first PR — +and follow our [Code of Conduct](CODE_OF_CONDUCT.md). + +Found a security issue? Please **don't** open a public issue — see +[SECURITY.md](SECURITY.md). + + +## License + +[MIT](LICENSE) © devicecloud.dev + + diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..047affc --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,55 @@ +# Security Policy + +We take the security of the devicecloud.dev CLI (`@devicecloud.dev/dcd`) +seriously. Thank you for helping keep our users safe. + +## Supported Versions + +Security fixes are released against the latest published major version on npm. +Always upgrade to the newest release before reporting: + +```sh-session +$ npm install -g @devicecloud.dev/dcd@latest # npm install +$ dcd upgrade # binary install +``` + +| Version | Supported | +| -------------- | ------------------ | +| Latest `5.x` | :white_check_mark: | +| Older majors | :x: | + +## Reporting a Vulnerability + +**Please do not open a public GitHub issue, pull request, or Discord message for +security vulnerabilities.** Public reports put users at risk before a fix is +available. + +Instead, email **security@devicecloud.dev** with: + +- A description of the vulnerability and its impact. +- Steps to reproduce (a proof of concept is ideal). +- The CLI version (`dcd --version`), OS, and Node.js version where applicable. +- Any suggested remediation, if you have one. + +### What to expect + +- **Acknowledgement** within 3 business days. +- An initial assessment and severity triage within 7 business days. +- Coordinated disclosure: we will work with you on a fix and a disclosure + timeline, and credit you in the release notes if you wish. + +Please give us a reasonable opportunity to remediate before any public +disclosure. + +## Scope + +This policy covers the code in this repository — the `dcd` CLI and the `dcd-mcp` +server. Vulnerabilities in the devicecloud.dev backend or web console should also +be sent to **security@devicecloud.dev** and will be routed to the right team. + +## Secrets + +This repository is scanned for committed secrets by [gitleaks](https://github.com/gitleaks/gitleaks) +on every push and pull request, and via a local pre-commit hook. If you believe +a secret has been committed, email **security@devicecloud.dev** immediately +rather than opening an issue.