@mediamonks/canopy-cli 0.0.1 → 0.2.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.
Files changed (66) hide show
  1. package/dist/api-CyJ-wBZh.mjs +40 -0
  2. package/dist/config-C-z7st1X.mjs +33 -0
  3. package/dist/{db-BBcgT1md.mjs → db-CtUG4vfG.mjs} +3 -3
  4. package/dist/{deploy-BfhAlb91.mjs → deploy-N88l4Kt3.mjs} +7 -6
  5. package/dist/{dev-BB7CwqoI.mjs → dev-DTGW0lm0.mjs} +6 -5
  6. package/dist/dev-D_GlUULk.mjs +2 -0
  7. package/dist/docs/ci.md +48 -0
  8. package/dist/docs/cli.md +67 -0
  9. package/dist/docs/data.md +49 -0
  10. package/dist/docs/deploy.md +50 -0
  11. package/dist/docs/dev.md +44 -0
  12. package/dist/docs/getting-started.md +100 -0
  13. package/dist/docs/troubleshooting.md +61 -0
  14. package/dist/docs-C3aOAx_A.mjs +179 -0
  15. package/dist/index.mjs +26 -16
  16. package/dist/{local-DhufX0eJ.mjs → local-951zc9qJ.mjs} +2 -2
  17. package/dist/{login-DrXKOEmr.mjs → login-Dif9Y32q.mjs} +38 -10
  18. package/dist/{open-DFWvrLFc.mjs → open-xLiGUz_W.mjs} +2 -2
  19. package/dist/package-OcWG7JAW.mjs +4 -0
  20. package/dist/{project-CrrpLEPs.mjs → project-CpiPLNby.mjs} +1 -1
  21. package/dist/projects-DJT_mJDR.mjs +228 -0
  22. package/dist/skill/canopy/SKILL.md +80 -0
  23. package/dist/skill-jbmERP1X.mjs +84 -0
  24. package/dist/templates/spa/.github/workflows/canopy-deploy.yml +34 -0
  25. package/dist/templates/spa/AGENTS.md +43 -0
  26. package/dist/templates/spa/README.md +14 -0
  27. package/dist/templates/spa/_gitignore +4 -0
  28. package/dist/templates/spa/canopy.json +5 -0
  29. package/dist/templates/spa/index.html +12 -0
  30. package/dist/templates/spa/package.json +21 -0
  31. package/dist/templates/spa/src/app.tsx +25 -0
  32. package/dist/templates/spa/src/canopy.ts +5 -0
  33. package/dist/templates/spa/src/main.tsx +10 -0
  34. package/dist/templates/spa/src/style.css +29 -0
  35. package/dist/templates/spa/tsconfig.json +16 -0
  36. package/dist/templates/spa/vite.config.ts +7 -0
  37. package/dist/templates/static/AGENTS.md +41 -0
  38. package/dist/templates/static/README.md +9 -0
  39. package/dist/templates/static/_gitignore +2 -0
  40. package/dist/templates/static/canopy.json +4 -0
  41. package/dist/templates/static/index.html +21 -0
  42. package/dist/templates/static/main.js +9 -0
  43. package/dist/templates/static/style.css +29 -0
  44. package/dist/templates/worker/.github/workflows/canopy-deploy.yml +34 -0
  45. package/dist/templates/worker/AGENTS.md +51 -0
  46. package/dist/templates/worker/README.md +18 -0
  47. package/dist/templates/worker/_gitignore +4 -0
  48. package/dist/templates/worker/canopy.json +6 -0
  49. package/dist/templates/worker/index.html +12 -0
  50. package/dist/templates/worker/package.json +22 -0
  51. package/dist/templates/worker/src/app.tsx +25 -0
  52. package/dist/templates/worker/src/canopy.ts +5 -0
  53. package/dist/templates/worker/src/main.tsx +10 -0
  54. package/dist/templates/worker/src/style.css +29 -0
  55. package/dist/templates/worker/tsconfig.json +16 -0
  56. package/dist/templates/worker/vite.config.ts +7 -0
  57. package/dist/templates/worker/worker/index.ts +29 -0
  58. package/dist/token-rTD9jxPZ.mjs +75 -0
  59. package/dist/ui-C8VuPzGp.mjs +40 -0
  60. package/dist/upgrade-Y8ejvoeg.mjs +99 -0
  61. package/dist/version-check-CoWgQs2h.mjs +128 -0
  62. package/package.json +2 -2
  63. package/dist/api-BEY4O4ap.mjs +0 -36
  64. package/dist/dev-Bvy21srH.mjs +0 -2
  65. package/dist/projects-f_KocDae.mjs +0 -295
  66. package/dist/ui-Cl5P_yQ6.mjs +0 -72
