@paths.design/caws-cli 11.1.6 → 11.1.8

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 (190) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +55 -58
  3. package/dist/init/hook-packs/manifest-claude-code.d.ts +1 -1
  4. package/dist/init/hook-packs/manifest-claude-code.d.ts.map +1 -1
  5. package/dist/init/hook-packs/manifest-claude-code.js +317 -6
  6. package/dist/init/hook-packs/manifest-claude-code.js.map +1 -1
  7. package/dist/init/hook-packs/types.js +1 -1
  8. package/dist/init/hook-packs/types.js.map +1 -1
  9. package/dist/shell/binding/resolve-binding.d.ts.map +1 -1
  10. package/dist/shell/binding/resolve-binding.js +105 -1
  11. package/dist/shell/binding/resolve-binding.js.map +1 -1
  12. package/dist/shell/binding/types.d.ts +47 -3
  13. package/dist/shell/binding/types.d.ts.map +1 -1
  14. package/dist/shell/command-metadata.d.ts +93 -0
  15. package/dist/shell/command-metadata.d.ts.map +1 -0
  16. package/dist/shell/command-metadata.js +687 -0
  17. package/dist/shell/command-metadata.js.map +1 -0
  18. package/dist/shell/commands/agents.d.ts +48 -0
  19. package/dist/shell/commands/agents.d.ts.map +1 -0
  20. package/dist/shell/commands/agents.js +577 -0
  21. package/dist/shell/commands/agents.js.map +1 -0
  22. package/dist/shell/commands/claim.d.ts +16 -0
  23. package/dist/shell/commands/claim.d.ts.map +1 -1
  24. package/dist/shell/commands/claim.js +88 -30
  25. package/dist/shell/commands/claim.js.map +1 -1
  26. package/dist/shell/commands/events.d.ts +106 -0
  27. package/dist/shell/commands/events.d.ts.map +1 -0
  28. package/dist/shell/commands/events.js +510 -0
  29. package/dist/shell/commands/events.js.map +1 -0
  30. package/dist/shell/commands/gates.d.ts +2 -2
  31. package/dist/shell/commands/gates.d.ts.map +1 -1
  32. package/dist/shell/commands/gates.js +106 -25
  33. package/dist/shell/commands/gates.js.map +1 -1
  34. package/dist/shell/commands/init.d.ts.map +1 -1
  35. package/dist/shell/commands/init.js +26 -0
  36. package/dist/shell/commands/init.js.map +1 -1
  37. package/dist/shell/commands/prepush.d.ts +26 -0
  38. package/dist/shell/commands/prepush.d.ts.map +1 -0
  39. package/dist/shell/commands/prepush.js +373 -0
  40. package/dist/shell/commands/prepush.js.map +1 -0
  41. package/dist/shell/commands/scope.d.ts.map +1 -1
  42. package/dist/shell/commands/scope.js +31 -1
  43. package/dist/shell/commands/scope.js.map +1 -1
  44. package/dist/shell/commands/specs.d.ts +44 -3
  45. package/dist/shell/commands/specs.d.ts.map +1 -1
  46. package/dist/shell/commands/specs.js +411 -15
  47. package/dist/shell/commands/specs.js.map +1 -1
  48. package/dist/shell/commands/status.d.ts +12 -0
  49. package/dist/shell/commands/status.d.ts.map +1 -1
  50. package/dist/shell/commands/status.js +236 -21
  51. package/dist/shell/commands/status.js.map +1 -1
  52. package/dist/shell/commands/worktree.d.ts +9 -0
  53. package/dist/shell/commands/worktree.d.ts.map +1 -1
  54. package/dist/shell/commands/worktree.js +353 -1
  55. package/dist/shell/commands/worktree.js.map +1 -1
  56. package/dist/shell/gates/disposition.d.ts.map +1 -1
  57. package/dist/shell/gates/disposition.js +43 -2
  58. package/dist/shell/gates/disposition.js.map +1 -1
  59. package/dist/shell/index.d.ts +14 -6
  60. package/dist/shell/index.d.ts.map +1 -1
  61. package/dist/shell/index.js +32 -1
  62. package/dist/shell/index.js.map +1 -1
  63. package/dist/shell/legacy-command-map.js +832 -0
  64. package/dist/shell/push-range/classify-range.d.ts +99 -0
  65. package/dist/shell/push-range/classify-range.d.ts.map +1 -0
  66. package/dist/shell/push-range/classify-range.js +155 -0
  67. package/dist/shell/push-range/classify-range.js.map +1 -0
  68. package/dist/shell/push-range/scope-match.d.ts +13 -0
  69. package/dist/shell/push-range/scope-match.d.ts.map +1 -0
  70. package/dist/shell/push-range/scope-match.js +53 -0
  71. package/dist/shell/push-range/scope-match.js.map +1 -0
  72. package/dist/shell/register.d.ts.map +1 -1
  73. package/dist/shell/register.js +350 -165
  74. package/dist/shell/register.js.map +1 -1
  75. package/dist/shell/registered-command-groups.js +48 -0
  76. package/dist/shell/render/status.d.ts +7 -1
  77. package/dist/shell/render/status.d.ts.map +1 -1
  78. package/dist/shell/render/status.js +72 -0
  79. package/dist/shell/render/status.js.map +1 -1
  80. package/dist/shell/rules.d.ts +19 -0
  81. package/dist/shell/rules.d.ts.map +1 -1
  82. package/dist/shell/rules.js +27 -0
  83. package/dist/shell/rules.js.map +1 -1
  84. package/dist/shell/session/resolve-session.d.ts +29 -1
  85. package/dist/shell/session/resolve-session.d.ts.map +1 -1
  86. package/dist/shell/session/resolve-session.js +817 -11
  87. package/dist/shell/session/resolve-session.js.map +1 -1
  88. package/dist/shell/session/types.d.ts +127 -1
  89. package/dist/shell/session/types.d.ts.map +1 -1
  90. package/dist/shell/session/types.js +10 -4
  91. package/dist/shell/session/types.js.map +1 -1
  92. package/dist/store/agents-store.d.ts.map +1 -1
  93. package/dist/store/agents-store.js +9 -0
  94. package/dist/store/agents-store.js.map +1 -1
  95. package/dist/store/apply-patch.d.ts.map +1 -1
  96. package/dist/store/apply-patch.js +15 -0
  97. package/dist/store/apply-patch.js.map +1 -1
  98. package/dist/store/doctor-snapshot.d.ts.map +1 -1
  99. package/dist/store/doctor-snapshot.js +169 -3
  100. package/dist/store/doctor-snapshot.js.map +1 -1
  101. package/dist/store/events-migration.d.ts +207 -0
  102. package/dist/store/events-migration.d.ts.map +1 -0
  103. package/dist/store/events-migration.js +358 -0
  104. package/dist/store/events-migration.js.map +1 -0
  105. package/dist/store/events-store.d.ts +47 -1
  106. package/dist/store/events-store.d.ts.map +1 -1
  107. package/dist/store/events-store.js +278 -0
  108. package/dist/store/events-store.js.map +1 -1
  109. package/dist/store/git-autocommit.d.ts +46 -0
  110. package/dist/store/git-autocommit.d.ts.map +1 -0
  111. package/dist/store/git-autocommit.js +198 -0
  112. package/dist/store/git-autocommit.js.map +1 -0
  113. package/dist/store/git-sparse-checkout.d.ts +25 -0
  114. package/dist/store/git-sparse-checkout.d.ts.map +1 -0
  115. package/dist/store/git-sparse-checkout.js +101 -0
  116. package/dist/store/git-sparse-checkout.js.map +1 -0
  117. package/dist/store/index.d.ts +6 -1
  118. package/dist/store/index.d.ts.map +1 -1
  119. package/dist/store/index.js +16 -1
  120. package/dist/store/index.js.map +1 -1
  121. package/dist/store/leases-store.d.ts +89 -0
  122. package/dist/store/leases-store.d.ts.map +1 -0
  123. package/dist/store/leases-store.js +427 -0
  124. package/dist/store/leases-store.js.map +1 -0
  125. package/dist/store/lifecycle-transaction.d.ts.map +1 -1
  126. package/dist/store/lifecycle-transaction.js +34 -1
  127. package/dist/store/lifecycle-transaction.js.map +1 -1
  128. package/dist/store/rules.d.ts +74 -1
  129. package/dist/store/rules.d.ts.map +1 -1
  130. package/dist/store/rules.js +76 -0
  131. package/dist/store/rules.js.map +1 -1
  132. package/dist/store/specs-migration.d.ts +128 -0
  133. package/dist/store/specs-migration.d.ts.map +1 -0
  134. package/dist/store/specs-migration.js +481 -0
  135. package/dist/store/specs-migration.js.map +1 -0
  136. package/dist/store/specs-store.d.ts.map +1 -1
  137. package/dist/store/specs-store.js +14 -2
  138. package/dist/store/specs-store.js.map +1 -1
  139. package/dist/store/specs-writer.d.ts +130 -3
  140. package/dist/store/specs-writer.d.ts.map +1 -1
  141. package/dist/store/specs-writer.js +941 -102
  142. package/dist/store/specs-writer.js.map +1 -1
  143. package/dist/store/types.d.ts +31 -1
  144. package/dist/store/types.d.ts.map +1 -1
  145. package/dist/store/waivers-store.d.ts.map +1 -1
  146. package/dist/store/waivers-store.js +8 -1
  147. package/dist/store/waivers-store.js.map +1 -1
  148. package/dist/store/worktrees-migration.d.ts +141 -0
  149. package/dist/store/worktrees-migration.d.ts.map +1 -0
  150. package/dist/store/worktrees-migration.js +356 -0
  151. package/dist/store/worktrees-migration.js.map +1 -0
  152. package/dist/store/worktrees-writer.d.ts +28 -0
  153. package/dist/store/worktrees-writer.d.ts.map +1 -1
  154. package/dist/store/worktrees-writer.js +147 -13
  155. package/dist/store/worktrees-writer.js.map +1 -1
  156. package/package.json +5 -2
  157. package/templates/hook-packs/claude-code/CLAUDE.md +11 -5
  158. package/templates/hook-packs/claude-code/agent-heartbeat.sh +131 -0
  159. package/templates/hook-packs/claude-code/agent-register.sh +62 -0
  160. package/templates/hook-packs/claude-code/agent-stop.sh +51 -0
  161. package/templates/hook-packs/claude-code/audit.sh +1 -1
  162. package/templates/hook-packs/claude-code/block-dangerous.sh +1 -1
  163. package/templates/hook-packs/claude-code/classify_command.py +1 -1
  164. package/templates/hook-packs/claude-code/cwd-guard.sh +30 -0
  165. package/templates/hook-packs/claude-code/dispatch/post_tool_use.sh +15 -4
  166. package/templates/hook-packs/claude-code/dispatch/pre_tool_use.sh +19 -2
  167. package/templates/hook-packs/claude-code/dispatch/session_start.sh +6 -2
  168. package/templates/hook-packs/claude-code/dispatch/stop.sh +7 -2
  169. package/templates/hook-packs/claude-code/duplicate-export-check.sh +156 -0
  170. package/templates/hook-packs/claude-code/god-object-check.sh +102 -0
  171. package/templates/hook-packs/claude-code/guard-strikes.sh +1 -1
  172. package/templates/hook-packs/claude-code/lib/parse-input.sh +115 -1
  173. package/templates/hook-packs/claude-code/lib/run-handlers.sh +1 -1
  174. package/templates/hook-packs/claude-code/loc-delta-check.sh +91 -0
  175. package/templates/hook-packs/claude-code/naming-check.sh +128 -0
  176. package/templates/hook-packs/claude-code/plan-transcript-finalize.sh +59 -0
  177. package/templates/hook-packs/claude-code/plan-transcript-snapshot.sh +86 -0
  178. package/templates/hook-packs/claude-code/protected-paths.sh +59 -0
  179. package/templates/hook-packs/claude-code/quiet-merge.sh +68 -0
  180. package/templates/hook-packs/claude-code/reset-danger-latch.sh +1 -1
  181. package/templates/hook-packs/claude-code/reset-strikes.sh +1 -1
  182. package/templates/hook-packs/claude-code/runtime-paths.sh +1 -1
  183. package/templates/hook-packs/claude-code/scan-secrets.sh +98 -0
  184. package/templates/hook-packs/claude-code/scope-guard.sh +47 -65
  185. package/templates/hook-packs/claude-code/session-caws-status.sh +7 -1
  186. package/templates/hook-packs/claude-code/session-log.sh +1 -1
  187. package/templates/hook-packs/claude-code/session_log_renderer.py +956 -0
  188. package/templates/hook-packs/claude-code/shortcut-language-check.sh +147 -0
  189. package/templates/hook-packs/claude-code/worktree-guard.sh +130 -4
  190. package/templates/hook-packs/claude-code/worktree-write-guard.sh +133 -18
