@deskwork/cli 0.9.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 (85) hide show
  1. package/dist/cli.d.ts +19 -0
  2. package/dist/cli.d.ts.map +1 -0
  3. package/dist/cli.js +98 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/commands/add.d.ts +13 -0
  6. package/dist/commands/add.d.ts.map +1 -0
  7. package/dist/commands/add.js +91 -0
  8. package/dist/commands/add.js.map +1 -0
  9. package/dist/commands/approve.d.ts +18 -0
  10. package/dist/commands/approve.d.ts.map +1 -0
  11. package/dist/commands/approve.js +179 -0
  12. package/dist/commands/approve.js.map +1 -0
  13. package/dist/commands/customize.d.ts +47 -0
  14. package/dist/commands/customize.d.ts.map +1 -0
  15. package/dist/commands/customize.js +176 -0
  16. package/dist/commands/customize.js.map +1 -0
  17. package/dist/commands/distribute.d.ts +30 -0
  18. package/dist/commands/distribute.d.ts.map +1 -0
  19. package/dist/commands/distribute.js +148 -0
  20. package/dist/commands/distribute.js.map +1 -0
  21. package/dist/commands/doctor.d.ts +35 -0
  22. package/dist/commands/doctor.d.ts.map +1 -0
  23. package/dist/commands/doctor.js +354 -0
  24. package/dist/commands/doctor.js.map +1 -0
  25. package/dist/commands/draft.d.ts +17 -0
  26. package/dist/commands/draft.d.ts.map +1 -0
  27. package/dist/commands/draft.js +77 -0
  28. package/dist/commands/draft.js.map +1 -0
  29. package/dist/commands/ingest.d.ts +43 -0
  30. package/dist/commands/ingest.d.ts.map +1 -0
  31. package/dist/commands/ingest.js +321 -0
  32. package/dist/commands/ingest.js.map +1 -0
  33. package/dist/commands/install-preflight.d.ts +83 -0
  34. package/dist/commands/install-preflight.d.ts.map +1 -0
  35. package/dist/commands/install-preflight.js +300 -0
  36. package/dist/commands/install-preflight.js.map +1 -0
  37. package/dist/commands/install.d.ts +27 -0
  38. package/dist/commands/install.d.ts.map +1 -0
  39. package/dist/commands/install.js +132 -0
  40. package/dist/commands/install.js.map +1 -0
  41. package/dist/commands/iterate.d.ts +33 -0
  42. package/dist/commands/iterate.d.ts.map +1 -0
  43. package/dist/commands/iterate.js +202 -0
  44. package/dist/commands/iterate.js.map +1 -0
  45. package/dist/commands/outline.d.ts +19 -0
  46. package/dist/commands/outline.d.ts.map +1 -0
  47. package/dist/commands/outline.js +102 -0
  48. package/dist/commands/outline.js.map +1 -0
  49. package/dist/commands/pause.d.ts +15 -0
  50. package/dist/commands/pause.d.ts.map +1 -0
  51. package/dist/commands/pause.js +70 -0
  52. package/dist/commands/pause.js.map +1 -0
  53. package/dist/commands/plan.d.ts +12 -0
  54. package/dist/commands/plan.d.ts.map +1 -0
  55. package/dist/commands/plan.js +74 -0
  56. package/dist/commands/plan.js.map +1 -0
  57. package/dist/commands/publish.d.ts +18 -0
  58. package/dist/commands/publish.d.ts.map +1 -0
  59. package/dist/commands/publish.js +105 -0
  60. package/dist/commands/publish.js.map +1 -0
  61. package/dist/commands/resume.d.ts +16 -0
  62. package/dist/commands/resume.d.ts.map +1 -0
  63. package/dist/commands/resume.js +70 -0
  64. package/dist/commands/resume.js.map +1 -0
  65. package/dist/commands/review-cancel.d.ts +15 -0
  66. package/dist/commands/review-cancel.d.ts.map +1 -0
  67. package/dist/commands/review-cancel.js +88 -0
  68. package/dist/commands/review-cancel.js.map +1 -0
  69. package/dist/commands/review-help.d.ts +12 -0
  70. package/dist/commands/review-help.d.ts.map +1 -0
  71. package/dist/commands/review-help.js +52 -0
  72. package/dist/commands/review-help.js.map +1 -0
  73. package/dist/commands/review-report.d.ts +13 -0
  74. package/dist/commands/review-report.d.ts.map +1 -0
  75. package/dist/commands/review-report.js +53 -0
  76. package/dist/commands/review-report.js.map +1 -0
  77. package/dist/commands/review-start.d.ts +17 -0
  78. package/dist/commands/review-start.d.ts.map +1 -0
  79. package/dist/commands/review-start.js +121 -0
  80. package/dist/commands/review-start.js.map +1 -0
  81. package/dist/commands/shortform-start.d.ts +33 -0
  82. package/dist/commands/shortform-start.d.ts.map +1 -0
  83. package/dist/commands/shortform-start.js +127 -0
  84. package/dist/commands/shortform-start.js.map +1 -0
  85. package/package.json +45 -0
