@1aboveio/skills 1.0.8 → 1.0.10

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.
Files changed (214) hide show
  1. package/.codex-plugin/plugin.json +13 -0
  2. package/.codex-plugin/resources.json +1827 -0
  3. package/README.md +22 -0
  4. package/package.json +9 -2
  5. package/skills/app-dev/airflow/SKILL.md +1 -1
  6. package/skills/app-dev/airflow/release-check.mjs +3 -1
  7. package/skills/app-dev/android-foundation/SKILL.md +1 -1
  8. package/skills/app-dev/android-foundation/release-check.mjs +3 -1
  9. package/skills/app-dev/app-debug/SKILL.md +1 -1
  10. package/skills/app-dev/app-debug/release-check.mjs +3 -1
  11. package/skills/app-dev/better-auth/SKILL.md +1 -1
  12. package/skills/app-dev/better-auth/release-check.mjs +3 -1
  13. package/skills/app-dev/data-catalog/SKILL.md +1 -1
  14. package/skills/app-dev/data-catalog/release-check.mjs +3 -1
  15. package/skills/app-dev/data-quality/SKILL.md +1 -1
  16. package/skills/app-dev/data-quality/release-check.mjs +3 -1
  17. package/skills/app-dev/ios-foundation/SKILL.md +1 -1
  18. package/skills/app-dev/ios-foundation/release-check.mjs +3 -1
  19. package/skills/app-dev/monorepo/SKILL.md +1 -1
  20. package/skills/app-dev/monorepo/release-check.mjs +3 -1
  21. package/skills/app-dev/nextjs-fullstack/SKILL.md +1 -1
  22. package/skills/app-dev/nextjs-fullstack/release-check.mjs +3 -1
  23. package/skills/app-dev/prisma-setup/SKILL.md +1 -1
  24. package/skills/app-dev/prisma-setup/release-check.mjs +3 -1
  25. package/skills/app-dev/pyspark/SKILL.md +1 -1
  26. package/skills/app-dev/pyspark/release-check.mjs +3 -1
  27. package/skills/app-dev/python-backend/SKILL.md +1 -1
  28. package/skills/app-dev/python-backend/release-check.mjs +3 -1
  29. package/skills/app-dev/shadcn/SKILL.md +1 -1
  30. package/skills/app-dev/shadcn/release-check.mjs +3 -1
  31. package/skills/app-dev/zod-v4/SKILL.md +1 -1
  32. package/skills/app-dev/zod-v4/release-check.mjs +3 -1
  33. package/skills/cicd/cloud-build/SKILL.md +1 -1
  34. package/skills/cicd/cloud-build/release-check.mjs +3 -1
  35. package/skills/cicd/cloud-debug/SKILL.md +1 -1
  36. package/skills/cicd/cloud-debug/release-check.mjs +3 -1
  37. package/skills/cicd/cloud-deploy/SKILL.md +1 -1
  38. package/skills/cicd/cloud-deploy/release-check.mjs +3 -1
  39. package/skills/cicd/docker/SKILL.md +1 -1
  40. package/skills/cicd/docker/release-check.mjs +3 -1
  41. package/skills/cicd/github-actions/SKILL.md +1 -1
  42. package/skills/cicd/github-actions/release-check.mjs +3 -1
  43. package/skills/cicd/github-flow/SKILL.md +1 -1
  44. package/skills/cicd/github-flow/release-check.mjs +3 -1
  45. package/skills/cicd/google-cloud/SKILL.md +1 -1
  46. package/skills/cicd/google-cloud/release-check.mjs +3 -1
  47. package/skills/cicd/mergify/SKILL.md +1 -1
  48. package/skills/cicd/mergify/release-check.mjs +3 -1
  49. package/skills/cicd/podman/SKILL.md +1 -1
  50. package/skills/cicd/podman/release-check.mjs +3 -1
  51. package/skills/content/article-review/SKILL.md +1 -1
  52. package/skills/content/article-review/release-check.mjs +3 -1
  53. package/skills/content/article-to-image/SKILL.md +1 -1
  54. package/skills/content/article-to-image/release-check.mjs +3 -1
  55. package/skills/content/flowchart-svg/SKILL.md +1 -1
  56. package/skills/content/flowchart-svg/release-check.mjs +3 -1
  57. package/skills/content/image-gen/SKILL.md +1 -1
  58. package/skills/content/image-gen/release-check.mjs +3 -1
  59. package/skills/content/mermaid/SKILL.md +1 -1
  60. package/skills/content/mermaid/release-check.mjs +3 -1
  61. package/skills/content/wechat-article-writer/SKILL.md +1 -1
  62. package/skills/content/wechat-article-writer/release-check.mjs +3 -1
  63. package/skills/content/wechat-publisher/SKILL.md +1 -1
  64. package/skills/content/wechat-publisher/release-check.mjs +3 -1
  65. package/skills/content/wechat-search/SKILL.md +1 -1
  66. package/skills/content/wechat-search/release-check.mjs +3 -1
  67. package/skills/content/xai-search/SKILL.md +88 -13
  68. package/skills/content/xai-search/release-check.mjs +3 -1
  69. package/skills/content/xai-search/scripts/xai_search.sh +125 -149
  70. package/skills/core/distill-writing/SKILL.md +1 -1
  71. package/skills/core/distill-writing/release-check.mjs +3 -1
  72. package/skills/core/doc-to-md/SKILL.md +1 -1
  73. package/skills/core/doc-to-md/release-check.mjs +3 -1
  74. package/skills/core/editorial-review/SKILL.md +1 -1
  75. package/skills/core/editorial-review/release-check.mjs +3 -1
  76. package/skills/core/house-style/SKILL.md +1 -1
  77. package/skills/core/house-style/release-check.mjs +3 -1
  78. package/skills/core/plain-language/SKILL.md +1 -1
  79. package/skills/core/plain-language/release-check.mjs +3 -1
  80. package/skills/core/polish-cn/SKILL.md +1 -1
  81. package/skills/core/polish-cn/release-check.mjs +3 -1
  82. package/skills/core/reg-parser/SKILL.md +1 -1
  83. package/skills/core/reg-parser/release-check.mjs +3 -1
  84. package/skills/core/terminology/SKILL.md +1 -1
  85. package/skills/core/terminology/release-check.mjs +3 -1
  86. package/skills/core/write-doc/SKILL.md +1 -1
  87. package/skills/core/write-doc/release-check.mjs +3 -1
  88. package/skills/engineering/better-review/SKILL.md +1 -1
  89. package/skills/engineering/better-review/release-check.mjs +3 -1
  90. package/skills/engineering/contributing/SKILL.md +1 -1
  91. package/skills/engineering/contributing/release-check.mjs +3 -1
  92. package/skills/engineering/e2e-test/SKILL.md +1 -1
  93. package/skills/engineering/e2e-test/release-check.mjs +3 -1
  94. package/skills/engineering/engineering-runtime/SKILL.md +1 -1
  95. package/skills/engineering/engineering-runtime/coherence/workflow.json +13 -13
  96. package/skills/engineering/engineering-runtime/release-check.mjs +3 -1
  97. package/skills/engineering/engineering-runtime/scripts/installation-resolver.mjs +191 -0
  98. package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +51 -10
  99. package/skills/engineering/ensure-coverage/SKILL.md +1 -1
  100. package/skills/engineering/ensure-coverage/release-check.mjs +3 -1
  101. package/skills/engineering/golden-path/SKILL.md +1 -1
  102. package/skills/engineering/golden-path/release-check.mjs +3 -1
  103. package/skills/engineering/harness-runtime/SKILL.md +1 -1
  104. package/skills/engineering/harness-runtime/release-check.mjs +3 -1
  105. package/skills/engineering/resolve-issues/SKILL.md +1 -1
  106. package/skills/engineering/resolve-issues/references/preflight.md +7 -0
  107. package/skills/engineering/resolve-issues/references/shared-modules.md +27 -0
  108. package/skills/engineering/resolve-issues/references/task-plan.md +5 -1
  109. package/skills/engineering/resolve-issues/release-check.mjs +3 -1
  110. package/skills/engineering/resolve-issues/scripts/active-installation.mjs +32 -0
  111. package/skills/engineering/resolve-issues/scripts/install-hooks.mjs +3 -0
  112. package/skills/engineering/resolve-issues/scripts/rehydrate.mjs +17 -1
  113. package/skills/engineering/resolve-release/SKILL.md +1 -1
  114. package/skills/engineering/resolve-release/release-check.mjs +3 -1
  115. package/skills/engineering/rush-issues/SKILL.md +1 -1
  116. package/skills/engineering/rush-issues/release-check.mjs +3 -1
  117. package/skills/engineering/rush-release/SKILL.md +1 -1
  118. package/skills/engineering/rush-release/release-check.mjs +3 -1
  119. package/skills/engineering/test-quality/SKILL.md +1 -1
  120. package/skills/engineering/test-quality/release-check.mjs +3 -1
  121. package/skills/risk-compliance/compliance-audit/SKILL.md +1 -1
  122. package/skills/risk-compliance/compliance-audit/release-check.mjs +3 -1
  123. package/skills/risk-compliance/contract-compare/SKILL.md +1 -1
  124. package/skills/risk-compliance/contract-compare/release-check.mjs +3 -1
  125. package/skills/risk-compliance/contract-review/SKILL.md +1 -1
  126. package/skills/risk-compliance/contract-review/release-check.mjs +3 -1
  127. package/skills/risk-compliance/doc-authenticity/SKILL.md +1 -1
  128. package/skills/risk-compliance/doc-authenticity/release-check.mjs +3 -1
  129. package/skills/risk-compliance/fraud-analysis/SKILL.md +1 -1
  130. package/skills/risk-compliance/fraud-analysis/release-check.mjs +3 -1
  131. package/skills/risk-compliance/payment-analysis/SKILL.md +1 -1
  132. package/skills/risk-compliance/payment-analysis/release-check.mjs +3 -1
  133. package/skills/risk-compliance/similar-domain/SKILL.md +1 -1
  134. package/skills/risk-compliance/similar-domain/release-check.mjs +3 -1
  135. package/skills/risk-compliance/tld-detection/SKILL.md +1 -1
  136. package/skills/risk-compliance/tld-detection/release-check.mjs +3 -1
  137. package/skills/app-dev/android-foundation/scripts/device-run.test.mjs +0 -436
  138. package/skills/app-dev/data-catalog/scripts/data-catalog.test.mjs +0 -36
  139. package/skills/app-dev/data-quality/scripts/data-quality.test.mjs +0 -12
  140. package/skills/cicd/github-actions/scripts/ci-run-audit.test.mjs +0 -637
  141. package/skills/cicd/github-flow/scripts/flow.test.mjs +0 -114
  142. package/skills/cicd/github-flow/scripts/persist-conventions.test.mjs +0 -108
  143. package/skills/cicd/mergify/scripts/audit.test.mjs +0 -201
  144. package/skills/cicd/mergify/scripts/entrypoints.test.mjs +0 -106
  145. package/skills/cicd/mergify/scripts/pr-620-mergify-comments.fixture.json +0 -30
  146. package/skills/cicd/mergify/scripts/stack-push.test.mjs +0 -233
  147. package/skills/cicd/mergify/scripts/watch-pr-delivery.test.mjs +0 -1826
  148. package/skills/content/image-gen/scripts/credentials.test.mjs +0 -212
  149. package/skills/content/image-gen/scripts/options.test.mjs +0 -245
  150. package/skills/content/xai-search/tests/smoke_test.sh +0 -36
  151. package/skills/core/polish-cn/scripts/polish-cn.test.mjs +0 -244
  152. package/skills/core/reg-parser/scripts/reg-parser.test.mjs +0 -165
  153. package/skills/engineering/better-review/scripts/pr-context.test.mjs +0 -168
  154. package/skills/engineering/better-review/scripts/rereview-scope.test.mjs +0 -587
  155. package/skills/engineering/better-review/scripts/scan-diff.test.mjs +0 -414
  156. package/skills/engineering/better-review/scripts/vendor-sync.test.mjs +0 -96
  157. package/skills/engineering/contributing/scripts/persist-conventions.test.mjs +0 -118
  158. package/skills/engineering/e2e-test/scripts/presentation-checks.test.mjs +0 -106
  159. package/skills/engineering/e2e-test/scripts/presentation-perceivability.test.mjs +0 -117
  160. package/skills/engineering/e2e-test/scripts/presentation-reachability.test.mjs +0 -69
  161. package/skills/engineering/e2e-test/scripts/presentation-render-health.test.mjs +0 -98
  162. package/skills/engineering/e2e-test/scripts/presentation-sweep.test.mjs +0 -71
  163. package/skills/engineering/e2e-test/scripts/presentation-temporal.test.mjs +0 -59
  164. package/skills/engineering/e2e-test/scripts/project-route-manifest.test.mjs +0 -76
  165. package/skills/engineering/engineering-runtime/engineering-runtime.test.mjs +0 -68
  166. package/skills/engineering/engineering-runtime/scripts/invocation-policy.test.mjs +0 -95
  167. package/skills/engineering/engineering-runtime/scripts/main-module.test.mjs +0 -288
  168. package/skills/engineering/engineering-runtime/scripts/required-check-plan.test.mjs +0 -96
  169. package/skills/engineering/ensure-coverage/scripts/adapters/nextjs-inventory.test.mjs +0 -96
  170. package/skills/engineering/ensure-coverage/scripts/check-quarantine-expiry.test.mjs +0 -47
  171. package/skills/engineering/ensure-coverage/scripts/ci-audit.test.mjs +0 -86
  172. package/skills/engineering/ensure-coverage/scripts/coverage-ledger.test.mjs +0 -447
  173. package/skills/engineering/ensure-coverage/scripts/design-parity.test.mjs +0 -552
  174. package/skills/engineering/ensure-coverage/scripts/lint-tests.test.mjs +0 -289
  175. package/skills/engineering/ensure-coverage/scripts/mock-policy-config.test.mjs +0 -119
  176. package/skills/engineering/golden-path/scripts/golden-path.test.mjs +0 -1457
  177. package/skills/engineering/harness-runtime/discover-models.test.mjs +0 -363
  178. package/skills/engineering/harness-runtime/harness-runtime.test.mjs +0 -967
  179. package/skills/engineering/harness-runtime/model-catalog-seed.test.mjs +0 -829
  180. package/skills/engineering/harness-runtime/model-catalog.test.mjs +0 -366
  181. package/skills/engineering/resolve-issues/scripts/cleanup-runs.test.mjs +0 -280
  182. package/skills/engineering/resolve-issues/scripts/dropbox.test.mjs +0 -346
  183. package/skills/engineering/resolve-issues/scripts/findings-reuse.test.mjs +0 -88
  184. package/skills/engineering/resolve-issues/scripts/github-reviews.test.mjs +0 -264
  185. package/skills/engineering/resolve-issues/scripts/install-hooks.test.mjs +0 -79
  186. package/skills/engineering/resolve-issues/scripts/issue-tree.test.mjs +0 -107
  187. package/skills/engineering/resolve-issues/scripts/manual-invocation.test.mjs +0 -14
  188. package/skills/engineering/resolve-issues/scripts/next-actions-capacity.test.mjs +0 -149
  189. package/skills/engineering/resolve-issues/scripts/next-actions.test.mjs +0 -915
  190. package/skills/engineering/resolve-issues/scripts/plan-sync.test.mjs +0 -156
  191. package/skills/engineering/resolve-issues/scripts/preflight-models.test.mjs +0 -448
  192. package/skills/engineering/resolve-issues/scripts/ready-check.test.mjs +0 -217
  193. package/skills/engineering/resolve-issues/scripts/rehydrate.test.mjs +0 -91
  194. package/skills/engineering/resolve-issues/scripts/review-verdict.test.mjs +0 -1060
  195. package/skills/engineering/resolve-issues/scripts/size-check.test.mjs +0 -458
  196. package/skills/engineering/resolve-release/scripts/apply.test.mjs +0 -99
  197. package/skills/engineering/resolve-release/scripts/dark-flags.test.mjs +0 -100
  198. package/skills/engineering/resolve-release/scripts/flow.test.mjs +0 -340
  199. package/skills/engineering/resolve-release/scripts/green-head.test.mjs +0 -101
  200. package/skills/engineering/resolve-release/scripts/npm-version-absence.test.mjs +0 -426
  201. package/skills/engineering/resolve-release/scripts/plan-npm.test.mjs +0 -659
  202. package/skills/engineering/resolve-release/scripts/plan-toml-boundary.test.mjs +0 -317
  203. package/skills/engineering/resolve-release/scripts/plan-uv.test.mjs +0 -291
  204. package/skills/engineering/resolve-release/scripts/plan.test.mjs +0 -428
  205. package/skills/engineering/test-quality/scripts/lint-tests.test.mjs +0 -591
  206. package/skills/engineering/test-quality/scripts/mock-policy-config.test.mjs +0 -119
  207. package/skills/engineering/test-quality/scripts/persist-conventions.test.mjs +0 -104
  208. package/skills/risk-compliance/compliance-audit/scripts/compliance-audit.test.mjs +0 -14
  209. package/skills/risk-compliance/doc-authenticity/manual-invocation.test.mjs +0 -12
  210. package/skills/risk-compliance/doc-authenticity/scripts/validate_verdict.test.mjs +0 -212
  211. package/skills/risk-compliance/tld-detection/scripts/detect_ladders.test.mjs +0 -14
  212. package/skills/risk-compliance/tld-detection/scripts/detect_streams.test.mjs +0 -14
  213. package/skills/risk-compliance/tld-detection/tests/test_detect_ladders.py +0 -134
  214. package/skills/risk-compliance/tld-detection/tests/test_detect_streams.py +0 -520
