@mediamonks/canopy-cli 0.5.1 → 0.7.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 (43) hide show
  1. package/dist/{db-BW1ZolWn.mjs → db-BkUmbGgx.mjs} +71 -15
  2. package/dist/{deploy-alC2--pZ.mjs → deploy-BcczXlSQ.mjs} +106 -8
  3. package/dist/dev-CvtoGFW0.mjs +2 -0
  4. package/dist/{dev-CQQhMOoD.mjs → dev-DvyKHe2d.mjs} +44 -14
  5. package/dist/docs/ci.md +1 -3
  6. package/dist/docs/cli.md +3 -4
  7. package/dist/docs/data.md +5 -4
  8. package/dist/docs/deploy.md +16 -4
  9. package/dist/docs/dev.md +13 -11
  10. package/dist/docs/getting-started.md +1 -3
  11. package/dist/docs/infrastructure.md +27 -15
  12. package/dist/docs/migrations.md +183 -0
  13. package/dist/docs/porting-nextjs.md +232 -0
  14. package/dist/docs/sdk-ai.md +103 -0
  15. package/dist/docs/sdk-auth.md +57 -0
  16. package/dist/docs/sdk-database.md +126 -0
  17. package/dist/docs/sdk-files.md +82 -0
  18. package/dist/docs/sdk-services.md +58 -0
  19. package/dist/docs/sdk.md +113 -0
  20. package/dist/docs/staging.md +98 -0
  21. package/dist/docs/static-serving.md +4 -1
  22. package/dist/docs/troubleshooting.md +1 -3
  23. package/dist/{docs-DvSPpSIR.mjs → docs-2cUEug69.mjs} +23 -10
  24. package/dist/index.mjs +22 -20
  25. package/dist/{local-C5-GWJcx.mjs → local-C47tmhl7.mjs} +365 -41
  26. package/dist/{login-BO6abf40.mjs → login-ByD0hcxu.mjs} +5 -3
  27. package/dist/migrations-I1adj0z2.mjs +50 -0
  28. package/dist/{open-DnlYDqrU.mjs → open-DD9oa-Ho.mjs} +11 -4
  29. package/dist/{package-CHoZKzaw.mjs → package-CDB-uxy3.mjs} +1 -1
  30. package/dist/{projects-ijfe7Ffx.mjs → projects-CSH7KsPi.mjs} +17 -9
  31. package/dist/{site-BJjoePQS.mjs → site-BUlQR117.mjs} +14 -1
  32. package/dist/skill/canopy/SKILL.md +24 -1
  33. package/dist/{skill-CW0QSbAJ.mjs → skill-DrWzmUMv.mjs} +2 -2
  34. package/dist/staging-CfF2-pHs.mjs +113 -0
  35. package/dist/templates/spa/AGENTS.md +4 -0
  36. package/dist/templates/static/AGENTS.md +4 -0
  37. package/dist/templates/worker/AGENTS.md +7 -0
  38. package/dist/{token-BeF9zczg.mjs → token-nieJV1w7.mjs} +2 -2
  39. package/dist/{ui-DThlyHgo.mjs → ui-D8HxX0Ng.mjs} +3 -2
  40. package/dist/{upgrade-CGz1yzsW.mjs → upgrade-CH_jHkc7.mjs} +2 -2
  41. package/dist/{usage-DQpH7A3X.mjs → usage-qqPtkDtT.mjs} +2 -2
  42. package/package.json +2 -2
  43. package/dist/dev-BJ5xEwqW.mjs +0 -2
@@ -1,5 +1,5 @@
1
- import { c as tryReadCanopyJson, n as siteConfig, o as projectUrl } from "./site-BJjoePQS.mjs";
2
- import { c as apiRequest, i as unwrap, n as reportErrors, r as requireTty } from "./ui-DThlyHgo.mjs";
1
+ import { n as siteConfig, s as projectUrl, u as tryReadCanopyJson } from "./site-BUlQR117.mjs";
2
+ import { c as apiRequest, i as unwrap, n as reportErrors, r as requireTty } from "./ui-D8HxX0Ng.mjs";
3
3
  import { defineCommand } from "citty";
4
4
  import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
5
5
  import { join, relative, resolve, sep } from "node:path";
@@ -75,7 +75,12 @@ function writeCanopyJson(dir, fields) {
75
75
  writeFileSync(join(dir, "canopy.json"), `${JSON.stringify(next, null, 2)}\n`);
76
76
  }
