@telora/daemon 0.24.2 → 0.24.5

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 (138) hide show
  1. package/build-info.json +8 -3
  2. package/dist/backends/claude/one-shot-model.d.ts.map +1 -1
  3. package/dist/backends/claude/one-shot-model.js +2 -0
  4. package/dist/backends/claude/one-shot-model.js.map +1 -1
  5. package/dist/ci/ci-status.d.ts.map +1 -1
  6. package/dist/ci/ci-status.js +1 -0
  7. package/dist/ci/ci-status.js.map +1 -1
  8. package/dist/ci/product-ci-repo.d.ts.map +1 -1
  9. package/dist/ci/product-ci-repo.js +3 -1
  10. package/dist/ci/product-ci-repo.js.map +1 -1
  11. package/dist/completion/state-cascade/review-approved-head-gate.d.ts.map +1 -1
  12. package/dist/completion/state-cascade/review-approved-head-gate.js +2 -0
  13. package/dist/completion/state-cascade/review-approved-head-gate.js.map +1 -1
  14. package/dist/completion/state-cascade/review-capture-head-gate.d.ts +28 -0
  15. package/dist/completion/state-cascade/review-capture-head-gate.d.ts.map +1 -0
  16. package/dist/completion/state-cascade/review-capture-head-gate.js +48 -0
  17. package/dist/completion/state-cascade/review-capture-head-gate.js.map +1 -0
  18. package/dist/completion/state-cascade/state-cascade.d.ts +12 -0
  19. package/dist/completion/state-cascade/state-cascade.d.ts.map +1 -1
  20. package/dist/completion/state-cascade/state-cascade.js +19 -10
  21. package/dist/completion/state-cascade/state-cascade.js.map +1 -1
  22. package/dist/composition/daemon-contexts.d.ts.map +1 -1
  23. package/dist/composition/daemon-contexts.js +3 -1
  24. package/dist/composition/daemon-contexts.js.map +1 -1
  25. package/dist/composition/execution-git-context.d.ts.map +1 -1
  26. package/dist/composition/execution-git-context.js +1 -0
  27. package/dist/composition/execution-git-context.js.map +1 -1
  28. package/dist/composition/execution-worktree-context.js +1 -1
  29. package/dist/composition/release-note-pass-context.d.ts +7 -0
  30. package/dist/composition/release-note-pass-context.d.ts.map +1 -0
  31. package/dist/composition/release-note-pass-context.js +64 -0
  32. package/dist/composition/release-note-pass-context.js.map +1 -0
  33. package/dist/composition/runtime-contexts.d.ts.map +1 -1
  34. package/dist/composition/runtime-contexts.js +2 -0
  35. package/dist/composition/runtime-contexts.js.map +1 -1
  36. package/dist/composition/spawn-pass-deps.d.ts +2 -2
  37. package/dist/composition/spawn-pass-deps.d.ts.map +1 -1
  38. package/dist/composition/spawn-pass-deps.js +3 -1
  39. package/dist/composition/spawn-pass-deps.js.map +1 -1
  40. package/dist/composition/state-cascade-context.d.ts.map +1 -1
  41. package/dist/composition/state-cascade-context.js +2 -0
  42. package/dist/composition/state-cascade-context.js.map +1 -1
  43. package/dist/config/live-daemon-config.js +1 -1
  44. package/dist/daemon-state/provider-window.d.ts.map +1 -1
  45. package/dist/daemon-state/provider-window.js +1 -0
  46. package/dist/daemon-state/provider-window.js.map +1 -1
  47. package/dist/directive/directive-queue.js +1 -1
  48. package/dist/focus/daemon-contexts.d.ts +3 -0
  49. package/dist/focus/daemon-contexts.d.ts.map +1 -1
  50. package/dist/focus/daemon-contexts.js.map +1 -1
  51. package/dist/focus/focus-loop-registry.d.ts.map +1 -1
  52. package/dist/focus/focus-loop-registry.js +21 -0
  53. package/dist/focus/focus-loop-registry.js.map +1 -1
  54. package/dist/focus/pending-review-approved-head.d.ts +5 -1
  55. package/dist/focus/pending-review-approved-head.d.ts.map +1 -1
  56. package/dist/focus/pending-review-approved-head.js +35 -1
  57. package/dist/focus/pending-review-approved-head.js.map +1 -1
  58. package/dist/focus/review-spawn-coverage.d.ts +11 -0
  59. package/dist/focus/review-spawn-coverage.d.ts.map +1 -1
  60. package/dist/focus/review-spawn-coverage.js +14 -0
  61. package/dist/focus/review-spawn-coverage.js.map +1 -1
  62. package/dist/git/delivery-trailer.d.ts.map +1 -1
  63. package/dist/git/delivery-trailer.js +2 -0
  64. package/dist/git/delivery-trailer.js.map +1 -1
  65. package/dist/git/utils.d.ts.map +1 -1
  66. package/dist/git/utils.js +2 -1
  67. package/dist/git/utils.js.map +1 -1
  68. package/dist/merge/candidate-rework.d.ts.map +1 -1
  69. package/dist/merge/candidate-rework.js +24 -2
  70. package/dist/merge/candidate-rework.js.map +1 -1
  71. package/dist/merge/completion-merge-activity.d.ts.map +1 -1
  72. package/dist/merge/completion-merge-activity.js +7 -1
  73. package/dist/merge/completion-merge-activity.js.map +1 -1
  74. package/dist/merge/completion-merge-driver.d.ts +15 -5
  75. package/dist/merge/completion-merge-driver.d.ts.map +1 -1
  76. package/dist/merge/completion-merge-driver.js +7 -2
  77. package/dist/merge/completion-merge-driver.js.map +1 -1
  78. package/dist/merge/completion-merge-gate.d.ts +5 -1
  79. package/dist/merge/completion-merge-gate.d.ts.map +1 -1
  80. package/dist/merge/completion-merge-gate.js +23 -7
  81. package/dist/merge/completion-merge-gate.js.map +1 -1
  82. package/dist/merge/merge-back-loop.d.ts.map +1 -1
  83. package/dist/merge/merge-back-loop.js +2 -1
  84. package/dist/merge/merge-back-loop.js.map +1 -1
  85. package/dist/merge/merge-gate-coverage.d.ts +0 -2
  86. package/dist/merge/merge-gate-coverage.d.ts.map +1 -1
  87. package/dist/merge/merge-gate-coverage.js +11 -9
  88. package/dist/merge/merge-gate-coverage.js.map +1 -1
  89. package/dist/prompt-sections/release-note-faithfulness-section.d.ts +28 -0
  90. package/dist/prompt-sections/release-note-faithfulness-section.d.ts.map +1 -0
  91. package/dist/prompt-sections/release-note-faithfulness-section.js +99 -0
  92. package/dist/prompt-sections/release-note-faithfulness-section.js.map +1 -0
  93. package/dist/prompt-sections/release-note-section.d.ts +58 -0
  94. package/dist/prompt-sections/release-note-section.d.ts.map +1 -0
  95. package/dist/prompt-sections/release-note-section.js +285 -0
  96. package/dist/prompt-sections/release-note-section.js.map +1 -0
  97. package/dist/queries/api-client/shared.d.ts +1 -0
  98. package/dist/queries/api-client/shared.d.ts.map +1 -1
  99. package/dist/queries/api-client/shared.js +16 -1
  100. package/dist/queries/api-client/shared.js.map +1 -1
  101. package/dist/queries/release-notes/release-notes.d.ts +242 -0
  102. package/dist/queries/release-notes/release-notes.d.ts.map +1 -0
  103. package/dist/queries/release-notes/release-notes.js +148 -0
  104. package/dist/queries/release-notes/release-notes.js.map +1 -0
  105. package/dist/release-notes/release-note-author.d.ts +56 -0
  106. package/dist/release-notes/release-note-author.d.ts.map +1 -0
  107. package/dist/release-notes/release-note-author.js +107 -0
  108. package/dist/release-notes/release-note-author.js.map +1 -0
  109. package/dist/release-notes/release-note-faithfulness.d.ts +40 -0
  110. package/dist/release-notes/release-note-faithfulness.d.ts.map +1 -0
  111. package/dist/release-notes/release-note-faithfulness.js +107 -0
  112. package/dist/release-notes/release-note-faithfulness.js.map +1 -0
  113. package/dist/release-notes/release-note-pass.d.ts +77 -0
  114. package/dist/release-notes/release-note-pass.d.ts.map +1 -0
  115. package/dist/release-notes/release-note-pass.js +201 -0
  116. package/dist/release-notes/release-note-pass.js.map +1 -0
  117. package/dist/testing/fixtures/api-client.js +1 -1
  118. package/dist/testing/fixtures/approved-head-inert-deps.d.ts +4 -3
  119. package/dist/testing/fixtures/approved-head-inert-deps.d.ts.map +1 -1
  120. package/dist/testing/fixtures/approved-head-inert-deps.js +3 -0
  121. package/dist/testing/fixtures/approved-head-inert-deps.js.map +1 -1
  122. package/dist/testing/fixtures/completion-judge-stubs.d.ts.map +1 -1
  123. package/dist/testing/fixtures/completion-judge-stubs.js +2 -0
  124. package/dist/testing/fixtures/completion-judge-stubs.js.map +1 -1
  125. package/dist/testing/fixtures/index.js +1 -1
  126. package/dist/testing/fixtures/pending-spawn-world.d.ts.map +1 -1
  127. package/dist/testing/fixtures/pending-spawn-world.js +1 -0
  128. package/dist/testing/fixtures/pending-spawn-world.js.map +1 -1
  129. package/dist/types/index.js +1 -1
  130. package/dist/worktree/capture-head-adoption.d.ts +44 -0
  131. package/dist/worktree/capture-head-adoption.d.ts.map +1 -0
  132. package/dist/worktree/capture-head-adoption.js +96 -0
  133. package/dist/worktree/capture-head-adoption.js.map +1 -0
  134. package/dist/worktree/safety.d.ts +12 -3
  135. package/dist/worktree/safety.d.ts.map +1 -1
  136. package/dist/worktree/safety.js +15 -3
  137. package/dist/worktree/safety.js.map +1 -1
  138. package/package.json +2 -2
