@loomweaver/cli 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 +400 -29
  2. package/package.json +1 -1
package/dist/main.mjs CHANGED
@@ -98,7 +98,7 @@ function ensureBuildTarget(target, amendment, projectRoot) {
98
98
  added.push(...assets.added.map((entry) => `assets: ${entry}`));
99
99
  }
100
100
  next["options"] = options;
101
- if (amendment.inlineCritical !== void 0 || amendment.serviceWorker) {
101
+ if (amendment.inlineCritical !== void 0 || amendment.serviceWorker || amendment.initialBudget) {
102
102
  const configurations = { ...asObject(next["configurations"]) };
103
103
  const production = { ...asObject(configurations["production"]) };
104
104
  if (amendment.serviceWorker && production["serviceWorker"] === void 0) {
@@ -124,6 +124,18 @@ function ensureBuildTarget(target, amendment, projectRoot) {
124
124
  );
125
125
  }
126
126
  }
127
+ if (amendment.initialBudget) {
128
+ const budgets = ensureInitialBudget(
129
+ production["budgets"],
130
+ amendment.initialBudget
131
+ );
132
+ if (budgets.changed) {
133
+ production["budgets"] = budgets.value;
134
+ added.push(
135
+ `production budget initial: ${amendment.initialBudget.warning} warning, ${amendment.initialBudget.error} error`
136
+ );
137
+ }
138
+ }
127
139
  configurations["production"] = production;
128
140
  next["configurations"] = configurations;
129
141
  }
