@loomweaver/mcp 0.9.0 → 0.9.2

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 (2) hide show
  1. package/dist/main.mjs +268 -13
  2. package/package.json +1 -1
package/dist/main.mjs CHANGED
@@ -31038,7 +31038,8 @@ function describeAmendment(amendment) {
31038
31038
  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.`;
31039
31039
  }
31040
31040
  if (amendment.kind === "compose-plugin") {
31041
- return `Register ${amendment.id} in the composition root: import { ${amendment.symbol} }, provideTranslationNamespaces('${amendment.id}'), provideCapabilityGrants({ ${amendment.id}: [${amendment.capabilities.map((capability) => `'${capability}'`).join(
31041
+ const providers = (amendment.providers ?? []).map((provider) => provider.line.replace(/,$/, ""));
31042
+ return `Register ${amendment.id} in the composition root: import { ${amendment.symbol} }, ${providers.map((line) => `${line}, `).join("")}provideTranslationNamespaces('${amendment.id}'), provideCapabilityGrants({ ${amendment.id}: [${amendment.capabilities.map((capability) => `'${capability}'`).join(
31042
31043
  ", "
31043
31044
  )}] }) and ...providePlugins(${amendment.symbol}). Without it none of its contributions appear.`;
31044
31045
  }
@@ -31054,7 +31055,10 @@ function describeAmendment(amendment) {
31054
31055
  ] : [],
31055
31056
  ...amendment.inlineCritical === void 0 ? [] : [
31056
31057
  `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)`
31057
- ]
31058
+ ],
31059
+ ...amendment.initialBudget ? [
31060
+ `raise the initial bundle budget to ${amendment.initialBudget.warning} warning and ${amendment.initialBudget.error} error in the production configuration (a fresh workspace carries one sized for an empty application, and the workbench alone spends almost all of it, so a release build fails)`
31061
+ ] : []
31058
31062
  ].map((step, index) => `${index + 1}. ${step}`).join(" ");
31059
31063
  }
31060
31064
 
@@ -31446,7 +31450,7 @@ function pause(): Promise<void> {
31446
31450
  }
31447
31451
 
31448
31452
  // ../devkit/src/recipes/angular-weaver/agent-files.ts
31449
- var AG_UI_ADAPTER_VERSION = "0.9.0";
31453
+ var AG_UI_ADAPTER_VERSION = "0.9.2";
31450
31454
  var AG_UI_PROTOCOL_VERSION = "0.0.x";
31451
31455
  function connectionFile(w) {
31452
31456
  return `import { signal } from '@angular/core';
@@ -32428,9 +32432,21 @@ var framePlugin = {
32428
32432
  }
32429
32433
  };
32430
32434
 
32435
+ // ../devkit/src/recipes/platform-version.ts
32436
+ var PLATFORM_VERSION = "0.9.2";
32437
+
32431
32438
  // ../devkit/src/recipes/angular-distribution/amendments.ts
32439
+ var DISTRIBUTION_INITIAL_BUDGET = {
32440
+ warning: "1.5MB",
32441
+ error: "2MB"
32442
+ };
32432
32443
  function distributionAmendments(d) {
32433
32444
  return [
32445
+ {
32446
+ kind: "package",
32447
+ name: "@loomweaver/frame-kit",
32448
+ version: `^${PLATFORM_VERSION}`
32449
+ },
32434
32450
  ...d.styles === "tailwind" ? [
32435
32451
  {
32436
32452
  kind: "postcss",
@@ -32457,7 +32473,8 @@ function distributionAmendments(d) {
32457
32473
  }
32458
32474
  ],
32459
32475
  serviceWorker: "ngsw-config.json",
32460
- inlineCritical: false
32476
+ inlineCritical: false,
32477
+ initialBudget: DISTRIBUTION_INITIAL_BUDGET
32461
32478
  }
32462
32479
  ];
32463
32480
  }
@@ -32652,9 +32669,10 @@ function readme2(d) {
32652
32669
  "the stylesheet with an **inline** `onload` handler that the policy blocks \u2014 the app then renders",
32653
32670
  "completely unstyled, and only in production builds.",
32654
32671
  "",
32655
- "One thing is still yours, because the scaffold cannot know your budget: a production build warns",
32656
- "that the initial bundle exceeds Angular's 500 kB default. The shell is a whole application",
32657
- "chrome, so raise the budgets in your build target.",
32672
+ "The initial-bundle budget in your build target was raised for the same reason: the shell is a",
32673
+ "whole application chrome and spends most of Angular's default before your own code arrives, so",
32674
+ "a production build would have failed on a number meant for an empty app. It is still a budget,",
32675
+ "and it is yours to move.",
32658
32676
  "",
32659
32677
  "## Ship less than the whole workbench",
32660
32678
  "",
@@ -32968,6 +32986,7 @@ var angularDistribution = {
32968
32986
  };
32969
32987
 
32970
32988
  // ../devkit/src/recipes/auth-source/recipe.ts
32989
+ var SESSION_PLUGIN_ID = "session";
32971
32990
  function resolveAuthSourceInput(input) {
32972
32991
  if (!isKebabId(input.name)) {
32973
32992
  throw new Error(`Auth source name must be kebab-case (e.g. "dev"); got "${input.name}".`);
@@ -32975,9 +32994,13 @@ function resolveAuthSourceInput(input) {
32975
32994
  return {
32976
32995
  name: input.name,
32977
32996
  className: toPascalCase(input.name),
32978
- propertyName: toCamelCase(input.name)
32997
+ propertyName: toCamelCase(input.name),
32998
+ bare: input.bare ?? false
32979
32999
  };
32980
33000
  }
33001
+ function sessionPluginSymbol(a) {
33002
+ return `${a.propertyName}SessionPlugin`;
33003
+ }
32981
33004
  function moduleFile(a) {
32982
33005
  return `// Provider-neutral AuthSource. LoomWeaver owns no authentication \u2014 it only reacts to
32983
33006
  // a session snapshot. Wire it with: provideAuthSource(() => ${a.propertyName}AuthSource()).
@@ -33016,11 +33039,177 @@ export function cycle${a.className}User(): void {
33016
33039
  }
33017
33040
  `;
33018
33041
  }
33042
+ function pluginFile2(a) {
33043
+ return `// The verbs a user needs to operate the stand-in session: sign in, switch the account, sign
33044
+ // out, from a rail item whose menu carries them. This is presentation for a product that has no
33045
+ // backend yet; nothing here protects anything. Delete it once your own session arrives.
33046
+ import type { Disposable, Plugin, PluginContext } from '@loomweaver/plugin-sdk';
33047
+ import { cycle${a.className}User, ${a.propertyName}AuthSource } from './${a.name}-auth-source';
33048
+
33049
+ const MENU = 'session.account/menu';
33050
+ const snapshot = ${a.propertyName}AuthSource();
33051
+
33052
+ let drawn: Disposable[] = [];
33053
+
33054
+ function signIn(): void {
33055
+ if (!snapshot().authenticated) {
33056
+ cycle${a.className}User();
33057
+ }
33058
+ }
33059
+
33060
+ function switchAccount(): void {
33061
+ cycle${a.className}User();
33062
+ if (!snapshot().authenticated) {
33063
+ cycle${a.className}User();
33064
+ }
33065
+ }
33066
+
33067
+ function signOut(): void {
33068
+ while (snapshot().authenticated) {
33069
+ cycle${a.className}User();
33070
+ }
33071
+ }
33072
+
33073
+ function initialsOf(name: string): string {
33074
+ return name
33075
+ .split(' ')
33076
+ .map((word) => word[0] ?? '')
33077
+ .join('')
33078
+ .slice(0, 2)
33079
+ .toUpperCase();
33080
+ }
33081
+
33082
+ function draw(ctx: PluginContext): void {
33083
+ for (const part of drawn) {
33084
+ part.dispose();
33085
+ }
33086
+ const current = snapshot();
33087
+ const name = current.displayName ?? '';
33088
+ drawn = [
33089
+ ctx.registerRailItem({
33090
+ id: 'session.account',
33091
+ rail: 'primary',
33092
+ icon: 'account',
33093
+ title: current.authenticated ? name : 'session.signIn',
33094
+ anchor: 'bottom',
33095
+ order: 20,
33096
+ menu: MENU,
33097
+ menuTrigger: 'primary',
33098
+ ...(current.authenticated ? { initials: initialsOf(name) } : {}),
33099
+ menuHeader: current.authenticated
33100
+ ? {
33101
+ title: name,
33102
+ detail: \`session.role.\${current.roles.includes('admin') ? 'admin' : 'user'}\`,
33103
+ initials: initialsOf(name),
33104
+ }
33105
+ : { title: 'session.signedOut', icon: 'account' },
33106
+ }),
33107
+ ...(current.authenticated
33108
+ ? [
33109
+ ctx.registerMenuItem({
33110
+ id: 'session.menu.switch',
33111
+ menu: MENU,
33112
+ command: 'session.switchAccount',
33113
+ group: 'account',
33114
+ order: 10,
33115
+ }),
33116
+ ctx.registerMenuItem({
33117
+ id: 'session.menu.signOut',
33118
+ menu: MENU,
33119
+ command: 'session.signOut',
33120
+ group: 'account',
33121
+ order: 20,
33122
+ }),
33123
+ ]
33124
+ : [
33125
+ ctx.registerMenuItem({
33126
+ id: 'session.menu.signIn',
33127
+ menu: MENU,
33128
+ command: 'session.signIn',
33129
+ group: 'account',
33130
+ order: 10,
33131
+ }),
33132
+ ]),
33133
+ ];
33134
+ }
33135
+
33136
+ export const ${sessionPluginSymbol(a)}: Plugin = {
33137
+ manifest: { id: 'session', name: 'Account', capabilities: ['contributions'] },
33138
+ activate(ctx) {
33139
+ const then = (step: () => void) => () => {
33140
+ step();
33141
+ draw(ctx);
33142
+ };
33143
+ ctx.registerCommand({
33144
+ id: 'session.signIn',
33145
+ title: 'session.signIn',
33146
+ icon: 'account',
33147
+ access: { authenticated: false },
33148
+ run: then(signIn),
33149
+ });
33150
+ ctx.registerCommand({
33151
+ id: 'session.switchAccount',
33152
+ title: 'session.switchAccount',
33153
+ icon: 'account',
33154
+ access: { authenticated: true },
33155
+ run: then(switchAccount),
33156
+ });
33157
+ ctx.registerCommand({
33158
+ id: 'session.signOut',
33159
+ title: 'session.signOut',
33160
+ icon: 'signOut',
33161
+ access: { authenticated: true },
33162
+ run: then(signOut),
33163
+ });
33164
+ draw(ctx);
33165
+ },
33166
+ deactivate() {
33167
+ for (const part of drawn) {
33168
+ part.dispose();
33169
+ }
33170
+ drawn = [];
33171
+ },
33172
+ };
33173
+ `;
33174
+ }
33175
+ function indexFile2(a) {
33176
+ return `export { cycle${a.className}User, ${a.propertyName}AuthSource } from './${a.name}-auth-source';
33177
+ export { ${sessionPluginSymbol(a)} } from './${a.name}-session.plugin';
33178
+ `;
33179
+ }
33180
+ var I18N = {
33181
+ en: {
33182
+ signIn: "Sign in",
33183
+ switchAccount: "Switch account",
33184
+ signOut: "Sign out",
33185
+ signedOut: "Not signed in",
33186
+ role: { user: "User", admin: "Administrator" }
33187
+ },
33188
+ de: {
33189
+ signIn: "Anmelden",
33190
+ switchAccount: "Konto wechseln",
33191
+ signOut: "Abmelden",
33192
+ signedOut: "Nicht angemeldet",
33193
+ role: { user: "Benutzer", admin: "Administrator" }
33194
+ }
33195
+ };
33019
33196
  var authSource = {
33020
33197
  id: "auth-source",
33021
33198
  build(input) {
33022
33199
  const a = resolveAuthSourceInput(input);
33023
- return { [`${a.name}-auth-source.ts`]: moduleFile(a) };
33200
+ const source = { [`${a.name}-auth-source.ts`]: moduleFile(a) };
33201
+ if (a.bare) {
33202
+ return source;
33203
+ }
33204
+ return {
33205
+ ...source,
33206
+ [`${a.name}-session.plugin.ts`]: pluginFile2(a),
33207
+ "index.ts": indexFile2(a),
33208
+ "i18n/en.json": `${JSON.stringify(I18N.en, null, 2)}
33209
+ `,
33210
+ "i18n/de.json": `${JSON.stringify(I18N.de, null, 2)}
33211
+ `
33212
+ };
33024
33213
  }
33025
33214
  };
33026
33215
 
@@ -33285,6 +33474,54 @@ function weaverAmendments(input, where) {
33285
33474
  ];
33286
33475
  }
33287
33476
 
33477
+ // ../devkit/src/recipes/auth-source/recipe-amendments.ts
33478
+ function authSourceAmendments(input, where) {
33479
+ const a = resolveAuthSourceInput(input);
33480
+ const directory = normalizeProjectRoot(where ?? "");
33481
+ if (a.bare || !directory) {
33482
+ return [];
33483
+ }
33484
+ return [
33485
+ {
33486
+ kind: "build-target",
33487
+ styles: [],
33488
+ assets: [
33489
+ {
33490
+ glob: "**/*.json",
33491
+ input: `${directory}/i18n`,
33492
+ from: "workspace",
33493
+ output: `i18n/${SESSION_PLUGIN_ID}`
33494
+ }
33495
+ ]
33496
+ },
33497
+ {
33498
+ kind: "compose-plugin",
33499
+ id: SESSION_PLUGIN_ID,
33500
+ symbol: sessionPluginSymbol(a),
33501
+ capabilities: ["contributions"],
33502
+ sourceRoot: directory,
33503
+ providers: [
33504
+ {
33505
+ line: `provideAuthSource(() => ${a.propertyName}AuthSource()),`,
33506
+ shell: ["provideAuthSource"],
33507
+ own: [`${a.propertyName}AuthSource`],
33508
+ unless: "provideAuthSource("
33509
+ },
33510
+ {
33511
+ line: "provideIcons({ account: heroUserCircle, signOut: heroArrowRightStartOnRectangle }),",
33512
+ shell: ["provideIcons"],
33513
+ from: [
33514
+ {
33515
+ path: "@ng-icons/heroicons/outline",
33516
+ symbols: ["heroArrowRightStartOnRectangle", "heroUserCircle"]
33517
+ }
33518
+ ]
33519
+ }
33520
+ ]
33521
+ }
33522
+ ];
33523
+ }
33524
+
33288
33525
  // ../devkit/src/lib/scaffolds/inputs.ts
33289
33526
  function weaverInput(values) {
33290
33527
  return {
@@ -33362,6 +33599,9 @@ var APP_OPTION = {
33362
33599
  description: "Application to drop into. Inferred when the workspace has exactly one.",
33363
33600
  workspaceOnly: true
33364
33601
  };
33602
+ function authSourceInput(values) {
33603
+ return { name: str(values, "name") ?? "", bare: bool(values, "bare") };
33604
+ }
33365
33605
  var SCAFFOLDS = [
33366
33606
  {
33367
33607
  name: "weaver",
@@ -33519,7 +33759,7 @@ var SCAFFOLDS = [
33519
33759
  },
33520
33760
  {
33521
33761
  name: "auth-source",
33522
- summary: "a provider-neutral AuthSource that feeds the session",
33762
+ summary: "a stand-in session a user can operate: the AuthSource, the sign-in, switch and sign-out verbs in the rail, composed in",
33523
33763
  options: [
33524
33764
  {
33525
33765
  name: "name",
@@ -33528,9 +33768,22 @@ var SCAFFOLDS = [
33528
33768
  required: true,
33529
33769
  pattern: ID_PATTERN
33530
33770
  },
33531
- APP_OPTION
33771
+ {
33772
+ name: "bare",
33773
+ type: "boolean",
33774
+ description: "Write the AuthSource alone, without the verbs, for a product that maps a session of its own onto it.",
33775
+ default: false
33776
+ },
33777
+ APP_OPTION,
33778
+ {
33779
+ name: "directory",
33780
+ type: "string",
33781
+ description: "Where the files land, relative to the workspace root.",
33782
+ workspaceOnly: true
33783
+ }
33532
33784
  ],
33533
- build: (values) => generate(authSource, { name: str(values, "name") ?? "" })
33785
+ build: (values) => generate(authSource, authSourceInput(values)),
33786
+ amend: (values) => authSourceAmendments(authSourceInput(values), str(values, "directory"))
33534
33787
  },
33535
33788
  {
33536
33789
  name: "settings-store",
@@ -33586,6 +33839,8 @@ var SCAFFOLDS = [
33586
33839
  build: (values) => generate(layout, { name: str(values, "name") })
33587
33840
  }
33588
33841
  ];
33842
+
33843
+ // ../devkit/src/lib/scaffolds/surface.ts
33589
33844
  function portableOptions(scaffold2) {
33590
33845
  return scaffold2.options.filter((option) => !option.workspaceOnly);
33591
33846
  }
@@ -34140,7 +34395,7 @@ function inputSchema(descriptor) {
34140
34395
  function createMcpServer() {
34141
34396
  const server = new McpServer({
34142
34397
  name: "loomweaver-devkit",
34143
- version: "0.9.0"
34398
+ version: "0.9.2"
34144
34399
  });
34145
34400
  server.registerTool(
34146
34401
  "list_generators",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loomweaver/mcp",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "description": "LoomWeaver: open-source plugin platform for Angular workbenches. The MCP server: scaffolding and validation as tools, so an AI assistant in any product repo can build weavers without a checkout.",
5
5
  "keywords": [
6
6
  "loomweaver",