magic-spells 0.1.0 → 0.2.1

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.
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  operations,
3
3
  operationsByName
4
- } from "./chunk-S5IUP7G2.js";
5
- import "./chunk-YT2Z756Z.js";
4
+ } from "./chunk-4Y3SKWF7.js";
5
+ import "./chunk-ZC4NCQBG.js";
6
6
  export {
7
7
  operations,
8
8
  operationsByName
@@ -3,16 +3,13 @@ import {
3
3
  operationsByName,
4
4
  pyramidError,
5
5
  toPyramidError
6
- } from "./chunk-S5IUP7G2.js";
6
+ } from "./chunk-4Y3SKWF7.js";
7
7
  import {
8
8
  MagicError,
9
9
  TtlCache,
10
- createCredentialStore,
11
- maskKey,
12
10
  readField,
13
- readStr,
14
- saveProductKey
15
- } from "./chunk-YT2Z756Z.js";
11
+ readStr
12
+ } from "./chunk-ZC4NCQBG.js";
16
13
 
17
14
  // ../pyramid/src/cache/resolver.ts
18
15
  var TTL_MS = 6e4;
@@ -890,7 +887,7 @@ var PYRAMID_CREDENTIAL = {
890
887
  var DEFAULT_API_URL = "https://api.pyramid.magicspells.io";
891
888
 
892
889
  // ../pyramid/src/doctor.ts
893
- var whoamiOp = async () => (await import("./operations-P3DUAVPP.js")).operationsByName.get("pyramid.whoami");
890
+ var whoamiOp = async () => (await import("./operations-VJZEQHSW.js")).operationsByName.get("pyramid.whoami");
894
891
  var doctorChecks = [
895
892
  {
896
893
  name: "pyramid auth",
@@ -923,226 +920,6 @@ var doctorChecks = [
923
920
  }
924
921
  ];
925
922
 
926
- // ../pyramid/src/login.ts
927
- import { spawn } from "node:child_process";
928
- import { randomBytes } from "node:crypto";
929
- import { createServer } from "node:http";
930
- var DEFAULT_WEB_URL = "https://pyramid.magicspells.io";
931
- var DEFAULT_LOGIN_TIMEOUT_MS = 2 * 60 * 1e3;
932
- var MAX_CALLBACK_BODY_BYTES = 4 * 1024;
933
- var realIO = {
934
- out: (line) => process.stderr.write(`${line}
935
- `),
936
- setKey: async (key) => {
937
- await saveProductKey(PYRAMID_CREDENTIAL, createCredentialStore(), key);
938
- },
939
- openBrowser,
940
- env: process.env,
941
- randomState: () => randomBytes(24).toString("base64url"),
942
- loginTimeoutMs: DEFAULT_LOGIN_TIMEOUT_MS
943
- };
944
- var LOGIN_USAGE = "usage: magic pyramid login [--web-url <url>] [--name <key name>]";
945
- function parseLoginOptions(argv, env) {
946
- let webUrl = env.MAGIC_PYRAMID_WEB_URL?.trim() || DEFAULT_WEB_URL;
947
- let name = "Magic CLI";
948
- const args = argv;
949
- for (let i = 0; i < args.length; i += 1) {
950
- const arg = args[i];
951
- if (arg === "--help" || arg === "-h") return "help";
952
- if (arg === "--web-url") {
953
- const next = args[++i];
954
- if (!next) return LOGIN_USAGE;
955
- webUrl = next;
956
- continue;
957
- }
958
- if (arg.startsWith("--web-url=")) {
959
- webUrl = arg.slice("--web-url=".length);
960
- continue;
961
- }
962
- if (arg === "--name") {
963
- const next = args[++i];
964
- if (!next) return LOGIN_USAGE;
965
- name = next;
966
- continue;
967
- }
968
- if (arg.startsWith("--name=")) {
969
- name = arg.slice("--name=".length);
970
- continue;
971
- }
972
- return `unknown option for magic pyramid login: ${arg}`;
973
- }
974
- try {
975
- new URL(webUrl);
976
- } catch {
977
- return `MAGIC_PYRAMID_WEB_URL is not a valid URL: "${webUrl}".`;
978
- }
979
- return { webUrl, name: name.trim() || "Magic CLI" };
980
- }
981
- function authURL(webUrl, callbackURL, state, name) {
982
- const target = new URL("/auth/cli", webUrl);
983
- target.searchParams.set("redirect_uri", callbackURL);
984
- target.searchParams.set("state", state);
985
- target.searchParams.set("name", name);
986
- return target.toString();
987
- }
988
- function readCallbackForm(req) {
989
- return new Promise((resolve, reject) => {
990
- const chunks = [];
991
- let size = 0;
992
- const onData = (chunk) => {
993
- size += chunk.length;
994
- if (size > MAX_CALLBACK_BODY_BYTES) {
995
- req.off("data", onData);
996
- req.resume();
997
- resolve(null);
998
- return;
999
- }
1000
- chunks.push(chunk);
1001
- };
1002
- req.on("data", onData);
1003
- req.once("end", () => resolve(new URLSearchParams(Buffer.concat(chunks).toString("utf8"))));
1004
- req.once("error", reject);
1005
- });
1006
- }
1007
- function closeServer(server) {
1008
- return new Promise((resolve) => {
1009
- server.close(() => resolve());
1010
- });
1011
- }
1012
- async function runLogin(argv, io = realIO) {
1013
- const opts = parseLoginOptions(argv, io.env);
1014
- if (opts === "help") {
1015
- io.out(LOGIN_USAGE);
1016
- io.out("Opens Pyramid in the browser and stores the workspace key it mints.");
1017
- return 0;
1018
- }
1019
- if (typeof opts === "string") {
1020
- io.out(opts);
1021
- return 2;
1022
- }
1023
- const state = io.randomState();
1024
- let settled = false;
1025
- let timeout;
1026
- let finish;
1027
- const done = new Promise((resolve) => {
1028
- finish = (code) => {
1029
- if (settled) return;
1030
- settled = true;
1031
- if (timeout) clearTimeout(timeout);
1032
- resolve(code);
1033
- };
1034
- });
1035
- const server = createServer(async (req, res) => {
1036
- const requestURL = new URL(req.url ?? "/", "http://127.0.0.1");
1037
- if (requestURL.pathname !== "/callback") {
1038
- res.writeHead(404, { "content-type": "text/plain; charset=utf-8" });
1039
- res.end("Not found.\n");
1040
- return;
1041
- }
1042
- if (req.method !== "POST" || requestURL.searchParams.has("key")) {
1043
- res.writeHead(405, { "content-type": "text/plain; charset=utf-8", allow: "POST" });
1044
- res.end("Method not allowed. Return to your terminal.\n");
1045
- io.out("Ignored a Pyramid login callback that did not POST the key.");
1046
- return;
1047
- }
1048
- let form;
1049
- try {
1050
- form = await readCallbackForm(req);
1051
- } catch {
1052
- return;
1053
- }
1054
- if (!form) {
1055
- res.writeHead(413, { "content-type": "text/plain; charset=utf-8", connection: "close" });
1056
- res.end("Login callback too large. Return to your terminal.\n");
1057
- io.out("Ignored an oversized Pyramid login callback.");
1058
- return;
1059
- }
1060
- const gotState = form.get("state") ?? "";
1061
- if (gotState !== state) {
1062
- res.writeHead(400, { "content-type": "text/plain; charset=utf-8" });
1063
- res.end("Invalid login state. Return to your terminal.\n");
1064
- io.out("Rejected Pyramid login callback with an invalid state.");
1065
- void closeServer(server).then(() => finish(1));
1066
- return;
1067
- }
1068
- const error = form.get("error");
1069
- if (error) {
1070
- res.writeHead(200, { "content-type": "text/plain; charset=utf-8" });
1071
- res.end("Pyramid login cancelled. Return to your terminal.\n");
1072
- io.out(
1073
- error === "access_denied" ? "Pyramid login cancelled." : `Pyramid login failed: ${error}`
1074
- );
1075
- void closeServer(server).then(() => finish(1));
1076
- return;
1077
- }
1078
- const key = form.get("key")?.trim() ?? "";
1079
- if (!key.startsWith(PYRAMID_CREDENTIAL.credential)) {
1080
- res.writeHead(400, { "content-type": "text/plain; charset=utf-8" });
1081
- res.end("Invalid Pyramid key. Return to your terminal.\n");
1082
- io.out("Pyramid login returned an invalid key.");
1083
- void closeServer(server).then(() => finish(1));
1084
- return;
1085
- }
1086
- try {
1087
- await io.setKey(key);
1088
- } catch (err) {
1089
- res.writeHead(500, { "content-type": "text/plain; charset=utf-8" });
1090
- res.end("Could not store the key. Return to your terminal.\n");
1091
- io.out(
1092
- `Could not store the Pyramid key: ${err instanceof Error ? err.message : String(err)}`
1093
- );
1094
- void closeServer(server).then(() => finish(1));
1095
- return;
1096
- }
1097
- res.writeHead(200, { "content-type": "text/plain; charset=utf-8" });
1098
- res.end("Pyramid CLI connected. You can close this tab.\n");
1099
- io.out(
1100
- `Saved ${maskKey(key, PYRAMID_CREDENTIAL.credential)} \u2014 magic and magic mcp will use it automatically.`
1101
- );
1102
- void closeServer(server).then(() => finish(0));
1103
- });
1104
- try {
1105
- await new Promise((resolve, reject) => {
1106
- server.once("error", reject);
1107
- server.listen(0, "127.0.0.1", () => {
1108
- server.off("error", reject);
1109
- resolve();
1110
- });
1111
- });
1112
- } catch (err) {
1113
- io.out(
1114
- `Could not start the local Pyramid login server: ${err instanceof Error ? err.message : String(err)}`
1115
- );
1116
- return 1;
1117
- }
1118
- const address = server.address();
1119
- const callbackURL = `http://127.0.0.1:${address.port}/callback`;
1120
- const loginURL = authURL(opts.webUrl, callbackURL, state, opts.name);
1121
- timeout = setTimeout(() => {
1122
- io.out("Pyramid login timed out before the browser completed the handoff.");
1123
- void closeServer(server).then(() => finish(1));
1124
- }, io.loginTimeoutMs);
1125
- const opened = await io.openBrowser(loginURL);
1126
- if (opened) {
1127
- io.out("Opened Pyramid in your browser. Authorize the CLI to finish login.");
1128
- } else {
1129
- io.out("Could not open your browser automatically. Open this URL to finish login:");
1130
- io.out(loginURL);
1131
- }
1132
- return done;
1133
- }
1134
- function openBrowser(url) {
1135
- return new Promise((resolve) => {
1136
- const platform = process.platform;
1137
- const command = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
1138
- const args = platform === "win32" ? ["/c", "start", "", url] : [url];
1139
- const child = spawn(command, args, { detached: true, stdio: "ignore" });
1140
- child.once("error", () => resolve(false));
1141
- child.once("close", (code) => resolve(code === 0));
1142
- child.unref();
1143
- });
1144
- }
1145
-
1146
923
  // ../pyramid/src/mcp/prompts.ts
1147
924
  var DOCTOR_DESCRIPTION = "Check your Pyramid setup: confirm the API key authenticates and show the user, workspace, and accessible projects.";
1148
925
  var DOCTOR_INSTRUCTION = [
@@ -1269,8 +1046,10 @@ function registerPyramidMcp(server, context) {
1269
1046
  var pyramid = {
1270
1047
  ...PYRAMID_CREDENTIAL,
1271
1048
  apiUrl: DEFAULT_API_URL,
1049
+ // `magic login` mints workspace keys here from the Account grant (API-PYRAMID-CLI-SESSIONS).
1050
+ sessions: { path: "/v1/cli/sessions" },
1272
1051
  // The operations graph loads only when a Pyramid command runs.
1273
- load: async () => (await import("./operations-P3DUAVPP.js")).operations,
1052
+ load: async () => (await import("./operations-VJZEQHSW.js")).operations,
1274
1053
  client(session, config) {
1275
1054
  const api = new PyramidClient({
1276
1055
  apiKey: session.key,
@@ -1280,12 +1059,6 @@ var pyramid = {
1280
1059
  },
1281
1060
  // `--project` stays a Pyramid flag, usable anywhere in argv (pyramid-cli's global).
1282
1061
  globalFlags: ["project"],
1283
- commands: {
1284
- login: {
1285
- summary: "Sign in through Pyramid in the browser and store a workspace key (until R1)",
1286
- run: (argv) => runLogin(argv)
1287
- }
1288
- },
1289
1062
  doctor: doctorChecks,
1290
1063
  mcp: { instructions, register: registerPyramidMcp }
1291
1064
  };
@@ -0,0 +1,16 @@
1
+ // ../sites/src/index.ts
2
+ var sites = {
3
+ id: "sites",
4
+ title: "Sites",
5
+ credential: "sites_",
6
+ apiUrl: "https://api.sites.magicspells.io",
7
+ keyHelp: "Sites \u2192 Settings \u2192 Access keys",
8
+ sessions: { path: "/v1/cli/sessions" },
9
+ load: async () => [],
10
+ client: () => null
11
+ };
12
+ var src_default = sites;
13
+ export {
14
+ src_default as default,
15
+ sites
16
+ };
@@ -0,0 +1,17 @@
1
+ // ../marketing/src/index.ts
2
+ var marketing = {
3
+ id: "marketing",
4
+ title: "Marketing",
5
+ credential: "marketing_",
6
+ apiUrl: "https://marketing.magicspells.io",
7
+ keyHelp: "Marketing \u2192 Settings \u2192 API keys",
8
+ // Marketing serves its API under /api/v1 on the app host.
9
+ sessions: { path: "/api/v1/cli/sessions" },
10
+ load: async () => [],
11
+ client: () => null
12
+ };
13
+ var src_default = marketing;
14
+ export {
15
+ src_default as default,
16
+ marketing
17
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "magic-spells",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "Magic CLI — one command line and MCP server for Magic Spells' hosted services.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -21,7 +21,7 @@
21
21
  "dependencies": {
22
22
  "@modelcontextprotocol/sdk": "^1.12.0",
23
23
  "undici": "^6.19.0",
24
- "zod": "^3.23.8"
24
+ "zod": "^4.6.7"
25
25
  },
26
26
  "scripts": {
27
27
  "bundle": "node scripts/bundle.mjs",