@@ -0,0 +1,40 @@
1
+ import { t as readConfig } from "./config-C-z7st1X.mjs";
2
+ //#region src/api.ts
3
+ /**
4
+ * Authenticated requests to the Canopy control plane. Credentials, in order:
5
+ * CANOPY_DEPLOY_TOKEN (CI — a project-scoped deploy token, docs/02-decisions.md
6
+ * D11), then the CLI token from `canopy login` (~/.canopy/config.json).
7
+ */
8
+ var ApiError = class extends Error {
9
+ status;
10
+ code;
11
+ constructor(status, code, detail) {
12
+ super(detail ? `${code}: ${detail}` : code);
13
+ this.status = status;
14
+ this.code = code;
15
+ }
16
+ };
17
+ async function apiRequest(method, path, body, rawContentType, headers) {
18
+ const config = readConfig();
19
+ const deployToken = process.env["CANOPY_DEPLOY_TOKEN"];
20
+ const token = deployToken || config.token;
21
+ if (!token) throw new Error("Not logged in — run `canopy login` first.");
22
+ const isForm = body instanceof FormData;
23
+ const response = await fetch(`${config.apiUrl}/v1${path}`, {
24
+ method,
25
+ headers: {
26
+ authorization: `Bearer ${token}`,
27
+ ...body === void 0 || isForm ? {} : { "content-type": rawContentType ?? "application/json" },
28
+ ...headers
29
+ },
30
+ body: body === void 0 ? void 0 : isForm ? body : rawContentType !== void 0 ? body : JSON.stringify(body)
31
+ });
32
+ if (!response.ok) {
33
+ const payload = await response.json().catch(() => ({}));
34
+ if (response.status === 401) throw new Error(deployToken ? "Deploy token rejected — it may have been revoked. Create a new one in the dashboard (Settings → Deploy tokens) or with `canopy token create`." : "Session expired — run `canopy login` again.");
35
+ throw new ApiError(response.status, payload.error ?? `http_${response.status}`, payload.detail);
36
+ }
37
+ return await response.json();
38
+ }
39
+ //#endregion
40
+ export { apiRequest as t };
@@ -0,0 +1,33 @@
1
+ import { chmodSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ //#region src/config.ts
5
+ /**
6
+ * CLI config at ~/.canopy/config.json — platform endpoints and the current
7
+ * CLI token. Env overrides: CANOPY_API_URL, CANOPY_OIDC_ISSUER,
8
+ * CANOPY_OIDC_CLIENT_ID.
9
+ */
10
+ const DEFAULT_API_URL = "https://canopy-api.arjan-van-wijk.workers.dev";
11
+ const DEFAULT_ISSUER = "https://s4capital.onelogin.com/oidc/2";
12
+ const DEFAULT_CLI_CLIENT_ID = "b69755d0-6678-013f-b5ce-09fe44a57aa0180501";
13
+ const configDir = join(homedir(), ".canopy");
14
+ const configPath = join(configDir, "config.json");
15
+ function readConfig() {
16
+ let stored = {};
17
+ try {
18
+ stored = JSON.parse(readFileSync(configPath, "utf8"));
19
+ } catch {}
20
+ return {
21
+ ...stored,
22
+ apiUrl: process.env["CANOPY_API_URL"] ?? stored.apiUrl ?? DEFAULT_API_URL,
23
+ issuer: process.env["CANOPY_OIDC_ISSUER"] ?? stored.issuer ?? DEFAULT_ISSUER,
24
+ cliClientId: process.env["CANOPY_OIDC_CLIENT_ID"] ?? stored.cliClientId ?? DEFAULT_CLI_CLIENT_ID
25
+ };
26
+ }
27
+ function writeConfig(config) {
28
+ mkdirSync(configDir, { recursive: true });
29
+ writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`);
30
+ chmodSync(configPath, 384);
31
+ }
32
+ //#endregion
33
+ export { writeConfig as n, readConfig as t };
@@ -1,6 +1,6 @@
1
- import { i as unwrap, n as reportErrors, r as requireTty } from "./ui-Cl5P_yQ6.mjs";
2
- import { t as apiRequest } from "./api-BEY4O4ap.mjs";
3
- import { i as resolveProject, n as projectFlagArgs } from "./project-CrrpLEPs.mjs";
1
+ import { t as apiRequest } from "./api-CyJ-wBZh.mjs";
2
+ import { i as resolveProject, n as projectFlagArgs } from "./project-CpiPLNby.mjs";
3
+ import { i as unwrap, n as reportErrors, r as requireTty } from "./ui-C8VuPzGp.mjs";
4
4
  import { defineCommand } from "citty";
5
5
  import { readFileSync, writeFileSync } from "node:fs";
6
6
  import * as p from "@clack/prompts";
@@ -1,11 +1,11 @@
1
- import { i as unwrap, n as reportErrors } from "./ui-Cl5P_yQ6.mjs";
2
- import { t as apiRequest } from "./api-BEY4O4ap.mjs";
3
- import { a as tryReadCanopyJson, i as resolveProject, n as projectFlagArgs, r as projectUrl, t as projectDirArgs } from "./project-CrrpLEPs.mjs";
1
+ import { t as apiRequest } from "./api-CyJ-wBZh.mjs";
2
+ import { a as tryReadCanopyJson, i as resolveProject, n as projectFlagArgs, r as projectUrl, t as projectDirArgs } from "./project-CpiPLNby.mjs";
3
+ import { i as unwrap, n as reportErrors } from "./ui-C8VuPzGp.mjs";
4
4
  import { defineCommand } from "citty";
5
+ import { spawn } from "node:child_process";
5
6
  import { readFileSync, readdirSync, statSync } from "node:fs";
6
- import * as p from "@clack/prompts";
7
7
  import { join, relative, resolve } from "node:path";
8
- import { spawn } from "node:child_process";
8
+ import * as p from "@clack/prompts";
9
9
  //#region src/deploy.ts
10
10
  /**
11
11
  * canopy deploy — build (optional), bundle the output directory as multipart
@@ -17,6 +17,7 @@ import { spawn } from "node:child_process";
17
17
  */
18
18
  const IGNORED = /* @__PURE__ */ new Set([
19
19
  "canopy.json",
20
+ "AGENTS.md",
20
21
  "CLAUDE.md",
21
22
  "README.md",
22
23
  ".gitignore",
@@ -88,7 +89,7 @@ const deployCommand = defineCommand({
88
89
  spin.start(`Deploying ${paths.length} files (${(total / 1024).toFixed(0)} kB) → ${slug}`);
89
90
  let result;
90
91
  try {
91
- ({deploy: result} = await apiRequest("POST", `/projects/${slug}/deploys`, form));
92
+ ({deploy: result} = await apiRequest("POST", `/projects/${slug}/deploys`, form, void 0, process.env["GITHUB_ACTIONS"] ? { "x-canopy-source": "github-action" } : void 0));
92
93
  } catch (err) {
93
94
  spin.error("Deploy failed.");
94
95
  throw err;
@@ -1,6 +1,7 @@
1
- import { a as readConfig, n as reportErrors } from "./ui-Cl5P_yQ6.mjs";
2
- import { t as apiRequest } from "./api-BEY4O4ap.mjs";
3
- import { i as resolveProject, t as projectDirArgs } from "./project-CrrpLEPs.mjs";
1
+ import { t as readConfig } from "./config-C-z7st1X.mjs";
2
+ import { t as apiRequest } from "./api-CyJ-wBZh.mjs";
3
+ import { i as resolveProject, t as projectDirArgs } from "./project-CpiPLNby.mjs";
4
+ import { n as reportErrors } from "./ui-C8VuPzGp.mjs";
4
5
  import { defineCommand } from "citty";
5
6
  import { join } from "node:path";
6
7
  //#region src/dev.ts
@@ -54,7 +55,7 @@ async function devRemote(flags, slug) {
54
55
  async function devLocal(flags, slug) {
55
56
  let dump;
56
57
  if (flags.pull) {
57
- const { fetchProjectDump } = await import("./local-DhufX0eJ.mjs");
58
+ const { fetchProjectDump } = await import("./local-951zc9qJ.mjs");
58
59
  console.log(`Pulling a fresh export of ${slug}…`);
59
60
  dump = await fetchProjectDump(slug);
60
61
  }
@@ -68,7 +69,7 @@ async function devLocal(flags, slug) {
68
69
  } catch (err) {
69
70
  console.log(`Note: ai/services will be unavailable — could not reach the platform (${err instanceof Error ? err.message : String(err)}).`);
70
71
  }
71
- const { createSandbox } = await import("./local-DhufX0eJ.mjs");
72
+ const { createSandbox } = await import("./local-951zc9qJ.mjs");
72
73
  const sandbox = await createSandbox({
73
74
  slug,
74
75
  persistDir: join(flags.dir, ".canopy", "local"),
@@ -0,0 +1,2 @@
1
+ import { t as devCommand } from "./dev-DTGW0lm0.mjs";
2
+ export { devCommand };
@@ -0,0 +1,48 @@
1
+ ---
2
+ title: CI and deploy tokens
3
+ summary: Push-to-main deploys using a project-scoped deploy token.
4
+ ---
5
+
6
+ # CI and deploy tokens
7
+
8
+ Interactive `canopy login` is for humans at a terminal. For automated deploys
9
+ (GitHub Actions, etc.) use a **deploy token**: a project-scoped credential that
10
+ can deploy that one project and nothing else.
11
+
12
+ ## Create a token
13
+
14
+ From inside the project directory:
15
+
16
+ ```bash
17
+ canopy token create --name "GitHub Actions"
18
+ ```
19
+
20
+ This prints the token **once** — copy it immediately and store it as a CI secret
21
+ (e.g. `CANOPY_DEPLOY_TOKEN`). It is not shown again.
22
+
23
+ Manage tokens:
24
+
25
+ ```bash
26
+ canopy token list
27
+ canopy token revoke <id>
28
+ ```
29
+
30
+ ## Use it in CI
31
+
32
+ The CLI picks up `CANOPY_DEPLOY_TOKEN` from the environment and uses it instead
33
+ of an interactive login. A minimal GitHub Actions step:
34
+
35
+ ```yaml
36
+ - run: npm install -g @mediamonks/canopy-cli
37
+ - run: canopy deploy --build
38
+ env:
39
+ CANOPY_DEPLOY_TOKEN: ${{ secrets.CANOPY_DEPLOY_TOKEN }}
40
+ ```
41
+
42
+ No `canopy login` step is needed — the token is the credential.
43
+
44
+ ## Notes
45
+
46
+ - A deploy token can only deploy its own project. If it strays to another
47
+ project's resources, the platform rejects it.
48
+ - Revoke a token the moment it might be exposed; create a fresh one to replace it.
@@ -0,0 +1,67 @@
1
+ ---
2
+ title: CLI command reference
3
+ summary: Every canopy command, its flags, and what it does.
4
+ ---
5
+
6
+ # CLI command reference
7
+
8
+ Run `canopy <command> --help` for the authoritative flags of any command. This
9
+ is the overview.
10
+
11
+ ## Auth
12
+
13
+ - `canopy login` — sign in via OneLogin (opens the browser; finish there).
14
+ Add `--json` for machine-readable status output (for agents/CI).
15
+ - `canopy whoami` — show the current login and token expiry.
16
+ - `canopy logout` — forget the local CLI token.
17
+
18
+ ## Projects
19
+
20
+ - `canopy create [name]` — create and register a project.
21
+ - `--slug <slug>` — URL slug (defaults to a slugified name).
22
+ - `--template <id>` — `static` | `spa` | `worker` (picker when omitted).
23
+ - `--scaffold` — write `./<slug>/` from the starter template.
24
+ - `canopy projects` — list your projects. `--all` includes ones you can't edit.
25
+ - `canopy delete [slug]` — full teardown of a project. `--yes` skips the
26
+ type-the-slug confirmation.
27
+
28
+ ## Develop
29
+
30
+ - `canopy dev` — run the project locally against live platform data.
31
+ - `--port <port>` — dev server port.
32
+ - `--local` — offline sandbox (Miniflare D1/R2 under `.canopy/local/`).
33
+ - `--pull` — hydrate the sandbox from a fresh prod export first (with `--local`).
34
+
35
+ ## Deploy
36
+
37
+ - `canopy deploy` — build and deploy the project.
38
+ - `--build` — run the `canopy.json` build command first.
39
+ - `canopy rollback [version]` — make an earlier deploy live again, e.g. `v3`
40
+ (picked from history when omitted). `--dir <path>` to target another directory.
41
+ - `canopy open` — open the deployed project in your browser.
42
+
43
+ ## Data
44
+
45
+ - `canopy db pull` — download a fresh SQL dump. `--out <file>` to name it.
46
+ - `canopy db snapshot` — store a dump server-side (restorable anytime).
47
+ - `canopy db snapshots` — list stored snapshots.
48
+ - `canopy db restore [file]` — replace ALL project data from a `.sql` file or
49
+ `--snapshot <key>`. `--yes` skips the confirmation. **Destructive.**
50
+
51
+ ## CI / deploy tokens
52
+
53
+ - `canopy token create` — create a project-scoped deploy token for CI.
54
+ `--name "<label>"` to label it.
55
+ - `canopy token list` — list the project's deploy tokens.
56
+ - `canopy token revoke <id>` — revoke a token.
57
+
58
+ See `canopy docs ci` for wiring push-to-main deploys.
59
+
60
+ ## Maintenance
61
+
62
+ - `canopy upgrade` — update the CLI to the latest version. `--version <v>` pins a
63
+ release; `--pm <npm|pnpm|yarn|bun>` overrides the package-manager guess.
64
+ Upgrading also refreshes the installed Canopy agent skill.
65
+ - `canopy docs [topic]` — list docs, or print one. `--refresh` re-fetches from
66
+ the platform.
67
+ - `canopy skill install` — (re)install the Canopy agent skill into this repo.
@@ -0,0 +1,49 @@
1
+ ---
2
+ title: Working with project data
3
+ summary: Pulling, snapshotting, and restoring your project database.
4
+ ---
5
+
6
+ # Working with project data
7
+
8
+ Each Canopy project gets its own database (D1) and blob storage (R2). Your app
9
+ reads and writes them through the Canopy SDK at runtime; the CLI gives you tools
10
+ to manage the data around it.
11
+
12
+ ## Download a dump
13
+
14
+ ```bash
15
+ canopy db pull # writes <slug>-<timestamp>.sql
16
+ canopy db pull --out data.sql # choose the filename
17
+ ```
18
+
19
+ A plain SQL dump you can inspect, diff, or keep as a backup.
20
+
21
+ ## Snapshots (server-side backups)
22
+
23
+ ```bash
24
+ canopy db snapshot # store a dump on the platform
25
+ canopy db snapshots # list stored snapshots
26
+ ```
27
+
28
+ Snapshots live on the platform and can be restored at any time — handy before a
29
+ risky change.
30
+
31
+ ## Restore — destructive
32
+
33
+ Restoring **replaces ALL project data**:
34
+
35
+ ```bash
36
+ canopy db restore backup.sql # from a local dump
37
+ canopy db restore --snapshot <key> # from a server-side snapshot
38
+ ```
39
+
40
+ You'll be asked to type the project slug to confirm. `--yes` skips that prompt —
41
+ use it only in scripts you trust.
42
+
43
+ ## Safe workflow for agents
44
+
45
+ Before any destructive data change:
46
+
47
+ 1. `canopy db snapshot` — take a restore point.
48
+ 2. Make the change (or test it first with `canopy dev --local --pull`).
49
+ 3. If something goes wrong, `canopy db restore --snapshot <key>`.
@@ -0,0 +1,50 @@
1
+ ---
2
+ title: Deploying a project
3
+ summary: How canopy deploy builds, uploads, and makes a version live.
4
+ ---
5
+
6
+ # Deploying a project
7
+
8
+ From inside a project directory:
9
+
10
+ ```bash
11
+ canopy deploy
12
+ ```
13
+
14
+ This uploads your built assets to the platform, creates a new immutable deploy
15
+ version, and makes it live. Each deploy is versioned (`v1`, `v2`, …).
16
+
17
+ ## Building first
18
+
19
+ If your project needs a build step (React SPA, anything with a bundler), declare
20
+ the build command in `canopy.json` and pass `--build`:
21
+
22
+ ```bash
23
+ canopy deploy --build
24
+ ```
25
+
26
+ `--build` runs the project's configured build command before uploading. Without
27
+ it, `canopy deploy` uploads whatever is already built (or the static files as-is
28
+ for a `static` project).
29
+
30
+ ## Rolling back
31
+
32
+ Every deploy is kept, so you can instantly revert:
33
+
34
+ ```bash
35
+ canopy rollback # pick a version from history
36
+ canopy rollback v3 # make v3 live again
37
+ ```
38
+
39
+ Rollback re-points the live version at an existing deploy — it does not rebuild.
40
+
41
+ ## Seeing the live site
42
+
43
+ ```bash
44
+ canopy open
45
+ ```
46
+
47
+ ## Deploying from CI
48
+
49
+ For automated push-to-main deploys, use a deploy token instead of an interactive
50
+ login — see `canopy docs ci`.
@@ -0,0 +1,44 @@
1
+ ---
2
+ title: Local development
3
+ summary: Running a project locally against live or sandboxed data.
4
+ ---
5
+
6
+ # Local development
7
+
8
+ From inside a project directory:
9
+
10
+ ```bash
11
+ canopy dev
12
+ ```
13
+
14
+ By default `canopy dev` runs your project locally but talks to **live platform
15
+ data** (your project's real database, blobs, and AI). This is the fastest way to
16
+ develop against realistic state.
17
+
18
+ - `--port <port>` — choose the dev-server port.
19
+
20
+ ## Offline sandbox
21
+
22
+ To develop without touching live data — for example on a plane, or before you
23
+ trust a destructive change — use a local sandbox backed by Miniflare:
24
+
25
+ ```bash
26
+ canopy dev --local
27
+ ```
28
+
29
+ This creates local D1 and R2 under `.canopy/local/` in your project. The sandbox
30
+ starts empty.
31
+
32
+ To seed the sandbox from a fresh copy of production data first:
33
+
34
+ ```bash
35
+ canopy dev --local --pull
36
+ ```
37
+
38
+ `.canopy/local/` is disposable — delete it to reset the sandbox.
39
+
40
+ ## Which mode should an agent use?
41
+
42
+ - Iterating on UI or read-only features → `canopy dev` (live data, realistic).
43
+ - Testing writes, migrations, or anything destructive → `canopy dev --local`
44
+ (optionally `--pull` to start from real data).
@@ -0,0 +1,100 @@
1
+ ---
2
+ title: Getting started
3
+ summary: Install the CLI, sign in with OneLogin, and ship your first project.
4
+ ---
5
+
6
+ # Getting started with Canopy
7
+
8
+ Canopy is Monks' managed platform for vibecoded projects. You build a small web
9
+ app, and Canopy hosts it, gives it a database, blob storage, and AI — no
10
+ infrastructure to manage.
11
+
12
+ This guide is written so an AI coding agent (Claude, Cursor, etc.) can follow it
13
+ on your behalf. Everything runs through one command-line tool: `canopy`.
14
+
15
+ ## 1. Install the CLI
16
+
17
+ The CLI is published on npm. Install it globally:
18
+
19
+ ```bash
20
+ npm install -g @mediamonks/canopy-cli
21
+ ```
22
+
23
+ Confirm it's on your PATH:
24
+
25
+ ```bash
26
+ canopy --version
27
+ ```
28
+
29
+ If `npm` isn't available, install Node.js 20+ first (https://nodejs.org), then
30
+ re-run the install.
31
+
32
+ ## 2. Sign in
33
+
34
+ Canopy authenticates through Monks' OneLogin. Run:
35
+
36
+ ```bash
37
+ canopy login
38
+ ```
39
+
40
+ This opens your browser. **Finish the sign-in there** — the CLI waits for the
41
+ browser to redirect back, then stores a token in `~/.canopy/config.json`.
42
+
43
+ > If you are an agent: run `canopy login`, then stop and tell the human to
44
+ > complete the sign-in in the browser window that just opened. Never ask for or
45
+ > type the user's password or any codes yourself.
46
+
47
+ Check who you are at any time:
48
+
49
+ ```bash
50
+ canopy whoami
51
+ ```
52
+
53
+ ## 3. Create a project
54
+
55
+ ```bash
56
+ canopy create
57
+ ```
58
+
59
+ This prompts for a name and a starter template, scaffolds a runnable project
60
+ directory, and registers the project on the platform. To skip the prompts:
61
+
62
+ ```bash
63
+ canopy create "My App" --scaffold --template static
64
+ ```
65
+
66
+ ## 4. Run it locally
67
+
68
+ ```bash
69
+ cd my-app
70
+ canopy dev
71
+ ```
72
+
73
+ Your project runs against live platform data by default. For an offline sandbox
74
+ with local data, use `canopy dev --local`.
75
+
76
+ ## 5. Deploy
77
+
78
+ ```bash
79
+ canopy deploy
80
+ ```
81
+
82
+ Then open the live site:
83
+
84
+ ```bash
85
+ canopy open
86
+ ```
87
+
88
+ ## Where to go next
89
+
90
+ Everything the CLI can do is documented and available offline. List the topics:
91
+
92
+ ```bash
93
+ canopy docs
94
+ ```
95
+
96
+ Read one, e.g.:
97
+
98
+ ```bash
99
+ canopy docs deploy
100
+ ```
@@ -0,0 +1,61 @@
1
+ ---
2
+ title: Troubleshooting
3
+ summary: Common errors and how to resolve them.
4
+ ---
5
+
6
+ # Troubleshooting
7
+
8
+ ## `command not found: canopy`
9
+
10
+ The CLI isn't installed or isn't on your PATH. Install it:
11
+
12
+ ```bash
13
+ npm install -g @mediamonks/canopy-cli
14
+ ```
15
+
16
+ If it installs but still isn't found, your npm global bin directory isn't on your
17
+ PATH. Run `npm bin -g` to find it and add that directory to your PATH.
18
+
19
+ ## `Not logged in — run canopy login`
20
+
21
+ You have no valid CLI token. Run `canopy login` and finish the sign-in in the
22
+ browser. Check status with `canopy whoami`.
23
+
24
+ ## `Session expired — run canopy login again`
25
+
26
+ Your token expired. Just run `canopy login` again.
27
+
28
+ ## The browser didn't open during login
29
+
30
+ `canopy login` prints the sign-in URL as a fallback — open it manually in a
31
+ browser on the **same machine** as the CLI (login uses a local loopback
32
+ redirect, so it must be the same machine).
33
+
34
+ ## `Port 8976 is in use`
35
+
36
+ A previous login attempt is still holding the callback port. Close it (or wait a
37
+ moment) and retry `canopy login`.
38
+
39
+ ## Login hangs and never completes
40
+
41
+ Login only works when the CLI runs on the machine whose browser you're using
42
+ (the redirect goes to `127.0.0.1`). It cannot complete on a remote/headless box.
43
+ Run it on your own laptop.
44
+
45
+ ## `Deploy token rejected`
46
+
47
+ The `CANOPY_DEPLOY_TOKEN` was revoked or is wrong. Create a new one with
48
+ `canopy token create` (or in the dashboard) and update your CI secret.
49
+
50
+ ## Docs are stale
51
+
52
+ `canopy docs` caches the platform's docs. Force a refresh:
53
+
54
+ ```bash
55
+ canopy docs <topic> --refresh
56
+ ```
57
+
58
+ ## Still stuck?
59
+
60
+ Run the failing command again and share its full output. `canopy whoami` and
61
+ `canopy --version` are useful to include.