@loomweaver/mcp 0.7.2 → 0.7.3

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 (3) hide show
  1. package/README.md +0 -4
  2. package/dist/main.mjs +161 -67
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -14,10 +14,6 @@ is not inside this repo (a chat assistant, a remote client) can scaffold and val
14
14
 
15
15
  ## Consume from npm (product repos)
16
16
 
17
- > **Availability:** the `@loomweaver/*` packages are not on the public npm registry yet — the first
18
- > public release publishes them. Until then they come from LoomWeaver's own package feed, and
19
- > `npx` needs that registry configured for the `@loomweaver` scope.
20
-
21
17
  `@loomweaver/mcp` ships as a self-contained bundle (devkit + the MCP SDK are inlined — no transitive
22
18
  install). A product repo that already consumes `@loomweaver/shell` / `@loomweaver/plugin-sdk` just adds the
23
19
  server to its `.mcp.json`; `npx` fetches the bundle and starts the stdio server:
package/dist/main.mjs CHANGED
@@ -31012,6 +31012,36 @@ function generate(recipe, input) {
31012
31012
  }
31013
31013
  return files;
31014
31014
  }
31015
+ function amendments(recipe, input) {
31016
+ return recipe.amend?.(input) ?? [];
31017
+ }
31018
+
31019
+ // ../devkit/src/lib/amend/describe.ts
31020
+ function describeAmendment(amendment) {
31021
+ if (amendment.kind === "postcss") {
31022
+ return `Write ${amendment.file} beside your package.json, naming ${amendment.plugin}. Without it the stylesheet is read as plain CSS: no utility class is emitted, the workbench renders unstyled, and the build still reports success.`;
31023
+ }
31024
+ if (amendment.kind === "stylesheet-source") {
31025
+ return `Add an @source entry for '${amendment.sourceRoot}' to the application's entry stylesheet, resolved from that stylesheet. Without it none of that code's utilities are emitted.`;
31026
+ }
31027
+ if (amendment.kind === "compose-plugin") {
31028
+ return `Register ${amendment.id} in the composition root: import { ${amendment.symbol} }, provideTranslationNamespaces('${amendment.id}'), provideCapabilityGrants({ ${amendment.id}: [${amendment.capabilities.map((capability) => `'${capability}'`).join(
31029
+ ", "
31030
+ )}] }) and ...providePlugins(${amendment.symbol}). Without it none of its contributions appear.`;
31031
+ }
31032
+ return [
31033
+ ...amendment.styles.length > 0 ? [`name ${amendment.styles.join(", ")} in styles`] : [],
31034
+ ...amendment.assets.length > 0 ? [
31035
+ `add assets for ${amendment.assets.map((asset) => asset.input).join(", ")} (the shell fetches its own strings at runtime, so without that glob every label in the chrome renders as its raw translation key)`
31036
+ ] : [],
31037
+ ...amendment.serviceWorker ? [
31038
+ `set serviceWorker to ${amendment.serviceWorker} in the production configuration (provideShell registers a worker that 404s otherwise)`
31039
+ ] : [],
31040
+ ...amendment.inlineCritical === void 0 ? [] : [
31041
+ `set optimization.styles.inlineCritical to ${amendment.inlineCritical} in the production configuration (the generated content-security policy blocks the inline handler Angular's critical-CSS pass attaches, so a release build renders unstyled)`
31042
+ ]
31043
+ ].map((step, index) => `${index + 1}. ${step}`).join(" ");
31044
+ }
31015
31045
 
31016
31046
  // ../devkit/src/lib/generate/casing.ts
31017
31047
  function isKebabId(value) {
@@ -31834,6 +31864,40 @@ var framePlugin = {
31834
31864
  }
31835
31865
  };
31836
31866
 
31867
+ // ../devkit/src/recipes/angular-distribution/amendments.ts
31868
+ function distributionAmendments(d) {
31869
+ return [
31870
+ ...d.styles === "tailwind" ? [
31871
+ {
31872
+ kind: "postcss",
31873
+ file: ".postcssrc.json",
31874
+ plugin: "@tailwindcss/postcss"
31875
+ }
31876
+ ] : [],
31877
+ {
31878
+ kind: "build-target",
31879
+ styles: ["src/styles.css"],
31880
+ assets: [
31881
+ { glob: "**/*", input: "public", from: "project" },
31882
+ {
31883
+ glob: "**/*",
31884
+ input: "node_modules/@loomweaver/shell/i18n",
31885
+ from: "workspace",
31886
+ output: "i18n"
31887
+ },
31888
+ {
31889
+ glob: "**/*",
31890
+ input: "node_modules/@loomweaver/frame-kit/dist",
31891
+ from: "workspace",
31892
+ output: "frame-kit"
31893
+ }
31894
+ ],
31895
+ serviceWorker: "ngsw-config.json",
31896
+ inlineCritical: false
31897
+ }
31898
+ ];
31899
+ }
31900
+
31837
31901
  // ../devkit/src/recipes/shell-regions.ts
