@afoures/auto-release 0.2.11 → 0.3.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.
@@ -7,19 +7,21 @@ import { access, mkdir, readFile, writeFile } from "node:fs/promises";
7
7
 
8
8
  //#region src/lib/commands/init.ts
9
9
  function generate_config_source(options) {
10
- const { apps, changes_dir, target_branch, default_release_branch_prefix, git } = options;
10
+ const { projects, changes_dir, target_branch, default_release_branch_prefix = "release", git } = options;
11
11
  const imports = ["import { define_config } from \"@afoures/auto-release\";"];
12
- const component_types = /* @__PURE__ */ new Set();
13
- for (const app of apps) for (const component of app.components) component_types.add(component.type);
14
- if (component_types.size > 0) {
15
- const components = Array.from(component_types).sort();
16
- imports.push(`import { ${components.join(", ")} } from "@afoures/auto-release/components";`);
17
- }
18
- const versioning_types = /* @__PURE__ */ new Set();
19
- for (const app of apps) versioning_types.add(app.versioning);
20
- if (versioning_types.size > 0) {
21
- const versioning = Array.from(versioning_types).sort();
22
- imports.push(`import { ${versioning.join(", ")} } from "@afoures/auto-release/versioning";`);
12
+ if (projects.length > 0) {
13
+ const component_types = /* @__PURE__ */ new Set();
14
+ for (const project of projects) for (const component of project.components) component_types.add(component.type);
15
+ if (component_types.size > 0) {
16
+ const components = Array.from(component_types).sort();
17
+ imports.push(`import { ${components.join(", ")} } from "@afoures/auto-release/components";`);
18
+ }
19
+ const versioning_types = /* @__PURE__ */ new Set();
20
+ for (const project of projects) versioning_types.add(project.versioning);
21
+ if (versioning_types.size > 0) {
22
+ const versioning = Array.from(versioning_types).sort();
23
+ imports.push(`import { ${versioning.join(", ")} } from "@afoures/auto-release/versioning";`);
24
+ }
23
25
  }
24
26
  if (git.platform === "github") imports.push("import { github } from \"@afoures/auto-release/platforms\";");
25
27
  else imports.push("import { gitlab } from \"@afoures/auto-release/platforms\";");
@@ -29,31 +31,31 @@ function generate_config_source(options) {
29
31
  "export default define_config({"
30
32
  ];
31
33
  if (changes_dir !== ".changes") lines.push(` changes_dir: ${JSON.stringify(changes_dir)},`);
32
- lines.push(" apps: {");
33
- apps.forEach((app, index) => {
34
- lines.push(` ${JSON.stringify(app.name)}: {`);
34
+ lines.push(" projects: {");
35
+ projects.forEach((project, index) => {
36
+ lines.push(` ${JSON.stringify(project.name)}: {`);
35
37
  lines.push(" components: [");
36
- app.components.forEach((component) => {
38
+ project.components.forEach((component) => {
37
39
  lines.push(` ${component.type}(${JSON.stringify(component.path)}),`);
38
40
  });
39
41
  lines.push(" ],");
40
- lines.push(` versioning: ${app.versioning}(),`);
41
- lines.push(` changelog: ${JSON.stringify(app.changelog_path)},`);
42
- lines.push(index === apps.length - 1 ? " }," : " },");
42
+ lines.push(` versioning: ${project.versioning}(),`);
43
+ lines.push(` changelog: ${JSON.stringify(project.changelog_path)},`);
44
+ lines.push(index === projects.length - 1 ? " }," : " },");
43
45
  });
44
46
  lines.push(" },");
45
47
  lines.push(" git: {");
46
48
  if (git.platform === "github") {
47
49
  lines.push(" platform: github({");
48
- lines.push(` token: process.env.${git.token_env}!,`);
49
50
  lines.push(` owner: ${JSON.stringify(git.owner)},`);
50
51
  lines.push(` repo: ${JSON.stringify(git.repo)},`);
52
+ lines.push(` token: undefined,`);
51
53
  lines.push(" }),");
52
54
  } else {
53
55
  lines.push(" platform: gitlab({");
54
- lines.push(` token: process.env.${git.token_env}!,`);
55
56
  lines.push(` project_id: ${JSON.stringify(git.project_id)},`);
56
57
  if (git.host) lines.push(` host: ${JSON.stringify(git.host)},`);
58
+ lines.push(` token: undefined,`);
57
59
  lines.push(" }),");
58
60
  }
59
61
  if (target_branch !== "main") lines.push(` target_branch: ${JSON.stringify(target_branch)},`);
@@ -68,9 +70,6 @@ const PACKAGE_MANAGER_LOCKS = {
68
70
  yarn: ["yarn.lock"],
69
71
  bun: ["bun.lockb", "bun.lock"]
70
72
  };
71
- function normalize_app_name(input) {
72
- return input.trim().toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-{2,}/g, "-").replace(/^-|-$/g, "") || "app";
73
- }
74
73
  async function path_exists(target) {
75
74
  try {
76
75
  await access(target, constants.F_OK);
@@ -94,6 +93,14 @@ function get_install_command(package_manager) {
94
93
  default: return "npm install --save-dev @afoures/auto-release";
95
94
  }
96
95
  }
96
+ function get_exec_list_command(package_manager) {
97
+ switch (package_manager) {
98
+ case "pnpm": return "pnpm exec auto-release list";
99
+ case "yarn": return "yarn exec auto-release list";
100
+ case "bun": return "bunx auto-release list";
101
+ default: return "npx auto-release list";
102
+ }
103
+ }
97
104
  async function ensure_package_json(path) {
98
105
  if (await path_exists(path)) {
99
106
  const content = await readFile(path, "utf-8");
@@ -108,21 +115,6 @@ async function ensure_package_json(path) {
108
115
  log.info(`Created package.json for ${template.name}`);
109
116
  return template;
110
117
  }
111
- async function create_changes_directories(cwd, changes_dir, apps) {
112
- const root_dir = join(cwd, changes_dir);
113
- await mkdir(root_dir, { recursive: true });
114
- for (const app of apps) await mkdir(join(root_dir, app.name), { recursive: true });
115
- }
116
- async function ensure_changelog(app, cwd) {
117
- const absolute_path = join(cwd, app.changelog_path);
118
- await mkdir(dirname(absolute_path), { recursive: true });
119
- if (!await path_exists(absolute_path)) await writeFile(absolute_path, `# ${app.name} changelog\n\nAll notable changes to this project will be documented in this file.\n`, "utf-8");
120
- }
121
- function sanitize_env_var(value, fallback) {
122
- const trimmed = value.trim();
123
- if (!trimmed) return fallback;
124
- return trimmed.replace(/[^a-zA-Z0-9_]/g, "_").toUpperCase();
125
- }
126
118
  const init = create_command({
127
119
  name: "init",
128
120
  description: "Set up auto-release in the current repository",
@@ -185,16 +177,6 @@ const init = create_command({
185
177
  return { status: "success" };
186
178
  }
187
179
  const changes_dir = changes_dir_input.trim();
188
- const release_prefix_input = await text({
189
- message: "Release branch prefix",
190
- initialValue: "release",
191
- validate: (value = "") => value.trim().length === 0 ? "Release branch prefix cannot be empty" : void 0
192
- });
193
- if (isCancel(release_prefix_input)) {
194
- cancel("Initialization cancelled");
195
- return { status: "success" };
196
- }
197
- const default_release_branch_prefix = release_prefix_input.trim();
198
180
  const target_branch_input = await text({
199
181
  message: "Target branch (main branch for PRs)",
200
182
  initialValue: "main",
@@ -205,128 +187,6 @@ const init = create_command({
205
187
  return { status: "success" };
206
188
  }
207
189
  const target_branch = target_branch_input.trim();
208
- const app_count_input = await text({
209
- message: "How many apps should auto-release manage?",
210
- initialValue: "1",
211
- validate: (value = "") => {
212
- const parsed = Number.parseInt(value, 10);
213
- return Number.isNaN(parsed) || parsed <= 0 ? "Enter a positive number" : void 0;
214
- }
215
- });
216
- if (isCancel(app_count_input)) {
217
- cancel("Initialization cancelled");
218
- return { status: "success" };
219
- }
220
- const app_count = Number.parseInt(app_count_input, 10);
221
- const apps = [];
222
- for (let index = 0; index < app_count; index++) {
223
- const default_name = index === 0 && package_json.name ? normalize_app_name(package_json.name) : `app-${index + 1}`;
224
- const app_name_input = await text({
225
- message: `App #${index + 1} name (lowercase, no spaces)`,
226
- initialValue: default_name,
227
- validate: (value = "") => value.trim().length === 0 ? "App name is required" : void 0
228
- });
229
- if (isCancel(app_name_input)) {
230
- cancel("Initialization cancelled");
231
- return { status: "success" };
232
- }
233
- const app_name = normalize_app_name(app_name_input);
234
- const component_count_input = await text({
235
- message: `How many components for ${app_name}?`,
236
- initialValue: "1",
237
- validate: (value = "") => {
238
- const parsed = Number.parseInt(value, 10);
239
- return Number.isNaN(parsed) || parsed <= 0 ? "Enter a positive number" : void 0;
240
- }
241
- });
242
- if (isCancel(component_count_input)) {
243
- cancel("Initialization cancelled");
244
- return { status: "success" };
245
- }
246
- const component_count = Number.parseInt(component_count_input, 10);
247
- const components = [];
248
- for (let comp_index = 0; comp_index < component_count; comp_index++) {
249
- const component_type_choice = await select({
250
- message: `Component #${comp_index + 1} type for ${app_name}`,
251
- options: [
252
- {
253
- value: "node",
254
- label: "Node (package.json)"
255
- },
256
- {
257
- value: "bun",
258
- label: "Bun (package.json)"
259
- },
260
- {
261
- value: "expo",
262
- label: "Expo (package.json + app.json)"
263
- },
264
- {
265
- value: "php",
266
- label: "PHP (composer.json)"
267
- }
268
- ]
269
- });
270
- if (isCancel(component_type_choice)) {
271
- cancel("Initialization cancelled");
272
- return { status: "success" };
273
- }
274
- const component_type = component_type_choice;
275
- const default_path = app_count === 1 && component_count === 1 ? "." : `apps/${app_name}`;
276
- const component_path_input = await text({
277
- message: `Component #${comp_index + 1} path for ${app_name}`,
278
- initialValue: default_path,
279
- validate: (value = "") => value.trim().length === 0 ? "Component path is required" : void 0
280
- });
281
- if (isCancel(component_path_input)) {
282
- cancel("Initialization cancelled");
283
- return { status: "success" };
284
- }
285
- const component_path = component_path_input.trim();
286
- components.push({
287
- type: component_type,
288
- path: component_path
289
- });
290
- }
291
- const changelog_input = await text({
292
- message: `Changelog path for ${app_name}`,
293
- initialValue: app_count === 1 ? "CHANGELOG.md" : `apps/${app_name}/CHANGELOG.md`,
294
- validate: (value = "") => value.trim().length === 0 ? "Changelog path is required" : void 0
295
- });
296
- if (isCancel(changelog_input)) {
297
- cancel("Initialization cancelled");
298
- return { status: "success" };
299
- }
300
- const changelog_path = changelog_input.trim();
301
- const version_choice = await select({
302
- message: `Versioning strategy for ${app_name}`,
303
- initialValue: "semver",
304
- options: [
305
- {
306
- value: "semver",
307
- label: "Semver (1.2.3) - major, minor, patch"
308
- },
309
- {
310
- value: "calver",
311
- label: "Calver (YYYY.MM.micro) - feature, fix"
312
- },
313
- {
314
- value: "markver",
315
- label: "Markver (1.0.0) - marketing, feature, fix"
316
- }
317
- ]
318
- });
319
- if (isCancel(version_choice)) {
320
- cancel("Initialization cancelled");
321
- return { status: "success" };
322
- }
323
- apps.push({
324
- name: app_name,
325
- components,
326
- changelog_path,
327
- versioning: version_choice
328
- });
329
- }
330
190
  const git_choice = await select({
331
191
  message: "Which git platform do you use?",
332
192
  options: [{
@@ -354,26 +214,17 @@ const init = create_command({
354
214
  }
355
215
  const repo_input = await text({
356
216
  message: "GitHub repository name",
357
- initialValue: package_json.name ? package_json.name.replace(/^@[^/]+\//, "") : apps[0]?.name || "",
217
+ initialValue: package_json.name ? package_json.name.replace(/^@[^/]+\//, "") : "",
358
218
  validate: (value = "") => value.trim().length === 0 ? "Repository is required" : void 0
359
219
  });
360
220
  if (isCancel(repo_input)) {
361
221
  cancel("Initialization cancelled");
362
222
  return { status: "success" };
363
223
  }
364
- const token_env_input = await text({
365
- message: "Environment variable for the GitHub token",
366
- initialValue: "GITHUB_TOKEN"
367
- });
368
- if (isCancel(token_env_input)) {
369
- cancel("Initialization cancelled");
370
- return { status: "success" };
371
- }
372
224
  git_answers = {
373
225
  platform: "github",
374
226
  owner: owner_input.trim(),
375
- repo: repo_input.trim(),
376
- token_env: sanitize_env_var(token_env_input, "GITHUB_TOKEN")
227
+ repo: repo_input.trim()
377
228
  };
378
229
  } else {
379
230
  const project_input = await text({
@@ -392,19 +243,10 @@ const init = create_command({
392
243
  cancel("Initialization cancelled");
393
244
  return { status: "success" };
394
245
  }
395
- const token_env_input = await text({
396
- message: "Environment variable for the GitLab token",
397
- initialValue: "GITLAB_TOKEN"
398
- });
399
- if (isCancel(token_env_input)) {
400
- cancel("Initialization cancelled");
401
- return { status: "success" };
402
- }
403
246
  git_answers = {
404
247
  platform: "gitlab",
405
248
  project_id: project_input.trim(),
406
- host: host_input.trim() || void 0,
407
- token_env: sanitize_env_var(token_env_input, "GITLAB_TOKEN")
249
+ host: host_input.trim() || void 0
408
250
  };
409
251
  }
410
252
  const config_path = join(context.cwd, "auto-release.config.ts");
@@ -424,19 +266,18 @@ const init = create_command({
424
266
  }
425
267
  }
426
268
  await writeFile(config_path, generate_config_source({
427
- apps,
269
+ projects: [],
428
270
  changes_dir,
429
271
  target_branch,
430
- default_release_branch_prefix,
431
272
  git: git_answers
432
273
  }), "utf-8");
433
- await create_changes_directories(context.cwd, changes_dir, apps);
434
- for (const app of apps) await ensure_changelog(app, context.cwd);
274
+ await mkdir(join(context.cwd, changes_dir), { recursive: true });
435
275
  log.success("Generated auto-release.config.ts");
436
276
  log.success(`Change files directory: ${changes_dir}`);
437
- apps.forEach((app) => {
438
- log.success(`App ${app.name} ready with ${app.components.length} component(s)`);
439
- });
277
+ log.message("");
278
+ log.message("Next: add projects to auto-release.config.ts");
279
+ log.message(" Edit the `projects` object and add entries with components, versioning, and changelog path.");
280
+ log.message(` Then run \`${get_exec_list_command(package_manager)}\` to verify.`);
440
281
  outro("auto-release init complete!");
441
282
  return {
442
283
  status: "success",
@@ -8,7 +8,7 @@ import { relative } from "node:path";
8
8
  //#region src/lib/commands/list.ts
9
9
  const list = create_command({
10
10
  name: "list",
11
- description: "List all registered apps with their current version and registered components",
11
+ description: "List all registered projects with their current version and registered components",
12
12
  schema: { config: {
13
13
  type: "string",
14
14
  description: "Path to config file",
@@ -26,25 +26,25 @@ const list = create_command({
26
26
  },
27
27
  run: async ({ context: { config, root } }) => {
28
28
  const logger = create_logger();
29
- if (config.managed_applications.length === 0) {
30
- logger.info("no applications registered.");
29
+ if (config.managed_projects.length === 0) {
30
+ logger.info("no projects registered.");
31
31
  return { status: "success" };
32
32
  }
33
- const count = config.managed_applications.length;
33
+ const count = config.managed_projects.length;
34
34
  const warnings = [];
35
- logger.info(`found ${count} application${count > 1 ? "s" : ""}:`);
35
+ logger.info(`found ${count} project${count > 1 ? "s" : ""}:`);
36
36
  logger.info("");
37
- for (const app of config.managed_applications) {
38
- const version = await compute_current_version(app, { get_file_content: (file_path) => read_file(file_path) });
37
+ for (const project of config.managed_projects) {
38
+ const version = await compute_current_version(project, { get_file_content: (file_path) => read_file(file_path) });
39
39
  if (version === null) {
40
- warnings.push(`${app.name} has no version`);
40
+ warnings.push(`${project.name} has no version`);
41
41
  continue;
42
42
  }
43
- const parts = app.components.flatMap((component) => component.parts.map((part) => ({
43
+ const parts = project.components.flatMap((component) => component.parts.map((part) => ({
44
44
  relative_path: relative(root, part.file),
45
45
  missing: part.exists === false
46
46
  })));
47
- logger.note(`${app.name} (${version})`, parts.map((part) => `./${part.relative_path} ${part.missing ? "⚠️ missing" : ""}`).join("\n"));
47
+ logger.note(`${project.name} (${version})`, parts.map((part) => `./${part.relative_path} ${part.missing ? "⚠️ missing" : ""}`).join("\n"));
48
48
  logger.info("");
49
49
  }
50
50
  return {
@@ -57,15 +57,15 @@ const manual_release = create_command({
57
57
  error: "Not on a branch (detached HEAD). Please checkout a branch first."
58
58
  };
59
59
  log.info(`Current branch: ${current_branch}`);
60
- const app_names = config.managed_applications.map((app$1) => app$1.name);
61
- let app_name;
62
- if (app_names.length === 1) {
63
- app_name = app_names[0];
64
- log.success(`Defaulting to app: ${app_name}`);
60
+ const project_names = config.managed_projects.map((project$1) => project$1.name);
61
+ let project_name;
62
+ if (project_names.length === 1) {
63
+ project_name = project_names[0];
64
+ log.success(`Defaulting to project: ${project_name}`);
65
65
  } else {
66
66
  const selected = await select({
67
- message: "Select app to release:",
68
- options: app_names.map((name) => ({
67
+ message: "Select a project to release",
68
+ options: project_names.map((name) => ({
69
69
  value: name,
70
70
  label: name
71
71
  }))
@@ -74,28 +74,47 @@ const manual_release = create_command({
74
74
  cancel("Manual release cancelled");
75
75
  return { status: "success" };
76
76
  }
77
- app_name = selected;
77
+ project_name = selected;
78
78
  }
79
- const app = config.managed_applications.find((item) => item.name === app_name);
80
- if (!app) return {
79
+ const project = config.managed_projects.find((item) => item.name === project_name);
80
+ if (!project) return {
81
81
  status: "error",
82
- error: `App "${app_name}" not found in config`
82
+ error: `Project "${project_name}" not found in config`
83
83
  };
84
- const changes = await find_change_files(join(config.changes_dir, app_name), { allowed_kinds: app.versioning.allowed_changes });
84
+ const changes = await find_change_files(join(config.changes_dir, project_name), { allowed_kinds: project.versioning.allowed_changes });
85
85
  if (changes.warnings.length > 0) for (const warning of changes.warnings) log.warn(warning);
86
86
  log.success(`Found ${changes.list.length} change file(s)`);
87
- const current_version = await compute_current_version(app, { get_file_content: (file_path) => read_file(file_path) }) ?? app.versioning.initial_version;
87
+ const current_version = await compute_current_version(project, { get_file_content: (file_path) => read_file(file_path) }) ?? project.versioning.initial_version;
88
88
  log.info(`Current version: ${current_version}`);
89
- const next_version = app.versioning.bump({
89
+ const next_version_candidate = project.versioning.bump({
90
90
  version: current_version,
91
91
  changes: changes.list,
92
92
  date: /* @__PURE__ */ new Date()
93
93
  });
94
- log.info(`Next version will be: ${next_version}`);
94
+ log.info(`Next version will be: ${next_version_candidate}`);
95
+ const version_input = await text({
96
+ message: `Enter version [or press Enter to use ${next_version_candidate}]:`,
97
+ placeholder: next_version_candidate,
98
+ validate: (value = "") => {
99
+ const trimmed = value.trim();
100
+ if (trimmed.length === 0) return;
101
+ if (!project.versioning.validate({ version: trimmed })) return `Invalid version format. Expected format compatible with ${project.versioning.allowed_changes.join(", ")}`;
102
+ }
103
+ });
104
+ if (isCancel(version_input)) {
105
+ cancel("Manual release cancelled");
106
+ return { status: "success" };
107
+ }
108
+ const next_version = version_input.trim() || next_version_candidate;
109
+ log.info(`Using version: ${next_version}`);
110
+ const proposed_tag = config.git.tag_generator({
111
+ project: { name: project.name },
112
+ version: next_version
113
+ });
95
114
  const tag_input = await text({
96
115
  message: "Enter tag name:",
97
- placeholder: `${app_name}@${next_version}`,
98
- initialValue: `${app_name}@${next_version}`,
116
+ placeholder: proposed_tag,
117
+ initialValue: proposed_tag,
99
118
  validate: (value = "") => {
100
119
  if (value.trim().length === 0) return "Tag name is required";
101
120
  }
@@ -126,14 +145,14 @@ const manual_release = create_command({
126
145
  log.warn(`Could not check remote tag existence: ${error.message}`);
127
146
  log.warn("Continuing with local tag check only...");
128
147
  }
129
- const changes_summary = changes.list.map((change) => ` ${change.summary.split("\n").join("\n ")}`).join("\n");
148
+ const changes_summary = changes.list.map((change) => ` ${change.summary.split("\n").join("\n ")}`).join("\n");
130
149
  note(`Manual release plan:
131
- - App: ${app_name}
132
- - Current version: ${current_version}
133
- - Next version: ${next_version}
134
- - Tag: ${tag}
135
- - Change files:
136
- ${changes_summary}`, "Release details");
150
+ - Project: ${project_name}
151
+ - Current version: ${current_version}
152
+ - Next version: ${next_version}
153
+ - Tag: ${tag}
154
+ - Change files:
155
+ ${changes_summary || " No changes in this release."}`, "Release details");
137
156
  const proceed_confirmation = await confirm({
138
157
  message: "Proceed with generating changelog and version bump?",
139
158
  initialValue: false
@@ -143,11 +162,11 @@ ${changes_summary}`, "Release details");
143
162
  return { status: "success" };
144
163
  }
145
164
  const files_to_stage = [];
146
- const changes_dir = join(config.changes_dir, app_name);
165
+ const changes_dir = join(config.changes_dir, project_name);
147
166
  const deleted_change_files = await delete_all_files_from_folder(changes_dir);
148
167
  files_to_stage.push(...deleted_change_files);
149
168
  log.success(`Deleted ${deleted_change_files.length} change file(s)`);
150
- for (const component of app.components) for (const part of component.parts) {
169
+ for (const component of project.components) for (const part of component.parts) {
151
170
  const initial_content = await read_file(part.file);
152
171
  if (initial_content === null) continue;
153
172
  const updated_content = part.update_version(initial_content, next_version);
@@ -155,8 +174,8 @@ ${changes_summary}`, "Release details");
155
174
  files_to_stage.push(part.file);
156
175
  }
157
176
  log.success("Updated component versions");
158
- const formatter = app.versioning.formatter;
159
- const initial_changelog_content = await read_file(app.changelog);
177
+ const formatter = project.versioning.formatter;
178
+ const initial_changelog_content = await read_file(project.changelog);
160
179
  const changelog_as_mdast = parse_markdown(initial_changelog_content ?? "");
161
180
  const changelog = formatter.transform_markdown(changelog_as_mdast, initial_changelog_content ?? "");
162
181
  const updated_changelog_content = formatter.format_changelog({
@@ -164,15 +183,15 @@ ${changes_summary}`, "Release details");
164
183
  releases: [{
165
184
  version: next_version,
166
185
  changes: changes.list
167
- }, ...changelog.releases.filter((release) => release.version !== next_version)].sort((a, b) => app.versioning.compare(b.version, a.version))
168
- }, { app: { name: app_name } });
169
- await write_file(app.changelog, updated_changelog_content);
170
- files_to_stage.push(app.changelog);
186
+ }, ...changelog.releases.filter((release) => release.version !== next_version)].sort((a, b) => project.versioning.compare(b.version, a.version))
187
+ }, { project: { name: project_name } });
188
+ await write_file(project.changelog, updated_changelog_content);
189
+ files_to_stage.push(project.changelog);
171
190
  log.success("Updated changelog");
172
191
  const commit_message_input = await text({
173
192
  message: "Enter commit message:",
174
- placeholder: `release: ${app_name}@${next_version}`,
175
- initialValue: `release: ${app_name}@${next_version}`,
193
+ placeholder: `release: ${project_name}@${next_version}`,
194
+ initialValue: `release: ${project_name}@${next_version}`,
176
195
  validate: (value = "") => {
177
196
  if (value.trim().length === 0) return "Commit message is required";
178
197
  }
@@ -188,7 +207,7 @@ ${changes_summary}`, "Release details");
188
207
  if (diff) note(diff, "Changes to be committed");
189
208
  const confirm_commit = await confirm({
190
209
  message: "Review the changes above. Proceed with commit?",
191
- initialValue: true
210
+ initialValue: false
192
211
  });
193
212
  if (isCancel(confirm_commit) || !confirm_commit) {
194
213
  await reset(root);
@@ -67,9 +67,9 @@ const record_change = create_command({
67
67
  name: "record-change",
68
68
  description: "Record a new change",
69
69
  schema: {
70
- app: {
70
+ project: {
71
71
  type: "string",
72
- description: "App name"
72
+ description: "Project name"
73
73
  },
74
74
  type: {
75
75
  type: "string",
@@ -93,40 +93,40 @@ const record_change = create_command({
93
93
  run: async ({ args, context }) => {
94
94
  intro(`record a new change`);
95
95
  const config = context.config;
96
- let app_name = args.app;
97
- if (!app_name) {
98
- const app_names = config.managed_applications.map((app$1) => app$1.name);
99
- if (app_names.length === 1) {
100
- app_name = app_names[0];
101
- log.success(`Defaulting to app: ${app_name}`);
96
+ let project_name = args.project;
97
+ if (!project_name) {
98
+ const project_names = config.managed_projects.map((project$1) => project$1.name);
99
+ if (project_names.length === 1) {
100
+ project_name = project_names[0];
101
+ log.success(`Defaulting to project: ${project_name}`);
102
102
  } else {
103
103
  const selected = await select({
104
- message: "Select app:",
105
- options: app_names.map((name) => ({
104
+ message: "Select project:",
105
+ options: project_names.map((name) => ({
106
106
  value: name,
107
107
  label: name
108
108
  }))
109
109
  });
110
110
  if (isCancel(selected)) {
111
- cancel("App selection cancelled");
111
+ cancel("Project selection cancelled");
112
112
  return { status: "success" };
113
113
  }
114
- app_name = selected;
114
+ project_name = selected;
115
115
  }
116
116
  }
117
- const app = config.managed_applications.find((item) => item.name === app_name);
118
- if (!app) return {
117
+ const project = config.managed_projects.find((item) => item.name === project_name);
118
+ if (!project) return {
119
119
  status: "error",
120
- error: `App "${app_name}" not found in config`
120
+ error: `Project "${project_name}" not found in config`
121
121
  };
122
- const valid_types = Array.from(app.versioning.allowed_changes);
122
+ const valid_types = Array.from(project.versioning.allowed_changes);
123
123
  let change_type = args.type;
124
124
  if (!change_type) {
125
125
  const selected = await select({
126
126
  message: "Select change type:",
127
127
  options: valid_types.map((t) => ({
128
128
  value: t,
129
- label: app.versioning.display_map[t]?.singular ?? t
129
+ label: project.versioning.display_map[t]?.singular ?? t
130
130
  }))
131
131
  });
132
132
  if (isCancel(selected)) {
@@ -137,7 +137,7 @@ const record_change = create_command({
137
137
  }
138
138
  if (!valid_types.includes(change_type)) return {
139
139
  status: "error",
140
- error: `Invalid change type "${change_type}". Valid types for ${app_name}: ${valid_types.join(", ")}`
140
+ error: `Invalid change type "${change_type}". Valid types for ${project_name}: ${valid_types.join(", ")}`
141
141
  };
142
142
  const initial_slug = humanId({
143
143
  separator: "-",
@@ -155,7 +155,7 @@ const record_change = create_command({
155
155
  summary: ""
156
156
  });
157
157
  try {
158
- const file_path = await save_change_file(change_file, join(config.changes_dir, app_name));
158
+ const file_path = await save_change_file(change_file, join(config.changes_dir, project_name));
159
159
  const editor = await get_editor(config.changes_dir);
160
160
  if (!editor) return {
161
161
  status: "error",