@mediamonks/canopy-cli 0.7.43 → 0.7.44

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 (38) hide show
  1. package/dist/{browse-dyOThTyf.mjs → browse-B8-0dweq.mjs} +1 -1
  2. package/dist/dev-CUJKgaqJ.mjs +2 -0
  3. package/dist/{dev-adLLSY1F.mjs → dev-Cq98yblV.mjs} +95 -13
  4. package/dist/{dev-worker-DJekKSdb.mjs → dev-worker-CcYwQjxz.mjs} +23 -10
  5. package/dist/docs/agent-browsing.md +2 -2
  6. package/dist/docs/agent-tools.md +2 -2
  7. package/dist/docs/ci.md +1 -1
  8. package/dist/docs/cli-browse.md +1 -1
  9. package/dist/docs/cli-dev.md +1 -0
  10. package/dist/docs/cli-mcp.md +1 -1
  11. package/dist/docs/cli-members.md +41 -0
  12. package/dist/docs/cli-roles.md +39 -0
  13. package/dist/docs/cli-token.md +1 -1
  14. package/dist/docs/index.json +16 -1
  15. package/dist/docs/overview-faq.md +6 -4
  16. package/dist/docs/overview-how-it-works.md +3 -2
  17. package/dist/docs/overview-use-cases.md +1 -1
  18. package/dist/docs/overview-what-is-canopy.md +1 -1
  19. package/dist/docs/platform-client-access.md +1 -1
  20. package/dist/docs/platform-members-and-access.md +66 -42
  21. package/dist/docs/roles.md +100 -0
  22. package/dist/docs/sdk-auth.md +24 -10
  23. package/dist/docs/sdk-realtime.md +1 -1
  24. package/dist/docs/static-serving.md +1 -1
  25. package/dist/{docs-CaAgJWK3.mjs → docs-KmN6jD1S.mjs} +1 -1
  26. package/dist/{feedback-CMnG2Zvs.mjs → feedback-B5-95neo.mjs} +1 -1
  27. package/dist/index.mjs +10 -8
  28. package/dist/{local-2xtxtoUd.mjs → local-CIkL7tXP.mjs} +4 -3
  29. package/dist/{mcp-BVIU4j9N.mjs → mcp-DZdMNTWr.mjs} +2 -2
  30. package/dist/{package-XOtqboS1.mjs → package-Bvly8-rB.mjs} +1 -1
  31. package/dist/roles-BDZaN3vi.mjs +2 -0
  32. package/dist/roles-UM0Iiws6.mjs +379 -0
  33. package/dist/skill/canopy/SKILL.md +9 -0
  34. package/dist/{skill-Ct-aCOzg.mjs → skill-DRLniv-I.mjs} +1 -1
  35. package/dist/{src-CScXotBB.mjs → src-8vxOBOxW.mjs} +38 -3
  36. package/dist/{upgrade-DJogeXAF.mjs → upgrade-D_yrD7zp.mjs} +1 -1
  37. package/package.json +2 -2
  38. package/dist/dev-BmI5kwoG.mjs +0 -2
