laneyard 0.3.0 → 0.4.1

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 (46) hide show
  1. package/README.md +227 -20
  2. package/dist/src/cli/detect.js +12 -3
  3. package/dist/src/cli/prompt.js +28 -3
  4. package/dist/src/cli/secret-import.js +162 -0
  5. package/dist/src/cli/secret.js +162 -1
  6. package/dist/src/cli/setup.js +44 -7
  7. package/dist/src/cli/uninstall.js +390 -0
  8. package/dist/src/credentials/kinds.js +120 -0
  9. package/dist/src/db/credentials.js +100 -0
  10. package/dist/src/db/schema.sql +39 -0
  11. package/dist/src/db/secrets.js +53 -0
  12. package/dist/src/db/sessions.js +61 -0
  13. package/dist/src/git/workspace.js +32 -6
  14. package/dist/src/heuristics/android-root.js +49 -0
  15. package/dist/src/heuristics/android-signing.js +98 -0
  16. package/dist/src/heuristics/appfile.js +60 -0
  17. package/dist/src/heuristics/blocking-actions.js +2 -0
  18. package/dist/src/heuristics/env-example.js +36 -0
  19. package/dist/src/heuristics/platforms.js +69 -10
  20. package/dist/src/heuristics/readiness.js +554 -25
  21. package/dist/src/main.js +23 -2
  22. package/dist/src/runner/gradle-properties.js +187 -0
  23. package/dist/src/runner/materialise.js +92 -0
  24. package/dist/src/runner/orchestrate.js +91 -2
  25. package/dist/src/secrets/vault.js +137 -5
  26. package/dist/src/server/app.js +30 -3
  27. package/dist/src/server/auth.js +50 -10
  28. package/dist/src/server/permissions.js +2 -0
  29. package/dist/src/server/required-secrets.js +30 -0
  30. package/dist/src/server/routes/account.js +57 -0
  31. package/dist/src/server/routes/credentials.js +108 -0
  32. package/dist/src/server/routes/projects.js +60 -2
  33. package/dist/src/server/routes/readiness.js +162 -6
  34. package/dist/src/server/routes/secrets.js +101 -0
  35. package/dist/src/sidecar/bridge.js +21 -1
  36. package/dist/src/sidecar/fastlane-dir.js +23 -0
  37. package/dist/src/sidecar/lanes.js +6 -0
  38. package/dist/src/sidecar/uses.js +21 -5
  39. package/dist/web/assets/{Editor-DNFBA4gv.js → Editor-9nLYwtg7.js} +1 -1
  40. package/dist/web/assets/index-DsjxZtsO.css +1 -0
  41. package/dist/web/assets/index-pzPa9EZr.js +62 -0
  42. package/dist/web/index.html +2 -2
  43. package/package.json +1 -1
  44. package/ruby/introspect.rb +122 -9
  45. package/dist/web/assets/index-De6sxx6G.css +0 -1
  46. package/dist/web/assets/index-TWRQ1cJg.js +0 -62
@@ -1,11 +1,16 @@
1
1
  import { execFile } from "node:child_process";
2
- import { access } from "node:fs/promises";
2
+ import { access, readFile } from "node:fs/promises";
3
3
  import { join } from "node:path";
4
4
  import { promisify } from "node:util";
5
5
  import { glob } from "tinyglobby";
6
6
  import { Workspace } from "../../git/workspace.js";
7
- import { resolvePlatforms } from "../../heuristics/platforms.js";
7
+ import { NO_APPFILE, parseAppfile } from "../../heuristics/appfile.js";
8
+ import { findAndroidBuild } from "../../heuristics/android-root.js";
9
+ import { exportedVarNames } from "../../credentials/kinds.js";
10
+ import { envExampleNames } from "../required-secrets.js";
11
+ import { appRootOf, resolvePlatforms, searchDir } from "../../heuristics/platforms.js";
8
12
  import { runChecklist } from "../../heuristics/readiness.js";
13
+ import { LANEYARD_MARKER, propertyNames } from "../../runner/gradle-properties.js";
9
14
  const exec = promisify(execFile);
10
15
  /**
11
16
  * `bundle check` in the workspace, rejecting with what bundler said.
@@ -35,9 +40,100 @@ async function findFastlane() {
35
40
  return null;
36
41
  }
37
42
  }
38
- /** The globbing `heuristics/platforms.ts` asks for, bound to the workspace. */
43
+ /** The globbing `heuristics/platforms.ts` asks for, bound to a directory. */
39
44
  const findIn = (dir) => (globs, { onlyDirectories }) => glob(globs, onlyDirectories ? { cwd: dir, onlyDirectories: true } : { cwd: dir, onlyFiles: true });
40
45
  const exists = async (path) => access(path).then(() => true, () => false);
46
+ /**
47
+ * Is this the user's own properties file — as opposed to one Laneyard wrote
48
+ * and failed to clean up?
49
+ *
50
+ * `gradle-properties.ts` marks every file it writes with `LANEYARD_MARKER` as
51
+ * its first line, precisely so this check can tell the two apart. A run killed
52
+ * between writing the file and reaching its `finally` leaves a marked one
53
+ * behind in the persistent clone; counting it as the user's own signing
54
+ * configuration would flip the checklist from "the release build will use the
55
+ * debug key" to "the release key is used" — a green verdict Laneyard
56
+ * manufactured for itself out of a cleanup it failed to run.
57
+ *
58
+ * Reading fails the same way `exists` does: a missing file, a permission
59
+ * error, or one this process cannot open are all "not the user's file",
60
+ * because none of them is evidence of a real signing configuration.
61
+ */
62
+ async function isUsersOwn(path) {
63
+ const text = await readFile(path, "utf8").catch(() => null);
64
+ if (text === null)
65
+ return false;
66
+ return (text.split("\n")[0] ?? "").trimEnd() !== LANEYARD_MARKER;
67
+ }
68
+ /**
69
+ * Is the properties file where the build script would look for it — and is it
70
+ * the user's, not Laneyard's own leftover?
71
+ *
72
+ * The module directory is the one holding the build script, and the Gradle root
73
+ * is its parent — `android/` for an `android/app/build.gradle`. Which of the two
74
+ * the name is relative to is the script's decision, and the parser reports which
75
+ * one it made. When it could not tell, both are looked in: answering "not in the
76
+ * clone" because the wrong directory was searched would have the checklist
77
+ * inventing the very failure it exists to catch. Both places apply the same
78
+ * marker rule — a leftover in either one is still Laneyard's, not the user's.
79
+ */
80
+ async function isPresent(build, file) {
81
+ const { moduleDir, gradleRoot } = build;
82
+ const places = file.scope === "root"
83
+ ? [gradleRoot]
84
+ : file.scope === "module"
85
+ ? [moduleDir]
86
+ : [gradleRoot, moduleDir];
87
+ const found = await Promise.all(places.map((dir) => isUsersOwn(join(dir, file.name))));
88
+ return found.some(Boolean);
89
+ }
90
+ /**
91
+ * What the android build script says about release signing, and whether the
92
+ * file it depends on is in the clone.
93
+ *
94
+ * The listing is the caller's half of the answer, as everywhere else here: the
95
+ * check reads text and reaches for nothing. Which script speaks for the android
96
+ * side is `heuristics/android-root.ts`'s decision rather than this file's,
97
+ * because the runner writes the properties file against that same decision — see
98
+ * that module for why the two must not be able to disagree.
99
+ */
100
+ async function androidSigning(workspacePath, appRoot, unreachable) {
101
+ if (unreachable !== null) {
102
+ return { androidSigning: { ok: false, reason: unreachable }, signingFilePresent: false };
103
+ }
104
+ const build = await findAndroidBuild(join(workspacePath, appRoot));
105
+ if (build === null) {
106
+ return {
107
+ androidSigning: { ok: false, reason: "no android build.gradle found in the clone" },
108
+ signingFilePresent: false,
109
+ };
110
+ }
111
+ const present = build.facts.conditionalOn === null ? false : await isPresent(build, build.facts.conditionalOn);
112
+ return { androidSigning: { ok: true, value: build.facts }, signingFilePresent: present };
113
+ }
114
+ /**
115
+ * What the keystore block says about the properties file, and nothing else.
116
+ *
117
+ * The block has to be decrypted to be asked — `property_names` and
118
+ * `properties_path` are stored with the passphrases — so the narrowing happens
119
+ * here, at the last point that touches plaintext. What crosses into the
120
+ * checklist is two settings a browser is already shown on the block's own form.
121
+ *
122
+ * A block that will not decrypt is not an error page: it is a keystore the
123
+ * checklist cannot speak for, and `credentials` already reports that separately.
124
+ */
125
+ function keystoreSetting(vault, slug) {
126
+ try {
127
+ const block = vault.resolveCredential(slug, "android_keystore");
128
+ if (!block)
129
+ return null;
130
+ const path = (block.fields["properties_path"] ?? "").trim();
131
+ return { propertyNames: propertyNames(block.fields), propertiesPath: path === "" ? null : path };
132
+ }
133
+ catch {
134
+ return null;
135
+ }
136
+ }
41
137
  export async function registerReadinessRoutes(app, ctx) {
42
138
  /**
43
139
  * Computed only when asked for.
@@ -67,14 +163,30 @@ export async function registerReadinessRoutes(app, ctx) {
67
163
  }
68
164
  const resolved = await ctx.config.resolve(slug, workspacePath);
69
165
  const fastlaneDir = resolved?.settings.fastlane_dir ?? "fastlane";
70
- const uses = unreachable !== null
166
+ const read = unreachable !== null
71
167
  ? { ok: false, reason: unreachable }
72
168
  : await ctx
73
169
  .uses(slug, workspacePath, fastlaneDir)
74
- .then((lanes) => ({ ok: true, value: lanes }))
170
+ .then((value) => ({ ok: true, value }))
75
171
  // Broken Fastfile, no Ruby, no fastlane: all of them are "could not
76
172
  // tell", none of them is a 500.
77
173
  .catch((cause) => ({ ok: false, reason: cause.message }));
174
+ const uses = read.ok
175
+ ? { ok: true, value: read.value.lanes }
176
+ : { ok: false, reason: read.reason };
177
+ // What reading the Fastfile could not account for. `fastlane/actions` is the
178
+ // caller's half of the answer — a directory listing, not something the Ruby
179
+ // parser could know — and the sidecar supplies the other, `import`. A check
180
+ // that would conclude something from finding nothing consults this first.
181
+ const unread = read.ok
182
+ ? {
183
+ ok: true,
184
+ value: {
185
+ imports: read.value.imports,
186
+ customActions: await exists(join(workspacePath, fastlaneDir, "actions")),
187
+ },
188
+ }
189
+ : { ok: false, reason: read.reason };
78
190
  // What the project builds for decides which half of the checklist applies.
79
191
  // `laneyard.yml` answers on its own; without it the workspace is looked at,
80
192
  // and an unreachable workspace is a "could not tell" rather than a claim
@@ -82,7 +194,29 @@ export async function registerReadinessRoutes(app, ctx) {
82
194
  const configured = resolved?.settings.platforms;
83
195
  const platforms = unreachable !== null && (configured === undefined || configured.length === 0)
84
196
  ? { ok: false, reason: unreachable }
85
- : { ok: true, value: await resolvePlatforms(configured, findIn(workspacePath)) };
197
+ : {
198
+ ok: true,
199
+ // Beside the Fastfile rather than at the repository root: in a
200
+ // monorepo the app is one directory down, and so are its platform
201
+ // folders.
202
+ value: await resolvePlatforms(configured, findIn(searchDir(workspacePath, appRootOf(fastlaneDir)))),
203
+ };
204
+ // The Appfile is fastlane's own file, beside the Fastfile, and it is where a
205
+ // project configured long before it met Laneyard keeps its Play Store
206
+ // service account. An absent one is a fact — `NO_APPFILE` — not a failure;
207
+ // an unreachable workspace is the only reason this cannot be answered.
208
+ const appfile = unreachable !== null
209
+ ? { ok: false, reason: unreachable }
210
+ : await readFile(join(workspacePath, fastlaneDir, "Appfile"), "utf8").then((text) => ({ ok: true, value: parseAppfile(text) }),
211
+ // Missing, unreadable, a directory: all of them mean the same to a
212
+ // check, which is that the Appfile says nothing.
213
+ () => ({ ok: true, value: NO_APPFILE }));
214
+ // Listed the same way platforms are, from the clone rather than from any
215
+ // path a Fastfile mentions: what is asked is "does the repository carry a
216
+ // key", which is a question about the repository.
217
+ const keyFilesInRepo = unreachable !== null
218
+ ? { ok: false, reason: unreachable }
219
+ : await glob(["**/*.p8"], { cwd: workspacePath, onlyFiles: true, dot: true }).then((found) => ({ ok: true, value: found.sort() }), (cause) => ({ ok: false, reason: cause.message }));
86
220
  const sections = await runChecklist({
87
221
  probeRepository: () => workspace.probeRemote(),
88
222
  dependencies: {
@@ -94,8 +228,30 @@ export async function registerReadinessRoutes(app, ctx) {
94
228
  },
95
229
  // Names only: the vault never hands a value to anything but a run.
96
230
  secretKeys: ctx.vault.list(slug).map((s) => s.key),
231
+ // Which blocks apply, resolved the way a run resolves them — a project's
232
+ // own shadowing a global one — so the checklist and the run cannot
233
+ // disagree about whether a credential exists.
234
+ blocks: ctx.vault.listCredentials(slug).map((c) => c.kind),
235
+ // And the names those blocks will export, which the environment check
236
+ // counts as supplied — Laneyard writes the file and sets the variable
237
+ // itself, so a lane reading it is not a lane short of anything. The same
238
+ // list the secrets screen is given, from the same call.
239
+ blockNames: exportedVarNames(ctx.vault.listCredentials(slug)),
240
+ keystore: keystoreSetting(ctx.vault, slug),
97
241
  uses,
98
242
  platforms,
243
+ appfile,
244
+ keyFilesInRepo,
245
+ unread,
246
+ // A run inherits the server's environment, so a variable exported where
247
+ // Laneyard was started really is available to a lane. Names only: a
248
+ // checklist has no business reading a value, here least of all.
249
+ serverEnv: Object.keys(process.env),
250
+ ...(await androidSigning(workspacePath, appRootOf(fastlaneDir), unreachable)),
251
+ declaredSecrets: [
252
+ ...(resolved?.settings.required_secrets ?? []),
253
+ ...(await envExampleNames(workspacePath, fastlaneDir)),
254
+ ],
99
255
  });
100
256
  return { checkedAt: new Date().toISOString(), sections };
101
257
  });
