clispark 1.8.1 → 1.10.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 +348 -249
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- /package/templates/{base → node}/ARCHITECTURE.md +0 -0
- /package/templates/{base → node}/README.md +0 -0
- /package/templates/{base → node}/bin/run.ts +0 -0
- /package/templates/{base → node}/gitignore +0 -0
- /package/templates/{base → node}/package.json +0 -0
- /package/templates/{base → node}/src/base-command.test.ts +0 -0
- /package/templates/{base → node}/src/base-command.ts +0 -0
- /package/templates/{base → node}/src/commands/hello.test.ts +0 -0
- /package/templates/{base → node}/src/commands/hello.ts +0 -0
- /package/templates/{base → node}/src/commands/task/complete.test.ts +0 -0
- /package/templates/{base → node}/src/commands/task/complete.ts +0 -0
- /package/templates/{base → node}/src/commands/task/list.test.ts +0 -0
- /package/templates/{base → node}/src/commands/task/list.ts +0 -0
- /package/templates/{base → node}/src/commands/task.test.ts +0 -0
- /package/templates/{base → node}/src/commands/task.ts +0 -0
- /package/templates/{base → node}/src/index.ts +0 -0
- /package/templates/{base → node}/src/logger.test.ts +0 -0
- /package/templates/{base → node}/src/logger.ts +0 -0
- /package/templates/{base → node}/tsconfig.json +0 -0
- /package/templates/{base → node}/tsup.config.ts +0 -0
- /package/templates/{base → node}/vitest.config.ts +0 -0
package/dist/cli.js
CHANGED
|
@@ -1,16 +1,201 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
|
-
import
|
|
4
|
+
import path9 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
|
-
// src/
|
|
11
|
-
|
|
10
|
+
// src/languages/packs/node-oclif.ts
|
|
11
|
+
import path4 from "path";
|
|
12
|
+
|
|
13
|
+
// src/package-root.ts
|
|
14
|
+
import { existsSync, readFileSync } from "fs";
|
|
15
|
+
import path from "path";
|
|
16
|
+
import { fileURLToPath } from "url";
|
|
17
|
+
function findPackageRoot() {
|
|
18
|
+
let dir = path.dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
while (true) {
|
|
20
|
+
const pkgPath = path.join(dir, "package.json");
|
|
21
|
+
if (existsSync(pkgPath)) {
|
|
22
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
23
|
+
if (pkg.name === "clispark") return dir;
|
|
24
|
+
}
|
|
25
|
+
const parentDir = path.dirname(dir);
|
|
26
|
+
if (parentDir === dir) {
|
|
27
|
+
throw new Error("Could not locate clispark's own package.json.");
|
|
28
|
+
}
|
|
29
|
+
dir = parentDir;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// src/update/adapters/node-oclif.ts
|
|
34
|
+
import { readFile, writeFile } from "fs/promises";
|
|
35
|
+
import path2 from "path";
|
|
36
|
+
|
|
37
|
+
// src/update/reconcile.ts
|
|
38
|
+
function reconcileEntry(currentLiveValue, oldManifestValue, newTemplateValue, isEqual) {
|
|
39
|
+
if (currentLiveValue === void 0) {
|
|
40
|
+
return { outcome: "added", value: newTemplateValue };
|
|
41
|
+
}
|
|
42
|
+
if (oldManifestValue !== void 0 && isEqual(currentLiveValue, oldManifestValue)) {
|
|
43
|
+
return { outcome: "replaced", value: newTemplateValue };
|
|
44
|
+
}
|
|
45
|
+
return { outcome: "skipped", value: oldManifestValue ?? currentLiveValue };
|
|
46
|
+
}
|
|
47
|
+
function stringEquals(a, b) {
|
|
48
|
+
return a === b;
|
|
49
|
+
}
|
|
50
|
+
function deepEquals(a, b) {
|
|
51
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/update/adapters/node-oclif.ts
|
|
55
|
+
var CORE_FILE_PATHS = [
|
|
56
|
+
"bin/run.ts",
|
|
57
|
+
"src/index.ts",
|
|
58
|
+
"src/base-command.ts",
|
|
59
|
+
"src/logger.ts",
|
|
60
|
+
"tsup.config.ts",
|
|
61
|
+
"vitest.config.ts",
|
|
62
|
+
"tsconfig.json",
|
|
63
|
+
"ARCHITECTURE.md",
|
|
64
|
+
".gitignore"
|
|
65
|
+
];
|
|
66
|
+
var CORE_SCRIPT_NAMES = ["build", "postbuild", "pretest", "test", "typecheck"];
|
|
67
|
+
function currentDependencyValue(pkg, name) {
|
|
68
|
+
if (pkg.dependencies?.[name] !== void 0) return { section: "dependencies", value: pkg.dependencies[name] };
|
|
69
|
+
if (pkg.devDependencies?.[name] !== void 0) {
|
|
70
|
+
return { section: "devDependencies", value: pkg.devDependencies[name] };
|
|
71
|
+
}
|
|
72
|
+
return void 0;
|
|
73
|
+
}
|
|
74
|
+
function extractCoreFields(pkg) {
|
|
75
|
+
const coreDependencies = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
76
|
+
const coreScripts = {};
|
|
77
|
+
for (const name of CORE_SCRIPT_NAMES) {
|
|
78
|
+
const value = pkg.scripts?.[name];
|
|
79
|
+
if (value !== void 0) coreScripts[name] = value;
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
coreDependencies,
|
|
83
|
+
coreScripts,
|
|
84
|
+
coreFields: {
|
|
85
|
+
engines: pkg.engines ?? {},
|
|
86
|
+
oclif: pkg.oclif ?? {}
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function mergePackageJson(currentPkg, oldManifest, newTemplatePkg) {
|
|
91
|
+
const updatedFile = { ...currentPkg };
|
|
92
|
+
let changed = false;
|
|
93
|
+
const dependencies = [];
|
|
94
|
+
const coreDependencies = {};
|
|
95
|
+
const dependencyNames = /* @__PURE__ */ new Set([
|
|
96
|
+
...Object.keys(newTemplatePkg.dependencies ?? {}),
|
|
97
|
+
...Object.keys(newTemplatePkg.devDependencies ?? {})
|
|
98
|
+
]);
|
|
99
|
+
for (const name of dependencyNames) {
|
|
100
|
+
const inNewDependencies = newTemplatePkg.dependencies?.[name] !== void 0;
|
|
101
|
+
const newValue = (inNewDependencies ? newTemplatePkg.dependencies : newTemplatePkg.devDependencies)[name];
|
|
102
|
+
const current = currentDependencyValue(currentPkg, name);
|
|
103
|
+
const oldValue = oldManifest.coreDependencies[name];
|
|
104
|
+
const result = reconcileEntry(current?.value, oldValue, newValue, stringEquals);
|
|
105
|
+
dependencies.push({ key: name, outcome: result.outcome });
|
|
106
|
+
coreDependencies[name] = result.value;
|
|
107
|
+
if (result.outcome !== "skipped" && result.value !== current?.value) {
|
|
108
|
+
changed = true;
|
|
109
|
+
const section = current?.section ?? (inNewDependencies ? "dependencies" : "devDependencies");
|
|
110
|
+
updatedFile[section] = { ...updatedFile[section], [name]: result.value };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const scripts = [];
|
|
114
|
+
const coreScripts = {};
|
|
115
|
+
for (const name of CORE_SCRIPT_NAMES) {
|
|
116
|
+
const newValue = newTemplatePkg.scripts?.[name];
|
|
117
|
+
if (newValue === void 0) continue;
|
|
118
|
+
const currentValue = currentPkg.scripts?.[name];
|
|
119
|
+
const oldValue = oldManifest.coreScripts[name];
|
|
120
|
+
const result = reconcileEntry(currentValue, oldValue, newValue, stringEquals);
|
|
121
|
+
scripts.push({ key: name, outcome: result.outcome });
|
|
122
|
+
coreScripts[name] = result.value;
|
|
123
|
+
if (result.outcome !== "skipped" && result.value !== currentValue) {
|
|
124
|
+
changed = true;
|
|
125
|
+
updatedFile.scripts = { ...updatedFile.scripts, [name]: result.value };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const oldCoreFields = oldManifest.coreFields;
|
|
129
|
+
const fields = [];
|
|
130
|
+
let enginesValue = oldCoreFields.engines ?? {};
|
|
131
|
+
let oclifValue = oldCoreFields.oclif ?? {};
|
|
132
|
+
if (newTemplatePkg.engines !== void 0) {
|
|
133
|
+
const enginesResult = reconcileEntry(
|
|
134
|
+
currentPkg.engines,
|
|
135
|
+
oldCoreFields.engines,
|
|
136
|
+
newTemplatePkg.engines,
|
|
137
|
+
deepEquals
|
|
138
|
+
);
|
|
139
|
+
fields.push({ key: "engines", outcome: enginesResult.outcome });
|
|
140
|
+
enginesValue = enginesResult.value;
|
|
141
|
+
if (enginesResult.outcome !== "skipped" && !deepEquals(enginesResult.value, currentPkg.engines)) {
|
|
142
|
+
changed = true;
|
|
143
|
+
updatedFile.engines = enginesResult.value;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (newTemplatePkg.oclif !== void 0) {
|
|
147
|
+
const oclifResult = reconcileEntry(currentPkg.oclif, oldCoreFields.oclif, newTemplatePkg.oclif, deepEquals);
|
|
148
|
+
fields.push({ key: "oclif", outcome: oclifResult.outcome });
|
|
149
|
+
oclifValue = oclifResult.value;
|
|
150
|
+
if (oclifResult.outcome !== "skipped" && !deepEquals(oclifResult.value, currentPkg.oclif)) {
|
|
151
|
+
changed = true;
|
|
152
|
+
updatedFile.oclif = oclifResult.value;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
updatedFile,
|
|
157
|
+
changed,
|
|
158
|
+
dependencies,
|
|
159
|
+
scripts,
|
|
160
|
+
fields,
|
|
161
|
+
coreDependencies,
|
|
162
|
+
coreScripts,
|
|
163
|
+
coreFields: { engines: enginesValue, oclif: oclifValue }
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
var nodeOclifAdapter = {
|
|
167
|
+
coreFilePaths: CORE_FILE_PATHS,
|
|
168
|
+
templateSourcePath(relativePath) {
|
|
169
|
+
return relativePath === ".gitignore" ? "gitignore" : relativePath;
|
|
170
|
+
},
|
|
171
|
+
manifestFileName: "package.json",
|
|
172
|
+
async readManifestFile(dir) {
|
|
173
|
+
const content = await readFile(path2.join(dir, "package.json"), "utf8");
|
|
174
|
+
return JSON.parse(content);
|
|
175
|
+
},
|
|
176
|
+
async writeManifestFile(dir, content) {
|
|
177
|
+
await writeFile(path2.join(dir, "package.json"), JSON.stringify(content, null, 2) + "\n");
|
|
178
|
+
},
|
|
179
|
+
parseManifestFile(rawContent) {
|
|
180
|
+
return JSON.parse(rawContent);
|
|
181
|
+
},
|
|
182
|
+
readProjectName(manifestFile) {
|
|
183
|
+
return manifestFile.name;
|
|
184
|
+
},
|
|
185
|
+
extractCoreFields(manifestFile) {
|
|
186
|
+
return extractCoreFields(manifestFile);
|
|
187
|
+
},
|
|
188
|
+
mergeManifestFile(current, oldManifest, newTemplate) {
|
|
189
|
+
return mergePackageJson(current, oldManifest, newTemplate);
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
// src/languages/registry-checkers/npm.ts
|
|
194
|
+
import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
195
|
+
import path3 from "path";
|
|
196
|
+
var NPM_DEFAULT_REGISTRY_URL = "https://registry.npmjs.org";
|
|
12
197
|
var FETCH_TIMEOUT_MS = 5e3;
|
|
13
|
-
async function
|
|
198
|
+
async function checkNameAvailability(name, registryUrl) {
|
|
14
199
|
const url = `${registryUrl.replace(/\/$/, "")}/${encodeURIComponent(name)}`;
|
|
15
200
|
try {
|
|
16
201
|
const response = await fetch(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });
|
|
@@ -21,10 +206,51 @@ async function checkPackageNameAvailability(name, registryUrl = DEFAULT_REGISTRY
|
|
|
21
206
|
return "unverified";
|
|
22
207
|
}
|
|
23
208
|
}
|
|
209
|
+
async function applyPrivateIntent(targetDir) {
|
|
210
|
+
const packageJsonPath = path3.join(targetDir, "package.json");
|
|
211
|
+
const pkg = JSON.parse(await readFile2(packageJsonPath, "utf8"));
|
|
212
|
+
pkg.private = true;
|
|
213
|
+
await writeFile2(packageJsonPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
214
|
+
}
|
|
215
|
+
var npmRegistryChecker = {
|
|
216
|
+
checkNameAvailability,
|
|
217
|
+
applyPrivateIntent
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
// src/languages/packs/node-oclif.ts
|
|
221
|
+
function validateProjectName(value) {
|
|
222
|
+
if (!value || value.trim().length === 0) return "Project name is required.";
|
|
223
|
+
if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(value)) {
|
|
224
|
+
return "Use lowercase letters and numbers, with single hyphens between words (no leading, trailing, or repeated hyphens).";
|
|
225
|
+
}
|
|
226
|
+
return void 0;
|
|
227
|
+
}
|
|
228
|
+
var nodeOclifPack = {
|
|
229
|
+
id: "node",
|
|
230
|
+
displayName: "Node.js / TypeScript (oclif)",
|
|
231
|
+
templateDir: path4.join(findPackageRoot(), "templates", "node"),
|
|
232
|
+
scaffoldCommands: [
|
|
233
|
+
{ command: "npm", args: ["install"] },
|
|
234
|
+
{ command: "npm", args: ["run", "build"] }
|
|
235
|
+
],
|
|
236
|
+
validateProjectName,
|
|
237
|
+
updateAdapter: nodeOclifAdapter,
|
|
238
|
+
registry: {
|
|
239
|
+
defaultUrl: NPM_DEFAULT_REGISTRY_URL,
|
|
240
|
+
promptLabel: "Custom npm registry URL (leave empty for npmjs.org)",
|
|
241
|
+
checkNameAvailability: npmRegistryChecker.checkNameAvailability,
|
|
242
|
+
applyPrivateIntent: npmRegistryChecker.applyPrivateIntent
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
// src/languages/index.ts
|
|
247
|
+
var LANGUAGE_PACKS = {
|
|
248
|
+
[nodeOclifPack.id]: nodeOclifPack
|
|
249
|
+
};
|
|
24
250
|
|
|
25
251
|
// src/wizard.ts
|
|
26
252
|
var defaultDeps = {
|
|
27
|
-
|
|
253
|
+
languagePacks: LANGUAGE_PACKS
|
|
28
254
|
};
|
|
29
255
|
function exitIfCancelled(value) {
|
|
30
256
|
if (isCancel(value)) {
|
|
@@ -32,18 +258,18 @@ function exitIfCancelled(value) {
|
|
|
32
258
|
process.exit(1);
|
|
33
259
|
}
|
|
34
260
|
}
|
|
35
|
-
function validateProjectName(value) {
|
|
36
|
-
if (!value || value.trim().length === 0) return "Project name is required.";
|
|
37
|
-
if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(value)) {
|
|
38
|
-
return "Use lowercase letters and numbers, with single hyphens between words (no leading, trailing, or repeated hyphens).";
|
|
39
|
-
}
|
|
40
|
-
return void 0;
|
|
41
|
-
}
|
|
42
261
|
async function runWizard(deps = defaultDeps) {
|
|
43
262
|
intro("clispark \u2014 scaffold a new CLI project");
|
|
263
|
+
const packs = Object.values(deps.languagePacks);
|
|
264
|
+
const languageValue = await select({
|
|
265
|
+
message: "Which language?",
|
|
266
|
+
options: packs.map((pack2) => ({ value: pack2.id, label: pack2.displayName }))
|
|
267
|
+
});
|
|
268
|
+
exitIfCancelled(languageValue);
|
|
269
|
+
const pack = deps.languagePacks[languageValue];
|
|
44
270
|
const nameValue = await text({
|
|
45
271
|
message: "Project name",
|
|
46
|
-
validate: validateProjectName
|
|
272
|
+
validate: pack.validateProjectName
|
|
47
273
|
});
|
|
48
274
|
exitIfCancelled(nameValue);
|
|
49
275
|
let projectName = nameValue;
|
|
@@ -56,18 +282,18 @@ async function runWizard(deps = defaultDeps) {
|
|
|
56
282
|
});
|
|
57
283
|
exitIfCancelled(profileValue);
|
|
58
284
|
const profile = profileValue;
|
|
59
|
-
let registryUrl =
|
|
285
|
+
let registryUrl = pack.registry.defaultUrl;
|
|
60
286
|
if (profile === "work") {
|
|
61
287
|
const registryValue = await text({
|
|
62
|
-
message:
|
|
63
|
-
placeholder:
|
|
64
|
-
defaultValue:
|
|
288
|
+
message: pack.registry.promptLabel,
|
|
289
|
+
placeholder: pack.registry.defaultUrl,
|
|
290
|
+
defaultValue: pack.registry.defaultUrl
|
|
65
291
|
});
|
|
66
292
|
exitIfCancelled(registryValue);
|
|
67
|
-
registryUrl = registryValue ||
|
|
293
|
+
registryUrl = registryValue || pack.registry.defaultUrl;
|
|
68
294
|
}
|
|
69
295
|
const publishIntentValue = await select({
|
|
70
|
-
message: "Do you plan to publish this
|
|
296
|
+
message: "Do you plan to publish this?",
|
|
71
297
|
options: [
|
|
72
298
|
{ value: false, label: "No" },
|
|
73
299
|
{ value: true, label: "Yes" }
|
|
@@ -78,37 +304,36 @@ async function runWizard(deps = defaultDeps) {
|
|
|
78
304
|
const publishIntent = publishIntentValue;
|
|
79
305
|
let nameAvailability = "skipped";
|
|
80
306
|
if (publishIntent) {
|
|
81
|
-
nameAvailability = await
|
|
307
|
+
nameAvailability = await pack.registry.checkNameAvailability(projectName, registryUrl);
|
|
82
308
|
while (nameAvailability === "taken") {
|
|
83
309
|
log.warn(`"${projectName}" is already taken on ${registryUrl}. Please choose a different name.`);
|
|
84
310
|
const retryValue = await text({
|
|
85
311
|
message: "Project name",
|
|
86
|
-
validate: validateProjectName
|
|
312
|
+
validate: pack.validateProjectName
|
|
87
313
|
});
|
|
88
314
|
exitIfCancelled(retryValue);
|
|
89
315
|
projectName = retryValue;
|
|
90
|
-
nameAvailability = await
|
|
316
|
+
nameAvailability = await pack.registry.checkNameAvailability(projectName, registryUrl);
|
|
91
317
|
}
|
|
92
318
|
if (nameAvailability === "unverified") {
|
|
93
319
|
log.warn(`Could not verify availability of "${projectName}" on ${registryUrl}. Continuing anyway.`);
|
|
94
320
|
}
|
|
95
321
|
}
|
|
96
322
|
outro(`Ready to scaffold "${projectName}".`);
|
|
97
|
-
return { projectName, profile, registryUrl, publishIntent, nameAvailability };
|
|
323
|
+
return { language: pack.id, projectName, profile, registryUrl, publishIntent, nameAvailability };
|
|
98
324
|
}
|
|
99
325
|
|
|
100
326
|
// src/scaffold.ts
|
|
327
|
+
import { cp, readdir, readFile as readFile4, rename, writeFile as writeFile4 } from "fs/promises";
|
|
328
|
+
import path6 from "path";
|
|
101
329
|
import spawn from "cross-spawn";
|
|
102
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
103
|
-
import path2 from "path";
|
|
104
|
-
import { cp, readdir, readFile as readFile2, rename, writeFile as writeFile2 } from "fs/promises";
|
|
105
330
|
|
|
106
331
|
// src/update/manifest.ts
|
|
107
332
|
import { createHash } from "crypto";
|
|
108
|
-
import { existsSync, readFileSync } from "fs";
|
|
109
|
-
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
110
|
-
import
|
|
111
|
-
import { fileURLToPath } from "url";
|
|
333
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
334
|
+
import { mkdir, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
335
|
+
import path5 from "path";
|
|
336
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
112
337
|
|
|
113
338
|
// src/errors.ts
|
|
114
339
|
var UserError = class extends Error {
|
|
@@ -119,64 +344,33 @@ var UserError = class extends Error {
|
|
|
119
344
|
};
|
|
120
345
|
|
|
121
346
|
// src/update/manifest.ts
|
|
122
|
-
var CORE_FILE_PATHS = [
|
|
123
|
-
"bin/run.ts",
|
|
124
|
-
"src/index.ts",
|
|
125
|
-
"src/base-command.ts",
|
|
126
|
-
"src/logger.ts",
|
|
127
|
-
"tsup.config.ts",
|
|
128
|
-
"vitest.config.ts",
|
|
129
|
-
"tsconfig.json",
|
|
130
|
-
"ARCHITECTURE.md",
|
|
131
|
-
".gitignore"
|
|
132
|
-
];
|
|
133
|
-
var CORE_SCRIPT_NAMES = ["build", "postbuild", "pretest", "test", "typecheck"];
|
|
134
|
-
function templateSourcePath(relativePath) {
|
|
135
|
-
return relativePath === ".gitignore" ? "gitignore" : relativePath;
|
|
136
|
-
}
|
|
137
347
|
function hashContent(content) {
|
|
138
348
|
return createHash("sha256").update(content).digest("hex");
|
|
139
349
|
}
|
|
140
|
-
async function hashCoreFiles(dir) {
|
|
350
|
+
async function hashCoreFiles(dir, adapter) {
|
|
141
351
|
const entries = await Promise.all(
|
|
142
|
-
|
|
143
|
-
const content = await
|
|
352
|
+
adapter.coreFilePaths.map(async (relativePath) => {
|
|
353
|
+
const content = await readFile3(path5.join(dir, relativePath), "utf8");
|
|
144
354
|
return [relativePath, hashContent(content)];
|
|
145
355
|
})
|
|
146
356
|
);
|
|
147
357
|
return Object.fromEntries(entries);
|
|
148
358
|
}
|
|
149
|
-
function
|
|
150
|
-
const
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if (value !== void 0) coreScripts[name] = value;
|
|
155
|
-
}
|
|
156
|
-
return {
|
|
157
|
-
coreDependencies,
|
|
158
|
-
coreScripts,
|
|
159
|
-
coreFields: {
|
|
160
|
-
engines: pkg.engines ?? {},
|
|
161
|
-
oclif: pkg.oclif ?? {}
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
async function buildManifest(targetDir, generatorVersion) {
|
|
166
|
-
const coreFiles = await hashCoreFiles(targetDir);
|
|
167
|
-
const pkg = JSON.parse(await readFile(path.join(targetDir, "package.json"), "utf8"));
|
|
168
|
-
const { coreDependencies, coreScripts, coreFields } = extractCoreFields(pkg);
|
|
169
|
-
return { generatorVersion, coreFiles, coreDependencies, coreScripts, coreFields };
|
|
359
|
+
async function buildManifest(targetDir, generatorVersion, language, adapter) {
|
|
360
|
+
const coreFiles = await hashCoreFiles(targetDir, adapter);
|
|
361
|
+
const manifestFile = await adapter.readManifestFile(targetDir);
|
|
362
|
+
const { coreDependencies, coreScripts, coreFields } = adapter.extractCoreFields(manifestFile);
|
|
363
|
+
return { generatorVersion, language, coreFiles, coreDependencies, coreScripts, coreFields };
|
|
170
364
|
}
|
|
171
|
-
var MANIFEST_RELATIVE_PATH =
|
|
365
|
+
var MANIFEST_RELATIVE_PATH = path5.join(".clispark", "manifest.json");
|
|
172
366
|
async function writeManifest(targetDir, manifest) {
|
|
173
|
-
const manifestPath =
|
|
174
|
-
await mkdir(
|
|
175
|
-
await
|
|
367
|
+
const manifestPath = path5.join(targetDir, MANIFEST_RELATIVE_PATH);
|
|
368
|
+
await mkdir(path5.dirname(manifestPath), { recursive: true });
|
|
369
|
+
await writeFile3(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
|
|
176
370
|
}
|
|
177
371
|
async function readManifest(targetDir) {
|
|
178
372
|
try {
|
|
179
|
-
const content = await
|
|
373
|
+
const content = await readFile3(path5.join(targetDir, MANIFEST_RELATIVE_PATH), "utf8");
|
|
180
374
|
return JSON.parse(content);
|
|
181
375
|
} catch {
|
|
182
376
|
return void 0;
|
|
@@ -192,14 +386,14 @@ async function requireManifest(targetDir) {
|
|
|
192
386
|
return manifest;
|
|
193
387
|
}
|
|
194
388
|
function getGeneratorVersion() {
|
|
195
|
-
let dir =
|
|
389
|
+
let dir = path5.dirname(fileURLToPath2(import.meta.url));
|
|
196
390
|
while (true) {
|
|
197
|
-
const pkgPath =
|
|
198
|
-
if (
|
|
199
|
-
const pkg = JSON.parse(
|
|
391
|
+
const pkgPath = path5.join(dir, "package.json");
|
|
392
|
+
if (existsSync2(pkgPath)) {
|
|
393
|
+
const pkg = JSON.parse(readFileSync2(pkgPath, "utf8"));
|
|
200
394
|
if (pkg.name === "clispark") return pkg.version;
|
|
201
395
|
}
|
|
202
|
-
const parentDir =
|
|
396
|
+
const parentDir = path5.dirname(dir);
|
|
203
397
|
if (parentDir === dir) {
|
|
204
398
|
throw new Error("Could not locate clispark's own package.json.");
|
|
205
399
|
}
|
|
@@ -208,7 +402,6 @@ function getGeneratorVersion() {
|
|
|
208
402
|
}
|
|
209
403
|
|
|
210
404
|
// src/scaffold.ts
|
|
211
|
-
var TEMPLATE_DIR = path2.join(path2.dirname(fileURLToPath2(import.meta.url)), "..", "templates", "base");
|
|
212
405
|
async function assertTargetDirIsUsable(targetDir) {
|
|
213
406
|
let entries;
|
|
214
407
|
try {
|
|
@@ -227,7 +420,7 @@ async function collectFiles(dir) {
|
|
|
227
420
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
228
421
|
const files = await Promise.all(
|
|
229
422
|
entries.map((entry) => {
|
|
230
|
-
const fullPath =
|
|
423
|
+
const fullPath = path6.join(dir, entry.name);
|
|
231
424
|
return entry.isDirectory() ? collectFiles(fullPath) : Promise.resolve([fullPath]);
|
|
232
425
|
})
|
|
233
426
|
);
|
|
@@ -237,30 +430,24 @@ async function replacePlaceholdersInTree(targetDir, projectName) {
|
|
|
237
430
|
const files = await collectFiles(targetDir);
|
|
238
431
|
await Promise.all(
|
|
239
432
|
files.map(async (filePath) => {
|
|
240
|
-
const content = await
|
|
433
|
+
const content = await readFile4(filePath, "utf8");
|
|
241
434
|
if (content.includes("{{projectName}}")) {
|
|
242
|
-
await
|
|
435
|
+
await writeFile4(filePath, applyPlaceholders(content, projectName));
|
|
243
436
|
}
|
|
244
437
|
})
|
|
245
438
|
);
|
|
246
439
|
}
|
|
247
|
-
async function
|
|
248
|
-
const packageJsonPath = path2.join(targetDir, "package.json");
|
|
249
|
-
const pkg = JSON.parse(await readFile2(packageJsonPath, "utf8"));
|
|
250
|
-
pkg.private = true;
|
|
251
|
-
await writeFile2(packageJsonPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
252
|
-
}
|
|
253
|
-
async function copyTemplate(options) {
|
|
440
|
+
async function copyTemplate(options, pack) {
|
|
254
441
|
const { projectName, targetDir, registryUrl, publishIntent } = options;
|
|
255
442
|
await assertTargetDirIsUsable(targetDir);
|
|
256
|
-
await cp(
|
|
257
|
-
await rename(
|
|
443
|
+
await cp(pack.templateDir, targetDir, { recursive: true });
|
|
444
|
+
await rename(path6.join(targetDir, "gitignore"), path6.join(targetDir, ".gitignore"));
|
|
258
445
|
await replacePlaceholdersInTree(targetDir, projectName);
|
|
259
446
|
if (publishIntent === false) {
|
|
260
|
-
await
|
|
447
|
+
await pack.registry.applyPrivateIntent(targetDir);
|
|
261
448
|
}
|
|
262
|
-
if (registryUrl && registryUrl !==
|
|
263
|
-
await
|
|
449
|
+
if (registryUrl && registryUrl !== pack.registry.defaultUrl) {
|
|
450
|
+
await writeFile4(path6.join(targetDir, ".npmrc"), `registry=${registryUrl}
|
|
264
451
|
`);
|
|
265
452
|
}
|
|
266
453
|
}
|
|
@@ -278,22 +465,23 @@ async function defaultRunCommand(command, args, cwd) {
|
|
|
278
465
|
});
|
|
279
466
|
}
|
|
280
467
|
var defaultScaffoldDeps = { runCommand: defaultRunCommand };
|
|
281
|
-
async function scaffoldProject(options, deps = defaultScaffoldDeps) {
|
|
282
|
-
await copyTemplate(options);
|
|
468
|
+
async function scaffoldProject(options, pack, deps = defaultScaffoldDeps) {
|
|
469
|
+
await copyTemplate(options, pack);
|
|
283
470
|
const { targetDir } = options;
|
|
284
|
-
const manifest = await buildManifest(targetDir, getGeneratorVersion());
|
|
471
|
+
const manifest = await buildManifest(targetDir, getGeneratorVersion(), pack.id, pack.updateAdapter);
|
|
285
472
|
await writeManifest(targetDir, manifest);
|
|
286
473
|
await deps.runCommand("git", ["init"], targetDir);
|
|
287
474
|
await deps.runCommand("git", ["add", "-A"], targetDir);
|
|
288
475
|
await deps.runCommand("git", ["commit", "-m", "chore: initial scaffold from clispark"], targetDir);
|
|
289
|
-
|
|
290
|
-
|
|
476
|
+
for (const scaffoldCommand of pack.scaffoldCommands) {
|
|
477
|
+
await deps.runCommand(scaffoldCommand.command, scaffoldCommand.args, targetDir);
|
|
478
|
+
}
|
|
291
479
|
}
|
|
292
480
|
|
|
293
481
|
// src/logger.ts
|
|
294
482
|
import { randomBytes } from "crypto";
|
|
295
483
|
import { mkdirSync, readdirSync, statSync, unlinkSync, writeFileSync } from "fs";
|
|
296
|
-
import
|
|
484
|
+
import path7 from "path";
|
|
297
485
|
import envPaths from "env-paths";
|
|
298
486
|
import pino from "pino";
|
|
299
487
|
var paths = envPaths("clispark", { suffix: "" });
|
|
@@ -329,7 +517,7 @@ var SWEEP_MARKER_FILE = ".last-sweep";
|
|
|
329
517
|
var SWEEP_THROTTLE_MS = 24 * 60 * 60 * 1e3;
|
|
330
518
|
function sweepOldLogs(logDir) {
|
|
331
519
|
safely(() => {
|
|
332
|
-
const markerPath =
|
|
520
|
+
const markerPath = path7.join(logDir, SWEEP_MARKER_FILE);
|
|
333
521
|
let shouldSweep = true;
|
|
334
522
|
try {
|
|
335
523
|
shouldSweep = Date.now() - statSync(markerPath).mtimeMs >= SWEEP_THROTTLE_MS;
|
|
@@ -339,7 +527,7 @@ function sweepOldLogs(logDir) {
|
|
|
339
527
|
const cutoffMs = Date.now() - getRetentionDays() * 24 * 60 * 60 * 1e3;
|
|
340
528
|
for (const file of readdirSync(logDir)) {
|
|
341
529
|
if (file === SWEEP_MARKER_FILE) continue;
|
|
342
|
-
const filePath =
|
|
530
|
+
const filePath = path7.join(logDir, file);
|
|
343
531
|
if (statSync(filePath).mtimeMs < cutoffMs) {
|
|
344
532
|
unlinkSync(filePath);
|
|
345
533
|
}
|
|
@@ -350,7 +538,7 @@ function sweepOldLogs(logDir) {
|
|
|
350
538
|
function createLogger(commandName, logDir = paths.log) {
|
|
351
539
|
mkdirSync(logDir, { recursive: true });
|
|
352
540
|
sweepOldLogs(logDir);
|
|
353
|
-
const logFilePath =
|
|
541
|
+
const logFilePath = path7.join(logDir, buildLogFileName(commandName));
|
|
354
542
|
const fileDestination = pino.destination({ dest: logFilePath, sync: true, mode: 384 });
|
|
355
543
|
const destination = process.env.DEBUG ? pino.multistream([{ stream: fileDestination }, { stream: process.stdout }]) : fileDestination;
|
|
356
544
|
const logger = pino({ redact: buildRedactPaths([...SENSITIVE_LOG_KEYS, "registryUrl"]) }, destination);
|
|
@@ -388,27 +576,10 @@ function withLogging(commandName, action, logDir = paths.log, loggerFactory = cr
|
|
|
388
576
|
}
|
|
389
577
|
|
|
390
578
|
// src/update/update.ts
|
|
391
|
-
import { mkdir as mkdir2, readFile as
|
|
392
|
-
import
|
|
579
|
+
import { mkdir as mkdir2, readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
|
|
580
|
+
import path8 from "path";
|
|
393
581
|
import spawn2 from "cross-spawn";
|
|
394
582
|
|
|
395
|
-
// src/update/reconcile.ts
|
|
396
|
-
function reconcileEntry(currentLiveValue, oldManifestValue, newTemplateValue, isEqual) {
|
|
397
|
-
if (currentLiveValue === void 0) {
|
|
398
|
-
return { outcome: "added", value: newTemplateValue };
|
|
399
|
-
}
|
|
400
|
-
if (oldManifestValue !== void 0 && isEqual(currentLiveValue, oldManifestValue)) {
|
|
401
|
-
return { outcome: "replaced", value: newTemplateValue };
|
|
402
|
-
}
|
|
403
|
-
return { outcome: "skipped", value: oldManifestValue ?? currentLiveValue };
|
|
404
|
-
}
|
|
405
|
-
function stringEquals(a, b) {
|
|
406
|
-
return a === b;
|
|
407
|
-
}
|
|
408
|
-
function deepEquals(a, b) {
|
|
409
|
-
return JSON.stringify(a) === JSON.stringify(b);
|
|
410
|
-
}
|
|
411
|
-
|
|
412
583
|
// src/update/releasenotes.ts
|
|
413
584
|
function stripV(version) {
|
|
414
585
|
return version.startsWith("v") ? version.slice(1) : version;
|
|
@@ -452,95 +623,6 @@ function formatReleaseNotes(result) {
|
|
|
452
623
|
${r.body}`).join("\n\n");
|
|
453
624
|
}
|
|
454
625
|
|
|
455
|
-
// src/update/update-package-json.ts
|
|
456
|
-
function currentDependencyValue(pkg, name) {
|
|
457
|
-
if (pkg.dependencies?.[name] !== void 0) return { section: "dependencies", value: pkg.dependencies[name] };
|
|
458
|
-
if (pkg.devDependencies?.[name] !== void 0) {
|
|
459
|
-
return { section: "devDependencies", value: pkg.devDependencies[name] };
|
|
460
|
-
}
|
|
461
|
-
return void 0;
|
|
462
|
-
}
|
|
463
|
-
function mergePackageJson(currentPkg, oldManifest, newTemplatePkg) {
|
|
464
|
-
const updatedPkg = { ...currentPkg };
|
|
465
|
-
let changed = false;
|
|
466
|
-
const dependencies = [];
|
|
467
|
-
const coreDependencies = {};
|
|
468
|
-
const dependencyNames = /* @__PURE__ */ new Set([
|
|
469
|
-
...Object.keys(newTemplatePkg.dependencies ?? {}),
|
|
470
|
-
...Object.keys(newTemplatePkg.devDependencies ?? {})
|
|
471
|
-
]);
|
|
472
|
-
for (const name of dependencyNames) {
|
|
473
|
-
const inNewDependencies = newTemplatePkg.dependencies?.[name] !== void 0;
|
|
474
|
-
const newValue = (inNewDependencies ? newTemplatePkg.dependencies : newTemplatePkg.devDependencies)[name];
|
|
475
|
-
const current = currentDependencyValue(currentPkg, name);
|
|
476
|
-
const oldValue = oldManifest.coreDependencies[name];
|
|
477
|
-
const result = reconcileEntry(current?.value, oldValue, newValue, stringEquals);
|
|
478
|
-
dependencies.push({ key: name, outcome: result.outcome });
|
|
479
|
-
coreDependencies[name] = result.value;
|
|
480
|
-
if (result.outcome !== "skipped" && result.value !== current?.value) {
|
|
481
|
-
changed = true;
|
|
482
|
-
const section = current?.section ?? (inNewDependencies ? "dependencies" : "devDependencies");
|
|
483
|
-
updatedPkg[section] = { ...updatedPkg[section], [name]: result.value };
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
const scripts = [];
|
|
487
|
-
const coreScripts = {};
|
|
488
|
-
for (const name of CORE_SCRIPT_NAMES) {
|
|
489
|
-
const newValue = newTemplatePkg.scripts?.[name];
|
|
490
|
-
if (newValue === void 0) continue;
|
|
491
|
-
const currentValue = currentPkg.scripts?.[name];
|
|
492
|
-
const oldValue = oldManifest.coreScripts[name];
|
|
493
|
-
const result = reconcileEntry(currentValue, oldValue, newValue, stringEquals);
|
|
494
|
-
scripts.push({ key: name, outcome: result.outcome });
|
|
495
|
-
coreScripts[name] = result.value;
|
|
496
|
-
if (result.outcome !== "skipped" && result.value !== currentValue) {
|
|
497
|
-
changed = true;
|
|
498
|
-
updatedPkg.scripts = { ...updatedPkg.scripts, [name]: result.value };
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
const fields = [];
|
|
502
|
-
let enginesValue = oldManifest.coreFields.engines;
|
|
503
|
-
let oclifValue = oldManifest.coreFields.oclif;
|
|
504
|
-
if (newTemplatePkg.engines !== void 0) {
|
|
505
|
-
const enginesResult = reconcileEntry(
|
|
506
|
-
currentPkg.engines,
|
|
507
|
-
oldManifest.coreFields.engines,
|
|
508
|
-
newTemplatePkg.engines,
|
|
509
|
-
deepEquals
|
|
510
|
-
);
|
|
511
|
-
fields.push({ key: "engines", outcome: enginesResult.outcome });
|
|
512
|
-
enginesValue = enginesResult.value;
|
|
513
|
-
if (enginesResult.outcome !== "skipped" && !deepEquals(enginesResult.value, currentPkg.engines)) {
|
|
514
|
-
changed = true;
|
|
515
|
-
updatedPkg.engines = enginesResult.value;
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
if (newTemplatePkg.oclif !== void 0) {
|
|
519
|
-
const oclifResult = reconcileEntry(
|
|
520
|
-
currentPkg.oclif,
|
|
521
|
-
oldManifest.coreFields.oclif,
|
|
522
|
-
newTemplatePkg.oclif,
|
|
523
|
-
deepEquals
|
|
524
|
-
);
|
|
525
|
-
fields.push({ key: "oclif", outcome: oclifResult.outcome });
|
|
526
|
-
oclifValue = oclifResult.value;
|
|
527
|
-
if (oclifResult.outcome !== "skipped" && !deepEquals(oclifResult.value, currentPkg.oclif)) {
|
|
528
|
-
changed = true;
|
|
529
|
-
updatedPkg.oclif = oclifResult.value;
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
return {
|
|
533
|
-
updatedPkg,
|
|
534
|
-
changed,
|
|
535
|
-
dependencies,
|
|
536
|
-
scripts,
|
|
537
|
-
fields,
|
|
538
|
-
coreDependencies,
|
|
539
|
-
coreScripts,
|
|
540
|
-
coreFields: { engines: enginesValue, oclif: oclifValue }
|
|
541
|
-
};
|
|
542
|
-
}
|
|
543
|
-
|
|
544
626
|
// src/update/update.ts
|
|
545
627
|
async function defaultRunCommand2(command, args, cwd) {
|
|
546
628
|
await new Promise((resolve, reject) => {
|
|
@@ -567,7 +649,7 @@ async function defaultCaptureCommand(command, args, cwd) {
|
|
|
567
649
|
});
|
|
568
650
|
}
|
|
569
651
|
var defaultUpdateDeps = { runCommand: defaultRunCommand2, captureCommand: defaultCaptureCommand };
|
|
570
|
-
async function updateProject(targetDir, deps = defaultUpdateDeps) {
|
|
652
|
+
async function updateProject(targetDir, adapter, templateDir, language, deps = defaultUpdateDeps) {
|
|
571
653
|
const status = (await deps.captureCommand("git", ["status", "--porcelain"], targetDir)).trim();
|
|
572
654
|
if (status.length > 0) {
|
|
573
655
|
throw new UserError("Working tree is not clean. Commit or stash your changes before running update.");
|
|
@@ -578,24 +660,26 @@ async function updateProject(targetDir, deps = defaultUpdateDeps) {
|
|
|
578
660
|
if (compareVersions(fromVersion, toVersion) >= 0) {
|
|
579
661
|
return { status: "up-to-date", fromVersion, toVersion, files: [], dependencies: [], scripts: [], fields: [] };
|
|
580
662
|
}
|
|
581
|
-
const
|
|
582
|
-
const projectName =
|
|
583
|
-
const
|
|
584
|
-
|
|
663
|
+
const currentManifestFile = await adapter.readManifestFile(targetDir);
|
|
664
|
+
const projectName = adapter.readProjectName(currentManifestFile);
|
|
665
|
+
const newTemplateRaw = applyPlaceholders(
|
|
666
|
+
await readFile5(path8.join(templateDir, adapter.manifestFileName), "utf8"),
|
|
667
|
+
projectName
|
|
585
668
|
);
|
|
669
|
+
const newTemplateManifestFile = adapter.parseManifestFile(newTemplateRaw);
|
|
586
670
|
const files = [];
|
|
587
671
|
const newCoreFiles = {};
|
|
588
672
|
const fileWrites = [];
|
|
589
673
|
const perFileResults = await Promise.all(
|
|
590
|
-
|
|
674
|
+
adapter.coreFilePaths.map(async (relativePath) => {
|
|
591
675
|
const newContent = applyPlaceholders(
|
|
592
|
-
await
|
|
676
|
+
await readFile5(path8.join(templateDir, adapter.templateSourcePath(relativePath)), "utf8"),
|
|
593
677
|
projectName
|
|
594
678
|
);
|
|
595
679
|
const newHash = hashContent(newContent);
|
|
596
680
|
let currentHash;
|
|
597
681
|
try {
|
|
598
|
-
currentHash = hashContent(await
|
|
682
|
+
currentHash = hashContent(await readFile5(path8.join(targetDir, relativePath), "utf8"));
|
|
599
683
|
} catch {
|
|
600
684
|
currentHash = void 0;
|
|
601
685
|
}
|
|
@@ -607,46 +691,47 @@ async function updateProject(targetDir, deps = defaultUpdateDeps) {
|
|
|
607
691
|
files.push({ path: relativePath, outcome: result.outcome });
|
|
608
692
|
newCoreFiles[relativePath] = result.value;
|
|
609
693
|
if (result.outcome === "added" || result.outcome === "replaced") {
|
|
610
|
-
fileWrites.push({ targetPath:
|
|
694
|
+
fileWrites.push({ targetPath: path8.join(targetDir, relativePath), content: newContent });
|
|
611
695
|
}
|
|
612
696
|
}
|
|
613
697
|
for (const relativePath of Object.keys(oldManifest.coreFiles)) {
|
|
614
|
-
if (
|
|
698
|
+
if (adapter.coreFilePaths.includes(relativePath)) continue;
|
|
615
699
|
try {
|
|
616
|
-
await
|
|
700
|
+
await readFile5(path8.join(targetDir, relativePath), "utf8");
|
|
617
701
|
files.push({ path: relativePath, outcome: "no-longer-core" });
|
|
618
702
|
} catch {
|
|
619
703
|
}
|
|
620
704
|
}
|
|
621
|
-
const
|
|
705
|
+
const fileMerge = adapter.mergeManifestFile(currentManifestFile, oldManifest, newTemplateManifestFile);
|
|
622
706
|
const hasFileChanges = files.some(
|
|
623
707
|
(f) => f.outcome === "added" || f.outcome === "replaced" || f.outcome === "no-longer-core"
|
|
624
708
|
);
|
|
625
|
-
const hasChanges = hasFileChanges ||
|
|
709
|
+
const hasChanges = hasFileChanges || fileMerge.changed;
|
|
626
710
|
if (!hasChanges) {
|
|
627
711
|
return {
|
|
628
712
|
status: "no-changes",
|
|
629
713
|
fromVersion,
|
|
630
714
|
toVersion,
|
|
631
715
|
files,
|
|
632
|
-
dependencies:
|
|
633
|
-
scripts:
|
|
634
|
-
fields:
|
|
716
|
+
dependencies: fileMerge.dependencies,
|
|
717
|
+
scripts: fileMerge.scripts,
|
|
718
|
+
fields: fileMerge.fields
|
|
635
719
|
};
|
|
636
720
|
}
|
|
637
721
|
for (const write of fileWrites) {
|
|
638
|
-
await mkdir2(
|
|
639
|
-
await
|
|
722
|
+
await mkdir2(path8.dirname(write.targetPath), { recursive: true });
|
|
723
|
+
await writeFile5(write.targetPath, write.content);
|
|
640
724
|
}
|
|
641
|
-
if (
|
|
642
|
-
await
|
|
725
|
+
if (fileMerge.changed) {
|
|
726
|
+
await adapter.writeManifestFile(targetDir, fileMerge.updatedFile);
|
|
643
727
|
}
|
|
644
728
|
const newManifest = {
|
|
645
729
|
generatorVersion: toVersion,
|
|
730
|
+
language,
|
|
646
731
|
coreFiles: newCoreFiles,
|
|
647
|
-
coreDependencies:
|
|
648
|
-
coreScripts:
|
|
649
|
-
coreFields:
|
|
732
|
+
coreDependencies: fileMerge.coreDependencies,
|
|
733
|
+
coreScripts: fileMerge.coreScripts,
|
|
734
|
+
coreFields: fileMerge.coreFields
|
|
650
735
|
};
|
|
651
736
|
await writeManifest(targetDir, newManifest);
|
|
652
737
|
await deps.runCommand("git", ["add", "-A"], targetDir);
|
|
@@ -656,9 +741,9 @@ async function updateProject(targetDir, deps = defaultUpdateDeps) {
|
|
|
656
741
|
fromVersion,
|
|
657
742
|
toVersion,
|
|
658
743
|
files,
|
|
659
|
-
dependencies:
|
|
660
|
-
scripts:
|
|
661
|
-
fields:
|
|
744
|
+
dependencies: fileMerge.dependencies,
|
|
745
|
+
scripts: fileMerge.scripts,
|
|
746
|
+
fields: fileMerge.fields
|
|
662
747
|
};
|
|
663
748
|
}
|
|
664
749
|
function formatUpdateSummary(result) {
|
|
@@ -689,7 +774,7 @@ function formatUpdateSummary(result) {
|
|
|
689
774
|
(o) => o.outcome !== "skipped"
|
|
690
775
|
);
|
|
691
776
|
if (fieldOutcomes.length) {
|
|
692
|
-
lines.push(`
|
|
777
|
+
lines.push(` Manifest: ${fieldOutcomes.map((o) => `${o.key} (${o.outcome})`).join(", ")}`);
|
|
693
778
|
}
|
|
694
779
|
if (result.status === "updated") {
|
|
695
780
|
lines.push('Run "clispark releasenotes" to see what changed.');
|
|
@@ -700,17 +785,28 @@ function formatUpdateSummary(result) {
|
|
|
700
785
|
// src/cli.ts
|
|
701
786
|
var program = new Command();
|
|
702
787
|
program.name("clispark").description("Interactive scaffolding tool for new CLI projects").version(getGeneratorVersion());
|
|
788
|
+
function resolvePack(language) {
|
|
789
|
+
const pack = LANGUAGE_PACKS[language];
|
|
790
|
+
if (!pack) {
|
|
791
|
+
throw new UserError(`Unknown language "${language}" \u2014 is your clispark installation out of date?`);
|
|
792
|
+
}
|
|
793
|
+
return pack;
|
|
794
|
+
}
|
|
703
795
|
program.action(
|
|
704
796
|
withLogging("scaffold", async (logger) => {
|
|
705
797
|
const answers = await runWizard();
|
|
706
|
-
const targetDir =
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
798
|
+
const targetDir = path9.join(process.cwd(), answers.projectName);
|
|
799
|
+
const pack = resolvePack(answers.language);
|
|
800
|
+
logger.info({ projectName: answers.projectName, targetDir, language: pack.id }, "scaffold started");
|
|
801
|
+
await scaffoldProject(
|
|
802
|
+
{
|
|
803
|
+
projectName: answers.projectName,
|
|
804
|
+
targetDir,
|
|
805
|
+
registryUrl: answers.registryUrl,
|
|
806
|
+
publishIntent: answers.publishIntent
|
|
807
|
+
},
|
|
808
|
+
pack
|
|
809
|
+
);
|
|
714
810
|
logger.info({ projectName: answers.projectName }, "scaffold completed");
|
|
715
811
|
console.log(`
|
|
716
812
|
Done! Your new CLI project is ready at ${targetDir}`);
|
|
@@ -719,8 +815,11 @@ Done! Your new CLI project is ready at ${targetDir}`);
|
|
|
719
815
|
program.command("update").description("Update generator-managed core files and dependencies to the latest clispark version").action(
|
|
720
816
|
withLogging("update", async (logger) => {
|
|
721
817
|
const targetDir = process.cwd();
|
|
722
|
-
|
|
723
|
-
const
|
|
818
|
+
const manifest = await requireManifest(targetDir);
|
|
819
|
+
const language = manifest.language ?? "node";
|
|
820
|
+
const pack = resolvePack(language);
|
|
821
|
+
logger.info({ targetDir, language }, "update started");
|
|
822
|
+
const result = await updateProject(targetDir, pack.updateAdapter, pack.templateDir, language);
|
|
724
823
|
logger.info({ status: result.status }, "update completed");
|
|
725
824
|
console.log(formatUpdateSummary(result));
|
|
726
825
|
})
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/wizard.ts","../src/registry.ts","../src/scaffold.ts","../src/update/manifest.ts","../src/errors.ts","../src/logger.ts","../src/update/update.ts","../src/update/reconcile.ts","../src/update/releasenotes.ts","../src/update/update-package-json.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 } from './update/manifest';\n\nconst program = new Command();\n\nprogram\n .name('clispark')\n .description('Interactive scaffolding tool for new CLI projects')\n .version(getGeneratorVersion());\n\nprogram.action(\n withLogging('scaffold', async (logger) => {\n const answers = await runWizard();\n const targetDir = path.join(process.cwd(), answers.projectName);\n\n logger.info({ projectName: answers.projectName, targetDir }, 'scaffold started');\n await scaffoldProject({\n projectName: answers.projectName,\n targetDir,\n registryUrl: answers.registryUrl,\n publishIntent: answers.publishIntent,\n });\n logger.info({ projectName: answers.projectName }, 'scaffold completed');\n\n console.log(`\\nDone! Your new CLI project is ready at ${targetDir}`);\n }),\n);\n\nprogram\n .command('update')\n .description('Update generator-managed core files and dependencies to the latest clispark version')\n .action(\n withLogging('update', async (logger) => {\n const targetDir = process.cwd();\n logger.info({ targetDir }, 'update started');\n const result = await updateProject(targetDir);\n logger.info({ status: result.status }, 'update completed');\n console.log(formatUpdateSummary(result));\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.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 { checkPackageNameAvailability, DEFAULT_REGISTRY_URL, type NameCheckResult } from './registry';\nimport type { Profile, WizardAnswers } from './types';\n\nexport interface WizardDeps {\n checkAvailability: typeof checkPackageNameAvailability;\n}\n\nconst defaultDeps: WizardDeps = {\n checkAvailability: checkPackageNameAvailability,\n};\n\nfunction exitIfCancelled(value: unknown): void {\n if (isCancel(value)) {\n cancel('Operation cancelled.');\n process.exit(1);\n }\n}\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 async function runWizard(deps: WizardDeps = defaultDeps): Promise<WizardAnswers> {\n intro('clispark — scaffold a new CLI project');\n\n const nameValue = await text({\n message: 'Project name',\n validate: 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 = DEFAULT_REGISTRY_URL;\n if (profile === 'work') {\n const registryValue = await text({\n message: 'Custom npm registry URL (leave empty for npmjs.org)',\n placeholder: DEFAULT_REGISTRY_URL,\n defaultValue: DEFAULT_REGISTRY_URL,\n });\n exitIfCancelled(registryValue);\n registryUrl = (registryValue as string) || DEFAULT_REGISTRY_URL;\n }\n\n const publishIntentValue = await select({\n message: 'Do you plan to publish this to npm?',\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 deps.checkAvailability(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: validateProjectName,\n });\n exitIfCancelled(retryValue);\n projectName = retryValue as string;\n\n nameAvailability = await deps.checkAvailability(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 { projectName, profile, registryUrl, publishIntent, nameAvailability };\n}\n","export const DEFAULT_REGISTRY_URL = 'https://registry.npmjs.org';\n\nexport type NameCheckResult = 'available' | 'taken' | 'unverified' | 'skipped';\n\nconst FETCH_TIMEOUT_MS = 5000;\n\nexport async function checkPackageNameAvailability(\n name: string,\n registryUrl: string = DEFAULT_REGISTRY_URL,\n): 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","import spawn from 'cross-spawn';\nimport { fileURLToPath } from 'node:url';\nimport path from 'node:path';\nimport { cp, readdir, readFile, rename, writeFile } from 'node:fs/promises';\nimport { DEFAULT_REGISTRY_URL } from './registry';\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\nexport const TEMPLATE_DIR = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'templates', 'base');\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\nasync function markPackageJsonPrivate(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\nexport async function copyTemplate(options: ScaffoldOptions): Promise<void> {\n const { projectName, targetDir, registryUrl, publishIntent } = options;\n\n await assertTargetDirIsUsable(targetDir);\n await cp(TEMPLATE_DIR, 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 markPackageJsonPrivate(targetDir);\n }\n\n if (registryUrl && registryUrl !== DEFAULT_REGISTRY_URL) {\n await writeFile(path.join(targetDir, '.npmrc'), `registry=${registryUrl}\\n`);\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 deps: ScaffoldDeps = defaultScaffoldDeps,\n): Promise<void> {\n await copyTemplate(options);\n\n const { targetDir } = options;\n const manifest = await buildManifest(targetDir, getGeneratorVersion());\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 await deps.runCommand('npm', ['install'], targetDir);\n await deps.runCommand('npm', ['run', 'build'], targetDir);\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';\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\n/** The base template stores .gitignore as \"gitignore\" (renamed on copy); every other core path is identical in the template and in a generated project. */\nexport function templateSourcePath(relativePath: string): string {\n return relativePath === '.gitignore' ? 'gitignore' : relativePath;\n}\n\nexport interface Manifest {\n generatorVersion: string;\n coreFiles: Record<string, string>;\n coreDependencies: Record<string, string>;\n coreScripts: Record<string, string>;\n coreFields: {\n engines: Record<string, string>;\n oclif: Record<string, unknown>;\n };\n}\n\nexport interface PackageJsonCore {\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}\n\nexport function hashContent(content: string): string {\n return createHash('sha256').update(content).digest('hex');\n}\n\nexport async function hashCoreFiles(dir: string): Promise<Record<string, string>> {\n const entries = await Promise.all(\n CORE_FILE_PATHS.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 function extractCoreFields(\n pkg: PackageJsonCore,\n): Pick<Manifest, 'coreDependencies' | 'coreScripts' | 'coreFields'> {\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\nexport async function buildManifest(targetDir: string, generatorVersion: string): Promise<Manifest> {\n const coreFiles = await hashCoreFiles(targetDir);\n const pkg = JSON.parse(await readFile(path.join(targetDir, 'package.json'), 'utf8')) as PackageJsonCore;\n const { coreDependencies, coreScripts, coreFields } = extractCoreFields(pkg);\n return { generatorVersion, 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, TEMPLATE_DIR } from '../scaffold';\nimport {\n CORE_FILE_PATHS,\n getGeneratorVersion,\n hashContent,\n requireManifest,\n templateSourcePath,\n writeManifest,\n type Manifest,\n} from './manifest';\nimport { reconcileEntry, stringEquals } from './reconcile';\nimport { UserError } from '../errors';\nimport { compareVersions } from './releasenotes';\nimport { mergePackageJson, type FieldOutcome, type PackageJsonShape } from './update-package-json';\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(targetDir: string, deps: UpdateDeps = defaultUpdateDeps): 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 currentPkg = JSON.parse(await readFile(path.join(targetDir, 'package.json'), 'utf8')) as PackageJsonShape;\n const projectName = currentPkg.name;\n\n const newTemplatePkg = JSON.parse(\n applyPlaceholders(await readFile(path.join(TEMPLATE_DIR, 'package.json'), 'utf8'), projectName),\n ) as PackageJsonShape;\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 CORE_FILE_PATHS\n // order below so files/fileWrites stay deterministic regardless of I/O timing.\n const perFileResults = await Promise.all(\n CORE_FILE_PATHS.map(async (relativePath) => {\n const newContent = applyPlaceholders(\n await readFile(path.join(TEMPLATE_DIR, 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 ((CORE_FILE_PATHS as readonly string[]).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 pkgMerge = mergePackageJson(currentPkg, oldManifest, newTemplatePkg);\n\n const hasFileChanges = files.some(\n (f) => f.outcome === 'added' || f.outcome === 'replaced' || f.outcome === 'no-longer-core',\n );\n const hasChanges = hasFileChanges || pkgMerge.changed;\n\n if (!hasChanges) {\n return {\n status: 'no-changes',\n fromVersion,\n toVersion,\n files,\n dependencies: pkgMerge.dependencies,\n scripts: pkgMerge.scripts,\n fields: pkgMerge.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 (pkgMerge.changed) {\n await writeFile(path.join(targetDir, 'package.json'), JSON.stringify(pkgMerge.updatedPkg, null, 2) + '\\n');\n }\n\n const newManifest: Manifest = {\n generatorVersion: toVersion,\n coreFiles: newCoreFiles,\n coreDependencies: pkgMerge.coreDependencies,\n coreScripts: pkgMerge.coreScripts,\n coreFields: pkgMerge.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: pkgMerge.dependencies,\n scripts: pkgMerge.scripts,\n fields: pkgMerge.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(` package.json: ${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","export type ReconcileOutcome = 'added' | 'replaced' | 'skipped';\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/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","import { CORE_SCRIPT_NAMES, type Manifest } from './manifest';\nimport { deepEquals, reconcileEntry, stringEquals, type ReconcileOutcome } from './reconcile';\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\nexport interface FieldOutcome {\n key: string;\n outcome: ReconcileOutcome;\n}\n\nexport interface PackageJsonMergeResult {\n updatedPkg: PackageJsonShape;\n changed: boolean;\n dependencies: FieldOutcome[];\n scripts: FieldOutcome[];\n fields: FieldOutcome[];\n coreDependencies: Record<string, string>;\n coreScripts: Record<string, string>;\n coreFields: Manifest['coreFields'];\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\nexport function mergePackageJson(\n currentPkg: PackageJsonShape,\n oldManifest: Manifest,\n newTemplatePkg: PackageJsonShape,\n): PackageJsonMergeResult {\n const updatedPkg: 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 updatedPkg[section] = { ...updatedPkg[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 updatedPkg.scripts = { ...updatedPkg.scripts, [name]: result.value };\n }\n }\n\n const fields: FieldOutcome[] = [];\n let enginesValue = oldManifest.coreFields.engines;\n let oclifValue = oldManifest.coreFields.oclif;\n\n if (newTemplatePkg.engines !== undefined) {\n const enginesResult = reconcileEntry(\n currentPkg.engines,\n oldManifest.coreFields.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 updatedPkg.engines = enginesResult.value;\n }\n }\n\n if (newTemplatePkg.oclif !== undefined) {\n const oclifResult = reconcileEntry(\n currentPkg.oclif,\n oldManifest.coreFields.oclif,\n newTemplatePkg.oclif,\n deepEquals,\n );\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 updatedPkg.oclif = oclifResult.value;\n }\n }\n\n return {\n updatedPkg,\n changed,\n dependencies,\n scripts,\n fields,\n coreDependencies,\n coreScripts,\n coreFields: { engines: enginesValue, oclif: oclifValue },\n };\n}\n"],"mappings":"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","names":["path","fileURLToPath","path","readFile","writeFile","path","fileURLToPath","readFile","writeFile","path","mkdir","readFile","writeFile","path","spawn","FETCH_TIMEOUT_MS","defaultRunCommand","spawn","readFile","path","mkdir","writeFile","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/index.ts","../src/scaffold.ts","../src/update/manifest.ts","../src/errors.ts","../src/logger.ts","../src/update/update.ts","../src/update/releasenotes.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';\n\nconst program = new Command();\n\nprogram\n .name('clispark')\n .description('Interactive scaffolding tool for new CLI projects')\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(\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 }),\n);\n\nprogram\n .command('update')\n .description('Update generator-managed core files and dependencies to the latest clispark version')\n .action(\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 }),\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.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 },\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\nexport const npmRegistryChecker: RegistryChecker = {\n checkNameAvailability,\n applyPrivateIntent,\n};\n","// src/languages/index.ts\nimport type { LanguagePack } from './pack';\nimport { nodeOclifPack } from './packs/node-oclif';\n\nexport const LANGUAGE_PACKS: Record<string, LanguagePack> = {\n [nodeOclifPack.id]: nodeOclifPack,\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 writeFile(path.join(targetDir, '.npmrc'), `registry=${registryUrl}\\n`);\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"],"mappings":"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","names":["path","path","path","path","readFile","writeFile","path","path","pack","readFile","writeFile","path","existsSync","readFileSync","readFile","writeFile","path","fileURLToPath","readFile","path","writeFile","fileURLToPath","existsSync","readFileSync","path","readFile","writeFile","path","mkdir","readFile","writeFile","path","spawn","FETCH_TIMEOUT_MS","defaultRunCommand","spawn","readFile","path","mkdir","writeFile","path"]}
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|