@@ -0,0 +1,379 @@
1
+ import { l as resolveProject, o as projectDirArgs } from "./site-0i7wAJqg.mjs";
2
+ import { a as apiRequest, f as withContext } from "./api-Bl6SG8Oq.mjs";
3
+ import { r as reportErrors } from "./ui-CLnICOne.mjs";
4
+ import { defineCommand } from "citty";
5
+ //#region src/roles.ts
6
+ /**
7
+ * canopy roles / canopy members — a project's app roles and its roster from
8
+ * the terminal (OpenSpec project-roles), so an agent can look up the real
9
+ * role slugs before it writes `roles.includes(...)`, and set people up
10
+ * without the dashboard.
11
+ *
12
+ * Canopy roles (owner / editor / viewer) decide who may manage the project
13
+ * and, when it is members-only, who may open it. App roles are the project's
14
+ * own labels, delivered to the app as `roles` and never enforced by Canopy.
15
+ */
16
+ const ROLE_FIXES = {
17
+ not_found: "The project or role doesn't exist, or you can't manage this project — only its owner and editors can.",
18
+ invalid_role_slug: "Slugs are 1–32 lowercase letters, digits and dashes, starting with a letter. Pass one with --slug.",
19
+ role_exists: "That slug is taken on this project — `canopy roles list` shows them.",
20
+ too_many_roles: "A project has at most 20 app roles — remove one first.",
21
+ default_role: "Make another role the default first (`canopy roles default <slug>`), then remove this one.",
22
+ unknown_role: "Use a slug from `canopy roles list`, or create it with `canopy roles add`."
23
+ };
24
+ /** One line per role, default marked — what `canopy roles list` prints. */
25
+ function formatRoles(roles) {
26
+ if (roles.length === 0) return [];
27
+ const width = Math.max(...roles.map((r) => r.slug.length));
28
+ return roles.map((r) => `${r.slug.padEnd(width)} ${r.name}${r.default ? " (default)" : ""}`);
29
+ }
30
+ /** One line per person on the roster — what `canopy members list` prints. */
31
+ function formatRoster(members, invites) {
32
+ const rows = [...members.map((m) => ({
33
+ who: m.email,
34
+ role: m.role,
35
+ apps: m.app_roles,
36
+ note: ""
37
+ })), ...invites.map((i) => ({
38
+ who: i.email,
39
+ role: i.role,
40
+ apps: i.app_roles,
41
+ note: " (invited, not signed in yet)"
42
+ }))];
43
+ if (rows.length === 0) return [];
44
+ const whoWidth = Math.max(...rows.map((r) => r.who.length));
45
+ const roleWidth = Math.max(...rows.map((r) => r.role.length));
46
+ return rows.map((r) => `${r.who.padEnd(whoWidth)} ${r.role.padEnd(roleWidth)} ${r.apps.length > 0 ? r.apps.join(", ") : "-"}${r.note}`);
47
+ }
48
+ /** `--app-role a --app-role b,c` → ["a", "b", "c"]; undefined when the flag is absent. */
49
+ function parseAppRoleFlag(value) {
50
+ if (value === void 0) return void 0;
51
+ const list = (Array.isArray(value) ? value : [value]).flatMap((v) => v.split(",")).map((v) => v.trim()).filter(Boolean);
52
+ return [...new Set(list)];
53
+ }
54
+ /** The Canopy role named by `--editor` / `--viewer`, refusing both at once. */
55
+ function canopyRoleFlag(args) {
56
+ if (args.editor && args.viewer) throw new Error("Pass --editor or --viewer, not both.");
57
+ if (args.viewer) return "viewer";
58
+ if (args.editor) return "editor";
59
+ }
60
+ const appRoleArg = { "app-role": {
61
+ type: "string",
62
+ description: "An app role slug to give them (repeatable, or comma-separated)"
63
+ } };
64
+ /** citty hands a repeated string flag over as an array at runtime. */
65
+ const appRolesOf = (args) => parseAppRoleFlag(args["app-role"]);
66
+ const rolesCommand = defineCommand({
67
+ meta: {
68
+ name: "roles",
69
+ description: "Manage the project's app roles (list / add / rename / default / remove)"
70
+ },
71
+ subCommands: {
72
+ list: defineCommand({
73
+ meta: {
74
+ name: "list",
75
+ description: "List the project's app roles (the default is marked)"
76
+ },
77
+ args: {
78
+ ...projectDirArgs,
79
+ json: {
80
+ type: "boolean",
81
+ default: false,
82
+ description: "Print the roles as JSON"
83
+ }
84
+ },
85
+ run: reportErrors("roles list", async ({ args }) => {
86
+ const { slug } = resolveProject(args);
87
+ const { roles } = await withContext(apiRequest("GET", `/projects/${slug}/roles`), {
88
+ action: `list app roles of ${slug}`,
89
+ fixes: ROLE_FIXES
90
+ });
91
+ if (args.json) {
92
+ console.log(JSON.stringify({ roles }, null, 2));
93
+ return;
94
+ }
95
+ if (roles.length === 0) {
96
+ console.log(`${slug} has no app roles — add one with \`canopy roles add "Approver"\`.`);
97
+ return;
98
+ }
99
+ for (const line of formatRoles(roles)) console.log(line);
100
+ })
101
+ }),
102
+ add: defineCommand({
103
+ meta: {
104
+ name: "add",
105
+ description: "Create an app role (the first one becomes the default)"
106
+ },
107
+ args: {
108
+ name: {
109
+ type: "positional",
110
+ description: "Display name, e.g. \"Approver\"",
111
+ required: true
112
+ },
113
+ slug: {
114
+ type: "string",
115
+ description: "The slug your code checks (default: derived from the name; never changes)"
116
+ },
117
+ ...projectDirArgs
118
+ },
119
+ run: reportErrors("roles add", async ({ args }) => {
120
+ const { slug } = resolveProject(args);
121
+ const { role } = await withContext(apiRequest("POST", `/projects/${slug}/roles`, {
122
+ name: args.name,
123
+ ...args.slug && { slug: args.slug }
124
+ }), {
125
+ action: `add app role "${args.name}" to ${slug}`,
126
+ fixes: ROLE_FIXES
127
+ });
128
+ console.log(`Added ${role.slug} ("${role.name}")${role.default ? " — the default role, so every visitor has it" : ""}.`);
129
+ })
130
+ }),
131
+ rename: defineCommand({
132
+ meta: {
133
+ name: "rename",
134
+ description: "Change an app role's display name (the slug stays)"
135
+ },
136
+ args: {
137
+ role: {
138
+ type: "positional",
139
+ description: "Role slug",
140
+ required: true
141
+ },
142
+ name: {
143
+ type: "positional",
144
+ description: "New display name",
145
+ required: true
146
+ },
147
+ ...projectDirArgs
148
+ },
149
+ run: reportErrors("roles rename", async ({ args }) => {
150
+ const { slug } = resolveProject(args);
151
+ await withContext(apiRequest("PATCH", `/projects/${slug}/roles/${args.role}`, { name: args.name }), {
152
+ action: `rename app role ${args.role} on ${slug}`,
153
+ fixes: ROLE_FIXES
154
+ });
155
+ console.log(`Renamed ${args.role} to "${args.name}".`);
156
+ })
157
+ }),
158
+ default: defineCommand({
159
+ meta: {
160
+ name: "default",
161
+ description: "Make an app role the default — every visitor gets it on top of their own"
162
+ },
163
+ args: {
164
+ role: {
165
+ type: "positional",
166
+ description: "Role slug",
167
+ required: true
168
+ },
169
+ ...projectDirArgs
170
+ },
171
+ run: reportErrors("roles default", async ({ args }) => {
172
+ const { slug } = resolveProject(args);
173
+ await withContext(apiRequest("PATCH", `/projects/${slug}/roles/${args.role}`, { default: true }), {
174
+ action: `make ${args.role} the default on ${slug}`,
175
+ fixes: ROLE_FIXES
176
+ });
177
+ console.log(`${args.role} is now the default role on ${slug}.`);
178
+ })
179
+ }),
180
+ remove: defineCommand({
181
+ meta: {
182
+ name: "remove",
183
+ description: "Delete an app role and take it away from everyone"
184
+ },
185
+ args: {
186
+ role: {
187
+ type: "positional",
188
+ description: "Role slug",
189
+ required: true
190
+ },
191
+ ...projectDirArgs
192
+ },
193
+ run: reportErrors("roles remove", async ({ args }) => {
194
+ const { slug } = resolveProject(args);
195
+ await withContext(apiRequest("DELETE", `/projects/${slug}/roles/${args.role}`), {
196
+ action: `remove app role ${args.role} from ${slug}`,
197
+ fixes: ROLE_FIXES
198
+ });
199
+ console.log(`Removed ${args.role} from ${slug}.`);
200
+ })
201
+ })
202
+ }
203
+ });
204
+ const MEMBER_FIXES = {
205
+ ...ROLE_FIXES,
206
+ not_found: "No such person on the project, or you can't manage it — only the owner adds and removes people.",
207
+ forbidden: "Only the project's owner changes who is an editor or a viewer.",
208
+ already_member: "They're already on the project — change them with `canopy members set`.",
209
+ already_invited: "They already have a pending invite — change it with `canopy members set`.",
210
+ email_domain_not_allowed: "Only colleagues who can sign in to Canopy can be added.",
211
+ cannot_change_owner: "The owner's role is fixed.",
212
+ cannot_remove_owner: "The owner can't be removed — delete the project instead."
213
+ };
214
+ const roster = (slug) => withContext(apiRequest("GET", `/projects/${slug}/members`), {
215
+ action: `read the members of ${slug}`,
216
+ fixes: MEMBER_FIXES
217
+ });
218
+ const membersCommand = defineCommand({
219
+ meta: {
220
+ name: "members",
221
+ description: "Manage who is on the project and their roles (list / add / set / remove)"
222
+ },
223
+ subCommands: {
224
+ list: defineCommand({
225
+ meta: {
226
+ name: "list",
227
+ description: "List members and pending invites with their roles"
228
+ },
229
+ args: {
230
+ ...projectDirArgs,
231
+ json: {
232
+ type: "boolean",
233
+ default: false,
234
+ description: "Print the roster as JSON"
235
+ }
236
+ },
237
+ run: reportErrors("members list", async ({ args }) => {
238
+ const { slug } = resolveProject(args);
239
+ const { members, invites } = await roster(slug);
240
+ if (args.json) {
241
+ console.log(JSON.stringify({
242
+ members,
243
+ invites
244
+ }, null, 2));
245
+ return;
246
+ }
247
+ for (const line of formatRoster(members, invites)) console.log(line);
248
+ })
249
+ }),
250
+ add: defineCommand({
251
+ meta: {
252
+ name: "add",
253
+ description: "Add someone as an editor (default) or viewer; invites them if they haven't signed in yet"
254
+ },
255
+ args: {
256
+ email: {
257
+ type: "positional",
258
+ description: "Their company email",
259
+ required: true
260
+ },
261
+ viewer: {
262
+ type: "boolean",
263
+ description: "May open the app, not manage the project"
264
+ },
265
+ editor: {
266
+ type: "boolean",
267
+ description: "May manage the project (the default)"
268
+ },
269
+ ...appRoleArg,
270
+ ...projectDirArgs
271
+ },
272
+ run: reportErrors("members add", async ({ args }) => {
273
+ const { slug } = resolveProject(args);
274
+ const role = canopyRoleFlag(args) ?? "editor";
275
+ const appRoles = appRolesOf(args);
276
+ const res = await withContext(apiRequest("POST", `/projects/${slug}/members`, {
277
+ email: args.email,
278
+ role,
279
+ ...appRoles && { app_roles: appRoles }
280
+ }), {
281
+ action: `add ${args.email} to ${slug}`,
282
+ fixes: MEMBER_FIXES
283
+ });
284
+ const roles = appRoles?.length ? ` with ${appRoles.join(", ")}` : "";
285
+ console.log(res.invite ? `Invited ${args.email} as ${role}${roles} — it takes effect when they first sign in. Canopy sends no email, so let them know.` : `Added ${args.email} as ${role}${roles}.`);
286
+ })
287
+ }),
288
+ set: defineCommand({
289
+ meta: {
290
+ name: "set",
291
+ description: "Change someone's Canopy role (owner only) and/or app roles (editors too)"
292
+ },
293
+ args: {
294
+ email: {
295
+ type: "positional",
296
+ description: "Their email, as `members list` shows it",
297
+ required: true
298
+ },
299
+ viewer: {
300
+ type: "boolean",
301
+ description: "Make them a viewer"
302
+ },
303
+ editor: {
304
+ type: "boolean",
305
+ description: "Make them an editor"
306
+ },
307
+ ...appRoleArg,
308
+ "clear-app-roles": {
309
+ type: "boolean",
310
+ description: "Take all their app roles away"
311
+ },
312
+ ...projectDirArgs
313
+ },
314
+ run: reportErrors("members set", async ({ args }) => {
315
+ const { slug } = resolveProject(args);
316
+ const role = canopyRoleFlag(args);
317
+ const appRoles = args["clear-app-roles"] ? [] : appRolesOf(args);
318
+ if (role === void 0 && appRoles === void 0) throw new Error("Nothing to change — pass --editor, --viewer, --app-role or --clear-app-roles.");
319
+ const body = {
320
+ ...role && { role },
321
+ ...appRoles && { app_roles: appRoles }
322
+ };
323
+ const email = args.email.trim().toLowerCase();
324
+ const { members, invites } = await roster(slug);
325
+ const member = members.find((m) => m.email.toLowerCase() === email);
326
+ const invite = invites.find((i) => i.email === email);
327
+ if (!member && !invite) throw new Error(`${args.email} is not on ${slug} — add them with \`canopy members add\`.`);
328
+ await withContext(apiRequest("PATCH", member ? `/projects/${slug}/members/${encodeURIComponent(member.user_id)}` : `/projects/${slug}/invites/${encodeURIComponent(email)}`, body), {
329
+ action: `update ${args.email} on ${slug}`,
330
+ fixes: MEMBER_FIXES
331
+ });
332
+ console.log([
333
+ `Updated ${args.email}`,
334
+ role && `now ${role}`,
335
+ appRoles && (appRoles.length ? `app roles ${appRoles.join(", ")}` : "no app roles")
336
+ ].filter(Boolean).join(" — ") + ".");
337
+ })
338
+ }),
339
+ remove: defineCommand({
340
+ meta: {
341
+ name: "remove",
342
+ description: "Remove someone from the project, or withdraw their invite"
343
+ },
344
+ args: {
345
+ email: {
346
+ type: "positional",
347
+ description: "Their email, as `members list` shows it",
348
+ required: true
349
+ },
350
+ ...projectDirArgs
351
+ },
352
+ run: reportErrors("members remove", async ({ args }) => {
353
+ const { slug } = resolveProject(args);
354
+ const email = args.email.trim().toLowerCase();
355
+ const { members, invites } = await roster(slug);
356
+ const member = members.find((m) => m.email.toLowerCase() === email);
357
+ if (member) {
358
+ await withContext(apiRequest("DELETE", `/projects/${slug}/members/${encodeURIComponent(member.user_id)}`), {
359
+ action: `remove ${args.email} from ${slug}`,
360
+ fixes: MEMBER_FIXES
361
+ });
362
+ console.log(`Removed ${args.email} from ${slug}.`);
363
+ return;
364
+ }
365
+ if (invites.some((i) => i.email === email)) {
366
+ await withContext(apiRequest("DELETE", `/projects/${slug}/invites/${encodeURIComponent(email)}`), {
367
+ action: `withdraw the invite for ${args.email}`,
368
+ fixes: MEMBER_FIXES
369
+ });
370
+ console.log(`Withdrew the invite for ${args.email}.`);
371
+ return;
372
+ }
373
+ throw new Error(`${args.email} is not on ${slug}.`);
374
+ })
375
+ })
376
+ }
377
+ });
378
+ //#endregion
379
+ export { parseAppRoleFlag as a, membersCommand as i, formatRoles as n, rolesCommand as o, formatRoster as r, canopyRoleFlag as t };
@@ -109,6 +109,15 @@ and never go stale.
109
109
  hard-coded ids — model ids outside that list are refused.
