clispark 1.15.0 → 1.16.0
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/dist/cli.js +445 -50
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
|
-
import
|
|
4
|
+
import path14 from "path";
|
|
5
5
|
import { Command } from "commander";
|
|
6
6
|
|
|
7
7
|
// src/wizard.ts
|
|
8
8
|
import { intro, outro, text, select, log, isCancel, cancel } from "@clack/prompts";
|
|
9
9
|
|
|
10
10
|
// src/languages/packs/node-oclif.ts
|
|
11
|
-
import
|
|
11
|
+
import path5 from "path";
|
|
12
12
|
|
|
13
13
|
// src/package-root.ts
|
|
14
14
|
import { existsSync, readFileSync } from "fs";
|
|
@@ -222,6 +222,127 @@ var npmRegistryChecker = {
|
|
|
222
222
|
applyRegistryUrl
|
|
223
223
|
};
|
|
224
224
|
|
|
225
|
+
// src/languages/command-generators/node-oclif.ts
|
|
226
|
+
import { mkdir, readdir, writeFile as writeFile3 } from "fs/promises";
|
|
227
|
+
import path4 from "path";
|
|
228
|
+
|
|
229
|
+
// src/languages/command-generator.ts
|
|
230
|
+
function buildCommandTree(paths2) {
|
|
231
|
+
const nodesByPath = /* @__PURE__ */ new Map();
|
|
232
|
+
const roots = [];
|
|
233
|
+
function getOrCreateNode(nodePath) {
|
|
234
|
+
let node = nodesByPath.get(nodePath);
|
|
235
|
+
if (!node) {
|
|
236
|
+
const segments = nodePath.split(" ");
|
|
237
|
+
node = { path: nodePath, displayLabel: segments.join(" > "), children: [] };
|
|
238
|
+
nodesByPath.set(nodePath, node);
|
|
239
|
+
if (segments.length === 1) {
|
|
240
|
+
roots.push(node);
|
|
241
|
+
} else {
|
|
242
|
+
const parent = getOrCreateNode(segments.slice(0, -1).join(" "));
|
|
243
|
+
parent.children.push(node);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return node;
|
|
247
|
+
}
|
|
248
|
+
for (const p of paths2) {
|
|
249
|
+
getOrCreateNode(p);
|
|
250
|
+
}
|
|
251
|
+
return roots;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// src/languages/command-generators/node-oclif.ts
|
|
255
|
+
async function collectCommandFiles(dir, baseDir = dir) {
|
|
256
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
257
|
+
const files = [];
|
|
258
|
+
for (const entry of entries) {
|
|
259
|
+
const fullPath = path4.join(dir, entry.name);
|
|
260
|
+
if (entry.isDirectory()) {
|
|
261
|
+
files.push(...await collectCommandFiles(fullPath, baseDir));
|
|
262
|
+
} else if (entry.name.endsWith(".ts") && !entry.name.endsWith(".test.ts")) {
|
|
263
|
+
files.push(path4.relative(baseDir, fullPath));
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return files;
|
|
267
|
+
}
|
|
268
|
+
function toCommandPath(relativeFilePath) {
|
|
269
|
+
return relativeFilePath.replace(/\.ts$/, "").split(path4.sep).join(" ");
|
|
270
|
+
}
|
|
271
|
+
async function listExistingCommands(targetDir) {
|
|
272
|
+
const commandsDir = path4.join(targetDir, "src", "commands");
|
|
273
|
+
const files = await collectCommandFiles(commandsDir);
|
|
274
|
+
return buildCommandTree(files.map(toCommandPath));
|
|
275
|
+
}
|
|
276
|
+
function toClassName(pathSegments) {
|
|
277
|
+
return pathSegments.map((seg) => seg[0].toUpperCase() + seg.slice(1)).join("");
|
|
278
|
+
}
|
|
279
|
+
function argFor(param) {
|
|
280
|
+
const opts = [`required: ${param.required}`, `description: '${param.name}'`];
|
|
281
|
+
if (param.type === "enum") {
|
|
282
|
+
opts.push(`options: [${(param.allowedValues ?? []).map((v) => `'${v}'`).join(", ")}]`);
|
|
283
|
+
}
|
|
284
|
+
const argsMethod = param.type === "enum" ? "string" : param.type;
|
|
285
|
+
return `Args.${argsMethod}({ ${opts.join(", ")} })`;
|
|
286
|
+
}
|
|
287
|
+
function generateCommandFileContent(spec) {
|
|
288
|
+
const className = toClassName(spec.pathSegments);
|
|
289
|
+
const argsLines = spec.parameters.map((p) => ` ${p.name}: ${argFor(p)},`).join("\n");
|
|
290
|
+
const logExpr = spec.parameters.map((p) => `${p.name}=\${args.${p.name}}`).join(" ");
|
|
291
|
+
const depth = spec.pathSegments.length;
|
|
292
|
+
const baseCommandImportPath = "../".repeat(depth) + "base-command";
|
|
293
|
+
return `import { Args } from '@oclif/core';
|
|
294
|
+
import { BaseCommand } from '${baseCommandImportPath}';
|
|
295
|
+
|
|
296
|
+
export default class ${className} extends BaseCommand {
|
|
297
|
+
static description = '${spec.pathSegments[spec.pathSegments.length - 1]} command';
|
|
298
|
+
static args = {
|
|
299
|
+
${argsLines}
|
|
300
|
+
};
|
|
301
|
+
static flags = {};
|
|
302
|
+
|
|
303
|
+
async run(): Promise<void> {
|
|
304
|
+
const { args } = await this.parse(${className});
|
|
305
|
+
this.log(\`${logExpr}\`);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
`;
|
|
309
|
+
}
|
|
310
|
+
function sampleArgValue(param) {
|
|
311
|
+
if (param.type === "enum") return param.allowedValues?.[0] ?? "";
|
|
312
|
+
if (param.type === "integer") return "1";
|
|
313
|
+
if (param.type === "boolean") return "true";
|
|
314
|
+
return "value";
|
|
315
|
+
}
|
|
316
|
+
function generateTestFileContent(spec) {
|
|
317
|
+
const commandInvocation = spec.pathSegments.join(" ");
|
|
318
|
+
const sampleArgs = spec.parameters.map(sampleArgValue).join(" ");
|
|
319
|
+
const fullInvocation = sampleArgs ? `${commandInvocation} ${sampleArgs}` : commandInvocation;
|
|
320
|
+
return `import { describe, it, expect } from 'vitest';
|
|
321
|
+
import { runCommand } from '@oclif/test';
|
|
322
|
+
|
|
323
|
+
describe('${commandInvocation}', () => {
|
|
324
|
+
it('runs successfully', async () => {
|
|
325
|
+
const { error } = await runCommand('${fullInvocation}');
|
|
326
|
+
expect(error).toBeUndefined();
|
|
327
|
+
});
|
|
328
|
+
});
|
|
329
|
+
`;
|
|
330
|
+
}
|
|
331
|
+
async function generateCommand(targetDir, spec) {
|
|
332
|
+
const relDir = path4.join("src", "commands", ...spec.pathSegments.slice(0, -1));
|
|
333
|
+
const fileName = spec.pathSegments[spec.pathSegments.length - 1];
|
|
334
|
+
const commandRelPath = path4.join(relDir, `${fileName}.ts`);
|
|
335
|
+
const testRelPath = path4.join(relDir, `${fileName}.test.ts`);
|
|
336
|
+
await mkdir(path4.join(targetDir, relDir), { recursive: true });
|
|
337
|
+
await writeFile3(path4.join(targetDir, commandRelPath), generateCommandFileContent(spec));
|
|
338
|
+
await writeFile3(path4.join(targetDir, testRelPath), generateTestFileContent(spec));
|
|
339
|
+
return { commandFile: commandRelPath, testFile: testRelPath };
|
|
340
|
+
}
|
|
341
|
+
var nodeOclifCommandGenerator = {
|
|
342
|
+
listExistingCommands,
|
|
343
|
+
generateCommand
|
|
344
|
+
};
|
|
345
|
+
|
|
225
346
|
// src/languages/packs/node-oclif.ts
|
|
226
347
|
function validateProjectName(value) {
|
|
227
348
|
if (!value || value.trim().length === 0) return "Project name is required.";
|
|
@@ -233,7 +354,7 @@ function validateProjectName(value) {
|
|
|
233
354
|
var nodeOclifPack = {
|
|
234
355
|
id: "node",
|
|
235
356
|
displayName: "Node.js / TypeScript (oclif)",
|
|
236
|
-
templateDir:
|
|
357
|
+
templateDir: path5.join(findPackageRoot(), "templates", "node"),
|
|
237
358
|
scaffoldCommands: [
|
|
238
359
|
{ command: "npm", args: ["install"] },
|
|
239
360
|
{ command: "npm", args: ["run", "build"] }
|
|
@@ -246,15 +367,16 @@ var nodeOclifPack = {
|
|
|
246
367
|
checkNameAvailability: npmRegistryChecker.checkNameAvailability,
|
|
247
368
|
applyPrivateIntent: npmRegistryChecker.applyPrivateIntent,
|
|
248
369
|
applyRegistryUrl: npmRegistryChecker.applyRegistryUrl
|
|
249
|
-
}
|
|
370
|
+
},
|
|
371
|
+
commandGenerator: nodeOclifCommandGenerator
|
|
250
372
|
};
|
|
251
373
|
|
|
252
374
|
// src/languages/packs/dotnet.ts
|
|
253
|
-
import
|
|
375
|
+
import path9 from "path";
|
|
254
376
|
|
|
255
377
|
// src/update/adapters/dotnet.ts
|
|
256
|
-
import { readFile as readFile3, writeFile as
|
|
257
|
-
import
|
|
378
|
+
import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
|
|
379
|
+
import path6 from "path";
|
|
258
380
|
var CORE_FILE_PATHS2 = [
|
|
259
381
|
"Cli.slnx",
|
|
260
382
|
"src/Program.cs",
|
|
@@ -366,11 +488,11 @@ var dotnetAdapter = {
|
|
|
366
488
|
},
|
|
367
489
|
manifestFileName: "src/Cli.csproj",
|
|
368
490
|
async readManifestFile(dir) {
|
|
369
|
-
const content = await readFile3(
|
|
491
|
+
const content = await readFile3(path6.join(dir, "src", "Cli.csproj"), "utf8");
|
|
370
492
|
return parseManifestFile(content);
|
|
371
493
|
},
|
|
372
494
|
async writeManifestFile(dir, content) {
|
|
373
|
-
await
|
|
495
|
+
await writeFile4(path6.join(dir, "src", "Cli.csproj"), content.raw);
|
|
374
496
|
},
|
|
375
497
|
parseManifestFile,
|
|
376
498
|
readProjectName(manifestFile) {
|
|
@@ -385,8 +507,8 @@ var dotnetAdapter = {
|
|
|
385
507
|
};
|
|
386
508
|
|
|
387
509
|
// src/languages/registry-checkers/nuget.ts
|
|
388
|
-
import { mkdir, readFile as readFile4, writeFile as
|
|
389
|
-
import
|
|
510
|
+
import { mkdir as mkdir2, readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
|
|
511
|
+
import path7 from "path";
|
|
390
512
|
var NUGET_DEFAULT_REGISTRY_URL = "https://api.nuget.org/v3/index.json";
|
|
391
513
|
var NUGET_FLATCONTAINER_BASE = "https://api.nuget.org/v3-flatcontainer";
|
|
392
514
|
var FETCH_TIMEOUT_MS2 = 5e3;
|
|
@@ -402,13 +524,13 @@ async function checkNameAvailability2(name) {
|
|
|
402
524
|
}
|
|
403
525
|
}
|
|
404
526
|
async function applyPrivateIntent2(targetDir) {
|
|
405
|
-
const csprojPath =
|
|
527
|
+
const csprojPath = path7.join(targetDir, "src", "Cli.csproj");
|
|
406
528
|
const content = await readFile4(csprojPath, "utf8");
|
|
407
529
|
const updated = content.replace(
|
|
408
530
|
/(<PropertyGroup>\s*\n)/,
|
|
409
531
|
"$1 <IsPackable>false</IsPackable>\n"
|
|
410
532
|
);
|
|
411
|
-
await
|
|
533
|
+
await writeFile5(csprojPath, updated);
|
|
412
534
|
}
|
|
413
535
|
async function applyRegistryUrl2(targetDir, registryUrl) {
|
|
414
536
|
const config = [
|
|
@@ -421,8 +543,8 @@ async function applyRegistryUrl2(targetDir, registryUrl) {
|
|
|
421
543
|
"</configuration>",
|
|
422
544
|
""
|
|
423
545
|
].join("\n");
|
|
424
|
-
await
|
|
425
|
-
await
|
|
546
|
+
await mkdir2(targetDir, { recursive: true });
|
|
547
|
+
await writeFile5(path7.join(targetDir, "NuGet.config"), config);
|
|
426
548
|
}
|
|
427
549
|
var nugetRegistryChecker = {
|
|
428
550
|
checkNameAvailability: checkNameAvailability2,
|
|
@@ -430,6 +552,120 @@ var nugetRegistryChecker = {
|
|
|
430
552
|
applyRegistryUrl: applyRegistryUrl2
|
|
431
553
|
};
|
|
432
554
|
|
|
555
|
+
// src/languages/command-generators/dotnet.ts
|
|
556
|
+
import { mkdir as mkdir3, readFile as readFile5, readdir as readdir2, writeFile as writeFile6 } from "fs/promises";
|
|
557
|
+
import path8 from "path";
|
|
558
|
+
async function listExistingCommands2(targetDir) {
|
|
559
|
+
const commandsDir = path8.join(targetDir, "src", "Commands");
|
|
560
|
+
const files = await readdir2(commandsDir);
|
|
561
|
+
const paths2 = [];
|
|
562
|
+
for (const file of files) {
|
|
563
|
+
if (!file.endsWith(".cs")) continue;
|
|
564
|
+
const content = await readFile5(path8.join(commandsDir, file), "utf8");
|
|
565
|
+
const match = content.match(/\[CommandPath\("([^"]+)"\)\]/);
|
|
566
|
+
if (match) paths2.push(match[1]);
|
|
567
|
+
}
|
|
568
|
+
return buildCommandTree(paths2);
|
|
569
|
+
}
|
|
570
|
+
function toClassName2(pathSegments) {
|
|
571
|
+
return pathSegments.map((seg) => seg[0].toUpperCase() + seg.slice(1)).join("") + "Command";
|
|
572
|
+
}
|
|
573
|
+
function csharpDeclType(param) {
|
|
574
|
+
const baseType = param.type === "integer" ? "int" : param.type === "boolean" ? "bool" : "string";
|
|
575
|
+
if (param.required) return baseType;
|
|
576
|
+
return `${baseType}?`;
|
|
577
|
+
}
|
|
578
|
+
function argumentDeclaration(param) {
|
|
579
|
+
const varName = `${param.name}Argument`;
|
|
580
|
+
const declType = csharpDeclType(param);
|
|
581
|
+
const arityLine = param.required ? "" : "\n Arity = ArgumentArity.ZeroOrOne,";
|
|
582
|
+
const lines = [
|
|
583
|
+
` var ${varName} = new Argument<${declType}>("${param.name}")`,
|
|
584
|
+
` {`,
|
|
585
|
+
` Description = "${param.name}",${arityLine}`,
|
|
586
|
+
` };`
|
|
587
|
+
];
|
|
588
|
+
if (param.type === "enum") {
|
|
589
|
+
lines.push(` ${varName}.AcceptOnlyFromAmong(${(param.allowedValues ?? []).map((v) => `"${v}"`).join(", ")});`);
|
|
590
|
+
}
|
|
591
|
+
return lines.join("\n");
|
|
592
|
+
}
|
|
593
|
+
function generateCommandFileContent2(spec) {
|
|
594
|
+
const className = toClassName2(spec.pathSegments);
|
|
595
|
+
const commandPath = spec.pathSegments.join(" ");
|
|
596
|
+
const lastSegment = spec.pathSegments[spec.pathSegments.length - 1];
|
|
597
|
+
const argDecls = spec.parameters.map(argumentDeclaration).join("\n\n");
|
|
598
|
+
const addLines = spec.parameters.map((p) => ` command.Arguments.Add(${p.name}Argument);`).join("\n");
|
|
599
|
+
const getValueLines = spec.parameters.map((p) => ` var ${p.name} = parseResult.GetValue(${p.name}Argument);`).join("\n");
|
|
600
|
+
const interpolated = spec.parameters.map((p) => `${p.name}={${p.name}}`).join(" ");
|
|
601
|
+
return `using System.CommandLine;
|
|
602
|
+
|
|
603
|
+
namespace Cli.Commands;
|
|
604
|
+
|
|
605
|
+
[CommandPath("${commandPath}")]
|
|
606
|
+
public sealed class ${className} : ICliCommand
|
|
607
|
+
{
|
|
608
|
+
public Command Build()
|
|
609
|
+
{
|
|
610
|
+
${argDecls}
|
|
611
|
+
|
|
612
|
+
var command = new Command("${lastSegment}", "${lastSegment} command");
|
|
613
|
+
${addLines}
|
|
614
|
+
command.SetAction(parseResult =>
|
|
615
|
+
{
|
|
616
|
+
${getValueLines}
|
|
617
|
+
Console.WriteLine($"${interpolated}");
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
return command;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
`;
|
|
624
|
+
}
|
|
625
|
+
function sampleArgValue2(param) {
|
|
626
|
+
if (param.type === "enum") return param.allowedValues?.[0] ?? "";
|
|
627
|
+
if (param.type === "integer") return "1";
|
|
628
|
+
if (param.type === "boolean") return "true";
|
|
629
|
+
return "value";
|
|
630
|
+
}
|
|
631
|
+
function generateTestFileContent2(spec) {
|
|
632
|
+
const className = toClassName2(spec.pathSegments);
|
|
633
|
+
const sampleArgs = spec.parameters.map(sampleArgValue2);
|
|
634
|
+
return `using System.CommandLine;
|
|
635
|
+
using Cli.Commands;
|
|
636
|
+
|
|
637
|
+
namespace Cli.Tests;
|
|
638
|
+
|
|
639
|
+
public class ${className}Tests
|
|
640
|
+
{
|
|
641
|
+
[Fact]
|
|
642
|
+
public void RunsSuccessfully()
|
|
643
|
+
{
|
|
644
|
+
var command = new ${className}().Build();
|
|
645
|
+
var parseResult = command.Parse([${sampleArgs.map((a) => `"${a}"`).join(", ")}]);
|
|
646
|
+
|
|
647
|
+
var exitCode = parseResult.Invoke();
|
|
648
|
+
|
|
649
|
+
Assert.Equal(0, exitCode);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
`;
|
|
653
|
+
}
|
|
654
|
+
async function generateCommand2(targetDir, spec) {
|
|
655
|
+
const className = toClassName2(spec.pathSegments);
|
|
656
|
+
const commandRelPath = path8.join("src", "Commands", `${className}.cs`);
|
|
657
|
+
const testRelPath = path8.join("tests", `${className}Tests.cs`);
|
|
658
|
+
await mkdir3(path8.join(targetDir, "src", "Commands"), { recursive: true });
|
|
659
|
+
await mkdir3(path8.join(targetDir, "tests"), { recursive: true });
|
|
660
|
+
await writeFile6(path8.join(targetDir, commandRelPath), generateCommandFileContent2(spec));
|
|
661
|
+
await writeFile6(path8.join(targetDir, testRelPath), generateTestFileContent2(spec));
|
|
662
|
+
return { commandFile: commandRelPath, testFile: testRelPath };
|
|
663
|
+
}
|
|
664
|
+
var dotnetCommandGenerator = {
|
|
665
|
+
listExistingCommands: listExistingCommands2,
|
|
666
|
+
generateCommand: generateCommand2
|
|
667
|
+
};
|
|
668
|
+
|
|
433
669
|
// src/languages/packs/dotnet.ts
|
|
434
670
|
function validateProjectName2(value) {
|
|
435
671
|
if (!value || value.trim().length === 0) return "Project name is required.";
|
|
@@ -441,7 +677,7 @@ function validateProjectName2(value) {
|
|
|
441
677
|
var dotnetPack = {
|
|
442
678
|
id: "dotnet",
|
|
443
679
|
displayName: ".NET / C# (System.CommandLine)",
|
|
444
|
-
templateDir:
|
|
680
|
+
templateDir: path9.join(findPackageRoot(), "templates", "dotnet"),
|
|
445
681
|
scaffoldCommands: [
|
|
446
682
|
{ command: "dotnet", args: ["restore"] },
|
|
447
683
|
{ command: "dotnet", args: ["build"] }
|
|
@@ -454,7 +690,8 @@ var dotnetPack = {
|
|
|
454
690
|
checkNameAvailability: nugetRegistryChecker.checkNameAvailability,
|
|
455
691
|
applyPrivateIntent: nugetRegistryChecker.applyPrivateIntent,
|
|
456
692
|
applyRegistryUrl: nugetRegistryChecker.applyRegistryUrl
|
|
457
|
-
}
|
|
693
|
+
},
|
|
694
|
+
commandGenerator: dotnetCommandGenerator
|
|
458
695
|
};
|
|
459
696
|
|
|
460
697
|
// src/languages/index.ts
|
|
@@ -539,15 +776,15 @@ async function runWizard(deps = defaultDeps) {
|
|
|
539
776
|
}
|
|
540
777
|
|
|
541
778
|
// src/scaffold.ts
|
|
542
|
-
import { cp, readdir, readFile as
|
|
543
|
-
import
|
|
779
|
+
import { cp, readdir as readdir3, readFile as readFile7, rename, writeFile as writeFile8 } from "fs/promises";
|
|
780
|
+
import path11 from "path";
|
|
544
781
|
import spawn from "cross-spawn";
|
|
545
782
|
|
|
546
783
|
// src/update/manifest.ts
|
|
547
784
|
import { createHash } from "crypto";
|
|
548
785
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
549
|
-
import { mkdir as
|
|
550
|
-
import
|
|
786
|
+
import { mkdir as mkdir4, readFile as readFile6, writeFile as writeFile7 } from "fs/promises";
|
|
787
|
+
import path10 from "path";
|
|
551
788
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
552
789
|
|
|
553
790
|
// src/errors.ts
|
|
@@ -565,7 +802,7 @@ function hashContent(content) {
|
|
|
565
802
|
async function hashCoreFiles(dir, adapter) {
|
|
566
803
|
const entries = await Promise.all(
|
|
567
804
|
adapter.coreFilePaths.map(async (relativePath) => {
|
|
568
|
-
const content = await
|
|
805
|
+
const content = await readFile6(path10.join(dir, relativePath), "utf8");
|
|
569
806
|
return [relativePath, hashContent(content)];
|
|
570
807
|
})
|
|
571
808
|
);
|
|
@@ -577,15 +814,15 @@ async function buildManifest(targetDir, generatorVersion, language, adapter) {
|
|
|
577
814
|
const { coreDependencies, coreScripts, coreFields } = adapter.extractCoreFields(manifestFile);
|
|
578
815
|
return { generatorVersion, language, coreFiles, coreDependencies, coreScripts, coreFields };
|
|
579
816
|
}
|
|
580
|
-
var MANIFEST_RELATIVE_PATH =
|
|
817
|
+
var MANIFEST_RELATIVE_PATH = path10.join(".clispark", "manifest.json");
|
|
581
818
|
async function writeManifest(targetDir, manifest) {
|
|
582
|
-
const manifestPath =
|
|
583
|
-
await
|
|
584
|
-
await
|
|
819
|
+
const manifestPath = path10.join(targetDir, MANIFEST_RELATIVE_PATH);
|
|
820
|
+
await mkdir4(path10.dirname(manifestPath), { recursive: true });
|
|
821
|
+
await writeFile7(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
|
|
585
822
|
}
|
|
586
823
|
async function readManifest(targetDir) {
|
|
587
824
|
try {
|
|
588
|
-
const content = await
|
|
825
|
+
const content = await readFile6(path10.join(targetDir, MANIFEST_RELATIVE_PATH), "utf8");
|
|
589
826
|
return JSON.parse(content);
|
|
590
827
|
} catch {
|
|
591
828
|
return void 0;
|
|
@@ -601,14 +838,14 @@ async function requireManifest(targetDir) {
|
|
|
601
838
|
return manifest;
|
|
602
839
|
}
|
|
603
840
|
function getGeneratorVersion() {
|
|
604
|
-
let dir =
|
|
841
|
+
let dir = path10.dirname(fileURLToPath2(import.meta.url));
|
|
605
842
|
while (true) {
|
|
606
|
-
const pkgPath =
|
|
843
|
+
const pkgPath = path10.join(dir, "package.json");
|
|
607
844
|
if (existsSync2(pkgPath)) {
|
|
608
845
|
const pkg = JSON.parse(readFileSync2(pkgPath, "utf8"));
|
|
609
846
|
if (pkg.name === "clispark") return pkg.version;
|
|
610
847
|
}
|
|
611
|
-
const parentDir =
|
|
848
|
+
const parentDir = path10.dirname(dir);
|
|
612
849
|
if (parentDir === dir) {
|
|
613
850
|
throw new Error("Could not locate clispark's own package.json.");
|
|
614
851
|
}
|
|
@@ -620,7 +857,7 @@ function getGeneratorVersion() {
|
|
|
620
857
|
async function assertTargetDirIsUsable(targetDir) {
|
|
621
858
|
let entries;
|
|
622
859
|
try {
|
|
623
|
-
entries = await
|
|
860
|
+
entries = await readdir3(targetDir);
|
|
624
861
|
} catch {
|
|
625
862
|
return;
|
|
626
863
|
}
|
|
@@ -632,10 +869,10 @@ function applyPlaceholders(content, projectName) {
|
|
|
632
869
|
return content.replaceAll("{{projectName}}", projectName);
|
|
633
870
|
}
|
|
634
871
|
async function collectFiles(dir) {
|
|
635
|
-
const entries = await
|
|
872
|
+
const entries = await readdir3(dir, { withFileTypes: true });
|
|
636
873
|
const files = await Promise.all(
|
|
637
874
|
entries.map((entry) => {
|
|
638
|
-
const fullPath =
|
|
875
|
+
const fullPath = path11.join(dir, entry.name);
|
|
639
876
|
return entry.isDirectory() ? collectFiles(fullPath) : Promise.resolve([fullPath]);
|
|
640
877
|
})
|
|
641
878
|
);
|
|
@@ -645,9 +882,9 @@ async function replacePlaceholdersInTree(targetDir, projectName) {
|
|
|
645
882
|
const files = await collectFiles(targetDir);
|
|
646
883
|
await Promise.all(
|
|
647
884
|
files.map(async (filePath) => {
|
|
648
|
-
const content = await
|
|
885
|
+
const content = await readFile7(filePath, "utf8");
|
|
649
886
|
if (content.includes("{{projectName}}")) {
|
|
650
|
-
await
|
|
887
|
+
await writeFile8(filePath, applyPlaceholders(content, projectName));
|
|
651
888
|
}
|
|
652
889
|
})
|
|
653
890
|
);
|
|
@@ -656,7 +893,7 @@ async function copyTemplate(options, pack) {
|
|
|
656
893
|
const { projectName, targetDir, registryUrl, publishIntent } = options;
|
|
657
894
|
await assertTargetDirIsUsable(targetDir);
|
|
658
895
|
await cp(pack.templateDir, targetDir, { recursive: true });
|
|
659
|
-
await rename(
|
|
896
|
+
await rename(path11.join(targetDir, "gitignore"), path11.join(targetDir, ".gitignore"));
|
|
660
897
|
await replacePlaceholdersInTree(targetDir, projectName);
|
|
661
898
|
if (publishIntent === false) {
|
|
662
899
|
await pack.registry.applyPrivateIntent(targetDir);
|
|
@@ -695,7 +932,7 @@ async function scaffoldProject(options, pack, deps = defaultScaffoldDeps) {
|
|
|
695
932
|
// src/logger.ts
|
|
696
933
|
import { randomBytes } from "crypto";
|
|
697
934
|
import { mkdirSync, readdirSync, statSync, unlinkSync, writeFileSync } from "fs";
|
|
698
|
-
import
|
|
935
|
+
import path12 from "path";
|
|
699
936
|
import envPaths from "env-paths";
|
|
700
937
|
import pino from "pino";
|
|
701
938
|
var paths = envPaths("clispark", { suffix: "" });
|
|
@@ -731,7 +968,7 @@ var SWEEP_MARKER_FILE = ".last-sweep";
|
|
|
731
968
|
var SWEEP_THROTTLE_MS = 24 * 60 * 60 * 1e3;
|
|
732
969
|
function sweepOldLogs(logDir) {
|
|
733
970
|
safely(() => {
|
|
734
|
-
const markerPath =
|
|
971
|
+
const markerPath = path12.join(logDir, SWEEP_MARKER_FILE);
|
|
735
972
|
let shouldSweep = true;
|
|
736
973
|
try {
|
|
737
974
|
shouldSweep = Date.now() - statSync(markerPath).mtimeMs >= SWEEP_THROTTLE_MS;
|
|
@@ -741,7 +978,7 @@ function sweepOldLogs(logDir) {
|
|
|
741
978
|
const cutoffMs = Date.now() - getRetentionDays() * 24 * 60 * 60 * 1e3;
|
|
742
979
|
for (const file of readdirSync(logDir)) {
|
|
743
980
|
if (file === SWEEP_MARKER_FILE) continue;
|
|
744
|
-
const filePath =
|
|
981
|
+
const filePath = path12.join(logDir, file);
|
|
745
982
|
if (statSync(filePath).mtimeMs < cutoffMs) {
|
|
746
983
|
unlinkSync(filePath);
|
|
747
984
|
}
|
|
@@ -752,7 +989,7 @@ function sweepOldLogs(logDir) {
|
|
|
752
989
|
function createLogger(commandName, logDir = paths.log) {
|
|
753
990
|
mkdirSync(logDir, { recursive: true });
|
|
754
991
|
sweepOldLogs(logDir);
|
|
755
|
-
const logFilePath =
|
|
992
|
+
const logFilePath = path12.join(logDir, buildLogFileName(commandName));
|
|
756
993
|
const fileDestination = pino.destination({ dest: logFilePath, sync: true, mode: 384 });
|
|
757
994
|
const destination = process.env.DEBUG ? pino.multistream([{ stream: fileDestination }, { stream: process.stdout }]) : fileDestination;
|
|
758
995
|
const logger = pino({ redact: buildRedactPaths([...SENSITIVE_LOG_KEYS, "registryUrl"]) }, destination);
|
|
@@ -790,8 +1027,8 @@ function withLogging(commandName, action, logDir = paths.log, loggerFactory = cr
|
|
|
790
1027
|
}
|
|
791
1028
|
|
|
792
1029
|
// src/update/update.ts
|
|
793
|
-
import { mkdir as
|
|
794
|
-
import
|
|
1030
|
+
import { mkdir as mkdir5, readFile as readFile8, writeFile as writeFile9 } from "fs/promises";
|
|
1031
|
+
import path13 from "path";
|
|
795
1032
|
import spawn2 from "cross-spawn";
|
|
796
1033
|
|
|
797
1034
|
// src/update/releasenotes.ts
|
|
@@ -877,7 +1114,7 @@ async function updateProject(targetDir, adapter, templateDir, language, deps = d
|
|
|
877
1114
|
const currentManifestFile = await adapter.readManifestFile(targetDir);
|
|
878
1115
|
const projectName = adapter.readProjectName(currentManifestFile);
|
|
879
1116
|
const newTemplateRaw = applyPlaceholders(
|
|
880
|
-
await
|
|
1117
|
+
await readFile8(path13.join(templateDir, adapter.manifestFileName), "utf8"),
|
|
881
1118
|
projectName
|
|
882
1119
|
);
|
|
883
1120
|
const newTemplateManifestFile = adapter.parseManifestFile(newTemplateRaw);
|
|
@@ -887,13 +1124,13 @@ async function updateProject(targetDir, adapter, templateDir, language, deps = d
|
|
|
887
1124
|
const perFileResults = await Promise.all(
|
|
888
1125
|
adapter.coreFilePaths.map(async (relativePath) => {
|
|
889
1126
|
const newContent = applyPlaceholders(
|
|
890
|
-
await
|
|
1127
|
+
await readFile8(path13.join(templateDir, adapter.templateSourcePath(relativePath)), "utf8"),
|
|
891
1128
|
projectName
|
|
892
1129
|
);
|
|
893
1130
|
const newHash = hashContent(newContent);
|
|
894
1131
|
let currentHash;
|
|
895
1132
|
try {
|
|
896
|
-
currentHash = hashContent(await
|
|
1133
|
+
currentHash = hashContent(await readFile8(path13.join(targetDir, relativePath), "utf8"));
|
|
897
1134
|
} catch {
|
|
898
1135
|
currentHash = void 0;
|
|
899
1136
|
}
|
|
@@ -905,13 +1142,13 @@ async function updateProject(targetDir, adapter, templateDir, language, deps = d
|
|
|
905
1142
|
files.push({ path: relativePath, outcome: result.outcome });
|
|
906
1143
|
newCoreFiles[relativePath] = result.value;
|
|
907
1144
|
if (result.outcome === "added" || result.outcome === "replaced") {
|
|
908
|
-
fileWrites.push({ targetPath:
|
|
1145
|
+
fileWrites.push({ targetPath: path13.join(targetDir, relativePath), content: newContent });
|
|
909
1146
|
}
|
|
910
1147
|
}
|
|
911
1148
|
for (const relativePath of Object.keys(oldManifest.coreFiles)) {
|
|
912
1149
|
if (adapter.coreFilePaths.includes(relativePath)) continue;
|
|
913
1150
|
try {
|
|
914
|
-
await
|
|
1151
|
+
await readFile8(path13.join(targetDir, relativePath), "utf8");
|
|
915
1152
|
files.push({ path: relativePath, outcome: "no-longer-core" });
|
|
916
1153
|
} catch {
|
|
917
1154
|
}
|
|
@@ -933,8 +1170,8 @@ async function updateProject(targetDir, adapter, templateDir, language, deps = d
|
|
|
933
1170
|
};
|
|
934
1171
|
}
|
|
935
1172
|
for (const write of fileWrites) {
|
|
936
|
-
await
|
|
937
|
-
await
|
|
1173
|
+
await mkdir5(path13.dirname(write.targetPath), { recursive: true });
|
|
1174
|
+
await writeFile9(write.targetPath, write.content);
|
|
938
1175
|
}
|
|
939
1176
|
if (fileMerge.changed) {
|
|
940
1177
|
await adapter.writeManifestFile(targetDir, fileMerge.updatedFile);
|
|
@@ -996,6 +1233,153 @@ function formatUpdateSummary(result) {
|
|
|
996
1233
|
return lines.join("\n");
|
|
997
1234
|
}
|
|
998
1235
|
|
|
1236
|
+
// src/add-wizard.ts
|
|
1237
|
+
import { intro as intro2, outro as outro2, select as select2, text as text2, confirm, isCancel as isCancel2, cancel as cancel2, log as log2 } from "@clack/prompts";
|
|
1238
|
+
function exitIfCancelled2(value) {
|
|
1239
|
+
if (isCancel2(value)) {
|
|
1240
|
+
cancel2("Operation cancelled.");
|
|
1241
|
+
process.exit(1);
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
var NEW_TOP_LEVEL = "__new_top_level__";
|
|
1245
|
+
var HERE = "__here__";
|
|
1246
|
+
function flattenForMenu(nodes) {
|
|
1247
|
+
const result = [];
|
|
1248
|
+
for (const node of nodes) {
|
|
1249
|
+
result.push({ value: node.path, label: node.displayLabel });
|
|
1250
|
+
result.push(...flattenForMenu(node.children));
|
|
1251
|
+
}
|
|
1252
|
+
return result;
|
|
1253
|
+
}
|
|
1254
|
+
function findNode(nodes, targetPath) {
|
|
1255
|
+
for (const node of nodes) {
|
|
1256
|
+
if (node.path === targetPath) return node;
|
|
1257
|
+
const found = findNode(node.children, targetPath);
|
|
1258
|
+
if (found) return found;
|
|
1259
|
+
}
|
|
1260
|
+
return void 0;
|
|
1261
|
+
}
|
|
1262
|
+
async function selectWithinNode(node) {
|
|
1263
|
+
if (node.children.length === 0) {
|
|
1264
|
+
return node.path.split(" ");
|
|
1265
|
+
}
|
|
1266
|
+
const options = [
|
|
1267
|
+
{ value: HERE, label: `Direct subcommand of "${node.path}"` },
|
|
1268
|
+
...node.children.map((child) => ({ value: child.path, label: `Under "${child.path}"` }))
|
|
1269
|
+
];
|
|
1270
|
+
const choice = await select2({ message: `Where under "${node.path}"?`, options });
|
|
1271
|
+
exitIfCancelled2(choice);
|
|
1272
|
+
if (choice === HERE) {
|
|
1273
|
+
return node.path.split(" ");
|
|
1274
|
+
}
|
|
1275
|
+
const childNode = node.children.find((c) => c.path === choice);
|
|
1276
|
+
return selectWithinNode(childNode);
|
|
1277
|
+
}
|
|
1278
|
+
async function selectPath(existing) {
|
|
1279
|
+
const options = [{ value: NEW_TOP_LEVEL, label: "New top-level command" }, ...flattenForMenu(existing)];
|
|
1280
|
+
const choice = await select2({ message: "Where should the new command go?", options });
|
|
1281
|
+
exitIfCancelled2(choice);
|
|
1282
|
+
if (choice === NEW_TOP_LEVEL) {
|
|
1283
|
+
return [];
|
|
1284
|
+
}
|
|
1285
|
+
const node = findNode(existing, choice);
|
|
1286
|
+
return selectWithinNode(node);
|
|
1287
|
+
}
|
|
1288
|
+
function flattenPaths(nodes) {
|
|
1289
|
+
return nodes.flatMap((node) => [node.path, ...flattenPaths(node.children)]);
|
|
1290
|
+
}
|
|
1291
|
+
async function collectParameters() {
|
|
1292
|
+
const parameters = [];
|
|
1293
|
+
let hasOptional = false;
|
|
1294
|
+
for (; ; ) {
|
|
1295
|
+
const addMore = await confirm({
|
|
1296
|
+
message: parameters.length === 0 ? "Add a parameter?" : "Add another parameter?"
|
|
1297
|
+
});
|
|
1298
|
+
exitIfCancelled2(addMore);
|
|
1299
|
+
if (!addMore) break;
|
|
1300
|
+
const nameValue = await text2({
|
|
1301
|
+
message: "Parameter name",
|
|
1302
|
+
validate: (value) => {
|
|
1303
|
+
if (!/^[a-z][a-zA-Z0-9]*$/.test(value)) return "Use a single word starting with a lowercase letter.";
|
|
1304
|
+
if (parameters.some((p) => p.name === value)) return "A parameter with this name already exists.";
|
|
1305
|
+
return void 0;
|
|
1306
|
+
}
|
|
1307
|
+
});
|
|
1308
|
+
exitIfCancelled2(nameValue);
|
|
1309
|
+
const name = nameValue;
|
|
1310
|
+
const typeValue = await select2({
|
|
1311
|
+
message: "Parameter type",
|
|
1312
|
+
options: [
|
|
1313
|
+
{ value: "string", label: "String" },
|
|
1314
|
+
{ value: "integer", label: "Integer" },
|
|
1315
|
+
{ value: "boolean", label: "Boolean" },
|
|
1316
|
+
{ value: "enum", label: "String with allowed values" }
|
|
1317
|
+
]
|
|
1318
|
+
});
|
|
1319
|
+
exitIfCancelled2(typeValue);
|
|
1320
|
+
const type = typeValue;
|
|
1321
|
+
let required = false;
|
|
1322
|
+
if (type !== "boolean") {
|
|
1323
|
+
const options = hasOptional ? [{ value: false, label: "Optional" }] : [
|
|
1324
|
+
{ value: true, label: "Required" },
|
|
1325
|
+
{ value: false, label: "Optional" }
|
|
1326
|
+
];
|
|
1327
|
+
const requiredValue = await select2({ message: "Required or optional?", options });
|
|
1328
|
+
exitIfCancelled2(requiredValue);
|
|
1329
|
+
required = requiredValue;
|
|
1330
|
+
}
|
|
1331
|
+
if (!required) hasOptional = true;
|
|
1332
|
+
let allowedValues;
|
|
1333
|
+
if (type === "enum") {
|
|
1334
|
+
const valuesInput = await text2({
|
|
1335
|
+
message: "Allowed values (comma-separated)",
|
|
1336
|
+
validate: (value) => {
|
|
1337
|
+
const values = value.split(",").map((v) => v.trim()).filter(Boolean);
|
|
1338
|
+
if (values.length < 2) return "Enter at least two comma-separated values.";
|
|
1339
|
+
for (const v of values) {
|
|
1340
|
+
if (!/^[A-Za-z0-9_-]+$/.test(v)) {
|
|
1341
|
+
return `Invalid value "${v}": use only letters, numbers, hyphens, and underscores.`;
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
return void 0;
|
|
1345
|
+
}
|
|
1346
|
+
});
|
|
1347
|
+
exitIfCancelled2(valuesInput);
|
|
1348
|
+
allowedValues = valuesInput.split(",").map((v) => v.trim()).filter(Boolean);
|
|
1349
|
+
}
|
|
1350
|
+
parameters.push({ name, type, required, allowedValues });
|
|
1351
|
+
}
|
|
1352
|
+
return parameters;
|
|
1353
|
+
}
|
|
1354
|
+
async function runAddWizard(targetDir, deps) {
|
|
1355
|
+
intro2("clispark add \u2014 add a new command");
|
|
1356
|
+
const existing = await deps.commandGenerator.listExistingCommands(targetDir);
|
|
1357
|
+
const pathSegments = await selectPath(existing);
|
|
1358
|
+
const existingPaths = new Set(flattenPaths(existing));
|
|
1359
|
+
const nameValue = await text2({
|
|
1360
|
+
message: "Command name",
|
|
1361
|
+
validate: (value) => {
|
|
1362
|
+
if (!/^[a-z][a-zA-Z0-9]*$/.test(value)) return "Use a single word starting with a lowercase letter.";
|
|
1363
|
+
const fullPath = [...pathSegments, value].join(" ");
|
|
1364
|
+
if (existingPaths.has(fullPath)) return `"${fullPath}" already exists.`;
|
|
1365
|
+
return void 0;
|
|
1366
|
+
}
|
|
1367
|
+
});
|
|
1368
|
+
exitIfCancelled2(nameValue);
|
|
1369
|
+
const fullPathSegments = [...pathSegments, nameValue];
|
|
1370
|
+
const parameters = await collectParameters();
|
|
1371
|
+
log2.info(`About to create "${fullPathSegments.join(" ")}" with ${parameters.length} parameter(s).`);
|
|
1372
|
+
const proceed = await confirm({ message: "Proceed?" });
|
|
1373
|
+
exitIfCancelled2(proceed);
|
|
1374
|
+
if (!proceed) {
|
|
1375
|
+
cancel2("Cancelled.");
|
|
1376
|
+
process.exit(1);
|
|
1377
|
+
}
|
|
1378
|
+
const spec = { pathSegments: fullPathSegments, parameters };
|
|
1379
|
+
const result = await deps.commandGenerator.generateCommand(targetDir, spec);
|
|
1380
|
+
outro2(`Created ${result.commandFile} and ${result.testFile}.`);
|
|
1381
|
+
}
|
|
1382
|
+
|
|
999
1383
|
// src/whoami.ts
|
|
1000
1384
|
import os from "os";
|
|
1001
1385
|
var JOKE_API_URL = "https://v2.jokeapi.dev/joke/Programming,Miscellaneous";
|
|
@@ -1110,7 +1494,7 @@ function resolvePack(language) {
|
|
|
1110
1494
|
program.action(
|
|
1111
1495
|
(options) => withLogging("scaffold", async (logger) => {
|
|
1112
1496
|
const answers = await runWizard();
|
|
1113
|
-
const targetDir =
|
|
1497
|
+
const targetDir = path14.join(process.cwd(), answers.projectName);
|
|
1114
1498
|
const pack = resolvePack(answers.language);
|
|
1115
1499
|
logger.info({ projectName: answers.projectName, targetDir, language: pack.id }, "scaffold started");
|
|
1116
1500
|
await scaffoldProject(
|
|
@@ -1151,6 +1535,17 @@ program.command("releasenotes").description("Show what changed between this proj
|
|
|
1151
1535
|
console.log(formatReleaseNotes(result));
|
|
1152
1536
|
})
|
|
1153
1537
|
);
|
|
1538
|
+
program.command("add").description("Add a new command to an already-scaffolded project").action(
|
|
1539
|
+
withLogging("add", async (logger) => {
|
|
1540
|
+
const targetDir = process.cwd();
|
|
1541
|
+
const manifest = await requireManifest(targetDir);
|
|
1542
|
+
const language = manifest.language ?? "node";
|
|
1543
|
+
const pack = resolvePack(language);
|
|
1544
|
+
logger.info({ targetDir, language }, "add started");
|
|
1545
|
+
await runAddWizard(targetDir, { commandGenerator: pack.commandGenerator });
|
|
1546
|
+
logger.info({}, "add completed");
|
|
1547
|
+
})
|
|
1548
|
+
);
|
|
1154
1549
|
function resolveWhoamiMode(options) {
|
|
1155
1550
|
if (options.joke && options.fact) {
|
|
1156
1551
|
throw new UserError("Use either --joke or --fact, not both.");
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/wizard.ts","../src/languages/packs/node-oclif.ts","../src/package-root.ts","../src/update/adapters/node-oclif.ts","../src/update/reconcile.ts","../src/languages/registry-checkers/npm.ts","../src/languages/packs/dotnet.ts","../src/update/adapters/dotnet.ts","../src/languages/registry-checkers/nuget.ts","../src/languages/index.ts","../src/scaffold.ts","../src/update/manifest.ts","../src/errors.ts","../src/logger.ts","../src/update/update.ts","../src/update/releasenotes.ts","../src/whoami.ts","../src/confetti.ts"],"sourcesContent":["// src/cli.ts\nimport path from 'node:path';\nimport { Command } from 'commander';\nimport { runWizard } from './wizard';\nimport { scaffoldProject } from './scaffold';\nimport { withLogging } from './logger';\nimport { formatUpdateSummary, updateProject } from './update/update';\nimport { fetchReleaseNotes, formatReleaseNotes } from './update/releasenotes';\nimport { getGeneratorVersion, requireManifest } from './update/manifest';\nimport { LANGUAGE_PACKS } from './languages';\nimport type { LanguagePack } from './languages/pack';\nimport { UserError } from './errors';\nimport { getWhoamiOutput, type WhoamiMode } from './whoami';\nimport { printConfetti } from './confetti';\n\nconst program = new Command();\n\nprogram\n .name('clispark')\n .description('Interactive scaffolding tool for new CLI projects')\n .option('--no-confetti', 'Skip the confetti after a successful run')\n .configureHelp({ showGlobalOptions: true })\n .version(getGeneratorVersion());\n\nfunction resolvePack(language: string): LanguagePack {\n const pack = LANGUAGE_PACKS[language];\n if (!pack) {\n throw new UserError(`Unknown language \"${language}\" — is your clispark installation out of date?`);\n }\n return pack;\n}\n\nprogram.action((options: { confetti?: boolean }) =>\n withLogging('scaffold', async (logger) => {\n const answers = await runWizard();\n const targetDir = path.join(process.cwd(), answers.projectName);\n const pack = resolvePack(answers.language);\n\n logger.info({ projectName: answers.projectName, targetDir, language: pack.id }, 'scaffold started');\n await scaffoldProject(\n {\n projectName: answers.projectName,\n targetDir,\n registryUrl: answers.registryUrl,\n publishIntent: answers.publishIntent,\n },\n pack,\n );\n logger.info({ projectName: answers.projectName }, 'scaffold completed');\n\n console.log(`\\nDone! Your new CLI project is ready at ${targetDir}`);\n if (options.confetti !== false) printConfetti();\n })(),\n);\n\nprogram\n .command('update')\n .description('Update generator-managed core files and dependencies to the latest clispark version')\n .action((_options: unknown, command: Command) =>\n withLogging('update', async (logger) => {\n const targetDir = process.cwd();\n const manifest = await requireManifest(targetDir);\n const language = manifest.language ?? 'node';\n const pack = resolvePack(language);\n logger.info({ targetDir, language }, 'update started');\n const result = await updateProject(targetDir, pack.updateAdapter, pack.templateDir, language);\n logger.info({ status: result.status }, 'update completed');\n console.log(formatUpdateSummary(result));\n const { confetti } = command.optsWithGlobals<{ confetti?: boolean }>();\n if (confetti !== false && result.status === 'updated') printConfetti();\n })(),\n );\n\nprogram\n .command('releasenotes')\n .description(\"Show what changed between this project's generator version and the latest clispark version\")\n .action(\n withLogging('releasenotes', async (logger) => {\n const targetDir = process.cwd();\n logger.info({ targetDir }, 'releasenotes started');\n const result = await fetchReleaseNotes(targetDir);\n logger.info({ status: result.status }, 'releasenotes completed');\n console.log(formatReleaseNotes(result));\n }),\n );\n\nfunction resolveWhoamiMode(options: { joke?: boolean; fact?: boolean }): WhoamiMode {\n if (options.joke && options.fact) {\n throw new UserError('Use either --joke or --fact, not both.');\n }\n if (options.joke) return 'joke';\n if (options.fact) return 'fact';\n return 'random';\n}\n\nprogram\n .command('whoami')\n .description('A little something extra')\n .option('--joke', 'Always show a joke')\n .option('--fact', 'Always show a fun fact about this machine')\n .action((options: { joke?: boolean; fact?: boolean }) =>\n withLogging('whoami', async (logger) => {\n const mode = resolveWhoamiMode(options);\n logger.info({ mode }, 'whoami started');\n console.log(await getWhoamiOutput(fetch, undefined, undefined, mode));\n logger.info({}, 'whoami completed');\n })(),\n );\n\nprogram.parseAsync(process.argv).catch((error: unknown) => {\n console.error(error);\n process.exit(1);\n});\n","// src/wizard.ts\nimport { intro, outro, text, select, log, isCancel, cancel } from '@clack/prompts';\nimport { LANGUAGE_PACKS } from './languages';\nimport type { LanguagePack } from './languages/pack';\nimport type { NameCheckResult } from './languages/registry-checker';\nimport type { Profile, WizardAnswers } from './types';\n\nexport interface WizardDeps {\n languagePacks: Record<string, LanguagePack>;\n}\n\nconst defaultDeps: WizardDeps = {\n languagePacks: LANGUAGE_PACKS,\n};\n\nfunction exitIfCancelled(value: unknown): void {\n if (isCancel(value)) {\n cancel('Operation cancelled.');\n process.exit(1);\n }\n}\n\nexport async function runWizard(deps: WizardDeps = defaultDeps): Promise<WizardAnswers> {\n intro('clispark — scaffold a new CLI project');\n\n const packs = Object.values(deps.languagePacks);\n const languageValue = await select({\n message: 'Which language?',\n options: packs.map((pack) => ({ value: pack.id, label: pack.displayName })),\n });\n exitIfCancelled(languageValue);\n const pack = deps.languagePacks[languageValue as string];\n\n const nameValue = await text({\n message: 'Project name',\n validate: pack.validateProjectName,\n });\n exitIfCancelled(nameValue);\n let projectName = nameValue as string;\n\n const profileValue = await select({\n message: 'Is this a work or private project?',\n options: [\n { value: 'private', label: 'Private' },\n { value: 'work', label: 'Work' },\n ],\n });\n exitIfCancelled(profileValue);\n const profile = profileValue as Profile;\n\n let registryUrl = pack.registry.defaultUrl;\n if (profile === 'work') {\n const registryValue = await text({\n message: pack.registry.promptLabel,\n placeholder: pack.registry.defaultUrl,\n defaultValue: pack.registry.defaultUrl,\n });\n exitIfCancelled(registryValue);\n registryUrl = (registryValue as string) || pack.registry.defaultUrl;\n }\n\n const publishIntentValue = await select({\n message: 'Do you plan to publish this?',\n options: [\n { value: false, label: 'No' },\n { value: true, label: 'Yes' },\n ],\n initialValue: false,\n });\n exitIfCancelled(publishIntentValue);\n const publishIntent = publishIntentValue as boolean;\n\n let nameAvailability: NameCheckResult = 'skipped';\n\n if (publishIntent) {\n nameAvailability = await pack.registry.checkNameAvailability(projectName, registryUrl);\n\n while (nameAvailability === 'taken') {\n log.warn(`\"${projectName}\" is already taken on ${registryUrl}. Please choose a different name.`);\n\n const retryValue = await text({\n message: 'Project name',\n validate: pack.validateProjectName,\n });\n exitIfCancelled(retryValue);\n projectName = retryValue as string;\n\n nameAvailability = await pack.registry.checkNameAvailability(projectName, registryUrl);\n }\n\n if (nameAvailability === 'unverified') {\n log.warn(`Could not verify availability of \"${projectName}\" on ${registryUrl}. Continuing anyway.`);\n }\n }\n\n outro(`Ready to scaffold \"${projectName}\".`);\n\n return { language: pack.id, projectName, profile, registryUrl, publishIntent, nameAvailability };\n}\n","// src/languages/packs/node-oclif.ts\nimport path from 'node:path';\nimport { findPackageRoot } from '../../package-root';\nimport type { LanguagePack } from '../pack';\nimport { nodeOclifAdapter } from '../../update/adapters/node-oclif';\nimport { npmRegistryChecker, NPM_DEFAULT_REGISTRY_URL } from '../registry-checkers/npm';\n\nfunction validateProjectName(value: string): string | undefined {\n if (!value || value.trim().length === 0) return 'Project name is required.';\n if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(value)) {\n return 'Use lowercase letters and numbers, with single hyphens between words (no leading, trailing, or repeated hyphens).';\n }\n return undefined;\n}\n\nexport const nodeOclifPack: LanguagePack = {\n id: 'node',\n displayName: 'Node.js / TypeScript (oclif)',\n templateDir: path.join(findPackageRoot(), 'templates', 'node'),\n scaffoldCommands: [\n { command: 'npm', args: ['install'] },\n { command: 'npm', args: ['run', 'build'] },\n ],\n validateProjectName,\n updateAdapter: nodeOclifAdapter,\n registry: {\n defaultUrl: NPM_DEFAULT_REGISTRY_URL,\n promptLabel: 'Custom npm registry URL (leave empty for npmjs.org)',\n checkNameAvailability: npmRegistryChecker.checkNameAvailability,\n applyPrivateIntent: npmRegistryChecker.applyPrivateIntent,\n applyRegistryUrl: npmRegistryChecker.applyRegistryUrl,\n },\n};\n","import { existsSync, readFileSync } from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/**\n * Finds clispark's own package root by walking up from this module's\n * location. A fixed relative path can't work here: this module's depth\n * below the package root differs between running from source (tests) and\n * running as part of the bundled `dist/cli.js` (tsup flattens everything\n * into one file, so `import.meta.url` no longer reflects the original\n * per-module nesting) — but the walk-up strategy is depth-independent\n * either way, since it doesn't matter where exactly the walk starts.\n */\nexport function findPackageRoot(): string {\n let dir = path.dirname(fileURLToPath(import.meta.url));\n while (true) {\n const pkgPath = path.join(dir, 'package.json');\n if (existsSync(pkgPath)) {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as { name?: string };\n if (pkg.name === 'clispark') return dir;\n }\n const parentDir = path.dirname(dir);\n if (parentDir === dir) {\n throw new Error(\"Could not locate clispark's own package.json.\");\n }\n dir = parentDir;\n }\n}\n","// src/update/adapters/node-oclif.ts\nimport { readFile, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport type { Manifest } from '../manifest';\nimport type { CoreFieldsExtraction, ManifestFileMergeResult, UpdateAdapter } from '../adapter';\nimport { deepEquals, reconcileEntry, stringEquals, type FieldOutcome } from '../reconcile';\n\nexport const CORE_FILE_PATHS = [\n 'bin/run.ts',\n 'src/index.ts',\n 'src/base-command.ts',\n 'src/logger.ts',\n 'tsup.config.ts',\n 'vitest.config.ts',\n 'tsconfig.json',\n 'ARCHITECTURE.md',\n '.gitignore',\n] as const;\n\nexport const CORE_SCRIPT_NAMES = ['build', 'postbuild', 'pretest', 'test', 'typecheck'] as const;\n\nexport interface PackageJsonShape {\n name: string;\n version: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n scripts?: Record<string, string>;\n engines?: Record<string, string>;\n oclif?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\nfunction currentDependencyValue(\n pkg: PackageJsonShape,\n name: string,\n): { section: 'dependencies' | 'devDependencies'; value: string } | undefined {\n if (pkg.dependencies?.[name] !== undefined) return { section: 'dependencies', value: pkg.dependencies[name] };\n if (pkg.devDependencies?.[name] !== undefined) {\n return { section: 'devDependencies', value: pkg.devDependencies[name] };\n }\n return undefined;\n}\n\nfunction extractCoreFields(pkg: PackageJsonShape): CoreFieldsExtraction {\n const coreDependencies = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) };\n\n const coreScripts: Record<string, string> = {};\n for (const name of CORE_SCRIPT_NAMES) {\n const value = pkg.scripts?.[name];\n if (value !== undefined) coreScripts[name] = value;\n }\n\n return {\n coreDependencies,\n coreScripts,\n coreFields: {\n engines: pkg.engines ?? {},\n oclif: pkg.oclif ?? {},\n },\n };\n}\n\nfunction mergePackageJson(\n currentPkg: PackageJsonShape,\n oldManifest: Manifest,\n newTemplatePkg: PackageJsonShape,\n): ManifestFileMergeResult {\n const updatedFile: PackageJsonShape = { ...currentPkg };\n let changed = false;\n\n const dependencies: FieldOutcome[] = [];\n const coreDependencies: Record<string, string> = {};\n const dependencyNames = new Set([\n ...Object.keys(newTemplatePkg.dependencies ?? {}),\n ...Object.keys(newTemplatePkg.devDependencies ?? {}),\n ]);\n\n for (const name of dependencyNames) {\n const inNewDependencies = newTemplatePkg.dependencies?.[name] !== undefined;\n const newValue = (inNewDependencies ? newTemplatePkg.dependencies : newTemplatePkg.devDependencies)![name];\n const current = currentDependencyValue(currentPkg, name);\n const oldValue = oldManifest.coreDependencies[name];\n\n const result = reconcileEntry(current?.value, oldValue, newValue, stringEquals);\n dependencies.push({ key: name, outcome: result.outcome });\n coreDependencies[name] = result.value;\n\n if (result.outcome !== 'skipped' && result.value !== current?.value) {\n changed = true;\n const section = current?.section ?? (inNewDependencies ? 'dependencies' : 'devDependencies');\n updatedFile[section] = { ...updatedFile[section], [name]: result.value };\n }\n }\n\n const scripts: FieldOutcome[] = [];\n const coreScripts: Record<string, string> = {};\n\n for (const name of CORE_SCRIPT_NAMES) {\n const newValue = newTemplatePkg.scripts?.[name];\n if (newValue === undefined) continue;\n const currentValue = currentPkg.scripts?.[name];\n const oldValue = oldManifest.coreScripts[name];\n\n const result = reconcileEntry(currentValue, oldValue, newValue, stringEquals);\n scripts.push({ key: name, outcome: result.outcome });\n coreScripts[name] = result.value;\n\n if (result.outcome !== 'skipped' && result.value !== currentValue) {\n changed = true;\n updatedFile.scripts = { ...updatedFile.scripts, [name]: result.value };\n }\n }\n\n const oldCoreFields = oldManifest.coreFields as {\n engines?: Record<string, string>;\n oclif?: Record<string, unknown>;\n };\n const fields: FieldOutcome[] = [];\n let enginesValue: Record<string, string> = oldCoreFields.engines ?? {};\n let oclifValue: Record<string, unknown> = oldCoreFields.oclif ?? {};\n\n if (newTemplatePkg.engines !== undefined) {\n const enginesResult = reconcileEntry(\n currentPkg.engines,\n oldCoreFields.engines,\n newTemplatePkg.engines,\n deepEquals,\n );\n fields.push({ key: 'engines', outcome: enginesResult.outcome });\n enginesValue = enginesResult.value;\n if (enginesResult.outcome !== 'skipped' && !deepEquals(enginesResult.value, currentPkg.engines)) {\n changed = true;\n updatedFile.engines = enginesResult.value;\n }\n }\n\n if (newTemplatePkg.oclif !== undefined) {\n const oclifResult = reconcileEntry(currentPkg.oclif, oldCoreFields.oclif, newTemplatePkg.oclif, deepEquals);\n fields.push({ key: 'oclif', outcome: oclifResult.outcome });\n oclifValue = oclifResult.value;\n if (oclifResult.outcome !== 'skipped' && !deepEquals(oclifResult.value, currentPkg.oclif)) {\n changed = true;\n updatedFile.oclif = oclifResult.value;\n }\n }\n\n return {\n updatedFile,\n changed,\n dependencies,\n scripts,\n fields,\n coreDependencies,\n coreScripts,\n coreFields: { engines: enginesValue, oclif: oclifValue },\n };\n}\n\nexport const nodeOclifAdapter: UpdateAdapter = {\n coreFilePaths: CORE_FILE_PATHS,\n\n templateSourcePath(relativePath) {\n return relativePath === '.gitignore' ? 'gitignore' : relativePath;\n },\n\n manifestFileName: 'package.json',\n\n async readManifestFile(dir) {\n const content = await readFile(path.join(dir, 'package.json'), 'utf8');\n return JSON.parse(content) as PackageJsonShape;\n },\n\n async writeManifestFile(dir, content) {\n await writeFile(path.join(dir, 'package.json'), JSON.stringify(content, null, 2) + '\\n');\n },\n\n parseManifestFile(rawContent) {\n return JSON.parse(rawContent) as PackageJsonShape;\n },\n\n readProjectName(manifestFile) {\n return (manifestFile as PackageJsonShape).name;\n },\n\n extractCoreFields(manifestFile) {\n return extractCoreFields(manifestFile as PackageJsonShape);\n },\n\n mergeManifestFile(current, oldManifest, newTemplate) {\n return mergePackageJson(current as PackageJsonShape, oldManifest, newTemplate as PackageJsonShape);\n },\n};\n","export type ReconcileOutcome = 'added' | 'replaced' | 'skipped';\n\n/** A named field/dependency/script whose reconciliation outcome should be reported to the user (e.g. \"pino: replaced\"). */\nexport interface FieldOutcome {\n key: string;\n outcome: ReconcileOutcome;\n}\n\nexport interface ReconcileResult<T> {\n outcome: ReconcileOutcome;\n value: T;\n}\n\nexport function reconcileEntry<T>(\n currentLiveValue: T | undefined,\n oldManifestValue: T | undefined,\n newTemplateValue: T,\n isEqual: (a: T, b: T) => boolean,\n): ReconcileResult<T> {\n if (currentLiveValue === undefined) {\n return { outcome: 'added', value: newTemplateValue };\n }\n if (oldManifestValue !== undefined && isEqual(currentLiveValue, oldManifestValue)) {\n return { outcome: 'replaced', value: newTemplateValue };\n }\n return { outcome: 'skipped', value: oldManifestValue ?? currentLiveValue };\n}\n\nexport function stringEquals(a: string, b: string): boolean {\n return a === b;\n}\n\nexport function deepEquals(a: unknown, b: unknown): boolean {\n return JSON.stringify(a) === JSON.stringify(b);\n}\n","// src/languages/registry-checkers/npm.ts\nimport { readFile, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport type { NameCheckResult, RegistryChecker } from '../registry-checker';\n\nexport const NPM_DEFAULT_REGISTRY_URL = 'https://registry.npmjs.org';\n\nconst FETCH_TIMEOUT_MS = 5000;\n\nasync function checkNameAvailability(name: string, registryUrl: string): Promise<NameCheckResult> {\n const url = `${registryUrl.replace(/\\/$/, '')}/${encodeURIComponent(name)}`;\n\n try {\n const response = await fetch(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });\n if (response.status === 404) return 'available';\n if (response.status === 200) return 'taken';\n return 'unverified';\n } catch {\n return 'unverified';\n }\n}\n\nasync function applyPrivateIntent(targetDir: string): Promise<void> {\n const packageJsonPath = path.join(targetDir, 'package.json');\n const pkg = JSON.parse(await readFile(packageJsonPath, 'utf8')) as Record<string, unknown>;\n pkg.private = true;\n await writeFile(packageJsonPath, JSON.stringify(pkg, null, 2) + '\\n');\n}\n\nasync function applyRegistryUrl(targetDir: string, registryUrl: string): Promise<void> {\n await writeFile(path.join(targetDir, '.npmrc'), `registry=${registryUrl}\\n`);\n}\n\nexport const npmRegistryChecker: RegistryChecker = {\n checkNameAvailability,\n applyPrivateIntent,\n applyRegistryUrl,\n};\n","// src/languages/packs/dotnet.ts\nimport path from 'node:path';\nimport { findPackageRoot } from '../../package-root';\nimport type { LanguagePack } from '../pack';\nimport { dotnetAdapter } from '../../update/adapters/dotnet';\nimport { nugetRegistryChecker, NUGET_DEFAULT_REGISTRY_URL } from '../registry-checkers/nuget';\n\nfunction validateProjectName(value: string): string | undefined {\n if (!value || value.trim().length === 0) return 'Project name is required.';\n if (!/^[A-Z][A-Za-z0-9]*$/.test(value)) {\n return 'Use PascalCase, starting with an uppercase letter (e.g. MyTool).';\n }\n return undefined;\n}\n\nexport const dotnetPack: LanguagePack = {\n id: 'dotnet',\n displayName: '.NET / C# (System.CommandLine)',\n templateDir: path.join(findPackageRoot(), 'templates', 'dotnet'),\n scaffoldCommands: [\n { command: 'dotnet', args: ['restore'] },\n { command: 'dotnet', args: ['build'] },\n ],\n validateProjectName,\n updateAdapter: dotnetAdapter,\n registry: {\n defaultUrl: NUGET_DEFAULT_REGISTRY_URL,\n promptLabel: 'Custom NuGet feed URL (leave empty for nuget.org)',\n checkNameAvailability: nugetRegistryChecker.checkNameAvailability,\n applyPrivateIntent: nugetRegistryChecker.applyPrivateIntent,\n applyRegistryUrl: nugetRegistryChecker.applyRegistryUrl,\n },\n};\n","// src/update/adapters/dotnet.ts\nimport { readFile, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport type { Manifest } from '../manifest';\nimport type { CoreFieldsExtraction, ManifestFileMergeResult, UpdateAdapter } from '../adapter';\nimport { reconcileEntry, stringEquals, type FieldOutcome } from '../reconcile';\n\nexport const CORE_FILE_PATHS = [\n 'Cli.slnx',\n 'src/Program.cs',\n 'src/ICliCommand.cs',\n 'src/CommandPathAttribute.cs',\n 'src/CommandDiscovery.cs',\n 'src/CliUserException.cs',\n 'src/Logging/CliLoggerFactory.cs',\n 'src/Logging/SensitivePropertyEnricher.cs',\n 'tests/Cli.Tests.csproj',\n 'ARCHITECTURE.md',\n '.gitignore',\n] as const;\n\nexport interface DotnetManifestFile {\n raw: string;\n version: string;\n targetFramework: string;\n packageId: string;\n toolCommandName: string;\n packageReferences: Record<string, string>;\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nfunction extractTag(content: string, tag: string): string {\n const match = content.match(new RegExp(`<${tag}>([^<]*)</${tag}>`));\n if (!match) throw new Error(`.csproj is missing a <${tag}> tag`);\n return match[1];\n}\n\nfunction extractPackageReferences(content: string): Record<string, string> {\n const refs: Record<string, string> = {};\n const re = /<PackageReference\\s+Include=\"([^\"]+)\"\\s+Version=\"([^\"]+)\"\\s*\\/>/g;\n let m: RegExpExecArray | null;\n while ((m = re.exec(content))) {\n refs[m[1]] = m[2];\n }\n return refs;\n}\n\nfunction setTag(content: string, tag: string, value: string): string {\n const escapedTag = escapeRegExp(tag);\n return content.replace(new RegExp(`(<${escapedTag}>)[^<]*(</${escapedTag}>)`), `$1${value}$2`);\n}\n\nfunction setPackageReferenceVersion(content: string, name: string, version: string): string {\n const re = new RegExp(`(<PackageReference\\\\s+Include=\"${escapeRegExp(name)}\"\\\\s+Version=\")[^\"]+(\")`);\n return content.replace(re, `$1${version}$2`);\n}\n\nfunction addPackageReference(content: string, name: string, version: string): string {\n // Reuses the indentation of the last existing <PackageReference> line\n // immediately preceding </ItemGroup>, so the new line matches siblings exactly.\n const re = /^([ \\t]*)<PackageReference[^\\n]*\\/>\\n(?=[ \\t]*<\\/ItemGroup>)/m;\n return content.replace(re, (match, indent: string) => `${match}${indent}<PackageReference Include=\"${name}\" Version=\"${version}\" />\\n`);\n}\n\nfunction parseManifestFile(rawContent: string): DotnetManifestFile {\n return {\n raw: rawContent,\n version: extractTag(rawContent, 'Version'),\n targetFramework: extractTag(rawContent, 'TargetFramework'),\n packageId: extractTag(rawContent, 'PackageId'),\n toolCommandName: extractTag(rawContent, 'ToolCommandName'),\n packageReferences: extractPackageReferences(rawContent),\n };\n}\n\nfunction extractCoreFields(manifestFile: DotnetManifestFile): CoreFieldsExtraction {\n return {\n coreDependencies: manifestFile.packageReferences,\n coreScripts: {},\n coreFields: { TargetFramework: manifestFile.targetFramework },\n };\n}\n\nfunction mergeManifestFile(\n current: DotnetManifestFile,\n oldManifest: Manifest,\n newTemplate: DotnetManifestFile,\n): ManifestFileMergeResult {\n let raw = current.raw;\n let changed = false;\n\n const dependencies: FieldOutcome[] = [];\n const coreDependencies: Record<string, string> = {};\n\n for (const name of Object.keys(newTemplate.packageReferences)) {\n const newValue = newTemplate.packageReferences[name];\n const currentValue = current.packageReferences[name];\n const oldValue = oldManifest.coreDependencies[name];\n\n const result = reconcileEntry(currentValue, oldValue, newValue, stringEquals);\n dependencies.push({ key: name, outcome: result.outcome });\n coreDependencies[name] = result.value;\n\n if (result.outcome === 'added') {\n changed = true;\n raw = addPackageReference(raw, name, result.value);\n } else if (result.outcome !== 'skipped' && result.value !== currentValue) {\n changed = true;\n raw = setPackageReferenceVersion(raw, name, result.value);\n }\n }\n\n const oldCoreFields = oldManifest.coreFields as { TargetFramework?: string };\n const fields: FieldOutcome[] = [];\n\n const targetFrameworkResult = reconcileEntry(\n current.targetFramework,\n oldCoreFields.TargetFramework,\n newTemplate.targetFramework,\n stringEquals,\n );\n fields.push({ key: 'TargetFramework', outcome: targetFrameworkResult.outcome });\n if (targetFrameworkResult.outcome !== 'skipped' && targetFrameworkResult.value !== current.targetFramework) {\n changed = true;\n raw = setTag(raw, 'TargetFramework', targetFrameworkResult.value);\n }\n\n return {\n updatedFile: { ...current, raw },\n changed,\n dependencies,\n scripts: [],\n fields,\n coreDependencies,\n coreScripts: {},\n coreFields: { TargetFramework: targetFrameworkResult.value },\n };\n}\n\nexport const dotnetAdapter: UpdateAdapter = {\n coreFilePaths: CORE_FILE_PATHS,\n\n templateSourcePath(relativePath) {\n return relativePath === '.gitignore' ? 'gitignore' : relativePath;\n },\n\n manifestFileName: 'src/Cli.csproj',\n\n async readManifestFile(dir) {\n const content = await readFile(path.join(dir, 'src', 'Cli.csproj'), 'utf8');\n return parseManifestFile(content);\n },\n\n async writeManifestFile(dir, content) {\n await writeFile(path.join(dir, 'src', 'Cli.csproj'), (content as DotnetManifestFile).raw);\n },\n\n parseManifestFile,\n\n readProjectName(manifestFile) {\n return (manifestFile as DotnetManifestFile).packageId;\n },\n\n extractCoreFields(manifestFile) {\n return extractCoreFields(manifestFile as DotnetManifestFile);\n },\n\n mergeManifestFile(current, oldManifest, newTemplate) {\n return mergeManifestFile(current as DotnetManifestFile, oldManifest, newTemplate as DotnetManifestFile);\n },\n};\n","// src/languages/registry-checkers/nuget.ts\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport type { NameCheckResult, RegistryChecker } from '../registry-checker';\n\nexport const NUGET_DEFAULT_REGISTRY_URL = 'https://api.nuget.org/v3/index.json';\n\nconst NUGET_FLATCONTAINER_BASE = 'https://api.nuget.org/v3-flatcontainer';\nconst FETCH_TIMEOUT_MS = 5000;\n\nasync function checkNameAvailability(name: string): Promise<NameCheckResult> {\n const url = `${NUGET_FLATCONTAINER_BASE}/${encodeURIComponent(name.toLowerCase())}/index.json`;\n\n try {\n const response = await fetch(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });\n if (response.status === 404) return 'available';\n if (response.status === 200) return 'taken';\n return 'unverified';\n } catch {\n return 'unverified';\n }\n}\n\nasync function applyPrivateIntent(targetDir: string): Promise<void> {\n const csprojPath = path.join(targetDir, 'src', 'Cli.csproj');\n const content = await readFile(csprojPath, 'utf8');\n const updated = content.replace(\n /(<PropertyGroup>\\s*\\n)/,\n '$1 <IsPackable>false</IsPackable>\\n',\n );\n await writeFile(csprojPath, updated);\n}\n\nasync function applyRegistryUrl(targetDir: string, registryUrl: string): Promise<void> {\n const config = [\n '<?xml version=\"1.0\" encoding=\"utf-8\"?>',\n '<configuration>',\n ' <packageSources>',\n ' <clear />',\n ` <add key=\"custom\" value=\"${registryUrl}\" />`,\n ' </packageSources>',\n '</configuration>',\n '',\n ].join('\\n');\n await mkdir(targetDir, { recursive: true });\n await writeFile(path.join(targetDir, 'NuGet.config'), config);\n}\n\nexport const nugetRegistryChecker: RegistryChecker = {\n checkNameAvailability,\n applyPrivateIntent,\n applyRegistryUrl,\n};\n","// src/languages/index.ts\nimport type { LanguagePack } from './pack';\nimport { nodeOclifPack } from './packs/node-oclif';\nimport { dotnetPack } from './packs/dotnet';\n\nexport const LANGUAGE_PACKS: Record<string, LanguagePack> = {\n [nodeOclifPack.id]: nodeOclifPack,\n [dotnetPack.id]: dotnetPack,\n};\n\nexport function getPackById(id: string): LanguagePack | undefined {\n return LANGUAGE_PACKS[id];\n}\n","// src/scaffold.ts\nimport { cp, readdir, readFile, rename, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport spawn from 'cross-spawn';\nimport type { LanguagePack } from './languages/pack';\nimport { buildManifest, getGeneratorVersion, writeManifest } from './update/manifest';\nimport { UserError } from './errors';\n\nexport interface ScaffoldOptions {\n projectName: string;\n targetDir: string;\n registryUrl?: string;\n publishIntent?: boolean;\n}\n\nasync function assertTargetDirIsUsable(targetDir: string): Promise<void> {\n let entries: string[];\n try {\n entries = await readdir(targetDir);\n } catch {\n return;\n }\n if (entries.length > 0) {\n throw new UserError(`Directory \"${targetDir}\" already exists and is not empty.`);\n }\n}\n\nexport function applyPlaceholders(content: string, projectName: string): string {\n return content.replaceAll('{{projectName}}', projectName);\n}\n\nasync function collectFiles(dir: string): Promise<string[]> {\n const entries = await readdir(dir, { withFileTypes: true });\n const files = await Promise.all(\n entries.map((entry) => {\n const fullPath = path.join(dir, entry.name);\n return entry.isDirectory() ? collectFiles(fullPath) : Promise.resolve([fullPath]);\n }),\n );\n return files.flat();\n}\n\n// Scans every copied file rather than a hardcoded list, so a new template file\n// that needs {{projectName}} substituted can't silently be forgotten here.\nasync function replacePlaceholdersInTree(targetDir: string, projectName: string): Promise<void> {\n const files = await collectFiles(targetDir);\n await Promise.all(\n files.map(async (filePath) => {\n const content = await readFile(filePath, 'utf8');\n if (content.includes('{{projectName}}')) {\n await writeFile(filePath, applyPlaceholders(content, projectName));\n }\n }),\n );\n}\n\nexport async function copyTemplate(options: ScaffoldOptions, pack: LanguagePack): Promise<void> {\n const { projectName, targetDir, registryUrl, publishIntent } = options;\n\n await assertTargetDirIsUsable(targetDir);\n await cp(pack.templateDir, targetDir, { recursive: true });\n\n await rename(path.join(targetDir, 'gitignore'), path.join(targetDir, '.gitignore'));\n\n await replacePlaceholdersInTree(targetDir, projectName);\n\n if (publishIntent === false) {\n await pack.registry.applyPrivateIntent(targetDir);\n }\n\n if (registryUrl && registryUrl !== pack.registry.defaultUrl) {\n await pack.registry.applyRegistryUrl(targetDir, registryUrl);\n }\n}\n\nexport interface ScaffoldDeps {\n runCommand: (command: string, args: string[], cwd: string) => Promise<void>;\n}\n\nasync function defaultRunCommand(command: string, args: string[], cwd: string): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const child = spawn(command, args, { cwd, stdio: 'inherit' });\n child.on('error', reject);\n child.on('close', (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error(`Command \"${command} ${args.join(' ')}\" exited with code ${code}`));\n }\n });\n });\n}\n\nconst defaultScaffoldDeps: ScaffoldDeps = { runCommand: defaultRunCommand };\n\nexport async function scaffoldProject(\n options: ScaffoldOptions,\n pack: LanguagePack,\n deps: ScaffoldDeps = defaultScaffoldDeps,\n): Promise<void> {\n await copyTemplate(options, pack);\n\n const { targetDir } = options;\n const manifest = await buildManifest(targetDir, getGeneratorVersion(), pack.id, pack.updateAdapter);\n await writeManifest(targetDir, manifest);\n\n await deps.runCommand('git', ['init'], targetDir);\n await deps.runCommand('git', ['add', '-A'], targetDir);\n await deps.runCommand('git', ['commit', '-m', 'chore: initial scaffold from clispark'], targetDir);\n\n for (const scaffoldCommand of pack.scaffoldCommands) {\n await deps.runCommand(scaffoldCommand.command, scaffoldCommand.args, targetDir);\n }\n}\n","// src/update/manifest.ts\nimport { createHash } from 'node:crypto';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { UserError } from '../errors';\nimport type { UpdateAdapter } from './adapter';\n\nexport interface Manifest {\n generatorVersion: string;\n language: string;\n coreFiles: Record<string, string>;\n coreDependencies: Record<string, string>;\n coreScripts: Record<string, string>;\n coreFields: Record<string, unknown>;\n}\n\nexport function hashContent(content: string): string {\n return createHash('sha256').update(content).digest('hex');\n}\n\nexport async function hashCoreFiles(dir: string, adapter: UpdateAdapter): Promise<Record<string, string>> {\n const entries = await Promise.all(\n adapter.coreFilePaths.map(async (relativePath) => {\n const content = await readFile(path.join(dir, relativePath), 'utf8');\n return [relativePath, hashContent(content)] as const;\n }),\n );\n return Object.fromEntries(entries);\n}\n\nexport async function buildManifest(\n targetDir: string,\n generatorVersion: string,\n language: string,\n adapter: UpdateAdapter,\n): Promise<Manifest> {\n const coreFiles = await hashCoreFiles(targetDir, adapter);\n const manifestFile = await adapter.readManifestFile(targetDir);\n const { coreDependencies, coreScripts, coreFields } = adapter.extractCoreFields(manifestFile);\n return { generatorVersion, language, coreFiles, coreDependencies, coreScripts, coreFields };\n}\n\nexport const MANIFEST_RELATIVE_PATH = path.join('.clispark', 'manifest.json');\n\nexport async function writeManifest(targetDir: string, manifest: Manifest): Promise<void> {\n const manifestPath = path.join(targetDir, MANIFEST_RELATIVE_PATH);\n await mkdir(path.dirname(manifestPath), { recursive: true });\n await writeFile(manifestPath, JSON.stringify(manifest, null, 2) + '\\n');\n}\n\nexport async function readManifest(targetDir: string): Promise<Manifest | undefined> {\n try {\n const content = await readFile(path.join(targetDir, MANIFEST_RELATIVE_PATH), 'utf8');\n return JSON.parse(content) as Manifest;\n } catch {\n return undefined;\n }\n}\n\nexport async function requireManifest(targetDir: string): Promise<Manifest> {\n const manifest = await readManifest(targetDir);\n if (!manifest) {\n throw new UserError(\n 'No .clispark/manifest.json found — this project predates update support, or is not a clispark project.',\n );\n }\n return manifest;\n}\n\n/**\n * Finds clispark's own package.json by walking up from this file's location.\n * A fixed relative path (`../package.json`) can't work here: this module's\n * depth below the package root differs between running from source (tests)\n * and running as part of the bundled `dist/cli.js` (tsup flattens everything\n * into one file, so `import.meta.url` no longer reflects the original\n * per-module nesting).\n */\nexport function getGeneratorVersion(): string {\n let dir = path.dirname(fileURLToPath(import.meta.url));\n while (true) {\n const pkgPath = path.join(dir, 'package.json');\n if (existsSync(pkgPath)) {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as { name?: string; version: string };\n if (pkg.name === 'clispark') return pkg.version;\n }\n const parentDir = path.dirname(dir);\n if (parentDir === dir) {\n throw new Error(\"Could not locate clispark's own package.json.\");\n }\n dir = parentDir;\n }\n}\n","// src/errors.ts\n\n/** An expected, user-fixable failure (bad input, unmet precondition) — distinct from an unexpected crash. */\nexport class UserError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'UserError';\n }\n}\n","import { randomBytes } from 'node:crypto';\nimport { mkdirSync, readdirSync, statSync, unlinkSync, writeFileSync } from 'node:fs';\nimport path from 'node:path';\nimport envPaths from 'env-paths';\nimport pino, { type Logger } from 'pino';\n\nconst paths = envPaths('clispark', { suffix: '' });\n\n/** Runs fn, silently swallowing any error — for best-effort work that must never abort the caller. */\nexport function safely(fn: () => void): void {\n try {\n fn();\n } catch {\n // best-effort; a failure here must never affect the surrounding operation\n }\n}\n\nexport interface LoggerHandle {\n logger: Logger;\n logFilePath: string;\n}\n\nfunction buildLogFileName(commandName: string): string {\n const timestamp = new Date().toISOString().replaceAll(/[:.]/g, '-');\n const suffix = randomBytes(3).toString('hex');\n return `${commandName}-${timestamp}-${suffix}.log`;\n}\n\nfunction getRetentionDays(): number {\n const parsed = Number(process.env.LOG_RETENTION_DAYS);\n return Number.isFinite(parsed) ? parsed : 14;\n}\n\n// Common secret-shaped field names, redacted at the top level and one level of\n// nesting (`*.<key>`). Edit this list directly if your own logging needs more.\nexport const SENSITIVE_LOG_KEYS = [\n 'password',\n 'secret',\n 'token',\n 'apiKey',\n 'accessToken',\n 'refreshToken',\n 'clientSecret',\n 'authorization',\n];\n\nfunction buildRedactPaths(keys: string[]): string[] {\n return keys.flatMap((key) => [key, `*.${key}`]);\n}\n\nconst SWEEP_MARKER_FILE = '.last-sweep';\nconst SWEEP_THROTTLE_MS = 24 * 60 * 60 * 1000; // once a day is enough given day-granularity retention\n\nfunction sweepOldLogs(logDir: string): void {\n safely(() => {\n const markerPath = path.join(logDir, SWEEP_MARKER_FILE);\n let shouldSweep = true;\n try {\n shouldSweep = Date.now() - statSync(markerPath).mtimeMs >= SWEEP_THROTTLE_MS;\n } catch {\n // no marker yet (first run in this directory) - sweep now\n }\n if (!shouldSweep) return;\n\n const cutoffMs = Date.now() - getRetentionDays() * 24 * 60 * 60 * 1000;\n for (const file of readdirSync(logDir)) {\n if (file === SWEEP_MARKER_FILE) continue;\n const filePath = path.join(logDir, file);\n if (statSync(filePath).mtimeMs < cutoffMs) {\n unlinkSync(filePath);\n }\n }\n writeFileSync(markerPath, '');\n });\n}\n\nexport function createLogger(commandName: string, logDir: string = paths.log): LoggerHandle {\n mkdirSync(logDir, { recursive: true });\n sweepOldLogs(logDir);\n\n const logFilePath = path.join(logDir, buildLogFileName(commandName));\n const fileDestination = pino.destination({ dest: logFilePath, sync: true, mode: 0o600 });\n const destination = process.env.DEBUG\n ? pino.multistream([{ stream: fileDestination }, { stream: process.stdout }])\n : fileDestination;\n const logger = pino({ redact: buildRedactPaths([...SENSITIVE_LOG_KEYS, 'registryUrl']) }, destination);\n\n return { logger, logFilePath };\n}\n\nexport function withLogging(\n commandName: string,\n action: (logger: Logger) => Promise<void>,\n logDir: string = paths.log,\n loggerFactory: typeof createLogger = createLogger,\n): () => Promise<void> {\n return async () => {\n let handle: LoggerHandle;\n try {\n handle = loggerFactory(commandName, logDir);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n console.error(`\\n✖ ${message}`);\n process.exit(1);\n return;\n }\n\n const { logger, logFilePath } = handle;\n safely(() => logger.info({ command: commandName }, 'started'));\n\n try {\n await action(logger);\n safely(() => logger.info({ command: commandName }, 'completed'));\n if (process.env.DEBUG) {\n console.log(`Details: ${logFilePath}`);\n }\n } catch (error) {\n safely(() => logger.error({ command: commandName, err: error }, 'failed'));\n const message = error instanceof Error ? error.message : String(error);\n console.error(`\\n✖ ${message}`);\n console.error(`Details: ${logFilePath}`);\n process.exit(1);\n }\n };\n}\n","// src/update/update.ts\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport spawn from 'cross-spawn';\nimport { applyPlaceholders } from '../scaffold';\nimport { getGeneratorVersion, hashContent, requireManifest, writeManifest, type Manifest } from './manifest';\nimport { reconcileEntry, stringEquals, type FieldOutcome } from './reconcile';\nimport { UserError } from '../errors';\nimport { compareVersions } from './releasenotes';\nimport type { UpdateAdapter } from './adapter';\n\nexport interface UpdateDeps {\n runCommand: (command: string, args: string[], cwd: string) => Promise<void>;\n captureCommand: (command: string, args: string[], cwd: string) => Promise<string>;\n}\n\nasync function defaultRunCommand(command: string, args: string[], cwd: string): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const child = spawn(command, args, { cwd, stdio: 'inherit' });\n child.on('error', reject);\n child.on('close', (code) => {\n if (code === 0) resolve();\n else reject(new Error(`Command \"${command} ${args.join(' ')}\" exited with code ${code}`));\n });\n });\n}\n\nasync function defaultCaptureCommand(command: string, args: string[], cwd: string): Promise<string> {\n return new Promise<string>((resolve, reject) => {\n const child = spawn(command, args, { cwd });\n let stdout = '';\n child.stdout?.on('data', (chunk: Buffer) => {\n stdout += chunk.toString();\n });\n child.on('error', reject);\n child.on('close', (code) => {\n if (code === 0) resolve(stdout);\n else reject(new Error(`Command \"${command} ${args.join(' ')}\" exited with code ${code}`));\n });\n });\n}\n\nconst defaultUpdateDeps: UpdateDeps = { runCommand: defaultRunCommand, captureCommand: defaultCaptureCommand };\n\nexport interface FileOutcomeEntry {\n path: string;\n outcome: 'added' | 'replaced' | 'skipped' | 'no-longer-core';\n}\n\nexport interface UpdateResult {\n status: 'up-to-date' | 'no-changes' | 'updated';\n fromVersion: string;\n toVersion: string;\n files: FileOutcomeEntry[];\n dependencies: FieldOutcome[];\n scripts: FieldOutcome[];\n fields: FieldOutcome[];\n}\n\nexport async function updateProject(\n targetDir: string,\n adapter: UpdateAdapter,\n templateDir: string,\n language: string,\n deps: UpdateDeps = defaultUpdateDeps,\n): Promise<UpdateResult> {\n const status = (await deps.captureCommand('git', ['status', '--porcelain'], targetDir)).trim();\n if (status.length > 0) {\n throw new UserError('Working tree is not clean. Commit or stash your changes before running update.');\n }\n\n const oldManifest = await requireManifest(targetDir);\n const toVersion = getGeneratorVersion();\n const fromVersion = oldManifest.generatorVersion;\n\n if (compareVersions(fromVersion, toVersion) >= 0) {\n return { status: 'up-to-date', fromVersion, toVersion, files: [], dependencies: [], scripts: [], fields: [] };\n }\n\n const currentManifestFile = await adapter.readManifestFile(targetDir);\n const projectName = adapter.readProjectName(currentManifestFile);\n\n const newTemplateRaw = applyPlaceholders(\n await readFile(path.join(templateDir, adapter.manifestFileName), 'utf8'),\n projectName,\n );\n const newTemplateManifestFile = adapter.parseManifestFile(newTemplateRaw);\n\n const files: FileOutcomeEntry[] = [];\n const newCoreFiles: Record<string, string> = {};\n const fileWrites: { targetPath: string; content: string }[] = [];\n\n // Reads + hashes run in parallel; results are then applied in adapter.coreFilePaths\n // order below so files/fileWrites stay deterministic regardless of I/O timing.\n const perFileResults = await Promise.all(\n adapter.coreFilePaths.map(async (relativePath) => {\n const newContent = applyPlaceholders(\n await readFile(path.join(templateDir, adapter.templateSourcePath(relativePath)), 'utf8'),\n projectName,\n );\n const newHash = hashContent(newContent);\n\n let currentHash: string | undefined;\n try {\n currentHash = hashContent(await readFile(path.join(targetDir, relativePath), 'utf8'));\n } catch {\n currentHash = undefined;\n }\n\n const result = reconcileEntry(currentHash, oldManifest.coreFiles[relativePath], newHash, stringEquals);\n return { relativePath, newContent, result };\n }),\n );\n\n for (const { relativePath, newContent, result } of perFileResults) {\n files.push({ path: relativePath, outcome: result.outcome });\n newCoreFiles[relativePath] = result.value;\n\n if (result.outcome === 'added' || result.outcome === 'replaced') {\n fileWrites.push({ targetPath: path.join(targetDir, relativePath), content: newContent });\n }\n }\n\n for (const relativePath of Object.keys(oldManifest.coreFiles)) {\n if (adapter.coreFilePaths.includes(relativePath)) continue;\n try {\n await readFile(path.join(targetDir, relativePath), 'utf8');\n files.push({ path: relativePath, outcome: 'no-longer-core' });\n } catch {\n // already gone locally, nothing to report\n }\n }\n\n const fileMerge = adapter.mergeManifestFile(currentManifestFile, oldManifest, newTemplateManifestFile);\n\n const hasFileChanges = files.some(\n (f) => f.outcome === 'added' || f.outcome === 'replaced' || f.outcome === 'no-longer-core',\n );\n const hasChanges = hasFileChanges || fileMerge.changed;\n\n if (!hasChanges) {\n return {\n status: 'no-changes',\n fromVersion,\n toVersion,\n files,\n dependencies: fileMerge.dependencies,\n scripts: fileMerge.scripts,\n fields: fileMerge.fields,\n };\n }\n\n for (const write of fileWrites) {\n await mkdir(path.dirname(write.targetPath), { recursive: true });\n await writeFile(write.targetPath, write.content);\n }\n\n if (fileMerge.changed) {\n await adapter.writeManifestFile(targetDir, fileMerge.updatedFile);\n }\n\n const newManifest: Manifest = {\n generatorVersion: toVersion,\n language,\n coreFiles: newCoreFiles,\n coreDependencies: fileMerge.coreDependencies,\n coreScripts: fileMerge.coreScripts,\n coreFields: fileMerge.coreFields,\n };\n await writeManifest(targetDir, newManifest);\n\n await deps.runCommand('git', ['add', '-A'], targetDir);\n await deps.runCommand('git', ['commit', '-m', `chore: update clispark core to v${toVersion}`], targetDir);\n\n return {\n status: 'updated',\n fromVersion,\n toVersion,\n files,\n dependencies: fileMerge.dependencies,\n scripts: fileMerge.scripts,\n fields: fileMerge.fields,\n };\n}\n\nexport function formatUpdateSummary(result: UpdateResult): string {\n if (result.status === 'up-to-date') {\n return `Already up to date (v${result.toVersion}).`;\n }\n\n const added = result.files.filter((f) => f.outcome === 'added');\n const replaced = result.files.filter((f) => f.outcome === 'replaced');\n const skipped = result.files.filter((f) => f.outcome === 'skipped');\n const noLongerCore = result.files.filter((f) => f.outcome === 'no-longer-core');\n\n const lines: string[] = [];\n if (result.status === 'no-changes') {\n lines.push(\n noLongerCore.length\n ? `No changes applied: nothing to update since v${result.fromVersion}.`\n : `No changes applied: every core file/field has been modified locally since v${result.fromVersion}.`,\n );\n } else {\n lines.push(`Updated core from v${result.fromVersion} to v${result.toVersion}.`);\n }\n\n if (added.length) lines.push(` New: ${added.map((f) => f.path).join(', ')}`);\n if (replaced.length) lines.push(` Updated: ${replaced.map((f) => f.path).join(', ')}`);\n if (skipped.length) lines.push(` Skipped (locally modified): ${skipped.map((f) => f.path).join(', ')}`);\n if (noLongerCore.length) {\n lines.push(\n ` No longer part of the core, safe to remove manually: ${noLongerCore.map((f) => f.path).join(', ')}`,\n );\n }\n\n const fieldOutcomes = [...result.dependencies, ...result.scripts, ...result.fields].filter(\n (o) => o.outcome !== 'skipped',\n );\n if (fieldOutcomes.length) {\n lines.push(` Manifest: ${fieldOutcomes.map((o) => `${o.key} (${o.outcome})`).join(', ')}`);\n }\n\n if (result.status === 'updated') {\n lines.push('Run \"clispark releasenotes\" to see what changed.');\n }\n\n return lines.join('\\n');\n}\n","// src/update/releasenotes.ts\nimport { getGeneratorVersion, requireManifest } from './manifest';\n\nexport interface GitHubRelease {\n tag_name: string;\n name: string;\n body: string;\n}\n\nfunction stripV(version: string): string {\n return version.startsWith('v') ? version.slice(1) : version;\n}\n\nexport function compareVersions(a: string, b: string): number {\n const partsA = stripV(a).split('.').map(Number);\n const partsB = stripV(b).split('.').map(Number);\n const length = Math.max(partsA.length, partsB.length);\n for (let i = 0; i < length; i++) {\n const diff = (partsA[i] ?? 0) - (partsB[i] ?? 0);\n if (diff !== 0) return diff;\n }\n return 0;\n}\n\nexport interface ReleaseNotesResult {\n status: 'up-to-date' | 'releases-found';\n fromVersion: string;\n toVersion: string;\n releases: GitHubRelease[];\n}\n\nconst RELEASES_URL = 'https://api.github.com/repos/martinwichner/clispark/releases';\nconst FETCH_TIMEOUT_MS = 5000;\n\nexport async function fetchReleaseNotes(\n targetDir: string,\n fetchFn: typeof fetch = fetch,\n): Promise<ReleaseNotesResult> {\n const manifest = await requireManifest(targetDir);\n const fromVersion = manifest.generatorVersion;\n const toVersion = getGeneratorVersion();\n\n if (compareVersions(fromVersion, toVersion) >= 0) {\n return { status: 'up-to-date', fromVersion, toVersion, releases: [] };\n }\n\n const response = await fetchFn(RELEASES_URL, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });\n if (!response.ok) {\n throw new Error(`Failed to fetch release notes: GitHub API responded with ${response.status}`);\n }\n const allReleases = (await response.json()) as GitHubRelease[];\n\n const releases = allReleases\n .filter((r) => compareVersions(r.tag_name, fromVersion) > 0 && compareVersions(r.tag_name, toVersion) <= 0)\n .sort((a, b) => compareVersions(b.tag_name, a.tag_name));\n\n return { status: 'releases-found', fromVersion, toVersion, releases };\n}\n\nexport function formatReleaseNotes(result: ReleaseNotesResult): string {\n if (result.status === 'up-to-date') {\n return `You're on the latest clispark version (v${result.toVersion}), nothing to show.`;\n }\n if (result.releases.length === 0) {\n return `No published releases found between v${result.fromVersion} and v${result.toVersion}.`;\n }\n return result.releases.map((r) => `## ${r.tag_name}\\n\\n${r.body}`).join('\\n\\n');\n}\n","// src/whoami.ts\nimport os from 'node:os';\n\nconst JOKE_API_URL = 'https://v2.jokeapi.dev/joke/Programming,Miscellaneous';\nconst FETCH_TIMEOUT_MS = 3000;\n\n/** Languages JokeAPI (https://jokeapi.dev/) currently supports, per its /languages endpoint. */\nconst SUPPORTED_JOKE_LANGUAGES = ['cs', 'de', 'en', 'es', 'fr', 'pt'];\n\nexport const LOGO = String.raw`\n ⚡ clispark\n`;\n\nexport const FALLBACK_QUOTES = [\n \"Green unit tests don't mean it works. Real end-to-end verification does.\",\n 'A default value can silently reintroduce coupling you just removed.',\n \"The bug you can't find locally is waiting for you in CI.\",\n \"YAGNI until you actually need it — then it's just an adapter away.\",\n 'Every folder move has a bundling-depth bug waiting to happen.',\n 'The cheapest fix is the one you verify before you ship it.',\n 'TDD: write the failing test first, or explain later why it passed by accident.',\n \"If it's not tested against a real filesystem, it's a theory, not a fact.\",\n];\n\ninterface JokeApiSingle {\n error: false;\n type: 'single';\n joke: string;\n}\n\ninterface JokeApiTwoPart {\n error: false;\n type: 'twopart';\n setup: string;\n delivery: string;\n}\n\ninterface JokeApiError {\n error: true;\n}\n\ntype JokeApiResponse = JokeApiSingle | JokeApiTwoPart | JokeApiError;\n\n/** Maps a BCP-47 locale (e.g. \"de-DE\") to a JokeAPI language code, defaulting to \"en\" when unsupported. */\nexport function detectJokeLanguage(\n locale: string = Intl.DateTimeFormat().resolvedOptions().locale,\n): string {\n const primary = locale.split('-')[0].toLowerCase();\n return SUPPORTED_JOKE_LANGUAGES.includes(primary) ? primary : 'en';\n}\n\nfunction pickFallbackQuote(): string {\n return FALLBACK_QUOTES[Math.floor(Math.random() * FALLBACK_QUOTES.length)];\n}\n\nexport interface OsFacts {\n uptime: () => number;\n hostname: () => string;\n cpus: () => os.CpuInfo[];\n totalmem: () => number;\n platform: () => NodeJS.Platform;\n release: () => string;\n arch: () => string;\n}\n\nconst defaultOsFacts: OsFacts = {\n uptime: () => os.uptime(),\n hostname: () => os.hostname(),\n cpus: () => os.cpus(),\n totalmem: () => os.totalmem(),\n platform: () => os.platform(),\n release: () => os.release(),\n arch: () => os.arch(),\n};\n\nfunction formatUptime(seconds: number): string {\n const days = Math.floor(seconds / 86400);\n const hours = Math.floor((seconds % 86400) / 3600);\n const minutes = Math.floor((seconds % 3600) / 60);\n const parts: string[] = [];\n if (days > 0) parts.push(`${days}d`);\n if (days > 0 || hours > 0) parts.push(`${hours}h`);\n parts.push(`${minutes}m`);\n return parts.join(' ');\n}\n\nconst FACT_GENERATORS: Array<(facts: OsFacts) => string> = [\n (facts) => `This machine has been up for ${formatUptime(facts.uptime())}.`,\n (facts) => `Hostname: ${facts.hostname()}`,\n (facts) => {\n const cpus = facts.cpus();\n return `CPU: ${cpus[0]?.model.trim() ?? 'unknown'} (${cpus.length} logical cores)`;\n },\n (facts) => `RAM: ${(facts.totalmem() / 1024 ** 3).toFixed(1)} GB total`,\n (facts) => `OS: ${facts.platform()} ${facts.release()} (${facts.arch()})`,\n];\n\nexport function getRandomFunFact(osFacts: OsFacts = defaultOsFacts, randomFn: () => number = Math.random): string {\n const index = Math.floor(randomFn() * FACT_GENERATORS.length);\n return FACT_GENERATORS[index](osFacts);\n}\n\nasync function fetchJoke(language: string, fetchFn: typeof fetch): Promise<string | undefined> {\n try {\n const url = `${JOKE_API_URL}?lang=${language}&safe-mode`;\n const response = await fetchFn(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });\n if (!response.ok) return undefined;\n\n const data = (await response.json()) as JokeApiResponse;\n if (data.error) return undefined;\n return data.type === 'single' ? data.joke : `${data.setup}\\n${data.delivery}`;\n } catch {\n return undefined;\n }\n}\n\nexport type WhoamiMode = 'joke' | 'fact' | 'random';\n\nexport async function getWhoamiOutput(\n fetchFn: typeof fetch = fetch,\n osFacts: OsFacts = defaultOsFacts,\n randomFn: () => number = Math.random,\n mode: WhoamiMode = 'random',\n): Promise<string> {\n const showFact = mode === 'fact' || (mode === 'random' && randomFn() < 0.5);\n if (showFact) {\n return `${LOGO}\\n${getRandomFunFact(osFacts, randomFn)}\\n`;\n }\n\n const language = detectJokeLanguage();\n const quote = (await fetchJoke(language, fetchFn)) ?? pickFallbackQuote();\n return `${LOGO}\\n${quote}\\n`;\n}\n","// src/confetti.ts\n\nconst CONFETTI_VARIANTS = [\n '✨ 🎉 ✨ 🎊 ✨ 🎉 ✨\\n 🎈 🎊 🎈\\n✨ 🎉 ✨ 🎉',\n '🎊 ✨ 🎈 ✨ 🎊\\n 🎉 🎉 🎉\\n✨ 🎈 ✨ 🎈 ✨',\n '🎉✨🎊✨🎉✨🎊✨🎉\\n 🎈 🎈\\n✨🎊✨🎉✨🎊✨🎉✨',\n];\n\nexport function getConfetti(randomFn: () => number = Math.random): string {\n const index = Math.floor(randomFn() * CONFETTI_VARIANTS.length);\n return CONFETTI_VARIANTS[index];\n}\n\nexport function printConfetti(randomFn: () => number = Math.random): void {\n console.log(`\\n${getConfetti(randomFn)}\\n`);\n}\n"],"mappings":"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","names":["path","path","path","path","readFile","writeFile","path","path","path","readFile","writeFile","path","CORE_FILE_PATHS","extractCoreFields","readFile","path","writeFile","readFile","writeFile","path","FETCH_TIMEOUT_MS","checkNameAvailability","applyPrivateIntent","applyRegistryUrl","validateProjectName","path","pack","readFile","writeFile","path","existsSync","readFileSync","mkdir","readFile","writeFile","path","fileURLToPath","readFile","path","mkdir","writeFile","fileURLToPath","existsSync","readFileSync","path","readFile","writeFile","path","mkdir","readFile","writeFile","path","spawn","FETCH_TIMEOUT_MS","defaultRunCommand","spawn","readFile","path","mkdir","writeFile","FETCH_TIMEOUT_MS","path"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/wizard.ts","../src/languages/packs/node-oclif.ts","../src/package-root.ts","../src/update/adapters/node-oclif.ts","../src/update/reconcile.ts","../src/languages/registry-checkers/npm.ts","../src/languages/command-generators/node-oclif.ts","../src/languages/command-generator.ts","../src/languages/packs/dotnet.ts","../src/update/adapters/dotnet.ts","../src/languages/registry-checkers/nuget.ts","../src/languages/command-generators/dotnet.ts","../src/languages/index.ts","../src/scaffold.ts","../src/update/manifest.ts","../src/errors.ts","../src/logger.ts","../src/update/update.ts","../src/update/releasenotes.ts","../src/add-wizard.ts","../src/whoami.ts","../src/confetti.ts"],"sourcesContent":["// src/cli.ts\nimport path from 'node:path';\nimport { Command } from 'commander';\nimport { runWizard } from './wizard';\nimport { scaffoldProject } from './scaffold';\nimport { withLogging } from './logger';\nimport { formatUpdateSummary, updateProject } from './update/update';\nimport { fetchReleaseNotes, formatReleaseNotes } from './update/releasenotes';\nimport { getGeneratorVersion, requireManifest } from './update/manifest';\nimport { LANGUAGE_PACKS } from './languages';\nimport type { LanguagePack } from './languages/pack';\nimport { UserError } from './errors';\nimport { runAddWizard } from './add-wizard';\nimport { getWhoamiOutput, type WhoamiMode } from './whoami';\nimport { printConfetti } from './confetti';\n\nconst program = new Command();\n\nprogram\n .name('clispark')\n .description('Interactive scaffolding tool for new CLI projects')\n .option('--no-confetti', 'Skip the confetti after a successful run')\n .configureHelp({ showGlobalOptions: true })\n .version(getGeneratorVersion());\n\nfunction resolvePack(language: string): LanguagePack {\n const pack = LANGUAGE_PACKS[language];\n if (!pack) {\n throw new UserError(`Unknown language \"${language}\" — is your clispark installation out of date?`);\n }\n return pack;\n}\n\nprogram.action((options: { confetti?: boolean }) =>\n withLogging('scaffold', async (logger) => {\n const answers = await runWizard();\n const targetDir = path.join(process.cwd(), answers.projectName);\n const pack = resolvePack(answers.language);\n\n logger.info({ projectName: answers.projectName, targetDir, language: pack.id }, 'scaffold started');\n await scaffoldProject(\n {\n projectName: answers.projectName,\n targetDir,\n registryUrl: answers.registryUrl,\n publishIntent: answers.publishIntent,\n },\n pack,\n );\n logger.info({ projectName: answers.projectName }, 'scaffold completed');\n\n console.log(`\\nDone! Your new CLI project is ready at ${targetDir}`);\n if (options.confetti !== false) printConfetti();\n })(),\n);\n\nprogram\n .command('update')\n .description('Update generator-managed core files and dependencies to the latest clispark version')\n .action((_options: unknown, command: Command) =>\n withLogging('update', async (logger) => {\n const targetDir = process.cwd();\n const manifest = await requireManifest(targetDir);\n const language = manifest.language ?? 'node';\n const pack = resolvePack(language);\n logger.info({ targetDir, language }, 'update started');\n const result = await updateProject(targetDir, pack.updateAdapter, pack.templateDir, language);\n logger.info({ status: result.status }, 'update completed');\n console.log(formatUpdateSummary(result));\n const { confetti } = command.optsWithGlobals<{ confetti?: boolean }>();\n if (confetti !== false && result.status === 'updated') printConfetti();\n })(),\n );\n\nprogram\n .command('releasenotes')\n .description(\"Show what changed between this project's generator version and the latest clispark version\")\n .action(\n withLogging('releasenotes', async (logger) => {\n const targetDir = process.cwd();\n logger.info({ targetDir }, 'releasenotes started');\n const result = await fetchReleaseNotes(targetDir);\n logger.info({ status: result.status }, 'releasenotes completed');\n console.log(formatReleaseNotes(result));\n }),\n );\n\nprogram\n .command('add')\n .description('Add a new command to an already-scaffolded project')\n .action(\n withLogging('add', async (logger) => {\n const targetDir = process.cwd();\n const manifest = await requireManifest(targetDir);\n const language = manifest.language ?? 'node';\n const pack = resolvePack(language);\n logger.info({ targetDir, language }, 'add started');\n await runAddWizard(targetDir, { commandGenerator: pack.commandGenerator });\n logger.info({}, 'add completed');\n }),\n );\n\nfunction resolveWhoamiMode(options: { joke?: boolean; fact?: boolean }): WhoamiMode {\n if (options.joke && options.fact) {\n throw new UserError('Use either --joke or --fact, not both.');\n }\n if (options.joke) return 'joke';\n if (options.fact) return 'fact';\n return 'random';\n}\n\nprogram\n .command('whoami')\n .description('A little something extra')\n .option('--joke', 'Always show a joke')\n .option('--fact', 'Always show a fun fact about this machine')\n .action((options: { joke?: boolean; fact?: boolean }) =>\n withLogging('whoami', async (logger) => {\n const mode = resolveWhoamiMode(options);\n logger.info({ mode }, 'whoami started');\n console.log(await getWhoamiOutput(fetch, undefined, undefined, mode));\n logger.info({}, 'whoami completed');\n })(),\n );\n\nprogram.parseAsync(process.argv).catch((error: unknown) => {\n console.error(error);\n process.exit(1);\n});\n","// src/wizard.ts\nimport { intro, outro, text, select, log, isCancel, cancel } from '@clack/prompts';\nimport { LANGUAGE_PACKS } from './languages';\nimport type { LanguagePack } from './languages/pack';\nimport type { NameCheckResult } from './languages/registry-checker';\nimport type { Profile, WizardAnswers } from './types';\n\nexport interface WizardDeps {\n languagePacks: Record<string, LanguagePack>;\n}\n\nconst defaultDeps: WizardDeps = {\n languagePacks: LANGUAGE_PACKS,\n};\n\nfunction exitIfCancelled(value: unknown): void {\n if (isCancel(value)) {\n cancel('Operation cancelled.');\n process.exit(1);\n }\n}\n\nexport async function runWizard(deps: WizardDeps = defaultDeps): Promise<WizardAnswers> {\n intro('clispark — scaffold a new CLI project');\n\n const packs = Object.values(deps.languagePacks);\n const languageValue = await select({\n message: 'Which language?',\n options: packs.map((pack) => ({ value: pack.id, label: pack.displayName })),\n });\n exitIfCancelled(languageValue);\n const pack = deps.languagePacks[languageValue as string];\n\n const nameValue = await text({\n message: 'Project name',\n validate: pack.validateProjectName,\n });\n exitIfCancelled(nameValue);\n let projectName = nameValue as string;\n\n const profileValue = await select({\n message: 'Is this a work or private project?',\n options: [\n { value: 'private', label: 'Private' },\n { value: 'work', label: 'Work' },\n ],\n });\n exitIfCancelled(profileValue);\n const profile = profileValue as Profile;\n\n let registryUrl = pack.registry.defaultUrl;\n if (profile === 'work') {\n const registryValue = await text({\n message: pack.registry.promptLabel,\n placeholder: pack.registry.defaultUrl,\n defaultValue: pack.registry.defaultUrl,\n });\n exitIfCancelled(registryValue);\n registryUrl = (registryValue as string) || pack.registry.defaultUrl;\n }\n\n const publishIntentValue = await select({\n message: 'Do you plan to publish this?',\n options: [\n { value: false, label: 'No' },\n { value: true, label: 'Yes' },\n ],\n initialValue: false,\n });\n exitIfCancelled(publishIntentValue);\n const publishIntent = publishIntentValue as boolean;\n\n let nameAvailability: NameCheckResult = 'skipped';\n\n if (publishIntent) {\n nameAvailability = await pack.registry.checkNameAvailability(projectName, registryUrl);\n\n while (nameAvailability === 'taken') {\n log.warn(`\"${projectName}\" is already taken on ${registryUrl}. Please choose a different name.`);\n\n const retryValue = await text({\n message: 'Project name',\n validate: pack.validateProjectName,\n });\n exitIfCancelled(retryValue);\n projectName = retryValue as string;\n\n nameAvailability = await pack.registry.checkNameAvailability(projectName, registryUrl);\n }\n\n if (nameAvailability === 'unverified') {\n log.warn(`Could not verify availability of \"${projectName}\" on ${registryUrl}. Continuing anyway.`);\n }\n }\n\n outro(`Ready to scaffold \"${projectName}\".`);\n\n return { language: pack.id, projectName, profile, registryUrl, publishIntent, nameAvailability };\n}\n","// src/languages/packs/node-oclif.ts\nimport path from 'node:path';\nimport { findPackageRoot } from '../../package-root';\nimport type { LanguagePack } from '../pack';\nimport { nodeOclifAdapter } from '../../update/adapters/node-oclif';\nimport { npmRegistryChecker, NPM_DEFAULT_REGISTRY_URL } from '../registry-checkers/npm';\nimport { nodeOclifCommandGenerator } from '../command-generators/node-oclif';\n\nfunction validateProjectName(value: string): string | undefined {\n if (!value || value.trim().length === 0) return 'Project name is required.';\n if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(value)) {\n return 'Use lowercase letters and numbers, with single hyphens between words (no leading, trailing, or repeated hyphens).';\n }\n return undefined;\n}\n\nexport const nodeOclifPack: LanguagePack = {\n id: 'node',\n displayName: 'Node.js / TypeScript (oclif)',\n templateDir: path.join(findPackageRoot(), 'templates', 'node'),\n scaffoldCommands: [\n { command: 'npm', args: ['install'] },\n { command: 'npm', args: ['run', 'build'] },\n ],\n validateProjectName,\n updateAdapter: nodeOclifAdapter,\n registry: {\n defaultUrl: NPM_DEFAULT_REGISTRY_URL,\n promptLabel: 'Custom npm registry URL (leave empty for npmjs.org)',\n checkNameAvailability: npmRegistryChecker.checkNameAvailability,\n applyPrivateIntent: npmRegistryChecker.applyPrivateIntent,\n applyRegistryUrl: npmRegistryChecker.applyRegistryUrl,\n },\n commandGenerator: nodeOclifCommandGenerator,\n};\n","import { existsSync, readFileSync } from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/**\n * Finds clispark's own package root by walking up from this module's\n * location. A fixed relative path can't work here: this module's depth\n * below the package root differs between running from source (tests) and\n * running as part of the bundled `dist/cli.js` (tsup flattens everything\n * into one file, so `import.meta.url` no longer reflects the original\n * per-module nesting) — but the walk-up strategy is depth-independent\n * either way, since it doesn't matter where exactly the walk starts.\n */\nexport function findPackageRoot(): string {\n let dir = path.dirname(fileURLToPath(import.meta.url));\n while (true) {\n const pkgPath = path.join(dir, 'package.json');\n if (existsSync(pkgPath)) {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as { name?: string };\n if (pkg.name === 'clispark') return dir;\n }\n const parentDir = path.dirname(dir);\n if (parentDir === dir) {\n throw new Error(\"Could not locate clispark's own package.json.\");\n }\n dir = parentDir;\n }\n}\n","// src/update/adapters/node-oclif.ts\nimport { readFile, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport type { Manifest } from '../manifest';\nimport type { CoreFieldsExtraction, ManifestFileMergeResult, UpdateAdapter } from '../adapter';\nimport { deepEquals, reconcileEntry, stringEquals, type FieldOutcome } from '../reconcile';\n\nexport const CORE_FILE_PATHS = [\n 'bin/run.ts',\n 'src/index.ts',\n 'src/base-command.ts',\n 'src/logger.ts',\n 'tsup.config.ts',\n 'vitest.config.ts',\n 'tsconfig.json',\n 'ARCHITECTURE.md',\n '.gitignore',\n] as const;\n\nexport const CORE_SCRIPT_NAMES = ['build', 'postbuild', 'pretest', 'test', 'typecheck'] as const;\n\nexport interface PackageJsonShape {\n name: string;\n version: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n scripts?: Record<string, string>;\n engines?: Record<string, string>;\n oclif?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\nfunction currentDependencyValue(\n pkg: PackageJsonShape,\n name: string,\n): { section: 'dependencies' | 'devDependencies'; value: string } | undefined {\n if (pkg.dependencies?.[name] !== undefined) return { section: 'dependencies', value: pkg.dependencies[name] };\n if (pkg.devDependencies?.[name] !== undefined) {\n return { section: 'devDependencies', value: pkg.devDependencies[name] };\n }\n return undefined;\n}\n\nfunction extractCoreFields(pkg: PackageJsonShape): CoreFieldsExtraction {\n const coreDependencies = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) };\n\n const coreScripts: Record<string, string> = {};\n for (const name of CORE_SCRIPT_NAMES) {\n const value = pkg.scripts?.[name];\n if (value !== undefined) coreScripts[name] = value;\n }\n\n return {\n coreDependencies,\n coreScripts,\n coreFields: {\n engines: pkg.engines ?? {},\n oclif: pkg.oclif ?? {},\n },\n };\n}\n\nfunction mergePackageJson(\n currentPkg: PackageJsonShape,\n oldManifest: Manifest,\n newTemplatePkg: PackageJsonShape,\n): ManifestFileMergeResult {\n const updatedFile: PackageJsonShape = { ...currentPkg };\n let changed = false;\n\n const dependencies: FieldOutcome[] = [];\n const coreDependencies: Record<string, string> = {};\n const dependencyNames = new Set([\n ...Object.keys(newTemplatePkg.dependencies ?? {}),\n ...Object.keys(newTemplatePkg.devDependencies ?? {}),\n ]);\n\n for (const name of dependencyNames) {\n const inNewDependencies = newTemplatePkg.dependencies?.[name] !== undefined;\n const newValue = (inNewDependencies ? newTemplatePkg.dependencies : newTemplatePkg.devDependencies)![name];\n const current = currentDependencyValue(currentPkg, name);\n const oldValue = oldManifest.coreDependencies[name];\n\n const result = reconcileEntry(current?.value, oldValue, newValue, stringEquals);\n dependencies.push({ key: name, outcome: result.outcome });\n coreDependencies[name] = result.value;\n\n if (result.outcome !== 'skipped' && result.value !== current?.value) {\n changed = true;\n const section = current?.section ?? (inNewDependencies ? 'dependencies' : 'devDependencies');\n updatedFile[section] = { ...updatedFile[section], [name]: result.value };\n }\n }\n\n const scripts: FieldOutcome[] = [];\n const coreScripts: Record<string, string> = {};\n\n for (const name of CORE_SCRIPT_NAMES) {\n const newValue = newTemplatePkg.scripts?.[name];\n if (newValue === undefined) continue;\n const currentValue = currentPkg.scripts?.[name];\n const oldValue = oldManifest.coreScripts[name];\n\n const result = reconcileEntry(currentValue, oldValue, newValue, stringEquals);\n scripts.push({ key: name, outcome: result.outcome });\n coreScripts[name] = result.value;\n\n if (result.outcome !== 'skipped' && result.value !== currentValue) {\n changed = true;\n updatedFile.scripts = { ...updatedFile.scripts, [name]: result.value };\n }\n }\n\n const oldCoreFields = oldManifest.coreFields as {\n engines?: Record<string, string>;\n oclif?: Record<string, unknown>;\n };\n const fields: FieldOutcome[] = [];\n let enginesValue: Record<string, string> = oldCoreFields.engines ?? {};\n let oclifValue: Record<string, unknown> = oldCoreFields.oclif ?? {};\n\n if (newTemplatePkg.engines !== undefined) {\n const enginesResult = reconcileEntry(\n currentPkg.engines,\n oldCoreFields.engines,\n newTemplatePkg.engines,\n deepEquals,\n );\n fields.push({ key: 'engines', outcome: enginesResult.outcome });\n enginesValue = enginesResult.value;\n if (enginesResult.outcome !== 'skipped' && !deepEquals(enginesResult.value, currentPkg.engines)) {\n changed = true;\n updatedFile.engines = enginesResult.value;\n }\n }\n\n if (newTemplatePkg.oclif !== undefined) {\n const oclifResult = reconcileEntry(currentPkg.oclif, oldCoreFields.oclif, newTemplatePkg.oclif, deepEquals);\n fields.push({ key: 'oclif', outcome: oclifResult.outcome });\n oclifValue = oclifResult.value;\n if (oclifResult.outcome !== 'skipped' && !deepEquals(oclifResult.value, currentPkg.oclif)) {\n changed = true;\n updatedFile.oclif = oclifResult.value;\n }\n }\n\n return {\n updatedFile,\n changed,\n dependencies,\n scripts,\n fields,\n coreDependencies,\n coreScripts,\n coreFields: { engines: enginesValue, oclif: oclifValue },\n };\n}\n\nexport const nodeOclifAdapter: UpdateAdapter = {\n coreFilePaths: CORE_FILE_PATHS,\n\n templateSourcePath(relativePath) {\n return relativePath === '.gitignore' ? 'gitignore' : relativePath;\n },\n\n manifestFileName: 'package.json',\n\n async readManifestFile(dir) {\n const content = await readFile(path.join(dir, 'package.json'), 'utf8');\n return JSON.parse(content) as PackageJsonShape;\n },\n\n async writeManifestFile(dir, content) {\n await writeFile(path.join(dir, 'package.json'), JSON.stringify(content, null, 2) + '\\n');\n },\n\n parseManifestFile(rawContent) {\n return JSON.parse(rawContent) as PackageJsonShape;\n },\n\n readProjectName(manifestFile) {\n return (manifestFile as PackageJsonShape).name;\n },\n\n extractCoreFields(manifestFile) {\n return extractCoreFields(manifestFile as PackageJsonShape);\n },\n\n mergeManifestFile(current, oldManifest, newTemplate) {\n return mergePackageJson(current as PackageJsonShape, oldManifest, newTemplate as PackageJsonShape);\n },\n};\n","export type ReconcileOutcome = 'added' | 'replaced' | 'skipped';\n\n/** A named field/dependency/script whose reconciliation outcome should be reported to the user (e.g. \"pino: replaced\"). */\nexport interface FieldOutcome {\n key: string;\n outcome: ReconcileOutcome;\n}\n\nexport interface ReconcileResult<T> {\n outcome: ReconcileOutcome;\n value: T;\n}\n\nexport function reconcileEntry<T>(\n currentLiveValue: T | undefined,\n oldManifestValue: T | undefined,\n newTemplateValue: T,\n isEqual: (a: T, b: T) => boolean,\n): ReconcileResult<T> {\n if (currentLiveValue === undefined) {\n return { outcome: 'added', value: newTemplateValue };\n }\n if (oldManifestValue !== undefined && isEqual(currentLiveValue, oldManifestValue)) {\n return { outcome: 'replaced', value: newTemplateValue };\n }\n return { outcome: 'skipped', value: oldManifestValue ?? currentLiveValue };\n}\n\nexport function stringEquals(a: string, b: string): boolean {\n return a === b;\n}\n\nexport function deepEquals(a: unknown, b: unknown): boolean {\n return JSON.stringify(a) === JSON.stringify(b);\n}\n","// src/languages/registry-checkers/npm.ts\nimport { readFile, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport type { NameCheckResult, RegistryChecker } from '../registry-checker';\n\nexport const NPM_DEFAULT_REGISTRY_URL = 'https://registry.npmjs.org';\n\nconst FETCH_TIMEOUT_MS = 5000;\n\nasync function checkNameAvailability(name: string, registryUrl: string): Promise<NameCheckResult> {\n const url = `${registryUrl.replace(/\\/$/, '')}/${encodeURIComponent(name)}`;\n\n try {\n const response = await fetch(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });\n if (response.status === 404) return 'available';\n if (response.status === 200) return 'taken';\n return 'unverified';\n } catch {\n return 'unverified';\n }\n}\n\nasync function applyPrivateIntent(targetDir: string): Promise<void> {\n const packageJsonPath = path.join(targetDir, 'package.json');\n const pkg = JSON.parse(await readFile(packageJsonPath, 'utf8')) as Record<string, unknown>;\n pkg.private = true;\n await writeFile(packageJsonPath, JSON.stringify(pkg, null, 2) + '\\n');\n}\n\nasync function applyRegistryUrl(targetDir: string, registryUrl: string): Promise<void> {\n await writeFile(path.join(targetDir, '.npmrc'), `registry=${registryUrl}\\n`);\n}\n\nexport const npmRegistryChecker: RegistryChecker = {\n checkNameAvailability,\n applyPrivateIntent,\n applyRegistryUrl,\n};\n","// src/languages/command-generators/node-oclif.ts\nimport { mkdir, readdir, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport type {\n CommandGenerator,\n CommandSpec,\n ExistingCommandNode,\n GeneratedFiles,\n ParameterSpec,\n} from '../command-generator';\nimport { buildCommandTree } from '../command-generator';\n\nasync function collectCommandFiles(dir: string, baseDir: string = dir): Promise<string[]> {\n const entries = await readdir(dir, { withFileTypes: true });\n const files: string[] = [];\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n files.push(...(await collectCommandFiles(fullPath, baseDir)));\n } else if (entry.name.endsWith('.ts') && !entry.name.endsWith('.test.ts')) {\n files.push(path.relative(baseDir, fullPath));\n }\n }\n return files;\n}\n\nfunction toCommandPath(relativeFilePath: string): string {\n return relativeFilePath.replace(/\\.ts$/, '').split(path.sep).join(' ');\n}\n\nasync function listExistingCommands(targetDir: string): Promise<ExistingCommandNode[]> {\n const commandsDir = path.join(targetDir, 'src', 'commands');\n const files = await collectCommandFiles(commandsDir);\n return buildCommandTree(files.map(toCommandPath));\n}\n\nfunction toClassName(pathSegments: string[]): string {\n return pathSegments.map((seg) => seg[0].toUpperCase() + seg.slice(1)).join('');\n}\n\nfunction argFor(param: ParameterSpec): string {\n const opts = [`required: ${param.required}`, `description: '${param.name}'`];\n if (param.type === 'enum') {\n opts.push(`options: [${(param.allowedValues ?? []).map((v) => `'${v}'`).join(', ')}]`);\n }\n const argsMethod = param.type === 'enum' ? 'string' : param.type;\n return `Args.${argsMethod}({ ${opts.join(', ')} })`;\n}\n\nfunction generateCommandFileContent(spec: CommandSpec): string {\n const className = toClassName(spec.pathSegments);\n const argsLines = spec.parameters.map((p) => ` ${p.name}: ${argFor(p)},`).join('\\n');\n const logExpr = spec.parameters.map((p) => `${p.name}=\\${args.${p.name}}`).join(' ');\n const depth = spec.pathSegments.length;\n const baseCommandImportPath = '../'.repeat(depth) + 'base-command';\n\n return `import { Args } from '@oclif/core';\nimport { BaseCommand } from '${baseCommandImportPath}';\n\nexport default class ${className} extends BaseCommand {\n static description = '${spec.pathSegments[spec.pathSegments.length - 1]} command';\n static args = {\n${argsLines}\n };\n static flags = {};\n\n async run(): Promise<void> {\n const { args } = await this.parse(${className});\n this.log(\\`${logExpr}\\`);\n }\n}\n`;\n}\n\nfunction sampleArgValue(param: ParameterSpec): string {\n if (param.type === 'enum') return param.allowedValues?.[0] ?? '';\n if (param.type === 'integer') return '1';\n if (param.type === 'boolean') return 'true';\n return 'value';\n}\n\nfunction generateTestFileContent(spec: CommandSpec): string {\n const commandInvocation = spec.pathSegments.join(' ');\n const sampleArgs = spec.parameters.map(sampleArgValue).join(' ');\n const fullInvocation = sampleArgs ? `${commandInvocation} ${sampleArgs}` : commandInvocation;\n\n return `import { describe, it, expect } from 'vitest';\nimport { runCommand } from '@oclif/test';\n\ndescribe('${commandInvocation}', () => {\n it('runs successfully', async () => {\n const { error } = await runCommand('${fullInvocation}');\n expect(error).toBeUndefined();\n });\n});\n`;\n}\n\nasync function generateCommand(targetDir: string, spec: CommandSpec): Promise<GeneratedFiles> {\n const relDir = path.join('src', 'commands', ...spec.pathSegments.slice(0, -1));\n const fileName = spec.pathSegments[spec.pathSegments.length - 1];\n const commandRelPath = path.join(relDir, `${fileName}.ts`);\n const testRelPath = path.join(relDir, `${fileName}.test.ts`);\n\n await mkdir(path.join(targetDir, relDir), { recursive: true });\n await writeFile(path.join(targetDir, commandRelPath), generateCommandFileContent(spec));\n await writeFile(path.join(targetDir, testRelPath), generateTestFileContent(spec));\n\n return { commandFile: commandRelPath, testFile: testRelPath };\n}\n\nexport const nodeOclifCommandGenerator: CommandGenerator = {\n listExistingCommands,\n generateCommand,\n};\n","// src/languages/command-generator.ts\n\nexport interface ExistingCommandNode {\n path: string;\n displayLabel: string;\n children: ExistingCommandNode[];\n}\n\nexport type ParameterType = 'string' | 'integer' | 'boolean' | 'enum';\n\nexport interface ParameterSpec {\n name: string;\n type: ParameterType;\n required: boolean;\n allowedValues?: string[];\n}\n\nexport interface CommandSpec {\n pathSegments: string[];\n parameters: ParameterSpec[];\n}\n\nexport interface GeneratedFiles {\n commandFile: string;\n testFile: string;\n}\n\nexport interface CommandGenerator {\n listExistingCommands(targetDir: string): Promise<ExistingCommandNode[]>;\n generateCommand(targetDir: string, spec: CommandSpec): Promise<GeneratedFiles>;\n}\n\n/** Builds a tree of ExistingCommandNode from a flat list of space-separated command paths. */\nexport function buildCommandTree(paths: string[]): ExistingCommandNode[] {\n const nodesByPath = new Map<string, ExistingCommandNode>();\n const roots: ExistingCommandNode[] = [];\n\n function getOrCreateNode(nodePath: string): ExistingCommandNode {\n let node = nodesByPath.get(nodePath);\n if (!node) {\n const segments = nodePath.split(' ');\n node = { path: nodePath, displayLabel: segments.join(' > '), children: [] };\n nodesByPath.set(nodePath, node);\n if (segments.length === 1) {\n roots.push(node);\n } else {\n const parent = getOrCreateNode(segments.slice(0, -1).join(' '));\n parent.children.push(node);\n }\n }\n return node;\n }\n\n for (const p of paths) {\n getOrCreateNode(p);\n }\n\n return roots;\n}\n","// src/languages/packs/dotnet.ts\nimport path from 'node:path';\nimport { findPackageRoot } from '../../package-root';\nimport type { LanguagePack } from '../pack';\nimport { dotnetAdapter } from '../../update/adapters/dotnet';\nimport { nugetRegistryChecker, NUGET_DEFAULT_REGISTRY_URL } from '../registry-checkers/nuget';\nimport { dotnetCommandGenerator } from '../command-generators/dotnet';\n\nfunction validateProjectName(value: string): string | undefined {\n if (!value || value.trim().length === 0) return 'Project name is required.';\n if (!/^[A-Z][A-Za-z0-9]*$/.test(value)) {\n return 'Use PascalCase, starting with an uppercase letter (e.g. MyTool).';\n }\n return undefined;\n}\n\nexport const dotnetPack: LanguagePack = {\n id: 'dotnet',\n displayName: '.NET / C# (System.CommandLine)',\n templateDir: path.join(findPackageRoot(), 'templates', 'dotnet'),\n scaffoldCommands: [\n { command: 'dotnet', args: ['restore'] },\n { command: 'dotnet', args: ['build'] },\n ],\n validateProjectName,\n updateAdapter: dotnetAdapter,\n registry: {\n defaultUrl: NUGET_DEFAULT_REGISTRY_URL,\n promptLabel: 'Custom NuGet feed URL (leave empty for nuget.org)',\n checkNameAvailability: nugetRegistryChecker.checkNameAvailability,\n applyPrivateIntent: nugetRegistryChecker.applyPrivateIntent,\n applyRegistryUrl: nugetRegistryChecker.applyRegistryUrl,\n },\n commandGenerator: dotnetCommandGenerator,\n};\n","// src/update/adapters/dotnet.ts\nimport { readFile, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport type { Manifest } from '../manifest';\nimport type { CoreFieldsExtraction, ManifestFileMergeResult, UpdateAdapter } from '../adapter';\nimport { reconcileEntry, stringEquals, type FieldOutcome } from '../reconcile';\n\nexport const CORE_FILE_PATHS = [\n 'Cli.slnx',\n 'src/Program.cs',\n 'src/ICliCommand.cs',\n 'src/CommandPathAttribute.cs',\n 'src/CommandDiscovery.cs',\n 'src/CliUserException.cs',\n 'src/Logging/CliLoggerFactory.cs',\n 'src/Logging/SensitivePropertyEnricher.cs',\n 'tests/Cli.Tests.csproj',\n 'ARCHITECTURE.md',\n '.gitignore',\n] as const;\n\nexport interface DotnetManifestFile {\n raw: string;\n version: string;\n targetFramework: string;\n packageId: string;\n toolCommandName: string;\n packageReferences: Record<string, string>;\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nfunction extractTag(content: string, tag: string): string {\n const match = content.match(new RegExp(`<${tag}>([^<]*)</${tag}>`));\n if (!match) throw new Error(`.csproj is missing a <${tag}> tag`);\n return match[1];\n}\n\nfunction extractPackageReferences(content: string): Record<string, string> {\n const refs: Record<string, string> = {};\n const re = /<PackageReference\\s+Include=\"([^\"]+)\"\\s+Version=\"([^\"]+)\"\\s*\\/>/g;\n let m: RegExpExecArray | null;\n while ((m = re.exec(content))) {\n refs[m[1]] = m[2];\n }\n return refs;\n}\n\nfunction setTag(content: string, tag: string, value: string): string {\n const escapedTag = escapeRegExp(tag);\n return content.replace(new RegExp(`(<${escapedTag}>)[^<]*(</${escapedTag}>)`), `$1${value}$2`);\n}\n\nfunction setPackageReferenceVersion(content: string, name: string, version: string): string {\n const re = new RegExp(`(<PackageReference\\\\s+Include=\"${escapeRegExp(name)}\"\\\\s+Version=\")[^\"]+(\")`);\n return content.replace(re, `$1${version}$2`);\n}\n\nfunction addPackageReference(content: string, name: string, version: string): string {\n // Reuses the indentation of the last existing <PackageReference> line\n // immediately preceding </ItemGroup>, so the new line matches siblings exactly.\n const re = /^([ \\t]*)<PackageReference[^\\n]*\\/>\\n(?=[ \\t]*<\\/ItemGroup>)/m;\n return content.replace(re, (match, indent: string) => `${match}${indent}<PackageReference Include=\"${name}\" Version=\"${version}\" />\\n`);\n}\n\nfunction parseManifestFile(rawContent: string): DotnetManifestFile {\n return {\n raw: rawContent,\n version: extractTag(rawContent, 'Version'),\n targetFramework: extractTag(rawContent, 'TargetFramework'),\n packageId: extractTag(rawContent, 'PackageId'),\n toolCommandName: extractTag(rawContent, 'ToolCommandName'),\n packageReferences: extractPackageReferences(rawContent),\n };\n}\n\nfunction extractCoreFields(manifestFile: DotnetManifestFile): CoreFieldsExtraction {\n return {\n coreDependencies: manifestFile.packageReferences,\n coreScripts: {},\n coreFields: { TargetFramework: manifestFile.targetFramework },\n };\n}\n\nfunction mergeManifestFile(\n current: DotnetManifestFile,\n oldManifest: Manifest,\n newTemplate: DotnetManifestFile,\n): ManifestFileMergeResult {\n let raw = current.raw;\n let changed = false;\n\n const dependencies: FieldOutcome[] = [];\n const coreDependencies: Record<string, string> = {};\n\n for (const name of Object.keys(newTemplate.packageReferences)) {\n const newValue = newTemplate.packageReferences[name];\n const currentValue = current.packageReferences[name];\n const oldValue = oldManifest.coreDependencies[name];\n\n const result = reconcileEntry(currentValue, oldValue, newValue, stringEquals);\n dependencies.push({ key: name, outcome: result.outcome });\n coreDependencies[name] = result.value;\n\n if (result.outcome === 'added') {\n changed = true;\n raw = addPackageReference(raw, name, result.value);\n } else if (result.outcome !== 'skipped' && result.value !== currentValue) {\n changed = true;\n raw = setPackageReferenceVersion(raw, name, result.value);\n }\n }\n\n const oldCoreFields = oldManifest.coreFields as { TargetFramework?: string };\n const fields: FieldOutcome[] = [];\n\n const targetFrameworkResult = reconcileEntry(\n current.targetFramework,\n oldCoreFields.TargetFramework,\n newTemplate.targetFramework,\n stringEquals,\n );\n fields.push({ key: 'TargetFramework', outcome: targetFrameworkResult.outcome });\n if (targetFrameworkResult.outcome !== 'skipped' && targetFrameworkResult.value !== current.targetFramework) {\n changed = true;\n raw = setTag(raw, 'TargetFramework', targetFrameworkResult.value);\n }\n\n return {\n updatedFile: { ...current, raw },\n changed,\n dependencies,\n scripts: [],\n fields,\n coreDependencies,\n coreScripts: {},\n coreFields: { TargetFramework: targetFrameworkResult.value },\n };\n}\n\nexport const dotnetAdapter: UpdateAdapter = {\n coreFilePaths: CORE_FILE_PATHS,\n\n templateSourcePath(relativePath) {\n return relativePath === '.gitignore' ? 'gitignore' : relativePath;\n },\n\n manifestFileName: 'src/Cli.csproj',\n\n async readManifestFile(dir) {\n const content = await readFile(path.join(dir, 'src', 'Cli.csproj'), 'utf8');\n return parseManifestFile(content);\n },\n\n async writeManifestFile(dir, content) {\n await writeFile(path.join(dir, 'src', 'Cli.csproj'), (content as DotnetManifestFile).raw);\n },\n\n parseManifestFile,\n\n readProjectName(manifestFile) {\n return (manifestFile as DotnetManifestFile).packageId;\n },\n\n extractCoreFields(manifestFile) {\n return extractCoreFields(manifestFile as DotnetManifestFile);\n },\n\n mergeManifestFile(current, oldManifest, newTemplate) {\n return mergeManifestFile(current as DotnetManifestFile, oldManifest, newTemplate as DotnetManifestFile);\n },\n};\n","// src/languages/registry-checkers/nuget.ts\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport type { NameCheckResult, RegistryChecker } from '../registry-checker';\n\nexport const NUGET_DEFAULT_REGISTRY_URL = 'https://api.nuget.org/v3/index.json';\n\nconst NUGET_FLATCONTAINER_BASE = 'https://api.nuget.org/v3-flatcontainer';\nconst FETCH_TIMEOUT_MS = 5000;\n\nasync function checkNameAvailability(name: string): Promise<NameCheckResult> {\n const url = `${NUGET_FLATCONTAINER_BASE}/${encodeURIComponent(name.toLowerCase())}/index.json`;\n\n try {\n const response = await fetch(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });\n if (response.status === 404) return 'available';\n if (response.status === 200) return 'taken';\n return 'unverified';\n } catch {\n return 'unverified';\n }\n}\n\nasync function applyPrivateIntent(targetDir: string): Promise<void> {\n const csprojPath = path.join(targetDir, 'src', 'Cli.csproj');\n const content = await readFile(csprojPath, 'utf8');\n const updated = content.replace(\n /(<PropertyGroup>\\s*\\n)/,\n '$1 <IsPackable>false</IsPackable>\\n',\n );\n await writeFile(csprojPath, updated);\n}\n\nasync function applyRegistryUrl(targetDir: string, registryUrl: string): Promise<void> {\n const config = [\n '<?xml version=\"1.0\" encoding=\"utf-8\"?>',\n '<configuration>',\n ' <packageSources>',\n ' <clear />',\n ` <add key=\"custom\" value=\"${registryUrl}\" />`,\n ' </packageSources>',\n '</configuration>',\n '',\n ].join('\\n');\n await mkdir(targetDir, { recursive: true });\n await writeFile(path.join(targetDir, 'NuGet.config'), config);\n}\n\nexport const nugetRegistryChecker: RegistryChecker = {\n checkNameAvailability,\n applyPrivateIntent,\n applyRegistryUrl,\n};\n","// src/languages/command-generators/dotnet.ts\nimport { mkdir, readFile, readdir, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport type {\n CommandGenerator,\n CommandSpec,\n ExistingCommandNode,\n GeneratedFiles,\n ParameterSpec,\n} from '../command-generator';\nimport { buildCommandTree } from '../command-generator';\n\nasync function listExistingCommands(targetDir: string): Promise<ExistingCommandNode[]> {\n const commandsDir = path.join(targetDir, 'src', 'Commands');\n const files = await readdir(commandsDir);\n const paths: string[] = [];\n for (const file of files) {\n if (!file.endsWith('.cs')) continue;\n const content = await readFile(path.join(commandsDir, file), 'utf8');\n const match = content.match(/\\[CommandPath\\(\"([^\"]+)\"\\)\\]/);\n if (match) paths.push(match[1]);\n }\n return buildCommandTree(paths);\n}\n\nfunction toClassName(pathSegments: string[]): string {\n return pathSegments.map((seg) => seg[0].toUpperCase() + seg.slice(1)).join('') + 'Command';\n}\n\nfunction csharpDeclType(param: ParameterSpec): string {\n const baseType = param.type === 'integer' ? 'int' : param.type === 'boolean' ? 'bool' : 'string';\n if (param.required) return baseType;\n return `${baseType}?`;\n}\n\nfunction argumentDeclaration(param: ParameterSpec): string {\n const varName = `${param.name}Argument`;\n const declType = csharpDeclType(param);\n const arityLine = param.required ? '' : '\\n Arity = ArgumentArity.ZeroOrOne,';\n const lines = [\n ` var ${varName} = new Argument<${declType}>(\"${param.name}\")`,\n ` {`,\n ` Description = \"${param.name}\",${arityLine}`,\n ` };`,\n ];\n if (param.type === 'enum') {\n lines.push(` ${varName}.AcceptOnlyFromAmong(${(param.allowedValues ?? []).map((v) => `\"${v}\"`).join(', ')});`);\n }\n return lines.join('\\n');\n}\n\nfunction generateCommandFileContent(spec: CommandSpec): string {\n const className = toClassName(spec.pathSegments);\n const commandPath = spec.pathSegments.join(' ');\n const lastSegment = spec.pathSegments[spec.pathSegments.length - 1];\n\n const argDecls = spec.parameters.map(argumentDeclaration).join('\\n\\n');\n const addLines = spec.parameters.map((p) => ` command.Arguments.Add(${p.name}Argument);`).join('\\n');\n const getValueLines = spec.parameters\n .map((p) => ` var ${p.name} = parseResult.GetValue(${p.name}Argument);`)\n .join('\\n');\n const interpolated = spec.parameters.map((p) => `${p.name}={${p.name}}`).join(' ');\n\n return `using System.CommandLine;\n\nnamespace Cli.Commands;\n\n[CommandPath(\"${commandPath}\")]\npublic sealed class ${className} : ICliCommand\n{\n public Command Build()\n {\n${argDecls}\n\n var command = new Command(\"${lastSegment}\", \"${lastSegment} command\");\n${addLines}\n command.SetAction(parseResult =>\n {\n${getValueLines}\n Console.WriteLine($\"${interpolated}\");\n });\n\n return command;\n }\n}\n`;\n}\n\nfunction sampleArgValue(param: ParameterSpec): string {\n if (param.type === 'enum') return param.allowedValues?.[0] ?? '';\n if (param.type === 'integer') return '1';\n if (param.type === 'boolean') return 'true';\n return 'value';\n}\n\nfunction generateTestFileContent(spec: CommandSpec): string {\n const className = toClassName(spec.pathSegments);\n const sampleArgs = spec.parameters.map(sampleArgValue);\n\n return `using System.CommandLine;\nusing Cli.Commands;\n\nnamespace Cli.Tests;\n\npublic class ${className}Tests\n{\n [Fact]\n public void RunsSuccessfully()\n {\n var command = new ${className}().Build();\n var parseResult = command.Parse([${sampleArgs.map((a) => `\"${a}\"`).join(', ')}]);\n\n var exitCode = parseResult.Invoke();\n\n Assert.Equal(0, exitCode);\n }\n}\n`;\n}\n\nasync function generateCommand(targetDir: string, spec: CommandSpec): Promise<GeneratedFiles> {\n const className = toClassName(spec.pathSegments);\n const commandRelPath = path.join('src', 'Commands', `${className}.cs`);\n const testRelPath = path.join('tests', `${className}Tests.cs`);\n\n await mkdir(path.join(targetDir, 'src', 'Commands'), { recursive: true });\n await mkdir(path.join(targetDir, 'tests'), { recursive: true });\n await writeFile(path.join(targetDir, commandRelPath), generateCommandFileContent(spec));\n await writeFile(path.join(targetDir, testRelPath), generateTestFileContent(spec));\n\n return { commandFile: commandRelPath, testFile: testRelPath };\n}\n\nexport const dotnetCommandGenerator: CommandGenerator = {\n listExistingCommands,\n generateCommand,\n};\n","// src/languages/index.ts\nimport type { LanguagePack } from './pack';\nimport { nodeOclifPack } from './packs/node-oclif';\nimport { dotnetPack } from './packs/dotnet';\n\nexport const LANGUAGE_PACKS: Record<string, LanguagePack> = {\n [nodeOclifPack.id]: nodeOclifPack,\n [dotnetPack.id]: dotnetPack,\n};\n\nexport function getPackById(id: string): LanguagePack | undefined {\n return LANGUAGE_PACKS[id];\n}\n","// src/scaffold.ts\nimport { cp, readdir, readFile, rename, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport spawn from 'cross-spawn';\nimport type { LanguagePack } from './languages/pack';\nimport { buildManifest, getGeneratorVersion, writeManifest } from './update/manifest';\nimport { UserError } from './errors';\n\nexport interface ScaffoldOptions {\n projectName: string;\n targetDir: string;\n registryUrl?: string;\n publishIntent?: boolean;\n}\n\nasync function assertTargetDirIsUsable(targetDir: string): Promise<void> {\n let entries: string[];\n try {\n entries = await readdir(targetDir);\n } catch {\n return;\n }\n if (entries.length > 0) {\n throw new UserError(`Directory \"${targetDir}\" already exists and is not empty.`);\n }\n}\n\nexport function applyPlaceholders(content: string, projectName: string): string {\n return content.replaceAll('{{projectName}}', projectName);\n}\n\nasync function collectFiles(dir: string): Promise<string[]> {\n const entries = await readdir(dir, { withFileTypes: true });\n const files = await Promise.all(\n entries.map((entry) => {\n const fullPath = path.join(dir, entry.name);\n return entry.isDirectory() ? collectFiles(fullPath) : Promise.resolve([fullPath]);\n }),\n );\n return files.flat();\n}\n\n// Scans every copied file rather than a hardcoded list, so a new template file\n// that needs {{projectName}} substituted can't silently be forgotten here.\nasync function replacePlaceholdersInTree(targetDir: string, projectName: string): Promise<void> {\n const files = await collectFiles(targetDir);\n await Promise.all(\n files.map(async (filePath) => {\n const content = await readFile(filePath, 'utf8');\n if (content.includes('{{projectName}}')) {\n await writeFile(filePath, applyPlaceholders(content, projectName));\n }\n }),\n );\n}\n\nexport async function copyTemplate(options: ScaffoldOptions, pack: LanguagePack): Promise<void> {\n const { projectName, targetDir, registryUrl, publishIntent } = options;\n\n await assertTargetDirIsUsable(targetDir);\n await cp(pack.templateDir, targetDir, { recursive: true });\n\n await rename(path.join(targetDir, 'gitignore'), path.join(targetDir, '.gitignore'));\n\n await replacePlaceholdersInTree(targetDir, projectName);\n\n if (publishIntent === false) {\n await pack.registry.applyPrivateIntent(targetDir);\n }\n\n if (registryUrl && registryUrl !== pack.registry.defaultUrl) {\n await pack.registry.applyRegistryUrl(targetDir, registryUrl);\n }\n}\n\nexport interface ScaffoldDeps {\n runCommand: (command: string, args: string[], cwd: string) => Promise<void>;\n}\n\nasync function defaultRunCommand(command: string, args: string[], cwd: string): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const child = spawn(command, args, { cwd, stdio: 'inherit' });\n child.on('error', reject);\n child.on('close', (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error(`Command \"${command} ${args.join(' ')}\" exited with code ${code}`));\n }\n });\n });\n}\n\nconst defaultScaffoldDeps: ScaffoldDeps = { runCommand: defaultRunCommand };\n\nexport async function scaffoldProject(\n options: ScaffoldOptions,\n pack: LanguagePack,\n deps: ScaffoldDeps = defaultScaffoldDeps,\n): Promise<void> {\n await copyTemplate(options, pack);\n\n const { targetDir } = options;\n const manifest = await buildManifest(targetDir, getGeneratorVersion(), pack.id, pack.updateAdapter);\n await writeManifest(targetDir, manifest);\n\n await deps.runCommand('git', ['init'], targetDir);\n await deps.runCommand('git', ['add', '-A'], targetDir);\n await deps.runCommand('git', ['commit', '-m', 'chore: initial scaffold from clispark'], targetDir);\n\n for (const scaffoldCommand of pack.scaffoldCommands) {\n await deps.runCommand(scaffoldCommand.command, scaffoldCommand.args, targetDir);\n }\n}\n","// src/update/manifest.ts\nimport { createHash } from 'node:crypto';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { UserError } from '../errors';\nimport type { UpdateAdapter } from './adapter';\n\nexport interface Manifest {\n generatorVersion: string;\n language: string;\n coreFiles: Record<string, string>;\n coreDependencies: Record<string, string>;\n coreScripts: Record<string, string>;\n coreFields: Record<string, unknown>;\n}\n\nexport function hashContent(content: string): string {\n return createHash('sha256').update(content).digest('hex');\n}\n\nexport async function hashCoreFiles(dir: string, adapter: UpdateAdapter): Promise<Record<string, string>> {\n const entries = await Promise.all(\n adapter.coreFilePaths.map(async (relativePath) => {\n const content = await readFile(path.join(dir, relativePath), 'utf8');\n return [relativePath, hashContent(content)] as const;\n }),\n );\n return Object.fromEntries(entries);\n}\n\nexport async function buildManifest(\n targetDir: string,\n generatorVersion: string,\n language: string,\n adapter: UpdateAdapter,\n): Promise<Manifest> {\n const coreFiles = await hashCoreFiles(targetDir, adapter);\n const manifestFile = await adapter.readManifestFile(targetDir);\n const { coreDependencies, coreScripts, coreFields } = adapter.extractCoreFields(manifestFile);\n return { generatorVersion, language, coreFiles, coreDependencies, coreScripts, coreFields };\n}\n\nexport const MANIFEST_RELATIVE_PATH = path.join('.clispark', 'manifest.json');\n\nexport async function writeManifest(targetDir: string, manifest: Manifest): Promise<void> {\n const manifestPath = path.join(targetDir, MANIFEST_RELATIVE_PATH);\n await mkdir(path.dirname(manifestPath), { recursive: true });\n await writeFile(manifestPath, JSON.stringify(manifest, null, 2) + '\\n');\n}\n\nexport async function readManifest(targetDir: string): Promise<Manifest | undefined> {\n try {\n const content = await readFile(path.join(targetDir, MANIFEST_RELATIVE_PATH), 'utf8');\n return JSON.parse(content) as Manifest;\n } catch {\n return undefined;\n }\n}\n\nexport async function requireManifest(targetDir: string): Promise<Manifest> {\n const manifest = await readManifest(targetDir);\n if (!manifest) {\n throw new UserError(\n 'No .clispark/manifest.json found — this project predates update support, or is not a clispark project.',\n );\n }\n return manifest;\n}\n\n/**\n * Finds clispark's own package.json by walking up from this file's location.\n * A fixed relative path (`../package.json`) can't work here: this module's\n * depth below the package root differs between running from source (tests)\n * and running as part of the bundled `dist/cli.js` (tsup flattens everything\n * into one file, so `import.meta.url` no longer reflects the original\n * per-module nesting).\n */\nexport function getGeneratorVersion(): string {\n let dir = path.dirname(fileURLToPath(import.meta.url));\n while (true) {\n const pkgPath = path.join(dir, 'package.json');\n if (existsSync(pkgPath)) {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as { name?: string; version: string };\n if (pkg.name === 'clispark') return pkg.version;\n }\n const parentDir = path.dirname(dir);\n if (parentDir === dir) {\n throw new Error(\"Could not locate clispark's own package.json.\");\n }\n dir = parentDir;\n }\n}\n","// src/errors.ts\n\n/** An expected, user-fixable failure (bad input, unmet precondition) — distinct from an unexpected crash. */\nexport class UserError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'UserError';\n }\n}\n","import { randomBytes } from 'node:crypto';\nimport { mkdirSync, readdirSync, statSync, unlinkSync, writeFileSync } from 'node:fs';\nimport path from 'node:path';\nimport envPaths from 'env-paths';\nimport pino, { type Logger } from 'pino';\n\nconst paths = envPaths('clispark', { suffix: '' });\n\n/** Runs fn, silently swallowing any error — for best-effort work that must never abort the caller. */\nexport function safely(fn: () => void): void {\n try {\n fn();\n } catch {\n // best-effort; a failure here must never affect the surrounding operation\n }\n}\n\nexport interface LoggerHandle {\n logger: Logger;\n logFilePath: string;\n}\n\nfunction buildLogFileName(commandName: string): string {\n const timestamp = new Date().toISOString().replaceAll(/[:.]/g, '-');\n const suffix = randomBytes(3).toString('hex');\n return `${commandName}-${timestamp}-${suffix}.log`;\n}\n\nfunction getRetentionDays(): number {\n const parsed = Number(process.env.LOG_RETENTION_DAYS);\n return Number.isFinite(parsed) ? parsed : 14;\n}\n\n// Common secret-shaped field names, redacted at the top level and one level of\n// nesting (`*.<key>`). Edit this list directly if your own logging needs more.\nexport const SENSITIVE_LOG_KEYS = [\n 'password',\n 'secret',\n 'token',\n 'apiKey',\n 'accessToken',\n 'refreshToken',\n 'clientSecret',\n 'authorization',\n];\n\nfunction buildRedactPaths(keys: string[]): string[] {\n return keys.flatMap((key) => [key, `*.${key}`]);\n}\n\nconst SWEEP_MARKER_FILE = '.last-sweep';\nconst SWEEP_THROTTLE_MS = 24 * 60 * 60 * 1000; // once a day is enough given day-granularity retention\n\nfunction sweepOldLogs(logDir: string): void {\n safely(() => {\n const markerPath = path.join(logDir, SWEEP_MARKER_FILE);\n let shouldSweep = true;\n try {\n shouldSweep = Date.now() - statSync(markerPath).mtimeMs >= SWEEP_THROTTLE_MS;\n } catch {\n // no marker yet (first run in this directory) - sweep now\n }\n if (!shouldSweep) return;\n\n const cutoffMs = Date.now() - getRetentionDays() * 24 * 60 * 60 * 1000;\n for (const file of readdirSync(logDir)) {\n if (file === SWEEP_MARKER_FILE) continue;\n const filePath = path.join(logDir, file);\n if (statSync(filePath).mtimeMs < cutoffMs) {\n unlinkSync(filePath);\n }\n }\n writeFileSync(markerPath, '');\n });\n}\n\nexport function createLogger(commandName: string, logDir: string = paths.log): LoggerHandle {\n mkdirSync(logDir, { recursive: true });\n sweepOldLogs(logDir);\n\n const logFilePath = path.join(logDir, buildLogFileName(commandName));\n const fileDestination = pino.destination({ dest: logFilePath, sync: true, mode: 0o600 });\n const destination = process.env.DEBUG\n ? pino.multistream([{ stream: fileDestination }, { stream: process.stdout }])\n : fileDestination;\n const logger = pino({ redact: buildRedactPaths([...SENSITIVE_LOG_KEYS, 'registryUrl']) }, destination);\n\n return { logger, logFilePath };\n}\n\nexport function withLogging(\n commandName: string,\n action: (logger: Logger) => Promise<void>,\n logDir: string = paths.log,\n loggerFactory: typeof createLogger = createLogger,\n): () => Promise<void> {\n return async () => {\n let handle: LoggerHandle;\n try {\n handle = loggerFactory(commandName, logDir);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n console.error(`\\n✖ ${message}`);\n process.exit(1);\n return;\n }\n\n const { logger, logFilePath } = handle;\n safely(() => logger.info({ command: commandName }, 'started'));\n\n try {\n await action(logger);\n safely(() => logger.info({ command: commandName }, 'completed'));\n if (process.env.DEBUG) {\n console.log(`Details: ${logFilePath}`);\n }\n } catch (error) {\n safely(() => logger.error({ command: commandName, err: error }, 'failed'));\n const message = error instanceof Error ? error.message : String(error);\n console.error(`\\n✖ ${message}`);\n console.error(`Details: ${logFilePath}`);\n process.exit(1);\n }\n };\n}\n","// src/update/update.ts\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport spawn from 'cross-spawn';\nimport { applyPlaceholders } from '../scaffold';\nimport { getGeneratorVersion, hashContent, requireManifest, writeManifest, type Manifest } from './manifest';\nimport { reconcileEntry, stringEquals, type FieldOutcome } from './reconcile';\nimport { UserError } from '../errors';\nimport { compareVersions } from './releasenotes';\nimport type { UpdateAdapter } from './adapter';\n\nexport interface UpdateDeps {\n runCommand: (command: string, args: string[], cwd: string) => Promise<void>;\n captureCommand: (command: string, args: string[], cwd: string) => Promise<string>;\n}\n\nasync function defaultRunCommand(command: string, args: string[], cwd: string): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const child = spawn(command, args, { cwd, stdio: 'inherit' });\n child.on('error', reject);\n child.on('close', (code) => {\n if (code === 0) resolve();\n else reject(new Error(`Command \"${command} ${args.join(' ')}\" exited with code ${code}`));\n });\n });\n}\n\nasync function defaultCaptureCommand(command: string, args: string[], cwd: string): Promise<string> {\n return new Promise<string>((resolve, reject) => {\n const child = spawn(command, args, { cwd });\n let stdout = '';\n child.stdout?.on('data', (chunk: Buffer) => {\n stdout += chunk.toString();\n });\n child.on('error', reject);\n child.on('close', (code) => {\n if (code === 0) resolve(stdout);\n else reject(new Error(`Command \"${command} ${args.join(' ')}\" exited with code ${code}`));\n });\n });\n}\n\nconst defaultUpdateDeps: UpdateDeps = { runCommand: defaultRunCommand, captureCommand: defaultCaptureCommand };\n\nexport interface FileOutcomeEntry {\n path: string;\n outcome: 'added' | 'replaced' | 'skipped' | 'no-longer-core';\n}\n\nexport interface UpdateResult {\n status: 'up-to-date' | 'no-changes' | 'updated';\n fromVersion: string;\n toVersion: string;\n files: FileOutcomeEntry[];\n dependencies: FieldOutcome[];\n scripts: FieldOutcome[];\n fields: FieldOutcome[];\n}\n\nexport async function updateProject(\n targetDir: string,\n adapter: UpdateAdapter,\n templateDir: string,\n language: string,\n deps: UpdateDeps = defaultUpdateDeps,\n): Promise<UpdateResult> {\n const status = (await deps.captureCommand('git', ['status', '--porcelain'], targetDir)).trim();\n if (status.length > 0) {\n throw new UserError('Working tree is not clean. Commit or stash your changes before running update.');\n }\n\n const oldManifest = await requireManifest(targetDir);\n const toVersion = getGeneratorVersion();\n const fromVersion = oldManifest.generatorVersion;\n\n if (compareVersions(fromVersion, toVersion) >= 0) {\n return { status: 'up-to-date', fromVersion, toVersion, files: [], dependencies: [], scripts: [], fields: [] };\n }\n\n const currentManifestFile = await adapter.readManifestFile(targetDir);\n const projectName = adapter.readProjectName(currentManifestFile);\n\n const newTemplateRaw = applyPlaceholders(\n await readFile(path.join(templateDir, adapter.manifestFileName), 'utf8'),\n projectName,\n );\n const newTemplateManifestFile = adapter.parseManifestFile(newTemplateRaw);\n\n const files: FileOutcomeEntry[] = [];\n const newCoreFiles: Record<string, string> = {};\n const fileWrites: { targetPath: string; content: string }[] = [];\n\n // Reads + hashes run in parallel; results are then applied in adapter.coreFilePaths\n // order below so files/fileWrites stay deterministic regardless of I/O timing.\n const perFileResults = await Promise.all(\n adapter.coreFilePaths.map(async (relativePath) => {\n const newContent = applyPlaceholders(\n await readFile(path.join(templateDir, adapter.templateSourcePath(relativePath)), 'utf8'),\n projectName,\n );\n const newHash = hashContent(newContent);\n\n let currentHash: string | undefined;\n try {\n currentHash = hashContent(await readFile(path.join(targetDir, relativePath), 'utf8'));\n } catch {\n currentHash = undefined;\n }\n\n const result = reconcileEntry(currentHash, oldManifest.coreFiles[relativePath], newHash, stringEquals);\n return { relativePath, newContent, result };\n }),\n );\n\n for (const { relativePath, newContent, result } of perFileResults) {\n files.push({ path: relativePath, outcome: result.outcome });\n newCoreFiles[relativePath] = result.value;\n\n if (result.outcome === 'added' || result.outcome === 'replaced') {\n fileWrites.push({ targetPath: path.join(targetDir, relativePath), content: newContent });\n }\n }\n\n for (const relativePath of Object.keys(oldManifest.coreFiles)) {\n if (adapter.coreFilePaths.includes(relativePath)) continue;\n try {\n await readFile(path.join(targetDir, relativePath), 'utf8');\n files.push({ path: relativePath, outcome: 'no-longer-core' });\n } catch {\n // already gone locally, nothing to report\n }\n }\n\n const fileMerge = adapter.mergeManifestFile(currentManifestFile, oldManifest, newTemplateManifestFile);\n\n const hasFileChanges = files.some(\n (f) => f.outcome === 'added' || f.outcome === 'replaced' || f.outcome === 'no-longer-core',\n );\n const hasChanges = hasFileChanges || fileMerge.changed;\n\n if (!hasChanges) {\n return {\n status: 'no-changes',\n fromVersion,\n toVersion,\n files,\n dependencies: fileMerge.dependencies,\n scripts: fileMerge.scripts,\n fields: fileMerge.fields,\n };\n }\n\n for (const write of fileWrites) {\n await mkdir(path.dirname(write.targetPath), { recursive: true });\n await writeFile(write.targetPath, write.content);\n }\n\n if (fileMerge.changed) {\n await adapter.writeManifestFile(targetDir, fileMerge.updatedFile);\n }\n\n const newManifest: Manifest = {\n generatorVersion: toVersion,\n language,\n coreFiles: newCoreFiles,\n coreDependencies: fileMerge.coreDependencies,\n coreScripts: fileMerge.coreScripts,\n coreFields: fileMerge.coreFields,\n };\n await writeManifest(targetDir, newManifest);\n\n await deps.runCommand('git', ['add', '-A'], targetDir);\n await deps.runCommand('git', ['commit', '-m', `chore: update clispark core to v${toVersion}`], targetDir);\n\n return {\n status: 'updated',\n fromVersion,\n toVersion,\n files,\n dependencies: fileMerge.dependencies,\n scripts: fileMerge.scripts,\n fields: fileMerge.fields,\n };\n}\n\nexport function formatUpdateSummary(result: UpdateResult): string {\n if (result.status === 'up-to-date') {\n return `Already up to date (v${result.toVersion}).`;\n }\n\n const added = result.files.filter((f) => f.outcome === 'added');\n const replaced = result.files.filter((f) => f.outcome === 'replaced');\n const skipped = result.files.filter((f) => f.outcome === 'skipped');\n const noLongerCore = result.files.filter((f) => f.outcome === 'no-longer-core');\n\n const lines: string[] = [];\n if (result.status === 'no-changes') {\n lines.push(\n noLongerCore.length\n ? `No changes applied: nothing to update since v${result.fromVersion}.`\n : `No changes applied: every core file/field has been modified locally since v${result.fromVersion}.`,\n );\n } else {\n lines.push(`Updated core from v${result.fromVersion} to v${result.toVersion}.`);\n }\n\n if (added.length) lines.push(` New: ${added.map((f) => f.path).join(', ')}`);\n if (replaced.length) lines.push(` Updated: ${replaced.map((f) => f.path).join(', ')}`);\n if (skipped.length) lines.push(` Skipped (locally modified): ${skipped.map((f) => f.path).join(', ')}`);\n if (noLongerCore.length) {\n lines.push(\n ` No longer part of the core, safe to remove manually: ${noLongerCore.map((f) => f.path).join(', ')}`,\n );\n }\n\n const fieldOutcomes = [...result.dependencies, ...result.scripts, ...result.fields].filter(\n (o) => o.outcome !== 'skipped',\n );\n if (fieldOutcomes.length) {\n lines.push(` Manifest: ${fieldOutcomes.map((o) => `${o.key} (${o.outcome})`).join(', ')}`);\n }\n\n if (result.status === 'updated') {\n lines.push('Run \"clispark releasenotes\" to see what changed.');\n }\n\n return lines.join('\\n');\n}\n","// src/update/releasenotes.ts\nimport { getGeneratorVersion, requireManifest } from './manifest';\n\nexport interface GitHubRelease {\n tag_name: string;\n name: string;\n body: string;\n}\n\nfunction stripV(version: string): string {\n return version.startsWith('v') ? version.slice(1) : version;\n}\n\nexport function compareVersions(a: string, b: string): number {\n const partsA = stripV(a).split('.').map(Number);\n const partsB = stripV(b).split('.').map(Number);\n const length = Math.max(partsA.length, partsB.length);\n for (let i = 0; i < length; i++) {\n const diff = (partsA[i] ?? 0) - (partsB[i] ?? 0);\n if (diff !== 0) return diff;\n }\n return 0;\n}\n\nexport interface ReleaseNotesResult {\n status: 'up-to-date' | 'releases-found';\n fromVersion: string;\n toVersion: string;\n releases: GitHubRelease[];\n}\n\nconst RELEASES_URL = 'https://api.github.com/repos/martinwichner/clispark/releases';\nconst FETCH_TIMEOUT_MS = 5000;\n\nexport async function fetchReleaseNotes(\n targetDir: string,\n fetchFn: typeof fetch = fetch,\n): Promise<ReleaseNotesResult> {\n const manifest = await requireManifest(targetDir);\n const fromVersion = manifest.generatorVersion;\n const toVersion = getGeneratorVersion();\n\n if (compareVersions(fromVersion, toVersion) >= 0) {\n return { status: 'up-to-date', fromVersion, toVersion, releases: [] };\n }\n\n const response = await fetchFn(RELEASES_URL, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });\n if (!response.ok) {\n throw new Error(`Failed to fetch release notes: GitHub API responded with ${response.status}`);\n }\n const allReleases = (await response.json()) as GitHubRelease[];\n\n const releases = allReleases\n .filter((r) => compareVersions(r.tag_name, fromVersion) > 0 && compareVersions(r.tag_name, toVersion) <= 0)\n .sort((a, b) => compareVersions(b.tag_name, a.tag_name));\n\n return { status: 'releases-found', fromVersion, toVersion, releases };\n}\n\nexport function formatReleaseNotes(result: ReleaseNotesResult): string {\n if (result.status === 'up-to-date') {\n return `You're on the latest clispark version (v${result.toVersion}), nothing to show.`;\n }\n if (result.releases.length === 0) {\n return `No published releases found between v${result.fromVersion} and v${result.toVersion}.`;\n }\n return result.releases.map((r) => `## ${r.tag_name}\\n\\n${r.body}`).join('\\n\\n');\n}\n","// src/add-wizard.ts\nimport { intro, outro, select, text, confirm, isCancel, cancel, log } from '@clack/prompts';\nimport type {\n CommandGenerator,\n CommandSpec,\n ExistingCommandNode,\n ParameterSpec,\n ParameterType,\n} from './languages/command-generator';\n\nexport interface AddWizardDeps {\n commandGenerator: CommandGenerator;\n}\n\nfunction exitIfCancelled(value: unknown): void {\n if (isCancel(value)) {\n cancel('Operation cancelled.');\n process.exit(1);\n }\n}\n\nconst NEW_TOP_LEVEL = '__new_top_level__';\nconst HERE = '__here__';\n\nfunction flattenForMenu(nodes: ExistingCommandNode[]): { value: string; label: string }[] {\n const result: { value: string; label: string }[] = [];\n for (const node of nodes) {\n result.push({ value: node.path, label: node.displayLabel });\n result.push(...flattenForMenu(node.children));\n }\n return result;\n}\n\nfunction findNode(nodes: ExistingCommandNode[], targetPath: string): ExistingCommandNode | undefined {\n for (const node of nodes) {\n if (node.path === targetPath) return node;\n const found = findNode(node.children, targetPath);\n if (found) return found;\n }\n return undefined;\n}\n\nasync function selectWithinNode(node: ExistingCommandNode): Promise<string[]> {\n if (node.children.length === 0) {\n return node.path.split(' ');\n }\n\n const options = [\n { value: HERE, label: `Direct subcommand of \"${node.path}\"` },\n ...node.children.map((child) => ({ value: child.path, label: `Under \"${child.path}\"` })),\n ];\n const choice = await select({ message: `Where under \"${node.path}\"?`, options });\n exitIfCancelled(choice);\n\n if (choice === HERE) {\n return node.path.split(' ');\n }\n const childNode = node.children.find((c) => c.path === choice)!;\n return selectWithinNode(childNode);\n}\n\nasync function selectPath(existing: ExistingCommandNode[]): Promise<string[]> {\n const options = [{ value: NEW_TOP_LEVEL, label: 'New top-level command' }, ...flattenForMenu(existing)];\n const choice = await select({ message: 'Where should the new command go?', options });\n exitIfCancelled(choice);\n\n if (choice === NEW_TOP_LEVEL) {\n return [];\n }\n\n const node = findNode(existing, choice as string)!;\n return selectWithinNode(node);\n}\n\nfunction flattenPaths(nodes: ExistingCommandNode[]): string[] {\n return nodes.flatMap((node) => [node.path, ...flattenPaths(node.children)]);\n}\n\nasync function collectParameters(): Promise<ParameterSpec[]> {\n const parameters: ParameterSpec[] = [];\n let hasOptional = false;\n\n for (;;) {\n const addMore = await confirm({\n message: parameters.length === 0 ? 'Add a parameter?' : 'Add another parameter?',\n });\n exitIfCancelled(addMore);\n if (!addMore) break;\n\n const nameValue = await text({\n message: 'Parameter name',\n validate: (value) => {\n if (!/^[a-z][a-zA-Z0-9]*$/.test(value)) return 'Use a single word starting with a lowercase letter.';\n if (parameters.some((p) => p.name === value)) return 'A parameter with this name already exists.';\n return undefined;\n },\n });\n exitIfCancelled(nameValue);\n const name = nameValue as string;\n\n const typeValue = await select({\n message: 'Parameter type',\n options: [\n { value: 'string', label: 'String' },\n { value: 'integer', label: 'Integer' },\n { value: 'boolean', label: 'Boolean' },\n { value: 'enum', label: 'String with allowed values' },\n ],\n });\n exitIfCancelled(typeValue);\n const type = typeValue as ParameterType;\n\n let required = false;\n if (type !== 'boolean') {\n const options = hasOptional\n ? [{ value: false, label: 'Optional' }]\n : [\n { value: true, label: 'Required' },\n { value: false, label: 'Optional' },\n ];\n const requiredValue = await select({ message: 'Required or optional?', options });\n exitIfCancelled(requiredValue);\n required = requiredValue as boolean;\n }\n if (!required) hasOptional = true;\n\n let allowedValues: string[] | undefined;\n if (type === 'enum') {\n const valuesInput = await text({\n message: 'Allowed values (comma-separated)',\n validate: (value) => {\n const values = value\n .split(',')\n .map((v) => v.trim())\n .filter(Boolean);\n if (values.length < 2) return 'Enter at least two comma-separated values.';\n for (const v of values) {\n if (!/^[A-Za-z0-9_-]+$/.test(v)) {\n return `Invalid value \"${v}\": use only letters, numbers, hyphens, and underscores.`;\n }\n }\n return undefined;\n },\n });\n exitIfCancelled(valuesInput);\n allowedValues = (valuesInput as string)\n .split(',')\n .map((v) => v.trim())\n .filter(Boolean);\n }\n\n parameters.push({ name, type, required, allowedValues });\n }\n\n return parameters;\n}\n\nexport async function runAddWizard(targetDir: string, deps: AddWizardDeps): Promise<void> {\n intro('clispark add — add a new command');\n\n const existing = await deps.commandGenerator.listExistingCommands(targetDir);\n const pathSegments = await selectPath(existing);\n const existingPaths = new Set(flattenPaths(existing));\n\n const nameValue = await text({\n message: 'Command name',\n validate: (value) => {\n if (!/^[a-z][a-zA-Z0-9]*$/.test(value)) return 'Use a single word starting with a lowercase letter.';\n const fullPath = [...pathSegments, value].join(' ');\n if (existingPaths.has(fullPath)) return `\"${fullPath}\" already exists.`;\n return undefined;\n },\n });\n exitIfCancelled(nameValue);\n const fullPathSegments = [...pathSegments, nameValue as string];\n\n const parameters = await collectParameters();\n\n log.info(`About to create \"${fullPathSegments.join(' ')}\" with ${parameters.length} parameter(s).`);\n const proceed = await confirm({ message: 'Proceed?' });\n exitIfCancelled(proceed);\n if (!proceed) {\n cancel('Cancelled.');\n process.exit(1);\n }\n\n const spec: CommandSpec = { pathSegments: fullPathSegments, parameters };\n const result = await deps.commandGenerator.generateCommand(targetDir, spec);\n\n outro(`Created ${result.commandFile} and ${result.testFile}.`);\n}\n","// src/whoami.ts\nimport os from 'node:os';\n\nconst JOKE_API_URL = 'https://v2.jokeapi.dev/joke/Programming,Miscellaneous';\nconst FETCH_TIMEOUT_MS = 3000;\n\n/** Languages JokeAPI (https://jokeapi.dev/) currently supports, per its /languages endpoint. */\nconst SUPPORTED_JOKE_LANGUAGES = ['cs', 'de', 'en', 'es', 'fr', 'pt'];\n\nexport const LOGO = String.raw`\n ⚡ clispark\n`;\n\nexport const FALLBACK_QUOTES = [\n \"Green unit tests don't mean it works. Real end-to-end verification does.\",\n 'A default value can silently reintroduce coupling you just removed.',\n \"The bug you can't find locally is waiting for you in CI.\",\n \"YAGNI until you actually need it — then it's just an adapter away.\",\n 'Every folder move has a bundling-depth bug waiting to happen.',\n 'The cheapest fix is the one you verify before you ship it.',\n 'TDD: write the failing test first, or explain later why it passed by accident.',\n \"If it's not tested against a real filesystem, it's a theory, not a fact.\",\n];\n\ninterface JokeApiSingle {\n error: false;\n type: 'single';\n joke: string;\n}\n\ninterface JokeApiTwoPart {\n error: false;\n type: 'twopart';\n setup: string;\n delivery: string;\n}\n\ninterface JokeApiError {\n error: true;\n}\n\ntype JokeApiResponse = JokeApiSingle | JokeApiTwoPart | JokeApiError;\n\n/** Maps a BCP-47 locale (e.g. \"de-DE\") to a JokeAPI language code, defaulting to \"en\" when unsupported. */\nexport function detectJokeLanguage(\n locale: string = Intl.DateTimeFormat().resolvedOptions().locale,\n): string {\n const primary = locale.split('-')[0].toLowerCase();\n return SUPPORTED_JOKE_LANGUAGES.includes(primary) ? primary : 'en';\n}\n\nfunction pickFallbackQuote(): string {\n return FALLBACK_QUOTES[Math.floor(Math.random() * FALLBACK_QUOTES.length)];\n}\n\nexport interface OsFacts {\n uptime: () => number;\n hostname: () => string;\n cpus: () => os.CpuInfo[];\n totalmem: () => number;\n platform: () => NodeJS.Platform;\n release: () => string;\n arch: () => string;\n}\n\nconst defaultOsFacts: OsFacts = {\n uptime: () => os.uptime(),\n hostname: () => os.hostname(),\n cpus: () => os.cpus(),\n totalmem: () => os.totalmem(),\n platform: () => os.platform(),\n release: () => os.release(),\n arch: () => os.arch(),\n};\n\nfunction formatUptime(seconds: number): string {\n const days = Math.floor(seconds / 86400);\n const hours = Math.floor((seconds % 86400) / 3600);\n const minutes = Math.floor((seconds % 3600) / 60);\n const parts: string[] = [];\n if (days > 0) parts.push(`${days}d`);\n if (days > 0 || hours > 0) parts.push(`${hours}h`);\n parts.push(`${minutes}m`);\n return parts.join(' ');\n}\n\nconst FACT_GENERATORS: Array<(facts: OsFacts) => string> = [\n (facts) => `This machine has been up for ${formatUptime(facts.uptime())}.`,\n (facts) => `Hostname: ${facts.hostname()}`,\n (facts) => {\n const cpus = facts.cpus();\n return `CPU: ${cpus[0]?.model.trim() ?? 'unknown'} (${cpus.length} logical cores)`;\n },\n (facts) => `RAM: ${(facts.totalmem() / 1024 ** 3).toFixed(1)} GB total`,\n (facts) => `OS: ${facts.platform()} ${facts.release()} (${facts.arch()})`,\n];\n\nexport function getRandomFunFact(osFacts: OsFacts = defaultOsFacts, randomFn: () => number = Math.random): string {\n const index = Math.floor(randomFn() * FACT_GENERATORS.length);\n return FACT_GENERATORS[index](osFacts);\n}\n\nasync function fetchJoke(language: string, fetchFn: typeof fetch): Promise<string | undefined> {\n try {\n const url = `${JOKE_API_URL}?lang=${language}&safe-mode`;\n const response = await fetchFn(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });\n if (!response.ok) return undefined;\n\n const data = (await response.json()) as JokeApiResponse;\n if (data.error) return undefined;\n return data.type === 'single' ? data.joke : `${data.setup}\\n${data.delivery}`;\n } catch {\n return undefined;\n }\n}\n\nexport type WhoamiMode = 'joke' | 'fact' | 'random';\n\nexport async function getWhoamiOutput(\n fetchFn: typeof fetch = fetch,\n osFacts: OsFacts = defaultOsFacts,\n randomFn: () => number = Math.random,\n mode: WhoamiMode = 'random',\n): Promise<string> {\n const showFact = mode === 'fact' || (mode === 'random' && randomFn() < 0.5);\n if (showFact) {\n return `${LOGO}\\n${getRandomFunFact(osFacts, randomFn)}\\n`;\n }\n\n const language = detectJokeLanguage();\n const quote = (await fetchJoke(language, fetchFn)) ?? pickFallbackQuote();\n return `${LOGO}\\n${quote}\\n`;\n}\n","// src/confetti.ts\n\nconst CONFETTI_VARIANTS = [\n '✨ 🎉 ✨ 🎊 ✨ 🎉 ✨\\n 🎈 🎊 🎈\\n✨ 🎉 ✨ 🎉',\n '🎊 ✨ 🎈 ✨ 🎊\\n 🎉 🎉 🎉\\n✨ 🎈 ✨ 🎈 ✨',\n '🎉✨🎊✨🎉✨🎊✨🎉\\n 🎈 🎈\\n✨🎊✨🎉✨🎊✨🎉✨',\n];\n\nexport function getConfetti(randomFn: () => number = Math.random): string {\n const index = Math.floor(randomFn() * CONFETTI_VARIANTS.length);\n return CONFETTI_VARIANTS[index];\n}\n\nexport function printConfetti(randomFn: () => number = Math.random): void {\n console.log(`\\n${getConfetti(randomFn)}\\n`);\n}\n"],"mappings":"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","names":["path","path","path","path","readFile","writeFile","path","writeFile","path","paths","path","writeFile","path","path","readFile","writeFile","path","CORE_FILE_PATHS","extractCoreFields","readFile","path","writeFile","mkdir","readFile","writeFile","path","FETCH_TIMEOUT_MS","checkNameAvailability","applyPrivateIntent","applyRegistryUrl","mkdir","readFile","readdir","writeFile","path","listExistingCommands","path","readdir","paths","readFile","toClassName","generateCommandFileContent","sampleArgValue","generateTestFileContent","generateCommand","mkdir","writeFile","validateProjectName","path","pack","readdir","readFile","writeFile","path","existsSync","readFileSync","mkdir","readFile","writeFile","path","fileURLToPath","readFile","path","mkdir","writeFile","fileURLToPath","existsSync","readFileSync","readdir","path","readFile","writeFile","path","mkdir","readFile","writeFile","path","spawn","FETCH_TIMEOUT_MS","defaultRunCommand","spawn","readFile","path","mkdir","writeFile","intro","outro","select","text","isCancel","cancel","log","exitIfCancelled","FETCH_TIMEOUT_MS","path"]}
|