@skillcap/gdh 0.23.0 → 0.24.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 (128) hide show
  1. package/INSTALL-BUNDLE.json +1 -1
  2. package/RELEASE-SPAN-UPDATE-CONTRACTS.json +64 -0
  3. package/node_modules/@gdh/adapters/dist/authoring-hook-render.d.ts.map +1 -1
  4. package/node_modules/@gdh/adapters/dist/authoring-hook-render.js +2 -1
  5. package/node_modules/@gdh/adapters/dist/authoring-hook-render.js.map +1 -1
  6. package/node_modules/@gdh/adapters/dist/claude-statusline-render.d.ts.map +1 -1
  7. package/node_modules/@gdh/adapters/dist/claude-statusline-render.js +2 -1
  8. package/node_modules/@gdh/adapters/dist/claude-statusline-render.js.map +1 -1
  9. package/node_modules/@gdh/adapters/dist/claude-update-hook-render.d.ts.map +1 -1
  10. package/node_modules/@gdh/adapters/dist/claude-update-hook-render.js +2 -1
  11. package/node_modules/@gdh/adapters/dist/claude-update-hook-render.js.map +1 -1
  12. package/node_modules/@gdh/adapters/dist/claude-update-worker-render.d.ts.map +1 -1
  13. package/node_modules/@gdh/adapters/dist/claude-update-worker-render.js +2 -1
  14. package/node_modules/@gdh/adapters/dist/claude-update-worker-render.js.map +1 -1
  15. package/node_modules/@gdh/adapters/dist/deferred-actions-advisory.d.ts +71 -0
  16. package/node_modules/@gdh/adapters/dist/deferred-actions-advisory.d.ts.map +1 -0
  17. package/node_modules/@gdh/adapters/dist/deferred-actions-advisory.js +89 -0
  18. package/node_modules/@gdh/adapters/dist/deferred-actions-advisory.js.map +1 -0
  19. package/node_modules/@gdh/adapters/dist/durable-backup.d.ts +209 -0
  20. package/node_modules/@gdh/adapters/dist/durable-backup.d.ts.map +1 -0
  21. package/node_modules/@gdh/adapters/dist/durable-backup.js +346 -0
  22. package/node_modules/@gdh/adapters/dist/durable-backup.js.map +1 -0
  23. package/node_modules/@gdh/adapters/dist/index.d.ts +10 -1
  24. package/node_modules/@gdh/adapters/dist/index.d.ts.map +1 -1
  25. package/node_modules/@gdh/adapters/dist/index.js +24 -2
  26. package/node_modules/@gdh/adapters/dist/index.js.map +1 -1
  27. package/node_modules/@gdh/adapters/dist/inventory-sweep.d.ts +53 -0
  28. package/node_modules/@gdh/adapters/dist/inventory-sweep.d.ts.map +1 -0
  29. package/node_modules/@gdh/adapters/dist/inventory-sweep.js +98 -0
  30. package/node_modules/@gdh/adapters/dist/inventory-sweep.js.map +1 -0
  31. package/node_modules/@gdh/adapters/dist/process-orchestration.d.ts +223 -0
  32. package/node_modules/@gdh/adapters/dist/process-orchestration.d.ts.map +1 -0
  33. package/node_modules/@gdh/adapters/dist/process-orchestration.js +368 -0
  34. package/node_modules/@gdh/adapters/dist/process-orchestration.js.map +1 -0
  35. package/node_modules/@gdh/adapters/dist/self-update-mechanics.d.ts +157 -14
  36. package/node_modules/@gdh/adapters/dist/self-update-mechanics.d.ts.map +1 -1
  37. package/node_modules/@gdh/adapters/dist/self-update-mechanics.js +570 -89
  38. package/node_modules/@gdh/adapters/dist/self-update-mechanics.js.map +1 -1
  39. package/node_modules/@gdh/adapters/dist/skill-rendering.d.ts.map +1 -1
  40. package/node_modules/@gdh/adapters/dist/skill-rendering.js +25 -0
  41. package/node_modules/@gdh/adapters/dist/skill-rendering.js.map +1 -1
  42. package/node_modules/@gdh/adapters/package.json +8 -8
  43. package/node_modules/@gdh/authoring/package.json +2 -2
  44. package/node_modules/@gdh/cli/dist/index.d.ts +9 -0
  45. package/node_modules/@gdh/cli/dist/index.d.ts.map +1 -1
  46. package/node_modules/@gdh/cli/dist/index.js +244 -2
  47. package/node_modules/@gdh/cli/dist/index.js.map +1 -1
  48. package/node_modules/@gdh/cli/dist/migrate.d.ts +152 -1
  49. package/node_modules/@gdh/cli/dist/migrate.d.ts.map +1 -1
  50. package/node_modules/@gdh/cli/dist/migrate.js +290 -6
  51. package/node_modules/@gdh/cli/dist/migrate.js.map +1 -1
  52. package/node_modules/@gdh/cli/dist/self-update.d.ts +14 -0
  53. package/node_modules/@gdh/cli/dist/self-update.d.ts.map +1 -1
  54. package/node_modules/@gdh/cli/dist/self-update.js +197 -15
  55. package/node_modules/@gdh/cli/dist/self-update.js.map +1 -1
  56. package/node_modules/@gdh/cli/package.json +10 -10
  57. package/node_modules/@gdh/core/dist/index.d.ts +97 -5
  58. package/node_modules/@gdh/core/dist/index.d.ts.map +1 -1
  59. package/node_modules/@gdh/core/dist/index.js +23 -5
  60. package/node_modules/@gdh/core/dist/index.js.map +1 -1
  61. package/node_modules/@gdh/core/dist/migrations/entries/s2c2_to_s2c3_rules_schema_v2_to_v3.d.ts +3 -0
  62. package/node_modules/@gdh/core/dist/migrations/entries/s2c2_to_s2c3_rules_schema_v2_to_v3.d.ts.map +1 -0
  63. package/node_modules/@gdh/core/dist/migrations/entries/s2c2_to_s2c3_rules_schema_v2_to_v3.js +247 -0
  64. package/node_modules/@gdh/core/dist/migrations/entries/s2c2_to_s2c3_rules_schema_v2_to_v3.js.map +1 -0
  65. package/node_modules/@gdh/core/dist/migrations/entries/s3c8_to_s3c9_register_runtime_bridge_autoload.d.ts +3 -0
  66. package/node_modules/@gdh/core/dist/migrations/entries/s3c8_to_s3c9_register_runtime_bridge_autoload.d.ts.map +1 -0
  67. package/node_modules/@gdh/core/dist/migrations/entries/s3c8_to_s3c9_register_runtime_bridge_autoload.js +152 -0
  68. package/node_modules/@gdh/core/dist/migrations/entries/s3c8_to_s3c9_register_runtime_bridge_autoload.js.map +1 -0
  69. package/node_modules/@gdh/core/dist/migrations/envelopes/envelope-output-validator.d.ts +3 -0
  70. package/node_modules/@gdh/core/dist/migrations/envelopes/envelope-output-validator.d.ts.map +1 -0
  71. package/node_modules/@gdh/core/dist/migrations/envelopes/envelope-output-validator.js +67 -0
  72. package/node_modules/@gdh/core/dist/migrations/envelopes/envelope-output-validator.js.map +1 -0
  73. package/node_modules/@gdh/core/dist/migrations/envelopes/index.d.ts +37 -0
  74. package/node_modules/@gdh/core/dist/migrations/envelopes/index.d.ts.map +1 -0
  75. package/node_modules/@gdh/core/dist/migrations/envelopes/index.js +60 -0
  76. package/node_modules/@gdh/core/dist/migrations/envelopes/index.js.map +1 -0
  77. package/node_modules/@gdh/core/dist/migrations/envelopes/types.d.ts +121 -0
  78. package/node_modules/@gdh/core/dist/migrations/envelopes/types.d.ts.map +1 -0
  79. package/node_modules/@gdh/core/dist/migrations/envelopes/types.js +2 -0
  80. package/node_modules/@gdh/core/dist/migrations/envelopes/types.js.map +1 -0
  81. package/node_modules/@gdh/core/dist/migrations/golden-harness.d.ts +40 -0
  82. package/node_modules/@gdh/core/dist/migrations/golden-harness.d.ts.map +1 -0
  83. package/node_modules/@gdh/core/dist/migrations/golden-harness.js +71 -0
  84. package/node_modules/@gdh/core/dist/migrations/golden-harness.js.map +1 -0
  85. package/node_modules/@gdh/core/dist/migrations/managed-surface-classes.d.ts +322 -0
  86. package/node_modules/@gdh/core/dist/migrations/managed-surface-classes.d.ts.map +1 -0
  87. package/node_modules/@gdh/core/dist/migrations/managed-surface-classes.js +384 -0
  88. package/node_modules/@gdh/core/dist/migrations/managed-surface-classes.js.map +1 -0
  89. package/node_modules/@gdh/core/dist/migrations/probes.d.ts +58 -0
  90. package/node_modules/@gdh/core/dist/migrations/probes.d.ts.map +1 -0
  91. package/node_modules/@gdh/core/dist/migrations/probes.js +112 -0
  92. package/node_modules/@gdh/core/dist/migrations/probes.js.map +1 -0
  93. package/node_modules/@gdh/core/dist/migrations/registry.d.ts +205 -0
  94. package/node_modules/@gdh/core/dist/migrations/registry.d.ts.map +1 -0
  95. package/node_modules/@gdh/core/dist/migrations/registry.js +214 -0
  96. package/node_modules/@gdh/core/dist/migrations/registry.js.map +1 -0
  97. package/node_modules/@gdh/core/dist/state/atomic-write.d.ts +19 -0
  98. package/node_modules/@gdh/core/dist/state/atomic-write.d.ts.map +1 -0
  99. package/node_modules/@gdh/core/dist/state/atomic-write.js +34 -0
  100. package/node_modules/@gdh/core/dist/state/atomic-write.js.map +1 -0
  101. package/node_modules/@gdh/core/dist/state/migration-state.d.ts +135 -0
  102. package/node_modules/@gdh/core/dist/state/migration-state.d.ts.map +1 -0
  103. package/node_modules/@gdh/core/dist/state/migration-state.js +186 -0
  104. package/node_modules/@gdh/core/dist/state/migration-state.js.map +1 -0
  105. package/node_modules/@gdh/core/dist/state/processes-snapshot.d.ts +72 -0
  106. package/node_modules/@gdh/core/dist/state/processes-snapshot.d.ts.map +1 -0
  107. package/node_modules/@gdh/core/dist/state/processes-snapshot.js +113 -0
  108. package/node_modules/@gdh/core/dist/state/processes-snapshot.js.map +1 -0
  109. package/node_modules/@gdh/core/dist/state/render-inventory.d.ts +54 -0
  110. package/node_modules/@gdh/core/dist/state/render-inventory.d.ts.map +1 -0
  111. package/node_modules/@gdh/core/dist/state/render-inventory.js +77 -0
  112. package/node_modules/@gdh/core/dist/state/render-inventory.js.map +1 -0
  113. package/node_modules/@gdh/core/package.json +1 -1
  114. package/node_modules/@gdh/docs/dist/agent-contract.d.ts.map +1 -1
  115. package/node_modules/@gdh/docs/dist/agent-contract.js +2 -1
  116. package/node_modules/@gdh/docs/dist/agent-contract.js.map +1 -1
  117. package/node_modules/@gdh/docs/dist/guidance.d.ts.map +1 -1
  118. package/node_modules/@gdh/docs/dist/guidance.js +3 -1
  119. package/node_modules/@gdh/docs/dist/guidance.js.map +1 -1
  120. package/node_modules/@gdh/docs/package.json +2 -2
  121. package/node_modules/@gdh/mcp/package.json +8 -8
  122. package/node_modules/@gdh/observability/package.json +2 -2
  123. package/node_modules/@gdh/runtime/dist/bridge-surface.js +63 -2
  124. package/node_modules/@gdh/runtime/dist/bridge-surface.js.map +1 -1
  125. package/node_modules/@gdh/runtime/package.json +2 -2
  126. package/node_modules/@gdh/scan/package.json +3 -3
  127. package/node_modules/@gdh/verify/package.json +7 -7
  128. package/package.json +11 -11
