@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,131 @@
1
+ import { fetchIssue } from "../github/fetch-issue.js";
2
+ import { normalize } from "../normalize/normalize.js";
3
+ import { parseRaw } from "../raw/parse-raw.js";
4
+ import { unwrapIssue } from "../raw/unwrap.js";
5
+ function exitCodeFor(outcome) {
6
+ switch (outcome) {
7
+ case "converted":
8
+ return 0;
9
+ case "invalid":
10
+ return 1;
11
+ case "invalid-invocation":
12
+ return 2;
13
+ case "unavailable":
14
+ return 3;
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
+ detail: reason,
24
+ exitCode: exitCodeFor("invalid-invocation"),
25
+ };
26
+ }
27
+ /** The issue number a Fetch would re-read, before any normalization. */
28
+ function fetchableNumber(issue) {
29
+ const value = issue.number;
30
+ if (typeof value === "number" && Number.isInteger(value) && value > 0) {
31
+ return value;
32
+ }
33
+ if (typeof value === "string" && /^\d+$/.test(value.trim())) {
34
+ return Number(value.trim());
35
+ }
36
+ return undefined;
37
+ }
38
+ /**
39
+ * Run one FeatureAdapter invocation to a run outcome.
40
+ */
41
+ export async function runAdapter(options) {
42
+ const { invocation, raw } = options;
43
+ const write = options.write ?? (() => { });
44
+ const now = options.now ?? (() => Date.now());
45
+ const interruptState = options.interruptFlag ?? { interrupted: false };
46
+ const shouldInterrupt = () => interruptState.interrupted;
47
+ const finishInvalid = (invalid) => {
48
+ write({
49
+ event: "result",
50
+ manager: invocation.manager,
51
+ outcome: "invalid",
52
+ code: invalid.code,
53
+ reason: invalid.reason,
54
+ });
55
+ return { outcome: "invalid", invalid, exitCode: exitCodeFor("invalid") };
56
+ };
57
+ const finishUnavailable = (detail) => {
58
+ write({ event: "result", manager: invocation.manager, outcome: "unavailable", detail });
59
+ return { outcome: "unavailable", detail, exitCode: exitCodeFor("unavailable") };
60
+ };
61
+ const finishInterrupted = () => {
62
+ write({ event: "result", manager: invocation.manager, outcome: "interrupted" });
63
+ return { outcome: "interrupted", exitCode: exitCodeFor("interrupted") };
64
+ };
65
+ if (shouldInterrupt()) {
66
+ return finishInterrupted();
67
+ }
68
+ const parsed = parseRaw(raw, invocation.maxRawBytes);
69
+ if (!parsed.ok) {
70
+ // No issue to re-read: the Fetch is skipped entirely.
71
+ return finishInvalid(parsed.invalid);
72
+ }
73
+ const unwrapped = unwrapIssue(parsed.object);
74
+ let merged = unwrapped;
75
+ if (invocation.fetch) {
76
+ const number = fetchableNumber(unwrapped.issue);
77
+ if (options.github === undefined) {
78
+ return finishUnavailable("No authenticated channel was given for the Fetch.");
79
+ }
80
+ if (number === undefined) {
81
+ // Nothing to ask for: normalization will refuse this with missing-id.
82
+ write({ event: "fetch-finished", manager: invocation.manager, result: "skipped" });
83
+ }
84
+ else {
85
+ const fetched = await fetchIssue({
86
+ invocation,
87
+ github: options.github,
88
+ number,
89
+ deadlineMs: now() + (invocation.fetchDurationMs ?? 1),
90
+ now,
91
+ shouldInterrupt,
92
+ });
93
+ write({ event: "fetch-finished", manager: invocation.manager, result: fetched.kind });
94
+ if (fetched.kind === "interrupted") {
95
+ return finishInterrupted();
96
+ }
97
+ if (fetched.kind === "unavailable") {
98
+ return finishUnavailable(fetched.detail);
99
+ }
100
+ // The Fetch is the base; the raw intention is the fresher of the two.
101
+ merged = { ...unwrapped, issue: { ...fetched.issue, ...unwrapped.issue } };
102
+ }
103
+ }
104
+ if (shouldInterrupt()) {
105
+ return finishInterrupted();
106
+ }
107
+ const result = normalize(merged, {
108
+ manager: invocation.manager,
109
+ repo: invocation.repo,
110
+ defaultPriority: invocation.defaultPriority,
111
+ projectLabelPrefix: invocation.projectLabelPrefix,
112
+ priorityLabelPrefix: invocation.priorityLabelPrefix,
113
+ readyLabel: invocation.readyLabel,
114
+ normalizedAt: invocation.at ?? new Date(now()).toISOString(),
115
+ ...(invocation.defaultProject !== undefined
116
+ ? { defaultProject: invocation.defaultProject }
117
+ : {}),
118
+ });
119
+ if (!result.ok) {
120
+ return finishInvalid(result.invalid);
121
+ }
122
+ write({
123
+ event: "result",
124
+ manager: invocation.manager,
125
+ key: result.feature.key,
126
+ outcome: "converted",
127
+ feature: result.feature,
128
+ });
129
+ return { outcome: "converted", feature: result.feature, exitCode: exitCodeFor("converted") };
130
+ }
131
+ //# sourceMappingURL=run-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-adapter.js","sourceRoot":"","sources":["../../../src/adapter/run/run-adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ /** Domain types owned by FeatureAdapter. Names match the Block perimeter only. */
2
+ export type RunOutcome = "converted" | "invalid" | "invalid-invocation" | "unavailable" | "interrupted";
3
+ export type Intent = "upsert" | "ready" | "cancel";
4
+ export type InvalidCode = "raw-too-large" | "raw-not-json" | "raw-not-object" | "not-an-issue" | "unknown-action" | "missing-id" | "missing-project" | "ambiguous-project" | "missing-intention" | "bad-field-type" | "bad-priority";
5
+ export type Repository = {
6
+ owner: string;
7
+ name: string;
8
+ };
9
+ export type Invocation = {
10
+ manager: string;
11
+ repo: Repository;
12
+ /** Root of the REST API, so a GitHub Enterprise host is one argument away. */
13
+ apiBase: string;
14
+ /** The raw intention as one argument; absent means stdin. */
15
+ raw?: string;
16
+ defaultProject?: string;
17
+ defaultPriority: number;
18
+ maxRawBytes: number;
19
+ /** Prefix of the label carrying the project, e.g. `project:`. */
20
+ projectLabelPrefix: string;
21
+ /** Prefix of the label carrying the priority, e.g. `priority:`. */
22
+ priorityLabelPrefix: string;
23
+ /** Label whose arrival means a human unblocked the intention. */
24
+ readyLabel: string;
25
+ /** Re-read the issue from the API before normalizing. */
26
+ fetch: boolean;
27
+ fetchDurationMs?: number;
28
+ requestRetries: number;
29
+ /** Value stamped as normalized_at; absent means the current time. */
30
+ at?: string;
31
+ };
32
+ export type ParseResult =
33
+ /** The token is beside the Invocation, never inside it, and only a Fetch needs one. */
34
+ {
35
+ ok: true;
36
+ invocation: Invocation;
37
+ token?: string;
38
+ } | {
39
+ ok: false;
40
+ reason: string;
41
+ };
42
+ export type FeatureStandard = {
43
+ key: string;
44
+ manager: string;
45
+ external_id: string;
46
+ intent: Intent;
47
+ project: string;
48
+ title?: string;
49
+ intention?: string;
50
+ priority: number;
51
+ source?: {
52
+ ref?: string;
53
+ revision?: string;
54
+ };
55
+ fingerprint: string;
56
+ normalized_at: string;
57
+ };
58
+ export type Invalid = {
59
+ code: InvalidCode;
60
+ reason: string;
61
+ };
62
+ export type NormalizeResult = {
63
+ ok: true;
64
+ feature: FeatureStandard;
65
+ } | {
66
+ ok: false;
67
+ invalid: Invalid;
68
+ };
69
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/adapter/types.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAElF,MAAM,MAAM,UAAU,GAClB,WAAW,GACX,SAAS,GACT,oBAAoB,GACpB,aAAa,GACb,aAAa,CAAC;AAElB,MAAM,MAAM,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEnD,MAAM,MAAM,WAAW,GACnB,eAAe,GACf,cAAc,GACd,gBAAgB,GAChB,cAAc,GACd,gBAAgB,GAChB,YAAY,GACZ,iBAAiB,GACjB,mBAAmB,GACnB,mBAAmB,GACnB,gBAAgB,GAChB,cAAc,CAAC;AAEnB,MAAM,MAAM,UAAU,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzD,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,UAAU,CAAC;IACjB,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mEAAmE;IACnE,mBAAmB,EAAE,MAAM,CAAC;IAC5B,iEAAiE;IACjE,UAAU,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,KAAK,EAAE,OAAO,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,qEAAqE;IACrE,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,WAAW;AACrB,uFAAuF;AACvF;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,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5D,MAAM,MAAM,eAAe,GACvB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,eAAe,CAAA;CAAE,GACtC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** Domain types owned by FeatureAdapter. 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/adapter/types.ts"],"names":[],"mappings":"AAAA,kFAAkF"}
@@ -0,0 +1,29 @@
1
+ import type { EventFields, EventName } from "../types.js";
2
+ export type FieldName = keyof EventFields;
3
+ /** Column order of the matrix: it also orders a rendered section. */
4
+ export declare const FIELD_ORDER: FieldName[];
5
+ export declare const EVENT_NAMES: EventName[];
6
+ type Rule = {
7
+ required: FieldName[];
8
+ optional: FieldName[];
9
+ };
10
+ /**
11
+ * What each Event accepts. A field outside its row is refused, not dropped:
12
+ * a caller setting `reference` on `planned` has confused two Events, and a
13
+ * report that hides that is worse than a refusal.
14
+ */
15
+ export declare const FIELD_MATRIX: Record<EventName, Rule>;
16
+ export type ValidationResult = {
17
+ ok: true;
18
+ } | {
19
+ ok: false;
20
+ reason: string;
21
+ };
22
+ /**
23
+ * Check one Event's fields against the matrix, plus the two rules on top of it.
24
+ * Pure: no directory, no clock.
25
+ */
26
+ export declare function validateFields(event: EventName, fields: EventFields): ValidationResult;
27
+ export declare function flagOf(field: FieldName): string;
28
+ export {};
29
+ //# sourceMappingURL=field-matrix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-matrix.d.ts","sourceRoot":"","sources":["../../../src/emitter/event/field-matrix.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,MAAM,SAAS,GAAG,MAAM,WAAW,CAAC;AAE1C,qEAAqE;AACrE,eAAO,MAAM,WAAW,EAAE,SAAS,EAelC,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,SAAS,EAYlC,CAAC;AAEF,KAAK,IAAI,GAAG;IAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;IAAC,QAAQ,EAAE,SAAS,EAAE,CAAA;CAAE,CAAC;AAE7D;;;;GAIG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,SAAS,EAAE,IAAI,CAyBhD,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5E;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,GAAG,gBAAgB,CA4BtF;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAE/C"}
@@ -0,0 +1,94 @@
1
+ /** Column order of the matrix: it also orders a rendered section. */
2
+ export const FIELD_ORDER = [
3
+ "summary",
4
+ "reason",
5
+ "stage",
6
+ "trace",
7
+ "counters",
8
+ "plan",
9
+ "priority",
10
+ "unit",
11
+ "remaining",
12
+ "state",
13
+ "resume_point",
14
+ "reference",
15
+ "integration_reference",
16
+ "workspace_ref",
17
+ ];
18
+ export const EVENT_NAMES = [
19
+ "invalid",
20
+ "accepted",
21
+ "planned",
22
+ "progress",
23
+ "escalated",
24
+ "escalation_reminder",
25
+ "resumed",
26
+ "submitted",
27
+ "done",
28
+ "cancelled",
29
+ "reject_late",
30
+ ];
31
+ /**
32
+ * What each Event accepts. A field outside its row is refused, not dropped:
33
+ * a caller setting `reference` on `planned` has confused two Events, and a
34
+ * report that hides that is worse than a refusal.
35
+ */
36
+ export const FIELD_MATRIX = {
37
+ invalid: { required: ["reason"], optional: [] },
38
+ accepted: { required: ["priority"], optional: [] },
39
+ planned: { required: ["plan"], optional: [] },
40
+ // Progress is one sentence a person reads — a Subtask landed, a refusal
41
+ // being repaired — and whatever detail the caller wants to leave under it.
42
+ progress: {
43
+ required: ["summary"],
44
+ optional: ["unit", "remaining", "state", "stage", "reason", "trace", "counters"],
45
+ },
46
+ escalated: {
47
+ required: ["reason", "stage"],
48
+ optional: ["trace", "counters", "unit"],
49
+ },
50
+ escalation_reminder: {
51
+ required: ["reason", "stage"],
52
+ optional: ["trace", "counters", "unit"],
53
+ },
54
+ resumed: { required: ["resume_point"], optional: ["reason"] },
55
+ // The work is in front of the Authority; the reference is where it can be seen.
56
+ submitted: { required: ["reference"], optional: [] },
57
+ // A local fold names nothing a reader could open; only an Authority's fold has a reference.
58
+ done: { required: [], optional: ["reference", "integration_reference"] },
59
+ cancelled: { required: ["state"], optional: ["reason", "workspace_ref"] },
60
+ reject_late: { required: ["reason"], optional: ["state", "reference"] },
61
+ };
62
+ /**
63
+ * Check one Event's fields against the matrix, plus the two rules on top of it.
64
+ * Pure: no directory, no clock.
65
+ */
66
+ export function validateFields(event, fields) {
67
+ const rule = FIELD_MATRIX[event];
68
+ const allowed = new Set([...rule.required, ...rule.optional]);
69
+ const given = FIELD_ORDER.filter((field) => fields[field] !== undefined);
70
+ const refused = given.filter((field) => !allowed.has(field));
71
+ if (refused.length > 0) {
72
+ return {
73
+ ok: false,
74
+ reason: `Event "${event}" does not accept: ${refused.map(flagOf).join(", ")}.`,
75
+ };
76
+ }
77
+ const missing = rule.required.filter((field) => fields[field] === undefined);
78
+ if (missing.length > 0) {
79
+ return {
80
+ ok: false,
81
+ reason: `Event "${event}" requires: ${missing.map(flagOf).join(", ")}.`,
82
+ };
83
+ }
84
+ // An escalation about work that ran, without what it left behind, forces a
85
+ // human to reproduce the failure before they can understand it.
86
+ if (fields.stage === "unit" && fields.trace === undefined) {
87
+ return { ok: false, reason: 'Stage "unit" requires --trace or --trace-file.' };
88
+ }
89
+ return { ok: true };
90
+ }
91
+ export function flagOf(field) {
92
+ return `--${field.replace(/_/g, "-")}`;
93
+ }
94
+ //# sourceMappingURL=field-matrix.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-matrix.js","sourceRoot":"","sources":["../../../src/emitter/event/field-matrix.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { type GithubClient } from "../../github/client.js";
2
+ import type { Invocation } from "../types.js";
3
+ import type { CallContext, TargetResult } from "./result.js";
4
+ /**
5
+ * Every comment body already in the Thread. Read only for idempotence: this
6
+ * Block never edits or deletes a comment, its own included.
7
+ */
8
+ export declare function listCommentBodies(invocation: Invocation, github: GithubClient, context: CallContext): Promise<TargetResult<string[]>>;
9
+ export type CreatedComment = {
10
+ url: string | undefined;
11
+ };
12
+ /** Append one comment. One request, so it lands whole or not at all. */
13
+ export declare function createComment(invocation: Invocation, github: GithubClient, context: CallContext, body: string): Promise<TargetResult<CreatedComment>>;
14
+ //# sourceMappingURL=comments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comments.d.ts","sourceRoot":"","sources":["../../../src/emitter/github/comments.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,YAAY,EAAe,MAAM,wBAAwB,CAAC;AACpF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAa7D;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC,CAkCjC;AAED,MAAM,MAAM,cAAc,GAAG;IAAE,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEzD,wEAAwE;AACxE,wBAAsB,aAAa,CACjC,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,WAAW,EACpB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,CAAC,CAmBvC"}
@@ -0,0 +1,69 @@
1
+ import { callSignal, readFailure } from "../../github/client.js";
2
+ const PER_PAGE = 100;
3
+ /** A Thread nobody would scroll; past it, the idempotence scan gives up. */
4
+ const MAX_PAGES = 50;
5
+ function failed(error, context) {
6
+ if (context.shouldInterrupt()) {
7
+ return { kind: "interrupted" };
8
+ }
9
+ return { kind: "unreportable", detail: readFailure(error).detail };
10
+ }
11
+ /**
12
+ * Every comment body already in the Thread. Read only for idempotence: this
13
+ * Block never edits or deletes a comment, its own included.
14
+ */
15
+ export async function listCommentBodies(invocation, github, context) {
16
+ const bodies = [];
17
+ for (let page = 1; page <= MAX_PAGES; page += 1) {
18
+ const call = callSignal(context.deadlineMs, context.now, context.shouldInterrupt);
19
+ try {
20
+ const response = await github.request("GET /repos/{owner}/{repo}/issues/{issue_number}/comments", {
21
+ owner: invocation.repo.owner,
22
+ repo: invocation.repo.name,
23
+ issue_number: invocation.issue,
24
+ per_page: PER_PAGE,
25
+ page,
26
+ request: { signal: call.signal },
27
+ });
28
+ for (const comment of response.data) {
29
+ if (typeof comment.body === "string") {
30
+ bodies.push(comment.body);
31
+ }
32
+ }
33
+ if (response.data.length < PER_PAGE) {
34
+ return { kind: "ok", value: bodies };
35
+ }
36
+ }
37
+ catch (error) {
38
+ return failed(error, context);
39
+ }
40
+ finally {
41
+ call.release();
42
+ }
43
+ }
44
+ return {
45
+ kind: "unreportable",
46
+ detail: `The Thread holds more than ${MAX_PAGES * PER_PAGE} comments; idempotence cannot be established.`,
47
+ };
48
+ }
49
+ /** Append one comment. One request, so it lands whole or not at all. */
50
+ export async function createComment(invocation, github, context, body) {
51
+ const call = callSignal(context.deadlineMs, context.now, context.shouldInterrupt);
52
+ try {
53
+ const response = await github.request("POST /repos/{owner}/{repo}/issues/{issue_number}/comments", {
54
+ owner: invocation.repo.owner,
55
+ repo: invocation.repo.name,
56
+ issue_number: invocation.issue,
57
+ body,
58
+ request: { signal: call.signal },
59
+ });
60
+ return { kind: "ok", value: { url: response.data.html_url } };
61
+ }
62
+ catch (error) {
63
+ return failed(error, context);
64
+ }
65
+ finally {
66
+ call.release();
67
+ }
68
+ }
69
+ //# sourceMappingURL=comments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comments.js","sourceRoot":"","sources":["../../../src/emitter/github/comments.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { type GithubClient } from "../../github/client.js";
2
+ import type { Invocation } from "../types.js";
3
+ import type { CallContext, TargetResult } from "./result.js";
4
+ /** The label this Event stands for, e.g. `mason:escalated`. */
5
+ export declare function labelFor(prefix: string, event: string): string;
6
+ export type LabelSync = {
7
+ added?: string;
8
+ removed: string[];
9
+ };
10
+ /**
11
+ * Move the Thread's state label to this Event.
12
+ *
13
+ * Only labels carrying the prefix are touched: a `project:` or a `bug` label is
14
+ * somebody else's, and a report that rewrites the issue's whole label set is a
15
+ * report that destroys data.
16
+ */
17
+ export declare function syncStateLabel(invocation: Invocation, github: GithubClient, context: CallContext, prefix: string): Promise<TargetResult<LabelSync>>;
18
+ //# sourceMappingURL=labels.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"labels.d.ts","sourceRoot":"","sources":["../../../src/emitter/github/labels.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,YAAY,EAAe,MAAM,wBAAwB,CAAC;AACpF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI7D,+DAA+D;AAC/D,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,MAAM,MAAM,SAAS,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAS9D;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAgElC"}
@@ -0,0 +1,81 @@
1
+ import { callSignal, readFailure } from "../../github/client.js";
2
+ const PER_PAGE = 100;
3
+ /** The label this Event stands for, e.g. `mason:escalated`. */
4
+ export function labelFor(prefix, event) {
5
+ return `${prefix}${event}`;
6
+ }
7
+ function failed(error, context) {
8
+ if (context.shouldInterrupt()) {
9
+ return { kind: "interrupted" };
10
+ }
11
+ return { kind: "unreportable", detail: readFailure(error).detail };
12
+ }
13
+ /**
14
+ * Move the Thread's state label to this Event.
15
+ *
16
+ * Only labels carrying the prefix are touched: a `project:` or a `bug` label is
17
+ * somebody else's, and a report that rewrites the issue's whole label set is a
18
+ * report that destroys data.
19
+ */
20
+ export async function syncStateLabel(invocation, github, context, prefix) {
21
+ const target = labelFor(prefix, invocation.event);
22
+ const issue = {
23
+ owner: invocation.repo.owner,
24
+ repo: invocation.repo.name,
25
+ issue_number: invocation.issue,
26
+ };
27
+ let present;
28
+ const listing = callSignal(context.deadlineMs, context.now, context.shouldInterrupt);
29
+ try {
30
+ const response = await github.request("GET /repos/{owner}/{repo}/issues/{issue_number}/labels", {
31
+ ...issue,
32
+ per_page: PER_PAGE,
33
+ request: { signal: listing.signal },
34
+ });
35
+ present = response.data.map((label) => label.name);
36
+ }
37
+ catch (error) {
38
+ return failed(error, context);
39
+ }
40
+ finally {
41
+ listing.release();
42
+ }
43
+ const stale = present.filter((name) => name.toLowerCase().startsWith(prefix.toLowerCase()) && name !== target);
44
+ const removed = [];
45
+ for (const name of stale) {
46
+ const call = callSignal(context.deadlineMs, context.now, context.shouldInterrupt);
47
+ try {
48
+ await github.request("DELETE /repos/{owner}/{repo}/issues/{issue_number}/labels/{name}", {
49
+ ...issue,
50
+ name,
51
+ request: { signal: call.signal },
52
+ });
53
+ removed.push(name);
54
+ }
55
+ catch (error) {
56
+ return failed(error, context);
57
+ }
58
+ finally {
59
+ call.release();
60
+ }
61
+ }
62
+ if (present.includes(target)) {
63
+ return { kind: "ok", value: { removed } };
64
+ }
65
+ const adding = callSignal(context.deadlineMs, context.now, context.shouldInterrupt);
66
+ try {
67
+ await github.request("POST /repos/{owner}/{repo}/issues/{issue_number}/labels", {
68
+ ...issue,
69
+ labels: [target],
70
+ request: { signal: adding.signal },
71
+ });
72
+ }
73
+ catch (error) {
74
+ return failed(error, context);
75
+ }
76
+ finally {
77
+ adding.release();
78
+ }
79
+ return { kind: "ok", value: { added: target, removed } };
80
+ }
81
+ //# sourceMappingURL=labels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"labels.js","sourceRoot":"","sources":["../../../src/emitter/github/labels.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAqB,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAIpF,MAAM,QAAQ,GAAG,GAAG,CAAC;AAErB,+DAA+D;AAC/D,MAAM,UAAU,QAAQ,CAAC,MAAc,EAAE,KAAa;IACpD,OAAO,GAAG,MAAM,GAAG,KAAK,EAAE,CAAC;AAC7B,CAAC;AAID,SAAS,MAAM,CAAI,KAAc,EAAE,OAAoB;IACrD,IAAI,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC;QAC9B,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;IACjC,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC;AACrE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,UAAsB,EACtB,MAAoB,EACpB,OAAoB,EACpB,MAAc;IAEd,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;IAClD,MAAM,KAAK,GAAG;QACZ,KAAK,EAAE,UAAU,CAAC,IAAI,CAAC,KAAK;QAC5B,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,IAAI;QAC1B,YAAY,EAAE,UAAU,CAAC,KAAK;KAC/B,CAAC;IAEF,IAAI,OAAiB,CAAC;IACtB,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IACrF,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,OAAO,CACnC,wDAAwD,EACxD;YACE,GAAG,KAAK;YACR,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE;SACpC,CACF,CAAC;QACF,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACrD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAChC,CAAC;YAAS,CAAC;QACT,OAAO,CAAC,OAAO,EAAE,CAAC;IACpB,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAC1B,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,IAAI,IAAI,KAAK,MAAM,CACjF,CAAC;IAEF,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;QAClF,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,OAAO,CAAC,kEAAkE,EAAE;gBACvF,GAAG,KAAK;gBACR,IAAI;gBACJ,OAAO,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE;aACjC,CAAC,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAChC,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC;IAC5C,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IACpF,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,OAAO,CAAC,yDAAyD,EAAE;YAC9E,GAAG,KAAK;YACR,MAAM,EAAE,CAAC,MAAM,CAAC;YAChB,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;SACnC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAChC,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,19 @@
1
+ /** What a call to the Target can end as, from this Block's point of view. */
2
+ export type TargetResult<T> = {
3
+ kind: "ok";
4
+ value: T;
5
+ }
6
+ /** The Target refused, or nobody answered within the retries and the clock. */
7
+ | {
8
+ kind: "unreportable";
9
+ detail: string;
10
+ } | {
11
+ kind: "interrupted";
12
+ };
13
+ /** The bound every call of one invocation runs under. */
14
+ export type CallContext = {
15
+ deadlineMs: number;
16
+ now: () => number;
17
+ shouldInterrupt: () => boolean;
18
+ };
19
+ //# sourceMappingURL=result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../../../src/emitter/github/result.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,MAAM,MAAM,YAAY,CAAC,CAAC,IACtB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE;AAC1B,+EAA+E;GAC7E;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,CAAC;AAE5B,yDAAyD;AACzD,MAAM,MAAM,WAAW,GAAG;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,OAAO,CAAC;CAChC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=result.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.js","sourceRoot":"","sources":["../../../src/emitter/github/result.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ export type ProgressWriter = (line: Record<string, unknown>) => void;
2
+ export declare function createStdoutProgressWriter(): ProgressWriter;
3
+ //# sourceMappingURL=emit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../../../src/emitter/progress/emit.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;AAErE,wBAAgB,0BAA0B,IAAI,cAAc,CAI3D"}
@@ -0,0 +1,6 @@
1
+ export function createStdoutProgressWriter() {
2
+ return (line) => {
3
+ process.stdout.write(`${JSON.stringify(line)}\n`);
4
+ };
5
+ }
6
+ //# sourceMappingURL=emit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit.js","sourceRoot":"","sources":["../../../src/emitter/progress/emit.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,0BAA0B;IACxC,OAAO,CAAC,IAAI,EAAE,EAAE;QACd,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpD,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { EventRecord, Invocation } from "../types.js";
2
+ export type Rendered = {
3
+ record: EventRecord;
4
+ /** One section for the human surface, trailing newline included. */
5
+ section: string;
6
+ /** The exact bytes the comment receives: the section, then the record. */
7
+ body: string;
8
+ };
9
+ /**
10
+ * Turn one invocation into the exact bytes the Thread receives.
11
+ * Pure: --dry-run renders through this same function, so a preview cannot lie.
12
+ */
13
+ export declare function renderEvent(invocation: Invocation): Rendered;
14
+ /**
15
+ * `80/100` says nothing to someone who never saw the scale. A word first, the
16
+ * number after, and "default" when nobody chose — so a reader knows a label
17
+ * would change it.
18
+ */
19
+ export declare function priorityInWords(priority: number, fallback: number | undefined): string;
20
+ //# sourceMappingURL=render-event.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-event.d.ts","sourceRoot":"","sources":["../../../src/emitter/render/render-event.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAA0B,WAAW,EAAE,UAAU,EAAS,MAAM,aAAa,CAAC;AAkD1F,MAAM,MAAM,QAAQ,GAAG;IACrB,MAAM,EAAE,WAAW,CAAC;IACpB,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;GAGG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,UAAU,GAAG,QAAQ,CA+C5D;AA8LD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAMtF"}