@mediamonks/canopy-cli 0.7.30 → 0.7.31

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 (39) hide show
  1. package/dist/{ai-fAvjdjVX.mjs → ai-DHLnyqfq.mjs} +2 -1
  2. package/dist/{ui-CeupNHNa.mjs → api-C4rMhE7i.mjs} +1 -122
  3. package/dist/{db-KTLn8J1u.mjs → db-BB6O6085.mjs} +3 -2
  4. package/dist/{deploy-CBf44bvG.mjs → deploy-B-znPE-v.mjs} +4 -2
  5. package/dist/{dev-JlzMZJow.mjs → dev-CkhBnSlv.mjs} +13 -6
  6. package/dist/dev-MoHHjQh1.mjs +2 -0
  7. package/dist/dev-server-file-Dk9pk4AR.mjs +54 -0
  8. package/dist/{dev-worker-DjJGSUGj.mjs → dev-worker-CaCsGBkn.mjs} +34 -2
  9. package/dist/docs/agent-tools.md +213 -0
  10. package/dist/docs/cli-mcp.md +88 -0
  11. package/dist/docs/developers-agents-and-ai.md +8 -0
  12. package/dist/docs/index.json +10 -0
  13. package/dist/{docs-Dg0UJugG.mjs → docs-YD4z70gq.mjs} +2 -2
  14. package/dist/{egress-Cn9zDfDT.mjs → egress-If_Gsx_M.mjs} +2 -1
  15. package/dist/{feedback-Dvb6CdlP.mjs → feedback-Cd7Rvg9a.mjs} +3 -2
  16. package/dist/index.mjs +32 -29
  17. package/dist/{local-BA_TPWpN.mjs → local-DAYCNUyz.mjs} +3 -3
  18. package/dist/{login-MX0xq8UE.mjs → login-B-m-i8uu.mjs} +1 -1
  19. package/dist/{logs-D5RWqsWl.mjs → logs-DQQOawOG.mjs} +2 -1
  20. package/dist/mcp-GKwctfHN.mjs +457 -0
  21. package/dist/{migrations-C8yRPJIX.mjs → migrations-Czlcddyz.mjs} +1 -1
  22. package/dist/{open-BJgd0R61.mjs → open-DcaQKi1v.mjs} +1 -1
  23. package/dist/{package-CnS450Yc.mjs → package-CiKTWo0_.mjs} +1 -1
  24. package/dist/{projects-BG7Injpb.mjs → projects-CN2YhCZn.mjs} +2 -1
  25. package/dist/{schedule-CLuksxSM.mjs → schedule-C5lMf3ny.mjs} +2 -1
  26. package/dist/{secrets-Bl3uOx4l.mjs → secrets-BSEjZnxg.mjs} +2 -1
  27. package/dist/skill/canopy/SKILL.md +7 -0
  28. package/dist/{skill-CuES7kPj.mjs → skill-BWmXiJAz.mjs} +2 -2
  29. package/dist/{src-C7zPhbxi.mjs → src-BkACMkol.mjs} +15 -1
  30. package/dist/{staging-D06zobnf.mjs → staging-BZVty57b.mjs} +2 -1
  31. package/dist/templates/spa/package.json +1 -1
  32. package/dist/templates/worker/package.json +1 -1
  33. package/dist/templates/worker/worker/index.ts +17 -0
  34. package/dist/{token-C_PFNqcv.mjs → token-HHlUR0CF.mjs} +2 -1
  35. package/dist/ui-C_jSc1Kz.mjs +123 -0
  36. package/dist/{upgrade-C8YdSKKd.mjs → upgrade-Cexs9KYX.mjs} +2 -2
  37. package/dist/{usage-CV7TjTO8.mjs → usage-CUYrWxv0.mjs} +2 -1
  38. package/package.json +4 -2
  39. package/dist/dev-DGCu9MjB.mjs +0 -2
@@ -1,5 +1,5 @@
1
- import { t as version } from "./package-CnS450Yc.mjs";
2
- import { r as reportErrors } from "./ui-CeupNHNa.mjs";
1
+ import { t as version } from "./package-CiKTWo0_.mjs";
2
+ import { r as reportErrors } from "./ui-C_jSc1Kz.mjs";
3
3
  import { defineCommand } from "citty";
