@bluewombat/manager-github 0.1.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 (155) hide show
  1. package/README.md +162 -0
  2. package/SPECS.md +126 -0
  3. package/dist/adapter/github/fetch-issue.d.ts +29 -0
  4. package/dist/adapter/github/fetch-issue.d.ts.map +1 -0
  5. package/dist/adapter/github/fetch-issue.js +34 -0
  6. package/dist/adapter/github/fetch-issue.js.map +1 -0
  7. package/dist/adapter/normalize/body.d.ts +24 -0
  8. package/dist/adapter/normalize/body.d.ts.map +1 -0
  9. package/dist/adapter/normalize/body.js +104 -0
  10. package/dist/adapter/normalize/body.js.map +1 -0
  11. package/dist/adapter/normalize/fingerprint.d.ts +8 -0
  12. package/dist/adapter/normalize/fingerprint.d.ts.map +1 -0
  13. package/dist/adapter/normalize/fingerprint.js +26 -0
  14. package/dist/adapter/normalize/fingerprint.js.map +1 -0
  15. package/dist/adapter/normalize/intent.d.ts +27 -0
  16. package/dist/adapter/normalize/intent.d.ts.map +1 -0
  17. package/dist/adapter/normalize/intent.js +57 -0
  18. package/dist/adapter/normalize/intent.js.map +1 -0
  19. package/dist/adapter/normalize/labels.d.ts +17 -0
  20. package/dist/adapter/normalize/labels.d.ts.map +1 -0
  21. package/dist/adapter/normalize/labels.js +43 -0
  22. package/dist/adapter/normalize/labels.js.map +1 -0
  23. package/dist/adapter/normalize/noise.d.ts +13 -0
  24. package/dist/adapter/normalize/noise.d.ts.map +1 -0
  25. package/dist/adapter/normalize/noise.js +28 -0
  26. package/dist/adapter/normalize/noise.js.map +1 -0
  27. package/dist/adapter/normalize/normalize.d.ts +22 -0
  28. package/dist/adapter/normalize/normalize.d.ts.map +1 -0
  29. package/dist/adapter/normalize/normalize.js +216 -0
  30. package/dist/adapter/normalize/normalize.js.map +1 -0
  31. package/dist/adapter/progress/emit.d.ts +3 -0
  32. package/dist/adapter/progress/emit.d.ts.map +1 -0
  33. package/dist/adapter/progress/emit.js +6 -0
  34. package/dist/adapter/progress/emit.js.map +1 -0
  35. package/dist/adapter/raw/parse-raw.d.ts +14 -0
  36. package/dist/adapter/raw/parse-raw.d.ts.map +1 -0
  37. package/dist/adapter/raw/parse-raw.js +47 -0
  38. package/dist/adapter/raw/parse-raw.js.map +1 -0
  39. package/dist/adapter/raw/unwrap.d.ts +12 -0
  40. package/dist/adapter/raw/unwrap.d.ts.map +1 -0
  41. package/dist/adapter/raw/unwrap.js +19 -0
  42. package/dist/adapter/raw/unwrap.js.map +1 -0
  43. package/dist/adapter/run/run-adapter.d.ts +28 -0
  44. package/dist/adapter/run/run-adapter.d.ts.map +1 -0
  45. package/dist/adapter/run/run-adapter.js +131 -0
  46. package/dist/adapter/run/run-adapter.js.map +1 -0
  47. package/dist/adapter/types.d.ts +69 -0
  48. package/dist/adapter/types.d.ts.map +1 -0
  49. package/dist/adapter/types.js +3 -0
  50. package/dist/adapter/types.js.map +1 -0
  51. package/dist/emitter/event/field-matrix.d.ts +29 -0
  52. package/dist/emitter/event/field-matrix.d.ts.map +1 -0
  53. package/dist/emitter/event/field-matrix.js +94 -0
  54. package/dist/emitter/event/field-matrix.js.map +1 -0
  55. package/dist/emitter/github/comments.d.ts +14 -0
  56. package/dist/emitter/github/comments.d.ts.map +1 -0
  57. package/dist/emitter/github/comments.js +69 -0
  58. package/dist/emitter/github/comments.js.map +1 -0
  59. package/dist/emitter/github/labels.d.ts +18 -0
  60. package/dist/emitter/github/labels.d.ts.map +1 -0
  61. package/dist/emitter/github/labels.js +81 -0
  62. package/dist/emitter/github/labels.js.map +1 -0
  63. package/dist/emitter/github/result.d.ts +19 -0
  64. package/dist/emitter/github/result.d.ts.map +1 -0
  65. package/dist/emitter/github/result.js +2 -0
  66. package/dist/emitter/github/result.js.map +1 -0
  67. package/dist/emitter/progress/emit.d.ts +3 -0
  68. package/dist/emitter/progress/emit.d.ts.map +1 -0
  69. package/dist/emitter/progress/emit.js +6 -0
  70. package/dist/emitter/progress/emit.js.map +1 -0
  71. package/dist/emitter/render/render-event.d.ts +20 -0
  72. package/dist/emitter/render/render-event.d.ts.map +1 -0
  73. package/dist/emitter/render/render-event.js +293 -0
  74. package/dist/emitter/render/render-event.js.map +1 -0
  75. package/dist/emitter/render/truncate.d.ts +9 -0
  76. package/dist/emitter/render/truncate.d.ts.map +1 -0
  77. package/dist/emitter/render/truncate.js +10 -0
  78. package/dist/emitter/render/truncate.js.map +1 -0
  79. package/dist/emitter/run/run-emitter.d.ts +27 -0
  80. package/dist/emitter/run/run-emitter.d.ts.map +1 -0
  81. package/dist/emitter/run/run-emitter.js +121 -0
  82. package/dist/emitter/run/run-emitter.js.map +1 -0
  83. package/dist/emitter/thread/marker.d.ts +15 -0
  84. package/dist/emitter/thread/marker.d.ts.map +1 -0
  85. package/dist/emitter/thread/marker.js +37 -0
  86. package/dist/emitter/thread/marker.js.map +1 -0
  87. package/dist/emitter/types.d.ts +64 -0
  88. package/dist/emitter/types.d.ts.map +1 -0
  89. package/dist/emitter/types.js +3 -0
  90. package/dist/emitter/types.js.map +1 -0
  91. package/dist/github/client.d.ts +63 -0
  92. package/dist/github/client.d.ts.map +1 -0
  93. package/dist/github/client.js +96 -0
  94. package/dist/github/client.js.map +1 -0
  95. package/dist/index.d.ts +55 -0
  96. package/dist/index.d.ts.map +1 -0
  97. package/dist/index.js +357 -0
  98. package/dist/index.js.map +1 -0
  99. package/dist/issue-number.d.ts +5 -0
  100. package/dist/issue-number.d.ts.map +1 -0
  101. package/dist/issue-number.js +32 -0
  102. package/dist/issue-number.js.map +1 -0
  103. package/dist/labels.d.ts +3 -0
  104. package/dist/labels.d.ts.map +1 -0
  105. package/dist/labels.js +24 -0
  106. package/dist/labels.js.map +1 -0
  107. package/dist/listener/delivery/run-hook.d.ts +8 -0
  108. package/dist/listener/delivery/run-hook.d.ts.map +1 -0
  109. package/dist/listener/delivery/run-hook.js +50 -0
  110. package/dist/listener/delivery/run-hook.js.map +1 -0
  111. package/dist/listener/github/list-issues.d.ts +30 -0
  112. package/dist/listener/github/list-issues.d.ts.map +1 -0
  113. package/dist/listener/github/list-issues.js +36 -0
  114. package/dist/listener/github/list-issues.js.map +1 -0
  115. package/dist/listener/progress/emit.d.ts +3 -0
  116. package/dist/listener/progress/emit.d.ts.map +1 -0
  117. package/dist/listener/progress/emit.js +6 -0
  118. package/dist/listener/progress/emit.js.map +1 -0
  119. package/dist/listener/run/run-listener.d.ts +35 -0
  120. package/dist/listener/run/run-listener.d.ts.map +1 -0
  121. package/dist/listener/run/run-listener.js +217 -0
  122. package/dist/listener/run/run-listener.js.map +1 -0
  123. package/dist/listener/source/select-events.d.ts +46 -0
  124. package/dist/listener/source/select-events.d.ts.map +1 -0
  125. package/dist/listener/source/select-events.js +102 -0
  126. package/dist/listener/source/select-events.js.map +1 -0
  127. package/dist/listener/types.d.ts +56 -0
  128. package/dist/listener/types.d.ts.map +1 -0
  129. package/dist/listener/types.js +3 -0
  130. package/dist/listener/types.js.map +1 -0
  131. package/dist/manager.d.ts +29 -0
  132. package/dist/manager.d.ts.map +1 -0
  133. package/dist/manager.js +256 -0
  134. package/dist/manager.js.map +1 -0
  135. package/dist/probe/probe-issue.d.ts +20 -0
  136. package/dist/probe/probe-issue.d.ts.map +1 -0
  137. package/dist/probe/probe-issue.js +45 -0
  138. package/dist/probe/probe-issue.js.map +1 -0
  139. package/dist/repo.d.ts +6 -0
  140. package/dist/repo.d.ts.map +1 -0
  141. package/dist/repo.js +14 -0
  142. package/dist/repo.js.map +1 -0
  143. package/dist/setup.d.ts +43 -0
  144. package/dist/setup.d.ts.map +1 -0
  145. package/dist/setup.js +281 -0
  146. package/dist/setup.js.map +1 -0
  147. package/dist/submission/submission.d.ts +44 -0
  148. package/dist/submission/submission.d.ts.map +1 -0
  149. package/dist/submission/submission.js +189 -0
  150. package/dist/submission/submission.js.map +1 -0
  151. package/dist/written-fingerprint.d.ts +7 -0
  152. package/dist/written-fingerprint.d.ts.map +1 -0
  153. package/dist/written-fingerprint.js +38 -0
  154. package/dist/written-fingerprint.js.map +1 -0
  155. package/package.json +51 -0