77
77
  function slugify(input) {
78
- return input.toLowerCase().replaceAll(/[^a-z0-9]+/g, "-").replaceAll(/(^-+|-+$)/g, "").slice(0, 40);
78
+ let slug = input.toLowerCase().replaceAll(/[^a-z0-9]+/g, "-").replaceAll(/(^-+|-+$)/g, "").slice(0, 40);
79
+ while (slug.includes("-dot-")) slug = slug.replaceAll("-dot-", "-");
80
+ return slug;
81
+ }
82
+ function shouldScaffoldCreate(requested, cwd = process.cwd()) {
83
+ return requested ?? !existsSync(join(cwd, "canopy.json"));
79
84
  }
80
85
  const createCommand = defineCommand({
81
86
  meta: {
@@ -98,7 +103,6 @@ const createCommand = defineCommand({
98
103
  },
99
104
  scaffold: {
100
105
  type: "boolean",
101
- default: true,
102
106
  description: "Scaffold ./<slug>/ from the starter template",
103
107
  negativeDescription: "Only register — no files written"
104
108
  }
@@ -118,12 +122,16 @@ const createCommand = defineCommand({
118
122
  message: "Slug",
119
123
  defaultValue: slugify(name),
120
124
  placeholder: slugify(name),
121
- validate: (value) => !value || /^[a-z0-9][a-z0-9-]*$/.test(value) ? void 0 : "Lowercase letters, digits and dashes only."
125
+ validate: (value) => {
126
+ if (value && !/^[a-z0-9][a-z0-9-]*$/.test(value)) return "Lowercase letters, digits and dashes only.";
127
+ if (value?.includes("-dot-")) return `"-dot-" is reserved for preview hostnames.`;
128
+ }
122
129
  })).trim();
123
130
  slug ||= slugify(name);
131
+ const scaffold = shouldScaffoldCreate(args.scaffold);
124
132
  let template = TEMPLATES.find((t) => t.id === (args.template ?? "static"));
125
133
  if (!template) throw new Error(`Unknown template "${args.template}" — available: ${TEMPLATES.map((t) => t.id).join(", ")}.`);
126
- if (args.scaffold && !args.template && process.stdin.isTTY) {
134
+ if (scaffold && !args.template && process.stdin.isTTY) {
127
135
  const id = unwrap(await p.select({
128
136
  message: "Template",
129
137
  options: TEMPLATES.filter((t) => !t.hidden).map((t) => ({
@@ -136,7 +144,7 @@ const createCommand = defineCommand({
136
144
  }
137
145
  if (template.hidden) p.log.warn("Per-project Workers are not deployable yet (Phase 2) — `canopy deploy` publishes the frontend only for now.");
138
146
  const targetDir = resolve(slug);
139
- if (args.scaffold && existsSync(targetDir)) throw new Error(`Directory ./${slug} already exists — remove it, or use --no-scaffold to only register.`);
147
+ if (scaffold && existsSync(targetDir)) throw new Error(`Directory ./${slug} already exists — remove it, or use --no-scaffold to only register.`);
140
148
  const spin = p.spinner();
141
149
  spin.start(`Registering ${slug}…`);
142
150
  let project;
@@ -150,7 +158,7 @@ const createCommand = defineCommand({
150
158
  throw err;
151
159
  }
152
160
  spin.stop(`Created ${project.name} — ${projectUrl(project.slug)}`);
153
- if (args.scaffold) {
161
+ if (scaffold) {
154
162
  scaffoldTemplate(template.id, targetDir, {
155
163
  name,
156
164
  slug
@@ -166,7 +174,7 @@ const createCommand = defineCommand({
166
174
  ];
167
175
  p.note(steps.join("\n"), `Scaffolded ./${slug}/ (${template.id}) — next`);
168
176
  p.outro(`Live URL (after first deploy): ${projectUrl(project.slug)}`);
169
- } else p.outro("Registered without scaffolding — add a canopy.json to deploy an existing app.");
177
+ } else p.outro(existsSync(join(process.cwd(), "canopy.json")) ? "Registered without scaffolding — the existing canopy.json was left unchanged." : "Registered without scaffolding — add a canopy.json to deploy an existing app.");
170
178
  })
171
179
  });
172
180
  /** Empty enough to scaffold into: missing, or holding only dotfiles (.git, .agents…). */
@@ -175,6 +175,12 @@ function projectUrl(slug) {
175
175
  if (apiHost === "run.app" || apiHost.endsWith(".run.app") || apiHost.startsWith("api.")) throw new Error("Cannot derive the project URL. Set projectDomain (baked profile or CANOPY_PROJECT_DOMAIN).");
176
176
  return `https://${slug}.${apiHost.split(".").slice(-2).join(".")}`;
177
177
  }
178
+ /** The staging channel's URL (docs/14): the first label becomes `staging-dot-<slug>`. */
179
+ function stagingUrl(slug) {
180
+ const url = new URL(projectUrl(slug));
181
+ url.hostname = `staging-dot-${url.hostname}`;
182
+ return url.origin;
183
+ }
178
184
  /** canopy.json parsed if present; undefined when the file is missing. */
179
185
  function tryReadCanopyJson(dir) {
180
186
  let raw;
@@ -185,6 +191,13 @@ function tryReadCanopyJson(dir) {
185
191
  }
186
192
  return JSON.parse(raw);
187
193
  }
194
+ /** The validated dialect lock from canopy.json, if the project set one. */
195
+ function projectDialect(dir) {
196
+ const dialect = tryReadCanopyJson(dir)?.dialect;
197
+ if (dialect === void 0) return void 0;
198
+ if (dialect !== "sqlite" && dialect !== "postgres") throw new Error(`canopy.json "dialect" must be "sqlite" or "postgres", not ${JSON.stringify(dialect)}.`);
199
+ return dialect;
200
+ }
188
201
  function readCanopyJson(dir) {
189
202
  const config = tryReadCanopyJson(dir);
190
203
  if (config === void 0) throw new Error(`No canopy.json in ${dir} — run from a project created by \`canopy create\`, add one ({"slug": "<slug>", "dist": "dist"}), or pass --project <slug>.`);
@@ -251,4 +264,4 @@ function siteHeaderLine(cliVersion) {
251
264
  return `canopy ${cliVersion} · ${c.envOverride || !c.profileId ? c.apiUrl : `${c.profileId} (${c.projectDomain ?? new URL(c.apiUrl).hostname})`}`;
252
265
  }
253
266
  //#endregion
254
- export { projectFlagArgs as a, tryReadCanopyJson as c, readConfigFile as d, setActiveProfile as f, isProfileId as g, getBakedProfile as h, projectDirArgs as i, clearAllProfileTokens as l, writeConfigFile as m, siteConfig as n, projectUrl as o, upsertProfileAuth as p, siteHeaderLine as r, resolveProject as s, setInvocationProfile as t, listBakedProfiles as u };
267
+ export { getBakedProfile as _, projectDirArgs as a, resolveProject as c, clearAllProfileTokens as d, listBakedProfiles as f, writeConfigFile as g, upsertProfileAuth as h, projectDialect as i, stagingUrl as l, setActiveProfile as m, siteConfig as n, projectFlagArgs as o, readConfigFile as p, siteHeaderLine as r, projectUrl as s, setInvocationProfile as t, tryReadCanopyJson as u, isProfileId as v };
@@ -89,11 +89,34 @@ truth and never go stale.
89
89
  current directory; add `--no-scaffold` to link an app you already have.
90
90
  - Run locally: `canopy dev` (live data) or `canopy dev --local` (offline sandbox)
91
91
  - Deploy: `canopy deploy` (add `--build` if the project has a build step)
92
+ - Test first on staging: `canopy deploy --staging` → verify → `canopy promote`
93
+ (own database cloned from live; `canopy staging status | sync | destroy`)
92
94
  - Roll back: `canopy rollback`
93
95
  - Open the live site: `canopy open`
94
- - Manage data: `canopy db pull | snapshot | snapshots | restore`
96
+ - Manage data: `canopy db pull | snapshot | snapshots | restore | migrate`
95
97
  - CI credentials: `canopy token create | list | revoke`
96
98
 
99
+ ## Custom tables & migrations (devs; Drizzle recommended)
100
+
101
+ The document API (`canopy.db.collection(…)`) needs no schema — prefer it. When
102
+ a project defines its **own tables** (raw `canopy.db.sql()` / Drizzle), use the
103
+ migrations flow — read `canopy docs migrations` first. The rules that prevent
104
+ confusing failures:
105
+
106
+ - Pin `"dialect"` and `"migrations"` in `canopy.json`; put ordered `.sql`
107
+ files in that directory (Drizzle: `npx drizzle-kit generate` writes them).
108
+ - **There is no `DATABASE_URL` and never will be.** Never run
109
+ `drizzle-kit push`/`migrate`/`studio` or Drizzle's runtime `migrate()` —
110
+ generating is local, applying is Canopy's job: `canopy deploy` applies
111
+ pending migrations automatically (`canopy db migrate` applies without a
112
+ deploy; `canopy dev --local` applies to the sandbox on boot).
113
+ - Never edit an applied migration (the platform refuses edited history) and
114
+ never reference `_canopy_*` tables.
115
+ - **Schema change? Rehearse it on staging.** `canopy deploy --staging` applies
116
+ pending migrations to the staging database (a clone of live) — verify the
117
+ app there, then `canopy promote` replays them against live and flips the
118
+ version. Never promote with failing checks.
119
+
97
120
  ## Choosing a starter template (`canopy create` / `canopy init`)
98
121
 
99
122
  Both `canopy create` and `canopy init` scaffold from the same three templates.
@@ -1,5 +1,5 @@
1
- import { t as version } from "./package-CHoZKzaw.mjs";
2
- import { n as reportErrors } from "./ui-DThlyHgo.mjs";
1
+ import { t as version } from "./package-CDB-uxy3.mjs";
2
+ import { n as reportErrors } from "./ui-D8HxX0Ng.mjs";
3
3
  import { defineCommand } from "citty";
4
4
  import { cpSync, existsSync, mkdirSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
5
5
  import { join, relative } from "node:path";
@@ -0,0 +1,113 @@
1
+ import { c as resolveProject, l as stagingUrl, o as projectFlagArgs, s as projectUrl } from "./site-BUlQR117.mjs";
2
+ import { c as apiRequest, i as unwrap, l as withContext, n as reportErrors, r as requireTty } from "./ui-D8HxX0Ng.mjs";
3
+ import { defineCommand } from "citty";
4
+ import * as p from "@clack/prompts";
5
+ //#region src/staging.ts
6
+ /**
7
+ * canopy staging status | sync | destroy — the project's staging channel
8
+ * (docs/14): its own database (a clone of live), blob prefix and backend
9
+ * worker, served at staging-dot-<slug>.<domain>. Created lazily by
10
+ * `canopy deploy --staging`; promoted with `canopy promote`.
11
+ */
12
+ const fetchStatus = (slug) => apiRequest("GET", `/projects/${slug}/staging`);
13
+ const stagingCommand = defineCommand({
14
+ meta: {
15
+ name: "staging",
16
+ description: "Staging channel: status, sync, destroy"
17
+ },
18
+ subCommands: {
19
+ status: defineCommand({
20
+ meta: {
21
+ name: "status",
22
+ description: "Show the staging channel's state"
23
+ },
24
+ args: projectFlagArgs,
25
+ run: reportErrors("staging status", async ({ args }) => {
26
+ const { slug } = resolveProject(args);
27
+ const { staging } = await fetchStatus(slug);
28
+ if (!staging.provisioned) {
29
+ console.log(`No staging channel for ${slug} — create one with \`canopy deploy --staging\`.`);
30
+ return;
31
+ }
32
+ console.log(`Staging: ${stagingUrl(slug)}`);
33
+ console.log(` staged v${staging.version ?? "— (nothing deployed yet)"}` + (staging.hasWorker ? " (with backend)" : ""));
34
+ console.log(` live v${staging.live ?? "—"} ${projectUrl(slug)}`);
35
+ if (staging.version !== null && staging.version !== staging.live) console.log(` \`canopy promote\` makes v${staging.version} live`);
36
+ })
37
+ }),
38
+ sync: defineCommand({
39
+ meta: {
40
+ name: "sync",
41
+ description: "Re-clone the live database into staging (staging data is replaced)"
42
+ },
43
+ args: {
44
+ ...projectFlagArgs,
45
+ yes: {
46
+ type: "boolean",
47
+ default: false,
48
+ description: "Skip the confirmation prompt"
49
+ }
50
+ },
51
+ run: reportErrors("staging sync", async ({ args }) => {
52
+ const { slug } = resolveProject(args);
53
+ if (!args.yes) {
54
+ requireTty("pass --yes to sync without confirmation.");
55
+ if (!unwrap(await p.confirm({ message: `Replace "${slug}"'s STAGING data with a fresh copy of live?` }))) {
56
+ p.cancel("Aborted.");
57
+ return;
58
+ }
59
+ }
60
+ const spin = p.spinner();
61
+ spin.start(`Cloning live → staging for ${slug}…`);
62
+ try {
63
+ await withContext(apiRequest("POST", `/projects/${slug}/staging/sync`), {
64
+ action: `sync staging for "${slug}"`,
65
+ fixes: { staging_not_provisioned: "This project has no staging channel yet — `canopy deploy --staging` creates one (already cloned from live)." }
66
+ });
67
+ } catch (err) {
68
+ spin.error("Sync failed.");
69
+ throw err;
70
+ }
71
+ spin.stop(`Staging database now matches live for ${slug}.`);
72
+ })
73
+ }),
74
+ destroy: defineCommand({
75
+ meta: {
76
+ name: "destroy",
77
+ description: "Tear the staging channel down (database, files, backend — live is untouched)"
78
+ },
79
+ args: {
80
+ ...projectFlagArgs,
81
+ yes: {
82
+ type: "boolean",
83
+ default: false,
84
+ description: "Skip the type-the-slug confirmation"
85
+ }
86
+ },
87
+ run: reportErrors("staging destroy", async ({ args }) => {
88
+ const { slug } = resolveProject(args);
89
+ if (!args.yes) {
90
+ requireTty("pass --yes to destroy without confirmation.");
91
+ if (unwrap(await p.text({ message: `This deletes "${slug}"'s staging database, files and backend (live is untouched). Type the slug to confirm.` })).trim() !== slug) {
92
+ p.cancel("Aborted.");
93
+ return;
94
+ }
95
+ }
96
+ const spin = p.spinner();
97
+ spin.start(`Destroying staging for ${slug}…`);
98
+ try {
99
+ await withContext(apiRequest("DELETE", `/projects/${slug}/staging`), {
100
+ action: `destroy staging for "${slug}"`,
101
+ fixes: { staging_not_provisioned: "This project has no staging channel." }
102
+ });
103
+ } catch (err) {
104
+ spin.error("Destroy failed.");
105
+ throw err;
106
+ }
107
+ spin.stop(`Staging channel removed for ${slug}. \`canopy deploy --staging\` recreates it.`);
108
+ })
109
+ })
110
+ }
111
+ });
112
+ //#endregion
113
+ export { stagingCommand };
@@ -30,6 +30,10 @@ the [Canopy dashboard](https://dashboard.thanarie.dev).
30
30
  writes never reach the platform. Prefer it for destructive experiments.
31
31
  - `canopy deploy` — builds (`npm run build`) and publishes `dist/`; live
32
32
  (behind company login) at https://{{slug}}.thanarie.dev.
33
+ - Risky change (schema migration, backend rework)? `canopy deploy --staging`
34
+ first — a private copy with its own database cloned from live — verify, then
35
+ `canopy promote` ships the exact tested version. Never promote with failing
36
+ checks.
33
37
 
34
38
  ## Boundaries
35
39
 
@@ -29,6 +29,10 @@ the [Canopy dashboard](https://dashboard.thanarie.dev).
29
29
  writes never reach the platform. Prefer it for destructive experiments.
30
30
  - `canopy deploy` — publish; live (behind company login) at
31
31
  https://{{slug}}.thanarie.dev.
32
+ - Risky change (schema migration, backend rework)? `canopy deploy --staging`
33
+ first — a private copy with its own database cloned from live — verify, then
34
+ `canopy promote` ships the exact tested version. Never promote with failing
35
+ checks.
32
36
 
33
37
  ## Boundaries
34
38
 
@@ -39,6 +39,13 @@ the [Canopy dashboard](https://dashboard.thanarie.dev).
39
39
  writes never reach the platform. Prefer it for destructive experiments.
40
40
  - `canopy deploy` — builds (`npm run build`) and publishes; live (behind
41
41
  company login) at https://{{slug}}.thanarie.dev.
42
+ - Defining your own tables (raw `sql()` / Drizzle)? Use the migrations flow —
43
+ `canopy docs migrations`. Never invent a `DATABASE_URL` (none exists):
44
+ generate migrations locally, and `canopy deploy` applies them.
45
+ - Risky change (schema migration, backend rework)? `canopy deploy --staging`
46
+ first — a private copy with its own database cloned from live — verify, then
47
+ `canopy promote` ships the exact tested version. Never promote with failing
48
+ checks.
42
49
 
43
50
  ## Boundaries
44
51
 
@@ -1,5 +1,5 @@
1
- import { a as projectFlagArgs, i as projectDirArgs, s as resolveProject } from "./site-BJjoePQS.mjs";
2
- import { c as apiRequest, n as reportErrors } from "./ui-DThlyHgo.mjs";
1
+ import { a as projectDirArgs, c as resolveProject, o as projectFlagArgs } from "./site-BUlQR117.mjs";
2
+ import { c as apiRequest, n as reportErrors } from "./ui-D8HxX0Ng.mjs";
3
3
  import { defineCommand } from "citty";
4
4
  const tokenCommand = defineCommand({
5
5
  meta: {
@@ -1,4 +1,4 @@
1
- import { n as siteConfig } from "./site-BJjoePQS.mjs";
1
+ import { n as siteConfig } from "./site-BUlQR117.mjs";
2
2
  import { spawn } from "node:child_process";
3
3
  import { cancel, isCancel } from "@clack/prompts";
4
4
  //#region src/api.ts
@@ -211,13 +211,14 @@ async function apiDownload(path) {
211
211
  * unscoped; the target project rides as X-Canopy-Project and the api. gateway
212
212
  * re-vouches it (docs/10-cli-sites.md D17).
213
213
  */
214
- async function apiDataRequest(method, path, projectSlug, body, rawContentType) {
214
+ async function apiDataRequest(method, path, projectSlug, body, rawContentType, channel) {
215
215
  const { apiUrl, token, isDeployToken } = credentials();
216
216
  const response = await fetch(`${apiUrl}/data/v1${path}`, {
217
217
  method,
218
218
  headers: {
219
219
  authorization: `Bearer ${token}`,
220
220
  "x-canopy-project": projectSlug,
221
+ ...channel === "staging" ? { "x-canopy-channel": "staging" } : {},
221
222
  ...body === void 0 ? {} : { "content-type": rawContentType ?? "application/json" }
222
223
  },
223
224
  body: body === void 0 ? void 0 : rawContentType !== void 0 ? body : JSON.stringify(body)
@@ -1,5 +1,5 @@
1
1
  import { t as PACKAGE_NAME } from "./version-check-Cuh6HaLX.mjs";
2
- import { n as reportErrors } from "./ui-DThlyHgo.mjs";
2
+ import { n as reportErrors } from "./ui-D8HxX0Ng.mjs";
3
3
  import { defineCommand } from "citty";
4
4
  import { spawn } from "node:child_process";
5
5
  import { fileURLToPath } from "node:url";
@@ -112,7 +112,7 @@ const upgradeCommand = defineCommand({
112
112
  const spec = `${PACKAGE_NAME}@${args.version ?? "latest"}`;
113
113
  const command = pmCommand(pm);
114
114
  const cmd = installArgs(pm, spec);
115
- const { skillInstalled } = await import("./skill-CW0QSbAJ.mjs");
115
+ const { skillInstalled } = await import("./skill-DrWzmUMv.mjs");
116
116
  const refreshSkill = skillInstalled(process.cwd());
117
117
  console.log(`Upgrading via ${command}: ${command} ${cmd.join(" ")}`);
118
118
  await run(command, cmd);
@@ -1,5 +1,5 @@
1
- import { a as projectFlagArgs, s as resolveProject } from "./site-BJjoePQS.mjs";
2
- import { c as apiRequest, l as withContext, n as reportErrors } from "./ui-DThlyHgo.mjs";
1
+ import { c as resolveProject, o as projectFlagArgs } from "./site-BUlQR117.mjs";
2
+ import { c as apiRequest, l as withContext, n as reportErrors } from "./ui-D8HxX0Ng.mjs";
3
3
  import { defineCommand } from "citty";
4
4
  //#region src/usage.ts
5
5
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mediamonks/canopy-cli",
3
- "version": "0.5.1",
3
+ "version": "0.7.0",
4
4
  "description": "Canopy CLI — create, develop and deploy Canopy projects.",
5
5
  "bin": {
6
6
  "canopy": "./dist/index.mjs"
@@ -21,7 +21,7 @@
21
21
  "hono": "^4.8.0",
22
22
  "vite-server": "npm:vite@^7",
23
23
  "@mediamonks/canopy": "0.0.3",
24
- "@mediamonks/canopy-data-plane": "0.0.1"
24
+ "@mediamonks/canopy-data-plane": "0.0.2"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@types/node": "^26.1.1",
@@ -1,2 +0,0 @@
1
- import { t as devCommand } from "./dev-CQQhMOoD.mjs";
2
- export { devCommand };