@@ -1,233 +0,0 @@
1
- // @covers mergify-stack-push
2
- // @level unit
3
- import { test } from 'node:test'
4
- import assert from 'node:assert/strict'
5
- import { EXIT, MIN_CLI_VERSION, REREAD_ATTEMPTS, parseArgs, pushArgs, pushedPrs, stackPush } from './stack-push-core.mjs'
6
-
7
- const HOOKS = '/repo/.git/hooks'
8
-
9
- const listJson = (entries) => JSON.stringify({ branch: 'feat/x', trunk: 'origin/main', entries })
10
- const entry = (sha, pr = null) => ({
11
- commit_sha: sha,
12
- title: `feat: ${sha}`,
13
- change_id: `I${sha}`,
14
- status: pr ? 'open' : 'no_pr',
15
- pull_number: pr,
16
- pull_url: pr ? `https://github.com/o/r/pull/${pr}` : null,
17
- })
18
-
19
- // A fake for the external CLIs (git, mergify, gh). `script` maps a command key to a queue of
20
- // results, so a test can return a different stack before and after the push.
21
- function harness(script, { hooks = true, version = { status: 0, stdout: `mergify ${MIN_CLI_VERSION}\n`, stderr: '' } } = {}) {
22
- const calls = []
23
- const queues = Object.fromEntries(Object.entries(script).map(([k, v]) => [k, [...v]]))
24
- const exec = (cmd, args) => {
25
- calls.push([cmd, ...args])
26
- if (cmd === 'git' && args[0] === 'config') return { status: 1, stdout: '', stderr: '' }
27
- if (cmd === 'mergify' && args[0] === '--version') return version
28
- if (cmd === 'git' && args.includes('--show-toplevel')) return { status: 0, stdout: '/repo\n', stderr: '' }
29
- if (cmd === 'git' && args.includes('--git-common-dir')) return { status: 0, stdout: '/repo/.git\n', stderr: '' }
30
- const key = cmd === 'mergify' ? `${args[0]} ${args[1]}` : `${cmd} ${args[0]} ${args[1]}`
31
- const queue = queues[key]
32
- if (!queue || queue.length === 0) throw new Error(`unexpected call: ${cmd} ${args.join(' ')}`)
33
- return queue.length > 1 ? queue.shift() : queue[0]
34
- }
35
- const out = { text: '', write(s) { this.text += s } }
36
- const err = { text: '', write(s) { this.text += s } }
37
- const exists = (path) => hooks && path === `${HOOKS}/mergify-hooks`
38
- const sleeps = []
39
- return { calls, sleeps, deps: { exec, exists, out, err, sleep: (ms) => sleeps.push(ms) }, out, err }
40
- }
41
-
42
- const ok = (stdout = '') => ({ status: 0, stdout, stderr: '' })
43
-
44
- test('refuses a repo without Mergify stack hooks and pushes nothing', () => {
45
- const h = harness({}, { hooks: false })
46
- assert.equal(stackPush([], h.deps), EXIT.NOT_STACK_REPO)
47
- assert.match(h.err.text, /git push.*gh pr create/)
48
- assert.ok(!h.calls.some((c) => c[0] === 'mergify'))
49
- })
50
-
51
- test('an older mergify CLI stops before reading or pushing the stack and names the upgrade', () => {
52
- const h = harness({}, { version: ok('mergify 2026.7.8.1\n') })
53
- assert.equal(stackPush([], h.deps), EXIT.OLD_CLI)
54
- assert.match(h.err.text, new RegExp(`2026\\.7\\.8\\.1.*${MIN_CLI_VERSION.replaceAll('.', '\\.')}.*brew upgrade mergify-cli`))
55
- assert.ok(!h.calls.some((c) => c[0] === 'mergify' && c[1] === 'stack'))
56
- })
57
-
58
- test('an unreadable mergify version warns and still pushes', () => {
59
- const h = harness({ 'stack list': [ok(listJson([entry('a1', 11)]))], 'stack push': [ok()] }, { version: { status: 1, stdout: '', stderr: 'boom' } })
60
- assert.equal(stackPush([], h.deps), EXIT.OK)
61
- assert.match(h.err.text, /could not read the mergify CLI version/)
62
- assert.ok(h.calls.some((c) => c[0] === 'mergify' && c[1] === 'stack' && c[2] === 'push'))
63
- })
64
-
65
- test('the minimum CLI version and newer ones push', () => {
66
- for (const v of [MIN_CLI_VERSION, '2026.11.1', '2027.1.2.1']) {
67
- const h = harness({ 'stack list': [ok(listJson([entry('a1', 11)]))], 'stack push': [ok()] }, { version: ok(`mergify ${v}\n`) })
68
- assert.equal(stackPush([], h.deps), EXIT.OK, v)
69
- }
70
- })
71
-
72
- test('a push that falls back to Depends-On warns that the stack is not GitHub-native', () => {
73
- const h = harness({
74
- 'stack list': [ok(listJson([entry('a1'), entry('b2')])), ok(listJson([entry('a1', 11), entry('b2', 12)]))],
75
- 'stack push': [{ status: 0, stdout: 'stack: not registered on GitHub (stacking API unavailable)\n', stderr: '' }],
76
- })
77
- assert.equal(stackPush([], h.deps), EXIT.OK)
78
- assert.match(h.err.text, /not a GitHub-native stack.*Depends-On.*delete_branch_on_merge/)
79
- })
80
-
81
- test('a native stack push prints no Depends-On warning', () => {
82
- const h = harness({
83
- 'stack list': [ok(listJson([entry('a1'), entry('b2')])), ok(listJson([entry('a1', 11), entry('b2', 12)]))],
84
- 'stack push': [ok()],
85
- })
86
- assert.equal(stackPush([], h.deps), EXIT.OK)
87
- assert.doesNotMatch(h.err.text, /not a GitHub-native stack/)
88
- })
89
-
90
- test('a commit without Change-Id stops before the push and names the amend fix', () => {
91
- const h = harness({
92
- 'stack list': [{ status: 7, stdout: '', stderr: 'mergify: `Change-Id:` line is missing on commit c0f001685487cf95174b01801366a390d20d3bd5\n' }],
93
- })
94
- assert.equal(stackPush([], h.deps), EXIT.FIX_COMMITS)
95
- assert.match(h.err.text, /c0f001685487.*git commit --amend --no-edit/)
96
- assert.ok(!h.calls.some((c) => c[1] === 'stack' && c[2] === 'push'))
97
- })
98
-
99
- test('an empty stack asks for a commit instead of pushing', () => {
100
- const h = harness({ 'stack list': [ok(listJson([]))] })
101
- assert.equal(stackPush([], h.deps), EXIT.FIX_COMMITS)
102
- assert.match(h.err.text, /no commits.*origin\/main/)
103
- })
104
-
105
- test('pushes with the trunk and kept PR bodies, never skips hooks, and reports every PR', () => {
106
- const h = harness({
107
- 'stack list': [ok(listJson([entry('aaa'), entry('bbb')])), ok(listJson([entry('aaa', 11), entry('bbb', 12)]))],
108
- 'stack push': [ok('[created] #11\n[created] #12\n')],
109
- })
110
- assert.equal(stackPush([], h.deps), EXIT.OK)
111
- const push = h.calls.find((c) => c[0] === 'mergify' && c[2] === 'push')
112
- assert.deepEqual(push.slice(3), ['--trunk', 'origin/main', '--keep-pull-request-title-and-body'])
113
- assert.ok(!h.calls.flat().includes('--no-verify'))
114
- assert.deepEqual(JSON.parse(h.out.text).prs.map((p) => p.pr), [11, 12])
115
- assert.match(h.err.text.trim().split('\n').at(-1), /2 PR\(s\): #11 #12$/)
116
- })
117
-
118
- test('a push that moves an open PR warns that its queue request is cancelled (fmm-express #1846)', () => {
119
- const moved = (pr) => ({ ...entry('new', pr), commit_sha: 'new' })
120
- const h = harness({
121
- 'stack list': [ok(listJson([entry('old', 1846), entry('kept', 1847)])), ok(listJson([moved(1846), entry('kept', 1847)]))],
122
- 'stack push': [ok()],
123
- })
124
- assert.equal(stackPush([], h.deps), EXIT.OK)
125
- assert.match(h.err.text, /new commits on #1846 cancel any Mergify queue request on them; requeue with --enqueue/)
126
- assert.doesNotMatch(h.err.text, /#1847 cancel/, 'an unchanged PR keeps its queue request')
127
- const fresh = harness({ 'stack list': [ok(listJson([entry('aaa')])), ok(listJson([entry('aaa', 9)]))], 'stack push': [ok()] })
128
- assert.equal(stackPush([], fresh.deps), EXIT.OK)
129
- assert.doesNotMatch(fresh.err.text, /cancel/, 'a new PR had no queue request')
130
- const requeued = harness({
131
- 'stack list': [ok(listJson([entry('old', 1846)])), ok(listJson([moved(1846)]))],
132
- 'stack push': [ok()],
133
- 'gh pr comment': [ok()],
134
- })
135
- assert.equal(stackPush(['--enqueue'], requeued.deps), EXIT.OK)
136
- assert.doesNotMatch(requeued.err.text, /cancel/, '--enqueue already requeues')
137
- })
138
-
139
- test('--enqueue comments on every stack PR after the push, in one pass', () => {
140
- const h = harness({
141
- 'stack list': [ok(listJson([entry('aaa')])), ok(listJson([entry('aaa', 21), entry('bbb', 22)]))],
142
- 'stack push': [ok()],
143
- 'gh pr comment': [ok()],
144
- })
145
- assert.equal(stackPush(['--enqueue'], h.deps), EXIT.OK)
146
- const comments = h.calls.filter((c) => c[0] === 'gh')
147
- assert.deepEqual(comments, [
148
- ['gh', 'pr', 'comment', '21', '--body', '@mergifyio queue'],
149
- ['gh', 'pr', 'comment', '22', '--body', '@mergifyio queue'],
150
- ])
151
- assert.ok(h.calls.indexOf(comments[0]) > h.calls.findIndex((c) => c[2] === 'push'))
152
- assert.deepEqual(JSON.parse(h.out.text).enqueued, [21, 22])
153
- })
154
-
155
- test('a rebase conflict reports how to continue and enqueues nothing', () => {
156
- const h = harness({
157
- 'stack list': [ok(listJson([entry('aaa', 31)]))],
158
- 'stack push': [{ status: 4, stdout: '', stderr: 'mergify: rebase failed — there may be conflicts\n' }],
159
- })
160
- assert.equal(stackPush(['--enqueue'], h.deps), EXIT.FAILED)
161
- assert.match(h.err.text, /git rebase --continue/)
162
- assert.ok(!h.calls.some((c) => c[0] === 'gh'))
163
- })
164
-
165
- test('a pushed commit left without a PR fails instead of reporting success', () => {
166
- const h = harness({
167
- 'stack list': [ok(listJson([entry('aaa')])), ok(listJson([entry('aaa', 41), entry('bbb')]))],
168
- 'stack push': [ok()],
169
- })
170
- assert.equal(stackPush([], h.deps), EXIT.FAILED)
171
- assert.match(h.err.text, /1 commit\(s\) have no PR: bbb/)
172
- assert.equal(h.calls.filter((c) => c[0] === 'mergify' && c[2] === 'list').length, 1 + REREAD_ATTEMPTS, 'fails only after every re-read')
173
- })
174
-
175
- test('a PR the stack list sees only on a later re-read is reported, not failed (ai #1766)', () => {
176
- // ai #1766 (2026-10-17): the push left no readable PR line and the first list lagged, so the
177
- // script failed a push whose PR a `stack list` showed seconds later.
178
- const h = harness({
179
- 'stack list': [ok(listJson([entry('aaa')])), ok(listJson([entry('aaa')])), ok(listJson([entry('aaa')])), ok(listJson([entry('aaa', 1766)]))],
180
- 'stack push': [ok(' ✓ read 1 pull request(s)\n')],
181
- })
182
- assert.equal(stackPush([], h.deps), EXIT.OK)
183
- assert.deepEqual(JSON.parse(h.out.text).prs.map((p) => p.pr), [1766])
184
- assert.equal(h.sleeps.length, 2, 'stops re-reading once every commit has its PR')
185
- })
186
-
187
- test('a fresh PR the follow-up stack list cannot see yet is taken from the push output', () => {
188
- // fmm-express #1816 and ai #1756 (2026-10-16): the push created the PR, but `stack list` read
189
- // straight after still had pull_number null, so the script failed a push that had succeeded.
190
- const sha = 'ceb8e142d8840a35e4d109523f985713e94c3ab3'
191
- // The exact text a real push printed (ai #1757): no sha, a middle dot, and tabs.
192
- const plan = ' ✓ read 1 pull request(s)\n ✓ branch `feat/x` rebased on `origin/main`\n · [created]\t\thttps://github.com/o/r/pull/1816\tfeat: ceb8e142d8840a35e4d109523f985713e94c3ab3\nAlready up to date.\n'
193
- const h = harness({ 'stack list': [ok(listJson([entry(sha)])), ok(listJson([entry(sha)]))], 'stack push': [ok(plan)] })
194
- assert.equal(stackPush([], h.deps), EXIT.OK)
195
- const result = JSON.parse(h.out.text)
196
- assert.equal(result.prs[0].pr, 1816)
197
- assert.equal(result.prs[0].url, 'https://github.com/o/r/pull/1816')
198
- assert.match(h.err.text, /1 PR\(s\): #1816/)
199
- })
200
-
201
- test('pushedPrs reads every push line state and ignores lines without a PR', () => {
202
- const text = ' ✓ read 2 pull request(s)\n · [created]\t\thttps://github.com/o/r/pull/12\tfix: b\n · [skipped]\t\tchore: c\n'
203
- assert.deepEqual(pushedPrs(text).map((p) => [p.title, p.pr]), [['fix: b', 12]])
204
- assert.deepEqual(pushedPrs(''), [])
205
- const real = pushedPrs(' · [up-to-date]\t\thttps://github.com/1aboveio/ai/pull/1757\tfix(mergify): take a fresh PR\'s number\n')
206
- assert.deepEqual(real, [{ title: "fix(mergify): take a fresh PR's number", url: 'https://github.com/1aboveio/ai/pull/1757', pr: 1757 }])
207
- // fmm-express #1839 (2026-10-17): a check-mark bullet and the commit in the second column.
208
- const checked = pushedPrs(' ✓ [created]\taf9adcc\thttps://github.com/1aboveio/fmm-express/pull/1839\tfix(ci): absorb handoff walk races\n')
209
- assert.deepEqual(checked, [{ title: 'fix(ci): absorb handoff walk races', url: 'https://github.com/1aboveio/fmm-express/pull/1839', pr: 1839 }])
210
- })
211
-
212
- test('--dry-run passes through to mergify and stops after the plan', () => {
213
- const h = harness({ 'stack list': [ok(listJson([entry('aaa')]))], 'stack push': [ok('plan\n')] })
214
- assert.equal(stackPush(['--dry-run', '--trunk', 'upstream/develop'], h.deps), EXIT.OK)
215
- assert.deepEqual(pushArgs(parseArgs(['--dry-run', '--trunk', 'upstream/develop'])).slice(2), ['--trunk', 'upstream/develop', '--keep-pull-request-title-and-body', '--dry-run'])
216
- assert.equal(h.calls.filter((c) => c[0] === 'mergify' && c[2] === 'list').length, 1)
217
- assert.equal(JSON.parse(h.out.text).dryRun, true)
218
- })
219
-
220
- test('rejects unknown flags, a malformed trunk, and --enqueue with --dry-run', () => {
221
- for (const argv of [['--repo', 'o/r'], ['--trunk', 'main'], ['--enqueue', '--dry-run'], ['--no-verify']]) {
222
- const h = harness({})
223
- assert.equal(stackPush(argv, h.deps), EXIT.USAGE, argv.join(' '))
224
- }
225
- })
226
-
227
- test('honours a relative core.hooksPath', () => {
228
- const h = harness({ 'stack list': [ok(listJson([]))] })
229
- const base = h.deps.exec
230
- h.deps.exec = (cmd, args) => (cmd === 'git' && args[0] === 'config' ? ok('.githooks\n') : base(cmd, args))
231
- h.deps.exists = (path) => path === '/repo/.githooks/mergify-hooks'
232
- assert.equal(stackPush([], h.deps), EXIT.FIX_COMMITS)
233
- })