@@ -0,0 +1,321 @@
1
+ /**
2
+ * deskwork ingest — backfill existing markdown content into the editorial
3
+ * calendar.
4
+ *
5
+ * Discovery is the heavy lifting; this module is the CLI surface around
6
+ * `discoverIngestCandidates` from @deskwork/core/ingest.
7
+ *
8
+ * Argv shape (after the dispatcher injects projectRoot when needed):
9
+ *
10
+ * <project-root> [flags] <path>...
11
+ *
12
+ * Flags:
13
+ * --site <slug> Target site (defaults to config.defaultSite)
14
+ * --apply Commit the plan; default is dry-run
15
+ * --json Machine-readable plan output
16
+ * --force Bypass duplicate-slug skip
17
+ * --slug-from <where> 'frontmatter' or 'path' (default 'path')
18
+ * --state-from <where> 'frontmatter' (default) or 'datePublished'
19
+ * --slug <value> Explicit slug (only with single-file ingest)
20
+ * --state <stage> Explicit stage; wins over derivation
21
+ * --date <YYYY-MM-DD> Explicit ISO date; wins over derivation
22
+ * --title-field <name> Frontmatter field for title (default: title)
23
+ * --description-field <n> Frontmatter field for description
24
+ * (default: description)
25
+ * --slug-field <name> Frontmatter field for slug (default: slug)
26
+ * --state-field <name> Frontmatter field for state (default: state)
27
+ * --date-field <name> Frontmatter field for date (default:
28
+ * datePublished)
29
+ *
30
+ * Dry-run output (text mode):
31
+ *
32
+ * Plan: 3 add, 1 skip
33
+ *
34
+ * add whats-in-a-name Published 2020-10-01 state:fm date:fm slug:path
35
+ * add the-deskwork-experiment Published 2026-04-20 state:fm date:fm slug:path
36
+ * skip on-revising-in-the-open already in calendar
37
+ *
38
+ * `--apply` writes calendar rows for non-skipped candidates and appends
39
+ * a journal entry per ingested file (`event: 'ingest'`) so a future
40
+ * review-start has provenance to anchor against.
41
+ */
42
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
43
+ import { isAbsolute, join, resolve } from 'node:path';
44
+ import { randomUUID } from 'node:crypto';
45
+ import { readConfig } from '@deskwork/core/config';
46
+ import { readCalendar, writeCalendar } from '@deskwork/core/calendar';
47
+ import { resolveSite, resolveCalendarPath, resolveContentDir } from '@deskwork/core/paths';
48
+ import { isStage } from '@deskwork/core/types';
49
+ import { absolutize, fail, parseArgs } from '@deskwork/core/cli-args';
50
+ import { appendJournal } from '@deskwork/core/journal';
51
+ import { updateFrontmatter } from '@deskwork/core/frontmatter';
52
+ import { candidateToEntry, discoverIngestCandidates, } from '@deskwork/core/ingest';
53
+ const KNOWN_FLAGS = [
54
+ 'site',
55
+ 'slug-from',
56
+ 'state-from',
57
+ 'slug',
58
+ 'state',
59
+ 'date',
60
+ 'title-field',
61
+ 'description-field',
62
+ 'slug-field',
63
+ 'state-field',
64
+ 'date-field',
65
+ ];
66
+ const BOOLEAN_FLAGS = ['apply', 'json', 'force', 'no-write-frontmatter'];
67
+ const DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
68
+ export async function run(argv) {
69
+ const { positional, flags, booleans } = parseInput(argv);
70
+ if (positional.length < 2) {
71
+ fail('Usage: deskwork ingest <project-root> [--site <slug>] [--apply] [--json] ' +
72
+ '[--force] [--no-write-frontmatter] ' +
73
+ '[--slug-from frontmatter|path] [--state-from frontmatter|datePublished] ' +
74
+ '[--slug <s>] [--state <stage>] [--date YYYY-MM-DD] [--title-field <n>] ' +
75
+ '[--description-field <n>] [--slug-field <n>] [--state-field <n>] ' +
76
+ '[--date-field <n>] <path>...', 2);
77
+ }
78
+ const [rootArg, ...paths] = positional;
79
+ const projectRoot = absolutize(rootArg);
80
+ const slugFrom = parseSlugFrom(flags['slug-from']);
81
+ const stateFrom = parseStateFrom(flags['state-from']);
82
+ const explicitState = parseExplicitState(flags.state);
83
+ const explicitDate = parseExplicitDate(flags.date);
84
+ let config;
85
+ try {
86
+ config = readConfig(projectRoot);
87
+ }
88
+ catch (err) {
89
+ fail(err instanceof Error ? err.message : String(err));
90
+ }
91
+ const site = resolveSite(config, flags.site);
92
+ const calendarPath = resolveCalendarPath(projectRoot, config, site);
93
+ const calendar = readCalendar(calendarPath);
94
+ // Build absolute path arguments. Relative paths resolve against
95
+ // the project root (not cwd) — the operator's mental model is
96
+ // "paths inside this project", and the dispatcher's cwd may differ
97
+ // from the project root in tests / scripted invocations.
98
+ const absolutePaths = paths.map((p) => isAbsolute(p) ? p : resolve(projectRoot, p));
99
+ // Compute scrapbook root for the resolved site so files under it
100
+ // are skipped by default (operators have to explicitly opt in to
101
+ // ingest a sketchpad — `deskwork ingest content/scrapbook/` works
102
+ // because absolutePaths goes through the scrapbook check on a
103
+ // file-by-file basis, not on the discovery root).
104
+ const contentDir = resolveContentDir(projectRoot, config, site);
105
+ const scrapbookRoots = [join(contentDir, 'scrapbook')];
106
+ let discovery;
107
+ try {
108
+ discovery = discoverIngestCandidates(absolutePaths, {
109
+ projectRoot,
110
+ ...(slugFrom !== undefined ? { slugFrom } : {}),
111
+ ...(stateFrom !== undefined ? { stateFrom } : {}),
112
+ ...(flags.slug !== undefined ? { explicitSlug: flags.slug } : {}),
113
+ ...(explicitState !== undefined ? { explicitState } : {}),
114
+ ...(explicitDate !== undefined ? { explicitDate } : {}),
115
+ fieldNames: buildFieldNames(flags),
116
+ calendar,
117
+ ...(booleans.has('force') ? { force: true } : {}),
118
+ scrapbookRoots,
119
+ });
120
+ }
121
+ catch (err) {
122
+ fail(err instanceof Error ? err.message : String(err), 2);
123
+ }
124
+ // Split candidates into actionable vs. ambiguous-state. Ambiguous
125
+ // ones don't get applied without an explicit --state — emit them
126
+ // as skips with an actionable reason.
127
+ const ambiguous = [];
128
+ const actionable = [];
129
+ for (const c of discovery.candidates) {
130
+ if (c.derivedState === null) {
131
+ ambiguous.push({
132
+ filePath: c.filePath,
133
+ relativePath: c.relativePath,
134
+ slug: c.derivedSlug,
135
+ reason: `state ambiguous (raw frontmatter value: "${c.rawState ?? ''}"); pass --state <stage> to commit`,
136
+ });
137
+ continue;
138
+ }
139
+ actionable.push({ candidate: c, stage: c.derivedState });
140
+ }
141
+ const allSkips = [...discovery.skips, ...ambiguous];
142
+ if (booleans.has('json')) {
143
+ emitJsonPlan({
144
+ apply: booleans.has('apply'),
145
+ site,
146
+ calendarPath,
147
+ add: actionable.map((a) => candidatePlanRecord(a.candidate, a.stage)),
148
+ skip: allSkips,
149
+ });
150
+ }
151
+ else {
152
+ emitTextPlan({
153
+ apply: booleans.has('apply'),
154
+ add: actionable,
155
+ skip: allSkips,
156
+ });
157
+ }
158
+ if (!booleans.has('apply'))
159
+ return;
160
+ const writeFrontmatterBinding = !booleans.has('no-write-frontmatter');
161
+ // Apply path: append entries and write journal records. The
162
+ // calendar is written once at the end so a partial run does not
163
+ // leave a torn calendar file. Issue #63: also persist the freshly-
164
+ // minted UUID into the source file's frontmatter under `deskwork.id`
165
+ // so the calendar entry isn't orphaned at creation (doctor was
166
+ // immediately flagging `missing-frontmatter-id` against every ingest).
167
+ for (const { candidate, stage } of actionable) {
168
+ const id = randomUUID();
169
+ const entry = { id, ...candidateToEntry(candidate, stage) };
170
+ calendar.entries.push(entry);
171
+ writeIngestJournalEntry(projectRoot, config, site, candidate, entry);
172
+ if (writeFrontmatterBinding) {
173
+ writeDeskworkIdToFile(candidate.filePath, id);
174
+ }
175
+ }
176
+ writeCalendar(calendarPath, calendar);
177
+ }
178
+ /**
179
+ * Patch the markdown file at `filePath` so its frontmatter includes
180
+ * `deskwork.id: <id>`. Round-trip-preserving (Issue #37): only the
181
+ * `deskwork:` namespace is touched; existing frontmatter fields keep
182
+ * their byte-for-byte formatting (quoting, comments, key order). When
183
+ * the file has no existing frontmatter, a fresh `---` block is
184
+ * prepended.
185
+ */
186
+ function writeDeskworkIdToFile(filePath, id) {
187
+ const original = readFileSync(filePath, 'utf-8');
188
+ const updated = updateFrontmatter(original, { deskwork: { id } });
189
+ if (updated !== original) {
190
+ writeFileSync(filePath, updated, 'utf-8');
191
+ }
192
+ }
193
+ // ---------------------------------------------------------------------------
194
+ // Argv parsing
195
+ // ---------------------------------------------------------------------------
196
+ function parseInput(argv) {
197
+ try {
198
+ return parseArgs(argv, KNOWN_FLAGS, BOOLEAN_FLAGS);
199
+ }
200
+ catch (err) {
201
+ fail(err instanceof Error ? err.message : String(err), 2);
202
+ }
203
+ }
204
+ function parseSlugFrom(value) {
205
+ if (value === undefined)
206
+ return undefined;
207
+ if (value !== 'frontmatter' && value !== 'path') {
208
+ fail(`--slug-from must be 'frontmatter' or 'path' (got "${value}")`, 2);
209
+ }
210
+ return value;
211
+ }
212
+ function parseStateFrom(value) {
213
+ if (value === undefined)
214
+ return undefined;
215
+ if (value !== 'frontmatter' && value !== 'datePublished') {
216
+ fail(`--state-from must be 'frontmatter' or 'datePublished' (got "${value}")`, 2);
217
+ }
218
+ return value;
219
+ }
220
+ function parseExplicitState(value) {
221
+ if (value === undefined)
222
+ return undefined;
223
+ // Accept the case-insensitive lane name as the operator types it.
224
+ const normalized = value.charAt(0).toUpperCase() + value.slice(1).toLowerCase();
225
+ if (!isStage(normalized)) {
226
+ fail(`--state must be one of Ideas, Planned, Outlining, Drafting, Review, Published ` +
227
+ `(got "${value}")`, 2);
228
+ }
229
+ return normalized;
230
+ }
231
+ function parseExplicitDate(value) {
232
+ if (value === undefined)
233
+ return undefined;
234
+ if (!DATE_RE.test(value)) {
235
+ fail(`--date must match YYYY-MM-DD (got "${value}")`, 2);
236
+ }
237
+ return value;
238
+ }
239
+ function buildFieldNames(flags) {
240
+ const out = {};
241
+ if (flags['title-field'] !== undefined)
242
+ out.title = flags['title-field'];
243
+ if (flags['description-field'] !== undefined)
244
+ out.description = flags['description-field'];
245
+ if (flags['slug-field'] !== undefined)
246
+ out.slug = flags['slug-field'];
247
+ if (flags['state-field'] !== undefined)
248
+ out.state = flags['state-field'];
249
+ if (flags['date-field'] !== undefined)
250
+ out.date = flags['date-field'];
251
+ return out;
252
+ }
253
+ function candidatePlanRecord(c, stage) {
254
+ return {
255
+ action: 'add',
256
+ slug: c.derivedSlug,
257
+ title: c.title,
258
+ stage,
259
+ date: c.derivedDate,
260
+ filePath: c.filePath,
261
+ relativePath: c.relativePath,
262
+ sources: {
263
+ slug: c.slugSource,
264
+ state: c.stateSource,
265
+ date: c.dateSource,
266
+ },
267
+ };
268
+ }
269
+ function emitJsonPlan(plan) {
270
+ process.stdout.write(`${JSON.stringify(plan, null, 2)}\n`);
271
+ }
272
+ function emitTextPlan(plan) {
273
+ const heading = plan.apply
274
+ ? `Applying: ${plan.add.length} add, ${plan.skip.length} skip`
275
+ : `Plan: ${plan.add.length} add, ${plan.skip.length} skip (dry-run; pass --apply to commit)`;
276
+ process.stdout.write(`${heading}\n\n`);
277
+ for (const { candidate, stage } of plan.add) {
278
+ const sources = `slug:${candidate.slugSource} state:${candidate.stateSource} date:${candidate.dateSource}`;
279
+ process.stdout.write(`add ${pad(candidate.derivedSlug, 36)} ${pad(stage, 10)} ${pad(candidate.derivedDate, 12)} ${sources}\n`);
280
+ }
281
+ for (const skip of plan.skip) {
282
+ const slug = skip.slug ?? '(no slug)';
283
+ process.stdout.write(`skip ${pad(slug, 36)} ${skip.reason}\n`);
284
+ }
285
+ }
286
+ function pad(s, n) {
287
+ if (s.length >= n)
288
+ return s;
289
+ return s + ' '.repeat(n - s.length);
290
+ }
291
+ /**
292
+ * Append a journal record under `<reviewJournalDir>/ingest/` so a
293
+ * later review-start (or audit) can find provenance for the ingested
294
+ * row. We reuse the existing journal infrastructure rather than
295
+ * inventing a new dir — review-journal already uses one-file-per-event
296
+ * shape that a tight-fit for ingest events.
297
+ */
298
+ function writeIngestJournalEntry(projectRoot, config, site, candidate, entry) {
299
+ const journalRoot = join(projectRoot, config.reviewJournalDir ?? '.deskwork/review-journal', 'ingest');
300
+ if (!existsSync(journalRoot)) {
301
+ mkdirSync(journalRoot, { recursive: true });
302
+ }
303
+ const record = {
304
+ id: entry.id ?? randomUUID(),
305
+ timestamp: new Date().toISOString(),
306
+ event: 'ingest',
307
+ slug: entry.slug,
308
+ entryId: entry.id ?? '',
309
+ site,
310
+ stage: entry.stage,
311
+ sourceFile: candidate.relativePath,
312
+ frontmatterSnapshot: candidate.frontmatter,
313
+ derivation: {
314
+ slug: candidate.slugSource,
315
+ state: candidate.stateSource,
316
+ date: candidate.dateSource,
317
+ },
318
+ };
319
+ appendJournal(journalRoot, record);
320
+ }
321
+ //# sourceMappingURL=ingest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingest.js","sourceRoot":"","sources":["../../src/commands/ingest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Install pre-flight checks (Issue #42 + #45, Phase 22).
3
+ *
4
+ * Two non-blocking probes that run after `.deskwork/config.json` is
5
+ * written, before the install command exits successfully:
6
+ *
7
+ * 1. detectExistingPipeline — heuristic walk for signals of a competing
8
+ * in-house editorial implementation (e.g. the audiocontrol journal
9
+ * layout deskwork was extracted from). When detected, the operator
10
+ * is warned that deskwork installs ALONGSIDE the existing pipeline
11
+ * rather than replacing it.
12
+ *
13
+ * 2. preflightSchema — for Astro sites only, statically inspect the
14
+ * host's content schema source for either a `deskwork` field
15
+ * declaration or a top-level `.passthrough()`. If neither matches
16
+ * (or the schema file is missing / ambiguous), the schema-patch
17
+ * instructions are printed inline at install time so the operator
18
+ * sees the requirement BEFORE the first deskwork write.
19
+ *
20
+ * Both probes are loud but non-blocking — they print to stdout and
21
+ * return without throwing. Install still completes successfully.
22
+ *
23
+ * Sibling-relative imports per the project convention.
24
+ */
25
+ import type { DeskworkConfig } from '@deskwork/core/config';
26
+ /**
27
+ * Result of the schema preflight check for one site. The probe is
28
+ * intentionally coarse — it asks "could this schema accept the
29
+ * `deskwork:` namespace?" rather than parsing TypeScript.
30
+ */
31
+ export type SchemaProbeOutcome = {
32
+ kind: 'compatible';
33
+ schemaPath: string;
34
+ reason: string;
35
+ } | {
36
+ kind: 'uncertain';
37
+ schemaPath: string | null;
38
+ reason: string;
39
+ } | {
40
+ kind: 'skipped';
41
+ reason: string;
42
+ };
43
+ /**
44
+ * Probe the content-schema file for compatibility with deskwork's
45
+ * `deskwork:` namespace binding. Static text inspection — does NOT
46
+ * evaluate the TypeScript.
47
+ *
48
+ * Returns `compatible` when either a `deskwork`-named schema field
49
+ * declaration OR a top-level `.passthrough()` is detected. Anything
50
+ * else (file missing, no signal found) is `uncertain` — the caller
51
+ * surfaces patch instructions to the operator.
52
+ */
53
+ export declare function preflightSchemaForProject(projectRoot: string): SchemaProbeOutcome;
54
+ /**
55
+ * Print the schema preflight result to stdout. Non-blocking — install
56
+ * continues regardless of outcome.
57
+ *
58
+ * The function is responsible for the entire textual surface of the
59
+ * check so the install command stays focused on its own concerns.
60
+ */
61
+ export declare function printSchemaPreflight(projectRoot: string, config: DeskworkConfig): void;
62
+ /**
63
+ * One signal found by `detectExistingPipeline`. The `kind` discriminator
64
+ * lets the formatter group findings logically when multiple matches
65
+ * land in the same category.
66
+ */
67
+ export interface PipelineSignal {
68
+ kind: 'journal-tree' | 'editorial-skill' | 'editorial-astro-page' | 'editorial-script-module';
69
+ /** Path relative to the project root, for display. */
70
+ relativePath: string;
71
+ }
72
+ /**
73
+ * Walk the project for signals of a competing in-house editorial
74
+ * implementation. Each branch is independent — any one signal is mild,
75
+ * the combination is loud.
76
+ */
77
+ export declare function detectExistingPipeline(projectRoot: string): PipelineSignal[];
78
+ /**
79
+ * Print the existing-pipeline warning to stdout when signals were
80
+ * detected. No-op when nothing was found.
81
+ */
82
+ export declare function printExistingPipelineWarning(signals: ReadonlyArray<PipelineSignal>): void;
83
+ //# sourceMappingURL=install-preflight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-preflight.d.ts","sourceRoot":"","sources":["../../src/commands/install-preflight.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AA2C5D;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC1D;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAChE;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAExC;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,GAClB,kBAAkB,CAqDpB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,GACrB,IAAI,CAuCN;AAMD;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EACA,cAAc,GACd,iBAAiB,GACjB,sBAAsB,GACtB,yBAAyB,CAAC;IAC9B,sDAAsD;IACtD,YAAY,EAAE,MAAM,CAAC;CACtB;AA0BD;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,GAClB,cAAc,EAAE,CAuFlB;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,aAAa,CAAC,cAAc,CAAC,GACrC,IAAI,CAiBN"}