maiass 5.15.6 → 5.15.13
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/lib/ci-templates.js
CHANGED
|
@@ -16,6 +16,11 @@ function renderTemplate(src) {
|
|
|
16
16
|
// .trim() guards against a stray newline or whitespace from a mis-quoted
|
|
17
17
|
// .env.maiass entry silently breaking the YAML trigger filter
|
|
18
18
|
const developBranch = (process.env.MAIASS_DEVELOPBRANCH || 'develop').trim() || 'develop';
|
|
19
|
+
// Note: the develop branch MUST be baked in here because the CI trigger
|
|
20
|
+
// filter has to be a YAML literal. The credential-missing behaviour
|
|
21
|
+
// (MAIASS_CI_FAIL_SILENTLY) is deliberately NOT baked — it lives as an
|
|
22
|
+
// editable env var inside the generated workflow, so it has a single source
|
|
23
|
+
// of truth (the YAML) rather than a stale copy in .env.maiass.
|
|
19
24
|
return fs.readFileSync(src, 'utf8').replaceAll('__MAIASS_DEVELOPBRANCH__', developBranch);
|
|
20
25
|
}
|
|
21
26
|
|
package/lib/commit.js
CHANGED
|
@@ -329,6 +329,77 @@ async function createAnonymousSubscriptionIfNeeded() {
|
|
|
329
329
|
}
|
|
330
330
|
}
|
|
331
331
|
|
|
332
|
+
/**
|
|
333
|
+
* Normalize a bullet-style AI commit suggestion into a deterministic on-disk
|
|
334
|
+
* format. Pure function — no side effects. The normalizer is deliberately
|
|
335
|
+
* conservative and content-preserving: it reformats whitespace/markers but
|
|
336
|
+
* never fabricates a subject and never drops body content.
|
|
337
|
+
*
|
|
338
|
+
* Contract:
|
|
339
|
+
* - Input is coerced via String(text); non-string input cannot throw.
|
|
340
|
+
* - CRLF (`\r\n`) and CR line endings are tolerated (trailing \r stripped).
|
|
341
|
+
* - Early return (input returned trimmed, unchanged) when the input has zero
|
|
342
|
+
* or one non-empty line — a bare title with no bullets, or empty input.
|
|
343
|
+
* - No-title passthrough: if the first non-empty line already starts with a
|
|
344
|
+
* bullet marker (`-` or `*`), the model produced bullets with no summary
|
|
345
|
+
* line. A deterministic normalizer must not invent a subject, so the input
|
|
346
|
+
* is returned trimmed and otherwise unchanged.
|
|
347
|
+
* - Otherwise the first non-empty line becomes the title (trailing whitespace
|
|
348
|
+
* stripped; no marker stripping — it is not a marker line by definition).
|
|
349
|
+
* - Each subsequent non-empty line that starts with a bullet marker becomes
|
|
350
|
+
* " - <content>" (exactly two-space indent, single dash; the original
|
|
351
|
+
* marker and leading indentation are stripped).
|
|
352
|
+
* - Each subsequent non-empty line that does NOT start with a marker is a
|
|
353
|
+
* soft-wrapped continuation of the previous line: it is appended to the
|
|
354
|
+
* previous bullet (joined with a single space). If no bullet exists yet,
|
|
355
|
+
* it is appended to the title line instead.
|
|
356
|
+
* - Blank lines between the title and bullets (and trailing blanks) are
|
|
357
|
+
* dropped.
|
|
358
|
+
* @param {string} text - raw AI suggestion (already trimmed/quote-stripped)
|
|
359
|
+
* @returns {string} normalized bullet-style message
|
|
360
|
+
*/
|
|
361
|
+
function normalizeBulletMessage(text) {
|
|
362
|
+
const source = String(text);
|
|
363
|
+
// Normalize line endings so \r\n / \r inputs behave identically to \n.
|
|
364
|
+
const lines = source.split(/\r\n|\r|\n/);
|
|
365
|
+
|
|
366
|
+
// Guard: zero or one non-empty line (empty input or a bare title) is left
|
|
367
|
+
// untouched apart from outer trimming.
|
|
368
|
+
if (lines.filter(l => l.trim() !== '').length <= 1) {
|
|
369
|
+
return source.trim();
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// No-title passthrough: the model emitted bullets with no summary line. Do
|
|
373
|
+
// not promote a bullet to a title — return the input trimmed, unchanged.
|
|
374
|
+
const firstNonEmpty = lines.find(l => l.trim() !== '');
|
|
375
|
+
if (/^\s*[-*]\s+/.test(firstNonEmpty)) {
|
|
376
|
+
return source.trim();
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const isMarker = (line) => /^\s*[-*]\s+/.test(line);
|
|
380
|
+
const stripMarker = (line) => line.replace(/^\s*[-*]\s+/, '').trim();
|
|
381
|
+
|
|
382
|
+
const out = [];
|
|
383
|
+
let titleSet = false;
|
|
384
|
+
for (const raw of lines) {
|
|
385
|
+
const line = raw.replace(/\s+$/, '');
|
|
386
|
+
if (line.trim() === '') continue;
|
|
387
|
+
if (!titleSet) {
|
|
388
|
+
// First non-empty line is the title (guaranteed non-marker above).
|
|
389
|
+
out.push(line.trim());
|
|
390
|
+
titleSet = true;
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
if (isMarker(line)) {
|
|
394
|
+
out.push(' - ' + stripMarker(line));
|
|
395
|
+
} else {
|
|
396
|
+
// Soft-wrapped continuation: append to the previous line.
|
|
397
|
+
out[out.length - 1] = out[out.length - 1] + ' ' + line.trim();
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return out.join('\n');
|
|
401
|
+
}
|
|
402
|
+
|
|
332
403
|
/**
|
|
333
404
|
* Get AI commit message suggestion
|
|
334
405
|
* @param {Object} gitInfo - Git information object
|
|
@@ -466,20 +537,31 @@ async function getAICommitSuggestion(gitInfo) {
|
|
|
466
537
|
}
|
|
467
538
|
|
|
468
539
|
// Create AI prompt based on commit message style
|
|
540
|
+
//
|
|
541
|
+
// ⚠️ MAI-108 PROMPT CHANGE / ROLLBACK POINT: the bullet prompt below was
|
|
542
|
+
// rewritten (placeholders + anti-leak/anti-invent guard) because small/local
|
|
543
|
+
// models echoed the old few-shot example bullets verbatim. The PREVIOUS,
|
|
544
|
+
// long-standing prompt is production-proven against the 1min.ai chat path.
|
|
545
|
+
// If hosted-model commit-message QUALITY regresses, revert this block to its
|
|
546
|
+
// pre-change form: see git history of this file before commit dca4519 (PR #28).
|
|
469
547
|
let prompt;
|
|
470
548
|
if (commitMessageStyle === 'bullet') {
|
|
471
|
-
prompt = `
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
-
|
|
475
|
-
-
|
|
476
|
-
|
|
477
|
-
|
|
549
|
+
prompt = `Write a git commit message for the diff below.
|
|
550
|
+
Format exactly like this template:
|
|
551
|
+
<one-line summary>
|
|
552
|
+
- <type>: <description>
|
|
553
|
+
- <type>: <description>
|
|
554
|
+
Rules:
|
|
555
|
+
- First line: a brief past-tense summary with no leading dash.
|
|
556
|
+
- Then one or more bullet lines, each indented by exactly two spaces, starting with "- ", then a conventional-commit type (feat, fix, docs, refactor, chore) and a colon.
|
|
557
|
+
- No blank line between the summary line and the bullets.
|
|
558
|
+
- Describe ONLY the actual changes in the diff. Do not output the literal words type or description or any angle brackets, and do not invent changes that are not in the diff.
|
|
559
|
+
- Do not wrap the response in quotes.
|
|
478
560
|
|
|
479
561
|
Git diff:
|
|
480
562
|
${gitDiff}`;
|
|
481
563
|
} else {
|
|
482
|
-
prompt = `Analyze the following git diff and create a concise, descriptive commit message. Use conventional commit format when appropriate (feat:, fix:, docs:, etc.). Keep it under 72 characters for the first line.
|
|
564
|
+
prompt = `Analyze the following git diff and create a concise, descriptive commit message. Use conventional commit format when appropriate (feat:, fix:, docs:, etc.). Keep it under 72 characters for the first line. Describe only the actual changes in the diff; do not invent changes.
|
|
483
565
|
|
|
484
566
|
Git diff:
|
|
485
567
|
${gitDiff}`;
|
|
@@ -577,11 +659,16 @@ ${gitDiff}`;
|
|
|
577
659
|
}
|
|
578
660
|
|
|
579
661
|
// Clean up any quotes that might wrap the entire response
|
|
580
|
-
if ((suggestion.startsWith("'") && suggestion.endsWith("'")) ||
|
|
662
|
+
if ((suggestion.startsWith("'") && suggestion.endsWith("'")) ||
|
|
581
663
|
(suggestion.startsWith('"') && suggestion.endsWith('"'))) {
|
|
582
664
|
suggestion = suggestion.slice(1, -1).trim();
|
|
583
665
|
}
|
|
584
|
-
|
|
666
|
+
|
|
667
|
+
// Deterministically normalize bullet format so it's model-independent.
|
|
668
|
+
if (commitMessageStyle === 'bullet') {
|
|
669
|
+
suggestion = normalizeBulletMessage(suggestion);
|
|
670
|
+
}
|
|
671
|
+
|
|
585
672
|
// Extract credit information from billing data
|
|
586
673
|
let creditsUsed, creditsRemaining;
|
|
587
674
|
if (data.billing) {
|
|
@@ -1157,6 +1244,7 @@ export {
|
|
|
1157
1244
|
getCommitMessage,
|
|
1158
1245
|
handleStagedCommit,
|
|
1159
1246
|
getAICommitSuggestion,
|
|
1247
|
+
normalizeBulletMessage,
|
|
1160
1248
|
executeGitCommand,
|
|
1161
1249
|
remoteExists
|
|
1162
1250
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "maiass",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "5.15.
|
|
4
|
+
"version": "5.15.13",
|
|
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": {
|
|
@@ -21,6 +21,11 @@
|
|
|
21
21
|
# - Create an app password with Repositories: Read & Write scope
|
|
22
22
|
# - Add it as a repository variable named BB_APP_PASSWORD (secured)
|
|
23
23
|
# - Add your Bitbucket username as BB_USERNAME
|
|
24
|
+
#
|
|
25
|
+
# Missing-credential behaviour:
|
|
26
|
+
# If BB_USERNAME / BB_APP_PASSWORD are not set, a preflight (by default) fails
|
|
27
|
+
# the step with a clear message. To instead skip with a warning and pass, set
|
|
28
|
+
# MAIASS_CI_FAIL_SILENTLY to "true" on the first line of the script below.
|
|
24
29
|
|
|
25
30
|
pipelines:
|
|
26
31
|
branches:
|
|
@@ -29,6 +34,29 @@ pipelines:
|
|
|
29
34
|
name: MAIASS Version Bump
|
|
30
35
|
image: node:20
|
|
31
36
|
script:
|
|
37
|
+
# Bitbucket doesn't reliably export a step-level variables: block to
|
|
38
|
+
# the script, so these are exported here instead.
|
|
39
|
+
# Disable AI so CI runs consume no credits (the CLI also self-guards
|
|
40
|
+
# via CI detection, but keep this explicit and effective).
|
|
41
|
+
- export MAIASS_AI_MODE="off"
|
|
42
|
+
# Edit to "true" to skip with a warning instead of failing when the
|
|
43
|
+
# push credential is missing.
|
|
44
|
+
- export MAIASS_CI_FAIL_SILENTLY="false"
|
|
45
|
+
# Preflight: BB_USERNAME/BB_APP_PASSWORD are required to push the
|
|
46
|
+
# bump back. Behaviour when missing is controlled by
|
|
47
|
+
# MAIASS_CI_FAIL_SILENTLY above: false (default) fails the step;
|
|
48
|
+
# true skips with a warning.
|
|
49
|
+
- |
|
|
50
|
+
if [ -z "$BB_USERNAME" ] || [ -z "$BB_APP_PASSWORD" ]; then
|
|
51
|
+
MSG="BB_USERNAME / BB_APP_PASSWORD repository variables are not set — add them (app password with Repositories: Read & Write) to enable automatic version bumping."
|
|
52
|
+
if [ "$MAIASS_CI_FAIL_SILENTLY" = "true" ]; then
|
|
53
|
+
echo "WARNING: $MSG Skipping version bump."
|
|
54
|
+
exit 0
|
|
55
|
+
else
|
|
56
|
+
echo "ERROR: $MSG"
|
|
57
|
+
exit 1
|
|
58
|
+
fi
|
|
59
|
+
fi
|
|
32
60
|
# Guard: skip if last commit was already a version bump
|
|
33
61
|
- |
|
|
34
62
|
LAST_MSG=$(git log -1 --pretty=format:'%s')
|
|
@@ -42,5 +70,3 @@ pipelines:
|
|
|
42
70
|
# Authenticate push via app password
|
|
43
71
|
- git remote set-url origin "https://${BB_USERNAME}:${BB_APP_PASSWORD}@bitbucket.org/${BITBUCKET_REPO_FULL_NAME}.git"
|
|
44
72
|
- maiass -a patch
|
|
45
|
-
variables:
|
|
46
|
-
MAIASS_AI_MODE: "off" # Disable AI — no credits used in CI
|
|
@@ -17,6 +17,11 @@
|
|
|
17
17
|
# 3. Add the PAT as a repository secret named GH_PAT
|
|
18
18
|
#
|
|
19
19
|
# Notes:
|
|
20
|
+
# - If the GH_PAT secret is missing, this workflow runs a preflight that, by
|
|
21
|
+
# default, fails with a clear message (the merge itself is unaffected — this
|
|
22
|
+
# runs after merge). To instead skip with a warning and keep the run green,
|
|
23
|
+
# set MAIASS_CI_FAIL_SILENTLY to "true" in the preflight step's env: block
|
|
24
|
+
# below.
|
|
20
25
|
# - AI is disabled (MAIASS_AI_MODE: off) so no credits are used.
|
|
21
26
|
# - The branch name below is substituted at install time from
|
|
22
27
|
# MAIASS_DEVELOPBRANCH. GitHub Actions requires `on.pull_request.branches`
|
|
@@ -43,12 +48,46 @@ jobs:
|
|
|
43
48
|
contents: write # Required to push the version bump commit
|
|
44
49
|
|
|
45
50
|
steps:
|
|
51
|
+
# Preflight: this workflow runs AFTER the PR is merged, so a missing
|
|
52
|
+
# GH_PAT can't block the merge — but it would fail the checkout/push with
|
|
53
|
+
# a confusing auth error on every merge. Detect the empty secret up front
|
|
54
|
+
# and emit a clear, actionable message. Behaviour is controlled by the
|
|
55
|
+
# MAIASS_CI_FAIL_SILENTLY env var below:
|
|
56
|
+
# false (default) — fail the run so the missing secret is noticed.
|
|
57
|
+
# true — skip with a warning; the run stays green.
|
|
58
|
+
- name: Check GH_PAT secret
|
|
59
|
+
id: preflight
|
|
60
|
+
env:
|
|
61
|
+
GH_PAT: ${{ secrets.GH_PAT }}
|
|
62
|
+
# Edit this to "true" to skip with a warning instead of failing when
|
|
63
|
+
# GH_PAT is missing.
|
|
64
|
+
MAIASS_CI_FAIL_SILENTLY: "false"
|
|
65
|
+
run: |
|
|
66
|
+
if [ -n "$GH_PAT" ]; then
|
|
67
|
+
exit 0
|
|
68
|
+
fi
|
|
69
|
+
MSG="GH_PAT secret is not set, so the version bump cannot be pushed back to the repo. Add a fine-grained PAT as a repo secret named GH_PAT (Settings → Secrets → Actions) with Contents: Read & Write, Metadata: Read-only, Workflows: Read & Write."
|
|
70
|
+
{
|
|
71
|
+
echo "### ⚠️ MAIASS version bump — GH_PAT missing"
|
|
72
|
+
echo ""
|
|
73
|
+
echo "$MSG"
|
|
74
|
+
} >> "$GITHUB_STEP_SUMMARY"
|
|
75
|
+
if [ "$MAIASS_CI_FAIL_SILENTLY" = "true" ]; then
|
|
76
|
+
echo "::warning title=MAIASS version bump skipped::$MSG"
|
|
77
|
+
echo "skip=true" >> "$GITHUB_OUTPUT"
|
|
78
|
+
else
|
|
79
|
+
echo "::error title=MAIASS version bump failed::$MSG"
|
|
80
|
+
exit 1
|
|
81
|
+
fi
|
|
82
|
+
|
|
46
83
|
- uses: actions/checkout@v4
|
|
84
|
+
if: steps.preflight.outputs.skip != 'true'
|
|
47
85
|
with:
|
|
48
86
|
fetch-depth: 0 # Full history needed for changelog generation
|
|
49
87
|
token: ${{ secrets.GH_PAT }} # PAT allows the bot to push back to the repo
|
|
50
88
|
|
|
51
89
|
- uses: actions/setup-node@v4
|
|
90
|
+
if: steps.preflight.outputs.skip != 'true'
|
|
52
91
|
with:
|
|
53
92
|
node-version: '24'
|
|
54
93
|
# No cache: this workflow only does `npm install -g maiass`, which
|
|
@@ -57,9 +96,11 @@ jobs:
|
|
|
57
96
|
# WordPress/PHP plugins): "Dependencies lock file is not found".
|
|
58
97
|
|
|
59
98
|
- name: Install maiass
|
|
99
|
+
if: steps.preflight.outputs.skip != 'true'
|
|
60
100
|
run: npm install -g maiass --no-fund --no-audit
|
|
61
101
|
|
|
62
102
|
- name: Configure git
|
|
103
|
+
if: steps.preflight.outputs.skip != 'true'
|
|
63
104
|
run: |
|
|
64
105
|
git config user.name "github-actions[bot]"
|
|
65
106
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
@@ -67,9 +108,11 @@ jobs:
|
|
|
67
108
|
# Explicitly check out the develop branch head (the pull_request closed
|
|
68
109
|
# event checks out a merge ref, not the branch itself)
|
|
69
110
|
- name: Checkout __MAIASS_DEVELOPBRANCH__
|
|
111
|
+
if: steps.preflight.outputs.skip != 'true'
|
|
70
112
|
run: git checkout __MAIASS_DEVELOPBRANCH__
|
|
71
113
|
|
|
72
114
|
- name: Bump version
|
|
115
|
+
if: steps.preflight.outputs.skip != 'true'
|
|
73
116
|
run: maiass -a patch
|
|
74
117
|
env:
|
|
75
118
|
# Quoted: unquoted `off` is a YAML boolean that GitHub stringifies to
|
|
@@ -17,6 +17,11 @@
|
|
|
17
17
|
# Double-bump protection:
|
|
18
18
|
# The script checks the last commit author and skips if it was already made
|
|
19
19
|
# by the CI bot — preventing an infinite loop of version bumps.
|
|
20
|
+
#
|
|
21
|
+
# Missing-token behaviour:
|
|
22
|
+
# If GITLAB_TOKEN is not set, a preflight (by default) fails the job with a
|
|
23
|
+
# clear message. To instead skip with a warning and pass, set
|
|
24
|
+
# MAIASS_CI_FAIL_SILENTLY to "true" in the variables: block below.
|
|
20
25
|
|
|
21
26
|
stages:
|
|
22
27
|
- version
|
|
@@ -27,6 +32,20 @@ maiass-version-bump:
|
|
|
27
32
|
only:
|
|
28
33
|
- __MAIASS_DEVELOPBRANCH__
|
|
29
34
|
script:
|
|
35
|
+
# Preflight: GITLAB_TOKEN is required to push the bump back. Behaviour when
|
|
36
|
+
# it's missing is controlled by MAIASS_CI_FAIL_SILENTLY in the variables:
|
|
37
|
+
# block below: false (default) fails the job; true skips with a warning.
|
|
38
|
+
- |
|
|
39
|
+
if [ -z "$GITLAB_TOKEN" ]; then
|
|
40
|
+
MSG="GITLAB_TOKEN CI/CD variable is not set — add it (masked, protected) with write access to enable automatic version bumping."
|
|
41
|
+
if [ "$MAIASS_CI_FAIL_SILENTLY" = "true" ]; then
|
|
42
|
+
echo "WARNING: $MSG Skipping version bump."
|
|
43
|
+
exit 0
|
|
44
|
+
else
|
|
45
|
+
echo "ERROR: $MSG"
|
|
46
|
+
exit 1
|
|
47
|
+
fi
|
|
48
|
+
fi
|
|
30
49
|
# Skip if the last commit was already a version bump from this pipeline
|
|
31
50
|
- |
|
|
32
51
|
LAST_AUTHOR=$(git log -1 --pretty=format:'%an')
|
|
@@ -43,3 +62,5 @@ maiass-version-bump:
|
|
|
43
62
|
- maiass -a patch
|
|
44
63
|
variables:
|
|
45
64
|
MAIASS_AI_MODE: "off" # Disable AI — no credits used in CI
|
|
65
|
+
# Missing GITLAB_TOKEN: "false" fails the job, "true" skips with a warning.
|
|
66
|
+
MAIASS_CI_FAIL_SILENTLY: "false"
|