@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.
- package/dist/{ai-fAvjdjVX.mjs → ai-DHLnyqfq.mjs} +2 -1
- package/dist/{ui-CeupNHNa.mjs → api-C4rMhE7i.mjs} +1 -122
- package/dist/{db-KTLn8J1u.mjs → db-BB6O6085.mjs} +3 -2
- package/dist/{deploy-CBf44bvG.mjs → deploy-B-znPE-v.mjs} +4 -2
- package/dist/{dev-JlzMZJow.mjs → dev-CkhBnSlv.mjs} +13 -6
- package/dist/dev-MoHHjQh1.mjs +2 -0
- package/dist/dev-server-file-Dk9pk4AR.mjs +54 -0
- package/dist/{dev-worker-DjJGSUGj.mjs → dev-worker-CaCsGBkn.mjs} +34 -2
- package/dist/docs/agent-tools.md +213 -0
- package/dist/docs/cli-mcp.md +88 -0
- package/dist/docs/developers-agents-and-ai.md +8 -0
- package/dist/docs/index.json +10 -0
- package/dist/{docs-Dg0UJugG.mjs → docs-YD4z70gq.mjs} +2 -2
- package/dist/{egress-Cn9zDfDT.mjs → egress-If_Gsx_M.mjs} +2 -1
- package/dist/{feedback-Dvb6CdlP.mjs → feedback-Cd7Rvg9a.mjs} +3 -2
- package/dist/index.mjs +32 -29
- package/dist/{local-BA_TPWpN.mjs → local-DAYCNUyz.mjs} +3 -3
- package/dist/{login-MX0xq8UE.mjs → login-B-m-i8uu.mjs} +1 -1
- package/dist/{logs-D5RWqsWl.mjs → logs-DQQOawOG.mjs} +2 -1
- package/dist/mcp-GKwctfHN.mjs +457 -0
- package/dist/{migrations-C8yRPJIX.mjs → migrations-Czlcddyz.mjs} +1 -1
- package/dist/{open-BJgd0R61.mjs → open-DcaQKi1v.mjs} +1 -1
- package/dist/{package-CnS450Yc.mjs → package-CiKTWo0_.mjs} +1 -1
- package/dist/{projects-BG7Injpb.mjs → projects-CN2YhCZn.mjs} +2 -1
- package/dist/{schedule-CLuksxSM.mjs → schedule-C5lMf3ny.mjs} +2 -1
- package/dist/{secrets-Bl3uOx4l.mjs → secrets-BSEjZnxg.mjs} +2 -1
- package/dist/skill/canopy/SKILL.md +7 -0
- package/dist/{skill-CuES7kPj.mjs → skill-BWmXiJAz.mjs} +2 -2
- package/dist/{src-C7zPhbxi.mjs → src-BkACMkol.mjs} +15 -1
- package/dist/{staging-D06zobnf.mjs → staging-BZVty57b.mjs} +2 -1
- package/dist/templates/spa/package.json +1 -1
- package/dist/templates/worker/package.json +1 -1
- package/dist/templates/worker/worker/index.ts +17 -0
- package/dist/{token-C_PFNqcv.mjs → token-HHlUR0CF.mjs} +2 -1
- package/dist/ui-C_jSc1Kz.mjs +123 -0
- package/dist/{upgrade-C8YdSKKd.mjs → upgrade-Cexs9KYX.mjs} +2 -2
- package/dist/{usage-CV7TjTO8.mjs → usage-CUYrWxv0.mjs} +2 -1
- package/package.json +4 -2
- package/dist/dev-DGCu9MjB.mjs +0 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as version } from "./package-
|
|
2
|
-
import { r as reportErrors } from "./ui-
|
|
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 {
|
|
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 {
|
|
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
|
|
@@ -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 {
|
|
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-
|
|
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-
|
|
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 {
|
|
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.
|
|
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.
|
|
25
|
+
"@mediamonks/canopy": "0.0.11",
|
|
24
26
|
"@mediamonks/canopy-data-plane": "0.0.4"
|
|
25
27
|
},
|
|
26
28
|
"devDependencies": {
|
package/dist/dev-DGCu9MjB.mjs
DELETED