@@ -139,6 +151,56 @@ function ensureStylesheetSource(css, source) {
139
151
  @source '${source}';
140
152
  `;
141
153
  }
154
+ function ensureInitialBudget(budgets, wanted) {
155
+ const entries = Array.isArray(budgets) ? [...budgets] : [];
156
+ const index = entries.findIndex(
157
+ (entry) => asObject(entry)?.["type"] === "initial"
158
+ );
159
+ if (index === -1) {
160
+ return {
161
+ value: [
162
+ ...entries,
163
+ {
164
+ type: "initial",
165
+ maximumWarning: wanted.warning,
166
+ maximumError: wanted.error
167
+ }
168
+ ],
169
+ changed: true
170
+ };
171
+ }
172
+ const current = asObject(entries[index]) ?? {};
173
+ if (!isBelow(current["maximumError"], wanted.error)) {
174
+ return { value: entries, changed: false };
175
+ }
176
+ entries[index] = {
177
+ ...current,
178
+ maximumWarning: wanted.warning,
179
+ maximumError: wanted.error
180
+ };
181
+ return { value: entries, changed: true };
182
+ }
183
+ function isBelow(recorded, wanted) {
184
+ const left = toBytes(recorded);
185
+ const right = toBytes(wanted);
186
+ return left !== void 0 && right !== void 0 && left < right;
187
+ }
188
+ function toBytes(size) {
189
+ if (typeof size !== "string") {
190
+ return void 0;
191
+ }
192
+ const match = /^([\d.]+)\s*(b|kb|mb|gb)?$/i.exec(size.trim());
193
+ if (!match) {
194
+ return void 0;
195
+ }
196
+ const units = {
197
+ b: 1,
198
+ kb: 1e3,
199
+ mb: 1e3 * 1e3,
200
+ gb: 1e3 * 1e3 * 1e3
201
+ };
202
+ return Number(match[1]) * units[(match[2] ?? "b").toLowerCase()];
203
+ }
142
204
  function ensureInlineCritical(optimization, inlineCritical) {
143
205
  if (typeof optimization === "boolean") {
144
206
  return { value: optimization, changed: false, declined: true };
@@ -199,6 +261,7 @@ function asObject(value) {
199
261
 
200
262
  // ../devkit/src/lib/amend/compose.ts
201
263
  var APP_CONFIG = /export\s+const\s+appConfig\s*:[^=]*=\s*\{/;
264
+ var NAMESPACES = /provideTranslationNamespaces\(([^)]*)\)/;
202
265
  var PROVIDERS_OPEN = /providers\s*:\s*\[/g;
203
266
  var SHELL_IMPORT = /import\s*\{([^}]*)\}\s*from\s*'@loomweaver\/shell';/;
204
267
  function closingLine(source, from) {
@@ -228,47 +291,96 @@ function providersBlock(source) {
228
291
  }
229
292
  function composePlugin(source, amendment, importPath) {
230
293
  if (source.includes(amendment.symbol)) {
231
- return { source, composed: true };
294
+ return { source, composed: true, kept: [] };
232
295
  }
233
296
  const shellImport = SHELL_IMPORT.exec(source);
234
297
  if (!shellImport || !providersBlock(source)) {
235
- return { source, composed: false };
298
+ return { source, composed: false, kept: [] };
236
299
  }
300
+ const wanted = providersToAdd(source, amendment);
301
+ const ownSymbols = [amendment.symbol, ...wanted.flatMap((provider) => provider.own ?? [])];
302
+ const foreign = wanted.flatMap((provider) => provider.from ?? []);
237
303
  const withImports = source.replace(
238
304
  SHELL_IMPORT,
239
- () => `import {${withShellSymbols(shellImport[1])}} from '@loomweaver/shell';
240
- import { ${amendment.symbol} } from '${importPath}';`
305
+ () => [
306
+ `import {${withShellSymbols(shellImport[1], wanted)}} from '@loomweaver/shell';`,
307
+ ...foreign.map(
308
+ (entry) => `import { ${[...entry.symbols].toSorted((a, b) => a.localeCompare(b)).join(", ")} } from '${entry.path}';`
309
+ ),
310
+ `import { ${ownSymbols.toSorted((a, b) => a.localeCompare(b)).join(", ")} } from '${importPath}';`
311
+ ].join("\n")
241
312
  );
242
- const block = providersBlock(withImports);
313
+ const joined = joinNamespaces(withImports, amendment.id);
314
+ const block = providersBlock(joined.source);
243
315
  if (!block) {
244
- return { source, composed: false };
316
+ return { source, composed: false, kept: [] };
245
317
  }
246
318
  const indent = `${block.indent} `;
247
319
  const lines = [
248
- `${indent}provideTranslationNamespaces('${amendment.id}'),`,
320
+ ...wanted.map((provider) => `${indent}${provider.line}`),
321
+ ...joined.joined ? [] : [`${indent}provideTranslationNamespaces('${amendment.id}'),`],
249
322
  `${indent}provideCapabilityGrants({ ${amendment.id}: [${amendment.capabilities.map((capability) => `'${capability}'`).join(", ")}] }),`,
250
323
  `${indent}...providePlugins(${amendment.symbol}),`
251
324
  ].join("\n");
252
325
  return {
253
- source: `${withImports.slice(0, block.insertAt)}
254
- ${lines}${withImports.slice(block.insertAt)}`,
255
- composed: true
326
+ source: `${joined.source.slice(0, block.insertAt)}
327
+ ${lines}${joined.source.slice(block.insertAt)}`,
328
+ composed: true,
329
+ kept: keptProviders(source, amendment).map((provider) => provider.line)
256
330
  };
257
331
  }
332
+ function joinNamespaces(source, id) {
333
+ const existing = NAMESPACES.exec(source);
334
+ if (!existing) {
335
+ return { source, joined: false };
336
+ }
337
+ const names = existing[1].split(",").map((name) => name.trim()).filter(Boolean);
338
+ if (names.includes(`'${id}'`)) {
339
+ return { source, joined: true };
340
+ }
341
+ return {
342
+ source: source.replace(
343
+ NAMESPACES,
344
+ () => `provideTranslationNamespaces(${[...names, `'${id}'`].join(", ")})`
345
+ ),
346
+ joined: true
347
+ };
348
+ }
349
+ function providersToAdd(source, amendment) {
350
+ return (amendment.providers ?? []).filter(
351
+ (provider) => !(provider.unless && source.includes(provider.unless))
352
+ );
353
+ }
354
+ function keptProviders(source, amendment) {
355
+ return (amendment.providers ?? []).filter(
356
+ (provider) => provider.unless !== void 0 && source.includes(provider.unless)
357
+ );
358
+ }
258
359
  function composeLines(amendment, importPath) {
360
+ const providers = amendment.providers ?? [];
361
+ const own = [amendment.symbol, ...providers.flatMap((provider) => provider.own ?? [])];
362
+ const shell = [
363
+ "providePlugins",
364
+ "provideCapabilityGrants",
365
+ "provideTranslationNamespaces",
366
+ ...providers.flatMap((provider) => provider.shell ?? [])
367
+ ];
259
368
  return [
260
- `import { ${amendment.symbol} } from '${importPath}';`,
261
- "import { providePlugins, provideCapabilityGrants, provideTranslationNamespaces } from '@loomweaver/shell';",
369
+ `import { ${own.join(", ")} } from '${importPath}';`,
370
+ `import { ${shell.join(", ")} } from '@loomweaver/shell';`,
371
+ ...providers.flatMap((provider) => provider.from ?? []).map((entry) => `import { ${entry.symbols.join(", ")} } from '${entry.path}';`),
372
+ ...providers.map((provider) => provider.line),
262
373
  `provideTranslationNamespaces('${amendment.id}'),`,
263
374
  `provideCapabilityGrants({ ${amendment.id}: [${amendment.capabilities.map((capability) => `'${capability}'`).join(", ")}] }),`,
264
375
  `...providePlugins(${amendment.symbol}),`
265
376
  ];
266
377
  }
267
- function withShellSymbols(existing) {
378
+ function withShellSymbols(existing, providers) {
268
379
  const wanted = [
269
380
  "provideCapabilityGrants",
270
381
  "providePlugins",
271
- "provideTranslationNamespaces"
382
+ "provideTranslationNamespaces",
383
+ ...providers.flatMap((provider) => provider.shell ?? [])
272
384
  ];
273
385
  const present = existing.split(",").map((symbol) => symbol.trim()).filter(Boolean);
274
386
  const missing = wanted.filter(
@@ -296,7 +408,8 @@ function describeAmendment(amendment) {
296
408
  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.`;
297
409
  }
