litmus-cli 1.4.7-eng1502.4 → 1.4.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.
- package/README.md +0 -29
- package/dist/commands/connect.d.ts.map +1 -1
- package/dist/commands/connect.js +20 -2
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/doctor.d.ts +1 -41
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +26 -188
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.d.ts +1 -3
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +36 -77
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +25 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/submit.d.ts.map +1 -1
- package/dist/commands/submit.js +4 -83
- package/dist/commands/submit.js.map +1 -1
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/ai-tracking.d.ts +10 -0
- package/dist/lib/ai-tracking.d.ts.map +1 -1
- package/dist/lib/ai-tracking.js +25 -0
- package/dist/lib/ai-tracking.js.map +1 -1
- package/dist/lib/backlog-flush.d.ts +118 -0
- package/dist/lib/backlog-flush.d.ts.map +1 -0
- package/dist/lib/backlog-flush.js +268 -0
- package/dist/lib/backlog-flush.js.map +1 -0
- package/dist/lib/config.d.ts +0 -20
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +0 -27
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/detect-project.d.ts +46 -1
- package/dist/lib/detect-project.d.ts.map +1 -1
- package/dist/lib/detect-project.js +40 -19
- package/dist/lib/detect-project.js.map +1 -1
- package/dist/lib/hook-logger.cjs +136 -2
- package/dist/lib/keepalive.d.ts +33 -0
- package/dist/lib/keepalive.d.ts.map +1 -0
- package/dist/lib/keepalive.js +39 -0
- package/dist/lib/keepalive.js.map +1 -0
- package/dist/lib/shadow.d.ts +14 -0
- package/dist/lib/shadow.d.ts.map +1 -1
- package/dist/lib/shadow.js +33 -0
- package/dist/lib/shadow.js.map +1 -1
- package/dist/lib/tracker.d.ts.map +1 -1
- package/dist/lib/tracker.js +9 -1
- package/dist/lib/tracker.js.map +1 -1
- package/dist/lib/watcher.js +31 -7
- package/dist/lib/watcher.js.map +1 -1
- package/package.json +1 -1
- package/dist/lib/editor.d.ts +0 -73
- package/dist/lib/editor.d.ts.map +0 -1
- package/dist/lib/editor.js +0 -222
- package/dist/lib/editor.js.map +0 -1
- package/dist/lib/open-url.d.ts +0 -9
- package/dist/lib/open-url.d.ts.map +0 -1
- package/dist/lib/open-url.js +0 -45
- package/dist/lib/open-url.js.map +0 -1
- package/dist/lib/select.d.ts +0 -64
- package/dist/lib/select.d.ts.map +0 -1
- package/dist/lib/select.js +0 -170
- package/dist/lib/select.js.map +0 -1
- package/dist/lib/session.d.ts +0 -104
- package/dist/lib/session.d.ts.map +0 -1
- package/dist/lib/session.js +0 -327
- package/dist/lib/session.js.map +0 -1
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, renameSync, unlinkSync } from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { uploadActivityEvents } from "./api.js";
|
|
4
|
+
/**
|
|
5
|
+
* Backlog flush for a dead watcher's un-uploaded tail (ENG-1491, extracted
|
|
6
|
+
* verbatim from `litmus doctor`).
|
|
7
|
+
*
|
|
8
|
+
* Everything the trackers record lands in activity.jsonl first, so the file
|
|
9
|
+
* is the source of truth. When the watcher dies, whatever sat in its
|
|
10
|
+
* in-memory upload buffer (at most one heartbeat interval of events) never
|
|
11
|
+
* reached the server — but it is still on disk. This module delivers that
|
|
12
|
+
* gap through the same /cli/activity endpoint, verbatim (chained watcher
|
|
13
|
+
* events stay verifiable), with a forward-only byte cursor so an interrupted
|
|
14
|
+
* flush resumes without re-sending or skipping anything.
|
|
15
|
+
*
|
|
16
|
+
* Two callers: `litmus doctor` (the loud, candidate-facing repair) and
|
|
17
|
+
* `litmus status`'s tracker revival (quiet — see flushDeathGapBacklog).
|
|
18
|
+
*/
|
|
19
|
+
// Backlog flush window when there is no cursor: the dead watcher's last
|
|
20
|
+
// heartbeat marks roughly when server uploads stopped, and its unflushed
|
|
21
|
+
// in-memory buffer held at most one heartbeat interval of events. Reaching
|
|
22
|
+
// one extra interval further back trades a few duplicate rows (the server
|
|
23
|
+
// stores batches append-only) for never missing the gap.
|
|
24
|
+
export const FLUSH_WINDOW_BEFORE_LAST_HEARTBEAT_MS = 10 * 60 * 1000;
|
|
25
|
+
// Per-request caps for the backlog flush. The server accepts up to 5000
|
|
26
|
+
// events per batch and rate-limits /cli/activity per candidate, so a bounded
|
|
27
|
+
// number of modest batches per run stays well inside both while still
|
|
28
|
+
// clearing any realistic gap. Anything left over is remembered in the cursor
|
|
29
|
+
// and picked up by the next run.
|
|
30
|
+
export const MAX_EVENTS_PER_BATCH = 500;
|
|
31
|
+
export const MAX_BATCH_BYTES = 2000000;
|
|
32
|
+
export const MAX_BATCHES_PER_RUN = 4;
|
|
33
|
+
/** One pass over raw activity-log text: counts and latest timestamps. */
|
|
34
|
+
export function scanActivityLog(text) {
|
|
35
|
+
const scan = {
|
|
36
|
+
totalBytes: Buffer.byteLength(text, "utf8"),
|
|
37
|
+
eventCount: 0,
|
|
38
|
+
malformedCount: 0,
|
|
39
|
+
aiPromptCount: 0,
|
|
40
|
+
lastEventTs: null,
|
|
41
|
+
lastHeartbeatTs: null,
|
|
42
|
+
lastLiveAiPromptTs: null,
|
|
43
|
+
};
|
|
44
|
+
for (const line of text.split("\n")) {
|
|
45
|
+
if (!line.trim())
|
|
46
|
+
continue;
|
|
47
|
+
let event;
|
|
48
|
+
try {
|
|
49
|
+
event = JSON.parse(line);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
scan.malformedCount++;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (!event || typeof event !== "object") {
|
|
56
|
+
scan.malformedCount++;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
scan.eventCount++;
|
|
60
|
+
const e = event;
|
|
61
|
+
if (typeof e.ts === "string")
|
|
62
|
+
scan.lastEventTs = e.ts;
|
|
63
|
+
if (e.type === "ai_prompt") {
|
|
64
|
+
scan.aiPromptCount++;
|
|
65
|
+
if (e.backfilled !== true && typeof e.ts === "string")
|
|
66
|
+
scan.lastLiveAiPromptTs = e.ts;
|
|
67
|
+
}
|
|
68
|
+
if (e.type === "heartbeat" && typeof e.ts === "string")
|
|
69
|
+
scan.lastHeartbeatTs = e.ts;
|
|
70
|
+
}
|
|
71
|
+
return scan;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Byte offset of the first log line whose event timestamp is at or after
|
|
75
|
+
* `cutoffMs`. Lines without a parseable timestamp don't start the window.
|
|
76
|
+
* Returns the total byte length (i.e. "flush nothing") when no line qualifies.
|
|
77
|
+
*/
|
|
78
|
+
export function offsetForFirstEventAtOrAfter(text, cutoffMs) {
|
|
79
|
+
let offset = 0;
|
|
80
|
+
for (const line of text.split("\n")) {
|
|
81
|
+
const lineBytes = Buffer.byteLength(line, "utf8") + 1; // + newline
|
|
82
|
+
if (line.trim()) {
|
|
83
|
+
try {
|
|
84
|
+
const event = JSON.parse(line);
|
|
85
|
+
if (typeof event.ts === "string") {
|
|
86
|
+
const ts = Date.parse(event.ts);
|
|
87
|
+
if (!isNaN(ts) && ts >= cutoffMs)
|
|
88
|
+
return offset;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch { /* malformed line can't start the window */ }
|
|
92
|
+
}
|
|
93
|
+
offset += lineBytes;
|
|
94
|
+
}
|
|
95
|
+
return Buffer.byteLength(text, "utf8");
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Slice the log from `startOffset` into upload batches. Events are passed
|
|
99
|
+
* through VERBATIM (chained watcher events stay verifiable); malformed lines
|
|
100
|
+
* are skipped but still advance the offset so they are never retried forever.
|
|
101
|
+
* `startOffset` must fall on a line boundary (it always does: every stored
|
|
102
|
+
* cursor value is a `FlushBatch.endOffset`); a mid-line offset skips the torn
|
|
103
|
+
* line rather than uploading half an event.
|
|
104
|
+
*/
|
|
105
|
+
export function planFlushBatches(text, startOffset) {
|
|
106
|
+
const batches = [];
|
|
107
|
+
let offset = 0;
|
|
108
|
+
let current = [];
|
|
109
|
+
let currentBytes = 0;
|
|
110
|
+
let end = startOffset;
|
|
111
|
+
const finish = () => {
|
|
112
|
+
if (current.length > 0) {
|
|
113
|
+
batches.push({ events: current, endOffset: end });
|
|
114
|
+
current = [];
|
|
115
|
+
currentBytes = 0;
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
for (const line of text.split("\n")) {
|
|
119
|
+
const lineBytes = Buffer.byteLength(line, "utf8") + 1;
|
|
120
|
+
const lineStart = offset;
|
|
121
|
+
offset += lineBytes;
|
|
122
|
+
if (lineStart < startOffset)
|
|
123
|
+
continue;
|
|
124
|
+
if (!line.trim()) {
|
|
125
|
+
end = Math.min(offset, Buffer.byteLength(text, "utf8"));
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
let event;
|
|
129
|
+
try {
|
|
130
|
+
event = JSON.parse(line);
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
end = offset; // skip malformed, but move past it
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const eventBytes = Buffer.byteLength(line, "utf8");
|
|
137
|
+
if (current.length >= MAX_EVENTS_PER_BATCH || currentBytes + eventBytes > MAX_BATCH_BYTES) {
|
|
138
|
+
finish();
|
|
139
|
+
}
|
|
140
|
+
current.push(event);
|
|
141
|
+
currentBytes += eventBytes;
|
|
142
|
+
end = Math.min(offset, Buffer.byteLength(text, "utf8"));
|
|
143
|
+
}
|
|
144
|
+
finish();
|
|
145
|
+
return batches;
|
|
146
|
+
}
|
|
147
|
+
// ── Flush cursor (.litmus/upload-state.json) ─────────────────────
|
|
148
|
+
// Records the byte offset up to which a flush has delivered locally-recorded
|
|
149
|
+
// events to the server. Only exists while a recovery is in flight: a fully
|
|
150
|
+
// flushed backlog removes it (live watcher uploads own everything after
|
|
151
|
+
// that), and it NEVER moves backward.
|
|
152
|
+
const UPLOAD_STATE_FILE = "upload-state.json";
|
|
153
|
+
export function readUploadState(litmusDir) {
|
|
154
|
+
try {
|
|
155
|
+
const raw = JSON.parse(readFileSync(path.join(litmusDir, UPLOAD_STATE_FILE), "utf8"));
|
|
156
|
+
const v = raw?.flushFromBytes;
|
|
157
|
+
if (typeof v === "number" && Number.isFinite(v) && v >= 0)
|
|
158
|
+
return v;
|
|
159
|
+
}
|
|
160
|
+
catch { /* absent or unreadable */ }
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
export function writeUploadState(litmusDir, flushFromBytes) {
|
|
164
|
+
const existing = readUploadState(litmusDir);
|
|
165
|
+
// Forward-only: a smaller offset would make the next run re-upload events
|
|
166
|
+
// the server already has.
|
|
167
|
+
const value = Math.max(existing ?? 0, flushFromBytes);
|
|
168
|
+
const target = path.join(litmusDir, UPLOAD_STATE_FILE);
|
|
169
|
+
const tmp = `${target}.litmus-tmp-${process.pid}-${Date.now()}`;
|
|
170
|
+
writeFileSync(tmp, JSON.stringify({ flushFromBytes: value, updatedAt: new Date().toISOString() }, null, 2) + "\n", "utf8");
|
|
171
|
+
renameSync(tmp, target);
|
|
172
|
+
}
|
|
173
|
+
export function clearUploadState(litmusDir) {
|
|
174
|
+
try {
|
|
175
|
+
unlinkSync(path.join(litmusDir, UPLOAD_STATE_FILE));
|
|
176
|
+
}
|
|
177
|
+
catch { /* already gone */ }
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Where a flush should start, or null when there is nothing to flush. A
|
|
181
|
+
* stored cursor (an earlier interrupted flush) always wins; otherwise the
|
|
182
|
+
* window opens FLUSH_WINDOW_BEFORE_LAST_HEARTBEAT_MS before the dead
|
|
183
|
+
* watcher's last heartbeat.
|
|
184
|
+
*/
|
|
185
|
+
export function resolveFlushStart(args) {
|
|
186
|
+
const cursor = readUploadState(args.litmusDir);
|
|
187
|
+
if (cursor !== null)
|
|
188
|
+
return Math.min(cursor, args.totalBytes ?? cursor);
|
|
189
|
+
if (args.lastHeartbeatTs) {
|
|
190
|
+
const cutoff = Date.parse(args.lastHeartbeatTs) - FLUSH_WINDOW_BEFORE_LAST_HEARTBEAT_MS;
|
|
191
|
+
return offsetForFirstEventAtOrAfter(args.logText, cutoff);
|
|
192
|
+
}
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Deliver up to MAX_BATCHES_PER_RUN batches starting at `flushFrom`. Stops at
|
|
197
|
+
* the first upload failure; the caller persists `lastGood` so the next run
|
|
198
|
+
* resumes exactly where this one stopped.
|
|
199
|
+
*/
|
|
200
|
+
export async function deliverFlushBatches(logText, flushFrom, upload) {
|
|
201
|
+
const batches = planFlushBatches(logText, flushFrom);
|
|
202
|
+
const totalEvents = batches.reduce((n, b) => n + b.events.length, 0);
|
|
203
|
+
let sent = 0;
|
|
204
|
+
let lastGood = flushFrom;
|
|
205
|
+
let failure = null;
|
|
206
|
+
for (const batch of batches.slice(0, MAX_BATCHES_PER_RUN)) {
|
|
207
|
+
try {
|
|
208
|
+
await upload(batch.events);
|
|
209
|
+
sent += batch.events.length;
|
|
210
|
+
lastGood = batch.endOffset;
|
|
211
|
+
}
|
|
212
|
+
catch (err) {
|
|
213
|
+
failure = err instanceof Error ? err.message : String(err);
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return { totalEvents, sent, lastGood, failure };
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* The quiet twin of doctor's backlog flush, for `litmus status`'s tracker
|
|
221
|
+
* revival (ENG-1491). When status revives a dead watcher, the dead watcher's
|
|
222
|
+
* last few minutes of events are on disk but never reached the server — and
|
|
223
|
+
* the replacement watcher only uploads what IT captures, so without this the
|
|
224
|
+
* gap sat there until someone happened to run doctor.
|
|
225
|
+
*
|
|
226
|
+
* `logText` must be snapshotted BEFORE the replacement watcher starts
|
|
227
|
+
* appending, so the flush delivers the dead watcher's tail rather than
|
|
228
|
+
* racing the live one's own uploads. Cursor handling matches doctor: cleared
|
|
229
|
+
* when the backlog is fully delivered, advanced to the last good batch when
|
|
230
|
+
* it is not (doctor or the next revival picks up the rest).
|
|
231
|
+
*
|
|
232
|
+
* Returns null when there was nothing to flush. Never throws — a status run
|
|
233
|
+
* must not fail over an upload courtesy.
|
|
234
|
+
*/
|
|
235
|
+
export async function flushDeathGapBacklog(args) {
|
|
236
|
+
try {
|
|
237
|
+
const litmusDir = path.join(args.projectRoot, ".litmus");
|
|
238
|
+
const scan = scanActivityLog(args.logText);
|
|
239
|
+
const flushFrom = resolveFlushStart({
|
|
240
|
+
litmusDir,
|
|
241
|
+
logText: args.logText,
|
|
242
|
+
totalBytes: scan.totalBytes,
|
|
243
|
+
// Revival implies the tracker was dead, so the heartbeat window applies.
|
|
244
|
+
lastHeartbeatTs: scan.lastHeartbeatTs,
|
|
245
|
+
});
|
|
246
|
+
if (flushFrom === null)
|
|
247
|
+
return null;
|
|
248
|
+
const { totalEvents, sent, lastGood, failure } = await deliverFlushBatches(args.logText, flushFrom, (events) => uploadActivityEvents(args.backendUrl, args.token, events));
|
|
249
|
+
if (totalEvents === 0) {
|
|
250
|
+
clearUploadState(litmusDir);
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
if (totalEvents - sent === 0 && failure === null) {
|
|
254
|
+
clearUploadState(litmusDir);
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
try {
|
|
258
|
+
writeUploadState(litmusDir, lastGood);
|
|
259
|
+
}
|
|
260
|
+
catch { /* next run recomputes */ }
|
|
261
|
+
}
|
|
262
|
+
return { sent, total: totalEvents, failure };
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
//# sourceMappingURL=backlog-flush.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backlog-flush.js","sourceRoot":"","sources":["../../src/lib/backlog-flush.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { EditorId } from "./editor.js";
|
|
2
1
|
export interface LitmusConfig {
|
|
3
2
|
assessmentId: string;
|
|
4
3
|
assessmentName: string;
|
|
@@ -12,7 +11,6 @@ export interface LitmusConfig {
|
|
|
12
11
|
apiBase: string;
|
|
13
12
|
backendUrl?: string;
|
|
14
13
|
cliVersion?: string;
|
|
15
|
-
editor?: EditorId;
|
|
16
14
|
}
|
|
17
15
|
/**
|
|
18
16
|
* Calculate the effective deadline timestamp (ms) from config.
|
|
@@ -20,24 +18,6 @@ export interface LitmusConfig {
|
|
|
20
18
|
*/
|
|
21
19
|
export declare function getEffectiveDeadline(config: Pick<LitmusConfig, "deadline" | "startedAt" | "timeLimit">): number | null;
|
|
22
20
|
export declare function writeConfig(projectRoot: string, config: LitmusConfig): Promise<void>;
|
|
23
|
-
/**
|
|
24
|
-
* Record the editor the candidate picked, merging into whatever is on disk NOW
|
|
25
|
-
* rather than over an in-memory copy.
|
|
26
|
-
*
|
|
27
|
-
* This has to be a read-modify-write. Init writes the config, starts the
|
|
28
|
-
* watcher, and only then asks which editor to open — and while that prompt sits
|
|
29
|
-
* there the watcher can fold server-authoritative times into config.json
|
|
30
|
-
* (ENG-1489). Writing back an object captured before the prompt would revert
|
|
31
|
-
* that sync, and it would NOT self-correct: computeTimeSync compares against
|
|
32
|
-
* the watcher's own in-memory copy, so having already applied the change it
|
|
33
|
-
* writes nothing further until the server times move again. A deadline
|
|
34
|
-
* extension granted at init time could be silently rolled back on disk, and a
|
|
35
|
-
* watcher restart would then arm the earlier cutoff.
|
|
36
|
-
*
|
|
37
|
-
* Best-effort: failing to record the editor only costs the window close at
|
|
38
|
-
* submit, which is itself best-effort.
|
|
39
|
-
*/
|
|
40
|
-
export declare function recordEditorChoice(projectRoot: string, editor: EditorId): Promise<void>;
|
|
41
21
|
/**
|
|
42
22
|
* Sanity-check restore-time metadata before writing a rebuilt config.
|
|
43
23
|
* Returns a human-readable problem, or null when the times are usable.
|
package/dist/lib/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAA;IACpB,cAAc,EAAE,MAAM,CAAA;IACtB,cAAc,EAAE,MAAM,CAAA;IACtB,aAAa,EAAE,MAAM,CAAA;IACrB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;IAOnB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,UAAU,GAAG,WAAW,GAAG,WAAW,CAAC,GAAG,MAAM,GAAG,IAAI,CAStH;AAKD,wBAAsB,WAAW,CAC/B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,IAAI,CAAC,CAcf;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EAC9E,KAAK,EAAE,MAAM,GACZ,MAAM,GAAG,IAAI,CASf;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,YAAY,EACrB,KAAK,EAAE;IAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EACtF,KAAK,EAAE,MAAM,GACZ;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,YAAY,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAsBtF;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,MAAM,GAAG,IAAI,CAe/C;AAED;;;GAGG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAwB/D"}
|
package/dist/lib/config.js
CHANGED
|
@@ -32,33 +32,6 @@ export async function writeConfig(projectRoot, config) {
|
|
|
32
32
|
// restored without the candidate doing anything. Best-effort by design.
|
|
33
33
|
writeShadowConfig(projectRoot, config);
|
|
34
34
|
}
|
|
35
|
-
/**
|
|
36
|
-
* Record the editor the candidate picked, merging into whatever is on disk NOW
|
|
37
|
-
* rather than over an in-memory copy.
|
|
38
|
-
*
|
|
39
|
-
* This has to be a read-modify-write. Init writes the config, starts the
|
|
40
|
-
* watcher, and only then asks which editor to open — and while that prompt sits
|
|
41
|
-
* there the watcher can fold server-authoritative times into config.json
|
|
42
|
-
* (ENG-1489). Writing back an object captured before the prompt would revert
|
|
43
|
-
* that sync, and it would NOT self-correct: computeTimeSync compares against
|
|
44
|
-
* the watcher's own in-memory copy, so having already applied the change it
|
|
45
|
-
* writes nothing further until the server times move again. A deadline
|
|
46
|
-
* extension granted at init time could be silently rolled back on disk, and a
|
|
47
|
-
* watcher restart would then arm the earlier cutoff.
|
|
48
|
-
*
|
|
49
|
-
* Best-effort: failing to record the editor only costs the window close at
|
|
50
|
-
* submit, which is itself best-effort.
|
|
51
|
-
*/
|
|
52
|
-
export async function recordEditorChoice(projectRoot, editor) {
|
|
53
|
-
const configPath = path.join(projectRoot, CONFIG_DIR, CONFIG_FILE);
|
|
54
|
-
try {
|
|
55
|
-
const current = JSON.parse(await readFile(configPath, "utf8"));
|
|
56
|
-
await writeConfig(projectRoot, { ...current, editor });
|
|
57
|
-
}
|
|
58
|
-
catch {
|
|
59
|
-
// No readable config to merge into — nothing safe to write.
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
35
|
/**
|
|
63
36
|
* Sanity-check restore-time metadata before writing a rebuilt config.
|
|
64
37
|
* Returns a human-readable problem, or null when the times are usable.
|
package/dist/lib/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAA;AAC/B,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
export type ProjectType = "node" | "python" | "go" | "java" | "dotnet" | "rust" | "ruby" | "php" | "unknown";
|
|
2
|
+
/** Seams the caller can replace. Both read the HOST by default, which is what
|
|
3
|
+
* makes them worth injecting: a test cannot control whether this machine has
|
|
4
|
+
* bun, so without these the runtime behaviour is only assertable as "either". */
|
|
5
|
+
export interface DetectDeps {
|
|
6
|
+
isOnPath?: (bin: string) => boolean;
|
|
7
|
+
}
|
|
2
8
|
export interface ProjectInfo {
|
|
3
9
|
type: ProjectType;
|
|
4
10
|
installCommand: string | null;
|
|
@@ -9,6 +15,17 @@ export interface ProjectInfo {
|
|
|
9
15
|
* the README told them could not happen.
|
|
10
16
|
*/
|
|
11
17
|
toolchainWarning?: string;
|
|
18
|
+
/**
|
|
19
|
+
* A RUNTIME that `installCommand` needs and that is not on PATH.
|
|
20
|
+
*
|
|
21
|
+
* Reported as state rather than as a warning string, because the right thing
|
|
22
|
+
* to say depends on what the caller manages to DO about it: `init` installs
|
|
23
|
+
* bun and says nothing, or fails to and says so. A message authored here
|
|
24
|
+
* would have to be written before either outcome is known, which is how the
|
|
25
|
+
* first version came to tell candidates to install bun by hand in the case
|
|
26
|
+
* where we had just installed it for them.
|
|
27
|
+
*/
|
|
28
|
+
missingRuntime?: "bun";
|
|
12
29
|
}
|
|
13
30
|
/**
|
|
14
31
|
* The Python the candidate's submission is actually GRADED on.
|
|
@@ -38,8 +55,36 @@ export declare function resolvePythonInterpreter(): {
|
|
|
38
55
|
matchesGrader: boolean;
|
|
39
56
|
detectedVersion: string | null;
|
|
40
57
|
};
|
|
58
|
+
/**
|
|
59
|
+
* Is `bin` runnable from PATH?
|
|
60
|
+
*
|
|
61
|
+
* `--version` rather than `which`/`where`: one probe that works on all three
|
|
62
|
+
* platforms, and it proves the binary actually EXECUTES. A PATH entry pointing at
|
|
63
|
+
* a broken install or the wrong architecture resolves fine and then fails on use,
|
|
64
|
+
* which is the case a warning most needs to catch. `shell: true` on Windows so
|
|
65
|
+
* `.cmd`/`.ps1` shims resolve, matching the Python probe above.
|
|
66
|
+
*/
|
|
67
|
+
export declare function isOnPath(bin: string): boolean;
|
|
41
68
|
/**
|
|
42
69
|
* Detect project type and suggest an install command.
|
|
43
70
|
*/
|
|
44
|
-
export declare function detectProject(dir: string): ProjectInfo;
|
|
71
|
+
export declare function detectProject(dir: string, deps?: DetectDeps): ProjectInfo;
|
|
72
|
+
/** How each supported runtime is obtained. npm ships per-platform bun binaries,
|
|
73
|
+
* and npm is guaranteed present because this CLI is an npm package. */
|
|
74
|
+
export declare const RUNTIME_INSTALL: Record<"bun", string>;
|
|
75
|
+
export type RuntimeOutcome = "installed" | "unavailable";
|
|
76
|
+
export interface InstallRuntimeDeps {
|
|
77
|
+
exec?: (command: string) => void;
|
|
78
|
+
isOnPath?: (bin: string) => boolean;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Install a runtime the project needs and the machine lacks.
|
|
82
|
+
*
|
|
83
|
+
* Separated from `init`'s reporting so all three outcomes are assertable: the
|
|
84
|
+
* install failing, and the install "succeeding" while leaving nothing on PATH.
|
|
85
|
+
* That second case is the one worth a unit test — a global install can land
|
|
86
|
+
* somewhere this process cannot reach, and treating it as success means the
|
|
87
|
+
* dependency install below dies on a command-not-found we already knew about.
|
|
88
|
+
*/
|
|
89
|
+
export declare function installRuntime(runtime: "bun", deps?: InstallRuntimeDeps): RuntimeOutcome;
|
|
45
90
|
//# sourceMappingURL=detect-project.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detect-project.d.ts","sourceRoot":"","sources":["../../src/lib/detect-project.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,WAAW,GACnB,MAAM,GACN,QAAQ,GACR,IAAI,GACJ,MAAM,GACN,QAAQ,GACR,MAAM,GACN,MAAM,GACN,KAAK,GACL,SAAS,CAAA;AAEb,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,WAAW,CAAA;IACjB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"detect-project.d.ts","sourceRoot":"","sources":["../../src/lib/detect-project.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,WAAW,GACnB,MAAM,GACN,QAAQ,GACR,IAAI,GACJ,MAAM,GACN,QAAQ,GACR,MAAM,GACN,MAAM,GACN,KAAK,GACL,SAAS,CAAA;AAEb;;kFAEkF;AAClF,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAA;CACpC;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,WAAW,CAAA;IACjB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;;;;;;;OASG;IACH,cAAc,CAAC,EAAE,KAAK,CAAA;CACvB;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,sBAAsB,SAAS,CAAA;AA0D5C;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,IAAI;IAC1C,OAAO,EAAE,MAAM,CAAA;IACf,aAAa,EAAE,OAAO,CAAA;IACtB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;CAC/B,CAkBA;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAY7C;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,UAAe,GAAG,WAAW,CAyF7E;AAGD;wEACwE;AACxE,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAEjD,CAAA;AAED,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,aAAa,CAAA;AAExD,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAA;CACpC;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,KAAK,EACd,IAAI,GAAE,kBAAuB,GAC5B,cAAc,CAchB"}
|
|
@@ -101,7 +101,7 @@ export function resolvePythonInterpreter() {
|
|
|
101
101
|
* which is the case a warning most needs to catch. `shell: true` on Windows so
|
|
102
102
|
* `.cmd`/`.ps1` shims resolve, matching the Python probe above.
|
|
103
103
|
*/
|
|
104
|
-
function isOnPath(bin) {
|
|
104
|
+
export function isOnPath(bin) {
|
|
105
105
|
try {
|
|
106
106
|
return (spawnSync(bin, ["--version"], {
|
|
107
107
|
encoding: "utf8",
|
|
@@ -116,7 +116,8 @@ function isOnPath(bin) {
|
|
|
116
116
|
/**
|
|
117
117
|
* Detect project type and suggest an install command.
|
|
118
118
|
*/
|
|
119
|
-
export function detectProject(dir) {
|
|
119
|
+
export function detectProject(dir, deps = {}) {
|
|
120
|
+
const onPath = deps.isOnPath ?? isOnPath;
|
|
120
121
|
if (existsSync(path.join(dir, "package.json"))) {
|
|
121
122
|
const hasYarnLock = existsSync(path.join(dir, "yarn.lock"));
|
|
122
123
|
const hasPnpmLock = existsSync(path.join(dir, "pnpm-lock.yaml"));
|
|
@@ -133,24 +134,13 @@ export function detectProject(dir) {
|
|
|
133
134
|
: hasBunLock
|
|
134
135
|
? "bun install"
|
|
135
136
|
: "npm install";
|
|
136
|
-
// Same disclosure contract as the Python skew below: a missing toolchain is
|
|
137
|
-
// ours to state here, not theirs to infer. Without this, `init`'s install
|
|
138
|
-
// failure prints "run `bun install` manually", which is the command that just
|
|
139
|
-
// failed — and the candidate is left guessing that a runtime they may never
|
|
140
|
-
// have heard of is the missing piece.
|
|
141
|
-
//
|
|
142
137
|
// Gated on the SELECTED command, not on `hasBunLock`. A repo carrying both a
|
|
143
|
-
// bun lockfile and a pnpm/yarn one resolves to pnpm/yarn above, and
|
|
144
|
-
//
|
|
145
|
-
//
|
|
146
|
-
//
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
"your PATH. Install it from https://bun.sh, then re-run `bun install` in " +
|
|
150
|
-
"this folder. npm can install the dependencies but cannot run the " +
|
|
151
|
-
"scaffold's server — it uses Bun-only APIs."
|
|
152
|
-
: undefined;
|
|
153
|
-
return { type: "node", installCommand, toolchainWarning };
|
|
138
|
+
// bun lockfile and a pnpm/yarn one resolves to pnpm/yarn above, and reporting
|
|
139
|
+
// bun as missing there would send the candidate to install a second,
|
|
140
|
+
// competing dependency tree over the one we just built. Also means
|
|
141
|
+
// npm/yarn/pnpm repos never pay for the PATH probe.
|
|
142
|
+
const missingRuntime = installCommand === "bun install" && !onPath("bun") ? "bun" : undefined;
|
|
143
|
+
return { type: "node", installCommand, missingRuntime };
|
|
154
144
|
}
|
|
155
145
|
if (existsSync(path.join(dir, "requirements.txt")) ||
|
|
156
146
|
existsSync(path.join(dir, "pyproject.toml")) ||
|
|
@@ -203,4 +193,35 @@ export function detectProject(dir) {
|
|
|
203
193
|
}
|
|
204
194
|
return { type: "unknown", installCommand: null };
|
|
205
195
|
}
|
|
196
|
+
/** How each supported runtime is obtained. npm ships per-platform bun binaries,
|
|
197
|
+
* and npm is guaranteed present because this CLI is an npm package. */
|
|
198
|
+
export const RUNTIME_INSTALL = {
|
|
199
|
+
bun: "npm install -g bun",
|
|
200
|
+
};
|
|
201
|
+
/**
|
|
202
|
+
* Install a runtime the project needs and the machine lacks.
|
|
203
|
+
*
|
|
204
|
+
* Separated from `init`'s reporting so all three outcomes are assertable: the
|
|
205
|
+
* install failing, and the install "succeeding" while leaving nothing on PATH.
|
|
206
|
+
* That second case is the one worth a unit test — a global install can land
|
|
207
|
+
* somewhere this process cannot reach, and treating it as success means the
|
|
208
|
+
* dependency install below dies on a command-not-found we already knew about.
|
|
209
|
+
*/
|
|
210
|
+
export function installRuntime(runtime, deps = {}) {
|
|
211
|
+
const exec = deps.exec ?? ((command) => {
|
|
212
|
+
// spawnSync reports a failure in `status` rather than throwing, so surface
|
|
213
|
+
// it as one — the catch below is what turns it into "unavailable".
|
|
214
|
+
const r = spawnSync(command, { shell: true, stdio: "pipe" });
|
|
215
|
+
if (r.status !== 0)
|
|
216
|
+
throw new Error(`\`${command}\` exited ${r.status}`);
|
|
217
|
+
});
|
|
218
|
+
const onPath = deps.isOnPath ?? isOnPath;
|
|
219
|
+
try {
|
|
220
|
+
exec(RUNTIME_INSTALL[runtime]);
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
return "unavailable";
|
|
224
|
+
}
|
|
225
|
+
return onPath(runtime) ? "installed" : "unavailable";
|
|
226
|
+
}
|
|
206
227
|
//# sourceMappingURL=detect-project.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detect-project.js","sourceRoot":"","sources":["../../src/lib/detect-project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACzC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,IAAI,CAAA;AAC5C,OAAO,IAAI,MAAM,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"detect-project.js","sourceRoot":"","sources":["../../src/lib/detect-project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACzC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,IAAI,CAAA;AAC5C,OAAO,IAAI,MAAM,MAAM,CAAA;AA2CvB;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAA;AAS5C;;;;;;;;;;;;;;;;GAgBG;AACH,SAAS,gBAAgB;IACvB,MAAM,OAAO,GAAG,sBAAsB,CAAA;IACtC,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,OAAO;YACL,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,IAAI,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,OAAO,EAAE,EAAE;YAC/D,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;YACtC,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE;YAC9C,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE;SACjD,CAAA;IACH,CAAC;IACD,OAAO;QACL,EAAE,GAAG,EAAE,SAAS,OAAO,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,OAAO,EAAE,EAAE;QAClE,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE;KACjD,CAAA;AACH,CAAC;AAED,2EAA2E;AAC3E,SAAS,YAAY,CAAC,SAA0B;IAC9C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,SAAS,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,GAAG,SAAS,CAAC,IAAI,EAAE,WAAW,CAAC,EAAE;YACxE,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO;SACpC,CAAC,CAAA;QACF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAA;QACpC,MAAM,KAAK,GAAG,6BAA6B,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC,CAAA;QAChG,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,iEAAiE;QACjE,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,wBAAwB;IAKtC,MAAM,UAAU,GAAG,gBAAgB,EAAE,CAAA;IACrC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,MAAM,eAAe,GAAG,YAAY,CAAC,SAAS,CAAC,CAAA;QAC/C,IAAI,CAAC,eAAe;YAAE,SAAQ;QAC9B,OAAO;YACL,OAAO,EAAE,SAAS,CAAC,OAAO;YAC1B,wEAAwE;YACxE,mEAAmE;YACnE,sCAAsC;YACtC,aAAa,EAAE,eAAe,CAAC,UAAU,CAAC,GAAG,sBAAsB,GAAG,CAAC;gBACrE,eAAe,KAAK,sBAAsB;YAC5C,eAAe;SAChB,CAAA;IACH,CAAC;IAED,MAAM,IAAI,GAAG,UAAU,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAC9C,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,CAAA;AAC/E,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,QAAQ,CAAC,GAAW;IAClC,IAAI,CAAC;QACH,OAAO,CACL,SAAS,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,EAAE;YAC5B,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO;SACpC,CAAC,CAAC,MAAM,KAAK,CAAC,CAChB,CAAA;IACH,CAAC;IAAC,MAAM,CAAC;QACP,0EAA0E;QAC1E,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW,EAAE,OAAmB,EAAE;IAC9D,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAA;IACxC,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC;QAC/C,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAA;QAC3D,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC,CAAA;QAChE,8EAA8E;QAC9E,+EAA+E;QAC/E,gFAAgF;QAChF,+EAA+E;QAC/E,yDAAyD;QACzD,MAAM,UAAU,GACd,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAA;QACnF,MAAM,cAAc,GAAG,WAAW;YAChC,CAAC,CAAC,cAAc;YAChB,CAAC,CAAC,WAAW;gBACX,CAAC,CAAC,MAAM;gBACR,CAAC,CAAC,UAAU;oBACV,CAAC,CAAC,aAAa;oBACf,CAAC,CAAC,aAAa,CAAA;QACrB,6EAA6E;QAC7E,8EAA8E;QAC9E,qEAAqE;QACrE,mEAAmE;QACnE,oDAAoD;QACpD,MAAM,cAAc,GAClB,cAAc,KAAK,aAAa,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAE,KAAe,CAAC,CAAC,CAAC,SAAS,CAAA;QACnF,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,cAAc,EAAE,CAAA;IACzD,CAAC;IAED,IACE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC;QAC9C,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;QAC5C,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC,EACtC,CAAC;QACD,0EAA0E;QAC1E,0EAA0E;QAC1E,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,cAAc,CAAA;QACnF,MAAM,MAAM,GAAG,wBAAwB,EAAE,CAAA;QACzC,MAAM,cAAc,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC;YACnE,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,oBAAoB,MAAM,8BAA8B;YAC3E,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,oBAAoB,MAAM,eAAe,CAAA;QAC9D,2EAA2E;QAC3E,yEAAyE;QACzE,yEAAyE;QACzE,4EAA4E;QAC5E,mDAAmD;QACnD,MAAM,gBAAgB,GAAG,MAAM,CAAC,aAAa;YAC3C,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,MAAM,CAAC,eAAe;gBACtB,CAAC,CAAC,uCAAuC,sBAAsB,yBAAyB;oBACtF,UAAU,MAAM,CAAC,eAAe,OAAO,MAAM,CAAC,OAAO,wCAAwC;oBAC7F,oEAAoE;oBACpE,GAAG,sBAAsB,oDAAoD;gBAC/E,CAAC,CAAC,sDAAsD,MAAM,CAAC,OAAO,kBAAkB;oBACtF,sDAAsD,sBAAsB,aAAa;oBACzF,0CAA0C,CAAA;QAChD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,cAAc,EAAE,gBAAgB,EAAE,CAAA;IAC7D,CAAC;IAED,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC;QACzC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,iBAAiB,EAAE,CAAA;IAC1D,CAAC;IAED,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC;QAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,aAAa,EAAE,CAAA;IACxD,CAAC;IAED,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC,EAAE,CAAC;QACjG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,cAAc,EAAE,CAAA;IACzD,CAAC;IAED,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAA;IAC9B,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;QACjE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,cAAc,EAAE,gBAAgB,EAAE,CAAA;IAC7D,CAAC;IAED,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC;QAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,CAAA;IAC/C,CAAC;IAED,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC;QAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,gBAAgB,EAAE,CAAA;IAC3D,CAAC;IAED,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC;QAChD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAA;IAC5D,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,cAAc,EAAE,IAAI,EAAE,CAAA;AAClD,CAAC;AAGD;wEACwE;AACxE,MAAM,CAAC,MAAM,eAAe,GAA0B;IACpD,GAAG,EAAE,oBAAoB;CAC1B,CAAA;AASD;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAC5B,OAAc,EACd,OAA2B,EAAE;IAE7B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,OAAe,EAAE,EAAE;QAC7C,2EAA2E;QAC3E,mEAAmE;QACnE,MAAM,CAAC,GAAG,SAAS,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;QAC5D,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,KAAK,OAAO,aAAa,CAAC,CAAC,MAAM,EAAE,CAAC,CAAA;IAC1E,CAAC,CAAC,CAAA;IACF,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAA;IACxC,IAAI,CAAC;QACH,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAA;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,aAAa,CAAA;IACtB,CAAC;IACD,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,aAAa,CAAA;AACtD,CAAC"}
|