@@ -0,0 +1,293 @@
1
+ import { FIELD_ORDER } from "../event/field-matrix.js";
2
+ import { renderMarker } from "../thread/marker.js";
3
+ import { truncateText } from "./truncate.js";
4
+ /** Free-text fields the report ceiling applies to. */
5
+ const BOUNDED_FIELDS = ["reason", "plan", "trace"];
6
+ /** Fields rendered as a fenced block rather than a bullet. */
7
+ const BLOCK_FIELDS = ["trace"];
8
+ /** Fields that are already text a reader can read, rendered as they are. */
9
+ const PROSE_FIELDS = ["plan"];
10
+ /** Said first, as a sentence: no label, no bullet. */
11
+ const LEAD_FIELDS = ["summary"];
12
+ /**
13
+ * The heading of a comment.
14
+ *
15
+ * The Event, in words, and nothing else: the issue page already shows who
16
+ * commented and when, and the timestamp stays in the record below for machines.
17
+ */
18
+ const TITLES = {
19
+ invalid: "Not accepted",
20
+ accepted: "Accepted",
21
+ planned: "Planned",
22
+ progress: "In progress",
23
+ escalated: "Escalated",
24
+ escalation_reminder: "Still escalated",
25
+ resumed: "Resumed",
26
+ submitted: "Submitted",
27
+ done: "Done",
28
+ cancelled: "Cancelled",
29
+ reject_late: "Too late",
30
+ };
31
+ const SECTION_TITLES = {
32
+ trace: "Trace",
33
+ plan: "Plan",
34
+ };
35
+ /** A field whose generic name says nothing useful under a given Event. */
36
+ const FIELD_LABELS = {
37
+ done: { reference: "merged into", integration_reference: "commit" },
38
+ submitted: { reference: "under review at" },
39
+ };
40
+ /** Where on the 0…100 scale a priority stops being ordinary. */
41
+ const HIGH_PRIORITY = 75;
42
+ const LOW_PRIORITY = 25;
43
+ /**
44
+ * Turn one invocation into the exact bytes the Thread receives.
45
+ * Pure: --dry-run renders through this same function, so a preview cannot lie.
46
+ */
47
+ export function renderEvent(invocation) {
48
+ const bounded = applyCeiling(invocation.fields, invocation.maxReportChars);
49
+ // The record is what a machine needs to tell one comment from another and
50
+ // to say it once — nothing more. The fields are in the section above it,
51
+ // where a human reads them; repeating them here doubled every comment.
52
+ const record = {
53
+ event: invocation.event,
54
+ key: invocation.key,
55
+ project: invocation.project,
56
+ at: invocation.at,
57
+ };
58
+ if (invocation.eventId !== undefined) {
59
+ record.event_id = invocation.eventId;
60
+ }
61
+ if (bounded.truncated.length > 0) {
62
+ record.truncated = bounded.truncated;
63
+ }
64
+ let section;
65
+ switch (invocation.event) {
66
+ case "invalid":
67
+ section = renderInvalid(bounded.fields);
68
+ break;
69
+ case "accepted":
70
+ section = renderAccepted(invocation, bounded.fields);
71
+ break;
72
+ case "planned":
73
+ section = renderPlanned(bounded.fields);
74
+ break;
75
+ case "escalated":
76
+ section = renderEscalated(bounded.fields);
77
+ break;
78
+ case "resumed":
79
+ section = renderResumed(bounded.fields);
80
+ break;
81
+ case "done":
82
+ section =
83
+ bounded.fields.reference === undefined && bounded.fields.integration_reference === undefined
84
+ ? renderDoneLocally()
85
+ : renderSection(invocation, bounded.fields);
86
+ break;
87
+ default:
88
+ section = renderSection(invocation, bounded.fields);
89
+ break;
90
+ }
91
+ return { record, section, body: `${section}${renderMarker(record)}\n` };
92
+ }
93
+ function applyCeiling(fields, maxChars) {
94
+ const out = { ...fields };
95
+ const truncated = [];
96
+ for (const field of BOUNDED_FIELDS) {
97
+ const value = out[field];
98
+ if (typeof value !== "string") {
99
+ continue;
100
+ }
101
+ const cut = truncateText(value, maxChars);
102
+ if (cut.truncated) {
103
+ truncated.push(field);
104
+ out[field] = cut.text;
105
+ }
106
+ }
107
+ return { fields: out, truncated };
108
+ }
109
+ /**
110
+ * Dedicated comments for Events the generic field dump would mis-say.
111
+ * Each is a string literal; `renderEvent` is what chooses this over `renderSection`.
112
+ */
113
+ function renderInvalid(fields) {
114
+ return `## Not accepted
115
+
116
+ I’m sorry, but I can’t process this issue because some of the required information is missing.
117
+
118
+ ${fields.reason ?? ""}
119
+ `;
120
+ }
121
+ function renderAccepted(invocation, fields) {
122
+ const priority = typeof fields.priority === "number" ? fields.priority : 0;
123
+ return `## Accepted
124
+
125
+ Taken in at ${priorityPhrase(priority, invocation.defaultPriority)}.
126
+ `;
127
+ }
128
+ function renderPlanned(fields) {
129
+ return `## Planned
130
+
131
+ I have planned this work this issue.
132
+
133
+ ${fields.plan ?? ""}
134
+ `;
135
+ }
136
+ function renderEscalated(fields) {
137
+ const where = escalatedWhere(fields);
138
+ const trace = fields.trace === undefined || fields.trace.length === 0
139
+ ? ""
140
+ : `
141
+
142
+ ### Trace
143
+
144
+ \`\`\`text
145
+ ${fields.trace}
146
+ \`\`\``;
147
+ return `## Escalated
148
+
149
+ 🙋 A human action is required to continue.
150
+
151
+ ${fields.reason ?? ""}${where}
152
+
153
+ No further work starts until a human answers.${trace}
154
+ `;
155
+ }
156
+ /** A fold with no Authority: there is nothing a reader could open, so say where it went in words. */
157
+ function renderDoneLocally() {
158
+ return `## Done
159
+
160
+ Folded into the work line.
161
+ `;
162
+ }
163
+ function renderResumed(fields) {
164
+ const reason = fields.reason === undefined || fields.reason.length === 0 ? "" : `\n\n${fields.reason}`;
165
+ return `## Resumed
166
+
167
+ Work continues from ${fields.resume_point ?? ""}.${reason}
168
+ `;
169
+ }
170
+ const STAGE_PHRASE = {
171
+ plan: "while planning",
172
+ unit: "on a Subtask",
173
+ integrating: "while assembling the feature",
174
+ submitting: "while the Submission was under review",
175
+ merging: "while folding into the work line",
176
+ };
177
+ function escalatedWhere(fields) {
178
+ const unit = fields.unit;
179
+ const attempts = fields.counters?.attempts;
180
+ if (unit !== undefined && unit.length > 0 && attempts !== undefined) {
181
+ return `\n\nAfter ${attemptsShown(attempts)} attempts on \`${unit}\`.`;
182
+ }
183
+ if (unit !== undefined && unit.length > 0) {
184
+ return `\n\nOn \`${unit}\`.`;
185
+ }
186
+ if (fields.stage !== undefined) {
187
+ return `\n\nThis happened ${STAGE_PHRASE[fields.stage]}.`;
188
+ }
189
+ return "";
190
+ }
191
+ function attemptsShown(raw) {
192
+ const slash = /^(\d+)\/(\d+)$/.exec(raw);
193
+ return slash === null ? raw : `${slash[1]} of ${slash[2]}`;
194
+ }
195
+ function priorityPhrase(priority, fallback) {
196
+ if (fallback !== undefined && priority === fallback) {
197
+ return `priority ${priority}/100 (the default)`;
198
+ }
199
+ const word = priority >= HIGH_PRIORITY ? "high" : priority <= LOW_PRIORITY ? "low" : "normal";
200
+ return `${word} priority (${priority}/100)`;
201
+ }
202
+ function renderSection(invocation, fields) {
203
+ // The key and the project are not repeated here: this comment is on that
204
+ // issue, and the project is on its label. Both stay in the record below.
205
+ const lines = [`## ${TITLES[invocation.event]}`];
206
+ for (const field of LEAD_FIELDS) {
207
+ const value = fields[field];
208
+ if (typeof value === "string") {
209
+ lines.push("", value);
210
+ }
211
+ }
212
+ // Collected rather than pushed, so an Event carrying no bullet at all does
213
+ // not leave a blank line standing under its heading.
214
+ const bullets = [];
215
+ for (const field of FIELD_ORDER) {
216
+ if (BLOCK_FIELDS.includes(field) ||
217
+ PROSE_FIELDS.includes(field) ||
218
+ LEAD_FIELDS.includes(field)) {
219
+ continue;
220
+ }
221
+ const value = fields[field];
222
+ if (value === undefined) {
223
+ continue;
224
+ }
225
+ const shown = field === "priority" && typeof value === "number"
226
+ ? priorityInWords(value, invocation.defaultPriority)
227
+ : bullet(value);
228
+ bullets.push(`- ${label(invocation.event, field)}: ${shown}`);
229
+ }
230
+ const note = standingNote(invocation);
231
+ if (note !== undefined) {
232
+ bullets.push(`- ${note}`);
233
+ }
234
+ if (bullets.length > 0) {
235
+ lines.push("", ...bullets);
236
+ }
237
+ for (const field of PROSE_FIELDS) {
238
+ const value = fields[field];
239
+ if (typeof value !== "string") {
240
+ continue;
241
+ }
242
+ lines.push("", `### ${title(field)}`, "", value);
243
+ }
244
+ for (const field of BLOCK_FIELDS) {
245
+ const value = fields[field];
246
+ if (typeof value !== "string") {
247
+ continue;
248
+ }
249
+ lines.push("", `### ${title(field)}`, "", "```text", value, "```");
250
+ }
251
+ lines.push("");
252
+ return `${lines.join("\n")}\n`;
253
+ }
254
+ /**
255
+ * `80/100` says nothing to someone who never saw the scale. A word first, the
256
+ * number after, and "default" when nobody chose — so a reader knows a label
257
+ * would change it.
258
+ */
259
+ export function priorityInWords(priority, fallback) {
260
+ if (fallback !== undefined && priority === fallback) {
261
+ return `${priority}/100 (default)`;
262
+ }
263
+ const word = priority >= HIGH_PRIORITY ? "high" : priority <= LOW_PRIORITY ? "low" : "normal";
264
+ return `${word} (${priority}/100)`;
265
+ }
266
+ /** What a reader must be told about this Event beyond its fields. */
267
+ function standingNote(invocation) {
268
+ switch (invocation.event) {
269
+ case "escalated":
270
+ return "frozen: no further work starts until a human answers";
271
+ case "escalation_reminder":
272
+ return "frozen: still waiting, this is a repeat of an earlier escalation";
273
+ case "reject_late":
274
+ return "too late: this arrived after the point of no return";
275
+ default:
276
+ return undefined;
277
+ }
278
+ }
279
+ function label(event, field) {
280
+ return FIELD_LABELS[event]?.[field] ?? field.replace(/_/g, " ");
281
+ }
282
+ function title(field) {
283
+ return SECTION_TITLES[field] ?? field.replace(/_/g, " ");
284
+ }
285
+ function bullet(value) {
286
+ if (value !== null && typeof value === "object") {
287
+ return Object.entries(value)
288
+ .map(([name, entry]) => `${name}=${entry}`)
289
+ .join(", ");
290
+ }
291
+ return String(value);
292
+ }
293
+ //# sourceMappingURL=render-event.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-event.js","sourceRoot":"","sources":["../../../src/emitter/render/render-event.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export declare const TRUNCATION_MARKER = " [\u2026truncated]";
2
+ export type TruncateResult = {
3
+ text: string;
4
+ truncated: boolean;
5
+ };
6
+ /** Cut long free text, and say so: a silent cut makes a human trust a
7
+ * truncated diagnosis. */
8
+ export declare function truncateText(text: string, maxChars: number): TruncateResult;
9
+ //# sourceMappingURL=truncate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncate.d.ts","sourceRoot":"","sources":["../../../src/emitter/render/truncate.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,uBAAkB,CAAC;AAEjD,MAAM,MAAM,cAAc,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC;AAElE;2BAC2B;AAC3B,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,CAK3E"}
@@ -0,0 +1,10 @@
1
+ export const TRUNCATION_MARKER = " […truncated]";
2
+ /** Cut long free text, and say so: a silent cut makes a human trust a
3
+ * truncated diagnosis. */
4
+ export function truncateText(text, maxChars) {
5
+ if (text.length <= maxChars) {
6
+ return { text, truncated: false };
7
+ }
8
+ return { text: `${text.slice(0, maxChars)}${TRUNCATION_MARKER}`, truncated: true };
9
+ }
10
+ //# sourceMappingURL=truncate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncate.js","sourceRoot":"","sources":["../../../src/emitter/render/truncate.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,iBAAiB,GAAG,eAAe,CAAC;AAIjD;2BAC2B;AAC3B,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,QAAgB;IACzD,IAAI,IAAI,CAAC,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC5B,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IACpC,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,iBAAiB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AACrF,CAAC"}
@@ -0,0 +1,27 @@
1
+ import type { GithubClient } from "../../github/client.js";
2
+ import type { ProgressWriter } from "../progress/emit.js";
3
+ import type { Invocation, RunOutcome } from "../types.js";
4
+ export type RunResult = {
5
+ outcome: RunOutcome;
6
+ /** `<owner>/<name>#<issue>`: the Thread this Event was appended to. */
7
+ thread: string;
8
+ commentUrl?: string;
9
+ detail?: string;
10
+ exitCode: number;
11
+ };
12
+ export type RunOptions = {
13
+ invocation: Invocation;
14
+ /** The authenticated channel to the Target. Not needed by a dry run. */
15
+ github?: GithubClient;
16
+ write?: ProgressWriter;
17
+ now?: () => number;
18
+ interruptFlag?: {
19
+ interrupted: boolean;
20
+ };
21
+ };
22
+ export declare function invalidInvocationResult(write: ProgressWriter, reason: string): RunResult;
23
+ /**
24
+ * Run one FeatureEmitter invocation to a run outcome.
25
+ */
26
+ export declare function runEmitter(options: RunOptions): Promise<RunResult>;
27
+ //# sourceMappingURL=run-emitter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-emitter.d.ts","sourceRoot":"","sources":["../../../src/emitter/run/run-emitter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAI3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAG1D,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,EAAE,UAAU,CAAC;IACpB,uEAAuE;IACvE,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,UAAU,EAAE,UAAU,CAAC;IACvB,wEAAwE;IACxE,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE;QAAE,WAAW,EAAE,OAAO,CAAA;KAAE,CAAC;CAC1C,CAAC;AAiBF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,CAQxF;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAoGxE"}
@@ -0,0 +1,121 @@
1
+ import { createComment, listCommentBodies } from "../github/comments.js";
2
+ import { syncStateLabel } from "../github/labels.js";
3
+ import { renderEvent } from "../render/render-event.js";
4
+ import { hasEventId } from "../thread/marker.js";
5
+ function exitCodeFor(outcome) {
6
+ switch (outcome) {
7
+ case "reported":
8
+ case "duplicate":
9
+ case "rendered":
10
+ return 0;
11
+ case "unreportable":
12
+ return 1;
13
+ case "invalid-invocation":
14
+ return 2;
15
+ case "interrupted":
16
+ return 130;
17
+ }
18
+ }
19
+ export function invalidInvocationResult(write, reason) {
20
+ write({ event: "result", outcome: "invalid-invocation", detail: reason });
21
+ return {
22
+ outcome: "invalid-invocation",
23
+ thread: "",
24
+ detail: reason,
25
+ exitCode: exitCodeFor("invalid-invocation"),
26
+ };
27
+ }
28
+ /**
29
+ * Run one FeatureEmitter invocation to a run outcome.
30
+ */
31
+ export async function runEmitter(options) {
32
+ const { invocation } = options;
33
+ const write = options.write ?? (() => { });
34
+ const now = options.now ?? (() => Date.now());
35
+ const interruptState = options.interruptFlag ?? { interrupted: false };
36
+ const shouldInterrupt = () => interruptState.interrupted;
37
+ const thread = `${invocation.repo.owner}/${invocation.repo.name}#${invocation.issue}`;
38
+ let commentUrl;
39
+ const finish = (outcome, detail) => {
40
+ const line = {
41
+ event: "result",
42
+ outcome,
43
+ key: invocation.key,
44
+ project: invocation.project,
45
+ thread,
46
+ };
47
+ if (commentUrl !== undefined) {
48
+ line.comment_url = commentUrl;
49
+ }
50
+ if (detail !== undefined) {
51
+ line.detail = detail;
52
+ }
53
+ write(line);
54
+ const result = { outcome, thread, exitCode: exitCodeFor(outcome) };
55
+ if (commentUrl !== undefined) {
56
+ result.commentUrl = commentUrl;
57
+ }
58
+ if (detail !== undefined) {
59
+ result.detail = detail;
60
+ }
61
+ return result;
62
+ };
63
+ if (shouldInterrupt()) {
64
+ return finish("interrupted");
65
+ }
66
+ const rendered = renderEvent(invocation);
67
+ if (invocation.dryRun) {
68
+ write({
69
+ event: "render",
70
+ key: invocation.key,
71
+ thread,
72
+ body: rendered.body,
73
+ record: rendered.record,
74
+ });
75
+ return finish("rendered");
76
+ }
77
+ if (options.github === undefined) {
78
+ return finish("unreportable", "No authenticated channel was given for the Target.");
79
+ }
80
+ const github = options.github;
81
+ const context = {
82
+ deadlineMs: now() + invocation.durationMs,
83
+ now,
84
+ shouldInterrupt,
85
+ };
86
+ if (invocation.eventId !== undefined) {
87
+ const listed = await listCommentBodies(invocation, github, context);
88
+ if (listed.kind === "interrupted") {
89
+ return finish("interrupted");
90
+ }
91
+ if (listed.kind === "unreportable") {
92
+ return finish("unreportable", listed.detail);
93
+ }
94
+ if (hasEventId(listed.value, invocation.eventId)) {
95
+ return finish("duplicate");
96
+ }
97
+ }
98
+ const created = await createComment(invocation, github, context, rendered.body);
99
+ if (created.kind === "interrupted") {
100
+ return finish("interrupted");
101
+ }
102
+ if (created.kind === "unreportable") {
103
+ return finish("unreportable", created.detail);
104
+ }
105
+ commentUrl = created.value.url;
106
+ // The Event is committed. The label is a rendering of it: failing to move it
107
+ // leaves the report standing, the way a missing section leaves the truth.
108
+ if (invocation.labelPrefix !== undefined) {
109
+ const synced = await syncStateLabel(invocation, github, context, invocation.labelPrefix);
110
+ write({
111
+ event: "labels-finished",
112
+ key: invocation.key,
113
+ thread,
114
+ result: synced.kind === "ok" ? "moved" : synced.kind,
115
+ ...(synced.kind === "ok" ? { added: synced.value.added, removed: synced.value.removed } : {}),
116
+ ...(synced.kind === "unreportable" ? { detail: synced.detail } : {}),
117
+ });
118
+ }
119
+ return finish("reported");
120
+ }
121
+ //# sourceMappingURL=run-emitter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-emitter.js","sourceRoot":"","sources":["../../../src/emitter/run/run-emitter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { EventRecord } from "../types.js";
2
+ /**
3
+ * The machine surface of a Thread.
4
+ *
5
+ * A comment is one surface for two audiences: a human reads the section, and a
6
+ * machine reads the record. The record travels inside an HTML comment, which
7
+ * GitHub renders as nothing at all, so neither audience pays for the other.
8
+ */
9
+ export declare const MARKER_TAG = "feature-event";
10
+ export declare function renderMarker(record: EventRecord): string;
11
+ /** Every record a comment body carries. A body a human wrote carries none. */
12
+ export declare function readMarkers(body: string): EventRecord[];
13
+ /** Whether this event id is already in the Thread. */
14
+ export declare function hasEventId(bodies: string[], eventId: string): boolean;
15
+ //# sourceMappingURL=marker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"marker.d.ts","sourceRoot":"","sources":["../../../src/emitter/thread/marker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,kBAAkB,CAAC;AAE1C,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAExD;AAED,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,EAAE,CAkBvD;AAED,sDAAsD;AACtD,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAErE"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * The machine surface of a Thread.
3
+ *
4
+ * A comment is one surface for two audiences: a human reads the section, and a
5
+ * machine reads the record. The record travels inside an HTML comment, which
6
+ * GitHub renders as nothing at all, so neither audience pays for the other.
7
+ */
8
+ export const MARKER_TAG = "feature-event";
9
+ export function renderMarker(record) {
10
+ return `<!-- ${MARKER_TAG} ${JSON.stringify(record)} -->`;
11
+ }
12
+ /** Every record a comment body carries. A body a human wrote carries none. */
13
+ export function readMarkers(body) {
14
+ const pattern = new RegExp(`<!--\\s*${MARKER_TAG}\\s*([\\s\\S]*?)-->`, "g");
15
+ const records = [];
16
+ for (const matched of body.matchAll(pattern)) {
17
+ const payload = matched[1];
18
+ if (payload === undefined) {
19
+ continue;
20
+ }
21
+ try {
22
+ const parsed = JSON.parse(payload.trim());
23
+ if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
24
+ records.push(parsed);
25
+ }
26
+ }
27
+ catch {
28
+ // A marker this Block did not write is not a record it has to honour.
29
+ }
30
+ }
31
+ return records;
32
+ }
33
+ /** Whether this event id is already in the Thread. */
34
+ export function hasEventId(bodies, eventId) {
35
+ return bodies.some((body) => readMarkers(body).some((record) => record.event_id === eventId));
36
+ }
37
+ //# sourceMappingURL=marker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"marker.js","sourceRoot":"","sources":["../../../src/emitter/thread/marker.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,eAAe,CAAC;AAE1C,MAAM,UAAU,YAAY,CAAC,MAAmB;IAC9C,OAAO,QAAQ,UAAU,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC;AAC5D,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,WAAW,UAAU,qBAAqB,EAAE,GAAG,CAAC,CAAC;IAC5E,MAAM,OAAO,GAAkB,EAAE,CAAC;IAClC,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7C,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QAC3B,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,SAAS;QACX,CAAC;QACD,IAAI,CAAC;YACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;YACnD,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC5E,OAAO,CAAC,IAAI,CAAC,MAAqB,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,sEAAsE;QACxE,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,UAAU,CAAC,MAAgB,EAAE,OAAe;IAC1D,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC;AAChG,CAAC"}
@@ -0,0 +1,64 @@
1
+ /** Domain types owned by FeatureEmitter. Names match the Block perimeter only. */
2
+ export type RunOutcome = "reported" | "duplicate" | "rendered" | "unreportable" | "invalid-invocation" | "interrupted";
3
+ export type EventName = "invalid" | "accepted" | "planned" | "progress" | "escalated" | "escalation_reminder" | "resumed" | "submitted" | "done" | "cancelled" | "reject_late";
4
+ export type Stage = "plan" | "unit" | "integrating" | "submitting" | "merging";
5
+ export type ResumePoint = "planning" | "running" | "integrating";
6
+ /** The Target: one repository. */
7
+ export type Repository = {
8
+ owner: string;
9
+ name: string;
10
+ };
11
+ /** Every field an Event may carry beyond key, project and timestamp. */
12
+ export type EventFields = {
13
+ /** One sentence a reader gets first, under the heading and before any field. */
14
+ summary?: string;
15
+ reason?: string;
16
+ stage?: Stage;
17
+ trace?: string;
18
+ counters?: Record<string, string>;
19
+ plan?: string;
20
+ priority?: number;
21
+ unit?: string;
22
+ remaining?: number;
23
+ state?: string;
24
+ resume_point?: ResumePoint;
25
+ reference?: string;
26
+ /** On `done`: the work line's own name for the fold — a commit — when the Authority gave one. */
27
+ integration_reference?: string;
28
+ workspace_ref?: string;
29
+ };
30
+ export type Invocation = {
31
+ repo: Repository;
32
+ /** The Thread: the issue this Event is appended to. */
33
+ issue: number;
34
+ /** Root of the REST API, so a GitHub Enterprise host is one argument away. */
35
+ apiBase: string;
36
+ event: EventName;
37
+ key: string;
38
+ project: string;
39
+ at: string;
40
+ eventId?: string;
41
+ fields: EventFields;
42
+ maxReportChars: number;
43
+ /** What `priority` is when nobody chose one, so the comment can say so. */
44
+ defaultPriority?: number;
45
+ /** When set, the Event also lands as `<prefix><event>` on the issue. */
46
+ labelPrefix?: string;
47
+ durationMs: number;
48
+ /** Extra attempts after the first, on a transport failure, a 5xx, or a rate limit. */
49
+ requestRetries: number;
50
+ dryRun: boolean;
51
+ };
52
+ export type ParseResult =
53
+ /** The token is beside the Invocation, never inside it; a dry run needs none. */
54
+ {
55
+ ok: true;
56
+ invocation: Invocation;
57
+ token?: string;
58
+ } | {
59
+ ok: false;
60
+ reason: string;
61
+ };
62
+ /** The record a comment carries for machines, inside its marker. */
63
+ export type EventRecord = Record<string, unknown>;
64
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/emitter/types.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAElF,MAAM,MAAM,UAAU,GAClB,UAAU,GACV,WAAW,GACX,UAAU,GACV,cAAc,GACd,oBAAoB,GACpB,aAAa,CAAC;AAElB,MAAM,MAAM,SAAS,GACjB,SAAS,GACT,UAAU,GACV,SAAS,GACT,UAAU,GACV,WAAW,GACX,qBAAqB,GACrB,SAAS,GACT,WAAW,GACX,MAAM,GACN,WAAW,GACX,aAAa,CAAC;AAElB,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,aAAa,GAAG,YAAY,GAAG,SAAS,CAAC;AAE/E,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,SAAS,GAAG,aAAa,CAAC;AAEjE,kCAAkC;AAClC,MAAM,MAAM,UAAU,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzD,wEAAwE;AACxE,MAAM,MAAM,WAAW,GAAG;IACxB,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,WAAW,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iGAAiG;IACjG,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,UAAU,CAAC;IACjB,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,SAAS,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,2EAA2E;IAC3E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,sFAAsF;IACtF,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,WAAW;AACrB,iFAAiF;AACjF;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,UAAU,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvF,oEAAoE;AACpE,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** Domain types owned by FeatureEmitter. Names match the Block perimeter only. */
2
+ export {};
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/emitter/types.ts"],"names":[],"mappings":"AAAA,kFAAkF"}