issue-flow 0.11.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/README.md +79 -274
  2. package/dist/agent-BXRIEKVM.js +238 -0
  3. package/dist/agent-BXRIEKVM.js.map +1 -0
  4. package/dist/{analyze-XV3K25K3.js → analyze-WS47UYGN.js} +32 -15
  5. package/dist/analyze-WS47UYGN.js.map +1 -0
  6. package/dist/{apply-WUJHDD7A.js → apply-OS62UWRN.js} +15 -5
  7. package/dist/{apply-WUJHDD7A.js.map → apply-OS62UWRN.js.map} +1 -1
  8. package/dist/bench-SA3BOME5.js +906 -0
  9. package/dist/bench-SA3BOME5.js.map +1 -0
  10. package/dist/chunk-37N2RJW2.js +120 -0
  11. package/dist/chunk-37N2RJW2.js.map +1 -0
  12. package/dist/chunk-3XLCNVMD.js +180 -0
  13. package/dist/chunk-3XLCNVMD.js.map +1 -0
  14. package/dist/chunk-5TB6KLC2.js +72 -0
  15. package/dist/chunk-5TB6KLC2.js.map +1 -0
  16. package/dist/{chunk-OBLVLIUS.js → chunk-664Y3NDX.js} +25 -13
  17. package/dist/chunk-664Y3NDX.js.map +1 -0
  18. package/dist/chunk-6FDFRNXZ.js +357 -0
  19. package/dist/chunk-6FDFRNXZ.js.map +1 -0
  20. package/dist/chunk-7KD66LIM.js +658 -0
  21. package/dist/chunk-7KD66LIM.js.map +1 -0
  22. package/dist/chunk-7Z4Y3VKM.js +26 -0
  23. package/dist/chunk-7Z4Y3VKM.js.map +1 -0
  24. package/dist/chunk-ARFVHC2F.js +1111 -0
  25. package/dist/chunk-ARFVHC2F.js.map +1 -0
  26. package/dist/{chunk-RKTEV6EG.js → chunk-BHJCGWQX.js} +141 -12
  27. package/dist/chunk-BHJCGWQX.js.map +1 -0
  28. package/dist/chunk-BQDQTIM7.js +74 -0
  29. package/dist/chunk-BQDQTIM7.js.map +1 -0
  30. package/dist/chunk-CNBYCMSU.js +2709 -0
  31. package/dist/chunk-CNBYCMSU.js.map +1 -0
  32. package/dist/chunk-CRGIQFUQ.js +83 -0
  33. package/dist/chunk-CRGIQFUQ.js.map +1 -0
  34. package/dist/chunk-DIG5XKQQ.js +298 -0
  35. package/dist/chunk-DIG5XKQQ.js.map +1 -0
  36. package/dist/chunk-FZDR7CGH.js +71 -0
  37. package/dist/chunk-FZDR7CGH.js.map +1 -0
  38. package/dist/chunk-HEF2RMKN.js +413 -0
  39. package/dist/chunk-HEF2RMKN.js.map +1 -0
  40. package/dist/{chunk-IVHZEYAX.js → chunk-HJGGNLWI.js} +25 -19
  41. package/dist/chunk-HJGGNLWI.js.map +1 -0
  42. package/dist/chunk-HQAHNIAR.js +283 -0
  43. package/dist/chunk-HQAHNIAR.js.map +1 -0
  44. package/dist/{chunk-GANSDJV7.js → chunk-IHIEXUTC.js} +46 -24
  45. package/dist/chunk-IHIEXUTC.js.map +1 -0
  46. package/dist/chunk-IV5SS4JN.js +84 -0
  47. package/dist/chunk-IV5SS4JN.js.map +1 -0
  48. package/dist/{chunk-HC2MT7BX.js → chunk-IYV6KNVF.js} +158 -592
  49. package/dist/chunk-IYV6KNVF.js.map +1 -0
  50. package/dist/{chunk-LVKQ2AKT.js → chunk-J62QSVP6.js} +10 -8
  51. package/dist/chunk-J62QSVP6.js.map +1 -0
  52. package/dist/chunk-KMMASOA6.js +134 -0
  53. package/dist/chunk-KMMASOA6.js.map +1 -0
  54. package/dist/chunk-KQHB7ZT3.js +559 -0
  55. package/dist/chunk-KQHB7ZT3.js.map +1 -0
  56. package/dist/chunk-L6HSKTQE.js +77 -0
  57. package/dist/chunk-L6HSKTQE.js.map +1 -0
  58. package/dist/{chunk-6N7LZZ5U.js → chunk-LZ6GFQAG.js} +474 -160
  59. package/dist/chunk-LZ6GFQAG.js.map +1 -0
  60. package/dist/{chunk-HQYXVIH6.js → chunk-MIVHK5YI.js} +5 -5
  61. package/dist/chunk-NEZZ6KDR.js +1217 -0
  62. package/dist/chunk-NEZZ6KDR.js.map +1 -0
  63. package/dist/{run-DBF2VWUN.js → chunk-OPNGPUKJ.js} +747 -594
  64. package/dist/chunk-OPNGPUKJ.js.map +1 -0
  65. package/dist/chunk-P3LRUNC6.js +16 -0
  66. package/dist/chunk-P3LRUNC6.js.map +1 -0
  67. package/dist/{chunk-BXCPXRBR.js → chunk-PIVGJM6K.js} +129 -32
  68. package/dist/chunk-PIVGJM6K.js.map +1 -0
  69. package/dist/{chunk-AAY6KM7N.js → chunk-PV4OX5TC.js} +167 -196
  70. package/dist/chunk-PV4OX5TC.js.map +1 -0
  71. package/dist/chunk-QCXPNSEL.js +141 -0
  72. package/dist/chunk-QCXPNSEL.js.map +1 -0
  73. package/dist/{chunk-34WNTK3K.js → chunk-QXDNBYQF.js} +53 -13
  74. package/dist/chunk-QXDNBYQF.js.map +1 -0
  75. package/dist/chunk-SNTTOQAD.js +30 -0
  76. package/dist/chunk-SNTTOQAD.js.map +1 -0
  77. package/dist/{chunk-EY6WMHV2.js → chunk-TM67EHSV.js} +67 -23
  78. package/dist/chunk-TM67EHSV.js.map +1 -0
  79. package/dist/chunk-TVN2JVOF.js +77 -0
  80. package/dist/chunk-TVN2JVOF.js.map +1 -0
  81. package/dist/chunk-TX5WIVYP.js +129 -0
  82. package/dist/chunk-TX5WIVYP.js.map +1 -0
  83. package/dist/{chunk-KQ4JQN7T.js → chunk-UJ7XWK7J.js} +83 -21
  84. package/dist/chunk-UJ7XWK7J.js.map +1 -0
  85. package/dist/{chunk-47VIN33V.js → chunk-UOCPC2Y2.js} +596 -17
  86. package/dist/chunk-UOCPC2Y2.js.map +1 -0
  87. package/dist/chunk-XEYH6ZZI.js +289 -0
  88. package/dist/chunk-XEYH6ZZI.js.map +1 -0
  89. package/dist/cli.js +390 -40
  90. package/dist/cli.js.map +1 -1
  91. package/dist/config-MEM2IWWN.js +76 -0
  92. package/dist/contract-JH2WBIO6.js +8 -0
  93. package/dist/conventions-WV4NDXGH.js +143 -0
  94. package/dist/conventions-WV4NDXGH.js.map +1 -0
  95. package/dist/execute-NITIHHCK.js +31 -0
  96. package/dist/{generate-TBVTLMOP.js → generate-MVQI7A45.js} +39 -19
  97. package/dist/{generate-TBVTLMOP.js.map → generate-MVQI7A45.js.map} +1 -1
  98. package/dist/git-YRVRUN3C.js +31 -0
  99. package/dist/init-OKWEC3EV.js +21 -0
  100. package/dist/operations-LU6JA3BX.js +374 -0
  101. package/dist/operations-LU6JA3BX.js.map +1 -0
  102. package/dist/permissions-7NMDFU27.js +18 -0
  103. package/dist/plan-LEJJF3DE.js +31 -0
  104. package/dist/{policy-XQW5NUIE.js → policy-JSYEK5B2.js} +17 -4
  105. package/dist/policy-JSYEK5B2.js.map +1 -0
  106. package/dist/pr-HPVUZ7S3.js +36 -0
  107. package/dist/pr-review-R2QZBT3F.js +29 -0
  108. package/dist/pr-review-R2QZBT3F.js.map +1 -0
  109. package/dist/prd-5O6GYCC6.js +30 -0
  110. package/dist/prd-5O6GYCC6.js.map +1 -0
  111. package/dist/ps-TNE44R5V.js +90 -0
  112. package/dist/ps-TNE44R5V.js.map +1 -0
  113. package/dist/recorder-XGF55WXI.js +31 -0
  114. package/dist/recorder-XGF55WXI.js.map +1 -0
  115. package/dist/registry-LGPE53QD.js +15 -0
  116. package/dist/registry-LGPE53QD.js.map +1 -0
  117. package/dist/resume-QMEPMSZW.js +238 -0
  118. package/dist/resume-QMEPMSZW.js.map +1 -0
  119. package/dist/review-YKWD6SNN.js +32 -0
  120. package/dist/review-YKWD6SNN.js.map +1 -0
  121. package/dist/routing-2ZUMZPJB.js +91 -0
  122. package/dist/routing-2ZUMZPJB.js.map +1 -0
  123. package/dist/run-YU4TR62R.js +50 -0
  124. package/dist/run-YU4TR62R.js.map +1 -0
  125. package/dist/state-manager-X3PT3FGT.js +36 -0
  126. package/dist/state-manager-X3PT3FGT.js.map +1 -0
  127. package/dist/usage-VCFLDA5Y.js +174 -0
  128. package/dist/usage-VCFLDA5Y.js.map +1 -0
  129. package/dist/{web-ANQQTTRD.js → web-XVHLX62B.js} +43 -27
  130. package/dist/web-XVHLX62B.js.map +1 -0
  131. package/package.json +6 -2
  132. package/prompts/execute.md +7 -8
  133. package/prompts/plan.md +4 -5
  134. package/prompts/pr.md +13 -6
  135. package/web/AGENTS.md +3 -3
  136. package/web/public/app.css +38 -0
  137. package/web/public/app.js +132 -10
  138. package/web/public/index.html +24 -0
  139. package/dist/analyze-XV3K25K3.js.map +0 -1
  140. package/dist/chunk-34WNTK3K.js.map +0 -1
  141. package/dist/chunk-3BOHTH4V.js +0 -58
  142. package/dist/chunk-3BOHTH4V.js.map +0 -1
  143. package/dist/chunk-47VIN33V.js.map +0 -1
  144. package/dist/chunk-6N7LZZ5U.js.map +0 -1
  145. package/dist/chunk-AAY6KM7N.js.map +0 -1
  146. package/dist/chunk-BXCPXRBR.js.map +0 -1
  147. package/dist/chunk-EWDJENFW.js +0 -303
  148. package/dist/chunk-EWDJENFW.js.map +0 -1
  149. package/dist/chunk-EY6WMHV2.js.map +0 -1
  150. package/dist/chunk-GANSDJV7.js.map +0 -1
  151. package/dist/chunk-HC2MT7BX.js.map +0 -1
  152. package/dist/chunk-HDV3YDTG.js +0 -52
  153. package/dist/chunk-HDV3YDTG.js.map +0 -1
  154. package/dist/chunk-IVHZEYAX.js.map +0 -1
  155. package/dist/chunk-KQ4JQN7T.js.map +0 -1
  156. package/dist/chunk-LVKQ2AKT.js.map +0 -1
  157. package/dist/chunk-OBLVLIUS.js.map +0 -1
  158. package/dist/chunk-RKTEV6EG.js.map +0 -1
  159. package/dist/chunk-VQ5VN7DF.js +0 -1018
  160. package/dist/chunk-VQ5VN7DF.js.map +0 -1
  161. package/dist/config-4THHOXNN.js +0 -41
  162. package/dist/execute-5OEKLM5X.js +0 -15
  163. package/dist/init-PRMOTQ7N.js +0 -9
  164. package/dist/plan-Y2BYZD24.js +0 -17
  165. package/dist/policy-XQW5NUIE.js.map +0 -1
  166. package/dist/pr-H6GLOSXF.js +0 -21
  167. package/dist/pr-review-CK5FR6WX.js +0 -17
  168. package/dist/prd-4PWLCGH5.js +0 -17
  169. package/dist/review-QGVAHEZF.js +0 -15
  170. package/dist/run-DBF2VWUN.js.map +0 -1
  171. package/dist/web-ANQQTTRD.js.map +0 -1
  172. /package/dist/{chunk-HQYXVIH6.js.map → chunk-MIVHK5YI.js.map} +0 -0
  173. /package/dist/{config-4THHOXNN.js.map → config-MEM2IWWN.js.map} +0 -0
  174. /package/dist/{execute-5OEKLM5X.js.map → contract-JH2WBIO6.js.map} +0 -0
  175. /package/dist/{init-PRMOTQ7N.js.map → execute-NITIHHCK.js.map} +0 -0
  176. /package/dist/{plan-Y2BYZD24.js.map → git-YRVRUN3C.js.map} +0 -0
  177. /package/dist/{pr-H6GLOSXF.js.map → init-OKWEC3EV.js.map} +0 -0
  178. /package/dist/{pr-review-CK5FR6WX.js.map → permissions-7NMDFU27.js.map} +0 -0
  179. /package/dist/{prd-4PWLCGH5.js.map → plan-LEJJF3DE.js.map} +0 -0
  180. /package/dist/{review-QGVAHEZF.js.map → pr-HPVUZ7S3.js.map} +0 -0
