@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.
- package/dist/{browse-dyOThTyf.mjs → browse-B8-0dweq.mjs} +1 -1
- package/dist/dev-CUJKgaqJ.mjs +2 -0
- package/dist/{dev-adLLSY1F.mjs → dev-Cq98yblV.mjs} +95 -13
- package/dist/{dev-worker-DJekKSdb.mjs → dev-worker-CcYwQjxz.mjs} +23 -10
- package/dist/docs/agent-browsing.md +2 -2
- package/dist/docs/agent-tools.md +2 -2
- package/dist/docs/ci.md +1 -1
- package/dist/docs/cli-browse.md +1 -1
- package/dist/docs/cli-dev.md +1 -0
- package/dist/docs/cli-mcp.md +1 -1
- package/dist/docs/cli-members.md +41 -0
- package/dist/docs/cli-roles.md +39 -0
- package/dist/docs/cli-token.md +1 -1
- package/dist/docs/index.json +16 -1
- package/dist/docs/overview-faq.md +6 -4
- package/dist/docs/overview-how-it-works.md +3 -2
- package/dist/docs/overview-use-cases.md +1 -1
- package/dist/docs/overview-what-is-canopy.md +1 -1
- package/dist/docs/platform-client-access.md +1 -1
- package/dist/docs/platform-members-and-access.md +66 -42
- package/dist/docs/roles.md +100 -0
- package/dist/docs/sdk-auth.md +24 -10
- package/dist/docs/sdk-realtime.md +1 -1
- package/dist/docs/static-serving.md +1 -1
- package/dist/{docs-CaAgJWK3.mjs → docs-KmN6jD1S.mjs} +1 -1
- package/dist/{feedback-CMnG2Zvs.mjs → feedback-B5-95neo.mjs} +1 -1
- package/dist/index.mjs +10 -8
- package/dist/{local-2xtxtoUd.mjs → local-CIkL7tXP.mjs} +4 -3
- package/dist/{mcp-BVIU4j9N.mjs → mcp-DZdMNTWr.mjs} +2 -2
- package/dist/{package-XOtqboS1.mjs → package-Bvly8-rB.mjs} +1 -1
- package/dist/roles-BDZaN3vi.mjs +2 -0
- package/dist/roles-UM0Iiws6.mjs +379 -0
- package/dist/skill/canopy/SKILL.md +9 -0
- package/dist/{skill-Ct-aCOzg.mjs → skill-DRLniv-I.mjs} +1 -1
- package/dist/{src-CScXotBB.mjs → src-8vxOBOxW.mjs} +38 -3
- package/dist/{upgrade-DJogeXAF.mjs → upgrade-D_yrD7zp.mjs} +1 -1
- package/package.json +2 -2
- package/dist/dev-BmI5kwoG.mjs +0 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Members & access
|
|
3
|
-
description: Everything on Canopy sits behind Monks sign-in.
|
|
3
|
+
description: Everything on Canopy sits behind Monks sign-in. Editors manage a project, viewers open it, and your app can hand out its own roles on top.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
Nothing on Canopy is reachable by the anonymous internet. Every project URL
|
|
@@ -23,52 +23,76 @@ nobody outside the team can touch its data or settings.
|
|
|
23
23
|
|
|
24
24
|
## Roles
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
26
|
+
Everyone on a project's roster has one Canopy role:
|
|
27
|
+
|
|
28
|
+
- **Owner**: the person who created the project. Owners govern it: they add
|
|
29
|
+
and remove members, decide who is an editor or a viewer, change access
|
|
30
|
+
settings, and can delete the project.
|
|
31
|
+
- **Editor**: does the day-to-day work. Editors deploy, roll back, browse and
|
|
32
|
+
edit data, and manage schedules, secrets and app roles. They can't delete
|
|
33
|
+
the project or change who is on it.
|
|
34
|
+
- **Viewer**: can open the app, and nothing else. Viewers don't see the
|
|
35
|
+
project's management pages. Adding someone as a viewer only makes a
|
|
36
|
+
difference when the project is limited to members, or when you give them
|
|
37
|
+
[app roles](#app-roles).
|
|
38
|
+
- **Platform admin**: can manage any project from the dashboard. Admins don't
|
|
39
|
+
quietly get past a members-only app (see below).
|
|
40
|
+
|
|
41
|
+
## Adding members
|
|
42
|
+
|
|
43
|
+
Open the project's **Settings → Access** page and use the **Members** card.
|
|
44
|
+
Start typing a name or email: colleagues who have signed in to Canopy before
|
|
45
|
+
show up as suggestions. Pick **Editor** or **Viewer** and add them.
|
|
46
|
+
|
|
47
|
+
Someone who has never opened Canopy can be added too. Type their full company
|
|
48
|
+
email and choose **Invite by email**. They show up as **invited** and join
|
|
49
|
+
automatically the first time they sign in, whether that's opening the
|
|
50
|
+
project's URL or running `canopy login`. Until then the invite grants nothing.
|
|
51
|
+
Canopy doesn't send them a message, so let them know yourself.
|
|
52
|
+
|
|
53
|
+
The owner can switch anyone between editor and viewer, remove people, or
|
|
54
|
+
withdraw an invite from the same card. From a terminal,
|
|
55
|
+
[`canopy members`](https://docs.canopy.website/cli/members) does the same.
|
|
56
|
+
|
|
57
|
+
## App roles
|
|
58
|
+
|
|
59
|
+
Many apps need their own permissions: "everyone can look, but only a few
|
|
60
|
+
people approve", or "only these people get in, each with their own role".
|
|
61
|
+
App roles cover that without a table of emails in your code.
|
|
62
|
+
|
|
63
|
+
Under **Settings → Access → App roles**, create the roles your app needs. Each
|
|
64
|
+
has a name and a slug, like `approver`. Then give members their roles from the
|
|
65
|
+
Members card. Your app reads them as `roles` on the signed-in user, from
|
|
66
|
+
[`auth.user()`](https://docs.canopy.website/sdk/auth) or `env.CALLER` in a backend worker.
|
|
67
|
+
|
|
68
|
+
One role is always the **default**. Everyone who can open the app has it,
|
|
69
|
+
client-password visitors included, so you don't have to hand it out. The first
|
|
70
|
+
role you create becomes the default, and you can make another one the default
|
|
71
|
+
at any time.
|
|
72
|
+
|
|
73
|
+
Canopy hands roles to your app but never checks them for you. Read
|
|
74
|
+
[Roles and permissions](https://docs.canopy.website/guides/roles) for how to use them safely.
|
|
75
|
+
|
|
76
|
+
## Members-only mode
|
|
77
|
+
|
|
78
|
+
Sometimes "any Monk can look" is too open: payroll prototypes, sensitive
|
|
79
|
+
client work, unfinished things you'd rather not demo by accident. Turn on
|
|
80
|
+
**Settings → Access → Who at Monks can open it → Restrict to members** and the
|
|
81
|
+
live app is limited to the project's roster, editors and viewers alike:
|
|
82
|
+
|
|
83
|
+
- Other Monks who open the URL get a "limited to its members" page instead of
|
|
84
|
+
the app.
|
|
85
|
+
- The project still appears in the company list. It isn't hidden, just
|
|
62
86
|
closed.
|
|
63
87
|
- Platform admins can still manage the project in the dashboard, but they
|
|
64
|
-
must add themselves as
|
|
65
|
-
- [Client password access](https://docs.canopy.website/platform/client-access), if you've
|
|
66
|
-
|
|
88
|
+
must add themselves as members to open the live app.
|
|
89
|
+
- [Client password access](https://docs.canopy.website/platform/client-access), if you've turned it on,
|
|
90
|
+
is unaffected. The two controls are independent.
|
|
67
91
|
|
|
68
92
|
Turning it off again is the same toggle.
|
|
69
93
|
|
|
70
|
-
> **Note:**
|
|
71
|
-
>
|
|
94
|
+
> **Note:** Members-only gates the **live app**. Management pages (settings, data, deploys) are always for the
|
|
95
|
+
> owner and editors only, whatever this toggle says.
|
|
72
96
|
|
|
73
97
|
## Platform admins and the Admin page
|
|
74
98
|
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Roles and permissions
|
|
3
|
+
description: Give people different powers inside your app with app roles, and check them where it counts.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Canopy decides who can open your app. App roles decide what each person can
|
|
7
|
+
do once they're in. You create the roles, give them to people, and your code
|
|
8
|
+
reads them. Canopy never checks them for you.
|
|
9
|
+
|
|
10
|
+
## Two kinds of role
|
|
11
|
+
|
|
12
|
+
- **Canopy roles** (owner, editor, viewer) are about the project itself: who
|
|
13
|
+
can deploy, see the data, change settings. Viewers can only open the app.
|
|
14
|
+
See [Members and access](https://docs.canopy.website/platform/members-and-access).
|
|
15
|
+
- **App roles** are your app's own labels, like `approver` or `admin`. They
|
|
16
|
+
mean whatever your code makes them mean.
|
|
17
|
+
|
|
18
|
+
The two are independent. A viewer can be your app's `admin`, and an editor
|
|
19
|
+
can have no app roles at all.
|
|
20
|
+
|
|
21
|
+
## Set roles up
|
|
22
|
+
|
|
23
|
+
In the dashboard, open **Settings → Access**:
|
|
24
|
+
|
|
25
|
+
1. Under **App roles**, add a role. Give it a name ("Approver") and check the
|
|
26
|
+
slug (`approver`). The slug is what your code checks, and it can't change
|
|
27
|
+
later. The name can.
|
|
28
|
+
2. Under **Members**, open the tag button next to someone and tick their
|
|
29
|
+
roles. To give roles to a colleague who only needs to use the app, add
|
|
30
|
+
them as a **Viewer** first.
|
|
31
|
+
|
|
32
|
+
Or from a terminal, which is also how an agent sets them up:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
canopy roles add "Approver"
|
|
36
|
+
canopy members add jane@monks.com --viewer --app-role approver
|
|
37
|
+
canopy roles list
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## The default role
|
|
41
|
+
|
|
42
|
+
The first role you create is the **default**. Everyone who can open the app
|
|
43
|
+
has it: members, any other Monk on an open project, and client-password
|
|
44
|
+
visitors. That lets your code treat everyone the same way ("everyone is at
|
|
45
|
+
least a `user`") without listing every person. Make another role the default
|
|
46
|
+
whenever you like; everyone's roles change with it. The default role can't be
|
|
47
|
+
deleted while other roles exist.
|
|
48
|
+
|
|
49
|
+
## Read roles in your code
|
|
50
|
+
|
|
51
|
+
`roles` is a list of slugs, the default first:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
const user = await canopy.auth.user();
|
|
55
|
+
user.roles; // ["user", "approver"]
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
In a backend worker, `env.CALLER.roles` holds the same list without a round
|
|
59
|
+
trip, and so does `env.USER.roles` for a signed-in Monk.
|
|
60
|
+
|
|
61
|
+
## Check roles where it counts
|
|
62
|
+
|
|
63
|
+
A check that only runs in the browser hides buttons. It doesn't protect
|
|
64
|
+
anything, because a visitor can call your data and routes directly. Put the
|
|
65
|
+
check that matters in your backend worker:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
app.post("/api/approve/:id", async (c) => {
|
|
69
|
+
if (!c.env.CALLER?.roles?.includes("approver")) {
|
|
70
|
+
return c.json({ error: "approvers only" }, 403);
|
|
71
|
+
}
|
|
72
|
+
// only approvers get here
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Keep data that only some roles may see in tables or collections whose names
|
|
77
|
+
start with `private_`. Pages can't reach those, only your worker can. See
|
|
78
|
+
[Database](https://docs.canopy.website/sdk/database).
|
|
79
|
+
|
|
80
|
+
## Try another role locally
|
|
81
|
+
|
|
82
|
+
`canopy dev` runs with your own roles. To see the app the way someone else
|
|
83
|
+
does, pass `--as-role`:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
canopy dev --as-role reviewer
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
You keep the project's default role, as a real visitor would, and get
|
|
90
|
+
`reviewer` instead of your own roles. It only changes your local session.
|
|
91
|
+
Nothing changes on the platform.
|
|
92
|
+
|
|
93
|
+
## Good to know
|
|
94
|
+
|
|
95
|
+
- Role changes reach your app within a few seconds.
|
|
96
|
+
- A backend deployed before app roles existed sees no `roles` on
|
|
97
|
+
`env.CALLER` until you redeploy it. `auth.user()` has them right away.
|
|
98
|
+
- Client-password visitors all share one password, so they only ever get the
|
|
99
|
+
default role.
|
|
100
|
+
- Scheduled runs have no caller and no roles.
|
package/dist/docs/sdk-auth.md
CHANGED
|
@@ -15,15 +15,16 @@ Returns the authenticated user for the current session as a `CanopyUser`:
|
|
|
15
15
|
|
|
16
16
|
```ts
|
|
17
17
|
const user = await canopy.auth.user();
|
|
18
|
-
// { id: "…", email: "ada@monks.com", name: "Ada Lovelace", kind: "monk" }
|
|
18
|
+
// { id: "…", email: "ada@monks.com", name: "Ada Lovelace", kind: "monk", roles: ["user"] }
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
| Field | Type | Meaning
|
|
22
|
-
| ------- | ---------------------- |
|
|
23
|
-
| `id` | `string` | Stable subject from OneLogin — safe to key user data on.
|
|
24
|
-
| `email` | `string` | The user's email address.
|
|
25
|
-
| `name` | `string` | Display name.
|
|
26
|
-
| `kind` | `"monk" \| "external"` | `"monk"` = signed in through OneLogin; `"external"` = a visitor who got in with the project's client password instead.
|
|
21
|
+
| Field | Type | Meaning |
|
|
22
|
+
| ------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
|
|
23
|
+
| `id` | `string` | Stable subject from OneLogin — safe to key user data on. |
|
|
24
|
+
| `email` | `string` | The user's email address. |
|
|
25
|
+
| `name` | `string` | Display name. |
|
|
26
|
+
| `kind` | `"monk" \| "external"` | `"monk"` = signed in through OneLogin; `"external"` = a visitor who got in with the project's client password instead. |
|
|
27
|
+
| `roles` | `string[]` | The project's [app roles](https://docs.canopy.website/guides/roles) this person has: the default role first, then their own. Empty when the project has none. |
|
|
27
28
|
|
|
28
29
|
`kind: "external"` sessions come from client-password access — clients viewing
|
|
29
30
|
a shared project without a Monks account. Branch on it when externals should
|
|
@@ -46,8 +47,8 @@ if (user.kind === "external") {
|
|
|
46
47
|
### In a backend worker
|
|
47
48
|
|
|
48
49
|
A worker route already knows who is calling, without asking: `env.CALLER`
|
|
49
|
-
holds the same `id`, `email`, `name` and `
|
|
50
|
-
plus `agent`, which is `true` when an AI agent is acting for a Monk.
|
|
50
|
+
holds the same `id`, `email`, `name`, `kind` and `roles` that `auth.user()`
|
|
51
|
+
returns, plus `agent`, which is `true` when an AI agent is acting for a Monk.
|
|
51
52
|
|
|
52
53
|
```ts
|
|
53
54
|
import type { CanopyCaller } from "@mediamonks/canopy";
|
|
@@ -67,7 +68,20 @@ A client-password visitor has no email address and is named `"Client"`. Its
|
|
|
67
68
|
`id` changes with every password unlock, so don't key data on it that has to
|
|
68
69
|
last.
|
|
69
70
|
|
|
70
|
-
|
|
71
|
+
This is the place to check app roles, because a visitor can't change what
|
|
72
|
+
your worker sees:
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
app.post("/api/approve/:id", (c) => {
|
|
76
|
+
if (!c.env.CALLER?.roles?.includes("approver")) {
|
|
77
|
+
return c.json({ error: "approvers only" }, 403);
|
|
78
|
+
}
|
|
79
|
+
// …
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
A backend gets `env.CALLER` from its next deploy, and `roles` on it from its
|
|
84
|
+
first deploy after app roles shipped. Until it is redeployed,
|
|
71
85
|
`auth.user()` through the `CANOPY` binding gives the same answer:
|
|
72
86
|
|
|
73
87
|
```ts
|
|
@@ -121,7 +121,7 @@ right away and `onOpen` runs, so the page catches up from the database. A
|
|
|
121
121
|
quick switch away and back keeps the connection.
|
|
122
122
|
|
|
123
123
|
Every connection also renews itself about every quarter of an hour, and
|
|
124
|
-
whenever access to the project changes (the client password,
|
|
124
|
+
whenever access to the project changes (the client password, members
|
|
125
125
|
only, someone removed). Each renewal runs `onOpen` again, which is what
|
|
126
126
|
keeps the reload-on-open pattern correct.
|
|
127
127
|
|
|
@@ -17,7 +17,7 @@ Every request passes the sign-in wall before a single byte of your project is
|
|
|
17
17
|
read. A visitor arrives with a company login, or — if you've turned on
|
|
18
18
|
[client access](https://docs.canopy.website/platform/client-access) — the project's password. There is no
|
|
19
19
|
public URL, no "unlisted" link, and no way to opt a single file out. A project
|
|
20
|
-
is readable by any signed-in colleague unless you set it to
|
|
20
|
+
is readable by any signed-in colleague unless you set it to members only,
|
|
21
21
|
in [members and access](https://docs.canopy.website/platform/members-and-access).
|
|
22
22
|
|
|
23
23
|
## Deep links work — routing is yours
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as version } from "./package-
|
|
1
|
+
import { t as version } from "./package-Bvly8-rB.mjs";
|
|
2
2
|
import { r as siteConfig } from "./site-0i7wAJqg.mjs";
|
|
3
3
|
import { i as latestKnownVersion, r as compareSemver } from "./version-check-CcsA1QjI.mjs";
|
|
4
4
|
import { n as agentHeaders } from "./api-Bl6SG8Oq.mjs";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as version } from "./package-
|
|
1
|
+
import { t as version } from "./package-Bvly8-rB.mjs";
|
|
2
2
|
import { f as tryReadCanopyJson, l as resolveProject, o as projectDirArgs, p as tryResolveProject, r as siteConfig } from "./site-0i7wAJqg.mjs";
|
|
3
3
|
import { a as apiRequest, c as credentials, i as apiDownload, o as apiUpload, s as commonHeaders } from "./api-Bl6SG8Oq.mjs";
|
|
4
4
|
import { r as reportErrors, t as formatDateTime } from "./ui-CLnICOne.mjs";
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as version } from "./package-
|
|
2
|
+
import { t as version } from "./package-Bvly8-rB.mjs";
|
|
3
3
|
import { i as siteHeaderLine, n as setInvocationProfile } from "./site-0i7wAJqg.mjs";
|
|
4
4
|
import { a as notifyOfUpdate, o as runRefresh } from "./version-check-CcsA1QjI.mjs";
|
|
5
5
|
import { defineCommand, runMain } from "citty";
|
|
@@ -71,7 +71,7 @@ const main = defineCommand({
|
|
|
71
71
|
projects: () => import("./projects-BRG2HnBs.mjs").then((m) => m.projectsCommand),
|
|
72
72
|
delete: () => import("./projects-BRG2HnBs.mjs").then((m) => m.deleteCommand),
|
|
73
73
|
rename: () => import("./rename-BGKa25Rq.mjs").then((m) => m.renameCommand),
|
|
74
|
-
dev: () => import("./dev-
|
|
74
|
+
dev: () => import("./dev-CUJKgaqJ.mjs").then((m) => m.devCommand),
|
|
75
75
|
deploy: () => import("./deploy-ExrIeX_m.mjs").then((m) => m.deployCommand),
|
|
76
76
|
promote: () => import("./deploy-ExrIeX_m.mjs").then((m) => m.promoteCommand),
|
|
77
77
|
staging: () => import("./staging-_2Js0Fkc.mjs").then((m) => m.stagingCommand),
|
|
@@ -80,18 +80,20 @@ const main = defineCommand({
|
|
|
80
80
|
token: () => import("./token-7vSNuz-X.mjs").then((m) => m.tokenCommand),
|
|
81
81
|
egress: () => import("./egress-C2amvqmE.mjs").then((m) => m.egressCommand),
|
|
82
82
|
secrets: () => import("./secrets-BjbIi7Gp.mjs").then((m) => m.secretsCommand),
|
|
83
|
+
roles: () => import("./roles-BDZaN3vi.mjs").then((m) => m.rolesCommand),
|
|
84
|
+
members: () => import("./roles-BDZaN3vi.mjs").then((m) => m.membersCommand),
|
|
83
85
|
schedule: () => import("./schedule-BcqBspn3.mjs").then((m) => m.scheduleCommand),
|
|
84
|
-
feedback: () => import("./feedback-
|
|
86
|
+
feedback: () => import("./feedback-B5-95neo.mjs").then((m) => m.feedbackCommand),
|
|
85
87
|
db: () => import("./db-BJJGydgL.mjs").then((m) => m.dbCommand),
|
|
86
88
|
usage: () => import("./usage-DGGmTwjJ.mjs").then((m) => m.usageCommand),
|
|
87
89
|
ai: () => import("./ai-FBHTSCLZ.mjs").then((m) => m.aiCommand),
|
|
88
90
|
open: () => import("./open-Bpz4C2Sr.mjs").then((m) => m.openCommand),
|
|
89
|
-
browse: () => import("./browse-
|
|
90
|
-
docs: () => import("./docs-
|
|
91
|
-
skill: () => import("./skill-
|
|
92
|
-
upgrade: () => import("./upgrade-
|
|
91
|
+
browse: () => import("./browse-B8-0dweq.mjs").then((m) => m.browseCommand),
|
|
92
|
+
docs: () => import("./docs-KmN6jD1S.mjs").then((m) => m.docsCommand),
|
|
93
|
+
skill: () => import("./skill-DRLniv-I.mjs").then((m) => m.skillCommand),
|
|
94
|
+
upgrade: () => import("./upgrade-D_yrD7zp.mjs").then((m) => m.upgradeCommand),
|
|
93
95
|
logs: () => import("./logs-BnrNZvLc.mjs").then((m) => m.logsCommand),
|
|
94
|
-
mcp: () => import("./mcp-
|
|
96
|
+
mcp: () => import("./mcp-DZdMNTWr.mjs").then((m) => m.mcpCommand),
|
|
95
97
|
repo: () => import("./repo-DmFs6H9m.mjs").then((m) => m.repoCommand),
|
|
96
98
|
template: () => import("./project-template-715H_lnu.mjs").then((m) => m.templateCommand)
|
|
97
99
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { r as apiDataRequest } from "./api-Bl6SG8Oq.mjs";
|
|
2
|
-
import { a as realtimeRouter, c as META_COLUMNS, l as blobRouter, n as WORKER_ATTEST_HEADER, o as dbRouter, s as hasPrivateNames } from "./src-
|
|
3
|
-
import { a as rewriteApiPath } from "./dev-
|
|
2
|
+
import { a as realtimeRouter, c as META_COLUMNS, l as blobRouter, n as WORKER_ATTEST_HEADER, o as dbRouter, s as hasPrivateNames } from "./src-8vxOBOxW.mjs";
|
|
3
|
+
import { a as rewriteApiPath } from "./dev-Cq98yblV.mjs";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { dirname, join, relative, sep } from "node:path";
|
|
@@ -942,7 +942,8 @@ async function createSandbox(options) {
|
|
|
942
942
|
id: "local-dev",
|
|
943
943
|
email: options.email ?? "dev@localhost",
|
|
944
944
|
name: "Local Dev",
|
|
945
|
-
kind: "monk"
|
|
945
|
+
kind: "monk",
|
|
946
|
+
roles: options.roles ?? []
|
|
946
947
|
}));
|
|
947
948
|
app.all("/data/v1/ai/*", (c) => c.json({
|
|
948
949
|
error: "not_available_in_local_dev",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as version } from "./package-
|
|
1
|
+
import { t as version } from "./package-Bvly8-rB.mjs";
|
|
2
2
|
import { c as projectUrl, d as stagingUrl, p as tryResolveProject, r as siteConfig } from "./site-0i7wAJqg.mjs";
|
|
3
3
|
import { a as apiRequest, d as noticeRenamesOnly, l as currentSlug, t as ApiError } from "./api-Bl6SG8Oq.mjs";
|
|
4
4
|
import { t as liveDevServer } from "./dev-server-file-Dk9pk4AR.mjs";
|
|
@@ -171,7 +171,7 @@ function explainRefusal(status, body, project) {
|
|
|
171
171
|
case "agent_token_required":
|
|
172
172
|
case "agent_token_invalid": return "Canopy refused the sign-in for this agent session — run `canopy login` and restart the MCP server.";
|
|
173
173
|
case "agent_token_scope": return `The agent credential does not cover ${project} on this channel.`;
|
|
174
|
-
case "members_only": return `${project} is limited to its
|
|
174
|
+
case "members_only": return `${project} is limited to its members — ask the owner to add you.`;
|
|
175
175
|
case "project_not_found": return `There is no project ${project} on this site — check the slug and --profile.`;
|
|
176
176
|
case "project_paused": return `${project} is paused.`;
|
|
177
177
|
case "project_moved": return `${project} has moved${body.moved_to ? ` to ${body.moved_to}` : ""}.`;
|