@@ -0,0 +1,148 @@
1
+ // PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
2
+ // Pinned by: packages/daemon/src/composition/release-note-pass-context.test.ts,
3
+ // packages/daemon/src/prompt-sections/release-note-section.test.ts,
4
+ // packages/daemon/src/queries/release-notes/release-notes.test.ts,
5
+ // packages/daemon/src/release-notes/release-note-author.test.ts,
6
+ // packages/daemon/src/release-notes/release-note-faithfulness.test.ts,
7
+ // packages/daemon/src/release-notes/release-note-pass.test.ts
8
+ // PINNED-BY-END
9
+ /**
10
+ * The release-note drafting pass's reads and writes (product-api
11
+ * daemon_get_release_note_candidates / daemon_release_note_claim /
12
+ * daemon_release_note_write; the edge side is
13
+ * supabase/functions/product-api/handlers/daemon-release-note-handlers.ts and
14
+ * the drafting context release-drafting.ts). All three ride the isolated
15
+ * `releaseNotes` circuit breaker, so a failing drafting pass never opens a
16
+ * breaker armed work reads or writes through.
17
+ *
18
+ * A claim answers the DRAFTING CONTEXT: every piece of work the release
19
+ * carries, in its own engineering words (the source material, and the internal
20
+ * names the note must not repeat), the radar blips and themes that informed it,
21
+ * and the links a user reaches it by in the release's environment.
22
+ *
23
+ * Every outcome is written under the claim it was made with. A draft the edge
24
+ * refuses comes back as an ApiError: HTTP 400 `validation_failed` (the note is
25
+ * not in the format, or not faithful) or HTTP 409 `state_conflict` (the claim
26
+ * was lost, or the human changed the release's work while it was drafted).
27
+ * readReleaseNoteWriteFailure is the one reader of those.
28
+ *
29
+ * WHAT THE DAEMON CAN READ OF A REFUSAL. The edge's 400 body carries every
30
+ * violation in a `violations` array, but the daemon's API transport
31
+ * (@telora/daemon-core createApiClient -> ApiError) keeps only the body's
32
+ * `error` text, the HTTP status and the `code`. The refusal's violations are
33
+ * therefore read from the error TEXT, verbatim, as one entry -- whatever the
34
+ * edge writes there is what the corrective attempt is shown.
35
+ */
36
+ import { z } from 'zod';
37
+ import { callApiValidated } from '../api-client/shared.js';
38
+ const nullableString = () => z.string().nullable().optional().default(null);
39
+ const ReleaseNoteCandidateSchema = z.object({
40
+ releaseId: z.string(),
41
+ productId: z.string(),
42
+ name: z.string(),
43
+ cutAt: z.string(),
44
+ }).passthrough();
45
+ const ReleaseNoteCandidatesSchema = z.object({
46
+ releases: z.array(ReleaseNoteCandidateSchema),
47
+ }).passthrough();
48
+ const DraftingLinkSchema = z.object({
49
+ /** Absolute https: the environment's address joined to a QA case path. */
50
+ url: z.string(),
51
+ built: z.string().optional().default(''),
52
+ criterion: z.string().optional().default(''),
53
+ expected: z.string().optional().default(''),
54
+ }).passthrough();
55
+ const DraftingWorkSchema = z.object({
56
+ deliveryId: z.string(),
57
+ title: z.string(),
58
+ description: nullableString(),
59
+ acceptanceCriteria: nullableString(),
60
+ workFacing: nullableString(),
61
+ focus: z.object({
62
+ focusId: z.string(),
63
+ title: z.string(),
64
+ description: nullableString(),
65
+ }).passthrough().nullable().optional().default(null),
66
+ issues: z.array(z.object({ title: z.string(), issueType: nullableString() }).passthrough()).optional().default([]),
67
+ radar: z.object({
68
+ blips: z.array(z.object({ title: z.string(), category: z.string(), assessment: z.string() }).passthrough()).optional().default([]),
69
+ themes: z.array(z.object({ title: z.string(), assessment: z.string() }).passthrough()).optional().default([]),
70
+ }).passthrough().optional().default({ blips: [], themes: [] }),
71
+ links: z.array(DraftingLinkSchema).optional().default([]),
72
+ }).passthrough();
73
+ const DraftingContextSchema = z.object({
74
+ releaseId: z.string(),
75
+ productId: z.string(),
76
+ productName: z.string(),
77
+ releaseName: z.string(),
78
+ /** The release date, YYYY-MM-DD. */
79
+ date: z.string(),
80
+ environment: z.object({ name: z.string(), address: nullableString() }).passthrough(),
81
+ work: z.array(DraftingWorkSchema),
82
+ /** Focus, delivery and issue titles: internal names no note may repeat. */
83
+ internalNames: z.array(z.string()).optional().default([]),
84
+ }).passthrough();
85
+ const ReleaseNoteClaimSchema = z.discriminatedUnion('claimed', [
86
+ z.object({ claimed: z.literal(false), reason: z.string().optional().default('') }).passthrough(),
87
+ z.object({ claimed: z.literal(true), claimId: z.string(), context: DraftingContextSchema }).passthrough(),
88
+ ]);
89
+ const ReleaseNoteWriteResultSchema = z.object({
90
+ release: z.unknown().optional(),
91
+ released: z.boolean().optional(),
92
+ }).passthrough();
93
+ /** The product's releases still drafting and held by no live pass, oldest cut first (bounded by the edge). */
94
+ export async function getReleaseNoteCandidates(productId) {
95
+ const result = await callApiValidated('daemon_get_release_note_candidates', ReleaseNoteCandidatesSchema, { productId });
96
+ return result.releases;
97
+ }
98
+ /** Take one release to draft. Not claimed when it stopped drafting or another pass holds it. */
99
+ export async function claimReleaseNote(releaseId) {
100
+ return callApiValidated('daemon_release_note_claim', ReleaseNoteClaimSchema, { releaseId });
101
+ }
102
+ /** Write the draft or the failure under the claim. Throws on a refusal (readReleaseNoteWriteFailure reads it). */
103
+ export async function writeReleaseNote(write) {
104
+ await callApiValidated('daemon_release_note_write', ReleaseNoteWriteResultSchema, { ...write });
105
+ }
106
+ /** Give the claim back so the next tick can draft the release again; false when this pass no longer held it. */
107
+ export async function unclaimReleaseNote(releaseId, claimId) {
108
+ const result = await callApiValidated('daemon_release_note_write', ReleaseNoteWriteResultSchema, {
109
+ releaseId, claimId, outcome: 'unclaim',
110
+ });
111
+ return result.released === true;
112
+ }
113
+ function errorMessage(err) {
114
+ return err instanceof Error ? err.message : String(err);
115
+ }
116
+ /** The edge's refusal text: this first line, then one "- <violation>" line per violation. */
117
+ const REFUSAL_PREFIX = 'the note was refused:';
118
+ /**
119
+ * The violations a refusal names. The edge writes each one into its message,
120
+ * one per line (the api client keeps the message, not the body), so they are
121
+ * read back from it; a message in any other shape is kept whole as one
122
+ * violation.
123
+ */
124
+ export function refusalViolations(message) {
125
+ if (!message.startsWith(REFUSAL_PREFIX))
126
+ return [message];
127
+ const parts = message
128
+ .slice(REFUSAL_PREFIX.length)
129
+ .split('\n')
130
+ .map((line) => line.trim().replace(/^- /, '').trim())
131
+ .filter((line) => line.length > 0);
132
+ return parts.length > 0 ? parts : [message];
133
+ }
134
+ /**
135
+ * Classify what a release-note write threw, from the edge envelope's HTTP
136
+ * status and machine code (ApiError.statusCode / wireCode), never its prose.
137
+ * Total: every input yields a failure. Pure.
138
+ */
139
+ export function readReleaseNoteWriteFailure(err) {
140
+ const { statusCode, wireCode } = (err ?? {});
141
+ const detail = errorMessage(err);
142
+ if (statusCode === 400 && wireCode === 'validation_failed')
143
+ return { kind: 'refused', violations: refusalViolations(detail) };
144
+ if (statusCode === 409)
145
+ return { kind: 'conflict', detail };
146
+ return { kind: 'error', detail };
147
+ }
148
+ //# sourceMappingURL=release-notes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"release-notes.js","sourceRoot":"","sources":["../../../src/queries/release-notes/release-notes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ import type { DraftingContext, ReleaseNoteDraft } from '../queries/release-notes/release-notes.js';
2
+ /** Each attempt's wall-clock bound. */
3
+ export declare const RELEASE_NOTE_TIMEOUT_MS: number;
4
+ /** The turn cap (the pass has no tools: everything it knows is in its prompt). */
5
+ export declare const RELEASE_NOTE_MAX_TURNS = 3;
6
+ /** One model run, as the author asks for it. */
7
+ export interface ReleaseNoteInvokeOptions {
8
+ label: string;
9
+ extraArgs: readonly string[];
10
+ timeoutMs: number;
11
+ maxTurns: number;
12
+ }
13
+ /** Run the model once; resolve with its final answer text, or reject (a ModelUnavailable names why). */
14
+ export type ReleaseNoteInvoke = (systemPrompt: string, userMessage: string, opts: ReleaseNoteInvokeOptions) => Promise<{
15
+ text: string;
16
+ }>;
17
+ export interface ReleaseNoteAuthorDeps {
18
+ invoke: ReleaseNoteInvoke;
19
+ }
20
+ /** What the corrective attempt is shown: the refused note and why it was refused. */
21
+ export interface ReleaseNoteCorrection {
22
+ previous: ReleaseNoteDraft;
23
+ violations: readonly string[];
24
+ }
25
+ export type ReleaseNoteAuthorResult = {
26
+ kind: 'note';
27
+ note: ReleaseNoteDraft;
28
+ } | {
29
+ kind: 'failed';
30
+ reason: string;
31
+ } | {
32
+ kind: 'held';
33
+ reason: string;
34
+ };
35
+ export type ReleaseNoteOutput = {
36
+ kind: 'note';
37
+ note: ReleaseNoteDraft;
38
+ } | {
39
+ kind: 'error';
40
+ error: string;
41
+ };
42
+ /** The argv the pass adds to the one-shot argv: no tools, no MCP servers. Pure. */
43
+ export declare function buildReleaseNoteArgs(): string[];
44
+ /**
45
+ * Parse a release-note answer: the last fenced json block, holding a note
46
+ * object. Only the note's own fields are kept (a title is the release's own,
47
+ * set by the edge). Pure.
48
+ */
49
+ export declare function parseReleaseNoteOutput(text: string): ReleaseNoteOutput;
50
+ /**
51
+ * Author one release's note -- or, given a correction, the whole note again
52
+ * with the refused note and its violations appended. Never throws for a model
53
+ * or parse problem (those are results).
54
+ */
55
+ export declare function authorReleaseNote(context: DraftingContext, deps: ReleaseNoteAuthorDeps, correction?: ReleaseNoteCorrection | null): Promise<ReleaseNoteAuthorResult>;
56
+ //# sourceMappingURL=release-note-author.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"release-note-author.d.ts","sourceRoot":"","sources":["../../src/release-notes/release-note-author.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAOnG,uCAAuC;AACvC,eAAO,MAAM,uBAAuB,QAAc,CAAC;AACnD,kFAAkF;AAClF,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC,gDAAgD;AAChD,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wGAAwG;AACxG,MAAM,MAAM,iBAAiB,GAAG,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,wBAAwB,KAAK,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEzI,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,iBAAiB,CAAC;CAC3B;AAED,qFAAqF;AACrF,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/B;AAED,MAAM,MAAM,uBAAuB,GAC/B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,gBAAgB,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAErC,MAAM,MAAM,iBAAiB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5G,mFAAmF;AACnF,wBAAgB,oBAAoB,IAAI,MAAM,EAAE,CAE/C;AAQD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAmBtE;AAMD;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,qBAAqB,EAC3B,UAAU,GAAE,qBAAqB,GAAG,IAAW,GAC9C,OAAO,CAAC,uBAAuB,CAAC,CAsBlC"}
@@ -0,0 +1,107 @@
1
+ // PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
2
+ // Pinned by: packages/daemon/src/composition/release-note-pass-context.test.ts,
3
+ // packages/daemon/src/prompt-sections/release-note-section.test.ts,
4
+ // packages/daemon/src/release-notes/release-note-author.test.ts,
5
+ // packages/daemon/src/release-notes/release-note-faithfulness.test.ts,
6
+ // packages/daemon/src/release-notes/release-note-pass.test.ts
7
+ // PINNED-BY-END
8
+ /**
9
+ * Author one release's note: a FRESH one-shot model run (no tools, no MCP
10
+ * servers, a three-turn cap, ten minutes) over the drafting context the claim
11
+ * answered, read back as the LAST fenced ```json block of the answer.
12
+ *
13
+ * The check here is structural only -- a summary, a non-empty list of item
14
+ * objects -- so an answer that could never be a note is caught before it is
15
+ * written. The format (src/lib/releases/release-note-format.ts) and the
16
+ * faithfulness rules (sources name release work, links are ones offered for
17
+ * that work, no internal names, ids or commits) are the edge's: a draft it
18
+ * refuses comes back to the pass, which asks ONCE more with the refusal
19
+ * appended (a `correction`). Items are sent as the model wrote them, so the
20
+ * edge's refusal names exactly what to fix.
21
+ *
22
+ * A provider rate limit is not a failure of the pass: it returns `held`, and
23
+ * the pass gives the claim back so a later tick drafts the release. Every other
24
+ * problem is `failed` with its reason. The model run is injected
25
+ * (ReleaseNoteAuthorDeps.invoke), so no test needs a claude binary.
26
+ */
27
+ import { isModelUnavailable } from '../backends/claude/one-shot-model.js';
28
+ import { buildReleaseNoteCorrection, buildReleaseNotePrompt, RELEASE_NOTE_SYSTEM_PROMPT, } from '../prompt-sections/release-note-section.js';
29
+ /** Each attempt's wall-clock bound. */
30
+ export const RELEASE_NOTE_TIMEOUT_MS = 10 * 60_000;
31
+ /** The turn cap (the pass has no tools: everything it knows is in its prompt). */
32
+ export const RELEASE_NOTE_MAX_TURNS = 3;
33
+ /** The argv the pass adds to the one-shot argv: no tools, no MCP servers. Pure. */
34
+ export function buildReleaseNoteArgs() {
35
+ return ['--tools', '', '--strict-mcp-config'];
36
+ }
37
+ const FENCED_JSON = /```json[^\S\n]*\n([\s\S]*?)```/gi;
38
+ function isRecord(value) {
39
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
40
+ }
41
+ /**
42
+ * Parse a release-note answer: the last fenced json block, holding a note
43
+ * object. Only the note's own fields are kept (a title is the release's own,
44
+ * set by the edge). Pure.
45
+ */
46
+ export function parseReleaseNoteOutput(text) {
47
+ const blocks = [...text.matchAll(FENCED_JSON)].map((m) => m[1] ?? '');
48
+ const last = blocks.at(-1);
49
+ if (last === undefined)
50
+ return { kind: 'error', error: 'the answer has no fenced json block' };
51
+ let parsed;
52
+ try {
53
+ parsed = JSON.parse(last);
54
+ }
55
+ catch (err) {
56
+ return { kind: 'error', error: `the last json block is not valid JSON: ${err.message}` };
57
+ }
58
+ if (!isRecord(parsed))
59
+ return { kind: 'error', error: 'the last json block is not an object' };
60
+ const { summary, items, knownIssues } = parsed;
61
+ if (typeof summary !== 'string' || summary.trim() === '')
62
+ return { kind: 'error', error: 'the note has no summary' };
63
+ if (!Array.isArray(items) || items.length === 0)
64
+ return { kind: 'error', error: 'the note lists no items' };
65
+ const bad = items.findIndex((item) => !isRecord(item));
66
+ if (bad !== -1)
67
+ return { kind: 'error', error: `item ${bad + 1} is not an object` };
68
+ const note = { summary, items: items };
69
+ if (knownIssues !== undefined && knownIssues !== null)
70
+ note.knownIssues = knownIssues;
71
+ return { kind: 'note', note };
72
+ }
73
+ function errorMessage(err) {
74
+ return err instanceof Error ? err.message : String(err);
75
+ }
76
+ /**
77
+ * Author one release's note -- or, given a correction, the whole note again
78
+ * with the refused note and its violations appended. Never throws for a model
79
+ * or parse problem (those are results).
80
+ */
81
+ export async function authorReleaseNote(context, deps, correction = null) {
82
+ const attempt = correction ? 'corrective attempt' : 'drafting pass';
83
+ let prompt = buildReleaseNotePrompt(context);
84
+ if (correction)
85
+ prompt = `${prompt}\n${buildReleaseNoteCorrection(correction.violations, correction.previous)}`;
86
+ const label = `release-note:${context.releaseId.slice(0, 8)}${correction ? ':corrective' : ''}`;
87
+ let text;
88
+ try {
89
+ text = (await deps.invoke(RELEASE_NOTE_SYSTEM_PROMPT, prompt, {
90
+ label,
91
+ extraArgs: buildReleaseNoteArgs(),
92
+ timeoutMs: RELEASE_NOTE_TIMEOUT_MS,
93
+ maxTurns: RELEASE_NOTE_MAX_TURNS,
94
+ })).text;
95
+ }
96
+ catch (err) {
97
+ if (isModelUnavailable(err) && err.kind === 'rate_limit') {
98
+ return { kind: 'held', reason: `the ${attempt} hit the provider rate limit: ${err.message}` };
99
+ }
100
+ return { kind: 'failed', reason: `the ${attempt} could not run: ${errorMessage(err)}` };
101
+ }
102
+ const out = parseReleaseNoteOutput(text);
103
+ if (out.kind === 'error')
104
+ return { kind: 'failed', reason: `the ${attempt} answered no usable note: ${out.error}` };
105
+ return out;
106
+ }
107
+ //# sourceMappingURL=release-note-author.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"release-note-author.js","sourceRoot":"","sources":["../../src/release-notes/release-note-author.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import type { DraftingContext, ReleaseNoteDraft } from '../queries/release-notes/release-notes.js';
2
+ import { type ReleaseNoteAuthorDeps } from './release-note-author.js';
3
+ /** The check's wall-clock bound. */
4
+ export declare const RELEASE_NOTE_FAITHFULNESS_TIMEOUT_MS: number;
5
+ /** Its turn cap: it has no tools, so it answers in one. */
6
+ export declare const RELEASE_NOTE_FAITHFULNESS_MAX_TURNS = 2;
7
+ export type ReleaseNoteJudgement = {
8
+ kind: 'faithful';
9
+ } | {
10
+ kind: 'unfaithful';
11
+ violations: string[];
12
+ } | {
13
+ kind: 'failed';
14
+ reason: string;
15
+ } | {
16
+ kind: 'held';
17
+ reason: string;
18
+ };
19
+ export interface FaithfulnessVerdict {
20
+ item: number;
21
+ faithful: boolean;
22
+ reason: string;
23
+ }
24
+ export type FaithfulnessOutput = {
25
+ kind: 'verdicts';
26
+ verdicts: FaithfulnessVerdict[];
27
+ } | {
28
+ kind: 'error';
29
+ error: string;
30
+ };
31
+ /**
32
+ * Read the check's answer: the last fenced json block, holding exactly one
33
+ * verdict for each of the note's `itemCount` items. Pure.
34
+ */
35
+ export declare function parseFaithfulnessOutput(text: string, itemCount: number): FaithfulnessOutput;
36
+ /** A not-faithful verdict as a violation the corrective attempt is shown. */
37
+ export declare function faithfulnessViolation(note: ReleaseNoteDraft, verdict: FaithfulnessVerdict): string;
38
+ /** Judge every item's Why against its work's source. Never throws for a model or parse problem. */
39
+ export declare function judgeReleaseNoteWhys(context: DraftingContext, note: ReleaseNoteDraft, deps: ReleaseNoteAuthorDeps): Promise<ReleaseNoteJudgement>;
40
+ //# sourceMappingURL=release-note-faithfulness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"release-note-faithfulness.d.ts","sourceRoot":"","sources":["../../src/release-notes/release-note-faithfulness.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAKnG,OAAO,EAAwB,KAAK,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAE5F,oCAAoC;AACpC,eAAO,MAAM,oCAAoC,QAAa,CAAC;AAC/D,2DAA2D;AAC3D,eAAO,MAAM,mCAAmC,IAAI,CAAC;AAErD,MAAM,MAAM,oBAAoB,GAC5B;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GACpB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAErC,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,kBAAkB,GAAG;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,mBAAmB,EAAE,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAQ1H;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,kBAAkB,CAwB3F;AAOD,6EAA6E;AAC7E,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,mBAAmB,GAAG,MAAM,CAIlG;AAMD,mGAAmG;AACnG,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,gBAAgB,EACtB,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,oBAAoB,CAAC,CAqB/B"}
@@ -0,0 +1,107 @@
1
+ // PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
2
+ // Pinned by: packages/daemon/src/release-notes/release-note-faithfulness.test.ts,
3
+ // packages/daemon/src/release-notes/release-note-pass.test.ts
4
+ // PINNED-BY-END
5
+ /**
6
+ * The drafting pass's MODEL faithfulness check: before a drafted note is
7
+ * written, a FRESH one-shot model run (no tools, no MCP servers) reads each
8
+ * item's Why against the source of the work it names -- the requests users
9
+ * raised, else the problem the work states -- and answers, per item, whether
10
+ * the Why states it (prompt-sections/release-note-faithfulness-section.ts).
11
+ *
12
+ * This is where a Why's MEANING is judged. The edge refuses only a Why that
13
+ * turns its source around by adding or dropping a negation; whether it states
14
+ * its source well is this check's and, after it, the human's who edits and
15
+ * publishes the note (docs/DECISIONS.md, "A release carries done deliveries
16
+ * once per environment", item 7).
17
+ *
18
+ * An item judged unfaithful comes back to the pass as a violation, on the same
19
+ * footing as an edge refusal: the pass re-asks the author ONCE with it
20
+ * appended (release-note-pass.ts). A provider rate limit is `held` (the claim
21
+ * is given back); a run that fails, or an answer that is not one verdict per
22
+ * item, is `failed` -- a note the check could not judge is not written as if
23
+ * it had been. The model run is injected, so no test needs a claude binary.
24
+ */
25
+ import { isModelUnavailable } from '../backends/claude/one-shot-model.js';
26
+ import { buildReleaseNoteFaithfulnessPrompt, RELEASE_NOTE_FAITHFULNESS_SYSTEM_PROMPT, } from '../prompt-sections/release-note-faithfulness-section.js';
27
+ import { buildReleaseNoteArgs } from './release-note-author.js';
28
+ /** The check's wall-clock bound. */
29
+ export const RELEASE_NOTE_FAITHFULNESS_TIMEOUT_MS = 5 * 60_000;
30
+ /** Its turn cap: it has no tools, so it answers in one. */
31
+ export const RELEASE_NOTE_FAITHFULNESS_MAX_TURNS = 2;
32
+ const FENCED_JSON = /```json[^\S\n]*\n([\s\S]*?)```/gi;
33
+ function isRecord(value) {
34
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
35
+ }
36
+ /**
37
+ * Read the check's answer: the last fenced json block, holding exactly one
38
+ * verdict for each of the note's `itemCount` items. Pure.
39
+ */
40
+ export function parseFaithfulnessOutput(text, itemCount) {
41
+ const last = [...text.matchAll(FENCED_JSON)].map((m) => m[1] ?? '').at(-1);
42
+ if (last === undefined)
43
+ return { kind: 'error', error: 'the answer has no fenced json block' };
44
+ let parsed;
45
+ try {
46
+ parsed = JSON.parse(last);
47
+ }
48
+ catch (err) {
49
+ return { kind: 'error', error: `the last json block is not valid JSON: ${err.message}` };
50
+ }
51
+ if (!isRecord(parsed) || !Array.isArray(parsed.items))
52
+ return { kind: 'error', error: 'the answer lists no items' };
53
+ const byItem = new Map();
54
+ for (const entry of parsed.items) {
55
+ if (!isRecord(entry) || typeof entry.item !== 'number' || typeof entry.faithful !== 'boolean') {
56
+ return { kind: 'error', error: 'a verdict is not {item, faithful, reason}' };
57
+ }
58
+ byItem.set(entry.item, { item: entry.item, faithful: entry.faithful, reason: typeof entry.reason === 'string' ? entry.reason.trim() : '' });
59
+ }
60
+ const verdicts = [];
61
+ for (let item = 1; item <= itemCount; item++) {
62
+ const verdict = byItem.get(item);
63
+ if (!verdict)
64
+ return { kind: 'error', error: `item ${item} has no verdict` };
65
+ verdicts.push(verdict);
66
+ }
67
+ return { kind: 'verdicts', verdicts };
68
+ }
69
+ function headlineOf(note, index) {
70
+ const headline = note.items[index]?.headline;
71
+ return typeof headline === 'string' ? headline.slice(0, 60) : '';
72
+ }
73
+ /** A not-faithful verdict as a violation the corrective attempt is shown. */
74
+ export function faithfulnessViolation(note, verdict) {
75
+ return `item ${verdict.item} ("${headlineOf(note, verdict.item - 1)}"): its Why does not state its work's source -- ` +
76
+ `${verdict.reason || 'the check gave no reason'}: say the request users raised (or the problem the work states), ` +
77
+ 'in its sense, in the reader\'s words';
78
+ }
79
+ function errorMessage(err) {
80
+ return err instanceof Error ? err.message : String(err);
81
+ }
82
+ /** Judge every item's Why against its work's source. Never throws for a model or parse problem. */
83
+ export async function judgeReleaseNoteWhys(context, note, deps) {
84
+ let text;
85
+ try {
86
+ text = (await deps.invoke(RELEASE_NOTE_FAITHFULNESS_SYSTEM_PROMPT, buildReleaseNoteFaithfulnessPrompt(context, note), {
87
+ label: `release-note:${context.releaseId.slice(0, 8)}:faithfulness`,
88
+ extraArgs: buildReleaseNoteArgs(),
89
+ timeoutMs: RELEASE_NOTE_FAITHFULNESS_TIMEOUT_MS,
90
+ maxTurns: RELEASE_NOTE_FAITHFULNESS_MAX_TURNS,
91
+ })).text;
92
+ }
93
+ catch (err) {
94
+ if (isModelUnavailable(err) && err.kind === 'rate_limit') {
95
+ return { kind: 'held', reason: `the faithfulness check hit the provider rate limit: ${err.message}` };
96
+ }
97
+ return { kind: 'failed', reason: `the faithfulness check could not run: ${errorMessage(err)}` };
98
+ }
99
+ const out = parseFaithfulnessOutput(text, note.items.length);
100
+ if (out.kind === 'error')
101
+ return { kind: 'failed', reason: `the faithfulness check answered no usable verdicts: ${out.error}` };
102
+ const unfaithful = out.verdicts.filter((v) => !v.faithful);
103
+ return unfaithful.length === 0
104
+ ? { kind: 'faithful' }
105
+ : { kind: 'unfaithful', violations: unfaithful.map((v) => faithfulnessViolation(note, v)) };
106
+ }
107
+ //# sourceMappingURL=release-note-faithfulness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"release-note-faithfulness.js","sourceRoot":"","sources":["../../src/release-notes/release-note-faithfulness.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * The release-note drafting pass: for every configured product, the releases a
3
+ * human has cut that are still drafting and held by no live pass get their
4
+ * note drafted, one release at a time.
5
+ *
6
+ * Per candidate: claim it (a release another pass holds, or that stopped
7
+ * drafting, is skipped) -> author the note from the drafting context the claim
8
+ * answered (release-note-author.ts) -> JUDGE it: the model faithfulness check
9
+ * reads each item's Why against its work's source (release-note-faithfulness.ts)
10
+ * -> write it as the release's draft under the claim. The edge stores a draft
11
+ * only when it is a note in the one format and keeps its rules. A draft the
12
+ * check finds unfaithful, or the edge REFUSES, is authored ONCE more with what
13
+ * was wrong appended, judged and written again; a second rejection is written
14
+ * as the release's failure with what was said (a human redraft retries). A
15
+ * check that cannot judge the note records the failure too: a note is never
16
+ * written as if it had been judged.
17
+ * A draft written after the human changed the release's work is a conflict:
18
+ * the claim is given back, so the next tick drafts the release again from the
19
+ * work it now carries. A claim this pass lost is left alone. A provider rate
20
+ * limit gives the claim back too: the next tick may take it at once.
21
+ *
22
+ * The pass's only writes are those release-note writes (product-api
23
+ * daemon_release_note_claim / daemon_release_note_write); it never writes a
24
+ * focus, a delivery or an arm.
25
+ *
26
+ * IT NEVER DELAYS ARMED WORK. It acquires no ResourceGovernor slot and never
27
+ * waits on one: its hold (composition/release-note-pass-context.ts) reads the
28
+ * governor's utilization and does not start, or go on to the next release,
29
+ * while every session slot is taken or a spawn is queued for one, while the
30
+ * claude provider's rate-limit window is open, or while the daemon is
31
+ * read-only. At most ONE pass runs per daemon: a tick that finds one in flight
32
+ * returns at once.
33
+ */
34
+ import type { ResourceGovernor } from '@telora/daemon-core';
35
+ import { type DraftingContext, type ReleaseNoteCandidate, type ReleaseNoteClaim, type ReleaseNoteDraft, type ReleaseNoteWrite } from '../queries/release-notes/release-notes.js';
36
+ import type { ReleaseNoteAuthorResult, ReleaseNoteCorrection } from './release-note-author.js';
37
+ import type { ReleaseNoteJudgement } from './release-note-faithfulness.js';
38
+ /** The loop's cadence. */
39
+ export declare const RELEASE_NOTE_PASS_INTERVAL_MS = 60000;
40
+ export interface ReleaseNotePassDeps {
41
+ products: ReadonlyArray<{
42
+ id: string;
43
+ }>;
44
+ readCandidates: (productId: string) => Promise<ReleaseNoteCandidate[]>;
45
+ claim: (releaseId: string) => Promise<ReleaseNoteClaim>;
46
+ write: (write: ReleaseNoteWrite) => Promise<void>;
47
+ /** Give the claim back; false when this pass no longer held it. */
48
+ unclaim: (releaseId: string, claimId: string) => Promise<boolean>;
49
+ author: (context: DraftingContext, correction: ReleaseNoteCorrection | null) => Promise<ReleaseNoteAuthorResult>;
50
+ /** The model faithfulness check: does each item's Why state its work's source? */
51
+ judge: (context: DraftingContext, note: ReleaseNoteDraft) => Promise<ReleaseNoteJudgement>;
52
+ /** Why the pass must not start or go on to the next release now, or null. */
53
+ holdReason: () => string | null;
54
+ }
55
+ /** The pass's deps over the running daemon, or null before it has a live config (composition/release-note-pass-context.ts). */
56
+ export type ReleaseNotePassDepsSource = (governor: ResourceGovernor | null) => ReleaseNotePassDeps | null;
57
+ export interface ReleaseNotePassOutcome {
58
+ /** Why the pass stopped early or did not start, when it did. */
59
+ skipped: string | null;
60
+ /** Drafts stored. */
61
+ drafted: number;
62
+ /** Releases written draft_failed. */
63
+ failed: number;
64
+ /** Claims given back (a provider rate limit, or the release's work changed while drafting). */
65
+ released: number;
66
+ /** Claims this pass lost to another (or the release left drafting) before it wrote. */
67
+ lost: number;
68
+ /** Candidates another pass held when this one tried to claim them. */
69
+ notClaimed: number;
70
+ /** Failed reads, claims and writes. */
71
+ errors: number;
72
+ }
73
+ /** Run one pass over every product. One product's failed read never stops another's. */
74
+ export declare function runReleaseNotePass(deps: ReleaseNotePassDeps): Promise<ReleaseNotePassOutcome>;
75
+ /** The loop tick: one pass over the live deps, never throwing into the timer. */
76
+ export declare function runReleaseNotePassSafely(source: ReleaseNotePassDepsSource, governor: ResourceGovernor | null): Promise<void>;
77
+ //# sourceMappingURL=release-note-pass.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"release-note-pass.d.ts","sourceRoot":"","sources":["../../src/release-notes/release-note-pass.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EAEtB,MAAM,2CAA2C,CAAC;AACnD,OAAO,KAAK,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAC/F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAI3E,0BAA0B;AAC1B,eAAO,MAAM,6BAA6B,QAAS,CAAC;AAEpD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,aAAa,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxC,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC;IACvE,KAAK,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACxD,KAAK,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,mEAAmE;IACnE,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAClE,MAAM,EAAE,CAAC,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,qBAAqB,GAAG,IAAI,KAAK,OAAO,CAAC,uBAAuB,CAAC,CAAC;IACjH,kFAAkF;IAClF,KAAK,EAAE,CAAC,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,gBAAgB,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC3F,6EAA6E;IAC7E,UAAU,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,+HAA+H;AAC/H,MAAM,MAAM,yBAAyB,GAAG,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI,KAAK,mBAAmB,GAAG,IAAI,CAAC;AAE1G,MAAM,WAAW,sBAAsB;IACrC,gEAAgE;IAChE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,qBAAqB;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,+FAA+F;IAC/F,QAAQ,EAAE,MAAM,CAAC;IACjB,uFAAuF;IACvF,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,UAAU,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;CAChB;AA2JD,wFAAwF;AACxF,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CA0BnG;AAED,iFAAiF;AACjF,wBAAsB,wBAAwB,CAAC,MAAM,EAAE,yBAAyB,EAAE,QAAQ,EAAE,gBAAgB,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAclI"}