298
410
  if (amendment.kind === "compose-plugin") {
299
- return `Register ${amendment.id} in the composition root: import { ${amendment.symbol} }, provideTranslationNamespaces('${amendment.id}'), provideCapabilityGrants({ ${amendment.id}: [${amendment.capabilities.map((capability) => `'${capability}'`).join(
411
+ const providers = (amendment.providers ?? []).map((provider) => provider.line.replace(/,$/, ""));
412
+ 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(
300
413
  ", "
301
414
  )}] }) and ...providePlugins(${amendment.symbol}). Without it none of its contributions appear.`;
302
415
  }
@@ -312,7 +425,10 @@ function describeAmendment(amendment) {
312
425
  ] : [],
313
426
  ...amendment.inlineCritical === void 0 ? [] : [
314
427
  `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)`
315
- ]
428
+ ],
429
+ ...amendment.initialBudget ? [
430
+ `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)`
431
+ ] : []
316
432
  ].map((step, index) => `${index + 1}. ${step}`).join(" ");
317
433
  }
318
434
 
@@ -704,7 +820,7 @@ function pause(): Promise<void> {
704
820
  }
705
821
 
706
822
  // ../devkit/src/recipes/angular-weaver/agent-files.ts
707
- var AG_UI_ADAPTER_VERSION = "0.9.0";
823
+ var AG_UI_ADAPTER_VERSION = "0.9.2";
708
824
  var AG_UI_PROTOCOL_VERSION = "0.0.x";
