maiass 5.14.2 → 5.15.3
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/README.md +8 -3
- package/lib/account-info.js +1 -1
- package/lib/bootstrap.js +4 -0
- package/lib/commit.js +24 -6
- package/lib/config-command.js +1 -1
- package/lib/config-manager.js +1 -1
- package/lib/maiass-command.js +6 -3
- package/lib/maiass-pipeline.js +307 -71
- package/lib/maiass-variables.js +5 -2
- package/lib/version-manager.js +33 -4
- package/maiass.mjs +48 -22
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
Run `maiass` in any git repo and it
|
|
13
|
+
Run `maiass` in any git repo and it commits your staged changes, writes the commit message, bumps the version, updates the changelog, and merges the branch. It's for developers who do this routine every day and want the keystrokes back. Anonymous on first run — no email, no card, no sign-up.
|
|
14
|
+
|
|
15
|
+
By default MAIASS only ever commits changes you have already staged — it leaves unstaged and untracked files alone. To have it stage everything for you, either answer the interactive prompt, pass `--auto-stage` for a single run, or set `MAIASS_AUTO_STAGE_UNSTAGED=true` to make it the default.
|
|
14
16
|
|
|
15
17
|
> Site: [maiass.net](https://maiass.net) · Bash/Homebrew source: [bashmaiass](https://github.com/vsmash/bashmaiass)
|
|
16
18
|
|
|
@@ -47,8 +49,11 @@ maiass
|
|
|
47
49
|
maiass minor # 1.2.3 → 1.3.0
|
|
48
50
|
maiass major # 1.2.3 → 2.0.0
|
|
49
51
|
|
|
50
|
-
#
|
|
51
|
-
maiass --commits-only
|
|
52
|
+
# Interactive commit-only, skip version management
|
|
53
|
+
maiass --commits-only # short: -c or -co
|
|
54
|
+
|
|
55
|
+
# Unattended commit-only — commit STAGED changes, push, then stop (no merge, no bump)
|
|
56
|
+
maiass --unattended-commit # short: -uc (interactive sibling: -co / --commits-only)
|
|
52
57
|
|
|
53
58
|
# Preview without making changes
|
|
54
59
|
maiass --dry-run patch
|
package/lib/account-info.js
CHANGED
|
@@ -444,7 +444,7 @@ export async function handleAccountInfoCommand(options = {}) {
|
|
|
444
444
|
console.log('Explanation: Your token was rejected. Ensure it is correct, not expired, and associated with an active subscription.');
|
|
445
445
|
} else if (result.status === 401 || statusField === 401) {
|
|
446
446
|
console.log('Status: 401 Unauthorized');
|
|
447
|
-
console.log('Explanation: Missing or invalid credentials. Try updating your token with \'
|
|
447
|
+
console.log('Explanation: Missing or invalid credentials. Try updating your token with \'maiass config --global maiass_token=your_token\'.');
|
|
448
448
|
} else if (result.status >= 200 && result.status < 300) {
|
|
449
449
|
console.log(`Status: ${result.status} OK`);
|
|
450
450
|
} else {
|
package/lib/bootstrap.js
CHANGED
|
@@ -552,6 +552,10 @@ MAIASS_STAGINGBRANCH=${config.branches.staging}
|
|
|
552
552
|
|
|
553
553
|
// Add standard options
|
|
554
554
|
content += `# Auto-Yes Functionality (for CI/CD and non-interactive mode)
|
|
555
|
+
# MAIASS_AUTO_STAGE_UNSTAGED: opt-in only (MAI-93). When false (default), even
|
|
556
|
+
# unattended runs (-a / -uc / --silent) commit ONLY already-staged changes and
|
|
557
|
+
# leave unstaged/untracked files alone. Set to true to restore the old
|
|
558
|
+
# 'git add -A' sweep that stages everything before committing.
|
|
555
559
|
#MAIASS_AUTO_STAGE_UNSTAGED=false
|
|
556
560
|
#MAIASS_AUTO_PUSH_COMMITS=false
|
|
557
561
|
#MAIASS_AUTO_MERGE_TO_DEVELOP=false
|
package/lib/commit.js
CHANGED
|
@@ -1038,16 +1038,34 @@ export async function commitThis(options = {}) {
|
|
|
1038
1038
|
// Handle unstaged/untracked changes first
|
|
1039
1039
|
if (status.unstagedCount > 0 || status.untrackedCount > 0) {
|
|
1040
1040
|
if (!autoStage) {
|
|
1041
|
+
// MAI-93: auto-staging of unstaged/untracked changes is now strictly
|
|
1042
|
+
// opt-in. The only thing that triggers a `git add -A` sweep here is the
|
|
1043
|
+
// user/config explicitly setting MAIASS_AUTO_STAGE_UNSTAGED=true.
|
|
1044
|
+
const optInAutoStage = process.env.MAIASS_AUTO_STAGE_UNSTAGED === 'true';
|
|
1045
|
+
// An unattended run is one where prompts are auto-answered: either a
|
|
1046
|
+
// silent run, or an auto/-co run that auto-approves AI suggestions.
|
|
1047
|
+
const unattended = silent || process.env.MAIASS_AUTO_APPROVE_AI_SUGGESTIONS === 'true';
|
|
1048
|
+
|
|
1041
1049
|
let reply;
|
|
1042
|
-
|
|
1043
|
-
|
|
1050
|
+
if (optInAutoStage) {
|
|
1051
|
+
// Explicit opt-in → preserve the historical `git add -A` sweep.
|
|
1044
1052
|
reply = 'y';
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1053
|
+
console.log('🔄 |)) Automatically staging changes (MAIASS_AUTO_STAGE_UNSTAGED=true)');
|
|
1054
|
+
} else if (unattended) {
|
|
1055
|
+
// MAI-93: unattended but auto-stage OFF → never prompt, never sweep.
|
|
1056
|
+
// Proceed with already-staged changes only.
|
|
1057
|
+
if (status.stagedCount > 0) {
|
|
1058
|
+
log.info(SYMBOLS.INFO, 'Proceeding with staged changes only');
|
|
1059
|
+
return await handleStagedCommit(gitInfo, { silent, dryRun, providedMessage });
|
|
1049
1060
|
}
|
|
1061
|
+
// Nothing staged → clean no-op (exit 0). This is the unattended
|
|
1062
|
+
// commit-only path with nothing to commit. Use console.log (not
|
|
1063
|
+
// log.info, which is suppressed at brief/normal verbosity) so the
|
|
1064
|
+
// skip reason always surfaces.
|
|
1065
|
+
console.log('Nothing staged; MAIASS_AUTO_STAGE_UNSTAGED=false — skipping commit');
|
|
1066
|
+
return true;
|
|
1050
1067
|
} else {
|
|
1068
|
+
// Interactive (non-auto) behaviour is unchanged — prompt as before.
|
|
1051
1069
|
reply = await getSingleCharInput('Do you want to stage and commit them? [y/N] ');
|
|
1052
1070
|
}
|
|
1053
1071
|
if (reply === 'y') {
|
package/lib/config-command.js
CHANGED
package/lib/config-manager.js
CHANGED
|
@@ -321,7 +321,7 @@ export function validateConfig(config) {
|
|
|
321
321
|
errors.push({
|
|
322
322
|
key,
|
|
323
323
|
error: 'Unknown configuration variable',
|
|
324
|
-
suggestion: 'Check available variables with:
|
|
324
|
+
suggestion: 'Check available variables with: maiass config --list-vars'
|
|
325
325
|
});
|
|
326
326
|
return;
|
|
327
327
|
}
|
package/lib/maiass-command.js
CHANGED
|
@@ -12,8 +12,11 @@ import colors from './colors.js';
|
|
|
12
12
|
*/
|
|
13
13
|
export const FLAGS = [
|
|
14
14
|
'--auto', '-a',
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
// MAI-93: -uc / --unattended-commit is the UNATTENDED commit-only flag
|
|
16
|
+
// (replaces the removed -ac / --auto-commit).
|
|
17
|
+
'--unattended-commit', '-uc',
|
|
18
|
+
// Interactive commit-only. -co is an alias of --commits-only (bash parity).
|
|
19
|
+
'--commits-only', '-c', '-co',
|
|
17
20
|
'--auto-stage',
|
|
18
21
|
'--dry-run', '-d',
|
|
19
22
|
'--force', '-f',
|
|
@@ -21,7 +24,7 @@ export const FLAGS = [
|
|
|
21
24
|
'--tag', '-t',
|
|
22
25
|
// -m / --message <value>: supply the commit message verbatim, non-interactively
|
|
23
26
|
// (MAI-XX node+bash parity). Bypasses AI + interactive prompt. Works with the
|
|
24
|
-
// default workflow
|
|
27
|
+
// default workflow, commits-only (-c / -co), and unattended-commit (-uc).
|
|
25
28
|
'--message', '-m',
|
|
26
29
|
];
|
|
27
30
|
|
package/lib/maiass-pipeline.js
CHANGED
|
@@ -239,6 +239,132 @@ async function validateAndHandleBranching(options = {}) {
|
|
|
239
239
|
};
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
+
/**
|
|
243
|
+
* MAI-93: get the current stash ref SHA, or null if there is no stash.
|
|
244
|
+
* Used to detect whether `git stash push` actually created a stash (it is a
|
|
245
|
+
* no-op on a clean tree and we must NOT then try to pop).
|
|
246
|
+
* @returns {string|null} The SHA of refs/stash, or null if no stash exists.
|
|
247
|
+
*/
|
|
248
|
+
export function getStashRef() {
|
|
249
|
+
const result = executeGitCommand('git rev-parse --verify --quiet refs/stash', true);
|
|
250
|
+
if (!result.success) return null;
|
|
251
|
+
const sha = (result.output || '').trim();
|
|
252
|
+
return sha.length > 0 ? sha : null;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* MAI-93: stash leftover (unstaged tracked + untracked) changes so the
|
|
257
|
+
* merge/version pipeline runs on a clean tree, avoiding `git checkout`/`git
|
|
258
|
+
* merge` refusing on collisions or carrying edits onto the wrong branch.
|
|
259
|
+
*
|
|
260
|
+
* `git stash push` is a no-op on a clean tree, so we compare refs/stash before
|
|
261
|
+
* and after to decide whether a stash was actually created. Only when one was
|
|
262
|
+
* created do we report `stashed: true` — the caller must then pop it.
|
|
263
|
+
*
|
|
264
|
+
* @returns {{stashed: boolean, ref: string|null, message: string|null}}
|
|
265
|
+
*/
|
|
266
|
+
export function stashLeftoverChanges() {
|
|
267
|
+
const before = getStashRef();
|
|
268
|
+
const message = `maiass-auto-${Date.now()}`;
|
|
269
|
+
const result = executeGitCommand(
|
|
270
|
+
`git stash push --include-untracked -m "${message}"`,
|
|
271
|
+
);
|
|
272
|
+
if (!result.success) {
|
|
273
|
+
return { stashed: false, ref: null, message: null };
|
|
274
|
+
}
|
|
275
|
+
const after = getStashRef();
|
|
276
|
+
// A stash was created iff refs/stash now points somewhere new.
|
|
277
|
+
const stashed = after !== null && after !== before;
|
|
278
|
+
return { stashed, ref: stashed ? after : null, message: stashed ? message : null };
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* MAI-93: restore changes stashed by stashLeftoverChanges().
|
|
283
|
+
*
|
|
284
|
+
* Runs `git stash pop`. On a clean pop the stash entry is removed and the
|
|
285
|
+
* user's leftover work is back in the working tree. On a conflicting pop, git
|
|
286
|
+
* leaves the stash entry INTACT (exit non-zero) — we must NOT discard it; we
|
|
287
|
+
* surface a prominent warning telling the user where their work lives and
|
|
288
|
+
* return a non-fatal warning rather than crashing.
|
|
289
|
+
*
|
|
290
|
+
* @param {{message?: string|null}} stashInfo - Info from stashLeftoverChanges().
|
|
291
|
+
* @returns {{success: boolean, conflict: boolean, message?: string}}
|
|
292
|
+
*/
|
|
293
|
+
export function restoreStashedChanges(stashInfo = {}) {
|
|
294
|
+
const result = executeGitCommand('git stash pop', true);
|
|
295
|
+
if (result.success) {
|
|
296
|
+
log.success(SYMBOLS.CHECKMARK, 'Restored your stashed changes to the working tree');
|
|
297
|
+
return { success: true, conflict: false };
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Pop failed — almost always a merge conflict on restore. Do NOT drop the
|
|
301
|
+
// stash; it is still at stash@{0}. Warn loudly so work is never lost silently.
|
|
302
|
+
const ref = stashInfo.message ? `stash@{0} (${stashInfo.message})` : 'stash@{0}';
|
|
303
|
+
console.log();
|
|
304
|
+
log.warning(SYMBOLS.WARNING, 'Could not automatically restore your stashed changes (conflict on pop)');
|
|
305
|
+
log.warning(SYMBOLS.WARNING, `Your changes are preserved in ${ref} — resolve manually`);
|
|
306
|
+
log.info(SYMBOLS.INFO, 'Run `git stash pop` and resolve the conflicts when ready.');
|
|
307
|
+
return { success: false, conflict: true, message: ref };
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* MAI-93: guarded stash restore — pop only after we are back on the branch the
|
|
312
|
+
* stash was taken from.
|
|
313
|
+
*
|
|
314
|
+
* On the happy path version management returns us to the original branch before
|
|
315
|
+
* the finally runs, so a bare pop is fine. But on early-return FAILURE paths
|
|
316
|
+
* (merge failure, version failure) the pipeline may still be on develop /
|
|
317
|
+
* release/* when cleanup runs. Popping a user's feature-branch work onto the
|
|
318
|
+
* wrong branch is worse than not popping, so this:
|
|
319
|
+
* 1. checks the current branch;
|
|
320
|
+
* 2. if it differs from the target, attempts a guarded checkout;
|
|
321
|
+
* 3. only pops if we are (or got) on the target branch;
|
|
322
|
+
* 4. if we can't get there, PRESERVES the stash and warns where it lives.
|
|
323
|
+
* It never throws — safe to call from a finally block.
|
|
324
|
+
*
|
|
325
|
+
* Dependencies are injectable for unit testing; defaults use the module's git
|
|
326
|
+
* helpers and the real pop.
|
|
327
|
+
*
|
|
328
|
+
* @param {{stashed?: boolean, ref?: string, message?: string|null}} stashInfo
|
|
329
|
+
* @param {string} targetBranch - branch the stash was captured on.
|
|
330
|
+
* @param {object} [deps] - { getCurrentBranchFn, switchToBranchFn, restoreFn }
|
|
331
|
+
* @returns {Promise<{popped: boolean, preserved: boolean, reason?: string}>}
|
|
332
|
+
*/
|
|
333
|
+
export async function restoreStashedChangesOnBranch(stashInfo = {}, targetBranch, deps = {}) {
|
|
334
|
+
if (!stashInfo || !stashInfo.stashed) {
|
|
335
|
+
return { popped: false, preserved: false, reason: 'no-stash' };
|
|
336
|
+
}
|
|
337
|
+
const getCurrentBranchFn = deps.getCurrentBranchFn || getCurrentBranch;
|
|
338
|
+
const switchToBranchFn = deps.switchToBranchFn || switchToBranch;
|
|
339
|
+
const restoreFn = deps.restoreFn || restoreStashedChanges;
|
|
340
|
+
|
|
341
|
+
const stashRef = () =>
|
|
342
|
+
stashInfo.message ? `stash@{0} (${stashInfo.message})` : 'stash@{0}';
|
|
343
|
+
|
|
344
|
+
try {
|
|
345
|
+
const current = getCurrentBranchFn();
|
|
346
|
+
if (targetBranch && current !== targetBranch) {
|
|
347
|
+
const switched = await switchToBranchFn(targetBranch);
|
|
348
|
+
if (!switched) {
|
|
349
|
+
log.warning(SYMBOLS.WARNING, `Could not return to ${targetBranch} to restore your stashed changes`);
|
|
350
|
+
log.warning(
|
|
351
|
+
SYMBOLS.WARNING,
|
|
352
|
+
`Your changes are preserved in ${stashRef()} — checkout ${targetBranch} and run \`git stash pop\` manually`,
|
|
353
|
+
);
|
|
354
|
+
return { popped: false, preserved: true, reason: 'checkout-failed' };
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
} catch (e) {
|
|
358
|
+
// Never let cleanup throw out of a finally — preserve the stash instead.
|
|
359
|
+
log.warning(SYMBOLS.WARNING, `Could not verify the branch before restoring your stash: ${e.message}`);
|
|
360
|
+
log.warning(SYMBOLS.WARNING, `Your changes are preserved in ${stashRef()} — restore manually with \`git stash pop\``);
|
|
361
|
+
return { popped: false, preserved: true, reason: 'branch-check-threw' };
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
restoreFn(stashInfo);
|
|
365
|
+
return { popped: true, preserved: false };
|
|
366
|
+
}
|
|
367
|
+
|
|
242
368
|
/**
|
|
243
369
|
* Handle the commit workflow phase
|
|
244
370
|
* @param {Object} branchInfo - Branch information from validation
|
|
@@ -265,20 +391,57 @@ async function handleCommitWorkflow(branchInfo, options = {}) {
|
|
|
265
391
|
return { success: false, cancelled: true, error: 'Commit workflow cancelled by user' };
|
|
266
392
|
}
|
|
267
393
|
|
|
268
|
-
// After commit workflow, check if working directory is clean for version
|
|
269
|
-
// If we're not in commits-only mode,
|
|
394
|
+
// After commit workflow, check if working directory is clean for version
|
|
395
|
+
// management. If we're not in commits-only mode, an unclean working tree
|
|
396
|
+
// normally stops the pipeline so unrelated work isn't silently swept into
|
|
397
|
+
// the version bump.
|
|
398
|
+
//
|
|
399
|
+
// MAI-93: in an UNATTENDED auto run with auto-stage OFF, the user has
|
|
400
|
+
// explicitly asked for an unattended bump. The merge/version pipeline does
|
|
401
|
+
// branch switching (checkout develop, merge, release branch, merge-back),
|
|
402
|
+
// which `git checkout`/`git merge` will refuse on a dirty tree (or worse,
|
|
403
|
+
// carry the edits onto the wrong branch). So instead of proceeding dirty we
|
|
404
|
+
// STASH the leftover changes, let the pipeline run on a clean tree, and the
|
|
405
|
+
// caller restores them afterward (see runMaiassPipeline's finally block).
|
|
406
|
+
// Interactive runs keep the protective stop.
|
|
270
407
|
if (!commitsOnly) {
|
|
271
408
|
const postCommitGitInfo = getGitInfo();
|
|
272
409
|
const postCommitStatus = postCommitGitInfo.status;
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
410
|
+
const leftover =
|
|
411
|
+
(postCommitStatus?.unstagedCount || 0) + (postCommitStatus?.untrackedCount || 0);
|
|
412
|
+
|
|
413
|
+
if (leftover > 0) {
|
|
414
|
+
const optInAutoStage = process.env.MAIASS_AUTO_STAGE_UNSTAGED === 'true';
|
|
415
|
+
const unattended =
|
|
416
|
+
silent || process.env.MAIASS_AUTO_APPROVE_AI_SUGGESTIONS === 'true';
|
|
417
|
+
|
|
418
|
+
if (unattended && !optInAutoStage) {
|
|
419
|
+
// MAI-93: stash the leftover changes so the version pipeline runs on a
|
|
420
|
+
// clean tree. The caller pops the stash once we're back on the
|
|
421
|
+
// original branch (try/finally — restored even if the pipeline fails).
|
|
422
|
+
const stashInfo = stashLeftoverChanges();
|
|
423
|
+
if (stashInfo.stashed) {
|
|
424
|
+
// Use success-level so it is visible even in brief verbosity (the
|
|
425
|
+
// default) — the user must know their work was set aside, and the
|
|
426
|
+
// matching "Restored..." confirmation is also success-level.
|
|
427
|
+
log.success(
|
|
428
|
+
SYMBOLS.INFO,
|
|
429
|
+
`Stashed ${leftover} unrelated change${leftover === 1 ? '' : 's'} for the version pipeline; will restore after`,
|
|
430
|
+
);
|
|
431
|
+
return { success: true, stashInfo };
|
|
432
|
+
}
|
|
433
|
+
// Push reported success but created no stash (e.g. all leftover was
|
|
434
|
+
// ignored/no-op) — nothing to restore, proceed normally.
|
|
435
|
+
return { success: true };
|
|
436
|
+
} else {
|
|
437
|
+
// Working directory is not clean, cannot proceed with version management
|
|
438
|
+
console.log();
|
|
439
|
+
log.warning(SYMBOLS.WARNING, 'Working directory has uncommitted changes');
|
|
440
|
+
log.info(SYMBOLS.INFO, 'Cannot proceed with version management - pipeline stopped');
|
|
441
|
+
log.info(SYMBOLS.INFO, `Current branch: ${getCurrentBranch()}`);
|
|
442
|
+
log.success('', 'Thank you for using MAIASS.');
|
|
443
|
+
return { success: true, stoppedDueToUncommittedChanges: true };
|
|
444
|
+
}
|
|
282
445
|
}
|
|
283
446
|
}
|
|
284
447
|
|
|
@@ -601,6 +764,59 @@ async function handleVersionManagement(branchInfo, mergeResult, options = {}) {
|
|
|
601
764
|
}
|
|
602
765
|
}
|
|
603
766
|
|
|
767
|
+
/**
|
|
768
|
+
* MAI-93: stage ONLY the version + changelog files for the version-bump commit.
|
|
769
|
+
*
|
|
770
|
+
* Previously the version commit ran `git add -A`, which swept any unrelated
|
|
771
|
+
* unstaged/untracked files in the working tree into the "Bumped version"
|
|
772
|
+
* commit. A `-a` run on a dirty tree must bump+commit ONLY version/changelog
|
|
773
|
+
* files and leave everything else untouched.
|
|
774
|
+
*
|
|
775
|
+
* @param {Object} versionResult - Result of updateVersionFiles() — its
|
|
776
|
+
* `.updated[]` entries carry the `.path` of each written version file.
|
|
777
|
+
* @returns {{success: boolean, error?: string, staged: string[]}}
|
|
778
|
+
*/
|
|
779
|
+
function stageVersionAndChangelogFiles(versionResult) {
|
|
780
|
+
// Collect version file paths from the update result.
|
|
781
|
+
const paths = new Set();
|
|
782
|
+
for (const entry of (versionResult?.updated || [])) {
|
|
783
|
+
// MAI-93: prefer `path`, but fall back to `file` so any result shape that
|
|
784
|
+
// only carries a filename (e.g. secondary version files) is still staged.
|
|
785
|
+
const p = entry?.path || entry?.file;
|
|
786
|
+
if (p) paths.add(p);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
// Add the changelog file(s) written by updateChangelogNew — computed from
|
|
790
|
+
// the same env vars the changelog writer uses, so they stay in lockstep.
|
|
791
|
+
const changelogPath = process.env.MAIASS_CHANGELOG_PATH || '.';
|
|
792
|
+
const changelogName = process.env.MAIASS_CHANGELOG_NAME || 'CHANGELOG.md';
|
|
793
|
+
const changelogInternalName = process.env.MAIASS_CHANGELOG_INTERNAL_NAME || '.CHANGELOG_internal.md';
|
|
794
|
+
const changelogInternalPath = process.env.MAIASS_CHANGELOG_INTERNAL_PATH || changelogPath;
|
|
795
|
+
const changelogFile = path.join(changelogPath, changelogName);
|
|
796
|
+
const changelogInternalFile = path.join(changelogInternalPath, changelogInternalName);
|
|
797
|
+
// Only stage changelog files that actually exist on disk (the internal one
|
|
798
|
+
// is optional, and the public one may be skipped if there was nothing to add).
|
|
799
|
+
for (const f of [changelogFile, changelogInternalFile]) {
|
|
800
|
+
try {
|
|
801
|
+
if (fs.existsSync(f)) paths.add(f);
|
|
802
|
+
} catch { /* ignore */ }
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
const fileList = [...paths];
|
|
806
|
+
if (fileList.length === 0) {
|
|
807
|
+
// Nothing to stage — let the caller's commit step decide what to do.
|
|
808
|
+
return { success: true, staged: [] };
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
// Stage each path explicitly. Quote to survive spaces in paths.
|
|
812
|
+
const quoted = fileList.map(p => `"${p}"`).join(' ');
|
|
813
|
+
const addResult = executeGitCommand(`git add -- ${quoted}`);
|
|
814
|
+
if (!addResult.success) {
|
|
815
|
+
return { success: false, error: 'Git add failed', staged: [] };
|
|
816
|
+
}
|
|
817
|
+
return { success: true, staged: fileList };
|
|
818
|
+
}
|
|
819
|
+
|
|
604
820
|
/**
|
|
605
821
|
* Handle simple version bump without release branch or tagging
|
|
606
822
|
* @param {string} newVersion - New version to set
|
|
@@ -624,20 +840,21 @@ async function handleSimpleVersionBump(newVersion, versionInfo, developBranch, o
|
|
|
624
840
|
const changelogPath = process.env.MAIASS_CHANGELOG_PATH || '.';
|
|
625
841
|
await updateChangelogNew(changelogPath, newVersion);
|
|
626
842
|
|
|
627
|
-
// Commit version changes
|
|
843
|
+
// Commit version changes. MAI-93: stage ONLY version + changelog files,
|
|
844
|
+
// never `git add -A`, so unrelated unstaged work is left untouched.
|
|
628
845
|
logger.info(SYMBOLS.GEAR, 'Committing version changes...');
|
|
629
|
-
const addResult =
|
|
846
|
+
const addResult = stageVersionAndChangelogFiles(versionResult);
|
|
630
847
|
if (!addResult.success) {
|
|
631
|
-
logger.error(SYMBOLS.CROSS, 'Git operation failed: add
|
|
848
|
+
logger.error(SYMBOLS.CROSS, 'Git operation failed: add (version/changelog files)');
|
|
632
849
|
return { success: false, error: 'Git add failed' };
|
|
633
850
|
}
|
|
634
|
-
|
|
851
|
+
|
|
635
852
|
const { success: committed } = executeGitCommand(`git commit -m "Bumped version to ${newVersion}"`);
|
|
636
853
|
if (!committed) {
|
|
637
854
|
logger.error(SYMBOLS.CROSS, 'Git operation failed: commit');
|
|
638
855
|
return { success: false, error: 'Version commit failed' };
|
|
639
856
|
}
|
|
640
|
-
|
|
857
|
+
|
|
641
858
|
// Push to remote if exists
|
|
642
859
|
const hasRemote = await checkRemoteExists('origin');
|
|
643
860
|
if (hasRemote) {
|
|
@@ -710,20 +927,21 @@ async function handleReleaseBranchWorkflow(newVersion, versionInfo, developBranc
|
|
|
710
927
|
const changelogPath = process.env.MAIASS_CHANGELOG_PATH || '.';
|
|
711
928
|
await updateChangelogNew(changelogPath, newVersion);
|
|
712
929
|
|
|
713
|
-
// Commit version changes
|
|
930
|
+
// Commit version changes. MAI-93: stage ONLY version + changelog files,
|
|
931
|
+
// never `git add -A`, so unrelated unstaged work is left untouched.
|
|
714
932
|
logger.info(SYMBOLS.GEAR, 'Committing version changes...');
|
|
715
|
-
const addResult =
|
|
933
|
+
const addResult = stageVersionAndChangelogFiles(versionResult);
|
|
716
934
|
if (!addResult.success) {
|
|
717
|
-
logger.error(SYMBOLS.CROSS, 'Git operation failed: add
|
|
935
|
+
logger.error(SYMBOLS.CROSS, 'Git operation failed: add (version/changelog files)');
|
|
718
936
|
return { success: false, error: 'Git add failed' };
|
|
719
937
|
}
|
|
720
|
-
|
|
938
|
+
|
|
721
939
|
const { success: committed } = executeGitCommand(`git commit -m "Bumped version to ${newVersion}"`);
|
|
722
940
|
if (!committed) {
|
|
723
941
|
logger.error(SYMBOLS.CROSS, 'Git operation failed: commit');
|
|
724
942
|
return { success: false, error: 'Version commit failed' };
|
|
725
943
|
}
|
|
726
|
-
|
|
944
|
+
|
|
727
945
|
// Create version tag
|
|
728
946
|
logger.info(SYMBOLS.GEAR, `Creating version tag...`);
|
|
729
947
|
const { success: tagged } = executeGitCommand(`git tag -a ${newVersion} -m "Release version ${newVersion}"`);
|
|
@@ -898,59 +1116,77 @@ export async function runMaiassPipeline(options = {}) {
|
|
|
898
1116
|
console.log(colors.BBlue(`${SYMBOLS.INFO} Current branch: ${getCurrentBranch()}`));
|
|
899
1117
|
return { success: true, phase: 'commits-only', dryRun };
|
|
900
1118
|
}
|
|
901
|
-
|
|
1119
|
+
|
|
902
1120
|
console.log();
|
|
903
|
-
|
|
904
|
-
// Phase 3: Merge to Develop
|
|
905
|
-
log.blue(SYMBOLS.INFO, 'Phase 3: Merge to Develop');
|
|
906
|
-
const mergeResult = await handleMergeToDevelop(branchInfo, commitResult, {
|
|
907
|
-
force,
|
|
908
|
-
silent,
|
|
909
|
-
originalGitInfo,
|
|
910
|
-
autoSwitch: !commitsOnly,
|
|
911
|
-
versionBump,
|
|
912
|
-
tag
|
|
913
|
-
});
|
|
914
|
-
|
|
915
|
-
if (!mergeResult.success) {
|
|
916
|
-
return mergeResult;
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
// If merge was cancelled by user, stop here gracefully
|
|
920
|
-
if (mergeResult.cancelled) {
|
|
921
|
-
console.log();
|
|
922
|
-
logger.success(SYMBOLS.CHECKMARK, `Workflow completed on ${getCurrentBranch()}`);
|
|
923
|
-
logger.info(SYMBOLS.INFO, 'Thank you for using MAIASS!');
|
|
924
|
-
return { success: true, cancelled: true, phase: 'merge-cancelled' };
|
|
925
|
-
}
|
|
926
1121
|
|
|
927
|
-
//
|
|
928
|
-
//
|
|
929
|
-
//
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
1122
|
+
// MAI-93: if the commit phase stashed leftover changes (unattended -a with a
|
|
1123
|
+
// dirty tree), the merge/version pipeline below runs on a clean tree. The
|
|
1124
|
+
// stash MUST be popped once we're back on the original branch — even if the
|
|
1125
|
+
// pipeline throws or returns failure — so the user's work is never stranded.
|
|
1126
|
+
// The try/finally guarantees the pop runs. The pop itself preserves the
|
|
1127
|
+
// stash on conflict (restoreStashedChanges) rather than discarding work.
|
|
1128
|
+
const stashInfo = commitResult.stashInfo || null;
|
|
1129
|
+
let mergeResult, versionResult;
|
|
1130
|
+
try {
|
|
1131
|
+
// Phase 3: Merge to Develop
|
|
1132
|
+
log.blue(SYMBOLS.INFO, 'Phase 3: Merge to Develop');
|
|
1133
|
+
mergeResult = await handleMergeToDevelop(branchInfo, commitResult, {
|
|
1134
|
+
force,
|
|
1135
|
+
silent,
|
|
1136
|
+
originalGitInfo,
|
|
1137
|
+
autoSwitch: !commitsOnly,
|
|
1138
|
+
versionBump,
|
|
1139
|
+
tag
|
|
1140
|
+
});
|
|
1141
|
+
|
|
1142
|
+
if (!mergeResult.success) {
|
|
1143
|
+
return mergeResult;
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
// If merge was cancelled by user, stop here gracefully
|
|
1147
|
+
if (mergeResult.cancelled) {
|
|
1148
|
+
console.log();
|
|
1149
|
+
logger.success(SYMBOLS.CHECKMARK, `Workflow completed on ${getCurrentBranch()}`);
|
|
1150
|
+
logger.info(SYMBOLS.INFO, 'Thank you for using MAIASS!');
|
|
1151
|
+
return { success: true, cancelled: true, phase: 'merge-cancelled' };
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
// If PR flow was used, the merge will happen on the platform — stop the
|
|
1155
|
+
// pipeline here. Version management will run on the next maiass invocation
|
|
1156
|
+
// after the user merges the PR.
|
|
1157
|
+
if (mergeResult.pullRequest) {
|
|
1158
|
+
console.log();
|
|
1159
|
+
logger.info(SYMBOLS.INFO, 'Thank you for using MAIASS!');
|
|
1160
|
+
return { success: true, pullRequest: true, url: mergeResult.url };
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
console.log('');
|
|
1164
|
+
|
|
1165
|
+
// Phase 4: Version Management
|
|
1166
|
+
log.blue(SYMBOLS.INFO, 'Phase 4: Version Management');
|
|
1167
|
+
versionResult = await handleVersionManagement(branchInfo, mergeResult, {
|
|
1168
|
+
versionBump,
|
|
1169
|
+
versionBumpExplicit,
|
|
1170
|
+
dryRun,
|
|
1171
|
+
tag,
|
|
1172
|
+
force,
|
|
1173
|
+
silent,
|
|
1174
|
+
originalGitInfo
|
|
1175
|
+
});
|
|
1176
|
+
|
|
1177
|
+
if (!versionResult.success) {
|
|
1178
|
+
return versionResult;
|
|
1179
|
+
}
|
|
1180
|
+
} finally {
|
|
1181
|
+
// Pop only when we actually stashed (clean-tree -a / CI never stashes),
|
|
1182
|
+
// and only after we are back on the branch the stash was captured on —
|
|
1183
|
+
// otherwise an early-return failure path could pop the user's work onto
|
|
1184
|
+
// develop/release/*. The helper is failure-safe (never throws).
|
|
1185
|
+
if (stashInfo && stashInfo.stashed) {
|
|
1186
|
+
await restoreStashedChangesOnBranch(stashInfo, branchInfo?.originalBranch);
|
|
1187
|
+
}
|
|
952
1188
|
}
|
|
953
|
-
|
|
1189
|
+
|
|
954
1190
|
// Cache branch info to avoid multiple git calls that might hang
|
|
955
1191
|
const finalBranch = getCurrentBranch();
|
|
956
1192
|
const originalBranch = branchInfo.originalBranch;
|
package/lib/maiass-variables.js
CHANGED
|
@@ -8,8 +8,11 @@ export const MAIASS_VARIABLES = {
|
|
|
8
8
|
'MAIASS_DEBUG': { default: 'false', description: 'Enable debug mode' },
|
|
9
9
|
'MAIASS_BRAND': { default: 'MAIASS', description: 'Brand name for display' },
|
|
10
10
|
|
|
11
|
-
// Auto-yes flags
|
|
12
|
-
//
|
|
11
|
+
// Auto-yes flags. -a (--auto) and -uc (--unattended-commit) set
|
|
12
|
+
// MAIASS_AUTO_PUSH_COMMITS + MAIASS_AUTO_APPROVE_AI_SUGGESTIONS; -a also sets
|
|
13
|
+
// MAIASS_AUTO_MERGE_TO_DEVELOP. Neither sets MAIASS_AUTO_STAGE_UNSTAGED any
|
|
14
|
+
// more (MAI-93 — auto-staging is opt-in). Setting any of these in .env.maiass
|
|
15
|
+
// makes that prompt auto-approve permanently.
|
|
13
16
|
'MAIASS_AUTO_STAGE_UNSTAGED': { default: 'false', description: 'Auto-stage unstaged changes during commit phase' },
|
|
14
17
|
'MAIASS_AUTO_PUSH_COMMITS': { default: 'false', description: 'Auto-push commits to origin' },
|
|
15
18
|
'MAIASS_AUTO_APPROVE_AI_SUGGESTIONS': { default: 'false', description: 'Auto-approve AI commit message suggestions' },
|
package/lib/version-manager.js
CHANGED
|
@@ -438,7 +438,12 @@ function updatePhpVersionConstant(filePath, constantName, newVersion) {
|
|
|
438
438
|
function updateWordPressVersions(newVersion, projectPath = process.cwd()) {
|
|
439
439
|
const wpConfig = getWordPressConfig(projectPath);
|
|
440
440
|
let success = true;
|
|
441
|
-
|
|
441
|
+
// MAI-93: collect every file we actually modify so the caller can stage them
|
|
442
|
+
// into the version commit (mirrors bash's track_bumped_file). Without this the
|
|
443
|
+
// pipeline's targeted `git add` bumps WordPress files on disk but omits them
|
|
444
|
+
// from the release commit.
|
|
445
|
+
const updatedFiles = [];
|
|
446
|
+
|
|
442
447
|
// Handle plugin path
|
|
443
448
|
if (wpConfig.pluginPath) {
|
|
444
449
|
const pluginPath = path.isAbsolute(wpConfig.pluginPath)
|
|
@@ -465,6 +470,8 @@ function updateWordPressVersions(newVersion, projectPath = process.cwd()) {
|
|
|
465
470
|
const constantName = wpConfig.versionConstant || generateVersionConstant(wpConfig.pluginPath);
|
|
466
471
|
if (!updatePhpVersionConstant(mainPluginFile, constantName, newVersion)) {
|
|
467
472
|
success = false;
|
|
473
|
+
} else {
|
|
474
|
+
updatedFiles.push(mainPluginFile);
|
|
468
475
|
}
|
|
469
476
|
} else {
|
|
470
477
|
console.log(colors.BYellow(`${SYMBOLS.WARNING} Could not find main plugin file in ${pluginPath}`)); // codeql[js/clear-text-logging] -- pluginPath is a file path, not a credential
|
|
@@ -513,6 +520,8 @@ function updateWordPressVersions(newVersion, projectPath = process.cwd()) {
|
|
|
513
520
|
|
|
514
521
|
if (!updatePhpVersionConstant(functionsFile, constantName, newVersion)) {
|
|
515
522
|
success = false;
|
|
523
|
+
} else {
|
|
524
|
+
updatedFiles.push(functionsFile);
|
|
516
525
|
}
|
|
517
526
|
} else {
|
|
518
527
|
console.log(colors.BYellow(`${SYMBOLS.WARNING} Could not find functions.php in ${themePath}`)); // codeql[js/clear-text-logging] -- themePath is a file path, not a credential
|
|
@@ -529,13 +538,18 @@ function updateWordPressVersions(newVersion, projectPath = process.cwd()) {
|
|
|
529
538
|
logger.debug(` style.css found, updating theme version header`);
|
|
530
539
|
if (!updateThemeStyleVersion(styleFile, newVersion)) {
|
|
531
540
|
success = false;
|
|
541
|
+
} else {
|
|
542
|
+
updatedFiles.push(styleFile);
|
|
532
543
|
}
|
|
533
544
|
} else {
|
|
534
545
|
logger.debug(` style.css not found at: ${styleFile}`);
|
|
535
546
|
}
|
|
536
547
|
}
|
|
537
|
-
|
|
538
|
-
return success
|
|
548
|
+
|
|
549
|
+
// MAI-93: return both the overall success flag and the list of modified files
|
|
550
|
+
// so the caller can stage them. Returned as an object; the previous boolean
|
|
551
|
+
// return is now `success`.
|
|
552
|
+
return { success, updatedFiles };
|
|
539
553
|
}
|
|
540
554
|
|
|
541
555
|
/**
|
|
@@ -891,6 +905,11 @@ async function updateSecondaryVersionFiles(newVersion, config, dryRun = false) {
|
|
|
891
905
|
logger.success(SYMBOLS.CHECKMARK, `Updated version to ${newVersion} in ${filename}`);
|
|
892
906
|
results.updated.push({
|
|
893
907
|
file: filename,
|
|
908
|
+
// MAI-93: the pipeline stager keys off `path` to build the targeted
|
|
909
|
+
// `git add`. Without it, secondary files are bumped on disk but never
|
|
910
|
+
// staged into the version commit. Keep `file` too in case other code
|
|
911
|
+
// reads it.
|
|
912
|
+
path: filename,
|
|
894
913
|
type,
|
|
895
914
|
pattern,
|
|
896
915
|
newVersion
|
|
@@ -993,7 +1012,17 @@ export async function updateVersionFiles(newVersion, versionFiles, dryRun = fals
|
|
|
993
1012
|
if (!dryRun) {
|
|
994
1013
|
// change to use logger
|
|
995
1014
|
logger.info(SYMBOLS.INFO, 'Checking for WordPress plugin/theme version updates...');
|
|
996
|
-
const wpSuccess = updateWordPressVersions(newVersion);
|
|
1015
|
+
const { success: wpSuccess, updatedFiles: wpFiles } = updateWordPressVersions(newVersion);
|
|
1016
|
+
// MAI-93: stage the WordPress files we actually modified (style.css,
|
|
1017
|
+
// functions.php, plugin header PHP). `path` is the key the pipeline stager
|
|
1018
|
+
// uses to build its targeted `git add`.
|
|
1019
|
+
for (const wpFile of (wpFiles || [])) {
|
|
1020
|
+
results.updated.push({
|
|
1021
|
+
file: wpFile,
|
|
1022
|
+
path: wpFile,
|
|
1023
|
+
newVersion
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
997
1026
|
if (!wpSuccess) {
|
|
998
1027
|
results.success = false;
|
|
999
1028
|
results.failed.push({
|
package/maiass.mjs
CHANGED
|
@@ -101,7 +101,7 @@ if (firstArg && versionBumpTypes.includes(firstArg)) {
|
|
|
101
101
|
console.log('Version bump types:');
|
|
102
102
|
console.log(' ' + versionBumpTypes.join(', '));
|
|
103
103
|
console.log('');
|
|
104
|
-
console.log(`Run '
|
|
104
|
+
console.log(`Run 'maiass --help' for more information.`);
|
|
105
105
|
process.exit(1);
|
|
106
106
|
}
|
|
107
107
|
command = firstArg;
|
|
@@ -110,14 +110,30 @@ if (firstArg && versionBumpTypes.includes(firstArg)) {
|
|
|
110
110
|
command = 'maiass';
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
// MAI-93: `-ac` / `--auto-commit` has been REMOVED (breaking change, no alias).
|
|
114
|
+
// Reject it early — before any work — and point users at the replacement.
|
|
115
|
+
// Skip any position that is the VALUE of -m/--message, so a legitimate commit
|
|
116
|
+
// message like `maiass -uc -m "-ac"` is NOT treated as the removed flag.
|
|
117
|
+
const usesRemovedAutoCommit = args.some(
|
|
118
|
+
(a, i) => (a === '--auto-commit' || a === '-ac') && !messageArgIndices.has(i)
|
|
119
|
+
);
|
|
120
|
+
if (usesRemovedAutoCommit) {
|
|
121
|
+
console.error('Please use -uc (--unattended-commit)');
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
|
|
113
125
|
// Auto modes:
|
|
114
|
-
// -a / --auto:
|
|
115
|
-
//
|
|
116
|
-
// -
|
|
117
|
-
//
|
|
118
|
-
//
|
|
119
|
-
|
|
120
|
-
|
|
126
|
+
// -a / --auto: full auto — push, merge to develop, version bump.
|
|
127
|
+
// Does NOT force-stage unstaged/untracked changes any
|
|
128
|
+
// more (MAI-93) — auto-staging is opt-in via
|
|
129
|
+
// MAIASS_AUTO_STAGE_UNSTAGED=true.
|
|
130
|
+
// -uc / --unattended-commit: auto-yes for commit phase only — commits STAGED
|
|
131
|
+
// changes, pushes the current branch, then stops (no
|
|
132
|
+
// merge, no bump). Unattended but does NOT force-stage
|
|
133
|
+
// (MAI-93). Distinct from the INTERACTIVE commits-only
|
|
134
|
+
// (-c / -co / --commits-only), which prompts.
|
|
135
|
+
const isUnattendedCommit = args.includes('--unattended-commit') || args.includes('-uc');
|
|
136
|
+
const isAuto = !isUnattendedCommit && (args.includes('--auto') || args.includes('-a'));
|
|
121
137
|
|
|
122
138
|
// Auto-mode env vars are applied AFTER flag validation below — see
|
|
123
139
|
// "Apply auto-mode env vars" block. Detected here only because the booleans
|
|
@@ -180,7 +196,7 @@ if (!flagValidation.valid) {
|
|
|
180
196
|
if (longFlags.length) console.log(' ' + longFlags.join(', '));
|
|
181
197
|
if (shortFlags.length) console.log(' ' + shortFlags.join(', '));
|
|
182
198
|
console.log('');
|
|
183
|
-
console.log(`Run '
|
|
199
|
+
console.log(`Run 'maiass --help' or 'maiass ${command} --help' for more information.`);
|
|
184
200
|
process.exit(1);
|
|
185
201
|
}
|
|
186
202
|
|
|
@@ -195,9 +211,13 @@ if (providedMessage !== null && providedMessage.trim() === '') {
|
|
|
195
211
|
// Apply auto-mode env vars now that validation has passed. Setting these
|
|
196
212
|
// before validation would leak MAIASS_AUTO_* into process.env for commands
|
|
197
213
|
// that reject --auto (e.g. `account-info --auto`) — see MAI-43 code review.
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
214
|
+
//
|
|
215
|
+
// MAI-93: auto modes NO LONGER force MAIASS_AUTO_STAGE_UNSTAGED. Auto-staging
|
|
216
|
+
// of unstaged/untracked changes is now opt-in — whatever the user/config set
|
|
217
|
+
// (loaded into process.env at maiass.mjs:25) is preserved; default off. The
|
|
218
|
+
// auto-yes vars below only cover push and AI-suggestion approval.
|
|
219
|
+
if (isAuto || isUnattendedCommit) {
|
|
220
|
+
// Shared auto-yes vars for both modes (NOT auto-stage — see MAI-93 above)
|
|
201
221
|
process.env.MAIASS_AUTO_PUSH_COMMITS = 'true';
|
|
202
222
|
process.env.MAIASS_AUTO_APPROVE_AI_SUGGESTIONS = 'true';
|
|
203
223
|
}
|
|
@@ -208,11 +228,11 @@ if (isAuto) {
|
|
|
208
228
|
if (process.env.MAIASS_DEBUG === 'true') {
|
|
209
229
|
logger.debug('[DEBUG] Auto mode enabled — full pipeline runs unattended');
|
|
210
230
|
}
|
|
211
|
-
} else if (
|
|
212
|
-
// -
|
|
231
|
+
} else if (isUnattendedCommit) {
|
|
232
|
+
// -uc: stop after commit phase. Implemented by treating it as commits-only
|
|
213
233
|
process.env.MAIASS_AUTO_FINISH_AFTER_COMMIT = 'true';
|
|
214
234
|
if (process.env.MAIASS_DEBUG === 'true') {
|
|
215
|
-
logger.debug('[DEBUG]
|
|
235
|
+
logger.debug('[DEBUG] Unattended-commit mode enabled — stops after commit phase');
|
|
216
236
|
}
|
|
217
237
|
}
|
|
218
238
|
|
|
@@ -243,12 +263,15 @@ if (args.includes('--help') || args.includes('-h') || command === 'help') {
|
|
|
243
263
|
console.log('\nOptions:');
|
|
244
264
|
console.log(' --account-info Show your account status (masked token)');
|
|
245
265
|
console.log(' --cleanup-changelogs AI-clean CHANGELOG.md + .CHANGELOG_internal.md (backfills from git; writes .bak)');
|
|
246
|
-
console.log(' --auto, -a Full auto —
|
|
247
|
-
console.log('
|
|
248
|
-
console.log(' --commits-only, -c
|
|
266
|
+
console.log(' --auto, -a Full auto — commit staged, push, merge to develop, bump version');
|
|
267
|
+
console.log(' (auto-staging of UNSTAGED changes is opt-in: MAIASS_AUTO_STAGE_UNSTAGED=true)');
|
|
268
|
+
console.log(' --commits-only, -c, -co Interactive commit-only — generate AI commits without version management');
|
|
269
|
+
console.log(' --unattended-commit, -uc Unattended commit-only — commits STAGED changes, pushes current branch,');
|
|
270
|
+
console.log(' then stops (no merge/bump; auto-staging of unstaged changes is opt-in)');
|
|
249
271
|
console.log(' --message, -m <msg> Use this commit message verbatim (skips AI + the message prompt; no credit/token needed).');
|
|
250
|
-
console.log(' Supplies the message only; for fully unattended use combine with -
|
|
251
|
-
console.log(' --auto-stage
|
|
272
|
+
console.log(' Supplies the message only; for fully unattended use combine with -uc (or --auto-stage).');
|
|
273
|
+
console.log(' --auto-stage Stage all changes for this run (one-shot opt-in; otherwise unstaged');
|
|
274
|
+
console.log(' changes are left alone unless MAIASS_AUTO_STAGE_UNSTAGED=true)');
|
|
252
275
|
console.log(' --setup, --bootstrap Run interactive project setup');
|
|
253
276
|
console.log(' --help, -h Show this help message');
|
|
254
277
|
console.log(' --version, -v Show version');
|
|
@@ -361,8 +384,11 @@ if (args.includes('--show-bb-excerpt')) { showBitbucketExcerpt(); process.exit(
|
|
|
361
384
|
// Positionals must exclude the -m/--message value token (it doesn't start
|
|
362
385
|
// with '-' but is NOT a command/bump-type positional).
|
|
363
386
|
_: process.argv.slice(2).filter((arg, i) => !arg.startsWith('-') && !messageArgIndices.has(i)),
|
|
364
|
-
// -
|
|
365
|
-
|
|
387
|
+
// commits-only is the INTERACTIVE commit-only mode: -c / -co / --commits-only.
|
|
388
|
+
// The UNATTENDED variant -uc / --unattended-commit also maps here, then adds
|
|
389
|
+
// the auto-yes / auto-finish env vars set above (MAI-93).
|
|
390
|
+
'commits-only': args.includes('--commits-only') || args.includes('-c') || args.includes('-co')
|
|
391
|
+
|| args.includes('--unattended-commit') || args.includes('-uc'),
|
|
366
392
|
'auto-stage': args.includes('--auto-stage'),
|
|
367
393
|
'auto': args.includes('--auto') || args.includes('-a'),
|
|
368
394
|
'version-bump': versionBump,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "maiass",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "5.
|
|
4
|
+
"version": "5.15.3",
|
|
5
5
|
"description": "AI commit messages, version bumps, and changelogs from one command. Stages, commits, merges, tags. Anonymous on first run — no email, no card.",
|
|
6
6
|
"main": "maiass.mjs",
|
|
7
7
|
"bin": {
|