@homeflare/alchemy 0.20.0 → 0.21.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.
- package/README.md +25 -0
- package/dist/caddy/access-forward-auth.d.ts +56 -0
- package/dist/caddy/access-forward-auth.d.ts.map +1 -0
- package/dist/caddy/index.d.ts +6 -0
- package/dist/caddy/index.d.ts.map +1 -1
- package/dist/caddy/index.js +169 -75
- package/dist/caddy/index.js.map +10 -7
- package/dist/cloudflare/mcp-server-api.d.ts +135 -0
- package/dist/cloudflare/mcp-server-api.d.ts.map +1 -0
- package/dist/cloudflare/mcp-server-form.d.ts +116 -0
- package/dist/cloudflare/mcp-server-form.d.ts.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/launchd/file-converge.d.ts +70 -0
- package/dist/launchd/file-converge.d.ts.map +1 -0
- package/dist/launchd/file-identity.d.ts +32 -0
- package/dist/launchd/file-identity.d.ts.map +1 -0
- package/dist/launchd/host-file-form.d.ts +2 -0
- package/dist/launchd/host-file-form.d.ts.map +1 -1
- package/dist/launchd/host-file-lifecycle.d.ts +11 -24
- package/dist/launchd/host-file-lifecycle.d.ts.map +1 -1
- package/dist/launchd/host-file.d.ts.map +1 -1
- package/dist/launchd/index.js +173 -120
- package/dist/launchd/index.js.map +12 -10
- package/dist/launchd/local-runner.d.ts.map +1 -1
- package/dist/launchd/runner.d.ts +17 -2
- package/dist/launchd/runner.d.ts.map +1 -1
- package/dist/launchd/sudo-runner.d.ts +11 -0
- package/dist/launchd/sudo-runner.d.ts.map +1 -1
- package/dist/linux/index.js.map +3 -3
- package/dist/linux/sudo-listing.d.ts +47 -0
- package/dist/linux/sudo-listing.d.ts.map +1 -0
- package/dist/proxmox/credential-literals.d.ts +1 -1
- package/dist/proxmox/credential-literals.d.ts.map +1 -1
- package/dist/proxmox/generated/pbs/nodes-node.d.ts +1 -1
- package/dist/proxmox/generated/pbs/nodes-node.d.ts.map +1 -1
- package/dist/proxmox/generated/pbs.d.ts +7 -0
- package/dist/proxmox/generated/pbs.d.ts.map +1 -1
- package/dist/proxmox/generated/pve.d.ts +7 -0
- package/dist/proxmox/generated/pve.d.ts.map +1 -1
- package/dist/proxmox/index.d.ts +1 -1
- package/dist/proxmox/index.d.ts.map +1 -1
- package/dist/proxmox/index.js +2 -2
- package/dist/proxmox/index.js.map +9 -9
- package/dist/proxmox/pbs-notification-target-form.d.ts +1 -1
- package/dist/proxmox/pbs-notification-target-form.d.ts.map +1 -1
- package/dist/proxmox/pbs-notification-target.d.ts +1 -1
- package/dist/proxmox/pbs-notification-target.d.ts.map +1 -1
- package/dist/release/archive.d.ts +11 -0
- package/dist/release/archive.d.ts.map +1 -0
- package/dist/release/binary-claim.d.ts +53 -0
- package/dist/release/binary-claim.d.ts.map +1 -0
- package/dist/release/binary-diff.d.ts +38 -0
- package/dist/release/binary-diff.d.ts.map +1 -0
- package/dist/release/binary-form.d.ts +118 -0
- package/dist/release/binary-form.d.ts.map +1 -0
- package/dist/release/binary-lifecycle.d.ts +55 -0
- package/dist/release/binary-lifecycle.d.ts.map +1 -0
- package/dist/release/binary-read.d.ts +11 -0
- package/dist/release/binary-read.d.ts.map +1 -0
- package/dist/release/binary.d.ts +68 -0
- package/dist/release/binary.d.ts.map +1 -0
- package/dist/release/catalog.d.ts +76 -0
- package/dist/release/catalog.d.ts.map +1 -0
- package/dist/release/checksums.d.ts +22 -0
- package/dist/release/checksums.d.ts.map +1 -0
- package/dist/release/declared-pins.d.ts +4 -0
- package/dist/release/declared-pins.d.ts.map +1 -0
- package/dist/release/download.d.ts +44 -0
- package/dist/release/download.d.ts.map +1 -0
- package/dist/release/fake-deploy.d.ts +48 -0
- package/dist/release/fake-deploy.d.ts.map +1 -0
- package/dist/release/fake-engine.d.ts +8 -0
- package/dist/release/fake-engine.d.ts.map +1 -0
- package/dist/release/fake-install.d.ts +39 -0
- package/dist/release/fake-install.d.ts.map +1 -0
- package/dist/release/fake-provider.d.ts +58 -0
- package/dist/release/fake-provider.d.ts.map +1 -0
- package/dist/release/fake-release.d.ts +95 -0
- package/dist/release/fake-release.d.ts.map +1 -0
- package/dist/release/index.d.ts +24 -0
- package/dist/release/index.d.ts.map +1 -0
- package/dist/release/index.js +1365 -0
- package/dist/release/index.js.map +35 -0
- package/dist/release/providers.d.ts +19 -0
- package/dist/release/providers.d.ts.map +1 -0
- package/dist/release/refused.d.ts +39 -0
- package/dist/release/refused.d.ts.map +1 -0
- package/dist/release/tar.d.ts +14 -0
- package/dist/release/tar.d.ts.map +1 -0
- package/dist/release/victoria.d.ts +36 -0
- package/dist/release/victoria.d.ts.map +1 -0
- package/dist/{proxmox → secrets}/write-only.d.ts.map +1 -1
- package/docs/release-binary-catalogs.md +113 -0
- package/docs/release-binary-measured.md +163 -0
- package/docs/release-binary-refusals.md +57 -0
- package/docs/release-binary-upstream.md +163 -0
- package/docs/release-binary.md +154 -0
- package/package.json +5 -1
- package/src/caddy/access-forward-auth.test.ts +63 -0
- package/src/caddy/access-forward-auth.ts +120 -0
- package/src/caddy/index.ts +10 -0
- package/src/caddy/providers.test.ts +4 -0
- package/src/cloudflare/mcp-server-api.ts +294 -0
- package/src/cloudflare/mcp-server-form.ts +219 -0
- package/src/index.ts +1 -0
- package/src/launchd/file-converge.ts +233 -0
- package/src/launchd/file-identity.ts +69 -0
- package/src/launchd/host-file-alias.test.ts +65 -0
- package/src/launchd/host-file-form.ts +2 -1
- package/src/launchd/host-file-lifecycle.ts +25 -144
- package/src/launchd/host-file.ts +8 -2
- package/src/launchd/local-runner.test.ts +12 -1
- package/src/launchd/local-runner.ts +2 -0
- package/src/launchd/runner.ts +17 -2
- package/src/launchd/sudo-runner.ts +11 -0
- package/src/linux/sudo-listing.ts +122 -0
- package/src/proxmox/credential-literals.ts +1 -1
- package/src/proxmox/generated/pbs/nodes-node.ts +1 -1
- package/src/proxmox/generated/pbs.ts +7 -0
- package/src/proxmox/generated/pve.ts +7 -0
- package/src/proxmox/index.ts +1 -1
- package/src/proxmox/pbs-notification-target-form.ts +1 -1
- package/src/proxmox/pbs-notification-target-lifecycle.ts +1 -1
- package/src/proxmox/pbs-notification-target-wire.ts +1 -1
- package/src/proxmox/pbs-notification-target.ts +1 -1
- package/src/release/adopt-parity.test.ts +106 -0
- package/src/release/apply-pins.test.ts +128 -0
- package/src/release/archive.ts +94 -0
- package/src/release/binary-alias.test.ts +109 -0
- package/src/release/binary-claim.ts +80 -0
- package/src/release/binary-claims.test.ts +47 -0
- package/src/release/binary-diff.ts +73 -0
- package/src/release/binary-form.ts +229 -0
- package/src/release/binary-lifecycle.test.ts +90 -0
- package/src/release/binary-lifecycle.ts +202 -0
- package/src/release/binary-read.ts +55 -0
- package/src/release/binary-refusals.test.ts +192 -0
- package/src/release/binary-sudo.test.ts +93 -0
- package/src/release/binary.ts +181 -0
- package/src/release/catalog.test.ts +96 -0
- package/src/release/catalog.ts +175 -0
- package/src/release/checksums.test.ts +35 -0
- package/src/release/checksums.ts +43 -0
- package/src/release/declared-pins.ts +39 -0
- package/src/release/download.test.ts +138 -0
- package/src/release/download.ts +110 -0
- package/src/release/error-channel.test.ts +69 -0
- package/src/release/fake-deploy.ts +87 -0
- package/src/release/fake-engine.ts +50 -0
- package/src/release/fake-install.ts +59 -0
- package/src/release/fake-provider.ts +68 -0
- package/src/release/fake-release.ts +185 -0
- package/src/release/fixtures/victoria/darwin-arm64-assets.txt +22 -0
- package/src/release/fixtures/victoria/victoria-logs-darwin-arm64-v1.52.0_checksums.txt +2 -0
- package/src/release/fixtures/victoria/victoria-metrics-darwin-arm64-v1.151.0_checksums.txt +2 -0
- package/src/release/fixtures/victoria/victoria-traces-darwin-arm64-v0.10.0_checksums.txt +2 -0
- package/src/release/fixtures/victoria/vmutils-darwin-arm64-v1.151.0_checksums.txt +8 -0
- package/src/release/index.ts +41 -0
- package/src/release/plan.test.ts +189 -0
- package/src/release/provider-refusals.test.ts +48 -0
- package/src/release/providers.test.ts +174 -0
- package/src/release/providers.ts +24 -0
- package/src/release/recovery-read.test.ts +44 -0
- package/src/release/refused.ts +40 -0
- package/src/release/tar.test.ts +142 -0
- package/src/release/tar.ts +195 -0
- package/src/release/victoria.test.ts +108 -0
- package/src/release/victoria.ts +154 -0
- package/src/{proxmox → secrets}/write-only.ts +6 -0
- /package/dist/{proxmox → secrets}/write-only.d.ts +0 -0
- /package/src/{proxmox → secrets}/write-only.test.ts +0 -0
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/launchd/host-file.ts", "../src/ownership/adopt.ts", "../src/ownership/resume.ts", "../src/ownership/rows.ts", "../src/ownership/whole.ts", "../src/launchd/
|
|
3
|
+
"sources": ["../src/launchd/host-file.ts", "../src/ownership/adopt.ts", "../src/ownership/resume.ts", "../src/ownership/rows.ts", "../src/ownership/whole.ts", "../src/launchd/file-identity.ts", "../src/launchd/host-effect.ts", "../src/launchd/job-form.ts", "../src/launchd/plist.ts", "../src/launchd/runner.ts", "../src/launchd/file-converge.ts", "../src/launchd/secret-tripwire.ts", "../src/launchd/host-file-form.ts", "../src/launchd/host-file-lifecycle.ts", "../src/launchd/job.ts", "../src/launchd/job-validate.ts", "../src/launchd/launchctl.ts", "../src/launchd/job-preflight.ts", "../src/launchd/job-lifecycle.ts", "../src/launchd/local-runner.ts", "../src/launchd/host-lookup.ts", "../src/launchd/providers.ts", "../src/launchd/sudo-allowlist.ts", "../src/launchd/sudo-acl.ts", "../src/launchd/sudo-guard.ts", "../src/launchd/sudo-said.ts", "../src/launchd/sudo-stage.ts", "../src/launchd/sudo-runner.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * `Host.File` — one text file on the host, declared: content, mode, owner, group.\n *\n * - create / update — atomic write (temp file in the same directory, mode and owner set, rename),\n * skipped when the file already matches; then read back and compared.\n * - read — lstat plus the SHA-256 of the bytes.\n * - diff — declared SHA-256 against the stored and on-disk digest, plus mode and owner.\n * - replace — only when `path` changes; create-before-delete.\n * - delete — removes the file.\n *\n * ⛔ NEVER A SECRET — see host-file-form.ts. Secret files stay rendered by openbao-agent.\n * ⚠️ NOTHING IS ADOPTED WITHOUT `--adopt`: a file already at the path reads as `Unowned`, and where\n * the plan never asked, reconcile refuses it unless adoption is on (docs/ownership.md).\n * ★ IT LIVES IN THE launchd SUBPATH because the two travel together: a Mac host stack declares a\n * daemon's config file and the daemon that reads it, through the same HostRunner.\n */\nimport { Resource } from 'alchemy';\nimport { Unowned } from 'alchemy/AdoptPolicy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport { adoptsAtApply } from '../ownership/adopt.ts';\nimport { noteUnfinished } from '../ownership/resume.ts';\nimport { lift, resolvedString } from './host-effect.ts';\nimport type { HostFileAttributes, HostFileProps } from './host-file-form.ts';\nimport { deleteFile, diffFile, readFileAttributes, reconcileFile } from './host-file-lifecycle.ts';\nimport { HostRunnerService } from './runner.ts';\n\nexport type { HostFileAttributes, HostFileProps } from './host-file-form.ts';\n\nexport interface HostFile extends Resource<'Host.File', HostFileProps, HostFileAttributes> {}\n\nexport const HostFile = Resource<HostFile>('Host.File');\n\nexport const HostFileProvider = () =>\n Provider.effect(\n HostFile,\n Effect.gen(function* () {\n const runner = yield* HostRunnerService;\n return HostFile.Provider.of({\n list: () => Effect.succeed([]),\n\n read: ({ olds, output }) =>\n lift(async () => {\n const found = await readFileAttributes(runner, olds.path);\n if (found === undefined) return undefined;\n return output === undefined ? Unowned(found) : found;\n }),\n\n diff: ({ instanceId, news, output }) => {\n // ★ An unfinished generation of our own: `--adopt` may resume it (ownership/resume.ts).\n if (output === undefined) return noteUnfinished(instanceId);\n if (isResolved(news)) return lift(() => diffFile(runner, news, output));\n // ⛔ A new path is a replace even while `content` is unresolved (an Output templated in):\n // the engine's default would be an update, which writes the new path and never\n // removes the old one. reconcileFile also defends, for a path that is an Output.\n const path = resolvedString(news, 'path');\n return Effect.succeed(
|
|
5
|
+
"/**\n * `Host.File` — one text file on the host, declared: content, mode, owner, group.\n *\n * - create / update — atomic write (temp file in the same directory, mode and owner set, rename),\n * skipped when the file already matches; then read back and compared.\n * - read — lstat plus the SHA-256 of the bytes.\n * - diff — declared SHA-256 against the stored and on-disk digest, plus mode and owner.\n * - replace — only when `path` changes; create-before-delete.\n * - delete — removes the file.\n *\n * ⛔ NEVER A SECRET — see host-file-form.ts. Secret files stay rendered by openbao-agent.\n * ⚠️ NOTHING IS ADOPTED WITHOUT `--adopt`: a file already at the path reads as `Unowned`, and where\n * the plan never asked, reconcile refuses it unless adoption is on (docs/ownership.md).\n * ★ IT LIVES IN THE launchd SUBPATH because the two travel together: a Mac host stack declares a\n * daemon's config file and the daemon that reads it, through the same HostRunner.\n */\nimport { Resource } from 'alchemy';\nimport { Unowned } from 'alchemy/AdoptPolicy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport { adoptsAtApply } from '../ownership/adopt.ts';\nimport { noteUnfinished } from '../ownership/resume.ts';\nimport { oneFile } from './file-identity.ts';\nimport { lift, resolvedString } from './host-effect.ts';\nimport type { HostFileAttributes, HostFileProps } from './host-file-form.ts';\nimport { deleteFile, diffFile, readFileAttributes, reconcileFile } from './host-file-lifecycle.ts';\nimport { HostRunnerService } from './runner.ts';\n\nexport type { HostFileAttributes, HostFileProps } from './host-file-form.ts';\n\nexport interface HostFile extends Resource<'Host.File', HostFileProps, HostFileAttributes> {}\n\nexport const HostFile = Resource<HostFile>('Host.File');\n\nexport const HostFileProvider = () =>\n Provider.effect(\n HostFile,\n Effect.gen(function* () {\n const runner = yield* HostRunnerService;\n return HostFile.Provider.of({\n list: () => Effect.succeed([]),\n\n read: ({ olds, output }) =>\n lift(async () => {\n const found = await readFileAttributes(runner, olds.path);\n if (found === undefined) return undefined;\n return output === undefined ? Unowned(found) : found;\n }),\n\n diff: ({ instanceId, news, output }) => {\n // ★ An unfinished generation of our own: `--adopt` may resume it (ownership/resume.ts).\n if (output === undefined) return noteUnfinished(instanceId);\n if (isResolved(news)) return lift(() => diffFile(runner, news, output));\n // ⛔ A new path is a replace even while `content` is unresolved (an Output templated in):\n // the engine's default would be an update, which writes the new path and never\n // removes the old one. reconcileFile also defends, for a path that is an Output.\n // ⛔ Unless the new path is the old FILE under another spelling (file-identity.ts):\n // a replace's Phase 2 would delete it. The update then records the new spelling.\n const path = resolvedString(news, 'path');\n if (path === undefined || path === output.path) return Effect.succeed(undefined);\n return lift(async () =>\n (await oneFile(runner, path, output.path)) === true\n ? undefined\n : { action: 'replace' as const },\n );\n },\n\n // ★ `--adopt` reaches the apply too: the probe never ran for a create with an Output prop.\n // ⛔ A create or an unfinished generation — never a fresh replace's, never offered it.\n reconcile: ({ fqn, instanceId, news, output }) =>\n Effect.flatMap(adoptsAtApply({ fqn, instanceId, output }), (adopt) =>\n lift(() => reconcileFile(runner, news, output, adopt)),\n ),\n\n delete: ({ output }) => lift(() => deleteFile(runner, output)),\n });\n }),\n );\n",
|
|
6
6
|
"/**\n * Whether a live object this stack holds no state for may be written — the apply-time half of the\n * house rule that NOTHING IS ADOPTED WITHOUT `--adopt` (decided 2026-09-21 for HostFile, LaunchdJob,\n * CaddyConfig and every Bao.* family). probe.ts is the plan-time half.\n *\n * ★ FAMILY-NEUTRAL ON PURPOSE. The engine questions here — what `--adopt` resolves to for one FQN,\n * whether this apply resumes the resource's own interrupted create — are the same for a vault\n * role, a launchd plist and a Caddy config, so they live once, outside every subpath's directory.\n */\nimport { AdoptPolicy } from 'alchemy/AdoptPolicy';\nimport { AlchemyContext } from 'alchemy/AlchemyContext';\nimport { Stack } from 'alchemy/Stack';\nimport * as Effect from 'effect/Effect';\nimport * as Option from 'effect/Option';\nimport { resumes, unfinished } from './resume.ts';\nimport { forgetRefusedCreate, isCreate } from './rows.ts';\n\n/**\n * Whether the resource at `fqn` may be adopted, resolved exactly as the planner resolves it (alchemy\n * beta.79 Plan.ts: `resource.Adopt ?? shouldAdopt`): a resource-scoped `adopt(…)`, else the\n * `AdoptPolicy` service, else `AlchemyContext.adopt`, else off.\n * ★ FOR A CREATE THE ENGINE NEVER PROBED. Alchemy skips the adoption probe while `news` holds an\n * Output, so an ownership check that must still honour `--adopt` can only run at apply. All three\n * reach the apply: Alchemist runs plan AND apply under the session context, which provides the\n * services from the CLI flag and the Stack the resources registered on (Alchemist/Session.ts,\n * routes/stack.ts; Apply.ts reads the same Stack).\n * ⛔ THE RESOURCE-SCOPED SETTING WINS, BOTH WAYS. The engine captures `adopt(…)` on the resource at\n * registration (Resource.ts `Adopt`, into `Stack.resources[fqn]`) and never hands it to a\n * provider. Reading only the deploy-wide flag let `--adopt` take over a resource declared\n * `.pipe(adopt(false))` — which the planner refuses — and refused one declared `adopt(true)`.\n * ⚠️ `resources` carries an `@internal` comment in Alchemy's source, but it is in the published types\n * and the planner reads `Adopt` from it. caddy/adopt-scope.test.ts registers through the real\n * `Resource`, so an upgrade that stops recording it there fails the suite.\n */\nexport const adoptEnabled = (fqn: string): Effect.Effect<boolean> =>\n Effect.gen(function* () {\n const stack = yield* Effect.serviceOption(Stack);\n const scoped = Option.isSome(stack) ? stack.value.resources[fqn]?.Adopt : undefined;\n if (scoped !== undefined) return scoped;\n const policy = yield* Effect.serviceOption(AdoptPolicy);\n if (Option.isSome(policy)) return policy.value;\n const context = yield* Effect.serviceOption(AlchemyContext);\n return Option.isSome(context) ? context.value.adopt : false;\n });\n\n/** The three fields of a `reconcile` (or `read`) call that say whose object this is. */\nexport type Owner = {\n readonly fqn: string;\n readonly instanceId: string;\n /** The attributes state holds; `undefined` on a create. */\n readonly output: unknown;\n};\n\n/**\n * Whether `--adopt` may speak for this apply's generation: a CREATE (rows.ts isCreate), or an\n * UNFINISHED generation whose row this plan's diff saw with no attributes (resume.ts) — the\n * resume Alchemy itself offers `--adopt` for (\"Cannot resume creating … Re-run with --adopt\").\n * ⛔ NOT A FRESH REPLACE'S NEW GENERATION. The planner never probes it and never offers it adoption,\n * so the identity it moves to was never asked about under `--adopt`: 🔴 MEASURED 2026-09-21\n * (launchd/adopt-apply.test.ts), a HostFile whose path changed onto a file it did not own\n * overwrote that file under a deploy-wide `--adopt` meant for something else. A Bao rename onto a\n * taken identity already fails the plan, `--adopt` or not (rename.ts judgeMove); this keeps the\n * apply to the same answer.\n */\nconst adoptable = (owner: Owner): Effect.Effect<boolean> =>\n Effect.gen(function* () {\n if (yield* isCreate(owner.fqn, owner.instanceId)) return true;\n return yield* unfinished(owner.instanceId);\n });\n\n/** Whether a stateless `reconcile` may take over a live object: adoption on, for an adoptable one. */\nexport const adoptsAtApply = (owner: Owner): Effect.Effect<boolean> =>\n Effect.gen(function* () {\n if (!(yield* adoptEnabled(owner.fqn))) return false;\n return yield* adoptable(owner);\n });\n\n/** A lifecycle helper's hook for refuseTakeover, bound to one call's Owner: `(what) => …`. */\nexport type Claim = (what: string) => Effect.Effect<void>;\n\n/**\n * `reconcile`'s check, called with the live object it found BEFORE any write: dies unless that\n * object may be written. It may when state already vouches for it (`output`), when this apply\n * resumes the resource's own interrupted create or replace and its diff proved the object that\n * generation's (resume.ts), or when adoption is on for a create or an unfinished generation\n * (adoptable).\n * ⛔ WHY IT EXISTS AT ALL: THE PROBE DOES NOT GUARD EVERY CREATE. Alchemy skips it while `news` holds\n * an Output (Plan.ts), a new generation of a replace is never probed, and an object can appear\n * between plan and apply. Each of those used to be a silent takeover: written over, then recorded\n * as ours, and deleted with the stack under `destroy`.\n * ⚠️ A CHECK, THEN A WRITE — NOT A LOCK. Two creates of one name in the same deploy run\n * concurrently, both read nothing, and both write (measured with the fakes, 2026-09-21). Nothing\n * between a read and a write can close that; declare each name once.\n * ⚠️ AN IDENTICAL OBJECT IS STILL A TAKEOVER (decided 2026-09-21). Nothing would be written, but the\n * state row would claim it, and a later delete would remove what another owner still relies on.\n * ⛔ A REFUSED CREATE FORGETS ITS `creating` ROW (rows.ts forgetRefusedCreate), or the next plan's\n * recovery read would adopt the very object this refused.\n */\nexport const refuseTakeover = (owner: Owner, what: string): Effect.Effect<void> =>\n Effect.gen(function* () {\n if (owner.output !== undefined) return;\n if (yield* resumes(owner.instanceId)) return;\n const may = yield* adoptable(owner);\n if (may && (yield* adoptEnabled(owner.fqn))) return;\n yield* forgetRefusedCreate(owner.fqn, owner.instanceId);\n const remedy = may\n ? 'Deploy with --adopt (or wrap the resource in adopt(true)) to take it over, or remove it first.'\n : 'It is the new identity of a replace, which --adopt does not cover: remove it first.';\n return yield* Effect.die(\n new Error(\n `${what}: already exists, and this stack holds no state for it — the plan could not ask ` +\n 'first (a prop was still an Output, a replace moved onto it, or it appeared after the ' +\n `plan). Nothing was written. ${remedy}`,\n ),\n );\n });\n\n/** refuseTakeover bound to one call's Owner, for a lifecycle helper that finds the live object. */\nexport const claimFor =\n (owner: Owner): Claim =>\n (what) =>\n refuseTakeover(owner, what);\n",
|
|
7
7
|
"/**\n * Whether this apply RESUMES a create or replace the engine already started for this resource AND\n * the live object it will find is proven that generation's own — the one case in which a stateless\n * `reconcile` may write over a live object without `--adopt`.\n *\n * ★ HOW THE ENGINE TELLS US. Alchemy calls `diff` whenever a state row exists, and hands it `output`\n * = that row's attributes (alchemy beta.79 Plan.ts). A row with NO attributes is exactly an\n * unfinished generation: `creating` (a create interrupted after its write, before its commit),\n * `replacing` (the same for a replace), or `deleting` re-driven as a create. A fresh create is\n * never diffed at all. So the diff of such a row decides, and the apply that follows (the same\n * instance id: Apply.ts reuses the row's) finds the note.\n * ⛔ A ROW PROVES NOTHING BY ITSELF (red team, 2026-09-21). Apply commits it BEFORE reconcile runs, so\n * a deploy killed before the claim — an upstream that failed, a Ctrl-C — leaves a row whose create\n * never asked whose object sat at its identity. 🔴 MEASURED (openbao/adopt-holes.test.ts): with the\n * name an Output, the next deploy \"resumed\" that create and wrote over another owner's role, in\n * every family that had a note on the row alone. So the note is left only when the family's own\n * `read`, asked as the recovery read (probe.ts ownedRead: a recorded instance, a row carrying the\n * whole declaration, and a live object that matches it), answers \"ours\". For a `creating` row\n * that is the question Plan.ts already asked; for a `replacing` row it is the only time it is asked.\n * ⚠️ WHY NOT THE STATE STORE ALONE. At reconcile both look the same: Apply commits the fresh create's\n * `creating` row before calling reconcile, so a row with this instance id is always there.\n * ★ THE CHANNEL IS ALCHEMY'S OWN: `Artifacts`, the per-FQN bag the engine shares between one plan\n * and its apply (Artifacts.ts: \"diff computes … create / update reads the same artifact\").\n * Deploy.ts and the Alchemist session both hold one store across the pair.\n * ⚠️ IT FAILS CLOSED. No bag, a bag the plan never wrote, or an object the read cannot prove ours\n * reads as a fresh create, and adopt.ts then asks for `--adopt` — the safe direction.\n * ★ AN UNPROVEN RESUME IS STILL MARKED UNFINISHED (`noteUnfinished`), so `--adopt` can take it over\n * the way Alchemy's own \"Cannot resume creating … Re-run with --adopt\" offers for a create — while\n * a FRESH replace's new generation, which no diff ever saw without attributes, stays unadoptable.\n */\nimport { Unowned } from 'alchemy/AdoptPolicy';\nimport { Artifacts } from 'alchemy/Artifacts';\nimport * as Effect from 'effect/Effect';\nimport * as Option from 'effect/Option';\n\nconst PROVEN = 'homeflare/ownership/resumes';\nconst UNFINISHED = 'homeflare/ownership/unfinished';\n\nconst note = (key: string, instanceId: string): Effect.Effect<void> =>\n Effect.gen(function* () {\n const bag = yield* Effect.serviceOption(Artifacts);\n if (Option.isSome(bag)) yield* bag.value.set(key, instanceId);\n });\n\nconst noted = (key: string, instanceId: string): Effect.Effect<boolean> =>\n Effect.gen(function* () {\n const bag = yield* Effect.serviceOption(Artifacts);\n if (Option.isNone(bag)) return false;\n return (yield* bag.value.get<string>(key)) === instanceId;\n });\n\n/**\n * `diff`'s note for a row with no attributes: `instanceId` is an unfinished generation of this\n * resource's own, which `--adopt` may resume when nothing proves it (adopt.ts adoptable). Returns\n * `undefined`, a diff's \"defer to the engine\".\n */\nexport const noteUnfinished = (instanceId: string): Effect.Effect<undefined> =>\n Effect.as(note(UNFINISHED, instanceId), undefined);\n\n/**\n * Note `instanceId` unfinished, and a proven resume when `recovered` — the family's `read` of the\n * row's props, asked with no attributes — answers a plain object: ours. `Unowned`, nothing, or a\n * read that fails or dies proves nothing. ⚠️ Never fails the plan: an unproven resume is refused\n * at apply instead, unless `--adopt`.\n */\nexport const noteResume = <R>(\n instanceId: string,\n recovered: Effect.Effect<unknown, unknown, R>,\n): Effect.Effect<void, never, R> =>\n Effect.gen(function* () {\n yield* noteUnfinished(instanceId);\n const unproven = () => Effect.succeed(undefined);\n const found = yield* recovered.pipe(Effect.catch(unproven), Effect.catchDefect(unproven));\n if (found === undefined || found === null || Unowned.is(found)) return;\n yield* note(PROVEN, instanceId);\n });\n\n/** Whether the plan for this apply noted `instanceId` as a proven resumed create or replace. */\nexport const resumes = (instanceId: string): Effect.Effect<boolean> => noted(PROVEN, instanceId);\n\n/** Whether the plan for this apply saw `instanceId` as an unfinished generation (proven or not). */\nexport const unfinished = (instanceId: string): Effect.Effect<boolean> =>\n noted(UNFINISHED, instanceId);\n\n/** The fields of a `read` or `diff` call provingResumes uses; a family's own input carries more. */\ntype Ask = {\n readonly id: string;\n readonly fqn: string;\n readonly instanceId: string;\n readonly olds: unknown;\n readonly output: unknown;\n};\ntype Hook = Effect.Effect<unknown, unknown, unknown>;\n\n/** The two hooks provingResumes wraps, as Alchemy's ProviderService declares them. */\ninterface Resumable {\n read?(input: Ask): Hook;\n diff?(input: Ask): Hook;\n}\n\n/**\n * A provider whose `diff`, for a row with no attributes, first asks the provider's own `read` whether\n * the live object is that unfinished generation's (noteResume), then runs as written. Every Bao.*\n * family is built through it, so their diffs answer such a row with a plain `undefined`.\n */\nexport const provingResumes = <S extends Resumable>(service: S): S => {\n const { diff, read } = service;\n if (diff === undefined || read === undefined) return service;\n const proving: Resumable['diff'] = (input) =>\n Effect.gen(function* () {\n if (input.output === undefined) {\n yield* noteResume(input.instanceId, read({ ...input, output: undefined }));\n }\n return yield* diff(input);\n });\n // ⚠️ The one cast: `diff` keeps the family's own signature — it is the family's diff, run after.\n return { ...service, diff: proving } as S;\n};\n",
|
|
8
8
|
"/**\n * The questions ownership/ asks of Alchemy's state store: does a row record this instance, and with\n * its whole declaration (probe.ts); is this apply a create rather than a replace's new generation\n * (adopt.ts); and — when reconcile refuses a create — forget the row Apply committed for it\n * (adopt.ts). Alchemy's own AWS.EC2.SecurityGroup provider reads the store the same way: the Stack\n * service names the stack and stage, and `State` yields the store.\n *\n * ⚠️ WITHOUT A STACK OR STATE IN CONTEXT, or with a store that errors, a row reads as \"not\n * recorded\" — the object is then `Unowned`, the safe answer — and nothing is forgotten, which\n * leaves the one gap forgetRefusedCreate exists to close. `alchemy deploy` and the Alchemist\n * session provide both.\n */\nimport { Stack } from 'alchemy/Stack';\nimport { State, type StateService, isActionState } from 'alchemy/State/State';\nimport * as Effect from 'effect/Effect';\nimport * as Option from 'effect/Option';\nimport { wholeDeclaration } from './whole.ts';\n\ntype Where = { readonly stack: string; readonly stage: string };\n\n/** The store, where this stack lives, and what it declares — or undefined outside a stack. */\nconst storeOf = Effect.gen(function* () {\n const stack = yield* Effect.serviceOption(Stack);\n const state = yield* Effect.serviceOption(State);\n if (Option.isNone(stack) || Option.isNone(state)) return undefined;\n const store: StateService = yield* state.value;\n const where: Where = { stack: stack.value.name, stage: stack.value.stage };\n return { resources: stack.value.resources, store, where };\n});\n\nconst rowAt = (store: StateService, where: Where, fqn: string) =>\n store.get({ ...where, fqn }).pipe(Effect.orElseSucceed(() => undefined));\n\n/** One generation of a persisted row, as far as ownership/ reads it. */\nexport type Generation = {\n readonly instanceId?: unknown;\n readonly status?: unknown;\n readonly props?: unknown;\n readonly attr?: unknown;\n readonly old?: unknown;\n /** Set by Apply on the `updating` row of an adoption, until that update commits (Apply.ts). */\n readonly adopting?: unknown;\n};\n\n/** The generation of a persisted row that carries `instanceId`: the row itself, or one in `old`. */\nconst generationOf = (row: unknown, instanceId: string): Generation | undefined => {\n let at = row;\n while (typeof at === 'object' && at !== null && !isActionState(at as never)) {\n const generation = at as Generation;\n if (generation.instanceId === instanceId) return generation;\n at = generation.old;\n }\n return undefined;\n};\n\n/** The generation `instanceId` names — at the FQN, or at a former FQN `renamedFrom` names. */\nexport const recordedGeneration = (\n fqn: string,\n instanceId: string,\n): Effect.Effect<Generation | undefined> =>\n Effect.gen(function* () {\n const found = yield* storeOf;\n if (found === undefined) return undefined;\n for (const at of [fqn, ...(found.resources[fqn]?.FormerFqns ?? [])]) {\n const generation = generationOf(yield* rowAt(found.store, found.where, at), instanceId);\n if (generation !== undefined) return generation;\n }\n return undefined;\n });\n\n/**\n * What the state store says of `instanceId` for this resource (at its FQN, or at a former FQN its\n * `renamedFrom` names — the planner migrates that row before it recovers it):\n * · `absent` — no row holds it. ★ This is what separates the probe from the recovery read: the\n * probe's instance id is minted for the probe (Plan.ts `generateInstanceId()`), 128 random bits\n * no row can hold.\n * · `partial` — a row holds it, but its props lack part of the declaration: a prop stripped at\n * commit because it was still an Output (whole.ts). Those props cannot prove an object ours.\n * · `whole` — a row holds it with every prop the declaration names.\n */\nexport type Recorded = 'absent' | 'partial' | 'whole';\n\nexport const recordedInstance = (fqn: string, instanceId: string): Effect.Effect<Recorded> =>\n Effect.gen(function* () {\n const generation = yield* recordedGeneration(fqn, instanceId);\n if (generation === undefined) return 'absent';\n return (yield* wholeDeclaration(fqn, generation.props)) ? 'whole' : 'partial';\n });\n\n/**\n * Whether this apply's `instanceId` is a CREATE: the row Apply committed for it is `creating`.\n * ⛔ A REPLACE'S NEW GENERATION IS NOT ONE. Apply commits it as `replacing`, and the planner never\n * offers it adoption — the probe runs only for a resource with no state — so `--adopt` must not\n * let it write over whatever sits at its new identity (adopt.ts adoptsAtApply).\n */\nexport const isCreate = (fqn: string, instanceId: string): Effect.Effect<boolean> =>\n Effect.map(\n recordedGeneration(fqn, instanceId),\n (generation) => generation?.status === 'creating',\n );\n\n/**\n * ⛔ A REFUSED CREATE MUST NOT LEAVE A ROW THAT CLAIMS THE OBJECT IT REFUSED. Apply commits a\n * `creating` row for this instance before it calls reconcile, and a failed reconcile leaves it\n * there. The next plan's recovery read would then find our instance id and an object that can\n * match its props — a prop that was an Output is stripped from the row, and an omitted prop is\n * \"not managed\" — and adopt exactly what this apply refused. 🔴 MEASURED 2026-09-21: Bao.Mount\n * and Bao.AuthMethod did (openbao/adopt-core.test.ts). So the row goes, and state reads as if\n * the create never started: the next plan probes, and the probe answers `Unowned`.\n * ⚠️ ONLY a `creating` row of THIS instance with no attributes — the one Apply just wrote. A\n * `replacing` row carries the previous generation in `old` and is never touched.\n */\nexport const forgetRefusedCreate = (fqn: string, instanceId: string): Effect.Effect<void> =>\n Effect.gen(function* () {\n const found = yield* storeOf;\n if (found === undefined) return;\n const row = yield* rowAt(found.store, found.where, fqn);\n const mine = row as { status?: unknown; instanceId?: unknown; attr?: unknown } | undefined;\n if (mine?.status !== 'creating' || mine.instanceId !== instanceId || mine.attr !== undefined) {\n return;\n }\n yield* found.store.delete({ ...found.where, fqn }).pipe(Effect.ignore);\n });\n",
|
|
9
9
|
"/**\n * Whether a state row's props say everything the declaration says — the test that separates a row\n * whose props can prove an object ours from one that cannot (probe.ts, rows.ts).\n *\n * ★ WHY A ROW CAN BE MISSING PART OF ITS DECLARATION. Apply commits the `creating` (or `replacing`)\n * row BEFORE reconcile runs, and strips every prop still an Output at that moment (alchemy\n * beta.79 Apply.ts `commit` → Diff.ts `stripUnresolved`); a JSON store then drops the key. So a\n * row written while an upstream was still being created carries a HOLE where that prop was.\n * ⛔ A HOLE IS \"UNKNOWN\", NOT \"UNMANAGED\". Most families read an absent prop as \"not managed\", so a\n * recovery read comparing the live object with holed props proves nothing: 🔴 MEASURED 2026-09-21\n * (openbao/adopt-holes.test.ts), a Bao.Mount whose `defaultLeaseTtl` was an Output, killed before\n * its reconcile ran, adopted — and tuned — another owner's mount on the next deploy; with the\n * NAME an Output, every role family read an empty name, found nothing, and the resumed create\n * wrote over another owner's role. Neither deploy had ever asked whose object it was.\n * ★ THE DECLARATION IS WHAT TELLS A HOLE FROM AN OMISSION. It still holds the Output (or the literal)\n * the row lacks, while an optional prop left out is absent from both.\n * ⚠️ CONSERVATIVE BY DESIGN: a prop added to the declaration after the crash also reads as a hole.\n * That costs one `--adopt`, never a takeover.\n */\nimport { Stack } from 'alchemy/Stack';\nimport * as Effect from 'effect/Effect';\nimport * as Option from 'effect/Option';\n\nconst absent = (value: unknown): boolean => value === undefined || value === null;\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n const proto: unknown = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n};\n\n/**\n * Whether `recorded` carries a value everywhere `declared` does. Plain objects and arrays are\n * walked; any other declared value — a literal, an Output, an Effect — needs a value in the row.\n */\nexport const carries = (declared: unknown, recorded: unknown): boolean => {\n if (absent(declared)) return true;\n if (absent(recorded)) return false;\n if (Array.isArray(declared)) {\n if (!Array.isArray(recorded)) return false;\n return declared.every((each, index) => carries(each, recorded[index]));\n }\n if (isPlainObject(declared)) {\n if (!isPlainObject(recorded)) return false;\n return Object.entries(declared).every(([key, each]) => carries(each, recorded[key]));\n }\n return true;\n};\n\n/**\n * Whether `props` — one generation's, from the state store — carry the whole declaration of the\n * resource at `fqn`. ⛔ FALSE WITH NOTHING TO COMPARE: no Stack in context, or a resource no longer\n * declared (an orphan's delete). That object then reads as `Unowned` and Apply leaves it in place\n * with a note, rather than deleting what it cannot prove it made.\n */\nexport const wholeDeclaration = (fqn: string, props: unknown): Effect.Effect<boolean> =>\n Effect.map(Effect.serviceOption(Stack), (stack) => {\n const declared = Option.isSome(stack) ? stack.value.resources[fqn] : undefined;\n return declared !== undefined && carries(declared.Props, props);\n });\n",
|
|
10
|
+
"/**\n * Whether two paths name ONE file — the question a move must answer before it deletes its old\n * path, and a plan before it answers `replace`.\n *\n * 🔴 MEASURED 2026-09-22 (release/binary-alias.test.ts, localRunner over a real temp directory,\n * through Alchemy's own Plan and Apply): a Release.Binary whose directory was respelled to\n * another path for the SAME file — through a symlinked parent (`/tmp` → `/private/tmp`, `/etc`\n * → `/private/etc`), or by case alone on case-insensitive APFS, macOS's default — planned a\n * `replace`. The new generation took the file already there as its own (same bytes, same mode:\n * file-converge.ts's resume rule), then Phase 2 deleted the old generation's path, which was that\n * same file. The deploy SUCCEEDED and the binary was gone. The `update` route lost it in one step:\n * convergeFile's move removed the old path after \"writing\" the new one. Host.File shares both.\n * ★ IDENTITY, NOT SPELLING. Case-folding the strings would be wrong on a case-sensitive volume and\n * blind to a symlinked parent; device and inode from lstat are what the kernel itself compares.\n * ⚠️ A HARD LINK also shares an inode. At the old path of a move it is therefore kept, not removed:\n * one stray link left behind, rather than the risk of deleting the file just verified.\n */\nimport type { FileStat, HostRunner } from './runner.ts';\n\n/**\n * `true` when both entries exist and are one file; `false` when either is absent or they differ;\n * `undefined` when the runner reported no identity, so nobody can tell (fakes, custom runners).\n */\nexport const sameEntry = (\n a: FileStat | undefined,\n b: FileStat | undefined,\n): boolean | undefined => {\n if (a === undefined || b === undefined) return false;\n if (a.dev === undefined || a.ino === undefined || b.dev === undefined || b.ino === undefined) {\n return undefined;\n }\n return a.dev === b.dev && a.ino === b.ino;\n};\n\n/** Whether `a` and `b` are one file on this host right now. Equal strings always are. */\nexport const oneFile = async (\n runner: HostRunner,\n a: string,\n b: string,\n): Promise<boolean | undefined> => {\n if (a === b) return true;\n const [left, right] = await Promise.all([runner.stat(a), runner.stat(b)]);\n return sameEntry(left, right);\n};\n\n/**\n * The last step of a move: `remove` the old path unless it is the file just verified at `path`.\n * ⚠️ A runner that reports no identity cannot be asked beforehand, so `path` is checked after: a\n * file lost to a respelling then fails the deploy instead of reporting success.\n */\nexport const leaveOldPath = async (\n runner: HostRunner,\n oldPath: string,\n path: string,\n remove: () => Promise<void>,\n refuse: (path: string, message: string) => Error,\n): Promise<void> => {\n const same = await oneFile(runner, oldPath, path);\n if (same === true) return;\n await remove();\n if (same === undefined && (await runner.stat(path)) === undefined) {\n throw refuse(\n path,\n `removing the old path ${oldPath} removed this file too: they are one file under two ` +\n 'spellings (a symlinked parent, or case on a case-insensitive volume). Deploy again to ' +\n 'reinstall it, and keep one spelling.',\n );\n }\n};\n",
|
|
10
11
|
"/**\n * The one place a HostRunner's promises become Effects — plus the one probe of an unresolved\n * `news` both providers' diffs share. (The engine's adopt setting lives in ownership/adopt.ts.)\n *\n * ★ The lifecycle files are plain async functions over a HostRunner (see runner.ts for why the\n * runner is promise-based), so each provider handler is a single `lift(() => step(runner, …))`.\n * ⚠️ A thrown Error stays that Error — its message is the refusal a deploy prints. Anything else\n * thrown is wrapped, so the failure channel is always an Error with a readable message.\n */\nimport * as Effect from 'effect/Effect';\n\nexport const lift = <A>(step: () => Promise<A>): Effect.Effect<A, Error> =>\n Effect.tryPromise({\n catch: (cause) => (cause instanceof Error ? cause : new Error(String(cause))),\n try: step,\n });\n\n/**\n * A string prop of a diff's `news`, when that one prop is already resolved; `undefined` while it\n * is still an Output (a function-typed proxy), an Effect or a Config.\n * ★ For the identity props a diff must see even when the rest of `news` is unresolved — a plain\n * string is resolved by definition, so `typeof` is the whole test.\n */\nexport const resolvedString = (news: unknown, key: string): string | undefined => {\n if (typeof news !== 'object' || news === null) return undefined;\n const value = (news as Record<string, unknown>)[key];\n return typeof value === 'string' ? value : undefined;\n};\n",
|
|
11
|
-
"/**\n * A tripwire for the obvious ways a secret ends up in Alchemy state through these providers.\n *\n * ⛔ WHY IT EXISTS. Alchemy persists every prop UNENCRYPTED in its state store — the same reason\n * the OpenBao families are metadata-only (openbao/policy.ts). A LaunchdJob's `environment` and\n * `programArguments`, and a HostFile's `content`, are props. A token declared there is a token\n * copied into the state store, into every plan diff, and into the plist or file on disk.\n * ★ THE ALTERNATIVE, NAMED IN EVERY REFUSAL: let a secret renderer (openbao-agent, or any other)\n * write the secret to a root-owned file, and declare only its PATH — `FOO_TOKEN_FILE=/path`,\n * `--token-file /path`. The job reads the file at start; the state holds a path.\n *\n * ⚠️ A TRIPWIRE, NOT A SCANNER. It catches the names and shapes people actually type. A token in\n * an innocently named variable passes; nothing here can make a secret safe to declare.\n */\nimport type { PlistDict, PlistValue } from './plist.ts';\n\nconst ALTERNATIVE =\n 'props are stored unencrypted in Alchemy state. Have a secret renderer (e.g. openbao-agent) ' +\n 'write it to a root-owned file and declare the file path instead (FOO_FILE=/path, --foo-file /path).';\n\n/** Names that end in a word meaning \"this is the secret itself\". `*_FILE`, `*_PATH` never match. */\nconst SECRET_NAME =\n /(?:^|_)(?:TOKEN|SECRET|PASSWORD|PASSWD|PASSPHRASE|API_?KEY|ACCESS_KEY|PRIVATE_KEY|SECRET_KEY|CREDENTIALS?)$/i;\n\n/** `--token=…` / `-password=…` style flags carrying their value inline. */\nconst INLINE_FLAG = /^--?[a-z0-9-]*(?:token|password|passwd|passphrase|secret|api-?key)=./i;\n\n/** A flag whose NEXT argv element is the secret: `--token abc`. */\nconst BARE_FLAG = /^--?(?:[a-z0-9]+-)*(?:token|password|passwd|passphrase|secret|api-?key)$/i;\n\nexport const PRIVATE_KEY = /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----/;\n\n/** Paths of every string leaf in a plist value holding a private key. */\nconst keyLeaves = (value: PlistValue, path: string): string[] => {\n if (typeof value === 'string') return PRIVATE_KEY.test(value) ? [path] : [];\n if (Array.isArray(value)) {\n return (value as readonly PlistValue[]).flatMap((item, index) =>\n keyLeaves(item, `${path}[${String(index)}]`),\n );\n }\n if (typeof value === 'object' && value !== null) {\n return Object.entries(value).flatMap(([key, item]) => keyLeaves(item, `${path}.${key}`));\n }\n return [];\n};\n\n/**\n * Refusals for a job's environment, argv and extraKeys. Empty means nothing tripped.\n * ★ extraKeys too: it is a prop like the others, so it lands in state just the same.\n */\nexport const jobSecretProblems = (\n environment: Readonly<Record<string, string>> | undefined,\n argv: readonly string[],\n extraKeys?: PlistDict,\n): string[] => {\n const found: string[] = [];\n for (const [name, value] of Object.entries(environment ?? {})) {\n if (SECRET_NAME.test(name))\n found.push(`environment ${name} looks like a secret: ${ALTERNATIVE}`);\n else if (PRIVATE_KEY.test(value))\n found.push(`environment ${name} holds a private key: ${ALTERNATIVE}`);\n }\n for (const [index, arg] of argv.entries()) {\n // ⛔ Never echo the argument itself: if it IS a secret, the refusal would print it.\n if (INLINE_FLAG.test(arg)) {\n found.push(`programArguments[${String(index)}] passes a secret inline: ${ALTERNATIVE}`);\n } else if (BARE_FLAG.test(arg) && index + 1 < argv.length) {\n found.push(`programArguments[${String(index + 1)}] follows a secret flag: ${ALTERNATIVE}`);\n } else if (PRIVATE_KEY.test(arg)) {\n found.push(`programArguments[${String(index)}] holds a private key: ${ALTERNATIVE}`);\n }\n }\n for (const path of keyLeaves(extraKeys ?? {}, 'extraKeys')) {\n found.push(`${path} holds a private key: ${ALTERNATIVE}`);\n }\n return found;\n};\n\n/** Refusals for a HostFile's content. */\nexport const fileSecretProblems = (content: string): string[] =>\n PRIVATE_KEY.test(content) ? [`content holds a private key: ${ALTERNATIVE}`] : [];\n",
|
|
12
|
-
"/**\n * HostFile's props, attributes and validation — the pure half of the provider.\n *\n * ⛔ `content` IS NEVER A SECRET. Alchemy stores props unencrypted, so the content of every HostFile\n * sits in the state store and in every plan diff. A secret file stays RENDERED BY A SECRET\n * RENDERER (openbao-agent templates, on this estate) that fetches it at run time; the stack\n * declares only non-secret config, and at most the PATH the renderer writes to.\n * secret-tripwire.ts refuses the obvious case (a PEM private key); nothing can catch all of them.\n */\nimport { fileSecretProblems } from './secret-tripwire.ts';\n\nexport interface HostFileProps {\n /** Absolute path. The parent directory must already exist. */\n path: string;\n /** UTF-8 text. ⛔ Never a secret — see the file header. */\n content: string;\n /** Permission bits. @default 0o644 */\n mode?: number;\n /** User name or numeric uid. Omitted: whoever the runner writes as (a rewrite keeps no owner). */\n owner?: string | number;\n /** Group name or numeric gid. Omitted: the directory's default group. */\n group?: string | number;\n}\n\nexport interface HostFileAttributes {\n path: string;\n /** SHA-256 of the bytes on disk. */\n sha256: string;\n mode: number;\n uid: number;\n gid: number;\n size: number;\n}\n\nexport const DEFAULT_MODE = 0o644;\n\nconst identityProblems = (name: string, value: string | number | undefined): string[] => {\n if (value === undefined) return [];\n if (typeof value === 'number') {\n return Number.isSafeInteger(value) && value >= 0\n ? []\n : [`${name} must be a non-negative integer id`];\n }\n return /^[A-Za-z_][A-Za-z0-9_.-]*$/.test(value) || /^\\d+$/.test(value)\n ? []\n : [`${name} ${JSON.stringify(value)} is not a valid user or group name`];\n};\n\n/**\n * An absolute, normalised path, or the reasons it is not. ★ Shared with sudo-allowlist.ts, so a\n * path the sudo runner may touch as root obeys exactly the rule a declared file does.\n */\nexport const pathProblems = (path: string): string[] => {\n const found: string[] = [];\n if (!path.startsWith('/')) found.push('path must be absolute');\n // ★ One spelling per file: `a/./b`, `a//b` and `a/../b` would each be a second resource for the\n // same inode, and `..` is how a derived path walks out of the directory it was meant for.\n if (\n path.endsWith('/') ||\n path\n .split('/')\n .slice(1)\n .some((part) => part === '' || part === '.' || part === '..')\n ) {\n found.push('path must be normalised (no trailing slash, no empty, \".\" or \"..\" segments)');\n }\n if (path.includes('\\x00')) found.push('path contains NUL');\n return found;\n};\n\nexport const fileProblems = (props: HostFileProps): string[] => {\n const found = pathProblems(props.path);\n const mode = props.mode ?? DEFAULT_MODE;\n if (!Number.isSafeInteger(mode) || mode < 0 || mode > 0o7777) found.push('mode must be 0–0o7777');\n found.push(...identityProblems('owner', props.owner));\n found.push(...identityProblems('group', props.group));\n found.push(...fileSecretProblems(props.content));\n return found;\n};\n",
|
|
13
12
|
"/**\n * LaunchdJob's props, attributes and the pure half of the provider: domain parsing, the plist path,\n * and the props → plist mapping whose SHA-256 is the whole diff.\n *\n * ★ KEY NAMES AND MEANINGS FROM launchd.plist(5), checked against the 148 nix-darwin daemons on a\n * macOS 27.2 host on 2026-09-21 (read-only, from /nix/store): Label, ProgramArguments, RunAtLoad,\n * KeepAlive (boolean or {SuccessfulExit}), ThrottleInterval, StandardOutPath/StandardErrorPath,\n * EnvironmentVariables, UserName, StartInterval and StartCalendarInterval are the keys in real\n * use. Everything rarer goes through `extraKeys`.\n */\nimport { createHash } from 'node:crypto';\nimport { type PlistDict, type PlistValue, renderPlist } from './plist.ts';\n\n/** `system` (LaunchDaemons, root) or one user's login session, `gui/<uid>` (LaunchAgents). */\nexport type LaunchdDomain = 'system' | `gui/${number}`;\n\n/** One StartCalendarInterval entry. An omitted field is a wildcard, as in cron. */\nexport type CalendarInterval = {\n readonly minute?: number;\n readonly hour?: number;\n readonly day?: number;\n /** 0 and 7 are both Sunday. */\n readonly weekday?: number;\n readonly month?: number;\n};\n\n/** `true` = always restart; the object form restarts only on the named conditions. */\nexport type KeepAlive = boolean | { readonly successfulExit?: boolean; readonly crashed?: boolean };\n\nexport interface LaunchdJobProps {\n /** Reverse-DNS label. Unique per domain; also the plist's file name. */\n label: string;\n domain: LaunchdDomain;\n /** argv; the first element must be an absolute path. */\n programArguments: readonly string[];\n /**\n * ⛔ NON-SECRET VALUES ONLY. Props are stored unencrypted in Alchemy state, and these also land in\n * the plist on disk and in `launchctl print`. Pass a secret as a FILE PATH that a secret renderer\n * (openbao-agent) maintains — secret-tripwire.ts refuses the obvious mistakes.\n */\n environment?: Readonly<Record<string, string>>;\n runAtLoad?: boolean;\n keepAlive?: KeepAlive;\n /** Seconds between starts. */\n startInterval?: number;\n startCalendarInterval?: CalendarInterval | readonly CalendarInterval[];\n /** Minimum seconds between (re)starts; launchd's default is 10. */\n throttleInterval?: number;\n standardOutPath?: string;\n standardErrorPath?: string;\n workingDirectory?: string;\n /** Run as this user. ⚠️ System domain only — launchd ignores it for agents, so it is refused. */\n userName?: string;\n /** Run as this group. ⚠️ System domain only, like `userName`. */\n groupName?: string;\n /**\n * Any other launchd.plist(5) key, verbatim (`ProcessType`, `SoftResourceLimits`, …).\n * ⛔ A key the typed props own is refused, so one job can never say two things.\n */\n extraKeys?: PlistDict;\n}\n\nexport interface LaunchdJobAttributes {\n label: string;\n domain: LaunchdDomain;\n /** `<domain>/<label>` — what `launchctl print` / `bootout` take. */\n serviceTarget: string;\n plistPath: string;\n /** SHA-256 of the plist bytes last bootstrapped (reconcile) or found on disk (read). */\n plistSha256: string;\n /** Bootstrapped into the domain — not necessarily running. */\n loaded: boolean;\n /** launchd's own word: `running`, `not running`, … */\n state?: string;\n pid?: number;\n lastExitCode?: number;\n}\n\nexport type ParsedDomain =\n | { readonly kind: 'system' }\n | { readonly kind: 'gui'; readonly uid: number };\n\nexport const parseDomain = (domain: string): ParsedDomain | undefined => {\n if (domain === 'system') return { kind: 'system' };\n const match = /^gui\\/(\\d+)$/.exec(domain);\n return match?.[1] === undefined ? undefined : { kind: 'gui', uid: Number(match[1]) };\n};\n\nexport const serviceTarget = (label: string, domain: LaunchdDomain): string => `${domain}/${label}`;\n\n/**\n * Where launchd expects the job's plist. ★ Derived, never declared: a daemon's plist outside\n * /Library/LaunchDaemons is not bootstrapped at boot, so a free-form path would be a job that\n * silently stops existing after the next restart.\n */\nexport const plistPathFor = (\n label: string,\n domain: ParsedDomain,\n home: string | undefined,\n): string => {\n if (domain.kind === 'system') return `/Library/LaunchDaemons/${label}.plist`;\n // ⛔ No `~` fallback: the provider may run as root, whose `~` is not the agent owner's home.\n if (home === undefined || !home.startsWith('/')) {\n throw new Error(`gui/${String(domain.uid)}: no home directory for that uid on this host`);\n }\n return `${home}/Library/LaunchAgents/${label}.plist`;\n};\n\n/** Plist keys the typed props own — `extraKeys` may not name them. `Program` is refused too. */\nexport const OWNED_KEYS: readonly string[] = [\n 'EnvironmentVariables',\n 'GroupName',\n 'KeepAlive',\n 'Label',\n 'Program',\n 'ProgramArguments',\n 'RunAtLoad',\n 'StandardErrorPath',\n 'StandardOutPath',\n 'StartCalendarInterval',\n 'StartInterval',\n 'ThrottleInterval',\n 'UserName',\n 'WorkingDirectory',\n];\n\nconst calendarDict = (entry: CalendarInterval): PlistDict => {\n const dict: Record<string, PlistValue> = {};\n if (entry.minute !== undefined) dict['Minute'] = entry.minute;\n if (entry.hour !== undefined) dict['Hour'] = entry.hour;\n if (entry.day !== undefined) dict['Day'] = entry.day;\n if (entry.weekday !== undefined) dict['Weekday'] = entry.weekday;\n if (entry.month !== undefined) dict['Month'] = entry.month;\n return dict;\n};\n\nconst keepAliveValue = (keepAlive: KeepAlive): PlistValue => {\n if (typeof keepAlive === 'boolean') return keepAlive;\n const dict: Record<string, PlistValue> = {};\n if (keepAlive.successfulExit !== undefined) dict['SuccessfulExit'] = keepAlive.successfulExit;\n if (keepAlive.crashed !== undefined) dict['Crashed'] = keepAlive.crashed;\n return dict;\n};\n\n/** The plist dict for a job. ⚠️ Assumes jobProblems() came back empty. */\nexport const jobPlistDict = (props: LaunchdJobProps): PlistDict => {\n const dict: Record<string, PlistValue> = { ...props.extraKeys };\n dict['Label'] = props.label;\n dict['ProgramArguments'] = [...props.programArguments];\n const env = props.environment ?? {};\n if (Object.keys(env).length > 0) dict['EnvironmentVariables'] = { ...env };\n if (props.runAtLoad !== undefined) dict['RunAtLoad'] = props.runAtLoad;\n if (props.keepAlive !== undefined) dict['KeepAlive'] = keepAliveValue(props.keepAlive);\n if (props.startInterval !== undefined) dict['StartInterval'] = props.startInterval;\n const calendar = props.startCalendarInterval;\n if (calendar !== undefined) {\n dict['StartCalendarInterval'] = Array.isArray(calendar)\n ? (calendar as readonly CalendarInterval[]).map(calendarDict)\n : calendarDict(calendar as CalendarInterval);\n }\n if (props.throttleInterval !== undefined) dict['ThrottleInterval'] = props.throttleInterval;\n if (props.standardOutPath !== undefined) dict['StandardOutPath'] = props.standardOutPath;\n if (props.standardErrorPath !== undefined) dict['StandardErrorPath'] = props.standardErrorPath;\n if (props.workingDirectory !== undefined) dict['WorkingDirectory'] = props.workingDirectory;\n if (props.userName !== undefined) dict['UserName'] = props.userName;\n if (props.groupName !== undefined) dict['GroupName'] = props.groupName;\n return dict;\n};\n\nexport const sha256Hex = (bytes: Uint8Array | string): string =>\n createHash('sha256').update(bytes).digest('hex');\n\n/** The rendered plist and its digest — the only thing LaunchdJob compares. */\nexport const renderJob = (\n props: LaunchdJobProps,\n): { text: string; bytes: Uint8Array; sha256: string } => {\n const text = renderPlist(jobPlistDict(props));\n const bytes = new TextEncoder().encode(text);\n return { bytes, sha256: sha256Hex(bytes), text };\n};\n",
|
|
14
13
|
"/**\n * An XML property list serializer — the subset launchd.plist(5) reads, and nothing else.\n *\n * ★ WHY NOT AN npm LIBRARY. Nothing in this workspace depends on one (checked 2026-09-21: no\n * `plist`, `xmlbuilder` or `@xmldom/xmldom` anywhere under node_modules), and the common one pulls\n * an XML DOM in for PARSING, which a provider that only RENDERS never does. The subset a launchd\n * job needs is five node types, so this is ~100 lines plus exhaustive tests (plist.test.ts), which\n * also round-trip every case through Apple's own `plutil` when the tests run on macOS.\n *\n * ⛔ THE OUTPUT MUST BE DETERMINISTIC. LaunchdJob diffs by the SHA-256 of these bytes, so two\n * renders of one declaration must be byte-identical: dict keys are sorted, indentation is fixed,\n * and nothing depends on insertion order. A non-deterministic render is a forever-`update`.\n * ⚠️ AND A CHANGE TO THIS FILE'S OUTPUT RESTARTS EVERY JOB. A new header, indent or escape changes\n * every digest, so the next deploy after the kit upgrade updates — restarts — every declared\n * job at once. Treat any byte change here as a breaking change and say so in its changeset.\n *\n * ⛔ REFUSE, NEVER COERCE. `undefined`, `null`, a fraction, NaN, a class instance or a character XML\n * 1.0 cannot carry is a thrown PlistError naming the path, not a silently dropped key. A dropped\n * `KeepAlive` is a daemon that never restarts, and nothing downstream would say why.\n */\n\n/** Every value launchd reads. ⚠️ No `<real>`, `<date>` or `<data>`: no launchd key needs one. */\nexport type PlistValue =\n | string\n | number\n | boolean\n | readonly PlistValue[]\n | { readonly [key: string]: PlistValue };\n\nexport type PlistDict = { readonly [key: string]: PlistValue };\n\nexport class PlistError extends Error {\n constructor(\n readonly path: string,\n detail: string,\n ) {\n super(`plist ${path === '' ? '(root)' : path}: ${detail}`);\n this.name = 'PlistError';\n }\n}\n\nconst HEADER =\n '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n' +\n '<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" ' +\n '\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\\n' +\n '<plist version=\"1.0\">\\n';\n\n/** ⚠️ A cycle, or a runaway generator, would otherwise recurse until the stack dies. */\nconst MAX_DEPTH = 32;\n\n/**\n * ⛔ CHARACTERS XML 1.0 CANNOT CARRY AT ALL — not even escaped (XML 1.0 §2.2 `Char`). C0 controls\n * other than tab, LF and CR; U+FFFE / U+FFFF; and an unpaired surrogate, which has no UTF-8 form.\n */\n// ★ The `u` flag makes a VALID surrogate pair one code point above U+FFFF, outside this class, so\n// only an unpaired half matches the \\uD800-\\uDFFF range.\n// oxlint-disable-next-line no-control-regex -- matching control characters is the point\nconst FORBIDDEN = /[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\uD800-\\uDFFF\\uFFFE\\uFFFF]/u;\n\n/**\n * Escape text content.\n * ⚠️ CR IS A CHARACTER REFERENCE, NOT A LITERAL. An XML parser normalises a literal CR (and CRLF)\n * to LF before the application sees it (XML 1.0 §2.11), so `a\\r\\nb` would come back as `a\\nb` and\n * the argument launchd passes would differ from the one declared. ` ` survives normalisation.\n */\nexport const escapeText = (text: string, path: string): string => {\n const bad = FORBIDDEN.exec(text);\n if (bad !== null) {\n const code = bad[0].codePointAt(0) ?? 0;\n throw new PlistError(\n path,\n `U+${code.toString(16).toUpperCase().padStart(4, '0')} cannot appear in XML 1.0`,\n );\n }\n return text\n .replaceAll('&', '&')\n .replaceAll('<', '<')\n .replaceAll('>', '>')\n .replaceAll('\\r', ' ');\n};\n\nconst isPlainObject = (value: object): boolean => {\n const proto = Object.getPrototypeOf(value) as unknown;\n return proto === Object.prototype || proto === null;\n};\n\nconst renderValue = (value: unknown, path: string, depth: number, out: string[]): void => {\n const pad = '\\t'.repeat(depth);\n if (depth > MAX_DEPTH) throw new PlistError(path, `nested deeper than ${String(MAX_DEPTH)}`);\n if (typeof value === 'string') {\n out.push(`${pad}<string>${escapeText(value, path)}</string>`);\n return;\n }\n if (typeof value === 'boolean') {\n out.push(`${pad}<${value ? 'true' : 'false'}/>`);\n return;\n }\n if (typeof value === 'number') {\n // ⛔ launchd reads every numeric key as an integer; 1.5 would be a silently different job.\n if (!Number.isSafeInteger(value)) {\n throw new PlistError(path, `${String(value)} is not a safe integer (no <real> support)`);\n }\n out.push(`${pad}<integer>${String(value === 0 ? 0 : value)}</integer>`);\n return;\n }\n if (Array.isArray(value)) {\n if (value.length === 0) {\n out.push(`${pad}<array/>`);\n return;\n }\n out.push(`${pad}<array>`);\n for (const [index, item] of (value as readonly unknown[]).entries()) {\n renderValue(item, `${path}[${String(index)}]`, depth + 1, out);\n }\n out.push(`${pad}</array>`);\n return;\n }\n if (typeof value === 'object' && value !== null && isPlainObject(value)) {\n renderDict(value as Record<string, unknown>, path, depth, out);\n return;\n }\n const kind = value === null ? 'null' : typeof value;\n throw new PlistError(path, `${kind} has no plist form — omit the key instead`);\n};\n\nconst renderDict = (\n dict: Record<string, unknown>,\n path: string,\n depth: number,\n out: string[],\n): void => {\n const pad = '\\t'.repeat(depth);\n // ★ Code-unit order, not localeCompare: the same bytes on every machine and every locale.\n const keys = Object.keys(dict).sort();\n if (keys.length === 0) {\n out.push(`${pad}<dict/>`);\n return;\n }\n out.push(`${pad}<dict>`);\n for (const key of keys) {\n const child = path === '' ? key : `${path}.${key}`;\n out.push(`${pad}\\t<key>${escapeText(key, child)}</key>`);\n renderValue(dict[key], child, depth + 1, out);\n }\n out.push(`${pad}</dict>`);\n};\n\n/** Render a top-level dict as a complete XML plist document, ending in a newline. */\nexport const renderPlist = (dict: PlistDict): string => {\n if (typeof dict !== 'object' || dict === null || Array.isArray(dict) || !isPlainObject(dict)) {\n throw new PlistError('', 'the top level of a launchd plist must be a dict');\n }\n const out: string[] = [];\n renderDict(dict as Record<string, unknown>, '', 0, out);\n return `${HEADER}${out.join('\\n')}\\n</plist>\\n`;\n};\n",
|
|
15
|
-
"/**\n * The one seam between the launchd providers and the host: every file read, file write and\n * `launchctl` call goes through a HostRunner, and nothing in this directory touches the host any\n * other way.\n *\n * ★ WHY A SEAM AND NOT DIRECT node:fs CALLS. launchd has no SDK — the provider renders a plist and\n * drives `launchctl` — so the only way to test the lifecycle without a real launchd (and without\n * writing /Library) is to swap the host out. fake-runner.ts is an in-memory host with a scripted\n * launchd; local-runner.ts is the real one. The same seam is where a consumer plugs in a runner\n * that reaches a host some other way.\n *\n * ★ PROMISES, NOT EFFECTS, ON PURPOSE. A consumer writing their own runner implements plain async\n * functions; the providers lift them into Effect at the call site (host-effect.ts).\n */\nimport * as Context from 'effect/Context';\nimport * as Layer from 'effect/Layer';\n\n/** One finished process. ⛔ `stdout` may carry anything the job's environment holds — never log it. */\nexport type ExecResult = {\n readonly exitCode: number;\n readonly stdout: string;\n readonly stderr: string;\n};\n\n/**\n * What `lstat` says about a path. ⚠️ lstat, not stat: a symlink is reported as a symlink, because\n * writing through one would change a file this resource never named.\n */\nexport type FileStat = {\n readonly kind: 'file' | 'directory' | 'symlink' | 'other';\n /** Permission bits only (`& 0o7777`), never the file-type bits. */\n readonly mode: number;\n readonly uid: number;\n readonly gid: number;\n readonly size: number;\n};\n\nexport type WriteOptions = {\n
|
|
16
|
-
"/**\n * HostFile's read / diff / reconcile / delete as plain async functions over a HostRunner, so the\n * lifecycle runs against fake-runner.ts in tests.\n *\n * ⛔ SYMLINKS AND DIRECTORIES ARE REFUSED, NOT REPLACED. rename(2) over a symlink replaces the LINK,\n * so a path that is a symlink (nix-darwin's /etc entries point into /nix/store) would be quietly\n * taken from the tool that owns it — which puts it back, or refuses its next activation. Remove\n * the path from its owner first, then declare it here.\n */\nimport type { Diff } from 'alchemy/Diff';\nimport {\n DEFAULT_MODE,\n type HostFileAttributes,\n type HostFileProps,\n fileProblems,\n} from './host-file-form.ts';\nimport { sha256Hex } from './job-form.ts';\nimport { type HostRunner, type WriteOptions, canActAsRoot } from './runner.ts';\n\ntype Desired = {\n readonly bytes: Uint8Array;\n readonly sha256: string;\n readonly mode: number;\n readonly uid?: number;\n readonly gid?: number;\n};\n\nconst refuse = (path: string, message: string): Error => new Error(`Host.File ${path}: ${message}`);\n\nconst numericId = (value: string | number): number | undefined =>\n typeof value === 'number' ? value : /^\\d+$/.test(value) ? Number(value) : undefined;\n\n/** Validate, then resolve owner/group names to ids through the runner. */\nexport const desiredFile = async (runner: HostRunner, props: HostFileProps): Promise<Desired> => {\n const found = fileProblems(props);\n if (found.length > 0) throw refuse(props.path, found.join('; '));\n const bytes = new TextEncoder().encode(props.content);\n let uid: number | undefined;\n let gid: number | undefined;\n if (props.owner !== undefined) {\n uid = numericId(props.owner) ?? (await runner.lookupUser(String(props.owner)))?.uid;\n if (uid === undefined) throw refuse(props.path, `no user ${String(props.owner)} on this host`);\n }\n if (props.group !== undefined) {\n gid = numericId(props.group) ?? (await runner.lookupGroup(String(props.group)));\n if (gid === undefined) throw refuse(props.path, `no group ${String(props.group)} on this host`);\n }\n return {\n bytes,\n mode: props.mode ?? DEFAULT_MODE,\n sha256: sha256Hex(bytes),\n ...(uid === undefined ? {} : { uid }),\n ...(gid === undefined ? {} : { gid }),\n };\n};\n\n/** The file as it is now, or `undefined` when nothing is at the path. Non-files read with no digest. */\nexport const readFileAttributes = async (\n runner: HostRunner,\n path: string,\n): Promise<HostFileAttributes | undefined> => {\n const stat = await runner.stat(path);\n if (stat === undefined) return undefined;\n const bytes = stat.kind === 'file' ? await runner.readFile(path) : undefined;\n return {\n gid: stat.gid,\n mode: stat.mode,\n path,\n sha256: bytes === undefined ? '' : sha256Hex(bytes),\n size: stat.size,\n uid: stat.uid,\n };\n};\n\nconst writeOptionsOf = (want: Desired): WriteOptions => ({\n mode: want.mode,\n ...(want.uid === undefined ? {} : { uid: want.uid }),\n ...(want.gid === undefined ? {} : { gid: want.gid }),\n});\n\nconst matches = (live: HostFileAttributes, want: Desired): boolean =>\n live.sha256 === want.sha256 &&\n live.mode === want.mode &&\n (want.uid === undefined || live.uid === want.uid) &&\n (want.gid === undefined || live.gid === want.gid);\n\n/**\n * ★ A PLAN THAT WILL WRITE ASKS THE RUNNER FIRST (`checkWrite`, when it has one): sudoRunner's\n * refusals — a setuid or group-writable root file, a directory under a prefix another user may\n * change — then fail the plan, before any resource is applied, instead of halfway through it.\n */\nexport const diffFile = async (\n runner: HostRunner,\n news: HostFileProps,\n output: HostFileAttributes,\n): Promise<Diff> => {\n const want = await desiredFile(runner, news);\n const writes = async (diff: Diff): Promise<Diff> => {\n await runner.checkWrite?.(news.path, writeOptionsOf(want));\n return diff;\n };\n // ★ Create-before-delete: two paths can hold two files at once, so nothing forces deleteFirst.\n if (news.path !== output.path) return writes({ action: 'replace' });\n if (want.sha256 !== output.sha256) return writes({ action: 'update' });\n const live = await readFileAttributes(runner, news.path);\n return live !== undefined && matches(live, want)\n ? { action: 'noop' }\n : writes({ action: 'update' });\n};\n\n/**\n * `adopt` is whether adoption is on AND this apply is a create or an unfinished generation of our\n * own (ownership/adopt.ts adoptsAtApply). It lets such a generation take over a file already at the\n * path — the takeover the plan's probe would have allowed, had it run. ⛔ A move onto an occupied\n * path stays refused, both ways the engine drives one: an `update` across the move (`moved`,\n * below), and a fresh replace's new generation, which the caller never marks adoptable (its\n * `output` is undefined too, so this function cannot tell it from a create by itself).\n */\nexport const reconcileFile = async (\n runner: HostRunner,\n props: HostFileProps,\n output?: HostFileAttributes,\n adopt = false,\n): Promise<HostFileAttributes> => {\n const want = await desiredFile(runner, props);\n // ⛔ NO SILENT SUDO: handing a file to another user is root's call (chown(2)), so say so up front.\n if (want.uid !== undefined && want.uid !== runner.effectiveUid() && !canActAsRoot(runner)) {\n throw refuse(\n props.path,\n `owner ${String(props.owner)} is not the deploying user; only root may chown. Deploy as root ` +\n 'or through a privileged HostRunner (sudoRunner() with this path under a prefix). This ' +\n 'provider never calls sudo itself.',\n );\n }\n const stat = await runner.stat(props.path);\n if (stat !== undefined && stat.kind !== 'file') {\n throw refuse(\n props.path,\n `is a ${stat.kind}; remove it from whatever owns it before declaring it here`,\n );\n }\n const before = stat === undefined ? undefined : await readFileAttributes(runner, props.path);\n // ⚠️ An `output` at another path: the engine planned an UPDATE across a move, which it does\n // when diff could not see the new path (host-file.ts). Finish it the way a replace would.\n const moved = output !== undefined && output.path !== props.path;\n const prior = moved ? undefined : output;\n /**\n * ⛔ A FILE THIS RESOURCE DOES NOT OWN IS NEVER OVERWRITTEN. With no prior state for this path,\n * the engine's adoption probe has already refused anything it found — except where it never\n * looked: the new path of a replace, and a create whose props still held an Output at plan\n * time. A path typo there would otherwise overwrite, say, a system file that a fresh\n * declaration of the same path would have been refused as `Unowned`. ★ With adoption on, a\n * create takes it over, as the probe would have let it (decided 2026-09-21).\n */\n const takeOver = adopt && output === undefined;\n if (prior === undefined && before !== undefined && !matches(before, want) && !takeOver) {\n throw refuse(\n props.path,\n 'already exists and is not this resource. Remove it, or declare it as a new resource and ' +\n 'deploy with --adopt.',\n );\n }\n if (before === undefined || !matches(before, want)) {\n await runner.writeFileAtomic(props.path, want.bytes, writeOptionsOf(want));\n }\n // ⚠️ READ BACK, never echo the declaration: a umask, an ACL or a runner that ignored `uid` shows\n // up here as a refusal instead of as a forever-`update`.\n const after = await readFileAttributes(runner, props.path);\n if (after === undefined || !matches(after, want)) {\n // ⚠️ Roll back a CREATE: left behind, the next plan's recovery `read` finds a file with no\n // state, reports it `Unowned`, and every later deploy demands --adopt for our own file.\n if (before === undefined) await runner.removeFile(props.path).catch(() => undefined);\n throw refuse(\n props.path,\n 'the write returned but the file on disk does not match the declaration',\n );\n }\n // ★ Create-before-delete, as the replace would have been: the old path goes only once the new\n // one is written and verified.\n if (moved) await deleteFile(runner, output);\n return after;\n};\n\n/** Remove the file. Idempotent. ⛔ Refuses a path that has since become a symlink or directory. */\nexport const deleteFile = async (runner: HostRunner, output: HostFileAttributes): Promise<void> => {\n const stat = await runner.stat(output.path);\n if (stat === undefined) return;\n if (stat.kind !== 'file') throw refuse(output.path, `is now a ${stat.kind}; not removing it`);\n await runner.removeFile(output.path);\n};\n",
|
|
14
|
+
"/**\n * The one seam between the launchd providers and the host: every file read, file write and\n * `launchctl` call goes through a HostRunner, and nothing in this directory touches the host any\n * other way.\n *\n * ★ WHY A SEAM AND NOT DIRECT node:fs CALLS. launchd has no SDK — the provider renders a plist and\n * drives `launchctl` — so the only way to test the lifecycle without a real launchd (and without\n * writing /Library) is to swap the host out. fake-runner.ts is an in-memory host with a scripted\n * launchd; local-runner.ts is the real one. The same seam is where a consumer plugs in a runner\n * that reaches a host some other way.\n *\n * ★ PROMISES, NOT EFFECTS, ON PURPOSE. A consumer writing their own runner implements plain async\n * functions; the providers lift them into Effect at the call site (host-effect.ts).\n */\nimport * as Context from 'effect/Context';\nimport * as Layer from 'effect/Layer';\n\n/** One finished process. ⛔ `stdout` may carry anything the job's environment holds — never log it. */\nexport type ExecResult = {\n readonly exitCode: number;\n readonly stdout: string;\n readonly stderr: string;\n};\n\n/**\n * What `lstat` says about a path. ⚠️ lstat, not stat: a symlink is reported as a symlink, because\n * writing through one would change a file this resource never named.\n */\nexport type FileStat = {\n readonly kind: 'file' | 'directory' | 'symlink' | 'other';\n /** Permission bits only (`& 0o7777`), never the file-type bits. */\n readonly mode: number;\n readonly uid: number;\n readonly gid: number;\n readonly size: number;\n /**\n * The entry's identity, device and inode, when the runner can say. ★ Two spellings of ONE file\n * (`/tmp/x` and `/private/tmp/x`; `Bin` and `bin` on case-insensitive APFS) differ as strings\n * and match here, and a move must not delete its old path when that path IS the new file\n * (file-identity.ts). Optional: a runner that leaves them out gets a check after the fact.\n */\n readonly dev?: number;\n readonly ino?: number;\n};\n\nexport type WriteOptions = {\n /**\n * Permission bits for the final file. localRunner applies them BEFORE the file is visible at\n * `path`. ⚠️ sudoRunner's `install -S` does NOT: MEASURED 2026-09-22 on macOS 27.2 (an lstat\n * poller racing /usr/bin/install), the new inode appears at `path` as 0600 and is chmodded\n * 0.2–0.4 ms later. Never torn, never wider than declared, but briefly not executable.\n */\n readonly mode: number;\n /** Numeric owner; omitted means whoever the runner writes as. */\n readonly uid?: number;\n /** Numeric group; omitted means the directory's default. */\n readonly gid?: number;\n};\n\nexport type HostUser = { readonly uid: number; readonly gid: number; readonly home: string };\n\nexport interface HostRunner {\n /**\n * ⛔ DECLARED, NEVER INFERRED. `true` only when this runner can do every root-needing call the\n * providers make of it: every call already runs as root (a runner that talks to a root helper,\n * say), or the runner elevates exactly those calls (sudoRunner). The providers refuse\n * system-domain writes unless `effectiveUid()` is 0 or this is `true`, so claiming it falsely\n * turns that refusal into an EACCES halfway through a deploy.\n * ⛔ THE KIT NEVER ELEVATES SILENTLY. localRunner() never calls `sudo`: a deploy that prompts for\n * a password mid-plan, or quietly borrows a cached sudo ticket, is exactly the \"no silent sudo\"\n * failure. sudoRunner() does call `sudo -n`, but only when a stack passes it explicitly, only\n * for the argv shapes in sudo-allowlist.ts, and logging each one (decided 2026-09-21).\n */\n readonly privileged: boolean;\n /** The uid file writes and launchctl calls run as. */\n effectiveUid(): number;\n /** Run a program with an argv — ⛔ never through a shell. */\n exec(argv: readonly string[]): Promise<ExecResult>;\n /** File bytes, or `undefined` when nothing is at `path`. */\n readFile(path: string): Promise<Uint8Array | undefined>;\n /** lstat, or `undefined` when nothing is at `path`. */\n stat(path: string): Promise<FileStat | undefined>;\n /**\n * Write `bytes` so that `path` holds either the old file or the new one, never a torn mix:\n * a temporary file in the same directory, mode and owner set on it, then rename(2) over `path`\n * (sudoRunner: the mode just after the rename, measured — see WriteOptions.mode; the owner too,\n * ⚠️ REASONED NOT MEASURED, since measuring it needs root).\n * ⚠️ The parent directory must exist; creating it would invent an owner and mode nobody declared.\n */\n writeFileAtomic(path: string, bytes: Uint8Array, options: WriteOptions): Promise<void>;\n /**\n * PLAN TIME: refuse, reading only and writing nothing, a write this runner would refuse at\n * apply — so the plan shows it before any resource is applied. Optional: a runner without it\n * refuses at the write. ★ sudoRunner implements it with the checks it makes before `sudo -n`;\n * ⛔ it never elevates, so a plan still never calls sudo.\n */\n checkWrite?(path: string, options: WriteOptions): Promise<void>;\n /** Remove a file. Idempotent: nothing at `path` is success. */\n removeFile(path: string): Promise<void>;\n /** A user by name or numeric id, or `undefined` when the host has none. */\n lookupUser(nameOrId: string): Promise<HostUser | undefined>;\n /** A group's gid by name or numeric id, or `undefined` when the host has none. */\n lookupGroup(nameOrId: string): Promise<number | undefined>;\n /** Wait between launchctl polls. ★ Injected so a test never sleeps for real. */\n sleep(ms: number): Promise<void>;\n}\n\n/** The Effect service every launchd provider reads its runner from. */\nexport class HostRunnerService extends Context.Service<HostRunnerService, HostRunner>()(\n 'homeflare/launchd/HostRunner',\n) {}\n\n/** Provide a runner to the providers: `Layer.provide(hostRunnerLayer(localRunner()))`. */\nexport const hostRunnerLayer = (runner: HostRunner): Layer.Layer<HostRunnerService> =>\n Layer.succeed(HostRunnerService, runner);\n\n/** True when this runner may write root-owned paths and drive the system domain. */\nexport const canActAsRoot = (runner: HostRunner): boolean =>\n runner.privileged || runner.effectiveUid() === 0;\n",
|
|
15
|
+
"/**\n * The one path a declared file's bytes take onto a host, shared by every resource that owns ONE\n * whole file: `Host.File` (text it was handed) and `Release.Binary` (bytes it downloaded and\n * verified). Read, diff, converge and delete, as plain async functions over a HostRunner.\n *\n * ★ EXTRACTED FROM host-file-lifecycle.ts, NOT COPIED (2026-09-22). The ownership rules below — a\n * file this resource does not own is never overwritten, a move onto an occupied path stays\n * refused, a failed create is rolled back — were red-teamed on Host.File (docs/ownership.md). A\n * second resource that writes a whole file gets them by calling this, so a fix lands in both.\n * ★ THE BYTES ARE ASKED FOR ONLY WHEN A WRITE IS DUE (`bytesFor`). Host.File has them already; a\n * binary has only a pinned digest until it downloads, and a host whose file already matches\n * must not cost a 120 MB download to prove it.\n * ⛔ SYMLINKS AND DIRECTORIES ARE REFUSED, NOT REPLACED. rename(2) over a symlink replaces the LINK,\n * so a path that is a symlink (nix-darwin's /etc entries point into /nix/store) would be quietly\n * taken from the tool that owns it — which puts it back, or refuses its next activation. Remove\n * the path from its owner first, then declare it here.\n */\nimport type { Diff } from 'alchemy/Diff';\nimport { leaveOldPath, oneFile } from './file-identity.ts';\nimport type { HostFileAttributes } from './host-file-form.ts';\nimport { sha256Hex } from './job-form.ts';\nimport { type HostRunner, type WriteOptions, canActAsRoot } from './runner.ts';\n\n/** What a whole file must be: where, which bytes (by digest), which mode and owner. */\nexport type FileTarget = {\n readonly path: string;\n readonly sha256: string;\n readonly mode: number;\n readonly uid?: number;\n readonly gid?: number;\n};\n\n/** A family's refusal: `<Type> <path>: <message>`, so a deploy log names the resource that said no. */\nexport type Refuse = (path: string, message: string) => Error;\n\nconst numericId = (value: string | number): number | undefined =>\n typeof value === 'number' ? value : /^\\d+$/.test(value) ? Number(value) : undefined;\n\n/** Resolve a declared owner and group (names or ids) to ids through the runner. */\nexport const resolveIds = async (\n runner: HostRunner,\n declared: { readonly owner?: string | number; readonly group?: string | number },\n path: string,\n refuse: Refuse,\n): Promise<{ uid?: number; gid?: number }> => {\n let uid: number | undefined;\n let gid: number | undefined;\n if (declared.owner !== undefined) {\n uid = numericId(declared.owner) ?? (await runner.lookupUser(String(declared.owner)))?.uid;\n if (uid === undefined) throw refuse(path, `no user ${String(declared.owner)} on this host`);\n }\n if (declared.group !== undefined) {\n gid = numericId(declared.group) ?? (await runner.lookupGroup(String(declared.group)));\n if (gid === undefined) throw refuse(path, `no group ${String(declared.group)} on this host`);\n }\n return { ...(uid === undefined ? {} : { uid }), ...(gid === undefined ? {} : { gid }) };\n};\n\n/** The file as it is now, or `undefined` when nothing is at the path. Non-files read with no digest. */\nexport const readFileAttributes = async (\n runner: HostRunner,\n path: string,\n): Promise<HostFileAttributes | undefined> => {\n const stat = await runner.stat(path);\n if (stat === undefined) return undefined;\n const bytes = stat.kind === 'file' ? await runner.readFile(path) : undefined;\n return {\n gid: stat.gid,\n mode: stat.mode,\n path,\n sha256: bytes === undefined ? '' : sha256Hex(bytes),\n size: stat.size,\n uid: stat.uid,\n };\n};\n\nexport const writeOptionsOf = (want: FileTarget): WriteOptions => ({\n mode: want.mode,\n ...(want.uid === undefined ? {} : { uid: want.uid }),\n ...(want.gid === undefined ? {} : { gid: want.gid }),\n});\n\nexport const fileMatches = (live: HostFileAttributes, want: FileTarget): boolean =>\n live.sha256 === want.sha256 &&\n live.mode === want.mode &&\n (want.uid === undefined || live.uid === want.uid) &&\n (want.gid === undefined || live.gid === want.gid);\n\n/**\n * ★ A PLAN THAT WILL WRITE ASKS THE RUNNER FIRST (`checkWrite`, when it has one): sudoRunner's\n * refusals — a setuid or group-writable root file, a directory under a prefix another user may\n * change — then fail the plan, before any resource is applied, instead of halfway through it.\n */\nexport const diffTarget = async (\n runner: HostRunner,\n want: FileTarget,\n output: HostFileAttributes,\n): Promise<Diff> => {\n const writes = async (diff: Diff): Promise<Diff> => {\n await runner.checkWrite?.(want.path, writeOptionsOf(want));\n return diff;\n };\n // ★ Create-before-delete: two paths can hold two files at once, so nothing forces deleteFirst.\n // ⛔ …unless the two paths are ONE file (file-identity.ts). That is a respelling, not a move: a\n // replace would let Phase 2 delete the old generation's path, which is the new one's file. An\n // update records the new spelling, and convergeFile keeps the file.\n if (want.path !== output.path) {\n const same = await oneFile(runner, want.path, output.path);\n return writes({ action: same === true ? 'update' : 'replace' });\n }\n if (want.sha256 !== output.sha256) return writes({ action: 'update' });\n const live = await readFileAttributes(runner, want.path);\n return live !== undefined && fileMatches(live, want)\n ? { action: 'noop' }\n : writes({ action: 'update' });\n};\n\nexport type Converge = {\n readonly want: FileTarget;\n /** The owner as declared (a name or an id), for the chown refusal's wording. */\n readonly owner?: string | number | undefined;\n /** The bytes to write, asked for only when a write is due; `before` is what is there now. */\n readonly bytesFor: (before: HostFileAttributes | undefined) => Promise<Uint8Array>;\n readonly refuse: Refuse;\n};\n\n/**\n * Make the file at `want.path` match `want`, and return it as read back.\n *\n * `adopt` is whether adoption is on AND this apply is a create or an unfinished generation of our\n * own (ownership/adopt.ts adoptsAtApply). It lets such a generation take over a file already at the\n * path — the takeover the plan's probe would have allowed, had it run. ⛔ A move onto an occupied\n * path stays refused, both ways the engine drives one: an `update` across the move (`moved`,\n * below), and a fresh replace's new generation, which the caller never marks adoptable (its\n * `output` is undefined too, so this function cannot tell it from a create by itself).\n */\nexport const convergeFile = async (\n runner: HostRunner,\n spec: Converge,\n output?: HostFileAttributes,\n adopt = false,\n): Promise<HostFileAttributes> => {\n const { want, refuse } = spec;\n const path = want.path;\n // ⛔ NO SILENT SUDO: handing a file to another user is root's call (chown(2)), so say so up front.\n if (want.uid !== undefined && want.uid !== runner.effectiveUid() && !canActAsRoot(runner)) {\n throw refuse(\n path,\n `owner ${String(spec.owner)} is not the deploying user; only root may chown. Deploy as root ` +\n 'or through a privileged HostRunner (sudoRunner() with this path under a prefix). This ' +\n 'provider never calls sudo itself.',\n );\n }\n const stat = await runner.stat(path);\n if (stat !== undefined && stat.kind !== 'file') {\n throw refuse(\n path,\n `is a ${stat.kind}; remove it from whatever owns it before declaring it here`,\n );\n }\n const before = stat === undefined ? undefined : await readFileAttributes(runner, path);\n // ⚠️ An `output` at another path: the engine planned an UPDATE across a move, which it does\n // when diff could not see the new path (host-file.ts). Finish it the way a replace would.\n // ★ A respelling of ONE file (file-identity.ts) still counts as moved here, so a file there\n // that does not match is refused below — never rewritten in place under the old spelling's pins.\n const moved = output !== undefined && output.path !== path;\n const prior = moved ? undefined : output;\n /**\n * ⛔ A FILE THIS RESOURCE DOES NOT OWN IS NEVER OVERWRITTEN. With no prior state for this path,\n * the engine's adoption probe has already refused anything it found — except where it never\n * looked: the new path of a replace, and a create whose props still held an Output at plan\n * time. A path typo there would otherwise overwrite, say, a system file that a fresh\n * declaration of the same path would have been refused as `Unowned`. ★ With adoption on, a\n * create takes it over, as the probe would have let it (decided 2026-09-21).\n */\n const takeOver = adopt && output === undefined;\n if (prior === undefined && before !== undefined && !fileMatches(before, want) && !takeOver) {\n throw refuse(\n path,\n 'already exists and is not this resource. Remove it, or declare it as a new resource and ' +\n 'deploy with --adopt.',\n );\n }\n if (before === undefined || !fileMatches(before, want)) {\n const bytes = await spec.bytesFor(before);\n // ⛔ THE ONE WRITER NEVER WRITES BYTES THAT ARE NOT THE DECLARED ONES. Host.File's always are;\n // a supplier that verifies elsewhere (a download) is held to the same digest here, last.\n if (sha256Hex(bytes) !== want.sha256) {\n throw refuse(path, `the bytes to write do not hash to ${want.sha256}. Nothing was written.`);\n }\n await runner.writeFileAtomic(path, bytes, writeOptionsOf(want));\n }\n // ⚠️ READ BACK, never echo the declaration: a umask, an ACL or a runner that ignored `uid` shows\n // up here as a refusal instead of as a forever-`update`.\n // ⚠️ Roll back a CREATE: left behind, the next plan's recovery `read` finds a file with no state,\n // reports it `Unowned`, and every later deploy demands --adopt for our own file. ⛔ Also when\n // the read-back THROWS: MEASURED 2026-09-22, a 0111 binary written as a non-root operator read\n // back EACCES and stayed, and every later plan's probe failed with the same EACCES.\n const rollBack = async () => {\n if (before === undefined) await runner.removeFile(path).catch(() => undefined);\n };\n const after = await readFileAttributes(runner, path).catch(async (cause: unknown) => {\n await rollBack();\n throw refuse(path, `the write returned but reading it back failed: ${String(cause)}`);\n });\n if (after === undefined || !fileMatches(after, want)) {\n await rollBack();\n throw refuse(path, 'the write returned but the file on disk does not match the declaration');\n }\n // ★ Create-before-delete, as the replace would have been: the old path goes only once the new\n // one is written and verified — and ⛔ never when the old path IS this file (file-identity.ts).\n if (moved)\n await leaveOldPath(\n runner,\n output.path,\n path,\n () => removeWholeFile(runner, output, refuse),\n refuse,\n );\n return after;\n};\n\n/** Remove the file. Idempotent. ⛔ Refuses a path that has since become a symlink or directory. */\nexport const removeWholeFile = async (\n runner: HostRunner,\n output: HostFileAttributes,\n refuse: Refuse,\n): Promise<void> => {\n const stat = await runner.stat(output.path);\n if (stat === undefined) return;\n if (stat.kind !== 'file') throw refuse(output.path, `is now a ${stat.kind}; not removing it`);\n await runner.removeFile(output.path);\n};\n",
|
|
16
|
+
"/**\n * A tripwire for the obvious ways a secret ends up in Alchemy state through these providers.\n *\n * ⛔ WHY IT EXISTS. Alchemy persists every prop UNENCRYPTED in its state store — the same reason\n * the OpenBao families are metadata-only (openbao/policy.ts). A LaunchdJob's `environment` and\n * `programArguments`, and a HostFile's `content`, are props. A token declared there is a token\n * copied into the state store, into every plan diff, and into the plist or file on disk.\n * ★ THE ALTERNATIVE, NAMED IN EVERY REFUSAL: let a secret renderer (openbao-agent, or any other)\n * write the secret to a root-owned file, and declare only its PATH — `FOO_TOKEN_FILE=/path`,\n * `--token-file /path`. The job reads the file at start; the state holds a path.\n *\n * ⚠️ A TRIPWIRE, NOT A SCANNER. It catches the names and shapes people actually type. A token in\n * an innocently named variable passes; nothing here can make a secret safe to declare.\n */\nimport type { PlistDict, PlistValue } from './plist.ts';\n\nconst ALTERNATIVE =\n 'props are stored unencrypted in Alchemy state. Have a secret renderer (e.g. openbao-agent) ' +\n 'write it to a root-owned file and declare the file path instead (FOO_FILE=/path, --foo-file /path).';\n\n/** Names that end in a word meaning \"this is the secret itself\". `*_FILE`, `*_PATH` never match. */\nconst SECRET_NAME =\n /(?:^|_)(?:TOKEN|SECRET|PASSWORD|PASSWD|PASSPHRASE|API_?KEY|ACCESS_KEY|PRIVATE_KEY|SECRET_KEY|CREDENTIALS?)$/i;\n\n/** `--token=…` / `-password=…` style flags carrying their value inline. */\nconst INLINE_FLAG = /^--?[a-z0-9-]*(?:token|password|passwd|passphrase|secret|api-?key)=./i;\n\n/** A flag whose NEXT argv element is the secret: `--token abc`. */\nconst BARE_FLAG = /^--?(?:[a-z0-9]+-)*(?:token|password|passwd|passphrase|secret|api-?key)$/i;\n\nexport const PRIVATE_KEY = /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----/;\n\n/** Paths of every string leaf in a plist value holding a private key. */\nconst keyLeaves = (value: PlistValue, path: string): string[] => {\n if (typeof value === 'string') return PRIVATE_KEY.test(value) ? [path] : [];\n if (Array.isArray(value)) {\n return (value as readonly PlistValue[]).flatMap((item, index) =>\n keyLeaves(item, `${path}[${String(index)}]`),\n );\n }\n if (typeof value === 'object' && value !== null) {\n return Object.entries(value).flatMap(([key, item]) => keyLeaves(item, `${path}.${key}`));\n }\n return [];\n};\n\n/**\n * Refusals for a job's environment, argv and extraKeys. Empty means nothing tripped.\n * ★ extraKeys too: it is a prop like the others, so it lands in state just the same.\n */\nexport const jobSecretProblems = (\n environment: Readonly<Record<string, string>> | undefined,\n argv: readonly string[],\n extraKeys?: PlistDict,\n): string[] => {\n const found: string[] = [];\n for (const [name, value] of Object.entries(environment ?? {})) {\n if (SECRET_NAME.test(name))\n found.push(`environment ${name} looks like a secret: ${ALTERNATIVE}`);\n else if (PRIVATE_KEY.test(value))\n found.push(`environment ${name} holds a private key: ${ALTERNATIVE}`);\n }\n for (const [index, arg] of argv.entries()) {\n // ⛔ Never echo the argument itself: if it IS a secret, the refusal would print it.\n if (INLINE_FLAG.test(arg)) {\n found.push(`programArguments[${String(index)}] passes a secret inline: ${ALTERNATIVE}`);\n } else if (BARE_FLAG.test(arg) && index + 1 < argv.length) {\n found.push(`programArguments[${String(index + 1)}] follows a secret flag: ${ALTERNATIVE}`);\n } else if (PRIVATE_KEY.test(arg)) {\n found.push(`programArguments[${String(index)}] holds a private key: ${ALTERNATIVE}`);\n }\n }\n for (const path of keyLeaves(extraKeys ?? {}, 'extraKeys')) {\n found.push(`${path} holds a private key: ${ALTERNATIVE}`);\n }\n return found;\n};\n\n/** Refusals for a HostFile's content. */\nexport const fileSecretProblems = (content: string): string[] =>\n PRIVATE_KEY.test(content) ? [`content holds a private key: ${ALTERNATIVE}`] : [];\n",
|
|
17
|
+
"/**\n * HostFile's props, attributes and validation — the pure half of the provider.\n *\n * ⛔ `content` IS NEVER A SECRET. Alchemy stores props unencrypted, so the content of every HostFile\n * sits in the state store and in every plan diff. A secret file stays RENDERED BY A SECRET\n * RENDERER (openbao-agent templates, on this estate) that fetches it at run time; the stack\n * declares only non-secret config, and at most the PATH the renderer writes to.\n * secret-tripwire.ts refuses the obvious case (a PEM private key); nothing can catch all of them.\n */\nimport { fileSecretProblems } from './secret-tripwire.ts';\n\nexport interface HostFileProps {\n /** Absolute path. The parent directory must already exist. */\n path: string;\n /** UTF-8 text. ⛔ Never a secret — see the file header. */\n content: string;\n /** Permission bits. @default 0o644 */\n mode?: number;\n /** User name or numeric uid. Omitted: whoever the runner writes as (a rewrite keeps no owner). */\n owner?: string | number;\n /** Group name or numeric gid. Omitted: the directory's default group. */\n group?: string | number;\n}\n\nexport interface HostFileAttributes {\n path: string;\n /** SHA-256 of the bytes on disk. */\n sha256: string;\n mode: number;\n uid: number;\n gid: number;\n size: number;\n}\n\nexport const DEFAULT_MODE = 0o644;\n\n/** A user or group as declared: a non-negative id, or a name the host could have. */\nexport const identityProblems = (name: string, value: string | number | undefined): string[] => {\n if (value === undefined) return [];\n if (typeof value === 'number') {\n return Number.isSafeInteger(value) && value >= 0\n ? []\n : [`${name} must be a non-negative integer id`];\n }\n return /^[A-Za-z_][A-Za-z0-9_.-]*$/.test(value) || /^\\d+$/.test(value)\n ? []\n : [`${name} ${JSON.stringify(value)} is not a valid user or group name`];\n};\n\n/**\n * An absolute, normalised path, or the reasons it is not. ★ Shared with sudo-allowlist.ts, so a\n * path the sudo runner may touch as root obeys exactly the rule a declared file does.\n */\nexport const pathProblems = (path: string): string[] => {\n const found: string[] = [];\n if (!path.startsWith('/')) found.push('path must be absolute');\n // ★ One spelling per file: `a/./b`, `a//b` and `a/../b` would each be a second resource for the\n // same inode, and `..` is how a derived path walks out of the directory it was meant for.\n if (\n path.endsWith('/') ||\n path\n .split('/')\n .slice(1)\n .some((part) => part === '' || part === '.' || part === '..')\n ) {\n found.push('path must be normalised (no trailing slash, no empty, \".\" or \"..\" segments)');\n }\n if (path.includes('\\x00')) found.push('path contains NUL');\n return found;\n};\n\nexport const fileProblems = (props: HostFileProps): string[] => {\n const found = pathProblems(props.path);\n const mode = props.mode ?? DEFAULT_MODE;\n if (!Number.isSafeInteger(mode) || mode < 0 || mode > 0o7777) found.push('mode must be 0–0o7777');\n found.push(...identityProblems('owner', props.owner));\n found.push(...identityProblems('group', props.group));\n found.push(...fileSecretProblems(props.content));\n return found;\n};\n",
|
|
18
|
+
"/**\n * HostFile's read / diff / reconcile / delete as plain async functions over a HostRunner, so the\n * lifecycle runs against fake-runner.ts in tests.\n *\n * ★ THE CONVERGENCE ITSELF IS file-converge.ts, shared with every resource that owns one whole file\n * (Release.Binary is the second). What stays here is what makes a HOST FILE: text content, its\n * validation (never a secret — host-file-form.ts), and the refusal wording `Host.File <path>: …`.\n * ⛔ SYMLINKS AND DIRECTORIES ARE REFUSED, NOT REPLACED — see file-converge.ts for why.\n */\nimport type { Diff } from 'alchemy/Diff';\nimport {\n type FileTarget,\n convergeFile,\n diffTarget,\n removeWholeFile,\n resolveIds,\n} from './file-converge.ts';\nimport {\n DEFAULT_MODE,\n type HostFileAttributes,\n type HostFileProps,\n fileProblems,\n} from './host-file-form.ts';\nimport { sha256Hex } from './job-form.ts';\nimport type { HostRunner } from './runner.ts';\n\nexport { readFileAttributes } from './file-converge.ts';\n\ntype Desired = FileTarget & { readonly bytes: Uint8Array };\n\nconst refuse = (path: string, message: string): Error => new Error(`Host.File ${path}: ${message}`);\n\n/** Validate, then resolve owner/group names to ids through the runner. */\nexport const desiredFile = async (runner: HostRunner, props: HostFileProps): Promise<Desired> => {\n const found = fileProblems(props);\n if (found.length > 0) throw refuse(props.path, found.join('; '));\n const bytes = new TextEncoder().encode(props.content);\n return {\n bytes,\n mode: props.mode ?? DEFAULT_MODE,\n path: props.path,\n sha256: sha256Hex(bytes),\n ...(await resolveIds(runner, props, props.path, refuse)),\n };\n};\n\n/** Declared digest, mode and owner against state and the live file — see diffTarget. */\nexport const diffFile = async (\n runner: HostRunner,\n news: HostFileProps,\n output: HostFileAttributes,\n): Promise<Diff> => diffTarget(runner, await desiredFile(runner, news), output);\n\n/**\n * Write the declared text, unless the file already matches. `adopt` is adoptsAtApply's answer;\n * what it may and may not take over is convergeFile's ⛔.\n */\nexport const reconcileFile = async (\n runner: HostRunner,\n props: HostFileProps,\n output?: HostFileAttributes,\n adopt = false,\n): Promise<HostFileAttributes> => {\n const want = await desiredFile(runner, props);\n const spec = { bytesFor: async () => want.bytes, owner: props.owner, refuse, want };\n return convergeFile(runner, spec, output, adopt);\n};\n\n/** Remove the file. Idempotent. ⛔ Refuses a path that has since become a symlink or directory. */\nexport const deleteFile = (runner: HostRunner, output: HostFileAttributes): Promise<void> =>\n removeWholeFile(runner, output, refuse);\n",
|
|
17
19
|
"/**\n * `Launchd.Job` — one launchd job (a LaunchDaemon in `system`, a LaunchAgent in `gui/<uid>`),\n * declared rather than hand-loaded.\n *\n * ★ launchd HAS NO SDK. The provider renders the plist (plist.ts), writes it where launchd looks\n * (job-form.ts plistPathFor), and drives `launchctl` (launchctl.ts) — all through the HostRunner\n * the stack provides (runner.ts), so none of it is reachable except through that seam.\n *\n * Lifecycle (job-lifecycle.ts has the reasoning for each step):\n * - create / update — write the plist atomically, boot out the old job if loaded, bootstrap.\n * An update is therefore a RESTART; a converged job is left alone.\n * - read — `launchctl print` (loaded? pid? last exit?) plus the plist's SHA-256.\n * - diff — the rendered plist's SHA-256 against the stored AND the on-disk digest.\n * - replace — only when `label` or `domain` changes, and DELETE FIRST (labels are unique); so\n * everything the new job would be refused for is refused at plan time (job-preflight.ts).\n * - delete — boot out, remove the plist.\n *\n * ⛔ ENVIRONMENT IS NON-SECRET ONLY — see the ⛔ on LaunchdJobProps.environment.\n * ⛔ NO SILENT SUDO — see assertMayWrite in job-preflight.ts.\n * ⚠️ NOTHING IS ADOPTED WITHOUT `--adopt`. A label already loaded, or a plist already on disk, reads\n * as `Unowned`, so Alchemy refuses to take it over unless asked — and reconcile, where the plan\n * never asked, honours the same `--adopt` / `adopt(…)` (docs/ownership.md). Labels under `org.nixos.`,\n * `com.apple.` and `homebrew.mxcl.` are refused outright (job-validate.ts) — declare a new label\n * and cut over instead (docs/launchd.md).\n */\nimport { Resource } from 'alchemy';\nimport { Unowned } from 'alchemy/AdoptPolicy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport { adoptsAtApply } from '../ownership/adopt.ts';\nimport { noteUnfinished } from '../ownership/resume.ts';\nimport { lift, resolvedString } from './host-effect.ts';\nimport type { LaunchdJobAttributes, LaunchdJobProps } from './job-form.ts';\nimport { deleteJob, diffJob, readJob, reconcileJob, replaceDiff } from './job-lifecycle.ts';\nimport { HostRunnerService } from './runner.ts';\n\nexport type {\n CalendarInterval,\n KeepAlive,\n LaunchdDomain,\n LaunchdJobAttributes,\n LaunchdJobProps,\n} from './job-form.ts';\n\nexport interface LaunchdJob extends Resource<\n 'Launchd.Job',\n LaunchdJobProps,\n LaunchdJobAttributes\n> {}\n\nexport const LaunchdJob = Resource<LaunchdJob>('Launchd.Job');\n\nexport const LaunchdJobProvider = () =>\n Provider.effect(\n LaunchdJob,\n Effect.gen(function* () {\n const runner = yield* HostRunnerService;\n return LaunchdJob.Provider.of({\n /**\n * ⛔ launchd's job list is not a list of things this stack owns — it is every Apple, Nix\n * and hand-loaded job on the host. Returning them would invite a nuke to boot them out.\n */\n list: () => Effect.succeed([]),\n\n read: ({ olds, output }) =>\n lift(async () => {\n const found = await readJob(runner, olds);\n if (found === undefined) return undefined;\n return output === undefined ? Unowned(found) : found;\n }),\n\n diff: ({ instanceId, news, output }) => {\n // ★ An unfinished generation of our own: `--adopt` may resume it (ownership/resume.ts).\n if (output === undefined) return noteUnfinished(instanceId);\n if (isResolved(news)) return lift(() => diffJob(runner, news, output));\n /**\n * ⛔ A RENAME MUST BE SEEN EVEN WHILE OTHER PROPS ARE UNRESOLVED. Returning undefined\n * hands the call to the engine's default — `update` for any prop change (Plan.ts,\n * havePropsChanged) — and an update under a new label bootstraps the new job and\n * orphans the old one, still running. `config.path` in programArguments (the pattern\n * docs/launchd.md recommends) is unresolved exactly when its HostFile changes in the\n * same deploy. reconcileJob also defends against this, for a label that is itself an\n * Output; seeing it here is what gets it planned as the replace it is.\n */\n const label = resolvedString(news, 'label');\n const domain = resolvedString(news, 'domain') as LaunchdJobProps['domain'] | undefined;\n return label !== undefined &&\n domain !== undefined &&\n (label !== output.label || domain !== output.domain)\n ? lift(() => replaceDiff(runner, { domain, label }, undefined, output))\n : Effect.succeed(undefined);\n },\n\n // ★ `--adopt` reaches the apply too: the probe never ran for a create with an Output prop.\n // ⛔ A create or an unfinished generation — never a fresh replace's, never offered it.\n reconcile: ({ fqn, instanceId, news, output }) =>\n Effect.flatMap(adoptsAtApply({ fqn, instanceId, output }), (adopt) =>\n lift(() => reconcileJob(runner, news, output, adopt)),\n ),\n\n delete: ({ output }) => lift(() => deleteJob(runner, output)),\n });\n }),\n );\n",
|
|
18
20
|
"/**\n * Everything LaunchdJob refuses before it touches the host. Run at plan time (diff) and again at\n * reconcile, so a bad declaration fails the plan instead of half-applying.\n *\n * ★ REFUSE WHAT launchd WOULD SILENTLY IGNORE OR MISREAD. launchd loads a plist with an out-of-range\n * calendar field or a UserName on an agent without complaint and then simply never does what the\n * declaration says; a plan that fails is cheaper than a job that quietly does nothing.\n */\nimport {\n type CalendarInterval,\n type LaunchdJobProps,\n OWNED_KEYS,\n parseDomain,\n} from './job-form.ts';\nimport { jobSecretProblems } from './secret-tripwire.ts';\n\n/** ★ Labels become file names: no `/`, no leading dot, nothing a path could re-interpret. */\nexport const LABEL = /^[A-Za-z0-9][A-Za-z0-9._-]{0,199}$/;\n\n/**\n * ⛔ LABELS OTHER TOOLS OWN ARE NEVER DECLARED HERE. nix-darwin (`org.nixos.*`) rewrites its plists\n * on every activation and unloads any it no longer lists; macOS owns `com.apple.*`; `brew\n * services` owns `homebrew.mxcl.*`. Declaring one of those makes two tools fight over one file.\n * To move a job off such a tool, declare a NEW label and cut over (docs/launchd.md).\n */\nexport const RESERVED_LABEL_PREFIXES: readonly string[] = [\n 'org.nixos.',\n 'com.apple.',\n 'homebrew.mxcl.',\n];\n\nconst ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\nconst RANGES: ReadonlyArray<readonly [keyof CalendarInterval, number, number]> = [\n ['minute', 0, 59],\n ['hour', 0, 23],\n ['day', 1, 31],\n ['weekday', 0, 7],\n ['month', 1, 12],\n];\n\nconst isInt = (value: number, min: number, max = Number.MAX_SAFE_INTEGER) =>\n Number.isSafeInteger(value) && value >= min && value <= max;\n\nconst calendarProblems = (entries: readonly CalendarInterval[]): string[] => {\n if (entries.length === 0) return ['startCalendarInterval is an empty list; omit it instead'];\n const found: string[] = [];\n for (const [index, entry] of entries.entries()) {\n for (const [field, min, max] of RANGES) {\n const value = entry[field];\n if (value !== undefined && !isInt(value, min, max)) {\n found.push(\n `startCalendarInterval[${String(index)}].${field} must be ${String(min)}–${String(max)}`,\n );\n }\n }\n }\n return found;\n};\n\nconst absolute = (name: string, value: string | undefined): string[] =>\n value === undefined || value.startsWith('/') ? [] : [`${name} must be an absolute path`];\n\n/**\n * The label and domain alone — the job's identity. ★ Split out because a rename is a delete-first\n * replace, and it must be refusable at plan time even while other props are still unresolved\n * Outputs (see job.ts diff): otherwise the old job is deleted and only then is the new label\n * found to be invalid.\n */\nexport const identityProblems = (label: string, domainText: string): string[] => {\n const found: string[] = [];\n if (!LABEL.test(label)) {\n found.push('label must be 1–200 of [A-Za-z0-9._-], starting with a letter or digit');\n }\n const reserved = RESERVED_LABEL_PREFIXES.find((prefix) => label.startsWith(prefix));\n if (reserved !== undefined) {\n found.push(`label ${label} is under ${reserved}, which another tool owns; declare a new label`);\n }\n if (parseDomain(domainText) === undefined)\n found.push(`domain must be 'system' or 'gui/<uid>', not ${domainText}`);\n return found;\n};\n\nexport const jobProblems = (props: LaunchdJobProps): string[] => {\n const found = identityProblems(props.label, props.domain);\n const domain = parseDomain(props.domain);\n\n const [program] = props.programArguments;\n // ★ Absolute, because launchd's PATH for a job is not the deploying shell's PATH.\n if (program === undefined) found.push('programArguments must name a program');\n else if (!program.startsWith('/')) found.push('programArguments[0] must be an absolute path');\n\n for (const name of Object.keys(props.environment ?? {})) {\n if (!ENV_NAME.test(name))\n found.push(`environment name ${JSON.stringify(name)} is not a valid variable name`);\n }\n found.push(...jobSecretProblems(props.environment, props.programArguments, props.extraKeys));\n\n if (props.startInterval !== undefined && !isInt(props.startInterval, 1)) {\n found.push('startInterval must be a positive whole number of seconds');\n }\n if (props.throttleInterval !== undefined && !isInt(props.throttleInterval, 0)) {\n found.push('throttleInterval must be a non-negative whole number of seconds');\n }\n const calendar = props.startCalendarInterval;\n if (calendar !== undefined) {\n found.push(\n ...calendarProblems(Array.isArray(calendar) ? calendar : [calendar as CalendarInterval]),\n );\n }\n const keepAlive = props.keepAlive;\n if (\n typeof keepAlive === 'object' &&\n keepAlive.successfulExit === undefined &&\n keepAlive.crashed === undefined\n ) {\n found.push('keepAlive {} names no condition; use true, false, or a condition');\n }\n\n found.push(...absolute('standardOutPath', props.standardOutPath));\n found.push(...absolute('standardErrorPath', props.standardErrorPath));\n found.push(...absolute('workingDirectory', props.workingDirectory));\n\n if (domain?.kind === 'gui' && (props.userName !== undefined || props.groupName !== undefined)) {\n found.push(\n 'userName/groupName apply only to the system domain; launchd ignores them for agents',\n );\n }\n for (const key of Object.keys(props.extraKeys ?? {})) {\n if (OWNED_KEYS.includes(key))\n found.push(`extraKeys.${key} is owned by a typed prop; use that instead`);\n }\n return found;\n};\n",
|
|
19
21
|
"/**\n * The four `launchctl` subcommands LaunchdJob uses — print, print-disabled, bootstrap, bootout —\n * over a HostRunner, plus the parsers for the two read-only ones.\n *\n * ★ MEASURED 2026-09-21 ON macOS 27.2 (read-only `print` / `print-disabled` only; nothing was\n * bootstrapped or booted out to write this):\n * - `print system/<unknown>` exits **113** with \"Could not find service … in domain for system\"\n * on stderr. 113 is therefore \"not loaded\", not an error.\n * - `print` of a loaded job is a `<target> = {` block. Its own fields sit one tab deep\n * (`\\tstate = running`, `\\tpid = 1219`, `\\tlast exit code = 0` or `(never exited)`); nested\n * blocks (`resource coalition`, `semaphores`) repeat names like `state` two tabs deep.\n * - `print-disabled <domain>` lists `\"label\" => enabled|disabled`.\n * - reading needs no root: a uid-501 shell printed system-domain jobs.\n * - `print gui/<uid>/<label>` for a uid with NO LOGIN SESSION exits **112** with \"Could not find\n * domain for user gui: <uid>\" (and so does `print-disabled gui/<uid>`); a malformed target is\n * 64, a missing service in a live gui domain is 113. So 112 + that text is \"the domain does\n * not exist\", which means the job cannot be loaded — not an error for a read or a delete.\n * ⚠️ REASONED, NOT MEASURED: bootstrap/bootout exit codes. nix-darwin's own activation script on the\n * same host notes \"`bootout` on an already-absent job is a no-op that returns non-zero\", which is\n * why bootout here is always preceded by a print and followed by a poll, never trusted alone.\n * ⛔ NEVER PUT `print` STDOUT IN AN ERROR. It contains the job's whole environment.\n */\nimport type { HostRunner } from './runner.ts';\n\nexport const LAUNCHCTL = '/bin/launchctl';\n/** `launchctl print` of an unknown service — measured, see above. */\nexport const NOT_FOUND = 113;\n/** `launchctl print` into a gui domain with no login session — measured, see above. */\nexport const NO_DOMAIN = 112;\nconst NO_DOMAIN_TEXT = 'Could not find domain';\n\nexport class LaunchctlError extends Error {\n constructor(command: string, exitCode: number, stderr: string) {\n super(`launchctl ${command} -> ${String(exitCode)}: ${stderr.trim().slice(0, 300)}`);\n this.name = 'LaunchctlError';\n }\n}\n\nexport type ServiceStatus = {\n readonly loaded: boolean;\n /** The domain itself is absent (a gui/<uid> with no login session). Implies `loaded: false`. */\n readonly domainMissing?: true;\n readonly state?: string;\n readonly pid?: number;\n readonly lastExitCode?: number;\n};\n\n/**\n * The job block's own `key = value` lines, ignoring nested blocks.\n * ⚠️ A multi-line ProgramArguments entry is printed raw inside `arguments = {`, so a close is only\n * accepted when its indentation matches the open. An argument that itself contains a line of\n * exactly one tab and `}` would still desynchronise this; no real job has one.\n */\nexport const printFields = (stdout: string): Map<string, string> => {\n const fields = new Map<string, string>();\n const closers: string[] = [];\n for (const line of stdout.split('\\n')) {\n if (closers.length === 0) {\n if (fields.size === 0 && line.endsWith(' = {')) closers.push('}');\n continue;\n }\n if (line === closers[closers.length - 1]) {\n closers.pop();\n continue;\n }\n const opened = /^(\\t+)\\S.* = \\{$/.exec(line);\n if (opened?.[1] !== undefined && opened[1].length === closers.length) {\n closers.push(`${opened[1]}}`);\n continue;\n }\n const field = closers.length === 1 ? /^\\t([a-z][a-z ]*[a-z]) = (.*)$/.exec(line) : null;\n if (field?.[1] !== undefined && field[2] !== undefined && !fields.has(field[1])) {\n fields.set(field[1], field[2]);\n }\n }\n return fields;\n};\n\nconst leadingInt = (text: string | undefined): number | undefined => {\n const match = text === undefined ? null : /^(-?\\d+)/.exec(text);\n return match?.[1] === undefined ? undefined : Number(match[1]);\n};\n\nexport const parsePrint = (stdout: string): ServiceStatus => {\n const fields = printFields(stdout);\n const state = fields.get('state');\n const pid = leadingInt(fields.get('pid'));\n // \"(never exited)\" parses to undefined; \"78: EX_CONFIG\" to 78.\n const lastExitCode = leadingInt(fields.get('last exit code'));\n return {\n loaded: true,\n ...(state === undefined ? {} : { state }),\n ...(pid === undefined ? {} : { pid }),\n ...(lastExitCode === undefined ? {} : { lastExitCode }),\n };\n};\n\n/** Labels `print-disabled` reports as disabled. Older releases printed `=> true` for disabled. */\nexport const parseDisabled = (stdout: string): Set<string> => {\n const disabled = new Set<string>();\n for (const match of stdout.matchAll(/^\\s*\"([^\"]+)\" => (\\w+)\\s*$/gm)) {\n if (match[1] !== undefined && (match[2] === 'disabled' || match[2] === 'true')) {\n disabled.add(match[1]);\n }\n }\n return disabled;\n};\n\nexport const printService = async (runner: HostRunner, target: string): Promise<ServiceStatus> => {\n const result = await runner.exec([LAUNCHCTL, 'print', target]);\n if (result.exitCode === NOT_FOUND) return { loaded: false };\n // ⚠️ Without this, deleting an agent while its user is logged out fails on the read, and the\n // plist stays in LaunchAgents — where launchd loads it again at that user's next login.\n if (result.exitCode === NO_DOMAIN && result.stderr.includes(NO_DOMAIN_TEXT)) {\n return { domainMissing: true, loaded: false };\n }\n if (result.exitCode !== 0)\n throw new LaunchctlError(`print ${target}`, result.exitCode, result.stderr);\n return parsePrint(result.stdout);\n};\n\nexport const isDisabled = async (\n runner: HostRunner,\n domain: string,\n label: string,\n): Promise<boolean> => {\n const result = await runner.exec([LAUNCHCTL, 'print-disabled', domain]);\n if (result.exitCode !== 0) {\n throw new LaunchctlError(`print-disabled ${domain}`, result.exitCode, result.stderr);\n }\n return parseDisabled(result.stdout).has(label);\n};\n\nexport const bootstrap = async (\n runner: HostRunner,\n domain: string,\n plistPath: string,\n): Promise<void> => {\n const result = await runner.exec([LAUNCHCTL, 'bootstrap', domain, plistPath]);\n if (result.exitCode !== 0) {\n throw new LaunchctlError(`bootstrap ${domain} ${plistPath}`, result.exitCode, result.stderr);\n }\n};\n\n/**\n * Poll `print` until the service is gone. ⚠️ bootout can return before launchd lets go of it.\n * ★ 30 s, because a job gets SIGTERM and then its ExitTimeOut before SIGKILL: launchd.plist(5)\n * documents a 20 s default (a macOS 27.2 `print` showed `exit timeout = 5` for a job that sets\n * none). Giving up sooner would fail a deploy over a job that was, correctly, still exiting.\n */\nexport const waitUnloaded = async (\n runner: HostRunner,\n target: string,\n attempts = 120,\n intervalMs = 250,\n): Promise<void> => {\n for (let attempt = 0; attempt < attempts; attempt += 1) {\n if (!(await printService(runner, target)).loaded) return;\n await runner.sleep(intervalMs);\n }\n throw new Error(\n `${target} is still loaded ${String((attempts * intervalMs) / 1000)}s after bootout`,\n );\n};\n\n/** Boot a service out if it is loaded, and wait until launchd has let go. Idempotent. */\nexport const bootoutIfLoaded = async (runner: HostRunner, target: string): Promise<void> => {\n if (!(await printService(runner, target)).loaded) return;\n const result = await runner.exec([LAUNCHCTL, 'bootout', target]);\n /**\n * ⚠️ A non-zero bootout is only an error if the service is STILL there after the wait (see\n * header) — so wait FIRST, then judge. A job slower to exit than launchctl's own wait is widely\n * reported to fail bootout with `36: Operation now in progress` (EINPROGRESS) while it is\n * still going away; REASONED from those reports, not measured here. Judging on an immediate\n * print would fail the deploy with the new plist written and the old job already exiting —\n * the job ends up down either way, and the error would blame the wrong step.\n */\n try {\n await waitUnloaded(runner, target);\n } catch (cause) {\n if (result.exitCode === 0) throw cause;\n throw new LaunchctlError(\n `bootout ${target}`,\n result.exitCode,\n `${result.stderr.trim()} (and still loaded after waiting)`,\n );\n }\n};\n",
|
|
20
22
|
"/**\n * Everything LaunchdJob checks before it touches the host — split from job-lifecycle.ts so that a\n * reconcile and a plan-time REPLACE run the very same checks.\n *\n * ★ WHY A REPLACE IS CHECKED AT PLAN TIME. A label or domain change is a delete-first replace, and\n * Alchemy runs `delete` on the old job BEFORE `reconcile` on the new one (Apply.ts,\n * deleteOldGenerations under `node.deleteFirst`; read in alchemy 2.0.0-beta.79 on 2026-09-21).\n * A refusal that fired only in reconcile would therefore arrive after the old job was already\n * booted out: nothing running, and a plan that had promised a clean swap.\n * ★ EVERY CHECK HERE IS READ-ONLY: validation, a user lookup, `launchctl print` and\n * `print-disabled` — none of which needs root (measured, see launchctl.ts).\n */\nimport {\n type LaunchdJobAttributes,\n type LaunchdJobProps,\n type ParsedDomain,\n parseDomain,\n plistPathFor,\n serviceTarget,\n sha256Hex,\n} from './job-form.ts';\nimport { identityProblems, jobProblems } from './job-validate.ts';\nimport { type ServiceStatus, isDisabled, printService } from './launchctl.ts';\nimport { type HostRunner, type WriteOptions, canActAsRoot } from './runner.ts';\n\nexport type Location = {\n readonly domain: ParsedDomain;\n readonly plistPath: string;\n readonly target: string;\n};\n\nexport type Identity = Pick<LaunchdJobProps, 'label' | 'domain'>;\n\n/**\n * ⚠️ launchd refuses a daemon plist that is not root:wheel or is group/world-writable (\"bad\n * ownership/permissions\"), so the system domain always writes 0644 root:wheel. An agent's plist\n * belongs to its user. REASONED from launchd's documented behaviour, not measured here (no\n * bootstrap was run to write this); the nix-darwin daemons on the reference host are 0644 root.\n */\nexport const plistWriteOptions = (domain: ParsedDomain): WriteOptions =>\n domain.kind === 'system' ? { gid: 0, mode: 0o644, uid: 0 } : { mode: 0o644, uid: domain.uid };\n\n/**\n * PLAN TIME, for a plan that will write the plist: the runner's own pre-write refusals\n * (HostRunner.checkWrite — sudoRunner's directory and mode checks), reading only.\n */\nexport const checkPlistWrite = async (runner: HostRunner, location: Location): Promise<void> =>\n runner.checkWrite?.(location.plistPath, plistWriteOptions(location.domain));\n\nexport const refuse = (label: string, message: string): Error =>\n new Error(`Launchd.Job ${label}: ${message}`);\n\n/** Throw every refusal at once, so one plan shows the whole list. */\nexport const assertValid = (props: LaunchdJobProps): void => {\n const found = jobProblems(props);\n if (found.length > 0) throw refuse(props.label, found.join('; '));\n};\n\nexport const locate = async (runner: HostRunner, props: Identity): Promise<Location> => {\n const domain = parseDomain(props.domain);\n if (domain === undefined) throw refuse(props.label, `unknown domain ${props.domain}`);\n const home =\n domain.kind === 'gui' ? (await runner.lookupUser(String(domain.uid)))?.home : undefined;\n return {\n domain,\n plistPath: plistPathFor(props.label, domain, home),\n target: serviceTarget(props.label, props.domain),\n };\n};\n\n/**\n * ⛔ NO SILENT SUDO. The system domain, and another user's gui domain, need root. Refuse up front\n * with the two ways out, rather than let launchctl or rename(2) fail halfway through.\n */\nexport const assertMayWrite = (runner: HostRunner, label: string, domain: ParsedDomain): void => {\n if (canActAsRoot(runner)) return;\n if (domain.kind === 'system') {\n throw refuse(\n label,\n 'the system domain needs root. Run the deploy as root, or pass a deliberately privileged ' +\n 'HostRunner: sudoRunner() elevates exactly the calls this needs. This provider never ' +\n 'calls sudo itself.',\n );\n }\n if (domain.uid !== runner.effectiveUid()) {\n throw refuse(\n label,\n `gui/${String(domain.uid)} belongs to another user; only root may write it. ` +\n 'Deploy as that user, as root, or through a privileged HostRunner.',\n );\n }\n};\n\n/** Where the job goes, whether we may write it there, and launchd's current view of it. */\nexport const preflight = async (\n runner: HostRunner,\n props: Identity,\n): Promise<{ location: Location; status: ServiceStatus }> => {\n const location = await locate(runner, props);\n assertMayWrite(runner, props.label, location.domain);\n const status = await printService(runner, location.target);\n if (status.domainMissing === true) {\n throw refuse(\n props.label,\n `${props.domain} does not exist: that user has no login session, and launchd creates a gui ` +\n 'domain only at login. Log the user in (or declare a system-domain job with userName), ' +\n 'then redeploy. Nothing was written.',\n );\n }\n /**\n * ⛔ A DISABLED LABEL IS SOMEONE'S DECISION, NOT DRIFT. `launchctl disable` persists across boots\n * and makes bootstrap fail; enabling it here would silently overrule whoever disabled it.\n */\n if (await isDisabled(runner, props.domain, props.label)) {\n throw refuse(\n props.label,\n `${location.target} is disabled (launchctl print-disabled ${props.domain}). ` +\n `If that is stale, run \\`launchctl enable ${location.target}\\` deliberately, then redeploy.`,\n );\n }\n return { location, status };\n};\n\n/**\n * ⛔ A JOB THIS RESOURCE DOES NOT OWN IS NEVER OVERWRITTEN. Alchemy's adoption probe guards a\n * create, but NOT the new label of a replace — the engine reads nothing there — so a rename onto\n * a label someone already loaded would boot their job out and write ours over its plist.\n * ★ A plist byte-identical to our render is exempt: it is this declaration's own leftover (a\n * deploy that died between write and bootstrap), and rewriting it changes nothing.\n */\nexport const assertUnclaimed = async (\n runner: HostRunner,\n label: string,\n location: Location,\n status: ServiceStatus,\n renderedSha256: string | undefined,\n): Promise<void> => {\n const bytes = await runner.readFile(location.plistPath);\n const foreignFile = bytes !== undefined && sha256Hex(bytes) !== renderedSha256;\n if (foreignFile || (bytes === undefined && status.loaded)) {\n throw refuse(\n label,\n `${location.target} is already on this host (${foreignFile ? location.plistPath : 'loaded'})` +\n ' and is not this resource. Remove it, or declare it as a new resource and deploy with ' +\n '--adopt.',\n );\n }\n};\n\n/**\n * A rename, checked at plan time: the new identity must be valid, writable, bootstrappable and\n * free, and the old one deletable — before the plan may promise a delete-first replace.\n * `full` is the whole declaration when it is already resolved; otherwise only the identity is.\n */\nexport const assertReplaceable = async (\n runner: HostRunner,\n next: Identity,\n full: LaunchdJobProps | undefined,\n old: LaunchdJobAttributes,\n renderedSha256: string | undefined,\n): Promise<void> => {\n const found = full === undefined ? identityProblems(next.label, next.domain) : jobProblems(full);\n if (found.length > 0) throw refuse(next.label, found.join('; '));\n const oldDomain = parseDomain(old.domain);\n if (oldDomain === undefined) throw refuse(old.label, `unknown domain ${old.domain}`);\n assertMayWrite(runner, old.label, oldDomain);\n const { location, status } = await preflight(runner, next);\n await assertUnclaimed(runner, next.label, location, status, renderedSha256);\n await checkPlistWrite(runner, location);\n};\n",
|
|
21
23
|
"/**\n * LaunchdJob's read / diff / reconcile / delete as plain async functions over a HostRunner — split\n * from job.ts so the whole lifecycle runs against fake-runner.ts in tests, with no real launchd.\n * The checks made before any write live in job-preflight.ts.\n *\n * ★ THE ORDER IS WRITE, BOOTOUT, BOOTSTRAP — not bootout first. launchd reads the plist only at\n * bootstrap, so writing the new file while the old job runs changes nothing yet, and a write that\n * fails (disk full, EACCES) leaves the old job running instead of leaving nothing running.\n * ⚠️ A FAILED BOOTSTRAP LEAVES THE JOB DOWN. On an UPDATE the new plist stays on disk, the state\n * keeps the previous digest, and the next deploy retries. On a CREATE the plist this deploy wrote\n * is removed again: left behind, the next plan's recovery `read` would find a plist with no\n * state and report it `Unowned`, and every later deploy would demand `--adopt` for our own file.\n * There is no rollback to an older plist: one that launchd refuses is a declaration to fix, and\n * re-bootstrapping the old one could fail for the same host-side reason.\n */\nimport type { Diff } from 'alchemy/Diff';\nimport {\n type LaunchdJobAttributes,\n type LaunchdJobProps,\n parseDomain,\n renderJob,\n sha256Hex,\n} from './job-form.ts';\nimport {\n type Identity,\n type Location,\n assertMayWrite,\n assertReplaceable,\n assertUnclaimed,\n assertValid,\n checkPlistWrite,\n locate,\n plistWriteOptions,\n preflight,\n refuse,\n} from './job-preflight.ts';\nimport { type ServiceStatus, bootoutIfLoaded, bootstrap, printService } from './launchctl.ts';\nimport type { HostRunner } from './runner.ts';\n\nconst attributesOf = (\n props: Identity,\n location: Location,\n plistSha256: string,\n status: ServiceStatus,\n): LaunchdJobAttributes => ({\n domain: props.domain,\n label: props.label,\n loaded: status.loaded,\n plistPath: location.plistPath,\n plistSha256,\n serviceTarget: location.target,\n ...(status.state === undefined ? {} : { state: status.state }),\n ...(status.pid === undefined ? {} : { pid: status.pid }),\n ...(status.lastExitCode === undefined ? {} : { lastExitCode: status.lastExitCode }),\n});\n\n/** What is on the host now: the plist's digest and launchd's view. `undefined` when neither exists. */\nexport const readJob = async (\n runner: HostRunner,\n props: Identity,\n): Promise<LaunchdJobAttributes | undefined> => {\n const location = await locate(runner, props);\n const bytes = await runner.readFile(location.plistPath);\n const status = await printService(runner, location.target);\n if (bytes === undefined && !status.loaded) return undefined;\n return attributesOf(props, location, bytes === undefined ? '' : sha256Hex(bytes), status);\n};\n\n/**\n * ★ `deleteFirst`: labels are unique per domain, and the old and new job would otherwise run the\n * same program side by side — same port, same files — until the old one is deleted. A brief\n * outage beats two copies. ⛔ Which is why everything the new job's reconcile would refuse is\n * refused HERE, at plan time (job-preflight.ts): after the delete it would be too late.\n * `full` is the whole declaration when resolved; job.ts passes only the identity otherwise.\n */\nexport const replaceDiff = async (\n runner: HostRunner,\n next: Identity,\n full: LaunchdJobProps | undefined,\n output: LaunchdJobAttributes,\n): Promise<Diff> => {\n // ★ Validate before rendering, so a bad declaration shows its whole list, not a render error.\n if (full !== undefined) assertValid(full);\n const rendered = full === undefined ? undefined : renderJob(full).sha256;\n await assertReplaceable(runner, next, full, output, rendered);\n return { action: 'replace', deleteFirst: true };\n};\n\nexport const diffJob = async (\n runner: HostRunner,\n news: LaunchdJobProps,\n output: LaunchdJobAttributes,\n): Promise<Diff> => {\n if (news.label !== output.label || news.domain !== output.domain) {\n return replaceDiff(runner, news, news, output);\n }\n assertValid(news);\n const desired = renderJob(news).sha256;\n // ★ A plan that will write the plist asks the runner first (checkPlistWrite, HostRunner.checkWrite).\n const update = async (): Promise<Diff> => {\n await checkPlistWrite(runner, await locate(runner, news));\n return { action: 'update' };\n };\n // ⛔ BOTH digests: the stored one catches a bootstrap that failed after the write landed, the live\n // one catches a hand edit. Either alone would report `noop` over a job that is not what we say.\n if (desired !== output.plistSha256) return update();\n const live = await readJob(runner, news);\n if (live === undefined || !live.loaded || live.plistSha256 !== desired) return update();\n return { action: 'noop' };\n};\n\n/**\n * `adopt` is whether adoption is on AND this apply is a create or an unfinished generation of our\n * own (ownership/adopt.ts adoptsAtApply): it lets such a generation take over a job already on the\n * host, as the plan's probe would have. A rename onto an occupied label stays refused, as it is at\n * plan time (assertReplaceable) — including a label taken between that plan and a fresh replace's\n * new generation, which the caller never marks adoptable.\n */\nexport const reconcileJob = async (\n runner: HostRunner,\n props: LaunchdJobProps,\n output: LaunchdJobAttributes | undefined,\n adopt = false,\n): Promise<LaunchdJobAttributes> => {\n assertValid(props);\n const { location, status } = await preflight(runner, props);\n const rendered = renderJob(props);\n /**\n * ⚠️ AN `output` UNDER ANOTHER LABEL OR DOMAIN means the engine planned an UPDATE across a rename —\n * which it does whenever diff could not see the rename (a label that was itself an unresolved\n * Output at plan time; job.ts). Bootstrapping the new label alone would orphan the old job,\n * still running, with nothing left in state to ever remove it. So do what the replace would\n * have done: every check above first, then delete the old job, then create the new one.\n */\n const renamed =\n output !== undefined && (output.label !== props.label || output.domain !== props.domain);\n const prior = renamed ? undefined : output;\n // ⛔ No prior state for THIS identity: whatever is there already belongs to someone else —\n // unless adoption is on for a create, where the probe was skipped (a prop still an Output).\n if (prior === undefined && !(adopt && output === undefined)) {\n await assertUnclaimed(runner, props.label, location, status, rendered.sha256);\n }\n if (renamed) await deleteJob(runner, output);\n const before = await runner.readFile(location.plistPath);\n // ★ Already converged (a retried deploy, or an adopted job that matches): do not restart it.\n // ⛔ The STORED digest is part of the test: a write that landed before a failed bootout leaves\n // the new plist on disk and the OLD job loaded — both look right, and only state knows better.\n if (\n status.loaded &&\n before !== undefined &&\n sha256Hex(before) === rendered.sha256 &&\n prior?.plistSha256 === rendered.sha256\n ) {\n return attributesOf(props, location, rendered.sha256, status);\n }\n // ⚠️ Owner and mode are launchd's rule, not a choice: see plistWriteOptions (job-preflight.ts).\n await runner.writeFileAtomic(\n location.plistPath,\n rendered.bytes,\n plistWriteOptions(location.domain),\n );\n await bootoutIfLoaded(runner, location.target);\n const failed = async (detail: string): Promise<never> => {\n // ⚠️ A failed removal must not replace the bootstrap error, nor let the message claim it worked.\n const removed =\n before === undefined &&\n (await runner.removeFile(location.plistPath).then(\n () => true,\n () => false,\n ));\n throw refuse(\n props.label,\n removed\n ? `bootstrap failed, so the job is NOT RUNNING; the plist this deploy wrote was removed ` +\n `again, so the next deploy starts clean. ${detail}`\n : `bootstrap failed, so the job is NOT RUNNING; the new plist is at ${location.plistPath} ` +\n `and the next deploy retries. ${detail}`,\n );\n };\n try {\n await bootstrap(runner, props.domain, location.plistPath);\n } catch (cause) {\n return failed(cause instanceof Error ? cause.message : String(cause));\n }\n const after = await printService(runner, location.target);\n if (!after.loaded) return failed('bootstrap exited 0 but launchctl print cannot find the job');\n return attributesOf(props, location, rendered.sha256, after);\n};\n\n/** Boot out, then remove the plist. Idempotent: an absent job and an absent file are success. */\nexport const deleteJob = async (\n runner: HostRunner,\n output: LaunchdJobAttributes,\n): Promise<void> => {\n const domain = parseDomain(output.domain);\n if (domain === undefined) throw refuse(output.label, `unknown domain ${output.domain}`);\n assertMayWrite(runner, output.label, domain);\n // ★ A gui domain with no login session reads as \"not loaded\" (launchctl.ts), so the plist is\n // still removed — which is what stops launchd loading it again at that user's next login.\n await bootoutIfLoaded(runner, output.serviceTarget);\n await runner.removeFile(output.plistPath);\n};\n",
|
|
22
|
-
"/**\n * The real HostRunner: this process, this machine, this uid.\n *\n * ★ node:fs AND node:child_process, NOT Bun APIs. An Alchemy stack usually runs under bun, but\n * the published dist also loads under node (the package's smoke test and the kit's AGENTS.md:\n * consumers run dist/, not src/), and both runtimes implement these modules.\n * ⛔ NO ELEVATION, EVER. `privileged` is false; a system-domain write succeeds only when the whole\n * deploy was started as root. See the ⛔ on HostRunner.privileged for why nothing here calls sudo;\n * the opt-in elevating runner is sudo-runner.ts, which wraps this one.\n * ⛔ NO SHELL. `exec` spawns argv directly, so a label, path or argument can never be re-parsed\n * as shell syntax.\n */\nimport { spawn } from 'node:child_process';\nimport { randomBytes } from 'node:crypto';\nimport { lstat, open, readFile, rename, unlink } from 'node:fs/promises';\nimport { basename, dirname, join } from 'node:path';\nimport { groupQuery, parseGroup, parseUser, userQuery } from './host-lookup.ts';\nimport type { ExecResult, FileStat, HostRunner, WriteOptions } from './runner.ts';\n\nexport type LocalRunnerOptions = {\n /** Kill a spawned program after this long. @default 120_000 */\n readonly execTimeoutMs?: number;\n};\n\n/** The errno code of a thrown fs error (`ENOENT`, `EACCES`, …), if it has one. */\nexport const errnoCode = (cause: unknown): string | undefined =>\n typeof cause === 'object' && cause !== null && 'code' in cause\n ? String((cause as { code: unknown }).code)\n : undefined;\n\n/** ENOENT and ENOTDIR both mean \"nothing is at this path\". */\nconst absent = (cause: unknown): boolean =>\n errnoCode(cause) === 'ENOENT' || errnoCode(cause) === 'ENOTDIR';\n\nconst run = (argv: readonly string[], timeoutMs: number): Promise<ExecResult> =>\n new Promise((resolve, reject) => {\n const [program, ...args] = argv;\n if (program === undefined) {\n reject(new Error('exec: empty argv'));\n return;\n }\n const child = spawn(program, args, {\n shell: false,\n stdio: ['ignore', 'pipe', 'pipe'],\n timeout: timeoutMs,\n });\n const out: Buffer[] = [];\n const err: Buffer[] = [];\n child.stdout.on('data', (chunk: Buffer) => out.push(chunk));\n child.stderr.on('data', (chunk: Buffer) => err.push(chunk));\n child.on('error', (cause) => {\n reject(new Error(`exec ${program}: ${cause.message}`));\n });\n child.on('close', (exitCode, signal) => {\n const stderr = Buffer.concat(err).toString('utf8');\n resolve({\n // ⚠️ A signal (including our own timeout) has no exit code; -1 keeps it a failure.\n exitCode: exitCode ?? -1,\n stderr: signal === null ? stderr : `${stderr}\\n(killed by ${signal})`.trim(),\n stdout: Buffer.concat(out).toString('utf8'),\n });\n });\n });\n\nconst kindOf = (stats: Awaited<ReturnType<typeof lstat>>): FileStat['kind'] => {\n if (stats.isSymbolicLink()) return 'symlink';\n if (stats.isFile()) return 'file';\n if (stats.isDirectory()) return 'directory';\n return 'other';\n};\n\nconst writeAtomic = async (path: string, bytes: Uint8Array, options: WriteOptions) => {\n // ★ Same directory as the target, so rename(2) never crosses a filesystem (which would EXDEV).\n const temp = join(dirname(path), `.${basename(path)}.${randomBytes(6).toString('hex')}.tmp`);\n // ⛔ 'wx' = O_CREAT|O_EXCL, and 0600 until the final mode: the temp file is never readable by\n // anyone else in the moment before its mode is set, and never follows a planted symlink.\n const handle = await open(temp, 'wx', 0o600);\n try {\n try {\n await handle.writeFile(bytes);\n // ⚠️ chown BEFORE chmod: a chown by root clears setuid/setgid bits, so the other order\n // would silently drop a declared 4755.\n if (options.uid !== undefined || options.gid !== undefined) {\n await handle.chown(options.uid ?? -1, options.gid ?? -1);\n }\n await handle.chmod(options.mode);\n await handle.sync();\n } finally {\n await handle.close();\n }\n await rename(temp, path);\n } catch (cause) {\n await unlink(temp).catch(() => undefined);\n throw cause;\n }\n};\n\nexport const localRunner = (options: LocalRunnerOptions = {}): HostRunner => {\n const timeoutMs = options.execTimeoutMs ?? 120_000;\n const platform = process.platform;\n return {\n effectiveUid: () => process.geteuid?.() ?? -1,\n exec: (argv) => run(argv, timeoutMs),\n lookupGroup: async (nameOrId) => {\n const result = await run(groupQuery(platform, nameOrId), timeoutMs);\n return result.exitCode === 0 ? parseGroup(platform, result.stdout) : undefined;\n },\n lookupUser: async (nameOrId) => {\n const result = await run(userQuery(platform, nameOrId), timeoutMs);\n return result.exitCode === 0 ? parseUser(platform, result.stdout) : undefined;\n },\n privileged: false,\n readFile: async (path) => {\n try {\n return new Uint8Array(await readFile(path));\n } catch (cause) {\n if (absent(cause)) return undefined;\n throw cause;\n }\n },\n removeFile: async (path) => {\n try {\n await unlink(path);\n } catch (cause) {\n if (!absent(cause)) throw cause;\n }\n },\n sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),\n stat: async (path) => {\n try {\n const stats = await lstat(path);\n return {\n gid: stats.gid,\n kind: kindOf(stats),\n mode: stats.mode & 0o7777,\n size: stats.size,\n uid: stats.uid,\n };\n } catch (cause) {\n if (absent(cause)) return undefined;\n throw cause;\n }\n },\n writeFileAtomic: writeAtomic,\n };\n};\n",
|
|
24
|
+
"/**\n * The real HostRunner: this process, this machine, this uid.\n *\n * ★ node:fs AND node:child_process, NOT Bun APIs. An Alchemy stack usually runs under bun, but\n * the published dist also loads under node (the package's smoke test and the kit's AGENTS.md:\n * consumers run dist/, not src/), and both runtimes implement these modules.\n * ⛔ NO ELEVATION, EVER. `privileged` is false; a system-domain write succeeds only when the whole\n * deploy was started as root. See the ⛔ on HostRunner.privileged for why nothing here calls sudo;\n * the opt-in elevating runner is sudo-runner.ts, which wraps this one.\n * ⛔ NO SHELL. `exec` spawns argv directly, so a label, path or argument can never be re-parsed\n * as shell syntax.\n */\nimport { spawn } from 'node:child_process';\nimport { randomBytes } from 'node:crypto';\nimport { lstat, open, readFile, rename, unlink } from 'node:fs/promises';\nimport { basename, dirname, join } from 'node:path';\nimport { groupQuery, parseGroup, parseUser, userQuery } from './host-lookup.ts';\nimport type { ExecResult, FileStat, HostRunner, WriteOptions } from './runner.ts';\n\nexport type LocalRunnerOptions = {\n /** Kill a spawned program after this long. @default 120_000 */\n readonly execTimeoutMs?: number;\n};\n\n/** The errno code of a thrown fs error (`ENOENT`, `EACCES`, …), if it has one. */\nexport const errnoCode = (cause: unknown): string | undefined =>\n typeof cause === 'object' && cause !== null && 'code' in cause\n ? String((cause as { code: unknown }).code)\n : undefined;\n\n/** ENOENT and ENOTDIR both mean \"nothing is at this path\". */\nconst absent = (cause: unknown): boolean =>\n errnoCode(cause) === 'ENOENT' || errnoCode(cause) === 'ENOTDIR';\n\nconst run = (argv: readonly string[], timeoutMs: number): Promise<ExecResult> =>\n new Promise((resolve, reject) => {\n const [program, ...args] = argv;\n if (program === undefined) {\n reject(new Error('exec: empty argv'));\n return;\n }\n const child = spawn(program, args, {\n shell: false,\n stdio: ['ignore', 'pipe', 'pipe'],\n timeout: timeoutMs,\n });\n const out: Buffer[] = [];\n const err: Buffer[] = [];\n child.stdout.on('data', (chunk: Buffer) => out.push(chunk));\n child.stderr.on('data', (chunk: Buffer) => err.push(chunk));\n child.on('error', (cause) => {\n reject(new Error(`exec ${program}: ${cause.message}`));\n });\n child.on('close', (exitCode, signal) => {\n const stderr = Buffer.concat(err).toString('utf8');\n resolve({\n // ⚠️ A signal (including our own timeout) has no exit code; -1 keeps it a failure.\n exitCode: exitCode ?? -1,\n stderr: signal === null ? stderr : `${stderr}\\n(killed by ${signal})`.trim(),\n stdout: Buffer.concat(out).toString('utf8'),\n });\n });\n });\n\nconst kindOf = (stats: Awaited<ReturnType<typeof lstat>>): FileStat['kind'] => {\n if (stats.isSymbolicLink()) return 'symlink';\n if (stats.isFile()) return 'file';\n if (stats.isDirectory()) return 'directory';\n return 'other';\n};\n\nconst writeAtomic = async (path: string, bytes: Uint8Array, options: WriteOptions) => {\n // ★ Same directory as the target, so rename(2) never crosses a filesystem (which would EXDEV).\n const temp = join(dirname(path), `.${basename(path)}.${randomBytes(6).toString('hex')}.tmp`);\n // ⛔ 'wx' = O_CREAT|O_EXCL, and 0600 until the final mode: the temp file is never readable by\n // anyone else in the moment before its mode is set, and never follows a planted symlink.\n const handle = await open(temp, 'wx', 0o600);\n try {\n try {\n await handle.writeFile(bytes);\n // ⚠️ chown BEFORE chmod: a chown by root clears setuid/setgid bits, so the other order\n // would silently drop a declared 4755.\n if (options.uid !== undefined || options.gid !== undefined) {\n await handle.chown(options.uid ?? -1, options.gid ?? -1);\n }\n await handle.chmod(options.mode);\n await handle.sync();\n } finally {\n await handle.close();\n }\n await rename(temp, path);\n } catch (cause) {\n await unlink(temp).catch(() => undefined);\n throw cause;\n }\n};\n\nexport const localRunner = (options: LocalRunnerOptions = {}): HostRunner => {\n const timeoutMs = options.execTimeoutMs ?? 120_000;\n const platform = process.platform;\n return {\n effectiveUid: () => process.geteuid?.() ?? -1,\n exec: (argv) => run(argv, timeoutMs),\n lookupGroup: async (nameOrId) => {\n const result = await run(groupQuery(platform, nameOrId), timeoutMs);\n return result.exitCode === 0 ? parseGroup(platform, result.stdout) : undefined;\n },\n lookupUser: async (nameOrId) => {\n const result = await run(userQuery(platform, nameOrId), timeoutMs);\n return result.exitCode === 0 ? parseUser(platform, result.stdout) : undefined;\n },\n privileged: false,\n readFile: async (path) => {\n try {\n return new Uint8Array(await readFile(path));\n } catch (cause) {\n if (absent(cause)) return undefined;\n throw cause;\n }\n },\n removeFile: async (path) => {\n try {\n await unlink(path);\n } catch (cause) {\n if (!absent(cause)) throw cause;\n }\n },\n sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),\n stat: async (path) => {\n try {\n const stats = await lstat(path);\n return {\n dev: stats.dev,\n gid: stats.gid,\n ino: stats.ino,\n kind: kindOf(stats),\n mode: stats.mode & 0o7777,\n size: stats.size,\n uid: stats.uid,\n };\n } catch (cause) {\n if (absent(cause)) return undefined;\n throw cause;\n }\n },\n writeFileAtomic: writeAtomic,\n };\n};\n",
|
|
23
25
|
"/**\n * User and group lookups, as argv plus a parser — split out so the parsing is tested against the\n * real output shapes without running anything.\n *\n * ★ macOS FIRST, getent ELSEWHERE. macOS has no `getent`; its directory service answers through\n * `dscacheutil`. Shape MEASURED 2026-09-21 on macOS 27.2 (read-only query):\n *\n * name: someone\n * password: ********\n * uid: 501\n * gid: 20\n * dir: /Users/someone\n * shell: /bin/zsh\n *\n * An unknown uid printed NOTHING and exited 0 — so \"no record\" is an empty parse, never an\n * exit code. `getent` exits 2 for an unknown key; that also parses as no record.\n * ⛔ NEVER PARSE OR KEEP THE `password:` LINE. It is a placeholder on macOS, but a parser that\n * copies every field would carry a hash from any host where it is not.\n */\nimport type { HostUser } from './runner.ts';\n\nconst NUMERIC = /^\\d+$/;\n\n/** argv for looking up a user, by name or numeric id. */\nexport const userQuery = (platform: string, nameOrId: string): readonly string[] =>\n platform === 'darwin'\n ? [\n '/usr/bin/dscacheutil',\n '-q',\n 'user',\n '-a',\n NUMERIC.test(nameOrId) ? 'uid' : 'name',\n nameOrId,\n ]\n : ['getent', 'passwd', nameOrId];\n\n/** argv for looking up a group, by name or numeric id. */\nexport const groupQuery = (platform: string, nameOrId: string): readonly string[] =>\n platform === 'darwin'\n ? [\n '/usr/bin/dscacheutil',\n '-q',\n 'group',\n '-a',\n NUMERIC.test(nameOrId) ? 'gid' : 'name',\n nameOrId,\n ]\n : ['getent', 'group', nameOrId];\n\n/** The first `key: value` record in dscacheutil output, minus any password field. */\nconst firstRecord = (stdout: string): Map<string, string> => {\n const fields = new Map<string, string>();\n for (const line of stdout.split('\\n')) {\n if (line.trim() === '') {\n if (fields.size > 0) break; // ⚠️ records are blank-line separated; keep the first only\n continue;\n }\n const at = line.indexOf(': ');\n if (at <= 0) continue;\n const key = line.slice(0, at);\n if (key === 'password') continue;\n fields.set(key, line.slice(at + 2).trim());\n }\n return fields;\n};\n\nconst toId = (text: string | undefined): number | undefined =>\n text !== undefined && NUMERIC.test(text) ? Number(text) : undefined;\n\nexport const parseUser = (platform: string, stdout: string): HostUser | undefined => {\n if (platform === 'darwin') {\n const record = firstRecord(stdout);\n const uid = toId(record.get('uid'));\n const gid = toId(record.get('gid'));\n const home = record.get('dir');\n return uid === undefined || gid === undefined || home === undefined\n ? undefined\n : { gid, home, uid };\n }\n // getent passwd: name:x:uid:gid:gecos:home:shell\n const fields = (stdout.split('\\n')[0] ?? '').split(':');\n const uid = toId(fields[2]);\n const gid = toId(fields[3]);\n const home = fields[5];\n return uid === undefined || gid === undefined || home === undefined || home === ''\n ? undefined\n : { gid, home, uid };\n};\n\nexport const parseGroup = (platform: string, stdout: string): number | undefined => {\n if (platform === 'darwin') return toId(firstRecord(stdout).get('gid'));\n // getent group: name:x:gid:members\n return toId((stdout.split('\\n')[0] ?? '').split(':')[2]);\n};\n",
|
|
24
26
|
"/**\n * Both launchd-subpath providers with one HostRunner, as a single layer for a host stack.\n *\n * Layer.mergeAll(launchdProviders(), …the stack's other providers)\n *\n * ★ ONE RUNNER FOR BOTH, so a daemon's config file (HostFile) and the daemon (LaunchdJob) are\n * written by the same identity on the same host — a stack cannot write the file as one user and\n * bootstrap the job as another by accident.\n * ⚠️ The default is localRunner(): this process, never elevated. A system-domain job therefore\n * needs the deploy itself started as root, or a runner passed here with `privileged: true` —\n * `launchdProviders(sudoRunner({ prefixes }))` is the kit's own (sudo-runner.ts).\n */\nimport * as Layer from 'effect/Layer';\nimport { HostFileProvider } from './host-file.ts';\nimport { LaunchdJobProvider } from './job.ts';\nimport { localRunner } from './local-runner.ts';\nimport { type HostRunner, hostRunnerLayer } from './runner.ts';\n\nexport const launchdProviders = (runner: HostRunner = localRunner()) =>\n Layer.mergeAll(LaunchdJobProvider(), HostFileProvider()).pipe(\n Layer.provide(hostRunnerLayer(runner)),\n );\n",
|
|
25
27
|
"/**\n * Everything sudo-runner.ts may run as root, as exact argv shapes, plus the rule for which calls\n * need root at all. Pure: no I/O, so every shape is tested without sudo (sudo-allowlist.test.ts).\n *\n * ⛔ AN ALLOWLIST OF SHAPES, NOT OF PROGRAMS. Allowing \"launchctl\" would allow `bootout system` with\n * no service, which removes the whole system domain, and `bootstrap system <directory>`, which\n * loads every plist in that directory (launchctl(1), read on macOS 27.2 on 2026-09-21). Each shape\n * below fixes the subcommand, the domain, the flags and the number of operands, so neither of\n * those can be written.\n * ⛔ PATHS ARE CHECKED LEXICALLY HERE: absolute, normalised (the same rule a HostFile path obeys,\n * host-file-form.ts) and STRICTLY under a prefix the stack declared. sudo-guard.ts then checks\n * the host with lstat: the prefix a root-only directory, no symlinks, and only regular files.\n * ⛔ `install` COPIES ONLY THE FILE THIS RUNNER STAGED. Any other source would let the runner copy\n * a file only root can read (/etc/master.passwd, say) to a path the deploying user can read.\n */\nimport { pathProblems } from './host-file-form.ts';\nimport { plistPathFor } from './job-form.ts';\nimport { LABEL, RESERVED_LABEL_PREFIXES } from './job-validate.ts';\nimport { LAUNCHCTL } from './launchctl.ts';\n\n/**\n * A privileged call that was refused before it ran: by the allowlist, by a host check\n * (sudo-guard.ts), or by sudo itself. ★ Here, beside the allowlist, so the guard and the runner\n * throw the same class and a caller can tell \"nothing ran as root\" from \"it ran and failed\".\n */\nexport class SudoRefusedError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'SudoRefusedError';\n }\n}\n\n/** ★ Absolute program paths, so neither sudo nor the command is looked up on the caller's PATH. */\nexport const SUDO = '/usr/bin/sudo';\nexport const INSTALL = '/usr/bin/install';\nexport const RM = '/bin/rm';\n\n/** The launchctl subcommands that change a domain. Everything else launchctl does is a read. */\nconst WRITES: ReadonlySet<string> = new Set(['bootstrap', 'bootout', 'kickstart']);\n\n/** A mode as `install -m` takes it: four octal digits, so `0644` and `4755` are both exact. */\nexport const octalMode = (mode: number): string | undefined =>\n Number.isSafeInteger(mode) && mode >= 0 && mode <= 0o7777\n ? mode.toString(8).padStart(4, '0')\n : undefined;\n\n/** Validate the stack's prefixes once, when the runner is built. */\nexport const checkPrefixes = (prefixes: readonly string[]): readonly string[] => {\n if (prefixes.length === 0) {\n throw new Error(\n 'sudoRunner: no prefixes. Name the directories root may write, e.g. /Library/LaunchDaemons.',\n );\n }\n for (const prefix of prefixes) {\n const found = prefix === '/' ? ['\"/\" would allow every path'] : pathProblems(prefix);\n if (found.length > 0) {\n throw new Error(`sudoRunner: prefix ${JSON.stringify(prefix)}: ${found.join('; ')}`);\n }\n }\n return [...prefixes];\n};\n\n/**\n * The declared prefix `path` is strictly under, or `undefined`.\n * ⚠️ `${prefix}/`, never a bare startsWith: `/opt/example` must not admit `/opt/example-other`.\n */\nexport const prefixOf = (path: string, prefixes: readonly string[]): string | undefined =>\n pathProblems(path).length > 0\n ? undefined\n : prefixes.find((prefix) => path.startsWith(`${prefix}/`));\n\nconst labelOk = (label: string): boolean =>\n LABEL.test(label) && !RESERVED_LABEL_PREFIXES.some((prefix) => label.startsWith(prefix));\n\n/** The label of `system/<label>`, when it is one LaunchdJob itself would accept. */\nconst systemLabel = (target: string | undefined): string | undefined => {\n const label = target?.startsWith('system/') === true ? target.slice('system/'.length) : undefined;\n return label !== undefined && labelOk(label) ? label : undefined;\n};\n\n/**\n * A label's daemon plist, when that path is under a declared prefix.\n * ★ ONLY `/Library/LaunchDaemons/<label>.plist`, derived by the same plistPathFor LaunchdJob uses:\n * it is the one directory launchd loads daemons from at boot, so a plist anywhere else under a\n * prefix would be a root daemon that silently vanishes at the next restart. Root never loads one.\n */\nconst daemonPlist = (label: string, prefixes: readonly string[]): string | undefined => {\n const path = plistPathFor(label, { kind: 'system' }, undefined);\n return prefixOf(path, prefixes) === undefined ? undefined : path;\n};\n\nconst NO_DAEMON_PREFIX =\n 'needs /Library/LaunchDaemons among the prefixes, where the job’s plist is written and removed';\n\nconst launchctlProblem = (\n args: readonly string[],\n prefixes: readonly string[],\n): string | undefined => {\n const [sub, ...rest] = args;\n if (sub === 'bootstrap') {\n const given = rest[1] ?? '';\n const name = given.slice(given.lastIndexOf('/') + 1);\n const label = name.endsWith('.plist') ? name.slice(0, -'.plist'.length) : '';\n const shaped = rest.length === 2 && rest[0] === 'system' && labelOk(label);\n if (!shaped) return 'bootstrap takes exactly `system /Library/LaunchDaemons/<label>.plist`';\n const plist = daemonPlist(label, prefixes);\n if (plist === undefined) return `bootstrap ${NO_DAEMON_PREFIX}`;\n return given === plist ? undefined : `bootstrap loads only ${plist}, never another path`;\n }\n if (sub === 'bootout') {\n const label = rest.length === 1 ? systemLabel(rest[0]) : undefined;\n if (label === undefined) return 'bootout takes exactly `system/<label>`, never a bare domain';\n /**\n * ⚠️ WITHOUT THE PREFIX, A DELETE STOPS HALFWAY. deleteJob boots the job out, then removes its\n * plist; with /Library/LaunchDaemons undeclared the removal is refused AFTER the bootout, the\n * plist stays, and launchd loads the job again at the next boot. Refused here, nothing moves.\n */\n return daemonPlist(label, prefixes) === undefined ? `bootout ${NO_DAEMON_PREFIX}` : undefined;\n }\n if (sub === 'kickstart') {\n const flags = rest.slice(0, -1);\n const flagsOk =\n flags.every((flag) => flag === '-k' || flag === '-p') && new Set(flags).size === flags.length;\n return flagsOk && systemLabel(rest[rest.length - 1]) !== undefined\n ? undefined\n : 'kickstart takes only -k / -p, then `system/<label>`';\n }\n return `launchctl ${String(sub)} is never run as root`;\n};\n\nconst ID = /^\\d+$/;\n\n/** `install`'s optional owner flags: none, `-o N`, `-g N`, or `-o N -g N`. Numeric ids only. */\nconst idsOk = (ids: readonly string[]): boolean => {\n const [flag, id, second, secondId] = ids;\n if (ids.length === 0) return true;\n if (ids.length === 2) return (flag === '-o' || flag === '-g') && ID.test(id ?? '');\n return (\n ids.length === 4 &&\n flag === '-o' &&\n ID.test(id ?? '') &&\n second === '-g' &&\n ID.test(secondId ?? '')\n );\n};\n\n/** The one source `install` may copy and the prefixes, for the call being checked. */\nexport type AllowContext = { readonly prefixes: readonly string[]; readonly staged?: string };\n\n/** `undefined` when `argv` is exactly an allowed privileged shape, else the reason it is not. */\nexport const privilegedProblem = (\n argv: readonly string[],\n context: AllowContext,\n): string | undefined => {\n const [program, ...args] = argv;\n const under = (path: string | undefined) =>\n path !== undefined && prefixOf(path, context.prefixes) !== undefined;\n if (program === LAUNCHCTL) return launchctlProblem(args, context.prefixes);\n if (program === INSTALL) {\n // -S -m MODE [-o UID] [-g GID] STAGED DEST: nothing else, in this order.\n const [safe, m, mode, ...rest] = args;\n if (safe !== '-S' || m !== '-m' || mode === undefined || !/^[0-7]{4}$/.test(mode)) {\n return 'install takes exactly `-S -m <4 octal digits> [-o <uid>] [-g <gid>] <staged> <dest>`';\n }\n if (rest.length < 2 || !idsOk(rest.slice(0, -2))) return 'install takes only -o <uid> -g <gid>';\n const [source, dest] = rest.slice(-2);\n if (source === undefined || source !== context.staged) {\n return 'install copies only the file this runner staged';\n }\n return under(dest) ? undefined : 'install destination is not under a declared prefix';\n }\n if (program === RM) {\n const [force, end, path, ...extra] = args;\n return force === '-f' && end === '--' && extra.length === 0 && under(path)\n ? undefined\n : 'rm takes exactly `-f -- <path under a declared prefix>`';\n }\n return `${String(program)} is not on the sudo allowlist`;\n};\n\n/** Where one exec goes: run as the deploying user, run as root through the allowlist, or refused. */\nexport type Route =\n | { readonly as: 'operator' }\n | { readonly as: 'root' }\n | { readonly refuse: string };\n\n/**\n * ★ WHY THIS REFUSES AS WELL AS ROUTES. sudoRunner reports `privileged: true`, which switches off\n * the providers' own \"another user's gui domain needs root\" refusal (job-preflight.ts). This\n * runner elevates only the system domain, so it gives that refusal back itself. (A write into\n * another user's LaunchAgents is refused by the writer first: outside every prefix, a foreign\n * owner needs root. This covers the delete, which reaches launchctl before any file.)\n * ⚠️ Reads (`print`, `print-disabled`) always run as the deploying user: launchctl(1) says anyone\n * may read or query the system domain, and launchctl.ts measured it on 2026-09-21.\n */\nexport const routeExec = (argv: readonly string[], operatorUid: number): Route => {\n const [program, sub] = argv;\n if (program === 'sudo' || program?.endsWith('/sudo') === true) {\n return {\n refuse: 'sudoRunner never passes a sudo argv through; it elevates only its allowlist',\n };\n }\n if (program !== LAUNCHCTL || sub === undefined || !WRITES.has(sub)) return { as: 'operator' };\n const target = sub === 'kickstart' ? argv[argv.length - 1] : argv[2];\n if (target === 'system' || target?.startsWith('system/') === true) return { as: 'root' };\n const owner = /^(?:gui|user)\\/(\\d+)(?:\\/|$)/.exec(target ?? '')?.[1];\n if (owner === undefined || Number(owner) === operatorUid) return { as: 'operator' };\n return {\n refuse:\n `launchctl ${sub} ${String(target)}: that domain belongs to uid ${owner}, and sudoRunner ` +\n 'elevates only the system domain. Deploy as that user, or as root.',\n };\n};\n",
|
|
@@ -27,9 +29,9 @@
|
|
|
27
29
|
"/**\n * The checks sudo-runner.ts makes against the host, as the deploying user, before it runs anything\n * as root. sudo-allowlist.ts checks the argv; this checks what the paths in it actually are.\n *\n * ⛔ WHAT IS LOGGED IS WHAT IS WRITTEN. A symlinked directory under a prefix would make\n * `install` or `rm`, running as root, act on a path the log never named. So every directory\n * between the prefix and the file must be a real directory.\n * ⛔ EVERY DIRECTORY FROM THE PREFIX DOWN IS ROOT'S ALONE (decided 2026-09-21). A directory below\n * the prefix that another user owns, or that group or other may write, lets that user swap what\n * lies under it — a symlink where the file was — between these checks and the privileged call.\n * So each one must be owned by root and not group/other-writable (rootOnlyProblem), exactly as\n * the prefix itself must.\n * ⛔ AND EVERY DIRECTORY ABOVE THE PREFIX (red team, 2026-09-21). Whoever may write the prefix's\n * parent may rename the prefix away and put a symlink in its place between these checks and the\n * privileged call — the same swap one level up. So `/` down to the prefix's parent must be\n * root-only too (a root-owned symlink among them, `/etc` -> `private/etc`, is root's own and is\n * followed; its target is root's choice, and not walked).\n * ⛔ AND NO ACL THAT SAYS OTHERWISE (sudo-acl.ts): mode bits are not the whole answer on macOS.\n * ⚠️ These checks run before the privileged call, as the deploying user. They guard against a\n * mistaken declaration and against every user but root; root itself could still change a path\n * in that window.\n */\nimport type { FileStat, HostRunner, WriteOptions } from './runner.ts';\nimport { assertNoAclGrants } from './sudo-acl.ts';\nimport { SudoRefusedError } from './sudo-allowlist.ts';\n\nconst refuse = (path: string, message: string): Error =>\n new SudoRefusedError(`sudoRunner ${path}: ${message}`);\n\n/** The directories strictly between `prefix` and the file at `path`. */\nexport const betweenDirs = (prefix: string, path: string): string[] => {\n const parts = path\n .slice(prefix.length + 1)\n .split('/')\n .slice(0, -1);\n return parts.map((_, index) => `${prefix}/${parts.slice(0, index + 1).join('/')}`);\n};\n\n/** The directories strictly above `prefix`: `/`, then each one down to the prefix's parent. */\nexport const aboveDirs = (prefix: string): string[] => {\n const parts = prefix.split('/').slice(1, -1);\n return ['/', ...parts.map((_, index) => `/${parts.slice(0, index + 1).join('/')}`)];\n};\n\n/**\n * What must be at `path` itself: a regular file, or (for a write or a remove) nothing yet.\n * ⚠️ A DIRECTORY AT THE DESTINATION IS THE TRAP: `install src dir` copies INTO the directory\n * (install(1)), and install decides that with stat, so a symlink to a directory does the same.\n */\nexport type Expect = 'file' | 'file-or-absent';\n\n/**\n * ⛔ THE PREFIX, AND EVERY DIRECTORY BELOW IT ON THE WAY TO THE FILE, MUST BE A DIRECTORY ONLY ROOT\n * CAN CHANGE, checked at every call rather than trusted from the declaration. A symlinked prefix makes root write wherever it points, which the\n * log never names (`/opt/example` -> `/etc` turns a HostFile at `/opt/example/sudoers` into\n * `/etc/sudoers`). A prefix another user owns or may write lets that user swap a directory below\n * it for a symlink between this check and the privileged call.\n * ⚠️ lstat of the prefix itself: a symlink ABOVE it (`/etc` -> `/private/etc` on macOS) is the\n * system's and is followed, as every path lookup does — when root owns it (aboveDirs).\n * ★ MEASURED 2026-09-21 on macOS 27.2 (`ls -ldn`): /Library/LaunchDaemons, /private/etc, /opt and\n * /usr/local are uid 0, mode 0755, so the prefixes a host stack declares pass as they are.\n */\nconst rootOnlyProblem = (stat: FileStat | undefined): string | undefined => {\n if (stat === undefined) return 'is missing';\n if (stat.kind !== 'directory') return `is a ${stat.kind}, not a directory`;\n if (stat.uid !== 0) return `is owned by uid ${String(stat.uid)}, not root`;\n if ((stat.mode & 0o022) !== 0) {\n return `is writable by group or other (mode ${stat.mode.toString(8).padStart(4, '0')})`;\n }\n return undefined;\n};\n\n/**\n * Refuse a prefix that is not a root-only directory, a symlink or a non-directory between the\n * prefix and `path`, and anything but a file at it.\n */\nexport const assertPlainPath = async (\n base: HostRunner,\n prefix: string,\n path: string,\n expect: Expect,\n): Promise<'file' | 'absent'> => {\n const above = aboveDirs(prefix);\n for (const [index, stat] of (await Promise.all(above.map((dir) => base.stat(dir)))).entries()) {\n const up = stat?.kind === 'symlink' && stat.uid === 0 ? undefined : rootOnlyProblem(stat);\n if (up !== undefined) {\n throw refuse(\n path,\n `${String(above[index])}, above the declared prefix ${prefix}, ${up}. Whoever may change it ` +\n 'may swap the prefix itself; every directory from / down must be root-only. Nothing ran as root.',\n );\n }\n }\n const dirs = betweenDirs(prefix, path);\n const [prefixStat, ...stats] = await Promise.all([prefix, ...dirs].map((dir) => base.stat(dir)));\n const bad = rootOnlyProblem(prefixStat);\n if (bad !== undefined) {\n throw refuse(\n path,\n `the declared prefix ${prefix} ${bad}. Declare only a real directory that root owns and ` +\n 'only root may write. Nothing ran as root.',\n );\n }\n for (const [index, stat] of stats.entries()) {\n const dir = String(dirs[index]);\n if (stat?.kind !== 'directory') {\n throw refuse(\n path,\n `${dir} is ${stat === undefined ? 'missing' : `a ${stat.kind}`}; root ` +\n 'writes only through real directories under a declared prefix.',\n );\n }\n const below = rootOnlyProblem(stat);\n if (below !== undefined) {\n throw refuse(\n path,\n `${dir} ${below}. Every directory from the prefix ${prefix} down to the file must be one ` +\n 'that root owns and only root may write. Nothing ran as root.',\n );\n }\n }\n await assertNoAclGrants(base, path, [...above, prefix, ...dirs]);\n const target = await base.stat(path);\n if (target === undefined && expect === 'file-or-absent') return 'absent';\n if (target?.kind === 'file') return 'file';\n throw refuse(path, `is ${target === undefined ? 'missing' : `a ${target.kind}`}, not a file`);\n};\n\n/**\n * ⛔ A ROOT-OWNED FILE UNDER A PREFIX IS ROOT'S TO CHANGE, AND ONLY ROOT'S (decided 2026-09-21).\n * Group- or world-writable, anyone in that class rewrites a file root installed — a daemon's\n * config, a script a LaunchDaemon runs as root — which is root by another name. Setuid or setgid,\n * it runs as root (or its group) for whoever executes it. install(1) would apply either, as root.\n * ★ Root-owned is an omitted owner (the runner installs as root under a prefix) or uid 0. A file\n * handed to another user is that user's to change; the sticky bit changes nothing on a file.\n */\nexport const modeProblem = (options: WriteOptions): string | undefined => {\n if (options.uid !== undefined && options.uid !== 0) return undefined;\n const found: string[] = [];\n if ((options.mode & 0o6000) !== 0) found.push('setuid/setgid');\n if ((options.mode & 0o022) !== 0) found.push('writable by group or other');\n if (found.length === 0) return undefined;\n return `mode ${options.mode.toString(8).padStart(4, '0')} is ${found.join(' and ')} on a root-owned file`;\n};\n\n/**\n * Every check a write under `prefix` meets before anything is staged or run as root: the mode, the\n * path (assertPlainPath) and the read-back (assertReadableBack). ★ Reads only, as the deploying\n * user — so sudoRunner's `checkWrite` runs it at PLAN time too, and a plan still never calls sudo.\n */\nexport const assertInstallable = async (\n base: HostRunner,\n prefix: string,\n path: string,\n options: WriteOptions,\n groups: readonly number[] | undefined,\n): Promise<void> => {\n const mode = modeProblem(options);\n if (mode !== undefined) {\n throw refuse(\n path,\n `${mode}. Declare a mode without those bits (0644, 0640, 0755), or give the file to its ` +\n 'real owner. Nothing ran as root.',\n );\n }\n await assertPlainPath(base, prefix, path, 'file-or-absent');\n await assertReadableBack(base, path, options, groups);\n};\n\n/**\n * POSIX read permission for one uid: owner class, else group class, else other. `undefined` when\n * only group membership could decide and the groups are unknown.\n * ⚠️ EXACTLY ONE CLASS APPLIES. A group member gets the group bits even when the other bits are\n * wider (`0604` hides a file from its group), so \"other can read\" is not enough on its own.\n */\nexport const canRead = (\n file: { readonly uid: number; readonly gid: number; readonly mode: number },\n uid: number,\n groups: readonly number[] | undefined,\n): boolean | undefined => {\n if (uid === 0) return true;\n if (file.uid === uid) return (file.mode & 0o400) !== 0;\n const groupRead = (file.mode & 0o040) !== 0;\n const otherRead = (file.mode & 0o004) !== 0;\n // Membership cannot change the answer when both classes agree.\n if (groupRead === otherRead) return groupRead;\n if (groups === undefined) return undefined;\n return groups.includes(file.gid) ? groupRead : otherRead;\n};\n\n/**\n * ⛔ REFUSE A FILE THE DEPLOYING USER COULD NOT READ BACK, before writing it. Both providers read\n * every write back to verify it (host-file-lifecycle.ts, job-lifecycle.ts) and read it again at\n * every plan, as the deploying user; this runner elevates writes, never reads. A root-only\n * `0600` would be installed, then fail the read-back with EACCES and stay on disk with no state,\n * so every later plan would fail too.\n * ★ An omitted owner is root (under a prefix the runner writes as root). An omitted group is the\n * parent directory's, which is the group a new file gets on macOS.\n * ⚠️ Unknown groups never refuse: the read-back after the write stays the final judge.\n */\nexport const assertReadableBack = async (\n base: HostRunner,\n path: string,\n options: WriteOptions,\n groups: readonly number[] | undefined,\n): Promise<void> => {\n const operator = base.effectiveUid();\n const parent = path.slice(0, path.lastIndexOf('/')) || '/';\n const gid = options.gid ?? (await base.stat(parent))?.gid ?? 0;\n const file = { gid, mode: options.mode, uid: options.uid ?? 0 };\n if (canRead(file, operator, groups) !== false) return;\n throw refuse(\n path,\n `owner ${String(file.uid)}, group ${String(gid)}, mode ${file.mode.toString(8)} would hide it ` +\n `from the deploying user (uid ${String(operator)}), who reads every file back. Declare a ` +\n 'mode that user can read, or deploy as root. Nothing was written.',\n );\n};\n\n/**\n * The deploying user's groups, from `id -G`; `undefined` when that fails.\n * ⚠️ NOT process.getgroups(). MEASURED 2026-09-21 on macOS 27.2: getgroups() returned 16 groups\n * where `id -G` returned 18, because macOS caps a process's own list at 16. A group past the\n * 16th would read as \"not a member\" and refuse a file the user can in fact read.\n */\nexport const operatorGroups = async (base: HostRunner): Promise<readonly number[] | undefined> => {\n const result = await base.exec(['/usr/bin/id', '-G']);\n const ids = result.stdout.trim().split(/\\s+/);\n return result.exitCode === 0 && ids.every((id) => /^\\d+$/.test(id)) ? ids.map(Number) : undefined;\n};\n",
|
|
28
30
|
"/**\n * What sudo's own failure means, for sudo-runner.ts: which exit-1 answers are sudo refusing to run\n * the command (so NOTHING ran as root), and what an EACCES outside every prefix most likely means.\n * Split out of sudo-runner.ts, which keeps only the runner.\n *\n * ⚠️ REASONED, NOT MEASURED: sudo's failure text. The kit never runs sudo. The strings below follow\n * sudoers(5) for sudo 1.9.17p2 on macOS 27.2 (\"a password is required\": -n was given but a\n * password was needed) and sudo(8) (sudo exits 1 when it fails itself).\n */\nimport { errnoCode } from './local-runner.ts';\nimport type { ExecResult } from './runner.ts';\nimport { SudoRefusedError } from './sudo-allowlist.ts';\n\n/**\n * ⚠️ ANCHORED TO sudo'S OWN MESSAGE FORMS (`sudo: …` lines, `Sorry, user …`), so a launchctl or\n * install error that happens to say \"not allowed\" is never reported as \"the command did not run\".\n * The refusals are the three a sudoers denial prints: the command not allowed, the user not in\n * sudoers, and the user not allowed on this host (`<user> is not allowed to run sudo on <host>.`).\n * REASONED from sudo 1.9's sudoers plugin, like the rest (header).\n */\nconst PASSWORD =\n /^sudo: (?:a password is required|a terminal is required|sorry, you must have a tty)/m;\nconst NOT_ALLOWED =\n /^(?:Sorry, user \\S+ (?:is not allowed to execute|may not run sudo)|\\S+ is not (?:in the sudoers file|allowed to run sudo on ))/m;\n\n/** ★ An EACCES outside every prefix is almost always a directory the stack forgot to declare. */\nexport const undeclared =\n (path: string, prefixes: readonly string[]) =>\n (cause: unknown): never => {\n const code = errnoCode(cause);\n if (code !== 'EACCES' && code !== 'EPERM') throw cause;\n throw new Error(\n `sudoRunner ${path}: ${code} as the deploying user, and the path is under no declared prefix ` +\n `(${prefixes.join(', ')}). If root owns its directory, declare that directory as a prefix.`,\n { cause },\n );\n };\n\n/**\n * The refusal sudo itself answered for `shown` (the argv as JSON), or `undefined` when the command\n * ran — whatever its own exit code. ★ `SudoRefusedError` always means nothing ran as root.\n */\nexport const sudoRefusal = (shown: string, result: ExecResult): SudoRefusedError | undefined => {\n if (result.exitCode !== 1) return undefined;\n if (PASSWORD.test(result.stderr)) {\n return new SudoRefusedError(\n `sudo -n ${shown}: a password is required, and this runner never prompts. Run \\`sudo -v\\` ` +\n 'in the deploying terminal just before the deploy, or grant exactly these commands ' +\n 'NOPASSWD (docs/launchd-sudo.md). The command did not run.',\n );\n }\n if (NOT_ALLOWED.test(result.stderr)) {\n return new SudoRefusedError(\n `sudo -n ${shown}: sudoers does not let the deploying user run this. The command did not run.`,\n );\n }\n return undefined;\n};\n",
|
|
29
31
|
"/**\n * Where sudo-runner.ts puts a file's bytes before `install` copies them into place as root.\n *\n * ★ WHY STAGE AT ALL. The deploying user cannot write inside a root-owned directory, and the bytes\n * must not travel through argv (they would reach the log and `ps`). So they are written, as the\n * deploying user, to a private file, and `install` copies that one file.\n * ⛔ A 0700 DIRECTORY, A 0600 FILE, O_EXCL: between the write and the install, nobody but the\n * deploying user and root can read the bytes or swap the file.\n */\nimport { mkdtemp, rm, writeFile } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\n\n/** A file staged for `install`, and how to remove it again. */\nexport type Staged = { readonly path: string; readonly dispose: () => Promise<void> };\n\nexport const stageFile = async (bytes: Uint8Array): Promise<Staged> => {\n const dir = await mkdtemp(join(tmpdir(), 'hf-sudo-'));\n const dispose = () => rm(dir, { force: true, recursive: true });\n try {\n const path = join(dir, 'staged');\n await writeFile(path, bytes, { flag: 'wx', mode: 0o600 });\n return { dispose, path };\n } catch (cause) {\n await dispose();\n throw cause;\n }\n};\n",
|
|
30
|
-
"/**\n * sudoRunner(): the kit's one elevating HostRunner. The deploy runs as the operator, and only the\n * calls that need root go through `sudo -n`, in the exact shapes sudo-allowlist.ts names:\n *\n * - `launchctl bootstrap | bootout | kickstart` in the system domain;\n * - a file under a prefix the stack declared: staged in a private temp file as the operator, then\n * `sudo -n install -S -m <mode> [-o <uid>] [-g <gid>] <staged> <path>`; removed with\n * `sudo -n rm -f -- <path>`.\n *\n * Everything else (reads, lookups, the operator's own files and gui domain) goes to localRunner().\n *\n * ★ DECIDED 2026-09-21. A host stack deploys as the operator rather than as root, so a provider bug\n * or a wrong declaration can do no more than this list. It is an explicit opt-in,\n * `launchdProviders(sudoRunner({ prefixes }))`, and nothing ever falls back to it: localRunner()\n * stays the default and never elevates.\n * ⛔ `sudo -n`, NEVER A PROMPT. A deploy that stops mid-apply to ask for a password is the failure\n * \"no silent sudo\" exists to prevent. With -n, sudo fails at once, and that failure becomes an\n * error saying what to do.\n * ⛔ EVERY PRIVILEGED ARGV IS LOGGED BEFORE IT RUNS, and it is only ever an argv: a file's bytes\n * travel through the staged file, never through argv, so a log line cannot carry content.\n * ★ `install -S`: install(1) on macOS 27.2 (read 2026-09-21) always writes a temp file in the\n * target directory and renames it, so the file is never torn, and -S adds the fsync that\n * localRunner's `handle.sync()` does.\n * ⚠️ REASONED, NOT MEASURED: sudo's failure text (sudo-said.ts has the strings and their sources).\n * ⛔ EVERY CHECK BEFORE SUDO ALSO RUNS AT PLAN TIME (`checkWrite`, 2026-09-21): the mode, the\n * directories from the prefix down, the read-back. Reads only, as the operator — never sudo.\n */\nimport { type LocalRunnerOptions, localRunner } from './local-runner.ts';\nimport type { ExecResult, HostRunner, WriteOptions } from './runner.ts';\nimport {\n INSTALL,\n RM,\n SUDO,\n SudoRefusedError,\n checkPrefixes,\n octalMode,\n prefixOf,\n privilegedProblem,\n routeExec,\n} from './sudo-allowlist.ts';\nimport { assertInstallable, assertPlainPath, operatorGroups } from './sudo-guard.ts';\nimport { sudoRefusal, undeclared } from './sudo-said.ts';\nimport { type Staged, stageFile } from './sudo-stage.ts';\n\nexport { SudoRefusedError };\n\nexport type SudoRunnerOptions = LocalRunnerOptions & {\n /**\n * The directories root may install into and remove from: `/Library/LaunchDaemons` for system\n * jobs (bootstrap and bootout are refused without it), plus wherever the stack's root-owned\n * HostFiles live. ⛔ Required: absolute, normalised, never `/`; and at every privileged call a\n * real directory that root owns and only root may write (sudo-guard.ts). Outside every prefix a\n * file is written as the deploying user, or refused when that needs root.\n */\n readonly prefixes: readonly string[];\n /** Receives one line per privileged argv, before it runs. @default a line on stderr */\n readonly log?: (line: string) => void;\n};\n\n/** What a sudo runner is built from. ★ Split out so the tests swap the host, never the logic. */\nexport type SudoDeps = {\n /** Runs everything, including `sudo` itself. localRunner() for the real one. */\n readonly base: HostRunner;\n readonly stage: (bytes: Uint8Array) => Promise<Staged>;\n /** The deploying user's groups, for the read-back check; `undefined` when unknown. */\n readonly groups: () => Promise<readonly number[] | undefined>;\n readonly log: (line: string) => void;\n};\n\nexport const makeSudoRunner = (prefixList: readonly string[], deps: SudoDeps): HostRunner => {\n const prefixes = checkPrefixes(prefixList);\n const { base } = deps;\n\n /**\n * ⛔ THE ONE PLACE `sudo` IS SPAWNED: allowlist, then any host check (`before`), then the log\n * line, then `sudo -n -- argv`.\n */\n const elevate = async (\n argv: readonly string[],\n { before, staged }: { before?: () => Promise<unknown>; staged?: string } = {},\n ): Promise<ExecResult> => {\n const shown = JSON.stringify(argv);\n const problem = privilegedProblem(argv, {\n prefixes,\n ...(staged === undefined ? {} : { staged }),\n });\n if (problem !== undefined)\n throw new SudoRefusedError(`sudoRunner refused ${shown}: ${problem}`);\n await before?.();\n deps.log(`homeflare/launchd sudo -n ${shown}`);\n const result = await base.exec([SUDO, '-n', '--', ...argv]);\n const refused = sudoRefusal(shown, result);\n if (refused !== undefined) throw refused;\n return result;\n };\n\n /**\n * Every refusal a write can meet before sudo is asked — as the deploying user, reading only — so\n * the same checks run at plan time (`checkWrite`) and at the write. `undefined` outside every\n * prefix, where the operator writes; else the prefix and the mode as `install -m` takes it.\n */\n const vetWrite = async (path: string, options: WriteOptions) => {\n const prefix = prefixOf(path, prefixes);\n const operator = base.effectiveUid();\n if (prefix === undefined) {\n if (options.uid !== undefined && options.uid !== operator && operator !== 0) {\n throw new SudoRefusedError(\n `sudoRunner ${path}: owner ${String(options.uid)} needs root, and the path is under no ` +\n `declared prefix (${prefixes.join(', ')}). Declare its directory, or deploy as root. ` +\n 'Nothing was written.',\n );\n }\n return undefined;\n }\n const mode = octalMode(options.mode);\n if (mode === undefined) throw new SudoRefusedError(`sudoRunner ${path}: mode must be 0–0o7777`);\n await assertInstallable(base, prefix, path, options, await deps.groups());\n return { mode, prefix };\n };\n\n /** A privileged file operation: anything but exit 0 is an error. ⚠️ stderr names paths only. */\n const mustSucceed = async (argv: readonly string[], staged?: string): Promise<void> => {\n const result = await elevate(argv, staged === undefined ? {} : { staged });\n if (result.exitCode !== 0) {\n const stderr = result.stderr.trim().slice(0, 300);\n throw new Error(`sudo -n ${JSON.stringify(argv)} -> ${String(result.exitCode)}: ${stderr}`);\n }\n };\n\n return {\n // ★ The plan-time half of vetWrite: the providers' diffs call it, and it never elevates.\n checkWrite: async (path, options) => {\n await vetWrite(path, options);\n },\n effectiveUid: () => base.effectiveUid(),\n exec: async (argv) => {\n const route = routeExec(argv, base.effectiveUid());\n if ('refuse' in route) throw new SudoRefusedError(`sudoRunner: ${route.refuse}`);\n if (route.as === 'operator') return base.exec(argv);\n // ⛔ bootstrap makes root read the plist: it must be a plain file exactly where argv says.\n // The allowlist has already put it under a prefix by the time `before` runs.\n const plist = argv[1] === 'bootstrap' ? argv[3] : undefined;\n const prefix = plist === undefined ? undefined : prefixOf(plist, prefixes);\n return elevate(argv, {\n before: async () => {\n if (plist !== undefined && prefix !== undefined) {\n await assertPlainPath(base, prefix, plist, 'file');\n }\n },\n });\n },\n lookupGroup: (nameOrId) => base.lookupGroup(nameOrId),\n lookupUser: (nameOrId) => base.lookupUser(nameOrId),\n // ★ True, so the providers let a system-domain job through to this runner (canActAsRoot).\n privileged: true,\n readFile: (path) => base.readFile(path),\n removeFile: async (path) => {\n const prefix = prefixOf(path, prefixes);\n if (prefix === undefined) return base.removeFile(path).catch(undeclared(path, prefixes));\n /**\n * ★ Nothing there is success without a privileged call, so an idempotent delete logs nothing.\n * ⚠️ lstat the path FIRST: a directory on the way that is already gone means nothing is there\n * (HostRunner.removeFile is idempotent, and localRunner treats ENOENT/ENOTDIR so), where the\n * guard alone would refuse it as a missing directory.\n */\n if ((await base.stat(path)) === undefined) return;\n await assertPlainPath(base, prefix, path, 'file');\n await mustSucceed([RM, '-f', '--', path]);\n },\n sleep: (ms) => base.sleep(ms),\n stat: (path) => base.stat(path),\n writeFileAtomic: async (path, bytes, options) => {\n const vetted = await vetWrite(path, options);\n if (vetted === undefined) {\n return base.writeFileAtomic(path, bytes, options).catch(undeclared(path, prefixes));\n }\n const { mode } = vetted;\n const staged = await deps.stage(bytes);\n try {\n await mustSucceed(\n [\n INSTALL,\n '-S',\n '-m',\n mode,\n ...(options.uid === undefined ? [] : ['-o', String(options.uid)]),\n ...(options.gid === undefined ? [] : ['-g', String(options.gid)]),\n staged.path,\n path,\n ],\n staged.path,\n );\n } finally {\n await staged.dispose();\n }\n },\n };\n};\n\n/**\n * The real sudo runner: localRunner() for everything, `/usr/bin/sudo -n` for the allowlist.\n * Pass it explicitly: `launchdProviders(sudoRunner({ prefixes: ['/Library/LaunchDaemons'] }))`.\n */\nexport const sudoRunner = (options: SudoRunnerOptions): HostRunner => {\n const base = localRunner(options);\n return makeSudoRunner(options.prefixes, {\n base,\n groups: () => operatorGroups(base),\n log:\n options.log ??\n ((line) => {\n process.stderr.write(`${line}\\n`);\n }),\n stage: stageFile,\n });\n};\n"
|
|
32
|
+
"/**\n * sudoRunner(): the kit's one elevating HostRunner. The deploy runs as the operator, and only the\n * calls that need root go through `sudo -n`, in the exact shapes sudo-allowlist.ts names:\n *\n * - `launchctl bootstrap | bootout | kickstart` in the system domain;\n * - a file under a prefix the stack declared: staged in a private temp file as the operator, then\n * `sudo -n install -S -m <mode> [-o <uid>] [-g <gid>] <staged> <path>`; removed with\n * `sudo -n rm -f -- <path>`.\n *\n * Everything else (reads, lookups, the operator's own files and gui domain) goes to localRunner().\n *\n * ★ DECIDED 2026-09-21. A host stack deploys as the operator rather than as root, so a provider bug\n * or a wrong declaration can do no more than this list. It is an explicit opt-in,\n * `launchdProviders(sudoRunner({ prefixes }))`, and nothing ever falls back to it: localRunner()\n * stays the default and never elevates.\n * ⛔ `sudo -n`, NEVER A PROMPT. A deploy that stops mid-apply to ask for a password is the failure\n * \"no silent sudo\" exists to prevent. With -n, sudo fails at once, and that failure becomes an\n * error saying what to do.\n * ⛔ EVERY PRIVILEGED ARGV IS LOGGED BEFORE IT RUNS, and it is only ever an argv: a file's bytes\n * travel through the staged file, never through argv, so a log line cannot carry content.\n * ★ `install -S`: install(1) on macOS 27.2 (read 2026-09-21) always writes a temp file in the\n * target directory and renames it, so the file is never torn, and -S adds the fsync that\n * localRunner's `handle.sync()` does.\n * ⚠️ BUT IT CHMODS AFTER THE RENAME. MEASURED 2026-09-22 (an lstat poller racing\n * `/usr/bin/install -S -m 0755`, 300 MB, six runs, target absent and present): the new inode\n * is visible at the path as 0600, then 0755 0.2–0.4 ms later. Only ever narrower than declared.\n * ⚠️ REASONED NOT MEASURED: a launchd start inside that window gets EACCES and retries after its\n * throttle, and an install killed inside it leaves a root-owned 0600 file the operator cannot\n * read back. Closing it needs a second privileged step (install to a temp name, then rename),\n * which is a change to this allowlist and wants its own red team.\n * ⚠️ AND IT COPIES XATTRS, com.apple.quarantine included (MEASURED 2026-09-22: a quarantined\n * source installed as a quarantined target). The staged file is written by this process, and\n * node:fs writes here carried only com.apple.provenance (measured the same day) — so nothing\n * is quarantined today, but a quarantined staging file would be installed quarantined.\n * ⚠️ REASONED, NOT MEASURED: sudo's failure text (sudo-said.ts has the strings and their sources).\n * ⛔ EVERY CHECK BEFORE SUDO ALSO RUNS AT PLAN TIME (`checkWrite`, 2026-09-21): the mode, the\n * directories from the prefix down, the read-back. Reads only, as the operator — never sudo.\n */\nimport { type LocalRunnerOptions, localRunner } from './local-runner.ts';\nimport type { ExecResult, HostRunner, WriteOptions } from './runner.ts';\nimport {\n INSTALL,\n RM,\n SUDO,\n SudoRefusedError,\n checkPrefixes,\n octalMode,\n prefixOf,\n privilegedProblem,\n routeExec,\n} from './sudo-allowlist.ts';\nimport { assertInstallable, assertPlainPath, operatorGroups } from './sudo-guard.ts';\nimport { sudoRefusal, undeclared } from './sudo-said.ts';\nimport { type Staged, stageFile } from './sudo-stage.ts';\n\nexport { SudoRefusedError };\n\nexport type SudoRunnerOptions = LocalRunnerOptions & {\n /**\n * The directories root may install into and remove from: `/Library/LaunchDaemons` for system\n * jobs (bootstrap and bootout are refused without it), plus wherever the stack's root-owned\n * HostFiles live. ⛔ Required: absolute, normalised, never `/`; and at every privileged call a\n * real directory that root owns and only root may write (sudo-guard.ts). Outside every prefix a\n * file is written as the deploying user, or refused when that needs root.\n */\n readonly prefixes: readonly string[];\n /** Receives one line per privileged argv, before it runs. @default a line on stderr */\n readonly log?: (line: string) => void;\n};\n\n/** What a sudo runner is built from. ★ Split out so the tests swap the host, never the logic. */\nexport type SudoDeps = {\n /** Runs everything, including `sudo` itself. localRunner() for the real one. */\n readonly base: HostRunner;\n readonly stage: (bytes: Uint8Array) => Promise<Staged>;\n /** The deploying user's groups, for the read-back check; `undefined` when unknown. */\n readonly groups: () => Promise<readonly number[] | undefined>;\n readonly log: (line: string) => void;\n};\n\nexport const makeSudoRunner = (prefixList: readonly string[], deps: SudoDeps): HostRunner => {\n const prefixes = checkPrefixes(prefixList);\n const { base } = deps;\n\n /**\n * ⛔ THE ONE PLACE `sudo` IS SPAWNED: allowlist, then any host check (`before`), then the log\n * line, then `sudo -n -- argv`.\n */\n const elevate = async (\n argv: readonly string[],\n { before, staged }: { before?: () => Promise<unknown>; staged?: string } = {},\n ): Promise<ExecResult> => {\n const shown = JSON.stringify(argv);\n const problem = privilegedProblem(argv, {\n prefixes,\n ...(staged === undefined ? {} : { staged }),\n });\n if (problem !== undefined)\n throw new SudoRefusedError(`sudoRunner refused ${shown}: ${problem}`);\n await before?.();\n deps.log(`homeflare/launchd sudo -n ${shown}`);\n const result = await base.exec([SUDO, '-n', '--', ...argv]);\n const refused = sudoRefusal(shown, result);\n if (refused !== undefined) throw refused;\n return result;\n };\n\n /**\n * Every refusal a write can meet before sudo is asked — as the deploying user, reading only — so\n * the same checks run at plan time (`checkWrite`) and at the write. `undefined` outside every\n * prefix, where the operator writes; else the prefix and the mode as `install -m` takes it.\n */\n const vetWrite = async (path: string, options: WriteOptions) => {\n const prefix = prefixOf(path, prefixes);\n const operator = base.effectiveUid();\n if (prefix === undefined) {\n if (options.uid !== undefined && options.uid !== operator && operator !== 0) {\n throw new SudoRefusedError(\n `sudoRunner ${path}: owner ${String(options.uid)} needs root, and the path is under no ` +\n `declared prefix (${prefixes.join(', ')}). Declare its directory, or deploy as root. ` +\n 'Nothing was written.',\n );\n }\n return undefined;\n }\n const mode = octalMode(options.mode);\n if (mode === undefined) throw new SudoRefusedError(`sudoRunner ${path}: mode must be 0–0o7777`);\n await assertInstallable(base, prefix, path, options, await deps.groups());\n return { mode, prefix };\n };\n\n /** A privileged file operation: anything but exit 0 is an error. ⚠️ stderr names paths only. */\n const mustSucceed = async (argv: readonly string[], staged?: string): Promise<void> => {\n const result = await elevate(argv, staged === undefined ? {} : { staged });\n if (result.exitCode !== 0) {\n const stderr = result.stderr.trim().slice(0, 300);\n throw new Error(`sudo -n ${JSON.stringify(argv)} -> ${String(result.exitCode)}: ${stderr}`);\n }\n };\n\n return {\n // ★ The plan-time half of vetWrite: the providers' diffs call it, and it never elevates.\n checkWrite: async (path, options) => {\n await vetWrite(path, options);\n },\n effectiveUid: () => base.effectiveUid(),\n exec: async (argv) => {\n const route = routeExec(argv, base.effectiveUid());\n if ('refuse' in route) throw new SudoRefusedError(`sudoRunner: ${route.refuse}`);\n if (route.as === 'operator') return base.exec(argv);\n // ⛔ bootstrap makes root read the plist: it must be a plain file exactly where argv says.\n // The allowlist has already put it under a prefix by the time `before` runs.\n const plist = argv[1] === 'bootstrap' ? argv[3] : undefined;\n const prefix = plist === undefined ? undefined : prefixOf(plist, prefixes);\n return elevate(argv, {\n before: async () => {\n if (plist !== undefined && prefix !== undefined) {\n await assertPlainPath(base, prefix, plist, 'file');\n }\n },\n });\n },\n lookupGroup: (nameOrId) => base.lookupGroup(nameOrId),\n lookupUser: (nameOrId) => base.lookupUser(nameOrId),\n // ★ True, so the providers let a system-domain job through to this runner (canActAsRoot).\n privileged: true,\n readFile: (path) => base.readFile(path),\n removeFile: async (path) => {\n const prefix = prefixOf(path, prefixes);\n if (prefix === undefined) return base.removeFile(path).catch(undeclared(path, prefixes));\n /**\n * ★ Nothing there is success without a privileged call, so an idempotent delete logs nothing.\n * ⚠️ lstat the path FIRST: a directory on the way that is already gone means nothing is there\n * (HostRunner.removeFile is idempotent, and localRunner treats ENOENT/ENOTDIR so), where the\n * guard alone would refuse it as a missing directory.\n */\n if ((await base.stat(path)) === undefined) return;\n await assertPlainPath(base, prefix, path, 'file');\n await mustSucceed([RM, '-f', '--', path]);\n },\n sleep: (ms) => base.sleep(ms),\n stat: (path) => base.stat(path),\n writeFileAtomic: async (path, bytes, options) => {\n const vetted = await vetWrite(path, options);\n if (vetted === undefined) {\n return base.writeFileAtomic(path, bytes, options).catch(undeclared(path, prefixes));\n }\n const { mode } = vetted;\n const staged = await deps.stage(bytes);\n try {\n await mustSucceed(\n [\n INSTALL,\n '-S',\n '-m',\n mode,\n ...(options.uid === undefined ? [] : ['-o', String(options.uid)]),\n ...(options.gid === undefined ? [] : ['-g', String(options.gid)]),\n staged.path,\n path,\n ],\n staged.path,\n );\n } finally {\n await staged.dispose();\n }\n },\n };\n};\n\n/**\n * The real sudo runner: localRunner() for everything, `/usr/bin/sudo -n` for the allowlist.\n * Pass it explicitly: `launchdProviders(sudoRunner({ prefixes: ['/Library/LaunchDaemons'] }))`.\n */\nexport const sudoRunner = (options: SudoRunnerOptions): HostRunner => {\n const base = localRunner(options);\n return makeSudoRunner(options.prefixes, {\n base,\n groups: () => operatorGroups(base),\n log:\n options.log ??\n ((line) => {\n process.stderr.write(`${line}\\n`);\n }),\n stage: stageFile,\n });\n};\n"
|
|
31
33
|
],
|
|
32
|
-
"mappings": ";AAgBA;AACA,oBAAS;AACT;AACA;AACA;;;ACXA;AACA;AACA,kBAAS;AACT;AACA;;;ACiBA;AACA;AACA;AACA;AAEA,IAAM,SAAS;AACf,IAAM,aAAa;AAEnB,IAAM,OAAO,CAAC,KAAa,eAClB,WAAI,UAAU,GAAG;AAAA,EACtB,MAAM,MAAM,OAAc,qBAAc,SAAS;AAAA,EACjD,IAAW,cAAO,GAAG;AAAA,IAAG,OAAO,IAAI,MAAM,IAAI,KAAK,UAAU;AAAA,CAC7D;AAEH,IAAM,QAAQ,CAAC,KAAa,eACnB,WAAI,UAAU,GAAG;AAAA,EACtB,MAAM,MAAM,OAAc,qBAAc,SAAS;AAAA,EACjD,IAAW,cAAO,GAAG;AAAA,IAAG,OAAO;AAAA,EAC/B,QAAQ,OAAO,IAAI,MAAM,IAAY,GAAG,OAAO;AAAA,CAChD;AAOI,IAAM,iBAAiB,CAAC,eACtB,UAAG,KAAK,YAAY,UAAU,GAAG,SAAS;AAQ5C,IAAM,aAAa,CACxB,YACA,cAEO,WAAI,UAAU,GAAG;AAAA,EACtB,OAAO,eAAe,UAAU;AAAA,EAChC,MAAM,WAAW,MAAa,eAAQ,SAAS;AAAA,EAC/C,MAAM,QAAQ,OAAO,UAAU,KAAY,aAAM,QAAQ,GAAU,mBAAY,QAAQ,CAAC;AAAA,EACxF,IAAI,UAAU,aAAa,UAAU,QAAQ,QAAQ,GAAG,KAAK;AAAA,IAAG;AAAA,EAChE,OAAO,KAAK,QAAQ,UAAU;AAAA,CAC/B;AAGI,IAAM,UAAU,CAAC,eAA+C,MAAM,QAAQ,UAAU;AAGxF,IAAM,aAAa,CAAC,eACzB,MAAM,YAAY,UAAU;AAuBvB,IAAM,iBAAiB,CAAsB,YAAkB;AAAA,EACpE,QAAQ,MAAM,SAAS;AAAA,EACvB,IAAI,SAAS,aAAa,SAAS;AAAA,IAAW,OAAO;AAAA,EACrD,MAAM,UAA6B,CAAC,UAC3B,WAAI,UAAU,GAAG;AAAA,IACtB,IAAI,MAAM,WAAW,WAAW;AAAA,MAC9B,OAAO,WAAW,MAAM,YAAY,KAAK,KAAK,OAAO,QAAQ,UAAU,CAAC,CAAC;AAAA,IAC3E;AAAA,IACA,OAAO,OAAO,KAAK,KAAK;AAAA,GACzB;AAAA,EAEH,OAAO,KAAK,SAAS,MAAM,QAAQ;AAAA;;;ACxGrC,kBAAS;AACT;AACA;AACA;;;ACIA;AACA;AACA;AAEA,IAAM,SAAS,CAAC,UAA4B,UAAU,aAAa,UAAU;AAE7E,IAAM,gBAAgB,CAAC,UAAqD;AAAA,EAC1E,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK;AAAA,IAAG,OAAO;AAAA,EAChF,MAAM,QAAiB,OAAO,eAAe,KAAK;AAAA,EAClD,OAAO,UAAU,OAAO,aAAa,UAAU;AAAA;AAO1C,IAAM,UAAU,CAAC,UAAmB,aAA+B;AAAA,EACxE,IAAI,OAAO,QAAQ;AAAA,IAAG,OAAO;AAAA,EAC7B,IAAI,OAAO,QAAQ;AAAA,IAAG,OAAO;AAAA,EAC7B,IAAI,MAAM,QAAQ,QAAQ,GAAG;AAAA,IAC3B,IAAI,CAAC,MAAM,QAAQ,QAAQ;AAAA,MAAG,OAAO;AAAA,IACrC,OAAO,SAAS,MAAM,CAAC,MAAM,UAAU,QAAQ,MAAM,SAAS,MAAM,CAAC;AAAA,EACvE;AAAA,EACA,IAAI,cAAc,QAAQ,GAAG;AAAA,IAC3B,IAAI,CAAC,cAAc,QAAQ;AAAA,MAAG,OAAO;AAAA,IACrC,OAAO,OAAO,QAAQ,QAAQ,EAAE,MAAM,EAAE,KAAK,UAAU,QAAQ,MAAM,SAAS,IAAI,CAAC;AAAA,EACrF;AAAA,EACA,OAAO;AAAA;AASF,IAAM,mBAAmB,CAAC,KAAa,UACrC,YAAW,sBAAc,KAAK,GAAG,CAAC,UAAU;AAAA,EACjD,MAAM,WAAkB,eAAO,KAAK,IAAI,MAAM,MAAM,UAAU,OAAO;AAAA,EACrE,OAAO,aAAa,aAAa,QAAQ,SAAS,OAAO,KAAK;AAAA,CAC/D;;;ADtCH,IAAM,UAAiB,YAAI,UAAU,GAAG;AAAA,EACtC,MAAM,QAAQ,OAAc,sBAAc,MAAK;AAAA,EAC/C,MAAM,QAAQ,OAAc,sBAAc,KAAK;AAAA,EAC/C,IAAW,eAAO,KAAK,KAAY,eAAO,KAAK;AAAA,IAAG;AAAA,EAClD,MAAM,QAAsB,OAAO,MAAM;AAAA,EACzC,MAAM,QAAe,EAAE,OAAO,MAAM,MAAM,MAAM,OAAO,MAAM,MAAM,MAAM;AAAA,EACzE,OAAO,EAAE,WAAW,MAAM,MAAM,WAAW,OAAO,MAAM;AAAA,CACzD;AAED,IAAM,QAAQ,CAAC,OAAqB,OAAc,QAChD,MAAM,IAAI,KAAK,OAAO,IAAI,CAAC,EAAE,KAAY,sBAAc,MAAG;AAAA,EAAG;AAAA,CAAS,CAAC;AAczE,IAAM,eAAe,CAAC,KAAc,eAA+C;AAAA,EACjF,IAAI,KAAK;AAAA,EACT,OAAO,OAAO,OAAO,YAAY,OAAO,QAAQ,CAAC,cAAc,EAAW,GAAG;AAAA,IAC3E,MAAM,aAAa;AAAA,IACnB,IAAI,WAAW,eAAe;AAAA,MAAY,OAAO;AAAA,IACjD,KAAK,WAAW;AAAA,EAClB;AAAA,EACA;AAAA;AAIK,IAAM,qBAAqB,CAChC,KACA,eAEO,YAAI,UAAU,GAAG;AAAA,EACtB,MAAM,QAAQ,OAAO;AAAA,EACrB,IAAI,UAAU;AAAA,IAAW;AAAA,EACzB,WAAW,MAAM,CAAC,KAAK,GAAI,MAAM,UAAU,MAAM,cAAc,CAAC,CAAE,GAAG;AAAA,IACnE,MAAM,aAAa,aAAa,OAAO,MAAM,MAAM,OAAO,MAAM,OAAO,EAAE,GAAG,UAAU;AAAA,IACtF,IAAI,eAAe;AAAA,MAAW,OAAO;AAAA,EACvC;AAAA,EACA;AAAA,CACD;AAcI,IAAM,mBAAmB,CAAC,KAAa,eACrC,YAAI,UAAU,GAAG;AAAA,EACtB,MAAM,aAAa,OAAO,mBAAmB,KAAK,UAAU;AAAA,EAC5D,IAAI,eAAe;AAAA,IAAW,OAAO;AAAA,EACrC,QAAQ,OAAO,iBAAiB,KAAK,WAAW,KAAK,KAAK,UAAU;AAAA,CACrE;AAQI,IAAM,WAAW,CAAC,KAAa,eAC7B,YACL,mBAAmB,KAAK,UAAU,GAClC,CAAC,eAAe,YAAY,WAAW,UACzC;AAaK,IAAM,sBAAsB,CAAC,KAAa,eACxC,YAAI,UAAU,GAAG;AAAA,EACtB,MAAM,QAAQ,OAAO;AAAA,EACrB,IAAI,UAAU;AAAA,IAAW;AAAA,EACzB,MAAM,MAAM,OAAO,MAAM,MAAM,OAAO,MAAM,OAAO,GAAG;AAAA,EACtD,MAAM,OAAO;AAAA,EACb,IAAI,MAAM,WAAW,cAAc,KAAK,eAAe,cAAc,KAAK,SAAS,WAAW;AAAA,IAC5F;AAAA,EACF;AAAA,EACA,OAAO,MAAM,MAAM,OAAO,KAAK,MAAM,OAAO,IAAI,CAAC,EAAE,KAAY,cAAM;AAAA,CACtE;;;AFxFI,IAAM,eAAe,CAAC,QACpB,YAAI,UAAU,GAAG;AAAA,EACtB,MAAM,QAAQ,OAAc,sBAAc,MAAK;AAAA,EAC/C,MAAM,SAAgB,eAAO,KAAK,IAAI,MAAM,MAAM,UAAU,MAAM,QAAQ;AAAA,EAC1E,IAAI,WAAW;AAAA,IAAW,OAAO;AAAA,EACjC,MAAM,SAAS,OAAc,sBAAc,WAAW;AAAA,EACtD,IAAW,eAAO,MAAM;AAAA,IAAG,OAAO,OAAO;AAAA,EACzC,MAAM,UAAU,OAAc,sBAAc,cAAc;AAAA,EAC1D,OAAc,eAAO,OAAO,IAAI,QAAQ,MAAM,QAAQ;AAAA,CACvD;AAqBH,IAAM,YAAY,CAAC,UACV,YAAI,UAAU,GAAG;AAAA,EACtB,IAAI,OAAO,SAAS,MAAM,KAAK,MAAM,UAAU;AAAA,IAAG,OAAO;AAAA,EACzD,OAAO,OAAO,WAAW,MAAM,UAAU;AAAA,CAC1C;AAGI,IAAM,gBAAgB,CAAC,UACrB,YAAI,UAAU,GAAG;AAAA,EACtB,IAAI,EAAE,OAAO,aAAa,MAAM,GAAG;AAAA,IAAI,OAAO;AAAA,EAC9C,OAAO,OAAO,UAAU,KAAK;AAAA,CAC9B;AAuBI,IAAM,iBAAiB,CAAC,OAAc,SACpC,YAAI,UAAU,GAAG;AAAA,EACtB,IAAI,MAAM,WAAW;AAAA,IAAW;AAAA,EAChC,IAAI,OAAO,QAAQ,MAAM,UAAU;AAAA,IAAG;AAAA,EACtC,MAAM,MAAM,OAAO,UAAU,KAAK;AAAA,EAClC,IAAI,QAAQ,OAAO,aAAa,MAAM,GAAG;AAAA,IAAI;AAAA,EAC7C,OAAO,oBAAoB,MAAM,KAAK,MAAM,UAAU;AAAA,EACtD,MAAM,SAAS,MACX,mGACA;AAAA,EACJ,OAAO,OAAc,YACnB,IAAI,MACF,GAAG,yFACD,0FACA,+BAA+B,QACnC,CACF;AAAA,CACD;AAGI,IAAM,WACX,CAAC,UACD,CAAC,SACC,eAAe,OAAO,IAAI;;;AIhH9B;AAEO,IAAM,OAAO,CAAI,SACf,mBAAW;AAAA,EAChB,OAAO,CAAC,UAAW,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAAA,EAC3E,KAAK;AACP,CAAC;AAQI,IAAM,iBAAiB,CAAC,MAAe,QAAoC;AAAA,EAChF,IAAI,OAAO,SAAS,YAAY,SAAS;AAAA,IAAM;AAAA,EAC/C,MAAM,QAAS,KAAiC;AAAA,EAChD,OAAO,OAAO,UAAU,WAAW,QAAQ;AAAA;;;ACV7C,IAAM,cACJ,gGACA;AAGF,IAAM,cACJ;AAGF,IAAM,cAAc;AAGpB,IAAM,YAAY;AAEX,IAAM,cAAc;AAG3B,IAAM,YAAY,CAAC,OAAmB,SAA2B;AAAA,EAC/D,IAAI,OAAO,UAAU;AAAA,IAAU,OAAO,YAAY,KAAK,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC;AAAA,EAC1E,IAAI,MAAM,QAAQ,KAAK,GAAG;AAAA,IACxB,OAAQ,MAAgC,QAAQ,CAAC,MAAM,UACrD,UAAU,MAAM,GAAG,QAAQ,OAAO,KAAK,IAAI,CAC7C;AAAA,EACF;AAAA,EACA,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAAA,IAC/C,OAAO,OAAO,QAAQ,KAAK,EAAE,QAAQ,EAAE,KAAK,UAAU,UAAU,MAAM,GAAG,QAAQ,KAAK,CAAC;AAAA,EACzF;AAAA,EACA,OAAO,CAAC;AAAA;AAOH,IAAM,oBAAoB,CAC/B,aACA,MACA,cACa;AAAA,EACb,MAAM,QAAkB,CAAC;AAAA,EACzB,YAAY,MAAM,UAAU,OAAO,QAAQ,eAAe,CAAC,CAAC,GAAG;AAAA,IAC7D,IAAI,YAAY,KAAK,IAAI;AAAA,MACvB,MAAM,KAAK,eAAe,6BAA6B,aAAa;AAAA,IACjE,SAAI,YAAY,KAAK,KAAK;AAAA,MAC7B,MAAM,KAAK,eAAe,6BAA6B,aAAa;AAAA,EACxE;AAAA,EACA,YAAY,OAAO,QAAQ,KAAK,QAAQ,GAAG;AAAA,IAEzC,IAAI,YAAY,KAAK,GAAG,GAAG;AAAA,MACzB,MAAM,KAAK,oBAAoB,OAAO,KAAK,8BAA8B,aAAa;AAAA,IACxF,EAAO,SAAI,UAAU,KAAK,GAAG,KAAK,QAAQ,IAAI,KAAK,QAAQ;AAAA,MACzD,MAAM,KAAK,oBAAoB,OAAO,QAAQ,CAAC,6BAA6B,aAAa;AAAA,IAC3F,EAAO,SAAI,YAAY,KAAK,GAAG,GAAG;AAAA,MAChC,MAAM,KAAK,oBAAoB,OAAO,KAAK,2BAA2B,aAAa;AAAA,IACrF;AAAA,EACF;AAAA,EACA,WAAW,QAAQ,UAAU,aAAa,CAAC,GAAG,WAAW,GAAG;AAAA,IAC1D,MAAM,KAAK,GAAG,6BAA6B,aAAa;AAAA,EAC1D;AAAA,EACA,OAAO;AAAA;AAIF,IAAM,qBAAqB,CAAC,YACjC,YAAY,KAAK,OAAO,IAAI,CAAC,gCAAgC,aAAa,IAAI,CAAC;;;AC9C1E,IAAM,eAAe;AAE5B,IAAM,mBAAmB,CAAC,MAAc,UAAiD;AAAA,EACvF,IAAI,UAAU;AAAA,IAAW,OAAO,CAAC;AAAA,EACjC,IAAI,OAAO,UAAU,UAAU;AAAA,IAC7B,OAAO,OAAO,cAAc,KAAK,KAAK,SAAS,IAC3C,CAAC,IACD,CAAC,GAAG,wCAAwC;AAAA,EAClD;AAAA,EACA,OAAO,6BAA6B,KAAK,KAAK,KAAK,QAAQ,KAAK,KAAK,IACjE,CAAC,IACD,CAAC,GAAG,QAAQ,KAAK,UAAU,KAAK,qCAAqC;AAAA;AAOpE,IAAM,eAAe,CAAC,SAA2B;AAAA,EACtD,MAAM,QAAkB,CAAC;AAAA,EACzB,IAAI,CAAC,KAAK,WAAW,GAAG;AAAA,IAAG,MAAM,KAAK,uBAAuB;AAAA,EAG7D,IACE,KAAK,SAAS,GAAG,KACjB,KACG,MAAM,GAAG,EACT,MAAM,CAAC,EACP,KAAK,CAAC,SAAS,SAAS,MAAM,SAAS,OAAO,SAAS,IAAI,GAC9D;AAAA,IACA,MAAM,KAAK,6EAA6E;AAAA,EAC1F;AAAA,EACA,IAAI,KAAK,SAAS,MAAM;AAAA,IAAG,MAAM,KAAK,mBAAmB;AAAA,EACzD,OAAO;AAAA;AAGF,IAAM,eAAe,CAAC,UAAmC;AAAA,EAC9D,MAAM,QAAQ,aAAa,MAAM,IAAI;AAAA,EACrC,MAAM,OAAO,MAAM,QAAQ;AAAA,EAC3B,IAAI,CAAC,OAAO,cAAc,IAAI,KAAK,OAAO,KAAK,OAAO;AAAA,IAAQ,MAAM,KAAK,uBAAuB;AAAA,EAChG,MAAM,KAAK,GAAG,iBAAiB,SAAS,MAAM,KAAK,CAAC;AAAA,EACpD,MAAM,KAAK,GAAG,iBAAiB,SAAS,MAAM,KAAK,CAAC;AAAA,EACpD,MAAM,KAAK,GAAG,mBAAmB,MAAM,OAAO,CAAC;AAAA,EAC/C,OAAO;AAAA;;;ACnET;;;ACqBO,MAAM,mBAAmB,MAAM;AAAA,EAEzB;AAAA,EADX,WAAW,CACA,MACT,QACA;AAAA,IACA,MAAM,SAAS,SAAS,KAAK,WAAW,SAAS,QAAQ;AAAA,IAHhD;AAAA,IAIT,KAAK,OAAO;AAAA;AAEhB;AAEA,IAAM,SACJ;AAAA,IACA,0DACA;AAAA,IACA;AAAA;AAGF,IAAM,YAAY;AASlB,IAAM,YAAY;AAQX,IAAM,aAAa,CAAC,MAAc,SAAyB;AAAA,EAChE,MAAM,MAAM,UAAU,KAAK,IAAI;AAAA,EAC/B,IAAI,QAAQ,MAAM;AAAA,IAChB,MAAM,OAAO,IAAI,GAAG,YAAY,CAAC,KAAK;AAAA,IACtC,MAAM,IAAI,WACR,MACA,KAAK,KAAK,SAAS,EAAE,EAAE,YAAY,EAAE,SAAS,GAAG,GAAG,4BACtD;AAAA,EACF;AAAA,EACA,OAAO,KACJ,WAAW,KAAK,OAAO,EACvB,WAAW,KAAK,MAAM,EACtB,WAAW,KAAK,MAAM,EACtB,WAAW,MAAM,OAAO;AAAA;AAG7B,IAAM,iBAAgB,CAAC,UAA2B;AAAA,EAChD,MAAM,QAAQ,OAAO,eAAe,KAAK;AAAA,EACzC,OAAO,UAAU,OAAO,aAAa,UAAU;AAAA;AAGjD,IAAM,cAAc,CAAC,OAAgB,MAAc,OAAe,QAAwB;AAAA,EACxF,MAAM,MAAM,KAAK,OAAO,KAAK;AAAA,EAC7B,IAAI,QAAQ;AAAA,IAAW,MAAM,IAAI,WAAW,MAAM,sBAAsB,OAAO,SAAS,GAAG;AAAA,EAC3F,IAAI,OAAO,UAAU,UAAU;AAAA,IAC7B,IAAI,KAAK,GAAG,cAAc,WAAW,OAAO,IAAI,YAAY;AAAA,IAC5D;AAAA,EACF;AAAA,EACA,IAAI,OAAO,UAAU,WAAW;AAAA,IAC9B,IAAI,KAAK,GAAG,OAAO,QAAQ,SAAS,WAAW;AAAA,IAC/C;AAAA,EACF;AAAA,EACA,IAAI,OAAO,UAAU,UAAU;AAAA,IAE7B,IAAI,CAAC,OAAO,cAAc,KAAK,GAAG;AAAA,MAChC,MAAM,IAAI,WAAW,MAAM,GAAG,OAAO,KAAK,6CAA6C;AAAA,IACzF;AAAA,IACA,IAAI,KAAK,GAAG,eAAe,OAAO,UAAU,IAAI,IAAI,KAAK,aAAa;AAAA,IACtE;AAAA,EACF;AAAA,EACA,IAAI,MAAM,QAAQ,KAAK,GAAG;AAAA,IACxB,IAAI,MAAM,WAAW,GAAG;AAAA,MACtB,IAAI,KAAK,GAAG,aAAa;AAAA,MACzB;AAAA,IACF;AAAA,IACA,IAAI,KAAK,GAAG,YAAY;AAAA,IACxB,YAAY,OAAO,SAAU,MAA6B,QAAQ,GAAG;AAAA,MACnE,YAAY,MAAM,GAAG,QAAQ,OAAO,KAAK,MAAM,QAAQ,GAAG,GAAG;AAAA,IAC/D;AAAA,IACA,IAAI,KAAK,GAAG,aAAa;AAAA,IACzB;AAAA,EACF;AAAA,EACA,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,eAAc,KAAK,GAAG;AAAA,IACvE,WAAW,OAAkC,MAAM,OAAO,GAAG;AAAA,IAC7D;AAAA,EACF;AAAA,EACA,MAAM,OAAO,UAAU,OAAO,SAAS,OAAO;AAAA,EAC9C,MAAM,IAAI,WAAW,MAAM,GAAG,+CAA+C;AAAA;AAG/E,IAAM,aAAa,CACjB,MACA,MACA,OACA,QACS;AAAA,EACT,MAAM,MAAM,KAAK,OAAO,KAAK;AAAA,EAE7B,MAAM,OAAO,OAAO,KAAK,IAAI,EAAE,KAAK;AAAA,EACpC,IAAI,KAAK,WAAW,GAAG;AAAA,IACrB,IAAI,KAAK,GAAG,YAAY;AAAA,IACxB;AAAA,EACF;AAAA,EACA,IAAI,KAAK,GAAG,WAAW;AAAA,EACvB,WAAW,OAAO,MAAM;AAAA,IACtB,MAAM,QAAQ,SAAS,KAAK,MAAM,GAAG,QAAQ;AAAA,IAC7C,IAAI,KAAK,GAAG,YAAa,WAAW,KAAK,KAAK,SAAS;AAAA,IACvD,YAAY,KAAK,MAAM,OAAO,QAAQ,GAAG,GAAG;AAAA,EAC9C;AAAA,EACA,IAAI,KAAK,GAAG,YAAY;AAAA;AAInB,IAAM,cAAc,CAAC,SAA4B;AAAA,EACtD,IAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,MAAM,QAAQ,IAAI,KAAK,CAAC,eAAc,IAAI,GAAG;AAAA,IAC5F,MAAM,IAAI,WAAW,IAAI,iDAAiD;AAAA,EAC5E;AAAA,EACA,MAAM,MAAgB,CAAC;AAAA,EACvB,WAAW,MAAiC,IAAI,GAAG,GAAG;AAAA,EACtD,OAAO,GAAG,SAAS,IAAI,KAAK;AAAA,CAAI;AAAA;AAAA;AAAA;;;ADxE3B,IAAM,cAAc,CAAC,WAA6C;AAAA,EACvE,IAAI,WAAW;AAAA,IAAU,OAAO,EAAE,MAAM,SAAS;AAAA,EACjD,MAAM,QAAQ,eAAe,KAAK,MAAM;AAAA,EACxC,OAAO,QAAQ,OAAO,YAAY,YAAY,EAAE,MAAM,OAAO,KAAK,OAAO,MAAM,EAAE,EAAE;AAAA;AAG9E,IAAM,gBAAgB,CAAC,OAAe,WAAkC,GAAG,UAAU;AAOrF,IAAM,eAAe,CAC1B,OACA,QACA,SACW;AAAA,EACX,IAAI,OAAO,SAAS;AAAA,IAAU,OAAO,0BAA0B;AAAA,EAE/D,IAAI,SAAS,aAAa,CAAC,KAAK,WAAW,GAAG,GAAG;AAAA,IAC/C,MAAM,IAAI,MAAM,OAAO,OAAO,OAAO,GAAG,gDAAgD;AAAA,EAC1F;AAAA,EACA,OAAO,GAAG,6BAA6B;AAAA;AAIlC,IAAM,aAAgC;AAAA,EAC3C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,eAAe,CAAC,UAAuC;AAAA,EAC3D,MAAM,OAAmC,CAAC;AAAA,EAC1C,IAAI,MAAM,WAAW;AAAA,IAAW,KAAK,YAAY,MAAM;AAAA,EACvD,IAAI,MAAM,SAAS;AAAA,IAAW,KAAK,UAAU,MAAM;AAAA,EACnD,IAAI,MAAM,QAAQ;AAAA,IAAW,KAAK,SAAS,MAAM;AAAA,EACjD,IAAI,MAAM,YAAY;AAAA,IAAW,KAAK,aAAa,MAAM;AAAA,EACzD,IAAI,MAAM,UAAU;AAAA,IAAW,KAAK,WAAW,MAAM;AAAA,EACrD,OAAO;AAAA;AAGT,IAAM,iBAAiB,CAAC,cAAqC;AAAA,EAC3D,IAAI,OAAO,cAAc;AAAA,IAAW,OAAO;AAAA,EAC3C,MAAM,OAAmC,CAAC;AAAA,EAC1C,IAAI,UAAU,mBAAmB;AAAA,IAAW,KAAK,oBAAoB,UAAU;AAAA,EAC/E,IAAI,UAAU,YAAY;AAAA,IAAW,KAAK,aAAa,UAAU;AAAA,EACjE,OAAO;AAAA;AAIF,IAAM,eAAe,CAAC,UAAsC;AAAA,EACjE,MAAM,OAAmC,KAAK,MAAM,UAAU;AAAA,EAC9D,KAAK,WAAW,MAAM;AAAA,EACtB,KAAK,sBAAsB,CAAC,GAAG,MAAM,gBAAgB;AAAA,EACrD,MAAM,MAAM,MAAM,eAAe,CAAC;AAAA,EAClC,IAAI,OAAO,KAAK,GAAG,EAAE,SAAS;AAAA,IAAG,KAAK,0BAA0B,KAAK,IAAI;AAAA,EACzE,IAAI,MAAM,cAAc;AAAA,IAAW,KAAK,eAAe,MAAM;AAAA,EAC7D,IAAI,MAAM,cAAc;AAAA,IAAW,KAAK,eAAe,eAAe,MAAM,SAAS;AAAA,EACrF,IAAI,MAAM,kBAAkB;AAAA,IAAW,KAAK,mBAAmB,MAAM;AAAA,EACrE,MAAM,WAAW,MAAM;AAAA,EACvB,IAAI,aAAa,WAAW;AAAA,IAC1B,KAAK,2BAA2B,MAAM,QAAQ,QAAQ,IACjD,SAAyC,IAAI,YAAY,IAC1D,aAAa,QAA4B;AAAA,EAC/C;AAAA,EACA,IAAI,MAAM,qBAAqB;AAAA,IAAW,KAAK,sBAAsB,MAAM;AAAA,EAC3E,IAAI,MAAM,oBAAoB;AAAA,IAAW,KAAK,qBAAqB,MAAM;AAAA,EACzE,IAAI,MAAM,sBAAsB;AAAA,IAAW,KAAK,uBAAuB,MAAM;AAAA,EAC7E,IAAI,MAAM,qBAAqB;AAAA,IAAW,KAAK,sBAAsB,MAAM;AAAA,EAC3E,IAAI,MAAM,aAAa;AAAA,IAAW,KAAK,cAAc,MAAM;AAAA,EAC3D,IAAI,MAAM,cAAc;AAAA,IAAW,KAAK,eAAe,MAAM;AAAA,EAC7D,OAAO;AAAA;AAGF,IAAM,YAAY,CAAC,UACxB,WAAW,QAAQ,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK;AAG1C,IAAM,YAAY,CACvB,UACwD;AAAA,EACxD,MAAM,OAAO,YAAY,aAAa,KAAK,CAAC;AAAA,EAC5C,MAAM,QAAQ,IAAI,YAAY,EAAE,OAAO,IAAI;AAAA,EAC3C,OAAO,EAAE,OAAO,QAAQ,UAAU,KAAK,GAAG,KAAK;AAAA;;;AEpKjD;AACA;AAAA;AA8EO,MAAM,0BAAkC,gBAAuC,EACpF,8BACF,EAAE;AAAC;AAGI,IAAM,kBAAkB,CAAC,WACxB,cAAQ,mBAAmB,MAAM;AAGlC,IAAM,eAAe,CAAC,WAC3B,OAAO,cAAc,OAAO,aAAa,MAAM;;;AC5EjD,IAAM,SAAS,CAAC,MAAc,YAA2B,IAAI,MAAM,aAAa,SAAS,SAAS;AAElG,IAAM,YAAY,CAAC,UACjB,OAAO,UAAU,WAAW,QAAQ,QAAQ,KAAK,KAAK,IAAI,OAAO,KAAK,IAAI;AAGrE,IAAM,cAAc,OAAO,QAAoB,UAA2C;AAAA,EAC/F,MAAM,QAAQ,aAAa,KAAK;AAAA,EAChC,IAAI,MAAM,SAAS;AAAA,IAAG,MAAM,OAAO,MAAM,MAAM,MAAM,KAAK,IAAI,CAAC;AAAA,EAC/D,MAAM,QAAQ,IAAI,YAAY,EAAE,OAAO,MAAM,OAAO;AAAA,EACpD,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI,MAAM,UAAU,WAAW;AAAA,IAC7B,MAAM,UAAU,MAAM,KAAK,MAAM,MAAM,OAAO,WAAW,OAAO,MAAM,KAAK,CAAC,IAAI;AAAA,IAChF,IAAI,QAAQ;AAAA,MAAW,MAAM,OAAO,MAAM,MAAM,WAAW,OAAO,MAAM,KAAK,gBAAgB;AAAA,EAC/F;AAAA,EACA,IAAI,MAAM,UAAU,WAAW;AAAA,IAC7B,MAAM,UAAU,MAAM,KAAK,KAAM,MAAM,OAAO,YAAY,OAAO,MAAM,KAAK,CAAC;AAAA,IAC7E,IAAI,QAAQ;AAAA,MAAW,MAAM,OAAO,MAAM,MAAM,YAAY,OAAO,MAAM,KAAK,gBAAgB;AAAA,EAChG;AAAA,EACA,OAAO;AAAA,IACL;AAAA,IACA,MAAM,MAAM,QAAQ;AAAA,IACpB,QAAQ,UAAU,KAAK;AAAA,OACnB,QAAQ,YAAY,CAAC,IAAI,EAAE,IAAI;AAAA,OAC/B,QAAQ,YAAY,CAAC,IAAI,EAAE,IAAI;AAAA,EACrC;AAAA;AAIK,IAAM,qBAAqB,OAChC,QACA,SAC4C;AAAA,EAC5C,MAAM,OAAO,MAAM,OAAO,KAAK,IAAI;AAAA,EACnC,IAAI,SAAS;AAAA,IAAW;AAAA,EACxB,MAAM,QAAQ,KAAK,SAAS,SAAS,MAAM,OAAO,SAAS,IAAI,IAAI;AAAA,EACnE,OAAO;AAAA,IACL,KAAK,KAAK;AAAA,IACV,MAAM,KAAK;AAAA,IACX;AAAA,IACA,QAAQ,UAAU,YAAY,KAAK,UAAU,KAAK;AAAA,IAClD,MAAM,KAAK;AAAA,IACX,KAAK,KAAK;AAAA,EACZ;AAAA;AAGF,IAAM,iBAAiB,CAAC,UAAiC;AAAA,EACvD,MAAM,KAAK;AAAA,KACP,KAAK,QAAQ,YAAY,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI;AAAA,KAC9C,KAAK,QAAQ,YAAY,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI;AACpD;AAEA,IAAM,UAAU,CAAC,MAA0B,SACzC,KAAK,WAAW,KAAK,UACrB,KAAK,SAAS,KAAK,SAClB,KAAK,QAAQ,aAAa,KAAK,QAAQ,KAAK,SAC5C,KAAK,QAAQ,aAAa,KAAK,QAAQ,KAAK;AAOxC,IAAM,WAAW,OACtB,QACA,MACA,WACkB;AAAA,EAClB,MAAM,OAAO,MAAM,YAAY,QAAQ,IAAI;AAAA,EAC3C,MAAM,SAAS,OAAO,SAA8B;AAAA,IAClD,MAAM,OAAO,aAAa,KAAK,MAAM,eAAe,IAAI,CAAC;AAAA,IACzD,OAAO;AAAA;AAAA,EAGT,IAAI,KAAK,SAAS,OAAO;AAAA,IAAM,OAAO,OAAO,EAAE,QAAQ,UAAU,CAAC;AAAA,EAClE,IAAI,KAAK,WAAW,OAAO;AAAA,IAAQ,OAAO,OAAO,EAAE,QAAQ,SAAS,CAAC;AAAA,EACrE,MAAM,OAAO,MAAM,mBAAmB,QAAQ,KAAK,IAAI;AAAA,EACvD,OAAO,SAAS,aAAa,QAAQ,MAAM,IAAI,IAC3C,EAAE,QAAQ,OAAO,IACjB,OAAO,EAAE,QAAQ,SAAS,CAAC;AAAA;AAW1B,IAAM,gBAAgB,OAC3B,QACA,OACA,QACA,QAAQ,UACwB;AAAA,EAChC,MAAM,OAAO,MAAM,YAAY,QAAQ,KAAK;AAAA,EAE5C,IAAI,KAAK,QAAQ,aAAa,KAAK,QAAQ,OAAO,aAAa,KAAK,CAAC,aAAa,MAAM,GAAG;AAAA,IACzF,MAAM,OACJ,MAAM,MACN,SAAS,OAAO,MAAM,KAAK,sEACzB,2FACA,mCACJ;AAAA,EACF;AAAA,EACA,MAAM,OAAO,MAAM,OAAO,KAAK,MAAM,IAAI;AAAA,EACzC,IAAI,SAAS,aAAa,KAAK,SAAS,QAAQ;AAAA,IAC9C,MAAM,OACJ,MAAM,MACN,QAAQ,KAAK,gEACf;AAAA,EACF;AAAA,EACA,MAAM,SAAS,SAAS,YAAY,YAAY,MAAM,mBAAmB,QAAQ,MAAM,IAAI;AAAA,EAG3F,MAAM,QAAQ,WAAW,aAAa,OAAO,SAAS,MAAM;AAAA,EAC5D,MAAM,QAAQ,QAAQ,YAAY;AAAA,EASlC,MAAM,WAAW,SAAS,WAAW;AAAA,EACrC,IAAI,UAAU,aAAa,WAAW,aAAa,CAAC,QAAQ,QAAQ,IAAI,KAAK,CAAC,UAAU;AAAA,IACtF,MAAM,OACJ,MAAM,MACN,6FACE,sBACJ;AAAA,EACF;AAAA,EACA,IAAI,WAAW,aAAa,CAAC,QAAQ,QAAQ,IAAI,GAAG;AAAA,IAClD,MAAM,OAAO,gBAAgB,MAAM,MAAM,KAAK,OAAO,eAAe,IAAI,CAAC;AAAA,EAC3E;AAAA,EAGA,MAAM,QAAQ,MAAM,mBAAmB,QAAQ,MAAM,IAAI;AAAA,EACzD,IAAI,UAAU,aAAa,CAAC,QAAQ,OAAO,IAAI,GAAG;AAAA,IAGhD,IAAI,WAAW;AAAA,MAAW,MAAM,OAAO,WAAW,MAAM,IAAI,EAAE,MAAM,MAAG;AAAA,QAAG;AAAA,OAAS;AAAA,IACnF,MAAM,OACJ,MAAM,MACN,wEACF;AAAA,EACF;AAAA,EAGA,IAAI;AAAA,IAAO,MAAM,WAAW,QAAQ,MAAM;AAAA,EAC1C,OAAO;AAAA;AAIF,IAAM,aAAa,OAAO,QAAoB,WAA8C;AAAA,EACjG,MAAM,OAAO,MAAM,OAAO,KAAK,OAAO,IAAI;AAAA,EAC1C,IAAI,SAAS;AAAA,IAAW;AAAA,EACxB,IAAI,KAAK,SAAS;AAAA,IAAQ,MAAM,OAAO,OAAO,MAAM,YAAY,KAAK,uBAAuB;AAAA,EAC5F,MAAM,OAAO,WAAW,OAAO,IAAI;AAAA;;;AX5J9B,IAAM,WAAW,SAAmB,WAAW;AAE/C,IAAM,mBAAmB,MACrB,gBACP,UACO,YAAI,UAAU,GAAG;AAAA,EACtB,MAAM,SAAS,OAAO;AAAA,EACtB,OAAO,SAAS,SAAS,GAAG;AAAA,IAC1B,MAAM,MAAa,gBAAQ,CAAC,CAAC;AAAA,IAE7B,MAAM,GAAG,MAAM,aACb,KAAK,YAAY;AAAA,MACf,MAAM,QAAQ,MAAM,mBAAmB,QAAQ,KAAK,IAAI;AAAA,MACxD,IAAI,UAAU;AAAA,QAAW;AAAA,MACzB,OAAO,WAAW,YAAY,SAAQ,KAAK,IAAI;AAAA,KAChD;AAAA,IAEH,MAAM,GAAG,YAAY,MAAM,aAAa;AAAA,MAEtC,IAAI,WAAW;AAAA,QAAW,OAAO,eAAe,UAAU;AAAA,MAC1D,IAAI,WAAW,IAAI;AAAA,QAAG,OAAO,KAAK,MAAM,SAAS,QAAQ,MAAM,MAAM,CAAC;AAAA,MAItE,MAAM,OAAO,eAAe,MAAM,MAAM;AAAA,MACxC,OAAc,gBACZ,SAAS,aAAa,SAAS,OAAO,OAAO,EAAE,QAAQ,UAAmB,IAAI,SAChF;AAAA;AAAA,IAKF,WAAW,GAAG,KAAK,YAAY,MAAM,aAC5B,gBAAQ,cAAc,EAAE,KAAK,YAAY,OAAO,CAAC,GAAG,CAAC,UAC1D,KAAK,MAAM,cAAc,QAAQ,MAAM,QAAQ,KAAK,CAAC,CACvD;AAAA,IAEF,QAAQ,GAAG,aAAa,KAAK,MAAM,WAAW,QAAQ,MAAM,CAAC;AAAA,EAC/D,CAAC;AAAA,CACF,CACH;;AY/CF,qBAAS;AACT,oBAAS;AACT,uBAAS;AACT;AACA;;;ACZO,IAAM,QAAQ;AAQd,IAAM,0BAA6C;AAAA,EACxD;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,WAAW;AAEjB,IAAM,SAA2E;AAAA,EAC/E,CAAC,UAAU,GAAG,EAAE;AAAA,EAChB,CAAC,QAAQ,GAAG,EAAE;AAAA,EACd,CAAC,OAAO,GAAG,EAAE;AAAA,EACb,CAAC,WAAW,GAAG,CAAC;AAAA,EAChB,CAAC,SAAS,GAAG,EAAE;AACjB;AAEA,IAAM,QAAQ,CAAC,OAAe,KAAa,MAAM,OAAO,qBACtD,OAAO,cAAc,KAAK,KAAK,SAAS,OAAO,SAAS;AAE1D,IAAM,mBAAmB,CAAC,YAAmD;AAAA,EAC3E,IAAI,QAAQ,WAAW;AAAA,IAAG,OAAO,CAAC,yDAAyD;AAAA,EAC3F,MAAM,QAAkB,CAAC;AAAA,EACzB,YAAY,OAAO,UAAU,QAAQ,QAAQ,GAAG;AAAA,IAC9C,YAAY,OAAO,KAAK,QAAQ,QAAQ;AAAA,MACtC,MAAM,QAAQ,MAAM;AAAA,MACpB,IAAI,UAAU,aAAa,CAAC,MAAM,OAAO,KAAK,GAAG,GAAG;AAAA,QAClD,MAAM,KACJ,yBAAyB,OAAO,KAAK,MAAM,iBAAiB,OAAO,GAAG,KAAK,OAAO,GAAG,GACvF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AAGT,IAAM,WAAW,CAAC,MAAc,UAC9B,UAAU,aAAa,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,+BAA+B;AAQlF,IAAM,oBAAmB,CAAC,OAAe,eAAiC;AAAA,EAC/E,MAAM,QAAkB,CAAC;AAAA,EACzB,IAAI,CAAC,MAAM,KAAK,KAAK,GAAG;AAAA,IACtB,MAAM,KAAK,wEAAwE;AAAA,EACrF;AAAA,EACA,MAAM,WAAW,wBAAwB,KAAK,CAAC,WAAW,MAAM,WAAW,MAAM,CAAC;AAAA,EAClF,IAAI,aAAa,WAAW;AAAA,IAC1B,MAAM,KAAK,SAAS,kBAAkB,wDAAwD;AAAA,EAChG;AAAA,EACA,IAAI,YAAY,UAAU,MAAM;AAAA,IAC9B,MAAM,KAAK,+CAA+C,YAAY;AAAA,EACxE,OAAO;AAAA;AAGF,IAAM,cAAc,CAAC,UAAqC;AAAA,EAC/D,MAAM,QAAQ,kBAAiB,MAAM,OAAO,MAAM,MAAM;AAAA,EACxD,MAAM,SAAS,YAAY,MAAM,MAAM;AAAA,EAEvC,OAAO,WAAW,MAAM;AAAA,EAExB,IAAI,YAAY;AAAA,IAAW,MAAM,KAAK,sCAAsC;AAAA,EACvE,SAAI,CAAC,QAAQ,WAAW,GAAG;AAAA,IAAG,MAAM,KAAK,8CAA8C;AAAA,EAE5F,WAAW,QAAQ,OAAO,KAAK,MAAM,eAAe,CAAC,CAAC,GAAG;AAAA,IACvD,IAAI,CAAC,SAAS,KAAK,IAAI;AAAA,MACrB,MAAM,KAAK,oBAAoB,KAAK,UAAU,IAAI,gCAAgC;AAAA,EACtF;AAAA,EACA,MAAM,KAAK,GAAG,kBAAkB,MAAM,aAAa,MAAM,kBAAkB,MAAM,SAAS,CAAC;AAAA,EAE3F,IAAI,MAAM,kBAAkB,aAAa,CAAC,MAAM,MAAM,eAAe,CAAC,GAAG;AAAA,IACvE,MAAM,KAAK,0DAA0D;AAAA,EACvE;AAAA,EACA,IAAI,MAAM,qBAAqB,aAAa,CAAC,MAAM,MAAM,kBAAkB,CAAC,GAAG;AAAA,IAC7E,MAAM,KAAK,iEAAiE;AAAA,EAC9E;AAAA,EACA,MAAM,WAAW,MAAM;AAAA,EACvB,IAAI,aAAa,WAAW;AAAA,IAC1B,MAAM,KACJ,GAAG,iBAAiB,MAAM,QAAQ,QAAQ,IAAI,WAAW,CAAC,QAA4B,CAAC,CACzF;AAAA,EACF;AAAA,EACA,MAAM,YAAY,MAAM;AAAA,EACxB,IACE,OAAO,cAAc,YACrB,UAAU,mBAAmB,aAC7B,UAAU,YAAY,WACtB;AAAA,IACA,MAAM,KAAK,kEAAkE;AAAA,EAC/E;AAAA,EAEA,MAAM,KAAK,GAAG,SAAS,mBAAmB,MAAM,eAAe,CAAC;AAAA,EAChE,MAAM,KAAK,GAAG,SAAS,qBAAqB,MAAM,iBAAiB,CAAC;AAAA,EACpE,MAAM,KAAK,GAAG,SAAS,oBAAoB,MAAM,gBAAgB,CAAC;AAAA,EAElE,IAAI,QAAQ,SAAS,UAAU,MAAM,aAAa,aAAa,MAAM,cAAc,YAAY;AAAA,IAC7F,MAAM,KACJ,qFACF;AAAA,EACF;AAAA,EACA,WAAW,OAAO,OAAO,KAAK,MAAM,aAAa,CAAC,CAAC,GAAG;AAAA,IACpD,IAAI,WAAW,SAAS,GAAG;AAAA,MACzB,MAAM,KAAK,aAAa,gDAAgD;AAAA,EAC5E;AAAA,EACA,OAAO;AAAA;;;AC5GF,IAAM,YAAY;AAElB,IAAM,YAAY;AAElB,IAAM,YAAY;AACzB,IAAM,iBAAiB;AAAA;AAEhB,MAAM,uBAAuB,MAAM;AAAA,EACxC,WAAW,CAAC,SAAiB,UAAkB,QAAgB;AAAA,IAC7D,MAAM,aAAa,cAAc,OAAO,QAAQ,MAAM,OAAO,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG;AAAA,IACnF,KAAK,OAAO;AAAA;AAEhB;AAiBO,IAAM,cAAc,CAAC,WAAwC;AAAA,EAClE,MAAM,SAAS,IAAI;AAAA,EACnB,MAAM,UAAoB,CAAC;AAAA,EAC3B,WAAW,QAAQ,OAAO,MAAM;AAAA,CAAI,GAAG;AAAA,IACrC,IAAI,QAAQ,WAAW,GAAG;AAAA,MACxB,IAAI,OAAO,SAAS,KAAK,KAAK,SAAS,MAAM;AAAA,QAAG,QAAQ,KAAK,GAAG;AAAA,MAChE;AAAA,IACF;AAAA,IACA,IAAI,SAAS,QAAQ,QAAQ,SAAS,IAAI;AAAA,MACxC,QAAQ,IAAI;AAAA,MACZ;AAAA,IACF;AAAA,IACA,MAAM,SAAS,mBAAmB,KAAK,IAAI;AAAA,IAC3C,IAAI,SAAS,OAAO,aAAa,OAAO,GAAG,WAAW,QAAQ,QAAQ;AAAA,MACpE,QAAQ,KAAK,GAAG,OAAO,KAAK;AAAA,MAC5B;AAAA,IACF;AAAA,IACA,MAAM,QAAQ,QAAQ,WAAW,IAAI,iCAAiC,KAAK,IAAI,IAAI;AAAA,IACnF,IAAI,QAAQ,OAAO,aAAa,MAAM,OAAO,aAAa,CAAC,OAAO,IAAI,MAAM,EAAE,GAAG;AAAA,MAC/E,OAAO,IAAI,MAAM,IAAI,MAAM,EAAE;AAAA,IAC/B;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AAGT,IAAM,aAAa,CAAC,SAAiD;AAAA,EACnE,MAAM,QAAQ,SAAS,YAAY,OAAO,WAAW,KAAK,IAAI;AAAA,EAC9D,OAAO,QAAQ,OAAO,YAAY,YAAY,OAAO,MAAM,EAAE;AAAA;AAGxD,IAAM,aAAa,CAAC,WAAkC;AAAA,EAC3D,MAAM,SAAS,YAAY,MAAM;AAAA,EACjC,MAAM,QAAQ,OAAO,IAAI,OAAO;AAAA,EAChC,MAAM,MAAM,WAAW,OAAO,IAAI,KAAK,CAAC;AAAA,EAExC,MAAM,eAAe,WAAW,OAAO,IAAI,gBAAgB,CAAC;AAAA,EAC5D,OAAO;AAAA,IACL,QAAQ;AAAA,OACJ,UAAU,YAAY,CAAC,IAAI,EAAE,MAAM;AAAA,OACnC,QAAQ,YAAY,CAAC,IAAI,EAAE,IAAI;AAAA,OAC/B,iBAAiB,YAAY,CAAC,IAAI,EAAE,aAAa;AAAA,EACvD;AAAA;AAIK,IAAM,gBAAgB,CAAC,WAAgC;AAAA,EAC5D,MAAM,WAAW,IAAI;AAAA,EACrB,WAAW,SAAS,OAAO,SAAS,8BAA8B,GAAG;AAAA,IACnE,IAAI,MAAM,OAAO,cAAc,MAAM,OAAO,cAAc,MAAM,OAAO,SAAS;AAAA,MAC9E,SAAS,IAAI,MAAM,EAAE;AAAA,IACvB;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AAGF,IAAM,eAAe,OAAO,QAAoB,WAA2C;AAAA,EAChG,MAAM,SAAS,MAAM,OAAO,KAAK,CAAC,WAAW,SAAS,MAAM,CAAC;AAAA,EAC7D,IAAI,OAAO,aAAa;AAAA,IAAW,OAAO,EAAE,QAAQ,MAAM;AAAA,EAG1D,IAAI,OAAO,aAAa,aAAa,OAAO,OAAO,SAAS,cAAc,GAAG;AAAA,IAC3E,OAAO,EAAE,eAAe,MAAM,QAAQ,MAAM;AAAA,EAC9C;AAAA,EACA,IAAI,OAAO,aAAa;AAAA,IACtB,MAAM,IAAI,eAAe,SAAS,UAAU,OAAO,UAAU,OAAO,MAAM;AAAA,EAC5E,OAAO,WAAW,OAAO,MAAM;AAAA;AAG1B,IAAM,aAAa,OACxB,QACA,QACA,UACqB;AAAA,EACrB,MAAM,SAAS,MAAM,OAAO,KAAK,CAAC,WAAW,kBAAkB,MAAM,CAAC;AAAA,EACtE,IAAI,OAAO,aAAa,GAAG;AAAA,IACzB,MAAM,IAAI,eAAe,kBAAkB,UAAU,OAAO,UAAU,OAAO,MAAM;AAAA,EACrF;AAAA,EACA,OAAO,cAAc,OAAO,MAAM,EAAE,IAAI,KAAK;AAAA;AAGxC,IAAM,YAAY,OACvB,QACA,QACA,cACkB;AAAA,EAClB,MAAM,SAAS,MAAM,OAAO,KAAK,CAAC,WAAW,aAAa,QAAQ,SAAS,CAAC;AAAA,EAC5E,IAAI,OAAO,aAAa,GAAG;AAAA,IACzB,MAAM,IAAI,eAAe,aAAa,UAAU,aAAa,OAAO,UAAU,OAAO,MAAM;AAAA,EAC7F;AAAA;AASK,IAAM,eAAe,OAC1B,QACA,QACA,WAAW,KACX,aAAa,QACK;AAAA,EAClB,SAAS,UAAU,EAAG,UAAU,UAAU,WAAW,GAAG;AAAA,IACtD,IAAI,EAAE,MAAM,aAAa,QAAQ,MAAM,GAAG;AAAA,MAAQ;AAAA,IAClD,MAAM,OAAO,MAAM,UAAU;AAAA,EAC/B;AAAA,EACA,MAAM,IAAI,MACR,GAAG,0BAA0B,OAAQ,WAAW,aAAc,IAAI,kBACpE;AAAA;AAIK,IAAM,kBAAkB,OAAO,QAAoB,WAAkC;AAAA,EAC1F,IAAI,EAAE,MAAM,aAAa,QAAQ,MAAM,GAAG;AAAA,IAAQ;AAAA,EAClD,MAAM,SAAS,MAAM,OAAO,KAAK,CAAC,WAAW,WAAW,MAAM,CAAC;AAAA,EAS/D,IAAI;AAAA,IACF,MAAM,aAAa,QAAQ,MAAM;AAAA,IACjC,OAAO,OAAO;AAAA,IACd,IAAI,OAAO,aAAa;AAAA,MAAG,MAAM;AAAA,IACjC,MAAM,IAAI,eACR,WAAW,UACX,OAAO,UACP,GAAG,OAAO,OAAO,KAAK,oCACxB;AAAA;AAAA;;;AClJG,IAAM,oBAAoB,CAAC,WAChC,OAAO,SAAS,WAAW,EAAE,KAAK,GAAG,MAAM,KAAO,KAAK,EAAE,IAAI,EAAE,MAAM,KAAO,KAAK,OAAO,IAAI;AAMvF,IAAM,kBAAkB,OAAO,QAAoB,aACxD,OAAO,aAAa,SAAS,WAAW,kBAAkB,SAAS,MAAM,CAAC;AAErE,IAAM,UAAS,CAAC,OAAe,YACpC,IAAI,MAAM,eAAe,UAAU,SAAS;AAGvC,IAAM,cAAc,CAAC,UAAiC;AAAA,EAC3D,MAAM,QAAQ,YAAY,KAAK;AAAA,EAC/B,IAAI,MAAM,SAAS;AAAA,IAAG,MAAM,QAAO,MAAM,OAAO,MAAM,KAAK,IAAI,CAAC;AAAA;AAG3D,IAAM,SAAS,OAAO,QAAoB,UAAuC;AAAA,EACtF,MAAM,SAAS,YAAY,MAAM,MAAM;AAAA,EACvC,IAAI,WAAW;AAAA,IAAW,MAAM,QAAO,MAAM,OAAO,kBAAkB,MAAM,QAAQ;AAAA,EACpF,MAAM,OACJ,OAAO,SAAS,SAAS,MAAM,OAAO,WAAW,OAAO,OAAO,GAAG,CAAC,IAAI,OAAO;AAAA,EAChF,OAAO;AAAA,IACL;AAAA,IACA,WAAW,aAAa,MAAM,OAAO,QAAQ,IAAI;AAAA,IACjD,QAAQ,cAAc,MAAM,OAAO,MAAM,MAAM;AAAA,EACjD;AAAA;AAOK,IAAM,iBAAiB,CAAC,QAAoB,OAAe,WAA+B;AAAA,EAC/F,IAAI,aAAa,MAAM;AAAA,IAAG;AAAA,EAC1B,IAAI,OAAO,SAAS,UAAU;AAAA,IAC5B,MAAM,QACJ,OACA,6FACE,yFACA,oBACJ;AAAA,EACF;AAAA,EACA,IAAI,OAAO,QAAQ,OAAO,aAAa,GAAG;AAAA,IACxC,MAAM,QACJ,OACA,OAAO,OAAO,OAAO,GAAG,wDACtB,mEACJ;AAAA,EACF;AAAA;AAIK,IAAM,YAAY,OACvB,QACA,UAC2D;AAAA,EAC3D,MAAM,WAAW,MAAM,OAAO,QAAQ,KAAK;AAAA,EAC3C,eAAe,QAAQ,MAAM,OAAO,SAAS,MAAM;AAAA,EACnD,MAAM,SAAS,MAAM,aAAa,QAAQ,SAAS,MAAM;AAAA,EACzD,IAAI,OAAO,kBAAkB,MAAM;AAAA,IACjC,MAAM,QACJ,MAAM,OACN,GAAG,MAAM,sFACP,2FACA,qCACJ;AAAA,EACF;AAAA,EAKA,IAAI,MAAM,WAAW,QAAQ,MAAM,QAAQ,MAAM,KAAK,GAAG;AAAA,IACvD,MAAM,QACJ,MAAM,OACN,GAAG,SAAS,gDAAgD,MAAM,cAChE,4CAA4C,SAAS,uCACzD;AAAA,EACF;AAAA,EACA,OAAO,EAAE,UAAU,OAAO;AAAA;AAUrB,IAAM,kBAAkB,OAC7B,QACA,OACA,UACA,QACA,mBACkB;AAAA,EAClB,MAAM,QAAQ,MAAM,OAAO,SAAS,SAAS,SAAS;AAAA,EACtD,MAAM,cAAc,UAAU,aAAa,UAAU,KAAK,MAAM;AAAA,EAChE,IAAI,eAAgB,UAAU,aAAa,OAAO,QAAS;AAAA,IACzD,MAAM,QACJ,OACA,GAAG,SAAS,mCAAmC,cAAc,SAAS,YAAY,cAChF,2FACA,UACJ;AAAA,EACF;AAAA;AAQK,IAAM,oBAAoB,OAC/B,QACA,MACA,MACA,KACA,mBACkB;AAAA,EAClB,MAAM,QAAQ,SAAS,YAAY,kBAAiB,KAAK,OAAO,KAAK,MAAM,IAAI,YAAY,IAAI;AAAA,EAC/F,IAAI,MAAM,SAAS;AAAA,IAAG,MAAM,QAAO,KAAK,OAAO,MAAM,KAAK,IAAI,CAAC;AAAA,EAC/D,MAAM,YAAY,YAAY,IAAI,MAAM;AAAA,EACxC,IAAI,cAAc;AAAA,IAAW,MAAM,QAAO,IAAI,OAAO,kBAAkB,IAAI,QAAQ;AAAA,EACnF,eAAe,QAAQ,IAAI,OAAO,SAAS;AAAA,EAC3C,QAAQ,UAAU,WAAW,MAAM,UAAU,QAAQ,IAAI;AAAA,EACzD,MAAM,gBAAgB,QAAQ,KAAK,OAAO,UAAU,QAAQ,cAAc;AAAA,EAC1E,MAAM,gBAAgB,QAAQ,QAAQ;AAAA;;;ACjIxC,IAAM,eAAe,CACnB,OACA,UACA,aACA,YAC0B;AAAA,EAC1B,QAAQ,MAAM;AAAA,EACd,OAAO,MAAM;AAAA,EACb,QAAQ,OAAO;AAAA,EACf,WAAW,SAAS;AAAA,EACpB;AAAA,EACA,eAAe,SAAS;AAAA,KACpB,OAAO,UAAU,YAAY,CAAC,IAAI,EAAE,OAAO,OAAO,MAAM;AAAA,KACxD,OAAO,QAAQ,YAAY,CAAC,IAAI,EAAE,KAAK,OAAO,IAAI;AAAA,KAClD,OAAO,iBAAiB,YAAY,CAAC,IAAI,EAAE,cAAc,OAAO,aAAa;AACnF;AAGO,IAAM,UAAU,OACrB,QACA,UAC8C;AAAA,EAC9C,MAAM,WAAW,MAAM,OAAO,QAAQ,KAAK;AAAA,EAC3C,MAAM,QAAQ,MAAM,OAAO,SAAS,SAAS,SAAS;AAAA,EACtD,MAAM,SAAS,MAAM,aAAa,QAAQ,SAAS,MAAM;AAAA,EACzD,IAAI,UAAU,aAAa,CAAC,OAAO;AAAA,IAAQ;AAAA,EAC3C,OAAO,aAAa,OAAO,UAAU,UAAU,YAAY,KAAK,UAAU,KAAK,GAAG,MAAM;AAAA;AAUnF,IAAM,cAAc,OACzB,QACA,MACA,MACA,WACkB;AAAA,EAElB,IAAI,SAAS;AAAA,IAAW,YAAY,IAAI;AAAA,EACxC,MAAM,WAAW,SAAS,YAAY,YAAY,UAAU,IAAI,EAAE;AAAA,EAClE,MAAM,kBAAkB,QAAQ,MAAM,MAAM,QAAQ,QAAQ;AAAA,EAC5D,OAAO,EAAE,QAAQ,WAAW,aAAa,KAAK;AAAA;AAGzC,IAAM,UAAU,OACrB,QACA,MACA,WACkB;AAAA,EAClB,IAAI,KAAK,UAAU,OAAO,SAAS,KAAK,WAAW,OAAO,QAAQ;AAAA,IAChE,OAAO,YAAY,QAAQ,MAAM,MAAM,MAAM;AAAA,EAC/C;AAAA,EACA,YAAY,IAAI;AAAA,EAChB,MAAM,UAAU,UAAU,IAAI,EAAE;AAAA,EAEhC,MAAM,SAAS,YAA2B;AAAA,IACxC,MAAM,gBAAgB,QAAQ,MAAM,OAAO,QAAQ,IAAI,CAAC;AAAA,IACxD,OAAO,EAAE,QAAQ,SAAS;AAAA;AAAA,EAI5B,IAAI,YAAY,OAAO;AAAA,IAAa,OAAO,OAAO;AAAA,EAClD,MAAM,OAAO,MAAM,QAAQ,QAAQ,IAAI;AAAA,EACvC,IAAI,SAAS,aAAa,CAAC,KAAK,UAAU,KAAK,gBAAgB;AAAA,IAAS,OAAO,OAAO;AAAA,EACtF,OAAO,EAAE,QAAQ,OAAO;AAAA;AAUnB,IAAM,eAAe,OAC1B,QACA,OACA,QACA,QAAQ,UAC0B;AAAA,EAClC,YAAY,KAAK;AAAA,EACjB,QAAQ,UAAU,WAAW,MAAM,UAAU,QAAQ,KAAK;AAAA,EAC1D,MAAM,WAAW,UAAU,KAAK;AAAA,EAQhC,MAAM,UACJ,WAAW,cAAc,OAAO,UAAU,MAAM,SAAS,OAAO,WAAW,MAAM;AAAA,EACnF,MAAM,QAAQ,UAAU,YAAY;AAAA,EAGpC,IAAI,UAAU,aAAa,EAAE,SAAS,WAAW,YAAY;AAAA,IAC3D,MAAM,gBAAgB,QAAQ,MAAM,OAAO,UAAU,QAAQ,SAAS,MAAM;AAAA,EAC9E;AAAA,EACA,IAAI;AAAA,IAAS,MAAM,UAAU,QAAQ,MAAM;AAAA,EAC3C,MAAM,SAAS,MAAM,OAAO,SAAS,SAAS,SAAS;AAAA,EAIvD,IACE,OAAO,UACP,WAAW,aACX,UAAU,MAAM,MAAM,SAAS,UAC/B,OAAO,gBAAgB,SAAS,QAChC;AAAA,IACA,OAAO,aAAa,OAAO,UAAU,SAAS,QAAQ,MAAM;AAAA,EAC9D;AAAA,EAEA,MAAM,OAAO,gBACX,SAAS,WACT,SAAS,OACT,kBAAkB,SAAS,MAAM,CACnC;AAAA,EACA,MAAM,gBAAgB,QAAQ,SAAS,MAAM;AAAA,EAC7C,MAAM,SAAS,OAAO,WAAmC;AAAA,IAEvD,MAAM,UACJ,WAAW,aACV,MAAM,OAAO,WAAW,SAAS,SAAS,EAAE,KAC3C,MAAM,MACN,MAAM,KACR;AAAA,IACF,MAAM,QACJ,MAAM,OACN,UACI,0FACE,2CAA2C,WAC7C,oEAAoE,SAAS,eAC3E,gCAAgC,QACxC;AAAA;AAAA,EAEF,IAAI;AAAA,IACF,MAAM,UAAU,QAAQ,MAAM,QAAQ,SAAS,SAAS;AAAA,IACxD,OAAO,OAAO;AAAA,IACd,OAAO,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA;AAAA,EAEtE,MAAM,QAAQ,MAAM,aAAa,QAAQ,SAAS,MAAM;AAAA,EACxD,IAAI,CAAC,MAAM;AAAA,IAAQ,OAAO,OAAO,4DAA4D;AAAA,EAC7F,OAAO,aAAa,OAAO,UAAU,SAAS,QAAQ,KAAK;AAAA;AAItD,IAAM,YAAY,OACvB,QACA,WACkB;AAAA,EAClB,MAAM,SAAS,YAAY,OAAO,MAAM;AAAA,EACxC,IAAI,WAAW;AAAA,IAAW,MAAM,QAAO,OAAO,OAAO,kBAAkB,OAAO,QAAQ;AAAA,EACtF,eAAe,QAAQ,OAAO,OAAO,MAAM;AAAA,EAG3C,MAAM,gBAAgB,QAAQ,OAAO,aAAa;AAAA,EAClD,MAAM,OAAO,WAAW,OAAO,SAAS;AAAA;;;AJrJnC,IAAM,aAAa,UAAqB,aAAa;AAErD,IAAM,qBAAqB,MACvB,iBACP,YACO,YAAI,UAAU,GAAG;AAAA,EACtB,MAAM,SAAS,OAAO;AAAA,EACtB,OAAO,WAAW,SAAS,GAAG;AAAA,IAK5B,MAAM,MAAa,gBAAQ,CAAC,CAAC;AAAA,IAE7B,MAAM,GAAG,MAAM,aACb,KAAK,YAAY;AAAA,MACf,MAAM,QAAQ,MAAM,QAAQ,QAAQ,IAAI;AAAA,MACxC,IAAI,UAAU;AAAA,QAAW;AAAA,MACzB,OAAO,WAAW,YAAY,SAAQ,KAAK,IAAI;AAAA,KAChD;AAAA,IAEH,MAAM,GAAG,YAAY,MAAM,aAAa;AAAA,MAEtC,IAAI,WAAW;AAAA,QAAW,OAAO,eAAe,UAAU;AAAA,MAC1D,IAAI,YAAW,IAAI;AAAA,QAAG,OAAO,KAAK,MAAM,QAAQ,QAAQ,MAAM,MAAM,CAAC;AAAA,MAUrE,MAAM,QAAQ,eAAe,MAAM,OAAO;AAAA,MAC1C,MAAM,SAAS,eAAe,MAAM,QAAQ;AAAA,MAC5C,OAAO,UAAU,aACf,WAAW,cACV,UAAU,OAAO,SAAS,WAAW,OAAO,UAC3C,KAAK,MAAM,YAAY,QAAQ,EAAE,QAAQ,MAAM,GAAG,WAAW,MAAM,CAAC,IAC7D,gBAAQ,SAAS;AAAA;AAAA,IAK9B,WAAW,GAAG,KAAK,YAAY,MAAM,aAC5B,gBAAQ,cAAc,EAAE,KAAK,YAAY,OAAO,CAAC,GAAG,CAAC,UAC1D,KAAK,MAAM,aAAa,QAAQ,MAAM,QAAQ,KAAK,CAAC,CACtD;AAAA,IAEF,QAAQ,GAAG,aAAa,KAAK,MAAM,UAAU,QAAQ,MAAM,CAAC;AAAA,EAC9D,CAAC;AAAA,CACF,CACH;;AK5FF;AACA;AACA;AACA;;;ACMA,IAAM,UAAU;AAGT,IAAM,YAAY,CAAC,UAAkB,aAC1C,aAAa,WACT;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ,KAAK,QAAQ,IAAI,QAAQ;AAAA,EACjC;AACF,IACA,CAAC,UAAU,UAAU,QAAQ;AAG5B,IAAM,aAAa,CAAC,UAAkB,aAC3C,aAAa,WACT;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ,KAAK,QAAQ,IAAI,QAAQ;AAAA,EACjC;AACF,IACA,CAAC,UAAU,SAAS,QAAQ;AAGlC,IAAM,cAAc,CAAC,WAAwC;AAAA,EAC3D,MAAM,SAAS,IAAI;AAAA,EACnB,WAAW,QAAQ,OAAO,MAAM;AAAA,CAAI,GAAG;AAAA,IACrC,IAAI,KAAK,KAAK,MAAM,IAAI;AAAA,MACtB,IAAI,OAAO,OAAO;AAAA,QAAG;AAAA,MACrB;AAAA,IACF;AAAA,IACA,MAAM,KAAK,KAAK,QAAQ,IAAI;AAAA,IAC5B,IAAI,MAAM;AAAA,MAAG;AAAA,IACb,MAAM,MAAM,KAAK,MAAM,GAAG,EAAE;AAAA,IAC5B,IAAI,QAAQ;AAAA,MAAY;AAAA,IACxB,OAAO,IAAI,KAAK,KAAK,MAAM,KAAK,CAAC,EAAE,KAAK,CAAC;AAAA,EAC3C;AAAA,EACA,OAAO;AAAA;AAGT,IAAM,OAAO,CAAC,SACZ,SAAS,aAAa,QAAQ,KAAK,IAAI,IAAI,OAAO,IAAI,IAAI;AAErD,IAAM,YAAY,CAAC,UAAkB,WAAyC;AAAA,EACnF,IAAI,aAAa,UAAU;AAAA,IACzB,MAAM,SAAS,YAAY,MAAM;AAAA,IACjC,MAAM,OAAM,KAAK,OAAO,IAAI,KAAK,CAAC;AAAA,IAClC,MAAM,OAAM,KAAK,OAAO,IAAI,KAAK,CAAC;AAAA,IAClC,MAAM,QAAO,OAAO,IAAI,KAAK;AAAA,IAC7B,OAAO,SAAQ,aAAa,SAAQ,aAAa,UAAS,YACtD,YACA,EAAE,WAAK,aAAM,UAAI;AAAA,EACvB;AAAA,EAEA,MAAM,UAAU,OAAO,MAAM;AAAA,CAAI,EAAE,MAAM,IAAI,MAAM,GAAG;AAAA,EACtD,MAAM,MAAM,KAAK,OAAO,EAAE;AAAA,EAC1B,MAAM,MAAM,KAAK,OAAO,EAAE;AAAA,EAC1B,MAAM,OAAO,OAAO;AAAA,EACpB,OAAO,QAAQ,aAAa,QAAQ,aAAa,SAAS,aAAa,SAAS,KAC5E,YACA,EAAE,KAAK,MAAM,IAAI;AAAA;AAGhB,IAAM,aAAa,CAAC,UAAkB,WAAuC;AAAA,EAClF,IAAI,aAAa;AAAA,IAAU,OAAO,KAAK,YAAY,MAAM,EAAE,IAAI,KAAK,CAAC;AAAA,EAErE,OAAO,MAAM,OAAO,MAAM;AAAA,CAAI,EAAE,MAAM,IAAI,MAAM,GAAG,EAAE,EAAE;AAAA;;;ADnElD,IAAM,YAAY,CAAC,UACxB,OAAO,UAAU,YAAY,UAAU,SAAQ,UAAU,SACrD,OAAQ,MAA4B,IAAI,IACxC;AAGN,IAAM,UAAS,CAAC,UACd,UAAU,KAAK,MAAM,YAAY,UAAU,KAAK,MAAM;AAExD,IAAM,MAAM,CAAC,MAAyB,cACpC,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,EAC/B,OAAO,YAAY,QAAQ;AAAA,EAC3B,IAAI,YAAY,WAAW;AAAA,IACzB,OAAO,IAAI,MAAM,kBAAkB,CAAC;AAAA,IACpC;AAAA,EACF;AAAA,EACA,MAAM,QAAQ,MAAM,SAAS,MAAM;AAAA,IACjC,OAAO;AAAA,IACP,OAAO,CAAC,UAAU,QAAQ,MAAM;AAAA,IAChC,SAAS;AAAA,EACX,CAAC;AAAA,EACD,MAAM,MAAgB,CAAC;AAAA,EACvB,MAAM,MAAgB,CAAC;AAAA,EACvB,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAkB,IAAI,KAAK,KAAK,CAAC;AAAA,EAC1D,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAkB,IAAI,KAAK,KAAK,CAAC;AAAA,EAC1D,MAAM,GAAG,SAAS,CAAC,UAAU;AAAA,IAC3B,OAAO,IAAI,MAAM,QAAQ,YAAY,MAAM,SAAS,CAAC;AAAA,GACtD;AAAA,EACD,MAAM,GAAG,SAAS,CAAC,UAAU,WAAW;AAAA,IACtC,MAAM,SAAS,OAAO,OAAO,GAAG,EAAE,SAAS,MAAM;AAAA,IACjD,QAAQ;AAAA,MAEN,UAAU,YAAY;AAAA,MACtB,QAAQ,WAAW,OAAO,SAAS,GAAG;AAAA,aAAsB,UAAU,KAAK;AAAA,MAC3E,QAAQ,OAAO,OAAO,GAAG,EAAE,SAAS,MAAM;AAAA,IAC5C,CAAC;AAAA,GACF;AAAA,CACF;AAEH,IAAM,SAAS,CAAC,UAA+D;AAAA,EAC7E,IAAI,MAAM,eAAe;AAAA,IAAG,OAAO;AAAA,EACnC,IAAI,MAAM,OAAO;AAAA,IAAG,OAAO;AAAA,EAC3B,IAAI,MAAM,YAAY;AAAA,IAAG,OAAO;AAAA,EAChC,OAAO;AAAA;AAGT,IAAM,cAAc,OAAO,MAAc,OAAmB,YAA0B;AAAA,EAEpF,MAAM,OAAO,KAAK,QAAQ,IAAI,GAAG,IAAI,SAAS,IAAI,KAAK,YAAY,CAAC,EAAE,SAAS,KAAK,OAAO;AAAA,EAG3F,MAAM,SAAS,MAAM,KAAK,MAAM,MAAM,GAAK;AAAA,EAC3C,IAAI;AAAA,IACF,IAAI;AAAA,MACF,MAAM,OAAO,UAAU,KAAK;AAAA,MAG5B,IAAI,QAAQ,QAAQ,aAAa,QAAQ,QAAQ,WAAW;AAAA,QAC1D,MAAM,OAAO,MAAM,QAAQ,OAAO,IAAI,QAAQ,OAAO,EAAE;AAAA,MACzD;AAAA,MACA,MAAM,OAAO,MAAM,QAAQ,IAAI;AAAA,MAC/B,MAAM,OAAO,KAAK;AAAA,cAClB;AAAA,MACA,MAAM,OAAO,MAAM;AAAA;AAAA,IAErB,MAAM,OAAO,MAAM,IAAI;AAAA,IACvB,OAAO,OAAO;AAAA,IACd,MAAM,OAAO,IAAI,EAAE,MAAM,MAAG;AAAA,MAAG;AAAA,KAAS;AAAA,IACxC,MAAM;AAAA;AAAA;AAIH,IAAM,cAAc,CAAC,UAA8B,CAAC,MAAkB;AAAA,EAC3E,MAAM,YAAY,QAAQ,iBAAiB;AAAA,EAC3C,MAAM,WAAW,QAAQ;AAAA,EACzB,OAAO;AAAA,IACL,cAAc,MAAM,QAAQ,UAAU,KAAK;AAAA,IAC3C,MAAM,CAAC,SAAS,IAAI,MAAM,SAAS;AAAA,IACnC,aAAa,OAAO,aAAa;AAAA,MAC/B,MAAM,SAAS,MAAM,IAAI,WAAW,UAAU,QAAQ,GAAG,SAAS;AAAA,MAClE,OAAO,OAAO,aAAa,IAAI,WAAW,UAAU,OAAO,MAAM,IAAI;AAAA;AAAA,IAEvE,YAAY,OAAO,aAAa;AAAA,MAC9B,MAAM,SAAS,MAAM,IAAI,UAAU,UAAU,QAAQ,GAAG,SAAS;AAAA,MACjE,OAAO,OAAO,aAAa,IAAI,UAAU,UAAU,OAAO,MAAM,IAAI;AAAA;AAAA,IAEtE,YAAY;AAAA,IACZ,UAAU,OAAO,SAAS;AAAA,MACxB,IAAI;AAAA,QACF,OAAO,IAAI,WAAW,MAAM,SAAS,IAAI,CAAC;AAAA,QAC1C,OAAO,OAAO;AAAA,QACd,IAAI,QAAO,KAAK;AAAA,UAAG;AAAA,QACnB,MAAM;AAAA;AAAA;AAAA,IAGV,YAAY,OAAO,SAAS;AAAA,MAC1B,IAAI;AAAA,QACF,MAAM,OAAO,IAAI;AAAA,QACjB,OAAO,OAAO;AAAA,QACd,IAAI,CAAC,QAAO,KAAK;AAAA,UAAG,MAAM;AAAA;AAAA;AAAA,IAG9B,OAAO,CAAC,OAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAAA,IAC/D,MAAM,OAAO,SAAS;AAAA,MACpB,IAAI;AAAA,QACF,MAAM,QAAQ,MAAM,MAAM,IAAI;AAAA,QAC9B,OAAO;AAAA,UACL,KAAK,MAAM;AAAA,UACX,MAAM,OAAO,KAAK;AAAA,UAClB,MAAM,MAAM,OAAO;AAAA,UACnB,MAAM,MAAM;AAAA,UACZ,KAAK,MAAM;AAAA,QACb;AAAA,QACA,OAAO,OAAO;AAAA,QACd,IAAI,QAAO,KAAK;AAAA,UAAG;AAAA,QACnB,MAAM;AAAA;AAAA;AAAA,IAGV,iBAAiB;AAAA,EACnB;AAAA;;AEpIF;AAMO,IAAM,mBAAmB,CAAC,SAAqB,YAAY,MAC1D,gBAAS,mBAAmB,GAAG,iBAAiB,CAAC,EAAE,KACjD,eAAQ,gBAAgB,MAAM,CAAC,CACvC;;ACIK,MAAM,yBAAyB,MAAM;AAAA,EAC1C,WAAW,CAAC,SAAiB;AAAA,IAC3B,MAAM,OAAO;AAAA,IACb,KAAK,OAAO;AAAA;AAEhB;AAGO,IAAM,OAAO;AACb,IAAM,UAAU;AAChB,IAAM,KAAK;AAGlB,IAAM,SAA8B,IAAI,IAAI,CAAC,aAAa,WAAW,WAAW,CAAC;AAG1E,IAAM,YAAY,CAAC,SACxB,OAAO,cAAc,IAAI,KAAK,QAAQ,KAAK,QAAQ,OAC/C,KAAK,SAAS,CAAC,EAAE,SAAS,GAAG,GAAG,IAChC;AAGC,IAAM,gBAAgB,CAAC,aAAmD;AAAA,EAC/E,IAAI,SAAS,WAAW,GAAG;AAAA,IACzB,MAAM,IAAI,MACR,4FACF;AAAA,EACF;AAAA,EACA,WAAW,UAAU,UAAU;AAAA,IAC7B,MAAM,QAAQ,WAAW,MAAM,CAAC,4BAA4B,IAAI,aAAa,MAAM;AAAA,IACnF,IAAI,MAAM,SAAS,GAAG;AAAA,MACpB,MAAM,IAAI,MAAM,sBAAsB,KAAK,UAAU,MAAM,MAAM,MAAM,KAAK,IAAI,GAAG;AAAA,IACrF;AAAA,EACF;AAAA,EACA,OAAO,CAAC,GAAG,QAAQ;AAAA;AAOd,IAAM,WAAW,CAAC,MAAc,aACrC,aAAa,IAAI,EAAE,SAAS,IACxB,YACA,SAAS,KAAK,CAAC,WAAW,KAAK,WAAW,GAAG,SAAS,CAAC;AAE7D,IAAM,UAAU,CAAC,UACf,MAAM,KAAK,KAAK,KAAK,CAAC,wBAAwB,KAAK,CAAC,WAAW,MAAM,WAAW,MAAM,CAAC;AAGzF,IAAM,cAAc,CAAC,WAAmD;AAAA,EACtE,MAAM,QAAQ,QAAQ,WAAW,SAAS,MAAM,OAAO,OAAO,MAAM,UAAU,MAAM,IAAI;AAAA,EACxF,OAAO,UAAU,aAAa,QAAQ,KAAK,IAAI,QAAQ;AAAA;AASzD,IAAM,cAAc,CAAC,OAAe,aAAoD;AAAA,EACtF,MAAM,OAAO,aAAa,OAAO,EAAE,MAAM,SAAS,GAAG,SAAS;AAAA,EAC9D,OAAO,SAAS,MAAM,QAAQ,MAAM,YAAY,YAAY;AAAA;AAG9D,IAAM,mBACJ;AAEF,IAAM,mBAAmB,CACvB,MACA,aACuB;AAAA,EACvB,OAAO,QAAQ,QAAQ;AAAA,EACvB,IAAI,QAAQ,aAAa;AAAA,IACvB,MAAM,QAAQ,KAAK,MAAM;AAAA,IACzB,MAAM,OAAO,MAAM,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC;AAAA,IACnD,MAAM,QAAQ,KAAK,SAAS,QAAQ,IAAI,KAAK,MAAM,GAAG,CAAC,SAAS,MAAM,IAAI;AAAA,IAC1E,MAAM,SAAS,KAAK,WAAW,KAAK,KAAK,OAAO,YAAY,QAAQ,KAAK;AAAA,IACzE,IAAI,CAAC;AAAA,MAAQ,OAAO;AAAA,IACpB,MAAM,QAAQ,YAAY,OAAO,QAAQ;AAAA,IACzC,IAAI,UAAU;AAAA,MAAW,OAAO,aAAa;AAAA,IAC7C,OAAO,UAAU,QAAQ,YAAY,wBAAwB;AAAA,EAC/D;AAAA,EACA,IAAI,QAAQ,WAAW;AAAA,IACrB,MAAM,QAAQ,KAAK,WAAW,IAAI,YAAY,KAAK,EAAE,IAAI;AAAA,IACzD,IAAI,UAAU;AAAA,MAAW,OAAO;AAAA,IAMhC,OAAO,YAAY,OAAO,QAAQ,MAAM,YAAY,WAAW,qBAAqB;AAAA,EACtF;AAAA,EACA,IAAI,QAAQ,aAAa;AAAA,IACvB,MAAM,QAAQ,KAAK,MAAM,GAAG,EAAE;AAAA,IAC9B,MAAM,UACJ,MAAM,MAAM,CAAC,SAAS,SAAS,QAAQ,SAAS,IAAI,KAAK,IAAI,IAAI,KAAK,EAAE,SAAS,MAAM;AAAA,IACzF,OAAO,WAAW,YAAY,KAAK,KAAK,SAAS,EAAE,MAAM,YACrD,YACA;AAAA,EACN;AAAA,EACA,OAAO,aAAa,OAAO,GAAG;AAAA;AAGhC,IAAM,KAAK;AAGX,IAAM,QAAQ,CAAC,QAAoC;AAAA,EACjD,OAAO,MAAM,IAAI,QAAQ,YAAY;AAAA,EACrC,IAAI,IAAI,WAAW;AAAA,IAAG,OAAO;AAAA,EAC7B,IAAI,IAAI,WAAW;AAAA,IAAG,QAAQ,SAAS,QAAQ,SAAS,SAAS,GAAG,KAAK,MAAM,EAAE;AAAA,EACjF,OACE,IAAI,WAAW,KACf,SAAS,QACT,GAAG,KAAK,MAAM,EAAE,KAChB,WAAW,QACX,GAAG,KAAK,YAAY,EAAE;AAAA;AAQnB,IAAM,oBAAoB,CAC/B,MACA,YACuB;AAAA,EACvB,OAAO,YAAY,QAAQ;AAAA,EAC3B,MAAM,QAAQ,CAAC,SACb,SAAS,aAAa,SAAS,MAAM,QAAQ,QAAQ,MAAM;AAAA,EAC7D,IAAI,YAAY;AAAA,IAAW,OAAO,iBAAiB,MAAM,QAAQ,QAAQ;AAAA,EACzE,IAAI,YAAY,SAAS;AAAA,IAEvB,OAAO,MAAM,GAAG,SAAS,QAAQ;AAAA,IACjC,IAAI,SAAS,QAAQ,MAAM,QAAQ,SAAS,aAAa,CAAC,aAAa,KAAK,IAAI,GAAG;AAAA,MACjF,OAAO;AAAA,IACT;AAAA,IACA,IAAI,KAAK,SAAS,KAAK,CAAC,MAAM,KAAK,MAAM,GAAG,EAAE,CAAC;AAAA,MAAG,OAAO;AAAA,IACzD,OAAO,QAAQ,QAAQ,KAAK,MAAM,EAAE;AAAA,IACpC,IAAI,WAAW,aAAa,WAAW,QAAQ,QAAQ;AAAA,MACrD,OAAO;AAAA,IACT;AAAA,IACA,OAAO,MAAM,IAAI,IAAI,YAAY;AAAA,EACnC;AAAA,EACA,IAAI,YAAY,IAAI;AAAA,IAClB,OAAO,OAAO,KAAK,SAAS,SAAS;AAAA,IACrC,OAAO,UAAU,QAAQ,QAAQ,QAAQ,MAAM,WAAW,KAAK,MAAM,IAAI,IACrE,YACA;AAAA,EACN;AAAA,EACA,OAAO,GAAG,OAAO,OAAO;AAAA;AAkBnB,IAAM,YAAY,CAAC,MAAyB,gBAA+B;AAAA,EAChF,OAAO,SAAS,OAAO;AAAA,EACvB,IAAI,YAAY,UAAU,SAAS,SAAS,OAAO,MAAM,MAAM;AAAA,IAC7D,OAAO;AAAA,MACL,QAAQ;AAAA,IACV;AAAA,EACF;AAAA,EACA,IAAI,YAAY,aAAa,QAAQ,aAAa,CAAC,OAAO,IAAI,GAAG;AAAA,IAAG,OAAO,EAAE,IAAI,WAAW;AAAA,EAC5F,MAAM,SAAS,QAAQ,cAAc,KAAK,KAAK,SAAS,KAAK,KAAK;AAAA,EAClE,IAAI,WAAW,YAAY,QAAQ,WAAW,SAAS,MAAM;AAAA,IAAM,OAAO,EAAE,IAAI,OAAO;AAAA,EACvF,MAAM,QAAQ,+BAA+B,KAAK,UAAU,EAAE,IAAI;AAAA,EAClE,IAAI,UAAU,aAAa,OAAO,KAAK,MAAM;AAAA,IAAa,OAAO,EAAE,IAAI,WAAW;AAAA,EAClF,OAAO;AAAA,IACL,QACE,aAAa,OAAO,OAAO,MAAM,iCAAiC,2BAClE;AAAA,EACJ;AAAA;;;ACjMK,IAAM,KAAK;AAGlB,IAAM,eAAoC,IAAI,IAAI;AAAA,EAChD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,IAAM,QAAQ;AAGP,IAAM,YAAY,CAAC,YACxB,QACG,MAAM;AAAA,CAAI,EACV,OAAO,CAAC,SAAS;AAAA,EAChB,MAAM,SAAS,MAAM,KAAK,IAAI,IAAI;AAAA,EAClC,OAAO,WAAW,aAAa,OAAO,MAAM,GAAG,EAAE,KAAK,CAAC,UAAU,aAAa,IAAI,KAAK,CAAC;AAAA,CACzF,EACA,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC;AAMvB,IAAM,oBAAoB,OAC/B,MACA,MACA,UACkB;AAAA,EAClB,MAAM,SAAS,MAAM,KAAK,KAAK,CAAC,IAAI,SAAS,MAAM,GAAG,KAAK,CAAC;AAAA,EAC5D,IAAI,OAAO,aAAa,GAAG;AAAA,IACzB,MAAM,IAAI,iBACR,cAAc,wEACZ,IAAI,iBAAiB,OAAO,OAAO,QAAQ,0BAC/C;AAAA,EACF;AAAA,EACA,MAAM,SAAS,UAAU,OAAO,MAAM;AAAA,EACtC,IAAI,OAAO,WAAW;AAAA,IAAG;AAAA,EACzB,MAAM,IAAI,iBACR,cAAc,gFACZ,mCAAmC,OAAO,KAAK,IAAI,yCACnD,oDACJ;AAAA;;;ACxCF,IAAM,UAAS,CAAC,MAAc,YAC5B,IAAI,iBAAiB,cAAc,SAAS,SAAS;AAGhD,IAAM,cAAc,CAAC,QAAgB,SAA2B;AAAA,EACrE,MAAM,QAAQ,KACX,MAAM,OAAO,SAAS,CAAC,EACvB,MAAM,GAAG,EACT,MAAM,GAAG,EAAE;AAAA,EACd,OAAO,MAAM,IAAI,CAAC,GAAG,UAAU,GAAG,UAAU,MAAM,MAAM,GAAG,QAAQ,CAAC,EAAE,KAAK,GAAG,GAAG;AAAA;AAI5E,IAAM,YAAY,CAAC,WAA6B;AAAA,EACrD,MAAM,QAAQ,OAAO,MAAM,GAAG,EAAE,MAAM,GAAG,EAAE;AAAA,EAC3C,OAAO,CAAC,KAAK,GAAG,MAAM,IAAI,CAAC,GAAG,UAAU,IAAI,MAAM,MAAM,GAAG,QAAQ,CAAC,EAAE,KAAK,GAAG,GAAG,CAAC;AAAA;AAqBpF,IAAM,kBAAkB,CAAC,SAAmD;AAAA,EAC1E,IAAI,SAAS;AAAA,IAAW,OAAO;AAAA,EAC/B,IAAI,KAAK,SAAS;AAAA,IAAa,OAAO,QAAQ,KAAK;AAAA,EACnD,IAAI,KAAK,QAAQ;AAAA,IAAG,OAAO,mBAAmB,OAAO,KAAK,GAAG;AAAA,EAC7D,KAAK,KAAK,OAAO,QAAW,GAAG;AAAA,IAC7B,OAAO,uCAAuC,KAAK,KAAK,SAAS,CAAC,EAAE,SAAS,GAAG,GAAG;AAAA,EACrF;AAAA,EACA;AAAA;AAOK,IAAM,kBAAkB,OAC7B,MACA,QACA,MACA,WAC+B;AAAA,EAC/B,MAAM,QAAQ,UAAU,MAAM;AAAA,EAC9B,YAAY,OAAO,UAAU,MAAM,QAAQ,IAAI,MAAM,IAAI,CAAC,QAAQ,KAAK,KAAK,GAAG,CAAC,CAAC,GAAG,QAAQ,GAAG;AAAA,IAC7F,MAAM,KAAK,MAAM,SAAS,aAAa,KAAK,QAAQ,IAAI,YAAY,gBAAgB,IAAI;AAAA,IACxF,IAAI,OAAO,WAAW;AAAA,MACpB,MAAM,QACJ,MACA,GAAG,OAAO,MAAM,MAAM,gCAAgC,WAAW,+BAC/D,iGACJ;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAM,OAAO,YAAY,QAAQ,IAAI;AAAA,EACrC,OAAO,eAAe,SAAS,MAAM,QAAQ,IAAI,CAAC,QAAQ,GAAG,IAAI,EAAE,IAAI,CAAC,QAAQ,KAAK,KAAK,GAAG,CAAC,CAAC;AAAA,EAC/F,MAAM,MAAM,gBAAgB,UAAU;AAAA,EACtC,IAAI,QAAQ,WAAW;AAAA,IACrB,MAAM,QACJ,MACA,uBAAuB,UAAU,2DAC/B,2CACJ;AAAA,EACF;AAAA,EACA,YAAY,OAAO,SAAS,MAAM,QAAQ,GAAG;AAAA,IAC3C,MAAM,MAAM,OAAO,KAAK,MAAM;AAAA,IAC9B,IAAI,MAAM,SAAS,aAAa;AAAA,MAC9B,MAAM,QACJ,MACA,GAAG,UAAU,SAAS,YAAY,YAAY,KAAK,KAAK,kBACtD,+DACJ;AAAA,IACF;AAAA,IACA,MAAM,QAAQ,gBAAgB,IAAI;AAAA,IAClC,IAAI,UAAU,WAAW;AAAA,MACvB,MAAM,QACJ,MACA,GAAG,OAAO,0CAA0C,yCAClD,8DACJ;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAM,kBAAkB,MAAM,MAAM,CAAC,GAAG,OAAO,QAAQ,GAAG,IAAI,CAAC;AAAA,EAC/D,MAAM,SAAS,MAAM,KAAK,KAAK,IAAI;AAAA,EACnC,IAAI,WAAW,aAAa,WAAW;AAAA,IAAkB,OAAO;AAAA,EAChE,IAAI,QAAQ,SAAS;AAAA,IAAQ,OAAO;AAAA,EACpC,MAAM,QAAO,MAAM,MAAM,WAAW,YAAY,YAAY,KAAK,OAAO,oBAAoB;AAAA;AAWvF,IAAM,cAAc,CAAC,YAA8C;AAAA,EACxE,IAAI,QAAQ,QAAQ,aAAa,QAAQ,QAAQ;AAAA,IAAG;AAAA,EACpD,MAAM,QAAkB,CAAC;AAAA,EACzB,KAAK,QAAQ,OAAO,UAAY;AAAA,IAAG,MAAM,KAAK,eAAe;AAAA,EAC7D,KAAK,QAAQ,OAAO,QAAW;AAAA,IAAG,MAAM,KAAK,4BAA4B;AAAA,EACzE,IAAI,MAAM,WAAW;AAAA,IAAG;AAAA,EACxB,OAAO,QAAQ,QAAQ,KAAK,SAAS,CAAC,EAAE,SAAS,GAAG,GAAG,QAAQ,MAAM,KAAK,OAAO;AAAA;AAQ5E,IAAM,oBAAoB,OAC/B,MACA,QACA,MACA,SACA,WACkB;AAAA,EAClB,MAAM,OAAO,YAAY,OAAO;AAAA,EAChC,IAAI,SAAS,WAAW;AAAA,IACtB,MAAM,QACJ,MACA,GAAG,yFACD,kCACJ;AAAA,EACF;AAAA,EACA,MAAM,gBAAgB,MAAM,QAAQ,MAAM,gBAAgB;AAAA,EAC1D,MAAM,mBAAmB,MAAM,MAAM,SAAS,MAAM;AAAA;AAS/C,IAAM,UAAU,CACrB,MACA,KACA,WACwB;AAAA,EACxB,IAAI,QAAQ;AAAA,IAAG,OAAO;AAAA,EACtB,IAAI,KAAK,QAAQ;AAAA,IAAK,QAAQ,KAAK,OAAO,SAAW;AAAA,EACrD,MAAM,aAAa,KAAK,OAAO,QAAW;AAAA,EAC1C,MAAM,aAAa,KAAK,OAAO,OAAW;AAAA,EAE1C,IAAI,cAAc;AAAA,IAAW,OAAO;AAAA,EACpC,IAAI,WAAW;AAAA,IAAW;AAAA,EAC1B,OAAO,OAAO,SAAS,KAAK,GAAG,IAAI,YAAY;AAAA;AAa1C,IAAM,qBAAqB,OAChC,MACA,MACA,SACA,WACkB;AAAA,EAClB,MAAM,WAAW,KAAK,aAAa;AAAA,EACnC,MAAM,SAAS,KAAK,MAAM,GAAG,KAAK,YAAY,GAAG,CAAC,KAAK;AAAA,EACvD,MAAM,MAAM,QAAQ,QAAQ,MAAM,KAAK,KAAK,MAAM,IAAI,OAAO;AAAA,EAC7D,MAAM,OAAO,EAAE,KAAK,MAAM,QAAQ,MAAM,KAAK,QAAQ,OAAO,EAAE;AAAA,EAC9D,IAAI,QAAQ,MAAM,UAAU,MAAM,MAAM;AAAA,IAAO;AAAA,EAC/C,MAAM,QACJ,MACA,SAAS,OAAO,KAAK,GAAG,YAAY,OAAO,GAAG,WAAW,KAAK,KAAK,SAAS,CAAC,qBAC3E,gCAAgC,OAAO,QAAQ,8CAC/C,kEACJ;AAAA;AASK,IAAM,iBAAiB,OAAO,SAA6D;AAAA,EAChG,MAAM,SAAS,MAAM,KAAK,KAAK,CAAC,eAAe,IAAI,CAAC;AAAA,EACpD,MAAM,MAAM,OAAO,OAAO,KAAK,EAAE,MAAM,KAAK;AAAA,EAC5C,OAAO,OAAO,aAAa,KAAK,IAAI,MAAM,CAAC,OAAO,QAAQ,KAAK,EAAE,CAAC,IAAI,IAAI,IAAI,MAAM,IAAI;AAAA;;;AChN1F,IAAM,WACJ;AACF,IAAM,cACJ;AAGK,IAAM,aACX,CAAC,MAAc,aACf,CAAC,UAA0B;AAAA,EACzB,MAAM,OAAO,UAAU,KAAK;AAAA,EAC5B,IAAI,SAAS,YAAY,SAAS;AAAA,IAAS,MAAM;AAAA,EACjD,MAAM,IAAI,MACR,cAAc,SAAS,0EACrB,IAAI,SAAS,KAAK,IAAI,uEACxB,EAAE,MAAM,CACV;AAAA;AAOG,IAAM,cAAc,CAAC,OAAe,WAAqD;AAAA,EAC9F,IAAI,OAAO,aAAa;AAAA,IAAG;AAAA,EAC3B,IAAI,SAAS,KAAK,OAAO,MAAM,GAAG;AAAA,IAChC,OAAO,IAAI,iBACT,WAAW,mFACT,uFACA,2DACJ;AAAA,EACF;AAAA,EACA,IAAI,YAAY,KAAK,OAAO,MAAM,GAAG;AAAA,IACnC,OAAO,IAAI,iBACT,WAAW,mFACb;AAAA,EACF;AAAA,EACA;AAAA;;;AC/CF;AACA;AACA,iBAAS;AAKF,IAAM,YAAY,OAAO,UAAuC;AAAA,EACrE,MAAM,MAAM,MAAM,QAAQ,MAAK,OAAO,GAAG,UAAU,CAAC;AAAA,EACpD,MAAM,UAAU,MAAM,GAAG,KAAK,EAAE,OAAO,MAAM,WAAW,KAAK,CAAC;AAAA,EAC9D,IAAI;AAAA,IACF,MAAM,OAAO,MAAK,KAAK,QAAQ;AAAA,IAC/B,MAAM,UAAU,MAAM,OAAO,EAAE,MAAM,MAAM,MAAM,IAAM,CAAC;AAAA,IACxD,OAAO,EAAE,SAAS,KAAK;AAAA,IACvB,OAAO,OAAO;AAAA,IACd,MAAM,QAAQ;AAAA,IACd,MAAM;AAAA;AAAA;;;AC4CH,IAAM,iBAAiB,CAAC,YAA+B,SAA+B;AAAA,EAC3F,MAAM,WAAW,cAAc,UAAU;AAAA,EACzC,QAAQ,SAAS;AAAA,EAMjB,MAAM,UAAU,OACd,QACE,QAAQ,WAAiE,CAAC,MACpD;AAAA,IACxB,MAAM,QAAQ,KAAK,UAAU,IAAI;AAAA,IACjC,MAAM,UAAU,kBAAkB,MAAM;AAAA,MACtC;AAAA,SACI,WAAW,YAAY,CAAC,IAAI,EAAE,OAAO;AAAA,IAC3C,CAAC;AAAA,IACD,IAAI,YAAY;AAAA,MACd,MAAM,IAAI,iBAAiB,sBAAsB,UAAU,SAAS;AAAA,IACtE,MAAM,SAAS;AAAA,IACf,KAAK,IAAI,6BAA6B,OAAO;AAAA,IAC7C,MAAM,SAAS,MAAM,KAAK,KAAK,CAAC,MAAM,MAAM,MAAM,GAAG,IAAI,CAAC;AAAA,IAC1D,MAAM,UAAU,YAAY,OAAO,MAAM;AAAA,IACzC,IAAI,YAAY;AAAA,MAAW,MAAM;AAAA,IACjC,OAAO;AAAA;AAAA,EAQT,MAAM,WAAW,OAAO,MAAc,YAA0B;AAAA,IAC9D,MAAM,SAAS,SAAS,MAAM,QAAQ;AAAA,IACtC,MAAM,WAAW,KAAK,aAAa;AAAA,IACnC,IAAI,WAAW,WAAW;AAAA,MACxB,IAAI,QAAQ,QAAQ,aAAa,QAAQ,QAAQ,YAAY,aAAa,GAAG;AAAA,QAC3E,MAAM,IAAI,iBACR,cAAc,eAAe,OAAO,QAAQ,GAAG,4CAC7C,oBAAoB,SAAS,KAAK,IAAI,mDACtC,sBACJ;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,IACA,MAAM,OAAO,UAAU,QAAQ,IAAI;AAAA,IACnC,IAAI,SAAS;AAAA,MAAW,MAAM,IAAI,iBAAiB,cAAc,6BAA6B;AAAA,IAC9F,MAAM,kBAAkB,MAAM,QAAQ,MAAM,SAAS,MAAM,KAAK,OAAO,CAAC;AAAA,IACxE,OAAO,EAAE,MAAM,OAAO;AAAA;AAAA,EAIxB,MAAM,cAAc,OAAO,MAAyB,WAAmC;AAAA,IACrF,MAAM,SAAS,MAAM,QAAQ,MAAM,WAAW,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC;AAAA,IACzE,IAAI,OAAO,aAAa,GAAG;AAAA,MACzB,MAAM,SAAS,OAAO,OAAO,KAAK,EAAE,MAAM,GAAG,GAAG;AAAA,MAChD,MAAM,IAAI,MAAM,WAAW,KAAK,UAAU,IAAI,QAAQ,OAAO,OAAO,QAAQ,MAAM,QAAQ;AAAA,IAC5F;AAAA;AAAA,EAGF,OAAO;AAAA,IAEL,YAAY,OAAO,MAAM,YAAY;AAAA,MACnC,MAAM,SAAS,MAAM,OAAO;AAAA;AAAA,IAE9B,cAAc,MAAM,KAAK,aAAa;AAAA,IACtC,MAAM,OAAO,SAAS;AAAA,MACpB,MAAM,QAAQ,UAAU,MAAM,KAAK,aAAa,CAAC;AAAA,MACjD,IAAI,YAAY;AAAA,QAAO,MAAM,IAAI,iBAAiB,eAAe,MAAM,QAAQ;AAAA,MAC/E,IAAI,MAAM,OAAO;AAAA,QAAY,OAAO,KAAK,KAAK,IAAI;AAAA,MAGlD,MAAM,QAAQ,KAAK,OAAO,cAAc,KAAK,KAAK;AAAA,MAClD,MAAM,SAAS,UAAU,YAAY,YAAY,SAAS,OAAO,QAAQ;AAAA,MACzE,OAAO,QAAQ,MAAM;AAAA,QACnB,QAAQ,YAAY;AAAA,UAClB,IAAI,UAAU,aAAa,WAAW,WAAW;AAAA,YAC/C,MAAM,gBAAgB,MAAM,QAAQ,OAAO,MAAM;AAAA,UACnD;AAAA;AAAA,MAEJ,CAAC;AAAA;AAAA,IAEH,aAAa,CAAC,aAAa,KAAK,YAAY,QAAQ;AAAA,IACpD,YAAY,CAAC,aAAa,KAAK,WAAW,QAAQ;AAAA,IAElD,YAAY;AAAA,IACZ,UAAU,CAAC,SAAS,KAAK,SAAS,IAAI;AAAA,IACtC,YAAY,OAAO,SAAS;AAAA,MAC1B,MAAM,SAAS,SAAS,MAAM,QAAQ;AAAA,MACtC,IAAI,WAAW;AAAA,QAAW,OAAO,KAAK,WAAW,IAAI,EAAE,MAAM,WAAW,MAAM,QAAQ,CAAC;AAAA,MAOvF,IAAK,MAAM,KAAK,KAAK,IAAI,MAAO;AAAA,QAAW;AAAA,MAC3C,MAAM,gBAAgB,MAAM,QAAQ,MAAM,MAAM;AAAA,MAChD,MAAM,YAAY,CAAC,IAAI,MAAM,MAAM,IAAI,CAAC;AAAA;AAAA,IAE1C,OAAO,CAAC,OAAO,KAAK,MAAM,EAAE;AAAA,IAC5B,MAAM,CAAC,SAAS,KAAK,KAAK,IAAI;AAAA,IAC9B,iBAAiB,OAAO,MAAM,OAAO,YAAY;AAAA,MAC/C,MAAM,SAAS,MAAM,SAAS,MAAM,OAAO;AAAA,MAC3C,IAAI,WAAW,WAAW;AAAA,QACxB,OAAO,KAAK,gBAAgB,MAAM,OAAO,OAAO,EAAE,MAAM,WAAW,MAAM,QAAQ,CAAC;AAAA,MACpF;AAAA,MACA,QAAQ,SAAS;AAAA,MACjB,MAAM,SAAS,MAAM,KAAK,MAAM,KAAK;AAAA,MACrC,IAAI;AAAA,QACF,MAAM,YACJ;AAAA,UACE;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,GAAI,QAAQ,QAAQ,YAAY,CAAC,IAAI,CAAC,MAAM,OAAO,QAAQ,GAAG,CAAC;AAAA,UAC/D,GAAI,QAAQ,QAAQ,YAAY,CAAC,IAAI,CAAC,MAAM,OAAO,QAAQ,GAAG,CAAC;AAAA,UAC/D,OAAO;AAAA,UACP;AAAA,QACF,GACA,OAAO,IACT;AAAA,gBACA;AAAA,QACA,MAAM,OAAO,QAAQ;AAAA;AAAA;AAAA,EAG3B;AAAA;AAOK,IAAM,aAAa,CAAC,YAA2C;AAAA,EACpE,MAAM,OAAO,YAAY,OAAO;AAAA,EAChC,OAAO,eAAe,QAAQ,UAAU;AAAA,IACtC;AAAA,IACA,QAAQ,MAAM,eAAe,IAAI;AAAA,IACjC,KACE,QAAQ,QACP,CAAC,SAAS;AAAA,MACT,QAAQ,OAAO,MAAM,GAAG;AAAA,CAAQ;AAAA;AAAA,IAEpC,OAAO;AAAA,EACT,CAAC;AAAA;",
|
|
33
|
-
"debugId": "
|
|
34
|
+
"mappings": "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",
|
|
35
|
+
"debugId": "3EE0567FCAB27DCF64756E2164756E21",
|
|
34
36
|
"names": []
|
|
35
37
|
}
|