@@ -1,13 +1,354 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- getProjectRoot,
4
3
  loadPolicyConfig,
5
- mergeConfigLayers,
6
- run
7
- } from "./chunk-VQ5VN7DF.js";
4
+ mergeConfigLayers
5
+ } from "./chunk-CNBYCMSU.js";
8
6
  import {
9
7
  printWarning
10
- } from "./chunk-HC2MT7BX.js";
8
+ } from "./chunk-IYV6KNVF.js";
9
+ import {
10
+ getProjectRoot,
11
+ run
12
+ } from "./chunk-KQHB7ZT3.js";
13
+
14
+ // src/conventions/git/types.ts
15
+ var CHANGE_TYPES = [
16
+ "feat",
17
+ "fix",
18
+ "docs",
19
+ "refactor",
20
+ "perf",
21
+ "test",
22
+ "build",
23
+ "ci",
24
+ "chore",
25
+ "style",
26
+ "revert"
27
+ ];
28
+ var DEFAULT_BRANCH_CONVENTION = "{type}/{N}-{slug}";
29
+ var SLUG_MAX_LENGTH = 40;
30
+ var BRANCH_MAX_LENGTH = 60;
31
+ var DEFAULT_LABEL_TYPE_MAP = {
32
+ bug: "fix",
33
+ documentation: "docs",
34
+ docs: "docs",
35
+ refactor: "refactor",
36
+ "tech-debt": "refactor",
37
+ infra: "ci",
38
+ "ci-cd": "ci",
39
+ enhancement: "feat",
40
+ architecture: "feat",
41
+ investigation: "chore"
42
+ };
43
+ var FORBIDDEN_PROVIDER_NAMES = ["claude", "codex", "cursor", "antigravity"];
44
+ function isChangeType(value) {
45
+ return CHANGE_TYPES.includes(value);
46
+ }
47
+ function isForbiddenProviderToken(value) {
48
+ return FORBIDDEN_PROVIDER_NAMES.includes(value.toLowerCase());
49
+ }
50
+
51
+ // src/conventions/git/slug.ts
52
+ var COMBINING = /[\u0300-\u036f]/g;
53
+ var NON_SLUG = /[^a-z0-9]+/g;
54
+ function slugify(title, maxLength = SLUG_MAX_LENGTH) {
55
+ const withoutLock = title.replace(/\.lock$/i, "");
56
+ const normalized = withoutLock.normalize("NFD").replace(COMBINING, "").toLowerCase();
57
+ let slug = normalized.replace(NON_SLUG, "-").replace(/^-+|-+$/g, "");
58
+ slug = slug.replace(/\.{2,}/g, ".").replace(/^\.+|\.+$/g, "");
59
+ slug = slug.replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "");
60
+ if (slug.length <= maxLength) return slug;
61
+ const cut = slug.slice(0, maxLength);
62
+ const lastHyphen = cut.lastIndexOf("-");
63
+ if (lastHyphen >= Math.floor(maxLength / 2)) {
64
+ return cut.slice(0, lastHyphen).replace(/-+$/g, "");
65
+ }
66
+ return cut.replace(/-+$/g, "");
67
+ }
68
+
69
+ // src/conventions/git/branch.ts
70
+ var LEGACY_PREFIX = "issue";
71
+ function branchType(type) {
72
+ return type === "style" || type === "revert" ? "chore" : type;
73
+ }
74
+ function applyConvention(convention, type, issueNumber, slug) {
75
+ const hasNumber = issueNumber !== void 0 && issueNumber !== null;
76
+ let result = convention.replaceAll("{type}", type).replaceAll("{N}", hasNumber ? String(issueNumber) : "").replaceAll("{slug}", slug);
77
+ result = result.replace(/\/{2,}/g, "/").replace(/-{2,}/g, "-");
78
+ result = result.replace(/\/-/g, "/").replace(/-\//g, "/");
79
+ result = result.replace(/^\/+|\/+$/g, "").replace(/^-+|-+$/g, "");
80
+ if (!hasNumber) {
81
+ result = result.replace(`${type}/-`, `${type}/`).replace(/\/$/g, "");
82
+ }
83
+ if (slug === "") {
84
+ result = result.replace(/\/-$/, "").replace(/-$/, "");
85
+ }
86
+ return result.replace(/\/{2,}/g, "/").replace(/^\/+|\/+$/g, "");
87
+ }
88
+ function truncateBranch(name, max) {
89
+ if (name.length <= max) return name;
90
+ const slash = name.indexOf("/");
91
+ const prefix = slash === -1 ? "" : name.slice(0, slash + 1);
92
+ const rest = slash === -1 ? name : name.slice(slash + 1);
93
+ const budget = max - prefix.length;
94
+ if (budget < 1) return name.slice(0, max);
95
+ const cut = rest.slice(0, budget);
96
+ const lastHyphen = cut.lastIndexOf("-");
97
+ const trimmed = lastHyphen >= Math.floor(budget / 2) ? cut.slice(0, lastHyphen) : cut;
98
+ return `${prefix}${trimmed.replace(/-+$/g, "")}`;
99
+ }
100
+ function collide(name, existingRefs, currentOid) {
101
+ if (existingRefs === void 0 || existingRefs.length === 0) return name;
102
+ const byName = new Map(existingRefs.map((ref) => [ref.name, ref.oid]));
103
+ const existing = byName.get(name);
104
+ if (existing === void 0) return name;
105
+ if (currentOid !== void 0 && existing === currentOid) return name;
106
+ for (let n = 2; n < 100; n += 1) {
107
+ const candidate = `${name}-${n}`;
108
+ const oid = byName.get(candidate);
109
+ if (oid === void 0 || currentOid !== void 0 && oid === currentOid) {
110
+ return candidate;
111
+ }
112
+ }
113
+ return `${name}-${Date.now()}`;
114
+ }
115
+ function branchName(input) {
116
+ const type = branchType(input.type);
117
+ const convention = input.convention ?? DEFAULT_BRANCH_CONVENTION;
118
+ const slug = slugify(input.title);
119
+ const raw = applyConvention(convention, type, input.issueNumber, slug);
120
+ const truncated = truncateBranch(raw, BRANCH_MAX_LENGTH);
121
+ return collide(truncated, input.existingRefs, input.currentOid);
122
+ }
123
+ function parseBranch(name) {
124
+ const raw = name.trim();
125
+ const match = raw.match(/^([^/]+)\/(?:(\d+)(?:-(.*))?|(.*))$/);
126
+ if (match === null) {
127
+ return { type: null, issueNumber: null, slug: raw, raw };
128
+ }
129
+ const prefix = match[1] ?? "";
130
+ const numbered = match[2];
131
+ const numberedSlug = match[3] ?? "";
132
+ const unnumberedSlug = match[4] ?? "";
133
+ const type = prefix === LEGACY_PREFIX ? "issue" : isChangeType(prefix) ? prefix : null;
134
+ if (numbered !== void 0) {
135
+ return { type, issueNumber: Number(numbered), slug: numberedSlug, raw };
136
+ }
137
+ return { type, issueNumber: null, slug: unnumberedSlug, raw };
138
+ }
139
+ function archiveFolderName(branch) {
140
+ const parsed = parseBranch(branch);
141
+ if (parsed.issueNumber !== null && parsed.slug !== "") {
142
+ return `${parsed.issueNumber}-${parsed.slug}`.replace(/[<>:"|?*\\]/g, "_");
143
+ }
144
+ if (parsed.issueNumber !== null) {
145
+ return String(parsed.issueNumber);
146
+ }
147
+ return branch.replace(/^[^/]+\//, "").replace(/[<>:"|?*\\]/g, "_");
148
+ }
149
+
150
+ // src/conventions/git/change-type.ts
151
+ var ISSUE_TYPE_MAP = {
152
+ bug: "fix",
153
+ feature: "feat",
154
+ task: "chore",
155
+ epic: "chore",
156
+ idea: "chore",
157
+ research: "chore",
158
+ documentation: "docs"
159
+ };
160
+ var TITLE_PREFIX_MAP = {
161
+ bug: "fix",
162
+ fix: "fix",
163
+ feature: "feat",
164
+ enhancement: "feat",
165
+ architecture: "feat",
166
+ refactor: "refactor",
167
+ docs: "docs",
168
+ documentation: "docs",
169
+ chore: "chore",
170
+ perf: "perf",
171
+ test: "test",
172
+ ci: "ci"
173
+ };
174
+ function normalizeKey(value) {
175
+ return value.trim().toLowerCase();
176
+ }
177
+ function typeFromIssueType(issueType) {
178
+ const key = normalizeKey(issueType);
179
+ if (isChangeType(key)) return key;
180
+ return ISSUE_TYPE_MAP[key] ?? null;
181
+ }
182
+ function mergedTypeMap(overlay) {
183
+ const merged = { ...DEFAULT_LABEL_TYPE_MAP };
184
+ if (overlay === void 0 || overlay === null) return merged;
185
+ for (const [label, type] of Object.entries(overlay)) {
186
+ if (isChangeType(type)) {
187
+ merged[normalizeKey(label)] = type;
188
+ }
189
+ }
190
+ return merged;
191
+ }
192
+ function typeFromLabels(labels, typeMap) {
193
+ for (const label of labels) {
194
+ const key = normalizeKey(label);
195
+ const mapped = typeMap[key] ?? typeMap[key.replace(/^type:/, "")];
196
+ if (mapped !== void 0) return mapped;
197
+ }
198
+ return null;
199
+ }
200
+ function typeFromTitle(title) {
201
+ const match = title.match(/^\s*\[([^\]]+)\]/);
202
+ if (match?.[1] === void 0) return null;
203
+ const key = normalizeKey(match[1]);
204
+ if (isChangeType(key)) return key;
205
+ return TITLE_PREFIX_MAP[key] ?? null;
206
+ }
207
+ function resolveChangeType(input) {
208
+ if (input.declaredType !== void 0 && input.declaredType !== null) {
209
+ return { type: input.declaredType, source: "declared" };
210
+ }
211
+ const labels = input.labels ?? [];
212
+ const typeMap = mergedTypeMap(input.typeMap);
213
+ const fromLabels = typeFromLabels(labels, typeMap);
214
+ const fromIssueType = input.issueType !== void 0 && input.issueType !== null && input.issueType !== "" ? typeFromIssueType(input.issueType) : null;
215
+ if (fromIssueType !== null) {
216
+ const issueKey = normalizeKey(input.issueType ?? "");
217
+ if (issueKey === "task" && fromLabels !== null) {
218
+ return { type: fromLabels, source: "label" };
219
+ }
220
+ if (fromLabels !== null && fromLabels !== fromIssueType) {
221
+ return {
222
+ type: fromIssueType,
223
+ source: "issue-type",
224
+ conflict: { issueType: fromIssueType, label: fromLabels }
225
+ };
226
+ }
227
+ return { type: fromIssueType, source: "issue-type" };
228
+ }
229
+ if (fromLabels !== null) {
230
+ return { type: fromLabels, source: "label" };
231
+ }
232
+ if (input.titleConvention !== null && input.title !== void 0) {
233
+ const fromTitle = typeFromTitle(input.title);
234
+ if (fromTitle !== null) {
235
+ return { type: fromTitle, source: "title" };
236
+ }
237
+ } else if (input.title !== void 0) {
238
+ const fromTitle = typeFromTitle(input.title);
239
+ if (fromTitle !== null) {
240
+ return { type: fromTitle, source: "title" };
241
+ }
242
+ }
243
+ return { type: "feat", source: "fallback" };
244
+ }
245
+
246
+ // src/conventions/git/commit.ts
247
+ var HEADER_MAX = 72;
248
+ var BODY_WIDTH = 72;
249
+ var STORY_ID = /^US-\d+$/i;
250
+ function wrap(text, width) {
251
+ const paragraphs = text.replace(/\r\n/g, "\n").split("\n");
252
+ return paragraphs.map((paragraph) => {
253
+ if (paragraph.trim() === "") return "";
254
+ const words = paragraph.split(/\s+/);
255
+ const lines = [];
256
+ let current = "";
257
+ for (const word of words) {
258
+ const next = current === "" ? word : `${current} ${word}`;
259
+ if (next.length > width && current !== "") {
260
+ lines.push(current);
261
+ current = word;
262
+ } else {
263
+ current = next;
264
+ }
265
+ }
266
+ if (current !== "") lines.push(current);
267
+ return lines.join("\n");
268
+ }).join("\n");
269
+ }
270
+ function sanitizeScope(scope) {
271
+ if (scope === void 0 || scope === null) return void 0;
272
+ const trimmed = scope.trim();
273
+ if (trimmed === "" || isForbiddenProviderToken(trimmed)) return void 0;
274
+ return trimmed;
275
+ }
276
+ function sanitizeType(type) {
277
+ return isForbiddenProviderToken(type) ? "chore" : type;
278
+ }
279
+ function headerLine(type, scope, breaking, subject) {
280
+ const bang = breaking ? "!" : "";
281
+ const scoped = scope === void 0 ? `${type}${bang}` : `${type}(${scope})${bang}`;
282
+ const cleaned = subject.replace(/\.$/, "").trim();
283
+ const prefix = `${scoped}: `;
284
+ const budget = HEADER_MAX - prefix.length;
285
+ const clipped = budget < 1 ? "" : cleaned.length > budget ? cleaned.slice(0, budget).trimEnd() : cleaned;
286
+ return `${prefix}${clipped}`;
287
+ }
288
+ function commitMessage(input) {
289
+ const type = sanitizeType(input.type);
290
+ const scope = sanitizeScope(input.scope);
291
+ const breaking = input.breaking !== void 0 && input.breaking !== null && input.breaking !== "";
292
+ const lines = [headerLine(type, scope, breaking, input.subject)];
293
+ if (input.body !== void 0 && input.body !== "") {
294
+ lines.push("", wrap(input.body, BODY_WIDTH));
295
+ }
296
+ const footers = [];
297
+ if (input.issueNumber !== void 0 && input.issueNumber !== null) {
298
+ footers.push(`Refs #${input.issueNumber}`);
299
+ }
300
+ if (input.storyId !== void 0 && input.storyId !== null && STORY_ID.test(input.storyId)) {
301
+ footers.push(`Story: ${input.storyId}`);
302
+ }
303
+ if (breaking) {
304
+ footers.push(`BREAKING CHANGE: ${input.breaking}`);
305
+ }
306
+ if (input.signoff === true) {
307
+ footers.push("Signed-off-by:");
308
+ } else if (typeof input.signoff === "string" && input.signoff !== "") {
309
+ footers.push(`Signed-off-by: ${input.signoff}`);
310
+ }
311
+ if (footers.length > 0) {
312
+ lines.push("", ...footers);
313
+ }
314
+ return lines.join("\n");
315
+ }
316
+
317
+ // src/conventions/git/pull-request.ts
318
+ var IMPACT = ["feat", "fix"];
319
+ function sanitizeScope2(scope) {
320
+ if (scope === void 0 || scope === null) return void 0;
321
+ const trimmed = scope.trim();
322
+ if (trimmed === "" || isForbiddenProviderToken(trimmed)) return void 0;
323
+ return trimmed;
324
+ }
325
+ function highestImpact(types) {
326
+ for (const type of IMPACT) {
327
+ if (types.includes(type)) return type;
328
+ }
329
+ return types[0] ?? "feat";
330
+ }
331
+ function scopesAgree(scopes) {
332
+ const unique2 = [
333
+ ...new Set(scopes.map((scope) => sanitizeScope2(scope)).filter((scope) => scope !== void 0))
334
+ ];
335
+ return unique2.length === 1 ? unique2[0] : void 0;
336
+ }
337
+ function pullRequestTitle(input) {
338
+ const type = input.types !== void 0 && input.types.length > 0 ? highestImpact(input.types) : input.type;
339
+ const scope = input.scopes !== void 0 && input.scopes.length > 0 ? scopesAgree(input.scopes) : sanitizeScope2(input.scope);
340
+ const subject = input.subject.replace(/\.$/, "").trim();
341
+ if (isForbiddenProviderToken(type)) {
342
+ return scope === void 0 ? `chore: ${subject}` : `chore(${scope}): ${subject}`;
343
+ }
344
+ return scope === void 0 ? `${type}: ${subject}` : `${type}(${scope}): ${subject}`;
345
+ }
346
+ function issueReferenceLines(input) {
347
+ return input.references.map((ref) => {
348
+ const closes = ref.container === true ? ref.allChildrenComplete === true : ref.complete;
349
+ return `${closes ? "Closes" : "Refs"} #${ref.number}`;
350
+ }).join("\n");
351
+ }
11
352
 
12
353
  // src/policy/resolve.ts
13
354
  import { isAbsolute, normalize, sep as sep2 } from "path";
@@ -56,6 +397,118 @@ function extractReferencedDocuments(content, fromPath) {
56
397
  return found;
57
398
  }
58
399
 
400
+ // src/policy/parsers/git.ts
401
+ var COMMITLINT_NAMES = [
402
+ ".commitlintrc",
403
+ ".commitlintrc.json",
404
+ ".commitlintrc.yaml",
405
+ ".commitlintrc.yml",
406
+ ".commitlintrc.js",
407
+ ".commitlintrc.cjs",
408
+ ".commitlintrc.mjs",
409
+ ".commitlintrc.ts",
410
+ "commitlint.config.js",
411
+ "commitlint.config.cjs",
412
+ "commitlint.config.mjs",
413
+ "commitlint.config.ts"
414
+ ];
415
+ function unique(values) {
416
+ return [...new Set(values)];
417
+ }
418
+ function extractQuotedStrings(block) {
419
+ const matches = block.match(/['"]([a-z][a-z0-9-]*)['"]/g) ?? [];
420
+ return matches.map((token) => token.slice(1, -1));
421
+ }
422
+ function extractEnum(source, rule) {
423
+ const escaped = rule.replace("-", "\\-");
424
+ const match = source.match(new RegExp(`${escaped}[\\s\\S]{0,800}?\\[([\\s\\S]*?)\\]`, "i"));
425
+ if (match?.[1] === void 0) return [];
426
+ return extractQuotedStrings(match[1]).filter((value) => value !== "always" && value !== "never");
427
+ }
428
+ function parseCommitlintSource(source, path) {
429
+ const types = extractEnum(source, "type-enum").filter(isChangeType);
430
+ const scopes = extractEnum(source, "scope-enum");
431
+ const conventional = /conventional|commitlint/i.test(source) || types.length > 0;
432
+ return {
433
+ commitConvention: conventional ? "conventional" : null,
434
+ pullRequestTitleConvention: null,
435
+ allowedTypes: types.length > 0 ? unique(types) : null,
436
+ scopes: scopes.length > 0 ? unique(scopes) : null,
437
+ sources: [{ path, detail: conventional ? "commitlint" : "commitlint (unrecognised)" }]
438
+ };
439
+ }
440
+ function parsePackageCommitlint(pkg) {
441
+ if (pkg === null || typeof pkg !== "object" || Array.isArray(pkg)) return null;
442
+ const commitlint = pkg.commitlint;
443
+ if (commitlint === void 0 || commitlint === null) return null;
444
+ const source = JSON.stringify(commitlint);
445
+ return parseCommitlintSource(source, "package.json#commitlint");
446
+ }
447
+ function parseSemanticPrWorkflow(source, path) {
448
+ if (!/amannn\/action-semantic-pull-request/.test(source)) return null;
449
+ const typesBlock = source.match(/types:\s*[|>]?\s*\n((?:\s{2,}[a-z][a-z0-9-]*\s*\n)+)/i);
450
+ const scopesBlock = source.match(/scopes:\s*[|>]?\s*\n((?:\s{2,}[a-z][a-z0-9-]*\s*\n)+)/i);
451
+ const types = typesBlock?.[1]?.split("\n").map((line) => line.trim()).filter((line) => isChangeType(line)) ?? [];
452
+ const scopes = scopesBlock?.[1]?.split("\n").map((line) => line.trim()).filter((line) => /^[a-z][a-z0-9-]*$/.test(line)) ?? [];
453
+ return {
454
+ commitConvention: "conventional",
455
+ pullRequestTitleConvention: "conventional",
456
+ allowedTypes: types.length > 0 ? unique(types) : null,
457
+ scopes: scopes.length > 0 ? unique(scopes) : null,
458
+ sources: [{ path, detail: "amannn/action-semantic-pull-request" }]
459
+ };
460
+ }
461
+ function parseCommitlintText(source, path) {
462
+ return parseCommitlintSource(source, path);
463
+ }
464
+ function parsePackageJsonCommitlint(raw) {
465
+ try {
466
+ return parsePackageCommitlint(JSON.parse(raw));
467
+ } catch {
468
+ return null;
469
+ }
470
+ }
471
+ function parseReleasePlease(_raw, path) {
472
+ return {
473
+ commitConvention: "conventional",
474
+ pullRequestTitleConvention: null,
475
+ allowedTypes: null,
476
+ scopes: null,
477
+ sources: [{ path, detail: "release-please (Conventional Commits)" }]
478
+ };
479
+ }
480
+ function parseSemanticRelease(path) {
481
+ return {
482
+ commitConvention: "conventional",
483
+ pullRequestTitleConvention: null,
484
+ allowedTypes: null,
485
+ scopes: null,
486
+ sources: [{ path, detail: "semantic-release" }]
487
+ };
488
+ }
489
+ function parseChangesetConfig(path) {
490
+ return {
491
+ commitConvention: null,
492
+ pullRequestTitleConvention: null,
493
+ allowedTypes: null,
494
+ scopes: null,
495
+ sources: [{ path, detail: "changesets release flow" }]
496
+ };
497
+ }
498
+ function parseHuskyCommitMsg(path) {
499
+ return {
500
+ commitConvention: null,
501
+ pullRequestTitleConvention: null,
502
+ allowedTypes: null,
503
+ scopes: null,
504
+ sources: [{ path, detail: "husky commit-msg hook" }]
505
+ };
506
+ }
507
+ function parseSemanticPullRequestWorkflow(source, path) {
508
+ return parseSemanticPrWorkflow(source, path);
509
+ }
510
+ var COMMITLINT_FILE_NAMES = COMMITLINT_NAMES;
511
+
59
512
  // src/policy/parsers/labels.ts
60
513
  function parseLabels(payload) {
61
514
  if (!Array.isArray(payload)) return [];
@@ -549,6 +1002,85 @@ async function discoverDocuments(root, scope) {
549
1002
  }
550
1003
  return { documents, sources };
551
1004
  }
1005
+ function asPolicySources(discovered) {
1006
+ return discovered.sources.map((entry) => ({
1007
+ kind: "git-conventions",
1008
+ origin: "filesystem",
1009
+ path: entry.path,
1010
+ status: "found",
1011
+ detail: entry.detail
1012
+ }));
1013
+ }
1014
+ async function discoverGitConventions(root) {
1015
+ let merged = {
1016
+ commitConvention: null,
1017
+ pullRequestTitleConvention: null,
1018
+ allowedTypes: null,
1019
+ scopes: null,
1020
+ sources: []
1021
+ };
1022
+ const take = (extra) => {
1023
+ if (extra === null) return;
1024
+ merged = {
1025
+ commitConvention: merged.commitConvention ?? extra.commitConvention,
1026
+ pullRequestTitleConvention: merged.pullRequestTitleConvention ?? extra.pullRequestTitleConvention,
1027
+ allowedTypes: merged.allowedTypes ?? extra.allowedTypes,
1028
+ scopes: merged.scopes ?? extra.scopes,
1029
+ sources: [...merged.sources, ...extra.sources]
1030
+ };
1031
+ };
1032
+ const pkg = await readCapped(join(root, "package.json"));
1033
+ if (pkg !== null) {
1034
+ take(parsePackageJsonCommitlint(pkg.content));
1035
+ }
1036
+ for (const name of COMMITLINT_FILE_NAMES) {
1037
+ const found = await findFile(root, [name]);
1038
+ if (found === null) continue;
1039
+ const file = await readCapped(join(root, found));
1040
+ if (file === null) continue;
1041
+ take(parseCommitlintText(file.content, found));
1042
+ }
1043
+ for (const name of ["release-please-config.json", ".release-please-manifest.json"]) {
1044
+ const found = await findFile(root, [name]);
1045
+ if (found === null) continue;
1046
+ const file = await readCapped(join(root, found));
1047
+ if (file === null) continue;
1048
+ take(parseReleasePlease(file.content, found));
1049
+ }
1050
+ for (const name of [
1051
+ ".releaserc",
1052
+ ".releaserc.json",
1053
+ ".releaserc.yaml",
1054
+ ".releaserc.yml",
1055
+ "release.config.js"
1056
+ ]) {
1057
+ const found = await findFile(root, [name]);
1058
+ if (found === null) continue;
1059
+ take(parseSemanticRelease(found));
1060
+ }
1061
+ const changeset = await findFile(join(root, ".changeset"), ["config.json"]);
1062
+ if (changeset !== null) {
1063
+ take(parseChangesetConfig(`.changeset/${changeset}`));
1064
+ }
1065
+ const husky = await findFile(join(root, ".husky"), ["commit-msg"]);
1066
+ if (husky !== null) {
1067
+ take(parseHuskyCommitMsg(`.husky/${husky}`));
1068
+ }
1069
+ const workflowDir = join(root, ".github", "workflows");
1070
+ for (const name of await listDirectory(workflowDir)) {
1071
+ if (!/\.ya?ml$/i.test(name)) continue;
1072
+ const file = await readCapped(join(workflowDir, name));
1073
+ if (file === null) continue;
1074
+ take(parseSemanticPullRequestWorkflow(file.content, `.github/workflows/${name}`));
1075
+ }
1076
+ return {
1077
+ commitConvention: merged.commitConvention,
1078
+ pullRequestTitleConvention: merged.pullRequestTitleConvention,
1079
+ allowedTypes: merged.allowedTypes,
1080
+ scopes: merged.scopes,
1081
+ sources: asPolicySources(merged)
1082
+ };
1083
+ }
552
1084
  async function discoverBaseBranch(root, exec = defaultExec) {
553
1085
  const options = { cwd: root, timeout: DISCOVERY_TIMEOUT_MS };
554
1086
  try {
@@ -834,7 +1366,15 @@ function emptyPolicy(root, scope, enabled, sources) {
834
1366
  enabled,
835
1367
  issues: { templates: [], types: [], labels: [], titleConvention: null },
836
1368
  pullRequests: { template: null, templates: [], baseBranch: null, titleConvention: null },
837
- git: { branchConvention: null, commitConvention: null },
1369
+ git: {
1370
+ branchConvention: null,
1371
+ commitConvention: null,
1372
+ pullRequestTitleConvention: null,
1373
+ issueReference: null,
1374
+ typeMap: null,
1375
+ allowedTypes: null,
1376
+ scopes: null
1377
+ },
838
1378
  docs: [],
839
1379
  codeowners: null,
840
1380
  sources
@@ -852,7 +1392,7 @@ function disabledSource(kind) {
852
1392
  var DECLARATION_KINDS = {
853
1393
  issues: "issue-templates",
854
1394
  pullRequests: "pull-request-template",
855
- git: "base-branch"
1395
+ git: "git-conventions"
856
1396
  };
857
1397
  async function resolvePolicy(root, scope, options) {
858
1398
  const warn = options.warn ?? printWarning;
@@ -868,12 +1408,15 @@ async function resolvePolicy(root, scope, options) {
868
1408
  ]);
869
1409
  }
870
1410
  const toggles = config.discovery;
871
- const [templateDiscovery, prTemplates, documents, codeowners] = await Promise.all([
872
- toggles.issueTemplates ? discoverIssueTemplates(root) : Promise.resolve({ templates: [], sources: [disabledSource("issue-templates")] }),
873
- toggles.pullRequestTemplate ? discoverPullRequestTemplates(root) : Promise.resolve({ templates: [], sources: [disabledSource("pull-request-template")] }),
874
- toggles.docs ? discoverDocuments(root, scope) : Promise.resolve({ documents: [], sources: [disabledSource("docs")] }),
875
- toggles.codeowners ? discoverCodeowners(root) : Promise.resolve({ content: null, sources: [disabledSource("codeowners")] })
876
- ]);
1411
+ const [templateDiscovery, prTemplates, documents, codeowners, gitConventions] = await Promise.all(
1412
+ [
1413
+ toggles.issueTemplates ? discoverIssueTemplates(root) : Promise.resolve({ templates: [], sources: [disabledSource("issue-templates")] }),
1414
+ toggles.pullRequestTemplate ? discoverPullRequestTemplates(root) : Promise.resolve({ templates: [], sources: [disabledSource("pull-request-template")] }),
1415
+ toggles.docs ? discoverDocuments(root, scope) : Promise.resolve({ documents: [], sources: [disabledSource("docs")] }),
1416
+ toggles.codeowners ? discoverCodeowners(root) : Promise.resolve({ content: null, sources: [disabledSource("codeowners")] }),
1417
+ discoverGitConventions(root)
1418
+ ]
1419
+ );
877
1420
  const wantsOrgTemplates = toggles.issueTemplates && templateDiscovery.templates.length === 0;
878
1421
  const [baseBranch, slug] = await Promise.all([
879
1422
  discoverBaseBranch(root, options.exec),
@@ -899,7 +1442,8 @@ async function resolvePolicy(root, scope, options) {
899
1442
  ...prTemplates.sources,
900
1443
  ...baseBranch.sources,
901
1444
  ...documents.sources,
902
- ...codeowners.sources
1445
+ ...codeowners.sources,
1446
+ ...gitConventions.sources
903
1447
  ];
904
1448
  const discoveredPullRequests = {};
905
1449
  if (baseBranch.baseBranch !== null) {
@@ -914,8 +1458,30 @@ async function resolvePolicy(root, scope, options) {
914
1458
  discovered: discoveredPullRequests,
915
1459
  project: config.pullRequests
916
1460
  });
1461
+ const discoveredGit = {};
1462
+ if (gitConventions.commitConvention !== null) {
1463
+ discoveredGit.commitConvention = gitConventions.commitConvention;
1464
+ }
1465
+ if (gitConventions.pullRequestTitleConvention !== null) {
1466
+ discoveredGit.pullRequestTitleConvention = gitConventions.pullRequestTitleConvention;
1467
+ }
1468
+ if (gitConventions.allowedTypes !== null) {
1469
+ discoveredGit.allowedTypes = gitConventions.allowedTypes;
1470
+ }
1471
+ if (gitConventions.scopes !== null) {
1472
+ discoveredGit.scopes = gitConventions.scopes;
1473
+ }
917
1474
  const git = mergeConfigLayers({
918
- defaults: { branchConvention: null, commitConvention: null },
1475
+ defaults: {
1476
+ branchConvention: null,
1477
+ commitConvention: null,
1478
+ pullRequestTitleConvention: null,
1479
+ issueReference: null,
1480
+ typeMap: null,
1481
+ allowedTypes: null,
1482
+ scopes: null
1483
+ },
1484
+ discovered: discoveredGit,
919
1485
  project: config.git
920
1486
  });
921
1487
  for (const group of ["issues", "pullRequests", "git"]) {
@@ -948,7 +1514,12 @@ async function resolvePolicy(root, scope, options) {
948
1514
  },
949
1515
  git: {
950
1516
  branchConvention: git.branchConvention ?? null,
951
- commitConvention: git.commitConvention ?? null
1517
+ commitConvention: git.commitConvention ?? null,
1518
+ pullRequestTitleConvention: git.pullRequestTitleConvention ?? null,
1519
+ issueReference: git.issueReference ?? null,
1520
+ typeMap: git.typeMap ?? null,
1521
+ allowedTypes: git.allowedTypes ?? gitConventions.allowedTypes,
1522
+ scopes: git.scopes ?? gitConventions.scopes
952
1523
  },
953
1524
  docs: documents.documents,
954
1525
  codeowners: codeowners.content,
@@ -978,6 +1549,14 @@ async function loadRepositoryPolicy(options = {}) {
978
1549
  }
979
1550
 
980
1551
  export {
1552
+ DEFAULT_BRANCH_CONVENTION,
1553
+ isChangeType,
1554
+ branchName,
1555
+ archiveFolderName,
1556
+ resolveChangeType,
1557
+ commitMessage,
1558
+ pullRequestTitle,
1559
+ issueReferenceLines,
981
1560
  loadRepositoryPolicy
982
1561
  };
983
- //# sourceMappingURL=chunk-47VIN33V.js.map
1562
+ //# sourceMappingURL=chunk-UOCPC2Y2.js.map