@@ -0,0 +1,207 @@
1
+ import { type Diagnostic, type Result } from '@paths.design/caws-kernel';
2
+ export declare const MIGRATION_RULES: {
3
+ /** events.jsonl could not be JSON-parsed at all; every line failed. */
4
+ readonly UNPARSEABLE_INPUT: "store.events.migration.unparseable_input";
5
+ /** events.jsonl is empty; there is nothing to migrate or rotate. */
6
+ readonly EMPTY_INPUT: "store.events.migration.empty_input";
7
+ /** A v10-shape spec YAML was detected during half-upgrade scan. */
8
+ readonly V10_SPEC_DETECTED: "store.events.migration.v10_spec_detected";
9
+ /** events.jsonl has SOME unparseable lines alongside parseable ones.
10
+ * The chain_rotated payload's prior_chain_status enum has no honest
11
+ * label for this case (parseable_unverified implies every line
12
+ * parsed; unparseable implies none did), so the planner refuses.
13
+ * Mirrors STORE_RULES.EVENTS_ROTATE_PARTIAL_CORRUPTION in rotateEvents
14
+ * so dry-run and apply paths agree. */
15
+ readonly PARTIAL_CORRUPTION_REFUSED: "store.events.migration.partial_corruption_refused";
16
+ /** The shell could not scan .caws/specs/ for v10-shape YAMLs (directory
17
+ * missing, unreadable, or sparse-checkout-excluded). The half-upgrade
18
+ * refusal CANNOT be enforced without a complete scan, so the migration
19
+ * command refuses by default rather than silently bypass the guard.
20
+ * No friction-flag escape in v11.2 scope. */
21
+ readonly SPEC_SCAN_UNAVAILABLE: "store.events.migration.spec_scan_unavailable";
22
+ /** Bug-class assertion: dry-run reported an archive name X and the
23
+ * apply path (rotateEvents) returned a different archive name Y.
24
+ * This indicates the dry-run's now-clock and the apply's now-clock
25
+ * drifted, or windowsSafeIso diverged between events-migration.ts
26
+ * and events-store.ts. Either way it is a programmer error, not an
27
+ * operator error; the shell surfaces it as an internal failure. */
28
+ readonly INTERNAL_DRYRUN_APPLY_MISMATCH: "store.events.migration.internal_dryrun_apply_mismatch";
29
+ /** events migrate refused because the underlying log is fully
30
+ * unparseable. Migration cannot claim it found a v10 chain. The
31
+ * lower-level `caws events rotate` may still archive a fully
32
+ * unparseable log under the honest 'unparseable' status as evidence
33
+ * quarantine — that semantic is intentional and distinct from
34
+ * migration. */
35
+ readonly MIGRATE_UNPARSEABLE_REFUSED: "store.events.migration.unparseable_refused";
36
+ /** verify-archive: events.jsonl exists but contains no chain_rotated
37
+ * event. There is nothing to verify against. */
38
+ readonly VERIFY_NO_ROTATION_EVENT: "store.events.verify_archive.no_rotation_event";
39
+ /** verify-archive: the archive file named by the most recent
40
+ * chain_rotated event does not exist on disk. */
41
+ readonly VERIFY_ARCHIVE_MISSING: "store.events.verify_archive.archive_missing";
42
+ /** verify-archive: the current events.jsonl could not be loaded
43
+ * (e.g., malformed JSON line, invalid chain). The shell cannot
44
+ * determine the most recent chain_rotated event. */
45
+ readonly VERIFY_CURRENT_CHAIN_INVALID: "store.events.verify_archive.current_chain_invalid";
46
+ };
47
+ export type MigrationRule = (typeof MIGRATION_RULES)[keyof typeof MIGRATION_RULES];
48
+ export interface ActorShapeStats {
49
+ readonly v10_string_actor: number;
50
+ readonly v11_object_actor: number;
51
+ readonly unparseable: number;
52
+ }
53
+ export type EventsLogKind =
54
+ /** Every parseable line has a string actor (v10 envelope). */
55
+ 'all_v10'
56
+ /** Every parseable line has a structured actor (v11 envelope). */
57
+ | 'all_v11'
58
+ /** Lines exist with both shapes. */
59
+ | 'mixed_v10_v11'
60
+ /** The file has zero non-empty lines. */
61
+ | 'empty'
62
+ /** No line could be JSON-parsed. */
63
+ | 'unparseable_only';
64
+ export interface EventsLogShape {
65
+ readonly kind: EventsLogKind;
66
+ readonly stats: ActorShapeStats;
67
+ /** Total non-empty lines (parseable + unparseable). */
68
+ readonly lineCount: number;
69
+ /** Tail event_hash if the last non-empty line parsed and carried one. */
70
+ readonly tailHash: string | null;
71
+ /** Tail seq if the last non-empty line parsed and carried a valid integer. */
72
+ readonly tailSeq: number | null;
73
+ }
74
+ /**
75
+ * Classify the actor-shape of every non-empty line in a raw events.jsonl
76
+ * payload. Pure: takes the file contents as a string, returns the
77
+ * detection result. No filesystem access.
78
+ *
79
+ * Errors:
80
+ * - returns Err for an empty input. The shell treats this as "nothing
81
+ * to do" rather than a hard error — the same condition rotateEvents
82
+ * refuses on, so the migration command can short-circuit before
83
+ * calling into the store.
84
+ *
85
+ * The detector deliberately does NOT call validateChainedEvent: the
86
+ * whole point of this slice is to handle v10-shape lines that the
87
+ * strict validator rejects. JSON.parse + direct actor-shape inspection
88
+ * is the entire contract.
89
+ */
90
+ export declare function detectEventsLogShape(raw: string): Result<EventsLogShape>;
91
+ export interface SpecYamlInput {
92
+ /** Relative or absolute path; used in the report to point at the file. */
93
+ readonly path: string;
94
+ /** Raw YAML contents. */
95
+ readonly raw: string;
96
+ }
97
+ export interface V10SpecsScanResult {
98
+ /** True iff at least one input file looks v10-shape. */
99
+ readonly detected: boolean;
100
+ /** Files classified as v10-shape, by path. */
101
+ readonly v10Paths: readonly string[];
102
+ /** Files classified as v11-shape, by path. */
103
+ readonly v11Paths: readonly string[];
104
+ /** Files that could not be classified (parse error or no signal). */
105
+ readonly unclassifiedPaths: readonly string[];
106
+ }
107
+ /**
108
+ * Minimal v10-vs-v11 spec YAML scanner. Used by the events migrate
109
+ * command to enforce the half-upgrade refusal (A10): if v10-shape spec
110
+ * YAMLs exist alongside v10 events, the operator must either run the
111
+ * specs migration first or explicitly pass --allow-partial-upgrade.
112
+ *
113
+ * Classification heuristic (per the spec's A10 invariant — "the check
114
+ * is mechanical: scan .caws/specs/*.yaml for v10 top-level keys (type,
115
+ * status, acceptance_criteria) and refuse if any are found"):
116
+ *
117
+ * - v10: file contains any of the top-level keys `type:`, `status:`,
118
+ * or `acceptance_criteria:` at column 0.
119
+ * - v11: file contains any of the top-level keys `mode:`,
120
+ * `lifecycle_state:`, or `acceptance:` at column 0, AND none of
121
+ * the v10 keys.
122
+ * - unclassified: no signal in either direction (e.g., empty file,
123
+ * comment-only file, malformed YAML).
124
+ *
125
+ * This is a regex-level scan, not a full YAML parse. Deliverable 2
126
+ * (CAWS-MIGRATE-V10-SPECS-001) may replace it with detectSpecVersion
127
+ * from packages/caws-kernel/src/spec/migrate-v10.ts when that ships,
128
+ * but the refusal contract owned by this slice (A10) is named here.
129
+ */
130
+ export declare function detectV10SpecsPresent(files: readonly SpecYamlInput[]): V10SpecsScanResult;
131
+ export interface PlanOptions {
132
+ /** Operator-supplied reason. Mirrors rotateEvents's reason field. */
133
+ readonly reason: string;
134
+ /** Pass-through to the rotateEvents allowClean friction flag. */
135
+ readonly allowClean?: boolean;
136
+ /** When true, ignores v10-spec presence and admits rotation anyway. */
137
+ readonly allowPartialUpgrade?: boolean;
138
+ /** Required for archive-name proposal. The shell injects new Date(). */
139
+ readonly now: Date;
140
+ /**
141
+ * Optional v10-spec scan result. When omitted, the planner does NOT
142
+ * fire the half-upgrade refusal — that requires the caller (the shell)
143
+ * to have scanned the specs directory. When present and detected:true
144
+ * AND allowPartialUpgrade !== true, the plan is a refusal.
145
+ */
146
+ readonly v10Specs?: V10SpecsScanResult;
147
+ }
148
+ /** Why a plan refused, when kind === 'refuse'. */
149
+ export type PlanRefusalCause = 'empty' | 'unparseable_only' | 'partial_corruption' | 'clean_chain_requires_allow_clean' | 'v10_specs_require_allow_partial_upgrade';
150
+ /** Plan to rotate. The shell may invoke rotateEvents with these inputs. */
151
+ export interface RotatePlan {
152
+ readonly kind: 'rotate';
153
+ /** Pass-through to rotateEvents. */
154
+ readonly reason: string;
155
+ /** Pass-through to rotateEvents. */
156
+ readonly allowClean: boolean;
157
+ /** Pass-through to rotateEvents. */
158
+ readonly now: Date;
159
+ /** What the proposed archive will be named. Informational; rotateEvents
160
+ * computes the same name from its own `now` parameter. */
161
+ readonly proposedArchiveName: string;
162
+ /** The detected shape that justified the plan; included so dry-run can
163
+ * render the full classification next to the rotation summary. */
164
+ readonly detection: EventsLogShape;
165
+ /** v10-spec scan result if the caller provided one; informational. */
166
+ readonly v10Specs?: V10SpecsScanResult;
167
+ }
168
+ /** Plan to refuse, with a structured cause and the diagnostic the
169
+ * shell should emit. */
170
+ export interface RefusePlan {
171
+ readonly kind: 'refuse';
172
+ readonly cause: PlanRefusalCause;
173
+ readonly diagnostic: Diagnostic;
174
+ /** Detection result that informed the refusal, when applicable. */
175
+ readonly detection?: EventsLogShape;
176
+ /** v10-spec scan result, when the refusal was triggered by it. */
177
+ readonly v10Specs?: V10SpecsScanResult;
178
+ }
179
+ export type RotationPlan = RotatePlan | RefusePlan;
180
+ /**
181
+ * Compose a deterministic rotation plan from a previously-detected
182
+ * events-log shape plus operator policy. Pure: no I/O, no clock access
183
+ * (the caller supplies opts.now).
184
+ *
185
+ * The planner is structurally consistent with rotateEvents's refusal
186
+ * logic in events-store.ts — same conditions, same diagnostic rules
187
+ * (sourced from STORE_RULES not from MIGRATION_RULES, so a `rotate
188
+ * --apply` later that goes through rotateEvents will emit the same
189
+ * rule ids). The migration command can therefore present a dry-run
190
+ * plan that exactly mirrors what would happen at apply time.
191
+ *
192
+ * Order of refusal checks (highest precedence first):
193
+ * 1. unparseable_only — nothing to rotate; the log is corrupt
194
+ * and the operator must inspect before any archiving.
195
+ * 2. partial_corruption — some unparseable lines alongside
196
+ * parseable ones; chain_rotated payload cannot honestly label
197
+ * this case. Mirrors STORE_RULES.EVENTS_ROTATE_PARTIAL_CORRUPTION
198
+ * in rotateEvents. No friction-flag escape in v11.2 scope.
199
+ * 3. v10_specs_present — half-upgrade refusal; requires
200
+ * allowPartialUpgrade.
201
+ * 4. clean_chain (all_v11) — friction flag; requires allowClean.
202
+ *
203
+ * If all checks pass, returns RotatePlan with the proposed archive
204
+ * name and the inputs the shell will pass to rotateEvents.
205
+ */
206
+ export declare function planEventsRotation(detection: EventsLogShape, opts: PlanOptions): RotationPlan;
207
+ //# sourceMappingURL=events-migration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events-migration.d.ts","sourceRoot":"","sources":["../../src/store/events-migration.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,358 @@
1
+ "use strict";
2
+ // Pure migration module for v10→v11 events.jsonl rotation
3
+ // (CAWS-MIGRATE-V10-EVENTS-001 A9).
4
+ //
5
+ // This module contains zero filesystem I/O and zero shell parsing. It
6
+ // classifies a raw events.jsonl payload, gathers actor-shape stats and
7
+ // tail metadata, and produces a deterministic rotation plan. The shell
8
+ // reads files, calls into this module, prints the plan, and (on --apply)
9
+ // invokes rotateEvents in events-store.ts. The shell is the only layer
10
+ // that touches `.caws/`.
11
+ //
12
+ // This mirrors the worktrees-migration.ts precedent: pure detector +
13
+ // pure planner + shell-does-IO. Refer to worktrees-migration.ts for the
14
+ // canonical pattern.
15
+ //
16
+ // Note on validation: detectEventsLogShape NEVER calls validateChainedEvent.
17
+ // Calling the strict validator on a v10 line is the exact failure mode
18
+ // this slice exists to repair (the v11 envelope shape rejects every line
19
+ // where actor is a string). The detector parses each line with JSON.parse
20
+ // defensively and classifies actor shape by direct type inspection. See
21
+ // docs/architecture/caws-vnext-command-surface.md invariant 14 and the
22
+ // rotateEvents tolerant-scan helper in events-store.ts.
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.MIGRATION_RULES = void 0;
25
+ exports.detectEventsLogShape = detectEventsLogShape;
26
+ exports.detectV10SpecsPresent = detectV10SpecsPresent;
27
+ exports.planEventsRotation = planEventsRotation;
28
+ const caws_kernel_1 = require("@paths.design/caws-kernel");
29
+ const caws_kernel_2 = require("@paths.design/caws-kernel");
30
+ // ---------------------------------------------------------------------------
31
+ // Migration-local rule constants
32
+ //
33
+ // These rules are local to the migration surface and named with the
34
+ // `store.events.migration.*` prefix. They are emitted only by this
35
+ // module and by the shell command that invokes it (A10).
36
+ // ---------------------------------------------------------------------------
37
+ exports.MIGRATION_RULES = {
38
+ /** events.jsonl could not be JSON-parsed at all; every line failed. */
39
+ UNPARSEABLE_INPUT: 'store.events.migration.unparseable_input',
40
+ /** events.jsonl is empty; there is nothing to migrate or rotate. */
41
+ EMPTY_INPUT: 'store.events.migration.empty_input',
42
+ /** A v10-shape spec YAML was detected during half-upgrade scan. */
43
+ V10_SPEC_DETECTED: 'store.events.migration.v10_spec_detected',
44
+ /** events.jsonl has SOME unparseable lines alongside parseable ones.
45
+ * The chain_rotated payload's prior_chain_status enum has no honest
46
+ * label for this case (parseable_unverified implies every line
47
+ * parsed; unparseable implies none did), so the planner refuses.
48
+ * Mirrors STORE_RULES.EVENTS_ROTATE_PARTIAL_CORRUPTION in rotateEvents
49
+ * so dry-run and apply paths agree. */
50
+ PARTIAL_CORRUPTION_REFUSED: 'store.events.migration.partial_corruption_refused',
51
+ /** The shell could not scan .caws/specs/ for v10-shape YAMLs (directory
52
+ * missing, unreadable, or sparse-checkout-excluded). The half-upgrade
53
+ * refusal CANNOT be enforced without a complete scan, so the migration
54
+ * command refuses by default rather than silently bypass the guard.
55
+ * No friction-flag escape in v11.2 scope. */
56
+ SPEC_SCAN_UNAVAILABLE: 'store.events.migration.spec_scan_unavailable',
57
+ /** Bug-class assertion: dry-run reported an archive name X and the
58
+ * apply path (rotateEvents) returned a different archive name Y.
59
+ * This indicates the dry-run's now-clock and the apply's now-clock
60
+ * drifted, or windowsSafeIso diverged between events-migration.ts
61
+ * and events-store.ts. Either way it is a programmer error, not an
62
+ * operator error; the shell surfaces it as an internal failure. */
63
+ INTERNAL_DRYRUN_APPLY_MISMATCH: 'store.events.migration.internal_dryrun_apply_mismatch',
64
+ /** events migrate refused because the underlying log is fully
65
+ * unparseable. Migration cannot claim it found a v10 chain. The
66
+ * lower-level `caws events rotate` may still archive a fully
67
+ * unparseable log under the honest 'unparseable' status as evidence
68
+ * quarantine — that semantic is intentional and distinct from
69
+ * migration. */
70
+ MIGRATE_UNPARSEABLE_REFUSED: 'store.events.migration.unparseable_refused',
71
+ /** verify-archive: events.jsonl exists but contains no chain_rotated
72
+ * event. There is nothing to verify against. */
73
+ VERIFY_NO_ROTATION_EVENT: 'store.events.verify_archive.no_rotation_event',
74
+ /** verify-archive: the archive file named by the most recent
75
+ * chain_rotated event does not exist on disk. */
76
+ VERIFY_ARCHIVE_MISSING: 'store.events.verify_archive.archive_missing',
77
+ /** verify-archive: the current events.jsonl could not be loaded
78
+ * (e.g., malformed JSON line, invalid chain). The shell cannot
79
+ * determine the most recent chain_rotated event. */
80
+ VERIFY_CURRENT_CHAIN_INVALID: 'store.events.verify_archive.current_chain_invalid',
81
+ };
82
+ /**
83
+ * Classify the actor-shape of every non-empty line in a raw events.jsonl
84
+ * payload. Pure: takes the file contents as a string, returns the
85
+ * detection result. No filesystem access.
86
+ *
87
+ * Errors:
88
+ * - returns Err for an empty input. The shell treats this as "nothing
89
+ * to do" rather than a hard error — the same condition rotateEvents
90
+ * refuses on, so the migration command can short-circuit before
91
+ * calling into the store.
92
+ *
93
+ * The detector deliberately does NOT call validateChainedEvent: the
94
+ * whole point of this slice is to handle v10-shape lines that the
95
+ * strict validator rejects. JSON.parse + direct actor-shape inspection
96
+ * is the entire contract.
97
+ */
98
+ function detectEventsLogShape(raw) {
99
+ const trailingNewline = raw.endsWith('\n');
100
+ const parts = raw.split('\n');
101
+ const lines = trailingNewline ? parts.slice(0, -1) : parts;
102
+ const nonEmpty = lines.filter((l) => l.length > 0);
103
+ if (nonEmpty.length === 0) {
104
+ return (0, caws_kernel_2.err)((0, caws_kernel_1.diagnostic)({
105
+ rule: exports.MIGRATION_RULES.EMPTY_INPUT,
106
+ authority: 'kernel/diagnostics',
107
+ message: 'events.jsonl is empty; nothing to migrate. rotateEvents refuses on the same condition (EVENTS_ROTATE_NOTHING_TO_ROTATE).',
108
+ }));
109
+ }
110
+ let v10 = 0;
111
+ let v11 = 0;
112
+ let bad = 0;
113
+ let tailHash = null;
114
+ let tailSeq = null;
115
+ for (let i = 0; i < nonEmpty.length; i++) {
116
+ const line = nonEmpty[i];
117
+ let parsed;
118
+ try {
119
+ parsed = JSON.parse(line);
120
+ }
121
+ catch {
122
+ bad += 1;
123
+ continue;
124
+ }
125
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
126
+ bad += 1;
127
+ continue;
128
+ }
129
+ const obj = parsed;
130
+ const actor = obj['actor'];
131
+ if (typeof actor === 'string') {
132
+ v10 += 1;
133
+ }
134
+ else if (actor !== null &&
135
+ typeof actor === 'object' &&
136
+ !Array.isArray(actor) &&
137
+ typeof actor['kind'] === 'string') {
138
+ v11 += 1;
139
+ }
140
+ else {
141
+ bad += 1;
142
+ }
143
+ if (i === nonEmpty.length - 1) {
144
+ const eh = obj['event_hash'];
145
+ if (typeof eh === 'string' && /^sha256:[0-9a-f]{64}$/.test(eh)) {
146
+ tailHash = eh;
147
+ }
148
+ const sq = obj['seq'];
149
+ if (typeof sq === 'number' && Number.isInteger(sq) && sq >= 1) {
150
+ tailSeq = sq;
151
+ }
152
+ }
153
+ }
154
+ const kind = classifyKind(v10, v11, bad);
155
+ return (0, caws_kernel_2.ok)({
156
+ kind,
157
+ stats: { v10_string_actor: v10, v11_object_actor: v11, unparseable: bad },
158
+ lineCount: nonEmpty.length,
159
+ tailHash,
160
+ tailSeq,
161
+ });
162
+ }
163
+ function classifyKind(v10, v11, bad) {
164
+ const totalParseable = v10 + v11;
165
+ if (totalParseable === 0 && bad > 0)
166
+ return 'unparseable_only';
167
+ if (v10 > 0 && v11 > 0)
168
+ return 'mixed_v10_v11';
169
+ if (v10 > 0)
170
+ return 'all_v10';
171
+ // v11 > 0 with no v10. We allow unparseable to coexist (rare crash
172
+ // recovery line) and still report 'all_v11' — the planner's clean-chain
173
+ // check explicitly excludes unparseable > 0 from triggering the friction
174
+ // flag, mirroring rotateEvents's isCleanV11 condition in events-store.ts.
175
+ if (v11 > 0)
176
+ return 'all_v11';
177
+ // No parseable lines and no unparseable lines reaches here only if the
178
+ // input was empty, which the caller handled before classifyKind ran.
179
+ return 'unparseable_only';
180
+ }
181
+ /**
182
+ * Minimal v10-vs-v11 spec YAML scanner. Used by the events migrate
183
+ * command to enforce the half-upgrade refusal (A10): if v10-shape spec
184
+ * YAMLs exist alongside v10 events, the operator must either run the
185
+ * specs migration first or explicitly pass --allow-partial-upgrade.
186
+ *
187
+ * Classification heuristic (per the spec's A10 invariant — "the check
188
+ * is mechanical: scan .caws/specs/*.yaml for v10 top-level keys (type,
189
+ * status, acceptance_criteria) and refuse if any are found"):
190
+ *
191
+ * - v10: file contains any of the top-level keys `type:`, `status:`,
192
+ * or `acceptance_criteria:` at column 0.
193
+ * - v11: file contains any of the top-level keys `mode:`,
194
+ * `lifecycle_state:`, or `acceptance:` at column 0, AND none of
195
+ * the v10 keys.
196
+ * - unclassified: no signal in either direction (e.g., empty file,
197
+ * comment-only file, malformed YAML).
198
+ *
199
+ * This is a regex-level scan, not a full YAML parse. Deliverable 2
200
+ * (CAWS-MIGRATE-V10-SPECS-001) may replace it with detectSpecVersion
201
+ * from packages/caws-kernel/src/spec/migrate-v10.ts when that ships,
202
+ * but the refusal contract owned by this slice (A10) is named here.
203
+ */
204
+ function detectV10SpecsPresent(files) {
205
+ const v10Paths = [];
206
+ const v11Paths = [];
207
+ const unclassifiedPaths = [];
208
+ const V10_KEY = /^(?:type|status|acceptance_criteria):/m;
209
+ const V11_KEY = /^(?:mode|lifecycle_state|acceptance):/m;
210
+ for (const file of files) {
211
+ const hasV10 = V10_KEY.test(file.raw);
212
+ const hasV11 = V11_KEY.test(file.raw);
213
+ if (hasV10) {
214
+ // Any v10 signal wins, even if v11 keys also appear (mixed-shape
215
+ // spec is itself a problem the specs migration owns).
216
+ v10Paths.push(file.path);
217
+ }
218
+ else if (hasV11) {
219
+ v11Paths.push(file.path);
220
+ }
221
+ else {
222
+ unclassifiedPaths.push(file.path);
223
+ }
224
+ }
225
+ return {
226
+ detected: v10Paths.length > 0,
227
+ v10Paths,
228
+ v11Paths,
229
+ unclassifiedPaths,
230
+ };
231
+ }
232
+ const ARCHIVE_PREFIX = 'events.jsonl.archive-';
233
+ /**
234
+ * Compose a deterministic rotation plan from a previously-detected
235
+ * events-log shape plus operator policy. Pure: no I/O, no clock access
236
+ * (the caller supplies opts.now).
237
+ *
238
+ * The planner is structurally consistent with rotateEvents's refusal
239
+ * logic in events-store.ts — same conditions, same diagnostic rules
240
+ * (sourced from STORE_RULES not from MIGRATION_RULES, so a `rotate
241
+ * --apply` later that goes through rotateEvents will emit the same
242
+ * rule ids). The migration command can therefore present a dry-run
243
+ * plan that exactly mirrors what would happen at apply time.
244
+ *
245
+ * Order of refusal checks (highest precedence first):
246
+ * 1. unparseable_only — nothing to rotate; the log is corrupt
247
+ * and the operator must inspect before any archiving.
248
+ * 2. partial_corruption — some unparseable lines alongside
249
+ * parseable ones; chain_rotated payload cannot honestly label
250
+ * this case. Mirrors STORE_RULES.EVENTS_ROTATE_PARTIAL_CORRUPTION
251
+ * in rotateEvents. No friction-flag escape in v11.2 scope.
252
+ * 3. v10_specs_present — half-upgrade refusal; requires
253
+ * allowPartialUpgrade.
254
+ * 4. clean_chain (all_v11) — friction flag; requires allowClean.
255
+ *
256
+ * If all checks pass, returns RotatePlan with the proposed archive
257
+ * name and the inputs the shell will pass to rotateEvents.
258
+ */
259
+ function planEventsRotation(detection, opts) {
260
+ // 1. unparseable_only — refuse outright; rotation here would archive
261
+ // a corrupt chain without operator inspection. The shell points
262
+ // at the file and asks the operator what to do.
263
+ if (detection.kind === 'unparseable_only') {
264
+ return {
265
+ kind: 'refuse',
266
+ cause: 'unparseable_only',
267
+ diagnostic: (0, caws_kernel_1.diagnostic)({
268
+ rule: exports.MIGRATION_RULES.UNPARSEABLE_INPUT,
269
+ authority: 'kernel/diagnostics',
270
+ message: `events.jsonl has no JSON-parseable lines (${detection.stats.unparseable} unparseable, ${detection.lineCount} total). Inspect the file before rotation; manual recovery may be required.`,
271
+ }),
272
+ detection,
273
+ };
274
+ }
275
+ // 2. partial_corruption — some unparseable lines exist alongside
276
+ // parseable ones. The chain_rotated payload's prior_chain_status
277
+ // enum has no honest label for this case ('parseable_unverified'
278
+ // implies every line parsed; 'unparseable' implies none did).
279
+ // Refuse rather than archive a partially-corrupt log under a
280
+ // misleading status. Mirrors rotateEvents's same-named refusal
281
+ // so dry-run and apply paths agree exactly. No friction-flag
282
+ // escape in v11.2 scope; a future opt-in path may be added
283
+ // alongside a new 'partially_unparseable' enum value in a
284
+ // later slice.
285
+ if (detection.stats.unparseable > 0 &&
286
+ detection.stats.unparseable < detection.lineCount) {
287
+ const parseable = detection.stats.v10_string_actor + detection.stats.v11_object_actor;
288
+ return {
289
+ kind: 'refuse',
290
+ cause: 'partial_corruption',
291
+ diagnostic: (0, caws_kernel_1.diagnostic)({
292
+ rule: exports.MIGRATION_RULES.PARTIAL_CORRUPTION_REFUSED,
293
+ authority: 'kernel/diagnostics',
294
+ message: `events.jsonl has ${detection.stats.unparseable} unparseable line(s) alongside ${parseable} parseable line(s) (${detection.lineCount} total). Mixed parseable + unparseable cannot be honestly labeled by the chain_rotated payload. Inspect the file and recover manually, or remove the corrupt lines before retrying.`,
295
+ narrowRepair: 'Open events.jsonl, identify the unparseable line(s) (often a truncated/crash-recovery tail), and either restore them or remove them. Re-run after the file has only parseable JSON lines.',
296
+ }),
297
+ detection,
298
+ };
299
+ }
300
+ // 3. Half-upgrade refusal. The planner only fires this when the
301
+ // caller has supplied a v10Specs scan AND detected: true. The
302
+ // contract is "if you scanned and found v10 specs, the planner
303
+ // enforces; if you didn't scan, the planner trusts you."
304
+ if (opts.v10Specs?.detected === true &&
305
+ opts.allowPartialUpgrade !== true) {
306
+ return {
307
+ kind: 'refuse',
308
+ cause: 'v10_specs_require_allow_partial_upgrade',
309
+ diagnostic: (0, caws_kernel_1.diagnostic)({
310
+ rule: exports.MIGRATION_RULES.V10_SPEC_DETECTED,
311
+ authority: 'kernel/diagnostics',
312
+ message: `events migrate --apply refuses: ${opts.v10Specs.v10Paths.length} v10-shape spec(s) detected (${opts.v10Specs.v10Paths.join(', ')}). Run 'caws specs migrate --from v10 --dry-run' first or pass --allow-partial-upgrade.`,
313
+ narrowRepair: "Run 'caws specs migrate --from v10' to migrate specs first, then re-run 'caws events migrate --apply'. If you intentionally want the events log to migrate ahead of specs, pass --allow-partial-upgrade.",
314
+ }),
315
+ detection,
316
+ v10Specs: opts.v10Specs,
317
+ };
318
+ }
319
+ // 4. Clean v11 chain friction flag. Mirrors rotateEvents's isCleanV11
320
+ // check in events-store.ts so dry-run and apply agree.
321
+ const isCleanV11 = detection.kind === 'all_v11' &&
322
+ detection.stats.v10_string_actor === 0 &&
323
+ detection.stats.unparseable === 0 &&
324
+ detection.stats.v11_object_actor > 0;
325
+ if (isCleanV11 && opts.allowClean !== true) {
326
+ return {
327
+ kind: 'refuse',
328
+ cause: 'clean_chain_requires_allow_clean',
329
+ diagnostic: (0, caws_kernel_1.diagnostic)({
330
+ rule: 'store.events.rotate.clean_chain_requires_allow_clean',
331
+ authority: 'kernel/diagnostics',
332
+ message: `rotateEvents would refuse: prior chain is a clean v11 chain (${detection.stats.v11_object_actor} structured actors); pass allowClean: true (CLI: --allow-clean) to rotate it anyway.`,
333
+ narrowRepair: 'If you intend to rotate a healthy v11 chain (e.g., for operational reasons unrelated to migration), pass --allow-clean. Otherwise, no rotation is needed.',
334
+ }),
335
+ detection,
336
+ };
337
+ }
338
+ // All checks passed. Compose the rotate plan.
339
+ return {
340
+ kind: 'rotate',
341
+ reason: opts.reason,
342
+ allowClean: opts.allowClean === true,
343
+ now: opts.now,
344
+ proposedArchiveName: `${ARCHIVE_PREFIX}${windowsSafeIso(opts.now)}`,
345
+ detection,
346
+ ...(opts.v10Specs !== undefined ? { v10Specs: opts.v10Specs } : {}),
347
+ };
348
+ }
349
+ /**
350
+ * Windows-safe ISO timestamp for archive filenames. Replaces both ':'
351
+ * and '.' with '-' so the archive name is filesystem-safe everywhere.
352
+ * Must match events-store.ts windowsSafeIso exactly so the planner's
353
+ * proposedArchiveName matches what rotateEvents will actually use.
354
+ */
355
+ function windowsSafeIso(d) {
356
+ return d.toISOString().replace(/:/g, '-').replace(/\./g, '-');
357
+ }
358
+ //# sourceMappingURL=events-migration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events-migration.js","sourceRoot":"","sources":["../../src/store/events-migration.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { type ChainedEvent, type EventBody, type Result } from '@paths.design/caws-kernel';
1
+ import { type Actor, type ChainedEvent, type EventBody, type Result } from '@paths.design/caws-kernel';
2
2
  import type { EventsLoadResult } from './types';