4
4
  import { cpSync, existsSync, mkdirSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
5
5
  import { homedir } from "node:os";
@@ -843,6 +843,19 @@ const IDENTITY_STAMP_HEADERS = [
843
843
  "x-canopy-user-email",
844
844
  "x-canopy-user-name"
845
845
  ];
846
+ /**
847
+ * Header the gateway attaches to a project tools call (`/__canopy/mcp`,
848
+ * docs/49): the caller's agent token. A credential like the session cookie —
849
+ * the host keeps it for `env.CANOPY.fetch` and redacts it from the bundle.
850
+ * It travels in its own header because on Cloud Run `Authorization` carries
851
+ * the Google ID token that let the gateway in.
852
+ */
853
+ const AGENT_CREDENTIAL_HEADER = "x-canopy-agent-credential";
854
+ /**
855
+ * Gateway-stamped marker on a tools call: `agent`. Never a credential, but
856
+ * only the gateway may set it — it strips client copies on every dispatch.
857
+ */
858
+ const CALLER_HEADER = "x-canopy-caller";
846
859
  /** Cookies that authenticate to Canopy itself — the monk session and the client-page session. */
847
860
  const CANOPY_COOKIE_NAMES = /* @__PURE__ */ new Set(["canopy_session", "canopy_client"]);
848
861
  /**
@@ -874,6 +887,7 @@ function redactCanopyCredentials(headers) {
874
887
  else headers.set("cookie", kept);
875
888
  }
876
889
  if (headers.get("authorization")?.startsWith("Bearer cnpy_")) headers.delete("authorization");
890
+ headers.delete(AGENT_CREDENTIAL_HEADER);
877
891
  return headers;
878
892
  }
879
893
  /**
@@ -889,4 +903,4 @@ function stampWorkerHeaders(headers, ctx) {
889
903
  return headers;
890
904
  }
891
905
  //#endregion
892
- export { META_COLUMNS as a, dbRouter as i, stampWorkerHeaders as n, blobRouter as o, realtimeRouter as r, redactCanopyCredentials as t };
906
+ export { dbRouter as a, realtimeRouter as i, redactCanopyCredentials as n, META_COLUMNS as o, stampWorkerHeaders as r, blobRouter as s, CALLER_HEADER as t };
@@ -1,5 +1,6 @@
1
1
  import { c as resolveProject, l as stagingUrl, o as projectFlagArgs, s as projectUrl } from "./site-DM2J10CB.mjs";
2
- import { a as unwrap, d as withContext, i as requireTty, l as apiRequest, r as reportErrors, t as formatDateTime } from "./ui-CeupNHNa.mjs";
2
+ import { i as apiRequest, o as withContext } from "./api-C4rMhE7i.mjs";
3
+ import { a as unwrap, i as requireTty, r as reportErrors, t as formatDateTime } from "./ui-C_jSc1Kz.mjs";
3
4
  import { defineCommand } from "citty";
4
5
  import * as p from "@clack/prompts";
5
6
  //#region src/staging.ts
@@ -7,7 +7,7 @@
7
7
  "build": "tsc && vite build"
8
8
  },
9
9
  "dependencies": {
10
- "@mediamonks/canopy": "^0.0.6",
10
+ "@mediamonks/canopy": "^0.0.11",
11
11
  "react": "^19.1.0",
12
12
  "react-dom": "^19.1.0"
13
13
  },
@@ -7,7 +7,7 @@
7
7
  "build": "tsc && vite build"
8
8
  },
9
9
  "dependencies": {
10
- "@mediamonks/canopy": "^0.0.6",
10
+ "@mediamonks/canopy": "^0.0.11",
11
11
  "hono": "^4.8.0",
12
12
  "react": "^19.1.0",
13
13
  "react-dom": "^19.1.0"
@@ -53,6 +53,23 @@ app.get("/api/notes", async (c) => {
53
53
  return c.json({ notes });
54
54
  });
55
55
 
56
+ // Let AI agents (Claude Code, Cursor…) use this backend as MCP tools, through
57
+ // `canopy mcp serve`. They always act as the signed-in Monk running it. Route
58
+ // tools wrap the routes above; uncomment to try it, then redeploy:
59
+ //
60
+ // import { mountMcpTools } from "@mediamonks/canopy/mcp";
61
+ //
62
+ // mountMcpTools(app, [
63
+ // {
64
+ // name: "list_notes",
65
+ // description: "List all notes in this project",
66
+ // route: "GET /api/notes",
67
+ // annotations: { readOnlyHint: true },
68
+ // },
69
+ // ]);
70
+ //
71
+ // Guide: https://docs.canopy.website/guides/agent-tools
72
+
56
73
  export default {
57
74
  fetch: app.fetch.bind(app),
58
75
 
@@ -1,5 +1,6 @@
1
1
  import { a as projectDirArgs, c as resolveProject, o as projectFlagArgs } from "./site-DM2J10CB.mjs";
2
- import { l as apiRequest, r as reportErrors, t as formatDateTime } from "./ui-CeupNHNa.mjs";
2
+ import { i as apiRequest } from "./api-C4rMhE7i.mjs";
3
+ import { r as reportErrors, t as formatDateTime } from "./ui-C_jSc1Kz.mjs";
3
4
  import { defineCommand } from "citty";
4
5
  const tokenCommand = defineCommand({
5
6
  meta: {
@@ -0,0 +1,123 @@
1
+ import { t as ApiError } from "./api-C4rMhE7i.mjs";
2
+ import { spawn } from "node:child_process";
3
+ import { cancel, isCancel } from "@clack/prompts";
4
+ //#region src/ui.ts
5
+ /**
6
+ * Shared terminal UX plumbing: clack prompt unwrapping and uniform
7
+ * command error reporting.
8
+ */
9
+ /** Unwrap a clack prompt result, exiting cleanly when the user cancels (ctrl-c). */
10
+ function unwrap(result) {
11
+ if (isCancel(result)) {
12
+ cancel("Aborted.");
13
+ process.exit(130);
14
+ }
15
+ return result;
16
+ }
17
+ /** Terminal width to wrap error copy to, bounded so it stays readable. */
18
+ const TEXT_WIDTH = Math.min(process.stdout.columns || 80, 88);
19
+ /** Render ` Label text…`, wrapping and aligning continuation lines under the text. */
20
+ function labeled(label, text) {
21
+ const lead = ` ${label} `;
22
+ const indent = " ".repeat(lead.length);
23
+ const max = Math.max(TEXT_WIDTH - lead.length, 24);
24
+ const lines = [];
25
+ let line = "";
26
+ for (const word of text.split(/\s+/)) if (line && line.length + 1 + word.length > max) {
27
+ lines.push(line);
28
+ line = word;
29
+ } else line = line ? `${line} ${word}` : word;
30
+ if (line) lines.push(line);
31
+ return lines.map((l, i) => (i === 0 ? lead : indent) + l).join("\n");
32
+ }
33
+ /**
34
+ * Compose a command failure. API failures get a three-part block — what we
35
+ * tried (headline), why it failed, and how to fix it — everything else prints
36
+ * as a single `canopy <name>: <message>` line.
37
+ */
38
+ function formatCliError(name, err) {
39
+ if (err instanceof ApiError) {
40
+ const { headline, why, fix } = err.explain();
41
+ return [
42
+ `canopy ${name}: ${headline}`,
43
+ "",
44
+ labeled("Why", why),
45
+ labeled("Fix", fix),
46
+ ""
47
+ ].join("\n");
48
+ }
49
+ return `canopy ${name}: ${err instanceof Error ? err.message : String(err)}`;
50
+ }
51
+ const kebab = (s) => s.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);
52
+ const camel = (s) => s.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
53
+ /**
54
+ * Reject flags a command does not declare. citty parses with strict: false, so
55
+ * a misspelled or not-yet-released flag would otherwise be silently dropped —
56
+ * on `deploy --staging` (pre-0.7) that meant deploying to the wrong channel.
57
+ */
58
+ function assertKnownFlags(name, rawArgs, argDefs) {
59
+ const known = /* @__PURE__ */ new Set([
60
+ "help",
61
+ "h",
62
+ "version",
63
+ "profile"
64
+ ]);
65
+ for (const [key, def] of Object.entries(argDefs)) {
66
+ if (def.type === "positional") continue;
67
+ known.add(key);
68
+ known.add(kebab(key));
69
+ known.add(camel(key));
70
+ const aliases = typeof def.alias === "string" ? [def.alias] : def.alias ?? [];
71
+ for (const a of aliases) known.add(a);
72
+ if (def.type === "boolean") {
73
+ known.add(`no-${key}`);
74
+ known.add(`no-${kebab(key)}`);
75
+ }
76
+ }
77
+ for (const token of rawArgs) {
78
+ if (token === "--") break;
79
+ if (!token.startsWith("-") || token === "-") continue;
80
+ const body = token.replace(/^--?/, "").split("=")[0] ?? "";
81
+ if (!body || /^\d/.test(body)) continue;
82
+ if (!known.has(body)) throw new Error(`Unknown flag --${body}. Run \`canopy ${name} --help\` to see supported flags — if the docs mention it, your CLI may be outdated (\`canopy upgrade\`).`);
83
+ }
84
+ }
85
+ /** Wrap a command action so failures print an actionable report and exit 1. */
86
+ function reportErrors(name, action) {
87
+ return async (...args) => {
88
+ try {
89
+ const ctx = args[0];
90
+ if (ctx?.rawArgs && ctx.cmd?.args) assertKnownFlags(name, ctx.rawArgs, ctx.cmd.args);
91
+ await action(...args);
92
+ } catch (err) {
93
+ console.error(formatCliError(name, err));
94
+ process.exit(1);
95
+ }
96
+ };
97
+ }
98
+ /** Guard interactive prompts: bail with a actionable message on non-TTY runs. */
99
+ function requireTty(hint) {
100
+ if (!process.stdin.isTTY) throw new Error(`This needs an interactive terminal — ${hint}`);
101
+ }
102
+ /**
103
+ * API timestamps are UTC — ISO with a Z suffix, though a lagging API site may
104
+ * still send the bare "YYYY-MM-DD HH:MM:SS" form. Parse either as UTC and
105
+ * render compact local wall-clock time ("2026-08-25 14:23").
106
+ */
107
+ function formatDateTime(raw) {
108
+ const hasZone = /(?:Z|[+-]\d{2}:?\d{2})$/i.test(raw);
109
+ const date = new Date(hasZone ? raw : raw.replace(" ", "T") + "Z");
110
+ if (Number.isNaN(date.getTime())) return raw;
111
+ const pad = (n) => String(n).padStart(2, "0");
112
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;
113
+ }
114
+ /** Open a URL in the default browser, fire-and-forget. */
115
+ function openBrowser(url) {
116
+ spawn(process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open", [url], {
117
+ stdio: "ignore",
118
+ detached: true,
119
+ shell: process.platform === "win32"
120
+ }).on("error", () => {}).unref();
121
+ }
122
+ //#endregion
123
+ export { unwrap as a, requireTty as i, openBrowser as n, reportErrors as r, formatDateTime as t };
@@ -1,5 +1,5 @@
1
1
  import { t as PACKAGE_NAME } from "./version-check-CcsA1QjI.mjs";
