@1aboveio/skills 1.0.7 → 1.0.9

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 (224) 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 +92 -34
  8. package/skills/app-dev/android-foundation/assets/android-ci-job.yml +13 -7
  9. package/skills/app-dev/android-foundation/references/ci.md +23 -13
  10. package/skills/app-dev/android-foundation/references/delivery-focus.md +29 -0
  11. package/skills/app-dev/android-foundation/references/diagnosis.md +136 -0
  12. package/skills/app-dev/android-foundation/references/gotchas.md +20 -11
  13. package/skills/app-dev/android-foundation/references/setup.md +15 -6
  14. package/skills/app-dev/android-foundation/release-check.mjs +3 -1
  15. package/skills/app-dev/android-foundation/scripts/device-run.sh +148 -42
  16. package/skills/app-dev/app-debug/SKILL.md +1 -1
  17. package/skills/app-dev/app-debug/release-check.mjs +3 -1
  18. package/skills/app-dev/better-auth/SKILL.md +1 -1
  19. package/skills/app-dev/better-auth/release-check.mjs +3 -1
  20. package/skills/app-dev/data-catalog/SKILL.md +1 -1
  21. package/skills/app-dev/data-catalog/release-check.mjs +3 -1
  22. package/skills/app-dev/data-quality/SKILL.md +1 -1
  23. package/skills/app-dev/data-quality/release-check.mjs +3 -1
  24. package/skills/app-dev/ios-foundation/SKILL.md +1 -1
  25. package/skills/app-dev/ios-foundation/release-check.mjs +3 -1
  26. package/skills/app-dev/monorepo/SKILL.md +1 -1
  27. package/skills/app-dev/monorepo/release-check.mjs +3 -1
  28. package/skills/app-dev/nextjs-fullstack/SKILL.md +1 -1
  29. package/skills/app-dev/nextjs-fullstack/release-check.mjs +3 -1
  30. package/skills/app-dev/prisma-setup/SKILL.md +1 -1
  31. package/skills/app-dev/prisma-setup/release-check.mjs +3 -1
  32. package/skills/app-dev/pyspark/SKILL.md +1 -1
  33. package/skills/app-dev/pyspark/release-check.mjs +3 -1
  34. package/skills/app-dev/python-backend/SKILL.md +1 -1
  35. package/skills/app-dev/python-backend/release-check.mjs +3 -1
  36. package/skills/app-dev/shadcn/SKILL.md +1 -1
  37. package/skills/app-dev/shadcn/release-check.mjs +3 -1
  38. package/skills/app-dev/zod-v4/SKILL.md +1 -1
  39. package/skills/app-dev/zod-v4/release-check.mjs +3 -1
  40. package/skills/cicd/cloud-build/SKILL.md +1 -1
  41. package/skills/cicd/cloud-build/release-check.mjs +3 -1
  42. package/skills/cicd/cloud-debug/SKILL.md +1 -1
  43. package/skills/cicd/cloud-debug/release-check.mjs +3 -1
  44. package/skills/cicd/cloud-deploy/SKILL.md +1 -1
  45. package/skills/cicd/cloud-deploy/release-check.mjs +3 -1
  46. package/skills/cicd/docker/SKILL.md +1 -1
  47. package/skills/cicd/docker/release-check.mjs +3 -1
  48. package/skills/cicd/github-actions/SKILL.md +1 -1
  49. package/skills/cicd/github-actions/release-check.mjs +3 -1
  50. package/skills/cicd/github-flow/SKILL.md +1 -1
  51. package/skills/cicd/github-flow/release-check.mjs +3 -1
  52. package/skills/cicd/google-cloud/SKILL.md +1 -1
  53. package/skills/cicd/google-cloud/release-check.mjs +3 -1
  54. package/skills/cicd/mergify/SKILL.md +1 -1
  55. package/skills/cicd/mergify/release-check.mjs +3 -1
  56. package/skills/cicd/podman/SKILL.md +1 -1
  57. package/skills/cicd/podman/release-check.mjs +3 -1
  58. package/skills/content/article-review/SKILL.md +1 -1
  59. package/skills/content/article-review/release-check.mjs +3 -1
  60. package/skills/content/article-to-image/SKILL.md +1 -1
  61. package/skills/content/article-to-image/release-check.mjs +3 -1
  62. package/skills/content/flowchart-svg/SKILL.md +1 -1
  63. package/skills/content/flowchart-svg/release-check.mjs +3 -1
  64. package/skills/content/image-gen/SKILL.md +1 -1
  65. package/skills/content/image-gen/release-check.mjs +3 -1
  66. package/skills/content/mermaid/SKILL.md +1 -1
  67. package/skills/content/mermaid/release-check.mjs +3 -1
  68. package/skills/content/wechat-article-writer/SKILL.md +1 -1
  69. package/skills/content/wechat-article-writer/release-check.mjs +3 -1
  70. package/skills/content/wechat-publisher/SKILL.md +1 -1
  71. package/skills/content/wechat-publisher/release-check.mjs +3 -1
  72. package/skills/content/wechat-search/SKILL.md +1 -1
  73. package/skills/content/wechat-search/release-check.mjs +3 -1
  74. package/skills/content/xai-search/SKILL.md +88 -13
  75. package/skills/content/xai-search/release-check.mjs +3 -1
  76. package/skills/content/xai-search/scripts/xai_search.sh +125 -149
  77. package/skills/core/distill-writing/SKILL.md +1 -1
  78. package/skills/core/distill-writing/release-check.mjs +3 -1
  79. package/skills/core/doc-to-md/SKILL.md +1 -1
  80. package/skills/core/doc-to-md/release-check.mjs +3 -1
  81. package/skills/core/editorial-review/SKILL.md +1 -1
  82. package/skills/core/editorial-review/release-check.mjs +3 -1
  83. package/skills/core/house-style/SKILL.md +1 -1
  84. package/skills/core/house-style/release-check.mjs +3 -1
  85. package/skills/core/plain-language/SKILL.md +1 -1
  86. package/skills/core/plain-language/release-check.mjs +3 -1
  87. package/skills/core/polish-cn/SKILL.md +1 -1
  88. package/skills/core/polish-cn/release-check.mjs +3 -1
  89. package/skills/core/reg-parser/SKILL.md +1 -1
  90. package/skills/core/reg-parser/release-check.mjs +3 -1
  91. package/skills/core/terminology/SKILL.md +1 -1
  92. package/skills/core/terminology/release-check.mjs +3 -1
  93. package/skills/core/write-doc/SKILL.md +1 -1
  94. package/skills/core/write-doc/release-check.mjs +3 -1
  95. package/skills/engineering/better-review/SKILL.md +1 -1
  96. package/skills/engineering/better-review/release-check.mjs +3 -1
  97. package/skills/engineering/contributing/SKILL.md +1 -1
  98. package/skills/engineering/contributing/release-check.mjs +3 -1
  99. package/skills/engineering/e2e-test/SKILL.md +1 -1
  100. package/skills/engineering/e2e-test/release-check.mjs +3 -1
  101. package/skills/engineering/engineering-runtime/SKILL.md +1 -1
  102. package/skills/engineering/engineering-runtime/coherence/workflow.json +13 -13
  103. package/skills/engineering/engineering-runtime/release-check.mjs +3 -1
  104. package/skills/engineering/engineering-runtime/scripts/installation-resolver.mjs +191 -0
  105. package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +51 -10
  106. package/skills/engineering/ensure-coverage/SKILL.md +1 -1
  107. package/skills/engineering/ensure-coverage/release-check.mjs +3 -1
  108. package/skills/engineering/golden-path/SKILL.md +1 -1
  109. package/skills/engineering/golden-path/release-check.mjs +3 -1
  110. package/skills/engineering/harness-runtime/SKILL.md +1 -1
  111. package/skills/engineering/harness-runtime/release-check.mjs +3 -1
  112. package/skills/engineering/resolve-issues/SKILL.md +11 -20
  113. package/skills/engineering/resolve-issues/references/delivery-progress.md +63 -0
  114. package/skills/engineering/resolve-issues/references/expire.md +24 -11
  115. package/skills/engineering/resolve-issues/references/implementation.md +9 -1
  116. package/skills/engineering/resolve-issues/references/preflight.md +7 -0
  117. package/skills/engineering/resolve-issues/references/shared-modules.md +27 -0
  118. package/skills/engineering/resolve-issues/references/task-plan.md +12 -5
  119. package/skills/engineering/resolve-issues/release-check.mjs +3 -1
  120. package/skills/engineering/resolve-issues/scripts/active-installation.mjs +32 -0
  121. package/skills/engineering/resolve-issues/scripts/install-hooks.mjs +3 -0
  122. package/skills/engineering/resolve-issues/scripts/rehydrate.mjs +17 -1
  123. package/skills/engineering/resolve-release/SKILL.md +1 -1
  124. package/skills/engineering/resolve-release/release-check.mjs +3 -1
  125. package/skills/engineering/rush-issues/SKILL.md +5 -2
  126. package/skills/engineering/rush-issues/release-check.mjs +3 -1
  127. package/skills/engineering/rush-release/SKILL.md +1 -1
  128. package/skills/engineering/rush-release/release-check.mjs +3 -1
  129. package/skills/engineering/test-quality/SKILL.md +1 -1
  130. package/skills/engineering/test-quality/release-check.mjs +3 -1
  131. package/skills/risk-compliance/compliance-audit/SKILL.md +1 -1
  132. package/skills/risk-compliance/compliance-audit/release-check.mjs +3 -1
  133. package/skills/risk-compliance/contract-compare/SKILL.md +1 -1
  134. package/skills/risk-compliance/contract-compare/release-check.mjs +3 -1
  135. package/skills/risk-compliance/contract-review/SKILL.md +1 -1
  136. package/skills/risk-compliance/contract-review/release-check.mjs +3 -1
  137. package/skills/risk-compliance/doc-authenticity/SKILL.md +1 -1
  138. package/skills/risk-compliance/doc-authenticity/release-check.mjs +3 -1
  139. package/skills/risk-compliance/fraud-analysis/SKILL.md +1 -1
  140. package/skills/risk-compliance/fraud-analysis/release-check.mjs +3 -1
  141. package/skills/risk-compliance/payment-analysis/SKILL.md +1 -1
  142. package/skills/risk-compliance/payment-analysis/release-check.mjs +3 -1
  143. package/skills/risk-compliance/similar-domain/SKILL.md +1 -1
  144. package/skills/risk-compliance/similar-domain/release-check.mjs +3 -1
  145. package/skills/risk-compliance/tld-detection/SKILL.md +1 -1
  146. package/skills/risk-compliance/tld-detection/release-check.mjs +3 -1
  147. package/skills/app-dev/android-foundation/scripts/device-run.test.mjs +0 -172
  148. package/skills/app-dev/data-catalog/scripts/data-catalog.test.mjs +0 -36
  149. package/skills/app-dev/data-quality/scripts/data-quality.test.mjs +0 -12
  150. package/skills/cicd/github-actions/scripts/ci-run-audit.test.mjs +0 -637
  151. package/skills/cicd/github-flow/scripts/flow.test.mjs +0 -114
  152. package/skills/cicd/github-flow/scripts/persist-conventions.test.mjs +0 -108
  153. package/skills/cicd/mergify/scripts/audit.test.mjs +0 -201
  154. package/skills/cicd/mergify/scripts/entrypoints.test.mjs +0 -106
  155. package/skills/cicd/mergify/scripts/pr-620-mergify-comments.fixture.json +0 -30
  156. package/skills/cicd/mergify/scripts/stack-push.test.mjs +0 -233
  157. package/skills/cicd/mergify/scripts/watch-pr-delivery.test.mjs +0 -1826
  158. package/skills/content/image-gen/scripts/credentials.test.mjs +0 -212
  159. package/skills/content/image-gen/scripts/options.test.mjs +0 -245
  160. package/skills/content/xai-search/tests/smoke_test.sh +0 -36
  161. package/skills/core/polish-cn/scripts/polish-cn.test.mjs +0 -244
  162. package/skills/core/reg-parser/scripts/reg-parser.test.mjs +0 -165
  163. package/skills/engineering/better-review/scripts/pr-context.test.mjs +0 -168
  164. package/skills/engineering/better-review/scripts/rereview-scope.test.mjs +0 -587
  165. package/skills/engineering/better-review/scripts/scan-diff.test.mjs +0 -414
  166. package/skills/engineering/better-review/scripts/vendor-sync.test.mjs +0 -96
  167. package/skills/engineering/contributing/scripts/persist-conventions.test.mjs +0 -118
  168. package/skills/engineering/e2e-test/scripts/presentation-checks.test.mjs +0 -106
  169. package/skills/engineering/e2e-test/scripts/presentation-perceivability.test.mjs +0 -117
  170. package/skills/engineering/e2e-test/scripts/presentation-reachability.test.mjs +0 -69
  171. package/skills/engineering/e2e-test/scripts/presentation-render-health.test.mjs +0 -98
  172. package/skills/engineering/e2e-test/scripts/presentation-sweep.test.mjs +0 -71
  173. package/skills/engineering/e2e-test/scripts/presentation-temporal.test.mjs +0 -59
  174. package/skills/engineering/e2e-test/scripts/project-route-manifest.test.mjs +0 -76
  175. package/skills/engineering/engineering-runtime/engineering-runtime.test.mjs +0 -68
  176. package/skills/engineering/engineering-runtime/scripts/invocation-policy.test.mjs +0 -95
  177. package/skills/engineering/engineering-runtime/scripts/main-module.test.mjs +0 -288
  178. package/skills/engineering/engineering-runtime/scripts/required-check-plan.test.mjs +0 -96
  179. package/skills/engineering/ensure-coverage/scripts/adapters/nextjs-inventory.test.mjs +0 -96
  180. package/skills/engineering/ensure-coverage/scripts/check-quarantine-expiry.test.mjs +0 -47
  181. package/skills/engineering/ensure-coverage/scripts/ci-audit.test.mjs +0 -86
  182. package/skills/engineering/ensure-coverage/scripts/coverage-ledger.test.mjs +0 -447
  183. package/skills/engineering/ensure-coverage/scripts/design-parity.test.mjs +0 -552
  184. package/skills/engineering/ensure-coverage/scripts/lint-tests.test.mjs +0 -289
  185. package/skills/engineering/ensure-coverage/scripts/mock-policy-config.test.mjs +0 -119
  186. package/skills/engineering/golden-path/scripts/golden-path.test.mjs +0 -1457
  187. package/skills/engineering/harness-runtime/discover-models.test.mjs +0 -363
  188. package/skills/engineering/harness-runtime/harness-runtime.test.mjs +0 -967
  189. package/skills/engineering/harness-runtime/model-catalog-seed.test.mjs +0 -829
  190. package/skills/engineering/harness-runtime/model-catalog.test.mjs +0 -366
  191. package/skills/engineering/resolve-issues/scripts/cleanup-runs.test.mjs +0 -280
  192. package/skills/engineering/resolve-issues/scripts/dropbox.test.mjs +0 -346
  193. package/skills/engineering/resolve-issues/scripts/findings-reuse.test.mjs +0 -88
  194. package/skills/engineering/resolve-issues/scripts/github-reviews.test.mjs +0 -264
  195. package/skills/engineering/resolve-issues/scripts/install-hooks.test.mjs +0 -79
  196. package/skills/engineering/resolve-issues/scripts/issue-tree.test.mjs +0 -107
  197. package/skills/engineering/resolve-issues/scripts/manual-invocation.test.mjs +0 -14
  198. package/skills/engineering/resolve-issues/scripts/next-actions-capacity.test.mjs +0 -149
  199. package/skills/engineering/resolve-issues/scripts/next-actions.test.mjs +0 -915
  200. package/skills/engineering/resolve-issues/scripts/plan-sync.test.mjs +0 -156
  201. package/skills/engineering/resolve-issues/scripts/preflight-models.test.mjs +0 -448
  202. package/skills/engineering/resolve-issues/scripts/ready-check.test.mjs +0 -217
  203. package/skills/engineering/resolve-issues/scripts/rehydrate.test.mjs +0 -91
  204. package/skills/engineering/resolve-issues/scripts/review-verdict.test.mjs +0 -1060
  205. package/skills/engineering/resolve-issues/scripts/size-check.test.mjs +0 -458
  206. package/skills/engineering/resolve-release/scripts/apply.test.mjs +0 -99
  207. package/skills/engineering/resolve-release/scripts/dark-flags.test.mjs +0 -100
  208. package/skills/engineering/resolve-release/scripts/flow.test.mjs +0 -340
  209. package/skills/engineering/resolve-release/scripts/green-head.test.mjs +0 -101
  210. package/skills/engineering/resolve-release/scripts/npm-version-absence.test.mjs +0 -426
  211. package/skills/engineering/resolve-release/scripts/plan-npm.test.mjs +0 -659
  212. package/skills/engineering/resolve-release/scripts/plan-toml-boundary.test.mjs +0 -317
  213. package/skills/engineering/resolve-release/scripts/plan-uv.test.mjs +0 -291
  214. package/skills/engineering/resolve-release/scripts/plan.test.mjs +0 -428
  215. package/skills/engineering/test-quality/scripts/lint-tests.test.mjs +0 -591
  216. package/skills/engineering/test-quality/scripts/mock-policy-config.test.mjs +0 -119
  217. package/skills/engineering/test-quality/scripts/persist-conventions.test.mjs +0 -104
  218. package/skills/risk-compliance/compliance-audit/scripts/compliance-audit.test.mjs +0 -14
  219. package/skills/risk-compliance/doc-authenticity/manual-invocation.test.mjs +0 -12
  220. package/skills/risk-compliance/doc-authenticity/scripts/validate_verdict.test.mjs +0 -212
  221. package/skills/risk-compliance/tld-detection/scripts/detect_ladders.test.mjs +0 -14
  222. package/skills/risk-compliance/tld-detection/scripts/detect_streams.test.mjs +0 -14
  223. package/skills/risk-compliance/tld-detection/tests/test_detect_ladders.py +0 -134
  224. 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
- })