3
3
  /**
4
4
  * Load events from `.caws/events.jsonl`.
@@ -30,4 +30,50 @@ export declare function loadEvents(cawsDir: string): Result<EventsLoadResult>;
30
30
  * authority.
31
31
  */
32
32
  export declare function appendEvent(cawsDir: string, body: EventBody): Result<ChainedEvent>;
33
+ export interface RotateEventsOptions {
34
+ /**
35
+ * Operator-supplied reason recorded verbatim into chain_rotated.data.
36
+ * migration_reason. Required for every rotate invocation regardless of
37
+ * chain shape; see CAWS-MIGRATE-V10-EVENTS-001 A6/A8.
38
+ */
39
+ readonly reason: string;
40
+ /**
41
+ * Actor to attribute the chain_rotated event to. The kernel envelope
42
+ * requires a structured Actor; the shell command's buildActor() helper
43
+ * is the conventional source.
44
+ */
45
+ readonly actor: Actor;
46
+ /**
47
+ * Friction flag. When the prior chain has only structured (v11) actors,
48
+ * rotation is refused unless allowClean === true. Default false means
49
+ * rotation against a clean chain is treated as an operator slip; the
50
+ * caller must explicitly opt in to log rotation as a non-migration
51
+ * maintenance operation. See A8.
52
+ */
53
+ readonly allowClean?: boolean;
54
+ /**
55
+ * Override the wall-clock used for the archive timestamp. Tests inject
56
+ * a fixed Date; production omits this and the function uses new Date().
57
+ */
58
+ readonly now?: Date;
59
+ }
60
+ /**
61
+ * Rotate the events.jsonl chain: archive the existing file under a
62
+ * timestamped name and write a fresh chain whose genesis event is
63
+ * chain_rotated, cryptographically tying the archive to the new chain
64
+ * via prior_file_digest.
65
+ *
66
+ * Refusals (typed Diagnostic, no file mutations on any refusal path):
67
+ * - EVENTS_ROTATE_NOTHING_TO_ROTATE: file missing or zero-length.
68
+ * - EVENTS_ROTATE_CLEAN_CHAIN_REQUIRES_ALLOW_CLEAN: all entries are
69
+ * structured (v11) actors and allowClean !== true.
70
+ * - EVENTS_PREPARE_APPEND_REJECTED: the constructed chain_rotated body
71
+ * failed kernel validation (programmer error in this function or a
72
+ * schema change drift). Carries kernel diagnostics in data.source_rule.
73
+ * - WRITE_IO_FAILED: rename or genesis-write failed at the FS layer.
74
+ *
75
+ * On success returns the new ChainedEvent (the chain_rotated genesis event
76
+ * that is now the entirety of the new events.jsonl).
77
+ */
78
+ export declare function rotateEvents(cawsDir: string, opts: RotateEventsOptions): Result<ChainedEvent>;
33
79
  //# sourceMappingURL=events-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"events-store.d.ts","sourceRoot":"","sources":["../../src/store/events-store.ts"],"names":[],"mappings":"AAsBA,OAAO,EAML,KAAK,YAAY,EAEjB,KAAK,SAAS,EACd,KAAK,MAAM,EACZ,MAAM,2BAA2B,CAAC;AAGnC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAUhD;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAoBpE;AAoFD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,GACd,MAAM,CAAC,YAAY,CAAC,CAgEtB"}
1
+ {"version":3,"file":"events-store.d.ts","sourceRoot":"","sources":["../../src/store/events-store.ts"],"names":[],"mappings":"AAuBA,OAAO,EAML,KAAK,KAAK,EACV,KAAK,YAAY,EAEjB,KAAK,SAAS,EACd,KAAK,MAAM,EACZ,MAAM,2BAA2B,CAAC;AAGnC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAUhD;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAoBpE;AAoFD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,GACd,MAAM,CAAC,YAAY,CAAC,CAgEtB;AAoCD,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB;;;;;;OAMG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B;;;OAGG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,mBAAmB,GACxB,MAAM,CAAC,YAAY,CAAC,CA0MtB"}