2
- import { r as reportErrors } from "./ui-CeupNHNa.mjs";
2
+ import { r as reportErrors } from "./ui-C_jSc1Kz.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-CuES7kPj.mjs");
115
+ const { skillInstalled } = await import("./skill-BWmXiJAz.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());
@@ -1,5 +1,6 @@
1
1
  import { c as resolveProject, o as projectFlagArgs } from "./site-DM2J10CB.mjs";
2
- import { d as withContext, l as apiRequest, r as reportErrors } from "./ui-CeupNHNa.mjs";
2
+ import { i as apiRequest, o as withContext } from "./api-C4rMhE7i.mjs";
3
+ import { r as reportErrors } from "./ui-C_jSc1Kz.mjs";
3
4
  import { defineCommand } from "citty";
4
5
  //#region src/usage.ts
5
6
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mediamonks/canopy-cli",
3
- "version": "0.7.30",
3
+ "version": "0.7.31",
4
4
  "description": "Canopy CLI — create, develop and deploy Canopy projects.",
5
5
  "bin": {
6
6
  "canopy": "./dist/index.mjs"
@@ -16,11 +16,13 @@
16
16
  "dependencies": {
17
17
  "@clack/prompts": "^1.7.0",
18
18
  "@electric-sql/pglite": "^0.3.14",
19
+ "@modelcontextprotocol/client": "^2.3.1",
20
+ "@modelcontextprotocol/server": "^2.3.1",
19
21
  "citty": "^0.2.2",
20
22
  "esbuild": "^0.28.1",
21
23
  "hono": "^4.8.0",
22
24
  "vite-server": "npm:vite@^7",
23
- "@mediamonks/canopy": "0.0.10",
25
+ "@mediamonks/canopy": "0.0.11",
24
26
  "@mediamonks/canopy-data-plane": "0.0.4"
25
27
  },
26
28
  "devDependencies": {
@@ -1,2 +0,0 @@
1
- import { n as devCommand } from "./dev-JlzMZJow.mjs";
2
- export { devCommand };