@@ -0,0 +1,205 @@
1
+ import type { GdhManagedSurfaceClass } from "./managed-surface-classes.js";
2
+ import type { GdhMigrationEnvelope } from "./envelopes/types.js";
3
+ /**
4
+ * Schema/agentContract pair that identifies a migration boundary.
5
+ * D-02: pair drives chain resolution; package version is presentation only.
6
+ */
7
+ export interface GdhMigrationVersionPair {
8
+ readonly schema: number;
9
+ readonly agentContract: number;
10
+ }
11
+ /**
12
+ * Result of a per-entry verify probe (D-05).
13
+ * Distinct from STA-03 deferred-action probes (those live in migration.json).
14
+ */
15
+ export type GdhMigrationEntryVerifyResult = {
16
+ readonly ok: true;
17
+ } | {
18
+ readonly ok: false;
19
+ readonly reason: string;
20
+ };
21
+ /**
22
+ * GDH migration registry entry (REG-01 / D-01).
23
+ *
24
+ * Each entry covers a single schema/agentContract pair transition.
25
+ * Append-only; no removal of historic entries within the supported range.
26
+ *
27
+ * The `transform` signature is filesystem-first per the walk-test consumer shape
28
+ * at tests/integration/migration-chain.test.ts:244-253. Per-entry golden tests
29
+ * adapt this to the file-map shape via runMigrationGolden.
30
+ */
31
+ export interface GdhMigrationEntry {
32
+ readonly id: string;
33
+ readonly from: GdhMigrationVersionPair;
34
+ readonly to: GdhMigrationVersionPair;
35
+ readonly classesTouched: readonly GdhManagedSurfaceClass[];
36
+ readonly transform: (targetPath: string) => Promise<void>;
37
+ readonly verify: (targetPath: string) => Promise<GdhMigrationEntryVerifyResult>;
38
+ /** Optional reference to a Phase 73 subagent envelope. Unused in Phase 72 (D-25). */
39
+ readonly envelope_ref?: string;
40
+ /**
41
+ * Per-release supplementary cleanup paths declared by this entry —
42
+ * workspace-relative POSIX paths the inventory sweep should delete in
43
+ * addition to set-diff orphans.
44
+ *
45
+ * Use sparingly: orphans normally come from manifest set-diff (the new
46
+ * render set vs the prior render-inventory.paths). This field is for
47
+ * targets OUTSIDE the rendered surface — e.g., orphaned MCP processes
48
+ * captured at registry-entry resolution time, or class-1 file drops the
49
+ * inventory-set-diff cannot derive.
50
+ *
51
+ * Validated by `isWorkspaceRelativePath` at sweep time (T-72-03-01); any
52
+ * candidate failing the check is skipped with a structured warning, never
53
+ * deleted. Per 72-CONTEXT.md "specifics" section.
54
+ */
55
+ readonly supplementaryDeletions?: readonly string[];
56
+ }
57
+ /**
58
+ * Validates a path is workspace-relative POSIX.
59
+ *
60
+ * Rejects:
61
+ * - empty string
62
+ * - absolute paths (starts with "/")
63
+ * - paths containing ".." segments
64
+ * - paths containing "" segments (double-slash)
65
+ * - paths containing null bytes
66
+ *
67
+ * Used to gate `supplementaryDeletions` and inventory-sweep delete targets
68
+ * against path traversal (T-72-03-01). Any candidate failing this check
69
+ * MUST be skipped by the sweep with a `path_traversal_blocked` reason.
70
+ */
71
+ export declare function isWorkspaceRelativePath(candidate: string): boolean;
72
+ /**
73
+ * Central migration registry (REG-01 / D-01).
74
+ *
75
+ * Ordered ascending by `from` pair (schema, then agentContract).
76
+ * Append-only across phases.
77
+ *
78
+ * D-09 (clarified by Phase 72 Plan 02 audit, see
79
+ * .planning/phases/72-migration-workflow-internals-registry-inventory-durable-back/72-02-AUDIT.md):
80
+ * the registry contains one entry per real class-2/3 schema/agent-contract
81
+ * bump in the supported version range. Bumps that produce no class-2/3
82
+ * work — i.e., the bump's user-visible effect is fully covered by
83
+ * deterministic class-1 re-render — are owned by
84
+ * `installSupportedAgentAdapters` re-bake at D-10 step 7 and are NOT
85
+ * represented in the registry. Adding identity-only entries for such
86
+ * bumps is the rejected "no-op identity entry" pattern: it would create
87
+ * a transform with no work and a verify probe with no shape to assert,
88
+ * masking real drift the chain matrix is meant to catch. Rollup
89
+ * mega-entries are also rejected (loses chain composition fidelity).
90
+ *
91
+ * Phase 72 Plan 02 populates this array with one entry
92
+ * (`entry_s2c2_to_s2c3_rules_schema`); the other three v0.18→HEAD bumps
93
+ * (s2c3→s2c6, s2c6→s2c7, s3c7→s3c8) are class-1-only per the audit and
94
+ * are intentionally absent.
95
+ */
96
+ export declare const MIGRATION_REGISTRY_ENTRIES: readonly [GdhMigrationEntry, GdhMigrationEntry];
97
+ /**
98
+ * Result of applyMigrationChain (D-06).
99
+ *
100
+ * Discriminated union following the project pattern in self-update-mechanics.ts.
101
+ *
102
+ * **Externalized rollback contract (WR-05).** This function does NOT roll back
103
+ * partial transform output on `verify_failed` or `transform_threw`. The
104
+ * `transform` step writes to disk BEFORE its own `verify` runs (and before the
105
+ * next entry's transform). When verify rejects, those writes persist on disk
106
+ * unchanged; the failed entry's intended-but-rejected state is also already
107
+ * partially or fully on disk on `transform_threw`. The `partialWriteOccurred`
108
+ * field on both failure variants is a typed reminder that the caller MUST
109
+ * either (a) restore from a durable backup taken before the chain ran (the
110
+ * pattern used by `bumpAndRebakePin`'s D-10 step 8a), or (b) accept the
111
+ * partial mutation. Standalone callers that consume `applyMigrationChain`
112
+ * without a durable backup MUST treat `partialWriteOccurred: true` as a
113
+ * cleanup obligation; ignoring it leaves the workspace in a half-applied
114
+ * state that the next chain run may verify-pass against (entries are
115
+ * idempotent) but which violates the all-or-nothing guarantee operators
116
+ * expect from migration tooling.
117
+ */
118
+ export type GdhApplyMigrationChainResult = {
119
+ readonly state: "applied";
120
+ readonly applied: readonly string[];
121
+ } | {
122
+ readonly state: "noop";
123
+ readonly applied: readonly string[];
124
+ } | {
125
+ readonly state: "verify_failed";
126
+ readonly failedEntryId: string;
127
+ readonly reason: string;
128
+ readonly applied: readonly string[];
129
+ /**
130
+ * WR-05: Always `true` on this variant — the failed entry's `transform`
131
+ * ran to completion before `verify` rejected, so its intended output is
132
+ * already on disk. Caller must restore from durable backup or accept
133
+ * the partial write.
134
+ */
135
+ readonly partialWriteOccurred: true;
136
+ } | {
137
+ readonly state: "transform_threw";
138
+ readonly failedEntryId: string;
139
+ readonly error: string;
140
+ readonly applied: readonly string[];
141
+ /**
142
+ * WR-05 / Phase 73: `true` when the entry's `transform` threw mid-execution
143
+ * (existing Phase 72 path) — an indeterminate amount of its intended output
144
+ * may already be on disk; caller must restore from durable backup or accept
145
+ * the partial write. `false` for Phase 73 synthetic envelope-resolution
146
+ * failures (`envelope_not_found`) where the gate trips BEFORE transform
147
+ * runs and nothing is on disk — bumpAndRebakePin still rolls back from the
148
+ * durable backup, but no partial chain output requires cleanup.
149
+ */
150
+ readonly partialWriteOccurred: boolean;
151
+ } | {
152
+ /** Phase 73 D-09: chain paused on an unresolved envelope_ref. */
153
+ readonly state: "needs_envelope";
154
+ readonly envelopeRef: string;
155
+ readonly envelope: GdhMigrationEnvelope;
156
+ readonly fromPair: GdhMigrationVersionPair;
157
+ readonly toPair: GdhMigrationVersionPair;
158
+ /** Entries already applied in this chain run before the pause. */
159
+ readonly applied: readonly string[];
160
+ };
161
+ /**
162
+ * applyMigrationChain — filter entries whose `from` >= fromPair AND `to` <= toPair,
163
+ * iterate in registry order, run transform then verify, halt on first failure.
164
+ *
165
+ * **Phase 73 envelope gate (D-09 / D-10).** When an entry declares
166
+ * `envelope_ref` (Phase 73), this function pauses BEFORE running its transform
167
+ * and returns a `needs_envelope` result so the calling agent can run the
168
+ * envelope (subagent or inline per D-05/D-06). On the resume run, if a
169
+ * recorded slot exists in `migration.json.envelopes[<envelope_ref>]` whose
170
+ * `(envelope_ref, from_pin, to_pin)` triple matches the current chain step
171
+ * (per `envelopePinContext`), the entry is treated as advanced (Phase 73
172
+ * records evidence only — Pitfall 7) and the chain continues. Stale slot
173
+ * (pin mismatch) → re-emit `needs_envelope`. Missing/unresolved envelope file
174
+ * → synthetic `transform_threw` with `envelope_not_found:` reason. Phase 72
175
+ * mechanical entries (envelope_ref undefined) skip this gate entirely.
176
+ *
177
+ * **Externalized rollback contract (WR-05).** This function does NOT roll back
178
+ * partial transform output. On `verify_failed`, the failed entry's transform
179
+ * ran to completion (writing to disk) before verify rejected. On
180
+ * `transform_threw`, an indeterminate amount of the failed entry's output may
181
+ * be on disk. In both cases the result carries `partialWriteOccurred: true`
182
+ * so callers cannot silently ignore the cleanup obligation. The integrated
183
+ * `bumpAndRebakePin` orchestrator restores from the durable backup at
184
+ * `.gdh-state/backup/` per Plan 72-08 D-10 step 8a. Standalone callers (the
185
+ * chain matrix walk-test, future direct invocations) that lack a durable
186
+ * backup MUST either implement an equivalent rollback or accept the partial
187
+ * mutation.
188
+ *
189
+ * The `entries` parameter exists for testability; production callers omit it
190
+ * and the default `MIGRATION_REGISTRY_ENTRIES` is used.
191
+ */
192
+ export declare function applyMigrationChain(targetPath: string, fromPair: GdhMigrationVersionPair, toPair: GdhMigrationVersionPair, entries?: readonly GdhMigrationEntry[],
193
+ /**
194
+ * Phase 73 (Plan 73-03): optional pin pair for D-10 envelope staleness
195
+ * comparison. When omitted (Phase 72 callers, the chain matrix walk-test),
196
+ * envelope-bearing entries are unreachable in the Phase 72 registry — the
197
+ * function still type-checks, but the envelope gate cannot validate
198
+ * `from_pin`/`to_pin` and fails closed (re-emits the envelope). Production
199
+ * callers (`bumpAndRebakePin` in Plan 73-04) always pass this argument.
200
+ */
201
+ envelopePinContext?: {
202
+ readonly fromPin: string;
203
+ readonly toPin: string;
204
+ }): Promise<GdhApplyMigrationChainResult>;
205
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/migrations/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,214 @@
1
+ import { entry_s2c2_to_s2c3 } from "./entries/s2c2_to_s2c3_rules_schema_v2_to_v3.js";
2
+ import { entry_s3c8_to_s3c9 } from "./entries/s3c8_to_s3c9_register_runtime_bridge_autoload.js";
3
+ import { resolveEnvelopeBySlug } from "./envelopes/index.js";
4
+ import { readMigrationState } from "../state/migration-state.js";
5
+ /**
6
+ * Validates a path is workspace-relative POSIX.
7
+ *
8
+ * Rejects:
9
+ * - empty string
10
+ * - absolute paths (starts with "/")
11
+ * - paths containing ".." segments
12
+ * - paths containing "" segments (double-slash)
13
+ * - paths containing null bytes
14
+ *
15
+ * Used to gate `supplementaryDeletions` and inventory-sweep delete targets
16
+ * against path traversal (T-72-03-01). Any candidate failing this check
17
+ * MUST be skipped by the sweep with a `path_traversal_blocked` reason.
18
+ */
19
+ export function isWorkspaceRelativePath(candidate) {
20
+ if (typeof candidate !== "string" || candidate.length === 0)
21
+ return false;
22
+ if (candidate.startsWith("/"))
23
+ return false;
24
+ if (candidate.includes("\0"))
25
+ return false;
26
+ const segments = candidate.split("/");
27
+ return !segments.some((s) => s === ".." || s === "");
28
+ }
29
+ /**
30
+ * Central migration registry (REG-01 / D-01).
31
+ *
32
+ * Ordered ascending by `from` pair (schema, then agentContract).
33
+ * Append-only across phases.
34
+ *
35
+ * D-09 (clarified by Phase 72 Plan 02 audit, see
36
+ * .planning/phases/72-migration-workflow-internals-registry-inventory-durable-back/72-02-AUDIT.md):
37
+ * the registry contains one entry per real class-2/3 schema/agent-contract
38
+ * bump in the supported version range. Bumps that produce no class-2/3
39
+ * work — i.e., the bump's user-visible effect is fully covered by
40
+ * deterministic class-1 re-render — are owned by
41
+ * `installSupportedAgentAdapters` re-bake at D-10 step 7 and are NOT
42
+ * represented in the registry. Adding identity-only entries for such
43
+ * bumps is the rejected "no-op identity entry" pattern: it would create
44
+ * a transform with no work and a verify probe with no shape to assert,
45
+ * masking real drift the chain matrix is meant to catch. Rollup
46
+ * mega-entries are also rejected (loses chain composition fidelity).
47
+ *
48
+ * Phase 72 Plan 02 populates this array with one entry
49
+ * (`entry_s2c2_to_s2c3_rules_schema`); the other three v0.18→HEAD bumps
50
+ * (s2c3→s2c6, s2c6→s2c7, s3c7→s3c8) are class-1-only per the audit and
51
+ * are intentionally absent.
52
+ */
53
+ export const MIGRATION_REGISTRY_ENTRIES = [
54
+ entry_s2c2_to_s2c3,
55
+ entry_s3c8_to_s3c9,
56
+ ];
57
+ /**
58
+ * Pair comparator: returns negative if a < b, zero if equal, positive if a > b.
59
+ * Schema is the major axis; agentContract is the minor axis.
60
+ */
61
+ function comparePair(a, b) {
62
+ if (a.schema !== b.schema)
63
+ return a.schema - b.schema;
64
+ return a.agentContract - b.agentContract;
65
+ }
66
+ /**
67
+ * D-10 staleness check (Phase 73). A recorded envelope slot is valid only when
68
+ * BOTH the slot's `from_pin` and `to_pin` match the chain step's bump pair.
69
+ * The slot is keyed by `envelope_ref` at the call site (the caller looks it up
70
+ * in `state.envelopes[entry.envelope_ref]`); this helper validates the
71
+ * remaining two axes of the (envelope_ref, from_pin, to_pin) triple.
72
+ *
73
+ * Pitfall 1 — defense in depth: the explicit pin-pair comparison is what
74
+ * stops a hand-edited `migration.json` slot whose pin pair targets a
75
+ * different chain step from silently advancing the current step.
76
+ */
77
+ function isEnvelopeRecordValid(slot, expected) {
78
+ return slot.from_pin === expected.from_pin && slot.to_pin === expected.to_pin;
79
+ }
80
+ /**
81
+ * applyMigrationChain — filter entries whose `from` >= fromPair AND `to` <= toPair,
82
+ * iterate in registry order, run transform then verify, halt on first failure.
83
+ *
84
+ * **Phase 73 envelope gate (D-09 / D-10).** When an entry declares
85
+ * `envelope_ref` (Phase 73), this function pauses BEFORE running its transform
86
+ * and returns a `needs_envelope` result so the calling agent can run the
87
+ * envelope (subagent or inline per D-05/D-06). On the resume run, if a
88
+ * recorded slot exists in `migration.json.envelopes[<envelope_ref>]` whose
89
+ * `(envelope_ref, from_pin, to_pin)` triple matches the current chain step
90
+ * (per `envelopePinContext`), the entry is treated as advanced (Phase 73
91
+ * records evidence only — Pitfall 7) and the chain continues. Stale slot
92
+ * (pin mismatch) → re-emit `needs_envelope`. Missing/unresolved envelope file
93
+ * → synthetic `transform_threw` with `envelope_not_found:` reason. Phase 72
94
+ * mechanical entries (envelope_ref undefined) skip this gate entirely.
95
+ *
96
+ * **Externalized rollback contract (WR-05).** This function does NOT roll back
97
+ * partial transform output. On `verify_failed`, the failed entry's transform
98
+ * ran to completion (writing to disk) before verify rejected. On
99
+ * `transform_threw`, an indeterminate amount of the failed entry's output may
100
+ * be on disk. In both cases the result carries `partialWriteOccurred: true`
101
+ * so callers cannot silently ignore the cleanup obligation. The integrated
102
+ * `bumpAndRebakePin` orchestrator restores from the durable backup at
103
+ * `.gdh-state/backup/` per Plan 72-08 D-10 step 8a. Standalone callers (the
104
+ * chain matrix walk-test, future direct invocations) that lack a durable
105
+ * backup MUST either implement an equivalent rollback or accept the partial
106
+ * mutation.
107
+ *
108
+ * The `entries` parameter exists for testability; production callers omit it
109
+ * and the default `MIGRATION_REGISTRY_ENTRIES` is used.
110
+ */
111
+ export async function applyMigrationChain(targetPath, fromPair, toPair, entries = MIGRATION_REGISTRY_ENTRIES,
112
+ /**
113
+ * Phase 73 (Plan 73-03): optional pin pair for D-10 envelope staleness
114
+ * comparison. When omitted (Phase 72 callers, the chain matrix walk-test),
115
+ * envelope-bearing entries are unreachable in the Phase 72 registry — the
116
+ * function still type-checks, but the envelope gate cannot validate
117
+ * `from_pin`/`to_pin` and fails closed (re-emits the envelope). Production
118
+ * callers (`bumpAndRebakePin` in Plan 73-04) always pass this argument.
119
+ */
120
+ envelopePinContext) {
121
+ const inRange = entries.filter((entry) => comparePair(entry.from, fromPair) >= 0 &&
122
+ comparePair(entry.to, toPair) <= 0);
123
+ const applied = [];
124
+ for (const entry of inRange) {
125
+ // ── Phase 73 envelope gate (D-09 / Pitfall 3 ordering invariant) ──
126
+ // MUST run BEFORE entry.transform: an unresolved envelope must not
127
+ // mutate disk. Phase 72 mechanical entries (envelope_ref undefined)
128
+ // skip this branch entirely.
129
+ if (entry.envelope_ref !== undefined) {
130
+ const envelope = resolveEnvelopeBySlug(entry.envelope_ref);
131
+ if (envelope === null) {
132
+ // Author bug: entry declares envelope_ref but no envelope file is
133
+ // registered in ENVELOPE_REGISTRY. Surface as transform_threw with
134
+ // the synthetic `envelope_not_found` reason so the existing rollback
135
+ // path applies (durable backup is intact at the bumpAndRebakePin
136
+ // layer); partialWriteOccurred=false because nothing was written.
137
+ return {
138
+ state: "transform_threw",
139
+ failedEntryId: entry.id,
140
+ error: `envelope_not_found: entry ${entry.id} declares envelope_ref="${entry.envelope_ref}" but no envelope file is registered`,
141
+ applied,
142
+ partialWriteOccurred: false,
143
+ };
144
+ }
145
+ const state = await readMigrationState(targetPath);
146
+ const recorded = state?.envelopes?.[entry.envelope_ref] ?? null;
147
+ const triple = envelopePinContext !== undefined
148
+ ? {
149
+ envelope_ref: entry.envelope_ref,
150
+ from_pin: envelopePinContext.fromPin,
151
+ to_pin: envelopePinContext.toPin,
152
+ }
153
+ : null;
154
+ const valid = recorded !== null &&
155
+ triple !== null &&
156
+ isEnvelopeRecordValid(recorded, triple) &&
157
+ // WR-01: only `output_contract.state === "apply"` advances the chain.
158
+ // `abort` and `needs_clarification` are recorded as evidence (Pitfall 7
159
+ // — record-only) but MUST NOT advance the chain past the entry, which
160
+ // would silently claim success for an envelope the agent declined or
161
+ // could not resolve. Re-emit needs_envelope so the operator can either
162
+ // re-record the envelope (after collecting clarification) or run
163
+ // `gdh migration clear-envelope <slug>` and re-attempt.
164
+ recorded.output_contract.state === "apply";
165
+ if (!valid) {
166
+ return {
167
+ state: "needs_envelope",
168
+ envelopeRef: entry.envelope_ref,
169
+ envelope,
170
+ fromPair: entry.from,
171
+ toPair: entry.to,
172
+ applied,
173
+ };
174
+ }
175
+ // Recorded result is valid for this triple AND output_contract.state is
176
+ // "apply". Phase 73 records evidence ONLY (Pitfall 7); the apply-consumer
177
+ // that mutates disk based on output_contract.changes is out of scope for
178
+ // v1.18 because no Phase 72 entry has envelope_ref set. Mark the entry
179
+ // as advanced and continue.
180
+ applied.push(entry.id);
181
+ continue;
182
+ }
183
+ // ── existing Phase 72 transform → verify path (unchanged) ──
184
+ try {
185
+ await entry.transform(targetPath);
186
+ }
187
+ catch (error) {
188
+ return {
189
+ state: "transform_threw",
190
+ failedEntryId: entry.id,
191
+ error: error instanceof Error ? error.message : String(error),
192
+ applied,
193
+ // WR-05: transform threw mid-execution; partial output may be on disk.
194
+ partialWriteOccurred: true,
195
+ };
196
+ }
197
+ const verifyResult = await entry.verify(targetPath);
198
+ if (!verifyResult.ok) {
199
+ return {
200
+ state: "verify_failed",
201
+ failedEntryId: entry.id,
202
+ reason: verifyResult.reason,
203
+ applied,
204
+ // WR-05: transform completed before verify rejected; output is on disk.
205
+ partialWriteOccurred: true,
206
+ };
207
+ }
208
+ applied.push(entry.id);
209
+ }
210
+ return inRange.length === 0
211
+ ? { state: "noop", applied: [] }
212
+ : { state: "applied", applied };
213
+ }
214
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/migrations/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Atomic write via temp-file + POSIX rename. POSIX rename is atomic on the
3
+ * same filesystem, which `.gdh-state/` placement guarantees. The temp file
4
+ * lives in the same directory as the destination so the rename is local.
5
+ *
6
+ * Source pattern: packages/runtime/src/bridge-broker.ts:721-733. Extracted
7
+ * here so plans 04 (backup manifest), 05 (migration-state), and 06
8
+ * (processes-snapshot) can reuse a single implementation instead of
9
+ * copy-pasting the helper into each writer.
10
+ *
11
+ * Failure semantics: on any failure during writeFile/rename, the temp file
12
+ * is removed (best-effort) and the original error rethrown. The destination
13
+ * file is never left in a half-written state — either the new content is
14
+ * fully visible at the destination path, or the destination is unchanged.
15
+ */
16
+ export declare function writeFileAtomic(filePath: string, content: string, options?: {
17
+ readonly mode?: number;
18
+ }): Promise<void>;
19
+ //# sourceMappingURL=atomic-write.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atomic-write.d.ts","sourceRoot":"","sources":["../../src/state/atomic-write.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;IAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GACvC,OAAO,CAAC,IAAI,CAAC,CAgBf"}
@@ -0,0 +1,34 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ /**
5
+ * Atomic write via temp-file + POSIX rename. POSIX rename is atomic on the
6
+ * same filesystem, which `.gdh-state/` placement guarantees. The temp file
7
+ * lives in the same directory as the destination so the rename is local.
8
+ *
9
+ * Source pattern: packages/runtime/src/bridge-broker.ts:721-733. Extracted
10
+ * here so plans 04 (backup manifest), 05 (migration-state), and 06
11
+ * (processes-snapshot) can reuse a single implementation instead of
12
+ * copy-pasting the helper into each writer.
13
+ *
14
+ * Failure semantics: on any failure during writeFile/rename, the temp file
15
+ * is removed (best-effort) and the original error rethrown. The destination
16
+ * file is never left in a half-written state — either the new content is
17
+ * fully visible at the destination path, or the destination is unchanged.
18
+ */
19
+ export async function writeFileAtomic(filePath, content, options = {}) {
20
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
21
+ const tempPath = path.join(path.dirname(filePath), `.${path.basename(filePath)}.${randomUUID()}.tmp`);
22
+ try {
23
+ await fs.writeFile(tempPath, content, { mode: options.mode });
24
+ if (options.mode !== undefined) {
25
+ await fs.chmod(tempPath, options.mode).catch(() => { });
26
+ }
27
+ await fs.rename(tempPath, filePath);
28
+ }
29
+ catch (error) {
30
+ await fs.rm(tempPath, { force: true }).catch(() => { });
31
+ throw error;
32
+ }
33
+ }
34
+ //# sourceMappingURL=atomic-write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atomic-write.js","sourceRoot":"","sources":["../../src/state/atomic-write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAgB,EAChB,OAAe,EACf,UAAsC,EAAE;IAExC,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CACxB,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EACtB,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,UAAU,EAAE,MAAM,CAClD,CAAC;IACF,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9D,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC/B,MAAM,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACzD,CAAC;QACD,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACtC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,EAAE,CAAC,EAAE,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACvD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,135 @@
1
+ import type { GdhMigrationEnvelopeOutput } from "../migrations/envelopes/types.js";
2
+ /**
3
+ * Path of the GDH migration-state envelope (D-12 / D-15 / D-16).
4
+ *
5
+ * Holds the post-rebake `last_applied_at` provenance and a typed
6
+ * `deferred_actions` list. Closed-kind `verify.kind` enum + structured
7
+ * `verify.payload` (no shell strings) eliminates the shell-injection
8
+ * surface called out in T-72-05-01.
9
+ */
10
+ export declare const MIGRATION_STATE_RELATIVE_PATH = ".gdh-state/migration.json";
11
+ /**
12
+ * Closed enumeration of probe statuses (D-12).
13
+ *
14
+ * - `pending`: probe ran but the deferred condition is not yet observed
15
+ * (host harness has not reloaded skill metadata, process not yet running).
16
+ * - `clean`: deferred condition observed; the action is satisfied.
17
+ * - `stale`: probe could not be run cleanly (unknown verify.kind, malformed
18
+ * payload, host threw). Treated as not-clean by the advisory gate.
19
+ */
20
+ export type GdhDeferredActionStatus = "pending" | "clean" | "stale";
21
+ /**
22
+ * Closed enumeration of verify dispatch kinds (D-12 / D-27).
23
+ *
24
+ * Adding a new kind requires showing GDH cannot perform the action with a
25
+ * precise file edit or process call (D-27 — bounded out-of-band action list).
26
+ */
27
+ export type GdhDeferredActionVerifyKind = "agent_skill_metadata_reload" | "process_restart";
28
+ /**
29
+ * Verify descriptor (D-12). `kind` selects the dispatch arm; `payload` carries
30
+ * the per-kind structured data the probe runner needs. There is no
31
+ * `verify_command` shell string — that field intentionally does NOT exist
32
+ * (T-72-05-01 mitigation).
33
+ */
34
+ export interface GdhDeferredActionVerify {
35
+ readonly kind: GdhDeferredActionVerifyKind;
36
+ readonly payload: Record<string, unknown>;
37
+ }
38
+ export interface GdhDeferredAction {
39
+ readonly id: string;
40
+ readonly description: string;
41
+ readonly verify: GdhDeferredActionVerify;
42
+ readonly status: GdhDeferredActionStatus;
43
+ /** Optional ISO timestamp of last probe run; informational only. */
44
+ readonly last_checked_at?: string;
45
+ }
46
+ export interface GdhMigrationStateAppliedAt {
47
+ readonly package: string;
48
+ readonly schema: number;
49
+ readonly agentContract: number;
50
+ }
51
+ /**
52
+ * One recorded-result attempt history entry (D-08). Same shape as a slot, minus
53
+ * the `attempts` field (history doesn't recurse).
54
+ */
55
+ export interface GdhMigrationEnvelopeAttempt {
56
+ readonly recorded_at: string;
57
+ readonly from_pin: string;
58
+ readonly to_pin: string;
59
+ readonly output_contract: GdhMigrationEnvelopeOutput;
60
+ }
61
+ /**
62
+ * Per-envelope-ref slot (D-08). One current slot per envelope; re-runs of
63
+ * `gdh migration record-envelope-result` append the prior slot's outer fields
64
+ * onto this slot's `attempts[]`.
65
+ */
66
+ export interface GdhMigrationEnvelopeSlot {
67
+ readonly recorded_at: string;
68
+ readonly from_pin: string;
69
+ readonly to_pin: string;
70
+ readonly output_contract: GdhMigrationEnvelopeOutput;
71
+ readonly attempts: readonly GdhMigrationEnvelopeAttempt[];
72
+ }
73
+ /**
74
+ * In-flight resume marker (D-11). Set atomically at the applyMigrationChain
75
+ * pause point (alongside the durable backup); cleared atomically when the
76
+ * chain advances past that envelope on resume. Mirrors Phase 72's receipt-
77
+ * before-cleanup discipline for processes-snapshot.json — the marker is the
78
+ * resume substrate, distinct from the migration.json success receipt.
79
+ */
80
+ export interface GdhPendingEnvelopeResumeMarker {
81
+ readonly envelope_ref: string;
82
+ readonly from_pin: string;
83
+ readonly to_pin: string;
84
+ }
85
+ /**
86
+ * Migration-state envelope (D-12).
87
+ *
88
+ * `migration_version` is `1` and locked; future shape changes require a new
89
+ * version number and a degraded-fallback path on read.
90
+ */
91
+ export interface GdhMigrationState {
92
+ readonly migration_version: 1;
93
+ readonly last_applied_at: GdhMigrationStateAppliedAt;
94
+ readonly deferred_actions: readonly GdhDeferredAction[];
95
+ /**
96
+ * D-08 — per-envelope-ref recorded-result evidence. Optional for backward
97
+ * read-compat: Phase 72-written migration.json files omit this field, and
98
+ * the schema guard treats `undefined` as "no recorded results."
99
+ */
100
+ readonly envelopes?: Readonly<Record<string, GdhMigrationEnvelopeSlot>>;
101
+ /**
102
+ * D-11 — in-flight resume marker. Set when applyMigrationChain pauses on an
103
+ * unresolved envelope_ref; cleared when bumpAndRebakePin advances past that
104
+ * envelope on resume. Optional for back-compat: absence reads as "no pending
105
+ * envelope."
106
+ */
107
+ readonly pending_envelope_resume?: GdhPendingEnvelopeResumeMarker;
108
+ }
109
+ /**
110
+ * Read the migration-state envelope if present.
111
+ *
112
+ * Returns null when missing, parse-failed, or schema-invalid (T-72-05-04
113
+ * mitigation: degraded fallback prevents corrupted manifest from crashing
114
+ * status). Caller treats null as "no prior state" and the advisory gate
115
+ * keeps `deferredActions: []` with `backupAdvisory: null`.
116
+ */
117
+ export declare function readMigrationState(targetPath: string): Promise<GdhMigrationState | null>;
118
+ /**
119
+ * Write the migration-state envelope atomically (D-15).
120
+ *
121
+ * Uses {@link writeFileAtomic} (temp-file + POSIX rename) so the destination
122
+ * is either the previous state or the new state — never half-written content
123
+ * if the process is interrupted between writeFile and rename.
124
+ */
125
+ export declare function writeMigrationState(targetPath: string, state: GdhMigrationState): Promise<void>;
126
+ /**
127
+ * Idempotent first-run bootstrap (D-16).
128
+ *
129
+ * Returns the existing state when present; otherwise returns a fresh empty
130
+ * envelope using `defaultLastAppliedAt`. Never throws — corrupted state files
131
+ * degrade to a fresh empty envelope so the caller can re-establish provenance
132
+ * at the next rebake.
133
+ */
134
+ export declare function bootstrapMigrationStateOrEmpty(targetPath: string, defaultLastAppliedAt: GdhMigrationStateAppliedAt): Promise<GdhMigrationState>;
135
+ //# sourceMappingURL=migration-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-state.d.ts","sourceRoot":"","sources":["../../src/state/migration-state.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AAEnF;;;;;;;GAOG;AACH,eAAO,MAAM,6BAA6B,8BAA8B,CAAC;AAEzE;;;;;;;;GAQG;AACH,MAAM,MAAM,uBAAuB,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAEpE;;;;;GAKG;AACH,MAAM,MAAM,2BAA2B,GACnC,6BAA6B,GAC7B,iBAAiB,CAAC;AAEtB;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,EAAE,2BAA2B,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,uBAAuB,CAAC;IACzC,QAAQ,CAAC,MAAM,EAAE,uBAAuB,CAAC;IACzC,oEAAoE;IACpE,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CACnC;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,eAAe,EAAE,0BAA0B,CAAC;CACtD;AAED;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,eAAe,EAAE,0BAA0B,CAAC;IACrD,QAAQ,CAAC,QAAQ,EAAE,SAAS,2BAA2B,EAAE,CAAC;CAC3D;AAED;;;;;;GAMG;AACH,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,iBAAiB,EAAE,CAAC,CAAC;IAC9B,QAAQ,CAAC,eAAe,EAAE,0BAA0B,CAAC;IACrD,QAAQ,CAAC,gBAAgB,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACxD;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC,CAAC;IACxE;;;;;OAKG;IACH,QAAQ,CAAC,uBAAuB,CAAC,EAAE,8BAA8B,CAAC;CACnE;AAmHD;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAYnC;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,iBAAiB,GACvB,OAAO,CAAC,IAAI,CAAC,CAGf;AAED;;;;;;;GAOG;AACH,wBAAsB,8BAA8B,CAClD,UAAU,EAAE,MAAM,EAClB,oBAAoB,EAAE,0BAA0B,GAC/C,OAAO,CAAC,iBAAiB,CAAC,CAQ5B"}