110
110
  - Work bug reports & feedback: `canopy feedback list | show | comment | note | status | report | watch`
111
111
  — see [Working feedback reports](#working-feedback-reports-issues) below
112
+ - **People and permissions in the app** (`canopy docs roles`): app roles are
113
+ the project's own labels, read as `roles` on `auth.user()` / `env.CALLER`.
114
+ Run `canopy roles list --json` before writing a role check and use only those
115
+ slugs; create missing ones with `canopy roles add "<Name>"` and assign them
116
+ with `canopy members set <email> --app-role <slug>`. **Enforce roles in the
117
+ backend worker** (`env.CALLER.roles`), never only in the page; keep data
118
+ only some roles may see in `private_` tables. Try other roles locally with
119
+ `canopy dev --as-role <slug>`. Adding or removing people is the owner's call
120
+ (`canopy members add|remove`) — confirm with the user first.
112
121
  - CI credentials: `canopy token create | list | revoke`
113
122
  - Git: `canopy repo show --json` (is there a repository, and its remote) ·
114
123
  `canopy repo create` · `canopy repo clone <slug>` · `canopy repo connect`
@@ -1,4 +1,4 @@
1
- import { t as version } from "./package-XOtqboS1.mjs";
1
+ import { t as version } from "./package-Bvly8-rB.mjs";
2
2
  import { r as reportErrors } from "./ui-CLnICOne.mjs";
3
3
  import { defineCommand } from "citty";
4
4
  import { cpSync, existsSync, mkdirSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
@@ -860,7 +860,8 @@ const IDENTITY_STAMP_HEADERS = [
860
860
  "x-canopy-identity-kind",
861
861
  "x-canopy-identity-id",
862
862
  "x-canopy-identity-email",
863
- "x-canopy-identity-name"
863
+ "x-canopy-identity-name",
864
+ "x-canopy-identity-roles"
864
865
  ];
865
866
  /**
866
867
  * Header carrying the project's worker token as runtime-origin proof (docs/35).
@@ -960,15 +961,30 @@ const IDENTITY_STAMP_HEADERS = [
960
961
  "x-canopy-identity-id",
961
962
  "x-canopy-identity-email",
962
963
  "x-canopy-identity-name",
964
+ "x-canopy-identity-roles",
963
965
  ];
964
966
 
967
+ // App roles (project-roles) — transcribed from rolesFromHeaders in
968
+ // project-runtime/src/user.ts: undefined without the header (an older
969
+ // gateway), so the property stays absent rather than [].
970
+ function rolesFromHeaders(headers) {
971
+ const raw = headers.get("x-canopy-identity-roles");
972
+ if (raw === null) return undefined;
973
+ return raw
974
+ .split(",")
975
+ .map((r) => r.trim())
976
+ .filter(Boolean);
977
+ }
978
+
965
979
  function userFromHeaders(headers) {
966
980
  const sub = (headers.get("x-canopy-user-sub") || "").trim();
967
981
  if (!sub) return null;
982
+ const roles = rolesFromHeaders(headers);
968
983
  return {
969
984
  sub,
970
985
  email: (headers.get("x-canopy-user-email") || "").trim(),
971
986
  name: (headers.get("x-canopy-user-name") || "").trim(),
987
+ ...(roles && { roles }),
972
988
  };
973
989
  }
974
990
 
@@ -979,17 +995,28 @@ function callerFromHeaders(headers) {
979
995
  const kind = (headers.get("x-canopy-identity-kind") || "").trim();
980
996
  const id = (headers.get("x-canopy-identity-id") || "").trim();
981
997
  if ((kind !== "monk" && kind !== "external") || !id) return null;
998
+ const roles = rolesFromHeaders(headers);
982
999
  return {
983
1000
  kind,
984
1001
  id,
985
1002
  email: (headers.get("x-canopy-identity-email") || "").trim(),
986
1003
  name: (headers.get("x-canopy-identity-name") || "").trim(),
987
1004
  agent: headers.get("x-canopy-caller") === "agent",
1005
+ ...(roles && { roles }),
988
1006
  };
989
1007
  }
990
1008
 
991
1009
  function callerFromUser(user) {
992
- return user ? { kind: "monk", id: user.sub, email: user.email, name: user.name, agent: false } : null;
1010
+ return user
1011
+ ? {
1012
+ kind: "monk",
1013
+ id: user.sub,
1014
+ email: user.email,
1015
+ name: user.name,
1016
+ agent: false,
1017
+ ...(user.roles && { roles: user.roles }),
1018
+ }
1019
+ : null;
993
1020
  }
994
1021
 
995
1022
  function rewriteCanopyUrl(raw, apiUrl) {
@@ -1576,7 +1603,15 @@ export default {
1576
1603
  // workspace, or an unknown caller, is nobody.
1577
1604
  workerEnv.USER =
1578
1605
  typeof body.user === "object" && body.user !== null && typeof body.user.sub === "string"
1579
- ? { sub: body.user.sub, email: body.user.email || "", name: body.user.name || "" }
1606
+ ? {
1607
+ sub: body.user.sub,
1608
+ email: body.user.email || "",
1609
+ name: body.user.name || "",
1610
+ // App roles (project-roles), resolved by canopy-api.
1611
+ ...(Array.isArray(body.user.roles) && {
1612
+ roles: body.user.roles.filter((r) => typeof r === "string"),
1613
+ }),
1614
+ }
1580
1615
  : null;
1581
1616
  workerEnv.CALLER = callerFromUser(workerEnv.USER);
1582
1617
  try {
@@ -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-Ct-aCOzg.mjs");
115
+ const { skillInstalled } = await import("./skill-DRLniv-I.mjs");
116
116
  const { homedir } = await import("node:os");
117
117
  const refreshGlobal = skillInstalled(homedir());
118
118
  const refreshRepo = process.cwd() !== homedir() && skillInstalled(process.cwd());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mediamonks/canopy-cli",
3
- "version": "0.7.43",
3
+ "version": "0.7.44",
4
4
  "description": "Canopy CLI — create, develop and deploy Canopy projects.",
5
5
  "bin": {
6
6
  "canopy": "./dist/index.mjs"
@@ -22,7 +22,7 @@
22
22
  "esbuild": "^0.28.1",
23
23
  "hono": "^4.8.0",
24
24
  "vite-server": "npm:vite@^7",
25
- "@mediamonks/canopy": "0.0.12",
25
+ "@mediamonks/canopy": "0.0.13",
26
26
  "@mediamonks/canopy-data-plane": "0.0.4"
27
27
  },
28
28
  "devDependencies": {
@@ -1,2 +0,0 @@
1
- import { n as devCommand } from "./dev-adLLSY1F.mjs";
2
- export { devCommand };