laneyard 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,12 +14,38 @@ import { CREDENTIAL_KINDS, defaultVarNames, fieldsOf } from "../../credentials/k
14
14
  /** POSIX environment variable names. Anything else would never reach fastlane. */
15
15
  const VALID_VAR = /^[A-Za-z_][A-Za-z0-9_]*$/;
16
16
  export async function registerCredentialRoutes(app, ctx) {
17
- app.get("/api/credentials", async () => ctx.vault.listGlobalCredentials());
18
17
  app.get("/api/projects/:slug/credentials", async (req, reply) => {
19
18
  const { slug } = req.params;
20
19
  if (!ctx.config.project(slug))
21
20
  return reply.code(404).send({ error: "Unknown project" });
22
- return ctx.vault.listCredentials(slug);
21
+ // Fields included, secret ones excepted — an alias or a key id that cannot
22
+ // be read cannot be checked, and `stored` says the same thing about a right
23
+ // value and a wrong one. The passwords come one at a time through the route
24
+ // below, so opening the screen still puts none of them in a browser.
25
+ return ctx.vault.listCredentialsWithFields(slug);
26
+ });
27
+ /**
28
+ * One field of one block, in the clear — including a password.
29
+ *
30
+ * The same shape and the same reasoning as revealing a secret: a separate
31
+ * request, for one named field, made because somebody pressed `show`. A block
32
+ * can only be corrected by uploading it again in full, so a password nobody
33
+ * can read is a password that gets replaced by the same typo twice.
34
+ */
35
+ app.get("/api/projects/:slug/credentials/:kind/fields/:field/value", async (req, reply) => {
36
+ const { slug, kind, field } = req.params;
37
+ if (!ctx.config.project(slug))
38
+ return reply.code(404).send({ error: "Unknown project" });
39
+ const spec = CREDENTIAL_KINDS.find((k) => k.kind === kind);
40
+ if (!spec)
41
+ return reply.code(404).send({ error: "Unknown credential" });
42
+ if (!spec.fields.some((f) => f.name === field)) {
43
+ return reply.code(404).send({ error: `A ${spec.what} has no field called "${field}".` });
44
+ }
45
+ const value = ctx.vault.revealCredentialField(slug, spec.kind, field);
46
+ if (value === null)
47
+ return reply.code(404).send({ error: "Unknown credential" });
48
+ return { field, value };
23
49
  });
24
50
  const put = async (slug, kind, body, reply) => {
25
51
  const spec = CREDENTIAL_KINDS.find((k) => k.kind === kind);
@@ -82,24 +108,100 @@ export async function registerCredentialRoutes(app, ctx) {
82
108
  await ctx.vault.setCredential(slug, spec.kind, { fileName, fileBytes, fields: kept, varNames: names });
83
109
  return reply.code(204).send();
84
110
  };
85
- app.put("/api/credentials/:kind", async (req, reply) => put(null, req.params.kind, req.body, reply));
86
111
  app.put("/api/projects/:slug/credentials/:kind", async (req, reply) => {
87
112
  const { slug, kind } = req.params;
88
113
  if (!ctx.config.project(slug))
89
114
  return reply.code(404).send({ error: "Unknown project" });
90
115
  return put(slug, kind, req.body, reply);
91
116
  });
92
- app.delete("/api/credentials/:kind", async (req, reply) => {
93
- const { kind } = req.params;
94
- const removed = ctx.vault.removeCredential(null, kind);
95
- return removed ? reply.code(204).send() : reply.code(404).send({ error: "Unknown credential" });
96
- });
97
117
  /**
98
- * Removes this project's own block, and only that one. A global block that
99
- * was shadowed comes back into view, which is the deletion someone asked for:
100
- * they are undoing an override, not deleting everyone's key from inside one
101
- * project.
118
+ * Corrects fields of a block already stored, the file left alone.
119
+ *
120
+ * `PUT` takes a block whole because a keystore arriving without its alias is
121
+ * not a partial success. That reasoning stops applying the moment the block is
122
+ * in place: a store password typed one character short could only be fixed by
123
+ * uploading the `.jks` again — re-supplying the part nobody doubted, and
124
+ * getting another chance to mistype the part that was wrong.
125
+ *
126
+ * A required field may be corrected, never emptied: an empty one is the state
127
+ * `PUT` refuses, and reaching it through another verb would leave a block that
128
+ * signs nothing behind a screen saying it is in place. An optional one is
129
+ * emptied on purpose — that is how a setting is taken back.
130
+ *
131
+ * The file is one of the things that changes on its own, and the commonest: a
132
+ * `.p8` is rotated far more often than the key id and issuer id beside it.
102
133
  */
134
+ app.patch("/api/projects/:slug/credentials/:kind", async (req, reply) => {
135
+ const { slug, kind } = req.params;
136
+ if (!ctx.config.project(slug))
137
+ return reply.code(404).send({ error: "Unknown project" });
138
+ const spec = CREDENTIAL_KINDS.find((k) => k.kind === kind);
139
+ if (!spec)
140
+ return reply.code(404).send({ error: "Unknown credential" });
141
+ const { fileName, fileBase64, fields, varNames } = (req.body ?? {});
142
+ // The two travel together: a name without bytes would rename the file the
143
+ // run writes without changing what is in it, and bytes without a name would
144
+ // leave `AuthKey_OLD.p8` on screen describing a key that is gone.
145
+ if ((fileName === undefined) !== (fileBase64 === undefined)) {
146
+ return reply.code(400).send({ error: "Send the file and its name together." });
147
+ }
148
+ let file;
149
+ if (fileName !== undefined) {
150
+ if (typeof fileName !== "string" || fileName === "") {
151
+ return reply.code(400).send({ error: "A file name is required" });
152
+ }
153
+ if (typeof fileBase64 !== "string" || fileBase64 === "") {
154
+ return reply.code(400).send({ error: `The ${spec.what} file is required, base64-encoded.` });
155
+ }
156
+ // The same check `PUT` makes, and for the same reason: Node's decoder
157
+ // ignores what it cannot read, so a truncated upload would be stored as a
158
+ // shorter file and only surface as an unreadable key at signing time.
159
+ const fileBytes = Buffer.from(fileBase64, "base64");
160
+ if (fileBytes.length === 0 || fileBytes.toString("base64").replace(/=+$/, "") !== fileBase64.replace(/=+$/, "")) {
161
+ return reply.code(400).send({ error: "The file is not valid base64." });
162
+ }
163
+ file = { fileName, fileBytes };
164
+ }
165
+ const given = (fields ?? {});
166
+ if (typeof given !== "object" || Array.isArray(given)) {
167
+ return reply.code(400).send({ error: "`fields` is an object of name to value." });
168
+ }
169
+ const changed = {};
170
+ for (const [name, value] of Object.entries(given)) {
171
+ const field = spec.fields.find((f) => f.name === name);
172
+ if (!field)
173
+ return reply.code(400).send({ error: `A ${spec.what} has no field called "${name}".` });
174
+ if (typeof value !== "string") {
175
+ return reply.code(400).send({ error: `"${name}" is text.` });
176
+ }
177
+ if (value === "" && !field.optional) {
178
+ return reply.code(400).send({
179
+ error: `A ${spec.what} needs ${name}. Without it the file alone signs nothing.`,
180
+ });
181
+ }
182
+ changed[name] = value;
183
+ }
184
+ const names = (varNames ?? {});
185
+ for (const [slot, name] of Object.entries(names)) {
186
+ if (!(slot in defaultVarNames(spec.kind))) {
187
+ return reply.code(400).send({ error: `A ${spec.what} exports nothing called "${slot}".` });
188
+ }
189
+ if (typeof name !== "string" || !VALID_VAR.test(name)) {
190
+ return reply.code(400).send({
191
+ error: `"${name}" is not a valid environment variable name: letters, digits and underscore, not starting with a digit.`,
192
+ });
193
+ }
194
+ }
195
+ if (!file && Object.keys(changed).length === 0 && Object.keys(names).length === 0) {
196
+ return reply.code(400).send({ error: "Send a field, a name, or a file to change." });
197
+ }
198
+ const updated = await ctx.vault.updateCredential(slug, spec.kind, {
199
+ file,
200
+ fields: changed,
201
+ varNames: names,
202
+ });
203
+ return updated ? reply.code(204).send() : reply.code(404).send({ error: "Unknown credential" });
204
+ });
103
205
  app.delete("/api/projects/:slug/credentials/:kind", async (req, reply) => {
104
206
  const { slug, kind } = req.params;
105
207
  const removed = ctx.vault.removeCredential(slug, kind);
@@ -42,9 +42,6 @@ export async function registerProjectRoutes(app, ctx) {
42
42
  * `.p8` or a keystore; the file that went in is still in the password
43
43
  * manager or the safe it came from. The answer says so, the way
44
44
  * `uninstall` does, so nobody is left thinking their keystore is gone.
45
- * - global secrets and global signing blocks. They are read by every project
46
- * on the machine, not this one's to take — `vault.forget` touches only
47
- * slug-scoped rows, and the answer counts the global ones it left alone.
48
45
  *
49
46
  * The confirmation is the project's own slug, sent back as `?confirm=`.
50
47
  * Without a match nothing is removed: a bare DELETE is a refusal, not a
@@ -73,12 +70,6 @@ export async function registerProjectRoutes(app, ctx) {
73
70
  error: `"${slug}" has a run in flight. Wait for it to finish, or cancel it, then remove the project.`,
74
71
  });
75
72
  }
76
- // The global counts are read now — the last moment anyone is looking — so
77
- // the answer can say what it left alone. They are shared by every project
78
- // and survive one of them going away, which is why the removal never takes
79
- // them and the reply names them apart.
80
- const globalSecrets = ctx.vault.listGlobal().length;
81
- const globalSigningBlocks = ctx.vault.listGlobalCredentials().length;
82
73
  // The removal itself lives in one place, shared with `laneyard remove`: the
83
74
  // route confirms and shapes the reply, the core does the deleting.
84
75
  const result = await removeProjectData({
@@ -109,13 +100,6 @@ export async function registerProjectRoutes(app, ctx) {
109
100
  secrets: result.secrets,
110
101
  signingBlocks: result.signingBlocks,
111
102
  },
112
- // Named, not removed. The git remote and the credential originals are the
113
- // user's and are never touched here; the global rows are shared by every
114
- // project and survive one of them going away.
115
- untouched: {
116
- globalSecrets,
117
- globalSigningBlocks,
118
- },
119
103
  });
120
104
  });
121
105
  app.get("/api/projects/:slug/lanes", async (req, reply) => {
@@ -1,6 +1,6 @@
1
1
  import { execFile } from "node:child_process";
2
2
  import { access, readFile } from "node:fs/promises";
3
- import { join } from "node:path";
3
+ import { isAbsolute, join, relative } from "node:path";
4
4
  import { promisify } from "node:util";
5
5
  import { glob } from "tinyglobby";
6
6
  import { Workspace } from "../../git/workspace.js";
@@ -99,17 +99,43 @@ async function isPresent(build, file) {
99
99
  */
100
100
  async function androidSigning(workspacePath, appRoot, unreachable) {
101
101
  if (unreachable !== null) {
102
- return { androidSigning: { ok: false, reason: unreachable }, signingFilePresent: false };
102
+ return { androidSigning: { ok: false, reason: unreachable }, signingFilePresent: false, signingFileAt: null };
103
103
  }
104
104
  const build = await findAndroidBuild(join(workspacePath, appRoot));
105
105
  if (build === null) {
106
106
  return {
107
107
  androidSigning: { ok: false, reason: "no android build.gradle found in the clone" },
108
108
  signingFilePresent: false,
109
+ signingFileAt: null,
109
110
  };
110
111
  }
111
112
  const present = build.facts.conditionalOn === null ? false : await isPresent(build, build.facts.conditionalOn);
112
- return { androidSigning: { ok: true, value: build.facts }, signingFilePresent: present };
113
+ return {
114
+ androidSigning: { ok: true, value: build.facts },
115
+ signingFilePresent: present,
116
+ signingFileAt: propertiesFileAt(build, join(workspacePath, appRoot)),
117
+ };
118
+ }
119
+ /**
120
+ * Where the build reads the properties file, relative to the app.
121
+ *
122
+ * The scope resolved into a path someone can paste into the block's form, and
123
+ * the same resolution `runner/gradle-properties.ts` makes — `root` is the Gradle
124
+ * root, `module` the app module. `unknown` stays null: that is the case the
125
+ * configured path exists to settle, and inventing a likely answer for it would
126
+ * put a file in the wrong directory with nothing to say it was a guess.
127
+ */
128
+ function propertiesFileAt(build, appRoot) {
129
+ const on = build.facts.conditionalOn;
130
+ if (on === null)
131
+ return null;
132
+ const dir = on.scope === "root" ? build.gradleRoot : on.scope === "module" ? build.moduleDir : null;
133
+ if (dir === null)
134
+ return null;
135
+ const inside = relative(appRoot, join(dir, on.name));
136
+ // A build outside the app root is a shape nothing here can name relative to
137
+ // it, and a `../` in this field would be refused by the runner anyway.
138
+ return inside.startsWith("..") || isAbsolute(inside) ? null : inside;
113
139
  }
114
140
  /**
115
141
  * What the keystore block says about the properties file, and nothing else.
@@ -135,6 +161,32 @@ function keystoreSetting(vault, slug) {
135
161
  }
136
162
  }
137
163
  export async function registerReadinessRoutes(app, ctx) {
164
+ /**
165
+ * Where this project's build reads its signing properties file.
166
+ *
167
+ * One fact, read from the clone, and the whole of what the keystore block's
168
+ * form cannot ask for itself: the field is a path relative to the app, and
169
+ * nobody types one of those correctly from a build script they are not looking
170
+ * at. Pre-filled with this, a wrong value is visible as a value that differs.
171
+ *
172
+ * Cheap enough to answer on opening a screen — two files parsed, no git, no
173
+ * bundler — which is why it is not part of the readiness answer even though
174
+ * that computes it too. Null for a project with no android build, or one whose
175
+ * script names the file in a way the parser cannot resolve to a directory.
176
+ */
177
+ app.get("/api/projects/:slug/signing-hints", async (req, reply) => {
178
+ const { slug } = req.params;
179
+ const entry = ctx.config.project(slug);
180
+ if (!entry)
181
+ return reply.code(404).send({ error: "Unknown project" });
182
+ const workspacePath = ctx.workspacePath(slug);
183
+ const resolved = await ctx.config.resolve(slug, workspacePath).catch(() => null);
184
+ const appRoot = appRootOf(resolved?.settings.fastlane_dir ?? "fastlane");
185
+ // The clone as it stands, never fetched for this: a screen opening must not
186
+ // pull a repository, and a project never cloned simply has no hint to give.
187
+ const build = await findAndroidBuild(searchDir(workspacePath, appRoot)).catch(() => null);
188
+ return { propertiesPath: build === null ? null : propertiesFileAt(build, searchDir(workspacePath, appRoot)) };
189
+ });
138
190
  /**
139
191
  * Computed only when asked for.
140
192
  *
@@ -228,9 +280,8 @@ export async function registerReadinessRoutes(app, ctx) {
228
280
  },
229
281
  // Names only: the vault never hands a value to anything but a run.
230
282
  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.
283
+ // Which blocks this project holds, read the way a run reads them, so the
284
+ // checklist and the run cannot disagree about whether a credential exists.
234
285
  blocks: ctx.vault.listCredentials(slug).map((c) => c.kind),
235
286
  // And the names those blocks will export, which the environment check
236
287
  // counts as supplied — Laneyard writes the file and sets the variable
@@ -1,23 +1,19 @@
1
1
  import { MIN_LENGTH as MIN_REDACTABLE } from "../../logs/redact.js";
2
2
  import { exportedVarNames } from "../../credentials/kinds.js";
3
3
  import { requiredSecrets } from "../required-secrets.js";
4
+ import { dotenvLine } from "../../runner/env-file.js";
5
+ import { envFileProblem, setEnvFileSetting } from "../../config/env-file-setting.js";
4
6
  /** POSIX environment variable names. Anything else would never reach fastlane. */
5
7
  const VALID_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;
6
8
  export async function registerSecretRoutes(app, ctx) {
7
- // A project's listing carries the values that were never declared secret; the
8
- // global one carries names only. Not a judgement about global secrets — it is
9
- // that `/api/secrets` answers for no project in particular, and a value is
10
- // only ever decrypted in the context of the project that reads it.
11
- const listRoute = (slug) => slug === null ? ctx.vault.listGlobal() : ctx.vault.listWithValues(slug);
12
- app.get("/api/secrets", async () => listRoute(null));
13
9
  app.get("/api/projects/:slug/secrets", async (req, reply) => {
14
10
  const { slug } = req.params;
15
11
  if (!ctx.config.project(slug))
16
12
  return reply.code(404).send({ error: "Unknown project" });
17
- return listRoute(slug);
13
+ return ctx.vault.listWithValues(slug);
18
14
  });
19
15
  const put = async (slug, key, body, reply) => {
20
- const { value, masked } = (body ?? {});
16
+ const { value, masked, inEnvFile } = (body ?? {});
21
17
  if (!VALID_KEY.test(key)) {
22
18
  return reply.code(400).send({
23
19
  error: `"${key}" is not a valid environment variable name: letters, digits and underscore, not starting with a digit.`,
@@ -35,10 +31,11 @@ export async function registerSecretRoutes(app, ctx) {
35
31
  "Store it unmasked if you accept it appearing in the output.",
36
32
  });
37
33
  }
38
- await ctx.vault.set(slug, key, value, masked !== false);
34
+ // Defaults to false: a variable goes in the file because someone said so,
35
+ // never because a field was left out of a request.
36
+ await ctx.vault.set(slug, key, value, masked !== false, inEnvFile === true);
39
37
  return reply.code(204).send();
40
38
  };
41
- app.put("/api/secrets/:key", async (req, reply) => put(null, req.params.key, req.body, reply));
42
39
  app.put("/api/projects/:slug/secrets/:key", async (req, reply) => {
43
40
  const { slug, key } = req.params;
44
41
  if (!ctx.config.project(slug))
@@ -69,31 +66,37 @@ export async function registerSecretRoutes(app, ctx) {
69
66
  return { key, value };
70
67
  });
71
68
  /**
72
- * Turns the redaction on or off, leaving the value alone.
69
+ * Turns a flag on or off, leaving the value alone.
73
70
  *
74
71
  * Needed because of a circle: to read a value you must first declare it not
75
72
  * secret, and declaring that by storing it again would mean typing the value
76
73
  * you were trying to read.
74
+ *
75
+ * Two independent flags, and either may be sent alone: `masked` is about what
76
+ * a run prints, `inEnvFile` about whether the variable is also written into
77
+ * the file the build reads. Sending one must not disturb the other — they
78
+ * answer different questions about the same row.
77
79
  */
78
80
  app.patch("/api/projects/:slug/secrets/:key", async (req, reply) => {
79
81
  const { slug, key } = req.params;
80
82
  if (!ctx.config.project(slug))
81
83
  return reply.code(404).send({ error: "Unknown project" });
82
- const { masked } = (req.body ?? {});
83
- if (typeof masked !== "boolean") {
84
+ const { masked, inEnvFile } = (req.body ?? {});
85
+ if (masked !== undefined && typeof masked !== "boolean") {
84
86
  return reply.code(400).send({ error: "`masked` is true or false." });
85
87
  }
88
+ if (inEnvFile !== undefined && typeof inEnvFile !== "boolean") {
89
+ return reply.code(400).send({ error: "`inEnvFile` is true or false." });
90
+ }
91
+ if (masked === undefined && inEnvFile === undefined) {
92
+ return reply.code(400).send({ error: "Send `masked`, `inEnvFile`, or both." });
93
+ }
86
94
  const existing = ctx.vault.list(slug).find((s) => s.key === key);
87
95
  if (!existing)
88
96
  return reply.code(404).send({ error: "Unknown secret" });
89
- if (existing.scope === "global") {
90
- // The same rule the interface draws: a global secret belongs to every
91
- // project, so changing it from inside one would hide that from the rest.
92
- return reply.code(409).send({ error: "That is a global secret. Change it with `laneyard secret set`." });
93
- }
94
97
  // A value too short to redact cannot be masked, the same refusal as on the
95
98
  // way in — accepting it would leave someone believing they are protected.
96
- if (masked) {
99
+ if (masked === true) {
97
100
  const value = ctx.vault.reveal(slug, key);
98
101
  if (value !== null && value.length < MIN_REDACTABLE) {
99
102
  return reply.code(400).send({
@@ -101,7 +104,80 @@ export async function registerSecretRoutes(app, ctx) {
101
104
  });
102
105
  }
103
106
  }
104
- ctx.vault.setMasked(slug, key, masked);
107
+ if (masked !== undefined)
108
+ ctx.vault.setMasked(slug, key, masked);
109
+ if (inEnvFile !== undefined)
110
+ ctx.vault.setInEnvFile(slug, key, inEnvFile);
111
+ return reply.code(204).send();
112
+ });
113
+ /**
114
+ * The environment file this project will write, before it writes it.
115
+ *
116
+ * The whole reason the flag lives on the variable rather than in a picker: a
117
+ * list of tick boxes cannot tell you that one is missing, and this can. What
118
+ * comes back is the file, rendered exactly as the run will render it, with
119
+ * every masked value replaced by dots.
120
+ *
121
+ * **The masking happens before the render, never after.** Rendering the real
122
+ * values and then trying to blank them would put every secret this project
123
+ * holds into a browser and hope the second pass caught them all. The values
124
+ * that leave this process are dots and the names beside them.
125
+ */
126
+ app.get("/api/projects/:slug/env-file", async (req, reply) => {
127
+ const { slug } = req.params;
128
+ if (!ctx.config.project(slug))
129
+ return reply.code(404).send({ error: "Unknown project" });
130
+ const resolved = await ctx.config.resolve(slug, ctx.workspacePath(slug));
131
+ const path = resolved?.settings.env_file ?? null;
132
+ const provenance = path === null ? null : (resolved?.provenance.env_file ?? null);
133
+ const masked = new Set(ctx.vault
134
+ .list(slug)
135
+ .filter((s) => s.masked)
136
+ .map((s) => s.key));
137
+ const values = ctx.vault.envFileValues(slug);
138
+ const body = Object.keys(values)
139
+ .sort()
140
+ .map((key) => (masked.has(key) ? `${key}=••••\n` : dotenvLine(key, values[key])))
141
+ .join("");
142
+ return { path, provenance, body };
143
+ });
144
+ /**
145
+ * Turns the environment file on, moves it, or turns it off.
146
+ *
147
+ * Writes `config.yml`, because that is where configuration lives — and it is
148
+ * written from here because a setting reachable only by editing YAML by hand
149
+ * is a feature nobody finds. The accounts screen already writes that file for
150
+ * the same reason.
151
+ *
152
+ * Refused where the repository's own `laneyard.yml` names the path: that file
153
+ * wins for every setting, and a screen that appeared to change it while the
154
+ * next run ignored what it wrote would be worse than one that says who decides.
155
+ */
156
+ app.put("/api/projects/:slug/env-file", async (req, reply) => {
157
+ const { slug } = req.params;
158
+ if (!ctx.config.project(slug))
159
+ return reply.code(404).send({ error: "Unknown project" });
160
+ const { path } = (req.body ?? {});
161
+ if (path !== null && typeof path !== "string") {
162
+ return reply.code(400).send({ error: "`path` is a path, or null to write no file." });
163
+ }
164
+ const resolved = await ctx.config.resolve(slug, ctx.workspacePath(slug));
165
+ if (resolved?.provenance.env_file === "repo") {
166
+ return reply.code(409).send({
167
+ error: "The repository's laneyard.yml sets env_file. Change it there, and commit it.",
168
+ });
169
+ }
170
+ if (typeof path === "string") {
171
+ const problem = envFileProblem(path.trim());
172
+ if (problem)
173
+ return reply.code(400).send({ error: problem });
174
+ }
175
+ const found = await setEnvFileSetting(ctx.config.configPath(), slug, typeof path === "string" ? path.trim() : null);
176
+ if (!found)
177
+ return reply.code(404).send({ error: "Unknown project" });
178
+ // The file is watched, but on a debounce: reloading here is what makes the
179
+ // very next request — the one this screen is about to send — truthful.
180
+ await ctx.config.load();
105
181
  return reply.code(204).send();
106
182
  });
107
183
  /**
@@ -136,17 +212,10 @@ export async function registerSecretRoutes(app, ctx) {
136
212
  workspacePath,
137
213
  fastlaneDir,
138
214
  vaultKeys: ctx.vault.list(slug).map((s) => s.key),
139
- // Resolved the way a run resolves them, a project's own block shadowing a
140
- // global one, so the form and the checklist cannot disagree about what is
141
- // already supplied.
142
215
  blockNames: exportedVarNames(ctx.vault.listCredentials(slug)),
143
216
  serverEnv: Object.keys(process.env),
144
217
  });
145
218
  });
146
- app.delete("/api/secrets/:key", async (req, reply) => {
147
- const removed = ctx.vault.remove(null, req.params.key);
148
- return removed ? reply.code(204).send() : reply.code(404).send({ error: "Unknown secret" });
149
- });
150
219
  app.delete("/api/projects/:slug/secrets/:key", async (req, reply) => {
151
220
  const { slug, key } = req.params;
152
221
  const removed = ctx.vault.remove(slug, key);
@@ -1,4 +1,4 @@
1
- import{r as Fn,j as Eh}from"./index-Cq1Ze8dP.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-D5rjA4_5.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}.field-list>li{display:flex;align-items:baseline;gap:10px}.field-list input[type=text]{width:32ch}.credentials-group .platform{margin:10px 0 0}.credentials .grow{white-space:normal;overflow:visible}.head-with-action{display:flex;align-items:baseline;gap:10px}.head-with-action button{text-transform:none;letter-spacing:normal;font-size:13px}.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}.env-file-preview{margin:0;padding:8px 12px;overflow-x:auto;white-space:pre;font:inherit;color:var(--text-dim);border-left:2px solid var(--border)}.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}.pair{display:inline-flex;align-items:baseline;gap:14px;min-width:0}.pair>.key{min-width:24ch}.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}}