31838
31902
  var SHELL_REGIONS = [
31839
31903
  "{ id: 'top-bar', type: 'bar', dock: 'top' }",
@@ -32086,20 +32150,15 @@ function stylesNotes(d) {
32086
32150
  }
32087
32151
  return [
32088
32152
  "`src/styles.css` compiles the shell's source theme with Tailwind 4, which is also what lets you",
32089
- "write Tailwind utilities in your own templates. It needs two things the scaffold cannot add for",
32090
- "you \u2014 the packages:",
32153
+ "write Tailwind utilities in your own templates. The scaffold wrote `.postcssrc.json` beside your",
32154
+ "`package.json` for you, because without it the stylesheet is read as plain CSS: no utility class",
32155
+ "is emitted, the workbench renders unstyled, and the build still reports success. The packages are",
32156
+ "the one thing left, because a scaffold does not install:",
32091
32157
  "",
32092
32158
  "```sh",
32093
32159
  "npm install -D tailwindcss @tailwindcss/postcss @tailwindcss/typography",
32094
32160
  "```",
32095
32161
  "",
32096
- "and the PostCSS plugin, in a file next to your `package.json`:",
32097
- "",
32098
- "```jsonc",
32099
- "// .postcssrc.json",
32100
- '{ "plugins": { "@tailwindcss/postcss": {} } }',
32101
- "```",
32102
- "",
32103
32162
  "Use **semantic tokens only** in your own templates (`bg-surface`, `text-content`, `text-brand`,",
32104
32163
  "`border-border`), never raw palette colours.",
32105
32164
  "",
@@ -32185,39 +32244,25 @@ function readme2(d) {
32185
32244
  "",
32186
32245
  "## Build wiring",
32187
32246
  "",
32188
- "The Nx generator put all of this in `project.json`. Scaffolded over the CLI or MCP, add it to",
32189
- "your build target yourself \u2014 `angular.json` under `projects.<name>.architect.build.options` with",
32190
- "the Angular CLI, `project.json` under `targets.build.options` in Nx. Paths inside `assets` are",
32191
- "resolved from the workspace root, so they read the same either way:",
32192
- "",
32193
- "```jsonc",
32194
- '"styles": ["src/styles.css"],',
32195
- '"assets": [',
32196
- ' { "glob": "**/*", "input": "public" },',
32197
- ' { "glob": "**/*", "input": "node_modules/@loomweaver/shell/i18n", "output": "i18n" },',
32198
- ' { "glob": "**/*", "input": "node_modules/@loomweaver/frame-kit/dist", "output": "frame-kit" }',
32199
- "],",
32200
- '"serviceWorker": "ngsw-config.json"',
32201
- "```",
32202
- "",
32203
- "And in the **production** configuration of that same target:",
32247
+ "The scaffold did this. Your build target now names the stylesheet, three asset globs, the",
32248
+ "service worker and one production setting, and the run that wrote these files listed each one it",
32249
+ "added. Anything you had already set was left exactly as you set it.",
32204
32250
  "",
32205
- "```jsonc",
32206
- '"optimization": { "styles": { "inlineCritical": false } }',
32207
- "```",
32251
+ "What each is for, so that nobody removes one as clutter. The **`@loomweaver/shell/i18n` glob**",
32252
+ "serves the strings the shell fetches at runtime; without it every label in the chrome renders as",
32253
+ "its raw translation key and nothing errors. The **frame-kit** glob only matters if you host",
32254
+ "sandboxed (iframe) plugins \u2014 until you install that package the glob simply matches nothing.",
32255
+ "**`serviceWorker`** emits the worker that `provideShell()` already registers for you (inert in",
32256
+ "dev) \u2014 never add `provideServiceWorker` yourself, and if you would rather ship no worker at all,",
32257
+ "drop `ngsw-config.json` and pass `provideShell({ serviceWorker: false })`, because otherwise the",
32258
+ "registration 404s in production. **`optimization.styles.inlineCritical: false`** is not optional:",
32259
+ "the `index.html` above ships a strict `script-src 'self'`, and Angular's critical-CSS pass loads",
32260
+ "the stylesheet with an **inline** `onload` handler that the policy blocks \u2014 the app then renders",
32261
+ "completely unstyled, and only in production builds.",
32208
32262
  "",
32209
- "Each of those earns its place. The **`@loomweaver/shell/i18n` glob** is the one whose absence is easy",
32210
- "to misread: the shell fetches its own UI strings at runtime, so without it every label in the",
32211
- "chrome renders as its raw translation key and nothing errors. The **frame-kit** glob only",
32212
- "matters if you host sandboxed (iframe) plugins \u2014 install that package then; until you do, the",
32213
- "glob simply matches nothing. **`serviceWorker`** emits the worker that `provideShell()` already",
32214
- "registers for you (inert in dev) \u2014 never add `provideServiceWorker` yourself, and if you would",
32215
- "rather ship no worker at all, drop `ngsw-config.json` and pass",
32216
- "`provideShell({ serviceWorker: false })`, because otherwise the registration 404s in production.",
32217
- "**`inlineCritical: false`** is not optional here: the `index.html` above ships a strict",
32218
- "`script-src 'self'`, and Angular's critical-CSS pass loads the stylesheet with an **inline**",
32219
- "`onload` handler that the policy blocks \u2014 the app then renders completely unstyled, and only in",
32220
- "production builds.",
32263
+ "One thing is still yours, because the scaffold cannot know your budget: a production build warns",
32264
+ "that the initial bundle exceeds Angular's 500 kB default. The shell is a whole application",
32265
+ "chrome, so raise the budgets in your build target.",
32221
32266
  "",
32222
32267
  "## Ship less than the whole workbench",
32223
32268
  "",
@@ -32256,6 +32301,9 @@ function readme2(d) {
32256
32301
  }
32257
32302
  var angularDistribution = {
32258
32303
  id: "angular-distribution",
32304
+ amend(input) {
32305
+ return distributionAmendments(resolveDistributionInput(input));
32306
+ },
32259
32307
  build(input) {
32260
32308
  const d = resolveDistributionInput(input);
32261
32309
  return {
@@ -32546,6 +32594,67 @@ var layout = {
32546
32594
  }
32547
32595
  };
32548
32596
 
32597
+ // ../devkit/src/recipes/angular-weaver/amendments.ts
32598
+ function weaverAmendments(input, where) {
32599
+ const w = resolveWeaverInput(input);
32600
+ const directory = (where ?? "").replace(/^\.?\/*/, "").replace(/\/+$/, "");
32601
+ if (!directory) {
32602
+ return [];
32603
+ }
32604
+ return [
32605
+ {
32606
+ kind: "build-target",
32607
+ styles: [],
32608
+ assets: [
32609
+ {
32610
+ glob: "**/*.json",
32611
+ input: `${directory}/src/lib/i18n`,
32612
+ from: "workspace",
32613
+ output: `i18n/${w.id}`
32614
+ }
32615
+ ]
32616
+ },
32617
+ { kind: "stylesheet-source", sourceRoot: `${directory}/src` },
32618
+ {
32619
+ kind: "compose-plugin",
32620
+ id: w.id,
32621
+ symbol: `${w.propertyName}Plugin`,
32622
+ capabilities: w.capabilities,
32623
+ sourceRoot: `${directory}/src`
32624
+ }
32625
+ ];
32626
+ }
32627
+
32628
+ // ../devkit/src/lib/scaffolds/inputs.ts
32629
+ function weaverInput(values) {
32630
+ return {
32631
+ id: str(values, "id") ?? "",
32632
+ name: str(values, "name"),
32633
+ prefix: str(values, "prefix"),
32634
+ importPath: str(values, "importPath"),
32635
+ features: {
32636
+ command: bool(values, "command"),
32637
+ shortcut: str(values, "shortcut"),
32638
+ menu: str(values, "menu"),
32639
+ barItem: bool(values, "barItem"),
32640
+ settings: bool(values, "settings"),
32641
+ about: bool(values, "about"),
32642
+ instanceable: bool(values, "instanceable"),
32643
+ container: bool(values, "container"),
32644
+ access: str(values, "access"),
32645
+ spec: bool(values, "spec")
32646
+ }
32647
+ };
32648
+ }
32649
+ function distributionInput(values) {
32650
+ return {
32651
+ name: str(values, "name") ?? "",
32652
+ title: str(values, "title"),
32653
+ directory: str(values, "directory"),
32654
+ styles: str(values, "styles") ?? "tailwind"
32655
+ };
32656
+ }
32657
+
32549
32658
  // ../devkit/src/lib/scaffolds/scaffolds.ts
32550
32659
  function str(values, name) {
32551
32660
  const value = values[name];
@@ -32681,24 +32790,8 @@ var SCAFFOLDS = [
32681
32790
  APP_OPTION,
32682
32791
  ...PLACEMENT_OPTIONS
32683
32792
  ],
32684
- build: (values) => generate(angularWeaver, {
32685
- id: str(values, "id") ?? "",
32686
- name: str(values, "name"),
32687
- prefix: str(values, "prefix"),
32688
- importPath: str(values, "importPath"),
32689
- features: {
32690
- command: bool(values, "command"),
32691
- shortcut: str(values, "shortcut"),
32692
- menu: str(values, "menu"),
32693
- barItem: bool(values, "barItem"),
32694
- settings: bool(values, "settings"),
32695
- about: bool(values, "about"),
32696
- instanceable: bool(values, "instanceable"),
32697
- container: bool(values, "container"),
32698
- access: str(values, "access"),
32699
- spec: bool(values, "spec")
32700
- }
32701
- })
32793
+ build: (values) => generate(angularWeaver, weaverInput(values)),
32794
+ amend: (values) => weaverAmendments(weaverInput(values), str(values, "directory"))
32702
32795
  },
32703
32796
  {
32704
32797
  name: "frame-plugin",
@@ -32754,12 +32847,8 @@ var SCAFFOLDS = [
32754
32847
  },
32755
32848
  ...PLACEMENT_OPTIONS
32756
32849
  ],
32757
- build: (values) => generate(angularDistribution, {
32758
- name: str(values, "name") ?? "",
32759
- title: str(values, "title"),
32760
- directory: str(values, "directory"),
32761
- styles: str(values, "styles") ?? "tailwind"
32762
- })
32850
+ build: (values) => generate(angularDistribution, distributionInput(values)),
32851
+ amend: (values) => amendments(angularDistribution, distributionInput(values))
32763
32852
  },
32764
32853
  {
32765
32854
  name: "auth-source",
@@ -33130,7 +33219,12 @@ function valuesFor(scaffold2, args) {
33130
33219
  return values;
33131
33220
  }
33132
33221
  function scaffold(scaffold2, args) {
33133
- return ok({ files: scaffold2.build(valuesFor(scaffold2, args)) });
33222
+ const values = valuesFor(scaffold2, args);
33223
+ const remaining = (scaffold2.amend?.(values) ?? []).map(describeAmendment);
33224
+ return ok({
33225
+ files: scaffold2.build(values),
33226
+ ...remaining.length > 0 ? { remaining } : {}
33227
+ });
33134
33228
  }
33135
33229
  function validateManifestTool(a) {
33136
33230
  return ok({
@@ -33150,7 +33244,7 @@ function validateI18nTool(a) {
33150
33244
  }
33151
33245
 
33152
33246
  // src/lib/server.ts
33153
- var FILE_MAP_NOTE = "Returns a file map (relative path -> content); write the files into your project.";
33247
+ var FILE_MAP_NOTE = 'Returns a file map (relative path -> content); write the files into your project. May also return "remaining": steps the workspace needs that this route cannot perform, each saying what it costs to skip. Carry them out, or the generated output builds and does not work.';
33154
33248
  function inputSchema(descriptor) {
33155
33249
  const shape = {};
33156
33250
  for (const option of portableOptions(descriptor)) {
@@ -33163,7 +33257,7 @@ function inputSchema(descriptor) {
33163
33257
  function createMcpServer() {
33164
33258
  const server = new McpServer({
33165
33259
  name: "loomweaver-devkit",
33166
- version: "0.7.2"
33260
+ version: "0.7.3"
33167
33261
  });
33168
33262
  server.registerTool(
33169
33263
  "list_generators",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loomweaver/mcp",
3
- "version": "0.7.2",
3
+ "version": "0.7.3",
4
4
  "description": "LoomWeaver MCP server: exposes LoomWeaver's scaffolding and validation as MCP tools, so an AI assistant in any product repo can scaffold and validate weavers, distributions and integrations without a LoomWeaver checkout.",
5
5
  "keywords": [
6
6
  "loomweaver",