@mediamonks/canopy-cli 0.7.3 → 0.7.4
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/docs/troubleshooting.md +13 -0
- package/dist/{docs-BwtpnE8W.mjs → docs-IxKmYx_G.mjs} +1 -1
- package/dist/index.mjs +6 -19
- package/dist/logs-DBLDS3aQ.mjs +109 -0
- package/dist/{package-BjMP21nL.mjs → package-DBEmT6Uh.mjs} +1 -1
- package/dist/{skill-aTr-RQil.mjs → skill-D3MHtg4s.mjs} +1 -1
- package/dist/{upgrade-Dl6DiMhL.mjs → upgrade-PcE6l9uj.mjs} +1 -1
- package/package.json +1 -1
|
@@ -77,6 +77,19 @@ or use dashboard Settings → Outbound hosts. Details and entry rules:
|
|
|
77
77
|
target outbound requests are currently unrestricted, so this error only
|
|
78
78
|
appears on GCP.
|
|
79
79
|
|
|
80
|
+
## The worker returns errors and you can't see why
|
|
81
|
+
|
|
82
|
+
Read its console output instead of adding diagnostic endpoints:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
canopy logs --since 15m
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`console.log` / `console.error` from your deployed worker, straight in the
|
|
89
|
+
terminal; `--follow` tails it live while you reproduce the problem. See
|
|
90
|
+
[canopy logs](https://docs.canopy.website/cli/logs). (On sites without worker log capture the command
|
|
91
|
+
answers `not_supported_on_target`.)
|
|
92
|
+
|
|
80
93
|
## Docs are stale
|
|
81
94
|
|
|
82
95
|
`canopy docs` caches the platform's docs. Force a refresh:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as version } from "./package-
|
|
1
|
+
import { t as version } from "./package-DBEmT6Uh.mjs";
|
|
2
2
|
import { n as siteConfig } from "./site-BUlQR117.mjs";
|
|
3
3
|
import { i as latestKnownVersion, r as compareSemver } from "./version-check-CcsA1QjI.mjs";
|
|
4
4
|
import { n as reportErrors } from "./ui-CpdtK7mt.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-DBEmT6Uh.mjs";
|
|
3
3
|
import { r as siteHeaderLine, t as setInvocationProfile } from "./site-BUlQR117.mjs";
|
|
4
4
|
import { a as notifyOfUpdate, o as runRefresh } from "./version-check-CcsA1QjI.mjs";
|
|
5
5
|
import { defineCommand, runMain } from "citty";
|
|
@@ -15,7 +15,7 @@ import { defineCommand, runMain } from "citty";
|
|
|
15
15
|
* deploy build & deploy assets (+ worker) [phase 1/2]
|
|
16
16
|
* token create|list|revoke deploy tokens for CI [phase 2]
|
|
17
17
|
* db pull|snapshot|restore [phase 2]
|
|
18
|
-
* logs
|
|
18
|
+
* logs [--follow] read the project's worker logs [phase 2]
|
|
19
19
|
* usage AI spend + storage for a project [phase 1]
|
|
20
20
|
* open open the deployed project / dashboard [phase 1]
|
|
21
21
|
*/
|
|
@@ -53,19 +53,6 @@ function takeGlobalProfile(argv) {
|
|
|
53
53
|
const profileFlag = takeGlobalProfile(process.argv);
|
|
54
54
|
if (profileFlag) setInvocationProfile(profileFlag);
|
|
55
55
|
else if (process.env["CANOPY_PROFILE"]) setInvocationProfile(process.env["CANOPY_PROFILE"]);
|
|
56
|
-
/** A roadmap command that has not landed yet (docs/04-roadmap.md). */
|
|
57
|
-
function planned(name, description, phase) {
|
|
58
|
-
return defineCommand({
|
|
59
|
-
meta: {
|
|
60
|
-
name,
|
|
61
|
-
description: `${description} (not implemented yet — Phase ${phase})`
|
|
62
|
-
},
|
|
63
|
-
run() {
|
|
64
|
-
console.error(`canopy ${name}: not implemented yet — lands in Phase ${phase} (docs/04-roadmap.md).`);
|
|
65
|
-
process.exit(1);
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
56
|
const main = defineCommand({
|
|
70
57
|
meta: {
|
|
71
58
|
name: "canopy",
|
|
@@ -91,10 +78,10 @@ const main = defineCommand({
|
|
|
91
78
|
db: () => import("./db-D3RKaLVU.mjs").then((m) => m.dbCommand),
|
|
92
79
|
usage: () => import("./usage-wpew0a2M.mjs").then((m) => m.usageCommand),
|
|
93
80
|
open: () => import("./open-CLSh6oez.mjs").then((m) => m.openCommand),
|
|
94
|
-
docs: () => import("./docs-
|
|
95
|
-
skill: () => import("./skill-
|
|
96
|
-
upgrade: () => import("./upgrade-
|
|
97
|
-
logs:
|
|
81
|
+
docs: () => import("./docs-IxKmYx_G.mjs").then((m) => m.docsCommand),
|
|
82
|
+
skill: () => import("./skill-D3MHtg4s.mjs").then((m) => m.skillCommand),
|
|
83
|
+
upgrade: () => import("./upgrade-PcE6l9uj.mjs").then((m) => m.upgradeCommand),
|
|
84
|
+
logs: () => import("./logs-DBLDS3aQ.mjs").then((m) => m.logsCommand)
|
|
98
85
|
}
|
|
99
86
|
});
|
|
100
87
|
if (process.argv[2] !== "upgrade") notifyOfUpdate(version);
|
|
@@ -0,0 +1,109 @@
|
|
|
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-CpdtK7mt.mjs";
|
|
3
|
+
import { defineCommand } from "citty";
|
|
4
|
+
//#region src/logs.ts
|
|
5
|
+
/**
|
|
6
|
+
* canopy logs — read the project worker's stdout/stderr
|
|
7
|
+
* (GET /v1/projects/:slug/logs, docs/17-worker-logs.md). `--follow` is a
|
|
8
|
+
* polling loop on since=<last ts>; output is stdout-clean for piping.
|
|
9
|
+
*/
|
|
10
|
+
const FOLLOW_INTERVAL_MS = 4e3;
|
|
11
|
+
/** `--since` accepts a duration (30s, 15m, 2h, 1d) or an RFC 3339 timestamp. */
|
|
12
|
+
function parseSince(value, now = Date.now()) {
|
|
13
|
+
const duration = /^(\d+)([smhd])$/.exec(value.trim());
|
|
14
|
+
if (duration) {
|
|
15
|
+
const unitMs = {
|
|
16
|
+
s: 1e3,
|
|
17
|
+
m: 6e4,
|
|
18
|
+
h: 36e5,
|
|
19
|
+
d: 864e5
|
|
20
|
+
}[duration[2]];
|
|
21
|
+
return new Date(now - Number(duration[1]) * unitMs).toISOString();
|
|
22
|
+
}
|
|
23
|
+
const ms = Date.parse(value);
|
|
24
|
+
if (Number.isNaN(ms)) throw new Error(`--since must be a duration (30s, 15m, 2h, 1d) or a timestamp, not ${JSON.stringify(value)}.`);
|
|
25
|
+
return new Date(ms).toISOString();
|
|
26
|
+
}
|
|
27
|
+
/** `SEVERITY ts text` — severity padded so lines column-align. */
|
|
28
|
+
function formatEntry(entry) {
|
|
29
|
+
return `${entry.severity.padEnd(8)} ${entry.ts} ${entry.text}`;
|
|
30
|
+
}
|
|
31
|
+
async function fetchLogs(slug, params) {
|
|
32
|
+
const query = new URLSearchParams({ channel: params.channel });
|
|
33
|
+
if (params.since) query.set("since", params.since);
|
|
34
|
+
if (params.limit) query.set("limit", String(params.limit));
|
|
35
|
+
return withContext(apiRequest("GET", `/projects/${slug}/logs?${query}`), {
|
|
36
|
+
action: `read worker logs for "${slug}"`,
|
|
37
|
+
fixes: { not_supported_on_target: "Worker logs aren't available on this site yet — GCP sites only." }
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const logsCommand = defineCommand({
|
|
41
|
+
meta: {
|
|
42
|
+
name: "logs",
|
|
43
|
+
description: "Show the project worker's logs (stdout/stderr)"
|
|
44
|
+
},
|
|
45
|
+
args: {
|
|
46
|
+
...projectFlagArgs,
|
|
47
|
+
staging: {
|
|
48
|
+
type: "boolean",
|
|
49
|
+
default: false,
|
|
50
|
+
description: "Read the staging channel's worker instead of live"
|
|
51
|
+
},
|
|
52
|
+
since: {
|
|
53
|
+
type: "string",
|
|
54
|
+
description: "How far back to read: a duration (30s, 15m, 2h, 1d) or a timestamp",
|
|
55
|
+
default: "1h"
|
|
56
|
+
},
|
|
57
|
+
limit: {
|
|
58
|
+
type: "string",
|
|
59
|
+
description: "Max entries to print (1–1000)",
|
|
60
|
+
default: "100"
|
|
61
|
+
},
|
|
62
|
+
follow: {
|
|
63
|
+
type: "boolean",
|
|
64
|
+
alias: "f",
|
|
65
|
+
default: false,
|
|
66
|
+
description: "Keep polling for new entries (Ctrl-C to stop)"
|
|
67
|
+
},
|
|
68
|
+
json: {
|
|
69
|
+
type: "boolean",
|
|
70
|
+
default: false,
|
|
71
|
+
description: "Print entries as JSON lines instead of formatted text"
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
run: reportErrors("logs", async ({ args }) => {
|
|
75
|
+
const { slug } = resolveProject(args);
|
|
76
|
+
const channel = args.staging ? "staging" : "live";
|
|
77
|
+
const limit = Number(args.limit);
|
|
78
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 1e3) throw new Error("--limit must be an integer between 1 and 1000.");
|
|
79
|
+
let since = parseSince(args.since);
|
|
80
|
+
const print = (entries) => {
|
|
81
|
+
for (const entry of entries) console.log(args.json ? JSON.stringify(entry) : formatEntry(entry));
|
|
82
|
+
};
|
|
83
|
+
const initial = [...(await fetchLogs(slug, {
|
|
84
|
+
channel,
|
|
85
|
+
since,
|
|
86
|
+
limit
|
|
87
|
+
})).entries].reverse();
|
|
88
|
+
print(initial);
|
|
89
|
+
if (!args.follow) {
|
|
90
|
+
if (initial.length === 0) console.error(`No log entries since ${since} — is the worker getting traffic?`);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
console.error(`Following ${slug}${channel === "staging" ? " [staging]" : ""}… (Ctrl-C to stop)`);
|
|
94
|
+
let lastTs = initial.at(-1)?.ts ?? since;
|
|
95
|
+
for (;;) {
|
|
96
|
+
await new Promise((resolve) => setTimeout(resolve, FOLLOW_INTERVAL_MS));
|
|
97
|
+
const fresh = [...(await fetchLogs(slug, {
|
|
98
|
+
channel,
|
|
99
|
+
since: lastTs,
|
|
100
|
+
limit: 1e3
|
|
101
|
+
})).entries].reverse().filter((e) => e.ts > lastTs);
|
|
102
|
+
if (fresh.length === 0) continue;
|
|
103
|
+
print(fresh);
|
|
104
|
+
lastTs = fresh.at(-1).ts;
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
});
|
|
108
|
+
//#endregion
|
|
109
|
+
export { logsCommand };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as version } from "./package-
|
|
1
|
+
import { t as version } from "./package-DBEmT6Uh.mjs";
|
|
2
2
|
import { n as reportErrors } from "./ui-CpdtK7mt.mjs";
|
|
3
3
|
import { defineCommand } from "citty";
|
|
4
4
|
import { cpSync, existsSync, mkdirSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
|
|
@@ -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-D3MHtg4s.mjs");
|
|
116
116
|
const refreshSkill = skillInstalled(process.cwd());
|
|
117
117
|
console.log(`Upgrading via ${command}: ${command} ${cmd.join(" ")}`);
|
|
118
118
|
await run(command, cmd);
|