@@ -1,4 +1,6 @@
1
1
  import { MIN_LENGTH as MIN_REDACTABLE } from "../../logs/redact.js";
2
+ import { exportedVarNames } from "../../credentials/kinds.js";
3
+ import { requiredSecrets } from "../required-secrets.js";
2
4
  /** POSIX environment variable names. Anything else would never reach fastlane. */
3
5
  const VALID_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;
4
6
  export async function registerSecretRoutes(app, ctx) {
@@ -39,6 +41,105 @@ export async function registerSecretRoutes(app, ctx) {
39
41
  return reply.code(404).send({ error: "Unknown project" });
40
42
  return put(slug, key, req.body, reply);
41
43
  });
44
+ /**
45
+ * One value, in the clear — and only one that was never declared secret.
46
+ *
47
+ * A separate route rather than a field on the listing, so that reading a value
48
+ * is always a deliberate request for one named key. A listing that carried
49
+ * values would put every one of them in a browser at once, for a page most
50
+ * people open to check a name.
51
+ */
52
+ app.get("/api/projects/:slug/secrets/:key/value", async (req, reply) => {
53
+ const { slug, key } = req.params;
54
+ if (!ctx.config.project(slug))
55
+ return reply.code(404).send({ error: "Unknown project" });
56
+ try {
57
+ const value = ctx.vault.reveal(slug, key);
58
+ if (value === null)
59
+ return reply.code(404).send({ error: "Unknown secret" });
60
+ return { key, value };
61
+ }
62
+ catch (cause) {
63
+ // The vault refuses a masked value whoever asks. 409 rather than 403: the
64
+ // request is not forbidden to this account, it is refused for this secret.
65
+ return reply.code(409).send({ error: cause.message });
66
+ }
67
+ });
68
+ /**
69
+ * Turns the redaction on or off, leaving the value alone.
70
+ *
71
+ * Needed because of a circle: to read a value you must first declare it not
72
+ * secret, and declaring that by storing it again would mean typing the value
73
+ * you were trying to read.
74
+ */
75
+ app.patch("/api/projects/:slug/secrets/:key", async (req, reply) => {
76
+ const { slug, key } = req.params;
77
+ if (!ctx.config.project(slug))
78
+ return reply.code(404).send({ error: "Unknown project" });
79
+ const { masked } = (req.body ?? {});
80
+ if (typeof masked !== "boolean") {
81
+ return reply.code(400).send({ error: "`masked` is true or false." });
82
+ }
83
+ const existing = ctx.vault.list(slug).find((s) => s.key === key);
84
+ if (!existing)
85
+ return reply.code(404).send({ error: "Unknown secret" });
86
+ if (existing.scope === "global") {
87
+ // The same rule the interface draws: a global secret belongs to every
88
+ // project, so changing it from inside one would hide that from the rest.
89
+ return reply.code(409).send({ error: "That is a global secret. Change it with `laneyard secret set`." });
90
+ }
91
+ // A value too short to redact cannot be masked, the same refusal as on the
92
+ // way in — accepting it would leave someone believing they are protected.
93
+ if (masked) {
94
+ const value = ctx.vault.reveal(slug, key);
95
+ if (value !== null && value.length < MIN_REDACTABLE) {
96
+ return reply.code(400).send({
97
+ error: `A value kept out of the logs must be at least ${MIN_REDACTABLE} characters.`,
98
+ });
99
+ }
100
+ }
101
+ ctx.vault.setMasked(slug, key, masked);
102
+ return reply.code(204).send();
103
+ });
104
+ /**
105
+ * The names this project needs, and which of them are still missing.
106
+ *
107
+ * Exists so the secrets screen can put the form up with the names already in
108
+ * it. Someone arriving here has just been told by the checklist that eight
109
+ * variables are missing; retyping those eight names by hand, correctly, is a
110
+ * chore where one typo stores a secret nothing will ever read.
111
+ *
112
+ * Names only, and never a value from anywhere: the file that holds the real
113
+ * ones is the file that does not reach a clone, which is the problem rather
114
+ * than a source. What goes in the boxes is typed by a person.
115
+ */
116
+ app.get("/api/projects/:slug/required-secrets", async (req, reply) => {
117
+ const { slug } = req.params;
118
+ if (!ctx.config.project(slug))
119
+ return reply.code(404).send({ error: "Unknown project" });
120
+ const workspacePath = ctx.workspacePath(slug);
121
+ const resolved = await ctx.config.resolve(slug, workspacePath);
122
+ const fastlaneDir = resolved?.settings.fastlane_dir ?? "fastlane";
123
+ // A workspace that was never cloned, or a Fastfile that will not parse, is
124
+ // a reason to offer nothing — not a reason to fail the page someone opened
125
+ // to store a secret by hand.
126
+ const lanes = await ctx
127
+ .uses(slug, workspacePath, fastlaneDir)
128
+ .then((u) => u.lanes)
129
+ .catch(() => []);
130
+ return requiredSecrets({
131
+ lanes,
132
+ declared: resolved?.settings.required_secrets ?? [],
133
+ workspacePath,
134
+ fastlaneDir,
135
+ vaultKeys: ctx.vault.list(slug).map((s) => s.key),
136
+ // Resolved the way a run resolves them, a project's own block shadowing a
137
+ // global one, so the form and the checklist cannot disagree about what is
138
+ // already supplied.
139
+ blockNames: exportedVarNames(ctx.vault.listCredentials(slug)),
140
+ serverEnv: Object.keys(process.env),
141
+ });
142
+ });
42
143
  app.delete("/api/secrets/:key", async (req, reply) => {
43
144
  const removed = ctx.vault.remove(null, req.params.key);
44
145
  return removed ? reply.code(204).send() : reply.code(404).send({ error: "Unknown secret" });
@@ -1,5 +1,6 @@
1
1
  import { execFile } from "node:child_process";
2
- import { existsSync } from "node:fs";
2
+ import { createHash } from "node:crypto";
3
+ import { existsSync, readFileSync } from "node:fs";
3
4
  import { dirname, join } from "node:path";
4
5
  import { fileURLToPath } from "node:url";
5
6
  import { promisify } from "node:util";
@@ -21,6 +22,25 @@ export function resolveSidecarScript(moduleDir) {
21
22
  return candidates.find((candidate) => existsSync(candidate)) ?? candidates[0];
22
23
  }
23
24
  const SCRIPT = resolveSidecarScript(dirname(fileURLToPath(import.meta.url)));
25
+ /**
26
+ * A digest of the sidecar script, for whoever caches what it produced.
27
+ *
28
+ * Caching introspection on the fastlane folder's contents alone is wrong in one
29
+ * direction that is easy to miss: the answer depends on the *reader* as much as
30
+ * on what is read. Teaching the parser to follow a lane into the methods it
31
+ * calls changed what a Fastfile means without changing the Fastfile, so every
32
+ * existing install went on being served the answer from before — a Play Store
33
+ * check reporting "no lane uploads", permanently, on a project that uploads.
34
+ *
35
+ * Hashing the script rather than bumping a constant is what keeps that from
36
+ * happening again: there is nothing to remember. Read once, because the file
37
+ * cannot change under a running process that already loaded it.
38
+ */
39
+ let scriptDigest = null;
40
+ export function sidecarVersion() {
41
+ scriptDigest ??= createHash("sha256").update(readFileSync(SCRIPT)).digest("hex").slice(0, 16);
42
+ return scriptDigest;
43
+ }
24
44
  /**
25
45
  * Runs the sidecar in the project's context.
26
46
  * In `bundle` mode, the invocation goes through `bundle exec` to see the
@@ -0,0 +1,23 @@
1
+ import { stat } from "node:fs/promises";
2
+ /**
3
+ * Refuses a missing fastlane directory with a sentence instead of an ENOENT.
4
+ *
5
+ * The raw error read `ENOENT: no such file or directory, scandir
6
+ * '…/workspaces/popotheque-app/fastlane'` — technically accurate and no help at
7
+ * all, because the interesting part is *why* it was looking there.
8
+ *
9
+ * It is nearly always the same story. `laneyard setup` writes `laneyard.yml`
10
+ * into the working copy, and Laneyard builds from a clone of the remote, so the
11
+ * file that says where fastlane lives does not reach the clone until it is
12
+ * committed and pushed. Until then `fastlane_dir` falls back to `fastlane`,
13
+ * which in a monorepo is not where anything is.
14
+ */
15
+ export async function assertFastlaneDir(dir, configured) {
16
+ const found = await stat(dir).then((s) => s.isDirectory(), () => false);
17
+ if (found)
18
+ return;
19
+ throw new Error(`No ${configured}/ in the clone. Laneyard builds from a clone of the remote, ` +
20
+ "so `laneyard.yml` only takes effect once it is committed and pushed — " +
21
+ "until then this falls back to `fastlane`. Push it, or set `fastlane_dir` " +
22
+ "on the project's block in config.yml.");
23
+ }
@@ -1,13 +1,19 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { readdir, readFile } from "node:fs/promises";
3
3
  import { join } from "node:path";
4
+ import { sidecarVersion } from "./bridge.js";
5
+ import { assertFastlaneDir } from "./fastlane-dir.js";
4
6
  /**
5
7
  * Hash of the whole fastlane folder, not just the Fastfile:
6
8
  * an Appfile, a Pluginfile, or an imported file change the lanes just as much.
7
9
  */
8
10
  async function hashFastlaneDir(root, fastlaneDir) {
9
11
  const dir = join(root, fastlaneDir);
12
+ await assertFastlaneDir(dir, fastlaneDir);
10
13
  const hash = createHash("sha256");
14
+ // Same reason as in `uses.ts`: the reader is part of the key, so improving the
15
+ // sidecar cannot leave an install served by what the old one concluded.
16
+ hash.update(sidecarVersion());
11
17
  const entries = (await readdir(dir, { withFileTypes: true, recursive: true }))
12
18
  .filter((e) => e.isFile())
13
19
  .map((e) => join(e.parentPath, e.name))
@@ -1,13 +1,20 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { readdir, readFile } from "node:fs/promises";
3
3
  import { join } from "node:path";
4
+ import { sidecarVersion } from "./bridge.js";
5
+ import { assertFastlaneDir } from "./fastlane-dir.js";
4
6
  /**
5
7
  * Hash of the whole fastlane folder, not just the Fastfile:
6
8
  * an Appfile, a Pluginfile, or an imported file change the lanes just as much.
7
9
  */
8
10
  async function hashFastlaneDir(root, fastlaneDir) {
9
11
  const dir = join(root, fastlaneDir);
12
+ await assertFastlaneDir(dir, fastlaneDir);
10
13
  const hash = createHash("sha256");
14
+ // The sidecar is part of the question, not just the answer: a parser that
15
+ // learns to read more finds more in a Fastfile that never changed, and a key
16
+ // built from the folder alone would serve the old reading for ever.
17
+ hash.update(sidecarVersion());
11
18
  const entries = (await readdir(dir, { withFileTypes: true, recursive: true }))
12
19
  .filter((e) => e.isFile())
13
20
  .map((e) => join(e.parentPath, e.name))
@@ -28,13 +35,22 @@ export class UsesReader {
28
35
  async read(slug, workspacePath, fastlaneDir) {
29
36
  const hash = await hashFastlaneDir(workspacePath, fastlaneDir);
30
37
  const cached = this.cache.get(slug, "uses", hash);
31
- if (cached)
32
- return cached;
38
+ // An entry cached before `imports` existed is an array, not an object. Read
39
+ // as "nothing known to be hidden", which is what it meant when it was
40
+ // written — rather than throwing away a cache on every upgrade.
41
+ if (cached) {
42
+ return Array.isArray(cached)
43
+ ? { lanes: cached, imports: false }
44
+ : cached;
45
+ }
33
46
  const res = await this.invoke("uses", workspacePath, fastlaneDir);
34
47
  if (!res.ok)
35
48
  throw new Error(res.error);
36
- const lanes = res["lanes"];
37
- this.cache.put(slug, "uses", hash, lanes);
38
- return lanes;
49
+ const uses = {
50
+ lanes: res["lanes"],
51
+ imports: res["imports"] === true,
52
+ };
53
+ this.cache.put(slug, "uses", hash, uses);
54
+ return uses;
39
55
  }
40
56
  }
@@ -1,4 +1,4 @@
1
- import{r as Fn,j as Eh}from"./index-TWRQ1cJg.js";let hs=[],tl=[];(()=>{let n="lc,34,7n,7,7b,19,,,,2,,2,,,20,b,1c,l,g,,2t,7,2,6,2,2,,4,z,,u,r,2j,b,1m,9,9,,o,4,,9,,3,,5,17,3,3b,f,,w,1j,,,,4,8,4,,3,7,a,2,t,,1m,,,,2,4,8,,9,,a,2,q,,2,2,1l,,4,2,4,2,2,3,3,,u,2,3,,b,2,1l,,4,5,,2,4,,k,2,m,6,,,1m,,,2,,4,8,,7,3,a,2,u,,1n,,,,c,,9,,14,,3,,1l,3,5,3,,4,7,2,b,2,t,,1m,,2,,2,,3,,5,2,7,2,b,2,s,2,1l,2,,,2,4,8,,9,,a,2,t,,20,,4,,2,3,,,8,,29,,2,7,c,8,2q,,2,9,b,6,22,2,r,,,,,,1j,e,,5,,2,5,b,,10,9,,2u,4,,6,,2,2,2,p,2,4,3,g,4,d,,2,2,6,,f,,jj,3,qa,3,t,3,t,2,u,2,1s,2,,7,8,,2,b,9,,19,3,3b,2,y,,3a,3,4,2,9,,6,3,63,2,2,,1m,,,7,,,,,2,8,6,a,2,,1c,h,1r,4,1c,7,,,5,,14,9,c,2,w,4,2,2,,3,1k,,,2,3,,,3,1m,8,2,2,48,3,,d,,7,4,,6,,3,2,5i,1m,,5,ek,,5f,x,2da,3,3x,,2o,w,fe,6,2x,2,n9w,4,,a,w,2,28,2,7k,,3,,4,,p,2,5,,47,2,q,i,d,,12,8,p,b,1a,3,1c,,2,4,2,2,13,,1v,6,2,2,2,2,c,,8,,1b,,1f,,,3,2,2,5,2,,,16,2,8,,6m,,2,,4,,fn4,,kh,g,g,g,a6,2,gt,,6a,,45,5,1ae,3,,2,5,4,14,3,4,,4l,2,fx,4,ar,2,49,b,4w,,1i,f,1k,3,1d,4,2,2,1x,3,10,5,,8,1q,,c,2,1g,9,a,4,2,,2n,3,2,,,2,6,,4g,,3,8,l,2,1l,2,,,,,m,,e,7,3,5,5f,8,2,3,,,n,,29,,2,6,,,2,,,2,,2,6j,,2,4,6,2,,2,r,2,2d,8,2,,,2,2y,,,,2,6,,,2t,3,2,4,,5,77,9,,2,6t,,a,2,,,4,,40,4,2,2,4,,w,a,14,6,2,4,8,,9,6,2,3,1a,d,,2,ba,7,,6,,,2a,m,2,7,,2,,2,3e,6,3,,,2,,7,,,20,2,3,,,,9n,2,f0b,5,1n,7,t4,,1r,4,29,,f5k,2,43q,,,3,4,5,8,8,2,7,u,4,44,3,1iz,1j,4,1e,8,,e,,m,5,,f,11s,7,,h,2,7,,2,,5,79,7,c5,4,15s,7,31,7,240,5,gx7k,2o,3k,6o".split(",").map(e=>e?parseInt(e,36):1);for(let e=0,t=0;e<n.length;e++)(e%2?tl:hs).push(t=t+n[e])})();function Rh(n){if(n<768)return!1;for(let e=0,t=hs.length;;){let i=e+t>>1;if(n<hs[i])t=i;else if(n>=tl[i])e=i+1;else return!0;if(e==t)return!1}}function Pr(n){return n>=127462&&n<=127487}const Ir=8205;function Ph(n,e,t=!0,i=!0){return(t?il:Ih)(n,e,i)}function il(n,e,t){if(e==n.length)return e;e&&nl(n.charCodeAt(e))&&sl(n.charCodeAt(e-1))&&e--;let i=Hn(n,e);for(e+=Nr(i);e<n.length;){let s=Hn(n,e);if(i==Ir||s==Ir||t&&Rh(s))e+=Nr(s),i=s;else if(Pr(s)){let r=0,o=e-2;for(;o>=0&&Pr(Hn(n,o));)r++,o-=2;if(r%2==0)break;e+=2}else break}return e}function Ih(n,e,t){for(;e>1;){let i=il(n,e-2,t);if(i<e)return i;e--}return 0}function Hn(n,e){let t=n.charCodeAt(e);if(!sl(t)||e+1==n.length)return t;let i=n.charCodeAt(e+1);return nl(i)?(t-55296<<10)+(i-56320)+65536:t}function nl(n){return n>=56320&&n<57344}function sl(n){return n>=55296&&n<56320}function Nr(n){return n<65536?1:2}class W{lineAt(e){if(e<0||e>this.length)throw new RangeError(`Invalid position ${e} in document of length ${this.length}`);return this.lineInner(e,!1,1,0)}line(e){if(e<1||e>this.lines)throw new RangeError(`Invalid line number ${e} in ${this.lines}-line document`);return this.lineInner(e,!0,1,0)}replace(e,t,i){[e,t]=Ht(this,e,t);let s=[];return this.decompose(0,e,s,2),i.length&&i.decompose(0,i.length,s,3),this.decompose(t,this.length,s,1),Ve.from(s,this.length-(t-e)+i.length)}append(e){return this.replace(this.length,this.length,e)}slice(e,t=this.length){[e,t]=Ht(this,e,t);let i=[];return this.decompose(e,t,i,0),Ve.from(i,t-e)}eq(e){if(e==this)return!0;if(e.length!=this.length||e.lines!=this.lines)return!1;let t=this.scanIdentical(e,1),i=this.length-this.scanIdentical(e,-1),s=new ri(this),r=new ri(e);for(let o=t,l=t;;){if(s.next(o),r.next(o),o=0,s.lineBreak!=r.lineBreak||s.done!=r.done||s.value!=r.value)return!1;if(l+=s.value.length,s.done||l>=i)return!0}}iter(e=1){return new ri(this,e)}iterRange(e,t=this.length){return new rl(this,e,t)}iterLines(e,t){let i;if(e==null)i=this.iter();else{t==null&&(t=this.lines+1);let s=this.line(e).from;i=this.iterRange(s,Math.max(s,t==this.lines+1?this.length:t<=1?0:this.line(t-1).to))}return new ol(i)}toString(){return this.sliceString(0)}toJSON(){let e=[];return this.flatten(e),e}constructor(){}static of(e){if(e.length==0)throw new RangeError("A document must have at least one line");return e.length==1&&!e[0]?W.empty:e.length<=32?new J(e):Ve.from(J.split(e,[]))}}class J extends W{constructor(e,t=Nh(e)){super(),this.text=e,this.length=t}get lines(){return this.text.length}get children(){return null}lineInner(e,t,i,s){for(let r=0;;r++){let o=this.text[r],l=s+o.length;if((t?i:l)>=e)return new Wh(s,l,i,o);s=l+1,i++}}decompose(e,t,i,s){let r=e<=0&&t>=this.length?this:new J(Wr(this.text,e,t),Math.min(t,this.length)-Math.max(0,e));if(s&1){let o=i.pop(),l=Yi(r.text,o.text.slice(),0,r.length);if(l.length<=32)i.push(new J(l,o.length+r.length));else{let a=l.length>>1;i.push(new J(l.slice(0,a)),new J(l.slice(a)))}}else i.push(r)}replace(e,t,i){if(!(i instanceof J))return super.replace(e,t,i);[e,t]=Ht(this,e,t);let s=Yi(this.text,Yi(i.text,Wr(this.text,0,e)),t),r=this.length+i.length-(t-e);return s.length<=32?new J(s,r):Ve.from(J.split(s,[]),r)}sliceString(e,t=this.length,i=`
1
+ import{r as Fn,j as Eh}from"./index-pzPa9EZr.js";let hs=[],tl=[];(()=>{let n="lc,34,7n,7,7b,19,,,,2,,2,,,20,b,1c,l,g,,2t,7,2,6,2,2,,4,z,,u,r,2j,b,1m,9,9,,o,4,,9,,3,,5,17,3,3b,f,,w,1j,,,,4,8,4,,3,7,a,2,t,,1m,,,,2,4,8,,9,,a,2,q,,2,2,1l,,4,2,4,2,2,3,3,,u,2,3,,b,2,1l,,4,5,,2,4,,k,2,m,6,,,1m,,,2,,4,8,,7,3,a,2,u,,1n,,,,c,,9,,14,,3,,1l,3,5,3,,4,7,2,b,2,t,,1m,,2,,2,,3,,5,2,7,2,b,2,s,2,1l,2,,,2,4,8,,9,,a,2,t,,20,,4,,2,3,,,8,,29,,2,7,c,8,2q,,2,9,b,6,22,2,r,,,,,,1j,e,,5,,2,5,b,,10,9,,2u,4,,6,,2,2,2,p,2,4,3,g,4,d,,2,2,6,,f,,jj,3,qa,3,t,3,t,2,u,2,1s,2,,7,8,,2,b,9,,19,3,3b,2,y,,3a,3,4,2,9,,6,3,63,2,2,,1m,,,7,,,,,2,8,6,a,2,,1c,h,1r,4,1c,7,,,5,,14,9,c,2,w,4,2,2,,3,1k,,,2,3,,,3,1m,8,2,2,48,3,,d,,7,4,,6,,3,2,5i,1m,,5,ek,,5f,x,2da,3,3x,,2o,w,fe,6,2x,2,n9w,4,,a,w,2,28,2,7k,,3,,4,,p,2,5,,47,2,q,i,d,,12,8,p,b,1a,3,1c,,2,4,2,2,13,,1v,6,2,2,2,2,c,,8,,1b,,1f,,,3,2,2,5,2,,,16,2,8,,6m,,2,,4,,fn4,,kh,g,g,g,a6,2,gt,,6a,,45,5,1ae,3,,2,5,4,14,3,4,,4l,2,fx,4,ar,2,49,b,4w,,1i,f,1k,3,1d,4,2,2,1x,3,10,5,,8,1q,,c,2,1g,9,a,4,2,,2n,3,2,,,2,6,,4g,,3,8,l,2,1l,2,,,,,m,,e,7,3,5,5f,8,2,3,,,n,,29,,2,6,,,2,,,2,,2,6j,,2,4,6,2,,2,r,2,2d,8,2,,,2,2y,,,,2,6,,,2t,3,2,4,,5,77,9,,2,6t,,a,2,,,4,,40,4,2,2,4,,w,a,14,6,2,4,8,,9,6,2,3,1a,d,,2,ba,7,,6,,,2a,m,2,7,,2,,2,3e,6,3,,,2,,7,,,20,2,3,,,,9n,2,f0b,5,1n,7,t4,,1r,4,29,,f5k,2,43q,,,3,4,5,8,8,2,7,u,4,44,3,1iz,1j,4,1e,8,,e,,m,5,,f,11s,7,,h,2,7,,2,,5,79,7,c5,4,15s,7,31,7,240,5,gx7k,2o,3k,6o".split(",").map(e=>e?parseInt(e,36):1);for(let e=0,t=0;e<n.length;e++)(e%2?tl:hs).push(t=t+n[e])})();function Rh(n){if(n<768)return!1;for(let e=0,t=hs.length;;){let i=e+t>>1;if(n<hs[i])t=i;else if(n>=tl[i])e=i+1;else return!0;if(e==t)return!1}}function Pr(n){return n>=127462&&n<=127487}const Ir=8205;function Ph(n,e,t=!0,i=!0){return(t?il:Ih)(n,e,i)}function il(n,e,t){if(e==n.length)return e;e&&nl(n.charCodeAt(e))&&sl(n.charCodeAt(e-1))&&e--;let i=Hn(n,e);for(e+=Nr(i);e<n.length;){let s=Hn(n,e);if(i==Ir||s==Ir||t&&Rh(s))e+=Nr(s),i=s;else if(Pr(s)){let r=0,o=e-2;for(;o>=0&&Pr(Hn(n,o));)r++,o-=2;if(r%2==0)break;e+=2}else break}return e}function Ih(n,e,t){for(;e>1;){let i=il(n,e-2,t);if(i<e)return i;e--}return 0}function Hn(n,e){let t=n.charCodeAt(e);if(!sl(t)||e+1==n.length)return t;let i=n.charCodeAt(e+1);return nl(i)?(t-55296<<10)+(i-56320)+65536:t}function nl(n){return n>=56320&&n<57344}function sl(n){return n>=55296&&n<56320}function Nr(n){return n<65536?1:2}class W{lineAt(e){if(e<0||e>this.length)throw new RangeError(`Invalid position ${e} in document of length ${this.length}`);return this.lineInner(e,!1,1,0)}line(e){if(e<1||e>this.lines)throw new RangeError(`Invalid line number ${e} in ${this.lines}-line document`);return this.lineInner(e,!0,1,0)}replace(e,t,i){[e,t]=Ht(this,e,t);let s=[];return this.decompose(0,e,s,2),i.length&&i.decompose(0,i.length,s,3),this.decompose(t,this.length,s,1),Ve.from(s,this.length-(t-e)+i.length)}append(e){return this.replace(this.length,this.length,e)}slice(e,t=this.length){[e,t]=Ht(this,e,t);let i=[];return this.decompose(e,t,i,0),Ve.from(i,t-e)}eq(e){if(e==this)return!0;if(e.length!=this.length||e.lines!=this.lines)return!1;let t=this.scanIdentical(e,1),i=this.length-this.scanIdentical(e,-1),s=new ri(this),r=new ri(e);for(let o=t,l=t;;){if(s.next(o),r.next(o),o=0,s.lineBreak!=r.lineBreak||s.done!=r.done||s.value!=r.value)return!1;if(l+=s.value.length,s.done||l>=i)return!0}}iter(e=1){return new ri(this,e)}iterRange(e,t=this.length){return new rl(this,e,t)}iterLines(e,t){let i;if(e==null)i=this.iter();else{t==null&&(t=this.lines+1);let s=this.line(e).from;i=this.iterRange(s,Math.max(s,t==this.lines+1?this.length:t<=1?0:this.line(t-1).to))}return new ol(i)}toString(){return this.sliceString(0)}toJSON(){let e=[];return this.flatten(e),e}constructor(){}static of(e){if(e.length==0)throw new RangeError("A document must have at least one line");return e.length==1&&!e[0]?W.empty:e.length<=32?new J(e):Ve.from(J.split(e,[]))}}class J extends W{constructor(e,t=Nh(e)){super(),this.text=e,this.length=t}get lines(){return this.text.length}get children(){return null}lineInner(e,t,i,s){for(let r=0;;r++){let o=this.text[r],l=s+o.length;if((t?i:l)>=e)return new Wh(s,l,i,o);s=l+1,i++}}decompose(e,t,i,s){let r=e<=0&&t>=this.length?this:new J(Wr(this.text,e,t),Math.min(t,this.length)-Math.max(0,e));if(s&1){let o=i.pop(),l=Yi(r.text,o.text.slice(),0,r.length);if(l.length<=32)i.push(new J(l,o.length+r.length));else{let a=l.length>>1;i.push(new J(l.slice(0,a)),new J(l.slice(a)))}}else i.push(r)}replace(e,t,i){if(!(i instanceof J))return super.replace(e,t,i);[e,t]=Ht(this,e,t);let s=Yi(this.text,Yi(i.text,Wr(this.text,0,e)),t),r=this.length+i.length-(t-e);return s.length<=32?new J(s,r):Ve.from(J.split(s,[]),r)}sliceString(e,t=this.length,i=`
2
2
  `){[e,t]=Ht(this,e,t);let s="";for(let r=0,o=0;r<=t&&o<this.text.length;o++){let l=this.text[o],a=r+l.length;r>e&&o&&(s+=i),e<a&&t>r&&(s+=l.slice(Math.max(0,e-r),t-r)),r=a+1}return s}flatten(e){for(let t of this.text)e.push(t)}scanIdentical(){return 0}static split(e,t){let i=[],s=-1;for(let r of e)i.push(r),s+=r.length+1,i.length==32&&(t.push(new J(i,s)),i=[],s=-1);return s>-1&&t.push(new J(i,s)),t}}class Ve extends W{constructor(e,t){super(),this.children=e,this.length=t,this.lines=0;for(let i of e)this.lines+=i.lines}lineInner(e,t,i,s){for(let r=0;;r++){let o=this.children[r],l=s+o.length,a=i+o.lines-1;if((t?a:l)>=e)return o.lineInner(e,t,i,s);s=l+1,i=a+1}}decompose(e,t,i,s){for(let r=0,o=0;o<=t&&r<this.children.length;r++){let l=this.children[r],a=o+l.length;if(e<=a&&t>=o){let h=s&((o<=e?1:0)|(a>=t?2:0));o>=e&&a<=t&&!h?i.push(l):l.decompose(e-o,t-o,i,h)}o=a+1}}replace(e,t,i){if([e,t]=Ht(this,e,t),i.lines<this.lines)for(let s=0,r=0;s<this.children.length;s++){let o=this.children[s],l=r+o.length;if(e>=r&&t<=l){let a=o.replace(e-r,t-r,i),h=this.lines-o.lines+a.lines;if(a.lines<h>>4&&a.lines>h>>6){let c=this.children.slice();return c[s]=a,new Ve(c,this.length-(t-e)+i.length)}return super.replace(r,l,a)}r=l+1}return super.replace(e,t,i)}sliceString(e,t=this.length,i=`
3
3
  `){[e,t]=Ht(this,e,t);let s="";for(let r=0,o=0;r<this.children.length&&o<=t;r++){let l=this.children[r],a=o+l.length;o>e&&r&&(s+=i),e<a&&t>o&&(s+=l.sliceString(e-o,t-o,i)),o=a+1}return s}flatten(e){for(let t of this.children)t.flatten(e)}scanIdentical(e,t){if(!(e instanceof Ve))return 0;let i=0,[s,r,o,l]=t>0?[0,0,this.children.length,e.children.length]:[this.children.length-1,e.children.length-1,-1,-1];for(;;s+=t,r+=t){if(s==o||r==l)return i;let a=this.children[s],h=e.children[r];if(a!=h)return i+a.scanIdentical(h,t);i+=a.length+1}}static from(e,t=e.reduce((i,s)=>i+s.length+1,-1)){let i=0;for(let d of e)i+=d.lines;if(i<32){let d=[];for(let p of e)p.flatten(d);return new J(d,t)}let s=Math.max(32,i>>5),r=s<<1,o=s>>1,l=[],a=0,h=-1,c=[];function f(d){let p;if(d.lines>r&&d instanceof Ve)for(let g of d.children)f(g);else d.lines>o&&(a>o||!a)?(u(),l.push(d)):d instanceof J&&a&&(p=c[c.length-1])instanceof J&&d.lines+p.lines<=32?(a+=d.lines,h+=d.length+1,c[c.length-1]=new J(p.text.concat(d.text),p.length+1+d.length)):(a+d.lines>s&&u(),a+=d.lines,h+=d.length+1,c.push(d))}function u(){a!=0&&(l.push(c.length==1?c[0]:Ve.from(c,h)),h=-1,a=c.length=0)}for(let d of e)f(d);return u(),l.length==1?l[0]:new Ve(l,t)}}W.empty=new J([""],0);function Nh(n){let e=-1;for(let t of n)e+=t.length+1;return e}function Yi(n,e,t=0,i=1e9){for(let s=0,r=0,o=!0;r<n.length&&s<=i;r++){let l=n[r],a=s+l.length;a>=t&&(a>i&&(l=l.slice(0,i-s)),s<t&&(l=l.slice(t-s)),o?(e[e.length-1]+=l,o=!1):e.push(l)),s=a+1}return e}function Wr(n,e,t){return Yi(n,[""],e,t)}class ri{constructor(e,t=1){this.dir=t,this.done=!1,this.lineBreak=!1,this.value="",this.nodes=[e],this.offsets=[t>0?1:(e instanceof J?e.text.length:e.children.length)<<1]}nextInner(e,t){for(this.done=this.lineBreak=!1;;){let i=this.nodes.length-1,s=this.nodes[i],r=this.offsets[i],o=r>>1,l=s instanceof J?s.text.length:s.children.length;if(o==(t>0?l:0)){if(i==0)return this.done=!0,this.value="",this;t>0&&this.offsets[i-1]++,this.nodes.pop(),this.offsets.pop()}else if((r&1)==(t>0?0:1)){if(this.offsets[i]+=t,e==0)return this.lineBreak=!0,this.value=`
4
4
  `,this;e--}else if(s instanceof J){let a=s.text[o+(t<0?-1:0)];if(this.offsets[i]+=t,a.length>Math.max(0,e))return this.value=e==0?a:t>0?a.slice(e):a.slice(0,a.length-e),this;e-=a.length}else{let a=s.children[o+(t<0?-1:0)];e>a.length?(e-=a.length,this.offsets[i]+=t):(t<0&&this.offsets[i]--,this.nodes.push(a),this.offsets.push(t>0?1:(a instanceof J?a.text.length:a.children.length)<<1))}}}next(e=0){return e<0&&(this.nextInner(-e,-this.dir),e=this.value.length),this.nextInner(e,this.dir)}}class rl{constructor(e,t,i){this.value="",this.done=!1,this.cursor=new ri(e,t>i?-1:1),this.pos=t>i?e.length:0,this.from=Math.min(t,i),this.to=Math.max(t,i)}nextInner(e,t){if(t<0?this.pos<=this.from:this.pos>=this.to)return this.value="",this.done=!0,this;e+=Math.max(0,t<0?this.pos-this.to:this.from-this.pos);let i=t<0?this.pos-this.from:this.to-this.pos;e>i&&(e=i),i-=e;let{value:s}=this.cursor.next(e);return this.pos+=(s.length+e)*t,this.value=s.length<=i?s:t<0?s.slice(s.length-i):s.slice(0,i),this.done=!this.value,this}next(e=0){return e<0?e=Math.max(e,this.from-this.pos):e>0&&(e=Math.min(e,this.to-this.pos)),this.nextInner(e,this.cursor.dir)}get lineBreak(){return this.cursor.lineBreak&&this.value!=""}}class ol{constructor(e){this.inner=e,this.afterBreak=!0,this.value="",this.done=!1}next(e=0){let{done:t,lineBreak:i,value:s}=this.inner.next(e);return t&&this.afterBreak?(this.value="",this.afterBreak=!1):t?(this.done=!0,this.value=""):i?this.afterBreak?this.value="":(this.afterBreak=!0,this.next()):(this.value=s,this.afterBreak=!1),this}get lineBreak(){return!1}}typeof Symbol<"u"&&(W.prototype[Symbol.iterator]=function(){return this.iter()},ri.prototype[Symbol.iterator]=rl.prototype[Symbol.iterator]=ol.prototype[Symbol.iterator]=function(){return this});class Wh{constructor(e,t,i,s){this.from=e,this.to=t,this.number=i,this.text=s}get length(){return this.to-this.from}}function Ht(n,e,t){return e=Math.max(0,Math.min(n.length,e)),[e,Math.max(e,Math.min(n.length,t))]}function ee(n,e,t=!0,i=!0){return Ph(n,e,t,i)}function Fh(n){return n>=56320&&n<57344}function Hh(n){return n>=55296&&n<56320}function er(n,e){let t=n.charCodeAt(e);if(!Hh(t)||e+1==n.length)return t;let i=n.charCodeAt(e+1);return Fh(i)?(t-55296<<10)+(i-56320)+65536:t}function Vh(n){return n<=65535?String.fromCharCode(n):(n-=65536,String.fromCharCode((n>>10)+55296,(n&1023)+56320))}function ll(n){return n<65536?1:2}const cs=/\r\n?|\n/;var xe=function(n){return n[n.Simple=0]="Simple",n[n.TrackDel=1]="TrackDel",n[n.TrackBefore=2]="TrackBefore",n[n.TrackAfter=3]="TrackAfter",n}(xe||(xe={}));class Ue{constructor(e){this.sections=e}get length(){let e=0;for(let t=0;t<this.sections.length;t+=2)e+=this.sections[t];return e}get newLength(){let e=0;for(let t=0;t<this.sections.length;t+=2){let i=this.sections[t+1];e+=i<0?this.sections[t]:i}return e}get empty(){return this.sections.length==0||this.sections.length==2&&this.sections[1]<0}iterGaps(e){for(let t=0,i=0,s=0;t<this.sections.length;){let r=this.sections[t++],o=this.sections[t++];o<0?(e(i,s,r),s+=r):s+=o,i+=r}}iterChangedRanges(e,t=!1){fs(this,e,t)}get invertedDesc(){let e=[];for(let t=0;t<this.sections.length;){let i=this.sections[t++],s=this.sections[t++];s<0?e.push(i,s):e.push(s,i)}return new Ue(e)}composeDesc(e){return this.empty?e:e.empty?this:al(this,e)}mapDesc(e,t=!1){return e.empty?this:us(this,e,t)}mapPos(e,t=-1,i=xe.Simple){let s=0,r=0;for(let o=0;o<this.sections.length;){let l=this.sections[o++],a=this.sections[o++],h=s+l;if(a<0){if(h>e)return r+(e-s);r+=l}else{if(i!=xe.Simple&&h>=e&&(i==xe.TrackDel&&s<e&&h>e||i==xe.TrackBefore&&s<e||i==xe.TrackAfter&&h>e))return null;if(h>e||h==e&&t<0&&!l)return e==s||t<0?r:r+a;r+=a}s=h}if(e>s)throw new RangeError(`Position ${e} is out of range for changeset of length ${s}`);return r}touchesRange(e,t=e){for(let i=0,s=0;i<this.sections.length&&s<=t;){let r=this.sections[i++],o=this.sections[i++],l=s+r;if(o>=0&&s<=t&&l>=e)return s<e&&l>t?"cover":!0;s=l}return!1}toString(){let e="";for(let t=0;t<this.sections.length;){let i=this.sections[t++],s=this.sections[t++];e+=(e?" ":"")+i+(s>=0?":"+s:"")}return e}toJSON(){return this.sections}static fromJSON(e){if(!Array.isArray(e)||e.length%2||e.some(t=>typeof t!="number"))throw new RangeError("Invalid JSON representation of ChangeDesc");return new Ue(e)}static create(e){return new Ue(e)}}class X extends Ue{constructor(e,t){super(e),this.inserted=t}apply(e){if(this.length!=e.length)throw new RangeError("Applying change set to a document with the wrong length");return fs(this,(t,i,s,r,o)=>e=e.replace(s,s+(i-t),o),!1),e}mapDesc(e,t=!1){return us(this,e,t,!0)}invert(e){let t=this.sections.slice(),i=[];for(let s=0,r=0;s<t.length;s+=2){let o=t[s],l=t[s+1];if(l>=0){t[s]=l,t[s+1]=o;let a=s>>1;for(;i.length<a;)i.push(W.empty);i.push(o?e.slice(r,r+o):W.empty)}r+=o}return new X(t,i)}compose(e){return this.empty?e:e.empty?this:al(this,e,!0)}map(e,t=!1){return e.empty?this:us(this,e,t,!0)}iterChanges(e,t=!1){fs(this,e,t)}get desc(){return Ue.create(this.sections)}filter(e){let t=[],i=[],s=[],r=new fi(this);e:for(let o=0,l=0;;){let a=o==e.length?1e9:e[o++];for(;l<a||l==a&&r.len==0;){if(r.done)break e;let c=Math.min(r.len,a-l);oe(s,c,-1);let f=r.ins==-1?-1:r.off==0?r.ins:0;oe(t,c,f),f>0&&nt(i,t,r.text),r.forward(c),l+=c}let h=e[o++];for(;l<h;){if(r.done)break e;let c=Math.min(r.len,h-l);oe(t,c,-1),oe(s,c,r.ins==-1?-1:r.off==0?r.ins:0),r.forward(c),l+=c}}return{changes:new X(t,i),filtered:Ue.create(s)}}toJSON(){let e=[];for(let t=0;t<this.sections.length;t+=2){let i=this.sections[t],s=this.sections[t+1];s<0?e.push(i):s==0?e.push([i]):e.push([i].concat(this.inserted[t>>1].toJSON()))}return e}static of(e,t,i){let s=[],r=[],o=0,l=null;function a(c=!1){if(!c&&!s.length)return;o<t&&oe(s,t-o,-1);let f=new X(s,r);l=l?l.compose(f.map(l)):f,s=[],r=[],o=0}function h(c){if(Array.isArray(c))for(let f of c)h(f);else if(c instanceof X){if(c.length!=t)throw new RangeError(`Mismatched change set length (got ${c.length}, expected ${t})`);a(),l=l?l.compose(c.map(l)):c}else{let{from:f,to:u=f,insert:d}=c;if(f>u||f<0||u>t)throw new RangeError(`Invalid change range ${f} to ${u} (in doc of length ${t})`);let p=d?typeof d=="string"?W.of(d.split(i||cs)):d:W.empty,g=p.length;if(f==u&&g==0)return;f<o&&a(),f>o&&oe(s,f-o,-1),oe(s,u-f,g),nt(r,s,p),o=u}}return h(e),a(!l),l}static empty(e){return new X(e?[e,-1]:[],[])}static fromJSON(e){if(!Array.isArray(e))throw new RangeError("Invalid JSON representation of ChangeSet");let t=[],i=[];for(let s=0;s<e.length;s++){let r=e[s];if(typeof r=="number")t.push(r,-1);else{if(!Array.isArray(r)||typeof r[0]!="number"||r.some((o,l)=>l&&typeof o!="string"))throw new RangeError("Invalid JSON representation of ChangeSet");if(r.length==1)t.push(r[0],0);else{for(;i.length<s;)i.push(W.empty);i[s]=W.of(r.slice(1)),t.push(r[0],i[s].length)}}}return new X(t,i)}static createSet(e,t){return new X(e,t)}}function oe(n,e,t,i=!1){if(e==0&&t<=0)return;let s=n.length-2;s>=0&&t<=0&&t==n[s+1]?n[s]+=e:s>=0&&e==0&&n[s]==0?n[s+1]+=t:i?(n[s]+=e,n[s+1]+=t):n.push(e,t)}function nt(n,e,t){if(t.length==0)return;let i=e.length-2>>1;if(i<n.length)n[n.length-1]=n[n.length-1].append(t);else{for(;n.length<i;)n.push(W.empty);n.push(t)}}function fs(n,e,t){let i=n.inserted;for(let s=0,r=0,o=0;o<n.sections.length;){let l=n.sections[o++],a=n.sections[o++];if(a<0)s+=l,r+=l;else{let h=s,c=r,f=W.empty;for(;h+=l,c+=a,a&&i&&(f=f.append(i[o-2>>1])),!(t||o==n.sections.length||n.sections[o+1]<0);)l=n.sections[o++],a=n.sections[o++];e(s,h,r,c,f),s=h,r=c}}}function us(n,e,t,i=!1){let s=[],r=i?[]:null,o=new fi(n),l=new fi(e);for(let a=-1;;){if(o.done&&l.len||l.done&&o.len)throw new Error("Mismatched change set lengths");if(o.ins==-1&&l.ins==-1){let h=Math.min(o.len,l.len);oe(s,h,-1),o.forward(h),l.forward(h)}else if(l.ins>=0&&(o.ins<0||a==o.i||o.off==0&&(l.len<o.len||l.len==o.len&&!t))){let h=l.len;for(oe(s,l.ins,-1);h;){let c=Math.min(o.len,h);o.ins>=0&&a<o.i&&o.len<=c&&(oe(s,0,o.ins),r&&nt(r,s,o.text),a=o.i),o.forward(c),h-=c}l.next()}else if(o.ins>=0){let h=0,c=o.len;for(;c;)if(l.ins==-1){let f=Math.min(c,l.len);h+=f,c-=f,l.forward(f)}else if(l.ins==0&&l.len<c)c-=l.len,l.next();else break;oe(s,h,a<o.i?o.ins:0),r&&a<o.i&&nt(r,s,o.text),a=o.i,o.forward(o.len-c)}else{if(o.done&&l.done)return r?X.createSet(s,r):Ue.create(s);throw new Error("Mismatched change set lengths")}}}function al(n,e,t=!1){let i=[],s=t?[]:null,r=new fi(n),o=new fi(e);for(let l=!1;;){if(r.done&&o.done)return s?X.createSet(i,s):Ue.create(i);if(r.ins==0)oe(i,r.len,0,l),r.next();else if(o.len==0&&!o.done)oe(i,0,o.ins,l),s&&nt(s,i,o.text),o.next();else{if(r.done||o.done)throw new Error("Mismatched change set lengths");{let a=Math.min(r.len2,o.len),h=i.length;if(r.ins==-1){let c=o.ins==-1?-1:o.off?0:o.ins;oe(i,a,c,l),s&&c&&nt(s,i,o.text)}else o.ins==-1?(oe(i,r.off?0:r.len,a,l),s&&nt(s,i,r.textBit(a))):(oe(i,r.off?0:r.len,o.off?0:o.ins,l),s&&!o.off&&nt(s,i,o.text));l=(r.ins>a||o.ins>=0&&o.len>a)&&(l||i.length>h),r.forward2(a),o.forward(a)}}}}class fi{constructor(e){this.set=e,this.i=0,this.next()}next(){let{sections:e}=this.set;this.i<e.length?(this.len=e[this.i++],this.ins=e[this.i++]):(this.len=0,this.ins=-2),this.off=0}get done(){return this.ins==-2}get len2(){return this.ins<0?this.len:this.ins}get text(){let{inserted:e}=this.set,t=this.i-2>>1;return t>=e.length?W.empty:e[t]}textBit(e){let{inserted:t}=this.set,i=this.i-2>>1;return i>=t.length&&!e?W.empty:t[i].slice(this.off,e==null?void 0:this.off+e)}forward(e){e==this.len?this.next():(this.len-=e,this.off+=e)}forward2(e){this.ins==-1?this.forward(e):e==this.ins?this.next():(this.ins-=e,this.off+=e)}}class tt{constructor(e,t,i,s){this.from=e,this.to=t,this.flags=i,this.goalColumn=s}get anchor(){return this.flags&32?this.to:this.from}get head(){return this.flags&32?this.from:this.to}get empty(){return this.from==this.to}get assoc(){return this.flags&8?-1:this.flags&16?1:0}get undirectional(){return(this.flags&64)>0}get bidiLevel(){let e=this.flags&7;return e==7?null:e}map(e,t=-1){let i,s;return this.empty?i=s=e.mapPos(this.from,t):(i=e.mapPos(this.from,1),s=e.mapPos(this.to,-1)),i==this.from&&s==this.to?this:new tt(i,s,this.flags,this.goalColumn)}extend(e,t=e,i=0){if(e<=this.anchor&&t>=this.anchor)return b.range(e,t,void 0,void 0,i);let s=Math.abs(e-this.anchor)>Math.abs(t-this.anchor)?e:t;return b.range(this.anchor,s,void 0,void 0,i)}eq(e,t=!1){return this.anchor==e.anchor&&this.head==e.head&&this.goalColumn==e.goalColumn&&(!t||!this.empty||this.assoc==e.assoc)}toJSON(){return{anchor:this.anchor,head:this.head}}static fromJSON(e){if(!e||typeof e.anchor!="number"||typeof e.head!="number")throw new RangeError("Invalid JSON representation for SelectionRange");return b.range(e.anchor,e.head)}static create(e,t,i,s){return new tt(e,t,i,s)}}class b{constructor(e,t){this.ranges=e,this.mainIndex=t}map(e,t=-1){return e.empty?this:b.create(this.ranges.map(i=>i.map(e,t)),this.mainIndex)}eq(e,t=!1){if(this.ranges.length!=e.ranges.length||this.mainIndex!=e.mainIndex)return!1;for(let i=0;i<this.ranges.length;i++)if(!this.ranges[i].eq(e.ranges[i],t))return!1;return!0}get main(){return this.ranges[this.mainIndex]}asSingle(){return this.ranges.length==1?this:new b([this.main],0)}addRange(e,t=!0){return b.create([e].concat(this.ranges),t?0:this.mainIndex+1)}replaceRange(e,t=this.mainIndex){let i=this.ranges.slice();return i[t]=e,b.create(i,this.mainIndex)}toJSON(){return{ranges:this.ranges.map(e=>e.toJSON()),main:this.mainIndex}}static fromJSON(e){if(!e||!Array.isArray(e.ranges)||typeof e.main!="number"||e.main>=e.ranges.length)throw new RangeError("Invalid JSON representation for EditorSelection");return new b(e.ranges.map(t=>tt.fromJSON(t)),e.main)}static single(e,t=e){return new b([b.range(e,t)],0)}static create(e,t=0){if(e.length==0)throw new RangeError("A selection needs at least one range");for(let i=0,s=0;s<e.length;s++){let r=e[s];if(r.empty?r.from<=i:r.from<i)return b.normalized(e.slice(),t);i=r.to}return new b(e,t)}static cursor(e,t=0,i,s){return tt.create(e,e,(t==0?0:t<0?8:16)|(i==null?7:Math.min(6,i)),s)}static range(e,t,i,s,r){let o=s==null?7:Math.min(6,s);return!r&&e!=t&&(r=t<e?1:-1),r&&(o|=r<0?8:16),t<e?tt.create(t,e,o|32,i):tt.create(e,t,o,i)}static undirectionalRange(e,t){return tt.create(e,t,64,void 0)}static normalized(e,t=0){let i=e[t];e.sort((s,r)=>s.from-r.from),t=e.indexOf(i);for(let s=1;s<e.length;s++){let r=e[s],o=e[s-1];if(r.empty?r.from<=o.to:r.from<o.to){let l=o.from,a=Math.max(r.to,o.to);s<=t&&t--,e.splice(--s,2,r.anchor>r.head?b.range(a,l):b.range(l,a))}}return new b(e,t)}}function hl(n,e){for(let t of n.ranges)if(t.to>e)throw new RangeError("Selection points outside of document")}let tr=0;class A{constructor(e,t,i,s,r){this.combine=e,this.compareInput=t,this.compare=i,this.isStatic=s,this.id=tr++,this.default=e([]),this.extensions=typeof r=="function"?r(this):r}get reader(){return this}static define(e={}){return new A(e.combine||(t=>t),e.compareInput||((t,i)=>t===i),e.compare||(e.combine?(t,i)=>t===i:ir),!!e.static,e.enables)}of(e){return new Xi([],this,0,e)}compute(e,t){if(this.isStatic)throw new Error("Can't compute a static facet");return new Xi(e,this,1,t)}computeN(e,t){if(this.isStatic)throw new Error("Can't compute a static facet");return new Xi(e,this,2,t)}from(e,t){return t||(t=i=>i),this.compute([e],i=>t(i.field(e)))}}function ir(n,e){return n==e||n.length==e.length&&n.every((t,i)=>t===e[i])}class Xi{constructor(e,t,i,s){this.dependencies=e,this.facet=t,this.type=i,this.value=s,this.id=tr++}dynamicSlot(e){var t;let i=this.value,s=this.facet.compareInput,r=this.id,o=e[r]>>1,l=this.type==2,a=!1,h=!1,c=[];for(let f of this.dependencies)f=="doc"?a=!0:f=="selection"?h=!0:((t=e[f.id])!==null&&t!==void 0?t:1)&1||c.push(e[f.id]);return{create(f){return f.values[o]=i(f),1},update(f,u){if(a&&u.docChanged||h&&(u.docChanged||u.selection)||ds(f,c)){let d=i(f);if(l?!Fr(d,f.values[o],s):!s(d,f.values[o]))return f.values[o]=d,1}return 0},reconfigure:(f,u)=>{let d,p=u.config.address[r];if(p!=null){let g=ln(u,p);if(this.dependencies.every(m=>m instanceof A?u.facet(m)===f.facet(m):m instanceof Ge?u.field(m,!1)==f.field(m,!1):!0)||(l?Fr(d=i(f),g,s):s(d=i(f),g)))return f.values[o]=g,0}else d=i(f);return f.values[o]=d,1}}}get extension(){return this}}function Fr(n,e,t){if(n.length!=e.length)return!1;for(let i=0;i<n.length;i++)if(!t(n[i],e[i]))return!1;return!0}function ds(n,e){let t=!1;for(let i of e)oi(n,i)&1&&(t=!0);return t}function zh(n,e,t){let i=t.map(a=>n[a.id]),s=t.map(a=>a.type),r=i.filter(a=>!(a&1)),o=n[e.id]>>1;function l(a){let h=[];for(let c=0;c<i.length;c++){let f=ln(a,i[c]);if(s[c]==2)for(let u of f)h.push(u);else h.push(f)}return e.combine(h)}return{create(a){for(let h of i)oi(a,h);return a.values[o]=l(a),1},update(a,h){if(!ds(a,r))return 0;let c=l(a);return e.compare(c,a.values[o])?0:(a.values[o]=c,1)},reconfigure(a,h){let c=ds(a,i),f=h.config.facets[e.id],u=h.facet(e);if(f&&!c&&ir(t,f))return a.values[o]=u,0;let d=l(a);return e.compare(d,u)?(a.values[o]=u,0):(a.values[o]=d,1)}}}const Li=A.define({static:!0});class Ge{constructor(e,t,i,s,r){this.id=e,this.createF=t,this.updateF=i,this.compareF=s,this.spec=r,this.provides=void 0}static define(e){let t=new Ge(tr++,e.create,e.update,e.compare||((i,s)=>i===s),e);return e.provide&&(t.provides=e.provide(t)),t}create(e){let t=e.facet(Li).find(i=>i.field==this);return((t==null?void 0:t.create)||this.createF)(e)}slot(e){let t=e[this.id]>>1;return{create:i=>(i.values[t]=this.create(i),1),update:(i,s)=>{let r=i.values[t],o=this.updateF(r,s);return this.compareF(r,o)?0:(i.values[t]=o,1)},reconfigure:(i,s)=>{let r=i.facet(Li),o=s.facet(Li),l;return(l=r.find(a=>a.field==this))&&l!=o.find(a=>a.field==this)?(i.values[t]=l.create(i),1):s.config.address[this.id]!=null?(i.values[t]=s.field(this),0):(i.values[t]=this.create(i),1)}}}init(e){return[this,Li.of({field:this,create:e})]}get extension(){return this}}const mt={lowest:4,low:3,default:2,high:1,highest:0};function Xt(n){return e=>new cl(e,n)}const vi={highest:Xt(mt.highest),high:Xt(mt.high),default:Xt(mt.default),low:Xt(mt.low),lowest:Xt(mt.lowest)};class cl{constructor(e,t){this.inner=e,this.prec=t}get extension(){return this}}class Mn{of(e){return new ps(this,e)}reconfigure(e){return Mn.reconfigure.of({compartment:this,extension:e})}get(e){return e.config.compartments.get(this)}}class ps{constructor(e,t){this.compartment=e,this.inner=t}get extension(){return this}}class on{constructor(e,t,i,s,r,o){for(this.base=e,this.compartments=t,this.dynamicSlots=i,this.address=s,this.staticValues=r,this.facets=o,this.statusTemplate=[];this.statusTemplate.length<i.length;)this.statusTemplate.push(0)}staticFacet(e){let t=this.address[e.id];return t==null?e.default:this.staticValues[t>>1]}static resolve(e,t,i){let s=[],r=Object.create(null),o=new Map;for(let u of qh(e,t,o))u instanceof Ge?s.push(u):(r[u.facet.id]||(r[u.facet.id]=[])).push(u);let l=Object.create(null),a=[],h=[];for(let u of s)l[u.id]=h.length<<1,h.push(d=>u.slot(d));let c=i==null?void 0:i.config.facets;for(let u in r){let d=r[u],p=d[0].facet,g=c&&c[u]||[];if(d.every(m=>m.type==0))if(l[p.id]=a.length<<1|1,ir(g,d))a.push(i.facet(p));else{let m=p.combine(d.map(y=>y.value));a.push(i&&p.compare(m,i.facet(p))?i.facet(p):m)}else{for(let m of d)m.type==0?(l[m.id]=a.length<<1|1,a.push(m.value)):(l[m.id]=h.length<<1,h.push(y=>m.dynamicSlot(y)));l[p.id]=h.length<<1,h.push(m=>zh(m,p,d))}}let f=h.map(u=>u(l));return new on(e,o,f,l,a,r)}}function qh(n,e,t){let i=[[],[],[],[],[]],s=new Map;function r(o,l){let a=s.get(o);if(a!=null){if(a<=l)return;let h=i[a].indexOf(o);h>-1&&i[a].splice(h,1),o instanceof ps&&t.delete(o.compartment)}if(s.set(o,l),Array.isArray(o))for(let h of o)r(h,l);else if(o instanceof ps){if(t.has(o.compartment))throw new RangeError("Duplicate use of compartment in extensions");let h=e.get(o.compartment)||o.inner;t.set(o.compartment,h),r(h,l)}else if(o instanceof cl)r(o.inner,o.prec);else if(o instanceof Ge)i[l].push(o),o.provides&&r(o.provides,l);else if(o instanceof Xi)i[l].push(o),o.facet.extensions&&r(o.facet.extensions,mt.default);else{let h=o.extension;if(!h)throw new Error(`Unrecognized extension value in extension set (${o}).`);if(h==o)throw new Error(`Unrecognized extension value in extension set (${o}). This sometimes happens because multiple instances of @codemirror/state are loaded, breaking instanceof checks.`);r(h,l)}}return r(n,mt.default),i.reduce((o,l)=>o.concat(l))}function oi(n,e){if(e&1)return 2;let t=e>>1,i=n.status[t];if(i==4)throw new Error("Cyclic dependency between fields and/or facets");if(i&2)return i;n.status[t]=4;let s=n.computeSlot(n,n.config.dynamicSlots[t]);return n.status[t]=2|s}function ln(n,e){return e&1?n.config.staticValues[e>>1]:n.values[e>>1]}const fl=A.define(),gs=A.define({combine:n=>n.some(e=>e),static:!0}),ul=A.define({combine:n=>n.length?n[0]:void 0,static:!0}),dl=A.define(),pl=A.define(),gl=A.define(),ml=A.define({combine:n=>n.length?n[0]:!1});class ft{constructor(e,t){this.type=e,this.value=t}static define(){return new Kh}}class Kh{of(e){return new ft(this,e)}}class $h{constructor(e){this.map=e}of(e){return new K(this,e)}}class K{constructor(e,t){this.type=e,this.value=t}map(e){let t=this.type.map(this.value,e);return t===void 0?void 0:t==this.value?this:new K(this.type,t)}is(e){return this.type==e}static define(e={}){return new $h(e.map||(t=>t))}static mapEffects(e,t){if(!e.length)return e;let i=[];for(let s of e){let r=s.map(t);r&&i.push(r)}return i}}K.reconfigure=K.define();K.appendConfig=K.define();class Q{constructor(e,t,i,s,r,o){this.startState=e,this.changes=t,this.selection=i,this.effects=s,this.annotations=r,this.scrollIntoView=o,this._doc=null,this._state=null,i&&hl(i,t.newLength),r.some(l=>l.type==Q.time)||(this.annotations=r.concat(Q.time.of(Date.now())))}static create(e,t,i,s,r,o){return new Q(e,t,i,s,r,o)}get newDoc(){return this._doc||(this._doc=this.changes.apply(this.startState.doc))}get newSelection(){return this.selection||this.startState.selection.map(this.changes)}get state(){return this._state||this.startState.applyTransaction(this),this._state}annotation(e){for(let t of this.annotations)if(t.type==e)return t.value}get docChanged(){return!this.changes.empty}get reconfigured(){return this.startState.config!=this.state.config}isUserEvent(e){let t=this.annotation(Q.userEvent);return!!(t&&(t==e||t.length>e.length&&t.slice(0,e.length)==e&&t[e.length]=="."))}}Q.time=ft.define();Q.userEvent=ft.define();Q.addToHistory=ft.define();Q.remote=ft.define();function jh(n,e){let t=[];for(let i=0,s=0;;){let r,o;if(i<n.length&&(s==e.length||e[s]>=n[i]))r=n[i++],o=n[i++];else if(s<e.length)r=e[s++],o=e[s++];else return t;!t.length||t[t.length-1]<r?t.push(r,o):t[t.length-1]<o&&(t[t.length-1]=o)}}function yl(n,e,t){var i;let s,r,o;return t?(s=e.changes,r=X.empty(e.changes.length),o=n.changes.compose(e.changes)):(s=e.changes.map(n.changes),r=n.changes.mapDesc(e.changes,!0),o=n.changes.compose(s)),{changes:o,selection:e.selection?e.selection.map(r):(i=n.selection)===null||i===void 0?void 0:i.map(s),effects:K.mapEffects(n.effects,s).concat(K.mapEffects(e.effects,r)),annotations:n.annotations.length?n.annotations.concat(e.annotations):e.annotations,scrollIntoView:n.scrollIntoView||e.scrollIntoView}}function ms(n,e,t){let i=e.selection,s=Pt(e.annotations);return e.userEvent&&(s=s.concat(Q.userEvent.of(e.userEvent))),{changes:e.changes instanceof X?e.changes:X.of(e.changes||[],t,n.facet(ul)),selection:i&&(i instanceof b?i:b.single(i.anchor,i.head)),effects:Pt(e.effects),annotations:s,scrollIntoView:!!e.scrollIntoView}}function bl(n,e,t){let i=ms(n,e.length?e[0]:{},n.doc.length);e.length&&e[0].filter===!1&&(t=!1);for(let r=1;r<e.length;r++){e[r].filter===!1&&(t=!1);let o=!!e[r].sequential;i=yl(i,ms(n,e[r],o?i.changes.newLength:n.doc.length),o)}let s=Q.create(n,i.changes,i.selection,i.effects,i.annotations,i.scrollIntoView);return _h(t?Uh(s):s)}function Uh(n){let e=n.startState,t=!0;for(let s of e.facet(dl)){let r=s(n);if(r===!1){t=!1;break}Array.isArray(r)&&(t=t===!0?r:jh(t,r))}if(t!==!0){let s,r;if(t===!1)r=n.changes.invertedDesc,s=X.empty(e.doc.length);else{let o=n.changes.filter(t);s=o.changes,r=o.filtered.mapDesc(o.changes).invertedDesc}n=Q.create(e,s,n.selection&&n.selection.map(r),K.mapEffects(n.effects,r),n.annotations,n.scrollIntoView)}let i=e.facet(pl);for(let s=i.length-1;s>=0;s--){let r=i[s](n);r instanceof Q?n=r:Array.isArray(r)&&r.length==1&&r[0]instanceof Q?n=r[0]:n=bl(e,Pt(r),!1)}return n}function _h(n){let e=n.startState,t=e.facet(gl),i=n;for(let s=t.length-1;s>=0;s--){let r=t[s](n);r&&Object.keys(r).length&&(i=yl(i,ms(e,r,n.changes.newLength),!0))}return i==n?n:Q.create(e,n.changes,n.selection,i.effects,i.annotations,i.scrollIntoView)}const Gh=[];function Pt(n){return n==null?Gh:Array.isArray(n)?n:[n]}var se=function(n){return n[n.Word=0]="Word",n[n.Space=1]="Space",n[n.Other=2]="Other",n}(se||(se={}));const Jh=/[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;let ys;try{ys=new RegExp("[\\p{Alphabetic}\\p{Number}_]","u")}catch{}function Yh(n){if(ys)return ys.test(n);for(let e=0;e<n.length;e++){let t=n[e];if(/\w/.test(t)||t>"€"&&(t.toUpperCase()!=t.toLowerCase()||Jh.test(t)))return!0}return!1}function Xh(n){return e=>{if(!/\S/.test(e))return se.Space;if(Yh(e))return se.Word;for(let t=0;t<n.length;t++)if(e.indexOf(n[t])>-1)return se.Word;return se.Other}}class N{constructor(e,t,i,s,r,o){this.config=e,this.doc=t,this.selection=i,this.values=s,this.status=e.statusTemplate.slice(),this.computeSlot=r,o&&(o._state=this);for(let l=0;l<this.config.dynamicSlots.length;l++)oi(this,l<<1);this.computeSlot=null}field(e,t=!0){let i=this.config.address[e.id];if(i==null){if(t)throw new RangeError("Field is not present in this state");return}return oi(this,i),ln(this,i)}update(...e){return bl(this,e,!0)}applyTransaction(e){let t=this.config,{base:i,compartments:s}=t;for(let l of e.effects)l.is(Mn.reconfigure)?(t&&(s=new Map,t.compartments.forEach((a,h)=>s.set(h,a)),t=null),s.set(l.value.compartment,l.value.extension)):l.is(K.reconfigure)?(t=null,i=l.value):l.is(K.appendConfig)&&(t=null,i=Pt(i).concat(l.value));let r;t?r=e.startState.values.slice():(t=on.resolve(i,s,this),r=new N(t,this.doc,this.selection,t.dynamicSlots.map(()=>null),(a,h)=>h.reconfigure(a,this),null).values);let o=e.startState.facet(gs)?e.newSelection:e.newSelection.asSingle();new N(t,e.newDoc,o,r,(l,a)=>a.update(l,e),e)}replaceSelection(e){return typeof e=="string"&&(e=this.toText(e)),this.changeByRange(t=>({changes:{from:t.from,to:t.to,insert:e},range:b.cursor(t.from+e.length)}))}changeByRange(e){let t=this.selection,i=e(t.ranges[0]),s=this.changes(i.changes),r=[i.range],o=Pt(i.effects);for(let l=1;l<t.ranges.length;l++){let a=e(t.ranges[l]),h=this.changes(a.changes),c=h.map(s);for(let u=0;u<l;u++)r[u]=r[u].map(c);let f=s.mapDesc(h,!0);r.push(a.range.map(f)),s=s.compose(c),o=K.mapEffects(o,c).concat(K.mapEffects(Pt(a.effects),f))}return{changes:s,selection:b.create(r,t.mainIndex),effects:o}}changes(e=[]){return e instanceof X?e:X.of(e,this.doc.length,this.facet(N.lineSeparator))}toText(e){return W.of(e.split(this.facet(N.lineSeparator)||cs))}sliceDoc(e=0,t=this.doc.length){return this.doc.sliceString(e,t,this.lineBreak)}facet(e){let t=this.config.address[e.id];return t==null?e.default:(oi(this,t),ln(this,t))}toJSON(e){let t={doc:this.sliceDoc(),selection:this.selection.toJSON()};if(e)for(let i in e){let s=e[i];s instanceof Ge&&this.config.address[s.id]!=null&&(t[i]=s.spec.toJSON(this.field(e[i]),this))}return t}static fromJSON(e,t={},i){if(!e||typeof e.doc!="string")throw new RangeError("Invalid JSON representation for EditorState");let s=[];if(i){for(let r in i)if(Object.prototype.hasOwnProperty.call(e,r)){let o=i[r],l=e[r];s.push(o.init(a=>o.spec.fromJSON(l,a)))}}return N.create({doc:e.doc,selection:b.fromJSON(e.selection),extensions:t.extensions?s.concat([t.extensions]):s})}static create(e={}){let t=on.resolve(e.extensions||[],new Map),i=e.doc instanceof W?e.doc:W.of((e.doc||"").split(t.staticFacet(N.lineSeparator)||cs)),s=e.selection?e.selection instanceof b?e.selection:b.single(e.selection.anchor,e.selection.head):b.single(0);return hl(s,i.length),t.staticFacet(gs)||(s=s.asSingle()),new N(t,i,s,t.dynamicSlots.map(()=>null),(r,o)=>o.create(r),null)}get tabSize(){return this.facet(N.tabSize)}get lineBreak(){return this.facet(N.lineSeparator)||`
@@ -0,0 +1 @@
1
+ :root{--font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;--bg: #14161a;--bg-raised: #1b1e24;--bg-inset: #171a1f;--border: #262a31;--text: #c8ccd4;--text-dim: #676e7b;--text-bright: #e6e9ee;--accent: #7ee787;--ok: #7ee787;--running: #e3b341;--error: #f8746a;--info: #79c0ff;--term-bg: #0e1013;--term-text: #c9d1d9}:root[data-theme=light]{--bg: #f2efe6;--bg-raised: #e7e2d5;--bg-inset: #ebe7dc;--border: #d9d3c4;--text: #2f2b25;--text-dim: #8b8375;--text-bright: #14110c;--accent: #3f7d3f;--ok: #3f7d3f;--running: #a76c14;--error: #b03a34;--info: #2f6f9e}*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--text);font-family:var(--font-mono);font-size:13px;line-height:1.6}.panel{background:var(--bg-raised);border:1px solid var(--border)}.status-success{color:var(--ok)}.status-running{color:var(--running)}.status-failed,.status-interrupted{color:var(--error)}.status-queued,.status-preparing,.dim{color:var(--text-dim)}.bright{color:var(--text-bright)}.accent{color:var(--accent)}.status-cancelled{color:var(--text-dim)}a{color:inherit;text-decoration:none}a:hover{color:var(--text-bright)}h1,h2,h3{font-size:13px;font-weight:400;margin:0}.section{color:var(--text-dim);text-transform:uppercase;letter-spacing:.14em;font-size:11px}button,input,select{font:inherit;color:var(--text);background:var(--bg-inset);border:1px solid var(--border);border-radius:0;padding:2px 8px}button{cursor:pointer}button:hover:not(:disabled){color:var(--text-bright);border-color:var(--text-dim)}button:disabled,input:disabled{color:var(--text-dim);cursor:default}input:focus,button:focus-visible{outline:1px solid var(--accent);outline-offset:-1px}ul{list-style:none;margin:0;padding:0}code{color:var(--text-bright)}.shell{display:grid;grid-template-columns:240px minmax(0,1fr);grid-template-rows:32px 1fr;height:100vh}.shell>header{grid-column:1 / -1;display:flex;align-items:center;justify-content:space-between;gap:16px;padding:0 12px;border-bottom:1px solid var(--border);background:var(--bg-raised)}.brand{color:var(--accent);letter-spacing:.12em}.who{display:flex;align-items:baseline;gap:8px}.account-link{border-bottom:1px solid var(--border)}.account-link:hover{border-bottom-color:var(--text-dim)}.shell>nav{border-right:1px solid var(--border);background:var(--bg-raised);overflow-y:auto;padding:12px 0}.shell>main{min-width:0;overflow:auto;padding:16px}.nav-head{padding:0 12px 6px}.nav-item{display:block;padding:2px 12px;border-left:2px solid transparent;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.nav-item:hover{background:var(--bg-inset)}.nav-item.current{border-left-color:var(--accent);background:var(--bg-inset);color:var(--text-bright)}.login{height:100vh;display:flex;align-items:center;justify-content:center}.login form{width:320px;padding:20px;display:flex;flex-direction:column;gap:12px}.login input{width:100%;padding:4px 8px}.rows>li{display:flex;align-items:baseline;gap:8px;padding:4px 0;border-bottom:1px solid var(--border)}.rows>li:last-child{border-bottom:none}.grow{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mark{width:1ch;display:inline-block}.tabs{display:flex;gap:16px;border-bottom:1px solid var(--border);margin-bottom:12px}.tabs a{color:var(--text-dim);text-transform:uppercase;letter-spacing:.14em;font-size:11px;padding-bottom:4px;border-bottom:2px solid transparent}.tabs a:hover{color:var(--text)}.tabs a.current{color:var(--text-bright);border-bottom-color:var(--accent)}.secret-form{display:flex;flex-wrap:wrap;align-items:baseline;gap:8px;margin:8px 0 4px}.secret-form input[type=text],.secret-form input[type=password]{width:24ch}.secret-form label{display:flex;align-items:baseline;gap:6px;color:var(--text-dim)}.secret-form input[type=checkbox]{accent-color:var(--accent);width:auto;padding:0}.file-chosen{display:flex;align-items:baseline;gap:6px}.credentials>li{display:block}.block-head{display:flex;align-items:baseline;gap:8px;width:100%;padding:0;text-align:left;background:none;border:none}.block-head:hover{background:var(--bg-inset)}.block-head:hover .dim{color:var(--text)}.block-body{border-left:2px solid var(--border);padding-left:10px;margin:2px 0 6px 1ch}.block-body[hidden]{display:none}.credentials-group .platform{margin:10px 0 0}.credentials .grow{white-space:normal;overflow:visible}.needed .needed-name{flex:none;min-width:26ch}.needed input{min-width:0}.row-flag{display:flex;align-items:baseline;gap:5px;flex:none;color:var(--text-dim);white-space:nowrap;cursor:pointer}.rows>li.superseded{border-left:2px solid var(--running);padding-left:8px;margin-left:-10px}.superseded-note{display:block;color:var(--text-dim);white-space:normal}.revealed{color:var(--text-bright);word-break:break-all}.file-pick{cursor:pointer}.file-pick input[type=file]{display:none}.file-pick:hover .accent{color:var(--text-bright)}table{border-collapse:collapse;width:100%}td,th{text-align:left;font-weight:400;padding:2px 12px 2px 0}.checks .grow{white-space:normal;overflow:visible}.checks>li{border-left:2px solid transparent;padding-left:8px;margin-left:-10px}.checks>li.check-warn{border-left-color:var(--running)}.checks>li.check-unknown{border-left-color:var(--text-dim)}.checks>li.check-ok .check-title{color:var(--text-dim)}.tally{display:flex;flex-wrap:wrap;gap:14px;margin:10px 0 2px}.tally .none{color:var(--text-dim)}.consequences .grow{white-space:normal;overflow:visible}.consequences .path{color:var(--text-bright);word-break:break-all}.danger{border:1px solid var(--error);background:color-mix(in srgb,var(--error) 4%,var(--bg));padding:14px 16px;margin-top:4px}.danger .section{color:var(--error)}.danger .section:first-child{margin-top:0}.danger .irreversible{color:var(--text-bright);margin-top:6px}.danger .irreversible .mark{color:var(--error)}.confirm-form{display:flex;flex-wrap:wrap;align-items:baseline;gap:8px;margin:8px 0 4px}.confirm-form input{width:24ch}.confirm-form button:not(:disabled){color:var(--error);border-color:var(--error)}.editor-bar,.commit-bar{display:flex;align-items:baseline;gap:8px;margin:8px 0 4px}.commit-bar input{flex:1;max-width:48ch}.editor{height:calc(100vh - 420px);min-height:240px;overflow:hidden}.save-error{white-space:normal;margin:8px 0}.diff{margin:8px 0 0;padding:8px 12px;max-height:40vh;overflow:auto;background:var(--term-bg);color:var(--term-text);white-space:pre;font:inherit}.run-head{display:flex;align-items:baseline;flex-wrap:wrap;gap:6px 20px;padding:8px 12px;margin-bottom:12px}.run-body{display:grid;grid-template-columns:260px minmax(0,1fr);gap:12px;align-items:start;min-width:0}.steps>li{display:flex;gap:8px;padding:2px 8px}.steps>li.clickable{cursor:pointer}.steps>li.clickable:hover{background:var(--bg-inset);color:var(--text-bright)}.steps>li.inert{color:var(--text-dim)}.pane-title{padding:6px 12px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;gap:12px}.terminal{background:var(--term-bg);color:var(--term-text);display:flex;flex-direction:column;height:calc(100vh - 190px);min-height:260px}.terminal pre{margin:0;flex:1;overflow:auto;padding:8px 12px;white-space:pre;font:inherit}.terminal .a-black{color:#6e7681}.terminal .a-red{color:#ff7b72}.terminal .a-green{color:#7ee787}.terminal .a-yellow{color:#d29922}.terminal .a-blue{color:#79c0ff}.terminal .a-magenta{color:#d2a8ff}.terminal .a-cyan{color:#56d4dd}.terminal .a-white{color:#b1bac4}.terminal .a-bright-black{color:#8b949e}.terminal .a-bright-red{color:#ffa198}.terminal .a-bright-green{color:#56d364}.terminal .a-bright-yellow{color:#e3b341}.terminal .a-bright-blue{color:#a5d6ff}.terminal .a-bright-magenta{color:#e2c5ff}.terminal .a-bright-cyan{color:#b3f0ff}.terminal .a-bright-white{color:#f0f6fc}.terminal .a-bold{font-weight:700}.terminal .a-dim{opacity:.7}.terminal-input{display:flex;align-items:center;gap:8px;padding:4px 12px;border-top:1px solid var(--border)}.terminal-input input{flex:1;background:transparent;border:none;color:var(--term-text);padding:0}.terminal-input input:disabled{color:#4c525c}.terminal-input .prompt{color:var(--accent)}.terminal-input .reason{color:#676e7b}@media (max-width: 820px){.shell{grid-template-columns:1fr;grid-template-rows:32px auto 1fr;height:auto;min-height:100vh}.shell>nav{border-right:none;border-bottom:1px solid var(--border);display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 12px;padding:6px 12px}.nav-head{padding:0;width:100%}.nav-item{border-left:none;border-bottom:2px solid transparent;padding:0 2px}.nav-item.current{border-left-color:transparent;border-bottom-color:var(--accent)}.run-body{grid-template-columns:1fr}.terminal{height:60vh}}