709
825
  function connectionFile(w) {
710
826
  return `import { signal } from '@angular/core';
@@ -1686,9 +1802,21 @@ var framePlugin = {
1686
1802
  }
1687
1803
  };
1688
1804
 
1805
+ // ../devkit/src/recipes/platform-version.ts
1806
+ var PLATFORM_VERSION = "0.9.2";
1807
+
1689
1808
  // ../devkit/src/recipes/angular-distribution/amendments.ts
1809
+ var DISTRIBUTION_INITIAL_BUDGET = {
1810
+ warning: "1.5MB",
1811
+ error: "2MB"
1812
+ };
1690
1813
  function distributionAmendments(d) {
1691
1814
  return [
1815
+ {
1816
+ kind: "package",
1817
+ name: "@loomweaver/frame-kit",
1818
+ version: `^${PLATFORM_VERSION}`
1819
+ },
1692
1820
  ...d.styles === "tailwind" ? [
1693
1821
  {
1694
1822
  kind: "postcss",
@@ -1715,7 +1843,8 @@ function distributionAmendments(d) {
1715
1843
  }
1716
1844
  ],
1717
1845
  serviceWorker: "ngsw-config.json",
1718
- inlineCritical: false
1846
+ inlineCritical: false,
1847
+ initialBudget: DISTRIBUTION_INITIAL_BUDGET
1719
1848
  }
1720
1849
  ];
1721
1850
  }
@@ -1910,9 +2039,10 @@ function readme2(d) {
1910
2039
  "the stylesheet with an **inline** `onload` handler that the policy blocks \u2014 the app then renders",
1911
2040
  "completely unstyled, and only in production builds.",
1912
2041
  "",
1913
- "One thing is still yours, because the scaffold cannot know your budget: a production build warns",
1914
- "that the initial bundle exceeds Angular's 500 kB default. The shell is a whole application",
1915
- "chrome, so raise the budgets in your build target.",
2042
+ "The initial-bundle budget in your build target was raised for the same reason: the shell is a",
2043
+ "whole application chrome and spends most of Angular's default before your own code arrives, so",
2044
+ "a production build would have failed on a number meant for an empty app. It is still a budget,",
2045
+ "and it is yours to move.",
1916
2046
  "",
1917
2047
  "## Ship less than the whole workbench",
1918
2048
  "",
@@ -2226,6 +2356,7 @@ var angularDistribution = {
2226
2356
  };
2227
2357
 
2228
2358
  // ../devkit/src/recipes/auth-source/recipe.ts
2359
+ var SESSION_PLUGIN_ID = "session";
2229
2360
  function resolveAuthSourceInput(input) {
2230
2361
  if (!isKebabId(input.name)) {
2231
2362
  throw new Error(`Auth source name must be kebab-case (e.g. "dev"); got "${input.name}".`);
@@ -2233,9 +2364,13 @@ function resolveAuthSourceInput(input) {
2233
2364
  return {
2234
2365
  name: input.name,
2235
2366
  className: toPascalCase(input.name),
2236
- propertyName: toCamelCase(input.name)
2367
+ propertyName: toCamelCase(input.name),
2368
+ bare: input.bare ?? false
2237
2369
  };
2238
2370
  }
2371
+ function sessionPluginSymbol(a) {
2372
+ return `${a.propertyName}SessionPlugin`;
2373
+ }
2239
2374
  function moduleFile(a) {
2240
2375
  return `// Provider-neutral AuthSource. LoomWeaver owns no authentication \u2014 it only reacts to
2241
2376
  // a session snapshot. Wire it with: provideAuthSource(() => ${a.propertyName}AuthSource()).
@@ -2274,11 +2409,177 @@ export function cycle${a.className}User(): void {
2274
2409
  }
2275
2410
  `;
2276
2411
  }
2412
+ function pluginFile2(a) {
2413
+ return `// The verbs a user needs to operate the stand-in session: sign in, switch the account, sign
2414
+ // out, from a rail item whose menu carries them. This is presentation for a product that has no
2415
+ // backend yet; nothing here protects anything. Delete it once your own session arrives.
2416
+ import type { Disposable, Plugin, PluginContext } from '@loomweaver/plugin-sdk';
2417
+ import { cycle${a.className}User, ${a.propertyName}AuthSource } from './${a.name}-auth-source';
2418
+
2419
+ const MENU = 'session.account/menu';
2420
+ const snapshot = ${a.propertyName}AuthSource();
2421
+
2422
+ let drawn: Disposable[] = [];
2423
+
2424
+ function signIn(): void {
2425
+ if (!snapshot().authenticated) {
2426
+ cycle${a.className}User();
2427
+ }
2428
+ }
2429
+
2430
+ function switchAccount(): void {
2431
+ cycle${a.className}User();
2432
+ if (!snapshot().authenticated) {
2433
+ cycle${a.className}User();
2434
+ }
2435
+ }
2436
+
2437
+ function signOut(): void {
2438
+ while (snapshot().authenticated) {
2439
+ cycle${a.className}User();
2440
+ }
2441
+ }
2442
+
2443
+ function initialsOf(name: string): string {
2444
+ return name
2445
+ .split(' ')
2446
+ .map((word) => word[0] ?? '')
2447
+ .join('')
2448
+ .slice(0, 2)
2449
+ .toUpperCase();
2450
+ }
2451
+
2452
+ function draw(ctx: PluginContext): void {
2453
+ for (const part of drawn) {
2454
+ part.dispose();
2455
+ }
2456
+ const current = snapshot();
2457
+ const name = current.displayName ?? '';
2458
+ drawn = [
2459
+ ctx.registerRailItem({
2460
+ id: 'session.account',
2461
+ rail: 'primary',
2462
+ icon: 'account',
2463
+ title: current.authenticated ? name : 'session.signIn',
2464
+ anchor: 'bottom',
2465
+ order: 20,
2466
+ menu: MENU,
2467
+ menuTrigger: 'primary',
2468
+ ...(current.authenticated ? { initials: initialsOf(name) } : {}),
2469
+ menuHeader: current.authenticated
2470
+ ? {
2471
+ title: name,
2472
+ detail: \`session.role.\${current.roles.includes('admin') ? 'admin' : 'user'}\`,
2473
+ initials: initialsOf(name),
2474
+ }
2475
+ : { title: 'session.signedOut', icon: 'account' },
2476
+ }),
2477
+ ...(current.authenticated
2478
+ ? [
2479
+ ctx.registerMenuItem({
2480
+ id: 'session.menu.switch',
2481
+ menu: MENU,
2482
+ command: 'session.switchAccount',
2483
+ group: 'account',
2484
+ order: 10,
2485
+ }),
2486
+ ctx.registerMenuItem({
2487
+ id: 'session.menu.signOut',
2488
+ menu: MENU,
2489
+ command: 'session.signOut',
2490
+ group: 'account',
2491
+ order: 20,
2492
+ }),
2493
+ ]
2494
+ : [
2495
+ ctx.registerMenuItem({
2496
+ id: 'session.menu.signIn',
2497
+ menu: MENU,
2498
+ command: 'session.signIn',
2499
+ group: 'account',
2500
+ order: 10,
2501
+ }),
2502
+ ]),
2503
+ ];
2504
+ }
2505
+
2506
+ export const ${sessionPluginSymbol(a)}: Plugin = {
2507
+ manifest: { id: 'session', name: 'Account', capabilities: ['contributions'] },
2508
+ activate(ctx) {
2509
+ const then = (step: () => void) => () => {
2510
+ step();
2511
+ draw(ctx);
2512
+ };
2513
+ ctx.registerCommand({
2514
+ id: 'session.signIn',
2515
+ title: 'session.signIn',
2516
+ icon: 'account',
2517
+ access: { authenticated: false },
2518
+ run: then(signIn),
2519
+ });
2520
+ ctx.registerCommand({
2521
+ id: 'session.switchAccount',
2522
+ title: 'session.switchAccount',
2523
+ icon: 'account',
2524
+ access: { authenticated: true },
2525
+ run: then(switchAccount),
2526
+ });
2527
+ ctx.registerCommand({
2528
+ id: 'session.signOut',
2529
+ title: 'session.signOut',
2530
+ icon: 'signOut',
2531
+ access: { authenticated: true },
2532
+ run: then(signOut),
2533
+ });
2534
+ draw(ctx);
2535
+ },
2536
+ deactivate() {
2537
+ for (const part of drawn) {
2538
+ part.dispose();
2539
+ }
2540
+ drawn = [];
2541
+ },
2542
+ };
2543
+ `;
2544
+ }
2545
+ function indexFile2(a) {
2546
+ return `export { cycle${a.className}User, ${a.propertyName}AuthSource } from './${a.name}-auth-source';
2547
+ export { ${sessionPluginSymbol(a)} } from './${a.name}-session.plugin';
2548
+ `;
2549
+ }
2550
+ var I18N = {
2551
+ en: {
2552
+ signIn: "Sign in",
2553
+ switchAccount: "Switch account",
2554
+ signOut: "Sign out",
2555
+ signedOut: "Not signed in",
2556
+ role: { user: "User", admin: "Administrator" }
2557
+ },
2558
+ de: {
2559
+ signIn: "Anmelden",
2560
+ switchAccount: "Konto wechseln",
2561
+ signOut: "Abmelden",
2562
+ signedOut: "Nicht angemeldet",
2563
+ role: { user: "Benutzer", admin: "Administrator" }
2564
+ }
2565
+ };
2277
2566
  var authSource = {
2278
2567
  id: "auth-source",
2279
2568
  build(input) {
2280
2569
  const a = resolveAuthSourceInput(input);
2281
- return { [`${a.name}-auth-source.ts`]: moduleFile(a) };
2570
+ const source = { [`${a.name}-auth-source.ts`]: moduleFile(a) };
2571
+ if (a.bare) {
2572
+ return source;
2573
+ }
2574
+ return {
2575
+ ...source,
2576
+ [`${a.name}-session.plugin.ts`]: pluginFile2(a),
2577
+ "index.ts": indexFile2(a),
2578
+ "i18n/en.json": `${JSON.stringify(I18N.en, null, 2)}
2579
+ `,
2580
+ "i18n/de.json": `${JSON.stringify(I18N.de, null, 2)}
2581
+ `
2582
+ };
2282
2583
  }
2283
2584
  };
2284
2585
 
@@ -2543,6 +2844,54 @@ function weaverAmendments(input, where) {
2543
2844
  ];
2544
2845
  }
2545
2846
 
2847
+ // ../devkit/src/recipes/auth-source/recipe-amendments.ts
2848
+ function authSourceAmendments(input, where) {
2849
+ const a = resolveAuthSourceInput(input);
2850
+ const directory = normalizeProjectRoot(where ?? "");
2851
+ if (a.bare || !directory) {
2852
+ return [];
2853
+ }
2854
+ return [
2855
+ {
2856
+ kind: "build-target",
2857
+ styles: [],
2858
+ assets: [
2859
+ {
2860
+ glob: "**/*.json",
2861
+ input: `${directory}/i18n`,
2862
+ from: "workspace",
2863
+ output: `i18n/${SESSION_PLUGIN_ID}`
2864
+ }
2865
+ ]
2866
+ },
2867
+ {
2868
+ kind: "compose-plugin",
2869
+ id: SESSION_PLUGIN_ID,
2870
+ symbol: sessionPluginSymbol(a),
2871
+ capabilities: ["contributions"],
2872
+ sourceRoot: directory,
2873
+ providers: [
2874
+ {
2875
+ line: `provideAuthSource(() => ${a.propertyName}AuthSource()),`,
2876
+ shell: ["provideAuthSource"],
2877
+ own: [`${a.propertyName}AuthSource`],
2878
+ unless: "provideAuthSource("
2879
+ },
2880
+ {
2881
+ line: "provideIcons({ account: heroUserCircle, signOut: heroArrowRightStartOnRectangle }),",
2882
+ shell: ["provideIcons"],
2883
+ from: [
2884
+ {
2885
+ path: "@ng-icons/heroicons/outline",
2886
+ symbols: ["heroArrowRightStartOnRectangle", "heroUserCircle"]
2887
+ }
2888
+ ]
2889
+ }
2890
+ ]
2891
+ }
2892
+ ];
2893
+ }
2894
+
2546
2895
  // ../devkit/src/lib/scaffolds/inputs.ts
2547
2896
  function weaverInput(values) {
2548
2897
  return {
@@ -2623,6 +2972,9 @@ var APP_OPTION = {
2623
2972
  description: "Application to drop into. Inferred when the workspace has exactly one.",
2624
2973
  workspaceOnly: true
2625
2974
  };
2975
+ function authSourceInput(values) {
2976
+ return { name: str(values, "name") ?? "", bare: bool(values, "bare") };
2977
+ }
2626
2978
  var SCAFFOLDS = [
2627
2979
  {
2628
2980
  name: "weaver",
@@ -2780,7 +3132,7 @@ var SCAFFOLDS = [
2780
3132
  },
2781
3133
  {
2782
3134
  name: "auth-source",
2783
- summary: "a provider-neutral AuthSource that feeds the session",
3135
+ summary: "a stand-in session a user can operate: the AuthSource, the sign-in, switch and sign-out verbs in the rail, composed in",
2784
3136
  options: [
2785
3137
  {
2786
3138
  name: "name",
@@ -2789,9 +3141,22 @@ var SCAFFOLDS = [
2789
3141
  required: true,
2790
3142
  pattern: ID_PATTERN
2791
3143
  },
2792
- APP_OPTION
3144
+ {
3145
+ name: "bare",
3146
+ type: "boolean",
3147
+ description: "Write the AuthSource alone, without the verbs, for a product that maps a session of its own onto it.",
3148
+ default: false
3149
+ },
3150
+ APP_OPTION,
3151
+ {
3152
+ name: "directory",
3153
+ type: "string",
3154
+ description: "Where the files land, relative to the workspace root.",
3155
+ workspaceOnly: true
3156
+ }
2793
3157
  ],
2794
- build: (values) => generate(authSource, { name: str(values, "name") ?? "" })
3158
+ build: (values) => generate(authSource, authSourceInput(values)),
3159
+ amend: (values) => authSourceAmendments(authSourceInput(values), str(values, "directory"))
2795
3160
  },
2796
3161
  {
2797
3162
  name: "settings-store",
@@ -2850,6 +3215,8 @@ var SCAFFOLDS = [
2850
3215
  function findScaffold(name) {
2851
3216
  return SCAFFOLDS.find((scaffold2) => scaffold2.name === name);
2852
3217
  }
3218
+
3219
+ // ../devkit/src/lib/scaffolds/surface.ts
2853
3220
  function portableOptions(scaffold2) {
2854
3221
  return scaffold2.options.filter((option) => !option.workspaceOnly);
2855
3222
  }
@@ -3709,7 +4076,11 @@ var Amender = class {
3709
4076
  file: root,
3710
4077
  display: this.displayName(root),
3711
4078
  added: [
3712
- `${amendment.symbol}, its translations and its capability grants`
4079
+ `${amendment.symbol}, its translations and its capability grants`,
4080
+ ...(amendment.providers ?? []).filter((provider) => !result.kept.includes(provider.line)).map((provider) => provider.line.replace(/,$/, "")),
4081
+ ...result.kept.map(
4082
+ (line) => `kept the ${line.split("(", 1)[0]} already there instead of ${line.replace(/,$/, "")}`
4083
+ )
3713
4084
  ],
3714
4085
  content: result.source
3715
4086
  });
@@ -3929,7 +4300,7 @@ function replaceSymlinkEntry(absolute) {
3929
4300
  }
3930
4301
 
3931
4302
  // src/lib/run.ts
3932
- var VERSION = "0.9.0";
4303
+ var VERSION = "0.9.2";
3933
4304
  function help() {
3934
4305
  const commands = SCAFFOLDS.map((s) => ` ${s.name.padEnd(16)}${s.summary}`);
3935
4306
  return [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loomweaver/cli",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "description": "LoomWeaver: open-source plugin platform for Angular workbenches. The scaffolding CLI: generates weavers, distributions and integrations into any project, with no Nx workspace and no checkout required.",
5
5
  "keywords": [
6
6
  "loomweaver",