@weave-framework/cli 0.2.53 → 0.2.162

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/README.md ADDED
@@ -0,0 +1,21 @@
1
+ # @weave-framework/cli
2
+
3
+ The Weave CLI — `weave build`, `weave dev` (watch + live-reload), `weave check`, `weave routes`.
4
+
5
+ Part of **[Weave](https://weaveframework.dev/)** — a fine-grained reactive, signal-native UI framework: no Virtual DOM, zero third-party runtime dependencies.
6
+
7
+ ```bash
8
+ npm install -D @weave-framework/cli
9
+ ```
10
+
11
+ Scaffolded apps already include it (with scripts wired up):
12
+
13
+ ```bash
14
+ npm create weave@latest my-app
15
+ ```
16
+
17
+ 📚 **Guides + full API reference:** [weaveframework.dev](https://weaveframework.dev/)
18
+
19
+ ## License
20
+
21
+ MIT
package/bin/weave.mjs CHANGED
@@ -23,6 +23,9 @@ await esbuild({
23
23
  bundle: true,
24
24
  format: 'esm',
25
25
  platform: 'node',
26
+ // NB: @weave-framework/mcp stays INLINED in the dev bin (unlike the prod build, which
27
+ // externalizes it) — the dev bundle runs from node_modules/.weave/, whose module
28
+ // resolution can't reach the workspace-linked package, so we bundle it in.
26
29
  external: ['esbuild', 'typescript', 'sass'],
27
30
  outfile: out,
28
31
  });
package/dist/cli.js CHANGED
@@ -507,6 +507,9 @@ var Parser = class {
507
507
  if (rawName.startsWith("class:")) {
508
508
  return { type: "class", name: rawName.slice(6), expr: exprOf(), offset };
509
509
  }
510
+ if (rawName.startsWith("style:")) {
511
+ return { type: "style", name: rawName.slice(6), expr: exprOf(), offset };
512
+ }
510
513
  if (rawName.startsWith("bind:")) {
511
514
  return { type: "bind", name: rawName.slice(5), expr: exprOf(), offset };
512
515
  }
@@ -741,10 +744,11 @@ function rewrite(expr, scope, ctxRef = "ctx") {
741
744
  const name = expr.slice(i, j);
742
745
  const isProperty = lastNonSpace(out) === ".";
743
746
  const binding = scope.get(name);
744
- if (binding && !isProperty) {
747
+ const prev = lastNonSpace(out);
748
+ const next = firstNonSpaceFrom(expr, j);
749
+ const isObjectKey = (prev === "{" || prev === ",") && next === ":";
750
+ if (binding && !isProperty && !isObjectKey) {
745
751
  if (binding.kind !== "local") {
746
- const prev = lastNonSpace(out);
747
- const next = firstNonSpaceFrom(expr, j);
748
752
  if ((prev === "{" || prev === ",") && (next === "," || next === "}")) insert(`${name}: `);
749
753
  }
750
754
  if (binding.kind === "ctx") {
@@ -943,8 +947,11 @@ function freeIdentifiers(expr) {
943
947
  let j = i + 1;
944
948
  while (j < n && ID_CHAR.test(expr[j])) j++;
945
949
  const name = expr.slice(i, j);
946
- const isProperty = lastNonSpace(expr.slice(0, i)) === ".";
947
- if (!isProperty && !NON_CTX.has(name) && !params.has(name)) out.add(name);
950
+ const prev = lastNonSpace(expr.slice(0, i));
951
+ const next = firstNonSpaceFrom(expr, j);
952
+ const isProperty = prev === ".";
953
+ const isObjectKey = (prev === "{" || prev === ",") && next === ":";
954
+ if (!isProperty && !isObjectKey && !NON_CTX.has(name) && !params.has(name)) out.add(name);
948
955
  i = j;
949
956
  continue;
950
957
  }
@@ -978,6 +985,8 @@ var Gen = class {
978
985
  // @weave-framework/runtime/dom helpers
979
986
  usedCore = /* @__PURE__ */ new Set();
980
987
  // @weave-framework/runtime primitives (computed, …)
988
+ usedComponents = /* @__PURE__ */ new Set();
989
+ // PascalCase child tags referenced in module mode
981
990
  templates = [];
982
991
  tplN = 0;
983
992
  fnN = 0;
@@ -989,13 +998,19 @@ var Gen = class {
989
998
  this.usedCore.add(name);
990
999
  return this.mode === "function" ? `rt.${name}` : name;
991
1000
  }
992
- /** Reference a child component: from the `_c` map in function mode, bare (imported) in module mode. */
1001
+ /**
1002
+ * Reference a child component: from the `_c` map in function mode, bare (imported)
1003
+ * in module mode. In module mode the bare identifier must be in the emitted module's
1004
+ * scope — the loader resolves each recorded tag to a real `import` (see the plugin's
1005
+ * child-import injection), or the component's own `<script>` imports it explicitly.
1006
+ */
993
1007
  Comp(name) {
1008
+ this.usedComponents.add(name);
994
1009
  return this.mode === "function" ? `_c.${name}` : name;
995
1010
  }
996
- tpl(html) {
1011
+ tpl(html, svg = false) {
997
1012
  const v = `_t${this.tplN++}`;
998
- this.templates.push(`const ${v} = ${this.H("template")}(${JSON.stringify(html)});`);
1013
+ this.templates.push(`const ${v} = ${this.H(svg ? "templateSvg" : "template")}(${JSON.stringify(html)});`);
999
1014
  return v;
1000
1015
  }
1001
1016
  fn(prefix = "_b") {
@@ -1008,15 +1023,79 @@ function compileTemplate(input, options = {}) {
1008
1023
  const gen = new Gen(mode, options.scopeAttr, options.hostAttr);
1009
1024
  const ast = parseTemplate(input);
1010
1025
  const render = compileFragment(gen, ast, ctxScope(options.scope ?? []), "render", "ctx, slots", true);
1026
+ const components = [...gen.usedComponents];
1011
1027
  if (mode === "function") {
1012
1028
  const body = [...gen.templates, render, "return render(ctx, {});"].join("\n");
1013
- return { code: body };
1029
+ return { code: body, components };
1014
1030
  }
1015
1031
  const domImport = `import { ${[...gen.used].sort().join(", ")} } from ${JSON.stringify(runtimeImport)};`;
1016
1032
  const coreImport = gen.usedCore.size ? `import { ${[...gen.usedCore].sort().join(", ")} } from "@weave-framework/runtime";
1017
1033
  ` : "";
1018
1034
  const code = [domImport + "\n" + coreImport, ...gen.templates, `export default ${render}`].join("\n");
1019
- return { code };
1035
+ return { code, components };
1036
+ }
1037
+ var SVG_TAGS = /* @__PURE__ */ new Set([
1038
+ "path",
1039
+ "rect",
1040
+ "circle",
1041
+ "ellipse",
1042
+ "line",
1043
+ "polyline",
1044
+ "polygon",
1045
+ "g",
1046
+ "defs",
1047
+ "use",
1048
+ "symbol",
1049
+ "marker",
1050
+ "mask",
1051
+ "pattern",
1052
+ "clipPath",
1053
+ "linearGradient",
1054
+ "radialGradient",
1055
+ "stop",
1056
+ "image",
1057
+ "foreignObject",
1058
+ "text",
1059
+ "tspan",
1060
+ "textPath",
1061
+ "desc",
1062
+ "view",
1063
+ "filter",
1064
+ "feBlend",
1065
+ "feColorMatrix",
1066
+ "feComponentTransfer",
1067
+ "feComposite",
1068
+ "feConvolveMatrix",
1069
+ "feDiffuseLighting",
1070
+ "feDisplacementMap",
1071
+ "feDropShadow",
1072
+ "feFlood",
1073
+ "feFuncA",
1074
+ "feFuncB",
1075
+ "feFuncG",
1076
+ "feFuncR",
1077
+ "feGaussianBlur",
1078
+ "feImage",
1079
+ "feMerge",
1080
+ "feMergeNode",
1081
+ "feMorphology",
1082
+ "feOffset",
1083
+ "feSpecularLighting",
1084
+ "feTile",
1085
+ "feTurbulence",
1086
+ "animate",
1087
+ "animateMotion",
1088
+ "animateTransform",
1089
+ "mpath",
1090
+ "set"
1091
+ ]);
1092
+ var TRANSITION_PHASES = /* @__PURE__ */ new Set(["enterstart", "enterend", "leavestart", "leaveend"]);
1093
+ function pascalToKebab(tag) {
1094
+ return tag.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").toLowerCase();
1095
+ }
1096
+ function childImportCandidates(tag) {
1097
+ const k = pascalToKebab(tag);
1098
+ return [`../${k}/${k}`, `./${k}`, `./${k}/${k}`];
1020
1099
  }
1021
1100
  function compileFragment(gen, nodes, scope, name, param = "", isHost = false) {
1022
1101
  const top = trimTop(nodes);
@@ -1180,6 +1259,9 @@ function compileFragment(gen, nodes, scope, name, param = "", isHost = false) {
1180
1259
  case "class":
1181
1260
  sink.push(`${gen.H("bindClass")}(${n}, ${q(attr.name)}, () => ${rewrite(attr.expr, sc).code});`);
1182
1261
  break;
1262
+ case "style":
1263
+ sink.push(`${gen.H("bindStyleProp")}(${n}, ${q(attr.name)}, () => ${rewrite(attr.expr, sc).code});`);
1264
+ break;
1183
1265
  case "show":
1184
1266
  sink.push(`${gen.H("bindShow")}(${n}, () => ${rewrite(attr.expr, sc).code});`);
1185
1267
  break;
@@ -1190,6 +1272,10 @@ function compileFragment(gen, nodes, scope, name, param = "", isHost = false) {
1190
1272
  break;
1191
1273
  }
1192
1274
  case "event": {
1275
+ if (TRANSITION_PHASES.has(attr.name)) {
1276
+ sink.push(`${gen.H("transitionEvent")}(${n}, ${q(attr.name)}, ${rewrite(attr.expr, sc).code});`);
1277
+ break;
1278
+ }
1193
1279
  const handler = wrapHandler(attr, sc);
1194
1280
  const opts = eventOpts(attr.modifiers);
1195
1281
  sink.push(`${gen.H("listen")}(${n}, ${q(attr.name)}, ${handler}${opts ? `, ${opts}` : ""});`);
@@ -1201,7 +1287,7 @@ function compileFragment(gen, nodes, scope, name, param = "", isHost = false) {
1201
1287
  case "use": {
1202
1288
  const action = rewrite(attr.name, sc).code;
1203
1289
  sink.push(
1204
- attr.expr !== void 0 ? `${gen.H("applyAction")}(${n}, ${action}, ${rewrite(attr.expr, sc).code});` : `${gen.H("applyAction")}(${n}, ${action});`
1290
+ attr.expr !== void 0 ? `${gen.H("applyAction")}(${n}, ${action}, () => ${rewrite(attr.expr, sc).code});` : `${gen.H("applyAction")}(${n}, ${action});`
1205
1291
  );
1206
1292
  break;
1207
1293
  }
@@ -1384,8 +1470,10 @@ function compileFragment(gen, nodes, scope, name, param = "", isHost = false) {
1384
1470
  }
1385
1471
  if (singleRoot) emitElement(sole, [], scope, isHost);
1386
1472
  else emitChildren(top, [], scope, isHost);
1473
+ const topEls = top.filter((n) => n.type === "element");
1474
+ const svgRoot = topEls.length > 0 && SVG_TAGS.has(topEls[0].tag);
1387
1475
  const ctor = singleRoot ? gen.H("clone") : gen.H("cloneFragment");
1388
- const tplVar = gen.tpl(html);
1476
+ const tplVar = gen.tpl(html, svgRoot);
1389
1477
  const body = [
1390
1478
  `const _r = ${ctor}(${tplVar});`,
1391
1479
  ...nodeDecls,
@@ -1852,7 +1940,7 @@ function compileComponent(src, opts = {}) {
1852
1940
  renderBody,
1853
1941
  `export default defineComponent(${setupArg});`
1854
1942
  ].filter(Boolean).join("\n\n");
1855
- return { code, css, hash };
1943
+ return { code, css, hash, components: compiled.components };
1856
1944
  }
1857
1945
  function parseSfcLoc(source) {
1858
1946
  const script = locateBlock(source, "script");
@@ -1916,7 +2004,7 @@ function extractBlock(source, tag) {
1916
2004
  }
1917
2005
 
1918
2006
  // packages/compiler/src/sources.ts
1919
- var DECL = /export\s+const\s+(template|styles)\s*(?::[^=]+)?=\s*/g;
2007
+ var DECL = /export\s+const\s+(template|styles)\s*(?::[^=\n]+)?=\s*/g;
1920
2008
  function extractSources(script) {
1921
2009
  let template;
1922
2010
  let templateRange;
@@ -1948,10 +2036,30 @@ function extractSources(script) {
1948
2036
  function parseLiteral(src, i, kind) {
1949
2037
  i = skipWs(src, i);
1950
2038
  const c = src[i];
1951
- if (c === '"' || c === "'" || c === "`") return parseString(src, i);
2039
+ if (c === '"' || c === "'" || c === "`") return parseConcat(src, i);
1952
2040
  if (c === "[") return parseArray(src, i);
1953
2041
  throw new Error(`weave: \`${kind}\` must be a static string${kind === "styles" ? " or array of strings" : ""}`);
1954
2042
  }
2043
+ function parseConcat(src, i) {
2044
+ const first = parseString(src, i);
2045
+ let value = first.value;
2046
+ let end = first.end;
2047
+ let single = true;
2048
+ for (; ; ) {
2049
+ const plus = skipWs(src, end);
2050
+ if (src[plus] !== "+") break;
2051
+ const nextStart = skipWs(src, plus + 1);
2052
+ const c = src[nextStart];
2053
+ if (c !== '"' && c !== "'" && c !== "`") {
2054
+ throw new Error("weave: `template`/`styles` must be a static string \u2014 `+` may only join string literals");
2055
+ }
2056
+ const next = parseString(src, nextStart);
2057
+ value += next.value;
2058
+ end = next.end;
2059
+ single = false;
2060
+ }
2061
+ return single ? { value, end, innerStart: first.innerStart, innerEnd: first.innerEnd } : { value, end };
2062
+ }
1955
2063
  function parseString(src, i) {
1956
2064
  const quote = src[i];
1957
2065
  const innerStart = i + 1;
@@ -1983,7 +2091,7 @@ function parseArray(src, i) {
1983
2091
  j++;
1984
2092
  continue;
1985
2093
  }
1986
- const str = parseString(src, j);
2094
+ const str = parseConcat(src, j);
1987
2095
  items.push(str.value);
1988
2096
  j = str.end;
1989
2097
  }
@@ -2028,15 +2136,18 @@ function langFromExt(file) {
2028
2136
  if (file.endsWith(".sass")) return "sass";
2029
2137
  return "css";
2030
2138
  }
2139
+ function pkgImporters(sass) {
2140
+ return [new sass.NodePackageImporter()];
2141
+ }
2031
2142
  async function compileStyleFile(path) {
2032
2143
  if (langFromExt(path) === "css") return readFile(path, "utf8");
2033
2144
  const sass = await import("sass");
2034
- return sass.compile(path).css;
2145
+ return sass.compile(path, { importers: pkgImporters(sass) }).css;
2035
2146
  }
2036
2147
  async function compileStyleFileTracked(path) {
2037
2148
  if (langFromExt(path) === "css") return { css: await readFile(path, "utf8"), files: [path] };
2038
2149
  const sass = await import("sass");
2039
- const result = sass.compile(path);
2150
+ const result = sass.compile(path, { importers: pkgImporters(sass) });
2040
2151
  const files = result.loadedUrls.filter((u) => u.protocol === "file:").map((u) => fileURLToPath(u));
2041
2152
  return { css: result.css, files };
2042
2153
  }
@@ -2045,15 +2156,24 @@ async function compileStyleSource(source, lang, fromDir) {
2045
2156
  const sass = await import("sass");
2046
2157
  return sass.compileString(source, {
2047
2158
  syntax: lang === "sass" ? "indented" : "scss",
2048
- loadPaths: fromDir ? [fromDir] : []
2159
+ loadPaths: fromDir ? [fromDir] : [],
2160
+ importers: pkgImporters(sass)
2049
2161
  }).css;
2050
2162
  }
2051
2163
 
2052
2164
  // packages/cli/src/plugin.ts
2165
+ function styleId(css) {
2166
+ let h = 5381;
2167
+ for (let i = 0; i < css.length; i++) h = Math.imul(h, 33) ^ css.charCodeAt(i) | 0;
2168
+ return "w-css-" + (h >>> 0).toString(36);
2169
+ }
2053
2170
  function cssInjector(css) {
2054
2171
  if (!css) return "";
2172
+ const id = styleId(css);
2055
2173
  return `
2056
- ;(()=>{const s=document.createElement("style");s.textContent=${JSON.stringify(
2174
+ ;(()=>{const id=${JSON.stringify(
2175
+ id
2176
+ )};if(document.getElementById(id))return;const s=document.createElement("style");s.id=id;s.textContent=${JSON.stringify(
2057
2177
  css
2058
2178
  )};document.head.appendChild(s);})();
2059
2179
  `;
@@ -2100,6 +2220,78 @@ async function resolveStyles(decl, tsPath, dir, styleLang) {
2100
2220
  const compiled = await compileStyleFileTracked(siblingStyle);
2101
2221
  return { css: compiled.css, files: compiled.files };
2102
2222
  }
2223
+ function stripComments(code) {
2224
+ let out = "";
2225
+ let i = 0;
2226
+ const n = code.length;
2227
+ while (i < n) {
2228
+ const c = code[i];
2229
+ const d = code[i + 1];
2230
+ if (c === '"' || c === "'" || c === "`") {
2231
+ const quote = c;
2232
+ out += c;
2233
+ i++;
2234
+ while (i < n) {
2235
+ const ch = code[i];
2236
+ if (ch === "\\") {
2237
+ out += ch + (code[i + 1] ?? "");
2238
+ i += 2;
2239
+ continue;
2240
+ }
2241
+ out += ch;
2242
+ i++;
2243
+ if (ch === quote) break;
2244
+ }
2245
+ continue;
2246
+ }
2247
+ if (c === "/" && d === "/") {
2248
+ while (i < n && code[i] !== "\n") i++;
2249
+ continue;
2250
+ }
2251
+ if (c === "/" && d === "*") {
2252
+ i += 2;
2253
+ while (i < n && !(code[i] === "*" && code[i + 1] === "/")) i++;
2254
+ i += 2;
2255
+ continue;
2256
+ }
2257
+ out += c;
2258
+ i++;
2259
+ }
2260
+ return out;
2261
+ }
2262
+ function importsBinding(script, name) {
2263
+ if (!script) return false;
2264
+ const code = stripComments(script);
2265
+ const word = new RegExp(`\\b${name}\\b`);
2266
+ const IMPORT = /import\s+([^;]*?)\s+from\s+['"][^'"]+['"]/g;
2267
+ let m;
2268
+ while ((m = IMPORT.exec(code)) !== null) {
2269
+ if (word.test(m[1])) return true;
2270
+ }
2271
+ return false;
2272
+ }
2273
+ function resolveChildModule(tag, dir) {
2274
+ for (const cand of childImportCandidates(tag)) {
2275
+ for (const ext of [".ts", ".weave"]) {
2276
+ if (existsSync(resolve(dir, cand + ext))) return cand;
2277
+ }
2278
+ }
2279
+ return null;
2280
+ }
2281
+ function injectChildImports(code, components, dir, script, filename) {
2282
+ const imports = [];
2283
+ for (const tag of components) {
2284
+ if (importsBinding(script, tag)) continue;
2285
+ const cand = resolveChildModule(tag, dir);
2286
+ if (cand === null) {
2287
+ throw new Error(
2288
+ `weave: ${filename} composes <${tag}> but no import for it was found. Import it in the component's script, or place its module at ${childImportCandidates(tag).map((c) => `${c}.ts`).join(" / ")} (relative to the component).`
2289
+ );
2290
+ }
2291
+ imports.push(`import ${tag} from ${JSON.stringify(cand + ".js")};`);
2292
+ }
2293
+ return imports.length ? imports.join("\n") + "\n" + code : code;
2294
+ }
2103
2295
  function weave(state, options = {}) {
2104
2296
  const styleLang = options.styleLang ?? "css";
2105
2297
  const dev2 = options.dev ?? false;
@@ -2118,8 +2310,9 @@ function weave(state, options = {}) {
2118
2310
  const source = await readFile2(args.path, "utf8");
2119
2311
  const src = parseSfc(source);
2120
2312
  const styles = src.styles ? await compileStyleSource(src.styles, styleLang, dirname(args.path)) : void 0;
2121
- const { code, css } = compileComponent({ ...src, styles }, { filename: args.path });
2122
- return emit2(code, css, dirname(args.path));
2313
+ const { code, css, components } = compileComponent({ ...src, styles }, { filename: args.path });
2314
+ const wired = injectChildImports(code, components, dirname(args.path), src.script, args.path);
2315
+ return emit2(wired, css, dirname(args.path));
2123
2316
  });
2124
2317
  build2.onLoad({ filter: /\.ts$/ }, async (args) => {
2125
2318
  if (args.path.includes("node_modules")) return void 0;
@@ -2142,11 +2335,12 @@ function weave(state, options = {}) {
2142
2335
  dir,
2143
2336
  styleLang
2144
2337
  );
2145
- const { code, css } = compileComponent(
2338
+ const { code, css, components } = compileComponent(
2146
2339
  { script: decl.script, template: template.text, styles: styles.css },
2147
2340
  { filename: args.path }
2148
2341
  );
2149
- return { ...emit2(code, css, dir), watchFiles: [...template.files, ...styles.files] };
2342
+ const wired = injectChildImports(code, components, dir, decl.script, args.path);
2343
+ return { ...emit2(wired, css, dir), watchFiles: [...template.files, ...styles.files] };
2150
2344
  });
2151
2345
  }
2152
2346
  };
@@ -2309,7 +2503,7 @@ async function build(config) {
2309
2503
  import { context } from "esbuild";
2310
2504
  import { createServer } from "node:http";
2311
2505
  import { mkdir as mkdir2, writeFile as writeFile2, readFile as readFile4 } from "node:fs/promises";
2312
- import { join as join3, extname, relative as relative2, sep as sep2 } from "node:path";
2506
+ import { join as join3, extname, relative as relative2, sep as sep2, isAbsolute } from "node:path";
2313
2507
  var RELOAD_PATH = "/__weave_reload";
2314
2508
  var MIME = {
2315
2509
  ".html": "text/html; charset=utf-8",
@@ -2336,7 +2530,7 @@ async function devInMemory(config) {
2336
2530
  const css = (await Promise.all(config.styles.map(compileStyleFile))).join("\n");
2337
2531
  if (css)
2338
2532
  banner = {
2339
- js: `(()=>{const s=document.createElement("style");s.textContent=${JSON.stringify(
2533
+ js: `(()=>{const id="w-global-styles";if(document.getElementById(id))return;const s=document.createElement("style");s.id=id;s.textContent=${JSON.stringify(
2340
2534
  css
2341
2535
  )};document.head.appendChild(s);})();`
2342
2536
  };
@@ -2401,8 +2595,15 @@ async function handleRequest(req, res, config, outputs, clients) {
2401
2595
  return;
2402
2596
  }
2403
2597
  if (extname(url)) {
2598
+ const target = join3(config.servedir, url);
2599
+ const rel = relative2(config.servedir, target);
2600
+ if (rel === ".." || rel.startsWith(".." + sep2) || isAbsolute(rel)) {
2601
+ res.writeHead(403);
2602
+ res.end("Forbidden");
2603
+ return;
2604
+ }
2404
2605
  try {
2405
- const buf = await readFile4(join3(config.servedir, url));
2606
+ const buf = await readFile4(target);
2406
2607
  res.writeHead(200, { "content-type": mime(url) });
2407
2608
  res.end(buf);
2408
2609
  } catch {
@@ -2604,7 +2805,7 @@ function generateRoutes(dir, opts = {}) {
2604
2805
  import { build as esbuildBuild } from "esbuild";
2605
2806
  import { existsSync as existsSync4 } from "node:fs";
2606
2807
  import { readFile as readFile5 } from "node:fs/promises";
2607
- import { resolve as resolve2, dirname as dirname2, join as join5, isAbsolute } from "node:path";
2808
+ import { resolve as resolve2, dirname as dirname2, join as join5, isAbsolute as isAbsolute2 } from "node:path";
2608
2809
  function defineConfig(config) {
2609
2810
  return config;
2610
2811
  }
@@ -2648,7 +2849,7 @@ async function importConfigModule(file) {
2648
2849
  return mod.default ?? mod;
2649
2850
  }
2650
2851
  function resolveConfig(raw, root) {
2651
- const abs = (p) => isAbsolute(p) ? p : resolve2(root, p);
2852
+ const abs = (p) => isAbsolute2(p) ? p : resolve2(root, p);
2652
2853
  if (!raw.root && !raw.entry) {
2653
2854
  throw new Error("weave: config must declare either `root` (generated bootstrap) or `entry` (hand-written)");
2654
2855
  }
@@ -3201,8 +3402,21 @@ weave check: ${errors} error${errors === 1 ? "" : "s"}`);
3201
3402
  console.log(`weave routes \u2192 ${written}`);
3202
3403
  return;
3203
3404
  }
3405
+ if (cmd === "mcp") {
3406
+ try {
3407
+ const mcp = await import("@weave-framework/mcp");
3408
+ await mcp.runStdioServer();
3409
+ } catch (e) {
3410
+ console.error(
3411
+ `weave mcp: could not start the MCP server \u2014 is @weave-framework/mcp installed?
3412
+ ${e?.message ?? String(e)}`
3413
+ );
3414
+ process.exit(1);
3415
+ }
3416
+ return;
3417
+ }
3204
3418
  console.error(
3205
- "usage: weave <build|dev|check|routes> [entry|paths\u2026] [--config file] [--out dir] [--serve dir] [--port n] [--no-minify] [--eager]"
3419
+ "usage: weave <build|dev|check|routes|mcp> [entry|paths\u2026] [--config file] [--out dir] [--serve dir] [--port n] [--no-minify] [--eager]"
3206
3420
  );
3207
3421
  process.exit(1);
3208
3422
  }
package/dist/styles.d.ts CHANGED
@@ -10,7 +10,7 @@
10
10
  export type StyleLang = 'css' | 'scss' | 'sass';
11
11
  /** The style language implied by a file extension (defaults to plain CSS). */
12
12
  export declare function langFromExt(file: string): StyleLang;
13
- /** Compile a style FILE to CSS — `@use`/`@import` resolve relative to it. */
13
+ /** Compile a style FILE to CSS — `@use`/`@import` resolve relative to it (+ `pkg:` packages). */
14
14
  export declare function compileStyleFile(path: string): Promise<string>;
15
15
  /**
16
16
  * Like {@link compileStyleFile} but also reports every file the compile pulled in —
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weave-framework/cli",
3
- "version": "0.2.53",
3
+ "version": "0.2.162",
4
4
  "description": "Weave CLI — `weave build`, `weave dev` (watch + live-reload), `weave check`, `weave routes`.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -31,7 +31,8 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "esbuild": "^0.25.0",
34
- "typescript": "^5.7.0"
34
+ "typescript": "^5.7.0",
35
+ "@weave-framework/mcp": "0.2.162"
35
36
  },
36
37
  "optionalDependencies": {
37
38
  "sass": "^1.0.0"